1 #include <lwk/kernel.h>
3 #include <lwk/resource.h>
4 #include <lwk/cpuinfo.h>
8 #include <arch/pgtable.h>
9 #include <arch/fixmap.h>
10 #include <arch/apicdef.h>
11 #include <arch/apic.h>
12 #include <arch/idt_vectors.h>
16 * Physical address of the local APIC memory mapping.
17 * If the system BIOS provided an MP configuration table, this is set in
18 * arch/x86_64/kernel/mpparse.c to the value parsed from the table.
19 * Otherwise, the default address is used.
21 unsigned long lapic_phys_addr = APIC_DEFAULT_PHYS_BASE;
24 * Resource entry for the local APIC memory mapping.
26 static struct resource lapic_resource = {
28 .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
29 /* .start and .end filled in later based on detected address */
33 * Creates a kernel mapping for the local APIC.
35 * The hardware/platform/BIOS maps each CPU's local APIC at the same location
36 * in physical memory. This function uses the 'fixmap' to map the local APIC
37 * into the kernel's virtual memory space at a fixed virtual address that is
38 * known at compile time. Since the local APIC's virtual address is known
39 * at compile time, local APIC registers can be accessed directly, without
40 * any pointer dereferencing.
46 panic("No local APIC.");
48 /* Reserve physical memory used by the local APIC */
49 lapic_resource.start = lapic_phys_addr;
50 lapic_resource.end = lapic_phys_addr + 4096 - 1;
51 request_resource(&iomem_resource, &lapic_resource);
53 /* Map local APIC into the kernel */
54 set_fixmap_nocache(FIX_APIC_BASE, lapic_phys_addr);
56 printk(KERN_DEBUG "Local APIC mapped to virtual address 0x%016lx\n",
57 fix_to_virt(FIX_APIC_BASE));
61 * Initializes the calling CPU's local APIC.
69 * Initialize Destination Format Register.
70 * When using logical destination mode, we want to use the flat model.
72 apic_write(APIC_DFR, APIC_DFR_FLAT);
75 * Initialize the Logical Destination Register.
76 * The LWK never uses logical destination mode, so just set it to the
77 * APIC's physical ID to avoid possible confusion.
79 val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
80 val |= SET_APIC_LOGICAL_ID( GET_APIC_ID(apic_read(APIC_ID)) );
81 apic_write(APIC_LDR, val);
84 * Initialize the Task Priority Register.
85 * We set this to accept all (0) and never touch it again.
87 val = apic_read(APIC_TASKPRI) & ~APIC_TPRI_MASK;
88 apic_write(APIC_TASKPRI, val);
91 * Intialize the Spurious-Interrupt Vector Register.
92 * This also enables the local APIC.
94 val = apic_read(APIC_SPIV) & ~APIC_VECTOR_MASK;
95 val |= (APIC_SPIV_APIC_ENABLED | APIC_SPURIOUS_VECTOR);
96 apic_write(APIC_SPIV, val);
98 /* Setup LVT[0] = APIC Timer Interrupt */
99 apic_write(APIC_LVTT, 0
100 | APIC_DM_FIXED /* route to fixed IDT vector */
101 | APIC_TIMER_VECTOR /* IDT vector to route to */
102 | APIC_LVT_MASKED /* initially disable */
105 /* Setup LVT[1] = Thermal Sensor Interrupt */
106 apic_write(APIC_LVTTHMR, 0
107 | APIC_DM_FIXED /* route to fixed IDT vector */
108 | APIC_THERMAL_VECTOR /* IDT vector to route to */
111 /* Setup LVT[2] = Performance Counter Interrupt */
112 apic_write(APIC_LVTPC, 0
113 | APIC_DM_NMI /* treat as non-maskable interrupt */
114 /* NMIs are routed to IDT vector 2 */
115 | APIC_LVT_MASKED /* initially disable */
118 /* Setup LVT[3] = Local Interrupt Pin 0 */
119 apic_write(APIC_LVT0, 0
120 | APIC_DM_EXTINT /* hooked up to old 8259A PIC */
121 /* IDT vector provided by 8259A */
122 | APIC_LVT_MASKED /* disable */
125 /* Setup LVT[4] = Local Interrupt Pin 1 */
126 apic_write(APIC_LVT1, 0
127 | APIC_DM_NMI /* treat as non-maskable interrupt */
128 /* NMIs are routed to IDT vector 2 */
130 ? APIC_LVT_MASKED /* mask on all but bootstrap CPU */
131 : 0) /* bootstrap CPU (0) receives NMIs */
134 /* Setup LVT[5] = Internal APIC Error Detector Interrupt */
135 apic_write(APIC_LVTERR, 0
136 | APIC_DM_FIXED /* route to fixed IDT vector */
137 | APIC_ERROR_VECTOR /* IDT vector to route to */
139 apic_write(APIC_ESR, 0); /* spec says to clear after enabling LVTERR */
143 lapic_set_timer(uint32_t count)
147 /* Setup Divide Count Register to use the bus frequency directly. */
148 apic_write(APIC_TDCR, APIC_TDR_DIV_1);
150 /* Program the initial count register */
151 apic_write(APIC_TMICT, count);
153 /* Enable the local APIC timer */
154 lvt = apic_read(APIC_LVTT);
155 lvt &= ~APIC_LVT_MASKED;
156 lvt |= APIC_LVT_TIMER_PERIODIC;
157 apic_write(APIC_LVTT, lvt);
161 lapic_stop_timer(void)
165 /* Set the initial count to 0 */
166 apic_write(APIC_TMICT, 0);
168 /* Enable the local APIC timer */
169 lvt = apic_read(APIC_LVTT);
170 lvt |= APIC_LVT_MASKED;
171 apic_write(APIC_LVTT, lvt);
175 * Detects the local APIC reference bus clock. The only sure-fire way to do
176 * this is to depend on some other absolute timing source. This function uses
177 * the CPU's cycle counter and the previously detected CPU clock frequency.
179 * NOTE: This assumes that the CPU's clock frequency has already been detected.
180 * (i.e., cpu_info[cpu_id()].arch.tsc_khz has been initialized.
183 lapic_calibrate_timer(void)
185 const unsigned int tick_count = 100000000;
186 cycles_t tsc_start, tsc_now;
187 uint32_t apic_start, apic_now;
188 unsigned int apic_Hz;
190 /* Start the APIC counter running for calibration */
191 lapic_set_timer(4000000000);
193 apic_start = apic_read(APIC_TMCCT);
194 tsc_start = get_cycles_sync();
196 /* Spin until enough ticks for a meaningful result have elapsed */
198 apic_now = apic_read(APIC_TMCCT);
199 tsc_now = get_cycles_sync();
200 } while ( ((tsc_now - tsc_start) < tick_count) &&
201 ((apic_start - apic_now) < tick_count) );
203 apic_Hz = (apic_start - apic_now) * 1000L *
204 cpu_info[this_cpu].arch.tsc_khz / (tsc_now - tsc_start);
208 return (apic_Hz / 1000);
212 lapic_wait4_icr_idle(void)
214 uint32_t send_status;
217 /* Wait up to 100 milliseconds */
220 send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
224 } while (timeout++ < 1000);
230 * Returns the number of entries in the Local Vector Table minus one.
232 * This should return 5 or higher on all x86_64 CPUs.
233 * 6 is returned if the APIC Thermal Interrupt is supported, 5 otherwise.
236 lapic_get_maxlvt(void)
238 return GET_APIC_MAXLVT(apic_read(APIC_LVR));
242 * Sends an INIT inter-processor interrupt.
243 * This is used during bootstrap to wakeup the AP CPUs.
246 lapic_send_init_ipi(unsigned int cpu)
249 unsigned int apic_id = cpu_info[cpu].arch.apic_id;
251 /* Turn on INIT at target CPU */
252 apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
253 apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
255 status = lapic_wait4_icr_idle();
257 panic("INIT IPI ERROR: failed to assert INIT. (%x)", status);
260 /* Turn off INIT at target CPU */
261 apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
262 apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
263 status = lapic_wait4_icr_idle();
265 panic("INIT IPI ERROR: failed to deassert INIT. (%x)", status);
269 * Send a STARTUP inter-processor interrupt.
270 * This is used during bootstrap to wakeup the AP CPUs.
273 lapic_send_startup_ipi(
274 unsigned int cpu, /* Logical CPU ID */
275 unsigned long start_rip /* Physical addr */
279 unsigned int maxlvt = lapic_get_maxlvt();
280 unsigned int apic_id = cpu_info[cpu].arch.apic_id;
283 apic_write(APIC_ESR, 0);
287 apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
289 /* Send Startup IPI to target CPU */
290 apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
291 apic_write(APIC_ICR, APIC_DM_STARTUP | (start_rip >> 12));
292 udelay(300); /* Give AP CPU some time to accept the IPI */
293 status = lapic_wait4_icr_idle();
295 panic("STARTUP IPI ERROR: failed to send. (%x)", status);
296 udelay(300); /* Give AP CPU some time to accept the IPI */
298 /* Fixup for Pentium erratum 3AP, clear errors */
300 apic_write(APIC_ESR, 0);
302 /* Verify that IPI was accepted */
303 status = (apic_read(APIC_ESR) & 0xEF);
305 panic("STARTUP IPI ERROR: failed to accept. (%x)", status);
309 * Sends an inter-processor interrupt (IPI) to the specified CPU.
310 * Note that the IPI has not necessarily been delivered when this function
315 unsigned int cpu, /* Logical CPU ID */
316 unsigned int vector /* Interrupt vector to send */
320 unsigned int apic_id;
323 status = lapic_wait4_icr_idle();
325 panic("lapic_wait4_icr_idle() timed out. (%x)", status);
328 apic_id = cpu_info[cpu].arch.apic_id;
329 apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
332 if (unlikely(vector == NMI_VECTOR))
333 apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_NMI);
335 apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_FIXED|vector);
339 * Converts an entry in a local APIC's Local Vector Table to a
340 * human-readable string.
343 lvt_stringify(uint32_t entry, char *buf)
345 uint32_t delivery_mode = GET_APIC_DELIVERY_MODE(entry);
347 if (delivery_mode == APIC_MODE_FIXED) {
348 sprintf(buf, "FIXED -> IDT_VECTOR %d",
349 entry & APIC_VECTOR_MASK
351 } else if (delivery_mode == APIC_MODE_NMI) {
352 sprintf(buf, "NMI -> IDT VECTOR 2");
353 } else if (delivery_mode == APIC_MODE_EXTINT) {
354 sprintf(buf, "ExtINT, hooked to old 8259A PIC");
356 sprintf(buf, "UNKNOWN");
359 if (entry & APIC_LVT_MASKED)
360 strcat(buf, ", MASKED");
366 * Prints various local APIC registers of interest to the console.
373 printk(KERN_DEBUG "LOCAL APIC DUMP (LOGICAL CPU #%d):\n", this_cpu);
376 * Lead off with the important stuff...
379 " ID: 0x%08x (id=%d)\n",
381 GET_APIC_ID(apic_read(APIC_ID))
384 " VER: 0x%08x (version=0x%x, max_lvt=%d)\n",
386 GET_APIC_VERSION(apic_read(APIC_LVR)),
387 GET_APIC_MAXLVT(apic_read(APIC_LVR))
390 " ESR: 0x%08x (Error Status Reg, non-zero is bad)\n",
394 " SVR: 0x%08x (Spurious vector=%d, %s)\n",
395 apic_read(APIC_SPIV),
396 apic_read(APIC_SPIV) & APIC_VECTOR_MASK,
397 (apic_read(APIC_SPIV) & APIC_SPIV_APIC_ENABLED)
405 printk(KERN_DEBUG " Local Vector Table Entries:\n");
406 printk(KERN_DEBUG " LVT[0] Timer: 0x%08x (%s)\n",
407 apic_read(APIC_LVTT),
408 lvt_stringify(apic_read(APIC_LVTT), buf)
410 printk(KERN_DEBUG " LVT[1] Thermal: 0x%08x (%s)\n",
411 apic_read(APIC_LVTTHMR),
412 lvt_stringify(apic_read(APIC_LVTTHMR), buf)
414 printk(KERN_DEBUG " LVT[2] Perf Cnt: 0x%08x (%s)\n",
415 apic_read(APIC_LVTPC),
416 lvt_stringify(apic_read(APIC_LVTPC), buf)
418 printk(KERN_DEBUG " LVT[3] LINT0 Pin: 0x%08x (%s)\n",
419 apic_read(APIC_LVT0),
420 lvt_stringify(apic_read(APIC_LVT0), buf)
422 printk(KERN_DEBUG " LVT[4] LINT1 Pin: 0x%08x (%s)\n",
423 apic_read(APIC_LVT1),
424 lvt_stringify(apic_read(APIC_LVT1), buf)
426 printk(KERN_DEBUG " LVT[5] Error: 0x%08x (%s)\n",
427 apic_read(APIC_LVTERR),
428 lvt_stringify(apic_read(APIC_LVTERR), buf)
432 * APIC timer configuration registers
434 printk(KERN_DEBUG " Local APIC Timer:\n");
435 printk(KERN_DEBUG " DCR (Divide Config Reg): 0x%08x\n",
438 printk(KERN_DEBUG " ICT (Initial Count Reg): 0x%08x\n",
439 apic_read(APIC_TMICT)
441 printk(KERN_DEBUG " CCT (Current Count Reg): 0x%08x\n",
442 apic_read(APIC_TMCCT)
446 * Logical APIC addressing mode registers
448 printk(KERN_DEBUG " Logical Addressing Mode Information:\n");
449 printk(KERN_DEBUG " LDR (Logical Dest Reg): 0x%08x (id=%d)\n",
451 GET_APIC_LOGICAL_ID(apic_read(APIC_LDR))
453 printk(KERN_DEBUG " DFR (Dest Format Reg): 0x%08x (%s)\n",
455 (apic_read(APIC_DFR) == APIC_DFR_FLAT) ? "FLAT" : "CLUSTER"
459 * Task/processor/arbitration priority registers
461 printk(KERN_DEBUG " Task/Processor/Arbitration Priorities:\n");
462 printk(KERN_DEBUG " TPR (Task Priority Reg): 0x%08x\n",
463 apic_read(APIC_TASKPRI)
465 printk(KERN_DEBUG " PPR (Processor Priority Reg): 0x%08x\n",
466 apic_read(APIC_PROCPRI)
468 printk(KERN_DEBUG " APR (Arbitration Priority Reg): 0x%08x\n",
469 apic_read(APIC_ARBPRI)