Statistics
| Branch: | Revision:

root / hw / apic.c @ a8d3431a

History | View | Annotate | Download (10.7 kB)

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
void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
104
{
105
    APICState *s = env->apic_state;
106
    s->tpr = (val & 0x0f) << 4;
107
}
108

    
109
uint8_t cpu_get_apic_tpr(CPUX86State *env)
110
{
111
    APICState *s = env->apic_state;
112
    return s->tpr >> 4;
113
}
114

    
115
/* return -1 if no bit is set */
116
static int get_highest_priority_int(uint32_t *tab)
117
{
118
    int i;
119
    for(i = 0;i < 8; i++) {
120
        if (tab[i] != 0) {
121
            return i * 32 + ffs(tab[i]) - 1;
122
        }
123
    }
124
    return -1;
125
}
126

    
127
static inline void set_bit(uint32_t *tab, int index)
128
{
129
    int i, mask;
130
    i = index >> 5;
131
    mask = 1 << (index & 0x1f);
132
    tab[i] |= mask;
133
}
134

    
135
static inline void reset_bit(uint32_t *tab, int index)
136
{
137
    int i, mask;
138
    i = index >> 5;
139
    mask = 1 << (index & 0x1f);
140
    tab[i] &= ~mask;
141
}
142

    
143
static int apic_get_ppr(APICState *s)
144
{
145
    int tpr, isrv, ppr;
146

    
147
    tpr = (s->tpr >> 4);
148
    isrv = get_highest_priority_int(s->isr);
149
    if (isrv < 0)
150
        isrv = 0;
151
    isrv >>= 4;
152
    if (tpr >= isrv)
153
        ppr = s->tpr;
154
    else
155
        ppr = isrv << 4;
156
    return ppr;
157
}
158

    
159
/* signal the CPU if an irq is pending */
160
static void apic_update_irq(APICState *s)
161
{
162
    int irrv, isrv;
163
    irrv = get_highest_priority_int(s->irr);
164
    if (irrv < 0)
165
        return;
166
    isrv = get_highest_priority_int(s->isr);
167
    /* if the pending irq has less priority, we do not make a new request */
168
    if (isrv >= 0 && irrv >= isrv)
169
        return;
170
    cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
171
}
172

    
173
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
174
{
175
    set_bit(s->irr, vector_num);
176
    if (trigger_mode)
177
        set_bit(s->tmr, vector_num);
178
    else
179
        reset_bit(s->tmr, vector_num);
180
    apic_update_irq(s);
181
}
182

    
183
static void apic_eoi(APICState *s)
184
{
185
    int isrv;
186
    isrv = get_highest_priority_int(s->isr);
187
    if (isrv < 0)
188
        return;
189
    reset_bit(s->isr, isrv);
190
    apic_update_irq(s);
191
}
192

    
193
int apic_get_interrupt(CPUState *env)
194
{
195
    APICState *s = env->apic_state;
196
    int intno;
197

    
198
    /* if the APIC is installed or enabled, we let the 8259 handle the
199
       IRQs */
200
    if (!s)
201
        return -1;
202
    if (!(s->spurious_vec & APIC_SV_ENABLE))
203
        return -1;
204
    
205
    /* XXX: spurious IRQ handling */
206
    intno = get_highest_priority_int(s->irr);
207
    if (intno < 0)
208
        return -1;
209
    reset_bit(s->irr, intno);
210
    set_bit(s->isr, intno);
211
    apic_update_irq(s);
212
    return intno;
213
}
214

    
215
static uint32_t apic_get_current_count(APICState *s)
216
{
217
    int64_t d;
218
    uint32_t val;
219
    d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> 
220
        s->count_shift;
221
    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
222
        /* periodic */
223
        val = s->initial_count - (d % (s->initial_count + 1));
224
    } else {
225
        if (d >= s->initial_count)
226
            val = 0;
227
        else
228
            val = s->initial_count - d;
229
    }
230
    return val;
231
}
232

    
233
static void apic_timer_update(APICState *s, int64_t current_time)
234
{
235
    int64_t next_time, d;
236
    
237
    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
238
        d = (current_time - s->initial_count_load_time) >> 
239
            s->count_shift;
240
        if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
241
            d = ((d / (s->initial_count + 1)) + 1) * (s->initial_count + 1);
242
        } else {
243
            if (d >= s->initial_count)
244
                goto no_timer;
245
            d = s->initial_count + 1;
246
        }
247
        next_time = s->initial_count_load_time + (d << s->count_shift);
248
        qemu_mod_timer(s->timer, next_time);
249
        s->next_time = next_time;
250
    } else {
251
    no_timer:
252
        qemu_del_timer(s->timer);
253
    }
254
}
255

    
256
static void apic_timer(void *opaque)
257
{
258
    APICState *s = opaque;
259

    
260
    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
261
        apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
262
    }
263
    apic_timer_update(s, s->next_time);
