fpu: save each process's x87/SSE registers; keep the kernel off them
Nothing ever saved the FPU and SSE registers on a context switch. musl's memcpy, the compiler's struct copies and any arithmetic on doubles keep live values in %xmm, so two processes sharing a CPU wrote over each other's: two shells counting in a loop on one processor took a NULL+8 page fault within seconds, at a different rip every time. It reproduces on kernels from before this week too -- it had always been there, and every crash nobody could explain was a candidate. sched() now fxsaves the process leaving the CPU and scheduler() fxrstors the one arriving. A new process starts from the ABI's state (FCW 0x37F, MXCSR 0x1F80), fork copies the parent's live registers, exec resets them, and a signal handler's are put back by rt_sigreturn so the interrupted code finds what it had. The kernel was free to use %xmm too -- GCC vectorised struct copies and memset into 153 instructions of it -- so an interrupt could clobber the registers of the program it interrupted with no switch at all. Kernel, lwIP and uACPI objects are built -mgeneral-regs-only now and the image has none; cmd/ keeps SSE. Checked under QEMU: three concurrent loops three times over, on 1 CPU and on 4, no faults; before, every run faulted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
a2d987db5f
commit
0e39e711f1
6 changed files with 69 additions and 0 deletions
8
Makefile
8
Makefile
|
|
@ -425,6 +425,14 @@ CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -Wall -MD -MP -ggdb
|
|||
CFLAGS += -ffreestanding -fno-common -nostdlib -I./include $(XFLAGS) $(OPT)
|
||||
CFLAGS += $(NO_SSP) $(CFLAGS_EXTRA)
|
||||
|
||||
# The kernel keeps its hands off the FPU and SSE registers: they belong to
|
||||
# whichever process is running, and are saved only when it is switched out
|
||||
# (see "The FPU" in kernel/proc/proc.c). Without this GCC vectorises struct
|
||||
# copies and memset into %xmm, and an interrupt then scribbles over the
|
||||
# registers of the program it interrupted. Kernel objects only -- cmd/ is
|
||||
# built with these CFLAGS too and is welcome to use SSE.
|
||||
$(BUILD)/kernel/%.o $(BUILD)/lwip/%.o $(BUILD)/uacpi/%.o: CFLAGS += -mgeneral-regs-only
|
||||
|
||||
# lwIP's own headers, plus ours (cc.h and lwipopts.h live in kernel/net/lwip).
|
||||
# Only the network files are compiled with these: putting them in the global
|
||||
# CFLAGS would let any kernel file include lwIP by accident, and the stack is
|
||||
|
|
|
|||
Loading…
Reference in a new issue