--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+
+struct lapic_id_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t rsvd : 24;
+ uint_t apic_id : 8;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct apic_ver_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t ver : 8;
+ uint_t rsvd1 : 8;
+ uint_t max_lvts : 8;
+ uint_t rsvd2 : 7;
+ uint_t ext_reg_present : 1;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct ext_apic_ctrl_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t ver : 1;
+ uint_t seoi_enable : 1;
+ uint_t ext_id_enable : 1;
+ uint_t rsvd2 : 29;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct local_vec_tbl_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t msg_type : 3;
+ uint_t rsvd1 : 1;
+ uint_t del_status : 1;
+ uint_t rsvd2 : 1;
+ uint_t rem_irr : 1;
+ uint_t trig_mode : 1;
+ uint_t mask : 1;
+ uint_t tmr_mode : 1;
+ uint_t rsvd3 : 14;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct tmr_vec_tbl_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t rsvd : 4;
+ uint_t del_status : 1;
+ uint_t rsvd2 : 3;
+ uint_t mask : 1;
+ uint_t tmr_mode : 1;
+ uint_t rsvd3 : 14;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct div_cfg_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t div_val : 2;
+ uint_t rsvd : 1;
+ uint_t div_val2 : 1;
+ uint_t rsvd2 : 28;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct lint_vec_tbl_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t msg_type : 3;
+ uint_t rsvd1 : 1;
+ uint_t del_status : 1;
+ uint_t rsvd2 : 1;
+ uint_t rem_irr : 1;
+ uint_t trig_mode : 1;
+ uint_t mask : 1;
+ uint_t rsvd3 : 15;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct perf_ctr_loc_vec_tbl_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t msg_type : 3;
+ uint_t rsvd1 : 1;
+ uint_t del_status : 1;
+ uint_t rsvd2 : 3;
+ uint_t mask : 1;
+ uint_t rsvd3 : 15;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct therm_loc_vec_tbl_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t msg_type : 3;
+ uint_t rsvd1 : 1;
+ uint_t del_status : 1;
+ uint_t rsvd2 : 3;
+ uint_t mask : 1;
+ uint_t rsvd3 : 15;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct err_vec_tbl_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t msg_type : 3;
+ uint_t rsvd1 : 1;
+ uint_t del_status : 1;
+ uint_t rsvd2 : 3;
+ uint_t mask : 1;
+ uint_t rsvd3 : 15;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct err_status_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t rsvd1 : 2;
+ uint_t sent_acc_err : 1;
+ uint_t recv_acc_err : 1;
+ uint_t rsvd2 : 1;
+ uint_t sent_ill_err : 1;
+ uint_t recv_ill_err : 1;
+ uint_t ill_reg_addr : 1;
+ uint_t rsvd3 : 24;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct spurious_int_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t apic_soft_en : 1;
+ uint_t foc_cpu_chk : 1;
+ uint_t rsvd1 : 22;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct int_cmd_reg {
+ union {
+ uint64_t val;
+
+ struct {
+ uint32_t lo;
+ uint32_t hi;
+ } __attribute__((packed));
+
+ struct {
+ uint_t vec : 8;
+ uint_t msg_type : 3;
+ uint_t dst_mode : 1;
+ uint_t del_status : 1;
+ uint_t rsvd1 : 1;
+ uint_t lvl : 1;
+ uint_t trig_mode : 1;
+ uint_t rem_rd_status : 2;
+ uint_t dst_shorthand : 2;
+ uint64_t rsvd2 : 36;
+ uint32_t dst : 8;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct loc_dst_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t rsvd1 : 24;
+ uint_t dst_log_id : 8;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct dst_fmt_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t rsvd1 : 28;
+ uint_t model : 4;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct arb_prio_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t arb_prio_sub : 4;
+ uint_t arb_prio : 4;
+ uint_t rsvd1 : 24;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+
+struct task_prio_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t task_prio_sub : 4;
+ uint_t task_prio : 4;
+ uint_t rsvd1 : 24;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+struct proc_prio_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t proc_prio_sub : 4;
+ uint_t proc_prio : 4;
+ uint_t rsvd1 : 24;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct ext_apic_feature_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t int_en_reg_cap : 1;
+ uint_t spec_eoi_cap : 1;
+ uint_t ext_apic_id_cap: 1;
+ uint_t rsvd1 : 13;
+ uint_t ext_lvt_cnt : 8;
+ uint_t rsvd2 : 8;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct spec_eoi_reg {
+ union {
+ uint32_t val;
+ struct {
+ uint_t vec : 8;
+ uint_t rsvd1 : 24;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
#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;
}