From 34ccf695695d05693ec68ab26fa5996e76936bc0 Mon Sep 17 00:00:00 2001 From: Hydrostic Date: Sat, 11 Apr 2026 09:42:09 +0800 Subject: [PATCH] feat(loader, kernel): impl part of loader and initialize kernel structure --- .gitignore | 9 +- .vscode/settings.json | 4 - README.md | 1 - arch/x86/boot/.gitignore | 1 - arch/x86/boot/build.zig | 86 ------ arch/x86/boot/extractor.zig | 0 arch/x86/boot/header.S | 86 ------ arch/x86/boot/helper.sh | 30 --- arch/x86/boot/kcapsule.ld | 60 ----- arch/x86/boot/payload.S | 0 arch/x86/boot/setup.ld | 28 -- arch/x86/boot/setup/stage1.zig | 0 arch/x86/kernel_bin.ld | 29 -- arch/x86_64/arch.zig | 3 + arch/x86_64/boot/boot.zig | 7 + arch/x86_64/boot/build_boot.zig | 159 +++++++++++ .../boot/build_tool/compress_kernel.zig | 57 ++++ .../x86_64/boot/build_tool/generate_image.zig | 50 ++++ .../x86_64/boot/build_tool/symbol_extract.zig | 41 +++ arch/x86_64/boot/cmdline.zig | 82 ++++++ arch/x86_64/boot/early_serial_console.zig | 118 +++++++++ arch/x86_64/boot/extractor.zig | 46 ++++ arch/x86_64/boot/head.S | 181 +++++++++++++ arch/x86_64/boot/header.S | 69 +++++ arch/x86_64/boot/header.ld | 9 + arch/x86_64/boot/ident_map.zig | 62 +++++ arch/x86_64/boot/idt.zig | 23 ++ arch/x86_64/boot/idt_handlers.S | 56 ++++ arch/x86_64/boot/include/boot.h | 6 + arch/x86_64/boot/include/multiboot2.h | 39 +++ arch/x86_64/boot/include/processor_flags.h | 15 ++ arch/x86_64/boot/kcapsule.ld | 59 +++++ arch/x86_64/boot/multiboot.zig | 250 ++++++++++++++++++ arch/x86_64/boot/params.zig | 52 ++++ arch/x86_64/boot/payload.zig | 13 + arch/x86_64/boot/relocate.zig | 20 ++ arch/x86_64/boot/video.zig | 67 +++++ arch/x86_64/build_arch.zig | 26 ++ arch/x86_64/desc.zig | 43 +++ arch/x86_64/io.zig | 19 ++ arch/x86_64/mem.zig | 43 +++ arch/x86_64/processor.zig | 44 +++ arch/x86_64/trap.zig | 26 ++ build.zig | 50 ++-- build.zig.zon | 88 ++---- drivers/firmware/efi/console.zig | 75 ------ drivers/firmware/efi/x86.zig | 17 -- include/format/pe.h | 211 --------------- init/main.zig | 4 - kernel/build.zig | 32 --- kernel/main.zig | 4 + tools/build_img.sh | 13 +- tools/run_qemu.sh | 7 + 53 files changed, 1743 insertions(+), 777 deletions(-) delete mode 100644 .vscode/settings.json delete mode 100644 README.md delete mode 100644 arch/x86/boot/.gitignore delete mode 100644 arch/x86/boot/build.zig delete mode 100644 arch/x86/boot/extractor.zig delete mode 100644 arch/x86/boot/header.S delete mode 100644 arch/x86/boot/helper.sh delete mode 100644 arch/x86/boot/kcapsule.ld delete mode 100644 arch/x86/boot/payload.S delete mode 100644 arch/x86/boot/setup.ld delete mode 100644 arch/x86/boot/setup/stage1.zig delete mode 100644 arch/x86/kernel_bin.ld create mode 100644 arch/x86_64/arch.zig create mode 100644 arch/x86_64/boot/boot.zig create mode 100644 arch/x86_64/boot/build_boot.zig create mode 100644 arch/x86_64/boot/build_tool/compress_kernel.zig create mode 100644 arch/x86_64/boot/build_tool/generate_image.zig create mode 100644 arch/x86_64/boot/build_tool/symbol_extract.zig create mode 100644 arch/x86_64/boot/cmdline.zig create mode 100644 arch/x86_64/boot/early_serial_console.zig create mode 100644 arch/x86_64/boot/extractor.zig create mode 100644 arch/x86_64/boot/head.S create mode 100644 arch/x86_64/boot/header.S create mode 100644 arch/x86_64/boot/header.ld create mode 100644 arch/x86_64/boot/ident_map.zig create mode 100644 arch/x86_64/boot/idt.zig create mode 100644 arch/x86_64/boot/idt_handlers.S create mode 100644 arch/x86_64/boot/include/boot.h create mode 100644 arch/x86_64/boot/include/multiboot2.h create mode 100644 arch/x86_64/boot/include/processor_flags.h create mode 100644 arch/x86_64/boot/kcapsule.ld create mode 100644 arch/x86_64/boot/multiboot.zig create mode 100644 arch/x86_64/boot/params.zig create mode 100644 arch/x86_64/boot/payload.zig create mode 100644 arch/x86_64/boot/relocate.zig create mode 100644 arch/x86_64/boot/video.zig create mode 100644 arch/x86_64/build_arch.zig create mode 100644 arch/x86_64/desc.zig create mode 100644 arch/x86_64/io.zig create mode 100644 arch/x86_64/mem.zig create mode 100644 arch/x86_64/processor.zig create mode 100644 arch/x86_64/trap.zig delete mode 100644 drivers/firmware/efi/console.zig delete mode 100644 drivers/firmware/efi/x86.zig delete mode 100644 include/format/pe.h delete mode 100644 init/main.zig delete mode 100644 kernel/build.zig create mode 100644 kernel/main.zig create mode 100644 tools/run_qemu.sh diff --git a/.gitignore b/.gitignore index 5f92393..0e16c49 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,3 @@ -zig-out .zig-cache - -yukiImage -kcapsule -*.img - - +zig-out +zig-pkg \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 691fb1a..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "files.associations": { - } -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 33aa535..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# YukiOS diff --git a/arch/x86/boot/.gitignore b/arch/x86/boot/.gitignore deleted file mode 100644 index c834e83..0000000 --- a/arch/x86/boot/.gitignore +++ /dev/null @@ -1 +0,0 @@ -offset.h \ No newline at end of file diff --git a/arch/x86/boot/build.zig b/arch/x86/boot/build.zig deleted file mode 100644 index ec1a0c8..0000000 --- a/arch/x86/boot/build.zig +++ /dev/null @@ -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; -} diff --git a/arch/x86/boot/extractor.zig b/arch/x86/boot/extractor.zig deleted file mode 100644 index e69de29..0000000 diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S deleted file mode 100644 index a9ce82f..0000000 --- a/arch/x86/boot/header.S +++ /dev/null @@ -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 \ No newline at end of file diff --git a/arch/x86/boot/helper.sh b/arch/x86/boot/helper.sh deleted file mode 100644 index cc9deec..0000000 --- a/arch/x86/boot/helper.sh +++ /dev/null @@ -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 \ No newline at end of file diff --git a/arch/x86/boot/kcapsule.ld b/arch/x86/boot/kcapsule.ld deleted file mode 100644 index 4604ad3..0000000 --- a/arch/x86/boot/kcapsule.ld +++ /dev/null @@ -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!") -} \ No newline at end of file diff --git a/arch/x86/boot/payload.S b/arch/x86/boot/payload.S deleted file mode 100644 index e69de29..0000000 diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld deleted file mode 100644 index 812c50f..0000000 --- a/arch/x86/boot/setup.ld +++ /dev/null @@ -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*) - } - -} \ No newline at end of file diff --git a/arch/x86/boot/setup/stage1.zig b/arch/x86/boot/setup/stage1.zig deleted file mode 100644 index e69de29..0000000 diff --git a/arch/x86/kernel_bin.ld b/arch/x86/kernel_bin.ld deleted file mode 100644 index 0016bba..0000000 --- a/arch/x86/kernel_bin.ld +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/arch/x86_64/arch.zig b/arch/x86_64/arch.zig new file mode 100644 index 0000000..a4594f5 --- /dev/null +++ b/arch/x86_64/arch.zig @@ -0,0 +1,3 @@ +pub const io = @import("io.zig"); +pub const processor = @import("processor.zig"); +pub const mem = @import("mem.zig"); \ No newline at end of file diff --git a/arch/x86_64/boot/boot.zig b/arch/x86_64/boot/boot.zig new file mode 100644 index 0000000..8f3cee3 --- /dev/null +++ b/arch/x86_64/boot/boot.zig @@ -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; diff --git a/arch/x86_64/boot/build_boot.zig b/arch/x86_64/boot/build_boot.zig new file mode 100644 index 0000000..f38d4b5 --- /dev/null +++ b/arch/x86_64/boot/build_boot.zig @@ -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); +} \ No newline at end of file diff --git a/arch/x86_64/boot/build_tool/compress_kernel.zig b/arch/x86_64/boot/build_tool/compress_kernel.zig new file mode 100644 index 0000000..e92221f --- /dev/null +++ b/arch/x86_64/boot/build_tool/compress_kernel.zig @@ -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} \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}); +} \ No newline at end of file diff --git a/arch/x86_64/boot/build_tool/generate_image.zig b/arch/x86_64/boot/build_tool/generate_image.zig new file mode 100644 index 0000000..2271267 --- /dev/null +++ b/arch/x86_64/boot/build_tool/generate_image.zig @@ -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} \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(); +} \ No newline at end of file diff --git a/arch/x86_64/boot/build_tool/symbol_extract.zig b/arch/x86_64/boot/build_tool/symbol_extract.zig new file mode 100644 index 0000000..696cc7a --- /dev/null +++ b/arch/x86_64/boot/build_tool/symbol_extract.zig @@ -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} \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(); +} + diff --git a/arch/x86_64/boot/cmdline.zig b/arch/x86_64/boot/cmdline.zig new file mode 100644 index 0000000..2347710 --- /dev/null +++ b/arch/x86_64/boot/cmdline.zig @@ -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; + } + } +}; + + + diff --git a/arch/x86_64/boot/early_serial_console.zig b/arch/x86_64/boot/early_serial_console.zig new file mode 100644 index 0000000..5ef00ff --- /dev/null +++ b/arch/x86_64/boot/early_serial_console.zig @@ -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 {}; +} \ No newline at end of file diff --git a/arch/x86_64/boot/extractor.zig b/arch/x86_64/boot/extractor.zig new file mode 100644 index 0000000..99ed808 --- /dev/null +++ b/arch/x86_64/boot/extractor.zig @@ -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){} +} diff --git a/arch/x86_64/boot/head.S b/arch/x86_64/boot/head.S new file mode 100644 index 0000000..96086e7 --- /dev/null +++ b/arch/x86_64/boot/head.S @@ -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: \ No newline at end of file diff --git a/arch/x86_64/boot/header.S b/arch/x86_64/boot/header.S new file mode 100644 index 0000000..2d5ed72 --- /dev/null +++ b/arch/x86_64/boot/header.S @@ -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 \ No newline at end of file diff --git a/arch/x86_64/boot/header.ld b/arch/x86_64/boot/header.ld new file mode 100644 index 0000000..d56cb94 --- /dev/null +++ b/arch/x86_64/boot/header.ld @@ -0,0 +1,9 @@ +OUTPUT_ARCH(x86_64) + +SECTIONS { + . = 0; + .header : { + KEEP(*(.header)) + } + header_size = ALIGN(ABSOLUTE(.), 4096); +} \ No newline at end of file diff --git a/arch/x86_64/boot/ident_map.zig b/arch/x86_64/boot/ident_map.zig new file mode 100644 index 0000000..4d26297 --- /dev/null +++ b/arch/x86_64/boot/ident_map.zig @@ -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); +} \ No newline at end of file diff --git a/arch/x86_64/boot/idt.zig b/arch/x86_64/boot/idt.zig new file mode 100644 index 0000000..7acb442 --- /dev/null +++ b/arch/x86_64/boot/idt.zig @@ -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); +} \ No newline at end of file diff --git a/arch/x86_64/boot/idt_handlers.S b/arch/x86_64/boot/idt_handlers.S new file mode 100644 index 0000000..9047b98 --- /dev/null +++ b/arch/x86_64/boot/idt_handlers.S @@ -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 \ No newline at end of file diff --git a/arch/x86_64/boot/include/boot.h b/arch/x86_64/boot/include/boot.h new file mode 100644 index 0000000..d39fa83 --- /dev/null +++ b/arch/x86_64/boot/include/boot.h @@ -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) \ No newline at end of file diff --git a/arch/x86_64/boot/include/multiboot2.h b/arch/x86_64/boot/include/multiboot2.h new file mode 100644 index 0000000..488c536 --- /dev/null +++ b/arch/x86_64/boot/include/multiboot2.h @@ -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 + diff --git a/arch/x86_64/boot/include/processor_flags.h b/arch/x86_64/boot/include/processor_flags.h new file mode 100644 index 0000000..d2ac68b --- /dev/null +++ b/arch/x86_64/boot/include/processor_flags.h @@ -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 \ No newline at end of file diff --git a/arch/x86_64/boot/kcapsule.ld b/arch/x86_64/boot/kcapsule.ld new file mode 100644 index 0000000..51134a9 --- /dev/null +++ b/arch/x86_64/boot/kcapsule.ld @@ -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.*) + } + +} \ No newline at end of file diff --git a/arch/x86_64/boot/multiboot.zig b/arch/x86_64/boot/multiboot.zig new file mode 100644 index 0000000..5d89bb5 --- /dev/null +++ b/arch/x86_64/boot/multiboot.zig @@ -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; +} \ No newline at end of file diff --git a/arch/x86_64/boot/params.zig b/arch/x86_64/boot/params.zig new file mode 100644 index 0000000..649efea --- /dev/null +++ b/arch/x86_64/boot/params.zig @@ -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 +}; \ No newline at end of file diff --git a/arch/x86_64/boot/payload.zig b/arch/x86_64/boot/payload.zig new file mode 100644 index 0000000..b5a05e1 --- /dev/null +++ b/arch/x86_64/boot/payload.zig @@ -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)); +} \ No newline at end of file diff --git a/arch/x86_64/boot/relocate.zig b/arch/x86_64/boot/relocate.zig new file mode 100644 index 0000000..d22ddca --- /dev/null +++ b/arch/x86_64/boot/relocate.zig @@ -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)); + } + } +} diff --git a/arch/x86_64/boot/video.zig b/arch/x86_64/boot/video.zig new file mode 100644 index 0000000..1f4a3b1 --- /dev/null +++ b/arch/x86_64/boot/video.zig @@ -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); +} \ No newline at end of file diff --git a/arch/x86_64/build_arch.zig b/arch/x86_64/build_arch.zig new file mode 100644 index 0000000..f4f9b27 --- /dev/null +++ b/arch/x86_64/build_arch.zig @@ -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); +} \ No newline at end of file diff --git a/arch/x86_64/desc.zig b/arch/x86_64/desc.zig new file mode 100644 index 0000000..e1026b6 --- /dev/null +++ b/arch/x86_64/desc.zig @@ -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) + : .{} + ); +} \ No newline at end of file diff --git a/arch/x86_64/io.zig b/arch/x86_64/io.zig new file mode 100644 index 0000000..53e76d5 --- /dev/null +++ b/arch/x86_64/io.zig @@ -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; +} \ No newline at end of file diff --git a/arch/x86_64/mem.zig b/arch/x86_64/mem.zig new file mode 100644 index 0000000..b49a05d --- /dev/null +++ b/arch/x86_64/mem.zig @@ -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; + } +}; \ No newline at end of file diff --git a/arch/x86_64/processor.zig b/arch/x86_64/processor.zig new file mode 100644 index 0000000..2b86bb1 --- /dev/null +++ b/arch/x86_64/processor.zig @@ -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, +}; diff --git a/arch/x86_64/trap.zig b/arch/x86_64/trap.zig new file mode 100644 index 0000000..585ba12 --- /dev/null +++ b/arch/x86_64/trap.zig @@ -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 +}; diff --git a/build.zig b/build.zig index 5896e3a..4ac2f8f 100644 --- a/build.zig +++ b/build.zig @@ -1,35 +1,25 @@ 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 { - const kernel_only_step = b.step("kernel", "Build the kernel only"); - const full_step = b.step("full", "Build the full OS image"); - const qemu_step = b.step("qemu", "Build and run in QEMU"); - const target = b.resolveTargetQuery(.{ - .cpu_arch = .x86_64, - .os_tag = .freestanding, - .abi = .none + var arch_build_image: ?*const fn(*std.Build)void = null; + const target = b.standardTargetOptions(.{ + .default_target = .{ + .cpu_arch = .x86_64, + .os_tag = .freestanding, + .abi = .none, + } }); - const optimize = b.standardOptimizeOption(.{}); - - const kernel_install = kernel_build.buildKernelBin(b, target, optimize); - kernel_only_step.dependOn(&kernel_install.step); - const image_step = buildImage(b, target, optimize); - b.getInstallStep().dependOn(image_step); - full_step.dependOn(image_step); - - qemu_step.dependOn(image_step); - + if (target.query.cpu_arch) |arch| { + switch (arch) { + .x86_64 => { + arch_build_image = @import("arch/x86_64/build_arch.zig").buildImage; + }, + else => {}, + } + } + if (arch_build_image) |build_fn| { + build_fn(b); + } else { + @panic("Architecture not specified or unsupported"); + } } diff --git a/build.zig.zon b/build.zig.zon index d174b11..ec9abe6 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -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 `, 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, - // 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", - // Together with name, this represents a globally unique package - // identifier. This field is generated by the Zig toolchain when the - // 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. + .fingerprint = 0x85d3440a268a6d56, // Changing this has security and trust implications. + .minimum_zig_version = "0.16.0-dev.2471+e9eadee00", .dependencies = .{ - // See `zig fetch --save ` for a command-line interface for adding dependencies. - //.example = .{ - // // When updating this field to a new URL, be sure to delete the corresponding - // // `hash`, otherwise you are communicating that you expect to find the old hash at - // // the new URL. If the contents of a URL change this will result in a hash mismatch - // // which will prevent zig from using it. - // .url = "https://example.com/foo.tar.gz", - // - // // This is computed from the file contents of the directory of files that is - // // 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, - //}, + .elfy = .{ + .url = "https://github.com/Hydrostic/elfy.zig/archive/refs/tags/v0.1.1.tar.gz", + .hash = "elfy-0.1.0-BML8MtggAQCLYjG-mEkO20uMf3-6cfU0_s3Xht3tSFWW", + .lazy = false, + }, + .mvzr = .{ + .url = "https://github.com/mnemnion/mvzr/archive/refs/tags/v0.3.7.tar.gz", + .hash = "mvzr-0.3.7-ZSOky5FtAQB2VrFQPNbXHQCFJxWTMAYEK7ljYEaMR6jt", + .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 = .{ "build.zig", "build.zig.zon", - "src", - // For example... - //"LICENSE", - //"README.md", + "arch", + "drivers", + "fs", + "kernel", + "mm", }, } diff --git a/drivers/firmware/efi/console.zig b/drivers/firmware/efi/console.zig deleted file mode 100644 index 4b45ee9..0000000 --- a/drivers/firmware/efi/console.zig +++ /dev/null @@ -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 {}; -} \ No newline at end of file diff --git a/drivers/firmware/efi/x86.zig b/drivers/firmware/efi/x86.zig deleted file mode 100644 index 76838f9..0000000 --- a/drivers/firmware/efi/x86.zig +++ /dev/null @@ -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; -} diff --git a/include/format/pe.h b/include/format/pe.h deleted file mode 100644 index a85277f..0000000 --- a/include/format/pe.h +++ /dev/null @@ -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 */ \ No newline at end of file diff --git a/init/main.zig b/init/main.zig deleted file mode 100644 index 4c04715..0000000 --- a/init/main.zig +++ /dev/null @@ -1,4 +0,0 @@ -export fn kernel_start() noreturn { - while (true) {} - -} \ No newline at end of file diff --git a/kernel/build.zig b/kernel/build.zig deleted file mode 100644 index e2eeb12..0000000 --- a/kernel/build.zig +++ /dev/null @@ -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), .{}); -} \ No newline at end of file diff --git a/kernel/main.zig b/kernel/main.zig new file mode 100644 index 0000000..afedb59 --- /dev/null +++ b/kernel/main.zig @@ -0,0 +1,4 @@ +export fn start_kernel() callconv(.c) noreturn { + // Placeholder for kernel start function + while (true) {} +} \ No newline at end of file diff --git a/tools/build_img.sh b/tools/build_img.sh index fde120b..9aabfb0 100644 --- a/tools/build_img.sh +++ b/tools/build_img.sh @@ -1,11 +1,12 @@ #!/usr/bin/env bash set -e +zig build -IMG=disk.img +IMG=zig-out/disk.img SIZE=256M MNT=/tmp/$(tr -dc 'A-Za-z0-9' /dev/null << 'EOF' timeout: 1 /Yuki OS - protocol: efi + protocol: multiboot2 path: boot():/boot/yukiImage + cmdline: earlyprintk=serial,ttyS0,115200 EOF echo "[*] Syncing..." @@ -53,5 +55,6 @@ sync echo "[*] Unmounting..." sudo umount "$MNT" sudo losetup -d "$LOOP" - -echo "[+] Done: $IMG created successfully" \ No newline at end of file +sudo chown $USER:$USER "$IMG" +rmdir "$MNT" +echo "[+] Done: $IMG created successfully" diff --git a/tools/run_qemu.sh b/tools/run_qemu.sh new file mode 100644 index 0000000..8f8a340 --- /dev/null +++ b/tools/run_qemu.sh @@ -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 \ No newline at end of file