#include <palacios/vm_guest_mem.h>
#include <palacios/vmm_ctrl_regs.h>
#include <palacios/vmm_direct_paging.h>
+#include <palacios/svm.h>
-#ifndef CONFIG_DEBUG_CTRL_REGS
+#ifndef V3_CONFIG_DEBUG_CTRL_REGS
#undef PrintDebug
#define PrintDebug(fmt, args...)
#endif
*guest_cr0 = *new_cr0;
// This value must always be set to 1
- guest_cr0->et = 1;
+ guest_cr0->et = 1;
// Set the shadow register to catch non-virtualized flags
*shadow_cr0 = *guest_cr0;
// Paging is always enabled
- shadow_cr0->pg = 1;
+ shadow_cr0->pg = 1;
+
+ if (guest_cr0->pg == 0) {
+ // If paging is not enabled by the guest, then we always enable write-protect to catch memory hooks
+ shadow_cr0->wp = 1;
+ }
// Was there a paging transition
// Meaning we need to change the page tables
}
-
-// TODO: this is a disaster we need to clean this up...
int v3_handle_efer_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
- //struct efer_64 * new_efer = (struct efer_64 *)&(src.value);
- struct efer_64 * shadow_efer = (struct efer_64 *)&(core->ctrl_regs.efer);
- struct v3_msr * guest_efer = &(core->shdw_pg_state.guest_efer);
-
- PrintDebug("EFER Write\n");
- PrintDebug("EFER Write Values: HI=%x LO=%x\n", src.hi, src.lo);
- //PrintDebug("Old EFER=%p\n", (void *)*(addr_t*)(shadow_efer));
-
- // We virtualize the guests efer to hide the SVME and LMA bits
- guest_efer->value = src.value;
-
+ struct v3_msr * vm_efer = &(core->shdw_pg_state.guest_efer);
+ struct efer_64 * hw_efer = (struct efer_64 *)&(core->ctrl_regs.efer);
+ struct efer_64 old_hw_efer = *((struct efer_64 *)&core->ctrl_regs.efer);
- // Enable/Disable Syscall
- shadow_efer->sce = src.value & 0x1;
+ PrintDebug("EFER Write HI=%x LO=%x\n", src.hi, src.lo);
+
+ // Set EFER value seen by guest if it reads EFER
+ vm_efer->value = src.value;
+
+ // 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)) {
+ 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) {
+ // 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 {
+ // 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;
+ }
+
+ return 0;
+}
+
+int v3_handle_vm_cr_read(struct guest_info * core, uint_t msr, struct v3_msr * dst, void * priv_data) {
+ /* tell the guest that the BIOS disabled SVM, that way it doesn't get
+ * confused by the fact that CPUID reports SVM as available but it still
+ * cannot be used
+ */
+ dst->value = SVM_VM_CR_MSR_lock | SVM_VM_CR_MSR_svmdis;
+ PrintDebug("VM_CR Read HI=%x LO=%x\n", dst->hi, dst->lo);
+ return 0;
+}
+
+int v3_handle_vm_cr_write(struct guest_info * core, uint_t msr, struct v3_msr src, void * priv_data) {
+ PrintDebug("VM_CR Write\n");
+ PrintDebug("VM_CR Write Values: HI=%x LO=%x\n", src.hi, src.lo);
+
+ /* writes to LOCK and SVMDIS are silently ignored (according to the spec),
+ * other writes indicate the guest wants to use some feature we haven't
+ * implemented
+ */
+ if (src.value & ~(SVM_VM_CR_MSR_lock | SVM_VM_CR_MSR_svmdis)) {
+ PrintDebug("VM_CR write sets unsupported bits: HI=%x LO=%x\n", src.hi, src.lo);
+ return -1;
+ }
return 0;
}