boot: separate BIOS from UEFI

boot/bios/ now holds the MBR, the El Torito stub and the real-mode stage
2; boot/uefi/ is empty and documented.

Separate directories rather than #ifdefs, because the two share almost
nothing. A BIOS loader lives in 16-bit real mode, reaches the firmware
through software interrupts, and walks itself up into long mode. A UEFI
loader is a 64-bit PE that the firmware has already placed in long mode
with paging on, calling services through a table of function pointers.
What they do share is the hand-off contract, which boot/README.md now
writes down: ELF segments placed, long mode, a 24-byte-entry memory map
at E820_MAP_ADDR, framebuffer geometry at VBE_INFO_ADDR.

That contract is the point of documenting it now. UEFI's GetMemoryMap
returns EFI_MEMORY_DESCRIPTORs, and the right move is to translate them
into the entries kernel/arch/x86_64/e820.c already parses rather than
teach the kernel a second format.

Build output paths under $(BUILD)/boot are unchanged; only sources moved.
This commit is contained in:
Nexoniarz 2026-08-09 16:00:03 +02:00
commit 08a1a9033a
19 changed files with 125 additions and 33 deletions

View file

@ -16,7 +16,7 @@ one group. Verified rendering correctly on 2026-08-08.
counter-intuitive part and it is a timing fact, not a preference: the kernel does counter-intuitive part and it is a timing fact, not a preference: the kernel does
not reach `vga_init()` until roughly the last 300ms of a ~2.8s boot, so a not reach `vga_init()` until roughly the last 300ms of a ~2.8s boot, so a
kernel-drawn logo appeared for about one frame before `console_takeover()` wiped kernel-drawn logo appeared for about one frame before `console_takeover()` wiped
it. Drawn from `splash()` in `boot/stage2main.c` it is up for the whole boot. it. Drawn from `splash()` in `boot/bios/stage2main.c` it is up for the whole boot.
`kernel/dev/vga.c` keeps the same drawing code against the same mask `kernel/dev/vga.c` keeps the same drawing code against the same mask
(`vga_draw_logo`, `vga_logo_centered`) for things that want the mark *after* (`vga_draw_logo`, `vga_logo_centered`) for things that want the mark *after*
boot — the crash screen, eventually `schinit`. Don't "fix" the duplication by boot — the crash screen, eventually `schinit`. Don't "fix" the duplication by
@ -35,7 +35,7 @@ for the one rule. 4 bits rather than 8 because the header is included by the
**`STAGE2_SECTORS` was encoded in five places, not the three `docs/layout.md` **`STAGE2_SECTORS` was encoded in five places, not the three `docs/layout.md`
claimed.** Raising it 24 → 48 to fit the 8 KiB mask proved it: the `dd seek=25` claimed.** Raising it 24 → 48 to fit the 8 KiB mask proved it: the `dd seek=25`
offset stayed behind and the kernel got written straight over stage2's tail. offset stayed behind and the kernel got written straight over stage2's tail.
The five were `boot/bootasm.S`, `boot/stage2main.c`, the `dd seek=`, and *twice* The five were `boot/bios/bootasm.S`, `boot/bios/stage2main.c`, the `dd seek=`, and *twice*
inside `tools/mkiso.sh` (its size assertion and `-boot-load-size`). It now lives inside `tools/mkiso.sh` (its size assertion and `-boot-load-size`). It now lives
only in the root Makefile, which passes `-DSTAGE2_SECTORS` and exports it to only in the root Makefile, which passes `-DSTAGE2_SECTORS` and exports it to
mkiso; the `#define`s left in the boot sources are `#ifndef` fallbacks. Hard mkiso; the `#define`s left in the boot sources are `#ifndef` fallbacks. Hard

View file

