#include <devices/apic.h>
+#include <devices/apic_regs.h>
#include <palacios/vmm.h>
#include <palacios/vmm_msr.h>
#define BASE_ADDR_MSR 0x0000001B
#define DEFAULT_BASE_ADDR 0xfee00000
-
-struct apic_base_addr_reg {
- uchar_t rsvd;
- uint_t bsc : 1;
- uint_t rsvd2 : 2;
- uint_t apic_enable : 1;
- ullong_t base_addr : 40;
- uint_t rsvd3 : 12;
+#define APIC_ID_OFFSET 0x020
+#define APIC_VERSION_OFFSET 0x030
+#define TPR_OFFSET 0x080
+#define APR_OFFSET 0x090
+#define PPR_OFFSET 0x0a0
+#define EOI_OFFSET 0x0b0
+#define REMOTE_READ_OFFSET 0x0c0
+#define LDR_OFFSET 0x0d0
+#define DFR_OFFSET 0x0e0
+#define SPURIOUS_INT_VEC_OFFSET 0x0f0
+#define ISR_OFFSET 0x100 // 0x100 - 0x170
+#define TMR_OFFSET 0x180 // 0x180 - 0x1f0
+#define IRR_OFFSET 0x200 // 0x200 - 0x270
+#define ESR_OFFSET 0x280
+#define INT_CMD_LO_OFFSET 0x300
+#define INT_CMD_HI_OFFSET 0x310
+#define TMR_LOC_VEC_TBL_OFFSET 0x320
+#define THERM_LOC_VEC_TBL_OFFSET 0x330
+#define PERF_CTR_LOC_VEC_TBL_OFFSET 0x340
+#define LINT0_VEC_TBL_OFFSET 0x350
+#define LINT1_VEC_TBL_OFFSET 0x360
+#define ERR_VEC_TBL_OFFSET 0x370
+#define TMR_INIT_CNT_OFFSET 0x380
+#define TMR_CUR_CNT_OFFSET 0x390
+#define TMR_DIV_CFG_OFFSET 0x3e0
+#define EXT_APIC_FEATURE_OFFSET 0x400
+#define EXT_APIC_CMD_OFFSET 0x410
+#define SEOI_OFFSET 0x420
+#define IER_OFFSET 0x480 // 0x480 - 0x4f0
+#define EXT_INT_LOC_VEC_TBL_OFFSET 0x500 // 0x500 - 0x530
+
+
+struct apic_base_addr_msr {
+ union {
+ uint64_t val;
+ struct {
+ uchar_t rsvd;
+ uint_t cpu_core : 1;
+ uint_t rsvd2 : 2;
+ uint_t apic_enable : 1;
+ ullong_t base_addr : 40;
+ uint_t rsvd3 : 12;
+ } __attribute__((packed));
+ } __attribute__((packed));
} __attribute__((packed));
+
+
+
struct apic_state {
addr_t base_addr;
- v3_msr_t base_addr_reg;
+ /* MSRs */
+ v3_msr_t base_addr_msr;
+
+
+ /* memory map registers */
+
+ struct lapic_id_reg lapic_id;
+ struct apic_ver_reg apic_ver;
+ struct ext_apic_ctrl_reg ext_apic_ctrl;
+ struct local_vec_tbl_reg local_vec_tbl;
+ struct tmr_vec_tbl_reg tmr_vec_tbl;
+ struct div_cfg_reg div_cfg;
+ struct lint_vec_tbl_reg lint_vec_tbl;
+ struct perf_ctr_loc_vec_tbl_reg perf_ctr_loc_vec_tbl;
+ struct therm_loc_vec_tbl_reg therm_loc_vec_tbl;
+ struct err_vec_tbl_reg err_vec_tbl;
+ struct err_status_reg err_status;
+ struct spurious_int_reg spurious_int;
+ struct int_cmd_reg int_cmd;
+ struct loc_dst_reg loc_dst;
+ struct dst_fmt_reg dst_fmt;
+ struct arb_prio_reg arb_prio;
+ struct task_prio_reg task_prio;
+ struct proc_prio_reg proc_prio;
+ struct ext_apic_feature_reg ext_apic_feature;
+ struct spec_eoi_reg spec_eoi;
+
+
+ uint32_t tmr_cur_cnt_reg;
+ uint32_t tmr_init_cnt_reg;
+
+
+
+ uint32_t rem_rd_data;
+
+ uchar_t int_req_reg[32];
+ uchar_t int_svc_reg[32];
+ uchar_t int_en_reg[32];
+ uchar_t trig_mode_reg[32];
+ uint32_t eoi;
+
};
static int read_apic_msr(uint_t msr, v3_msr_t * dst, void * priv_data) {
struct vm_device * dev = (struct vm_device *)priv_data;
struct apic_state * apic = (struct apic_state *)dev->private_data;
- PrintDebug("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_reg.hi, apic->base_addr_reg.lo);
+ PrintDebug("READING APIC BASE ADDR: HI=%x LO=%x\n", apic->base_addr_msr.hi, apic->base_addr_msr.lo);
return -1;
}
static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
- PrintDebug("Read from apic address space\n");
- return -1;
+ struct vm_device * dev = (struct vm_device *)priv_data;
+ struct apic_state * apic = (struct apic_state *)dev->private_data;
+ addr_t reg_addr = guest_addr - apic->base_addr;
+
+ if (length != 4) {
+ PrintError("Invalid apic readlength\n");
+ return -1;
+ }
+
+ switch (reg_addr) {
+ case APIC_ID_OFFSET:
+ case APIC_VERSION_OFFSET:
+ case TPR_OFFSET:
+ case APR_OFFSET:
+ case PPR_OFFSET:
+ case EOI_OFFSET:
+ case REMOTE_READ_OFFSET:
+ case LDR_OFFSET:
+ case DFR_OFFSET:
+ case SPURIOUS_INT_VEC_OFFSET:
+ case ISR_OFFSET:
+ case TMR_OFFSET:
+ case IRR_OFFSET:
+ case ESR_OFFSET:
+ case INT_CMD_LO_OFFSET:
+ case INT_CMD_HI_OFFSET:
+ case TMR_LOC_VEC_TBL_OFFSET:
+ case THERM_LOC_VEC_TBL_OFFSET:
+ case PERF_CTR_LOC_VEC_TBL_OFFSET:
+ case LINT0_VEC_TBL_OFFSET:
+ case LINT1_VEC_TBL_OFFSET:
+ case ERR_VEC_TBL_OFFSET:
+ case TMR_INIT_CNT_OFFSET:
+ case TMR_CUR_CNT_OFFSET:
+ case TMR_DIV_CFG_OFFSET:
+ case EXT_APIC_FEATURE_OFFSET:
+ case EXT_APIC_CMD_OFFSET:
+ case SEOI_OFFSET:
+ case IER_OFFSET:
+ case EXT_INT_LOC_VEC_TBL_OFFSET:
+ default:
+ PrintError("Read from Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
+ return -1;
+ }
+ return length;
}
static int apic_write(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
PrintDebug("Write to apic address space\n");
- return -1;
+ struct vm_device * dev = (struct vm_device *)priv_data;
+ struct apic_state * apic = (struct apic_state *)dev->private_data;
+ addr_t reg_addr = guest_addr - apic->base_addr;
+
+ if (length != 4) {
+ PrintError("Invalid apic write length\n");
+ return -1;
+ }
+
+ switch (reg_addr) {
+ case APIC_ID_OFFSET:
+ case APIC_VERSION_OFFSET:
+ case TPR_OFFSET:
+ case APR_OFFSET:
+ case PPR_OFFSET:
+ case EOI_OFFSET:
+ case REMOTE_READ_OFFSET:
+ case LDR_OFFSET:
+ case DFR_OFFSET:
+ case SPURIOUS_INT_VEC_OFFSET:
+ case ISR_OFFSET:
+ case TMR_OFFSET:
+ case IRR_OFFSET:
+ case ESR_OFFSET:
+ case INT_CMD_LO_OFFSET:
+ case INT_CMD_HI_OFFSET:
+ case TMR_LOC_VEC_TBL_OFFSET:
+ case THERM_LOC_VEC_TBL_OFFSET:
+ case PERF_CTR_LOC_VEC_TBL_OFFSET:
+ case LINT0_VEC_TBL_OFFSET:
+ case LINT1_VEC_TBL_OFFSET:
+ case ERR_VEC_TBL_OFFSET:
+ case TMR_INIT_CNT_OFFSET:
+ case TMR_CUR_CNT_OFFSET:
+ case TMR_DIV_CFG_OFFSET:
+ case EXT_APIC_FEATURE_OFFSET:
+ case EXT_APIC_CMD_OFFSET:
+ case SEOI_OFFSET:
+ case IER_OFFSET:
+ case EXT_INT_LOC_VEC_TBL_OFFSET:
+ default:
+ PrintError("Write to Unhandled APIC Register: %x\n", (uint32_t)reg_addr);
+ return -1;
+ }
+
+ return length;
}