aboutsummaryrefslogtreecommitdiffstats
path: root/include/hw/i386/apic_internal.h
blob: c175e7e718165d81824f2b3348ee09ee8637fd86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/*
 *  APIC support - internal interfaces
 *
 *  Copyright (c) 2004-2005 Fabrice Bellard
 *  Copyright (c) 2011      Jan Kiszka, Siemens AG
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <http://www.gnu.org/licenses/>
 */

#ifndef QEMU_APIC_INTERNAL_H
#define QEMU_APIC_INTERNAL_H

#include "cpu.h"
#include "exec/memory.h"
#include "qemu/timer.h"
#include "target/i386/cpu-qom.h"
#include "qom/object.h"

/* APIC Local Vector Table */
#define APIC_LVT_TIMER                  0
#define APIC_LVT_THERMAL                1
#define APIC_LVT_PERFORM                2
#define APIC_LVT_LINT0                  3
#define APIC_LVT_LINT1                  4
#define APIC_LVT_ERROR                  5
#define APIC_LVT_NB                     6

/* APIC delivery modes */
#define APIC_DM_FIXED                   0
#define APIC_DM_LOWPRI                  1
#define APIC_DM_SMI                     2
#define APIC_DM_NMI                     4
#define APIC_DM_INIT                    5
#define APIC_DM_SIPI                    6
#define APIC_DM_EXTINT                  7

/* APIC destination mode */
#define APIC_DESTMODE_FLAT              0xf
#define APIC_DESTMODE_CLUSTER           1

#define APIC_TRIGGER_EDGE               0
#define APIC_TRIGGER_LEVEL              1

#define APIC_VECTOR_MASK                0xff
#define APIC_DCR_MASK                   0xf

#define APIC_LVT_TIMER_SHIFT            17
#define APIC_LVT_MASKED_SHIFT           16
#define APIC_LVT_LEVEL_TRIGGER_SHIFT    15
#define APIC_LVT_REMOTE_IRR_SHIFT       14
#define APIC_LVT_INT_POLARITY_SHIFT     13
#define APIC_LVT_DELIV_STS_SHIFT        12
#define APIC_LVT_DELIV_MOD_SHIFT        8

#define APIC_LVT_TIMER_TSCDEADLINE      (2 << APIC_LVT_TIMER_SHIFT)
#define APIC_LVT_TIMER_PERIODIC         (1 << APIC_LVT_TIMER_SHIFT)
#define APIC_LVT_MASKED                 (1 << APIC_LVT_MASKED_SHIFT)
#define APIC_LVT_LEVEL_TRIGGER          (1 << APIC_LVT_LEVEL_TRIGGER_SHIFT)
#define APIC_LVT_REMOTE_IRR             (1 << APIC_LVT_REMOTE_IRR_SHIFT)
#define APIC_LVT_INT_POLARITY           (1 << APIC_LVT_INT_POLARITY_SHIFT)
#define APIC_LVT_DELIV_STS              (1 << APIC_LVT_DELIV_STS_SHIFT)
#define APIC_LVT_DELIV_MOD              (7 << APIC_LVT_DELIV_MOD_SHIFT)

#define APIC_ESR_ILL_ADDRESS_SHIFT      7
#define APIC_ESR_RECV_ILL_VECT_SHIFT    6
#define APIC_ESR_SEND_ILL_VECT_SHIFT    5
#define APIC_ESR_RECV_ACCEPT_SHIFT      3
#define APIC_ESR_SEND_ACCEPT_SHIFT      2
#define APIC_ESR_RECV_CHECK_SUM_SHIFT   1

#define APIC_ESR_ILLEGAL_ADDRESS        (1 << APIC_ESR_ILL_ADDRESS_SHIFT)
#define APIC_ESR_RECV_ILLEGAL_VECT      (1 << APIC_ESR_RECV_ILL_VECT_SHIFT)
#define APIC_ESR_SEND_ILLEGAL_VECT      (1 << APIC_ESR_SEND_ILL_VECT_SHIFT)
#define APIC_ESR_RECV_ACCEPT            (1 << APIC_ESR_RECV_ACCEPT_SHIFT)
#define APIC_ESR_SEND_ACCEPT            (1 << APIC_ESR_SEND_ACCEPT_SHIFT)
#define APIC_ESR_RECV_CHECK_SUM         (1 << APIC_ESR_RECV_CHECK_SUM_SHIFT)
#define APIC_ESR_SEND_CHECK_SUM         1

#define APIC_ICR_DEST_SHIFT             24
#define APIC_ICR_DEST_SHORT_SHIFT       18
#define APIC_ICR_TRIGGER_MOD_SHIFT      15
#define APIC_ICR_LEVEL_SHIFT            14
#define APIC_ICR_DELIV_STS_SHIFT        12
#define APIC_ICR_DEST_MOD_SHIFT         11
#define APIC_ICR_DELIV_MOD_SHIFT        8

