mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-15 16:33:40 +00:00
targets: minimal uefi target support (#5452)
* runtime: split baremetal memory setup * runtime: extract Windows PE globals scan helper * compileopts,builder: add target linker flavor override * machine,runtime,targets: add minimal uefi-amd64 target * runtime,examples: add clean UEFI exit path test * machine,x86: fix amd64 ABI stack handling * machine/uefi: add CHAR16 conversion helpers * machine/uefi: add loaded image protocol support * runtime: add UEFI PE globals support * machine,runtime,x86: add UEFI time and text output support * machine,runtime,x86: add UEFI text and time support * machine,runtime,examples: add UEFI text input support * machine,examples: add UEFI graphics output support * add rest of STOP methods (direct UEFI ABI only) * runtime: fix UEFI sleep tick conversion * machine/uefi: make text input waits cooperative * address TestClangAttributes/uefi-amd64 failure * address TestConfigLinkerFlavor bug * uefi: move raw bindings to device package * strip down implementation to bare minimum * amd64: rename x86 package * do git restore upstream/dev for src/net * add smoketest for uefi-amd64; add required zeroSizeAllocPtr constant * address PR issues: remove unused files; make putchar() insert '\r' before '\n' * swap lines around
This commit is contained in:
@@ -657,6 +657,8 @@ smoketest: testchdir
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pico2-ice examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -o test.efi -target=uefi-amd64 examples/test
|
||||||
|
@$(MD5SUM) test.efi
|
||||||
# test simulated boards on play.tinygo.org
|
# test simulated boards on play.tinygo.org
|
||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino_uno examples/blinky1
|
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino_uno examples/blinky1
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ func TestClangAttributes(t *testing.T) {
|
|||||||
"nintendoswitch",
|
"nintendoswitch",
|
||||||
"riscv-qemu",
|
"riscv-qemu",
|
||||||
"tkey",
|
"tkey",
|
||||||
|
"uefi-amd64",
|
||||||
"wasip1",
|
"wasip1",
|
||||||
"wasip2",
|
"wasip2",
|
||||||
"wasm",
|
"wasm",
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build baremetal
|
//go:build baremetal && !uefi
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build baremetal || tinygo.wasm
|
//go:build (baremetal || tinygo.wasm) && !uefi
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
//go:build gc.leaking && uefi
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
//go:export tinygo_scanstack
|
||||||
|
func tinygo_scanstack() {
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !baremetal || tkey
|
//go:build !baremetal || tkey || uefi
|
||||||
|
|
||||||
package interrupt
|
package interrupt
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build windows
|
//go:build windows || uefi
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
//go:build uefi
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import "device/uefi"
|
||||||
|
|
||||||
|
const zeroSizeAllocPtr uintptr = 16
|
||||||
|
|
||||||
|
//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) {
|
||||||
|
if c == '\n' {
|
||||||
|
buf := [4]uefi.CHAR16{'\r', 0, '\n', 0}
|
||||||
|
uefi.ST().ConOut.OutputString(&buf[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -248,6 +248,9 @@ func sleep(duration int64) {
|
|||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if schedulerSleepCustom(duration) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
addSleepTask(task.Current(), nanosecondsToTicks(duration))
|
addSleepTask(task.Current(), nanosecondsToTicks(duration))
|
||||||
task.Pause()
|
task.Pause()
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build !(scheduler.tasks && uefi)
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
func schedulerSleepCustom(duration int64) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -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
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"build-tags": ["uefi", "baremetal", "linux", "amd64"],
|
||||||
|
"llvm-target": "x86_64-unknown-windows-gnu",
|
||||||
|
"cpu": "x86-64",
|
||||||
|
"features": "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87",
|
||||||
|
"goos": "linux",
|
||||||
|
"goarch": "amd64",
|
||||||
|
"gc": "leaking",
|
||||||
|
"scheduler": "none",
|
||||||
|
"linker": "ld.lld",
|
||||||
|
"linker-flavor": "coff",
|
||||||
|
"libc": "picolibc",
|
||||||
|
"automatic-stack-size": false,
|
||||||
|
"default-stack-size": 65536,
|
||||||
|
"cflags": [
|
||||||
|
"-Werror",
|
||||||
|
"-fshort-enums",
|
||||||
|
"-fomit-frame-pointer",
|
||||||
|
"-fno-exceptions", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables",
|
||||||
|
"-ffunction-sections", "-fdata-sections",
|
||||||
|
"-ffreestanding",
|
||||||
|
"-fshort-wchar",
|
||||||
|
"-mno-red-zone"
|
||||||
|
],
|
||||||
|
"ldflags": [
|
||||||
|
"-m", "i386pep",
|
||||||
|
"--image-base", "0x400000",
|
||||||
|
"--entry", "efi_main",
|
||||||
|
"--subsystem", "efi_application",
|
||||||
|
"-Bdynamic",
|
||||||
|
"--gc-sections",
|
||||||
|
"--no-insert-timestamp",
|
||||||
|
"--no-dynamicbase"
|
||||||
|
],
|
||||||
|
"extra-files": [
|
||||||
|
"src/device/amd64/cpu_amd64.S",
|
||||||
|
"src/device/uefi/asm_amd64.S",
|
||||||
|
"src/runtime/asm_amd64_windows.S"
|
||||||
|
],
|
||||||
|
"gdb": ["gdb-multiarch", "gdb"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user