diff --git a/fs/bc.c b/fs/bc.c index e3922c4..f1a700d 100644 --- a/fs/bc.c +++ b/fs/bc.c @@ -31,6 +31,7 @@ bc_pgfault(struct UTrapframe *utf) { void *addr = (void *) utf->utf_fault_va; uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; + uint32_t secno = blockno * (BLKSIZE / SECTSIZE); int r; // Check that the fault was within the block cache region @@ -48,6 +49,11 @@ bc_pgfault(struct UTrapframe *utf) // the disk. // // LAB 5: you code here: + addr = ROUNDDOWN(addr, PGSIZE); + if((r = sys_page_alloc(0, addr, PTE_U | PTE_W | PTE_P)) < 0) + panic("failed to allocate page for block cache"); + if((r = ide_read(secno, addr, BLKSIZE / SECTSIZE)) < 0) + panic("failed to read from disk into block cache"); // Clear the dirty bit for the disk block page since we just read the // block from disk @@ -72,12 +78,21 @@ void flush_block(void *addr) { uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; + uint32_t secno = blockno * (BLKSIZE / SECTSIZE); + int r; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. - panic("flush_block not implemented"); + addr = ROUNDDOWN(addr, PGSIZE); + if(!(va_is_mapped(addr) && va_is_dirty(addr))) return; + + if((r = ide_write(secno, addr, BLKSIZE / SECTSIZE)) < 0) + panic("failed to flush block into cache"); + + if((r = sys_page_map(0, addr, 0, addr, uvpt[PGNUM(addr)] & PTE_SYSCALL)) < 0) + panic("failed to remove dirty bit from page"); } // Test that the block cache works, by smashing the superblock and diff --git a/fs/fs.c b/fs/fs.c index 45ecaf8..93be06c 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -60,9 +60,15 @@ alloc_block(void) // The bitmap consists of one or more blocks. A single bitmap block // contains the in-use bits for BLKBITSIZE blocks. There are // super->s_nblocks blocks in the disk altogether. + uint32_t* search = bitmap + 1; + for(uint32_t block = 1; block < super->s_nblocks; block++) { + if(bitmap[block / 32] & (1 << (block % 32))) { + bitmap[block / 32] &= ~(1 << (block % 32)); + flush_block(&bitmap[block / 32]); + return block; + } + } - // LAB 5: Your code here. - panic("alloc_block not implemented"); return -E_NO_DISK; } @@ -135,7 +141,23 @@ static int file_block_walk(struct File *f, uint32_t filebno, uint32_t **ppdiskbno, bool alloc) { // LAB 5: Your code here. - panic("file_block_walk not implemented"); + int newblock; + if(filebno < NDIRECT) { + *ppdiskbno = &f->f_direct[filebno]; + return 0; + } else if(filebno < NDIRECT + NINDIRECT) { + filebno -= NDIRECT; + if(!f->f_indirect) { + if(!alloc) return -E_NOT_FOUND; + if((newblock = alloc_block()) < 0) return newblock; + f->f_indirect = newblock; + } + + uint32_t* indirect = diskaddr(f->f_indirect); + *ppdiskbno = &indirect[filebno]; + return 0; + } + return -E_INVAL; } // Set *blk to the address in memory where the filebno'th @@ -150,7 +172,19 @@ int file_get_block(struct File *f, uint32_t filebno, char **blk) { // LAB 5: Your code here. - panic("file_get_block not implemented"); + uint32_t* blockno; + int r; + + if ((r = file_block_walk(f, filebno, &blockno, 1)) < 0) + return r; + + if(*blockno == 0) { + if((r = alloc_block()) < 0) return r; + *blockno = r; + } + + *blk = diskaddr(*blockno); + return 0; } // Try to find a file named "name" in dir. If so, set *file to it. diff --git a/fs/serv.c b/fs/serv.c index 76c1d99..b1e7792 100644 --- a/fs/serv.c +++ b/fs/serv.c @@ -209,12 +209,20 @@ serve_read(envid_t envid, union Fsipc *ipc) { struct Fsreq_read *req = &ipc->read; struct Fsret_read *ret = &ipc->readRet; + struct OpenFile* open_file; + int r; if (debug) cprintf("serve_read %08x %08x %08x\n", envid, req->req_fileid, req->req_n); - // Lab 5: Your code here: - return 0; + if((r = openfile_lookup(envid, req->req_fileid, &open_file)) < 0) + return r; + + if((r = file_read(open_file->o_file, ret->ret_buf, req->req_n, open_file->o_fd->fd_offset)) < 0) + return r; + + open_file->o_fd->fd_offset += r; + return r; } @@ -227,9 +235,17 @@ serve_write(envid_t envid, struct Fsreq_write *req) { if (debug) cprintf("serve_write %08x %08x %08x\n", envid, req->req_fileid, req->req_n); + + struct OpenFile* open_file; + int r; - // LAB 5: Your code here. - panic("serve_write not implemented"); + if((r = openfile_lookup(envid, req->req_fileid, &open_file)) < 0) + return r; + if((r = file_write(open_file->o_file, req->req_buf, req->req_n, open_file->o_fd->fd_offset)) < 0) + return r; + + open_file->o_fd->fd_offset += r; + return r; } // Stat ipc->stat.req_fileid. Return the file's struct Stat to the diff --git a/kern/env.c b/kern/env.c index 623a72c..b8ed502 100644 --- a/kern/env.c +++ b/kern/env.c @@ -289,7 +289,7 @@ region_alloc(struct Env *e, void *va, size_t len) // You should round va down, and round (va + len) up. // (Watch out for corner-cases!) va = ROUNDDOWN(va, PGSIZE); - size_t count = ROUNDUP(len, PGSIZE) / PGSIZE; + size_t count = ROUNDUP(len, PGSIZE) / PGSIZE + 1; struct PageInfo* p; while(count--) { @@ -393,6 +393,10 @@ env_create(uint8_t *binary, enum EnvType type) if(env_alloc(&new_env, 0) < 0) panic("Failed to allocate environment"); new_env->env_type = type; + + if(type == ENV_TYPE_FS) + new_env->env_tf.tf_eflags |= FL_IOPL_3; + load_icode(new_env, binary); } diff --git a/kern/syscall.c b/kern/syscall.c index 180cdf7..eace7d7 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -116,6 +116,11 @@ sys_env_set_status(envid_t envid, int status) return 0; } +#define SYS_CHECKPERMS(perm) \ + ((((perm) & (PTE_P | PTE_U)) == (PTE_P | PTE_U)) && \ + (((perm) & ~(PTE_P | PTE_U | PTE_W | PTE_AVAIL)) == 0)) +#define SYS_CHECKADDR(addr) (((uintptr_t) (addr) < UTOP) && ((uintptr_t) (addr) % PGSIZE == 0)) + // Set envid's trap frame to 'tf'. // tf is modified to make sure that user environments always run at code // protection level 3 (CPL 3), interrupts enabled, and IOPL of 0. @@ -129,7 +134,19 @@ sys_env_set_trapframe(envid_t envid, struct Trapframe *tf) // LAB 5: Your code here. // Remember to check whether the user has supplied us with a good // address! - panic("sys_env_set_trapframe not implemented"); + int r; + struct Env* chenv; + SYS_CHECKADDR(tf); + + if((r = envid2env(envid, &chenv, true)) < 0) + return r; + + tf->tf_cs |= 3; + tf->tf_eflags &= ~(FL_IOPL_3); + tf->tf_eflags |= FL_IF; + + chenv->env_tf = *tf; + return 0; } // Set the page fault upcall for 'envid' by modifying the corresponding struct @@ -150,11 +167,6 @@ sys_env_set_pgfault_upcall(envid_t envid, void *func) return 0; } -#define SYS_CHECKPERMS(perm) \ - ((((perm) & (PTE_P | PTE_U)) == (PTE_P | PTE_U)) && \ - (((perm) & ~(PTE_P | PTE_U | PTE_W | PTE_AVAIL)) == 0)) -#define SYS_CHECKADDR(addr) (((uintptr_t) (addr) < UTOP) && ((uintptr_t) (addr) % PGSIZE == 0)) - // Allocate a page of memory and map it at 'va' with permission // 'perm' in the address space of 'envid'. // The page's contents are set to 0. @@ -408,6 +420,8 @@ syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, return sys_ipc_try_send(a1, a2, (void*) a3, a4); case SYS_ipc_recv: return sys_ipc_recv((void*) a1); + case SYS_env_set_trapframe: + return sys_env_set_trapframe(a1, (void*) a2); default: return -E_INVAL; } diff --git a/kern/trap.c b/kern/trap.c index ad23e9f..4a62769 100644 --- a/kern/trap.c +++ b/kern/trap.c @@ -260,6 +260,12 @@ trap_dispatch(struct Trapframe *tf) } else if (tf->tf_trapno == IRQ_OFFSET + IRQ_TIMER) { lapic_eoi(); sched_yield(); + } else if (tf->tf_trapno == IRQ_OFFSET + IRQ_KBD) { + kbd_intr(); + return; + } else if (tf->tf_trapno == IRQ_OFFSET + IRQ_SERIAL) { + serial_intr(); + return; } // Handle spurious interrupts @@ -360,6 +366,8 @@ page_fault_handler(struct Trapframe *tf) // Handle kernel-mode page faults. // LAB 3: Your code here. + if(!curenv) + panic("kernel-level page fault, va %p, eip %p", fault_va, tf->tf_eip); // We've already handled kernel-mode exceptions, so if we get here, // the page fault happened in user mode. diff --git a/lib/file.c b/lib/file.c index 39025b2..be468f3 100644 --- a/lib/file.c +++ b/lib/file.c @@ -141,7 +141,13 @@ devfile_write(struct Fd *fd, const void *buf, size_t n) // remember that write is always allowed to write *fewer* // bytes than requested. // LAB 5: Your code here - panic("devfile_write not implemented"); + size_t writesize = MIN(sizeof(fsipcbuf.write.req_buf), n); + + fsipcbuf.write.req_fileid = fd->fd_file.id; + fsipcbuf.write.req_n = writesize; + memcpy(fsipcbuf.write.req_buf, buf, writesize); + + return fsipc(FSREQ_WRITE, NULL); } static int diff --git a/lib/fork.c b/lib/fork.c index b8dcfa3..b650511 100644 --- a/lib/fork.c +++ b/lib/fork.c @@ -62,7 +62,7 @@ duppage(envid_t envid, unsigned pn) void* addr = (void*) (pn * PGSIZE); // If we're writable, remove write permission - if((new_pte & PTE_W) || (new_pte & PTE_COW)) { + if(((new_pte & PTE_W) && !(new_pte & PTE_SHARE)) || (new_pte & PTE_COW)) { perms = (perms & ~PTE_W) | PTE_COW; change_own = true; } diff --git a/lib/spawn.c b/lib/spawn.c index 9d0eb07..3f4e7a0 100644 --- a/lib/spawn.c +++ b/lib/spawn.c @@ -302,6 +302,21 @@ static int copy_shared_pages(envid_t child) { // LAB 5: Your code here. + int r; + for(int pde_i = 0; pde_i < PDX(UTOP); pde_i++) { + pde_t pde = uvpd[pde_i]; + if(!(pde & PTE_P)) continue; + + 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 | PTE_SHARE)) != (PTE_P | PTE_SHARE)) continue; + void* addr = (void*) (pn * PGSIZE); + if((r = sys_page_map(0, addr, child, addr, pte & PTE_SYSCALL)) < 0) + return r; + } + } return 0; } diff --git a/user/sh.c b/user/sh.c index 26f501a..5bec84f 100644 --- a/user/sh.c +++ b/user/sh.c @@ -53,9 +53,16 @@ again: // then check whether 'fd' is 0. // If not, dup 'fd' onto file descriptor 0, // then close the original 'fd'. - // LAB 5: Your code here. - panic("< redirection not implemented"); + if ((fd = open(t, O_RDONLY)) < 0) { + cprintf("open %s for read: %e", t, fd); + } + + if(fd != 0) { + dup(fd, 0); + close(fd); + } + break; case '>': // Output redirection