1/*
2 * Local APIC virtualization
3 *
4 * Copyright (C) 2006 Qumranet, Inc.
5 * Copyright (C) 2007 Novell
6 * Copyright (C) 2007 Intel
7 * Copyright 2009 Red Hat, Inc. and/or its affiliates.
8 *
9 * Authors:
10 *   Dor Laor <dor.laor@qumranet.com>
11 *   Gregory Haskins <ghaskins@novell.com>
12 *   Yaozu (Eddie) Dong <eddie.dong@intel.com>
13 *
14 * Based on Xen 3.1 code, Copyright (c) 2004, Intel Corporation.
15 *
16 * This work is licensed under the terms of the GNU GPL, version 2.  See
17 * the COPYING file in the top-level directory.
18 */
19
20// SPDX-License-Identifier: GPL-2.0-only
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <utils/util.h>
26
27#include <sel4vm/guest_vm.h>
28#include <sel4vm/boot.h>
29#include <sel4vm/guest_vcpu_fault.h>
30
31#include "processor/lapic.h"
32#include "processor/apicdef.h"
33#include "processor/msr.h"
34#include "i8259/i8259.h"
35#include "interrupt.h"
36
37#define APIC_BUS_CYCLE_NS 1
38
39#define APIC_DEBUG 0
40#define apic_debug(lvl,...) do{ if(lvl < APIC_DEBUG){printf(__VA_ARGS__);fflush(stdout);}}while (0)
41
42#define APIC_LVT_NUM            6
43/* 14 is the version for Xeon and Pentium 8.4.8*/
44#define APIC_VERSION            (0x14UL | ((APIC_LVT_NUM - 1) << 16))
45#define LAPIC_MMIO_LENGTH       (BIT(12))
46/* followed define is not in apicdef.h */
47#define APIC_SHORT_MASK         0xc0000
48#define APIC_DEST_NOSHORT       0x0
49#define APIC_DEST_MASK          0x800
50#define MAX_APIC_VECTOR         256
51#define APIC_VECTORS_PER_REG        32
52
53inline static int pic_get_interrupt(vm_t *vm)
54{
55    return i8259_get_interrupt(vm);
56}
57
58inline static int pic_has_interrupt(vm_t *vm)
59{
60    return i8259_has_interrupt(vm);
61}
62
63struct vm_lapic_irq {
64    uint32_t vector;
65    uint32_t delivery_mode;
66    uint32_t dest_mode;
67    uint32_t level;
68    uint32_t trig_mode;
69    uint32_t shorthand;
70    uint32_t dest_id;
71};
72
73/* Generic bit operations; TODO move these elsewhere */
74static inline int fls(int x)
75{
76    int r = 32;
77
78    if (!x) {
79        return 0;
80    }
81
82    if (!(x & 0xffff0000u)) {
83        x <<= 16;
84        r -= 16;
85    }
86    if (!(x & 0xff000000u)) {
87        x <<= 8;
88        r -= 8;
89    }
90    if (!(x & 0xf0000000u)) {
91        x <<= 4;
92        r -= 4;
93    }
94    if (!(x & 0xc0000000u)) {
95        x <<= 2;
96        r -= 2;
97    }
98    if (!(x & 0x80000000u)) {
99        x <<= 1;
100        r -= 1;
101    }
102    return r;
103}
104
105static uint32_t hweight32(unsigned int w)
106{
107    uint32_t res = w - ((w >> 1) & 0x55555555);
108    res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
109    res = (res + (res >> 4)) & 0x0F0F0F0F;
110    res = res + (res >> 8);
111    return (res + (res >> 16)) & 0x000000FF;
112}
113/* End generic bit ops */
114
115void vm_lapic_reset(vm_vcpu_t *vcpu);
116
117// Returns whether the irq delivery mode is lowest prio
118inline static bool vm_is_dm_lowest_prio(struct vm_lapic_irq *irq)
119{
120    return irq->delivery_mode == APIC_DM_LOWEST;
121}
122
123// Access register field
124static inline void apic_set_reg(vm_lapic_t *apic, int reg_off, uint32_t val)
125{
126    *((uint32_t *)(apic->regs + reg_off)) = val;
127}
128
129static inline uint32_t vm_apic_get_reg(vm_lapic_t *apic, int reg_off)
130{
131    return *((uint32_t *)(apic->regs + reg_off));
132}
133
134static inline int apic_test_vector(int vec, void *bitmap)
135{
136    return ((1UL << (vec & 31)) & ((uint32_t *)bitmap)[vec >> 5]) != 0;
137}
138
139bool vm_apic_pending_eoi(vm_vcpu_t *vcpu, int vector)
140{
141    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
142
143    return apic_test_vector(vector, apic->regs + APIC_ISR) ||
144           apic_test_vector(vector, apic->regs + APIC_IRR);
145}
146
147static inline void apic_set_vector(int vec, void *bitmap)
148{
149    ((uint32_t *)bitmap)[vec >> 5] |= 1UL << (vec & 31);
150}
151
152static inline void apic_clear_vector(int vec, void *bitmap)
153{
154    ((uint32_t *)bitmap)[vec >> 5] &= ~(1UL << (vec & 31));
155}
156
157static inline int vm_apic_sw_enabled(vm_lapic_t *apic)
158{
159    return vm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
160}
161
162static inline int vm_apic_hw_enabled(vm_lapic_t *apic)
163{
164    return apic->apic_base & MSR_IA32_APICBASE_ENABLE;
165}
166
167inline int vm_apic_enabled(vm_lapic_t *apic)
168{
169    return vm_apic_sw_enabled(apic) && vm_apic_hw_enabled(apic);
170}
171
172#define LVT_MASK    \
173    (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK)
174
175#define LINT_MASK   \
176    (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
177     APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
178
179static inline int vm_apic_id(vm_lapic_t *apic)
180{
181    return (vm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
182}
183
184static inline void apic_set_spiv(vm_lapic_t *apic, uint32_t val)
185{
186    apic_set_reg(apic, APIC_SPIV, val);
187}
188
189static const unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
190    LVT_MASK,       /* part LVTT mask, timer mode mask added at runtime */
191    LVT_MASK | APIC_MODE_MASK,  /* LVTTHMR */
192    LVT_MASK | APIC_MODE_MASK,  /* LVTPC */
193    LINT_MASK, LINT_MASK,   /* LVT0-1 */
194    LVT_MASK        /* LVTERR */
195};
196
197static inline void vm_apic_set_id(vm_lapic_t *apic, uint8_t id)
198{
199    apic_set_reg(apic, APIC_ID, id << 24);
200}
201
202static inline void vm_apic_set_ldr(vm_lapic_t *apic, uint32_t id)
203{
204    apic_set_reg(apic, APIC_LDR, id);
205}
206
207static inline int apic_lvt_enabled(vm_lapic_t *apic, int lvt_type)
208{
209    return !(vm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
210}
211
212static inline int apic_lvt_vector(vm_lapic_t *apic, int lvt_type)
213{
214    return vm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
215}
216
217static inline int vm_vcpu_is_bsp(vm_vcpu_t *vcpu)
218{
219    return vcpu->vcpu_id == BOOT_VCPU;
220}
221
222static inline int apic_lvt_nmi_mode(uint32_t lvt_val)
223{
224    return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI;
225}
226
227int vm_apic_compare_prio(vm_vcpu_t *vcpu1, vm_vcpu_t *vcpu2)
228{
229    return vcpu1->vcpu_arch.lapic->arb_prio - vcpu2->vcpu_arch.lapic->arb_prio;
230}
231
232static void UNUSED dump_vector(const char *name, void *bitmap)
233{
234    int vec;
235    uint32_t *reg = bitmap;
236
237    printf("%s = 0x", name);
238
239    for (vec = MAX_APIC_VECTOR - APIC_VECTORS_PER_REG;
240         vec >= 0; vec -= APIC_VECTORS_PER_REG) {
241        printf("%08x", reg[vec >> 5]);
242    }
243
244    printf("\n");
245}
246
247static int find_highest_vector(void *bitmap)
248{
249    int vec;
250    uint32_t *reg = bitmap;
251
252    for (vec = MAX_APIC_VECTOR - APIC_VECTORS_PER_REG;
253         vec >= 0; vec -= APIC_VECTORS_PER_REG) {
254        if (reg[vec >> 5]) {
255            return fls(reg[vec >> 5]) - 1 + vec;
256        }
257    }
258
259    return -1;
260}
261
262static uint8_t UNUSED count_vectors(void *bitmap)
263{
264    int vec;
265    uint32_t *reg = bitmap;
266    uint8_t count = 0;
267
268    for (vec = 0; vec < MAX_APIC_VECTOR; vec += APIC_VECTORS_PER_REG) {
269        count += hweight32(reg[vec >> 5]);
270    }
271
272    return count;
273}
274
275static inline int apic_search_irr(vm_lapic_t *apic)
276{
277    return find_highest_vector(apic->regs + APIC_IRR);
278}
279
280static inline int apic_find_highest_irr(vm_lapic_t *apic)
281{
282    int result;
283
284    if (!apic->irr_pending) {
285        return -1;
286    }
287
288    result = apic_search_irr(apic);
289    assert(result == -1 || result >= 16);
290
291    return result;
292}
293
294static inline void apic_set_irr(int vec, vm_lapic_t *apic)
295{
296    if (vec != 0x30) {
297        apic_debug(5, "!settting irr 0x%x\n", vec);
298    }
299
300    apic->irr_pending = true;
301    apic_set_vector(vec, apic->regs + APIC_IRR);
302}
303
304static inline void apic_clear_irr(int vec, vm_lapic_t *apic)
305{
306    apic_clear_vector(vec, apic->regs + APIC_IRR);
307
308    vec = apic_search_irr(apic);
309    apic->irr_pending = (vec != -1);
310}
311
312static inline void apic_set_isr(int vec, vm_lapic_t *apic)
313{
314    if (apic_test_vector(vec, apic->regs + APIC_ISR)) {
315        return;
316    }
317    apic_set_vector(vec, apic->regs + APIC_ISR);
318
319    ++apic->isr_count;
320    /*
321     * ISR (in service register) bit is set when injecting an interrupt.
322     * The highest vector is injected. Thus the latest bit set matches
323     * the highest bit in ISR.
324     */
325}
326
327static inline int apic_find_highest_isr(vm_lapic_t *apic)
328{
329    int result;
330
331    /*
332     * Note that isr_count is always 1, and highest_isr_cache
333     * is always -1, with APIC virtualization enabled.
334     */
335    if (!apic->isr_count) {
336        return -1;
337    }
338    if (apic->highest_isr_cache != -1) {
339        return apic->highest_isr_cache;
340    }
341
342    result = find_highest_vector(apic->regs + APIC_ISR);
343    assert(result == -1 || result >= 16);
344
345    return result;
346}
347
348static inline void apic_clear_isr(int vec, vm_lapic_t *apic)
349{
350    if (!apic_test_vector(vec, apic->regs + APIC_ISR)) {
351        return;
352    }
353    apic_clear_vector(vec, apic->regs + APIC_ISR);
354
355    --apic->isr_count;
356    apic->highest_isr_cache = -1;
357}
358
359int vm_lapic_find_highest_irr(vm_vcpu_t *vcpu)
360{
361    int highest_irr;
362
363    highest_irr = apic_find_highest_irr(vcpu->vcpu_arch.lapic);
364
365    return highest_irr;
366}
367
368static int __apic_accept_irq(vm_vcpu_t *vcpu, int delivery_mode,
369                             int vector, int level, int trig_mode,
370                             unsigned long *dest_map);
371
372int vm_apic_set_irq(vm_vcpu_t *vcpu, struct vm_lapic_irq *irq,
373                    unsigned long *dest_map)
374{
375    return __apic_accept_irq(vcpu, irq->delivery_mode, irq->vector,
376                             irq->level, irq->trig_mode, dest_map);
377}
378
379void vm_apic_update_tmr(vm_vcpu_t *vcpu, uint32_t *tmr)
380{
381    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
382    int i;
383
384    for (i = 0; i < 8; i++) {
385        apic_set_reg(apic, APIC_TMR + 0x10 * i, tmr[i]);
386    }
387}
388
389static void apic_update_ppr(vm_vcpu_t *vcpu)
390{
391    uint32_t tpr, isrv, ppr, old_ppr;
392    int isr;
393    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
394
395    old_ppr = vm_apic_get_reg(apic, APIC_PROCPRI);
396    tpr = vm_apic_get_reg(apic, APIC_TASKPRI);
397    isr = apic_find_highest_isr(apic);
398    isrv = (isr != -1) ? isr : 0;
399
400    if ((tpr & 0xf0) >= (isrv & 0xf0)) {
401        ppr = tpr & 0xff;
402    } else {
403        ppr = isrv & 0xf0;
404    }
405
406    apic_debug(6, "vlapic %p, ppr 0x%x, isr 0x%x, isrv 0x%x\n",
407               apic, ppr, isr, isrv);
408
409    if (old_ppr != ppr) {
410        apic_set_reg(apic, APIC_PROCPRI, ppr);
411        if (ppr < old_ppr) {
412            /* Might have unmasked some pending interrupts */
413            vm_vcpu_accept_interrupt(vcpu);
414        }
415    }
416}
417
418static void apic_set_tpr(vm_vcpu_t *vcpu, uint32_t tpr)
419{
420    apic_set_reg(vcpu->vcpu_arch.lapic, APIC_TASKPRI, tpr);
421    apic_debug(3, "vcpu %d lapic TPR set to %d\n", vcpu->vcpu_id, tpr);
422    apic_update_ppr(vcpu);
423}
424
425int vm_apic_match_physical_addr(vm_lapic_t *apic, uint16_t dest)
426{
427    return dest == 0xff || vm_apic_id(apic) == dest;
428}
429
430int vm_apic_match_logical_addr(vm_lapic_t *apic, uint8_t mda)
431{
432    int result = 0;
433    uint32_t logical_id;
434
435    logical_id = GET_APIC_LOGICAL_ID(vm_apic_get_reg(apic, APIC_LDR));
436
437    switch (vm_apic_get_reg(apic, APIC_DFR)) {
438    case APIC_DFR_FLAT:
439        if (logical_id & mda) {
440            result = 1;
441        }
442        break;
443    case APIC_DFR_CLUSTER:
444        if (((logical_id >> 4) == (mda >> 0x4))
445            && (logical_id & mda & 0xf)) {
446            result = 1;
447        }
448        break;
449    default:
450        apic_debug(1, "Bad DFR: %08x\n", vm_apic_get_reg(apic, APIC_DFR));
451        break;
452    }
453
454    return result;
455}
456
457int vm_apic_match_dest(vm_vcpu_t *vcpu, vm_lapic_t *source,
458                       int short_hand, int dest, int dest_mode)
459{
460    int result = 0;
461    vm_lapic_t *target = vcpu->vcpu_arch.lapic;
462
463    assert(target);
464    switch (short_hand) {
465    case APIC_DEST_NOSHORT:
466        if (dest_mode == 0)
467            /* Physical mode. */
468        {
469            result = vm_apic_match_physical_addr(target, dest);
470        } else
471            /* Logical mode. */
472        {
473            result = vm_apic_match_logical_addr(target, dest);
474        }
475        break;
476    case APIC_DEST_SELF:
477        result = (target == source);
478        break;
479    case APIC_DEST_ALLINC:
480        result = 1;
481        break;
482    case APIC_DEST_ALLBUT:
483        result = (target != source);
484        break;
485    default:
486        apic_debug(2, "apic: Bad dest shorthand value %x\n",
487                   short_hand);
488        break;
489    }
490
491    apic_debug(4, "target %p, source %p, dest 0x%x, "
492               "dest_mode 0x%x, short_hand 0x%x",
493               target, source, dest, dest_mode, short_hand);
494    if (result) {
495        apic_debug(4, " MATCH\n");
496    } else {
497        apic_debug(4, "\n");
498    }
499
500    return result;
501}
502
503int vm_irq_delivery_to_apic(vm_vcpu_t *src_vcpu, struct vm_lapic_irq *irq, unsigned long *dest_map)
504{
505    int i, r = -1;
506    vm_lapic_t *src = src_vcpu->vcpu_arch.lapic;
507    vm_t *vm = src_vcpu->vm;
508
509    vm_vcpu_t *lowest = NULL;
510
511    if (irq->shorthand == APIC_DEST_SELF) {
512        return vm_apic_set_irq(src_vcpu, irq, dest_map);
513    }
514
515    vm_vcpu_t *dest_vcpu = vm->vcpus[BOOT_VCPU];
516
517    if (!vm_apic_hw_enabled(dest_vcpu->vcpu_arch.lapic)) {
518        return r;
519    }
520
521    if (!vm_apic_match_dest(dest_vcpu, src, irq->shorthand,
522                            irq->dest_id, irq->dest_mode)) {
523        return r;
524    }
525
526    if (!vm_is_dm_lowest_prio(irq) || (vm_apic_enabled(dest_vcpu->vcpu_arch.lapic))) {
527        r = vm_apic_set_irq(dest_vcpu, irq, dest_map);
528    }
529
530    return r;
531}
532
533/*
534 * Add a pending IRQ into lapic.
535 * Return 1 if successfully added and 0 if discarded.
536 */
537static int __apic_accept_irq(vm_vcpu_t *vcpu, int delivery_mode,
538                             int vector, int level, int trig_mode,
539                             unsigned long *dest_map)
540{
541    int result = 0;
542    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
543
544    switch (delivery_mode) {
545    case APIC_DM_LOWEST:
546        apic->arb_prio++;
547    case APIC_DM_FIXED:
548        /* FIXME add logic for vcpu on reset */
549        if (!vm_apic_enabled(apic)) {
550            break;
551        }
552        apic_debug(4, "####fixed ipi 0x%x to vcpu %d\n", vector, vcpu->vcpu_id);
553
554        result = 1;
555        apic_set_irr(vector, apic);
556        vm_vcpu_accept_interrupt(vcpu);
557        break;
558
559    case APIC_DM_NMI:
560    case APIC_DM_REMRD:
561        result = 1;
562        vm_vcpu_accept_interrupt(vcpu);
563        break;
564
565    case APIC_DM_SMI:
566        apic_debug(2, "Ignoring guest SMI\n");
567        break;
568
569    case APIC_DM_INIT:
570        apic_debug(2, "Got init ipi on vcpu %d\n", vcpu->vcpu_id);
571        if (!trig_mode || level) {
572            if (apic->state == LAPIC_STATE_RUN) {
573                /* Already running, ignore inits */
574                break;
575            }
576            result = 1;
577            vm_lapic_reset(vcpu);
578            apic->arb_prio = vm_apic_id(apic);
579            apic->state = LAPIC_STATE_WAITSIPI;
580        } else {
581            apic_debug(2, "Ignoring de-assert INIT to vcpu %d\n",
582                       vcpu->vcpu_id);
583        }
584        break;
585
586    case APIC_DM_STARTUP:
587        if (apic->state != LAPIC_STATE_WAITSIPI) {
588            apic_debug(1, "Received SIPI while processor was not in wait for SIPI state\n");
589        } else {
590            apic_debug(2, "SIPI to vcpu %d vector 0x%02x\n",
591                       vcpu->vcpu_id, vector);
592            result = 1;
593            apic->sipi_vector = vector;
594            apic->state = LAPIC_STATE_RUN;
595
596            /* Start the VCPU thread. */
597            vm_start_ap_vcpu(vcpu, vector);
598        }
599        break;
600
601    case APIC_DM_EXTINT:
602        /* extints are handled by vm_apic_consume_extints */
603        printf("extint should not come to this function. vcpu %d\n", vcpu->vcpu_id);
604        assert(0);
605        break;
606
607    default:
608        printf("TODO: unsupported lapic ipi delivery mode %x", delivery_mode);
609        assert(0);
610        break;
611    }
612    return result;
613}
614
615static int apic_set_eoi(vm_vcpu_t *vcpu)
616{
617    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
618    int vector = apic_find_highest_isr(apic);
619
620    /*
621     * Not every write EOI will has corresponding ISR,
622     * one example is when Kernel check timer on setup_IO_APIC
623     */
624    if (vector == -1) {
625        return vector;
626    }
627
628    apic_clear_isr(vector, apic);
629    apic_update_ppr(vcpu);
630
631    /* If another interrupt is pending, raise it */
632    vm_vcpu_accept_interrupt(vcpu);
633
634    return vector;
635}
636
637static void apic_send_ipi(vm_vcpu_t *vcpu)
638{
639    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
640    uint32_t icr_low = vm_apic_get_reg(apic, APIC_ICR);
641    uint32_t icr_high = vm_apic_get_reg(apic, APIC_ICR2);
642    struct vm_lapic_irq irq;
643
644    irq.vector = icr_low & APIC_VECTOR_MASK;
645    irq.delivery_mode = icr_low & APIC_MODE_MASK;
646    irq.dest_mode = icr_low & APIC_DEST_MASK;
647    irq.level = icr_low & APIC_INT_ASSERT;
648    irq.trig_mode = icr_low & APIC_INT_LEVELTRIG;
649    irq.shorthand = icr_low & APIC_SHORT_MASK;
650    irq.dest_id = GET_APIC_DEST_FIELD(icr_high);
651
652    apic_debug(3, "icr_high 0x%x, icr_low 0x%x, "
653               "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
654               "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
655               icr_high, icr_low, irq.shorthand, irq.dest_id,
656               irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
657               irq.vector);
658
659    vm_irq_delivery_to_apic(vcpu, &irq, NULL);
660}
661
662static uint32_t __apic_read(vm_lapic_t *apic, unsigned int offset)
663{
664    uint32_t val = 0;
665
666    if (offset >= LAPIC_MMIO_LENGTH) {
667        return 0;
668    }
669
670    switch (offset) {
671    case APIC_ID:
672        val = vm_apic_id(apic) << 24;
673        break;
674    case APIC_ARBPRI:
675        apic_debug(2, "Access APIC ARBPRI register which is for P6\n");
676        break;
677
678    case APIC_TMCCT:    /* Timer CCR */
679        break;
680    case APIC_PROCPRI:
681        val = vm_apic_get_reg(apic, offset);
682        break;
683    default:
684        val = vm_apic_get_reg(apic, offset);
685        break;
686    }
687
688    return val;
689}
690
691static void apic_manage_nmi_watchdog(vm_lapic_t *apic, uint32_t lvt0_val)
692{
693    int nmi_wd_enabled = apic_lvt_nmi_mode(vm_apic_get_reg(apic, APIC_LVT0));
694
695    if (apic_lvt_nmi_mode(lvt0_val)) {
696        if (!nmi_wd_enabled) {
697            apic_debug(4, "Receive NMI setting on APIC_LVT0 \n");
698        }
699    }
700}
701
702static int apic_reg_write(vm_vcpu_t *vcpu, uint32_t reg, uint32_t val)
703{
704    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
705    int ret = 0;
706
707    switch (reg) {
708    case APIC_ID:       /* Local APIC ID */
709        vm_apic_set_id(apic, val >> 24);
710        break;
711
712    case APIC_TASKPRI:
713        apic_set_tpr(vcpu, val & 0xff);
714        break;
715
716    case APIC_EOI:
717        apic_set_eoi(vcpu);
718        break;
719
720    case APIC_LDR:
721        vm_apic_set_ldr(apic, val & APIC_LDR_MASK);
722        break;
723
724    case APIC_DFR:
725        apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
726        break;
727
728    case APIC_SPIV: {
729        uint32_t mask = 0x3ff;
730        if (vm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI) {
731            mask |= APIC_SPIV_DIRECTED_EOI;
732        }
733        apic_set_spiv(apic, val & mask);
734        if (!(val & APIC_SPIV_APIC_ENABLED)) {
735            int i;
736            uint32_t lvt_val;
737
738            for (i = 0; i < APIC_LVT_NUM; i++) {
739                lvt_val = vm_apic_get_reg(apic,
740                                          APIC_LVTT + 0x10 * i);
741                apic_set_reg(apic, APIC_LVTT + 0x10 * i,
742                             lvt_val | APIC_LVT_MASKED);
743            }
744            //    atomic_set(&apic->lapic_timer.pending, 0);
745
746        }
747        break;
748    }
749    case APIC_ICR:
750        /* No delay here, so we always clear the pending bit */
751        apic_set_reg(apic, APIC_ICR, val & ~(BIT(12)));
752        apic_send_ipi(vcpu);
753        break;
754
755    case APIC_ICR2:
756        val &= 0xff000000;
757        apic_set_reg(apic, APIC_ICR2, val);
758        break;
759
760    case APIC_LVT0:
761        apic_manage_nmi_watchdog(apic, val);
762    case APIC_LVTTHMR:
763    case APIC_LVTPC:
764    case APIC_LVT1:
765    case APIC_LVTERR:
766        /* TODO: Check vector */
767        if (!vm_apic_sw_enabled(apic)) {
768            val |= APIC_LVT_MASKED;
769        }
770
771        val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
772        apic_set_reg(apic, reg, val);
773
774        break;
775
776    case APIC_LVTT:
777        apic_set_reg(apic, APIC_LVTT, val);
778        break;
779
780    case APIC_TMICT:
781        apic_set_reg(apic, APIC_TMICT, val);
782        break;
783
784    case APIC_TDCR:
785        apic_set_reg(apic, APIC_TDCR, val);
786        break;
787
788    default:
789        ret = 1;
790        break;
791    }
792    if (ret) {
793        apic_debug(2, "Local APIC Write to read-only register %x\n", reg);
794    }
795    return ret;
796}
797
798void vm_apic_mmio_write(vm_vcpu_t *vcpu, void *cookie, uint32_t offset,
799                        int len, const uint32_t data)
800{
801    (void)cookie;
802
803    /*
804     * APIC register must be aligned on 128-bits boundary.
805     * 32/64/128 bits registers must be accessed thru 32 bits.
806     * Refer SDM 8.4.1
807     */
808    if (len != 4 || (offset & 0xf)) {
809        apic_debug(1, "apic write: bad size=%d %x\n", len, offset);
810        return;
811    }
812
813    /* too common printing */
814    if (offset != APIC_EOI)
815        apic_debug(6, "lapic mmio write at %s: offset 0x%x with length 0x%x, and value is "
816                   "0x%x\n", __func__, offset, len, data);
817
818    apic_reg_write(vcpu, offset & 0xff0, data);
819}
820
821static int apic_reg_read(vm_lapic_t *apic, uint32_t offset, int len,
822                         void *data)
823{
824    unsigned char alignment = offset & 0xf;
825    uint32_t result;
826    /* this bitmask has a bit cleared for each reserved register */
827    static const uint64_t rmask = 0x43ff01ffffffe70cULL;
828
829    if ((alignment + len) > 4) {
830        apic_debug(2, "APIC READ: alignment error %x %d\n",
831                   offset, len);
832        return 1;
833    }
834
835    if (offset > 0x3f0 || !(rmask & (1ULL << (offset >> 4)))) {
836        apic_debug(2, "APIC_READ: read reserved register %x\n",
837                   offset);
838        return 1;
839    }
840
841    result = __apic_read(apic, offset & ~0xf);
842
843    switch (len) {
844    case 1:
845    case 2:
846    case 4:
847        memcpy(data, (char *)&result + alignment, len);
848        break;
849    default:
850        apic_debug(2, "Local APIC read with len = %x, "
851                   "should be 1,2, or 4 instead\n", len);
852        break;
853    }
854    return 0;
855}
856
857void vm_apic_mmio_read(vm_vcpu_t *vcpu, void *cookie, uint32_t offset,
858                       int len, uint32_t *data)
859{
860    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
861    (void)cookie;
862
863    apic_reg_read(apic, offset, len, data);
864
865    apic_debug(6, "lapic mmio read on vcpu %d, reg %08x = %08x\n", vcpu->vcpu_id, offset, *data);
866
867    return;
868}
869
870memory_fault_result_t apic_fault_callback(vm_t *vm, vm_vcpu_t *vcpu, uintptr_t fault_addr, size_t fault_length,
871                                          void *cookie)
872{
873    uint32_t data;
874    if (is_vcpu_read_fault(vcpu)) {
875        vm_apic_mmio_read(vcpu, cookie, APIC_DEFAULT_PHYS_BASE - fault_addr, fault_length, &data);
876        set_vcpu_fault_data(vcpu, data);
877    } else {
878        data = get_vcpu_fault_data(vcpu);
879        vm_apic_mmio_write(vcpu, cookie, APIC_DEFAULT_PHYS_BASE - fault_addr, fault_length, data);
880    }
881    advance_vcpu_fault(vcpu);
882    return FAULT_HANDLED;
883}
884
885void vm_free_lapic(vm_vcpu_t *vcpu)
886{
887    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
888
889    if (!apic) {
890        return;
891    }
892
893    if (apic->regs) {
894        free(apic->regs);
895    }
896
897    free(apic);
898}
899
900void vm_lapic_set_base_msr(vm_vcpu_t *vcpu, uint32_t value)
901{
902    apic_debug(2, "IA32_APIC_BASE MSR set to %08x on vcpu %d\n", value, vcpu->vcpu_id);
903
904    if (!(value & MSR_IA32_APICBASE_ENABLE)) {
905        printf("Warning! Local apic has been disabled by MSR on vcpu %d. "
906               "This will probably not work!\n", vcpu->vcpu_id);
907    }
908
909    vcpu->vcpu_arch.lapic->apic_base = value;
910}
911
912uint32_t vm_lapic_get_base_msr(vm_vcpu_t *vcpu)
913{
914    uint32_t value = vcpu->vcpu_arch.lapic->apic_base;
915
916    if (vm_vcpu_is_bsp(vcpu)) {
917        value |= MSR_IA32_APICBASE_BSP;
918    } else {
919        value &= ~MSR_IA32_APICBASE_BSP;
920    }
921
922    apic_debug(2, "Read from IA32_APIC_BASE MSR returns %08x on vcpu %d\n", value, vcpu->vcpu_id);
923
924    return value;
925}
926
927void vm_lapic_reset(vm_vcpu_t *vcpu)
928{
929    vm_lapic_t *apic;
930    int i;
931
932    apic_debug(4, "%s\n", __func__);
933
934    assert(vcpu);
935    apic = vcpu->vcpu_arch.lapic;
936    assert(apic != NULL);
937
938    /* Stop the timer in case it's a reset to an active apic */
939
940    vm_apic_set_id(apic, vcpu->vcpu_id); /* In agreement with ACPI code */
941    apic_set_reg(apic, APIC_LVR, APIC_VERSION);
942
943    for (i = 0; i < APIC_LVT_NUM; i++) {
944        apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
945    }
946
947    apic_set_reg(apic, APIC_DFR, 0xffffffffU);
948    apic_set_spiv(apic, 0xff);
949    apic_set_reg(apic, APIC_TASKPRI, 0);
950    vm_apic_set_ldr(apic, 0);
951    apic_set_reg(apic, APIC_ESR, 0);
952    apic_set_reg(apic, APIC_ICR, 0);
953    apic_set_reg(apic, APIC_ICR2, 0);
954    apic_set_reg(apic, APIC_TDCR, 0);
955    apic_set_reg(apic, APIC_TMICT, 0);
956    for (i = 0; i < 8; i++) {
957        apic_set_reg(apic, APIC_IRR + 0x10 * i, 0);
958        apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
959        apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
960    }
961    apic->irr_pending = 0;
962    apic->isr_count = 0;
963    apic->highest_isr_cache = -1;
964    apic_update_ppr(vcpu);
965
966    vcpu->vcpu_arch.lapic->arb_prio = 0;
967
968    apic_debug(4, "%s: vcpu=%p, id=%d, base_msr="
969               "0x%016x\n", __func__,
970               vcpu, vm_apic_id(apic),
971               apic->apic_base);
972
973    if (vcpu->vcpu_id == BOOT_VCPU) {
974        /* Bootstrap boot vcpu lapic in virtual wire mode */
975        apic_set_reg(apic, APIC_LVT0,
976                     SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
977        apic_set_reg(apic, APIC_SPIV, APIC_SPIV_APIC_ENABLED);
978
979        assert(vm_apic_sw_enabled(apic));
980    } else {
981        apic_set_reg(apic, APIC_SPIV, 0);
982    }
983}
984
985int vm_create_lapic(vm_vcpu_t *vcpu, int enabled)
986{
987    vm_lapic_t *apic;
988
989    assert(vcpu != NULL);
990    apic_debug(2, "apic_init %d\n", vcpu->vcpu_id);
991
992    apic = calloc(1, sizeof(*apic));
993    if (!apic) {
994        goto nomem;
995    }
996
997    vcpu->vcpu_arch.lapic = apic;
998
999    apic->regs = calloc(1, sizeof(struct local_apic_regs)); // TODO this is a page; allocate a page
1000    if (!apic->regs) {
1001        printf("calloc apic regs error for vcpu %x\n",
1002               vcpu->vcpu_id);
1003        goto nomem_free_apic;
1004    }
1005
1006    if (enabled) {
1007        vm_lapic_set_base_msr(vcpu, APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE);
1008    } else {
1009        vm_lapic_set_base_msr(vcpu, APIC_DEFAULT_PHYS_BASE);
1010    }
1011
1012    /* mainly init registers */
1013    vm_lapic_reset(vcpu);
1014
1015    return 0;
1016nomem_free_apic:
1017    free(apic);
1018nomem:
1019    return -1;
1020}
1021
1022/* Return 1 if this vcpu should accept a PIC interrupt */
1023int vm_apic_accept_pic_intr(vm_vcpu_t *vcpu)
1024{
1025    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
1026    uint32_t lvt0 = vm_apic_get_reg(apic, APIC_LVT0);
1027
1028    return ((lvt0 & APIC_LVT_MASKED) == 0 &&
1029            GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT &&
1030            vm_apic_sw_enabled(vcpu->vcpu_arch.lapic));
1031}
1032
1033/* Service an interrupt */
1034int vm_apic_get_interrupt(vm_vcpu_t *vcpu)
1035{
1036    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
1037    int vector = vm_apic_has_interrupt(vcpu);
1038
1039    if (vector == 1) {
1040        return pic_get_interrupt(vcpu->vm);
1041    } else if (vector == -1) {
1042        return -1;
1043    }
1044
1045    apic_set_isr(vector, apic);
1046    apic_update_ppr(vcpu);
1047    apic_clear_irr(vector, apic);
1048    return vector;
1049}
1050
1051/* Return which vector is next up for servicing */
1052int vm_apic_has_interrupt(vm_vcpu_t *vcpu)
1053{
1054    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
1055    int highest_irr;
1056
1057    if (vm_apic_accept_pic_intr(vcpu) && pic_has_interrupt(vcpu->vm)) {
1058        return 1;
1059    }
1060
1061    highest_irr = apic_find_highest_irr(apic);
1062    if ((highest_irr == -1) ||
1063        ((highest_irr & 0xF0) <= vm_apic_get_reg(apic, APIC_PROCPRI))) {
1064        return -1;
1065    }
1066
1067    return highest_irr;
1068}
1069
1070#if 0
1071int vm_apic_local_deliver(vm_vcpu_t *vcpu, int lvt_type)
1072{
1073    vm_lapic_t *apic = vcpu->vcpu_arch.lapic;
1074    uint32_t reg = vm_apic_get_reg(apic, lvt_type);
1075    int vector, mode, trig_mode;
1076
1077    if (!(reg & APIC_LVT_MASKED)) {
1078        vector = reg & APIC_VECTOR_MASK;
1079        mode = reg & APIC_MODE_MASK;
1080        trig_mode = reg & APIC_LVT_LEVEL_TRIGGER;
1081        return __apic_accept_irq(vcpu, mode, vector, 1, trig_mode, NULL);
1082    }
1083    return 0;
1084}
1085#endif
1086