Statistics
| Branch: | Revision:

root / hw / apic.c @ db6e6ed7

History | View | Annotate | Download (24 kB)

1 574bbf7b bellard
/*
2 574bbf7b bellard
 *  APIC support
3 574bbf7b bellard
 * 
4 574bbf7b bellard
 *  Copyright (c) 2004-2005 Fabrice Bellard
5 574bbf7b bellard
 *
6 574bbf7b bellard
 * This library is free software; you can redistribute it and/or
7 574bbf7b bellard
 * modify it under the terms of the GNU Lesser General Public
8 574bbf7b bellard
 * License as published by the Free Software Foundation; either
9 574bbf7b bellard
 * version 2 of the License, or (at your option) any later version.
10 574bbf7b bellard
 *
11 574bbf7b bellard
 * This library is distributed in the hope that it will be useful,
12 574bbf7b bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 574bbf7b bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 574bbf7b bellard
 * Lesser General Public License for more details.
15 574bbf7b bellard
 *
16 574bbf7b bellard
 * You should have received a copy of the GNU Lesser General Public
17 574bbf7b bellard
 * License along with this library; if not, write to the Free Software
18 574bbf7b bellard
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 574bbf7b bellard
 */
20 574bbf7b bellard
#include "vl.h"
21 574bbf7b bellard
22 574bbf7b bellard
//#define DEBUG_APIC
23 d592d303 bellard
//#define DEBUG_IOAPIC
24 574bbf7b bellard
25 574bbf7b bellard
/* APIC Local Vector Table */
26 574bbf7b bellard
#define APIC_LVT_TIMER   0
27 574bbf7b bellard
#define APIC_LVT_THERMAL 1
28 574bbf7b bellard
#define APIC_LVT_PERFORM 2
29 574bbf7b bellard
#define APIC_LVT_LINT0   3
30 574bbf7b bellard
#define APIC_LVT_LINT1   4
31 574bbf7b bellard
#define APIC_LVT_ERROR   5
32 574bbf7b bellard
#define APIC_LVT_NB      6
33 574bbf7b bellard
34 574bbf7b bellard
/* APIC delivery modes */
35 574bbf7b bellard
#define APIC_DM_FIXED        0
36 574bbf7b bellard
#define APIC_DM_LOWPRI        1
37 574bbf7b bellard
#define APIC_DM_SMI        2
38 574bbf7b bellard
#define APIC_DM_NMI        4
39 574bbf7b bellard
#define APIC_DM_INIT        5
40 574bbf7b bellard
#define APIC_DM_SIPI        6
41 574bbf7b bellard
#define APIC_DM_EXTINT        7
42 574bbf7b bellard
43 d592d303 bellard
/* APIC destination mode */
44 d592d303 bellard
#define APIC_DESTMODE_FLAT        0xf
45 d592d303 bellard
#define APIC_DESTMODE_CLUSTER        1
46 d592d303 bellard
47 574bbf7b bellard
#define APIC_TRIGGER_EDGE  0
48 574bbf7b bellard
#define APIC_TRIGGER_LEVEL 1
49 574bbf7b bellard
50 574bbf7b bellard
#define        APIC_LVT_TIMER_PERIODIC                (1<<17)
51 574bbf7b bellard
#define        APIC_LVT_MASKED                        (1<<16)
52 574bbf7b bellard
#define        APIC_LVT_LEVEL_TRIGGER                (1<<15)
53 574bbf7b bellard
#define        APIC_LVT_REMOTE_IRR                (1<<14)
54 574bbf7b bellard
#define        APIC_INPUT_POLARITY                (1<<13)
55 574bbf7b bellard
#define        APIC_SEND_PENDING                (1<<12)
56 574bbf7b bellard
57 d592d303 bellard
#define IOAPIC_NUM_PINS                        0x18
58 d592d303 bellard
59 574bbf7b bellard
#define ESR_ILLEGAL_ADDRESS (1 << 7)
60 574bbf7b bellard
61 574bbf7b bellard
#define APIC_SV_ENABLE (1 << 8)
62 574bbf7b bellard
63 574bbf7b bellard
typedef struct APICState {
64 574bbf7b bellard
    CPUState *cpu_env;
65 574bbf7b bellard
    uint32_t apicbase;
66 574bbf7b bellard
    uint8_t id;
67 d592d303 bellard
    uint8_t arb_id;
68 574bbf7b bellard
    uint8_t tpr;
69 574bbf7b bellard
    uint32_t spurious_vec;
70 d592d303 bellard
    uint8_t log_dest;
71 d592d303 bellard
    uint8_t dest_mode;
72 574bbf7b bellard
    uint32_t isr[8];  /* in service register */
73 574bbf7b bellard
    uint32_t tmr[8];  /* trigger mode register */
74 574bbf7b bellard
    uint32_t irr[8]; /* interrupt request register */
75 574bbf7b bellard
    uint32_t lvt[APIC_LVT_NB];
76 574bbf7b bellard
    uint32_t esr; /* error register */
77 574bbf7b bellard
    uint32_t icr[2];
78 574bbf7b bellard
79 574bbf7b bellard
    uint32_t divide_conf;
80 574bbf7b bellard
    int count_shift;
81 574bbf7b bellard
    uint32_t initial_count;
82 574bbf7b bellard
    int64_t initial_count_load_time, next_time;
83 574bbf7b bellard
    QEMUTimer *timer;
84 d592d303 bellard
85 d592d303 bellard
    struct APICState *next_apic;
86 574bbf7b bellard
} APICState;
87 574bbf7b bellard
88 d592d303 bellard
struct IOAPICState {
89 d592d303 bellard
    uint8_t id;
90 d592d303 bellard
    uint8_t ioregsel;
91 d592d303 bellard
92 d592d303 bellard
    uint32_t irr;
93 d592d303 bellard
    uint64_t ioredtbl[IOAPIC_NUM_PINS];
94 d592d303 bellard
};
95 d592d303 bellard
96 574bbf7b bellard
static int apic_io_memory;
97 d592d303 bellard
static APICState *first_local_apic = NULL;
98 d592d303 bellard
static int last_apic_id = 0;
99 d592d303 bellard
100 d592d303 bellard
static void apic_init_ipi(APICState *s);
101 d592d303 bellard
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
102 d592d303 bellard
static void apic_update_irq(APICState *s);
103 d592d303 bellard
104 d592d303 bellard
static void apic_bus_deliver(uint32_t deliver_bitmask, uint8_t delivery_mode,
105 d592d303 bellard
                             uint8_t vector_num, uint8_t polarity,
106 d592d303 bellard
                             uint8_t trigger_mode)
