X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=blobdiff_plain;f=palacios%2Fsrc%2Fextensions%2Fext_trans_mem.c;h=7a4c838c25cd32d882b662b9e944a765a3893947;hb=4454a172129d12e97793c9c353339b85d3335af4;hp=9042e5522714af811cf056fc217342118aaec642;hpb=e42b257e5364f8ddba2c86668631013859cb2e46;p=palacios.git diff --git a/palacios/src/extensions/ext_trans_mem.c b/palacios/src/extensions/ext_trans_mem.c index 9042e55..7a4c838 100644 --- a/palacios/src/extensions/ext_trans_mem.c +++ b/palacios/src/extensions/ext_trans_mem.c @@ -44,11 +44,6 @@ #define PrintDebug(fmt, args...) #endif -/* TODO LIST: - * - save/restore register state on XBEGIN/XABORT - * - put status codes in RAX - * - Implement proper exceptions for failed XBEGINS etc. - */ /* this includes a mov to rax */ static const char * vmmcall_bytes = "\x48\xc7\xc0\x37\x13\x00\x00\x0f\x01\xd9"; @@ -241,7 +236,7 @@ v3_store_next_instr (struct guest_info * core, struct v3_trans_mem * tm) /* this will attempt to abort all the remote cores */ if (tm_handle_decode_fail(core) == -1) { TM_ERR(core,Error,"Could not handle failed decode\n"); - return -1; + return ERR_STORE_FAIL; } /* we need to trigger a local abort */ @@ -378,7 +373,7 @@ tm_handle_fault_ifetch (struct guest_info * core, return ERR_TRANS_FAULT_FAIL; } else if (sto == ERR_STORE_MUST_ABORT) { TM_DBG(core,EXIT,"aborting for some reason\n"); - v3_handle_trans_abort(core); + v3_handle_trans_abort(core, TM_ABORT_UNSPECIFIED, 0); return TRANS_FAULT_OK; } @@ -512,7 +507,7 @@ tm_handle_fault_extern_ifetch (struct guest_info * core, } else if (sto == ERR_STORE_MUST_ABORT) { TM_ERR(core,IFETCH,"decode failed, going out of single stepping\n"); - v3_handle_trans_abort(core); + v3_handle_trans_abort(core, TM_ABORT_UNSPECIFIED, 0); return TRANS_FAULT_OK; } @@ -663,7 +658,7 @@ tm_handle_hcall_dec_abort (struct guest_info * core, TM_DBG(core,EXIT,"we are in ABORT, call the abort handler\n"); tm->TM_ABORT = 0; - v3_handle_trans_abort(core); + v3_handle_trans_abort(core, TM_ABORT_UNSPECIFIED, 0); TM_DBG(core,EXIT,"RIP after abort: %p\n", ((void*)(core->rip))); @@ -708,7 +703,7 @@ tm_check_list_conflict (struct guest_info * core, } else if (conflict == CHECK_IS_CONFLICT) { TM_DBG(core,EXIT,"we have a conflict, aborting\n"); - v3_handle_trans_abort(core); + v3_handle_trans_abort(core, TM_ABORT_CONFLICT, 0); return CHECK_MUST_ABORT; } @@ -837,8 +832,43 @@ v3_tm_inc_tnum (struct v3_trans_mem * tm) } +static void +tm_set_abort_status (struct guest_info * core, + tm_abrt_cause_t cause, + uint8_t xabort_reason) +{ + core->vm_regs.rax = 0; + + switch (cause) { + case TM_ABORT_XABORT: + // we put the xabort immediate in eax 31:24 + // cause is zero + core->vm_regs.rax |= (xabort_reason << 24); + break; + case TM_ABORT_CONFLICT: + // if this was a conflict from another core, it may work + // if we try again + core->vm_regs.rax |= (1 << ABORT_CONFLICT) | (1 << ABORT_RETRY); + break; + case TM_ABORT_INTERNAL: + 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; + } +} + + +// xabort_reason is only used for XABORT instruction int -v3_handle_trans_abort (struct guest_info * core) +v3_handle_trans_abort (struct guest_info * core, + tm_abrt_cause_t cause, + uint8_t xabort_reason) { struct v3_trans_mem * tm = (struct v3_trans_mem *)v3_get_ext_core_state(core, "trans_mem"); @@ -870,7 +900,8 @@ v3_handle_trans_abort (struct guest_info * core) v3_tm_inc_tnum(tm); } - + tm_set_abort_status(core, cause, xabort_reason); + // time to garbage collect if (tm_hash_gc(tm) == -1) { TM_ERR(core,GC,"could not gc!\n"); @@ -1108,28 +1139,20 @@ static int tm_collect_context (struct v3_trans_mem * tm, struct hashtable_iter * ctxt_iter, struct hash_chain * curr, - uint64_t * begin_time, - uint64_t * end_time, addr_t gva) { uint64_t i; for (i = 0; i < tm->ginfo->vm_info->num_cores; i++) { - void * buf[3]; + struct v3_ctxt_tuple tup; struct v3_tm_access_type * type; addr_t key; - rdtscll(*end_time); - if ((*end_time - *begin_time) > 100000000) { - TM_ERR(tm->ginfo,GC,"time threshhold exceeded, exiting!!!\n"); - return -1; - } - - buf[0] = (void *)gva; - buf[1] = (void *)i; - buf[2] = (void *)curr->curr_lt[i]; + tup.gva = (void *)gva; + tup.core_id = (void *)i; + tup.core_lt = (void *)curr->curr_lt[i]; - key = v3_hash_buffer((uchar_t*)buf, sizeof(void*)*3); + key = v3_hash_buffer((uchar_t*)&tup, sizeof(struct v3_ctxt_tuple)); type = (struct v3_tm_access_type *)v3_htable_search(tm->access_type, key); @@ -1153,9 +1176,7 @@ static int tm_collect_all_contexts (struct v3_trans_mem * tm, struct hashtable_iter * ctxt_iter, uint64_t tmoff, - uint64_t * lt_copy, - uint64_t * begin_time, - uint64_t * end_time) + uint64_t * lt_copy) { struct hash_chain * tmp; struct hash_chain * curr; @@ -1183,7 +1204,7 @@ tm_collect_all_contexts (struct v3_trans_mem * tm, TM_DBG(tm->ginfo,GC,"garbage collecting entries for address %llx\n", (uint64_t)gva); /* found one, delete corresponding entries in access_type */ - if (tm_collect_context(tm, ctxt_iter, curr, begin_time, end_time, gva) == -1) { + if (tm_collect_context(tm, ctxt_iter, curr, gva) == -1) { TM_ERR(tm->ginfo,GC,"ERROR collecting context\n"); return -1; } @@ -1210,7 +1231,7 @@ tm_hash_gc (struct v3_trans_mem * tm) { addr_t irqstate, irqstate2; int rc = 0; - uint64_t begin_time, end_time, tmoff; + uint64_t tmoff; uint64_t * lt_copy; struct v3_tm_state * tms = NULL; struct hashtable_iter * ctxt_iter = NULL; @@ -1235,8 +1256,6 @@ tm_hash_gc (struct v3_trans_mem * tm) memset(lt_copy, 0, sizeof(uint64_t)*(tm->ginfo->vm_info->num_cores)); - rdtscll(begin_time); - /* lt_copy holds the last transaction number for each core */ irqstate = v3_lock_irqsave(tm_global_state->lock); memcpy(lt_copy, tm_global_state->last_trans, sizeof(uint64_t)*(tm->ginfo->vm_info->num_cores)); @@ -1257,7 +1276,7 @@ tm_hash_gc (struct v3_trans_mem * tm) /* we check each address stored in the hash */ while (ctxt_iter->entry) { /* NOTE: this call advances the hash iterator */ - if (tm_collect_all_contexts(tm, ctxt_iter, tmoff, lt_copy, &begin_time, &end_time) == -1) { + if (tm_collect_all_contexts(tm, ctxt_iter, tmoff, lt_copy) == -1) { rc = -1; goto out1; } @@ -1270,12 +1289,10 @@ out: v3_unlock_irqrestore(tm->access_type_lock, irqstate); v3_unlock_irqrestore(tm->addr_ctxt_lock, irqstate2); - rdtscll(end_time); - if (rc == -1) { - TM_ERR(tm->ginfo,GC,"garbage collection failed, time spent: %d cycles\n", (int)(end_time - begin_time)); + TM_ERR(tm->ginfo,GC,"garbage collection failed\n"); } else { - TM_DBG(tm->ginfo,GC,"ended garbage collection succesfuly, time spent: %d cycles\n", (int)(end_time - begin_time)); + TM_DBG(tm->ginfo,GC,"ended garbage collection succesfuly\n"); } TM_DBG(tm->ginfo,GC,"\t %d entries in addr_ctxt (post)\n", (int)v3_htable_count(tm->addr_ctxt)); @@ -1755,16 +1772,14 @@ static int tm_handle_xend (struct guest_info * core, struct v3_trans_mem * tm) { - 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; + } /* Our transaction finished! */ @@ -1816,10 +1831,13 @@ tm_handle_xend (struct guest_info * core, */ static int tm_handle_xabort (struct guest_info * core, - struct v3_trans_mem * tm) + struct v3_trans_mem * tm, + uchar_t * instr) { - /* TODO: this probably needs to move somewhere else */ - rdtscll(tm->exit_time); + uint8_t reason; + + // we must reflect the immediate back into EAX 31:24 + reason = *(uint8_t*)(instr+2); // Error checking! make sure that we have gotten here in a legitimate manner if (tm->TM_MODE != TM_ON) { @@ -1834,7 +1852,7 @@ tm_handle_xabort (struct guest_info * core, } // Handle the exit - v3_handle_trans_abort(core); + v3_handle_trans_abort(core, TM_ABORT_XABORT, reason); return 0; } @@ -1850,22 +1868,38 @@ 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; } - rdtscll(tm->entry_time); - tm->entry_exits = core->num_exits; + /* TODO: also raise GPF if we're in long mode and failcall isn't canonical */ + /* set the tm_mode for this core */ v3_set_tm(tm); 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); @@ -1889,13 +1923,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; @@ -1934,7 +1976,7 @@ tm_handle_ud (struct guest_info * core) TM_DBG(core, UD, "Encountered Haswell-specific XABORT %x %x %d at %llx\n", byte1, byte2, byte3, (uint64_t)core->rip); - if (tm_handle_xabort(core, tm) == -1) { + if (tm_handle_xabort(core, tm, instr) == -1) { TM_ERR(core, UD, "Problem handling XABORT\n"); return -1; } @@ -1993,7 +2035,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to DE exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP1: @@ -2002,7 +2044,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to DB exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP3: @@ -2011,7 +2053,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to BP exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP4: @@ -2020,7 +2062,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to OF exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP5: @@ -2029,7 +2071,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to BR exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP7: @@ -2038,7 +2080,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to NM exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP10: @@ -2047,7 +2089,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to TS exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP11: @@ -2056,7 +2098,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to NP exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP12: @@ -2065,7 +2107,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to SS exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP13: @@ -2074,7 +2116,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to GPF exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP16: @@ -2083,7 +2125,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to MF exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP17: @@ -2092,7 +2134,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to AC exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; case SVM_EXIT_EXCP19: @@ -2101,7 +2143,7 @@ v3_tm_handle_exception (struct guest_info * info, } else { TM_DBG(info,EXCP,"aborting due to XF exception\n"); - v3_handle_trans_abort(info); + v3_handle_trans_abort(info, TM_ABORT_UNSPECIFIED, 0); } break; @@ -2149,28 +2191,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"); - v3_handle_trans_abort(info); + 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(); }