}
+/*
+ The CR8 and APIC TPR interaction are kind of crazy.
+
+ CR8 mandates that the priority class is in bits 3:0
+
+ The interaction of CR8 and an actual APIC is somewhat implementation dependent, but
+ a basic current APIC has the priority class at 7:4 and the *subclass* at 3:0
+
+ The APIC TPR (both fields) can be written as the APIC register
+ A write to CR8 sets the priority class field, and should zero the subclass
+ A read from CR8 gets just the priority class field
+
+ In the apic_tpr storage location, we have:
+
+ zeros [class] [subclass]
+
+ Because of this, an APIC implementation should use apic_tpr to store its TPR
+ In fact, it *should* do this, otherwise its TPR may get out of sync with the architected TPR
+
+ On a CR8 read, we return just
+
+ zeros 0000 [class]
+
+ On a CR8 write, we set the register to
+
+ zeros [class] 0000
+
+*/
+
+int v3_handle_cr8_write(struct guest_info * info) {
+ int ret;
+ uchar_t instr[15];
+ struct x86_instr dec_instr;
+
+ if (info->mem_mode == PHYSICAL_MEM) {
+ ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ } else {
+ ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ }
+
+ if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
+ PrintError("Could not decode instruction\n");
+ return -1;
+ }
+
+ if (dec_instr.op_type == V3_OP_MOV2CR) {
+ PrintDebug("MOV2CR8 (cpu_mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
+
+ if ((info->cpu_mode == LONG) ||
+ (info->cpu_mode == LONG_32_COMPAT)) {
+ uint64_t *val = (uint64_t *)(dec_instr.src_operand.operand);
+
+ info->ctrl_regs.apic_tpr = (*val & 0xf) << 4;
+
+ V3_Print("Write of CR8 sets apic_tpr to 0x%llx\n",info->ctrl_regs.apic_tpr);
+
+ } else {
+ // probably should raise exception here
+ }
+ } else {
+ PrintError("Unhandled opcode in handle_cr8_write\n");
+ return -1;
+ }
+
+ info->rip += dec_instr.instr_length;
+
+ return 0;
+}
+
+
+
+int v3_handle_cr8_read(struct guest_info * info) {
+ uchar_t instr[15];
+ int ret;
+ struct x86_instr dec_instr;
+
+ if (info->mem_mode == PHYSICAL_MEM) {
+ ret = v3_read_gpa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ } else {
+ ret = v3_read_gva_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
+ }
+
+ if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
+ PrintError("Could not decode instruction\n");
+ return -1;
+ }
+
+ if (dec_instr.op_type == V3_OP_MOVCR2) {
+ PrintDebug("MOVCR82 (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
+
+ if ((info->cpu_mode == LONG) ||
+ (info->cpu_mode == LONG_32_COMPAT)) {
+ uint64_t *dst_reg = (uint64_t *)(dec_instr.dst_operand.operand);
+
+ *dst_reg = (info->ctrl_regs.apic_tpr >> 4) & 0xf;
+
+ V3_Print("Read of CR8 (apic_tpr) returns 0x%llx\n",*dst_reg);
+
+ } else {
+ // probably should raise exception
+ }
+
+ } else {
+ PrintError("Unhandled opcode in handle_cr8_read\n");
+ return -1;
+ }
+
+ info->rip += dec_instr.instr_length;
+
+ return 0;
+}
+
+
int v3_handle_efer_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
PrintDebug("EFER Read HI=%x LO=%x\n", core->shdw_pg_state.guest_efer.hi, core->shdw_pg_state.guest_efer.lo);
// Set EFER value seen by hardware while the guest is running
*(uint64_t *)hw_efer = src.value;
- // Catch unsupported features
- if ((old_hw_efer.lme == 1) && (hw_efer->lme == 0)) {
+ // We have gotten here either because we are using
+ // shadow paging, or we are using nested paging on SVM
+ // In the latter case, we don't need to do anything
+ // like the following
+ if (core->shdw_pg_mode == SHADOW_PAGING) {
+ // Catch unsupported features
+ if ((old_hw_efer.lme == 1) && (hw_efer->lme == 0)) {
PrintError("Disabling long mode once it has been enabled is not supported\n");
return -1;
- }
-
- // Set LME and LMA bits seen by hardware
- if (old_hw_efer.lme == 0) {
+ }
+
+ // Set LME and LMA bits seen by hardware
+ if (old_hw_efer.lme == 0) {
// Long mode was not previously enabled, so the lme bit cannot
// be set yet. It will be set later when the guest sets CR0.PG
// to enable paging.
hw_efer->lme = 0;
- } else {
+ } else {
// Long mode was previously enabled. Ensure LMA bit is set.
// VMX does not automatically set LMA, and this should not affect SVM.
hw_efer->lma = 1;
+ }
}
-
-
+
+
PrintDebug("RIP=%p\n", (void *)core->rip);
PrintDebug("New EFER value HW(hi=%p), VM(hi=%p)\n", (void *)*(uint64_t *)hw_efer, (void *)vm_efer->value);