-----Original Message----- From: ros-dev-bounces@reactos.com [mailto:ros-dev-bounces@reactos.com] On Behalf Of Gregor Anich Sent: Sunday, October 10, 2004 2:13 AM To: ReactOS Development List Subject: Re: [ros-dev] Save FPU on task switch/SSE support
Hartmut Birr wrote:
We can do the same for sse. If sse is available we must use
fxsave/fxrstor
instead of fsave/frstor and the buffer is 512 byte (108 byte
for normal
fpu).
- Hartmut
Hi!
I have thought about it a bit more and talked to tamlin a bit... now here's how I think some things should be done... and some things which i am not sure about...
- Initialize NpxState of KTHREAD to cr0 & MP | TS | EM in
Ke386InitThreadWithContext (maybe in Ke386InitThread too? I don't think so...) and change FLOATING_SAVE_AREA to FX_SAVE_AREA in that function - ke/i386/thread.c
MP, EM and NE should be set at startup and never change again. NpxState should be initialised, that the first fpu/sse instraction triggers the initialisation of the fpu. NpxState contains a status for kernel and user mode. The status is - context is invalid, fpu must be initialized - context is valid, fpu state must be restored - fpu has execute an instruction, fpu state must be saved
- in Ki386ContextSwitch we save cr0 & MP | TS | EM into the old
thread's NpxState, and put the NpxState of the new thread or'ed with TS into cr0 (this could be skipped, we could just set TS unless there was a reason to run some processes with EM set and some without; MP should never change I think - but this way is safer) - ke/i386/tskswitch.S
In Ki386ContextSwitch we must check NpxState:
a) user mode has execute a fpu instruction -> save user mode context, set NpxState to 'user mode valid', set TS and go on b) kernel mode has execute a fpu instruction -> save kernel mode context, set NpxState to 'kernel mode valid', set TS and go on c) no fpu instruction was exceute, TS is already set
- in KiTrapHandler handle the device-not-present exception
in a special way if TS in cr0 is set (or maybe assert that TS is set?) - can the device-not-present fault happen for non-FPU /SEE/MMX code? - ke/i386/exp.c
In KiTrapHandler (device not present) we must check NpxState and the mode by testing bit 0 of the saved cs:
A) called from user mode -> clear TS Aa) user mode has a valid context -> restore user mode context, set NpxState to 'user mode execute' and go on Ab) user mode has an invalid context -> initialize fpu, set NpxState to 'user mode execute' and go on
B) called from kernel mode -> clear TS Ba) user mode has execute a fpu instraction -> save user mode context, set NpxState to 'user mode valid' Bb) kernel mode has a valid context -> restore kernel mode context, set NpxState to 'kernel mode execute' and go on Bc) kernel mode has an invalid context -> initialize fpu, set NpxState to 'kernel mode execute' and go on
4.) Entering kernel mode (Syscall/int 2e):
We must check the previous mode. If the previous mode was user mode we set TS.
5.) Leaving kernel mode (Sysret/int 2e):
We must check the previous mode. We set TS. If the previous mode was user mode we set NpxState to 'kernel mode invalid'.
6.) NtW32Call/NtCallbackReturn:
We must save/restore the current context + NpxState and initialize the new context + NpxState on the new stack.
I am not sure when to save the FPU state... I think it has to be saved when the thread enters Ki386ContextSwitch and if TS is not set - this means the thread has used the FPU. Then the new thread will run, TS is set and the first FPU code will get into KiTrapHandler, where we handle it in a special way - we restore the previous (or initial) FPU state (FX_SAVE_AREA) from the kernel stack top, unset TS and let the thread run until it reaches Ki386ContextSwitch again where the FPU state will be saved if TS is unset.
Just bad that we will always have to save it if it was used I think, even if no other program uses it. First I thought maybe we could save the state of the old thread in the exception handler for the new threads first opcode (somewhere the previous thread is saved, isnt it?) and then restore the new thread's previous state - but this wouldnt work if one thread used the FPU, it switched to another (which doesnt use the FPU) and then to yet another which uses the FPU - the previous thread would then not be the first but the second thread which didnt use FPU)
If a thread has used the fpu, we must always save the the fpu state. An other idea is to put a pointer to the last thread, which has used the cpu, into the new thread. If the new thread use the fpu, it can save the old state to the saved thread. On thread switching, there is put the saved pointer or the current thread into the new thread. This is very difficult on thread terminating, because there can exist a 'fpu save pointer' in an other thread for the thread which is terminating.
- Hartmut