feat(loader, kernel): impl part of loader and initialize kernel structure

This commit is contained in:
2026-04-11 09:42:09 +08:00
parent 1233ae9e9b
commit 34ccf69569
53 changed files with 1743 additions and 777 deletions

9
.gitignore vendored
View File

@@ -1,8 +1,3 @@
zig-out
.zig-cache .zig-cache
zig-out
yukiImage zig-pkg
kcapsule
*.img

View File

@@ -1,4 +0,0 @@
{
"files.associations": {
}
}

View File

@@ -1 +0,0 @@
# YukiOS

View File

@@ -1 +0,0 @@
offset.h

View File

@@ -1,86 +0,0 @@
const std = @import("std");
const kernel_build = @import("../../../kernel/build.zig");
const Step = std.Build.Step;
pub fn buildSetup(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, kcapsule: *Step.Compile) *Step.Compile {
const offset_generate = b.addSystemCommand(&[_][]const u8{
"sh",
"arch/x86/boot/helper.sh",
"generate_offset_header",
});
offset_generate.addFileArg(kcapsule.getEmittedBin());
offset_generate.step.dependOn(&kcapsule.step);
const setup = b.addExecutable(.{
.name = "setup",
.use_lld = true,
.use_llvm = true,
.root_module = b.createModule(.{
.root_source_file = b.path("arch/x86/boot/setup/stage1.zig"),
.target = target,
.optimize = optimize,
}),
});
setup.step.dependOn(&offset_generate.step);
setup.step.addWatchInput(b.path("arch/x86/boot/offset.h")) catch {};
setup.addAssemblyFile(b.path("arch/x86/boot/header.S"));
setup.addIncludePath(b.path("include"));
setup.addIncludePath(b.path("arch/x86/boot"));
setup.setLinkerScript(b.path("arch/x86/boot/setup.ld"));
return setup;
}
pub fn buildKcapsule(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *Step.Compile {
const kernel = kernel_build.buildKernelBin(b, target, optimize);
const kcapsule = b.addExecutable(.{
.name = "kcapsule",
.use_lld = true,
.use_llvm = true,
.root_module = b.createModule(.{
.root_source_file = b.path("arch/x86/boot/extractor.zig"),
.target = target,
.optimize = optimize,
.pic = true,
}),
});
const efi_target = b.resolveTargetQuery(.{
.cpu_arch = .x86_64,
.os_tag = .freestanding,
.abi = .msvc,
});
const efi_loader = b.addObject(.{
.name = "efi_loader",
.use_lld = true,
.use_llvm = true,
.root_module = b.createModule(.{
.root_source_file = b.path("drivers/firmware/efi/x86.zig"),
.target = efi_target,
.optimize = optimize,
.pic = true,
}),
});
kcapsule.pie = true;
kcapsule.entry = .{ .symbol_name = "efi_pe_entry" };
kcapsule.addObject(efi_loader);
kcapsule.addAssemblyFile(b.path("arch/x86/boot/payload.S"));
kcapsule.setLinkerScript(b.path("arch/x86/boot/kcapsule.ld"));
kcapsule.step.dependOn(&kernel.step);
return kcapsule;
}
pub fn buildImage(b: *std.Build, optimize: std.builtin.OptimizeMode) *Step {
const target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .freestanding, .abi = .none });
const kcapsule = buildKcapsule(b, target, optimize);
const setup = buildSetup(b, target, optimize, kcapsule);
const image = b.addSystemCommand(&[_][]const u8{
"sh",
"arch/x86/boot/helper.sh",
"build_image",
});
image.addFileArg(setup.getEmittedBin());
image.addFileArg(kcapsule.getEmittedBin());
image.step.dependOn(&setup.step);
image.step.dependOn(&kcapsule.step);
return &image.step;
}

View File

