Skip to content

Pr/minimal uefi target support#5452

Open
sparques wants to merge 23 commits into
tinygo-org:devfrom
sparques:pr/minimal-uefi-target-support
Open

Pr/minimal uefi target support#5452
sparques wants to merge 23 commits into
tinygo-org:devfrom
sparques:pr/minimal-uefi-target-support

Conversation

@sparques

@sparques sparques commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a minimal uefi-amd64 target to TinyGo.

The intent is to land the smallest useful slice of UEFI support first:

  • target definition for uefi-amd64
  • PE/COFF linking support through ld.lld
  • minimal UEFI runtime entry/exit path
  • minimal firmware bindings needed for startup, console output, timing, and heap allocation
  • a tiny clean-exit example for validation

This PR does not try to upstream the larger protocol surface from the previous UEFI branch. It is intentionally limited
to getting a basic UEFI application built and run as a TinyGo baremetal target.

What this adds

  • targets/uefi-amd64.json
  • generic target-controlled linker flavor selection, so a target can request PE/COFF-style ld.lld handling without a UEFI-
    specific builder special case
  • minimal device/uefi support for:
    • system table access
    • boot services calls
    • text output
    • simple timing support
  • minimal UEFI runtime support for:
    • efi_main entry
    • heap allocation through AllocatePages
    • clean return from a do-nothing application
  • minimal amd64 support code needed by this target
  • examples/uefi-exit as a simple regression-style smoke example

What this does not add

This PR intentionally leaves out higher-level UEFI features, including:

  • filesystem protocols
  • graphics output
  • networking
  • serial I/O
  • environment variables / argument handling
  • broader protocol coverage

Those can be added in follow-up PRs once the target itself is established.

Design notes

TinyGo baremetal targets commonly use goos: "linux" for runtime selection, and this target follows that existing
convention.

The unusual part of UEFI is not the runtime model, but the output format: the target must produce a valid PE/COFF image. The linker changes here keep the working ld.lld-based approach, but move it behind a generic target property instead of a UEFI-specific special case in the builder.

The runtime in this PR is intentionally minimal:

  • gc=leaking
  • scheduler=none

That keeps the initial target small and reduces the number of moving pieces needed for first upstream support.

Testing

Built successfully with:

./build/tinygo build -size short -o /tmp/tinygo-uefi-empty.exe -target=uefi-amd64 examples/empty
./build/tinygo build -size short -o /tmp/tinygo-uefi-exit.exe -target=uefi-amd64 ./examples/uefi-exit

Observed behavior:

- firmware accepts the generated PE/COFF image
- examples/empty runs as expected
- examples/uefi-exit cleanly returns to firmware (this is more of a challenge than it sounds)

@sparques

sparques commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

@deadprogram, I do have a lot more features implemented like text input, graphics output, time functions, etc, but this is as small as I could make the diff and still produce an executable .efi file.

@sparques

sparques commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

If you want to try out a hello world you can compile:

tinygo build -target=uefi-amd64 -scheduler=none -gc=leaking -o hello.efi hello.go

And if you have qemu and OVMF / tianocore firmware installed you can do:

qemu-system-x86_64 -m 1g -bios /usr/share/ovmf/x64/OVMF.4m.fd -hdb fat:rw:$PWD

Select the efi shell, type fs0: and then run hello.efi

image

@deadprogram

Copy link
Copy Markdown
Member

@sparques this PR is very hard to review due to having so many commits as well as changes. Is there some way you could reduce into a smaller number of more atomic commits?

Also, we need people with more UEFI knowledge than I have to help out once it is a bit easier to review.

Thank you!

@b0ch3nski

Copy link
Copy Markdown
Contributor

I'm not an UEFI expert though I've looked over this PR and it actually looks like its the minimal effort possible on getting hello world (but do not take my words for granted!).

The only thing I've noticed is a src/device/x86 directory that holds the file guarded by amd64 build tag which might be a little bit misleading - someone could assume that amd64 should live in x86-64 directory :) So I'd just rename this dir to amd64.

@sparques

sparques commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@deadprogram Here's what I can think of doing; let me know if this is the right direction or if I need to rethink it:

  1. Split out builder changes, but don't include the uefi-amd64 target. This would be the LinkerFlavor stuff and the like that lets us use COFF linker with GOOS=linux
  2. Split out device/uefi package; this can exist in isolation by itself and not affect anything.
  3. Everything else: uefi-amd target json, runtime and machine package changes.

I don't see a way to meaningfully break this down further, but I'm not the sharpest crayon in the box and am open to suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants