Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel'
[palacios.git] / kitten / arch / x86_64 / kernel / lapic.c
1 #include <lwk/kernel.h>
2 #include <lwk/init.h>
3 #include <lwk/resource.h>
4 #include <lwk/cpuinfo.h>
5 #include <lwk/smp.h>
6 #include <lwk/delay.h>
7 #include <arch/page.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>
13 #include <arch/tsc.h>
14
15 /**
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.
20  */
21 unsigned long lapic_phys_addr = APIC_DEFAULT_PHYS_BASE;
22
23 /**
24  * Resource entry for the local APIC memory mapping.
25  */
26 static struct resource lapic_resource = {
27         .name  = "Local APIC",
28         .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
29         /* .start and .end filled in later based on detected address */
30 };
31
32 /**
33  * Creates a kernel mapping for the local APIC.
34  *
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.
41  */
42 void __init
43 lapic_map(void)
44 {
45         if (!cpu_has_apic)
46                 panic("No local APIC.");
47
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);
52
53         /* Map local APIC into the kernel */ 
54         set_fixmap_nocache(FIX_APIC_BASE, lapic_phys_addr);
55
56         printk(KERN_DEBUG "Local APIC mapped to virtual address 0x%016lx\n",
57                           fix_to_virt(FIX_APIC_BASE));
58 }
59
60 /**
61  * Initializes the calling CPU's local APIC.
62  */
63 void __init
64 lapic_init(void)
65 {
66         uint32_t val;
67
68         /*
69          * Initialize Destination Format Register.
70          * When using logical destination mode, we want to use the flat model.
71          */
72         apic_write(APIC_DFR, APIC_DFR_FLAT);
73
74         /*
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.
78          */
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);
82
83         /*
84          * Initialize the Task Priority Register.
85          * We set this to accept all (0) and never touch it again.
86          */
87         val = apic_read(APIC_TASKPRI) & ~APIC_TPRI_MASK;
88         apic_write(APIC_TASKPRI, val);
89
90         /*
91          * Intialize the Spurious-Interrupt Vector Register.
92          * This also enables the local APIC.
93          */
94         val = apic_read(APIC_SPIV) & ~APIC_VECTOR_MASK;
95         val |= (APIC_SPIV_APIC_ENABLED | APIC_SPURIOUS_VECTOR);
96         apic_write(APIC_SPIV, val);
97
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 */
103         );
104
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 */
109         );
110
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 */
116         );
117
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 */
123         );
124
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 */
129                      | ((this_cpu != 0)
130                          ? APIC_LVT_MASKED /* mask on all but bootstrap CPU */
131                          : 0)              /* bootstrap CPU (0) receives NMIs */
132         );
133
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 */
138         );
139         apic_write(APIC_ESR, 0); /* spec says to clear after enabling LVTERR */
140 }
141
142 void 
143 lapic_set_timer(uint32_t count)
144 {
145         uint32_t lvt;
146
147         /* Setup Divide Count Register to use the bus frequency directly. */
148         apic_write(APIC_TDCR, APIC_TDR_DIV_1);
149
150         /* Program the initial count register */
151         apic_write(APIC_TMICT, count);
152
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);
158 }
159
160 void
161 lapic_stop_timer(void)
162 {
163         uint32_t lvt;
164
165         /* Set the initial count to 0 */
166         apic_write(APIC_TMICT, 0);
167
168         /* Enable the local APIC timer */
169         lvt = apic_read(APIC_LVTT);
170         lvt |= APIC_LVT_MASKED;
171         apic_write(APIC_LVTT, lvt);
172 }
173
174 /**
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.
178  *
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.
181  */
182 unsigned int __init
183 lapic_calibrate_timer(void)
184 {
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;
189
190         /* Start the APIC counter running for calibration */
191         lapic_set_timer(4000000000);
192
193         apic_start = apic_read(APIC_TMCCT);
194         tsc_start  = get_cycles_sync();
195
196         /* Spin until enough ticks for a meaningful result have elapsed */
197         do {
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) );
202
203         apic_Hz = (apic_start - apic_now) * 1000L *
204                   cpu_info[this_cpu].arch.tsc_khz / (tsc_now - tsc_start);
205
206         lapic_stop_timer();
207
208         return (apic_Hz / 1000);
209 }
210
211 static uint32_t
212 lapic_wait4_icr_idle(void)
213 {
214         uint32_t send_status;
215         int timeout;
216
217         /* Wait up to 100 milliseconds */
218         timeout = 0;
219         do {
220                 send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
221                 if (!send_status)
222                         break;
223                 udelay(100);
224         } while (timeout++ < 1000);
225
226         return send_status;
227 }
228
229 /**
230  * Returns the number of entries in the Local Vector Table minus one.
231  * 
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.
234  */
235 static uint32_t
236 lapic_get_maxlvt(void)
237 {
238         return GET_APIC_MAXLVT(apic_read(APIC_LVR));
239 }
240
241 /**
242  * Sends an INIT inter-processor interrupt.
243  * This is used during bootstrap to wakeup the AP CPUs.
244  */
245 void __init
246 lapic_send_init_ipi(unsigned int cpu)
247 {
248         uint32_t status;
249         unsigned int apic_id = cpu_info[cpu].arch.apic_id;
250
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
254                                 | APIC_DM_INIT);
255         status = lapic_wait4_icr_idle();
256         if (status)
257                 panic("INIT IPI ERROR: failed to assert INIT. (%x)", status);
258         mdelay(10);
259
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();
264         if (status)
265                 panic("INIT IPI ERROR: failed to deassert INIT. (%x)", status);
266 }
267
268 /**
269  * Send a STARTUP inter-processor interrupt.
270  * This is used during bootstrap to wakeup the AP CPUs.
271  */
272 void __init
273 lapic_send_startup_ipi(
274         unsigned int    cpu,            /* Logical CPU ID */
275         unsigned long   start_rip       /* Physical addr  */
276 )
277 {
278         uint32_t status;
279         unsigned int maxlvt  = lapic_get_maxlvt();
280         unsigned int apic_id = cpu_info[cpu].arch.apic_id;
281
282         /* Clear errors */
283         apic_write(APIC_ESR, 0);
284         apic_read(APIC_ESR);
285
286         /* Set target CPU */
287         apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
288
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();
294         if (status)
295                 panic("STARTUP IPI ERROR: failed to send. (%x)", status);
296         udelay(300);  /* Give AP CPU some time to accept the IPI */
297
298         /* Fixup for Pentium erratum 3AP, clear errors */
299         if (maxlvt > 3)
300                 apic_write(APIC_ESR, 0);
301
302         /* Verify that IPI was accepted */
303         status = (apic_read(APIC_ESR) & 0xEF);
304         if (status)
305                 panic("STARTUP IPI ERROR: failed to accept. (%x)", status);
306 }
307
308 /**
309  * Sends an inter-processor interrupt (IPI) to the specified CPU.
310  * Note that the IPI has not necessarily been delivered when this function
311  * returns.
312  */
313 void
314 lapic_send_ipi(
315         unsigned int    cpu,            /* Logical CPU ID */
316         unsigned int    vector          /* Interrupt vector to send */
317 )
318 {
319         uint32_t status;
320         unsigned int apic_id;
321
322         /* Wait for idle */
323         status = lapic_wait4_icr_idle();
324         if (status)
325                 panic("lapic_wait4_icr_idle() timed out. (%x)", status);
326
327         /* Set target CPU */
328         apic_id = cpu_info[cpu].arch.apic_id;
329         apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apic_id));
330
331         /* Send the IPI */
332         if (unlikely(vector == NMI_VECTOR))
333                 apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_NMI);
334         else
335                 apic_write(APIC_ICR, APIC_DEST_PHYSICAL|APIC_DM_FIXED|vector);
336 }
337
338 /**
339  * Converts an entry in a local APIC's Local Vector Table to a
340  * human-readable string.
341  */
342 static char *
343 lvt_stringify(uint32_t entry, char *buf)
344 {
345         uint32_t delivery_mode = GET_APIC_DELIVERY_MODE(entry);
346
347         if (delivery_mode == APIC_MODE_FIXED) {
348                 sprintf(buf, "FIXED -> IDT_VECTOR %d",
349                         entry & APIC_VECTOR_MASK
350                 );
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");
355         } else {
356                 sprintf(buf, "UNKNOWN");
357         }
358
359         if (entry & APIC_LVT_MASKED)
360                 strcat(buf, ", MASKED");
361
362         return buf;
363 }
364
365 /**
366  * Prints various local APIC registers of interest to the console.
367  */
368 void
369 lapic_dump(void)
370 {
371         char buf[128];
372
373         printk(KERN_DEBUG "LOCAL APIC DUMP (LOGICAL CPU #%d):\n", this_cpu);
374
375         /*
376          * Lead off with the important stuff...
377          */
378         printk(KERN_DEBUG
379                 "  ID:  0x%08x (id=%d)\n",
380                 apic_read(APIC_ID),
381                 GET_APIC_ID(apic_read(APIC_ID))
382         );
383         printk(KERN_DEBUG
384                 "  VER: 0x%08x (version=0x%x, max_lvt=%d)\n",
385                 apic_read(APIC_LVR),
386                 GET_APIC_VERSION(apic_read(APIC_LVR)),
387                 GET_APIC_MAXLVT(apic_read(APIC_LVR))
388         );
389         printk(KERN_DEBUG
390                 "  ESR: 0x%08x (Error Status Reg, non-zero is bad)\n",
391                 apic_read(APIC_ESR)
392         );
393         printk(KERN_DEBUG
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)
398                         ? "APIC IS ENABLED"
399                         : "APIC IS DISABLED"
400         );
401
402         /*
403          * Local Vector Table
404          */
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)
409         );
410         printk(KERN_DEBUG "      LVT[1] Thermal:   0x%08x (%s)\n",
411                 apic_read(APIC_LVTTHMR),
412                 lvt_stringify(apic_read(APIC_LVTTHMR), buf)
413         );
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)
417         );
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)
421         );
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)
425         );
426         printk(KERN_DEBUG "      LVT[5] Error:     0x%08x (%s)\n",
427                 apic_read(APIC_LVTERR),
428                 lvt_stringify(apic_read(APIC_LVTERR), buf)
429         );
430
431         /*
432          * APIC timer configuration registers
433          */
434         printk(KERN_DEBUG "  Local APIC Timer:\n");
435         printk(KERN_DEBUG "      DCR (Divide Config Reg): 0x%08x\n",
436                 apic_read(APIC_TDCR)
437         );
438         printk(KERN_DEBUG "      ICT (Initial Count Reg): 0x%08x\n",
439                 apic_read(APIC_TMICT)
440         );
441         printk(KERN_DEBUG "      CCT (Current Count Reg): 0x%08x\n",
442                 apic_read(APIC_TMCCT)
443         );
444
445         /*
446          * Logical APIC addressing mode registers
447          */
448         printk(KERN_DEBUG "  Logical Addressing Mode Information:\n");
449         printk(KERN_DEBUG "      LDR (Logical Dest Reg):  0x%08x (id=%d)\n",
450                 apic_read(APIC_LDR),
451                 GET_APIC_LOGICAL_ID(apic_read(APIC_LDR))
452         );
453         printk(KERN_DEBUG "      DFR (Dest Format Reg):   0x%08x (%s)\n",
454                 apic_read(APIC_DFR),
455                 (apic_read(APIC_DFR) == APIC_DFR_FLAT) ? "FLAT" : "CLUSTER"
456         );
457
458         /*
459          * Task/processor/arbitration priority registers
460          */
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)
464         );
465         printk(KERN_DEBUG "      PPR (Processor Priority Reg):   0x%08x\n",
466                 apic_read(APIC_PROCPRI)
467         );
468         printk(KERN_DEBUG "      APR (Arbitration Priority Reg): 0x%08x\n",
469                 apic_read(APIC_ARBPRI)
470         );
471 }
472