boot: one UI for both firmwares, and a metal look
The BIOS loader drew its own splash and the UEFI loader drew a different
one, which is how two implementations of a single screen end up looking
nothing alike: only one of them ever got a change. stage2main.c's
fourteen drawing functions are deleted and it calls boot/common/ui.c,
which is what the UEFI loader already used. There is one splash now.
What changed in the look, in order of how much it mattered:
- No product name under the mark. The name is *in* the mark, and
setting it again underneath read as a placeholder nobody removed.
- The mark is scaled to the bar's width and sits directly above it, so
the two are one object rather than a large logo with an unrelated
line beneath. Box-filtered down from the source mask, never up:
point-sampling a coverage mask drops half the edge pixels and puts
holes in the thin strokes.
- Metal rather than flat grey. A vertical gradient with a knee near the
top where a highlight falls, applied to the mark, the bar fill and
panel headings. A single colour on a dark ground looks printed; the
knee is what makes it look lit. No texture -- at this size noise
reads as dirt.
- The boot manager is a panel with a lit selected row, replacing a
screen laid out in literals with a magic y of 340 that only ever
looked right at 800x600.
Three defects found by reading pixels rather than code:
- the UEFI loader kept calling print() after the splash, and ConOut on
a graphical firmware renders into the same framebuffer -- a
screenshot showed firmware text across our mark from the left edge.
Diagnostics go to COM1 directly now, which is where they were being
read from anyway, and the console is cleared before drawing so the
firmware has nothing to put back.
- SPLASH_UP was declared and read but never assigned, so that redirect
was dead code and the "serial works" reading was OVMF's own console.
- stage2 overflowed its allocation -- 25440 bytes against 24576 -- and
the build did not stop. The kernel is written at sector
1 + STAGE2_SECTORS, so a stage2 past its allocation is overwritten by
the kernel it is loading. STAGE2_SECTORS is 64 now, and the padding
tool's check does fire; it had simply not been re-run.
Verified from the host on both: BIOS 800x600 and UEFI 1280x800 both draw
a centred group with zero stray pixels, UEFI's spanning x 576-703 which
is exactly the mark width centred. bootcheck 108 [ok], iso builds.
Still text-mode: the resolution menu. On BIOS it necessarily is -- it
runs in real mode before any framebuffer exists, which is the whole
reason it can set one. On UEFI it could be graphical and is not yet.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
64e4835524
commit
799abbc19a
5 changed files with 375 additions and 298 deletions
|
|
@ -79,9 +79,46 @@ static EFI_BOOT_SERVICES *BS;
|
|||
// Console. Enough to say what went wrong, and no more.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* Once the splash is up, nothing may write to the console.
|
||||
*
|
||||
* ConOut on a graphical firmware renders text into the same framebuffer the
|
||||
* splash is drawn in, so every diagnostic after that point is scribbled across
|
||||
* it -- which is exactly what a screenshot showed: our mark centred, and
|
||||
* firmware text over the top of it from the left edge.
|
||||
*
|
||||
* The diagnostics are worth keeping, so they go to COM1 directly instead. That
|
||||
* is legal before ExitBootServices, costs nothing, and is where they were being
|
||||
* read from anyway.
|
||||
*/
|
||||
static int SPLASH_UP;
|
||||
|
||||
static void
|
||||
serial_putc(char c)
|
||||
{
|
||||
/* Bounded, for the same reason the BIOS loader's is: a machine with no
|
||||
* serial port reads 0xFF from the status register forever. */
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
UINT8 st;
|
||||
/* Through DX, not an immediate: the immediate form of in/out only
|
||||
* encodes ports 0-255, and COM1's registers are at 0x3F8. */
|
||||
__asm__ volatile("inb %1, %0" : "=a"(st) : "d"((UINT16)0x3FD));
|
||||
if (st & 0x20)
|
||||
break;
|
||||
}
|
||||
__asm__ volatile("outb %0, %1" : : "a"((UINT8)c), "d"((UINT16)0x3F8));
|
||||
}
|
||||
|
||||
static void
|
||||
print(const CHAR16 *s)
|
||||
{
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
if (SPLASH_UP) {
|
||||
for (int i = 0; s[i]; i++)
|
||||
serial_putc((char)(s[i] & 0x7F));
|
||||
return;
|
||||
}
|
||||
if (ST && ST->ConOut)
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16 *)s);
|
||||
}
|
||||
|
|
@ -474,8 +511,19 @@ setup_framebuffer(void)
|
|||
uifb.width = info->HorizontalResolution;
|
||||
uifb.height = info->VerticalResolution;
|
||||
uifb.stride = stride;
|
||||
// Tell the firmware its console is empty before drawing over it. ConOut
|
||||
// keeps its own idea of what is on screen and repaints that region when it
|
||||
// feels like it -- a screenshot showed a black band across the top third,
|
||||
// which is its text area put back on top of the splash.
|
||||
if (ST && ST->ConOut)
|
||||
ST->ConOut->ClearScreen(ST->ConOut);
|
||||
|
||||
ui_init(&uifb);
|
||||
ui_splash("SchOS", "Starting up");
|
||||
ui_splash(0);
|
||||
|
||||
// From here on, diagnostics go to COM1 rather than the console, or each one
|
||||
// is drawn across the splash.
|
||||
SPLASH_UP = ui_active();
|
||||
|
||||
print(L"schos: framebuffer "); print_hex(fb);
|
||||
print(L" "); print_hex(info->HorizontalResolution);
|
||||
|
|
@ -563,8 +611,6 @@ EfiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
|||
ST = systab;
|
||||
BS = systab->BootServices;
|
||||
|
||||
if (ST->ConOut)
|
||||
ST->ConOut->ClearScreen(ST->ConOut);
|
||||
print(L"SchOS UEFI loader\r\n");
|
||||
|
||||
// The display comes first, before the kernel is read.
|
||||
|
|
|
|||
Loading…
Reference in a new issue