- Fix prototype/definition of HalCalibratePerformanceCounter and properly implement it.

- Implement KeStallExecutionProcessor in its own assembly file isntead of using inlined GCC assembly, and align the loop to 16 bytes for more streamlined execution speed.
- Mask out clock interrupt during Phase 0 and Initialize clock interrupt on HAL Phase 1. This enables the HAL clock interrupt which was already written.
- Make the clock interrupt use HalpCurrentTimeIncrement instead of hardcoding a value.
- Re-implement HalpInitializeClock to allow for dynamic increments from 1ms to 15ms with appropriate rollovers and to call KeSetTimeIncrement to update timer values with the kernel.
- Implement HalSetTimeIncrement to allow changing the clock ms increment (but this isn't yet respected).
- Remove system/runtime update routines from the deprecated IRQ implementation and use the newer assembly ones already written, since we're now using the HAL clock interrupt. Remove other unused code.
- Fix more bugs in new hal IRQ implementation (that still isn't used yet due to regressions) and implement HalClearSoftwareInterrupt.

svn path=/trunk/; revision=24908
This commit is contained in:
Alex Ionescu 2006-11-28 08:11:14 +00:00
parent 7df718a150
commit 088b3cd98e
12 changed files with 341 additions and 450 deletions

View file

@ -173,7 +173,8 @@ HalBeginSystemInterrupt (KIRQL Irql,
VOID
NTAPI
HalCalibratePerformanceCounter(
ULONG Count)
volatile LONG *Count,
ULONGLONG NewCount)
{
UNIMPLEMENTED;
}

View file

@ -30,7 +30,7 @@ HalAllocateCommonBuffer@16
HalAllocateCrashDumpRegisters@8
HalAssignSlotResources@32
HalBeginSystemInterrupt@12
HalCalibratePerformanceCounter@4
HalCalibratePerformanceCounter@12
HalDisableSystemInterrupt@8
HalDisplayString@4
HalEnableSystemInterrupt@12

View file

@ -17,6 +17,7 @@
<file>sysbus.c</file>
<file>sysinfo.c</file>
<file>timer.c</file>
<file>systimer.S</file>
<pch>../include/hal.h</pch>
</module>
<module name="hal_generic_up" type="objectlibrary">
@ -28,7 +29,6 @@
<file>irql.c</file>
<file>processor.c</file>
<file>spinlock.c</file>
<file>systimer.S</file>
</module>
<module name="hal_generic_pc" type="objectlibrary">
<include base="hal_generic_pc">../include</include>

View file

@ -113,7 +113,7 @@ HalInitSystem(IN ULONG BootPhase,
HalpInitNonBusHandler();
/* Initialize the clock interrupt */
//HalpInitPhase1();
HalpInitPhase1();
/* Initialize DMA. NT does this in Phase 0 */
HalpInitDma();

View file

@ -67,18 +67,21 @@ KiI8259MaskTable:
.long 0xFFFFFFFB /* IRQL 31 */
HalpSysIntHandler:
.rept 8
.rept 7
.long GenericIRQ /* IRQ 0-7 */
.endr
.long IRQ7 /* IRQ 7 */
.rept 8
.rept 7
.long GenericIRQ /* IRQ 8-15 */
.endr
.long IRQ15 /* IRQ 15 */
.rept 20
.long GenericIRQ /* IRQ 16-35 */
.endr
#if DBG
.rept 172
.long InvalidIRQ /* IRQ 36-207 */
#endif
.endr
SoftIntByteTable:
@ -147,9 +150,22 @@ InitLoop:
ret
.endfunc
.globl @HalClearSoftwareInterrupt@4
.func @HalClearSoftwareInterrupt@4, @HalClearSoftwareInterrupt@4
@HalClearSoftwareInterrupt@4:
/* Get IRR mask */
mov eax, 1
shl eax, cl
not eax
/* Set IRR */
and PCR[KPCR_IRR], eax
ret
.endfunc
.globl @HalRequestSoftwareInterrupt@4
.func @HalRequestSoftwareInterrupt@4
_@HalRequestSoftwareInterrupt@4:
.func @HalRequestSoftwareInterrupt@4, @HalRequestSoftwareInterrupt@4
@HalRequestSoftwareInterrupt@4:
/* Get IRR mask */
@ -161,11 +177,11 @@ _@HalRequestSoftwareInterrupt@4:
cli
/* Set IRR and get IRQL */
or [fs:KPCR_IRR], eax
mov ecx, [fs:KPCR_IRQL]
or PCR[KPCR_IRR], eax
mov ecx, PCR[KPCR_IRQL]
/* Get software IRR mask */
mov eax, [fs:KPCR_IRR]
mov eax, PCR[KPCR_IRR]
and eax, 3
/* Get highest pending software interrupt and check if it's higher */
@ -196,7 +212,7 @@ _HalDisableSystemInterrupt@8:
mov edx, 1
shl edx, cl
cli
or [fs:KPCR_IDR], edx
or PCR[KPCR_IDR], edx
/* Get the current mask */
xor eax, eax
@ -263,12 +279,12 @@ AfterMask:
shl eax, cl
not eax
cli
and [fs:KPCR_IDR], eax
and PCR[KPCR_IDR], eax
/* Get the current IRQL and mask the IRQs in the PIC */
mov eax, [fs:KPCR_IRQL]
movzx eax, byte ptr PCR[KPCR_IRQL]
mov eax, KiI8259MaskTable[eax*4]
or eax, [fs:KPCR_IDR]
or eax, PCR[KPCR_IDR]
out 0x21, al
shr eax, 8
out 0xA1, al
@ -281,7 +297,9 @@ AfterMask:
Invalid:
/* Fail, invalid IRQ */
#if DBG
int 3
#endif
xor eax, eax
ret 12
.endfunc
@ -291,7 +309,7 @@ Invalid:
_HalBeginSystemInterrupt@12:
/* Convert to IRQ and call the handler */
mov edx, [esp+8]
movzx edx, byte ptr [esp+8]
sub edx, PRIMARY_VECTOR_BASE
jmp HalpSysIntHandler[edx*4]
@ -326,22 +344,22 @@ IRQ7:
GenericIRQ:
/* Return the current IRQL */
mov eax, [esp+12]
mov ecx, [fs:KPCR_IRQL]
movzx ecx, byte ptr PCR[KPCR_IRQL]
mov [eax], cl
/* Set the new IRQL */
movzx eax, byte ptr [esp+4]
mov [fs:KPCR_IRQL], eax
mov PCR[KPCR_IRQL], al
/* Set IRQ mask in the PIC */
mov eax, KiI8259MaskTable[eax*4]
or eax, [fs:KPCR_IDR]
or eax, PCR[KPCR_IDR]
out 0x21, al
shr eax, 8
out 0xA1, al
/* Check to which PIC the EOI was sent */
mov eax, ebx
mov eax, edx
cmp eax, 8
jnb Pic1
@ -363,11 +381,13 @@ DoneBegin:
sti
mov eax, 1
ret 12
#if DBG
InvalidIRQ:
/* Dismiss it */
mov eax, 0
ret 12
#endif
.endfunc
.globl _HalEndSystemInterrupt@8
@ -376,12 +396,12 @@ _HalEndSystemInterrupt@8:
/* Get the IRQL and check if it's a software interrupt */
movzx ecx, byte ptr [esp+4]
cmp dword ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
cmp byte ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
jbe SkipMask2
/* Hardware interrupt, mask the appropriate IRQs in the PIC */
mov eax, KiI8259MaskTable[ecx*4]
or eax, [fs:KPCR_IDR]
or eax, PCR[KPCR_IDR]
out 0x21, al
shr eax, 8
out 0xA1, al
@ -389,8 +409,8 @@ _HalEndSystemInterrupt@8:
SkipMask2:
/* Set IRQL and check if there are pending software interrupts */
mov [fs:KPCR_IRQL], ecx
mov eax, [fs:KPCR_IRR]
mov PCR[KPCR_IRQL], cl
mov eax, PCR[KPCR_IRR]
mov al, SoftIntByteTable[eax]
cmp al, cl
ja DoCall
@ -411,15 +431,21 @@ _@KfLowerIrql@4:
/* Save flags since we'll disable interrupts */
pushf
/* Disable interrupts and check if IRQL is below DISPATCH_LEVEL */
/* Validate IRQL */
movzx ecx, cl
cmp dword ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
#if DBG
cmp cl, PCR[KPCR_IRQL]
ja InvalidIrql
#endif
/* Disable interrupts and check if IRQL is below DISPATCH_LEVEL */
cmp byte ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
cli
jbe SkipMask
/* Clear interrupt masks since there's a pending hardware interrupt */
mov eax, KiI8259MaskTable[ecx*4]
or eax, [fs:KPCR_IDR]
or eax, PCR[KPCR_IDR]
out 0x21, al
shr eax, 8
out 0xA1, al
@ -427,8 +453,8 @@ _@KfLowerIrql@4:
SkipMask:
/* Set the new IRQL and check if there's a pending software interrupt */
mov [fs:KPCR_IRQL], ecx
mov eax, [fs:KPCR_IRR]
mov PCR[KPCR_IRQL], cl
mov eax, PCR[KPCR_IRR]
mov al, SoftIntByteTable[eax]
cmp al, cl
ja DoCall3
@ -436,6 +462,22 @@ SkipMask:
/* Restore interrupts and return */
popf
ret
#if DBG
InvalidIrql:
/* Set HIGH_LEVEL */
movzx eax, byte ptr PCR[KPCR_IRQL]
mov byte ptr PCR[KPCR_IRQL], HIGH_LEVEL
/* Bugcheck the system */
push 3
push 0
push ecx
push eax
push IRQL_NOT_LESS_OR_EQUAL
call _KeBugCheckEx@20
#endif
DoCall3:
/* There is, call it */
call SoftIntHandlerTable[eax*4]
@ -450,10 +492,19 @@ DoCall3:
_@KfRaiseIrql@4:
@KfRaiseIrql@4:
/* Get the IRQL and check if it's Software level only */
mov eax, [fs:KPCR_IRQL]
/* Get the IRQL */
xor eax, eax
mov al, PCR[KPCR_IRQL]
movzx ecx, cl
cmp ecx, DISPATCH_LEVEL
#if DBG
/* Validate it */
cmp eax, ecx
ja InvalidKfRaise
#endif
/* Check if it's in the software level */
cmp cl, DISPATCH_LEVEL
jbe SetIrql
/* Save the current IRQL */
@ -464,11 +515,11 @@ _@KfRaiseIrql@4:
cli
/* Set the new IRQL */
mov [fs:KPCR_IRQL], cl
mov PCR[KPCR_IRQL], cl
/* Mask the interrupts in the PIC */
mov eax, KiI8259MaskTable[ecx*4]
or eax, [fs:KPCR_IDR]
or eax, PCR[KPCR_IDR]
out 0x21, al
shr eax, 8
out 0xA1, al
@ -481,8 +532,22 @@ _@KfRaiseIrql@4:
SetIrql:
/* Set the IRQL and return */
mov [fs:KPCR_IRQL], ecx
mov PCR[KPCR_IRQL], cl
ret
#if DBG
InvalidKfRaise:
/* Set to passive */
mov byte ptr PCR[KPCR_IRQL], PASSIVE_LEVEL
/* Bugcheck the system */
push 9
push 0
push ecx
push eax
push IRQL_NOT_GREATER_OR_EQUAL
call _KeBugCheckEx@20
#endif
.endfunc
.globl _KeGetCurrentIrql@0
@ -490,7 +555,7 @@ SetIrql:
_KeGetCurrentIrql@0:
/* Return the IRQL */
mov eax, [fs:KPCR_IRQL]
movzx eax, byte ptr PCR[KPCR_IRQL]
ret
.endfunc
@ -499,11 +564,29 @@ _KeGetCurrentIrql@0:
_KeRaiseIrqlToDpcLevel@0:
/* Get the current IRQL */
mov eax, [fs:KPCR_IRQL]
xor eax, eax
mov al, PCR[KPCR_IRQL]
/* Set DISPATCH_LEVEL */
mov dword ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
mov byte ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
#if DBG
/* Make sure we were not higher then dispatch */
cmp al, DISPATCH_LEVEL
ja InvalidRaise
#endif
ret
#if DBG
InvalidRaise:
/* Bugcheck the system */
push 1
push 0
push DISPATCH_LEVEL
push eax
push IRQL_NOT_GREATER_OR_EQUAL
call _KeBugCheckEx@20
#endif
.endfunc
.globl _KeRaiseIrqlToSynchLevel@0
@ -516,16 +599,35 @@ _KeRaiseIrqlToSynchLevel@0:
/* Mask out interrupts */
mov eax, KiI8259MaskTable[DISPATCH_LEVEL*4]
or eax, [fs:KPCR_IDR]
or eax, PCR[KPCR_IDR]
out 0x21, al
shr eax, 8
out 0xA1, al
/* Return the old IRQL, enable interrupts and set to DISPATCH */
mov eax, [fs:KPCR_IRQL]
mov dword ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
mov al, PCR[KPCR_IRQL]
mov byte ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
popf
#if DBG
/* Validate raise */
cmp al, DISPATCH_LEVEL
ja InvalidSyRaise
#endif
/* Return */
ret
#if DBG
InvalidSyRaise:
/* Bugcheck the system */
push 2
push 0
push DISPATCH_LEVEL
push eax
push IRQL_NOT_GREATER_OR_EQUAL
call _KeBugCheckEx@20
#endif
.endfunc
.globl _HalpApcInterrupt
@ -547,9 +649,9 @@ _HalpApcInterrupt:
_HalpApcInterrupt2ndEntry:
/* Save current IRQL and set to APC level */
push [fs:KPCR_IRQL]
mov dword ptr [fs:KPCR_IRQL], APC_LEVEL
and dword ptr [fs:KPCR_IRR], ~(1 << APC_LEVEL)
push PCR[KPCR_IRQL]
mov dword ptr PCR[KPCR_IRQL], APC_LEVEL
and dword ptr PCR[KPCR_IRR], ~(1 << APC_LEVEL)
/* Enable interrupts and check if we came from User/V86 mode */
sti
@ -594,9 +696,9 @@ _HalpDispatchInterrupt:
_HalpDispatchInterrupt2ndEntry:
/* Save current IRQL and set to DPC level */
push [fs:KPCR_IRQL]
mov dword ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
and dword ptr [fs:KPCR_IRR], ~(1 << DISPATCH_LEVEL)
push PCR[KPCR_IRQL]
mov dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
and dword ptr PCR[KPCR_IRR], ~(1 << DISPATCH_LEVEL)
/* Enable interrupts and let the kernel handle this */
sti
@ -614,20 +716,20 @@ _HalpEndSoftwareInterrupt@4:
/* Get the IRQL and check if we're in the software region */
movzx ecx, byte ptr [esp+4]
cmp dword ptr [fs:KPCR_IRQL], DISPATCH_LEVEL
cmp dword ptr PCR[KPCR_IRQL], DISPATCH_LEVEL
jbe SoftwareInt
/* Set the right mask in the PIC for the hardware IRQ */
mov eax, KiI8259MaskTable[ecx*4]
or eax, [fs:KPCR_IDR]
or eax, PCR[KPCR_IDR]
out 0x21, al
shr eax, 8
out 0xA1, al
SoftwareInt:
/* Check if there are pending software interrupts */
mov [fs:KPCR_IRQL], ecx
mov eax, [fs:KPCR_IRR]
mov PCR[KPCR_IRQL], ecx
mov eax, PCR[KPCR_IRR]
mov al, SoftIntByteTable[eax]
cmp al, cl
ja DoCall2

View file

@ -96,8 +96,8 @@ VOID NTAPI HalpInitPICs(VOID)
WRITE_PORT_UCHAR((PUCHAR)0x21, 0x1);
WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x1);
/* Enable interrupts */
WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master);
WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave);
WRITE_PORT_UCHAR((PUCHAR)0x21, 0xFF);
WRITE_PORT_UCHAR((PUCHAR)0xa1, 0xFF);
/* We can now enable interrupts */
_enable();
@ -305,7 +305,7 @@ KeRaiseIrqlToDpcLevel (VOID)
KIRQL STDCALL
KeRaiseIrqlToSynchLevel (VOID)
{
return KfRaiseIrql (CLOCK2_LEVEL);
return KfRaiseIrql (DISPATCH_LEVEL);
}

