Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 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
4ea5256
Merge branch 'dev' into pr/minimal-uefi-target-support
sparques Jul 8, 2026
a3645f0
Merge branch 'dev' of ssh://github.com/tinygo-org/tinygo into pr/mini…
sparques Jul 8, 2026
3dc2ddf
Merge branch 'pr/minimal-uefi-target-support' of ssh://github.com/spa…
sparques Jul 8, 2026
031b449
do git restore upstream/dev for src/net
sparques Jul 8, 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
1 change: 1 addition & 0 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestClangAttributes(t *testing.T) {
"nintendoswitch",
"riscv-qemu",
"tkey",
"uefi-amd64",
"wasip1",
"wasip2",
"wasm",
Expand Down
111 changes: 111 additions & 0 deletions src/machine/machine_uefi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//go:build uefi

package machine

import (
deviceuefi "device/uefi"
)

const deviceName = "UEFI"

type (
EFI_STATUS = deviceuefi.EFI_STATUS
TextOutput = deviceuefi.TextOutput

Error = deviceuefi.Error
)

const (
EFI_SUCCESS = deviceuefi.EFI_SUCCESS
EFI_LOAD_ERROR = deviceuefi.EFI_LOAD_ERROR
EFI_INVALID_PARAMETER = deviceuefi.EFI_INVALID_PARAMETER
EFI_UNSUPPORTED = deviceuefi.EFI_UNSUPPORTED
EFI_BAD_BUFFER_SIZE = deviceuefi.EFI_BAD_BUFFER_SIZE
EFI_BUFFER_TOO_SMALL = deviceuefi.EFI_BUFFER_TOO_SMALL
EFI_NOT_READY = deviceuefi.EFI_NOT_READY
EFI_DEVICE_ERROR = deviceuefi.EFI_DEVICE_ERROR
EFI_WRITE_PROTECTED = deviceuefi.EFI_WRITE_PROTECTED
EFI_OUT_OF_RESOURCES = deviceuefi.EFI_OUT_OF_RESOURCES
EFI_VOLUME_CORRUPTED = deviceuefi.EFI_VOLUME_CORRUPTED
EFI_VOLUME_FULL = deviceuefi.EFI_VOLUME_FULL
EFI_NO_MEDIA = deviceuefi.EFI_NO_MEDIA
EFI_MEDIA_CHANGED = deviceuefi.EFI_MEDIA_CHANGED
EFI_NOT_FOUND = deviceuefi.EFI_NOT_FOUND
EFI_ACCESS_DENIED = deviceuefi.EFI_ACCESS_DENIED
EFI_NO_RESPONSE = deviceuefi.EFI_NO_RESPONSE
EFI_NO_MAPPING = deviceuefi.EFI_NO_MAPPING
EFI_TIMEOUT = deviceuefi.EFI_TIMEOUT
EFI_NOT_STARTED = deviceuefi.EFI_NOT_STARTED
EFI_ALREADY_STARTED = deviceuefi.EFI_ALREADY_STARTED
EFI_ABORTED = deviceuefi.EFI_ABORTED
EFI_ICMP_ERROR = deviceuefi.EFI_ICMP_ERROR
EFI_TFTP_ERROR = deviceuefi.EFI_TFTP_ERROR
EFI_PROTOCOL_ERROR = deviceuefi.EFI_PROTOCOL_ERROR
EFI_INCOMPATIBLE_VERSION = deviceuefi.EFI_INCOMPATIBLE_VERSION
EFI_SECURITY_VIOLATION = deviceuefi.EFI_SECURITY_VIOLATION
EFI_CRC_ERROR = deviceuefi.EFI_CRC_ERROR
EFI_END_OF_MEDIA = deviceuefi.EFI_END_OF_MEDIA
EFI_END_OF_FILE = deviceuefi.EFI_END_OF_FILE
EFI_INVALID_LANGUAGE = deviceuefi.EFI_INVALID_LANGUAGE
EFI_COMPROMISED_DATA = deviceuefi.EFI_COMPROMISED_DATA
EFI_IP_ADDRESS_CONFLICT = deviceuefi.EFI_IP_ADDRESS_CONFLICT
EFI_HTTP_ERROR = deviceuefi.EFI_HTTP_ERROR
)

var (
ErrLoadError = deviceuefi.ErrLoadError
ErrInvalidParameter = deviceuefi.ErrInvalidParameter
ErrUnsupported = deviceuefi.ErrUnsupported
ErrBadBufferSize = deviceuefi.ErrBadBufferSize
ErrBufferTooSmall = deviceuefi.ErrBufferTooSmall
ErrNotReady = deviceuefi.ErrNotReady
ErrDeviceError = deviceuefi.ErrDeviceError
ErrWriteProtected = deviceuefi.ErrWriteProtected
ErrOutOfResources = deviceuefi.ErrOutOfResources
ErrVolumeCorrupted = deviceuefi.ErrVolumeCorrupted
ErrVolumeFull = deviceuefi.ErrVolumeFull
ErrNoMedia = deviceuefi.ErrNoMedia
ErrMediaChanged = deviceuefi.ErrMediaChanged
ErrNotFound = deviceuefi.ErrNotFound
ErrAccessDenied = deviceuefi.ErrAccessDenied
ErrNoResponse = deviceuefi.ErrNoResponse
ErrNoMapping = deviceuefi.ErrNoMapping
ErrTimeout = deviceuefi.ErrTimeout
ErrNotStarted = deviceuefi.ErrNotStarted
ErrAlreadyStarted = deviceuefi.ErrAlreadyStarted
ErrAborted = deviceuefi.ErrAborted
ErrICMPError = deviceuefi.ErrICMPError
ErrTFTPError = deviceuefi.ErrTFTPError
ErrProtocolError = deviceuefi.ErrProtocolError
ErrIncompatibleVersion = deviceuefi.ErrIncompatibleVersion
ErrSecurityViolation = deviceuefi.ErrSecurityViolation
ErrCRCError = deviceuefi.ErrCRCError
ErrEndOfMedia = deviceuefi.ErrEndOfMedia
ErrEndOfFile = deviceuefi.ErrEndOfFile
ErrInvalidLanguage = deviceuefi.ErrInvalidLanguage
ErrCompromisedData = deviceuefi.ErrCompromisedData
ErrIPAddressConflict = deviceuefi.ErrIPAddressConflict
ErrHTTPError = deviceuefi.ErrHTTPError
)

func ConsoleOut() *TextOutput {
return deviceuefi.ConsoleOut()
}

func StandardError() *TextOutput {
return deviceuefi.StandardError()
}

func StatusError(status EFI_STATUS) *Error {
return deviceuefi.StatusError(status)
}

func (Pin) Configure(PinConfig) {
}

func (Pin) Set(bool) {
}

func (Pin) Get() bool {
return false
}
2 changes: 1 addition & 1 deletion src/runtime/baremetal_memory.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build baremetal
//go:build baremetal && !uefi

package runtime

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/gc_globals.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build baremetal || tinygo.wasm
//go:build (baremetal || tinygo.wasm) && !uefi

package runtime

Expand Down
9 changes: 9 additions & 0 deletions src/runtime/gc_leaking_uefi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//go:build gc.leaking && uefi

package runtime

import _ "unsafe"

//go:export tinygo_scanstack
func tinygo_scanstack() {
}
2 changes: 1 addition & 1 deletion src/runtime/interrupt/interrupt_none.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !baremetal || tkey
//go:build !baremetal || tkey || uefi

package interrupt

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/os_windows_pe.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build windows
//go:build windows || uefi

package runtime

Expand Down
132 changes: 132 additions & 0 deletions src/runtime/runtime_uefi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
//go:build uefi

package runtime

import "device/uefi"

//go:linkname procPin sync/atomic.runtime_procPin
func procPin() {
}

//go:linkname procUnpin sync/atomic.runtime_procUnpin
func procUnpin() {
}

var heapSize uintptr = 64 * 1024 * 1024
var heapStart, heapEnd uintptr
var stackTop uintptr
var allocatePagesAddress uefi.EFI_PHYSICAL_ADDRESS
var waitForEventsFunction = func() {
uefi.CpuPause()
}

func ticks() timeUnit {
return timeUnit(uefi.Ticks())
}

func nanosecondsToTicks(ns int64) timeUnit {
frequency := int64(uefi.TicksFrequency())
if frequency == 0 {
return timeUnit(ns)
}
seconds := ns / 1000000000
remainder := ns % 1000000000
return timeUnit(seconds*frequency + (remainder*frequency)/1000000000)
}

func ticksToNanoseconds(t timeUnit) int64 {
frequency := int64(uefi.TicksFrequency())
if frequency == 0 {
return int64(t)
}
return int64(t) * 1000000000 / frequency
}

func sleepTicks(d timeUnit) {
if d == 0 {
return
}
end := ticks() + d
for ticks() < end {
uefi.CpuPause()
}
}

func putchar(c byte) {
buf := [2]uefi.CHAR16{uefi.CHAR16(c), 0}
uefi.ST().ConOut.OutputString(&buf[0])
}

func exit(code int) {
uefi.BS().Exit(uefi.GetImageHandle(), uefi.EFI_STATUS(code), 0, nil)
}

func abort() {
uefi.BS().Exit(uefi.GetImageHandle(), uefi.EFI_ABORTED, 0, nil)
}

func preinit() {
uefi.BS().SetWatchdogTimer(0, 0, 0, nil)
if !growHeap() {
runtimePanic("could not allocate initial UEFI heap")
}
}

func growHeap() bool {
newHeapSize := ((heapSize * 4) / 3) &^ 4095
for newHeapSize >= heapSize {
pages := newHeapSize / 4096
status := uefi.BS().AllocatePages(
uefi.AllocateAnyPages,
uefi.EfiLoaderData,
uefi.UINTN(pages),
&allocatePagesAddress,
)
if status == uefi.EFI_SUCCESS {
heapStart = uintptr(allocatePagesAddress)
heapSize = newHeapSize
setHeapEnd(heapStart + heapSize)
return true
}
if status != uefi.EFI_OUT_OF_RESOURCES {
return false
}
newHeapSize /= 2
}
return false
}

func SetWaitForEvents(f func()) {
waitForEventsFunction = f
}

func waitForEvents() {
waitForEventsFunction()
}

//go:noinline
func runMain() {
run()
}

func buffered() int {
return 0
}

func getchar() byte {
return 0
}

//export efi_main
func main(imageHandle uintptr, systemTable uintptr) uintptr {
uefi.Init(imageHandle, systemTable)
preinit()
stackTop = getCurrentStackPointer()
runMain()

if heapStart != 0 {
uefi.BS().FreePages(uefi.EFI_PHYSICAL_ADDRESS(heapStart), uefi.UINTN(heapSize/4096))
}

return 0
}
32 changes: 32 additions & 0 deletions src/runtime/runtime_uefi_schednone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//go:build uefi && scheduler.none

package runtime

//go:noinline
func runProgram() {
runProgramInitRand()
runProgramInitHeap()
runProgramInitAll()
runProgramCallMain()
mainExited = true
}

//go:noinline
func runProgramInitRand() {
initRand()
}

//go:noinline
func runProgramInitHeap() {
initHeap()
}

//go:noinline
func runProgramInitAll() {
initAll()
}

//go:noinline
func runProgramCallMain() {
callMain()
}
3 changes: 3 additions & 0 deletions src/runtime/scheduler_cooperative.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ func sleep(duration int64) {
if duration <= 0 {
return
}
if schedulerSleepCustom(duration) {
return
}

addSleepTask(task.Current(), nanosecondsToTicks(duration))
task.Pause()
Expand Down
7 changes: 7 additions & 0 deletions src/runtime/sleep_custom_default.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !(scheduler.tasks && uefi)

package runtime

func schedulerSleepCustom(duration int64) bool {
return false
}
14 changes: 14 additions & 0 deletions src/runtime/sleep_custom_uefi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build scheduler.tasks && uefi

package runtime

//go:linkname gosched runtime.Gosched
func gosched()

func schedulerSleepCustom(duration int64) bool {
deadline := ticks() + nanosecondsToTicks(duration)
for ticks() < deadline {
gosched()
}
return true
}
2 changes: 1 addition & 1 deletion src/runtime/wait_other.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//go:build !tinygo.riscv && !cortexm && !(linux && !baremetal && !tinygo.wasm && !nintendoswitch) && !darwin && !wasip1
//go:build !tinygo.riscv && !cortexm && !(linux && !baremetal && !tinygo.wasm && !nintendoswitch) && !darwin && !wasip1 && !uefi

package runtime

Expand Down
Loading
Loading