bug pass: whole console lines, a quiet SCI, an honest reserve warning
- schinit, schinitd and vgpud build every message from pieces, one
write() each, so a job starting on another CPU landed mid-line:
"schinitd: starting vgpud: os.schos.resolvconfno virtio-gpu on this
machine". They now collect a line and write it at the newline;
resolvconf's verbose line is one write with its prefix.
- The ACPI SCI registers IRQ_QUIET. A desktop's SCI never fires, and the
poller took two seconds of silence for a misrouted line ("irq 9:
nothing has arrived on it") and called the handler every tick. A line
is only exempt while every handler on it is quiet.
- The loader claims each segment from where the last one's claim ended,
so two segments sharing a page no longer ask for it twice. When a
claim is still refused, it names the memory-map entries in the way.
- Stale divesymlink() declaration gone; the kernel.md struct table
re-measured (inode, buf and file pools grow from slabs now).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
7af579a20d
commit
e659c6b187
10 changed files with 184 additions and 25 deletions
|
|
@ -90,6 +90,7 @@ static EFI_BOOT_SERVICES *BS;
|
|||
static void mirrors_show(void); /* see "the other displays", further down */
|
||||
static void mirrors_match(EFI_GRAPHICS_OUTPUT_PROTOCOL *primary);
|
||||
static void describe_gop(EFI_GRAPHICS_OUTPUT_PROTOCOL *g, const CHAR16 *tag);
|
||||
static void explain_range(UINT64 lo, UINT64 hi);
|
||||
|
||||
/* Once the splash is up, nothing may write to the console.
|
||||
*
|
||||
|
|
@ -522,6 +523,8 @@ load_elf(EFI_FILE_PROTOCOL *file)
|
|||
}
|
||||
ui_progress_begin("Loading SchOS", (ui_u32)(total ? total : 1));
|
||||
|
||||
EFI_PHYSICAL_ADDRESS claimed_end = 0; /* see the AllocatePages below */
|
||||
|
||||
for (UINT16 i = 0; i < eh.e_phnum; i++) {
|
||||
struct elf64_phdr ph;
|
||||
n = sizeof ph;
|
||||
|
|
@ -537,9 +540,23 @@ load_elf(EFI_FILE_PROTOCOL *file)
|
|||
// and this is its memory until it says otherwise; writing to
|
||||
// conventional memory it has not handed over is how a loader corrupts
|
||||
// the very services it is about to call.
|
||||
EFI_PHYSICAL_ADDRESS at = ph.p_paddr & ~0xfffULL;
|
||||
UINTN pages = (UINTN)((ph.p_paddr + ph.p_memsz - at + 0xfff) / 0x1000);
|
||||
st = BS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &at);
|
||||
//
|
||||
// From the end of what the previous segment claimed, not from this
|
||||
// one's first page. The linker packs segments without page-aligning
|
||||
// them -- .text ending at 0x1dc9fe and .rodata starting at 0x1dca00 --
|
||||
// so two segments routinely share a page, and asking for that page a
|
||||
// second time is refused because it is ours already. That was the
|
||||
// "could not reserve" warning on every boot, about memory that was
|
||||
// reserved all along.
|
||||
EFI_PHYSICAL_ADDRESS at = ph.p_paddr & ~0xfffULL;
|
||||
EFI_PHYSICAL_ADDRESS end = (ph.p_paddr + ph.p_memsz + 0xfff) & ~0xfffULL;
|
||||
if (at < claimed_end)
|
||||
at = claimed_end;
|
||||
UINTN pages = at < end ? (UINTN)((end - at) / 0x1000) : 0;
|
||||
st = pages ? BS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &at)
|
||||
: EFI_SUCCESS;
|
||||
if (end > claimed_end)
|
||||
claimed_end = end;
|
||||
if (EFI_ERROR(st)) {
|
||||
// Already allocated by the firmware for something of its own, or
|
||||
// simply not conventional memory. Not fatal on its own -- the
|
||||
|
|
@ -547,6 +564,7 @@ load_elf(EFI_FILE_PROTOCOL *file)
|
|||
// that boots and then corrupts itself starts here.
|
||||
print(L"schos: warning: could not reserve "); print_hex(at);
|
||||
print(L"\r\n");
|
||||
explain_range(at, end);
|
||||
}
|
||||
|
||||
if (ph.p_filesz) {
|
||||
|
|
@ -1044,6 +1062,32 @@ map_read(UINTN *size, UINTN *key, UINTN *dsize, UINT32 *dver)
|
|||
key, dsize, dver);
|
||||
}
|
||||
|
||||
/* Who owns [lo, hi), when it was not ours to take.
|
||||
*
|
||||
* "could not reserve" alone says where and not why, and the why decides
|
||||
* whether it matters: boot-services memory is the firmware's until
|
||||
* ExitBootServices and harmless to overwrite after it, while runtime services
|
||||
* or ACPI tables under the kernel are a machine that will corrupt itself. So
|
||||
* every descriptor in the range that is not free memory is named. */
|
||||
static void
|
||||
explain_range(UINT64 lo, UINT64 hi)
|
||||
{
|
||||
UINTN size, key, dsize;
|
||||
UINT32 dver;
|
||||
|
||||
if (EFI_ERROR(map_read(&size, &key, &dsize, &dver)) || !dsize)
|
||||
return;
|
||||
for (UINTN off = 0; off + dsize <= size; off += dsize) {
|
||||
EFI_MEMORY_DESCRIPTOR *d = (EFI_MEMORY_DESCRIPTOR *)(mapbuf + off);
|
||||
UINT64 a = d->PhysicalStart, b = a + d->NumberOfPages * 4096;
|
||||
if (b <= lo || a >= hi || d->Type == EfiConventionalMemory)
|
||||
continue;
|
||||
print(L"schos: type "); print_dec(d->Type);
|
||||
print(L" at "); print_hex(a); print(L".."); print_hex(b);
|
||||
print(L"\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
static UINT64
|
||||
memory_mb(void)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue