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 / 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] = { 1 };
30
31 /**
32  * Addresses of the IO APICs in the system.
33  * The array is indexed by ioapic_index.
34  */
35 uintptr_t ioapic_phys_addr[MAX_IO_APICS] = { 0xFEC00000 };
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         {
254                 printk( "%s: Faking IO APIC\n", __func__ );
255                 ioapic_num = 1;
256         }
257
258         /*
259          * Allocate enough memory for one resource structure per detected IO
260          * APIC in the system. Memory for the resource name strings is tacked
261          * onto the end of the allocation (name_size*ioapic_num bytes).
262          */
263         ioapic_resources = alloc_bootmem(ioapic_num *
264                                          (sizeof(struct resource) + name_size));
265         name = ((char *)ioapic_resources) + ioapic_num*sizeof(struct resource);
266
267         for (i = 0; i < ioapic_num; i++) {
268                 /* Reserve the physical memory used by the IO APIC */
269                 sprintf(name, "IO APIC %u", i);
270                 ioapic_resources[i].name  = name;
271                 ioapic_resources[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
272                 ioapic_resources[i].start = ioapic_phys_addr[i];
273                 ioapic_resources[i].end   = ioapic_phys_addr[i] + 4096 - 1;
274                 request_resource(&iomem_resource, &ioapic_resources[i]);
275                 name += name_size;
276
277                 /* Map the IO APIC into the kernel */
278                 set_fixmap_nocache(FIX_IO_APIC_BASE_0 + i, ioapic_phys_addr[i]);
279
280                 printk(KERN_DEBUG
281                        "IO APIC mapped to virtual address 0x%016lx\n",
282                        __fix_to_virt(FIX_IO_APIC_BASE_0 + i)
283                 );
284         }
285 }
286
287 /**
288  * Initializes all IO APICs in the system.
289  */
290 void __init
291 ioapic_init(void)
292 {
293         if (ioapic_num == 0)
294                 return;
295
296 /* TODO: FIX THIS... NEED TO PARSE MPTABLE OR SOMETHING ELSE */
297 #ifdef CONFIG_PC
298         /* TODO: For now, only initializes the first one. */
299         ioapic_init_primary(0);
300         ioapic_dump();
301 #endif
302 }
303
304 /**
305  * Dumps the current state of all IO APICs in the system.
306  */
307 void __init
308 ioapic_dump(void)
309 {
310         unsigned int ioapic_index, pin;
311         union IO_APIC_reg_00 reg_00;
312         union IO_APIC_reg_01 reg_01;
313         union IO_APIC_reg_02 reg_02;
314         struct IO_APIC_route_entry entry;
315         unsigned long flags;
316
317         for (ioapic_index = 0; ioapic_index < ioapic_num; ioapic_index++) {
318
319                 spin_lock_irqsave(&ioapic_lock, flags);
320                 reg_00.raw = ioapic_read(ioapic_index, 0);
321                 reg_01.raw = ioapic_read(ioapic_index, 1);
322                 if (reg_01.bits.version >= 0x10)
323                     reg_02.raw = ioapic_read(ioapic_index, 2);
324                 spin_unlock_irqrestore(&ioapic_lock, flags);
325
326                 printk(KERN_DEBUG "Dump of IO APIC %u (physical id %u):\n",
327                                   ioapic_index, ioapic_id[ioapic_index]);
328                 printk(KERN_DEBUG "  register #00: %08X\n", reg_00.raw);
329                 printk(KERN_DEBUG "    physical APIC id: %02u\n", reg_00.bits.ID);
330                 printk(KERN_DEBUG "  register #01: %08X\n", *(int *)&reg_01);
331                 printk(KERN_DEBUG "    max redirection entries: %04X\n", reg_01.bits.entries);
332                 printk(KERN_DEBUG "    PRQ implemented: %X\n", reg_01.bits.PRQ);
333                 printk(KERN_DEBUG "    IO APIC version: %04X\n", reg_01.bits.version);
334                 if (reg_01.bits.version >= 0x10) {
335                         printk(KERN_DEBUG "  register #02: %08X\n", reg_02.raw);
336                         printk(KERN_DEBUG "    arbitration: %02X\n", reg_02.bits.arbitration);
337                 }
338
339                 printk(KERN_DEBUG "  Interrupt Redirection Table:\n");
340                 for (pin = 0; pin <= reg_01.bits.entries; pin++) {
341                         entry = ioapic_read_pin(ioapic_index, pin);
342                         printk(KERN_DEBUG
343                                "    %02u: vector=%u dest=%03u mask=%1d "
344                                          "trigger=%1d irr=%1d polarity=%1d\n",
345                                       pin, entry.vector, entry.dest, entry.mask,
346                                       entry.trigger, entry.irr, entry.polarity);
347                         printk(KERN_DEBUG
348                                "        dest_mode=%1d delivery_mode=%1d "
349                                        "delivery_status=%1d\n",
350                                       entry.dest_mode, entry.delivery_mode,
351                                       entry.delivery_status);
352                 }
353         }
354 }
355