authorgravatar for mail@linusgroh.deLinus Groh <mail@linusgroh.de> 2025-03-03 10:07:41+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-03-03 10:07:41+00:00
log6d29ef0bafa3a6d1646658b9bb88c2326f3720a1
tree91d88ca1d295d908baefa4886b0186efe1e1ffe7
parent00a8742bbf71b5175b52ecdf736fb4a53ab8177f
parent3bea47883aae5c7585a27d4b751d656dd723576d
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #23046 from linusg/uefi-time

Three time-related fixes for UEFI

2 files changed, 52 insertions(+), 42 deletions(-)

lib/std/os/uefi.zig+19-11
...@@ -113,31 +113,39 @@ pub const Time = extern struct {...@@ -113,31 +113,39 @@ pub const Time = extern struct {
113 /// 0 - 59113 /// 0 - 59
114 second: u8,114 second: u8,
115115
116 _pad1: u8,
117
116 /// 0 - 999999999118 /// 0 - 999999999
117 nanosecond: u32,119 nanosecond: u32,
118120
119 /// The time's offset in minutes from UTC.121 /// The time's offset in minutes from UTC.
120 /// Allowed values are -1440 to 1440 or unspecified_timezone122 /// Allowed values are -1440 to 1440 or unspecified_timezone
121 timezone: i16,123 timezone: i16,
122 daylight: packed struct {124 daylight: packed struct(u8) {
123 _pad1: u6,
124
125 /// If true, the time has been adjusted for daylight savings time.125 /// If true, the time has been adjusted for daylight savings time.
126 in_daylight: bool,126 in_daylight: bool,
127127
128 /// If true, the time is affected by daylight savings time.128 /// If true, the time is affected by daylight savings time.
129 adjust_daylight: bool,129 adjust_daylight: bool,
130
131 _: u6,
130 },132 },
131133
134 _pad2: u8,
135
136 comptime {
137 std.debug.assert(@sizeOf(Time) == 16);
138 }
139
132 /// Time is to be interpreted as local time140 /// Time is to be interpreted as local time
133 pub const unspecified_timezone: i16 = 0x7ff;141 pub const unspecified_timezone: i16 = 0x7ff;
134142
135 fn daysInYear(year: u16, maxMonth: u4) u32 {143 fn daysInYear(year: u16, max_month: u4) u9 {
136 const leapYear: std.time.epoch.YearLeapKind = if (std.time.epoch.isLeapYear(year)) .leap else .not_leap;144 const leap_year: std.time.epoch.YearLeapKind = if (std.time.epoch.isLeapYear(year)) .leap else .not_leap;
137 var days: u32 = 0;145 var days: u9 = 0;
138 var month: u4 = 0;146 var month: u4 = 0;
139 while (month < maxMonth) : (month += 1) {147 while (month < max_month) : (month += 1) {
140 days += std.time.epoch.getDaysInMonth(leapYear, @enumFromInt(month + 1));148 days += std.time.epoch.getDaysInMonth(leap_year, @enumFromInt(month + 1));
141 }149 }
142 return days;150 return days;
143 }151 }
...@@ -151,9 +159,9 @@ pub const Time = extern struct {...@@ -151,9 +159,9 @@ pub const Time = extern struct {
151 }159 }
152160
153 days += daysInYear(self.year, @as(u4, @intCast(self.month)) - 1) + self.day;161 days += daysInYear(self.year, @as(u4, @intCast(self.month)) - 1) + self.day;
154 const hours = self.hour + (days * 24);162 const hours: u64 = self.hour + (days * 24);
155 const minutes = self.minute + (hours * 60);163 const minutes: u64 = self.minute + (hours * 60);
156 const seconds = self.second + (minutes * std.time.s_per_min);164 const seconds: u64 = self.second + (minutes * std.time.s_per_min);
157 return self.nanosecond + (seconds * std.time.ns_per_s);165 return self.nanosecond + (seconds * std.time.ns_per_s);
158 }166 }
159};167};
lib/std/time.zig+33-31
...@@ -135,7 +135,7 @@ pub const Instant = struct {...@@ -135,7 +135,7 @@ pub const Instant = struct {
135 const clock_id = switch (builtin.os.tag) {135 const clock_id = switch (builtin.os.tag) {
136 .windows => {136 .windows => {
137 // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.137 // QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
138 return Instant{ .timestamp = windows.QueryPerformanceCounter() };138 return .{ .timestamp = windows.QueryPerformanceCounter() };
139 },139 },
140 .wasi => {140 .wasi => {
141 var ns: std.os.wasi.timestamp_t = undefined;141 var ns: std.os.wasi.timestamp_t = undefined;
...@@ -147,7 +147,7 @@ pub const Instant = struct {...@@ -147,7 +147,7 @@ pub const Instant = struct {
147 var value: std.os.uefi.Time = undefined;147 var value: std.os.uefi.Time = undefined;
148 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);148 const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
149 if (status != .success) return error.Unsupported;149 if (status != .success) return error.Unsupported;
150 return Instant{ .timestamp = value.toEpoch() };150 return .{ .timestamp = value.toEpoch() };
151 },151 },
152 // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while152 // On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while
153 // suspended.153 // suspended.
...@@ -185,36 +185,38 @@ pub const Instant = struct {...@@ -185,36 +185,38 @@ pub const Instant = struct {
185 /// This assumes that the `earlier` Instant represents a moment in time before or equal to `self`.185 /// This assumes that the `earlier` Instant represents a moment in time before or equal to `self`.
186 /// This also assumes that the time that has passed between both Instants fits inside a u64 (~585 yrs).186 /// This also assumes that the time that has passed between both Instants fits inside a u64 (~585 yrs).
187 pub fn since(self: Instant, earlier: Instant) u64 {187 pub fn since(self: Instant, earlier: Instant) u64 {
188 if (builtin.os.tag == .windows) {188 switch (builtin.os.tag) {
189 // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA189 .windows => {
190 // (a read-only page of info updated and mapped by the kernel to all processes):190 // We don't need to cache QPF as it's internally just a memory read to KUSER_SHARED_DATA
191 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data191 // (a read-only page of info updated and mapped by the kernel to all processes):
192 // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm192 // https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
193 const qpc = self.timestamp - earlier.timestamp;193 // https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
194 const qpf = windows.QueryPerformanceFrequency();194 const qpc = self.timestamp - earlier.timestamp;
195195 const qpf = windows.QueryPerformanceFrequency();
196 // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.196
197 // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701197 // 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
198 const common_qpf = 10_000_000;198 // https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
199 if (qpf == common_qpf) {199 const common_qpf = 10_000_000;
200 return qpc * (ns_per_s / common_qpf);200 if (qpf == common_qpf) {
201 }201 return qpc * (ns_per_s / common_qpf);
202202 }
203 // Convert to ns using fixed point.203
204 const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf));204 // Convert to ns using fixed point.
205 const result = (@as(u96, qpc) * scale) >> 32;205 const scale = @as(u64, std.time.ns_per_s << 32) / @as(u32, @intCast(qpf));
206 return @as(u64, @truncate(result));206 const result = (@as(u96, qpc) * scale) >> 32;
207 }207 return @as(u64, @truncate(result));
208208 },
209 // WASI timestamps are directly in nanoseconds209 .uefi, .wasi => {
210 if (builtin.os.tag == .wasi) {210 // UEFI and WASI timestamps are directly in nanoseconds
211 return self.timestamp - earlier.timestamp;211 return self.timestamp - earlier.timestamp;
212 },
213 else => {
214 // Convert timespec diff to ns
215 const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec));
216 const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec));
217 return elapsed - @as(u32, @intCast(earlier.timestamp.nsec));
218 },
212 }219 }
213
214 // Convert timespec diff to ns
215 const seconds = @as(u64, @intCast(self.timestamp.sec - earlier.timestamp.sec));
216 const elapsed = (seconds * ns_per_s) + @as(u32, @intCast(self.timestamp.nsec));
217 return elapsed - @as(u32, @intCast(earlier.timestamp.nsec));
218 }220 }
219};221};
220222