diff options
-rw-r--r-- | hw/ppce500_mpc8544ds.c | 2 | ||||
-rw-r--r-- | target-ppc/cpu.h | 2 | ||||
-rw-r--r-- | target-ppc/kvm.c | 85 |
3 files changed, 89 insertions, 0 deletions
diff --git a/hw/ppce500_mpc8544ds.c b/hw/ppce500_mpc8544ds.c index b86a008c9c..61151d886c 100644 --- a/hw/ppce500_mpc8544ds.c +++ b/hw/ppce500_mpc8544ds.c @@ -189,6 +189,8 @@ static void mmubooke_create_initial_mapping(CPUState *env, tlb->mas2 = va & TARGET_PAGE_MASK; tlb->mas7_3 = pa & TARGET_PAGE_MASK; tlb->mas7_3 |= MAS3_UR | MAS3_UW | MAS3_UX | MAS3_SR | MAS3_SW | MAS3_SX; + + env->tlb_dirty = true; } static void mpc8544ds_cpu_reset_sec(void *opaque) diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index b8d42e0b2c..3e7f797e0b 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -934,6 +934,8 @@ struct CPUPPCState { ppc_tlb_t tlb; /* TLB is optional. Allocate them only if needed */ /* 403 dedicated access protection registers */ target_ulong pb[4]; + bool tlb_dirty; /* Set to non-zero when modifying TLB */ + bool kvm_sw_tlb; /* non-zero if KVM SW TLB API is active */ #endif /* Other registers */ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index f65b6e1f4a..35a6f1086e 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -112,6 +112,52 @@ static int kvm_arch_sync_sregs(CPUState *cenv) return kvm_vcpu_ioctl(cenv, KVM_SET_SREGS, &sregs); } +/* Set up a shared TLB array with KVM */ +static int kvm_booke206_tlb_init(CPUState *env) +{ + struct kvm_book3e_206_tlb_params params = {}; + struct kvm_config_tlb cfg = {}; + struct kvm_enable_cap encap = {}; + unsigned int entries = 0; + int ret, i; + + if (!kvm_enabled() || + !kvm_check_extension(env->kvm_state, KVM_CAP_SW_TLB)) { + return 0; + } + + assert(ARRAY_SIZE(params.tlb_sizes) == BOOKE206_MAX_TLBN); + + for (i = 0; i < BOOKE206_MAX_TLBN; i++) { + params.tlb_sizes[i] = booke206_tlb_size(env, i); + params.tlb_ways[i] = booke206_tlb_ways(env, i); + entries += params.tlb_sizes[i]; + } + + assert(entries == env->nb_tlb); + assert(sizeof(struct kvm_book3e_206_tlb_entry) == sizeof(ppcmas_tlb_t)); + + env->tlb_dirty = true; + + cfg.array = (uintptr_t)env->tlb.tlbm; + cfg.array_len = sizeof(ppcmas_tlb_t) * entries; + cfg.params = (uintptr_t)¶ms; + cfg.mmu_type = KVM_MMU_FSL_BOOKE_NOHV; + + encap.cap = KVM_CAP_SW_TLB; + encap.args[0] = (uintptr_t)&cfg; + + ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &encap); + if (ret < 0) { + fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n", + __func__, strerror(-ret)); + return ret; + } + + env->kvm_sw_tlb = true; + return 0; +} + int kvm_arch_init_vcpu(CPUState *cenv) { int ret; @@ -123,6 +169,15 @@ int kvm_arch_init_vcpu(CPUState *cenv) idle_timer = qemu_new_timer_ns(vm_clock, kvm_kick_env, cenv); + /* Some targets support access to KVM's guest TLB. */ + switch (cenv->mmu_model) { + case POWERPC_MMU_BOOKE206: + ret = kvm_booke206_tlb_init(cenv); + break; + default: + break; + } + return ret; } @@ -130,6 +185,31 @@ void kvm_arch_reset_vcpu(CPUState *env) { } +static void kvm_sw_tlb_put(CPUState *env) +{ + struct kvm_dirty_tlb dirty_tlb; + unsigned char *bitmap; + int ret; + + if (!env->kvm_sw_tlb) { + return; + } + + bitmap = g_malloc((env->nb_tlb + 7) / 8); + memset(bitmap, 0xFF, (env->nb_tlb + 7) / 8); + + dirty_tlb.bitmap = (uintptr_t)bitmap; + dirty_tlb.num_dirty = env->nb_tlb; + + ret = kvm_vcpu_ioctl(env, KVM_DIRTY_TLB, &dirty_tlb); + if (ret) { + fprintf(stderr, "%s: KVM_DIRTY_TLB: %s\n", + __func__, strerror(-ret)); + } + + g_free(bitmap); +} + int kvm_arch_put_registers(CPUState *env, int level) { struct kvm_regs regs; @@ -167,6 +247,11 @@ int kvm_arch_put_registers(CPUState *env, int level) if (ret < 0) return ret; + if (env->tlb_dirty) { + kvm_sw_tlb_put(env); + env->tlb_dirty = false; + } + return ret; } |