My kernel has FPU support, including SSE and friends, and with lazy task switching. Basically my approach is to create an FPU image in the task state, drop in the constants needed for SSE to work, then just reload cr0 with the TS bit upon task switch.
Then when the FPU is actually needed, the previous state is stored and the new state loaded.
You are free to post these snippets on the wiki. Probably best if someone doublechecked them in case I misinterpreted something from the manuals - I don't have working 386s and 486s to check if all code paths do what they should.
Code: Select all
DetectCoprocessor: CPU 386 FPU
MOV EDX, CR0 ; CR0 has a bit on the matter as well
AND EDX, CR0_ET ; Check Extension Type
JZ .nofpu ; The processor supports no FPU
MOV EDX, CR0 ; Start probe, get CR0
AND EDX, (-1) - (CR0_TS + CR0_EM) ; clear TS and EM to force fpu access
OR EDX, CR0_NE ; set NE (workaround no-wait bug)
MOV CR0, EDX ; store control word
FNINIT ; load defaults to FPU
FNSTSW [.testword] ; store status word. If there's no coprocessor, nothing happens
CMP word [.testword], 0 ; compare the written status
JNE .nofpu
.hasfpu: ; do something when there is an FPU installed
.nofpu: ; do something when there isn't an FPU installed
RET
.testword: DW 0x55AA
Useful for those machines when there's no CPUID to ask, or the coprocessor isn't on-chip
Anyway, if you have a CPU without on-chip FPU, you might want to do paranoia checks on the interrupt handling that it indeed works, otherwise, you should set CR0.NE since that doesn't require your chipset to have that wiring in place.
If you want to enable SSE, you should check the CPUID bits for SSE
and Fast save-restore functionality. If your processor can handle that, you can set CR4.OSFXSR and CR4.OSXMMEXCPT.
To switch FPU states you'll have to store the context. Note that this differs when SSE is enabled. FNSAVE/FNRSTOR doesn't store SSE state, FXSAVE/FXRSTOR do but you'll get errors when you try that on a non-sse-enabled machine
Code: Select all
; EDX -> store data
; EAX -> get data
CMP dword [sse_enabled], 0
JE .fpuonly
CPU 686
.fpuandsse: CLTS
FXSAVE [EDX]
FXRSTOR [EAX]
JMP .done2
.fpuonly: CLTS
FNSAVE [EDX]
FRSTOR [EAX]
JMP .done2
CPU 386
For FPU support, you should write the #NM handler (for handling lazy FPU switches) and #MF handler (for dealing with FPU exceptions)
For SSE, you should write the XF handler as well (for SIMD exceptions).