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 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 *
@ -557,50 +572,68 @@ static void vm_print(u32_t *root)
}
#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;
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 */
if(who != NONE) {
int n;
if(!isokendpt(who, &n)) return ESRCH;
whoptr = proc_addr(n);
}
p = c | (c << 8) | (c << 16) | (c << 24);
if (who != NONE && !(whoptr = endpoint_lookup(who)))
return ESRCH;
c &= 0xFF;
pattern = c | (c << 8) | (c << 16) | (c << 24);
assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v);
assert(!catch_pagefaults);
catch_pagefaults=1;
catch_pagefaults = 1;
/* With VM, we have to map in the memory (virtual or physical).
* We can do this 4MB at a time.
/* We can memset as many bytes as we have remaining,
* or as many as remain in the 4MB chunk we mapped in.
*/
while(bytes > 0) {
int changed = 0;
phys_bytes chunk = bytes, ptr, pfa;
ptr = createpde(whoptr, ph, &chunk, 0, &changed);
if(changed)
reload_cr3();
while (left > 0) {
new_cr3 = 0;
chunk = left;
ptr = createpde(whoptr, cur_ph, &chunk, 0, &new_cr3);
/* We can memset as many bytes as we have remaining,
* or as many as remain in the 4MB chunk we mapped in.
*/
if((pfa=phys_memset(ptr, p, chunk))) {
printf("kernel memset pagefault\n");
break;
if (new_cr3)
reload_cr3();
/* If a page fault happens, pfa is non-null */
if ((pfa = phys_memset(ptr, pattern, chunk))) {
/* 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(catch_pagefaults);
catch_pagefaults = 0;
return OK;
}
@ -647,12 +680,8 @@ int vmcheck; /* if nonzero, can return VMSUSPEND */
procs[i] = p;
}
if(caller && (caller->p_misc_flags & MF_KCALL_RESUME)) {
assert(caller->p_vmrequest.vmresult != VMSUSPEND);
if(caller->p_vmrequest.vmresult != OK) {
return caller->p_vmrequest.vmresult;
}
}
if ((r = check_resumed_caller(caller)) != OK)
return r;
if((r=lin_lin_copy(procs[_SRC_], vir_addr[_SRC_]->offset,
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,
vir_bytes bytes);
phys_bytes seg2phys(u16_t);
int vm_memset(endpoint_t who,
phys_bytes source, u8_t pattern, phys_bytes count);
int vm_memset(struct proc *caller, endpoint_t who, phys_bytes dst,
int pattern, phys_bytes count);
int intr_init(int);
void halt_cpu(void);
void arch_init(void);

View file

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