my state.

trying to get some memory optimisation (less pagetable reloading,
less tlb purging) features working smoothly.

to be documented when committing to trunk :)
This commit is contained in:
Ben Gras
2009-06-06 23:27:10 +00:00
parent 9d56ac3fc9
commit 4dae6c4bbc
30 changed files with 721 additions and 588 deletions

View File

@@ -77,7 +77,7 @@ register message *m_ptr; /* pointer to request message */
return EPERM;
}
/* Get and check physical address. */
if ((phys_buf = umap_virtual(proc_addr(proc_nr), D,
if ((phys_buf = umap_local(proc_addr(proc_nr), D,
(vir_bytes) m_ptr->DIO_VEC_ADDR, count)) == 0)
return(EFAULT);
}

View File

@@ -11,53 +11,67 @@
#include <minix/sysutil.h>
#include "../../proc.h"
#include "../../proto.h"
#include "../../vm.h"
extern int vm_copy_in_progress, catch_pagefaults;
extern struct proc *vm_copy_from, *vm_copy_to;
extern u32_t npagefaults;
u32_t pagefault_cr2, pagefault_count = 0;
vir_bytes *old_eip_ptr = NULL, *old_eax_ptr = NULL;
PUBLIC u32_t pagefault_count = 0;
void pagefault(vir_bytes old_eip, struct proc *pr, int trap_errno)
void pagefault(vir_bytes old_eip, struct proc *pr, int trap_errno,
u32_t *old_eipptr, u32_t *old_eaxptr, u32_t pagefaultcr2)
{
int s;
vir_bytes ph;
u32_t pte;
int procok = 0, pcok = 0, rangeok = 0;
int in_memcpy = 0, in_physcopy = 0;
int in_physcopy = 0;
vir_bytes test_eip;
vmassert(old_eip_ptr);
vmassert(old_eax_ptr);
vmassert(old_eipptr);
vmassert(old_eaxptr);
vmassert(*old_eip_ptr == old_eip);
vmassert(old_eip_ptr != &old_eip);
vmassert(*old_eipptr == old_eip);
vmassert(old_eipptr != &old_eip);
vmassert(pagefault_count == 1);
if(catch_pagefaults) {
vir_bytes test_eip;
test_eip = k_reenter ? old_eip : pr->p_reg.pc;
in_memcpy = (test_eip > (vir_bytes) _memcpy_k) &&
(test_eip < (vir_bytes) _memcpy_k_fault);
in_physcopy = (test_eip > (vir_bytes) phys_copy) &&
(test_eip < (vir_bytes) phys_copy_fault);
if((pcok = in_memcpy || in_physcopy)) {
pagefault_count = 0;
#if 0
printf("kernel: pagefault in pr %d, addr 0x%lx, his cr3 0x%lx, actual cr3 0x%lx\n",
pr->p_endpoint, pagefaultcr2, pr->p_seg.p_cr3, read_cr3());
#endif
if(in_memcpy) {
vmassert(!in_physcopy);
*old_eip_ptr = _memcpy_k_fault;
}
if(in_physcopy) {
vmassert(!in_memcpy);
*old_eip_ptr = phys_copy_fault;
}
*old_eax_ptr = pagefault_cr2;
return;
}
if(pr->p_seg.p_cr3) {
#if 0
vm_print(pr->p_seg.p_cr3);
#endif
vmassert(pr->p_seg.p_cr3 == read_cr3());
} else {
vmassert(ptproc);
vmassert(ptproc->p_seg.p_cr3 == read_cr3());
}
test_eip = k_reenter ? old_eip : pr->p_reg.pc;
in_physcopy = (test_eip > (vir_bytes) phys_copy) &&
(test_eip < (vir_bytes) phys_copy_fault);
if((k_reenter || iskernelp(pr)) &&
catch_pagefaults && in_physcopy) {
#if 0
printf("pf caught! addr 0x%lx\n", pagefaultcr2);
#endif
*old_eipptr = phys_copy_fault;
*old_eaxptr = pagefaultcr2;
pagefault_count = 0;
return;
}
npagefaults++;
/* System processes that don't have their own page table can't
* have page faults. VM does have its own page table but also
* can't have page faults (because VM has to handle them).
@@ -67,9 +81,9 @@ void pagefault(vir_bytes old_eip, struct proc *pr, int trap_errno)
/* Page fault we can't / don't want to
* handle.
*/
kprintf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x\n",
kprintf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x, k_reenter %d\n",
pr->p_endpoint, pr->p_name, pr->p_reg.pc,
pagefault_cr2, trap_errno);
pagefaultcr2, trap_errno, k_reenter);
proc_stacktrace(pr);
minix_panic("page fault in system process", pr->p_endpoint);
@@ -86,12 +100,12 @@ void pagefault(vir_bytes old_eip, struct proc *pr, int trap_errno)
* and tell VM there is a pagefault to be
* handled.
*/
pr->p_pagefault.pf_virtual = pagefault_cr2;
pr->p_pagefault.pf_virtual = pagefaultcr2;
pr->p_pagefault.pf_flags = trap_errno;
pr->p_nextpagefault = pagefaults;
pagefaults = pr;
lock_notify(SYSTEM, VM_PROC_NR);
lock_notify(HARDWARE, VM_PROC_NR);
pagefault_count = 0;
@@ -101,12 +115,16 @@ void pagefault(vir_bytes old_eip, struct proc *pr, int trap_errno)
/*===========================================================================*
* exception *
*===========================================================================*/
PUBLIC void exception(vec_nr, trap_errno, old_eip, old_cs, old_eflags)
PUBLIC void exception(vec_nr, trap_errno, old_eip, old_cs, old_eflags,
old_eipptr, old_eaxptr, pagefaultcr2)
unsigned vec_nr;
u32_t trap_errno;
u32_t old_eip;
U16_t old_cs;
u32_t old_eflags;
u32_t *old_eipptr;
u32_t *old_eaxptr;
u32_t pagefaultcr2;
{
/* An exception or unexpected interrupt has occurred. */
@@ -141,6 +159,8 @@ struct proc *t;
/* Save proc_ptr, because it may be changed by debug statements. */
saved_proc = proc_ptr;
CHECK_RUNQUEUES;
ep = &ex_data[vec_nr];
@@ -150,8 +170,9 @@ struct proc *t;
}
if(vec_nr == PAGE_FAULT_VECTOR) {
pagefault(old_eip, saved_proc, trap_errno);
return;
pagefault(old_eip, saved_proc, trap_errno,
old_eipptr, old_eaxptr, pagefaultcr2);
return;
}
/* If an exception occurs while running a process, the k_reenter variable
@@ -222,7 +243,7 @@ PUBLIC void proc_stacktrace(struct proc *proc)
break;
}
if(PRCOPY(proc, v_bp + sizeof(v_pc), &v_pc, sizeof(v_pc)) != OK) {
kprintf("(v_pc 0x%lx ?)", v_pc);
kprintf("(v_pc 0x%lx ?)", v_bp + sizeof(v_pc));
break;
}
kprintf("0x%lx ", (unsigned long) v_pc);

View File

@@ -383,8 +383,6 @@ _phys_copy:
mov edi, PC_ARGS+4(esp)
mov eax, PC_ARGS+4+4(esp)
mov (_catch_pagefaults), 1
cmp eax, 10 ! avoid align overhead for small counts
jb pc_small
mov ecx, esi ! align source, hope target is too
@@ -403,12 +401,11 @@ pc_small:
rep
eseg movsb
mov eax, 0 ! 0 means: no fault
_phys_copy_fault: ! kernel can send us here
pop es
pop edi
pop esi
mov eax, 0 ! 0 means: no fault
_phys_copy_fault: ! kernel can send us here
mov (_catch_pagefaults), 0
ret
!*===========================================================================*
@@ -439,7 +436,7 @@ fill_start:
jnz fill_start
! Any remaining bytes?
mov eax, 16(ebp)
! and eax, 3
and eax, 3
remain_fill:
cmp eax, 0
jz fill_done

View File

@@ -9,21 +9,21 @@
#include <minix/cpufeature.h>
#include <string.h>
#define FREEPDE_SRC 0
#define FREEPDE_DST 1
#define FREEPDE_MEMSET 2
#include <sys/vm_i386.h>
#include <minix/portio.h>
#include "proto.h"
#include "../../proto.h"
#include "../../proto.h"
#include "../../debug.h"
PRIVATE int psok = 0;
extern u32_t createpde, linlincopies, physzero;
int verifyrange = 0;
extern u32_t newpde, overwritepde, linlincopies,
physzero, invlpgs, vmcheckranges, straightpdes;
#define PROCPDEPTR(pr, pi) ((u32_t *) ((u8_t *) vm_pagedirs +\
I386_PAGE_SIZE * pr->p_nr + \
@@ -37,12 +37,15 @@ u8_t *vm_pagedirs = NULL;
u32_t i386_invlpg_addr = 0;
#define WANT_FREEPDES 4
PRIVATE int nfreepdes = 0, freepdes[WANT_FREEPDES];
#define NOPDE -1
#define PDEMASK(n) (1L << (n))
PRIVATE int nfreepdes = 0, freepdes[WANT_FREEPDES], inusepde = NOPDE;
PUBLIC u32_t dirtypde;
#define HASPT(procptr) ((procptr)->p_seg.p_cr3 != 0)
FORWARD _PROTOTYPE( u32_t phys_get32, (vir_bytes v) );
FORWARD _PROTOTYPE( void vm_set_cr3, (u32_t value) );
FORWARD _PROTOTYPE( void vm_set_cr3, (struct proc *pr) );
FORWARD _PROTOTYPE( void set_cr3, (void) );
FORWARD _PROTOTYPE( void vm_enable_paging, (void) );
@@ -50,34 +53,13 @@ FORWARD _PROTOTYPE( void vm_enable_paging, (void) );
PUBLIC void vm_init(struct proc *newptproc)
{
u32_t newcr3;
int i;
if(vm_running)
minix_panic("vm_init: vm_running", NO_NUM);
ptproc = newptproc;
newcr3 = ptproc->p_seg.p_cr3;
kprintf("vm_init: ptproc: %s / %d, cr3 0x%lx\n",
ptproc->p_name, ptproc->p_endpoint,
ptproc->p_seg.p_cr3);
vmassert(newcr3);
/* Set this cr3 now (not active until paging enabled). */
vm_set_cr3(newcr3);
kprintf("vm_init: writing cr3 0x%lx done; cr3: 0x%lx\n",
newcr3, read_cr3());
kprintf("vm_init: enabling\n");
/* Actually enable paging (activating cr3 load above). */
vm_set_cr3(newptproc);
level0(vm_enable_paging);
kprintf("vm_init: enabled\n");
/* Don't do this init in the future. */
vm_running = 1;
kprintf("vm_init done\n");
}
PRIVATE u32_t phys_get32(addr)
@@ -91,9 +73,8 @@ phys_bytes addr;
return v;
}
if((r=lin_lin_copy(NULL, addr, NULL, D,
proc_addr(SYSTEM), &v, &v, D,
sizeof(v))) != OK) {
if((r=lin_lin_copy(NULL, addr,
proc_addr(SYSTEM), vir2phys(&v), sizeof(v))) != OK) {
minix_panic("lin_lin_copy for phys_get32 failed", r);
}
@@ -102,11 +83,16 @@ phys_bytes addr;
PRIVATE u32_t vm_cr3; /* temp arg to level0() func */
PRIVATE void vm_set_cr3(value)
u32_t value;
PRIVATE void vm_set_cr3(struct proc *newptproc)
{
vm_cr3= value;
level0(set_cr3);
int u = 0;
if(!intr_disabled()) { lock; u = 1; }
vm_cr3= newptproc->p_seg.p_cr3;
if(vm_cr3) {
level0(set_cr3);
ptproc = newptproc;
}
if(u) { unlock; }
}
PRIVATE void set_cr3()
@@ -343,11 +329,13 @@ PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical,
pde_v = phys_get32((u32_t) (root + pde));
if(!(pde_v & I386_VM_PRESENT)) {
#if 0
#if 1
if(verifyrange) {
kprintf("vm_lookup: %d:%s:0x%lx: cr3 0x%lx: pde %d not present\n",
proc->p_endpoint, proc->p_name, virtual, root, pde);
kprintf("kernel stack: ");
util_stacktrace();
}
#endif
NOREC_RETURN(vmlookup, EFAULT);
}
@@ -365,6 +353,14 @@ PUBLIC int vm_lookup(struct proc *proc, vir_bytes virtual, vir_bytes *physical,
vmassert(pte >= 0 && pte < I386_VM_PT_ENTRIES);
pte_v = phys_get32((u32_t) (pt + pte));
if(!(pte_v & I386_VM_PRESENT)) {
#if 1
if(verifyrange) {
kprintf("vm_lookup: %d:%s:0x%lx: cr3 0x%lx: pte %d not present\n",
proc->p_endpoint, proc->p_name, virtual, root, pte);
kprintf("kernel stack: ");
util_stacktrace();
}
#endif
NOREC_RETURN(vmlookup, EFAULT);
}
@@ -449,35 +445,90 @@ PUBLIC int vm_contiguous(struct proc *targetproc, u32_t vir_buf, size_t bytes)
boundaries++;
}
if(verbose_vm)
kprintf("vm_contiguous: yes (%d boundaries tested)\n",
boundaries);
return 1;
}
int vm_checkrange_verbose = 0;
extern u32_t vmreqs;
/*===========================================================================*
* vm_suspend *
*===========================================================================*/
PUBLIC int vm_suspend(struct proc *caller, struct proc *target)
PUBLIC int vm_suspend(struct proc *caller, struct proc *target,
vir_bytes linaddr, vir_bytes len, int wrflag, int type)
{
/* This range is not OK for this process. Set parameters
* of the request and notify VM about the pending request.
*/
if(RTS_ISSET(caller, VMREQUEST))
minix_panic("VMREQUEST already set", caller->p_endpoint);
RTS_LOCK_SET(caller, VMREQUEST);
vmassert(!RTS_ISSET(caller, VMREQUEST));
vmassert(!RTS_ISSET(caller, VMREQTARGET));
vmassert(!RTS_ISSET(target, VMREQUEST));
vmassert(!RTS_ISSET(target, VMREQTARGET));
RTS_LOCK_SET(caller, VMREQUEST);
RTS_LOCK_SET(target, VMREQTARGET);
#if DEBUG_VMASSERT
caller->p_vmrequest.stacktrace[0] = '\0';
util_stacktrace_strcat(caller->p_vmrequest.stacktrace);
#endif
vmreqs++;
/* Set caller in target. */
target->p_vmrequest.requestor = caller;
caller->p_vmrequest.writeflag = 1;
caller->p_vmrequest.start = linaddr;
caller->p_vmrequest.length = len;
caller->p_vmrequest.who = target->p_endpoint;
caller->p_vmrequest.type = type;
/* Connect caller on vmrequest wait queue. */
caller->p_vmrequest.nextrequestor = vmrequest;
vmrequest = caller;
if(!caller->p_vmrequest.nextrequestor)
if(!(caller->p_vmrequest.nextrequestor = vmrequest))
lock_notify(SYSTEM, VM_PROC_NR);
vmrequest = caller;
}
/*===========================================================================*
* delivermsg *
*===========================================================================*/
int delivermsg(struct proc *rp)
{
phys_bytes addr;
int r;
NOREC_ENTER(deliver);
vmassert(rp->p_misc_flags & MF_DELIVERMSG);
vmassert(rp->p_delivermsg.m_source != NONE);
vmassert(rp->p_delivermsg_lin);
vmassert(rp->p_delivermsg_lin ==
umap_local(rp, D, rp->p_delivermsg_vir, sizeof(message)));
vm_set_cr3(rp);
vmassert(intr_disabled());
vmassert(!catch_pagefaults);
catch_pagefaults = 1;
addr = phys_copy(vir2phys(&rp->p_delivermsg),
rp->p_delivermsg_lin, sizeof(message));
vmassert(catch_pagefaults);
catch_pagefaults = 0;
if(addr) {
printf("phys_copy failed - addr 0x%lx\n", addr);
vm_suspend(rp, rp, rp->p_delivermsg_lin, sizeof(message), 1,
VMSTYPE_DELIVERMSG);
r = VMSUSPEND;
} else {
#if DEBUG_VMASSERT
rp->p_delivermsg.m_source = NONE;
rp->p_delivermsg_lin = 0;
#endif
rp->p_misc_flags &= ~MF_DELIVERMSG;
r = OK;
}
NOREC_RETURN(deliver, r);
}
/*===========================================================================*
@@ -491,22 +542,23 @@ PUBLIC int vm_checkrange(struct proc *caller, struct proc *target,
NOREC_ENTER(vmcheckrange);
vmcheckranges++;
if(!HASPT(target))
NOREC_RETURN(vmcheckrange, OK);
/* If caller has had a reply to this request, return it. */
if(RTS_ISSET(caller, VMREQUEST)) {
if(!verifyrange && RTS_ISSET(caller, VMREQUEST)) {
if(caller->p_vmrequest.who == target->p_endpoint) {
if(caller->p_vmrequest.vmresult == VMSUSPEND)
minix_panic("check sees VMSUSPEND?", NO_NUM);
vmassert(caller->p_vmrequest.vmresult != VMSUSPEND);
RTS_LOCK_UNSET(caller, VMREQUEST);
#if 0
#if 1
kprintf("SYSTEM: vm_checkrange: returning vmresult %d\n",
caller->p_vmrequest.vmresult);
#endif
NOREC_RETURN(vmcheckrange, caller->p_vmrequest.vmresult);
} else {
#if 0
#if 1
kprintf("SYSTEM: vm_checkrange: caller has a request for %d, "
"but our target is %d\n",
caller->p_vmrequest.who, target->p_endpoint);
@@ -525,25 +577,29 @@ PUBLIC int vm_checkrange(struct proc *caller, struct proc *target,
for(v = vir; v < vir + bytes; v+= I386_PAGE_SIZE) {
u32_t phys;
int r;
/* If page exists and it's writable if desired, we're OK
* for this page.
*/
if(vm_lookup(target, v, &phys, &flags) == OK &&
if((r=vm_lookup(target, v, &phys, &flags)) == OK &&
!(wrfl && !(flags & I386_VM_WRITE))) {
continue;
}
if(!checkonly) {
/* Set parameters in caller. */
vm_suspend(caller, target);
caller->p_vmrequest.writeflag = wrfl;
caller->p_vmrequest.start = vir;
caller->p_vmrequest.length = bytes;
caller->p_vmrequest.who = target->p_endpoint;
if(verifyrange) {
int wrok;
wrok = !(wrfl && !(flags & I386_VM_WRITE));
printf("checkrange failed; lookup: %d; write ok: %d\n",
r, wrok);
}
if(!checkonly) {
vmassert(k_reenter == -1);
vm_suspend(caller, target, vir, bytes, wrfl,
VMSTYPE_KERNELCALL);
}
/* SYSTEM loop will fill in VMSTYPE_SYS_MESSAGE. */
NOREC_RETURN(vmcheckrange, VMSUSPEND);
}
@@ -636,9 +692,17 @@ void invlpg_range(u32_t lin, u32_t bytes)
o = lin % I386_PAGE_SIZE;
lin -= o;
limit = (limit + o) & I386_VM_ADDR_MASK;
#if 0
for(i386_invlpg_addr = lin; i386_invlpg_addr <= limit;
i386_invlpg_addr += I386_PAGE_SIZE)
i386_invlpg_addr += I386_PAGE_SIZE) {
invlpgs++;
level0(i386_invlpg_level0);
}
#else
vm_cr3= ptproc->p_seg.p_cr3;
vmassert(vm_cr3);
level0(set_cr3);
#endif
}
u32_t thecr3;
@@ -662,79 +726,77 @@ u32_t read_cr3(void)
* address space), SEG (hardware segment), VIRT (in-datasegment
* address if known).
*/
#define CREATEPDE(PROC, PTR, LINADDR, OFFSET, FREEPDE, VIRT, SEG, REMAIN, BYTES) { \
#define CREATEPDE(PROC, PTR, LINADDR, REMAIN, BYTES) { \
int proc_pde_index; \
FIXME("CREATEPDE: check if invlpg is necessary"); \
if(PROC == ptproc) { \
FIXME("CREATEPDE: use in-memory process"); \
} \
if((PROC) && iskernelp(PROC) && SEG == D) { \
PTR = VIRT; \
OFFSET = 0; \
proc_pde_index = I386_VM_PDE(LINADDR); \
if((PROC) && (((PROC) == ptproc) || iskernelp(PROC))) { \
PTR = LINADDR; \
straightpdes++; \
} else { \
u32_t pdeval, *pdevalptr, newlin; \
int pde_index; \
int use_pde = NOPDE; \
int fp; \
int mustinvl; \
u32_t pdeval, *pdevalptr, mask; \
phys_bytes offset; \
vmassert(psok); \
pde_index = I386_VM_PDE(LINADDR); \
vmassert(!iskernelp(PROC)); \
createpde++; \
if(PROC) { \
u32_t *pdeptr; \
u32_t *pdeptr; \
vmassert(!iskernelp(PROC)); \
vmassert(HASPT(PROC)); \
pdeptr = PROCPDEPTR(PROC, pde_index); \
pdeval = *pdeptr; \
} else { \
pdeptr = PROCPDEPTR(PROC, proc_pde_index); \
pdeval = *pdeptr; \
} else { \
vmassert(!iskernelp(PROC)); \
pdeval = (LINADDR & I386_VM_ADDR_MASK_4MB) | \
I386_VM_BIGPAGE | I386_VM_PRESENT | \
I386_VM_WRITE | I386_VM_USER; \
} \
*PROCPDEPTR(ptproc, FREEPDE) = pdeval; \
newlin = I386_BIG_PAGE_SIZE*FREEPDE; \
PTR = (u8_t *) phys2vir(newlin); \
OFFSET = LINADDR & I386_VM_OFFSET_MASK_4MB; \
REMAIN = MIN(REMAIN, I386_BIG_PAGE_SIZE - OFFSET); \
invlpg_range(newlin + OFFSET, REMAIN); \
for(fp = 0; fp < nfreepdes; fp++) { \
int k = freepdes[fp]; \
if(inusepde == k) \
continue; \
use_pde = k; \
mask = PDEMASK(k); \
vmassert(mask); \
if(dirtypde & mask) \
continue; \
break; \
} \
vmassert(use_pde != NOPDE); \
vmassert(mask); \
if(dirtypde & mask) { \
mustinvl = 1; \
overwritepde++; \
} else { \
mustinvl = 0; \
dirtypde |= mask; \
newpde++; \
} \
inusepde = use_pde; \
*PROCPDEPTR(ptproc, use_pde) = pdeval; \
offset = LINADDR & I386_VM_OFFSET_MASK_4MB; \
PTR = I386_BIG_PAGE_SIZE*use_pde + offset; \
REMAIN = MIN(REMAIN, I386_BIG_PAGE_SIZE - offset); \
if(1 || mustinvl) { \
invlpg_range(PTR, REMAIN); \
} \
} \
}
/*===========================================================================*
* arch_switch_copymsg *
*===========================================================================*/
phys_bytes arch_switch_copymsg(struct proc *rp, message *m, phys_bytes lin)
{
phys_bytes r;
int u = 0;
if(!intr_disabled()) { lock; u = 1; }
if(rp->p_seg.p_cr3 && ptproc != rp) {
vm_set_cr3(rp->p_seg.p_cr3);
ptproc = rp;
}
r = phys_copy(vir2phys(m), lin, sizeof(message));
if(u) { unlock; }
}
/*===========================================================================*
* lin_lin_copy *
*===========================================================================*/
int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, u8_t *vsrc,
int srcseg,
struct proc *dstproc, vir_bytes dstlinaddr, u8_t *vdst,
int dstseg,
vir_bytes bytes)
int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr,
struct proc *dstproc, vir_bytes dstlinaddr, vir_bytes bytes)
{
u32_t addr;
int procslot;
u32_t catchrange_dst, catchrange_lo, catchrange_hi;
NOREC_ENTER(linlincopy);
linlincopies++;
if(srcproc && dstproc && iskernelp(srcproc) && iskernelp(dstproc)) {
memcpy(vdst, vsrc, bytes);
NOREC_RETURN(linlincopy, OK);
}
FIXME("lin_lin_copy requires big pages");
vmassert(vm_running);
vmassert(!catch_pagefaults);
@@ -747,37 +809,30 @@ int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, u8_t *vsrc,
procslot = ptproc->p_nr;
vmassert(procslot >= 0 && procslot < I386_VM_DIR_ENTRIES);
vmassert(freepdes[FREEPDE_SRC] < freepdes[FREEPDE_DST]);
catchrange_lo = I386_BIG_PAGE_SIZE*freepdes[FREEPDE_SRC];
catchrange_dst = I386_BIG_PAGE_SIZE*freepdes[FREEPDE_DST];
catchrange_hi = I386_BIG_PAGE_SIZE*(freepdes[FREEPDE_DST]+1);
while(bytes > 0) {
u8_t *srcptr, *dstptr;
vir_bytes srcoffset, dstoffset;
phys_bytes srcptr, dstptr;
vir_bytes chunk = bytes;
/* Set up 4MB ranges. */
CREATEPDE(srcproc, srcptr, srclinaddr, srcoffset,
freepdes[FREEPDE_SRC], vsrc, srcseg, chunk, bytes);
CREATEPDE(dstproc, dstptr, dstlinaddr, dstoffset,
freepdes[FREEPDE_DST], vdst, dstseg, chunk, bytes);
inusepde = NOPDE;
CREATEPDE(srcproc, srcptr, srclinaddr, chunk, bytes);
CREATEPDE(dstproc, dstptr, dstlinaddr, chunk, bytes);
/* Copy pages. */
vmassert(intr_disabled());
vmassert(!catch_pagefaults);
catch_pagefaults = 1;
addr=_memcpy_k(dstptr + dstoffset, srcptr + srcoffset, chunk);
addr=phys_copy(srcptr, dstptr, chunk);
vmassert(intr_disabled());
vmassert(catch_pagefaults);
catch_pagefaults = 0;
if(addr) {
if(addr >= catchrange_lo && addr < catchrange_dst) {
if(addr >= srcptr && addr < (srcptr + chunk)) {
NOREC_RETURN(linlincopy, EFAULT_SRC);
}
if(addr >= catchrange_dst && addr < catchrange_hi) {
if(addr >= dstptr && addr < (dstptr + chunk)) {
NOREC_RETURN(linlincopy, EFAULT_DST);
}
minix_panic("lin_lin_copy fault out of range", NO_NUM);
@@ -785,15 +840,11 @@ int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, u8_t *vsrc,
/* Not reached. */
NOREC_RETURN(linlincopy, EFAULT);
}
vmassert(memcmp(dstptr + dstoffset, srcptr + srcoffset, chunk) == 0);
/* Update counter and addresses for next iteration, if any. */
bytes -= chunk;
srclinaddr += chunk;
dstlinaddr += chunk;
vsrc += chunk;
vdst += chunk;
}
NOREC_RETURN(linlincopy, OK);
@@ -805,12 +856,12 @@ int lin_lin_copy(struct proc *srcproc, vir_bytes srclinaddr, u8_t *vsrc,
int vm_phys_memset(phys_bytes ph, u8_t c, phys_bytes bytes)
{
char *v;
u32_t p;
p = c | (c << 8) | (c << 16) | (c << 24);
physzero++;
if(!vm_running) {
u32_t p;
p = c | (c << 8) | (c << 16) | (c << 24);
phys_memset(ph, p, bytes);
return OK;
}
@@ -822,14 +873,13 @@ int vm_phys_memset(phys_bytes ph, u8_t c, phys_bytes bytes)
*/
while(bytes > 0) {
vir_bytes chunk = bytes;
u8_t *ptr;
u32_t offset;
CREATEPDE(((struct proc *) NULL), ptr, ph,
offset, freepdes[FREEPDE_MEMSET], 0, 0, chunk, bytes);
phys_bytes ptr;
inusepde = NOPDE;
CREATEPDE(((struct proc *) NULL), ptr, ph, chunk, bytes);
/* We can memset as many bytes as we have remaining,
* or as many as remain in the 4MB chunk we mapped in.
*/
memset(ptr + offset, c, chunk);
phys_memset(ptr, p, chunk);
bytes -= chunk;
ph += chunk;
}
@@ -930,30 +980,43 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
if(vm_running) {
int r;
struct proc *target, *caller;
struct proc *caller;
caller = proc_addr(who_p);
if(RTS_ISSET(caller, VMREQUEST)) {
struct proc *target;
int pn;
vmassert(caller->p_vmrequest.vmresult != VMSUSPEND);
RTS_LOCK_UNSET(caller, VMREQUEST);
if(caller->p_vmrequest.vmresult != OK) {
printf("virtual_copy: returning VM error %d\n",
caller->p_vmrequest.vmresult);
NOREC_RETURN(virtualcopy, caller->p_vmrequest.vmresult);
}
}
if((r=lin_lin_copy(procs[_SRC_], phys_addr[_SRC_],
(u8_t *) src_addr->offset, src_addr->segment,
procs[_DST_], phys_addr[_DST_], (u8_t *) dst_addr->offset,
dst_addr->segment, bytes)) != OK) {
procs[_DST_], phys_addr[_DST_], bytes)) != OK) {
struct proc *target;
int wr;
phys_bytes lin;
if(r != EFAULT_SRC && r != EFAULT_DST)
minix_panic("lin_lin_copy failed", r);
if(!vmcheck) {
NOREC_RETURN(virtualcopy, r);
}
caller = proc_addr(who_p);
vmassert(procs[_SRC_] && procs[_DST_]);
if(r == EFAULT_SRC) {
caller->p_vmrequest.start = phys_addr[_SRC_];
lin = phys_addr[_SRC_];
target = procs[_SRC_];
caller->p_vmrequest.writeflag = 0;
wr = 0;
} else if(r == EFAULT_DST) {
caller->p_vmrequest.start = phys_addr[_DST_];
lin = phys_addr[_DST_];
target = procs[_DST_];
caller->p_vmrequest.writeflag = 1;
wr = 1;
} else {
minix_panic("r strange", r);
}
@@ -964,10 +1027,9 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
target->p_endpoint, target->p_name);
#endif
caller->p_vmrequest.length = bytes;
caller->p_vmrequest.who = target->p_endpoint;
vm_suspend(caller, target);
vmassert(k_reenter == -1);
vmassert(proc_ptr->p_endpoint == SYSTEM);
vm_suspend(caller, target, lin, bytes, wr, VMSTYPE_KERNELCALL);
NOREC_RETURN(virtualcopy, VMSUSPEND);
}
@@ -990,7 +1052,8 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
}
/* Now copy bytes between physical addresseses. */
phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes);
if(phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes))
NOREC_RETURN(virtualcopy, EFAULT);
NOREC_RETURN(virtualcopy, OK);
}

