Add the advisories to go with the updates.

Approved by:	so
This commit is contained in:
Gordon Tetlow 2019-11-12 18:48:44 +00:00
parent 15e75c5b82
commit eccf9265a4
Notes: svn2git 2020-12-08 03:00:23 +00:00
svn path=/head/; revision=53592
11 changed files with 1204 additions and 0 deletions

View file

@ -0,0 +1,219 @@
--- stand/efi/loader/bootinfo.c.orig
+++ stand/efi/loader/bootinfo.c
@@ -287,12 +287,12 @@
bi_load_efi_data(struct preloaded_file *kfp)
{
EFI_MEMORY_DESCRIPTOR *mm;
- EFI_PHYSICAL_ADDRESS addr;
+ EFI_PHYSICAL_ADDRESS addr = 0;
EFI_STATUS status;
const char *efi_novmap;
size_t efisz;
UINTN efi_mapkey;
- UINTN mmsz, pages, retry, sz;
+ UINTN dsz, pages, retry, sz;
UINT32 mmver;
struct efi_map_header *efihdr;
bool do_vmap;
@@ -323,76 +323,94 @@
efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf;
/*
- * Assgin size of EFI_MEMORY_DESCRIPTOR to keep compatible with
+ * Assign size of EFI_MEMORY_DESCRIPTOR to keep compatible with
* u-boot which doesn't fill this value when buffer for memory
* descriptors is too small (eg. 0 to obtain memory map size)
*/
- mmsz = sizeof(EFI_MEMORY_DESCRIPTOR);
+ dsz = sizeof(EFI_MEMORY_DESCRIPTOR);
/*
- * It is possible that the first call to ExitBootServices may change
- * the map key. Fetch a new map key and retry ExitBootServices in that
- * case.
+ * Allocate enough pages to hold the bootinfo block and the
+ * memory map EFI will return to us. The memory map has an
+ * unknown size, so we have to determine that first. Note that
+ * the AllocatePages call can itself modify the memory map, so
+ * we have to take that into account as well. The changes to
+ * the memory map are caused by splitting a range of free
+ * memory into two, so that one is marked as being loader
+ * data.
+ */
+
+ sz = 0;
+
+ /*
+ * Matthew Garrett has observed at least one system changing the
+ * memory map when calling ExitBootServices, causing it to return an
+ * error, probably because callbacks are allocating memory.
+ * So we need to retry calling it at least once.
*/
for (retry = 2; retry > 0; retry--) {
- /*
- * Allocate enough pages to hold the bootinfo block and the
- * memory map EFI will return to us. The memory map has an
- * unknown size, so we have to determine that first. Note that
- * the AllocatePages call can itself modify the memory map, so
- * we have to take that into account as well. The changes to
- * the memory map are caused by splitting a range of free
- * memory into two (AFAICT), so that one is marked as being
- * loader data.
- */
- sz = 0;
- BS->GetMemoryMap(&sz, NULL, &efi_mapkey, &mmsz, &mmver);
- sz += mmsz;
- sz = (sz + 0xf) & ~0xf;
- pages = EFI_SIZE_TO_PAGES(sz + efisz);
- status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
- pages, &addr);
- if (EFI_ERROR(status)) {
- printf("%s: AllocatePages error %lu\n", __func__,
- EFI_ERROR_CODE(status));
- return (ENOMEM);
- }
+ for (;;) {
+ status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &dsz, &mmver);
+ if (!EFI_ERROR(status))
+ break;
+
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ printf("%s: GetMemoryMap error %lu\n", __func__,
+ EFI_ERROR_CODE(status));
+ return (EINVAL);
+ }
+
+ if (addr != 0)
+ BS->FreePages(addr, pages);
+
+ /* Add 10 descriptors to the size to allow for
+ * fragmentation caused by calling AllocatePages */
+ sz += (10 * dsz);
+ pages = EFI_SIZE_TO_PAGES(sz + efisz);
+ status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
+ pages, &addr);
+ if (EFI_ERROR(status)) {
+ printf("%s: AllocatePages error %lu\n", __func__,
+ EFI_ERROR_CODE(status));
+ return (ENOMEM);
+ }
- /*
- * Read the memory map and stash it after bootinfo. Align the
- * memory map on a 16-byte boundary (the bootinfo block is page
- * aligned).
- */
- efihdr = (struct efi_map_header *)(uintptr_t)addr;
- mm = (void *)((uint8_t *)efihdr + efisz);
- sz = (EFI_PAGE_SIZE * pages) - efisz;
-
- status = BS->GetMemoryMap(&sz, mm, &efi_mapkey, &mmsz, &mmver);
- if (EFI_ERROR(status)) {
- printf("%s: GetMemoryMap error %lu\n", __func__,
- EFI_ERROR_CODE(status));
- return (EINVAL);
- }
- status = BS->ExitBootServices(IH, efi_mapkey);
- if (EFI_ERROR(status) == 0) {
/*
- * This may be disabled by setting efi_disable_vmap in
- * loader.conf(5). By default we will setup the virtual
- * map entries.
+ * Read the memory map and stash it after bootinfo. Align the
+ * memory map on a 16-byte boundary (the bootinfo block is page
+ * aligned).
*/
- if (do_vmap)
- efi_do_vmap(mm, sz, mmsz, mmver);
- efihdr->memory_size = sz;
- efihdr->descriptor_size = mmsz;
- efihdr->descriptor_version = mmver;
- file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz,
- efihdr);
- return (0);
+ efihdr = (struct efi_map_header *)(uintptr_t)addr;
+ mm = (void *)((uint8_t *)efihdr + efisz);
+ sz = (EFI_PAGE_SIZE * pages) - efisz;
}
+
+ status = BS->ExitBootServices(IH, efi_mapkey);
+ if (!EFI_ERROR(status))
+ break;
+ }
+
+ if (retry == 0) {
BS->FreePages(addr, pages);
+ printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status));
+ return (EINVAL);
}
- printf("ExitBootServices error %lu\n", EFI_ERROR_CODE(status));
- return (EINVAL);
+
+ /*
+ * This may be disabled by setting efi_disable_vmap in
+ * loader.conf(5). By default we will setup the virtual
+ * map entries.
+ */
+
+ if (do_vmap)
+ efi_do_vmap(mm, sz, dsz, mmver);
+ efihdr->memory_size = sz;
+ efihdr->descriptor_size = dsz;
+ efihdr->descriptor_version = mmver;
+ file_addmetadata(kfp, MODINFOMD_EFI_MAP, efisz + sz,
+ efihdr);
+
+ return (0);
}
/*
--- stand/efi/loader/copy.c.orig
+++ stand/efi/loader/copy.c
@@ -95,7 +95,7 @@
efi_verify_staging_size(unsigned long *nr_pages)
{
UINTN sz;
- EFI_MEMORY_DESCRIPTOR *map, *p;
+ EFI_MEMORY_DESCRIPTOR *map = NULL, *p;
EFI_PHYSICAL_ADDRESS start, end;
UINTN key, dsz;
UINT32 dver;
@@ -104,17 +104,28 @@
unsigned long available_pages = 0;
sz = 0;
- status = BS->GetMemoryMap(&sz, 0, &key, &dsz, &dver);
- if (status != EFI_BUFFER_TOO_SMALL) {
- printf("Can't determine memory map size\n");
- return;
- }
- map = malloc(sz);
- status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
- if (EFI_ERROR(status)) {
- printf("Can't read memory map\n");
- goto out;
+ for (;;) {
+ status = BS->GetMemoryMap(&sz, map, &key, &dsz, &dver);
+ if (!EFI_ERROR(status))
+ break;
+
+ if (status != EFI_BUFFER_TOO_SMALL) {
+ printf("Can't read memory map: %lu\n",
+ EFI_ERROR_CODE(status));
+ goto out;
+ }
+
+ free(map);
+
+ /* Allocate 10 descriptors more than the size reported,
+ * to allow for any fragmentation caused by calling
+ * malloc */
+ map = malloc(sz + (10 * dsz));
+ if (map == NULL) {
+ printf("Unable to allocate memory\n");
+ goto out;
+ }
}
ndesc = sz / dsz;

