From: Arne Welzel Date: Sat, 22 Sep 2012 19:58:05 +0000 (+0000) Subject: kernel: handle pagefaults in vm_memset() X-Git-Tag: v3.2.1~305 X-Git-Url: http://zhaoyanbai.com/repos/Bv9ARM.ch12.html?a=commitdiff_plain;h=0617743bd1bc58603f9f8fda2baf299e3be153a9;p=minix.git kernel: handle pagefaults in vm_memset() --- diff --git a/kernel/arch/i386/memory.c b/kernel/arch/i386/memory.c index 776fec03a..3446a590c 100644 --- a/kernel/arch/i386/memory.c +++ b/kernel/arch/i386/memory.c @@ -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; - assert(get_cpulocal_var(ptproc)->p_seg.p_cr3_v); + 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); + + 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; + } - /* 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; + /* Pagefault when phys copying ?! */ + panic("vm_memset: pf %lx addr=%lx len=%lu\n", + pfa , ptr, chunk); } - bytes -= chunk; - ph += chunk; - } - assert(catch_pagefaults); - catch_pagefaults=0; + cur_ph += chunk; + left -= chunk; + } 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) { diff --git a/kernel/proto.h b/kernel/proto.h index aa9702480..15d761cde 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -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); diff --git a/kernel/system/do_memset.c b/kernel/system/do_memset.c index f7db063d8..cea520f43 100644 --- a/kernel/system/do_memset.c +++ b/kernel/system/do_memset.c @@ -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); }