From 9cd37653342e8025a7588069b40b9b1adbf76112 Mon Sep 17 00:00:00 2001 From: Samuel Tebbs Date: Sat, 23 Apr 2022 19:46:09 +0100 Subject: [PATCH] Combine ComptimeBitmap and Bitmap --- src/kernel/bitmap.zig | 456 +++++++++++++++------------------------ src/kernel/pmm.zig | 43 ++-- src/kernel/scheduler.zig | 9 +- src/kernel/task.zig | 92 +++++--- src/kernel/vmm.zig | 34 +-- 5 files changed, 281 insertions(+), 353 deletions(-) diff --git a/src/kernel/bitmap.zig b/src/kernel/bitmap.zig index 571bec4..cee6fdb 100644 --- a/src/kernel/bitmap.zig +++ b/src/kernel/bitmap.zig @@ -1,206 +1,33 @@ const std = @import("std"); const builtin = std.builtin; const testing = std.testing; +const expectEqual = testing.expectEqual; const Allocator = std.mem.Allocator; -/// -/// A comptime bitmap that uses a specific type to store the entries. No allocators needed. -/// -/// Arguments: -/// IN BitmapType: type - The integer type to use to store entries. -/// -/// Return: type. -/// The bitmap type created. -/// -pub fn ComptimeBitmap(comptime BitmapType: type) type { - return struct { - const Self = @This(); - - /// The number of entries that one bitmap type can hold. Evaluates to the number of bits the type has - pub const NUM_ENTRIES: usize = std.meta.bitCount(BitmapType); - - /// The value that a full bitmap will have - pub const BITMAP_FULL = std.math.maxInt(BitmapType); - - /// The type of an index into a bitmap entry. The smallest integer needed to represent all bit positions in the bitmap entry type - pub const IndexType = std.meta.Int(.unsigned, std.math.log2(std.math.ceilPowerOfTwo(u16, std.meta.bitCount(BitmapType)) catch unreachable)); - - bitmap: BitmapType, - num_free_entries: BitmapType, - - /// - /// Create an instance of this bitmap type. - /// - /// Return: Self. - /// The bitmap instance. - /// - pub fn init() Self { - return .{ - .bitmap = 0, - .num_free_entries = NUM_ENTRIES, - }; - } - - /// - /// Set an entry within a bitmap as occupied. - /// - /// Arguments: - /// IN/OUT self: *Self - The bitmap to modify. - /// IN idx: IndexType - The index within the bitmap to set. - /// - pub fn setEntry(self: *Self, idx: IndexType) void { - if (!self.isSet(idx)) { - self.bitmap |= indexToBit(idx); - self.num_free_entries -= 1; - } - } - - /// - /// Set an entry within a bitmap as unoccupied. - /// - /// Arguments: - /// IN/OUT self: *Self - The bitmap to modify. - /// IN idx: IndexType - The index within the bitmap to clear. - /// - pub fn clearEntry(self: *Self, idx: IndexType) void { - if (self.isSet(idx)) { - self.bitmap &= ~indexToBit(idx); - self.num_free_entries += 1; - } - } - - /// - /// Convert a global bitmap index into the bit corresponding to an entry within a single BitmapType. - /// - /// Arguments: - /// IN self: *const Self - The bitmap to use. - /// IN idx: IndexType - The index into all of the bitmaps entries. - /// - /// Return: BitmapType. - /// The bit corresponding to that index but within a single BitmapType. - /// - fn indexToBit(idx: IndexType) BitmapType { - return @as(BitmapType, 1) << idx; - } - - /// - /// Find a number of contiguous free entries and set them. - /// - /// Arguments: - /// IN/OUT self: *Self - The bitmap to modify. - /// IN num: usize - The number of entries to set. - /// IN from: ?IndexType - The entry number to start allocate from or null if it can start anywhere - /// - /// Return: ?IndexType - /// The first entry set or null if there weren't enough contiguous entries. - /// If `from` was not null and any entry between `from` and `from` + num is set then null is returned. - /// - pub fn setContiguous(self: *Self, num: usize, from: ?IndexType) ?IndexType { - if (num > self.num_free_entries) { - return null; - } - - var count: usize = 0; - var start: ?IndexType = null; - - var bit = from orelse 0; - while (true) { - const entry = bit; - if (entry >= NUM_ENTRIES) { - return null; - } - if ((self.bitmap & @as(BitmapType, 1) << bit) != 0) { - // This is a one so clear the progress - count = 0; - start = null; - // If the caller requested the allocation to start from - // a specific entry and it failed then return null - if (from) |_| { - return null; - } - } else { - // It's a zero so increment the count - count += 1; - if (start == null) { - // Start of the contiguous zeroes - start = entry; - } - if (count == num) { - // Reached the desired number - break; - } - } - // Avoiding overflow by checking if bit is less than the max - 1 - if (bit < NUM_ENTRIES - 1) { - bit += 1; - } else { - break; - } - } - - if (count == num) { - if (start) |start_entry| { - var i: IndexType = 0; - while (i < num) : (i += 1) { - self.setEntry(start_entry + i); - } - return start_entry; - } - } - return null; - } - - /// - /// Set the first free entry within the bitmaps as occupied. - /// - /// Return: ?IndexType. - /// The index within all bitmaps that was set or null if there wasn't one free. - /// 0 .. NUM_ENTRIES - 1 if in the first bitmap, NUM_ENTRIES .. NUM_ENTRIES * 2 - 1 if in the second etc. - /// - pub fn setFirstFree(self: *Self) ?IndexType { - if (self.num_free_entries == 0 or self.bitmap == BITMAP_FULL) { - std.debug.assert(self.num_free_entries == 0 and self.bitmap == BITMAP_FULL); - return null; - } - const bit = @truncate(IndexType, @ctz(BitmapType, ~self.bitmap)); - self.setEntry(bit); - return bit; - } - - /// - /// Check if an entry is set. - /// - /// Arguments: - /// IN self: *const Self - The bitmap to check. - /// IN idx: usize - The entry to check. - /// - /// Return: bool. - /// True if the entry is set, else false. - /// - pub fn isSet(self: *const Self, idx: IndexType) bool { - return (self.bitmap & indexToBit(idx)) != 0; - } - }; -} +/// The possible errors thrown by bitmap functions +pub const BitmapError = error{ + /// The address given was outside the region covered by a bitmap + OutOfBounds, +}; /// /// A bitmap that uses a specific type to store the entries. +/// The bitmap can either be statically or dynamically allocated. +/// Statically allocated bitmaps are allocated at compile time and therefore must know the number of entries at compile time. +/// Dynamically allocated bitmaps do not need to know the number of entries until being initialised, but do need an allocator. /// /// Arguments: +/// IN static: comptime bool - Whether this bitmap is statically or dynamically allocated /// IN BitmapType: type - The integer type to use to store entries. +/// IN num_entries: usize or ?usize - The number of entries if static, else ignored (can be null) /// /// Return: type. /// The bitmap type created. /// -pub fn Bitmap(comptime BitmapType: type) type { +pub fn Bitmap(comptime num_entries: ?usize, comptime BitmapType: type) type { return struct { - /// The possible errors thrown by bitmap functions - pub const BitmapError = error{ - /// The address given was outside the region covered by a bitmap - OutOfBounds, - }; - const Self = @This(); + const static = num_entries != null; /// The number of entries that one bitmap type can hold. Evaluates to the number of bits the type has pub const ENTRIES_PER_BITMAP: usize = std.meta.bitCount(BitmapType); @@ -213,37 +40,48 @@ pub fn Bitmap(comptime BitmapType: type) type { num_bitmaps: usize, num_entries: usize, - bitmaps: []BitmapType, + bitmaps: if (static) [std.mem.alignForward(num_entries.?, ENTRIES_PER_BITMAP) / ENTRIES_PER_BITMAP]BitmapType else []BitmapType, num_free_entries: usize, - allocator: Allocator, + allocator: if (static) ?Allocator else Allocator, /// /// Create an instance of this bitmap type. /// /// Arguments: - /// IN num_entries: usize - The number of entries that the bitmap created will have. - /// The number of BitmapType required to store this many entries will be allocated and each will be zeroed. - /// IN allocator: Allocator - The allocator to use when allocating the BitmapTypes required. + /// IN num: ?usize or usize - The number of entries that the bitmap created will have if dynamically allocated, else ignored (can be null) + /// The number of BitmapType required to store this many entries will be allocated (dynamically or statically) and each will be zeroed. + /// IN allocator: ?Allocator or Allocator - The allocator to use when allocating the BitmapTypes required. Ignored if statically allocated. /// /// Return: Self. /// The bitmap instance. /// /// Error: Allocator.Error - /// OutOfMemory: There isn't enough memory available to allocate the required number of BitmapType. + /// OutOfMemory: There isn't enough memory available to allocate the required number of BitmapType. A statically allocated bitmap will not throw this error. /// - pub fn init(num_entries: usize, allocator: Allocator) !Self { - const num = std.mem.alignForward(num_entries, ENTRIES_PER_BITMAP) / ENTRIES_PER_BITMAP; - const self = Self{ - .num_bitmaps = num, - .num_entries = num_entries, - .bitmaps = try allocator.alloc(BitmapType, num), - .num_free_entries = num_entries, - .allocator = allocator, - }; - for (self.bitmaps) |*bmp| { - bmp.* = 0; + pub fn init(num: if (static) ?usize else usize, allocator: if (static) ?Allocator else Allocator) !Self { + if (static) { + const n = std.mem.alignForward(num_entries.?, ENTRIES_PER_BITMAP) / ENTRIES_PER_BITMAP; + return Self{ + .num_bitmaps = n, + .bitmaps = [_]BitmapType{0} ** (std.mem.alignForward(num_entries.?, ENTRIES_PER_BITMAP) / ENTRIES_PER_BITMAP), + .num_entries = num_entries.?, + .num_free_entries = num_entries.?, + .allocator = null, + }; + } else { + const n = std.mem.alignForward(num, ENTRIES_PER_BITMAP) / ENTRIES_PER_BITMAP; + const self = Self{ + .num_bitmaps = n, + .num_entries = num, + .bitmaps = try allocator.alloc(BitmapType, n), + .num_free_entries = num, + .allocator = allocator, + }; + for (self.bitmaps) |*bmp| { + bmp.* = 0; + } + return self; } - return self; } /// @@ -271,12 +109,13 @@ pub fn Bitmap(comptime BitmapType: type) type { /// /// Free the memory occupied by this bitmap's internal state. It will become unusable afterwards. + /// Does nothing if the bitmap was statically allocated. /// /// Arguments: /// IN self: *Self - The bitmap that should be deinitialised /// pub fn deinit(self: *Self) void { - self.allocator.free(self.bitmaps); + if (!static) self.allocator.free(self.bitmaps); } /// @@ -459,102 +298,117 @@ pub fn Bitmap(comptime BitmapType: type) type { }; } -test "Comptime setEntry" { - var bmp = ComptimeBitmap(u32).init(); +test "static setEntry" { + const BmpTy = Bitmap(32, u32); + var bmp = try BmpTy.init(null, null); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); try testing.expectEqual(@as(u32, 32), bmp.num_free_entries); - bmp.setEntry(0); - try testing.expectEqual(@as(u32, 1), bmp.bitmap); + try bmp.setEntry(0); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries); - bmp.setEntry(1); - try testing.expectEqual(@as(u32, 3), bmp.bitmap); + try bmp.setEntry(1); + try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries); // Repeat setting entry 1 to make sure state doesn't change - bmp.setEntry(1); - try testing.expectEqual(@as(u32, 3), bmp.bitmap); + try bmp.setEntry(1); + try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries); } -test "Comptime clearEntry" { - var bmp = ComptimeBitmap(u32).init(); +test "static clearEntry" { + const BmpTy = Bitmap(32, u32); + var bmp = try BmpTy.init(null, null); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); try testing.expectEqual(@as(u32, 32), bmp.num_free_entries); - bmp.setEntry(0); + try bmp.setEntry(0); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries); - bmp.setEntry(1); + try bmp.setEntry(1); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries); - try testing.expectEqual(@as(u32, 3), bmp.bitmap); - bmp.clearEntry(0); + try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]); + try bmp.clearEntry(0); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries); - try testing.expectEqual(@as(u32, 2), bmp.bitmap); + try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]); // Repeat to make sure state doesn't change - bmp.clearEntry(0); + try bmp.clearEntry(0); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries); - try testing.expectEqual(@as(u32, 2), bmp.bitmap); + try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]); // Try clearing an unset entry to make sure state doesn't change - bmp.clearEntry(2); + try bmp.clearEntry(2); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries); - try testing.expectEqual(@as(u32, 2), bmp.bitmap); + try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]); } -test "Comptime setFirstFree" { - var bmp = ComptimeBitmap(u32).init(); +test "static setFirstFree" { + const BmpTy = Bitmap(32, u32); + var bmp = try BmpTy.init(null, null); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); // Allocate the first entry try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); - try testing.expectEqual(bmp.bitmap, 1); + try testing.expectEqual(bmp.bitmaps[0], 1); // Allocate the second entry try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1); - try testing.expectEqual(bmp.bitmap, 3); + try testing.expectEqual(bmp.bitmaps[0], 3); // Make all but the MSB occupied and try to allocate it - bmp.bitmap = ComptimeBitmap(u32).BITMAP_FULL & ~@as(u32, 1 << (ComptimeBitmap(u32).NUM_ENTRIES - 1)); + for (bmp.bitmaps) |*b, i| { + b.* = BmpTy.BITMAP_FULL; + if (i <= bmp.num_bitmaps - 1) b.* &= ~(@as(usize, 1) << BmpTy.ENTRIES_PER_BITMAP - 1); + } bmp.num_free_entries = 1; - try testing.expectEqual(bmp.setFirstFree() orelse unreachable, ComptimeBitmap(u32).NUM_ENTRIES - 1); - try testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL); + try testing.expectEqual(bmp.setFirstFree() orelse unreachable, bmp.num_entries - 1); + for (bmp.bitmaps) |b| { + try testing.expectEqual(b, BmpTy.BITMAP_FULL); + } // We should no longer be able to allocate any entries try testing.expectEqual(bmp.setFirstFree(), null); - try testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL); + for (bmp.bitmaps) |b| { + try testing.expectEqual(b, BmpTy.BITMAP_FULL); + } } -test "Comptime isSet" { - var bmp = ComptimeBitmap(u32).init(); +test "static isSet" { + const BmpTy = Bitmap(32, u32); + var bmp = try BmpTy.init(null, null); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); - bmp.bitmap = 1; + bmp.bitmaps[0] = 1; // Make sure that only the set entry is considered set - try testing.expect(bmp.isSet(0)); + try testing.expect(try bmp.isSet(0)); var i: usize = 1; - while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) { - try testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i))); + while (i < bmp.num_entries) : (i += 1) { + try testing.expect(!(try bmp.isSet(@truncate(BmpTy.IndexType, i)))); } - bmp.bitmap = 3; - try testing.expect(bmp.isSet(0)); - try testing.expect(bmp.isSet(1)); + bmp.bitmaps[0] = 3; + try testing.expect(try bmp.isSet(0)); + try testing.expect(try bmp.isSet(1)); i = 2; - while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) { - try testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i))); + while (i < bmp.num_entries) : (i += 1) { + try testing.expect(!(try bmp.isSet(@truncate(BmpTy.IndexType, i)))); } - bmp.bitmap = 11; - try testing.expect(bmp.isSet(0)); - try testing.expect(bmp.isSet(1)); - try testing.expect(!bmp.isSet(2)); - try testing.expect(bmp.isSet(3)); + bmp.bitmaps[0] = 11; + try testing.expect(try bmp.isSet(0)); + try testing.expect(try bmp.isSet(1)); + try testing.expect(!(try bmp.isSet(2))); + try testing.expect(try bmp.isSet(3)); i = 4; - while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) { - try testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i))); + while (i < bmp.num_entries) : (i += 1) { + try testing.expect(!(try bmp.isSet(@truncate(BmpTy.IndexType, i)))); } } -test "Comptime indexToBit" { - const Type = ComptimeBitmap(u8); +test "static indexToBit" { + const Type = Bitmap(8, u8); try testing.expectEqual(Type.indexToBit(0), 1); try testing.expectEqual(Type.indexToBit(1), 2); try testing.expectEqual(Type.indexToBit(2), 4); @@ -565,45 +419,73 @@ test "Comptime indexToBit" { try testing.expectEqual(Type.indexToBit(7), 128); } -test "Comptime setContiguous" { - var bmp = ComptimeBitmap(u16).init(); +test "static setContiguous" { + var bmp = try Bitmap(16, u16).init(null, null); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); // Test trying to set more entries than the bitmap has try testing.expectEqual(bmp.setContiguous(bmp.num_free_entries + 1, null), null); try testing.expectEqual(bmp.setContiguous(bmp.num_free_entries + 1, 1), null); // All entries should still be free try testing.expectEqual(bmp.num_free_entries, 16); - try testing.expectEqual(bmp.bitmap, 0b0000000000000000); + for (bmp.bitmaps) |b| { + try expectEqual(b, 0); + } try testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0); - try testing.expectEqual(bmp.bitmap, 0b0000000000000111); + try expectEqual(bmp.bitmaps[0], 0b0000000000000111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } // Test setting from top try testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14); - try testing.expectEqual(bmp.bitmap, 0b1100000000000111); + try expectEqual(bmp.bitmaps[0], 0b1100000000000111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } try testing.expectEqual(bmp.setContiguous(3, 12), null); - try testing.expectEqual(bmp.bitmap, 0b1100000000000111); + try expectEqual(bmp.bitmaps[0], 0b1100000000000111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } try testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3); - try testing.expectEqual(bmp.bitmap, 0b1100000000111111); + try expectEqual(bmp.bitmaps[0], 0b1100000000111111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } // Test setting beyond the what is available try testing.expectEqual(bmp.setContiguous(9, null), null); - try testing.expectEqual(bmp.bitmap, 0b1100000000111111); + try expectEqual(bmp.bitmaps[0], 0b1100000000111111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } try testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6); - try testing.expectEqual(bmp.bitmap, 0b1111111111111111); + try expectEqual(bmp.bitmaps[0], 0b1111111111111111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } // No more are possible try testing.expectEqual(bmp.setContiguous(1, null), null); - try testing.expectEqual(bmp.bitmap, 0b1111111111111111); + try expectEqual(bmp.bitmaps[0], 0b1111111111111111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } try testing.expectEqual(bmp.setContiguous(1, 0), null); - try testing.expectEqual(bmp.bitmap, 0b1111111111111111); + try expectEqual(bmp.bitmaps[0], 0b1111111111111111); + for (bmp.bitmaps) |b, i| { + if (i > 0) try expectEqual(b, 0); + } } test "setEntry" { - var bmp = try Bitmap(u32).init(31, std.testing.allocator); + var bmp = try Bitmap(null, u32).init(31, std.testing.allocator); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); defer bmp.deinit(); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries); @@ -620,12 +502,13 @@ test "setEntry" { try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 29), bmp.num_free_entries); - try testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.setEntry(31)); + try testing.expectError(BitmapError.OutOfBounds, bmp.setEntry(31)); try testing.expectEqual(@as(u32, 29), bmp.num_free_entries); } test "clearEntry" { - var bmp = try Bitmap(u32).init(32, std.testing.allocator); + var bmp = try Bitmap(null, u32).init(32, std.testing.allocator); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); defer bmp.deinit(); try testing.expectEqual(@as(u32, 32), bmp.num_free_entries); @@ -648,11 +531,13 @@ test "clearEntry" { try testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]); - try testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.clearEntry(32)); + try testing.expectError(BitmapError.OutOfBounds, bmp.clearEntry(32)); } test "setFirstFree multiple bitmaps" { - var bmp = try Bitmap(u8).init(9, std.testing.allocator); + const BmpTy = Bitmap(null, u8); + var bmp = try BmpTy.init(9, std.testing.allocator); + try testing.expectEqual(@as(u32, 2), bmp.bitmaps.len); defer bmp.deinit(); // Allocate the first entry @@ -666,10 +551,10 @@ test "setFirstFree multiple bitmaps" { // Allocate the entirety of the first bitmap var entry: u32 = 2; var expected: u8 = 7; - while (entry < Bitmap(u8).ENTRIES_PER_BITMAP) { + while (entry < BmpTy.ENTRIES_PER_BITMAP) { try testing.expectEqual(bmp.setFirstFree() orelse unreachable, entry); try testing.expectEqual(bmp.bitmaps[0], expected); - if (entry + 1 < Bitmap(u8).ENTRIES_PER_BITMAP) { + if (entry + 1 < BmpTy.ENTRIES_PER_BITMAP) { entry += 1; expected = expected * 2 + 1; } else { @@ -678,18 +563,20 @@ test "setFirstFree multiple bitmaps" { } // Try allocating an entry in the next bitmap - try testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u8).ENTRIES_PER_BITMAP); - try testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL); + try testing.expectEqual(bmp.setFirstFree() orelse unreachable, BmpTy.ENTRIES_PER_BITMAP); + try testing.expectEqual(bmp.bitmaps[0], BmpTy.BITMAP_FULL); try testing.expectEqual(bmp.bitmaps[1], 1); // We should no longer be able to allocate any entries try testing.expectEqual(bmp.setFirstFree(), null); - try testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL); + try testing.expectEqual(bmp.bitmaps[0], BmpTy.BITMAP_FULL); try testing.expectEqual(bmp.bitmaps[1], 1); } test "setFirstFree" { - var bmp = try Bitmap(u32).init(32, std.testing.allocator); + const BmpTy = Bitmap(null, u32); + var bmp = try BmpTy.init(32, std.testing.allocator); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); defer bmp.deinit(); // Allocate the first entry @@ -701,17 +588,18 @@ test "setFirstFree" { try testing.expectEqual(bmp.bitmaps[0], 3); // Make all but the MSB occupied and try to allocate it - bmp.bitmaps[0] = Bitmap(u32).BITMAP_FULL & ~@as(u32, 1 << (Bitmap(u32).ENTRIES_PER_BITMAP - 1)); - try testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u32).ENTRIES_PER_BITMAP - 1); - try testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL); + bmp.bitmaps[0] = BmpTy.BITMAP_FULL & ~@as(u32, 1 << (BmpTy.ENTRIES_PER_BITMAP - 1)); + try testing.expectEqual(bmp.setFirstFree() orelse unreachable, BmpTy.ENTRIES_PER_BITMAP - 1); + try testing.expectEqual(bmp.bitmaps[0], BmpTy.BITMAP_FULL); // We should no longer be able to allocate any entries try testing.expectEqual(bmp.setFirstFree(), null); - try testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL); + try testing.expectEqual(bmp.bitmaps[0], BmpTy.BITMAP_FULL); } test "isSet" { - var bmp = try Bitmap(u32).init(32, std.testing.allocator); + var bmp = try Bitmap(null, u32).init(32, std.testing.allocator); + try testing.expectEqual(@as(u32, 1), bmp.bitmaps.len); defer bmp.deinit(); bmp.bitmaps[0] = 1; @@ -740,12 +628,13 @@ test "isSet" { try testing.expect(!try bmp.isSet(i)); } - try testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.isSet(33)); + try testing.expectError(BitmapError.OutOfBounds, bmp.isSet(33)); } test "indexToBit" { - const Type = Bitmap(u8); + const Type = Bitmap(null, u8); var bmp = try Type.init(10, std.testing.allocator); + try testing.expectEqual(@as(u32, 2), bmp.bitmaps.len); defer bmp.deinit(); try testing.expectEqual(Type.indexToBit(0), 1); try testing.expectEqual(Type.indexToBit(1), 2); @@ -759,7 +648,7 @@ test "indexToBit" { try testing.expectEqual(Type.indexToBit(9), 2); } -fn testCheckBitmaps(bmp: Bitmap(u4), b1: u4, b2: u4, b3: u4, b4: u4) !void { +fn testCheckBitmaps(bmp: Bitmap(null, u4), b1: u4, b2: u4, b3: u4, b4: u4) !void { try testing.expectEqual(@as(u4, b1), bmp.bitmaps[0]); try testing.expectEqual(@as(u4, b2), bmp.bitmaps[1]); try testing.expectEqual(@as(u4, b3), bmp.bitmaps[2]); @@ -767,7 +656,8 @@ fn testCheckBitmaps(bmp: Bitmap(u4), b1: u4, b2: u4, b3: u4, b4: u4) !void { } test "setContiguous" { - var bmp = try Bitmap(u4).init(16, std.testing.allocator); + var bmp = try Bitmap(null, u4).init(16, std.testing.allocator); + try testing.expectEqual(@as(u32, 4), bmp.bitmaps.len); defer bmp.deinit(); // Test trying to set more entries than the bitmap has try testing.expectEqual(bmp.setContiguous(bmp.num_entries + 1, null), null); diff --git a/src/kernel/pmm.zig b/src/kernel/pmm.zig index 5f99b4e..395269d 100644 --- a/src/kernel/pmm.zig +++ b/src/kernel/pmm.zig @@ -6,10 +6,11 @@ const arch = @import("arch.zig").internals; const MemProfile = @import("mem.zig").MemProfile; const testing = std.testing; const panic = @import("panic.zig").panic; -const Bitmap = @import("bitmap.zig").Bitmap; +const bitmap = @import("bitmap.zig"); +const Bitmap = bitmap.Bitmap; const Allocator = std.mem.Allocator; -const PmmBitmap = Bitmap(u32); +const PmmBitmap = Bitmap(null, u32); /// The possible errors thrown by bitmap functions const PmmError = error{ @@ -20,7 +21,7 @@ const PmmError = error{ /// The size of memory associated with each bitmap entry pub const BLOCK_SIZE: usize = arch.MEMORY_BLOCK_SIZE; -var bitmap: PmmBitmap = undefined; +var the_bitmap: PmmBitmap = undefined; /// /// Set the bitmap entry for an address as occupied @@ -31,8 +32,8 @@ var bitmap: PmmBitmap = undefined; /// Error: PmmBitmap.BitmapError. /// *: See PmmBitmap.setEntry. Could occur if the address is out of bounds. /// -pub fn setAddr(addr: usize) PmmBitmap.BitmapError!void { - try bitmap.setEntry(@intCast(u32, addr / BLOCK_SIZE)); +pub fn setAddr(addr: usize) bitmap.BitmapError!void { + try the_bitmap.setEntry(@intCast(u32, addr / BLOCK_SIZE)); } /// @@ -46,8 +47,8 @@ pub fn setAddr(addr: usize) PmmBitmap.BitmapError!void { /// Error: PmmBitmap.BitmapError. /// *: See PmmBitmap.setEntry. Could occur if the address is out of bounds. /// -pub fn isSet(addr: usize) PmmBitmap.BitmapError!bool { - return bitmap.isSet(@intCast(u32, addr / BLOCK_SIZE)); +pub fn isSet(addr: usize) bitmap.BitmapError!bool { + return the_bitmap.isSet(@intCast(u32, addr / BLOCK_SIZE)); } /// @@ -56,7 +57,7 @@ pub fn isSet(addr: usize) PmmBitmap.BitmapError!bool { /// Return: The address that was allocated. /// pub fn alloc() ?usize { - if (bitmap.setFirstFree()) |entry| { + if (the_bitmap.setFirstFree()) |entry| { return entry * BLOCK_SIZE; } return null; @@ -72,10 +73,10 @@ pub fn alloc() ?usize { /// PmmError.NotAllocated: The address wasn't allocated. /// PmmBitmap.BitmapError.OutOfBounds: The address given was out of bounds. /// -pub fn free(addr: usize) (PmmBitmap.BitmapError || PmmError)!void { +pub fn free(addr: usize) (bitmap.BitmapError || PmmError)!void { const idx = @intCast(u32, addr / BLOCK_SIZE); - if (try bitmap.isSet(idx)) { - try bitmap.clearEntry(idx); + if (try the_bitmap.isSet(idx)) { + try the_bitmap.clearEntry(idx); } else { return PmmError.NotAllocated; } @@ -88,7 +89,7 @@ pub fn free(addr: usize) (PmmBitmap.BitmapError || PmmError)!void { /// The number of unallocated blocks of memory /// pub fn blocksFree() usize { - return bitmap.num_free_entries; + return the_bitmap.num_free_entries; } /// Intiialise the physical memory manager and set all unavailable regions as occupied (those from the memory map and those from the linker symbols). @@ -101,7 +102,7 @@ pub fn init(mem_profile: *const MemProfile, allocator: Allocator) void { log.info("Init\n", .{}); defer log.info("Done\n", .{}); - bitmap = PmmBitmap.init(mem_profile.mem_kb * 1024 / BLOCK_SIZE, allocator) catch |e| { + the_bitmap = PmmBitmap.init(mem_profile.mem_kb * 1024 / BLOCK_SIZE, allocator) catch |e| { panic(@errorReturnTrace(), "Bitmap allocation failed: {}\n", .{e}); }; @@ -116,7 +117,7 @@ pub fn init(mem_profile: *const MemProfile, allocator: Allocator) void { while (addr < end) : (addr += BLOCK_SIZE) { setAddr(addr) catch |e| switch (e) { // We can ignore out of bounds errors as the memory won't be available anyway - PmmBitmap.BitmapError.OutOfBounds => break, + bitmap.BitmapError.OutOfBounds => break, else => panic(@errorReturnTrace(), "Failed setting address 0x{x} from memory map as occupied: {}", .{ addr, e }), }; } @@ -132,12 +133,12 @@ pub fn init(mem_profile: *const MemProfile, allocator: Allocator) void { /// Free the internal state of the PMM. Is unusable aftwards unless re-initialised /// pub fn deinit() void { - bitmap.deinit(); + the_bitmap.deinit(); } test "alloc" { - bitmap = try Bitmap(u32).init(32, testing.allocator); - defer bitmap.deinit(); + the_bitmap = try Bitmap(null, u32).init(32, testing.allocator); + defer the_bitmap.deinit(); comptime var addr = 0; comptime var i = 0; // Allocate all entries, making sure they succeed and return the correct addresses @@ -155,8 +156,8 @@ test "alloc" { } test "free" { - bitmap = try Bitmap(u32).init(32, testing.allocator); - defer bitmap.deinit(); + the_bitmap = try Bitmap(null, u32).init(32, testing.allocator); + defer the_bitmap.deinit(); comptime var i = 0; // Allocate and free all entries inline while (i < 32) : (i += 1) { @@ -173,8 +174,8 @@ test "free" { test "setAddr and isSet" { const num_entries: u32 = 32; - bitmap = try Bitmap(u32).init(num_entries, testing.allocator); - defer bitmap.deinit(); + the_bitmap = try Bitmap(null, u32).init(num_entries, testing.allocator); + defer the_bitmap.deinit(); var addr: u32 = 0; var i: u32 = 0; while (i < num_entries) : ({ diff --git a/src/kernel/scheduler.zig b/src/kernel/scheduler.zig index b8f27e2..d05336e 100644 --- a/src/kernel/scheduler.zig +++ b/src/kernel/scheduler.zig @@ -195,8 +195,11 @@ test "pickNextTask" { tasks = TailQueue(*Task){}; // Set up a current task - current_task = try allocator.create(Task); - defer allocator.destroy(current_task); + var first = try allocator.create(Task); + // We use an intermediary variable to avoid a double-free. + // Deferring freeing current_task will free whatever current_task points to at the end + defer allocator.destroy(first); + current_task = first; current_task.pid = 0; current_task.kernel_stack = @intToPtr([*]u32, @ptrToInt(&KERNEL_STACK_START))[0..4096]; current_task.stack_pointer = @ptrToInt(&KERNEL_STACK_START); @@ -232,7 +235,7 @@ test "pickNextTask" { // The stack pointer of the re-added task should point to the context try expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx)); - // Should be back tot he beginning + // Should be back to the beginning try expectEqual(current_task.pid, 0); // Reset the test pid diff --git a/src/kernel/task.zig b/src/kernel/task.zig index cadd266..fa45f88 100644 --- a/src/kernel/task.zig +++ b/src/kernel/task.zig @@ -11,7 +11,6 @@ const pmm = @import("pmm.zig"); const mem = @import("mem.zig"); const elf = @import("elf.zig"); const bitmap = @import("bitmap.zig"); -const ComptimeBitmap = bitmap.ComptimeBitmap; const Allocator = std.mem.Allocator; const log = std.log.scoped(.task); @@ -23,14 +22,14 @@ extern var KERNEL_STACK_START: *u32; pub const EntryPoint = usize; /// The bitmap type for the PIDs -const PidBitmap = if (is_test) ComptimeBitmap(u128) else ComptimeBitmap(u1024); +const PidBitmap = bitmap.Bitmap(1024, usize); /// The list of PIDs that have been allocated. -var all_pids: PidBitmap = brk: { - var pids = PidBitmap.init(); - // Set the first PID as this is for the current task running, init 0 +var all_pids: PidBitmap = init: { + var pids = PidBitmap.init(1024, null) catch unreachable; + // Reserve PID 0 for the init task _ = pids.setFirstFree() orelse unreachable; - break :brk pids; + break :init pids; }; /// The default stack size of a task. Currently this is set to a page size. @@ -41,7 +40,7 @@ pub const Task = struct { const Self = @This(); /// The unique task identifier - pid: PidBitmap.IndexType, + pid: usize, /// Pointer to the kernel stack for the task. This will be allocated on initialisation. kernel_stack: []usize, @@ -81,7 +80,7 @@ pub const Task = struct { errdefer allocator.destroy(task); const pid = allocatePid(); - errdefer freePid(pid); + errdefer freePid(pid) catch |e| panic(@errorReturnTrace(), "Failed to free task PID in errdefer ({}): {}\n", .{ pid, e }); var k_stack = try allocator.alloc(usize, STACK_SIZE); errdefer allocator.free(k_stack); @@ -103,7 +102,7 @@ pub const Task = struct { return task; } - pub fn createFromElf(program_elf: elf.Elf, kernel: bool, task_vmm: *vmm.VirtualMemoryManager(arch.VmmPayload), allocator: Allocator) (bitmap.Bitmap(usize).BitmapError || vmm.VmmError || Allocator.Error)!*Task { + pub fn createFromElf(program_elf: elf.Elf, kernel: bool, task_vmm: *vmm.VirtualMemoryManager(arch.VmmPayload), allocator: Allocator) (bitmap.BitmapError || vmm.VmmError || Allocator.Error)!*Task { const task = try create(program_elf.header.entry_address, kernel, task_vmm, allocator); errdefer task.destroy(allocator); @@ -143,7 +142,7 @@ pub const Task = struct { /// IN allocator: Allocator - The allocator used to create the task. /// pub fn destroy(self: *Self, allocator: Allocator) void { - freePid(self.pid); + freePid(self.pid) catch |e| panic(@errorReturnTrace(), "Failed to free task's PID ({}): {}\n", .{ self.pid, e }); // We need to check that the the stack has been allocated as task 0 (init) won't have a // stack allocated as this in the linker script if (@ptrToInt(self.kernel_stack.ptr) != @ptrToInt(&KERNEL_STACK_START)) { @@ -163,7 +162,7 @@ pub const Task = struct { /// Return: u32 /// A new PID. /// -fn allocatePid() PidBitmap.IndexType { +fn allocatePid() usize { return all_pids.setFirstFree() orelse panic(@errorReturnTrace(), "Out of PIDs\n", .{}); } @@ -171,13 +170,16 @@ fn allocatePid() PidBitmap.IndexType { /// Free an allocated PID. One must be allocated to be freed. If one wasn't allocated will panic. /// /// Arguments: -/// IN pid: u32 - The PID to free. +/// IN pid: usize - The PID to free. /// -fn freePid(pid: PidBitmap.IndexType) void { - if (!all_pids.isSet(pid)) { +/// Error: BitmapError. +/// OutOfBounds: The index given is out of bounds. +/// +fn freePid(pid: usize) bitmap.BitmapError!void { + if (!(try all_pids.isSet(pid))) { panic(@errorReturnTrace(), "PID {} not allocated\n", .{pid}); } - all_pids.clearEntry(pid); + try all_pids.clearEntry(pid); } // For testing the errdefer @@ -197,7 +199,9 @@ test "create out of memory for task" { try expectEqual(fa.allocated_bytes, fa.freed_bytes); // Make sure no PIDs were allocated - try expectEqual(all_pids.bitmap, 0); + for (all_pids.bitmaps) |bmp| { + try expectEqual(bmp, 0); + } } test "create out of memory for stack" { @@ -211,7 +215,9 @@ test "create out of memory for stack" { try expectEqual(fa.allocated_bytes, fa.freed_bytes); // Make sure no PIDs were allocated - try expectEqual(all_pids.bitmap, 0); + for (all_pids.bitmaps) |bmp| { + try expectEqual(bmp, 0); + } } test "create expected setup" { @@ -242,7 +248,9 @@ test "destroy cleans up" { user_task.destroy(allocator); // All PIDs were freed - try expectEqual(all_pids.bitmap, 0); + for (all_pids.bitmaps) |bmp| { + try expectEqual(bmp, 0); + } } test "Multiple create" { @@ -251,16 +259,25 @@ test "Multiple create" { try expectEqual(task1.pid, 0); try expectEqual(task2.pid, 1); - try expectEqual(all_pids.bitmap, 3); + try expectEqual(all_pids.bitmaps[0], 3); + for (all_pids.bitmaps) |bmp, i| { + if (i > 0) try expectEqual(bmp, 0); + } task1.destroy(std.testing.allocator); - try expectEqual(all_pids.bitmap, 2); + try expectEqual(all_pids.bitmaps[0], 2); + for (all_pids.bitmaps) |bmp, i| { + if (i > 0) try expectEqual(bmp, 0); + } var task3 = try Task.create(@ptrToInt(test_fn1), true, undefined, std.testing.allocator); try expectEqual(task3.pid, 0); - try expectEqual(all_pids.bitmap, 3); + try expectEqual(all_pids.bitmaps[0], 3); + for (all_pids.bitmaps) |bmp, i| { + if (i > 0) try expectEqual(bmp, 0); + } task2.destroy(std.testing.allocator); task3.destroy(std.testing.allocator); @@ -268,28 +285,39 @@ test "Multiple create" { var user_task = try Task.create(@ptrToInt(test_fn1), false, undefined, std.testing.allocator); try expectEqual(user_task.pid, 0); - try expectEqual(all_pids.bitmap, 1); + try expectEqual(all_pids.bitmaps[0], 1); + for (all_pids.bitmaps) |bmp, i| { + if (i > 0) try expectEqual(bmp, 0); + } user_task.destroy(std.testing.allocator); - try expectEqual(all_pids.bitmap, 0); + for (all_pids.bitmaps) |bmp| { + try expectEqual(bmp, 0); + } } test "allocatePid and freePid" { - try expectEqual(all_pids.bitmap, 0); + for (all_pids.bitmaps) |bmp| { + try expectEqual(bmp, 0); + } var i: usize = 0; - while (i < PidBitmap.NUM_ENTRIES) : (i += 1) { + while (i < all_pids.num_entries) : (i += 1) { try expectEqual(i, allocatePid()); } - try expectEqual(all_pids.bitmap, PidBitmap.BITMAP_FULL); - - i = 0; - while (i < PidBitmap.NUM_ENTRIES) : (i += 1) { - freePid(@truncate(PidBitmap.IndexType, i)); + for (all_pids.bitmaps) |bmp| { + try expectEqual(bmp, PidBitmap.BITMAP_FULL); } - try expectEqual(all_pids.bitmap, 0); + i = 0; + while (i < all_pids.num_entries) : (i += 1) { + try freePid(i); + } + + for (all_pids.bitmaps) |bmp| { + try expectEqual(bmp, 0); + } } test "createFromElf" { @@ -333,7 +361,7 @@ test "createFromElf clean-up" { // Test OutOfMemory var allocator2 = std.testing.FailingAllocator.init(allocator, 0).allocator(); try std.testing.expectError(std.mem.Allocator.Error.OutOfMemory, Task.createFromElf(the_elf, true, &the_vmm, allocator2)); - try std.testing.expectEqual(all_pids.num_free_entries, PidBitmap.NUM_ENTRIES - 1); + try std.testing.expectEqual(all_pids.num_free_entries, all_pids.num_entries - 1); // Test AlreadyAllocated try std.testing.expectError(error.AlreadyAllocated, Task.createFromElf(the_elf, true, &the_vmm, allocator)); // Test OutOfBounds diff --git a/src/kernel/vmm.zig b/src/kernel/vmm.zig index 7f223c3..453fb0f 100644 --- a/src/kernel/vmm.zig +++ b/src/kernel/vmm.zig @@ -133,7 +133,7 @@ pub var kernel_vmm: VirtualMemoryManager(arch.VmmPayload) = undefined; pub fn VirtualMemoryManager(comptime Payload: type) type { return struct { /// The bitmap that keeps track of allocated and free regions - bmp: bitmap.Bitmap(usize), + bmp: bitmap.Bitmap(null, usize), /// The start of the memory to be tracked start: usize, @@ -173,7 +173,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type { /// pub fn init(start: usize, end: usize, allocator: Allocator, mapper: Mapper(Payload), payload: Payload) Allocator.Error!Self { const size = end - start; - var bmp = try bitmap.Bitmap(usize).init(std.mem.alignForward(size, pmm.BLOCK_SIZE) / pmm.BLOCK_SIZE, allocator); + var bmp = try bitmap.Bitmap(null, usize).init(std.mem.alignForward(size, pmm.BLOCK_SIZE) / pmm.BLOCK_SIZE, allocator); return Self{ .bmp = bmp, .start = start, @@ -305,7 +305,10 @@ pub fn VirtualMemoryManager(comptime Payload: type) type { /// Error: pmm.PmmError /// Bitmap(u32).Error.OutOfBounds - The address given is outside of the memory managed /// - pub fn isSet(self: *const Self, virt: usize) bitmap.Bitmap(u32).BitmapError!bool { + pub fn isSet(self: *const Self, virt: usize) bitmap.BitmapError!bool { + if (virt < self.start) { + return bitmap.BitmapError.OutOfBounds; + } return self.bmp.isSet((virt - self.start) / BLOCK_SIZE); } @@ -328,7 +331,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type { /// Allocator.Error.OutOfMemory - Allocating the required memory failed /// MapperError.* - The causes depend on the mapper used /// - pub fn set(self: *Self, virtual: mem.Range, physical: ?mem.Range, attrs: Attributes) (VmmError || bitmap.Bitmap(u32).BitmapError || Allocator.Error || MapperError)!void { + pub fn set(self: *Self, virtual: mem.Range, physical: ?mem.Range, attrs: Attributes) (VmmError || bitmap.BitmapError || Allocator.Error || MapperError)!void { var virt = virtual.start; while (virt < virtual.end) : (virt += BLOCK_SIZE) { if (try self.isSet(virt)) { @@ -440,14 +443,15 @@ pub fn VirtualMemoryManager(comptime Payload: type) type { /// Bitmap(u32).Error.OutOfBounds - The address given is outside of the memory managed /// Allocator.Error.OutOfMemory - There wasn't enough memory available to fulfill the request /// - pub fn copyData(self: *Self, other: *const Self, comptime from: bool, data: if (from) []const u8 else []u8, address: usize) (bitmap.Bitmap(usize).BitmapError || VmmError || Allocator.Error)!void { + pub fn copyData(self: *Self, other: *const Self, comptime from: bool, data: if (from) []const u8 else []u8, address: usize) (bitmap.BitmapError || VmmError || Allocator.Error)!void { if (data.len == 0) { return; } const start_addr = std.mem.alignBackward(address, BLOCK_SIZE); const end_addr = std.mem.alignForward(address + data.len, BLOCK_SIZE); + if (end_addr >= other.end or start_addr < other.start) - return bitmap.Bitmap(usize).BitmapError.OutOfBounds; + return bitmap.BitmapError.OutOfBounds; // Find physical blocks for the address var blocks = std.ArrayList(usize).init(self.allocator); defer blocks.deinit(); @@ -511,7 +515,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type { /// VmmError.NotAllocated - This address hasn't been allocated yet /// Bitmap.BitmapError.OutOfBounds - The address is out of the manager's bounds /// - pub fn free(self: *Self, vaddr: usize) (bitmap.Bitmap(u32).BitmapError || VmmError)!void { + pub fn free(self: *Self, vaddr: usize) (bitmap.BitmapError || VmmError)!void { const entry = (vaddr - self.start) / BLOCK_SIZE; if (try self.bmp.isSet(entry)) { // There will be an allocation associated with this virtual address @@ -666,8 +670,8 @@ test "alloc and free" { // Allocation failed as there weren't enough free entries if (vaddr >= num_entries * BLOCK_SIZE) { // If this address is beyond the VMM's end address, it should be out of bounds - try std.testing.expectError(bitmap.Bitmap(u32).BitmapError.OutOfBounds, vmm.isSet(vaddr)); - try std.testing.expectError(bitmap.Bitmap(u64).BitmapError.OutOfBounds, allocations.isSet(vaddr / BLOCK_SIZE)); + try std.testing.expectError(bitmap.BitmapError.OutOfBounds, vmm.isSet(vaddr)); + try std.testing.expectError(bitmap.BitmapError.OutOfBounds, allocations.isSet(vaddr / BLOCK_SIZE)); } else { // Else it should not be set try std.testing.expect(!(try vmm.isSet(vaddr))); @@ -685,6 +689,8 @@ test "alloc and free" { try std.testing.expect(!(try pmm.isSet(later_entry * BLOCK_SIZE))); } } + // Out of bounds entries should cause an error + try std.testing.expectError(bitmap.BitmapError.OutOfBounds, vmm.isSet((entry + 1) * BLOCK_SIZE)); // Try freeing all allocations for (virtual_allocations.items) |alloc| { @@ -832,8 +838,8 @@ test "copyData from" { try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries); // Test Bitmap.Error.OutOfBounds - try std.testing.expectError(bitmap.Bitmap(usize).BitmapError.OutOfBounds, vmm2.copyData(&vmm, true, buff[0..buff.len], vmm.end)); - try std.testing.expectError(bitmap.Bitmap(usize).BitmapError.OutOfBounds, vmm.copyData(&vmm2, true, buff[0..buff.len], vmm2.end)); + try std.testing.expectError(bitmap.BitmapError.OutOfBounds, vmm2.copyData(&vmm, true, buff[0..buff.len], vmm.end)); + try std.testing.expectError(bitmap.BitmapError.OutOfBounds, vmm.copyData(&vmm2, true, buff[0..buff.len], vmm2.end)); try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries); try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries); } @@ -857,7 +863,7 @@ test "copyDaya to" { try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries); } -var test_allocations: ?*bitmap.Bitmap(u64) = null; +var test_allocations: ?*bitmap.Bitmap(null, u64) = null; var test_mapper = Mapper(arch.VmmPayload){ .mapFn = testMap, .unmapFn = testUnmap }; /// @@ -874,8 +880,8 @@ var test_mapper = Mapper(arch.VmmPayload){ .mapFn = testMap, .unmapFn = testUnma /// pub fn testInit(num_entries: u32) Allocator.Error!VirtualMemoryManager(arch.VmmPayload) { if (test_allocations == null) { - test_allocations = try std.testing.allocator.create(bitmap.Bitmap(u64)); - test_allocations.?.* = try bitmap.Bitmap(u64).init(num_entries, std.testing.allocator); + test_allocations = try std.testing.allocator.create(bitmap.Bitmap(null, u64)); + test_allocations.?.* = try bitmap.Bitmap(null, u64).init(num_entries, std.testing.allocator); } else |allocations| { var entry: u32 = 0; while (entry < allocations.num_entries) : (entry += 1) {