107 d592d303 bellard
{
108 d592d303 bellard
    APICState *apic_iter;
109 d592d303 bellard
110 d592d303 bellard
    switch (delivery_mode) {
111 d592d303 bellard
        case APIC_DM_LOWPRI:
112 d592d303 bellard
        case APIC_DM_FIXED:
113 d592d303 bellard
            /* XXX: arbitration */
114 d592d303 bellard
            break;
115 d592d303 bellard
116 d592d303 bellard
        case APIC_DM_SMI:
117 d592d303 bellard
        case APIC_DM_NMI:
118 d592d303 bellard
            break;
119 d592d303 bellard
120 d592d303 bellard
        case APIC_DM_INIT:
121 d592d303 bellard
            /* normal INIT IPI sent to processors */
122 d592d303 bellard
            for (apic_iter = first_local_apic; apic_iter != NULL;
123 d592d303 bellard
                 apic_iter = apic_iter->next_apic) {
124 d592d303 bellard
                apic_init_ipi(apic_iter);
125 d592d303 bellard
            }
126 d592d303 bellard
            return;
127 d592d303 bellard
    
128 d592d303 bellard
        case APIC_DM_EXTINT:
129 b1fc0348 bellard
            /* handled in I/O APIC code */
130 d592d303 bellard
            break;
131 d592d303 bellard
132 d592d303 bellard
        default:
133 d592d303 bellard
            return;
134 d592d303 bellard
    }
135 d592d303 bellard
136 d592d303 bellard
    for (apic_iter = first_local_apic; apic_iter != NULL;
137 d592d303 bellard
         apic_iter = apic_iter->next_apic) {
138 d592d303 bellard
        if (deliver_bitmask & (1 << apic_iter->id))
139 d592d303 bellard
            apic_set_irq(apic_iter, vector_num, trigger_mode);
140 d592d303 bellard
    }
141 d592d303 bellard
}
142 574bbf7b bellard
143 574bbf7b bellard
void cpu_set_apic_base(CPUState *env, uint64_t val)
144 574bbf7b bellard
{
145 574bbf7b bellard
    APICState *s = env->apic_state;
146 574bbf7b bellard
#ifdef DEBUG_APIC
147 574bbf7b bellard
    printf("cpu_set_apic_base: %016llx\n", val);
148 574bbf7b bellard
#endif
149 574bbf7b bellard
    s->apicbase = (val & 0xfffff000) | 
150 574bbf7b bellard
        (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
151 574bbf7b bellard
    /* if disabled, cannot be enabled again */
152 574bbf7b bellard
    if (!(val & MSR_IA32_APICBASE_ENABLE)) {
153 574bbf7b bellard
        s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
154 574bbf7b bellard
        env->cpuid_features &= ~CPUID_APIC;
155 574bbf7b bellard
        s->spurious_vec &= ~APIC_SV_ENABLE;
156 574bbf7b bellard
    }
157 574bbf7b bellard
}
158 574bbf7b bellard
159 574bbf7b bellard
uint64_t cpu_get_apic_base(CPUState *env)
160 574bbf7b bellard
{
161 574bbf7b bellard
    APICState *s = env->apic_state;
162 574bbf7b bellard
#ifdef DEBUG_APIC
163 574bbf7b bellard
    printf("cpu_get_apic_base: %016llx\n", (uint64_t)s->apicbase);
164 574bbf7b bellard
#endif
165 574bbf7b bellard
    return s->apicbase;
166 574bbf7b bellard
}
167 574bbf7b bellard
168 9230e66e bellard
void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
169 9230e66e bellard
{
170 9230e66e bellard
    APICState *s = env->apic_state;
171 9230e66e bellard
    s->tpr = (val & 0x0f) << 4;
172 d592d303 bellard
    apic_update_irq(s);
173 9230e66e bellard
}
174 9230e66e bellard
175 9230e66e bellard
uint8_t cpu_get_apic_tpr(CPUX86State *env)
176 9230e66e bellard
{
177 9230e66e bellard
    APICState *s = env->apic_state;
178 9230e66e bellard
    return s->tpr >> 4;
179 9230e66e bellard
}
180 9230e66e bellard
181 db6e6ed7 bellard
static int fls_bit(int value)
182 574bbf7b bellard
{
183 d592d303 bellard
    unsigned int ret = 0;
184 d592d303 bellard
185 d592d303 bellard
#ifdef HOST_I386
186 d592d303 bellard
    __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
187 d592d303 bellard
    return ret;
188 d592d303 bellard
#else
189 d592d303 bellard
    if (value > 0xffff)
190 d592d303 bellard
        value >>= 16, ret = 16;
191 d592d303 bellard
    if (value > 0xff)
192 d592d303 bellard
        value >>= 8, ret += 8;
193 d592d303 bellard
    if (value > 0xf)
194 d592d303 bellard
        value >>= 4, ret += 4;
195 d592d303 bellard
    if (value > 0x3)
196 d592d303 bellard
        value >>= 2, ret += 2;
197 d592d303 bellard
    return ret + (value >> 1);
198 d592d303 bellard
#endif
199 574bbf7b bellard
}
200 574bbf7b bellard
201 574bbf7b bellard
static inline void set_bit(uint32_t *tab, int index)
202 574bbf7b bellard
{
203 574bbf7b bellard
    int i, mask;
204 574bbf7b bellard
    i = index >> 5;
205 574bbf7b bellard
    mask = 1 << (index & 0x1f);
206 574bbf7b bellard
    tab[i] |= mask;
207 574bbf7b bellard
}
208 574bbf7b bellard
209 574bbf7b bellard
static inline void reset_bit(uint32_t *tab, int index)
210 574bbf7b bellard
{
211 574bbf7b bellard
    int i, mask;
212 574bbf7b bellard
    i = index >> 5;
213 574bbf7b bellard
    mask = 1 << (index & 0x1f);
214 574bbf7b bellard
    tab[i] &= ~mask;
215 574bbf7b bellard
}
216 574bbf7b bellard
217 d592d303 bellard
/* return -1 if no bit is set */
218 d592d303 bellard
static int get_highest_priority_int(uint32_t *tab)
219 d592d303 bellard
{
220 d592d303 bellard
    int i;
221 d592d303 bellard
    for(i = 7; i >= 0; i--) {
222 d592d303 bellard
        if (tab[i] != 0) {
223 d592d303 bellard
            return i * 32 + fls_bit(tab[i]);
224 d592d303 bellard
        }
225 d592d303 bellard
    }
226 d592d303 bellard
    return -1;
227 d592d303 bellard
}
228 d592d303 bellard
229 574bbf7b bellard
static int apic_get_ppr(APICState *s)
230 574bbf7b bellard
{
231 574bbf7b bellard
    int tpr, isrv, ppr;
232 574bbf7b bellard
233 574bbf7b bellard
    tpr = (s->tpr >> 4);
234 574bbf7b bellard
    isrv = get_highest_priority_int(s->isr);
235 574bbf7b bellard
    if (isrv < 0)
236 574bbf7b bellard
        isrv = 0;
237 574bbf7b bellard
    isrv >>= 4;
238 574bbf7b bellard
    if (tpr >= isrv)
239 574bbf7b bellard
        ppr = s->tpr;
240 574bbf7b bellard
    else
241 574bbf7b bellard
        ppr = isrv << 4;
242 574bbf7b bellard
    return ppr;
243 574bbf7b bellard
}
244 574bbf7b bellard
245 d592d303 bellard
static int apic_get_arb_pri(APICState *s)
246 d592d303 bellard
{
247 d592d303 bellard
    /* XXX: arbitration */
248 d592d303 bellard
    return 0;
249 d592d303 bellard
}
250 d592d303 bellard
251 574bbf7b bellard
/* signal the CPU if an irq is pending */
252 574bbf7b bellard
static void apic_update_irq(APICState *s)
253 574bbf7b bellard
{
254 d592d303 bellard
    int irrv, ppr;
255 d592d303 bellard
    if (!(s->spurious_vec & APIC_SV_ENABLE))
256 d592d303 bellard
        return;
257 574bbf7b bellard
    irrv = get_highest_priority_int(s->irr);
258 574bbf7b bellard
    if (irrv < 0)
259 574bbf7b bellard
        return;
260 d592d303 bellard
    ppr = apic_get_ppr(s);
261 d592d303 bellard
    if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
262 574bbf7b bellard
        return;
263 574bbf7b bellard
    cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
264 574bbf7b bellard
}
265 574bbf7b bellard
266 574bbf7b bellard
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
267 574bbf7b bellard
{
268 574bbf7b bellard
    set_bit(s->irr, vector_num);
269 574bbf7b bellard
    if (trigger_mode)
270 574bbf7b bellard
        set_bit(s->tmr, vector_num);
271 574bbf7b bellard
    else
272 574bbf7b bellard
        reset_bit(s->tmr, vector_num);
273 574bbf7b bellard
    apic_update_irq(s);
274 574bbf7b bellard
}
275 574bbf7b bellard
276 574bbf7b bellard
static void apic_eoi(APICState *s)
277 574bbf7b bellard
{
278 574bbf7b bellard
    int isrv;
279 574bbf7b bellard
    isrv = get_highest_priority_int(s->isr);
280 574bbf7b bellard
    if (isrv < 0)
281 574bbf7b bellard
        return;
282 574bbf7b bellard
    reset_bit(s->isr, isrv);
283 d592d303 bellard
    /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
284 d592d303 bellard
            set the remote IRR bit for level triggered interrupts. */
285 574bbf7b bellard
    apic_update_irq(s);
286 574bbf7b bellard
}
287 574bbf7b bellard
288 d592d303 bellard
static uint32_t apic_get_delivery_bitmask(uint8_t dest, uint8_t dest_mode)
289 d592d303 bellard
{
290 d592d303 bellard
    uint32_t mask = 0;
291 d592d303 bellard
    APICState *apic_iter;
292 d592d303 bellard
293 d592d303 bellard
    if (dest_mode == 0) {
294 d592d303 bellard
        if (dest == 0xff)
295 d592d303 bellard
            mask = 0xff;
296 d592d303 bellard
        else
297 d592d303 bellard
            mask = 1 << dest;
298 d592d303 bellard
    } else {
299 d592d303 bellard
        /* XXX: cluster mode */
300 d592d303 bellard
        for (apic_iter = first_local_apic; apic_iter != NULL;
301 d592d303 bellard
             apic_iter = apic_iter->next_apic) {
302 d592d303 bellard
            if (dest & apic_iter->log_dest)
303 d592d303 bellard
                mask |= (1 << apic_iter->id);
304 d592d303 bellard
        }
305 d592d303 bellard
    }
306 d592d303 bellard
307 d592d303 bellard
    return mask;
308 d592d303 bellard
}
309 d592d303 bellard
310 d592d303 bellard
311 d592d303 bellard
static void apic_init_ipi(APICState *s)
312 d592d303 bellard
{
313 d592d303 bellard
    int i;
314 d592d303 bellard
315 d592d303 bellard
    for(i = 0; i < APIC_LVT_NB; i++)
316 d592d303 bellard
        s->lvt[i] = 1 << 16; /* mask LVT */
317 d592d303 bellard
    s->tpr = 0;
318 d592d303 bellard
    s->spurious_vec = 0xff;
319 d592d303 bellard
    s->log_dest = 0;
320 d592d303 bellard
    s->dest_mode = 0;
321 d592d303 bellard
    memset(s->isr, 0, sizeof(s->isr));
322 d592d303 bellard
    memset(s->tmr, 0, sizeof(s->tmr));
323 d592d303 bellard
    memset(s->irr, 0, sizeof(s->irr));
324 d592d303 bellard
    memset(s->lvt, 0, sizeof(s->lvt));
325 d592d303 bellard
    s->esr = 0;
326 d592d303 bellard
    memset(s->icr, 0, sizeof(s->icr));
327 d592d303 bellard
    s->divide_conf = 0;
328 d592d303 bellard
    s->count_shift = 0;
329 d592d303 bellard
    s->initial_count = 0;
330 d592d303 bellard
    s->initial_count_load_time = 0;
331 d592d303 bellard
    s->next_time = 0;
332 d592d303 bellard
}
333 d592d303 bellard
334 d592d303 bellard
static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
335 d592d303 bellard
                         uint8_t delivery_mode, uint8_t vector_num,
336 d592d303 bellard
                         uint8_t polarity, uint8_t trigger_mode)
