static int load_each_segment(struct vnode *v, off_t offset, vaddr_t vaddr, paddr_t paddr, size_t memsize, size_t filesize, int is_executable, int first_read) { struct uio u; int result; size_t fillamt; int spl; if (filesize > memsize) { kprintf("ELF: warning: segment filesize > segment memsize\n"); filesize = memsize; } DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", (unsigned long) filesize, (unsigned long) vaddr); if(first_read == 0){ u.uio_iovec.iov_ubase = (userptr_t)vaddr; u.uio_iovec.iov_len = memsize; // length of the memory space u.uio_resid = filesize; // amount to actually read u.uio_offset = offset; u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE; u.uio_rw = UIO_READ; u.uio_space = curthread->t_vmspace; }else{ return 0; } result = VOP_READ(v, &u); if (result) { return result; } if (u.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on segment - file truncated?\n"); return ENOEXEC; } /* Fill the rest of the memory space (if any) with zeros */ fillamt = memsize - filesize; if (fillamt > 0) { DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n", (unsigned long) fillamt); u.uio_resid += fillamt; result = uiomovezeros(fillamt, &u); } return result; }
/* * Load a segment at virtual address VADDR. The segment in memory * extends from VADDR up to (but not including) VADDR+MEMSIZE. The * segment on disk is located at file offset OFFSET and has length * FILESIZE. * * FILESIZE may be less than MEMSIZE; if so the remaining portion of * the in-memory segment should be zero-filled. * * Note that uiomove will catch it if someone tries to load an * executable whose load address is in kernel space. If you should * change this code to not use uiomove, be sure to check for this case * explicitly. */ int load_segment(struct vnode *v, off_t offset, vaddr_t vaddr, size_t memsize, size_t filesize, int is_executable) { struct uio u; // Memory block int result; size_t fillamt; // The virtual memory has to be bigger then the file that we are loading into it if (filesize > memsize) { kprintf("ELF: warning: segment filesize > segment memsize\n"); filesize = memsize; } DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", (unsigned long) filesize, (unsigned long) vaddr); //u.uio_iovec.iov_ubase = (userptr_t)PADDR_TO_KVADDR(vaddr); u.uio_iovec.iov_ubase = (userptr_t)vaddr; u.uio_iovec.iov_len = memsize; // length of the memory space u.uio_resid = filesize; // amount to actually read u.uio_offset = offset; //u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE; u.uio_segflg = UIO_SYSSPACE; u.uio_rw = UIO_READ; //u.uio_space = curthread->t_vmspace; u.uio_space = NULL; result = VOP_READ(v, &u); if (result) { return result; } DEBUG(1,"after read\n"); if (u.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on segment - file truncated?\n"); return ENOEXEC; } /* Fill the rest of the memory space (if any) with zeros */ fillamt = memsize - filesize; if (fillamt > 0) { DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n", (unsigned long) fillamt); u.uio_resid += fillamt; result = uiomovezeros(fillamt, &u); } return result; }
/* * Do I/O (either read or write) of a single whole block. */ static int sfs_blockio(struct sfs_vnode *sv, struct uio *uio) { struct sfs_fs *sfs = sv->sv_v.vn_fs->fs_data; u_int32_t diskblock; u_int32_t fileblock; int result; int doalloc = (uio->uio_rw==UIO_WRITE); off_t saveoff; off_t diskoff; off_t saveres; off_t diskres; /* Get the block number within the file */ fileblock = uio->uio_offset / SFS_BLOCKSIZE; /* Look up the disk block number */ result = sfs_bmap(sv, fileblock, doalloc, &diskblock); if (result) { return result; } if (diskblock == 0) { /* * No block - fill with zeros. * * We must be reading, or sfs_bmap would have * allocated a block for us. */ assert(uio->uio_rw == UIO_READ); return uiomovezeros(SFS_BLOCKSIZE, uio); } /* * Do the I/O directly to the uio region. Save the uio_offset, * and substitute one that makes sense to the device. */ saveoff = uio->uio_offset; diskoff = diskblock * SFS_BLOCKSIZE; uio->uio_offset = diskoff; /* * Temporarily set the residue to be one block size. */ assert(uio->uio_resid >= SFS_BLOCKSIZE); saveres = uio->uio_resid; diskres = SFS_BLOCKSIZE; uio->uio_resid = diskres; result = sfs_rwblock(sfs, uio); /* * Now, restore the original uio_offset and uio_resid and update * them by the amount of I/O done. */ uio->uio_offset = (uio->uio_offset - diskoff) + saveoff; uio->uio_resid = (uio->uio_resid - diskres) + saveres; return result; }
/* * Load a segment at virtual address VADDR. The segment in memory * extends from VADDR up to (but not including) VADDR+MEMSIZE. The * segment on disk is located at file offset OFFSET and has length * FILESIZE. * * FILESIZE may be less than MEMSIZE; if so the remaining portion of * the in-memory segment should be zero-filled. * * Note that uiomove will catch it if someone tries to load an * executable whose load address is in kernel space. If you should * change this code to not use uiomove, be sure to check for this case * explicitly. */ static int load_segment(struct addrspace *as, struct vnode *v, off_t offset, vaddr_t vaddr, size_t memsize, size_t filesize, int is_executable) { struct iovec iov; struct uio u; int result; if (filesize > memsize) { kprintf("ELF: warning: segment filesize > segment memsize\n"); filesize = memsize; } DEBUG(DB_EXEC, "ELF: Loading %lu bytes to 0x%lx\n", (unsigned long) filesize, (unsigned long) vaddr); iov.iov_ubase = (userptr_t)vaddr; iov.iov_len = memsize; // length of the memory space u.uio_iov = &iov; u.uio_iovcnt = 1; u.uio_resid = filesize; // amount to read from the file u.uio_offset = offset; u.uio_segflg = is_executable ? UIO_USERISPACE : UIO_USERSPACE; u.uio_rw = UIO_READ; u.uio_space = as; result = VOP_READ(v, &u); if (result) { return result; } if (u.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on segment - file truncated?\n"); return ENOEXEC; } /* * If memsize > filesize, the remaining space should be * zero-filled. There is no need to do this explicitly, * because the VM system should provide pages that do not * contain other processes' data, i.e., are already zeroed. * * During development of your VM system, it may have bugs that * cause it to (maybe only sometimes) not provide zero-filled * pages, which can cause user programs to fail in strange * ways. Explicitly zeroing program BSS may help identify such * bugs, so the following disabled code is provided as a * diagnostic tool. Note that it must be disabled again before * you submit your code for grading. */ #if 0 { size_t fillamt; fillamt = memsize - filesize; if (fillamt > 0) { DEBUG(DB_EXEC, "ELF: Zero-filling %lu more bytes\n", (unsigned long) fillamt); u.uio_resid += fillamt; result = uiomovezeros(fillamt, &u); } } #endif return result; }
int swap_pagein( u_int32_t paddr, int rw, u_int32_t mem, u_int32_t file, u_int32_t offset, int swap, int swap_index) { int result; int fillamt; struct uio u; struct addrspace *as; // struct vnode *swap_vnode; as = curthread->t_vmspace; if(swap == 1) { result = vfs_open(SWAP_DEVICE, O_RDWR, &swap_vnode); mk_kuio(&u, paddr, PAGE_SIZE, swap_index * PAGE_SIZE, UIO_READ); result = VOP_READ(swap_vnode, &u); if (result) { return result; } vfs_close(swap_vnode); } else { /* Open the file. */ struct vnode *v; result = vfs_open(as->as_progname, O_RDONLY, &v); if (result) { return result; } mk_kuio_pd(&u, paddr, mem, file, offset, rw); if(rw == UIO_READ) { result = VOP_READ(v, &u) ; } else { result = VOP_WRITE(v, &u); } if (u.uio_resid != 0) { /* short read; problem with executable? */ kprintf("ELF: short read on segment - file truncated?\n"); return ENOEXEC; } /* Fill the rest of the memory space (if any) with zeros */ fillamt = mem - file; if (fillamt > 0) { u.uio_resid += fillamt; u.uio_rw = UIO_READ; result = uiomovezeros(fillamt, &u); } if (result==EIO) { panic("swap: EIO on swapfile (offset %ld)\n", (long)as->as_offset1); } else if (result==EINVAL) { panic("swap: EINVAL from swapfile (offset %ld)\n", (long)as->as_offset1); } else if (result) { panic("swap: Error %d from swapfile (offset %ld)\n", result, (long)as->as_offset1); } /* Done with the file now. */ vfs_close(v); return 0; } }
/* * Do I/O (either read or write) of a single whole block. * * Locking: must hold vnode lock. May get/release sfs_freemaplock. * * Requires up to 2 buffers. */ static int sfs_blockio(struct sfs_vnode *sv, struct uio *uio) { struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; struct buf *iobuf; void *ioptr; daddr_t diskblock; uint32_t fileblock; int result; bool doalloc = (uio->uio_rw==UIO_WRITE); unsigned new_checksum = 0; KASSERT(lock_do_i_hold(sv->sv_lock)); /* Get the block number within the file */ fileblock = uio->uio_offset / SFS_BLOCKSIZE; /* Look up the disk block number */ result = sfs_bmap(sv, fileblock, doalloc, &diskblock); if (result) { return result; } if (diskblock == 0) { /* * No block - fill with zeros. * * We must be reading, or sfs_bmap would have * allocated a block for us. */ KASSERT(uio->uio_rw == UIO_READ); return uiomovezeros(SFS_BLOCKSIZE, uio); } if (uio->uio_rw == UIO_READ) { result = buffer_read(&sfs->sfs_absfs, diskblock, SFS_BLOCKSIZE, &iobuf); } else { result = buffer_get(&sfs->sfs_absfs, diskblock, SFS_BLOCKSIZE, &iobuf); } if (result) { return result; } /* * Do the I/O into the buffer. */ ioptr = buffer_map(iobuf); result = uiomove(ioptr, SFS_BLOCKSIZE, uio); if (result) { buffer_release(iobuf); return result; } if (uio->uio_rw == UIO_WRITE) { new_checksum = checksum(ioptr); sfs_jphys_write_wrapper(sfs, NULL, jentry_block_write(diskblock, new_checksum, false)); buffer_mark_valid(iobuf); buffer_mark_dirty(iobuf); // Journalled } buffer_release(iobuf); return 0; }
/* * Do I/O to a block of a file that doesn't cover the whole block. We * need to read in the original block first, even if we're writing, so * we don't clobber the portion of the block we're not intending to * write over. * * SKIPSTART is the number of bytes to skip past at the beginning of * the sector; LEN is the number of bytes to actually read or write. * UIO is the area to do the I/O into. * * Requires up to 2 buffers. */ static int sfs_partialio(struct sfs_vnode *sv, struct uio *uio, uint32_t skipstart, uint32_t len) { struct sfs_fs *sfs = sv->sv_absvn.vn_fs->fs_data; struct buf *iobuffer; unsigned char *ioptr; daddr_t diskblock; uint32_t fileblock; int result; unsigned new_checksum = 0; /* Allocate missing blocks if and only if we're writing */ bool doalloc = (uio->uio_rw==UIO_WRITE); KASSERT(lock_do_i_hold(sv->sv_lock)); KASSERT(skipstart + len <= SFS_BLOCKSIZE); /* Compute the block offset of this block in the file */ fileblock = uio->uio_offset / SFS_BLOCKSIZE; /* Get the disk block number */ result = sfs_bmap(sv, fileblock, doalloc, &diskblock); if (result) { return result; } if (diskblock == 0) { /* * There was no block mapped at this point in the file. * * We must be reading, or sfs_bmap would have * allocated a block for us. */ KASSERT(uio->uio_rw == UIO_READ); return uiomovezeros(len, uio); } else { /* * Read the block. */ result = buffer_read(&sfs->sfs_absfs, diskblock, SFS_BLOCKSIZE, &iobuffer); if (result) { return result; } } /* * Now perform the requested operation into/out of the buffer. */ ioptr = buffer_map(iobuffer); result = uiomove(ioptr+skipstart, len, uio); if (result) { buffer_release(iobuffer); return result; } /* * If it was a write, mark the modified block dirty and journal */ if (uio->uio_rw == UIO_WRITE) { // Compute checksum and journal new_checksum = checksum(ioptr); sfs_jphys_write_wrapper(sfs, NULL, jentry_block_write(diskblock, new_checksum, false)); buffer_mark_dirty(iobuffer); // Journalled } buffer_release(iobuffer); return 0; }