]> Zhao Yanbai Git Server - minix.git/commitdiff
kernel: handle pagefaults in vm_memset()
authorArne Welzel <arne.welzel@gmail.com>
Sat, 22 Sep 2012 19:58:05 +0000 (19:58 +0000)
committerBen Gras <ben@minix3.org>
Wed, 26 Sep 2012 00:17:59 +0000 (02:17 +0200)
kernel/arch/i386/memory.c
kernel/proto.h
kernel/system/do_memset.c

index 776fec03a18bd6ac2f63e5a8f281a15d0fe2efbf..3446a590c1fefbde979177a52e8e9a85fe16d0e4 100644 (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;
 
-       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) {
index aa97024800569f30a38640d32a031191b893a9a6..15d761cde5a3eaa741f0823ec273c7be27aab98a 100644 (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);
index f7db063d83a35430f5dc097c1cbdf45fad343d72..cea520f43718c0dc7ca3f82590ef7255aeb7963c 100644 (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);
 }