From c5c25e7abce1b50d23aa81aa152f07c0f530f0a8 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Wed, 12 May 2010 08:31:05 +0000 Subject: [PATCH] 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. --- include/arch/i386/archtypes.h | 1 + include/minix/com.h | 5 +++-- include/minix/syslib.h | 3 +++ kernel/arch/i386/arch_do_vmctl.c | 15 +++++---------- kernel/arch/i386/memory.c | 33 +++++++++++++++++++++++--------- kernel/arch/i386/sconst.h | 3 ++- kernel/proto.h | 1 + kernel/system/do_clear.c | 2 ++ kernel/system/do_fork.c | 3 +++ lib/libsys/sys_vmctl.c | 15 +++++++++++++++ servers/vm/arch/i386/pagetable.c | 28 +++++++++++++++------------ 11 files changed, 75 insertions(+), 34 deletions(-) diff --git a/include/arch/i386/archtypes.h b/include/arch/i386/archtypes.h index 3300a2ebb..7db2f481d 100644 --- a/include/arch/i386/archtypes.h +++ b/include/arch/i386/archtypes.h @@ -25,6 +25,7 @@ struct segdesc_s { /* segment descriptor for protected mode */ typedef struct segframe { reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */ reg_t p_cr3; /* page table root */ + u32_t *p_cr3_v; struct segdesc_s p_ldt[LDT_SIZE]; /* CS, DS and remote */ } segframe_t; diff --git a/include/minix/com.h b/include/minix/com.h index 86ac88016..9d64eec8f 100644 --- a/include/minix/com.h +++ b/include/minix/com.h @@ -601,6 +601,8 @@ #define SVMCTL_MRG_ADDR2 m2_l2 /* MEMREQ_GET reply: source address */ #define SVMCTL_MRG_REQUESTOR m2_p1 /* MEMREQ_GET reply: requestor */ #define SVMCTL_MAP_VIR_ADDR m1_p1 +#define SVMCTL_PTROOT m1_i3 +#define SVMCTL_PTROOT_V m1_p1 /* Reply message for VMCTL_KERN_PHYSMAP */ #define SVMCTL_MAP_FLAGS m2_i1 /* VMMF_* */ @@ -610,7 +612,6 @@ #define VMMF_UNCACHED (1L << 0) /* Values for SVMCTL_PARAM. */ -#define VMCTL_I386_SETCR3 10 #define VMCTL_CLEAR_PAGEFAULT 12 #define VMCTL_I386_GETCR3 13 #define VMCTL_MEMREQ_GET 14 @@ -618,13 +619,13 @@ #define VMCTL_INCSP 16 #define VMCTL_NOPAGEZERO 18 #define VMCTL_I386_KERNELLIMIT 19 -#define VMCTL_I386_PAGEDIRS 20 #define VMCTL_I386_FREEPDE 23 #define VMCTL_ENABLE_PAGING 24 #define VMCTL_I386_INVLPG 25 #define VMCTL_FLUSHTLB 26 #define VMCTL_KERN_PHYSMAP 27 #define VMCTL_KERN_MAP_REPLY 28 +#define VMCTL_SETADDRSPACE 29 /* Codes and field names for SYS_SYSCTL. */ #define SYSCTL_CODE m1_i1 /* SYSCTL_CODE_* below */ diff --git a/include/minix/syslib.h b/include/minix/syslib.h index 5d5954066..f09339374 100644 --- a/include/minix/syslib.h +++ b/include/minix/syslib.h @@ -79,6 +79,9 @@ _PROTOTYPE( int sys_sysctl_stacktrace, (endpoint_t who)); _PROTOTYPE( int sys_vmctl_get_mapping, (int index, phys_bytes *addr, phys_bytes *len, int *flags)); _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. */ #define sys_insb(port, proc_ep, buffer, count) \ diff --git a/kernel/arch/i386/arch_do_vmctl.c b/kernel/arch/i386/arch_do_vmctl.c index ca1d291b4..a1be5e39d 100644 --- a/kernel/arch/i386/arch_do_vmctl.c +++ b/kernel/arch/i386/arch_do_vmctl.c @@ -12,8 +12,6 @@ #include "proto.h" -extern u8_t *vm_pagedirs; - /*===========================================================================* * arch_do_vmctl * *===========================================================================*/ @@ -26,13 +24,15 @@ struct proc *p; /* Get process CR3. */ m_ptr->SVMCTL_VALUE = p->p_seg.p_cr3; return OK; - case VMCTL_I386_SETCR3: + case VMCTL_SETADDRSPACE: /* Set process CR3. */ - if(m_ptr->SVMCTL_VALUE) { - p->p_seg.p_cr3 = m_ptr->SVMCTL_VALUE; + if(m_ptr->SVMCTL_PTROOT) { + 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; } else { p->p_seg.p_cr3 = 0; + p->p_seg.p_cr3_v = NULL; p->p_misc_flags &= ~MF_FULLVM; } RTS_UNSET(p, RTS_VMINHIBIT); @@ -48,11 +48,6 @@ struct proc *p; r = prot_set_kern_seg_limit(m_ptr->SVMCTL_VALUE); return r; } - case VMCTL_I386_PAGEDIRS: - { - vm_pagedirs = (u8_t *) m_ptr->SVMCTL_VALUE; - return OK; - } case VMCTL_I386_FREEPDE: { i386_freepde(m_ptr->SVMCTL_VALUE); diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index bb2f327e2..b4c6111ad 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -28,12 +28,6 @@ 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) PRIVATE int nfreepdes = 0, freepdes[MAX_FREEPDES]; @@ -90,6 +84,7 @@ PRIVATE phys_bytes createpde( assert(free_pde_idx >= 0 && free_pde_idx < nfreepdes); pde = freepdes[free_pde_idx]; + assert(pde >= 0 && pde < 1024); if(pr && ((pr == ptproc) || !HASPT(pr))) { /* Process memory is requested, and @@ -106,7 +101,8 @@ PRIVATE phys_bytes createpde( * accessible directly. Grab the PDE entry of that process' * 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 { /* Requested address is physical. Make up the PDE entry. */ 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 * visible. */ - if(*PROCPDEPTR(ptproc, pde) != pdeval) { - *PROCPDEPTR(ptproc, pde) = pdeval; + assert(ptproc->p_seg.p_cr3_v); + if(ptproc->p_seg.p_cr3_v[pde] != pdeval) { + ptproc->p_seg.p_cr3_v[pde] = pdeval; *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); + 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) { phys_bytes srcptr, dstptr; vir_bytes chunk = bytes; @@ -191,6 +193,11 @@ PRIVATE int lin_lin_copy(const struct proc *srcproc, vir_bytes srclinaddr, 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; } @@ -677,6 +684,8 @@ int vm_phys_memset(phys_bytes ph, const u8_t c, phys_bytes bytes) assert(nfreepdes >= 3); + assert(ptproc->p_seg.p_cr3_v); + /* With VM, we have to map in the physical memory. * 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; } + assert(ptproc->p_seg.p_cr3_v); return OK; } @@ -1004,3 +1014,8 @@ PUBLIC int arch_enable_paging(struct proc * caller, const message * m_ptr) return OK; } + +PUBLIC void release_address_space(struct proc *pr) +{ + pr->p_seg.p_cr3_v = NULL; +} diff --git a/kernel/arch/i386/sconst.h b/kernel/arch/i386/sconst.h index 2a5e3b667..ca59b62bf 100644 --- a/kernel/arch/i386/sconst.h +++ b/kernel/arch/i386/sconst.h @@ -30,7 +30,8 @@ FP_SAVE_AREA_P = P_STACKTOP P_LDT_SEL = FP_SAVE_AREA_P + 532 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 Msize = 9 /* size of a message in 32-bit words*/ diff --git a/kernel/proto.h b/kernel/proto.h index 560f10662..7f58ac821 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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, message * user_mbuf)); _PROTOTYPE(void switch_address_space, (struct proc * p)); +_PROTOTYPE(void release_address_space, (struct proc *pr)); #endif /* PROTO_H */ diff --git a/kernel/system/do_clear.c b/kernel/system/do_clear.c index 58819aa5c..db960cb7a 100644 --- a/kernel/system/do_clear.c +++ b/kernel/system/do_clear.c @@ -31,6 +31,8 @@ PUBLIC int do_clear(struct proc * caller, message * m_ptr) } rc = proc_addr(exit_p); /* clean up */ + release_address_space(rc); + /* Don't clear if already cleared. */ if(isemptyp(rc)) return OK; diff --git a/kernel/system/do_fork.c b/kernel/system/do_fork.c index 936df8f5a..11629afb9 100644 --- a/kernel/system/do_fork.c +++ b/kernel/system/do_fork.c @@ -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)); sigemptyset(&rpc->p_pending); + rpc->p_seg.p_cr3 = 0; + rpc->p_seg.p_cr3_v = NULL; + return r; } diff --git a/lib/libsys/sys_vmctl.c b/lib/libsys/sys_vmctl.c index 73ab87430..965671054 100644 --- a/lib/libsys/sys_vmctl.c +++ b/lib/libsys/sys_vmctl.c @@ -26,6 +26,21 @@ PUBLIC int sys_vmctl_get_cr3_i386(endpoint_t who, u32_t *cr3) 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, vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s, endpoint_t *requestor) diff --git a/servers/vm/arch/i386/pagetable.c b/servers/vm/arch/i386/pagetable.c index 4fa248311..939322b41 100644 --- a/servers/vm/arch/i386/pagetable.c +++ b/servers/vm/arch/i386/pagetable.c @@ -717,7 +717,7 @@ PUBLIC void pt_init(phys_bytes usedlimit) */ pt_t *newpt; int s, r; - vir_bytes v, kpagedir; + vir_bytes v; phys_bytes lo, hi; vir_bytes extra_clicks; u32_t moveup = 0; @@ -886,14 +886,6 @@ PUBLIC void pt_init(phys_bytes usedlimit) /* first pde in use by process. */ 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. */ pt_mapkernel(newpt); /* didn't know about vm_dir pages earlier */ pt_bind(newpt, vmprocess); @@ -922,12 +914,15 @@ PUBLIC int pt_bind(pt_t *pt, struct vmproc *who) { int slot, ispt; u32_t phys; + void *pdes; /* Basic sanity checks. */ assert(who); assert(who->vm_flags & VMF_INUSE); assert(pt); + assert(pagedir_pde >= 0); + slot = who->vm_slot; assert(slot >= 0); assert(slot < ELEMENTS(vmproc)); @@ -939,12 +934,21 @@ PUBLIC int pt_bind(pt_t *pt, struct vmproc *who) /* Update "page directory pagetable." */ 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 - 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 /* Tell kernel about new page table root. */ - return sys_vmctl(who->vm_endpoint, VMCTL_I386_SETCR3, - pt ? pt->pt_dir_phys : 0); + return sys_vmctl_set_addrspace(who->vm_endpoint, + pt ? pt->pt_dir_phys : 0, + pt ? pdes : 0); } /*===========================================================================*