// Parameters: // diskno: disk number. // secno: start sector number. // dst: destination for data read from IDE disk. // nsecs: the number of sectors to read.
# read sector at specified offset from the beginning of the disk image. LEAF(read_sector) sw a0, 0xB3000010 # select the IDE id. sw a1, 0xB3000000 # offset. li t0, 0 sb t0, 0xB3000020 # start read. lw v0, 0xB3000030 nop jr ra nop END(read_sector)
sys_write_dev
系统调用写设备
位置:lib/syscall_all.c
dev意味device,设备
1 2 3 4 5 6 7 8 9 10 11 12
intsys_write_dev(int sysno, u_int va, u_int dev, u_int len) { // Your code here if (dev >= 0x10000000 && dev + len <= 0x10000020 || dev >= 0x13000000 && dev + len <= 0x13004200 || dev >= 0x15000000 && dev + len <= 0x15000200) { bcopy(va, 0xa0000000 + dev, len); return0; } return -E_INVAL; }
intsys_read_dev(int sysno, u_int va, u_int dev, u_int len) { // Your code here if (dev >= 0x10000000 && dev + len <= 0x10000020 || dev >= 0x13000000 && dev + len <= 0x13004200 || dev >= 0x15000000 && dev + len <= 0x15000200) { bcopy(0xa0000000 + dev, va, len); return0; } return -E_INVAL; }
// Make new block contians link to files in a directory. intmake_link_block(struct File *dirf, int nblk) { save_block_link(dirf, nblk, nextbno); dirf->f_size += BY2BLK; return next_block(BLOCK_FILE); }
flush_bitmap
把nextbno之前的所有块对应的bitmap标记为0,即,不可用
1 2 3 4 5 6 7 8
// Flush disk block usage to bitmap. voidflush_bitmap(){ int i; // update bitmap, mark all bit where corresponding block is used. for(i = 0; i < nextbno; ++i) { ((uint32_t *)disk[2+i/BIT2BLK].data)[(i%BIT2BLK)/32] &= ~(1<<(i%32)); } }
u_int block_is_mapped(u_int blockno) { u_int va = diskaddr(blockno); if (va_is_mapped(va)) { return va; } return0; }
write_block
写磁盘块。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
voidwrite_block(u_int blockno) { u_int va;
// Step 1: detect is this block is mapped, if not, can't write it's data to disk. // 判断磁盘块是否已经映射,没有映射说明错误 if (!block_is_mapped(blockno)) { user_panic("write unmapped block %08x", blockno); }
// Step2: write data to IDE disk. (using ide_write, and the diskno is 0) // 获取磁盘块对应的虚拟地址,将虚拟地址对应的内容写回到磁盘块 va = diskaddr(blockno); ide_write(0, blockno * SECT2BLK, (void *)va, SECT2BLK);
syscall_mem_map(0, va, 0, va, (PTE_V | PTE_R | PTE_LIBRARY)); }
map_block
检查指定的磁盘块是否已经映射到内存,如果没有,分配一页内存来保存磁盘上的数据
位置:fs/fs.c
1 2 3 4 5 6 7 8 9 10 11 12
int map_block(u_int blockno) { // Step 1: Decide whether this block has already mapped to a page of physical memory. // 根据给定磁盘块判断是否已经映射到虚拟地址了 if (block_is_mapped(blockno)) { return0; } // 如果没有映射到虚拟地址,为blockno对应的虚拟地址分配并映射一页 // Step 2: Alloc a page of memory for this block via syscall. return syscall_mem_alloc(0, diskaddr(blockno), PTE_R | PTE_V); }
void unmap_block(u_int blockno) { int r; u_int addr; // Step 1: check if this block is mapped. // 检查磁盘块是否确实已经被映射 addr = block_is_mapped(blockno); // Step 2: use block_is_free�~Lblock_is_dirty to check block, // if this block is used(not free) and dirty, it needs to be synced to disk: write_block // can't be unmap directly. // 如果磁盘块非free且已经被改写过,进行写块操作 if (!block_is_free(blockno) && block_is_dirty(blockno)) { write_block(blockno); } // 取消磁盘块对应虚拟地址的映射 // Step 3: use 'syscall_mem_unmap' to unmap corresponding virtual memory. r = syscall_mem_unmap(0, addr); if (r < 0) { return r; } // Step 4: validate result of this unmap operation. user_assert(!block_is_mapped(blockno)); }
// Step 1: validate blockno. Make file the block to read is within the disk. // 检查super是否为空,非空时blockno是否超过超级块控制的上限,返回对应的错误。 if (super && blockno >= super->s_nblocks) { user_panic("reading non-existent block %08x\n", blockno); }
// Step 2: validate this block is used, not free. // Hint: // If the bitmap is NULL, indicate that we haven't read bitmap from disk to memory // until now. So, before we check if a block is free using `block_is_free`, we must // ensure that the bitmap blocks are already read from the disk to memory. // 判断bitmap是否加载,接着判断该块对应是否为空块 if (bitmap && block_is_free(blockno)) { user_panic("reading free block %08x\n", blockno); }
// Step 3: transform block number to corresponding virtual address. // 调用diskaddr,将磁盘块号转为其在当前进程的虚拟地址 va = diskaddr(blockno);
// Step 4: read disk and set *isnew. // Hint: if this block is already mapped, just set *isnew, else alloc memory and // read data from IDE disk (use `syscall_mem_alloc` and `ide_read`). // We have only one IDE disk, so the diskno of ide_read should be 0. // 如果块已经映射了 if (block_is_mapped(blockno)) { //the block is in memory // 如果isnew不是空指针 if (isnew) { // 设置isnew为假 *isnew = 0; } } else { //the block is not in memory if (isnew) { // 设置isnew为真,即,分配了新内存页 *isnew = 1; } // 申请一个新的页 syscall_mem_alloc(0, va, PTE_V | PTE_R); // 将对应块的内容调到该页上 ide_read(0, blockno * SECT2BLK, (void *)va, SECT2BLK); }
// Step 5: if blk != NULL, set `va` to *blk. // 如果blk非空,返回其在内存中挂载的位置 if (blk) { *blk = (void *)va; } return0; }
intalloc_block_num(void) { int blockno; // walk through this bitmap, find a free one and mark it as used, then sync // this block to IDE disk (using `write_block`) from memory. for (blockno = 3; blockno < super->s_nblocks; blockno++) { if (bitmap[blockno / 32] & (1 << (blockno % 32))) { //the block is free bitmap[blockno / 32] &= ~(1 << (blockno % 32)); write_block(blockno / BIT2BLK); // write to disk. return blockno; } } // no free blocks. return -E_NO_DISK; }
if (filebno < NDIRECT) { // Step 1: if the target block is corresponded to a direct pointer, just return the // disk block number. // 如果索引号小于最大直接指针数量,可以直接返回 ptr = &f->f_direct[filebno]; } elseif (filebno < NINDIRECT) { // Step 2: if the target block is corresponded to the indirect block, but there's no // indirect block and `alloc` is set, create the indirect block. // 如果索引号大于10,说明需要检索间接索引 if (f->f_indirect == 0) { // 间接索引块不存在 if (alloc == 0) { // 索引块不存在并且参数表示不允许创建一个新块,返回错误值。 return -E_NOT_FOUND; } // 试图分配一个间接索引块 if ((r = alloc_block()) < 0) { return r; } f->f_indirect = r; }
// Step 3: read the new indirect block to memory. // 读取对应的磁盘块 if ((r = read_block(f->f_indirect, &blk, 0)) < 0) { return r; } // 设置索引指针。这里再次强调,我们的间接索引块的前十个索引是空的,因此直接使用filbno作为偏移即可 ptr = (u_int *)blk + filebno; } else { return -E_INVAL; }
// 设置索引指针 // Step 4: store the result into *ppdiskbno, and return 0. *ppdiskbno = ptr; return0; }
// 尝试寻找文件索引内部对应编号的索引指针 // Step 1: find the pointer for the target block. if ((r = file_block_walk(f, filebno, &ptr, alloc)) < 0) { return r; }
// 如果索引指针为空,并且alloc有效,分配一个新的block // Step 2: if the block not exists, and create is set, alloc one. if (*ptr == 0) { if (alloc == 0) { return -E_NOT_FOUND; }
// Step 1: find the disk block number is `f` using `file_map_block`. // 找到文件对应的索引块并读入内存 if ((r = file_map_block(f, filebno, &diskbno, 1)) < 0) { return r; }
// Step 2: read the data in this disk to blk. // 将指定磁盘块的内容读到内存中 if ((r = read_block(diskbno, blk, &isnew)) < 0) { return r; } return0; }
intfd_alloc(struct Fd **fd) { // Find the smallest i from 0 to MAXFD-1 that doesn't have // its fd page mapped. Set *fd to the fd page virtual address. // (Do not allocate a page. It is up to the caller to allocate // the page. This means that if someone calls fd_alloc twice // in a row without allocating the first page we return, we'll // return the same page the second time.) // Return 0 on success, or an error code on error. u_int va; u_int fdno;
// 从低至高遍历文件控制符,查找其中最小的没有被映射的fd for (fdno = 0; fdno < MAXFD - 1; fdno++) { // 转换为其对应的虚拟地址 va = INDEX2FD(fdno);
// 有效位为0,说明无效,说明这是个可以使用的fd if (((*vpd)[va / PDMAP] & PTE_V) == 0) { *fd = (struct Fd *)va; return0; } // 有效位为0,说明无效,说明这是个可使用的fd if (((*vpt)[va / BY2PG] & PTE_V) == 0) { //the fd is not used *fd = (struct Fd *)va; return0; } // 上述两层判断,含义为只要vpd和vpt有一个无效,就说明无效,就说明fd可用 }
// Overview: // Open a file (or directory). // // Returns: // the file descriptor onsuccess, // < 0 on failure. intopen(constchar *path, int mode) { structFd *fd; structFilefd *ffd; u_int size, fileid; int r; u_int va; u_int i;
// Step 1: Alloc a new Fd, return error code when fail to alloc. // Hint: Please use fd_alloc. // 申请一个新的文件描述符fd r = fd_alloc(&fd); if (r) return r;
// Step 2: Get the file descriptor of the file to open. // Hint: Read fsipc.c, and choose a function. // 根据给定路径和模式发送打开文件的ipc r = fsipc_open(path, mode, fd); if (r) return r;
// Step 3: Set the start address storing the file's content. Set size and fileid correctly. // Hint: Use fd2data to get the start address. // 根据文件内容设置起始地址 va = fd2data(fd);
// Step 4: Alloc memory, map the file content into memory. // 申请空间并映射文件内容 ffd = fd; size = ffd->f_file.f_size; fileid = ffd->f_fileid; // Step 5: Return the number of file descriptor. // 返回文件描述符 for (i = 0; i < size; i += BY2PG) { r = syscall_mem_alloc(0, va + i, PTE_R | PTE_V); if (r) return r; r = fsipc_map(fileid, i, va + i); if (r) return r; } int fdnum = fd2num(fd); if (mode & O_APPND) seek(fdnum, size); return fdnum; }
intfd_lookup(int fdnum, struct Fd **fd) { // Check that fdnum is in range and mapped. If not, return -E_INVAL. // Set *fd to the fd page virtual address. Return 0. u_int va;
// 大小超过文件控制符数量上限说明错误 if (fdnum >= MAXFD) { return -E_INVAL; }
va = INDEX2FD(fdnum);
if (((*vpt)[va / BY2PG] & PTE_V) != 0) { //the fd is used // 有效 *fd = (struct Fd *)va; return0; }
return -E_INVAL; }
dev_lookup
1 2 3 4 5 6 7 8 9 10 11 12 13 14
intdev_lookup(int dev_id, struct Dev **dev) { int i;
for (i = 0; devtab[i]; i++) if (devtab[i]->dev_id == dev_id) { *dev = devtab[i]; return0; }
writef("[%08x] unknown device type %d\n", env->env_id, dev_id); return -E_INVAL; }
This is copyright.