mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-08 22:15:28 +00:00
target-i386: Add NPT support
This implements NPT suport for SVM by hooking into x86_cpu_handle_mmu_fault where it reads the stage-1 page table. Whether we need to perform this 2nd stage translation, and how, is decided during vmrun and stored in hflags2, along with nested_cr3 and nested_pg_mode. As get_hphys performs a direct cpu_vmexit in case of NPT faults, we need retaddr in that function. To avoid changing the signature of cpu_handle_mmu_fault, this passes the value from tlb_fill to get_hphys via the CPU state. This was tested successfully via the Jailhouse hypervisor. Backports commit fe441054bb3f0c75ff23335790342c0408e11c3a from qemu
This commit is contained in:
parent
f5698ff9a5
commit
f5f1d9f86b
|
@ -192,6 +192,7 @@
|
|||
#define HF2_VINTR_SHIFT 3 /* value of V_INTR_MASKING bit */
|
||||
#define HF2_SMM_INSIDE_NMI_SHIFT 4 /* CPU serving SMI nested inside NMI */
|
||||
#define HF2_MPX_PR_SHIFT 5 /* BNDCFGx.BNDPRESERVE */
|
||||
#define HF2_NPT_SHIFT 6 /* Nested Paging enabled */
|
||||
|
||||
#define HF2_GIF_MASK (1 << HF2_GIF_SHIFT)
|
||||
#define HF2_HIF_MASK (1 << HF2_HIF_SHIFT)
|
||||
|
@ -199,6 +200,7 @@
|
|||
#define HF2_VINTR_MASK (1 << HF2_VINTR_SHIFT)
|
||||
#define HF2_SMM_INSIDE_NMI_MASK (1 << HF2_SMM_INSIDE_NMI_SHIFT)
|
||||
#define HF2_MPX_PR_MASK (1 << HF2_MPX_PR_SHIFT)
|
||||
#define HF2_NPT_MASK (1 << HF2_NPT_SHIFT)
|
||||
|
||||
#define CR0_PE_SHIFT 0
|
||||
#define CR0_MP_SHIFT 1
|
||||
|
@ -1208,12 +1210,16 @@ typedef struct CPUX86State {
|
|||
uint16_t intercept_dr_read;
|
||||
uint16_t intercept_dr_write;
|
||||
uint32_t intercept_exceptions;
|
||||
uint64_t nested_cr3;
|
||||
uint32_t nested_pg_mode;
|
||||
uint8_t v_tpr;
|
||||
|
||||
/* KVM states, automatically cleared on reset */
|
||||
uint8_t nmi_injected;
|
||||
uint8_t nmi_pending;
|
||||
|
||||
uintptr_t retaddr;
|
||||
|
||||
/* Fields up to this point are cleared by a CPU reset */
|
||||
struct {} end_reset_fields;
|
||||
|
||||
|
|
|
@ -204,13 +204,13 @@ void helper_boundl(CPUX86State *env, target_ulong a0, int v)
|
|||
void tlb_fill(CPUState *cs, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs->uc, cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
int ret;
|
||||
|
||||
env->retaddr = retaddr;
|
||||
ret = x86_cpu_handle_mmu_fault(cs, addr, size, access_type, mmu_idx);
|
||||
if (ret) {
|
||||
X86CPU *cpu = X86_CPU(cs->uc, cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
|
||||
raise_exception_err_ra(env, cs->exception_index, env->error_code, retaddr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -130,6 +130,20 @@
|
|||
|
||||
#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */
|
||||
|
||||
#define SVM_NPT_ENABLED (1 << 0)
|
||||
|
||||
#define SVM_NPT_PAE (1 << 0)
|
||||
#define SVM_NPT_LMA (1 << 1)
|
||||
#define SVM_NPT_NXE (1 << 2)
|
||||
|
||||
#define SVM_NPTEXIT_P (1ULL << 0)
|
||||
#define SVM_NPTEXIT_RW (1ULL << 1)
|
||||
#define SVM_NPTEXIT_US (1ULL << 2)
|
||||
#define SVM_NPTEXIT_RSVD (1ULL << 3)
|
||||
#define SVM_NPTEXIT_ID (1ULL << 4)
|
||||
#define SVM_NPTEXIT_GPA (1ULL << 32)
|
||||
#define SVM_NPTEXIT_GPT (1ULL << 33)
|
||||
|
||||
QEMU_PACK( struct vmcb_control_area {
|
||||
uint16_t intercept_cr_read;
|
||||
uint16_t intercept_cr_write;
|
||||
|
|
|
@ -125,6 +125,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
|
|||
{
|
||||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||
target_ulong addr;
|
||||
uint64_t nested_ctl;
|
||||
uint32_t event_inj;
|
||||
uint32_t int_ctl;
|
||||
|
||||
|
@ -207,6 +208,26 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
|
|||
control.intercept_exceptions
|
||||
));
|
||||
|
||||
nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb,
|
||||
control.nested_ctl));
|
||||
if (nested_ctl & SVM_NPT_ENABLED) {
|
||||
env->nested_cr3 = x86_ldq_phys(cs,
|
||||
env->vm_vmcb + offsetof(struct vmcb,
|
||||
control.nested_cr3));
|
||||
env->hflags2 |= HF2_NPT_MASK;
|
||||
|
||||
env->nested_pg_mode = 0;
|
||||
if (env->cr[4] & CR4_PAE_MASK) {
|
||||
env->nested_pg_mode |= SVM_NPT_PAE;
|
||||
}
|
||||
if (env->hflags & HF_LMA_MASK) {
|
||||
env->nested_pg_mode |= SVM_NPT_LMA;
|
||||
}
|
||||
if (env->efer & MSR_EFER_NXE) {
|
||||
env->nested_pg_mode |= SVM_NPT_NXE;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable intercepts */
|
||||
env->hflags |= HF_SVMI_MASK;
|
||||
|
||||
|
@ -605,6 +626,7 @@ void do_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
|
|||
x86_stl_phys(cs,
|
||||
env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
|
||||
}
|
||||
env->hflags2 &= ~HF2_NPT_MASK;
|
||||
|
||||
/* Save the VM state in the vmcb */
|
||||
svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es),
|
||||
|
|
Loading…
Reference in a new issue