Skip to content

Commit

Permalink
x86_64: recalibrate local APIC on each core
Browse files Browse the repository at this point in the history
  • Loading branch information
jewelcodes committed Oct 6, 2024
1 parent f651249 commit 46b481d
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 21 deletions.
21 changes: 5 additions & 16 deletions src/platform/x86_64/apic/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ int apMain() {

smpCPUInfoSetup();

// set up the local APIC
// on the bootstrap CPU this is done by apicTimerInit(), but we don't need
// to rerun it to not waste time recalibrating the APIC when we already did

// enable the local APIC (this should probably never be necessary because
// if the APIC wasn't enabled then how did we even boot to this point?)
uint64_t apic = readMSR(MSR_LAPIC);
Expand All @@ -178,14 +174,9 @@ int apMain() {
lapicWrite(LAPIC_DEST_FORMAT, lapicRead(LAPIC_DEST_FORMAT) | 0xF0000000); // flat mode
lapicWrite(LAPIC_SPURIOUS_VECTOR, 0x1FF);

// set up per-CPU kernel info structure

// APIC timer
lapicWrite(LAPIC_TIMER_INITIAL, 0); // disable timer so we can set up
lapicWrite(LAPIC_LVT_TIMER, LAPIC_TIMER_PERIODIC | LAPIC_LVT_MASK | LAPIC_TIMER_IRQ);
lapicWrite(LAPIC_TIMER_DIVIDE, LAPIC_TIMER_DIVIDER_1);
lapicWrite(LAPIC_LVT_TIMER, lapicRead(LAPIC_LVT_TIMER) & ~LAPIC_LVT_MASK);
lapicWrite(LAPIC_TIMER_INITIAL, apicTimerFrequency() / PLATFORM_TIMER_FREQUENCY);
// apparently each core can have a different APIC frequency, and so we need
// to recalibrate the local APIC
apicTimerInit();

// we don't need to install an IRQ handler because all CPUs share the same
// GDT/IDT; the same IRQ handler is valid for both the boot CPU and APs
Expand All @@ -209,9 +200,6 @@ int smpBoot() {
return 1;
}

// disable caching temporarily
writeCR0(readCR0() | CR0_CACHE_DISABLE);

KDEBUG("attempt to start %d application processors...\n", cpuCount - runningCpuCount);

// set up the AP entry point
Expand Down Expand Up @@ -240,7 +228,8 @@ int smpBoot() {
// identity map first 8 MB for the AP
// this will give it access to (most of) the kernel's physical memory
for(int i = 0; i < 2048; i++) {
platformMapPage(i * PAGE_SIZE, i * PAGE_SIZE, PLATFORM_PAGE_PRESENT | PLATFORM_PAGE_EXEC | PLATFORM_PAGE_WRITE);
platformMapPage(i * PAGE_SIZE, i * PAGE_SIZE,
PLATFORM_PAGE_PRESENT | PLATFORM_PAGE_EXEC | PLATFORM_PAGE_WRITE | PLATFORM_PAGE_NO_CACHE);
}

apEntryVars[AP_ENTRY_GDTR] = (uintptr_t)lowGDTR - KERNEL_BASE_ADDRESS;
Expand Down
9 changes: 4 additions & 5 deletions src/platform/x86_64/apic/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ int apicTimerInit() {
/* TODO: use the HPET instead of the PIT to measure timer frequency */
// set up the PIT to wait for a fraction of a second
uint16_t pitFrequency = 1193180 / 100; // PIT frequency divided by 100 Hz
KDEBUG("using PIT to calibrate local APIC timer: starting counter 0x%04X\n", pitFrequency);

// set up the APIC timer in one-shot mode with no interrupts
lapicWrite(LAPIC_TIMER_INITIAL, 0); // disable timer so we can set it up
Expand All @@ -63,12 +62,12 @@ int apicTimerInit() {
uint16_t oldCurrentCounter = pitFrequency;

// this way we correctly handle a zero counter, as well as an underflow
while(currentCounter <= oldCurrentCounter && currentCounter) {
while((currentCounter <= oldCurrentCounter) && currentCounter) {
oldCurrentCounter = currentCounter;

outb(0x43, 0x00); // channel 0, latch command
currentCounter = inb(0x40);
currentCounter |= inb(0x40) << 8;
currentCounter = (uint16_t) inb(0x40);
currentCounter |= (uint16_t) inb(0x40) << 8;
}

uint32_t apicFinal = lapicRead(LAPIC_TIMER_CURRENT);
Expand All @@ -86,7 +85,7 @@ int apicTimerInit() {
for(;;) platformHalt();
}

KDEBUG("setting up system timer at %d kHz\n", PLATFORM_TIMER_FREQUENCY / 1000);
//KDEBUG("setting up system timer at %d kHz\n", PLATFORM_TIMER_FREQUENCY / 1000);

// set up the local APIC timer in periodic mode and allocate interrupt 0xFE for it
lapicWrite(LAPIC_LVT_TIMER, LAPIC_TIMER_PERIODIC | LAPIC_LVT_MASK | LAPIC_TIMER_IRQ);
Expand Down

0 comments on commit 46b481d

Please sign in to comment.