diff --git a/boot/uefi/main.c b/boot/uefi/main.c index acc5804..dea1987 100644 --- a/boot/uefi/main.c +++ b/boot/uefi/main.c @@ -147,6 +147,45 @@ die(const CHAR16 *msg, EFI_STATUS st) print(L"schos: "); print(msg); print(L" (status "); print_hex(st); print(L")\r\n"); print(L"schos: halted.\r\n"); + + /* Say it on the screen too, if there is one. + * + * Once the splash is up, print() goes to the serial port and nowhere else. + * That is right for a development machine and useless on a laptop, which + * has no serial port -- a loader that failed after drawing the splash left + * a black screen and the firmware's own cursor, with the explanation going + * to a wire nobody was holding. A dead machine that says why is worth the + * dozen lines. */ + if (ui_active()) { + char line[96]; + int i = 0; + for (const char *q = "Cannot start SchOS: "; *q && i < (int)sizeof line - 1; q++) + line[i++] = *q; + for (int j = 0; msg[j] && i < (int)sizeof line - 1; j++) + line[i++] = (msg[j] >= 0x20 && msg[j] < 0x7F) ? (char)msg[j] : '?'; + line[i] = 0; + + char code[32]; + i = 0; + for (const char *q = "EFI status 0x"; *q && i < (int)sizeof code - 1; q++) + code[i++] = *q; + /* Low nibbles are enough to identify the error and keep this short; + * EFI_NOT_FOUND is 0x0E with the high bit set. */ + const char *hex = "0123456789ABCDEF"; + for (int sh = 12; sh >= 0; sh -= 4) + if (i < (int)sizeof code - 1) + code[i++] = hex[(st >> sh) & 0xF]; + code[i] = 0; + + /* Clear a band first. Without it the message lands on top of the + * logo, which is exactly the moment legibility matters most. */ + int mid = (int)ui_height() / 2; + ui_fill_rect(0, mid - 20, (int)ui_width(), 100, 0x0C0E13u); + ui_text_centered(mid, line, 0xE8EAEEu); + ui_text_centered(mid + 24, code, 0xB9BEC7u); + ui_text_centered(mid + 56, "Halted -- power off or reset", 0x8A9099u); + } + for (;;) __asm__ volatile("hlt"); } diff --git a/tools/posix/mkiso.sh b/tools/posix/mkiso.sh index a1663a6..613c852 100644 --- a/tools/posix/mkiso.sh +++ b/tools/posix/mkiso.sh @@ -89,9 +89,22 @@ if ! command -v mformat >/dev/null 2>&1 || ! command -v mcopy >/dev/null 2>&1; t fi rm -rf "$STAGING" -mkdir -p "$STAGING/boot" "$STAGING/EFI/BOOT" +mkdir -p "$STAGING/boot" "$STAGING/EFI/BOOT" "$STAGING/schos" cp "$EFIAPP" "$STAGING/EFI/BOOT/BOOTX64.EFI" +# The kernel in the ISO 9660 tree as well as inside the FAT image. +# +# Not redundancy for its own sake: it depends on who loaded us. Booting the +# disc directly, firmware runs the El Torito FAT image and the loader opens +# \schos\kernel on that volume. But a chainloader -- Ventoy is the common one +# -- ignores El Torito entirely, mounts the ISO 9660 tree and runs +# \EFI\BOOT\BOOTX64.EFI from *there*. The loader then looks for the kernel on +# the volume it was itself loaded from, which is now the ISO tree, and a disc +# with the kernel only in the FAT image cannot answer. +# +# The symptom is precise and was reported from a real machine: the loader comes +# up, draws its menu, and then dies with EFI_NOT_FOUND. +cp "$KERNEL" "$STAGING/schos/kernel" # The FAT image for the UEFI El Torito entry. #