admin管理员组

文章数量:1291103

(This question is related, but concerns x86 legacy BIOS instead of UEFI).

We are developing an OS for x86_64 using UEFI. I'm finding that while the OS boots perfectly fine in the OVMF firmware in QEMU, the computer seems to hang forever with a black screen and no activity on all 4 pieces of real hardware I have tried (a Lenovo Thinkpad, a System76 laptop, a Steam Deck, and a random x86 SBC). Worse, when putting some code at the beginning of the entry point to try to show some life (triggering an exception, writing to ConOut, and writing to the serial port), the hang-with-no-activity result is the same, suggesting that the real hardware is failing to load the image before it ever reaches the entry point at all, or is jumping to the wrong address.

For reasons, we are rolling our own code to generate the PE image (i.e. not using any standard C tools) and cannot share that code. We can, however, share the header of the EFI as well as the first bootloader stage:

00000000  4d 5a 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |MZ..............|
00000010  b8 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 80 00 00 00  |................|
00000040  0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000050  69 73 20 70 72 6f 67 72  61 6d 20 63 61 6e 6e 6f  |is program canno|
00000060  74 20 62 65 20 72 75 6e  20 69 6e 20 44 4f 53 20  |t be run in DOS |
00000070  6d 6f 64 65 2e 0d 0d 0a  24 00 00 00 00 00 00 00  |mode....$.......|
00000080  50 45 00 00 64 86 03 00  00 00 00 00 00 00 00 00  |PE..d...........|
00000090  00 00 00 00 70 00 06 02  0b 02 02 26 00 10 00 00  |....p......&....|
000000a0  00 d0 16 00 00 00 00 00  00 10 00 00 00 10 00 00  |................|
000000b0  00 00 00 00 00 00 00 00  00 10 00 00 00 10 00 00  |................|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000d0  00 f0 16 00 00 10 00 00  00 00 00 00 0a 00 00 00  |................|
000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000110  00 10 00 00 00 10 00 00  00 10 00 00 00 10 00 00  |................|
00000120  00 00 00 00 00 00 00 00  00 00 00 00 20 00 00 60  |............ ..`|
00000130  00 00 00 00 00 00 00 00  00 80 11 00 00 20 00 00  |............. ..|
00000140  00 80 11 00 00 20 00 00  00 00 00 00 00 00 00 00  |..... ..........|
00000150  00 00 00 00 40 00 00 c0  00 00 00 00 00 00 00 00  |....@...........|
00000160  00 50 05 00 00 a0 11 00  00 50 05 00 00 a0 11 00  |.P.......P......|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 40 00 00 c0  |............@...|
00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000  51 52 48 89 e5 48 89 d3  48 c7 c2 54 00 21 00 52  |QRH..H..H..T.!.R|
00001010  48 ba 53 00 54 00 41 00  52 00 52 48 89 e2 48 83  |H.S.T.A.R.RH..H.|
00001020  ec 40 48 8b 4b 40 ff 51  08 48 89 ec 48 89 da 48  |[email protected]@.Q.H..H..H|
00001030  8b 42 60 68 01 00 00 00  59 89 ca 68 98 01 00 00  |.B`h....Y..h....|
00001040  41 58 68 00 00 00 01 49  89 e1 48 83 ec 48 ff 50  |AXh....I..H..H.P|
00001050  28 48 83 c4 48 5f 81 c7  00 00 08 00 57 68 00 80  |(H..H_......Wh..|
00001060  11 00 59 48 8d 35 96 0f  00 00 f3 a4 5f 48 8d 35  |..YH.5......_H.5|
00001070  8c 8f 11 00 68 7f 53 01  00 59 ad 01 3c 07 e2 fa  |....h.S..Y..<...|
00001080  5a 5e 89 fc 8b 07 50 c3  00 00 00 00 00 00 00 00  |Z^....P.........|
00001090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

(Disassembly of code section at 0x1000, which prints a message, then copies the other two sections to newly allocated pages of memory and jumps to one of them):

push rcx ; rcx contains EFI handle
push rdx ; rdx contains System Table
mov rbp, rsp
mov rbx, rdx
mov rdx, 0x210054 ; push L"T!"
push rdx
movabs rdx, 0x52004100540053 ; push L"STAR"
push rdx
mov rdx, rsp
sub rsp, 0x40
mov rcx, qword ptr [rbx + 0x40] ; ConOut
call qword ptr [rcx + 8] ; StringOutput
mov rsp, rbp
mov rdx, rbx
mov rax, qword ptr [rdx + 0x60] ; BootServices
push 1
pop rcx
mov edx, ecx
push 0x198
pop r8
push 0x1000000
mov r9, rsp
sub rsp, 0x48
call qword ptr [rax + 0x28] ; AllocatePages
add rsp, 0x48
pop rdi
add edi, 0x80000
push rdi
push 0x118000
pop rcx
lea rsi, qword ptr [rip + 0xf96] ; pointer to first section
rep movsb byte ptr es:[rdi], byte ptr [rsi]
pop rdi
lea rsi, qword ptr [rip + 0x118f8c] ; pointer to second section
push 0x1537f
pop rcx
lodsd eax, dword ptr [rsi]
add dword ptr [rdi + rax], edi
loop 0x1007a
pop rdx
pop rsi
mov esp, edi
mov eax, dword ptr [rdi]
push rax
ret 

I've attempted to verify correctness by comparing to other known good EFI files, such as Limine and the EFI Shell (using the PE-Bear utility). I've also attempted to get more information by running the executable in the EFI shell and using the Intel Management Engine. The result is unfortunately the same: works perfectly in QEMU, hangs with no output on real hardware.

ADDENDUM: The watchdog timer has no effect - the real hardware machine is still in the same hung state after 10 minutes. Also, Ctrl+Alt+Del does not work - I have to power cycle the machine.

EDIT 1: @prl pointed out that we need to provide the shadow register space for EFI function calls. That does fix some issues shown in QEMU, but changes nothing on real hardware. I have updated the dump and disassembly above.

(This question is related, but concerns x86 legacy BIOS instead of UEFI).

We are developing an OS for x86_64 using UEFI. I'm finding that while the OS boots perfectly fine in the OVMF firmware in QEMU, the computer seems to hang forever with a black screen and no activity on all 4 pieces of real hardware I have tried (a Lenovo Thinkpad, a System76 laptop, a Steam Deck, and a random x86 SBC). Worse, when putting some code at the beginning of the entry point to try to show some life (triggering an exception, writing to ConOut, and writing to the serial port), the hang-with-no-activity result is the same, suggesting that the real hardware is failing to load the image before it ever reaches the entry point at all, or is jumping to the wrong address.

For reasons, we are rolling our own code to generate the PE image (i.e. not using any standard C tools) and cannot share that code. We can, however, share the header of the EFI as well as the first bootloader stage:

00000000  4d 5a 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |MZ..............|
00000010  b8 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 80 00 00 00  |................|
00000040  0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000050  69 73 20 70 72 6f 67 72  61 6d 20 63 61 6e 6e 6f  |is program canno|
00000060  74 20 62 65 20 72 75 6e  20 69 6e 20 44 4f 53 20  |t be run in DOS |
00000070  6d 6f 64 65 2e 0d 0d 0a  24 00 00 00 00 00 00 00  |mode....$.......|
00000080  50 45 00 00 64 86 03 00  00 00 00 00 00 00 00 00  |PE..d...........|
00000090  00 00 00 00 70 00 06 02  0b 02 02 26 00 10 00 00  |....p......&....|
000000a0  00 d0 16 00 00 00 00 00  00 10 00 00 00 10 00 00  |................|
000000b0  00 00 00 00 00 00 00 00  00 10 00 00 00 10 00 00  |................|
000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000000d0  00 f0 16 00 00 10 00 00  00 00 00 00 0a 00 00 00  |................|
000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000110  00 10 00 00 00 10 00 00  00 10 00 00 00 10 00 00  |................|
00000120  00 00 00 00 00 00 00 00  00 00 00 00 20 00 00 60  |............ ..`|
00000130  00 00 00 00 00 00 00 00  00 80 11 00 00 20 00 00  |............. ..|
00000140  00 80 11 00 00 20 00 00  00 00 00 00 00 00 00 00  |..... ..........|
00000150  00 00 00 00 40 00 00 c0  00 00 00 00 00 00 00 00  |....@...........|
00000160  00 50 05 00 00 a0 11 00  00 50 05 00 00 a0 11 00  |.P.......P......|
00000170  00 00 00 00 00 00 00 00  00 00 00 00 40 00 00 c0  |............@...|
00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001000  51 52 48 89 e5 48 89 d3  48 c7 c2 54 00 21 00 52  |QRH..H..H..T.!.R|
00001010  48 ba 53 00 54 00 41 00  52 00 52 48 89 e2 48 83  |H.S.T.A.R.RH..H.|
00001020  ec 40 48 8b 4b 40 ff 51  08 48 89 ec 48 89 da 48  |[email protected]@.Q.H..H..H|
00001030  8b 42 60 68 01 00 00 00  59 89 ca 68 98 01 00 00  |.B`h....Y..h....|
00001040  41 58 68 00 00 00 01 49  89 e1 48 83 ec 48 ff 50  |AXh....I..H..H.P|
00001050  28 48 83 c4 48 5f 81 c7  00 00 08 00 57 68 00 80  |(H..H_......Wh..|
00001060  11 00 59 48 8d 35 96 0f  00 00 f3 a4 5f 48 8d 35  |..YH.5......_H.5|
00001070  8c 8f 11 00 68 7f 53 01  00 59 ad 01 3c 07 e2 fa  |....h.S..Y..<...|
00001080  5a 5e 89 fc 8b 07 50 c3  00 00 00 00 00 00 00 00  |Z^....P.........|
00001090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

(Disassembly of code section at 0x1000, which prints a message, then copies the other two sections to newly allocated pages of memory and jumps to one of them):

push rcx ; rcx contains EFI handle
push rdx ; rdx contains System Table
mov rbp, rsp
mov rbx, rdx
mov rdx, 0x210054 ; push L"T!"
push rdx
movabs rdx, 0x52004100540053 ; push L"STAR"
push rdx
mov rdx, rsp
sub rsp, 0x40
mov rcx, qword ptr [rbx + 0x40] ; ConOut
call qword ptr [rcx + 8] ; StringOutput
mov rsp, rbp
mov rdx, rbx
mov rax, qword ptr [rdx + 0x60] ; BootServices
push 1
pop rcx
mov edx, ecx
push 0x198
pop r8
push 0x1000000
mov r9, rsp
sub rsp, 0x48
call qword ptr [rax + 0x28] ; AllocatePages
add rsp, 0x48
pop rdi
add edi, 0x80000
push rdi
push 0x118000
pop rcx
lea rsi, qword ptr [rip + 0xf96] ; pointer to first section
rep movsb byte ptr es:[rdi], byte ptr [rsi]
pop rdi
lea rsi, qword ptr [rip + 0x118f8c] ; pointer to second section
push 0x1537f
pop rcx
lodsd eax, dword ptr [rsi]
add dword ptr [rdi + rax], edi
loop 0x1007a
pop rdx
pop rsi
mov esp, edi
mov eax, dword ptr [rdi]
push rax
ret 

I've attempted to verify correctness by comparing to other known good EFI files, such as Limine and the EFI Shell (using the PE-Bear utility). I've also attempted to get more information by running the executable in the EFI shell and using the Intel Management Engine. The result is unfortunately the same: works perfectly in QEMU, hangs with no output on real hardware.

ADDENDUM: The watchdog timer has no effect - the real hardware machine is still in the same hung state after 10 minutes. Also, Ctrl+Alt+Del does not work - I have to power cycle the machine.

EDIT 1: @prl pointed out that we need to provide the shadow register space for EFI function calls. That does fix some issues shown in QEMU, but changes nothing on real hardware. I have updated the dump and disassembly above.

Share Improve this question edited Feb 14 at 16:07 TheHans255 asked Feb 13 at 21:52 TheHans255TheHans255 2,2552 gold badges24 silver badges40 bronze badges 1
  • In my experience, this a symptom of an unhandled fault. I found UEFI programming much easier once I had a reliable fault handler that printed the processor state and returned to the EFI shell. – prl Commented Feb 14 at 5:06
Add a comment  | 

1 Answer 1

Reset to default 1

It is calling StringOutput without aligning the stack nor allocating the required 32 bytes of shadow space at the top of the stack before the call.

Add sub rsp, 0x28 before the call and I expect you will see your start message.

本文标签: