master
  1const std = @import("std");
  2
  3const mem = std.mem;
  4const uefi = std.os.uefi;
  5
  6const assert = std.debug.assert;
  7
  8const Allocator = mem.Allocator;
  9
 10const UefiPoolAllocator = struct {
 11    fn getHeader(ptr: [*]u8) *[*]align(8) u8 {
 12        return @as(*[*]align(8) u8, @ptrFromInt(@intFromPtr(ptr) - @sizeOf(usize)));
 13    }
 14
 15    fn alloc(
 16        _: *anyopaque,
 17        len: usize,
 18        alignment: mem.Alignment,
 19        ret_addr: usize,
 20    ) ?[*]u8 {
 21        _ = ret_addr;
 22
 23        assert(len > 0);
 24
 25        const ptr_align = alignment.toByteUnits();
 26
 27        const metadata_len = mem.alignForward(usize, @sizeOf(usize), ptr_align);
 28
 29        const full_len = metadata_len + len;
 30
 31        const unaligned_slice = uefi.system_table.boot_services.?.allocatePool(
 32            uefi.efi_pool_memory_type,
 33            full_len,
 34        ) catch return null;
 35
 36        const unaligned_addr = @intFromPtr(unaligned_slice.ptr);
 37        const aligned_addr = mem.alignForward(usize, unaligned_addr + @sizeOf(usize), ptr_align);
 38
 39        const aligned_ptr = unaligned_slice.ptr + (aligned_addr - unaligned_addr);
 40        getHeader(aligned_ptr).* = unaligned_slice.ptr;
 41
 42        return aligned_ptr;
 43    }
 44
 45    fn resize(
 46        _: *anyopaque,
 47        buf: []u8,
 48        alignment: mem.Alignment,
 49        new_len: usize,
 50        ret_addr: usize,
 51    ) bool {
 52        _ = ret_addr;
 53        _ = alignment;
 54
 55        if (new_len > buf.len) return false;
 56        return true;
 57    }
 58
 59    fn remap(
 60        _: *anyopaque,
 61        buf: []u8,
 62        alignment: mem.Alignment,
 63        new_len: usize,
 64        ret_addr: usize,
 65    ) ?[*]u8 {
 66        _ = alignment;
 67        _ = ret_addr;
 68
 69        if (new_len > buf.len) return null;
 70        return buf.ptr;
 71    }
 72
 73    fn free(
 74        _: *anyopaque,
 75        buf: []u8,
 76        alignment: mem.Alignment,
 77        ret_addr: usize,
 78    ) void {
 79        _ = alignment;
 80        _ = ret_addr;
 81        uefi.system_table.boot_services.?.freePool(getHeader(buf.ptr).*) catch unreachable;
 82    }
 83};
 84
 85/// Supports the full Allocator interface, including alignment.
 86/// For a direct call of `allocatePool`, see `raw_pool_allocator`.
 87pub const pool_allocator = Allocator{
 88    .ptr = undefined,
 89    .vtable = &pool_allocator_vtable,
 90};
 91
 92const pool_allocator_vtable = Allocator.VTable{
 93    .alloc = UefiPoolAllocator.alloc,
 94    .resize = UefiPoolAllocator.resize,
 95    .remap = UefiPoolAllocator.remap,
 96    .free = UefiPoolAllocator.free,
 97};
 98
 99/// Asserts allocations are 8 byte aligned and calls `boot_services.allocatePool`.
100pub const raw_pool_allocator = Allocator{
101    .ptr = undefined,
102    .vtable = &raw_pool_allocator_table,
103};
104
105const raw_pool_allocator_table = Allocator.VTable{
106    .alloc = uefi_alloc,
107    .resize = uefi_resize,
108    .remap = uefi_remap,
109    .free = uefi_free,
110};
111
112fn uefi_alloc(
113    _: *anyopaque,
114    len: usize,
115    alignment: mem.Alignment,
116    ret_addr: usize,
117) ?[*]u8 {
118    _ = ret_addr;
119
120    std.debug.assert(@intFromEnum(alignment) <= 3);
121
122    const slice = uefi.system_table.boot_services.?.allocatePool(
123        uefi.efi_pool_memory_type,
124        len,
125    ) catch return null;
126
127    return slice.ptr;
128}
129
130fn uefi_resize(
131    _: *anyopaque,
132    buf: []u8,
133    alignment: mem.Alignment,
134    new_len: usize,
135    ret_addr: usize,
136) bool {
137    _ = ret_addr;
138
139    std.debug.assert(@intFromEnum(alignment) <= 3);
140
141    if (new_len > buf.len) return false;
142    return true;
143}
144
145fn uefi_remap(
146    _: *anyopaque,
147    buf: []u8,
148    alignment: mem.Alignment,
149    new_len: usize,
150    ret_addr: usize,
151) ?[*]u8 {
152    _ = ret_addr;
153
154    std.debug.assert(@intFromEnum(alignment) <= 3);
155
156    if (new_len > buf.len) return null;
157    return buf.ptr;
158}
159
160fn uefi_free(
161    _: *anyopaque,
162    buf: []u8,
163    alignment: mem.Alignment,
164    ret_addr: usize,
165) void {
166    _ = alignment;
167    _ = ret_addr;
168    uefi.system_table.boot_services.?.freePool(@alignCast(buf.ptr)) catch unreachable;
169}