aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/std/os/uefi.zig7
-rw-r--r--lib/std/os/uefi/pool_allocator.zig153
2 files changed, 160 insertions, 0 deletions
diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig
index b4582c121d..30f7f8a41b 100644
--- a/lib/std/os/uefi.zig
+++ b/lib/std/os/uefi.zig
@@ -7,6 +7,13 @@ pub const protocols = @import("uefi/protocols.zig");
pub const Status = @import("uefi/status.zig").Status;
pub const tables = @import("uefi/tables.zig");
+/// The memory type to allocate when using the pool
+/// Defaults to .LoaderData, the default data allocation type
+/// used by UEFI applications to allocate pool memory.
+pub var efi_pool_memory_type: tables.MemoryType = .LoaderData;
+pub const pool_allocator = @import("uefi/pool_allocator.zig").pool_allocator;
+pub const raw_pool_allocator = @import("uefi/pool_allocator.zig").raw_pool_allocator;
+
/// The EFI image's handle that is passed to its entry point.
pub var handle: Handle = undefined;
diff --git a/lib/std/os/uefi/pool_allocator.zig b/lib/std/os/uefi/pool_allocator.zig
new file mode 100644
index 0000000000..3294621a18
--- /dev/null
+++ b/lib/std/os/uefi/pool_allocator.zig
@@ -0,0 +1,153 @@
+const std = @import("std");
+
+const mem = std.mem;
+const uefi = std.os.uefi;
+
+const assert = std.debug.assert;
+
+const Allocator = mem.Allocator;
+
+const UefiPoolAllocator = struct {
+ fn getHeader(ptr: [*]u8) *[*]align(8) u8 {
+ return @intToPtr(*[*]align(8) u8, @ptrToInt(ptr) - @sizeOf(usize));
+ }
+
+ fn alignedAlloc(len: usize, alignment: usize) ?[*]u8 {
+ var unaligned_ptr: [*]align(8) u8 = undefined;
+
+ if (uefi.system_table.boot_services.?.allocatePool(uefi.efi_pool_memory_type, len, &unaligned_ptr) != .Success)
+ return null;
+
+ const unaligned_addr = @ptrToInt(unaligned_ptr);
+ const aligned_addr = mem.alignForward(unaligned_addr + @sizeOf(usize), alignment);
+
+ var aligned_ptr = unaligned_ptr + (aligned_addr - unaligned_addr);
+ getHeader(aligned_ptr).* = unaligned_ptr;
+
+ return aligned_ptr;
+ }
+
+ fn alignedFree(ptr: [*]u8) void {
+ _ = uefi.system_table.boot_services.?.freePool(getHeader(ptr).*);
+ }
+
+ fn alloc(
+ _: *anyopaque,
+ len: usize,
+ ptr_align: u29,
+ len_align: u29,
+ ret_addr: usize,
+ ) Allocator.Error![]u8 {
+ _ = ret_addr;
+
+ assert(len > 0);
+ assert(std.math.isPowerOfTwo(ptr_align));
+
+ var ptr = alignedAlloc(len, ptr_align) orelse return error.OutOfMemory;
+
+ if (len_align == 0)
+ return ptr[0..len];
+
+ return ptr[0..mem.alignBackwardAnyAlign(len, len_align)];
+ }
+
+ fn resize(
+ _: *anyopaque,
+ buf: []u8,
+ buf_align: u29,
+ new_len: usize,
+ len_align: u29,
+ ret_addr: usize,
+ ) ?usize {
+ _ = buf_align;
+ _ = ret_addr;
+
+ return if (new_len <= buf.len) mem.alignAllocLen(buf.len, new_len, len_align) else null;
+ }
+
+ fn free(
+ _: *anyopaque,
+ buf: []u8,
+ buf_align: u29,
+ ret_addr: usize,
+ ) void {
+ _ = buf_align;
+ _ = ret_addr;
+ alignedFree(buf.ptr);
+ }
+};
+
+/// Supports the full Allocator interface, including alignment.
+/// For a direct call of `allocatePool`, see `raw_pool_allocator`.
+pub const pool_allocator = Allocator{
+ .ptr = undefined,
+ .vtable = &pool_allocator_vtable,
+};
+
+const pool_allocator_vtable = Allocator.VTable{
+ .alloc = UefiPoolAllocator.alloc,
+ .resize = UefiPoolAllocator.resize,
+ .free = UefiPoolAllocator.free,
+};
+
+/// Asserts allocations are 8 byte aligned and calls `boot_services.allocatePool`.
+pub const raw_pool_allocator = Allocator{
+ .ptr = undefined,
+ .vtable = &raw_pool_allocator_table,
+};
+
+const raw_pool_allocator_table = Allocator.VTable{
+ .alloc = uefi_alloc,
+ .resize = uefi_resize,
+ .free = uefi_free,
+};
+
+fn uefi_alloc(
+ _: *anyopaque,
+ len: usize,
+ ptr_align: u29,
+ len_align: u29,
+ ret_addr: usize,
+) Allocator.Error![]u8 {
+ _ = len_align;
+ _ = ret_addr;
+
+ std.debug.assert(ptr_align <= 8);
+
+ var ptr: [*]align(8) u8 = undefined;
+
+ if (uefi.system_table.boot_services.?.allocatePool(uefi.efi_pool_memory_type, len, &ptr) != .Success) {
+ return error.OutOfMemory;
+ }
+
+ return ptr[0..len];
+}
+
+fn uefi_resize(
+ _: *anyopaque,
+ buf: []u8,
+ old_align: u29,
+ new_len: usize,
+ len_align: u29,
+ ret_addr: usize,
+) ?usize {
+ _ = old_align;
+ _ = ret_addr;
+
+ if (new_len <= buf.len) {
+ return mem.alignAllocLen(buf.len, new_len, len_align);
+ }
+
+ return null;
+}
+
+fn uefi_free(
+ _: *anyopaque,
+ buf: []u8,
+ buf_align: u29,
+ ret_addr: usize,
+) void {
+ _ = buf_align;
+ _ = ret_addr;
+ _ = uefi.system_table.boot_services.?.freePool(@alignCast(8, buf.ptr));
+}