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.


RTM code: abort on extern irqs and fixed bug in abort handling
[palacios.git] / palacios / src / extensions / ext_trans_mem.c
index a05c89f..d3c27c2 100644 (file)
@@ -859,6 +859,9 @@ tm_set_abort_status (struct guest_info * core,
         case TM_ABORT_BKPT:
             core->vm_regs.rax |= (1 << cause);
             break;
+        case TM_ABORT_UNSPECIFIED:
+            // just return 0 in EAX
+            break;
         default:
             TM_ERR(core, ABORT, "invalid abort cause\n");
             break;
@@ -1790,13 +1793,13 @@ tm_handle_xend (struct guest_info * core,
 {
     rdtscll(tm->exit_time);
 
-    // Error checking! make sure that we have gotten here in a legitimate manner
+    /* XEND should raise a GPF when RTM mode is not on */
     if (tm->TM_MODE != TM_ON) {
         TM_ERR(core, UD, "Encountered XEND while not in a transactional region\n");
         v3_free_staging_page(tm);
         v3_clr_vtlb(core);
         v3_clear_tm_lists(tm);
-        v3_raise_exception(core, UD_EXCEPTION);
+        v3_raise_exception(core, GPF_EXCEPTION);
         return 0;
     }
 
@@ -1889,12 +1892,32 @@ tm_handle_xbegin (struct guest_info * core,
                   uchar_t * instr)
 {
     sint32_t rel_addr = 0;
+    uint8_t out_of_bounds = 0;
+    uint8_t in_compat_no_long = 0;
 
     if (tm->TM_MODE == TM_ON) {
-        TM_ERR(core,UD,"We got here while already in a transactional region!");
+        /* TODO: this is actually an indication of nesting, we'll fix this later */
+        TM_ERR(core,UD,"We don't support nested transactions yet!\n");
         v3_raise_exception(core, UD_EXCEPTION);
+        return -1;
     }
 
+    // Save the fail_call address (first 2 bytes = opcode, last 4 = fail call addr)
+    rel_addr = *(sint32_t*)(instr+2);
+
+    /* raise a GPF if we're trying to set a fail call outside of code segment */
+    in_compat_no_long = (core->cpu_mode == LONG_32_COMPAT) || ((struct efer_64*)&(core->ctrl_regs.efer))->lma == 0;
+    out_of_bounds     = (core->rip + rel_addr > core->segments.cs.base + core->segments.cs.limit || 
+                         core->rip + rel_addr < core->segments.cs.base);
+
+    if (in_compat_no_long && out_of_bounds) {
+        v3_raise_exception(core, GPF_EXCEPTION);
+        return 0;
+    }
+
+    /* TODO: also raise GPF if we're in long mode and failcall isn't canonical */
+
+    /* TODO: put this elsewhere */
     rdtscll(tm->entry_time);
     tm->entry_exits = core->num_exits;
 
@@ -1903,8 +1926,7 @@ tm_handle_xbegin (struct guest_info * core,
 
     TM_DBG(core,UD,"Set the system in TM Mode, save fallback address");
 
-    // Save the fail_call address (first 2 bytes = opcode, last 4 = fail call addr)
-    rel_addr = *(sint32_t*)(instr+2);
+
     tm->fail_call = core->rip + XBEGIN_INSTR_LEN + rel_addr;
 
     TM_DBG(core,UD,"we set fail_call to %llx, rip is %llx, rel_addr is %x", (uint64_t)tm->fail_call,(uint64_t)core->rip,rel_addr);
@@ -1928,13 +1950,21 @@ static int
 tm_handle_xtest (struct guest_info * core,
                  struct v3_trans_mem * tm)
 {
+    struct rflags * rf = (struct rflags*)&(core->ctrl_regs.rflags);
+
     // if we are in tm mode, set zf to 0, otherwise 1
     if (tm->TM_MODE == TM_ON) {
-        core->ctrl_regs.rflags &= ~(1ULL << 6);
+        rf->zf = 0;
     } else {
-        core->ctrl_regs.rflags |= (1ULL << 6);
+        rf->zf = 1;
     }
 
+    rf->cf = 0;
+    rf->of = 0;
+    rf->sf = 0;
+    rf->pf = 0;
+    rf->af = 0;
+
     core->rip += XTEST_INSTR_LEN;
 
     return 0;
@@ -2188,28 +2218,26 @@ v3_tm_check_intr_state (struct guest_info * info,
 
     if (!tm) {
         TM_ERR(info,INTR,"TM extension state not found\n");
-        v3_stgi();
         return;
     }
 
-    /* TODO: work this in */
-    if (0 && (tm->TM_MODE == TM_ON) && 
-             (tm->TM_ABORT != 1)) {
+    if ((tm->TM_MODE == TM_ON) && 
+        (tm->TM_ABORT != 1)) {
 
         if (guest_ctrl->guest_ctrl.V_IRQ ||
             guest_ctrl->EVENTINJ.valid) {
 
-            rdtscll(tm->exit_time);
-            TM_DBG(info,INTR,"%lld exits happened, time delta is %lld",(info->num_exits - tm->entry_exits),(tm->entry_time - tm->exit_time));
-
             // We do indeed have pending interrupts
             v3_stgi();
-            TM_DBG(info,INTR,"we have a pending interrupt!\n");
+
+            TM_DBG(info,INTR,"we have a pending interrupt\n");
 
             v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0);
+
             // Copy new RIP state into arch dependent structure
             guest_state->rip = info->rip;
-            TM_DBG(info,INTR,"currently guest state rip is %llx\n",(uint64_t)guest_state->rip);
+
+            //TM_DBG(info,INTR,"currently guest state rip is %llx\n",(uint64_t)guest_state->rip);
             v3_clgi();
         }