Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
56f8c74
std.os.uefi: change Status enum to snake_case
truemedian Dec 19, 2023
dbcda37
std.os.uefi: add zig-like bindings for boot services
truemedian Dec 19, 2023
755af01
std.os.uefi: bind the rest of the system table functions, clean up im…
truemedian Dec 20, 2023
9cdd6db
std.os.uefi: add missing device path nodes, fix style and add documen…
truemedian Dec 26, 2023
ca6eaef
std.os.uefi: bind and fix console protocols
truemedian Dec 28, 2023
9fd071f
std.os.uefi: file protocols and improve std bindings
truemedian Dec 28, 2023
bbbd6ab
std.os.uefi: clean up allocator, add very basic std.os bindings for r…
truemedian Jan 15, 2024
1a150d6
std.os.uefi: fix bugs, add basic debug support
truemedian Jan 17, 2024
2fa76b3
std.debug: preliminary current stack trace for uefi
truemedian Jan 24, 2024
e10ff35
std.debug: transform uefi case into generic unwind failure
truemedian Jan 25, 2024
2be2ec4
improve std bindings, add path_to_text
truemedian Feb 6, 2024
9fece05
std.os.uefi: add DiskIo, prepare for service bindings
truemedian Feb 7, 2024
9146371
work
truemedian Feb 20, 2024
f365d4b
std.os.uefi: add DiskIo and PartitionInfo protocols
truemedian Feb 21, 2024
d5733d2
std.os.uefi: revert ucontext, it is no longer necessary
truemedian Apr 3, 2024
cdcf14e
work
truemedian Apr 3, 2024
d0b50e5
std.os.uefi: fix regressions introduced in rebase
truemedian Apr 3, 2024
b6505ab
std.os.uefi: add uefi to posix and fs.path membership, remove uefi wo…
truemedian Apr 4, 2024
5e70d28
std.os.uefi: fix getFdPath
truemedian Apr 4, 2024
8431767
std.os.uefi: posix membership part 2
truemedian Apr 6, 2024
2d5880b
std.os.uefi: posix membership part 3, and bug fixes galore
truemedian Apr 9, 2024
4a0f619
fix memcpy typo
truemedian Apr 19, 2024
04ec5b2
Merge remote-tracking branch 'truemedian/uefi-rework' into feat/uefi-…
RossComputerGuy Apr 19, 2024
ab302cb
Make the compiler build for UEFI
RossComputerGuy Apr 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/std/Build/Cache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ pub const Manifest = struct {
// WASI does not currently support flock, so we bypass it here.
// TODO: If/when flock is supported on WASI, this check should be removed.
// See https://github.com/WebAssembly/wasi-filesystem/issues/2
if (builtin.os.tag != .wasi or std.process.can_spawn or !builtin.single_threaded) {
if (builtin.os.tag != .wasi or builtin.os.tag != .uefi or std.process.can_spawn or !builtin.single_threaded) {
const manifest_file = self.manifest_file.?;
try manifest_file.downgradeLock();
}
Expand All @@ -945,7 +945,7 @@ pub const Manifest = struct {
// WASI does not currently support flock, so we bypass it here.
// TODO: If/when flock is supported on WASI, this check should be removed.
// See https://github.com/WebAssembly/wasi-filesystem/issues/2
if (builtin.os.tag != .wasi or std.process.can_spawn or !builtin.single_threaded) {
if (builtin.os.tag != .wasi or builtin.os.tag != .uefi or std.process.can_spawn or !builtin.single_threaded) {
const manifest_file = self.manifest_file.?;
// Here we intentionally have a period where the lock is released, in case there are
// other processes holding a shared lock.
Expand Down
48 changes: 0 additions & 48 deletions lib/std/builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -784,54 +784,6 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
std.debug.print("{s}", .{msg});
std.posix.abort();
},
.uefi => {
const uefi = std.os.uefi;

const ExitData = struct {
pub fn create_exit_data(exit_msg: []const u8, exit_size: *usize) ![*:0]u16 {
// Need boot services for pool allocation
if (uefi.system_table.boot_services == null) {
return error.BootServicesUnavailable;
}

// ExitData buffer must be allocated using boot_services.allocatePool
var utf16: []u16 = try uefi.raw_pool_allocator.alloc(u16, 256);
errdefer uefi.raw_pool_allocator.free(utf16);

if (exit_msg.len > 255) {
return error.MessageTooLong;
}

var fmt: [256]u8 = undefined;
const slice = try std.fmt.bufPrint(&fmt, "\r\nerr: {s}\r\n", .{exit_msg});
const len = try std.unicode.utf8ToUtf16Le(utf16, slice);

utf16[len] = 0;

exit_size.* = 256;

return @as([*:0]u16, @ptrCast(utf16.ptr));
}
};

var exit_size: usize = 0;
const exit_data = ExitData.create_exit_data(msg, &exit_size) catch null;

if (exit_data) |data| {
if (uefi.system_table.std_err) |out| {
_ = out.setAttribute(uefi.protocol.SimpleTextOutput.red);
_ = out.outputString(data);
_ = out.setAttribute(uefi.protocol.SimpleTextOutput.white);
}
}

if (uefi.system_table.boot_services) |bs| {
_ = bs.exit(uefi.handle, .Aborted, exit_size, exit_data);
}

// Didn't have boot_services, just fallback to whatever.
std.posix.abort();
},
.cuda, .amdhsa => std.posix.abort(),
.plan9 => {
var status: [std.os.plan9.ERRMAX]u8 = undefined;
Expand Down
22 changes: 17 additions & 5 deletions lib/std/child_process.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const native_os = builtin.os.tag;
pub const ChildProcess = struct {
pub const Id = switch (native_os) {
.windows => windows.HANDLE,
.wasi => void,
.wasi, .uefi => void,
else => posix.pid_t,
};

Expand Down Expand Up @@ -47,10 +47,16 @@ pub const ChildProcess = struct {
stderr_behavior: StdIo,

/// Set to change the user id when spawning the child process.
uid: if (native_os == .windows or native_os == .wasi) void else ?posix.uid_t,
uid: switch (native_os) {
.windows, .wasi, .uefi => void,
else => ?posix.uid_t,
},

/// Set to change the group id when spawning the child process.
gid: if (native_os == .windows or native_os == .wasi) void else ?posix.gid_t,
gid: switch (native_os) {
.windows, .wasi, .uefi => void,
else => ?posix.gid_t,
},

/// Set to change the current working directory when spawning the child process.
cwd: ?[]const u8,
Expand Down Expand Up @@ -169,8 +175,14 @@ pub const ChildProcess = struct {
.term = null,
.env_map = null,
.cwd = null,
.uid = if (native_os == .windows or native_os == .wasi) {} else null,
.gid = if (native_os == .windows or native_os == .wasi) {} else null,
.uid = switch (native_os) {
.windows, .wasi, .uefi => {},
else => null,
},
.gid = switch (native_os) {
.windows, .wasi, .uefi => {},
else => null,
},
.stdin = null,
.stdout = null,
.stderr = null,
Expand Down
77 changes: 72 additions & 5 deletions lib/std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const pdb = std.pdb;
const root = @import("root");
const File = std.fs.File;
const windows = std.os.windows;
const uefi = std.os.uefi;
const native_arch = builtin.cpu.arch;
const native_os = builtin.os.tag;
const native_endian = native_arch.endian();
Expand Down Expand Up @@ -687,6 +688,22 @@ pub const StackIterator = struct {
}

return true;
} else if (native_os == .uefi) {
if (uefi.system_table.boot_services) |boot_services| {
var map = boot_services.getMemoryMap(std.heap.page_allocator) catch return true;
defer map.deinit(std.heap.page_allocator);

var it = map.iterator();
while (it.next()) |entry| {
if (entry.physical_start <= address and address < entry.physical_start + entry.number_of_pages * mem.page_size) {
return true;
}
}

return false;
} else {
return true;
}
} else if (@hasDecl(posix.system, "msync") and native_os != .wasi and native_os != .emscripten) {
posix.msync(aligned_memory, posix.MSF.ASYNC) catch |err| {
switch (err) {
Expand Down Expand Up @@ -792,7 +809,11 @@ pub fn writeCurrentStackTrace(
} else null) orelse StackIterator.init(start_addr, null);
defer it.deinit();

// When true, the stack unwinder failed completely to produce a single frame.
var stack_unwind_missing = true;
while (it.next()) |return_address| {
stack_unwind_missing = false;

printLastUnwindError(&it, debug_info, out_stream, tty_config);

// On arm64 macOS, the address of the last frame is 0x0 rather than 0x1 as on x86_64 macOS,
Expand All @@ -803,6 +824,11 @@ pub fn writeCurrentStackTrace(
const address = if (return_address == 0) return_address else return_address - 1;
try printSourceAtAddress(debug_info, out_stream, address, tty_config);
} else printLastUnwindError(&it, debug_info, out_stream, tty_config);

// If the stack unwinder failed, print the top level frame via the given start_addr if available. This is not ideal, but it is better than nothing.
if (stack_unwind_missing and start_addr != null) {
try printSourceAtAddress(debug_info, out_stream, start_addr.?, tty_config);
}
}

pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const windows.CONTEXT) usize {
Expand Down Expand Up @@ -1051,6 +1077,7 @@ pub fn openSelfDebugInfo(allocator: mem.Allocator) OpenSelfDebugInfoError!DebugI
.solaris,
.illumos,
.windows,
.uefi,
=> return try DebugInfo.init(allocator),
else => return error.UnsupportedOperatingSystem,
}
Expand Down Expand Up @@ -1090,7 +1117,11 @@ fn readCoffDebugInfo(allocator: mem.Allocator, coff_obj: *coff.Coff) !ModuleDebu
di.dwarf = dwarf;
}

const raw_path = try coff_obj.getPdbPath() orelse return di;
const raw_path = if (native_os == .uefi) // this is a workaround because pdb paths are never UEFI paths
std.fs.path.basenameWindows(try coff_obj.getPdbPath() orelse return di)
else
try coff_obj.getPdbPath() orelse return di;

const path = blk: {
if (fs.path.isAbsolute(raw_path)) {
break :blk raw_path;
Expand Down Expand Up @@ -1758,6 +1789,8 @@ pub const DebugInfo = struct {
return self.lookupModuleHaiku(address);
} else if (comptime builtin.target.isWasm()) {
return self.lookupModuleWasm(address);
} else if (native_os == .uefi) {
return self.lookupModuleUefi(address);
} else {
return self.lookupModuleDl(address);
}
Expand All @@ -1775,6 +1808,8 @@ pub const DebugInfo = struct {
return null;
} else if (comptime builtin.target.isWasm()) {
return null;
} else if (native_os == .uefi) {
return null;
} else {
return self.lookupModuleNameDl(address);
}
Expand Down Expand Up @@ -1983,6 +2018,37 @@ pub const DebugInfo = struct {
return null;
}

fn lookupModuleUefi(self: *DebugInfo, address: usize) !*ModuleDebugInfo {
if (uefi.system_table.boot_services) |boot_services| {
const handles = try boot_services.locateHandleBuffer(.{ .by_protocol = &uefi.protocol.LoadedImage.guid });
defer boot_services.freePool(mem.sliceAsBytes(handles));

for (handles) |handle| {
const loaded_image: *const uefi.protocol.LoadedImage = try boot_services.openProtocol(handle, uefi.protocol.LoadedImage, .{});

if (address >= @intFromPtr(loaded_image.image_base) and address < @intFromPtr(loaded_image.image_base) + loaded_image.image_size) {
if (self.address_map.get(@intFromPtr(loaded_image.image_base))) |obj_di| {
return obj_di;
}

const obj_di = try self.allocator.create(ModuleDebugInfo);
errdefer self.allocator.destroy(obj_di);

const mapped_module = @as([*]const u8, @ptrFromInt(@intFromPtr(loaded_image.image_base)))[0..loaded_image.image_size];
var coff_obj = try coff.Coff.init(mapped_module, true);

obj_di.* = try readCoffDebugInfo(self.allocator, &coff_obj);
obj_di.base_address = @intFromPtr(loaded_image.image_base);

try self.address_map.putNoClobber(@intFromPtr(loaded_image.image_base), obj_di);
return obj_di;
}
}
}

return error.MissingDebugInfo;
}

fn lookupModuleNameDl(self: *DebugInfo, address: usize) ?[]const u8 {
_ = self;

Expand Down Expand Up @@ -2416,10 +2482,11 @@ pub const ModuleDebugInfo = switch (native_os) {
_ = allocator;
_ = address;

return switch (self.debug_data) {
.dwarf => |*dwarf| dwarf,
else => null,
};
if (self.dwarf) |*dwarf| {
return dwarf;
}

return null;
}
},
.linux, .netbsd, .freebsd, .dragonfly, .openbsd, .haiku, .solaris, .illumos => struct {
Expand Down
31 changes: 28 additions & 3 deletions lib/std/fs.zig
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub const File = @import("fs/File.zig");
pub const path = @import("fs/path.zig");

pub const has_executable_bit = switch (native_os) {
.windows, .wasi => false,
.windows, .wasi, .uefi => false,
else => true,
};

Expand Down Expand Up @@ -53,7 +53,7 @@ pub const MAX_PATH_BYTES = max_path_bytes;
/// * On other platforms, `[]u8` file paths are opaque sequences of bytes with
/// no particular encoding.
pub const max_path_bytes = switch (native_os) {
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .illumos, .plan9, .emscripten, .wasi => posix.PATH_MAX,
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .illumos, .plan9, .emscripten, .wasi, .uefi => posix.PATH_MAX,
// Each WTF-16LE code unit may be expanded to 3 WTF-8 bytes.
// If it would require 4 WTF-8 bytes, then there would be a surrogate
// pair in the WTF-16LE, and we (over)account 3 bytes for it that way.
Expand All @@ -74,7 +74,7 @@ pub const max_path_bytes = switch (native_os) {
/// On WASI, file name components are encoded as valid UTF-8.
/// On other platforms, `[]u8` components are an opaque sequence of bytes with no particular encoding.
pub const MAX_NAME_BYTES = switch (native_os) {
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .illumos => posix.NAME_MAX,
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .illumos, .uefi => posix.NAME_MAX,
// Haiku's NAME_MAX includes the null terminator, so subtract one.
.haiku => posix.NAME_MAX - 1,
// Each WTF-16LE character may be expanded to 3 WTF-8 bytes.
Expand Down Expand Up @@ -682,6 +682,31 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
else => |e| return e,
};
},
.uefi => {
const uefi = std.os.uefi;

if (uefi.system_table.boot_services) |boot_services| {
const loaded_image = boot_services.openProtocol(uefi.handle, uefi.protocol.LoadedImage, .{}) catch return error.FileNotFound;

const file_path = if (loaded_image.file_path.node()) |node| file_path: {
if (node == .media and node.media == .file_path)
break :file_path node.media.file_path.path();

return error.FileNotFound;
} else return error.FileNotFound;

if (file_path.len > uefi.PATH_MAX_WIDE) return error.NameTooLong;

// required because device paths are not aligned
var alignment_buffer: [uefi.PATH_MAX_WIDE]u16 = undefined;
@memcpy(alignment_buffer[0..file_path.len], file_path);

const len = std.unicode.wtf16LeToWtf8(out_buffer, alignment_buffer[0..file_path.len]);
return out_buffer[0..len];
}

return error.FileNotFound;
},
else => @compileError("std.fs.selfExePath not supported for this target"),
}
}
Expand Down
19 changes: 19 additions & 0 deletions lib/std/fs/Dir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,22 @@ pub const Iterator = switch (native_os) {
self.cookie = std.os.wasi.DIRCOOKIE_START;
}
},
.uefi => struct {
dir: Dir,

const Self = @This();

pub const Error = IteratorError;

pub fn next(self: *Self) Error!?Entry {
_ = self;
return null;
}

pub fn reset(self: *Self) void {
_ = self;
}
},
else => @compileError("unimplemented"),
};

Expand Down Expand Up @@ -641,6 +657,9 @@ fn iterateImpl(self: Dir, first_iter_start_value: bool) Iterator {
.end_index = 0,
.buf = undefined,
},
.uefi => return Iterator{
.dir = self,
},
else => @compileError("unimplemented"),
}
}
Expand Down
5 changes: 4 additions & 1 deletion lib/std/fs/File.zig
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ pub fn supportsAnsiEscapeCodes(self: File) bool {

return self.isCygwinPty();
}
if (builtin.os.tag == .uefi) {
// The UEFI console only supports a tiny subset of ANSI escape codes, primarily for color.
return false;
}
if (builtin.os.tag == .wasi) {
// WASI sanitizes stdout when fd is a tty so ANSI escape codes
// will not be interpreted as actual cursor commands, and
Expand Down Expand Up @@ -455,7 +459,6 @@ pub fn stat(self: File) StatError!Stat {
.ctime = windows.fromSysTime(info.BasicInformation.ChangeTime),
};
}

if (builtin.os.tag == .wasi and !builtin.link_libc) {
const st = try std.os.fstat_wasi(self.handle);
return Stat.fromWasi(st);
Expand Down
3 changes: 2 additions & 1 deletion lib/std/fs/get_app_data_dir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi
else => return error.AppDataDirUnavailable,
}
},
.uefi => return std.process.getCwdAlloc(allocator) catch error.AppDataDirUnavailable,
else => @compileError("Unsupported OS"),
}
}

test getAppDataDir {
if (native_os == .wasi) return error.SkipZigTest;
if (native_os == .wasi or native_os == .uefi) return error.SkipZigTest;

// We can't actually validate the result
const dir = getAppDataDir(std.testing.allocator, "zig") catch return;
Expand Down
Loading