Dynamic MTRR support
C code requires RAM for the stack and heap, and coreboot has to execute C code before RAM is initialized. The "cache-as-RAM" loader sets up a dynamic MTRR to allocate a small area of memory (0xfefc0000-0xfefc2000 by default) on the CPU cache to use as a stack/heap, and another one to shadow the BIOS area. Booting coreboot with no-op MTRRs (as currently done in master) results in a stack corruption as soon as the first C function returns, because the memory area it expects the stack to be in is unallocated and therefore always reads 0xff. It is possible to modify coreboot to assume all RAM is initialized and usable from the get go, like it already does for virtualizers, but that would violate our policy of emulating real machines.
The logical solution would be emulating the CPU cache, but that has massive implications mostly related to performance. I've opted to instead create a "parallel page table", where each MTRR declaration will dynamically allocate 4KB pages (the MTRR granularity on P6 is 4KB) as needed, and the (WB)INVD instructions will flush these pages accordingly. This implementation only accepts MTRRs up to 32KB in size, more than enough for coreboot, otherwise BIOSes and OSes might exhaust emulator memory by running a MTRR through the entire address space.
The branch also adds ENABLE_SERIAL_CONSOLE to serial.c, which logs all transmitted serial bytes to stdout to aid with coreboot debugging. Non-printable characters are printed as their hex value in brackets.
Fixes in master
Two issues encountered during development of the feature/mtrr branch had their fixes integrated to the master branch, as they affected emulator behavior outside the scope of coreboot.
1. The MTRRcap MSR now reports the sane value of 0x508 (8 supported MTRRs) instead of just 0, otherwise the coreboot cache-as-RAM loader loops infinitely while trying to clear uninitialized MTRRs.
-> This triggers a bug compatibility scenario starting in v2.10: at least on Award 440BX machines with the stock BIOS, Linux will only see up to ~512MB of RAM, because the kernel deems any RAM above what the BIOS leaves MTRRs for as uncacheable and trims it off to avoid performance issues in real systems; this check is skipped if no MTRRs are found ("virtualized system"), which was the case in v2.07 as MTRRcap reported 0 supported MTRRs. It is true that Klamath can only cache 512MB, but this happens with all CPUs.
Code: Select all
[ 0.000000] WARNING: BIOS bug: CPU MTRRs don't cover all of memory, losing 511MB of RAM.
SPD: also in master
Back in the 430 chipsets, a BIOS would detect the amount of installed RAM by probing around with the northbridge's DRAM Row Boundary (DRB) registers. The 440BX datasheet states that RAM should instead be detected through the new Serial Presence Detect (SPD) standard, which is an I2C ROM built into DIMMs containing information on the module such as its capacity, connected to the southbridge through the new System Management Bus (SMBus). However, standard BIOSes (such as Award and AMI) continued to use the old 430 DRB method, presumably because some early SDRAM DIMMs lacked the SPD chip, or because BIOS developers were lazy.
Then coreboot showed up, and it actually requires SPD to detect RAM, which is not a bad thing: it's a platform-independent way of detecting RAM, and the vast majority of DIMMs have SPD anyway. This brought me on an adventure where I've implemented emulation for SMBus, SPD (to satisfy coreboot) and hardware monitoring chips (to satisfy the stock BIOS on the coreboot-capable ASUS motherboards). The tracking thread for SMBus and devices is here.
Coreboot machines and hacks
ASUS P2B-LS and P3B-F, which were added to 86Box in their original forms specifically to allow for coreboot in the future.
Both have alternate machine list entries for coreboot, which enable the following hacks through the MACHINE_COREBOOT flag:
- mem: Make the new dynarec byte_*_mask arrays span the entire address space, because otherwise, recompilation in the BIOS area results in segfaults from out-of-bounds accesses to these arrays. This bumps the new dynarec's memory usage to 1GB (4GB ÷ 1 bit per byte × 2 arrays), further increasing 32-bit address space pressure.
- nvr_at: Sync the configured floppy drive types to CMOS as SeaBIOS has no setup utility.
- keyboard_at: Hard reset on i8042 reset to avoid a SeaBIOS soft reset loop. A better solution might exist, but this is mostly an upstream issue: SeaBIOS first tries to ACPI RESET_REG (not implemented on the coreboot ACPI tables for these machines, usually wired to TRC reset on newer machines), then i8042 reset, then TRC reset only if the i8042 is not responding or PS/2 support is not compiled in.
Build instructions for coreboot (I use WSL1 Ubuntu 16.04)
Code: Select all
apt install git build-essential gnat flex bison libncurses5-dev wget zlib1g-dev wget https://coreboot.org/releases/coreboot-4.12.tar.xz -O- | tar Jxf - wget https://coreboot.org/releases/coreboot-blobs-4.12.tar.xz -O- | tar Jxf - cd coreboot-4.12 make crossgcc-i386 CPUS=16 # change the value to your thread count - this takes a long time make distclean make menuconfig # Mainboard ---> # Mainboard vendor: ASUS # Mainboard model: P2B-LS or P3B-F # <Save> then <Exit> make -j16 # change the value to your thread count # copy build/coreboot.rom to [86box]/roms/machines/(p2bls|p3bf)/coreboot.rom # delete [86box]/nvr/(p2bls|p3bf).bin # start 86Box