Procdata and procinfo can be more than a page long
authorBarret Rhoden <brho@cs.berkeley.edu>
Sat, 9 Jan 2010 02:47:29 +0000 (18:47 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 14 Jan 2010 23:21:09 +0000 (15:21 -0800)
These regions need to be contiguous so that the kernel can access them
via kernel addresses.

kern/include/ros/procdata.h
kern/src/env.c
kern/src/pmap.c
kern/src/process.c

index 2bdeec2..dddbae4 100644 (file)
@@ -24,12 +24,12 @@ typedef struct procinfo {
 #define PROCINFO_NUM_PAGES  ((sizeof(procinfo_t)-1)/PGSIZE + 1)        
 
 typedef struct procdata {
-#ifdef __i386__
-       segdesc_t *ldt;
-#endif
        // The actual ring buffers for communicating with user space
        syscall_sring_t  syscallring;  // Per-process ring buffer for async syscalls
        sysevent_sring_t syseventring; // Per-process ring buffer for async sysevents
+#ifdef __i386__
+       segdesc_t *ldt;
+#endif
 } procdata_t;
 #define PROCDATA_NUM_PAGES  ((sizeof(procdata_t)-1)/PGSIZE + 1)
 
index 696e373..e60d595 100644 (file)
@@ -41,8 +41,6 @@ WRITES(e->env_pgdir, e->env_cr3, e->env_procinfo, e->env_procdata)
 {
        int i, r;
        page_t *pgdir = NULL;
-       page_t *pginfo[PROCINFO_NUM_PAGES] = {NULL};
-       page_t *pgdata[PROCDATA_NUM_PAGES] = {NULL};
        static page_t * RO shared_page = 0;
 
        /*
@@ -78,36 +76,25 @@ WRITES(e->env_pgdir, e->env_cr3, e->env_procinfo, e->env_procdata)
        e->env_pgdir[PDX(VPT)]  = PTE(LA2PPN(e->env_cr3), PTE_P | PTE_KERN_RW);
        e->env_pgdir[PDX(UVPT)] = PTE(LA2PPN(e->env_cr3), PTE_P | PTE_USER_RO);
 
-       /*
-        * Now allocate and insert all pages required for the shared
-        * procinfo structure into the page table
-        */
-       for(int i=0; i<PROCINFO_NUM_PAGES; i++) {
-               if(upage_alloc(e, &pginfo[i],1) < 0)
-                       goto env_setup_vm_error;
-               if(page_insert(e->env_pgdir, pginfo[i], (void*SNT)(UINFO + i*PGSIZE),
-                              PTE_USER_RO) < 0)
+       /* These need to be contiguous, so the kernel can alias them.  Note the
+        * pages return with a refcnt, but it's okay to insert them since we free
+        * them manually when the process is cleaned up. */
+       if (!(e->env_procinfo = get_cont_pages(LOG2_UP(PROCINFO_NUM_PAGES), 0)))
+               goto env_setup_vm_error_i;
+       if (!(e->env_procdata = get_cont_pages(LOG2_UP(PROCDATA_NUM_PAGES), 0)))
+               goto env_setup_vm_error_d;
+       for (int i = 0; i < PROCINFO_NUM_PAGES; i++) {
+               if (page_insert(e->env_pgdir, kva2page((void*)e->env_procinfo + i *
+                               PGSIZE), (void*SNT)(UINFO + i*PGSIZE), PTE_USER_RO) < 0)
                        goto env_setup_vm_error;
        }
-
-       /*
-        * Now allocate and insert all pages required for the shared
-        * procdata structure into the page table
-        */
-       for(int i=0; i<PROCDATA_NUM_PAGES; i++) {
-               if(upage_alloc(e, &pgdata[i],1) < 0)
-                       goto env_setup_vm_error;
-               if(page_insert(e->env_pgdir, pgdata[i], (void*SNT)(UDATA + i*PGSIZE),
-                              PTE_USER_RW) < 0)
+       for (int i = 0; i < PROCDATA_NUM_PAGES; i++) {
+               if (page_insert(e->env_pgdir, kva2page((void*)e->env_procdata + i *
+                               PGSIZE), (void*SNT)(UDATA + i*PGSIZE), PTE_USER_RW) < 0)
                        goto env_setup_vm_error;
        }
-
-       /*
-        * Now, set e->env_procinfo, and e->env_procdata to point to
-        * the proper pages just allocated and clear them out.
-        */
-       e->env_procinfo = (procinfo_t *SAFE) TC(page2kva(pginfo[0]));
-       e->env_procdata = (procdata_t *SAFE) TC(page2kva(pgdata[0]));
+       memset(e->env_procinfo, 0, sizeof(procinfo_t));
+       memset(e->env_procdata, 0, sizeof(procdata_t));
 
        /* Finally, set up the Global Shared Data page for all processes.
         * Can't be trusted, but still very useful at this stage for us.
@@ -130,13 +117,11 @@ WRITES(e->env_pgdir, e->env_cr3, e->env_procinfo, e->env_procdata)
        return 0;
 
 env_setup_vm_error:
+       free_cont_pages(e->env_procdata, LOG2_UP(PROCDATA_NUM_PAGES));
+env_setup_vm_error_d:
+       free_cont_pages(e->env_procinfo, LOG2_UP(PROCINFO_NUM_PAGES));
+env_setup_vm_error_i:
        page_free(shared_page);
-       for(int i=0; i< PROCDATA_NUM_PAGES; i++) {
-               page_free(pgdata[i]);
-       }
-       for(int i=0; i< PROCINFO_NUM_PAGES; i++) {
-               page_free(pginfo[i]);
-       }
        env_user_mem_free(e);
        page_free(pgdir);
        return -ENOMEM;
index cc12b7c..8b48c56 100644 (file)
@@ -68,6 +68,9 @@ void page_init(void)
         * from the memory free list
         */
        page_alloc_init();
+
+       static_assert(PROCINFO_NUM_PAGES <= PTSIZE);
+       static_assert(PROCDATA_NUM_PAGES <= PTSIZE);
 }
 
 /** 
index 4090b24..9d9624c 100644 (file)
@@ -317,6 +317,9 @@ static void __proc_free(struct proc *p)
 
        // Flush all mapped pages in the user portion of the address space
        env_user_mem_free(p);
+       /* These need to be free again, since they were allocated with a refcnt. */
+       free_cont_pages(p->env_procinfo, LOG2_UP(PROCINFO_NUM_PAGES));
+       free_cont_pages(p->env_procdata, LOG2_UP(PROCDATA_NUM_PAGES));
 
        // free the page directory
        pa = p->env_cr3;