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;
#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_* */
#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
#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 */
_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) \
#include "proto.h"
-extern u8_t *vm_pagedirs;
-
/*===========================================================================*
* arch_do_vmctl *
*===========================================================================*/
/* 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);
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);
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];
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
* 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) |
* 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;
}
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;
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;
}
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.
*/
ph += chunk;
}
+ assert(ptproc->p_seg.p_cr3_v);
return OK;
}
return OK;
}
+
+PUBLIC void release_address_space(struct proc *pr)
+{
+ pr->p_seg.p_cr3_v = NULL;
+}
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*/
_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 */
}
rc = proc_addr(exit_p); /* clean up */
+ release_address_space(rc);
+
/* Don't clear if already cleared. */
if(isemptyp(rc)) return OK;
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;
}
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)
*/
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;
/* 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);
{
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));
/* 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);
}
/*===========================================================================*