mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
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:
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user