337 d592d303 bellard
{
338 d592d303 bellard
    uint32_t deliver_bitmask = 0;
339 d592d303 bellard
    int dest_shorthand = (s->icr[0] >> 18) & 3;
340 d592d303 bellard
    APICState *apic_iter;
341 d592d303 bellard
342 d592d303 bellard
    switch (delivery_mode) {
343 d592d303 bellard
        case APIC_DM_LOWPRI:
344 d592d303 bellard
            /* XXX: serch for focus processor, arbitration */
345 d592d303 bellard
            dest = s->id;
346 d592d303 bellard
347 d592d303 bellard
        case APIC_DM_INIT:
348 d592d303 bellard
            {
349 d592d303 bellard
                int trig_mode = (s->icr[0] >> 15) & 1;
350 d592d303 bellard
                int level = (s->icr[0] >> 14) & 1;
351 d592d303 bellard
                if (level == 0 && trig_mode == 1) {
352 d592d303 bellard
                    for (apic_iter = first_local_apic; apic_iter != NULL;
353 d592d303 bellard
                         apic_iter = apic_iter->next_apic) {
354 d592d303 bellard
                        if (deliver_bitmask & (1 << apic_iter->id)) {
355 d592d303 bellard
                            apic_iter->arb_id = apic_iter->id;
356 d592d303 bellard
                        }
357 d592d303 bellard
                    }
358 d592d303 bellard
                    return;
359 d592d303 bellard
                }
360 d592d303 bellard
            }
361 d592d303 bellard
            break;
362 d592d303 bellard
363 d592d303 bellard
        case APIC_DM_SIPI:
364 d592d303 bellard
            for (apic_iter = first_local_apic; apic_iter != NULL;
365 d592d303 bellard
                 apic_iter = apic_iter->next_apic) {
366 d592d303 bellard
                if (deliver_bitmask & (1 << apic_iter->id)) {
367 d592d303 bellard
                    /* XXX: SMP support */
368 d592d303 bellard
                    /* apic_startup(apic_iter); */
369 d592d303 bellard
                }
370 d592d303 bellard
            }
371 d592d303 bellard
            return;
372 d592d303 bellard
    }
373 d592d303 bellard
374 d592d303 bellard
    switch (dest_shorthand) {
375 d592d303 bellard
        case 0:
376 d592d303 bellard
            deliver_bitmask = apic_get_delivery_bitmask(dest, dest_mode);
377 d592d303 bellard
            break;
378 d592d303 bellard
        case 1:
379 d592d303 bellard
            deliver_bitmask = (1 << s->id);
380 d592d303 bellard
            break;
381 d592d303 bellard
        case 2:
382 d592d303 bellard
            deliver_bitmask = 0xffffffff;
383 d592d303 bellard
            break;
384 d592d303 bellard
        case 3:
385 d592d303 bellard
            deliver_bitmask = 0xffffffff & ~(1 << s->id);
386 d592d303 bellard
            break;
387 d592d303 bellard
    }
388 d592d303 bellard
389 d592d303 bellard
    apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
390 d592d303 bellard
                     trigger_mode);
