mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-31 15:28:21 +00:00
initial commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub const Config = std.StringHashMap([]const u8);
|
||||
|
||||
pub const Platform = struct {
|
||||
arch: std.Target.Cpu.Arch,
|
||||
os: std.Target.Os.Tag,
|
||||
};
|
||||
|
||||
pub fn parseConfig(b: *std.Build) !Config {
|
||||
const file = try std.Io.Dir.cwd().readFileAlloc(b.graph.io, ".config", b.allocator, std.Io.Limit.unlimited);
|
||||
|
||||
var lines = std.mem.splitScalar(u8, file, '\n');
|
||||
|
||||
var map = std.StringHashMap([]const u8).init(b.allocator);
|
||||
|
||||
while (lines.next()) |line| {
|
||||
const trimmed = std.mem.trim(u8, line, " \r\t");
|
||||
if (trimmed.len == 0 or std.mem.startsWith(u8, trimmed, "#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var kv = std.mem.splitScalar(u8, trimmed, '=');
|
||||
const key = kv.first();
|
||||
const value = kv.rest();
|
||||
|
||||
try map.put(key, value);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
pub fn configStep(b: *std.Build) *std.Build.Step {
|
||||
return &b.addSystemCommand(&.{ "bash", "build/menuconfig" }).step;
|
||||
}
|
||||
|
||||
fn isInteger(str: []const u8) bool {
|
||||
_ = std.fmt.parseInt(i64, str, 10) catch return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn generateConfig(b: *std.Build, config: Config) !*std.Build.Step.WriteFile {
|
||||
var out = std.Io.Writer.Allocating.init(b.allocator);
|
||||
|
||||
var it = config.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const key = entry.key_ptr.*;
|
||||
const value = entry.value_ptr.*;
|
||||
|
||||
if (std.mem.eql(u8, value, "y")) {
|
||||
try out.writer.print("pub const {s}: bool = true;\n", .{key});
|
||||
} else if (isInteger(value)) {
|
||||
try out.writer.print("pub const {s}: i64 = {s};\n", .{ key, value });
|
||||
} else {
|
||||
try out.writer.print("pub const {s} = \"{s}\";\n", .{ key, value });
|
||||
}
|
||||
}
|
||||
|
||||
const wf = b.addWriteFiles();
|
||||
|
||||
_ = wf.add("config.gen.zig", out.written());
|
||||
_ = wf.addCopyFile(b.path(".config"), ".config");
|
||||
|
||||
return wf;
|
||||
}
|
||||
|
||||
pub fn getPlatform(config: Config) !Platform {
|
||||
const keys = .{
|
||||
.{ "CONFIG_ARCH_AMD64", Platform{ .arch = .x86_64, .os = .freestanding } },
|
||||
.{ "CONFIG_ARCH_AARCH64", Platform{ .arch = .aarch64, .os = .freestanding } },
|
||||
.{ "CONFIG_ARCH_RISCV64", Platform{ .arch = .riscv64, .os = .freestanding } },
|
||||
.{ "CONFIG_ARCH_UM", Platform{ .arch = builtin.cpu.arch, .os = .linux } },
|
||||
};
|
||||
|
||||
inline for (keys) |entry| {
|
||||
if (config.get(entry[0])) |val| {
|
||||
if (std.mem.eql(u8, val, "y")) return entry[1];
|
||||
}
|
||||
}
|
||||
|
||||
return error.NoArchConfigured;
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
|
||||
fn addLimineTool(b: *std.Build, limine: *std.Build.Dependency) *std.Build.Step.Compile {
|
||||
const tool = b.addExecutable(.{ .name = "limine", .root_module = b.addModule("limine", .{
|
||||
.target = b.graph.host,
|
||||
.link_libc = true,
|
||||
}) });
|
||||
tool.root_module.addCSourceFile(.{ .file = limine.path("limine.c") });
|
||||
return tool;
|
||||
}
|
||||
|
||||
pub const IsoResult = struct {
|
||||
step: *std.Build.Step,
|
||||
path: std.Build.LazyPath,
|
||||
};
|
||||
|
||||
pub fn addIso(
|
||||
b: *std.Build,
|
||||
arch: Arch,
|
||||
image_name: []const u8,
|
||||
kernel: *std.Build.Step.Compile,
|
||||
limine: *std.Build.Dependency,
|
||||
) IsoResult {
|
||||
const limine_tool = addLimineTool(b, limine);
|
||||
const kernel_bin = kernel.getEmittedBin();
|
||||
|
||||
const prep_script =
|
||||
\\set -euo pipefail
|
||||
\\kernel="$1"
|
||||
\\iso_root="$2"
|
||||
\\limine_conf="$3"
|
||||
\\limine_dir="$4"
|
||||
\\arch="$5"
|
||||
\\rm -rf "$iso_root"
|
||||
\\mkdir -p "$iso_root/boot/limine" "$iso_root/EFI/BOOT"
|
||||
\\cp "$kernel" "$iso_root/boot/kernel"
|
||||
\\cp "$limine_conf" "$iso_root/boot/limine/limine.conf"
|
||||
\\case "$arch" in
|
||||
\\ x86_64)
|
||||
\\ cp "$limine_dir/limine-bios.sys" "$limine_dir/limine-bios-cd.bin" "$limine_dir/limine-uefi-cd.bin" "$iso_root/boot/limine/"
|
||||
\\ cp "$limine_dir/BOOTX64.EFI" "$limine_dir/BOOTIA32.EFI" "$iso_root/EFI/BOOT/"
|
||||
\\ ;;
|
||||
\\ aarch64)
|
||||
\\ cp "$limine_dir/limine-uefi-cd.bin" "$iso_root/boot/limine/"
|
||||
\\ cp "$limine_dir/BOOTAA64.EFI" "$iso_root/EFI/BOOT/"
|
||||
\\ ;;
|
||||
\\ riscv64)
|
||||
\\ cp "$limine_dir/limine-uefi-cd.bin" "$iso_root/boot/limine/"
|
||||
\\ cp "$limine_dir/BOOTRISCV64.EFI" "$iso_root/EFI/BOOT/"
|
||||
\\ ;;
|
||||
\\ loongarch64)
|
||||
\\ cp "$limine_dir/limine-uefi-cd.bin" "$iso_root/boot/limine/"
|
||||
\\ cp "$limine_dir/BOOTLOONGARCH64.EFI" "$iso_root/EFI/BOOT/"
|
||||
\\ ;;
|
||||
\\esac
|
||||
;
|
||||
|
||||
const iso_root = b.addTempFiles();
|
||||
|
||||
const prep = b.addSystemCommand(&.{ "bash", "-ceu", prep_script, "--" });
|
||||
|
||||
prep.addFileArg(kernel_bin);
|
||||
prep.addDirectoryArg(iso_root.getDirectory());
|
||||
prep.addFileArg(b.path("build/limine.conf"));
|
||||
prep.addDirectoryArg(limine.path("."));
|
||||
prep.addArg(@tagName(arch));
|
||||
prep.step.dependOn(&iso_root.step);
|
||||
|
||||
const mkiso = b.addSystemCommand(&.{ "xorriso", "-as", "mkisofs", "-R", "-r", "-J" });
|
||||
switch (arch) {
|
||||
.x86_64 => mkiso.addArgs(&.{
|
||||
"-b", "boot/limine/limine-bios-cd.bin",
|
||||
"-no-emul-boot", "-boot-load-size",
|
||||
"4", "-boot-info-table",
|
||||
"-hfsplus", "-apm-block-size",
|
||||
"2048", "--efi-boot",
|
||||
"boot/limine/limine-uefi-cd.bin", "-efi-boot-part",
|
||||
"--efi-boot-image", "--protective-msdos-label",
|
||||
}),
|
||||
else => mkiso.addArgs(&.{
|
||||
"-hfsplus",
|
||||
"-apm-block-size",
|
||||
"2048",
|
||||
"--efi-boot",
|
||||
"boot/limine/limine-uefi-cd.bin",
|
||||
"-efi-boot-part",
|
||||
"--efi-boot-image",
|
||||
"--protective-msdos-label",
|
||||
}),
|
||||
}
|
||||
mkiso.addDirectoryArg(iso_root.getDirectory());
|
||||
mkiso.addArg("-o");
|
||||
const iso_out = mkiso.addOutputFileArg(b.fmt("{s}.iso", .{image_name}));
|
||||
mkiso.step.dependOn(&prep.step);
|
||||
|
||||
if (arch == .x86_64) {
|
||||
const bios_install = b.addRunArtifact(limine_tool);
|
||||
bios_install.addArg("bios-install");
|
||||
bios_install.addFileArg(iso_out);
|
||||
bios_install.step.dependOn(&mkiso.step);
|
||||
}
|
||||
|
||||
const install_iso = b.addInstallFile(iso_out, b.fmt("{s}.iso", .{image_name}));
|
||||
install_iso.step.dependOn(&mkiso.step);
|
||||
return .{
|
||||
.step = &install_iso.step,
|
||||
.path = iso_out,
|
||||
};
|
||||
}
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python3
|
||||
# Simple kernel symbol dumper
|
||||
# Usage: ksyms.py --input <kernel binary> --output <output file>
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
import argparse
|
||||
|
||||
excluded_symbols = ['text_start_addr', 'text_end_addr', 'rodata_start_addr', 'rodata_end_addr', 'data_start_addr', 'data_end_addr']
|
||||
|
||||
def parse_nm_line(line: str) -> tuple[int, str]:
|
||||
parts = line.split()
|
||||
if len(parts) < 3:
|
||||
return None
|
||||
|
||||
addr_str, type, name = parts[0], parts[1], parts[2]
|
||||
|
||||
# Only get symbols in text
|
||||
if type.lower() != 't':
|
||||
return None
|
||||
|
||||
if name in excluded_symbols:
|
||||
return None
|
||||
|
||||
addr = int(addr_str, 16)
|
||||
return addr, name
|
||||
|
||||
def run_nm(binary: str) -> list[str]:
|
||||
|
||||
result = subprocess.run(["nm", "-n", binary], capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(f"nm failed: {result.stderr}")
|
||||
return result.stdout.splitlines()
|
||||
|
||||
parser = argparse.ArgumentParser(description="Generate kernel symbols from a binary")
|
||||
parser.add_argument("--input", help="Input kernel binary")
|
||||
parser.add_argument("--output", help="Output C file")
|
||||
parser.add_argument("--empty", action="store_true", help="Generate empty ksyms")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.empty:
|
||||
with open(args.output, 'w') as f:
|
||||
f.write("// Auto-generated by build/ksyms.py - do not edit\n\n")
|
||||
f.write("pub const KSym = struct {\n addr: u64,\n name: []const u8,\n};\n\n")
|
||||
f.write("pub const ksyms: []const KSym = &.{};\n")
|
||||
sys.exit(0)
|
||||
|
||||
lines = run_nm(args.input)
|
||||
|
||||
symbols = []
|
||||
for line in lines:
|
||||
parsed = parse_nm_line(line)
|
||||
if parsed:
|
||||
symbols.append(parsed)
|
||||
|
||||
|
||||
# Sort by address
|
||||
symbols.sort(key=lambda x: x[0])
|
||||
|
||||
with open(args.output, 'w') as f:
|
||||
f.write("// Auto-generated by build/ksyms.py - do not edit\n\n")
|
||||
f.write("pub const KSym = struct {\n addr: u64,\n name: []const u8,\n};\n\n")
|
||||
f.write("pub const ksyms: []const KSym = &.{\n")
|
||||
for addr, name in symbols:
|
||||
f.write(f" .{{ .addr = 0x{addr:016x}, .name = \"{name}\" }},\n")
|
||||
f.write("};\n")
|
||||
@@ -0,0 +1,11 @@
|
||||
# Timeout in seconds that Limine will use before automatically booting.
|
||||
timeout: 3
|
||||
|
||||
# The entry name that will be displayed in the boot menu.
|
||||
/Limine Template (Zig)
|
||||
# We use the Limine boot protocol.
|
||||
protocol: limine
|
||||
|
||||
# Path to the kernel to boot. boot():/ represents the partition on which limine.conf is located.
|
||||
path: boot():/boot/kernel
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Tell the linker that we want an aarch64 ELF64 output file */
|
||||
OUTPUT_FORMAT(elf64-littleaarch64)
|
||||
|
||||
/* We want the symbol kmain to be our entry point */
|
||||
ENTRY(kmain)
|
||||
|
||||
/* Define the program headers we want so the bootloader gives us the right */
|
||||
/* MMU permissions; this also allows us to exert more control over the linking */
|
||||
/* process. */
|
||||
PHDRS
|
||||
{
|
||||
limine_requests PT_LOAD;
|
||||
text PT_LOAD;
|
||||
rodata PT_LOAD;
|
||||
data PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
|
||||
/* and because that is what the Limine spec mandates. */
|
||||
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
|
||||
/* that is the beginning of the region. */
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
KEEP(*(.limine_requests_end))
|
||||
} :limine_requests
|
||||
|
||||
/* Move to the next memory page for .text */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
/* Move to the next memory page for .rodata */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
/* Add a .note.gnu.build-id output section in case a build ID flag is added to the */
|
||||
/* linker command. */
|
||||
.note.gnu.build-id : {
|
||||
*(.note.gnu.build-id)
|
||||
} :rodata
|
||||
|
||||
/* Move to the next memory page for .data */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
|
||||
/* unnecessary zeros will be written to the binary. */
|
||||
/* If you need, for example, .init_array and .fini_array, those should be placed */
|
||||
/* above this. */
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame*)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Tell the linker that we want a loongarch64 ELF64 output file */
|
||||
OUTPUT_FORMAT(elf64-loongarch)
|
||||
|
||||
/* We want the symbol kmain to be our entry point */
|
||||
ENTRY(kmain)
|
||||
|
||||
/* Define the program headers we want so the bootloader gives us the right */
|
||||
/* MMU permissions; this also allows us to exert more control over the linking */
|
||||
/* process. */
|
||||
PHDRS
|
||||
{
|
||||
limine_requests PT_LOAD;
|
||||
text PT_LOAD;
|
||||
rodata PT_LOAD;
|
||||
data PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
|
||||
/* and because that is what the Limine spec mandates. */
|
||||
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
|
||||
/* that is the beginning of the region. */
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
KEEP(*(.limine_requests_end))
|
||||
} :limine_requests
|
||||
|
||||
/* Move to the next memory page for .text */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
/* Move to the next memory page for .rodata */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
/* Add a .note.gnu.build-id output section in case a build ID flag is added to the */
|
||||
/* linker command. */
|
||||
.note.gnu.build-id : {
|
||||
*(.note.gnu.build-id)
|
||||
} :rodata
|
||||
|
||||
/* Move to the next memory page for .data */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
|
||||
/* unnecessary zeros will be written to the binary. */
|
||||
/* If you need, for example, .init_array and .fini_array, those should be placed */
|
||||
/* above this. */
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame*)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Tell the linker that we want a riscv64 ELF64 output file */
|
||||
OUTPUT_FORMAT(elf64-littleriscv)
|
||||
|
||||
/* We want the symbol kmain to be our entry point */
|
||||
ENTRY(kmain)
|
||||
|
||||
/* Define the program headers we want so the bootloader gives us the right */
|
||||
/* MMU permissions; this also allows us to exert more control over the linking */
|
||||
/* process. */
|
||||
PHDRS
|
||||
{
|
||||
limine_requests PT_LOAD;
|
||||
text PT_LOAD;
|
||||
rodata PT_LOAD;
|
||||
data PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
|
||||
/* and because that is what the Limine spec mandates. */
|
||||
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
|
||||
/* that is the beginning of the region. */
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
KEEP(*(.limine_requests_end))
|
||||
} :limine_requests
|
||||
|
||||
/* Move to the next memory page for .text */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
/* Move to the next memory page for .rodata */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
/* Add a .note.gnu.build-id output section in case a build ID flag is added to the */
|
||||
/* linker command. */
|
||||
.note.gnu.build-id : {
|
||||
*(.note.gnu.build-id)
|
||||
} :rodata
|
||||
|
||||
/* Move to the next memory page for .data */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
|
||||
/* unnecessary zeros will be written to the binary. */
|
||||
/* If you need, for example, .init_array and .fini_array, those should be placed */
|
||||
/* above this. */
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame*)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Tell the linker that we want an x86_64 ELF64 output file */
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
|
||||
/* We want the symbol kmain to be our entry point */
|
||||
ENTRY(kmain)
|
||||
|
||||
/* Define the program headers we want so the bootloader gives us the right */
|
||||
/* MMU permissions; this also allows us to exert more control over the linking */
|
||||
/* process. */
|
||||
PHDRS
|
||||
{
|
||||
limine_requests PT_LOAD;
|
||||
text PT_LOAD;
|
||||
rodata PT_LOAD;
|
||||
data PT_LOAD;
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* We want to be placed in the topmost 2GiB of the address space, for optimisations */
|
||||
/* and because that is what the Limine spec mandates. */
|
||||
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
|
||||
/* that is the beginning of the region. */
|
||||
. = 0xffffffff80000000;
|
||||
|
||||
/* Define a section to contain the Limine requests and assign it to its own PHDR */
|
||||
.limine_requests : {
|
||||
KEEP(*(.limine_requests_start))
|
||||
KEEP(*(.limine_requests))
|
||||
KEEP(*(.limine_requests_end))
|
||||
} :limine_requests
|
||||
|
||||
/* Move to the next memory page for .text */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.text : {
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
|
||||
/* Move to the next memory page for .rodata */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.rodata : {
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
/* Add a .note.gnu.build-id output section in case a build ID flag is added to the */
|
||||
/* linker command. */
|
||||
.note.gnu.build-id : {
|
||||
*(.note.gnu.build-id)
|
||||
} :rodata
|
||||
|
||||
/* Move to the next memory page for .data */
|
||||
. = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
.data : {
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
/* NOTE: .bss needs to be the last thing mapped to :data, otherwise lots of */
|
||||
/* unnecessary zeros will be written to the binary. */
|
||||
/* If you need, for example, .init_array and .fini_array, those should be placed */
|
||||
/* above this. */
|
||||
.bss : {
|
||||
*(.bss .bss.*)
|
||||
*(COMMON)
|
||||
} :data
|
||||
|
||||
/* Discard .note.* and .eh_frame* since they may cause issues on some hosts. */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame*)
|
||||
*(.note .note.*)
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
frontend="${FRONTEND:-kconfig-nconf}"
|
||||
|
||||
has_kconfig_frontends=true
|
||||
|
||||
if ! command -v kconfig-mconf &> /dev/null
|
||||
then
|
||||
has_kconfig_frontends=false
|
||||
fi
|
||||
|
||||
|
||||
if [ "$has_kconfig_frontends" = false ]; then
|
||||
if ! command -v python3 -m menuconfig -h &> /dev/null
|
||||
then
|
||||
echo "No Kconfig frontend found. Please install kconfig-frontends or python3-kconfiglib"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python3 -m menuconfig
|
||||
else
|
||||
$frontend Kconfig
|
||||
fi
|
||||
@@ -0,0 +1,69 @@
|
||||
const std = @import("std");
|
||||
const config = @import("config.zig");
|
||||
const image = @import("image.zig");
|
||||
|
||||
const QemuArgs = struct {
|
||||
suffix: []u8,
|
||||
args: [][]u8,
|
||||
};
|
||||
|
||||
pub fn addRun(b: *std.Build, kernel: *std.Build.Step.Compile, plat: config.Platform) void {
|
||||
const run_step = b.step("run", "Run the kernel");
|
||||
const uefi = b.option(bool, "uefi", "Boot with UEFI firmware") orelse false;
|
||||
const debug = b.option(bool, "debug", "Boot in debug mode") orelse false;
|
||||
const extra_qemu_args = b.option([]const []const u8, "qemu-args", "Extra arguments to pass to QEMU") orelse &.{};
|
||||
|
||||
if (plat.os == .freestanding) {
|
||||
const limine = b.dependency("limine", .{});
|
||||
const ovmf = b.dependency("ovmf", .{});
|
||||
const iso_out = image.addIso(b, plat.arch, "myos", kernel, limine);
|
||||
|
||||
const qemu_bin = switch (plat.arch) {
|
||||
.x86_64 => "qemu-system-x86_64",
|
||||
.aarch64 => "qemu-system-aarch64",
|
||||
.riscv64 => "qemu-system-riscv64",
|
||||
else => "qemu-system-x86_64",
|
||||
};
|
||||
const ovmf_fd = switch (plat.arch) {
|
||||
.x86_64 => "ovmf-code-x86_64.fd",
|
||||
.aarch64 => "ovmf-code-aarch64.fd",
|
||||
.riscv64 => "ovmf-code-riscv64.fd",
|
||||
else => "ovmf-code-x86_64.fd",
|
||||
};
|
||||
|
||||
const qemu = b.addSystemCommand(&.{qemu_bin});
|
||||
|
||||
if (plat.arch != .x86_64 or uefi) {
|
||||
qemu.addArg("-drive");
|
||||
qemu.addPrefixedFileArg("if=pflash,format=raw,readonly=on,file=", ovmf.path(ovmf_fd));
|
||||
}
|
||||
|
||||
qemu.addArgs(extra_qemu_args);
|
||||
qemu.addArg("-cdrom");
|
||||
qemu.addFileArg(iso_out.path);
|
||||
|
||||
if (debug) {
|
||||
qemu.addArgs(&.{
|
||||
"-serial", "stdio",
|
||||
"-d", "int",
|
||||
"-D", "qemu.log",
|
||||
"-no-reboot", "-no-shutdown",
|
||||
});
|
||||
}
|
||||
|
||||
switch (plat.arch) {
|
||||
.x86_64 => {
|
||||
qemu.addArgs(&.{ "-debugcon", "stdio" });
|
||||
|
||||
if (!debug) qemu.addArgs(&.{ "-enable-kvm", "-cpu", "host" });
|
||||
},
|
||||
.aarch64 => qemu.addArgs(&.{ "-machine", "virt", "-cpu", "cortex-a57" }),
|
||||
.riscv64 => qemu.addArgs(&.{ "-machine", "virt" }),
|
||||
else => {},
|
||||
}
|
||||
|
||||
run_step.dependOn(&qemu.step);
|
||||
} else {
|
||||
run_step.dependOn(&b.addRunArtifact(kernel).step);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user