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.


6c5fc9846d8e7b8c4d7ee7fb489ca680f6d45127
[palacios.git] / kitten / arch / x86_64 / kernel / ioapic.c
1 #include <lwk/kernel.h>
2 #include <lwk/init.h>
3 #include <lwk/resource.h>
4 #include <lwk/bootmem.h>
5 #include <lwk/spinlock.h>
6 #include <lwk/cpuinfo.h>
7 #include <arch/io.h>
8 #include <arch/pgtable.h>
9 #include <arch/fixmap.h>
10 #include <arch/apicdef.h>
11 #include <arch/io_apic.h>
12 #include <arch/idt_vectors.h>
13
14 /**
15  * Lock that protects access to the IO APICs in the system.
16  * There is only one lock for all IO APICs.
17  */
18 static DEFINE_SPINLOCK(ioapic_lock);
19
20 /**
21  * Number of IO APICs in the system.
22  */
23 unsigned int ioapic_num;
24
25 /**
26  * Array containing the IDs of the IO APICs in the system.
27  * The array is indexed by ioapic_index.
28  */
29 unsigned int ioapic_id[MAX_IO_APICS];
30
31 /**
32  * Addresses of the IO APICs in the system.
33  * The array is indexed by ioapic_index.
34  */
35 unsigned long ioapic_phys_addr[MAX_IO_APICS];
36
37 /**
38  * Resource entries for the IO APIC memory mapping.
39  */
40 static struct resource *ioapic_resources;
41
42 /**
43  * Structure used to map IO APIC registers.
44  */
45 struct ioapic {
46         uint32_t index;
47         uint32_t unused[3];
48         uint32_t data;
49 };
50
51 /**
52  * Union used to map an IO APIC routing entry register.
53  */
54 union ioapic_entry_union {
55         struct { uint32_t low_word, high_word; };
56         struct IO_APIC_route_entry entry;
57 };
58
59 /**
60  * Returns the base kernel virtual address of the specified IO APIC's
61  * kernel mapping.
62  */
63 static struct ioapic *
64 ioapic_base_addr(int ioapic_index)
65 {
66         return (void *) __fix_to_virt(FIX_IO_APIC_BASE_0 + ioapic_index)
67                  + (ioapic_phys_addr[ioapic_index] & ~PAGE_MASK);
68 }
69
70 /**
71  * Reads a value from an IO APIC register.
72  */
73 static uint32_t
74 ioapic_read(unsigned int ioapic_index, uint32_t reg)
75 {
76         struct ioapic *ioapic = ioapic_base_addr(ioapic_index);
77         writel(reg, &ioapic->index);
78         return readl(&ioapic->data);
79 }
80
81 /**
82  * Writes a value to an IO APIC register.
83  */
84 static void
85 ioapic_write(unsigned int ioapic_index, uint32_t reg, uint32_t value)
86 {
87         struct ioapic *ioapic = ioapic_base_addr(ioapic_index);
88         writel(reg, &ioapic->index);
89         writel(value, &ioapic->data);
90 }
91
92 /**
93  * Reads an IO APIC pin routing entry.
94  */
95 static struct IO_APIC_route_entry
96 ioapic_read_pin(
97         unsigned int ioapic_index,
98         unsigned int pin
99 )
100 {
101         union ioapic_entry_union eu;
102         unsigned long flags;
103
104         spin_lock_irqsave(&ioapic_lock, flags);
105         eu.low_word  = ioapic_read(ioapic_index, 0x10 + 2 * pin);
106         eu.high_word = ioapic_read(ioapic_index, 0x11 + 2 * pin);
107         spin_unlock_irqrestore(&ioapic_lock, flags);
108
109         return eu.entry;
110 }
111
112 /**
113  * Writes an IO APIC pin routing entry.
114  *
115  * When we write a new IO APIC routing entry, we need to write the high word
116  * first. This is because the mask/enable bit is in the low word and we do not
117  * want to enable the entry before it is fully populated.
118  */
119 static void
120 ioapic_write_pin(
121         unsigned int               ioapic_index,
122         unsigned int               pin,
123         struct IO_APIC_route_entry pin_config
124 )
125 {
126         union ioapic_entry_union eu;
127         unsigned long flags;
128
129         spin_lock_irqsave(&ioapic_lock, flags);
130         eu.entry = pin_config;
131         ioapic_write(ioapic_index, 0x11 + 2 * pin, eu.high_word);
132         ioapic_write(ioapic_index, 0x10 + 2 * pin, eu.low_word);
133         spin_unlock_irqrestore(&ioapic_lock, flags);
134 }
135
136 /**
137  * Masks (disables) an IO APIC input pin.
138  */
139 static void
140 ioapic_mask_pin(
141         unsigned int ioapic_index,
142         unsigned int pin
143 )
144 {
145         struct IO_APIC_route_entry pin_config =
146                                         ioapic_read_pin(ioapic_index, pin);
147         pin_config.mask = 1;
148         ioapic_write_pin(ioapic_index, pin, pin_config);
149 }
150
151 /**
152  * Unmasks (enables) an IO APIC input pin.
153  */
154 static void
155 ioapic_unmask_pin(
156         unsigned int ioapic_index,
157         unsigned int pin
158 )
159 {
160         struct IO_APIC_route_entry pin_config =
161                                         ioapic_read_pin(ioapic_index, pin);
162         pin_config.mask = 0;
163         ioapic_write_pin(ioapic_index, pin, pin_config);
164 }
165
166 /**
167  * Returns the number of input pins provided by the specified IO APIC.
168  */
169 static unsigned int
170 ioapic_get_num_pins(unsigned int ioapic_index)
171 {
172         union IO_APIC_reg_01 reg_01;
173
174         reg_01.raw = ioapic_read(ioapic_index, 1);
175         return reg_01.bits.entries + 1;
176 }
177
178 /**
179  * Initializes the primary IO APIC (the one connected to the ISA IRQs).
180  */
181 static void __init
182 ioapic_init_primary(
183         unsigned int ioapic_index
184 )
185 {
186         unsigned int pin;
187         unsigned int num_pins = ioapic_get_num_pins(ioapic_index);
188         struct IO_APIC_route_entry cfg;
189
190         if (num_pins != 24)
191                 panic("Expected IOAPIC to have 24 pins, has %u.", num_pins);
192
193         /* Mask (disable) all pins */
194         for (pin = 0; pin < num_pins; pin++) {
195                 ioapic_mask_pin(ioapic_index, pin);
196         }
197
198         /*
199          * Configure ISA IRQs.
200          * (Assuming pins [1,15] are the standard ISA IRQs)
201          * (Assuming pin 2 is hooked to the timer interrupt)
202          * (Assuming pin 0 is hooked to the old i8259 PIC... don't use it)
203          */
204         for (pin = 1; pin <= 15; pin++) {
205                 cfg = ioapic_read_pin(ioapic_index, pin);
206
207                 cfg.delivery_mode = ioapic_fixed;
208                 cfg.dest_mode     = ioapic_physical_dest;
209                 cfg.polarity      = (pin == 8)
210                                         ? ioapic_active_low
211                                         : ioapic_active_high;
212                 cfg.trigger       = ioapic_edge_sensitive;
213                 cfg.dest          = (uint8_t) cpu_info[0].physical_id;
214                 cfg.vector        = IRQ0_VECTOR + pin;
215
216                 ioapic_write_pin(ioapic_index, pin, cfg);
217         }
218
219         /*
220          * Configure PCI IRQs.
221          * (Assuming pins [16,19] are PCI INTA, INTB, INTC, and INTD)
222          */
223         for (pin = 16; pin <= 19; pin++) {
224                 cfg = ioapic_read_pin(ioapic_index, pin);
225
226                 cfg.delivery_mode = ioapic_fixed;
227                 cfg.dest_mode     = ioapic_physical_dest;
228                 cfg.polarity      = ioapic_active_low;
229                 cfg.trigger       = ioapic_level_sensitive;
230                 cfg.dest          = (uint8_t) cpu_info[0].physical_id;
231                 cfg.vector        = IRQ0_VECTOR + pin;
232
233                 ioapic_write_pin(ioapic_index, pin, cfg);
234         } 
235
236         /* Unmask (enable) all of the pins that have been configured */
237         for (pin = 1; pin < 19; pin++) {
238                 ioapic_unmask_pin(ioapic_index, pin);
239         }
240 }
241
242 /**
243  * Creates a kernel mapping for all IO APICs in the system.
244  */
245 void __init
246 ioapic_map(void)
247 {
248         unsigned int i;
249         const int name_size = 16;
250         char *name;
251
252         if (ioapic_num == 0)
253                 return;
254
255         /*
256          * Allocate enough memory for one resource structure per detected IO
257          * APIC in the system. Memory for the resource name strings is tacked
258          * onto the end of the allocation (name_size*ioapic_num bytes).
259          */
260         ioapic_resources = alloc_bootmem(ioapic_num *
261                                          (sizeof(struct resource) + name_size));
262         name = ((char *)ioapic_resources) + ioapic_num*sizeof(struct resource);
263
264         for (i = 0; i < ioapic_num; i++) {
265                 /* Reserve the physical memory used by the IO APIC */
266                 sprintf(name, "IO APIC %u", i);
267                 ioapic_resources[i].name  = name;
268                 ioapic_resources[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
269                 ioapic_resources[i].start = ioapic_phys_addr[i];
270                 ioapic_resources[i].end   = ioapic_phys_addr[i] + 4096 - 1;
271                 request_resource(&iomem_resource, &ioapic_resources[i]);
272                 name += name_size;
273
274                 /* Map the IO APIC into the kernel */
275                 set_fixmap_nocache(FIX_IO_APIC_BASE_0 + i, ioapic_phys_addr[i]);
276
277                 printk(KERN_DEBUG
278                        "IO APIC mapped to virtual address 0x%016lx\n",
279                        __fix_to_virt(FIX_IO_APIC_BASE_0 + i)
280                 );
281         }
282 }
283
284 /**
285  * Initializes all IO APICs in the system.
286  */
287 void __init
288 ioapic_init(void)
289 {
290         if (ioapic_num == 0)
291                 return;
292
293 /* TODO: FIX THIS... NEED TO PARSE MPTABLE OR SOMETHING ELSE */
294 #ifdef CONFIG_PC
295         /* TODO: For now, only initializes the first one. */
296         ioapic_init_primary(0);
297         ioapic_dump();
298 #endif
299 }
300
301 /**
302  * Dumps the current state of all IO APICs in the system.
303  */
304 void __init
305 ioapic_dump(void)
306 {
307         unsigned int ioapic_index, pin;
308         union IO_APIC_reg_00 reg_00;
309         union IO_APIC_reg_01 reg_01;
310         union IO_APIC_reg_02 reg_02;
311         struct IO_APIC_route_entry entry;
312         unsigned long flags;
313
314         for (ioapic_index = 0; ioapic_index < ioapic_num; ioapic_index++) {
315
316                 spin_lock_irqsave(&ioapic_lock, flags);
317                 reg_00.raw = ioapic_read(ioapic_index, 0);
318                 reg_01.raw = ioapic_read(ioapic_index, 1);
319                 if (reg_01.bits.version >= 0x10)
320                     reg_02.raw = ioapic_read(ioapic_index, 2);
321                 spin_unlock_irqrestore(&ioapic_lock, flags);
322
323                 printk(KERN_DEBUG "Dump of IO APIC %u (physical id %u):\n",
324                                   ioapic_index, ioapic_id[ioapic_index]);
325                 printk(KERN_DEBUG "  register #00: %08X\n", reg_00.raw);
326                 printk(KERN_DEBUG "    physical APIC id: %02u\n", reg_00.bits.ID);
327                 printk(KERN_DEBUG "  register #01: %08X\n", *(int *)&reg_01);
328                 printk(KERN_DEBUG "    max redirection entries: %04X\n", reg_01.bits.entries);
329                 printk(KERN_DEBUG "    PRQ implemented: %X\n", reg_01.bits.PRQ);
330                 printk(KERN_DEBUG "    IO APIC version: %04X\n", reg_01.bits.version);
331                 if (reg_01.bits.version >= 0x10) {
332                         printk(KERN_DEBUG "  register #02: %08X\n", reg_02.raw);
333                         printk(KERN_DEBUG "    arbitration: %02X\n", reg_02.bits.arbitration);
334                 }
335
336                 printk(KERN_DEBUG "  Interrupt Redirection Table:\n");
337                 for (pin = 0; pin <= reg_01.bits.entries; pin++) {
338                         entry = ioapic_read_pin(ioapic_index, pin);
339                         printk(KERN_DEBUG
340                                "    %02u: vector=%u dest=%03u mask=%1d "
341                                          "trigger=%1d irr=%1d polarity=%1d\n",
342                                       pin, entry.vector, entry.dest, entry.mask,
343                                       entry.trigger, entry.irr, entry.polarity);
344                         printk(KERN_DEBUG
345                                "        dest_mode=%1d delivery_mode=%1d "
346                                        "delivery_status=%1d\n",
347                                       entry.dest_mode, entry.delivery_mode,
348                                       entry.delivery_status);
349                 }
350         }
351 }
352