-----Original Message-----
From: ros-dev-bounces(a)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...
1) 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
2) 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
3) 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