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;
{
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;
}
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;
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);
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;
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();
}