From 63d56c532d4485ff03f59ae0e79043e23bcc63d9 Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Thu, 25 Jul 2019 12:16:03 +0200 Subject: [PATCH 01/23] src/target.cpp: UEFI improvements --- src/target.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/target.cpp b/src/target.cpp index 6a949270aefa274a2daefc69cc053616109cbdeb..d80c917f6e9bb1ff79138a1a90a9d80930f6b700 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -989,7 +989,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) { } bool target_allows_addr_zero(const ZigTarget *target) { - return target->os == OsFreestanding; + return target->os == OsFreestanding || target->os == OsUefi; } const char *target_o_file_ext(const ZigTarget *target) { @@ -1414,12 +1414,12 @@ bool target_supports_fpic(const ZigTarget *target) { } bool target_supports_stack_probing(const ZigTarget *target) { - return target->os != OsWindows && (target->arch == ZigLLVM_x86 || target->arch == ZigLLVM_x86_64); + return target->os != OsWindows && target->os != OsUefi && (target->arch == ZigLLVM_x86 || target->arch == ZigLLVM_x86_64); } bool target_requires_pic(const ZigTarget *target, bool linking_libc) { // This function returns whether non-pic code is completely invalid on the given target. - return target->os == OsWindows || target_os_requires_libc(target->os) || + return target->os == OsWindows || target->os == OsUefi || target_os_requires_libc(target->os) || (linking_libc && target_is_glibc(target)); } -- 2.54.0 From 6e8ef5b6f2205ada3f2c1b4769aefdfc61aca39e Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Fri, 26 Jul 2019 15:42:50 +0200 Subject: [PATCH 02/23] std/build.zig: add checks for UEFI --- std/build.zig | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/std/build.zig b/std/build.zig index 3a0c34c8d1ae2ad9dde4f4b304623b8067631ce6..f12631ffb97cb58e499d83207d6ba95af58b7653 100644 --- a/std/build.zig +++ b/std/build.zig @@ -1174,6 +1174,13 @@ pub const Target = union(enum) { }; } + pub fn isUefi(self: Target) bool { + return switch (self.getOs()) { + .uefi => true, + else => false, + }; + } + pub fn isWasm(self: Target) bool { return switch (self.getArch()) { .wasm32, .wasm64 => true, @@ -1484,7 +1491,7 @@ pub const LibExeObjStep = struct { } pub fn producesPdbFile(self: *LibExeObjStep) bool { - if (!self.target.isWindows()) return false; + if (!self.target.isWindows() and !self.target.isUefi()) return false; if (self.strip) return false; return self.isDynamicLibrary() or self.kind == .Exe; } @@ -1581,7 +1588,7 @@ pub const LibExeObjStep = struct { /// Unless setOutputDir was called, this function must be called only in /// the make step, from a step that has declared a dependency on this one. pub fn getOutputPdbPath(self: *LibExeObjStep) []const u8 { - assert(self.target.isWindows()); + assert(self.target.isWindows() or self.target.isUefi()); return fs.path.join( self.builder.allocator, [_][]const u8{ self.output_dir.?, self.out_pdb_filename }, -- 2.54.0 From b979fc1bcd6d1bdc19b7f518498fb8c9740d6dea Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Sun, 28 Jul 2019 23:51:51 +0200 Subject: [PATCH 03/23] initial work torwards std lib support for uefi --- src/codegen.cpp | 10 +- std/os.zig | 12 +- std/os/uefi.zig | 43 +++++- std/os/uefi/protocols.zig | 31 ++++ .../protocols/absolute_pointer_protocol.zig | 60 ++++++++ .../uefi/protocols/edid_active_protocol.zig | 17 +++ .../protocols/edid_discovered_protocol.zig | 17 +++ .../uefi/protocols/edid_override_protocol.zig | 23 +++ .../protocols/graphics_output_protocol.zig | 90 +++++++++++ std/os/uefi/protocols/rng_protocol.zig | 73 +++++++++ .../protocols/simple_pointer_protocol.zig | 54 +++++++ .../simple_text_input_ex_protocol.zig | 81 ++++++++++ .../protocols/simple_text_output_protocol.zig | 143 ++++++++++++++++++ std/os/uefi/status.zig | 46 ++++++ std/os/uefi/tables.zig | 6 + std/os/uefi/tables/boot_services.zig | 64 ++++++++ std/os/uefi/tables/configuration_table.zig | 82 ++++++++++ std/os/uefi/tables/runtime_services.zig | 41 +++++ std/os/uefi/tables/system_table.zig | 46 ++++++ std/os/uefi/tables/table_header.zig | 8 + std/special/start.zig | 26 ++++ 21 files changed, 963 insertions(+), 10 deletions(-) create mode 100644 std/os/uefi/protocols.zig create mode 100644 std/os/uefi/protocols/absolute_pointer_protocol.zig create mode 100644 std/os/uefi/protocols/edid_active_protocol.zig create mode 100644 std/os/uefi/protocols/edid_discovered_protocol.zig create mode 100644 std/os/uefi/protocols/edid_override_protocol.zig create mode 100644 std/os/uefi/protocols/graphics_output_protocol.zig create mode 100644 std/os/uefi/protocols/rng_protocol.zig create mode 100644 std/os/uefi/protocols/simple_pointer_protocol.zig create mode 100644 std/os/uefi/protocols/simple_text_input_ex_protocol.zig create mode 100644 std/os/uefi/protocols/simple_text_output_protocol.zig create mode 100644 std/os/uefi/status.zig create mode 100644 std/os/uefi/tables.zig create mode 100644 std/os/uefi/tables/boot_services.zig create mode 100644 std/os/uefi/tables/configuration_table.zig create mode 100644 std/os/uefi/tables/runtime_services.zig create mode 100644 std/os/uefi/tables/system_table.zig create mode 100644 std/os/uefi/tables/table_header.zig diff --git a/src/codegen.cpp b/src/codegen.cpp index 0ac945e8c21bd375de4fc4e82dcd13e5859d5954..6ab76dea355869dcb9e154175bec5b970005360d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8540,10 +8540,6 @@ static bool want_startup_code(CodeGen *g) { if (g->is_test_build) return false; - // start code does not handle UEFI target - if (g->zig_target->os == OsUefi) - return false; - // WASM freestanding can still have an entry point but other freestanding targets do not. if (g->zig_target->os == OsFreestanding && !target_is_wasm(g->zig_target)) return false; @@ -8553,8 +8549,12 @@ static bool want_startup_code(CodeGen *g) { return false; // If there is a pub main in the root source file, that means we need start code. - if (g->have_pub_main) + if (g->have_pub_main) { return true; + } else { + if (g->zig_target->os == OsUefi) + return false; + } if (g->out_type == OutTypeExe) { // For build-exe, we might add start code even though there is no pub main, so that the diff --git a/std/os.zig b/std/os.zig index 190f02101e2c8672ea0b2560bf6641009ab1f6aa..9e3a6d3cb73a11e7e2a1716d07eacd95c5edc4ea 100644 --- a/std/os.zig +++ b/std/os.zig @@ -155,8 +155,7 @@ pub fn abort() noreturn { system.abort(); } if (builtin.os == .uefi) { - // TODO there must be a better thing to do here than loop forever - while (true) {} + exit(0); // TODO choose appropriate exit code } raise(SIGABRT) catch {}; @@ -228,6 +227,15 @@ pub fn exit(status: u8) noreturn { if (linux.is_the_target and !builtin.single_threaded) { linux.exit_group(status); } + if (uefi.is_the_target) { + // exit() is only avaliable if exitBootServices() has not been called yet. + // This call to exit should not fail, so we don't care about its return value. + if (uefi.system_table.boot_services) |bs| { + _ = bs.exit(uefi.handle, status, 0, null); + } + // If we can't exit, reboot the system instead. + uefi.system_table.runtime_services.resetSystem(uefi.tables.ResetType.ResetCold, status, 0, null); + } system.exit(status); } diff --git a/std/os/uefi.zig b/std/os/uefi.zig index 7102938d700d598077261d2098a8e8beabcb0e1b..7d757098f4cf36c8c72da889a6603da16584cbe6 100644 --- a/std/os/uefi.zig +++ b/std/os/uefi.zig @@ -1,6 +1,43 @@ -// TODO this is where the extern declarations go. For example, see -// inc/efilib.h in gnu-efi-code +pub const protocols = @import("uefi/protocols.zig"); +pub const status = @import("uefi/status.zig"); +pub const tables = @import("uefi/tables.zig"); const builtin = @import("builtin"); - pub const is_the_target = builtin.os == .uefi; + +pub var handle: *Handle = undefined; +pub var system_table: *tables.SystemTable = undefined; + +pub const Event = @OpaqueType(); +// GUIDs must be align(8) +pub const Guid = extern struct { + time_low: u32, + time_mid: u16, + time_high_and_version: u16, + clock_seq_high_and_reserved: u8, + clock_seq_low: u8, + node: [6]u8, +}; +pub const Handle = @OpaqueType(); +pub const Time = extern struct { + year: u16, + month: u8, + day: u8, + hour: u8, + minute: u8, + second: u8, + pad1: u8, + nanosecond: u32, + timezone: i16, + daylight: u8, + pad2: u8, + + pub const adjust_daylight: u8 = 1; + pub const in_daylight: u8 = 2; + pub const unspecified_timezone: i16 = 0x7ff; +}; +pub const TimeCapabilities = extern struct { + resolution: u32, + accuracy: u32, + sets_to_zero: bool, +}; diff --git a/std/os/uefi/protocols.zig b/std/os/uefi/protocols.zig new file mode 100644 index 0000000000000000000000000000000000000000..2d61ba08879e96c92162ce09d314b53918d3683c --- /dev/null +++ b/std/os/uefi/protocols.zig @@ -0,0 +1,31 @@ +pub const InputKey = @import("protocols/simple_text_input_ex_protocol.zig").InputKey; +pub const KeyData = @import("protocols/simple_text_input_ex_protocol.zig").KeyData; +pub const KeyState = @import("protocols/simple_text_input_ex_protocol.zig").KeyState; +pub const SimpleTextInputExProtocol = @import("protocols/simple_text_input_ex_protocol.zig").SimpleTextInputExProtocol; + +pub const SimpleTextOutputMode = @import("protocols/simple_text_output_protocol.zig").SimpleTextOutputMode; +pub const SimpleTextOutputProtocol = @import("protocols/simple_text_output_protocol.zig").SimpleTextOutputProtocol; + +pub const SimplePointerMode = @import("protocols/simple_pointer_protocol.zig").SimplePointerMode; +pub const SimplePointerProtocol = @import("protocols/simple_pointer_protocol.zig").SimplePointerProtocol; +pub const SimplePointerState = @import("protocols/simple_pointer_protocol.zig").SimplePointerState; + +pub const AbsolutePointerMode = @import("protocols/absolute_pointer_protocol.zig").AbsolutePointerMode; +pub const AbsolutePointerProtocol = @import("protocols/absolute_pointer_protocol.zig").AbsolutePointerProtocol; +pub const AbsolutePointerState = @import("protocols/absolute_pointer_protocol.zig").AbsolutePointerState; + +pub const GraphicsOutputBltPixel = @import("protocols/graphics_output_protocol.zig").GraphicsOutputBltPixel; +pub const GraphicsOutputBltOperation = @import("protocols/graphics_output_protocol.zig").GraphicsOutputBltOperation; +pub const GraphicsOutputModeInformation = @import("protocols/graphics_output_protocol.zig").GraphicsOutputModeInformation; +pub const GraphicsOutputProtocol = @import("protocols/graphics_output_protocol.zig").GraphicsOutputProtocol; +pub const GraphicsOutputProtocolMode = @import("protocols/graphics_output_protocol.zig").GraphicsOutputProtocolMode; +pub const GraphicsPixelFormat = @import("protocols/graphics_output_protocol.zig").GraphicsPixelFormat; +pub const PixelBitmask = @import("protocols/graphics_output_protocol.zig").PixelBitmask; + +pub const EdidDiscoveredProtocol = @import("protocols/edid_discovered_protocol.zig").EdidDiscoveredProtocol; + +pub const EdidActiveProtocol = @import("protocols/edid_active_protocol.zig").EdidActiveProtocol; + +pub const EdidOverrideProtocol = @import("protocols/edid_override_protocol.zig").EdidOverrideProtocol; + +pub const RNGProtocol = @import("protocols/rng_protocol.zig").RNGProtocol; diff --git a/std/os/uefi/protocols/absolute_pointer_protocol.zig b/std/os/uefi/protocols/absolute_pointer_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..ce6309b59225ceea83744569b67c055662391e6a --- /dev/null +++ b/std/os/uefi/protocols/absolute_pointer_protocol.zig @@ -0,0 +1,60 @@ +const uefi = @import("std").os.uefi; +const Event = uefi.Event; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 12.7 +pub const AbsolutePointerProtocol = extern struct { + _reset: extern fn (*const AbsolutePointerProtocol, bool) usize, + _get_state: extern fn (*const AbsolutePointerProtocol, *AbsolutePointerState) usize, + wait_for_input: *Event, + mode: *AbsolutePointerMode, + + pub fn reset(self: *const AbsolutePointerProtocol, verify: bool) usize { + return self._reset(self, verify); + } + + pub fn getState(self: *const AbsolutePointerProtocol, state: *AbsolutePointerState) usize { + return self._get_state(self, state); + } + + pub const guid align(8) = Guid{ + .time_low = 0x8d59d32b, + .time_mid = 0xc655, + .time_high_and_version = 0x4ae9, + .clock_seq_high_and_reserved = 0x9b, + .clock_seq_low = 0x15, + .node = [_]u8{ 0xf2, 0x59, 0x04, 0x99, 0x2a, 0x43 }, + }; +}; + +pub const AbsolutePointerMode = extern struct { + absolute_min_x: u64, + absolute_min_y: u64, + absolute_min_z: u64, + absolute_max_x: u64, + absolute_max_y: u64, + absolute_max_z: u64, + attributes: u32, + + pub const supports_alt_active: u32 = 1; + pub const supports_pressure_as_z: u32 = 2; +}; + +pub const AbsolutePointerState = extern struct { + current_x: u64, + current_y: u64, + current_z: u64, + active_buttons: u32, + + pub fn init() AbsolutePointerState { + return AbsolutePointerState{ + .current_x = undefined, + .current_y = undefined, + .current_z = undefined, + .active_buttons = undefined, + }; + } + + pub const touch_active: u32 = 1; + pub const alt_active: u32 = 2; +}; diff --git a/std/os/uefi/protocols/edid_active_protocol.zig b/std/os/uefi/protocols/edid_active_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..1a96cb6cd5b0071c0a270455478130aff0e0c15a --- /dev/null +++ b/std/os/uefi/protocols/edid_active_protocol.zig @@ -0,0 +1,17 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 12.9 +pub const EdidActiveProtocol = extern struct { + size_of_edid: u32, + edid: ?[*]u8, + + pub const guid align(8) = Guid{ + .time_low = 0xbd8c1056, + .time_mid = 0x9f36, + .time_high_and_version = 0x44ec, + .clock_seq_high_and_reserved = 0x92, + .clock_seq_low = 0xa8, + .node = [_]u8{ 0xa6, 0x33, 0x7f, 0x81, 0x79, 0x86 }, + }; +}; diff --git a/std/os/uefi/protocols/edid_discovered_protocol.zig b/std/os/uefi/protocols/edid_discovered_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..f68b0fa3d66c6b3a0db5ce0eda17ea807804389e --- /dev/null +++ b/std/os/uefi/protocols/edid_discovered_protocol.zig @@ -0,0 +1,17 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 12.9 +pub const EdidDiscoveredProtocol = extern struct { + size_of_edid: u32, + edid: ?[*]u8, + + pub const guid align(8) = Guid{ + .time_low = 0x1c0c34f6, + .time_mid = 0xd380, + .time_high_and_version = 0x41fa, + .clock_seq_high_and_reserved = 0xa0, + .clock_seq_low = 0x49, + .node = [_]u8{ 0x8a, 0xd0, 0x6c, 0x1a, 0x66, 0xaa }, + }; +}; diff --git a/std/os/uefi/protocols/edid_override_protocol.zig b/std/os/uefi/protocols/edid_override_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..7ed1358ed871ff0acefb7d8f4e015865ff5bc5c1 --- /dev/null +++ b/std/os/uefi/protocols/edid_override_protocol.zig @@ -0,0 +1,23 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; +const Handle = uefi.Handle; + +/// UEFI Specification, Version 2.8, 12.9 +pub const EdidOverrideProtocol = extern struct { + _get_edid: extern fn (*const EdidOverrideProtocol, *const Handle, *u32, *usize, *?[*]u8) usize, + + pub fn getEdid(self: *const EdidOverrideProtocol, handle: *const Handle, attributes: *u32, edid_size: *usize, edid: *?[*]u8) usize { + return self._get_edid(self, handle, attributes, edid_size, edid); + } + + pub const guid align(8) = Guid{ + .time_low = 0x48ecb431, + .time_mid = 0xfb72, + .time_high_and_version = 0x45c0, + .clock_seq_high_and_reserved = 0xa9, + .clock_seq_low = 0x22, + .node = [_]u8{ 0xf4, 0x58, 0xfe, 0x04, 0x0b, 0xd5 }, + }; + pub const dont_override: u32 = 1; + pub const enable_hot_plug: u32 = 2; +}; diff --git a/std/os/uefi/protocols/graphics_output_protocol.zig b/std/os/uefi/protocols/graphics_output_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..b4ce6a6f563544df65e52ec34f727ddf83503749 --- /dev/null +++ b/std/os/uefi/protocols/graphics_output_protocol.zig @@ -0,0 +1,90 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 12.9 +pub const GraphicsOutputProtocol = extern struct { + _query_mode: extern fn (*const GraphicsOutputProtocol, u32, *usize, **GraphicsOutputModeInformation) usize, + _set_mode: extern fn (*const GraphicsOutputProtocol, u32) usize, + _blt: extern fn (*const GraphicsOutputProtocol, ?[*]GraphicsOutputBltPixel, GraphicsOutputBltOperation, usize, usize, usize, usize, usize, usize, usize) usize, + mode: *GraphicsOutputProtocolMode, + + pub fn queryMode(self: *const GraphicsOutputProtocol, mode: u32, size_of_info: *usize, info: **GraphicsOutputModeInformation) usize { + return self._query_mode(self, mode, size_of_info, info); + } + + pub fn setMode(self: *const GraphicsOutputProtocol, mode: u32) usize { + return self._set_mode(self, mode); + } + + pub fn blt(self: *const GraphicsOutputProtocol, blt_buffer: ?[*]GraphicsOutputBltPixel, blt_operation: GraphicsOutputBltOperation, source_x: usize, source_y: usize, destination_x: usize, destination_y: usize, width: usize, height: usize, delta: usize) usize { + return self._blt(self, blt_buffer, blt_operation, source_x, source_y, destination_x, destination_y, width, height, delta); + } + + pub const guid align(8) = Guid{ + .time_low = 0x9042a9de, + .time_mid = 0x23dc, + .time_high_and_version = 0x4a38, + .clock_seq_high_and_reserved = 0x96, + .clock_seq_low = 0xfb, + .node = [_]u8{ 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a }, + }; +}; + +pub const GraphicsOutputProtocolMode = extern struct { + max_mode: u32, + mode: u32, + info: *GraphicsOutputModeInformation, + size_of_info: usize, + frame_buffer_base: u64, + frame_buffer_size: usize, +}; + +pub const GraphicsOutputModeInformation = extern struct { + version: u32, + horizontal_resolution: u32, + vertical_resolution: u32, + pixel_format: GraphicsPixelFormat, + pixel_information: PixelBitmask, + pixels_per_scan_line: u32, + + pub fn init() GraphicsOutputModeInformation { + return GraphicsOutputModeInformation{ + .version = undefined, + .horizontal_resolution = undefined, + .vertical_resolution = undefined, + .pixel_format = undefined, + .pixel_information = undefined, + .pixels_per_scan_line = undefined, + }; + } +}; + +pub const GraphicsPixelFormat = extern enum(u32) { + PixelRedGreenBlueReserved8BitPerColor, + PixelBlueGreenRedReserved8BitPerColor, + PixelBitMask, + PixelBltOnly, + PixelFormatMax, +}; + +pub const PixelBitmask = extern struct { + red_mask: u32, + green_mask: u32, + blue_mask: u32, + reserved_mask: u32, +}; + +pub const GraphicsOutputBltPixel = extern struct { + blue: u8, + green: u8, + red: u8, + reserved: u8 = undefined, +}; + +pub const GraphicsOutputBltOperation = extern enum(u32) { + BltVideoFill, + BltVideoToBltBuffer, + BltBufferToVideo, + BltVideoToVideo, + GraphicsOutputBltOperationMax, +}; diff --git a/std/os/uefi/protocols/rng_protocol.zig b/std/os/uefi/protocols/rng_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..565832caf9a68af708e5303e14ef5d2075036334 --- /dev/null +++ b/std/os/uefi/protocols/rng_protocol.zig @@ -0,0 +1,73 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 37.5 +pub const RNGProtocol = extern struct { + _get_info: extern fn (*const RNGProtocol, *usize, [*]align(8) Guid) usize, + _get_rng: extern fn (*const RNGProtocol, ?*align(8) const Guid, usize, [*]u8) usize, + + pub fn getInfo(self: *const RNGProtocol, list_size: *usize, list: [*]align(8) Guid) usize { + return self._get_info(self, list_size, list); + } + + pub fn getRNG(self: *const RNGProtocol, algo: ?*const Guid, value_length: usize, value: [*]u8) usize { + return self._get_rng(self, algo, value_length, value); + } + + pub const guid align(8) = Guid{ + .time_low = 0x3152bca5, + .time_mid = 0xeade, + .time_high_and_version = 0x433d, + .clock_seq_high_and_reserved = 0x86, + .clock_seq_low = 0x2e, + .node = [_]u8{ 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 }, + }; + pub const algorithm_sp800_90_hash_256 align(8) = Guid{ + .time_low = 0xa7af67cb, + .time_mid = 0x603b, + .time_high_and_version = 0x4d42, + .clock_seq_high_and_reserved = 0xba, + .clock_seq_low = 0x21, + .node = [_]u8{ 0x70, 0xbf, 0xb6, 0x29, 0x3f, 0x96 }, + }; + pub const algorithm_sp800_90_hmac_256 align(8) = Guid{ + .time_low = 0xc5149b43, + .time_mid = 0xae85, + .time_high_and_version = 0x4f53, + .clock_seq_high_and_reserved = 0x99, + .clock_seq_low = 0x82, + .node = [_]u8{ 0xb9, 0x43, 0x35, 0xd3, 0xa9, 0xe7 }, + }; + pub const algorithm_sp800_90_ctr_256 align(8) = Guid{ + .time_low = 0x44f0de6e, + .time_mid = 0x4d8c, + .time_high_and_version = 0x4045, + .clock_seq_high_and_reserved = 0xa8, + .clock_seq_low = 0xc7, + .node = [_]u8{ 0x4d, 0xd1, 0x68, 0x85, 0x6b, 0x9e }, + }; + pub const algorithm_x9_31_3des align(8) = Guid{ + .time_low = 0x63c4785a, + .time_mid = 0xca34, + .time_high_and_version = 0x4012, + .clock_seq_high_and_reserved = 0xa3, + .clock_seq_low = 0xc8, + .node = [_]u8{ 0x0b, 0x6a, 0x32, 0x4f, 0x55, 0x46 }, + }; + pub const algorithm_x9_31_aes align(8) = Guid{ + .time_low = 0xacd03321, + .time_mid = 0x777e, + .time_high_and_version = 0x4d3d, + .clock_seq_high_and_reserved = 0xb1, + .clock_seq_low = 0xc8, + .node = [_]u8{ 0x20, 0xcf, 0xd8, 0x88, 0x20, 0xc9 }, + }; + pub const algorithm_raw align(8) = Guid{ + .time_low = 0xe43176d7, + .time_mid = 0xb6e8, + .time_high_and_version = 0x4827, + .clock_seq_high_and_reserved = 0xb7, + .clock_seq_low = 0x84, + .node = [_]u8{ 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61 }, + }; +}; diff --git a/std/os/uefi/protocols/simple_pointer_protocol.zig b/std/os/uefi/protocols/simple_pointer_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..8a84bb4ccf65f2c07eb4abc1f0fa7337fa6c77a2 --- /dev/null +++ b/std/os/uefi/protocols/simple_pointer_protocol.zig @@ -0,0 +1,54 @@ +const uefi = @import("std").os.uefi; +const Event = uefi.Event; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 12.5 +pub const SimplePointerProtocol = struct { + _reset: extern fn (*const SimplePointerProtocol, bool) usize, + _get_state: extern fn (*const SimplePointerProtocol, *SimplePointerState) usize, + wait_for_input: *Event, + mode: *SimplePointerMode, + + pub fn reset(self: *const SimplePointerProtocol, verify: bool) usize { + return self._reset(self, verify); + } + + pub fn getState(self: *const SimplePointerProtocol, state: *SimplePointerState) usize { + return self._get_state(self, state); + } + + pub const guid align(8) = Guid{ + .time_low = 0x31878c87, + .time_mid = 0x0b75, + .time_high_and_version = 0x11d5, + .clock_seq_high_and_reserved = 0x9a, + .clock_seq_low = 0x4f, + .node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }, + }; +}; + +pub const SimplePointerMode = struct { + resolution_x: u64, + resolution_y: u64, + resolution_z: u64, + left_button: bool, + right_button: bool, +}; + +pub const SimplePointerState = struct { + relative_movement_x: i32, + relative_movement_y: i32, + relative_movement_z: i32, + left_button: bool, + right_button: bool, + + pub fn init() SimplePointerState { + return SimplePointerState{ + .relative_movement_x = undefined, + .relative_movement_y = undefined, + .relative_movement_z = undefined, + .left_button = undefined, + .right_button = undefined, + }; + } +}; diff --git a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..53b0a51f7e1cf8ec6c859e015fb9135d404fc121 --- /dev/null +++ b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig @@ -0,0 +1,81 @@ +const uefi = @import("std").os.uefi; +const Event = uefi.Event; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 12.3 +pub const SimpleTextInputExProtocol = extern struct { + _reset: extern fn (*const SimpleTextInputExProtocol, bool) usize, + _read_key_stroke_ex: extern fn (*const SimpleTextInputExProtocol, *KeyData) usize, + wait_for_key_ex: *Event, + _set_state: extern fn (*const SimpleTextInputExProtocol, *const u8) usize, + _register_key_notify: extern fn (*const SimpleTextInputExProtocol, *const KeyData, extern fn (*const KeyData) usize, **c_void) usize, + _unregister_key_notify: extern fn (*const SimpleTextInputExProtocol, *const c_void) usize, + + pub fn reset(self: *const SimpleTextInputExProtocol, verify: bool) usize { + return self._reset(self, verify); + } + + pub fn readKeyStrokeEx(self: *const SimpleTextInputExProtocol, key_data: *KeyData) usize { + return self._read_key_stroke_ex(self, key_data); + } + + pub fn setState(self: *const SimpleTextInputExProtocol, state: *const u8) usize { + return self._set_state(self, state); + } + + pub fn registerKeyNotify(self: *const SimpleTextInputExProtocol, key_data: *const KeyData, notify: extern fn (*const KeyData) usize, handle: **c_void) usize { + return self._register_key_notify(self, key_data, notify, handle); + } + + pub fn unregisterKeyNotify(self: *const SimpleTextInputExProtocol, handle: *const c_void) usize { + return self._unregister_key_notify(self, handle); + } + + pub const guid align(8) = Guid{ + .time_low = 0xdd9e7534, + .time_mid = 0x7762, + .time_high_and_version = 0x4698, + .clock_seq_high_and_reserved = 0x8c, + .clock_seq_low = 0x14, + .node = [_]u8{ 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa }, + }; +}; + +pub const KeyData = extern struct { + key: InputKey, + key_state: KeyState, + + pub fn init() KeyData { + return KeyData{ + .key = undefined, + .key_state = undefined, + }; + } +}; + +pub const KeyState = extern struct { + key_shift_state: u32, + key_toggle_state: u8, + + pub const shift_state_valid: u32 = 0x80000000; + pub const right_shift_pressed: u32 = 0x00000001; + pub const left_shift_pressed: u32 = 0x00000002; + pub const right_control_pressed: u32 = 0x00000004; + pub const left_control_pressed: u32 = 0x00000008; + pub const right_alt_pressed: u32 = 0x00000010; + pub const left_alt_pressed: u32 = 0x00000020; + pub const right_logo_pressed: u32 = 0x00000040; + pub const left_logo_pressed: u32 = 0x00000080; + pub const menu_key_pressed: u32 = 0x00000100; + pub const sys_req_pressed: u32 = 0x00000200; + pub const toggle_state_valid: u8 = 0x80; + pub const key_state_exposed: u8 = 0x40; + pub const scroll_lock_active: u8 = 0x01; + pub const num_lock_active: u8 = 0x02; + pub const caps_lock_active: u8 = 0x04; +}; + +pub const InputKey = extern struct { + scan_code: u16, + unicode_char: u16, +}; diff --git a/std/os/uefi/protocols/simple_text_output_protocol.zig b/std/os/uefi/protocols/simple_text_output_protocol.zig new file mode 100644 index 0000000000000000000000000000000000000000..e6b2e21c7016c467cb100139f106ca516726f158 --- /dev/null +++ b/std/os/uefi/protocols/simple_text_output_protocol.zig @@ -0,0 +1,143 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 12.4 +pub const SimpleTextOutputProtocol = extern struct { + _reset: extern fn (*const SimpleTextOutputProtocol, bool) usize, + _output_string: extern fn (*const SimpleTextOutputProtocol, [*]const u16) usize, + _test_string: extern fn (*const SimpleTextOutputProtocol, [*]const u16) usize, + _query_mode: extern fn (*const SimpleTextOutputProtocol, usize, *usize, *usize) usize, + _set_mode: extern fn (*const SimpleTextOutputProtocol, usize) usize, + _set_attribute: extern fn (*const SimpleTextOutputProtocol, usize) usize, + _clear_screen: extern fn (*const SimpleTextOutputProtocol) usize, + _set_cursor_position: extern fn (*const SimpleTextOutputProtocol, usize, usize) usize, + _enable_cursor: extern fn (*const SimpleTextOutputProtocol, bool) usize, + mode: *SimpleTextOutputMode, + + pub fn reset(self: *const SimpleTextOutputProtocol, verify: bool) usize { + return self._reset(self, verify); + } + + pub fn outputString(self: *const SimpleTextOutputProtocol, msg: [*]const u16) usize { + return self._output_string(self, msg); + } + + pub fn testString(self: *const SimpleTextOutputProtocol, msg: [*]const u16) usize { + return self._test_string(self, msg); + } + + pub fn queryMode(self: *const SimpleTextOutputProtocol, mode_number: usize, columns: *usize, rows: *usize) usize { + return self._query_mode(self, mode_number, columns, rows); + } + + pub fn setMode(self: *const SimpleTextOutputProtocol, mode_number: usize) usize { + return self._set_mode(self, mode_number); + } + + pub fn setAttribute(self: *const SimpleTextOutputProtocol, attribute: usize) usize { + return self._set_attribute(self, attribute); + } + + pub fn clearScreen(self: *const SimpleTextOutputProtocol) usize { + return self._clear_screen(self); + } + + pub fn setCursorPosition(self: *const SimpleTextOutputProtocol, column: usize, row: usize) usize { + return self._set_cursor_position(self, column, row); + } + + pub fn enableCursor(self: *const SimpleTextOutputProtocol, visible: bool) usize { + return self._enable_cursor(self, visible); + } + + pub const guid align(8) = Guid{ + .time_low = 0x387477c2, + .time_mid = 0x69c7, + .time_high_and_version = 0x11d2, + .clock_seq_high_and_reserved = 0x8e, + .clock_seq_low = 0x39, + .node = [_]u8{ 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b }, + }; + pub const boxdraw_horizontal: u16 = 0x2500; + pub const boxdraw_vertical: u16 = 0x2502; + pub const boxdraw_down_right: u16 = 0x250c; + pub const boxdraw_down_left: u16 = 0x2510; + pub const boxdraw_up_right: u16 = 0x2514; + pub const boxdraw_up_left: u16 = 0x2518; + pub const boxdraw_vertical_right: u16 = 0x251c; + pub const boxdraw_vertical_left: u16 = 0x2524; + pub const boxdraw_down_horizontal: u16 = 0x252c; + pub const boxdraw_up_horizontal: u16 = 0x2534; + pub const boxdraw_vertical_horizontal: u16 = 0x253c; + pub const boxdraw_double_horizontal: u16 = 0x2550; + pub const boxdraw_double_vertical: u16 = 0x2551; + pub const boxdraw_down_right_double: u16 = 0x2552; + pub const boxdraw_down_double_right: u16 = 0x2553; + pub const boxdraw_double_down_right: u16 = 0x2554; + pub const boxdraw_down_left_double: u16 = 0x2555; + pub const boxdraw_down_double_left: u16 = 0x2556; + pub const boxdraw_double_down_left: u16 = 0x2557; + pub const boxdraw_up_right_double: u16 = 0x2558; + pub const boxdraw_up_double_right: u16 = 0x2559; + pub const boxdraw_double_up_right: u16 = 0x255a; + pub const boxdraw_up_left_double: u16 = 0x255b; + pub const boxdraw_up_double_left: u16 = 0x255c; + pub const boxdraw_double_up_left: u16 = 0x255d; + pub const boxdraw_vertical_right_double: u16 = 0x255e; + pub const boxdraw_vertical_double_right: u16 = 0x255f; + pub const boxdraw_double_vertical_right: u16 = 0x2560; + pub const boxdraw_vertical_left_double: u16 = 0x2561; + pub const boxdraw_vertical_double_left: u16 = 0x2562; + pub const boxdraw_double_vertical_left: u16 = 0x2563; + pub const boxdraw_down_horizontal_double: u16 = 0x2564; + pub const boxdraw_down_double_horizontal: u16 = 0x2565; + pub const boxdraw_double_down_horizontal: u16 = 0x2566; + pub const boxdraw_up_horizontal_double: u16 = 0x2567; + pub const boxdraw_up_double_horizontal: u16 = 0x2568; + pub const boxdraw_double_up_horizontal: u16 = 0x2569; + pub const boxdraw_vertical_horizontal_double: u16 = 0x256a; + pub const boxdraw_vertical_double_horizontal: u16 = 0x256b; + pub const boxdraw_double_vertical_horizontal: u16 = 0x256c; + pub const blockelement_full_block: u16 = 0x2588; + pub const blockelement_light_shade: u16 = 0x2591; + pub const geometricshape_up_triangle: u16 = 0x25b2; + pub const geometricshape_right_triangle: u16 = 0x25ba; + pub const geometricshape_down_triangle: u16 = 0x25bc; + pub const geometricshape_left_triangle: u16 = 0x25c4; + pub const arrow_up: u16 = 0x2591; + pub const arrow_down: u16 = 0x2593; + pub const black: u8 = 0x00; + pub const blue: u8 = 0x01; + pub const green: u8 = 0x02; + pub const cyan: u8 = 0x03; + pub const red: u8 = 0x04; + pub const magenta: u8 = 0x05; + pub const brown: u8 = 0x06; + pub const lightgray: u8 = 0x07; + pub const bright: u8 = 0x08; + pub const darkgray: u8 = 0x08; + pub const lightblue: u8 = 0x09; + pub const lightgreen: u8 = 0x0a; + pub const lightcyan: u8 = 0x0b; + pub const lightred: u8 = 0x0c; + pub const lightmagenta: u8 = 0x0d; + pub const yellow: u8 = 0x0e; + pub const white: u8 = 0x0f; + pub const background_black: u8 = 0x00; + pub const background_blue: u8 = 0x10; + pub const background_green: u8 = 0x20; + pub const background_cyan: u8 = 0x30; + pub const background_red: u8 = 0x40; + pub const background_magenta: u8 = 0x50; + pub const background_brown: u8 = 0x60; + pub const background_lightgray: u8 = 0x70; +}; + +pub const SimpleTextOutputMode = extern struct { + max_mode: u32, // specified as signed + mode: u32, // specified as signed + attribute: i32, + cursor_column: i32, + cursor_row: i32, + cursor_visible: bool, +}; diff --git a/std/os/uefi/status.zig b/std/os/uefi/status.zig new file mode 100644 index 0000000000000000000000000000000000000000..6deb741d0d26cdb24ce29be253cc2fdee34df885 --- /dev/null +++ b/std/os/uefi/status.zig @@ -0,0 +1,46 @@ +const high_bit = 1 << @typeInfo(usize).Int.bits - 1; + +/// UEFI Specification, Version 2.8, Appendix D +pub const success: usize = 0; + +pub const load_error: usize = high_bit | 1; +pub const invalid_parameter: usize = high_bit | 2; +pub const unsupported: usize = high_bit | 3; +pub const bad_buffer_size: usize = high_bit | 4; +pub const buffer_too_small: usize = high_bit | 5; +pub const not_ready: usize = high_bit | 6; +pub const device_error: usize = high_bit | 7; +pub const write_protected: usize = high_bit | 8; +pub const out_of_resources: usize = high_bit | 9; +pub const volume_corrupted: usize = high_bit | 10; +pub const volume_full: usize = high_bit | 11; +pub const no_media: usize = high_bit | 12; +pub const media_changed: usize = high_bit | 13; +pub const not_found: usize = high_bit | 14; +pub const access_denied: usize = high_bit | 15; +pub const no_response: usize = high_bit | 16; +pub const no_mapping: usize = high_bit | 17; +pub const timeout: usize = high_bit | 18; +pub const not_started: usize = high_bit | 19; +pub const already_started: usize = high_bit | 20; +pub const aborted: usize = high_bit | 21; +pub const icmp_error: usize = high_bit | 22; +pub const tftp_error: usize = high_bit | 23; +pub const protocol_error: usize = high_bit | 24; +pub const incompatible_version: usize = high_bit | 25; +pub const security_violation: usize = high_bit | 26; +pub const crc_error: usize = high_bit | 27; +pub const end_of_media: usize = high_bit | 28; +pub const end_of_file: usize = high_bit | 31; +pub const invalid_language: usize = high_bit | 32; +pub const compromised_data: usize = high_bit | 33; +pub const ip_address_conflict: usize = high_bit | 34; +pub const http_error: usize = high_bit | 35; + +pub const warn_unknown_glyph: usize = 1; +pub const warn_delete_failure: usize = 2; +pub const warn_write_failure: usize = 3; +pub const warn_buffer_too_small: usize = 4; +pub const warn_stale_data: usize = 5; +pub const warn_file_system: usize = 6; +pub const warn_reset_required: usize = 7; diff --git a/std/os/uefi/tables.zig b/std/os/uefi/tables.zig new file mode 100644 index 0000000000000000000000000000000000000000..e5867ae657fd4f012ff810aa448e1417579366c2 --- /dev/null +++ b/std/os/uefi/tables.zig @@ -0,0 +1,6 @@ +pub const BootServices = @import("tables/boot_services.zig").BootServices; +pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable; +pub const ResetType = @import("tables/runtime_services.zig").ResetType; +pub const RuntimeServices = @import("tables/runtime_services.zig").RuntimeServices; +pub const SystemTable = @import("tables/system_table.zig").SystemTable; +pub const TableHeader = @import("tables/table_header.zig").TableHeader; diff --git a/std/os/uefi/tables/boot_services.zig b/std/os/uefi/tables/boot_services.zig new file mode 100644 index 0000000000000000000000000000000000000000..2ae234f77d1d61fffadb7eebd5bb41faa7887772 --- /dev/null +++ b/std/os/uefi/tables/boot_services.zig @@ -0,0 +1,64 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; +const Handle = uefi.Handle; +const TableHeader = uefi.tables.TableHeader; + +/// UEFI Specification, Version 2.8, 4.4 +/// +/// As the boot_services table may grow with new UEFI versions, it is important to check hdr.header_size. +/// +/// Boot Services must not be used after exitBootServices has been called. The only exception is +/// getMemoryMap, which may be used after the first unsuccessful call to exitBootServices. +/// After successfully calling exitBootServices, system_table.console_in_handle, system_table.con_in, +/// system_table.console_out_handle, system_table.con_out, system_table.standard_error_handle, +/// system_table.std_err, and system_table.boot_services should be set to null. After setting these +/// attributes to null, system_table.hdr.crc32 must be recomputed. See UEFI Specification, Version 2.8, 7.4. +pub const BootServices = extern struct { + hdr: TableHeader, + raiseTpl: usize, // TODO + restoreTpl: usize, // TODO + allocatePages: usize, // TODO + freePages: usize, // TODO + getMemoryMap: usize, // TODO + allocatePool: usize, // TODO + freePool: usize, // TODO + createEvent: usize, // TODO + setTimer: usize, // TODO + waitForEvent: usize, // TODO + signalEvent: usize, // TODO + closeEvent: usize, // TODO + checkEvent: usize, // TODO + installProtocolInterface: usize, // TODO + reinstallProtocolInterface: usize, // TODO + uninstallProtocolInterface: usize, // TODO + handleProtocol: usize, // TODO + reserved: *c_void, + registerProtocolNotify: usize, // TODO + locateHandle: usize, // TODO + locateDevicePath: usize, // TODO + installConfigurationTable: usize, // TODO + imageLoad: usize, // TODO + imageStart: usize, // TODO + exit: extern fn (*const Handle, usize, usize, ?*const c_void) usize, + imageUnload: usize, // TODO + exitBootServices: usize, // TODO + getNextMonotonicCount: usize, // TODO + stall: extern fn (usize) usize, + setWatchdogTimer: extern fn (usize, u64, usize, ?[*]const u16) usize, + connectController: usize, // TODO + disconnectController: usize, // TODO + openProtocol: usize, // TODO + closeProtocol: usize, // TODO + openProtocolInformation: usize, // TODO + protocolsPerHandle: usize, // TODO + locateHandleBuffer: usize, // TODO + locateProtocol: extern fn (*align(8) const Guid, ?*const c_void, *?*c_void) usize, + installMultipleProtocolInterfaces: usize, // TODO + uninstallMultipleProtocolInterfaces: usize, // TODO + calculateCrc32: usize, // TODO + copyMem: usize, // TODO + setMem: usize, // TODO + createEventEx: usize, // TODO + + pub const signature: u64 = 0x56524553544f4f42; +}; diff --git a/std/os/uefi/tables/configuration_table.zig b/std/os/uefi/tables/configuration_table.zig new file mode 100644 index 0000000000000000000000000000000000000000..eb99e08477fbb6f2a014f192a414778eeb9f225f --- /dev/null +++ b/std/os/uefi/tables/configuration_table.zig @@ -0,0 +1,82 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; + +/// UEFI Specification, Version 2.8, 4.6 +/// Because GUIDs must be align(8), structs of this type also must be align(8) +pub const ConfigurationTable = extern struct { + vendor_guid: Guid, + vendor_table: *c_void, + + pub const acpi_20_table_guid align(8) = Guid{ + .time_low = 0x8868e871, + .time_mid = 0xe4f1, + .time_high_and_version = 0x11d3, + .clock_seq_high_and_reserved = 0xbc, + .clock_seq_low = 0x22, + .node = [_]u8{ 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81 }, + }; + pub const acpi_10_table_guid align(8) = Guid{ + .time_low = 0xeb9d2d30, + .time_mid = 0x2d88, + .time_high_and_version = 0x11d3, + .clock_seq_high_and_reserved = 0x9a, + .clock_seq_low = 0x16, + .node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }, + }; + pub const sal_system_table_guid align(8) = Guid{ + .time_low = 0xeb9d2d32, + .time_mid = 0x2d88, + .time_high_and_version = 0x113d, + .clock_seq_high_and_reserved = 0x9a, + .clock_seq_low = 0x16, + .node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }, + }; + pub const smbios_table_guid align(8) = Guid{ + .time_low = 0xeb9d2d31, + .time_mid = 0x2d88, + .time_high_and_version = 0x11d3, + .clock_seq_high_and_reserved = 0x9a, + .clock_seq_low = 0x16, + .node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }, + }; + pub const smbios3_table_guid align(8) = Guid{ + .time_low = 0xf2fd1544, + .time_mid = 0x9794, + .time_high_and_version = 0x4a2c, + .clock_seq_high_and_reserved = 0x99, + .clock_seq_low = 0x2e, + .node = [_]u8{ 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 }, + }; + pub const mps_table_guid align(8) = Guid{ + .time_low = 0xeb9d2d2f, + .time_mid = 0x2d88, + .time_high_and_version = 0x11d3, + .clock_seq_high_and_reserved = 0x9a, + .clock_seq_low = 0x16, + .node = [_]u8{ 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d }, + }; + pub const json_config_data_table_guid align(8) = Guid{ + .time_low = 0x87367f87, + .time_mid = 0x1119, + .time_high_and_version = 0x41ce, + .clock_seq_high_and_reserved = 0xaa, + .clock_seq_low = 0xec, + .node = [_]u8{ 0x8b, 0xe0, 0x11, 0x1f, 0x55, 0x8a }, + }; + pub const json_capsule_data_table_guid align(8) = Guid{ + .time_low = 0x35e7a725, + .time_mid = 0x8dd2, + .time_high_and_version = 0x4cac, + .clock_seq_high_and_reserved = 0x80, + .clock_seq_low = 0x11, + .node = [_]u8{ 0x33, 0xcd, 0xa8, 0x10, 0x90, 0x56 }, + }; + pub const json_capsule_result_table_guid align(8) = Guid{ + .time_low = 0xdbc461c3, + .time_mid = 0xb3de, + .time_high_and_version = 0x422a, + .clock_seq_high_and_reserved = 0xb9, + .clock_seq_low = 0xb4, + .node = [_]u8{ 0x98, 0x86, 0xfd, 0x49, 0xa1, 0xe5 }, + }; +}; diff --git a/std/os/uefi/tables/runtime_services.zig b/std/os/uefi/tables/runtime_services.zig new file mode 100644 index 0000000000000000000000000000000000000000..bae808ac85fcda63a3e9b88fb07a7e6bc3617cc1 --- /dev/null +++ b/std/os/uefi/tables/runtime_services.zig @@ -0,0 +1,41 @@ +const uefi = @import("std").os.uefi; +const Guid = uefi.Guid; +const TableHeader = uefi.tables.TableHeader; +const Time = uefi.Time; +const TimeCapabilities = uefi.TimeCapabilities; + +/// UEFI Specification, Version 2.8, 4.5 +/// +/// As the runtime_services table may grow with new UEFI versions, it is important to check hdr.header_size. +/// +/// Some functions may not be supported. Check the RuntimeServicesSupported variable using getVariable. +/// getVariable is one of the functions that may not be supported. See UEFI Specification, Version 2.8, 8.1. +/// +/// Some functions may not be called while other functions are running. See UEFI Specification, Version 2.8, 8.1. +pub const RuntimeServices = extern struct { + hdr: TableHeader, + getTime: extern fn (*uefi.Time, ?*TimeCapabilities) usize, + setTime: usize, // TODO + getWakeupTime: usize, // TODO + setWakeupTime: usize, // TODO + setVirtualAddressMap: usize, // TODO + convertPointer: usize, // TODO + getVariable: extern fn ([*]const u16, *align(8) const Guid, ?*u32, *usize, ?*c_void) usize, + getNextVariableName: extern fn (*usize, [*]u16, *align(8) Guid) usize, + setVariable: extern fn ([*]const u16, *align(8) const Guid, u32, usize, *c_void) usize, + getNextHighMonotonicCount: usize, // TODO + resetSystem: extern fn (ResetType, usize, usize, ?*const c_void) noreturn, + updateCapsule: usize, // TODO + queryCapsuleCapabilities: usize, // TODO + queryVariableInfo: usize, // TODO + + pub const signature: u64 = 0x56524553544e5552; +}; + +/// UEFI Specification, Version 2.8, 8.5.1 +pub const ResetType = extern enum(u32) { + ResetCold, + ResetWarm, + ResetShutdown, + ResetPlatformSpecific, +}; diff --git a/std/os/uefi/tables/system_table.zig b/std/os/uefi/tables/system_table.zig new file mode 100644 index 0000000000000000000000000000000000000000..31534d03be951039696ece463f13943f661ebedc --- /dev/null +++ b/std/os/uefi/tables/system_table.zig @@ -0,0 +1,46 @@ +const uefi = @import("std").os.uefi; +const BootServices = uefi.tables.BootServices; +const ConfigurationTable = uefi.tables.ConfigurationTable; +const Handle = uefi.Handle; +const RuntimeServices = uefi.tables.RuntimeServices; +const SimpleTextInputExProtocol = uefi.protocols.SimpleTextInputExProtocol; +const SimpleTextOutputProtocol = uefi.protocols.SimpleTextOutputProtocol; +const TableHeader = uefi.tables.TableHeader; + +/// UEFI Specification, Version 2.8, 4.3 +/// +/// As the system_table may grow with new UEFI versions, it is important to check hdr.header_size. +/// +/// After successfully calling boot_services.exitBootServices, console_in_handle, +/// con_in, console_out_handle, con_out, standard_error_handle, std_err, and +/// boot_services should be set to null. After setting these attributes to null, +/// hdr.crc32 must be recomputed. See UEFI Specification, Version 2.8, 7.4. +pub const SystemTable = extern struct { + hdr: TableHeader, + firmware_vendor: *u16, + firmware_revision: u32, + console_in_handle: ?*Handle, + con_in: ?*SimpleTextInputExProtocol, + console_out_handle: ?*Handle, + con_out: ?*SimpleTextOutputProtocol, + standard_error_handle: ?*Handle, + std_err: ?*SimpleTextOutputProtocol, + runtime_services: *RuntimeServices, + boot_services: ?*BootServices, + number_of_table_entries: usize, + configuration_table: *ConfigurationTable, + + pub const signature: u64 = 0x5453595320494249; + pub const revision_1_02: u32 = (1 << 16) | 2; + pub const revision_1_10: u32 = (1 << 16) | 10; + pub const revision_2_00: u32 = (2 << 16); + pub const revision_2_10: u32 = (2 << 16) | 10; + pub const revision_2_20: u32 = (2 << 16) | 20; + pub const revision_2_30: u32 = (2 << 16) | 30; + pub const revision_2_31: u32 = (2 << 16) | 31; + pub const revision_2_40: u32 = (2 << 16) | 40; + pub const revision_2_50: u32 = (2 << 16) | 50; + pub const revision_2_60: u32 = (2 << 16) | 60; + pub const revision_2_70: u32 = (2 << 16) | 70; + pub const revision_2_80: u32 = (2 << 16) | 80; +}; diff --git a/std/os/uefi/tables/table_header.zig b/std/os/uefi/tables/table_header.zig new file mode 100644 index 0000000000000000000000000000000000000000..b955768e638d7dd03f3e5528dfb7c03106b6174d --- /dev/null +++ b/std/os/uefi/tables/table_header.zig @@ -0,0 +1,8 @@ +/// UEFI Specification, Version 2.8, 4.2 +pub const TableHeader = extern struct { + signature: u64, + revision: u32, + header_size: u32, + crc32: u32, + reserved: u32, +}; diff --git a/std/special/start.zig b/std/special/start.zig index f8a018e0ae08319f0a3a6331189639336f5a435c..dbd0912d9770486205035a77b8272e1e97922861 100644 --- a/std/special/start.zig +++ b/std/special/start.zig @@ -4,6 +4,7 @@ const root = @import("root"); const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; +const uefi = std.os.uefi; var argc_ptr: [*]usize = undefined; @@ -19,6 +20,8 @@ comptime { @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); } else if (is_wasm and builtin.os == .freestanding) { @export("_start", wasm_freestanding_start, .Strong); + } else if (builtin.os == .uefi) { + @export("EfiMain", EfiMain, .Strong); } else { @export("_start", _start, .Strong); } @@ -28,6 +31,29 @@ extern fn wasm_freestanding_start() void { _ = callMain(); } +extern fn EfiMain(handle: *uefi.Handle, system_table: *uefi.tables.SystemTable) usize { + const bad_efi_main_ret = "expected return type of main to be 'void', 'noreturn', or 'usize'"; + uefi.handle = handle; + uefi.system_table = system_table; + + switch (@typeInfo(@typeOf(root.main).ReturnType)) { + .NoReturn => { + root.main(); + }, + .Void => { + root.main(); + return 0; + }, + .Int => |info| { + if (info.bits != @typeInfo(usize).Int.bits) { + @compileError(bad_efi_main_ret); + } + return root.main(); + }, + else => @compileError(bad_efi_main_ret), + } +} + nakedcc fn _start() noreturn { if (builtin.os == builtin.Os.wasi) { std.os.wasi.proc_exit(callMain()); -- 2.54.0 From 20ce0b9952167d531f0a0e679c1b0409e9049d09 Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Mon, 5 Aug 2019 18:26:13 +0200 Subject: [PATCH 04/23] std/os/uefi: replace integer bit fields with packed structs --- std/os/uefi.zig | 12 +++--- std/os/uefi/protocols.zig | 1 + .../protocols/absolute_pointer_protocol.zig | 20 +++++---- .../uefi/protocols/edid_override_protocol.zig | 12 ++++-- .../simple_text_input_ex_protocol.zig | 43 +++++++++++-------- 5 files changed, 53 insertions(+), 35 deletions(-) diff --git a/std/os/uefi.zig b/std/os/uefi.zig index 7d757098f4cf36c8c72da889a6603da16584cbe6..58508df38f20a469860ee5ea9f4ba177d9b8d030 100644 --- a/std/os/uefi.zig +++ b/std/os/uefi.zig @@ -26,14 +26,16 @@ pub const Time = extern struct { hour: u8, minute: u8, second: u8, - pad1: u8, + _pad1: u8, nanosecond: u32, timezone: i16, - daylight: u8, - pad2: u8, + daylight: packed struct { + _pad1: u6, + in_daylight: bool, + adjust_daylight: bool, + }, + _pad2: u8, - pub const adjust_daylight: u8 = 1; - pub const in_daylight: u8 = 2; pub const unspecified_timezone: i16 = 0x7ff; }; pub const TimeCapabilities = extern struct { diff --git a/std/os/uefi/protocols.zig b/std/os/uefi/protocols.zig index 2d61ba08879e96c92162ce09d314b53918d3683c..2c8d870af063e8403d1a15e316d2a1a6d519f44c 100644 --- a/std/os/uefi/protocols.zig +++ b/std/os/uefi/protocols.zig @@ -27,5 +27,6 @@ pub const EdidDiscoveredProtocol = @import("protocols/edid_discovered_protocol.z pub const EdidActiveProtocol = @import("protocols/edid_active_protocol.zig").EdidActiveProtocol; pub const EdidOverrideProtocol = @import("protocols/edid_override_protocol.zig").EdidOverrideProtocol; +pub const EdidOverrideProtocolAttributes = @import("protocols/edid_override_protocol.zig").EdidOverrideProtocolAttributes; pub const RNGProtocol = @import("protocols/rng_protocol.zig").RNGProtocol; diff --git a/std/os/uefi/protocols/absolute_pointer_protocol.zig b/std/os/uefi/protocols/absolute_pointer_protocol.zig index ce6309b59225ceea83744569b67c055662391e6a..6621b3128860b92e99bf60dc36beff5e19f7e505 100644 --- a/std/os/uefi/protocols/absolute_pointer_protocol.zig +++ b/std/os/uefi/protocols/absolute_pointer_protocol.zig @@ -34,17 +34,24 @@ pub const AbsolutePointerMode = extern struct { absolute_max_x: u64, absolute_max_y: u64, absolute_max_z: u64, - attributes: u32, - - pub const supports_alt_active: u32 = 1; - pub const supports_pressure_as_z: u32 = 2; + attributes: packed struct { + _pad1: u6, + supports_pressure_as_z: bool, + supports_alt_active: bool, + _pad2: u24, + }, }; pub const AbsolutePointerState = extern struct { current_x: u64, current_y: u64, current_z: u64, - active_buttons: u32, + active_buttons: packed struct { + _pad1: u6, + alt_active: bool, + touch_active: bool, + _pad2: u24, + }, pub fn init() AbsolutePointerState { return AbsolutePointerState{ @@ -54,7 +61,4 @@ pub const AbsolutePointerState = extern struct { .active_buttons = undefined, }; } - - pub const touch_active: u32 = 1; - pub const alt_active: u32 = 2; }; diff --git a/std/os/uefi/protocols/edid_override_protocol.zig b/std/os/uefi/protocols/edid_override_protocol.zig index 7ed1358ed871ff0acefb7d8f4e015865ff5bc5c1..b4d3240ee0732eb89a6dfadfe51c0dde9c1d6149 100644 --- a/std/os/uefi/protocols/edid_override_protocol.zig +++ b/std/os/uefi/protocols/edid_override_protocol.zig @@ -6,7 +6,8 @@ const Handle = uefi.Handle; pub const EdidOverrideProtocol = extern struct { _get_edid: extern fn (*const EdidOverrideProtocol, *const Handle, *u32, *usize, *?[*]u8) usize, - pub fn getEdid(self: *const EdidOverrideProtocol, handle: *const Handle, attributes: *u32, edid_size: *usize, edid: *?[*]u8) usize { + /// attributes must be align(4) + pub fn getEdid(self: *const EdidOverrideProtocol, handle: *const Handle, attributes: *EdidOverrideProtocolAttributes, edid_size: *usize, edid: *?[*]u8) usize { return self._get_edid(self, handle, attributes, edid_size, edid); } @@ -18,6 +19,11 @@ pub const EdidOverrideProtocol = extern struct { .clock_seq_low = 0x22, .node = [_]u8{ 0xf4, 0x58, 0xfe, 0x04, 0x0b, 0xd5 }, }; - pub const dont_override: u32 = 1; - pub const enable_hot_plug: u32 = 2; +}; + +pub const EdidOverrideProtocolAttributes = packed struct { + _pad1: u6, + enable_hot_plug: bool, + dont_override: bool, + _pad2: u24, }; diff --git a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig index 53b0a51f7e1cf8ec6c859e015fb9135d404fc121..78d5cf2c8c25fb38e8238eb6e20255a27bdd7aaf 100644 --- a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig +++ b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig @@ -54,25 +54,30 @@ pub const KeyData = extern struct { }; pub const KeyState = extern struct { - key_shift_state: u32, - key_toggle_state: u8, - - pub const shift_state_valid: u32 = 0x80000000; - pub const right_shift_pressed: u32 = 0x00000001; - pub const left_shift_pressed: u32 = 0x00000002; - pub const right_control_pressed: u32 = 0x00000004; - pub const left_control_pressed: u32 = 0x00000008; - pub const right_alt_pressed: u32 = 0x00000010; - pub const left_alt_pressed: u32 = 0x00000020; - pub const right_logo_pressed: u32 = 0x00000040; - pub const left_logo_pressed: u32 = 0x00000080; - pub const menu_key_pressed: u32 = 0x00000100; - pub const sys_req_pressed: u32 = 0x00000200; - pub const toggle_state_valid: u8 = 0x80; - pub const key_state_exposed: u8 = 0x40; - pub const scroll_lock_active: u8 = 0x01; - pub const num_lock_active: u8 = 0x02; - pub const caps_lock_active: u8 = 0x04; + key_shift_state: packed struct { + left_logo_pressed: bool, + right_logo_pressed: bool, + left_alt_pressed: bool, + right_alt_pressed: bool, + left_control_pressed: bool, + right_control_pressed: bool, + left_shift_pressed: bool, + right_shift_pressed: bool, + _pad1: u6, + sys_req_pressed: bool, + menu_key_pressed: bool, + _pad2: u15, + shift_state_valid: bool, + }, + key_toggle_state: packed struct { + toggle_state_valid: bool, + _pad1: u2, + key_state_exposed: bool, + caps_lock_active: bool, + _pad2: u1, + num_lock_active: bool, + scroll_lock_active: bool, + }, }; pub const InputKey = extern struct { -- 2.54.0 From 88fdb303ff7a33d87207bbd61a648c5c1dbe56ad Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Tue, 6 Aug 2019 18:06:18 +0200 Subject: [PATCH 05/23] std/os/uefi: replace init() with default values --- .../protocols/absolute_pointer_protocol.zig | 17 ++++---------- .../protocols/graphics_output_protocol.zig | 23 +++++-------------- .../protocols/simple_pointer_protocol.zig | 20 ++++------------ .../simple_text_input_ex_protocol.zig | 11 ++------- 4 files changed, 17 insertions(+), 54 deletions(-) diff --git a/std/os/uefi/protocols/absolute_pointer_protocol.zig b/std/os/uefi/protocols/absolute_pointer_protocol.zig index 6621b3128860b92e99bf60dc36beff5e19f7e505..b1fcc4902e0c21fb63b26578d198d35a0e53e3fb 100644 --- a/std/os/uefi/protocols/absolute_pointer_protocol.zig +++ b/std/os/uefi/protocols/absolute_pointer_protocol.zig @@ -43,22 +43,13 @@ pub const AbsolutePointerMode = extern struct { }; pub const AbsolutePointerState = extern struct { - current_x: u64, - current_y: u64, - current_z: u64, + current_x: u64 = undefined, + current_y: u64 = undefined, + current_z: u64 = undefined, active_buttons: packed struct { _pad1: u6, alt_active: bool, touch_active: bool, _pad2: u24, - }, - - pub fn init() AbsolutePointerState { - return AbsolutePointerState{ - .current_x = undefined, - .current_y = undefined, - .current_z = undefined, - .active_buttons = undefined, - }; - } + } = undefined, }; diff --git a/std/os/uefi/protocols/graphics_output_protocol.zig b/std/os/uefi/protocols/graphics_output_protocol.zig index b4ce6a6f563544df65e52ec34f727ddf83503749..4713df0501d16a07fd27a61e59134bd50f376294 100644 --- a/std/os/uefi/protocols/graphics_output_protocol.zig +++ b/std/os/uefi/protocols/graphics_output_protocol.zig @@ -40,23 +40,12 @@ pub const GraphicsOutputProtocolMode = extern struct { }; pub const GraphicsOutputModeInformation = extern struct { - version: u32, - horizontal_resolution: u32, - vertical_resolution: u32, - pixel_format: GraphicsPixelFormat, - pixel_information: PixelBitmask, - pixels_per_scan_line: u32, - - pub fn init() GraphicsOutputModeInformation { - return GraphicsOutputModeInformation{ - .version = undefined, - .horizontal_resolution = undefined, - .vertical_resolution = undefined, - .pixel_format = undefined, - .pixel_information = undefined, - .pixels_per_scan_line = undefined, - }; - } + version: u32 = undefined, + horizontal_resolution: u32 = undefined, + vertical_resolution: u32 = undefined, + pixel_format: GraphicsPixelFormat = undefined, + pixel_information: PixelBitmask = undefined, + pixels_per_scan_line: u32 = undefined, }; pub const GraphicsPixelFormat = extern enum(u32) { diff --git a/std/os/uefi/protocols/simple_pointer_protocol.zig b/std/os/uefi/protocols/simple_pointer_protocol.zig index 8a84bb4ccf65f2c07eb4abc1f0fa7337fa6c77a2..26d11ca7f54d06401e5dbe3a8b056630bac95ad2 100644 --- a/std/os/uefi/protocols/simple_pointer_protocol.zig +++ b/std/os/uefi/protocols/simple_pointer_protocol.zig @@ -36,19 +36,9 @@ pub const SimplePointerMode = struct { }; pub const SimplePointerState = struct { - relative_movement_x: i32, - relative_movement_y: i32, - relative_movement_z: i32, - left_button: bool, - right_button: bool, - - pub fn init() SimplePointerState { - return SimplePointerState{ - .relative_movement_x = undefined, - .relative_movement_y = undefined, - .relative_movement_z = undefined, - .left_button = undefined, - .right_button = undefined, - }; - } + relative_movement_x: i32 = undefined, + relative_movement_y: i32 = undefined, + relative_movement_z: i32 = undefined, + left_button: bool = undefined, + right_button: bool = undefined, }; diff --git a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig index 78d5cf2c8c25fb38e8238eb6e20255a27bdd7aaf..16f676fd2d0f7c2b83b916d26bf4edf4f6715701 100644 --- a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig +++ b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig @@ -42,15 +42,8 @@ pub const SimpleTextInputExProtocol = extern struct { }; pub const KeyData = extern struct { - key: InputKey, - key_state: KeyState, - - pub fn init() KeyData { - return KeyData{ - .key = undefined, - .key_state = undefined, - }; - } + key: InputKey = undefined, + key_state: KeyState = undefined, }; pub const KeyState = extern struct { -- 2.54.0 From 9445b3f057bdeb57cdb02c86b94145ae9a345531 Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Fri, 9 Aug 2019 23:12:59 +0200 Subject: [PATCH 06/23] std/os/uefi: change type of Handle from @OpaqueType to *@OpaqueType --- std/os/uefi.zig | 4 ++-- std/os/uefi/protocols/edid_override_protocol.zig | 4 ++-- std/os/uefi/tables/boot_services.zig | 2 +- std/os/uefi/tables/system_table.zig | 6 +++--- std/special/start.zig | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/std/os/uefi.zig b/std/os/uefi.zig index 58508df38f20a469860ee5ea9f4ba177d9b8d030..9ddaad5aa6cb7491f71cf934ccb2e1b79c700008 100644 --- a/std/os/uefi.zig +++ b/std/os/uefi.zig @@ -5,7 +5,7 @@ pub const tables = @import("uefi/tables.zig"); const builtin = @import("builtin"); pub const is_the_target = builtin.os == .uefi; -pub var handle: *Handle = undefined; +pub var handle: Handle = undefined; pub var system_table: *tables.SystemTable = undefined; pub const Event = @OpaqueType(); @@ -18,7 +18,7 @@ pub const Guid = extern struct { clock_seq_low: u8, node: [6]u8, }; -pub const Handle = @OpaqueType(); +pub const Handle = *@OpaqueType(); pub const Time = extern struct { year: u16, month: u8, diff --git a/std/os/uefi/protocols/edid_override_protocol.zig b/std/os/uefi/protocols/edid_override_protocol.zig index b4d3240ee0732eb89a6dfadfe51c0dde9c1d6149..f7228f3c7a0ba44155caad348852e5609ba87ace 100644 --- a/std/os/uefi/protocols/edid_override_protocol.zig +++ b/std/os/uefi/protocols/edid_override_protocol.zig @@ -4,10 +4,10 @@ const Handle = uefi.Handle; /// UEFI Specification, Version 2.8, 12.9 pub const EdidOverrideProtocol = extern struct { - _get_edid: extern fn (*const EdidOverrideProtocol, *const Handle, *u32, *usize, *?[*]u8) usize, + _get_edid: extern fn (*const EdidOverrideProtocol, Handle, *u32, *usize, *?[*]u8) usize, /// attributes must be align(4) - pub fn getEdid(self: *const EdidOverrideProtocol, handle: *const Handle, attributes: *EdidOverrideProtocolAttributes, edid_size: *usize, edid: *?[*]u8) usize { + pub fn getEdid(self: *const EdidOverrideProtocol, handle: Handle, attributes: *EdidOverrideProtocolAttributes, edid_size: *usize, edid: *?[*]u8) usize { return self._get_edid(self, handle, attributes, edid_size, edid); } diff --git a/std/os/uefi/tables/boot_services.zig b/std/os/uefi/tables/boot_services.zig index 2ae234f77d1d61fffadb7eebd5bb41faa7887772..813677910be704754cceb0947556bb4b1181d02d 100644 --- a/std/os/uefi/tables/boot_services.zig +++ b/std/os/uefi/tables/boot_services.zig @@ -39,7 +39,7 @@ pub const BootServices = extern struct { installConfigurationTable: usize, // TODO imageLoad: usize, // TODO imageStart: usize, // TODO - exit: extern fn (*const Handle, usize, usize, ?*const c_void) usize, + exit: extern fn (Handle, usize, usize, ?*const c_void) usize, imageUnload: usize, // TODO exitBootServices: usize, // TODO getNextMonotonicCount: usize, // TODO diff --git a/std/os/uefi/tables/system_table.zig b/std/os/uefi/tables/system_table.zig index 31534d03be951039696ece463f13943f661ebedc..23140f984e202e25ac2fc4d6d568cae9b6bd9718 100644 --- a/std/os/uefi/tables/system_table.zig +++ b/std/os/uefi/tables/system_table.zig @@ -19,11 +19,11 @@ pub const SystemTable = extern struct { hdr: TableHeader, firmware_vendor: *u16, firmware_revision: u32, - console_in_handle: ?*Handle, + console_in_handle: ?Handle, con_in: ?*SimpleTextInputExProtocol, - console_out_handle: ?*Handle, + console_out_handle: ?Handle, con_out: ?*SimpleTextOutputProtocol, - standard_error_handle: ?*Handle, + standard_error_handle: ?Handle, std_err: ?*SimpleTextOutputProtocol, runtime_services: *RuntimeServices, boot_services: ?*BootServices, diff --git a/std/special/start.zig b/std/special/start.zig index dbd0912d9770486205035a77b8272e1e97922861..cffd432f741638e0e363e56341bf10965ed97506 100644 --- a/std/special/start.zig +++ b/std/special/start.zig @@ -31,7 +31,7 @@ extern fn wasm_freestanding_start() void { _ = callMain(); } -extern fn EfiMain(handle: *uefi.Handle, system_table: *uefi.tables.SystemTable) usize { +extern fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) usize { const bad_efi_main_ret = "expected return type of main to be 'void', 'noreturn', or 'usize'"; uefi.handle = handle; uefi.system_table = system_table; -- 2.54.0 From 47ce736abec2d97c70eed619b5a6a58edeb4816a Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Sat, 10 Aug 2019 00:32:43 +0200 Subject: [PATCH 07/23] std/os/uefi: add basic Event support --- std/os/uefi.zig | 2 +- .../protocols/absolute_pointer_protocol.zig | 2 +- .../protocols/simple_pointer_protocol.zig | 2 +- .../simple_text_input_ex_protocol.zig | 2 +- std/os/uefi/tables.zig | 1 + std/os/uefi/tables/boot_services.zig | 25 ++++++++++++++++--- 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/std/os/uefi.zig b/std/os/uefi.zig index 9ddaad5aa6cb7491f71cf934ccb2e1b79c700008..db46d50c1ffa909fa19932546e4bae9c0eb85dcd 100644 --- a/std/os/uefi.zig +++ b/std/os/uefi.zig @@ -8,7 +8,7 @@ pub const is_the_target = builtin.os == .uefi; pub var handle: Handle = undefined; pub var system_table: *tables.SystemTable = undefined; -pub const Event = @OpaqueType(); +pub const Event = *@OpaqueType(); // GUIDs must be align(8) pub const Guid = extern struct { time_low: u32, diff --git a/std/os/uefi/protocols/absolute_pointer_protocol.zig b/std/os/uefi/protocols/absolute_pointer_protocol.zig index b1fcc4902e0c21fb63b26578d198d35a0e53e3fb..8be52ad7e473ffcd0c96aa80cb1ce50d87e2d960 100644 --- a/std/os/uefi/protocols/absolute_pointer_protocol.zig +++ b/std/os/uefi/protocols/absolute_pointer_protocol.zig @@ -6,7 +6,7 @@ const Guid = uefi.Guid; pub const AbsolutePointerProtocol = extern struct { _reset: extern fn (*const AbsolutePointerProtocol, bool) usize, _get_state: extern fn (*const AbsolutePointerProtocol, *AbsolutePointerState) usize, - wait_for_input: *Event, + wait_for_input: Event, mode: *AbsolutePointerMode, pub fn reset(self: *const AbsolutePointerProtocol, verify: bool) usize { diff --git a/std/os/uefi/protocols/simple_pointer_protocol.zig b/std/os/uefi/protocols/simple_pointer_protocol.zig index 26d11ca7f54d06401e5dbe3a8b056630bac95ad2..369bc76aaa0e7a4687a6df53eece51e27b412d26 100644 --- a/std/os/uefi/protocols/simple_pointer_protocol.zig +++ b/std/os/uefi/protocols/simple_pointer_protocol.zig @@ -6,7 +6,7 @@ const Guid = uefi.Guid; pub const SimplePointerProtocol = struct { _reset: extern fn (*const SimplePointerProtocol, bool) usize, _get_state: extern fn (*const SimplePointerProtocol, *SimplePointerState) usize, - wait_for_input: *Event, + wait_for_input: Event, mode: *SimplePointerMode, pub fn reset(self: *const SimplePointerProtocol, verify: bool) usize { diff --git a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig index 16f676fd2d0f7c2b83b916d26bf4edf4f6715701..e23a68bacfbb3ab0fa44b6c4d5cfebbb45b4492c 100644 --- a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig +++ b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig @@ -6,7 +6,7 @@ const Guid = uefi.Guid; pub const SimpleTextInputExProtocol = extern struct { _reset: extern fn (*const SimpleTextInputExProtocol, bool) usize, _read_key_stroke_ex: extern fn (*const SimpleTextInputExProtocol, *KeyData) usize, - wait_for_key_ex: *Event, + wait_for_key_ex: Event, _set_state: extern fn (*const SimpleTextInputExProtocol, *const u8) usize, _register_key_notify: extern fn (*const SimpleTextInputExProtocol, *const KeyData, extern fn (*const KeyData) usize, **c_void) usize, _unregister_key_notify: extern fn (*const SimpleTextInputExProtocol, *const c_void) usize, diff --git a/std/os/uefi/tables.zig b/std/os/uefi/tables.zig index e5867ae657fd4f012ff810aa448e1417579366c2..51caed19d175c832962c095c9d1b78a6c91522a0 100644 --- a/std/os/uefi/tables.zig +++ b/std/os/uefi/tables.zig @@ -4,3 +4,4 @@ pub const ResetType = @import("tables/runtime_services.zig").ResetType; pub const RuntimeServices = @import("tables/runtime_services.zig").RuntimeServices; pub const SystemTable = @import("tables/system_table.zig").SystemTable; pub const TableHeader = @import("tables/table_header.zig").TableHeader; +pub const TimerDelay = @import("tables/boot_services.zig").TimerDelay; diff --git a/std/os/uefi/tables/boot_services.zig b/std/os/uefi/tables/boot_services.zig index 813677910be704754cceb0947556bb4b1181d02d..6007552bdda098bdf5abce034e70b36b4ab47263 100644 --- a/std/os/uefi/tables/boot_services.zig +++ b/std/os/uefi/tables/boot_services.zig @@ -1,4 +1,5 @@ const uefi = @import("std").os.uefi; +const Event = uefi.Event; const Guid = uefi.Guid; const Handle = uefi.Handle; const TableHeader = uefi.tables.TableHeader; @@ -22,10 +23,10 @@ pub const BootServices = extern struct { getMemoryMap: usize, // TODO allocatePool: usize, // TODO freePool: usize, // TODO - createEvent: usize, // TODO - setTimer: usize, // TODO + createEvent: extern fn (u32, usize, ?extern fn (Event, ?*const c_void) void, ?*const c_void, *Event) usize, + setTimer: extern fn (Event, TimerDelay, u64) usize, waitForEvent: usize, // TODO - signalEvent: usize, // TODO + signalEvent: extern fn (Event) usize, closeEvent: usize, // TODO checkEvent: usize, // TODO installProtocolInterface: usize, // TODO @@ -61,4 +62,22 @@ pub const BootServices = extern struct { createEventEx: usize, // TODO pub const signature: u64 = 0x56524553544f4f42; + + pub const event_timer: u32 = 0x80000000; + pub const event_runtime: u32 = 0x40000000; + pub const event_notify_wait: u32 = 0x00000100; + pub const event_notify_signal: u32 = 0x00000200; + pub const event_signal_exit_boot_services: u32 = 0x00000201; + pub const event_signal_virtual_address_change: u32 = 0x00000202; + + pub const tpl_application: usize = 4; + pub const tpl_callback: usize = 8; + pub const tpl_notify: usize = 16; + pub const tpl_high_level: usize = 31; +}; + +pub const TimerDelay = extern enum(u32) { + TimerCancel, + TimerPeriodic, + TimerRelative, }; -- 2.54.0 From a9b3700c6e5dbc830b648a585970ad61a34c5d63 Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Sat, 10 Aug 2019 01:00:09 +0200 Subject: [PATCH 08/23] src/codegen: configure stack probes explicitly --- src/codegen.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/codegen.cpp b/src/codegen.cpp index 6ab76dea355869dcb9e154175bec5b970005360d..91c4a47a5a0690bfa5484bfe0aad61b880e163f3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -474,6 +474,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) { } if (g->have_stack_probing && !fn_table_entry->def_scope->safety_off) { addLLVMFnAttrStr(fn_table_entry->llvm_value, "probe-stack", "__zig_probe_stack"); + } else { + addLLVMFnAttrStr(fn_table_entry->llvm_value, "no-stack-arg-probe", ""); } } else { maybe_import_dll(g, fn_table_entry->llvm_value, linkage); -- 2.54.0 From 70e62b86121dc5d54073bb34fe950ce6b3dff2cd Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Sun, 11 Aug 2019 15:50:03 +0200 Subject: [PATCH 09/23] std/os/uefi: some more events --- std/os/uefi/tables/boot_services.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/std/os/uefi/tables/boot_services.zig b/std/os/uefi/tables/boot_services.zig index 6007552bdda098bdf5abce034e70b36b4ab47263..ae548137c3188c9de03f390c726036779f6ffa76 100644 --- a/std/os/uefi/tables/boot_services.zig +++ b/std/os/uefi/tables/boot_services.zig @@ -25,9 +25,9 @@ pub const BootServices = extern struct { freePool: usize, // TODO createEvent: extern fn (u32, usize, ?extern fn (Event, ?*const c_void) void, ?*const c_void, *Event) usize, setTimer: extern fn (Event, TimerDelay, u64) usize, - waitForEvent: usize, // TODO + waitForEvent: extern fn (usize, [*]const Event, *usize) usize, signalEvent: extern fn (Event) usize, - closeEvent: usize, // TODO + closeEvent: extern fn (Event) usize, checkEvent: usize, // TODO installProtocolInterface: usize, // TODO reinstallProtocolInterface: usize, // TODO -- 2.54.0 From 03abc6edf450cfa6a55a3d416def44595a19a453 Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Mon, 2 Sep 2019 20:34:00 +0200 Subject: [PATCH 10/23] std/os/uefi: add global_variable guid --- std/os/uefi/tables.zig | 1 + std/os/uefi/tables/runtime_services.zig | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/std/os/uefi/tables.zig b/std/os/uefi/tables.zig index 51caed19d175c832962c095c9d1b78a6c91522a0..901591dea4ef0c4e2274c2d668a95e7b3d53f1cf 100644 --- a/std/os/uefi/tables.zig +++ b/std/os/uefi/tables.zig @@ -1,5 +1,6 @@ pub const BootServices = @import("tables/boot_services.zig").BootServices; pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable; +pub const global_variable align(8) = @import("tables/runtime_services.zig").global_variable; pub const ResetType = @import("tables/runtime_services.zig").ResetType; pub const RuntimeServices = @import("tables/runtime_services.zig").RuntimeServices; pub const SystemTable = @import("tables/system_table.zig").SystemTable; diff --git a/std/os/uefi/tables/runtime_services.zig b/std/os/uefi/tables/runtime_services.zig index bae808ac85fcda63a3e9b88fb07a7e6bc3617cc1..53cb17db501628a4fe8a6f71aa3182d8ed080395 100644 --- a/std/os/uefi/tables/runtime_services.zig +++ b/std/os/uefi/tables/runtime_services.zig @@ -39,3 +39,13 @@ pub const ResetType = extern enum(u32) { ResetShutdown, ResetPlatformSpecific, }; + +/// UEFI Specification, Version 2.8, 3.3 +pub const global_variable align(8) = Guid{ + .time_low = 0x8be4df61, + .time_mid = 0x93ca, + .time_high_and_version = 0x11d2, + .clock_seq_high_and_reserved = 0xaa, + .clock_seq_low = 0x0d, + .node = [_]u8{ 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c }, +}; -- 2.54.0 From 8db41b7adbd0d1112a914d05ed94e9b55cfaf2db Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Mon, 2 Sep 2019 19:04:26 +0200 Subject: [PATCH 11/23] std/os/uefi: add support for getting memory map --- std/os/uefi/tables.zig | 1 + std/os/uefi/tables/boot_services.zig | 44 +++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/std/os/uefi/tables.zig b/std/os/uefi/tables.zig index 901591dea4ef0c4e2274c2d668a95e7b3d53f1cf..fbb9abe7f6feabcfc89238e1d0315b5be6b0d6a8 100644 --- a/std/os/uefi/tables.zig +++ b/std/os/uefi/tables.zig @@ -1,6 +1,7 @@ pub const BootServices = @import("tables/boot_services.zig").BootServices; pub const ConfigurationTable = @import("tables/configuration_table.zig").ConfigurationTable; pub const global_variable align(8) = @import("tables/runtime_services.zig").global_variable; +pub const MemoryDescriptor = @import("tables/boot_services.zig").MemoryDescriptor; pub const ResetType = @import("tables/runtime_services.zig").ResetType; pub const RuntimeServices = @import("tables/runtime_services.zig").RuntimeServices; pub const SystemTable = @import("tables/system_table.zig").SystemTable; diff --git a/std/os/uefi/tables/boot_services.zig b/std/os/uefi/tables/boot_services.zig index ae548137c3188c9de03f390c726036779f6ffa76..55b0de3478940cd2dd526b90b29d18607e8227ee 100644 --- a/std/os/uefi/tables/boot_services.zig +++ b/std/os/uefi/tables/boot_services.zig @@ -20,7 +20,7 @@ pub const BootServices = extern struct { restoreTpl: usize, // TODO allocatePages: usize, // TODO freePages: usize, // TODO - getMemoryMap: usize, // TODO + getMemoryMap: extern fn (*usize, [*]MemoryDescriptor, *usize, *usize, *u32) usize, allocatePool: usize, // TODO freePool: usize, // TODO createEvent: extern fn (u32, usize, ?extern fn (Event, ?*const c_void) void, ?*const c_void, *Event) usize, @@ -81,3 +81,45 @@ pub const TimerDelay = extern enum(u32) { TimerPeriodic, TimerRelative, }; + +pub const MemoryDescriptor = extern struct { + type: extern enum(u32) { + ReservedMemoryType, + LoaderCode, + LoaderData, + BootServicesCode, + BootServicesData, + RuntimeServicesCode, + RuntimeServicesData, + ConventionalMemory, + UnusableMemory, + ACPIReclaimMemory, + ACPIMemoryNVS, + MemoryMappedIO, + MemoryMappedIOPortSpace, + PalCode, + PersistentMemory, + MaxMemoryType, + }, + physical_start: u64, + virtual_start: u64, + number_of_pages: usize, + attribute: packed struct { + uc: bool, + wc: bool, + wt: bool, + wb: bool, + uce: bool, + _pad1: u7, + wp: bool, + rp: bool, + xp: bool, + nv: bool, + more_reliable: bool, + ro: bool, + sp: bool, + cpu_crypto: bool, + _pad2: u43, + memory_runtime: bool, + }, +}; -- 2.54.0 From 5e874a89b991fcabe8177c551c220894593c1632 Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Mon, 2 Sep 2019 22:31:59 +0200 Subject: [PATCH 12/23] std/os/uefi: fix ordering of packed bit fields --- .../protocols/absolute_pointer_protocol.zig | 10 +++---- .../uefi/protocols/edid_override_protocol.zig | 5 ++-- .../simple_text_input_ex_protocol.zig | 30 +++++++++---------- 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/std/os/uefi/protocols/absolute_pointer_protocol.zig b/std/os/uefi/protocols/absolute_pointer_protocol.zig index 8be52ad7e473ffcd0c96aa80cb1ce50d87e2d960..df5a930319e521269b79b0bedf0d511a365cdbff 100644 --- a/std/os/uefi/protocols/absolute_pointer_protocol.zig +++ b/std/os/uefi/protocols/absolute_pointer_protocol.zig @@ -35,10 +35,9 @@ pub const AbsolutePointerMode = extern struct { absolute_max_y: u64, absolute_max_z: u64, attributes: packed struct { - _pad1: u6, - supports_pressure_as_z: bool, supports_alt_active: bool, - _pad2: u24, + supports_pressure_as_z: bool, + _pad1: u30, }, }; @@ -47,9 +46,8 @@ pub const AbsolutePointerState = extern struct { current_y: u64 = undefined, current_z: u64 = undefined, active_buttons: packed struct { - _pad1: u6, - alt_active: bool, touch_active: bool, - _pad2: u24, + alt_active: bool, + _pad1: u30, } = undefined, }; diff --git a/std/os/uefi/protocols/edid_override_protocol.zig b/std/os/uefi/protocols/edid_override_protocol.zig index f7228f3c7a0ba44155caad348852e5609ba87ace..ad2eec12073abfe23cb2cb9464c705bd1f200eca 100644 --- a/std/os/uefi/protocols/edid_override_protocol.zig +++ b/std/os/uefi/protocols/edid_override_protocol.zig @@ -22,8 +22,7 @@ pub const EdidOverrideProtocol = extern struct { }; pub const EdidOverrideProtocolAttributes = packed struct { - _pad1: u6, - enable_hot_plug: bool, dont_override: bool, - _pad2: u24, + enable_hot_plug: bool, + _pad1: u30, }; diff --git a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig index e23a68bacfbb3ab0fa44b6c4d5cfebbb45b4492c..5507b8950ca358de7c65655fea7fe51478a85958 100644 --- a/std/os/uefi/protocols/simple_text_input_ex_protocol.zig +++ b/std/os/uefi/protocols/simple_text_input_ex_protocol.zig @@ -48,28 +48,26 @@ pub const KeyData = extern struct { pub const KeyState = extern struct { key_shift_state: packed struct { - left_logo_pressed: bool, - right_logo_pressed: bool, - left_alt_pressed: bool, - right_alt_pressed: bool, - left_control_pressed: bool, - right_control_pressed: bool, - left_shift_pressed: bool, right_shift_pressed: bool, - _pad1: u6, - sys_req_pressed: bool, + left_shift_pressed: bool, + right_control_pressed: bool, + left_control_pressed: bool, + right_alt_pressed: bool, + left_alt_pressed: bool, + right_logo_pressed: bool, + left_logo_pressed: bool, menu_key_pressed: bool, - _pad2: u15, + sys_req_pressed: bool, + _pad1: u21, shift_state_valid: bool, }, key_toggle_state: packed struct { - toggle_state_valid: bool, - _pad1: u2, - key_state_exposed: bool, - caps_lock_active: bool, - _pad2: u1, - num_lock_active: bool, scroll_lock_active: bool, + num_lock_active: bool, + caps_lock_active: bool, + _pad1: u3, + key_state_exposed: bool, + toggle_state_valid: bool, }, }; -- 2.54.0 From c9b2210fcf58d9e99851ad2a6a1219c997cf0d82 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 10 Sep 2019 22:59:00 -0400 Subject: [PATCH 13/23] async function calls re-use frame buffers See #3069 --- src/analyze.cpp | 23 +++++++++++++++++++++-- src/codegen.cpp | 13 ++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 4347f06699d6e89b1684e52430bb036297d6fde2..946bbd17ae8804beec9afab8c4f1d8dc9757254f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2538,6 +2538,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { enum_type->data.enumeration.resolve_loop_flag = false; enum_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; + occupied_tag_values.deinit(); + return ErrorNone; } @@ -5878,6 +5880,11 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { fn->err_code_spill = &alloca_gen->base; } + ZigType *largest_call_frame_type = nullptr; + // Later we'll change this to be largest_call_frame_type instead of void. + IrInstruction *all_calls_alloca = ir_create_alloca(g, &fn->fndef_scope->base, fn->body_node, + fn, g->builtin_types.entry_void, "@async_call_frame"); + for (size_t i = 0; i < fn->call_list.length; i += 1) { IrInstructionCallGen *call = fn->call_list.at(i); if (call->new_stack != nullptr) { @@ -5921,9 +5928,21 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { mark_suspension_point(call->base.scope); - call->frame_result_loc = ir_create_alloca(g, call->base.scope, call->base.source_node, fn, - callee_frame_type, ""); + if ((err = type_resolve(g, callee_frame_type, ResolveStatusSizeKnown))) { + return err; + } + if (largest_call_frame_type == nullptr || + callee_frame_type->abi_size > largest_call_frame_type->abi_size) + { + largest_call_frame_type = callee_frame_type; + } + + call->frame_result_loc = all_calls_alloca; } + if (largest_call_frame_type != nullptr) { + all_calls_alloca->value.type = get_pointer_to_type(g, largest_call_frame_type, false); + } + // Since this frame is async, an await might represent a suspend point, and // therefore need to spill. It also needs to mark expr scopes as having to spill. // For example: foo() + await z diff --git a/src/codegen.cpp b/src/codegen.cpp index a4ceae57d95b87036cec2faee4c7642796eb1683..a9542f96d9214c2b884299a84aec35fe27a9f3e4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3863,6 +3863,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr ZigList gen_param_types = {}; LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr; LLVMValueRef zero = LLVMConstNull(usize_type_ref); + LLVMValueRef frame_result_loc_uncasted = nullptr; LLVMValueRef frame_result_loc; LLVMValueRef awaiter_init_val; LLVMValueRef ret_ptr; @@ -3871,7 +3872,10 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (instruction->modifier == CallModifierAsync) { frame_result_loc = result_loc; } else { - frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); + frame_result_loc_uncasted = ir_llvm_value(g, instruction->frame_result_loc); + src_assert(instruction->fn_entry != nullptr, instruction->base.source_node); + frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, + LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), ""); } } else { if (instruction->new_stack->value.type->id == ZigTypeIdPointer && @@ -4138,6 +4142,13 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr } } + if (frame_result_loc_uncasted != nullptr && instruction->fn_entry != nullptr) { + // Instead of a spill, we do the bitcast again. The uncasted LLVM IR instruction will + // be an Alloca from the entry block, so it does not need to be spilled. + frame_result_loc = LLVMBuildBitCast(g->builder, frame_result_loc_uncasted, + LLVMPointerType(get_llvm_type(g, instruction->fn_entry->frame_type), 0), ""); + } + LLVMValueRef result_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); return LLVMBuildLoad(g->builder, result_ptr, ""); } -- 2.54.0 From 67491a4222f2dacf047989329d4c16a5a2f163d5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 11 Sep 2019 15:01:21 -0400 Subject: [PATCH 14/23] disable runtime safety in std.io.InStream Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream read. This is equivalent to the fact that we don't memset the entire call stack to 0xaa for every function call. --- std/io/in_stream.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/io/in_stream.zig b/std/io/in_stream.zig index 850f8dcb067abe8893ee1ef683f8329b7d45040e..c617f10500485d104388b10ec1b8490d9abec458 100644 --- a/std/io/in_stream.zig +++ b/std/io/in_stream.zig @@ -32,10 +32,10 @@ pub fn InStream(comptime ReadError: type) type { /// End of stream is not an error condition. pub fn read(self: *Self, buffer: []u8) Error!usize { if (std.io.is_async) { + // Let's not be writing 0xaa in safe modes for upwards of 4 MiB for every stream read. + @setRuntimeSafety(false); var stack_frame: [stack_size]u8 align(stack_align) = undefined; - // TODO https://github.com/ziglang/zig/issues/3068 - var result: Error!usize = undefined; - return await @asyncCall(&stack_frame, &result, self.readFn, self, buffer); + return await @asyncCall(&stack_frame, {}, self.readFn, self, buffer); } else { return self.readFn(self, buffer); } -- 2.54.0 From 0eddee449d8a09a999b352d769b98379865e8dbc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 11 Sep 2019 15:05:00 -0400 Subject: [PATCH 15/23] add behavior test for `@enumToInt(enum(u1){x}.x)` closes #2737 --- test/stage1/behavior/enum.zig | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 24ea2f9583c699c7d0a30758a3b737a5d11de9b4..3f6b2b7bd3a5f45e12edef7c3b318a333d81a729 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1007,3 +1007,10 @@ test "enum literal casting to error union with payload enum" { expect((try bar) == Bar.B); } + +test "enum with one member and u1 tag type @enumToInt" { + const Enum = enum(u1) { + Test, + }; + expect(@enumToInt(Enum.Test) == 0); +} -- 2.54.0 From f36b8fd7b2c89d46dba95eca05b60487638dd2a0 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 11 Sep 2019 11:46:51 +0200 Subject: [PATCH 16/23] Recognize & skip the UTF-8 BOM --- src/tokenizer.cpp | 9 +++++++-- std/zig/tokenizer.zig | 11 ++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 465f652288fb30b37a5cc48cf43284dd36a6431f..71a24fe726758713922fa58f6d70f182fe6f83cb 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -407,9 +407,14 @@ void tokenize(Buf *buf, Tokenization *out) { t.buf = buf; out->line_offsets = allocate>(1); - out->line_offsets->append(0); - for (t.pos = 0; t.pos < buf_len(t.buf); t.pos += 1) { + + // Skip the UTF-8 BOM if present + if (buf_starts_with_mem(buf, "\xEF\xBB\xBF", 3)) { + t.pos += 3; + } + + for (; t.pos < buf_len(t.buf); t.pos += 1) { uint8_t c = buf_ptr(t.buf)[t.pos]; switch (t.state) { case TokenizeStateError: diff --git a/std/zig/tokenizer.zig b/std/zig/tokenizer.zig index 19fb233567d4c99ef9f8595b12e9c0c75dd8c23a..f25da12a91912f30ef87a084204135a6f0138a91 100644 --- a/std/zig/tokenizer.zig +++ b/std/zig/tokenizer.zig @@ -222,9 +222,11 @@ pub const Tokenizer = struct { }, }; } else { + // Skip the UTF-8 BOM if present + const src_start = if (mem.startsWith(u8, buffer, "\xEF\xBB\xBF")) 3 else usize(0); return Tokenizer{ .buffer = buffer, - .index = 0, + .index = src_start, .pending_invalid_token = null, }; } @@ -1455,6 +1457,13 @@ test "tokenizer - line comment followed by identifier" { }); } +test "tokenizer - UTF-8 BOM is recognized and skipped" { + testTokenize("\xEF\xBB\xBFa;\n", [_]Token.Id{ + Token.Id.Identifier, + Token.Id.Semicolon, + }); +} + fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { var tokenizer = Tokenizer.init(source); for (expected_tokens) |expected_token_id| { -- 2.54.0 From 68b49f74c45f9d46ceca0196ad5b2edeee30e26f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 11 Sep 2019 16:19:46 -0400 Subject: [PATCH 17/23] consolidate std.debug.parseDie and std.debug.parseDie1 --- std/debug.zig | 29 +++++------------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/std/debug.zig b/std/debug.zig index 344396efa7d184430300a5dd76d7a7b903dfc92c..377e6e4845de615b13b74343446affb5114b47af 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -1655,7 +1655,7 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con return null; } -fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die { +fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Die { const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream); if (abbrev_code == 0) return null; const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; @@ -1675,25 +1675,6 @@ fn parseDie1(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !?Di return result; } -fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { - const abbrev_code = try leb.readULEB128(u64, di.dwarf_in_stream); - const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; - - var result = Die{ - .tag_id = table_entry.tag_id, - .has_children = table_entry.has_children, - .attrs = ArrayList(Die.Attr).init(di.allocator()), - }; - try result.attrs.resize(table_entry.attrs.len); - for (table_entry.attrs.toSliceConst()) |attr, i| { - result.attrs.items[i] = Die.Attr{ - .id = attr.attr_id, - .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64), - }; - } - return result; -} - fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: usize) !LineInfo { const ofile = symbol.ofile orelse return error.MissingDebugInfo; const gop = try di.ofiles.getOrPut(ofile); @@ -2103,7 +2084,7 @@ fn scanAllFunctions(di: *DwarfInfo) !void { const next_unit_pos = this_unit_offset + next_offset; while ((try di.dwarf_seekable_stream.getPos()) < next_unit_pos) { - const die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse continue; + const die_obj = (try parseDie(di, abbrev_table, is_64)) orelse continue; const after_die_offset = try di.dwarf_seekable_stream.getPos(); switch (die_obj.tag_id) { @@ -2121,13 +2102,13 @@ fn scanAllFunctions(di: *DwarfInfo) !void { const ref_offset = try this_die_obj.getAttrRef(DW.AT_abstract_origin); if (ref_offset > next_offset) return error.InvalidDebugInfo; try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset); - this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; + this_die_obj = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; } else if (this_die_obj.getAttr(DW.AT_specification)) |ref| { // Follow the DIE it points to and repeat const ref_offset = try this_die_obj.getAttrRef(DW.AT_specification); if (ref_offset > next_offset) return error.InvalidDebugInfo; try di.dwarf_seekable_stream.seekTo(this_unit_offset + ref_offset); - this_die_obj = (try parseDie1(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; + this_die_obj = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; } else { break :x null; } @@ -2203,7 +2184,7 @@ fn scanAllCompileUnits(di: *DwarfInfo) !void { try di.dwarf_seekable_stream.seekTo(compile_unit_pos); const compile_unit_die = try di.allocator().create(Die); - compile_unit_die.* = try parseDie(di, abbrev_table, is_64); + compile_unit_die.* = (try parseDie(di, abbrev_table, is_64)) orelse return error.InvalidDebugInfo; if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; -- 2.54.0 From cf4bccf76566ac112f9142863c3e4dbf81e71d08 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 11 Sep 2019 20:22:49 -0400 Subject: [PATCH 18/23] improvements targeted at improving async functions * Reuse bytes of async function frames when non-async functions make `noasync` calls. This prevents explosive stack growth. * Zig now passes a stack size argument to the linker when linking ELF binaries. Linux ignores this value, but it is available as a program header called GNU_STACK. I prototyped some code that memory maps extra space to the stack using this program header, but there was still a problem when accessing stack memory very far down. Stack probing is needed or not working or something. I also prototyped using `@newStackCall` to call main and that does work around the issue but it also brings its own issues. That code is commented out for now in std/special/start.zig. I'm on a plane with no Internet, but I plan to consult with the musl community for advice when I get a chance. * Added `noasync` to a bunch of function calls in std.debug. It's very messy but it's a workaround that makes stack traces functional with evented I/O enabled. Eventually these will be cleaned up as the root bugs are found and fixed. Programs built in blocking mode are unaffected. * Lowered the default stack size of std.io.InStream (for the async version) to 1 MiB instead of 4. Until we figure out how to get choosing a stack size working (see 2nd bullet point above), 4 MiB tends to cause segfaults due to stack size running out, or usage of stack memory too far apart, or something like that. * Default thread stack size is bumped from 8 MiB to 16 to match the size we give for the main thread. It's planned to eventually remove this hard coded value and have Zig able to determine this value during semantic analysis, with call graph analysis and function pointer annotations and extern function annotations. --- src/codegen.cpp | 14 +++++++++++-- src/link.cpp | 5 +++++ std/debug.zig | 49 ++++++++++++++++++++++++++++++------------- std/io/in_stream.zig | 2 +- std/os/linux/tls.zig | 7 ++++++- std/special/start.zig | 43 ++++++++++++++++++++++++++----------- std/thread.zig | 2 +- 7 files changed, 90 insertions(+), 32 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index a9542f96d9214c2b884299a84aec35fe27a9f3e4..200589cd2a49dbeb147258a7eb784f2b2869aa1d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7184,6 +7184,9 @@ static void do_code_gen(CodeGen *g) { if (!is_async) { // allocate async frames for noasync calls & awaits to async functions + ZigType *largest_call_frame_type = nullptr; + IrInstruction *all_calls_alloca = ir_create_alloca(g, &fn_table_entry->fndef_scope->base, + fn_table_entry->body_node, fn_table_entry, g->builtin_types.entry_void, "@async_call_frame"); for (size_t i = 0; i < fn_table_entry->call_list.length; i += 1) { IrInstructionCallGen *call = fn_table_entry->call_list.at(i); if (call->fn_entry == nullptr) @@ -7195,8 +7198,15 @@ static void do_code_gen(CodeGen *g) { if (call->frame_result_loc != nullptr) continue; ZigType *callee_frame_type = get_fn_frame_type(g, call->fn_entry); - call->frame_result_loc = ir_create_alloca(g, call->base.scope, call->base.source_node, - fn_table_entry, callee_frame_type, ""); + if (largest_call_frame_type == nullptr || + callee_frame_type->abi_size > largest_call_frame_type->abi_size) + { + largest_call_frame_type = callee_frame_type; + } + call->frame_result_loc = all_calls_alloca; + } + if (largest_call_frame_type != nullptr) { + all_calls_alloca->value.type = get_pointer_to_type(g, largest_call_frame_type, false); } // allocate temporary stack data for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) { diff --git a/src/link.cpp b/src/link.cpp index 1130481dce85ae4ac927f80d6dda6e5882f53fa0..b10220d5da9a9bd24073a75606e1392fb11a5ac7 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -1615,6 +1615,11 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append("-error-limit=0"); + if (g->out_type == OutTypeExe) { + lj->args.append("-z"); + lj->args.append("stack-size=16777216"); // default to 16 MiB + } + if (g->linker_script) { lj->args.append("-T"); lj->args.append(g->linker_script); diff --git a/std/debug.zig b/std/debug.zig index 377e6e4845de615b13b74343446affb5114b47af..9fd2c0ff531b99d828fc8f8336bb5ac618537ebe 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -1478,10 +1478,11 @@ const LineNumberProgram = struct { } }; +// TODO the noasyncs here are workarounds fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { var buf = ArrayList(u8).init(allocator); while (true) { - const byte = try in_stream.readByte(); + const byte = try noasync in_stream.readByte(); if (byte == 0) break; try buf.append(byte); } @@ -1494,10 +1495,11 @@ fn getString(di: *DwarfInfo, offset: u64) ![]u8 { return di.readString(); } +// TODO the noasyncs here are workarounds fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 { const buf = try allocator.alloc(u8, size); errdefer allocator.free(buf); - if ((try in_stream.read(buf)) < size) return error.EndOfFile; + if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile; return buf; } @@ -1506,8 +1508,9 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize return FormValue{ .Block = buf }; } +// TODO the noasyncs here are workarounds fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { - const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size); + const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size); return parseFormValueBlockLen(allocator, in_stream, block_len); } @@ -1537,27 +1540,37 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo }; } +// TODO the noasyncs here are workarounds fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { - return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32)); + return if (is_64) try noasync in_stream.readIntLittle(u64) else u64(try noasync in_stream.readIntLittle(u32)); } +// TODO the noasyncs here are workarounds fn parseFormValueTargetAddrSize(in_stream: var) !u64 { - return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable; + if (@sizeOf(usize) == 4) { + return u64(try noasync in_stream.readIntLittle(u32)); + } else if (@sizeOf(usize) == 8) { + return noasync in_stream.readIntLittle(u64); + } else { + unreachable; + } } +// TODO the noasyncs here are workarounds fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue { return FormValue{ .Ref = switch (size) { - 1 => try in_stream.readIntLittle(u8), - 2 => try in_stream.readIntLittle(u16), - 4 => try in_stream.readIntLittle(u32), - 8 => try in_stream.readIntLittle(u64), - -1 => try leb.readULEB128(u64, in_stream), + 1 => try noasync in_stream.readIntLittle(u8), + 2 => try noasync in_stream.readIntLittle(u16), + 4 => try noasync in_stream.readIntLittle(u32), + 8 => try noasync in_stream.readIntLittle(u64), + -1 => try noasync leb.readULEB128(u64, in_stream), else => unreachable, }, }; } +// TODO the noasyncs here are workarounds fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue { return switch (form_id) { DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) }, @@ -1565,7 +1578,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), DW.FORM_block => x: { - const block_len = try leb.readULEB128(usize, in_stream); + const block_len = try noasync leb.readULEB128(usize, in_stream); return parseFormValueBlockLen(allocator, in_stream, block_len); }, DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1), @@ -1577,11 +1590,11 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 return parseFormValueConstant(allocator, in_stream, signed, -1); }, DW.FORM_exprloc => { - const size = try leb.readULEB128(usize, in_stream); + const size = try noasync leb.readULEB128(usize, in_stream); const buf = try readAllocBytes(allocator, in_stream, size); return FormValue{ .ExprLoc = buf }; }, - DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 }, + DW.FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 }, DW.FORM_flag_present => FormValue{ .Flag = true }, DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, @@ -1592,12 +1605,12 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1), DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref_sig8 => FormValue{ .Ref = try in_stream.readIntLittle(u64) }, + DW.FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) }, DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) }, DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, DW.FORM_indirect => { - const child_form_id = try leb.readULEB128(u64, in_stream); + const child_form_id = try noasync leb.readULEB128(u64, in_stream); const F = @typeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64)); var frame = try allocator.create(F); defer allocator.destroy(frame); @@ -2400,3 +2413,9 @@ stdcallcc fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) c_long { else => return windows.EXCEPTION_CONTINUE_SEARCH, } } + +pub fn dumpStackPointerAddr(prefix: []const u8) void { + const sp = asm ("" : [argc] "={rsp}" (-> usize)); + std.debug.warn("{} sp = 0x{x}\n", prefix, sp); +} + diff --git a/std/io/in_stream.zig b/std/io/in_stream.zig index c617f10500485d104388b10ec1b8490d9abec458..44c74fcca49dd1983a42b725b7cb8a5c2ba99654 100644 --- a/std/io/in_stream.zig +++ b/std/io/in_stream.zig @@ -6,7 +6,7 @@ const assert = std.debug.assert; const mem = std.mem; const Buffer = std.Buffer; -pub const default_stack_size = 4 * 1024 * 1024; +pub const default_stack_size = 1 * 1024 * 1024; pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_InStream")) root.stack_size_std_io_InStream else diff --git a/std/os/linux/tls.zig b/std/os/linux/tls.zig index 62df8709447004b4c2a6c2052938d951049ae498..8afc751401082fcaea058597c0857ba73b440030 100644 --- a/std/os/linux/tls.zig +++ b/std/os/linux/tls.zig @@ -125,7 +125,7 @@ pub fn setThreadPointer(addr: usize) void { } } -pub fn initTLS() void { +pub fn initTLS() ?*elf.Phdr { var tls_phdr: ?*elf.Phdr = null; var img_base: usize = 0; @@ -152,10 +152,13 @@ pub fn initTLS() void { // Search the TLS section const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum]; + var gnu_stack: ?*elf.Phdr = null; + for (phdrs) |*phdr| { switch (phdr.p_type) { elf.PT_PHDR => img_base = at_phdr - phdr.p_vaddr, elf.PT_TLS => tls_phdr = phdr, + elf.PT_GNU_STACK => gnu_stack = phdr, else => continue, } } @@ -217,6 +220,8 @@ pub fn initTLS() void { .data_offset = data_offset, }; } + + return gnu_stack; } pub fn copyTLS(addr: usize) usize { diff --git a/std/special/start.zig b/std/special/start.zig index fde79a4bafb0c8c9587e19f8fe053a7a275f0478..31639821b4568a0fcc7cba600a23ffdd1b0394d5 100644 --- a/std/special/start.zig +++ b/std/special/start.zig @@ -5,7 +5,7 @@ const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; -var argc_ptr: [*]usize = undefined; +var starting_stack_ptr: [*]usize = undefined; const is_wasm = switch (builtin.arch) { .wasm32, .wasm64 => true, @@ -35,17 +35,17 @@ nakedcc fn _start() noreturn { switch (builtin.arch) { .x86_64 => { - argc_ptr = asm ("" + starting_stack_ptr = asm ("" : [argc] "={rsp}" (-> [*]usize) ); }, .i386 => { - argc_ptr = asm ("" + starting_stack_ptr = asm ("" : [argc] "={esp}" (-> [*]usize) ); }, .aarch64, .aarch64_be, .arm => { - argc_ptr = asm ("mov %[argc], sp" + starting_stack_ptr = asm ("mov %[argc], sp" : [argc] "=r" (-> [*]usize) ); }, @@ -72,8 +72,8 @@ fn posixCallMainAndExit() noreturn { if (builtin.os == builtin.Os.freebsd) { @setAlignStack(16); } - const argc = argc_ptr[0]; - const argv = @ptrCast([*][*]u8, argc_ptr + 1); + const argc = starting_stack_ptr[0]; + const argv = @ptrCast([*][*]u8, starting_stack_ptr + 1); const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1); var envp_count: usize = 0; @@ -85,21 +85,40 @@ fn posixCallMainAndExit() noreturn { const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); std.os.linux.elf_aux_maybe = auxv; // Initialize the TLS area - std.os.linux.tls.initTLS(); + const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size"); if (std.os.linux.tls.tls_image) |tls_img| { const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); const tp = std.os.linux.tls.copyTLS(tls_addr); std.os.linux.tls.setThreadPointer(tp); } + + // TODO This is disabled because what should we do when linking libc and this code + // does not execute? And also it's causing a test failure in stack traces in release modes. + + //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further + //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down + //// the stack and requires "probing". So here we allocate our own stack. + //const wanted_stack_size = gnu_stack_phdr.p_memsz; + //assert(wanted_stack_size % std.mem.page_size == 0); + //// Allocate an extra page as the guard page. + //const total_size = wanted_stack_size + std.mem.page_size; + //const new_stack = std.os.mmap( + // null, + // total_size, + // std.os.PROT_READ | std.os.PROT_WRITE, + // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS, + // -1, + // 0, + //) catch @panic("out of memory"); + //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; + //std.os.exit(@newStackCall(new_stack, callMainWithArgs, argc, argv, envp)); } - std.os.exit(callMainWithArgs(argc, argv, envp)); + std.os.exit(@inlineCall(callMainWithArgs, argc, argv, envp)); } -// This is marked inline because for some reason LLVM in release mode fails to inline it, -// and we want fewer call frames in stack traces. -inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { +fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { std.os.argv = argv[0..argc]; std.os.environ = envp; @@ -112,7 +131,7 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { var env_count: usize = 0; while (c_envp[env_count] != null) : (env_count += 1) {} const envp = @ptrCast([*][*]u8, c_envp)[0..env_count]; - return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); + return @inlineCall(callMainWithArgs, @intCast(usize, c_argc), c_argv, envp); } // General error message for a malformed return type diff --git a/std/thread.zig b/std/thread.zig index abf2f1cae1304b6e98466c519201ed4a997ae4c2..278fcc827c0c3416d3eced392548fb4dd646baee 100644 --- a/std/thread.zig +++ b/std/thread.zig @@ -145,7 +145,7 @@ pub const Thread = struct { if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode"); // TODO compile-time call graph analysis to determine stack upper bound // https://github.com/ziglang/zig/issues/157 - const default_stack_size = 8 * 1024 * 1024; + const default_stack_size = 16 * 1024 * 1024; const Context = @typeOf(context); comptime assert(@ArgType(@typeOf(startFn), 0) == Context); -- 2.54.0 From 774f770056887c27418bd715136fe1fdc8806d7d Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 12 Sep 2019 12:42:59 +0200 Subject: [PATCH 19/23] Correct AT_FDCWD definition --- std/os/bits/linux.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/os/bits/linux.zig b/std/os/bits/linux.zig index 0617378da9f50d1a1751a5b3de3b8c247b3666e2..cd8a3cbca13ea0463c308cbc653041f45ae5c3dd 100644 --- a/std/os/bits/linux.zig +++ b/std/os/bits/linux.zig @@ -24,7 +24,7 @@ pub const STDOUT_FILENO = 1; pub const STDERR_FILENO = 2; /// Special value used to indicate openat should use the current working directory -pub const AT_FDCWD = 100; +pub const AT_FDCWD = -100; /// Do not follow symbolic links pub const AT_SYMLINK_NOFOLLOW = 0x100; -- 2.54.0 From 742abc71c75a3448526c14980d0daae1c6ff8f96 Mon Sep 17 00:00:00 2001 From: stratact Date: Wed, 11 Sep 2019 19:20:28 -0700 Subject: [PATCH 20/23] Add missing C dl_iterate_phdr function for FreeBSD --- std/c/freebsd.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 71dd4705f87e5b066d5c90285bbca58c68dfdf76..550b5a59b1d82aab5bbdbb4142ed423d7dd23f37 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -7,3 +7,6 @@ pub const _errno = __error; pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize; + +pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int; +pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; -- 2.54.0 From eb7d36ae0d240b8ef5421703e613d164cf691d8d Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 13 Sep 2019 12:12:12 +0200 Subject: [PATCH 21/23] Make single-element enum default to u0 * Allow comptime_int as explicit enum tag type Closes #2997 --- src/analyze.cpp | 9 +++------ test/stage1/behavior/enum.zig | 16 ++++++++++++++++ test/stage1/behavior/union.zig | 22 +++++++++++++++++++--- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 946bbd17ae8804beec9afab8c4f1d8dc9757254f..58ec0cf133ed15934a9c8250bc5b1b587db7db49 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2406,8 +2406,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { ZigType *tag_int_type; if (enum_type->data.enumeration.layout == ContainerLayoutExtern) { tag_int_type = get_c_int_type(g, CIntTypeInt); - } else if (enum_type->data.enumeration.layout == ContainerLayoutAuto && field_count == 1) { - tag_int_type = g->builtin_types.entry_num_lit_int; } else { tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); } @@ -2420,7 +2418,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); if (type_is_invalid(wanted_tag_int_type)) { enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } else if (wanted_tag_int_type->id != ZigTypeIdInt) { + } else if (wanted_tag_int_type->id != ZigTypeIdInt && + wanted_tag_int_type->id != ZigTypeIdComptimeInt) { enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; add_node_error(g, decl_node->data.container_decl.init_arg_expr, buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); @@ -2806,14 +2805,12 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - if (tag_int_type->id != ZigTypeIdInt) { + if (tag_int_type->id != ZigTypeIdInt && tag_int_type->id != ZigTypeIdComptimeInt) { add_node_error(g, enum_type_node, buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name))); union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - } else if (auto_layout && field_count == 1) { - tag_int_type = g->builtin_types.entry_num_lit_int; } else { tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); } diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 3f6b2b7bd3a5f45e12edef7c3b318a333d81a729..6084dad3cb92bb5d68e79da757e61273e392a55c 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1014,3 +1014,19 @@ test "enum with one member and u1 tag type @enumToInt" { }; expect(@enumToInt(Enum.Test) == 0); } + +test "enum with comptime_int tag type" { + const Enum = enum(comptime_int) { + One = 3, + Two = 2, + Three = 1, + }; + comptime expect(@TagType(Enum) == comptime_int); +} + +test "enum with one member default to u0 tag type" { + const E0 = enum { + X, + }; + comptime expect(@TagType(E0) == u0); +} diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 21308b0ea25f9e489627c28952cb34da953e77e2..75b01164f83f91fb75bf7b4bc89a11e15eb89ce4 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -324,7 +324,7 @@ test "union with only 1 field casted to its enum type" { var e = Expr{ .Literal = Literal{ .Bool = true } }; const Tag = @TagType(Expr); - comptime expect(@TagType(Tag) == comptime_int); + comptime expect(@TagType(Tag) == u0); var t = Tag(e); expect(t == Expr.Literal); } @@ -335,7 +335,7 @@ test "union with only 1 field casted to its enum type which has enum value speci Bool: bool, }; - const Tag = enum { + const Tag = enum(comptime_int) { Literal = 33, }; @@ -469,7 +469,7 @@ test "union no tag with struct member" { } fn testComparison() void { - var x = Payload{.A = 42}; + var x = Payload{ .A = 42 }; expect(x == .A); expect(x != .B); expect(x != .C); @@ -494,3 +494,19 @@ test "packed union generates correctly aligned LLVM type" { }; foo[0].f1(); } + +test "union with one member defaults to u0 tag type" { + const U0 = union(enum) { + X: u32, + }; + comptime expect(@TagType(@TagType(U0)) == u0); +} + +test "union with comptime_int tag" { + const Union = union(enum(comptime_int)) { + X: u32, + Y: u16, + Z: u8, + }; + comptime expect(@TagType(@TagType(Union)) == comptime_int); +} -- 2.54.0 From 2b698888ce6cd78e74258990b7519c9689c9d345 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 13 Sep 2019 14:41:59 -0400 Subject: [PATCH 22/23] fix regression from incorrect conflict resolution in prev commit thanks for catching this LemonBoy --- src/codegen.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index b720b84ec6d07e5925adfec4a43abcc57fd953da..62aaabb274e71dcb26e281fdee1b3a732f0fd010 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -516,9 +516,9 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { } } if (g->have_stack_probing && !fn->def_scope->safety_off) { - addLLVMFnAttrStr(fn->llvm_value, "probe-stack", "__zig_probe_stack"); + addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack"); } else { - addLLVMFnAttrStr(fn->llvm_value, "no-stack-arg-probe", ""); + addLLVMFnAttrStr(llvm_fn, "no-stack-arg-probe", ""); } } else { maybe_import_dll(g, llvm_fn, linkage); -- 2.54.0 From 8223aca09bc93279a88d1439d6dfc437144ec578 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 13 Sep 2019 14:46:22 -0400 Subject: [PATCH 23/23] no-stack-arg-probe only for UEFI --- src/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 62aaabb274e71dcb26e281fdee1b3a732f0fd010..4799c0a28f2ae8b8bc400fa322f5b887a86909db 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -517,7 +517,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { } if (g->have_stack_probing && !fn->def_scope->safety_off) { addLLVMFnAttrStr(llvm_fn, "probe-stack", "__zig_probe_stack"); - } else { + } else if (g->zig_target->os == OsUefi) { addLLVMFnAttrStr(llvm_fn, "no-stack-arg-probe", ""); } } else { -- 2.54.0