Add aarch64 target

This commit is contained in:
2025-03-17 19:56:43 +02:00
parent 1641327f28
commit aee04d2510
7 changed files with 287 additions and 30 deletions
+130 -30
View File
@@ -1,5 +1,86 @@
const std = @import("std");
const DEFAULT_ARCH = "riscv64";
const SupportedArch = enum {
aarch64,
riscv64,
fn fromStr(s: []const u8) ?SupportedArch {
return if (std.mem.eql(u8, s, "riscv64")) //
.riscv64
else if (std.mem.eql(u8, s, "aarch64")) //
.aarch64
else //
null;
}
fn makeTarget(self: SupportedArch, b: *std.Build) std.Build.ResolvedTarget {
return switch (self) {
.riscv64 => b.standardTargetOptions(.{ .default_target = .{
.cpu_arch = .riscv64,
.os_tag = .freestanding,
.abi = .none,
} }),
.aarch64 => b.standardTargetOptions(.{ .default_target = .{
.cpu_arch = .aarch64,
.os_tag = .freestanding,
.abi = .none,
} }),
};
}
fn addTargetSpecific(self: SupportedArch, b: *std.Build, kernel: *std.Build.Step.Compile) anyerror!*std.Build.Step {
switch (self) {
.riscv64 => {
kernel.entry = .{ .symbol_name = "__rv64_entry" };
kernel.setLinkerScript(b.path("etc/riscv64-unknown-none.ld"));
kernel.addCSourceFiles(.{
.files = &.{"src/arch/riscv64/entry.S"},
.flags = &.{},
});
},
.aarch64 => {
kernel.entry = .{ .symbol_name = "__aa64_entry" };
kernel.setLinkerScript(b.path("etc/aarch64-unknown-none.ld"));
kernel.addCSourceFiles(.{
.files = &.{"src/arch/aarch64/entry.S"},
.flags = &.{},
});
},
}
b.installArtifact(kernel);
if (self == .riscv64 or self == .aarch64) {
const fakeLinuxHeader: *std.Build.Step = try b.allocator.create(std.Build.Step);
fakeLinuxHeader.* = std.Build.Step.init(.{
.id = std.Build.Step.Id.custom,
.name = "insert fake linux header",
.owner = kernel.step.owner,
.makeFn = insertFakeLinuxImageHeader,
});
const elf2bin = b.addSystemCommand(&.{
"llvm-objcopy",
"-O",
"binary",
"zig-out/bin/kernel",
"zig-out/bin/kernel.bin",
});
fakeLinuxHeader.dependOn(b.getInstallStep());
elf2bin.step.dependOn(fakeLinuxHeader);
return &elf2bin.step;
} else {
@panic("Unreachable + don't care");
}
}
};
fn insertFakeLinuxImageHeader(step: *std.Build.Step, opts: std.Build.Step.MakeOptions) anyerror!void {
const RISCV_MAGIC1 = "RISCV\x00\x00\x00";
const RISCV_MAGIC2 = "RSC\x05";
@@ -46,53 +127,72 @@ fn insertFakeLinuxImageHeader(step: *std.Build.Step, opts: std.Build.Step.MakeOp
_ = opts;
}
fn build_riscv64(b: *std.Build) anyerror!void {
_ = b;
}
pub fn build(b: *std.Build) anyerror!void {
const maybeArchOption = b.option([]const u8, "arch", "Architecture to use");
const archOption = maybeArchOption orelse DEFAULT_ARCH;
const sTarget = SupportedArch.fromStr(archOption) orelse {
std.debug.print("Unsupported target arch: '{s}'", .{archOption});
return error.InvalidArgument;
};
const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseFast });
const target = b.standardTargetOptions(.{ .default_target = .{
.cpu_arch = .riscv64,
.os_tag = .freestanding,
.abi = .none,
} });
const target = sTarget.makeTarget(b);
const kernel_module = b.addModule("kernel", .{ .optimize = optimize, .target = target, .pic = true, .red_zone = false, .code_model = .medium, .root_source_file = b.path("src/kernel.zig") });
const kernel = b.addExecutable(.{ .name = "kernel", .root_module = kernel_module, .pic = true });
const codeModel: std.builtin.CodeModel = switch (sTarget) {
.riscv64 => .medium,
.aarch64 => .small,
};
const kernelModule = b.addModule("kernel", .{
.optimize = optimize,
.target = target,
.pic = true,
.red_zone = false,
.code_model = codeModel,
.root_source_file = b.path("src/kernel.zig"),
});
const kernel = b.addExecutable(.{
.name = "kernel",
.root_module = kernelModule,
.pic = true,
});
kernel.pie = true;
kernel.entry = .{ .symbol_name = "__rv64_entry" };
kernel.setLinkerScript(b.path("etc/riscv64-unknown-none.ld"));
kernel.addCSourceFiles(.{
.files = &.{"src/arch/riscv64/entry.S"},
.flags = &.{},
});
b.installArtifact(kernel);
const fakeLinuxHeader: *std.Build.Step = try b.allocator.create(std.Build.Step);
fakeLinuxHeader.* = std.Build.Step.init(.{
.id = std.Build.Step.Id.custom,
.name = "insert fake linux header",
.owner = kernel.step.owner,
.makeFn = insertFakeLinuxImageHeader,
});
const elf2bin = b.addSystemCommand(&.{ "llvm-objcopy", "-O", "binary", "zig-out/bin/kernel", "zig-out/bin/kernel.bin" });
const kernelStep = try sTarget.addTargetSpecific(b, kernel);
// TODO QEMU binary override
const qemu_info = switch (target.result.cpu.arch) {
.riscv64 => .{ "qemu-system-riscv64", "rv64" },
.aarch64 => .{ "qemu-system-aarch64", "cortex-a72" },
else => unreachable,
};
const qemu_cmd = b.addSystemCommand(&.{ qemu_info[0], "-M", "virt", "-kernel", "zig-out/bin/kernel.bin", "-m", "256M", "-cpu", qemu_info[1], "-serial", "mon:stdio", "-display", "none" });
const qemu_cmd = b.addSystemCommand(&.{
qemu_info[0],
"-M",
"virt",
"-kernel",
"zig-out/bin/kernel.bin",
"-m",
"256M",
"-cpu",
qemu_info[1],
"-serial",
"mon:stdio",
"-display",
"none",
});
if (target.result.cpu.arch == .riscv64) {
qemu_cmd.addArgs(&.{ "-bios", "etc/boot/rv64_fw_jump.bin" });
}
fakeLinuxHeader.dependOn(b.getInstallStep());
elf2bin.step.dependOn(fakeLinuxHeader);
qemu_cmd.step.dependOn(&elf2bin.step);
qemu_cmd.step.dependOn(kernelStep);
if (b.args) |args| qemu_cmd.addArgs(args);
const run_step = b.step("run", "Start the OS in qemu");
run_step.dependOn(&qemu_cmd.step);