@ -18,7 +18,7 @@ protected mode before it reads the kernel. That rules out both El Torito
emulation modes (hard-disk emulation exists only through the BIOS) and floppy emulation modes (hard-disk emulation exists only through the BIOS) and floppy
emulation (2.88 MB cap). So: emulation (2.88 MB cap). So:
- `boot/cdboot.S` — a separate stage 1 for optical media. `tools/mkiso.sh` - `boot/bios/cdboot.S` — a separate stage 1 for optical media. `tools/mkiso.sh`
passes `-boot-load-size 25`, so the BIOS loads cdboot *and* all 24 sectors of passes `-boot-load-size 25`, so the BIOS loads cdboot *and* all 24 sectors of
stage2 before anything of ours runs, putting stage2 at 0x7E00 exactly where stage2 before anything of ours runs, putting stage2 at 0x7E00 exactly where
`bootasm.S` would have. cdboot only records the medium and jumps. `bootasm.S` would have. cdboot only records the medium and jumps.

View file

@ -383,10 +383,10 @@ qemu-iso: schos.iso
# splash, and loads the kernel — not size-constrained the same way, just # splash, and loads the kernel — not size-constrained the same way, just
# padded out to a fixed STAGE2_SECTORS*512 bytes so the kernel's starting # padded out to a fixed STAGE2_SECTORS*512 bytes so the kernel's starting
# sector on disk is predictable (kept in sync with STAGE2_SECTORS in # sector on disk is predictable (kept in sync with STAGE2_SECTORS in
# boot/bootasm.S and boot/stage2main.c). # boot/bios/bootasm.S and boot/bios/stage2main.c).
# ----------------------------------------------------------------------- # -----------------------------------------------------------------------
# STAGE2_SECTORS used to be written out three times -- here, in boot/bootasm.S # STAGE2_SECTORS used to be written out three times -- here, in boot/bios/bootasm.S
# and in boot/stage2main.c -- and docs/layout.md carried a warning about keeping # and in boot/bios/stage2main.c -- and docs/layout.md carried a warning about keeping
# them in step. They are now all fed from this one variable via -D, so the # them in step. They are now all fed from this one variable via -D, so the
# warning describes a problem that can no longer happen. Both C/asm files keep # warning describes a problem that can no longer happen. Both C/asm files keep
# an #ifndef fallback purely so they still read sensibly on their own. # an #ifndef fallback purely so they still read sensibly on their own.
@ -405,9 +405,9 @@ STAGE2_DEF = -DSTAGE2_SECTORS=$(STAGE2_SECTORS)
# that make carried on and padstage2.pl received nonsense. # that make carried on and padstage2.pl received nonsense.
STAGE2_BYTES = $$(( $(STAGE2_SECTORS) * 512 )) STAGE2_BYTES = $$(( $(STAGE2_SECTORS) * 512 ))
$(BUILD)/boot/bootblock: boot/bootasm.S $(BUILD)/boot/bootblock: boot/bios/bootasm.S
@mkdir -p $(BUILD)/boot @mkdir -p $(BUILD)/boot
$(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -nostdinc -I./include -c boot/bootasm.S -o $(BUILD)/boot/bootasm.o $(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -nostdinc -I./include -c boot/bios/bootasm.S -o $(BUILD)/boot/bootasm.o
$(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e start -Ttext 0x7C00 \ $(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e start -Ttext 0x7C00 \
-o $(BUILD)/boot/bootblocktmp.o $(BUILD)/boot/bootasm.o -o $(BUILD)/boot/bootblocktmp.o $(BUILD)/boot/bootasm.o
$(OBJCOPY) -S -O binary -j .text $(BUILD)/boot/bootblocktmp.o $(BUILD)/boot/bootblock $(OBJCOPY) -S -O binary -j .text $(BUILD)/boot/bootblocktmp.o $(BUILD)/boot/bootblock
@ -415,19 +415,19 @@ $(BUILD)/boot/bootblock: boot/bootasm.S
# Stage 1 for optical media. Same job as bootblock, far less of it: El Torito # Stage 1 for optical media. Same job as bootblock, far less of it: El Torito
# has already loaded stage2 alongside this sector by the time it runs, so it # has already loaded stage2 alongside this sector by the time it runs, so it
# only records that we came from a CD and jumps. See boot/cdboot.S. # only records that we came from a CD and jumps. See boot/bios/cdboot.S.
$(BUILD)/boot/cdboot: boot/cdboot.S $(BUILD)/boot/cdboot: boot/bios/cdboot.S
@mkdir -p $(BUILD)/boot @mkdir -p $(BUILD)/boot
$(CC32) -fno-builtin -fno-pic -nostdinc -I./include -c boot/cdboot.S -o $(BUILD)/boot/cdbootasm.o $(CC32) -fno-builtin -fno-pic -nostdinc -I./include -c boot/bios/cdboot.S -o $(BUILD)/boot/cdbootasm.o
$(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e start -Ttext 0x7C00 \ $(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e start -Ttext 0x7C00 \
-o $(BUILD)/boot/cdboottmp.o $(BUILD)/boot/cdbootasm.o -o $(BUILD)/boot/cdboottmp.o $(BUILD)/boot/cdbootasm.o
$(OBJCOPY) -S -O binary -j .text $(BUILD)/boot/cdboottmp.o $@ $(OBJCOPY) -S -O binary -j .text $(BUILD)/boot/cdboottmp.o $@
./tools/sign.pl $@ ./tools/sign.pl $@
$(BUILD)/boot/stage2: boot/stage2.S boot/stage2main.c include/logo.h $(BUILD)/boot/stage2: boot/bios/stage2.S boot/bios/stage2main.c include/logo.h
@mkdir -p $(BUILD)/boot @mkdir -p $(BUILD)/boot
$(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -nostdinc -I./include -c boot/stage2.S -o $(BUILD)/boot/stage2asm.o $(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -nostdinc -I./include -c boot/bios/stage2.S -o $(BUILD)/boot/stage2asm.o
$(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -O -nostdinc -I./include -c boot/stage2main.c -o $(BUILD)/boot/stage2main.o $(CC32) $(STAGE2_DEF) -fno-builtin -fno-pic -O -nostdinc -I./include -c boot/bios/stage2main.c -o $(BUILD)/boot/stage2main.o
$(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e stage2start -Ttext 0x7E00 \ $(LD) -m elf_i386 -nostdlib $(LD_LOWBASE) -n -N -e stage2start -Ttext 0x7E00 \
-o $(BUILD)/boot/stage2tmp.o $(BUILD)/boot/stage2asm.o $(BUILD)/boot/stage2main.o -o $(BUILD)/boot/stage2tmp.o $(BUILD)/boot/stage2asm.o $(BUILD)/boot/stage2main.o
$(OBJCOPY) -S -O binary -j .text -j .rodata -j .data $(BUILD)/boot/stage2tmp.o $(BUILD)/boot/stage2 $(OBJCOPY) -S -O binary -j .text -j .rodata -j .data $(BUILD)/boot/stage2tmp.o $(BUILD)/boot/stage2

64
boot/README.md Normal file
View file

@ -0,0 +1,64 @@
<!-- SPDX-License-Identifier: Apache-2.0 -->
# Booting SchOS
Two firmware paths, kept apart on purpose:
```
boot/
bios/ legacy BIOS: MBR, El Torito CD stub, real-mode stage 2
uefi/ UEFI application (not written yet)
```
They are separate directories rather than `#ifdef`s in one because they share
almost nothing. A BIOS loader lives in 16-bit real mode, talks to the firmware
through software interrupts, and has to walk itself up into long mode. A UEFI
loader is a 64-bit PE executable that the firmware has *already* placed in long
mode with paging on, and it asks for services by calling through a table of
function pointers. The only things genuinely in common are the logo bitmap, the
menu's appearance, and the hand-off contract below.
## What the loader must hand the kernel
Whichever path runs, the kernel expects the same things. This is the contract;
a second loader is correct exactly when it satisfies it.
| | Where | Notes |
|---|---|---|
| Kernel image | loaded per its ELF program headers | entry at `entry64` |
| CPU state | long mode, paging on, interrupts off | BIOS path builds this itself |
| Memory map | `E820_MAP_ADDR`, 24-byte entries, count at `E820_COUNT_ADDR` | `kernel/arch/x86_64/e820.c` reads it |
| Framebuffer | `VBE_INFO_ADDR` | address, pitch, width, height, depth |
| Verbose flag | `BOOT_VERBOSE_FLAG_ADDR` | set by the F8 menu |
The addresses are defined once, in `include/memlayout.h` and
`boot/bios/stage2main.c`. A UEFI loader must fill the same structures — the
kernel does not care which firmware produced them, and that is what keeps the
split cheap.
`e820.c` reads a *BIOS* memory map. UEFI hands out a different structure
(`EFI_MEMORY_DESCRIPTOR`, from `GetMemoryMap`), so the UEFI loader has to
translate it into the same 24-byte entries rather than inventing a second
format for the kernel to learn.
## The BIOS path today
1. **`bios/bootasm.S`** — the literal MBR sector. Signed to 512 bytes by
`tools/sign.pl`, loads stage 2 from LBA 1 and jumps.
2. **`bios/cdboot.S`** — the same job for optical media, as an El Torito
no-emulation image. Separate because the loader never uses INT 13h and so
needs a real ATAPI read.
3. **`bios/stage2.S`** — collects the E820 map, sets a VBE mode, enters
protected mode.
4. **`bios/stage2main.c`** — the boot menu and splash, then loads the kernel
and enters long mode.
`STAGE2_SECTORS` is defined **once**, in the Makefile, and passed to both the
assembler and the `dd` that writes the image. It used to be written out by hand
in five places and silently truncated the loader when they disagreed.
## Why UEFI is worth doing
Everything since roughly 2012 boots UEFI by default, and Secure Boot machines
will not run the BIOS path at all without firmware settings most people never
touch. The BIOS loader stays regardless: it is what QEMU's default machine and
older hardware use, and it costs nothing to keep once the two are separated.

View file

@ -46,7 +46,7 @@ _Static_assert(0x7E00 + STAGE2_SECTORS * 512 <= 0x10000,
// kind of thing that turns into one later. // kind of thing that turns into one later.
#define BOOT_VERBOSE_FLAG_ADDR (VBE_INFO_ADDR + 0x100) #define BOOT_VERBOSE_FLAG_ADDR (VBE_INFO_ADDR + 0x100)
// Set by boot/cdboot.S when we were booted from optical media. One byte past // Set by boot/bios/cdboot.S when we were booted from optical media. One byte past
// the verbose flag, for the same reason that one sits where it does: clear of // the verbose flag, for the same reason that one sits where it does: clear of
// the 256-byte VBE mode info block at VBE_INFO_ADDR. // the 256-byte VBE mode info block at VBE_INFO_ADDR.
#define BOOT_MEDIA_FLAG_ADDR (VBE_INFO_ADDR + 0x101) #define BOOT_MEDIA_FLAG_ADDR (VBE_INFO_ADDR + 0x101)

28
boot/uefi/README.md Normal file
View file

@ -0,0 +1,28 @@
<!-- SPDX-License-Identifier: Apache-2.0 -->
# UEFI loader
Not written yet. This directory exists so the BIOS path could be moved into
`boot/bios/` without pretending the split was hypothetical.
See `../README.md` for the hand-off contract a loader has to satisfy. The
short version: the kernel wants long mode with paging on, its ELF segments
placed, a 24-byte-entry E820-shaped memory map, and framebuffer geometry — and
it does not care which firmware produced them.
What this will need, in rough order:
1. A PE/COFF target. clang can emit one directly
(`--target=x86_64-unknown-windows -fuse-ld=lld-link`), so no new toolchain:
the same LLVM install already builds every other target here.
2. The handful of UEFI structures actually used — the system table, boot
services, `LOADED_IMAGE`, `SIMPLE_FILE_SYSTEM`, `GRAPHICS_OUTPUT`. Written
from the specification rather than by importing gnu-efi or EDK II, which is
both a licence question and a large dependency for something this small.
3. `GetMemoryMap` translated into the same 24-byte entries `e820.c` already
parses. Not a second format for the kernel to learn.
4. `ExitBootServices` before touching the memory it described.
5. Graphics Output Protocol for the framebuffer, filling the same
`VBE_INFO_ADDR` structure the BIOS path fills.
The image goes at `EFI/BOOT/BOOTX64.EFI` on a FAT ESP, which also means the
ISO gains an El Torito EFI entry alongside the BIOS one it already has.

View file

@ -142,14 +142,14 @@ no room to add so much as a print statement.
Split into two stages, the standard way real bootloaders solve this: Split into two stages, the standard way real bootloaders solve this:
- **Stage 1** (`boot/bootasm.S`, still the literal MBR sector, still - **Stage 1** (`boot/bios/bootasm.S`, still the literal MBR sector, still
≤510 bytes) does exactly one thing: raw IDE PIO (LBA28) reads ≤510 bytes) does exactly one thing: raw IDE PIO (LBA28) reads
`STAGE2_SECTORS` (16) sectors starting at disk sector 1 into memory at `STAGE2_SECTORS` (16) sectors starting at disk sector 1 into memory at
`0x7E00`, then jumps there. Nothing else fits, nothing else is needed. `0x7E00`, then jumps there. Nothing else fits, nothing else is needed.
(Caught a real bug writing this: `outb $0x1F7,%al`-style immediates (Caught a real bug writing this: `outb $0x1F7,%al`-style immediates
silently truncate to 8 bits — ports 0x1F2-0x1F7 are all > 0xFF and need silently truncate to 8 bits — ports 0x1F2-0x1F7 are all > 0xFF and need
the `%dx` register form, or you're hitting the wrong I/O port entirely.) the `%dx` register form, or you're hitting the wrong I/O port entirely.)
- **Stage 2** (`boot/stage2.S` + `boot/stage2main.c`, loaded at `0x7E00`, - **Stage 2** (`boot/bios/stage2.S` + `boot/bios/stage2main.c`, loaded at `0x7E00`,
occupies disk sectors 1-16) does everything stage 1 used to skip straight occupies disk sectors 1-16) does everything stage 1 used to skip straight
to, plus a boot banner (BIOS teletype, real mode, before the VBE mode to, plus a boot banner (BIOS teletype, real mode, before the VBE mode
switch — note this only reaches the video device, not serial, so it switch — note this only reaches the video device, not serial, so it
@ -287,7 +287,7 @@ across a long `ls`-heavy session to see what's actually climbing.
## 6. Boot speed ## 6. Boot speed
Two cheap, real wins in `boot/stage2main.c`, no functional changes: Two cheap, real wins in `boot/bios/stage2main.c`, no functional changes:
- `progress_tick()` (called once per 512-byte disk sector) used to trigger - `progress_tick()` (called once per 512-byte disk sector) used to trigger
a full progress-bar redraw — border plus fill, a few thousand pixel a full progress-bar redraw — border plus fill, a few thousand pixel

View file

@ -155,7 +155,7 @@ blob's build location and those symbol names change; update the Makefile to
match or the kernel fails to link. match or the kernel fails to link.
**`STAGE2_SECTORS` now lives in exactly one place: the root `Makefile`.** It used **`STAGE2_SECTORS` now lives in exactly one place: the root `Makefile`.** It used
to be written out by hand in five — `boot/bootasm.S`, `boot/stage2main.c`'s to be written out by hand in five — `boot/bios/bootasm.S`, `boot/bios/stage2main.c`'s
`readseg()`, the `dd ... seek=` offset, and twice more inside `tools/posix/mkiso.sh` `readseg()`, the `dd ... seek=` offset, and twice more inside `tools/posix/mkiso.sh`
(its stage2 size assertion and `-boot-load-size`). This note used to warn you to (its stage2 size assertion and `-boot-load-size`). This note used to warn you to
keep three of them in step and did not know about the other two. keep three of them in step and did not know about the other two.
@ -170,6 +170,6 @@ Makefile always wins.
Two things still fail the build rather than silently misbooting, and should stay Two things still fail the build rather than silently misbooting, and should stay
that way: `tools/padstage2.pl` errors if stage2 overflows its budget instead of that way: `tools/padstage2.pl` errors if stage2 overflows its budget instead of
truncating it, and `boot/stage2main.c` static-asserts that stage2 cannot reach truncating it, and `boot/bios/stage2main.c` static-asserts that stage2 cannot reach
the multiboot kernel-search buffer at `0x10000` — which puts the hard ceiling at the multiboot kernel-search buffer at `0x10000` — which puts the hard ceiling at
65 sectors, since stage2 loads at `0x7E00`. 65 sectors, since stage2 loads at `0x7E00`.

View file

@ -354,7 +354,7 @@ stops being extendable: it is 16-bit real mode, INT 10h VBE, and PIO ATA, none
of which exist on a UEFI-only machine. The realistic shape is a *second* of which exist on a UEFI-only machine. The realistic shape is a *second*
loader — an EFI application that gets the framebuffer from GOP, the memory map loader — an EFI application that gets the framebuffer from GOP, the memory map
from `GetMemoryMap()`, loads the kernel off a FAT ESP, and enters at the same from `GetMemoryMap()`, loads the kernel off a FAT ESP, and enters at the same
place `boot/stage2main.c` does — rather than a port of the existing one. Worth place `boot/bios/stage2main.c` does — rather than a port of the existing one. Worth
noting that the splash work just done survives that transition: it is a mask, a noting that the splash work just done survives that transition: it is a mask, a
palette and a layout, none of which care how the pixels were found. What does palette and a layout, none of which care how the pixels were found. What does
not survive is every assumption in `stage2main.c` about where things live in low not survive is every assumption in `stage2main.c` about where things live in low
@ -465,9 +465,9 @@ does not. Measured 2026-08-08: boots at 224M and above, triple faults at 192M
and below. Nothing is actually being *used* — the requirement is entirely and below. Nothing is actually being *used* — the requirement is entirely
fictional. fictional.
**The fix is already half-built.** `boot/stage2.S` collects a full E820 memory **The fix is already half-built.** `boot/bios/stage2.S` collects a full E820 memory
map in real mode and leaves it at `VBE_INFO_ADDR + 0x200` (count) and `+ 0x208` map in real mode and leaves it at `VBE_INFO_ADDR + 0x200` (count) and `+ 0x208`
(24-byte entries); `boot/stage2main.c` already parses it to print detected RAM. (24-byte entries); `boot/bios/stage2main.c` already parses it to print detected RAM.
**The kernel never reads it.** So: have `main()` take the top of the highest **The kernel never reads it.** So: have `main()` take the top of the highest
usable E820 region instead of the constant, clamp it to what the direct map usable E820 region instead of the constant, clamp it to what the direct map
covers, and keep `PHYSTOP` only as a fallback for the case where the firmware covers, and keep `PHYSTOP` only as a fallback for the case where the firmware

View file

@ -7,7 +7,7 @@
// solid logo. Whoever draws it picks the colour, so the palette stays in // solid logo. Whoever draws it picks the colour, so the palette stays in
// include/theme.h and can change without regenerating anything. // include/theme.h and can change without regenerating anything.
// //
// Two pixels per byte, high nibble first. Included by boot/stage2main.c // Two pixels per byte, high nibble first. Included by boot/bios/stage2main.c
// as well as kernel/dev/vga.c, and stage2 must fit below the 0x10000 // as well as kernel/dev/vga.c, and stage2 must fit below the 0x10000
// kernel-search buffer -- hence 4 bits rather than 8. // kernel-search buffer -- hence 4 bits rather than 8.

View file

@ -13,7 +13,7 @@
// Boot, console and shell share SCH_BG/SCH_FG. The panic screen keeps the // Boot, console and shell share SCH_BG/SCH_FG. The panic screen keeps the
// full-bleed purple entirely to itself, which is what makes it mean something. // full-bleed purple entirely to itself, which is what makes it mean something.
// //
// Included by boot/stage2main.c (freestanding, pre-kernel), kernel/dev/vga.c, // Included by boot/bios/stage2main.c (freestanding, pre-kernel), kernel/dev/vga.c,
// kernel/core/console.c and kernel/core/panic.c. Plain #defines only — no // kernel/core/console.c and kernel/core/panic.c. Plain #defines only — no
// types, no code — because stage2 is compiled 32-bit against a different // types, no code — because stage2 is compiled 32-bit against a different
// world than the kernel. // world than the kernel.

View file

@ -7,7 +7,7 @@
// every byte above 224 MB is invisible. Measured before this file existed: // every byte above 224 MB is invisible. Measured before this file existed:
// SchOS booted at 224 MB and triple faulted at 192 MB, for no reason at all. // SchOS booted at 224 MB and triple faulted at 192 MB, for no reason at all.
// //
// The firmware has known the answer the whole time. boot/stage2.S asks it with // The firmware has known the answer the whole time. boot/bios/stage2.S asks it with
// INT 0x15 / E820 in real mode -- the same interface Linux's boot stub and GRUB // INT 0x15 / E820 in real mode -- the same interface Linux's boot stub and GRUB
// use -- and leaves the result in low memory. stage2main.c already parses it to // use -- and leaves the result in low memory. stage2main.c already parses it to
// print detected RAM on the splash. The kernel simply never read it. // print detected RAM on the splash. The kernel simply never read it.
@ -23,7 +23,7 @@
uint64 phystop = PHYSTOP_FALLBACK; uint64 phystop = PHYSTOP_FALLBACK;
// Where stage2 left the map. Must match E820_COUNT_ADDR / E820_MAP_ADDR in // Where stage2 left the map. Must match E820_COUNT_ADDR / E820_MAP_ADDR in
// boot/stage2main.c, which are themselves relative to VBE_INFO_ADDR. // boot/bios/stage2main.c, which are themselves relative to VBE_INFO_ADDR.
#define E820_COUNT_ADDR (0x30000 + 0x200) #define E820_COUNT_ADDR (0x30000 + 0x200)
#define E820_MAP_ADDR (0x30000 + 0x208) #define E820_MAP_ADDR (0x30000 + 0x208)

View file

@ -12,12 +12,12 @@ static void startothers(void);
static void mpmain(void) __attribute__((noreturn)); static void mpmain(void) __attribute__((noreturn));
extern char end[]; // first address after kernel loaded from ELF file extern char end[]; // first address after kernel loaded from ELF file
// Set by stage2main.c (boot/stage2main.c, BOOT_VERBOSE_FLAG_ADDR) when the // Set by stage2main.c (boot/bios/stage2main.c, BOOT_VERBOSE_FLAG_ADDR) when the
// user picks "Boot SchOS (verbose)" from the F8 boot menu; read once here, // user picks "Boot SchOS (verbose)" from the F8 boot menu; read once here,
// before anything else, so subsystem init can log its own steps. // before anything else, so subsystem init can log its own steps.
int boot_verbose; int boot_verbose;
// Must match BOOT_VERBOSE_FLAG_ADDR in boot/stage2main.c exactly: just past // Must match BOOT_VERBOSE_FLAG_ADDR in boot/bios/stage2main.c exactly: just past
// the VBE info block, not 0x7000 (startothers() below uses that address for // the VBE info block, not 0x7000 (startothers() below uses that address for
// the AP boot trampoline). // the AP boot trampoline).
#define BOOT_VERBOSE_FLAG_ADDR (0x30000 + 0x100) #define BOOT_VERBOSE_FLAG_ADDR (0x30000 + 0x100)

View file

@ -39,7 +39,7 @@ vga_set_bg(uint32 color)
vga_bg = color; vga_bg = color;
} }
// Written by boot/stage2.S's VBE call and read by boot/stage2main.c under // Written by boot/bios/stage2.S's VBE call and read by boot/bios/stage2main.c under
// the same name (VBE_INFO_ADDR) — not 0x9000, since stage2's own code now // the same name (VBE_INFO_ADDR) — not 0x9000, since stage2's own code now
// runs up to nearly 0x9000 once the boot-menu/progress-bar logic is // runs up to nearly 0x9000 once the boot-menu/progress-bar logic is
// included, which would otherwise clobber a mode info block placed there. // included, which would otherwise clobber a mode info block placed there.
@ -391,7 +391,7 @@ vga_text_at(int x, int y, const char *s, uint32 color)
// --- Logo ------------------------------------------------------------------ // --- Logo ------------------------------------------------------------------
// //
// The boot splash's logo is drawn by the *loader*, not here -- see splash() in // The boot splash's logo is drawn by the *loader*, not here -- see splash() in
// boot/stage2main.c. It has to be, because the kernel does not reach vga_init() // boot/bios/stage2main.c. It has to be, because the kernel does not reach vga_init()
// until roughly the last 300ms of a 2.8s boot: drawing it here put the logo on // until roughly the last 300ms of a 2.8s boot: drawing it here put the logo on
// screen for one frame before console_takeover() wiped it, which is worse than // screen for one frame before console_takeover() wiped it, which is worse than
// not having one. // not having one.

View file

@ -22,7 +22,7 @@
# is that stage2main.c reads the kernel back with ATAPI instead of ATA. # is that stage2main.c reads the kernel back with ATAPI instead of ATA.
# #
# STAGE2_SECTORS comes from the environment, set by the Makefile, because this # STAGE2_SECTORS comes from the environment, set by the Makefile, because this
# same number also lives in boot/bootasm.S, boot/stage2main.c and the dd offsets # same number also lives in boot/bios/bootasm.S, boot/bios/stage2main.c and the dd offsets
# in schos.img's recipe. It was previously written out by hand in three # in schos.img's recipe. It was previously written out by hand in three
# separate spots in this file alone, and raising it for the boot logo is what # separate spots in this file alone, and raising it for the boot logo is what
# turned that from a latent hazard into a broken image. # turned that from a latent hazard into a broken image.

View file

@ -468,7 +468,7 @@ if ($gens.Count -ge 2 -and
if ($Fb) { if ($Fb) {
Expect 'id\s+schosfb' 'FBIOGET_FSCREENINFO identifies the device' Expect 'id\s+schosfb' 'FBIOGET_FSCREENINFO identifies the device'
# 800x600 is what boot/stage2.S asks VBE for. Asserting the numbers rather # 800x600 is what boot/bios/stage2.S asks VBE for. Asserting the numbers rather
# than just "the ioctl returned" is the point: the old code path returned # than just "the ioctl returned" is the point: the old code path returned
# success with an untouched buffer, i.e. a 0x0 screen. # success with an untouched buffer, i.e. a 0x0 screen.
Expect '(?m)^xres\s+800' 'the reported width is the mode actually set' Expect '(?m)^xres\s+800' 'the reported width is the mode actually set'