[NTOS]: Implement KiSwapProcess in C.

[NTOS]: Implement KiIsNpxPresent and KiIsNpxErrataPresent in C. It's much clearer what these are doing now.
[NTOS]: Implement KiFlushNPXState and fix some bugs that were present in the ASM version, such as a wrong NPX state check.
[NTOS]: Implement working intrinsics for fxrstor, fxsave, fnsave and enable them for flushing. We'll update the FPU trap code to use these later.

svn path=/trunk/; revision=45156
This commit is contained in:
Sir Richard 2010-01-20 04:05:08 +00:00
parent 04a018d92b
commit 01d2a95033
5 changed files with 223 additions and 287 deletions

View file

@ -14,6 +14,28 @@
: /* no input */ \
: "memory");
FORCEINLINE
VOID
Ke386FxStore(IN PFX_SAVE_AREA SaveArea)
{
asm volatile ("fxrstor (%0)" : : "r"(SaveArea));
}
FORCEINLINE
VOID
Ke386FxSave(IN PFX_SAVE_AREA SaveArea)
{
asm volatile ("fxsave (%0)" : : "r"(SaveArea));
}
FORCEINLINE
VOID
Ke386FnSave(IN PFLOATING_SAVE_AREA SaveArea)
{
asm volatile ("fnsave (%0); wait" : : "r"(SaveArea));
}
FORCEINLINE
VOID
Ke386SaveFpuState(IN PFX_SAVE_AREA SaveArea)

View file

@ -0,0 +1,51 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: ntoskrnl/ke/i386/context.c
* PURPOSE: Context Switching Related Code
* PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
/* FUNCTIONS ******************************************************************/
VOID
NTAPI
KiSwapProcess(IN PKPROCESS NewProcess,
IN PKPROCESS OldProcess)
{
PKIPCR Pcr = (PKIPCR)KeGetPcr();
#ifdef CONFIG_SMP
ULONG SetMember;
/* Update active processor mask */
SetMember = Pcr->SetMember;
InterlockedXor(NewProcess->ActiveProcessors, SetMember);
InterlockedXor(OldProcess->ActiveProcessors, SetMember);
#endif
/* Check for new LDT */
if (NewProcess->LdtDescriptor.LimitLow != OldProcess->LdtDescriptor.LimitLow)
{
/* Not handled yet */
UNIMPLEMENTED;
while (TRUE);
}
/* Update CR3 */
__writecr3(NewProcess->DirectoryTableBase[0]);
/* Clear GS */
Ke386SetGs(0);
/* Update IOPM offset */
Pcr->TSS->IoMapBase = NewProcess->IopmOffset;
}

View file

