mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-18 03:24:00 +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
|
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 {
|
type EFI_BOOT_SERVICES struct {
|
||||||
Hdr EFI_TABLE_HEADER
|
Hdr EFI_TABLE_HEADER
|
||||||
raiseTPL uintptr
|
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)))
|
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 {
|
func (p *EFI_BOOT_SERVICES) CloseEvent(event EFI_EVENT) EFI_STATUS {
|
||||||
return UefiCall1(p.closeEvent, uintptr(event))
|
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"
|
const deviceName = "UEFI"
|
||||||
|
|
||||||
type (
|
type (
|
||||||
EFI_STATUS = deviceuefi.EFI_STATUS
|
EFI_STATUS = deviceuefi.EFI_STATUS
|
||||||
TextOutput = deviceuefi.TextOutput
|
EFI_TIME = deviceuefi.EFI_TIME
|
||||||
|
EFI_TIME_CAPABILITIES = deviceuefi.EFI_TIME_CAPABILITIES
|
||||||
|
TextOutput = deviceuefi.TextOutput
|
||||||
|
|
||||||
Error = deviceuefi.Error
|
Error = deviceuefi.Error
|
||||||
)
|
)
|
||||||
@@ -88,6 +90,10 @@ var (
|
|||||||
ErrHTTPError = deviceuefi.ErrHTTPError
|
ErrHTTPError = deviceuefi.ErrHTTPError
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetTime() (EFI_TIME, EFI_STATUS) {
|
||||||
|
return deviceuefi.GetTime()
|
||||||
|
}
|
||||||
|
|
||||||
func ConsoleOut() *TextOutput {
|
func ConsoleOut() *TextOutput {
|
||||||
return deviceuefi.ConsoleOut()
|
return deviceuefi.ConsoleOut()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,9 +56,8 @@ func sleepTicks(d timeUnit) {
|
|||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
if c == '\n' {
|
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])
|
uefi.ST().ConOut.OutputString(&buf[0])
|
||||||
return
|
|
||||||
}
|
}
|
||||||
buf := [2]uefi.CHAR16{uefi.CHAR16(c), 0}
|
buf := [2]uefi.CHAR16{uefi.CHAR16(c), 0}
|
||||||
uefi.ST().ConOut.OutputString(&buf[0])
|
uefi.ST().ConOut.OutputString(&buf[0])
|
||||||
@@ -103,6 +102,15 @@ func growHeap() bool {
|
|||||||
return false
|
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()) {
|
func SetWaitForEvents(f func()) {
|
||||||
waitForEventsFunction = f
|
waitForEventsFunction = f
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user