[U-Boot] [BUG] Crash when starting grub-arm.efi on BeagleBone Black
Heinrich Schuchardt
xypron.glpk at gmx.de
Fri Mar 8 20:39:12 UTC 2019
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
More information about the U-Boot
mailing list