]> Zhao Yanbai Git Server - minix.git/commitdiff
atomicity fix when enabling paging
authorTomas Hruby <tom@minix3.org>
Mon, 22 Mar 2010 07:42:52 +0000 (07:42 +0000)
committerTomas Hruby <tom@minix3.org>
Mon, 22 Mar 2010 07:42:52 +0000 (07:42 +0000)
- before enabling paging VM asks kernel to resize its segments. This
  may cause kernel to segfault if APIC is used and an interrupt
  happens between this and paging enabled. As these are 2 separate
  vmctl calls it is not atomic. This patch fixes this problem. VM does
  not ask kernel to resize the segments in a separate call anymore.
  The new segments limit is part of the "enable paging" call. It
  generalizes this call in such a way that more information can be
  passed as need be or the information may be completely different if
  another architecture requires this.

include/arch/i386/vm.h
include/minix/syslib.h
kernel/arch/i386/memory.c
kernel/proto.h
kernel/system/do_vmctl.c
lib/libsys/sys_vmctl.c
servers/vm/i386/pagetable.c

index ef0ff79d578cd8a51924a95c0e740939b48323ae..757a14a8eba6cd1c4447998effd298806bcc934f 100644 (file)
@@ -84,4 +84,15 @@ i386/vm.h
 #define CPUID1_ECX_SSE4_1      (1L << 19)
 #define CPUID1_ECX_SSE4_2      (1L << 20)
 
+#ifndef __ASSEMBLY__
+
+#include <minix/type.h>
+
+/* structure used by VM to pass data to the kernel while enabling paging */
+struct vm_ep_data {
+       struct mem_map  * mem_map;
+       vir_bytes       data_seg_limit;
+};
+#endif
+
 #endif /* __SYS_VM_386_H__ */
index bfad9ff6e4d02808a75952fbbe68fd74edee394c..430eda042d7ec99d2eee5145dea6d81864475078 100644 (file)
@@ -68,7 +68,7 @@ _PROTOTYPE( int sys_vmctl_get_cr3_i386, (endpoint_t who, u32_t *cr3)  );
 _PROTOTYPE( int sys_vmctl_get_memreq, (endpoint_t *who, vir_bytes *mem,
         vir_bytes *len, int *wrflag, endpoint_t *who_s, vir_bytes *mem_s,
         endpoint_t *) );
-_PROTOTYPE( int sys_vmctl_enable_paging, (struct mem_map *));
+_PROTOTYPE( int sys_vmctl_enable_paging, (void * data));
 
 _PROTOTYPE( int sys_readbios, (phys_bytes address, void *buf, size_t size));
 _PROTOTYPE( int sys_stime, (time_t boottime));
index ab20ecbc3de1844706b0c036c2e1810ae1c420ab..99745da743c1d4a467baff9a9529f06b7b0924bb 100644 (file)
@@ -4,6 +4,8 @@
 #include "../../proc.h"
 #include "../../vm.h"
 
+#include <machine/vm.h>
+
 #include <minix/type.h>
 #include <minix/syslib.h>
 #include <minix/cpufeature.h>
@@ -956,8 +958,37 @@ PUBLIC int arch_phys_map_reply(int index, vir_bytes addr)
        return OK;
 }
 
