userprog_SRC += userprog/tss.c # TSS management.
# No virtual memory code yet.
--#vm_SRC = vm/filename.c # Some file.
+-#vm_SRC = vm/file.c # Some file.
+vm_SRC = vm/page.c
+vm_SRC += vm/frame.c
+vm_SRC += vm/swap.c
return success;
}
-@@ -205,8 +210,10 @@ dir_list (const struct dir *dir)
+@@ -216,14 +216,17 @@
+ {
struct dir_entry e;
- size_t ofs;
-
+
+ inode_lock (dir->inode);
- for (ofs = 0; inode_read_at (dir->inode, &e, sizeof e, ofs) == sizeof e;
- ofs += sizeof e)
- if (e.in_use)
- printf ("%s\n", e.name);
+ while (inode_read_at (dir->inode, &e, sizeof e, dir->pos) == sizeof e)
+ {
+ dir->pos += sizeof e;
+ if (e.in_use)
+ {
+ strlcpy (name, e.name, NAME_MAX + 1);
++ inode_unlock (dir->inode);
+ return true;
+ }
+ }
+ inode_unlock (dir->inode);
+ return false;
}
Index: src/filesys/directory.h
diff -u src/filesys/directory.h~ src/filesys/directory.h
--- src/filesys/directory.h 2006-05-18 22:26:02.000000000 -0700
+++ src/filesys/directory.h 2006-05-18 22:05:40.000000000 -0700
@@ -12,6 +11,5 @@
- #define NAME_MAX 14
-
struct inode;
+
+ /* Opening and closing directories. */
-bool dir_create (disk_sector_t sector, size_t entry_cnt);
struct dir *dir_open (struct inode *);
struct dir *dir_open_root (void);
#include "devices/disk.h"
+#include "threads/thread.h"
- /* The disk that contains the filesystem. */
+ /* The disk that contains the file system. */
struct disk *filesys_disk;
@@ -23,6 +25,7 @@ filesys_init (bool format)
- PANIC ("hd0:1 (hdb) not present, filesystem initialization failed");
+ PANIC ("hd0:1 (hdb) not present, file system initialization failed");
inode_init ();
+ cache_init ();
+/* Resolves relative or absolute file NAME.
+ Returns true if successful, false on failure.
+ Stores the directory corresponding to the name into *DIRP,
-+ and the file name part into BASENAME. */
++ and the file name part into BASE_NAME. */
+static bool
+resolve_name (const char *name,
-+ struct dir **dirp, char basename[NAME_MAX + 1])
++ struct dir **dirp, char base_name[NAME_MAX + 1])
+{
+ struct dir *dir = NULL;
+ struct inode *inode;
+
+ /* Return our results. */
+ *dirp = dir;
-+ strlcpy (basename, part, NAME_MAX + 1);
++ strlcpy (base_name, part, NAME_MAX + 1);
+ return true;
+
+ error:
+ /* Return failure. */
+ dir_close (dir);
+ *dirp = NULL;
-+ basename[0] = '\0';
++ base_name[0] = '\0';
+ return false;
}
\f
+filesys_create (const char *name, off_t initial_size, enum inode_type type)
{
+ struct dir *dir;
-+ char basename[NAME_MAX + 1];
++ char base_name[NAME_MAX + 1];
disk_sector_t inode_sector = 0;
- struct dir *dir = dir_open_root ();
- bool success = (dir != NULL
- && free_map_allocate (1, &inode_sector)
- && inode_create (inode_sector, initial_size)
- && dir_add (dir, name, inode_sector));
-+ bool success = (resolve_name (name, &dir, basename)
++ bool success = (resolve_name (name, &dir, base_name)
+ && free_map_allocate (&inode_sector)
+ && inode_create (inode_sector, initial_size, type)
-+ && dir_add (dir, basename, inode_sector));
++ && dir_add (dir, base_name, inode_sector));
if (!success && inode_sector != 0)
- free_map_release (inode_sector, 1);
+ free_map_release (inode_sector);
dir_close (dir);
return success;
-@@ -64,17 +161,18 @@ filesys_create (const char *name, off_t
+@@ -64,17 +161,22 @@ filesys_create (const char *name, off_t
otherwise.
Fails if no file named NAME exists,
or if an internal memory allocation fails. */
filesys_open (const char *name)
{
- struct dir *dir = dir_open_root ();
-+ struct dir *dir;
-+ char basename[NAME_MAX + 1];
++ struct dir *dir = NULL;
++ char base_name[NAME_MAX + 1];
struct inode *inode = NULL;
- if (dir != NULL)
- dir_lookup (dir, name, &inode);
-+ if (resolve_name (name, &dir, basename))
-+ dir_lookup (dir, basename, &inode);
++ if (!strcmp (name, "/"))
++ inode = inode_open (ROOT_DIR_SECTOR);
++ else if (!strcmp (name, "."))
++ inode = inode_reopen (dir_get_inode (thread_current ()->wd));
++ else if (resolve_name (name, &dir, base_name))
++ dir_lookup (dir, base_name, &inode);
dir_close (dir);
- return file_open (inode);
}
/* Deletes the file named NAME.
-@@ -84,13 +182,56 @@ filesys_open (const char *name)
+@@ -84,7 +182,11 @@ filesys_open (const char *name)
bool
filesys_remove (const char *name)
{
- struct dir *dir = dir_open_root ();
- bool success = dir != NULL && dir_remove (dir, name);
+ struct dir *dir = NULL;
-+ char basename[NAME_MAX + 1];
++ char base_name[NAME_MAX + 1];
+ bool success = false;
+
-+ if (resolve_name (name, &dir, basename))
-+ success = dir_remove (dir, basename);
++ if (resolve_name (name, &dir, base_name))
++ success = dir_remove (dir, base_name);
dir_close (dir);
+@@ -91,5 +193,44 @@
return success;
}
-
+/* Change current directory to NAME.
+ Return true if successful, false on failure. */
+bool
+ }
+ else
+ {
-+ char basename[NAME_MAX + 1];
++ char base_name[NAME_MAX + 1];
+ struct inode *base_inode;
+ struct dir *base_dir;
-+ if (!resolve_name (name, &dir, basename)
-+ || !dir_lookup (dir, basename, &base_inode)
++ if (!resolve_name (name, &dir, base_name)
++ || !dir_lookup (dir, base_name, &base_inode)
+ || (base_dir = dir_open (base_inode)) == NULL)
+ {
+ dir_close (dir);
+ return true;
+}
+
- /* Prints a list of files in the filesystem to the system
- console.
- Returns true if successful, false on failure,
-@@ -98,15 +239,9 @@ filesys_remove (const char *name)
- bool
- filesys_list (void)
- {
-- struct dir *dir = dir_open_root ();
-- if (dir != NULL)
-- {
-- dir_list (dir);
-- dir_close (dir);
-- return true;
-- }
-- else
-- return false;
-+ dir_list (thread_current ()->wd);
-+
-+ return true;
- }
\f
static void must_succeed_function (int, bool) NO_INLINE;
+ #define MUST_SUCCEED(EXPR) must_succeed_function (__LINE__, EXPR)
@@ -129,8 +264,8 @@ filesys_self_test (void)
{
/* Create file and check that it contains zeros
@@ -173,9 +308,13 @@ static void
do_format (void)
{
- printf ("Formatting filesystem...");
+ printf ("Formatting file system...");
+
+ /* Set up free map. */
free_map_create ();
/* Sectors of system file inodes. */
#define FREE_MAP_SECTOR 0 /* Free map file inode sector. */
-@@ -13,8 +14,8 @@ extern struct disk *filesys_disk;
+@@ -13,9 +14,10 @@ extern struct disk *filesys_disk;
void filesys_init (bool format);
void filesys_done (void);
+bool filesys_create (const char *name, off_t initial_size, enum inode_type);
+struct inode *filesys_open (const char *name);
bool filesys_remove (const char *name);
- bool filesys_chdir (const char *name);
- bool filesys_list (void);
++bool filesys_chdir (const char *name);
+
+ void filesys_self_test (void);
+
Index: src/filesys/free-map.c
diff -u src/filesys/free-map.c~ src/filesys/free-map.c
--- src/filesys/free-map.c 2005-06-18 20:20:48.000000000 -0700
@@ -30,7 +30,7 @@ fsutil_cat (char **argv)
char *buffer;
- printf ("Printing '%s' to the console...\n", filename);
-- file = filesys_open (filename);
-+ file = file_open (filesys_open (filename));
+ printf ("Printing '%s' to the console...\n", file_name);
+- file = filesys_open (file_name);
++ file = file_open (filesys_open (file_name));
if (file == NULL)
- PANIC ("%s: open failed", filename);
+ PANIC ("%s: open failed", file_name);
buffer = palloc_get_page (PAL_ASSERT);
@@ -102,9 +102,9 @@ fsutil_put (char **argv)
- PANIC ("%s: invalid file size %d", filename, size);
+ PANIC ("%s: invalid file size %d", file_name, size);
/* Create destination file. */
-- if (!filesys_create (filename, size))
-+ if (!filesys_create (filename, size, FILE_INODE))
- PANIC ("%s: create failed", filename);
-- dst = filesys_open (filename);
-+ dst = file_open (filesys_open (filename));
+- if (!filesys_create (file_name, size))
++ if (!filesys_create (file_name, size, FILE_INODE))
+ PANIC ("%s: create failed", file_name);
+- dst = filesys_open (file_name);
++ dst = file_open (filesys_open (file_name));
if (dst == NULL)
- PANIC ("%s: open failed", filename);
+ PANIC ("%s: open failed", file_name);
@@ -154,7 +154,7 @@ fsutil_get (char **argv)
PANIC ("couldn't allocate buffer");
/* Open source file. */
-- src = filesys_open (filename);
-+ src = file_open (filesys_open (filename));
+- src = filesys_open (file_name);
++ src = file_open (filesys_open (file_name));
if (src == NULL)
- PANIC ("%s: open failed", filename);
+ PANIC ("%s: open failed", file_name);
size = file_length (src);
Index: src/filesys/inode.c
diff -u src/filesys/inode.c~ src/filesys/inode.c
+ thread. */
+struct exec_info
+ {
-+ const char *filename; /* Program to load. */
++ const char *file_name; /* Program to load. */
+ struct semaphore load_done; /* "Up"ed when loading complete. */
+ struct wait_status *wait_status; /* Child process. */
+ struct dir *wd; /* Working directory. */
+ };
/* Starts a new thread running a user program loaded from
- FILENAME. The new thread may be scheduled (and may even exit)
+ FILE_NAME. The new thread may be scheduled (and may even exit)
@@ -28,41 +43,78 @@ static bool load (const char *cmdline, v
tid_t
- process_execute (const char *filename)
+ process_execute (const char *file_name)
{
- char *fn_copy;
+ struct dir *wd = thread_current ()->wd;
+ char *save_ptr;
tid_t tid;
-- /* Make a copy of FILENAME.
+- /* Make a copy of FILE_NAME.
- Otherwise there's a race between the caller and load(). */
- fn_copy = palloc_get_page (0);
- if (fn_copy == NULL)
+ /* Initialize exec_info. */
-+ exec.filename = filename;
++ exec.file_name = file_name;
+ exec.wd = wd != NULL ? dir_reopen (wd) : dir_open_root ();
+ if (exec.wd == NULL)
return TID_ERROR;
-- strlcpy (fn_copy, filename, PGSIZE);
+- strlcpy (fn_copy, file_name, PGSIZE);
+ sema_init (&exec.load_done, 0);
- /* Create a new thread to execute FILENAME. */
-- tid = thread_create (filename, PRI_DEFAULT, execute_thread, fn_copy);
+ /* Create a new thread to execute FILE_NAME. */
+- tid = thread_create (file_name, PRI_DEFAULT, execute_thread, fn_copy);
- if (tid == TID_ERROR)
- palloc_free_page (fn_copy);
-+ strlcpy (thread_name, filename, sizeof thread_name);
++ strlcpy (thread_name, file_name, sizeof thread_name);
+ strtok_r (thread_name, " ", &save_ptr);
+ tid = thread_create (thread_name, PRI_DEFAULT, execute_thread, &exec);
+ if (tid != TID_ERROR)
/* A thread function that loads a user process and starts it
running. */
static void
--execute_thread (void *filename_)
+-execute_thread (void *file_name_)
+execute_thread (void *exec_)
{
-- char *filename = filename_;
+- char *file_name = file_name_;
+ struct exec_info *exec = exec_;
struct intr_frame if_;
bool success;
if_.gs = if_.fs = if_.es = if_.ds = if_.ss = SEL_UDSEG;
if_.cs = SEL_UCSEG;
if_.eflags = FLAG_IF | FLAG_MBS;
-- success = load (filename, &if_.eip, &if_.esp);
-+ success = load (exec->filename, &if_.eip, &if_.esp);
+- success = load (file_name, &if_.eip, &if_.esp);
++ success = load (exec->file_name, &if_.eip, &if_.esp);
- /* If load failed, quit. */
-- palloc_free_page (filename);
+- palloc_free_page (file_name);
+ /* Allocate wait_status. */
+ if (success)
+ {
if (!success)
thread_exit ();
-@@ -76,18 +128,47 @@ execute_thread (void *filename_)
+@@ -76,18 +128,47 @@ execute_thread (void *file_name_)
NOT_REACHED ();
}
and its initial stack pointer into *ESP.
Returns true if successful, false otherwise. */
bool
--load (const char *filename, void (**eip) (void), void **esp)
+-load (const char *file_name, void (**eip) (void), void **esp)
+load (const char *cmd_line, void (**eip) (void), void **esp)
{
struct thread *t = thread_current ();
-+ char filename[NAME_MAX + 2];
++ char file_name[NAME_MAX + 2];
struct Elf32_Ehdr ehdr;
struct file *file = NULL;
off_t file_ofs;
int i;
/* Allocate and activate page directory. */
-@@ -220,13 +330,28 @@ load (const char *filename, void (**eip)
+@@ -220,13 +330,28 @@ load (const char *file_name, void (**eip)
goto done;
process_activate ();
+ goto done;
+ hash_init (t->pages, page_hash, page_less, NULL);
+
-+ /* Extract filename from command line. */
++ /* Extract file_name from command line. */
+ while (*cmd_line == ' ')
+ cmd_line++;
-+ strlcpy (filename, cmd_line, sizeof filename);
-+ cp = strchr (filename, ' ');
++ strlcpy (file_name, cmd_line, sizeof file_name);
++ cp = strchr (file_name, ' ');
+ if (cp != NULL)
+ *cp = '\0';
+
/* Open executable file. */
-- file = filesys_open (filename);
-+ t->bin_file = file = file_open (filesys_open (filename));
+- file = filesys_open (file_name);
++ t->bin_file = file = file_open (filesys_open (file_name));
if (file == NULL)
{
- printf ("load: %s: open failed\n", filename);
+ printf ("load: %s: open failed\n", file_name);
goto done;
}
+ file_deny_write (file);
/* Read and verify executable header. */
if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
-@@ -301,7 +426,7 @@ load (const char *filename, void (**eip)
+@@ -301,7 +426,7 @@ load (const char *file_name, void (**eip)
}
/* Set up stack. */
goto done;
/* Start address. */
-@@ -311,14 +436,11 @@ load (const char *filename, void (**eip)
+@@ -311,14 +436,11 @@ load (const char *file_name, void (**eip)
done:
/* We arrive here whether the load is successful or not. */
diff -u src/userprog/syscall.c~ src/userprog/syscall.c
--- src/userprog/syscall.c 2005-06-18 20:21:21.000000000 -0700
+++ src/userprog/syscall.c 2006-05-18 21:26:51.000000000 -0700
-@@ -1,20 +1,594 @@
+@@ -1,20 +1,671 @@
#include "userprog/syscall.h"
#include <stdio.h>
+#include <string.h>
+static int sys_munmap (int mapping);
+static int sys_chdir (const char *udir);
+static int sys_mkdir (const char *udir);
-+static int sys_lsdir (void);
++static int sys_readdir (int handle, char *name);
++static int sys_isdir (int handle);
+
static void syscall_handler (struct intr_frame *);
-
+ {1, (syscall_function *) sys_munmap},
+ {1, (syscall_function *) sys_chdir},
+ {1, (syscall_function *) sys_mkdir},
-+ {0, (syscall_function *) sys_lsdir},
++ {2, (syscall_function *) sys_readdir},
++ {1, (syscall_function *) sys_isdir},
+ };
+ const struct syscall *sc;
+ }
+}
+
++/* Copies SIZE bytes from kernel address SRC to user address
++ UDST.
++ Call thread_exit() if any of the user accesses are invalid. */
++static void
++copy_out (void *udst_, const void *src_, size_t size)
++{
++ uint8_t *udst = udst_;
++ const uint8_t *src = src_;
++
++ while (size > 0)
++ {
++ size_t chunk_size = PGSIZE - pg_ofs (udst);
++ if (chunk_size > size)
++ chunk_size = size;
++
++ if (!page_lock (udst, false))
++ thread_exit ();
++ memcpy (udst, src, chunk_size);
++ page_unlock (udst);
++
++ udst += chunk_size;
++ src += chunk_size;
++ size -= chunk_size;
++ }
++}
++
+/* Creates a copy of user string US in kernel memory
+ and returns it as a page that must be freed with
+ palloc_free_page().
+ {
+ struct list_elem elem; /* List element. */
+ struct file *file; /* File. */
++ struct dir *dir; /* Directory. */
+ int handle; /* File handle. */
+ };
+
+ struct file_descriptor *fd;
+ int handle = -1;
+
-+ fd = malloc (sizeof *fd);
++ fd = calloc (1, sizeof *fd);
+ if (fd != NULL)
+ {
-+ fd->file = file_open (filesys_open (kfile));
-+ if (fd->file != NULL)
++ struct inode *inode = filesys_open (kfile);
++ if (inode != NULL)
+ {
-+ struct thread *cur = thread_current ();
-+ handle = fd->handle = cur->next_handle++;
-+ list_push_front (&cur->fds, &fd->elem);
++ if (inode_get_type (inode) == FILE_INODE)
++ fd->file = file_open (inode);
++ else
++ fd->dir = dir_open (inode);
++ if (fd->file != NULL || fd->dir != NULL)
++ {
++ struct thread *cur = thread_current ();
++ handle = fd->handle = cur->next_handle++;
++ list_push_front (&cur->fds, &fd->elem);
++ }
++ else
++ {
++ free (fd);
++ inode_close (inode);
++ }
+ }
-+ else
-+ free (fd);
+ }
+
+ palloc_free_page (kfile);
+ thread_exit ();
+}
+
++/* Returns the file descriptor associated with the given handle.
++ Terminates the process if HANDLE is not associated with an
++ open ordinary file. */
++static struct file_descriptor *
++lookup_file_fd (int handle)
++{
++ struct file_descriptor *fd = lookup_fd (handle);
++ if (fd->file == NULL)
++ thread_exit ();
++ return fd;
++}
++
++/* Returns the file descriptor associated with the given handle.
++ Terminates the process if HANDLE is not associated with an
++ open directory. */
++static struct file_descriptor *
++lookup_dir_fd (int handle)
++{
++ struct file_descriptor *fd = lookup_fd (handle);
++ if (fd->dir == NULL)
++ thread_exit ();
++ return fd;
++}
++
+/* Filesize system call. */
+static int
+sys_filesize (int handle)
+{
-+ struct file_descriptor *fd = lookup_fd (handle);
++ struct file_descriptor *fd = lookup_file_fd (handle);
+ int size;
+
+ size = file_length (fd->file);
+
+ /* Look up file descriptor. */
+ if (handle != STDIN_FILENO)
-+ fd = lookup_fd (handle);
++ fd = lookup_file_fd (handle);
+
+ while (size > 0)
+ {
+
+ /* Lookup up file descriptor. */
+ if (handle != STDOUT_FILENO)
-+ fd = lookup_fd (handle);
++ fd = lookup_file_fd (handle);
+
+ while (size > 0)
+ {
+sys_seek (int handle, unsigned position)
+{
+ if ((off_t) position >= 0)
-+ file_seek (lookup_fd (handle)->file, position);
++ file_seek (lookup_file_fd (handle)->file, position);
+ return 0;
+}
+
+static int
+sys_tell (int handle)
+{
-+ return file_tell (lookup_fd (handle)->file);
++ return file_tell (lookup_file_fd (handle)->file);
+}
+
+/* Close system call. */
+{
+ struct file_descriptor *fd = lookup_fd (handle);
+ file_close (fd->file);
++ dir_close (fd->dir);
+ list_remove (&fd->elem);
+ free (fd);
+ return 0;
+static int
+sys_mmap (int handle, void *addr)
+{
-+ struct file_descriptor *fd = lookup_fd (handle);
++ struct file_descriptor *fd = lookup_file_fd (handle);
+ struct mapping *m = malloc (sizeof *m);
+ size_t offset;
+ off_t length;
+ return ok;
+}
+
-+/* Lsdir system call. */
++/* Readdir system call. */
+static int
-+sys_lsdir (void)
++sys_readdir (int handle, char *uname)
+{
-+ dir_list (thread_current ()->wd);
-+ return 0;
++ struct file_descriptor *fd = lookup_dir_fd (handle);
++ char name[NAME_MAX + 1];
++ bool ok = dir_readdir (fd->dir, name);
++ if (ok)
++ copy_out (uname, name, strlen (name) + 1);
++ return ok;
++}
++
++/* Isdir system call. */
++static int
++sys_isdir (int handle)
++{
++ struct file_descriptor *fd = lookup_fd (handle);
++ return fd->dir != NULL;
+}
+\f
+/* On thread exit, close all open files and unmap all mappings. */
+ struct file_descriptor *fd = list_entry (e, struct file_descriptor, elem);
+ next = list_next (e);
+ file_close (fd->file);
++ dir_close (fd->dir);
+ free (fd);
+ }
+