Skip to content

Commit 634ab76

Browse files
tlendackyIngo Molnar
authored andcommitted
x86/mm: Always set the ASID valid bit for the INVLPGB instruction
When executing the INVLPGB instruction on a bare-metal host or hypervisor, if the ASID valid bit is not set, the instruction will flush the TLB entries that match the specified criteria for any ASID, not just the those of the host. If virtual machines are running on the system, this may result in inadvertent flushes of guest TLB entries. When executing the INVLPGB instruction in a guest and the INVLPGB instruction is not intercepted by the hypervisor, the hardware will replace the requested ASID with the guest ASID and set the ASID valid bit before doing the broadcast invalidation. Thus a guest is only able to flush its own TLB entries. So to limit the host TLB flushing reach, always set the ASID valid bit using an ASID value of 0 (which represents the host/hypervisor). This will will result in the desired effect in both host and guest. Signed-off-by: Tom Lendacky <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Link: https://lore.kernel.org/r/20250304120449.GHZ8bsYYyEBOKQIxBm@fat_crate.local
1 parent 440a65b commit 634ab76

File tree

1 file changed

+32
-26
lines changed
  • arch/x86/include/asm

1 file changed

+32
-26
lines changed

arch/x86/include/asm/tlb.h

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,58 @@ enum addr_stride {
3333
PMD_STRIDE = 1
3434
};
3535

36+
/*
37+
* INVLPGB can be targeted by virtual address, PCID, ASID, or any combination
38+
* of the three. For example:
39+
* - FLAG_VA | FLAG_INCLUDE_GLOBAL: invalidate all TLB entries at the address
40+
* - FLAG_PCID: invalidate all TLB entries matching the PCID
41+
*
42+
* The first is used to invalidate (kernel) mappings at a particular
43+
* address across all processes.
44+
*
45+
* The latter invalidates all TLB entries matching a PCID.
46+
*/
47+
#define INVLPGB_FLAG_VA BIT(0)
48+
#define INVLPGB_FLAG_PCID BIT(1)
49+
#define INVLPGB_FLAG_ASID BIT(2)
50+
#define INVLPGB_FLAG_INCLUDE_GLOBAL BIT(3)
51+
#define INVLPGB_FLAG_FINAL_ONLY BIT(4)
52+
#define INVLPGB_FLAG_INCLUDE_NESTED BIT(5)
53+
54+
/* The implied mode when all bits are clear: */
55+
#define INVLPGB_MODE_ALL_NONGLOBALS 0UL
56+
3657
#ifdef CONFIG_BROADCAST_TLB_FLUSH
3758
/*
3859
* INVLPGB does broadcast TLB invalidation across all the CPUs in the system.
3960
*
4061
* The INVLPGB instruction is weakly ordered, and a batch of invalidations can
4162
* be done in a parallel fashion.
4263
*
43-
* The instruction takes the number of extra pages to invalidate, beyond
44-
* the first page, while __invlpgb gets the more human readable number of
45-
* pages to invalidate.
64+
* The instruction takes the number of extra pages to invalidate, beyond the
65+
* first page, while __invlpgb gets the more human readable number of pages to
66+
* invalidate.
4667
*
4768
* The bits in rax[0:2] determine respectively which components of the address
4869
* (VA, PCID, ASID) get compared when flushing. If neither bits are set, *any*
4970
* address in the specified range matches.
5071
*
72+
* Since it is desired to only flush TLB entries for the ASID that is executing
73+
* the instruction (a host/hypervisor or a guest), the ASID valid bit should
74+
* always be set. On a host/hypervisor, the hardware will use the ASID value
75+
* specified in EDX[15:0] (which should be 0). On a guest, the hardware will
76+
* use the actual ASID value of the guest.
77+
*
5178
* TLBSYNC is used to ensure that pending INVLPGB invalidations initiated from
5279
* this CPU have completed.
5380
*/
5481
static inline void __invlpgb(unsigned long asid, unsigned long pcid,
5582
unsigned long addr, u16 nr_pages,
5683
enum addr_stride stride, u8 flags)
5784
{
58-
u32 edx = (pcid << 16) | asid;
85+
u64 rax = addr | flags | INVLPGB_FLAG_ASID;
5986
u32 ecx = (stride << 31) | (nr_pages - 1);
60-
u64 rax = addr | flags;
87+
u32 edx = (pcid << 16) | asid;
6188

6289
/* The low bits in rax are for flags. Verify addr is clean. */
6390
VM_WARN_ON_ONCE(addr & ~PAGE_MASK);
@@ -93,27 +120,6 @@ static inline void __invlpgb_all(unsigned long asid, unsigned long pcid, u8 flag
93120
static inline void __tlbsync(void) { }
94121
#endif
95122

96-
/*
97-
* INVLPGB can be targeted by virtual address, PCID, ASID, or any combination
98-
* of the three. For example:
99-
* - FLAG_VA | FLAG_INCLUDE_GLOBAL: invalidate all TLB entries at the address
100-
* - FLAG_PCID: invalidate all TLB entries matching the PCID
101-
*
102-
* The first is used to invalidate (kernel) mappings at a particular
103-
* address across all processes.
104-
*
105-
* The latter invalidates all TLB entries matching a PCID.
106-
*/
107-
#define INVLPGB_FLAG_VA BIT(0)
108-
#define INVLPGB_FLAG_PCID BIT(1)
109-
#define INVLPGB_FLAG_ASID BIT(2)
110-
#define INVLPGB_FLAG_INCLUDE_GLOBAL BIT(3)
111-
#define INVLPGB_FLAG_FINAL_ONLY BIT(4)
112-
#define INVLPGB_FLAG_INCLUDE_NESTED BIT(5)
113-
114-
/* The implied mode when all bits are clear: */
115-
#define INVLPGB_MODE_ALL_NONGLOBALS 0UL
116-
117123
static inline void invlpgb_flush_user_nr_nosync(unsigned long pcid,
118124
unsigned long addr,
119125
u16 nr, bool stride)

0 commit comments

Comments
 (0)