Skip to content
This repository has been archived by the owner on Jun 7, 2024. It is now read-only.

Commit

Permalink
Paging and general refactor
Browse files Browse the repository at this point in the history
- VMM
- Paging for x86_64
- Updated to zig master
- Now exceptions halt the OS, to avoid double faults
- Because of the removal of `main_mod_path` (see ziglang/zig#18160) the file with the entry point has to be directly on the module root path. To solve this, we now have a `src/main.zig` that does a `usingnamespace` with a `switch` for the appropiate `start.zig` file. As a benefit, some generic functions like `panic` or the `root.os` abstraction layer can be here.
- HAL system, mainly to abstract `cpu.zig`
  • Loading branch information
Arnau478 committed Jan 14, 2024
1 parent c2db0f7 commit df0ea9c
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 37 deletions.
17 changes: 8 additions & 9 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,31 @@ fn getFeatures(comptime arch: std.Target.Cpu.Arch) struct { add: std.Target.Cpu.
pub fn build(b: *std.Build) void {
const features = getFeatures(kernel_config.arch);

const target: std.zig.CrossTarget = .{
const target = b.resolveTargetQuery(.{
.cpu_arch = kernel_config.arch,
.os_tag = .freestanding,
.abi = .none,
.cpu_features_add = features.add,
.cpu_features_sub = features.sub,
};
});

const optimize = b.standardOptimizeOption(.{});

const kernel = b.addExecutable(.{
.name = "kernel",
.root_source_file = .{ .path = "kernel/src/arch/" ++ @tagName(kernel_config.arch) ++ "/start.zig" },
.main_mod_path = .{ .path = "kernel/src" },
.root_source_file = .{ .path = "kernel/src/main.zig" },
.target = target,
.optimize = optimize,
.single_threaded = true,
.code_model = .kernel,
.pic = true,
});
kernel.setLinkerScript(.{ .path = "kernel/linker-" ++ @tagName(kernel_config.arch) ++ ".ld" });
kernel.pie = true;
if (kernel_config.arch.isX86()) kernel.code_model = .kernel;

const kernel_options = b.addOptions();
kernel_options.addOption(std.SemanticVersion, "version", version);

kernel.addOptions("options", kernel_options);
kernel.root_module.addOptions("options", kernel_options);

const kernel_step = b.step("kernel", "Build the kernel");
kernel_step.dependOn(&b.addInstallArtifact(kernel, .{}).step);
Expand Down Expand Up @@ -108,10 +107,10 @@ pub fn build(b: *std.Build) void {
qemu_step.dependOn(&qemu_cmd.step);

const kernel_unit_tests = b.addTest(.{
.root_source_file = .{ .path = "kernel/src/arch/" ++ @tagName(kernel_config.arch) ++ "/start.zig" },
.root_source_file = .{ .path = "kernel/src/main.zig" },
.optimize = optimize,
});
kernel_unit_tests.addOptions("options", kernel_options);
kernel_unit_tests.root_module.addOptions("options", kernel_options);

const run_kernel_unit_tests = b.addRunArtifact(kernel_unit_tests);

Expand Down
9 changes: 9 additions & 0 deletions kernel/src/arch/x86_64/hal.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const cpu = @import("cpu.zig");

pub fn halt() noreturn {
cpu.halt();
}

pub fn debugcon(byte: u8) void {
cpu.outb(0xE9, byte);
}
1 change: 1 addition & 0 deletions kernel/src/arch/x86_64/int.zig
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ fn getVector(comptime i: u8) ?*const fn () callconv(.Interrupt) void {
break :blk struct {
fn vector() callconv(.Interrupt) void {
log.err(std.fmt.comptimePrint("Exception: {s}[{d}] ({s})", .{ exception.getMnemonic(), exception_i, exception.getDescription() }), .{});
cpu.halt();
}
}.vector;
},
Expand Down
106 changes: 106 additions & 0 deletions kernel/src/arch/x86_64/paging.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
const std = @import("std");
const vmm = @import("../../mm/vmm.zig");
const pmm = @import("../../mm/pmm.zig");

const log = std.log.scoped(.paging);

/// An abstraction of the page mapping
pub const PageMap = struct {
root: u64 = undefined,

/// Load the map
pub fn load(self: PageMap) void {
loadSpace(self.root);
}

/// Save the currently loaded map
pub fn save(self: *PageMap) void {
self.root = saveSpace();
}

/// Map a physical page to a virtual page
pub fn mapPage(self: *PageMap, flags: vmm.MapFlags, virt: u64, phys: u64, huge: bool) !void {
var root: [*]u64 = @ptrFromInt(vmm.toHigherHalf(self.root));

const indices = [4]u64{
getIndex(virt, 39), getIndex(virt, 30),
getIndex(virt, 21), getIndex(virt, 12),
};

root = (try getNextLevel(root, indices[0], true)).?;
root = (try getNextLevel(root, indices[1], true)).?;

if (huge) {
root[indices[2]] = createPte(flags, phys, true);
} else {
root = (try getNextLevel(root, indices[2], true)).?;
root[indices[3]] = createPte(flags, phys, false);
}
}
};

fn getNextLevel(level: [*]u64, index: usize, create: bool) !?[*]u64 {
// If entry not present
if ((level[index] & 1) == 0) {
if (!create) return null;

const table_ptr = @intFromPtr((try pmm.allocator.alloc(u8, 4096)).ptr);
level[index] = table_ptr;
level[index] |= 0b111;
}

return @ptrFromInt(vmm.toHigherHalf(level[index] & ~@as(u64, 0x1FF)));
}

fn createPte(flags: vmm.MapFlags, phys_ptr: u64, huge: bool) u64 {
var result: u64 = 1; // Present

const pat_bit = if (huge) @as(u64, 1) << 12 else @as(u64, 1) << 7;

if (flags.write) result |= @as(u64, 1) << 1;
if (!flags.execute) result |= @as(u64, 1) << 63;
if (flags.user) result |= @as(u64, 1) << 2;
if (huge) result |= @as(u64, 1) << 7;

switch (flags.cache_type) {
.uncached => {
result |= @as(u64, 1) << 4;
result |= @as(u64, 1) << 3;
result &= ~pat_bit;
},
.write_combining => {
result |= pat_bit;
result |= @as(u64, 1) << 4;
result |= @as(u64, 1) << 3;
},
.write_protect => {
result |= pat_bit;
result |= @as(u64, 1) << 4;
result &= ~(@as(u64, 1) << 3);
},
.write_back => {},
}

result |= phys_ptr;
return result;
}

inline fn getIndex(virt: u64, comptime shift: u6) u64 {
return ((virt & (0x1FF << shift)) >> shift);
}

inline fn loadSpace(root: u64) void {
asm volatile ("mov %[root], %%cr3"
:
: [root] "r" (root),
: "memory"
);
}

inline fn saveSpace() void {
asm volatile ("mov %%cr3, %[root]"
: [root] "=r" (-> u64),
:
: "memory"
);
}
33 changes: 5 additions & 28 deletions kernel/src/arch/x86_64/start.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,7 @@ const cpu = @import("cpu.zig");
const gdt = @import("gdt.zig");
const int = @import("int.zig");
const pmm = @import("../../mm/pmm.zig");

pub const os = @import("../../os.zig");

pub const std_options = struct {
pub fn logFn(comptime message_level: std.log.Level, comptime scope: @Type(.EnumLiteral), comptime format: []const u8, args: anytype) void {
var log_allocator_buf: [2048]u8 = undefined;
var log_fba = std.heap.FixedBufferAllocator.init(&log_allocator_buf);
const log_allocator = log_fba.allocator();

const msg = std.fmt.allocPrint(log_allocator, switch (message_level) {
.info => "\x1b[34m",
.warn => "\x1b[33m",
.err => "\x1b[31m",
.debug => "\x1b[90m",
} ++ "[" ++ @tagName(message_level) ++ "]\x1b[0m (" ++ @tagName(scope) ++ ") " ++ format ++ "\n", args) catch "LOG_FN_OOM";

for (msg) |char| {
cpu.outb(0xE9, char);
}
}
};

pub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
log.err("{s}", .{msg});
log.err("Root-level error, panicking", .{});

cpu.halt();
}
const vmm = @import("../../mm/vmm.zig");

const log = std.log.scoped(.core);

Expand All @@ -55,9 +28,13 @@ fn _start() callconv(.C) noreturn {

fn init() !void {
log.info("Booting chain (v{})", .{options.version});

gdt.init();
int.init();
pmm.init();
vmm.init();

log.info("Hello from chain", .{});
}

test {
Expand Down
6 changes: 6 additions & 0 deletions kernel/src/hal.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const builtin = @import("builtin");

pub usingnamespace switch (builtin.cpu.arch) {
.x86_64 => @import("arch/x86_64/hal.zig"),
else => |other| @compileError("Unimplemented for " ++ @tagName(other)),
};
12 changes: 12 additions & 0 deletions kernel/src/limine.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,15 @@ pub const MemoryMapRequest = extern struct {
revision: u64 = 0,
response: ?*MemoryMapResponse = null,
};

pub const KernelAddressResponse = extern struct {
revision: u64,
physical_base: u64,
virtual_base: u64,
};

pub const KernelAddressRequest = extern struct {
id: [4]u64 = magic(0x71ba76863cc55f63, 0xb2644a48c516a487),
revision: u64 = 0,
response: ?*KernelAddressResponse = null,
};
42 changes: 42 additions & 0 deletions kernel/src/main.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const std = @import("std");
const builtin = @import("builtin");
const pmm = @import("mm/pmm.zig");
const hal = @import("hal.zig");

pub const os = @import("os.zig");

const log = std.log.scoped(.core);

pub const std_options = struct {
pub fn logFn(comptime message_level: std.log.Level, comptime scope: @Type(.EnumLiteral), comptime format: []const u8, args: anytype) void {
var log_allocator_buf: [2048]u8 = undefined;
var log_fba = std.heap.FixedBufferAllocator.init(&log_allocator_buf);
const log_allocator = log_fba.allocator();

const msg = std.fmt.allocPrint(log_allocator, switch (message_level) {
.info => "\x1b[34m",
.warn => "\x1b[33m",
.err => "\x1b[31m",
.debug => "\x1b[90m",
} ++ "[" ++ @tagName(message_level) ++ "]\x1b[0m (" ++ @tagName(scope) ++ ") " ++ format ++ "\n", args) catch "LOG_FN_OOM";

for (msg) |char| {
hal.debugcon(char);
}
}
};

pub fn panic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
log.err("{s}", .{msg});

hal.halt();
}

pub const heap = struct {
pub const page_allocator = pmm.allocator;
};

pub usingnamespace switch (builtin.cpu.arch) {
.x86_64 => @import("arch/x86_64/start.zig"),
else => |other| @compileError("Unimplemented for " ++ @tagName(other)),
};
Loading

0 comments on commit df0ea9c

Please sign in to comment.