Update source tree for zig 0.9.1
This commit is contained in:
parent
2484cb08d0
commit
06f45400bd
49 changed files with 2347 additions and 2211 deletions
3
.github/workflows/main.yml
vendored
3
.github/workflows/main.yml
vendored
|
@ -19,8 +19,7 @@ jobs:
|
|||
- name: Download zig
|
||||
run: |
|
||||
export PYTHONIOENCODING=utf8
|
||||
# Lock the master commit that we download, because of blocking issues
|
||||
wget https://ziglang.org/builds/zig-linux-x86_64-0.8.0-dev.2133+ad33e3483.tar.xz
|
||||
wget https://ziglang.org/download/0.9.1/zig-linux-x86_64-0.9.1.tar.xz
|
||||
sudo apt-get install mtools
|
||||
tar -xvf zig*
|
||||
- name: Install qemu
|
||||
|
|
|
@ -17,7 +17,7 @@ All of these goals will benefit from the features of Zig.
|
|||
|
||||
## 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
|
||||
zig build
|
||||
|
|
29
build.zig
29
build.zig
|
@ -10,7 +10,7 @@ const Target = std.Target;
|
|||
const CrossTarget = std.zig.CrossTarget;
|
||||
const fs = std.fs;
|
||||
const File = fs.File;
|
||||
const Mode = builtin.Mode;
|
||||
const Mode = std.builtin.Mode;
|
||||
const TestMode = rt.TestMode;
|
||||
const ArrayList = std.ArrayList;
|
||||
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 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.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.setLinkerScriptPath(linker_script_path);
|
||||
exec.setLinkerScriptPath(std.build.FileSource{ .path = linker_script_path });
|
||||
exec.setTarget(target);
|
||||
|
||||
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,
|
||||
};
|
||||
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| {
|
||||
// Add some test files for the user mode runtime tests
|
||||
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.setOutputDir(b.install_path);
|
||||
user_program_step.setTarget(target);
|
||||
|
@ -103,18 +106,16 @@ pub fn build(b: *Builder) !void {
|
|||
b.default_step.dependOn(&make_iso.step);
|
||||
|
||||
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);
|
||||
unit_tests.setBuildMode(build_mode);
|
||||
unit_tests.setMainPkgPath(".");
|
||||
unit_tests.addBuildOption(TestMode, "test_mode", test_mode);
|
||||
unit_tests.addBuildOption([]const u8, "mock_path", mock_path);
|
||||
unit_tests.addBuildOption([]const u8, "arch_mock_path", arch_mock_path);
|
||||
const unit_test_options = b.addOptions();
|
||||
unit_tests.addOptions("build_options", unit_test_options);
|
||||
unit_test_options.addOption(TestMode, "test_mode", test_mode);
|
||||
unit_tests.setTarget(.{ .cpu_arch = target.cpu_arch });
|
||||
|
||||
if (builtin.os.tag != .windows) {
|
||||
unit_tests.enable_qemu = true;
|
||||
b.enable_qemu = true;
|
||||
}
|
||||
|
||||
// Run the mock gen
|
||||
|
@ -175,7 +176,7 @@ pub fn build(b: *Builder) !void {
|
|||
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 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{
|
||||
"gdb-multiarch",
|
||||
"-ex",
|
||||
|
@ -239,7 +240,7 @@ const Fat32BuilderStep = struct {
|
|||
pub fn create(builder: *Builder, options: Fat32.Options, out_file_path: []const u8) *Fat32BuilderStep {
|
||||
const fat32_builder_step = builder.allocator.create(Fat32BuilderStep) catch unreachable;
|
||||
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,
|
||||
.options = options,
|
||||
.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 {
|
||||
const ramdisk_step = builder.allocator.create(RamdiskStep) catch unreachable;
|
||||
ramdisk_step.* = .{
|
||||
.step = Step.init(.Custom, builder.fmt("Ramdisk", .{}), builder.allocator, make),
|
||||
.step = Step.init(.custom, builder.fmt("Ramdisk", .{}), builder.allocator, make),
|
||||
.builder = builder,
|
||||
.target = target,
|
||||
.files = files,
|
||||
|
|
19
fat32_cp.sh
19
fat32_cp.sh
|
@ -1,9 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
IMAGE_PATH_DIR=$1
|
||||
|
||||
mkdir test/fat32/mnt
|
||||
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/
|
||||
whoami
|
||||
|
||||
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
|
||||
|
|
|
@ -487,7 +487,7 @@ pub const Fat32 = struct {
|
|||
else => @compileError("Unexpected field type: " ++ @typeName(info.child)),
|
||||
},
|
||||
.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.
|
||||
///
|
||||
fn clearStream(stream: anytype, size: usize) ErrorSet(@TypeOf(stream))!void {
|
||||
comptime const buff_size = 4096;
|
||||
comptime const bytes: [buff_size]u8 = [_]u8{0x00} ** buff_size;
|
||||
const buff_size = 4096;
|
||||
const bytes: [buff_size]u8 = [_]u8{0x00} ** buff_size;
|
||||
|
||||
var remaining: usize = size;
|
||||
while (remaining > 0) {
|
||||
|
|
|
@ -2,9 +2,8 @@ const std = @import("std");
|
|||
const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
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"),
|
||||
else => unreachable,
|
||||
};
|
||||
|
|
|
@ -120,16 +120,16 @@ pub const MEMORY_BLOCK_SIZE: usize = paging.PAGE_SIZE_4KB;
|
|||
pub fn in(comptime Type: type, port: u16) Type {
|
||||
return switch (Type) {
|
||||
u8 => asm volatile ("inb %[port], %[result]"
|
||||
: [result] "={al}" (-> Type)
|
||||
: [port] "N{dx}" (port)
|
||||
: [result] "={al}" (-> Type),
|
||||
: [port] "N{dx}" (port),
|
||||
),
|
||||
u16 => asm volatile ("inw %[port], %[result]"
|
||||
: [result] "={ax}" (-> Type)
|
||||
: [port] "N{dx}" (port)
|
||||
: [result] "={ax}" (-> Type),
|
||||
: [port] "N{dx}" (port),
|
||||
),
|
||||
u32 => asm volatile ("inl %[port], %[result]"
|
||||
: [result] "={eax}" (-> Type)
|
||||
: [port] "N{dx}" (port)
|
||||
: [result] "={eax}" (-> Type),
|
||||
: [port] "N{dx}" (port),
|
||||
),
|
||||
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]"
|
||||
:
|
||||
: [port] "{dx}" (port),
|
||||
[data] "{al}" (data)
|
||||
[data] "{al}" (data),
|
||||
),
|
||||
u16 => asm volatile ("outw %[data], %[port]"
|
||||
:
|
||||
: [port] "{dx}" (port),
|
||||
[data] "{ax}" (data)
|
||||
[data] "{ax}" (data),
|
||||
),
|
||||
u32 => asm volatile ("outl %[data], %[port]"
|
||||
:
|
||||
: [port] "{dx}" (port),
|
||||
[data] "{eax}" (data)
|
||||
[data] "{eax}" (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
|
||||
asm volatile ("lgdt (%%eax)"
|
||||
:
|
||||
: [gdt_ptr] "{eax}" (gdt_ptr)
|
||||
: [gdt_ptr] "{eax}" (gdt_ptr),
|
||||
);
|
||||
|
||||
// Load the kernel data segment, index into the GDT
|
||||
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");
|
||||
|
@ -212,7 +212,7 @@ pub fn lgdt(gdt_ptr: *const gdt.GdtPtr) void {
|
|||
pub fn sgdt() gdt.GdtPtr {
|
||||
var gdt_ptr = gdt.GdtPtr{ .limit = 0, .base = 0 };
|
||||
asm volatile ("sgdt %[tab]"
|
||||
: [tab] "=m" (gdt_ptr)
|
||||
: [tab] "=m" (gdt_ptr),
|
||||
);
|
||||
return gdt_ptr;
|
||||
}
|
||||
|
@ -226,7 +226,7 @@ pub fn sgdt() gdt.GdtPtr {
|
|||
pub fn ltr(offset: u16) void {
|
||||
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 {
|
||||
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 {
|
||||
var idt_ptr = idt.IdtPtr{ .limit = 0, .base = 0 };
|
||||
asm volatile ("sidt %[tab]"
|
||||
: [tab] "=m" (idt_ptr)
|
||||
: [tab] "=m" (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
|
||||
///
|
||||
pub fn initSerial(boot_payload: BootPayload) Serial {
|
||||
// Suppress unused var warning
|
||||
_ = boot_payload;
|
||||
serial.init(serial.DEFAULT_BAUDRATE, serial.Port.COM1) catch |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
|
||||
///
|
||||
pub fn initTTY(boot_payload: BootPayload) TTY {
|
||||
// Suppress unused var warning
|
||||
_ = boot_payload;
|
||||
return .{
|
||||
.print = tty.writeString,
|
||||
.setCursor = tty.setCursor,
|
||||
|
@ -374,7 +378,7 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
|
|||
const mmap_addr = mb_info.mmap_addr;
|
||||
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_virtual_mem = std.ArrayList(mem.Map).init(allocator);
|
||||
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
|
||||
///
|
||||
/// 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
|
||||
/// The initialised PS/2 keyboard
|
||||
|
@ -496,7 +500,7 @@ pub fn initMem(mb_info: BootPayload) Allocator.Error!MemProfile {
|
|||
/// Error: std.mem.Allocator.Error
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -510,12 +514,12 @@ pub fn initKeyboard(allocator: *Allocator) Allocator.Error!*Keyboard {
|
|||
/// the initial CpuState on the kernel stack.
|
||||
/// IN entry_point: usize - The pointer to the entry point of the function. Functions only
|
||||
/// 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
|
||||
/// 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;
|
||||
// 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;
|
||||
|
@ -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.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN allocator: *Allocator - An allocator for getting the devices
|
||||
/// IN allocator: Allocator - An allocator for getting the devices
|
||||
///
|
||||
/// Return: []Device
|
||||
/// A list of hardware devices.
|
||||
|
@ -581,7 +585,7 @@ pub fn initTask(task: *Task, entry_point: usize, allocator: *Allocator) Allocato
|
|||
/// Error: Allocator.Error
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ export fn start_higher_half() callconv(.Naked) noreturn {
|
|||
// Get the multiboot header address and add the virtual offset
|
||||
const mb_info_addr = asm (
|
||||
\\mov %%ebx, %[res]
|
||||
: [res] "=r" (-> usize)
|
||||
: [res] "=r" (-> usize),
|
||||
) + @ptrToInt(&KERNEL_ADDR_OFFSET);
|
||||
kmain(@intToPtr(arch.BootPayload, mb_info_addr));
|
||||
while (true) {}
|
||||
|
|
|
@ -3,8 +3,7 @@ const builtin = @import("builtin");
|
|||
const is_test = builtin.is_test;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
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 current year to be used for calculating the 4 digit year, as the CMOS return the last two
|
||||
/// 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 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) {
|
||||
arch.out(ADDRESS, reg | NMI_BIT);
|
||||
} else {
|
||||
|
@ -151,7 +150,7 @@ fn selectRegister(reg: u8, comptime disable_nmi: bool) callconv(.Inline) void {
|
|||
/// Arguments:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -161,7 +160,7 @@ fn writeRegister(data: u8) callconv(.Inline) void {
|
|||
/// Return: u8
|
||||
/// The value in the selected register.
|
||||
///
|
||||
fn readRegister() callconv(.Inline) u8 {
|
||||
inline fn readRegister() u8 {
|
||||
return arch.in(u8, DATA);
|
||||
}
|
||||
|
||||
|
@ -176,7 +175,7 @@ fn readRegister() callconv(.Inline) u8 {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
arch.ioWait();
|
||||
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 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);
|
||||
arch.ioWait();
|
||||
writeRegister(data);
|
||||
|
@ -278,7 +277,7 @@ test "readRegister" {
|
|||
const expected = @as(u8, 0x55);
|
||||
const actual = readRegister();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "selectAndReadRegister NMI" {
|
||||
|
@ -294,7 +293,7 @@ test "selectAndReadRegister NMI" {
|
|||
const expected = @as(u8, 0x44);
|
||||
const actual = selectAndReadRegister(reg, false);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "selectAndReadRegister no NMI" {
|
||||
|
@ -310,7 +309,7 @@ test "selectAndReadRegister no NMI" {
|
|||
const expected = @as(u8, 0x44);
|
||||
const actual = selectAndReadRegister(reg, true);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "selectAndWriteRegister NMI" {
|
||||
|
@ -364,7 +363,7 @@ test "readRtcRegister" {
|
|||
const expected = @as(u8, 0x44);
|
||||
const actual = readRtcRegister(reg);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,7 +388,7 @@ test "readStatusRegister NMI" {
|
|||
const expected = @as(u8, 0x78);
|
||||
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 actual = readStatusRegister(reg, true);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ const builtin = @import("builtin");
|
|||
const is_test = builtin.is_test;
|
||||
const panic = @import("../../panic.zig").panic;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
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 access bits for a GDT entry.
|
||||
const AccessBits = packed struct {
|
||||
|
@ -427,73 +426,73 @@ pub fn init() void {
|
|||
}
|
||||
|
||||
fn mock_lgdt(ptr: *const GdtPtr) void {
|
||||
expectEqual(TABLE_SIZE, ptr.limit);
|
||||
expectEqual(@ptrToInt(&gdt_entries[0]), ptr.base);
|
||||
expectEqual(TABLE_SIZE, ptr.limit) catch panic(null, "GDT pointer limit was not correct", .{});
|
||||
expectEqual(@ptrToInt(&gdt_entries[0]), ptr.base) catch panic(null, "GDT pointer base was not correct", .{});
|
||||
}
|
||||
|
||||
test "GDT entries" {
|
||||
expectEqual(@as(u32, 1), @sizeOf(AccessBits));
|
||||
expectEqual(@as(u32, 1), @sizeOf(FlagBits));
|
||||
expectEqual(@as(u32, 8), @sizeOf(GdtEntry));
|
||||
expectEqual(@as(u32, 104), @sizeOf(Tss));
|
||||
expectEqual(@as(u32, 6), @sizeOf(GdtPtr));
|
||||
try expectEqual(@as(u32, 1), @sizeOf(AccessBits));
|
||||
try expectEqual(@as(u32, 1), @sizeOf(FlagBits));
|
||||
try expectEqual(@as(u32, 8), @sizeOf(GdtEntry));
|
||||
try expectEqual(@as(u32, 104), @sizeOf(Tss));
|
||||
try expectEqual(@as(u32, 6), @sizeOf(GdtPtr));
|
||||
|
||||
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];
|
||||
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];
|
||||
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];
|
||||
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];
|
||||
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];
|
||||
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);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.esp0);
|
||||
expectEqual(@as(u32, KERNEL_DATA_OFFSET), main_tss_entry.ss0);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.esp1);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ss1);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.esp2);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ss2);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.cr3);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.eip);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.eflags);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.eax);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ecx);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.edx);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ebx);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.esp);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ebp);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.esi);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.edi);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.es);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.cs);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ss);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ds);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.fs);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.gs);
|
||||
expectEqual(@as(u32, 0), main_tss_entry.ldtr);
|
||||
expectEqual(@as(u16, 0), main_tss_entry.trap);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.prev_tss);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.esp0);
|
||||
try expectEqual(@as(u32, KERNEL_DATA_OFFSET), main_tss_entry.ss0);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.esp1);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ss1);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.esp2);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ss2);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.cr3);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.eip);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.eflags);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.eax);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ecx);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.edx);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ebx);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.esp);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ebp);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.esi);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.edi);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.es);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.cs);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ss);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ds);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.fs);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.gs);
|
||||
try expectEqual(@as(u32, 0), main_tss_entry.ldtr);
|
||||
try expectEqual(@as(u16, 0), main_tss_entry.trap);
|
||||
|
||||
// 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" {
|
||||
const actual = makeGdtEntry(0, 0, NULL_SEGMENT, NULL_FLAGS);
|
||||
|
||||
const expected: u64 = 0;
|
||||
expectEqual(expected, @bitCast(u64, actual));
|
||||
try expectEqual(expected, @bitCast(u64, actual));
|
||||
}
|
||||
|
||||
test "makeGdtEntry alternating bit pattern" {
|
||||
|
@ -507,7 +506,7 @@ test "makeGdtEntry alternating bit pattern" {
|
|||
.present = 0,
|
||||
};
|
||||
|
||||
expectEqual(@as(u8, 0b01010101), @bitCast(u8, alt_access));
|
||||
try expectEqual(@as(u8, 0b01010101), @bitCast(u8, alt_access));
|
||||
|
||||
const alt_flag = FlagBits{
|
||||
.reserved_zero = 1,
|
||||
|
@ -516,12 +515,12 @@ test "makeGdtEntry alternating bit pattern" {
|
|||
.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 expected: u64 = 0b0101010101010101010101010101010101010101010101010101010101010101;
|
||||
expectEqual(expected, @bitCast(u64, actual));
|
||||
try expectEqual(expected, @bitCast(u64, actual));
|
||||
}
|
||||
|
||||
test "init" {
|
||||
|
@ -549,7 +548,7 @@ test "init" {
|
|||
// Flags are zero
|
||||
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
|
||||
gdt_ptr.base = 0;
|
||||
|
|
|
@ -7,9 +7,8 @@ const builtin = @import("builtin");
|
|||
const is_test = builtin.is_test;
|
||||
const panic = @import("../../panic.zig").panic;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
const gdt = if (is_test) @import(mock_path ++ "gdt_mock.zig") else @import("gdt.zig");
|
||||
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
|
||||
const gdt = if (is_test) @import("../../../../test/mock/kernel/gdt_mock.zig") else @import("gdt.zig");
|
||||
const arch = if (builtin.is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
|
||||
|
||||
/// The structure that contains all the information that each IDT entry needs.
|
||||
pub const IdtEntry = packed struct {
|
||||
|
@ -196,15 +195,15 @@ fn testHandler0() callconv(.Naked) void {}
|
|||
fn testHandler1() callconv(.Naked) void {}
|
||||
|
||||
fn mock_lidt(ptr: *const IdtPtr) void {
|
||||
expectEqual(TABLE_SIZE, ptr.limit);
|
||||
expectEqual(@ptrToInt(&idt_entries[0]), ptr.base);
|
||||
expectEqual(TABLE_SIZE, ptr.limit) catch panic(null, "IDT pointer limit was not correct", .{});
|
||||
expectEqual(@ptrToInt(&idt_entries[0]), ptr.base) catch panic(null, "IDT pointer base was not correct", .{});
|
||||
}
|
||||
|
||||
test "IDT entries" {
|
||||
expectEqual(@as(u32, 8), @sizeOf(IdtEntry));
|
||||
expectEqual(@as(u32, 6), @sizeOf(IdtPtr));
|
||||
expectEqual(TABLE_SIZE, idt_ptr.limit);
|
||||
expectEqual(@as(u32, 0), idt_ptr.base);
|
||||
try expectEqual(@as(u32, 8), @sizeOf(IdtEntry));
|
||||
try expectEqual(@as(u32, 6), @sizeOf(IdtPtr));
|
||||
try expectEqual(TABLE_SIZE, idt_ptr.limit);
|
||||
try expectEqual(@as(u32, 0), idt_ptr.base);
|
||||
}
|
||||
|
||||
test "makeEntry alternating bit pattern" {
|
||||
|
@ -212,7 +211,7 @@ test "makeEntry alternating bit pattern" {
|
|||
|
||||
const expected: u64 = 0b0101010101010101101001010000000001010101010101010101010101010101;
|
||||
|
||||
expectEqual(expected, @bitCast(u64, actual));
|
||||
try expectEqual(expected, @bitCast(u64, actual));
|
||||
}
|
||||
|
||||
test "isIdtOpen" {
|
||||
|
@ -238,17 +237,16 @@ test "isIdtOpen" {
|
|||
.base_high = 0,
|
||||
};
|
||||
|
||||
expectEqual(false, isIdtOpen(not_open));
|
||||
expectEqual(true, isIdtOpen(open));
|
||||
try expectEqual(false, isIdtOpen(not_open));
|
||||
try expectEqual(true, isIdtOpen(open));
|
||||
}
|
||||
|
||||
test "openInterruptGate" {
|
||||
const index: u8 = 100;
|
||||
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_1_addr = @ptrToInt(testHandler1);
|
||||
|
||||
const expected_entry0 = IdtEntry{
|
||||
.base_low = @truncate(u16, test_fn_0_addr),
|
||||
|
@ -261,7 +259,7 @@ test "openInterruptGate" {
|
|||
.base_high = @truncate(u16, test_fn_0_addr >> 16),
|
||||
};
|
||||
|
||||
expectEqual(expected_entry0, idt_entries[index]);
|
||||
try expectEqual(expected_entry0, idt_entries[index]);
|
||||
|
||||
// Reset
|
||||
idt_entries[index] = IdtEntry{
|
||||
|
@ -277,7 +275,7 @@ test "openInterruptGate" {
|
|||
|
||||
openInterruptGate(index, testHandler0) catch unreachable;
|
||||
// With different handler
|
||||
expectError(IdtError.IdtEntryExists, openInterruptGate(index, testHandler1));
|
||||
try expectError(IdtError.IdtEntryExists, openInterruptGate(index, testHandler1));
|
||||
|
||||
const expected_entry1 = IdtEntry{
|
||||
.base_low = @truncate(u16, test_fn_0_addr),
|
||||
|
@ -290,7 +288,7 @@ test "openInterruptGate" {
|
|||
.base_high = @truncate(u16, test_fn_0_addr >> 16),
|
||||
};
|
||||
|
||||
expectEqual(expected_entry1, idt_entries[index]);
|
||||
try expectEqual(expected_entry1, idt_entries[index]);
|
||||
|
||||
// Reset
|
||||
idt_entries[index] = IdtEntry{
|
||||
|
@ -316,7 +314,7 @@ test "init" {
|
|||
init();
|
||||
|
||||
// Post testing
|
||||
expectEqual(@ptrToInt(&idt_entries), idt_ptr.base);
|
||||
try expectEqual(@ptrToInt(&idt_entries), idt_ptr.base);
|
||||
|
||||
// Reset
|
||||
idt_ptr.base = 0;
|
||||
|
|
|
@ -99,7 +99,7 @@ pub fn getInterruptStub(comptime interrupt_num: u32) idt.InterruptHandler {
|
|||
\\ pushl %[nr]
|
||||
\\ jmp commonStub
|
||||
:
|
||||
: [nr] "n" (interrupt_num)
|
||||
: [nr] "n" (interrupt_num),
|
||||
);
|
||||
}
|
||||
}.func;
|
||||
|
|
|
@ -7,10 +7,9 @@ const expectError = std.testing.expectError;
|
|||
const log = std.log.scoped(.x86_irq);
|
||||
const build_options = @import("build_options");
|
||||
const panic = @import("../../panic.zig").panic;
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
const idt = if (is_test) @import(mock_path ++ "idt_mock.zig") else @import("idt.zig");
|
||||
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
|
||||
const pic = if (is_test) @import(mock_path ++ "pic_mock.zig") else @import("pic.zig");
|
||||
const idt = if (is_test) @import("../../../../test/mock/kernel/idt_mock.zig") else @import("idt.zig");
|
||||
const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
|
||||
const pic = if (is_test) @import("../../../../test/mock/kernel/pic_mock.zig") else @import("pic.zig");
|
||||
const interrupts = @import("interrupts.zig");
|
||||
|
||||
/// 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 testFunction1(ctx: *arch.CpuState) u32 {
|
||||
// Suppress unused variable warnings
|
||||
_ = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn testFunction2(ctx: *arch.CpuState) u32 {
|
||||
// Suppress unused variable warnings
|
||||
_ = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -169,10 +174,10 @@ test "openIrq" {
|
|||
test "isValidIrq" {
|
||||
comptime var i = 0;
|
||||
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" {
|
||||
|
@ -184,19 +189,19 @@ test "registerIrq re-register irq handler" {
|
|||
|
||||
// Pre testing
|
||||
for (irq_handlers) |h| {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
}
|
||||
|
||||
// Call function
|
||||
try registerIrq(0, testFunction1);
|
||||
expectError(IrqError.IrqExists, registerIrq(0, testFunction2));
|
||||
try expectError(IrqError.IrqExists, registerIrq(0, testFunction2));
|
||||
|
||||
// Post testing
|
||||
for (irq_handlers) |h, i| {
|
||||
if (i != 0) {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
} else {
|
||||
expectEqual(testFunction1, h.?);
|
||||
try expectEqual(testFunction1, h.?);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,7 +218,7 @@ test "registerIrq register irq handler" {
|
|||
|
||||
// Pre testing
|
||||
for (irq_handlers) |h| {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
}
|
||||
|
||||
// Call function
|
||||
|
@ -222,9 +227,9 @@ test "registerIrq register irq handler" {
|
|||
// Post testing
|
||||
for (irq_handlers) |h, i| {
|
||||
if (i != 0) {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
} else {
|
||||
expectEqual(testFunction1, h.?);
|
||||
try expectEqual(testFunction1, h.?);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,7 +238,7 @@ test "registerIrq register irq handler" {
|
|||
}
|
||||
|
||||
test "registerIrq invalid irq index" {
|
||||
expectError(IrqError.InvalidIrq, registerIrq(200, testFunction1));
|
||||
try expectError(IrqError.InvalidIrq, registerIrq(200, testFunction1));
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
@ -6,11 +6,10 @@ const expectEqual = std.testing.expectEqual;
|
|||
const expectError = std.testing.expectError;
|
||||
const log = std.log.scoped(.x86_isr);
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
const syscalls = @import("syscalls.zig");
|
||||
const panic = @import("../../panic.zig").panic;
|
||||
const idt = if (is_test) @import(mock_path ++ "idt_mock.zig") else @import("idt.zig");
|
||||
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
|
||||
const idt = if (is_test) @import("../../../../test/mock/kernel/idt_mock.zig") else @import("idt.zig");
|
||||
const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
|
||||
const interrupts = @import("interrupts.zig");
|
||||
|
||||
/// 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 testFunction1(ctx: *arch.CpuState) u32 {
|
||||
// Suppress unused var warning
|
||||
_ = ctx;
|
||||
return 0;
|
||||
}
|
||||
fn testFunction2(ctx: *arch.CpuState) u32 {
|
||||
// Suppress unused var warning
|
||||
_ = ctx;
|
||||
return 0;
|
||||
}
|
||||
fn testFunction3(ctx: *arch.CpuState) u32 {
|
||||
// Suppress unused var warning
|
||||
_ = ctx;
|
||||
return 0;
|
||||
}
|
||||
fn testFunction4(ctx: *arch.CpuState) u32 {
|
||||
// Suppress unused var warning
|
||||
_ = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -284,24 +291,24 @@ test "openIsr" {
|
|||
test "isValidIsr" {
|
||||
comptime var i = 0;
|
||||
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" {
|
||||
// Pre testing
|
||||
expect(null == syscall_handler);
|
||||
try expect(null == syscall_handler);
|
||||
|
||||
// Call function
|
||||
try registerIsr(syscalls.INTERRUPT, testFunction3);
|
||||
expectError(IsrError.IsrExists, registerIsr(syscalls.INTERRUPT, testFunction4));
|
||||
try expectError(IsrError.IsrExists, registerIsr(syscalls.INTERRUPT, testFunction4));
|
||||
|
||||
// Post testing
|
||||
expectEqual(testFunction3, syscall_handler.?);
|
||||
try expectEqual(testFunction3, syscall_handler.?);
|
||||
|
||||
// Clean up
|
||||
syscall_handler = null;
|
||||
|
@ -309,13 +316,13 @@ test "registerIsr re-register syscall handler" {
|
|||
|
||||
test "registerIsr register syscall handler" {
|
||||
// Pre testing
|
||||
expect(null == syscall_handler);
|
||||
try expect(null == syscall_handler);
|
||||
|
||||
// Call function
|
||||
try registerIsr(syscalls.INTERRUPT, testFunction3);
|
||||
|
||||
// Post testing
|
||||
expectEqual(testFunction3, syscall_handler.?);
|
||||
try expectEqual(testFunction3, syscall_handler.?);
|
||||
|
||||
// Clean up
|
||||
syscall_handler = null;
|
||||
|
@ -324,19 +331,19 @@ test "registerIsr register syscall handler" {
|
|||
test "registerIsr re-register isr handler" {
|
||||
// Pre testing
|
||||
for (isr_handlers) |h| {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
}
|
||||
|
||||
// Call function
|
||||
try registerIsr(0, testFunction1);
|
||||
expectError(IsrError.IsrExists, registerIsr(0, testFunction2));
|
||||
try expectError(IsrError.IsrExists, registerIsr(0, testFunction2));
|
||||
|
||||
// Post testing
|
||||
for (isr_handlers) |h, i| {
|
||||
if (i != 0) {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
} else {
|
||||
expectEqual(testFunction1, h.?);
|
||||
try expectEqual(testFunction1, h.?);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,7 +354,7 @@ test "registerIsr re-register isr handler" {
|
|||
test "registerIsr register isr handler" {
|
||||
// Pre testing
|
||||
for (isr_handlers) |h| {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
}
|
||||
|
||||
// Call function
|
||||
|
@ -356,9 +363,9 @@ test "registerIsr register isr handler" {
|
|||
// Post testing
|
||||
for (isr_handlers) |h, i| {
|
||||
if (i != 0) {
|
||||
expect(null == h);
|
||||
try expect(null == h);
|
||||
} else {
|
||||
expectEqual(testFunction1, h.?);
|
||||
try expectEqual(testFunction1, h.?);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -367,7 +374,7 @@ test "registerIsr register isr handler" {
|
|||
}
|
||||
|
||||
test "registerIsr invalid isr index" {
|
||||
expectError(IsrError.InvalidIsr, registerIsr(200, testFunction1));
|
||||
try expectError(IsrError.InvalidIsr, registerIsr(200, testFunction1));
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
@ -6,7 +6,7 @@ const testing = std.testing;
|
|||
const log = std.log.scoped(.x86_keyboard);
|
||||
const irq = @import("irq.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 kb = @import("../../keyboard.zig");
|
||||
const Keyboard = kb.Keyboard;
|
||||
|
@ -164,7 +164,7 @@ fn onKeyEvent(ctx: *arch.CpuState) usize {
|
|||
const scan_code = readKeyboardBuffer();
|
||||
if (parseScanCode(scan_code)) |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);
|
||||
|
@ -174,7 +174,7 @@ fn onKeyEvent(ctx: *arch.CpuState) usize {
|
|||
/// Initialise the PS/2 keyboard
|
||||
///
|
||||
/// 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
|
||||
/// The keyboard created
|
||||
|
@ -182,7 +182,7 @@ fn onKeyEvent(ctx: *arch.CpuState) usize {
|
|||
/// Error: std.mem.Allocator.Error
|
||||
/// 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| {
|
||||
panic(@errorReturnTrace(), "Failed to register keyboard IRQ: {}\n", .{e});
|
||||
};
|
||||
|
@ -297,23 +297,23 @@ test "parseScanCode" {
|
|||
var res = parseScanCode(scan_code);
|
||||
if (key) |k| {
|
||||
const r = res orelse unreachable;
|
||||
testing.expectEqual(k, r.position);
|
||||
testing.expectEqual(false, r.released);
|
||||
testing.expectEqual(pressed_keys, 1);
|
||||
try testing.expectEqual(k, r.position);
|
||||
try testing.expectEqual(false, r.released);
|
||||
try testing.expectEqual(pressed_keys, 1);
|
||||
}
|
||||
testing.expectEqual(on_print_screen, false);
|
||||
testing.expectEqual(special_sequence, false);
|
||||
testing.expectEqual(expected_releases, 0);
|
||||
try testing.expectEqual(on_print_screen, false);
|
||||
try testing.expectEqual(special_sequence, false);
|
||||
try testing.expectEqual(expected_releases, 0);
|
||||
// Test release scan code for key
|
||||
if (key) |k| {
|
||||
res = parseScanCode(scan_code | 128);
|
||||
const r = res orelse unreachable;
|
||||
testing.expectEqual(k, r.position);
|
||||
testing.expectEqual(true, r.released);
|
||||
testing.expectEqual(pressed_keys, 0);
|
||||
testing.expectEqual(on_print_screen, false);
|
||||
testing.expectEqual(special_sequence, false);
|
||||
testing.expectEqual(expected_releases, 0);
|
||||
try testing.expectEqual(k, r.position);
|
||||
try testing.expectEqual(true, r.released);
|
||||
try testing.expectEqual(pressed_keys, 0);
|
||||
try testing.expectEqual(on_print_screen, false);
|
||||
try testing.expectEqual(special_sequence, false);
|
||||
try testing.expectEqual(expected_releases, 0);
|
||||
}
|
||||
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 };
|
||||
for (simple_special_keys) |key, i| {
|
||||
testing.expectEqual(parseScanCode(128), null);
|
||||
testing.expectEqual(pressed_keys, 0);
|
||||
testing.expectEqual(on_print_screen, false);
|
||||
testing.expectEqual(special_sequence, true);
|
||||
testing.expectEqual(expected_releases, 0);
|
||||
try testing.expectEqual(parseScanCode(128), null);
|
||||
try testing.expectEqual(pressed_keys, 0);
|
||||
try testing.expectEqual(on_print_screen, false);
|
||||
try testing.expectEqual(special_sequence, true);
|
||||
try testing.expectEqual(expected_releases, 0);
|
||||
|
||||
var res = parseScanCode(simple_special_codes[i]) orelse unreachable;
|
||||
testing.expectEqual(false, res.released);
|
||||
testing.expectEqual(key, res.position);
|
||||
testing.expectEqual(pressed_keys, 1);
|
||||
testing.expectEqual(on_print_screen, false);
|
||||
testing.expectEqual(special_sequence, true);
|
||||
testing.expectEqual(expected_releases, 1);
|
||||
try testing.expectEqual(false, res.released);
|
||||
try testing.expectEqual(key, res.position);
|
||||
try testing.expectEqual(pressed_keys, 1);
|
||||
try testing.expectEqual(on_print_screen, false);
|
||||
try testing.expectEqual(special_sequence, true);
|
||||
try testing.expectEqual(expected_releases, 1);
|
||||
|
||||
testing.expectEqual(parseScanCode(128), null);
|
||||
testing.expectEqual(pressed_keys, 1);
|
||||
testing.expectEqual(on_print_screen, false);
|
||||
testing.expectEqual(special_sequence, true);
|
||||
testing.expectEqual(expected_releases, 0);
|
||||
try testing.expectEqual(parseScanCode(128), null);
|
||||
try testing.expectEqual(pressed_keys, 1);
|
||||
try testing.expectEqual(on_print_screen, false);
|
||||
try testing.expectEqual(special_sequence, true);
|
||||
try testing.expectEqual(expected_releases, 0);
|
||||
|
||||
res = parseScanCode(simple_special_codes[i] | 128) orelse unreachable;
|
||||
testing.expectEqual(true, res.released);
|
||||
testing.expectEqual(key, res.position);
|
||||
testing.expectEqual(pressed_keys, 0);
|
||||
testing.expectEqual(on_print_screen, false);
|
||||
testing.expectEqual(special_sequence, false);
|
||||
testing.expectEqual(expected_releases, 0);
|
||||
try testing.expectEqual(true, res.released);
|
||||
try testing.expectEqual(key, res.position);
|
||||
try testing.expectEqual(pressed_keys, 0);
|
||||
try testing.expectEqual(on_print_screen, false);
|
||||
try testing.expectEqual(special_sequence, false);
|
||||
try testing.expectEqual(expected_releases, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_uint16_t = c_ushort;
|
||||
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,
|
||||
};
|
||||
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 {
|
||||
flags: multiboot_uint32_t,
|
||||
mem_lower: multiboot_uint32_t,
|
||||
|
@ -38,10 +107,7 @@ pub const struct_multiboot_info = extern struct {
|
|||
cmdline: multiboot_uint32_t,
|
||||
mods_count: multiboot_uint32_t,
|
||||
mods_addr: multiboot_uint32_t,
|
||||
u: extern union {
|
||||
aout_sym: multiboot_aout_symbol_table_t,
|
||||
elf_sec: multiboot_elf_section_header_table_t,
|
||||
},
|
||||
u: union_unnamed_1,
|
||||
mmap_length: multiboot_uint32_t,
|
||||
mmap_addr: 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_bpp: multiboot_uint8_t,
|
||||
framebuffer_type: multiboot_uint8_t,
|
||||
framebuffer: extern union {
|
||||
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,
|
||||
},
|
||||
},
|
||||
unnamed_0: union_unnamed_2,
|
||||
};
|
||||
pub const multiboot_info_t = struct_multiboot_info;
|
||||
pub const struct_multiboot_color = extern struct {
|
||||
|
@ -82,7 +135,7 @@ pub const struct_multiboot_color = extern struct {
|
|||
green: 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,
|
||||
addr: 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,
|
||||
dseg_len: multiboot_uint16_t,
|
||||
};
|
||||
pub const __GCC_ATOMIC_TEST_AND_SET_TRUEVAL = 1;
|
||||
pub const __BIGGEST_ALIGNMENT__ = 16;
|
||||
pub const __SIZEOF_FLOAT__ = 4;
|
||||
pub const __INT64_FMTd__ = "ld";
|
||||
pub const __STDC_VERSION__ = @as(c_long, 201112);
|
||||
pub const __INT_LEAST32_FMTi__ = "i";
|
||||
pub const __tune_znver1__ = 1;
|
||||
pub const __INT_LEAST8_FMTi__ = "hhi";
|
||||
pub const __LDBL_EPSILON__ = 0.000000;
|
||||
pub const __LZCNT__ = 1;
|
||||
pub const __INT_LEAST32_FMTd__ = "d";
|
||||
pub const __STDC_UTF_32__ = 1;
|
||||
pub const __SIG_ATOMIC_WIDTH__ = 32;
|
||||
pub const MULTIBOOT_MEMORY_BADRAM = 5;
|
||||
pub const __UINT_FAST64_FMTX__ = "lX";
|
||||
pub const __GCC_ATOMIC_LLONG_LOCK_FREE = 2;
|
||||
pub const __SEG_FS = 1;
|
||||
pub const __clang_version__ = "9.0.0 (tags/RELEASE_900/final)";
|
||||
pub const __UINT_LEAST8_FMTo__ = "hho";
|
||||
pub const __GCC_ASM_FLAG_OUTPUTS__ = 1;
|
||||
pub const __SIZEOF_DOUBLE__ = 8;
|
||||
pub const __INTMAX_FMTd__ = "ld";
|
||||
pub const __CLANG_ATOMIC_CHAR_LOCK_FREE = 2;
|
||||
pub const __INT_LEAST16_FMTi__ = "hi";
|
||||
pub const __GCC_ATOMIC_SHORT_LOCK_FREE = 2;
|
||||
pub const __FMA__ = 1;
|
||||
pub const __MMX__ = 1;
|
||||
pub const __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 = 1;
|
||||
pub const __SIZE_FMTX__ = "lX";
|
||||
pub const __RDSEED__ = 1;
|
||||
pub const __WCHAR_WIDTH__ = 32;
|
||||
pub const __FSGSBASE__ = 1;
|
||||
pub const __PTRDIFF_FMTd__ = "ld";
|
||||
pub const __DBL_MIN_EXP__ = -1021;
|
||||
pub const __FLT_EVAL_METHOD__ = 0;
|
||||
pub const __SSE_MATH__ = 1;
|
||||
pub const __UINT_FAST8_FMTo__ = "hho";
|
||||
pub const __UINT_LEAST64_MAX__ = @as(c_ulong, 18446744073709551615);
|
||||
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 __INTMAX_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `L`"); // (no file):67:9
|
||||
pub const __UINTMAX_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `UL`"); // (no file):73:9
|
||||
pub const __INT64_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `L`"); // (no file):164:9
|
||||
pub const __UINT32_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `U`"); // (no file):186:9
|
||||
pub const __UINT64_C_SUFFIX__ = @compileError("unable to translate macro: undefined identifier `UL`"); // (no file):194:9
|
||||
pub const __seg_gs = @compileError("unable to translate macro: undefined identifier `__attribute__`"); // (no file):312:9
|
||||
pub const __seg_fs = @compileError("unable to translate macro: undefined identifier `__attribute__`"); // (no file):313:9
|
||||
pub const __llvm__ = @as(c_int, 1);
|
||||
pub const __clang__ = @as(c_int, 1);
|
||||
pub const __clang_major__ = @as(c_int, 13);
|
||||
pub const __clang_minor__ = @as(c_int, 0);
|
||||
pub const __clang_patchlevel__ = @as(c_int, 0);
|
||||
pub const __clang_version__ = "13.0.0 (git@github.com:llvm/llvm-project d7b669b3a30345cfcdb2fde2af6f48aa4b94845d)";
|
||||
pub const __GNUC__ = @as(c_int, 4);
|
||||
pub const __GNUC_MINOR__ = @as(c_int, 2);
|
||||
pub const __GNUC_PATCHLEVEL__ = @as(c_int, 1);
|
||||
pub const __GXX_ABI_VERSION = @as(c_int, 1002);
|
||||
pub const __ATOMIC_RELAXED = @as(c_int, 0);
|
||||
pub const __ATOMIC_CONSUME = @as(c_int, 1);
|
||||
pub const __ATOMIC_ACQUIRE = @as(c_int, 2);
|
||||
pub const __ATOMIC_RELEASE = @as(c_int, 3);
|
||||
pub const __ATOMIC_ACQ_REL = @as(c_int, 4);
|
||||
pub const __ATOMIC_SEQ_CST = @as(c_int, 5);
|
||||
pub const __OPENCL_MEMORY_SCOPE_WORK_ITEM = @as(c_int, 0);
|
||||
pub const __OPENCL_MEMORY_SCOPE_WORK_GROUP = @as(c_int, 1);
|
||||
pub const __OPENCL_MEMORY_SCOPE_DEVICE = @as(c_int, 2);
|
||||
pub const __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES = @as(c_int, 3);
|
||||
pub const __OPENCL_MEMORY_SCOPE_SUB_GROUP = @as(c_int, 4);
|
||||
pub const __PRAGMA_REDEFINE_EXTNAME = @as(c_int, 1);
|
||||
pub const __VERSION__ = "Clang 13.0.0 (git@github.com:llvm/llvm-project d7b669b3a30345cfcdb2fde2af6f48aa4b94845d)";
|
||||
pub const __OBJC_BOOL_IS_BOOL = @as(c_int, 0);
|
||||
pub const __CONSTANT_CFSTRINGS__ = @as(c_int, 1);
|
||||
pub const __clang_literal_encoding__ = "UTF-8";
|
||||
pub const __clang_wide_literal_encoding__ = "UTF-32";
|
||||
pub const __OPTIMIZE__ = @as(c_int, 1);
|
||||
pub const __ORDER_LITTLE_ENDIAN__ = @as(c_int, 1234);
|
||||
pub const __ORDER_BIG_ENDIAN__ = @as(c_int, 4321);
|
||||
pub const __ORDER_PDP_ENDIAN__ = @as(c_int, 3412);
|
||||
pub const __BYTE_ORDER__ = __ORDER_LITTLE_ENDIAN__;
|
||||
pub const __SSE2__ = 1;
|
||||
pub const MULTIBOOT_INFO_FRAMEBUFFER_INFO = 4096;
|
||||
pub const __INT_MAX__ = 2147483647;
|
||||
pub const __INTMAX_FMTi__ = "li";
|
||||
pub const __DBL_DENORM_MIN__ = 0.000000;
|
||||
pub const MULTIBOOT_INFO_APM_TABLE = 1024;
|
||||
pub const __clang_major__ = 9;
|
||||
pub const __GNUC__ = 4;
|
||||
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 __LITTLE_ENDIAN__ = @as(c_int, 1);
|
||||
pub const _LP64 = @as(c_int, 1);
|
||||
pub const __LP64__ = @as(c_int, 1);
|
||||
pub const __CHAR_BIT__ = @as(c_int, 8);
|
||||
pub const __SCHAR_MAX__ = @as(c_int, 127);
|
||||
pub const __SHRT_MAX__ = @as(c_int, 32767);
|
||||
pub const __INT_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
|
||||
pub const __LONG_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const __LONG_LONG_MAX__ = @as(c_longlong, 9223372036854775807);
|
||||
pub const __OPENCL_MEMORY_SCOPE_SUB_GROUP = 4;
|
||||
pub const MULTIBOOT_MEMORY_NVS = 4;
|
||||
pub const __RDPID__ = 1;
|
||||
pub const MULTIBOOT_INFO_MEM_MAP = 64;
|
||||
pub const __INTMAX_MAX__ = @as(c_long, 9223372036854775807);
|
||||
pub const __UINT_LEAST32_FMTx__ = "x";
|
||||
pub const __WCHAR_MAX__ = 2147483647;
|
||||
pub const __INT64_MAX__ = @as(c_long, 9223372036854775807);
|
||||
pub const __CLANG_ATOMIC_CHAR32_T_LOCK_FREE = 2;
|
||||
pub const __INT_LEAST64_MAX__ = @as(c_long, 9223372036854775807);
|
||||
pub const __WCHAR_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_int, 2147483647, .decimal);
|
||||
pub const __WINT_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_uint, 4294967295, .decimal);
|
||||
pub const __INTMAX_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const __SIZE_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
|
||||
pub const __UINTMAX_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
|
||||
pub const __PTRDIFF_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const __INTPTR_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_long, 9223372036854775807, .decimal);
|
||||
pub const __UINTPTR_MAX__ = @import("std").zig.c_translation.promoteIntLiteral(c_ulong, 18446744073709551615, .decimal);
|
||||
pub const __SIZEOF_DOUBLE__ = @as(c_int, 8);
|
||||
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 __OPENCL_MEMORY_SCOPE_WORK_ITEM = 0;
|
||||
pub const __FLT_HAS_DENORM__ = 1;
|
||||
pub const __DECIMAL_DIG__ = __LDBL_DECIMAL_DIG__;
|
||||
pub const __INTMAX_WIDTH__ = @as(c_int, 64);
|
||||
pub const __PTRDIFF_TYPE__ = c_long;
|
||||
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 __DBL_HAS_INFINITY__ = 1;
|
||||
pub const __FINITE_MATH_ONLY__ = 0;
|
||||
pub const __INT32_C_SUFFIX__ = "";
|
||||
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_aout_symbol_table = struct_multiboot_aout_symbol_table;
|
||||
pub const multiboot_elf_section_header_table = struct_multiboot_elf_section_header_table;
|
||||
|
|
|
@ -7,8 +7,7 @@ const builtin = @import("builtin");
|
|||
const is_test = builtin.is_test;
|
||||
const panic = @import("../../panic.zig").panic;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
const arch = if (is_test) @import(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 isr = @import("isr.zig");
|
||||
const MemProfile = @import("../../mem.zig").MemProfile;
|
||||
const tty = @import("../../tty.zig");
|
||||
|
@ -133,7 +132,7 @@ pub var kernel_directory: Directory align(@truncate(u29, PAGE_SIZE_4KB)) = Direc
|
|||
/// Return: usize
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
@ -146,7 +145,7 @@ fn virtToDirEntryIdx(virt: usize) callconv(.Inline) usize {
|
|||
/// Return: usize
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
@ -157,7 +156,7 @@ fn virtToTableEntryIdx(virt: usize) callconv(.Inline) usize {
|
|||
/// val: *align(1) u32 - The entry to modify
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
@ -168,7 +167,7 @@ fn setAttribute(val: *align(1) u32, attr: u32) callconv(.Inline) void {
|
|||
/// val: *align(1) u32 - The entry to modify
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
@ -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_end: usize - The end of the physical space to map
|
||||
/// 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
|
||||
///
|
||||
/// 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
|
||||
/// 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) {
|
||||
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_end: usize - The end of the virtual space to map
|
||||
/// 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
|
||||
/// 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 table = dir.tables[entry] orelse return vmm.MapperError.NotMapped;
|
||||
var addr = virt_start;
|
||||
|
@ -287,7 +288,7 @@ fn unmapDirEntry(dir: *Directory, virt_start: usize, virt_end: usize, allocator:
|
|||
if (dir == &kernel_directory) {
|
||||
asm volatile ("invlpg (%[addr])"
|
||||
:
|
||||
: [addr] "r" (addr)
|
||||
: [addr] "r" (addr),
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
@ -341,7 +342,7 @@ fn mapTableEntry(dir: *const Directory, entry: *align(1) TableEntry, virt_addr:
|
|||
if (dir == &kernel_directory) {
|
||||
asm volatile ("invlpg (%[addr])"
|
||||
:
|
||||
: [addr] "r" (virt_addr)
|
||||
: [addr] "r" (virt_addr),
|
||||
: "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_end: usize - The end (exclusive) of the physical region to map to
|
||||
/// 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
|
||||
///
|
||||
/// Error: vmm.MapperError || Allocator.Error
|
||||
/// * - 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 phys_addr = phys_start;
|
||||
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
|
||||
/// 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_next = std.math.min(virtual_end, std.mem.alignBackward(virt_addr, PAGE_SIZE_4MB) + PAGE_SIZE_4MB);
|
||||
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 {
|
||||
log.info("State: {X}\n", .{state});
|
||||
var cr0 = asm volatile ("mov %%cr0, %[cr0]"
|
||||
: [cr0] "=r" (-> u32)
|
||||
: [cr0] "=r" (-> u32),
|
||||
);
|
||||
var cr2 = asm volatile ("mov %%cr2, %[cr2]"
|
||||
: [cr2] "=r" (-> u32)
|
||||
: [cr2] "=r" (-> u32),
|
||||
);
|
||||
var cr3 = asm volatile ("mov %%cr3, %[cr3]"
|
||||
: [cr3] "=r" (-> u32)
|
||||
: [cr3] "=r" (-> u32),
|
||||
);
|
||||
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 });
|
||||
@panic("Page fault");
|
||||
|
@ -454,7 +455,7 @@ pub fn init(mem_profile: *const MemProfile) void {
|
|||
const dir_physaddr = @ptrToInt(mem.virtToPhys(&kernel_directory));
|
||||
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);
|
||||
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 {
|
||||
expectEqual(entry & DENTRY_PRESENT, if (present) DENTRY_PRESENT else 0);
|
||||
expectEqual(entry & DENTRY_WRITABLE, if (attrs.writable) DENTRY_WRITABLE else 0);
|
||||
expectEqual(entry & DENTRY_USER, if (attrs.kernel) 0 else DENTRY_USER);
|
||||
expectEqual(entry & DENTRY_WRITE_THROUGH, DENTRY_WRITE_THROUGH);
|
||||
expectEqual(entry & DENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else DENTRY_CACHE_DISABLED);
|
||||
expectEqual(entry & DENTRY_4MB_PAGES, 0);
|
||||
expectEqual(entry & DENTRY_ZERO, 0);
|
||||
fn checkDirEntry(entry: DirectoryEntry, virt_start: usize, virt_end: usize, phys_start: usize, attrs: vmm.Attributes, table: *Table, present: bool) !void {
|
||||
try expectEqual(entry & DENTRY_PRESENT, if (present) DENTRY_PRESENT else 0);
|
||||
try expectEqual(entry & DENTRY_WRITABLE, if (attrs.writable) DENTRY_WRITABLE else 0);
|
||||
try expectEqual(entry & DENTRY_USER, if (attrs.kernel) 0 else DENTRY_USER);
|
||||
try expectEqual(entry & DENTRY_WRITE_THROUGH, DENTRY_WRITE_THROUGH);
|
||||
try expectEqual(entry & DENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else DENTRY_CACHE_DISABLED);
|
||||
try expectEqual(entry & DENTRY_4MB_PAGES, 0);
|
||||
try expectEqual(entry & DENTRY_ZERO, 0);
|
||||
|
||||
var tentry_idx = virtToTableEntryIdx(virt_start);
|
||||
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;
|
||||
}) {
|
||||
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 {
|
||||
expectEqual(entry & TENTRY_PRESENT, if (present) TENTRY_PRESENT else 0);
|
||||
expectEqual(entry & TENTRY_WRITABLE, if (attrs.writable) TENTRY_WRITABLE else 0);
|
||||
expectEqual(entry & TENTRY_USER, if (attrs.kernel) 0 else TENTRY_USER);
|
||||
expectEqual(entry & TENTRY_WRITE_THROUGH, TENTRY_WRITE_THROUGH);
|
||||
expectEqual(entry & TENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else TENTRY_CACHE_DISABLED);
|
||||
expectEqual(entry & TENTRY_ZERO, 0);
|
||||
expectEqual(entry & TENTRY_GLOBAL, 0);
|
||||
expectEqual(entry & TENTRY_PAGE_ADDR, page_phys);
|
||||
fn checkTableEntry(entry: TableEntry, page_phys: usize, attrs: vmm.Attributes, present: bool) !void {
|
||||
try expectEqual(entry & TENTRY_PRESENT, if (present) TENTRY_PRESENT else 0);
|
||||
try expectEqual(entry & TENTRY_WRITABLE, if (attrs.writable) TENTRY_WRITABLE else 0);
|
||||
try expectEqual(entry & TENTRY_USER, if (attrs.kernel) 0 else TENTRY_USER);
|
||||
try expectEqual(entry & TENTRY_WRITE_THROUGH, TENTRY_WRITE_THROUGH);
|
||||
try expectEqual(entry & TENTRY_CACHE_DISABLED, if (attrs.cachable) 0 else TENTRY_CACHE_DISABLED);
|
||||
try expectEqual(entry & TENTRY_ZERO, 0);
|
||||
try expectEqual(entry & TENTRY_GLOBAL, 0);
|
||||
try expectEqual(entry & TENTRY_PAGE_ADDR, page_phys);
|
||||
}
|
||||
|
||||
test "setAttribute and clearAttribute" {
|
||||
|
@ -502,35 +503,35 @@ test "setAttribute and clearAttribute" {
|
|||
for (attrs) |attr| {
|
||||
const old_val = val;
|
||||
setAttribute(&val, attr);
|
||||
std.testing.expectEqual(val, old_val | attr);
|
||||
try std.testing.expectEqual(val, old_val | attr);
|
||||
}
|
||||
|
||||
for (attrs) |attr| {
|
||||
const old_val = val;
|
||||
clearAttribute(&val, attr);
|
||||
std.testing.expectEqual(val, old_val & ~attr);
|
||||
try std.testing.expectEqual(val, old_val & ~attr);
|
||||
}
|
||||
}
|
||||
|
||||
test "virtToDirEntryIdx" {
|
||||
expectEqual(virtToDirEntryIdx(0), 0);
|
||||
expectEqual(virtToDirEntryIdx(123), 0);
|
||||
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB - 1), 0);
|
||||
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB), 1);
|
||||
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB + 1), 1);
|
||||
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * 2), 2);
|
||||
expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * (ENTRIES_PER_DIRECTORY - 1)), ENTRIES_PER_DIRECTORY - 1);
|
||||
try expectEqual(virtToDirEntryIdx(0), 0);
|
||||
try expectEqual(virtToDirEntryIdx(123), 0);
|
||||
try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB - 1), 0);
|
||||
try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB), 1);
|
||||
try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB + 1), 1);
|
||||
try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * 2), 2);
|
||||
try expectEqual(virtToDirEntryIdx(PAGE_SIZE_4MB * (ENTRIES_PER_DIRECTORY - 1)), ENTRIES_PER_DIRECTORY - 1);
|
||||
}
|
||||
|
||||
test "virtToTableEntryIdx" {
|
||||
expectEqual(virtToTableEntryIdx(0), 0);
|
||||
expectEqual(virtToTableEntryIdx(123), 0);
|
||||
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB - 1), 0);
|
||||
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB), 1);
|
||||
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB + 1), 1);
|
||||
expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * 2), 2);
|
||||
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(0), 0);
|
||||
try expectEqual(virtToTableEntryIdx(123), 0);
|
||||
try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB - 1), 0);
|
||||
try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB), 1);
|
||||
try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB + 1), 1);
|
||||
try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * 2), 2);
|
||||
try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * (ENTRIES_PER_TABLE - 1)), ENTRIES_PER_TABLE - 1);
|
||||
try expectEqual(virtToTableEntryIdx(PAGE_SIZE_4KB * (ENTRIES_PER_TABLE)), 0);
|
||||
}
|
||||
|
||||
test "mapDirEntry" {
|
||||
|
@ -550,7 +551,7 @@ test "mapDirEntry" {
|
|||
const entry_idx = virtToDirEntryIdx(virt);
|
||||
const entry = dir.entries[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];
|
||||
allocator.free(table_free);
|
||||
}
|
||||
|
@ -565,7 +566,7 @@ test "mapDirEntry" {
|
|||
const entry_idx = virtToDirEntryIdx(virt);
|
||||
const entry = dir.entries[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];
|
||||
allocator.free(table_free);
|
||||
}
|
||||
|
@ -575,11 +576,11 @@ test "mapDirEntry returns errors correctly" {
|
|||
var allocator = std.testing.allocator;
|
||||
var dir = Directory{ .entries = [_]DirectoryEntry{0} ** ENTRIES_PER_DIRECTORY, .tables = undefined };
|
||||
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));
|
||||
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));
|
||||
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.MisalignedVirtualAddress, mapDirEntry(&dir, 1, PAGE_SIZE_4KB + 1, 0, PAGE_SIZE_4KB, attrs, allocator));
|
||||
try testing.expectError(vmm.MapperError.MisalignedPhysicalAddress, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, PAGE_SIZE_4KB + 1, attrs, allocator));
|
||||
try testing.expectError(vmm.MapperError.AddressMismatch, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, PAGE_SIZE_4KB, attrs, allocator));
|
||||
try testing.expectError(vmm.MapperError.InvalidVirtualAddress, mapDirEntry(&dir, 1, 0, 0, PAGE_SIZE_4KB, attrs, allocator));
|
||||
try testing.expectError(vmm.MapperError.InvalidPhysicalAddress, mapDirEntry(&dir, 0, PAGE_SIZE_4KB, 1, 0, attrs, allocator));
|
||||
}
|
||||
|
||||
test "map and unmap" {
|
||||
|
@ -605,7 +606,7 @@ test "map and unmap" {
|
|||
const entry_idx = virtToDirEntryIdx(virt);
|
||||
const entry = dir.entries[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);
|
||||
|
@ -618,7 +619,7 @@ test "map and unmap" {
|
|||
const entry_idx = virtToDirEntryIdx(virt);
|
||||
const entry = dir.entries[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();
|
||||
const dir_slice = @ptrCast([*]const u8, &dir)[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
|
||||
dir2.tables[1] = &table0;
|
||||
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
|
||||
|
@ -665,7 +666,7 @@ fn rt_accessUnmappedMem(v_end: u32) void {
|
|||
var ptr = @intToPtr(*u8, v_end);
|
||||
var value = ptr.*;
|
||||
// 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
|
||||
asm volatile (
|
||||
\\.global rt_fault_callback
|
||||
|
@ -682,7 +683,8 @@ fn rt_accessMappedMem(v_end: u32) void {
|
|||
faulted = false;
|
||||
// Accessing mapped memory doesn't cause a page fault
|
||||
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 (
|
||||
\\.global rt_fault_callback2
|
||||
\\rt_fault_callback2:
|
||||
|
|
|
@ -3,11 +3,10 @@ const builtin = @import("builtin");
|
|||
const is_test = builtin.is_test;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
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.
|
||||
const CONFIG_ADDRESS: u16 = 0x0CF8;
|
||||
|
@ -161,7 +160,7 @@ const PciDevice = struct {
|
|||
|
||||
// RevisionId is a u8 width, offset 0
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN allocator: *Allocator - An allocator used for creating the list.
|
||||
/// IN allocator: Allocator - An allocator used for creating the list.
|
||||
///
|
||||
/// Return: []PciDeviceInfo
|
||||
/// The list of PCI devices information.
|
||||
|
@ -325,7 +324,7 @@ pub const PciDeviceInfo = struct {
|
|||
/// Error: Allocator.Error
|
||||
/// 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.
|
||||
var pci_device_infos = ArrayList(PciDeviceInfo).init(allocator);
|
||||
defer pci_device_infos.deinit();
|
||||
|
|
|
@ -5,9 +5,8 @@ const log = std.log.scoped(.x86_pic);
|
|||
const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
|
||||
const panic = if (is_test) @import(mock_path ++ "panic_mock.zig").panic else @import("../../panic.zig").panic;
|
||||
const arch = if (is_test) @import("../../../../test/mock/kernel/arch_mock.zig") else @import("arch.zig");
|
||||
const panic = @import("../../panic.zig").panic;
|
||||
|
||||
// ----------
|
||||
// Port address for the PIC master and slave registers.
|
||||
|
@ -251,7 +250,7 @@ var spurious_irq_counter: u32 = 0;
|
|||
/// Arguments:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -261,7 +260,7 @@ fn sendCommandMaster(cmd: u8) callconv(.Inline) void {
|
|||
/// Arguments:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -271,7 +270,7 @@ fn sendCommandSlave(cmd: u8) callconv(.Inline) void {
|
|||
/// Arguments:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -281,7 +280,7 @@ fn sendDataMaster(data: u8) callconv(.Inline) void {
|
|||
/// Arguments:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -291,7 +290,7 @@ fn sendDataSlave(data: u8) callconv(.Inline) void {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -301,7 +300,7 @@ fn readDataMaster() callconv(.Inline) u8 {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -311,7 +310,7 @@ fn readDataSlave() callconv(.Inline) u8 {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
return arch.in(u8, MASTER_STATUS_REG);
|
||||
}
|
||||
|
@ -322,7 +321,7 @@ fn readMasterIrr() callconv(.Inline) u8 {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
return arch.in(u8, SLAVE_STATUS_REG);
|
||||
}
|
||||
|
@ -333,7 +332,7 @@ fn readSlaveIrr() callconv(.Inline) u8 {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
return arch.in(u8, MASTER_STATUS_REG);
|
||||
}
|
||||
|
@ -344,7 +343,7 @@ fn readMasterIsr() callconv(.Inline) u8 {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
return arch.in(u8, SLAVE_STATUS_REG);
|
||||
}
|
||||
|
@ -529,7 +528,7 @@ test "readDataMaster" {
|
|||
|
||||
arch.addTestParams("in", .{ MASTER_DATA_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readDataMaster());
|
||||
try expectEqual(@as(u8, 10), readDataMaster());
|
||||
}
|
||||
|
||||
test "readDataSlave" {
|
||||
|
@ -539,7 +538,7 @@ test "readDataSlave" {
|
|||
|
||||
arch.addTestParams("in", .{ SLAVE_DATA_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readDataSlave());
|
||||
try expectEqual(@as(u8, 10), readDataSlave());
|
||||
}
|
||||
|
||||
test "readMasterIrr" {
|
||||
|
@ -550,7 +549,7 @@ test "readMasterIrr" {
|
|||
arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0A) });
|
||||
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readMasterIrr());
|
||||
try expectEqual(@as(u8, 10), readMasterIrr());
|
||||
}
|
||||
|
||||
test "readSlaveIrr" {
|
||||
|
@ -561,7 +560,7 @@ test "readSlaveIrr" {
|
|||
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0A) });
|
||||
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readSlaveIrr());
|
||||
try expectEqual(@as(u8, 10), readSlaveIrr());
|
||||
}
|
||||
|
||||
test "readMasterIsr" {
|
||||
|
@ -572,7 +571,7 @@ test "readMasterIsr" {
|
|||
arch.addTestParams("out", .{ MASTER_COMMAND_REG, @as(u8, 0x0B) });
|
||||
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readMasterIsr());
|
||||
try expectEqual(@as(u8, 10), readMasterIsr());
|
||||
}
|
||||
|
||||
test "readSlaveIsr" {
|
||||
|
@ -583,7 +582,7 @@ test "readSlaveIsr" {
|
|||
arch.addTestParams("out", .{ SLAVE_COMMAND_REG, @as(u8, 0x0B) });
|
||||
arch.addTestParams("in", .{ SLAVE_STATUS_REG, @as(u8, 10) });
|
||||
|
||||
expectEqual(@as(u8, 10), readSlaveIsr());
|
||||
try expectEqual(@as(u8, 10), readSlaveIsr());
|
||||
}
|
||||
|
||||
test "sendEndOfInterrupt master only" {
|
||||
|
@ -615,17 +614,17 @@ test "sendEndOfInterrupt master and slave" {
|
|||
|
||||
test "spuriousIrq not spurious IRQ number" {
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
var i: u8 = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
if (i != 7 and i != 15) {
|
||||
expectEqual(false, spuriousIrq(i));
|
||||
try expectEqual(false, spuriousIrq(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Post testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
// Clean up
|
||||
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) });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
// Call function
|
||||
expectEqual(false, spuriousIrq(7));
|
||||
try expectEqual(false, spuriousIrq(7));
|
||||
|
||||
// Post testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
// Clean up
|
||||
spurious_irq_counter = 0;
|
||||
|
@ -663,13 +662,13 @@ test "spuriousIrq spurious master IRQ number spurious" {
|
|||
arch.addTestParams("in", .{ MASTER_STATUS_REG, @as(u8, 0x0) });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
// Call function
|
||||
expectEqual(true, spuriousIrq(7));
|
||||
try expectEqual(true, spuriousIrq(7));
|
||||
|
||||
// Post testing
|
||||
expectEqual(@as(u32, 1), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 1), spurious_irq_counter);
|
||||
|
||||
// Clean up
|
||||
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) });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
// Call function
|
||||
expectEqual(false, spuriousIrq(15));
|
||||
try expectEqual(false, spuriousIrq(15));
|
||||
|
||||
// Post testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
// Clean up
|
||||
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 });
|
||||
|
||||
// Pre testing
|
||||
expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 0), spurious_irq_counter);
|
||||
|
||||
// Call function
|
||||
expectEqual(true, spuriousIrq(15));
|
||||
try expectEqual(true, spuriousIrq(15));
|
||||
|
||||
// Post testing
|
||||
expectEqual(@as(u32, 1), spurious_irq_counter);
|
||||
try expectEqual(@as(u32, 1), spurious_irq_counter);
|
||||
|
||||
// Clean up
|
||||
spurious_irq_counter = 0;
|
||||
|
|
|
@ -7,8 +7,7 @@ const expectEqual = std.testing.expectEqual;
|
|||
const expectError = std.testing.expectError;
|
||||
const log = std.log.scoped(.x86_pit);
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
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 panic = @import("../../panic.zig").panic;
|
||||
const irq = @import("irq.zig");
|
||||
const pic = @import("pic.zig");
|
||||
|
@ -198,7 +197,7 @@ var time_under_1_ns: u32 = undefined;
|
|||
/// Arguments:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -211,7 +210,7 @@ fn sendCommand(cmd: u8) callconv(.Inline) void {
|
|||
/// Return: u8
|
||||
/// 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);
|
||||
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 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);
|
||||
}
|
||||
|
||||
|
@ -368,7 +367,7 @@ pub fn init() void {
|
|||
|
||||
// Set up counter 0 at 10000hz in a square wave mode counting in binary
|
||||
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});
|
||||
};
|
||||
|
||||
|
@ -412,7 +411,7 @@ test "readBackCommand" {
|
|||
|
||||
const actual = readBackCommand(CounterSelect.Counter0);
|
||||
|
||||
expectEqual(@as(u8, 0x20), actual);
|
||||
try expectEqual(@as(u8, 0x20), actual);
|
||||
}
|
||||
|
||||
test "sendDataToCounter" {
|
||||
|
@ -431,36 +430,14 @@ test "setupCounter lowest frequency" {
|
|||
defer arch.freeTest();
|
||||
|
||||
const counter = CounterSelect.Counter0;
|
||||
const port = counter.getRegister();
|
||||
|
||||
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 command = mode | OCW_READ_LOAD_DATA | counter.getCounterOCW();
|
||||
|
||||
while (freq <= 18) : (freq += 1) {
|
||||
// arch.addTestParams("out", COMMAND_REGISTER, command, port, @truncate(u8, expected_reload_value), port, @truncate(u8, expected_reload_value >> 8));
|
||||
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);
|
||||
try expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
|
||||
}
|
||||
|
||||
// Reset globals
|
||||
time_ns = 0;
|
||||
current_freq_0 = 0;
|
||||
ticks = 0;
|
||||
}
|
||||
|
||||
test "setupCounter highest frequency" {
|
||||
|
@ -468,36 +445,13 @@ test "setupCounter highest frequency" {
|
|||
defer arch.freeTest();
|
||||
|
||||
const counter = CounterSelect.Counter0;
|
||||
const port = counter.getRegister();
|
||||
|
||||
// Set the frequency above the maximum
|
||||
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 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));
|
||||
|
||||
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;
|
||||
try expectError(PitError.InvalidFrequency, setupCounter(counter, freq, mode));
|
||||
}
|
||||
|
||||
test "setupCounter normal frequency" {
|
||||
|
@ -519,13 +473,13 @@ test "setupCounter normal frequency" {
|
|||
|
||||
setupCounter(counter, freq, mode) catch unreachable;
|
||||
|
||||
expectEqual(@as(u32, 0), ticks);
|
||||
expectEqual(expected_freq, current_freq_0);
|
||||
expectEqual(expected_freq, getFrequency());
|
||||
try expectEqual(@as(u32, 0), ticks);
|
||||
try expectEqual(expected_freq, current_freq_0);
|
||||
try expectEqual(expected_freq, getFrequency());
|
||||
|
||||
// These are the hard coded expected values. Calculated externally to check the internal calculation
|
||||
expectEqual(@as(u32, 99730), time_ns);
|
||||
expectEqual(@as(u32, 727), time_under_1_ns);
|
||||
try expectEqual(@as(u32, 99730), time_ns);
|
||||
try expectEqual(@as(u32, 727), time_under_1_ns);
|
||||
|
||||
// Reset globals
|
||||
time_ns = 0;
|
||||
|
|
|
@ -6,12 +6,11 @@ const expectEqual = std.testing.expectEqual;
|
|||
const expectError = std.testing.expectError;
|
||||
const log = std.log.scoped(.x86_rtc);
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
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 pic = @import("pic.zig");
|
||||
const pit = @import("pit.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 scheduler = @import("../../scheduler.zig");
|
||||
|
||||
|
@ -166,7 +165,7 @@ fn rtcHandler(ctx: *arch.CpuState) usize {
|
|||
|
||||
// Need to read status register C
|
||||
// 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;
|
||||
}
|
||||
|
@ -290,7 +289,7 @@ pub fn init() void {
|
|||
enableInterrupts();
|
||||
|
||||
// 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) {
|
||||
.Initialisation => runtimeTests(),
|
||||
|
@ -307,7 +306,7 @@ test "isBusy not busy" {
|
|||
.{ cmos.StatusRegister.A, false, @as(u8, 0x60) },
|
||||
);
|
||||
|
||||
expect(!isBusy());
|
||||
try expect(!isBusy());
|
||||
}
|
||||
|
||||
test "isBusy busy" {
|
||||
|
@ -319,7 +318,7 @@ test "isBusy busy" {
|
|||
.{ cmos.StatusRegister.A, false, @as(u8, 0x80) },
|
||||
);
|
||||
|
||||
expect(isBusy());
|
||||
try expect(isBusy());
|
||||
}
|
||||
|
||||
test "calcDayOfWeek" {
|
||||
|
@ -337,7 +336,7 @@ test "calcDayOfWeek" {
|
|||
var actual = calcDayOfWeek(date_time);
|
||||
var expected = @as(u32, 5);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
|
||||
date_time.day = 20;
|
||||
date_time.month = 7;
|
||||
|
@ -346,7 +345,7 @@ test "calcDayOfWeek" {
|
|||
actual = calcDayOfWeek(date_time);
|
||||
expected = @as(u32, 6);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
|
||||
date_time.day = 9;
|
||||
date_time.month = 11;
|
||||
|
@ -355,7 +354,7 @@ test "calcDayOfWeek" {
|
|||
actual = calcDayOfWeek(date_time);
|
||||
expected = @as(u32, 1);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
|
||||
date_time.day = 1;
|
||||
date_time.month = 1;
|
||||
|
@ -364,7 +363,7 @@ test "calcDayOfWeek" {
|
|||
actual = calcDayOfWeek(date_time);
|
||||
expected = @as(u32, 6);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "isBcd not BCD" {
|
||||
|
@ -376,7 +375,7 @@ test "isBcd not BCD" {
|
|||
.{ cmos.StatusRegister.B, false, @as(u8, 0x00) },
|
||||
);
|
||||
|
||||
expect(!isBcd());
|
||||
try expect(!isBcd());
|
||||
}
|
||||
|
||||
test "isBcd BCD" {
|
||||
|
@ -388,7 +387,7 @@ test "isBcd BCD" {
|
|||
.{ cmos.StatusRegister.B, false, @as(u8, 0x04) },
|
||||
);
|
||||
|
||||
expect(isBcd());
|
||||
try expect(isBcd());
|
||||
}
|
||||
|
||||
test "is12Hr not 12Hr" {
|
||||
|
@ -411,7 +410,7 @@ test "is12Hr not 12Hr" {
|
|||
.{ cmos.StatusRegister.B, false, @as(u8, 0x00) },
|
||||
);
|
||||
|
||||
expect(!is12Hr(date_time));
|
||||
try expect(!is12Hr(date_time));
|
||||
}
|
||||
|
||||
test "is12Hr 12Hr" {
|
||||
|
@ -434,24 +433,24 @@ test "is12Hr 12Hr" {
|
|||
.{ cmos.StatusRegister.B, false, @as(u8, 0x02) },
|
||||
);
|
||||
|
||||
expect(is12Hr(date_time));
|
||||
try expect(is12Hr(date_time));
|
||||
}
|
||||
|
||||
test "bcdToBinary" {
|
||||
var expected = @as(u32, 59);
|
||||
var actual = bcdToBinary(0x59);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
|
||||
expected = @as(u32, 48);
|
||||
actual = bcdToBinary(0x48);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
|
||||
expected = @as(u32, 1);
|
||||
actual = bcdToBinary(0x01);
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "readRtcRegisters" {
|
||||
|
@ -486,7 +485,7 @@ test "readRtcRegisters" {
|
|||
};
|
||||
const actual = readRtcRegisters();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "readRtc unstable read" {
|
||||
|
@ -560,7 +559,7 @@ test "readRtc unstable read" {
|
|||
};
|
||||
const actual = getDateTime();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "readRtc is BCD" {
|
||||
|
@ -613,7 +612,7 @@ test "readRtc is BCD" {
|
|||
};
|
||||
const actual = getDateTime();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "readRtc is 12 hours" {
|
||||
|
@ -666,13 +665,13 @@ test "readRtc is 12 hours" {
|
|||
};
|
||||
const actual = getDateTime();
|
||||
|
||||
expectEqual(expected, actual);
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "setRate below 3" {
|
||||
expectError(RtcError.RateError, setRate(0));
|
||||
expectError(RtcError.RateError, setRate(1));
|
||||
expectError(RtcError.RateError, setRate(2));
|
||||
try expectError(RtcError.RateError, setRate(0));
|
||||
try expectError(RtcError.RateError, setRate(1));
|
||||
try expectError(RtcError.RateError, setRate(2));
|
||||
}
|
||||
|
||||
test "setRate" {
|
||||
|
|
|
@ -151,21 +151,21 @@ test "lcrValue computes the correct value" {
|
|||
@boolToInt(stop_bit) << 2 |
|
||||
@boolToInt(parity_bit) << 3 |
|
||||
@intCast(u8, msb) << 7;
|
||||
testing.expectEqual(val, expected);
|
||||
try testing.expectEqual(val, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check invalid char lengths
|
||||
testing.expectError(SerialError.InvalidCharacterLength, lcrValue(4, false, false, 0));
|
||||
testing.expectError(SerialError.InvalidCharacterLength, lcrValue(9, false, false, 0));
|
||||
try testing.expectError(SerialError.InvalidCharacterLength, lcrValue(4, false, false, 0));
|
||||
try testing.expectError(SerialError.InvalidCharacterLength, lcrValue(9, false, false, 0));
|
||||
}
|
||||
|
||||
test "baudDivisor" {
|
||||
// Check invalid baudrates
|
||||
inline for ([_]u32{ 0, BAUD_MAX + 1 }) |baud| {
|
||||
testing.expectError(SerialError.InvalidBaudRate, baudDivisor(baud));
|
||||
try testing.expectError(SerialError.InvalidBaudRate, baudDivisor(baud));
|
||||
}
|
||||
|
||||
// Check valid baudrates
|
||||
|
@ -173,6 +173,6 @@ test "baudDivisor" {
|
|||
while (baud <= BAUD_MAX) : (baud += 1) {
|
||||
const val = try baudDivisor(baud);
|
||||
const expected = @truncate(u16, BAUD_MAX / baud);
|
||||
testing.expectEqual(val, expected);
|
||||
try testing.expectEqual(val, expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@ const log = std.log.scoped(.x86_syscalls);
|
|||
const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.arch_mock_path;
|
||||
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 testing = std.testing;
|
||||
const expect = std.testing.expect;
|
||||
const isr = @import("isr.zig");
|
||||
|
@ -18,7 +17,7 @@ pub const INTERRUPT: u16 = 0x80;
|
|||
pub const NUM_HANDLERS: u16 = 256;
|
||||
|
||||
/// 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
|
||||
pub const Error = error{
|
||||
|
@ -65,7 +64,7 @@ fn handle(ctx: *arch.CpuState) usize {
|
|||
const syscall = ctx.eax;
|
||||
if (isValidSyscall(syscall)) {
|
||||
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| {
|
||||
ctx.eax = res;
|
||||
ctx.ebx = 0;
|
||||
|
@ -112,15 +111,15 @@ pub fn registerSyscall(syscall: usize, handler: Handler) Error!void {
|
|||
/// Error: syscalls.Error
|
||||
/// 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 (
|
||||
\\int $0x80
|
||||
: [ret] "={eax}" (-> usize)
|
||||
: [syscall] "{eax}" (syscall)
|
||||
: [ret] "={eax}" (-> usize),
|
||||
: [syscall] "{eax}" (syscall),
|
||||
: "ebx"
|
||||
);
|
||||
const err = asm (""
|
||||
: [ret] "={ebx}" (-> usize)
|
||||
: [ret] "={ebx}" (-> usize),
|
||||
);
|
||||
if (err != 0) {
|
||||
return syscalls.fromErrorCode(err);
|
||||
|
@ -141,15 +140,15 @@ fn syscall0(syscall: usize) callconv(.Inline) syscalls.Error!usize {
|
|||
/// Error: syscalls.Error
|
||||
/// 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 (
|
||||
\\int $0x80
|
||||
: [ret] "={eax}" (-> usize)
|
||||
: [ret] "={eax}" (-> usize),
|
||||
: [syscall] "{eax}" (syscall),
|
||||
[arg1] "{ebx}" (arg)
|
||||
[arg1] "{ebx}" (arg),
|
||||
);
|
||||
const err = asm (""
|
||||
: [ret] "={ebx}" (-> usize)
|
||||
: [ret] "={ebx}" (-> usize),
|
||||
);
|
||||
if (err != 0) {
|
||||
return syscalls.fromErrorCode(err);
|
||||
|
@ -171,16 +170,16 @@ fn syscall1(syscall: usize, arg: usize) callconv(.Inline) syscalls.Error!usize {
|
|||
/// Error: syscalls.Error
|
||||
/// 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 (
|
||||
\\int $0x80
|
||||
: [ret] "={eax}" (-> usize)
|
||||
: [ret] "={eax}" (-> usize),
|
||||
: [syscall] "{eax}" (syscall),
|
||||
[arg1] "{ebx}" (arg1),
|
||||
[arg2] "{ecx}" (arg2)
|
||||
[arg2] "{ecx}" (arg2),
|
||||
);
|
||||
const err = asm (""
|
||||
: [ret] "={ebx}" (-> usize)
|
||||
: [ret] "={ebx}" (-> usize),
|
||||
);
|
||||
if (err != 0) {
|
||||
return syscalls.fromErrorCode(err);
|
||||
|
@ -203,17 +202,17 @@ fn syscall2(syscall: usize, arg1: usize, arg2: usize) callconv(.Inline) syscalls
|
|||
/// Error: syscalls.Error
|
||||
/// 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 (
|
||||
\\int $0x80
|
||||
: [ret] "={eax}" (-> usize)
|
||||
: [ret] "={eax}" (-> usize),
|
||||
: [syscall] "{eax}" (syscall),
|
||||
[arg1] "{ebx}" (arg1),
|
||||
[arg2] "{ecx}" (arg2),
|
||||
[arg3] "{edx}" (arg3)
|
||||
[arg3] "{edx}" (arg3),
|
||||
);
|
||||
const err = asm (""
|
||||
: [ret] "={ebx}" (-> usize)
|
||||
: [ret] "={ebx}" (-> usize),
|
||||
);
|
||||
if (err != 0) {
|
||||
return syscalls.fromErrorCode(err);
|
||||
|
@ -237,18 +236,18 @@ fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) callconv(.Inl
|
|||
/// Error: syscalls.Error
|
||||
/// 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 (
|
||||
\\int $0x80
|
||||
: [ret] "={eax}" (-> usize)
|
||||
: [ret] "={eax}" (-> usize),
|
||||
: [syscall] "{eax}" (syscall),
|
||||
[arg1] "{ebx}" (arg1),
|
||||
[arg2] "{ecx}" (arg2),
|
||||
[arg3] "{edx}" (arg3),
|
||||
[arg4] "{esi}" (arg4)
|
||||
[arg4] "{esi}" (arg4),
|
||||
);
|
||||
const err = asm (""
|
||||
: [ret] "={ebx}" (-> usize)
|
||||
: [ret] "={ebx}" (-> usize),
|
||||
);
|
||||
if (err != 0) {
|
||||
return syscalls.fromErrorCode(err);
|
||||
|
@ -273,19 +272,19 @@ fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize)
|
|||
/// Error: syscalls.Error
|
||||
/// 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 (
|
||||
\\int $0x80
|
||||
: [ret] "={eax}" (-> usize)
|
||||
: [ret] "={eax}" (-> usize),
|
||||
: [syscall] "{eax}" (syscall),
|
||||
[arg1] "{ebx}" (arg1),
|
||||
[arg2] "{ecx}" (arg2),
|
||||
[arg3] "{edx}" (arg3),
|
||||
[arg4] "{esi}" (arg4),
|
||||
[arg5] "{edi}" (arg5)
|
||||
[arg5] "{edi}" (arg5),
|
||||
);
|
||||
const err = asm (""
|
||||
: [ret] "={ebx}" (-> usize)
|
||||
: [ret] "={ebx}" (-> usize),
|
||||
);
|
||||
if (err != 0) {
|
||||
return syscalls.fromErrorCode(err);
|
||||
|
@ -304,7 +303,7 @@ fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
|
|||
/// Return: usize
|
||||
/// 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) {
|
||||
0 => ctx.ebx,
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
}.func;
|
||||
|
@ -359,43 +358,69 @@ pub fn init() void {
|
|||
/// Tests
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
test "registerSyscall returns SyscallExists" {
|
||||
try registerSyscall(122, testHandler0);
|
||||
std.testing.expectError(Error.SyscallExists, registerSyscall(122, testHandler0));
|
||||
try std.testing.expectError(Error.SyscallExists, registerSyscall(122, testHandler0));
|
||||
}
|
||||
|
||||
fn runtimeTests() void {
|
||||
|
@ -459,7 +484,7 @@ fn runtimeTests() void {
|
|||
panic(@errorReturnTrace(), "FAILURE syscall5 errored: {}\n", .{e});
|
||||
}
|
||||
|
||||
if (syscall0(121)) |res| {
|
||||
if (syscall0(121)) {
|
||||
panic(@errorReturnTrace(), "FAILURE syscall6\n", .{});
|
||||
} else |e| {
|
||||
if (e != syscalls.Error.OutOfMemory) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,7 +4,7 @@ const is_test = builtin.is_test;
|
|||
const expectEqual = std.testing.expectEqual;
|
||||
const log = std.log.scoped(.x86_vga);
|
||||
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;
|
||||
|
||||
/// 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
|
||||
/// to.
|
||||
///
|
||||
fn sendPort(index: u8) callconv(.Inline) void {
|
||||
inline fn sendPort(index: u8) void {
|
||||
arch.out(PORT_ADDRESS, index);
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ fn sendPort(index: u8) callconv(.Inline) void {
|
|||
/// Arguments:
|
||||
/// 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);
|
||||
}
|
||||
|
||||
|
@ -141,7 +141,7 @@ fn sendData(data: u8) callconv(.Inline) void {
|
|||
/// Return: u8
|
||||
/// The data in the selected register.
|
||||
///
|
||||
fn getData() callconv(.Inline) u8 {
|
||||
inline fn getData() u8 {
|
||||
return arch.in(u8, PORT_DATA);
|
||||
}
|
||||
///
|
||||
|
@ -152,7 +152,7 @@ fn getData() callconv(.Inline) u8 {
|
|||
// data to.
|
||||
/// 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);
|
||||
sendData(data);
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ fn sendPortData(index: u8, data: u8) callconv(.Inline) void {
|
|||
/// Return: u8
|
||||
/// The data in the selected register.
|
||||
///
|
||||
fn getPortData(index: u8) callconv(.Inline) u8 {
|
||||
inline fn getPortData(index: u8) u8 {
|
||||
sendPort(index);
|
||||
return getData();
|
||||
}
|
||||
|
@ -303,34 +303,34 @@ test "entryColour" {
|
|||
var fg = COLOUR_BLACK;
|
||||
var bg = COLOUR_BLACK;
|
||||
var res = entryColour(fg, bg);
|
||||
expectEqual(@as(u8, 0x00), res);
|
||||
try expectEqual(@as(u8, 0x00), res);
|
||||
|
||||
fg = COLOUR_LIGHT_GREEN;
|
||||
bg = COLOUR_BLACK;
|
||||
res = entryColour(fg, bg);
|
||||
expectEqual(@as(u8, 0x0A), res);
|
||||
try expectEqual(@as(u8, 0x0A), res);
|
||||
|
||||
fg = COLOUR_BLACK;
|
||||
bg = COLOUR_LIGHT_GREEN;
|
||||
res = entryColour(fg, bg);
|
||||
expectEqual(@as(u8, 0xA0), res);
|
||||
try expectEqual(@as(u8, 0xA0), res);
|
||||
|
||||
fg = COLOUR_BROWN;
|
||||
bg = COLOUR_LIGHT_GREEN;
|
||||
res = entryColour(fg, bg);
|
||||
expectEqual(@as(u8, 0xA6), res);
|
||||
try expectEqual(@as(u8, 0xA6), res);
|
||||
}
|
||||
|
||||
test "entry" {
|
||||
const colour = entryColour(COLOUR_BROWN, COLOUR_LIGHT_GREEN);
|
||||
expectEqual(@as(u8, 0xA6), colour);
|
||||
try expectEqual(@as(u8, 0xA6), colour);
|
||||
|
||||
// Character '0' is 0x30
|
||||
var video_entry = entry('0', colour);
|
||||
expectEqual(@as(u16, 0xA630), video_entry);
|
||||
try expectEqual(@as(u16, 0xA630), video_entry);
|
||||
|
||||
video_entry = entry(0x55, colour);
|
||||
expectEqual(@as(u16, 0xA655), video_entry);
|
||||
try expectEqual(@as(u16, 0xA655), video_entry);
|
||||
}
|
||||
|
||||
test "updateCursor width out of bounds" {
|
||||
|
@ -447,7 +447,7 @@ test "getCursor 1: 10" {
|
|||
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0) });
|
||||
|
||||
const actual = getCursor();
|
||||
expectEqual(expect, actual);
|
||||
try expectEqual(expect, actual);
|
||||
}
|
||||
|
||||
test "getCursor 2: 0xBEEF" {
|
||||
|
@ -463,7 +463,7 @@ test "getCursor 2: 0xBEEF" {
|
|||
arch.addTestParams("in", .{ PORT_DATA, @as(u8, 0xBE) });
|
||||
|
||||
const actual = getCursor();
|
||||
expectEqual(expect, actual);
|
||||
try expectEqual(expect, actual);
|
||||
}
|
||||
|
||||
test "enableCursor" {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
const testing = std.testing;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
|
@ -50,7 +50,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
|
|||
///
|
||||
pub fn setEntry(self: *Self, idx: IndexType) void {
|
||||
if (!self.isSet(idx)) {
|
||||
self.bitmap |= self.indexToBit(idx);
|
||||
self.bitmap |= indexToBit(idx);
|
||||
self.num_free_entries -= 1;
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
|
|||
///
|
||||
pub fn clearEntry(self: *Self, idx: IndexType) void {
|
||||
if (self.isSet(idx)) {
|
||||
self.bitmap &= ~self.indexToBit(idx);
|
||||
self.bitmap &= ~indexToBit(idx);
|
||||
self.num_free_entries += 1;
|
||||
}
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
|
|||
/// Return: 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;
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,7 @@ pub fn ComptimeBitmap(comptime BitmapType: type) type {
|
|||
/// True if the entry is set, else false.
|
||||
///
|
||||
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,
|
||||
bitmaps: []BitmapType,
|
||||
num_free_entries: usize,
|
||||
allocator: *std.mem.Allocator,
|
||||
allocator: Allocator,
|
||||
|
||||
///
|
||||
/// Create an instance of this bitmap type.
|
||||
|
@ -223,15 +223,15 @@ pub fn Bitmap(comptime BitmapType: type) type {
|
|||
/// Arguments:
|
||||
/// IN num_entries: usize - The number of entries that the bitmap created will have.
|
||||
/// The number of BitmapType required to store this many entries will be allocated and each will be zeroed.
|
||||
/// IN allocator: *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.
|
||||
/// 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.
|
||||
///
|
||||
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 self = Self{
|
||||
.num_bitmaps = num,
|
||||
|
@ -255,10 +255,10 @@ pub fn Bitmap(comptime BitmapType: type) type {
|
|||
/// Return: Self
|
||||
/// 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.
|
||||
///
|
||||
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 i: usize = 0;
|
||||
while (i < copy.num_entries) : (i += 1) {
|
||||
|
@ -294,7 +294,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
|
|||
return BitmapError.OutOfBounds;
|
||||
}
|
||||
if (!try self.isSet(idx)) {
|
||||
const bit = self.indexToBit(idx);
|
||||
const bit = indexToBit(idx);
|
||||
self.bitmaps[idx / ENTRIES_PER_BITMAP] |= bit;
|
||||
self.num_free_entries -= 1;
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
|
|||
return BitmapError.OutOfBounds;
|
||||
}
|
||||
if (try self.isSet(idx)) {
|
||||
const bit = self.indexToBit(idx);
|
||||
const bit = indexToBit(idx);
|
||||
self.bitmaps[idx / ENTRIES_PER_BITMAP] &= ~bit;
|
||||
self.num_free_entries += 1;
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ pub fn Bitmap(comptime BitmapType: type) type {
|
|||
/// Return: 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);
|
||||
}
|
||||
|
||||
|
@ -454,73 +454,73 @@ pub fn Bitmap(comptime BitmapType: type) type {
|
|||
if (idx >= self.num_entries) {
|
||||
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" {
|
||||
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);
|
||||
testing.expectEqual(@as(u32, 1), bmp.bitmap);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 1), bmp.bitmap);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
|
||||
bmp.setEntry(1);
|
||||
testing.expectEqual(@as(u32, 3), bmp.bitmap);
|
||||
testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 3), bmp.bitmap);
|
||||
try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
|
||||
// Repeat setting entry 1 to make sure state doesn't change
|
||||
bmp.setEntry(1);
|
||||
testing.expectEqual(@as(u32, 3), bmp.bitmap);
|
||||
testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 3), bmp.bitmap);
|
||||
try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
}
|
||||
|
||||
test "Comptime clearEntry" {
|
||||
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);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
bmp.setEntry(1);
|
||||
testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 3), bmp.bitmap);
|
||||
try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 3), bmp.bitmap);
|
||||
bmp.clearEntry(0);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 2), bmp.bitmap);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 2), bmp.bitmap);
|
||||
|
||||
// Repeat to make sure state doesn't change
|
||||
bmp.clearEntry(0);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 2), bmp.bitmap);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 2), bmp.bitmap);
|
||||
|
||||
// Try clearing an unset entry to make sure state doesn't change
|
||||
bmp.clearEntry(2);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 2), bmp.bitmap);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 2), bmp.bitmap);
|
||||
}
|
||||
|
||||
test "Comptime setFirstFree" {
|
||||
var bmp = ComptimeBitmap(u32).init();
|
||||
|
||||
// Allocate the first entry
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
|
||||
testing.expectEqual(bmp.bitmap, 1);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
|
||||
try testing.expectEqual(bmp.bitmap, 1);
|
||||
|
||||
// Allocate the second entry
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
|
||||
testing.expectEqual(bmp.bitmap, 3);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
|
||||
try testing.expectEqual(bmp.bitmap, 3);
|
||||
|
||||
// Make all but the MSB occupied and try to allocate it
|
||||
bmp.bitmap = ComptimeBitmap(u32).BITMAP_FULL & ~@as(u32, 1 << (ComptimeBitmap(u32).NUM_ENTRIES - 1));
|
||||
bmp.num_free_entries = 1;
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, ComptimeBitmap(u32).NUM_ENTRIES - 1);
|
||||
testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, ComptimeBitmap(u32).NUM_ENTRIES - 1);
|
||||
try testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL);
|
||||
|
||||
// We should no longer be able to allocate any entries
|
||||
testing.expectEqual(bmp.setFirstFree(), null);
|
||||
testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL);
|
||||
try testing.expectEqual(bmp.setFirstFree(), null);
|
||||
try testing.expectEqual(bmp.bitmap, ComptimeBitmap(u32).BITMAP_FULL);
|
||||
}
|
||||
|
||||
test "Comptime isSet" {
|
||||
|
@ -528,127 +528,127 @@ test "Comptime isSet" {
|
|||
|
||||
bmp.bitmap = 1;
|
||||
// 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;
|
||||
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;
|
||||
testing.expect(bmp.isSet(0));
|
||||
testing.expect(bmp.isSet(1));
|
||||
try testing.expect(bmp.isSet(0));
|
||||
try testing.expect(bmp.isSet(1));
|
||||
i = 2;
|
||||
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;
|
||||
testing.expect(bmp.isSet(0));
|
||||
testing.expect(bmp.isSet(1));
|
||||
testing.expect(!bmp.isSet(2));
|
||||
testing.expect(bmp.isSet(3));
|
||||
try testing.expect(bmp.isSet(0));
|
||||
try testing.expect(bmp.isSet(1));
|
||||
try testing.expect(!bmp.isSet(2));
|
||||
try testing.expect(bmp.isSet(3));
|
||||
i = 4;
|
||||
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" {
|
||||
var bmp = ComptimeBitmap(u8).init();
|
||||
testing.expectEqual(bmp.indexToBit(0), 1);
|
||||
testing.expectEqual(bmp.indexToBit(1), 2);
|
||||
testing.expectEqual(bmp.indexToBit(2), 4);
|
||||
testing.expectEqual(bmp.indexToBit(3), 8);
|
||||
testing.expectEqual(bmp.indexToBit(4), 16);
|
||||
testing.expectEqual(bmp.indexToBit(5), 32);
|
||||
testing.expectEqual(bmp.indexToBit(6), 64);
|
||||
testing.expectEqual(bmp.indexToBit(7), 128);
|
||||
const Type = ComptimeBitmap(u8);
|
||||
try testing.expectEqual(Type.indexToBit(0), 1);
|
||||
try testing.expectEqual(Type.indexToBit(1), 2);
|
||||
try testing.expectEqual(Type.indexToBit(2), 4);
|
||||
try testing.expectEqual(Type.indexToBit(3), 8);
|
||||
try testing.expectEqual(Type.indexToBit(4), 16);
|
||||
try testing.expectEqual(Type.indexToBit(5), 32);
|
||||
try testing.expectEqual(Type.indexToBit(6), 64);
|
||||
try testing.expectEqual(Type.indexToBit(7), 128);
|
||||
}
|
||||
|
||||
test "Comptime setContiguous" {
|
||||
var bmp = ComptimeBitmap(u16).init();
|
||||
// Test trying to set more entries than the bitmap has
|
||||
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, null), null);
|
||||
try testing.expectEqual(bmp.setContiguous(bmp.num_free_entries + 1, 1), null);
|
||||
// All entries should still be free
|
||||
testing.expectEqual(bmp.num_free_entries, 16);
|
||||
testing.expectEqual(bmp.bitmap, 0b0000000000000000);
|
||||
try testing.expectEqual(bmp.num_free_entries, 16);
|
||||
try testing.expectEqual(bmp.bitmap, 0b0000000000000000);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0);
|
||||
testing.expectEqual(bmp.bitmap, 0b0000000000000111);
|
||||
try testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0);
|
||||
try testing.expectEqual(bmp.bitmap, 0b0000000000000111);
|
||||
|
||||
// Test setting from top
|
||||
testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14);
|
||||
testing.expectEqual(bmp.bitmap, 0b1100000000000111);
|
||||
try testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14);
|
||||
try testing.expectEqual(bmp.bitmap, 0b1100000000000111);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(3, 12), null);
|
||||
testing.expectEqual(bmp.bitmap, 0b1100000000000111);
|
||||
try testing.expectEqual(bmp.setContiguous(3, 12), null);
|
||||
try testing.expectEqual(bmp.bitmap, 0b1100000000000111);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3);
|
||||
testing.expectEqual(bmp.bitmap, 0b1100000000111111);
|
||||
try testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3);
|
||||
try testing.expectEqual(bmp.bitmap, 0b1100000000111111);
|
||||
|
||||
// Test setting beyond the what is available
|
||||
testing.expectEqual(bmp.setContiguous(9, null), null);
|
||||
testing.expectEqual(bmp.bitmap, 0b1100000000111111);
|
||||
try testing.expectEqual(bmp.setContiguous(9, null), null);
|
||||
try testing.expectEqual(bmp.bitmap, 0b1100000000111111);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6);
|
||||
testing.expectEqual(bmp.bitmap, 0b1111111111111111);
|
||||
try testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6);
|
||||
try testing.expectEqual(bmp.bitmap, 0b1111111111111111);
|
||||
|
||||
// No more are possible
|
||||
testing.expectEqual(bmp.setContiguous(1, null), null);
|
||||
testing.expectEqual(bmp.bitmap, 0b1111111111111111);
|
||||
try testing.expectEqual(bmp.setContiguous(1, null), null);
|
||||
try testing.expectEqual(bmp.bitmap, 0b1111111111111111);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(1, 0), null);
|
||||
testing.expectEqual(bmp.bitmap, 0b1111111111111111);
|
||||
try testing.expectEqual(bmp.setContiguous(1, 0), null);
|
||||
try testing.expectEqual(bmp.bitmap, 0b1111111111111111);
|
||||
}
|
||||
|
||||
test "setEntry" {
|
||||
var bmp = try Bitmap(u32).init(31, std.testing.allocator);
|
||||
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);
|
||||
testing.expectEqual(@as(u32, 1), bmp.bitmaps[0]);
|
||||
testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 1), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
|
||||
try bmp.setEntry(1);
|
||||
testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
|
||||
testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
|
||||
|
||||
// Repeat setting entry 1 to make sure state doesn't change
|
||||
try bmp.setEntry(1);
|
||||
testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
|
||||
testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
|
||||
|
||||
testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.setEntry(31));
|
||||
testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
|
||||
try testing.expectError(Bitmap(u32).BitmapError.OutOfBounds, bmp.setEntry(31));
|
||||
try testing.expectEqual(@as(u32, 29), bmp.num_free_entries);
|
||||
}
|
||||
|
||||
test "clearEntry" {
|
||||
var bmp = try Bitmap(u32).init(32, std.testing.allocator);
|
||||
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);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try bmp.setEntry(1);
|
||||
testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u32, 30), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 3), bmp.bitmaps[0]);
|
||||
try bmp.clearEntry(0);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
|
||||
|
||||
// Repeat to make sure state doesn't change
|
||||
try bmp.clearEntry(0);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
try testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
|
||||
|
||||
// Try clearing an unset entry to make sure state doesn't change
|
||||
try bmp.clearEntry(2);
|
||||
testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
testing.expectEqual(@as(u32, 2), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u32, 31), bmp.num_free_entries);
|
||||
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" {
|
||||
|
@ -656,19 +656,19 @@ test "setFirstFree multiple bitmaps" {
|
|||
defer bmp.deinit();
|
||||
|
||||
// Allocate the first entry
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
|
||||
testing.expectEqual(bmp.bitmaps[0], 1);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
|
||||
try testing.expectEqual(bmp.bitmaps[0], 1);
|
||||
|
||||
// Allocate the second entry
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
|
||||
testing.expectEqual(bmp.bitmaps[0], 3);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
|
||||
try testing.expectEqual(bmp.bitmaps[0], 3);
|
||||
|
||||
// Allocate the entirety of the first bitmap
|
||||
var entry: u32 = 2;
|
||||
var expected: u8 = 7;
|
||||
while (entry < Bitmap(u8).ENTRIES_PER_BITMAP) {
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, entry);
|
||||
testing.expectEqual(bmp.bitmaps[0], expected);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, entry);
|
||||
try testing.expectEqual(bmp.bitmaps[0], expected);
|
||||
if (entry + 1 < Bitmap(u8).ENTRIES_PER_BITMAP) {
|
||||
entry += 1;
|
||||
expected = expected * 2 + 1;
|
||||
|
@ -678,14 +678,14 @@ test "setFirstFree multiple bitmaps" {
|
|||
}
|
||||
|
||||
// Try allocating an entry in the next bitmap
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u8).ENTRIES_PER_BITMAP);
|
||||
testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL);
|
||||
testing.expectEqual(bmp.bitmaps[1], 1);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, Bitmap(u8).ENTRIES_PER_BITMAP);
|
||||
try testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL);
|
||||
try testing.expectEqual(bmp.bitmaps[1], 1);
|
||||
|
||||
// We should no longer be able to allocate any entries
|
||||
testing.expectEqual(bmp.setFirstFree(), null);
|
||||
testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL);
|
||||
testing.expectEqual(bmp.bitmaps[1], 1);
|
||||
try testing.expectEqual(bmp.setFirstFree(), null);
|
||||
try testing.expectEqual(bmp.bitmaps[0], Bitmap(u8).BITMAP_FULL);
|
||||
try testing.expectEqual(bmp.bitmaps[1], 1);
|
||||
}
|
||||
|
||||
test "setFirstFree" {
|
||||
|
@ -693,21 +693,21 @@ test "setFirstFree" {
|
|||
defer bmp.deinit();
|
||||
|
||||
// Allocate the first entry
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
|
||||
testing.expectEqual(bmp.bitmaps[0], 1);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 0);
|
||||
try testing.expectEqual(bmp.bitmaps[0], 1);
|
||||
|
||||
// Allocate the second entry
|
||||
testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
|
||||
testing.expectEqual(bmp.bitmaps[0], 3);
|
||||
try testing.expectEqual(bmp.setFirstFree() orelse unreachable, 1);
|
||||
try testing.expectEqual(bmp.bitmaps[0], 3);
|
||||
|
||||
// Make all but the MSB occupied and try to allocate it
|
||||
bmp.bitmaps[0] = Bitmap(u32).BITMAP_FULL & ~@as(u32, 1 << (Bitmap(u32).ENTRIES_PER_BITMAP - 1));
|
||||
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.setFirstFree() orelse unreachable, Bitmap(u32).ENTRIES_PER_BITMAP - 1);
|
||||
try testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL);
|
||||
|
||||
// We should no longer be able to allocate any entries
|
||||
testing.expectEqual(bmp.setFirstFree(), null);
|
||||
testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL);
|
||||
try testing.expectEqual(bmp.setFirstFree(), null);
|
||||
try testing.expectEqual(bmp.bitmaps[0], Bitmap(u32).BITMAP_FULL);
|
||||
}
|
||||
|
||||
test "isSet" {
|
||||
|
@ -716,89 +716,90 @@ test "isSet" {
|
|||
|
||||
bmp.bitmaps[0] = 1;
|
||||
// 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;
|
||||
while (i < bmp.num_entries) : (i += 1) {
|
||||
testing.expect(!try bmp.isSet(i));
|
||||
try testing.expect(!try bmp.isSet(i));
|
||||
}
|
||||
|
||||
bmp.bitmaps[0] = 3;
|
||||
testing.expect(try bmp.isSet(0));
|
||||
testing.expect(try bmp.isSet(1));
|
||||
try testing.expect(try bmp.isSet(0));
|
||||
try testing.expect(try bmp.isSet(1));
|
||||
i = 2;
|
||||
while (i < bmp.num_entries) : (i += 1) {
|
||||
testing.expect(!try bmp.isSet(i));
|
||||
try testing.expect(!try bmp.isSet(i));
|
||||
}
|
||||
|
||||
bmp.bitmaps[0] = 11;
|
||||
testing.expect(try bmp.isSet(0));
|
||||
testing.expect(try bmp.isSet(1));
|
||||
testing.expect(!try bmp.isSet(2));
|
||||
testing.expect(try bmp.isSet(3));
|
||||
try testing.expect(try bmp.isSet(0));
|
||||
try testing.expect(try bmp.isSet(1));
|
||||
try testing.expect(!try bmp.isSet(2));
|
||||
try testing.expect(try bmp.isSet(3));
|
||||
i = 4;
|
||||
while (i < 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" {
|
||||
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();
|
||||
testing.expectEqual(bmp.indexToBit(0), 1);
|
||||
testing.expectEqual(bmp.indexToBit(1), 2);
|
||||
testing.expectEqual(bmp.indexToBit(2), 4);
|
||||
testing.expectEqual(bmp.indexToBit(3), 8);
|
||||
testing.expectEqual(bmp.indexToBit(4), 16);
|
||||
testing.expectEqual(bmp.indexToBit(5), 32);
|
||||
testing.expectEqual(bmp.indexToBit(6), 64);
|
||||
testing.expectEqual(bmp.indexToBit(7), 128);
|
||||
testing.expectEqual(bmp.indexToBit(8), 1);
|
||||
testing.expectEqual(bmp.indexToBit(9), 2);
|
||||
try testing.expectEqual(Type.indexToBit(0), 1);
|
||||
try testing.expectEqual(Type.indexToBit(1), 2);
|
||||
try testing.expectEqual(Type.indexToBit(2), 4);
|
||||
try testing.expectEqual(Type.indexToBit(3), 8);
|
||||
try testing.expectEqual(Type.indexToBit(4), 16);
|
||||
try testing.expectEqual(Type.indexToBit(5), 32);
|
||||
try testing.expectEqual(Type.indexToBit(6), 64);
|
||||
try testing.expectEqual(Type.indexToBit(7), 128);
|
||||
try testing.expectEqual(Type.indexToBit(8), 1);
|
||||
try testing.expectEqual(Type.indexToBit(9), 2);
|
||||
}
|
||||
|
||||
fn testCheckBitmaps(bmp: Bitmap(u4), b1: u4, b2: u4, b3: u4, b4: u4) void {
|
||||
testing.expectEqual(@as(u4, b1), bmp.bitmaps[0]);
|
||||
testing.expectEqual(@as(u4, b2), bmp.bitmaps[1]);
|
||||
testing.expectEqual(@as(u4, b3), bmp.bitmaps[2]);
|
||||
testing.expectEqual(@as(u4, b4), bmp.bitmaps[3]);
|
||||
fn testCheckBitmaps(bmp: Bitmap(u4), b1: u4, b2: u4, b3: u4, b4: u4) !void {
|
||||
try testing.expectEqual(@as(u4, b1), bmp.bitmaps[0]);
|
||||
try testing.expectEqual(@as(u4, b2), bmp.bitmaps[1]);
|
||||
try testing.expectEqual(@as(u4, b3), bmp.bitmaps[2]);
|
||||
try testing.expectEqual(@as(u4, b4), bmp.bitmaps[3]);
|
||||
}
|
||||
|
||||
test "setContiguous" {
|
||||
var bmp = try Bitmap(u4).init(16, std.testing.allocator);
|
||||
defer bmp.deinit();
|
||||
// Test trying to set more entries than the bitmap has
|
||||
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, null), null);
|
||||
try testing.expectEqual(bmp.setContiguous(bmp.num_entries + 1, 1), null);
|
||||
// All entries should still be free
|
||||
testing.expectEqual(bmp.num_free_entries, bmp.num_entries);
|
||||
testCheckBitmaps(bmp, 0, 0, 0, 0);
|
||||
try testing.expectEqual(bmp.num_free_entries, bmp.num_entries);
|
||||
try testCheckBitmaps(bmp, 0, 0, 0, 0);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0);
|
||||
testCheckBitmaps(bmp, 0b0111, 0, 0, 0);
|
||||
try testing.expectEqual(bmp.setContiguous(3, 0) orelse unreachable, 0);
|
||||
try testCheckBitmaps(bmp, 0b0111, 0, 0, 0);
|
||||
|
||||
// Test setting from top
|
||||
testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14);
|
||||
testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100);
|
||||
try testing.expectEqual(bmp.setContiguous(2, 14) orelse unreachable, 14);
|
||||
try testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(3, 12), null);
|
||||
testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100);
|
||||
try testing.expectEqual(bmp.setContiguous(3, 12), null);
|
||||
try testCheckBitmaps(bmp, 0b0111, 0, 0, 0b1100);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3);
|
||||
testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100);
|
||||
try testing.expectEqual(bmp.setContiguous(3, null) orelse unreachable, 3);
|
||||
try testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100);
|
||||
|
||||
// Test setting beyond the what is available
|
||||
testing.expectEqual(bmp.setContiguous(9, null), null);
|
||||
testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100);
|
||||
try testing.expectEqual(bmp.setContiguous(9, null), null);
|
||||
try testCheckBitmaps(bmp, 0b1111, 0b0011, 0, 0b1100);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6);
|
||||
testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
|
||||
try testing.expectEqual(bmp.setContiguous(8, null) orelse unreachable, 6);
|
||||
try testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
|
||||
|
||||
// No more are possible
|
||||
testing.expectEqual(bmp.setContiguous(1, null), null);
|
||||
testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
|
||||
try testing.expectEqual(bmp.setContiguous(1, null), null);
|
||||
try testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
|
||||
|
||||
testing.expectEqual(bmp.setContiguous(1, 0), null);
|
||||
testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
|
||||
try testing.expectEqual(bmp.setContiguous(1, 0), null);
|
||||
try testCheckBitmaps(bmp, 0b1111, 0b1111, 0b1111, 0b1111);
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ test "ASCII toCodePage" {
|
|||
var ascii: u8 = 0x20;
|
||||
while (ascii < 0x7F) : (ascii += 1) {
|
||||
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;
|
||||
while (ascii < 0x7F) : (ascii += 1) {
|
||||
const char = CodePage.toWideChar(.CP437, ascii);
|
||||
std.testing.expectEqual(char, ascii);
|
||||
try std.testing.expectEqual(char, ascii);
|
||||
}
|
||||
}
|
||||
|
||||
test "Invalid characters" {
|
||||
const char = '€';
|
||||
std.testing.expectError(CodePage.Error.InvalidChar, CodePage.toCodePage(.CP437, char));
|
||||
try std.testing.expectError(CodePage.Error.InvalidChar, CodePage.toCodePage(.CP437, char));
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Endian = builtin.Endian;
|
||||
const Endian = std.builtin.Endian;
|
||||
const log = std.log.scoped(.elf);
|
||||
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
|
||||
section_data: []?[]const u8,
|
||||
/// The allocator used
|
||||
allocator: *std.mem.Allocator,
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
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.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)]);
|
||||
if (header.magic_number != 0x464C457F) {
|
||||
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)]);
|
||||
}
|
||||
|
||||
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 header_size = if (is_32_bit) 0x34 else 0x40;
|
||||
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,
|
||||
else => unreachable,
|
||||
},
|
||||
.endianness = switch (builtin.arch.endian()) {
|
||||
.endianness = switch (builtin.cpu.arch.endian()) {
|
||||
.Big => .Big,
|
||||
.Little => .Little,
|
||||
},
|
||||
|
@ -491,7 +491,7 @@ pub fn testInitData(allocator: *std.mem.Allocator, section_name: []const u8, str
|
|||
.padding2 = 0,
|
||||
.padding3 = 0,
|
||||
.file_type = file_type,
|
||||
.architecture = switch (builtin.arch) {
|
||||
.architecture = switch (builtin.cpu.arch) {
|
||||
.i386 => .x86,
|
||||
.x86_64 => .AMD_64,
|
||||
else => unreachable,
|
||||
|
@ -563,62 +563,62 @@ test "init" {
|
|||
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);
|
||||
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();
|
||||
|
||||
testing.expectEqual(elf.header.data_size, if (is_32_bit) .ThirtyTwoBit else .SixtyFourBit);
|
||||
testing.expectEqual(elf.header.file_type, .Executable);
|
||||
testing.expectEqual(elf.header.architecture, switch (builtin.arch) {
|
||||
try testing.expectEqual(elf.header.data_size, if (is_32_bit) .ThirtyTwoBit else .SixtyFourBit);
|
||||
try testing.expectEqual(elf.header.file_type, .Executable);
|
||||
try testing.expectEqual(elf.header.architecture, switch (builtin.cpu.arch) {
|
||||
.i386 => .x86,
|
||||
.x86_64 => .AMD_64,
|
||||
else => unreachable,
|
||||
});
|
||||
testing.expectEqual(elf.header.entry_address, 0);
|
||||
testing.expectEqual(elf.header.flags, 0);
|
||||
testing.expectEqual(elf.header.section_name_index, 1);
|
||||
try testing.expectEqual(elf.header.entry_address, 0);
|
||||
try testing.expectEqual(elf.header.flags, 0);
|
||||
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];
|
||||
testing.expectEqual(@as(u32, 0), section_one.name_offset);
|
||||
testing.expectEqual(SectionType.ProgramData, section_one.section_type);
|
||||
testing.expectEqual(@as(usize, 123), section_one.flags);
|
||||
testing.expectEqual(@as(usize, 456), section_one.virtual_address);
|
||||
try testing.expectEqual(@as(u32, 0), section_one.name_offset);
|
||||
try testing.expectEqual(SectionType.ProgramData, section_one.section_type);
|
||||
try testing.expectEqual(@as(usize, 123), section_one.flags);
|
||||
try testing.expectEqual(@as(usize, 456), section_one.virtual_address);
|
||||
|
||||
const section_two = elf.section_headers[1];
|
||||
testing.expectEqual(section_name.len + 1, section_two.name_offset);
|
||||
testing.expectEqual(SectionType.StringTable, section_two.section_type);
|
||||
testing.expectEqual(@as(usize, 789), section_two.flags);
|
||||
testing.expectEqual(@as(usize, 012), section_two.virtual_address);
|
||||
try testing.expectEqual(section_name.len + 1, section_two.name_offset);
|
||||
try testing.expectEqual(SectionType.StringTable, section_two.section_type);
|
||||
try testing.expectEqual(@as(usize, 789), section_two.flags);
|
||||
try testing.expectEqual(@as(usize, 012), section_two.virtual_address);
|
||||
|
||||
testing.expectEqual(@as(usize, 2), elf.section_data.len);
|
||||
testing.expectEqual(elf.section_headers[0].size, elf.section_data[0].?.len);
|
||||
try testing.expectEqual(@as(usize, 2), elf.section_data.len);
|
||||
try testing.expectEqual(elf.section_headers[0].size, elf.section_data[0].?.len);
|
||||
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
|
||||
var section_header = elf.section_headers[1];
|
||||
section_header.section_type = .ProgramData;
|
||||
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);
|
||||
|
||||
// Test the section_name_index being out of bounds
|
||||
var header = elf.header;
|
||||
header.section_name_index = 3;
|
||||
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
|
||||
header = elf.header;
|
||||
header.endianness = switch (builtin.arch.endian()) {
|
||||
header.endianness = switch (builtin.cpu.arch.endian()) {
|
||||
.Big => .Little,
|
||||
.Little => .Big,
|
||||
};
|
||||
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
|
||||
header.data_size = switch (@bitSizeOf(usize)) {
|
||||
|
@ -626,20 +626,20 @@ test "init" {
|
|||
else => .ThirtyTwoBit,
|
||||
};
|
||||
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
|
||||
header.architecture = switch (builtin.arch) {
|
||||
header.architecture = switch (builtin.cpu.arch) {
|
||||
.x86_64 => .Aarch64,
|
||||
else => .AMD_64,
|
||||
};
|
||||
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
|
||||
header.magic_number = 123;
|
||||
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" {
|
||||
|
@ -648,26 +648,23 @@ test "getName" {
|
|||
var string_section_name = "strings";
|
||||
const data = try testInitData(testing.allocator, section_name, string_section_name, .Executable, 0, undefined, undefined, undefined, undefined, undefined);
|
||||
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();
|
||||
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[0].getName(elf), section_name);
|
||||
try testing.expectEqualSlices(u8, elf.section_headers[1].getName(elf), string_section_name);
|
||||
}
|
||||
|
||||
test "toNumBits" {
|
||||
testing.expectEqual(DataSize.ThirtyTwoBit.toNumBits(), 32);
|
||||
testing.expectEqual(DataSize.SixtyFourBit.toNumBits(), 64);
|
||||
try testing.expectEqual(DataSize.ThirtyTwoBit.toNumBits(), 32);
|
||||
try testing.expectEqual(DataSize.SixtyFourBit.toNumBits(), 64);
|
||||
}
|
||||
|
||||
test "toEndian" {
|
||||
testing.expectEqual(Endianness.Little.toEndian(), Endian.Little);
|
||||
testing.expectEqual(Endianness.Big.toEndian(), Endian.Big);
|
||||
try testing.expectEqual(Endianness.Little.toEndian(), Endian.Little);
|
||||
try testing.expectEqual(Endianness.Big.toEndian(), Endian.Big);
|
||||
}
|
||||
|
||||
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| {
|
||||
const architecture = @field(Architecture, field.name);
|
||||
|
||||
|
@ -677,9 +674,9 @@ test "toArch" {
|
|||
};
|
||||
|
||||
if (!is_known) {
|
||||
testing.expectError(Error.UnknownArchitecture, architecture.toArch());
|
||||
try testing.expectError(Error.UnknownArchitecture, architecture.toArch());
|
||||
} else {
|
||||
testing.expectEqual(architecture.toArch(), switch (architecture) {
|
||||
try testing.expectEqual(architecture.toArch(), switch (architecture) {
|
||||
.Sparc => .sparc,
|
||||
.x86 => .i386,
|
||||
.MIPS => .mips,
|
||||
|
@ -696,11 +693,9 @@ test "toArch" {
|
|||
}
|
||||
|
||||
test "hasData" {
|
||||
const no_data = [_]SectionType{ .Unused, .ProgramSpace, .Reserved };
|
||||
|
||||
inline for (@typeInfo(SectionType).Enum.fields) |field| {
|
||||
const sec_type = @field(SectionType, field.name);
|
||||
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
|
@ -1,13 +1,12 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
const is_test = std.builtin.is_test;
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const expectError = std.testing.expectError;
|
||||
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||
const log = std.log.scoped(.initrd);
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.mock_path;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const AutoHashMap = std.AutoHashMap;
|
||||
const vfs = @import("vfs.zig");
|
||||
|
@ -43,7 +42,7 @@ pub const InitrdFS = struct {
|
|||
fs: *vfs.FileSystem,
|
||||
|
||||
/// 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
|
||||
/// allocations.
|
||||
|
@ -67,7 +66,7 @@ pub const InitrdFS = struct {
|
|||
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
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -84,12 +83,19 @@ pub const InitrdFS = struct {
|
|||
|
||||
/// See vfs.FileSystem.write
|
||||
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;
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
var self = @fieldParentPtr(InitrdFS, "instance", fs.instance);
|
||||
// Suppress unused var warning
|
||||
_ = args;
|
||||
_ = dir;
|
||||
switch (flags) {
|
||||
.CREATE_DIR, .CREATE_FILE, .CREATE_SYMLINK => return vfs.Error.InvalidFlags,
|
||||
.NO_CREATION => {
|
||||
|
@ -135,7 +141,7 @@ pub const InitrdFS = struct {
|
|||
///
|
||||
/// Arguments:
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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", .{});
|
||||
defer log.info("Done\n", .{});
|
||||
|
||||
|
@ -237,15 +243,17 @@ pub const InitrdFS = struct {
|
|||
/// three files: test1.txt, test2.txt and test3.txt.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN allocator: *Allocator - The allocator to alloc the raw ramdisk.
|
||||
/// IN allocator: Allocator - The allocator to alloc the raw ramdisk.
|
||||
///
|
||||
/// Return: []u8
|
||||
/// The bytes of the raw ramdisk in memory.
|
||||
///
|
||||
/// Error: Allocator.Error
|
||||
/// 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
|
||||
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" };
|
||||
|
@ -275,8 +283,8 @@ fn createInitrd(allocator: *Allocator) (Allocator.Error || std.io.FixedBufferStr
|
|||
try ramdisk_stream.writer().writeAll(file_contents[i]);
|
||||
}
|
||||
// Make sure we are full
|
||||
expectEqual(try ramdisk_stream.getPos(), total_ramdisk_len);
|
||||
expectEqual(try ramdisk_stream.getPos(), try ramdisk_stream.getEndPos());
|
||||
try expectEqual(try ramdisk_stream.getPos(), total_ramdisk_len);
|
||||
try expectEqual(try ramdisk_stream.getPos(), try ramdisk_stream.getEndPos());
|
||||
return ramdisk_bytes;
|
||||
}
|
||||
|
||||
|
@ -288,24 +296,24 @@ test "init with files valid" {
|
|||
var fs = try InitrdFS.init(&initrd_stream, std.testing.allocator);
|
||||
defer fs.deinit();
|
||||
|
||||
expectEqual(fs.files.len, 3);
|
||||
expectEqualSlices(u8, fs.files[0].name, "test1.txt");
|
||||
expectEqualSlices(u8, fs.files[1].content, "This is a test: part 2");
|
||||
expectEqual(fs.opened_files.count(), 0);
|
||||
try expectEqual(fs.files.len, 3);
|
||||
try expectEqualSlices(u8, fs.files[0].name, "test1.txt");
|
||||
try expectEqualSlices(u8, fs.files[1].content, "This is a test: part 2");
|
||||
try expectEqual(fs.opened_files.count(), 0);
|
||||
}
|
||||
|
||||
test "init with files invalid - invalid number of files" {
|
||||
var ramdisk_bytes = try createInitrd(std.testing.allocator);
|
||||
// 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);
|
||||
|
||||
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
|
||||
std.mem.writeIntSlice(usize, ramdisk_bytes[0..], 0, builtin.endian);
|
||||
expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator));
|
||||
std.mem.writeIntSlice(usize, ramdisk_bytes[0..], 0, builtin.cpu.arch.endian());
|
||||
try expectError(error.InvalidRamDisk, InitrdFS.init(&initrd_stream, std.testing.allocator));
|
||||
}
|
||||
|
||||
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);
|
||||
// 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);
|
||||
|
||||
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);
|
||||
// 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
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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" {
|
||||
|
@ -376,21 +384,21 @@ test "open valid file" {
|
|||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
defer file1.close();
|
||||
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
expectEqualSlices(u8, fs.opened_files.get(@ptrCast(*const vfs.Node, file1)).?.name, "test1.txt");
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
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, .{});
|
||||
defer file3_node.File.close();
|
||||
|
||||
expectEqual(fs.opened_files.count(), 2);
|
||||
expectEqualSlices(u8, fs.opened_files.get(file3_node).?.content, "This is a test: the prequel");
|
||||
try expectEqual(fs.opened_files.count(), 2);
|
||||
try expectEqualSlices(u8, fs.opened_files.get(file3_node).?.content, "This is a test: the prequel");
|
||||
|
||||
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;
|
||||
defer file2.close();
|
||||
|
||||
expectEqual(fs.opened_files.count(), 3);
|
||||
try expectEqual(fs.opened_files.count(), 3);
|
||||
}
|
||||
|
||||
test "open fail with invalid flags" {
|
||||
|
@ -403,21 +411,21 @@ test "open fail with invalid flags" {
|
|||
|
||||
try vfs.setRoot(fs.root_node);
|
||||
|
||||
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_DIR));
|
||||
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_FILE));
|
||||
expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_SYMLINK));
|
||||
expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_DIR));
|
||||
expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_FILE));
|
||||
expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_SYMLINK));
|
||||
expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_DIR));
|
||||
expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_FILE));
|
||||
expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_SYMLINK));
|
||||
expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_DIR));
|
||||
expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_FILE));
|
||||
expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_SYMLINK));
|
||||
expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_FILE));
|
||||
expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_DIR));
|
||||
expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_SYMLINK));
|
||||
try expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_DIR));
|
||||
try expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_FILE));
|
||||
try expectError(error.InvalidFlags, vfs.openFile("/text10.txt", .CREATE_SYMLINK));
|
||||
try expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_DIR));
|
||||
try expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_FILE));
|
||||
try expectError(error.InvalidFlags, vfs.openDir("/text10.txt", .CREATE_SYMLINK));
|
||||
try expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_DIR));
|
||||
try expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_FILE));
|
||||
try expectError(error.InvalidFlags, vfs.openFile("/test/", .CREATE_SYMLINK));
|
||||
try expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_DIR));
|
||||
try expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_FILE));
|
||||
try expectError(error.InvalidFlags, vfs.openDir("/test/", .CREATE_SYMLINK));
|
||||
try expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_FILE));
|
||||
try expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_DIR));
|
||||
try expectError(error.InvalidFlags, vfs.openSymlink("/test/", "", .CREATE_SYMLINK));
|
||||
}
|
||||
|
||||
test "open fail with NoSuchFileOrDir" {
|
||||
|
@ -429,8 +437,8 @@ test "open fail with NoSuchFileOrDir" {
|
|||
defer fs.deinit();
|
||||
|
||||
try vfs.setRoot(fs.root_node);
|
||||
expectError(error.NoSuchFileOrDir, vfs.openFile("/text10.txt", .NO_CREATION));
|
||||
expectError(error.NoSuchFileOrDir, vfs.openDir("/temp/", .NO_CREATION));
|
||||
try expectError(error.NoSuchFileOrDir, vfs.openFile("/text10.txt", .NO_CREATION));
|
||||
try expectError(error.NoSuchFileOrDir, vfs.openDir("/temp/", .NO_CREATION));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
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" {
|
||||
|
@ -464,14 +472,14 @@ test "open two of the same file" {
|
|||
const file2 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
defer file2.close();
|
||||
|
||||
expectEqual(fs.opened_files.count(), 2);
|
||||
expect(file1 != file2);
|
||||
try expectEqual(fs.opened_files.count(), 2);
|
||||
try expect(file1 != file2);
|
||||
|
||||
var b1: [128]u8 = undefined;
|
||||
const length1 = try file1.read(b1[0..b1.len]);
|
||||
var b2: [128]u8 = undefined;
|
||||
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" {
|
||||
|
@ -486,24 +494,22 @@ test "close a file" {
|
|||
|
||||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
|
||||
var file1_node = @ptrCast(*const vfs.Node, file1);
|
||||
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
|
||||
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();
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
|
||||
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;
|
||||
defer file2.close();
|
||||
|
||||
expectEqual(fs.opened_files.count(), 2);
|
||||
try expectEqual(fs.opened_files.count(), 2);
|
||||
file3_node.File.close();
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
}
|
||||
|
||||
test "close a non-opened file" {
|
||||
|
@ -521,7 +527,7 @@ test "close a non-opened file" {
|
|||
defer file1.close();
|
||||
|
||||
// Only one file open
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
|
||||
// Craft a 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();
|
||||
|
||||
// Still only one file open
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
}
|
||||
|
||||
test "read a file" {
|
||||
|
@ -549,12 +555,12 @@ test "read a file" {
|
|||
var bytes1: [128]u8 = undefined;
|
||||
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;
|
||||
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" {
|
||||
|
@ -572,7 +578,7 @@ test "read a file, invalid/not opened/crafted *const Node" {
|
|||
defer file1.close();
|
||||
|
||||
// Only one file open
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
|
||||
// Craft a 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 } };
|
||||
|
||||
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
|
||||
expectEqual(fs.opened_files.count(), 1);
|
||||
try expectEqual(fs.opened_files.count(), 1);
|
||||
}
|
||||
|
||||
test "write does nothing" {
|
||||
|
@ -600,10 +606,10 @@ test "write does nothing" {
|
|||
var file1 = try vfs.openFile("/test1.txt", .NO_CREATION);
|
||||
defer file1.close();
|
||||
|
||||
expectEqual(@as(usize, 0), try file1.write("Blah"));
|
||||
try expectEqual(@as(usize, 0), try file1.write("Blah"));
|
||||
|
||||
// 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.
|
||||
|
@ -622,10 +628,7 @@ fn expectEqualSlicesClone(comptime T: type, expected: []const T, actual: []const
|
|||
///
|
||||
/// Test that we can open, read and close a file
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN allocator: *Allocator - The allocator used for reading.
|
||||
///
|
||||
fn rt_openReadClose(allocator: *Allocator) void {
|
||||
fn rt_openReadClose() void {
|
||||
const f1 = vfs.openFile("/ramdisk_test1.txt", .NO_CREATION) catch |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| {
|
||||
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) {
|
||||
panic(@errorReturnTrace(), "FAILURE: Didn't close all files\n", .{});
|
||||
}
|
||||
|
|
|
@ -319,7 +319,7 @@ fn traversePath(path: []const u8, follow_symlinks: bool, flags: OpenFlags, args:
|
|||
|
||||
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
|
||||
const seg = split.next() orelse unreachable;
|
||||
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
|
||||
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
|
||||
const result = try TraversalParent.func(&split, root, follow_symlinks, .NO_CREATION);
|
||||
|
||||
|
@ -569,7 +569,7 @@ const TestFS = struct {
|
|||
data: ?[]u8,
|
||||
children: *ArrayList(*@This()),
|
||||
|
||||
fn deinit(self: *@This(), allocator: *Allocator) void {
|
||||
fn deinit(self: *@This(), allocator: Allocator) void {
|
||||
allocator.destroy(self.val);
|
||||
allocator.free(self.name);
|
||||
if (self.data) |d| {
|
||||
|
@ -586,7 +586,7 @@ const TestFS = struct {
|
|||
|
||||
tree: TreeNode,
|
||||
fs: *FileSystem,
|
||||
allocator: *Allocator,
|
||||
allocator: Allocator,
|
||||
open_count: usize,
|
||||
instance: usize,
|
||||
|
||||
|
@ -635,6 +635,8 @@ const TestFS = struct {
|
|||
}
|
||||
|
||||
fn close(fs: *const FileSystem, node: *const Node) void {
|
||||
// Suppress unused var warning
|
||||
_ = node;
|
||||
var test_fs = @fieldParentPtr(TestFS, "instance", fs.instance);
|
||||
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);
|
||||
var testfs = try allocator.create(TestFS);
|
||||
var root_node = try allocator.create(Node);
|
||||
|
@ -754,7 +756,7 @@ test "mount" {
|
|||
var testfs = try testInitFs(allocator);
|
||||
defer allocator.destroy(testfs);
|
||||
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;
|
||||
root = testfs.tree.val;
|
||||
|
@ -763,7 +765,7 @@ test "mount" {
|
|||
var testfs2 = try testInitFs(allocator);
|
||||
defer allocator.destroy(testfs2);
|
||||
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;
|
||||
// Create the dir to mount to
|
||||
|
@ -771,21 +773,21 @@ test "mount" {
|
|||
defer dir.close();
|
||||
try mount(dir, testfs2.fs);
|
||||
defer umount(dir);
|
||||
testing.expectError(MountError.DirAlreadyMounted, mount(dir, testfs2.fs));
|
||||
try testing.expectError(MountError.DirAlreadyMounted, mount(dir, testfs2.fs));
|
||||
|
||||
// Ensure the mount worked
|
||||
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), testfs2.fs.getRootNode(testfs2.fs));
|
||||
try testing.expectEqual((dir.mount orelse unreachable).fs, testfs2.fs);
|
||||
// Create a file within the mounted directory
|
||||
var test_file = try openFile("/mnt/123.txt", .CREATE_FILE);
|
||||
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
|
||||
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, 1), testfs.tree.children.items.len);
|
||||
try testing.expectEqual(@as(usize, 0), testfs.tree.children.items[0].children.items.len);
|
||||
// It should be in the mounted fs
|
||||
testing.expectEqual(@as(usize, 1), testfs2.tree.children.items.len);
|
||||
testing.expectEqual(test_file, &testfs2.tree.children.items[0].val.File);
|
||||
try testing.expectEqual(@as(usize, 1), testfs2.tree.children.items.len);
|
||||
try testing.expectEqual(test_file, &testfs2.tree.children.items[0].val.File);
|
||||
}
|
||||
|
||||
test "traversePath" {
|
||||
|
@ -797,11 +799,11 @@ test "traversePath" {
|
|||
|
||||
// Get the root
|
||||
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
|
||||
var child1 = try test_root.Dir.open("child1.txt", .CREATE_FILE, .{});
|
||||
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
|
||||
child1.File.close();
|
||||
child1_traversed.File.close();
|
||||
|
@ -809,12 +811,12 @@ test "traversePath" {
|
|||
// Same but with a directory
|
||||
var child2 = try test_root.Dir.open("child2", .CREATE_DIR, .{});
|
||||
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
|
||||
var child3 = try child2.Dir.open("child3.txt", .CREATE_FILE, .{});
|
||||
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
|
||||
child2.Dir.close();
|
||||
child2_traversed.Dir.close();
|
||||
|
@ -823,38 +825,38 @@ test "traversePath" {
|
|||
// Create and open a symlink
|
||||
var child4 = try traversePath("/child2/link", false, .CREATE_SYMLINK, .{ .symlink_target = "/child2/child3.txt" });
|
||||
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_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();
|
||||
child4.Symlink.close();
|
||||
child5.Symlink.close();
|
||||
child4_linked.File.close();
|
||||
child5_linked.File.close();
|
||||
|
||||
testing.expectError(Error.NotAbsolutePath, traversePath("abc", false, .NO_CREATION, .{}));
|
||||
testing.expectError(Error.NotAbsolutePath, traversePath("", false, .NO_CREATION, .{}));
|
||||
testing.expectError(Error.NotAbsolutePath, traversePath("a/", false, .NO_CREATION, .{}));
|
||||
testing.expectError(Error.NoSuchFileOrDir, traversePath("/notadir/abc.txt", false, .NO_CREATION, .{}));
|
||||
testing.expectError(Error.NoSuchFileOrDir, traversePath("/ ", false, .NO_CREATION, .{}));
|
||||
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.NotAbsolutePath, traversePath("abc", false, .NO_CREATION, .{}));
|
||||
try testing.expectError(Error.NotAbsolutePath, traversePath("", false, .NO_CREATION, .{}));
|
||||
try testing.expectError(Error.NotAbsolutePath, traversePath("a/", false, .NO_CREATION, .{}));
|
||||
try testing.expectError(Error.NoSuchFileOrDir, traversePath("/notadir/abc.txt", false, .NO_CREATION, .{}));
|
||||
try testing.expectError(Error.NoSuchFileOrDir, traversePath("/ ", false, .NO_CREATION, .{}));
|
||||
try testing.expectError(Error.NotADirectory, traversePath("/child1.txt/abc.txt", false, .NO_CREATION, .{}));
|
||||
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
|
||||
testing.expectEqual(testfs.open_count, 0);
|
||||
try testing.expectEqual(testfs.open_count, 0);
|
||||
}
|
||||
|
||||
test "isAbsolute" {
|
||||
testing.expect(isAbsolute("/"));
|
||||
testing.expect(isAbsolute("/abc"));
|
||||
testing.expect(isAbsolute("/abc/def"));
|
||||
testing.expect(isAbsolute("/ a bc/de f"));
|
||||
testing.expect(isAbsolute("//"));
|
||||
testing.expect(!isAbsolute(" /"));
|
||||
testing.expect(!isAbsolute(""));
|
||||
testing.expect(!isAbsolute("abc"));
|
||||
testing.expect(!isAbsolute("abc/def"));
|
||||
try testing.expect(isAbsolute("/"));
|
||||
try testing.expect(isAbsolute("/abc"));
|
||||
try testing.expect(isAbsolute("/abc/def"));
|
||||
try testing.expect(isAbsolute("/ a bc/de f"));
|
||||
try testing.expect(isAbsolute("//"));
|
||||
try testing.expect(!isAbsolute(" /"));
|
||||
try testing.expect(!isAbsolute(""));
|
||||
try testing.expect(!isAbsolute("abc"));
|
||||
try testing.expect(!isAbsolute("abc/def"));
|
||||
}
|
||||
|
||||
test "isDir" {
|
||||
|
@ -862,9 +864,9 @@ test "isDir" {
|
|||
const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } };
|
||||
const file = Node{ .File = .{ .fs = &fs } };
|
||||
const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } };
|
||||
testing.expect(!symlink.isDir());
|
||||
testing.expect(!file.isDir());
|
||||
testing.expect(dir.isDir());
|
||||
try testing.expect(!symlink.isDir());
|
||||
try testing.expect(!file.isDir());
|
||||
try testing.expect(dir.isDir());
|
||||
}
|
||||
|
||||
test "isFile" {
|
||||
|
@ -872,9 +874,9 @@ test "isFile" {
|
|||
const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } };
|
||||
const file = Node{ .File = .{ .fs = &fs } };
|
||||
const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } };
|
||||
testing.expect(!dir.isFile());
|
||||
testing.expect(!symlink.isFile());
|
||||
testing.expect(file.isFile());
|
||||
try testing.expect(!dir.isFile());
|
||||
try testing.expect(!symlink.isFile());
|
||||
try testing.expect(file.isFile());
|
||||
}
|
||||
|
||||
test "isSymlink" {
|
||||
|
@ -882,9 +884,9 @@ test "isSymlink" {
|
|||
const dir = Node{ .Dir = .{ .fs = &fs, .mount = null } };
|
||||
const file = Node{ .File = .{ .fs = &fs } };
|
||||
const symlink = Node{ .Symlink = .{ .fs = &fs, .path = "" } };
|
||||
testing.expect(!dir.isSymlink());
|
||||
testing.expect(!file.isSymlink());
|
||||
testing.expect(symlink.isSymlink());
|
||||
try testing.expect(!dir.isSymlink());
|
||||
try testing.expect(!file.isSymlink());
|
||||
try testing.expect(symlink.isSymlink());
|
||||
}
|
||||
|
||||
test "open" {
|
||||
|
@ -895,46 +897,46 @@ test "open" {
|
|||
|
||||
// Creating a 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];
|
||||
testing.expect(tree.val.isFile());
|
||||
testing.expectEqual(test_node, &tree.val.File);
|
||||
testing.expect(std.mem.eql(u8, tree.name, "abc.txt"));
|
||||
testing.expectEqual(tree.data, null);
|
||||
testing.expectEqual(tree.children.items.len, 0);
|
||||
try testing.expect(tree.val.isFile());
|
||||
try testing.expectEqual(test_node, &tree.val.File);
|
||||
try testing.expect(std.mem.eql(u8, tree.name, "abc.txt"));
|
||||
try testing.expectEqual(tree.data, null);
|
||||
try testing.expectEqual(tree.children.items.len, 0);
|
||||
|
||||
// Creating a 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];
|
||||
testing.expect(tree.val.isDir());
|
||||
testing.expectEqual(test_dir, &tree.val.Dir);
|
||||
testing.expect(std.mem.eql(u8, tree.name, "def"));
|
||||
testing.expectEqual(tree.data, null);
|
||||
testing.expectEqual(tree.children.items.len, 0);
|
||||
try testing.expect(tree.val.isDir());
|
||||
try testing.expectEqual(test_dir, &tree.val.Dir);
|
||||
try testing.expect(std.mem.eql(u8, tree.name, "def"));
|
||||
try testing.expectEqual(tree.data, null);
|
||||
try testing.expectEqual(tree.children.items.len, 0);
|
||||
|
||||
// Creating a file under a new dir
|
||||
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];
|
||||
testing.expect(tree.val.isFile());
|
||||
testing.expectEqual(test_node, &tree.val.File);
|
||||
testing.expect(std.mem.eql(u8, tree.name, "ghi.zig"));
|
||||
testing.expectEqual(tree.data, null);
|
||||
testing.expectEqual(tree.children.items.len, 0);
|
||||
try testing.expect(tree.val.isFile());
|
||||
try testing.expectEqual(test_node, &tree.val.File);
|
||||
try testing.expect(std.mem.eql(u8, tree.name, "ghi.zig"));
|
||||
try testing.expectEqual(tree.data, null);
|
||||
try testing.expectEqual(tree.children.items.len, 0);
|
||||
|
||||
testing.expectError(Error.NoSuchFileOrDir, openDir("/jkl", .NO_CREATION));
|
||||
testing.expectError(Error.NoSuchFileOrDir, openFile("/mno.txt", .NO_CREATION));
|
||||
testing.expectError(Error.NoSuchFileOrDir, openFile("/def/pqr.txt", .NO_CREATION));
|
||||
testing.expectError(Error.NoSuchFileOrDir, openDir("/mno/stu", .NO_CREATION));
|
||||
testing.expectError(Error.NoSuchFileOrDir, openFile("/mno/stu.txt", .NO_CREATION));
|
||||
testing.expectError(Error.NotADirectory, openFile("/abc.txt/vxy.md", .NO_CREATION));
|
||||
testing.expectError(Error.IsADirectory, openFile("/def", .NO_CREATION));
|
||||
testing.expectError(Error.InvalidFlags, openFile("/abc.txt", .CREATE_DIR));
|
||||
testing.expectError(Error.InvalidFlags, openDir("/abc.txt", .CREATE_FILE));
|
||||
testing.expectError(Error.NotAbsolutePath, open("", false, .NO_CREATION, .{}));
|
||||
testing.expectError(Error.NotAbsolutePath, open("abc", false, .NO_CREATION, .{}));
|
||||
testing.expectError(Error.NoSymlinkTarget, open("/abc", false, .CREATE_SYMLINK, .{}));
|
||||
try testing.expectError(Error.NoSuchFileOrDir, openDir("/jkl", .NO_CREATION));
|
||||
try testing.expectError(Error.NoSuchFileOrDir, openFile("/mno.txt", .NO_CREATION));
|
||||
try testing.expectError(Error.NoSuchFileOrDir, openFile("/def/pqr.txt", .NO_CREATION));
|
||||
try testing.expectError(Error.NoSuchFileOrDir, openDir("/mno/stu", .NO_CREATION));
|
||||
try testing.expectError(Error.NoSuchFileOrDir, openFile("/mno/stu.txt", .NO_CREATION));
|
||||
try testing.expectError(Error.NotADirectory, openFile("/abc.txt/vxy.md", .NO_CREATION));
|
||||
try testing.expectError(Error.IsADirectory, openFile("/def", .NO_CREATION));
|
||||
try testing.expectError(Error.InvalidFlags, openFile("/abc.txt", .CREATE_DIR));
|
||||
try testing.expectError(Error.InvalidFlags, openDir("/abc.txt", .CREATE_FILE));
|
||||
try testing.expectError(Error.NotAbsolutePath, open("", false, .NO_CREATION, .{}));
|
||||
try testing.expectError(Error.NotAbsolutePath, open("abc", false, .NO_CREATION, .{}));
|
||||
try testing.expectError(Error.NoSymlinkTarget, open("/abc", false, .CREATE_SYMLINK, .{}));
|
||||
}
|
||||
|
||||
test "read" {
|
||||
|
@ -946,40 +948,40 @@ test "read" {
|
|||
var test_file = try openFile("/foo.txt", .CREATE_FILE);
|
||||
var f_data = &testfs.tree.children.items[0].data;
|
||||
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;
|
||||
{
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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
|
||||
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);
|
||||
{
|
||||
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 f_data = &testfs.tree.children.items[0].data;
|
||||
testing.expectEqual(f_data.*, null);
|
||||
try testing.expectEqual(f_data.*, null);
|
||||
|
||||
var str = "test123";
|
||||
const length = try test_file.write(str);
|
||||
testing.expect(std.mem.eql(u8, str, f_data.* orelse unreachable));
|
||||
testing.expect(length == str.len);
|
||||
try testing.expect(std.mem.eql(u8, str, f_data.* orelse unreachable));
|
||||
try testing.expect(length == str.len);
|
||||
|
||||
// Try writing to a symlink
|
||||
var test_link = try openSymlink("/link", "/foo.txt", .CREATE_SYMLINK);
|
||||
testing.expectEqual(test_link, "/foo.txt");
|
||||
var link_file = try openFile("/link", .NO_CREATION);
|
||||
try testing.expectEqual(test_link, "/foo.txt");
|
||||
_ = try openFile("/link", .NO_CREATION);
|
||||
|
||||
var str2 = "test456";
|
||||
const length2 = try test_file.write(str2);
|
||||
testing.expect(std.mem.eql(u8, str2, f_data.* orelse unreachable));
|
||||
_ = try test_file.write(str2);
|
||||
try testing.expect(std.mem.eql(u8, str2, f_data.* orelse unreachable));
|
||||
}
|
||||
|
|
|
@ -2,10 +2,9 @@ const std = @import("std");
|
|||
const Allocator = std.mem.Allocator;
|
||||
const testing = std.testing;
|
||||
const log = std.log.scoped(.heap);
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
const is_test = builtin.is_test;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.mock_path;
|
||||
const vmm = @import("vmm.zig");
|
||||
const panic = @import("panic.zig").panic;
|
||||
|
||||
|
@ -15,7 +14,7 @@ pub const FreeListAllocator = struct {
|
|||
size: usize,
|
||||
next_free: ?*Header,
|
||||
|
||||
const Self = @Self();
|
||||
const Self = @This();
|
||||
|
||||
///
|
||||
/// Initialise the header for a free allocation node
|
||||
|
@ -33,9 +32,9 @@ pub const FreeListAllocator = struct {
|
|||
};
|
||||
}
|
||||
};
|
||||
const Self = @This();
|
||||
|
||||
first_free: ?*Header,
|
||||
allocator: Allocator,
|
||||
|
||||
///
|
||||
/// Initialise an empty and free FreeListAllocator
|
||||
|
@ -54,13 +53,13 @@ pub const FreeListAllocator = struct {
|
|||
if (size <= @sizeOf(Header)) return Error.TooSmall;
|
||||
return FreeListAllocator{
|
||||
.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
|
||||
///
|
||||
|
@ -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 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| {
|
||||
p.next_free = header;
|
||||
} else {
|
||||
|
@ -100,8 +99,12 @@ pub const FreeListAllocator = struct {
|
|||
/// Arguments:
|
||||
/// IN self: *FreeListAllocator - The allocator being freed within
|
||||
/// 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 addr = @ptrToInt(mem.ptr);
|
||||
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.
|
||||
///
|
||||
/// 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_align: u29 - The original alignment for old_mem.
|
||||
/// IN new_size: usize - What to resize to.
|
||||
/// 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
|
||||
///
|
||||
/// Return: usize
|
||||
/// The new size of the buffer, which will be new_size if the operation was successful.
|
||||
/// Return: ?usize
|
||||
/// 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
|
||||
/// std.Allocator.Error.OutOfMemory - If there wasn't enough free memory to expand into
|
||||
///
|
||||
fn resize(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, size_alignment: u29, ret_addr: usize) Allocator.Error!usize {
|
||||
var self = @fieldParentPtr(FreeListAllocator, "allocator", allocator);
|
||||
fn resize(self: *Self, old_mem: []u8, old_align: u29, new_size: usize, size_alignment: u29, ret_addr: usize) ?usize {
|
||||
// Suppress unused var warning
|
||||
_ = old_align;
|
||||
_ = ret_addr;
|
||||
if (new_size == 0) {
|
||||
self.free(old_mem);
|
||||
self.free(old_mem, old_align, ret_addr);
|
||||
return 0;
|
||||
}
|
||||
if (new_size == old_mem.len) return new_size;
|
||||
|
@ -227,12 +229,12 @@ pub const FreeListAllocator = struct {
|
|||
if (real_size > old_mem.len) {
|
||||
if (next) |n| {
|
||||
// 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 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 (!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;
|
||||
// We don't do any splitting when consuming the whole neighbour
|
||||
if (!consumes_whole_neighbour) {
|
||||
|
@ -244,7 +246,7 @@ pub const FreeListAllocator = struct {
|
|||
return real_size;
|
||||
}
|
||||
// The neighbour isn't free so we can't expand into it
|
||||
return Allocator.Error.OutOfMemory;
|
||||
return null;
|
||||
} else {
|
||||
// Shrinking
|
||||
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
|
||||
///
|
||||
/// 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 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
|
||||
|
@ -315,8 +317,9 @@ pub const FreeListAllocator = struct {
|
|||
/// Error: std.Allocator.Error
|
||||
/// 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 {
|
||||
var self = @fieldParentPtr(FreeListAllocator, "allocator", allocator);
|
||||
pub fn alloc(self: *Self, size: usize, alignment: u29, size_alignment: u29, ret_addr: usize) Allocator.Error![]u8 {
|
||||
// Suppress unused var warning
|
||||
_ = ret_addr;
|
||||
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)
|
||||
|
@ -420,11 +423,11 @@ pub const FreeListAllocator = struct {
|
|||
var free_list = &(try FreeListAllocator.init(@ptrToInt(region.ptr), size));
|
||||
|
||||
var header = @intToPtr(*FreeListAllocator.Header, @ptrToInt(region.ptr));
|
||||
testing.expectEqual(header, free_list.first_free.?);
|
||||
testing.expectEqual(header.next_free, null);
|
||||
testing.expectEqual(header.size, size - @sizeOf(Header));
|
||||
try testing.expectEqual(header, free_list.first_free.?);
|
||||
try testing.expectEqual(header.next_free, null);
|
||||
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" {
|
||||
|
@ -433,79 +436,77 @@ pub const FreeListAllocator = struct {
|
|||
defer testing.allocator.free(region);
|
||||
const start = @ptrToInt(region.ptr);
|
||||
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);
|
||||
// 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
|
||||
var header = @intToPtr(*Header, start + 64);
|
||||
testing.expectEqual(header.size, size - 64 - @sizeOf(Header));
|
||||
testing.expectEqual(header.next_free, null);
|
||||
testing.expectEqual(free_list.first_free, header);
|
||||
try testing.expectEqual(header.size, size - 64 - @sizeOf(Header));
|
||||
try testing.expectEqual(header.next_free, null);
|
||||
try testing.expectEqual(free_list.first_free, header);
|
||||
|
||||
std.debug.warn("", .{});
|
||||
std.debug.print("", .{});
|
||||
|
||||
// 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_end = alloc1_addr + alloc1.len;
|
||||
// Should be to the right of the first allocation, with some alignment padding in between
|
||||
const alloc0_end = alloc0_addr + alloc0.len;
|
||||
testing.expect(alloc0_end <= alloc1_addr);
|
||||
testing.expectEqual(std.mem.alignForward(alloc0_end, 4), alloc1_addr);
|
||||
try testing.expect(alloc0_end <= alloc1_addr);
|
||||
try testing.expectEqual(std.mem.alignForward(alloc0_end, 4), alloc1_addr);
|
||||
// It should have produced a node on the right
|
||||
header = @intToPtr(*Header, alloc1_end);
|
||||
testing.expectEqual(header.size, size - (alloc1_end - start) - @sizeOf(Header));
|
||||
testing.expectEqual(header.next_free, null);
|
||||
testing.expectEqual(free_list.first_free, header);
|
||||
try testing.expectEqual(header.size, size - (alloc1_end - start) - @sizeOf(Header));
|
||||
try testing.expectEqual(header.next_free, null);
|
||||
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_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
|
||||
const second_header = @intToPtr(*Header, alloc2_end);
|
||||
testing.expectEqual(second_header.size, size - (alloc2_end - start) - @sizeOf(Header));
|
||||
testing.expectEqual(second_header.next_free, null);
|
||||
try testing.expectEqual(second_header.size, size - (alloc2_end - start) - @sizeOf(Header));
|
||||
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)
|
||||
if (alloc2_addr - alloc1_end >= @sizeOf(Header)) {
|
||||
header = @intToPtr(*Header, alloc1_end);
|
||||
testing.expectEqual(free_list.first_free, header);
|
||||
testing.expectEqual(header.next_free, second_header);
|
||||
try testing.expectEqual(free_list.first_free, header);
|
||||
try testing.expectEqual(header.next_free, second_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_end = alloc3_addr + @sizeOf(Header);
|
||||
const header2 = @intToPtr(*Header, alloc3_end);
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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_end = alloc4_addr + std.mem.alignForward(13, @alignOf(Header));
|
||||
const header3 = @intToPtr(*Header, alloc4_end);
|
||||
const header4 = @intToPtr(*Header, alloc4_addr);
|
||||
|
||||
// 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)
|
||||
testing.expectEqual(alloc4_end - alloc4_addr, 16);
|
||||
try testing.expectEqual(alloc4_end - alloc4_addr, 16);
|
||||
|
||||
// Previous header should now point to the next header
|
||||
testing.expectEqual(header2.next_free, header3);
|
||||
try testing.expectEqual(header2.next_free, header3);
|
||||
}
|
||||
|
||||
test "free" {
|
||||
|
@ -514,74 +515,72 @@ pub const FreeListAllocator = struct {
|
|||
defer testing.allocator.free(region);
|
||||
const start = @ptrToInt(region.ptr);
|
||||
var free_list = &(try FreeListAllocator.init(start, size));
|
||||
var allocator = &free_list.allocator;
|
||||
|
||||
var alloc0 = try alloc(allocator, 128, 0, 0, @returnAddress());
|
||||
var alloc1 = try alloc(allocator, 256, 0, 0, @returnAddress());
|
||||
var alloc2 = try alloc(allocator, 64, 0, 0, @returnAddress());
|
||||
var alloc0 = try free_list.alloc(128, 0, 0, @returnAddress());
|
||||
var alloc1 = try free_list.alloc(256, 0, 0, @returnAddress());
|
||||
var alloc2 = try free_list.alloc(64, 0, 0, @returnAddress());
|
||||
|
||||
// There should be a single free node after alloc2
|
||||
const free_node3 = @intToPtr(*Header, @ptrToInt(alloc2.ptr) + alloc2.len);
|
||||
testing.expectEqual(free_list.first_free, free_node3);
|
||||
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_list.first_free, free_node3);
|
||||
try testing.expectEqual(free_node3.size, size - alloc0.len - alloc1.len - alloc2.len - @sizeOf(Header));
|
||||
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
|
||||
const free_node0 = @intToPtr(*Header, start);
|
||||
testing.expectEqual(free_list.first_free, free_node0);
|
||||
testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header));
|
||||
testing.expectEqual(free_node0.next_free, free_node3);
|
||||
try testing.expectEqual(free_list.first_free, free_node0);
|
||||
try testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header));
|
||||
try testing.expectEqual(free_node0.next_free, free_node3);
|
||||
|
||||
// Freeing alloc1 should join it with free_node0
|
||||
free_list.free(alloc1);
|
||||
testing.expectEqual(free_list.first_free, free_node0);
|
||||
testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header) + alloc1.len);
|
||||
testing.expectEqual(free_node0.next_free, free_node3);
|
||||
free_list.free(alloc1, 0, 0);
|
||||
try testing.expectEqual(free_list.first_free, free_node0);
|
||||
try testing.expectEqual(free_node0.size, alloc0.len - @sizeOf(Header) + alloc1.len);
|
||||
try testing.expectEqual(free_node0.next_free, free_node3);
|
||||
|
||||
// Freeing alloc2 should then join them all together into one big free node
|
||||
free_list.free(alloc2);
|
||||
testing.expectEqual(free_list.first_free, free_node0);
|
||||
testing.expectEqual(free_node0.size, size - @sizeOf(Header));
|
||||
testing.expectEqual(free_node0.next_free, null);
|
||||
free_list.free(alloc2, 0, 0);
|
||||
try testing.expectEqual(free_list.first_free, free_node0);
|
||||
try testing.expectEqual(free_node0.size, size - @sizeOf(Header));
|
||||
try testing.expectEqual(free_node0.next_free, null);
|
||||
}
|
||||
|
||||
test "resize" {
|
||||
std.debug.warn("", .{});
|
||||
std.debug.print("", .{});
|
||||
const size = 1024;
|
||||
var region = try testing.allocator.alloc(u8, size);
|
||||
defer testing.allocator.free(region);
|
||||
const start = @ptrToInt(region.ptr);
|
||||
var free_list = &(try FreeListAllocator.init(start, size));
|
||||
var allocator = &free_list.allocator;
|
||||
|
||||
var alloc0 = try alloc(allocator, 128, 0, 0, @returnAddress());
|
||||
var alloc1 = try alloc(allocator, 256, 0, 0, @returnAddress());
|
||||
var alloc0 = try free_list.alloc(128, 0, 0, @returnAddress());
|
||||
var alloc1 = try free_list.alloc(256, 0, 0, @returnAddress());
|
||||
|
||||
// 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
|
||||
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];
|
||||
// And there should be a free node on the right of it
|
||||
var header = @intToPtr(*Header, @ptrToInt(alloc1.ptr) + 512);
|
||||
testing.expectEqual(header.size, size - 128 - 512 - @sizeOf(Header));
|
||||
testing.expectEqual(header.next_free, null);
|
||||
testing.expectEqual(free_list.first_free, header);
|
||||
try testing.expectEqual(header.size, size - 128 - 512 - @sizeOf(Header));
|
||||
try testing.expectEqual(header.next_free, null);
|
||||
try testing.expectEqual(free_list.first_free, header);
|
||||
|
||||
// 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];
|
||||
header = @intToPtr(*Header, @ptrToInt(alloc1.ptr) + 128);
|
||||
testing.expectEqual(header.size, size - 128 - 128 - @sizeOf(Header));
|
||||
testing.expectEqual(header.next_free, null);
|
||||
testing.expectEqual(free_list.first_free, header);
|
||||
try testing.expectEqual(header.size, size - 128 - 128 - @sizeOf(Header));
|
||||
try testing.expectEqual(header.next_free, null);
|
||||
try testing.expectEqual(free_list.first_free, header);
|
||||
|
||||
// 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
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -216,44 +216,44 @@ pub const Keyboard = struct {
|
|||
|
||||
test "init" {
|
||||
const keyboard = Keyboard.init();
|
||||
testing.expectEqual(keyboard.queue_front, 0);
|
||||
testing.expectEqual(keyboard.queue_end, 0);
|
||||
try testing.expectEqual(keyboard.queue_front, 0);
|
||||
try testing.expectEqual(keyboard.queue_end, 0);
|
||||
}
|
||||
|
||||
test "isEmpty" {
|
||||
var keyboard = Keyboard.init();
|
||||
testing.expect(keyboard.isEmpty());
|
||||
try testing.expect(keyboard.isEmpty());
|
||||
|
||||
keyboard.queue_end += 1;
|
||||
testing.expect(!keyboard.isEmpty());
|
||||
try testing.expect(!keyboard.isEmpty());
|
||||
|
||||
keyboard.queue_front += 1;
|
||||
testing.expect(keyboard.isEmpty());
|
||||
try testing.expect(keyboard.isEmpty());
|
||||
|
||||
keyboard.queue_end = std.math.maxInt(QueueIndex);
|
||||
keyboard.queue_front = 0;
|
||||
testing.expect(!keyboard.isEmpty());
|
||||
try testing.expect(!keyboard.isEmpty());
|
||||
|
||||
keyboard.queue_front = std.math.maxInt(QueueIndex);
|
||||
testing.expect(keyboard.isEmpty());
|
||||
try testing.expect(keyboard.isEmpty());
|
||||
}
|
||||
|
||||
test "isFull" {
|
||||
var keyboard = Keyboard.init();
|
||||
testing.expect(!keyboard.isFull());
|
||||
try testing.expect(!keyboard.isFull());
|
||||
|
||||
keyboard.queue_end += 1;
|
||||
testing.expect(!keyboard.isFull());
|
||||
try testing.expect(!keyboard.isFull());
|
||||
|
||||
keyboard.queue_front += 1;
|
||||
testing.expect(!keyboard.isFull());
|
||||
try testing.expect(!keyboard.isFull());
|
||||
|
||||
keyboard.queue_end = 0;
|
||||
testing.expect(keyboard.isFull());
|
||||
try testing.expect(keyboard.isFull());
|
||||
|
||||
keyboard.queue_front = 0;
|
||||
keyboard.queue_end = std.math.maxInt(QueueIndex);
|
||||
testing.expect(keyboard.isFull());
|
||||
try testing.expect(keyboard.isFull());
|
||||
}
|
||||
|
||||
test "writeKey" {
|
||||
|
@ -261,20 +261,20 @@ pub const Keyboard = struct {
|
|||
|
||||
comptime var i = 0;
|
||||
inline while (i < QUEUE_SIZE - 1) : (i += 1) {
|
||||
testing.expectEqual(keyboard.writeKey(.{
|
||||
try testing.expectEqual(keyboard.writeKey(.{
|
||||
.position = @intToEnum(KeyPosition, i),
|
||||
.released = false,
|
||||
}), true);
|
||||
testing.expectEqual(keyboard.queue[i].position, @intToEnum(KeyPosition, i));
|
||||
testing.expectEqual(keyboard.queue_end, i + 1);
|
||||
testing.expectEqual(keyboard.queue_front, 0);
|
||||
try testing.expectEqual(keyboard.queue[i].position, @intToEnum(KeyPosition, i));
|
||||
try testing.expectEqual(keyboard.queue_end, i + 1);
|
||||
try testing.expectEqual(keyboard.queue_front, 0);
|
||||
}
|
||||
|
||||
testing.expectEqual(keyboard.writeKey(.{
|
||||
try testing.expectEqual(keyboard.writeKey(.{
|
||||
.position = @intToEnum(KeyPosition, 33),
|
||||
.released = false,
|
||||
}), false);
|
||||
testing.expect(keyboard.isFull());
|
||||
try testing.expect(keyboard.isFull());
|
||||
}
|
||||
|
||||
test "readKey" {
|
||||
|
@ -282,7 +282,7 @@ pub const Keyboard = struct {
|
|||
|
||||
comptime var i = 0;
|
||||
inline while (i < QUEUE_SIZE - 1) : (i += 1) {
|
||||
testing.expectEqual(keyboard.writeKey(.{
|
||||
try testing.expectEqual(keyboard.writeKey(.{
|
||||
.position = @intToEnum(KeyPosition, i),
|
||||
.released = false,
|
||||
}), true);
|
||||
|
@ -290,13 +290,13 @@ pub const Keyboard = struct {
|
|||
|
||||
i = 0;
|
||||
inline while (i < QUEUE_SIZE - 1) : (i += 1) {
|
||||
testing.expectEqual(keyboard.readKey().?.position, @intToEnum(KeyPosition, i));
|
||||
testing.expectEqual(keyboard.queue_end, QUEUE_SIZE - 1);
|
||||
testing.expectEqual(keyboard.queue_front, i + 1);
|
||||
try testing.expectEqual(keyboard.readKey().?.position, @intToEnum(KeyPosition, i));
|
||||
try testing.expectEqual(keyboard.queue_end, QUEUE_SIZE - 1);
|
||||
try testing.expectEqual(keyboard.queue_front, i + 1);
|
||||
}
|
||||
|
||||
testing.expect(keyboard.isEmpty());
|
||||
testing.expectEqual(keyboard.readKey(), null);
|
||||
try testing.expect(keyboard.isEmpty());
|
||||
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
|
||||
///
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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);
|
||||
return arch.initKeyboard(allocator);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,8 @@ const kmain_log = std.log.scoped(.kmain);
|
|||
const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.mock_path;
|
||||
const arch = @import("arch.zig").internals;
|
||||
const tty = @import("tty.zig");
|
||||
const vga = @import("vga.zig");
|
||||
const log_root = @import("log.zig");
|
||||
const pmm = @import("pmm.zig");
|
||||
const serial = @import("serial.zig");
|
||||
|
@ -23,7 +21,7 @@ const Allocator = std.mem.Allocator;
|
|||
|
||||
comptime {
|
||||
if (!is_test) {
|
||||
switch (builtin.arch) {
|
||||
switch (builtin.cpu.arch) {
|
||||
.i386 => _ = @import("arch/x86/boot.zig"),
|
||||
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;
|
||||
|
||||
// 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);
|
||||
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 {
|
||||
const serial_stream = serial.init(boot_payload);
|
||||
|
||||
log_root.init(serial_stream);
|
||||
|
||||
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;
|
||||
|
||||
panic_root.init(&mem_profile, &fixed_allocator.allocator) catch |e| {
|
||||
panic_root.panic(@errorReturnTrace(), "Failed to initialise panic: {}\n", .{e});
|
||||
};
|
||||
|
||||
pmm.init(&mem_profile, &fixed_allocator.allocator);
|
||||
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});
|
||||
};
|
||||
|
||||
kmain_log.info("Init arch " ++ @tagName(builtin.arch) ++ "\n", .{});
|
||||
kmain_log.info("Init arch " ++ @tagName(builtin.cpu.arch) ++ "\n", .{});
|
||||
arch.init(&mem_profile);
|
||||
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
|
||||
switch (build_options.test_mode) {
|
||||
.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});
|
||||
};
|
||||
|
||||
tty.init(&kernel_heap.allocator, boot_payload);
|
||||
var arch_kb = keyboard.init(&fixed_allocator.allocator) catch |e| {
|
||||
tty.init(kernel_heap.allocator(), boot_payload);
|
||||
var arch_kb = keyboard.init(fixed_allocator.allocator()) catch |e| {
|
||||
panic_root.panic(@errorReturnTrace(), "Failed to inititalise keyboard: {}\n", .{e});
|
||||
};
|
||||
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 ramdisk_bytes = @intToPtr([*]u8, module.region.start)[0..rd_len];
|
||||
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});
|
||||
};
|
||||
|
||||
|
@ -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});
|
||||
};
|
||||
|
||||
|
@ -147,10 +144,10 @@ export fn kmain(boot_payload: arch.BootPayload) void {
|
|||
kmain_log.info("Creating init2\n", .{});
|
||||
|
||||
// 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});
|
||||
};
|
||||
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});
|
||||
};
|
||||
|
||||
|
@ -177,7 +174,7 @@ fn initStage2() noreturn {
|
|||
|
||||
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});
|
||||
};
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ var serial: Serial = undefined;
|
|||
/// {} - No error as LoggingError is empty.
|
||||
///
|
||||
fn logCallback(context: void, str: []const u8) LoggingError!usize {
|
||||
// Suppress unused var warning
|
||||
_ = context;
|
||||
serial.writeBytes(str);
|
||||
return str.len;
|
||||
}
|
||||
|
|
|
@ -102,15 +102,15 @@ pub fn physToVirt(phys: anytype) @TypeOf(phys) {
|
|||
test "physToVirt" {
|
||||
ADDR_OFFSET = 0xC0000000;
|
||||
const offset: usize = ADDR_OFFSET;
|
||||
expectEqual(physToVirt(@as(usize, 0)), offset + 0);
|
||||
expectEqual(physToVirt(@as(usize, 123)), offset + 123);
|
||||
expectEqual(@ptrToInt(physToVirt(@intToPtr(*align(1) usize, 123))), offset + 123);
|
||||
try expectEqual(physToVirt(@as(usize, 0)), offset + 0);
|
||||
try expectEqual(physToVirt(@as(usize, 123)), offset + 123);
|
||||
try expectEqual(@ptrToInt(physToVirt(@intToPtr(*align(1) usize, 123))), offset + 123);
|
||||
}
|
||||
|
||||
test "virtToPhys" {
|
||||
ADDR_OFFSET = 0xC0000000;
|
||||
const offset: usize = ADDR_OFFSET;
|
||||
expectEqual(virtToPhys(offset + 0), 0);
|
||||
expectEqual(virtToPhys(offset + 123), 123);
|
||||
expectEqual(@ptrToInt(virtToPhys(@intToPtr(*align(1) usize, offset + 123))), 123);
|
||||
try expectEqual(virtToPhys(offset + 0), 0);
|
||||
try expectEqual(virtToPhys(offset + 123), 123);
|
||||
try expectEqual(@ptrToInt(virtToPhys(@intToPtr(*align(1) usize, offset + 123))), 123);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
const arch = @import("arch.zig").internals;
|
||||
const multiboot = @import("multiboot.zig");
|
||||
const mem = @import("mem.zig");
|
||||
const build_options = @import("build_options");
|
||||
const ArrayList = std.ArrayList;
|
||||
|
@ -32,12 +31,12 @@ const SymbolMap = struct {
|
|||
/// Initialise an empty symbol map.
|
||||
///
|
||||
/// 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
|
||||
/// The symbol map.
|
||||
///
|
||||
pub fn init(allocator: *Allocator) SymbolMap {
|
||||
pub fn init(allocator: Allocator) SymbolMap {
|
||||
return SymbolMap{
|
||||
.symbols = ArrayList(MapEntry).init(allocator),
|
||||
};
|
||||
|
@ -111,7 +110,7 @@ var symbol_map: ?SymbolMap = null;
|
|||
///
|
||||
fn logTraceAddress(addr: usize) void {
|
||||
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 {
|
||||
@setCold(true);
|
||||
log.emerg("Kernel panic: " ++ format ++ "\n", args);
|
||||
log.err("Kernel panic: " ++ format ++ "\n", args);
|
||||
if (trace) |trc| {
|
||||
var last_addr: u64 = 0;
|
||||
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
|
||||
/// symbols from it. Exits early if no such module was found.
|
||||
/// Initialise the symbol table used by the panic subsystem by looking for a boot module called "kernel.map" and loading the
|
||||
/// symbol entries from it. Exits early if no such module was found.
|
||||
///
|
||||
/// Arguments:
|
||||
/// IN mem_profile: *const mem.MemProfile - The memory profile from which to get the loaded boot
|
||||
/// 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
|
||||
/// PanicError.InvalidSymbolFile - A terminating whitespace wasn't found before the end address.
|
||||
/// Allocator.Error.OutOfMemory - If there wasn't enough memory.
|
||||
/// 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", .{});
|
||||
defer log.info("Done\n", .{});
|
||||
|
||||
|
@ -355,91 +354,91 @@ test "parseChar" {
|
|||
const str: []const u8 = "plutoisthebest";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
var char = try parseChar(str.ptr, end);
|
||||
testing.expectEqual(char, 'p');
|
||||
try testing.expectEqual(char, 'p');
|
||||
char = try parseChar(str.ptr + 1, end);
|
||||
testing.expectEqual(char, 'l');
|
||||
testing.expectError(PanicError.InvalidSymbolFile, parseChar(str.ptr + str.len, end));
|
||||
try testing.expectEqual(char, 'l');
|
||||
try testing.expectError(PanicError.InvalidSymbolFile, parseChar(str.ptr + str.len, end));
|
||||
}
|
||||
|
||||
test "parseWhitespace" {
|
||||
const str: []const u8 = " a";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
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" {
|
||||
const str: []const u8 = " ";
|
||||
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" {
|
||||
const str: []const u8 = "ab ";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
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" {
|
||||
const str: []const u8 = "abc";
|
||||
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" {
|
||||
const str: []const u8 = "ab\n";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
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" {
|
||||
const str: []const u8 = "abc";
|
||||
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" {
|
||||
const str: []const u8 = "1a2b3c4d ";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
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" {
|
||||
const str: []const u8 = "1a2b3c4d";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
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" {
|
||||
const str: []const u8 = "1g2t ";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
var ptr = str.ptr;
|
||||
testing.expectError(error.InvalidCharacter, parseAddr(&ptr, end));
|
||||
try testing.expectError(error.InvalidCharacter, parseAddr(&ptr, end));
|
||||
}
|
||||
|
||||
test "parseName" {
|
||||
const str: []const u8 = "func_name\n";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
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" {
|
||||
const str: []const u8 = "func_name(*const type )\n";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
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" {
|
||||
const str: []const u8 = "func_name";
|
||||
const end = @ptrCast(*const u8, str.ptr + str.len);
|
||||
var ptr = str.ptr;
|
||||
testing.expectError(PanicError.InvalidSymbolFile, parseName(&ptr, end));
|
||||
try testing.expectError(PanicError.InvalidSymbolFile, parseName(&ptr, end));
|
||||
}
|
||||
|
||||
test "parseMapEntry" {
|
||||
|
@ -449,37 +448,37 @@ test "parseMapEntry" {
|
|||
|
||||
var actual = try parseMapEntry(&ptr, end);
|
||||
var expected = MapEntry{ .addr = 0x1a2b3c4d, .func_name = "func_name" };
|
||||
testing.expectEqual(actual.addr, expected.addr);
|
||||
testing.expectEqualSlices(u8, actual.func_name, expected.func_name);
|
||||
try testing.expectEqual(actual.addr, expected.addr);
|
||||
try testing.expectEqualSlices(u8, actual.func_name, expected.func_name);
|
||||
|
||||
actual = try parseMapEntry(&ptr, end);
|
||||
expected = MapEntry{ .addr = 0x5e6f7a8b, .func_name = "func_name2" };
|
||||
testing.expectEqual(actual.addr, expected.addr);
|
||||
testing.expectEqualSlices(u8, actual.func_name, expected.func_name);
|
||||
try testing.expectEqual(actual.addr, expected.addr);
|
||||
try testing.expectEqualSlices(u8, actual.func_name, expected.func_name);
|
||||
}
|
||||
|
||||
test "parseMapEntry fails without a terminating newline" {
|
||||
const str: []const u8 = "1a2b3c4d func_name";
|
||||
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" {
|
||||
const str: []const u8 = " ";
|
||||
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" {
|
||||
const str: []const u8 = "xyz func_name";
|
||||
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" {
|
||||
const str: []const u8 = "123 ";
|
||||
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" {
|
||||
|
@ -490,18 +489,18 @@ test "SymbolMap" {
|
|||
try map.addEntry(MapEntry{ .func_name = "def"[0..], .addr = 456 });
|
||||
try map.add("ghi"[0..], 789);
|
||||
try map.addEntry(MapEntry{ .func_name = "jkl"[0..], .addr = 1010 });
|
||||
testing.expectEqual(map.search(54), null);
|
||||
testing.expectEqual(map.search(122), null);
|
||||
testing.expectEqual(map.search(123), "abc");
|
||||
testing.expectEqual(map.search(234), "abc");
|
||||
testing.expectEqual(map.search(455), "abc");
|
||||
testing.expectEqual(map.search(456), "def");
|
||||
testing.expectEqual(map.search(678), "def");
|
||||
testing.expectEqual(map.search(788), "def");
|
||||
testing.expectEqual(map.search(789), "ghi");
|
||||
testing.expectEqual(map.search(1009), "ghi");
|
||||
testing.expectEqual(map.search(1010), "jkl");
|
||||
testing.expectEqual(map.search(2345), "jkl");
|
||||
try testing.expectEqual(map.search(54), null);
|
||||
try testing.expectEqual(map.search(122), null);
|
||||
try testing.expectEqual(map.search(123), "abc");
|
||||
try testing.expectEqual(map.search(234), "abc");
|
||||
try testing.expectEqual(map.search(455), "abc");
|
||||
try testing.expectEqual(map.search(456), "def");
|
||||
try testing.expectEqual(map.search(678), "def");
|
||||
try testing.expectEqual(map.search(788), "def");
|
||||
try testing.expectEqual(map.search(789), "ghi");
|
||||
try testing.expectEqual(map.search(1009), "ghi");
|
||||
try testing.expectEqual(map.search(1010), "jkl");
|
||||
try testing.expectEqual(map.search(2345), "jkl");
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
@ -2,8 +2,7 @@ const is_test = @import("builtin").is_test;
|
|||
const std = @import("std");
|
||||
const log = std.log.scoped(.pmm);
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.mock_path;
|
||||
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig").internals;
|
||||
const arch = @import("arch.zig").internals;
|
||||
const MemProfile = @import("mem.zig").MemProfile;
|
||||
const testing = std.testing;
|
||||
const panic = @import("panic.zig").panic;
|
||||
|
@ -96,9 +95,9 @@ pub fn blocksFree() usize {
|
|||
///
|
||||
/// Arguments:
|
||||
/// 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", .{});
|
||||
defer log.info("Done\n", .{});
|
||||
|
||||
|
@ -146,13 +145,13 @@ test "alloc" {
|
|||
i += 1;
|
||||
addr += BLOCK_SIZE;
|
||||
}) {
|
||||
testing.expect(!(try isSet(addr)));
|
||||
testing.expect(alloc().? == addr);
|
||||
testing.expect(try isSet(addr));
|
||||
testing.expectEqual(blocksFree(), 31 - i);
|
||||
try testing.expect(!(try isSet(addr)));
|
||||
try testing.expect(alloc().? == addr);
|
||||
try testing.expect(try isSet(addr));
|
||||
try testing.expectEqual(blocksFree(), 31 - i);
|
||||
}
|
||||
// Allocation should now fail
|
||||
testing.expect(alloc() == null);
|
||||
try testing.expect(alloc() == null);
|
||||
}
|
||||
|
||||
test "free" {
|
||||
|
@ -162,13 +161,13 @@ test "free" {
|
|||
// Allocate and free all entries
|
||||
inline while (i < 32) : (i += 1) {
|
||||
const addr = alloc().?;
|
||||
testing.expect(try isSet(addr));
|
||||
testing.expectEqual(blocksFree(), 31);
|
||||
try testing.expect(try isSet(addr));
|
||||
try testing.expectEqual(blocksFree(), 31);
|
||||
try free(addr);
|
||||
testing.expectEqual(blocksFree(), 32);
|
||||
testing.expect(!(try isSet(addr)));
|
||||
try testing.expectEqual(blocksFree(), 32);
|
||||
try testing.expect(!(try isSet(addr)));
|
||||
// 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;
|
||||
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
|
||||
try setAddr(addr);
|
||||
testing.expect(try isSet(addr));
|
||||
testing.expectEqual(blocksFree(), num_entries - i - 1);
|
||||
try testing.expect(try isSet(addr));
|
||||
try testing.expectEqual(blocksFree(), num_entries - i - 1);
|
||||
|
||||
// Ensure all successive entries are not set
|
||||
var j: u32 = i + 1;
|
||||
|
@ -205,7 +204,7 @@ test "setAddr and isSet" {
|
|||
j += 1;
|
||||
addr3 += BLOCK_SIZE;
|
||||
}) {
|
||||
testing.expect(!try isSet(addr3));
|
||||
try testing.expect(!try isSet(addr3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,9 +214,9 @@ test "setAddr and isSet" {
|
|||
///
|
||||
/// Arguments:
|
||||
/// 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
|
||||
var prev_alloc: usize = std.math.maxInt(usize);
|
||||
var alloc_list = std.ArrayList(usize).init(allocator);
|
||||
|
|
|
@ -6,7 +6,6 @@ const log = std.log.scoped(.scheduler);
|
|||
const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.mock_path;
|
||||
const arch = @import("arch.zig").internals;
|
||||
const panic = @import("panic.zig").panic;
|
||||
const task = @import("task.zig");
|
||||
|
@ -105,12 +104,13 @@ pub fn pickNextTask(ctx: *arch.CpuState) usize {
|
|||
///
|
||||
/// Arguments:
|
||||
/// 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
|
||||
/// OutOfMemory - If there isn't enough memory for the a task/stack. Any memory allocated will
|
||||
/// 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);
|
||||
task_node.* = .{ .data = new_task };
|
||||
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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// Error: Allocator.Error
|
||||
/// 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?
|
||||
log.info("Init\n", .{});
|
||||
defer log.info("Done\n", .{});
|
||||
|
@ -170,7 +170,7 @@ fn test_fn2() void {}
|
|||
|
||||
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);
|
||||
errdefer allocator.destroy(t);
|
||||
t.pid = test_pid_counter;
|
||||
|
@ -181,7 +181,7 @@ fn createTestTask(entry_point: EntryPoint, allocator: *Allocator, kernel: bool,
|
|||
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)) {
|
||||
allocator.free(self.kernel_stack);
|
||||
}
|
||||
|
@ -214,26 +214,26 @@ test "pickNextTask" {
|
|||
const fn1_stack_pointer = test_fn1_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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx));
|
||||
try expectEqual(tasks.first.?.data.stack_pointer, @ptrToInt(&ctx));
|
||||
|
||||
// Should be back tot he beginning
|
||||
expectEqual(current_task.pid, 0);
|
||||
try expectEqual(current_task.pid, 0);
|
||||
|
||||
// Reset the test pid
|
||||
test_pid_counter = 1;
|
||||
|
@ -255,7 +255,7 @@ test "createNewTask add new task" {
|
|||
defer test_fn1_task.destroy(allocator);
|
||||
try scheduleTask(test_fn1_task, allocator);
|
||||
|
||||
expectEqual(tasks.len, 1);
|
||||
try expectEqual(tasks.len, 1);
|
||||
|
||||
// Free the memory
|
||||
allocator.destroy(tasks.first.?);
|
||||
|
@ -266,11 +266,11 @@ test "init" {
|
|||
|
||||
try init(allocator, undefined);
|
||||
|
||||
expectEqual(current_task.pid, 0);
|
||||
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.pid, 0);
|
||||
try expectEqual(@ptrToInt(current_task.kernel_stack.ptr), @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
|
||||
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.
|
||||
///
|
||||
/// 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
|
||||
is_set = allocator.create(bool) catch unreachable;
|
||||
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 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| {
|
||||
// 1. Create user VMM
|
||||
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| {
|
||||
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();
|
||||
|
||||
const current_physical_blocks = pmm.blocksFree();
|
||||
|
||||
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 });
|
||||
};
|
||||
|
@ -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.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
fn runtimeTests(allocator: *Allocator, mem_profile: *const mem.MemProfile) void {
|
||||
fn runtimeTests(allocator: Allocator, mem_profile: *const mem.MemProfile) void {
|
||||
arch.enableInterrupts();
|
||||
rt_user_task(allocator, mem_profile);
|
||||
rt_variable_preserved(allocator);
|
||||
|
|
|
@ -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 {
|
||||
// Suppress unused variable warnings
|
||||
_ = arg1;
|
||||
_ = arg2;
|
||||
_ = arg3;
|
||||
_ = arg4;
|
||||
_ = arg5;
|
||||
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 {
|
||||
// Suppress unused variable warnings
|
||||
_ = arg1;
|
||||
_ = arg2;
|
||||
_ = arg3;
|
||||
_ = arg4;
|
||||
_ = arg5;
|
||||
return std.mem.Allocator.Error.OutOfMemory;
|
||||
}
|
||||
|
||||
test "getHandler" {
|
||||
std.testing.expectEqual(Syscall.Test1.getHandler(), handleTest1);
|
||||
std.testing.expectEqual(Syscall.Test2.getHandler(), handleTest2);
|
||||
std.testing.expectEqual(Syscall.Test3.getHandler(), handleTest3);
|
||||
try std.testing.expectEqual(Syscall.Test1.getHandler(), handleTest1);
|
||||
try std.testing.expectEqual(Syscall.Test2.getHandler(), handleTest2);
|
||||
try std.testing.expectEqual(Syscall.Test3.getHandler(), handleTest3);
|
||||
}
|
||||
|
||||
test "handle" {
|
||||
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));
|
||||
std.testing.expectError(Error.OutOfMemory, handle(.Test3, 0, 0, 0, 0, 0));
|
||||
try std.testing.expectEqual(@as(usize, 0), try handle(.Test1, 0, 0, 0, 0, 0));
|
||||
try std.testing.expectEqual(@as(usize, 1 + 2 + 3 + 4 + 5), try handle(.Test2, 1, 2, 3, 4, 5));
|
||||
try std.testing.expectError(Error.OutOfMemory, handle(.Test3, 0, 0, 0, 0, 0));
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ const expectError = std.testing.expectError;
|
|||
const builtin = @import("builtin");
|
||||
const is_test = builtin.is_test;
|
||||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.mock_path;
|
||||
const arch = @import("arch.zig").internals;
|
||||
const panic = @import("panic.zig").panic;
|
||||
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 kernel: bool - Whether the task has kernel or user privileges.
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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);
|
||||
errdefer allocator.destroy(task);
|
||||
|
||||
|
@ -104,7 +103,7 @@ pub const Task = struct {
|
|||
return task;
|
||||
}
|
||||
|
||||
pub fn createFromElf(program_elf: elf.Elf, kernel: bool, task_vmm: *vmm.VirtualMemoryManager(arch.VmmPayload), allocator: *Allocator) (bitmap.Bitmap(usize).BitmapError || vmm.VmmError || Allocator.Error)!*Task {
|
||||
pub fn createFromElf(program_elf: elf.Elf, kernel: bool, task_vmm: *vmm.VirtualMemoryManager(arch.VmmPayload), allocator: Allocator) (bitmap.Bitmap(usize).BitmapError || vmm.VmmError || Allocator.Error)!*Task {
|
||||
const task = try create(program_elf.header.entry_address, kernel, task_vmm, allocator);
|
||||
errdefer task.destroy(allocator);
|
||||
|
||||
|
@ -141,8 +140,9 @@ pub const Task = struct {
|
|||
///
|
||||
/// Arguments:
|
||||
/// 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);
|
||||
// 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
|
||||
|
@ -182,7 +182,7 @@ fn freePid(pid: PidBitmap.IndexType) void {
|
|||
|
||||
// For testing the errdefer
|
||||
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 {}
|
||||
|
||||
|
@ -190,28 +190,28 @@ test "create out of memory for task" {
|
|||
// Set the global allocator
|
||||
var fa = FailingAllocator.init(testing_allocator, 0);
|
||||
|
||||
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), true, undefined, fa.allocator()));
|
||||
try expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), false, undefined, fa.allocator()));
|
||||
|
||||
// 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
|
||||
expectEqual(all_pids.bitmap, 0);
|
||||
try expectEqual(all_pids.bitmap, 0);
|
||||
}
|
||||
|
||||
test "create out of memory for stack" {
|
||||
// Set the global allocator
|
||||
var fa = FailingAllocator.init(testing_allocator, 1);
|
||||
|
||||
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), true, undefined, fa.allocator()));
|
||||
try expectError(error.OutOfMemory, Task.create(@ptrToInt(test_fn1), false, undefined, fa.allocator()));
|
||||
|
||||
// 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
|
||||
expectEqual(all_pids.bitmap, 0);
|
||||
try expectEqual(all_pids.bitmap, 0);
|
||||
}
|
||||
|
||||
test "create expected setup" {
|
||||
|
@ -219,15 +219,15 @@ test "create expected setup" {
|
|||
defer task.destroy(std.testing.allocator);
|
||||
|
||||
// Will allocate the first PID 0
|
||||
expectEqual(task.pid, 0);
|
||||
expectEqual(task.kernel_stack.len, STACK_SIZE);
|
||||
expectEqual(task.user_stack.len, 0);
|
||||
try expectEqual(task.pid, 0);
|
||||
try expectEqual(task.kernel_stack.len, STACK_SIZE);
|
||||
try expectEqual(task.user_stack.len, 0);
|
||||
|
||||
var user_task = try Task.create(@ptrToInt(test_fn1), false, undefined, std.testing.allocator);
|
||||
defer user_task.destroy(std.testing.allocator);
|
||||
expectEqual(user_task.pid, 1);
|
||||
expectEqual(user_task.user_stack.len, STACK_SIZE);
|
||||
expectEqual(user_task.kernel_stack.len, STACK_SIZE);
|
||||
try expectEqual(user_task.pid, 1);
|
||||
try expectEqual(user_task.user_stack.len, STACK_SIZE);
|
||||
try expectEqual(user_task.kernel_stack.len, STACK_SIZE);
|
||||
}
|
||||
|
||||
test "destroy cleans up" {
|
||||
|
@ -242,54 +242,54 @@ test "destroy cleans up" {
|
|||
user_task.destroy(allocator);
|
||||
|
||||
// All PIDs were freed
|
||||
expectEqual(all_pids.bitmap, 0);
|
||||
try expectEqual(all_pids.bitmap, 0);
|
||||
}
|
||||
|
||||
test "Multiple create" {
|
||||
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);
|
||||
|
||||
expectEqual(task1.pid, 0);
|
||||
expectEqual(task2.pid, 1);
|
||||
expectEqual(all_pids.bitmap, 3);
|
||||
try expectEqual(task1.pid, 0);
|
||||
try expectEqual(task2.pid, 1);
|
||||
try expectEqual(all_pids.bitmap, 3);
|
||||
|
||||
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);
|
||||
|
||||
expectEqual(task3.pid, 0);
|
||||
expectEqual(all_pids.bitmap, 3);
|
||||
try expectEqual(task3.pid, 0);
|
||||
try expectEqual(all_pids.bitmap, 3);
|
||||
|
||||
task2.destroy(std.testing.allocator);
|
||||
task3.destroy(std.testing.allocator);
|
||||
|
||||
var user_task = try Task.create(@ptrToInt(test_fn1), false, undefined, std.testing.allocator);
|
||||
|
||||
expectEqual(user_task.pid, 0);
|
||||
expectEqual(all_pids.bitmap, 1);
|
||||
try expectEqual(user_task.pid, 0);
|
||||
try expectEqual(all_pids.bitmap, 1);
|
||||
|
||||
user_task.destroy(std.testing.allocator);
|
||||
expectEqual(all_pids.bitmap, 0);
|
||||
try expectEqual(all_pids.bitmap, 0);
|
||||
}
|
||||
|
||||
test "allocatePid and freePid" {
|
||||
expectEqual(all_pids.bitmap, 0);
|
||||
try expectEqual(all_pids.bitmap, 0);
|
||||
|
||||
var i: usize = 0;
|
||||
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;
|
||||
while (i < PidBitmap.NUM_ENTRIES) : (i += 1) {
|
||||
freePid(@truncate(PidBitmap.IndexType, i));
|
||||
}
|
||||
|
||||
expectEqual(all_pids.bitmap, 0);
|
||||
try expectEqual(all_pids.bitmap, 0);
|
||||
}
|
||||
|
||||
test "createFromElf" {
|
||||
|
@ -300,7 +300,7 @@ test "createFromElf" {
|
|||
const 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);
|
||||
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();
|
||||
|
||||
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);
|
||||
defer task.destroy(allocator);
|
||||
|
||||
std.testing.expectEqual(task.pid, 0);
|
||||
std.testing.expectEqual(task.user_stack.len, 0);
|
||||
std.testing.expectEqual(task.kernel_stack.len, STACK_SIZE);
|
||||
try std.testing.expectEqual(task.pid, 0);
|
||||
try std.testing.expectEqual(task.user_stack.len, 0);
|
||||
try std.testing.expectEqual(task.kernel_stack.len, STACK_SIZE);
|
||||
}
|
||||
|
||||
test "createFromElf clean-up" {
|
||||
|
@ -321,7 +321,7 @@ test "createFromElf clean-up" {
|
|||
const 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);
|
||||
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();
|
||||
|
||||
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 OutOfMemory
|
||||
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));
|
||||
std.testing.expectEqual(all_pids.num_free_entries, PidBitmap.NUM_ENTRIES - 1);
|
||||
var allocator2 = std.testing.FailingAllocator.init(allocator, 0).allocator();
|
||||
try std.testing.expectError(std.mem.Allocator.Error.OutOfMemory, Task.createFromElf(the_elf, true, &the_vmm, allocator2));
|
||||
try std.testing.expectEqual(all_pids.num_free_entries, PidBitmap.NUM_ENTRIES - 1);
|
||||
// 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
|
||||
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
|
||||
// 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);
|
||||
// Make the strings section allocatable so createFromElf tries to allocate more than one
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ pub const TTY = struct {
|
|||
|
||||
/// The current tty stream
|
||||
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.
|
||||
|
@ -37,6 +37,8 @@ var allocator: *Allocator = undefined;
|
|||
/// The number of characters printed
|
||||
///
|
||||
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});
|
||||
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 {
|
||||
// Printing can't error because of the scrolling, if it does, we have a big problem
|
||||
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
|
||||
///
|
||||
/// 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
|
||||
///
|
||||
pub fn init(alloc: *Allocator, boot_payload: arch.BootPayload) void {
|
||||
pub fn init(alloc: Allocator, boot_payload: arch.BootPayload) void {
|
||||
log.info("Init\n", .{});
|
||||
defer log.info("Done\n", .{});
|
||||
tty = arch.initTTY(boot_payload);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const build_options = @import("build_options");
|
||||
const mock_path = build_options.mock_path;
|
||||
const builtin = @import("builtin");
|
||||
const builtin = std.builtin;
|
||||
const is_test = builtin.is_test;
|
||||
const std = @import("std");
|
||||
const log = std.log.scoped(.vmm);
|
||||
|
@ -9,8 +9,9 @@ const pmm = @import("pmm.zig");
|
|||
const mem = @import("mem.zig");
|
||||
const tty = @import("tty.zig");
|
||||
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 assert = std.debug.assert;
|
||||
|
||||
/// Attributes for a virtual memory allocation
|
||||
pub const Attributes = struct {
|
||||
|
@ -71,7 +72,7 @@ pub fn Mapper(comptime Payload: type) type {
|
|||
/// Error: AllocatorError || MapperError
|
||||
/// 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.
|
||||
|
@ -85,7 +86,7 @@ pub fn Mapper(comptime Payload: type) type {
|
|||
/// Error: MapperError
|
||||
/// 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,
|
||||
|
||||
/// The allocator to use when allocating and freeing regions
|
||||
allocator: *Allocator,
|
||||
allocator: Allocator,
|
||||
|
||||
/// All allocations that have been made with this manager
|
||||
allocations: std.hash_map.AutoHashMap(usize, Allocation),
|
||||
|
@ -160,7 +161,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
/// Arguments:
|
||||
/// 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/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 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.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;
|
||||
var bmp = try bitmap.Bitmap(usize).init(std.mem.alignForward(size, pmm.BLOCK_SIZE) / pmm.BLOCK_SIZE, allocator);
|
||||
return Self{
|
||||
|
@ -209,10 +210,10 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
var it = self.allocations.iterator();
|
||||
while (it.next()) |entry| {
|
||||
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 clone.allocations.put(entry.key, Allocation{ .physical = list });
|
||||
_ = try clone.allocations.put(entry.key_ptr.*, Allocation{ .physical = list });
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
@ -227,7 +228,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
self.bmp.deinit();
|
||||
var it = self.allocations.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.value.physical.deinit();
|
||||
entry.value_ptr.physical.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 {
|
||||
var it = self.allocations.iterator();
|
||||
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 (vaddr <= virt and vaddr + (allocation.physical.items.len * BLOCK_SIZE) > virt) {
|
||||
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 {
|
||||
var it = self.allocations.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const vaddr = entry.key;
|
||||
const allocation = entry.value;
|
||||
const vaddr = entry.key_ptr.*;
|
||||
const allocation = entry.value_ptr.*;
|
||||
|
||||
for (allocation.physical.items) |block, i| {
|
||||
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
|
||||
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);
|
||||
try block_list.ensureCapacity(num);
|
||||
try block_list.ensureUnusedCapacity(num);
|
||||
|
||||
var i: usize = 0;
|
||||
const vaddr_start = self.start + entry * BLOCK_SIZE;
|
||||
|
@ -452,8 +453,8 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
defer blocks.deinit();
|
||||
var it = other.allocations.iterator();
|
||||
while (it.next()) |allocation| {
|
||||
const virtual = allocation.key;
|
||||
const physical = allocation.value.physical.items;
|
||||
const virtual = allocation.key_ptr.*;
|
||||
const physical = allocation.value_ptr.*.physical.items;
|
||||
if (start_addr >= virtual and virtual + physical.len * BLOCK_SIZE >= end_addr) {
|
||||
const first_block_idx = (start_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 });
|
||||
};
|
||||
// The allocation is freed so remove from the map
|
||||
self.allocations.removeAssertDiscard(vaddr);
|
||||
assert(self.allocations.remove(vaddr));
|
||||
} else {
|
||||
return VmmError.NotAllocated;
|
||||
}
|
||||
|
@ -545,7 +546,7 @@ pub fn VirtualMemoryManager(comptime Payload: type) type {
|
|||
///
|
||||
/// 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/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
|
||||
/// 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.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", .{});
|
||||
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 + 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));
|
||||
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 + BLOCK_SIZE * 2, try vmm.virtToPhys(vstart));
|
||||
try std.testing.expectEqual(pstart + BLOCK_SIZE * 2 + 29, (try vmm.virtToPhys(vstart + 29)));
|
||||
try std.testing.expectEqual(pstart + 29, (try vmm.virtToPhys(vstart + BLOCK_SIZE + 29)));
|
||||
|
||||
std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vstart - 1));
|
||||
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(vstart - 1));
|
||||
try std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend));
|
||||
try std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(vend + 1));
|
||||
}
|
||||
|
||||
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 + 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));
|
||||
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, try vmm.physToVirt(pstart + BLOCK_SIZE * 2));
|
||||
try std.testing.expectEqual(vstart + 29, (try vmm.physToVirt(pstart + BLOCK_SIZE * 2 + 29)));
|
||||
try std.testing.expectEqual(vstart + BLOCK_SIZE + 29, (try vmm.physToVirt(pstart + 29)));
|
||||
|
||||
std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pstart - 1));
|
||||
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(pstart - 1));
|
||||
try std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend));
|
||||
try std.testing.expectError(VmmError.NotAllocated, vmm.physToVirt(pend + 1));
|
||||
}
|
||||
|
||||
test "alloc and free" {
|
||||
|
@ -645,11 +646,11 @@ test "alloc and free" {
|
|||
var should_be_set = true;
|
||||
if (entry + num_to_alloc > num_entries) {
|
||||
// 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;
|
||||
} else {
|
||||
// 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.?);
|
||||
}
|
||||
|
||||
|
@ -658,20 +659,20 @@ test "alloc and free" {
|
|||
while (vaddr < (entry + num_to_alloc) * BLOCK_SIZE) : (vaddr += BLOCK_SIZE) {
|
||||
if (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
|
||||
std.testing.expect(try allocations.isSet(vaddr / BLOCK_SIZE));
|
||||
try std.testing.expect(try allocations.isSet(vaddr / BLOCK_SIZE));
|
||||
} else {
|
||||
// Allocation failed as there weren't enough free entries
|
||||
if (vaddr >= num_entries * BLOCK_SIZE) {
|
||||
// If this address is beyond the VMM's end address, it should be out of bounds
|
||||
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(u32).BitmapError.OutOfBounds, vmm.isSet(vaddr));
|
||||
try std.testing.expectError(bitmap.Bitmap(u64).BitmapError.OutOfBounds, allocations.isSet(vaddr / BLOCK_SIZE));
|
||||
} else {
|
||||
// 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
|
||||
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
|
||||
var later_entry = entry;
|
||||
while (later_entry < num_entries) : (later_entry += 1) {
|
||||
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 vmm.isSet(vmm.start + later_entry * BLOCK_SIZE)));
|
||||
try std.testing.expect(!(try pmm.isSet(later_entry * BLOCK_SIZE)));
|
||||
}
|
||||
}
|
||||
|
||||
// Try freeing all allocations
|
||||
for (virtual_allocations.items) |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;
|
||||
// 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);
|
||||
defer physical_copy.deinit();
|
||||
// Make sure they are all reserved in the PMM
|
||||
for (physical.items) |phys| {
|
||||
std.testing.expect(try pmm.isSet(phys));
|
||||
try std.testing.expect(try pmm.isSet(phys));
|
||||
try physical_copy.append(phys);
|
||||
}
|
||||
vmm.free(alloc) catch unreachable;
|
||||
// This virtual allocation should no longer be in the hashmap
|
||||
std.testing.expectEqual(vmm.allocations.get(alloc), null);
|
||||
std.testing.expect(!try vmm.isSet(alloc));
|
||||
try std.testing.expectEqual(vmm.allocations.get(alloc), null);
|
||||
try std.testing.expect(!try vmm.isSet(alloc));
|
||||
// And all its physical blocks should now be free
|
||||
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 };
|
||||
// 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
|
||||
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;
|
||||
// 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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.end, attrs), null);
|
||||
try std.testing.expectEqual(vmm.alloc(1, vmm.start - BLOCK_SIZE, attrs), null);
|
||||
}
|
||||
|
||||
test "set" {
|
||||
|
@ -748,21 +749,21 @@ test "set" {
|
|||
const attrs = Attributes{ .kernel = true, .writable = true, .cachable = true };
|
||||
try vmm.set(.{ .start = vstart, .end = vend }, mem.Range{ .start = pstart, .end = pend }, attrs);
|
||||
// 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.?;
|
||||
// The entries before the virtual start shouldn't be set
|
||||
var vaddr = vmm.start;
|
||||
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
|
||||
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
|
||||
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);
|
||||
|
||||
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();
|
||||
defer mirrored.deinit();
|
||||
std.testing.expectEqual(vmm.bmp.num_free_entries, mirrored.bmp.num_free_entries);
|
||||
std.testing.expectEqual(vmm.start, mirrored.start);
|
||||
std.testing.expectEqual(vmm.end, mirrored.end);
|
||||
std.testing.expectEqual(vmm.allocations.count(), mirrored.allocations.count());
|
||||
try std.testing.expectEqual(vmm.bmp.num_free_entries, mirrored.bmp.num_free_entries);
|
||||
try std.testing.expectEqual(vmm.start, mirrored.start);
|
||||
try std.testing.expectEqual(vmm.end, mirrored.end);
|
||||
try std.testing.expectEqual(vmm.allocations.count(), mirrored.allocations.count());
|
||||
var it = vmm.allocations.iterator();
|
||||
while (it.next()) |next| {
|
||||
for (mirrored.allocations.get(next.key).?.physical.items) |block, i| {
|
||||
std.testing.expectEqual(block, vmm.allocations.get(next.key).?.physical.items[i]);
|
||||
for (mirrored.allocations.get(next.key_ptr.*).?.physical.items) |block, i| {
|
||||
try std.testing.expectEqual(block, vmm.allocations.get(next.key_ptr.*).?.physical.items[i]);
|
||||
}
|
||||
}
|
||||
std.testing.expectEqual(vmm.mapper, mirrored.mapper);
|
||||
std.testing.expectEqual(vmm.payload, mirrored.payload);
|
||||
try std.testing.expectEqual(vmm.mapper, mirrored.mapper);
|
||||
try std.testing.expectEqual(vmm.payload, mirrored.payload);
|
||||
|
||||
// Allocating in the new VMM shouldn't allocate in the mirrored one
|
||||
const alloc1 = (try mirrored.alloc(3, null, attrs)).?;
|
||||
std.testing.expectEqual(vmm.allocations.count() + 1, mirrored.allocations.count());
|
||||
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.expectEqual(vmm.allocations.count() + 1, mirrored.allocations.count());
|
||||
try std.testing.expectEqual(vmm.bmp.num_free_entries - 3, mirrored.bmp.num_free_entries);
|
||||
try std.testing.expectError(VmmError.NotAllocated, vmm.virtToPhys(alloc1));
|
||||
|
||||
// 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 alloc4 = (try vmm.alloc(1, null, attrs)).?;
|
||||
std.testing.expectEqual(vmm.allocations.count() - 2, mirrored.allocations.count());
|
||||
std.testing.expectEqual(vmm.bmp.num_free_entries + 2, mirrored.bmp.num_free_entries);
|
||||
std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc3));
|
||||
std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc4));
|
||||
try std.testing.expectEqual(vmm.allocations.count() - 2, mirrored.allocations.count());
|
||||
try std.testing.expectEqual(vmm.bmp.num_free_entries + 2, mirrored.bmp.num_free_entries);
|
||||
try std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc3));
|
||||
try std.testing.expectError(VmmError.NotAllocated, mirrored.virtToPhys(alloc4));
|
||||
}
|
||||
|
||||
test "copyData from" {
|
||||
|
@ -820,21 +821,21 @@ test "copyData from" {
|
|||
|
||||
// Make sure they are the same
|
||||
var buff2 = @intToPtr([*]u8, alloc)[0..buff.len];
|
||||
std.testing.expectEqualSlices(u8, buff[0..buff.len], buff2);
|
||||
std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
|
||||
try std.testing.expectEqualSlices(u8, buff[0..buff.len], buff2);
|
||||
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
|
||||
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
|
||||
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);
|
||||
std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries);
|
||||
try std.testing.expectError(VmmError.NotAllocated, vmm2.copyData(&vmm, true, buff[0..buff.len], alloc + alloc1_blocks * BLOCK_SIZE));
|
||||
try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
|
||||
try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries);
|
||||
|
||||
// Test Bitmap.Error.OutOfBounds
|
||||
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));
|
||||
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.expectError(bitmap.Bitmap(usize).BitmapError.OutOfBounds, vmm2.copyData(&vmm, true, buff[0..buff.len], vmm.end));
|
||||
try std.testing.expectError(bitmap.Bitmap(usize).BitmapError.OutOfBounds, vmm.copyData(&vmm2, true, buff[0..buff.len], vmm2.end));
|
||||
try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
|
||||
try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries);
|
||||
}
|
||||
|
||||
test "copyDaya to" {
|
||||
|
@ -851,9 +852,9 @@ test "copyDaya to" {
|
|||
var buff2 = @intToPtr([*]u8, alloc)[0..buff.len];
|
||||
try vmm2.copyData(&vmm, false, buff[0..], alloc);
|
||||
|
||||
std.testing.expectEqualSlices(u8, buff[0..buff.len], buff2);
|
||||
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.expectEqualSlices(u8, buff[0..buff.len], buff2);
|
||||
try std.testing.expectEqual(vmm_free_entries, vmm.bmp.num_free_entries);
|
||||
try std.testing.expectEqual(vmm2_free_entries - 1, vmm2.bmp.num_free_entries);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
var allocations = test_allocations orelse unreachable;
|
||||
const mem_profile = mem.MemProfile{
|
||||
.vaddr_end = 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 pend: usize - The end of the physical region to map
|
||||
/// 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
|
||||
///
|
||||
fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attributes, allocator: *Allocator, payload: arch.VmmPayload) (Allocator.Error || MapperError)!void {
|
||||
std.testing.expectEqual(arch.KERNEL_VMM_PAYLOAD, payload);
|
||||
fn testMap(vstart: usize, vend: usize, pstart: usize, pend: usize, attrs: Attributes, allocator: Allocator, payload: arch.VmmPayload) MapperError!void {
|
||||
// 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 allocations = test_allocations.?;
|
||||
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 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 {
|
||||
std.testing.expectEqual(arch.KERNEL_VMM_PAYLOAD, payload);
|
||||
fn testUnmap(vstart: usize, vend: usize, allocator: Allocator, payload: arch.VmmPayload) MapperError!void {
|
||||
// Suppress unused var warning
|
||||
_ = allocator;
|
||||
std.testing.expectEqual(arch.KERNEL_VMM_PAYLOAD, payload) catch unreachable;
|
||||
var vaddr = vstart;
|
||||
var allocations = test_allocations.?;
|
||||
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
|
||||
// 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)) {
|
||||
panic(@errorReturnTrace(), "Third lot of data copied doesn't have the expected values\n", .{});
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -67,6 +67,8 @@ const types = .{
|
|||
.{ "fn (usize) bool", "FN_IUSIZE_OBOOL", "", "", "" },
|
||||
.{ "fn (RtcRegister) u8", "FN_IRTCREGISTER_OU8", "", "", "" },
|
||||
.{ "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 IdtPtr) void", "FN_IPTRCONSTIDTPTR_OVOID", "", "", "" },
|
||||
|
||||
|
@ -74,6 +76,7 @@ const types = .{
|
|||
.{ "fn (u8, u8) u16", "FN_IU8_IU8_OU16", "", "", "" },
|
||||
.{ "fn (u8, fn () callconv(.Naked) void) IdtError!void", "FN_IU8_IFNCCNAKEDOVOID_EIDTERROR_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, u32) void", "FN_IU16_IU32_OVOID", "", "", "" },
|
||||
.{ "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(.{}){};
|
||||
defer _ = gpa.deinit();
|
||||
const allocator = &gpa.allocator;
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
// All the string
|
||||
const imports_str = comptime genImports();
|
||||
|
|
|
@ -56,12 +56,12 @@ pub const CpuState = struct {
|
|||
user_ss: u32,
|
||||
};
|
||||
|
||||
pub const VmmPayload = switch (builtin.arch) {
|
||||
pub const VmmPayload = switch (builtin.cpu.arch) {
|
||||
.i386 => *x86_paging.Directory,
|
||||
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,
|
||||
else => unreachable,
|
||||
};
|
||||
|
@ -78,8 +78,21 @@ var KERNEL_VADDR_START: u32 = 0xC0100000;
|
|||
var KERNEL_VADDR_END: u32 = 0xC1100000;
|
||||
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 unmap(start: usize, end: usize, 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 {
|
||||
_ = 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 {
|
||||
return mock_framework.performAction("out", void, .{ port, data });
|
||||
|
@ -134,10 +147,14 @@ pub fn haltNoInterrupts() noreturn {
|
|||
}
|
||||
|
||||
pub fn initSerial(boot_payload: BootPayload) Serial {
|
||||
// Suppress unused variable warnings
|
||||
_ = boot_payload;
|
||||
return .{ .write = undefined };
|
||||
}
|
||||
|
||||
pub fn initTTY(boot_payload: BootPayload) TTY {
|
||||
// Suppress unused variable warnings
|
||||
_ = boot_payload;
|
||||
return .{
|
||||
.print = undefined,
|
||||
.setCursor = undefined,
|
||||
|
@ -148,6 +165,8 @@ pub fn initTTY(boot_payload: BootPayload) TTY {
|
|||
}
|
||||
|
||||
pub fn initMem(payload: BootPayload) Allocator.Error!mem.MemProfile {
|
||||
// Suppress unused variable warnings
|
||||
_ = payload;
|
||||
return MemProfile{
|
||||
.vaddr_end = @ptrCast([*]u8, &KERNEL_VADDR_END),
|
||||
.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;
|
||||
}
|
||||
|
||||
pub fn getDevices(allocator: *Allocator) Allocator.Error![]Device {
|
||||
pub fn getDevices(allocator: Allocator) Allocator.Error![]Device {
|
||||
// Suppress unused variable warnings
|
||||
_ = allocator;
|
||||
return &[_]Device{};
|
||||
}
|
||||
|
||||
|
@ -188,6 +216,8 @@ pub fn getDateTime() DateTime {
|
|||
}
|
||||
|
||||
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.
|
||||
// When I come on to the mem.zig testing, I'll fix :)
|
||||
//return mock_framework.performAction("init", void, mem_profile);
|
||||
|
|
|
@ -194,7 +194,7 @@ fn Mock() type {
|
|||
|
||||
// Test that the types match
|
||||
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
|
||||
const actual_function = getDataValue(expected_function, test_element);
|
||||
|
@ -219,13 +219,13 @@ fn Mock() type {
|
|||
|
||||
// Test that the types match
|
||||
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
|
||||
const actual_value = getDataValue(ExpectedType, elem);
|
||||
|
||||
// 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
|
||||
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);
|
||||
} else {
|
||||
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.
|
||||
if (self.named_actions.getEntry(fun_name)) |actions_kv| {
|
||||
// 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{
|
||||
.action = action_type,
|
||||
.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 {
|
||||
if (self.named_actions.getEntry(fun_name)) |kv_actions_list| {
|
||||
// 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
|
||||
if (action_list.*.first) |action_node| {
|
||||
const action = action_node.data;
|
||||
|
@ -331,7 +331,7 @@ fn Mock() type {
|
|||
|
||||
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: {
|
||||
// Now pop the action as we are going to use it
|
||||
|
@ -383,13 +383,13 @@ fn Mock() type {
|
|||
var it = self.named_actions.iterator();
|
||||
while (it.next()) |next| {
|
||||
// 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| {
|
||||
const action = action_node.data;
|
||||
switch (action.action) {
|
||||
ActionType.TestValue, ActionType.ConsumeFunctionCall => {
|
||||
// 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 => {
|
||||
// As this is a repeat action, the function will still be here
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
|
||||
const arch = @import("arch.zig").internals;
|
||||
const arch = @import("arch_mock.zig");
|
||||
const mock_framework = @import("mock_framework.zig");
|
||||
|
||||
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 {
|
||||
// Here we can do any testing we like with the parameters. e.g. test out of bounds
|
||||
expect(x < WIDTH);
|
||||
expect(y < HEIGHT);
|
||||
expect(x < WIDTH) catch @panic("Cursor x is out of bounds\n");
|
||||
expect(y < HEIGHT) catch @panic("Cursor x is out of bounds\n");
|
||||
}
|
||||
|
||||
pub fn mock_enableCursor() void {}
|
||||
|
|
|
@ -99,7 +99,7 @@ pub const RuntimeStep = struct {
|
|||
while (true) {
|
||||
const msg = self.get_msg() catch return true;
|
||||
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;
|
||||
defer self.builder.allocator.free(msg);
|
||||
// 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")) |_| {
|
||||
return false;
|
||||
} 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;
|
||||
defer self.builder.allocator.free(msg);
|
||||
// Print the line to see what is going on
|
||||
std.debug.warn("{s}\n", .{msg});
|
||||
if (std.mem.eql(u8, msg, "[emerg] (panic): Kernel panic: integer overflow")) {
|
||||
std.debug.print("{s}\n", .{msg});
|
||||
if (std.mem.eql(u8, msg, "[err] (panic): Kernel panic: integer overflow")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ pub const RuntimeStep = struct {
|
|||
const msg = self.get_msg() catch return false;
|
||||
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
|
||||
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();
|
||||
|
||||
// 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
|
||||
const res = self.test_func(self);
|
||||
|
@ -215,7 +215,7 @@ pub const RuntimeStep = struct {
|
|||
_ = try self.os_proc.kill();
|
||||
|
||||
// Join the thread
|
||||
thread.wait();
|
||||
thread.join();
|
||||
|
||||
// Free the rest of the queue
|
||||
while (self.msg_queue.get()) |node| {
|
||||
|
@ -248,7 +248,7 @@ pub const RuntimeStep = struct {
|
|||
return;
|
||||
},
|
||||
else => {
|
||||
std.debug.warn("Unexpected error: {}\n", .{e});
|
||||
std.debug.print("Unexpected error: {}\n", .{e});
|
||||
unreachable;
|
||||
},
|
||||
};
|
||||
|
@ -299,7 +299,7 @@ pub const RuntimeStep = struct {
|
|||
pub fn create(builder: *Builder, test_mode: TestMode, qemu_args: [][]const u8) *RuntimeStep {
|
||||
const runtime_step = builder.allocator.create(RuntimeStep) catch unreachable;
|
||||
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,
|
||||
.msg_queue = Queue.init(),
|
||||
.os_proc = undefined,
|
||||
|
|
Loading…
Reference in a new issue