Merge branch 'lab4' into lab5
This commit is contained in:
75
lib/fork.c
75
lib/fork.c
@@ -23,18 +23,22 @@ pgfault(struct UTrapframe *utf)
|
||||
// Hint:
|
||||
// Use the read-only page table mappings at uvpt
|
||||
// (see <inc/memlayout.h>).
|
||||
|
||||
// LAB 4: Your code here.
|
||||
if(!((err & FEC_WR) && (uvpt[(uintptr_t) addr >> PGSHIFT] & PTE_COW)))
|
||||
panic("page fault (addr %p)! %c", addr, (err & FEC_WR) ? 'w' : 'r');
|
||||
|
||||
// Allocate a new page, map it at a temporary location (PFTEMP),
|
||||
// copy the data from the old page to the new page, then move the new
|
||||
// page to the old page's address.
|
||||
// Hint:
|
||||
// You should make three system calls.
|
||||
void* temp_addr = (void*) PFTEMP;
|
||||
void* fault_addr = ROUNDDOWN(addr, PGSIZE);
|
||||
if(sys_page_alloc(0, temp_addr, PTE_P | PTE_W | PTE_U) < 0)
|
||||
panic("failed to allocate new page");
|
||||
|
||||
// LAB 4: Your code here.
|
||||
|
||||
panic("pgfault not implemented");
|
||||
memcpy(temp_addr, fault_addr, PGSIZE);
|
||||
sys_page_map(0, temp_addr, 0, fault_addr, PTE_P | PTE_U | PTE_W);
|
||||
sys_page_unmap(0, temp_addr);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -52,9 +56,27 @@ static int
|
||||
duppage(envid_t envid, unsigned pn)
|
||||
{
|
||||
int r;
|
||||
bool change_own = false;
|
||||
pte_t new_pte = uvpt[pn];
|
||||
pte_t perms = new_pte & (PTE_P | PTE_U | PTE_W | PTE_AVAIL);
|
||||
void* addr = (void*) (pn * PGSIZE);
|
||||
|
||||
// If we're writable, remove write permission
|
||||
if((new_pte & PTE_W) || (new_pte & PTE_COW)) {
|
||||
perms = (perms & ~PTE_W) | PTE_COW;
|
||||
change_own = true;
|
||||
}
|
||||
|
||||
// Map either with the same permissions or with COW.
|
||||
if((r = sys_page_map(0, addr, envid, addr, perms)) < 0)
|
||||
return r;
|
||||
|
||||
// Update our own permissions if necessary
|
||||
if(change_own) {
|
||||
if((r = sys_page_map(0, addr, 0, addr, perms)) < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
// LAB 4: Your code here.
|
||||
panic("duppage not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -77,8 +99,43 @@ duppage(envid_t envid, unsigned pn)
|
||||
envid_t
|
||||
fork(void)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("fork not implemented");
|
||||
set_pgfault_handler(pgfault);
|
||||
|
||||
int return_code;
|
||||
envid_t forked;
|
||||
|
||||
forked = sys_exofork();
|
||||
if(forked < 0) return forked;
|
||||
if(forked == 0) { thisenv = &envs[ENVX(sys_getenvid())]; return 0; }
|
||||
|
||||
// Map all accessible page directory entries
|
||||
for(int pde_i = 0; pde_i < PDX(UTOP); pde_i++) {
|
||||
pde_t pde = uvpd[pde_i];
|
||||
if(!(pde & PTE_P)) continue;
|
||||
|
||||
// For each PDE, map all the underlying PTEs
|
||||
for(int pte_i = 0; pte_i < NPTENTRIES; pte_i++) {
|
||||
int pn = pde_i * NPTENTRIES + pte_i;
|
||||
pte_t pte = uvpt[pn];
|
||||
if(!(pte & PTE_P)) continue;
|
||||
|
||||
// Do not map user exception stack, though
|
||||
if(pn == ((UXSTACKTOP - PGSIZE) >> PGSHIFT)) continue;
|
||||
|
||||
if((return_code = duppage(forked, pn)) < 0) return return_code;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate new page for the exception stack
|
||||
return_code = sys_page_alloc(forked, (void*) UXSTACKTOP - PGSIZE,
|
||||
PTE_P | PTE_U | PTE_W);
|
||||
if(return_code < 0) return return_code;
|
||||
|
||||
// Set the upcall entry point
|
||||
sys_env_set_pgfault_upcall(forked, thisenv->env_pgfault_upcall);
|
||||
sys_env_set_status(forked, ENV_RUNNABLE);
|
||||
|
||||
return forked;
|
||||
}
|
||||
|
||||
// Challenge!
|
||||
|
||||
19
lib/ipc.c
19
lib/ipc.c
@@ -22,9 +22,14 @@
|
||||
int32_t
|
||||
ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("ipc_recv not implemented");
|
||||
return 0;
|
||||
int return_code;
|
||||
if((return_code = sys_ipc_recv(pg ? pg : (void*) ~0)) < 0)
|
||||
return return_code;
|
||||
|
||||
if(from_env_store) *from_env_store = thisenv->env_ipc_from;
|
||||
if(perm_store) *perm_store = thisenv->env_ipc_perm;
|
||||
|
||||
return thisenv->env_ipc_value;
|
||||
}
|
||||
|
||||
// Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'.
|
||||
@@ -38,8 +43,12 @@ ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
|
||||
void
|
||||
ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
panic("ipc_send not implemented");
|
||||
int return_code = -E_IPC_NOT_RECV;
|
||||
while(return_code == -E_IPC_NOT_RECV) {
|
||||
return_code = sys_ipc_try_send(to_env, val, pg ? pg : (void*) ~0, perm);
|
||||
sys_yield();
|
||||
}
|
||||
if(return_code != 0) panic("failed to send\n");
|
||||
}
|
||||
|
||||
// Find the first environment of the given type. We'll use this to
|
||||
|
||||
@@ -13,7 +13,8 @@ libmain(int argc, char **argv)
|
||||
{
|
||||
// set thisenv to point at our Env structure in envs[].
|
||||
// LAB 3: Your code here.
|
||||
thisenv = 0;
|
||||
envid_t id = sys_getenvid();
|
||||
thisenv = &envs[ENVX(id)];
|
||||
|
||||
// save the name of the program so that panic() can use it
|
||||
if (argc > 0)
|
||||
|
||||
@@ -65,18 +65,29 @@ _pgfault_upcall:
|
||||
// ways as registers become unavailable as scratch space.
|
||||
//
|
||||
// LAB 4: Your code here.
|
||||
mov 40(%esp), %eax // Take the EIP from memory
|
||||
mov 48(%esp), %ebp // Take the ESP from memory
|
||||
sub $4, %ebp // Push onto trap-time ESP
|
||||
mov %eax, (%ebp)
|
||||
mov %ebp, 48(%esp) // Put ESP back
|
||||
|
||||
// Restore the trap-time registers. After you do this, you
|
||||
// can no longer modify any general-purpose registers.
|
||||
// LAB 4: Your code here.
|
||||
add $0x8, %esp
|
||||
popal
|
||||
|
||||
// Restore eflags from the stack. After you do this, you can
|
||||
// no longer use arithmetic operations or anything else that
|
||||
// modifies eflags.
|
||||
// LAB 4: Your code here.
|
||||
add $0x4, %esp
|
||||
popfl
|
||||
|
||||
// Switch back to the adjusted trap-time stack.
|
||||
// LAB 4: Your code here.
|
||||
pop %esp
|
||||
|
||||
// Return to re-execute the instruction that faulted.
|
||||
// LAB 4: Your code here.
|
||||
ret
|
||||
|
||||
@@ -27,9 +27,9 @@ set_pgfault_handler(void (*handler)(struct UTrapframe *utf))
|
||||
int r;
|
||||
|
||||
if (_pgfault_handler == 0) {
|
||||
// First time through!
|
||||
// LAB 4: Your code here.
|
||||
panic("set_pgfault_handler not implemented");
|
||||
if(sys_page_alloc(0, (void*) UXSTACKTOP - PGSIZE, PTE_U | PTE_P | PTE_W) < 0)
|
||||
panic("set_pgfault_handler");
|
||||
sys_env_set_pgfault_upcall(0, _pgfault_upcall);
|
||||
}
|
||||
|
||||
// Save handler pointer for assembly to call.
|
||||
|
||||
@@ -214,11 +214,9 @@ vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap)
|
||||
|
||||
// (unsigned) octal
|
||||
case 'o':
|
||||
// LAB 1: Replace this with your code.
|
||||
putch('X', putdat);
|
||||
putch('X', putdat);
|
||||
putch('X', putdat);
|
||||
break;
|
||||
num = getuint(&ap, lflag);
|
||||
base = 8;
|
||||
goto number;
|
||||
|
||||
// pointer
|
||||
case 'p':
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <inc/syscall.h>
|
||||
#include <inc/lib.h>
|
||||
#include <inc/x86.h>
|
||||
|
||||
static inline int32_t
|
||||
syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
||||
@@ -37,6 +38,20 @@ syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t
|
||||
fast_syscall(int num, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4) {
|
||||
asm volatile(
|
||||
"push %%ebp\n\t"
|
||||
"mov %%esp, %%ebp\n\t"
|
||||
"lea syscall_ret_%=, %%esi\n\t"
|
||||
"sysenter\n\t"
|
||||
"syscall_ret_%=: pop %%ebp\n\t"
|
||||
: "+a" (num)
|
||||
: "d" (a1), "c" (a2), "b" (a3), "D" (a4)
|
||||
: "esi");
|
||||
return num;
|
||||
}
|
||||
|
||||
void
|
||||
sys_cputs(const char *s, size_t len)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user