#define APIC_ICR_DEST_SHORT             (3 << APIC_ICR_DEST_SHORT_SHIFT)
#define APIC_ICR_TRIGGER_MOD            (1 << APIC_ICR_TRIGGER_MOD_SHIFT)
#define APIC_ICR_LEVEL                  (1 << APIC_ICR_LEVEL_SHIFT)
#define APIC_ICR_DELIV_STS              (1 << APIC_ICR_DELIV_STS_SHIFT)
#define APIC_ICR_DEST_MOD               (1 << APIC_ICR_DEST_MOD_SHIFT)
#define APIC_ICR_DELIV_MOD              (7 << APIC_ICR_DELIV_MOD_SHIFT)

#define APIC_PR_CLASS_SHIFT             4
#define APIC_PR_SUB_CLASS               0xf

#define APIC_LOGDEST_XAPIC_SHIFT        4
#define APIC_LOGDEST_XAPIC_ID           0xf

#define APIC_LOGDEST_X2APIC_SHIFT       16
#define APIC_LOGDEST_X2APIC_ID          0xffff

#define APIC_SPURIO_FOCUS_SHIFT         9
#define APIC_SPURIO_ENABLED_SHIFT       8

#define APIC_SPURIO_FOCUS               (1 << APIC_SPURIO_FOCUS_SHIFT)
#define APIC_SPURIO_ENABLED             (1 << APIC_SPURIO_ENABLED_SHIFT)

#define APIC_SV_DIRECTED_IO             (1 << 12)
#define APIC_SV_ENABLE                  (1 << 8)

#define VAPIC_ENABLE_BIT                0
#define VAPIC_ENABLE_MASK               (1 << VAPIC_ENABLE_BIT)

typedef struct APICCommonState APICCommonState;

#define TYPE_APIC_COMMON "apic-common"
typedef struct APICCommonClass APICCommonClass;
DECLARE_OBJ_CHECKERS(APICCommonState, APICCommonClass,
                     APIC_COMMON, TYPE_APIC_COMMON)

struct APICCommonClass {
    DeviceClass parent_class;

    DeviceRealize realize;
    DeviceUnrealize unrealize;
    void (*set_base)(APICCommonState *s, uint64_t val);
    void (*set_tpr)(APICCommonState *s, uint8_t val);
    uint8_t (*get_tpr)(APICCommonState *s);
    void (*enable_tpr_reporting)(APICCommonState *s, bool enable);
    void (*vapic_base_update)(APICCommonState *s);
    void (*external_nmi)(APICCommonState *s);
    void (*pre_save)(APICCommonState *s);
    void (*post_load)(APICCommonState *s);
    void (*reset)(APICCommonState *s);
    /* send_msi emulates an APIC bus and its proper place would be in a new
     * device, but it's convenient to have it here for now.
     */
    void (*send_msi)(MSIMessage *msi);
};

struct APICCommonState {
    /*< private >*/
    DeviceState parent_obj;
    /*< public >*/

    MemoryRegion io_memory;
    X86CPU *cpu;
    uint32_t apicbase;
    uint8_t id; /* legacy APIC ID */
    uint32_t initial_apic_id;
    uint8_t version;
    uint8_t arb_id;
    uint8_t tpr;
    uint32_t spurious_vec;
    uint8_t log_dest;
    uint8_t dest_mode;
    uint32_t isr[8];  /* in service register */
    uint32_t tmr[8];  /* trigger mode register */
    uint32_t irr[8]; /* interrupt request register */
    uint32_t lvt[APIC_LVT_NB];
    uint32_t esr; /* error register */
    uint32_t icr[2];

    uint32_t divide_conf;
    int count_shift;
    uint32_t initial_count;
    int64_t initial_count_load_time;
    int64_t next_time;
    QEMUTimer *timer;
    int64_t timer_expiry;
    int sipi_vector;
    int wait_for_sipi;

    uint32_t vapic_control;
    DeviceState *vapic;
    hwaddr vapic_paddr; /* note: persistence via kvmvapic */
    bool legacy_instance_id;
};

typedef struct VAPICState {
    uint8_t tpr;
    uint8_t isr;
    uint8_t zero;
    uint8_t irr;
    uint8_t enabled;
} QEMU_PACKED VAPICState;

extern bool apic_report_tpr_access;

void apic_report_irq_delivered(int delivered);
bool apic_next_timer(APICCommonState *s, int64_t current_time);
void apic_enable_tpr_access_reporting(DeviceState *d, bool enable);
void apic_enable_vapic(DeviceState *d, hwaddr paddr);

void vapic_report_tpr_access(DeviceState *dev, CPUState *cpu, target_ulong ip,
                             TPRAccess access);

int apic_get_ppr(APICCommonState *s);
uint32_t apic_get_current_count(APICCommonState *s);

static inline void apic_set_bit(uint32_t *tab, int index)
{
    int i, mask;
    i = index >> 5;
    mask = 1 << (index & 0x1f);
    tab[i] |= mask;
}

static inline int apic_get_bit(uint32_t *tab, int index)
{
    int i, mask;
    i = index >> 5;
    mask = 1 << (index & 0x1f);
    return !!(tab[i] & mask);
}

APICCommonClass *apic_get_class(void);

#endif /* QEMU_APIC_INTERNAL_H */