UEFI: Add support for UEFI time and UEFI events; fix STOP \n -> \r\n conversion (#5549)

* add support for UEFI time and UEFI events; fix STOP \n -> \r\n conversion

* apply EFI timezone offset
This commit is contained in:
Matthew Hiles
2026-07-24 13:29:42 -04:00
committed by GitHub
parent 528476f2b3
commit 259842dc2e
5 changed files with 151 additions and 4 deletions
+21
View File
@@ -0,0 +1,21 @@
package uefi
import _ "unsafe"
//go:linkname gosched runtime.Gosched
func gosched()
// WaitForEvent blocks while yielding to the TinyGo scheduler so other
// goroutines can continue to run.
func WaitForEvent(event EFI_EVENT) EFI_STATUS {
for {
status := BS().CheckEvent(event)
if status == EFI_SUCCESS {
return EFI_SUCCESS
}
if status != EFI_NOT_READY {
return status
}
gosched()
}
}
+8
View File
@@ -20,6 +20,10 @@ type EFI_RUNTIME_SERVICES struct {
queryVariableInfo uintptr
}
func (p *EFI_RUNTIME_SERVICES) GetTime(time *EFI_TIME, capabilities *EFI_TIME_CAPABILITIES) EFI_STATUS {
return UefiCall2(p.getTime, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(capabilities)))
}
type EFI_BOOT_SERVICES struct {
Hdr EFI_TABLE_HEADER
raiseTPL uintptr
@@ -82,6 +86,10 @@ func (p *EFI_BOOT_SERVICES) WaitForEvent(numberOfEvents UINTN, event *EFI_EVENT,
return UefiCall3(p.waitForEvent, uintptr(numberOfEvents), uintptr(unsafe.Pointer(event)), uintptr(unsafe.Pointer(index)))
}
func (p *EFI_BOOT_SERVICES) SignalEvent(event EFI_EVENT) EFI_STATUS {
return UefiCall1(p.signalEvent, uintptr(event))
}
func (p *EFI_BOOT_SERVICES) CloseEvent(event EFI_EVENT) EFI_STATUS {
return UefiCall1(p.closeEvent, uintptr(event))
}
+104
View File
@@ -0,0 +1,104 @@
package uefi
type EFI_TIME struct {
Year uint16
Month byte
Day byte
Hour byte
Minute byte
Second byte
Pad1 byte
Nanosecond uint32
TimeZone int16
Daylight byte
Pad2 byte
}
type EFI_TIME_CAPABILITIES struct {
Resolution uint32
Accuracy uint32
SetsToZero BOOLEAN
}
func GetTime() (EFI_TIME, EFI_STATUS) {
var time EFI_TIME
status := ST().RuntimeServices.GetTime(&time, nil)
return time, status
}
func (t *EFI_TIME) GetEpoch() (sec int64, nsec int32) {
if t.TimeZone != 0x07FF { // EFI_UNSPECIFIED_TIMEZONE
sec -= int64(t.TimeZone) * 60
}
year := int(t.Year)
month := int(t.Month)
d := daysSinceEpoch(year)
d += uint64(daysBefore[month-1])
if isLeap(year) && month > 2 {
d++
}
d += uint64(t.Day - 1)
abs := d * secondsPerDay
abs += uint64(uint64(t.Hour)*uint64(secondsPerHour) + uint64(t.Minute)*uint64(secondsPerMinute) + uint64(t.Second))
sec = int64(abs) + (absoluteToInternal + internalToUnix)
nsec = int32(t.Nanosecond)
return
}
const (
secondsPerMinute = 60
secondsPerHour = 60 * secondsPerMinute
secondsPerDay = 24 * secondsPerHour
daysPer400Years = 365*400 + 97
daysPer100Years = 365*100 + 24
daysPer4Years = 365*4 + 1
absoluteZeroYear = -292277022399
internalYear = 1
absoluteToInternal int64 = (absoluteZeroYear - internalYear) * 365.2425 * secondsPerDay
unixToInternal int64 = (1969*365 + 1969/4 - 1969/100 + 1969/400) * secondsPerDay
internalToUnix int64 = -unixToInternal
)
var daysBefore = [...]int32{
0,
31,
31 + 28,
31 + 28 + 31,
31 + 28 + 31 + 30,
31 + 28 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
}
func daysSinceEpoch(year int) uint64 {
y := uint64(int64(year) - absoluteZeroYear)
n := y / 400
y -= 400 * n
d := daysPer400Years * n
n = y / 100
y -= 100 * n
d += daysPer100Years * n
n = y / 4
y -= 4 * n
d += daysPer4Years * n
d += 365 * y
return d
}
func isLeap(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
+8 -2
View File
@@ -9,8 +9,10 @@ import (
const deviceName = "UEFI"
type (
EFI_STATUS = deviceuefi.EFI_STATUS
TextOutput = deviceuefi.TextOutput
EFI_STATUS = deviceuefi.EFI_STATUS
EFI_TIME = deviceuefi.EFI_TIME
EFI_TIME_CAPABILITIES = deviceuefi.EFI_TIME_CAPABILITIES
TextOutput = deviceuefi.TextOutput
Error = deviceuefi.Error
)
@@ -88,6 +90,10 @@ var (
ErrHTTPError = deviceuefi.ErrHTTPError
)
func GetTime() (EFI_TIME, EFI_STATUS) {
return deviceuefi.GetTime()
}
func ConsoleOut() *TextOutput {
return deviceuefi.ConsoleOut()
}
+10 -2
View File
@@ -56,9 +56,8 @@ func sleepTicks(d timeUnit) {
func putchar(c byte) {
if c == '\n' {
buf := [4]uefi.CHAR16{'\r', 0, '\n', 0}
buf := [2]uefi.CHAR16{uefi.CHAR16('\r'), 0}
uefi.ST().ConOut.OutputString(&buf[0])
return
}
buf := [2]uefi.CHAR16{uefi.CHAR16(c), 0}
uefi.ST().ConOut.OutputString(&buf[0])
@@ -103,6 +102,15 @@ func growHeap() bool {
return false
}
func init() {
mono := nanotime()
efiTime, status := uefi.GetTime()
if status == uefi.EFI_SUCCESS {
sec, nsec := efiTime.GetEpoch()
timeOffset.Store(sec*1000000000 + int64(nsec) - mono)
}
}
func SetWaitForEvents(f func()) {
waitForEventsFunction = f
}