// Test that write_block works, by smashing the superblock and reading it back. void check_write_block(void) { super = 0; // back up super block read_block(0, 0); memmove(diskaddr(0), diskaddr(1), PGSIZE); // smash it strcpy(diskaddr(1), "OOPS!\n"); write_block(1); assert(block_is_mapped(1)); assert(!va_is_dirty(diskaddr(1))); // clear it out sys_page_unmap(0, diskaddr(1)); assert(!block_is_mapped(1)); // read it back in read_block(1, 0); assert(strcmp(diskaddr(1), "OOPS!\n") == 0); // fix it memmove(diskaddr(1), diskaddr(0), PGSIZE); write_block(1); super = (struct Super*)diskaddr(1); cprintf("write_block is good\n"); }
// Fault any disk block that is read in to memory by // loading it from disk. static void bc_pgfault(struct UTrapframe *utf) { void *addr = (void *) utf->utf_fault_va; uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; int r; // Check that the fault was within the block cache region if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("page fault in FS: eip %08x, va %08x, err %04x", utf->utf_eip, addr, utf->utf_err); // Sanity check the block number. if (super && blockno >= super->s_nblocks) panic("reading non-existent block %08x\n", blockno); // Allocate a page in the disk map region, read the contents // of the block from the disk into that page. // Hint: first round addr to page boundary. fs/ide.c has code to read // 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("in bc_pgfault, sys_page_alloc: %e", r); } assert(!va_is_dirty(addr)); //debug if( (r = ide_read(blockno * BLKSECTS, addr, (PGSIZE/SECTSIZE))) != 0) { panic("in bc_pgfault, ide_read: %e", r); } assert(va_is_dirty(addr)); //debug // Clear the dirty bit for the disk block page since we just read the // block from disk if ((r = sys_page_map(0, addr, 0, addr, uvpt[PGNUM(addr)] & PTE_SYSCALL)) < 0) panic("in bc_pgfault, sys_page_map: %e", r); // Check that the block we read was allocated. (exercise for // the reader: why do we do this *after* reading the block // in?) if (bitmap && block_is_free(blockno)) panic("reading free block %08x\n", blockno); }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_SYSCALL constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. addr = ROUNDDOWN(addr, PGSIZE); if (!va_is_mapped(addr) || !va_is_dirty(addr)) return; ide_write(blockno * BLKSECTS, addr, BLKSECTS); sys_page_map(0, addr, 0, addr, uvpt[PGNUM(addr)] & PTE_SYSCALL); }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_USER constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; int r; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. addr = ROUNDDOWN(addr, PGSIZE); if (!va_is_mapped(addr) || !va_is_dirty(addr)) return; if (ide_write(blockno * BLKSECTS, addr, BLKSECTS) < 0) panic("ide_write failed"); if ((r = sys_page_map(0, addr, 0, addr, PTE_USER)) < 0) panic("sys_page_map: %e", r); }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_SYSCALL constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. addr = ROUNDDOWN(addr, PGSIZE); if (!va_is_mapped(addr) || !va_is_dirty(addr)) return; ide_write(blockno * BLKSECTS, addr, BLKSECTS); if (sys_page_map(0, addr, 0, addr, PTE_SYSCALL) < 0) panic("bc.c/flush_block: map page failed.\n"); //panic("flush_block not implemented"); }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_SYSCALL constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint64_t blockno = ((uint64_t)addr - DISKMAP) / BLKSIZE; int r; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. if((va_is_mapped(addr))&&(va_is_dirty(addr))) #ifndef VMM_GUEST ide_write(blockno*BLKSECTS, ROUNDDOWN(addr,BLKSIZE), BLKSECTS); #else host_write(blockno*BLKSECTS, ROUNDDOWN(addr,BLKSIZE), BLKSECTS); #endif if((va_is_mapped(addr)) && ((r = sys_page_map(0, ROUNDDOWN(addr,PGSIZE), 0, ROUNDDOWN(addr,PGSIZE), PTE_SYSCALL&~PTE_D)) < 0)) panic("Couldn't flush disk page%e",r); }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_SYSCALL constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { addr = (void *) ROUNDDOWN(addr, PGSIZE); uint32_t sectno = ((uint32_t)addr - DISKMAP) / SECTSIZE; uint32_t blockno = (sectno / BLKSECTS); if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. if(va_is_dirty(addr) && va_is_mapped(addr)) { ide_write(sectno, addr, BLKSECTS); sys_page_map(0, addr, 0, addr, (PTE_SYSCALL)); BC_DEBUG("Wrote block %08x, now mapped r/o\n", blockno); } }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_SYSCALL constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint64_t blockno = ((uint64_t)addr - DISKMAP) / BLKSIZE; int r; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. void *dst_addr = (void *)(ROUNDDOWN(addr, PGSIZE)); // Project addition --> Transparent disk encryption. if(va_is_mapped(dst_addr)) { if(va_is_dirty(dst_addr)) { if((blockno == 0) || (blockno == 2)) ide_write(blockno * BLKSECTS, dst_addr, BLKSECTS); else if((blockno == 1)) { if(!s_encrypted) ide_write(blockno * BLKSECTS, dst_addr, BLKSECTS); else { r = transparent_disk_encrypt(blockno, dst_addr); if(r) return; } } else { r = transparent_disk_encrypt(blockno, dst_addr); if(r) return; } sys_page_map(thisenv->env_id, dst_addr, thisenv->env_id, dst_addr, PTE_SYSCALL); } } // panic("flush_block not implemented"); }
// Test that the block cache works, by smashing the superblock and // reading it back. static void check_bc(void) { cprintf("Starting..\n"); struct Super backup; // back up super block memmove(&backup, diskaddr(1), sizeof(backup)); BC_DEBUG("Wrote superblock to disk ram block..\n"); BC_DEBUG("in memory magic number: %08x\n", ((struct Super*)diskaddr(1))->s_magic); // smash it strcpy(diskaddr(1), "OOPS!\n"); flush_block(diskaddr(1)); assert(va_is_mapped(diskaddr(1))); assert(!va_is_dirty(diskaddr(1))); cprintf("Smashed disk superblock..\n"); // clear it out sys_page_unmap(0, diskaddr(1)); assert(!va_is_mapped(diskaddr(1))); cprintf("Unmapped superblock va..\n"); // read it back in assert(strcmp(diskaddr(1), "OOPS!\n") == 0); cprintf("re-read superblock va..\n"); // fix it memmove(diskaddr(1), &backup, sizeof(backup)); assert(memcmp(diskaddr(1), &backup, sizeof(backup)) == 0); flush_block(diskaddr(1)); assert(memcmp(diskaddr(1), &backup, sizeof(backup)) == 0); BC_DEBUG("backup magic number : %08x\n", backup.s_magic); BC_DEBUG("in memory magic number: %08x\n", ((struct Super*)diskaddr(1))->s_magic); BC_DEBUG("expected magic value : %08x\n", FS_MAGIC); cprintf("Fixed superblock..\n"); cprintf("block cache is good\n"); }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_USER constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. int r; void *blkva; blkva=ROUNDDOWN(addr,BLKSIZE); if(va_is_mapped(addr)&&va_is_dirty(addr)) { ide_write(blockno*BLKSECTS,blkva,BLKSECTS); if((r=sys_page_map(0,blkva,0,blkva,PTE_USER))<0) panic("page mapping failed:%e\n",r); } //panic("flush_block not implemented"); }
// Copy the current contents of the block out to disk. // Then clear the PTE_D bit using sys_page_map. // Hint: Use ide_write. // Hint: Use the PTE_USER constant when calling sys_page_map. void write_block(uint32_t blockno) { char *addr; if (!block_is_mapped(blockno)) panic("write unmapped block %08x", blockno); // Write the disk block and clear PTE_D. // LAB 5: Your code here. addr = diskaddr(blockno); if(va_is_dirty(addr) == 0){ cprintf("va isn't dirty!\n"); return; } if(ide_write(blockno * BLKSECTS, addr, BLKSECTS) < 0) panic("write_block ide_write fail!\n"); if(sys_page_map(0,addr,0,addr, PTE_USER) < 0) panic("write_block sys_page_map fail!\n"); return; }
// Copy the current contents of the block out to disk. // Then clear the PTE_D bit using sys_page_map. // Hint: Use ide_write. // Hint: Use the PTE_USER constant when calling sys_page_map. void write_block(uint32_t blockno) { char *addr; int r; if (!block_is_mapped(blockno)) panic("write unmapped block %08x", blockno); // Write the disk block and clear PTE_D. // LAB 5: Your code here. addr = diskaddr(blockno); if(va_is_dirty(addr)){ r = ide_write(blockno*BLKSECTS, (void *)addr, BLKSECTS); if(r < 0) panic("GZ write block fault !!\n"); r = sys_page_map(0, addr, 0, addr, PTE_USER); if(r < 0) panic("GZ can not clear PTE_D!!\n"); } //panic("write_block not implemented"); }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_USER constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint32_t blockno = ((uint32_t)addr - DISKMAP) / BLKSIZE; 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)) { ide_write(BLKSECTS*blockno, addr, BLKSECTS); if(sys_page_map(0, addr, 0, addr, PTE_USER) < 0) { panic ("flush_block(), sys_page_map error"); } } }
// Flush the contents of the block containing VA out to disk if // necessary, then clear the PTE_D bit using sys_page_map. // If the block is not in the block cache or is not dirty, does // nothing. // Hint: Use va_is_mapped, va_is_dirty, and ide_write. // Hint: Use the PTE_SYSCALL constant when calling sys_page_map. // Hint: Don't forget to round addr down. void flush_block(void *addr) { uint64_t blockno = ((uint64_t)addr - DISKMAP) / BLKSIZE; int r; if (addr < (void*)DISKMAP || addr >= (void*)(DISKMAP + DISKSIZE)) panic("flush_block of bad va %08x", addr); // LAB 5: Your code here. addr = ROUNDDOWN(addr,BLKSIZE); if (va_is_mapped(addr) && va_is_dirty(addr)) #ifdef VMM_GUEST host_write(blockno*BLKSECTS, addr, BLKSECTS); #else ide_write(blockno*BLKSECTS, addr, BLKSECTS); #endif if(va_is_mapped(addr)) { if ((r = sys_page_map(0,addr,0,addr,PTE_SYSCALL&~PTE_D))<0) cprintf("error in flushing the block : %e\n",r); } //panic("flush_block not implemented"); }
// Is this block dirty? bool block_is_dirty(uint32_t blockno) { char *va = diskaddr(blockno); return va_is_mapped(va) && va_is_dirty(va); }