docs: architecture describes what is built now
kernel (threads, demand paging, TLB shootdowns, dynamic linking, RAM direct map), syscalls, filesystem (/proc, /sys, /dev), terminals (12, VT handshake, ptys), networking (r8169 through LDLS), LDLS (module sets; Linux code may ship), devices (what stays in the kernel; hybrid.md's lasting content), boot (the loader's placement of the kernel), graphics (fbdev, GMMOS, QR 1-40), audio (ALSA over OSS), debugging, usb. New: packages.md (the apk root) and desktop.md (Xorg on the framebuffer). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
This commit is contained in:
parent
655c7d8d01
commit
2556a955b3
15 changed files with 921 additions and 341 deletions
|
|
@ -131,6 +131,42 @@ when the early console is set up. So a low framebuffer is attached exactly as
|
|||
before, and a high one is attached a few dozen instructions later, immediately
|
||||
after `kvmalloc()` — still thousands of lines before anything else happens.
|
||||
|
||||
### Where the kernel goes, and how it gets there
|
||||
|
||||
The kernel is linked at physical **16 MB** (`KERNPHYS` in `memlayout.h`, repeated in
|
||||
`kernel.ld`, which must agree) and is about 34 MB with the ramdisk inside it. From the
|
||||
old 1 MB it ran across 8 MB, where OVMF keeps ACPI NVS memory that outlives the firmware,
|
||||
so it was overwritten on every boot, after `ExitBootServices`. Firmware leaves its
|
||||
leftovers low; above 16 MB is where a machine is most reliably empty. (The 15 MB below
|
||||
the kernel is not given to the page allocator yet.)
|
||||
|
||||
**Every free page of that range is claimed first.** A segment lying wholly on claimed
|
||||
pages is read straight home; one that is not is read into a buffer elsewhere and
|
||||
**copied home after `ExitBootServices`**, when boot-services memory is ours. An HP
|
||||
all-in-one from 2012 used to freeze at the start of the loading bar because the loader
|
||||
said "could not reserve" and read the kernel there anyway, over the firmware's own memory
|
||||
with the firmware still running on it. Memory under the kernel that outlives the firmware
|
||||
(ACPI NVS, runtime services) is named, and so is the loader or its stack sitting in the
|
||||
range. Segments are read a megabyte at a time, so the bar moves through the ramdisk and
|
||||
shows where a machine stopped.
|
||||
|
||||
The copy and the jump themselves run from **one page below the kernel's lowest address**,
|
||||
allocated as loader code before the firmware exits: a short position-independent routine,
|
||||
the copy list and a stack, switching to the loader's page tables and its own stack before
|
||||
it copies anything. Doing the copy from code the firmware had placed wherever it liked put
|
||||
some of it inside the kernel's range on that machine: a triple fault and a reset. The
|
||||
routine is `sysv_abi`, because UEFI code is the Microsoft convention and the first try loaded
|
||||
the framebuffer address into `rsp`.
|
||||
|
||||
**No 1 GB pages, no problem.** Intel's desktop CPUs before Haswell have none, and there the
|
||||
PS bit in a PDPT entry is reserved: the first access after the switch is a page fault that
|
||||
cannot be handled either. Both the loader and the kernel check CPUID `0x80000001` EDX bit 26;
|
||||
without it the low 4 GB is four page directories of 2 MB pages (placed below the kernel, with
|
||||
the staged segments kept below 4 GB), and the kernel gives each gigabyte of its direct map
|
||||
and of `ioremap()` a page directory of its own. Neither KVM nor QEMU enforces the reserved
|
||||
bit, so the fault could not be reproduced here; with the fallback forced on, the kernel
|
||||
boots at 2 and 8 GB and both CPUs start.
|
||||
|
||||
### The loader jumped out from under itself
|
||||
|
||||
A machine with a lot of RAM froze at "Starting the kernel" — the splash still
|
||||
|
|
@ -610,7 +646,9 @@ in the one process that runs first.
|
|||
|
||||
## What it does not do
|
||||
|
||||
- **No BIOS path.** A machine without UEFI does not boot SchOS.
|
||||
- **No BIOS path.** A machine without UEFI does not boot SchOS. The ISO carries a real EFI
|
||||
system partition (MBR type `0xEF`, FAT16 by cluster count, the type old firmware reads best),
|
||||
so a stick written with `dd` or `write.sh` boots on strict firmware as well as on lenient.
|
||||
- **The quiet boot hides a slow one.** With nothing printing between the
|
||||
loader and the greeting, a boot that stalls for ten seconds looks the same as
|
||||
one that does not. F8 is the answer and it has to be pressed *before* the
|
||||
|
|
@ -621,9 +659,11 @@ in the one process that runs first.
|
|||
with its partitions, but nothing mounts it. See [usb.md](usb.md).
|
||||
- **NVMe and AHCI poll for completion**, one command at a time per disk. That
|
||||
is enough to boot and run from them, not to be fast.
|
||||
- **`make ramroot` is the only way to boot with no data disk.** It links a
|
||||
filesystem image into the kernel binary, which costs boot time and carries a
|
||||
licensing constraint — see [../licensing.md](../licensing.md) §4.
|
||||
- **The live ISO is a ramdisk root.** `make iso` builds the root as a SchFS image,
|
||||
compresses it ([scff.md](scff.md)) and links it into the kernel; nothing is written to
|
||||
the machine's disks, and everything written to the root is gone at reboot. There is
|
||||
no installer, and no kernel that finds a root on a disk by SchFS's GPT type as its
|
||||
*default*. `make ramroot` is the same without compression.
|
||||
- **The 32-bit multiboot entry is dead code.** It is left in place deliberately:
|
||||
deleting kernel entry code is its own piece of work with its own way of
|
||||
failing silently.
|
||||
|
|
|
|||
Loading…
Reference in a new issue