feat: add initial impl of efi-stub and kernel

This commit is contained in:
2026-01-28 16:01:38 +08:00
commit 1233ae9e9b
21 changed files with 845 additions and 0 deletions

1
arch/x86/boot/.gitignore vendored Normal file
View File

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

86
arch/x86/boot/build.zig Normal file
View File

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

View File

86
arch/x86/boot/header.S Normal file
View File

@@ -0,0 +1,86 @@
#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

30
arch/x86/boot/helper.sh Normal file
View File

@@ -0,0 +1,30 @@
#!/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

60
arch/x86/boot/kcapsule.ld Normal file
View File

@@ -0,0 +1,60 @@
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!")
}

0
arch/x86/boot/payload.S Normal file
View File

28
arch/x86/boot/setup.ld Normal file
View File

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

View File

29
arch/x86/kernel_bin.ld Normal file
View File

@@ -0,0 +1,29 @@
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);
}