391 d592d303 bellard
}
392 d592d303 bellard
393 574bbf7b bellard
int apic_get_interrupt(CPUState *env)
394 574bbf7b bellard
{
395 574bbf7b bellard
    APICState *s = env->apic_state;
396 574bbf7b bellard
    int intno;
397 574bbf7b bellard
398 574bbf7b bellard
    /* if the APIC is installed or enabled, we let the 8259 handle the
399 574bbf7b bellard
       IRQs */
400 574bbf7b bellard
    if (!s)
401 574bbf7b bellard
        return -1;
402 574bbf7b bellard
    if (!(s->spurious_vec & APIC_SV_ENABLE))
403 574bbf7b bellard
        return -1;
404 574bbf7b bellard
    
405 574bbf7b bellard
    /* XXX: spurious IRQ handling */
406 574bbf7b bellard
    intno = get_highest_priority_int(s->irr);
407 574bbf7b bellard
    if (intno < 0)
408 574bbf7b bellard
        return -1;
409 574bbf7b bellard
    reset_bit(s->irr, intno);
410 d592d303 bellard
    if (s->tpr && intno <= s->tpr)
411 d592d303 bellard
        return s->spurious_vec & 0xff;
412 574bbf7b bellard
    set_bit(s->isr, intno);
413 574bbf7b bellard
    apic_update_irq(s);
414 574bbf7b bellard
    return intno;
415 574bbf7b bellard
}
416 574bbf7b bellard
417 574bbf7b bellard
static uint32_t apic_get_current_count(APICState *s)
418 574bbf7b bellard
{
419 574bbf7b bellard
    int64_t d;
420 574bbf7b bellard
    uint32_t val;
421 574bbf7b bellard
    d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> 
422 574bbf7b bellard
        s->count_shift;
423 574bbf7b bellard
    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
424 574bbf7b bellard
        /* periodic */
425 d592d303 bellard
        val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
426 574bbf7b bellard
    } else {
427 574bbf7b bellard
        if (d >= s->initial_count)
428 574bbf7b bellard
            val = 0;
429 574bbf7b bellard
        else
430 574bbf7b bellard
            val = s->initial_count - d;
431 574bbf7b bellard
    }
432 574bbf7b bellard
    return val;
433 574bbf7b bellard
}
434 574bbf7b bellard
435 574bbf7b bellard
static void apic_timer_update(APICState *s, int64_t current_time)
436 574bbf7b bellard
{
437 574bbf7b bellard
    int64_t next_time, d;
438 574bbf7b bellard
    
439 574bbf7b bellard
    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
440 574bbf7b bellard
        d = (current_time - s->initial_count_load_time) >> 
441 574bbf7b bellard
            s->count_shift;
442 574bbf7b bellard
        if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
443 d592d303 bellard
            d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
444 574bbf7b bellard
        } else {
445 574bbf7b bellard
            if (d >= s->initial_count)
446 574bbf7b bellard
                goto no_timer;
447 d592d303 bellard
            d = (uint64_t)s->initial_count + 1;
448 574bbf7b bellard
        }
449 574bbf7b bellard
        next_time = s->initial_count_load_time + (d << s->count_shift);
450 574bbf7b bellard
        qemu_mod_timer(s->timer, next_time);
451 574bbf7b bellard
        s->next_time = next_time;
452 574bbf7b bellard
    } else {
453 574bbf7b bellard
    no_timer:
454 574bbf7b bellard
        qemu_del_timer(s->timer);
455 574bbf7b bellard
    }
456 574bbf7b bellard
}
457 574bbf7b bellard
458 574bbf7b bellard
static void apic_timer(void *opaque)
459 574bbf7b bellard
{
460 574bbf7b bellard
    APICState *s = opaque;
461 574bbf7b bellard
462 574bbf7b bellard
    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
463 574bbf7b bellard
        apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
464 574bbf7b bellard
    }
465 574bbf7b bellard
    apic_timer_update(s, s->next_time);
