PTE_SHARE added.
[mit-jos.git] / lib / fork.c
blobe0a8a3ad97de812031065a233b1610b425d79e60
1 // implement fork from user space
3 #include <inc/string.h>
4 #include <inc/lib.h>
6 // PTE_COW marks copy-on-write page table entries.
7 // It is one of the bits explicitly allocated to user processes (PTE_AVAIL).
8 #define PTE_COW 0x800
11 // Custom page fault handler - if faulting page is copy-on-write,
12 // map in our own private writable copy.
14 static void
15 pgfault(struct UTrapframe *utf)
17 void *addr = (void *) utf->utf_fault_va;
18 uint32_t err = utf->utf_err;
19 int r;
21 // Check that the faulting access was (1) a write, and (2) to a
22 // copy-on-write page. If not, panic.
23 // Hint:
24 // Use the read-only page table mappings at vpt
25 // (see <inc/memlayout.h>).
26 // LAB 4: Your code here.
27 if (!((err & FEC_WR) && (vpt[VPN((unsigned int)addr)] & PTE_COW)))
28 panic("not a write and not to a COW page, addr: %x, err: %x", addr, err & 7);
30 // Allocate a new page, map it at a temporary location (PFTEMP),
31 // copy the data from the old page to the new page, then move the new
32 // page to the old page's address.
33 // Hint:
34 // You should make three system calls.
35 // No need to explicitly delete the old page's mapping.
36 // LAB 4: Your code here.
37 if ((r = sys_page_alloc(0, (void *)PFTEMP, PTE_U | PTE_W | PTE_P)) < 0)
38 panic("sys_page_alloc error: %e", r);
40 // copy the actual content
41 memmove((void *)PFTEMP, ROUNDDOWN(addr, PGSIZE), PGSIZE);
42 if ((r = sys_page_map(0, (void *)PFTEMP, 0, ROUNDDOWN(addr, PGSIZE),
43 PTE_U | PTE_W | PTE_P)) < 0)
44 panic("sys_page_map error: %e", r);
46 if ((r = sys_page_unmap(0, (void *)PFTEMP)) < 0)
47 panic("sys_page_unmap error: %e", r);
51 // Map our virtual page pn (address pn*PGSIZE) into the target envid
52 // at the same virtual address. If the page is writable or copy-on-write,
53 // the new mapping must be created copy-on-write, and then our mapping must be
54 // marked copy-on-write as well. (Exercise: Why mark ours copy-on-write again
55 // if it was already copy-on-write?)
57 // Returns: 0 on success, < 0 on error.
58 // It is also OK to panic on error.
59 //
60 static int
61 duppage(envid_t envid, unsigned pn)
63 int r;
64 void *addr;
65 pte_t pte;
66 // LAB 4: Your code here.
68 pte = vpt[pn];
69 if (!(pte & PTE_SHARE) &&
70 ((pte & PTE_W) || (pte & PTE_COW))) {
71 if ((r = sys_page_map(0, (void *)(pn*PGSIZE),
72 envid, (void *)(pn*PGSIZE),
73 PTE_U | PTE_P | PTE_COW)) < 0)
74 panic("sys_page_map error: %e", r);
76 if ((r = sys_page_map(envid, (void *)(pn*PGSIZE),
77 0, (void *)(pn*PGSIZE),
78 PTE_U | PTE_P | PTE_COW)) < 0)
79 panic("sys_page_map error: %e", r);
80 } else {
81 // read-only page or share page
82 // if pte has bit PTE_SHARE set, the PTE should
83 // be copied directly from parent to child
84 if ((r = sys_page_map(0, (void *)(pn*PGSIZE),
85 envid, (void *)(pn*PGSIZE),
86 pte & PTE_USER)) < 0)
87 panic("sys_page_map error: %e", r);
90 return 0;
94 // User-level fork with copy-on-write.
95 // Set up our page fault handler appropriately.
96 // Create a child.
97 // Copy our address space and page fault handler setup to the child.
98 // Then mark the child as runnable and return.
100 // Returns: child's envid to the parent, 0 to the child, < 0 on error.
101 // It is also OK to panic on error.
103 // Hint:
104 // Use vpd, vpt, and duppage.
105 // Remember to fix "env" and the user exception stack in the child process.
106 // Neither user exception stack should ever be marked copy-on-write,
107 // so you must allocate a new page for the child's user exception stack.
109 envid_t
110 fork(void)
112 // LAB 4: Your code here.
113 envid_t envid;
114 int r;
115 int pn, i;
117 // install the page fault handler
118 set_pgfault_handler(pgfault);
120 envid = sys_exofork();
121 if (envid < 0)
122 panic("fork error");
124 if (envid == 0) {
125 // we are the child
126 env = &envs[ENVX(sys_getenvid())];
127 return 0;
130 // we are the parent
131 pn = UTOP / PGSIZE - 1;
132 while (--pn >= 0)
133 if (!(vpd[pn >> 10] & PTE_P))
134 pn = (pn >> 10) << 10;
135 else if (vpt[pn] & PTE_P)
136 duppage(envid, pn);
138 // allocate a new page for child - user exception stack
139 if ((r = sys_page_alloc(envid,
140 (void *)(UXSTACKTOP-PGSIZE),
141 PTE_W |PTE_U |PTE_P)) < 0)
142 panic("sys_page_alloc error: %e", r);
144 // fire the engine
145 if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
146 panic("sys_env_set_status: %e", r);
148 return envid;
151 // Challenge!
153 sfork(void)
155 panic("sfork not implemented");
156 return -E_INVAL;