View file

@ -10,9 +10,41 @@
#include <asm.h>
#include <internal/i386/asmmacro.S>
.intel_syntax noprefix
.extern _HalpCurrentTimeIncrement
/* FUNCTIONS *****************************************************************/
.globl _KeStallExecutionProcessor@4
.func KeStallExecutionProcessor@4
_KeStallExecutionProcessor@4:
/* Get the number of microseconds required */
mov ecx, [esp+4]
jecxz Done
/* Multiply by the stall factor */
mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
mul ecx
/* Align to 16 bytes */
.align 16
/* Jump to subtraction loop */
jmp SubtractLoop
/* Align to 16 bytes */
.align 16
/* Subtract one count */
SubtractLoop:
sub eax, 1
jnz SubtractLoop
Done:
/* Return */
ret 4
.endfunc
.globl _HalpClockInterrupt@0
.func HalpClockInterrupt@0
_HalpClockInterrupt@0:
@ -35,7 +67,8 @@ _HalpClockInterrupt@0:
jz Spurious
/* Do a tick */
mov eax, 100000
mov eax, _HalpCurrentTimeIncrement
xor ebx, ebx
jmp _KeUpdateSystemTime@0
Spurious:

View file

@ -38,127 +38,146 @@
/* GLOBALS ******************************************************************/
#define TMR_CTRL 0x43 /* I/O for control */
#define TMR_CNT0 0x40 /* I/O for counter 0 */
#define TMR_CNT1 0x41 /* I/O for counter 1 */
#define TMR_CNT2 0x42 /* I/O for counter 2 */
#define TMR_SC0 0 /* Select channel 0 */
#define TMR_SC1 0x40 /* Select channel 1 */
#define TMR_SC2 0x80 /* Select channel 2 */
#define TMR_LOW 0x10 /* RW low byte only */
#define TMR_HIGH 0x20 /* RW high byte only */
#define TMR_BOTH 0x30 /* RW both bytes */
#define TMR_MD0 0 /* Mode 0 */
#define TMR_MD1 0x2 /* Mode 1 */
#define TMR_MD2 0x4 /* Mode 2 */
#define TMR_MD3 0x6 /* Mode 3 */
#define TMR_MD4 0x8 /* Mode 4 */
#define TMR_MD5 0xA /* Mode 5 */
#define TMR_BCD 1 /* BCD mode */
#define TMR_LATCH 0 /* Latch command */
#define TMR_READ 0xF0 /* Read command */
#define TMR_CNT 0x20 /* CNT bit (Active low, subtract it) */
#define TMR_STAT 0x10 /* Status bit (Active low, subtract it) */
#define TMR_CH2 0x8 /* Channel 2 bit */
#define TMR_CH1 0x4 /* Channel 1 bit */
#define TMR_CH0 0x2 /* Channel 0 bit */
#define MILLISEC 10 /* Number of millisec between interrupts */
#define HZ (1000 / MILLISEC) /* Number of interrupts per second */
#define CLOCK_TICK_RATE 1193182 /* Clock frequency of the timer chip */
#define LATCH (CLOCK_TICK_RATE / HZ) /* Count to program into the timer chip */
#define PRECISION 8 /* Number of bits to calibrate for delay loop */
static BOOLEAN UdelayCalibrated = FALSE;
/* GLOBALS *******************************************************************/
/* FUNCTIONS **************************************************************/
BOOLEAN HalpClockSetMSRate;
ULONG HalpCurrentTimeIncrement;
ULONG HalpCurrentRollOver;
ULONG HalpNextMSRate = 14;
ULONG HalpLargestClockMS = 15;
/*
* NOTE: This function MUST NOT be optimized by the compiler!
* If it is, it obviously will not delay AT ALL, and the system
* will appear completely frozen at boot since
* HalpCalibrateStallExecution will never return.
* There are three options to stop optimization:
* 1. Use a volatile automatic variable. Making it delay quite a bit
* due to memory accesses, and keeping the code portable. However,
* as this involves memory access it depends on both the CPU cache,
* e.g. if the stack used is already in a cache line or not, and
* whether or not we're MP. If MP, another CPU could (probably would)
* also access RAM at the same time - making the delay imprecise.
* 2. Use compiler-specific #pragma's to disable optimization.
* 3. Use inline assembly, making it equally unportable as #2.
* For supported compilers we use inline assembler. For the others,
* portable plain C.
*/
DECLSPEC_NOINLINE VOID STDCALL
__KeStallExecutionProcessor(ULONG Loops)
LARGE_INTEGER HalpRolloverTable[15] =
{
if (!Loops)
{
return;
}
#if defined(__GNUC__)
__asm__ __volatile__ (
"mov %0, %%eax\n"
"ROSL1: dec %%eax\n"
"jnz ROSL1" : : "d" (Loops));
{{1197, 10032}},
{{2394, 20064}},
{{3591, 30096}},
{{4767, 39952}},
{{5964, 49984}},
{{7161, 60016}},
{{8358, 70048}},
{{9555, 80080}},
{{10731, 89936}},
{{11949, 100144}},
{{13125, 110000}},
{{14322, 120032}},
{{15519, 130064}},
{{16695, 139920}},
{{17892, 149952}}
};
#elif defined(_MSC_VER)
__asm mov eax, Loops
ROSL1:
__asm dec eax
__asm jnz ROSL1
#else
unsigned int target = Loops;
volatile unsigned int i;
for (i=0; i<target;i++);
#endif
}
/* PRIVATE FUNCTIONS *********************************************************/
VOID
STDCALL
KeStallExecutionProcessor(ULONG Microseconds)
NTAPI
HalpInitializeClock(VOID)
{
PKIPCR Pcr = (PKIPCR)KeGetPcr();
PKPRCB Prcb = KeGetCurrentPrcb();
ULONG Increment;
USHORT RollOver;
if (Pcr->PrcbData.FeatureBits & KF_RDTSC)
{
LARGE_INTEGER EndCount, CurrentCount;
EndCount.QuadPart = (LONGLONG)__rdtsc();
EndCount.QuadPart += Microseconds * (ULONGLONG)Pcr->PrcbData.MHz;
do
{
CurrentCount.QuadPart = (LONGLONG)__rdtsc();
}
while (CurrentCount.QuadPart < EndCount.QuadPart);
}
else
{
__KeStallExecutionProcessor((Pcr->StallScaleFactor*Microseconds)/1000);
}
/* Check the CPU Type */
if (Prcb->CpuType <= 4)
{
/* 486's or equal can't go higher then 10ms */
HalpLargestClockMS = 10;
HalpNextMSRate = 9;
}
/* Get increment and rollover for the largest time clock ms possible */
Increment= HalpRolloverTable[HalpLargestClockMS - 1].HighPart;
RollOver = (USHORT)HalpRolloverTable[HalpLargestClockMS - 1].LowPart;
/* Set the maximum and minimum increment with the kernel */
HalpCurrentTimeIncrement = Increment;
KeSetTimeIncrement(Increment, HalpRolloverTable[0].HighPart);
/* Disable interrupts */
_disable();
/* Set the rollover */
__outbyte(TIMER_CONTROL_PORT, TIMER_SC0 | TIMER_BOTH | TIMER_MD2);
__outbyte(TIMER_DATA_PORT0, RollOver & 0xFF);
__outbyte(TIMER_DATA_PORT0, RollOver >> 8);
/* Restore interrupts */
_enable();
/* Save rollover and return */
HalpCurrentRollOver = RollOver;
}
static ULONG Read8254Timer(VOID)
/* PUBLIC FUNCTIONS ***********************************************************/
/*
* @implemented
*/
VOID
NTAPI
HalCalibratePerformanceCounter(IN volatile PLONG Count,
IN ULONGLONG NewCount)
{
ULONG Count;
/* Disable interrupts */
_disable();
/* Disable interrupts */
_disable();
/* Do a decrement for this CPU */
//_InterlockedDecrement(Count);
InterlockedDecrement(Count);
WRITE_PORT_UCHAR((PUCHAR) TMR_CTRL, TMR_SC0 | TMR_LATCH);
Count = READ_PORT_UCHAR((PUCHAR) TMR_CNT0);
Count |= READ_PORT_UCHAR((PUCHAR) TMR_CNT0) << 8;
/* Wait for other CPUs */
while (*Count);
_enable();
return Count;
/* Bring interrupts back */
_enable();
}
/*
* @implemented
*/
ULONG
NTAPI
HalSetTimeIncrement(IN ULONG Increment)
{
/* Round increment to ms */
Increment /= 10000;
/* Normalize between our minimum (1 ms) and maximum (variable) setting */
if (Increment > HalpLargestClockMS) Increment = HalpLargestClockMS;
if (Increment < 0) Increment = 1;
/* Set the rate and tell HAL we want to change it */
HalpNextMSRate = Increment;
HalpClockSetMSRate = TRUE;
/* Return the increment */
return HalpRolloverTable[Increment - 1].HighPart;
}
/* STUFF *********************************************************************/
ULONG
FORCEINLINE
Read8254Timer(VOID)
{
ULONG Count;
/* Disable interrupts */
_disable();
/* Set the rollover */
__outbyte(TIMER_CONTROL_PORT, TIMER_SC0);
Count = __inbyte(TIMER_DATA_PORT0);
Count |= __inbyte(TIMER_DATA_PORT0) << 8;
/* Restore interrupts and return count*/
_enable();
return Count;
}
VOID WaitFor8254Wraparound(VOID)
{
@ -183,20 +202,6 @@ VOID WaitFor8254Wraparound(VOID)
while (Delta < 300);
}
VOID
NTAPI
HalpInitializeClock(VOID)
{
/* FIXME: Make dynamic */
/* Initialize the clock */
WRITE_PORT_UCHAR((PUCHAR) TMR_CTRL, TMR_SC0 | TMR_BOTH | TMR_MD2); /* binary, mode 2, LSB/MSB, ch 0 */
/* Set the increment */
WRITE_PORT_UCHAR((PUCHAR) TMR_CNT0, LATCH & 0xff); /* LSB */
WRITE_PORT_UCHAR((PUCHAR) TMR_CNT0, LATCH >> 8); /* MSB */
}
VOID HalpCalibrateStallExecution(VOID)
{
ULONG i;
@ -205,12 +210,6 @@ VOID HalpCalibrateStallExecution(VOID)
PKIPCR Pcr;
LARGE_INTEGER StartCount, EndCount;
if (UdelayCalibrated)
{
return;
}
UdelayCalibrated = TRUE;
Pcr = (PKIPCR)KeGetPcr();
if (Pcr->PrcbData.FeatureBits & KF_RDTSC)
@ -242,7 +241,7 @@ VOID HalpCalibrateStallExecution(VOID)
WaitFor8254Wraparound();
__KeStallExecutionProcessor(Pcr->StallScaleFactor); /* Do the delay */
KeStallExecutionProcessor(Pcr->StallScaleFactor); /* Do the delay */
CurCount = Read8254Timer();
}
@ -267,7 +266,7 @@ VOID HalpCalibrateStallExecution(VOID)
WaitFor8254Wraparound();
__KeStallExecutionProcessor(Pcr->StallScaleFactor); /* Do the delay */
KeStallExecutionProcessor(Pcr->StallScaleFactor); /* Do the delay */
CurCount = Read8254Timer();
if (CurCount <= LATCH / 2) /* If a tick has passed, turn the */
@ -295,19 +294,6 @@ VOID HalpCalibrateStallExecution(VOID)
#endif
}
VOID STDCALL
HalCalibratePerformanceCounter(ULONG Count)
{
/* Disable interrupts */
_disable();
__KeStallExecutionProcessor(Count);
_enable();
}
LARGE_INTEGER
STDCALL
KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFreq)
@ -360,12 +346,4 @@ KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFreq)
return Value;
}
ULONG
NTAPI
HalSetTimeIncrement(IN ULONG Increment)
{
/* FIXME: TODO */
return Increment;
}
/* EOF */

