APIC timer calibration.
Kind of. With the PIT. So 90's. Conflicts: Kernel/src/Tier0/kmain.calentours-dev
parent
31fed61a76
commit
b2e69f18b8
|
@ -15,7 +15,7 @@ void kputs(const s8 *szString);
|
||||||
void kputch(const s8 Character);
|
void kputch(const s8 Character);
|
||||||
void kclear(void);
|
void kclear(void);
|
||||||
void kprint(const s8 *szString);
|
void kprint(const s8 *szString);
|
||||||
void kputi(s32 Number);
|
void kputi(s64 Number);
|
||||||
void kprintf(const s8 *Format, ...);
|
void kprintf(const s8 *Format, ...);
|
||||||
void kdump(u8 *bData, u32 Length);
|
void kdump(u8 *bData, u32 Length);
|
||||||
void kprint_hex(u64 Number);
|
void kprint_hex(u64 Number);
|
||||||
|
|
|
@ -9,8 +9,12 @@
|
||||||
#define APIC_GET32(field) (*((u32*)(g_APIC.LAPIC + field)))
|
#define APIC_GET32(field) (*((u32*)(g_APIC.LAPIC + field)))
|
||||||
#define APIC_SET32A(field, value) do { APIC_SET32(field, value); ASSERT(APIC_GET32(field) == (value));} while(0)
|
#define APIC_SET32A(field, value) do { APIC_SET32(field, value); ASSERT(APIC_GET32(field) == (value));} while(0)
|
||||||
|
|
||||||
|
#define APIC_CALIBRATION_SAMPLES 8
|
||||||
struct {
|
struct {
|
||||||
void *LAPIC;
|
void *LAPIC;
|
||||||
|
volatile u32 CalibrationCounter;
|
||||||
|
volatile u32 CalibrationSamples[APIC_CALIBRATION_SAMPLES];
|
||||||
|
u32 BusSpeed;
|
||||||
} g_APIC;
|
} g_APIC;
|
||||||
|
|
||||||
void apic_eoi(void)
|
void apic_eoi(void)
|
||||||
|
@ -26,8 +30,26 @@ void apic_spurious_interrupt(T_ISR_REGISTERS Registers)
|
||||||
void apic_timer_interrupt(T_ISR_REGISTERS Registers)
|
void apic_timer_interrupt(T_ISR_REGISTERS Registers)
|
||||||
{
|
{
|
||||||
kprintf("ohai\n");
|
kprintf("ohai\n");
|
||||||
|
apic_eoi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apic_calibration_interrupt(T_ISR_REGISTERS Registers)
|
||||||
|
{
|
||||||
|
u32 Sample = APIC_GET32(APIC_TimerCCR);
|
||||||
|
if (g_APIC.CalibrationCounter >= APIC_CALIBRATION_SAMPLES)
|
||||||
|
{
|
||||||
|
koutb(0x20, 0x20);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
g_APIC.CalibrationSamples[g_APIC.CalibrationCounter] = Sample;
|
||||||
|
g_APIC.CalibrationCounter++;
|
||||||
|
|
||||||
|
// is the APIC timer 0? well shit.
|
||||||
|
if (Sample == 0)
|
||||||
|
PANIC("APIC Calibration look reached null timer value. Too many saples?");
|
||||||
|
|
||||||
|
koutb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
void apic_enable_lapic(void)
|
void apic_enable_lapic(void)
|
||||||
{
|
{
|
||||||
|
@ -46,6 +68,10 @@ void apic_enable_lapic(void)
|
||||||
kprintf("[i] LAPIC will be @0x%x.\n", Virtual);
|
kprintf("[i] LAPIC will be @0x%x.\n", Virtual);
|
||||||
paging_map_page(Virtual, 0xFEE00000);
|
paging_map_page(Virtual, 0xFEE00000);
|
||||||
|
|
||||||
|
// prepare interrupts ..
|
||||||
|
interrupts_setup_isr(39, (void *)apic_spurious_interrupt, E_INTERRUPTS_RING0);
|
||||||
|
interrupts_setup_isr(200, (void *)apic_timer_interrupt, E_INTERRUPTS_RING0);
|
||||||
|
|
||||||
g_APIC.LAPIC = (void *)Virtual;
|
g_APIC.LAPIC = (void *)Virtual;
|
||||||
|
|
||||||
// reset APIC to a kinda known state
|
// reset APIC to a kinda known state
|
||||||
|
@ -53,47 +79,52 @@ void apic_enable_lapic(void)
|
||||||
APIC_SET32(APIC_LDR, (APIC_GET32(APIC_LDR)&0x00FFFFFF)|1);
|
APIC_SET32(APIC_LDR, (APIC_GET32(APIC_LDR)&0x00FFFFFF)|1);
|
||||||
APIC_SET32A(APIC_LVTTimer, 0x10000); // mask bit
|
APIC_SET32A(APIC_LVTTimer, 0x10000); // mask bit
|
||||||
APIC_SET32A(APIC_LVTPerformanceCounter, 4 << 8); // NMI bit
|
APIC_SET32A(APIC_LVTPerformanceCounter, 4 << 8); // NMI bit
|
||||||
APIC_SET32A(APIC_LVTLINT0, 0x10000); // mask bit
|
APIC_SET32A(APIC_LVTLINT0, 0x10000); // mask vit
|
||||||
APIC_SET32A(APIC_LVTLINT1, 0x10000); // mask bit
|
APIC_SET32A(APIC_LVTLINT1, 0x10000); // mask bit
|
||||||
APIC_SET32A(APIC_TPR, 0); // task priority = 0 (accept all)
|
APIC_SET32A(APIC_TPR, 0); // task priority = 0 (accept all)
|
||||||
|
|
||||||
// prepare interrupts ..
|
|
||||||
interrupts_setup_isr(39, (void *)apic_spurious_interrupt, E_INTERRUPTS_RING0);
|
|
||||||
interrupts_setup_isr(32, (void *)apic_timer_interrupt, E_INTERRUPTS_RING0);
|
|
||||||
|
|
||||||
APIC_SET32A(APIC_SVR, 39 | 0x100); // spurious interrupt + sw enable bit
|
APIC_SET32A(APIC_SVR, 39 | 0x100); // spurious interrupt + sw enable bit
|
||||||
APIC_SET32A(APIC_LVTTimer, 32); // apic timer interrupt
|
APIC_SET32A(APIC_LVTTimer, 0x1000); // mask bit
|
||||||
APIC_SET32A(APIC_TimerDCR, 0x03); // timer divider = bus speed / 16
|
APIC_SET32A(APIC_TimerDCR, 0x03); // timer divider = bus speed / 16
|
||||||
|
|
||||||
kprintf("[i] LAPIC ready to calibrate timer.\n");
|
kprintf("[i] LAPIC ready to calibrate timer.\n");
|
||||||
|
|
||||||
// calibration time! let's use the PIT
|
// calibration time! let's use the PIT
|
||||||
koutb(0x61, kinb(0x61) | 0xFD); // disable speaker
|
// let's unmask IRQ0 only
|
||||||
koutb(0x43, 0xB2); // one shot, channel 2
|
koutb(0x21, 0xFE);
|
||||||
|
koutb(0xA1, 0xFF);
|
||||||
|
|
||||||
// to setup a 100Hz loop, wee need a divider of...
|
// let's make LINT0 trigger an extINT (yay PIC-time)
|
||||||
// 1193180 / 100 Hz = 11931 = 0x2e9b
|
APIC_SET32(APIC_LVTLINT0, 0x8700);
|
||||||
koutb(0x42, 0x9b); // write low byte
|
|
||||||
kinb(0x60); // wait a bit
|
|
||||||
koutb(0x42, 0x2e); // write high bte
|
|
||||||
|
|
||||||
// now we are ready to fire the PIT timer
|
// let's start the APIC timer and zero the calibration counter
|
||||||
kprintf("[i] Firing PIT for calibration...\n");
|
|
||||||
u8 Temporary = kinb(0x61) & 0xFE;
|
|
||||||
koutb(0x61, Temporary); // gate low
|
|
||||||
koutb(0x61, Temporary | 1); // gate high
|
|
||||||
// don't forget to actually fire the APIC timer at the same time...
|
|
||||||
APIC_SET32(APIC_TimerICR, 0xFFFFFFFF);
|
APIC_SET32(APIC_TimerICR, 0xFFFFFFFF);
|
||||||
// for(;;)
|
g_APIC.CalibrationCounter = 0;
|
||||||
// {
|
|
||||||
// kprintf("APIC: %x\n", APIC_GET32(APIC_TimerICR));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// wait for the PIT counter to reach zero...
|
// now let's program the PIT to run a channel0 (IRQ0) timer with a 100Hz loop
|
||||||
while (!(kinb(0x61) & 0x020));
|
interrupts_setup_isr(32, (void *)apic_calibration_interrupt, E_INTERRUPTS_RING0);
|
||||||
// disable APIC timer
|
koutb(0x43, 0x36);
|
||||||
|
koutb(0x40, 0x0B);
|
||||||
|
koutb(0x40, 0xE9);
|
||||||
|
|
||||||
|
// the timer is now running!
|
||||||
|
while (g_APIC.CalibrationCounter < APIC_CALIBRATION_SAMPLES) {};
|
||||||
|
|
||||||
|
// enough samples, let's clean up
|
||||||
|
kprintf("[i] Calibration loop finished.\n");
|
||||||
|
koutb(0x21, 0xFF);
|
||||||
|
koutb(0x21, 0xFF);
|
||||||
|
APIC_SET32(APIC_LVTLINT0, 0x1000); // mask bit
|
||||||
APIC_SET32(APIC_LVTTimer, 0x10000); // mask bit
|
APIC_SET32(APIC_LVTTimer, 0x10000); // mask bit
|
||||||
kprintf("[i] Timer reached zero, APIC Timer @%x.\n", APIC_GET32(APIC_TimerICR));
|
interrupts_setup_isr(32, (void *)apic_timer_interrupt, E_INTERRUPTS_RING0);
|
||||||
|
|
||||||
|
u64 Average = 0;
|
||||||
|
for (u32 i = 0; i < APIC_CALIBRATION_SAMPLES -1; i++)
|
||||||
|
Average += (g_APIC.CalibrationSamples[i] - g_APIC.CalibrationSamples[i + 1]);
|
||||||
|
|
||||||
|
Average /= (APIC_CALIBRATION_SAMPLES - 1);
|
||||||
|
g_APIC.BusSpeed = (Average * 16 * 50)/(1000000);
|
||||||
|
kprintf("[i] Bus speed %iMHz.\n", g_APIC.BusSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef APIC_SET
|
#undef APIC_SET
|
|
@ -119,26 +119,40 @@ void interrupts_remap_pic(void)
|
||||||
{
|
{
|
||||||
// remap the PIC IRQ's to 0x20-0x27 and 0x28-0x2F
|
// remap the PIC IRQ's to 0x20-0x27 and 0x28-0x2F
|
||||||
|
|
||||||
// save masks
|
|
||||||
u8 MaskMaster = kinb(0x21);
|
|
||||||
u8 MaskSlave = kinb(0xA1);
|
|
||||||
|
|
||||||
koutb(0x20, 0x11); // start initialization sequence
|
koutb(0x20, 0x11); // start initialization sequence
|
||||||
|
kio_wait();
|
||||||
koutb(0xA0, 0x11); // - " -
|
koutb(0xA0, 0x11); // - " -
|
||||||
|
kio_wait();
|
||||||
|
|
||||||
koutb(0x21, 0x20); // master from 0x20
|
koutb(0x21, 0x20); // master from 0x20
|
||||||
|
kio_wait();
|
||||||
koutb(0xA1, 0x28); // slave from 0x28
|
koutb(0xA1, 0x28); // slave from 0x28
|
||||||
|
kio_wait();
|
||||||
koutb(0x21, 0x04); // slave PIC at IRQ2
|
koutb(0x21, 0x04); // slave PIC at IRQ2
|
||||||
|
kio_wait();
|
||||||
koutb(0xA1, 0x02); // cascade
|
koutb(0xA1, 0x02); // cascade
|
||||||
|
kio_wait();
|
||||||
koutb(0x21, 0x01); // 8086 mode
|
koutb(0x21, 0x01); // 8086 mode
|
||||||
|
kio_wait();
|
||||||
koutb(0xA1, 0x01); // 8086 mode
|
koutb(0xA1, 0x01); // 8086 mode
|
||||||
|
kio_wait();
|
||||||
|
|
||||||
// restore masks
|
// set masks to accept no IRQs
|
||||||
koutb(0x21, MaskMaster);
|
koutb(0x21, 0xFF);
|
||||||
koutb(0xA1, MaskSlave);
|
kio_wait();
|
||||||
|
koutb(0xA1, 0xFF);
|
||||||
|
kio_wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GENERIC_IRQ_DEF(i) void interrupts_irq##i##_isr(void) { kprintf("[w] OOPS: Unhandled IRQ"#i"\n"); }
|
void interrupts_eoi_pic(u8 IRQ)
|
||||||
|
{
|
||||||
|
if (IRQ > 7)
|
||||||
|
koutb(0xA0, 0x20);
|
||||||
|
|
||||||
|
koutb(0x20, 0x20);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GENERIC_IRQ_DEF(i) void interrupts_irq##i##_isr(void) { kprintf("[w] OOPS: Unhandled IRQ"#i"\n"); interrupts_eoi_pic(i); }
|
||||||
#define GENERIC_IRQ_BIND(i) interrupts_setup_isr(0x20 + i, (void *)interrupts_irq##i##_isr, E_INTERRUPTS_RING0)
|
#define GENERIC_IRQ_BIND(i) interrupts_setup_isr(0x20 + i, (void *)interrupts_irq##i##_isr, E_INTERRUPTS_RING0)
|
||||||
PPHAX_DO16(GENERIC_IRQ_DEF);
|
PPHAX_DO16(GENERIC_IRQ_DEF);
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,8 @@ void kmain_newstack(void)
|
||||||
interrupts_init_simple();
|
interrupts_init_simple();
|
||||||
exceptions_init_simple();
|
exceptions_init_simple();
|
||||||
apic_enable_lapic();
|
apic_enable_lapic();
|
||||||
|
for (;;) {}
|
||||||
heap_init_simple();
|
heap_init_simple();
|
||||||
|
|
||||||
// enable FPU/SSE...
|
// enable FPU/SSE...
|
||||||
__asm__ volatile(
|
__asm__ volatile(
|
||||||
"movq %cr0, %rax;"
|
"movq %cr0, %rax;"
|
||||||
|
|
|
@ -46,14 +46,14 @@ void kio_wait(void)
|
||||||
__asm__ volatile("jmp 1f;1:jmp 1f;1:");
|
__asm__ volatile("jmp 1f;1:jmp 1f;1:");
|
||||||
}
|
}
|
||||||
|
|
||||||
void kputi(s32 Number)
|
void kputi(s64 Number)
|
||||||
{
|
{
|
||||||
s32 Sign, i;
|
s64 Sign, i;
|
||||||
|
|
||||||
if ((Sign = Number) < 0)
|
if ((Sign = Number) < 0)
|
||||||
Number = -Number;
|
Number = -Number;
|
||||||
|
|
||||||
u8 szString[11];
|
u8 szString[21];
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -94,10 +94,10 @@ void kprintf(const s8 *szFormat, ...)
|
||||||
kputs(va_arg(ap, s8*));
|
kputs(va_arg(ap, s8*));
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
kputi(va_arg(ap, s32));
|
kputi(va_arg(ap, s64));
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
kputi(va_arg(ap, u32));
|
kputi(va_arg(ap, u64));
|
||||||
break;
|
break;
|
||||||
case 'm': //dump
|
case 'm': //dump
|
||||||
; u8 *szString = va_arg(ap, u8*); //stupid gcc bug
|
; u8 *szString = va_arg(ap, u8*); //stupid gcc bug
|
||||||
|
|
Loading…
Reference in New Issue