UEFI Invalid Opcode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
EatMoreCookies3
Posts: 4
Joined: Thu Sep 26, 2024 10:39 am

UEFI Invalid Opcode

Post by EatMoreCookies3 »

Happy New Year's everyone! I've been experimenting with UEFI via QEMU + OVMF. I put together my own EFI header's and starting putting together simple unit tests to validate said headers. Outputting to the console works great, but I've found that the EFI 'stall' instructions causes a #UD fault.

https://uefi.org/specs/UEFI/2.10_A/07_S ... ices-stall

Looking for help troubleshooting. Building Arch Linux 6.11, with QEMU version 9.1.0, and clang 19.1.0

❯ clang --version
clang version 19.1.0
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /home/eatmorecookies/opt/llvm19.1.0/bin

The OVMF_* files in the command below came from the Arch install.

Code: Select all

> qemu-system-x86_64 \
-drive if=pflash,format=raw,unit=0,readonly=on,file=OVMF_CODE.fd \
-drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd \
-drive file=uefi.img,if=ide \
-net none \
-display curses \
-nographic

Code: Select all

WARNING: Image format was not specified for 'uefi.img' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.

BdsDxe: loading Boot0001 "EFI Internal Shell" from Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
BdsDxe: starting Boot0001 "EFI Internal Shell" from Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
UEFI Interactive Shell v2.2
EDK II
UEFI v2.70 (EDK II, 0x00010000)
Mapping table
      FS0: Alias(s):HD0a1:;BLK1:
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,GPT,CBF14CDC-0386-4457-89E9-A0ED9DE5BEF3,0x800,0x16614)
     BLK0: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
     BLK2: Alias(s):
          PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)

Press ESC in 1 seconds to skip startup.nsh or any other key to continue.
Shell> fs0:
FS0:\>bootx64.efi
Executing stall instruction...
!!!! X64 Exception Type - 06(#UD - Invalid Opcode)  CPU Apic ID - 00000000 !!!!
RIP  - 00000000000B0000, CS  - 0000000000000038, RFLAGS - 0000000000010247
RAX  - 0000000006B15160, RCX - 0000000000000032, RDX - 0000000000000000
RBX  - 0000000000000000, RSP - 0000000007EFA458, RBP - 0000000007EFA500
RSI  - 0000000000000007, RDI - 00000000063C9418
R8   - 0000000000000000, R9  - 0000000007EF98DF, R10 - 0000000007EF98C0
R11  - 0000000000000260, R12 - 00000000063C9B98, R13 - 0000000007EFA568
R14  - 0000000007EFA6E8, R15 - 00000000062BA740
DS   - 0000000000000030, ES  - 0000000000000030, FS  - 0000000000000030
GS   - 0000000000000030, SS  - 0000000000000030
CR0  - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007801000
CR4  - 0000000000000668, CR8 - 0000000000000000
DR0  - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
DR3  - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400
GDTR - 00000000075DC000 0000000000000047, LDTR - 0000000000000000
IDTR - 0000000007249018 0000000000000FFF,   TR - 0000000000000000
FXSAVE_STATE - 0000000007EFA0B0
!!!! Can't find image information. !!!!
Here are the relevant compile and link flags from the Makefile. I've googled clang with EFI and tried variations of this but nothing has helped. What I'm using below seems to be the minimum that everyone agrees should be included.

Code: Select all

CC = clang
CFLAGS = -I ./include -target x86_64-unknown-windows -mno-red-zone -ffreestanding -fno-stack-protector
LD = lld-link
LDFLAGS = -entry:efi_main -subsystem:efi_application -dll

obj/boot/bootx64.efi: obj/boot/boot.o obj/boot/check_sum.o
        $(LD) $(LDFLAGS) $^ -out:$@

obj/boot/boot.o: src/boot/boot.c
        mkdir -p obj/boot
        $(CC) $(CFLAGS) -c $< -o $@

obj/boot/check_sum.o: src/boot/check_sum.c
        mkdir -p obj/boot
        $(CC) $(CFLAGS) -c $< -o $@
And here is the actual code:

Code: Select all

#include "efi/base_types.h"
#include "efi/system_table.h"
#include "check_sum.h" // printf definition

EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *console;

EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table)
{
        console = table->ConOut;

        printf(u"Executing stall instruction...\r\n");

        table->BootServices->Stall(50); // microseconds

        printf(u"Stall complete...\r\n");

        return EFI_SUCCESS;
}
Removing the call to the Stall command allows the code to run successfully.

Also, thinking it may be a mistake in my EFI headers, I substituted another set of EFI headers I found online but got the same result.

Thanks for any assistance!
Octocontrabass
Member
Member
Posts: 5623
Joined: Mon Mar 25, 2013 7:01 pm

Re: UEFI Invalid Opcode

Post by Octocontrabass »

EatMoreCookies3 wrote: Mon Dec 30, 2024 12:52 pm

Code: Select all

-drive file=uefi.img,if=ide \
This is unrelated, but you can use QEMU's virtual FAT disk image to skip creating a disk image every time you want to run your binary.
EatMoreCookies3 wrote: Mon Dec 30, 2024 12:52 pm

Code: Select all

Shell> fs0:
FS0:\>bootx64.efi
This is also unrelated, but OVMF will automatically execute your binary if you place it in the standard /efi/boot/ directory instead of the root directory.
EatMoreCookies3 wrote: Mon Dec 30, 2024 12:52 pm

Code: Select all

RIP  - 00000000000B0000,
The CPU is jumping somewhere it shouldn't. Since you've already checked your UEFI headers, I'd guess it's an ABI mismatch or a bug in your copy of OVMF. You should be able to rule out OVMF pretty easily by finding another copy somewhere else.
EatMoreCookies3 wrote: Mon Dec 30, 2024 12:52 pm

Code: Select all

CFLAGS = -I ./include -target x86_64-unknown-windows -mno-red-zone -ffreestanding -fno-stack-protector
There's never a red zone in the Windows ABI so you don't need "-mno-red-zone". You probably should use "-mgeneral-regs-only" since there's firmware out there that might not initialize all of those registers correctly.
EatMoreCookies3 wrote: Mon Dec 30, 2024 12:52 pm

Code: Select all

LDFLAGS = -entry:efi_main -subsystem:efi_application -dll
You don't need "-dll".
User avatar
zaval
Member
Member
Posts: 660
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: UEFI Invalid Opcode

Post by zaval »

Can't help much, looking from the phone, but it's rather obvious, you messed up your headers and transfer control to some non existent paradise location. I see you have some printing capabilities, if you can print numbers, I suggest you print out "table", and esp. "table->BootServices" pointers before jumping into there. But it's here where you fkd it up.
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
Post Reply