2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
11 * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21 #include <devices/apic.h>
22 #include <devices/apic_regs.h>
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_msr.h>
26 #define BASE_ADDR_MSR 0x0000001B
27 #define DEFAULT_BASE_ADDR 0xfee00000
29 #define APIC_ID_OFFSET 0x020
30 #define APIC_VERSION_OFFSET 0x030
31 #define TPR_OFFSET 0x080
32 #define APR_OFFSET 0x090
33 #define PPR_OFFSET 0x0a0
34 #define EOI_OFFSET 0x0b0
35 #define REMOTE_READ_OFFSET 0x0c0
36 #define LDR_OFFSET 0x0d0
37 #define DFR_OFFSET 0x0e0
38 #define SPURIOUS_INT_VEC_OFFSET 0x0f0
39 #define ISR_OFFSET 0x100 // 0x100 - 0x170
40 #define TMR_OFFSET 0x180 // 0x180 - 0x1f0
41 #define IRR_OFFSET 0x200 // 0x200 - 0x270
42 #define ESR_OFFSET 0x280
43 #define INT_CMD_LO_OFFSET 0x300
44 #define INT_CMD_HI_OFFSET 0x310
45 #define TMR_LOC_VEC_TBL_OFFSET 0x320
46 #define THERM_LOC_VEC_TBL_OFFSET 0x330
47 #define PERF_CTR_LOC_VEC_TBL_OFFSET 0x340
48 #define LINT0_VEC_TBL_OFFSET 0x350
49 #define LINT1_VEC_TBL_OFFSET 0x360
50 #define ERR_VEC_TBL_OFFSET 0x370
51 #define TMR_INIT_CNT_OFFSET 0x380
52 #define TMR_CUR_CNT_OFFSET 0x390
53 #define TMR_DIV_CFG_OFFSET 0x3e0
54 #define EXT_APIC_FEATURE_OFFSET 0x400
55 #define EXT_APIC_CMD_OFFSET 0x410
56 #define SEOI_OFFSET 0x420
57 #define IER_OFFSET 0x480 // 0x480 - 0x4f0
58 #define EXT_INT_LOC_VEC_TBL_OFFSET 0x500 // 0x500 - 0x530
61 struct apic_base_addr_msr {
68 uint_t apic_enable : 1;
69 ullong_t base_addr : 40;
71 } __attribute__((packed));
72 } __attribute__((packed));
73 } __attribute__((packed));
82 v3_msr_t base_addr_msr;
85 /* memory map registers */
87 struct lapic_id_reg lapic_id;
88 struct apic_ver_reg apic_ver;
89 struct ext_apic_ctrl_reg ext_apic_ctrl;
90 struct local_vec_tbl_reg local_vec_tbl;
91 struct tmr_vec_tbl_reg tmr_vec_tbl;
92 struct div_cfg_reg div_cfg;
93 struct lint_vec_tbl_reg lint_vec_tbl;
94 struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
95 struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
96 struct err_vec_tbl_reg err_vec_tbl;
97 struct err_status_reg err_status;
98 struct spurious_int_reg spurious_int;
99 struct int_cmd_reg int_cmd;
100 struct loc_dst_reg loc_dst;
101 struct dst_fmt_reg dst_fmt;
102 struct arb_prio_reg arb_prio;
103 struct task_prio_reg task_prio;
104 struct proc_prio_reg proc_prio;
105 struct ext_apic_feature_reg ext_apic_feature;
106 struct spec_eoi_reg spec_eoi;
109 uint32_t tmr_cur_cnt_reg;
110 uint32_t tmr_init_cnt_reg;
114 uint32_t rem_rd_data;
117 uchar_t int_req_reg[32];
118 uchar_t int_svc_reg[32];
119 uchar_t int_en_reg[32];
120 uchar_t trig_mode_reg[32];
128 static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) {
129 struct vm_device * dev = (struct vm_device *)priv_data;
130 struct apic_state * apic = (struct apic_state *)dev->private_data;
131 PrintDebug("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo);
137 static int write_apic_msr(uint_t msr, v3_msr_t src, void * priv_data) {
138 // struct vm_device * dev = (struct vm_device *)priv_data;
139 // struct apic_state * apic = (struct apic_state *)dev->private_data;
141 PrintDebug("WRITING APIC BASE ADDR: HI=%x LO=%x\n", src.hi, src.lo);
147 static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
148 struct vm_device * dev = (struct vm_device *)priv_data;
149 struct apic_state * apic = (struct apic_state *)dev->private_data;
150 addr_t reg_addr = guest_addr - apic->base_addr;
153 PrintError("Invalid apic readlength\n");
159 case APIC_VERSION_OFFSET:
164 case REMOTE_READ_OFFSET:
167 case SPURIOUS_INT_VEC_OFFSET:
172 case INT_CMD_LO_OFFSET:
173 case INT_CMD_HI_OFFSET:
174 case TMR_LOC_VEC_TBL_OFFSET:
175 case THERM_LOC_VEC_TBL_OFFSET:
176 case PERF_CTR_LOC_VEC_TBL_OFFSET:
177 case LINT0_VEC_TBL_OFFSET:
178 case LINT1_VEC_TBL_OFFSET:
179 case ERR_VEC_TBL_OFFSET:
180 case TMR_INIT_CNT_OFFSET:
181 case TMR_CUR_CNT_OFFSET:
182 case TMR_DIV_CFG_OFFSET:
183 case EXT_APIC_FEATURE_OFFSET:
184 case EXT_APIC_CMD_OFFSET:
187 case EXT_INT_LOC_VEC_TBL_OFFSET:
189 PrintError("Read from Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
196 static int apic_write(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
197 PrintDebug("Write to apic address space\n");
198 struct vm_device * dev = (struct vm_device *)priv_data;
199 struct apic_state * apic = (struct apic_state *)dev->private_data;
200 addr_t reg_addr = guest_addr - apic->base_addr;
203 PrintError("Invalid apic write length\n");
209 case APIC_VERSION_OFFSET:
214 case REMOTE_READ_OFFSET:
217 case SPURIOUS_INT_VEC_OFFSET:
222 case INT_CMD_LO_OFFSET:
223 case INT_CMD_HI_OFFSET:
224 case TMR_LOC_VEC_TBL_OFFSET:
225 case THERM_LOC_VEC_TBL_OFFSET:
226 case PERF_CTR_LOC_VEC_TBL_OFFSET:
227 case LINT0_VEC_TBL_OFFSET:
228 case LINT1_VEC_TBL_OFFSET:
229 case ERR_VEC_TBL_OFFSET:
230 case TMR_INIT_CNT_OFFSET:
231 case TMR_CUR_CNT_OFFSET:
232 case TMR_DIV_CFG_OFFSET:
233 case EXT_APIC_FEATURE_OFFSET:
234 case EXT_APIC_CMD_OFFSET:
237 case EXT_INT_LOC_VEC_TBL_OFFSET:
239 PrintError("Write to Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
247 static int apic_deinit(struct vm_device * dev) {
248 struct guest_info * info = dev->vm;
250 v3_unhook_msr(info, BASE_ADDR_MSR);
256 static int apic_init(struct vm_device * dev) {
257 struct guest_info * info = dev->vm;
258 struct apic_state * apic = (struct apic_state *)(dev->private_data);
260 apic->base_addr = DEFAULT_BASE_ADDR;
262 v3_hook_msr(info, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
264 v3_hook_full_mem(info, DEFAULT_BASE_ADDR, DEFAULT_BASE_ADDR + PAGE_SIZE_4KB, apic_read, apic_write, dev);
271 static struct vm_device_ops dev_ops = {
273 .deinit = apic_deinit,
280 struct vm_device * v3_create_apic() {
281 PrintDebug("Creating APIC\n");
283 struct apic_state * apic = (struct apic_state *)V3_Malloc(sizeof(struct apic_state));
285 struct vm_device * device = v3_create_device("APIC", &dev_ops, apic);