466 574bbf7b bellard
}
467 574bbf7b bellard
468 574bbf7b bellard
static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
469 574bbf7b bellard
{
470 574bbf7b bellard
    return 0;
471 574bbf7b bellard
}
472 574bbf7b bellard
473 574bbf7b bellard
static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
474 574bbf7b bellard
{
475 574bbf7b bellard
    return 0;
476 574bbf7b bellard
}
477 574bbf7b bellard
478 574bbf7b bellard
static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
479 574bbf7b bellard
{
480 574bbf7b bellard
}
481 574bbf7b bellard
482 574bbf7b bellard
static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
483 574bbf7b bellard
{
484 574bbf7b bellard
}
485 574bbf7b bellard
486 574bbf7b bellard
static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
487 574bbf7b bellard
{
488 574bbf7b bellard
    CPUState *env;
489 574bbf7b bellard
    APICState *s;
490 574bbf7b bellard
    uint32_t val;
491 574bbf7b bellard
    int index;
492 574bbf7b bellard
493 574bbf7b bellard
    env = cpu_single_env;
494 574bbf7b bellard
    if (!env)
495 574bbf7b bellard
        return 0;
496 574bbf7b bellard
    s = env->apic_state;
497 574bbf7b bellard
498 574bbf7b bellard
    index = (addr >> 4) & 0xff;
499 574bbf7b bellard
    switch(index) {
500 574bbf7b bellard
    case 0x02: /* id */
501 574bbf7b bellard
        val = s->id << 24;
502 574bbf7b bellard
        break;
503 574bbf7b bellard
    case 0x03: /* version */
504 574bbf7b bellard
        val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
505 574bbf7b bellard
        break;
506 574bbf7b bellard
    case 0x08:
507 574bbf7b bellard
        val = s->tpr;
508 574bbf7b bellard
        break;
509 d592d303 bellard
    case 0x09:
510 d592d303 bellard
        val = apic_get_arb_pri(s);
511 d592d303 bellard
        break;
512 574bbf7b bellard
    case 0x0a:
513 574bbf7b bellard
        /* ppr */
514 574bbf7b bellard
        val = apic_get_ppr(s);
515 574bbf7b bellard
        break;
516 d592d303 bellard
    case 0x0d:
517 d592d303 bellard
        val = s->log_dest << 24;
518 d592d303 bellard
        break;
519 d592d303 bellard
    case 0x0e:
520 d592d303 bellard
        val = s->dest_mode << 28;
521 d592d303 bellard
        break;
522 574bbf7b bellard
    case 0x0f:
523 574bbf7b bellard
        val = s->spurious_vec;
524 574bbf7b bellard
        break;
525 574bbf7b bellard
    case 0x10 ... 0x17:
526 574bbf7b bellard
        val = s->isr[index & 7];
527 574bbf7b bellard
        break;
528 574bbf7b bellard
    case 0x18 ... 0x1f:
529 574bbf7b bellard
        val = s->tmr[index & 7];
530 574bbf7b bellard
        break;
531 574bbf7b bellard
    case 0x20 ... 0x27:
532 574bbf7b bellard
        val = s->irr[index & 7];
533 574bbf7b bellard
        break;
534 574bbf7b bellard
    case 0x28:
535 574bbf7b bellard
        val = s->esr;
536 574bbf7b bellard
        break;
537 574bbf7b bellard
    case 0x32 ... 0x37:
538 574bbf7b bellard
        val = s->lvt[index - 0x32];
539 574bbf7b bellard
        break;
540 574bbf7b bellard
    case 0x30:
541 574bbf7b bellard
    case 0x31:
542 574bbf7b bellard
        val = s->icr[index & 1];
543 574bbf7b bellard
        break;
544 574bbf7b bellard
    case 0x38:
545 574bbf7b bellard
        val = s->initial_count;
546 574bbf7b bellard
        break;
547 574bbf7b bellard
    case 0x39:
548 574bbf7b bellard
        val = apic_get_current_count(s);
549 574bbf7b bellard
        break;
550 574bbf7b bellard
    case 0x3e:
551 574bbf7b bellard
        val = s->divide_conf;
552 574bbf7b bellard
        break;
553 574bbf7b bellard
    default:
554 574bbf7b bellard
        s->esr |= ESR_ILLEGAL_ADDRESS;
555 574bbf7b bellard
        val = 0;
556 574bbf7b bellard
        break;
557 574bbf7b bellard
    }
558 574bbf7b bellard
#ifdef DEBUG_APIC
559 574bbf7b bellard
    printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
560 574bbf7b bellard
#endif
561 574bbf7b bellard
    return val;
562 574bbf7b bellard
}
563 574bbf7b bellard
564 574bbf7b bellard
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
565 574bbf7b bellard
{
566 574bbf7b bellard
    CPUState *env;
567 574bbf7b bellard
    APICState *s;
568 574bbf7b bellard
    int index;
569 574bbf7b bellard
570 574bbf7b bellard
    env = cpu_single_env;
571 574bbf7b bellard
    if (!env)
572 574bbf7b bellard
        return;
573 574bbf7b bellard
    s = env->apic_state;
574 574bbf7b bellard
575 574bbf7b bellard
#ifdef DEBUG_APIC
576 574bbf7b bellard
    printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
577 574bbf7b bellard
#endif
578 574bbf7b bellard
579 574bbf7b bellard
    index = (addr >> 4) & 0xff;
580 574bbf7b bellard
    switch(index) {
581 574bbf7b bellard
    case 0x02:
582 574bbf7b bellard
        s->id = (val >> 24);
583 574bbf7b bellard
        break;
584 574bbf7b bellard
    case 0x08:
585 574bbf7b bellard
        s->tpr = val;
586 d592d303 bellard
        apic_update_irq(s);
587 574bbf7b bellard
        break;
588 574bbf7b bellard
    case 0x0b: /* EOI */
589 574bbf7b bellard
        apic_eoi(s);
590 574bbf7b bellard
        break;
591 d592d303 bellard
    case 0x0d:
592 d592d303 bellard
        s->log_dest = val >> 24;
593 d592d303 bellard
        break;
594 d592d303 bellard
    case 0x0e:
595 d592d303 bellard
        s->dest_mode = val >> 28;
596 d592d303 bellard
        break;
597 574bbf7b bellard
    case 0x0f:
598 574bbf7b bellard
        s->spurious_vec = val & 0x1ff;
599 d592d303 bellard
        apic_update_irq(s);
600 574bbf7b bellard
        break;
601 574bbf7b bellard
    case 0x30:
602 d592d303 bellard
        s->icr[0] = val;
603 d592d303 bellard
        apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
604 d592d303 bellard
                     (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
605 d592d303 bellard
                     (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
606 d592d303 bellard
        break;
607 574bbf7b bellard
    case 0x31:
608 d592d303 bellard
        s->icr[1] = val;
609 574bbf7b bellard
        break;
610 574bbf7b bellard
    case 0x32 ... 0x37:
611 574bbf7b bellard
        {
612 574bbf7b bellard
            int n = index - 0x32;
613 574bbf7b bellard
            s->lvt[n] = val;
614 574bbf7b bellard
            if (n == APIC_LVT_TIMER)
615 574bbf7b bellard
                apic_timer_update(s, qemu_get_clock(vm_clock));
616 574bbf7b bellard
        }
617 574bbf7b bellard
        break;
618 574bbf7b bellard
    case 0x38:
619 574bbf7b bellard
        s->initial_count = val;
620 574bbf7b bellard
        s->initial_count_load_time = qemu_get_clock(vm_clock);
621 574bbf7b bellard
        apic_timer_update(s, s->initial_count_load_time);
622 574bbf7b bellard
        break;
623 574bbf7b bellard
    case 0x3e:
624 574bbf7b bellard
        {
625 574bbf7b bellard
            int v;
626 574bbf7b bellard
            s->divide_conf = val & 0xb;
627 574bbf7b bellard
            v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
628 574bbf7b bellard
            s->count_shift = (v + 1) & 7;
629 574bbf7b bellard
        }
630 574bbf7b bellard
        break;
631 574bbf7b bellard
    default:
632 574bbf7b bellard
        s->esr |= ESR_ILLEGAL_ADDRESS;
633 574bbf7b bellard
        break;
634 574bbf7b bellard
    }
635 574bbf7b bellard
}
636 574bbf7b bellard
637 d592d303 bellard
static void apic_save(QEMUFile *f, void *opaque)
638 d592d303 bellard
{
639 d592d303 bellard
    APICState *s = opaque;
640 d592d303 bellard
    int i;
641 d592d303 bellard
642 d592d303 bellard
    qemu_put_be32s(f, &s->apicbase);
643 d592d303 bellard
    qemu_put_8s(f, &s->id);
644 d592d303 bellard
    qemu_put_8s(f, &s->arb_id);
645 d592d303 bellard
    qemu_put_8s(f, &s->tpr);
646 d592d303 bellard
    qemu_put_be32s(f, &s->spurious_vec);
647 d592d303 bellard
    qemu_put_8s(f, &s->log_dest);
648 d592d303 bellard
    qemu_put_8s(f, &s->dest_mode);
649 d592d303 bellard
    for (i = 0; i < 8; i++) {
650 d592d303 bellard
        qemu_put_be32s(f, &s->isr[i]);
651 d592d303 bellard
        qemu_put_be32s(f, &s->tmr[i]);
652 d592d303 bellard
        qemu_put_be32s(f, &s->irr[i]);
653 d592d303 bellard
    }
654 d592d303 bellard
    for (i = 0; i < APIC_LVT_NB; i++) {
655 d592d303 bellard
        qemu_put_be32s(f, &s->lvt[i]);
656 d592d303 bellard
    }
657 d592d303 bellard
    qemu_put_be32s(f, &s->esr);
658 d592d303 bellard
    qemu_put_be32s(f, &s->icr[0]);
659 d592d303 bellard
    qemu_put_be32s(f, &s->icr[1]);
660 d592d303 bellard
    qemu_put_be32s(f, &s->divide_conf);
661 d592d303 bellard
    qemu_put_be32s(f, &s->count_shift);
662 d592d303 bellard
    qemu_put_be32s(f, &s->initial_count);
663 d592d303 bellard
    qemu_put_be64s(f, &s->initial_count_load_time);
664 d592d303 bellard
    qemu_put_be64s(f, &s->next_time);
665 d592d303 bellard
}
666 d592d303 bellard
667 d592d303 bellard
static int apic_load(QEMUFile *f, void *opaque, int version_id)
668 d592d303 bellard
{
669 d592d303 bellard
    APICState *s = opaque;
670 d592d303 bellard
    int i;
671 d592d303 bellard
672 d592d303 bellard
    if (version_id != 1)
673 d592d303 bellard
        return -EINVAL;
674 d592d303 bellard
675 d592d303 bellard
    /* XXX: what if the base changes? (registered memory regions) */
676 d592d303 bellard
    qemu_get_be32s(f, &s->apicbase);
677 d592d303 bellard
    qemu_get_8s(f, &s->id);
678 d592d303 bellard
    qemu_get_8s(f, &s->arb_id);
679 d592d303 bellard
    qemu_get_8s(f, &s->tpr);
680 d592d303 bellard
    qemu_get_be32s(f, &s->spurious_vec);
681 d592d303 bellard
    qemu_get_8s(f, &s->log_dest);
682 d592d303 bellard
    qemu_get_8s(f, &s->dest_mode);
683 d592d303 bellard
    for (i = 0; i < 8; i++) {
684 d592d303 bellard
        qemu_get_be32s(f, &s->isr[i]);
685 d592d303 bellard
        qemu_get_be32s(f, &s->tmr[i]);
686 d592d303 bellard
        qemu_get_be32s(f, &s->irr[i]);
687 d592d303 bellard
    }
688 d592d303 bellard
    for (i = 0; i < APIC_LVT_NB; i++) {
689 d592d303 bellard
        qemu_get_be32s(f, &s->lvt[i]);
690 d592d303 bellard
    }
691 d592d303 bellard
    qemu_get_be32s(f, &s->esr);
692 d592d303 bellard
    qemu_get_be32s(f, &s->icr[0]);
693 d592d303 bellard
    qemu_get_be32s(f, &s->icr[1]);
694 d592d303 bellard
    qemu_get_be32s(f, &s->divide_conf);
695 d592d303 bellard
    qemu_get_be32s(f, &s->count_shift);
696 d592d303 bellard
    qemu_get_be32s(f, &s->initial_count);
697 d592d303 bellard
    qemu_get_be64s(f, &s->initial_count_load_time);
698 d592d303 bellard
    qemu_get_be64s(f, &s->next_time);
699 d592d303 bellard
    return 0;
700 d592d303 bellard
}
701 574bbf7b bellard
702 d592d303 bellard
static void apic_reset(void *opaque)
703 d592d303 bellard
{
704 d592d303 bellard
    APICState *s = opaque;
705 d592d303 bellard
    apic_init_ipi(s);
706 d592d303 bellard
}
707 574bbf7b bellard
708 574bbf7b bellard
static CPUReadMemoryFunc *apic_mem_read[3] = {
709 574bbf7b bellard
    apic_mem_readb,
710 574bbf7b bellard
    apic_mem_readw,
711 574bbf7b bellard
    apic_mem_readl,
712 574bbf7b bellard
};
713 574bbf7b bellard
714 574bbf7b bellard
static CPUWriteMemoryFunc *apic_mem_write[3] = {
715 574bbf7b bellard
    apic_mem_writeb,
716 574bbf7b bellard
    apic_mem_writew,
717 574bbf7b bellard
    apic_mem_writel,
718 574bbf7b bellard
};
719 574bbf7b bellard
720 574bbf7b bellard
int apic_init(CPUState *env)
721 574bbf7b bellard
{
722 574bbf7b bellard
    APICState *s;
723 574bbf7b bellard
724 d592d303 bellard
    s = qemu_mallocz(sizeof(APICState));
725 574bbf7b bellard
    if (!s)
726 574bbf7b bellard
        return -1;
727 574bbf7b bellard
    env->apic_state = s;
728 d592d303 bellard
    apic_init_ipi(s);
729 d592d303 bellard
    s->id = last_apic_id++;
730 574bbf7b bellard
    s->cpu_env = env;
731 574bbf7b bellard
    s->apicbase = 0xfee00000 | 
732 d592d303 bellard
        (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
733 574bbf7b bellard
734 d592d303 bellard
    /* XXX: mapping more APICs at the same memory location */
735 574bbf7b bellard
    if (apic_io_memory == 0) {
736 574bbf7b bellard
        /* NOTE: the APIC is directly connected to the CPU - it is not
737 574bbf7b bellard
           on the global memory bus. */
738 574bbf7b bellard
        apic_io_memory = cpu_register_io_memory(0, apic_mem_read, 
739 574bbf7b bellard
                                                apic_mem_write, NULL);
740 d592d303 bellard
        cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
741 d592d303 bellard
                                     apic_io_memory);
742 574bbf7b bellard
    }
743 574bbf7b bellard
    s->timer = qemu_new_timer(vm_clock, apic_timer, s);
744 d592d303 bellard
745 d592d303 bellard
    register_savevm("apic", 0, 1, apic_save, apic_load, s);
746 d592d303 bellard
    qemu_register_reset(apic_reset, s);
747 d592d303 bellard
748 d592d303 bellard
    s->next_apic = first_local_apic;
749 d592d303 bellard
    first_local_apic = s;
750 d592d303 bellard
    
751 d592d303 bellard
    return 0;
752 d592d303 bellard
}
753 d592d303 bellard
754 d592d303 bellard
static void ioapic_service(IOAPICState *s)
755 d592d303 bellard
{
756 b1fc0348 bellard
    uint8_t i;
757 b1fc0348 bellard
    uint8_t trig_mode;
758 d592d303 bellard
    uint8_t vector;
759 b1fc0348 bellard
    uint8_t delivery_mode;
760 d592d303 bellard
    uint32_t mask;
761 d592d303 bellard
    uint64_t entry;
762 d592d303 bellard
    uint8_t dest;
763 d592d303 bellard
    uint8_t dest_mode;
764 b1fc0348 bellard
    uint8_t polarity;
765 d592d303 bellard
766 b1fc0348 bellard
    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
767 b1fc0348 bellard
        mask = 1 << i;
768 d592d303 bellard
        if (s->irr & mask) {
769 b1fc0348 bellard
            entry = s->ioredtbl[i];
770 d592d303 bellard
            if (!(entry & APIC_LVT_MASKED)) {
771 b1fc0348 bellard
                trig_mode = ((entry >> 15) & 1);
772 d592d303 bellard
                dest = entry >> 56;
773 d592d303 bellard
                dest_mode = (entry >> 11) & 1;
774 b1fc0348 bellard
                delivery_mode = (entry >> 8) & 7;
775 b1fc0348 bellard
                polarity = (entry >> 13) & 1;
776 b1fc0348 bellard
                if (trig_mode == APIC_TRIGGER_EDGE)
777 b1fc0348 bellard
                    s->irr &= ~mask;
778 b1fc0348 bellard
                if (delivery_mode == APIC_DM_EXTINT)
779 b1fc0348 bellard
                    vector = pic_read_irq(isa_pic);
780 b1fc0348 bellard
                else
781 b1fc0348 bellard
                    vector = entry & 0xff;
782 d592d303 bellard
                apic_bus_deliver(apic_get_delivery_bitmask(dest, dest_mode),
783 b1fc0348 bellard
                                 delivery_mode, vector, polarity, trig_mode);
784 d592d303 bellard
            }
785 d592d303 bellard
        }
786 d592d303 bellard
    }
787 d592d303 bellard
}
788 d592d303 bellard
789 d592d303 bellard
void ioapic_set_irq(void *opaque, int vector, int level)
790 d592d303 bellard
{
791 d592d303 bellard
    IOAPICState *s = opaque;
792 d592d303 bellard
793 d592d303 bellard
    if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
794 d592d303 bellard
        uint32_t mask = 1 << vector;
795 d592d303 bellard
        uint64_t entry = s->ioredtbl[vector];
796 d592d303 bellard
797 d592d303 bellard
        if ((entry >> 15) & 1) {
798 d592d303 bellard
            /* level triggered */
799 d592d303 bellard
            if (level) {
800 d592d303 bellard
                s->irr |= mask;
801 d592d303 bellard
                ioapic_service(s);
802 d592d303 bellard
            } else {
803 d592d303 bellard
                s->irr &= ~mask;
804 d592d303 bellard
            }
805 d592d303 bellard
        } else {
806 d592d303 bellard
            /* edge triggered */
807 d592d303 bellard
            if (level) {
808 d592d303 bellard
                s->irr |= mask;
809 d592d303 bellard
                ioapic_service(s);
810 d592d303 bellard
            }
811 d592d303 bellard
        }
812 d592d303 bellard
    }
813 d592d303 bellard
}
814 d592d303 bellard
815 d592d303 bellard
static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
816 d592d303 bellard
{
817 d592d303 bellard
    IOAPICState *s = opaque;
818 d592d303 bellard
    int index;
819 d592d303 bellard
    uint32_t val = 0;
820 d592d303 bellard
821 d592d303 bellard
    addr &= 0xff;
822 d592d303 bellard
    if (addr == 0x00) {
823 d592d303 bellard
        val = s->ioregsel;
824 d592d303 bellard
    } else if (addr == 0x10) {
825 d592d303 bellard
        switch (s->ioregsel) {
826 d592d303 bellard
            case 0x00:
827 d592d303 bellard
                val = s->id << 24;
828 d592d303 bellard
                break;
829 d592d303 bellard
            case 0x01:
830 d592d303 bellard
                val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
831 d592d303 bellard
                break;
832 d592d303 bellard
            case 0x02:
833 d592d303 bellard
                val = 0;
834 d592d303 bellard
                break;
835 d592d303 bellard
            default:
836 d592d303 bellard
                index = (s->ioregsel - 0x10) >> 1;
837 d592d303 bellard
                if (index >= 0 && index < IOAPIC_NUM_PINS) {
838 d592d303 bellard
                    if (s->ioregsel & 1)
839 d592d303 bellard
                        val = s->ioredtbl[index] >> 32;
840 d592d303 bellard
                    else
841 d592d303 bellard
                        val = s->ioredtbl[index] & 0xffffffff;
842 d592d303 bellard
                }
843 d592d303 bellard
        }
844 d592d303 bellard
#ifdef DEBUG_IOAPIC
845 d592d303 bellard
        printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
846 d592d303 bellard
#endif
847 d592d303 bellard
    }
848 d592d303 bellard
    return val;
849 d592d303 bellard
}
850 d592d303 bellard
851 d592d303 bellard
static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
852 d592d303 bellard
{
853 d592d303 bellard
    IOAPICState *s = opaque;
854 d592d303 bellard
    int index;
855 d592d303 bellard
856 d592d303 bellard
    addr &= 0xff;
857 d592d303 bellard
    if (addr == 0x00)  {
858 d592d303 bellard
        s->ioregsel = val;
859 d592d303 bellard
        return;
860 d592d303 bellard
    } else if (addr == 0x10) {
861 d592d303 bellard
#ifdef DEBUG_IOAPIC
862 d592d303 bellard
        printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
863 d592d303 bellard
#endif
864 d592d303 bellard
        switch (s->ioregsel) {
865 d592d303 bellard
            case 0x00:
866 d592d303 bellard
                s->id = (val >> 24) & 0xff;
867 d592d303 bellard
                return;
868 d592d303 bellard
            case 0x01:
869 d592d303 bellard
            case 0x02:
870 d592d303 bellard
                return;
871 d592d303 bellard
            default:
872 d592d303 bellard
                index = (s->ioregsel - 0x10) >> 1;
873 d592d303 bellard
                if (index >= 0 && index < IOAPIC_NUM_PINS) {
874 d592d303 bellard
                    if (s->ioregsel & 1) {
875 d592d303 bellard
                        s->ioredtbl[index] &= 0xffffffff;
876 d592d303 bellard
                        s->ioredtbl[index] |= (uint64_t)val << 32;
877 d592d303 bellard
                    } else {
878 d592d303 bellard
                        s->ioredtbl[index] &= ~0xffffffffULL;
879 d592d303 bellard
                        s->ioredtbl[index] |= val;
880 d592d303 bellard
                    }
881 d592d303 bellard
                    ioapic_service(s);
882 d592d303 bellard
                }
883 d592d303 bellard
        }
884 d592d303 bellard
    }
885 d592d303 bellard
}
886 d592d303 bellard
887 d592d303 bellard
static void ioapic_save(QEMUFile *f, void *opaque)
888 d592d303 bellard
{
889 d592d303 bellard
    IOAPICState *s = opaque;
890 d592d303 bellard
    int i;
891 d592d303 bellard
892 d592d303 bellard
    qemu_put_8s(f, &s->id);
893 d592d303 bellard
    qemu_put_8s(f, &s->ioregsel);
894 d592d303 bellard
    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
895 d592d303 bellard
        qemu_put_be64s(f, &s->ioredtbl[i]);
896 d592d303 bellard
    }
