[PATCH] x86emul: recognize CLDEMOTE

Jan Beulich posted 1 patch 2 years, 3 months ago
Test gitlab-ci failed
Patches applied successfully (tree, apply log)
git fetch https://gitlab.com/xen-project/patchew/xen tags/patchew/5812dc8e-d77d-f9de-4f37-b0ef094c5c09@suse.com
[PATCH] x86emul: recognize CLDEMOTE
Posted by Jan Beulich 2 years, 3 months ago
We claim to support the insn, but so far the emulator has been handling
it as a NOP.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
While handling x86emul_cldemote separately in hvmemul_cache_op() means
to carry some redundant code, folding it with CLFLUSH{,OPT} / CLWB
didn't seem very attractive either.

--- a/xen/arch/x86/arch.mk
+++ b/xen/arch/x86/arch.mk
@@ -23,6 +23,7 @@ $(call as-option-add,CFLAGS,CC,"xsaveopt
 $(call as-option-add,CFLAGS,CC,"rdseed %eax",-DHAVE_AS_RDSEED)
 $(call as-option-add,CFLAGS,CC,"clac",-DHAVE_AS_CLAC_STAC)
 $(call as-option-add,CFLAGS,CC,"clwb (%rax)",-DHAVE_AS_CLWB)
+$(call as-option-add,CFLAGS,CC,"cldemote (%rax)",-DHAVE_AS_CLDEMOTE)
 $(call as-option-add,CFLAGS,CC,".equ \"x\"$$(comma)1",-DHAVE_AS_QUOTED_SYM)
 $(call as-option-add,CFLAGS,CC,"invpcid (%rax)$$(comma)%rax",-DHAVE_AS_INVPCID)
 $(call as-option-add,CFLAGS,CC,"movdiri %rax$$(comma)(%rax)",-DHAVE_AS_MOVDIR)
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -2351,6 +2351,28 @@ static int hvmemul_cache_op(
          * to be sensibly used is in (virtualization unaware) firmware.
          */
         break;
+
+    case x86emul_cldemote:
+        ASSERT(!is_x86_system_segment(seg));
+
+        if ( !boot_cpu_has(X86_FEATURE_CLDEMOTE) ||
+             hvmemul_virtual_to_linear(seg, offset, 0, NULL, hvm_access_none,
+                                       hvmemul_ctxt, &addr) != X86EMUL_OKAY )
+            break;
+
+        if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 )
+            pfec |= PFEC_user_mode;
+
+        mapping = hvmemul_map_linear_addr(addr, 0, pfec, hvmemul_ctxt);
+        if ( mapping == ERR_PTR(~X86EMUL_EXCEPTION) )
+            x86_emul_reset_event(&hvmemul_ctxt->ctxt);
+        if ( IS_ERR_OR_NULL(mapping) )
+            break;
+
+        cldemote(mapping);
+
+        hvmemul_unmap_linear_addr(mapping, addr, 0, hvmemul_ctxt);
+        break;
     }
 
     return X86EMUL_OKAY;
--- a/xen/arch/x86/include/asm/system.h
+++ b/xen/arch/x86/include/asm/system.h
@@ -37,6 +37,16 @@ static inline void clwb(const void *p)
 #endif
 }
 
