Esempio n. 1
0
// Synchronize the root process's console special files
// with the actual console I/O device.
bool
cons_io(void)
{
	int num_io = 0;

	// Get output file
	fileinode *fi = &files->fi[FILEINO_CONSOUT];
	int c;
	// spinlock_acquire(&cons_lock);
	while(cons_out_pos < fi->size) {
		c = ((char*)FILEDATA(FILEINO_CONSOUT))[cons_out_pos];
		cons_putc(c);
		num_io++;
		cons_out_pos++;
	}
	// spinlock_release(&cons_lock);
	// Input file
	fi = &files->fi[FILEINO_CONSIN];
	// Read from console
	while(fi->size <= FILE_MAXSIZE && (c = cons_getc())) {
		// And appened to CONSIN
		((char*)FILEDATA(FILEINO_CONSIN))[fi->size++] = c;
		num_io++;
	}

	return num_io;
}
Esempio n. 2
0
// Grow or shrink a file to exactly a specified size.
// If growing a file, then fills the new space with zeros.
// Returns 0 if successful, or returns -1 and sets errno on error.
int
fileino_truncate(int ino, off_t newsize)
{
	assert(fileino_isvalid(ino));
	assert(newsize >= 0 && newsize <= FILE_MAXSIZE);

	size_t oldsize = files->fi[ino].size;
	size_t oldpagelim = ROUNDUP(files->fi[ino].size, PAGESIZE);
	size_t newpagelim = ROUNDUP(newsize, PAGESIZE);
	if (newsize > oldsize) {
		// Grow the file and fill the new space with zeros.
		sys_get(SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL,
			FILEDATA(ino) + oldpagelim,
			newpagelim - oldpagelim);
		memset(FILEDATA(ino) + oldsize, 0, newsize - oldsize);
	} else if (newsize > 0) {
		// Shrink the file, but not all the way to empty.
		// Would prefer to use SYS_ZERO to free the file content,
		// but SYS_ZERO isn't guaranteed to work at page granularity.
		sys_get(SYS_PERM, 0, NULL, NULL,
			FILEDATA(ino) + newpagelim, FILE_MAXSIZE - newpagelim);
	} else {
		// Shrink the file to empty.  Use SYS_ZERO to free completely.
		sys_get(SYS_ZERO, 0, NULL, NULL, FILEDATA(ino), FILE_MAXSIZE);
	}
	files->fi[ino].size = newsize;
	files->fi[ino].ver++;	// truncation is always an exclusive change
	return 0;
}
Esempio n. 3
0
void
file_initroot(proc *root)
{
	// Only one root process may perform external I/O directly -
	// all other processes do I/O indirectly via the process hierarchy.
	assert(root == proc_root);

	// Make sure the root process's page directory is loaded,
	// so that we can write into the root process's file area directly.
	cpu_cur()->proc = root;
	lcr3(mem_phys(root->pdir));

	// Enable read/write access on the file metadata area
	pmap_setperm(root->pdir, FILESVA, ROUNDUP(sizeof(filestate), PAGESIZE),
				SYS_READ | SYS_WRITE);
	memset(files, 0, sizeof(*files));

	// Set up the standard I/O descriptors for console I/O
	files->fd[0].ino = FILEINO_CONSIN;
	files->fd[0].flags = O_RDONLY;
	files->fd[1].ino = FILEINO_CONSOUT;
	files->fd[1].flags = O_WRONLY | O_APPEND;
	files->fd[2].ino = FILEINO_CONSOUT;
	files->fd[2].flags = O_WRONLY | O_APPEND;

	// Setup the inodes for the console I/O files and root directory
	strcpy(files->fi[FILEINO_CONSIN].de.d_name, "consin");
	strcpy(files->fi[FILEINO_CONSOUT].de.d_name, "consout");
	strcpy(files->fi[FILEINO_ROOTDIR].de.d_name, "/");
	files->fi[FILEINO_CONSIN].dino = FILEINO_ROOTDIR;
	files->fi[FILEINO_CONSOUT].dino = FILEINO_ROOTDIR;
	files->fi[FILEINO_ROOTDIR].dino = FILEINO_ROOTDIR;
	files->fi[FILEINO_CONSIN].mode = S_IFREG | S_IFPART;
	files->fi[FILEINO_CONSOUT].mode = S_IFREG;
	files->fi[FILEINO_ROOTDIR].mode = S_IFDIR;

	// Set the whole console input area to be read/write,
	// so we won't have to worry about perms in cons_io().
	pmap_setperm(root->pdir, (uintptr_t)FILEDATA(FILEINO_CONSIN),
				PTSIZE, SYS_READ | SYS_WRITE);

	// Set up the initial files in the root process's file system.
	// Some script magic in kern/Makefrag creates obj/kern/initfiles.h,
	// which gets included above (twice) to create the 'initfiles' array.
	// For each initial file numbered 0 <= i < ninitfiles,
	// initfiles[i][0] is a pointer to the filename string for that file,
	// initfiles[i][1] is a pointer to the start of the file's content, and
	// initfiles[i][2] is a pointer to the end of the file's content
	// (i.e., a pointer to the first byte after the file's last byte).
	int ninitfiles = sizeof(initfiles)/sizeof(initfiles[0]);
	// Lab 4: your file system initialization code here.
	warn("file_initroot: file system initialization not done\n");

	// Set root process's current working directory
	files->cwd = FILEINO_ROOTDIR;

	// Child process state - reserve PID 0 as a "scratch" child process.
	files->child[0].state = PROC_RESERVED;
}
Esempio n. 4
0
// Write 'count' data elements each of size 'eltsize'
// starting at absolute byte offset 'ofs' within the file in inode 'ino'.
// Returns the number of elements actually written,
// which should always be equal to the 'count' input parameter
// unless an error occurs, in which case this function
// returns -1 and sets errno appropriately.
// Since PIOS files can be up to only FILE_MAXSIZE bytes in size (4MB),
// one particular reason an error might occur is if an application
// tries to grow a file beyond this maximum file size,
// in which case this function generates the EFBIG error.
ssize_t
fileino_write(int ino, off_t ofs, const void *buf, size_t eltsize, size_t count)
{
	assert(fileino_isreg(ino));
	assert(ofs >= 0);
	assert(eltsize > 0);

	fileinode *fi = &files->fi[ino];
	assert(fi->size <= FILE_MAXSIZE);

#if SOL >= 4
	// Return an error if we'd be growing the file too big.
	size_t len = eltsize * count;
	size_t lim = ofs + len;
	if (lim < ofs || lim > FILE_MAXSIZE) {
		errno = EFBIG;
		return -1;
	}

	// Grow the file as necessary.
	if (lim > fi->size) {
		size_t oldpagelim = ROUNDUP(fi->size, PAGESIZE);
		size_t newpagelim = ROUNDUP(lim, PAGESIZE);
		if (newpagelim > oldpagelim)
			sys_get(SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL,
				FILEDATA(ino) + oldpagelim,
				newpagelim - oldpagelim);
		fi->size = lim;
	}

	// Write the data.
	memmove(FILEDATA(ino) + ofs, buf, len);
	return count;
#else	// ! SOL >= 4
	// Lab 4: insert your file writing code here.
	warn("fileino_write() not implemented");
	errno = EINVAL;
	return -1;
#endif	// ! SOL >= 4
}
Esempio n. 5
0
// Read up to 'count' data elements each of size 'eltsize',
// starting at absolute byte offset 'ofs' within the file in inode 'ino'.
// Returns the number of elements (NOT the number of bytes!) actually read,
// or if an error occurs, returns -1 and sets errno appropriately.
// The number of elements returned is normally equal to the 'count' parameter,
// but may be less (without resulting in an error)
// if the file is not large enough to read that many elements.
ssize_t
fileino_read(int ino, off_t ofs, void *buf, size_t eltsize, size_t count)
{
	assert(fileino_isreg(ino));
	assert(ofs >= 0);
	assert(eltsize > 0);

	fileinode *fi = &files->fi[ino];
#if LAB >= 9
	// XXX hack: allow reading init-files bigger than 4MB
#else
	assert(fi->size <= FILE_MAXSIZE);
#endif

#if SOL >= 4
	ssize_t actual = 0;
	while (count > 0) {
		// Read as many elements as we can from the file.
		// Note: fd->ofs could well point beyond the end of file,
		// which means that avail will be negative - but that's OK.
		ssize_t avail = MIN(count, (fi->size - ofs) / eltsize);
		if (ofs >= fi->size)
			avail = 0;
		if (avail > 0) {
			memmove(buf, FILEDATA(ino) + ofs, avail * eltsize);
			buf += avail * eltsize;
			actual += avail;
			count -= avail;
		}

		// If there's no more we can read, stop now.
		if (count == 0 || !(fi->mode & S_IFPART))
			break;

		// Wait for our parent to extend (or close) the file.
#if LAB >= 99
		cprintf("fileino_read: waiting for input on file %d\n",
			fd - files->fd);
#endif
		sys_ret();
	}
	return actual;
#else	// ! SOL >= 4
	// Lab 4: insert your file reading code here.
	warn("fileino_read() not implemented");
	errno = EINVAL;
	return -1;
#endif	// ! SOL >= 4
}
Esempio n. 6
0
int
ungetc(int c, FILE *fd)
{
	// We only support the most common use of ungetc(),
	// to back up the read position after "peeking" a character.
	assert(filedesc_isreadable(fd));
	fileinode *fi = &files->fi[fd->ino];
	if (c == EOF || fd->ofs <= 0 || fd->ofs > fi->size) {
		errno = EINVAL;
		return EOF;
	}
	if (((uint8_t*)FILEDATA(fd->ino))[--fd->ofs] != c)
		panic("ungetc: unsupported usage, ungetting the wrong char");
	return c;
}
Esempio n. 7
0
int
exec_readelf(const char *path)
{
	// We'll load the ELF image into a scratch area in our address space.
	sys_get(SYS_ZERO, 0, NULL, NULL, (void*)VM_SCRATCHLO, EXEMAX);

	// Open the ELF image to load.
	filedesc *fd = filedesc_open(NULL, path, O_RDONLY, 0);
	if (fd == NULL)
		return -1;
	void *imgdata = FILEDATA(fd->ino);
	size_t imgsize = files->fi[fd->ino].size;

	// Make sure it looks like an ELF image.
	elfhdr *eh = imgdata;
	if (imgsize < sizeof(*eh) || eh->e_magic != ELF_MAGIC) {
		warn("exec_readelf: ELF header not found");
		goto err;
	}

	// Load each program segment into the scratch area
	proghdr *ph = imgdata + eh->e_phoff;
	proghdr *eph = ph + eh->e_phnum;
	if (imgsize < (void*)eph - imgdata) {
		warn("exec_readelf: ELF program header truncated");
		goto err;
	}
	for (; ph < eph; ph++) {
		if (ph->p_type != ELF_PROG_LOAD)
			continue;

		// The executable should fit in the first 4MB of user space.
		intptr_t valo = ph->p_va;
		intptr_t vahi = valo + ph->p_memsz;
		if (valo < VM_USERLO || valo > VM_USERLO+EXEMAX ||
				vahi < valo || vahi > VM_USERLO+EXEMAX) {
			warn("exec_readelf: executable image too large "
				"(%d bytes > %d max)", vahi-valo, EXEMAX);
			goto err;
		}

		// Map all pages the segment touches in our scratch region.
		// They've already been zeroed by the SYS_ZERO above.
		intptr_t scratchofs = VM_SCRATCHLO - VM_USERLO;
		intptr_t pagelo = ROUNDDOWN(valo, PAGESIZE);
		intptr_t pagehi = ROUNDUP(vahi, PAGESIZE);
		sys_get(SYS_PERM | SYS_READ | SYS_WRITE, 0, NULL, NULL,
			(void*)pagelo + scratchofs, pagehi - pagelo);

		// Initialize the file-loaded part of the ELF image.
		// (We could use copy-on-write if SYS_COPY
		// supports copying at arbitrary page boundaries.)
		intptr_t filelo = ph->p_offset;
		intptr_t filehi = filelo + ph->p_filesz;
		if (filelo < 0 || filelo > imgsize
				|| filehi < filelo || filehi > imgsize) {
			warn("exec_readelf: loaded section out of bounds");
			goto err;
		}
		memcpy((void*)valo + scratchofs, imgdata + filelo,
			filehi - filelo);

		// Finally, remove write permissions on read-only segments.
		if (!(ph->p_flags & ELF_PROG_FLAG_WRITE))
			sys_get(SYS_PERM | SYS_READ, 0, NULL, NULL,
				(void*)pagelo + scratchofs, pagehi - pagelo);
	}

	// Copy the ELF image into its correct position in child 0.
	sys_put(SYS_COPY, 0, NULL, (void*)VM_SCRATCHLO,
		(void*)VM_USERLO, EXEMAX);

	// The new program should have the same entrypoint as we do!
	if (eh->e_entry != (intptr_t)start) {
		warn("exec_readelf: executable has a different start address");
		goto err;
	}

	filedesc_close(fd);	// Done with the ELF file
	return 0;

err:
	filedesc_close(fd);
	return -1;
}