@@ -1,86 +0,0 @@
#include "format/pe.h"
#include "offset.h"
.set salign, 0x1000
.set falign, 0x200
.section ".bstext", "ax" // allocatable, executable
.word IMAGE_DOS_SIGNATURE
.org 0x3c
.long pe_header
.global pe_header
pe_header:
.long IMAGE_NT_SIGNATURE
coff_header:
.word IMAGE_FILE_MACHINE_AMD64
.word section_count
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
.long 0 /* NumberOfSymbols */
.word section_table - optional_header /* SizeOfOptionalHeader */
.word IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_LINE_NUMS_STRIPPED /* Characteristics */
optional_header:
.word IMAGE_NT_OPTIONAL_HDR64_MAGIC /* Magic */
.byte 0 /* MajorLinkerVersion */
.byte 0 /* MinorLinkerVersion */
.long CAP__data /* SizeOfCode */
.long CAP__end - CAP__data /* SizeOfInitializedData */
.long 0 /* SizeOfUninitializedData */
.long setup_size + efi_pe_entry /* AddressOfEntryPoint */
.long setup_size /* BaseOfCode */
extra_header_fields:
.quad 0 /* ImageBase */
.long salign /* SectionAlignment */
.long falign /* FileAlignment */
.word 0 /* MajorOperatingSystemVersion */
.word 0 /* MinorOperatingSystemVersion */
.word 0 /* MajorImageVersion */
.word 0 /* MinorImageVersion */
.word 0 /* MajorSubsystemVersion */
.word 0 /* MinorSubsystemVersion */
.long 0 /* Win32VersionValue */
.long setup_size + CAP__end /* SizeOfImage */
.long salign /* SizeOfHeaders */
.long 0 /* CheckSum */
.word IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */
.word IMAGE_DLLCHARACTERISTICS_NX_COMPAT /* DllCharacteristics */
.quad 0 /* SizeOfStackReserve */
.quad 0 /* SizeOfStackCommit */
.quad 0 /* SizeOfHeapReserve */
.quad 0 /* SizeOfHeapCommit */
.long 0 /* LoaderFlags */
.long (section_table - .) / 8 /* NumberOfRvaAndSizes */
.quad 0
.quad 0
.quad 0
.quad 0
.quad 0
.quad 0
section_table:
# .ascii ".setup\0\0"
# .long setup_size - salign /* VirtualSize */
# .long salign /* VirtualAddress */
# .long setup_size - salign /* SizeOfRawData */
# .long salign /* PointerToRawData */
# .long 0,0,0
# .long IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
.ascii ".text\0\0\0"
.long text_size /* VirtualSize */
.long setup_size /* VirtualAddress */
.long text_size /* SizeOfRawData */
.long setup_size /* PointerToRawData */
.long 0,0,0
.long IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE
.ascii ".data\0\0\0"
.long CAP__end - CAP__data /* VirtualSize */
.long setup_size + CAP__data /* VirtualAddress */
.long CAP__edata - CAP__data /* SizeOfRawData */
.long setup_size + CAP__data /* PointerToRawData */
.long 0,0,0
.long IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
.set text_size, CAP__data
.set section_count, (. - section_table) / 40

View File

@@ -1,30 +0,0 @@
#!/bin/bash
generate_offset_header() {
echo "processing $1"
nm -n "$1" \
| grep -e ' _\(end\|edata\|data\)$' \
| awk '{print "#define CAP_" $3 " 0x" $1}' \
> arch/x86/boot/offset.h
nm -n "$1" \
| grep -e ' efi_pe_entry$' \
| awk '{print "#define efi_pe_entry 0x" $1}' \
>> arch/x86/boot/offset.h
}
build_image() {
echo "building image from $1 and $2"
(dd if=$1 bs=4k conv=sync; cat $2) > yukiImage
}
# Main dispatcher
case "$1" in
generate_offset_header)
generate_offset_header "$2"
;;
build_image)
build_image "$2" "$3"
;;
*)
echo "Usage: $0 {generate_offset_header|build_image} [args...]"
exit 1
;;
esac

View File

@@ -1,60 +0,0 @@
OUTPUT_ARCH(i386:x86_64)
SECTIONS {
. = 0x1000;
.text : {
_text = .;
*(.text)
*(.text.*)
_etext = .;
}
.rodata : {
_rodata = .;
*(.rodata)
*(.rodata.*)
_erodata = .;
}
. = ALIGN(0x1000);
.data : {
_data = .;
*(.data)
*(.data.*)
. = ALIGN(0x1000);
_edata = .;
}
.bss : {
_bss = .;
*(.bss)
*(.bss.*)
*(COMMON)
_ebss = .;
}
.pgtable : {
_pgtable = .;
*(.pgtable)
_epgtable = .;
}
. = ALIGN(0x1000);
_end = .;
.got.plt (INFO) : {
*(.got.plt)
}
ASSERT(SIZEOF(.got.plt) == 0 ||
SIZEOF(.got.plt) == 0x18,
"Unexpected GOT/PLT entries detected!")
/*
* Sections that should stay zero sized, which is safer to
* explicitly check instead of blindly discarding.
*/
.got : {
*(.got)
}
ASSERT(SIZEOF(.got) == 0, "Unexpected GOT entries detected!")
.plt : {
*(.plt) *(.plt.*)
}
ASSERT(SIZEOF(.plt) == 0, "Unexpected run-time procedure linkages detected!")
}

View File

@@ -1,28 +0,0 @@
OUTPUT_FORMAT(binary)
OUTPUT_ARCH(i386)
ENTRY(_start)
SECTIONS {
. = 0;
.bstext : {
*(.bstext)
. = 495;
} =0xffffffff
.text : {*(.text .text.*)}
. = ALIGN(16);
.rodata : {*(.rodata .rodata.*)}
. = ALIGN(16);
.data : {*(.data .data.*)}
setup_size = ALIGN(ABSOLUTE(.), 4096);
. = ALIGN(16);
.bss : {*(.bss) }
. = ALIGN(16);
/DISCARD/ : {
*(.note*)
}
}