+static inline void cldemote(const void *p)
+{
+#if defined(HAVE_AS_CLDEMOTE)
+    asm volatile ( "cldemote %0" :: "m" (*(const char *)p) );
+#else
+    asm volatile ( ".byte 0x0f, 0x1c, 0x02"
+                   :: "d" (p), "m" (*(const char *)p) );
+#endif
+}
+
 #define xchg(ptr,v) \
     ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
 
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -6290,7 +6290,8 @@ x86_emulate(
 
     case X86EMUL_OPC(0x0f, 0x0d): /* GrpP (prefetch) */
     case X86EMUL_OPC(0x0f, 0x18): /* Grp16 (prefetch/nop) */
-    case X86EMUL_OPC(0x0f, 0x19) ... X86EMUL_OPC(0x0f, 0x1f): /* nop */
+    case X86EMUL_OPC(0x0f, 0x19) ... X86EMUL_OPC(0x0f, 0x1b): /* nop */
+    case X86EMUL_OPC(0x0f, 0x1d) ... X86EMUL_OPC(0x0f, 0x1f): /* nop */
         break;
 
 #ifndef X86EMUL_NO_MMX
@@ -6627,6 +6628,12 @@ x86_emulate(
 
 #endif /* !X86EMUL_NO_SIMD */
 
+    case X86EMUL_OPC(0x0f, 0x1c): /* cldemote / nop */
+        if ( ctxt->cpuid->feat.cldemote && !vex.pfx && !modrm_reg &&
+             ops->cache_op )
+            ops->cache_op(x86emul_cldemote, ea.mem.seg, ea.mem.off, ctxt);
+        break;
+
     case X86EMUL_OPC(0x0f, 0x20): /* mov cr,reg */
     case X86EMUL_OPC(0x0f, 0x21): /* mov dr,reg */
     case X86EMUL_OPC(0x0f, 0x22): /* mov reg,cr */
--- a/xen/arch/x86/x86_emulate/x86_emulate.h
+++ b/xen/arch/x86/x86_emulate/x86_emulate.h
@@ -177,6 +177,7 @@ enum x86_emulate_fpu_type {
 };
 
 enum x86emul_cache_op {
+    x86emul_cldemote,
     x86emul_clflush,
     x86emul_clflushopt,
     x86emul_clwb,


Re: [PATCH] x86emul: recognize CLDEMOTE
Posted by Roger Pau Monné 2 years, 3 months ago
On Tue, Jan 25, 2022 at 03:22:25PM +0100, Jan Beulich wrote:
> We claim to support the insn, but so far the emulator has been handling
> it as a NOP.

While not ideal, the SDM mentions that "The CLDEMOTE instruction may
be ignored by hardware in certain cases and is not a guarantee.".

> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> ---
> While handling x86emul_cldemote separately in hvmemul_cache_op() means
> to carry some redundant code, folding it with CLFLUSH{,OPT} / CLWB
> didn't seem very attractive either.
> 
> --- a/xen/arch/x86/arch.mk
> +++ b/xen/arch/x86/arch.mk
> @@ -23,6 +23,7 @@ $(call as-option-add,CFLAGS,CC,"xsaveopt
>  $(call as-option-add,CFLAGS,CC,"rdseed %eax",-DHAVE_AS_RDSEED)
>  $(call as-option-add,CFLAGS,CC,"clac",-DHAVE_AS_CLAC_STAC)
>  $(call as-option-add,CFLAGS,CC,"clwb (%rax)",-DHAVE_AS_CLWB)
> +$(call as-option-add,CFLAGS,CC,"cldemote (%rax)",-DHAVE_AS_CLDEMOTE)
>  $(call as-option-add,CFLAGS,CC,".equ \"x\"$$(comma)1",-DHAVE_AS_QUOTED_SYM)
>  $(call as-option-add,CFLAGS,CC,"invpcid (%rax)$$(comma)%rax",-DHAVE_AS_INVPCID)
>  $(call as-option-add,CFLAGS,CC,"movdiri %rax$$(comma)(%rax)",-DHAVE_AS_MOVDIR)
> --- a/xen/arch/x86/hvm/emulate.c
> +++ b/xen/arch/x86/hvm/emulate.c
> @@ -2351,6 +2351,28 @@ static int hvmemul_cache_op(
>           * to be sensibly used is in (virtualization unaware) firmware.
>           */
>          break;
> +
> +    case x86emul_cldemote:
> +        ASSERT(!is_x86_system_segment(seg));
> +
> +        if ( !boot_cpu_has(X86_FEATURE_CLDEMOTE) ||
> +             hvmemul_virtual_to_linear(seg, offset, 0, NULL, hvm_access_none,
> +                                       hvmemul_ctxt, &addr) != X86EMUL_OKAY )
> +            break;
> +
> +        if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 )
> +            pfec |= PFEC_user_mode;
> +
> +        mapping = hvmemul_map_linear_addr(addr, 0, pfec, hvmemul_ctxt);

I think the emulator should map the address using the same cache
attributes as the guest, or else the result might be different than
intended?

Thanks, Roger.

Re: [PATCH] x86emul: recognize CLDEMOTE
Posted by Jan Beulich 2 years, 3 months ago
On 25.01.2022 15:35, Roger Pau Monné wrote:
> On Tue, Jan 25, 2022 at 03:22:25PM +0100, Jan Beulich wrote:
>> We claim to support the insn, but so far the emulator has been handling
>> it as a NOP.
> 
> While not ideal, the SDM mentions that "The CLDEMOTE instruction may
> be ignored by hardware in certain cases and is not a guarantee.".

Right; the same is effectively the case for CLFLUSH etc. Still, unlike
prefetches, we implement them in the emulator.

>> --- a/xen/arch/x86/hvm/emulate.c
>> +++ b/xen/arch/x86/hvm/emulate.c
>> @@ -2351,6 +2351,28 @@ static int hvmemul_cache_op(
>>           * to be sensibly used is in (virtualization unaware) firmware.
>>           */
>>          break;
>> +
>> +    case x86emul_cldemote:
>> +        ASSERT(!is_x86_system_segment(seg));
>> +
>> +        if ( !boot_cpu_has(X86_FEATURE_CLDEMOTE) ||
>> +             hvmemul_virtual_to_linear(seg, offset, 0, NULL, hvm_access_none,
>> +                                       hvmemul_ctxt, &addr) != X86EMUL_OKAY )
>> +            break;
>> +
>> +        if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 )
>> +            pfec |= PFEC_user_mode;
>> +
>> +        mapping = hvmemul_map_linear_addr(addr, 0, pfec, hvmemul_ctxt);
> 
> I think the emulator should map the address using the same cache
> attributes as the guest, or else the result might be different than
> intended?

That's a pre-existing problem everywhere, not something specific to
this one insn.

Jan


Re: [PATCH] x86emul: recognize CLDEMOTE
Posted by Jan Beulich 2 years, 3 months ago
On 25.01.2022 15:22, Jan Beulich wrote:
> We claim to support the insn, but so far the emulator has been handling
> it as a NOP.
> 
> Signed-off-by: Jan Beulich <jbeulich@suse.com>

I'm sorry, I should have Cc-ed Paul here as well.

Jan

> ---
> While handling x86emul_cldemote separately in hvmemul_cache_op() means
> to carry some redundant code, folding it with CLFLUSH{,OPT} / CLWB
> didn't seem very attractive either.
> 
> --- a/xen/arch/x86/arch.mk
> +++ b/xen/arch/x86/arch.mk
> @@ -23,6 +23,7 @@ $(call as-option-add,CFLAGS,CC,"xsaveopt
>  $(call as-option-add,CFLAGS,CC,"rdseed %eax",-DHAVE_AS_RDSEED)
>  $(call as-option-add,CFLAGS,CC,"clac",-DHAVE_AS_CLAC_STAC)
>  $(call as-option-add,CFLAGS,CC,"clwb (%rax)",-DHAVE_AS_CLWB)
> +$(call as-option-add,CFLAGS,CC,"cldemote (%rax)",-DHAVE_AS_CLDEMOTE)
>  $(call as-option-add,CFLAGS,CC,".equ \"x\"$$(comma)1",-DHAVE_AS_QUOTED_SYM)
>  $(call as-option-add,CFLAGS,CC,"invpcid (%rax)$$(comma)%rax",-DHAVE_AS_INVPCID)
>  $(call as-option-add,CFLAGS,CC,"movdiri %rax$$(comma)(%rax)",-DHAVE_AS_MOVDIR)
> --- a/xen/arch/x86/hvm/emulate.c
> +++ b/xen/arch/x86/hvm/emulate.c
> @@ -2351,6 +2351,28 @@ static int hvmemul_cache_op(
>           * to be sensibly used is in (virtualization unaware) firmware.
>           */
>          break;
> +
> +    case x86emul_cldemote:
> +        ASSERT(!is_x86_system_segment(seg));
> +
> +        if ( !boot_cpu_has(X86_FEATURE_CLDEMOTE) ||
> +             hvmemul_virtual_to_linear(seg, offset, 0, NULL, hvm_access_none,
> +                                       hvmemul_ctxt, &addr) != X86EMUL_OKAY )
> +            break;
> +
> +        if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 )
> +            pfec |= PFEC_user_mode;
> +
> +        mapping = hvmemul_map_linear_addr(addr, 0, pfec, hvmemul_ctxt);
> +        if ( mapping == ERR_PTR(~X86EMUL_EXCEPTION) )
> +            x86_emul_reset_event(&hvmemul_ctxt->ctxt);
> +        if ( IS_ERR_OR_NULL(mapping) )
> +            break;
> +
> +        cldemote(mapping);
> +
> +        hvmemul_unmap_linear_addr(mapping, addr, 0, hvmemul_ctxt);
> +        break;
>      }
>  
>      return X86EMUL_OKAY;
> --- a/xen/arch/x86/include/asm/system.h
> +++ b/xen/arch/x86/include/asm/system.h
> @@ -37,6 +37,16 @@ static inline void clwb(const void *p)
>  #endif
>  }
>  
> +static inline void cldemote(const void *p)
> +{
> +#if defined(HAVE_AS_CLDEMOTE)
> +    asm volatile ( "cldemote %0" :: "m" (*(const char *)p) );
> +#else
> +    asm volatile ( ".byte 0x0f, 0x1c, 0x02"
> +                   :: "d" (p), "m" (*(const char *)p) );
> +#endif
> +}
> +
>  #define xchg(ptr,v) \
>      ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
>  
> --- a/xen/arch/x86/x86_emulate/x86_emulate.c
> +++ b/xen/arch/x86/x86_emulate/x86_emulate.c
> @@ -6290,7 +6290,8 @@ x86_emulate(
>  
>      case X86EMUL_OPC(0x0f, 0x0d): /* GrpP (prefetch) */
>      case X86EMUL_OPC(0x0f, 0x18): /* Grp16 (prefetch/nop) */
> -    case X86EMUL_OPC(0x0f, 0x19) ... X86EMUL_OPC(0x0f, 0x1f): /* nop */
> +    case X86EMUL_OPC(0x0f, 0x19) ... X86EMUL_OPC(0x0f, 0x1b): /* nop */
> +    case X86EMUL_OPC(0x0f, 0x1d) ... X86EMUL_OPC(0x0f, 0x1f): /* nop */
>          break;
>  
>  #ifndef X86EMUL_NO_MMX
> @@ -6627,6 +6628,12 @@ x86_emulate(
>  
>  #endif /* !X86EMUL_NO_SIMD */
>  
> +    case X86EMUL_OPC(0x0f, 0x1c): /* cldemote / nop */
> +        if ( ctxt->cpuid->feat.cldemote && !vex.pfx && !modrm_reg &&
> +             ops->cache_op )
> +            ops->cache_op(x86emul_cldemote, ea.mem.seg, ea.mem.off, ctxt);
> +        break;
> +
>      case X86EMUL_OPC(0x0f, 0x20): /* mov cr,reg */
>      case X86EMUL_OPC(0x0f, 0x21): /* mov dr,reg */
>      case X86EMUL_OPC(0x0f, 0x22): /* mov reg,cr */
> --- a/xen/arch/x86/x86_emulate/x86_emulate.h
> +++ b/xen/arch/x86/x86_emulate/x86_emulate.h
> @@ -177,6 +177,7 @@ enum x86_emulate_fpu_type {
>  };
>  
>  enum x86emul_cache_op {
> +    x86emul_cldemote,
>      x86emul_clflush,
>      x86emul_clflushopt,
>      x86emul_clwb,
> 
> 


Re: [PATCH] x86emul: recognize CLDEMOTE
Posted by Durrant, Paul 2 years, 3 months ago
On 25/01/2022 15:08, Jan Beulich wrote:
> On 25.01.2022 15:22, Jan Beulich wrote:
>> We claim to support the insn, but so far the emulator has been handling
>> it as a NOP.
>>
>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> 
> I'm sorry, I should have Cc-ed Paul here as well.
> 

Acked-by: Paul Durrant <paul@xen.org>

> Jan
> 
>> ---
>> While handling x86emul_cldemote separately in hvmemul_cache_op() means
>> to carry some redundant code, folding it with CLFLUSH{,OPT} / CLWB
>> didn't seem very attractive either.
>>
>> --- a/xen/arch/x86/arch.mk
>> +++ b/xen/arch/x86/arch.mk
>> @@ -23,6 +23,7 @@ $(call as-option-add,CFLAGS,CC,"xsaveopt
>>   $(call as-option-add,CFLAGS,CC,"rdseed %eax",-DHAVE_AS_RDSEED)
>>   $(call as-option-add,CFLAGS,CC,"clac",-DHAVE_AS_CLAC_STAC)
>>   $(call as-option-add,CFLAGS,CC,"clwb (%rax)",-DHAVE_AS_CLWB)
>> +$(call as-option-add,CFLAGS,CC,"cldemote (%rax)",-DHAVE_AS_CLDEMOTE)
>>   $(call as-option-add,CFLAGS,CC,".equ \"x\"$$(comma)1",-DHAVE_AS_QUOTED_SYM)
>>   $(call as-option-add,CFLAGS,CC,"invpcid (%rax)$$(comma)%rax",-DHAVE_AS_INVPCID)
>>   $(call as-option-add,CFLAGS,CC,"movdiri %rax$$(comma)(%rax)",-DHAVE_AS_MOVDIR)
>> --- a/xen/arch/x86/hvm/emulate.c
>> +++ b/xen/arch/x86/hvm/emulate.c
>> @@ -2351,6 +2351,28 @@ static int hvmemul_cache_op(
>>            * to be sensibly used is in (virtualization unaware) firmware.
>>            */
>>           break;
>> +
>> +    case x86emul_cldemote:
>> +        ASSERT(!is_x86_system_segment(seg));
>> +
>> +        if ( !boot_cpu_has(X86_FEATURE_CLDEMOTE) ||
>> +             hvmemul_virtual_to_linear(seg, offset, 0, NULL, hvm_access_none,
>> +                                       hvmemul_ctxt, &addr) != X86EMUL_OKAY )
>> +            break;
>> +
>> +        if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 )
>> +            pfec |= PFEC_user_mode;
>> +
>> +        mapping = hvmemul_map_linear_addr(addr, 0, pfec, hvmemul_ctxt);
>> +        if ( mapping == ERR_PTR(~X86EMUL_EXCEPTION) )
>> +            x86_emul_reset_event(&hvmemul_ctxt->ctxt);
>> +        if ( IS_ERR_OR_NULL(mapping) )
>> +            break;
>> +
>> +        cldemote(mapping);
>> +
>> +        hvmemul_unmap_linear_addr(mapping, addr, 0, hvmemul_ctxt);
>> +        break;
>>       }
>>   
>>       return X86EMUL_OKAY;
>> --- a/xen/arch/x86/include/asm/system.h
>> +++ b/xen/arch/x86/include/asm/system.h
>> @@ -37,6 +37,16 @@ static inline void clwb(const void *p)
>>   #endif
>>   }
>>   
>> +static inline void cldemote(const void *p)
>> +{
>> +#if defined(HAVE_AS_CLDEMOTE)
>> +    asm volatile ( "cldemote %0" :: "m" (*(const char *)p) );
>> +#else
>> +    asm volatile ( ".byte 0x0f, 0x1c, 0x02"
>> +                   :: "d" (p), "m" (*(const char *)p) );
>> +#endif
>> +}
>> +
>>   #define xchg(ptr,v) \
>>       ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
>>   
>> --- a/xen/arch/x86/x86_emulate/x86_emulate.c
>> +++ b/xen/arch/x86/x86_emulate/x86_emulate.c
>> @@ -6290,7 +6290,8 @@ x86_emulate(
>>   
>>       case X86EMUL_OPC(0x0f, 0x0d): /* GrpP (prefetch) */
>>       case X86EMUL_OPC(0x0f, 0x18): /* Grp16 (prefetch/nop) */
>> -    case X86EMUL_OPC(0x0f, 0x19) ... X86EMUL_OPC(0x0f, 0x1f): /* nop */
>> +    case X86EMUL_OPC(0x0f, 0x19) ... X86EMUL_OPC(0x0f, 0x1b): /* nop */
>> +    case X86EMUL_OPC(0x0f, 0x1d) ... X86EMUL_OPC(0x0f, 0x1f): /* nop */
>>           break;
>>   
>>   #ifndef X86EMUL_NO_MMX
>> @@ -6627,6 +6628,12 @@ x86_emulate(
>>   
>>   #endif /* !X86EMUL_NO_SIMD */
>>   
>> +    case X86EMUL_OPC(0x0f, 0x1c): /* cldemote / nop */
>> +        if ( ctxt->cpuid->feat.cldemote && !vex.pfx && !modrm_reg &&
>> +             ops->cache_op )
>> +            ops->cache_op(x86emul_cldemote, ea.mem.seg, ea.mem.off, ctxt);
>> +        break;
>> +
>>       case X86EMUL_OPC(0x0f, 0x20): /* mov cr,reg */
>>       case X86EMUL_OPC(0x0f, 0x21): /* mov dr,reg */
>>       case X86EMUL_OPC(0x0f, 0x22): /* mov reg,cr */
>> --- a/xen/arch/x86/x86_emulate/x86_emulate.h
>> +++ b/xen/arch/x86/x86_emulate/x86_emulate.h
>> @@ -177,6 +177,7 @@ enum x86_emulate_fpu_type {
>>   };
>>   
>>   enum x86emul_cache_op {
>> +    x86emul_cldemote,
>>       x86emul_clflush,
>>       x86emul_clflushopt,
>>       x86emul_clwb,
>>
>>
> 


Re: [PATCH] x86emul: recognize CLDEMOTE
Posted by Andrew Cooper 2 years, 3 months ago
On 25/01/2022 14:22, Jan Beulich wrote:
> We claim to support the insn, but so far the emulator has been handling
> it as a NOP.
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>

Treating CLDEMOTE as a NOP is going to be more efficient than actually
setting up the mapping to execute a real CLDEMOTE instruction on the
line in question.  CLDEMOTE is very specifically an optimisation for
software producer/consumer pairs.

If we want to take this patch, it should Fix[es]: ad3abc47dd23c which
made the claim that CLDEMOTE needed no further additions.

The only issue on whether we can treat it as a NOP completely is whether
we believe the exception list.  I'm not sure I believe the absence of
AGU faults, but the instruction is taken from hint-nop space so
guaranteed to behave similarly to clflush/clwb.

~Andrew
Re: [PATCH] x86emul: recognize CLDEMOTE
Posted by Jan Beulich 2 years, 3 months ago
On 25.01.2022 16:09, Andrew Cooper wrote:
> On 25/01/2022 14:22, Jan Beulich wrote:
>> We claim to support the insn, but so far the emulator has been handling
>> it as a NOP.
>>
>> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> 
> Treating CLDEMOTE as a NOP is going to be more efficient than actually
> setting up the mapping to execute a real CLDEMOTE instruction on the
> line in question.  CLDEMOTE is very specifically an optimisation for
> software producer/consumer pairs.

Some similar argument could likely be made for treating CLFLUSH etc as
just a NOP then?

> If we want to take this patch, it should Fix[es]: ad3abc47dd23c which
> made the claim that CLDEMOTE needed no further additions.

Added.

> The only issue on whether we can treat it as a NOP completely is whether
> we believe the exception list.  I'm not sure I believe the absence of
> AGU faults,

I also was puzzled by this, but I have no way to verify one way or the
other. Hence the implementation follows what the SDM says.

> but the instruction is taken from hint-nop space so
> guaranteed to behave similarly to clflush/clwb.

I'm confused: CLFLUSH / CLWB specifically do not live in NOP space:
The former are under 0FAE, while NOP space is 0F18 ... 0F1F (with
CLDEMOTE being 0F1C).

Jan