feat(loader, kernel): impl part of loader and initialize kernel structure
This commit is contained in:
3
arch/x86_64/arch.zig
Normal file
3
arch/x86_64/arch.zig
Normal file
@@ -0,0 +1,3 @@
|
||||
pub const io = @import("io.zig");
|
||||
pub const processor = @import("processor.zig");
|
||||
pub const mem = @import("mem.zig");
|
||||
7
arch/x86_64/boot/boot.zig
Normal file
7
arch/x86_64/boot/boot.zig
Normal file
@@ -0,0 +1,7 @@
|
||||
const boot_consts = @cImport({
|
||||
@cInclude("boot.h");
|
||||
});
|
||||
|
||||
pub const BOOT_HEAP_SIZE: usize = boot_consts.BOOT_HEAP_SIZE;
|
||||
pub const BOOT_STACK_SIZE: usize = boot_consts.BOOT_STACK_SIZE;
|
||||
pub const LOAD_PHYSICAL_ADDR: usize = boot_consts.LOAD_PHYSICAL_ADDR;
|
||||
159
arch/x86_64/boot/build_boot.zig
Normal file
159
arch/x86_64/boot/build_boot.zig
Normal file
@@ -0,0 +1,159 @@
|
||||
const std = @import("std");
|
||||
const Step = std.Build.Step;
|
||||
const OptimizeMode = std.builtin.OptimizeMode;
|
||||
|
||||
fn getTarget(b: *std.Build) std.Build.ResolvedTarget {
|
||||
var query: std.Target.Query = .{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .freestanding,
|
||||
.abi = .none,
|
||||
};
|
||||
const Features = std.Target.x86.Feature;
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.mmx));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.sse));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.sse2));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.sse3));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.ssse3));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.sse4_1));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.sse4_2));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.avx));
|
||||
query.cpu_features_sub.addFeature(@intFromEnum(Features.avx2));
|
||||
query.cpu_features_add.addFeature(@intFromEnum(Features.soft_float));
|
||||
const target = b.resolveTargetQuery(query);
|
||||
return target;
|
||||
}
|
||||
var tool_extract_symbol: *Step.InstallArtifact = undefined;
|
||||
var tool_generate_image: *Step.InstallArtifact = undefined;
|
||||
var tool_compress_kernel: *Step.InstallArtifact = undefined;
|
||||
|
||||
fn buildTool(b: *std.Build) void {
|
||||
const mvzr = b.dependency("mvzr", .{}).module("mvzr");
|
||||
const elfy = b.dependency("elfy", .{}).module("elfy");
|
||||
const compile_extract_symbol = b.addExecutable(.{
|
||||
.name = "symbol_extract",
|
||||
.root_module = b.addModule("symbol_extract", .{
|
||||
.root_source_file = b.path("arch/x86_64/boot/build_tool/symbol_extract.zig"),
|
||||
.target = b.resolveTargetQuery(.{
|
||||
.cpu_arch = @import("builtin").target.cpu.arch,
|
||||
}),
|
||||
.optimize = OptimizeMode.ReleaseSafe,
|
||||
}),
|
||||
});
|
||||
compile_extract_symbol.root_module.addImport("mvzr", mvzr);
|
||||
compile_extract_symbol.root_module.addImport("elfy", elfy);
|
||||
tool_extract_symbol = b.addInstallArtifact(compile_extract_symbol, .{
|
||||
.dest_dir = .{ .override = .{ .custom = "build_tool" } }
|
||||
});
|
||||
const compile_generate_image = b.addExecutable(.{
|
||||
.name = "generate_image",
|
||||
.root_module = b.addModule("generate_image", .{
|
||||
.root_source_file = b.path("arch/x86_64/boot/build_tool/generate_image.zig"),
|
||||
.target = b.resolveTargetQuery(.{
|
||||
.cpu_arch = @import("builtin").target.cpu.arch,
|
||||
}),
|
||||
.optimize = OptimizeMode.ReleaseSafe,
|
||||
}),
|
||||
});
|
||||
tool_generate_image = b.addInstallArtifact(compile_generate_image, .{
|
||||
.dest_dir = .{ .override = .{ .custom = "build_tool" } }
|
||||
});
|
||||
const compile_compress_kernel = b.addExecutable(.{
|
||||
.name = "compress_kernel",
|
||||
.root_module = b.addModule("compress_kernel", .{
|
||||
.root_source_file = b.path("arch/x86_64/boot/build_tool/compress_kernel.zig"),
|
||||
.target = b.resolveTargetQuery(.{
|
||||
.cpu_arch = @import("builtin").target.cpu.arch,
|
||||
}),
|
||||
.optimize = OptimizeMode.ReleaseSafe,
|
||||
}),
|
||||
});
|
||||
tool_compress_kernel = b.addInstallArtifact(compile_compress_kernel, .{
|
||||
.dest_dir = .{ .override = .{ .custom = "build_tool" } }
|
||||
});
|
||||
}
|
||||
fn buildHeader(b: *std.Build, optimize: OptimizeMode, kcapsule: *Step.Compile) *Step.ObjCopy {
|
||||
const target = getTarget(b);
|
||||
const copy_header = b.addWriteFiles();
|
||||
const include_dir = copy_header.addCopyDirectory(b.path("arch/x86_64/boot/include"), "include", .{});
|
||||
const symbol_extract = b.addRunArtifact(tool_extract_symbol.artifact);
|
||||
symbol_extract.step.dependOn(&tool_extract_symbol.step);
|
||||
symbol_extract.addFileArg(kcapsule.getEmittedBin());
|
||||
symbol_extract.addArgs(&[_][] const u8{
|
||||
"^(_end|_edata|startup_32|startup_64)$",
|
||||
"CAP_"
|
||||
});
|
||||
symbol_extract.addFileArg(include_dir.join(b.allocator, "kcapsule.h") catch @panic("OOM"));
|
||||
symbol_extract.step.dependOn(©_header.step);
|
||||
symbol_extract.step.dependOn(&kcapsule.step);
|
||||
const header_elf = b.addExecutable(.{
|
||||
.name = "header.bin",
|
||||
.root_module = b.addModule("header", .{
|
||||
.root_source_file = null,
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
});
|
||||
header_elf.root_module.addAssemblyFile(b.path("arch/x86_64/boot/header.S"));
|
||||
header_elf.root_module.addIncludePath(include_dir);
|
||||
header_elf.setLinkerScript(b.path("arch/x86_64/boot/header.ld"));
|
||||
header_elf.step.dependOn(&symbol_extract.step);
|
||||
const header = b.addObjCopy(header_elf.getEmittedBin(), .{
|
||||
.format = .bin,
|
||||
});
|
||||
return header;
|
||||
}
|
||||
fn buildKcapsule(b: *std.Build,
|
||||
optimize: OptimizeMode,
|
||||
kernel: *Step.Compile) *Step.Compile {
|
||||
const target = getTarget(b);
|
||||
const compress = b.addRunArtifact(tool_compress_kernel.artifact);
|
||||
compress.step.dependOn(&kernel.step);
|
||||
compress.addFileArg(kernel.getEmittedBin());
|
||||
const kernelz_path = kernel.getEmittedBinDirectory().join(b.allocator, "kernelz") catch @panic("OOM");
|
||||
const payload_asm_path = kernel.getEmittedBinDirectory().join(b.allocator, "payload.S") catch @panic("OOM");
|
||||
compress.addFileArg(kernelz_path);
|
||||
compress.addFileArg(payload_asm_path);
|
||||
|
||||
const arch_module = b.addModule("arch", .{
|
||||
.root_source_file = b.path("arch/x86_64/arch.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.pic = true,
|
||||
});
|
||||
const loader_module = b.addModule("loader", .{
|
||||
.root_source_file = b.path("arch/x86_64/boot/extractor.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.pic = true,
|
||||
});
|
||||
loader_module.addImport("arch", arch_module);
|
||||
loader_module.addIncludePath(b.path("arch/x86_64/boot/include"));
|
||||
loader_module.addAssemblyFile(payload_asm_path);
|
||||
const kcapsule = b.addExecutable(.{
|
||||
.name = "kcapsule",
|
||||
.use_lld = true,
|
||||
.use_llvm = true,
|
||||
.root_module = loader_module,
|
||||
});
|
||||
kcapsule.pie = true;
|
||||
kcapsule.setLinkerScript(b.path("arch/x86_64/boot/kcapsule.ld"));
|
||||
kcapsule.root_module.addAssemblyFile(b.path("arch/x86_64/boot/head.S"));
|
||||
kcapsule.step.dependOn(&compress.step);
|
||||
return kcapsule;
|
||||
}
|
||||
pub fn buildBootImage(b: *std.Build, kernel: *Step.Compile) void {
|
||||
buildTool(b);
|
||||
const optimize = OptimizeMode.Debug;
|
||||
const kcapsule = buildKcapsule(b, optimize, kernel);
|
||||
const header = buildHeader(b, optimize, kcapsule);
|
||||
const kcapsule_install = b.addInstallArtifact(kcapsule, .{});
|
||||
const kcapsule_bin = b.addObjCopy(kcapsule.getEmittedBin(), .{
|
||||
.format = .bin,
|
||||
});
|
||||
const image = b.addRunArtifact(tool_generate_image.artifact);
|
||||
image.addFileArg(header.getOutput());
|
||||
image.addFileArg(kcapsule_bin.getOutput());
|
||||
image.addArg(std.fs.path.join(b.allocator, &[_][]const u8{ b.install_path, "yukiImage" }) catch @panic("OOM"));
|
||||
b.getInstallStep().dependOn(&kcapsule_install.step);
|
||||
b.getInstallStep().dependOn(&image.step);
|
||||
}
|
||||
57
arch/x86_64/boot/build_tool/compress_kernel.zig
Normal file
57
arch/x86_64/boot/build_tool/compress_kernel.zig
Normal file
@@ -0,0 +1,57 @@
|
||||
const std = @import("std");
|
||||
const Compress = std.compress.flate.Compress;
|
||||
const Dir = std.Io.Dir;
|
||||
const SIZE_ALIGN: usize = 0x200;
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
const args = try init.minimal.args.toSlice(init.arena.allocator());
|
||||
|
||||
if (args.len != 4) {
|
||||
std.debug.print("Usage: {s} <kernel_bin> <output_file> <assembly_file>\n", .{args[0]});
|
||||
std.process.exit(1);
|
||||
}
|
||||
const kernel_bin_path = args[1];
|
||||
const output_path = args[2];
|
||||
const assembly_path = args[3];
|
||||
std.debug.print("Compressing kernel: {s} -> {s}\n", .{kernel_bin_path, output_path});
|
||||
|
||||
const kernel_file = try Dir.cwd().openFile(init.io, kernel_bin_path, .{});
|
||||
defer kernel_file.close(init.io);
|
||||
|
||||
const compressed_file = try Dir.cwd().createFile(init.io, output_path, .{ .truncate = true });
|
||||
defer compressed_file.close(init.io);
|
||||
|
||||
var read_buffer: [4096]u8 = undefined;
|
||||
var write_buffer: [4096]u8 = undefined;
|
||||
var work_buffer: [std.compress.flate.max_window_len]u8 = undefined;
|
||||
|
||||
var writer = compressed_file.writer(init.io, &write_buffer);
|
||||
var reader = kernel_file.reader(init.io, &[0]u8{});
|
||||
var compressor = try Compress.init(&writer.interface, &work_buffer, .gzip, .best);
|
||||
var compressor_writer = &compressor.writer;
|
||||
var total_read: usize = 0;
|
||||
while (true) {
|
||||
const read_bytes = try reader.interface.readSliceShort(&read_buffer);
|
||||
if (read_bytes == 0) break;
|
||||
total_read += read_bytes;
|
||||
try compressor_writer.writeAll(read_buffer[0..read_bytes]);
|
||||
}
|
||||
try compressor_writer.flush();
|
||||
const aligned_size = (total_read + SIZE_ALIGN - 1) & ~(SIZE_ALIGN - 1);
|
||||
var assembly_file = try Dir.cwd().createFile(init.io, assembly_path, .{ .truncate = true });
|
||||
defer assembly_file.close(init.io);
|
||||
var assembly_writer = assembly_file.writer(init.io, &[0]u8{});
|
||||
try assembly_writer.interface.print(
|
||||
\\/* Auto-generated compressed kernel data */
|
||||
\\ .section .rodata.compressed,"a"
|
||||
\\ .global compressed_kernel_data
|
||||
\\compressed_kernel_data:
|
||||
\\ .incbin "{s}"
|
||||
\\compressed_end:
|
||||
\\ .set compressed_kernel_size, compressed_end - compressed_kernel_data
|
||||
\\ .set uncompressed_kernel_size, {d}
|
||||
\\ .global compressed_kernel_size
|
||||
\\ .global uncompressed_kernel_size
|
||||
, .{output_path, aligned_size});
|
||||
try assembly_writer.interface.flush();
|
||||
std.debug.print("Uncompressed aligned size: 0x{x} bytes\n", .{aligned_size});
|
||||
}
|
||||
50
arch/x86_64/boot/build_tool/generate_image.zig
Normal file
50
arch/x86_64/boot/build_tool/generate_image.zig
Normal file
@@ -0,0 +1,50 @@
|
||||
const std = @import("std");
|
||||
const Dir = std.Io.Dir;
|
||||
const ALIGN_SIZE: usize = 4096;
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
const args = try init.minimal.args.toSlice(init.arena.allocator());
|
||||
if (args.len != 4) {
|
||||
std.debug.print("Usage: {s} <header_file> <kcapsule_file> <output_file>\n", .{args[0]});
|
||||
std.process.exit(1);
|
||||
}
|
||||
const header_path = args[1];
|
||||
const kcapsule_path = args[2];
|
||||
const output_path = args[3];
|
||||
var image = try Dir.cwd().createFile(init.io, output_path, .{ .truncate = true });
|
||||
defer image.close(init.io);
|
||||
|
||||
var image_buffer: [4096]u8 = undefined;
|
||||
var w = image.writer(init.io, &image_buffer);
|
||||
var read_buffer: [4096]u8 = undefined;
|
||||
|
||||
const header_file = try Dir.cwd().openFile(init.io, header_path, .{});
|
||||
var r = header_file.reader(init.io, &[0]u8{});
|
||||
var written: usize = 0;
|
||||
while (true) {
|
||||
const read_bytes = try r.interface.readSliceShort(&read_buffer);
|
||||
if (read_bytes == 0) break;
|
||||
try w.interface.writeAll(read_buffer[0..read_bytes]);
|
||||
written += read_bytes;
|
||||
}
|
||||
header_file.close(init.io);
|
||||
|
||||
if (written % ALIGN_SIZE != 0) {
|
||||
var padding_size = ALIGN_SIZE - (written % ALIGN_SIZE);
|
||||
@memset(read_buffer[0..@min(padding_size, read_buffer.len)], 0);
|
||||
while (padding_size > 0) {
|
||||
const to_write = @min(padding_size, read_buffer.len);
|
||||
try w.interface.writeAll(read_buffer[0..to_write]);
|
||||
padding_size -= to_write;
|
||||
}
|
||||
}
|
||||
const kcapsule_file = try Dir.cwd().openFile(init.io, kcapsule_path, .{});
|
||||
r = kcapsule_file.reader(init.io, &[0]u8{});
|
||||
while (true) {
|
||||
const read_bytes = try r.interface.readSliceShort(&read_buffer);
|
||||
if (read_bytes == 0) break;
|
||||
try w.interface.writeAll(read_buffer[0..read_bytes]);
|
||||
written += read_bytes;
|
||||
}
|
||||
kcapsule_file.close(init.io);
|
||||
try w.interface.flush();
|
||||
}
|
||||
41
arch/x86_64/boot/build_tool/symbol_extract.zig
Normal file
41
arch/x86_64/boot/build_tool/symbol_extract.zig
Normal file
@@ -0,0 +1,41 @@
|
||||
const std = @import("std");
|
||||
const Dir = std.Io.Dir;
|
||||
|
||||
const elfy = @import("elfy");
|
||||
const mvzr = @import("mvzr");
|
||||
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
var gpa: std.heap.DebugAllocator(.{}) = .init;
|
||||
const allocator = gpa.allocator();
|
||||
defer _ = gpa.deinit();
|
||||
|
||||
const args = try init.minimal.args.toSlice(init.arena.allocator());
|
||||
|
||||
if (args.len != 5) {
|
||||
std.debug.print("Usage: {s} <source_file> <pattern> <prefix> <output_file>\n", .{args[0]});
|
||||
std.process.exit(1);
|
||||
}
|
||||
const input_path = args[1];
|
||||
const pattern = args[2];
|
||||
const prefix = args[3];
|
||||
const output_path = args[4];
|
||||
const re = mvzr.compile(pattern) orelse @panic("Failed to compile regex pattern");
|
||||
|
||||
var file = try Dir.cwd().createFile(init.io, output_path, .{ .truncate = true });
|
||||
defer file.close(init.io);
|
||||
var w = file.writer(init.io, &[0]u8{});
|
||||
|
||||
_ = try w.interface.write("/* Auto-generated symbol extract header */\n#pragma once\n");
|
||||
var binary = try elfy.Elf.init(init.io, input_path, .ReadOnly, allocator);
|
||||
defer binary.deinit();
|
||||
|
||||
var symbols = try binary.getIterator(elfy.ElfSymbol);
|
||||
while (try symbols.next()) |symbol| {
|
||||
const name = try binary.getSymbolName(symbol);
|
||||
if (re.isMatch(name)) {
|
||||
try w.interface.print("#define {s}{s} 0x{x}\n", .{prefix, name, symbol.getValue()});
|
||||
}
|
||||
}
|
||||
try w.interface.flush();
|
||||
}
|
||||
|
||||
82
arch/x86_64/boot/cmdline.zig
Normal file
82
arch/x86_64/boot/cmdline.zig
Normal file
@@ -0,0 +1,82 @@
|
||||
fn isWhitespace(c: u8) bool {
|
||||
return c == ' ' or c == '\t' or c == '\n' or c == '\r';
|
||||
}
|
||||
pub const Cmdline = struct {
|
||||
ptr: []const u8,
|
||||
pub fn init(ptr: []const u8) Cmdline {
|
||||
return Cmdline{
|
||||
.ptr = ptr,
|
||||
};
|
||||
}
|
||||
fn _parseArg(self: *const Cmdline, key: []const u8, buf: []u8) ?usize {
|
||||
var state: union(enum) {
|
||||
search_key,
|
||||
compare_key: usize,
|
||||
copy_value: usize,
|
||||
skip_arg
|
||||
} = .search_key;
|
||||
var i: usize = 0;
|
||||
while (i < self.ptr.len) {
|
||||
const c = self.ptr[i];
|
||||
switch (state) {
|
||||
.search_key => {
|
||||
if (isWhitespace(c)) {
|
||||
i = i + 1;
|
||||
continue;
|
||||
}
|
||||
state = .{ .compare_key = 0};
|
||||
},
|
||||
.compare_key => |key_index| {
|
||||
if (key_index < key.len) {
|
||||
if (c == key[key_index]) {
|
||||
state = .{ .compare_key = key_index + 1 };
|
||||
} else {
|
||||
state = .skip_arg;
|
||||
}
|
||||
} else {
|
||||
if (c == '=') {
|
||||
state = .{ .copy_value = 0 };
|
||||
} else if (isWhitespace(c)) {
|
||||
return 0;
|
||||
} else {
|
||||
state = .skip_arg;
|
||||
}
|
||||
}
|
||||
i = i + 1;
|
||||
},
|
||||
.skip_arg => {
|
||||
if (isWhitespace(c)) {
|
||||
state = .search_key;
|
||||
}
|
||||
i = i + 1;
|
||||
},
|
||||
.copy_value => |buf_index| {
|
||||
if (isWhitespace(c) or buf_index >= buf.len) {
|
||||
return buf_index;
|
||||
}
|
||||
buf[buf_index] = c;
|
||||
state = .{ .copy_value = buf_index + 1 };
|
||||
i = i + 1;
|
||||
},
|
||||
}
|
||||
}
|
||||
switch (state) {
|
||||
.copy_value => |buf_index| return buf_index,
|
||||
else => return null
|
||||
}
|
||||
}
|
||||
pub fn parseArg(self: *const Cmdline, key: []const u8, buf: []u8) ?usize {
|
||||
return self._parseArg(key, buf);
|
||||
}
|
||||
pub fn parseArgBool(self: *const Cmdline, key: []const u8) bool {
|
||||
const result = self._parseArg(key, &[_]u8{});
|
||||
if (result) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
118
arch/x86_64/boot/early_serial_console.zig
Normal file
118
arch/x86_64/boot/early_serial_console.zig
Normal file
@@ -0,0 +1,118 @@
|
||||
const std = @import("std");
|
||||
const Cmdline = @import("cmdline.zig").Cmdline;
|
||||
const io = @import("arch").io;
|
||||
|
||||
const PREDEFINED_PORTS: [2]u16 = .{
|
||||
0x3F8, // ttyS0
|
||||
0x2F8, // ttyS1
|
||||
};
|
||||
var serial_writer: ?SerialWriter = null;
|
||||
// Parse earlyprintk argument from cmdline
|
||||
// Format: earlyprintk=serial,port,baudrate, port can either be ioport address (e.g., 0x3F8) or
|
||||
// a predefined name (e.g., ttyS0/ttyS1).
|
||||
fn parseEarlyprintk(cmdline: *const Cmdline) ?struct { port: u16, baudrate: u32 } {
|
||||
var buf = [_]u8{0} ** 32;
|
||||
const len = cmdline.parseArg("earlyprintk", &buf) orelse 0;
|
||||
if (len == 0) return null;
|
||||
const arg = buf[0..len];
|
||||
var it = std.mem.splitAny(u8, arg, ",");
|
||||
if(std.mem.eql(u8, it.next() orelse "", "serial") == false) {
|
||||
return null;
|
||||
}
|
||||
const port_str = it.next() orelse return null;
|
||||
var port: u16 = undefined;
|
||||
if (port_str.len == 5 and std.mem.startsWith(u8, port_str, "ttyS")) {
|
||||
const port_idx = std.fmt.parseInt(u8, port_str[4..5], 10) catch return null;
|
||||
if (port_idx >= PREDEFINED_PORTS.len) {
|
||||
return null;
|
||||
}
|
||||
port = PREDEFINED_PORTS[port_idx];
|
||||
} else if (std.fmt.parseInt(u16, port_str, 16) catch null) |port_val| {
|
||||
port = port_val;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
const baudrate_str = it.next() orelse return null;
|
||||
const baudrate = std.fmt.parseInt(u32, baudrate_str, 10) catch return null;
|
||||
return .{ .port = port, .baudrate = baudrate };
|
||||
}
|
||||
|
||||
fn serialInit(port: u16, baudrate: u32) void {
|
||||
const divisor: u16 = @intCast(115200 / baudrate);
|
||||
// Disable interrupts
|
||||
io.outb(port + 1, 0x00);
|
||||
// Disable FIFO
|
||||
io.outb(port + 2, 0x00);
|
||||
// Set 8 data bits, 1 stop bit, no parity
|
||||
io.outb(port + 3, 0x80);
|
||||
const c = io.inb(port + 3);
|
||||
// Enable DLAB
|
||||
io.outb(port + 3, c | 0x80);
|
||||
// Set divisor low byte
|
||||
io.outb(port + 0, @intCast(divisor & 0x00FF));
|
||||
// Set divisor high byte
|
||||
io.outb(port + 1, @intCast((divisor >> 8) & 0x00FF));
|
||||
io.outb(port + 3, c & ~@as(u8, 0x80));
|
||||
}
|
||||
|
||||
pub fn earlyConsoleInit(cmdline: *const Cmdline) void {
|
||||
const result = parseEarlyprintk(cmdline) orelse return;
|
||||
serialInit(result.port, result.baudrate);
|
||||
serial_writer = SerialWriter.init(result.port);
|
||||
}
|
||||
const SerialWriter = struct {
|
||||
port: u16,
|
||||
interface: std.Io.Writer,
|
||||
var WRITER_VTABLE: std.Io.Writer.VTable = undefined;
|
||||
pub fn init(port: u16) SerialWriter {
|
||||
WRITER_VTABLE = .{
|
||||
.drain = SerialWriter.drain,
|
||||
};
|
||||
var sw = SerialWriter{
|
||||
.port = port,
|
||||
.interface = undefined,
|
||||
};
|
||||
sw.interface = .{
|
||||
.buffer = &[0]u8{},
|
||||
.vtable = @call(.never_inline, getWriterVTable, .{}),
|
||||
};
|
||||
return sw;
|
||||
}
|
||||
pub fn writer(self: *SerialWriter) *std.Io.Writer {
|
||||
return &self.interface;
|
||||
}
|
||||
fn getWriterVTable() *const std.Io.Writer.VTable {
|
||||
return &WRITER_VTABLE;
|
||||
}
|
||||
// fn getWriterDrain() *const @TypeOf(SerialWriter.drain) {
|
||||
// return SerialWriter.drain;
|
||||
// }
|
||||
fn drain(self: *std.Io.Writer, buf: []const []const u8, splat: usize) error{}!usize {
|
||||
const sw: *SerialWriter = @fieldParentPtr("interface", self);
|
||||
var written: usize = 0;
|
||||
for (buf, 0..buf.len) |part, i| {
|
||||
const repeat = if (i == buf.len - 1) splat else 1;
|
||||
for (0..repeat) |_| {
|
||||
for (part) |c| {
|
||||
SerialWriter.putchar(sw, c);
|
||||
written += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
fn putchar(self: *const SerialWriter, c: u8) void {
|
||||
var timeout: usize = 0xffff;
|
||||
while(io.inb(self.port + 5) & 0x20 == 0 and timeout > 0) {
|
||||
timeout -= 1;
|
||||
asm volatile ("pause"
|
||||
::: .{ .memory = true }
|
||||
);
|
||||
}
|
||||
io.outb(self.port, c);
|
||||
}
|
||||
};
|
||||
pub fn dprint(comptime fmt: []const u8, args: anytype) void {
|
||||
var sw = serial_writer orelse return;
|
||||
_ = sw.writer().print(fmt, args) catch {};
|
||||
}
|
||||
46
arch/x86_64/boot/extractor.zig
Normal file
46
arch/x86_64/boot/extractor.zig
Normal file
@@ -0,0 +1,46 @@
|
||||
const std = @import("std");
|
||||
const BootParams = @import("params.zig").BootParams;
|
||||
const early_serial_console = @import("early_serial_console.zig");
|
||||
const Cmdline = @import("cmdline.zig").Cmdline;
|
||||
const payload = @import("payload.zig");
|
||||
const multiboot = @import("multiboot.zig");
|
||||
const Decompress = std.compress.flate.Decompress;
|
||||
const relocate = @import("relocate.zig");
|
||||
const ident_map = @import("ident_map.zig");
|
||||
|
||||
comptime {
|
||||
@export(&relocate.relocateSelf, .{
|
||||
.name = "relocateSelf",
|
||||
});
|
||||
}
|
||||
fn decompress(target_addr: [*]u8) !void {
|
||||
var data_reader = std.Io.Reader.fixed(payload.getCompressedKernelData());
|
||||
var work_buffer: [std.compress.flate.max_window_len]u8 = undefined;
|
||||
var decompressor = Decompress.init(&data_reader, .gzip, &work_buffer);
|
||||
var decompressor_reader = &decompressor.reader;
|
||||
var decompress_buf = target_addr;
|
||||
while (true) {
|
||||
const read_bytes = try decompressor_reader.readSliceShort(decompress_buf[0..4096]);
|
||||
if (read_bytes == 0) break;
|
||||
decompress_buf = decompress_buf[read_bytes..];
|
||||
if ((@intFromPtr(decompress_buf) - @intFromPtr(target_addr) ) % 10240 == 0) {
|
||||
early_serial_console.dprint("Decompressed {d} bytes...\n", .{@intFromPtr(decompress_buf) - @intFromPtr(target_addr)});
|
||||
}
|
||||
}
|
||||
}
|
||||
export fn extractKernel(multiboot_info: *u8,
|
||||
target_addr: usize) callconv(.c) noreturn {
|
||||
const params = multiboot.parseMultibootInfo(multiboot_info);
|
||||
const cmdline = Cmdline.init(params.cmdline);
|
||||
early_serial_console.earlyConsoleInit(&cmdline);
|
||||
early_serial_console.dprint("Starting kernel extraction...\n", .{});
|
||||
early_serial_console.dprint("Kernel compressed size {d} bytes\n", .{payload.getCompressedKernelData().len});
|
||||
early_serial_console.dprint("Kernel uncompressed size {d} bytes\n", .{payload.getUncompressedKernelSize()});
|
||||
decompress(@ptrFromInt(target_addr)) catch |err| {
|
||||
early_serial_console.dprint("Kernel decompression failed: {s}\n", .{@errorName(err)});
|
||||
while(true){}
|
||||
};
|
||||
early_serial_console.dprint("Kernel extraction completed.\n", .{});
|
||||
|
||||
while(true){}
|
||||
}
|
||||
181
arch/x86_64/boot/head.S
Normal file
181
arch/x86_64/boot/head.S
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "boot.h"
|
||||
#include "processor_flags.h"
|
||||
|
||||
#define rva(x) ((x)-startup_32)
|
||||
#define __BOOT_DS (3*8)
|
||||
#define __KERNEL32_CS (1*8)
|
||||
#define __KERNEL_CS (2*8)
|
||||
|
||||
.section .head.text, "ax"
|
||||
.global _start
|
||||
_start: // just make linker happy
|
||||
.code32
|
||||
.global startup_32
|
||||
.type startup_32, %function
|
||||
startup_32:
|
||||
movl $0x50000, %edx
|
||||
movl $0xdeadbeef, (%edx)
|
||||
cld
|
||||
cli
|
||||
// Actually multiboot doesn't give us a scartch area to use as stack,
|
||||
// so we temporaily save the 2nd 32bit of boot information and use it as the stack.
|
||||
movl 4(%ebx), %ecx
|
||||
leal 8(%ebx), %esp
|
||||
call 1f
|
||||
1: popl %ebp
|
||||
movl %ecx, 4(%ebx)
|
||||
subl $rva(1b), %ebp
|
||||
leal rva(gdt)(%ebp), %eax
|
||||
mov %eax, 2(%eax)
|
||||
lgdt (%eax)
|
||||
|
||||
mov $__BOOT_DS, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
leal rva(boot_stack_end)(%ebp), %esp
|
||||
|
||||
pushl $__KERNEL32_CS
|
||||
leal rva(1f)(%ebp), %eax
|
||||
pushl %eax
|
||||
lret
|
||||
1:
|
||||
movl %cr4, %eax
|
||||
orl $X86_CR4_PAE, %eax
|
||||
movl %eax, %cr4
|
||||
|
||||
leal rva(pgtable)(%ebp), %edi
|
||||
xorl %eax, %eax
|
||||
movl $(BOOT_INIT_PGTABLE_SIZE/4), %ecx
|
||||
rep stosl
|
||||
|
||||
leal rva(pgtable)(%ebp), %edi
|
||||
leal 0x1007(%edi), %eax
|
||||
movl %eax, 0(%edi)
|
||||
|
||||
leal rva(pgtable + 0x1000)(%ebp), %edi
|
||||
leal 0x1007(%edi), %eax
|
||||
movl $4, %ecx
|
||||
1: movl %eax, 0(%edi)
|
||||
addl $0x1000, %eax
|
||||
addl $8, %edi
|
||||
decl %ecx
|
||||
jnz 1b
|
||||
|
||||
leal rva(pgtable + 0x2000)(%ebp), %edi
|
||||
movl $0x183, %eax
|
||||
movl $2048, %ecx
|
||||
1: movl %eax, 0(%edi)
|
||||
addl $0x200000, %eax
|
||||
addl $8, %edi
|
||||
decl %ecx
|
||||
jnz 1b
|
||||
|
||||
leal rva(pgtable)(%ebp), %eax
|
||||
movl %eax, %cr3
|
||||
movl $MSR_EFER, %ecx
|
||||
rdmsr
|
||||
btsl $_EFER_LME, %eax
|
||||
wrmsr
|
||||
|
||||
leal rva(startup_64)(%ebp), %eax
|
||||
pushl $__KERNEL_CS
|
||||
pushl %eax
|
||||
|
||||
movl $CR0_STATE, %eax
|
||||
movl %eax, %cr0
|
||||
|
||||
lret
|
||||
#define rva64(x) ((x)-startup_64)
|
||||
#define STARTUP64_OFFSET 0x200
|
||||
.code64
|
||||
.global startup_64
|
||||
.type startup_64, %function
|
||||
.org STARTUP64_OFFSET
|
||||
startup_64:
|
||||
cld
|
||||
cli
|
||||
|
||||
xorl %eax, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %ss
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
|
||||
movq %rbx, %rsi
|
||||
|
||||
movq $LOAD_PHYSICAL_ADDR, %rbp
|
||||
// movl has the side effect of zero-extending the upper 32 bits of rbx
|
||||
movl $uncompressed_kernel_size, %ebx
|
||||
// there's no need to copy the code before startup_64
|
||||
addq %rbp, %rbx
|
||||
|
||||
leaq rva64(boot_stack_end)(%rbx), %rsp
|
||||
movq %rsi, %r15
|
||||
leaq (_bss - 8)(%rip), %rsi
|
||||
leaq rva64(_bss - 8)(%rbx), %rdi
|
||||
movl $rva64(_bss), %ecx
|
||||
shrl $3, %ecx
|
||||
std
|
||||
rep movsq
|
||||
cld
|
||||
|
||||
leaq rva64(gdt64)(%rbx), %rax
|
||||
leaq rva64(gdt)(%rbx), %rdx
|
||||
movq %rdx, 2(%rax)
|
||||
lgdt (%rax)
|
||||
|
||||
leaq rva64(relocated)(%rbx), %rax
|
||||
jmp *%rax
|
||||
|
||||
.text
|
||||
relocated:
|
||||
// clear bss
|
||||
xorl %eax, %eax
|
||||
leaq _bss(%rip), %rdi
|
||||
leaq _ebss(%rip), %rcx
|
||||
subq %rdi, %rcx
|
||||
shrq $3, %rcx
|
||||
rep stosq
|
||||
|
||||
mov %rbx, %rdi
|
||||
subq $STARTUP64_OFFSET, %rdi
|
||||
call relocateSelf
|
||||
|
||||
movq %r15, %rdi // boot params pointer
|
||||
movq %rbp, %rsi // load physical address
|
||||
call extractKernel
|
||||
|
||||
|
||||
hlt
|
||||
.data
|
||||
gdt64:
|
||||
.word gdt_end - gdt - 1
|
||||
.quad gdt - gdt64
|
||||
gdt64_end:
|
||||
.balign 8
|
||||
gdt:
|
||||
.word gdt_end - gdt - 1
|
||||
.long 0
|
||||
.word 0
|
||||
.quad 0x00cf9a000000ffff // __KERNEL32_CS
|
||||
.quad 0x00af9a000000ffff // __KERNEL_CS
|
||||
.quad 0x00cf92000000ffff // __KERNEL_DS
|
||||
gdt_end:
|
||||
.bss
|
||||
.balign 4
|
||||
boot_heap:
|
||||
.space BOOT_HEAP_SIZE
|
||||
boot_stack:
|
||||
.space BOOT_STACK_SIZE
|
||||
boot_stack_end:
|
||||
|
||||
.section ".pgtable","aw",@nobits
|
||||
.balign 4096
|
||||
pgtable:
|
||||
.space BOOT_PGTABLE_SIZE
|
||||
pgtable_end:
|
||||
69
arch/x86_64/boot/header.S
Normal file
69
arch/x86_64/boot/header.S
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "multiboot2.h"
|
||||
#include "kcapsule.h" // Auto-generated file
|
||||
#include "boot.h"
|
||||
.set falign, 0x200
|
||||
.code16
|
||||
.section ".header", "a"
|
||||
.global _start
|
||||
_start: // Just make linker happy
|
||||
yuki_header:
|
||||
.ascii "YUKIOS"
|
||||
.quad 0x131084C
|
||||
|
||||
.org 0x50
|
||||
.balign 8
|
||||
multiboot2_header:
|
||||
.long MULTIBOOT2_HEADER_MAGIC
|
||||
.long MULTIBOOT_ARCHITECTURE_I386
|
||||
.long multiboot2_header_end - multiboot2_header
|
||||
.long -(MULTIBOOT2_HEADER_MAGIC + MULTIBOOT_ARCHITECTURE_I386 + (multiboot2_header_end - multiboot2_header))
|
||||
.balign 8
|
||||
address_tag:
|
||||
.short MULTIBOOT_HEADER_TAG_ADDRESS
|
||||
.short 0
|
||||
.long address_tag_end - address_tag
|
||||
.long LOAD_PHYSICAL_ADDR + multiboot2_header
|
||||
.long -1
|
||||
.long 0
|
||||
.long 0
|
||||
address_tag_end:
|
||||
.balign 8
|
||||
entry_tag:
|
||||
.short MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS
|
||||
.short MULTIBOOT_HEADER_TAG_OPTIONAL
|
||||
.long entry_tag_end - entry_tag
|
||||
.long LOAD_PHYSICAL_ADDR + header_size + CAP_startup_32
|
||||
entry_tag_end:
|
||||
// entry_efi_i386_tag:
|
||||
// .short MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32
|
||||
// .short MULTIBOOT_HEADER_TAG_OPTIONAL
|
||||
// .long entry_efi_i386_tag_end - entry_efi_i386_tag
|
||||
// .long header_size + CAP_startup_32
|
||||
// entry_efi_i386_tag_end:
|
||||
// entry_efi_amd64_tag:
|
||||
// .short MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64
|
||||
// .short MULTIBOOT_HEADER_TAG_OPTIONAL
|
||||
// .long entry_efi_amd64_tag_end - entry_efi_amd64_tag
|
||||
// .long header_size + CAP_startup_64
|
||||
// entry_efi_amd64_tag_end:
|
||||
.balign 8
|
||||
framebuffer_tag:
|
||||
.short MULTIBOOT_HEADER_TAG_FRAMEBUFFER
|
||||
.short MULTIBOOT_HEADER_TAG_OPTIONAL
|
||||
.long framebuffer_tag_end - framebuffer_tag
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
framebuffer_tag_end:
|
||||
// .balign 8
|
||||
// relocatable_tag:
|
||||
// .short MULTIBOOT_HEADER_TAG_RELOCATABLE
|
||||
// .short MULTIBOOT_HEADER_TAG_OPTIONAL
|
||||
// .long relocatable_tag_end - relocatable_tag
|
||||
// .long 0x0 /* min_addr */
|
||||
// .long 0xf0000000 /* max_addr */
|
||||
// .long falign /* align */
|
||||
// .long 0x0
|
||||
// relocatable_tag_end:
|
||||
multiboot2_header_end:
|
||||
.balign falign
|
||||
9
arch/x86_64/boot/header.ld
Normal file
9
arch/x86_64/boot/header.ld
Normal file
@@ -0,0 +1,9 @@
|
||||
OUTPUT_ARCH(x86_64)
|
||||
|
||||
SECTIONS {
|
||||
. = 0;
|
||||
.header : {
|
||||
KEEP(*(.header))
|
||||
}
|
||||
header_size = ALIGN(ABSOLUTE(.), 4096);
|
||||
}
|
||||
62
arch/x86_64/boot/ident_map.zig
Normal file
62
arch/x86_64/boot/ident_map.zig
Normal file
@@ -0,0 +1,62 @@
|
||||
const std = @import("std");
|
||||
const processor = @import("arch").processor;
|
||||
const mem = @import("arch").mem;
|
||||
const PFType = mem.PFType;
|
||||
const early_serial_console = @import("early_serial_console.zig");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
var pgtable_buffer: struct {
|
||||
buffer: [*][mem.PAGE_SIZE]u8,
|
||||
size: usize,
|
||||
used_pages: usize,
|
||||
} = undefined;
|
||||
|
||||
fn allocPgtablePage() error.OutOfMemory![4096]u8 {
|
||||
// if (used + mem.PAGE_SIZE > size) {
|
||||
// early_serial_console.dprint("Out of page table memory!\n", .{});
|
||||
// return error.OutOfMemory;
|
||||
// }
|
||||
// const page = buffer + used;
|
||||
// return page;
|
||||
}
|
||||
// fn pgdIdentInit() {
|
||||
|
||||
// }
|
||||
|
||||
// fn pudIdentInit() {
|
||||
|
||||
// }
|
||||
|
||||
fn kernelAddIdentityMap(pgdt_page: [*]mem.PGDEntry, start: u64, end: u64) void {
|
||||
assert(start % mem.PMD_SIZE == 0);
|
||||
assert(end % mem.PMD_SIZE == 0);
|
||||
var address = start;
|
||||
while (address < end) {
|
||||
// var pgd = &pgdt_page[mem.PGDEntry.getIndex(address)];
|
||||
// if ()
|
||||
address += mem.PMD_SIZE;
|
||||
}
|
||||
}
|
||||
export fn initializeIdentMap() void {
|
||||
// var pgd_table = processor.readCr3();
|
||||
// if (pgdtable == _pgtable) {
|
||||
|
||||
// }
|
||||
}
|
||||
fn printPF(msg: []const u8, errorCode: u64, faultAddress: u64, ip: u64) void {
|
||||
early_serial_console.dprint(
|
||||
\\{s}:
|
||||
\\error code: 0x{x}
|
||||
\\fault address: 0x{x}
|
||||
\\instruction pointer: 0x{x}
|
||||
\\
|
||||
, .{msg, errorCode, faultAddress, ip});
|
||||
}
|
||||
export fn doBootPageFault(regs: processor.PtRegs, errorCode: u64) void {
|
||||
const faultAddress = processor.readCr2();
|
||||
if (errorCode & (PFType.PROT | PFType.USER | PFType.RSVD) == 0) {
|
||||
printPF("Unexpected page fault", errorCode, faultAddress, regs.ip);
|
||||
}
|
||||
const address = faultAddress & mem.PMD_MASK;
|
||||
kernelAddIdentityMap(address, address + mem.PMD_SIZE);
|
||||
}
|
||||
23
arch/x86_64/boot/idt.zig
Normal file
23
arch/x86_64/boot/idt.zig
Normal file
@@ -0,0 +1,23 @@
|
||||
const desc = @import("arch").desc;
|
||||
const mem = @import("arch").mem;
|
||||
const TrapType = @import("arch").trap.TrapType;
|
||||
extern const __KERNEL_CS: u8;
|
||||
|
||||
var idt_table: [256]desc.IdtEntry align(mem.PAGE_SIZE) = .{.{}} ** 256;
|
||||
extern const boot_page_fault: u8;
|
||||
extern const boot_nmi: u8;
|
||||
|
||||
fn setIdtEntry(vec: usize, handler: anytype) void {
|
||||
var entry = desc.IdtEntry{};
|
||||
entry.setOffset(@intFromPtr(handler));
|
||||
entry.selector = @intFromPtr(&__KERNEL_CS);
|
||||
entry.gate_type = .trap;
|
||||
entry.present = 1;
|
||||
idt_table[vec] = entry;
|
||||
}
|
||||
|
||||
export fn loadLoaderIdt() void {
|
||||
setIdtEntry(TrapType.PF, &boot_page_fault);
|
||||
setIdtEntry(TrapType.NMI, &boot_nmi);
|
||||
desc.loadIdt(&idt_table);
|
||||
}
|
||||
56
arch/x86_64/boot/idt_handlers.S
Normal file
56
arch/x86_64/boot/idt_handlers.S
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
.macro EXCEPTION_HANDLER name function error_code=0
|
||||
.global \name
|
||||
.type \name, @function
|
||||
\name:
|
||||
if \error_code == 0
|
||||
pushq $0
|
||||
end
|
||||
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
pushq %rdx
|
||||
pushq %rcx
|
||||
pushq %rax
|
||||
pushq %r8
|
||||
pushq %r9
|
||||
pushq %r10
|
||||
pushq %r11
|
||||
pushq %rbx
|
||||
pushq %rbp
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
|
||||
movq %rsp, %rdi
|
||||
/* Error code is second parameter */
|
||||
movq 120(%rsp), %rsi
|
||||
call \function
|
||||
|
||||
/* Restore regs */
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
popq %rbp
|
||||
popq %rbx
|
||||
popq %r11
|
||||
popq %r10
|
||||
popq %r9
|
||||
popq %r8
|
||||
popq %rax
|
||||
popq %rcx
|
||||
popq %rdx
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
|
||||
addq $8, %rsp
|
||||
|
||||
iretq
|
||||
.endm
|
||||
.text
|
||||
.code64
|
||||
|
||||
EXCEPTION_HANDLER boot_page_fault doBootPageFault error_code=1
|
||||
EXCEPTION_HANDLER boot_nmi doBootNMI
|
||||
6
arch/x86_64/boot/include/boot.h
Normal file
6
arch/x86_64/boot/include/boot.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#define BOOT_HEAP_SIZE (512 * 1024)
|
||||
#define BOOT_STACK_SIZE (64 * 1024)
|
||||
#define LOAD_PHYSICAL_ADDR (0x100000)
|
||||
|
||||
#define BOOT_PGTABLE_SIZE (32 * 4096)
|
||||
#define BOOT_INIT_PGTABLE_SIZE (6 * 4096)
|
||||
39
arch/x86_64/boot/include/multiboot2.h
Normal file
39
arch/x86_64/boot/include/multiboot2.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
/* How many bytes from the start of the file we search for the header. */
|
||||
#define MULTIBOOT_SEARCH 32768
|
||||
#define MULTIBOOT_HEADER_ALIGN 8
|
||||
|
||||
/* The magic field should contain this. */
|
||||
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
|
||||
|
||||
/* Alignment of multiboot modules. */
|
||||
#define MULTIBOOT_MOD_ALIGN 0x00001000
|
||||
|
||||
/* Alignment of the multiboot info structure. */
|
||||
#define MULTIBOOT_INFO_ALIGN 0x00000008
|
||||
|
||||
|
||||
#define MULTIBOOT_HEADER_TAG_END 0
|
||||
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
|
||||
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
|
||||
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
|
||||
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
|
||||
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
|
||||
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
|
||||
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
|
||||
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
|
||||
|
||||
#define MULTIBOOT_ARCHITECTURE_I386 0
|
||||
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
|
||||
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
|
||||
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
|
||||
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
|
||||
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
|
||||
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
|
||||
|
||||
15
arch/x86_64/boot/include/processor_flags.h
Normal file
15
arch/x86_64/boot/include/processor_flags.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#define X86_CR0_PE 0x00000001
|
||||
#define X86_CR0_MP 0x00000002
|
||||
#define X86_CR0_ET 0x00000004
|
||||
#define X86_CR0_NE 0x00000020
|
||||
#define X86_CR0_WP 0x00010000
|
||||
#define X86_CR0_AM 0x00040000
|
||||
#define X86_CR0_PG 0x80000000
|
||||
#define CR0_STATE (X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | \
|
||||
X86_CR0_NE | X86_CR0_WP | X86_CR0_AM | \
|
||||
X86_CR0_PG)
|
||||
#define X86_CR4_PAE 0x00000020
|
||||
#define X86_CR4_OSFXSR 0x00000200
|
||||
#define X86_CR4_OSXMMEXCPT 0x00000400
|
||||
#define MSR_EFER 0xc0000080
|
||||
#define _EFER_LME 8
|
||||
59
arch/x86_64/boot/kcapsule.ld
Normal file
59
arch/x86_64/boot/kcapsule.ld
Normal file
@@ -0,0 +1,59 @@
|
||||
OUTPUT_ARCH(i386:x86_64)
|
||||
|
||||
ENTRY(startup_32)
|
||||
|
||||
SECTIONS {
|
||||
. = 0;
|
||||
.head.text : {
|
||||
KEEP(*(.head.text))
|
||||
}
|
||||
.rodata.compressed : {
|
||||
*(.rodata.compressed)
|
||||
}
|
||||
.text : {
|
||||
_text = .;
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
_etext = .;
|
||||
}
|
||||
.rodata : {
|
||||
_rodata = .;
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
_erodata = .;
|
||||
}
|
||||
.data : ALIGN(0x1000) {
|
||||
_data = .;
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
. = ALIGN(. + 4, 0x200);
|
||||
_edata = .;
|
||||
}
|
||||
.rela.dyn : {
|
||||
__rela_dyn_start = .;
|
||||
*(.rela.dyn)
|
||||
__rela_dyn_end = .;
|
||||
}
|
||||
. = ALIGN(8);
|
||||
.bss : {
|
||||
_bss = .;
|
||||
*(.bss)
|
||||
*(.bss.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(8);
|
||||
_ebss = .;
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
.pgtable : {
|
||||
_pgtable = .;
|
||||
*(.pgtable)
|
||||
_epgtable = .;
|
||||
}
|
||||
_end = .;
|
||||
/DISCARD/ : {
|
||||
*(.dynamic) *(.dynsym) *(.dynstr) *(.dynbss)
|
||||
*(.hash) *(.gnu.hash)
|
||||
*(.note.*)
|
||||
}
|
||||
|
||||
}
|
||||
250
arch/x86_64/boot/multiboot.zig
Normal file
250
arch/x86_64/boot/multiboot.zig
Normal file
@@ -0,0 +1,250 @@
|
||||
const std = @import("std");
|
||||
const BootParams = @import("params.zig").BootParams;
|
||||
pub const MULTIBOOT_TAG_ALIGN: usize = 8;
|
||||
pub const MultibootTagType = enum(u32) {
|
||||
end,
|
||||
cmdline,
|
||||
boot_loader_name,
|
||||
module,
|
||||
basic_meminfo,
|
||||
bootdev,
|
||||
mmap,
|
||||
vbe,
|
||||
framebuffer,
|
||||
elf_sections,
|
||||
apm,
|
||||
efi32,
|
||||
efi64,
|
||||
smbios,
|
||||
acpi_old,
|
||||
acpi_new,
|
||||
network,
|
||||
efi_mmap,
|
||||
efi_bs,
|
||||
efi32_ih,
|
||||
efi64_ih,
|
||||
load_base_addr,
|
||||
};
|
||||
|
||||
pub const MultibootTag = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagCmdline = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
string: [0]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagModule = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
mod_start: u32 align(1),
|
||||
mod_end: u32 align(1),
|
||||
cmdline: [0]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagBasicMeminfo = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
mem_lower: u32 align(1),
|
||||
mem_upper: u32 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagBootdev = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
biosdev: u32 align(1),
|
||||
slice: u32 align(1),
|
||||
part: u32 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootMmapEntry = extern struct {
|
||||
addr: u64 align(1),
|
||||
len: u64 align(1),
|
||||
type: u32 align(1),
|
||||
zero: u32 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagMmap = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
entry_size: u32 align(1),
|
||||
entry_version: u32 align(1),
|
||||
entries: [0]MultibootMmapEntry align(1),
|
||||
};
|
||||
|
||||
pub const MultibootVbeInfoBlock = extern struct {
|
||||
external_specification: [512]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootVbeModeInfoBlock = extern struct {
|
||||
external_specification: [256]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagVbe = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
|
||||
vbe_mode: u16 align(1),
|
||||
vbe_interface_seg: u16 align(1),
|
||||
vbe_interface_off: u16 align(1),
|
||||
vbe_interface_len: u16 align(1),
|
||||
|
||||
vbe_control_info: MultibootVbeInfoBlock align(1),
|
||||
vbe_mode_info: MultibootVbeModeInfoBlock align(1),
|
||||
};
|
||||
|
||||
pub const MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED = 0;
|
||||
pub const MULTIBOOT_FRAMEBUFFER_TYPE_RGB = 1;
|
||||
pub const MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT = 2;
|
||||
|
||||
pub const MultibootColor = extern struct {
|
||||
red: u8 align(1),
|
||||
green: u8 align(1),
|
||||
blue: u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagFramebufferCommon = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
|
||||
framebuffer_addr: u64 align(1),
|
||||
framebuffer_pitch: u32 align(1),
|
||||
framebuffer_width: u32 align(1),
|
||||
framebuffer_height: u32 align(1),
|
||||
framebuffer_bpp: u8 align(1),
|
||||
framebuffer_type: u8 align(1),
|
||||
reserved: u16 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagFramebuffer = extern struct {
|
||||
common: MultibootTagFramebufferCommon align(1),
|
||||
|
||||
details: extern union {
|
||||
indexed: extern struct {
|
||||
framebuffer_palette_num_colors: u16 align(1),
|
||||
framebuffer_palette: [*]MultibootColor align(1),
|
||||
} align(1),
|
||||
rgb: extern struct {
|
||||
framebuffer_red_field_position: u8 align(1),
|
||||
framebuffer_red_mask_size: u8 align(1),
|
||||
framebuffer_green_field_position: u8 align(1),
|
||||
framebuffer_green_mask_size: u8 align(1),
|
||||
framebuffer_blue_field_position: u8 align(1),
|
||||
framebuffer_blue_mask_size: u8 align(1),
|
||||
} align(1),
|
||||
} align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagElfSections = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
num: u32 align(1),
|
||||
entsize: u32 align(1),
|
||||
shndx: u32 align(1),
|
||||
sections: [*]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagApm = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
version: u16 align(1),
|
||||
cseg: u16 align(1),
|
||||
offset: u32 align(1),
|
||||
cseg_16: u16 align(1),
|
||||
dseg: u16 align(1),
|
||||
flags: u16 align(1),
|
||||
cseg_len: u16 align(1),
|
||||
cseg_16_len: u16 align(1),
|
||||
dseg_len: u16 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagEfi32 = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
pointer: u32 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagEfi64 = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
pointer: u64 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagSmbios = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
major: u8 align(1),
|
||||
minor: u8 align(1),
|
||||
reserved: [6]u8 align(1),
|
||||
tables: [*]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagOldAcpi = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
rsdp: [*]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagNewAcpi = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
rsdp: [*]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagNetwork = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
dhcpack: [*]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagEfiMmap = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
descr_size: u32 align(1),
|
||||
descr_vers: u32 align(1),
|
||||
efi_mmap: [*]u8 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagEfi32Ih = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
pointer: u32 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagEfi64Ih = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
pointer: u64 align(1),
|
||||
};
|
||||
|
||||
pub const MultibootTagLoadBaseAddr = extern struct {
|
||||
type: u32 align(1),
|
||||
size: u32 align(1),
|
||||
load_base_addr: u32 align(1),
|
||||
};
|
||||
|
||||
pub fn parseMultibootInfo(multiboot_info: *u8) BootParams {
|
||||
var params = BootParams{
|
||||
.cmdline = &[_]u8{},
|
||||
};
|
||||
var offset: usize = @sizeOf(MultibootTag);
|
||||
while (true) {
|
||||
const tag: *MultibootTag = @ptrFromInt(@intFromPtr(multiboot_info) + offset);
|
||||
if (tag.type == @intFromEnum(MultibootTagType.end)) {
|
||||
break;
|
||||
}
|
||||
switch (@as(MultibootTagType, @enumFromInt(tag.type))) {
|
||||
MultibootTagType.cmdline => {
|
||||
const cmdline_tag: *MultibootTagCmdline = @ptrCast(tag);
|
||||
const sentinel_cmdline = @as([*:0]u8, @ptrCast(&cmdline_tag.string));
|
||||
params.cmdline = sentinel_cmdline[0..std.mem.len(sentinel_cmdline)];
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
offset += (tag.size + MULTIBOOT_TAG_ALIGN - 1) & ~(MULTIBOOT_TAG_ALIGN - 1);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
52
arch/x86_64/boot/params.zig
Normal file
52
arch/x86_64/boot/params.zig
Normal file
@@ -0,0 +1,52 @@
|
||||
const std = @import("std");
|
||||
// // const e820 = @import("e820.zig");
|
||||
// const video = @import("video.zig");
|
||||
|
||||
// pub const SetupHeader = extern struct {
|
||||
// _pad1: [15]u8 align(1),
|
||||
// jump: u16 align(1),
|
||||
// header: u32 align(1),
|
||||
// version: u16 align(1),
|
||||
// _pad2: [8]u8 align(1),
|
||||
// type_of_loader: u8 align(1),
|
||||
// loadflags: u8 align(1),
|
||||
// _pad3: [22]u8 align(1),
|
||||
// cmd_line_ptr: u32 align(1),
|
||||
// _pad4: [4]u8 align(1),
|
||||
// kernel_alignment: u32 align(1),
|
||||
// relocatable_kernel: u8 align(1),
|
||||
// min_alignment: u8 align(1),
|
||||
// xloadflags: u16 align(1),
|
||||
// cmdline_size: u32 align(1),
|
||||
// _pad5: [36]u8 align(1),
|
||||
// init_size: u32 align(1),
|
||||
// _pad6: [8]u8 align(1),
|
||||
// };
|
||||
|
||||
// const E820_MAX_ENTRIES_BP = 128;
|
||||
|
||||
// pub const BootParams = extern struct {
|
||||
// screen_info: video.ScreenInfo align(1), // 0x000
|
||||
// _pad1: [0x30]u8 align(1), // 0x040
|
||||
// acpi_rsdp_addr: u64 align(1), // 0x070
|
||||
// _pad2: [0x50]u8 align(1), // 0x078
|
||||
// ext_cmd_line_ptr: u32 align(1), // 0x0c8
|
||||
// _pad3: [0x74]u8 align(1), // 0x0cc
|
||||
// edid_info: [0x80]u8 align(1), // 0x140 reserve for future use
|
||||
// _pad4: [0x28]u8 align(1), // 0x1c0
|
||||
// e820_entries: u8 align(1), // 0x1e8
|
||||
// _pad5: [0x8]u8 align(1), // 0x1e9
|
||||
// hdr: SetupHeader align(1), // 0x1f1
|
||||
// _pad6: [0x2d0 - 0x1f1 - @sizeOf(SetupHeader)]u8 align(1),
|
||||
// // e820_table: [E820_MAX_ENTRIES_BP]e820.E820Entry align(1), // 0x2d0
|
||||
// _pad7: [0x330]u8 align(1), // 0xcd0
|
||||
// };
|
||||
|
||||
// comptime {
|
||||
// const assert = std.debug.assert;
|
||||
// // assert(@sizeOf(BootParams) == 0x1000);
|
||||
// assert(@sizeOf(SetupHeader) == 0x07b);
|
||||
// }
|
||||
pub const BootParams = struct {
|
||||
cmdline: []u8
|
||||
};
|
||||
13
arch/x86_64/boot/payload.zig
Normal file
13
arch/x86_64/boot/payload.zig
Normal file
@@ -0,0 +1,13 @@
|
||||
const std = @import("std");
|
||||
|
||||
extern const compressed_kernel_data: u8;
|
||||
extern const compressed_kernel_size: u8;
|
||||
extern const uncompressed_kernel_size: u8;
|
||||
|
||||
pub fn getCompressedKernelData() []const u8 {
|
||||
return @as([*]const u8, @ptrCast(&compressed_kernel_data))[0..@as(usize, @intFromPtr(&compressed_kernel_size))];
|
||||
}
|
||||
|
||||
pub fn getUncompressedKernelSize() usize {
|
||||
return @as(usize, @intFromPtr(&uncompressed_kernel_size));
|
||||
}
|
||||
20
arch/x86_64/boot/relocate.zig
Normal file
20
arch/x86_64/boot/relocate.zig
Normal file
@@ -0,0 +1,20 @@
|
||||
const std = @import("std");
|
||||
const elf = std.elf;
|
||||
|
||||
extern var __rela_dyn_start: u8;
|
||||
extern var __rela_dyn_end: u8;
|
||||
|
||||
pub fn relocateSelf(base_addr: usize) callconv(.c) void {
|
||||
const rela_size = (@intFromPtr(&__rela_dyn_end) - @intFromPtr(&__rela_dyn_start)) / @sizeOf(elf.Elf64_Rela);
|
||||
const relas = @as([*]elf.Elf64_Rela, @ptrCast(@alignCast(&__rela_dyn_start)))[0..rela_size];
|
||||
for (relas) |rela| {
|
||||
const offset = rela.r_offset;
|
||||
const addend = rela.r_addend;
|
||||
// const sym_index = rela.r_info >> 32;
|
||||
const type_ = rela.r_info & 0xffffffff;
|
||||
if (type_ == @intFromEnum(elf.R_X86_64.RELATIVE)) {
|
||||
const reloc_addr: *u64 = @ptrFromInt(offset + base_addr);
|
||||
reloc_addr.* = base_addr + @as(usize, @intCast(addend));
|
||||
}
|
||||
}
|
||||
}
|
||||
67
arch/x86_64/boot/video.zig
Normal file
67
arch/x86_64/boot/video.zig
Normal file
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
|
||||
// Ported from Linux kernel include/uapi/linux/screen_info.h
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub const ScreenInfo = extern struct{
|
||||
orig_x: u8 align(1), // 0x00
|
||||
orig_y: u8 align(1), // 0x01
|
||||
ext_mem_k: u16 align(1), // 0x02
|
||||
orig_video_page: u16 align(1), // 0x04
|
||||
orig_video_mode: u8 align(1), // 0x06
|
||||
orig_video_cols: u8 align(1), // 0x07
|
||||
flags: u8 align(1), // 0x08
|
||||
unused2: u8 align(1), // 0x09
|
||||
orig_video_ega_bx: u16 align(1), // 0x0a
|
||||
unused3: u16 align(1), // 0x0c
|
||||
orig_video_lines: u8 align(1), // 0x0e
|
||||
orig_video_isVGA: u8 align(1), // 0x0f
|
||||
orig_video_points: u16 align(1), // 0x10
|
||||
|
||||
// VESA graphic mode -- linear frame buffer
|
||||
lfb_width: u16 align(1), // 0x12
|
||||
lfb_height: u16 align(1), // 0x14
|
||||
lfb_depth: u16 align(1), // 0x16
|
||||
lfb_base: u32 align(1), // 0x18
|
||||
lfb_size: u32 align(1), // 0x1c
|
||||
cl_magic: u16 align(1), // 0x20
|
||||
cl_offset: u16 align(1), // 0x22
|
||||
lfb_linelength: u16 align(1), // 0x24
|
||||
red_size: u8 align(1), // 0x26
|
||||
red_pos: u8 align(1), // 0x27
|
||||
green_size: u8 align(1), // 0x28
|
||||
green_pos: u8 align(1), // 0x29
|
||||
blue_size: u8 align(1), // 0x2a
|
||||
blue_pos: u8 align(1), // 0x2b
|
||||
rsvd_size: u8 align(1), // 0x2c
|
||||
rsvd_pos: u8 align(1), // 0x2d
|
||||
vesapm_seg: u16 align(1), // 0x2e
|
||||
vesapm_off: u16 align(1), // 0x30
|
||||
pages: u16 align(1), // 0x32
|
||||
vesa_attributes: u16 align(1), // 0x34
|
||||
capabilities: u32 align(1), // 0x36
|
||||
ext_lfb_base: u32 align(1), // 0x3a
|
||||
_reserved: [2]u8 align(1), // 0x3e
|
||||
};
|
||||
|
||||
// Common video types
|
||||
pub const VideoType = enum(u8) {
|
||||
MDA = 0x10, // Monochrome Text Display
|
||||
CGA = 0x11, // CGA Display
|
||||
EGAM = 0x20, // EGA/VGA in Monochrome Mode
|
||||
EGAC = 0x21, // EGA in Color Mode
|
||||
VGAC = 0x22, // VGA+ in Color Mode
|
||||
VLFB = 0x23, // VESA VGA in graphic mode
|
||||
EFI = 0x70, // EFI graphic mode
|
||||
};
|
||||
|
||||
// Video flags
|
||||
pub const VIDEO_FLAGS_NOCURSOR: u8 = 1 << 0; // The video mode has no cursor set
|
||||
|
||||
// Video capabilities
|
||||
pub const VIDEO_CAPABILITY_SKIP_QUIRKS: u32 = 1 << 0;
|
||||
pub const VIDEO_CAPABILITY_64BIT_BASE: u32 = 1 << 1; // Frame buffer base is 64-bit
|
||||
|
||||
comptime {
|
||||
std.debug.assert(@sizeOf(ScreenInfo) == 0x40);
|
||||
}
|
||||
26
arch/x86_64/build_arch.zig
Normal file
26
arch/x86_64/build_arch.zig
Normal file
@@ -0,0 +1,26 @@
|
||||
const std = @import("std");
|
||||
const Step = std.Build.Step;
|
||||
const boot_build = @import("boot/build_boot.zig");
|
||||
|
||||
fn buildKernel(b: *std.Build, optimize: std.builtin.OptimizeMode) *Step.Compile {
|
||||
const target = b.resolveTargetQuery(.{
|
||||
.cpu_arch = .x86_64,
|
||||
.os_tag = .freestanding,
|
||||
.abi = .none,
|
||||
});
|
||||
const kernel = b.addExecutable(.{
|
||||
.name = "kernel",
|
||||
.root_module = b.addModule("kernel", .{
|
||||
.root_source_file = b.path("kernel/main.zig"),
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
}),
|
||||
});
|
||||
kernel.entry = .{ .symbol_name = "start_kernel" };
|
||||
return kernel;
|
||||
}
|
||||
pub fn buildImage(b: *std.Build) void {
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
const kernel = buildKernel(b, optimize);
|
||||
boot_build.buildBootImage(b, kernel);
|
||||
}
|
||||
43
arch/x86_64/desc.zig
Normal file
43
arch/x86_64/desc.zig
Normal file
@@ -0,0 +1,43 @@
|
||||
const processor = @import("processor.zig");
|
||||
|
||||
pub const GateDesc = packed struct {
|
||||
offset_1: u16 = 0,
|
||||
selector: u16 = 0,
|
||||
ist: u3 = 0,
|
||||
_reserved_1: u5 = 0,
|
||||
gate_type: GateType = .interrupt,
|
||||
_padding: u1 = 0,
|
||||
dpl: processor.PrivilegeLevel = .Kernel,
|
||||
present: u1 = 0,
|
||||
offset_2: u16 = 0,
|
||||
offset_3: u32 = 0,
|
||||
_reserved_2: u32 = 0,
|
||||
pub const GateType = enum(u4) {
|
||||
interrupt = 0xe,
|
||||
trap = 0xf,
|
||||
};
|
||||
pub fn getOffset(self: *const GateDesc) u64 {
|
||||
return (@as(u64, self.offset_3) << 32) | (@as(u64, self.offset_2) << 16) | self.offset_1;
|
||||
}
|
||||
pub fn setOffset(self: *GateDesc, offset: u64) void {
|
||||
self.offset_1 = @as(u16, offset & 0xFFFF);
|
||||
self.offset_2 = @as(u16, (offset >> 16) & 0xFFFF);
|
||||
self.offset_3 = @as(u32, (offset >> 32) & 0xFFFFFFFF);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn loadIdt(idt_table: []const GateDesc) void {
|
||||
var idt_ptr: packed struct {
|
||||
limit: u16,
|
||||
base: u64,
|
||||
} = .{
|
||||
.limit = @as(u16, @sizeOf(GateDesc) * idt_table.len - 1),
|
||||
.base = @intFromPtr(&idt_table[0]),
|
||||
};
|
||||
asm volatile (
|
||||
\\ lidt %rax
|
||||
:
|
||||
: [idt_ptr] "{rax}" (&idt_ptr)
|
||||
: .{}
|
||||
);
|
||||
}
|
||||
19
arch/x86_64/io.zig
Normal file
19
arch/x86_64/io.zig
Normal file
@@ -0,0 +1,19 @@
|
||||
pub fn outb(port: u16, value: u8) void {
|
||||
asm volatile (
|
||||
\\outb %al, %dx
|
||||
:
|
||||
: [port] "{dx}" (port), [value] "{al}" (value)
|
||||
: .{}
|
||||
);
|
||||
}
|
||||
|
||||
pub fn inb(port: u16) u8 {
|
||||
var value: u8 = 0;
|
||||
asm volatile (
|
||||
\\inb %dx, %al
|
||||
: [value] "={al}" (value)
|
||||
: [port] "{dx}" (port)
|
||||
: .{}
|
||||
);
|
||||
return value;
|
||||
}
|
||||
43
arch/x86_64/mem.zig
Normal file
43
arch/x86_64/mem.zig
Normal file
@@ -0,0 +1,43 @@
|
||||
pub const PAGE_SHIFT: usize = 12;
|
||||
pub const PAGE_SIZE: usize = 1 << PAGE_SHIFT;
|
||||
|
||||
pub const PTE_SHIFT: u32 = 12;
|
||||
pub const PMD_SHIFT: u32 = 21;
|
||||
pub const PUD_SHIFT: u32 = 30;
|
||||
pub const PGD_SHIFT: u32 = 39;
|
||||
|
||||
pub const PTE_SIZE: usize = 1 << PTE_SHIFT;
|
||||
pub const PMD_SIZE: usize = 1 << PMD_SHIFT;
|
||||
pub const PUD_SIZE: usize = 1 << PUD_SHIFT;
|
||||
pub const PGD_SIZE: usize = 1 << PGD_SHIFT;
|
||||
|
||||
pub const PTE_MASK: usize = 1 << PTE_SHIFT - 1;
|
||||
pub const PMD_MASK: usize = 1 << PMD_SHIFT - 1;
|
||||
pub const PUD_MASK: usize = 1 << PUD_SHIFT - 1;
|
||||
pub const PGD_MASK: usize = 1 << PGD_SHIFT - 1;
|
||||
|
||||
pub const ENTRIES_PER_TABLE: usize = PAGE_SIZE / 64;
|
||||
|
||||
pub const PFType = struct{
|
||||
pub const PROT: usize = 0;
|
||||
pub const WRITE: usize = 1<<1;
|
||||
pub const USER: usize = 1<<2;
|
||||
pub const RSVD: usize = 1<<3;
|
||||
pub const INSTR: usize = 1<<4;
|
||||
pub const PK: usize = 1<<5;
|
||||
pub const SHSTK: usize = 1<<6;
|
||||
};
|
||||
|
||||
pub const PGDEntry = packed struct {
|
||||
present: u1,
|
||||
write: u1,
|
||||
supervisor: u1,
|
||||
write_through: u1,
|
||||
cache_disable: u1,
|
||||
accessed: u1,
|
||||
_padding_1: u6,
|
||||
addr: u40,
|
||||
pub fn getIndex(self: usize) usize {
|
||||
return (self >> PGD_SHIFT) & 0x1FF;
|
||||
}
|
||||
};
|
||||
44
arch/x86_64/processor.zig
Normal file
44
arch/x86_64/processor.zig
Normal file
@@ -0,0 +1,44 @@
|
||||
pub fn readCr2() u64 {
|
||||
return asm volatile (
|
||||
\\ mov %cr2, %rax
|
||||
: [ret] "={rax}" (-> u64),
|
||||
:
|
||||
: .{});
|
||||
}
|
||||
|
||||
pub fn readCr3() u64 {
|
||||
return asm volatile (
|
||||
\\ mov %cr3, %rax
|
||||
: [ret] "={rax}" (-> u64),
|
||||
:
|
||||
: .{});
|
||||
}
|
||||
|
||||
pub const PrivilegeLevel = enum(u4) {
|
||||
Kernel = 0,
|
||||
User = 3,
|
||||
};
|
||||
|
||||
pub const PtRegs = struct {
|
||||
r15: usize,
|
||||
r14: usize,
|
||||
r13: usize,
|
||||
r12: usize,
|
||||
bp: usize,
|
||||
bx: usize,
|
||||
r11: usize,
|
||||
r10: usize,
|
||||
r9: usize,
|
||||
r8: usize,
|
||||
ax: usize,
|
||||
cx: usize,
|
||||
dx: usize,
|
||||
si: usize,
|
||||
di: usize,
|
||||
code: usize,
|
||||
ip: usize,
|
||||
cs: usize,
|
||||
flags: usize,
|
||||
sp: usize,
|
||||
ss: usize,
|
||||
};
|
||||
26
arch/x86_64/trap.zig
Normal file
26
arch/x86_64/trap.zig
Normal file
@@ -0,0 +1,26 @@
|
||||
pub const TrapType = enum(u8) {
|
||||
DE = 0, // Divide-by-zero
|
||||
DB = 1, // Debug
|
||||
NMI = 2, // Non-maskable Interrupt
|
||||
BP = 3, // Breakpoint
|
||||
OF = 4, // Overflow
|
||||
BR = 5, // Bound Range Exceeded
|
||||
UD = 6, // Invalid Opcode
|
||||
NM = 7, // Device Not Available
|
||||
DF = 8, // Double Fault
|
||||
OLD_MF = 9, // Coprocessor Segment Overrun
|
||||
TS = 10, // Invalid TSS
|
||||
NP = 11, // Segment Not Present
|
||||
SS = 12, // Stack Segment Fault
|
||||
GP = 13, // General Protection Fault
|
||||
PF = 14, // Page Fault
|
||||
SPURIOUS = 15, // Spurious Interrupt
|
||||
MF = 16, // x87 Floating-Point Exception
|
||||
AC = 17, // Alignment Check
|
||||
MC = 18, // Machine Check
|
||||
XF = 19, // SIMD Floating-Point Exception
|
||||
VE = 20, // Virtualization Exception
|
||||
CP = 21, // Control Protection Exception
|
||||
VC = 29, // VMM Communication Exception
|
||||
IRET = 32, // IRET Exception
|
||||
};
|
||||
Reference in New Issue
Block a user