Added shared info/data pages and removed UENVS
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 22 Apr 2009 22:03:54 +0000 (15:03 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 25 Apr 2009 02:49:14 +0000 (19:49 -0700)
Changed the memory mappings and create per-process shared info (RO) and
shared data (RW) pages at specific locations in the address space.  Plus
assorted changes to pmap and env to handle the loss of UENVS and the new
mappings.  Also had to adjust userspace slightly to use the new labels.
Will need to sort the TODOs when we create actual structures to go in
each shared page.

inc/env.h
inc/lib.h
inc/memlayout.h
kern/env.c
kern/pmap.c
kern/trap.c
lib/entry.S
lib/libmain.c

index f9c19db..537555f 100644 (file)
--- a/inc/env.h
+++ b/inc/env.h
@@ -39,17 +39,19 @@ typedef int32_t envid_t;
 #define ENV_NOT_RUNNABLE       2
 
 struct Env {
-       trapframe_t env_tf;     // Saved registers
+       trapframe_t env_tf;                     // Saved registers
        LIST_ENTRY(env_t) env_link;     // Free list link pointers
-       envid_t env_id;                 // Unique environment identifier
+       envid_t env_id;                         // Unique environment identifier
        envid_t env_parent_id;          // env_id of this env's parent
        unsigned env_status;            // Status of the environment
-       uint32_t env_runs;              // Number of times environment has run
+       uint32_t env_runs;                      // Number of times environment has run
 
        // Address space
-       pde_t *env_pgdir;               // Kernel virtual address of page dir
-       physaddr_t env_cr3;             // Physical address of page dir
-
+       pde_t *env_pgdir;                       // Kernel virtual address of page dir
+       physaddr_t env_cr3;                     // Physical address of page dir
+       // TODO - give these two proper types (pointers to structs)
+       void* env_procinfo;     // KVA of per-process shared info table (RO)
+       void* env_procdata;     // KVA of per-process shared data table (RW)
 };
 
 #endif // !ROS_INC_ENV_H
index 31aa564..ccbee30 100644 (file)
--- a/inc/lib.h
+++ b/inc/lib.h
 // libos.c or entry.S
 extern char *binaryname;
 extern volatile env_t *env;
-extern volatile env_t envs[NENV];
+// will need to change these types when we have real structs
+// seems like they need to be either arrays [] or functions () for it to work
+extern volatile uint8_t procinfo[];
+extern volatile uint8_t procdata[];
 extern volatile page_t pages[];
 void   exit(void);
 
index 91f0ef6..2c6fc5b 100644 (file)
  *                     |  Cur. Page Table (User R-)   | R-/R-  PTSIZE
  *    UVPT      ---->  +------------------------------+ 0xbf400000
  *                     |          RO PAGES            | R-/R-  PTSIZE
- *    UPAGES    ---->  +------------------------------+ 0xbf000000
- *                     |           RO ENVS            | R-/R-  PTSIZE
- * UTOP,UENVS ------>  +------------------------------+ 0xbec00000
- * UXSTACKTOP -/       |     User Exception Stack     | RW/RW  PGSIZE
- *                     +------------------------------+ 0xbebff000
+ *    UPAGES    ---->  +------------------------------+ 0xbf000000      --+
+ *                     |  Unmapped (future expansion) | --/--             |
+ *                     +------------------------------+ 0xbec01000      PTSIZE
+ *                     |     Per-Process R/O Info     | R-/R-  PGSIZE     |
+ * UTOP, UINFO  ---->  +------------------------------+ 0xbec00000      --+
+ *                     |  Unmapped (future expansion) | --/--             |
+ *                     +------------------------------+ 0xbe801000      PTSIZE
+ *                     |     Per-Process R/W Data     | RW/RW  PGSIZE     |
+ * UDATA,UXSTACKTOP--> +------------------------------+ 0xbe800000      --+
+ *                     |     User Exception Stack     | RW/RW  PGSIZE
+ *                     +------------------------------+ 0xbe7ff000
  *                     |       Empty Memory (*)       | --/--  PGSIZE
- *    USTACKTOP  --->  +------------------------------+ 0xbebfe000
+ *    USTACKTOP  --->  +------------------------------+ 0xbe7fe000
  *                     |      Normal User Stack       | RW/RW  PGSIZE
- *                     +------------------------------+ 0xbebfd000
+ *                     +------------------------------+ 0xbe7fd000
  *                     |                              |
  *                     |                              |
  *                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 #define UVPT           (ULIM - PTSIZE)
 // Read-only copies of the Page structures
 #define UPAGES         (UVPT - PTSIZE)
-// Read-only copies of the global env structures
-#define UENVS          (UPAGES - PTSIZE)
+// Read-only, per-process shared info structures
+#define UINFO          (UPAGES - PTSIZE)
+#define UINFO_PAGES 1
 
 /*
  * Top of user VM. User can manipulate VA from UTOP-1 and down!
  */
 
 // Top of user-accessible VM
-#define UTOP           UENVS
+#define UTOP           UINFO
+
+// Read-write, per-process shared data structures
+#define UDATA          (UTOP - PTSIZE)
+#define UDATA_PAGES 1
+
 // Top of one-page user exception stack
-#define UXSTACKTOP     UTOP
+#define UXSTACKTOP     UDATA
 // Next page left invalid to guard against exception stack overflow; then:
 // Top of normal user stack
-#define USTACKTOP      (UTOP - 2*PGSIZE)
+#define USTACKTOP      (UXSTACKTOP - 2*PGSIZE)
 
 // Where user programs generally begin
 #define UTEXT          (2*PTSIZE)
index 28f0474..f4f3191 100644 (file)
@@ -98,18 +98,25 @@ static int
 env_setup_vm(env_t *e)
 {
        int i, r;
-       page_t *p = NULL;
-
-       // Allocate a page for the page directory
-       if ((r = page_alloc(&p)) < 0)
+       page_t *pgdir = NULL, *pginfo = NULL, *pgdata = NULL;
+
+       // Allocate pages for the page directory, shared info, and shared data pages
+       r = page_alloc(&pgdir);
+       r = page_alloc(&pginfo);
+       r = page_alloc(&pgdata);
+       if (r < 0) {
+               page_free(pgdir);
+               page_free(pginfo);
                return r;
-       
+       }
+
        // Now, set e->env_pgdir and e->env_cr3,
        // and initialize the page directory.
        //
        // Hint:
        //    - The VA space of all envs is identical above UTOP
        //      (except at VPT and UVPT, which we've set below).
+       //      (and not for UINFO either)
        //      See inc/memlayout.h for permissions and layout.
        //      Can you use boot_pgdir as a template?  Hint: Yes.
        //      (Make sure you got the permissions right in Lab 2.)
@@ -119,26 +126,47 @@ env_setup_vm(env_t *e)
        //      mapped above UTOP -- but you do need to increment
        //      env_pgdir's pp_ref!
 
-       p->pp_ref++;
-       e->env_pgdir = page2kva(p);
-       e->env_cr3 = page2pa(p);
+       // need to up pgdir's reference, since it will never be done elsewhere
+       pgdir->pp_ref++;
+       e->env_pgdir = page2kva(pgdir);
+       e->env_cr3 = page2pa(pgdir);
+       e->env_procinfo = page2kva(pginfo);
+       e->env_procdata = page2kva(pgdata);
 
        memset(e->env_pgdir, 0, PGSIZE);
+       memset(e->env_procinfo, 0, PGSIZE);
+       memset(e->env_procdata, 0, PGSIZE);
 
        // should be able to do this so long as boot_pgdir never has
        // anything put below UTOP
        memcpy(e->env_pgdir, boot_pgdir, PGSIZE);
-       
+
        // something like this.  TODO, if you want
        //memcpy(&e->env_pgdir[PDX(UTOP)], &boot_pgdir[PDX(UTOP)], PGSIZE - PDX(UTOP));
        // check with
        // assert(memcmp(e->env_pgdir, boot_pgdir, PGSIZE) == 0);
-       
+
        // VPT and UVPT map the env's own page table, with
        // different permissions.
        e->env_pgdir[PDX(VPT)]  = e->env_cr3 | PTE_P | PTE_W;
        e->env_pgdir[PDX(UVPT)] = e->env_cr3 | PTE_P | PTE_U;
 
+       // Insert the per-process info and data pages into this process's pgdir
+       // I don't want to do these two pages later (like with the stack), since
+       // the kernel wants to keep pointers to it easily.
+       // Could place all of this with a function that maps a shared memory page
+       // that can work between any two address spaces or something.
+       r = page_insert(e->env_pgdir, pginfo, (void*)UINFO, PTE_U);
+       r = page_insert(e->env_pgdir, pgdata, (void*)UDATA, PTE_U | PTE_W);
+       if (r < 0) {
+               // note that we can't currently deallocate the pages created by
+               // pgdir_walk (inside insert).  should be able to gather them up when
+               // we destroy environments and their page tables.
+               page_free(pgdir);
+               page_free(pginfo);
+               page_free(pgdata);
+               return r;
+       }
        return 0;
 }
 
@@ -169,7 +197,7 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
        if (generation <= 0)    // Don't create a negative env_id.
                generation = 1 << ENVGENSHIFT;
        e->env_id = generation | (e - envs);
-       
+
        // Set the basic status variables.
        e->env_parent_id = parent_id;
        e->env_status = ENV_RUNNABLE;
@@ -182,7 +210,7 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
        memset(&e->env_tf, 0, sizeof(e->env_tf));
 
        // Set up appropriate initial values for the segment registers.
-       // GD_UD is the user data segment selector in the GDT, and 
+       // GD_UD is the user data segment selector in the GDT, and
        // GD_UT is the user text segment selector (see inc/memlayout.h).
        // The low 2 bits of each segment register contains the
        // Requestor Privilege Level (RPL); 3 means user mode.
@@ -199,6 +227,12 @@ env_alloc(env_t **newenv_store, envid_t parent_id)
        LIST_REMOVE(e, env_link);
        *newenv_store = e;
 
+       // TODO: for now, the only info at procinfo is this env's struct
+       // note that we need to copy this over every time we make a change to env
+       // that we want userspace to see.  also note that we don't even want to
+       // show them all of env, only specific things like PID, PPID, etc
+       memcpy(e->env_procinfo, e, sizeof(env_t));
+
        cprintf("[%08x] new env %08x\n", curenv ? curenv->env_id : 0, e->env_id);
        return 0;
 }
