[U-Boot] [BUG] Crash when starting grub-arm.efi on BeagleBone Black

Heinrich Schuchardt xypron.glpk at gmx.de
Fri Mar 8 21:09:32 UTC 2019


On 3/8/19 9:39 PM, Heinrich Schuchardt wrote:
> On 3/7/19 11:29 PM, Heinrich Schuchardt wrote:
>> On 3/7/19 12:05 PM, Adam Podogrocki wrote:
>>>>      Hello Heinrich,
>>>>
>>>>      I've checked U-Boot behaviour in following setups:
>>>>
>>>>       1. U-Boot v2018.09/v2018.11 and GRUB commit 72e80c025 (used by us
>>>>          in other setups)
>>>>       2. U-Boot v2019.01 and GRUB commit 72e80c025 (used by us in other
>>>>          setups)
>>>>       3. U-Boot v2019.01 and GRUB latest commit 9223eff8f
>>
>> These are not commit numbers from git://git.savannah.gnu.org/grub.git
>> So to which repository do they relate?
>>
>> On Google drive you supplied to me GRUB 35b909062. This is also not a
>> valid commit number.
>>
>> First I tried to find the location of the crash that you reported:
>>
>> $ hexedit grub-arm.efi # GRUB 35b909062
>>
>> 000060D4   33 7B 31 68  03 F0 0F 02  4F EA 13 1B  02 9B 5F 18
>> 000060E4   2F 44 04 2A  78 D8 DF E8  02 F0 03 03  43 6A 75 00
>> 000060F4   F0 89 11 B3  08 BB 79 1E  11 F8 01 2F  6A B9 40 F2
>> 00006104   FD 11 00 EB  50 10 FB F7  F8 FC 60 4B  03 EB 81 01
>>                         ^^^^^^^^^^^
>>
>> I analyzed the file with the tool available at
>> https://github.com/xypron/efi_analyzer
>>
>> $ efianalyze grub-arm.efi # GRUB 35b909062
>>
>> Offset to PE = 80
>> Machine type: 0x01c2, ARM or Thumb ("interworking")
>> Characteristics 0x30e
>> Image type: PE32
>> EFI application
>> ImageBase=0x0
>> SectionAlignment=0x1000
>> SizeOfImage=0x55000
>> .reloc.address=0x54000
>> .reloc.size=0x1000
>> BaseOfCode=0x1000
>> AddressOfEntryPoint=0x1000
>> Number of Sections 4
>> Section[0] .text
>> Virtual size 0x8000
>> Virtual address 0x1000
>> Size of raw data 0x8000
>> Pointer to raw data 0x1000
>> End of raw data 0x9000
>> Section[1] .data
>> Virtual size 0xb000
>> Virtual address 0x9000
>> Size of raw data 0xb000
>> Pointer to raw data 0x9000
>> End of raw data 0x14000
>> Section[2] mods
>> Virtual size 0x40000
>> Virtual address 0x14000
>> Size of raw data 0x40000
>> Pointer to raw data 0x14000
>> End of raw data 0x54000
>> Section[3] .reloc
>> Virtual size 0x1000
>> Virtual address 0x54000
>> Size of raw data 0x1000
>> Pointer to raw data 0x54000
>> End of raw data 0x55000
>>
>> So the entry-point is 0x1000 and the virtual address 0x1000 matches the
>> position in the file. That makes things easy.
>>
>> $ /usr/bin/arm-linux-gnueabihf-objdump -D -b binary -marm grub-arm.efi
>>
>>     1000:       e59fc010        ldr     ip, [pc, #16]   ; 0x1018
>>     1004:       e58c0000        str     r0, [ip]
>>     1008:       e59fc00c        ldr     ip, [pc, #12]   ; 0x101c
>>     100c:       e58c1000        str     r1, [ip]
>>     1010:       e59fc008        ldr     ip, [pc, #8]    ; 0x1020
>>     1014:       e12fff1c        bx      ip
>>     1018:       0000c914        andeq   ip, r0, r4, lsl r9
>>     101c:       0000c910        andeq   ip, r0, r0, lsl r9
>>     1020:       0000610d        andeq   r6, r0, sp, lsl #2
>>
>> This matches function _start() in grub-core/kern/arm/efi/startup.S:
>>
>>         ldr     ip, =EXT_C(grub_efi_image_handle)
>>         str     r0, [ip]
>>         ldr     ip, =EXT_C(grub_efi_system_table)
>>         str     r1, [ip]
>>         ldr     ip, =EXT_C(grub_main)
>>         bx      ip
>>         END
>>
>> So here we first store the image handle and the system table. Then we
>> branch to 610C in thumb mode (bit 0 is set in the address).
>>
>> The entry point is called in U-Boot via
>>
>> 0x47f8765c <efi_start_image+100>        ldr    r0, [sp, #4]
>>
>> 0x47f87660 <efi_start_image+104>        blx    r3
>>
>> So we have first a blx jump to ARM and then a bx jump to THUMB.
>>
>> TODO for me:
>>
>> According to
>> http://infocenter.arm.com/help/topic/com.arm.doc.uan0002a/UAN002A_1176-pan_use_of_blx.pdf
>> depending on the alignment of the blx command this sequence of commands
>> may fail on some ARM11 processors.
>>
>> But the BeagleBone Black has an ARMv7-A and not an ARM11 processor. So
>> nothing to worry us.
>>
>> The further disassembly depends on the start address:
>>
>> /usr/bin/arm-linux-gnueabihf-objdump -D -b binary -marm \
>> --disassembler-options=force-thumb grub-arm.efi --start-addr=0x6100
>>
>> 00006100 <.data+0x6100>:
>>     6100:       b96a            cbnz    r2, 0x611e
>>     6102:       f240 11fd       movw    r1, #509        ; 0x1fd
>>     6106:       eb00 1050       add.w   r0, r0, r0, lsr #5
>>     610a:       f7fb fcf8       bl      0x1afe
>>     610e:       4b60            ldr     r3, [pc, #384]  ; (0x6290)
>>     6110:       eb03 0181       add.w   r1, r3, r1, lsl #2
>>     6114:       684a            ldr     r2, [r1, #4]
>>     6116:       b942            cbnz    r2, 0x612a
>>
>> /usr/bin/arm-linux-gnueabihf-objdump -D -b binary -marm \
>> --disassembler-options=force-thumb grub-arm.efi --start-addr=0x610c
>>
>> 0000610c <.data+0x610c>:
>>     610c:       fcf8 4b60       ldc2l   11, cr4, [r8], #384
>> 				; 0x180 ; <UNPREDICTABLE>
>>     6110:       eb03 0181       add.w   r1, r3, r1, lsl #2
>>     6114:       684a            ldr     r2, [r1, #4]
>>     6116:       b942            cbnz    r2, 0x612a
>>     6118:       463a            mov     r2, r7
>>     611a:       495e            ldr     r1, [pc, #376]  ; (0x6294)
>>
>> So the next instruction after branching is
>> `ldc2l   11, cr4, [r8], #384`.
>>
>> Next I put your grub_arm.efi into directory tftp/ and started U-Boot
>> qemu_arm_defconfig with:
>>
>> qemu-system-arm -machine virt -cpu cortex-a15 \
>> -bios u-boot.bin -nographic -gdb tcp::1234 -netdev \
>> user,id=eth0,tftp=tftp,net=192.168.76.0/24,dhcpstart=192.168.76.9 \
>> -device e1000,netdev=eth0
>>
>> I displayed the relocation offset with command bdinfo:
>>
>> => bdinfo
>> arch_number = 0x00000000
>> boot_params = 0x00000000
>> DRAM bank   = 0x00000000
>> -> start    = 0x40000000
>> -> size     = 0x08000000
>> baudrate    = 115200 bps
>> TLB addr    = 0x47ff0000
>> relocaddr   = 0x47f4f000 <<<<<< You need this address
>> reloc off   = 0x47f4f000
>> irq_sp      = 0x46e0dec0
>> sp start    = 0x46e0deb0
>> Early malloc usage: 11c / 400
>> fdt_blob    = 0x46e0ded8
>>
>> In a separate mode I opened GDB:
>>
>> gdb-multiarch u-boot -ex 'target remote localhost:1234'
>>
>> (gdb) add-symbol-file u-boot 0x47f4f000
>> add symbol table from file "u-boot" at
>>         .text_addr = 0x47f4f000
>> (y or n) y
>> Reading symbols from u-boot...done.
>> (gdb) b efi_start_image
>> Breakpoint 1 at 0x385f8: efi_start_image. (2 locations)
>> (gdb) c
>> Continuing
>>
>> When debugging the ldc2l instruction at 610c caused the same error that
>> you already observed:
>>
>> => bootefi $kernel_addr_r $fdtcontroladdr
>> Found 0 disks
>> ## Starting EFI application at 40400000 ...
>> undefined instruction
>> pc : [<45cb610a>]          lr : [<47f87664>]
>> reloc pc : [<fdd6710a>]    lr : [<00038664>]
>> sp : 46e0dc28  ip : 45cb610d     fp : 47f6a324
>> r10: 00000003  r9 : 00000000     r8 : 46f11080
>> r7 : 40400000  r6 : 45e0c040     r5 : 00000000  r4 : 47f4f7c8
>> r3 : 45cb1000  r2 : 00000000     r1 : 47f4f7c8  r0 : 46f18010
>> Flags: nZCv  IRQs off  FIQs off  Mode SVC_32
>> Code: 1e79bb08 2f01f811 f240b96a eb0011fd (f7fb1050)
>> UEFI image [0x45cb0000:0x45d04fff] pc=0x610a '/grub_arm.efi'
>> Resetting CPU ...
>>
>> I have no clue why GRUB would try to transfer data to a co-processor
>> (ldc2l   11, cr4, [r8], #384).
>>
>> As I cannot find a match in git://git.savannah.gnu.org/grub.git I wonder
>> how you ended up with this in your GRUB.
>>
>> I will stop my analysis here. I hope with the information provided you
>> are able to take over.
>>
>> Best regards
>>
>> Heinrich
>>
> 
> On 3/8/19 2:12 PM, Adam Podogrocki wrote:> Hello Heinrich,
>>
>> Just for clarification
>> -
> http://git.savannah.gnu.org/cgit/grub.git/commit/?id=35b909062e7b334eb4af372be3260d0f62d85375
>> - it is a commit I am referring to as GRUB #35b909062
>>
>> I truly appreciate your help.
>>
>> Regards,
>> Adam Podogrocki
> 
> Thanks for pointing me to that commit.
> 
> I now have built that GRUB version with
> 
> ./configure --target=arm-linux-gnueabihf --with-platform=efi \
>   --disable-grub-emu-usb TARGET_CC=arm-linux-gnueabihf-gcc
> 
> Now I tried to find out what grub_main() looks like:
> 
> $ objdump -D -marm  grub-core/foo/usr/local/lib/grub/arm-efi/kernel.img
> 
> 00005ce4 <grub_main>:
>     5ce4:       b583            push    {r0, r1, r7, lr}
>     5ce6:       f7ff fffe       bl      48 <grub_machine_init>
>     5cea:       2002            movs    r0, #2
>     5cec:       4e74            ldr     r6, [pc, #464]
>     5cee:       f7ff ffc3       bl      5c78 <grub_list_remove+0x16>
>     5cf2:       4874            ldr     r0, [pc, #464]
>     5cf4:       f7ff fffe       bl      69b0 <grub_err_printf>
>     5cf8:       2000            movs    r0, #0
>     5cfa:       f7ff ffbd       bl      5c78 <grub_list_remove+0x16>
> 
> I found that code in your grub_arm.efi:
> 
> $ hexedit grub-arm.efi
> 
>                                                   v
> 00006D00   C0 18 70 47  18 C9 00 00  6D 69 6D 67 >83 B5 FA F7
> 00006D10   9B F9 02 20  74 4E FF F7  C3 FF 74 48  00 F0 6C FE
> 00006D20   00 20 FF F7  BD FF 33 68  E3 B1 19 68  70 4A 91 42
> 
> So what remains to find out, is why function _start() in
> grub-core/kern/arm/efi/startup.S is not jumping to 0x6D0d but to 0x610D.
> 
> This is the start of the relocation table:
> 
> 00054000   00 10 00 00  88 00 00 00  18 30 1C 30  20 30 2C 30
> 00054010   44 30 80 30  84 30 88 30  94 30 C4 30  C8 30 34 31
> 00054020   38 31 3C 31  40 31 44 31  B8 31 BC 31  C0 31 E8 33
> 00054030   EC 33 FC 33  00 34 04 34  08 34 0C 34  10 34 14 34
> 
> So we start with
> Page RVA = 0x1000
> Block Size = 0x88
> 
> and these relocations
> Type 3 - E_REL_BASED_HIGHLOW @ 0x018
> Type 3 - E_REL_BASED_HIGHLOW @ 0x01c
> Type 3 - E_REL_BASED_HIGHLOW @ 0x020
> 
> This matches the three addresses used in _start().
> 
> According to the PE-COFF spec:
> "To apply a base relocation, the difference is calculated between the
> preferred base address and the base where the image is actually loaded.
> If the image is loaded at its preferred base, the difference is zero and
> thus the base relocations do not have to be applied."
> 
> The preferred load address of the image is ImageBase = 0 and the section
> starting at 0x1000 has a VirtualAddress of 0x1000. So in our analysis
> above no relocation has to be considered.
> 
> Thus I would consider this a bug in GRUB.
> 
> Best regards
> 
> Heinrich
> 

Leif pointed me to this patch series:
https://lists.gnu.org/archive/html/grub-devel/2019-01/msg00113.html

He assumes than one of
[PATCH v4 1/2] mkimage: Use EFI32_HEADER_SIZE define in arm-efi case
[PATCH v4 2/2] mkimage: Align efi sections on 4k boundary
broke GRUB on armhf.

Best regards

Heinrich


More information about the U-Boot mailing list