View File

@@ -73,10 +73,7 @@ begbss:
.define _restart
.define save
.define _pagefault_cr2
.define _pagefault_count
.define _old_eip_ptr
.define _old_eax_ptr
.define _cr3_test
.define _cr3_reload
.define _write_cr3 ! write cr3
@@ -104,6 +101,8 @@ begbss:
.define _params_size
.define _params_offset
.define _mon_ds
.define _schedcheck
.define _dirtypde
.define _hwint00 ! handlers for hardware interrupts
.define _hwint01
@@ -395,7 +394,7 @@ _p_s_call:
call _sys_call ! sys_call(call_nr, src_dst, m_ptr, bit_map)
! caller is now explicitly in proc_ptr
mov AXREG(esi), eax ! sys_call MUST PRESERVE si
mov AXREG(esi), eax
! Fall into code to restart proc/task running.
@@ -406,25 +405,22 @@ _restart:
! Restart the current process or the next process if it is set.
cmp (_next_ptr), 0 ! see if another process is scheduled
jz 0f
mov eax, (_next_ptr)
mov (_proc_ptr), eax ! schedule new process
mov (_next_ptr), 0
0: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
call _schedcheck ! ask C function who we're running
mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0
lldt P_LDT_SEL(esp) ! enable process' segment descriptors
inc (_cr3_test)
cmp P_CR3(esp), 0 ! process does not have its own PT
jz noload
jz 0f
mov eax, P_CR3(esp)
cmp eax, (loadedcr3)
jz noload
jz 0f
inc (_cr3_reload)
mov cr3, eax
mov (loadedcr3), eax
mov eax, (_proc_ptr)
mov (_ptproc), eax
noload:
! mov (_dirtypde), 0
0:
lea eax, P_STACKTOP(esp) ! arrange for next interrupt
mov (_tss+TSS3_S_SP0), eax ! to save state in process table
restart1:
@@ -500,7 +496,7 @@ _page_fault:
push PAGE_FAULT_VECTOR
push eax
mov eax, cr2
sseg mov (_pagefault_cr2), eax
sseg mov (pagefaultcr2), eax
sseg inc (_pagefault_count)
pop eax
jmp errexception
@@ -530,8 +526,8 @@ errexception:
sseg pop (ex_number)
sseg pop (trap_errno)
exception1: ! Common for all exceptions.
sseg mov (_old_eax_ptr), esp ! where will eax be saved?
sseg sub (_old_eax_ptr), PCREG-AXREG ! here
sseg mov (old_eax_ptr), esp ! where will eax be saved?
sseg sub (old_eax_ptr), PCREG-AXREG ! here
push eax ! eax is scratch register
@@ -539,7 +535,7 @@ exception1: ! Common for all exceptions.
sseg mov (old_eip), eax
mov eax, esp
add eax, 4
sseg mov (_old_eip_ptr), eax
sseg mov (old_eip_ptr), eax
movzx eax, 4+4(esp) ! old cs
sseg mov (old_cs), eax
mov eax, 8+4(esp) ! old eflags
@@ -547,6 +543,9 @@ exception1: ! Common for all exceptions.
pop eax
call save
push (pagefaultcr2)
push (old_eax_ptr)
push (old_eip_ptr)
push (old_eflags)
push (old_cs)
push (old_eip)
@@ -554,7 +553,7 @@ exception1: ! Common for all exceptions.
push (ex_number)
call _exception ! (ex_number, trap_errno, old_eip,
! old_cs, old_eflags)
add esp, 5*4
add esp, 8*4
ret
@@ -566,8 +565,14 @@ _write_cr3:
push ebp
mov ebp, esp
mov eax, 8(ebp)
inc (_cr3_test)
! cmp eax, (loadedcr3)
! jz 0f
inc (_cr3_reload)
mov cr3, eax
mov (loadedcr3), eax
! mov (_dirtypde), 0
0:
pop ebp
ret
@@ -591,8 +596,11 @@ k_stack:
k_stktop: ! top of kernel stack
.comm ex_number, 4
.comm trap_errno, 4
.comm old_eip_ptr, 4
.comm old_eax_ptr, 4
.comm old_eip, 4
.comm old_cs, 4
.comm old_eflags, 4
.comm pagefaultcr2, 4
.comm loadedcr3, 4

