initial APIC support
[qemu] / hw / apic.c
1 /*
2  *  APIC support
3  * 
4  *  Copyright (c) 2004-2005 Fabrice Bellard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include "vl.h"
21
22 //#define DEBUG_APIC
23
24 /* APIC Local Vector Table */
25 #define APIC_LVT_TIMER   0
26 #define APIC_LVT_THERMAL 1
27 #define APIC_LVT_PERFORM 2
28 #define APIC_LVT_LINT0   3
29 #define APIC_LVT_LINT1   4
30 #define APIC_LVT_ERROR   5
31 #define APIC_LVT_NB      6
32
33 /* APIC delivery modes */
34 #define APIC_DM_FIXED   0
35 #define APIC_DM_LOWPRI  1
36 #define APIC_DM_SMI     2
37 #define APIC_DM_NMI     4
38 #define APIC_DM_INIT    5
39 #define APIC_DM_SIPI    6
40 #define APIC_DM_EXTINT  7
41
42 #define APIC_TRIGGER_EDGE  0
43 #define APIC_TRIGGER_LEVEL 1
44
45 #define APIC_LVT_TIMER_PERIODIC         (1<<17)
46 #define APIC_LVT_MASKED                 (1<<16)
47 #define APIC_LVT_LEVEL_TRIGGER          (1<<15)
48 #define APIC_LVT_REMOTE_IRR             (1<<14)
49 #define APIC_INPUT_POLARITY             (1<<13)
50 #define APIC_SEND_PENDING               (1<<12)
51
52 #define ESR_ILLEGAL_ADDRESS (1 << 7)
53
54 #define APIC_SV_ENABLE (1 << 8)
55
56 typedef struct APICState {
57     CPUState *cpu_env;
58     uint32_t apicbase;
59     uint8_t id;
60     uint8_t tpr;
61     uint32_t spurious_vec;
62     uint32_t isr[8];  /* in service register */
63     uint32_t tmr[8];  /* trigger mode register */
64     uint32_t irr[8]; /* interrupt request register */
65     uint32_t lvt[APIC_LVT_NB];
66     uint32_t esr; /* error register */
67     uint32_t icr[2];
68
69     uint32_t divide_conf;
70     int count_shift;
71     uint32_t initial_count;
72     int64_t initial_count_load_time, next_time;
73     QEMUTimer *timer;
74 } APICState;
75
76 static int apic_io_memory;
77
78 void cpu_set_apic_base(CPUState *env, uint64_t val)
79 {
80     APICState *s = env->apic_state;
81 #ifdef DEBUG_APIC
82     printf("cpu_set_apic_base: %016llx\n", val);
83 #endif
84     s->apicbase = (val & 0xfffff000) | 
85         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
86     /* if disabled, cannot be enabled again */
87     if (!(val & MSR_IA32_APICBASE_ENABLE)) {
88         s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
89         env->cpuid_features &= ~CPUID_APIC;
90         s->spurious_vec &= ~APIC_SV_ENABLE;
91     }
92 }
93
94 uint64_t cpu_get_apic_base(CPUState *env)
95 {
96     APICState *s = env->apic_state;
97 #ifdef DEBUG_APIC
98     printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
99 #endif
100     return s->apicbase;
101 }
102
103 /* return -1 if no bit is set */
104 static int get_highest_priority_int(uint32_t *tab)
105 {
106     int i;
107     for(i = 0;i < 8; i++) {
108         if (tab[i] != 0) {
109             return i * 32 + ffs(tab[i]) - 1;
110         }
111     }
112     return -1;
113 }
114
115 static inline void set_bit(uint32_t *tab, int index)
116 {
117     int i, mask;
118     i = index >> 5;
119     mask = 1 << (index & 0x1f);
120     tab[i] |= mask;
121 }
122
123 static inline void reset_bit(uint32_t *tab, int index)
124 {
125     int i, mask;
126     i = index >> 5;
127     mask = 1 << (index & 0x1f);
128     tab[i] &= ~mask;
129 }
130
131 static int apic_get_ppr(APICState *s)
132 {
133     int tpr, isrv, ppr;
134
135     tpr = (s->tpr >> 4);
136     isrv = get_highest_priority_int(s->isr);
137     if (isrv < 0)
138         isrv = 0;
139     isrv >>= 4;
140     if (tpr >= isrv)
141         ppr = s->tpr;
142     else
143         ppr = isrv << 4;
144     return ppr;
145 }
146
147 /* signal the CPU if an irq is pending */
148 static void apic_update_irq(APICState *s)
149 {
150     int irrv, isrv;
151     irrv = get_highest_priority_int(s->irr);
152     if (irrv < 0)
153         return;
154     isrv = get_highest_priority_int(s->isr);
155     /* if the pending irq has less priority, we do not make a new request */
156     if (isrv >= 0 && irrv >= isrv)
157         return;
158     cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
159 }
160
161 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
162 {
163     set_bit(s->irr, vector_num);
164     if (trigger_mode)
165         set_bit(s->tmr, vector_num);
166     else
167         reset_bit(s->tmr, vector_num);
168     apic_update_irq(s);
169 }
170
171 static void apic_eoi(APICState *s)
172 {
173     int isrv;
174     isrv = get_highest_priority_int(s->isr);
175     if (isrv < 0)
176         return;
177     reset_bit(s->isr, isrv);
178     apic_update_irq(s);
179 }
180
181 int apic_get_interrupt(CPUState *env)
182 {
183     APICState *s = env->apic_state;
184     int intno;
185
186     /* if the APIC is installed or enabled, we let the 8259 handle the
187        IRQs */
188     if (!s)
189         return -1;
190     if (!(s->spurious_vec & APIC_SV_ENABLE))
191         return -1;
192     
193     /* XXX: spurious IRQ handling */
194     intno = get_highest_priority_int(s->irr);
195     if (intno < 0)
196         return -1;
197     reset_bit(s->irr, intno);
198     set_bit(s->isr, intno);
199     apic_update_irq(s);
200     return intno;
201 }
202
203 static uint32_t apic_get_current_count(APICState *s)
204 {
205     int64_t d;
206     uint32_t val;
207     d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> 
208         s->count_shift;
209     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
210         /* periodic */
211         val = s->initial_count - (d % (s->initial_count + 1));
212     } else {
213         if (d >= s->initial_count)
214             val = 0;
215         else
216             val = s->initial_count - d;
217     }
218     return val;
219 }
220
221 static void apic_timer_update(APICState *s, int64_t current_time)
222 {
223     int64_t next_time, d;
224     
225     if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
226         d = (current_time - s->initial_count_load_time) >> 
227             s->count_shift;
228         if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
229             d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1);
230         } else {
231             if (d >= s->initial_count)
232                 goto no_timer;
233             d = s->initial_count + 1;
234         }
235         next_time = s->initial_count_load_time + (d << s->count_shift);
236         qemu_mod_timer(s->timer, next_time);
237         s->next_time = next_time;
238     } else {
239     no_timer:
240         qemu_del_timer(s->timer);
241     }
242 }
243
244 static void apic_timer(void *opaque)
245 {
246     APICState *s = opaque;
247
248     if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
249         apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
250     }
251     apic_timer_update(s, s->next_time);
252 }
253
254 static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
255 {
256     return 0;
257 }
258
259 static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
260 {
261     return 0;
262 }
263
264 static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
265 {
266 }
267
268 static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
269 {
270 }
271
272 static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
273 {
274     CPUState *env;
275     APICState *s;
276     uint32_t val;
277     int index;
278
279     env = cpu_single_env;
280     if (!env)
281         return 0;
282     s = env->apic_state;
283
284     index = (addr >> 4) & 0xff;
285     switch(index) {
286     case 0x02: /* id */
287         val = s->id << 24;
288         break;
289     case 0x03: /* version */
290         val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
291         break;
292     case 0x08:
293         val = s->tpr;
294         break;
295     case 0x0a:
296         /* ppr */
297         val = apic_get_ppr(s);
298         break;
299     case 0x0f:
300         val = s->spurious_vec;
301         break;
302     case 0x10 ... 0x17:
303         val = s->isr[index & 7];
304         break;
305     case 0x18 ... 0x1f:
306         val = s->tmr[index & 7];
307         break;
308     case 0x20 ... 0x27:
309         val = s->irr[index & 7];
310         break;
311     case 0x28:
312         val = s->esr;
313         break;
314     case 0x32 ... 0x37:
315         val = s->lvt[index - 0x32];
316         break;
317     case 0x30:
318     case 0x31:
319         val = s->icr[index & 1];
320         break;
321     case 0x38:
322         val = s->initial_count;
323         break;
324     case 0x39:
325         val = apic_get_current_count(s);
326         break;
327     case 0x3e:
328         val = s->divide_conf;
329         break;
330     default:
331         s->esr |= ESR_ILLEGAL_ADDRESS;
332         val = 0;
333         break;
334     }
335 #ifdef DEBUG_APIC
336     printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
337 #endif
338     return val;
339 }
340
341 static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
342 {
343     CPUState *env;
344     APICState *s;
345     int index;
346
347     env = cpu_single_env;
348     if (!env)
349         return;
350     s = env->apic_state;
351
352 #ifdef DEBUG_APIC
353     printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
354 #endif
355
356     index = (addr >> 4) & 0xff;
357     switch(index) {
358     case 0x02:
359         s->id = (val >> 24);
360         break;
361     case 0x08:
362         s->tpr = val;
363         break;
364     case 0x0b: /* EOI */
365         apic_eoi(s);
366         break;
367     case 0x0f:
368         s->spurious_vec = val & 0x1ff;
369         break;
370     case 0x30:
371     case 0x31:
372         s->icr[index & 1] = val;
373         break;
374     case 0x32 ... 0x37:
375         {
376             int n = index - 0x32;
377             s->lvt[n] = val;
378             if (n == APIC_LVT_TIMER)
379                 apic_timer_update(s, qemu_get_clock(vm_clock));
380         }
381         break;
382     case 0x38:
383         s->initial_count = val;
384         s->initial_count_load_time = qemu_get_clock(vm_clock);
385         apic_timer_update(s, s->initial_count_load_time);
386         break;
387     case 0x3e:
388         {
389             int v;
390             s->divide_conf = val & 0xb;
391             v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
392             s->count_shift = (v + 1) & 7;
393         }
394         break;
395     default:
396         s->esr |= ESR_ILLEGAL_ADDRESS;
397         break;
398     }
399 }
400
401
402
403 static CPUReadMemoryFunc *apic_mem_read[3] = {
404     apic_mem_readb,
405     apic_mem_readw,
406     apic_mem_readl,
407 };
408
409 static CPUWriteMemoryFunc *apic_mem_write[3] = {
410     apic_mem_writeb,
411     apic_mem_writew,
412     apic_mem_writel,
413 };
414
415 int apic_init(CPUState *env)
416 {
417     APICState *s;
418     int i;
419
420     s = malloc(sizeof(APICState));
421     if (!s)
422         return -1;
423     memset(s, 0, sizeof(*s));
424     env->apic_state = s;
425     s->cpu_env = env;
426     s->apicbase = 0xfee00000 | 
427         MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;
428     for(i = 0; i < APIC_LVT_NB; i++)
429         s->lvt[i] = 1 << 16; /* mask LVT */
430     s->spurious_vec = 0xff;
431
432     if (apic_io_memory == 0) {
433         /* NOTE: the APIC is directly connected to the CPU - it is not
434            on the global memory bus. */
435         apic_io_memory = cpu_register_io_memory(0, apic_mem_read, 
436                                                 apic_mem_write, NULL);
437         cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory);
438     }
439     s->timer = qemu_new_timer(vm_clock, apic_timer, s);
440     return 0;
441 }