Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


timer fixes
Jack Lange [Tue, 10 Feb 2009 03:48:06 +0000 (21:48 -0600)]
palacios/include/devices/apic_regs.h
palacios/include/palacios/vmm_intr.h
palacios/include/palacios/vmm_util.h
palacios/src/devices/8254.c
palacios/src/devices/apic.c
palacios/src/devices/os_debug.c
palacios/src/palacios/vmm_config.c
palacios/src/palacios/vmm_emulator.c

index ea1d55a..c21debe 100644 (file)
@@ -56,6 +56,7 @@ struct ext_apic_ctrl_reg {
 } __attribute__((packed));
 
 
+
 struct local_vec_tbl_reg {
   union {
     uint32_t val;
@@ -84,6 +85,8 @@ struct tmr_vec_tbl_reg {
       uint_t del_status    : 1;
       uint_t rsvd2         : 3;
       uint_t mask          : 1;
+#define APIC_TMR_ONESHOT  0
+#define APIC_TMR_PERIODIC 1
       uint_t tmr_mode      : 1;
       uint_t rsvd3         : 14;
     } __attribute__((packed));
@@ -91,12 +94,20 @@ struct tmr_vec_tbl_reg {
 } __attribute__((packed));
 
 
-struct div_cfg_reg {
+struct tmr_div_cfg_reg {
+#define APIC_TMR_DIV1    0xb // 1011
+#define APIC_TMR_DIV2    0x0 // 0000
+#define APIC_TMR_DIV4    0x1 // 0001
+#define APIC_TMR_DIV8    0x2 // 0010
+#define APIC_TMR_DIV16   0x3 // 0011
+#define APIC_TMR_DIV32   0x8 // 1000
+#define APIC_TMR_DIV64   0x9 // 1001
+#define APIC_TMR_DIV128  0xa // 1010
   union {
     uint32_t val;
     struct {
       uint_t div_val       : 2;
-      uint_t rsvd          : 1;
+      uint_t rsvd1         : 1;
       uint_t div_val2      : 1;
       uint_t rsvd2         : 28;
     } __attribute__((packed));
@@ -224,7 +235,7 @@ struct int_cmd_reg {
 } __attribute__((packed));
 
 
-struct loc_dst_reg {
+struct log_dst_reg {
   union {
     uint32_t val;
     struct {
index fd83edb..e90d304 100644 (file)
@@ -23,7 +23,6 @@
 
 #ifdef __V3VEE__
 
-#include <palacios/vmm_intr.h>
 #include <palacios/vmm_types.h>
 
 
index 320c7bf..06cbcaf 100644 (file)
@@ -66,12 +66,25 @@ void PrintTraceMemDump(uchar_t * start, int n);
 #define rdtscl(low)                                            \
      __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
 
-#if defined(__i386__)
+
+
+#define rdtscll(val)                                                   \
+  do {                                                                 \
+    uint64_t tsc;                                                      \
+    uint32_t a, d;                                                     \
+    asm volatile("rdtsc" : "=a" (a), "=d" (d));                                \
+    *(uint32_t *)&(tsc) = a;                                           \
+    *(uint32_t *)(((uchar_t *)&tsc) + 4) = d;                          \
+    val = tsc;                                                         \
+  } while (0)                                  
+
+/*
+#if __V3_32BIT__
 
 #define rdtscll(val)                           \
      __asm__ __volatile__("rdtsc" : "=A" (val))
 
-#elif defined(__x86_64__)
+#elif __V3_64BIT__
 
 #define rdtscll(val) do {                                  \
     unsigned int a,d;                                      \
@@ -80,26 +93,39 @@ void PrintTraceMemDump(uchar_t * start, int n);
   } while(0)
 
 #endif
+*/
 
 
 
 
 
+#ifdef __V3_64BIT__
 
 
+#define do_divll(n, base) ({                           \
+      uint64_t __rem = 0;                              \
+      uint64_t __num = 0;                              \
+      while (n > base) {                               \
+       __num++;                                        \
+       n -= base;                                      \
+      }                                                        \
+      __rem = n;                                       \
+      n = __num;                                       \
+      __rem;                                           \
+    })                                         
 
-
-#ifdef __V3_64BIT__
-#define do_divll do_div
+//#define do_divll do_div
 
 
-#define do_div(n,base) ({                                      \
-       uint32_t __base = (base);                               \
-       uint32_t __rem;                                         \
-       __rem = ((uint64_t)(n)) % __base;                       \
-       (n) = ((uint64_t)(n)) / __base;                         \
-       __rem;                                                  \
- })
+/*
+  #define do_div(n,base) ({                                    \
+  uint32_t __base = (base);                                    \
+  uint32_t __rem;                                              \
+  __rem = ((uint64_t)(n)) % __base;                            \
+  (n) = ((uint64_t)(n)) / __base;                              \
+  __rem;                                                       \
+  })
+*/
 
 #else
 
index 7a81595..fa51251 100644 (file)
@@ -153,15 +153,21 @@ static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint
     return output_changed;
   } else {
     ushort_t reload_val = ch->reload_value; 
+
+    // TODO: Check this....
+    // Is this correct???
+    if (reload_val == 0) {
+      reload_val = 1;
+    }
+
     oscillations -= ch->counter;
     ch->counter = 0;
     channel_cycles = 1;
 
-    
     if (ch->op_mode == SQR_WAVE) {
       reload_val -= reload_val % 2;
     }
-    
+
     channel_cycles += oscillations / reload_val;
     oscillations = oscillations % reload_val;
 
@@ -240,7 +246,7 @@ static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priva
     // Easy...
     state->pit_counter -= cpu_cycles;
   } else {
-    
+    ushort_t reload_val = state->pit_reload;
     // Take off the first part
     cpu_cycles -= state->pit_counter;
     state->pit_counter = 0;
@@ -248,10 +254,26 @@ static void pit_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priva
     
     if (cpu_cycles > state->pit_reload) {
       // how many full oscillations
+      
+      // PrintError("cpu_cycles = %p, reload = %p...\n", 
+      //        (void *)(addr_t)cpu_cycles, 
+      //        (void *)(addr_t)state->pit_reload);
+
+      // How do we check for a one shot....
+      if (state->pit_reload == 0) {
+       reload_val = 1;
+      }
+
       tmp_cycles = cpu_cycles;
 
+      
+#ifdef __V3_64BIT__
+      cpu_cycles = tmp_cycles / state->pit_reload;
+      tmp_cycles = tmp_cycles % state->pit_reload;
+#else
       cpu_cycles = do_divll(tmp_cycles, state->pit_reload);
-
+#endif
+       
       oscillations += tmp_cycles;
     }
 
index e143990..7434b7d 100644 (file)
 #include <palacios/vmm.h>
 #include <palacios/vmm_msr.h>
 
+
+typedef enum { APIC_TMR_INT, APIC_THERM_INT, APIC_PERF_INT, 
+              APIC_LINT0_INT, APIC_LINT1_INT, APIC_ERR_INT } apic_irq_type_t;
+
+#define APIC_FIXED_DELIVERY  0x0
+#define APIC_SMI_DELIVERY    0x2
+#define APIC_NMI_DELIVERY    0x4
+#define APIC_INIT_DELIVERY   0x5
+#define APIC_EXTINT_DELIVERY 0x7
+
+
 #define BASE_ADDR_MSR 0x0000001B
 #define DEFAULT_BASE_ADDR 0xfee00000
 
 #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 ISR_OFFSET0                       0x100   // 0x100 - 0x170
+#define ISR_OFFSET1                       0x110   // 0x100 - 0x170
+#define ISR_OFFSET2                       0x120   // 0x100 - 0x170
+#define ISR_OFFSET3                       0x130   // 0x100 - 0x170
+#define ISR_OFFSET4                       0x140   // 0x100 - 0x170
+#define ISR_OFFSET5                       0x150   // 0x100 - 0x170
+#define ISR_OFFSET6                       0x160   // 0x100 - 0x170
+#define ISR_OFFSET7                       0x170   // 0x100 - 0x170
+
+#define TRIG_OFFSET0                      0x180   // 0x180 - 0x1f0
+#define TRIG_OFFSET1                      0x190   // 0x180 - 0x1f0
+#define TRIG_OFFSET2                      0x1a0   // 0x180 - 0x1f0
+#define TRIG_OFFSET3                      0x1b0   // 0x180 - 0x1f0
+#define TRIG_OFFSET4                      0x1c0   // 0x180 - 0x1f0
+#define TRIG_OFFSET5                      0x1d0   // 0x180 - 0x1f0
+#define TRIG_OFFSET6                      0x1e0   // 0x180 - 0x1f0
+#define TRIG_OFFSET7                      0x1f0   // 0x180 - 0x1f0
+
+
+#define IRR_OFFSET0                       0x200   // 0x200 - 0x270
+#define IRR_OFFSET1                       0x210   // 0x200 - 0x270
+#define IRR_OFFSET2                       0x220   // 0x200 - 0x270
+#define IRR_OFFSET3                       0x230   // 0x200 - 0x270
+#define IRR_OFFSET4                       0x240   // 0x200 - 0x270
+#define IRR_OFFSET5                       0x250   // 0x200 - 0x270
+#define IRR_OFFSET6                       0x260   // 0x200 - 0x270
+#define IRR_OFFSET7                       0x270   // 0x200 - 0x270
+
+
 #define ESR_OFFSET                        0x280
 #define INT_CMD_LO_OFFSET                 0x300
 #define INT_CMD_HI_OFFSET                 0x310
 #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
+
+#define IER_OFFSET0                       0x480   // 0x480 - 0x4f0
+#define IER_OFFSET1                       0x490   // 0x480 - 0x4f0
+#define IER_OFFSET2                       0x4a0   // 0x480 - 0x4f0
+#define IER_OFFSET3                       0x4b0   // 0x480 - 0x4f0
+#define IER_OFFSET4                       0x4c0   // 0x480 - 0x4f0
+#define IER_OFFSET5                       0x4d0   // 0x480 - 0x4f0
+#define IER_OFFSET6                       0x4e0   // 0x480 - 0x4f0
+#define IER_OFFSET7                       0x4f0   // 0x480 - 0x4f0
+
+#define EXT_INT_LOC_VEC_TBL_OFFSET0       0x500   // 0x500 - 0x530
+#define EXT_INT_LOC_VEC_TBL_OFFSET1       0x510   // 0x500 - 0x530
+#define EXT_INT_LOC_VEC_TBL_OFFSET2       0x520   // 0x500 - 0x530
+#define EXT_INT_LOC_VEC_TBL_OFFSET3       0x530   // 0x500 - 0x530
+
 
 
-struct apic_base_addr_msr {
+struct apic_msr {
   union {
     uint64_t val;
     struct {
       uchar_t rsvd;
-      uint_t cpu_core      : 1;
+      uint_t bootstrap_cpu : 1;
       uint_t rsvd2         : 2;
       uint_t apic_enable   : 1;
       ullong_t base_addr   : 40;
@@ -89,15 +140,16 @@ struct apic_state {
   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 tmr_div_cfg_reg tmr_div_cfg;
+  struct lint_vec_tbl_reg lint0_vec_tbl;
+  struct lint_vec_tbl_reg lint1_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 log_dst_reg log_dst;
   struct dst_fmt_reg dst_fmt;
   struct arb_prio_reg arb_prio;
   struct task_prio_reg task_prio;
@@ -106,8 +158,8 @@ struct apic_state {
   struct spec_eoi_reg spec_eoi;
   
 
-  uint32_t tmr_cur_cnt_reg;
-  uint32_t tmr_init_cnt_reg;
+  uint32_t tmr_cur_cnt;
+  uint32_t tmr_init_cnt;
 
 
 
@@ -125,6 +177,54 @@ struct apic_state {
 };
 
 
+static void init_apic_state(struct apic_state * apic) {
+  apic->base_addr = DEFAULT_BASE_ADDR;
+  apic->base_addr_msr.value = 0x0000000000000900LL;
+  apic->base_addr_msr.value |= ((uint64_t)DEFAULT_BASE_ADDR); 
+
+  PrintDebug("Sizeof Interrupt Request Register %d, should be 32\n", 
+            (uint_t)sizeof(apic->int_req_reg));
+
+  memset(apic->int_req_reg, 0, sizeof(apic->int_req_reg));
+  memset(apic->int_svc_reg, 0, sizeof(apic->int_svc_reg));
+  memset(apic->int_en_reg, 0xff, sizeof(apic->int_en_reg));
+  memset(apic->trig_mode_reg, 0, sizeof(apic->trig_mode_reg));
+
+  apic->eoi = 0x00000000;
+  apic->rem_rd_data = 0x00000000;
+  apic->tmr_init_cnt = 0x00000000;
+  apic->tmr_cur_cnt = 0x00000000;
+
+  // TODO:
+  // We need to figure out what the APIC ID is....
+  apic->lapic_id.val = 0x00000000;
+
+  // The P6 has 6 LVT entries, so we set the value to (6-1)...
+  apic->apic_ver.val = 0x80050010;
+
+  apic->task_prio.val = 0x00000000;
+  apic->arb_prio.val = 0x00000000;
+  apic->proc_prio.val = 0x00000000;
+  apic->log_dst.val = 0x00000000;
+  apic->dst_fmt.val = 0xffffffff;
+  apic->spurious_int.val = 0x000000ff;
+  apic->err_status.val = 0x00000000;
+  apic->int_cmd.val = 0x0000000000000000LL;
+  apic->tmr_vec_tbl.val = 0x00010000;
+  apic->therm_loc_vec_tbl.val = 0x00010000;
+  apic->perf_ctr_loc_vec_tbl.val = 0x00010000;
+  apic->lint0_vec_tbl.val = 0x00010000;
+  apic->lint1_vec_tbl.val = 0x00010000;
+  apic->err_vec_tbl.val = 0x00010000;
+  apic->tmr_div_cfg.val = 0x00000000;
+  apic->ext_apic_feature.val = 0x00040007;
+  apic->ext_apic_ctrl.val = 0x00000000;
+  apic->spec_eoi.val = 0x00000000;
+}
+
+
+
+
 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;
@@ -144,10 +244,101 @@ static int write_apic_msr(uint_t msr, v3_msr_t src, void * priv_data) {
 }
 
 
+// irq_num is the bit offset into a 256 bit buffer...
+static int activate_apic_irq(struct apic_state * apic, uint32_t irq_num) {
+  int major_offset = irq_num & ~0x00000007;
+  int minor_offset = irq_num & 0x00000007;
+  uchar_t * req_location = apic->int_req_reg + major_offset;
+  uchar_t * en_location = apic->int_en_reg + major_offset;
+  uchar_t flag = 0x1 << minor_offset;
+
+  if (irq_num <= 15) {
+    PrintError("Attempting to raise an invalid interrupt: %d\n", irq_num);
+    return -1;
+  }
+
+  if (*en_location & flag) {
+    *req_location |= flag;
+  } else {
+    return 0;
+  }
+
+  return 0;
+}
+
+
+static int activate_internal_irq(struct apic_state * apic, apic_irq_type_t int_type) {
+  uint32_t vec_num = 0;
+  uint32_t del_mode = 0;
+  int masked = 0;
+
+
+  switch (int_type) {
+  case APIC_TMR_INT:
+    vec_num = apic->tmr_vec_tbl.vec;
+    del_mode = APIC_FIXED_DELIVERY;
+    masked = apic->tmr_vec_tbl.mask;
+    break;
+  case APIC_THERM_INT:
+    vec_num = apic->therm_loc_vec_tbl.vec;
+    del_mode = apic->therm_loc_vec_tbl.msg_type;
+    masked = apic->therm_loc_vec_tbl.mask;
+    break;
+  case APIC_PERF_INT:
+    vec_num = apic->perf_ctr_loc_vec_tbl.vec;
+    del_mode = apic->perf_ctr_loc_vec_tbl.msg_type;
+    masked = apic->perf_ctr_loc_vec_tbl.mask;
+    break;
+  case APIC_LINT0_INT:
+    vec_num = apic->lint0_vec_tbl.vec;
+    del_mode = apic->lint0_vec_tbl.msg_type;
+    masked = apic->lint0_vec_tbl.mask;
+    break;
+  case APIC_LINT1_INT:
+    vec_num = apic->lint1_vec_tbl.vec;
+    del_mode = apic->lint1_vec_tbl.msg_type;
+    masked = apic->lint1_vec_tbl.mask;
+    break;
+  case APIC_ERR_INT:
+    vec_num = apic->err_vec_tbl.vec;
+    del_mode = APIC_FIXED_DELIVERY;
+    masked = apic->err_vec_tbl.mask;
+    break;
+  default:
+    PrintError("Invalid APIC interrupt type\n");
+    return -1;
+  }
+
+  // interrupt is masked, don't send
+  if (masked == 1) {
+    return 0;
+  }
+
+  if (del_mode == APIC_FIXED_DELIVERY) {
+    PrintDebug("Activating internal APIC IRQ\n");
+    return activate_apic_irq(apic, vec_num);
+  } else {
+    PrintError("Unhandled Delivery Mode\n");
+    return -1;
+  }
+}
+
+
 static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_data) {
   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;
+  struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
+  uint32_t * val_ptr = (uint32_t *)dst;
+
+  PrintDebug("Read apic address space (%p)\n", 
+            (void *)guest_addr);
+
+  if (msr->apic_enable == 0) {
+    PrintError("Write to APIC address space with disabled APIC\n");
+    return -1;
+  }
+
 
   if (length != 4) {
     PrintError("Invalid apic readlength\n");
@@ -155,49 +346,219 @@ static int apic_read(addr_t guest_addr, void * dst, uint_t length, void * priv_d
   }
 
   switch (reg_addr) {
+  case EOI_OFFSET:
+    PrintError("Attempting to read from write only register\n");
+    return -1;
+    break;
+
+    // data registers
   case APIC_ID_OFFSET:
+    *val_ptr = apic->lapic_id.val;
+    break;
   case APIC_VERSION_OFFSET:
+    *val_ptr = apic->apic_ver.val;
+    break;
   case TPR_OFFSET:
+    *val_ptr = apic->task_prio.val;
+    break;
   case APR_OFFSET:
+    *val_ptr = apic->arb_prio.val;
+    break;
   case PPR_OFFSET:
-  case EOI_OFFSET:
+    *val_ptr = apic->proc_prio.val;
+    break;
   case REMOTE_READ_OFFSET:
+    *val_ptr = apic->rem_rd_data;
+    break;
   case LDR_OFFSET:
+    *val_ptr = apic->log_dst.val;
+    break;
   case DFR_OFFSET:
+    *val_ptr = apic->dst_fmt.val;
+    break;
   case SPURIOUS_INT_VEC_OFFSET:
-  case ISR_OFFSET:
-  case TMR_OFFSET:
-  case IRR_OFFSET:
+    *val_ptr = apic->spurious_int.val;
+    break;
   case ESR_OFFSET:
-  case INT_CMD_LO_OFFSET:
-  case INT_CMD_HI_OFFSET:
+    *val_ptr = apic->err_status.val;
+    break;
   case TMR_LOC_VEC_TBL_OFFSET:
-  case THERM_LOC_VEC_TBL_OFFSET:
-  case PERF_CTR_LOC_VEC_TBL_OFFSET:
+    *val_ptr = apic->tmr_vec_tbl.val;
+    break;
   case LINT0_VEC_TBL_OFFSET:
+    *val_ptr = apic->lint0_vec_tbl.val;
+    break;
   case LINT1_VEC_TBL_OFFSET:
+    *val_ptr = apic->lint1_vec_tbl.val;
+    break;
   case ERR_VEC_TBL_OFFSET:
+    *val_ptr = apic->err_vec_tbl.val;
+    break;
   case TMR_INIT_CNT_OFFSET:
-  case TMR_CUR_CNT_OFFSET:
+    *val_ptr = apic->tmr_init_cnt;
+    break;
   case TMR_DIV_CFG_OFFSET:
+    *val_ptr = apic->tmr_div_cfg.val;
+    break;
+
+  case IER_OFFSET0:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg);
+    break;
+  case IER_OFFSET1:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg + 4);
+    break;
+  case IER_OFFSET2:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg + 8);
+    break;
+  case IER_OFFSET3:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg + 12);
+    break;
+  case IER_OFFSET4:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg + 16);
+    break;
+  case IER_OFFSET5:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg + 20);
+    break;
+  case IER_OFFSET6:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg + 24);
+    break;
+  case IER_OFFSET7:
+    *val_ptr = *(uint32_t *)(apic->int_en_reg + 28);
+    break;
+
+  case ISR_OFFSET0:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg);
+    break;
+  case ISR_OFFSET1:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 4);
+    break;
+  case ISR_OFFSET2:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 8);
+    break;
+  case ISR_OFFSET3:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 12);
+    break;
+  case ISR_OFFSET4:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 16);
+    break;
+  case ISR_OFFSET5:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 20);
+    break;
+  case ISR_OFFSET6:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 24);
+    break;
+  case ISR_OFFSET7:
+    *val_ptr = *(uint32_t *)(apic->int_svc_reg + 28);
+    break;
+   
+  case TRIG_OFFSET0:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg);
+    break;
+  case TRIG_OFFSET1:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 4);
+    break;
+  case TRIG_OFFSET2:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 8);
+    break;
+  case TRIG_OFFSET3:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 12);
+    break;
+  case TRIG_OFFSET4:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 16);
+    break;
+  case TRIG_OFFSET5:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 20);
+    break;
+  case TRIG_OFFSET6:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 24);
+    break;
+  case TRIG_OFFSET7:
+    *val_ptr = *(uint32_t *)(apic->trig_mode_reg + 28);
+    break;
+
+  case IRR_OFFSET0:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg);
+    break;
+  case IRR_OFFSET1:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg + 4);
+    break;
+  case IRR_OFFSET2:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg + 8);
+    break;
+  case IRR_OFFSET3:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg + 12);
+    break;
+  case IRR_OFFSET4:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg + 16);
+    break;
+  case IRR_OFFSET5:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg + 20);
+    break;
+  case IRR_OFFSET6:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg + 24);
+    break;
+  case IRR_OFFSET7:
+    *val_ptr = *(uint32_t *)(apic->int_req_reg + 28);
+    break;
+  case TMR_CUR_CNT_OFFSET:
+    *val_ptr = apic->tmr_cur_cnt;
+    break;
+
+    // We are not going to implement these....
+  case THERM_LOC_VEC_TBL_OFFSET:
+    *val_ptr = apic->therm_loc_vec_tbl.val;
+    break;
+  case PERF_CTR_LOC_VEC_TBL_OFFSET:
+    *val_ptr = apic->perf_ctr_loc_vec_tbl.val;
+    break;
+
+
+    // handled registers
+  case INT_CMD_LO_OFFSET:    
+    *val_ptr = apic->int_cmd.lo;
+    break;
+  case INT_CMD_HI_OFFSET:
+    *val_ptr = apic->int_cmd.hi;
+    break;
+
+    // handle current timer count
+
+    // Unhandled Registers
+  case EXT_INT_LOC_VEC_TBL_OFFSET0:
+  case EXT_INT_LOC_VEC_TBL_OFFSET1:
+  case EXT_INT_LOC_VEC_TBL_OFFSET2:
+  case EXT_INT_LOC_VEC_TBL_OFFSET3:
   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;
   }