View File

@@ -52,11 +52,13 @@ _PROTOTYPE( void vir_outsw, (u16_t port, struct proc *proc, u32_t vir, size_t co
_PROTOTYPE( void i386_updatepde, (int pde, u32_t val));
_PROTOTYPE( void i386_freepde, (int pde));
_PROTOTYPE( void getcr3val, (void));
_PROTOTYPE( void switchedcr3, (void));
/* exception.c */
_PROTOTYPE( void exception, (unsigned vec_nr, u32_t trap_errno,
u32_t old_eip, U16_t old_cs, u32_t old_eflags) );
u32_t old_eip, U16_t old_cs, u32_t old_eflags,
u32_t *old_eip_ptr, u32_t *old_eax_ptr, u32_t pagefaultcr2) );
/* klib386.s */
_PROTOTYPE( void level0, (void (*func)(void)) );

View File

@@ -14,11 +14,11 @@
#include "proto.h"
#include "../../proc.h"
#include "../../debug.h"
#define CR0_EM 0x0004 /* set to enable trap on any FP instruction */
FORWARD _PROTOTYPE( void ser_debug, (int c));
FORWARD _PROTOTYPE( void ser_dump_stats, (void));
PUBLIC void arch_shutdown(int how)
{
@@ -139,39 +139,65 @@ PUBLIC void do_ser_debug()
PRIVATE void ser_debug(int c)
{
int u = 0;
do_serial_debug++;
kprintf("ser_debug: %d\n", c);
/* Disable interrupts so that we get a consistent state. */
if(!intr_disabled()) { lock; u = 1; };
switch(c)
{
case '1':
ser_dump_proc();
break;
case '2':
ser_dump_stats();
ser_dump_queues();
break;
#define TOGGLECASE(ch, flag) \
case ch: { \
if(verboseflags & flag) { \
verboseflags &= ~flag; \
printf("%s disabled\n", #flag); \
} else { \
verboseflags |= flag; \
printf("%s enabled\n", #flag); \
} \
break; \
}
TOGGLECASE('8', VF_SCHEDULING)
TOGGLECASE('9', VF_PICKPROC)
}
do_serial_debug--;
if(u) { unlock; }
}
PRIVATE void printslot(struct proc *pp)
PRIVATE void printslot(struct proc *pp, int level)
{
static int level = 0;
struct proc *depproc = NULL;
int dep = NONE;
#define COL { int i; for(i = 0; i < level; i++) printf("> "); }
if(level >= NR_PROCS) {
kprintf("loop??\n");
return;
}
level++;
if(pp->p_ready && pp->p_rts_flags) {
printf("HUH? p_ready but rts flags!\n");
}
kprintf("%*s %d: %s %d prio %d/%d time %d/%d cr3 0x%lx rts %s misc %s ",
level, "",
if(!pp->p_ready && !pp->p_rts_flags) {
printf("HUH? not p_ready but no rts flags!\n");
}
COL
kprintf("%d: %s %d prio %d/%d time %d/%d cr3 0x%lx rts %s misc %s ready %d",
proc_nr(pp), pp->p_name, pp->p_endpoint,
pp->p_priority, pp->p_max_priority, pp->p_user_time,
pp->p_sys_time, pp->p_seg.p_cr3,
rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags));
rtsflagstr(pp->p_rts_flags), miscflagstr(pp->p_misc_flags),
pp->p_ready);
if(pp->p_rts_flags & SENDING) {
dep = pp->p_sendto_e;
@@ -201,65 +227,46 @@ PRIVATE void printslot(struct proc *pp)
} else {
kprintf("\n");
}
kprintf("%*s ", level, "");
COL
proc_stacktrace(pp);
if(pp->p_rts_flags & VMREQUEST) {
COL
printf("vmrequest set with: %s\n", pp->p_vmrequest.stacktrace);
}
if(depproc)
printslot(depproc);
level--;
printslot(depproc, level+1);
}
PUBLIC void ser_dump_queues()
{
int q;
for(q = 0; q < NR_SCHED_QUEUES; q++) {
struct proc *p;
if(rdy_head[q])
printf("%2d: ", q);
for(p = rdy_head[q]; p; p = p->p_nextready) {
printf("%s / %d ", p->p_name, p->p_endpoint);
}
printf("\n");
}
}
PUBLIC void ser_dump_proc()
{
struct proc *pp;
int u = 0;
/* Disable interrupts so that we get a consistent state. */
if(!intr_disabled()) { lock; u = 1; };
CHECK_RUNQUEUES;
for (pp= BEG_PROC_ADDR; pp < END_PROC_ADDR; pp++)
{
if (pp->p_rts_flags & SLOT_FREE)
continue;
printslot(pp);
printslot(pp, 0);
}
if(u) { unlock; }
}
PRIVATE void ser_dump_stats()
{
kprintf("ipc_stats:\n");
kprintf("deadproc: %d\n", ipc_stats.deadproc);
kprintf("bad_endpoint: %d\n", ipc_stats.bad_endpoint);
kprintf("dst_not_allowed: %d\n", ipc_stats.dst_not_allowed);
kprintf("bad_call: %d\n", ipc_stats.bad_call);
kprintf("call_not_allowed: %d\n", ipc_stats.call_not_allowed);
kprintf("bad_buffer: %d\n", ipc_stats.bad_buffer);
kprintf("deadlock: %d\n", ipc_stats.deadlock);
kprintf("not_ready: %d\n", ipc_stats.not_ready);
kprintf("src_died: %d\n", ipc_stats.src_died);
kprintf("dst_died: %d\n", ipc_stats.dst_died);
kprintf("no_priv: %d\n", ipc_stats.no_priv);
kprintf("bad_size: %d\n", ipc_stats.bad_size);
kprintf("bad_senda: %d\n", ipc_stats.bad_senda);
if (ex64hi(ipc_stats.total))
{
kprintf("total: %x:%08x\n", ex64hi(ipc_stats.total),
ex64lo(ipc_stats.total));
}
else
kprintf("total: %u\n", ex64lo(ipc_stats.total));
kprintf("sys_stats:\n");
kprintf("bad_req: %d\n", sys_stats.bad_req);
kprintf("not_allowed: %d\n", sys_stats.not_allowed);
if (ex64hi(sys_stats.total))
{
kprintf("total: %x:%08x\n", ex64hi(sys_stats.total),
ex64lo(sys_stats.total));
}
else
kprintf("total: %u\n", ex64lo(sys_stats.total));
}
#if SPROFILE

View File

@@ -1,15 +0,0 @@
.define _last_cr3
#define LOADCR3WITHEAX(type, newcr3, ptproc) ;\
sseg inc (_cr3switch) ;\
sseg mov eax, newcr3 ;\
sseg cmp (_last_cr3), eax ;\
jz 8f ;\
mov cr3, eax ;\
sseg inc (_cr3reload) ;\
sseg mov (_last_cr3), eax ;\
sseg mov eax, (ptproc) ;\
sseg mov (_ptproc), eax ;\
8: