Merge pull request #310 from kjaleshire/update-for-zig-0.8.0

Update source tree for zig 0.8.0
This commit is contained in:
Sam Tebbs 2022-03-06 15:26:54 +00:00 committed by GitHub
commit 765c07a457
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 2347 additions and 2211 deletions

View file

@ -19,8 +19,7 @@ jobs:
- name: Download zig - name: Download zig
run: | run: |
export PYTHONIOENCODING=utf8 export PYTHONIOENCODING=utf8
# Lock the master commit that we download, because of blocking issues wget https://ziglang.org/download/0.9.1/zig-linux-x86_64-0.9.1.tar.xz
wget https://ziglang.org/builds/zig-linux-x86_64-0.8.0-dev.2133+ad33e3483.tar.xz
sudo apt-get install mtools sudo apt-get install mtools
tar -xvf zig* tar -xvf zig*
- name: Install qemu - name: Install qemu

View file

@ -17,7 +17,7 @@ All of these goals will benefit from the features of Zig.
## Build ## Build
Requires a master build of Zig at commit ad33e3483 ([downloaded](https://ziglang.org/builds/zig-linux-x86_64-0.8.0-dev.2133+ad33e3483.tar.xz) or [built from source](https://github.com/ziglang/zig#building-from-source)), *xorriso* and the grub tools (such as *grub-mkrescue*). A *qemu-system* binary compatible with your chosen target is required to run the kernel (e.g. *qemu-system-i386*). Requires a master build of Zig 0.9.1([downloaded](https://ziglang.org/download) or [built from source](https://github.com/ziglang/zig#building-from-source)), *xorriso* and the grub tools (such as *grub-mkrescue*). A *qemu-system* binary compatible with your chosen target is required to run the kernel (e.g. *qemu-system-i386*).
```Shell ```Shell
zig build zig build

View file

@ -10,7 +10,7 @@ const Target = std.Target;
const CrossTarget = std.zig.CrossTarget; const CrossTarget = std.zig.CrossTarget;
const fs = std.fs; const fs = std.fs;
const File = fs.File; const File = fs.File;
const Mode = builtin.Mode; const Mode = std.builtin.Mode;
const TestMode = rt.TestMode; const TestMode = rt.TestMode;
const ArrayList = std.ArrayList; const ArrayList = std.ArrayList;
const Fat32 = @import("mkfat32.zig").Fat32; const Fat32 = @import("mkfat32.zig").Fat32;
@ -59,14 +59,17 @@ pub fn build(b: *Builder) !void {
const disable_display = b.option(bool, "disable-display", "Disable the qemu window") orelse false; const disable_display = b.option(bool, "disable-display", "Disable the qemu window") orelse false;
const exec = b.addExecutable("pluto.elf", main_src); const exec = b.addExecutable("pluto.elf", main_src);
const exec_output_path = try fs.path.join(b.allocator, &[_][]const u8{ b.install_path, "pluto.elf" });
exec.setOutputDir(b.install_path); exec.setOutputDir(b.install_path);
exec.addBuildOption(TestMode, "test_mode", test_mode); const exec_options = b.addOptions();
exec.addOptions("build_options", exec_options);
exec_options.addOption(TestMode, "test_mode", test_mode);
exec.setBuildMode(build_mode); exec.setBuildMode(build_mode);
exec.setLinkerScriptPath(linker_script_path); exec.setLinkerScriptPath(std.build.FileSource{ .path = linker_script_path });
exec.setTarget(target); exec.setTarget(target);
const make_iso = switch (target.getCpuArch()) { const make_iso = switch (target.getCpuArch()) {
.i386 => b.addSystemCommand(&[_][]const u8{ "./makeiso.sh", boot_path, modules_path, iso_dir_path, exec.getOutputPath(), ramdisk_path, output_iso }), .i386 => b.addSystemCommand(&[_][]const u8{ "./makeiso.sh", boot_path, modules_path, iso_dir_path, exec_output_path, ramdisk_path, output_iso }),
else => unreachable, else => unreachable,
}; };
make_iso.step.dependOn(&exec.step); make_iso.step.dependOn(&exec.step);
@ -85,7 +88,7 @@ pub fn build(b: *Builder) !void {
inline for (&[_][]const u8{ "user_program_data", "user_program" }) |user_program| { inline for (&[_][]const u8{ "user_program_data", "user_program" }) |user_program| {
// Add some test files for the user mode runtime tests // Add some test files for the user mode runtime tests
const user_program_step = b.addExecutable(user_program ++ ".elf", null); const user_program_step = b.addExecutable(user_program ++ ".elf", null);
user_program_step.setLinkerScriptPath("test/user_program.ld"); user_program_step.setLinkerScriptPath(.{ .path = "test/user_program.ld" });
user_program_step.addAssemblyFile("test/" ++ user_program ++ ".s"); user_program_step.addAssemblyFile("test/" ++ user_program ++ ".s");
user_program_step.setOutputDir(b.install_path); user_program_step.setOutputDir(b.install_path);
user_program_step.setTarget(target); user_program_step.setTarget(target);
@ -103,18 +106,16 @@ pub fn build(b: *Builder) !void {
b.default_step.dependOn(&make_iso.step); b.default_step.dependOn(&make_iso.step);
const test_step = b.step("test", "Run tests"); const test_step = b.step("test", "Run tests");
const mock_path = "../../test/mock/kernel/";
const arch_mock_path = "../../../../test/mock/kernel/";
const unit_tests = b.addTest(main_src); const unit_tests = b.addTest(main_src);
unit_tests.setBuildMode(build_mode); unit_tests.setBuildMode(build_mode);
unit_tests.setMainPkgPath("."); unit_tests.setMainPkgPath(".");
unit_tests.addBuildOption(TestMode, "test_mode", test_mode); const unit_test_options = b.addOptions();
unit_tests.addBuildOption([]const u8, "mock_path", mock_path); unit_tests.addOptions("build_options", unit_test_options);
unit_tests.addBuildOption([]const u8, "arch_mock_path", arch_mock_path); unit_test_options.addOption(TestMode, "test_mode", test_mode);
unit_tests.setTarget(.{ .cpu_arch = target.cpu_arch }); unit_tests.setTarget(.{ .cpu_arch = target.cpu_arch });
if (builtin.os.tag != .windows) { if (builtin.os.tag != .windows) {
unit_tests.enable_qemu = true; b.enable_qemu = true;
} }
// Run the mock gen // Run the mock gen
@ -175,7 +176,7 @@ pub fn build(b: *Builder) !void {
run_debug_step.dependOn(&qemu_debug_cmd.step); run_debug_step.dependOn(&qemu_debug_cmd.step);
const debug_step = b.step("debug", "Debug with gdb and connect to a running qemu instance"); const debug_step = b.step("debug", "Debug with gdb and connect to a running qemu instance");
const symbol_file_arg = try std.mem.join(b.allocator, " ", &[_][]const u8{ "symbol-file", exec.getOutputPath() }); const symbol_file_arg = try std.mem.join(b.allocator, " ", &[_][]const u8{ "symbol-file", exec_output_path });
const debug_cmd = b.addSystemCommand(&[_][]const u8{ const debug_cmd = b.addSystemCommand(&[_][]const u8{
"gdb-multiarch", "gdb-multiarch",
"-ex", "-ex",
@ -239,7 +240,7 @@ const Fat32BuilderStep = struct {
pub fn create(builder: *Builder, options: Fat32.Options, out_file_path: []const u8) *Fat32BuilderStep { pub fn create(builder: *Builder, options: Fat32.Options, out_file_path: []const u8) *Fat32BuilderStep {
const fat32_builder_step = builder.allocator.create(Fat32BuilderStep) catch unreachable; const fat32_builder_step = builder.allocator.create(Fat32BuilderStep) catch unreachable;
fat32_builder_step.* = .{ fat32_builder_step.* = .{
.step = Step.init(.Custom, builder.fmt("Fat32BuilderStep", .{}), builder.allocator, make), .step = Step.init(.custom, builder.fmt("Fat32BuilderStep", .{}), builder.allocator, make),
.builder = builder, .builder = builder,
.options = options, .options = options,
.out_file_path = out_file_path, .out_file_path = out_file_path,
@ -354,7 +355,7 @@ const RamdiskStep = struct {
pub fn create(builder: *Builder, target: CrossTarget, files: []const []const u8, out_file_path: []const u8) *RamdiskStep { pub fn create(builder: *Builder, target: CrossTarget, files: []const []const u8, out_file_path: []const u8) *RamdiskStep {
const ramdisk_step = builder.allocator.create(RamdiskStep) catch unreachable; const ramdisk_step = builder.allocator.create(RamdiskStep) catch unreachable;
ramdisk_step.* = .{ ramdisk_step.* = .{
.step = Step.init(.Custom, builder.fmt("Ramdisk", .{}), builder.allocator, make), .step = Step.init(.custom, builder.fmt("Ramdisk", .{}), builder.allocator, make),
.builder = builder, .builder = builder,
.target = target, .target = target,
.files = files, .files = files,

View file

@ -1,9 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -ex
IMAGE_PATH_DIR=$1 IMAGE_PATH_DIR=$1
mkdir test/fat32/mnt mkdir test/fat32/mnt
sudo mount -o utf8=true $IMAGE_PATH_DIR test/fat32/mnt/ whoami
sudo cp -r test/fat32/test_files/. test/fat32/mnt/
sudo umount test/fat32/mnt/ if [ "$(whoami)" = "root" ]; then
echo "Am root"
mount -o utf8=true $IMAGE_PATH_DIR test/fat32/mnt/
cp -r test/fat32/test_files/. test/fat32/mnt/
umount test/fat32/mnt/
else
echo "Not root"
sudo mount -o utf8=true $IMAGE_PATH_DIR test/fat32/mnt/
sudo cp -r test/fat32/test_files/. test/fat32/mnt/
sudo umount test/fat32/mnt/
fi
rm -rf test/fat32/mnt rm -rf test/fat32/mnt

View file

@ -487,7 +487,7 @@ pub const Fat32 = struct {
else => @compileError("Unexpected field type: " ++ @typeName(info.child)), else => @compileError("Unexpected field type: " ++ @typeName(info.child)),
}, },
.Int => try fat32_header_stream.writer().writeIntLittle(item.field_type, @field(fat32_header, item.name)), .Int => try fat32_header_stream.writer().writeIntLittle(item.field_type, @field(fat32_header, item.name)),
else => @compileError("Unexpected field type: " ++ @typeName(info.child)), else => @compileError("Unexpected field type: " ++ @typeName(@typeInfo(item.field_type))),
} }
} }
@ -567,8 +567,8 @@ pub const Fat32 = struct {
/// @TypeOf(stream).WriteError - Error writing to the stream. /// @TypeOf(stream).WriteError - Error writing to the stream.
/// ///
fn clearStream(stream: anytype, size: usize) ErrorSet(@TypeOf(stream))!void { fn clearStream(stream: anytype, size: usize) ErrorSet(@TypeOf(stream))!void {
comptime const buff_size = 4096; const buff_size = 4096;
comptime const bytes: [buff_size]u8 = [_]u8{0x00} ** buff_size; const bytes: [buff_size]u8 = [_]u8{0x00} ** buff_size;
var remaining: usize = size; var remaining: usize = size;
while (remaining > 0) { while (remaining > 0) {

View file

@ -2,9 +2,8 @@ const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path;
pub const internals = if (is_test) @import(mock_path ++ "arch_mock.zig") else switch (builtin.arch) { pub const internals = if (is_test) @import("../../test/mock/kernel/arch_mock.zig") else switch (builtin.cpu.arch) {
.i386 => @import("arch/x86/arch.zig"), .i386 => @import("arch/x86/arch.zig"),
else => unreachable, else => unreachable,
}; };

View file

@ -120,16 +120,16 @@ pub const MEMORY_BLOCK_SIZE: usize = paging.PAGE_SIZE_4KB;
pub fn in(comptime Type: type, port: u16) Type { pub fn in(comptime Type: type, port: u16) Type {
return switch (Type) { return switch (Type) {
u8 => asm volatile ("inb %[port], %[result]" u8 => asm volatile ("inb %[port], %[result]"
: [result] "={al}" (-> Type) : [result] "={al}" (-> Type),
: [port] "N{dx}" (port) : [port] "N{dx}" (port),
), ),
u16 => asm volatile ("inw %[port], %[result]" u16 => asm volatile ("inw %[port], %[result]"
: [result] "={ax}" (-> Type) : [result] "={ax}" (-> Type),
: [port] "N{dx}" (port) : [port] "N{dx}" (port),
), ),
u32 => asm volatile ("inl %[port], %[result]" u32 => asm volatile ("inl %[port], %[result]"
: [result] "={eax}" (-> Type) : [result] "={eax}" (-> Type),
: [port] "N{dx}" (port) : [port] "N{dx}" (port),
), ),
else => @compileError("Invalid data type. Only u8, u16 or u32, found: " ++ @typeName(Type)), else => @compileError("Invalid data type. Only u8, u16 or u32, found: " ++ @typeName(Type)),
}; };
@ -147,17 +147,17 @@ pub fn out(port: u16, data: anytype) void {
u8 => asm volatile ("outb %[data], %[port]" u8 => asm volatile ("outb %[data], %[port]"
: :
: [port] "{dx}" (port), : [port] "{dx}" (port),
[data] "{al}" (data) [data] "{al}" (data),
), ),
u16 => asm volatile ("outw %[data], %[port]" u16 => asm volatile ("outw %[data], %[port]"
: :
: [port] "{dx}" (port), : [port] "{dx}" (port),
[data] "{ax}" (data) [data] "{ax}" (data),
), ),
u32 => asm volatile ("outl %[data], %[port]" u32 => asm volatile ("outl %[data], %[port]"
: :
: [port] "{dx}" (port), : [port] "{dx}" (port),
[data] "{eax}" (data) [data] "{eax}" (data),
), ),
else => @compileError("Invalid data type. Only u8, u16 or u32, found: " ++ @typeName(@TypeOf(data))), else => @compileError("Invalid data type. Only u8, u16 or u32, found: " ++ @typeName(@TypeOf(data))),
} }
@ -182,13 +182,13 @@ pub fn lgdt(gdt_ptr: *const gdt.GdtPtr) void {
// Load the GDT into the CPU // Load the GDT into the CPU
asm volatile ("lgdt (%%eax)" asm volatile ("lgdt (%%eax)"
: :
: [gdt_ptr] "{eax}" (gdt_ptr) : [gdt_ptr] "{eax}" (gdt_ptr),
); );
// Load the kernel data segment, index into the GDT // Load the kernel data segment, index into the GDT
asm volatile ("mov %%bx, %%ds" asm volatile ("mov %%bx, %%ds"
: :
: [KERNEL_DATA_OFFSET] "{bx}" (gdt.KERNEL_DATA_OFFSET) : [KERNEL_DATA_OFFSET] "{bx}" (gdt.KERNEL_DATA_OFFSET),
); );
asm volatile ("mov %%bx, %%es"); asm volatile ("mov %%bx, %%es");
@ -212,7 +212,7 @@ pub fn lgdt(gdt_ptr: *const gdt.GdtPtr) void {
pub fn sgdt() gdt.GdtPtr { pub fn sgdt() gdt.GdtPtr {
var gdt_ptr = gdt.GdtPtr{ .limit = 0, .base = 0 }; var gdt_ptr = gdt.GdtPtr{ .limit = 0, .base = 0 };
asm volatile ("sgdt %[tab]" asm volatile ("sgdt %[tab]"
: [tab] "=m" (gdt_ptr) : [tab] "=m" (gdt_ptr),
); );
return gdt_ptr; return gdt_ptr;
} }
@ -226,7 +226,7 @@ pub fn sgdt() gdt.GdtPtr {
pub fn ltr(offset: u16) void { pub fn ltr(offset: u16) void {
asm volatile ("ltr %%ax" asm volatile ("ltr %%ax"
: :
: [offset] "{ax}" (offset) : [offset] "{ax}" (offset),
); );
} }
@ -239,7 +239,7 @@ pub fn ltr(offset: u16) void {
pub fn lidt(idt_ptr: *const idt.IdtPtr) void { pub fn lidt(idt_ptr: *const idt.IdtPtr) void {
asm volatile ("lidt (%%eax)" asm volatile ("lidt (%%eax)"
: :
: [idt_ptr] "{eax}" (idt_ptr) : [idt_ptr] "{eax}" (idt_ptr),
); );
} }
@ -252,7 +252,7 @@ pub fn lidt(idt_ptr: *const idt.IdtPtr) void {
pub fn sidt() idt.IdtPtr { pub fn sidt() idt.IdtPtr {
var idt_ptr = idt.IdtPtr{ .limit = 0, .base = 0 }; var idt_ptr = idt.IdtPtr{ .limit = 0, .base = 0 };
asm volatile ("sidt %[tab]" asm volatile ("sidt %[tab]"
: [tab] "=m" (idt_ptr) : [tab] "=m" (idt_ptr),
); );
return idt_ptr; return idt_ptr;
} }
@ -318,6 +318,8 @@ fn writeSerialCom1(byte: u8) void {
/// The Serial instance constructed with the function used to write bytes /// The Serial instance constructed with the function used to write bytes
/// ///
pub fn initSerial(boot_payload: BootPayload) Serial { pub fn initSerial(boot_payload: BootPayload) Serial {
// Suppress unused var warning
_ = boot_payload;
serial.init(serial.DEFAULT_BAUDRATE, serial.Port.COM1) catch |e| { serial.init(serial.DEFAULT_BAUDRATE, serial.Port.COM1) catch |e| {
panic(@errorReturnTrace(), "Failed to initialise serial: {}", .{e}); panic(@errorReturnTrace(), "Failed to initialise serial: {}", .{e});
}; };
@ -336,6 +338,8 @@ pub fn initSerial(boot_payload: BootPayload) Serial {
/// The TTY instance constructed with the information required by the rest of the kernel /// The TTY instance constructed with the information required by the rest of the kernel
/// ///
pub fn initTTY(boot_payload: BootPayload) TTY { pub fn initTTY(boot_payload: BootPayload) TTY {
// Suppress unused var warning
_ = boot_payload;
return .{ return .{
.print = tty.writeString, .print = tty.writeString,
.setCursor = tty.setCursor, .setCursor = tty.setCursor,
@ -374,7 +378,7 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
const mmap_addr = mb_info.mmap_addr; const mmap_addr = mb_info.mmap_addr;
const num_mmap_entries = mb_info.mmap_length / @sizeOf(multiboot.multiboot_memory_map_t); const num_mmap_entries = mb_info.mmap_length / @sizeOf(multiboot.multiboot_memory_map_t);
const allocator = &mem.fixed_buffer_allocator.allocator; const allocator = mem.fixed_buffer_allocator.allocator();
var reserved_physical_mem = std.ArrayList(mem.Range).init(allocator); var reserved_physical_mem = std.ArrayList(mem.Range).init(allocator);
var reserved_virtual_mem = std.ArrayList(mem.Map).init(allocator); var reserved_virtual_mem = std.ArrayList(mem.Map).init(allocator);
const mem_map = @intToPtr([*]multiboot.multiboot_memory_map_t, mmap_addr)[0..num_mmap_entries]; const mem_map = @intToPtr([*]multiboot.multiboot_memory_map_t, mmap_addr)[0..num_mmap_entries];
@ -488,7 +492,7 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
/// x86 initialises the keyboard connected to the PS/2 port /// x86 initialises the keyboard connected to the PS/2 port
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *std.mem.Allocator - The allocator to use if necessary /// IN allocator: std.mem.Allocator - The allocator to use if necessary
/// ///
/// Return: *Keyboard /// Return: *Keyboard
/// The initialised PS/2 keyboard /// The initialised PS/2 keyboard
@ -496,7 +500,7 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
/// Error: std.mem.Allocator.Error /// Error: std.mem.Allocator.Error
/// OutOfMemory - There wasn't enough memory to allocate what was needed /// OutOfMemory - There wasn't enough memory to allocate what was needed
/// ///
pub fn initKeyboard(allocator: *Allocator) Allocator.Error!*Keyboard { pub fn initKeyboard(allocator: Allocator) Allocator.Error!*Keyboard {
return keyboard.init(allocator); return keyboard.init(allocator);
} }
@ -510,12 +514,12 @@ pub fn initKeyboard(allocator: *Allocator) Allocator.Error!*Keyboard {
/// the initial CpuState on the kernel stack. /// the initial CpuState on the kernel stack.
/// IN entry_point: usize - The pointer to the entry point of the function. Functions only /// IN entry_point: usize - The pointer to the entry point of the function. Functions only
/// supported is fn () noreturn /// supported is fn () noreturn
/// IN allocator: *Allocator - The allocator use for allocating a stack. /// IN allocator: Allocator - The allocator use for allocating a stack.
/// ///
/// Error: Allocator.Error /// Error: Allocator.Error
/// OutOfMemory - Unable to allocate space for the stack. /// OutOfMemory - Unable to allocate space for the stack.
/// ///
pub fn initTask(task: *Task, entry_point: usize, allocator: *Allocator) Allocator.Error!void { pub fn initTask(task: *Task, entry_point: usize, allocator: Allocator) Allocator.Error!void {
const data_offset = if (task.kernel) gdt.KERNEL_DATA_OFFSET else gdt.USER_DATA_OFFSET | 0b11; const data_offset = if (task.kernel) gdt.KERNEL_DATA_OFFSET else gdt.USER_DATA_OFFSET | 0b11;
// Setting the bottom two bits of the code offset designates that this is a ring 3 task // Setting the bottom two bits of the code offset designates that this is a ring 3 task
const code_offset = if (task.kernel) gdt.KERNEL_CODE_OFFSET else gdt.USER_CODE_OFFSET | 0b11; const code_offset = if (task.kernel) gdt.KERNEL_CODE_OFFSET else gdt.USER_CODE_OFFSET | 0b11;
@ -573,7 +577,7 @@ pub fn initTask(task: *Task, entry_point: usize, allocator: *Allocator) Allocato
/// Get a list of hardware devices attached to the system. /// Get a list of hardware devices attached to the system.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - An allocator for getting the devices /// IN allocator: Allocator - An allocator for getting the devices
/// ///
/// Return: []Device /// Return: []Device
/// A list of hardware devices. /// A list of hardware devices.
@ -581,7 +585,7 @@ pub fn initTask(task: *Task, entry_point: usize, allocator: *Allocator) Allocato
/// Error: Allocator.Error /// Error: Allocator.Error
/// OutOfMemory - Unable to allocate space the operation. /// OutOfMemory - Unable to allocate space the operation.
/// ///
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device { pub fn getDevices(allocator: Allocator) Allocator.Error![]Device {
return pci.getDevices(allocator); return pci.getDevices(allocator);
} }

View file

@ -107,7 +107,7 @@ export fn start_higher_half() callconv(.Naked) noreturn {
// Get the multiboot header address and add the virtual offset // Get the multiboot header address and add the virtual offset
const mb_info_addr = asm ( const mb_info_addr = asm (
\\mov %%ebx, %[res] \\mov %%ebx, %[res]
: [res] "=r" (-> usize) : [res] "=r" (-> usize),
) + @ptrToInt(&KERNEL_ADDR_OFFSET); ) + @ptrToInt(&KERNEL_ADDR_OFFSET);
kmain(@intToPtr(arch.BootPayload, mb_info_addr)); kmain(@intToPtr(arch.BootPayload, mb_info_addr));
while (true) {} while (true) {}

View file

@ -3,8 +3,7 @@ const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const expectEqual = std.testing.expectEqual; const expectEqual = std.testing.expectEqual;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
/// The current year to be used for calculating the 4 digit year, as the CMOS return the last two /// The current year to be used for calculating the 4 digit year, as the CMOS return the last two
/// digits of the year. /// digits of the year.
@ -137,7 +136,7 @@ pub const RtcRegister = enum {
/// IN reg: u8 - The register index to select in the CMOS chip. /// IN reg: u8 - The register index to select in the CMOS chip.
/// IN comptime disable_nmi: bool - Whether to disable NMI when selecting a register. /// IN comptime disable_nmi: bool - Whether to disable NMI when selecting a register.
/// ///
fn selectRegister(reg: u8, comptime disable_nmi: bool) callconv(.Inline) void { inline fn selectRegister(reg: u8, comptime disable_nmi: bool) void {
if (disable_nmi) { if (disable_nmi) {
arch.out(ADDRESS, reg | NMI_BIT); arch.out(ADDRESS, reg | NMI_BIT);
} else { } else {
@ -151,7 +150,7 @@ fn selectRegister(reg: u8, comptime disable_nmi: bool) callconv(.Inline) void {
/// Arguments: /// Arguments:
/// IN data: u8 - The data to write to the selected register. /// IN data: u8 - The data to write to the selected register.
/// ///
fn writeRegister(data: u8) callconv(.Inline) void { inline fn writeRegister(data: u8) void {
arch.out(DATA, data); arch.out(DATA, data);
} }
@ -161,7 +160,7 @@ fn writeRegister(data: u8) callconv(.Inline) void {
/// Return: u8 /// Return: u8
/// The value in the selected register. /// The value in the selected register.
/// ///
fn readRegister() callconv(.Inline) u8 { inline fn readRegister() u8 {
return arch.in(u8, DATA); return arch.in(u8, DATA);
} }
@ -176,7 +175,7 @@ fn readRegister() callconv(.Inline) u8 {
/// Return: u8 /// Return: u8
/// The value in the selected register. /// The value in the selected register.
/// ///
fn selectAndReadRegister(reg: u8, comptime disable_nmi: bool) callconv(.Inline) u8 { inline fn selectAndReadRegister(reg: u8, comptime disable_nmi: bool) u8 {
selectRegister(reg, disable_nmi); selectRegister(reg, disable_nmi);
arch.ioWait(); arch.ioWait();
return readRegister(); return readRegister();
@ -191,7 +190,7 @@ fn selectAndReadRegister(reg: u8, comptime disable_nmi: bool) callconv(.Inline)
/// IN data: u8 - The data to write to the selected register. /// IN data: u8 - The data to write to the selected register.
/// IN comptime disable_nmi: bool - Whether to disable NMI when selecting a register. /// IN comptime disable_nmi: bool - Whether to disable NMI when selecting a register.
/// ///
fn selectAndWriteRegister(reg: u8, data: u8, comptime disable_nmi: bool) callconv(.Inline) void { inline fn selectAndWriteRegister(reg: u8, data: u8, comptime disable_nmi: bool) void {
selectRegister(reg, disable_nmi); selectRegister(reg, disable_nmi);
arch.ioWait(); arch.ioWait();
writeRegister(data); writeRegister(data);
@ -278,7 +277,7 @@ test "readRegister" {
const expected = @as(u8, 0x55); const expected = @as(u8, 0x55);
const actual = readRegister(); const actual = readRegister();
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "selectAndReadRegister NMI" { test "selectAndReadRegister NMI" {
@ -294,7 +293,7 @@ test "selectAndReadRegister NMI" {
const expected = @as(u8, 0x44); const expected = @as(u8, 0x44);
const actual = selectAndReadRegister(reg, false); const actual = selectAndReadRegister(reg, false);
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "selectAndReadRegister no NMI" { test "selectAndReadRegister no NMI" {
@ -310,7 +309,7 @@ test "selectAndReadRegister no NMI" {
const expected = @as(u8, 0x44); const expected = @as(u8, 0x44);
const actual = selectAndReadRegister(reg, true); const actual = selectAndReadRegister(reg, true);
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "selectAndWriteRegister NMI" { test "selectAndWriteRegister NMI" {
@ -364,7 +363,7 @@ test "readRtcRegister" {
const expected = @as(u8, 0x44); const expected = @as(u8, 0x44);
const actual = readRtcRegister(reg); const actual = readRtcRegister(reg);
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
} }
@ -389,7 +388,7 @@ test "readStatusRegister NMI" {
const expected = @as(u8, 0x78); const expected = @as(u8, 0x78);
const actual = readStatusRegister(reg, false); const actual = readStatusRegister(reg, false);
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
} }
@ -414,7 +413,7 @@ test "readStatusRegister no NMI" {
const expected = @as(u8, 0x78); const expected = @as(u8, 0x78);
const actual = readStatusRegister(reg, true); const actual = readStatusRegister(reg, true);
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
} }

View file

@ -6,8 +6,7 @@ const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
/// The access bits for a GDT entry. /// The access bits for a GDT entry.
const AccessBits = packed struct { const AccessBits = packed struct {
@ -427,73 +426,73 @@ pub fn init() void {
} }
fn mock_lgdt(ptr: *const GdtPtr) void { fn mock_lgdt(ptr: *const GdtPtr) void {
expectEqual(TABLE_SIZE, ptr.limit); expectEqual(TABLE_SIZE, ptr.limit) catch panic(null, "GDT pointer limit was not correct", .{});
expectEqual(@ptrToInt(&gdt_entries[0]), ptr.base); expectEqual(@ptrToInt(&gdt_entries[0]), ptr.base) catch panic(null, "GDT pointer base was not correct", .{});
} }
test "GDT entries" { test "GDT entries" {
expectEqual(@as(u32, 1), @sizeOf(AccessBits)); try expectEqual(@as(u32, 1), @sizeOf(AccessBits));
expectEqual(@as(u32, 1), @sizeOf(FlagBits)); try expectEqual(@as(u32, 1), @sizeOf(FlagBits));
expectEqual(@as(u32, 8), @sizeOf(GdtEntry)); try expectEqual(@as(u32, 8), @sizeOf(GdtEntry));
expectEqual(@as(u32, 104), @sizeOf(Tss)); try expectEqual(@as(u32, 104), @sizeOf(Tss));
expectEqual(@as(u32, 6), @sizeOf(GdtPtr)); try expectEqual(@as(u32, 6), @sizeOf(GdtPtr));
const null_entry = gdt_entries[NULL_INDEX]; const null_entry = gdt_entries[NULL_INDEX];
expectEqual(@as(u64, 0), @bitCast(u64, null_entry)); try expectEqual(@as(u64, 0), @bitCast(u64, null_entry));
const kernel_code_entry = gdt_entries[KERNEL_CODE_INDEX]; const kernel_code_entry = gdt_entries[KERNEL_CODE_INDEX];
expectEqual(@as(u64, 0xCF9A000000FFFF), @bitCast(u64, kernel_code_entry)); try expectEqual(@as(u64, 0xCF9A000000FFFF), @bitCast(u64, kernel_code_entry));
const kernel_data_entry = gdt_entries[KERNEL_DATA_INDEX]; const kernel_data_entry = gdt_entries[KERNEL_DATA_INDEX];
expectEqual(@as(u64, 0xCF92000000FFFF), @bitCast(u64, kernel_data_entry)); try expectEqual(@as(u64, 0xCF92000000FFFF), @bitCast(u64, kernel_data_entry));
const user_code_entry = gdt_entries[USER_CODE_INDEX]; const user_code_entry = gdt_entries[USER_CODE_INDEX];
expectEqual(@as(u64, 0xCFFA000000FFFF), @bitCast(u64, user_code_entry)); try expectEqual(@as(u64, 0xCFFA000000FFFF), @bitCast(u64, user_code_entry));
const user_data_entry = gdt_entries[USER_DATA_INDEX]; const user_data_entry = gdt_entries[USER_DATA_INDEX];
expectEqual(@as(u64, 0xCFF2000000FFFF), @bitCast(u64, user_data_entry)); try expectEqual(@as(u64, 0xCFF2000000FFFF), @bitCast(u64, user_data_entry));
const tss_entry = gdt_entries[TSS_INDEX]; const tss_entry = gdt_entries[TSS_INDEX];
expectEqual(@as(u64, 0), @bitCast(u64, tss_entry)); try expectEqual(@as(u64, 0), @bitCast(u64, tss_entry));
expectEqual(TABLE_SIZE, gdt_ptr.limit); try expectEqual(TABLE_SIZE, gdt_ptr.limit);
expectEqual(@as(u32, 0), main_tss_entry.prev_tss); try expectEqual(@as(u32, 0), main_tss_entry.prev_tss);
expectEqual(@as(u32, 0), main_tss_entry.esp0); try expectEqual(@as(u32, 0), main_tss_entry.esp0);
expectEqual(@as(u32, KERNEL_DATA_OFFSET), main_tss_entry.ss0); try expectEqual(@as(u32, KERNEL_DATA_OFFSET), main_tss_entry.ss0);
expectEqual(@as(u32, 0), main_tss_entry.esp1); try expectEqual(@as(u32, 0), main_tss_entry.esp1);
expectEqual(@as(u32, 0), main_tss_entry.ss1); try expectEqual(@as(u32, 0), main_tss_entry.ss1);
expectEqual(@as(u32, 0), main_tss_entry.esp2); try expectEqual(@as(u32, 0), main_tss_entry.esp2);
expectEqual(@as(u32, 0), main_tss_entry.ss2); try expectEqual(@as(u32, 0), main_tss_entry.ss2);
expectEqual(@as(u32, 0), main_tss_entry.cr3); try expectEqual(@as(u32, 0), main_tss_entry.cr3);
expectEqual(@as(u32, 0), main_tss_entry.eip); try expectEqual(@as(u32, 0), main_tss_entry.eip);
expectEqual(@as(u32, 0), main_tss_entry.eflags); try expectEqual(@as(u32, 0), main_tss_entry.eflags);
expectEqual(@as(u32, 0), main_tss_entry.eax); try expectEqual(@as(u32, 0), main_tss_entry.eax);
expectEqual(@as(u32, 0), main_tss_entry.ecx); try expectEqual(@as(u32, 0), main_tss_entry.ecx);
expectEqual(@as(u32, 0), main_tss_entry.edx); try expectEqual(@as(u32, 0), main_tss_entry.edx);
expectEqual(@as(u32, 0), main_tss_entry.ebx); try expectEqual(@as(u32, 0), main_tss_entry.ebx);
expectEqual(@as(u32, 0), main_tss_entry.esp); try expectEqual(@as(u32, 0), main_tss_entry.esp);
expectEqual(@as(u32, 0), main_tss_entry.ebp); try expectEqual(@as(u32, 0), main_tss_entry.ebp);
expectEqual(@as(u32, 0), main_tss_entry.esi); try expectEqual(@as(u32, 0), main_tss_entry.esi);
expectEqual(@as(u32, 0), main_tss_entry.edi); try expectEqual(@as(u32, 0), main_tss_entry.edi);
expectEqual(@as(u32, 0), main_tss_entry.es); try expectEqual(@as(u32, 0), main_tss_entry.es);
expectEqual(@as(u32, 0), main_tss_entry.cs); try expectEqual(@as(u32, 0), main_tss_entry.cs);
expectEqual(@as(u32, 0), main_tss_entry.ss); try expectEqual(@as(u32, 0), main_tss_entry.ss);
expectEqual(@as(u32, 0), main_tss_entry.ds); try expectEqual(@as(u32, 0), main_tss_entry.ds);
expectEqual(@as(u32, 0), main_tss_entry.fs); try expectEqual(@as(u32, 0), main_tss_entry.fs);
expectEqual(@as(u32, 0), main_tss_entry.gs); try expectEqual(@as(u32, 0), main_tss_entry.gs);
expectEqual(@as(u32, 0), main_tss_entry.ldtr); try expectEqual(@as(u32, 0), main_tss_entry.ldtr);
expectEqual(@as(u16, 0), main_tss_entry.trap); try expectEqual(@as(u16, 0), main_tss_entry.trap);
// Size of Tss will fit in a u16 as 104 < 65535 (2^16) // Size of Tss will fit in a u16 as 104 < 65535 (2^16)
expectEqual(@as(u16, @sizeOf(Tss)), main_tss_entry.io_permissions_base_offset); try expectEqual(@as(u16, @sizeOf(Tss)), main_tss_entry.io_permissions_base_offset);
} }
test "makeGdtEntry NULL" { test "makeGdtEntry NULL" {
const actual = makeGdtEntry(0, 0, NULL_SEGMENT, NULL_FLAGS); const actual = makeGdtEntry(0, 0, NULL_SEGMENT, NULL_FLAGS);
const expected: u64 = 0; const expected: u64 = 0;
expectEqual(expected, @bitCast(u64, actual)); try expectEqual(expected, @bitCast(u64, actual));
} }
test "makeGdtEntry alternating bit pattern" { test "makeGdtEntry alternating bit pattern" {
@ -507,7 +506,7 @@ test "makeGdtEntry alternating bit pattern" {
.present = 0, .present = 0,
}; };
expectEqual(@as(u8, 0b01010101), @bitCast(u8, alt_access)); try expectEqual(@as(u8, 0b01010101), @bitCast(u8, alt_access));
const alt_flag = FlagBits{ const alt_flag = FlagBits{
.reserved_zero = 1, .reserved_zero = 1,
@ -516,12 +515,12 @@ test "makeGdtEntry alternating bit pattern" {
.granularity = 0, .granularity = 0,
}; };
expectEqual(@as(u4, 0b0101), @bitCast(u4, alt_flag)); try expectEqual(@as(u4, 0b0101), @bitCast(u4, alt_flag));
const actual = makeGdtEntry(0b01010101010101010101010101010101, 0b01010101010101010101, alt_access, alt_flag); const actual = makeGdtEntry(0b01010101010101010101010101010101, 0b01010101010101010101, alt_access, alt_flag);
const expected: u64 = 0b0101010101010101010101010101010101010101010101010101010101010101; const expected: u64 = 0b0101010101010101010101010101010101010101010101010101010101010101;
expectEqual(expected, @bitCast(u64, actual)); try expectEqual(expected, @bitCast(u64, actual));
} }
test "init" { test "init" {
@ -549,7 +548,7 @@ test "init" {
// Flags are zero // Flags are zero
expected |= @as(u64, @truncate(u8, tss_addr >> 24)) << (16 + 24 + 8 + 4 + 4); expected |= @as(u64, @truncate(u8, tss_addr >> 24)) << (16 + 24 + 8 + 4 + 4);
expectEqual(expected, @bitCast(u64, tss_entry)); try expectEqual(expected, @bitCast(u64, tss_entry));
// Reset // Reset
gdt_ptr.base = 0; gdt_ptr.base = 0;

View file

@ -7,9 +7,8 @@ const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const gdt = if (is_test) @import("../../../../test/mock/kernel/gdt_mock.zig") else @import("gdt.zig");
const gdt = if (is_test) @import(mock_path ++ "gdt_mock.zig") else @import("gdt.zig"); const arch = if (builtin.is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
/// The structure that contains all the information that each IDT entry needs. /// The structure that contains all the information that each IDT entry needs.
pub const IdtEntry = packed struct { pub const IdtEntry = packed struct {
@ -196,15 +195,15 @@ fn testHandler0() callconv(.Naked) void {}
fn testHandler1() callconv(.Naked) void {} fn testHandler1() callconv(.Naked) void {}
fn mock_lidt(ptr: *const IdtPtr) void { fn mock_lidt(ptr: *const IdtPtr) void {
expectEqual(TABLE_SIZE, ptr.limit); expectEqual(TABLE_SIZE, ptr.limit) catch panic(null, "IDT pointer limit was not correct", .{});
expectEqual(@ptrToInt(&idt_entries[0]), ptr.base); expectEqual(@ptrToInt(&idt_entries[0]), ptr.base) catch panic(null, "IDT pointer base was not correct", .{});
} }
test "IDT entries" { test "IDT entries" {
expectEqual(@as(u32, 8), @sizeOf(IdtEntry)); try expectEqual(@as(u32, 8), @sizeOf(IdtEntry));
expectEqual(@as(u32, 6), @sizeOf(IdtPtr)); try expectEqual(@as(u32, 6), @sizeOf(IdtPtr));
expectEqual(TABLE_SIZE, idt_ptr.limit); try expectEqual(TABLE_SIZE, idt_ptr.limit);
expectEqual(@as(u32, 0), idt_ptr.base); try expectEqual(@as(u32, 0), idt_ptr.base);
} }
test "makeEntry alternating bit pattern" { test "makeEntry alternating bit pattern" {
@ -212,7 +211,7 @@ test "makeEntry alternating bit pattern" {
const expected: u64 = 0b0101010101010101101001010000000001010101010101010101010101010101; const expected: u64 = 0b0101010101010101101001010000000001010101010101010101010101010101;
expectEqual(expected, @bitCast(u64, actual)); try expectEqual(expected, @bitCast(u64, actual));
} }
test "isIdtOpen" { test "isIdtOpen" {
@ -238,17 +237,16 @@ test "isIdtOpen" {
.base_high = 0, .base_high = 0,
}; };
expectEqual(false, isIdtOpen(not_open)); try expectEqual(false, isIdtOpen(not_open));
expectEqual(true, isIdtOpen(open)); try expectEqual(true, isIdtOpen(open));
} }
test "openInterruptGate" { test "openInterruptGate" {
const index: u8 = 100; const index: u8 = 100;
openInterruptGate(index, testHandler0) catch unreachable; openInterruptGate(index, testHandler0) catch unreachable;
expectError(IdtError.IdtEntryExists, openInterruptGate(index, testHandler0)); try expectError(IdtError.IdtEntryExists, openInterruptGate(index, testHandler0));
const test_fn_0_addr = @ptrToInt(testHandler0); const test_fn_0_addr = @ptrToInt(testHandler0);
const test_fn_1_addr = @ptrToInt(testHandler1);
const expected_entry0 = IdtEntry{ const expected_entry0 = IdtEntry{
.base_low = @truncate(u16, test_fn_0_addr), .base_low = @truncate(u16, test_fn_0_addr),
@ -261,7 +259,7 @@ test "openInterruptGate" {
.base_high = @truncate(u16, test_fn_0_addr >> 16), .base_high = @truncate(u16, test_fn_0_addr >> 16),
}; };
expectEqual(expected_entry0, idt_entries[index]); try expectEqual(expected_entry0, idt_entries[index]);
// Reset // Reset
idt_entries[index] = IdtEntry{ idt_entries[index] = IdtEntry{
@ -277,7 +275,7 @@ test "openInterruptGate" {
openInterruptGate(index, testHandler0) catch unreachable; openInterruptGate(index, testHandler0) catch unreachable;
// With different handler // With different handler
expectError(IdtError.IdtEntryExists, openInterruptGate(index, testHandler1)); try expectError(IdtError.IdtEntryExists, openInterruptGate(index, testHandler1));
const expected_entry1 = IdtEntry{ const expected_entry1 = IdtEntry{
.base_low = @truncate(u16, test_fn_0_addr), .base_low = @truncate(u16, test_fn_0_addr),
@ -290,7 +288,7 @@ test "openInterruptGate" {
.base_high = @truncate(u16, test_fn_0_addr >> 16), .base_high = @truncate(u16, test_fn_0_addr >> 16),
}; };
expectEqual(expected_entry1, idt_entries[index]); try expectEqual(expected_entry1, idt_entries[index]);
// Reset // Reset
idt_entries[index] = IdtEntry{ idt_entries[index] = IdtEntry{
@ -316,7 +314,7 @@ test "init" {
init(); init();
// Post testing // Post testing
expectEqual(@ptrToInt(&idt_entries), idt_ptr.base); try expectEqual(@ptrToInt(&idt_entries), idt_ptr.base);
// Reset // Reset
idt_ptr.base = 0; idt_ptr.base = 0;

View file

@ -99,7 +99,7 @@ pub fn getInterruptStub(comptime interrupt_num: u32) idt.InterruptHandler {
\\ pushl %[nr] \\ pushl %[nr]
\\ jmp commonStub \\ jmp commonStub
: :
: [nr] "n" (interrupt_num) : [nr] "n" (interrupt_num),
); );
} }
}.func; }.func;

View file

@ -7,10 +7,9 @@ const expectError = std.testing.expectError;
const log = std.log.scoped(.x86_irq); const log = std.log.scoped(.x86_irq);
const build_options = @import("build_options"); const build_options = @import("build_options");
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const mock_path = build_options.arch_mock_path; const idt = if (is_test) @import("../../../../test/mock/kernel/idt_mock.zig") else @import("idt.zig");
const idt = if (is_test) @import(mock_path ++ "idt_mock.zig") else @import("idt.zig"); const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig"); const pic = if (is_test) @import("../../../../test/mock/kernel/pic_mock.zig") else @import("pic.zig");
const pic = if (is_test) @import(mock_path ++ "pic_mock.zig") else @import("pic.zig");
const interrupts = @import("interrupts.zig"); const interrupts = @import("interrupts.zig");
/// The error set for the IRQ. This will be from installing a IRQ handler. /// The error set for the IRQ. This will be from installing a IRQ handler.
@ -146,10 +145,16 @@ pub fn init() void {
} }
fn testFunction0() callconv(.Naked) void {} fn testFunction0() callconv(.Naked) void {}
fn testFunction1(ctx: *arch.CpuState) u32 { fn testFunction1(ctx: *arch.CpuState) u32 {
// Suppress unused variable warnings
_ = ctx;
return 0; return 0;
} }
fn testFunction2(ctx: *arch.CpuState) u32 { fn testFunction2(ctx: *arch.CpuState) u32 {
// Suppress unused variable warnings
_ = ctx;
return 0; return 0;
} }
@ -169,10 +174,10 @@ test "openIrq" {
test "isValidIrq" { test "isValidIrq" {
comptime var i = 0; comptime var i = 0;
inline while (i < NUMBER_OF_ENTRIES) : (i += 1) { inline while (i < NUMBER_OF_ENTRIES) : (i += 1) {
expect(isValidIrq(i)); try expect(isValidIrq(i));
} }
expect(!isValidIrq(200)); try expect(!isValidIrq(200));
} }
test "registerIrq re-register irq handler" { test "registerIrq re-register irq handler" {
@ -184,19 +189,19 @@ test "registerIrq re-register irq handler" {
// Pre testing // Pre testing
for (irq_handlers) |h| { for (irq_handlers) |h| {
expect(null == h); try expect(null == h);
} }
// Call function // Call function
try registerIrq(0, testFunction1); try registerIrq(0, testFunction1);
expectError(IrqError.IrqExists, registerIrq(0, testFunction2)); try expectError(IrqError.IrqExists, registerIrq(0, testFunction2));
// Post testing // Post testing
for (irq_handlers) |h, i| { for (irq_handlers) |h, i| {
if (i != 0) { if (i != 0) {
expect(null == h); try expect(null == h);
} else { } else {
expectEqual(testFunction1, h.?); try expectEqual(testFunction1, h.?);
} }
} }
@ -213,7 +218,7 @@ test "registerIrq register irq handler" {
// Pre testing // Pre testing
for (irq_handlers) |h| { for (irq_handlers) |h| {
expect(null == h); try expect(null == h);
} }
// Call function // Call function
@ -222,9 +227,9 @@ test "registerIrq register irq handler" {
// Post testing // Post testing
for (irq_handlers) |h, i| { for (irq_handlers) |h, i| {
if (i != 0) { if (i != 0) {
expect(null == h); try expect(null == h);
} else { } else {
expectEqual(testFunction1, h.?); try expectEqual(testFunction1, h.?);
} }
} }
@ -233,7 +238,7 @@ test "registerIrq register irq handler" {
} }
test "registerIrq invalid irq index" { test "registerIrq invalid irq index" {
expectError(IrqError.InvalidIrq, registerIrq(200, testFunction1)); try expectError(IrqError.InvalidIrq, registerIrq(200, testFunction1));
} }
/// ///

View file

@ -6,11 +6,10 @@ const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError; const expectError = std.testing.expectError;
const log = std.log.scoped(.x86_isr); const log = std.log.scoped(.x86_isr);
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path;
const syscalls = @import("syscalls.zig"); const syscalls = @import("syscalls.zig");
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const idt = if (is_test) @import(mock_path ++ "idt_mock.zig") else @import("idt.zig"); const idt = if (is_test) @import("../../../../test/mock/kernel/idt_mock.zig") else @import("idt.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig"); const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const interrupts = @import("interrupts.zig"); const interrupts = @import("interrupts.zig");
/// The error set for the ISR. This will be from installing a ISR handler. /// The error set for the ISR. This will be from installing a ISR handler.
@ -256,15 +255,23 @@ pub fn init() void {
fn testFunction0() callconv(.Naked) void {} fn testFunction0() callconv(.Naked) void {}
fn testFunction1(ctx: *arch.CpuState) u32 { fn testFunction1(ctx: *arch.CpuState) u32 {
// Suppress unused var warning
_ = ctx;
return 0; return 0;
} }
fn testFunction2(ctx: *arch.CpuState) u32 { fn testFunction2(ctx: *arch.CpuState) u32 {
// Suppress unused var warning
_ = ctx;
return 0; return 0;
} }
fn testFunction3(ctx: *arch.CpuState) u32 { fn testFunction3(ctx: *arch.CpuState) u32 {
// Suppress unused var warning
_ = ctx;
return 0; return 0;
} }
fn testFunction4(ctx: *arch.CpuState) u32 { fn testFunction4(ctx: *arch.CpuState) u32 {
// Suppress unused var warning
_ = ctx;
return 0; return 0;
} }
@ -284,24 +291,24 @@ test "openIsr" {
test "isValidIsr" { test "isValidIsr" {
comptime var i = 0; comptime var i = 0;
inline while (i < NUMBER_OF_ENTRIES) : (i += 1) { inline while (i < NUMBER_OF_ENTRIES) : (i += 1) {
expectEqual(true, isValidIsr(i)); try expectEqual(true, isValidIsr(i));
} }
expect(isValidIsr(syscalls.INTERRUPT)); try expect(isValidIsr(syscalls.INTERRUPT));
expect(!isValidIsr(200)); try expect(!isValidIsr(200));
} }
test "registerIsr re-register syscall handler" { test "registerIsr re-register syscall handler" {
// Pre testing // Pre testing
expect(null == syscall_handler); try expect(null == syscall_handler);
// Call function // Call function
try registerIsr(syscalls.INTERRUPT, testFunction3); try registerIsr(syscalls.INTERRUPT, testFunction3);
expectError(IsrError.IsrExists, registerIsr(syscalls.INTERRUPT, testFunction4)); try expectError(IsrError.IsrExists, registerIsr(syscalls.INTERRUPT, testFunction4));
// Post testing // Post testing
expectEqual(testFunction3, syscall_handler.?); try expectEqual(testFunction3, syscall_handler.?);
// Clean up // Clean up
syscall_handler = null; syscall_handler = null;
@ -309,13 +316,13 @@ test "registerIsr re-register syscall handler" {
test "registerIsr register syscall handler" { test "registerIsr register syscall handler" {
// Pre testing // Pre testing
expect(null == syscall_handler); try expect(null == syscall_handler);
// Call function // Call function
try registerIsr(syscalls.INTERRUPT, testFunction3); try registerIsr(syscalls.INTERRUPT, testFunction3);
// Post testing // Post testing
expectEqual(testFunction3, syscall_handler.?); try expectEqual(testFunction3, syscall_handler.?);
// Clean up // Clean up
syscall_handler = null; syscall_handler = null;
@ -324,19 +331,19 @@ test "registerIsr register syscall handler" {
test "registerIsr re-register isr handler" { test "registerIsr re-register isr handler" {
// Pre testing // Pre testing
for (isr_handlers) |h| { for (isr_handlers) |h| {
expect(null == h); try expect(null == h);
} }
// Call function // Call function
try registerIsr(0, testFunction1); try registerIsr(0, testFunction1);
expectError(IsrError.IsrExists, registerIsr(0, testFunction2)); try expectError(IsrError.IsrExists, registerIsr(0, testFunction2));
// Post testing // Post testing
for (isr_handlers) |h, i| { for (isr_handlers) |h, i| {
if (i != 0) { if (i != 0) {
expect(null == h); try expect(null == h);
} else { } else {
expectEqual(testFunction1, h.?); try expectEqual(testFunction1, h.?);
} }
} }
@ -347,7 +354,7 @@ test "registerIsr re-register isr handler" {
test "registerIsr register isr handler" { test "registerIsr register isr handler" {
// Pre testing // Pre testing
for (isr_handlers) |h| { for (isr_handlers) |h| {
expect(null == h); try expect(null == h);
} }
// Call function // Call function
@ -356,9 +363,9 @@ test "registerIsr register isr handler" {
// Post testing // Post testing
for (isr_handlers) |h, i| { for (isr_handlers) |h, i| {
if (i != 0) { if (i != 0) {
expect(null == h); try expect(null == h);
} else { } else {
expectEqual(testFunction1, h.?); try expectEqual(testFunction1, h.?);
} }
} }
@ -367,7 +374,7 @@ test "registerIsr register isr handler" {
} }
test "registerIsr invalid isr index" { test "registerIsr invalid isr index" {
expectError(IsrError.InvalidIsr, registerIsr(200, testFunction1)); try expectError(IsrError.InvalidIsr, registerIsr(200, testFunction1));
} }
/// ///

View file

@ -6,7 +6,7 @@ const testing = std.testing;
const log = std.log.scoped(.x86_keyboard); const log = std.log.scoped(.x86_keyboard);
const irq = @import("irq.zig"); const irq = @import("irq.zig");
const pic = @import("pic.zig"); const pic = @import("pic.zig");
const arch = if (builtin.is_test) @import(build_options.arch_mock_path ++ "arch_mock.zig") else @import("arch.zig"); const arch = if (builtin.is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const kb = @import("../../keyboard.zig"); const kb = @import("../../keyboard.zig");
const Keyboard = kb.Keyboard; const Keyboard = kb.Keyboard;
@ -164,7 +164,7 @@ fn onKeyEvent(ctx: *arch.CpuState) usize {
const scan_code = readKeyboardBuffer(); const scan_code = readKeyboardBuffer();
if (parseScanCode(scan_code)) |action| { if (parseScanCode(scan_code)) |action| {
if (!keyboard.writeKey(action)) { if (!keyboard.writeKey(action)) {
log.notice("No room for keyboard action {}\n", .{action}); log.warn("No room for keyboard action {}\n", .{action});
} }
} }
return @ptrToInt(ctx); return @ptrToInt(ctx);
@ -174,7 +174,7 @@ fn onKeyEvent(ctx: *arch.CpuState) usize {
/// Initialise the PS/2 keyboard /// Initialise the PS/2 keyboard
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - The allocator to use to create the keyboard instance /// IN allocator: Allocator - The allocator to use to create the keyboard instance
/// ///
/// Return: *Keyboard /// Return: *Keyboard
/// The keyboard created /// The keyboard created
@ -182,7 +182,7 @@ fn onKeyEvent(ctx: *arch.CpuState) usize {
/// Error: std.mem.Allocator.Error /// Error: std.mem.Allocator.Error
/// OutOfMemory - There isn't enough memory to allocate the keyboard instance /// OutOfMemory - There isn't enough memory to allocate the keyboard instance
/// ///
pub fn init(allocator: *Allocator) Allocator.Error!*Keyboard { pub fn init(allocator: Allocator) Allocator.Error!*Keyboard {
irq.registerIrq(pic.IRQ_KEYBOARD, onKeyEvent) catch |e| { irq.registerIrq(pic.IRQ_KEYBOARD, onKeyEvent) catch |e| {
panic(@errorReturnTrace(), "Failed to register keyboard IRQ: {}\n", .{e}); panic(@errorReturnTrace(), "Failed to register keyboard IRQ: {}\n", .{e});
}; };
@ -297,23 +297,23 @@ test "parseScanCode" {
var res = parseScanCode(scan_code); var res = parseScanCode(scan_code);
if (key) |k| { if (key) |k| {
const r = res orelse unreachable; const r = res orelse unreachable;
testing.expectEqual(k, r.position); try testing.expectEqual(k, r.position);
testing.expectEqual(false, r.released); try testing.expectEqual(false, r.released);
testing.expectEqual(pressed_keys, 1); try testing.expectEqual(pressed_keys, 1);
} }
testing.expectEqual(on_print_screen, false); try testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, false); try testing.expectEqual(special_sequence, false);
testing.expectEqual(expected_releases, 0); try testing.expectEqual(expected_releases, 0);
// Test release scan code for key // Test release scan code for key
if (key) |k| { if (key) |k| {
res = parseScanCode(scan_code | 128); res = parseScanCode(scan_code | 128);
const r = res orelse unreachable; const r = res orelse unreachable;
testing.expectEqual(k, r.position); try testing.expectEqual(k, r.position);
testing.expectEqual(true, r.released); try testing.expectEqual(true, r.released);
testing.expectEqual(pressed_keys, 0); try testing.expectEqual(pressed_keys, 0);
testing.expectEqual(on_print_screen, false); try testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, false); try testing.expectEqual(special_sequence, false);
testing.expectEqual(expected_releases, 0); try testing.expectEqual(expected_releases, 0);
} }
scan_code += 1; scan_code += 1;
} }
@ -338,32 +338,32 @@ test "parseScanCode" {
}; };
const simple_special_codes = &[_]u8{ 72, 75, 77, 80, 82, 71, 73, 83, 79, 81, 53, 28, 56, 91 }; const simple_special_codes = &[_]u8{ 72, 75, 77, 80, 82, 71, 73, 83, 79, 81, 53, 28, 56, 91 };
for (simple_special_keys) |key, i| { for (simple_special_keys) |key, i| {
testing.expectEqual(parseScanCode(128), null); try testing.expectEqual(parseScanCode(128), null);
testing.expectEqual(pressed_keys, 0); try testing.expectEqual(pressed_keys, 0);
testing.expectEqual(on_print_screen, false); try testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, true); try testing.expectEqual(special_sequence, true);
testing.expectEqual(expected_releases, 0); try testing.expectEqual(expected_releases, 0);
var res = parseScanCode(simple_special_codes[i]) orelse unreachable; var res = parseScanCode(simple_special_codes[i]) orelse unreachable;
testing.expectEqual(false, res.released); try testing.expectEqual(false, res.released);
testing.expectEqual(key, res.position); try testing.expectEqual(key, res.position);
testing.expectEqual(pressed_keys, 1); try testing.expectEqual(pressed_keys, 1);
testing.expectEqual(on_print_screen, false); try testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, true); try testing.expectEqual(special_sequence, true);
testing.expectEqual(expected_releases, 1); try testing.expectEqual(expected_releases, 1);
testing.expectEqual(parseScanCode(128), null); try testing.expectEqual(parseScanCode(128), null);
testing.expectEqual(pressed_keys, 1); try testing.expectEqual(pressed_keys, 1);
testing.expectEqual(on_print_screen, false); try testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, true); try testing.expectEqual(special_sequence, true);
testing.expectEqual(expected_releases, 0); try testing.expectEqual(expected_releases, 0);
res = parseScanCode(simple_special_codes[i] | 128) orelse unreachable; res = parseScanCode(simple_special_codes[i] | 128) orelse unreachable;
testing.expectEqual(true, res.released); try testing.expectEqual(true, res.released);
testing.expectEqual(key, res.position); try testing.expectEqual(key, res.position);
testing.expectEqual(pressed_keys, 0); try testing.expectEqual(pressed_keys, 0);
testing.expectEqual(on_print_screen, false); try testing.expectEqual(on_print_screen, false);
testing.expectEqual(special_sequence, false); try testing.expectEqual(special_sequence, false);
testing.expectEqual(expected_releases, 0); try testing.expectEqual(expected_releases, 0);
} }
} }

View file

@ -1,3 +1,52 @@
pub const __builtin_bswap16 = @import("std").zig.c_builtins.__builtin_bswap16;
pub const __builtin_bswap32 = @import("std").zig.c_builtins.__builtin_bswap32;
pub const __builtin_bswap64 = @import("std").zig.c_builtins.__builtin_bswap64;
pub const __builtin_signbit = @import("std").zig.c_builtins.__builtin_signbit;
pub const __builtin_signbitf = @import("std").zig.c_builtins.__builtin_signbitf;
pub const __builtin_popcount = @import("std").zig.c_builtins.__builtin_popcount;
pub const __builtin_ctz = @import("std").zig.c_builtins.__builtin_ctz;
pub const __builtin_clz = @import("std").zig.c_builtins.__builtin_clz;
pub const __builtin_sqrt = @import("std").zig.c_builtins.__builtin_sqrt;
pub const __builtin_sqrtf = @import("std").zig.c_builtins.__builtin_sqrtf;
pub const __builtin_sin = @import("std").zig.c_builtins.__builtin_sin;
pub const __builtin_sinf = @import("std").zig.c_builtins.__builtin_sinf;
pub const __builtin_cos = @import("std").zig.c_builtins.__builtin_cos;
pub const __builtin_cosf = @import("std").zig.c_builtins.__builtin_cosf;
pub const __builtin_exp = @import("std").zig.c_builtins.__builtin_exp;
pub const __builtin_expf = @import("std").zig.c_builtins.__builtin_expf;
pub const __builtin_exp2 = @import("std").zig.c_builtins.__builtin_exp2;
pub const __builtin_exp2f = @import("std").zig.c_builtins.__builtin_exp2f;
pub const __builtin_log = @import("std").zig.c_builtins.__builtin_log;
pub const __builtin_logf = @import("std").zig.c_builtins.__builtin_logf;
pub const __builtin_log2 = @import("std").zig.c_builtins.__builtin_log2;
pub const __builtin_log2f = @import("std").zig.c_builtins.__builtin_log2f;
pub const __builtin_log10 = @import("std").zig.c_builtins.__builtin_log10;
pub const __builtin_log10f = @import("std").zig.c_builtins.__builtin_log10f;
pub const __builtin_abs = @import("std").zig.c_builtins.__builtin_abs;
pub const __builtin_fabs = @import("std").zig.c_builtins.__builtin_fabs;
pub const __builtin_fabsf = @import("std").zig.c_builtins.__builtin_fabsf;
pub const __builtin_floor = @import("std").zig.c_builtins.__builtin_floor;
pub const __builtin_floorf = @import("std").zig.c_builtins.__builtin_floorf;
pub const __builtin_ceil = @import("std").zig.c_builtins.__builtin_ceil;
pub const __builtin_ceilf = @import("std").zig.c_builtins.__builtin_ceilf;
pub const __builtin_trunc = @import("std").zig.c_builtins.__builtin_trunc;
pub const __builtin_truncf = @import("std").zig.c_builtins.__builtin_truncf;
pub const __builtin_round = @import("std").zig.c_builtins.__builtin_round;
pub const __builtin_roundf = @import("std").zig.c_builtins.__builtin_roundf;
pub const __builtin_strlen = @import("std").zig.c_builtins.__builtin_strlen;
pub const __builtin_strcmp = @import("std").zig.c_builtins.__builtin_strcmp;
pub const __builtin_object_size = @import("std").zig.c_builtins.__builtin_object_size;
pub const __builtin___memset_chk = @import("std").zig.c_builtins.__builtin___memset_chk;
pub const __builtin_memset = @import("std").zig.c_builtins.__builtin_memset;
pub const __builtin___memcpy_chk = @import("std").zig.c_builtins.__builtin___memcpy_chk;
pub const __builtin_memcpy = @import("std").zig.c_builtins.__builtin_memcpy;
pub const __builtin_expect = @import("std").zig.c_builtins.__builtin_expect;
pub const __builtin_nanf = @import("std").zig.c_builtins.__builtin_nanf;
pub const __builtin_huge_valf = @import("std").zig.c_builtins.__builtin_huge_valf;
pub const __builtin_inff = @import("std").zig.c_builtins.__builtin_inff;
pub const __builtin_isnan = @import("std").zig.c_builtins.__builtin_isnan;
pub const __builtin_isinf = @import("std").zig.c_builtins.__builtin_isinf;
pub const __builtin_isinf_sign = @import("std").zig.c_builtins.__builtin_isinf_sign;
pub const multiboot_uint8_t = u8; pub const multiboot_uint8_t = u8;
pub const multiboot_uint16_t = c_ushort; pub const multiboot_uint16_t = c_ushort;
pub const multiboot_uint32_t = c_uint; pub const multiboot_uint32_t = c_uint;
@ -30,6 +79,26 @@ pub const struct_multiboot_elf_section_header_table = extern struct {
shndx: multiboot_uint32_t, shndx: multiboot_uint32_t,
}; };
pub const multiboot_elf_section_header_table_t = struct_multiboot_elf_section_header_table; pub const multiboot_elf_section_header_table_t = struct_multiboot_elf_section_header_table;
const union_unnamed_1 = extern union {
aout_sym: multiboot_aout_symbol_table_t,
elf_sec: multiboot_elf_section_header_table_t,
};
const struct_unnamed_3 = extern struct {
framebuffer_palette_addr: multiboot_uint32_t,
framebuffer_palette_num_colors: multiboot_uint16_t,
};
const struct_unnamed_4 = extern struct {
framebuffer_red_field_position: multiboot_uint8_t,
framebuffer_red_mask_size: multiboot_uint8_t,
framebuffer_green_field_position: multiboot_uint8_t,
framebuffer_green_mask_size: multiboot_uint8_t,
framebuffer_blue_field_position: multiboot_uint8_t,
framebuffer_blue_mask_size: multiboot_uint8_t,
};
const union_unnamed_2 = extern union {
unnamed_0: struct_unnamed_3,
unnamed_1: struct_unnamed_4,
};
pub const struct_multiboot_info = extern struct { pub const struct_multiboot_info = extern struct {
flags: multiboot_uint32_t, flags: multiboot_uint32_t,
mem_lower: multiboot_uint32_t, mem_lower: multiboot_uint32_t,
@ -38,10 +107,7 @@ pub const struct_multiboot_info = extern struct {
cmdline: multiboot_uint32_t, cmdline: multiboot_uint32_t,
mods_count: multiboot_uint32_t, mods_count: multiboot_uint32_t,
mods_addr: multiboot_uint32_t, mods_addr: multiboot_uint32_t,
u: extern union { u: union_unnamed_1,
aout_sym: multiboot_aout_symbol_table_t,
elf_sec: multiboot_elf_section_header_table_t,
},
mmap_length: multiboot_uint32_t, mmap_length: multiboot_uint32_t,
mmap_addr: multiboot_uint32_t, mmap_addr: multiboot_uint32_t,
drives_length: multiboot_uint32_t, drives_length: multiboot_uint32_t,
@ -61,20 +127,7 @@ pub const struct_multiboot_info = extern struct {
framebuffer_height: multiboot_uint32_t, framebuffer_height: multiboot_uint32_t,
framebuffer_bpp: multiboot_uint8_t, framebuffer_bpp: multiboot_uint8_t,
framebuffer_type: multiboot_uint8_t, framebuffer_type: multiboot_uint8_t,
framebuffer: extern union { unnamed_0: union_unnamed_2,
framebuffer_palette: extern struct {
framebuffer_palette_addr: multiboot_uint32_t,
framebuffer_palette_num_colors: multiboot_uint16_t,
},
framebuffer_colours: extern struct {
framebuffer_red_field_position: multiboot_uint8_t,
framebuffer_red_mask_size: multiboot_uint8_t,
framebuffer_green_field_position: multiboot_uint8_t,
framebuffer_green_mask_size: multiboot_uint8_t,
framebuffer_blue_field_position: multiboot_uint8_t,
framebuffer_blue_mask_size: multiboot_uint8_t,
},
},
}; };
pub const multiboot_info_t = struct_multiboot_info; pub const multiboot_info_t = struct_multiboot_info;
pub const struct_multiboot_color = extern struct { pub const struct_multiboot_color = extern struct {
@ -82,7 +135,7 @@ pub const struct_multiboot_color = extern struct {
green: multiboot_uint8_t, green: multiboot_uint8_t,
blue: multiboot_uint8_t, blue: multiboot_uint8_t,
}; };
pub const struct_multiboot_mmap_entry = extern struct { pub const struct_multiboot_mmap_entry = packed struct {
size: multiboot_uint32_t, size: multiboot_uint32_t,
addr: multiboot_uint64_t, addr: multiboot_uint64_t,
len: multiboot_uint64_t, len: multiboot_uint64_t,
@ -107,376 +160,416 @@ pub const struct_multiboot_apm_info = extern struct {
cseg_16_len: multiboot_uint16_t, cseg_16_len: multiboot_uint16_t,
dseg_len: multiboot_uint16_t, dseg_len: multiboot_uint16_t,
}; };
pub const __GCC_ATOMIC_TEST_AND_SET_TRUEVAL = 1; pub const __INTMAX_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `L`"); // (no file):67:9
pub const __BIGGEST_ALIGNMENT__ = 16; pub const __UINTMAX_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `UL`"); // (no file):73:9
pub const __SIZEOF_FLOAT__ = 4; pub const __INT64_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `L`"); // (no file):164:9
pub const __INT64_FMTd__ = "ld"; pub const __UINT32_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `U`"); // (no file):186:9
pub const __STDC_VERSION__ = @as(c_long, 201112); pub const __UINT64_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `UL`"); // (no file):194:9
pub const __INT_LEAST32_FMTi__ = "i"; pub const __seg_gs = @compileError("unable to translate macro: undefined identifier `__attribute__`"); // (no file):312:9
pub const __tune_znver1__ = 1; pub const __seg_fs = @compileError("unable to translate macro: undefined identifier `__attribute__`"); // (no file):313:9
pub const __INT_LEAST8_FMTi__ = "hhi"; pub const __llvm__ = @as(c_int, 1);
pub const __LDBL_EPSILON__ = 0.000000; pub const __clang__ = @as(c_int, 1);
pub const __LZCNT__ = 1; pub const __clang_major__ = @as(c_int, 13);
pub const __INT_LEAST32_FMTd__ = "d"; pub const __clang_minor__ = @as(c_int, 0);
pub const __STDC_UTF_32__ = 1; pub const __clang_patchlevel__ = @as(c_int, 0);
pub const __SIG_ATOMIC_WIDTH__ = 32; pub const __clang_version__ = "13.0.0 (git@github.com:llvm/llvm-project d7b669b3a30345cfcdb2fde2af6f48aa4b94845d)";
pub const MULTIBOOT_MEMORY_BADRAM = 5; pub const __GNUC__ = @as(c_int, 4);
pub const __UINT_FAST64_FMTX__ = "lX"; pub const __GNUC_MINOR__ = @as(c_int, 2);
pub const __GCC_ATOMIC_LLONG_LOCK_FREE = 2; pub const __GNUC_PATCHLEVEL__ = @as(c_int, 1);
pub const __SEG_FS = 1; pub const __GXX_ABI_VERSION = @as(c_int, 1002);
pub const __clang_version__ = "9.0.0 (tags/RELEASE_900/final)"; pub const __ATOMIC_RELAXED = @as(c_int, 0);
pub const __UINT_LEAST8_FMTo__ = "hho"; pub const __ATOMIC_CONSUME = @as(c_int, 1);
pub const __GCC_ASM_FLAG_OUTPUTS__ = 1; pub const __ATOMIC_ACQUIRE = @as(c_int, 2);
pub const __SIZEOF_DOUBLE__ = 8; pub const __ATOMIC_RELEASE = @as(c_int, 3);
pub const __INTMAX_FMTd__ = "ld"; pub const __ATOMIC_ACQ_REL = @as(c_int, 4);
pub const __CLANG_ATOMIC_CHAR_LOCK_FREE = 2; pub const __ATOMIC_SEQ_CST = @as(c_int, 5);
pub const __INT_LEAST16_FMTi__ = "hi"; pub const __OPENCL_MEMORY_SCOPE_WORK_ITEM = @as(c_int, 0);
pub const __GCC_ATOMIC_SHORT_LOCK_FREE = 2; pub const __OPENCL_MEMORY_SCOPE_WORK_GROUP = @as(c_int, 1);
pub const __FMA__ = 1; pub const __OPENCL_MEMORY_SCOPE_DEVICE = @as(c_int, 2);
pub const __MMX__ = 1; pub const __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES = @as(c_int, 3);
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 = 1; pub const __OPENCL_MEMORY_SCOPE_SUB_GROUP = @as(c_int, 4);
pub const __SIZE_FMTX__ = "lX"; pub const __PRAGMA_REDEFINE_EXTNAME = @as(c_int, 1);
pub const __RDSEED__ = 1; pub const __VERSION__ = "Clang 13.0.0 (git@github.com:llvm/llvm-project d7b669b3a30345cfcdb2fde2af6f48aa4b94845d)";
pub const __WCHAR_WIDTH__ = 32; pub const __OBJC_BOOL_IS_BOOL = @as(c_int, 0);
pub const __FSGSBASE__ = 1; pub const __CONSTANT_CFSTRINGS__ = @as(c_int, 1);
pub const __PTRDIFF_FMTd__ = "ld"; pub const __clang_literal_encoding__ = "UTF-8";
pub const __DBL_MIN_EXP__ = -1021; pub const __clang_wide_literal_encoding__ = "UTF-32";
pub const __FLT_EVAL_METHOD__ = 0; pub const __OPTIMIZE__ = @as(c_int, 1);
pub const __SSE_MATH__ = 1; pub const __ORDER_LITTLE_ENDIAN__ = @as(c_int, 1234);
pub const __UINT_FAST8_FMTo__ = "hho"; pub const __ORDER_BIG_ENDIAN__ = @as(c_int, 4321);
pub const __UINT_LEAST64_MAX__ = @as(c_ulong, 18446744073709551615); pub const __ORDER_PDP_ENDIAN__ = @as(c_int, 3412);
pub const MULTIBOOT_INFO_BOOT_LOADER_NAME = 512;
pub const __UINT_LEAST64_FMTx__ = "lx";
pub const __INT8_MAX__ = 127;
pub const __znver1 = 1;
pub const MULTIBOOT_MEMORY_AVAILABLE = 1;
pub const __DBL_HAS_DENORM__ = 1;
pub const __FLOAT128__ = 1;
pub const __ATOMIC_RELAXED = 0;
pub const __DBL_DECIMAL_DIG__ = 17;
pub const __XSAVEC__ = 1;
pub const MULTIBOOT_SEARCH = 8192;
pub const __SIZEOF_SHORT__ = 2;
pub const __UINT_FAST16_MAX__ = 65535;
pub const __UINT16_FMTX__ = "hX";
pub const __CLANG_ATOMIC_SHORT_LOCK_FREE = 2;
pub const __SSSE3__ = 1;
pub const __CONSTANT_CFSTRINGS__ = 1;
pub const __AVX2__ = 1;
pub const __LDBL_MAX_EXP__ = 16384;
pub const __WINT_MAX__ = @as(c_uint, 4294967295);
pub const __NO_MATH_INLINES = 1;
pub const __WCHAR_TYPE__ = int;
pub const __LONG_MAX__ = @as(c_long, 9223372036854775807);
pub const __STDC_HOSTED__ = 1;
pub const MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT = 2;
pub const __PTRDIFF_WIDTH__ = 64;
pub const __INT_FAST16_FMTi__ = "hi";
pub const __INT_LEAST32_TYPE__ = int;
pub const __SCHAR_MAX__ = 127;
pub const __LDBL_DENORM_MIN__ = 0.000000;
pub const MULTIBOOT_INFO_AOUT_SYMS = 16;
pub const __PRFCHW__ = 1;
pub const __INT64_C_SUFFIX__ = L;
pub const __ELF__ = 1;
pub const __LDBL_MANT_DIG__ = 64;
pub const MULTIBOOT_HEADER_ALIGN = 4;
pub const MULTIBOOT_INFO_CONFIG_TABLE = 256;
pub const __CLANG_ATOMIC_INT_LOCK_FREE = 2;
pub const __SIZEOF_PTRDIFF_T__ = 8;
pub const __SIG_ATOMIC_MAX__ = 2147483647;
pub const __UINT64_FMTX__ = "lX";
pub const __UINT64_MAX__ = @as(c_ulong, 18446744073709551615);
pub const __DBL_MANT_DIG__ = 53;
pub const __FLT_DECIMAL_DIG__ = 9;
pub const __INT_LEAST32_MAX__ = 2147483647;
pub const __DBL_DIG__ = 15;
pub const __ATOMIC_ACQUIRE = 2;
pub const __OPENCL_MEMORY_SCOPE_WORK_GROUP = 1;
pub const __UINT_FAST16_FMTu__ = "hu";
pub const __INTPTR_FMTi__ = "li";
pub const MULTIBOOT_INFO_MODS = 8;
pub const __UINT_FAST8_FMTX__ = "hhX";
pub const __LITTLE_ENDIAN__ = 1;
pub const __SSE__ = 1;
pub const __FLT_HAS_QUIET_NAN__ = 1;
pub const __SIZEOF_SIZE_T__ = 8;
pub const __SEG_GS = 1;
pub const __UINT_LEAST16_FMTo__ = "ho";
pub const __UINT8_FMTo__ = "hho";
pub const __UINT_LEAST16_FMTx__ = "hx";
pub const __CLANG_ATOMIC_WCHAR_T_LOCK_FREE = 2;
pub const __UINT_FAST16_FMTX__ = "hX";
pub const __VERSION__ = "Clang 9.0.0 (tags/RELEASE_900/final)";
pub const __UINT_FAST32_FMTx__ = "x";
pub const __UINTPTR_MAX__ = @as(c_ulong, 18446744073709551615);
pub const MULTIBOOT_INFO_ALIGN = 4;
pub const __UINT_FAST8_FMTu__ = "hhu";
pub const __UINT_LEAST8_FMTu__ = "hhu";
pub const __UINT_LEAST64_FMTo__ = "lo";
pub const __UINT_LEAST8_MAX__ = 255;
pub const __RDRND__ = 1;
pub const __SIZEOF_WCHAR_T__ = 4;
pub const __MOVBE__ = 1;
pub const __LDBL_MAX__ = inf;
pub const __UINT16_MAX__ = 65535;
pub const _LP64 = 1;
pub const __x86_64 = 1;
pub const __code_model_small_ = 1;
pub const linux = 1;
pub const __SIZEOF_WINT_T__ = 4;
pub const MULTIBOOT_INFO_CMDLINE = 4;
pub const __UINTMAX_FMTo__ = "lo";
pub const __FLT_DIG__ = 6;
pub const __UINT_LEAST8_FMTX__ = "hhX";
pub const __INT16_MAX__ = 32767;
pub const __WINT_UNSIGNED__ = 1;
pub const __FLT_MAX_10_EXP__ = 38;
pub const __UINTPTR_FMTX__ = "lX";
pub const __UINT_LEAST16_FMTu__ = "hu";
pub const __CLANG_ATOMIC_POINTER_LOCK_FREE = 2;
pub const __WINT_WIDTH__ = 32;
pub const __F16C__ = 1;
pub const __SHRT_MAX__ = 32767;
pub const __znver1__ = 1;
pub const __GCC_ATOMIC_BOOL_LOCK_FREE = 2;
pub const __POINTER_WIDTH__ = 64;
pub const __PTRDIFF_MAX__ = @as(c_long, 9223372036854775807);
pub const __INT32_FMTd__ = "d";
pub const __DBL_MIN__ = 0.000000;
pub const __SIZEOF_LONG__ = 8;
pub const __INTPTR_WIDTH__ = 64;
pub const MULTIBOOT_INFO_VBE_INFO = 2048;
pub const __INT_FAST32_TYPE__ = int;
pub const __NO_INLINE__ = 1;
pub const __UINT_FAST32_FMTX__ = "X";
pub const MULTIBOOT_AOUT_KLUDGE = 65536;
pub const __gnu_linux__ = 1;
pub const __INT_FAST32_MAX__ = 2147483647;
pub const __UINTMAX_FMTu__ = "lu";
pub const MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED = 0;
pub const __BMI__ = 1;
pub const MULTIBOOT_INFO_BOOTDEV = 2;
pub const __FLT_RADIX__ = 2;
pub const MULTIBOOT_INFO_MEMORY = 1;
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 = 1;
pub const MULTIBOOT_FRAMEBUFFER_TYPE_RGB = 1;
pub const __GCC_ATOMIC_INT_LOCK_FREE = 2;
pub const __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES = 3;
pub const __PRAGMA_REDEFINE_EXTNAME = 1;
pub const __INT_FAST8_FMTd__ = "hhd";
pub const __INT32_TYPE__ = int;
pub const MULTIBOOT_BOOTLOADER_MAGIC = 732803074;
pub const __UINTMAX_WIDTH__ = 64;
pub const __FLT_MIN__ = 0.000000;
pub const __INT64_FMTi__ = "li";
pub const __UINT_FAST64_FMTu__ = "lu";
pub const __INT8_FMTd__ = "hhd";
pub const __INT_FAST16_TYPE__ = short;
pub const __FLT_MAX_EXP__ = 128;
pub const __XSAVE__ = 1;
pub const __DBL_MAX_10_EXP__ = 308;
pub const __LDBL_MIN__ = 0.000000;
pub const __INT_FAST64_FMTi__ = "li";
pub const __INT_LEAST8_FMTd__ = "hhd";
pub const __CLANG_ATOMIC_LLONG_LOCK_FREE = 2;
pub const __UINT_LEAST32_FMTX__ = "X";
pub const __UINTMAX_MAX__ = @as(c_ulong, 18446744073709551615);
pub const __UINT_FAST16_FMTo__ = "ho";
pub const __LDBL_DECIMAL_DIG__ = 21;
pub const __UINT_LEAST64_FMTX__ = "lX";
pub const __clang_minor__ = 0;
pub const __SIZEOF_FLOAT128__ = 16;
pub const __UINT_FAST64_FMTo__ = "lo";
pub const __SIZE_FMTx__ = "lx";
pub const __DBL_MAX__ = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878;
pub const __DBL_EPSILON__ = 0.000000;
pub const __UINT64_FMTx__ = "lx";
pub const MULTIBOOT_HEADER = 1;
pub const __CLWB__ = 1;
pub const __CHAR_BIT__ = 8;
pub const __INT16_FMTi__ = "hi";
pub const _DEBUG = 1;
pub const __GNUC_MINOR__ = 2;
pub const __UINT_FAST32_MAX__ = @as(c_uint, 4294967295);
pub const __UINT8_FMTX__ = "hhX";
pub const __FLT_EPSILON__ = 0.000000;
pub const __UINTPTR_WIDTH__ = 64;
pub const __llvm__ = 1;
pub const __UINT_FAST64_MAX__ = @as(c_ulong, 18446744073709551615);
pub const __INT_FAST32_FMTi__ = "i";
pub const __FLT_HAS_INFINITY__ = 1;
pub const __AES__ = 1;
pub const __UINT8_FMTx__ = "hhx";
pub const __INTMAX_C_SUFFIX__ = L;
pub const __ORDER_LITTLE_ENDIAN__ = 1234;
pub const __GCC_ATOMIC_CHAR16_T_LOCK_FREE = 2;
pub const __INT16_FMTd__ = "hd";
pub const __UINT32_FMTX__ = "X";
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 = 1;
pub const __UINT32_C_SUFFIX__ = U;
pub const __INT32_MAX__ = 2147483647;
pub const __GCC_ATOMIC_CHAR_LOCK_FREE = 2;
pub const __INTMAX_WIDTH__ = 64;
pub const __CLANG_ATOMIC_BOOL_LOCK_FREE = 2;
pub const __SIZE_FMTo__ = "lo";
pub const __DBL_HAS_QUIET_NAN__ = 1;
pub const __INT_FAST8_FMTi__ = "hhi";
pub const __UINT_LEAST32_FMTo__ = "o";
pub const __STDC_UTF_16__ = 1;
pub const __UINT_LEAST32_MAX__ = @as(c_uint, 4294967295);
pub const __ATOMIC_RELEASE = 3;
pub const __UINT_FAST16_FMTx__ = "hx";
pub const __UINTMAX_C_SUFFIX__ = UL;
pub const __FLT_MIN_EXP__ = -125;
pub const __SIZEOF_LONG_DOUBLE__ = 16;
pub const __UINT_LEAST64_FMTu__ = "lu";
pub const MULTIBOOT_MOD_ALIGN = 4096;
pub const __GCC_ATOMIC_LONG_LOCK_FREE = 2;
pub const __ORDER_PDP_ENDIAN__ = 3412;
pub const MULTIBOOT_PAGE_ALIGN = 1;
pub const __INT_FAST64_FMTd__ = "ld";
pub const __CLANG_ATOMIC_LONG_LOCK_FREE = 2;
pub const __GXX_ABI_VERSION = 1002;
pub const __INT16_TYPE__ = short;
pub const __MWAITX__ = 1;
pub const __SSE2_MATH__ = 1;
pub const __FLT_MANT_DIG__ = 24;
pub const __UINT_FAST64_FMTx__ = "lx";
pub const __STDC__ = 1;
pub const __INT_FAST8_MAX__ = 127;
pub const __INTPTR_FMTd__ = "ld";
pub const __GNUC_PATCHLEVEL__ = 1;
pub const __UINT_LEAST8_FMTx__ = "hhx";
pub const __SIZE_WIDTH__ = 64;
pub const __INT_LEAST64_FMTi__ = "li";
pub const __SSE4_2__ = 1;
pub const __AVX__ = 1;
pub const __INT_FAST16_MAX__ = 32767;
pub const __INTPTR_MAX__ = @as(c_long, 9223372036854775807);
pub const __CLANG_ATOMIC_CHAR16_T_LOCK_FREE = 2;
pub const __UINT64_FMTu__ = "lu";
pub const __BYTE_ORDER__ = __ORDER_LITTLE_ENDIAN__; pub const __BYTE_ORDER__ = __ORDER_LITTLE_ENDIAN__;
pub const __SSE2__ = 1; pub const __LITTLE_ENDIAN__ = @as(c_int, 1);
pub const MULTIBOOT_INFO_FRAMEBUFFER_INFO = 4096; pub const _LP64 = @as(c_int, 1);
pub const __INT_MAX__ = 2147483647; pub const __LP64__ = @as(c_int, 1);
pub const __INTMAX_FMTi__ = "li"; pub const __CHAR_BIT__ = @as(c_int, 8);
pub const __DBL_DENORM_MIN__ = 0.000000; pub const __SCHAR_MAX__ = @as(c_int, 127);
pub const MULTIBOOT_INFO_APM_TABLE = 1024; pub const __SHRT_MAX__ = @as(c_int, 32767);
pub const __clang_major__ = 9; pub const __INT_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
pub const __GNUC__ = 4; pub const __LONG_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
pub const __UINT32_MAX__ = @as(c_uint, 4294967295);
pub const MULTIBOOT_MEMORY_RESERVED = 2;
pub const __FLT_DENORM_MIN__ = 0.000000;
pub const __DBL_MAX_EXP__ = 1024;
pub const __INT8_FMTi__ = "hhi";
pub const __UINT_LEAST16_MAX__ = 65535;
pub const __XSAVES__ = 1;
pub const __LDBL_HAS_DENORM__ = 1;
pub const __LDBL_HAS_QUIET_NAN__ = 1;
pub const __UINT_FAST8_MAX__ = 255;
pub const __DBL_MIN_10_EXP__ = -307;
pub const __UINT8_FMTu__ = "hhu";
pub const __SSE4A__ = 1;
pub const __INT_FAST64_MAX__ = @as(c_long, 9223372036854775807);
pub const __SSE3__ = 1;
pub const __UINT16_FMTu__ = "hu";
pub const __ATOMIC_SEQ_CST = 5;
pub const __SIZE_FMTu__ = "lu";
pub const __LDBL_MIN_EXP__ = -16381;
pub const __UINT_FAST32_FMTu__ = "u";
pub const __clang_patchlevel__ = 0;
pub const __SIZEOF_LONG_LONG__ = 8;
pub const __BMI2__ = 1;
pub const MULTIBOOT_INFO_ELF_SHDR = 32;
pub const __GNUC_STDC_INLINE__ = 1;
pub const __PCLMUL__ = 1;
pub const __FXSR__ = 1;
pub const __UINT8_MAX__ = 255;
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 = 1;
pub const __UINT32_FMTx__ = "x";
pub const __UINT16_FMTo__ = "ho";
pub const __POPCNT__ = 1;
pub const __OPENCL_MEMORY_SCOPE_DEVICE = 2;
pub const MULTIBOOT_VIDEO_MODE = 4;
pub const __UINT32_FMTu__ = "u";
pub const __SIZEOF_POINTER__ = 8;
pub const __SIZE_MAX__ = @as(c_ulong, 18446744073709551615);
pub const __unix = 1;
pub const __INT_FAST16_FMTd__ = "hd";
pub const unix = 1;
pub const __UINT_LEAST32_FMTu__ = "u";
pub const __FLT_MAX__ = 340282346999999984391321947108527833088.000000;
pub const __GCC_ATOMIC_WCHAR_T_LOCK_FREE = 2;
pub const __ATOMIC_CONSUME = 1;
pub const __unix__ = 1;
pub const __x86_64__ = 1;
pub const __LDBL_HAS_INFINITY__ = 1;
pub const __UINTMAX_FMTx__ = "lx";
pub const __UINT64_C_SUFFIX__ = UL;
pub const __FLT_MIN_10_EXP__ = -37;
pub const __INT_LEAST16_MAX__ = 32767;
pub const __UINT32_FMTo__ = "o";
pub const __UINTPTR_FMTo__ = "lo";
pub const __INT_LEAST16_FMTd__ = "hd";
pub const __UINTPTR_FMTx__ = "lx";
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 = 1;
pub const __INT_LEAST64_FMTd__ = "ld";
pub const __INT_LEAST16_TYPE__ = short;
pub const MULTIBOOT_HEADER_MAGIC = 464367618;
pub const __ORDER_BIG_ENDIAN__ = 4321;
pub const __LDBL_MIN_10_EXP__ = -4931;
pub const __INT_LEAST8_MAX__ = 127;
pub const __SIZEOF_INT__ = 4;
pub const __GCC_ATOMIC_POINTER_LOCK_FREE = 2;
pub const MULTIBOOT_INFO_DRIVE_INFO = 128;
pub const __SHA__ = 1;
pub const MULTIBOOT_MEMORY_INFO = 2;
pub const __amd64 = 1;
pub const __OBJC_BOOL_IS_BOOL = 0;
pub const __ADX__ = 1;
pub const __LDBL_MAX_10_EXP__ = 4932;
pub const __SIZEOF_INT128__ = 16;
pub const __UINT_FAST8_FMTx__ = "hhx";
pub const __CLZERO__ = 1;
pub const __linux = 1;
pub const __UINT16_FMTx__ = "hx";
pub const __UINTPTR_FMTu__ = "lu";
pub const __UINT_LEAST16_FMTX__ = "hX";
pub const __CLFLUSHOPT__ = 1;
pub const __amd64__ = 1;
pub const __UINT_FAST32_FMTo__ = "o";
pub const __linux__ = 1;
pub const __clang__ = 1;
pub const __LP64__ = 1;
pub const __PTRDIFF_FMTi__ = "li";
pub const __WBNOINVD__ = 1;
pub const __SSE4_1__ = 1;
pub const __LDBL_DIG__ = 18;
pub const __GCC_ATOMIC_CHAR32_T_LOCK_FREE = 2;
pub const __XSAVEOPT__ = 1;
pub const __UINT64_FMTo__ = "lo";
pub const __INT_FAST32_FMTd__ = "d";
pub const __ATOMIC_ACQ_REL = 4;
pub const MULTIBOOT_MEMORY_ACPI_RECLAIMABLE = 3;
pub const __LONG_LONG_MAX__ = @as(c_longlong, 9223372036854775807); pub const __LONG_LONG_MAX__ = @as(c_longlong, 9223372036854775807);
pub const __OPENCL_MEMORY_SCOPE_SUB_GROUP = 4; pub const __WCHAR_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
pub const MULTIBOOT_MEMORY_NVS = 4; pub const __WINT_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
pub const __RDPID__ = 1; pub const __INTMAX_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
pub const MULTIBOOT_INFO_MEM_MAP = 64; pub const __SIZE_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
pub const __INTMAX_MAX__ = @as(c_long, 9223372036854775807); pub const __UINTMAX_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
pub const __UINT_LEAST32_FMTx__ = "x"; pub const __PTRDIFF_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
pub const __WCHAR_MAX__ = 2147483647; pub const __INTPTR_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
pub const __INT64_MAX__ = @as(c_long, 9223372036854775807); pub const __UINTPTR_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
pub const __CLANG_ATOMIC_CHAR32_T_LOCK_FREE = 2; pub const __SIZEOF_DOUBLE__ = @as(c_int, 8);
pub const __INT_LEAST64_MAX__ = @as(c_long, 9223372036854775807); pub const __SIZEOF_FLOAT__ = @as(c_int, 4);
pub const __SIZEOF_INT__ = @as(c_int, 4);
pub const __SIZEOF_LONG__ = @as(c_int, 8);
pub const __SIZEOF_LONG_DOUBLE__ = @as(c_int, 16);
pub const __SIZEOF_LONG_LONG__ = @as(c_int, 8);
pub const __SIZEOF_POINTER__ = @as(c_int, 8);
pub const __SIZEOF_SHORT__ = @as(c_int, 2);
pub const __SIZEOF_PTRDIFF_T__ = @as(c_int, 8);
pub const __SIZEOF_SIZE_T__ = @as(c_int, 8);
pub const __SIZEOF_WCHAR_T__ = @as(c_int, 4);
pub const __SIZEOF_WINT_T__ = @as(c_int, 4);
pub const __SIZEOF_INT128__ = @as(c_int, 16);
pub const __INTMAX_TYPE__ = c_long;
pub const __INTMAX_FMTd__ = "ld";
pub const __INTMAX_FMTi__ = "li";
pub const __UINTMAX_TYPE__ = c_ulong;
pub const __UINTMAX_FMTo__ = "lo";
pub const __UINTMAX_FMTu__ = "lu";
pub const __UINTMAX_FMTx__ = "lx";
pub const __UINTMAX_FMTX__ = "lX"; pub const __UINTMAX_FMTX__ = "lX";
pub const __OPENCL_MEMORY_SCOPE_WORK_ITEM = 0; pub const __INTMAX_WIDTH__ = @as(c_int, 64);
pub const __FLT_HAS_DENORM__ = 1; pub const __PTRDIFF_TYPE__ = c_long;
pub const __DECIMAL_DIG__ = __LDBL_DECIMAL_DIG__; pub const __PTRDIFF_FMTd__ = "ld";
pub const __PTRDIFF_FMTi__ = "li";
pub const __PTRDIFF_WIDTH__ = @as(c_int, 64);
pub const __INTPTR_TYPE__ = c_long;
pub const __INTPTR_FMTd__ = "ld";
pub const __INTPTR_FMTi__ = "li";
pub const __INTPTR_WIDTH__ = @as(c_int, 64);
pub const __SIZE_TYPE__ = c_ulong;
pub const __SIZE_FMTo__ = "lo";
pub const __SIZE_FMTu__ = "lu";
pub const __SIZE_FMTx__ = "lx";
pub const __SIZE_FMTX__ = "lX";
pub const __SIZE_WIDTH__ = @as(c_int, 64);
pub const __WCHAR_TYPE__ = c_int;
pub const __WCHAR_WIDTH__ = @as(c_int, 32);
pub const __WINT_TYPE__ = c_uint;
pub const __WINT_WIDTH__ = @as(c_int, 32);
pub const __SIG_ATOMIC_WIDTH__ = @as(c_int, 32);
pub const __SIG_ATOMIC_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
pub const __CHAR16_TYPE__ = c_ushort;
pub const __CHAR32_TYPE__ = c_uint;
pub const __UINTMAX_WIDTH__ = @as(c_int, 64);
pub const __UINTPTR_TYPE__ = c_ulong;
pub const __UINTPTR_FMTo__ = "lo";
pub const __UINTPTR_FMTu__ = "lu";
pub const __UINTPTR_FMTx__ = "lx";
pub const __UINTPTR_FMTX__ = "lX";
pub const __UINTPTR_WIDTH__ = @as(c_int, 64);
pub const __FLT_DENORM_MIN__ = @as(f32, 1.40129846e-45);
pub const __FLT_HAS_DENORM__ = @as(c_int, 1);
pub const __FLT_DIG__ = @as(c_int, 6);
pub const __FLT_DECIMAL_DIG__ = @as(c_int, 9);
pub const __FLT_EPSILON__ = @as(f32, 1.19209290e-7);
pub const __FLT_HAS_INFINITY__ = @as(c_int, 1);
pub const __FLT_HAS_QUIET_NAN__ = @as(c_int, 1);
pub const __FLT_MANT_DIG__ = @as(c_int, 24);
pub const __FLT_MAX_10_EXP__ = @as(c_int, 38);
pub const __FLT_MAX_EXP__ = @as(c_int, 128);
pub const __FLT_MAX__ = @as(f32, 3.40282347e+38);
pub const __FLT_MIN_10_EXP__ = -@as(c_int, 37);
pub const __FLT_MIN_EXP__ = -@as(c_int, 125);
pub const __FLT_MIN__ = @as(f32, 1.17549435e-38);
pub const __DBL_DENORM_MIN__ = 4.9406564584124654e-324;
pub const __DBL_HAS_DENORM__ = @as(c_int, 1);
pub const __DBL_DIG__ = @as(c_int, 15);
pub const __DBL_DECIMAL_DIG__ = @as(c_int, 17);
pub const __DBL_EPSILON__ = 2.2204460492503131e-16;
pub const __DBL_HAS_INFINITY__ = @as(c_int, 1);
pub const __DBL_HAS_QUIET_NAN__ = @as(c_int, 1);
pub const __DBL_MANT_DIG__ = @as(c_int, 53);
pub const __DBL_MAX_10_EXP__ = @as(c_int, 308);
pub const __DBL_MAX_EXP__ = @as(c_int, 1024);
pub const __DBL_MAX__ = 1.7976931348623157e+308;
pub const __DBL_MIN_10_EXP__ = -@as(c_int, 307);
pub const __DBL_MIN_EXP__ = -@as(c_int, 1021);
pub const __DBL_MIN__ = 2.2250738585072014e-308;
pub const __LDBL_DENORM_MIN__ = @as(c_longdouble, 3.64519953188247460253e-4951);
pub const __LDBL_HAS_DENORM__ = @as(c_int, 1);
pub const __LDBL_DIG__ = @as(c_int, 18);
pub const __LDBL_DECIMAL_DIG__ = @as(c_int, 21);
pub const __LDBL_EPSILON__ = @as(c_longdouble, 1.08420217248550443401e-19);
pub const __LDBL_HAS_INFINITY__ = @as(c_int, 1);
pub const __LDBL_HAS_QUIET_NAN__ = @as(c_int, 1);
pub const __LDBL_MANT_DIG__ = @as(c_int, 64);
pub const __LDBL_MAX_10_EXP__ = @as(c_int, 4932);
pub const __LDBL_MAX_EXP__ = @as(c_int, 16384);
pub const __LDBL_MAX__ = @as(c_longdouble, 1.18973149535723176502e+4932);
pub const __LDBL_MIN_10_EXP__ = -@as(c_int, 4931);
pub const __LDBL_MIN_EXP__ = -@as(c_int, 16381);
pub const __LDBL_MIN__ = @as(c_longdouble, 3.36210314311209350626e-4932);
pub const __POINTER_WIDTH__ = @as(c_int, 64);
pub const __BIGGEST_ALIGNMENT__ = @as(c_int, 16);
pub const __WINT_UNSIGNED__ = @as(c_int, 1);
pub const __INT8_TYPE__ = i8;
pub const __INT8_FMTd__ = "hhd";
pub const __INT8_FMTi__ = "hhi";
pub const __INT8_C_SUFFIX__ = "";
pub const __INT16_TYPE__ = c_short;
pub const __INT16_FMTd__ = "hd";
pub const __INT16_FMTi__ = "hi";
pub const __INT16_C_SUFFIX__ = "";
pub const __INT32_TYPE__ = c_int;
pub const __INT32_FMTd__ = "d";
pub const __INT32_FMTi__ = "i"; pub const __INT32_FMTi__ = "i";
pub const __DBL_HAS_INFINITY__ = 1; pub const __INT32_C_SUFFIX__ = "";
pub const __FINITE_MATH_ONLY__ = 0; pub const __INT64_TYPE__ = c_long;
pub const __INT64_FMTd__ = "ld";
pub const __INT64_FMTi__ = "li";
pub const __UINT8_TYPE__ = u8;
pub const __UINT8_FMTo__ = "hho";
pub const __UINT8_FMTu__ = "hhu";
pub const __UINT8_FMTx__ = "hhx";
pub const __UINT8_FMTX__ = "hhX";
pub const __UINT8_C_SUFFIX__ = "";
pub const __UINT8_MAX__ = @as(c_int, 255);
pub const __INT8_MAX__ = @as(c_int, 127);
pub const __UINT16_TYPE__ = c_ushort;
pub const __UINT16_FMTo__ = "ho";
pub const __UINT16_FMTu__ = "hu";
pub const __UINT16_FMTx__ = "hx";
pub const __UINT16_FMTX__ = "hX";
pub const __UINT16_C_SUFFIX__ = "";
pub const __UINT16_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 65535, .decimal);
pub const __INT16_MAX__ = @as(c_int, 32767);
pub const __UINT32_TYPE__ = c_uint;
pub const __UINT32_FMTo__ = "o";
pub const __UINT32_FMTu__ = "u";
pub const __UINT32_FMTx__ = "x";
pub const __UINT32_FMTX__ = "X";
pub const __UINT32_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
pub const __INT32_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
pub const __UINT64_TYPE__ = c_ulong;
pub const __UINT64_FMTo__ = "lo";
pub const __UINT64_FMTu__ = "lu";
pub const __UINT64_FMTx__ = "lx";
pub const __UINT64_FMTX__ = "lX";
pub const __UINT64_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
pub const __INT64_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
pub const __INT_LEAST8_TYPE__ = i8;
pub const __INT_LEAST8_MAX__ = @as(c_int, 127);
pub const __INT_LEAST8_FMTd__ = "hhd";
pub const __INT_LEAST8_FMTi__ = "hhi";
pub const __UINT_LEAST8_TYPE__ = u8;
pub const __UINT_LEAST8_MAX__ = @as(c_int, 255);
pub const __UINT_LEAST8_FMTo__ = "hho";
pub const __UINT_LEAST8_FMTu__ = "hhu";
pub const __UINT_LEAST8_FMTx__ = "hhx";
pub const __UINT_LEAST8_FMTX__ = "hhX";
pub const __INT_LEAST16_TYPE__ = c_short;
pub const __INT_LEAST16_MAX__ = @as(c_int, 32767);
pub const __INT_LEAST16_FMTd__ = "hd";
pub const __INT_LEAST16_FMTi__ = "hi";
pub const __UINT_LEAST16_TYPE__ = c_ushort;
pub const __UINT_LEAST16_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 65535, .decimal);
pub const __UINT_LEAST16_FMTo__ = "ho";
pub const __UINT_LEAST16_FMTu__ = "hu";
pub const __UINT_LEAST16_FMTx__ = "hx";
pub const __UINT_LEAST16_FMTX__ = "hX";
pub const __INT_LEAST32_TYPE__ = c_int;
pub const __INT_LEAST32_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
pub const __INT_LEAST32_FMTd__ = "d";
pub const __INT_LEAST32_FMTi__ = "i";
pub const __UINT_LEAST32_TYPE__ = c_uint;
pub const __UINT_LEAST32_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
pub const __UINT_LEAST32_FMTo__ = "o";
pub const __UINT_LEAST32_FMTu__ = "u";
pub const __UINT_LEAST32_FMTx__ = "x";
pub const __UINT_LEAST32_FMTX__ = "X";
pub const __INT_LEAST64_TYPE__ = c_long;
pub const __INT_LEAST64_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
pub const __INT_LEAST64_FMTd__ = "ld";
pub const __INT_LEAST64_FMTi__ = "li";
pub const __UINT_LEAST64_TYPE__ = c_ulong;
pub const __UINT_LEAST64_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
pub const __UINT_LEAST64_FMTo__ = "lo";
pub const __UINT_LEAST64_FMTu__ = "lu";
pub const __UINT_LEAST64_FMTx__ = "lx";
pub const __UINT_LEAST64_FMTX__ = "lX";
pub const __INT_FAST8_TYPE__ = i8;
pub const __INT_FAST8_MAX__ = @as(c_int, 127);
pub const __INT_FAST8_FMTd__ = "hhd";
pub const __INT_FAST8_FMTi__ = "hhi";
pub const __UINT_FAST8_TYPE__ = u8;
pub const __UINT_FAST8_MAX__ = @as(c_int, 255);
pub const __UINT_FAST8_FMTo__ = "hho";
pub const __UINT_FAST8_FMTu__ = "hhu";
pub const __UINT_FAST8_FMTx__ = "hhx";
pub const __UINT_FAST8_FMTX__ = "hhX";
pub const __INT_FAST16_TYPE__ = c_short;
pub const __INT_FAST16_MAX__ = @as(c_int, 32767);
pub const __INT_FAST16_FMTd__ = "hd";
pub const __INT_FAST16_FMTi__ = "hi";
pub const __UINT_FAST16_TYPE__ = c_ushort;
pub const __UINT_FAST16_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 65535, .decimal);
pub const __UINT_FAST16_FMTo__ = "ho";
pub const __UINT_FAST16_FMTu__ = "hu";
pub const __UINT_FAST16_FMTx__ = "hx";
pub const __UINT_FAST16_FMTX__ = "hX";
pub const __INT_FAST32_TYPE__ = c_int;
pub const __INT_FAST32_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
pub const __INT_FAST32_FMTd__ = "d";
pub const __INT_FAST32_FMTi__ = "i";
pub const __UINT_FAST32_TYPE__ = c_uint;
pub const __UINT_FAST32_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
pub const __UINT_FAST32_FMTo__ = "o";
pub const __UINT_FAST32_FMTu__ = "u";
pub const __UINT_FAST32_FMTx__ = "x";
pub const __UINT_FAST32_FMTX__ = "X";
pub const __INT_FAST64_TYPE__ = c_long;
pub const __INT_FAST64_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
pub const __INT_FAST64_FMTd__ = "ld";
pub const __INT_FAST64_FMTi__ = "li";
pub const __UINT_FAST64_TYPE__ = c_ulong;
pub const __UINT_FAST64_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
pub const __UINT_FAST64_FMTo__ = "lo";
pub const __UINT_FAST64_FMTu__ = "lu";
pub const __UINT_FAST64_FMTx__ = "lx";
pub const __UINT_FAST64_FMTX__ = "lX";
pub const __USER_LABEL_PREFIX__ = "";
pub const __FINITE_MATH_ONLY__ = @as(c_int, 0);
pub const __GNUC_STDC_INLINE__ = @as(c_int, 1);
pub const __GCC_ATOMIC_TEST_AND_SET_TRUEVAL = @as(c_int, 1);
pub const __CLANG_ATOMIC_BOOL_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_CHAR_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_CHAR16_T_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_CHAR32_T_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_WCHAR_T_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_SHORT_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_INT_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_LONG_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_LLONG_LOCK_FREE = @as(c_int, 2);
pub const __CLANG_ATOMIC_POINTER_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_BOOL_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_CHAR_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_CHAR16_T_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_CHAR32_T_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_WCHAR_T_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_SHORT_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_INT_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_LONG_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_LLONG_LOCK_FREE = @as(c_int, 2);
pub const __GCC_ATOMIC_POINTER_LOCK_FREE = @as(c_int, 2);
pub const __FLT_EVAL_METHOD__ = @as(c_int, 0);
pub const __FLT_RADIX__ = @as(c_int, 2);
pub const __DECIMAL_DIG__ = __LDBL_DECIMAL_DIG__;
pub const __GCC_ASM_FLAG_OUTPUTS__ = @as(c_int, 1);
pub const __code_model_small__ = @as(c_int, 1);
pub const __amd64__ = @as(c_int, 1);
pub const __amd64 = @as(c_int, 1);
pub const __x86_64 = @as(c_int, 1);
pub const __x86_64__ = @as(c_int, 1);
pub const __SEG_GS = @as(c_int, 1);
pub const __SEG_FS = @as(c_int, 1);
pub const __znver2 = @as(c_int, 1);
pub const __znver2__ = @as(c_int, 1);
pub const __tune_znver2__ = @as(c_int, 1);
pub const __REGISTER_PREFIX__ = "";
pub const __NO_MATH_INLINES = @as(c_int, 1);
pub const __AES__ = @as(c_int, 1);
pub const __PCLMUL__ = @as(c_int, 1);
pub const __LAHF_SAHF__ = @as(c_int, 1);
pub const __LZCNT__ = @as(c_int, 1);
pub const __RDRND__ = @as(c_int, 1);
pub const __FSGSBASE__ = @as(c_int, 1);
pub const __BMI__ = @as(c_int, 1);
pub const __BMI2__ = @as(c_int, 1);
pub const __POPCNT__ = @as(c_int, 1);
pub const __PRFCHW__ = @as(c_int, 1);
pub const __RDSEED__ = @as(c_int, 1);
pub const __ADX__ = @as(c_int, 1);
pub const __MWAITX__ = @as(c_int, 1);
pub const __MOVBE__ = @as(c_int, 1);
pub const __SSE4A__ = @as(c_int, 1);
pub const __FMA__ = @as(c_int, 1);
pub const __F16C__ = @as(c_int, 1);
pub const __SHA__ = @as(c_int, 1);
pub const __FXSR__ = @as(c_int, 1);
pub const __XSAVE__ = @as(c_int, 1);
pub const __XSAVEOPT__ = @as(c_int, 1);
pub const __XSAVEC__ = @as(c_int, 1);
pub const __XSAVES__ = @as(c_int, 1);
pub const __CLFLUSHOPT__ = @as(c_int, 1);
pub const __CLWB__ = @as(c_int, 1);
pub const __WBNOINVD__ = @as(c_int, 1);
pub const __CLZERO__ = @as(c_int, 1);
pub const __RDPID__ = @as(c_int, 1);
pub const __AVX2__ = @as(c_int, 1);
pub const __AVX__ = @as(c_int, 1);
pub const __SSE4_2__ = @as(c_int, 1);
pub const __SSE4_1__ = @as(c_int, 1);
pub const __SSSE3__ = @as(c_int, 1);
pub const __SSE3__ = @as(c_int, 1);
pub const __SSE2__ = @as(c_int, 1);
pub const __SSE2_MATH__ = @as(c_int, 1);
pub const __SSE__ = @as(c_int, 1);
pub const __SSE_MATH__ = @as(c_int, 1);
pub const __MMX__ = @as(c_int, 1);
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1 = @as(c_int, 1);
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_2 = @as(c_int, 1);
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 = @as(c_int, 1);
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 = @as(c_int, 1);
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 = @as(c_int, 1);
pub const __SIZEOF_FLOAT128__ = @as(c_int, 16);
pub const unix = @as(c_int, 1);
pub const __unix = @as(c_int, 1);
pub const __unix__ = @as(c_int, 1);
pub const linux = @as(c_int, 1);
pub const __linux = @as(c_int, 1);
pub const __linux__ = @as(c_int, 1);
pub const __ELF__ = @as(c_int, 1);
pub const __gnu_linux__ = @as(c_int, 1);
pub const __FLOAT128__ = @as(c_int, 1);
pub const __STDC__ = @as(c_int, 1);
pub const __STDC_HOSTED__ = @as(c_int, 1);
pub const __STDC_VERSION__ = @as(c_long, 201710);
pub const __STDC_UTF_16__ = @as(c_int, 1);
pub const __STDC_UTF_32__ = @as(c_int, 1);
pub const _DEBUG = @as(c_int, 1);
pub const __GCC_HAVE_DWARF2_CFI_ASM = @as(c_int, 1);
pub const MULTIBOOT_HEADER = @as(c_int, 1);
pub const MULTIBOOT_SEARCH = @as(c_int, 8192);
pub const MULTIBOOT_HEADER_ALIGN = @as(c_int, 4);
pub const MULTIBOOT_HEADER_MAGIC = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x1BADB002, .hexadecimal);
pub const MULTIBOOT_BOOTLOADER_MAGIC = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x2BADB002, .hexadecimal);
pub const MULTIBOOT_MOD_ALIGN = @as(c_int, 0x00001000);
pub const MULTIBOOT_INFO_ALIGN = @as(c_int, 0x00000004);
pub const MULTIBOOT_PAGE_ALIGN = @as(c_int, 0x00000001);
pub const MULTIBOOT_MEMORY_INFO = @as(c_int, 0x00000002);
pub const MULTIBOOT_VIDEO_MODE = @as(c_int, 0x00000004);
pub const MULTIBOOT_AOUT_KLUDGE = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x00010000, .hexadecimal);
pub const MULTIBOOT_INFO_MEMORY = @as(c_int, 0x00000001);
pub const MULTIBOOT_INFO_BOOTDEV = @as(c_int, 0x00000002);
pub const MULTIBOOT_INFO_CMDLINE = @as(c_int, 0x00000004);
pub const MULTIBOOT_INFO_MODS = @as(c_int, 0x00000008);
pub const MULTIBOOT_INFO_AOUT_SYMS = @as(c_int, 0x00000010);
pub const MULTIBOOT_INFO_ELF_SHDR = @as(c_int, 0x00000020);
pub const MULTIBOOT_INFO_MEM_MAP = @as(c_int, 0x00000040);
pub const MULTIBOOT_INFO_DRIVE_INFO = @as(c_int, 0x00000080);
pub const MULTIBOOT_INFO_CONFIG_TABLE = @as(c_int, 0x00000100);
pub const MULTIBOOT_INFO_BOOT_LOADER_NAME = @as(c_int, 0x00000200);
pub const MULTIBOOT_INFO_APM_TABLE = @as(c_int, 0x00000400);
pub const MULTIBOOT_INFO_VBE_INFO = @as(c_int, 0x00000800);
pub const MULTIBOOT_INFO_FRAMEBUFFER_INFO = @as(c_int, 0x00001000);
pub const MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED = @as(c_int, 0);
pub const MULTIBOOT_FRAMEBUFFER_TYPE_RGB = @as(c_int, 1);
pub const MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT = @as(c_int, 2);
pub const MULTIBOOT_MEMORY_AVAILABLE = @as(c_int, 1);
pub const MULTIBOOT_MEMORY_RESERVED = @as(c_int, 2);
pub const MULTIBOOT_MEMORY_ACPI_RECLAIMABLE = @as(c_int, 3);
pub const MULTIBOOT_MEMORY_NVS = @as(c_int, 4);
pub const MULTIBOOT_MEMORY_BADRAM = @as(c_int, 5);
pub const multiboot_header = struct_multiboot_header; pub const multiboot_header = struct_multiboot_header;
pub const multiboot_aout_symbol_table = struct_multiboot_aout_symbol_table; pub const multiboot_aout_symbol_table = struct_multiboot_aout_symbol_table;
pub const multiboot_elf_section_header_table = struct_multiboot_elf_section_header_table; pub const multiboot_elf_section_header_table = struct_multiboot_elf_section_header_table;

View file

@ -7,8 +7,7 @@ const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const arch = if (builtin.is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
const isr = @import("isr.zig"); const isr = @import("isr.zig");
const MemProfile = @import("../../mem.zig").MemProfile; const MemProfile = @import("../../mem.zig").MemProfile;
const tty = @import("../../tty.zig"); const tty = @import("../../tty.zig");
@ -133,7 +132,7 @@ pub var kernel_directory: Directory align(@truncate(u29, PAGE_SIZE_4KB)) = Direc
/// Return: usize /// Return: usize
/// The index into an array of directory entries. /// The index into an array of directory entries.
/// ///
fn virtToDirEntryIdx(virt: usize) callconv(.Inline) usize { inline fn virtToDirEntryIdx(virt: usize) usize {
return virt / PAGE_SIZE_4MB; return virt / PAGE_SIZE_4MB;
} }
@ -146,7 +145,7 @@ fn virtToDirEntryIdx(virt: usize) callconv(.Inline) usize {
/// Return: usize /// Return: usize
/// The index into an array of table entries. /// The index into an array of table entries.
/// ///
fn virtToTableEntryIdx(virt: usize) callconv(.Inline) usize { inline fn virtToTableEntryIdx(virt: usize) usize {
return (virt / PAGE_SIZE_4KB) % ENTRIES_PER_TABLE; return (virt / PAGE_SIZE_4KB) % ENTRIES_PER_TABLE;
} }
@ -157,7 +156,7 @@ fn virtToTableEntryIdx(virt: usize) callconv(.Inline) usize {
/// val: *align(1) u32 - The entry to modify /// val: *align(1) u32 - The entry to modify
/// attr: u32 - The bits corresponding to the attribute to set /// attr: u32 - The bits corresponding to the attribute to set
/// ///
fn setAttribute(val: *align(1) u32, attr: u32) callconv(.Inline) void { inline fn setAttribute(val: *align(1) u32, attr: u32) void {
val.* |= attr; val.* |= attr;
} }
@ -168,7 +167,7 @@ fn setAttribute(val: *align(1) u32, attr: u32) callconv(.Inline) void {
/// val: *align(1) u32 - The entry to modify /// val: *align(1) u32 - The entry to modify
/// attr: u32 - The bits corresponding to the attribute to clear /// attr: u32 - The bits corresponding to the attribute to clear
/// ///
fn clearAttribute(val: *align(1) u32, attr: u32) callconv(.Inline) void { inline fn clearAttribute(val: *align(1) u32, attr: u32) void {
val.* &= ~attr; val.* &= ~attr;
} }
@ -182,7 +181,7 @@ fn clearAttribute(val: *align(1) u32, attr: u32) callconv(.Inline) void {
/// IN phys_addr: usize - The start of the physical space to map /// IN phys_addr: usize - The start of the physical space to map
/// IN phys_end: usize - The end of the physical space to map /// IN phys_end: usize - The end of the physical space to map
/// IN attrs: vmm.Attributes - The attributes to apply to this mapping /// IN attrs: vmm.Attributes - The attributes to apply to this mapping
/// IN allocator: *Allocator - The allocator to use to map any tables needed /// IN allocator: Allocator - The allocator to use to map any tables needed
/// OUT dir: *Directory - The directory that this entry is in /// OUT dir: *Directory - The directory that this entry is in
/// ///
/// Error: vmm.MapperError || Allocator.Error /// Error: vmm.MapperError || Allocator.Error
@ -193,7 +192,7 @@ fn clearAttribute(val: *align(1) u32, attr: u32) callconv(.Inline) void {
/// vmm.MapperError.MisalignedVirtualAddress - One or both of the virtual addresses aren't page size aligned /// vmm.MapperError.MisalignedVirtualAddress - One or both of the virtual addresses aren't page size aligned
/// Allocator.Error.* - See Allocator.alignedAlloc /// Allocator.Error.* - See Allocator.alignedAlloc
/// ///
fn mapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, phys_start: usize, phys_end: usize, attrs: vmm.Attributes, allocator: *Allocator) (vmm.MapperError || Allocator.Error)!void { fn mapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, phys_start: usize, phys_end: usize, attrs: vmm.Attributes, allocator: Allocator) (vmm.MapperError || Allocator.Error)!void {
if (phys_start > phys_end) { if (phys_start > phys_end) {
return vmm.MapperError.InvalidPhysicalAddress; return vmm.MapperError.InvalidPhysicalAddress;
} }
@ -271,12 +270,14 @@ fn mapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, phys_start:
/// IN virt_addr: usize - The start of the virtual space to map /// IN virt_addr: usize - The start of the virtual space to map
/// IN virt_end: usize - The end of the virtual space to map /// IN virt_end: usize - The end of the virtual space to map
/// OUT dir: *Directory - The directory that this entry is in /// OUT dir: *Directory - The directory that this entry is in
/// IN allocator: *Allocator - The allocator used to map the region to be freed. /// IN allocator: Allocator - The allocator used to map the region to be freed.
/// ///
/// Error: vmm.MapperError /// Error: vmm.MapperError
/// vmm.MapperError.NotMapped - If the region being unmapped wasn't mapped in the first place /// vmm.MapperError.NotMapped - If the region being unmapped wasn't mapped in the first place
/// ///
fn unmapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, allocator: *Allocator) vmm.MapperError!void { fn unmapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, allocator: Allocator) vmm.MapperError!void {
// Suppress unused var warning
_ = allocator;
const entry = virtToDirEntryIdx(virt_start); const entry = virtToDirEntryIdx(virt_start);
const table = dir.tables[entry] orelse return vmm.MapperError.NotMapped; const table = dir.tables[entry] orelse return vmm.MapperError.NotMapped;
var addr = virt_start; var addr = virt_start;
@ -287,7 +288,7 @@ fn unmapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, allocator:
if (dir == &kernel_directory) { if (dir == &kernel_directory) {
asm volatile ("invlpg (%[addr])" asm volatile ("invlpg (%[addr])"
: :
: [addr] "r" (addr) : [addr] "r" (addr),
: "memory" : "memory"
); );
} }
@ -341,7 +342,7 @@ fn mapTableEntry(dir: *const Directory, entry: *align(1) TableEntry, virt_addr:
if (dir == &kernel_directory) { if (dir == &kernel_directory) {
asm volatile ("invlpg (%[addr])" asm volatile ("invlpg (%[addr])"
: :
: [addr] "r" (virt_addr) : [addr] "r" (virt_addr),
: "memory" : "memory"
); );
} }
@ -360,13 +361,13 @@ fn mapTableEntry(dir: *const Directory, entry: *align(1) TableEntry, virt_addr:
/// IN physical_start: usize - The start of the physical region to map to /// IN physical_start: usize - The start of the physical region to map to
/// IN physical_end: usize - The end (exclusive) of the physical region to map to /// IN physical_end: usize - The end (exclusive) of the physical region to map to
/// IN attrs: vmm.Attributes - The attributes to apply to this mapping /// IN attrs: vmm.Attributes - The attributes to apply to this mapping
/// IN/OUT allocator: *Allocator - The allocator to use to allocate any intermediate data structures required to map this region /// IN/OUT allocator: Allocator - The allocator to use to allocate any intermediate data structures required to map this region
/// IN/OUT dir: *Directory - The page directory to map within /// IN/OUT dir: *Directory - The page directory to map within
/// ///
/// Error: vmm.MapperError || Allocator.Error /// Error: vmm.MapperError || Allocator.Error
/// * - See mapDirEntry /// * - See mapDirEntry
/// ///
pub fn map(virtual_start: usize, virtual_end: usize, phys_start: usize, phys_end: usize, attrs: vmm.Attributes, allocator: *Allocator, dir: *Directory) (Allocator.Error || vmm.MapperError)!void { pub fn map(virtual_start: usize, virtual_end: usize, phys_start: usize, phys_end: usize, attrs: vmm.Attributes, allocator: Allocator, dir: *Directory) (Allocator.Error || vmm.MapperError)!void {
var virt_addr = virtual_start; var virt_addr = virtual_start;
var phys_addr = phys_start; var phys_addr = phys_start;
var virt_next = std.math.min(virtual_end, std.mem.alignBackward(virt_addr, PAGE_SIZE_4MB) + PAGE_SIZE_4MB); var virt_next = std.math.min(virtual_end, std.mem.alignBackward(virt_addr, PAGE_SIZE_4MB) + PAGE_SIZE_4MB);
@ -394,7 +395,7 @@ pub fn map(virtual_start: usize, virtual_end: usize, phys_start: usize, phys_end
/// Error: vmm.MapperError /// Error: vmm.MapperError
/// vmm.MapperError.NotMapped - If the region being unmapped wasn't mapped in the first place /// vmm.MapperError.NotMapped - If the region being unmapped wasn't mapped in the first place
/// ///
pub fn unmap(virtual_start: usize, virtual_end: usize, allocator: *Allocator, dir: *Directory) vmm.MapperError!void { pub fn unmap(virtual_start: usize, virtual_end: usize, allocator: Allocator, dir: *Directory) vmm.MapperError!void {
var virt_addr = virtual_start; var virt_addr = virtual_start;
var virt_next = std.math.min(virtual_end, std.mem.alignBackward(virt_addr, PAGE_SIZE_4MB) + PAGE_SIZE_4MB); var virt_next = std.math.min(virtual_end, std.mem.alignBackward(virt_addr, PAGE_SIZE_4MB) + PAGE_SIZE_4MB);
var entry_idx = virtToDirEntryIdx(virt_addr); var entry_idx = virtToDirEntryIdx(virt_addr);
@ -423,16 +424,16 @@ pub fn unmap(virtual_start: usize, virtual_end: usize, allocator: *Allocator, di
fn pageFault(state: *arch.CpuState) u32 { fn pageFault(state: *arch.CpuState) u32 {
log.info("State: {X}\n", .{state}); log.info("State: {X}\n", .{state});
var cr0 = asm volatile ("mov %%cr0, %[cr0]" var cr0 = asm volatile ("mov %%cr0, %[cr0]"
: [cr0] "=r" (-> u32) : [cr0] "=r" (-> u32),
); );
var cr2 = asm volatile ("mov %%cr2, %[cr2]" var cr2 = asm volatile ("mov %%cr2, %[cr2]"
: [cr2] "=r" (-> u32) : [cr2] "=r" (-> u32),
); );
var cr3 = asm volatile ("mov %%cr3, %[cr3]" var cr3 = asm volatile ("mov %%cr3, %[cr3]"
: [cr3] "=r" (-> u32) : [cr3] "=r" (-> u32),
); );
var cr4 = asm volatile ("mov %%cr4, %[cr4]" var cr4 = asm volatile ("mov %%cr4, %[cr4]"
: [cr4] "=r" (-> u32) : [cr4] "=r" (-> u32),
); );
log.info("CR0: 0x{X}, CR2: 0x{X}, CR3: 0x{X}, CR4: 0x{X}\n", .{ cr0, cr2, cr3, cr4 }); log.info("CR0: 0x{X}, CR2: 0x{X}, CR3: 0x{X}, CR4: 0x{X}\n", .{ cr0, cr2, cr3, cr4 });
@panic("Page fault"); @panic("Page fault");
@ -454,7 +455,7 @@ pub fn init(mem_profile: *const MemProfile) void {
const dir_physaddr = @ptrToInt(mem.virtToPhys(&kernel_directory)); const dir_physaddr = @ptrToInt(mem.virtToPhys(&kernel_directory));
asm volatile ("mov %[addr], %%cr3" asm volatile ("mov %[addr], %%cr3"
: :
: [addr] "{eax}" (dir_physaddr) : [addr] "{eax}" (dir_physaddr),
); );
const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end), PAGE_SIZE_4KB); const v_end = std.mem.alignForward(@ptrToInt(mem_profile.vaddr_end), PAGE_SIZE_4KB);
switch (build_options.test_mode) { switch (build_options.test_mode) {
@ -463,14 +464,14 @@ pub fn init(mem_profile: *const MemProfile) void {
} }
} }
fn checkDirEntry(entry: DirectoryEntry, virt_start: usize, virt_end: usize, phys_start: usize, attrs: vmm.Attributes, table: *Table, present: bool) void { fn checkDirEntry(entry: DirectoryEntry, virt_start: usize, virt_end: usize, phys_start: usize, attrs: vmm.Attributes, table: *Table, present: bool) !void {
expectEqual(entry & DENTRY_PRESENT, if (present) DENTRY_PRESENT else 0); try expectEqual(entry & DENTRY_PRESENT, if (present) DENTRY_PRESENT else 0);
expectEqual(entry & DENTRY_WRITABLE, if (attrs.writable) DENTRY_WRITABLE else 0); try expectEqual(entry & DENTRY_WRITABLE, if (attrs.writable) DENTRY_WRITABLE else 0);
expectEqual(entry & DENTRY_USER, if (attrs.kernel) 0 else DENTRY_USER); try expectEqual(entry & DENTRY_USER, if (attrs.kernel) 0 else DENTRY_USER);
expectEqual(entry & DENTRY_WRITE_THROUGH, DENTRY_WRITE_THROUGH); try expectEqual(entry & DENTRY_WRITE_THROUGH, DENTRY_WRITE_THROUGH);
expectEqual(entry & DENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else DENTRY_CACHE_DISABLED); try expectEqual(entry & DENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else DENTRY_CACHE_DISABLED);
expectEqual(entry & DENTRY_4MB_PAGES, 0); try expectEqual(entry & DENTRY_4MB_PAGES, 0);
expectEqual(entry & DENTRY_ZERO, 0); try expectEqual(entry & DENTRY_ZERO, 0);
var tentry_idx = virtToTableEntryIdx(virt_start); var tentry_idx = virtToTableEntryIdx(virt_start);
var tentry_idx_end = virtToTableEntryIdx(virt_end); var tentry_idx_end = virtToTableEntryIdx(virt_end);
@ -480,19 +481,19 @@ fn checkDirEntry(entry: DirectoryEntry, virt_start: usize, virt_end: usize, phys
phys += PAGE_SIZE_4KB; phys += PAGE_SIZE_4KB;
}) { }) {
const tentry = table.entries[tentry_idx]; const tentry = table.entries[tentry_idx];
checkTableEntry(tentry, phys, attrs, present); try checkTableEntry(tentry, phys, attrs, present);
} }
} }
fn checkTableEntry(entry: TableEntry, page_phys: usize, attrs: vmm.Attributes, present: bool) void { fn checkTableEntry(entry: TableEntry, page_phys: usize, attrs: vmm.Attributes, present: bool) !void {
expectEqual(entry & TENTRY_PRESENT, if (present) TENTRY_PRESENT else 0); try expectEqual(entry & TENTRY_PRESENT, if (present) TENTRY_PRESENT else 0);
expectEqual(entry & TENTRY_WRITABLE, if (attrs.writable) TENTRY_WRITABLE else 0); try expectEqual(entry & TENTRY_WRITABLE, if (attrs.writable) TENTRY_WRITABLE else 0);
expectEqual(entry & TENTRY_USER, if (attrs.kernel) 0 else TENTRY_USER); try expectEqual(entry & TENTRY_USER, if (attrs.kernel) 0 else TENTRY_USER);
expectEqual(entry & TENTRY_WRITE_THROUGH, TENTRY_WRITE_THROUGH); try expectEqual(entry & TENTRY_WRITE_THROUGH, TENTRY_WRITE_THROUGH);
expectEqual(entry & TENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else TENTRY_CACHE_DISABLED); try expectEqual(entry & TENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else TENTRY_CACHE_DISABLED);
expectEqual(entry & TENTRY_ZERO, 0); try expectEqual(entry & TENTRY_ZERO, 0);
expectEqual(entry & TENTRY_GLOBAL, 0); try expectEqual(entry & TENTRY_GLOBAL, 0);
expectEqual(entry & TENTRY_PAGE_ADDR, page_phys); try expectEqual(entry & TENTRY_PAGE_ADDR, page_phys);
} }
test "setAttribute and clearAttribute" { test "setAttribute and clearAttribute" {
@ -502,35 +503,35 @@ test "setAttribute and clearAttribute" {
for (attrs) |attr| { for (attrs) |attr| {
const old_val = val; const old_val = val;
setAttribute(&val, attr); setAttribute(&val, attr);
std.testing.expectEqual(val, old_val | attr); try std.testing.expectEqual(val, old_val | attr);
} }
for (attrs) |attr| { for (attrs) |attr| {
const old_val = val; const old_val = val;
clearAttribute(&val, attr); clearAttribute(&val, attr);
std.testing.expectEqual(val, old_val & ~attr); try std.testing.expectEqual(val, old_val & ~attr);
} }
} }
test "virtToDirEntryIdx" { test "virtToDirEntryIdx" {
expectEqual(virtToDirEntryIdx(0), 0); try expectEqual(virtToDirEntryIdx(0), 0);
expectEqual(virtToDirEntryIdx(123), 0); try expectEqual(virtToDirEntryIdx(123), 0);
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB - 1), 0); try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB - 1), 0);
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB), 1); try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB), 1);
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB + 1), 1); try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB + 1), 1);
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * 2), 2); try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * 2), 2);
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * (ENTRIES_PER_DIRECTORY - 1)), ENTRIES_PER_DIRECTORY - 1); try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * (ENTRIES_PER_DIRECTORY - 1)), ENTRIES_PER_DIRECTORY - 1);
} }
test "virtToTableEntryIdx" { test "virtToTableEntryIdx" {
expectEqual(virtToTableEntryIdx(0), 0); try expectEqual(virtToTableEntryIdx(0), 0);
expectEqual(virtToTableEntryIdx(123), 0); try expectEqual(virtToTableEntryIdx(123), 0);
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB - 1), 0); try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB - 1), 0);
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB), 1); try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB), 1);
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB + 1), 1); try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB + 1), 1);
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * 2), 2); try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * 2), 2);
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * (ENTRIES_PER_TABLE - 1)), ENTRIES_PER_TABLE - 1); try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * (ENTRIES_PER_TABLE - 1)), ENTRIES_PER_TABLE - 1);
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * (ENTRIES_PER_TABLE)), 0); try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * (ENTRIES_PER_TABLE)), 0);
} }
test "mapDirEntry" { test "mapDirEntry" {
@ -550,7 +551,7 @@ test "mapDirEntry" {
const entry_idx = virtToDirEntryIdx(virt); const entry_idx = virtToDirEntryIdx(virt);
const entry = dir.entries[entry_idx]; const entry = dir.entries[entry_idx];
const table = dir.tables[entry_idx].?; const table = dir.tables[entry_idx].?;
checkDirEntry(entry, virt, virt_end, phys, attrs, table, true); try checkDirEntry(entry, virt, virt_end, phys, attrs, table, true);
const table_free = @ptrCast([*]Table, table)[0..1]; const table_free = @ptrCast([*]Table, table)[0..1];
allocator.free(table_free); allocator.free(table_free);
} }
@ -565,7 +566,7 @@ test "mapDirEntry" {
const entry_idx = virtToDirEntryIdx(virt); const entry_idx = virtToDirEntryIdx(virt);
const entry = dir.entries[entry_idx]; const entry = dir.entries[entry_idx];
const table = dir.tables[entry_idx].?; const table = dir.tables[entry_idx].?;
checkDirEntry(entry, virt, virt_end, phys, attrs, table, true); try checkDirEntry(entry, virt, virt_end, phys, attrs, table, true);
const table_free = @ptrCast([*]Table, table)[0..1]; const table_free = @ptrCast([*]Table, table)[0..1];
allocator.free(table_free); allocator.free(table_free);
} }
@ -575,11 +576,11 @@ test "mapDirEntry returns errors correctly" {
var allocator = std.testing.allocator; var allocator = std.testing.allocator;
var dir = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = undefined }; var dir = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = undefined };
const attrs = vmm.Attributes{ .kernel = true, .writable = true, .cachable = true }; const attrs = vmm.Attributes{ .kernel = true, .writable = true, .cachable = true };
testing.expectError(vmm.MapperError.MisalignedVirtualAddress, mapDirEntry(&dir, 1, PAGE_SIZE_4KB + 1, 0, PAGE_SIZE_4KB, attrs, allocator)); try testing.expectError(vmm.MapperError.MisalignedVirtualAddress, mapDirEntry(&dir, 1, PAGE_SIZE_4KB + 1, 0, PAGE_SIZE_4KB, attrs, allocator));
testing.expectError(vmm.MapperError.MisalignedPhysicalAddress, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, PAGE_SIZE_4KB + 1, attrs, allocator)); try testing.expectError(vmm.MapperError.MisalignedPhysicalAddress, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, PAGE_SIZE_4KB + 1, attrs, allocator));
testing.expectError(vmm.MapperError.AddressMismatch, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, PAGE_SIZE_4KB, attrs, allocator)); try testing.expectError(vmm.MapperError.AddressMismatch, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, PAGE_SIZE_4KB, attrs, allocator));
testing.expectError(vmm.MapperError.InvalidVirtualAddress, mapDirEntry(&dir, 1, 0, 0, PAGE_SIZE_4KB, attrs, allocator)); try testing.expectError(vmm.MapperError.InvalidVirtualAddress, mapDirEntry(&dir, 1, 0, 0, PAGE_SIZE_4KB, attrs, allocator));
testing.expectError(vmm.MapperError.InvalidPhysicalAddress, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, 0, attrs, allocator)); try testing.expectError(vmm.MapperError.InvalidPhysicalAddress, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, 0, attrs, allocator));
} }
test "map and unmap" { test "map and unmap" {
@ -605,7 +606,7 @@ test "map and unmap" {
const entry_idx = virtToDirEntryIdx(virt); const entry_idx = virtToDirEntryIdx(virt);
const entry = dir.entries[entry_idx]; const entry = dir.entries[entry_idx];
const table = dir.tables[entry_idx].?; const table = dir.tables[entry_idx].?;
checkDirEntry(entry, virt, virt + PAGE_SIZE_4MB, phys, attrs, table, true); try checkDirEntry(entry, virt, virt + PAGE_SIZE_4MB, phys, attrs, table, true);
} }
try unmap(virt_start, virt_end, allocator, &dir); try unmap(virt_start, virt_end, allocator, &dir);
@ -618,7 +619,7 @@ test "map and unmap" {
const entry_idx = virtToDirEntryIdx(virt); const entry_idx = virtToDirEntryIdx(virt);
const entry = dir.entries[entry_idx]; const entry = dir.entries[entry_idx];
const table = dir.tables[entry_idx].?; const table = dir.tables[entry_idx].?;
checkDirEntry(entry, virt, virt + PAGE_SIZE_4MB, phys, attrs, table, false); try checkDirEntry(entry, virt, virt + PAGE_SIZE_4MB, phys, attrs, table, false);
} }
} }
@ -634,12 +635,12 @@ test "copy" {
var dir2 = dir.copy(); var dir2 = dir.copy();
const dir_slice = @ptrCast([*]const u8, &dir)[0..@sizeOf(Directory)]; const dir_slice = @ptrCast([*]const u8, &dir)[0..@sizeOf(Directory)];
const dir2_slice = @ptrCast([*]const u8, &dir2)[0..@sizeOf(Directory)]; const dir2_slice = @ptrCast([*]const u8, &dir2)[0..@sizeOf(Directory)];
testing.expectEqualSlices(u8, dir_slice, dir2_slice); try testing.expectEqualSlices(u8, dir_slice, dir2_slice);
// Changes to one should not affect the other // Changes to one should not affect the other
dir2.tables[1] = &table0; dir2.tables[1] = &table0;
dir.tables[0] = &table56; dir.tables[0] = &table56;
testing.expect(!std.mem.eql(u8, dir_slice, dir2_slice)); try expect(!std.mem.eql(u8, dir_slice, dir2_slice));
} }
// The labels to jump to after attempting to cause a page fault. This is needed as we don't want to cause an // The labels to jump to after attempting to cause a page fault. This is needed as we don't want to cause an
@ -665,7 +666,7 @@ fn rt_accessUnmappedMem(v_end: u32) void {
var ptr = @intToPtr(*u8, v_end); var ptr = @intToPtr(*u8, v_end);
var value = ptr.*; var value = ptr.*;
// Need this as in release builds the above is optimised out so it needs to be use // Need this as in release builds the above is optimised out so it needs to be use
log.emerg("FAILURE: Value: {}\n", .{value}); log.err("FAILURE: Value: {}\n", .{value});
// This is the label that we return to after processing the page fault // This is the label that we return to after processing the page fault
asm volatile ( asm volatile (
\\.global rt_fault_callback \\.global rt_fault_callback
@ -682,7 +683,8 @@ fn rt_accessMappedMem(v_end: u32) void {
faulted = false; faulted = false;
// Accessing mapped memory doesn't cause a page fault // Accessing mapped memory doesn't cause a page fault
var ptr = @intToPtr(*u8, v_end - PAGE_SIZE_4KB); var ptr = @intToPtr(*u8, v_end - PAGE_SIZE_4KB);
var value = ptr.*; // Print the value to avoid the load from being optimised away
log.info("Read value in mapped memory: {}\n", .{ptr.*});
asm volatile ( asm volatile (
\\.global rt_fault_callback2 \\.global rt_fault_callback2
\\rt_fault_callback2: \\rt_fault_callback2:

View file

@ -3,11 +3,10 @@ const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const expectEqual = std.testing.expectEqual; const expectEqual = std.testing.expectEqual;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList; const ArrayList = std.ArrayList;
const log = std.log.scoped(.pci); const log = std.log.scoped(.pci);
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig"); const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
/// The port address for selecting a 32bit register in the PCI configuration space. /// The port address for selecting a 32bit register in the PCI configuration space.
const CONFIG_ADDRESS: u16 = 0x0CF8; const CONFIG_ADDRESS: u16 = 0x0CF8;
@ -161,7 +160,7 @@ const PciDevice = struct {
// RevisionId is a u8 width, offset 0 // RevisionId is a u8 width, offset 0
const res = device.configReadData(2, .RevisionId); const res = device.configReadData(2, .RevisionId);
expectEqual(res, 0x12); try expectEqual(res, 0x12);
} }
{ {
@ -175,7 +174,7 @@ const PciDevice = struct {
// ProgrammingInterface is a u8 width, offset 8 // ProgrammingInterface is a u8 width, offset 8
const res = device.configReadData(2, .ProgrammingInterface); const res = device.configReadData(2, .ProgrammingInterface);
expectEqual(res, 0xEF); try expectEqual(res, 0xEF);
} }
{ {
@ -189,7 +188,7 @@ const PciDevice = struct {
// Subclass is a u8 width, offset 16 // Subclass is a u8 width, offset 16
const res = device.configReadData(2, .Subclass); const res = device.configReadData(2, .Subclass);
expectEqual(res, 0xCD); try expectEqual(res, 0xCD);
} }
{ {
@ -203,7 +202,7 @@ const PciDevice = struct {
// ClassCode is a u8 width, offset 24 // ClassCode is a u8 width, offset 24
const res = device.configReadData(2, .ClassCode); const res = device.configReadData(2, .ClassCode);
expectEqual(res, 0xAB); try expectEqual(res, 0xAB);
} }
} }
@ -226,7 +225,7 @@ const PciDevice = struct {
// VenderId is a u16 width, offset 0 // VenderId is a u16 width, offset 0
const res = device.configReadData(2, .VenderId); const res = device.configReadData(2, .VenderId);
expectEqual(res, 0xEF12); try expectEqual(res, 0xEF12);
} }
{ {
@ -240,7 +239,7 @@ const PciDevice = struct {
// DeviceId is a u16 width, offset 16 // DeviceId is a u16 width, offset 16
const res = device.configReadData(2, .DeviceId); const res = device.configReadData(2, .DeviceId);
expectEqual(res, 0xABCD); try expectEqual(res, 0xABCD);
} }
} }
@ -263,7 +262,7 @@ const PciDevice = struct {
// BaseAddr0 is a u32 width, offset 0 // BaseAddr0 is a u32 width, offset 0
const res = device.configReadData(2, .BaseAddr0); const res = device.configReadData(2, .BaseAddr0);
expectEqual(res, 0xABCDEF12); try expectEqual(res, 0xABCDEF12);
} }
} }
}; };
@ -317,7 +316,7 @@ pub const PciDeviceInfo = struct {
/// Get a list of all the PCI device. The returned list will needed to be freed by the caller. /// Get a list of all the PCI device. The returned list will needed to be freed by the caller.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - An allocator used for creating the list. /// IN allocator: Allocator - An allocator used for creating the list.
/// ///
/// Return: []PciDeviceInfo /// Return: []PciDeviceInfo
/// The list of PCI devices information. /// The list of PCI devices information.
@ -325,7 +324,7 @@ pub const PciDeviceInfo = struct {
/// Error: Allocator.Error /// Error: Allocator.Error
/// error.OutOfMemory - If there isn't enough memory to create the info list. /// error.OutOfMemory - If there isn't enough memory to create the info list.
/// ///
pub fn getDevices(allocator: *Allocator) Allocator.Error![]PciDeviceInfo { pub fn getDevices(allocator: Allocator) Allocator.Error![]PciDeviceInfo {
// Create an array list for the devices. // Create an array list for the devices.
var pci_device_infos = ArrayList(PciDeviceInfo).init(allocator); var pci_device_infos = ArrayList(PciDeviceInfo).init(allocator);
defer pci_device_infos.deinit(); defer pci_device_infos.deinit();

View file

@ -5,9 +5,8 @@ const log = std.log.scoped(.x86_pic);
const builtin = @import("builtin"); const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig"); const panic = @import("../../panic.zig").panic;
const panic = if (is_test) @import(mock_path ++ "panic_mock.zig").panic else @import("../../panic.zig").panic;
// ---------- // ----------
// Port address for the PIC master and slave registers. // Port address for the PIC master and slave registers.
@ -251,7 +250,7 @@ var spurious_irq_counter: u32 = 0;
/// Arguments: /// Arguments:
/// IN cmd: u8 - The command to send. /// IN cmd: u8 - The command to send.
/// ///
fn sendCommandMaster(cmd: u8) callconv(.Inline) void { inline fn sendCommandMaster(cmd: u8) void {
arch.out(MASTER_COMMAND_REG, cmd); arch.out(MASTER_COMMAND_REG, cmd);
} }
@ -261,7 +260,7 @@ fn sendCommandMaster(cmd: u8) callconv(.Inline) void {
/// Arguments: /// Arguments:
/// IN cmd: u8 - The command to send. /// IN cmd: u8 - The command to send.
/// ///
fn sendCommandSlave(cmd: u8) callconv(.Inline) void { inline fn sendCommandSlave(cmd: u8) void {
arch.out(SLAVE_COMMAND_REG, cmd); arch.out(SLAVE_COMMAND_REG, cmd);
} }
@ -271,7 +270,7 @@ fn sendCommandSlave(cmd: u8) callconv(.Inline) void {
/// Arguments: /// Arguments:
/// IN data: u8 - The data to send. /// IN data: u8 - The data to send.
/// ///
fn sendDataMaster(data: u8) callconv(.Inline) void { inline fn sendDataMaster(data: u8) void {
arch.out(MASTER_DATA_REG, data); arch.out(MASTER_DATA_REG, data);
} }
@ -281,7 +280,7 @@ fn sendDataMaster(data: u8) callconv(.Inline) void {
/// Arguments: /// Arguments:
/// IN data: u8 - The data to send. /// IN data: u8 - The data to send.
/// ///
fn sendDataSlave(data: u8) callconv(.Inline) void { inline fn sendDataSlave(data: u8) void {
arch.out(SLAVE_DATA_REG, data); arch.out(SLAVE_DATA_REG, data);
} }
@ -291,7 +290,7 @@ fn sendDataSlave(data: u8) callconv(.Inline) void {
/// Return: u8 /// Return: u8
/// The data that is stored in the master data register. /// The data that is stored in the master data register.
/// ///
fn readDataMaster() callconv(.Inline) u8 { inline fn readDataMaster() u8 {
return arch.in(u8, MASTER_DATA_REG); return arch.in(u8, MASTER_DATA_REG);
} }
@ -301,7 +300,7 @@ fn readDataMaster() callconv(.Inline) u8 {
/// Return: u8 /// Return: u8
/// The data that is stored in the salve data register. /// The data that is stored in the salve data register.
/// ///
fn readDataSlave() callconv(.Inline) u8 { inline fn readDataSlave() u8 {
return arch.in(u8, SLAVE_DATA_REG); return arch.in(u8, SLAVE_DATA_REG);
} }
@ -311,7 +310,7 @@ fn readDataSlave() callconv(.Inline) u8 {
/// Return: u8 /// Return: u8
/// The data that is stored in the master IRR. /// The data that is stored in the master IRR.
/// ///
fn readMasterIrr() callconv(.Inline) u8 { inline fn readMasterIrr() u8 {
sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR); sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR);
return arch.in(u8, MASTER_STATUS_REG); return arch.in(u8, MASTER_STATUS_REG);
} }
@ -322,7 +321,7 @@ fn readMasterIrr() callconv(.Inline) u8 {
/// Return: u8 /// Return: u8
/// The data that is stored in the slave IRR. /// The data that is stored in the slave IRR.
/// ///
fn readSlaveIrr() callconv(.Inline) u8 { inline fn readSlaveIrr() u8 {
sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR); sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_IRR);
return arch.in(u8, SLAVE_STATUS_REG); return arch.in(u8, SLAVE_STATUS_REG);
} }
@ -333,7 +332,7 @@ fn readSlaveIrr() callconv(.Inline) u8 {
/// Return: u8 /// Return: u8
/// The data that is stored in the master ISR. /// The data that is stored in the master ISR.
/// ///
fn readMasterIsr() callconv(.Inline) u8 { inline fn readMasterIsr() u8 {
sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR); sendCommandMaster(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR);
return arch.in(u8, MASTER_STATUS_REG); return arch.in(u8, MASTER_STATUS_REG);
} }
@ -344,7 +343,7 @@ fn readMasterIsr() callconv(.Inline) u8 {
/// Return: u8 /// Return: u8
/// The data that is stored in the slave ISR. /// The data that is stored in the slave ISR.
/// ///
fn readSlaveIsr() callconv(.Inline) u8 { inline fn readSlaveIsr() u8 {
sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR); sendCommandSlave(OCW3_DEFAULT | OCW3_ACT_ON_READ | OCW3_READ_ISR);
return arch.in(u8, SLAVE_STATUS_REG); return arch.in(u8, SLAVE_STATUS_REG);
} }
@ -529,7 +528,7 @@ test "readDataMaster" {
arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 10) }); arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readDataMaster()); try expectEqual(@as(u8, 10), readDataMaster());
} }
test "readDataSlave" { test "readDataSlave" {
@ -539,7 +538,7 @@ test "readDataSlave" {
arch.addTestParams("in", .{ SLAVE_DATA_REG, @as(u8, 10) }); arch.addTestParams("in", .{ SLAVE_DATA_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readDataSlave()); try expectEqual(@as(u8, 10), readDataSlave());
} }
test "readMasterIrr" { test "readMasterIrr" {
@ -550,7 +549,7 @@ test "readMasterIrr" {
arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0A) }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0A) });
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readMasterIrr()); try expectEqual(@as(u8, 10), readMasterIrr());
} }
test "readSlaveIrr" { test "readSlaveIrr" {
@ -561,7 +560,7 @@ test "readSlaveIrr" {
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0A) }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0A) });
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readSlaveIrr()); try expectEqual(@as(u8, 10), readSlaveIrr());
} }
test "readMasterIsr" { test "readMasterIsr" {
@ -572,7 +571,7 @@ test "readMasterIsr" {
arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) });
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readMasterIsr()); try expectEqual(@as(u8, 10), readMasterIsr());
} }
test "readSlaveIsr" { test "readSlaveIsr" {
@ -583,7 +582,7 @@ test "readSlaveIsr" {
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) }); arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) });
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) }); arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
expectEqual(@as(u8, 10), readSlaveIsr()); try expectEqual(@as(u8, 10), readSlaveIsr());
} }
test "sendEndOfInterrupt master only" { test "sendEndOfInterrupt master only" {
@ -615,17 +614,17 @@ test "sendEndOfInterrupt master and slave" {
test "spuriousIrq not spurious IRQ number" { test "spuriousIrq not spurious IRQ number" {
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
var i: u8 = 0; var i: u8 = 0;
while (i < 16) : (i += 1) { while (i < 16) : (i += 1) {
if (i != 7 and i != 15) { if (i != 7 and i != 15) {
expectEqual(false, spuriousIrq(i)); try expectEqual(false, spuriousIrq(i));
} }
} }
// Post testing // Post testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
// Clean up // Clean up
spurious_irq_counter = 0; spurious_irq_counter = 0;
@ -641,13 +640,13 @@ test "spuriousIrq spurious master IRQ number not spurious" {
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x80) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x80) });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
// Call function // Call function
expectEqual(false, spuriousIrq(7)); try expectEqual(false, spuriousIrq(7));
// Post testing // Post testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
// Clean up // Clean up
spurious_irq_counter = 0; spurious_irq_counter = 0;
@ -663,13 +662,13 @@ test "spuriousIrq spurious master IRQ number spurious" {
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x0) }); arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x0) });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
// Call function // Call function
expectEqual(true, spuriousIrq(7)); try expectEqual(true, spuriousIrq(7));
// Post testing // Post testing
expectEqual(@as(u32, 1), spurious_irq_counter); try expectEqual(@as(u32, 1), spurious_irq_counter);
// Clean up // Clean up
spurious_irq_counter = 0; spurious_irq_counter = 0;
@ -685,13 +684,13 @@ test "spuriousIrq spurious slave IRQ number not spurious" {
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 0x80) }); arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 0x80) });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
// Call function // Call function
expectEqual(false, spuriousIrq(15)); try expectEqual(false, spuriousIrq(15));
// Post testing // Post testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
// Clean up // Clean up
spurious_irq_counter = 0; spurious_irq_counter = 0;
@ -709,13 +708,13 @@ test "spuriousIrq spurious slave IRQ number spurious" {
arch.addTestParams("out", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT }); arch.addTestParams("out", .{ MASTER_COMMAND_REG, OCW2_END_OF_INTERRUPT });
// Pre testing // Pre testing
expectEqual(@as(u32, 0), spurious_irq_counter); try expectEqual(@as(u32, 0), spurious_irq_counter);
// Call function // Call function
expectEqual(true, spuriousIrq(15)); try expectEqual(true, spuriousIrq(15));
// Post testing // Post testing
expectEqual(@as(u32, 1), spurious_irq_counter); try expectEqual(@as(u32, 1), spurious_irq_counter);
// Clean up // Clean up
spurious_irq_counter = 0; spurious_irq_counter = 0;

View file

@ -7,8 +7,7 @@ const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError; const expectError = std.testing.expectError;
const log = std.log.scoped(.x86_pit); const log = std.log.scoped(.x86_pit);
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const irq = @import("irq.zig"); const irq = @import("irq.zig");
const pic = @import("pic.zig"); const pic = @import("pic.zig");
@ -198,7 +197,7 @@ var time_under_1_ns: u32 = undefined;
/// Arguments: /// Arguments:
/// IN cmd: u8 - The command to send to the PIT. /// IN cmd: u8 - The command to send to the PIT.
/// ///
fn sendCommand(cmd: u8) callconv(.Inline) void { inline fn sendCommand(cmd: u8) void {
arch.out(COMMAND_REGISTER, cmd); arch.out(COMMAND_REGISTER, cmd);
} }
@ -211,7 +210,7 @@ fn sendCommand(cmd: u8) callconv(.Inline) void {
/// Return: u8 /// Return: u8
/// The mode the counter is operating in. Use the masks above to get each part. /// The mode the counter is operating in. Use the masks above to get each part.
/// ///
fn readBackCommand(counter: CounterSelect) callconv(.Inline) u8 { inline fn readBackCommand(counter: CounterSelect) u8 {
sendCommand(0xC2); sendCommand(0xC2);
return 0x3F & arch.in(u8, counter.getRegister()); return 0x3F & arch.in(u8, counter.getRegister());
} }
@ -223,7 +222,7 @@ fn readBackCommand(counter: CounterSelect) callconv(.Inline) u8 {
/// IN counter: CounterSelect - The counter port to send the data to. /// IN counter: CounterSelect - The counter port to send the data to.
/// IN data: u8 - The data to send. /// IN data: u8 - The data to send.
/// ///
fn sendDataToCounter(counter: CounterSelect, data: u8) callconv(.Inline) void { inline fn sendDataToCounter(counter: CounterSelect, data: u8) void {
arch.out(counter.getRegister(), data); arch.out(counter.getRegister(), data);
} }
@ -368,7 +367,7 @@ pub fn init() void {
// Set up counter 0 at 10000hz in a square wave mode counting in binary // Set up counter 0 at 10000hz in a square wave mode counting in binary
const freq: u32 = 10000; const freq: u32 = 10000;
setupCounter(CounterSelect.Counter0, freq, OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY) catch |e| { setupCounter(CounterSelect.Counter0, freq, OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY) catch {
panic(@errorReturnTrace(), "Invalid frequency: {}\n", .{freq}); panic(@errorReturnTrace(), "Invalid frequency: {}\n", .{freq});
}; };
@ -412,7 +411,7 @@ test "readBackCommand" {
const actual = readBackCommand(CounterSelect.Counter0); const actual = readBackCommand(CounterSelect.Counter0);
expectEqual(@as(u8, 0x20), actual); try expectEqual(@as(u8, 0x20), actual);
} }
test "sendDataToCounter" { test "sendDataToCounter" {
@ -431,36 +430,14 @@ test "setupCounter lowest frequency" {
defer arch.freeTest(); defer arch.freeTest();
const counter = CounterSelect.Counter0; const counter = CounterSelect.Counter0;
const port = counter.getRegister();
var freq: u32 = 0; var freq: u32 = 0;
// Reload value will be 0 (0x10000), the slowest speed for frequency less than 19
const expected_reload_value: u16 = 0;
// Slowest frequency the PIT can run at
const expected_freq: u32 = 19;
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY; const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
while (freq <= 18) : (freq += 1) { while (freq <= 18) : (freq += 1) {
// arch.addTestParams("out", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8)); try expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
// expectEqual(u32(0), ticks);
// expectEqual(expected_freq, current_freq_0);
// expectEqual(expected_freq, getFrequency());
// // These are the hard coded expected values. Calculated externally to check the internal calculation
// expectEqual(u32(52631578), time_ns);
// expectEqual(u32(947), time_under_1_ns);
} }
// Reset globals
time_ns = 0;
current_freq_0 = 0;
ticks = 0;
} }
test "setupCounter highest frequency" { test "setupCounter highest frequency" {
@ -468,36 +445,13 @@ test "setupCounter highest frequency" {
defer arch.freeTest(); defer arch.freeTest();
const counter = CounterSelect.Counter0; const counter = CounterSelect.Counter0;
const port = counter.getRegister();
// Set the frequency above the maximum // Set the frequency above the maximum
const freq = MAX_FREQUENCY + 10; const freq = MAX_FREQUENCY + 10;
// Reload value will be 1, the fastest speed for frequency greater than MAX_FREQUENCY
const expected_reload_value = 1;
// Slowest frequency the PIT can run at
const expected_freq = MAX_FREQUENCY;
const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY; const mode = OCW_MODE_SQUARE_WAVE_GENERATOR | OCW_BINARY_COUNT_BINARY;
const command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
// arch.addTestParams("out", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8)); try expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
// expectEqual(u32(0), ticks);
// expectEqual(expected_freq, current_freq_0);
// expectEqual(expected_freq, getFrequency());
// // These are the hard coded expected values. Calculated externally to check the internal calculation
// expectEqual(u32(838), time_ns);
// expectEqual(u32(95), time_under_1_ns);
// Reset globals
time_ns = 0;
current_freq_0 = 0;
ticks = 0;
} }
test "setupCounter normal frequency" { test "setupCounter normal frequency" {
@ -519,13 +473,13 @@ test "setupCounter normal frequency" {
setupCounter(counter, freq, mode) catch unreachable; setupCounter(counter, freq, mode) catch unreachable;
expectEqual(@as(u32, 0), ticks); try expectEqual(@as(u32, 0), ticks);
expectEqual(expected_freq, current_freq_0); try expectEqual(expected_freq, current_freq_0);
expectEqual(expected_freq, getFrequency()); try expectEqual(expected_freq, getFrequency());
// These are the hard coded expected values. Calculated externally to check the internal calculation // These are the hard coded expected values. Calculated externally to check the internal calculation
expectEqual(@as(u32, 99730), time_ns); try expectEqual(@as(u32, 99730), time_ns);
expectEqual(@as(u32, 727), time_under_1_ns); try expectEqual(@as(u32, 727), time_under_1_ns);
// Reset globals // Reset globals
time_ns = 0; time_ns = 0;

View file

@ -6,12 +6,11 @@ const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError; const expectError = std.testing.expectError;
const log = std.log.scoped(.x86_rtc); const log = std.log.scoped(.x86_rtc);
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
const pic = @import("pic.zig"); const pic = @import("pic.zig");
const pit = @import("pit.zig"); const pit = @import("pit.zig");
const irq = @import("irq.zig"); const irq = @import("irq.zig");
const cmos = if (is_test) @import(mock_path ++ "cmos_mock.zig") else @import("cmos.zig"); const cmos = if (is_test) @import("../../../../test/mock/kernel/cmos_mock.zig") else @import("cmos.zig");
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
const scheduler = @import("../../scheduler.zig"); const scheduler = @import("../../scheduler.zig");
@ -166,7 +165,7 @@ fn rtcHandler(ctx: *arch.CpuState) usize {
// Need to read status register C // Need to read status register C
// Might need to disable the NMI bit, set to true // Might need to disable the NMI bit, set to true
const reg_c = cmos.readStatusRegister(cmos.StatusRegister.C, false); _ = cmos.readStatusRegister(cmos.StatusRegister.C, false);
return ret_esp; return ret_esp;
} }
@ -290,7 +289,7 @@ pub fn init() void {
enableInterrupts(); enableInterrupts();
// Read status register C to clear any interrupts that may have happened during set up // Read status register C to clear any interrupts that may have happened during set up
const reg_c = cmos.readStatusRegister(cmos.StatusRegister.C, false); _ = cmos.readStatusRegister(cmos.StatusRegister.C, false);
switch (build_options.test_mode) { switch (build_options.test_mode) {
.Initialisation => runtimeTests(), .Initialisation => runtimeTests(),
@ -307,7 +306,7 @@ test "isBusy not busy" {
.{ cmos.StatusRegister.A, false, @as(u8, 0x60) }, .{ cmos.StatusRegister.A, false, @as(u8, 0x60) },
); );
expect(!isBusy()); try expect(!isBusy());
} }
test "isBusy busy" { test "isBusy busy" {
@ -319,7 +318,7 @@ test "isBusy busy" {
.{ cmos.StatusRegister.A, false, @as(u8, 0x80) }, .{ cmos.StatusRegister.A, false, @as(u8, 0x80) },
); );
expect(isBusy()); try expect(isBusy());
} }
test "calcDayOfWeek" { test "calcDayOfWeek" {
@ -337,7 +336,7 @@ test "calcDayOfWeek" {
var actual = calcDayOfWeek(date_time); var actual = calcDayOfWeek(date_time);
var expected = @as(u32, 5); var expected = @as(u32, 5);
expectEqual(expected, actual); try expectEqual(expected, actual);
date_time.day = 20; date_time.day = 20;
date_time.month = 7; date_time.month = 7;
@ -346,7 +345,7 @@ test "calcDayOfWeek" {
actual = calcDayOfWeek(date_time); actual = calcDayOfWeek(date_time);
expected = @as(u32, 6); expected = @as(u32, 6);
expectEqual(expected, actual); try expectEqual(expected, actual);
date_time.day = 9; date_time.day = 9;
date_time.month = 11; date_time.month = 11;
@ -355,7 +354,7 @@ test "calcDayOfWeek" {
actual = calcDayOfWeek(date_time); actual = calcDayOfWeek(date_time);
expected = @as(u32, 1); expected = @as(u32, 1);
expectEqual(expected, actual); try expectEqual(expected, actual);
date_time.day = 1; date_time.day = 1;
date_time.month = 1; date_time.month = 1;
@ -364,7 +363,7 @@ test "calcDayOfWeek" {
actual = calcDayOfWeek(date_time); actual = calcDayOfWeek(date_time);
expected = @as(u32, 6); expected = @as(u32, 6);
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "isBcd not BCD" { test "isBcd not BCD" {
@ -376,7 +375,7 @@ test "isBcd not BCD" {
.{ cmos.StatusRegister.B, false, @as(u8, 0x00) }, .{ cmos.StatusRegister.B, false, @as(u8, 0x00) },
); );
expect(!isBcd()); try expect(!isBcd());
} }
test "isBcd BCD" { test "isBcd BCD" {
@ -388,7 +387,7 @@ test "isBcd BCD" {
.{ cmos.StatusRegister.B, false, @as(u8, 0x04) }, .{ cmos.StatusRegister.B, false, @as(u8, 0x04) },
); );
expect(isBcd()); try expect(isBcd());
} }
test "is12Hr not 12Hr" { test "is12Hr not 12Hr" {
@ -411,7 +410,7 @@ test "is12Hr not 12Hr" {
.{ cmos.StatusRegister.B, false, @as(u8, 0x00) }, .{ cmos.StatusRegister.B, false, @as(u8, 0x00) },
); );
expect(!is12Hr(date_time)); try expect(!is12Hr(date_time));
} }
test "is12Hr 12Hr" { test "is12Hr 12Hr" {
@ -434,24 +433,24 @@ test "is12Hr 12Hr" {
.{ cmos.StatusRegister.B, false, @as(u8, 0x02) }, .{ cmos.StatusRegister.B, false, @as(u8, 0x02) },
); );
expect(is12Hr(date_time)); try expect(is12Hr(date_time));
} }
test "bcdToBinary" { test "bcdToBinary" {
var expected = @as(u32, 59); var expected = @as(u32, 59);
var actual = bcdToBinary(0x59); var actual = bcdToBinary(0x59);
expectEqual(expected, actual); try expectEqual(expected, actual);
expected = @as(u32, 48); expected = @as(u32, 48);
actual = bcdToBinary(0x48); actual = bcdToBinary(0x48);
expectEqual(expected, actual); try expectEqual(expected, actual);
expected = @as(u32, 1); expected = @as(u32, 1);
actual = bcdToBinary(0x01); actual = bcdToBinary(0x01);
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "readRtcRegisters" { test "readRtcRegisters" {
@ -486,7 +485,7 @@ test "readRtcRegisters" {
}; };
const actual = readRtcRegisters(); const actual = readRtcRegisters();
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "readRtc unstable read" { test "readRtc unstable read" {
@ -560,7 +559,7 @@ test "readRtc unstable read" {
}; };
const actual = getDateTime(); const actual = getDateTime();
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "readRtc is BCD" { test "readRtc is BCD" {
@ -613,7 +612,7 @@ test "readRtc is BCD" {
}; };
const actual = getDateTime(); const actual = getDateTime();
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "readRtc is 12 hours" { test "readRtc is 12 hours" {
@ -666,13 +665,13 @@ test "readRtc is 12 hours" {
}; };
const actual = getDateTime(); const actual = getDateTime();
expectEqual(expected, actual); try expectEqual(expected, actual);
} }
test "setRate below 3" { test "setRate below 3" {
expectError(RtcError.RateError, setRate(0)); try expectError(RtcError.RateError, setRate(0));
expectError(RtcError.RateError, setRate(1)); try expectError(RtcError.RateError, setRate(1));
expectError(RtcError.RateError, setRate(2)); try expectError(RtcError.RateError, setRate(2));
} }
test "setRate" { test "setRate" {

View file

@ -151,21 +151,21 @@ test "lcrValue computes the correct value" {
@boolToInt(stop_bit) << 2 | @boolToInt(stop_bit) << 2 |
@boolToInt(parity_bit) << 3 | @boolToInt(parity_bit) << 3 |
@intCast(u8, msb) << 7; @intCast(u8, msb) << 7;
testing.expectEqual(val, expected); try testing.expectEqual(val, expected);
} }
} }
} }
} }
// Check invalid char lengths // Check invalid char lengths
testing.expectError(SerialError.InvalidCharacterLength, lcrValue(4, false, false, 0)); try testing.expectError(SerialError.InvalidCharacterLength, lcrValue(4, false, false, 0));
testing.expectError(SerialError.InvalidCharacterLength, lcrValue(9, false, false, 0)); try testing.expectError(SerialError.InvalidCharacterLength, lcrValue(9, false, false, 0));
} }
test "baudDivisor" { test "baudDivisor" {
// Check invalid baudrates // Check invalid baudrates
inline for ([_]u32{ 0, BAUD_MAX + 1 }) |baud| { inline for ([_]u32{ 0, BAUD_MAX + 1 }) |baud| {
testing.expectError(SerialError.InvalidBaudRate, baudDivisor(baud)); try testing.expectError(SerialError.InvalidBaudRate, baudDivisor(baud));
} }
// Check valid baudrates // Check valid baudrates
@ -173,6 +173,6 @@ test "baudDivisor" {
while (baud <= BAUD_MAX) : (baud += 1) { while (baud <= BAUD_MAX) : (baud += 1) {
const val = try baudDivisor(baud); const val = try baudDivisor(baud);
const expected = @truncate(u16, BAUD_MAX / baud); const expected = @truncate(u16, BAUD_MAX / baud);
testing.expectEqual(val, expected); try testing.expectEqual(val, expected);
} }
} }

View file

@ -3,8 +3,7 @@ const log = std.log.scoped(.x86_syscalls);
const builtin = @import("builtin"); const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path; const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
const testing = std.testing; const testing = std.testing;
const expect = std.testing.expect; const expect = std.testing.expect;
const isr = @import("isr.zig"); const isr = @import("isr.zig");
@ -18,7 +17,7 @@ pub const INTERRUPT: u16 = 0x80;
pub const NUM_HANDLERS: u16 = 256; pub const NUM_HANDLERS: u16 = 256;
/// A syscall handler /// A syscall handler
pub const Handler = fn (ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize; pub const Handler = fn (arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize;
/// Errors that syscall utility functions can throw /// Errors that syscall utility functions can throw
pub const Error = error{ pub const Error = error{
@ -65,7 +64,7 @@ fn handle(ctx: *arch.CpuState) usize {
const syscall = ctx.eax; const syscall = ctx.eax;
if (isValidSyscall(syscall)) { if (isValidSyscall(syscall)) {
if (handlers[syscall]) |handler| { if (handlers[syscall]) |handler| {
const result = handler(ctx, syscallArg(ctx, 0), syscallArg(ctx, 1), syscallArg(ctx, 2), syscallArg(ctx, 3), syscallArg(ctx, 4)); const result = handler(syscallArg(ctx, 0), syscallArg(ctx, 1), syscallArg(ctx, 2), syscallArg(ctx, 3), syscallArg(ctx, 4));
if (result) |res| { if (result) |res| {
ctx.eax = res; ctx.eax = res;
ctx.ebx = 0; ctx.ebx = 0;
@ -112,15 +111,15 @@ pub fn registerSyscall(syscall: usize, handler: Handler) Error!void {
/// Error: syscalls.Error /// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
/// ///
fn syscall0(syscall: usize) callconv(.Inline) syscalls.Error!usize { inline fn syscall0(syscall: usize) syscalls.Error!usize {
const res = asm volatile ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize) : [ret] "={eax}" (-> usize),
: [syscall] "{eax}" (syscall) : [syscall] "{eax}" (syscall),
: "ebx" : "ebx"
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize) : [ret] "={ebx}" (-> usize),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -141,15 +140,15 @@ fn syscall0(syscall: usize) callconv(.Inline) syscalls.Error!usize {
/// Error: syscalls.Error /// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
/// ///
fn syscall1(syscall: usize, arg: usize) callconv(.Inline) syscalls.Error!usize { inline fn syscall1(syscall: usize, arg: usize) syscalls.Error!usize {
const res = asm volatile ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize) : [ret] "={eax}" (-> usize),
: [syscall] "{eax}" (syscall), : [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg) [arg1] "{ebx}" (arg),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize) : [ret] "={ebx}" (-> usize),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -171,16 +170,16 @@ fn syscall1(syscall: usize, arg: usize) callconv(.Inline) syscalls.Error!usize {
/// Error: syscalls.Error /// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
/// ///
fn syscall2(syscall: usize, arg1: usize, arg2: usize) callconv(.Inline) syscalls.Error!usize { inline fn syscall2(syscall: usize, arg1: usize, arg2: usize) syscalls.Error!usize {
const res = asm volatile ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize) : [ret] "={eax}" (-> usize),
: [syscall] "{eax}" (syscall), : [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1), [arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2) [arg2] "{ecx}" (arg2),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize) : [ret] "={ebx}" (-> usize),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -203,17 +202,17 @@ fn syscall2(syscall: usize, arg1: usize, arg2: usize) callconv(.Inline) syscalls
/// Error: syscalls.Error /// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
/// ///
fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) callconv(.Inline) syscalls.Error!usize { inline fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) syscalls.Error!usize {
const res = asm volatile ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize) : [ret] "={eax}" (-> usize),
: [syscall] "{eax}" (syscall), : [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1), [arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2), [arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3) [arg3] "{edx}" (arg3),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize) : [ret] "={ebx}" (-> usize),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -237,18 +236,18 @@ fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) callconv(.Inl
/// Error: syscalls.Error /// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
/// ///
fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) callconv(.Inline) syscalls.Error!usize { inline fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) syscalls.Error!usize {
const res = asm volatile ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize) : [ret] "={eax}" (-> usize),
: [syscall] "{eax}" (syscall), : [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1), [arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2), [arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3), [arg3] "{edx}" (arg3),
[arg4] "{esi}" (arg4) [arg4] "{esi}" (arg4),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize) : [ret] "={ebx}" (-> usize),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -273,19 +272,19 @@ fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize)
/// Error: syscalls.Error /// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
/// ///
fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) callconv(.Inline) syscalls.Error!usize { inline fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
const res = asm volatile ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize) : [ret] "={eax}" (-> usize),
: [syscall] "{eax}" (syscall), : [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1), [arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2), [arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3), [arg3] "{edx}" (arg3),
[arg4] "{esi}" (arg4), [arg4] "{esi}" (arg4),
[arg5] "{edi}" (arg5) [arg5] "{edi}" (arg5),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize) : [ret] "={ebx}" (-> usize),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -304,7 +303,7 @@ fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
/// Return: usize /// Return: usize
/// The syscall argument from the given index. /// The syscall argument from the given index.
/// ///
fn syscallArg(ctx: *arch.CpuState, comptime arg_idx: u32) callconv(.Inline) usize { inline fn syscallArg(ctx: *arch.CpuState, comptime arg_idx: u32) usize {
return switch (arg_idx) { return switch (arg_idx) {
0 => ctx.ebx, 0 => ctx.ebx,
1 => ctx.ecx, 1 => ctx.ecx,
@ -326,7 +325,7 @@ fn syscallArg(ctx: *arch.CpuState, comptime arg_idx: u32) callconv(.Inline) usiz
/// ///
fn makeHandler(comptime syscall: syscalls.Syscall) Handler { fn makeHandler(comptime syscall: syscalls.Syscall) Handler {
return struct { return struct {
fn func(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn func(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
return syscalls.handle(syscall, arg1, arg2, arg3, arg4, arg5); return syscalls.handle(syscall, arg1, arg2, arg3, arg4, arg5);
} }
}.func; }.func;
@ -359,43 +358,69 @@ pub fn init() void {
/// Tests /// Tests
var test_int: u32 = 0; var test_int: u32 = 0;
fn testHandler0(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn testHandler0(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
// Suppress unused variable warnings
_ = arg1;
_ = arg2;
_ = arg3;
_ = arg4;
_ = arg5;
test_int += 1; test_int += 1;
return 0; return 0;
} }
fn testHandler1(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn testHandler1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
// Suppress unused variable warnings
_ = arg2;
_ = arg3;
_ = arg4;
_ = arg5;
test_int += arg1; test_int += arg1;
return 1; return 1;
} }
fn testHandler2(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn testHandler2(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
// Suppress unused variable warnings
_ = arg3;
_ = arg4;
_ = arg5;
test_int += arg1 + arg2; test_int += arg1 + arg2;
return 2; return 2;
} }
fn testHandler3(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn testHandler3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
// Suppress unused variable warnings
_ = arg4;
_ = arg5;
test_int += arg1 + arg2 + arg3; test_int += arg1 + arg2 + arg3;
return 3; return 3;
} }
fn testHandler4(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn testHandler4(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
// Suppress unused variable warnings
_ = arg5;
test_int += arg1 + arg2 + arg3 + arg4; test_int += arg1 + arg2 + arg3 + arg4;
return 4; return 4;
} }
fn testHandler5(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn testHandler5(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
test_int += arg1 + arg2 + arg3 + arg4 + arg5; test_int += arg1 + arg2 + arg3 + arg4 + arg5;
return 5; return 5;
} }
fn testHandler6(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { fn testHandler6(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
// Suppress unused variable warnings
_ = arg1;
_ = arg2;
_ = arg3;
_ = arg4;
_ = arg5;
return syscalls.Error.OutOfMemory; return syscalls.Error.OutOfMemory;
} }
test "registerSyscall returns SyscallExists" { test "registerSyscall returns SyscallExists" {
try registerSyscall(122, testHandler0); try registerSyscall(122, testHandler0);
std.testing.expectError(Error.SyscallExists, registerSyscall(122, testHandler0)); try std.testing.expectError(Error.SyscallExists, registerSyscall(122, testHandler0));
} }
fn runtimeTests() void { fn runtimeTests() void {
@ -459,7 +484,7 @@ fn runtimeTests() void {
panic(@errorReturnTrace(), "FAILURE syscall5 errored: {}\n", .{e}); panic(@errorReturnTrace(), "FAILURE syscall5 errored: {}\n", .{e});
} }
if (syscall0(121)) |res| { if (syscall0(121)) {
panic(@errorReturnTrace(), "FAILURE syscall6\n", .{}); panic(@errorReturnTrace(), "FAILURE syscall6\n", .{});
} else |e| { } else |e| {
if (e != syscalls.Error.OutOfMemory) { if (e != syscalls.Error.OutOfMemory) {

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@ const is_test = builtin.is_test;
const expectEqual = std.testing.expectEqual; const expectEqual = std.testing.expectEqual;
const log = std.log.scoped(.x86_vga); const log = std.log.scoped(.x86_vga);
const build_options = @import("build_options"); const build_options = @import("build_options");
const arch = if (is_test) @import(build_options.arch_mock_path ++ "arch_mock.zig") else @import("arch.zig"); const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
const panic = @import("../../panic.zig").panic; const panic = @import("../../panic.zig").panic;
/// The port address for the VGA register selection. /// The port address for the VGA register selection.
@ -121,7 +121,7 @@ var cursor_scanline_end: u8 = undefined;
/// IN index: u8 - The index to send to the port address to select the register to write data /// IN index: u8 - The index to send to the port address to select the register to write data
/// to. /// to.
/// ///
fn sendPort(index: u8) callconv(.Inline) void { inline fn sendPort(index: u8) void {
arch.out(PORT_ADDRESS, index); arch.out(PORT_ADDRESS, index);
} }
@ -131,7 +131,7 @@ fn sendPort(index: u8) callconv(.Inline) void {
/// Arguments: /// Arguments:
/// IN data: u8 - The data to send to the selected register. /// IN data: u8 - The data to send to the selected register.
/// ///
fn sendData(data: u8) callconv(.Inline) void { inline fn sendData(data: u8) void {
arch.out(PORT_DATA, data); arch.out(PORT_DATA, data);
} }
@ -141,7 +141,7 @@ fn sendData(data: u8) callconv(.Inline) void {
/// Return: u8 /// Return: u8
/// The data in the selected register. /// The data in the selected register.
/// ///
fn getData() callconv(.Inline) u8 { inline fn getData() u8 {
return arch.in(u8, PORT_DATA); return arch.in(u8, PORT_DATA);
} }
/// ///
@ -152,7 +152,7 @@ fn getData() callconv(.Inline) u8 {
// data to. // data to.
/// IN data: u8 - The data to send to the selected register. /// IN data: u8 - The data to send to the selected register.
/// ///
fn sendPortData(index: u8, data: u8) callconv(.Inline) void { inline fn sendPortData(index: u8, data: u8) void {
sendPort(index); sendPort(index);
sendData(data); sendData(data);
} }
@ -167,7 +167,7 @@ fn sendPortData(index: u8, data: u8) callconv(.Inline) void {
/// Return: u8 /// Return: u8
/// The data in the selected register. /// The data in the selected register.
/// ///
fn getPortData(index: u8) callconv(.Inline) u8 { inline fn getPortData(index: u8) u8 {
sendPort(index); sendPort(index);
return getData(); return getData();
} }
@ -303,34 +303,34 @@ test "entryColour" {
var fg = COLOUR_BLACK; var fg = COLOUR_BLACK;
var bg = COLOUR_BLACK; var bg = COLOUR_BLACK;
var res = entryColour(fg, bg); var res = entryColour(fg, bg);
expectEqual(@as(u8, 0x00), res); try expectEqual(@as(u8, 0x00), res);
fg = COLOUR_LIGHT_GREEN; fg = COLOUR_LIGHT_GREEN;
bg = COLOUR_BLACK; bg = COLOUR_BLACK;
res = entryColour(fg, bg); res = entryColour(fg, bg);
expectEqual(@as(u8, 0x0A), res); try expectEqual(@as(u8, 0x0A), res);
fg = COLOUR_BLACK; fg = COLOUR_BLACK;
bg = COLOUR_LIGHT_GREEN; bg = COLOUR_LIGHT_GREEN;
res = entryColour(fg, bg); res = entryColour(fg, bg);
expectEqual(@as(u8, 0xA0), res); try expectEqual(@as(u8, 0xA0), res);
fg = COLOUR_BROWN; fg = COLOUR_BROWN;
bg = COLOUR_LIGHT_GREEN; bg = COLOUR_LIGHT_GREEN;
res = entryColour(fg, bg); res = entryColour(fg, bg);
expectEqual(@as(u8, 0xA6), res); try expectEqual(@as(u8, 0xA6), res);
} }
test "entry" { test "entry" {
const colour = entryColour(COLOUR_BROWN, COLOUR_LIGHT_GREEN); const colour = entryColour(COLOUR_BROWN, COLOUR_LIGHT_GREEN);
expectEqual(@as(u8, 0xA6), colour); try expectEqual(@as(u8, 0xA6), colour);
// Character '0' is 0x30 // Character '0' is 0x30
var video_entry = entry('0', colour); var video_entry = entry('0', colour);
expectEqual(@as(u16, 0xA630), video_entry); try expectEqual(@as(u16, 0xA630), video_entry);
video_entry = entry(0x55, colour); video_entry = entry(0x55, colour);
expectEqual(@as(u16, 0xA655), video_entry); try expectEqual(@as(u16, 0xA655), video_entry);
} }
test "updateCursor width out of bounds" { test "updateCursor width out of bounds" {
@ -447,7 +447,7 @@ test "getCursor 1: 10" {
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0) }); arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0) });
const actual = getCursor(); const actual = getCursor();
expectEqual(expect, actual); try expectEqual(expect, actual);
} }
test "getCursor 2: 0xBEEF" { test "getCursor 2: 0xBEEF" {
@ -463,7 +463,7 @@ test "getCursor 2: 0xBEEF" {
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0xBE) }); arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0xBE) });
const actual = getCursor(); const actual = getCursor();
expectEqual(expect, actual); try expectEqual(expect, actual);
} }
test "enableCursor" { test "enableCursor" {

View file

@ -1,5 +1,5 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = std.builtin;
const testing = std.testing; const testing = std.testing;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
@ -50,7 +50,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
/// ///
pub fn setEntry(self: *Self, idx: IndexType) void { pub fn setEntry(self: *Self, idx: IndexType) void {
if (!self.isSet(idx)) { if (!self.isSet(idx)) {
self.bitmap |= self.indexToBit(idx); self.bitmap |= indexToBit(idx);
self.num_free_entries -= 1; self.num_free_entries -= 1;
} }
} }
@ -64,7 +64,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
/// ///
pub fn clearEntry(self: *Self, idx: IndexType) void { pub fn clearEntry(self: *Self, idx: IndexType) void {
if (self.isSet(idx)) { if (self.isSet(idx)) {
self.bitmap &= ~self.indexToBit(idx); self.bitmap &= ~indexToBit(idx);
self.num_free_entries += 1; self.num_free_entries += 1;
} }
} }
@ -79,7 +79,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
/// Return: BitmapType. /// Return: BitmapType.
/// The bit corresponding to that index but within a single BitmapType. /// The bit corresponding to that index but within a single BitmapType.
/// ///
fn indexToBit(self: *const Self, idx: IndexType) BitmapType { fn indexToBit(idx: IndexType) BitmapType {
return @as(BitmapType, 1) << idx; return @as(BitmapType, 1) << idx;
} }
@ -178,7 +178,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
/// True if the entry is set, else false. /// True if the entry is set, else false.
/// ///
pub fn isSet(self: *const Self, idx: IndexType) bool { pub fn isSet(self: *const Self, idx: IndexType) bool {
return (self.bitmap & self.indexToBit(idx)) != 0; return (self.bitmap & indexToBit(idx)) != 0;
} }
}; };
} }
@ -215,7 +215,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
num_entries: usize, num_entries: usize,
bitmaps: []BitmapType, bitmaps: []BitmapType,
num_free_entries: usize, num_free_entries: usize,
allocator: *std.mem.Allocator, allocator: Allocator,
/// ///
/// Create an instance of this bitmap type. /// Create an instance of this bitmap type.
@ -223,15 +223,15 @@ pub fn Bitmap(comptime BitmapType: type) type {
/// Arguments: /// Arguments:
/// IN num_entries: usize - The number of entries that the bitmap created will have. /// 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. /// The number of BitmapType required to store this many entries will be allocated and each will be zeroed.
/// IN allocator: *std.mem.Allocator - The allocator to use when allocating the BitmapTypes required. /// IN allocator: Allocator - The allocator to use when allocating the BitmapTypes required.
/// ///
/// Return: Self. /// Return: Self.
/// The bitmap instance. /// The bitmap instance.
/// ///
/// Error: std.mem.Allocator.Error /// 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.
/// ///
pub fn init(num_entries: usize, allocator: *std.mem.Allocator) !Self { pub fn init(num_entries: usize, allocator: Allocator) !Self {
const num = std.mem.alignForward(num_entries, ENTRIES_PER_BITMAP) / ENTRIES_PER_BITMAP; const num = std.mem.alignForward(num_entries, ENTRIES_PER_BITMAP) / ENTRIES_PER_BITMAP;
const self = Self{ const self = Self{
.num_bitmaps = num, .num_bitmaps = num,
@ -255,10 +255,10 @@ pub fn Bitmap(comptime BitmapType: type) type {
/// Return: Self /// Return: Self
/// The cloned bitmap /// The cloned bitmap
/// ///
/// Error: std.mem.Allocator.Error /// 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.
/// ///
pub fn clone(self: *const Self) std.mem.Allocator.Error!Self { pub fn clone(self: *const Self) Allocator.Error!Self {
var copy = try init(self.num_entries, self.allocator); var copy = try init(self.num_entries, self.allocator);
var i: usize = 0; var i: usize = 0;
while (i < copy.num_entries) : (i += 1) { while (i < copy.num_entries) : (i += 1) {
@ -294,7 +294,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
return BitmapError.OutOfBounds; return BitmapError.OutOfBounds;
} }
if (!try self.isSet(idx)) { if (!try self.isSet(idx)) {
const bit = self.indexToBit(idx); const bit = indexToBit(idx);
self.bitmaps[idx / ENTRIES_PER_BITMAP] |= bit; self.bitmaps[idx / ENTRIES_PER_BITMAP] |= bit;
self.num_free_entries -= 1; self.num_free_entries -= 1;
} }
@ -315,7 +315,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
return BitmapError.OutOfBounds; return BitmapError.OutOfBounds;
} }
if (try self.isSet(idx)) { if (try self.isSet(idx)) {
const bit = self.indexToBit(idx); const bit = indexToBit(idx);
self.bitmaps[idx / ENTRIES_PER_BITMAP] &= ~bit; self.bitmaps[idx / ENTRIES_PER_BITMAP] &= ~bit;
self.num_free_entries += 1; self.num_free_entries += 1;
} }
@ -331,7 +331,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
/// Return: BitmapType. /// Return: BitmapType.
/// The bit corresponding to that index but within a single BitmapType. /// The bit corresponding to that index but within a single BitmapType.
/// ///
fn indexToBit(self: *const Self, idx: usize) BitmapType { fn indexToBit(idx: usize) BitmapType {
return @as(BitmapType, 1) << @intCast(IndexType, idx % ENTRIES_PER_BITMAP); return @as(BitmapType, 1) << @intCast(IndexType, idx % ENTRIES_PER_BITMAP);
} }
@ -454,73 +454,73 @@ pub fn Bitmap(comptime BitmapType: type) type {
if (idx >= self.num_entries) { if (idx >= self.num_entries) {
return BitmapError.OutOfBounds; return BitmapError.OutOfBounds;
} }
return (self.bitmaps[idx / ENTRIES_PER_BITMAP] & self.indexToBit(idx)) != 0; return (self.bitmaps[idx / ENTRIES_PER_BITMAP] & indexToBit(idx)) != 0;
} }
}; };
} }
test "Comptime setEntry" { test "Comptime setEntry" {
var bmp = ComptimeBitmap(u32).init(); var bmp = ComptimeBitmap(u32).init();
testing.expectEqual(@as(u32, 32), bmp.num_free_entries); try testing.expectEqual(@as(u32, 32), bmp.num_free_entries);
bmp.setEntry(0); bmp.setEntry(0);
testing.expectEqual(@as(u32, 1), bmp.bitmap); try testing.expectEqual(@as(u32, 1), bmp.bitmap);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
bmp.setEntry(1); bmp.setEntry(1);
testing.expectEqual(@as(u32, 3), bmp.bitmap); try testing.expectEqual(@as(u32, 3), bmp.bitmap);
testing.expectEqual(@as(u32, 30), bmp.num_free_entries); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
// Repeat setting entry 1 to make sure state doesn't change // Repeat setting entry 1 to make sure state doesn't change
bmp.setEntry(1); bmp.setEntry(1);
testing.expectEqual(@as(u32, 3), bmp.bitmap); try testing.expectEqual(@as(u32, 3), bmp.bitmap);
testing.expectEqual(@as(u32, 30), bmp.num_free_entries); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
} }
test "Comptime clearEntry" { test "Comptime clearEntry" {
var bmp = ComptimeBitmap(u32).init(); var bmp = ComptimeBitmap(u32).init();
testing.expectEqual(@as(u32, 32), bmp.num_free_entries); try testing.expectEqual(@as(u32, 32), bmp.num_free_entries);
bmp.setEntry(0); bmp.setEntry(0);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
bmp.setEntry(1); bmp.setEntry(1);
testing.expectEqual(@as(u32, 30), bmp.num_free_entries); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
testing.expectEqual(@as(u32, 3), bmp.bitmap); try testing.expectEqual(@as(u32, 3), bmp.bitmap);
bmp.clearEntry(0); bmp.clearEntry(0);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
testing.expectEqual(@as(u32, 2), bmp.bitmap); try testing.expectEqual(@as(u32, 2), bmp.bitmap);
// Repeat to make sure state doesn't change // Repeat to make sure state doesn't change
bmp.clearEntry(0); bmp.clearEntry(0);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
testing.expectEqual(@as(u32, 2), bmp.bitmap); try testing.expectEqual(@as(u32, 2), bmp.bitmap);
// Try clearing an unset entry to make sure state doesn't change // Try clearing an unset entry to make sure state doesn't change
bmp.clearEntry(2); bmp.clearEntry(2);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
testing.expectEqual(@as(u32, 2), bmp.bitmap); try testing.expectEqual(@as(u32, 2), bmp.bitmap);
} }
test "Comptime setFirstFree" { test "Comptime setFirstFree" {
var bmp = ComptimeBitmap(u32).init(); var bmp = ComptimeBitmap(u32).init();
// Allocate the first entry // Allocate the first entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
testing.expectEqual(bmp.bitmap, 1); try testing.expectEqual(bmp.bitmap, 1);
// Allocate the second entry // Allocate the second entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
testing.expectEqual(bmp.bitmap, 3); try testing.expectEqual(bmp.bitmap, 3);
// Make all but the MSB occupied and try to allocate it // 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)); bmp.bitmap = ComptimeBitmap(u32).BITMAP_FULL & ~@as(u32, 1 << (ComptimeBitmap(u32).NUM_ENTRIES - 1));
bmp.num_free_entries = 1; bmp.num_free_entries = 1;
testing.expectEqual(bmp.setFirstFree() orelse unreachable, ComptimeBitmap(u32).NUM_ENTRIES - 1); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, ComptimeBitmap(u32).NUM_ENTRIES - 1);
testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL); try testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL);
// We should no longer be able to allocate any entries // We should no longer be able to allocate any entries
testing.expectEqual(bmp.setFirstFree(), null); try testing.expectEqual(bmp.setFirstFree(), null);
testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL); try testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL);
} }
test "Comptime isSet" { test "Comptime isSet" {
@ -528,127 +528,127 @@ test "Comptime isSet" {
bmp.bitmap = 1; bmp.bitmap = 1;
// Make sure that only the set entry is considered set // Make sure that only the set entry is considered set
testing.expect(bmp.isSet(0)); try testing.expect(bmp.isSet(0));
var i: usize = 1; var i: usize = 1;
while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) { while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) {
testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i))); try testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i)));
} }
bmp.bitmap = 3; bmp.bitmap = 3;
testing.expect(bmp.isSet(0)); try testing.expect(bmp.isSet(0));
testing.expect(bmp.isSet(1)); try testing.expect(bmp.isSet(1));
i = 2; i = 2;
while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) { while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) {
testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i))); try testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i)));
} }
bmp.bitmap = 11; bmp.bitmap = 11;
testing.expect(bmp.isSet(0)); try testing.expect(bmp.isSet(0));
testing.expect(bmp.isSet(1)); try testing.expect(bmp.isSet(1));
testing.expect(!bmp.isSet(2)); try testing.expect(!bmp.isSet(2));
testing.expect(bmp.isSet(3)); try testing.expect(bmp.isSet(3));
i = 4; i = 4;
while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) { while (i < ComptimeBitmap(u32).NUM_ENTRIES) : (i += 1) {
testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i))); try testing.expect(!bmp.isSet(@truncate(ComptimeBitmap(u32).IndexType, i)));
} }
} }
test "Comptime indexToBit" { test "Comptime indexToBit" {
var bmp = ComptimeBitmap(u8).init(); const Type = ComptimeBitmap(u8);
testing.expectEqual(bmp.indexToBit(0), 1); try testing.expectEqual(Type.indexToBit(0), 1);
testing.expectEqual(bmp.indexToBit(1), 2); try testing.expectEqual(Type.indexToBit(1), 2);
testing.expectEqual(bmp.indexToBit(2), 4); try testing.expectEqual(Type.indexToBit(2), 4);
testing.expectEqual(bmp.indexToBit(3), 8); try testing.expectEqual(Type.indexToBit(3), 8);
testing.expectEqual(bmp.indexToBit(4), 16); try testing.expectEqual(Type.indexToBit(4), 16);
testing.expectEqual(bmp.indexToBit(5), 32); try testing.expectEqual(Type.indexToBit(5), 32);
testing.expectEqual(bmp.indexToBit(6), 64); try testing.expectEqual(Type.indexToBit(6), 64);
testing.expectEqual(bmp.indexToBit(7), 128); try testing.expectEqual(Type.indexToBit(7), 128);
} }
test "Comptime setContiguous" { test "Comptime setContiguous" {
var bmp = ComptimeBitmap(u16).init(); var bmp = ComptimeBitmap(u16).init();
// Test trying to set more entries than the bitmap has // Test trying to set more entries than the bitmap has
testing.expectEqual(bmp.setContiguous(bmp.num_free_entries + 1, null), null); try testing.expectEqual(bmp.setContiguous(bmp.num_free_entries + 1, null), null);
testing.expectEqual(bmp.setContiguous(bmp.num_free_entries + 1, 1), null); try testing.expectEqual(bmp.setContiguous(bmp.num_free_entries + 1, 1), null);
// All entries should still be free // All entries should still be free
testing.expectEqual(bmp.num_free_entries, 16); try testing.expectEqual(bmp.num_free_entries, 16);
testing.expectEqual(bmp.bitmap, 0b0000000000000000); try testing.expectEqual(bmp.bitmap, 0b0000000000000000);
testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0); try testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0);
testing.expectEqual(bmp.bitmap, 0b0000000000000111); try testing.expectEqual(bmp.bitmap, 0b0000000000000111);
// Test setting from top // Test setting from top
testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14); try testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14);
testing.expectEqual(bmp.bitmap, 0b1100000000000111); try testing.expectEqual(bmp.bitmap, 0b1100000000000111);
testing.expectEqual(bmp.setContiguous(3, 12), null); try testing.expectEqual(bmp.setContiguous(3, 12), null);
testing.expectEqual(bmp.bitmap, 0b1100000000000111); try testing.expectEqual(bmp.bitmap, 0b1100000000000111);
testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3); try testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3);
testing.expectEqual(bmp.bitmap, 0b1100000000111111); try testing.expectEqual(bmp.bitmap, 0b1100000000111111);
// Test setting beyond the what is available // Test setting beyond the what is available
testing.expectEqual(bmp.setContiguous(9, null), null); try testing.expectEqual(bmp.setContiguous(9, null), null);
testing.expectEqual(bmp.bitmap, 0b1100000000111111); try testing.expectEqual(bmp.bitmap, 0b1100000000111111);
testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6); try testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6);
testing.expectEqual(bmp.bitmap, 0b1111111111111111); try testing.expectEqual(bmp.bitmap, 0b1111111111111111);
// No more are possible // No more are possible
testing.expectEqual(bmp.setContiguous(1, null), null); try testing.expectEqual(bmp.setContiguous(1, null), null);
testing.expectEqual(bmp.bitmap, 0b1111111111111111); try testing.expectEqual(bmp.bitmap, 0b1111111111111111);
testing.expectEqual(bmp.setContiguous(1, 0), null); try testing.expectEqual(bmp.setContiguous(1, 0), null);
testing.expectEqual(bmp.bitmap, 0b1111111111111111); try testing.expectEqual(bmp.bitmap, 0b1111111111111111);
} }
test "setEntry" { test "setEntry" {
var bmp = try Bitmap(u32).init(31, std.testing.allocator); var bmp = try Bitmap(u32).init(31, std.testing.allocator);
defer bmp.deinit(); defer bmp.deinit();
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
try bmp.setEntry(0); try bmp.setEntry(0);
testing.expectEqual(@as(u32, 1), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 1), bmp.bitmaps[0]);
testing.expectEqual(@as(u32, 30), bmp.num_free_entries); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
try bmp.setEntry(1); try bmp.setEntry(1);
testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
testing.expectEqual(@as(u32, 29), bmp.num_free_entries); try testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
// Repeat setting entry 1 to make sure state doesn't change // Repeat setting entry 1 to make sure state doesn't change
try bmp.setEntry(1); try bmp.setEntry(1);
testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
testing.expectEqual(@as(u32, 29), bmp.num_free_entries); try testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.setEntry(31)); try testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.setEntry(31));
testing.expectEqual(@as(u32, 29), bmp.num_free_entries); try testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
} }
test "clearEntry" { test "clearEntry" {
var bmp = try Bitmap(u32).init(32, std.testing.allocator); var bmp = try Bitmap(u32).init(32, std.testing.allocator);
defer bmp.deinit(); defer bmp.deinit();
testing.expectEqual(@as(u32, 32), bmp.num_free_entries); try testing.expectEqual(@as(u32, 32), bmp.num_free_entries);
try bmp.setEntry(0); try bmp.setEntry(0);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
try bmp.setEntry(1); try bmp.setEntry(1);
testing.expectEqual(@as(u32, 30), bmp.num_free_entries); try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
try bmp.clearEntry(0); try bmp.clearEntry(0);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
// Repeat to make sure state doesn't change // Repeat to make sure state doesn't change
try bmp.clearEntry(0); try bmp.clearEntry(0);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
// Try clearing an unset entry to make sure state doesn't change // Try clearing an unset entry to make sure state doesn't change
try bmp.clearEntry(2); try bmp.clearEntry(2);
testing.expectEqual(@as(u32, 31), bmp.num_free_entries); try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]); try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.clearEntry(32)); try testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.clearEntry(32));
} }
test "setFirstFree multiple bitmaps" { test "setFirstFree multiple bitmaps" {
@ -656,19 +656,19 @@ test "setFirstFree multiple bitmaps" {
defer bmp.deinit(); defer bmp.deinit();
// Allocate the first entry // Allocate the first entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
testing.expectEqual(bmp.bitmaps[0], 1); try testing.expectEqual(bmp.bitmaps[0], 1);
// Allocate the second entry // Allocate the second entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
testing.expectEqual(bmp.bitmaps[0], 3); try testing.expectEqual(bmp.bitmaps[0], 3);
// Allocate the entirety of the first bitmap // Allocate the entirety of the first bitmap
var entry: u32 = 2; var entry: u32 = 2;
var expected: u8 = 7; var expected: u8 = 7;
while (entry < Bitmap(u8).ENTRIES_PER_BITMAP) { while (entry < Bitmap(u8).ENTRIES_PER_BITMAP) {
testing.expectEqual(bmp.setFirstFree() orelse unreachable, entry); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, entry);
testing.expectEqual(bmp.bitmaps[0], expected); try testing.expectEqual(bmp.bitmaps[0], expected);
if (entry + 1 < Bitmap(u8).ENTRIES_PER_BITMAP) { if (entry + 1 < Bitmap(u8).ENTRIES_PER_BITMAP) {
entry += 1; entry += 1;
expected = expected * 2 + 1; expected = expected * 2 + 1;
@ -678,14 +678,14 @@ test "setFirstFree multiple bitmaps" {
} }
// Try allocating an entry in the next bitmap // Try allocating an entry in the next bitmap
testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u8).ENTRIES_PER_BITMAP); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u8).ENTRIES_PER_BITMAP);
testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL); try testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL);
testing.expectEqual(bmp.bitmaps[1], 1); try testing.expectEqual(bmp.bitmaps[1], 1);
// We should no longer be able to allocate any entries // We should no longer be able to allocate any entries
testing.expectEqual(bmp.setFirstFree(), null); try testing.expectEqual(bmp.setFirstFree(), null);
testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL); try testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL);
testing.expectEqual(bmp.bitmaps[1], 1); try testing.expectEqual(bmp.bitmaps[1], 1);
} }
test "setFirstFree" { test "setFirstFree" {
@ -693,21 +693,21 @@ test "setFirstFree" {
defer bmp.deinit(); defer bmp.deinit();
// Allocate the first entry // Allocate the first entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
testing.expectEqual(bmp.bitmaps[0], 1); try testing.expectEqual(bmp.bitmaps[0], 1);
// Allocate the second entry // Allocate the second entry
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
testing.expectEqual(bmp.bitmaps[0], 3); try testing.expectEqual(bmp.bitmaps[0], 3);
// Make all but the MSB occupied and try to allocate it // 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)); bmp.bitmaps[0] = Bitmap(u32).BITMAP_FULL & ~@as(u32, 1 << (Bitmap(u32).ENTRIES_PER_BITMAP - 1));
testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u32).ENTRIES_PER_BITMAP - 1); try testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u32).ENTRIES_PER_BITMAP - 1);
testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL); try testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL);
// We should no longer be able to allocate any entries // We should no longer be able to allocate any entries
testing.expectEqual(bmp.setFirstFree(), null); try testing.expectEqual(bmp.setFirstFree(), null);
testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL); try testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL);
} }
test "isSet" { test "isSet" {
@ -716,89 +716,90 @@ test "isSet" {
bmp.bitmaps[0] = 1; bmp.bitmaps[0] = 1;
// Make sure that only the set entry is considered set // Make sure that only the set entry is considered set
testing.expect(try bmp.isSet(0)); try testing.expect(try bmp.isSet(0));
var i: u32 = 1; var i: u32 = 1;
while (i < bmp.num_entries) : (i += 1) { while (i < bmp.num_entries) : (i += 1) {
testing.expect(!try bmp.isSet(i)); try testing.expect(!try bmp.isSet(i));
} }
bmp.bitmaps[0] = 3; bmp.bitmaps[0] = 3;
testing.expect(try bmp.isSet(0)); try testing.expect(try bmp.isSet(0));
testing.expect(try bmp.isSet(1)); try testing.expect(try bmp.isSet(1));
i = 2; i = 2;
while (i < bmp.num_entries) : (i += 1) { while (i < bmp.num_entries) : (i += 1) {
testing.expect(!try bmp.isSet(i)); try testing.expect(!try bmp.isSet(i));
} }
bmp.bitmaps[0] = 11; bmp.bitmaps[0] = 11;
testing.expect(try bmp.isSet(0)); try testing.expect(try bmp.isSet(0));
testing.expect(try bmp.isSet(1)); try testing.expect(try bmp.isSet(1));
testing.expect(!try bmp.isSet(2)); try testing.expect(!try bmp.isSet(2));
testing.expect(try bmp.isSet(3)); try testing.expect(try bmp.isSet(3));
i = 4; i = 4;
while (i < bmp.num_entries) : (i += 1) { while (i < bmp.num_entries) : (i += 1) {
testing.expect(!try bmp.isSet(i)); try testing.expect(!try bmp.isSet(i));
} }
testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.isSet(33)); try testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.isSet(33));
} }
test "indexToBit" { test "indexToBit" {
var bmp = try Bitmap(u8).init(10, std.testing.allocator); const Type = Bitmap(u8);
var bmp = try Type.init(10, std.testing.allocator);
defer bmp.deinit(); defer bmp.deinit();
testing.expectEqual(bmp.indexToBit(0), 1); try testing.expectEqual(Type.indexToBit(0), 1);
testing.expectEqual(bmp.indexToBit(1), 2); try testing.expectEqual(Type.indexToBit(1), 2);
testing.expectEqual(bmp.indexToBit(2), 4); try testing.expectEqual(Type.indexToBit(2), 4);
testing.expectEqual(bmp.indexToBit(3), 8); try testing.expectEqual(Type.indexToBit(3), 8);
testing.expectEqual(bmp.indexToBit(4), 16); try testing.expectEqual(Type.indexToBit(4), 16);
testing.expectEqual(bmp.indexToBit(5), 32); try testing.expectEqual(Type.indexToBit(5), 32);
testing.expectEqual(bmp.indexToBit(6), 64); try testing.expectEqual(Type.indexToBit(6), 64);
testing.expectEqual(bmp.indexToBit(7), 128); try testing.expectEqual(Type.indexToBit(7), 128);
testing.expectEqual(bmp.indexToBit(8), 1); try testing.expectEqual(Type.indexToBit(8), 1);
testing.expectEqual(bmp.indexToBit(9), 2); 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(u4), b1: u4, b2: u4, b3: u4, b4: u4) !void {
testing.expectEqual(@as(u4, b1), bmp.bitmaps[0]); try testing.expectEqual(@as(u4, b1), bmp.bitmaps[0]);
testing.expectEqual(@as(u4, b2), bmp.bitmaps[1]); try testing.expectEqual(@as(u4, b2), bmp.bitmaps[1]);
testing.expectEqual(@as(u4, b3), bmp.bitmaps[2]); try testing.expectEqual(@as(u4, b3), bmp.bitmaps[2]);
testing.expectEqual(@as(u4, b4), bmp.bitmaps[3]); try testing.expectEqual(@as(u4, b4), bmp.bitmaps[3]);
} }
test "setContiguous" { test "setContiguous" {
var bmp = try Bitmap(u4).init(16, std.testing.allocator); var bmp = try Bitmap(u4).init(16, std.testing.allocator);
defer bmp.deinit(); defer bmp.deinit();
// Test trying to set more entries than the bitmap has // Test trying to set more entries than the bitmap has
testing.expectEqual(bmp.setContiguous(bmp.num_entries + 1, null), null); try testing.expectEqual(bmp.setContiguous(bmp.num_entries + 1, null), null);
testing.expectEqual(bmp.setContiguous(bmp.num_entries + 1, 1), null); try testing.expectEqual(bmp.setContiguous(bmp.num_entries + 1, 1), null);
// All entries should still be free // All entries should still be free
testing.expectEqual(bmp.num_free_entries, bmp.num_entries); try testing.expectEqual(bmp.num_free_entries, bmp.num_entries);
testCheckBitmaps(bmp, 0, 0, 0, 0); try testCheckBitmaps(bmp, 0, 0, 0, 0);
testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0); try testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0);
testCheckBitmaps(bmp, 0b0111, 0, 0, 0); try testCheckBitmaps(bmp, 0b0111, 0, 0, 0);
// Test setting from top // Test setting from top
testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14); try testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14);
testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100); try testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100);
testing.expectEqual(bmp.setContiguous(3, 12), null); try testing.expectEqual(bmp.setContiguous(3, 12), null);
testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100); try testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100);
testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3); try testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3);
testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100); try testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100);
// Test setting beyond the what is available // Test setting beyond the what is available
testing.expectEqual(bmp.setContiguous(9, null), null); try testing.expectEqual(bmp.setContiguous(9, null), null);
testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100); try testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100);
testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6); try testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6);
testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111); try testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
// No more are possible // No more are possible
testing.expectEqual(bmp.setContiguous(1, null), null); try testing.expectEqual(bmp.setContiguous(1, null), null);
testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111); try testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
testing.expectEqual(bmp.setContiguous(1, 0), null); try testing.expectEqual(bmp.setContiguous(1, 0), null);
testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111); try testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
} }

View file

@ -78,7 +78,7 @@ test "ASCII toCodePage" {
var ascii: u8 = 0x20; var ascii: u8 = 0x20;
while (ascii < 0x7F) : (ascii += 1) { while (ascii < 0x7F) : (ascii += 1) {
const char = try CodePage.toCodePage(.CP437, ascii); const char = try CodePage.toCodePage(.CP437, ascii);
std.testing.expectEqual(char, ascii); try std.testing.expectEqual(char, ascii);
} }
} }
@ -87,11 +87,11 @@ test "ASCII toWideChar" {
var ascii: u8 = 0x20; var ascii: u8 = 0x20;
while (ascii < 0x7F) : (ascii += 1) { while (ascii < 0x7F) : (ascii += 1) {
const char = CodePage.toWideChar(.CP437, ascii); const char = CodePage.toWideChar(.CP437, ascii);
std.testing.expectEqual(char, ascii); try std.testing.expectEqual(char, ascii);
} }
} }
test "Invalid characters" { test "Invalid characters" {
const char = '€'; const char = '€';
std.testing.expectError(CodePage.Error.InvalidChar, CodePage.toCodePage(.CP437, char)); try std.testing.expectError(CodePage.Error.InvalidChar, CodePage.toCodePage(.CP437, char));
} }

View file

@ -1,7 +1,7 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const Arch = std.Target.Cpu.Arch; const Arch = std.Target.Cpu.Arch;
const Endian = builtin.Endian; const Endian = std.builtin.Endian;
const log = std.log.scoped(.elf); const log = std.log.scoped(.elf);
const testing = std.testing; const testing = std.testing;
@ -366,7 +366,7 @@ pub const Elf = struct {
/// The data associated with each section, or null if a section doesn't have a data area /// The data associated with each section, or null if a section doesn't have a data area
section_data: []?[]const u8, section_data: []?[]const u8,
/// The allocator used /// The allocator used
allocator: *std.mem.Allocator, allocator: std.mem.Allocator,
const Self = @This(); const Self = @This();
@ -389,7 +389,7 @@ pub const Elf = struct {
/// Error.InvalidEndianness - The ELF file wasn't built with the endianness supported by the given architecture /// Error.InvalidEndianness - The ELF file wasn't built with the endianness supported by the given architecture
/// Error.WrongStringTableIndex - The string table index in the header does not point to a StringTable section /// Error.WrongStringTableIndex - The string table index in the header does not point to a StringTable section
/// ///
pub fn init(elf_data: []const u8, arch: Arch, allocator: *std.mem.Allocator) (std.mem.Allocator.Error || Error)!Self { pub fn init(elf_data: []const u8, arch: Arch, allocator: std.mem.Allocator) (std.mem.Allocator.Error || Error)!Self {
const header = std.mem.bytesToValue(Header, elf_data[0..@sizeOf(Header)]); const header = std.mem.bytesToValue(Header, elf_data[0..@sizeOf(Header)]);
if (header.magic_number != 0x464C457F) { if (header.magic_number != 0x464C457F) {
return Error.InvalidMagicNumber; return Error.InvalidMagicNumber;
@ -464,7 +464,7 @@ fn testSetSection(data: []u8, header: SectionHeader, idx: usize) void {
std.mem.copy(u8, dest, @ptrCast([*]const u8, &header)[0..@sizeOf(SectionHeader)]); std.mem.copy(u8, dest, @ptrCast([*]const u8, &header)[0..@sizeOf(SectionHeader)]);
} }
pub fn testInitData(allocator: *std.mem.Allocator, section_name: []const u8, string_section_name: []const u8, file_type: Type, entry_address: usize, flags: u32, section_flags: u32, strings_flags: u32, section_address: usize, strings_address: usize) ![]u8 { pub fn testInitData(allocator: std.mem.Allocator, section_name: []const u8, string_section_name: []const u8, file_type: Type, entry_address: usize, flags: u32, section_flags: u32, strings_flags: u32, section_address: usize, strings_address: usize) ![]u8 {
const is_32_bit = @bitSizeOf(usize) == 32; const is_32_bit = @bitSizeOf(usize) == 32;
const header_size = if (is_32_bit) 0x34 else 0x40; const header_size = if (is_32_bit) 0x34 else 0x40;
const p_header_size = if (is_32_bit) 0x20 else 0x38; const p_header_size = if (is_32_bit) 0x20 else 0x38;
@ -480,7 +480,7 @@ pub fn testInitData(allocator: *std.mem.Allocator, section_name: []const u8, str
64 => .SixtyFourBit, 64 => .SixtyFourBit,
else => unreachable, else => unreachable,
}, },
.endianness = switch (builtin.arch.endian()) { .endianness = switch (builtin.cpu.arch.endian()) {
.Big => .Big, .Big => .Big,
.Little => .Little, .Little => .Little,
}, },
@ -491,7 +491,7 @@ pub fn testInitData(allocator: *std.mem.Allocator, section_name: []const u8, str
.padding2 = 0, .padding2 = 0,
.padding3 = 0, .padding3 = 0,
.file_type = file_type, .file_type = file_type,
.architecture = switch (builtin.arch) { .architecture = switch (builtin.cpu.arch) {
.i386 => .x86, .i386 => .x86,
.x86_64 => .AMD_64, .x86_64 => .AMD_64,
else => unreachable, else => unreachable,
@ -563,62 +563,62 @@ test "init" {
const is_32_bit = @bitSizeOf(usize) == 32; const is_32_bit = @bitSizeOf(usize) == 32;
var data = try testInitData(testing.allocator, section_name, string_section_name, .Executable, 0, 0, 123, 789, 456, 012); var data = try testInitData(testing.allocator, section_name, string_section_name, .Executable, 0, 0, 123, 789, 456, 012);
defer testing.allocator.free(data); defer testing.allocator.free(data);
const elf = try Elf.init(data, builtin.arch, testing.allocator); const elf = try Elf.init(data, builtin.cpu.arch, testing.allocator);
defer elf.deinit(); defer elf.deinit();
testing.expectEqual(elf.header.data_size, if (is_32_bit) .ThirtyTwoBit else .SixtyFourBit); try testing.expectEqual(elf.header.data_size, if (is_32_bit) .ThirtyTwoBit else .SixtyFourBit);
testing.expectEqual(elf.header.file_type, .Executable); try testing.expectEqual(elf.header.file_type, .Executable);
testing.expectEqual(elf.header.architecture, switch (builtin.arch) { try testing.expectEqual(elf.header.architecture, switch (builtin.cpu.arch) {
.i386 => .x86, .i386 => .x86,
.x86_64 => .AMD_64, .x86_64 => .AMD_64,
else => unreachable, else => unreachable,
}); });
testing.expectEqual(elf.header.entry_address, 0); try testing.expectEqual(elf.header.entry_address, 0);
testing.expectEqual(elf.header.flags, 0); try testing.expectEqual(elf.header.flags, 0);
testing.expectEqual(elf.header.section_name_index, 1); try testing.expectEqual(elf.header.section_name_index, 1);
testing.expectEqual(elf.program_headers.len, 0); try testing.expectEqual(elf.program_headers.len, 0);
testing.expectEqual(elf.section_headers.len, 2); try testing.expectEqual(elf.section_headers.len, 2);
const section_one = elf.section_headers[0]; const section_one = elf.section_headers[0];
testing.expectEqual(@as(u32, 0), section_one.name_offset); try testing.expectEqual(@as(u32, 0), section_one.name_offset);
testing.expectEqual(SectionType.ProgramData, section_one.section_type); try testing.expectEqual(SectionType.ProgramData, section_one.section_type);
testing.expectEqual(@as(usize, 123), section_one.flags); try testing.expectEqual(@as(usize, 123), section_one.flags);
testing.expectEqual(@as(usize, 456), section_one.virtual_address); try testing.expectEqual(@as(usize, 456), section_one.virtual_address);
const section_two = elf.section_headers[1]; const section_two = elf.section_headers[1];
testing.expectEqual(section_name.len + 1, section_two.name_offset); try testing.expectEqual(section_name.len + 1, section_two.name_offset);
testing.expectEqual(SectionType.StringTable, section_two.section_type); try testing.expectEqual(SectionType.StringTable, section_two.section_type);
testing.expectEqual(@as(usize, 789), section_two.flags); try testing.expectEqual(@as(usize, 789), section_two.flags);
testing.expectEqual(@as(usize, 012), section_two.virtual_address); try testing.expectEqual(@as(usize, 012), section_two.virtual_address);
testing.expectEqual(@as(usize, 2), elf.section_data.len); try testing.expectEqual(@as(usize, 2), elf.section_data.len);
testing.expectEqual(elf.section_headers[0].size, elf.section_data[0].?.len); try testing.expectEqual(elf.section_headers[0].size, elf.section_data[0].?.len);
for ("some_section" ++ [_]u8{0} ++ "strings" ++ [_]u8{0}) |char, i| { for ("some_section" ++ [_]u8{0} ++ "strings" ++ [_]u8{0}) |char, i| {
testing.expectEqual(char, elf.section_data[1].?[i]); try testing.expectEqual(char, elf.section_data[1].?[i]);
} }
// Test the string section having the wrong type // Test the string section having the wrong type
var section_header = elf.section_headers[1]; var section_header = elf.section_headers[1];
section_header.section_type = .ProgramData; section_header.section_type = .ProgramData;
testSetSection(data, section_header, 1); testSetSection(data, section_header, 1);
testing.expectError(Error.WrongStringTableIndex, Elf.init(data, builtin.arch, testing.allocator)); try testing.expectError(Error.WrongStringTableIndex, Elf.init(data, builtin.cpu.arch, testing.allocator));
testSetSection(data, elf.section_headers[1], 1); testSetSection(data, elf.section_headers[1], 1);
// Test the section_name_index being out of bounds // Test the section_name_index being out of bounds
var header = elf.header; var header = elf.header;
header.section_name_index = 3; header.section_name_index = 3;
testSetHeader(data, header); testSetHeader(data, header);
testing.expectError(Error.WrongStringTableIndex, Elf.init(data, builtin.arch, testing.allocator)); try testing.expectError(Error.WrongStringTableIndex, Elf.init(data, builtin.cpu.arch, testing.allocator));
// Test incorrect endianness // Test incorrect endianness
header = elf.header; header = elf.header;
header.endianness = switch (builtin.arch.endian()) { header.endianness = switch (builtin.cpu.arch.endian()) {
.Big => .Little, .Big => .Little,
.Little => .Big, .Little => .Big,
}; };
testSetHeader(data, header); testSetHeader(data, header);
testing.expectError(Error.InvalidEndianness, Elf.init(data, builtin.arch, testing.allocator)); try testing.expectError(Error.InvalidEndianness, Elf.init(data, builtin.cpu.arch, testing.allocator));
// Test invalid data size // Test invalid data size
header.data_size = switch (@bitSizeOf(usize)) { header.data_size = switch (@bitSizeOf(usize)) {
@ -626,20 +626,20 @@ test "init" {
else => .ThirtyTwoBit, else => .ThirtyTwoBit,
}; };
testSetHeader(data, header); testSetHeader(data, header);
testing.expectError(Error.InvalidDataSize, Elf.init(data, builtin.arch, testing.allocator)); try testing.expectError(Error.InvalidDataSize, Elf.init(data, builtin.cpu.arch, testing.allocator));
// Test invalid architecture // Test invalid architecture
header.architecture = switch (builtin.arch) { header.architecture = switch (builtin.cpu.arch) {
.x86_64 => .Aarch64, .x86_64 => .Aarch64,
else => .AMD_64, else => .AMD_64,
}; };
testSetHeader(data, header); testSetHeader(data, header);
testing.expectError(Error.InvalidArchitecture, Elf.init(data, builtin.arch, testing.allocator)); try testing.expectError(Error.InvalidArchitecture, Elf.init(data, builtin.cpu.arch, testing.allocator));
// Test incorrect magic number // Test incorrect magic number
header.magic_number = 123; header.magic_number = 123;
testSetHeader(data, header); testSetHeader(data, header);
testing.expectError(Error.InvalidMagicNumber, Elf.init(data, builtin.arch, testing.allocator)); try testing.expectError(Error.InvalidMagicNumber, Elf.init(data, builtin.cpu.arch, testing.allocator));
} }
test "getName" { test "getName" {
@ -648,26 +648,23 @@ test "getName" {
var string_section_name = "strings"; var string_section_name = "strings";
const data = try testInitData(testing.allocator, section_name, string_section_name, .Executable, 0, undefined, undefined, undefined, undefined, undefined); const data = try testInitData(testing.allocator, section_name, string_section_name, .Executable, 0, undefined, undefined, undefined, undefined, undefined);
defer testing.allocator.free(data); defer testing.allocator.free(data);
const elf = try Elf.init(data, builtin.arch, testing.allocator); const elf = try Elf.init(data, builtin.cpu.arch, testing.allocator);
defer elf.deinit(); defer elf.deinit();
testing.expectEqualSlices(u8, elf.section_headers[0].getName(elf), section_name); try testing.expectEqualSlices(u8, elf.section_headers[0].getName(elf), section_name);
testing.expectEqualSlices(u8, elf.section_headers[1].getName(elf), string_section_name); try testing.expectEqualSlices(u8, elf.section_headers[1].getName(elf), string_section_name);
} }
test "toNumBits" { test "toNumBits" {
testing.expectEqual(DataSize.ThirtyTwoBit.toNumBits(), 32); try testing.expectEqual(DataSize.ThirtyTwoBit.toNumBits(), 32);
testing.expectEqual(DataSize.SixtyFourBit.toNumBits(), 64); try testing.expectEqual(DataSize.SixtyFourBit.toNumBits(), 64);
} }
test "toEndian" { test "toEndian" {
testing.expectEqual(Endianness.Little.toEndian(), Endian.Little); try testing.expectEqual(Endianness.Little.toEndian(), Endian.Little);
testing.expectEqual(Endianness.Big.toEndian(), Endian.Big); try testing.expectEqual(Endianness.Big.toEndian(), Endian.Big);
} }
test "toArch" { test "toArch" {
const known_architectures = [_]Architecture{ .Sparc, .x86, .MIPS, .PowerPC, .PowerPC_64, .ARM, .AMD_64, .Aarch64, .RISC_V };
const known_archs = [known_architectures.len]Arch{ .sparc, .i386, .mips, .powerpc, .powerpc64, .arm, .x86_64, .aarch64, .riscv32 };
inline for (@typeInfo(Architecture).Enum.fields) |field| { inline for (@typeInfo(Architecture).Enum.fields) |field| {
const architecture = @field(Architecture, field.name); const architecture = @field(Architecture, field.name);
@ -677,9 +674,9 @@ test "toArch" {
}; };
if (!is_known) { if (!is_known) {
testing.expectError(Error.UnknownArchitecture, architecture.toArch()); try testing.expectError(Error.UnknownArchitecture, architecture.toArch());
} else { } else {
testing.expectEqual(architecture.toArch(), switch (architecture) { try testing.expectEqual(architecture.toArch(), switch (architecture) {
.Sparc => .sparc, .Sparc => .sparc,
.x86 => .i386, .x86 => .i386,
.MIPS => .mips, .MIPS => .mips,
@ -696,11 +693,9 @@ test "toArch" {
} }
test "hasData" { test "hasData" {
const no_data = [_]SectionType{ .Unused, .ProgramSpace, .Reserved };
inline for (@typeInfo(SectionType).Enum.fields) |field| { inline for (@typeInfo(SectionType).Enum.fields) |field| {
const sec_type = @field(SectionType, field.name); const sec_type = @field(SectionType, field.name);
const should_not_have_data = sec_type == .Unused or sec_type == .ProgramSpace or sec_type == .Reserved; const should_not_have_data = sec_type == .Unused or sec_type == .ProgramSpace or sec_type == .Reserved;
testing.expectEqual(should_not_have_data, !sec_type.hasData()); try testing.expectEqual(should_not_have_data, !sec_type.hasData());
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,12 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = std.builtin.is_test;
const expect = std.testing.expect; const expect = std.testing.expect;
const expectEqual = std.testing.expectEqual; const expectEqual = std.testing.expectEqual;
const expectError = std.testing.expectError; const expectError = std.testing.expectError;
const expectEqualSlices = std.testing.expectEqualSlices; const expectEqualSlices = std.testing.expectEqualSlices;
const log = std.log.scoped(.initrd); const log = std.log.scoped(.initrd);
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const AutoHashMap = std.AutoHashMap; const AutoHashMap = std.AutoHashMap;
const vfs = @import("vfs.zig"); const vfs = @import("vfs.zig");
@ -43,7 +42,7 @@ pub const InitrdFS = struct {
fs: *vfs.FileSystem, fs: *vfs.FileSystem,
/// The allocator used for allocating memory for opening files. /// The allocator used for allocating memory for opening files.
allocator: *Allocator, allocator: Allocator,
/// The list of files in the ram disk. These will be pointers into the raw ramdisk to save on /// The list of files in the ram disk. These will be pointers into the raw ramdisk to save on
/// allocations. /// allocations.
@ -67,7 +66,7 @@ pub const InitrdFS = struct {
var self = @fieldParentPtr(InitrdFS, "instance", fs.instance); var self = @fieldParentPtr(InitrdFS, "instance", fs.instance);
// As close can't error, if provided with a invalid Node that isn't opened or try to close // As close can't error, if provided with a invalid Node that isn't opened or try to close
// the same file twice, will just do nothing. // the same file twice, will just do nothing.
if (self.opened_files.remove(node)) |entry_node| { if (self.opened_files.remove(node)) {
self.allocator.destroy(node); self.allocator.destroy(node);
} }
} }
@ -84,12 +83,19 @@ pub const InitrdFS = struct {
/// See vfs.FileSystem.write /// See vfs.FileSystem.write
fn write(fs: *const vfs.FileSystem, node: *const vfs.FileNode, bytes: []const u8) (Allocator.Error || vfs.Error)!usize { fn write(fs: *const vfs.FileSystem, node: *const vfs.FileNode, bytes: []const u8) (Allocator.Error || vfs.Error)!usize {
// Suppress unused var warning
_ = fs;
_ = node;
_ = bytes;
return 0; return 0;
} }
/// See vfs.FileSystem.open /// See vfs.FileSystem.open
fn open(fs: *const vfs.FileSystem, dir: *const vfs.DirNode, name: []const u8, flags: vfs.OpenFlags, args: vfs.OpenArgs) (Allocator.Error || vfs.Error)!*vfs.Node { fn open(fs: *const vfs.FileSystem, dir: *const vfs.DirNode, name: []const u8, flags: vfs.OpenFlags, args: vfs.OpenArgs) (Allocator.Error || vfs.Error)!*vfs.Node {
var self = @fieldParentPtr(InitrdFS, "instance", fs.instance); var self = @fieldParentPtr(InitrdFS, "instance", fs.instance);
// Suppress unused var warning
_ = args;
_ = dir;
switch (flags) { switch (flags) {
.CREATE_DIR, .CREATE_FILE, .CREATE_SYMLINK => return vfs.Error.InvalidFlags, .CREATE_DIR, .CREATE_FILE, .CREATE_SYMLINK => return vfs.Error.InvalidFlags,
.NO_CREATION => { .NO_CREATION => {
@ -135,7 +141,7 @@ pub const InitrdFS = struct {
/// ///
/// Arguments: /// Arguments:
/// IN stream: *std.io.FixedBufferStream([]u8) - The stream that contains the raw ramdisk data. /// IN stream: *std.io.FixedBufferStream([]u8) - The stream that contains the raw ramdisk data.
/// IN allocator: *Allocator - The allocator used for initialising any memory needed. /// IN allocator: Allocator - The allocator used for initialising any memory needed.
/// ///
/// Return: *InitrdFS /// Return: *InitrdFS
/// A pointer to the ram disk file system. /// A pointer to the ram disk file system.
@ -150,7 +156,7 @@ pub const InitrdFS = struct {
/// error.OutOfMemory - If there isn't enough memory for initialisation. Any memory /// error.OutOfMemory - If there isn't enough memory for initialisation. Any memory
/// allocated will be freed. /// allocated will be freed.
/// ///
pub fn init(stream: *std.io.FixedBufferStream([]u8), allocator: *Allocator) (Error || error{EndOfStream} || Allocator.Error)!*InitrdFS { pub fn init(stream: *std.io.FixedBufferStream([]u8), allocator: Allocator) (Error || error{EndOfStream} || Allocator.Error)!*InitrdFS {
log.info("Init\n", .{}); log.info("Init\n", .{});
defer log.info("Done\n", .{}); defer log.info("Done\n", .{});
@ -237,15 +243,17 @@ pub const InitrdFS = struct {
/// three files: test1.txt, test2.txt and test3.txt. /// three files: test1.txt, test2.txt and test3.txt.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - The allocator to alloc the raw ramdisk. /// IN allocator: Allocator - The allocator to alloc the raw ramdisk.
/// ///
/// Return: []u8 /// Return: []u8
/// The bytes of the raw ramdisk in memory. /// The bytes of the raw ramdisk in memory.
/// ///
/// Error: Allocator.Error /// Error: Allocator.Error
/// error.OutOfMemory - If there isn't enough memory for the in memory ramdisk. /// error.OutOfMemory - If there isn't enough memory for the in memory ramdisk.
/// FixedBufferStream.WriterError - Writing to the fixed buffer stream failed
/// error.TestExpectedEqual - An equality test failed
/// ///
fn createInitrd(allocator: *Allocator) (Allocator.Error || std.io.FixedBufferStream([]u8).WriteError)![]u8 { fn createInitrd(allocator: Allocator) ![]u8 {
// Create 3 valid ramdisk files in memory // Create 3 valid ramdisk files in memory
const file_names = [_][]const u8{ "test1.txt", "test2.txt", "test3.txt" }; const file_names = [_][]const u8{ "test1.txt", "test2.txt", "test3.txt" };
const file_contents = [_][]const u8{ "This is a test", "This is a test: part 2", "This is a test: the prequel" }; const file_contents = [_][]const u8{ "This is a test", "This is a test: part 2", "This is a test: the prequel" };
@ -275,8 +283,8 @@ fn createInitrd(allocator: *Allocator) (Allocator.Error || std.io.FixedBufferStr
try ramdisk_stream.writer().writeAll(file_contents[i]); try ramdisk_stream.writer().writeAll(file_contents[i]);
} }
// Make sure we are full // Make sure we are full
expectEqual(try ramdisk_stream.getPos(), total_ramdisk_len); try expectEqual(try ramdisk_stream.getPos(), total_ramdisk_len);
expectEqual(try ramdisk_stream.getPos(), try ramdisk_stream.getEndPos()); try expectEqual(try ramdisk_stream.getPos(), try ramdisk_stream.getEndPos());
return ramdisk_bytes; return ramdisk_bytes;
} }
@ -288,24 +296,24 @@ test "init with files valid" {
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator); var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
defer fs.deinit(); defer fs.deinit();
expectEqual(fs.files.len, 3); try expectEqual(fs.files.len, 3);
expectEqualSlices(u8, fs.files[0].name, "test1.txt"); try expectEqualSlices(u8, fs.files[0].name, "test1.txt");
expectEqualSlices(u8, fs.files[1].content, "This is a test: part 2"); try expectEqualSlices(u8, fs.files[1].content, "This is a test: part 2");
expectEqual(fs.opened_files.count(), 0); try expectEqual(fs.opened_files.count(), 0);
} }
test "init with files invalid - invalid number of files" { test "init with files invalid - invalid number of files" {
var ramdisk_bytes = try createInitrd(std.testing.allocator); var ramdisk_bytes = try createInitrd(std.testing.allocator);
// Override the number of files // Override the number of files
std.mem.writeIntSlice(usize, ramdisk_bytes[0..], 10, builtin.endian); std.mem.writeIntSlice(usize, ramdisk_bytes[0..], 10, builtin.cpu.arch.endian());
defer std.testing.allocator.free(ramdisk_bytes); defer std.testing.allocator.free(ramdisk_bytes);
var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes); var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes);
expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator)); try expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator));
// Override the number of files // Override the number of files
std.mem.writeIntSlice(usize, ramdisk_bytes[0..], 0, builtin.endian); std.mem.writeIntSlice(usize, ramdisk_bytes[0..], 0, builtin.cpu.arch.endian());
expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator)); try expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator));
} }
test "init with files invalid - mix - bad" { test "init with files invalid - mix - bad" {
@ -316,23 +324,23 @@ test "init with files invalid - mix - bad" {
{ {
var ramdisk_bytes = try createInitrd(std.testing.allocator); var ramdisk_bytes = try createInitrd(std.testing.allocator);
// Override the first file name length, make is shorter // Override the first file name length, make is shorter
std.mem.writeIntSlice(usize, ramdisk_bytes[4..], 2, builtin.endian); std.mem.writeIntSlice(usize, ramdisk_bytes[4..], 2, builtin.cpu.arch.endian());
defer std.testing.allocator.free(ramdisk_bytes); defer std.testing.allocator.free(ramdisk_bytes);
var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes); var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes);
expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator)); try expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator));
} }
{ {
var ramdisk_bytes = try createInitrd(std.testing.allocator); var ramdisk_bytes = try createInitrd(std.testing.allocator);
// Override the first file name length, make is 4 shorter // Override the first file name length, make is 4 shorter
std.mem.writeIntSlice(usize, ramdisk_bytes[4..], 5, builtin.endian); std.mem.writeIntSlice(usize, ramdisk_bytes[4..], 5, builtin.cpu.arch.endian());
// Override the second file name length, make is 4 longer // Override the second file name length, make is 4 longer
std.mem.writeIntSlice(usize, ramdisk_bytes[35..], 13, builtin.endian); std.mem.writeIntSlice(usize, ramdisk_bytes[35..], 13, builtin.cpu.arch.endian());
defer std.testing.allocator.free(ramdisk_bytes); defer std.testing.allocator.free(ramdisk_bytes);
var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes); var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes);
expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator)); try expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator));
} }
} }
@ -348,7 +356,7 @@ test "init with files cleans memory if OutOfMemory" {
defer std.testing.allocator.free(ramdisk_bytes); defer std.testing.allocator.free(ramdisk_bytes);
var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes); var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes);
expectError(error.OutOfMemory, InitrdFS.init(&initrd_stream, &fa.allocator)); try expectError(error.OutOfMemory, InitrdFS.init(&initrd_stream, fa.allocator()));
} }
} }
@ -360,7 +368,7 @@ test "getRootNode" {
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator); var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
defer fs.deinit(); defer fs.deinit();
expectEqual(fs.fs.getRootNode(fs.fs), &fs.root_node.Dir); try expectEqual(fs.fs.getRootNode(fs.fs), &fs.root_node.Dir);
} }
test "open valid file" { test "open valid file" {
@ -376,21 +384,21 @@ test "open valid file" {
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION); var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
defer file1.close(); defer file1.close();
expectEqual(fs.opened_files.count(), 1); try expectEqual(fs.opened_files.count(), 1);
expectEqualSlices(u8, fs.opened_files.get(@ptrCast(*const vfs.Node, file1)).?.name, "test1.txt"); try expectEqualSlices(u8, fs.opened_files.get(@ptrCast(*const vfs.Node, file1)).?.name, "test1.txt");
var file3_node = try vfs.open("/test3.txt", true, .NO_CREATION, .{}); var file3_node = try vfs.open("/test3.txt", true, .NO_CREATION, .{});
defer file3_node.File.close(); defer file3_node.File.close();
expectEqual(fs.opened_files.count(), 2); try expectEqual(fs.opened_files.count(), 2);
expectEqualSlices(u8, fs.opened_files.get(file3_node).?.content, "This is a test: the prequel"); try expectEqualSlices(u8, fs.opened_files.get(file3_node).?.content, "This is a test: the prequel");
var dir1 = try vfs.openDir("/", .NO_CREATION); var dir1 = try vfs.openDir("/", .NO_CREATION);
expectEqual(&fs.root_node.Dir, dir1); try expectEqual(&fs.root_node.Dir, dir1);
var file2 = &(try dir1.open("test2.txt", .NO_CREATION, .{})).File; var file2 = &(try dir1.open("test2.txt", .NO_CREATION, .{})).File;
defer file2.close(); defer file2.close();
expectEqual(fs.opened_files.count(), 3); try expectEqual(fs.opened_files.count(), 3);
} }
test "open fail with invalid flags" { test "open fail with invalid flags" {
@ -403,21 +411,21 @@ test "open fail with invalid flags" {
try vfs.setRoot(fs.root_node); try vfs.setRoot(fs.root_node);
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_DIR)); try expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_DIR));
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_FILE)); try expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_FILE));
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_SYMLINK)); try expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_SYMLINK));
expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_DIR)); try expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_DIR));
expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_FILE)); try expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_FILE));
expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_SYMLINK)); try expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_SYMLINK));
expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_DIR)); try expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_DIR));
expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_FILE)); try expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_FILE));
expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_SYMLINK)); try expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_SYMLINK));
expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_DIR)); try expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_DIR));
expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_FILE)); try expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_FILE));
expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_SYMLINK)); try expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_SYMLINK));
expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_FILE)); try expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_FILE));
expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_DIR)); try expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_DIR));
expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_SYMLINK)); try expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_SYMLINK));
} }
test "open fail with NoSuchFileOrDir" { test "open fail with NoSuchFileOrDir" {
@ -429,8 +437,8 @@ test "open fail with NoSuchFileOrDir" {
defer fs.deinit(); defer fs.deinit();
try vfs.setRoot(fs.root_node); try vfs.setRoot(fs.root_node);
expectError(error.NoSuchFileOrDir, vfs.openFile("/text10.txt", .NO_CREATION)); try expectError(error.NoSuchFileOrDir, vfs.openFile("/text10.txt", .NO_CREATION));
expectError(error.NoSuchFileOrDir, vfs.openDir("/temp/", .NO_CREATION)); try expectError(error.NoSuchFileOrDir, vfs.openDir("/temp/", .NO_CREATION));
} }
test "open a file, out of memory" { test "open a file, out of memory" {
@ -440,12 +448,12 @@ test "open a file, out of memory" {
defer std.testing.allocator.free(ramdisk_bytes); defer std.testing.allocator.free(ramdisk_bytes);
var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes); var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes);
var fs = try InitrdFS.init(&initrd_stream, &fa.allocator); var fs = try InitrdFS.init(&initrd_stream, fa.allocator());
defer fs.deinit(); defer fs.deinit();
try vfs.setRoot(fs.root_node); try vfs.setRoot(fs.root_node);
expectError(error.OutOfMemory, vfs.openFile("/test1.txt", .NO_CREATION)); try expectError(error.OutOfMemory, vfs.openFile("/test1.txt", .NO_CREATION));
} }
test "open two of the same file" { test "open two of the same file" {
@ -464,14 +472,14 @@ test "open two of the same file" {
const file2 = try vfs.openFile("/test1.txt", .NO_CREATION); const file2 = try vfs.openFile("/test1.txt", .NO_CREATION);
defer file2.close(); defer file2.close();
expectEqual(fs.opened_files.count(), 2); try expectEqual(fs.opened_files.count(), 2);
expect(file1 != file2); try expect(file1 != file2);
var b1: [128]u8 = undefined; var b1: [128]u8 = undefined;
const length1 = try file1.read(b1[0..b1.len]); const length1 = try file1.read(b1[0..b1.len]);
var b2: [128]u8 = undefined; var b2: [128]u8 = undefined;
const length2 = try file2.read(b2[0..b2.len]); const length2 = try file2.read(b2[0..b2.len]);
expectEqualSlices(u8, b1[0..length1], b2[0..length2]); try expectEqualSlices(u8, b1[0..length1], b2[0..length2]);
} }
test "close a file" { test "close a file" {
@ -486,24 +494,22 @@ test "close a file" {
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION); var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
var file1_node = @ptrCast(*const vfs.Node, file1); try expectEqual(fs.opened_files.count(), 1);
expectEqual(fs.opened_files.count(), 1);
var file3_node = try vfs.open("/test3.txt", true, .NO_CREATION, .{}); var file3_node = try vfs.open("/test3.txt", true, .NO_CREATION, .{});
expectEqual(fs.opened_files.count(), 2); try expectEqual(fs.opened_files.count(), 2);
file1.close(); file1.close();
expectEqual(fs.opened_files.count(), 1); try expectEqual(fs.opened_files.count(), 1);
var dir1 = try vfs.openDir("/", .NO_CREATION); var dir1 = try vfs.openDir("/", .NO_CREATION);
expectEqual(&fs.root_node.Dir, dir1); try expectEqual(&fs.root_node.Dir, dir1);
var file2 = &(try dir1.open("test2.txt", .NO_CREATION, .{})).File; var file2 = &(try dir1.open("test2.txt", .NO_CREATION, .{})).File;
defer file2.close(); defer file2.close();
expectEqual(fs.opened_files.count(), 2); try expectEqual(fs.opened_files.count(), 2);
file3_node.File.close(); file3_node.File.close();
expectEqual(fs.opened_files.count(), 1); try expectEqual(fs.opened_files.count(), 1);
} }
test "close a non-opened file" { test "close a non-opened file" {
@ -521,7 +527,7 @@ test "close a non-opened file" {
defer file1.close(); defer file1.close();
// Only one file open // Only one file open
expectEqual(fs.opened_files.count(), 1); try expectEqual(fs.opened_files.count(), 1);
// Craft a Node // Craft a Node
var fake_node = try std.testing.allocator.create(vfs.Node); var fake_node = try std.testing.allocator.create(vfs.Node);
@ -530,7 +536,7 @@ test "close a non-opened file" {
fake_node.File.close(); fake_node.File.close();
// Still only one file open // Still only one file open
expectEqual(fs.opened_files.count(), 1); try expectEqual(fs.opened_files.count(), 1);
} }
test "read a file" { test "read a file" {
@ -549,12 +555,12 @@ test "read a file" {
var bytes1: [128]u8 = undefined; var bytes1: [128]u8 = undefined;
const length1 = try file1.read(bytes1[0..bytes1.len]); const length1 = try file1.read(bytes1[0..bytes1.len]);
expectEqualSlices(u8, bytes1[0..length1], "This is a test"); try expectEqualSlices(u8, bytes1[0..length1], "This is a test");
var bytes2: [5]u8 = undefined; var bytes2: [5]u8 = undefined;
const length2 = try file1.read(bytes2[0..bytes2.len]); const length2 = try file1.read(bytes2[0..bytes2.len]);
expectEqualSlices(u8, bytes2[0..length2], "This "); try expectEqualSlices(u8, bytes2[0..length2], "This ");
} }
test "read a file, invalid/not opened/crafted *const Node" { test "read a file, invalid/not opened/crafted *const Node" {
@ -572,7 +578,7 @@ test "read a file, invalid/not opened/crafted *const Node" {
defer file1.close(); defer file1.close();
// Only one file open // Only one file open
expectEqual(fs.opened_files.count(), 1); try expectEqual(fs.opened_files.count(), 1);
// Craft a Node // Craft a Node
var fake_node = try std.testing.allocator.create(vfs.Node); var fake_node = try std.testing.allocator.create(vfs.Node);
@ -580,10 +586,10 @@ test "read a file, invalid/not opened/crafted *const Node" {
fake_node.* = .{ .File = .{ .fs = fs.fs } }; fake_node.* = .{ .File = .{ .fs = fs.fs } };
var unused: [1]u8 = undefined; var unused: [1]u8 = undefined;
expectError(error.NotOpened, fake_node.File.read(unused[0..unused.len])); try expectError(error.NotOpened, fake_node.File.read(unused[0..unused.len]));
// Still only one file open // Still only one file open
expectEqual(fs.opened_files.count(), 1); try expectEqual(fs.opened_files.count(), 1);
} }
test "write does nothing" { test "write does nothing" {
@ -600,10 +606,10 @@ test "write does nothing" {
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION); var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
defer file1.close(); defer file1.close();
expectEqual(@as(usize, 0), try file1.write("Blah")); try expectEqual(@as(usize, 0), try file1.write("Blah"));
// Unchanged file content // Unchanged file content
expectEqualSlices(u8, fs.opened_files.get(@ptrCast(*const vfs.Node, file1)).?.content, "This is a test"); try expectEqualSlices(u8, fs.opened_files.get(@ptrCast(*const vfs.Node, file1)).?.content, "This is a test");
} }
/// See std.testing.expectEqualSlices. As need our panic. /// See std.testing.expectEqualSlices. As need our panic.
@ -622,10 +628,7 @@ fn expectEqualSlicesClone(comptime T: type, expected: []const T, actual: []const
/// ///
/// Test that we can open, read and close a file /// Test that we can open, read and close a file
/// ///
/// Arguments: fn rt_openReadClose() void {
/// IN allocator: *Allocator - The allocator used for reading.
///
fn rt_openReadClose(allocator: *Allocator) void {
const f1 = vfs.openFile("/ramdisk_test1.txt", .NO_CREATION) catch |e| { const f1 = vfs.openFile("/ramdisk_test1.txt", .NO_CREATION) catch |e| {
panic(@errorReturnTrace(), "FAILURE: Failed to open file: {}\n", .{e}); panic(@errorReturnTrace(), "FAILURE: Failed to open file: {}\n", .{e});
}; };
@ -666,7 +669,7 @@ fn runtimeTests(rd_fs: *InitrdFS) void {
vfs.setRoot(rd_fs.root_node) catch |e| { vfs.setRoot(rd_fs.root_node) catch |e| {
panic(@errorReturnTrace(), "Ramdisk root node isn't a directory node: {}\n", .{e}); panic(@errorReturnTrace(), "Ramdisk root node isn't a directory node: {}\n", .{e});
}; };
rt_openReadClose(rd_fs.allocator); rt_openReadClose();
if (rd_fs.opened_files.count() != 0) { if (rd_fs.opened_files.count() != 0) {
panic(@errorReturnTrace(), "FAILURE: Didn't close all files\n", .{}); panic(@errorReturnTrace(), "FAILURE: Didn't close all files\n", .{});
} }

View file

@ -319,7 +319,7 @@ fn traversePath(path: []const u8, follow_symlinks: bool, flags: OpenFlags, args:
const Self = @This(); const Self = @This();
fn func(split: *std.mem.SplitIterator, node: *Node, follow_links: bool, rec_flags: OpenFlags) (Allocator.Error || Error)!Self { fn func(split: *std.mem.SplitIterator(u8), node: *Node, follow_links: bool, rec_flags: OpenFlags) (Allocator.Error || Error)!Self {
// Get segment string. This will not be unreachable as we've made sure the spliterator has more segments left // Get segment string. This will not be unreachable as we've made sure the spliterator has more segments left
const seg = split.next() orelse unreachable; const seg = split.next() orelse unreachable;
if (split.rest().len == 0) { if (split.rest().len == 0) {
@ -347,7 +347,7 @@ fn traversePath(path: []const u8, follow_symlinks: bool, flags: OpenFlags, args:
}; };
// Split path but skip the first separator character // Split path but skip the first separator character
var split = std.mem.split(path[1..], &[_]u8{SEPARATOR}); var split = std.mem.split(u8, path[1..], &[_]u8{SEPARATOR});
// Traverse directories while we're not at the last segment // Traverse directories while we're not at the last segment
const result = try TraversalParent.func(&split, root, follow_symlinks, .NO_CREATION); const result = try TraversalParent.func(&split, root, follow_symlinks, .NO_CREATION);
@ -569,7 +569,7 @@ const TestFS = struct {
data: ?[]u8, data: ?[]u8,
children: *ArrayList(*@This()), children: *ArrayList(*@This()),
fn deinit(self: *@This(), allocator: *Allocator) void { fn deinit(self: *@This(), allocator: Allocator) void {
allocator.destroy(self.val); allocator.destroy(self.val);
allocator.free(self.name); allocator.free(self.name);
if (self.data) |d| { if (self.data) |d| {
@ -586,7 +586,7 @@ const TestFS = struct {
tree: TreeNode, tree: TreeNode,
fs: *FileSystem, fs: *FileSystem,
allocator: *Allocator, allocator: Allocator,
open_count: usize, open_count: usize,
instance: usize, instance: usize,
@ -635,6 +635,8 @@ const TestFS = struct {
} }
fn close(fs: *const FileSystem, node: *const Node) void { fn close(fs: *const FileSystem, node: *const Node) void {
// Suppress unused var warning
_ = node;
var test_fs = @fieldParentPtr(TestFS, "instance", fs.instance); var test_fs = @fieldParentPtr(TestFS, "instance", fs.instance);
test_fs.open_count -= 1; test_fs.open_count -= 1;
} }
@ -716,7 +718,7 @@ const TestFS = struct {
} }
}; };
fn testInitFs(allocator: *Allocator) !*TestFS { fn testInitFs(allocator: Allocator) !*TestFS {
const fs = try allocator.create(FileSystem); const fs = try allocator.create(FileSystem);
var testfs = try allocator.create(TestFS); var testfs = try allocator.create(TestFS);
var root_node = try allocator.create(Node); var root_node = try allocator.create(Node);
@ -754,7 +756,7 @@ test "mount" {
var testfs = try testInitFs(allocator); var testfs = try testInitFs(allocator);
defer allocator.destroy(testfs); defer allocator.destroy(testfs);
defer testfs.deinit(); defer testfs.deinit();
defer testing.expectEqual(testfs.open_count, 0); defer testing.expectEqual(testfs.open_count, 0) catch @panic("Test fs open count is not zero\n");
testfs.instance = 1; testfs.instance = 1;
root = testfs.tree.val; root = testfs.tree.val;
@ -763,7 +765,7 @@ test "mount" {
var testfs2 = try testInitFs(allocator); var testfs2 = try testInitFs(allocator);
defer allocator.destroy(testfs2); defer allocator.destroy(testfs2);
defer testfs2.deinit(); defer testfs2.deinit();
defer testing.expectEqual(testfs2.open_count, 0); defer testing.expectEqual(testfs2.open_count, 0) catch @panic("Second test fs open count is not zero\n");
testfs2.instance = 2; testfs2.instance = 2;
// Create the dir to mount to // Create the dir to mount to
@ -771,21 +773,21 @@ test "mount" {
defer dir.close(); defer dir.close();
try mount(dir, testfs2.fs); try mount(dir, testfs2.fs);
defer umount(dir); defer umount(dir);
testing.expectError(MountError.DirAlreadyMounted, mount(dir, testfs2.fs)); try testing.expectError(MountError.DirAlreadyMounted, mount(dir, testfs2.fs));
// Ensure the mount worked // Ensure the mount worked
testing.expectEqual((dir.mount orelse unreachable), testfs2.fs.getRootNode(testfs2.fs)); try testing.expectEqual((dir.mount orelse unreachable), testfs2.fs.getRootNode(testfs2.fs));
testing.expectEqual((dir.mount orelse unreachable).fs, testfs2.fs); try testing.expectEqual((dir.mount orelse unreachable).fs, testfs2.fs);
// Create a file within the mounted directory // Create a file within the mounted directory
var test_file = try openFile("/mnt/123.txt", .CREATE_FILE); var test_file = try openFile("/mnt/123.txt", .CREATE_FILE);
defer test_file.close(); defer test_file.close();
testing.expectEqual(@ptrCast(*const FileSystem, testfs2.fs), test_file.fs); try testing.expectEqual(@ptrCast(*const FileSystem, testfs2.fs), test_file.fs);
// This shouldn't be in the root fs // This shouldn't be in the root fs
testing.expectEqual(@as(usize, 1), testfs.tree.children.items.len); try testing.expectEqual(@as(usize, 1), testfs.tree.children.items.len);
testing.expectEqual(@as(usize, 0), testfs.tree.children.items[0].children.items.len); try testing.expectEqual(@as(usize, 0), testfs.tree.children.items[0].children.items.len);
// It should be in the mounted fs // It should be in the mounted fs
testing.expectEqual(@as(usize, 1), testfs2.tree.children.items.len); try testing.expectEqual(@as(usize, 1), testfs2.tree.children.items.len);
testing.expectEqual(test_file, &testfs2.tree.children.items[0].val.File); try testing.expectEqual(test_file, &testfs2.tree.children.items[0].val.File);
} }
test "traversePath" { test "traversePath" {
@ -797,11 +799,11 @@ test "traversePath" {
// Get the root // Get the root
var test_root = try traversePath("/", false, .NO_CREATION, .{}); var test_root = try traversePath("/", false, .NO_CREATION, .{});
testing.expectEqual(test_root, root); try testing.expectEqual(test_root, root);
// Create a file in the root and try to traverse to it // Create a file in the root and try to traverse to it
var child1 = try test_root.Dir.open("child1.txt", .CREATE_FILE, .{}); var child1 = try test_root.Dir.open("child1.txt", .CREATE_FILE, .{});
var child1_traversed = try traversePath("/child1.txt", false, .NO_CREATION, .{}); var child1_traversed = try traversePath("/child1.txt", false, .NO_CREATION, .{});
testing.expectEqual(child1, child1_traversed); try testing.expectEqual(child1, child1_traversed);
// Close the open files // Close the open files
child1.File.close(); child1.File.close();
child1_traversed.File.close(); child1_traversed.File.close();
@ -809,12 +811,12 @@ test "traversePath" {
// Same but with a directory // Same but with a directory
var child2 = try test_root.Dir.open("child2", .CREATE_DIR, .{}); var child2 = try test_root.Dir.open("child2", .CREATE_DIR, .{});
const child2_traversed = try traversePath("/child2", false, .NO_CREATION, .{}); const child2_traversed = try traversePath("/child2", false, .NO_CREATION, .{});
testing.expectEqual(child2, child2_traversed); try testing.expectEqual(child2, child2_traversed);
// Again but with a file within that directory // Again but with a file within that directory
var child3 = try child2.Dir.open("child3.txt", .CREATE_FILE, .{}); var child3 = try child2.Dir.open("child3.txt", .CREATE_FILE, .{});
var child3_traversed = try traversePath("/child2/child3.txt", false, .NO_CREATION, .{}); var child3_traversed = try traversePath("/child2/child3.txt", false, .NO_CREATION, .{});
testing.expectEqual(child3, child3_traversed); try testing.expectEqual(child3, child3_traversed);
// Close the open files // Close the open files
child2.Dir.close(); child2.Dir.close();
child2_traversed.Dir.close(); child2_traversed.Dir.close();
@ -823,38 +825,38 @@ test "traversePath" {
// Create and open a symlink // Create and open a symlink
var child4 = try traversePath("/child2/link", false, .CREATE_SYMLINK, .{ .symlink_target = "/child2/child3.txt" }); var child4 = try traversePath("/child2/link", false, .CREATE_SYMLINK, .{ .symlink_target = "/child2/child3.txt" });
var child4_linked = try traversePath("/child2/link", true, .NO_CREATION, .{}); var child4_linked = try traversePath("/child2/link", true, .NO_CREATION, .{});
testing.expectEqual(child4_linked, child3); try testing.expectEqual(child4_linked, child3);
var child5 = try traversePath("/child4", false, .CREATE_SYMLINK, .{ .symlink_target = "/child2" }); var child5 = try traversePath("/child4", false, .CREATE_SYMLINK, .{ .symlink_target = "/child2" });
var child5_linked = try traversePath("/child4/child3.txt", true, .NO_CREATION, .{}); var child5_linked = try traversePath("/child4/child3.txt", true, .NO_CREATION, .{});
testing.expectEqual(child5_linked, child4_linked); try testing.expectEqual(child5_linked, child4_linked);
child3.File.close(); child3.File.close();
child4.Symlink.close(); child4.Symlink.close();
child5.Symlink.close(); child5.Symlink.close();
child4_linked.File.close(); child4_linked.File.close();
child5_linked.File.close(); child5_linked.File.close();
testing.expectError(Error.NotAbsolutePath, traversePath("abc", false, .NO_CREATION, .{})); try testing.expectError(Error.NotAbsolutePath, traversePath("abc", false, .NO_CREATION, .{}));
testing.expectError(Error.NotAbsolutePath, traversePath("", false, .NO_CREATION, .{})); try testing.expectError(Error.NotAbsolutePath, traversePath("", false, .NO_CREATION, .{}));
testing.expectError(Error.NotAbsolutePath, traversePath("a/", false, .NO_CREATION, .{})); try testing.expectError(Error.NotAbsolutePath, traversePath("a/", false, .NO_CREATION, .{}));
testing.expectError(Error.NoSuchFileOrDir, traversePath("/notadir/abc.txt", false, .NO_CREATION, .{})); try testing.expectError(Error.NoSuchFileOrDir, traversePath("/notadir/abc.txt", false, .NO_CREATION, .{}));
testing.expectError(Error.NoSuchFileOrDir, traversePath("/ ", false, .NO_CREATION, .{})); try testing.expectError(Error.NoSuchFileOrDir, traversePath("/ ", false, .NO_CREATION, .{}));
testing.expectError(Error.NotADirectory, traversePath("/child1.txt/abc.txt", false, .NO_CREATION, .{})); try testing.expectError(Error.NotADirectory, traversePath("/child1.txt/abc.txt", false, .NO_CREATION, .{}));
testing.expectError(Error.NoSymlinkTarget, traversePath("/childX.txt", false, .CREATE_SYMLINK, .{})); try testing.expectError(Error.NoSymlinkTarget, traversePath("/childX.txt", false, .CREATE_SYMLINK, .{}));
// Since we've closed all the files, the open files count should be zero // Since we've closed all the files, the open files count should be zero
testing.expectEqual(testfs.open_count, 0); try testing.expectEqual(testfs.open_count, 0);
} }
test "isAbsolute" { test "isAbsolute" {
testing.expect(isAbsolute("/")); try testing.expect(isAbsolute("/"));
testing.expect(isAbsolute("/abc")); try testing.expect(isAbsolute("/abc"));
testing.expect(isAbsolute("/abc/def")); try testing.expect(isAbsolute("/abc/def"));
testing.expect(isAbsolute("/ a bc/de f")); try testing.expect(isAbsolute("/ a bc/de f"));
testing.expect(isAbsolute("//")); try testing.expect(isAbsolute("//"));
testing.expect(!isAbsolute(" /")); try testing.expect(!isAbsolute(" /"));
testing.expect(!isAbsolute("")); try testing.expect(!isAbsolute(""));
testing.expect(!isAbsolute("abc")); try testing.expect(!isAbsolute("abc"));
testing.expect(!isAbsolute("abc/def")); try testing.expect(!isAbsolute("abc/def"));
} }
test "isDir" { test "isDir" {
@ -862,9 +864,9 @@ test "isDir" {
const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } }; const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } };
const file = Node{ .File = .{ .fs = &fs } }; const file = Node{ .File = .{ .fs = &fs } };
const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } }; const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } };
testing.expect(!symlink.isDir()); try testing.expect(!symlink.isDir());
testing.expect(!file.isDir()); try testing.expect(!file.isDir());
testing.expect(dir.isDir()); try testing.expect(dir.isDir());
} }
test "isFile" { test "isFile" {
@ -872,9 +874,9 @@ test "isFile" {
const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } }; const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } };
const file = Node{ .File = .{ .fs = &fs } }; const file = Node{ .File = .{ .fs = &fs } };
const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } }; const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } };
testing.expect(!dir.isFile()); try testing.expect(!dir.isFile());
testing.expect(!symlink.isFile()); try testing.expect(!symlink.isFile());
testing.expect(file.isFile()); try testing.expect(file.isFile());
} }
test "isSymlink" { test "isSymlink" {
@ -882,9 +884,9 @@ test "isSymlink" {
const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } }; const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } };
const file = Node{ .File = .{ .fs = &fs } }; const file = Node{ .File = .{ .fs = &fs } };
const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } }; const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } };
testing.expect(!dir.isSymlink()); try testing.expect(!dir.isSymlink());
testing.expect(!file.isSymlink()); try testing.expect(!file.isSymlink());
testing.expect(symlink.isSymlink()); try testing.expect(symlink.isSymlink());
} }
test "open" { test "open" {
@ -895,46 +897,46 @@ test "open" {
// Creating a file // Creating a file
var test_node = try openFile("/abc.txt", .CREATE_FILE); var test_node = try openFile("/abc.txt", .CREATE_FILE);
testing.expectEqual(testfs.tree.children.items.len, 1); try testing.expectEqual(testfs.tree.children.items.len, 1);
var tree = testfs.tree.children.items[0]; var tree = testfs.tree.children.items[0];
testing.expect(tree.val.isFile()); try testing.expect(tree.val.isFile());
testing.expectEqual(test_node, &tree.val.File); try testing.expectEqual(test_node, &tree.val.File);
testing.expect(std.mem.eql(u8, tree.name, "abc.txt")); try testing.expect(std.mem.eql(u8, tree.name, "abc.txt"));
testing.expectEqual(tree.data, null); try testing.expectEqual(tree.data, null);
testing.expectEqual(tree.children.items.len, 0); try testing.expectEqual(tree.children.items.len, 0);
// Creating a dir // Creating a dir
var test_dir = try openDir("/def", .CREATE_DIR); var test_dir = try openDir("/def", .CREATE_DIR);
testing.expectEqual(testfs.tree.children.items.len, 2); try testing.expectEqual(testfs.tree.children.items.len, 2);
tree = testfs.tree.children.items[1]; tree = testfs.tree.children.items[1];
testing.expect(tree.val.isDir()); try testing.expect(tree.val.isDir());
testing.expectEqual(test_dir, &tree.val.Dir); try testing.expectEqual(test_dir, &tree.val.Dir);
testing.expect(std.mem.eql(u8, tree.name, "def")); try testing.expect(std.mem.eql(u8, tree.name, "def"));
testing.expectEqual(tree.data, null); try testing.expectEqual(tree.data, null);
testing.expectEqual(tree.children.items.len, 0); try testing.expectEqual(tree.children.items.len, 0);
// Creating a file under a new dir // Creating a file under a new dir
test_node = try openFile("/def/ghi.zig", .CREATE_FILE); test_node = try openFile("/def/ghi.zig", .CREATE_FILE);
testing.expectEqual(testfs.tree.children.items[1].children.items.len, 1); try testing.expectEqual(testfs.tree.children.items[1].children.items.len, 1);
tree = testfs.tree.children.items[1].children.items[0]; tree = testfs.tree.children.items[1].children.items[0];
testing.expect(tree.val.isFile()); try testing.expect(tree.val.isFile());
testing.expectEqual(test_node, &tree.val.File); try testing.expectEqual(test_node, &tree.val.File);
testing.expect(std.mem.eql(u8, tree.name, "ghi.zig")); try testing.expect(std.mem.eql(u8, tree.name, "ghi.zig"));
testing.expectEqual(tree.data, null); try testing.expectEqual(tree.data, null);
testing.expectEqual(tree.children.items.len, 0); try testing.expectEqual(tree.children.items.len, 0);
testing.expectError(Error.NoSuchFileOrDir, openDir("/jkl", .NO_CREATION)); try testing.expectError(Error.NoSuchFileOrDir, openDir("/jkl", .NO_CREATION));
testing.expectError(Error.NoSuchFileOrDir, openFile("/mno.txt", .NO_CREATION)); try testing.expectError(Error.NoSuchFileOrDir, openFile("/mno.txt", .NO_CREATION));
testing.expectError(Error.NoSuchFileOrDir, openFile("/def/pqr.txt", .NO_CREATION)); try testing.expectError(Error.NoSuchFileOrDir, openFile("/def/pqr.txt", .NO_CREATION));
testing.expectError(Error.NoSuchFileOrDir, openDir("/mno/stu", .NO_CREATION)); try testing.expectError(Error.NoSuchFileOrDir, openDir("/mno/stu", .NO_CREATION));
testing.expectError(Error.NoSuchFileOrDir, openFile("/mno/stu.txt", .NO_CREATION)); try testing.expectError(Error.NoSuchFileOrDir, openFile("/mno/stu.txt", .NO_CREATION));
testing.expectError(Error.NotADirectory, openFile("/abc.txt/vxy.md", .NO_CREATION)); try testing.expectError(Error.NotADirectory, openFile("/abc.txt/vxy.md", .NO_CREATION));
testing.expectError(Error.IsADirectory, openFile("/def", .NO_CREATION)); try testing.expectError(Error.IsADirectory, openFile("/def", .NO_CREATION));
testing.expectError(Error.InvalidFlags, openFile("/abc.txt", .CREATE_DIR)); try testing.expectError(Error.InvalidFlags, openFile("/abc.txt", .CREATE_DIR));
testing.expectError(Error.InvalidFlags, openDir("/abc.txt", .CREATE_FILE)); try testing.expectError(Error.InvalidFlags, openDir("/abc.txt", .CREATE_FILE));
testing.expectError(Error.NotAbsolutePath, open("", false, .NO_CREATION, .{})); try testing.expectError(Error.NotAbsolutePath, open("", false, .NO_CREATION, .{}));
testing.expectError(Error.NotAbsolutePath, open("abc", false, .NO_CREATION, .{})); try testing.expectError(Error.NotAbsolutePath, open("abc", false, .NO_CREATION, .{}));
testing.expectError(Error.NoSymlinkTarget, open("/abc", false, .CREATE_SYMLINK, .{})); try testing.expectError(Error.NoSymlinkTarget, open("/abc", false, .CREATE_SYMLINK, .{}));
} }
test "read" { test "read" {
@ -946,40 +948,40 @@ test "read" {
var test_file = try openFile("/foo.txt", .CREATE_FILE); var test_file = try openFile("/foo.txt", .CREATE_FILE);
var f_data = &testfs.tree.children.items[0].data; var f_data = &testfs.tree.children.items[0].data;
var str = "test123"; var str = "test123";
f_data.* = try std.mem.dupe(testing.allocator, u8, str); f_data.* = try Allocator.dupe(testing.allocator, u8, str);
var buffer: [64]u8 = undefined; var buffer: [64]u8 = undefined;
{ {
const length = try test_file.read(buffer[0..str.len]); const length = try test_file.read(buffer[0..str.len]);
testing.expect(std.mem.eql(u8, str, buffer[0..length])); try testing.expect(std.mem.eql(u8, str, buffer[0..length]));
} }
{ {
const length = try test_file.read(buffer[0 .. str.len + 1]); const length = try test_file.read(buffer[0 .. str.len + 1]);
testing.expect(std.mem.eql(u8, str, buffer[0..length])); try testing.expect(std.mem.eql(u8, str, buffer[0..length]));
} }
{ {
const length = try test_file.read(buffer[0 .. str.len + 3]); const length = try test_file.read(buffer[0 .. str.len + 3]);
testing.expect(std.mem.eql(u8, str, buffer[0..length])); try testing.expect(std.mem.eql(u8, str, buffer[0..length]));
} }
{ {
const length = try test_file.read(buffer[0 .. str.len - 1]); const length = try test_file.read(buffer[0 .. str.len - 1]);
testing.expect(std.mem.eql(u8, str[0 .. str.len - 1], buffer[0..length])); try testing.expect(std.mem.eql(u8, str[0 .. str.len - 1], buffer[0..length]));
} }
{ {
const length = try test_file.read(buffer[0..0]); const length = try test_file.read(buffer[0..0]);
testing.expect(std.mem.eql(u8, str[0..0], buffer[0..length])); try testing.expect(std.mem.eql(u8, str[0..0], buffer[0..length]));
} }
// Try reading from a symlink // Try reading from a symlink
var test_link = try openSymlink("/link", "/foo.txt", .CREATE_SYMLINK); var test_link = try openSymlink("/link", "/foo.txt", .CREATE_SYMLINK);
testing.expectEqual(test_link, "/foo.txt"); try testing.expectEqual(test_link, "/foo.txt");
var link_file = try openFile("/link", .NO_CREATION); var link_file = try openFile("/link", .NO_CREATION);
{ {
const length = try link_file.read(buffer[0..]); const length = try link_file.read(buffer[0..]);
testing.expect(std.mem.eql(u8, str[0..], buffer[0..length])); try testing.expect(std.mem.eql(u8, str[0..], buffer[0..length]));
} }
} }
@ -991,19 +993,19 @@ test "write" {
var test_file = try openFile("/foo.txt", .CREATE_FILE); var test_file = try openFile("/foo.txt", .CREATE_FILE);
var f_data = &testfs.tree.children.items[0].data; var f_data = &testfs.tree.children.items[0].data;
testing.expectEqual(f_data.*, null); try testing.expectEqual(f_data.*, null);
var str = "test123"; var str = "test123";
const length = try test_file.write(str); const length = try test_file.write(str);
testing.expect(std.mem.eql(u8, str, f_data.* orelse unreachable)); try testing.expect(std.mem.eql(u8, str, f_data.* orelse unreachable));
testing.expect(length == str.len); try testing.expect(length == str.len);
// Try writing to a symlink // Try writing to a symlink
var test_link = try openSymlink("/link", "/foo.txt", .CREATE_SYMLINK); var test_link = try openSymlink("/link", "/foo.txt", .CREATE_SYMLINK);
testing.expectEqual(test_link, "/foo.txt"); try testing.expectEqual(test_link, "/foo.txt");
var link_file = try openFile("/link", .NO_CREATION); _ = try openFile("/link", .NO_CREATION);
var str2 = "test456"; var str2 = "test456";
const length2 = try test_file.write(str2); _ = try test_file.write(str2);
testing.expect(std.mem.eql(u8, str2, f_data.* orelse unreachable)); try testing.expect(std.mem.eql(u8, str2, f_data.* orelse unreachable));
} }

View file

@ -2,10 +2,9 @@ const std = @import("std");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const testing = std.testing; const testing = std.testing;
const log = std.log.scoped(.heap); const log = std.log.scoped(.heap);
const builtin = @import("builtin"); const builtin = std.builtin;
const is_test = builtin.is_test; const is_test = builtin.is_test;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path;
const vmm = @import("vmm.zig"); const vmm = @import("vmm.zig");
const panic = @import("panic.zig").panic; const panic = @import("panic.zig").panic;
@ -15,7 +14,7 @@ pub const FreeListAllocator = struct {
size: usize, size: usize,
next_free: ?*Header, next_free: ?*Header,
const Self = @Self(); const Self = @This();
/// ///
/// Initialise the header for a free allocation node /// Initialise the header for a free allocation node
@ -33,9 +32,9 @@ pub const FreeListAllocator = struct {
}; };
} }
}; };
const Self = @This();
first_free: ?*Header, first_free: ?*Header,
allocator: Allocator,
/// ///
/// Initialise an empty and free FreeListAllocator /// Initialise an empty and free FreeListAllocator
@ -54,13 +53,13 @@ pub const FreeListAllocator = struct {
if (size <= @sizeOf(Header)) return Error.TooSmall; if (size <= @sizeOf(Header)) return Error.TooSmall;
return FreeListAllocator{ return FreeListAllocator{
.first_free = insertFreeHeader(start, size - @sizeOf(Header), null), .first_free = insertFreeHeader(start, size - @sizeOf(Header), null),
.allocator = .{
.allocFn = alloc,
.resizeFn = resize,
},
}; };
} }
pub fn allocator(self: *Self) Allocator {
return Allocator.init(self, alloc, resize, free);
}
/// ///
/// Create a free header at a specific location /// Create a free header at a specific location
/// ///
@ -86,7 +85,7 @@ pub const FreeListAllocator = struct {
/// IN previous: ?*Header - The previous free node or null if there wasn't one. If null, self.first_free will be set to header, else previous.next_free will be set to header /// IN previous: ?*Header - The previous free node or null if there wasn't one. If null, self.first_free will be set to header, else previous.next_free will be set to header
/// IN header: ?*Header - The header being pointed to. This will be the new value of self.first_free or previous.next_free /// IN header: ?*Header - The header being pointed to. This will be the new value of self.first_free or previous.next_free
/// ///
fn registerFreeHeader(self: *FreeListAllocator, previous: ?*Header, header: ?*Header) void { fn registerFreeHeader(self: *Self, previous: ?*Header, header: ?*Header) void {
if (previous) |p| { if (previous) |p| {
p.next_free = header; p.next_free = header;
} else { } else {
@ -100,8 +99,12 @@ pub const FreeListAllocator = struct {
/// Arguments: /// Arguments:
/// IN self: *FreeListAllocator - The allocator being freed within /// IN self: *FreeListAllocator - The allocator being freed within
/// IN mem: []u8 - The memory to free /// IN mem: []u8 - The memory to free
/// IN alignment: u29 - The alignment used to allocate the memory
/// IN ret_addr: usize - The return address passed by the high-level Allocator API. This is ignored.
/// ///
fn free(self: *FreeListAllocator, mem: []u8) void { fn free(self: *Self, mem: []u8, alignment: u29, ret_addr: usize) void {
_ = alignment;
_ = ret_addr;
const size = std.math.max(mem.len, @sizeOf(Header)); const size = std.math.max(mem.len, @sizeOf(Header));
const addr = @ptrToInt(mem.ptr); const addr = @ptrToInt(mem.ptr);
var header = insertFreeHeader(addr, size - @sizeOf(Header), null); var header = insertFreeHeader(addr, size - @sizeOf(Header), null);
@ -181,23 +184,22 @@ pub const FreeListAllocator = struct {
/// The node before old_mem needs to then point to the new header and the new header needs to point to the next free node. /// The node before old_mem needs to then point to the new header and the new header needs to point to the next free node.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *std.Allocator - The allocator to resize within. /// IN self: *FreeListAllocator - The allocator to resize within.
/// IN old_mem: []u8 - The buffer to resize. /// IN old_mem: []u8 - The buffer to resize.
/// IN old_align: u29 - The original alignment for old_mem. /// IN old_align: u29 - The original alignment for old_mem.
/// IN new_size: usize - What to resize to. /// IN new_size: usize - What to resize to.
/// IN size_alignment: u29 - The alignment that the size should have. /// IN size_alignment: u29 - The alignment that the size should have.
/// IN ret_addr: usize - The return address passed by the high-level Allocator API. This is ignored /// IN ret_addr: usize - The return address passed by the high-level Allocator API. This is ignored
/// ///
/// Return: usize /// Return: ?usize
/// The new size of the buffer, which will be new_size if the operation was successful. /// The new size of the buffer, which will be new_size if the operation was successfull, or null if the operation wasn't successful.
/// ///
/// Error: std.Allocator.Error fn resize(self: *Self, old_mem: []u8, old_align: u29, new_size: usize, size_alignment: u29, ret_addr: usize) ?usize {
/// std.Allocator.Error.OutOfMemory - If there wasn't enough free memory to expand into // Suppress unused var warning
/// _ = old_align;
fn resize(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, size_alignment: u29, ret_addr: usize) Allocator.Error!usize { _ = ret_addr;
var self = @fieldParentPtr(FreeListAllocator, "allocator", allocator);
if (new_size == 0) { if (new_size == 0) {
self.free(old_mem); self.free(old_mem, old_align, ret_addr);
return 0; return 0;
} }
if (new_size == old_mem.len) return new_size; if (new_size == old_mem.len) return new_size;
@ -227,12 +229,12 @@ pub const FreeListAllocator = struct {
if (real_size > old_mem.len) { if (real_size > old_mem.len) {
if (next) |n| { if (next) |n| {
// If the free neighbour isn't big enough then fail // If the free neighbour isn't big enough then fail
if (old_mem.len + n.size + @sizeOf(Header) < real_size) return Allocator.Error.OutOfMemory; if (old_mem.len + n.size + @sizeOf(Header) < real_size) return null;
const size_diff = real_size - old_mem.len; const size_diff = real_size - old_mem.len;
const consumes_whole_neighbour = size_diff == n.size + @sizeOf(Header); const consumes_whole_neighbour = size_diff == n.size + @sizeOf(Header);
// If the space left over in the free neighbour from the resize isn't enough to fit a new node, then fail // If the space left over in the free neighbour from the resize isn't enough to fit a new node, then fail
if (!consumes_whole_neighbour and n.size + @sizeOf(Header) - size_diff < @sizeOf(Header)) return Allocator.Error.OutOfMemory; if (!consumes_whole_neighbour and n.size + @sizeOf(Header) - size_diff < @sizeOf(Header)) return null;
var new_next: ?*Header = n.next_free; var new_next: ?*Header = n.next_free;
// We don't do any splitting when consuming the whole neighbour // We don't do any splitting when consuming the whole neighbour
if (!consumes_whole_neighbour) { if (!consumes_whole_neighbour) {
@ -244,7 +246,7 @@ pub const FreeListAllocator = struct {
return real_size; return real_size;
} }
// The neighbour isn't free so we can't expand into it // The neighbour isn't free so we can't expand into it
return Allocator.Error.OutOfMemory; return null;
} else { } else {
// Shrinking // Shrinking
var size_diff = old_mem.len - real_size; var size_diff = old_mem.len - real_size;
@ -303,7 +305,7 @@ pub const FreeListAllocator = struct {
/// Splitting on the left and right can both happen in one allocation /// Splitting on the left and right can both happen in one allocation
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *std.Allocator - The allocator to use /// IN self: *FreeListAllocator - The allocator to use
/// IN size: usize - The amount of memory requested /// IN size: usize - The amount of memory requested
/// IN alignment: u29 - The alignment that the address of the allocated memory should have /// IN alignment: u29 - The alignment that the address of the allocated memory should have
/// IN size_alignment: u29 - The alignment that the length of the allocated memory should have /// IN size_alignment: u29 - The alignment that the length of the allocated memory should have
@ -315,8 +317,9 @@ pub const FreeListAllocator = struct {
/// Error: std.Allocator.Error /// Error: std.Allocator.Error
/// std.Allocator.Error.OutOfMemory - There wasn't enough memory left to fulfill the request /// std.Allocator.Error.OutOfMemory - There wasn't enough memory left to fulfill the request
/// ///
pub fn alloc(allocator: *Allocator, size: usize, alignment: u29, size_alignment: u29, ret_addr: usize) Allocator.Error![]u8 { pub fn alloc(self: *Self, size: usize, alignment: u29, size_alignment: u29, ret_addr: usize) Allocator.Error![]u8 {
var self = @fieldParentPtr(FreeListAllocator, "allocator", allocator); // Suppress unused var warning
_ = ret_addr;
if (self.first_free == null) return Allocator.Error.OutOfMemory; if (self.first_free == null) return Allocator.Error.OutOfMemory;
// Get the real size being allocated, which is the aligned size or the size of a header (whichever is largest) // Get the real size being allocated, which is the aligned size or the size of a header (whichever is largest)
@ -420,11 +423,11 @@ pub const FreeListAllocator = struct {
var free_list = &(try FreeListAllocator.init(@ptrToInt(region.ptr), size)); var free_list = &(try FreeListAllocator.init(@ptrToInt(region.ptr), size));
var header = @intToPtr(*FreeListAllocator.Header, @ptrToInt(region.ptr)); var header = @intToPtr(*FreeListAllocator.Header, @ptrToInt(region.ptr));
testing.expectEqual(header, free_list.first_free.?); try testing.expectEqual(header, free_list.first_free.?);
testing.expectEqual(header.next_free, null); try testing.expectEqual(header.next_free, null);
testing.expectEqual(header.size, size - @sizeOf(Header)); try testing.expectEqual(header.size, size - @sizeOf(Header));
testing.expectError(Error.TooSmall, FreeListAllocator.init(0, @sizeOf(Header) - 1)); try testing.expectError(Error.TooSmall, FreeListAllocator.init(0, @sizeOf(Header) - 1));
} }
test "alloc" { test "alloc" {
@ -433,79 +436,77 @@ pub const FreeListAllocator = struct {
defer testing.allocator.free(region); defer testing.allocator.free(region);
const start = @ptrToInt(region.ptr); const start = @ptrToInt(region.ptr);
var free_list = &(try FreeListAllocator.init(start, size)); var free_list = &(try FreeListAllocator.init(start, size));
var allocator = &free_list.allocator;
std.debug.warn("", .{}); std.debug.print("", .{});
const alloc0 = try alloc(allocator, 64, 0, 0, @returnAddress()); const alloc0 = try free_list.alloc(64, 0, 0, @returnAddress());
const alloc0_addr = @ptrToInt(alloc0.ptr); const alloc0_addr = @ptrToInt(alloc0.ptr);
// Should be at the start of the heap // Should be at the start of the heap
testing.expectEqual(alloc0_addr, start); try testing.expectEqual(alloc0_addr, start);
// The allocation should have produced a node on the right of the allocation // The allocation should have produced a node on the right of the allocation
var header = @intToPtr(*Header, start + 64); var header = @intToPtr(*Header, start + 64);
testing.expectEqual(header.size, size - 64 - @sizeOf(Header)); try testing.expectEqual(header.size, size - 64 - @sizeOf(Header));
testing.expectEqual(header.next_free, null); try testing.expectEqual(header.next_free, null);
testing.expectEqual(free_list.first_free, header); try testing.expectEqual(free_list.first_free, header);
std.debug.warn("", .{}); std.debug.print("", .{});
// 64 bytes aligned to 4 bytes // 64 bytes aligned to 4 bytes
const alloc1 = try alloc(allocator, 64, 4, 0, @returnAddress()); const alloc1 = try free_list.alloc(64, 4, 0, @returnAddress());
const alloc1_addr = @ptrToInt(alloc1.ptr); const alloc1_addr = @ptrToInt(alloc1.ptr);
const alloc1_end = alloc1_addr + alloc1.len; const alloc1_end = alloc1_addr + alloc1.len;
// Should be to the right of the first allocation, with some alignment padding in between // Should be to the right of the first allocation, with some alignment padding in between
const alloc0_end = alloc0_addr + alloc0.len; const alloc0_end = alloc0_addr + alloc0.len;
testing.expect(alloc0_end <= alloc1_addr); try testing.expect(alloc0_end <= alloc1_addr);
testing.expectEqual(std.mem.alignForward(alloc0_end, 4), alloc1_addr); try testing.expectEqual(std.mem.alignForward(alloc0_end, 4), alloc1_addr);
// It should have produced a node on the right // It should have produced a node on the right
header = @intToPtr(*Header, alloc1_end); header = @intToPtr(*Header, alloc1_end);
testing.expectEqual(header.size, size - (alloc1_end - start) - @sizeOf(Header)); try testing.expectEqual(header.size, size - (alloc1_end - start) - @sizeOf(Header));
testing.expectEqual(header.next_free, null); try testing.expectEqual(header.next_free, null);
testing.expectEqual(free_list.first_free, header); try testing.expectEqual(free_list.first_free, header);
const alloc2 = try alloc(allocator, 64, 256, 0, @returnAddress()); const alloc2 = try free_list.alloc(64, 256, 0, @returnAddress());
const alloc2_addr = @ptrToInt(alloc2.ptr); const alloc2_addr = @ptrToInt(alloc2.ptr);
const alloc2_end = alloc2_addr + alloc2.len; const alloc2_end = alloc2_addr + alloc2.len;
testing.expect(alloc1_end < alloc2_addr); try testing.expect(alloc1_end < alloc2_addr);
// There should be a free node to the right of alloc2 // There should be a free node to the right of alloc2
const second_header = @intToPtr(*Header, alloc2_end); const second_header = @intToPtr(*Header, alloc2_end);
testing.expectEqual(second_header.size, size - (alloc2_end - start) - @sizeOf(Header)); try testing.expectEqual(second_header.size, size - (alloc2_end - start) - @sizeOf(Header));
testing.expectEqual(second_header.next_free, null); try testing.expectEqual(second_header.next_free, null);
// There should be a free node in between alloc1 and alloc2 due to the large alignment padding (depends on the allocation by the testing allocator, hence the check) // There should be a free node in between alloc1 and alloc2 due to the large alignment padding (depends on the allocation by the testing allocator, hence the check)
if (alloc2_addr - alloc1_end >= @sizeOf(Header)) { if (alloc2_addr - alloc1_end >= @sizeOf(Header)) {
header = @intToPtr(*Header, alloc1_end); header = @intToPtr(*Header, alloc1_end);
testing.expectEqual(free_list.first_free, header); try testing.expectEqual(free_list.first_free, header);
testing.expectEqual(header.next_free, second_header); try testing.expectEqual(header.next_free, second_header);
} }
// Try allocating something smaller than @sizeOf(Header). This should scale up to @sizeOf(Header) // Try allocating something smaller than @sizeOf(Header). This should scale up to @sizeOf(Header)
var alloc3 = try alloc(allocator, 1, 0, 0, @returnAddress()); var alloc3 = try free_list.alloc(1, 0, 0, @returnAddress());
const alloc3_addr = @ptrToInt(alloc3.ptr); const alloc3_addr = @ptrToInt(alloc3.ptr);
const alloc3_end = alloc3_addr + @sizeOf(Header); const alloc3_end = alloc3_addr + @sizeOf(Header);
const header2 = @intToPtr(*Header, alloc3_end); const header2 = @intToPtr(*Header, alloc3_end);
// The new free node on the right should be the first one free // The new free node on the right should be the first one free
testing.expectEqual(free_list.first_free, header2); try testing.expectEqual(free_list.first_free, header2);
// And it should point to the free node on the right of alloc2 // And it should point to the free node on the right of alloc2
testing.expectEqual(header2.next_free, second_header); try testing.expectEqual(header2.next_free, second_header);
// Attempting to allocate more than the size of the largest free node should fail // Attempting to allocate more than the size of the largest free node should fail
const remaining_size = second_header.size + @sizeOf(Header); const remaining_size = second_header.size + @sizeOf(Header);
testing.expectError(Allocator.Error.OutOfMemory, alloc(&free_list.allocator, remaining_size + 1, 0, 0, @returnAddress())); try testing.expectError(Allocator.Error.OutOfMemory, free_list.alloc(remaining_size + 1, 0, 0, @returnAddress()));
// Alloc a non aligned to header // Alloc a non aligned to header
var alloc4 = try alloc(allocator, 13, 1, 0, @returnAddress()); var alloc4 = try free_list.alloc(13, 1, 0, @returnAddress());
const alloc4_addr = @ptrToInt(alloc4.ptr); const alloc4_addr = @ptrToInt(alloc4.ptr);
const alloc4_end = alloc4_addr + std.mem.alignForward(13, @alignOf(Header)); const alloc4_end = alloc4_addr + std.mem.alignForward(13, @alignOf(Header));
const header3 = @intToPtr(*Header, alloc4_end); const header3 = @intToPtr(*Header, alloc4_end);
const header4 = @intToPtr(*Header, alloc4_addr);
// We should still have a length of 13 // We should still have a length of 13
testing.expectEqual(alloc4.len, 13); try testing.expectEqual(alloc4.len, 13);
// But this should be aligned to Header (4) // But this should be aligned to Header (4)
testing.expectEqual(alloc4_end - alloc4_addr, 16); try testing.expectEqual(alloc4_end - alloc4_addr, 16);
// Previous header should now point to the next header // Previous header should now point to the next header
testing.expectEqual(header2.next_free, header3); try testing.expectEqual(header2.next_free, header3);
} }
test "free" { test "free" {
@ -514,74 +515,72 @@ pub const FreeListAllocator = struct {
defer testing.allocator.free(region); defer testing.allocator.free(region);
const start = @ptrToInt(region.ptr); const start = @ptrToInt(region.ptr);
var free_list = &(try FreeListAllocator.init(start, size)); var free_list = &(try FreeListAllocator.init(start, size));
var allocator = &free_list.allocator;
var alloc0 = try alloc(allocator, 128, 0, 0, @returnAddress()); var alloc0 = try free_list.alloc(128, 0, 0, @returnAddress());
var alloc1 = try alloc(allocator, 256, 0, 0, @returnAddress()); var alloc1 = try free_list.alloc(256, 0, 0, @returnAddress());
var alloc2 = try alloc(allocator, 64, 0, 0, @returnAddress()); var alloc2 = try free_list.alloc(64, 0, 0, @returnAddress());
// There should be a single free node after alloc2 // There should be a single free node after alloc2
const free_node3 = @intToPtr(*Header, @ptrToInt(alloc2.ptr) + alloc2.len); const free_node3 = @intToPtr(*Header, @ptrToInt(alloc2.ptr) + alloc2.len);
testing.expectEqual(free_list.first_free, free_node3); try testing.expectEqual(free_list.first_free, free_node3);
testing.expectEqual(free_node3.size, size - alloc0.len - alloc1.len - alloc2.len - @sizeOf(Header)); try testing.expectEqual(free_node3.size, size - alloc0.len - alloc1.len - alloc2.len - @sizeOf(Header));
testing.expectEqual(free_node3.next_free, null); try testing.expectEqual(free_node3.next_free, null);
free_list.free(alloc0); free_list.free(alloc0, 0, 0);
// There should now be two free nodes. One where alloc0 was and another after alloc2 // There should now be two free nodes. One where alloc0 was and another after alloc2
const free_node0 = @intToPtr(*Header, start); const free_node0 = @intToPtr(*Header, start);
testing.expectEqual(free_list.first_free, free_node0); try testing.expectEqual(free_list.first_free, free_node0);
testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header)); try testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header));
testing.expectEqual(free_node0.next_free, free_node3); try testing.expectEqual(free_node0.next_free, free_node3);
// Freeing alloc1 should join it with free_node0 // Freeing alloc1 should join it with free_node0
free_list.free(alloc1); free_list.free(alloc1, 0, 0);
testing.expectEqual(free_list.first_free, free_node0); try testing.expectEqual(free_list.first_free, free_node0);
testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header) + alloc1.len); try testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header) + alloc1.len);
testing.expectEqual(free_node0.next_free, free_node3); try testing.expectEqual(free_node0.next_free, free_node3);
// Freeing alloc2 should then join them all together into one big free node // Freeing alloc2 should then join them all together into one big free node
free_list.free(alloc2); free_list.free(alloc2, 0, 0);
testing.expectEqual(free_list.first_free, free_node0); try testing.expectEqual(free_list.first_free, free_node0);
testing.expectEqual(free_node0.size, size - @sizeOf(Header)); try testing.expectEqual(free_node0.size, size - @sizeOf(Header));
testing.expectEqual(free_node0.next_free, null); try testing.expectEqual(free_node0.next_free, null);
} }
test "resize" { test "resize" {
std.debug.warn("", .{}); std.debug.print("", .{});
const size = 1024; const size = 1024;
var region = try testing.allocator.alloc(u8, size); var region = try testing.allocator.alloc(u8, size);
defer testing.allocator.free(region); defer testing.allocator.free(region);
const start = @ptrToInt(region.ptr); const start = @ptrToInt(region.ptr);
var free_list = &(try FreeListAllocator.init(start, size)); var free_list = &(try FreeListAllocator.init(start, size));
var allocator = &free_list.allocator;
var alloc0 = try alloc(allocator, 128, 0, 0, @returnAddress()); var alloc0 = try free_list.alloc(128, 0, 0, @returnAddress());
var alloc1 = try alloc(allocator, 256, 0, 0, @returnAddress()); var alloc1 = try free_list.alloc(256, 0, 0, @returnAddress());
// Expanding alloc0 should fail as alloc1 is right next to it // Expanding alloc0 should fail as alloc1 is right next to it
testing.expectError(Allocator.Error.OutOfMemory, resize(&free_list.allocator, alloc0, 0, 136, 0, @returnAddress())); try testing.expectEqual(free_list.resize(alloc0, 0, 136, 0, @returnAddress()), null);
// Expanding alloc1 should succeed // Expanding alloc1 should succeed
testing.expectEqual(try resize(allocator, alloc1, 0, 512, 0, @returnAddress()), 512); try testing.expectEqual(free_list.resize(alloc1, 0, 512, 0, @returnAddress()), 512);
alloc1 = alloc1.ptr[0..512]; alloc1 = alloc1.ptr[0..512];
// And there should be a free node on the right of it // And there should be a free node on the right of it
var header = @intToPtr(*Header, @ptrToInt(alloc1.ptr) + 512); var header = @intToPtr(*Header, @ptrToInt(alloc1.ptr) + 512);
testing.expectEqual(header.size, size - 128 - 512 - @sizeOf(Header)); try testing.expectEqual(header.size, size - 128 - 512 - @sizeOf(Header));
testing.expectEqual(header.next_free, null); try testing.expectEqual(header.next_free, null);
testing.expectEqual(free_list.first_free, header); try testing.expectEqual(free_list.first_free, header);
// Shrinking alloc1 should produce a big free node on the right // Shrinking alloc1 should produce a big free node on the right
testing.expectEqual(try resize(allocator, alloc1, 0, 128, 0, @returnAddress()), 128); try testing.expectEqual(free_list.resize(alloc1, 0, 128, 0, @returnAddress()), 128);
alloc1 = alloc1.ptr[0..128]; alloc1 = alloc1.ptr[0..128];
header = @intToPtr(*Header, @ptrToInt(alloc1.ptr) + 128); header = @intToPtr(*Header, @ptrToInt(alloc1.ptr) + 128);
testing.expectEqual(header.size, size - 128 - 128 - @sizeOf(Header)); try testing.expectEqual(header.size, size - 128 - 128 - @sizeOf(Header));
testing.expectEqual(header.next_free, null); try testing.expectEqual(header.next_free, null);
testing.expectEqual(free_list.first_free, header); try testing.expectEqual(free_list.first_free, header);
// Shrinking by less space than would allow for a new Header shouldn't work // Shrinking by less space than would allow for a new Header shouldn't work
testing.expectEqual(resize(allocator, alloc1, 0, alloc1.len - @sizeOf(Header) / 2, 0, @returnAddress()), 128); try testing.expectEqual(free_list.resize(alloc1, 0, alloc1.len - @sizeOf(Header) / 2, 0, @returnAddress()), 128);
// Shrinking to less space than would allow for a new Header shouldn't work // Shrinking to less space than would allow for a new Header shouldn't work
testing.expectEqual(resize(allocator, alloc1, 0, @sizeOf(Header) / 2, 0, @returnAddress()), @sizeOf(Header)); try testing.expectEqual(free_list.resize(alloc1, 0, @sizeOf(Header) / 2, 0, @returnAddress()), @sizeOf(Header));
} }
}; };

View file

@ -216,44 +216,44 @@ pub const Keyboard = struct {
test "init" { test "init" {
const keyboard = Keyboard.init(); const keyboard = Keyboard.init();
testing.expectEqual(keyboard.queue_front, 0); try testing.expectEqual(keyboard.queue_front, 0);
testing.expectEqual(keyboard.queue_end, 0); try testing.expectEqual(keyboard.queue_end, 0);
} }
test "isEmpty" { test "isEmpty" {
var keyboard = Keyboard.init(); var keyboard = Keyboard.init();
testing.expect(keyboard.isEmpty()); try testing.expect(keyboard.isEmpty());
keyboard.queue_end += 1; keyboard.queue_end += 1;
testing.expect(!keyboard.isEmpty()); try testing.expect(!keyboard.isEmpty());
keyboard.queue_front += 1; keyboard.queue_front += 1;
testing.expect(keyboard.isEmpty()); try testing.expect(keyboard.isEmpty());
keyboard.queue_end = std.math.maxInt(QueueIndex); keyboard.queue_end = std.math.maxInt(QueueIndex);
keyboard.queue_front = 0; keyboard.queue_front = 0;
testing.expect(!keyboard.isEmpty()); try testing.expect(!keyboard.isEmpty());
keyboard.queue_front = std.math.maxInt(QueueIndex); keyboard.queue_front = std.math.maxInt(QueueIndex);
testing.expect(keyboard.isEmpty()); try testing.expect(keyboard.isEmpty());
} }
test "isFull" { test "isFull" {
var keyboard = Keyboard.init(); var keyboard = Keyboard.init();
testing.expect(!keyboard.isFull()); try testing.expect(!keyboard.isFull());
keyboard.queue_end += 1; keyboard.queue_end += 1;
testing.expect(!keyboard.isFull()); try testing.expect(!keyboard.isFull());
keyboard.queue_front += 1; keyboard.queue_front += 1;
testing.expect(!keyboard.isFull()); try testing.expect(!keyboard.isFull());
keyboard.queue_end = 0; keyboard.queue_end = 0;
testing.expect(keyboard.isFull()); try testing.expect(keyboard.isFull());
keyboard.queue_front = 0; keyboard.queue_front = 0;
keyboard.queue_end = std.math.maxInt(QueueIndex); keyboard.queue_end = std.math.maxInt(QueueIndex);
testing.expect(keyboard.isFull()); try testing.expect(keyboard.isFull());
} }
test "writeKey" { test "writeKey" {
@ -261,20 +261,20 @@ pub const Keyboard = struct {
comptime var i = 0; comptime var i = 0;
inline while (i < QUEUE_SIZE - 1) : (i += 1) { inline while (i < QUEUE_SIZE - 1) : (i += 1) {
testing.expectEqual(keyboard.writeKey(.{ try testing.expectEqual(keyboard.writeKey(.{
.position = @intToEnum(KeyPosition, i), .position = @intToEnum(KeyPosition, i),
.released = false, .released = false,
}), true); }), true);
testing.expectEqual(keyboard.queue[i].position, @intToEnum(KeyPosition, i)); try testing.expectEqual(keyboard.queue[i].position, @intToEnum(KeyPosition, i));
testing.expectEqual(keyboard.queue_end, i + 1); try testing.expectEqual(keyboard.queue_end, i + 1);
testing.expectEqual(keyboard.queue_front, 0); try testing.expectEqual(keyboard.queue_front, 0);
} }
testing.expectEqual(keyboard.writeKey(.{ try testing.expectEqual(keyboard.writeKey(.{
.position = @intToEnum(KeyPosition, 33), .position = @intToEnum(KeyPosition, 33),
.released = false, .released = false,
}), false); }), false);
testing.expect(keyboard.isFull()); try testing.expect(keyboard.isFull());
} }
test "readKey" { test "readKey" {
@ -282,7 +282,7 @@ pub const Keyboard = struct {
comptime var i = 0; comptime var i = 0;
inline while (i < QUEUE_SIZE - 1) : (i += 1) { inline while (i < QUEUE_SIZE - 1) : (i += 1) {
testing.expectEqual(keyboard.writeKey(.{ try testing.expectEqual(keyboard.writeKey(.{
.position = @intToEnum(KeyPosition, i), .position = @intToEnum(KeyPosition, i),
.released = false, .released = false,
}), true); }), true);
@ -290,13 +290,13 @@ pub const Keyboard = struct {
i = 0; i = 0;
inline while (i < QUEUE_SIZE - 1) : (i += 1) { inline while (i < QUEUE_SIZE - 1) : (i += 1) {
testing.expectEqual(keyboard.readKey().?.position, @intToEnum(KeyPosition, i)); try testing.expectEqual(keyboard.readKey().?.position, @intToEnum(KeyPosition, i));
testing.expectEqual(keyboard.queue_end, QUEUE_SIZE - 1); try testing.expectEqual(keyboard.queue_end, QUEUE_SIZE - 1);
testing.expectEqual(keyboard.queue_front, i + 1); try testing.expectEqual(keyboard.queue_front, i + 1);
} }
testing.expect(keyboard.isEmpty()); try testing.expect(keyboard.isEmpty());
testing.expectEqual(keyboard.readKey(), null); try testing.expectEqual(keyboard.readKey(), null);
} }
}; };
@ -336,7 +336,7 @@ pub fn addKeyboard(kb: *Keyboard) Allocator.Error!void {
/// Initialise the keyboard system and the architecture's keyboard /// Initialise the keyboard system and the architecture's keyboard
/// ///
/// Arguments: /// Arguments:
/// allocator: *std.mem.Allocator - The allocator to initialise the keyboard list and architecture keyboard with /// allocator: std.mem.Allocator - The allocator to initialise the keyboard list and architecture keyboard with
/// ///
/// Return: ?*Keyboard /// Return: ?*Keyboard
/// The architecture keyboard found, else null if one wasn't detected /// The architecture keyboard found, else null if one wasn't detected
@ -344,7 +344,7 @@ pub fn addKeyboard(kb: *Keyboard) Allocator.Error!void {
/// Error: std.mem.Allocator.Error /// Error: std.mem.Allocator.Error
/// OutOfMemory - There wasn't enough memory to initialise the keyboard list or the architecture keyboard /// OutOfMemory - There wasn't enough memory to initialise the keyboard list or the architecture keyboard
/// ///
pub fn init(allocator: *Allocator) Allocator.Error!?*Keyboard { pub fn init(allocator: Allocator) Allocator.Error!?*Keyboard {
keyboards = ArrayList(*Keyboard).init(allocator); keyboards = ArrayList(*Keyboard).init(allocator);
return arch.initKeyboard(allocator); return arch.initKeyboard(allocator);
} }

View file

@ -3,10 +3,8 @@ const kmain_log = std.log.scoped(.kmain);
const builtin = @import("builtin"); const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path;
const arch = @import("arch.zig").internals; const arch = @import("arch.zig").internals;
const tty = @import("tty.zig"); const tty = @import("tty.zig");
const vga = @import("vga.zig");
const log_root = @import("log.zig"); const log_root = @import("log.zig");
const pmm = @import("pmm.zig"); const pmm = @import("pmm.zig");
const serial = @import("serial.zig"); const serial = @import("serial.zig");
@ -23,7 +21,7 @@ const Allocator = std.mem.Allocator;
comptime { comptime {
if (!is_test) { if (!is_test) {
switch (builtin.arch) { switch (builtin.cpu.arch) {
.i386 => _ = @import("arch/x86/boot.zig"), .i386 => _ = @import("arch/x86/boot.zig"),
else => unreachable, else => unreachable,
} }
@ -42,7 +40,7 @@ export var KERNEL_PHYSADDR_START: u32 = if (builtin.is_test) 0x100000 else undef
export var KERNEL_PHYSADDR_END: u32 = if (builtin.is_test) 0x14E000 else undefined; export var KERNEL_PHYSADDR_END: u32 = if (builtin.is_test) 0x14E000 else undefined;
// Just call the panic function, as this need to be in the root source file // Just call the panic function, as this need to be in the root source file
pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn {
@setCold(true); @setCold(true);
panic_root.panic(error_return_trace, "{s}", .{msg}); panic_root.panic(error_return_trace, "{s}", .{msg});
} }
@ -62,7 +60,6 @@ var kernel_heap: heap.FreeListAllocator = undefined;
export fn kmain(boot_payload: arch.BootPayload) void { export fn kmain(boot_payload: arch.BootPayload) void {
const serial_stream = serial.init(boot_payload); const serial_stream = serial.init(boot_payload);
log_root.init(serial_stream); log_root.init(serial_stream);
const mem_profile = arch.initMem(boot_payload) catch |e| { const mem_profile = arch.initMem(boot_payload) catch |e| {
@ -70,19 +67,19 @@ export fn kmain(boot_payload: arch.BootPayload) void {
}; };
var fixed_allocator = mem_profile.fixed_allocator; var fixed_allocator = mem_profile.fixed_allocator;
panic_root.init(&mem_profile, &fixed_allocator.allocator) catch |e| { pmm.init(&mem_profile, fixed_allocator.allocator());
panic_root.panic(@errorReturnTrace(), "Failed to initialise panic: {}\n", .{e}); var kernel_vmm = vmm.init(&mem_profile, fixed_allocator.allocator()) catch |e| {
};
pmm.init(&mem_profile, &fixed_allocator.allocator);
var kernel_vmm = vmm.init(&mem_profile, &fixed_allocator.allocator) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel VMM: {}", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel VMM: {}", .{e});
}; };
kmain_log.info("Init arch " ++ @tagName(builtin.arch) ++ "\n", .{}); kmain_log.info("Init arch " ++ @tagName(builtin.cpu.arch) ++ "\n", .{});
arch.init(&mem_profile); arch.init(&mem_profile);
kmain_log.info("Arch init done\n", .{}); kmain_log.info("Arch init done\n", .{});
panic_root.initSymbols(&mem_profile, fixed_allocator.allocator()) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to initialise panic symbols: {}\n", .{e});
};
// The VMM runtime tests can't happen until the architecture has initialised itself // The VMM runtime tests can't happen until the architecture has initialised itself
switch (build_options.test_mode) { switch (build_options.test_mode) {
.Initialisation => vmm.runtimeTests(arch.VmmPayload, kernel_vmm, &mem_profile), .Initialisation => vmm.runtimeTests(arch.VmmPayload, kernel_vmm, &mem_profile),
@ -99,8 +96,8 @@ export fn kmain(boot_payload: arch.BootPayload) void {
panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel heap: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to initialise kernel heap: {}\n", .{e});
}; };
tty.init(&kernel_heap.allocator, boot_payload); tty.init(kernel_heap.allocator(), boot_payload);
var arch_kb = keyboard.init(&fixed_allocator.allocator) catch |e| { var arch_kb = keyboard.init(fixed_allocator.allocator()) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to inititalise keyboard: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to inititalise keyboard: {}\n", .{e});
}; };
if (arch_kb) |kb| { if (arch_kb) |kb| {
@ -119,7 +116,7 @@ export fn kmain(boot_payload: arch.BootPayload) void {
const rd_len: usize = module.region.end - module.region.start; const rd_len: usize = module.region.end - module.region.start;
const ramdisk_bytes = @intToPtr([*]u8, module.region.start)[0..rd_len]; const ramdisk_bytes = @intToPtr([*]u8, module.region.start)[0..rd_len];
var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes); var initrd_stream = std.io.fixedBufferStream(ramdisk_bytes);
var ramdisk_filesystem = initrd.InitrdFS.init(&initrd_stream, &kernel_heap.allocator) catch |e| { var ramdisk_filesystem = initrd.InitrdFS.init(&initrd_stream, kernel_heap.allocator()) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to initialise ramdisk: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to initialise ramdisk: {}\n", .{e});
}; };
@ -134,7 +131,7 @@ export fn kmain(boot_payload: arch.BootPayload) void {
}; };
} }
scheduler.init(&kernel_heap.allocator, &mem_profile) catch |e| { scheduler.init(kernel_heap.allocator(), &mem_profile) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to initialise scheduler: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to initialise scheduler: {}\n", .{e});
}; };
@ -147,10 +144,10 @@ export fn kmain(boot_payload: arch.BootPayload) void {
kmain_log.info("Creating init2\n", .{}); kmain_log.info("Creating init2\n", .{});
// Create a init2 task // Create a init2 task
var stage2_task = task.Task.create(@ptrToInt(initStage2), true, kernel_vmm, &kernel_heap.allocator) catch |e| { var stage2_task = task.Task.create(@ptrToInt(initStage2), true, kernel_vmm, kernel_heap.allocator()) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to create init stage 2 task: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to create init stage 2 task: {}\n", .{e});
}; };
scheduler.scheduleTask(stage2_task, &kernel_heap.allocator) catch |e| { scheduler.scheduleTask(stage2_task, kernel_heap.allocator()) catch |e| {
panic_root.panic(@errorReturnTrace(), "Failed to schedule init stage 2 task: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Failed to schedule init stage 2 task: {}\n", .{e});
}; };
@ -177,7 +174,7 @@ fn initStage2() noreturn {
tty.print("Hello Pluto from kernel :)\n", .{}); tty.print("Hello Pluto from kernel :)\n", .{});
const devices = arch.getDevices(&kernel_heap.allocator) catch |e| { const devices = arch.getDevices(kernel_heap.allocator()) catch |e| {
panic_root.panic(@errorReturnTrace(), "Unable to get device list: {}\n", .{e}); panic_root.panic(@errorReturnTrace(), "Unable to get device list: {}\n", .{e});
}; };

View file

@ -28,6 +28,8 @@ var serial: Serial = undefined;
/// {} - No error as LoggingError is empty. /// {} - No error as LoggingError is empty.
/// ///
fn logCallback(context: void, str: []const u8) LoggingError!usize { fn logCallback(context: void, str: []const u8) LoggingError!usize {
// Suppress unused var warning
_ = context;
serial.writeBytes(str); serial.writeBytes(str);
return str.len; return str.len;
} }

View file

@ -102,15 +102,15 @@ pub fn physToVirt(phys: anytype) @TypeOf(phys) {
test "physToVirt" { test "physToVirt" {
ADDR_OFFSET = 0xC0000000; ADDR_OFFSET = 0xC0000000;
const offset: usize = ADDR_OFFSET; const offset: usize = ADDR_OFFSET;
expectEqual(physToVirt(@as(usize, 0)), offset + 0); try expectEqual(physToVirt(@as(usize, 0)), offset + 0);
expectEqual(physToVirt(@as(usize, 123)), offset + 123); try expectEqual(physToVirt(@as(usize, 123)), offset + 123);
expectEqual(@ptrToInt(physToVirt(@intToPtr(*align(1) usize, 123))), offset + 123); try expectEqual(@ptrToInt(physToVirt(@intToPtr(*align(1) usize, 123))), offset + 123);
} }
test "virtToPhys" { test "virtToPhys" {
ADDR_OFFSET = 0xC0000000; ADDR_OFFSET = 0xC0000000;
const offset: usize = ADDR_OFFSET; const offset: usize = ADDR_OFFSET;
expectEqual(virtToPhys(offset + 0), 0); try expectEqual(virtToPhys(offset + 0), 0);
expectEqual(virtToPhys(offset + 123), 123); try expectEqual(virtToPhys(offset + 123), 123);
expectEqual(@ptrToInt(virtToPhys(@intToPtr(*align(1) usize, offset + 123))), 123); try expectEqual(@ptrToInt(virtToPhys(@intToPtr(*align(1) usize, offset + 123))), 123);
} }

View file

@ -1,7 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = std.builtin;
const arch = @import("arch.zig").internals; const arch = @import("arch.zig").internals;
const multiboot = @import("multiboot.zig");
const mem = @import("mem.zig"); const mem = @import("mem.zig");
const build_options = @import("build_options"); const build_options = @import("build_options");
const ArrayList = std.ArrayList; const ArrayList = std.ArrayList;
@ -32,12 +31,12 @@ const SymbolMap = struct {
/// Initialise an empty symbol map. /// Initialise an empty symbol map.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - The allocator to use to initialise the array list. /// IN allocator: Allocator - The allocator to use to initialise the array list.
/// ///
/// Return: SymbolMap /// Return: SymbolMap
/// The symbol map. /// The symbol map.
/// ///
pub fn init(allocator: *Allocator) SymbolMap { pub fn init(allocator: Allocator) SymbolMap {
return SymbolMap{ return SymbolMap{
.symbols = ArrayList(MapEntry).init(allocator), .symbols = ArrayList(MapEntry).init(allocator),
}; };
@ -111,7 +110,7 @@ var symbol_map: ?SymbolMap = null;
/// ///
fn logTraceAddress(addr: usize) void { fn logTraceAddress(addr: usize) void {
const str = if (symbol_map) |syms| syms.search(addr) orelse "?????" else "(no symbols available)"; const str = if (symbol_map) |syms| syms.search(addr) orelse "?????" else "(no symbols available)";
log.emerg("{x}: {s}\n", .{ addr, str }); log.err("{x}: {s}\n", .{ addr, str });
} }
/// ///
@ -278,7 +277,7 @@ fn parseMapEntry(start: *[*]const u8, end: *const u8) (PanicError || std.fmt.Par
pub fn panic(trace: ?*builtin.StackTrace, comptime format: []const u8, args: anytype) noreturn { pub fn panic(trace: ?*builtin.StackTrace, comptime format: []const u8, args: anytype) noreturn {
@setCold(true); @setCold(true);
log.emerg("Kernel panic: " ++ format ++ "\n", args); log.err("Kernel panic: " ++ format ++ "\n", args);
if (trace) |trc| { if (trace) |trc| {
var last_addr: u64 = 0; var last_addr: u64 = 0;
for (trc.instruction_addresses) |ret_addr| { for (trc.instruction_addresses) |ret_addr| {
@ -298,20 +297,20 @@ pub fn panic(trace: ?*builtin.StackTrace, comptime format: []const u8, args: any
} }
/// ///
/// Initialise the panic subsystem by looking for a boot module called "kernel.map" and loading the /// Initialise the symbol table used by the panic subsystem by looking for a boot module called "kernel.map" and loading the
/// symbols from it. Exits early if no such module was found. /// symbol entries from it. Exits early if no such module was found.
/// ///
/// Arguments: /// Arguments:
/// IN mem_profile: *const mem.MemProfile - The memory profile from which to get the loaded boot /// IN mem_profile: *const mem.MemProfile - The memory profile from which to get the loaded boot
/// modules. /// modules.
/// IN allocator: *Allocator - The allocator to use to store the symbol map. /// IN allocator: Allocator - The allocator to use to store the symbol map.
/// ///
/// Error: PanicError || Allocator.Error || std.fmt.ParseIntError /// Error: PanicError || Allocator.Error || std.fmt.ParseIntError
/// PanicError.InvalidSymbolFile - A terminating whitespace wasn't found before the end address. /// PanicError.InvalidSymbolFile - A terminating whitespace wasn't found before the end address.
/// Allocator.Error.OutOfMemory - If there wasn't enough memory. /// Allocator.Error.OutOfMemory - If there wasn't enough memory.
/// std.fmt.ParseIntError - See parseMapEntry. /// std.fmt.ParseIntError - See parseMapEntry.
/// ///
pub fn init(mem_profile: *const mem.MemProfile, allocator: *Allocator) (PanicError || Allocator.Error || std.fmt.ParseIntError)!void { pub fn initSymbols(mem_profile: *const mem.MemProfile, allocator: Allocator) (PanicError || Allocator.Error || std.fmt.ParseIntError)!void {
log.info("Init\n", .{}); log.info("Init\n", .{});
defer log.info("Done\n", .{}); defer log.info("Done\n", .{});
@ -355,91 +354,91 @@ test "parseChar" {
const str: []const u8 = "plutoisthebest"; const str: []const u8 = "plutoisthebest";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var char = try parseChar(str.ptr, end); var char = try parseChar(str.ptr, end);
testing.expectEqual(char, 'p'); try testing.expectEqual(char, 'p');
char = try parseChar(str.ptr + 1, end); char = try parseChar(str.ptr + 1, end);
testing.expectEqual(char, 'l'); try testing.expectEqual(char, 'l');
testing.expectError(PanicError.InvalidSymbolFile, parseChar(str.ptr + str.len, end)); try testing.expectError(PanicError.InvalidSymbolFile, parseChar(str.ptr + str.len, end));
} }
test "parseWhitespace" { test "parseWhitespace" {
const str: []const u8 = " a"; const str: []const u8 = " a";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = try parseWhitespace(str.ptr, end); var ptr = try parseWhitespace(str.ptr, end);
testing.expectEqual(@ptrToInt(str.ptr) + 4, @ptrToInt(ptr)); try testing.expectEqual(@ptrToInt(str.ptr) + 4, @ptrToInt(ptr));
} }
test "parseWhitespace fails without a terminating whitespace" { test "parseWhitespace fails without a terminating whitespace" {
const str: []const u8 = " "; const str: []const u8 = " ";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
testing.expectError(PanicError.InvalidSymbolFile, parseWhitespace(str.ptr, end)); try testing.expectError(PanicError.InvalidSymbolFile, parseWhitespace(str.ptr, end));
} }
test "parseNonWhitespace" { test "parseNonWhitespace" {
const str: []const u8 = "ab "; const str: []const u8 = "ab ";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = try parseNonWhitespace(str.ptr, end); var ptr = try parseNonWhitespace(str.ptr, end);
testing.expectEqual(@ptrToInt(str.ptr) + 2, @ptrToInt(ptr)); try testing.expectEqual(@ptrToInt(str.ptr) + 2, @ptrToInt(ptr));
} }
test "parseNonWhitespace fails without a terminating whitespace" { test "parseNonWhitespace fails without a terminating whitespace" {
const str: []const u8 = "abc"; const str: []const u8 = "abc";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
testing.expectError(PanicError.InvalidSymbolFile, parseNonWhitespace(str.ptr, end)); try testing.expectError(PanicError.InvalidSymbolFile, parseNonWhitespace(str.ptr, end));
} }
test "parseNonNewLine" { test "parseNonNewLine" {
const str: []const u8 = "ab\n"; const str: []const u8 = "ab\n";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = try parseNonNewLine(str.ptr, end); var ptr = try parseNonNewLine(str.ptr, end);
testing.expectEqual(@ptrToInt(str.ptr) + 2, @ptrToInt(ptr)); try testing.expectEqual(@ptrToInt(str.ptr) + 2, @ptrToInt(ptr));
} }
test "parseNonNewLine fails without a terminating newline" { test "parseNonNewLine fails without a terminating newline" {
const str: []const u8 = "abc"; const str: []const u8 = "abc";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
testing.expectError(PanicError.InvalidSymbolFile, parseNonNewLine(str.ptr, end)); try testing.expectError(PanicError.InvalidSymbolFile, parseNonNewLine(str.ptr, end));
} }
test "parseAddr" { test "parseAddr" {
const str: []const u8 = "1a2b3c4d "; const str: []const u8 = "1a2b3c4d ";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = str.ptr; var ptr = str.ptr;
testing.expectEqual(try parseAddr(&ptr, end), 0x1a2b3c4d); try testing.expectEqual(try parseAddr(&ptr, end), 0x1a2b3c4d);
} }
test "parseAddr fails without a terminating whitespace" { test "parseAddr fails without a terminating whitespace" {
const str: []const u8 = "1a2b3c4d"; const str: []const u8 = "1a2b3c4d";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = str.ptr; var ptr = str.ptr;
testing.expectError(PanicError.InvalidSymbolFile, parseAddr(&ptr, end)); try testing.expectError(PanicError.InvalidSymbolFile, parseAddr(&ptr, end));
} }
test "parseAddr fails with an invalid integer" { test "parseAddr fails with an invalid integer" {
const str: []const u8 = "1g2t "; const str: []const u8 = "1g2t ";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = str.ptr; var ptr = str.ptr;
testing.expectError(error.InvalidCharacter, parseAddr(&ptr, end)); try testing.expectError(error.InvalidCharacter, parseAddr(&ptr, end));
} }
test "parseName" { test "parseName" {
const str: []const u8 = "func_name\n"; const str: []const u8 = "func_name\n";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = str.ptr; var ptr = str.ptr;
testing.expectEqualSlices(u8, try parseName(&ptr, end), "func_name"); try testing.expectEqualSlices(u8, try parseName(&ptr, end), "func_name");
} }
test "parseName with spaces" { test "parseName with spaces" {
const str: []const u8 = "func_name(*const type )\n"; const str: []const u8 = "func_name(*const type )\n";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = str.ptr; var ptr = str.ptr;
testing.expectEqualSlices(u8, try parseName(&ptr, end), "func_name(*const type )"); try testing.expectEqualSlices(u8, try parseName(&ptr, end), "func_name(*const type )");
} }
test "parseName fails without a terminating newline" { test "parseName fails without a terminating newline" {
const str: []const u8 = "func_name"; const str: []const u8 = "func_name";
const end = @ptrCast(*const u8, str.ptr + str.len); const end = @ptrCast(*const u8, str.ptr + str.len);
var ptr = str.ptr; var ptr = str.ptr;
testing.expectError(PanicError.InvalidSymbolFile, parseName(&ptr, end)); try testing.expectError(PanicError.InvalidSymbolFile, parseName(&ptr, end));
} }
test "parseMapEntry" { test "parseMapEntry" {
@ -449,37 +448,37 @@ test "parseMapEntry" {
var actual = try parseMapEntry(&ptr, end); var actual = try parseMapEntry(&ptr, end);
var expected = MapEntry{ .addr = 0x1a2b3c4d, .func_name = "func_name" }; var expected = MapEntry{ .addr = 0x1a2b3c4d, .func_name = "func_name" };
testing.expectEqual(actual.addr, expected.addr); try testing.expectEqual(actual.addr, expected.addr);
testing.expectEqualSlices(u8, actual.func_name, expected.func_name); try testing.expectEqualSlices(u8, actual.func_name, expected.func_name);
actual = try parseMapEntry(&ptr, end); actual = try parseMapEntry(&ptr, end);
expected = MapEntry{ .addr = 0x5e6f7a8b, .func_name = "func_name2" }; expected = MapEntry{ .addr = 0x5e6f7a8b, .func_name = "func_name2" };
testing.expectEqual(actual.addr, expected.addr); try testing.expectEqual(actual.addr, expected.addr);
testing.expectEqualSlices(u8, actual.func_name, expected.func_name); try testing.expectEqualSlices(u8, actual.func_name, expected.func_name);
} }
test "parseMapEntry fails without a terminating newline" { test "parseMapEntry fails without a terminating newline" {
const str: []const u8 = "1a2b3c4d func_name"; const str: []const u8 = "1a2b3c4d func_name";
var ptr = str.ptr; var ptr = str.ptr;
testing.expectError(PanicError.InvalidSymbolFile, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr + 18))); try testing.expectError(PanicError.InvalidSymbolFile, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr + 18)));
} }
test "parseMapEntry fails without any characters" { test "parseMapEntry fails without any characters" {
const str: []const u8 = " "; const str: []const u8 = " ";
var ptr = str.ptr; var ptr = str.ptr;
testing.expectError(PanicError.InvalidSymbolFile, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr))); try testing.expectError(PanicError.InvalidSymbolFile, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr)));
} }
test "parseMapEntry fails with an invalid address" { test "parseMapEntry fails with an invalid address" {
const str: []const u8 = "xyz func_name"; const str: []const u8 = "xyz func_name";
var ptr = str.ptr; var ptr = str.ptr;
testing.expectError(error.InvalidCharacter, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr + 13))); try testing.expectError(error.InvalidCharacter, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr + 13)));
} }
test "parseMapEntry fails without a name" { test "parseMapEntry fails without a name" {
const str: []const u8 = "123 "; const str: []const u8 = "123 ";
var ptr = str.ptr; var ptr = str.ptr;
testing.expectError(PanicError.InvalidSymbolFile, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr + 4))); try testing.expectError(PanicError.InvalidSymbolFile, parseMapEntry(&ptr, @ptrCast(*const u8, str.ptr + 4)));
} }
test "SymbolMap" { test "SymbolMap" {
@ -490,18 +489,18 @@ test "SymbolMap" {
try map.addEntry(MapEntry{ .func_name = "def"[0..], .addr = 456 }); try map.addEntry(MapEntry{ .func_name = "def"[0..], .addr = 456 });
try map.add("ghi"[0..], 789); try map.add("ghi"[0..], 789);
try map.addEntry(MapEntry{ .func_name = "jkl"[0..], .addr = 1010 }); try map.addEntry(MapEntry{ .func_name = "jkl"[0..], .addr = 1010 });
testing.expectEqual(map.search(54), null); try testing.expectEqual(map.search(54), null);
testing.expectEqual(map.search(122), null); try testing.expectEqual(map.search(122), null);
testing.expectEqual(map.search(123), "abc"); try testing.expectEqual(map.search(123), "abc");
testing.expectEqual(map.search(234), "abc"); try testing.expectEqual(map.search(234), "abc");
testing.expectEqual(map.search(455), "abc"); try testing.expectEqual(map.search(455), "abc");
testing.expectEqual(map.search(456), "def"); try testing.expectEqual(map.search(456), "def");
testing.expectEqual(map.search(678), "def"); try testing.expectEqual(map.search(678), "def");
testing.expectEqual(map.search(788), "def"); try testing.expectEqual(map.search(788), "def");
testing.expectEqual(map.search(789), "ghi"); try testing.expectEqual(map.search(789), "ghi");
testing.expectEqual(map.search(1009), "ghi"); try testing.expectEqual(map.search(1009), "ghi");
testing.expectEqual(map.search(1010), "jkl"); try testing.expectEqual(map.search(1010), "jkl");
testing.expectEqual(map.search(2345), "jkl"); try testing.expectEqual(map.search(2345), "jkl");
} }
/// ///

View file

@ -2,8 +2,7 @@ const is_test = @import("builtin").is_test;
const std = @import("std"); const std = @import("std");
const log = std.log.scoped(.pmm); const log = std.log.scoped(.pmm);
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path; const arch = @import("arch.zig").internals;
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig").internals;
const MemProfile = @import("mem.zig").MemProfile; const MemProfile = @import("mem.zig").MemProfile;
const testing = std.testing; const testing = std.testing;
const panic = @import("panic.zig").panic; const panic = @import("panic.zig").panic;
@ -96,9 +95,9 @@ pub fn blocksFree() usize {
/// ///
/// Arguments: /// Arguments:
/// IN mem: *const MemProfile - The system's memory profile. /// IN mem: *const MemProfile - The system's memory profile.
/// IN allocator: *Allocator - The allocator to use to allocate the bitmaps. /// IN allocator: Allocator - The allocator to use to allocate the bitmaps.
/// ///
pub fn init(mem_profile: *const MemProfile, allocator: *Allocator) void { pub fn init(mem_profile: *const MemProfile, allocator: Allocator) void {
log.info("Init\n", .{}); log.info("Init\n", .{});
defer log.info("Done\n", .{}); defer log.info("Done\n", .{});
@ -146,13 +145,13 @@ test "alloc" {
i += 1; i += 1;
addr += BLOCK_SIZE; addr += BLOCK_SIZE;
}) { }) {
testing.expect(!(try isSet(addr))); try testing.expect(!(try isSet(addr)));
testing.expect(alloc().? == addr); try testing.expect(alloc().? == addr);
testing.expect(try isSet(addr)); try testing.expect(try isSet(addr));
testing.expectEqual(blocksFree(), 31 - i); try testing.expectEqual(blocksFree(), 31 - i);
} }
// Allocation should now fail // Allocation should now fail
testing.expect(alloc() == null); try testing.expect(alloc() == null);
} }
test "free" { test "free" {
@ -162,13 +161,13 @@ test "free" {
// Allocate and free all entries // Allocate and free all entries
inline while (i < 32) : (i += 1) { inline while (i < 32) : (i += 1) {
const addr = alloc().?; const addr = alloc().?;
testing.expect(try isSet(addr)); try testing.expect(try isSet(addr));
testing.expectEqual(blocksFree(), 31); try testing.expectEqual(blocksFree(), 31);
try free(addr); try free(addr);
testing.expectEqual(blocksFree(), 32); try testing.expectEqual(blocksFree(), 32);
testing.expect(!(try isSet(addr))); try testing.expect(!(try isSet(addr)));
// Double frees should be caught // Double frees should be caught
testing.expectError(PmmError.NotAllocated, free(addr)); try testing.expectError(PmmError.NotAllocated, free(addr));
} }
} }
@ -189,14 +188,14 @@ test "setAddr and isSet" {
h += 1; h += 1;
addr2 += BLOCK_SIZE; addr2 += BLOCK_SIZE;
}) { }) {
testing.expect(try isSet(addr2)); try testing.expect(try isSet(addr2));
} }
testing.expectEqual(blocksFree(), num_entries - i); try testing.expectEqual(blocksFree(), num_entries - i);
// Set the current block // Set the current block
try setAddr(addr); try setAddr(addr);
testing.expect(try isSet(addr)); try testing.expect(try isSet(addr));
testing.expectEqual(blocksFree(), num_entries - i - 1); try testing.expectEqual(blocksFree(), num_entries - i - 1);
// Ensure all successive entries are not set // Ensure all successive entries are not set
var j: u32 = i + 1; var j: u32 = i + 1;
@ -205,7 +204,7 @@ test "setAddr and isSet" {
j += 1; j += 1;
addr3 += BLOCK_SIZE; addr3 += BLOCK_SIZE;
}) { }) {
testing.expect(!try isSet(addr3)); try testing.expect(!try isSet(addr3));
} }
} }
} }
@ -215,9 +214,9 @@ test "setAddr and isSet" {
/// ///
/// Arguments: /// Arguments:
/// IN mem_profile: *const MemProfile - The memory profile to check for reserved memory regions. /// IN mem_profile: *const MemProfile - The memory profile to check for reserved memory regions.
/// IN/OUT allocator: *Allocator - The allocator to use when needing to create intermediate structures used for testing /// IN/OUT allocator: Allocator - The allocator to use when needing to create intermediate structures used for testing
/// ///
fn runtimeTests(mem_profile: *const MemProfile, allocator: *Allocator) void { fn runtimeTests(mem_profile: *const MemProfile, allocator: Allocator) void {
// Make sure that occupied memory can't be allocated // Make sure that occupied memory can't be allocated
var prev_alloc: usize = std.math.maxInt(usize); var prev_alloc: usize = std.math.maxInt(usize);
var alloc_list = std.ArrayList(usize).init(allocator); var alloc_list = std.ArrayList(usize).init(allocator);

View file

@ -6,7 +6,6 @@ const log = std.log.scoped(.scheduler);
const builtin = @import("builtin"); const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path;
const arch = @import("arch.zig").internals; const arch = @import("arch.zig").internals;
const panic = @import("panic.zig").panic; const panic = @import("panic.zig").panic;
const task = @import("task.zig"); const task = @import("task.zig");
@ -105,12 +104,13 @@ pub fn pickNextTask(ctx: *arch.CpuState) usize {
/// ///
/// Arguments: /// Arguments:
/// IN entry_point: EntryPoint - The entry point into the task. This must be a function. /// IN entry_point: EntryPoint - The entry point into the task. This must be a function.
/// IN allocator: Allocator - The allocator to use
/// ///
/// Error: Allocator.Error /// Error: Allocator.Error
/// OutOfMemory - If there isn't enough memory for the a task/stack. Any memory allocated will /// OutOfMemory - If there isn't enough memory for the a task/stack. Any memory allocated will
/// be freed on return. /// be freed on return.
/// ///
pub fn scheduleTask(new_task: *Task, allocator: *Allocator) Allocator.Error!void { pub fn scheduleTask(new_task: *Task, allocator: Allocator) Allocator.Error!void {
var task_node = try allocator.create(TailQueue(*Task).Node); var task_node = try allocator.create(TailQueue(*Task).Node);
task_node.* = .{ .data = new_task }; task_node.* = .{ .data = new_task };
tasks.prepend(task_node); tasks.prepend(task_node);
@ -123,13 +123,13 @@ pub fn scheduleTask(new_task: *Task, allocator: *Allocator) Allocator.Error!void
/// idle task for when there is no more tasks to run. /// idle task for when there is no more tasks to run.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - The allocator to use when needing to allocate memory. /// IN allocator: Allocator - The allocator to use when needing to allocate memory.
/// IN mem_profile: *const mem.MemProfile - The system's memory profile used for runtime testing. /// IN mem_profile: *const mem.MemProfile - The system's memory profile used for runtime testing.
/// ///
/// Error: Allocator.Error /// Error: Allocator.Error
/// OutOfMemory - There is no more memory. Any memory allocated will be freed on return. /// OutOfMemory - There is no more memory. Any memory allocated will be freed on return.
/// ///
pub fn init(allocator: *Allocator, mem_profile: *const mem.MemProfile) Allocator.Error!void { pub fn init(allocator: Allocator, mem_profile: *const mem.MemProfile) Allocator.Error!void {
// TODO: Maybe move the task init here? // TODO: Maybe move the task init here?
log.info("Init\n", .{}); log.info("Init\n", .{});
defer log.info("Done\n", .{}); defer log.info("Done\n", .{});
@ -170,7 +170,7 @@ fn test_fn2() void {}
var test_pid_counter: u7 = 1; var test_pid_counter: u7 = 1;
fn createTestTask(entry_point: EntryPoint, allocator: *Allocator, kernel: bool, task_vmm: *vmm.VirtualMemoryManager(u8)) Allocator.Error!*Task { fn createTestTask(allocator: Allocator) Allocator.Error!*Task {
var t = try allocator.create(Task); var t = try allocator.create(Task);
errdefer allocator.destroy(t); errdefer allocator.destroy(t);
t.pid = test_pid_counter; t.pid = test_pid_counter;
@ -181,7 +181,7 @@ fn createTestTask(entry_point: EntryPoint, allocator: *Allocator, kernel: bool,
return t; return t;
} }
fn destroyTestTask(self: *Task, allocator: *Allocator) void { fn destroyTestTask(self: *Task, allocator: Allocator) void {
if (@ptrToInt(self.kernel_stack.ptr) != @ptrToInt(&KERNEL_STACK_START)) { if (@ptrToInt(self.kernel_stack.ptr) != @ptrToInt(&KERNEL_STACK_START)) {
allocator.free(self.kernel_stack); allocator.free(self.kernel_stack);
} }
@ -214,26 +214,26 @@ test "pickNextTask" {
const fn1_stack_pointer = test_fn1_task.stack_pointer; const fn1_stack_pointer = test_fn1_task.stack_pointer;
const fn2_stack_pointer = test_fn2_task.stack_pointer; const fn2_stack_pointer = test_fn2_task.stack_pointer;
expectEqual(pickNextTask(&ctx), fn1_stack_pointer); try expectEqual(pickNextTask(&ctx), fn1_stack_pointer);
// The stack pointer of the re-added task should point to the context // The stack pointer of the re-added task should point to the context
expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx)); try expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx));
// Should be the PID of the next task // Should be the PID of the next task
expectEqual(current_task.pid, 1); try expectEqual(current_task.pid, 1);
expectEqual(pickNextTask(&ctx), fn2_stack_pointer); try expectEqual(pickNextTask(&ctx), fn2_stack_pointer);
// The stack pointer of the re-added task should point to the context // The stack pointer of the re-added task should point to the context
expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx)); try expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx));
// Should be the PID of the next task // Should be the PID of the next task
expectEqual(current_task.pid, 2); try expectEqual(current_task.pid, 2);
expectEqual(pickNextTask(&ctx), @ptrToInt(&ctx)); try expectEqual(pickNextTask(&ctx), @ptrToInt(&ctx));
// The stack pointer of the re-added task should point to the context // The stack pointer of the re-added task should point to the context
expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx)); try expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx));
// Should be back tot he beginning // Should be back tot he beginning
expectEqual(current_task.pid, 0); try expectEqual(current_task.pid, 0);
// Reset the test pid // Reset the test pid
test_pid_counter = 1; test_pid_counter = 1;
@ -255,7 +255,7 @@ test "createNewTask add new task" {
defer test_fn1_task.destroy(allocator); defer test_fn1_task.destroy(allocator);
try scheduleTask(test_fn1_task, allocator); try scheduleTask(test_fn1_task, allocator);
expectEqual(tasks.len, 1); try expectEqual(tasks.len, 1);
// Free the memory // Free the memory
allocator.destroy(tasks.first.?); allocator.destroy(tasks.first.?);
@ -266,11 +266,11 @@ test "init" {
try init(allocator, undefined); try init(allocator, undefined);
expectEqual(current_task.pid, 0); try expectEqual(current_task.pid, 0);
expectEqual(@ptrToInt(current_task.kernel_stack.ptr), @ptrToInt(&KERNEL_STACK_START)); try expectEqual(@ptrToInt(current_task.kernel_stack.ptr), @ptrToInt(&KERNEL_STACK_START));
expectEqual(current_task.kernel_stack.len, @ptrToInt(&KERNEL_STACK_END) - @ptrToInt(&KERNEL_STACK_START)); try expectEqual(current_task.kernel_stack.len, @ptrToInt(&KERNEL_STACK_END) - @ptrToInt(&KERNEL_STACK_START));
expectEqual(tasks.len, 1); try expectEqual(tasks.len, 1);
// Free the tasks created // Free the tasks created
current_task.destroy(allocator); current_task.destroy(allocator);
@ -298,9 +298,9 @@ fn task_function() noreturn {
/// occurs. Also tests that a global volatile can be test in one task and be reacted to in another. /// occurs. Also tests that a global volatile can be test in one task and be reacted to in another.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - The allocator to use when needing to allocate memory. /// IN allocator: Allocator - The allocator to use when needing to allocate memory.
/// ///
fn rt_variable_preserved(allocator: *Allocator) void { fn rt_variable_preserved(allocator: Allocator) void {
// Create the memory for the boolean // Create the memory for the boolean
is_set = allocator.create(bool) catch unreachable; is_set = allocator.create(bool) catch unreachable;
defer allocator.destroy(is_set); defer allocator.destroy(is_set);
@ -353,7 +353,7 @@ fn rt_variable_preserved(allocator: *Allocator) void {
/// IN allocator: *std.mem.Allocator - The allocator to use when intialising the task /// IN allocator: *std.mem.Allocator - The allocator to use when intialising the task
/// IN mem_profile: mem.MemProfile - The system's memory profile. Determines the end address of the user task's VMM. /// IN mem_profile: mem.MemProfile - The system's memory profile. Determines the end address of the user task's VMM.
/// ///
fn rt_user_task(allocator: *Allocator, mem_profile: *const mem.MemProfile) void { fn rt_user_task(allocator: Allocator, mem_profile: *const mem.MemProfile) void {
for (&[_][]const u8{ "/user_program_data.elf", "/user_program.elf" }) |user_program| { for (&[_][]const u8{ "/user_program_data.elf", "/user_program.elf" }) |user_program| {
// 1. Create user VMM // 1. Create user VMM
var task_vmm = allocator.create(vmm.VirtualMemoryManager(arch.VmmPayload)) catch |e| { var task_vmm = allocator.create(vmm.VirtualMemoryManager(arch.VmmPayload)) catch |e| {
@ -369,11 +369,9 @@ fn rt_user_task(allocator: *Allocator, mem_profile: *const mem.MemProfile) void
const code_len = user_program_file.read(code[0..code.len]) catch |e| { const code_len = user_program_file.read(code[0..code.len]) catch |e| {
panic(@errorReturnTrace(), "Failed to read {s}: {}\n", .{ user_program, e }); panic(@errorReturnTrace(), "Failed to read {s}: {}\n", .{ user_program, e });
}; };
const program_elf = elf.Elf.init(code[0..code_len], builtin.arch, allocator) catch |e| panic(@errorReturnTrace(), "Failed to load {s}: {}\n", .{ user_program, e }); const program_elf = elf.Elf.init(code[0..code_len], builtin.cpu.arch, allocator) catch |e| panic(@errorReturnTrace(), "Failed to load {s}: {}\n", .{ user_program, e });
defer program_elf.deinit(); defer program_elf.deinit();
const current_physical_blocks = pmm.blocksFree();
var user_task = task.Task.createFromElf(program_elf, false, task_vmm, allocator) catch |e| { var user_task = task.Task.createFromElf(program_elf, false, task_vmm, allocator) catch |e| {
panic(@errorReturnTrace(), "Failed to create task for {s}: {}\n", .{ user_program, e }); panic(@errorReturnTrace(), "Failed to create task for {s}: {}\n", .{ user_program, e });
}; };
@ -407,10 +405,10 @@ fn rt_user_task(allocator: *Allocator, mem_profile: *const mem.MemProfile) void
/// The scheduler runtime tests that will test the scheduling functionality. /// The scheduler runtime tests that will test the scheduling functionality.
/// ///
/// Arguments: /// Arguments:
/// IN allocator: *Allocator - The allocator to use when needing to allocate memory. /// IN allocator: Allocator - The allocator to use when needing to allocate memory.
/// IN mem_profile: *const mem.MemProfile - The system's memory profile. Used to set up user task VMMs. /// IN mem_profile: *const mem.MemProfile - The system's memory profile. Used to set up user task VMMs.
/// ///
fn runtimeTests(allocator: *Allocator, mem_profile: *const mem.MemProfile) void { fn runtimeTests(allocator: Allocator, mem_profile: *const mem.MemProfile) void {
arch.enableInterrupts(); arch.enableInterrupts();
rt_user_task(allocator, mem_profile); rt_user_task(allocator, mem_profile);
rt_variable_preserved(allocator); rt_variable_preserved(allocator);

View file

@ -98,6 +98,12 @@ pub fn handle(syscall: Syscall, arg1: usize, arg2: usize, arg3: usize, arg4: usi
} }
pub fn handleTest1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { pub fn handleTest1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize {
// Suppress unused variable warnings
_ = arg1;
_ = arg2;
_ = arg3;
_ = arg4;
_ = arg5;
return 0; return 0;
} }
@ -106,17 +112,23 @@ pub fn handleTest2(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usi
} }
pub fn handleTest3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { pub fn handleTest3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize {
// Suppress unused variable warnings
_ = arg1;
_ = arg2;
_ = arg3;
_ = arg4;
_ = arg5;
return std.mem.Allocator.Error.OutOfMemory; return std.mem.Allocator.Error.OutOfMemory;
} }
test "getHandler" { test "getHandler" {
std.testing.expectEqual(Syscall.Test1.getHandler(), handleTest1); try std.testing.expectEqual(Syscall.Test1.getHandler(), handleTest1);
std.testing.expectEqual(Syscall.Test2.getHandler(), handleTest2); try std.testing.expectEqual(Syscall.Test2.getHandler(), handleTest2);
std.testing.expectEqual(Syscall.Test3.getHandler(), handleTest3); try std.testing.expectEqual(Syscall.Test3.getHandler(), handleTest3);
} }
test "handle" { test "handle" {
std.testing.expectEqual(@as(usize, 0), try handle(.Test1, 0, 0, 0, 0, 0)); try std.testing.expectEqual(@as(usize, 0), try handle(.Test1, 0, 0, 0, 0, 0));
std.testing.expectEqual(@as(usize, 1 + 2 + 3 + 4 + 5), try handle(.Test2, 1, 2, 3, 4, 5)); try std.testing.expectEqual(@as(usize, 1 + 2 + 3 + 4 + 5), try handle(.Test2, 1, 2, 3, 4, 5));
std.testing.expectError(Error.OutOfMemory, handle(.Test3, 0, 0, 0, 0, 0)); try std.testing.expectError(Error.OutOfMemory, handle(.Test3, 0, 0, 0, 0, 0));
} }

View file

@ -4,7 +4,6 @@ const expectError = std.testing.expectError;
const builtin = @import("builtin"); const builtin = @import("builtin");
const is_test = builtin.is_test; const is_test = builtin.is_test;
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path;
const arch = @import("arch.zig").internals; const arch = @import("arch.zig").internals;
const panic = @import("panic.zig").panic; const panic = @import("panic.zig").panic;
const vmm = @import("vmm.zig"); const vmm = @import("vmm.zig");
@ -68,7 +67,7 @@ pub const Task = struct {
/// IN entry_point: EntryPoint - The entry point into the task. This must be a function. /// IN entry_point: EntryPoint - The entry point into the task. This must be a function.
/// IN kernel: bool - Whether the task has kernel or user privileges. /// IN kernel: bool - Whether the task has kernel or user privileges.
/// IN task_vmm: *VirtualMemoryManager - The virtual memory manager associated with the task. /// IN task_vmm: *VirtualMemoryManager - The virtual memory manager associated with the task.
/// IN allocator: *Allocator - The allocator for allocating memory for a task. /// IN allocator: Allocator - The allocator for allocating memory for a task.
/// ///
/// Return: *Task /// Return: *Task
/// Pointer to an allocated task. This will then need to be added to the task queue. /// Pointer to an allocated task. This will then need to be added to the task queue.
@ -77,7 +76,7 @@ pub const Task = struct {
/// OutOfMemory - If there is no more memory to allocate. Any memory or PID allocated will /// OutOfMemory - If there is no more memory to allocate. Any memory or PID allocated will
/// be freed on return. /// be freed on return.
/// ///
pub fn create(entry_point: EntryPoint, kernel: bool, task_vmm: *vmm.VirtualMemoryManager(arch.VmmPayload), allocator: *Allocator) Allocator.Error!*Task { pub fn create(entry_point: EntryPoint, kernel: bool, task_vmm: *vmm.VirtualMemoryManager(arch.VmmPayload), allocator: Allocator) Allocator.Error!*Task {
var task = try allocator.create(Task); var task = try allocator.create(Task);
errdefer allocator.destroy(task); errdefer allocator.destroy(task);
@ -104,7 +103,7 @@ pub const Task = struct {
return task; 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.Bitmap(usize).BitmapError || vmm.VmmError || Allocator.Error)!*Task {
const task = try create(program_elf.header.entry_address, kernel, task_vmm, allocator); const task = try create(program_elf.header.entry_address, kernel, task_vmm, allocator);
errdefer task.destroy(allocator); errdefer task.destroy(allocator);
@ -141,8 +140,9 @@ pub const Task = struct {
/// ///
/// Arguments: /// Arguments:
/// IN/OUT self: *Self - The pointer to self. /// IN/OUT self: *Self - The pointer to self.
/// IN allocator: Allocator - The allocator used to create the task.
/// ///
pub fn destroy(self: *Self, allocator: *Allocator) void { pub fn destroy(self: *Self, allocator: Allocator) void {
freePid(self.pid); freePid(self.pid);
// We need to check that the the stack has been allocated as task 0 (init) won't have a // 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 // stack allocated as this in the linker script
@ -182,7 +182,7 @@ fn freePid(pid: PidBitmap.IndexType) void {
// For testing the errdefer // For testing the errdefer
const FailingAllocator = std.testing.FailingAllocator; const FailingAllocator = std.testing.FailingAllocator;
const testing_allocator = &std.testing.base_allocator_instance.allocator; const testing_allocator = std.testing.base_allocator_instance.allocator();
fn test_fn1() void {} fn test_fn1() void {}
@ -190,28 +190,28 @@ test "create out of memory for task" {
// Set the global allocator // Set the global allocator
var fa = FailingAllocator.init(testing_allocator, 0); var fa = FailingAllocator.init(testing_allocator, 0);
expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), true, undefined, &fa.allocator)); try expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), true, undefined, fa.allocator()));
expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), false, undefined, &fa.allocator)); try expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), false, undefined, fa.allocator()));
// Make sure any memory allocated is freed // Make sure any memory allocated is freed
expectEqual(fa.allocated_bytes, fa.freed_bytes); try expectEqual(fa.allocated_bytes, fa.freed_bytes);
// Make sure no PIDs were allocated // Make sure no PIDs were allocated
expectEqual(all_pids.bitmap, 0); try expectEqual(all_pids.bitmap, 0);
} }
test "create out of memory for stack" { test "create out of memory for stack" {
// Set the global allocator // Set the global allocator
var fa = FailingAllocator.init(testing_allocator, 1); var fa = FailingAllocator.init(testing_allocator, 1);
expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), true, undefined, &fa.allocator)); try expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), true, undefined, fa.allocator()));
expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), false, undefined, &fa.allocator)); try expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), false, undefined, fa.allocator()));
// Make sure any memory allocated is freed // Make sure any memory allocated is freed
expectEqual(fa.allocated_bytes, fa.freed_bytes); try expectEqual(fa.allocated_bytes, fa.freed_bytes);
// Make sure no PIDs were allocated // Make sure no PIDs were allocated
expectEqual(all_pids.bitmap, 0); try expectEqual(all_pids.bitmap, 0);
} }
test "create expected setup" { test "create expected setup" {
@ -219,15 +219,15 @@ test "create expected setup" {
defer task.destroy(std.testing.allocator); defer task.destroy(std.testing.allocator);
// Will allocate the first PID 0 // Will allocate the first PID 0
expectEqual(task.pid, 0); try expectEqual(task.pid, 0);
expectEqual(task.kernel_stack.len, STACK_SIZE); try expectEqual(task.kernel_stack.len, STACK_SIZE);
expectEqual(task.user_stack.len, 0); try expectEqual(task.user_stack.len, 0);
var user_task = try Task.create(@ptrToInt(test_fn1), false, undefined, std.testing.allocator); var user_task = try Task.create(@ptrToInt(test_fn1), false, undefined, std.testing.allocator);
defer user_task.destroy(std.testing.allocator); defer user_task.destroy(std.testing.allocator);
expectEqual(user_task.pid, 1); try expectEqual(user_task.pid, 1);
expectEqual(user_task.user_stack.len, STACK_SIZE); try expectEqual(user_task.user_stack.len, STACK_SIZE);
expectEqual(user_task.kernel_stack.len, STACK_SIZE); try expectEqual(user_task.kernel_stack.len, STACK_SIZE);
} }
test "destroy cleans up" { test "destroy cleans up" {
@ -242,54 +242,54 @@ test "destroy cleans up" {
user_task.destroy(allocator); user_task.destroy(allocator);
// All PIDs were freed // All PIDs were freed
expectEqual(all_pids.bitmap, 0); try expectEqual(all_pids.bitmap, 0);
} }
test "Multiple create" { test "Multiple create" {
var task1 = try Task.create(@ptrToInt(test_fn1), true, undefined, std.testing.allocator); var task1 = try Task.create(@ptrToInt(test_fn1), true, undefined, std.testing.allocator);
var task2 = try Task.create(@ptrToInt(test_fn1), true, undefined, std.testing.allocator); var task2 = try Task.create(@ptrToInt(test_fn1), true, undefined, std.testing.allocator);
expectEqual(task1.pid, 0); try expectEqual(task1.pid, 0);
expectEqual(task2.pid, 1); try expectEqual(task2.pid, 1);
expectEqual(all_pids.bitmap, 3); try expectEqual(all_pids.bitmap, 3);
task1.destroy(std.testing.allocator); task1.destroy(std.testing.allocator);
expectEqual(all_pids.bitmap, 2); try expectEqual(all_pids.bitmap, 2);
var task3 = try Task.create(@ptrToInt(test_fn1), true, undefined, std.testing.allocator); var task3 = try Task.create(@ptrToInt(test_fn1), true, undefined, std.testing.allocator);
expectEqual(task3.pid, 0); try expectEqual(task3.pid, 0);
expectEqual(all_pids.bitmap, 3); try expectEqual(all_pids.bitmap, 3);
task2.destroy(std.testing.allocator); task2.destroy(std.testing.allocator);
task3.destroy(std.testing.allocator); task3.destroy(std.testing.allocator);
var user_task = try Task.create(@ptrToInt(test_fn1), false, undefined, std.testing.allocator); var user_task = try Task.create(@ptrToInt(test_fn1), false, undefined, std.testing.allocator);
expectEqual(user_task.pid, 0); try expectEqual(user_task.pid, 0);
expectEqual(all_pids.bitmap, 1); try expectEqual(all_pids.bitmap, 1);
user_task.destroy(std.testing.allocator); user_task.destroy(std.testing.allocator);
expectEqual(all_pids.bitmap, 0); try expectEqual(all_pids.bitmap, 0);
} }
test "allocatePid and freePid" { test "allocatePid and freePid" {
expectEqual(all_pids.bitmap, 0); try expectEqual(all_pids.bitmap, 0);
var i: usize = 0; var i: usize = 0;
while (i < PidBitmap.NUM_ENTRIES) : (i += 1) { while (i < PidBitmap.NUM_ENTRIES) : (i += 1) {
expectEqual(i, allocatePid()); try expectEqual(i, allocatePid());
} }
expectEqual(all_pids.bitmap, PidBitmap.BITMAP_FULL); try expectEqual(all_pids.bitmap, PidBitmap.BITMAP_FULL);
i = 0; i = 0;
while (i < PidBitmap.NUM_ENTRIES) : (i += 1) { while (i < PidBitmap.NUM_ENTRIES) : (i += 1) {
freePid(@truncate(PidBitmap.IndexType, i)); freePid(@truncate(PidBitmap.IndexType, i));
} }
expectEqual(all_pids.bitmap, 0); try expectEqual(all_pids.bitmap, 0);
} }
test "createFromElf" { test "createFromElf" {
@ -300,7 +300,7 @@ test "createFromElf" {
const code_address = 0; const code_address = 0;
const elf_data = try elf.testInitData(allocator, "abc123", "strings", .Executable, code_address, 0, elf.SECTION_ALLOCATABLE, 0, code_address, 0); const elf_data = try elf.testInitData(allocator, "abc123", "strings", .Executable, code_address, 0, elf.SECTION_ALLOCATABLE, 0, code_address, 0);
defer allocator.free(elf_data); defer allocator.free(elf_data);
var the_elf = try elf.Elf.init(elf_data, builtin.arch, std.testing.allocator); var the_elf = try elf.Elf.init(elf_data, builtin.cpu.arch, std.testing.allocator);
defer the_elf.deinit(); defer the_elf.deinit();
var the_vmm = try vmm.VirtualMemoryManager(arch.VmmPayload).init(0, 10000, std.testing.allocator, arch.VMM_MAPPER, arch.KERNEL_VMM_PAYLOAD); var the_vmm = try vmm.VirtualMemoryManager(arch.VmmPayload).init(0, 10000, std.testing.allocator, arch.VMM_MAPPER, arch.KERNEL_VMM_PAYLOAD);
@ -308,9 +308,9 @@ test "createFromElf" {
const task = try Task.createFromElf(the_elf, true, &the_vmm, std.testing.allocator); const task = try Task.createFromElf(the_elf, true, &the_vmm, std.testing.allocator);
defer task.destroy(allocator); defer task.destroy(allocator);
std.testing.expectEqual(task.pid, 0); try std.testing.expectEqual(task.pid, 0);
std.testing.expectEqual(task.user_stack.len, 0); try std.testing.expectEqual(task.user_stack.len, 0);
std.testing.expectEqual(task.kernel_stack.len, STACK_SIZE); try std.testing.expectEqual(task.kernel_stack.len, STACK_SIZE);
} }
test "createFromElf clean-up" { test "createFromElf clean-up" {
@ -321,7 +321,7 @@ test "createFromElf clean-up" {
const code_address = 0; const code_address = 0;
const elf_data = try elf.testInitData(allocator, "abc123", "strings", .Executable, code_address, 0, elf.SECTION_ALLOCATABLE, 0, code_address, 0); const elf_data = try elf.testInitData(allocator, "abc123", "strings", .Executable, code_address, 0, elf.SECTION_ALLOCATABLE, 0, code_address, 0);
defer allocator.free(elf_data); defer allocator.free(elf_data);
var the_elf = try elf.Elf.init(elf_data, builtin.arch, std.testing.allocator); var the_elf = try elf.Elf.init(elf_data, builtin.cpu.arch, std.testing.allocator);
defer the_elf.deinit(); defer the_elf.deinit();
var the_vmm = try vmm.VirtualMemoryManager(arch.VmmPayload).init(0, 10000, std.testing.allocator, arch.VMM_MAPPER, arch.KERNEL_VMM_PAYLOAD); var the_vmm = try vmm.VirtualMemoryManager(arch.VmmPayload).init(0, 10000, std.testing.allocator, arch.VMM_MAPPER, arch.KERNEL_VMM_PAYLOAD);
@ -331,14 +331,14 @@ test "createFromElf clean-up" {
// Test clean-up // Test clean-up
// Test OutOfMemory // Test OutOfMemory
var allocator2 = &std.testing.FailingAllocator.init(allocator, 0).allocator; var allocator2 = std.testing.FailingAllocator.init(allocator, 0).allocator();
std.testing.expectError(std.mem.Allocator.Error.OutOfMemory, Task.createFromElf(the_elf, true, &the_vmm, allocator2)); try std.testing.expectError(std.mem.Allocator.Error.OutOfMemory, Task.createFromElf(the_elf, true, &the_vmm, allocator2));
std.testing.expectEqual(all_pids.num_free_entries, PidBitmap.NUM_ENTRIES - 1); try std.testing.expectEqual(all_pids.num_free_entries, PidBitmap.NUM_ENTRIES - 1);
// Test AlreadyAllocated // Test AlreadyAllocated
std.testing.expectError(error.AlreadyAllocated, Task.createFromElf(the_elf, true, &the_vmm, allocator)); try std.testing.expectError(error.AlreadyAllocated, Task.createFromElf(the_elf, true, &the_vmm, allocator));
// Test OutOfBounds // Test OutOfBounds
the_elf.section_headers[0].virtual_address = the_vmm.end + 1; the_elf.section_headers[0].virtual_address = the_vmm.end + 1;
std.testing.expectError(error.OutOfBounds, Task.createFromElf(the_elf, true, &the_vmm, allocator)); try std.testing.expectError(error.OutOfBounds, Task.createFromElf(the_elf, true, &the_vmm, allocator));
// Test errdefer clean-up by fillng up all but one block in the VMM so allocating the last section fails // Test errdefer clean-up by fillng up all but one block in the VMM so allocating the last section fails
// The allocation for the first section should be cleaned up in case of an error // The allocation for the first section should be cleaned up in case of an error
@ -348,5 +348,5 @@ test "createFromElf clean-up" {
try the_vmm.free(available_address); try the_vmm.free(available_address);
// Make the strings section allocatable so createFromElf tries to allocate more than one // Make the strings section allocatable so createFromElf tries to allocate more than one
the_elf.section_headers[1].flags |= elf.SECTION_ALLOCATABLE; the_elf.section_headers[1].flags |= elf.SECTION_ALLOCATABLE;
std.testing.expectError(error.AlreadyAllocated, Task.createFromElf(the_elf, true, &the_vmm, std.testing.allocator)); try std.testing.expectError(error.AlreadyAllocated, Task.createFromElf(the_elf, true, &the_vmm, std.testing.allocator));
} }

View file

@ -24,7 +24,7 @@ pub const TTY = struct {
/// The current tty stream /// The current tty stream
var tty: TTY = undefined; var tty: TTY = undefined;
var allocator: *Allocator = undefined; var allocator: Allocator = undefined;
/// ///
/// A call back function for use in the formation of a string. This calls the architecture's print function. /// A call back function for use in the formation of a string. This calls the architecture's print function.
@ -37,6 +37,8 @@ var allocator: *Allocator = undefined;
/// The number of characters printed /// The number of characters printed
/// ///
fn printCallback(ctx: void, str: []const u8) !usize { fn printCallback(ctx: void, str: []const u8) !usize {
// Suppress unused var warning
_ = ctx;
tty.print(str) catch |e| panic(@errorReturnTrace(), "Failed to print to tty: {}\n", .{e}); tty.print(str) catch |e| panic(@errorReturnTrace(), "Failed to print to tty: {}\n", .{e});
return str.len; return str.len;
} }
@ -52,7 +54,7 @@ fn printCallback(ctx: void, str: []const u8) !usize {
pub fn print(comptime format: []const u8, args: anytype) void { pub fn print(comptime format: []const u8, args: anytype) void {
// Printing can't error because of the scrolling, if it does, we have a big problem // Printing can't error because of the scrolling, if it does, we have a big problem
fmt.format(Writer{ .context = {} }, format, args) catch |e| { fmt.format(Writer{ .context = {} }, format, args) catch |e| {
log.emerg("Error printing. Error: {}\n", .{e}); log.err("Error printing. Error: {}\n", .{e});
}; };
} }
@ -98,10 +100,10 @@ pub fn clear() void {
/// Initialise the TTY. The details of which are up to the architecture /// Initialise the TTY. The details of which are up to the architecture
/// ///
/// Arguments: /// Arguments:
/// IN alloc: *std.mem.Allocator - The allocator to use when requiring memory /// IN alloc: Allocator - The allocator to use when requiring memory
/// IN boot_payload: arch.BootPayload - The payload passed to the kernel on boot /// IN boot_payload: arch.BootPayload - The payload passed to the kernel on boot
/// ///
pub fn init(alloc: *Allocator, boot_payload: arch.BootPayload) void { pub fn init(alloc: Allocator, boot_payload: arch.BootPayload) void {
log.info("Init\n", .{}); log.info("Init\n", .{});
defer log.info("Done\n", .{}); defer log.info("Done\n", .{});
tty = arch.initTTY(boot_payload); tty = arch.initTTY(boot_payload);

View file

@ -1,6 +1,6 @@
const build_options = @import("build_options"); const build_options = @import("build_options");
const mock_path = build_options.mock_path; const mock_path = build_options.mock_path;
const builtin = @import("builtin"); const builtin = std.builtin;
const is_test = builtin.is_test; const is_test = builtin.is_test;
const std = @import("std"); const std = @import("std");
const log = std.log.scoped(.vmm); const log = std.log.scoped(.vmm);
@ -9,8 +9,9 @@ const pmm = @import("pmm.zig");
const mem = @import("mem.zig"); const mem = @import("mem.zig");
const tty = @import("tty.zig"); const tty = @import("tty.zig");
const panic = @import("panic.zig").panic; const panic = @import("panic.zig").panic;
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig").internals; const arch = @import("arch.zig").internals;
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
/// Attributes for a virtual memory allocation /// Attributes for a virtual memory allocation
pub const Attributes = struct { pub const Attributes = struct {
@ -71,7 +72,7 @@ pub fn Mapper(comptime Payload: type) type {
/// Error: AllocatorError || MapperError /// Error: AllocatorError || MapperError
/// The causes depend on the mapper used /// The causes depend on the mapper used
/// ///
mapFn: fn (virtual_start: usize, virtual_end: usize, physical_start: usize, physical_end: usize, attrs: Attributes, allocator: *Allocator, spec: Payload) (Allocator.Error || MapperError)!void, mapFn: fn (virtual_start: usize, virtual_end: usize, physical_start: usize, physical_end: usize, attrs: Attributes, allocator: Allocator, spec: Payload) (Allocator.Error || MapperError)!void,
/// ///
/// Unmap a region (can span more than one block) of virtual memory from its physical memory. After a call to this function, the memory should not be accessible without error. /// Unmap a region (can span more than one block) of virtual memory from its physical memory. After a call to this function, the memory should not be accessible without error.
@ -85,7 +86,7 @@ pub fn Mapper(comptime Payload: type) type {
/// Error: MapperError /// Error: MapperError
/// The causes depend on the mapper used /// The causes depend on the mapper used
/// ///
unmapFn: fn (virtual_start: usize, virtual_end: usize, allocator: *Allocator, spec: Payload) MapperError!void, unmapFn: fn (virtual_start: usize, virtual_end: usize, allocator: Allocator, spec: Payload) MapperError!void,
}; };
} }
@ -141,7 +142,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
end: usize, end: usize,
/// The allocator to use when allocating and freeing regions /// The allocator to use when allocating and freeing regions
allocator: *Allocator, allocator: Allocator,
/// All allocations that have been made with this manager /// All allocations that have been made with this manager
allocations: std.hash_map.AutoHashMap(usize, Allocation), allocations: std.hash_map.AutoHashMap(usize, Allocation),
@ -160,7 +161,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
/// Arguments: /// Arguments:
/// IN start: usize - The start of the memory region to manage /// IN start: usize - The start of the memory region to manage
/// IN end: usize - The end of the memory region to manage. Must be greater than the start /// IN end: usize - The end of the memory region to manage. Must be greater than the start
/// IN/OUT allocator: *Allocator - The allocator to use when allocating and freeing regions /// IN/OUT allocator: Allocator - The allocator to use when allocating and freeing regions
/// IN mapper: Mapper - The mapper to use when allocating and freeing regions /// IN mapper: Mapper - The mapper to use when allocating and freeing regions
/// IN payload: Payload - The payload data to be passed to the mapper /// IN payload: Payload - The payload data to be passed to the mapper
/// ///
@ -170,7 +171,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
/// Error: Allocator.Error /// Error: Allocator.Error
/// error.OutOfMemory - The allocator cannot allocate the memory required /// error.OutOfMemory - The allocator cannot allocate the memory required
/// ///
pub fn init(start: usize, end: usize, allocator: *Allocator, mapper: Mapper(Payload), payload: Payload) Allocator.Error!Self { pub fn init(start: usize, end: usize, allocator: Allocator, mapper: Mapper(Payload), payload: Payload) Allocator.Error!Self {
const size = end - start; 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(usize).init(std.mem.alignForward(size, pmm.BLOCK_SIZE) / pmm.BLOCK_SIZE, allocator);
return Self{ return Self{
@ -209,10 +210,10 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
var it = self.allocations.iterator(); var it = self.allocations.iterator();
while (it.next()) |entry| { while (it.next()) |entry| {
var list = std.ArrayList(usize).init(self.allocator); var list = std.ArrayList(usize).init(self.allocator);
for (entry.value.physical.items) |block| { for (entry.value_ptr.physical.items) |block| {
_ = try list.append(block); _ = try list.append(block);
} }
_ = try clone.allocations.put(entry.key, Allocation{ .physical = list }); _ = try clone.allocations.put(entry.key_ptr.*, Allocation{ .physical = list });
} }
return clone; return clone;
} }
@ -227,7 +228,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
self.bmp.deinit(); self.bmp.deinit();
var it = self.allocations.iterator(); var it = self.allocations.iterator();
while (it.next()) |entry| { while (it.next()) |entry| {
entry.value.physical.deinit(); entry.value_ptr.physical.deinit();
} }
self.allocations.deinit(); self.allocations.deinit();
} }
@ -248,9 +249,9 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
pub fn virtToPhys(self: *const Self, virt: usize) VmmError!usize { pub fn virtToPhys(self: *const Self, virt: usize) VmmError!usize {
var it = self.allocations.iterator(); var it = self.allocations.iterator();
while (it.next()) |entry| { while (it.next()) |entry| {
const vaddr = entry.key; const vaddr = entry.key_ptr.*;
const allocation = entry.value; const allocation = entry.value_ptr.*;
// If this allocation range covers the virtual address then figure out the corresponding physical block // If this allocation range covers the virtual address then figure out the corresponding physical block
if (vaddr <= virt and vaddr + (allocation.physical.items.len * BLOCK_SIZE) > virt) { if (vaddr <= virt and vaddr + (allocation.physical.items.len * BLOCK_SIZE) > virt) {
const block_number = (virt - vaddr) / BLOCK_SIZE; const block_number = (virt - vaddr) / BLOCK_SIZE;
@ -277,8 +278,8 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
pub fn physToVirt(self: *const Self, phys: usize) VmmError!usize { pub fn physToVirt(self: *const Self, phys: usize) VmmError!usize {
var it = self.allocations.iterator(); var it = self.allocations.iterator();
while (it.next()) |entry| { while (it.next()) |entry| {
const vaddr = entry.key; const vaddr = entry.key_ptr.*;
const allocation = entry.value; const allocation = entry.value_ptr.*;
for (allocation.physical.items) |block, i| { for (allocation.physical.items) |block, i| {
if (block <= phys and block + BLOCK_SIZE > phys) { if (block <= phys and block + BLOCK_SIZE > phys) {
@ -401,7 +402,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
// Allocate from a specific entry if the caller requested it // Allocate from a specific entry if the caller requested it
if (self.bmp.setContiguous(num, if (virtual_addr) |a| (a - self.start) / BLOCK_SIZE else null)) |entry| { if (self.bmp.setContiguous(num, if (virtual_addr) |a| (a - self.start) / BLOCK_SIZE else null)) |entry| {
var block_list = std.ArrayList(usize).init(self.allocator); var block_list = std.ArrayList(usize).init(self.allocator);
try block_list.ensureCapacity(num); try block_list.ensureUnusedCapacity(num);
var i: usize = 0; var i: usize = 0;
const vaddr_start = self.start + entry * BLOCK_SIZE; const vaddr_start = self.start + entry * BLOCK_SIZE;
@ -452,8 +453,8 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
defer blocks.deinit(); defer blocks.deinit();
var it = other.allocations.iterator(); var it = other.allocations.iterator();
while (it.next()) |allocation| { while (it.next()) |allocation| {
const virtual = allocation.key; const virtual = allocation.key_ptr.*;
const physical = allocation.value.physical.items; const physical = allocation.value_ptr.*.physical.items;
if (start_addr >= virtual and virtual + physical.len * BLOCK_SIZE >= end_addr) { if (start_addr >= virtual and virtual + physical.len * BLOCK_SIZE >= end_addr) {
const first_block_idx = (start_addr - virtual) / BLOCK_SIZE; const first_block_idx = (start_addr - virtual) / BLOCK_SIZE;
const last_block_idx = (end_addr - virtual) / BLOCK_SIZE; const last_block_idx = (end_addr - virtual) / BLOCK_SIZE;
@ -532,7 +533,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
panic(@errorReturnTrace(), "Failed to unmap VMM reserved memory from 0x{X} to 0x{X}: {}\n", .{ region_start, region_end, e }); panic(@errorReturnTrace(), "Failed to unmap VMM reserved memory from 0x{X} to 0x{X}: {}\n", .{ region_start, region_end, e });
}; };
// The allocation is freed so remove from the map // The allocation is freed so remove from the map
self.allocations.removeAssertDiscard(vaddr); assert(self.allocations.remove(vaddr));
} else { } else {
return VmmError.NotAllocated; return VmmError.NotAllocated;
} }
@ -545,7 +546,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
/// ///
/// Arguments: /// Arguments:
/// IN mem_profile: *const mem.MemProfile - The system's memory profile. This is used to find the kernel code region and boot modules /// IN mem_profile: *const mem.MemProfile - The system's memory profile. This is used to find the kernel code region and boot modules
/// IN/OUT allocator: *Allocator - The allocator to use when needing to allocate memory /// IN/OUT allocator: Allocator - The allocator to use when needing to allocate memory
/// ///
/// Return: VirtualMemoryManager /// Return: VirtualMemoryManager
/// The virtual memory manager created with all reserved virtual regions allocated /// The virtual memory manager created with all reserved virtual regions allocated
@ -553,7 +554,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
/// Error: Allocator.Error /// Error: Allocator.Error
/// error.OutOfMemory - The allocator cannot allocate the memory required /// error.OutOfMemory - The allocator cannot allocate the memory required
/// ///
pub fn init(mem_profile: *const mem.MemProfile, allocator: *Allocator) Allocator.Error!*VirtualMemoryManager(arch.VmmPayload) { pub fn init(mem_profile: *const mem.MemProfile, allocator: Allocator) Allocator.Error!*VirtualMemoryManager(arch.VmmPayload) {
log.info("Init\n", .{}); log.info("Init\n", .{});
defer log.info("Done\n", .{}); defer log.info("Done\n", .{});
@ -595,13 +596,13 @@ test "virtToPhys" {
try vmm.set(.{ .start = vstart, .end = vstart + BLOCK_SIZE }, mem.Range{ .start = pstart + BLOCK_SIZE * 2, .end = pend }, .{ .kernel = true, .writable = true, .cachable = true }); try vmm.set(.{ .start = vstart, .end = vstart + BLOCK_SIZE }, mem.Range{ .start = pstart + BLOCK_SIZE * 2, .end = pend }, .{ .kernel = true, .writable = true, .cachable = true });
try vmm.set(.{ .start = vstart + BLOCK_SIZE, .end = vend }, mem.Range{ .start = pstart, .end = pstart + BLOCK_SIZE * 2 }, .{ .kernel = true, .writable = true, .cachable = true }); try vmm.set(.{ .start = vstart + BLOCK_SIZE, .end = vend }, mem.Range{ .start = pstart, .end = pstart + BLOCK_SIZE * 2 }, .{ .kernel = true, .writable = true, .cachable = true });
std.testing.expectEqual(pstart + BLOCK_SIZE * 2, try vmm.virtToPhys(vstart)); try std.testing.expectEqual(pstart + BLOCK_SIZE * 2, try vmm.virtToPhys(vstart));
std.testing.expectEqual(pstart + BLOCK_SIZE * 2 + 29, (try vmm.virtToPhys(vstart + 29))); try std.testing.expectEqual(pstart + BLOCK_SIZE * 2 + 29, (try vmm.virtToPhys(vstart + 29)));
std.testing.expectEqual(pstart + 29, (try vmm.virtToPhys(vstart + BLOCK_SIZE + 29))); try std.testing.expectEqual(pstart + 29, (try vmm.virtToPhys(vstart + BLOCK_SIZE + 29)));
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vstart - 1)); try std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vstart - 1));
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend)); try std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend));
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend + 1)); try std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend + 1));
} }
test "physToVirt" { test "physToVirt" {
@ -618,13 +619,13 @@ test "physToVirt" {
try vmm.set(.{ .start = vstart, .end = vstart + BLOCK_SIZE }, mem.Range{ .start = pstart + BLOCK_SIZE * 2, .end = pend }, .{ .kernel = true, .writable = true, .cachable = true }); try vmm.set(.{ .start = vstart, .end = vstart + BLOCK_SIZE }, mem.Range{ .start = pstart + BLOCK_SIZE * 2, .end = pend }, .{ .kernel = true, .writable = true, .cachable = true });
try vmm.set(.{ .start = vstart + BLOCK_SIZE, .end = vend }, mem.Range{ .start = pstart, .end = pstart + BLOCK_SIZE * 2 }, .{ .kernel = true, .writable = true, .cachable = true }); try vmm.set(.{ .start = vstart + BLOCK_SIZE, .end = vend }, mem.Range{ .start = pstart, .end = pstart + BLOCK_SIZE * 2 }, .{ .kernel = true, .writable = true, .cachable = true });
std.testing.expectEqual(vstart, try vmm.physToVirt(pstart + BLOCK_SIZE * 2)); try std.testing.expectEqual(vstart, try vmm.physToVirt(pstart + BLOCK_SIZE * 2));
std.testing.expectEqual(vstart + 29, (try vmm.physToVirt(pstart + BLOCK_SIZE * 2 + 29))); try std.testing.expectEqual(vstart + 29, (try vmm.physToVirt(pstart + BLOCK_SIZE * 2 + 29)));
std.testing.expectEqual(vstart + BLOCK_SIZE + 29, (try vmm.physToVirt(pstart + 29))); try std.testing.expectEqual(vstart + BLOCK_SIZE + 29, (try vmm.physToVirt(pstart + 29)));
std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pstart - 1)); try std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pstart - 1));
std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend)); try std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend));
std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend + 1)); try std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend + 1));
} }
test "alloc and free" { test "alloc and free" {
@ -645,11 +646,11 @@ test "alloc and free" {
var should_be_set = true; var should_be_set = true;
if (entry + num_to_alloc > num_entries) { if (entry + num_to_alloc > num_entries) {
// If the number to allocate exceeded the number of entries, then allocation should have failed // If the number to allocate exceeded the number of entries, then allocation should have failed
std.testing.expectEqual(@as(?usize, null), result); try std.testing.expectEqual(@as(?usize, null), result);
should_be_set = false; should_be_set = false;
} else { } else {
// Else it should have succeeded and allocated the correct address // Else it should have succeeded and allocated the correct address
std.testing.expectEqual(@as(?usize, vmm.start + entry * BLOCK_SIZE), result); try std.testing.expectEqual(@as(?usize, vmm.start + entry * BLOCK_SIZE), result);
try virtual_allocations.append(result.?); try virtual_allocations.append(result.?);
} }
@ -658,20 +659,20 @@ test "alloc and free" {
while (vaddr < (entry + num_to_alloc) * BLOCK_SIZE) : (vaddr += BLOCK_SIZE) { while (vaddr < (entry + num_to_alloc) * BLOCK_SIZE) : (vaddr += BLOCK_SIZE) {
if (should_be_set) { if (should_be_set) {
// Allocation succeeded so this address should be set // Allocation succeeded so this address should be set
std.testing.expect(try vmm.isSet(vaddr)); try std.testing.expect(try vmm.isSet(vaddr));
// The test mapper should have received this address // The test mapper should have received this address
std.testing.expect(try allocations.isSet(vaddr / BLOCK_SIZE)); try std.testing.expect(try allocations.isSet(vaddr / BLOCK_SIZE));
} else { } else {
// Allocation failed as there weren't enough free entries // Allocation failed as there weren't enough free entries
if (vaddr >= num_entries * BLOCK_SIZE) { if (vaddr >= num_entries * BLOCK_SIZE) {
// If this address is beyond the VMM's end address, it should be out of bounds // If this address is beyond the VMM's end address, it should be out of bounds
std.testing.expectError(bitmap.Bitmap(u32).BitmapError.OutOfBounds, vmm.isSet(vaddr)); try std.testing.expectError(bitmap.Bitmap(u32).BitmapError.OutOfBounds, vmm.isSet(vaddr));
std.testing.expectError(bitmap.Bitmap(u64).BitmapError.OutOfBounds, allocations.isSet(vaddr / BLOCK_SIZE)); try std.testing.expectError(bitmap.Bitmap(u64).BitmapError.OutOfBounds, allocations.isSet(vaddr / BLOCK_SIZE));
} else { } else {
// Else it should not be set // Else it should not be set
std.testing.expect(!(try vmm.isSet(vaddr))); try std.testing.expect(!(try vmm.isSet(vaddr)));
// The test mapper should not have received this address // The test mapper should not have received this address
std.testing.expect(!(try allocations.isSet(vaddr / BLOCK_SIZE))); try std.testing.expect(!(try allocations.isSet(vaddr / BLOCK_SIZE)));
} }
} }
} }
@ -680,31 +681,31 @@ test "alloc and free" {
// All later entries should not be set // All later entries should not be set
var later_entry = entry; var later_entry = entry;
while (later_entry < num_entries) : (later_entry += 1) { while (later_entry < num_entries) : (later_entry += 1) {
std.testing.expect(!(try vmm.isSet(vmm.start + later_entry * BLOCK_SIZE))); try std.testing.expect(!(try vmm.isSet(vmm.start + later_entry * BLOCK_SIZE)));
std.testing.expect(!(try pmm.isSet(later_entry * BLOCK_SIZE))); try std.testing.expect(!(try pmm.isSet(later_entry * BLOCK_SIZE)));
} }
} }
// Try freeing all allocations // Try freeing all allocations
for (virtual_allocations.items) |alloc| { for (virtual_allocations.items) |alloc| {
const alloc_group = vmm.allocations.get(alloc); const alloc_group = vmm.allocations.get(alloc);
std.testing.expect(alloc_group != null); try std.testing.expect(alloc_group != null);
const physical = alloc_group.?.physical; const physical = alloc_group.?.physical;
// We need to create a copy of the physical allocations since the free call deinits them // We need to create a copy of the physical allocations since the free call deinits them
var physical_copy = std.ArrayList(usize).init(std.testing.allocator); var physical_copy = std.ArrayList(usize).init(std.testing.allocator);
defer physical_copy.deinit(); defer physical_copy.deinit();
// Make sure they are all reserved in the PMM // Make sure they are all reserved in the PMM
for (physical.items) |phys| { for (physical.items) |phys| {
std.testing.expect(try pmm.isSet(phys)); try std.testing.expect(try pmm.isSet(phys));
try physical_copy.append(phys); try physical_copy.append(phys);
} }
vmm.free(alloc) catch unreachable; vmm.free(alloc) catch unreachable;
// This virtual allocation should no longer be in the hashmap // This virtual allocation should no longer be in the hashmap
std.testing.expectEqual(vmm.allocations.get(alloc), null); try std.testing.expectEqual(vmm.allocations.get(alloc), null);
std.testing.expect(!try vmm.isSet(alloc)); try std.testing.expect(!try vmm.isSet(alloc));
// And all its physical blocks should now be free // And all its physical blocks should now be free
for (physical_copy.items) |phys| { for (physical_copy.items) |phys| {
std.testing.expect(!try pmm.isSet(phys)); try std.testing.expect(!try pmm.isSet(phys));
} }
} }
} }
@ -716,24 +717,24 @@ test "alloc at a specific address" {
const attrs = Attributes{ .writable = true, .cachable = true, .kernel = true }; const attrs = Attributes{ .writable = true, .cachable = true, .kernel = true };
// Try allocating at the start // Try allocating at the start
std.testing.expectEqual(vmm.alloc(10, vmm.start, attrs), vmm.start); try std.testing.expectEqual(vmm.alloc(10, vmm.start, attrs), vmm.start);
// Try that again // Try that again
std.testing.expectEqual(vmm.alloc(5, vmm.start, attrs), null); try std.testing.expectEqual(vmm.alloc(5, vmm.start, attrs), null);
const middle = vmm.start + (vmm.end - vmm.start) / 2; const middle = vmm.start + (vmm.end - vmm.start) / 2;
// Try allocating at the middle // Try allocating at the middle
std.testing.expectEqual(vmm.alloc(num_entries / 2, middle, attrs), middle); try std.testing.expectEqual(vmm.alloc(num_entries / 2, middle, attrs), middle);
// Allocating after the start and colliding with the middle should be impossible // Allocating after the start and colliding with the middle should be impossible
std.testing.expectEqual(vmm.alloc(num_entries / 2, vmm.start + 10 * BLOCK_SIZE, attrs), null); try std.testing.expectEqual(vmm.alloc(num_entries / 2, vmm.start + 10 * BLOCK_SIZE, attrs), null);
// Allocating within the last half should be impossible // Allocating within the last half should be impossible
std.testing.expectEqual(vmm.alloc(num_entries / 4, middle + BLOCK_SIZE, attrs), null); try std.testing.expectEqual(vmm.alloc(num_entries / 4, middle + BLOCK_SIZE, attrs), null);
// It should still be possible to allocate between the start and middle // It should still be possible to allocate between the start and middle
std.testing.expectEqual(vmm.alloc(num_entries / 2 - 10, vmm.start + 10 * BLOCK_SIZE, attrs), vmm.start + 10 * BLOCK_SIZE); try std.testing.expectEqual(vmm.alloc(num_entries / 2 - 10, vmm.start + 10 * BLOCK_SIZE, attrs), vmm.start + 10 * BLOCK_SIZE);
// It should now be full // It should now be full
std.testing.expectEqual(vmm.bmp.num_free_entries, 0); try std.testing.expectEqual(vmm.bmp.num_free_entries, 0);
// Allocating at the end and before the start should fail // Allocating at the end and before the start should fail
std.testing.expectEqual(vmm.alloc(1, vmm.end, attrs), null); try std.testing.expectEqual(vmm.alloc(1, vmm.end, attrs), null);
std.testing.expectEqual(vmm.alloc(1, vmm.start - BLOCK_SIZE, attrs), null); try std.testing.expectEqual(vmm.alloc(1, vmm.start - BLOCK_SIZE, attrs), null);
} }
test "set" { test "set" {
@ -748,21 +749,21 @@ test "set" {
const attrs = Attributes{ .kernel = true, .writable = true, .cachable = true }; const attrs = Attributes{ .kernel = true, .writable = true, .cachable = true };
try vmm.set(.{ .start = vstart, .end = vend }, mem.Range{ .start = pstart, .end = pend }, attrs); try vmm.set(.{ .start = vstart, .end = vend }, mem.Range{ .start = pstart, .end = pend }, attrs);
// Make sure it put the correct address in the map // Make sure it put the correct address in the map
std.testing.expect(vmm.allocations.get(vstart) != null); try std.testing.expect(vmm.allocations.get(vstart) != null);
var allocations = test_allocations.?; var allocations = test_allocations.?;
// The entries before the virtual start shouldn't be set // The entries before the virtual start shouldn't be set
var vaddr = vmm.start; var vaddr = vmm.start;
while (vaddr < vstart) : (vaddr += BLOCK_SIZE) { while (vaddr < vstart) : (vaddr += BLOCK_SIZE) {
std.testing.expect(!(try allocations.isSet((vaddr - vmm.start) / BLOCK_SIZE))); try std.testing.expect(!(try allocations.isSet((vaddr - vmm.start) / BLOCK_SIZE)));
} }
// The entries up until the virtual end should be set // The entries up until the virtual end should be set
while (vaddr < vend) : (vaddr += BLOCK_SIZE) { while (vaddr < vend) : (vaddr += BLOCK_SIZE) {
std.testing.expect(try allocations.isSet((vaddr - vmm.start) / BLOCK_SIZE)); try std.testing.expect(try allocations.isSet((vaddr - vmm.start) / BLOCK_SIZE));
} }
// The entries after the virtual end should not be set // The entries after the virtual end should not be set
while (vaddr < vmm.end) : (vaddr += BLOCK_SIZE) { while (vaddr < vmm.end) : (vaddr += BLOCK_SIZE) {
std.testing.expect(!(try allocations.isSet((vaddr - vmm.start) / BLOCK_SIZE))); try std.testing.expect(!(try allocations.isSet((vaddr - vmm.start) / BLOCK_SIZE)));
} }
} }
@ -772,37 +773,37 @@ test "copy" {
defer testDeinit(&vmm); defer testDeinit(&vmm);
const attrs = .{ .kernel = true, .cachable = true, .writable = true }; const attrs = .{ .kernel = true, .cachable = true, .writable = true };
const alloc0 = (try vmm.alloc(24, null, attrs)).?; _ = (try vmm.alloc(24, null, attrs)).?;
var mirrored = try vmm.copy(); var mirrored = try vmm.copy();
defer mirrored.deinit(); defer mirrored.deinit();
std.testing.expectEqual(vmm.bmp.num_free_entries, mirrored.bmp.num_free_entries); try std.testing.expectEqual(vmm.bmp.num_free_entries, mirrored.bmp.num_free_entries);
std.testing.expectEqual(vmm.start, mirrored.start); try std.testing.expectEqual(vmm.start, mirrored.start);
std.testing.expectEqual(vmm.end, mirrored.end); try std.testing.expectEqual(vmm.end, mirrored.end);
std.testing.expectEqual(vmm.allocations.count(), mirrored.allocations.count()); try std.testing.expectEqual(vmm.allocations.count(), mirrored.allocations.count());
var it = vmm.allocations.iterator(); var it = vmm.allocations.iterator();
while (it.next()) |next| { while (it.next()) |next| {
for (mirrored.allocations.get(next.key).?.physical.items) |block, i| { for (mirrored.allocations.get(next.key_ptr.*).?.physical.items) |block, i| {
std.testing.expectEqual(block, vmm.allocations.get(next.key).?.physical.items[i]); try std.testing.expectEqual(block, vmm.allocations.get(next.key_ptr.*).?.physical.items[i]);
} }
} }
std.testing.expectEqual(vmm.mapper, mirrored.mapper); try std.testing.expectEqual(vmm.mapper, mirrored.mapper);
std.testing.expectEqual(vmm.payload, mirrored.payload); try std.testing.expectEqual(vmm.payload, mirrored.payload);
// Allocating in the new VMM shouldn't allocate in the mirrored one // Allocating in the new VMM shouldn't allocate in the mirrored one
const alloc1 = (try mirrored.alloc(3, null, attrs)).?; const alloc1 = (try mirrored.alloc(3, null, attrs)).?;
std.testing.expectEqual(vmm.allocations.count() + 1, mirrored.allocations.count()); try std.testing.expectEqual(vmm.allocations.count() + 1, mirrored.allocations.count());
std.testing.expectEqual(vmm.bmp.num_free_entries - 3, mirrored.bmp.num_free_entries); try std.testing.expectEqual(vmm.bmp.num_free_entries - 3, mirrored.bmp.num_free_entries);
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(alloc1)); try std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(alloc1));
// And vice-versa // And vice-versa
const alloc2 = (try vmm.alloc(3, null, attrs)).?; _ = (try vmm.alloc(3, null, attrs)).?;
const alloc3 = (try vmm.alloc(1, null, attrs)).?; const alloc3 = (try vmm.alloc(1, null, attrs)).?;
const alloc4 = (try vmm.alloc(1, null, attrs)).?; const alloc4 = (try vmm.alloc(1, null, attrs)).?;
std.testing.expectEqual(vmm.allocations.count() - 2, mirrored.allocations.count()); try std.testing.expectEqual(vmm.allocations.count() - 2, mirrored.allocations.count());
std.testing.expectEqual(vmm.bmp.num_free_entries + 2, mirrored.bmp.num_free_entries); try std.testing.expectEqual(vmm.bmp.num_free_entries + 2, mirrored.bmp.num_free_entries);
std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc3)); try std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc3));
std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc4)); try std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc4));
} }
test "copyData from" { test "copyData from" {
@ -820,21 +821,21 @@ test "copyData from" {
// Make sure they are the same // Make sure they are the same
var buff2 = @intToPtr([*]u8, alloc)[0..buff.len]; var buff2 = @intToPtr([*]u8, alloc)[0..buff.len];
std.testing.expectEqualSlices(u8, buff[0..buff.len], buff2); try std.testing.expectEqualSlices(u8, buff[0..buff.len], buff2);
std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries); try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
// TODO Remove the subtraction by one once we are able to free the temp space in copyData // TODO Remove the subtraction by one once we are able to free the temp space in copyData
std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries); try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries);
// Test NotAllocated // Test NotAllocated
std.testing.expectError(VmmError.NotAllocated, vmm2.copyData(&vmm, true, buff[0..buff.len], alloc + alloc1_blocks * BLOCK_SIZE)); try std.testing.expectError(VmmError.NotAllocated, vmm2.copyData(&vmm, true, buff[0..buff.len], alloc + alloc1_blocks * BLOCK_SIZE));
std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries); try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries); try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries);
// Test Bitmap.Error.OutOfBounds // Test Bitmap.Error.OutOfBounds
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, vmm2.copyData(&vmm, true, buff[0..buff.len], vmm.end));
std.testing.expectError(bitmap.Bitmap(usize).BitmapError.OutOfBounds, vmm.copyData(&vmm2, true, buff[0..buff.len], vmm2.end)); try std.testing.expectError(bitmap.Bitmap(usize).BitmapError.OutOfBounds, vmm.copyData(&vmm2, true, buff[0..buff.len], vmm2.end));
std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries); try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries); try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries);
} }
test "copyDaya to" { test "copyDaya to" {
@ -851,9 +852,9 @@ test "copyDaya to" {
var buff2 = @intToPtr([*]u8, alloc)[0..buff.len]; var buff2 = @intToPtr([*]u8, alloc)[0..buff.len];
try vmm2.copyData(&vmm, false, buff[0..], alloc); try vmm2.copyData(&vmm, false, buff[0..], alloc);
std.testing.expectEqualSlices(u8, buff[0..buff.len], buff2); try std.testing.expectEqualSlices(u8, buff[0..buff.len], buff2);
std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries); try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries); 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(u64) = null;
@ -881,7 +882,6 @@ pub fn testInit(num_entries: u32) Allocator.Error!VirtualMemoryManager(arch.VmmP
allocations.clearEntry(entry) catch unreachable; allocations.clearEntry(entry) catch unreachable;
} }
} }
var allocations = test_allocations orelse unreachable;
const mem_profile = mem.MemProfile{ const mem_profile = mem.MemProfile{
.vaddr_end = undefined, .vaddr_end = undefined,
.vaddr_start = undefined, .vaddr_start = undefined,
@ -920,11 +920,15 @@ pub fn testDeinit(vmm: *VirtualMemoryManager(arch.VmmPayload)) void {
/// IN pstart: usize - The start of the physical region to map /// IN pstart: usize - The start of the physical region to map
/// IN pend: usize - The end of the physical region to map /// IN pend: usize - The end of the physical region to map
/// IN attrs: Attributes - The attributes to map with /// IN attrs: Attributes - The attributes to map with
/// IN/OUT allocator: *Allocator - The allocator to use. Ignored /// IN/OUT allocator: Allocator - The allocator to use. Ignored
/// IN payload: arch.VmmPayload - The payload value. Expected to be arch.KERNEL_VMM_PAYLOAD /// IN payload: arch.VmmPayload - The payload value. Expected to be arch.KERNEL_VMM_PAYLOAD
/// ///
fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attributes, allocator: *Allocator, payload: arch.VmmPayload) (Allocator.Error || MapperError)!void { fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attributes, allocator: Allocator, payload: arch.VmmPayload) MapperError!void {
std.testing.expectEqual(arch.KERNEL_VMM_PAYLOAD, payload); // Suppress unused var warning
_ = attrs;
_ = allocator;
if (vend - vstart != pend - pstart) return MapperError.AddressMismatch;
std.testing.expectEqual(arch.KERNEL_VMM_PAYLOAD, payload) catch unreachable;
var vaddr = vstart; var vaddr = vstart;
var allocations = test_allocations.?; var allocations = test_allocations.?;
while (vaddr < vend) : (vaddr += BLOCK_SIZE) { while (vaddr < vend) : (vaddr += BLOCK_SIZE) {
@ -940,8 +944,10 @@ fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attrib
/// IN vend: usize - The end of the virtual region to unmap /// IN vend: usize - The end of the virtual region to unmap
/// IN payload: arch.VmmPayload - The payload value. Expected to be arch.KERNEL_VMM_PAYLOAD /// IN payload: arch.VmmPayload - The payload value. Expected to be arch.KERNEL_VMM_PAYLOAD
/// ///
fn testUnmap(vstart: usize, vend: usize, allocator: *Allocator, payload: arch.VmmPayload) MapperError!void { fn testUnmap(vstart: usize, vend: usize, allocator: Allocator, payload: arch.VmmPayload) MapperError!void {
std.testing.expectEqual(arch.KERNEL_VMM_PAYLOAD, payload); // Suppress unused var warning
_ = allocator;
std.testing.expectEqual(arch.KERNEL_VMM_PAYLOAD, payload) catch unreachable;
var vaddr = vstart; var vaddr = vstart;
var allocations = test_allocations.?; var allocations = test_allocations.?;
while (vaddr < vend) : (vaddr += BLOCK_SIZE) { while (vaddr < vend) : (vaddr += BLOCK_SIZE) {
@ -1093,7 +1099,6 @@ fn rt_copyData(vmm: *VirtualMemoryManager(arch.VmmPayload)) void {
} }
// Make sure that the data at the allocated address is correct // Make sure that the data at the allocated address is correct
// Since vmm2 is a mirror of vmm, this address should be mapped by the CPU's MMU // Since vmm2 is a mirror of vmm, this address should be mapped by the CPU's MMU
const dest_buff2 = @intToPtr([*]u8, addr2)[0..buff3.len];
if (!std.mem.eql(u8, buff3[0..buff3.len], dest_buff)) { if (!std.mem.eql(u8, buff3[0..buff3.len], dest_buff)) {
panic(@errorReturnTrace(), "Third lot of data copied doesn't have the expected values\n", .{}); panic(@errorReturnTrace(), "Third lot of data copied doesn't have the expected values\n", .{});
} }

View file

@ -1 +0,0 @@
insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long_insanely_long.txt

View file

@ -67,6 +67,8 @@ const types = .{
.{ "fn (usize) bool", "FN_IUSIZE_OBOOL", "", "", "" }, .{ "fn (usize) bool", "FN_IUSIZE_OBOOL", "", "", "" },
.{ "fn (RtcRegister) u8", "FN_IRTCREGISTER_OU8", "", "", "" }, .{ "fn (RtcRegister) u8", "FN_IRTCREGISTER_OU8", "", "", "" },
.{ "fn (IdtEntry) bool", "FN_IIDTENTRY_OBOOL", "idt_mock", "", "IdtEntry" }, .{ "fn (IdtEntry) bool", "FN_IIDTENTRY_OBOOL", "idt_mock", "", "IdtEntry" },
.{ "fn (*const GdtPtr) anyerror!void", "FN_IPTRCONSTGDTPTR_EERROR_OVOID", "", "", "" },
.{ "fn (*const IdtPtr) anyerror!void", "FN_IPTRCONSTIDTPTR_EERROR_OVOID", "", "", "" },
.{ "fn (*const GdtPtr) void", "FN_IPTRCONSTGDTPTR_OVOID", "", "", "" }, .{ "fn (*const GdtPtr) void", "FN_IPTRCONSTGDTPTR_OVOID", "", "", "" },
.{ "fn (*const IdtPtr) void", "FN_IPTRCONSTIDTPTR_OVOID", "", "", "" }, .{ "fn (*const IdtPtr) void", "FN_IPTRCONSTIDTPTR_OVOID", "", "", "" },
@ -74,6 +76,7 @@ const types = .{
.{ "fn (u8, u8) u16", "FN_IU8_IU8_OU16", "", "", "" }, .{ "fn (u8, u8) u16", "FN_IU8_IU8_OU16", "", "", "" },
.{ "fn (u8, fn () callconv(.Naked) void) IdtError!void", "FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID", "", "", "" }, .{ "fn (u8, fn () callconv(.Naked) void) IdtError!void", "FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_OVOID", "", "", "" },
.{ "fn (u16, u8) void", "FN_IU16_IU8_OVOID", "", "", "" }, .{ "fn (u16, u8) void", "FN_IU16_IU8_OVOID", "", "", "" },
.{ "fn (u16, u16) anyerror!void", "FN_IU16_IU16_EERROR_OVOID", "", "", "" },
.{ "fn (u16, u16) void", "FN_IU16_IU16_OVOID", "", "", "" }, .{ "fn (u16, u16) void", "FN_IU16_IU16_OVOID", "", "", "" },
.{ "fn (u16, u32) void", "FN_IU16_IU32_OVOID", "", "", "" }, .{ "fn (u16, u32) void", "FN_IU16_IU32_OVOID", "", "", "" },
.{ "fn (StatusRegister, bool) u8", "FN_ISTATUSREGISTER_IBOOL_OU8", "", "", "" }, .{ "fn (StatusRegister, bool) u8", "FN_ISTATUSREGISTER_IBOOL_OU8", "", "", "" },
@ -179,7 +182,7 @@ pub fn main() (Allocator.Error || File.OpenError || File.WriteError || File.Read
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit(); defer _ = gpa.deinit();
const allocator = &gpa.allocator; const allocator = gpa.allocator();
// All the string // All the string
const imports_str = comptime genImports(); const imports_str = comptime genImports();

View file

@ -56,12 +56,12 @@ pub const CpuState = struct {
user_ss: u32, user_ss: u32,
}; };
pub const VmmPayload = switch (builtin.arch) { pub const VmmPayload = switch (builtin.cpu.arch) {
.i386 => *x86_paging.Directory, .i386 => *x86_paging.Directory,
else => unreachable, else => unreachable,
}; };
pub const KERNEL_VMM_PAYLOAD: VmmPayload = switch (builtin.arch) { pub const KERNEL_VMM_PAYLOAD: VmmPayload = switch (builtin.cpu.arch) {
.i386 => &x86_paging.kernel_directory, .i386 => &x86_paging.kernel_directory,
else => unreachable, else => unreachable,
}; };
@ -78,8 +78,21 @@ var KERNEL_VADDR_START: u32 = 0xC0100000;
var KERNEL_VADDR_END: u32 = 0xC1100000; var KERNEL_VADDR_END: u32 = 0xC1100000;
var KERNEL_ADDR_OFFSET: u32 = 0xC0000000; var KERNEL_ADDR_OFFSET: u32 = 0xC0000000;
pub fn map(start: usize, end: usize, p_start: usize, p_end: usize, attrs: vmm.Attributes, allocator: *Allocator, payload: VmmPayload) !void {} pub fn map(start: usize, end: usize, p_start: usize, p_end: usize, attrs: vmm.Attributes, allocator: Allocator, payload: VmmPayload) !void {
pub fn unmap(start: usize, end: usize, allocator: *Allocator, payload: VmmPayload) !void {} _ = start;
_ = end;
_ = p_start;
_ = p_end;
_ = attrs;
_ = allocator;
_ = payload;
}
pub fn unmap(start: usize, end: usize, allocator: Allocator, payload: VmmPayload) !void {
_ = start;
_ = end;
_ = allocator;
_ = payload;
}
pub fn out(port: u16, data: anytype) void { pub fn out(port: u16, data: anytype) void {
return mock_framework.performAction("out", void, .{ port, data }); return mock_framework.performAction("out", void, .{ port, data });
@ -134,10 +147,14 @@ pub fn haltNoInterrupts() noreturn {
} }
pub fn initSerial(boot_payload: BootPayload) Serial { pub fn initSerial(boot_payload: BootPayload) Serial {
// Suppress unused variable warnings
_ = boot_payload;
return .{ .write = undefined }; return .{ .write = undefined };
} }
pub fn initTTY(boot_payload: BootPayload) TTY { pub fn initTTY(boot_payload: BootPayload) TTY {
// Suppress unused variable warnings
_ = boot_payload;
return .{ return .{
.print = undefined, .print = undefined,
.setCursor = undefined, .setCursor = undefined,
@ -148,6 +165,8 @@ pub fn initTTY(boot_payload: BootPayload) TTY {
} }
pub fn initMem(payload: BootPayload) Allocator.Error!mem.MemProfile { pub fn initMem(payload: BootPayload) Allocator.Error!mem.MemProfile {
// Suppress unused variable warnings
_ = payload;
return MemProfile{ return MemProfile{
.vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END), .vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END),
.vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START), .vaddr_start = @ptrCast([*]u8, &KERNEL_VADDR_START),
@ -162,13 +181,22 @@ pub fn initMem(payload: BootPayload) Allocator.Error!mem.MemProfile {
}; };
} }
pub fn initTask(t: *Task, entry_point: usize, allocator: *Allocator) Allocator.Error!void {} pub fn initTask(t: *Task, entry_point: usize, allocator: Allocator) Allocator.Error!void {
// Suppress unused variable warnings
_ = t;
_ = entry_point;
_ = allocator;
}
pub fn initKeyboard(allocator: *Allocator) Allocator.Error!?*Keyboard { pub fn initKeyboard(allocator: Allocator) Allocator.Error!?*Keyboard {
// Suppress unused variable warnings
_ = allocator;
return null; return null;
} }
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device { pub fn getDevices(allocator: Allocator) Allocator.Error![]Device {
// Suppress unused variable warnings
_ = allocator;
return &[_]Device{}; return &[_]Device{};
} }
@ -188,6 +216,8 @@ pub fn getDateTime() DateTime {
} }
pub fn init(mem_profile: *const MemProfile) void { pub fn init(mem_profile: *const MemProfile) void {
// Suppress unused variable warnings
_ = mem_profile;
// I'll get back to this as this doesn't effect the current testing. // I'll get back to this as this doesn't effect the current testing.
// When I come on to the mem.zig testing, I'll fix :) // When I come on to the mem.zig testing, I'll fix :)
//return mock_framework.performAction("init", void, mem_profile); //return mock_framework.performAction("init", void, mem_profile);

View file

@ -194,7 +194,7 @@ fn Mock() type {
// Test that the types match // Test that the types match
const expect_type = comptime getDataElementType(expected_function); const expect_type = comptime getDataElementType(expected_function);
expectEqual(expect_type, @as(DataElementType, test_element)); expectEqual(expect_type, @as(DataElementType, test_element)) catch @panic("Function type is not as expected\n");
// Types match, so can use the expected type to get the actual data // Types match, so can use the expected type to get the actual data
const actual_function = getDataValue(expected_function, test_element); const actual_function = getDataValue(expected_function, test_element);
@ -219,13 +219,13 @@ fn Mock() type {
// Test that the types match // Test that the types match
const expect_type = comptime getDataElementType(ExpectedType); const expect_type = comptime getDataElementType(ExpectedType);
expectEqual(expect_type, @as(DataElementType, elem)); expectEqual(expect_type, @as(DataElementType, elem)) catch std.debug.panic("Expected {}, got {}\n", .{ expect_type, @as(DataElementType, elem) });
// Types match, so can use the expected type to get the actual data // Types match, so can use the expected type to get the actual data
const actual_value = getDataValue(ExpectedType, elem); const actual_value = getDataValue(ExpectedType, elem);
// Test the values // Test the values
expectEqual(expected_value, actual_value); expectEqual(expected_value, actual_value) catch std.debug.panic("Expected {}, got {}\n", .{ expected_value, actual_value });
} }
/// ///
@ -254,7 +254,7 @@ fn Mock() type {
// Test that the data match // Test that the data match
const expect_data = comptime getDataElementType(DataType); const expect_data = comptime getDataElementType(DataType);
expectEqual(expect_data, @as(DataElementType, action.data)); expectEqual(expect_data, @as(DataElementType, action.data)) catch std.debug.panic("Expected {}, got {}\n", .{ expect_data, action.data });
return getDataValue(DataType, action.data); return getDataValue(DataType, action.data);
} else { } else {
std.debug.panic("No more test values for the return of function: " ++ fun_name ++ "\n", .{}); std.debug.panic("No more test values for the return of function: " ++ fun_name ++ "\n", .{});
@ -281,7 +281,7 @@ fn Mock() type {
// Get the function mapping to add the parameter to. // Get the function mapping to add the parameter to.
if (self.named_actions.getEntry(fun_name)) |actions_kv| { if (self.named_actions.getEntry(fun_name)) |actions_kv| {
// Take a reference of the value so the underlying action list will update // Take a reference of the value so the underlying action list will update
var action_list = &actions_kv.value; var action_list = &actions_kv.value_ptr;
const action = Action{ const action = Action{
.action = action_type, .action = action_type,
.data = createDataElement(data), .data = createDataElement(data),
@ -312,7 +312,7 @@ fn Mock() type {
pub fn performAction(self: *Self, comptime fun_name: []const u8, comptime RetType: type, params: anytype) RetType { pub fn performAction(self: *Self, comptime fun_name: []const u8, comptime RetType: type, params: anytype) RetType {
if (self.named_actions.getEntry(fun_name)) |kv_actions_list| { if (self.named_actions.getEntry(fun_name)) |kv_actions_list| {
// Take a reference of the value so the underlying action list will update // Take a reference of the value so the underlying action list will update
var action_list = &kv_actions_list.value; var action_list = &kv_actions_list.value_ptr;
// Peak the first action to test the action type // Peak the first action to test the action type
if (action_list.*.first) |action_node| { if (action_list.*.first) |action_node| {
const action = action_node.data; const action = action_node.data;
@ -331,7 +331,7 @@ fn Mock() type {
expectTest(param_type, param, test_action.data); expectTest(param_type, param, test_action.data);
} }
break :ret expectGetValue(fun_name, action_list, RetType); break :ret expectGetValue(fun_name, action_list.*, RetType);
}, },
ActionType.ConsumeFunctionCall => ret: { ActionType.ConsumeFunctionCall => ret: {
// Now pop the action as we are going to use it // Now pop the action as we are going to use it
@ -383,13 +383,13 @@ fn Mock() type {
var it = self.named_actions.iterator(); var it = self.named_actions.iterator();
while (it.next()) |next| { while (it.next()) |next| {
// Take a reference so the underlying action list will be updated. // Take a reference so the underlying action list will be updated.
var action_list = &next.value; var action_list = &next.value_ptr;
if (action_list.*.popFirst()) |action_node| { if (action_list.*.popFirst()) |action_node| {
const action = action_node.data; const action = action_node.data;
switch (action.action) { switch (action.action) {
ActionType.TestValue, ActionType.ConsumeFunctionCall => { ActionType.TestValue, ActionType.ConsumeFunctionCall => {
// These need to be all consumed // These need to be all consumed
std.debug.panic("Unused testing value: Type: {}, value: {} for function '{s}'\n", .{ action.action, @as(DataElementType, action.data), next.key }); std.debug.panic("Unused testing value: Type: {}, value: {} for function '{s}'\n", .{ action.action, @as(DataElementType, action.data), next.key_ptr.* });
}, },
ActionType.RepeatFunctionCall => { ActionType.RepeatFunctionCall => {
// As this is a repeat action, the function will still be here // As this is a repeat action, the function will still be here

View file

@ -1,7 +1,7 @@
const std = @import("std"); const std = @import("std");
const expect = std.testing.expect; const expect = std.testing.expect;
const arch = @import("arch.zig").internals; const arch = @import("arch_mock.zig");
const mock_framework = @import("mock_framework.zig"); const mock_framework = @import("mock_framework.zig");
pub const initTest = mock_framework.initTest; pub const initTest = mock_framework.initTest;
@ -79,8 +79,8 @@ pub fn orig_entry(uc: u8, c: u8) u16 {
pub fn mock_updateCursor(x: u16, y: u16) void { pub fn mock_updateCursor(x: u16, y: u16) void {
// Here we can do any testing we like with the parameters. e.g. test out of bounds // Here we can do any testing we like with the parameters. e.g. test out of bounds
expect(x < WIDTH); expect(x < WIDTH) catch @panic("Cursor x is out of bounds\n");
expect(y < HEIGHT); expect(y < HEIGHT) catch @panic("Cursor x is out of bounds\n");
} }
pub fn mock_enableCursor() void {} pub fn mock_enableCursor() void {}

View file

@ -99,7 +99,7 @@ pub const RuntimeStep = struct {
while (true) { while (true) {
const msg = self.get_msg() catch return true; const msg = self.get_msg() catch return true;
defer self.builder.allocator.free(msg); defer self.builder.allocator.free(msg);
std.debug.warn("{s}\n", .{msg}); std.debug.print("{s}\n", .{msg});
} }
} }
@ -117,7 +117,7 @@ pub const RuntimeStep = struct {
const msg = self.get_msg() catch return false; const msg = self.get_msg() catch return false;
defer self.builder.allocator.free(msg); defer self.builder.allocator.free(msg);
// Print the line to see what is going on // Print the line to see what is going on
std.debug.warn("{s}\n", .{msg}); std.debug.print("{s}\n", .{msg});
if (std.mem.indexOf(u8, msg, "FAILURE")) |_| { if (std.mem.indexOf(u8, msg, "FAILURE")) |_| {
return false; return false;
} else if (std.mem.indexOf(u8, msg, "Kernel panic")) |_| { } else if (std.mem.indexOf(u8, msg, "Kernel panic")) |_| {
@ -142,8 +142,8 @@ pub const RuntimeStep = struct {
const msg = self.get_msg() catch return false; const msg = self.get_msg() catch return false;
defer self.builder.allocator.free(msg); defer self.builder.allocator.free(msg);
// Print the line to see what is going on // Print the line to see what is going on
std.debug.warn("{s}\n", .{msg}); std.debug.print("{s}\n", .{msg});
if (std.mem.eql(u8, msg, "[emerg] (panic): Kernel panic: integer overflow")) { if (std.mem.eql(u8, msg, "[err] (panic): Kernel panic: integer overflow")) {
return true; return true;
} }
} }
@ -164,7 +164,7 @@ pub const RuntimeStep = struct {
const msg = self.get_msg() catch return false; const msg = self.get_msg() catch return false;
defer self.builder.allocator.free(msg); defer self.builder.allocator.free(msg);
std.debug.warn("{s}\n", .{msg}); std.debug.print("{s}\n", .{msg});
// Make sure `[INFO] Switched` then `[INFO] SUCCESS: Scheduler variables preserved` are logged in this order // Make sure `[INFO] Switched` then `[INFO] SUCCESS: Scheduler variables preserved` are logged in this order
if (std.mem.eql(u8, msg, "[info] (scheduler): Switched") and state == 0) { if (std.mem.eql(u8, msg, "[info] (scheduler): Switched") and state == 0) {
@ -206,7 +206,7 @@ pub const RuntimeStep = struct {
try self.os_proc.spawn(); try self.os_proc.spawn();
// Start up the read thread // Start up the read thread
var thread = try Thread.spawn(read_logs, self); var thread = try Thread.spawn(Thread.SpawnConfig{}, read_logs, .{self});
// Call the testing function // Call the testing function
const res = self.test_func(self); const res = self.test_func(self);
@ -215,7 +215,7 @@ pub const RuntimeStep = struct {
_ = try self.os_proc.kill(); _ = try self.os_proc.kill();
// Join the thread // Join the thread
thread.wait(); thread.join();
// Free the rest of the queue // Free the rest of the queue
while (self.msg_queue.get()) |node| { while (self.msg_queue.get()) |node| {
@ -248,7 +248,7 @@ pub const RuntimeStep = struct {
return; return;
}, },
else => { else => {
std.debug.warn("Unexpected error: {}\n", .{e}); std.debug.print("Unexpected error: {}\n", .{e});
unreachable; unreachable;
}, },
}; };
@ -299,7 +299,7 @@ pub const RuntimeStep = struct {
pub fn create(builder: *Builder, test_mode: TestMode, qemu_args: [][]const u8) *RuntimeStep { pub fn create(builder: *Builder, test_mode: TestMode, qemu_args: [][]const u8) *RuntimeStep {
const runtime_step = builder.allocator.create(RuntimeStep) catch unreachable; const runtime_step = builder.allocator.create(RuntimeStep) catch unreachable;
runtime_step.* = RuntimeStep{ runtime_step.* = RuntimeStep{
.step = Step.init(.Custom, builder.fmt("Runtime {s}", .{@tagName(test_mode)}), builder.allocator, make), .step = Step.init(.custom, builder.fmt("Runtime {s}", .{@tagName(test_mode)}), builder.allocator, make),
.builder = builder, .builder = builder,
.msg_queue = Queue.init(), .msg_queue = Queue.init(),
.os_proc = undefined, .os_proc = undefined,