-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.zig
190 lines (166 loc) · 7 KB
/
build.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
const std = @import("std");
const builtin = @import("builtin");
const Arch = std.Target.Cpu.Arch;
const CrossTarget = std.zig.CrossTarget;
const kora_version = std.SemanticVersion{
.major = 0,
.minor = 1,
.patch = 0,
};
pub fn build(b: *std.Build) !void {
const arch = b.option(Arch, "arch", "The CPU architecture to build for") orelse .x86_64;
const target = try genTarget(arch);
const optimize = b.standardOptimizeOption(.{});
const exe_options = b.addOptions();
// From zls
const version = v: {
const version_string = b.fmt("{d}.{d}.{d}", .{ kora_version.major, kora_version.minor, kora_version.patch });
var code: u8 = undefined;
const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
"git", "-C", b.build_root.path.?, "describe", "--match", "*.*.*", "--tags",
}, &code, .Ignore) catch break :v version_string;
const git_describe = std.mem.trim(u8, git_describe_untrimmed, " \n\r");
switch (std.mem.count(u8, git_describe, "-")) {
0 => {
// Tagged release version (e.g. 0.10.0).
std.debug.assert(std.mem.eql(u8, git_describe, version_string)); // tagged release must match version string
break :v version_string;
},
2 => {
// Untagged development build (e.g. 0.10.0-dev.216+34ce200).
var it = std.mem.split(u8, git_describe, "-");
const tagged_ancestor = it.first();
const commit_height = it.next().?;
const commit_id = it.next().?;
const ancestor_ver = std.SemanticVersion.parse(tagged_ancestor) catch unreachable;
std.debug.assert(kora_version.order(ancestor_ver) == .gt); // version must be greater than its previous version
std.debug.assert(std.mem.startsWith(u8, commit_id, "g")); // commit hash is prefixed with a 'g'
break :v b.fmt("{s}-dev.{s}+{s}", .{ version_string, commit_height, commit_id[1..] });
},
else => {
std.debug.print("Unexpected 'git describe' output: '{s}'\n", .{git_describe});
std.process.exit(1);
},
}
};
exe_options.addOption([:0]const u8, "version", b.allocator.dupeZ(u8, version) catch "0.1.0-dev");
const exe = b.addExecutable(.{
.name = "headstart",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = optimize,
});
exe.addCSourceFiles(&[_][]const u8{
"external/flanterm/flanterm.c",
"external/flanterm/backends/fb.c",
}, &[_][]const u8{
"-ffreestanding",
"-nostdlib",
"-mno-red-zone",
});
exe.addIncludePath(.{ .path = "external" });
exe.addOptions("build_options", exe_options);
exe.code_model = switch (target.cpu_arch.?) {
.x86_64 => .kernel,
.aarch64 => .small,
.riscv64 => .medium,
else => return error.UnsupportedArchitecture,
};
const limine = b.dependency("limine", .{});
exe.addModule("limine", limine.module("limine"));
b.installArtifact(exe);
try run(b, arch);
}
fn genTarget(arch: Arch) !CrossTarget {
var target = CrossTarget{
.cpu_arch = arch,
.os_tag = .uefi,
.abi = .msvc,
};
switch (arch) {
.x86_64, .aarch64, .riscv64 => {},
else => return error.UnsupportedArchitecture,
}
return target;
}
fn downloadEdk2(b: *std.Build, arch: Arch) !void {
const link = switch (arch) {
.x86_64 => "https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF.fd",
.aarch64 => "https://retrage.github.io/edk2-nightly/bin/RELEASEAARCH64_QEMU_EFI.fd",
.riscv64 => "https://retrage.github.io/edk2-nightly/bin/RELEASERISCV64_VIRT.fd",
else => return error.UnsupportedArchitecture,
};
const cmd = &[_][]const u8{ "curl", link, "-Lo", try edk2FileName(b, arch) };
var child_proc = std.ChildProcess.init(cmd, b.allocator);
try child_proc.spawn();
const ret_val = try child_proc.wait();
try std.testing.expectEqual(ret_val, .{ .Exited = 0 });
}
fn edk2FileName(b: *std.Build, arch: Arch) ![]const u8 {
return std.mem.concat(b.allocator, u8, &[_][]const u8{ "zig-cache/edk2-", @tagName(arch), ".fd" });
}
fn run(b: *std.Build, arch: Arch) !void {
_ = std.fs.cwd().statFile(try edk2FileName(b, arch)) catch try downloadEdk2(b, arch);
const qemu_executable = switch (arch) {
.x86_64 => "qemu-system-x86_64",
.aarch64 => "qemu-system-aarch64",
.riscv64 => "qemu-system-riscv64",
else => return error.UnsupportedArchitecture,
};
const boot_efi_filename = switch (arch) {
.x86_64 => "BOOTX64.EFI",
.aarch64 => "BOOTAA64.EFI",
.riscv64 => "BOOTRISCV64.EFI",
else => return error.UnsupportedArchitecture,
};
const cmd = &[_][]const u8{
// zig fmt: off
"sh", "-c",
try std.mem.concat(b.allocator, u8, &[_][]const u8{
try std.mem.concat(b.allocator, u8, &[_][]const u8{
"mkdir -p zig-out/efi-root/EFI/BOOT && ",
"mkdir -p zig-out/efi-root/boot && ",
"cp zig-out/bin/headstart.efi zig-out/efi-root/EFI/BOOT/", boot_efi_filename, " && ",
"clang -target x86_64-unknown-elf -nostdlib -ffreestanding -fno-stack-protector -fno-stack-check -fno-lto -fpie -mno-red-zone -c example/main.c -o zig-cache/kernel.o && ",
"ld.lld -Texample/linker.ld -static -nostdlib -pie -z text -z max-page-size=0x1000 zig-cache/kernel.o -o zig-out/efi-root/boot/example.elf && ",
"cp headstart.example.json zig-out/efi-root/headstart.json && ",
}),
try std.mem.concat(b.allocator, u8, switch (arch) {
.x86_64 => &[_][]const u8{
// zig fmt: off
qemu_executable, " ",
//"-cpu max ",
"-smp 2 ",
"-M q35,accel=kvm:whpx:hvf:tcg ",
"-m 2G ",
"-hda fat:rw:zig-out/efi-root ",
"-bios ", try edk2FileName(b, arch), " ",
"-no-reboot ",
"-no-shutdown ",
"-d guest_errors ",
// zig fmt: on
},
.aarch64, .riscv64 => &[_][]const u8{
// zig fmt: off
qemu_executable, " ",
"-cpu cortex-a57 ",
"-smp 2 ",
"-M virt,accel=kvm:whpx:hvf:tcg ",
"-device virtio-gpu-pci ",
"-m 2G ",
"-hda fat:rw:zig-out/efi-root ",
"-bios ", try edk2FileName(b, arch), " ",
"-no-reboot ",
"-no-shutdown ",
// zig fmt: on
},
else => return error.UnsupportedArchitecture,
}),
}),
// zig fmt: on
};
const run_cmd = b.addSystemCommand(cmd);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Boot Headstart in QEMU");
run_step.dependOn(&run_cmd.step);
}