kernel/vm: change pde table info from single buffer to explicit per-process.
makes code in kernel more readable, and allows better sanity checking on using the pde info.
This commit is contained in:
parent
23204787d5
commit
c5c25e7abc
11 changed files with 75 additions and 34 deletions
|
@ -25,6 +25,7 @@ struct segdesc_s { /* segment descriptor for protected mode */
|
||||||
typedef struct segframe {
|
typedef struct segframe {
|
||||||
reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */
|
reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */
|
||||||
reg_t p_cr3; /* page table root */
|
reg_t p_cr3; /* page table root */
|
||||||
|
u32_t *p_cr3_v;
|
||||||
struct segdesc_s p_ldt[LDT_SIZE]; /* CS, DS and remote */
|
struct segdesc_s p_ldt[LDT_SIZE]; /* CS, DS and remote */
|
||||||
} segframe_t;
|
} segframe_t;
|
||||||
|
|
||||||
|
|
|
@ -601,6 +601,8 @@
|
||||||
#define SVMCTL_MRG_ADDR2 m2_l2 /* MEMREQ_GET reply: source address */
|
#define SVMCTL_MRG_ADDR2 m2_l2 /* MEMREQ_GET reply: source address */
|
||||||
#define SVMCTL_MRG_REQUESTOR m2_p1 /* MEMREQ_GET reply: requestor */
|
#define SVMCTL_MRG_REQUESTOR m2_p1 /* MEMREQ_GET reply: requestor */
|
||||||
#define SVMCTL_MAP_VIR_ADDR m1_p1
|
#define SVMCTL_MAP_VIR_ADDR m1_p1
|
||||||
|
#define SVMCTL_PTROOT m1_i3
|
||||||
|
#define SVMCTL_PTROOT_V m1_p1
|
||||||
|
|
||||||
/* Reply message for VMCTL_KERN_PHYSMAP */
|
/* Reply message for VMCTL_KERN_PHYSMAP */
|
||||||
#define SVMCTL_MAP_FLAGS m2_i1 /* VMMF_* */
|
#define SVMCTL_MAP_FLAGS m2_i1 /* VMMF_* */
|
||||||
|
@ -610,7 +612,6 @@
|
||||||
#define VMMF_UNCACHED (1L << 0)
|
#define VMMF_UNCACHED (1L << 0)
|
||||||
|
|
||||||
/* Values for SVMCTL_PARAM. */
|
/* Values for SVMCTL_PARAM. */
|
||||||
#define VMCTL_I386_SETCR3 10
|
|
||||||
#define VMCTL_CLEAR_PAGEFAULT 12
|
#define VMCTL_CLEAR_PAGEFAULT 12
|
||||||
#define VMCTL_I386_GETCR3 13
|
#define VMCTL_I386_GETCR3 13
|
||||||
#define VMCTL_MEMREQ_GET 14
|
#define VMCTL_MEMREQ_GET 14
|
||||||
|
@ -618,13 +619,13 @@
|
||||||
#define VMCTL_INCSP 16
|
#define VMCTL_INCSP 16
|
||||||
#define VMCTL_NOPAGEZERO 18
|
#define VMCTL_NOPAGEZERO 18
|
||||||
#define VMCTL_I386_KERNELLIMIT 19
|
#define VMCTL_I386_KERNELLIMIT 19
|
||||||
#define VMCTL_I386_PAGEDIRS 20
|
|
||||||
#define VMCTL_I386_FREEPDE 23
|
#define VMCTL_I386_FREEPDE 23
|
||||||
#define VMCTL_ENABLE_PAGING 24
|
#define VMCTL_ENABLE_PAGING 24
|
||||||
#define VMCTL_I386_INVLPG 25
|
#define VMCTL_I386_INVLPG 25
|
||||||
#define VMCTL_FLUSHTLB 26
|
#define VMCTL_FLUSHTLB 26
|
||||||
#define VMCTL_KERN_PHYSMAP 27
|
#define VMCTL_KERN_PHYSMAP 27
|
||||||
#define VMCTL_KERN_MAP_REPLY 28
|
#define VMCTL_KERN_MAP_REPLY 28
|
||||||
|
#define VMCTL_SETADDRSPACE 29
|
||||||
|
|
||||||
/* Codes and field names for SYS_SYSCTL. */
|
/* Codes and field names for SYS_SYSCTL. */
|
||||||
#define SYSCTL_CODE m1_i1 /* SYSCTL_CODE_* below */
|
#define SYSCTL_CODE m1_i1 /* SYSCTL_CODE_* below */
|
||||||
|
|
|
@ -79,6 +79,9 @@ _PROTOTYPE( int sys_sysctl_stacktrace, (endpoint_t who));
|
||||||
_PROTOTYPE( int sys_vmctl_get_mapping, (int index, phys_bytes *addr,
|
_PROTOTYPE( int sys_vmctl_get_mapping, (int index, phys_bytes *addr,
|
||||||
phys_bytes *len, int *flags));
|
phys_bytes *len, int *flags));
|
||||||
_PROTOTYPE( int sys_vmctl_reply_mapping, (int index, vir_bytes addr));
|
_PROTOTYPE( int sys_vmctl_reply_mapping, (int index, vir_bytes addr));
|
||||||
|
_PROTOTYPE( int sys_vmctl_set_addrspace, (endpoint_t who,
|
||||||
|
phys_bytes ptroot, void *ptroot_v));
|
||||||
|
|
||||||
|
|
||||||
/* Shorthands for sys_sdevio() system call. */
|
/* Shorthands for sys_sdevio() system call. */
|
||||||
#define sys_insb(port, proc_ep, buffer, count) \
|
#define sys_insb(port, proc_ep, buffer, count) \
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
|
|
||||||
#include "proto.h"
|
#include "proto.h"
|
||||||
|
|
||||||
extern u8_t *vm_pagedirs;
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* arch_do_vmctl *
|
* arch_do_vmctl *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -26,13 +24,15 @@ struct proc *p;
|
||||||
/* Get process CR3. */
|
/* Get process CR3. */
|
||||||
m_ptr->SVMCTL_VALUE = p->p_seg.p_cr3;
|
m_ptr->SVMCTL_VALUE = p->p_seg.p_cr3;
|
||||||
return OK;
|
return OK;
|
||||||
case VMCTL_I386_SETCR3:
|
case VMCTL_SETADDRSPACE:
|
||||||
/* Set process CR3. */
|
/* Set process CR3. */
|
||||||
if(m_ptr->SVMCTL_VALUE) {
|
if(m_ptr->SVMCTL_PTROOT) {
|
||||||
p->p_seg.p_cr3 = m_ptr->SVMCTL_VALUE;
|
p->p_seg.p_cr3 = m_ptr->SVMCTL_PTROOT;
|
||||||
|
p->p_seg.p_cr3_v = (u32_t *) m_ptr->SVMCTL_PTROOT_V;
|
||||||
p->p_misc_flags |= MF_FULLVM;
|
p->p_misc_flags |= MF_FULLVM;
|
||||||
} else {
|
} else {
|
||||||
p->p_seg.p_cr3 = 0;
|
p->p_seg.p_cr3 = 0;
|
||||||
|
p->p_seg.p_cr3_v = NULL;
|
||||||
p->p_misc_flags &= ~MF_FULLVM;
|
p->p_misc_flags &= ~MF_FULLVM;
|
||||||
}
|
}
|
||||||
RTS_UNSET(p, RTS_VMINHIBIT);
|
RTS_UNSET(p, RTS_VMINHIBIT);
|
||||||
|
@ -48,11 +48,6 @@ struct proc *p;
|
||||||
r = prot_set_kern_seg_limit(m_ptr->SVMCTL_VALUE);
|
r = prot_set_kern_seg_limit(m_ptr->SVMCTL_VALUE);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
case VMCTL_I386_PAGEDIRS:
|
|
||||||
{
|
|
||||||
vm_pagedirs = (u8_t *) m_ptr->SVMCTL_VALUE;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
case VMCTL_I386_FREEPDE:
|
case VMCTL_I386_FREEPDE:
|
||||||
{
|
{
|
||||||
i386_freepde(m_ptr->SVMCTL_VALUE);
|
i386_freepde(m_ptr->SVMCTL_VALUE);
|
||||||
|
|
|
@ -28,12 +28,6 @@
|
||||||
|
|
||||||
PRIVATE int psok = 0;
|
PRIVATE int psok = 0;
|
||||||
|
|
||||||
#define PROCPDEPTR(pr, pi) ((u32_t *) ((u8_t *) vm_pagedirs +\
|
|
||||||
I386_PAGE_SIZE * pr->p_nr + \
|
|
||||||
I386_VM_PT_ENT_SIZE * pi))
|
|
||||||
|
|
||||||
PUBLIC u8_t *vm_pagedirs = NULL;
|
|
||||||
|
|
||||||
#define MAX_FREEPDES (3 * CONFIG_MAX_CPUS)
|
#define MAX_FREEPDES (3 * CONFIG_MAX_CPUS)
|
||||||
PRIVATE int nfreepdes = 0, freepdes[MAX_FREEPDES];
|
PRIVATE int nfreepdes = 0, freepdes[MAX_FREEPDES];
|
||||||
|
|
||||||
|
@ -90,6 +84,7 @@ PRIVATE phys_bytes createpde(
|
||||||
|
|
||||||
assert(free_pde_idx >= 0 && free_pde_idx < nfreepdes);
|
assert(free_pde_idx >= 0 && free_pde_idx < nfreepdes);
|
||||||
pde = freepdes[free_pde_idx];
|
pde = freepdes[free_pde_idx];
|
||||||
|
assert(pde >= 0 && pde < 1024);
|
||||||
|
|
||||||
if(pr && ((pr == ptproc) || !HASPT(pr))) {
|
if(pr && ((pr == ptproc) || !HASPT(pr))) {
|
||||||
/* Process memory is requested, and
|
/* Process memory is requested, and
|
||||||
|
@ -106,7 +101,8 @@ PRIVATE phys_bytes createpde(
|
||||||
* accessible directly. Grab the PDE entry of that process'
|
* accessible directly. Grab the PDE entry of that process'
|
||||||
* page table that corresponds to the requested address.
|
* page table that corresponds to the requested address.
|
||||||
*/
|
*/
|
||||||
pdeval = *PROCPDEPTR(pr, I386_VM_PDE(linaddr));
|
assert(pr->p_seg.p_cr3_v);
|
||||||
|
pdeval = pr->p_seg.p_cr3_v[I386_VM_PDE(linaddr)];
|
||||||
} else {
|
} else {
|
||||||
/* Requested address is physical. Make up the PDE entry. */
|
/* Requested address is physical. Make up the PDE entry. */
|
||||||
pdeval = (linaddr & I386_VM_ADDR_MASK_4MB) |
|
pdeval = (linaddr & I386_VM_ADDR_MASK_4MB) |
|
||||||
|
@ -118,8 +114,9 @@ PRIVATE phys_bytes createpde(
|
||||||
* can access, into the currently loaded page table so it becomes
|
* can access, into the currently loaded page table so it becomes
|
||||||
* visible.
|
* visible.
|
||||||
*/
|
*/
|
||||||
if(*PROCPDEPTR(ptproc, pde) != pdeval) {
|
assert(ptproc->p_seg.p_cr3_v);
|
||||||
*PROCPDEPTR(ptproc, pde) = pdeval;
|
if(ptproc->p_seg.p_cr3_v[pde] != pdeval) {
|
||||||
|
ptproc->p_seg.p_cr3_v[pde] = pdeval;
|
||||||
*changed = 1;
|
*changed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +152,11 @@ PRIVATE int lin_lin_copy(const struct proc *srcproc, vir_bytes srclinaddr,
|
||||||
|
|
||||||
assert(procslot >= 0 && procslot < I386_VM_DIR_ENTRIES);
|
assert(procslot >= 0 && procslot < I386_VM_DIR_ENTRIES);
|
||||||
|
|
||||||
|
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE));
|
||||||
|
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE));
|
||||||
|
assert(!RTS_ISSET(ptproc, RTS_SLOT_FREE));
|
||||||
|
assert(ptproc->p_seg.p_cr3_v);
|
||||||
|
|
||||||
while(bytes > 0) {
|
while(bytes > 0) {
|
||||||
phys_bytes srcptr, dstptr;
|
phys_bytes srcptr, dstptr;
|
||||||
vir_bytes chunk = bytes;
|
vir_bytes chunk = bytes;
|
||||||
|
@ -191,6 +193,11 @@ PRIVATE int lin_lin_copy(const struct proc *srcproc, vir_bytes srclinaddr,
|
||||||
dstlinaddr += chunk;
|
dstlinaddr += chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(srcproc) assert(!RTS_ISSET(srcproc, RTS_SLOT_FREE));
|
||||||
|
if(dstproc) assert(!RTS_ISSET(dstproc, RTS_SLOT_FREE));
|
||||||
|
assert(!RTS_ISSET(ptproc, RTS_SLOT_FREE));
|
||||||
|
assert(ptproc->p_seg.p_cr3_v);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,6 +684,8 @@ int vm_phys_memset(phys_bytes ph, const u8_t c, phys_bytes bytes)
|
||||||
|
|
||||||
assert(nfreepdes >= 3);
|
assert(nfreepdes >= 3);
|
||||||
|
|
||||||
|
assert(ptproc->p_seg.p_cr3_v);
|
||||||
|
|
||||||
/* With VM, we have to map in the physical memory.
|
/* With VM, we have to map in the physical memory.
|
||||||
* We can do this 4MB at a time.
|
* We can do this 4MB at a time.
|
||||||
*/
|
*/
|
||||||
|
@ -695,6 +704,7 @@ int vm_phys_memset(phys_bytes ph, const u8_t c, phys_bytes bytes)
|
||||||
ph += chunk;
|
ph += chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(ptproc->p_seg.p_cr3_v);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -1004,3 +1014,8 @@ PUBLIC int arch_enable_paging(struct proc * caller, const message * m_ptr)
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUBLIC void release_address_space(struct proc *pr)
|
||||||
|
{
|
||||||
|
pr->p_seg.p_cr3_v = NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
FP_SAVE_AREA_P = P_STACKTOP
|
FP_SAVE_AREA_P = P_STACKTOP
|
||||||
P_LDT_SEL = FP_SAVE_AREA_P + 532
|
P_LDT_SEL = FP_SAVE_AREA_P + 532
|
||||||
P_CR3 = P_LDT_SEL+W
|
P_CR3 = P_LDT_SEL+W
|
||||||
P_LDT = P_CR3+W
|
P_CR3_V = P_CR3+4
|
||||||
|
P_LDT = P_CR3_V+W
|
||||||
P_MISC_FLAGS = P_LDT + 50
|
P_MISC_FLAGS = P_LDT + 50
|
||||||
Msize = 9 /* size of a message in 32-bit words*/
|
Msize = 9 /* size of a message in 32-bit words*/
|
||||||
|
|
||||||
|
|
|
@ -182,4 +182,5 @@ _PROTOTYPE( int copy_msg_from_user, (struct proc * p, message * user_mbuf,
|
||||||
_PROTOTYPE( int copy_msg_to_user, (struct proc * p, message * src,
|
_PROTOTYPE( int copy_msg_to_user, (struct proc * p, message * src,
|
||||||
message * user_mbuf));
|
message * user_mbuf));
|
||||||
_PROTOTYPE(void switch_address_space, (struct proc * p));
|
_PROTOTYPE(void switch_address_space, (struct proc * p));
|
||||||
|
_PROTOTYPE(void release_address_space, (struct proc *pr));
|
||||||
#endif /* PROTO_H */
|
#endif /* PROTO_H */
|
||||||
|
|
|
@ -31,6 +31,8 @@ PUBLIC int do_clear(struct proc * caller, message * m_ptr)
|
||||||
}
|
}
|
||||||
rc = proc_addr(exit_p); /* clean up */
|
rc = proc_addr(exit_p); /* clean up */
|
||||||
|
|
||||||
|
release_address_space(rc);
|
||||||
|
|
||||||
/* Don't clear if already cleared. */
|
/* Don't clear if already cleared. */
|
||||||
if(isemptyp(rc)) return OK;
|
if(isemptyp(rc)) return OK;
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,9 @@ PUBLIC int do_fork(struct proc * caller, message * m_ptr)
|
||||||
RTS_UNSET(rpc, (RTS_SIGNALED | RTS_SIG_PENDING | RTS_P_STOP));
|
RTS_UNSET(rpc, (RTS_SIGNALED | RTS_SIG_PENDING | RTS_P_STOP));
|
||||||
sigemptyset(&rpc->p_pending);
|
sigemptyset(&rpc->p_pending);
|
||||||
|
|
||||||
|
rpc->p_seg.p_cr3 = 0;
|
||||||
|
rpc->p_seg.p_cr3_v = NULL;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,21 @@ PUBLIC int sys_vmctl_get_cr3_i386(endpoint_t who, u32_t *cr3)
|
||||||
return(r);
|
return(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUBLIC int sys_vmctl_set_addrspace(endpoint_t who,
|
||||||
|
phys_bytes ptroot, void *ptroot_v)
|
||||||
|
{
|
||||||
|
message m;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
m.SVMCTL_WHO = who;
|
||||||
|
m.SVMCTL_PARAM = VMCTL_SETADDRSPACE;
|
||||||
|
m.SVMCTL_PTROOT = ptroot;
|
||||||
|
m.SVMCTL_PTROOT_V = ptroot_v;
|
||||||
|
r = _kernel_call(SYS_VMCTL, &m);
|
||||||
|
|
||||||
|
return(r);
|
||||||
|
}
|
||||||
|
|
||||||
PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem,
|
PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem,
|
||||||
vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s,
|
vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s,
|
||||||
endpoint_t *requestor)
|
endpoint_t *requestor)
|
||||||
|
|
|
@ -717,7 +717,7 @@ PUBLIC void pt_init(phys_bytes usedlimit)
|
||||||
*/
|
*/
|
||||||
pt_t *newpt;
|
pt_t *newpt;
|
||||||
int s, r;
|
int s, r;
|
||||||
vir_bytes v, kpagedir;
|
vir_bytes v;
|
||||||
phys_bytes lo, hi;
|
phys_bytes lo, hi;
|
||||||
vir_bytes extra_clicks;
|
vir_bytes extra_clicks;
|
||||||
u32_t moveup = 0;
|
u32_t moveup = 0;
|
||||||
|
@ -886,14 +886,6 @@ PUBLIC void pt_init(phys_bytes usedlimit)
|
||||||
/* first pde in use by process. */
|
/* first pde in use by process. */
|
||||||
proc_pde = free_pde;
|
proc_pde = free_pde;
|
||||||
|
|
||||||
kpagedir = arch_map2vir(&vmproc[VMP_SYSTEM],
|
|
||||||
pagedir_pde*I386_BIG_PAGE_SIZE);
|
|
||||||
|
|
||||||
/* Tell kernel how to get at the page directories. */
|
|
||||||
if((r=sys_vmctl(SELF, VMCTL_I386_PAGEDIRS, kpagedir)) != OK) {
|
|
||||||
panic("VMCTL_I386_PAGEDIRS failed: %d", r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Give our process the new, copied, private page table. */
|
/* Give our process the new, copied, private page table. */
|
||||||
pt_mapkernel(newpt); /* didn't know about vm_dir pages earlier */
|
pt_mapkernel(newpt); /* didn't know about vm_dir pages earlier */
|
||||||
pt_bind(newpt, vmprocess);
|
pt_bind(newpt, vmprocess);
|
||||||
|
@ -922,12 +914,15 @@ PUBLIC int pt_bind(pt_t *pt, struct vmproc *who)
|
||||||
{
|
{
|
||||||
int slot, ispt;
|
int slot, ispt;
|
||||||
u32_t phys;
|
u32_t phys;
|
||||||
|
void *pdes;
|
||||||
|
|
||||||
/* Basic sanity checks. */
|
/* Basic sanity checks. */
|
||||||
assert(who);
|
assert(who);
|
||||||
assert(who->vm_flags & VMF_INUSE);
|
assert(who->vm_flags & VMF_INUSE);
|
||||||
assert(pt);
|
assert(pt);
|
||||||
|
|
||||||
|
assert(pagedir_pde >= 0);
|
||||||
|
|
||||||
slot = who->vm_slot;
|
slot = who->vm_slot;
|
||||||
assert(slot >= 0);
|
assert(slot >= 0);
|
||||||
assert(slot < ELEMENTS(vmproc));
|
assert(slot < ELEMENTS(vmproc));
|
||||||
|
@ -939,12 +934,21 @@ PUBLIC int pt_bind(pt_t *pt, struct vmproc *who)
|
||||||
/* Update "page directory pagetable." */
|
/* Update "page directory pagetable." */
|
||||||
page_directories[slot] = phys | I386_VM_PRESENT|I386_VM_WRITE;
|
page_directories[slot] = phys | I386_VM_PRESENT|I386_VM_WRITE;
|
||||||
|
|
||||||
|
/* This is where the PDE's will be visible to the kernel
|
||||||
|
* in its address space.
|
||||||
|
*/
|
||||||
|
pdes = (void *) arch_map2vir(&vmproc[VMP_SYSTEM],
|
||||||
|
pagedir_pde*I386_BIG_PAGE_SIZE +
|
||||||
|
slot * I386_PAGE_SIZE);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printf("VM: slot %d has pde val 0x%lx\n", slot, page_directories[slot]);
|
printf("VM: slot %d endpoint %d has pde val 0x%lx at kernel address 0x%lx\n",
|
||||||
|
slot, who->vm_endpoint, page_directories[slot], pdes);
|
||||||
#endif
|
#endif
|
||||||
/* Tell kernel about new page table root. */
|
/* Tell kernel about new page table root. */
|
||||||
return sys_vmctl(who->vm_endpoint, VMCTL_I386_SETCR3,
|
return sys_vmctl_set_addrspace(who->vm_endpoint,
|
||||||
pt ? pt->pt_dir_phys : 0);
|
pt ? pt->pt_dir_phys : 0,
|
||||||
|
pt ? pdes : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
Loading…
Reference in a new issue