View File

@@ -1,29 +0,0 @@
OUTPUT_ARCH(i386:x86_64)
ENTRY(kernel_start)
SECTIONS {
.text : {
*(.text)
*(.text.*)
}
.rodata : {
*(.rodata)
*(.rodata.*)
}
.data : {
*(.data)
*(.data.*)
}
.bss : {
*(.bss)
*(.bss.*)
*(COMMON)
}
.pgtable : {
*(.pgtable)
}
. = ALIGN(0x1000);
}

3
arch/x86_64/arch.zig Normal file
View File

@@ -0,0 +1,3 @@
pub const io = @import("io.zig");
pub const processor = @import("processor.zig");
pub const mem = @import("mem.zig");

View 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;

View 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(&copy_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);
}

View 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});
}

View 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();
}

View 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();
}

View 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;
}
}
};

View 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 {};
}

View 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
View 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
View 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

View File

@@ -0,0 +1,9 @@
OUTPUT_ARCH(x86_64)
SECTIONS {
. = 0;
.header : {
KEEP(*(.header))
}
header_size = ALIGN(ABSOLUTE(.), 4096);
}

View 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
View 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);
}

View 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

View 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)

View 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

View 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

View 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.*)
}
}

View 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;
}

View 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
};

View 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));
}

View 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));
}
}
}

View 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);
}

View 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
View 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
View 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
View 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
View 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
View 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
};

View File

