kernel: handle pagefaults in vm_memset()

This commit is contained in:
Arne Welzel 2012-09-22 19:58:05 +00:00 committed by Ben Gras
parent e61268c454
commit 0617743bd1
3 changed files with 70 additions and 42 deletions

View file

@ -128,6 +128,21 @@ static phys_bytes createpde(
/* Return the linear address of the start of the new mapping. */ /* Return the linear address of the start of the new mapping. */
return I386_BIG_PAGE_SIZE*pde + offset; return I386_BIG_PAGE_SIZE*pde + offset;
} }
/*===========================================================================*
* check_resumed_caller *
*===========================================================================*/
static int check_resumed_caller(struct proc *caller)
{
/* Returns the result from VM if caller was resumed, otherwise OK. */
if (caller && (caller->p_misc_flags & MF_KCALL_RESUME)) {
assert(caller->p_vmrequest.vmresult != VMSUSPEND);
return caller->p_vmrequest.vmresult;
}
return OK;
}
/*===========================================================================* /*===========================================================================*
* lin_lin_copy * * lin_lin_copy *
@ -557,50 +572,68 @@ static void vm_print(u32_t *root)
} }
#endif #endif
int vm_memset(endpoint_t who, phys_bytes ph, const u8_t c, phys_bytes bytes) /*===========================================================================*
* vmmemset *
*===========================================================================*/
int vm_memset(struct proc* caller, endpoint_t who, phys_bytes ph, int c,
phys_bytes count)
{ {
u32_t p; u32_t pattern;
struct proc *whoptr = NULL; struct proc *whoptr = NULL;
phys_bytes cur_ph = ph;
phys_bytes left = count;
phys_bytes ptr, chunk, pfa = 0;
int new_cr3, r = OK;
if ((r = check_resumed_caller(caller)) != OK)
return r;
/* NONE for physical, otherwise virtual */ /* NONE for physical, otherwise virtual */
if(who != NONE) { if (who != NONE && !(whoptr = endpoint_lookup(who)))
int n; return ESRCH;
if(!isokendpt(who, &n)) return ESRCH;
whoptr = proc_addr(n); c &= 0xFF;
} pattern = c | (c << 8) | (c << 16) | (c << 24);
p = c | (c << 8) | (c << 16) | (c << 24);
assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v); assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v);
assert(!catch_pagefaults); assert(!catch_pagefaults);
catch_pagefaults=1; catch_pagefaults = 1;
/* With VM, we have to map in the memory (virtual or physical). /* We can memset as many bytes as we have remaining,
* We can do this 4MB at a time. * or as many as remain in the 4MB chunk we mapped in.
*/ */
while(bytes > 0) { while (left > 0) {
int changed = 0; new_cr3 = 0;
phys_bytes chunk = bytes, ptr, pfa; chunk = left;
ptr = createpde(whoptr, ph, &chunk, 0, &changed); ptr = createpde(whoptr, cur_ph, &chunk, 0, &new_cr3);
if(changed)
reload_cr3();
/* We can memset as many bytes as we have remaining, if (new_cr3)
* or as many as remain in the 4MB chunk we mapped in. reload_cr3();
*/
if((pfa=phys_memset(ptr, p, chunk))) { /* If a page fault happens, pfa is non-null */
printf("kernel memset pagefault\n"); if ((pfa = phys_memset(ptr, pattern, chunk))) {
break;
/* If a process pagefaults, VM may help out */
if (whoptr) {
vm_suspend(caller, whoptr, ph, count,
VMSTYPE_KERNELCALL);
assert(catch_pagefaults);
catch_pagefaults = 0;
return VMSUSPEND;
}
/* Pagefault when phys copying ?! */
panic("vm_memset: pf %lx addr=%lx len=%lu\n",
pfa , ptr, chunk);
} }
bytes -= chunk;
ph += chunk; cur_ph += chunk;
left -= chunk;
} }
assert(catch_pagefaults);
catch_pagefaults=0;
assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v); assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v);
assert(catch_pagefaults);
catch_pagefaults = 0;
return OK; return OK;
} }
@ -647,12 +680,8 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
procs[i] = p; procs[i] = p;
} }
if(caller && (caller->p_misc_flags & MF_KCALL_RESUME)) { if ((r = check_resumed_caller(caller)) != OK)
assert(caller->p_vmrequest.vmresult != VMSUSPEND); return r;
if(caller->p_vmrequest.vmresult != OK) {
return caller->p_vmrequest.vmresult;
}
}
if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset, if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset,
procs[_DST_], vir_addr[_DST_]->offset, bytes)) != OK) { procs[_DST_], vir_addr[_DST_]->offset, bytes)) != OK) {

View file

@ -171,8 +171,8 @@ int data_copy_vmcheck(struct proc *, endpoint_t from, vir_bytes
phys_bytes umap_virtual(struct proc* rp, int seg, vir_bytes vir_addr, phys_bytes umap_virtual(struct proc* rp, int seg, vir_bytes vir_addr,
vir_bytes bytes); vir_bytes bytes);
phys_bytes seg2phys(u16_t); phys_bytes seg2phys(u16_t);
int vm_memset(endpoint_t who, int vm_memset(struct proc *caller, endpoint_t who, phys_bytes dst,
phys_bytes source, u8_t pattern, phys_bytes count); int pattern, phys_bytes count);
int intr_init(int); int intr_init(int);
void halt_cpu(void); void halt_cpu(void);
void arch_init(void); void arch_init(void);

View file

@ -17,9 +17,8 @@
int do_memset(struct proc * caller, message * m_ptr) int do_memset(struct proc * caller, message * m_ptr)
{ {
/* Handle sys_memset(). This writes a pattern into the specified memory. */ /* Handle sys_memset(). This writes a pattern into the specified memory. */
unsigned char c = m_ptr->MEM_PATTERN; vm_memset(caller, m_ptr->MEM_PROCESS, (phys_bytes) m_ptr->MEM_PTR,
vm_memset(m_ptr->MEM_PROCESS, (phys_bytes) m_ptr->MEM_PTR, m_ptr->MEM_PATTERN, (phys_bytes) m_ptr->MEM_COUNT);
c, (phys_bytes) m_ptr->MEM_COUNT);
return(OK); return(OK);
} }