-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathbuild-usb.php
More file actions
131 lines (104 loc) · 4.54 KB
/
build-usb.php
File metadata and controls
131 lines (104 loc) · 4.54 KB
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
<?php
declare(strict_types=1);
echo ">> Building USB image...\n";
define('BUILD_DIR', getcwd());
const ISO_DIR = BUILD_DIR . '/iso';
const RR_ISO = BUILD_DIR . '/rr.iso';
const KERNEL_BIN = ISO_DIR . '/kernel.bin';
const KERNEL_SYM = ISO_DIR . '/kernel.sym';
const LIMINE_DIR = BUILD_DIR . '/../limine';
const LIMINE_BIN = LIMINE_DIR . '/limine';
const LIMINE_CONF = BUILD_DIR . '/../limine-usb.conf';
const OUT_IMG = BUILD_DIR . '/usb.img';
const VOL_LABEL = 'RETROROCKET';
const HEADROOM_MB = 64;
if (!is_file(LIMINE_BIN) || !is_executable(LIMINE_BIN)) {
chdir(LIMINE_DIR);
run('env -u MAKEFLAGS -u MFLAGS -u MAKELEVEL make -j1 CC="/usr/bin/gcc -B/usr/bin/" >/dev/null');
chdir(BUILD_DIR);
if (!is_file(LIMINE_BIN) || !is_executable(LIMINE_BIN)) {
throw new RuntimeException("limine build failed: missing or non-executable '" . LIMINE_BIN . "'");
}
}
function run(string $cmd, array $env = []): void {
$proc = proc_open($cmd, [1=>['pipe','w'], 2=>['pipe','w']], $pipes, null, $env + $_ENV);
if (!is_resource($proc)) {
throw new RuntimeException("failed to start: $cmd");
}
$out = stream_get_contents($pipes[1]); fclose($pipes[1]);
$err = stream_get_contents($pipes[2]); fclose($pipes[2]);
$rc = proc_close($proc);
if ($rc !== 0) {
throw new RuntimeException("Command failed ($rc): $cmd\n$err$out");
}
}
function ensure_file(string $path): void {
if (!is_file($path)) {
throw new RuntimeException("Missing file: $path");
}
}
function align_up(int $x, int $a): int {
return ($x + ($a - 1)) & ~($a - 1);
}
ensure_file(RR_ISO);
ensure_file(KERNEL_BIN);
ensure_file(KERNEL_SYM);
ensure_file(LIMINE_DIR . '/BOOTX64.EFI');
ensure_file(LIMINE_DIR . '/limine-bios.sys');
ensure_file(LIMINE_BIN);
ensure_file(LIMINE_CONF);
echo ">> Compressing root.iso.gz\n";
$root_gz = BUILD_DIR . '/root.iso.gz';
run(sprintf("gzip -9 -n -c %s > %s", escapeshellarg(RR_ISO), escapeshellarg($root_gz)));
$bytes_kernel = filesize(KERNEL_BIN);
$bytes_sym = filesize(KERNEL_SYM);
$bytes_cfg = filesize(LIMINE_CONF);
$bytes_rootgz = filesize($root_gz);
$bytes_overhead = (2 * 1024 * 1024) + (HEADROOM_MB * 1024 * 1024);
$partition_payload_bytes = $bytes_kernel + $bytes_sym + $bytes_cfg + $bytes_rootgz + $bytes_overhead;
$partition_size = align_up($partition_payload_bytes, 4 * 1024 * 1024);
$img_bytes = (1024 * 1024) + $partition_size;
$sector_size = 512;
$start_lba = 2048;
$offset_bytes = $start_lba * $sector_size;
if (is_file(OUT_IMG)) {
unlink(OUT_IMG);
}
echo ">> Truncating " . OUT_IMG . "\n";
run(sprintf("truncate -s %d %s", $img_bytes, escapeshellarg(OUT_IMG)));
echo ">> Partitioning " . OUT_IMG . "\n";
run(sprintf("sgdisk -o -a 1 -n 1:34:2047 -t 1:ef02 -n 2:%d:0 -t 2:ef00 %s", $start_lba, escapeshellarg(OUT_IMG)));
run(sprintf("sgdisk --hybrid 2:EE %s", escapeshellarg(OUT_IMG)));
run(sprintf("printf 'a\n1\nw\n' | fdisk %s", escapeshellarg(OUT_IMG)));
$env = ['MTOOLS_SKIP_CHECK' => '1'];
echo ">> Formatting " . OUT_IMG . "\n";
run(sprintf("mformat -i %s@@%d -F -v %s ::", escapeshellarg(OUT_IMG), $offset_bytes, escapeshellarg(VOL_LABEL)), $env);
echo ">> Copying files to " . OUT_IMG . "\n";
$img_spec = escapeshellarg(OUT_IMG . '@@' . (string)$offset_bytes);
run("mmd -i $img_spec ::/EFI", $env);
run("mmd -i $img_spec ::/EFI/BOOT", $env);
run(sprintf("mcopy -i %s %s ::/EFI/BOOT/BOOTX64.EFI", $img_spec, escapeshellarg(LIMINE_DIR . '/BOOTX64.EFI')), $env);
run(sprintf("mcopy -i %s %s ::/limine-bios.sys", $img_spec, escapeshellarg(LIMINE_DIR . '/limine-bios.sys')), $env);
run(sprintf("mcopy -i %s %s ::/kernel.bin", $img_spec, escapeshellarg(KERNEL_BIN)), $env);
run(sprintf("mcopy -i %s %s ::/kernel.sym", $img_spec, escapeshellarg(KERNEL_SYM)), $env);
run(sprintf("mcopy -i %s %s ::/root.iso.gz", $img_spec, escapeshellarg($root_gz)), $env);
run(sprintf("mcopy -i %s %s ::/limine.conf", $img_spec, escapeshellarg(LIMINE_CONF)), $env);
echo ">> Installing bootloader to " . OUT_IMG . "\n";
// Install BIOS bootloader
run(sprintf("%s bios-install %s 1", escapeshellarg(LIMINE_BIN), escapeshellarg(OUT_IMG)));
echo ">> Fixup\n";
$fp = fopen(OUT_IMG, 'r+b');
if ($fp === false) {
throw new RuntimeException("failed to open image for MBR boot flag update");
}
if (fseek($fp, 446) !== 0) {
fclose($fp);
throw new RuntimeException("failed to seek to MBR partition entry");
}
if (fwrite($fp, "\x80") !== 1) {
fclose($fp);
throw new RuntimeException("failed to write MBR boot flag");
}
fclose($fp);
$mb = (int) round($img_bytes / (1024 * 1024));
echo ">> USB image created: " . OUT_IMG . " (" . $mb . " MB)\n";