Introduce a new svs_page_add function, which can be used to map in the user

space a VA from the kernel space.

Use it to replace the PDIR_SLOT_PCPU slot: at boot time each CPU creates
its own slot which maps only its own pcpu_entry plus the common area (IDT+
LDT).

This way, the pcpu areas of the remote CPUs are not mapped in userland.
This commit is contained in:
maxv 2018-01-11 13:35:15 +00:00
parent 096556c986
commit 6f93fcf6fc
2 changed files with 83 additions and 9 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: machdep.c,v 1.288 2018/01/11 10:38:13 maxv Exp $ */
/* $NetBSD: machdep.c,v 1.289 2018/01/11 13:35:15 maxv Exp $ */
/*
* Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@ -110,7 +110,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.288 2018/01/11 10:38:13 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.289 2018/01/11 13:35:15 maxv Exp $");
/* #define XENDEBUG_LOW */
@ -2264,9 +2264,76 @@ mm_md_direct_mapped_phys(paddr_t paddr, vaddr_t *vaddr)
* TODO: for now, only PMAP_SLOT_PTE is unmapped.
*/
static void
svs_page_add(struct cpu_info *ci, vaddr_t va)
{
extern pd_entry_t * const normal_pdes[];
extern const vaddr_t ptp_masks[];
extern const int ptp_shifts[];
extern const long nbpd[];
pd_entry_t *srcpde, *dstpde;
size_t i, idx, pidx, mod;
struct vm_page *pg;
paddr_t pa;
KASSERT(va % PAGE_SIZE == 0);
dstpde = ci->ci_svs_updir;
mod = (size_t)-1;
for (i = PTP_LEVELS; i > 1; i--) {
idx = pl_i(va, i);
srcpde = normal_pdes[i - 2];
if (!pmap_valid_entry(srcpde[idx])) {
panic("%s: page not mapped", __func__);
}
pidx = pl_i(va % mod, i);
if (!pmap_valid_entry(dstpde[pidx])) {
pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_ZERO);
if (pg == 0)
panic("%s: failed to allocate PA for CPU %d\n",
__func__, cpu_index(ci));
pa = VM_PAGE_TO_PHYS(pg);
dstpde[pidx] = PG_V | PG_RW | pa;
}
pa = (paddr_t)(dstpde[pidx] & PG_FRAME);
dstpde = (pd_entry_t *)PMAP_DIRECT_MAP(pa);
mod = nbpd[i-1];
}
/* Do the last level manually */
idx = pl_i(va, 1);
srcpde = L1_BASE;
if (!pmap_valid_entry(srcpde[idx])) {
panic("%s: L1 page not mapped", __func__);
}
pidx = pl_i(va % mod, 1);
if (pmap_valid_entry(dstpde[pidx])) {
panic("%s: L1 page already mapped", __func__);
}
dstpde[pidx] = srcpde[idx];
}
static void
svs_range_add(struct cpu_info *ci, vaddr_t va, size_t size)
{
size_t i, n;
KASSERT(size % PAGE_SIZE == 0);
n = size / PAGE_SIZE;
for (i = 0; i < n; i++) {
svs_page_add(ci, va + i * PAGE_SIZE);
}
}
void
cpu_svs_init(struct cpu_info *ci)
{
const cpuid_t cid = cpu_index(ci);
struct vm_page *pg;
KASSERT(ci != NULL);
@ -2291,6 +2358,11 @@ cpu_svs_init(struct cpu_info *ci)
ci->ci_svs_kpdirpa = pmap_pdirpa(pmap_kernel(), 0);
mutex_init(&ci->ci_svs_mtx, MUTEX_DEFAULT, IPL_VM);
svs_page_add(ci, (vaddr_t)&pcpuarea->idt);
svs_page_add(ci, (vaddr_t)&pcpuarea->ldt);
svs_range_add(ci, (vaddr_t)&pcpuarea->ent[cid],
sizeof(struct pcpu_entry));
}
void
@ -2364,7 +2436,9 @@ svs_pdir_switch(struct pmap *pmap)
* This is where we decide what to unmap from the user page
* tables.
*/
if (pmap_direct_pdpe <= i &&
if (i == PDIR_SLOT_PCPU) {
/* keep the one created at boot time */
} else if (pmap_direct_pdpe <= i &&
i < pmap_direct_pdpe + pmap_direct_npdp) {
ci->ci_svs_updir[i] = 0;
} else if (i == PDIR_SLOT_PTE) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.c,v 1.145 2018/01/11 09:18:16 msaitoh Exp $ */
/* $NetBSD: cpu.c,v 1.146 2018/01/11 13:35:15 maxv Exp $ */
/*
* Copyright (c) 2000-2012 NetBSD Foundation, Inc.
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.145 2018/01/11 09:18:16 msaitoh Exp $");
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.146 2018/01/11 13:35:15 maxv Exp $");
#include "opt_ddb.h"
#include "opt_mpbios.h" /* for MPDEBUG */
@ -380,10 +380,6 @@ cpu_attach(device_t parent, device_t self, void *aux)
/* Must be before mi_cpu_attach(). */
cpu_vm_init(ci);
#ifdef SVS
cpu_svs_init(ci);
#endif
if (caa->cpu_role == CPU_ROLE_AP) {
int error;
@ -401,6 +397,10 @@ cpu_attach(device_t parent, device_t self, void *aux)
KASSERT(ci->ci_data.cpu_idlelwp != NULL);
}
#ifdef SVS
cpu_svs_init(ci);
#endif
pmap_reference(pmap_kernel());
ci->ci_pmap = pmap_kernel();
ci->ci_tlbstate = TLBSTATE_STALE;