@@ -1,35 +1,25 @@
const std = @import("std"); const std = @import("std");
const kernel_build = @import("kernel/build.zig");
fn buildImage(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step {
switch (target.result.cpu.arch) {
.x86_64 => {
const arch_build = @import("arch/x86/boot/build.zig");
return arch_build.buildImage(b, optimize);
},
else => {
@panic("target architecture unsupported");
}
}
}
pub fn build(b: *std.Build) void { pub fn build(b: *std.Build) void {
const kernel_only_step = b.step("kernel", "Build the kernel only"); var arch_build_image: ?*const fn(*std.Build)void = null;
const full_step = b.step("full", "Build the full OS image"); const target = b.standardTargetOptions(.{
const qemu_step = b.step("qemu", "Build and run in QEMU"); .default_target = .{
const target = b.resolveTargetQuery(.{
.cpu_arch = .x86_64, .cpu_arch = .x86_64,
.os_tag = .freestanding, .os_tag = .freestanding,
.abi = .none .abi = .none,
}
}); });
const optimize = b.standardOptimizeOption(.{}); if (target.query.cpu_arch) |arch| {
switch (arch) {
const kernel_install = kernel_build.buildKernelBin(b, target, optimize); .x86_64 => {
kernel_only_step.dependOn(&kernel_install.step); arch_build_image = @import("arch/x86_64/build_arch.zig").buildImage;
const image_step = buildImage(b, target, optimize); },
b.getInstallStep().dependOn(image_step); else => {},
full_step.dependOn(image_step); }
}
qemu_step.dependOn(image_step); if (arch_build_image) |build_fn| {
build_fn(b);
} else {
@panic("Architecture not specified or unsupported");
}
} }

View File

@@ -1,81 +1,27 @@
.{ .{
// This is the default name used by packages depending on this one. For
// example, when a user runs `zig fetch --save <url>`, this field is used
// as the key in the `dependencies` table. Although the user can choose a
// different name, most users will stick with this provided value.
//
// It is redundant to include "zig" in this name because it is already
// within the Zig package namespace.
.name = .YukiOS, .name = .YukiOS,
// This is a [Semantic Version](https://semver.org/).
// In a future version of Zig it will be used for package deduplication.
.version = "0.0.0", .version = "0.0.0",
// Together with name, this represents a globally unique package .fingerprint = 0x85d3440a268a6d56, // Changing this has security and trust implications.
// identifier. This field is generated by the Zig toolchain when the .minimum_zig_version = "0.16.0-dev.2471+e9eadee00",
// package is first created, and then *never changes*. This allows
// unambiguous detection of one package being an updated version of
// another.
//
// When forking a Zig project, this id should be regenerated (delete the
// field and run `zig build`) if the upstream project is still maintained.
// Otherwise, the fork is *hostile*, attempting to take control over the
// original project's identity. Thus it is recommended to leave the comment
// on the following line intact, so that it shows up in code reviews that
// modify the field.
.fingerprint = 0x85d3440a21cff096, // Changing this has security and trust implications.
// Tracks the earliest Zig version that the package considers to be a
// supported use case.
.minimum_zig_version = "0.15.2",
// This field is optional.
// Each dependency must either provide a `url` and `hash`, or a `path`.
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
// Once all dependencies are fetched, `zig build` no longer requires
// internet connectivity.
.dependencies = .{ .dependencies = .{
// See `zig fetch --save <url>` for a command-line interface for adding dependencies. .elfy = .{
//.example = .{ .url = "https://github.com/Hydrostic/elfy.zig/archive/refs/tags/v0.1.1.tar.gz",
// // When updating this field to a new URL, be sure to delete the corresponding .hash = "elfy-0.1.0-BML8MtggAQCLYjG-mEkO20uMf3-6cfU0_s3Xht3tSFWW",
// // `hash`, otherwise you are communicating that you expect to find the old hash at .lazy = false,
// // the new URL. If the contents of a URL change this will result in a hash mismatch },
// // which will prevent zig from using it. .mvzr = .{
// .url = "https://example.com/foo.tar.gz", .url = "https://github.com/mnemnion/mvzr/archive/refs/tags/v0.3.7.tar.gz",
// .hash = "mvzr-0.3.7-ZSOky5FtAQB2VrFQPNbXHQCFJxWTMAYEK7ljYEaMR6jt",
// // This is computed from the file contents of the directory of files that is .lazy = false,
// // obtained after fetching `url` and applying the inclusion rules given by }
// // `paths`.
// //
// // This field is the source of truth; packages do not come from a `url`; they
// // come from a `hash`. `url` is just one of many possible mirrors for how to
// // obtain a package matching this `hash`.
// //
// // Uses the [multihash](https://multiformats.io/multihash/) format.
// .hash = "...",
//
// // When this is provided, the package is found in a directory relative to the
// // build root. In this case the package's hash is irrelevant and therefore not
// // computed. This field and `url` are mutually exclusive.
// .path = "foo",
//
// // When this is set to `true`, a package is declared to be lazily
// // fetched. This makes the dependency only get fetched if it is
// // actually used.
// .lazy = false,
//},
}, },
// Specifies the set of files and directories that are included in this package.
// Only files and directories listed here are included in the `hash` that
// is computed for this package. Only files listed here will remain on disk
// when using the zig package manager. As a rule of thumb, one should list
// files required for compilation plus any license(s).
// Paths are relative to the build root. Use the empty string (`""`) to refer to
// the build root itself.
// A directory listed here means that all files within, recursively, are included.
.paths = .{ .paths = .{
"build.zig", "build.zig",
"build.zig.zon", "build.zig.zon",
"src", "arch",
// For example... "drivers",
//"LICENSE", "fs",
//"README.md", "kernel",
"mm",
}, },
} }

View File

@@ -1,75 +0,0 @@
const std = @import("std");
const uefi = std.os.uefi;
const unicode = std.unicode;
const SimpleTextOutput = uefi.protocol.SimpleTextOutput;
pub const UefiConsole = struct {
console_out: ?*SimpleTextOutput = null,
pub fn init(system_table: *uefi.tables.SystemTable) UefiConsole {
var console = UefiConsole{};
var con_out = system_table.con_out orelse return console;
con_out.clearScreen() catch return console;
con_out.setCursorPosition(0, 0) catch return console;
console.console_out = con_out;
UefiWriter.UEFI_WRITER_VTABLE = .{
.drain = UefiWriter.drain,
};
return console;
}
pub const UefiWriter = struct {
console: *UefiConsole,
interface: std.Io.Writer,
var UEFI_WRITER_VTABLE: std.io.Writer.VTable = .{
.drain = undefined,
};
pub fn drain(ptr: *std.Io.Writer, buf: []const []const u8, splat: usize) !usize {
_ = splat;
const self: *UefiWriter = @fieldParentPtr("interface", ptr);
if (self.console.console_out) |out| {
var written: usize = 0;
for (buf) |b| {
var start: usize = 0;
var ucs2_buf = [_]u16{0} ** 65;
while (start < buf.len) {
const len = unicode.utf8ToUtf16Le(ucs2_buf[0..64], b[start..@min(start + 64, b.len)]) catch {
return error.WriteFailed;
};
ucs2_buf[len] = 0;
_ = out.outputString(@ptrCast(&ucs2_buf)) catch {
return error.WriteFailed;
};
start += len;
}
written += b.len;
}
return written;
} else {
return 0;
}
}
};
pub fn writer(self: *UefiConsole) UefiWriter {
const w = UefiWriter{
.console = self,
.interface = .{
.vtable = @call(.never_inline, getVtable, .{}),
.buffer = &[0]u8{},
.end = 0
},
};
return w;
}
fn getVtable() *const std.Io.Writer.VTable {
return &UefiWriter.UEFI_WRITER_VTABLE;
}
};
pub var uc: UefiConsole = undefined;
pub fn initUefiConsole(system_table: *uefi.tables.SystemTable) void {
uc = UefiConsole.init(system_table);
}
pub fn info(comptime fmt: []const u8, args: anytype) void {
var w = uc.writer();
w.interface.print(fmt, args) catch {};
}

View File

@@ -1,17 +0,0 @@
const std = @import("std");
const console = @import("console.zig");
const uefi = std.os.uefi;
const SystemTable = uefi.tables.SystemTable;
export fn efi_pe_entry(image_handle: uefi.Handle, system_table: *SystemTable) callconv(.{ .x86_64_win = .{} }) uefi.Status {
const mark_ptr: *usize = @ptrFromInt(0x10000);
mark_ptr.* = 0xdeadbeef;
_ = image_handle;
if (system_table.hdr.signature != SystemTable.signature) {
return uefi.Status.invalid_parameter;
}
console.initUefiConsole(system_table);
console.info("Booting YukiOS kernel\n", .{});
while(true) {}
return .success;
}

View File

@@ -1,211 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Portable Executable (PE) format definitions.
*
* This file is derived from the Linux kernel source:
* include/linux/pe.h
*
* Copyright holders of the original Linux kernel code retain their copyright.
* See the original Linux kernel source for full copyright and licensing details.
*/
#define IMAGE_DOS_SIGNATURE 0x5a4d /* "MZ" */
#define IMAGE_NT_SIGNATURE 0x00004550 /* "PE\0\0" */
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x0107 /* ROM image (for R3000/R4000/R10000/ALPHA), without MZ and PE\0\0 sign */
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x010b /* PE32 executable image */
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x020b /* PE32+ executable image */
/* machine type */
#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 /* Unknown architecture */
#define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001 /* Interacts with the host and not a WOW64 guest (not for file image) */
#define IMAGE_FILE_MACHINE_ALPHA_OLD 0x0183 /* DEC Alpha AXP 32-bit (old images) */
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 /* DEC Alpha AXP 32-bit */
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 /* DEC Alpha AXP 64-bit (with 8kB page size) */
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_AM33 0x01d3 /* Matsushita AM33, now Panasonic MN103 */
#define IMAGE_FILE_MACHINE_AMD64 0x8664 /* AMD64 (x64) */
#define IMAGE_FILE_MACHINE_ARM 0x01c0 /* ARM Little-Endian (ARMv4) */
#define IMAGE_FILE_MACHINE_THUMB 0x01c2 /* ARM Thumb Little-Endian (ARMv4T) */
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 /* ARM Thumb-2 Little-Endian (ARMv7) */
#define IMAGE_FILE_MACHINE_ARMV7 IMAGE_FILE_MACHINE_ARMNT
#define IMAGE_FILE_MACHINE_ARM64 0xaa64 /* ARM64 Little-Endian (Classic ABI) */
#define IMAGE_FILE_MACHINE_ARM64EC 0xa641 /* ARM64 Little-Endian (Emulation Compatible ABI for AMD64) */
#define IMAGE_FILE_MACHINE_ARM64X 0xa64e /* ARM64 Little-Endian (fat binary with both Classic ABI and EC ABI code) */
#define IMAGE_FILE_MACHINE_CEE 0xc0ee /* COM+ Execution Engine (CLR pure MSIL object files) */
#define IMAGE_FILE_MACHINE_CEF 0x0cef /* Windows CE 3.0 Common Executable Format (CEF bytecode) */
#define IMAGE_FILE_MACHINE_CHPE_X86 0x3a64 /* ARM64 Little-Endian (Compiled Hybrid PE ABI for I386) */
#define IMAGE_FILE_MACHINE_HYBRID_X86 IMAGE_FILE_MACHINE_CHPE_X86
#define IMAGE_FILE_MACHINE_EBC 0x0ebc /* EFI/UEFI Byte Code */
#define IMAGE_FILE_MACHINE_I386 0x014c /* Intel 386 (x86) */
#define IMAGE_FILE_MACHINE_I860 0x014d /* Intel 860 (N10) */
#define IMAGE_FILE_MACHINE_IA64 0x0200 /* Intel IA-64 (with 8kB page size) */
#define IMAGE_FILE_MACHINE_LOONGARCH32 0x6232 /* LoongArch 32-bit processor family */
#define IMAGE_FILE_MACHINE_LOONGARCH64 0x6264 /* LoongArch 64-bit processor family */
#define IMAGE_FILE_MACHINE_M32R 0x9041 /* Mitsubishi M32R 32-bit Little-Endian */
#define IMAGE_FILE_MACHINE_M68K 0x0268 /* Motorola 68000 series */
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 /* MIPS III with MIPS16 ASE Little-Endian */
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 /* MIPS III with FPU Little-Endian */
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 /* MIPS III with MIPS16 ASE and FPU Little-Endian */
#define IMAGE_FILE_MACHINE_MPPC_601 0x0601 /* PowerPC 32-bit Big-Endian */
#define IMAGE_FILE_MACHINE_OMNI 0xace1 /* Microsoft OMNI VM (omniprox.dll) */
#define IMAGE_FILE_MACHINE_PARISC 0x0290 /* HP PA-RISC */
#define IMAGE_FILE_MACHINE_POWERPC 0x01f0 /* PowerPC 32-bit Little-Endian */
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 /* PowerPC 32-bit with FPU Little-Endian */
#define IMAGE_FILE_MACHINE_POWERPCBE 0x01f2 /* PowerPC 64-bit Big-Endian */
#define IMAGE_FILE_MACHINE_R3000 0x0162 /* MIPS I Little-Endian */
#define IMAGE_FILE_MACHINE_R3000_BE 0x0160 /* MIPS I Big-Endian */
#define IMAGE_FILE_MACHINE_R4000 0x0166 /* MIPS III Little-Endian (with 1kB or 4kB page size) */
#define IMAGE_FILE_MACHINE_R10000 0x0168 /* MIPS IV Little-Endian */
#define IMAGE_FILE_MACHINE_RISCV32 0x5032 /* RISC-V 32-bit address space */
#define IMAGE_FILE_MACHINE_RISCV64 0x5064 /* RISC-V 64-bit address space */
#define IMAGE_FILE_MACHINE_RISCV128 0x5128 /* RISC-V 128-bit address space */
#define IMAGE_FILE_MACHINE_SH3 0x01a2 /* Hitachi SH-3 32-bit Little-Endian (with 1kB page size) */
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 /* Hitachi SH-3 DSP 32-bit (with 1kB page size) */
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 /* Hitachi SH-3E Little-Endian (with 1kB page size) */
#define IMAGE_FILE_MACHINE_SH4 0x01a6 /* Hitachi SH-4 32-bit Little-Endian (with 1kB page size) */
#define IMAGE_FILE_MACHINE_SH5 0x01a8 /* Hitachi SH-5 64-bit */
#define IMAGE_FILE_MACHINE_TAHOE 0x07cc /* Intel EM machine */
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 /* Infineon AUDO 32-bit */
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 /* MIPS Windows CE v2 Little-Endian */
/* flags */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 /* Relocation info stripped from file */
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 /* File is executable (i.e. no unresolved external references) */
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 /* Line nunbers stripped from file */
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 /* Local symbols stripped from file */
#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 /* Aggressively trim working set */
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 /* App can handle >2gb addresses (image can be loaded at address above 2GB) */
#define IMAGE_FILE_16BIT_MACHINE 0x0040 /* 16 bit word machine */
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 /* Bytes of machine word are reversed (should be set together with IMAGE_FILE_BYTES_REVERSED_HI) */
#define IMAGE_FILE_32BIT_MACHINE 0x0100 /* 32 bit word machine */
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 /* Debugging info stripped from file in .DBG file */
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 /* If Image is on removable media, copy and run from the swap file */
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 /* If Image is on Net, copy and run from the swap file */
#define IMAGE_FILE_SYSTEM 0x1000 /* System kernel-mode file (can't be loaded in user-mode) */
#define IMAGE_FILE_DLL 0x2000 /* File is a DLL */
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 /* File should only be run on a UP (uniprocessor) machine */
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 /* Bytes of machine word are reversed (should be set together with IMAGE_FILE_BYTES_REVERSED_LO) */
/* subsys */
#define IMAGE_SUBSYSTEM_UNKNOWN 0 /* Unknown subsystem */
#define IMAGE_SUBSYSTEM_NATIVE 1 /* No subsystem required (NT device drivers and NT native system processes) */
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 /* Windows graphical user interface (GUI) subsystem */
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 /* Windows character-mode user interface (CUI) subsystem */
#define IMAGE_SUBSYSTEM_WINDOWS_OLD_CE_GUI 4 /* Old Windows CE subsystem */
#define IMAGE_SUBSYSTEM_OS2_CUI 5 /* OS/2 CUI subsystem */
#define IMAGE_SUBSYSTEM_RESERVED_6 6
#define IMAGE_SUBSYSTEM_POSIX_CUI 7 /* POSIX CUI subsystem */
#define IMAGE_SUBSYSTEM_MMOSA 8 /* MMOSA/Native Win32E */
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 /* Windows CE subsystem */
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 /* Extensible Firmware Interface (EFI) application */
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 /* EFI driver with boot services */
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 /* EFI driver with run-time services */
#define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13 /* EFI ROM image */
#define IMAGE_SUBSYSTEM_XBOX 14 /* Xbox system */
#define IMAGE_SUBSYSTEM_RESERVED_15 15
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 /* Windows Boot application */
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG 17 /* Xbox Code Catalog */
/* dll_flags */
#define IMAGE_LIBRARY_PROCESS_INIT 0x0001 /* DLL initialization function called just after process initialization */
#define IMAGE_LIBRARY_PROCESS_TERM 0x0002 /* DLL initialization function called just before process termination */
#define IMAGE_LIBRARY_THREAD_INIT 0x0004 /* DLL initialization function called just after thread initialization */
#define IMAGE_LIBRARY_THREAD_TERM 0x0008 /* DLL initialization function called just before thread initialization */
#define IMAGE_DLLCHARACTERISTICS_RESERVED_4 0x0010
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 /* ASLR with 64 bit address space (image can be loaded at address above 4GB) */
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 /* The DLL can be relocated at load time */
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 /* Code integrity checks are forced */
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 /* Image is compatible with data execution prevention */
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 /* Image is isolation aware, but should not be isolated (prevents loading of manifest file) */
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 /* Image does not use SEH, no SE handler may reside in this image */
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 /* Do not bind the image */
#define IMAGE_DLLCHARACTERISTICS_X86_THUNK 0x1000 /* Image is a Wx86 Thunk DLL (for non-x86/risc DLL files) */
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 /* Image should execute in an AppContainer (for EXE Metro Apps in Windows 8) */
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 /* A WDM driver */
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 /* Image supports Control Flow Guard */
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 /* The image is terminal server (Remote Desktop Services) aware */
/* IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS flags */
#define IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT 0x0001 /* Image is Control-flow Enforcement Technology Shadow Stack compatible */
#define IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE 0x0002 /* CET is enforced in strict mode */
#define IMAGE_DLLCHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE 0x0004 /* Relaxed mode for Context IP Validation under CET is allowed */
#define IMAGE_DLLCHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC 0x0008 /* Use of dynamic APIs is restricted to processes only */
#define IMAGE_DLLCHARACTERISTICS_EX_CET_RESERVED_1 0x0010
#define IMAGE_DLLCHARACTERISTICS_EX_CET_RESERVED_2 0x0020
#define IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT 0x0040 /* All branch targets in all image code sections are annotated with forward-edge control flow integrity guard instructions */
#define IMAGE_DLLCHARACTERISTICS_EX_HOTPATCH_COMPATIBLE 0x0080 /* Image can be modified while in use, hotpatch-compatible */
/* section_header flags */
#define IMAGE_SCN_SCALE_INDEX 0x00000001 /* address of tls index is scaled = multiplied by 4 (for .tls section on MIPS only) */
#define IMAGE_SCN_TYPE_NO_LOAD 0x00000002 /* reserved */
#define IMAGE_SCN_TYPE_GROUPED 0x00000004 /* obsolete (used for 16-bit offset code) */
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* .o only - don't pad - obsolete (same as IMAGE_SCN_ALIGN_1BYTES) */
#define IMAGE_SCN_TYPE_COPY 0x00000010 /* reserved */
#define IMAGE_SCN_CNT_CODE 0x00000020 /* .text */
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* .o only - other type than code, data or info */
#define IMAGE_SCN_LNK_INFO 0x00000200 /* .o only - .drectve comments */
#define IMAGE_SCN_LNK_OVERLAY 0x00000400 /* section contains overlay */
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* .o only - scn to be rm'd*/
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* .o only - COMDAT data */
#define IMAGE_SCN_RESERVED_13 0x00002000 /* spec omits this */
#define IMAGE_SCN_MEM_PROTECTED 0x00004000 /* section is memory protected (for M68K) */
#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 /* reset speculative exceptions handling bits in the TLB entries (for non-M68K) */
#define IMAGE_SCN_MEM_FARDATA 0x00008000 /* section uses FAR_EXTERNAL relocations (for M68K) */
#define IMAGE_SCN_GPREL 0x00008000 /* global pointer referenced data (for non-M68K) */
#define IMAGE_SCN_MEM_SYSHEAP 0x00010000 /* use system heap (for M68K) */
#define IMAGE_SCN_MEM_PURGEABLE 0x00020000 /* section can be released from RAM (for M68K) */
#define IMAGE_SCN_MEM_16BIT 0x00020000 /* section is 16-bit (for non-M68K where it makes sense: I386, THUMB, MIPS16, MIPSFPU16, ...) */
#define IMAGE_SCN_MEM_LOCKED 0x00040000 /* prevent the section from being moved (for M68K and .o I386) */
#define IMAGE_SCN_MEM_PRELOAD 0x00080000 /* section is preload to RAM (for M68K and .o I386) */
/* and here they just stuck a 1-byte integer in the middle of a bitfield */
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 /* .o only - it does what it says on the box */
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000
#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
#define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000
#define IMAGE_SCN_ALIGN_RESERVED 0x00f00000
#define IMAGE_SCN_ALIGN_MASK 0x00f00000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* .o only - extended relocations */
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* not pageable */
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* can be shared */
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 /* can be executed as code */
#define IMAGE_SCN_MEM_READ 0x40000000 /* readable */
#define IMAGE_SCN_MEM_WRITE 0x80000000 /* writeable */
#define IMAGE_DEBUG_TYPE_UNKNOWN 0 /* Unknown value, ignored by all tools */
#define IMAGE_DEBUG_TYPE_COFF 1 /* COFF debugging information */
#define IMAGE_DEBUG_TYPE_CODEVIEW 2 /* CodeView debugging information or Visual C++ Program Database debugging information */
#define IMAGE_DEBUG_TYPE_FPO 3 /* Frame pointer omission (FPO) information */
#define IMAGE_DEBUG_TYPE_MISC 4 /* Location of DBG file with CodeView debugging information */
#define IMAGE_DEBUG_TYPE_EXCEPTION 5 /* Exception information, copy of .pdata section */
#define IMAGE_DEBUG_TYPE_FIXUP 6 /* Fixup information */
#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 /* The mapping from an RVA in image to an RVA in source image */
#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 /* The mapping from an RVA in source image to an RVA in image */
#define IMAGE_DEBUG_TYPE_BORLAND 9 /* Borland debugging information */
#define IMAGE_DEBUG_TYPE_RESERVED10 10 /* Coldpath / Hotpatch debug information */
#define IMAGE_DEBUG_TYPE_CLSID 11 /* CLSID */
#define IMAGE_DEBUG_TYPE_VC_FEATURE 12 /* Visual C++ counts / statistics */
#define IMAGE_DEBUG_TYPE_POGO 13 /* COFF group information, data for profile-guided optimization */
#define IMAGE_DEBUG_TYPE_ILTCG 14 /* Incremental link-time code generation */
#define IMAGE_DEBUG_TYPE_MPX 15 /* Intel Memory Protection Extensions */
#define IMAGE_DEBUG_TYPE_REPRO 16 /* PE determinism or reproducibility */
#define IMAGE_DEBUG_TYPE_EMBEDDED_PORTABLE_PDB 17 /* Embedded Portable PDB debugging information */
#define IMAGE_DEBUG_TYPE_SPGO 18 /* Sample profile-guided optimization */
#define IMAGE_DEBUG_TYPE_PDBCHECKSUM 19 /* PDB Checksum */
#define IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS 20 /* Extended DLL characteristics bits */
#define IMAGE_DEBUG_TYPE_PERFMAP 21 /* Location of associated Ready To Run PerfMap file */

View File

@@ -1,4 +0,0 @@
export fn kernel_start() noreturn {
while (true) {}
}

View File

@@ -1,32 +0,0 @@
const std = @import("std");
pub fn buildKernelBin(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.Compile {
const kernel = b.addExecutable(.{
.name = "kernel.bin",
.use_llvm = true,
.use_lld = true,
.root_module = b.createModule(.{
.root_source_file = b.path("init/main.zig"),
.target = target,
.optimize = optimize,
.code_model = .kernel,
}),
});
switch (target.result.cpu.arch) {
.x86_64 => {
kernel.setLinkerScript(b.path("arch/x86/kernel_bin.ld"));
},
else => {
@panic("target architecture unsupported");
}
}
kernel.entry = .{
.symbol_name = "kernel_start",
};
kernel.link_gc_sections = false;
return kernel;
}
pub fn buildKernelBinInstall(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) *std.Build.Step.InstallArtifact {
return b.addInstallArtifact(buildKernelBin(b, target, optimize), .{});
}

4
kernel/main.zig Normal file
View File

@@ -0,0 +1,4 @@
export fn start_kernel() callconv(.c) noreturn {
// Placeholder for kernel start function
while (true) {}
}

View File

@@ -1,11 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -e set -e
zig build
IMG=disk.img IMG=zig-out/disk.img
SIZE=256M SIZE=256M
MNT=/tmp/$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 16) MNT=/tmp/$(tr -dc 'A-Za-z0-9' </dev/urandom | head -c 16)
LIMINE_DIR=$HOME/Limine LIMINE_DIR=$HOME/Limine
KERNEL=./yukiImage KERNEL=zig-out/yukiImage
echo "[*] Creating disk image..." echo "[*] Creating disk image..."
rm -f "$IMG" rm -f "$IMG"
@@ -43,8 +44,9 @@ sudo tee "$MNT/boot/limine.conf" > /dev/null << 'EOF'
timeout: 1 timeout: 1
/Yuki OS /Yuki OS
protocol: efi protocol: multiboot2
path: boot():/boot/yukiImage path: boot():/boot/yukiImage
cmdline: earlyprintk=serial,ttyS0,115200
EOF EOF
echo "[*] Syncing..." echo "[*] Syncing..."
@@ -53,5 +55,6 @@ sync
echo "[*] Unmounting..." echo "[*] Unmounting..."
sudo umount "$MNT" sudo umount "$MNT"
sudo losetup -d "$LOOP" sudo losetup -d "$LOOP"
sudo chown $USER:$USER "$IMG"
rmdir "$MNT"
echo "[+] Done: $IMG created successfully" echo "[+] Done: $IMG created successfully"

7
tools/run_qemu.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/usr/bin/env bash
qemu-system-x86_64 \
-enable-kvm -cpu host \
-drive file=zig-out/disk.img,format=raw \
-drive if=pflash,readonly=on,file=/usr/share/edk2/ovmf/OVMF_CODE.fd \
-serial stdio
# -s -S