@ -944,6 +944,155 @@ KiSaveProcessorState(IN PKTRAP_FRAME TrapFrame,
KiSaveProcessorControlState(&Prcb->ProcessorState);
}
BOOLEAN
NTAPI
KiIsNpxPresent(VOID)
{
ULONG Cr0;
USHORT Magic;
/* Set magic */
Magic = 0xFFFF;
/* Read CR0 and mask out FPU flags */
Cr0 = __readcr0() & ~(CR0_MP | CR0_TS | CR0_EM | CR0_ET);
/* Store on FPU stack */
asm volatile ("fninit;" "fnstsw %0" : "+m"(Magic));
/* Magic should now be cleared */
if (Magic & 0xFF)
{
/* You don't have an FPU -- enable emulation for now */
__writecr0(Cr0 | CR0_EM | CR0_TS);
return FALSE;
}
/* You have an FPU, enable it */
Cr0 |= CR0_ET;
/* Enable INT 16 on 486 and higher */
if (KeGetCurrentPrcb()->CpuType >= 3) Cr0 |= CR0_NE;
/* Set FPU state */
__writecr0(Cr0 | CR0_EM | CR0_TS);
return TRUE;
}
BOOLEAN
NTAPI
KiIsNpxErrataPresent(VOID)
{
BOOLEAN ErrataPresent;
ULONG Cr0;
volatile double Value1, Value2;
/* Disable interrupts */
_disable();
/* Read CR0 and remove FPU flags */
Cr0 = __readcr0();
__writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM));
/* Initialize FPU state */
asm volatile ("fninit");
/* Multiply the magic values and divide, we should get the result back */
Value1 = 4195835.0;
Value2 = 3145727.0;
ErrataPresent = (Value1 * Value2 / 3145727.0) != 4195835.0;
/* Restore CR0 */
__writecr0(Cr0);
/* Enable interrupts */
_enable();
/* Return if there's an errata */
return ErrataPresent;
}
NTAPI
VOID
KiFlushNPXState(IN PFLOATING_SAVE_AREA SaveArea)
{
ULONG EFlags, Cr0;
PKTHREAD Thread, NpxThread;
PFX_SAVE_AREA FxSaveArea;
/* Save volatiles and disable interrupts */
EFlags = __readeflags();
_disable();
/* Save the PCR and get the current thread */
Thread = KeGetCurrentThread();
/* Check if we're already loaded */
if (Thread->NpxState != NPX_STATE_LOADED)
{
/* If there's nothing to load, quit */
if (!SaveArea) return;
/* Need FXSR support for this */
ASSERT(KeI386FxsrPresent == TRUE);
/* Check for sane CR0 */
Cr0 = __readcr0();
if (Cr0 & (CR0_MP | CR0_TS | CR0_EM))
{
/* Mask out FPU flags */
__writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM));
}
/* Get the NPX thread and check its FPU state */
NpxThread = KeGetCurrentPrcb()->NpxThread;
if ((NpxThread) && (NpxThread->NpxState == NPX_STATE_LOADED))
{
/* Get the FX frame and store the state there */
FxSaveArea = KiGetThreadNpxArea(NpxThread);
Ke386FxSave(FxSaveArea);
/* NPX thread has lost its state */
NpxThread->NpxState = NPX_STATE_NOT_LOADED;
}
/* Now load NPX state from the NPX area */
FxSaveArea = KiGetThreadNpxArea(Thread);
Ke386FxStore(FxSaveArea);
}
else
{
/* Check for sane CR0 */
Cr0 = __readcr0();
if (Cr0 & (CR0_MP | CR0_TS | CR0_EM))
{
/* Mask out FPU flags */
__writecr0(Cr0 & ~(CR0_MP | CR0_TS | CR0_EM));
}
/* Get FX frame */
FxSaveArea = KiGetThreadNpxArea(Thread);
Thread->NpxState = NPX_STATE_NOT_LOADED;
/* Save state if supported by CPU */
if (KeI386FxsrPresent) Ke386FxSave(FxSaveArea);
}
/* Now save the FN state wherever it was requested */
if (SaveArea) Ke386FnSave(SaveArea);
/* Clear NPX thread */
KeGetCurrentPrcb()->NpxThread = NULL;
/* Add the CR0 from the NPX frame */
Cr0 |= NPX_STATE_NOT_LOADED;
Cr0 |= FxSaveArea->Cr0NpxState;
__writecr0(Cr0);
/* Restore interrupt state */
__writeeflags(EFlags);
}
/* PUBLIC FUNCTIONS **********************************************************/
/*

View file

@ -17,237 +17,8 @@
#define Running 2
#define WrDispatchInt 0x1F
Dividend: .float 4195835.0
Divisor: .float 3145727.0
Result1: .float 0
Result2: .float 0
/* FUNCTIONS ****************************************************************/
.globl _KiIsNpxErrataPresent@0
.func KiIsNpxErrataPresent@0
_KiIsNpxErrataPresent@0:
/* Disable interrupts */
cli
/* Get CR0 and mask out FPU flags */
mov eax, cr0
mov ecx, eax
and eax, ~(CR0_MP + CR0_TS + CR0_EM)
mov cr0, eax
/* Initialize the FPU */
fninit
/* Do the divison and inverse multiplication */
fld qword ptr Dividend
fstp qword ptr Result1
fld qword ptr Divisor
fstp qword ptr Result2
fld qword ptr Result1
fdiv qword ptr Result2
fmul qword ptr Result2
/* Do the compare and check flags */
fcomp qword ptr Result1
fstsw ax
sahf
/* Restore CR0 and interrupts */
mov cr0, ecx
sti
/* Return errata status */
xor eax, eax
jz NoErrata
inc eax
NoErrata:
ret
.endfunc
.globl _KiIsNpxPresent@0
.func KiIsNpxPresent@0
_KiIsNpxPresent@0:
/* Save stack */
push ebp
/* Get CR0 and mask out FPU flags */
mov eax, cr0
and eax, ~(CR0_MP + CR0_TS + CR0_EM + CR0_ET)
/* Initialize the FPU and assume FALSE for return */
xor edx, edx
fninit
/* Save magic value on stack */
mov ecx, 0x42424242
push ecx
/* Setup stack for FPU store */
mov ebp ,esp
fnstsw [ebp]
/* Now check if our magic got cleared */
cmp byte ptr [ebp], 0
jnz NoFpu
/* Enable FPU, set return to TRUE */
or eax, CR0_ET
mov edx, 1
/* If this is a 486 or higher, enable INT 16 as well */
cmp dword ptr fs:KPCR_PRCB_CPU_TYPE, 3
jbe NoFpu
or eax, CR0_NE
NoFpu:
/* Set emulation enabled during the first boot phase and set the CR0 */
or eax, (CR0_EM + CR0_TS)
mov cr0, eax
/* Restore stack */
pop eax
pop ebp
/* Return true or false */
mov eax, edx
ret
.endfunc
.globl _KiFlushNPXState@4
.func KiFlushNPXState@4
_KiFlushNPXState@4:
/* Save volatiles and disable interrupts */
push esi
push edi
push ebx
pushfd
cli
/* Save the PCR and get the current thread */
mov edi, fs:[KPCR_SELF]
mov esi, [edi+KPCR_CURRENT_THREAD]
/* Check if we're already loaded */
cmp byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_LOADED
je IsValid
/* Check if we're supposed to get it */
cmp dword ptr [esp+20], 0
je Return
#if DBG
/* Assert Fxsr support */
test byte ptr _KeI386FxsrPresent, 1
jnz AssertOk
int 3
AssertOk:
#endif
/* Get CR0 and test if it's valid */
mov ebx, cr0
test bl, CR0_MP + CR0_TS + CR0_EM
jz Cr0OK
/* Enable fnsave to work */
and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
mov cr0, ebx
Cr0OK:
/* Check if we are the NPX Thread */
mov eax, [edi+KPCR_NPX_THREAD]
or eax, eax
jz DontSave
/* Check if it's not loaded */
cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
jnz DontSave
#if DBG
/* We are the NPX Thread with an unloaded NPX State... this isn't normal! */
int 3
#endif
/* Save the NPX State */
mov ecx, [eax+KTHREAD_INITIAL_STACK]
sub ecx, NPX_FRAME_LENGTH
fxsave [ecx]
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
DontSave:
/* Load the NPX State */
mov ecx, [esi+KTHREAD_INITIAL_STACK]
sub ecx, NPX_FRAME_LENGTH
fxrstor [ecx]
/* Get the CR0 state and destination */
mov edx, [ecx+FN_CR0_NPX_STATE]
mov ecx, [esp+20]
jmp DoneLoad
IsValid:
/* We already have a valid state, flush it */
mov ebx, cr0
test bl, CR0_MP + CR0_TS + CR0_EM
jz Cr0OK2
/* Enable fnsave to work */
and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
mov cr0, ebx
Cr0OK2:
/* Get the kernel stack */
mov ecx, [esi+KTHREAD_INITIAL_STACK]
test byte ptr _KeI386FxsrPresent, 1
lea ecx, [ecx-NPX_FRAME_LENGTH]
/* Set the NPX State */
mov byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
/* Get Cr0 */
mov edx, [ecx+FN_CR0_NPX_STATE]
jz DoneLoad
/* Save the FX State */
fxsave [ecx]
/* Check if we also have to save it in the parameter */
mov ecx, [esp+20]
jecxz NoSave
DoneLoad:
/* Save the Fn state in the parameter we got */
fnsave [ecx]
fwait
NoSave:
/* Clear eax */
xor eax, eax
/* Add NPX State */
or ebx, NPX_STATE_NOT_LOADED
/* Clear the NPX thread */
mov [edi+KPCR_NPX_THREAD], eax
/* Add saved CR0 into NPX State, and set it */
or ebx, edx
mov cr0, ebx
/* Re-enable interrupts and return */
Return:
popf
pop ebx
pop edi
pop esi
ret 4
.endfunc
/*++
* KiSwapContextInternal
*
@ -736,64 +507,6 @@ NoNextThread:
#endif
.endfunc
.globl _KiSwapProcess@8
.func KiSwapProcess@8
_KiSwapProcess@8:
/* Get process pointers */
mov edx, [esp+4]
mov eax, [esp+8]
#ifdef CONFIG_SMP
/* Update active processors */
mov ecx, fs:[KPCR_SET_MEMBER]
lock xor [edx+KPROCESS_ACTIVE_PROCESSORS], ecx
lock xor [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
/* Sanity check */
#if DBG
test [edx+KPROCESS_ACTIVE_PROCESSORS], ecx
jz WrongCpu1
test [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
jnz WrongCpu2
#endif
#endif
/* Check if their LDTs changed */
mov ecx, [edx+KPROCESS_LDT_DESCRIPTOR0]
or ecx, [eax+KPROCESS_LDT_DESCRIPTOR0]
jnz NewLdt
/* Update CR3 */
mov eax, [edx+KPROCESS_DIRECTORY_TABLE_BASE]
mov cr3, eax
/* Get the KTSS */
mov ecx, fs:[KPCR_TSS]
/* Clear GS on process swap */
xor eax, eax
mov gs, ax
/* Update IOPM offset */
mov ax, [edx+KPROCESS_IOPM_OFFSET]
mov [ecx+KTSS_IOMAPBASE], ax
/* Return */
ret 8
NewLdt:
/* FIXME: TODO */
int 3
#if DBG
WrongCpu1:
int 3
WrongCpu2:
int 3
#endif
.endfunc
.globl _Ki386SetupAndExitToV86Mode@4
.func Ki386SetupAndExitToV86Mode@4
_Ki386SetupAndExitToV86Mode@4:

View file

@ -40,6 +40,7 @@
<directory name="i386">
<file>abios.c</file>
<file>cpu.c</file>
<file>context.c</file>
<file>ctxswitch.S</file>
<file>exp.c</file>
<file>irqobj.c</file>