View file

@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAl3K+llfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cKQDA//UrHA7uTNrdGlLotWJQfCnFyeso3/jgOV/9eouJ4x0Ci81ubXqjFGs8co
/lx2PVkFJoJpPHrQOeReYAKiHhvygCilh/04wA9fiVVsrt7Clb4hAY1v4qr4hu32
lBVZCBLBsWBsWppoN88Xmm6QbQrF1IuVLPxEw55gR/4G9cHUi13WcHrIB68YiBNI
S3cHqWpPawoLAZcfaEbiMYtEFpnhaVXxPgzNUsmu16pzlZRSof44x9cOP0d5j70c
3UUqsoO0fT3PQBSoU4xIGg7c6ZAg+iLQEnLnC2PWFMKSov8OFcVF7XbygaLniOc5
fYXPZWyDw+4T3GDfiftj9j6pXkTcYUJhFz+Ukb0CEJZtV2Pzb6PLS0U4W0+4fyUA
7vT7WBdkcN5GrMXilu3se6/F/BEGUMC3WvSxpGZv81LyAOZ1j+Sta3uGoBJycJw5
gX61kDwc2BpzAPrPbIQs0TRxfKaAjDaMYMUmAqXaZWLQDegatqIJ/VMXKiTUSznA
9lIgQCXaviHXTuBEOCe1NmFmCuYFzVqgzcxq4KrgRbFzTBK0KYcjOoWsTGzjzwdi
TnQPFsnITZvRqybSMxQDGOcOp3m5WW2jpXzKIsc4E7o4UBEgrPVJFvadhSjnTEAC
KmzFYMBMKxjdTK0c/B92vADoqOInQD8h5f99cUsu5qT8xM98A3c=
=U6/A
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,155 @@
--- sys/amd64/amd64/pmap.c.orig
+++ sys/amd64/amd64/pmap.c
@@ -1226,6 +1226,51 @@
m->md.pat_mode = PAT_WRITE_BACK;
}
+static int pmap_allow_2m_x_ept;
+SYSCTL_INT(_vm_pmap, OID_AUTO, allow_2m_x_ept, CTLFLAG_RWTUN | CTLFLAG_NOFETCH,
+ &pmap_allow_2m_x_ept, 0,
+ "Allow executable superpage mappings in EPT");
+
+void
+pmap_allow_2m_x_ept_recalculate(void)
+{
+ /*
+ * SKL002, SKL012S. Since the EPT format is only used by
+ * Intel CPUs, the vendor check is merely a formality.
+ */
+ if (!(cpu_vendor_id != CPU_VENDOR_INTEL ||
+ (cpu_ia32_arch_caps & IA32_ARCH_CAP_IF_PSCHANGE_MC_NO) != 0 ||
+ (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ (CPUID_TO_MODEL(cpu_id) == 0x26 || /* Atoms */
+ CPUID_TO_MODEL(cpu_id) == 0x27 ||
+ CPUID_TO_MODEL(cpu_id) == 0x35 ||
+ CPUID_TO_MODEL(cpu_id) == 0x36 ||
+ CPUID_TO_MODEL(cpu_id) == 0x37 ||
+ CPUID_TO_MODEL(cpu_id) == 0x86 ||
+ CPUID_TO_MODEL(cpu_id) == 0x1c ||
+ CPUID_TO_MODEL(cpu_id) == 0x4a ||
+ CPUID_TO_MODEL(cpu_id) == 0x4c ||
+ CPUID_TO_MODEL(cpu_id) == 0x4d ||
+ CPUID_TO_MODEL(cpu_id) == 0x5a ||
+ CPUID_TO_MODEL(cpu_id) == 0x5c ||
+ CPUID_TO_MODEL(cpu_id) == 0x5d ||
+ CPUID_TO_MODEL(cpu_id) == 0x5f ||
+ CPUID_TO_MODEL(cpu_id) == 0x6e ||
+ CPUID_TO_MODEL(cpu_id) == 0x7a ||
+ CPUID_TO_MODEL(cpu_id) == 0x57 || /* Knights */
+ CPUID_TO_MODEL(cpu_id) == 0x85))))
+ pmap_allow_2m_x_ept = 1;
+ TUNABLE_INT_FETCH("hw.allow_2m_x_ept", &pmap_allow_2m_x_ept);
+}
+
+static bool
+pmap_allow_2m_x_page(pmap_t pmap, bool executable)
+{
+
+ return (pmap->pm_type != PT_EPT || !executable ||
+ !pmap_allow_2m_x_ept);
+}
+
/*
* Initialize the pmap module.
* Called by vm_init, to initialize any structures that the pmap
@@ -1270,6 +1315,9 @@
}
}
+ /* IFU */
+ pmap_allow_2m_x_ept_recalculate();
+
/*
* Initialize the vm page array entries for the kernel pmap's
* page table pages.
@@ -4550,6 +4598,15 @@
}
#if VM_NRESERVLEVEL > 0
+static bool
+pmap_pde_ept_executable(pmap_t pmap, pd_entry_t pde)
+{
+
+ if (pmap->pm_type != PT_EPT)
+ return (false);
+ return ((pde & EPT_PG_EXECUTE) != 0);
+}
+
/*
* Tries to promote the 512, contiguous 4KB page mappings that are within a
* single page table page (PTP) to a single 2MB page mapping. For promotion
@@ -4584,7 +4641,9 @@
firstpte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME);
setpde:
newpde = *firstpte;
- if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V)) {
+ if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V) ||
+ !pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
+ newpde))) {
atomic_add_long(&pmap_pde_p_failures, 1);
CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx"
" in pmap %p", va, pmap);
@@ -5010,6 +5069,12 @@
PG_V = pmap_valid_bit(pmap);
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ if (!pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
+ newpde))) {
+ CTR2(KTR_PMAP, "pmap_enter_pde: 2m x blocked for va %#lx"
+ " in pmap %p", va, pmap);
+ return (KERN_FAILURE);
+ }
if ((pdpg = pmap_allocpde(pmap, va, (flags & PMAP_ENTER_NOSLEEP) != 0 ?
NULL : lockp)) == NULL) {
CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx"
@@ -5139,6 +5204,7 @@
va = start + ptoa(diff);
if ((va & PDRMASK) == 0 && va + NBPDR <= end &&
m->psind == 1 && pmap_ps_enabled(pmap) &&
+ pmap_allow_2m_x_page(pmap, (prot & VM_PROT_EXECUTE) != 0) &&
pmap_enter_2mpage(pmap, va, m, prot, &lock))
m = &m[NBPDR / PAGE_SIZE - 1];
else
--- sys/amd64/include/pmap.h.orig
+++ sys/amd64/include/pmap.h
@@ -407,6 +407,7 @@
void pmap_activate_boot(pmap_t pmap);
void pmap_activate_sw(struct thread *);
+void pmap_allow_2m_x_ept_recalculate(void);
void pmap_bootstrap(vm_paddr_t *);
int pmap_cache_bits(pmap_t pmap, int mode, boolean_t is_pde);
int pmap_change_attr(vm_offset_t, vm_size_t, int);
--- sys/dev/cpuctl/cpuctl.c.orig
+++ sys/dev/cpuctl/cpuctl.c
@@ -48,6 +48,10 @@
#include <sys/pmckern.h>
#include <sys/cpuctl.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
#include <machine/cpufunc.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
@@ -535,6 +539,9 @@
hw_ibrs_recalculate();
restore_cpu(oldcpu, is_bound, td);
hw_ssb_recalculate(true);
+#ifdef __amd64__
+ pmap_allow_2m_x_ept_recalculate();
+#endif
hw_mds_recalculate();
printcpuinfo();
return (0);
--- sys/x86/include/specialreg.h.orig
+++ sys/x86/include/specialreg.h
@@ -406,6 +406,7 @@
#define IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY 0x00000008
#define IA32_ARCH_CAP_SSB_NO 0x00000010
#define IA32_ARCH_CAP_MDS_NO 0x00000020
+#define IA32_ARCH_CAP_IF_PSCHANGE_MC_NO 0x00000040
/*
* CPUID manufacturers identifiers

View file

@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAl3K+mJfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cJLsg/7BAKmJMh9yd59hixizqFtK2yCPybFOiYau1gsO9FyELIb0PG6Ofb+OnaT
72tiextc4NIOhsKqayi0+AaIM2nmJfX/AvzrjT/jn7kVvEK5VZuRcXloISvtqwhG
aIT6OuMdJcCEEorGC3lhK0jjvtakb/OxIqqYuQ45F99lh0I9EtZ0SCP/7d7thIkh
saXvSXTr93ShDXQPLb25nz5Q9/fGh6TZRLhrwiWi7E1leZlnk8sLMrJMh+7g/ZlQ
DwjS/E7JRQ+UJ4BSfqDeRppCVs6lT7tCKZbqiptO/KPSx/yoO/fxq+N0wzWB9+I0
fqoppNNzo8ulmqQ/kclIRxadBDALWB2R9cvQU99nkorkQJ8xvOJLgHBw5o38ZvKO
E93Fbv0okrO6Pa4FHQlHxVqjmr2ayDILHGN+bLsQL08k86FhpE2Z7YB8IWEtrsuh
2mHEgzn3IoUg0iPEHUNN5gjv8X8loUeHppLDvIibpVlKfsiqXS0OfbEly9EJz358
JEr2lc8+IXm2incrsGCZj+To49Gt/6voD6IsPrE01gpevhWmYXL/tXF/QLTPTVSE
LbAcyddsIXx8Nc++LIUvHiwyk3wNA+coz6wi0DXXluM8l/idwKIWWU8vnWTA0o/L
D6+G+92yyhp0bNq8okLe1W+UlBZvWJybwKpbetkq23KveqLOUmk=
=ru3c
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,155 @@
--- sys/amd64/amd64/pmap.c.orig
+++ sys/amd64/amd64/pmap.c
@@ -1309,6 +1309,51 @@
m->md.pat_mode = PAT_WRITE_BACK;
}
+static int pmap_allow_2m_x_ept;
+SYSCTL_INT(_vm_pmap, OID_AUTO, allow_2m_x_ept, CTLFLAG_RWTUN | CTLFLAG_NOFETCH,
+ &pmap_allow_2m_x_ept, 0,
+ "Allow executable superpage mappings in EPT");
+
+void
+pmap_allow_2m_x_ept_recalculate(void)
+{
+ /*
+ * SKL002, SKL012S. Since the EPT format is only used by
+ * Intel CPUs, the vendor check is merely a formality.
+ */
+ if (!(cpu_vendor_id != CPU_VENDOR_INTEL ||
+ (cpu_ia32_arch_caps & IA32_ARCH_CAP_IF_PSCHANGE_MC_NO) != 0 ||
+ (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ (CPUID_TO_MODEL(cpu_id) == 0x26 || /* Atoms */
+ CPUID_TO_MODEL(cpu_id) == 0x27 ||
+ CPUID_TO_MODEL(cpu_id) == 0x35 ||
+ CPUID_TO_MODEL(cpu_id) == 0x36 ||
+ CPUID_TO_MODEL(cpu_id) == 0x37 ||
+ CPUID_TO_MODEL(cpu_id) == 0x86 ||
+ CPUID_TO_MODEL(cpu_id) == 0x1c ||
+ CPUID_TO_MODEL(cpu_id) == 0x4a ||
+ CPUID_TO_MODEL(cpu_id) == 0x4c ||
+ CPUID_TO_MODEL(cpu_id) == 0x4d ||
+ CPUID_TO_MODEL(cpu_id) == 0x5a ||
+ CPUID_TO_MODEL(cpu_id) == 0x5c ||
+ CPUID_TO_MODEL(cpu_id) == 0x5d ||
+ CPUID_TO_MODEL(cpu_id) == 0x5f ||
+ CPUID_TO_MODEL(cpu_id) == 0x6e ||
+ CPUID_TO_MODEL(cpu_id) == 0x7a ||
+ CPUID_TO_MODEL(cpu_id) == 0x57 || /* Knights */
+ CPUID_TO_MODEL(cpu_id) == 0x85))))
+ pmap_allow_2m_x_ept = 1;
+ TUNABLE_INT_FETCH("hw.allow_2m_x_ept", &pmap_allow_2m_x_ept);
+}
+
+static bool
+pmap_allow_2m_x_page(pmap_t pmap, bool executable)
+{
+
+ return (pmap->pm_type != PT_EPT || !executable ||
+ !pmap_allow_2m_x_ept);
+}
+
/*
* Initialize the pmap module.
* Called by vm_init, to initialize any structures that the pmap
@@ -1353,6 +1398,9 @@
}
}
+ /* IFU */
+ pmap_allow_2m_x_ept_recalculate();
+
/*
* Initialize the vm page array entries for the kernel pmap's
* page table pages.
@@ -4823,6 +4871,15 @@
}
#if VM_NRESERVLEVEL > 0
+static bool
+pmap_pde_ept_executable(pmap_t pmap, pd_entry_t pde)
+{
+
+ if (pmap->pm_type != PT_EPT)
+ return (false);
+ return ((pde & EPT_PG_EXECUTE) != 0);
+}
+
/*
* Tries to promote the 512, contiguous 4KB page mappings that are within a
* single page table page (PTP) to a single 2MB page mapping. For promotion
@@ -4857,7 +4914,9 @@
firstpte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME);
setpde:
newpde = *firstpte;
- if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V)) {
+ if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V) ||
+ !pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
+ newpde))) {
atomic_add_long(&pmap_pde_p_failures, 1);
CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx"
" in pmap %p", va, pmap);
@@ -5283,6 +5342,12 @@
PG_V = pmap_valid_bit(pmap);
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ if (!pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
+ newpde))) {
+ CTR2(KTR_PMAP, "pmap_enter_pde: 2m x blocked for va %#lx"
+ " in pmap %p", va, pmap);
+ return (KERN_FAILURE);
+ }
if ((pdpg = pmap_allocpde(pmap, va, (flags & PMAP_ENTER_NOSLEEP) != 0 ?
NULL : lockp)) == NULL) {
CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx"
@@ -5412,6 +5477,7 @@
va = start + ptoa(diff);
if ((va & PDRMASK) == 0 && va + NBPDR <= end &&
m->psind == 1 && pmap_ps_enabled(pmap) &&
+ pmap_allow_2m_x_page(pmap, (prot & VM_PROT_EXECUTE) != 0) &&
pmap_enter_2mpage(pmap, va, m, prot, &lock))
m = &m[NBPDR / PAGE_SIZE - 1];
else
--- sys/amd64/include/pmap.h.orig
+++ sys/amd64/include/pmap.h
@@ -413,6 +413,7 @@
void pmap_activate_boot(pmap_t pmap);
void pmap_activate_sw(struct thread *);
+void pmap_allow_2m_x_ept_recalculate(void);
void pmap_bootstrap(vm_paddr_t *);
int pmap_cache_bits(pmap_t pmap, int mode, boolean_t is_pde);
int pmap_change_attr(vm_offset_t, vm_size_t, int);
--- sys/dev/cpuctl/cpuctl.c.orig
+++ sys/dev/cpuctl/cpuctl.c
@@ -50,6 +50,10 @@
#include <sys/pmckern.h>
#include <sys/cpuctl.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
#include <machine/cpufunc.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
@@ -521,6 +525,9 @@
hw_ibrs_recalculate();
restore_cpu(oldcpu, is_bound, td);
hw_ssb_recalculate(true);
+#ifdef __amd64__
+ pmap_allow_2m_x_ept_recalculate();
+#endif
hw_mds_recalculate();
printcpuinfo();
return (0);
--- sys/x86/include/specialreg.h.orig
+++ sys/x86/include/specialreg.h
@@ -439,6 +439,7 @@
#define IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY 0x00000008
#define IA32_ARCH_CAP_SSB_NO 0x00000010
#define IA32_ARCH_CAP_MDS_NO 0x00000020
+#define IA32_ARCH_CAP_IF_PSCHANGE_MC_NO 0x00000040
/*
* CPUID manufacturers identifiers

View file

@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAl3K+mZfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cIg8Q//U0cJ4V5bX7tw3IPDS/FHXUXSjCgdQt4pTQoCQ3eNRp3+LNvl4VQDac0N
wUf3FLoeicFKKrysYVf3uEOElk0IfpFb2hqhs1Sp2BhcMlo3YydoQMyDFwZTCh32
vKV+iSD3mvQKCbIdaD1iErNuoxDogPG89ViPiSvQLPFtfY9UBl6CbQuAJooiqHk9
P8ESHnoACsnYkxve5asP6Qxckf/YBbP/4EIZjMHPnb3l1QB/5aMkpEr1BL4Q+02Y
VlRKPZLXXzWQSDBNe9WWEpod/3uHAFMZ036+gQgTkoJIl68ulZd2wQA4F7ZMar2t
Jj+ik1PD7ciQxzszi6lrbHGmbfAKMht+SVQO8VTfKGIzIS0i54RJVVMFRG5O0Qth
SqY+e0LjlfmzYjpgIQPi4pxKqIqshA/Fa5aXiEVEpIsi6/JJwSz+NonPtY1EC+Xl
wXGIvqEBByWvrg/XCUDu5e1W+qstHHjbWZL3z1eaRXj52S4ZyjJBmTGsVW6Zga3y
q1Yp1S60fRrGiD9I1ksIVuE2PTlAVeu311B86OGFVFyhpa51TJsZ8CEPZEd0fYfu
pS80U69ePvjHf+lctiQsRw+DgLm6u+TtviZDoKwFp/r3KWIEbcY+oLMf/maCb/8Y
SnI32ivm75JNe4VrGn8Xshb18GqAMa1OJSI00x6E21teBng/CIw=
=CTY6
-----END PGP SIGNATURE-----

View file

@ -0,0 +1,153 @@
--- sys/amd64/amd64/pmap.c.orig
+++ sys/amd64/amd64/pmap.c
@@ -1805,6 +1805,51 @@
m->md.pat_mode = PAT_WRITE_BACK;
}
+static int pmap_allow_2m_x_ept;
+SYSCTL_INT(_vm_pmap, OID_AUTO, allow_2m_x_ept, CTLFLAG_RWTUN | CTLFLAG_NOFETCH,
+ &pmap_allow_2m_x_ept, 0,
+ "Allow executable superpage mappings in EPT");
+
+void
+pmap_allow_2m_x_ept_recalculate(void)
+{
+ /*
+ * SKL002, SKL012S. Since the EPT format is only used by
+ * Intel CPUs, the vendor check is merely a formality.
+ */
+ if (!(cpu_vendor_id != CPU_VENDOR_INTEL ||
+ (cpu_ia32_arch_caps & IA32_ARCH_CAP_IF_PSCHANGE_MC_NO) != 0 ||
+ (CPUID_TO_FAMILY(cpu_id) == 0x6 &&
+ (CPUID_TO_MODEL(cpu_id) == 0x26 || /* Atoms */
+ CPUID_TO_MODEL(cpu_id) == 0x27 ||
+ CPUID_TO_MODEL(cpu_id) == 0x35 ||
+ CPUID_TO_MODEL(cpu_id) == 0x36 ||
+ CPUID_TO_MODEL(cpu_id) == 0x37 ||
+ CPUID_TO_MODEL(cpu_id) == 0x86 ||
+ CPUID_TO_MODEL(cpu_id) == 0x1c ||
+ CPUID_TO_MODEL(cpu_id) == 0x4a ||
+ CPUID_TO_MODEL(cpu_id) == 0x4c ||
+ CPUID_TO_MODEL(cpu_id) == 0x4d ||
+ CPUID_TO_MODEL(cpu_id) == 0x5a ||
+ CPUID_TO_MODEL(cpu_id) == 0x5c ||
+ CPUID_TO_MODEL(cpu_id) == 0x5d ||
+ CPUID_TO_MODEL(cpu_id) == 0x5f ||
+ CPUID_TO_MODEL(cpu_id) == 0x6e ||
+ CPUID_TO_MODEL(cpu_id) == 0x7a ||
+ CPUID_TO_MODEL(cpu_id) == 0x57 || /* Knights */
+ CPUID_TO_MODEL(cpu_id) == 0x85))))
+ pmap_allow_2m_x_ept = 1;
+ TUNABLE_INT_FETCH("hw.allow_2m_x_ept", &pmap_allow_2m_x_ept);
+}
+
+static bool
+pmap_allow_2m_x_page(pmap_t pmap, bool executable)
+{
+
+ return (pmap->pm_type != PT_EPT || !executable ||
+ !pmap_allow_2m_x_ept);
+}
+
/*
* Initialize the pmap module.
* Called by vm_init, to initialize any structures that the pmap
@@ -1849,6 +1894,9 @@
}
}
+ /* IFU */
+ pmap_allow_2m_x_ept_recalculate();
+
/*
* Initialize the vm page array entries for the kernel pmap's
* page table pages.
@@ -5452,6 +5500,15 @@
}
#if VM_NRESERVLEVEL > 0
+static bool
+pmap_pde_ept_executable(pmap_t pmap, pd_entry_t pde)
+{
+
+ if (pmap->pm_type != PT_EPT)
+ return (false);
+ return ((pde & EPT_PG_EXECUTE) != 0);
+}
+
/*
* Tries to promote the 512, contiguous 4KB page mappings that are within a
* single page table page (PTP) to a single 2MB page mapping. For promotion
@@ -5487,7 +5544,9 @@
firstpte = (pt_entry_t *)PHYS_TO_DMAP(*pde & PG_FRAME);
setpde:
newpde = *firstpte;
- if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V)) {
+ if ((newpde & ((PG_FRAME & PDRMASK) | PG_A | PG_V)) != (PG_A | PG_V) ||
+ !pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
+ newpde))) {
atomic_add_long(&pmap_pde_p_failures, 1);
CTR2(KTR_PMAP, "pmap_promote_pde: failure for va %#lx"
" in pmap %p", va, pmap);
@@ -5917,6 +5976,12 @@
PG_V = pmap_valid_bit(pmap);
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
+ if (!pmap_allow_2m_x_page(pmap, pmap_pde_ept_executable(pmap,
+ newpde))) {
+ CTR2(KTR_PMAP, "pmap_enter_pde: 2m x blocked for va %#lx"
+ " in pmap %p", va, pmap);
+ return (KERN_FAILURE);
+ }
if ((pdpg = pmap_allocpde(pmap, va, (flags & PMAP_ENTER_NOSLEEP) != 0 ?
NULL : lockp)) == NULL) {
CTR2(KTR_PMAP, "pmap_enter_pde: failure for va %#lx"
@@ -6063,6 +6128,7 @@
va = start + ptoa(diff);
if ((va & PDRMASK) == 0 && va + NBPDR <= end &&
m->psind == 1 && pmap_ps_enabled(pmap) &&
+ pmap_allow_2m_x_page(pmap, (prot & VM_PROT_EXECUTE) != 0) &&
pmap_enter_2mpage(pmap, va, m, prot, &lock))
m = &m[NBPDR / PAGE_SIZE - 1];
else
--- sys/amd64/include/pmap.h.orig
+++ sys/amd64/include/pmap.h
@@ -424,6 +424,7 @@
void pmap_activate_boot(pmap_t pmap);
void pmap_activate_sw(struct thread *);
+void pmap_allow_2m_x_ept_recalculate(void);
void pmap_bootstrap(vm_paddr_t *);
int pmap_cache_bits(pmap_t pmap, int mode, boolean_t is_pde);
int pmap_change_attr(vm_offset_t, vm_size_t, int);
--- sys/dev/cpuctl/cpuctl.c.orig
+++ sys/dev/cpuctl/cpuctl.c
@@ -50,6 +50,10 @@
#include <sys/pmckern.h>
#include <sys/cpuctl.h>
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
+
#include <machine/cpufunc.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
@@ -539,6 +543,7 @@
hw_ssb_recalculate(true);
#ifdef __amd64__
amd64_syscall_ret_flush_l1d_recalc();
+ pmap_allow_2m_x_ept_recalculate();
#endif
hw_mds_recalculate();
printcpuinfo();
--- sys/x86/include/specialreg.h.orig
+++ sys/x86/include/specialreg.h
@@ -447,6 +447,7 @@
#define IA32_ARCH_CAP_SKIP_L1DFL_VMENTRY 0x00000008
#define IA32_ARCH_CAP_SSB_NO 0x00000010
#define IA32_ARCH_CAP_MDS_NO 0x00000020
+#define IA32_ARCH_CAP_IF_PSCHANGE_MC_NO 0x00000040
/*
* CPUID manufacturers identifiers

View file

@ -0,0 +1,18 @@
-----BEGIN PGP SIGNATURE-----
iQKTBAABCgB9FiEE/A6HiuWv54gCjWNV05eS9J6n5cIFAl3K+mxfFIAAAAAALgAo
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldEZD
MEU4NzhBRTVBRkU3ODgwMjhENjM1NUQzOTc5MkY0OUVBN0U1QzIACgkQ05eS9J6n
5cKPwA/+LlSVXDK44aW1dsb9xkoOuyQZXQ+YYi1yhprodMflUhUz+Kno9qK9FL9t
BPeYonV5K9I7Pknjvgd6XpEEPAzPHwuLxH7AQ0y6TT5nAsRc3CxfnhmoII/JKGtx
ufKoiZAmpaPHQv8s+5CAof+f/CbCByzGOlfLHXIidp+3ULxPZ/r4hIRs8HiW+Jgb
kadbMdUtAdwV4gJR1PAFgBOoASLZJbShnvVewa8G3QP9kI2u5kz0Ed7AT6WvY2uT
gTltGuEE2PWjzeWya1ip4k2PidMJwA5Gw8SpajWV/jERsx9E75oEAM3ZQCETAdfR
Y4vCtADnDeczFHfCBKLnrW1gXaejGXG+2uzDwsBooz079ubLWog9Yy7mer9mf47Q
xk28xEDIi+BHjAuALaRdUvPtp4O/jvxQPAtHbxFAToe5OMAH761c2lAN2xOHN2w0
79mMlih9sIGbdKTRDtYqe3U8fOLmoG63KUagYBw1uXoLqmwXnoWVQCeU58CI8Is1
NQBSHErnSbSpr74JThIwFqHt2/b6PpQHXwJuQZlH6XCXSrPLXOZxjBIxzwDfVwW3
62voo7nATyhTWEwZyJrswxjbsgsYDKY0iMZcO3VMi3hY5haX9EGdISRibzdlyAsj
lbcSjApmHRgn55krzJNcG0Vg+u5GQaXw89u3LecY3Td2clgfLZQ=
=rfju
-----END PGP SIGNATURE-----