📄 cpu.c
字号:
}
} while (--CacheRequests);
}
break;
case CPU_AMD:
/* Check if we support CPUID 0x80000006 */
CPUID(Data, 0x80000000);
if (Data[0] >= 6)
{
/* Get 2nd level cache and tlb size */
CPUID(Data, 0x80000006);
/* Set the L2 Cache Size */
Pcr->SecondLevelCacheSize = (Data[2] & 0xFFFF0000) >> 6;
}
break;
}
}
VOID
NTAPI
KiSetCR0Bits(VOID)
{
ULONG Cr0;
/* Save current CR0 */
Cr0 = __readcr0();
/* If this is a 486, enable Write-Protection */
if (KeGetCurrentPrcb()->CpuType > 3) Cr0 |= CR0_WP;
/* Set new Cr0 */
__writecr0(Cr0);
}
VOID
NTAPI
KiInitializeTSS2(IN PKTSS Tss,
IN PKGDTENTRY TssEntry OPTIONAL)
{
PUCHAR p;
/* Make sure the GDT Entry is valid */
if (TssEntry)
{
/* Set the Limit */
TssEntry->LimitLow = sizeof(KTSS) - 1;
TssEntry->HighWord.Bits.LimitHi = 0;
}
/* Now clear the I/O Map */
RtlFillMemory(Tss->IoMaps[0].IoMap, 8096, -1);
/* Initialize Interrupt Direction Maps */
p = (PUCHAR)(Tss->IoMaps[0].DirectionMap);
RtlZeroMemory(p, 32);
/* Add DPMI support for interrupts */
p[0] = 4;
p[3] = 0x18;
p[4] = 0x18;
/* Initialize the default Interrupt Direction Map */
p = Tss->IntDirectionMap;
RtlZeroMemory(Tss->IntDirectionMap, 32);
/* Add DPMI support */
p[0] = 4;
p[3] = 0x18;
p[4] = 0x18;
}
VOID
NTAPI
KiInitializeTSS(IN PKTSS Tss)
{
/* Set an invalid map base */
Tss->IoMapBase = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
/* Disable traps during Task Switches */
Tss->Flags = 0;
/* Set LDT and Ring 0 SS */
Tss->LDT = 0;
Tss->Ss0 = KGDT_R0_DATA;
}
VOID
FASTCALL
Ki386InitializeTss(IN PKTSS Tss,
IN PKIDTENTRY Idt,
IN PKGDTENTRY Gdt)
{
PKGDTENTRY TssEntry, TaskGateEntry;
/* Initialize the boot TSS. */
TssEntry = &Gdt[KGDT_TSS / sizeof(KGDTENTRY)];
TssEntry->HighWord.Bits.Type = I386_TSS;
TssEntry->HighWord.Bits.Pres = 1;
TssEntry->HighWord.Bits.Dpl = 0;
KiInitializeTSS2(Tss, TssEntry);
KiInitializeTSS(Tss);
/* Load the task register */
Ke386SetTr(KGDT_TSS);
/* Setup the Task Gate for Double Fault Traps */
TaskGateEntry = (PKGDTENTRY)&Idt[8];
TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE;
TaskGateEntry->HighWord.Bits.Pres = 1;
TaskGateEntry->HighWord.Bits.Dpl = 0;
((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_DF_TSS;
/* Initialize the TSS used for handling double faults. */
Tss = (PKTSS)KiDoubleFaultTSS;
KiInitializeTSS(Tss);
Tss->CR3 = __readcr3();
Tss->Esp0 = PtrToUlong(KiDoubleFaultStack);
Tss->Eip = PtrToUlong(KiTrap8);
Tss->Cs = KGDT_R0_CODE;
Tss->Fs = KGDT_R0_PCR;
Tss->Ss = Ke386GetSs();
Tss->Es = KGDT_R3_DATA | RPL_MASK;
Tss->Ds = KGDT_R3_DATA | RPL_MASK;
/* Setup the Double Trap TSS entry in the GDT */
TssEntry = &Gdt[KGDT_DF_TSS / sizeof(KGDTENTRY)];
TssEntry->HighWord.Bits.Type = I386_TSS;
TssEntry->HighWord.Bits.Pres = 1;
TssEntry->HighWord.Bits.Dpl = 0;
TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF);
TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16);
TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
TssEntry->LimitLow = KTSS_IO_MAPS;
/* Now setup the NMI Task Gate */
TaskGateEntry = (PKGDTENTRY)&Idt[2];
TaskGateEntry->HighWord.Bits.Type = I386_TASK_GATE;
TaskGateEntry->HighWord.Bits.Pres = 1;
TaskGateEntry->HighWord.Bits.Dpl = 0;
((PKIDTENTRY)TaskGateEntry)->Selector = KGDT_NMI_TSS;
/* Initialize the actual TSS */
Tss = (PKTSS)KiNMITSS;
KiInitializeTSS(Tss);
Tss->CR3 = __readcr3();
Tss->Esp0 = PtrToUlong(KiDoubleFaultStack);
Tss->Eip = PtrToUlong(KiTrap2);
Tss->Cs = KGDT_R0_CODE;
Tss->Fs = KGDT_R0_PCR;
Tss->Ss = Ke386GetSs();
Tss->Es = KGDT_R3_DATA | RPL_MASK;
Tss->Ds = KGDT_R3_DATA | RPL_MASK;
/* And its associated TSS Entry */
TssEntry = &Gdt[KGDT_NMI_TSS / sizeof(KGDTENTRY)];
TssEntry->HighWord.Bits.Type = I386_TSS;
TssEntry->HighWord.Bits.Pres = 1;
TssEntry->HighWord.Bits.Dpl = 0;
TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF);
TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16);
TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
TssEntry->LimitLow = KTSS_IO_MAPS;
}
VOID
NTAPI
KeFlushCurrentTb(VOID)
{
/* Flush the TLB by resetting CR3 */
__writecr3(__readcr3());
}
VOID
NTAPI
KiRestoreProcessorControlState(PKPROCESSOR_STATE ProcessorState)
{
/* Restore the CR registers */
__writecr0(ProcessorState->SpecialRegisters.Cr0);
Ke386SetCr2(ProcessorState->SpecialRegisters.Cr2);
__writecr3(ProcessorState->SpecialRegisters.Cr3);
if (KeFeatureBits & KF_CR4) __writecr4(ProcessorState->SpecialRegisters.Cr4);
//
// Restore the DR registers
//
Ke386SetDr0(ProcessorState->SpecialRegisters.KernelDr0);
Ke386SetDr1(ProcessorState->SpecialRegisters.KernelDr1);
Ke386SetDr2(ProcessorState->SpecialRegisters.KernelDr2);
Ke386SetDr3(ProcessorState->SpecialRegisters.KernelDr3);
Ke386SetDr6(ProcessorState->SpecialRegisters.KernelDr6);
Ke386SetDr7(ProcessorState->SpecialRegisters.KernelDr7);
//
// Restore GDT, IDT, LDT and TSS
//
Ke386SetGlobalDescriptorTable(*(PKDESCRIPTOR)&ProcessorState->SpecialRegisters.Gdtr.Limit);
Ke386SetInterruptDescriptorTable(*(PKDESCRIPTOR)&ProcessorState->SpecialRegisters.Idtr.Limit);
Ke386SetTr(ProcessorState->SpecialRegisters.Tr);
Ke386SetLocalDescriptorTable(ProcessorState->SpecialRegisters.Ldtr);
}
VOID
NTAPI
KiSaveProcessorControlState(OUT PKPROCESSOR_STATE ProcessorState)
{
/* Save the CR registers */
ProcessorState->SpecialRegisters.Cr0 = __readcr0();
ProcessorState->SpecialRegisters.Cr2 = __readcr2();
ProcessorState->SpecialRegisters.Cr3 = __readcr3();
ProcessorState->SpecialRegisters.Cr4 = (KeFeatureBits & KF_CR4) ?
__readcr4() : 0;
/* Save the DR registers */
ProcessorState->SpecialRegisters.KernelDr0 = Ke386GetDr0();
ProcessorState->SpecialRegisters.KernelDr1 = Ke386GetDr1();
ProcessorState->SpecialRegisters.KernelDr2 = Ke386GetDr2();
ProcessorState->SpecialRegisters.KernelDr3 = Ke386GetDr3();
ProcessorState->SpecialRegisters.KernelDr6 = Ke386GetDr6();
ProcessorState->SpecialRegisters.KernelDr7 = Ke386GetDr7();
Ke386SetDr7(0);
/* Save GDT, IDT, LDT and TSS */
Ke386GetGlobalDescriptorTable(*(PKDESCRIPTOR)&ProcessorState->SpecialRegisters.Gdtr.Limit);
Ke386GetInterruptDescriptorTable(*(PKDESCRIPTOR)&ProcessorState->SpecialRegisters.Idtr.Limit);
Ke386GetTr(ProcessorState->SpecialRegisters.Tr);
Ke386GetLocalDescriptorTable(ProcessorState->SpecialRegisters.Ldtr);
}
VOID
NTAPI
KiInitializeMachineType(VOID)
{
/* Set the Machine Type we got from NTLDR */
KeI386MachineType = KeLoaderBlock->u.I386.MachineType & 0x000FF;
}
ULONG_PTR
NTAPI
KiLoadFastSyscallMachineSpecificRegisters(IN ULONG_PTR Context)
{
/* Set CS and ESP */
Ke386Wrmsr(0x174, KGDT_R0_CODE, 0);
Ke386Wrmsr(0x175, (ULONG)KeGetCurrentPrcb()->DpcStack, 0);
/* Set LSTAR */
Ke386Wrmsr(0x176, (ULONG)KiFastCallEntry, 0);
return 0;
}
VOID
NTAPI
KiRestoreFastSyscallReturnState(VOID)
{
/* FIXME: NT has support for SYSCALL, IA64-SYSENTER, etc. */
/* Check if the CPU Supports fast system call */
if (KeFeatureBits & KF_FAST_SYSCALL)
{
/* Do an IPI to enable it */
KeIpiGenericCall(KiLoadFastSyscallMachineSpecificRegisters, 0);
}
}
ULONG_PTR
NTAPI
Ki386EnableDE(IN ULONG_PTR Context)
{
/* Enable DE */
__writecr4(__readcr4() | CR4_DE);
return 0;
}
ULONG_PTR
NTAPI
Ki386EnableFxsr(IN ULONG_PTR Context)
{
/* Enable FXSR */
__writecr4(__readcr4() | CR4_FXSR);
return 0;
}
ULONG_PTR
NTAPI
Ki386EnableXMMIExceptions(IN ULONG_PTR Context)
{
#if 0 // needs kitrap13
PKIDTENTRY IdtEntry;
/* Get the IDT Entry for Interrupt 19 */
IdtEntry = ((PKIPCR)KeGetPcr())->IDT[19];
/* Set it up */
IdtEntry->Selector = KGDT_R0_CODE;
IdtEntry->Offset = (KiTrap13 & 0xFFFF);
IdtEntry->ExtendedOffset = (KiTrap13 >> 16) & 0xFFFF;
((PKIDT_ACCESS)&IdtEntry->Access)->Dpl = 0;
((PKIDT_ACCESS)&IdtEntry->Access)->Present = 1;
((PKIDT_ACCESS)&IdtEntry->Access)->SegmentType = I386_INTERRUPT_GATE;
#endif
/* Enable XMMI exceptions */
__writecr4(__readcr4() | CR4_XMMEXCPT);
return 0;
}
VOID
NTAPI
KiI386PentiumLockErrataFixup(VOID)
{
KDESCRIPTOR IdtDescriptor = {0};
PKIDTENTRY NewIdt, NewIdt2;
/* Allocate memory for a new IDT */
NewIdt = ExAllocatePool(NonPagedPool, 2 * PAGE_SIZE);
/* Put everything after the first 7 entries on a new page */
NewIdt2 = (PVOID)((ULONG_PTR)NewIdt + PAGE_SIZE - (7 * sizeof(KIDTENTRY)));
/* Disable interrupts */
_disable();
/* Get the current IDT and copy it */
Ke386GetInterruptDescriptorTable(*(PKDESCRIPTOR)&IdtDescriptor.Limit);
RtlCopyMemory(NewIdt2,
(PVOID)IdtDescriptor.Base,
IdtDescriptor.Limit + 1);
IdtDescriptor.Base = (ULONG)NewIdt2;
/* Set the new IDT */
Ke386SetInterruptDescriptorTable(*(PKDESCRIPTOR)&IdtDescriptor.Limit);
((PKIPCR)KeGetPcr())->IDT = NewIdt2;
/* Restore interrupts */
_enable();
/* Set the first 7 entries as read-only to produce a fault */
MmSetPageProtect(NULL, NewIdt, PAGE_READONLY);
}
BOOLEAN
NTAPI
KeFreezeExecution(IN PKTRAP_FRAME TrapFrame,
IN PKEXCEPTION_FRAME ExceptionFrame)
{
ULONG Flags = 0;
/* Disable interrupts and get previous state */
Ke386SaveFlags(Flags);
//Flags = __getcallerseflags();
_disable();
/* Save freeze flag */
KiFreezeFlag = 4;
/* Save the old IRQL */
KiOldIrql = KeGetCurrentIrql();
/* Return whether interrupts were enabled */
return (Flags & EFLAGS_INTERRUPT_MASK) ? TRUE: FALSE;
}
VOID
NTAPI
KeThawExecution(IN BOOLEAN Enable)
{
/* Cleanup CPU caches */
KeFlushCurrentTb();
/* Re-enable interrupts */
if (Enable) _enable();
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save)
{
PFNSAVE_FORMAT FpState;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
DPRINT1("%s is not really implemented\n", __FUNCTION__);
/* check if we are doing software emulation */
if (!KeI386NpxPresent) return STATUS_ILLEGAL_FLOAT_CONTEXT;
FpState = ExAllocatePool(NonPagedPool, sizeof (FNSAVE_FORMAT));
if (!FpState) return STATUS_INSUFFICIENT_RESOURCES;
*((PVOID *) Save) = FpState;
#ifdef __GNUC__
asm volatile("fnsave %0\n\t" : "=m" (*FpState));
#else
__asm
{
fnsave [FpState]
};
#endif
KeGetCurrentThread()->DispatcherHeader.NpxIrql = KeGetCurrentIrql();
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save)
{
PFNSAVE_FORMAT FpState = *((PVOID *) Save);
ASSERT(KeGetCurrentThread()->DispatcherHeader.NpxIrql == KeGetCurrentIrql());
DPRINT1("%s is not really implemented\n", __FUNCTION__);
#ifdef __GNUC__
asm volatile("fnclex\n\t");
asm volatile("frstor %0\n\t" : "=m" (*FpState));
#else
__asm
{
fnclex
frstor [FpState]
};
#endif
ExFreePool(FpState);
return STATUS_SUCCESS;
}
/*
* @implemented
*/
ULONG
NTAPI
KeGetRecommendedSharedDataAlignment(VOID)
{
/* Return the global variable */
return KeLargestCacheLine;
}
/*
* @implemented
*/
VOID
NTAPI
KeFlushEntireTb(IN BOOLEAN Invalid,
IN BOOLEAN AllProcessors)
{
KIRQL OldIrql;
/* Raise the IRQL for the TB Flush */
OldIrql = KeRaiseIrqlToSynchLevel();
#ifdef CONFIG_SMP
/* FIXME: Support IPI Flush */
#error Not yet implemented!
#endif
/* Flush the TB for the Current CPU */
KeFlushCurrentTb();
/* Return to Original IRQL */
KeLowerIrql(OldIrql);
}
/*
* @implemented
*/
VOID
NTAPI
KeSetDmaIoCoherency(IN ULONG Coherency)
{
/* Save the coherency globally */
KiDmaIoCoherency = Coherency;
}
/*
* @implemented
*/
KAFFINITY
NTAPI
KeQueryActiveProcessors(VOID)
{
PAGED_CODE();
/* Simply return the number of active processors */
return KeActiveProcessors;
}
/*
* @implemented
*/
VOID
__cdecl
KeSaveStateForHibernate(IN PKPROCESSOR_STATE State)
{
/* Capture the context */
RtlCaptureContext(&State->ContextFrame);
/* Capture the control state */
KiSaveProcessorControlState(State);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -