Author: sir_richard
Date: Wed Jan 20 05:05:08 2010
New Revision: 45156
URL:
http://svn.reactos.org/svn/reactos?rev=45156&view=rev
Log:
[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.
Added:
trunk/reactos/ntoskrnl/ke/i386/context.c (with props)
Modified:
trunk/reactos/ntoskrnl/include/internal/i386/intrin_i.h
trunk/reactos/ntoskrnl/ke/i386/cpu.c
trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild
Modified: trunk/reactos/ntoskrnl/include/internal/i386/intrin_i.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/intrin_i.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/intrin_i.h [iso-8859-1] Wed Jan 20
05:05:08 2010
@@ -13,6 +13,28 @@
: "=m" (*X) \
: /* 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
Added: trunk/reactos/ntoskrnl/ke/i386/context.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/context.c…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/context.c (added)
+++ trunk/reactos/ntoskrnl/ke/i386/context.c [iso-8859-1] Wed Jan 20 05:05:08 2010
@@ -1,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;
+}
+
Propchange: trunk/reactos/ntoskrnl/ke/i386/context.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/ntoskrnl/ke/i386/cpu.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/cpu.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/cpu.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/cpu.c [iso-8859-1] Wed Jan 20 05:05:08 2010
@@ -944,6 +944,155 @@
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 **********************************************************/
/*
Modified: trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/ctxswitch…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/ctxswitch.S [iso-8859-1] Wed Jan 20 05:05:08 2010
@@ -17,236 +17,7 @@
#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 @@
#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:
Modified: trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ntoskrnl-generic.…
==============================================================================
--- trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ntoskrnl-generic.rbuild [iso-8859-1] Wed Jan 20 05:05:08 2010
@@ -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>