From b1d72b5f52b57d4b462f4d9242bd78d6b7a9edd2 Mon Sep 17 00:00:00 2001 From: patrick Date: Wed, 19 May 2021 17:46:36 +0000 Subject: [PATCH] Disable global mappings when using PCID. Page table mappings are frequently created and destroyed in the kernel address space. Traditionally, these mappings have been marked as "global" mappings which means that a TLB flush via %cr3 load does not invalidate them. This is ok as these mappings are the same for all processes. With the advent of MELTDOWN, global mappings were disabled for CPUs that are affected by rogue data cache load (RDCL aka MELTDOWN). To compensate for this we started using PCID and the kernel got its own process context identifier. Thus the hardware is allowed to cache kernel mappings again. However, a CPU that supports PCID but is _not_ affected by MELTDOWN (i.e. ARCH_CAPABILTIES.RDCL_NO=1) will now use both: global PTE mappings and PCID. This is a problem if range based TLB invalidations are used to update/ flush cached TLBs after a change to the kernel page tables. The reason is that the invpcid instruction (function 0) that is used to remove the cached TLBs will not remove global mappings. In the non-PCID case invlpg is used instead which does remove global mappings. In the MELTDOWN case, global mappings are not used at all. The solution is to not use global mappings if PCID is active, as the latter should already by enough to let the hardware cache kernel address translations across address space switches and the global flag is not required. From Christian Ehrhardt ok bluhm@ guenther@ mlarkin@ --- sys/arch/amd64/amd64/pmap.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c index d1bf001fab0..49c69538367 100644 --- a/sys/arch/amd64/amd64/pmap.c +++ b/sys/arch/amd64/amd64/pmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.c,v 1.142 2021/05/10 00:52:15 guenther Exp $ */ +/* $OpenBSD: pmap.c,v 1.143 2021/05/19 17:46:36 patrick Exp $ */ /* $NetBSD: pmap.c,v 1.3 2003/05/08 18:13:13 thorpej Exp $ */ /* @@ -698,6 +698,14 @@ pmap_bootstrap(paddr_t first_avail, paddr_t max_pa) CPUID_LEAF(0x7, 0, dummy, ebx, dummy, dummy); if (ebx & SEFF0EBX_INVPCID) { pmap_use_pcid = 1; + /* + * We cannot use global mappings because + * invpcid function 0 does not invalidate global + * mappings. The hardware can cache kernel + * mappings based on PCID_KERN, i.e. there is no + * need for global mappings. + */ + pg_g_kern = 0; lcr4( rcr4() | CR4_PCIDE ); cr3_pcid_proc = PCID_PROC; cr3_pcid_temp = PCID_TEMP; -- 2.20.1