iso: boot both firmwares, from a disc with a real hierarchy
The disc carried one file -- boot/schos.bin -- with 8.3 uppercase names, one El Torito entry, and no way to boot a UEFI machine. Now: /boot/schos.bin BIOS entry, unchanged: no-emulation, 1+STAGE2_SECTORS /boot/efiboot.img UEFI entry: a FAT image built with mtools /EFI/BOOT/BOOTX64.EFI the loader, also visible as a file /bin /etc /usr ... the staged sysroot as an ordinary tree Rock Ridge and Joliet restore real names, permissions and symlinks; -cache-inodes matters more than it looks, because the sysroot is a toybox multicall binary with a couple of hundred hard links to it and without inode caching each link becomes its own copy. -isohybrid-gpt-basdat adds a GPT so the .iso can be dd'd to a stick and booted by UEFI. That is UEFI only and deliberately so: the BIOS isohybrid trick needs syslinux's isohdpfx.bin, and even with it this loader reads the kernel back over ATAPI, which a stick presented as a hard disk cannot serve. usbstick.img is what that is for. The FAT image carries the kernel as well as the loader, because BOOTX64.EFI opens \schos\kernel on the volume it was loaded from, and for a UEFI boot that is the FAT image rather than the ISO 9660 tree. Without it the loader halted with EFI_NOT_FOUND. Also fixes `make iso` and `make ramroot`, which were already broken: fs-ram.img was still built by the v1 mkfs while the kernel accepts only SchFS as root, so the ramdisk was a format it could not mount and it panicked with "schfs root: no SchFS volume on the root device". It is a mkschfs image now, which needed --exclude in mkschfs -- dropping the exclude list was not an option, because the ramdisk is linked into the kernel binary and what goes in it is a licensing question. RAMDISK_NINODES is gone with the v1 image: SchFS has no preallocated inode table. Verified: BIOS ISO boots to a shell and runs commands over serial (241 files in /bin, /etc/motd reads back). UEFI ISO boots to a prompt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
e4df779048
commit
61b35a1f71
3 changed files with 188 additions and 14 deletions
|
|
@ -464,6 +464,34 @@ nl_cmp(const void *a, const void *b)
|
|||
|
||||
static void add_tree(uint64_t dirino, const char *hostdir);
|
||||
|
||||
// Paths kept out of the image, sysroot-relative.
|
||||
//
|
||||
// Same rule and same spelling as mkfs.c, because the two tools build the same
|
||||
// tree and a path excluded from one must be excluded from the other. This is a
|
||||
// licensing mechanism before it is a size one: the ramdisk image is linked into
|
||||
// the kernel binary, so anything staged in sysroot/ when it is built becomes
|
||||
// part of a distributable artifact.
|
||||
#define MAXEXCLUDE 32
|
||||
static const char *excludes[MAXEXCLUDE];
|
||||
static int nexcludes;
|
||||
// strlen(sysroot) + 1, so a host path can be turned back into the
|
||||
// sysroot-relative one the exclude patterns are written against.
|
||||
static size_t sysroot_prefix;
|
||||
|
||||
// Matches exactly, or as a directory prefix so that "usr/share/misc" also drops
|
||||
// "usr/share/misc/big.dat".
|
||||
static int
|
||||
is_excluded(const char *relpath)
|
||||
{
|
||||
for (int i = 0; i < nexcludes; i++) {
|
||||
size_t n = strlen(excludes[i]);
|
||||
if (strncmp(relpath, excludes[i], n) == 0 &&
|
||||
(relpath[n] == '\0' || relpath[n] == '/'))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns 1 if the entry was a directory, so the caller can total up the link
|
||||
// count without walking the directory a second time.
|
||||
static int
|
||||
|
|
@ -472,6 +500,15 @@ add_entry(uint64_t dirino, const char *hostdir, const char *name)
|
|||
char path[8192];
|
||||
snprintf(path, sizeof(path), "%s/%s", hostdir, name);
|
||||
|
||||
// Checked before the entry is dispatched, so an excluded directory is never
|
||||
// opened and never gets an inode -- an empty directory left behind would
|
||||
// still describe what was removed.
|
||||
if (nexcludes && strlen(path) > sysroot_prefix &&
|
||||
is_excluded(path + sysroot_prefix)) {
|
||||
fprintf(stderr, "mkschfs: excluding %s\n", path + sysroot_prefix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
// lstat, not stat: a symlink must be stored as a symlink rather than
|
||||
// silently turned into a second copy of whatever it points at.
|
||||
|
|
@ -562,6 +599,14 @@ main(int argc, char **argv)
|
|||
nblocks = strtoull(argv[++i], NULL, 0);
|
||||
else if (strcmp(argv[i], "--label") == 0 && i + 1 < argc)
|
||||
label = argv[++i];
|
||||
else if (strcmp(argv[i], "--exclude") == 0 && i + 1 < argc) {
|
||||
if (nexcludes >= MAXEXCLUDE) {
|
||||
fprintf(stderr, "mkschfs: too many --exclude paths (max %d)\n",
|
||||
MAXEXCLUDE);
|
||||
return 1;
|
||||
}
|
||||
excludes[nexcludes++] = argv[++i];
|
||||
}
|
||||
else if (strcmp(argv[i], "--hash-bits") == 0 && i + 1 < argc) {
|
||||
// Testing only: shrink the name hash so collisions are the norm
|
||||
// rather than a once-in-a-lifetime event. schfs_fsck takes the
|
||||
|
|
@ -583,7 +628,9 @@ main(int argc, char **argv)
|
|||
if (!out || !sysroot) {
|
||||
fprintf(stderr,
|
||||
"usage: mkschfs out.img --sysroot DIR [--size BLOCKS] [--label NAME]\n"
|
||||
" BLOCKS are %d-byte SchFS blocks (default 6000 = %d MB)\n",
|
||||
" [--exclude PATH]...\n"
|
||||
" BLOCKS are %d-byte SchFS blocks (default 6000 = %d MB)\n"
|
||||
" --exclude omits a sysroot-relative path and its subtree\n",
|
||||
SCHFS_BLKSIZE, (int)(6000 * SCHFS_BLKSIZE / (1024 * 1024)));
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -630,6 +677,10 @@ main(int argc, char **argv)
|
|||
if (r != 0) die("writing the root inode", r);
|
||||
ndirs++;
|
||||
|
||||
// add_entry() builds host paths as "<sysroot>/<name>", so this is where the
|
||||
// sysroot-relative part of such a path begins.
|
||||
sysroot_prefix = strlen(sysroot) + 1;
|
||||
|
||||
add_tree(VOL.root_objectid, sysroot);
|
||||
|
||||
// Publish. Everything above this line is invisible to a reader; if the tool
|
||||
|
|
|
|||
Loading…
Reference in a new issue