897 d592d303 bellard
}
898 d592d303 bellard
899 d592d303 bellard
static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
900 d592d303 bellard
{
901 d592d303 bellard
    IOAPICState *s = opaque;
902 d592d303 bellard
    int i;
903 d592d303 bellard
904 d592d303 bellard
    if (version_id != 1)
905 d592d303 bellard
        return -EINVAL;
906 d592d303 bellard
907 d592d303 bellard
    qemu_get_8s(f, &s->id);
908 d592d303 bellard
    qemu_get_8s(f, &s->ioregsel);
909 d592d303 bellard
    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
910 d592d303 bellard
        qemu_get_be64s(f, &s->ioredtbl[i]);
911 d592d303 bellard
    }
912 574bbf7b bellard
    return 0;
913 574bbf7b bellard
}
914 d592d303 bellard
915 d592d303 bellard
static void ioapic_reset(void *opaque)
916 d592d303 bellard
{
917 d592d303 bellard
    IOAPICState *s = opaque;
918 d592d303 bellard
    int i;
919 d592d303 bellard
920 d592d303 bellard
    memset(s, 0, sizeof(*s));
921 d592d303 bellard
    for(i = 0; i < IOAPIC_NUM_PINS; i++)
922 d592d303 bellard
        s->ioredtbl[i] = 1 << 16; /* mask LVT */
923 d592d303 bellard
}
924 d592d303 bellard
925 d592d303 bellard
static CPUReadMemoryFunc *ioapic_mem_read[3] = {
926 d592d303 bellard
    ioapic_mem_readl,
927 d592d303 bellard
    ioapic_mem_readl,
928 d592d303 bellard
    ioapic_mem_readl,
929 d592d303 bellard
};
930 d592d303 bellard
931 d592d303 bellard
static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
932 d592d303 bellard
    ioapic_mem_writel,
933 d592d303 bellard
    ioapic_mem_writel,
934 d592d303 bellard
    ioapic_mem_writel,
935 d592d303 bellard
};
936 d592d303 bellard
937 d592d303 bellard
IOAPICState *ioapic_init(void)
938 d592d303 bellard
{
939 d592d303 bellard
    IOAPICState *s;
940 d592d303 bellard
    int io_memory;
941 d592d303 bellard
942 b1fc0348 bellard
    s = qemu_mallocz(sizeof(IOAPICState));
943 d592d303 bellard
    if (!s)
944 d592d303 bellard
        return NULL;
945 d592d303 bellard
    ioapic_reset(s);
946 d592d303 bellard
    s->id = last_apic_id++;
947 d592d303 bellard
948 d592d303 bellard
    io_memory = cpu_register_io_memory(0, ioapic_mem_read, 
949 d592d303 bellard
                                       ioapic_mem_write, s);
950 d592d303 bellard
    cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
951 d592d303 bellard
952 d592d303 bellard
    register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
953 d592d303 bellard
    qemu_register_reset(ioapic_reset, s);
954 d592d303 bellard
    
955 d592d303 bellard
    return s;
956 d592d303 bellard
}