mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 17:34:57 +00:00
[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:
parent
04a018d92b
commit
01d2a95033
5 changed files with 223 additions and 287 deletions
|
@ -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)
|
||||
|
|
51
reactos/ntoskrnl/ke/i386/context.c
Normal file
51
reactos/ntoskrnl/ke/i386/context.c
Normal 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;
|
||||
}
|
||||
|
|
@ -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 **********************************************************/
|
||||
|
||||
/*
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue