diff --git a/Kernel/include/Tier0/kstdio.h b/Kernel/include/Tier0/kstdio.h index aa1c9dc..0b4f9e9 100644 --- a/Kernel/include/Tier0/kstdio.h +++ b/Kernel/include/Tier0/kstdio.h @@ -17,7 +17,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); diff --git a/Kernel/src/Tier0/apic.c b/Kernel/src/Tier0/apic.c index cd76ec1..fe5e0de 100755 --- a/Kernel/src/Tier0/apic.c +++ b/Kernel/src/Tier0/apic.c @@ -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 \ No newline at end of file diff --git a/Kernel/src/Tier0/interrupts.c b/Kernel/src/Tier0/interrupts.c index 4f1021f..7b02fe3 100644 --- a/Kernel/src/Tier0/interrupts.c +++ b/Kernel/src/Tier0/interrupts.c @@ -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); diff --git a/Kernel/src/Tier0/kmain.c b/Kernel/src/Tier0/kmain.c index 3be986b..ac0e96b 100644 --- a/Kernel/src/Tier0/kmain.c +++ b/Kernel/src/Tier0/kmain.c @@ -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;" diff --git a/Kernel/src/Tier0/kstdio.c b/Kernel/src/Tier0/kstdio.c index 98a8f6f..ace0b11 100644 --- a/Kernel/src/Tier0/kstdio.c +++ b/Kernel/src/Tier0/kstdio.c @@ -58,14 +58,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 { @@ -106,10 +106,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