APIC timer calibration.

Kind of. With the PIT. So 90's.

Conflicts:

	Kernel/src/Tier0/kmain.c
alentours-dev
q3k 2012-10-29 18:59:09 +01:00 committed by Sergiusz 'q3k' Bazański
parent 31fed61a76
commit b2e69f18b8
5 changed files with 87 additions and 42 deletions

View File

@ -15,7 +15,7 @@ void kputs(const s8 *szString);
void kputch(const s8 Character);
void kclear(void);
void kprint(const s8 *szString);
void kputi(s32 Number);
void kputi(s64 Number);
void kprintf(const s8 *Format, ...);
void kdump(u8 *bData, u32 Length);
void kprint_hex(u64 Number);

View File

@ -9,8 +9,12 @@
#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_CALIBRATION_SAMPLES 8
struct {
void *LAPIC;
volatile u32 CalibrationCounter;
volatile u32 CalibrationSamples[APIC_CALIBRATION_SAMPLES];
u32 BusSpeed;
} g_APIC;
void apic_eoi(void)
@ -26,8 +30,26 @@ void apic_spurious_interrupt(T_ISR_REGISTERS Registers)
void apic_timer_interrupt(T_ISR_REGISTERS Registers)
{
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)
{
@ -46,6 +68,10 @@ void apic_enable_lapic(void)
kprintf("[i] LAPIC will be @0x%x.\n", Virtual);
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;
// 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_SET32A(APIC_LVTTimer, 0x10000); // mask 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_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_LVTTimer, 32); // apic timer interrupt
APIC_SET32A(APIC_LVTTimer, 0x1000); // mask bit
APIC_SET32A(APIC_TimerDCR, 0x03); // timer divider = bus speed / 16
kprintf("[i] LAPIC ready to calibrate timer.\n");
// calibration time! let's use the PIT
koutb(0x61, kinb(0x61) | 0xFD); // disable speaker
koutb(0x43, 0xB2); // one shot, channel 2
// let's unmask IRQ0 only
koutb(0x21, 0xFE);
koutb(0xA1, 0xFF);
// to setup a 100Hz loop, wee need a divider of...
// 1193180 / 100 Hz = 11931 = 0x2e9b
koutb(0x42, 0x9b); // write low byte
kinb(0x60); // wait a bit
koutb(0x42, 0x2e); // write high bte
// let's make LINT0 trigger an extINT (yay PIC-time)
APIC_SET32(APIC_LVTLINT0, 0x8700);
// now we are ready to fire the PIT timer
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...
// let's start the APIC timer and zero the calibration counter
APIC_SET32(APIC_TimerICR, 0xFFFFFFFF);
// for(;;)
// {
// kprintf("APIC: %x\n", APIC_GET32(APIC_TimerICR));
// }
g_APIC.CalibrationCounter = 0;
// wait for the PIT counter to reach zero...
while (!(kinb(0x61) & 0x020));
// disable APIC timer
// now let's program the PIT to run a channel0 (IRQ0) timer with a 100Hz loop
interrupts_setup_isr(32, (void *)apic_calibration_interrupt, E_INTERRUPTS_RING0);
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
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

View File

@ -119,26 +119,40 @@ void interrupts_remap_pic(void)
{
// 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
kio_wait();
koutb(0xA0, 0x11); // - " -
kio_wait();
koutb(0x21, 0x20); // master from 0x20
kio_wait();
koutb(0xA1, 0x28); // slave from 0x28
kio_wait();
koutb(0x21, 0x04); // slave PIC at IRQ2
kio_wait();
koutb(0xA1, 0x02); // cascade
kio_wait();
koutb(0x21, 0x01); // 8086 mode
kio_wait();
koutb(0xA1, 0x01); // 8086 mode
kio_wait();
// restore masks
koutb(0x21, MaskMaster);
koutb(0xA1, MaskSlave);
// set masks to accept no IRQs
koutb(0x21, 0xFF);
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)
PPHAX_DO16(GENERIC_IRQ_DEF);

View File

@ -95,8 +95,8 @@ void kmain_newstack(void)
interrupts_init_simple();
exceptions_init_simple();
apic_enable_lapic();
for (;;) {}
heap_init_simple();
// enable FPU/SSE...
__asm__ volatile(
"movq %cr0, %rax;"

View File

@ -46,14 +46,14 @@ void kio_wait(void)
__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)
Number = -Number;
u8 szString[11];
u8 szString[21];
i = 0;
do {
@ -94,10 +94,10 @@ void kprintf(const s8 *szFormat, ...)
kputs(va_arg(ap, s8*));
break;
case 'i':
kputi(va_arg(ap, s32));
kputi(va_arg(ap, s64));
break;
case 'u':
kputi(va_arg(ap, u32));
kputi(va_arg(ap, u64));
break;
case 'm': //dump
; u8 *szString = va_arg(ap, u8*); //stupid gcc bug