View file

@ -22,6 +22,13 @@
#define RTC_REG_A_UIP 0x80
#define RTC_REGISTER_CENTURY 0x32
/* Timer Registers and Ports */
#define TIMER_CONTROL_PORT 0x43
#define TIMER_DATA_PORT0 0x40
#define TIMER_SC0 0
#define TIMER_BOTH 0x30
#define TIMER_MD2 0x4
/* Conversion functions */
#define BCD_INT(bcd) \
(((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F))

View file

@ -20,6 +20,17 @@ Author:
#ifndef _ASM_H
#define _ASM_H
//
// PCR Access
//
#ifdef __ASM__
#ifdef CONFIG_SMP
#define PCR fs:
#else
#define PCR ds:[0xFF000000]
#endif
#endif
//
// CPU Modes
//
@ -145,6 +156,7 @@ Author:
#define KPCR_IDT 0x38
#define KPCR_GDT 0x3C
#define KPCR_TSS 0x40
#define KPCR_STALL_SCALE_FACTOR 0x4C
#define KPCR_SET_MEMBER 0x48
#define KPCR_NUMBER 0x51
#define KPCR_PRCB_DATA 0x120
@ -489,6 +501,8 @@ Author:
#define STATUS_FLOAT_MULTIPLE_FAULTS 0xC00002B4
#define STATUS_FLOAT_MULTIPLE_TRAPS 0xC00002B5
#define APC_INDEX_MISMATCH 0x01
#define IRQL_NOT_GREATER_OR_EQUAL 0x09
#define IRQL_NOT_LESS_OR_EQUAL 0x0A
#define TRAP_CAUSE_UNKNOWN 0x12
#define KMODE_EXCEPTION_NOT_HANDLED 0x13
#define IRQL_GT_ZERO_AT_SYSTEM_SERVICE 0x4A

View file

@ -177,231 +177,6 @@ KeInitInterrupts (VOID)
}
}
static VOID
KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame,
PKTRAP_FRAME TrapFrame)
{
TrapFrame->SegGs = (USHORT)IrqTrapFrame->Gs;
TrapFrame->SegFs = (USHORT)IrqTrapFrame->Fs;
TrapFrame->SegEs = (USHORT)IrqTrapFrame->Es;
TrapFrame->SegDs = (USHORT)IrqTrapFrame->Ds;
TrapFrame->Eax = IrqTrapFrame->Eax;
TrapFrame->Ecx = IrqTrapFrame->Ecx;
TrapFrame->Edx = IrqTrapFrame->Edx;
TrapFrame->Ebx = IrqTrapFrame->Ebx;
TrapFrame->HardwareEsp = IrqTrapFrame->Esp;
TrapFrame->Ebp = IrqTrapFrame->Ebp;
TrapFrame->Esi = IrqTrapFrame->Esi;
TrapFrame->Edi = IrqTrapFrame->Edi;
TrapFrame->Eip = IrqTrapFrame->Eip;
TrapFrame->SegCs = IrqTrapFrame->Cs;
TrapFrame->EFlags = IrqTrapFrame->Eflags;
}
static VOID
KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame,
PKIRQ_TRAPFRAME IrqTrapFrame)
{
IrqTrapFrame->Gs = TrapFrame->SegGs;
IrqTrapFrame->Fs = TrapFrame->SegFs;
IrqTrapFrame->Es = TrapFrame->SegEs;
IrqTrapFrame->Ds = TrapFrame->SegDs;
IrqTrapFrame->Eax = TrapFrame->Eax;
IrqTrapFrame->Ecx = TrapFrame->Ecx;
IrqTrapFrame->Edx = TrapFrame->Edx;
IrqTrapFrame->Ebx = TrapFrame->Ebx;
IrqTrapFrame->Esp = TrapFrame->HardwareEsp;
IrqTrapFrame->Ebp = TrapFrame->Ebp;
IrqTrapFrame->Esi = TrapFrame->Esi;
IrqTrapFrame->Edi = TrapFrame->Edi;
IrqTrapFrame->Eip = TrapFrame->Eip;
IrqTrapFrame->Cs = TrapFrame->SegCs;
IrqTrapFrame->Eflags = TrapFrame->EFlags;
}
/*
* NOTE: On Windows this function takes exactly one parameter and EBP is
* guaranteed to point to KTRAP_FRAME. The function is used only
* by HAL, so there's no point in keeping that prototype.
*
* @implemented
*/
VOID
STDCALL
KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql)
{
PKPRCB Prcb = KeGetCurrentPrcb();
PKTHREAD CurrentThread;
PKPROCESS CurrentProcess;
/* Make sure we don't go further if we're in early boot phase. */
if (!(Prcb) || !(Prcb->CurrentThread)) return;
/* Get the current thread and process */
CurrentThread = Prcb->CurrentThread;
CurrentProcess = CurrentThread->ApcState.Process;
/* Check if we came from user mode */
if (TrapFrame->PreviousPreviousMode != KernelMode)
{
/* Update user times */
CurrentThread->UserTime++;
InterlockedIncrement((PLONG)&CurrentProcess->UserTime);
Prcb->UserTime++;
}
else
{
/* Check IRQ */
if (Irql > DISPATCH_LEVEL)
{
/* This was an interrupt */
Prcb->InterruptTime++;
}
else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
{
/* This was normal kernel time */
CurrentThread->KernelTime++;
InterlockedIncrement((PLONG)&CurrentProcess->KernelTime);
}
else if (Irql == DISPATCH_LEVEL)
{
/* This was DPC time */
Prcb->DpcTime++;
}
/* Update CPU kernel time in all cases */
Prcb->KernelTime++;
}
/* Set the last DPC Count and request rate */
Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
Prcb->DpcRequestRate) / 2;
/* Check if we should request a DPC */
if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
{
/* Request one */
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
/* Update the depth if needed */
if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
(Prcb->MaximumDpcQueueDepth > 1))
{
/* Decrease the maximum depth by one */
Prcb->MaximumDpcQueueDepth--;
}
}
else
{
/* Decrease the adjustment threshold */
if (!(--Prcb->AdjustDpcThreshold))
{
/* We've hit 0, reset it */
Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
/* Check if we've hit queue maximum */
if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
{
/* Increase maximum by one */
Prcb->MaximumDpcQueueDepth++;
}
}
}
/*
* If we're at end of quantum request software interrupt. The rest
* is handled in KiDispatchInterrupt.
*
* NOTE: If one stays at DISPATCH_LEVEL for a long time the DPC routine
* which checks for quantum end will not be executed and decrementing
* the quantum here can result in overflow. This is not a problem since
* we don't care about the quantum value anymore after the QuantumEnd
* flag is set.
*/
if ((CurrentThread->Quantum -= 3) <= 0)
{
Prcb->QuantumEnd = TRUE;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
}
/*
* NOTE: On Windows this function takes exactly zero parameters and EBP is
* guaranteed to point to KTRAP_FRAME. Also [esp+0] contains an IRQL.
* The function is used only by HAL, so there's no point in keeping
* that prototype.
*
* @implemented
*/
VOID
STDCALL
KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
IN KIRQL Irql,
IN ULONG Increment)
{
LONG OldOffset;
LARGE_INTEGER Time;
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
if (!KiClockSetupComplete) return;
/* Update interrupt time */
Time.LowPart = SharedUserData->InterruptTime.LowPart;
Time.HighPart = SharedUserData->InterruptTime.High1Time;
Time.QuadPart += Increment;
SharedUserData->InterruptTime.High2Time = Time.u.HighPart;
SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
SharedUserData->InterruptTime.High1Time = Time.u.HighPart;
/* Increase the tick offset */
KiTickOffset -= Increment;
OldOffset = KiTickOffset;
/* Check if this isn't a tick yet */
if (KiTickOffset > 0)
{
/* Expire timers */
KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
}
else
{
/* Setup time structure for system time */
Time.LowPart = SharedUserData->SystemTime.LowPart;
Time.HighPart = SharedUserData->SystemTime.High1Time;
Time.QuadPart += KeTimeAdjustment;
SharedUserData->SystemTime.High2Time = Time.HighPart;
SharedUserData->SystemTime.LowPart = Time.LowPart;
SharedUserData->SystemTime.High1Time = Time.HighPart;
/* Setup time structure for tick time */
Time.LowPart = KeTickCount.LowPart;
Time.HighPart = KeTickCount.High1Time;
Time.QuadPart += 1;
KeTickCount.High2Time = Time.HighPart;
KeTickCount.LowPart = Time.LowPart;
KeTickCount.High1Time = Time.HighPart;
SharedUserData->TickCount.High2Time = Time.HighPart;
SharedUserData->TickCount.LowPart = Time.LowPart;
SharedUserData->TickCount.High1Time = Time.HighPart;
/* Update tick count in shared user data as well */
SharedUserData->TickCountLowDeprecated++;
/* Queue a DPC that will expire timers */
KeInsertQueueDpc(&KiExpireTimerDpc, (PVOID)TrapFrame->Eip, 0);
}
/* Update process and thread times */
if (OldOffset <= 0)
{
/* This was a tick, calculate the next one */
KiTickOffset += KeMaximumIncrement;
KeUpdateRunTime(TrapFrame, Irql);
}
}
VOID STDCALL
KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
/*
@ -453,9 +228,7 @@ KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
*/
{
KIRQL old_level;
KTRAP_FRAME KernelTrapFrame;
PKTHREAD CurrentThread;
PKTRAP_FRAME OldTrapFrame=NULL;
/*
* At this point we have interrupts disabled, nothing has been done to
@ -482,20 +255,12 @@ KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
*/
_enable();
#ifndef CONFIG_SMP
if (VECTOR2IRQ(vector) == 0)
{
KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
KeUpdateSystemTime(&KernelTrapFrame, old_level, 100000);
}
else
#endif
{
ASSERT (VECTOR2IRQ(vector) != 0);
/*
* Actually call the ISR.
*/
KiInterruptDispatch2(vector, old_level);
}
/*
* End the system interrupt.
@ -514,23 +279,14 @@ KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
((PETHREAD)CurrentThread)->Cid.UniqueThread,
Trapframe->Cs,
CurrentThread->TrapFrame ? CurrentThread->TrapFrame->SegCs : 0);
if (CurrentThread->TrapFrame == NULL)
{
OldTrapFrame = CurrentThread->TrapFrame;
KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
CurrentThread->TrapFrame = &KernelTrapFrame;
}
ASSERT (CurrentThread->TrapFrame);
_enable();
KiDeliverApc(UserMode, NULL, NULL);
_disable();
ASSERT(KeGetCurrentThread() == CurrentThread);
if (CurrentThread->TrapFrame == &KernelTrapFrame)
{
KeTrapFrameToIRQTrapFrame(&KernelTrapFrame, Trapframe);
CurrentThread->TrapFrame = OldTrapFrame;
}
ASSERT (CurrentThread->TrapFrame);
}
KeLowerIrql(PASSIVE_LEVEL);
}

View file

@ -226,7 +226,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
/* Set the system affinity and acquire the dispatcher lock */
KeSetSystemAffinityThread(1 << Number);
OldIrql = KeAcquireDispatcherDatabaseLock();
OldIrql = KiAcquireDispatcherLock();
/* Check if it's already been connected */
if (!Interrupt->Connected)
@ -272,7 +272,7 @@ KeConnectInterrupt(IN PKINTERRUPT Interrupt)
}
/* Unlock the dispatcher and revert affinity */
KeReleaseDispatcherDatabaseLock(OldIrql);
KiReleaseDispatcherLock(OldIrql);
KeRevertToUserAffinityThread();
/* Return to caller */
@ -296,7 +296,7 @@ KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
KeSetSystemAffinityThread(1 << Interrupt->Number);
/* Lock the dispatcher */
OldIrql = KeAcquireDispatcherDatabaseLock();
OldIrql = KiAcquireDispatcherLock();
/* Check if it's actually connected */
State = Interrupt->Connected;
@ -354,7 +354,7 @@ KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
}
/* Unlock the dispatcher and revert affinity */
KeReleaseDispatcherDatabaseLock(OldIrql);
KiReleaseDispatcherLock(OldIrql);
KeRevertToUserAffinityThread();
/* Return to caller */