qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2] x86: Implement SMEP and SMAP


From: Aurelien Jarno
Subject: Re: [Qemu-devel] [PATCH v2] x86: Implement SMEP and SMAP
Date: Thu, 27 Sep 2012 21:56:24 +0200
User-agent: Mutt/1.5.21 (2010-09-15)

On Wed, Sep 26, 2012 at 01:18:43PM -0700, H. Peter Anvin wrote:
> From: "H. Peter Anvin" <address@hidden>
> 
> This patch implements Supervisor Mode Execution Prevention (SMEP) and
> Supervisor Mode Access Prevention (SMAP) for x86.  The purpose of the
> patch, obviously, is to help kernel developers debug the support for
> those features.
> 
> A fair bit of the code relates to the handling of CPUID features.  The
> CPUID code probably would get greatly simplified if all the feature
> bit words were unified into a single vector object, but in the
> interest of producing a minimal patch for SMEP/SMAP, and because I had
> very limited time for this project, I followed the existing style.
> 
> [ v2: don't change the definition of the qemu64 CPU shorthand, since
>   that breaks loading old snapshots.  Per Anthony Liguori this can be
>   fixed once the CPU feature set is snapshot.
> 
>   Change the coding style slightly to conform to checkpatch.pl. ]
> 
> Signed-off-by: H. Peter Anvin <address@hidden>
> ---
>  target-i386/cc_helper.c |   10 +++
>  target-i386/cpu.c       |   34 ++++++++---
>  target-i386/cpu.h       |   33 ++++++++--
>  target-i386/helper.c    |  150 
> ++++++++++++++++++++++++++++++++++++++---------
>  target-i386/helper.h    |    2 +
>  target-i386/translate.c |   27 +++++++--
>  6 files changed, 207 insertions(+), 49 deletions(-)
> 
> diff --git a/target-i386/cc_helper.c b/target-i386/cc_helper.c
> index 07892f9..9422003 100644
> --- a/target-i386/cc_helper.c
> +++ b/target-i386/cc_helper.c
> @@ -353,6 +353,16 @@ void helper_sti(CPUX86State *env)
>      env->eflags |= IF_MASK;
>  }
>  
> +void helper_clac(CPUX86State *env)
> +{
> +    env->eflags &= ~AC_MASK;
> +}
> +
> +void helper_stac(CPUX86State *env)
> +{
> +    env->eflags |= AC_MASK;
> +}
> +
>  #if 0
>  /* vm86plus instructions */
>  void helper_cli_vm(CPUX86State *env)
> diff --git a/target-i386/cpu.c b/target-i386/cpu.c
> index fd4fe28..f186439 100644
> --- a/target-i386/cpu.c
> +++ b/target-i386/cpu.c
> @@ -100,6 +100,13 @@ static const char *svm_feature_name[] = {
>      NULL, NULL, NULL, NULL,
>  };
>  
> +static const char *cpuid_7_0_ebx_feature_name[] = {
> +    NULL, NULL, NULL, NULL, NULL, NULL, NULL, "smep",
> +    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
> +    NULL, NULL, NULL, NULL, "smap", NULL, NULL, NULL,
> +    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
> +};
> +
>  /* collects per-function cpuid data
>   */
>  typedef struct model_features_t {
> @@ -215,14 +222,17 @@ static void add_flagname_to_bitmaps(const char 
> *flagname, uint32_t *features,
>                                      uint32_t *ext2_features,
>                                      uint32_t *ext3_features,
>                                      uint32_t *kvm_features,
> -                                    uint32_t *svm_features)
> +                                    uint32_t *svm_features,
> +                                    uint32_t *cpuid_7_0_ebx_features)
>  {
>      if (!lookup_feature(features, flagname, NULL, feature_name) &&
>          !lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
>          !lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
>          !lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
>          !lookup_feature(kvm_features, flagname, NULL, kvm_feature_name) &&
> -        !lookup_feature(svm_features, flagname, NULL, svm_feature_name))
> +        !lookup_feature(svm_features, flagname, NULL, svm_feature_name) &&
> +        !lookup_feature(cpuid_7_0_ebx_features, flagname, NULL,
> +                        cpuid_7_0_ebx_feature_name))
>              fprintf(stderr, "CPU feature %s not found\n", flagname);
>  }
>  
> @@ -284,6 +294,7 @@ typedef struct x86_def_t {
>  #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \
>            CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A)
>  #define TCG_SVM_FEATURES 0
> +#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP)
>  
>  /* maintains list of cpu model definitions
>   */
> @@ -1091,10 +1102,12 @@ static int cpu_x86_find_by_name(x86_def_t 
> *x86_cpu_def, const char *cpu_model)
>      uint32_t plus_features = 0, plus_ext_features = 0;
>      uint32_t plus_ext2_features = 0, plus_ext3_features = 0;
>      uint32_t plus_kvm_features = 0, plus_svm_features = 0;
> +    uint32_t plus_7_0_ebx_features = 0;
>      /* Features to be removed */
>      uint32_t minus_features = 0, minus_ext_features = 0;
>      uint32_t minus_ext2_features = 0, minus_ext3_features = 0;
>      uint32_t minus_kvm_features = 0, minus_svm_features = 0;
> +    uint32_t minus_7_0_ebx_features = 0;
>      uint32_t numvalue;
>  
>      for (def = x86_defs; def; def = def->next)
> @@ -1121,8 +1134,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, 
> const char *cpu_model)
>  #endif
>  
>      add_flagname_to_bitmaps("hypervisor", &plus_features,
> -        &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
> -        &plus_kvm_features, &plus_svm_features);
> +            &plus_ext_features, &plus_ext2_features, &plus_ext3_features,
> +            &plus_kvm_features, &plus_svm_features,  &plus_7_0_ebx_features);
>  
>      featurestr = strtok(NULL, ",");
>  
> @@ -1132,12 +1145,12 @@ static int cpu_x86_find_by_name(x86_def_t 
> *x86_cpu_def, const char *cpu_model)
>              add_flagname_to_bitmaps(featurestr + 1, &plus_features,
>                              &plus_ext_features, &plus_ext2_features,
>                              &plus_ext3_features, &plus_kvm_features,
> -                            &plus_svm_features);
> +                            &plus_svm_features, &plus_7_0_ebx_features);
>          } else if (featurestr[0] == '-') {
>              add_flagname_to_bitmaps(featurestr + 1, &minus_features,
>                              &minus_ext_features, &minus_ext2_features,
>                              &minus_ext3_features, &minus_kvm_features,
> -                            &minus_svm_features);
> +                            &minus_svm_features, &minus_7_0_ebx_features);
>          } else if ((val = strchr(featurestr, '='))) {
>              *val = 0; val++;
>              if (!strcmp(featurestr, "family")) {
> @@ -1243,16 +1256,21 @@ static int cpu_x86_find_by_name(x86_def_t 
> *x86_cpu_def, const char *cpu_model)
>      x86_cpu_def->ext3_features |= plus_ext3_features;
>      x86_cpu_def->kvm_features |= plus_kvm_features;
>      x86_cpu_def->svm_features |= plus_svm_features;
> +    x86_cpu_def->cpuid_7_0_ebx_features |= plus_7_0_ebx_features;
>      x86_cpu_def->features &= ~minus_features;
>      x86_cpu_def->ext_features &= ~minus_ext_features;
>      x86_cpu_def->ext2_features &= ~minus_ext2_features;
>      x86_cpu_def->ext3_features &= ~minus_ext3_features;
>      x86_cpu_def->kvm_features &= ~minus_kvm_features;
>      x86_cpu_def->svm_features &= ~minus_svm_features;
> +    x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_7_0_ebx_features;
>      if (check_cpuid) {
>          if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
>              goto error;
>      }
> +    if (x86_cpu_def->cpuid_7_0_ebx_features && x86_cpu_def->level < 7) {
> +        x86_cpu_def->level = 7;
> +    }
>      g_free(s);
>      return 0;
>  
> @@ -1368,7 +1386,7 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
>      env->cpuid_kvm_features = def->kvm_features;
>      env->cpuid_svm_features = def->svm_features;
>      env->cpuid_ext4_features = def->ext4_features;
> -    env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
> +    env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features;
>      env->cpuid_xlevel2 = def->xlevel2;
>      object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
>                              "tsc-frequency", &error);
> @@ -1545,7 +1563,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, 
> uint32_t count,
>          /* Structured Extended Feature Flags Enumeration Leaf */
>          if (count == 0) {
>              *eax = 0; /* Maximum ECX value for sub-leaves */
> -            *ebx = env->cpuid_7_0_ebx; /* Feature flags */
> +            *ebx = env->cpuid_7_0_ebx_features; /* Feature flags */
>              *ecx = 0; /* Reserved */
>              *edx = 0; /* Reserved */
>          } else {
> diff --git a/target-i386/cpu.h b/target-i386/cpu.h
> index d7ea2f9..3cb9c08 100644
> --- a/target-i386/cpu.h
> +++ b/target-i386/cpu.h
> @@ -123,8 +123,8 @@
>  
>  /* hidden flags - used internally by qemu to represent additional cpu
>     states. Only the CPL, INHIBIT_IRQ, SMM and SVMI are not
> -   redundant. We avoid using the IOPL_MASK, TF_MASK and VM_MASK bit
> -   position to ease oring with eflags. */
> +   redundant. We avoid using the IOPL_MASK, TF_MASK, VM_MASK and AC_MASK
> +   bit positions to ease oring with eflags. */
>  /* current cpl */
>  #define HF_CPL_SHIFT         0
>  /* true if soft mmu is being used */
> @@ -147,10 +147,12 @@
>  #define HF_CS64_SHIFT       15 /* only used on x86_64: 64 bit code segment  
> */
>  #define HF_RF_SHIFT         16 /* must be same as eflags */
>  #define HF_VM_SHIFT         17 /* must be same as eflags */
> +#define HF_AC_SHIFT         18 /* must be same as eflags */
>  #define HF_SMM_SHIFT        19 /* CPU in SMM mode */
>  #define HF_SVME_SHIFT       20 /* SVME enabled (copy of EFER.SVME) */
>  #define HF_SVMI_SHIFT       21 /* SVM intercepts are active */
>  #define HF_OSFXSR_SHIFT     22 /* CR4.OSFXSR */
> +#define HF_SMAP_SHIFT       23 /* CR4.SMAP */
>  
>  #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
>  #define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
> @@ -168,10 +170,12 @@
>  #define HF_CS64_MASK         (1 << HF_CS64_SHIFT)
>  #define HF_RF_MASK           (1 << HF_RF_SHIFT)
>  #define HF_VM_MASK           (1 << HF_VM_SHIFT)
> +#define HF_AC_MASK           (1 << HF_AC_SHIFT)
>  #define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
>  #define HF_SVME_MASK         (1 << HF_SVME_SHIFT)
>  #define HF_SVMI_MASK         (1 << HF_SVMI_SHIFT)
>  #define HF_OSFXSR_MASK       (1 << HF_OSFXSR_SHIFT)
> +#define HF_SMAP_MASK         (1 << HF_SMAP_SHIFT)
>  
>  /* hflags2 */
>  
> @@ -210,6 +214,13 @@
>  #define CR4_OSFXSR_SHIFT 9
>  #define CR4_OSFXSR_MASK (1 << CR4_OSFXSR_SHIFT)
>  #define CR4_OSXMMEXCPT_MASK  (1 << 10)
> +#define CR4_VMXE_MASK   (1 << 13)
> +#define CR4_SMXE_MASK   (1 << 14)
> +#define CR4_FSGSBASE_MASK (1 << 16)
> +#define CR4_PCIDE_MASK  (1 << 17)
> +#define CR4_OSXSAVE_MASK (1 << 18)
> +#define CR4_SMEP_MASK   (1 << 20)
> +#define CR4_SMAP_MASK   (1 << 21)
>  
>  #define DR6_BD          (1 << 13)
>  #define DR6_BS          (1 << 14)
> @@ -462,6 +473,9 @@
>  #define CPUID_SVM_PAUSEFILTER  (1 << 10)
>  #define CPUID_SVM_PFTHRESHOLD  (1 << 12)
>  
> +#define CPUID_7_0_EBX_SMEP     (1 << 7)
> +#define CPUID_7_0_EBX_SMAP     (1 << 20)
> +
>  #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
>  #define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
>  #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
> @@ -637,7 +651,7 @@ typedef struct {
>  #define CPU_NB_REGS CPU_NB_REGS32
>  #endif
>  
> -#define NB_MMU_MODES 2
> +#define NB_MMU_MODES 3
>  
>  typedef enum TPRAccess {
>      TPR_ACCESS_READ,
> @@ -767,7 +781,7 @@ typedef struct CPUX86State {
>      uint32_t cpuid_xlevel2;
>      uint32_t cpuid_ext4_features;
>      /* Flags from CPUID[EAX=7,ECX=0].EBX */
> -    uint32_t cpuid_7_0_ebx;
> +    uint32_t cpuid_7_0_ebx_features;
>  
>      /* MTRRs */
>      uint64_t mtrr_fixed[11];
> @@ -1006,10 +1020,15 @@ static inline CPUX86State *cpu_init(const char 
> *cpu_model)
>  /* MMU modes definitions */
>  #define MMU_MODE0_SUFFIX _kernel
>  #define MMU_MODE1_SUFFIX _user
> -#define MMU_USER_IDX 1
> +#define MMU_MODE2_SUFFIX _ksmap /* Kernel with SMAP override */
> +#define MMU_KERNEL_IDX  0
> +#define MMU_USER_IDX    1
> +#define MMU_KSMAP_IDX   2
>  static inline int cpu_mmu_index (CPUX86State *env)
>  {
> -    return (env->hflags & HF_CPL_MASK) == 3 ? 1 : 0;
> +    return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX :
> +        ((env->hflags & HF_SMAP_MASK) && (env->eflags & AC_MASK))
> +        ? MMU_KSMAP_IDX : MMU_KERNEL_IDX;
>  }
>  
>  #undef EAX
> @@ -1095,7 +1114,7 @@ static inline void cpu_get_tb_cpu_state(CPUX86State 
> *env, target_ulong *pc,
>      *cs_base = env->segs[R_CS].base;
>      *pc = *cs_base + env->eip;
>      *flags = env->hflags |
> -        (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK));
> +        (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK | AC_MASK));
>  }
>  
>  void do_cpu_init(X86CPU *cpu);
> diff --git a/target-i386/helper.c b/target-i386/helper.c
> index 8a5da3d..c635667 100644
> --- a/target-i386/helper.c
> +++ b/target-i386/helper.c
> @@ -443,17 +443,27 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t 
> new_cr4)
>  #if defined(DEBUG_MMU)
>      printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
>  #endif
> -    if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
> -        (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
> +    if ((new_cr4 ^ env->cr[4]) &
> +        (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK |
> +         CR4_SMEP_MASK | CR4_SMAP_MASK)) {
>          tlb_flush(env, 1);
>      }
>      /* SSE handling */
> -    if (!(env->cpuid_features & CPUID_SSE))
> +    if (!(env->cpuid_features & CPUID_SSE)) {
>          new_cr4 &= ~CR4_OSFXSR_MASK;
> -    if (new_cr4 & CR4_OSFXSR_MASK)
> +    }
> +    env->hflags &= ~HF_OSFXSR_MASK;
> +    if (new_cr4 & CR4_OSFXSR_MASK) {
>          env->hflags |= HF_OSFXSR_MASK;
> -    else
> -        env->hflags &= ~HF_OSFXSR_MASK;
> +    }
> +
> +    if (!(env->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)) {
> +        new_cr4 &= ~CR4_SMAP_MASK;
> +    }
> +    env->hflags &= ~HF_SMAP_MASK;
> +    if (new_cr4 & CR4_SMAP_MASK) {
> +        env->hflags |= HF_SMAP_MASK;
> +    }
>  
>      env->cr[4] = new_cr4;
>  }
> @@ -591,17 +601,38 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, 
> target_ulong addr,
>              /* 2 MB page */
>              page_size = 2048 * 1024;
>              ptep ^= PG_NX_MASK;
> -            if ((ptep & PG_NX_MASK) && is_write1 == 2)
> +            if ((ptep & PG_NX_MASK) && is_write1 == 2) {
>                  goto do_fault_protect;
> -            if (is_user) {
> -                if (!(ptep & PG_USER_MASK))
> +            }
> +            switch (mmu_idx) {
> +            case MMU_USER_IDX:
> +                if (!(ptep & PG_USER_MASK)) {
>                      goto do_fault_protect;
> -                if (is_write && !(ptep & PG_RW_MASK))
> +                }
> +                if (is_write && !(ptep & PG_RW_MASK)) {
>                      goto do_fault_protect;
> -            } else {
> +                }
> +                break;
> +
> +            case MMU_KERNEL_IDX:
> +                if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) &&
> +                    (ptep & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
> +                /* fall through */
> +            case MMU_KSMAP_IDX:
> +                if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) &&
> +                    (ptep & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
>                  if ((env->cr[0] & CR0_WP_MASK) &&
> -                    is_write && !(ptep & PG_RW_MASK))
> +                    is_write && !(ptep & PG_RW_MASK)) {
>                      goto do_fault_protect;
> +                }
> +                break;
> +
> +            default: /* cannot happen */
> +                break;
>              }
>              is_dirty = is_write && !(pde & PG_DIRTY_MASK);
>              if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
> @@ -635,15 +666,35 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, 
> target_ulong addr,
>              ptep ^= PG_NX_MASK;
>              if ((ptep & PG_NX_MASK) && is_write1 == 2)
>                  goto do_fault_protect;
> -            if (is_user) {
> -                if (!(ptep & PG_USER_MASK))
> +            switch (mmu_idx) {
> +            case MMU_USER_IDX:
> +                if (!(ptep & PG_USER_MASK)) {
>                      goto do_fault_protect;
> -                if (is_write && !(ptep & PG_RW_MASK))
> +                }
> +                if (is_write && !(ptep & PG_RW_MASK)) {
>                      goto do_fault_protect;
> -            } else {
> +                }
> +                break;
> +
> +            case MMU_KERNEL_IDX:
> +                if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) &&
> +                    (ptep & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
> +                /* fall through */
> +            case MMU_KSMAP_IDX:
> +                if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) &&
> +                    (ptep & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
>                  if ((env->cr[0] & CR0_WP_MASK) &&
> -                    is_write && !(ptep & PG_RW_MASK))
> +                    is_write && !(ptep & PG_RW_MASK)) {
>                      goto do_fault_protect;
> +                }
> +                break;
> +
> +            default: /* cannot happen */
> +                break;
>              }
>              is_dirty = is_write && !(pte & PG_DIRTY_MASK);
>              if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
> @@ -670,15 +721,35 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, 
> target_ulong addr,
>          /* if PSE bit is set, then we use a 4MB page */
>          if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
>              page_size = 4096 * 1024;
> -            if (is_user) {
> -                if (!(pde & PG_USER_MASK))
> +            switch (mmu_idx) {
> +            case MMU_USER_IDX:
> +                if (!(pde & PG_USER_MASK)) {
>                      goto do_fault_protect;
> -                if (is_write && !(pde & PG_RW_MASK))
> +                }
> +                if (is_write && !(pde & PG_RW_MASK)) {
>                      goto do_fault_protect;
> -            } else {
> +                }
> +                break;
> +
> +            case MMU_KERNEL_IDX:
> +                if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) &&
> +                    (pde & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
> +                /* fall through */
> +            case MMU_KSMAP_IDX:
> +                if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) &&
> +                    (pde & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
>                  if ((env->cr[0] & CR0_WP_MASK) &&
> -                    is_write && !(pde & PG_RW_MASK))
> +                    is_write && !(pde & PG_RW_MASK)) {
>                      goto do_fault_protect;
> +                }
> +                break;
> +
> +            default: /* cannot happen */
> +                break;
>              }
>              is_dirty = is_write && !(pde & PG_DIRTY_MASK);
>              if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
> @@ -707,15 +778,35 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, 
> target_ulong addr,
>              }
>              /* combine pde and pte user and rw protections */
>              ptep = pte & pde;
> -            if (is_user) {
> -                if (!(ptep & PG_USER_MASK))
> +            switch (mmu_idx) {
> +            case MMU_USER_IDX:
> +                if (!(ptep & PG_USER_MASK)) {
>                      goto do_fault_protect;
> -                if (is_write && !(ptep & PG_RW_MASK))
> +                }
> +                if (is_write && !(ptep & PG_RW_MASK)) {
>                      goto do_fault_protect;
> -            } else {
> +                }
> +                break;
> +
> +            case MMU_KERNEL_IDX:
> +                if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) &&
> +                    (ptep & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
> +                /* fall through */
> +            case MMU_KSMAP_IDX:
> +                if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) &&
> +                    (ptep & PG_USER_MASK)) {
> +                    goto do_fault_protect;
> +                }
>                  if ((env->cr[0] & CR0_WP_MASK) &&
> -                    is_write && !(ptep & PG_RW_MASK))
> +                    is_write && !(ptep & PG_RW_MASK)) {
>                      goto do_fault_protect;
> +                }
> +                break;
> +
> +            default: /* cannot happen */
> +                break;
>              }
>              is_dirty = is_write && !(pte & PG_DIRTY_MASK);
>              if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
> @@ -762,8 +853,9 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, 
> target_ulong addr,
>      if (is_user)
>          error_code |= PG_ERROR_U_MASK;
>      if (is_write1 == 2 &&
> -        (env->efer & MSR_EFER_NXE) &&
> -        (env->cr[4] & CR4_PAE_MASK))
> +        (((env->efer & MSR_EFER_NXE) &&
> +          (env->cr[4] & CR4_PAE_MASK)) ||
> +         (env->cr[4] & CR4_SMEP_MASK)))
>          error_code |= PG_ERROR_I_D_MASK;
>      if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) {
>          /* cr2 is not modified in case of exceptions */
> diff --git a/target-i386/helper.h b/target-i386/helper.h
> index ab6af63..93850ce 100644
> --- a/target-i386/helper.h
> +++ b/target-i386/helper.h
> @@ -67,6 +67,8 @@ DEF_HELPER_3(raise_interrupt, void, env, int, int)
>  DEF_HELPER_2(raise_exception, void, env, int)
>  DEF_HELPER_1(cli, void, env)
>  DEF_HELPER_1(sti, void, env)
> +DEF_HELPER_1(clac, void, env)
> +DEF_HELPER_1(stac, void, env)
>  DEF_HELPER_1(set_inhibit_irq, void, env)
>  DEF_HELPER_1(reset_inhibit_irq, void, env)
>  DEF_HELPER_3(boundw, void, env, tl, int)
> diff --git a/target-i386/translate.c b/target-i386/translate.c
> index eb0cabc..b33d20a 100644
> --- a/target-i386/translate.c
> +++ b/target-i386/translate.c
> @@ -107,6 +107,7 @@ typedef struct DisasContext {
>      int cpuid_ext_features;
>      int cpuid_ext2_features;
>      int cpuid_ext3_features;
> +    int cpuid_7_0_ebx_features;
>  } DisasContext;
>  
>  static void gen_eob(DisasContext *s);
> @@ -6555,7 +6556,7 @@ static target_ulong disas_insn(DisasContext *s, 
> target_ulong pc_start)
>              }
>              gen_pop_update(s);
>              s->cc_op = CC_OP_EFLAGS;
> -            /* abort translation because TF flag may change */
> +            /* abort translation because TF/AC flag may change */
>              gen_jmp_im(s->pc - s->cs_base);
>              gen_eob(s);
>          }
> @@ -7205,6 +7206,24 @@ static target_ulong disas_insn(DisasContext *s, 
> target_ulong pc_start)
>                      gen_helper_mwait(cpu_env, tcg_const_i32(s->pc - 
> pc_start));
>                      gen_eob(s);
>                      break;
> +                case 2: /* clac */
> +                    if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) ||
> +                        s->cpl != 0) {
> +                        goto illegal_op;
> +                    }
> +                    gen_helper_clac(cpu_env);
> +                    gen_jmp_im(s->pc - s->cs_base);
> +                    gen_eob(s);
> +                    break;
> +                case 3: /* stac */
> +                    if (!(s->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP) ||
> +                        s->cpl != 0) {
> +                        goto illegal_op;
> +                    }
> +                    gen_helper_stac(cpu_env);
> +                    gen_jmp_im(s->pc - s->cs_base);
> +                    gen_eob(s);
> +                    break;
>                  default:
>                      goto illegal_op;
>                  }
> @@ -7900,15 +7919,13 @@ static inline void 
> gen_intermediate_code_internal(CPUX86State *env,
>      /* select memory access functions */
>      dc->mem_index = 0;
>      if (flags & HF_SOFTMMU_MASK) {
> -        if (dc->cpl == 3)
> -            dc->mem_index = 2 * 4;
> -        else
> -            dc->mem_index = 1 * 4;
> +        dc->mem_index = (cpu_mmu_index(env) + 1) << 2;
>      }
>      dc->cpuid_features = env->cpuid_features;
>      dc->cpuid_ext_features = env->cpuid_ext_features;
>      dc->cpuid_ext2_features = env->cpuid_ext2_features;
>      dc->cpuid_ext3_features = env->cpuid_ext3_features;
> +    dc->cpuid_7_0_ebx_features = env->cpuid_7_0_ebx_features;
>  #ifdef TARGET_X86_64
>      dc->lma = (flags >> HF_LMA_SHIFT) & 1;
>      dc->code64 = (flags >> HF_CS64_SHIFT) & 1;

I haven't tried it, but it looks fine to me.

Reviewed-by: Aurelien Jarno <address@hidden>


-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
address@hidden                 http://www.aurel32.net



reply via email to

[Prev in Thread] Current Thread [Next in Thread]