1 // implement fork from user space
3 #include <inc/string.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).
11 // Custom page fault handler - if faulting page is copy-on-write,
12 // map in our own private writable copy.
15 pgfault(struct UTrapframe
*utf
)
17 void *addr
= (void *) utf
->utf_fault_va
;
18 uint32_t err
= utf
->utf_err
;
21 // Check that the faulting access was (1) a write, and (2) to a
22 // copy-on-write page. If not, panic.
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.
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.
61 duppage(envid_t envid
, unsigned pn
)
66 // LAB 4: Your code here.
69 if ((pte
& PTE_W
) || (pte
& PTE_COW
)) {
70 if ((r
= sys_page_map(0, (void *)(pn
*PGSIZE
),
71 envid
, (void *)(pn
*PGSIZE
),
72 PTE_U
| PTE_P
| PTE_COW
)) < 0)
73 panic("sys_page_map error: %e", r
);
75 if ((r
= sys_page_map(envid
, (void *)(pn
*PGSIZE
),
76 0, (void *)(pn
*PGSIZE
),
77 PTE_U
| PTE_P
| PTE_COW
)) < 0)
78 panic("sys_page_map error: %e", r
);
80 if ((r
= sys_page_map(0, (void *)(pn
*PGSIZE
),
81 envid
, (void *)(pn
*PGSIZE
),
82 PTE_W
| PTE_P
| PTE_U
)) < 0)
83 panic("sys_page_map error: %e", r
);
90 // User-level fork with copy-on-write.
91 // Set up our page fault handler appropriately.
93 // Copy our address space and page fault handler setup to the child.
94 // Then mark the child as runnable and return.
96 // Returns: child's envid to the parent, 0 to the child, < 0 on error.
97 // It is also OK to panic on error.
100 // Use vpd, vpt, and duppage.
101 // Remember to fix "env" and the user exception stack in the child process.
102 // Neither user exception stack should ever be marked copy-on-write,
103 // so you must allocate a new page for the child's user exception stack.
108 // LAB 4: Your code here.
113 // install the page fault handler
114 set_pgfault_handler(pgfault
);
116 envid
= sys_exofork();
122 env
= &envs
[ENVX(sys_getenvid())];
127 pn
= UTOP
/ PGSIZE
- 1;
129 if (!(vpd
[pn
>> 10] & PTE_P
))
130 pn
= (pn
>> 10) << 10;
131 else if (vpt
[pn
] & PTE_P
)
134 // allocate a new page for child - user exception stack
135 if ((r
= sys_page_alloc(envid
,
136 (void *)(UXSTACKTOP
-PGSIZE
),
137 PTE_W
|PTE_U
|PTE_P
)) < 0)
138 panic("sys_page_alloc error: %e", r
);
141 if ((r
= sys_env_set_status(envid
, ENV_RUNNABLE
)) < 0)
142 panic("sys_env_set_status: %e", r
);
151 panic("sfork not implemented");