-PUBLIC int arch_enable_paging(void)
+PUBLIC int arch_enable_paging(struct proc * caller, message * m_ptr)
 {
+       struct vm_ep_data ep_data;
+       int r;
+
+       /*
+        * copy the extra data associated with the call from userspace
+        */
+       if((r=data_copy(caller->p_endpoint, (vir_bytes)m_ptr->SVMCTL_VALUE,
+               KERNEL, (vir_bytes) &ep_data, sizeof(ep_data))) != OK) {
+               printf("vmctl_enable_paging: data_copy failed! (%d)\n", r);
+               return r;
+       }
+
+       /*
+        * when turning paging on i386 we also change the segment limits to make
+        * the special mappings requested by the kernel reachable
+        */
+       if ((r = prot_set_kern_seg_limit(ep_data.data_seg_limit)) != OK)
+               return r;
+
+       /*
+        * install the new map provided by the call
+        */
+       if (newmap(caller, caller, ep_data.mem_map) != OK)
+               panic("arch_enable_paging: newmap failed");
+
+       FIXLINMSG(caller);
+       assert(caller->p_delivermsg_lin == umap_local(caller, D,
+                               caller->p_delivermsg_vir, sizeof(message)));
+
 #ifdef CONFIG_APIC
        /* if local APIC is enabled */
        if (lapic_addr) {
index c3261d39960da5d484a82101e1af945a1049c882..451bb9d71291ef04c4ddd651c97f9cc5af74ae5f 100644 (file)
@@ -173,7 +173,7 @@ _PROTOTYPE( void arch_do_syscall, (struct proc *proc)                       );
 _PROTOTYPE( int arch_phys_map, (int index, phys_bytes *addr,
        phys_bytes *len, int *flags));
 _PROTOTYPE( int arch_phys_map_reply, (int index, vir_bytes addr));
-_PROTOTYPE( int arch_enable_paging, (void));
+_PROTOTYPE( int arch_enable_paging, (struct proc * caller, message * m_ptr));
 
 _PROTOTYPE( int copy_msg_from_user, (struct proc * p, message * user_mbuf,
                                                        message * dst));
index 862e586a3143f8931965076a2c5b2c80813c2b1f..136b20b5522e75eff90d112dae97cf676c7cd738 100644 (file)
@@ -127,15 +127,7 @@ PUBLIC int do_vmctl(struct proc * caller, message * m_ptr)
                vm_init(p);
                if(!vm_running)
                        panic("do_vmctl: paging enabling failed");
-               if ((err = arch_enable_paging()) != OK) {
-                       return err;
-               }
-               if(newmap(caller, p, (struct mem_map *) m_ptr->SVMCTL_VALUE) != OK)
-                       panic("do_vmctl: newmap failed");
-               FIXLINMSG(p);
-               assert(p->p_delivermsg_lin ==
-                 umap_local(p, D, p->p_delivermsg_vir, sizeof(message)));
-               return OK;
+               return arch_enable_paging(caller, m_ptr);
        case VMCTL_KERN_PHYSMAP:
        {
                int i = m_ptr->SVMCTL_VALUE;
index 2bbe28f5bbbe3760cc958dd8aa6c49fdd06ee687..ad85216cd432705802260f90ea612411b1b4ae19 100644 (file)
@@ -64,12 +64,12 @@ PUBLIC int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem,
   return r;
 }
 
-PUBLIC int sys_vmctl_enable_paging(struct mem_map *map)
+PUBLIC int sys_vmctl_enable_paging(void * data)
 {
        message m;
        m.SVMCTL_WHO = SELF;
        m.SVMCTL_PARAM = VMCTL_ENABLE_PAGING;
-       m.SVMCTL_VALUE = (int) map;
+       m.SVMCTL_VALUE = (u32_t) data;
        return _kernel_call(SYS_VMCTL, &m);
 }
 
index c045cf9b7ebb11b52ab9caecefb2d60dc626fc05..1d9d8a9995e4c0a9f8dbbbe6201d1c6dd52e4f97 100644 (file)
@@ -639,7 +639,7 @@ PUBLIC void pt_init(phys_bytes usedlimit)
        int global_bit_ok = 0;
        int free_pde;
        int p;
-       vir_bytes kernlimit;
+       struct vm_ep_data ep_data;
        vir_bytes sparepages_mem;
        phys_bytes sparepages_ph;
 
@@ -803,13 +803,6 @@ PUBLIC void pt_init(phys_bytes usedlimit)
        /* first pde in use by process. */
        proc_pde = free_pde;
 
-       kernlimit = free_pde*I386_BIG_PAGE_SIZE;
-
-       /* Increase kernel segment to address this memory. */
-       if((r=sys_vmctl(SELF, VMCTL_I386_KERNELLIMIT, kernlimit)) != OK) {
-                panic("VMCTL_I386_KERNELLIMIT failed: %d", r);
-       }
-
        kpagedir = arch_map2vir(&vmproc[VMP_SYSTEM],
                pagedir_pde*I386_BIG_PAGE_SIZE);
 
@@ -822,8 +815,13 @@ PUBLIC void pt_init(phys_bytes usedlimit)
        pt_mapkernel(newpt);    /* didn't know about vm_dir pages earlier */
         pt_bind(newpt, vmp);
        
+       /* new segment limit for the kernel after paging is enabled */
+       ep_data.data_seg_limit = free_pde*I386_BIG_PAGE_SIZE;
+       /* the memory map which must be installed after paging is enabled */
+       ep_data.mem_map = vmp->vm_arch.vm_seg;
+
        /* Now actually enable paging. */
-       if(sys_vmctl_enable_paging(vmp->vm_arch.vm_seg) != OK)
+       if(sys_vmctl_enable_paging(&ep_data) != OK)
                panic("pt_init: enable paging failed");
 
         /* Back to reality - this is where the stack actually is. */