gfx: the console's typeface is replaceable, and the loader is what replaces it
Gate 0's last-but-one open item. Drop a TrueType file at \schos\console.ttf on
the ESP and the console is drawn with it; with no file, the face linked into
the kernel image, which is what an early panic needs and is not a degraded
mode.
**The loader reads it, and that is the decision worth writing down.** The
kernel opening the file once the root filesystem is mounted is the obvious
design. It is also wrong: the console has been drawing since the kernel's
first line, so a font arriving later changes the cell size, which changes the
column count, which re-lays out every terminal -- and blanks them. The kernel
log would vanish off the screen at the moment the root filesystem mounted,
which is exactly the log a machine being brought up for the first time is
being read for. Since the next thing on the list is real hardware, losing that
was not a trade worth making.
So the choice happens before anything is drawn. Three details make it cheap:
- **EfiReservedMemoryType**, not EfiLoaderData. The E820 handoff turns
loader data into usable memory, on the argument that the loader's own
pages are the kernel's the moment it runs -- true of the loader, not true
of a buffer it wants the kernel to keep reading from.
- **Below 4 GB**, because the kernel reaches this through its direct map and
that is how far the direct map goes. A font above it would need an ioremap
the console cannot do before there is a console.
- **Used in place.** No copy, which matters because the kernel has no
contiguous allocator to copy 112 KB into -- the only one is the DMA arena,
and that belongs to devices.
Sized without EFI_FILE_INFO and its GUID: seek past the end and ask where that
landed, which the specification requires to clamp.
Every failure falls back and keeps going -- no file, implausible size, no
memory, short read, unparseable file. The last says so in the log, because a
font that silently did not load looks exactly like a font that did.
Verified by booting with JetBrainsMono-ExtraBold.ttf on the ESP and
screendumping the console: visibly the bold face, against the Regular of a
boot with no file. Three boots each way, no traps and no panics, socktest and
memfdtest green in all six.
Nothing ships a console.ttf: the file would be the file already in the kernel,
and two copies of a font are two things that can disagree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
df304918f8
commit
d85274dbd9
5 changed files with 215 additions and 5 deletions
|
|
@ -23,6 +23,9 @@
|
|||
#include "gfx.h"
|
||||
#include "vt.h"
|
||||
#include "text.h"
|
||||
#include "schboot.h"
|
||||
#include "schboot.h"
|
||||
#include "memlayout.h"
|
||||
#include "ttf.h"
|
||||
|
||||
#define BACKSPACE 0x100
|
||||
|
|
@ -371,16 +374,50 @@ void
|
|||
gfx_font_init(void)
|
||||
{
|
||||
extern unsigned char _binary_consfont_start[], _binary_consfont_end[];
|
||||
const unsigned char *data = _binary_consfont_start;
|
||||
uint32 len = (uint32)(_binary_consfont_end - _binary_consfont_start);
|
||||
struct glyph gl;
|
||||
|
||||
if (cfont)
|
||||
return;
|
||||
|
||||
// A typeface off the boot volume, if the loader found one.
|
||||
//
|
||||
// Tried first and fallen back from silently: the built-in font is not a
|
||||
// degraded mode, it is the same font, and a machine with no console.ttf is
|
||||
// the ordinary case rather than a fault. What this buys is that the font is
|
||||
// *replaceable* -- drop a different TrueType file on the ESP and the console
|
||||
// is drawn with it, with no kernel to rebuild.
|
||||
//
|
||||
// In place, out of memory the loader marked reserved. See SCHBOOT_FONT_ADDR
|
||||
// for why the kernel does not read this file itself.
|
||||
{
|
||||
uint64 font_pa = *(volatile uint64 *)P2V(SCHBOOT_FONT_ADDR);
|
||||
uint32 font_len = *(volatile uint32 *)P2V(SCHBOOT_FONT_LEN);
|
||||
|
||||
if (font_pa && font_len >= 4096 && font_pa + font_len <= 0x100000000ULL) {
|
||||
data = (const unsigned char *)P2V(font_pa);
|
||||
len = font_len;
|
||||
}
|
||||
}
|
||||
|
||||
// 16 pixels per em. The bitmap it replaces is 16 tall, so the terminal keeps
|
||||
// the number of rows it had and nothing that assumed a screenful has to
|
||||
// change.
|
||||
if (ttf_open(&consttf, _binary_consfont_start, len, 16) != 0)
|
||||
return;
|
||||
if (ttf_open(&consttf, data, len, 16) != 0) {
|
||||
// A bad file on the ESP must not cost the console its font. Nothing has
|
||||
// been changed yet at this point, so the built-in one is still there to
|
||||
// fall back to -- and it is worth saying, because a font that silently
|
||||
// did not load looks exactly like a font that did.
|
||||
if (data == _binary_consfont_start)
|
||||
return;
|
||||
kinfo("console: the font on the boot volume would not parse; "
|
||||
"using the built-in one\n");
|
||||
data = _binary_consfont_start;
|
||||
len = (uint32)(_binary_consfont_end - _binary_consfont_start);
|
||||
if (ttf_open(&consttf, data, len, 16) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
struct font *f = ttf_font(&consttf);
|
||||
if (!f)
|
||||
|
|
|
|||
Loading…
Reference in a new issue