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

Conversation

RossComputerGuy
Copy link
Contributor

Largely based on #19486, this PR marks me starting to work on UEFI support in Zig again. This time, there will be multiple PR's instead of one so it becomes easier to manage. This PR simply makes the zig init example build.

I tested this in QEMU by loading in OVMF, entering the UEFI shell, loading FS0:\bin\$.efi. The zig-out can be shared by adding: -drive file=fat:rw:zig-out.
image

@@ -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.

@@ -66,7 +66,7 @@ pub fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
Impl.wake(ptr, max_waiters);
}

const Impl = if (builtin.single_threaded)
const Impl = if (builtin.single_threaded or builtin.os.tag == .uefi)
Copy link
Member

Choose a reason for hiding this comment

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

Should UEFI be treated as a proper single-threaded target?

zig/src/target.zig

Lines 66 to 81 in 82f35c5

pub fn alwaysSingleThreaded(target: std.Target) bool {
_ = target;
return false;
}
pub fn defaultSingleThreaded(target: std.Target) bool {
switch (target.cpu.arch) {
.wasm32, .wasm64 => return true,
else => {},
}
switch (target.os.tag) {
.haiku => return true,
else => {},
}
return false;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I just didn't know where the source was which defined that heh.

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've updated this and changed the defaultSingleThreaded for UEFI.

Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, is UEFI not always single threaded instead of just default single threaded?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You technically could implement a form of multithreading, just like with wasm. It's just builtin.single_threaded will default to true when single_threaded is not changed in your build. You probably could write a custom scheduler + mutltithreading stuff and use root.os stuff to get it working but no implementation will be made for upstream.

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 learned somewhat recently that UEFI does have EFI_MP_SERVICES_PROTOCOL so there is a way to do multiprocessing but not multithreading but likely is still out of the scope.

@@ -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)


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

Choose a reason for hiding this comment

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

Not sure if turning a compile error into a non-functional stub is that useful? Most people will assume the standard library functions work for a certain target if they compile.

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 hadn't figured out how to implement it just yet. I'll leave it out of this PR and work on it later on.

/// Allocates memory in pages.
///
/// This allocator is backed by `allocatePages` and is therefore only suitable for usage when Boot Services are available.
pub const PageAllocator = struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

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 have changed it now, hopefully it doesn't violate the fully qualified namespace stuff.

if (@errorReturnTrace()) |trace| {
std.debug.dumpStackTrace(trace.*);
}
std.time.sleep(5 * std.time.ns_per_s);
Copy link
Contributor

Choose a reason for hiding this comment

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

Magic sleep needs a comment

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This part of the code is based on what @truemedian did. I'm not sure either so CC'ing them for some information.

Copy link
Contributor

Choose a reason for hiding this comment

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

Magic sleep here was a debugging aid to prevent the uefi firmware from clearing the screen before I could read the any output because once EfiMain returns it will go to the next boot loader. Not necessary at all, unless that window to eead the error is desired.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I likely will remove it and it'll be up to the program to do that if they want to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants