Skip to content

Commit 190bce9

Browse files
committed
Add EFI support for amd64 and arm64 platforms.
Some decisions points: - no external libc dependency, builtin functions replaced by Go equivalent (runtime_minimal_libc.go) - assembly efi_main entrypoint as assembly stub is required for sbat and few symbols anyway - a default sbat section (required for Linux shim secure boot) - dedicated rand reader in crypto/rand for EFI as it doesn't fit well with the generic machine interface - the timer calibration is deliberately simple but hopefully good enough for EFI purpose - no heap grow support, just get the biggest memory region available
1 parent e665b32 commit 190bce9

33 files changed

+1936
-71
lines changed

GNUmakefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,18 @@ endif
818818
@$(MD5SUM) test.hex
819819
$(TINYGO) build -size short -o test.hex -target=xiao-rp2350 examples/blinky1
820820
@$(MD5SUM) test.hex
821+
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 examples/echo2
822+
@$(MD5SUM) test.exe
823+
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 examples/empty
824+
@$(MD5SUM) test.exe
825+
$(TINYGO) build -size short -o test.exe -target=uefi-amd64 examples/time-offset
826+
@$(MD5SUM) test.exe
827+
$(TINYGO) build -size short -o test.exe -target=uefi-arm64 examples/echo2
828+
@$(MD5SUM) test.exe
829+
$(TINYGO) build -size short -o test.exe -target=uefi-arm64 examples/empty
830+
@$(MD5SUM) test.exe
831+
$(TINYGO) build -size short -o test.exe -target=uefi-arm64 examples/time-offset
832+
@$(MD5SUM) test.exe
821833
# test pwm
822834
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
823835
@$(MD5SUM) test.hex

builder/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
813813
}
814814
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
815815
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
816-
if config.GOOS() == "windows" {
816+
if config.GOOS() == "windows" || slices.Contains(config.Target.BuildTags, "uefi") {
817817
// Options for the MinGW wrapper for the lld COFF linker.
818818
ldflags = append(ldflags,
819819
"-Xlink=/opt:lldlto="+strconv.Itoa(speedLevel),

builder/builder_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os"
66
"path/filepath"
77
"runtime"
8+
"strings"
89
"testing"
910

1011
"github.com/tinygo-org/tinygo/compileopts"
@@ -35,6 +36,8 @@ func TestClangAttributes(t *testing.T) {
3536
"nintendoswitch",
3637
"riscv-qemu",
3738
"tkey",
39+
"uefi-amd64",
40+
"uefi-arm64",
3841
"wasip1",
3942
"wasip2",
4043
"wasm",
@@ -128,7 +131,7 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
128131
defer mod.Dispose()
129132

130133
// Check whether the LLVM target matches.
131-
if mod.Target() != config.Triple() {
134+
if mod.Target() != config.Triple() && !strings.HasPrefix(mod.Target(), config.Triple()) {
132135
t.Errorf("target has LLVM triple %#v but Clang makes it LLVM triple %#v", config.Triple(), mod.Target())
133136
}
134137

emulators/qemu-uefi-aarch64.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
binary=$1
6+
dir=$(dirname $binary)
7+
8+
mkdir -p ${dir}/qemu-disk/efi/boot
9+
mv $binary ${dir}/qemu-disk/efi/boot/bootaa64.efi
10+
11+
ovmf_path=${OVMF_CODE:-/usr/share/AAVMF/AAVMF_CODE.no-secboot.fd}
12+
13+
exec qemu-system-aarch64 -M virt -bios $ovmf_path -device virtio-rng-pci \
14+
-cpu max,pauth-impdef=on -drive format=raw,file=fat:rw:${dir}/qemu-disk \
15+
-net none -nographic -no-reboot

emulators/qemu-uefi-x86_64.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
binary=$1
6+
dir=$(dirname $binary)
7+
8+
mkdir -p ${dir}/qemu-disk/efi/boot
9+
mv $binary ${dir}/qemu-disk/efi/boot/bootx64.efi
10+
11+
ovmf_path=${OVMF_CODE:-/usr/share/qemu/OVMF.fd}
12+
13+
exec qemu-system-x86_64 -bios $ovmf_path -cpu qemu64,+rdrand -device virtio-rng-pci \
14+
-drive format=raw,file=fat:rw:${dir}/qemu-disk -net none -nographic -no-reboot

lib/stm32-svd

Submodule stm32-svd updated 161 files

src/crypto/rand/rand_uefi.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//go:build uefi
2+
3+
package rand
4+
5+
import (
6+
"errors"
7+
"machine/uefi"
8+
)
9+
10+
func init() {
11+
Reader = &reader{}
12+
}
13+
14+
type reader struct {
15+
}
16+
17+
func (r *reader) Read(b []byte) (n int, err error) {
18+
if !uefi.HasRNGSupport() {
19+
return 0, errors.New("no hardware rng available")
20+
} else if len(b) == 0 {
21+
return 0, nil
22+
}
23+
24+
var randomByte uint64
25+
for i := range b {
26+
if i%8 == 0 {
27+
var ok bool
28+
randomByte, ok = uefi.ReadRandom()
29+
if !ok {
30+
return n, errors.New("no random seed available")
31+
}
32+
} else {
33+
randomByte >>= 8
34+
}
35+
b[i] = byte(randomByte)
36+
}
37+
38+
return len(b), nil
39+
}

src/internal/task/task_stack_amd64.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build scheduler.tasks && amd64 && !windows
1+
//go:build scheduler.tasks && amd64 && !windows && !uefi
22

33
package task
44

src/internal/task/task_stack_amd64_windows.go renamed to src/internal/task/task_stack_amd64_winabi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//go:build scheduler.tasks && amd64 && windows
1+
//go:build scheduler.tasks && amd64 && (windows || uefi)
22

33
package task
44

src/machine/uefi/api.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//go:build uefi
2+
3+
package uefi
4+
5+
// callAsm is the single assembly stub for all UEFI calls.
6+
// It takes a function pointer, a pointer to an argument array, and the count.
7+
//
8+
//export uefiCall
9+
func callAsm(fn uintptr, args *uintptr, nargs uintptr) Status
10+
11+
// Call invokes a UEFI function with the given arguments via the MS x64 ABI.
12+
func Call(fn uintptr, args ...uintptr) Status {
13+
if len(args) == 0 {
14+
return callAsm(fn, nil, 0)
15+
}
16+
return callAsm(fn, &args[0], uintptr(len(args)))
17+
}

0 commit comments

Comments
 (0)