diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 8ea0d1e6..d5f21089 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -36,6 +36,7 @@ extern "C" { #define APIC_ICR1 0x0300 // Interrupt Command Register [0-31] #define APIC_ICR2 0x0310 // Interrupt Command Register [32-63] #define APIC_LVT_T 0x0320 // LVT Timer Register +#define APIC_LVT_TSR 0x0330 // LVT Thermal Sensor Register #define APIC_LVT_PMC 0x0340 // LVT Performance Monitoring Counters Register #define APIC_LINT0 0x0350 // LVT LINT0 Register #define APIC_LINT1 0x0360 // LVT LINT1 Register diff --git a/arch/x86/kernel/apic.c b/arch/x86/kernel/apic.c index e134483b..206619ef 100644 --- a/arch/x86/kernel/apic.c +++ b/arch/x86/kernel/apic.c @@ -76,6 +76,7 @@ static inline void lapic_write(uint32_t addr, uint32_t value) * to avoid a pentium bug, we have to read a apic register * before we write a value to this register */ + //asm volatile ("cmpl (%0), %%eax; movl %1, (%0)" :: "r"(lapic+addr), "r"(value)); asm volatile ("movl (%%eax), %%edx; movl %%ebx, (%%eax)" :: "a"(lapic+addr), "b"(value) : "%edx"); //*((volatile uint32_t*) (lapic+addr)) = value; } @@ -109,6 +110,26 @@ uint32_t apic_cpu_id(void) return 0; } +static inline uint32_t apic_version(void) +{ + if (lapic) { + uint32_t i = *((uint32_t*) (lapic+APIC_VERSION)); + return i & 0xFF; + } + + return 0; +} + +static inline uint32_t apic_lvt_entries(void) +{ + if (lapic) { + uint32_t i = *((uint32_t*) (lapic+APIC_VERSION)); + return (i >> 16) & 0xFF; + } + + return 0; +} + int has_apic(void) { return (lapic != 0); @@ -276,10 +297,11 @@ int apic_calibration(void) ; diff = 0xFFFFFFFF - lapic_read(APIC_CCR); + diff = diff / 3; lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it - lapic_write(APIC_ICR, diff / 3); + lapic_write(APIC_ICR, diff); // Now, MetalSVM is able to use the APIC => Therefore, we disable the PIC outportb(0xA1, 0xFF); @@ -316,13 +338,14 @@ int apic_calibration(void) } while(ticks*TIMER_FREQ < 3*RC_REFCLOCKMHZ*1000000); diff = 0xFFFFFFFF - lapic_read(APIC_CCR); + diff = diff / 3; lapic_write(APIC_DCR, 0xB); // set it to 1 clock increments lapic_write(APIC_LVT_T, 0x2007B); // connects the timer to 123 and enables it - lapic_write(APIC_ICR, diff / 3); + lapic_write(APIC_ICR, diff); #endif - kprintf("APIC calibration determines an ICR of 0x%x\n", diff / 3); + kprintf("APIC calibration determines an ICR of 0x%x\n", diff); flags = irq_nested_disable(); #if MAX_CORES > 1 @@ -471,16 +494,20 @@ check_lapic: if (!lapic) goto out; - i = *((uint32_t*) (lapic+APIC_VERSION)); kprintf("Found APIC at 0x%x\n", lapic); - kprintf("Maximum LVT Entry: 0x%x\n", (i >> 16) & 0xFF); - kprintf("APIC Version: 0x%x\n", i & 0xFF); + kprintf("Maximum LVT Entry: 0x%x\n", apic_lvt_entries()); + kprintf("APIC Version: 0x%x\n", apic_version()); - if (!((i & 0xFF) >> 4)) { + if (!((apic_version() >> 4))) { kprintf("Currently, MetalSVM didn't supports extern APICs!\n"); goto out; } + if (apic_lvt_entries() < 3) { + kprintf("LVT is too small\n"); + goto out; + } + return 0; out: @@ -501,18 +528,25 @@ int apic_init(void) { int ret; uint8_t i; - + uint32_t v; + uint32_t max_lvt; + ret = apic_probe(); if (!ret) return ret; + max_lvt = apic_lvt_entries(); + + lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127 lapic_write(APIC_TPR, 0x00); // allow all interrupts lapic_write(APIC_LVT_T, 0x10000); // disable timer interrupt - lapic_write(APIC_LVT_PMC, 0x10000);// disable performance counter interrupt + if (max_lvt >= 4) + lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt + if (max_lvt >= 5) + lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt lapic_write(APIC_LINT0, 0x7C); // connect LINT0 to idt entry 124 lapic_write(APIC_LINT1, 0x7D); // connect LINT1 to idt entry 125 lapic_write(APIC_LVT_ER, 0x7E); // connect error to idt entry 126 - lapic_write(APIC_SVR, 0x17F); // enable the apic and connect to the idt entry 127 if (0) { //ioapic) { // enable timer interrupt