Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b8a8e70
runtime: split baremetal memory setup
sparques May 1, 2026
e906cf7
runtime: extract Windows PE globals scan helper
sparques May 1, 2026
36d6c7c
compileopts,builder: add target linker flavor override
sparques May 1, 2026
2ad1004
machine,runtime,targets: add minimal uefi-amd64 target
sparques May 1, 2026
0d905c1
runtime,examples: add clean UEFI exit path test
sparques May 1, 2026
6ad501d
machine,x86: fix amd64 ABI stack handling
sparques May 1, 2026
2929a18
machine/uefi: add CHAR16 conversion helpers
sparques May 2, 2026
da76f63
machine/uefi: add loaded image protocol support
sparques May 2, 2026
f0cc366
runtime: add UEFI PE globals support
sparques May 2, 2026
84dd7a9
machine,runtime,x86: add UEFI time and text output support
sparques May 2, 2026
1cb0280
machine,runtime,x86: add UEFI text and time support
sparques May 2, 2026
408bfbb
machine,runtime,examples: add UEFI text input support
sparques May 2, 2026
308a0ff
machine,examples: add UEFI graphics output support
sparques May 3, 2026
8a7f085
add rest of STOP methods (direct UEFI ABI only)
sparques May 3, 2026
f62bc0e
runtime: fix UEFI sleep tick conversion
sparques May 4, 2026
d108e99
machine/uefi: make text input waits cooperative
sparques May 4, 2026
d13ac22
Merge remote-tracking branch 'upstream/dev' into feat/uefi-restack
sparques Jun 6, 2026
a38dd8d
Merge remote-tracking branch 'upstream/dev' into feat/uefi-restack
sparques Jun 6, 2026
43029f5
address TestClangAttributes/uefi-amd64 failure
sparques Jun 6, 2026
c552153
address TestConfigLinkerFlavor bug
sparques Jun 6, 2026
119691c
uefi: move raw bindings to device package
sparques Jun 7, 2026
cc08fe5
strip down implementation to bare minimum
sparques Jun 7, 2026
145969f
Merge branch 'dev' into pr/minimal-uefi-target-support
sparques Jun 7, 2026
5d19dd9
amd64: rename x86 package
sparques Jun 9, 2026
cd09e82
Merge branch 'pr/minimal-uefi-target-support' of ssh://github.com/spa…
sparques Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -842,22 +842,25 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
if config.GOOS() == "windows" {
// Options for the MinGW wrapper for the lld COFF linker.
switch config.LinkerFlavor() {
case "coff":
// Options for driving ld.lld in PE/COFF mode.
ldflags = append(ldflags,
"-Xlink=/opt:lldlto="+strconv.Itoa(speedLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"))
} else if config.GOOS() == "darwin" {
case "darwin":
// Options for the ld64-compatible lld linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(speedLevel),
"-cache_path_lto", filepath.Join(cacheDir, "thinlto"))
} else {
case "gnu":
// Options for the ELF linker.
ldflags = append(ldflags,
"--lto-O"+strconv.Itoa(speedLevel),
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
)
default:
return fmt.Errorf("unknown linker flavor: %s", config.LinkerFlavor())
}
if config.CodeModel() != "default" {
ldflags = append(ldflags,
Expand Down
1 change: 1 addition & 0 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TestClangAttributes(t *testing.T) {
"nintendoswitch",
"riscv-qemu",
"tkey",
"uefi-amd64",
"wasip1",
"wasip2",
"wasm",
Expand Down
20 changes: 20 additions & 0 deletions compileopts/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,26 @@ func (c *Config) LDFlags() []string {
return ldflags
}

// LinkerFlavor returns how the configured linker should be driven.
// Usually this is derived from GOOS, but targets may override it explicitly.
func (c *Config) LinkerFlavor() string {
if c.Target.LinkerFlavor != "" {
return c.Target.LinkerFlavor
}
goos := c.GOOS()
if goos == "" {
goos = c.Options.GOOS
}
switch goos {
case "windows":
return "coff"
case "darwin":
return "darwin"
default:
return "gnu"
}
}

// ExtraFiles returns the list of extra files to be built and linked with the
// executable. This can include extra C and assembly files.
func (c *Config) ExtraFiles() []string {
Expand Down
3 changes: 2 additions & 1 deletion compileopts/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ type TargetSpec struct {
Scheduler string `json:"scheduler,omitempty"`
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
Linker string `json:"linker,omitempty"`
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
LinkerFlavor string `json:"linker-flavor,omitempty"` // how to drive the configured linker (for example: gnu, coff, darwin)
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc,omitempty"`
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
Expand Down
48 changes: 48 additions & 0 deletions compileopts/target_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,51 @@ func TestOverrideProperties(t *testing.T) {
}

}

func TestConfigLinkerFlavor(t *testing.T) {
tests := []struct {
name string
target *TargetSpec
goos string
want string
}{
{
name: "default gnu",
target: &TargetSpec{},
goos: "linux",
want: "gnu",
},
{
name: "default coff",
target: &TargetSpec{},
goos: "windows",
want: "coff",
},
{
name: "default darwin",
target: &TargetSpec{},
goos: "darwin",
want: "darwin",
},
{
name: "target override",
target: &TargetSpec{
LinkerFlavor: "coff",
},
goos: "linux",
want: "coff",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
config := &Config{
Options: &Options{GOOS: tc.goos},
Target: tc.target,
}
if got := config.LinkerFlavor(); got != tc.want {
t.Fatalf("LinkerFlavor() = %q, want %q", got, tc.want)
}
})
}
}
4 changes: 4 additions & 0 deletions examples/uefi-exit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package main

func main() {
}
74 changes: 74 additions & 0 deletions src/device/amd64/cpu.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//go:build amd64

package amd64

const (
CPUIDTimeStampCounter = 0x15
CPUIDProcessorFrequency = 0x16
)

type CPUExtendedFamily uint16

const (
CPUFamilyIntelCore CPUExtendedFamily = 6
)

//export asmPause
func AsmPause()

//export asmReadRdtsc
func AsmReadRdtsc() uint64

//export asmCpuid
func AsmCpuid(index uint32, registerEax *uint32, registerEbx *uint32, registerEcx *uint32) int

var maxCpuidIndex uint32
var stdVendorName0 uint32
var stdCpuid1Eax uint32

func init() {
AsmCpuid(0, &maxCpuidIndex, &stdVendorName0, nil)
AsmCpuid(1, &stdCpuid1Eax, nil, nil)
}

func getExtendedCPUFamily() CPUExtendedFamily {
family := CPUExtendedFamily((stdCpuid1Eax >> 8) & 0x0f)
family += CPUExtendedFamily((stdCpuid1Eax >> 20) & 0xff)
return family
}

func isIntel() bool {
return stdVendorName0 == 0x756e6547
}

func isIntelFamilyCore() bool {
return isIntel() && getExtendedCPUFamily() == CPUFamilyIntelCore
}

func InternalGetPerformanceCounterFrequency() uint64 {
if maxCpuidIndex >= CPUIDTimeStampCounter {
return cpuidCoreClockCalculateTSCFrequency()
}
return 0
}

func cpuidCoreClockCalculateTSCFrequency() uint64 {
var eax uint32
var ebx uint32
var ecx uint32

AsmCpuid(CPUIDTimeStampCounter, &eax, &ebx, &ecx)
if eax == 0 || ebx == 0 {
return 0
}

coreCrystalFrequency := uint64(ecx)
if coreCrystalFrequency == 0 {
if !isIntelFamilyCore() {
return 0
}
coreCrystalFrequency = 24000000
}

return ((coreCrystalFrequency * uint64(ebx)) + (uint64(eax) / 2)) / uint64(eax)
}
39 changes: 39 additions & 0 deletions src/device/amd64/cpu_amd64.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.section .text

.global asmPause
asmPause:
pause
ret

.global asmReadRdtsc
asmReadRdtsc:
rdtsc
shlq $0x20, %rdx
orq %rdx, %rax
ret

.global asmCpuid
asmCpuid:
pushq %rbx

mov %ecx, %eax
pushq %rax

pushq %rdx
cpuid

test %r9, %r9
jz .SkipEcx
mov %ecx, (%r9)
.SkipEcx:
popq %rcx
jrcxz .SkipEax
mov %eax, (%rcx)
.SkipEax:
mov %r8, %rcx
jrcxz .SkipEbx
mov %ebx, (%rcx)
.SkipEbx:
popq %rax
popq %rbx
ret
17 changes: 17 additions & 0 deletions src/device/uefi/arch_x86.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//go:build i386 || amd64

package uefi

import "device/amd64"

func Ticks() uint64 {
return amd64.AsmReadRdtsc()
}

func CpuPause() {
amd64.AsmPause()
}

func getTSCFrequency() uint64 {
return amd64.InternalGetPerformanceCounterFrequency()
}
Loading
Loading