+
+  PrintDebug("Read finished (val=%x)\n", *(uint32_t *)dst);
+
   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");
+static int apic_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
   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;
+  struct apic_msr * msr = (struct apic_msr *)&(apic->base_addr_msr.value);
+  uint32_t op_val = *(uint32_t *)src;
+
+  PrintDebug("Write to apic address space (%p) (val=%x)\n", 
+            (void *)guest_addr, *(uint32_t *)src);
+
+  if (msr->apic_enable == 0) {
+    PrintError("Write to APIC address space with disabled APIC\n");
+    return -1;
+  }
+
 
   if (length != 4) {
     PrintError("Invalid apic write length\n");
@@ -205,67 +566,333 @@ static int apic_write(addr_t guest_addr, void * dst, uint_t length, void * priv_
   }
 
   switch (reg_addr) {
-  case APIC_ID_OFFSET:
+  case REMOTE_READ_OFFSET:
   case APIC_VERSION_OFFSET:
-  case TPR_OFFSET:
   case APR_OFFSET:
+  case IRR_OFFSET0:
+  case IRR_OFFSET1:
+  case IRR_OFFSET2:
+  case IRR_OFFSET3:
+  case IRR_OFFSET4:
+  case IRR_OFFSET5:
+  case IRR_OFFSET6:
+  case IRR_OFFSET7:
+  case ISR_OFFSET0:
+  case ISR_OFFSET1:
+  case ISR_OFFSET2:
+  case ISR_OFFSET3:
+  case ISR_OFFSET4:
+  case ISR_OFFSET5:
+  case ISR_OFFSET6:
+  case ISR_OFFSET7:
+  case TRIG_OFFSET0:
+  case TRIG_OFFSET1:
+  case TRIG_OFFSET2:
+  case TRIG_OFFSET3:
+  case TRIG_OFFSET4:
+  case TRIG_OFFSET5:
+  case TRIG_OFFSET6:
+  case TRIG_OFFSET7:
   case PPR_OFFSET:
-  case EOI_OFFSET:
-  case REMOTE_READ_OFFSET:
+  case EXT_APIC_FEATURE_OFFSET:
+    PrintError("Attempting to write to read only register\n");
+    return -1;
+    break;
+
+    // Data registers
+  case APIC_ID_OFFSET:
+    apic->lapic_id.val = op_val;
+    break;
+  case TPR_OFFSET:
+    apic->task_prio.val = op_val;
+    break;
   case LDR_OFFSET:
+    apic->log_dst.val = op_val;
+    break;
   case DFR_OFFSET:
+    apic->dst_fmt.val = op_val;
+    break;
   case SPURIOUS_INT_VEC_OFFSET:
-  case ISR_OFFSET:
-  case TMR_OFFSET:
-  case IRR_OFFSET:
+    apic->spurious_int.val = op_val;
+    break;
   case ESR_OFFSET:
-  case INT_CMD_LO_OFFSET:
-  case INT_CMD_HI_OFFSET:
+    apic->err_status.val = op_val;
+    break;
   case TMR_LOC_VEC_TBL_OFFSET:
+    apic->tmr_vec_tbl.val = op_val;
+    break;
   case THERM_LOC_VEC_TBL_OFFSET:
+    apic->therm_loc_vec_tbl.val = op_val;
+    break;
   case PERF_CTR_LOC_VEC_TBL_OFFSET:
+    apic->perf_ctr_loc_vec_tbl.val = op_val;
+    break;
   case LINT0_VEC_TBL_OFFSET:
+    apic->lint0_vec_tbl.val = op_val;
+    break;
   case LINT1_VEC_TBL_OFFSET:
+    apic->lint1_vec_tbl.val = op_val;
+    break;
   case ERR_VEC_TBL_OFFSET:
+    apic->err_vec_tbl.val = op_val;
+    break;
   case TMR_INIT_CNT_OFFSET:
+    apic->tmr_init_cnt = op_val;
+    apic->tmr_cur_cnt = op_val;
+    break;
   case TMR_CUR_CNT_OFFSET:
+    apic->tmr_cur_cnt = op_val;
+    break;
   case TMR_DIV_CFG_OFFSET:
-  case EXT_APIC_FEATURE_OFFSET:
+    apic->tmr_div_cfg.val = op_val;
+    break;
+
+
+    // Enable mask (256 bits)
+  case IER_OFFSET0:
+    *(uint32_t *)(apic->int_en_reg) = op_val;
+    break;
+  case IER_OFFSET1:
+    *(uint32_t *)(apic->int_en_reg + 4) = op_val;
+    break;
+  case IER_OFFSET2:
+    *(uint32_t *)(apic->int_en_reg + 8) = op_val;
+    break;
+  case IER_OFFSET3:
+    *(uint32_t *)(apic->int_en_reg + 12) = op_val;
+    break;
+  case IER_OFFSET4:
+    *(uint32_t *)(apic->int_en_reg + 16) = op_val;
+    break;
+  case IER_OFFSET5:
+    *(uint32_t *)(apic->int_en_reg + 20) = op_val;
+    break;
+  case IER_OFFSET6:
+    *(uint32_t *)(apic->int_en_reg + 24) = op_val;
+    break;
+  case IER_OFFSET7:
+    *(uint32_t *)(apic->int_en_reg + 28) = op_val;
+    break;
+   
+
+    // Action Registers
+  case INT_CMD_LO_OFFSET:
+  case INT_CMD_HI_OFFSET:
+  case EOI_OFFSET:
+    // do eoi
+
+    // Unhandled Registers
+  case EXT_INT_LOC_VEC_TBL_OFFSET0:
+  case EXT_INT_LOC_VEC_TBL_OFFSET1:
+  case EXT_INT_LOC_VEC_TBL_OFFSET2:
+  case EXT_INT_LOC_VEC_TBL_OFFSET3:
   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;
   }
 
+  PrintDebug("Write finished\n");
+
   return length;
 }
 
 