@@ -268,7 +302,7 @@ segment_alloc(env_t *e, void *va, size_t len)
 static void
 load_icode(env_t *e, uint8_t *binary, size_t size)
 {
-       // Hints: 
+       // Hints:
        //  Load each program segment into virtual memory
        //  at the address specified in the ELF section header.
        //  You should only load segments with ph->p_type == ELF_PROG_LOAD.
@@ -305,7 +339,7 @@ load_icode(env_t *e, uint8_t *binary, size_t size)
        // make sure we have proghdrs to load
        assert(elfhdr->e_phnum);
 
-       // to actually access any pages alloc'd for this environment, we 
+       // to actually access any pages alloc'd for this environment, we
        // need to have the hardware use this environment's page tables.
        // we can use e's tables as long as we want, since it has the same
        // mappings for the kernel as does boot_pgdir
@@ -315,7 +349,7 @@ load_icode(env_t *e, uint8_t *binary, size_t size)
        for (i = 0; i < elfhdr->e_phnum; i++, phdr++) {
                if (phdr->p_type != ELF_PROG_LOAD)
                        continue;
-               // seg alloc creates PTE_U|PTE_W pages.  if you ever want to change 
+               // seg alloc creates PTE_U|PTE_W pages.  if you ever want to change
                // this, there will be issues with overlapping sections
                segment_alloc(e, (void*)phdr->p_va, phdr->p_memsz);
                memcpy((void*)phdr->p_va, binary + phdr->p_offset, phdr->p_filesz);
@@ -336,10 +370,10 @@ load_icode(env_t *e, uint8_t *binary, size_t size)
 // before running the first user-mode environment.
 // The new env's parent ID is set to 0.
 //
-// Where does the result go? 
+// Where does the result go?
 // By convention, envs[0] is the first environment allocated, so
 // whoever calls env_create simply looks for the newly created
-// environment there. 
+// environment there.
 void
 env_create(uint8_t *binary, size_t size)
 {
@@ -353,7 +387,7 @@ env_create(uint8_t *binary, size_t size)
 
 //
 // Frees env e and all memory it uses.
-// 
+//
 void
 env_free(env_t *e)
 {
@@ -407,7 +441,7 @@ env_free(env_t *e)
 // to the caller).
 //
 void
-env_destroy(env_t *e) 
+env_destroy(env_t *e)
 {
        env_free(e);
 
@@ -463,7 +497,7 @@ env_run(env_t *e)
        //      e->env_tf.  Go back through the code you wrote above
        //      and make sure you have set the relevant parts of
        //      e->env_tf to sensible values.
-       
+
                // would set the curenv->env_status if we had more states
        if (e != curenv) {
                curenv = e;
index 4f06ffa..0504c35 100644 (file)
@@ -472,21 +472,12 @@ i386_vm_init(void)
 
        //////////////////////////////////////////////////////////////////////
        // Make 'envs' point to an array of size 'NENV' of 'env_t'.
-       // Map this array read-only by the user at linear address UENVS
-       // (ie. perm = PTE_U | PTE_P).
-       // Permissions:
-       //    - envs itself -- kernel RW, user NONE
-       //    - the image of envs mapped at UENVS  -- kernel R, user R
+       // No longer mapping ENVS into the address space
        
        // round up to the nearest page
        size_t env_array_size = ROUNDUP(NENV*sizeof(env_t), PGSIZE);
        envs = (env_t *)boot_alloc(env_array_size, PGSIZE);
        memset(envs, 0, env_array_size);
-       if (env_array_size > PTSIZE) {
-               warn("env_array_size bigger than PTSIZE, userland will not see all environments");
-               env_array_size = PTSIZE;
-       }
-       boot_map_segment(pgdir, UENVS, env_array_size, PADDR(envs), PTE_U | PTE_G);
 
        // Check that the initial page directory has been set up correctly.
        check_boot_pgdir(pse);
@@ -573,11 +564,6 @@ check_boot_pgdir(bool pse)
        for (i = 0; i < n; i += PGSIZE)
                assert(check_va2pa(pgdir, UPAGES + i) == PADDR(pages) + i);
 
-       // check envs array (new test for lab 3)
-       n = ROUNDUP(NENV*sizeof(env_t), PGSIZE);
-       for (i = 0; i < n; i += PGSIZE)
-               assert(check_va2pa(pgdir, UENVS + i) == PADDR(envs) + i);
-
        // check phys mem
        //for (i = 0; KERNBASE + i != 0; i += PGSIZE)
        // adjusted check to account for only mapping avail mem
@@ -599,7 +585,6 @@ check_boot_pgdir(bool pse)
                case PDX(UVPT):
                case PDX(KSTACKTOP-1):
                case PDX(UPAGES):
-               case PDX(UENVS):
                case PDX(LAPIC_BASE): // LAPIC mapping.  TODO: remove when MTRRs are up
                        assert(pgdir[i]);
                        break;
@@ -619,7 +604,7 @@ check_boot_pgdir(bool pse)
        // check permissions
        // user read-only.  check for user and write, should be only user
        // eagle-eyed viewers should be able to explain the extra cases
-       for (i = UENVS; i < ULIM; i+=PGSIZE) {
+       for (i = UTOP; i < ULIM; i+=PGSIZE) {
                pte = get_vaperms(pgdir, i);
                if ((pte & PTE_P) && (i != UVPT+(VPT>>10))) {
                        if (pte & PTE_PS) {
@@ -791,9 +776,13 @@ page_alloc(page_t **pp_store)
 void
 page_free(page_t *pp)
 {
-       if (pp->pp_ref)
-               panic("Attempting to free page with non-zero reference count!");
-       LIST_INSERT_HEAD(&page_free_list, pp, pp_link);
+       // this check allows us to call this on null ptrs, which helps when
+       // allocating and checking for errors on several pages at once
+       if (pp) {
+               if (pp->pp_ref)
+                       panic("Attempting to free page with non-zero reference count!");
+               LIST_INSERT_HEAD(&page_free_list, pp, pp_link);
+       }
 }
 
 //
index c9e73c9..a9893fa 100644 (file)
@@ -192,7 +192,7 @@ static void
 void
 (IN_HANDLER trap)(trapframe_t *tf)
 {
-       cprintf("Incoming TRAP frame at %p\n", tf);
+       //cprintf("Incoming TRAP frame at %p\n", tf);
 
        if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
                print_trapframe(tf);
index 9fd1fc9..e8abca5 100644 (file)
@@ -6,8 +6,10 @@
 
 // Define the global symbols 'envs', 'pages', 'vpt', and 'vpd'
 // so that they can be used in C as if they were ordinary global arrays.
-       .globl envs
-       .set envs, UENVS
+       .globl procinfo
+       .set procinfo, UINFO
+       .globl procdata
+       .set procdata, UDATA
        .globl pages
        .set pages, UPAGES
        .globl vpt
index bc48d68..afdc74d 100644 (file)
@@ -12,8 +12,9 @@ void
 libmain(int argc, char **argv)
 {
        // set env to point at our env structure in envs[].
-       
-       env = &envs[ENVX(sys_getenvid())];
+       // TODO: for now, the kernel just copies our env struct to the beginning of
+       // proc_info.  When we figure out what we want there, change this.
+       env = (env_t*)procinfo;
 
        // save the name of the program so that panic() can use it
        if (argc > 0)