Merge pull request #18328 from ExpidusOS/feat/uefi-time

std: add support for getting the time in UEFI
This commit is contained in:
Veikka Tuominen 2023-12-26 01:03:10 +02:00 committed by GitHub
commit 94c63f31f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 40 additions and 1 deletions

View File

@ -131,6 +131,31 @@ pub const Time = extern struct {
/// Time is to be interpreted as local time
pub const unspecified_timezone: i16 = 0x7ff;
fn daysInYear(year: u16, maxMonth: u4) u32 {
const leapYear: std.time.epoch.YearLeapKind = if (std.time.epoch.isLeapYear(year)) .leap else .not_leap;
var days: u32 = 0;
var month: u4 = 0;
while (month < maxMonth) : (month += 1) {
days += std.time.epoch.getDaysInMonth(leapYear, @enumFromInt(month + 1));
}
return days;
}
pub fn toEpoch(self: std.os.uefi.Time) u64 {
var year: u16 = 0;
var days: u32 = 0;
while (year < (self.year - 1971)) : (year += 1) {
days += daysInYear(year + 1970, 12);
}
days += daysInYear(self.year, @as(u4, @intCast(self.month)) - 1) + self.day;
const hours = self.hour + (days * 24);
const minutes = self.minute + (hours * 60);
const seconds = self.second + (minutes * std.time.s_per_min);
return self.nanosecond + (seconds * std.time.ns_per_s);
}
};
/// Capabilities of the clock device

View File

@ -114,6 +114,13 @@ pub fn nanoTimestamp() i128 {
return ns;
}
if (builtin.os.tag == .uefi) {
var value: std.os.uefi.Time = undefined;
const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
assert(status == .Success);
return value.toEpoch();
}
var ts: os.timespec = undefined;
os.clock_gettime(os.CLOCK.REALTIME, &ts) catch |err| switch (err) {
error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
@ -176,7 +183,7 @@ pub const Instant = struct {
// true if we should use clock_gettime()
const is_posix = switch (builtin.os.tag) {
.wasi => builtin.link_libc,
.windows => false,
.windows, .uefi => false,
else => true,
};
@ -197,6 +204,13 @@ pub const Instant = struct {
return Instant{ .timestamp = ns };
}
if (builtin.os.tag == .uefi) {
var value: std.os.uefi.Time = undefined;
const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
if (status != .Success) return error.Unsupported;
return Instant{ .timestamp = value.toEpoch() };
}
// On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while suspended.
// On linux, use BOOTTIME instead of MONOTONIC as it ticks while suspended.
// On freebsd derivatives, use MONOTONIC_FAST as currently there's no precision tradeoff.