-static int apic_deinit(struct vm_device * dev) {
-  struct guest_info * info = dev->vm;
 
-  v3_unhook_msr(info, BASE_ADDR_MSR);
+/* Interrupt Controller Functions */
+
+static int apic_intr_pending(void * private_data) {
+  struct vm_device * dev = (struct vm_device *)private_data;
+  struct apic_state * apic = (struct apic_state *)dev->private_data;
+  int i = 0;
+
+  // just scan the request register looking for any set bit
+  // we should probably just do this with uint64 casts 
+  for (i = 0; i < 32; i++) {
+    if (apic->int_req_reg[i] & 0xff) {
+      return 1;
+    }
+  }
 
   return 0;
 }
 
+static int apic_get_intr_number(void * private_data) {
+  struct vm_device * dev = (struct vm_device *)private_data;
+  struct apic_state * apic = (struct apic_state *)dev->private_data;
+  int i = 0, j = 0;
+
+
+  // We iterate backwards to find the highest priority
+  for (i = 31; i >= 0; i--) {
+    uchar_t req_major = apic->int_req_reg[i];
+    
+    if (req_major & 0xff) {
+      for (j = 7; j >= 0; j--) {
+       if ((req_major >> j) == 0x1) {
+         return (i * 32) + j;
+       }
+      }
+    }
+  }
+
+  return -1;
+}
+
+static int apic_raise_intr(void * private_data, int irq) {
+  struct vm_device * dev = (struct vm_device *)private_data;
+  struct apic_state * apic = (struct apic_state *)dev->private_data;
+
+  return activate_apic_irq(apic, irq);
+}
+
+static int apic_lower_intr(void * private_data, int irq) {
+  struct vm_device * dev = (struct vm_device *)private_data;
+  struct apic_state * apic = (struct apic_state *)dev->private_data;
+  int major_offset = irq & ~0x00000007;
+  int minor_offset = irq & 0x00000007;
+  uchar_t * req_location = apic->int_req_reg + major_offset;
+  uchar_t flag = 0x01 << minor_offset;
+
+  *req_location &= ~flag;
+
+  return 0;
+}
+
+static int apic_begin_irq(void * private_data, int irq) {
+  struct vm_device * dev = (struct vm_device *)private_data;
+  struct apic_state * apic = (struct apic_state *)dev->private_data;
+  int major_offset = irq & ~0x00000007;
+  int minor_offset = irq & 0x00000007;
+  uchar_t * req_location = apic->int_req_reg + major_offset;
+  uchar_t * svc_location = apic->int_svc_reg + major_offset;
+  uchar_t flag = 0x01 << minor_offset;
+
+  *svc_location |= flag;
+  *req_location &= ~flag;
+
+  return 0;
+}
+
+
+
+/* Timer Functions */
+static void apic_update_time(ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) {
+  struct vm_device * dev = (struct vm_device *)priv_data;
+  struct apic_state * apic = (struct apic_state *)dev->private_data;
+  // The 32 bit GCC runtime is a pile of shit
+#ifdef __V3_64BIT__
+  uint64_t tmr_ticks = 0;
+#else 
+  uint32_t tmr_ticks = 0;
+#endif
+
+  uchar_t tmr_div = *(uchar_t *)&(apic->tmr_div_cfg.val);
+  uint_t shift_num = 0;
+
+
+  // Check whether this is true:
+  //   -> If the Init count is zero then the timer is disabled
+  //      and doesn't just blitz interrupts to the CPU
+  if ((apic->tmr_init_cnt == 0) || 
+      ( (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_ONESHOT) &&
+       (apic->tmr_cur_cnt == 0))) {
+    //PrintDebug("APIC timer not yet initialized\n");
+    return;
+  }
+
+
+  switch (tmr_div) {
+  case APIC_TMR_DIV1:
+    shift_num = 0;
+    break;
+  case APIC_TMR_DIV2:
+    shift_num = 1;
+    break;
+  case APIC_TMR_DIV4:
+    shift_num = 2;
+    break;
+  case APIC_TMR_DIV8:
+    shift_num = 3;
+    break;
+  case APIC_TMR_DIV16:
+    shift_num = 4;
+    break;
+  case APIC_TMR_DIV32:
+    shift_num = 5;
+    break;
+  case APIC_TMR_DIV64:
+    shift_num = 6;
+    break;
+ case APIC_TMR_DIV128:
+    shift_num = 7;
+    break;
+  default:
+    PrintError("Invalid Timer Divider configuration\n");
+    return;
+  }
+
+  tmr_ticks = cpu_cycles >> shift_num;
+  PrintDebug("Timer Ticks: %p\n", (void *)tmr_ticks);
+
+  if (tmr_ticks <= apic->tmr_cur_cnt) {
+    apic->tmr_cur_cnt -= tmr_ticks;
+  } else {
+    tmr_ticks -= apic->tmr_cur_cnt;
+    apic->tmr_cur_cnt = 0;
+
+    // raise irq
+    if (activate_internal_irq(apic, APIC_TMR_INT) == -1) {
+      PrintError("Could not raise Timer interrupt\n");
+    }
+  }
+
+  if (apic->tmr_vec_tbl.tmr_mode == APIC_TMR_PERIODIC) {
+    tmr_ticks = tmr_ticks % apic->tmr_init_cnt;
+    apic->tmr_init_cnt = apic->tmr_init_cnt - tmr_ticks;
+  }
+}
+
+
+
+static struct intr_ctrl_ops intr_ops = {
+  .intr_pending = apic_intr_pending,
+  .get_intr_number = apic_get_intr_number,
+  .raise_intr = apic_raise_intr,
+  .begin_irq = apic_begin_irq,
+  .lower_intr = apic_lower_intr, 
+};
+
+
+static struct vm_timer_ops timer_ops = {
+  .update_time = apic_update_time,
+};
+
 
 static int apic_init(struct vm_device * dev) {
   struct guest_info * info = dev->vm;
   struct apic_state * apic = (struct apic_state *)(dev->private_data);
 
-  apic->base_addr = DEFAULT_BASE_ADDR;
+  v3_set_intr_controller(dev->vm, &intr_ops, dev);
+  v3_add_timer(dev->vm, &timer_ops, dev);
+
+  init_apic_state(apic);
 
   v3_hook_msr(info, BASE_ADDR_MSR, read_apic_msr, write_apic_msr, dev);
 
-  v3_hook_full_mem(info, DEFAULT_BASE_ADDR, DEFAULT_BASE_ADDR + PAGE_SIZE_4KB, apic_read, apic_write, dev);
+  v3_hook_full_mem(info, apic->base_addr, apic->base_addr + PAGE_SIZE_4KB, apic_read, apic_write, dev);
 
   return 0;
 }
 
+static int apic_deinit(struct vm_device * dev) {
+  struct guest_info * info = dev->vm;
+
+  v3_unhook_msr(info, BASE_ADDR_MSR);
+
+  return 0;
+}
 
 
 static struct vm_device_ops dev_ops = {
index 2ceac6f..6bca537 100644 (file)
 #include <devices/os_debug.h>
 #include <palacios/vmm.h>
 
+#define BUF_SIZE 1024
 
-#define DEBUG_PORT1 0xcc
+#define DEBUG_PORT1 0xc0c0
 
 
+struct debug_state {
+  char debug_buf[BUF_SIZE];
+  uint_t debug_offset;
+
+};
 
 
 static int handle_gen_write(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
-  PrintError("OS_DEBUG Write\n");
-
-  switch (length) {
-  case 1:
-    PrintDebug("OS_DEBUG ->0x%.2x\n", *(uchar_t*)src);
-    break;
-  case 2:
-    PrintDebug("OS_DEBUG ->0x%.4x\n", *(ushort_t*)src);
-    break;
-  case 4:
-    PrintDebug("OS_DEBUG ->0x%.8x\n", *(uint_t*)src);
-    break;
-  default:
-    PrintError("OS_DEBUG -> Invalid length in handle_gen_write\n");
-    return -1;
-    break;
+  struct debug_state * state = (struct debug_state *)dev->private_data;
+
+  state->debug_buf[state->debug_offset++] = *(char*)src;
+
+  if ((*(char*)src == 0xa) ||  (state->debug_offset == (BUF_SIZE - 1))) {
+    PrintDebug("VM_CONSOLE>%s", state->debug_buf);
+    memset(state->debug_buf, 0, BUF_SIZE);
+    state->debug_offset = 0;
   }
 
   return length;
@@ -51,9 +49,12 @@ static int handle_gen_write(ushort_t port, void * src, uint_t length, struct vm_
 
 
 static int debug_init(struct vm_device * dev) {
+  struct debug_state * state = (struct debug_state *)dev->private_data;
 
   v3_dev_hook_io(dev, DEBUG_PORT1,  NULL, &handle_gen_write);
 
+  state->debug_offset = 0;
+  memset(state->debug_buf, 0, BUF_SIZE);
   
   return 0;
 }
@@ -78,9 +79,12 @@ static struct vm_device_ops dev_ops = {
 
 
 struct vm_device * v3_create_os_debug() {
+  struct debug_state * state = NULL;
+
+  state = (struct debug_state *)V3_Malloc(sizeof(struct debug_state));
 
   PrintDebug("Creating OS Debug Device\n");
-  struct vm_device * device = v3_create_device("OS Debug", &dev_ops, NULL);
+  struct vm_device * device = v3_create_device("OS Debug", &dev_ops, state);
 
 
 
index 7a20d99..4067160 100644 (file)
@@ -59,7 +59,7 @@ static struct vm_device *  configure_generic(struct guest_info * info, struct v3
 
 static int passthrough_mem_write(addr_t guest_addr, void * src, uint_t length, void * priv_data) {
 
-
+  return length;
   //  memcpy((void*)guest_addr, src, length);
   PrintDebug("Write of %d bytes to %p\n", length, (void *)guest_addr);
   PrintDebug("Write Value = %p\n", (void *)*(addr_t *)src);
index 82dc56c..859d6b2 100644 (file)
@@ -44,7 +44,7 @@ static int emulate_string_write_op(struct guest_info * info, struct x86_instr *
   addr_t src_addr = 0;
 
   if (dec_instr->op_type == V3_OP_MOVS) {
-    PrintError("MOVS emulation\n");
+    //   PrintError("MOVS emulation\n");
 
     if (dec_instr->dst_operand.operand != write_gva) {
       PrintError("Inconsistency between Pagefault and Instruction Decode XED_ADDR=%p, PF_ADDR=%p\n",