reset APIC before timer initialization
This commit is contained in:
parent
e96a549349
commit
ea5b7e4930
1 changed files with 61 additions and 34 deletions
|
@ -76,8 +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");
|
||||
asm volatile ("movl (%%eax), %%edx; movl %%ebx, (%%eax)" :: "a"(lapic+addr), "b"(value) : "%edx");
|
||||
//*((volatile uint32_t*) (lapic+addr)) = value;
|
||||
}
|
||||
|
||||
|
@ -255,6 +254,24 @@ int smp_init(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int lapic_reset(void)
|
||||
{
|
||||
uint32_t 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
|
||||
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
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* detects the timer frequency of the APIC and restart
|
||||
* the APIC timer with the correct period
|
||||
|
@ -263,10 +280,13 @@ int apic_calibration(void)
|
|||
{
|
||||
uint8_t i;
|
||||
uint32_t flags;
|
||||
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
uint64_t ticks, old;
|
||||
uint32_t diff;
|
||||
#else
|
||||
uint64_t start, end, ticks;
|
||||
uint32_t diff;
|
||||
#endif
|
||||
|
||||
if (!has_apic())
|
||||
return -ENXIO;
|
||||
|
@ -274,30 +294,47 @@ int apic_calibration(void)
|
|||
lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
|
||||
if (BUILTIN_EXPECT(!lapic, 0))
|
||||
return -ENXIO;
|
||||
kprintf("Mapped LAPIC at 0x%x\n", lapic);
|
||||
|
||||
if (ioapic) {
|
||||
size_t old = 0;
|
||||
|
||||
if (ioapic)
|
||||
ioapic = (ioapic_t*) map_region(0 /*(size_t)ioapic*/, (size_t) ioapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
|
||||
kprintf("Mapped IOAPIC at 0x%x\n", ioapic);
|
||||
|
||||
// map all processor entries
|
||||
for(i=0; i<MAX_CORES; i++) {
|
||||
if (apic_processors[i] && (old != (((size_t)apic_processors[i]) & 0xFFFFF000)))
|
||||
old = map_region(((size_t) apic_processors[i]) & 0xFFFFF000, ((size_t) apic_processors[i]) & 0xFFFFF000, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ROCKCREEK
|
||||
old = get_clock_tick();
|
||||
|
||||
/* wait for the next time slice */
|
||||
while((ticks = get_clock_tick()) - old == 0)
|
||||
;
|
||||
|
||||
HALT;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
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, 0xFFFFFFFFUL);
|
||||
irq_nested_enable(flags);
|
||||
|
||||
/* wait 3 time slices to determine a ICR */
|
||||
while(get_clock_tick() - ticks < 3)
|
||||
;
|
||||
HALT;
|
||||
|
||||
diff = 0xFFFFFFFFUL - lapic_read(APIC_CCR);
|
||||
diff = diff / 3;
|
||||
|
||||
flags = irq_nested_disable();
|
||||
lapic_reset();
|
||||
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);
|
||||
irq_nested_enable(flags);
|
||||
|
||||
// Now, MetalSVM is able to use the APIC => Therefore, we disable the PIC
|
||||
outportb(0xA1, 0xFF);
|
||||
|
@ -308,27 +345,17 @@ int apic_calibration(void)
|
|||
* and possess no PIC timer. Therfore, we use the rdtsc to
|
||||
* to calibrate the APIC timer.
|
||||
*/
|
||||
uint64_t start, end, ticks;
|
||||
uint32_t diff;
|
||||
|
||||
if (!has_apic())
|
||||
return -ENXIO;
|
||||
|
||||
lapic = map_region(0 /*lapic*/, lapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
|
||||
if (BUILTIN_EXPECT(!lapic, 0))
|
||||
return -ENXIO;
|
||||
|
||||
if (ioapic)
|
||||
ioapic = (ioapic_t*) map_region(0 /*(size_t)ioapic*/, (size_t)ioapic, 1, MAP_KERNEL_SPACE|MAP_NO_CACHE);
|
||||
flags = irq_nested_disable();
|
||||
|
||||
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, 0xFFFFFFFFUL);
|
||||
|
||||
/* wait 3 time slices to determine a ICR */
|
||||
rmb();
|
||||
start = rdtsc();
|
||||
do {
|
||||
flush_pipeline();
|
||||
rmb();
|
||||
end = rdtsc();
|
||||
ticks = end > start ? end - start : start - end;
|
||||
} while(ticks*TIMER_FREQ < 3*RC_REFCLOCKMHZ*1000000UL);
|
||||
|
@ -336,9 +363,12 @@ int apic_calibration(void)
|
|||
diff = 0xFFFFFFFFUL - lapic_read(APIC_CCR);
|
||||
diff = diff / 3;
|
||||
|
||||
lapic_reset();
|
||||
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);
|
||||
|
||||
irq_nested_enable(flags);
|
||||
#endif
|
||||
|
||||
kprintf("APIC calibration determines an ICR of 0x%x\n", diff);
|
||||
|
@ -520,31 +550,28 @@ no_mp:
|
|||
goto check_lapic;
|
||||
}
|
||||
|
||||
static void apic_err_handler(struct state *s)
|
||||
{
|
||||
kprintf("Got APIC error 0x%x\n", lapic_read(APIC_ESR));
|
||||
}
|
||||
|
||||
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();
|
||||
// set APIC error handler
|
||||
irq_install_handler(126, apic_err_handler);
|
||||
|
||||
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
|
||||
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
|
||||
ret = lapic_reset();
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
if (0) { //ioapic) {
|
||||
if (ioapic) {
|
||||
// enable timer interrupt
|
||||
ioapic_inton(0, apic_processors[boot_processor]->id);
|
||||
// now lets turn everything else off
|
||||
|
|
Loading…
Add table
Reference in a new issue