Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std: implement basic io and improve alloc in uefi #22226

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions lib/std/Thread.zig
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ else if (native_os == .linux)
LinuxThreadImpl
else if (native_os == .wasi)
WasiThreadImpl
else if (native_os == .uefi)
UefiThreadImpl
else
UnsupportedImpl;

Expand Down Expand Up @@ -1124,6 +1126,12 @@ const WasiThreadImpl = struct {
}
};

const UefiThreadImpl = struct {
fn getCurrentId() Id {
return 1;
}
};

const LinuxThreadImpl = struct {
const linux = std.os.linux;

Expand Down
2 changes: 1 addition & 1 deletion lib/std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ pub fn defaultPanic(

if (uefi.system_table.boot_services) |bs| {
// ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220)
const exit_data: []u16 = uefi.raw_pool_allocator.alloc(u16, exit_msg.len + 1) catch @trap();
const exit_data: []u16 = uefi.global_pool_allocator.allocator().alloc(u16, exit_msg.len + 1) catch @trap();
@memcpy(exit_data, exit_msg[0..exit_data.len]); // Includes null terminator.
_ = bs.exit(uefi.handle, .Aborted, exit_data.len, exit_data.ptr);
}
Expand Down
10 changes: 10 additions & 0 deletions lib/std/debug/SelfInfo.zig
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ pub fn getModuleForAddress(self: *SelfInfo, address: usize) !*Module {
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 @@ -146,6 +148,8 @@ pub fn getModuleNameForAddress(self: *SelfInfo, address: usize) ?[]const u8 {
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 @@ -500,6 +504,12 @@ fn lookupModuleWasm(self: *SelfInfo, address: usize) !*Module {
@panic("TODO implement lookup module for Wasm");
}

fn lookupModuleUefi(self: *SelfInfo, address: usize) !*Module {
_ = self;
_ = address;
@panic("TODO implement lookup module for UEFI");
}

pub const Module = switch (native_os) {
.macos, .ios, .watchos, .tvos, .visionos => struct {
base_address: usize,
Expand Down
4 changes: 2 additions & 2 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 @@ -52,7 +52,7 @@ pub const MAX_PATH_BYTES = @compileError("deprecated; renamed to 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,
Copy link
Contributor

@linusg linusg Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks wrong, I'd assume it needs to use similar logic as windows

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this ties in with #22226 (comment)

// 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 Down
2 changes: 1 addition & 1 deletion lib/std/fs/Dir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2787,4 +2787,4 @@ const assert = std.debug.assert;
const linux = std.os.linux;
const windows = std.os.windows;
const native_os = builtin.os.tag;
const have_flock = @TypeOf(posix.system.flock) != void;
const have_flock = @hasDecl(posix.system, "flock") and @TypeOf(posix.system.flock) != void;
3 changes: 3 additions & 0 deletions lib/std/fs/File.zig
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ pub fn supportsAnsiEscapeCodes(self: File) bool {
// stderr is always sanitized.
return false;
}
if (builtin.os.tag == .uefi) {
return false;
}
if (self.isTty()) {
if (self.handle == posix.STDOUT_FILENO or self.handle == posix.STDERR_FILENO) {
if (posix.getenvZ("TERM")) |term| {
Expand Down
2 changes: 2 additions & 0 deletions lib/std/heap.zig
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,8 @@ else if (builtin.target.os.tag == .plan9)
.ptr = undefined,
.vtable = &SbrkAllocator(std.os.plan9.sbrk).vtable,
}
else if (builtin.target.os.tag == .uefi)
std.os.uefi.global_page_allocator.allocator()
else
Allocator{
.ptr = undefined,
Expand Down
13 changes: 13 additions & 0 deletions lib/std/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const builtin = @import("builtin");
const root = @import("root");
const c = std.c;
const is_windows = builtin.os.tag == .windows;
const is_uefi = builtin.os.tag == .uefi;
const windows = std.os.windows;
const posix = std.posix;

Expand All @@ -23,6 +24,10 @@ fn getStdOutHandle() posix.fd_t {
return windows.peb().ProcessParameters.hStdOutput;
}

if (is_uefi) {
return .{ .simple_output = std.os.uefi.system_table.con_out.? };
}

if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdOutHandle")) {
return root.os.io.getStdOutHandle();
}
Expand All @@ -43,6 +48,10 @@ fn getStdErrHandle() posix.fd_t {
return windows.peb().ProcessParameters.hStdError;
}

if (is_uefi) {
return .{ .simple_output = std.os.uefi.system_table.std_err.? };
}

if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdErrHandle")) {
return root.os.io.getStdErrHandle();
}
Expand All @@ -63,6 +72,10 @@ fn getStdInHandle() posix.fd_t {
return windows.peb().ProcessParameters.hStdInput;
}

if (is_uefi) {
return .{ .simple_output = std.os.uefi.system_table.con_in.? };
}

if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdInHandle")) {
return root.os.io.getStdInHandle();
}
Expand Down
29 changes: 27 additions & 2 deletions lib/std/os/uefi.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const std = @import("../std.zig");

pub const posix = @import("uefi/posix.zig");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last I talked with Andrew about the future of std.posix, one thing we agreed on is that probably all Windows code in std.posix should be deleted. I would expect that the exact same thing is true of UEFI, as it is also not a POSIX platform in any meaningful sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree. The UEFI POSIX stuff is just a POSIX wrapper around the UEFI protocols. We can always ditch it. UEFI is close to Windows so I think whatever we do for Windows and POSIX, it would apply to UEFI.


/// A protocol is an interface identified by a GUID.
pub const protocol = @import("uefi/protocol.zig");
pub const DevicePath = @import("uefi/device_path.zig").DevicePath;
Expand All @@ -13,8 +15,31 @@ pub const tables = @import("uefi/tables.zig");
/// Defaults to .LoaderData, the default data allocation type
/// used by UEFI applications to allocate pool memory.
pub var efi_pool_memory_type: tables.MemoryType = .LoaderData;
pub const pool_allocator = @import("uefi/pool_allocator.zig").pool_allocator;
pub const raw_pool_allocator = @import("uefi/pool_allocator.zig").raw_pool_allocator;

const allocator = @import("uefi/allocator.zig");
pub const PageAllocator = allocator.Page;
pub const PoolAllocator = allocator.Pool;
pub const RawPoolAllocator = allocator.RawPool;

pub var global_page_allocator = PageAllocator{};
pub var global_pool_allocator = PoolAllocator{};

pub var working_directory: fd_t = .none;

pub const AT = posix.AT;
pub const CLOCK = posix.CLOCK;
pub const LOCK = posix.LOCK;
pub const NAME_MAX = posix.NAME_MAX;
pub const O = posix.O;
pub const PATH_MAX = posix.PATH_MAX;
pub const PATH_MAX_WIDE = posix.PATH_MAX_WIDE;
pub const S = posix.S;

pub const utsname = posix.utsname;
pub const Stat = posix.Stat;
pub const fd_t = posix.fd_t;
pub const ino_t = posix.ino_t;
pub const mode_t = posix.mode_t;

/// The EFI image's handle that is passed to its entry point.
pub var handle: Handle = undefined;
Expand Down
Loading