264
}
265

    
266
static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
267
{
268
    return 0;
269
}
270

    
271
static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
272
{
273
    return 0;
274
}
275

    
276
static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
277
{
278
}
279

    
280
static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
281
{
282
}
283

    
284
static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
285
{
286
    CPUState *env;
287
    APICState *s;
288
    uint32_t val;
289
    int index;
290

    
291
    env = cpu_single_env;
292
    if (!env)
293
        return 0;
294
    s = env->apic_state;
295

    
296
    index = (addr >> 4) & 0xff;
297
    switch(index) {
298
    case 0x02: /* id */
299
        val = s->id << 24;
300
        break;
301
    case 0x03: /* version */
302
        val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
303
        break;
304
    case 0x08:
305
        val = s->tpr;
306
        break;
307
    case 0x0a:
308
        /* ppr */
309
        val = apic_get_ppr(s);
310
        break;
311
    case 0x0f:
312
        val = s->spurious_vec;
313
        break;
314
    case 0x10 ... 0x17:
315
        val = s->isr[index & 7];
316
        break;
317
    case 0x18 ... 0x1f:
318
        val = s->tmr[index & 7];
319
        break;
320
    case 0x20 ... 0x27:
321
        val = s->irr[index & 7];
322
        break;
323
    case 0x28:
324
        val = s->esr;
325
        break;
326
    case 0x32 ... 0x37:
327
        val = s->lvt[index - 0x32];
328
        break;
329
    case 0x30:
330
    case 0x31:
331
        val = s->icr[index & 1];
332
        break;
333
    case 0x38:
334
        val = s->initial_count;
335
        break;
336
    case 0x39:
337
        val = apic_get_current_count(s);
338
        break;
339
    case 0x3e:
340
        val = s->divide_conf;
341
        break;
342
    default:
343
        s->esr |= ESR_ILLEGAL_ADDRESS;
344
        val = 0;
345
        break;
346
    }
347
#ifdef DEBUG_APIC
348
    printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
349
#endif
350
    return val;
351
}
352

    
353
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
354
{
355
    CPUState *env;
356
    APICState *s;
357
    int index;
358

    
359
    env = cpu_single_env;
360
    if (!env)
361
        return;
362
    s = env->apic_state;
363

    
364
#ifdef DEBUG_APIC
365
    printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
366
#endif
367

    
368
    index = (addr >> 4) & 0xff;
369
    switch(index) {
370
    case 0x02:
371
        s->id = (val >> 24);
372
        break;
373
    case 0x08:
374
        s->tpr = val;
375
        break;
376
    case 0x0b: /* EOI */
377
        apic_eoi(s);
378
        break;
379
    case 0x0f:
380
        s->spurious_vec = val & 0x1ff;
381
        break;
382
    case 0x30:
383
    case 0x31:
384
        s->icr[index & 1] = val;
385
        break;
386
    case 0x32 ... 0x37:
387
        {
388
            int n = index - 0x32;
389
            s->lvt[n] = val;
390
            if (n == APIC_LVT_TIMER)
391
                apic_timer_update(s, qemu_get_clock(vm_clock));
392
        }
393
        break;
394
    case 0x38:
395
        s->initial_count = val;
396
        s->initial_count_load_time = qemu_get_clock(vm_clock);
397
        apic_timer_update(s, s->initial_count_load_time);
398
        break;
399
    case 0x3e:
400
        {
401
            int v;
402
            s->divide_conf = val & 0xb;
403
            v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
404
            s->count_shift = (v + 1) & 7;
405
        }
406
        break;
407
    default:
408
        s->esr |= ESR_ILLEGAL_ADDRESS;
409
        break;
410
    }
411
}
412

    
413

    
414

    
415
static CPUReadMemoryFunc *apic_mem_read[3] = {
416
    apic_mem_readb,
417
    apic_mem_readw,
418
    apic_mem_readl,
419
};
420

    
421
static CPUWriteMemoryFunc *apic_mem_write[3] = {
422
    apic_mem_writeb,
423
    apic_mem_writew,
424
    apic_mem_writel,
425
};
426

    
427
int apic_init(CPUState *env)
428
{
429
    APICState *s;
430
    int i;
431

    
432
    s = malloc(sizeof(APICState));
433
    if (!s)
434
        return -1;
435
    memset(s, 0, sizeof(*s));
436
    env->apic_state = s;
437
    s->cpu_env = env;
438
    s->apicbase = 0xfee00000 | 
439
        MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE;
440
    for(i = 0; i < APIC_LVT_NB; i++)
441
        s->lvt[i] = 1 << 16; /* mask LVT */
442
    s->spurious_vec = 0xff;
443

    
444
    if (apic_io_memory == 0) {
445
        /* NOTE: the APIC is directly connected to the CPU - it is not
446
           on the global memory bus. */
447
        apic_io_memory = cpu_register_io_memory(0, apic_mem_read, 
448
                                                apic_mem_write, NULL);
449
        cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000, apic_io_memory);
450
    }
451
    s->timer = qemu_new_timer(vm_clock, apic_timer, s);
452
    return 0;
453
}