kernel: handle pagefaults in vm_memset()
This commit is contained in:
parent
e61268c454
commit
0617743bd1
3 changed files with 70 additions and 42 deletions
|
@ -129,6 +129,21 @@ static phys_bytes createpde(
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
p = c | (c << 8) | (c << 16) | (c << 24);
|
c &= 0xFF;
|
||||||
|
pattern = 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)
|
|
||||||
|
if (new_cr3)
|
||||||
reload_cr3();
|
reload_cr3();
|
||||||
|
|
||||||
/* We can memset as many bytes as we have remaining,
|
/* If a page fault happens, pfa is non-null */
|
||||||
* or as many as remain in the 4MB chunk we mapped in.
|
if ((pfa = phys_memset(ptr, pattern, chunk))) {
|
||||||
*/
|
|
||||||
if((pfa=phys_memset(ptr, p, chunk))) {
|
/* If a process pagefaults, VM may help out */
|
||||||
printf("kernel memset pagefault\n");
|
if (whoptr) {
|
||||||
break;
|
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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue