diff --git a/.gitignore b/.gitignore index b3ddb41aedfbab8bc3f8b59716dae0f5caa67134..fe0418548e417b12762d21108b1480b3e67fb620 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ examples/libc.a examples/my # Visual Studio folder /.vs +/CppProperties.json diff --git a/Makefile.build b/Makefile.build index 823d5af3f240461c01f294d8907cfee38a496ac4..c54f871c82dabe39e188a5015efd728a413cc9cd 100644 --- a/Makefile.build +++ b/Makefile.build @@ -62,6 +62,20 @@ userprog_SRC += userprog/exception.c # User exception handler. userprog_SRC += userprog/syscall.c # System call handler. userprog_SRC += userprog/gdt.c # GDT initialization. userprog_SRC += userprog/tss.c # TSS management. +userprog_SRC += userprog/syscall_exec.c +userprog_SRC += userprog/syscall_exit.c +userprog_SRC += userprog/syscall_open.c +userprog_SRC += userprog/syscall_halt.c +userprog_SRC += userprog/syscall_wait.c +userprog_SRC += userprog/syscall_create.c +userprog_SRC += userprog/syscall_remove.c +userprog_SRC += userprog/syscall_write.c +userprog_SRC += userprog/file_descriptors_map.c +userprog_SRC += userprog/syscall_read.c +userprog_SRC += userprog/syscall_filesize.c +userprog_SRC += userprog/syscall_tell.c +userprog_SRC += userprog/syscall_seek.c +userprog_SRC += userprog/syscall_close.c # No virtual memory code yet. #vm_SRC = vm/file.c # Some file. diff --git a/examples/Makefile b/examples/Makefile index 41a663d610cb89d30b7aa0277a644b0f63a2c0c5..37678a85f28246985ca2e24a445363f93de84999 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -3,14 +3,15 @@ SRCDIR = .. # Test programs to compile, and a list of sources for each. # To add a new test, put its name on the PROGS list # and then add a name_SRC line that lists its source files. -PROGS = cat cmp cp echo halt hex-dump ls mcat mcp mkdir pwd rm shell \ - bubsort insult lineup matmult recursor my +PROGS = cat cmp cp echo exit halt hex-dump ls mcat mcp mkdir pwd rm shell \ + bubsort insult lineup matmult recursor my touch # Should work from project 2 onward. cat_SRC = cat.c cmp_SRC = cmp.c cp_SRC = cp.c echo_SRC = echo.c +exit_SRC = exit.c halt_SRC = halt.c hex-dump_SRC = hex-dump.c insult_SRC = insult.c @@ -31,5 +32,8 @@ mkdir_SRC = mkdir.c pwd_SRC = pwd.c shell_SRC = shell.c +# Joshua Saxby special additions! +touch_SRC = touch.c + include $(SRCDIR)/Make.config include $(SRCDIR)/Makefile.userprog diff --git a/examples/echo.c b/examples/echo.c index 5621b69f409eaf1f180461fbc963922393538730..920fb9ef5b390ddd9f0e33c1fdc023f09e028d6b 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -10,5 +10,5 @@ main (int argc, char **argv) printf ("%s ", argv[i]); printf ("\n"); - return EXIT_SUCCESS; + return 5; } diff --git a/examples/exit b/examples/exit new file mode 100755 index 0000000000000000000000000000000000000000..a6569c49fe418705632d054e3e5337cf83e9da29 Binary files /dev/null and b/examples/exit differ diff --git a/examples/exit.c b/examples/exit.c new file mode 100644 index 0000000000000000000000000000000000000000..960fe22452edaa8402db7e1df5b8783fa5898f5f --- /dev/null +++ b/examples/exit.c @@ -0,0 +1,14 @@ +/* exit.c + + Simple program to test whether running a user program works. + + Invokes the exit syscall to test if it works */ + +#include <syscall.h> + +int +main (void) +{ + exit (5); + /* not reached */ +} diff --git a/examples/touch b/examples/touch new file mode 100755 index 0000000000000000000000000000000000000000..f68795f860f0e445ef5ee631e95ee05b7bc9e8c5 Binary files /dev/null and b/examples/touch differ diff --git a/examples/touch.c b/examples/touch.c new file mode 100644 index 0000000000000000000000000000000000000000..d6d3684b61a5834637541a6313e9100eaaea3333 --- /dev/null +++ b/examples/touch.c @@ -0,0 +1,16 @@ +/* touch.c + + Creates an empty file with the name given on the command-line. + + Author: Joshua Saxby + +*/ + +#include <stdio.h> +#include <syscall.h> + +int main (int argc, char *argv[]) { + if (argc != 2) exit(1); // very basic error-handling + char* filename = argv[1]; + return create(filename, 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/lib/kernel/stdio.h b/lib/kernel/stdio.h index 3e5bae9b65b27d6008ee758df692da91e2b00b58..c7f9b392acc1aaac194b340560f8c57bbc75cb3f 100644 --- a/lib/kernel/stdio.h +++ b/lib/kernel/stdio.h @@ -1,5 +1,6 @@ #ifndef __LIB_KERNEL_STDIO_H #define __LIB_KERNEL_STDIO_H +#include <stddef.h> void putbuf (const char *, size_t); diff --git a/threads/thread.h b/threads/thread.h index 2feb8cc242719e1d684aef2108d9c8ca501a922f..ba4adf7f15cdb827a750759d6754c64f20d09109 100644 --- a/threads/thread.h +++ b/threads/thread.h @@ -6,8 +6,7 @@ #include <stdint.h> /* States in a thread's life cycle. */ -enum thread_status - { +enum thread_status { THREAD_RUNNING, /* Running thread. */ THREAD_READY, /* Not running but ready to run. */ THREAD_BLOCKED, /* Waiting for an event to trigger. */ diff --git a/userprog/file_descriptors_map.c b/userprog/file_descriptors_map.c new file mode 100644 index 0000000000000000000000000000000000000000..7ab7943c883ce468a76190a336fbfc7ef8172028 --- /dev/null +++ b/userprog/file_descriptors_map.c @@ -0,0 +1,55 @@ +/* + * File Descriptors mapper + * + * Authored by Joshua Saxby + */ +#include <stddef.h> +#include "filesys/filesys.h" +#include "system_calls.h" + +// this means we can't have more than 255 open file handles at a time +#define MAX_FILE_POINTERS 255 + +static struct file* FILE_POINTERS_MAP[MAX_FILE_POINTERS] = {0}; + +struct file * get_associated_file_pointer(int fd) { + switch (fd) { + case 0: // keyboard (stdin) + case 1: // console (stdout) + case 2: // console (stderr) + return NULL; + default: + return FILE_POINTERS_MAP[fd - 3]; // exclude special fds + } +} + +int associate_new_file_descriptor(struct file* file_pointer) { + // if we have been passed NULL, refuse (it's silly!) + if (file_pointer == NULL) return -1; + // find the first decriptor which points to NULL + for (size_t i = 0; i < MAX_FILE_POINTERS; i++) { + if (FILE_POINTERS_MAP[i] == NULL) { + FILE_POINTERS_MAP[i] = file_pointer; + return i + 3; // exclude special fds + } + } + // if we got here, we've run out of spare slots, return failure + return -1; +} + +bool disassociate_file_descriptor(int fd) { + // clear the descriptor to NULL + switch (fd) { + case 0: // keyboard (stdin) + case 1: // console (stdout) + case 2: // console (stderr) + return false; + default: + if (FILE_POINTERS_MAP[fd - 3] != NULL) { // exclude special fds + FILE_POINTERS_MAP[fd - 3] = NULL; + return true; + } else { + return false; + } + } +} diff --git a/userprog/populate_stack.c b/userprog/populate_stack.c index d82e18fb72b85a3ac7546f23e393812534d1f83a..19c995c54dffc4a9d2b7af1c8835a6a8323958fc 100644 --- a/userprog/populate_stack.c +++ b/userprog/populate_stack.c @@ -1,6 +1,5 @@ /* * populates_stack.c --implements function for populating the program stack - * * * Authored by Alex Stratford */ @@ -23,8 +22,8 @@ void populate_stack(void** stack_pointer, int argc, char** argv) { while (--i >= 0) { *stack_pointer = *stack_pointer - (strlen(argv[i]) + 1) * sizeof(char); - - arr[i] = (uint32_t *)*stack_pointer; // Assigns the current reference of the stack pointer to the array + // Assigns the current reference of the stack pointer to the array + arr[i] = (uint32_t *)*stack_pointer; memcpy(*stack_pointer, argv[i], strlen(argv[i]) + 1); } @@ -36,7 +35,7 @@ void populate_stack(void** stack_pointer, int argc, char** argv) { while (--i >= 0) { - move_stack_pointer(stack_pointer, -4); //32bit Moves the stack pointer back 4 + move_stack_pointer(stack_pointer, -4); //Moves the stack pointer back 4 (*(uint32_t **)(*stack_pointer)) = arr[i]; } diff --git a/userprog/syscall.c b/userprog/syscall.c index 04635159d30520fa11296dc922e622f2ad2553d5..845508adf10abcae3b2da8702c162ead639ca67a 100644 --- a/userprog/syscall.c +++ b/userprog/syscall.c @@ -1,9 +1,40 @@ #include "userprog/syscall.h" #include <stdio.h> #include <syscall-nr.h> +#include "system_calls.h" #include "threads/interrupt.h" #include "threads/thread.h" + +/* System call numbers. */ +typedef enum syscall_t { + /* Projects 2 and later. */ + SYSCALL_HALT, /* Halt the operating system. */ + SYSCALL_EXIT, /* Terminate this process. */ + SYSCALL_EXEC, /* Start another process. */ + SYSCALL_WAIT, /* Wait for a child process to die. */ + SYSCALL_CREATE, /* Create a file. */ + SYSCALL_REMOVE, /* Delete a file. */ + SYSCALL_OPEN, /* Open a file. */ + SYSCALL_FILESIZE, /* Obtain a file's size. */ + SYSCALL_READ, /* Read from a file. */ + SYSCALL_WRITE, /* Write to a file. */ + SYSCALL_SEEK, /* Change position in a file. */ + SYSCALL_TELL, /* Report current position in a file. */ + SYSCALL_CLOSE, /* Close a file. */ + + /* Project 3 and optionally project 4. */ + SYSCALL_MMAP, /* Map a file into memory. */ + SYSCALL_MUNMAP, /* Remove a memory mapping. */ + + /* Project 4 only. */ + SYSCALL_CHDIR, /* Change the current directory. */ + SYSCALL_MKDIR, /* Create a directory. */ + SYSCALL_READDIR, /* Reads a directory entry. */ + SYSCALL_ISDIR, /* Tests if a fd represents a directory. */ + SYSCALL_INUMBER /* Returns the inode number for a fd. */ +} syscall_t; + static void syscall_handler (struct intr_frame *); void @@ -16,6 +47,55 @@ syscall_init (void) static void syscall_handler (struct intr_frame *f UNUSED) { - printf ("system call!\n"); - thread_exit (); + /* + * the syscall number is addressed by f->esp (pointer to void) + * here we cast it to a pointer to int and then dereference that + * to get the system call number + * --Joshua Saxby + */ + int syscall_number = *((int*)f->esp); + switch (syscall_number) { + case SYSCALL_HALT: + syscall_halt(f); + break; + case SYSCALL_EXIT: + syscall_exit(f); + break; + case SYSCALL_EXEC: + syscall_exec(f); + break; + case SYSCALL_WAIT: + syscall_wait(f); + break; + case SYSCALL_CREATE: + syscall_create(f); + break; + case SYSCALL_REMOVE: + syscall_remove(f); + break; + case SYSCALL_WRITE: + syscall_write(f); + break; + case SYSCALL_OPEN: + syscall_open(f); + break; + case SYSCALL_READ: + syscall_read(f); + break; + case SYSCALL_FILESIZE: + syscall_filesize(f); + break; + case SYSCALL_TELL: + syscall_tell(f); + break; + case SYSCALL_SEEK: + syscall_seek(f); + break; + case SYSCALL_CLOSE: + syscall_close(f); + break; + default: + printf ("WARNING: Invalid Syscall (%d)\n", syscall_number); + thread_exit (); + } } diff --git a/userprog/syscall_close.c b/userprog/syscall_close.c new file mode 100644 index 0000000000000000000000000000000000000000..8508962b192b2548c16d014234cc2c19b29f37aa --- /dev/null +++ b/userprog/syscall_close.c @@ -0,0 +1,28 @@ +/* + * Closes file descriptor fd. Exiting or terminating a process implicitly closes + * all its open file descriptors, as if by calling this function for each one. + * + * Authored by Alex Stratford + */ + +#include "system_calls.h" +#include <stddef.h> // Dependency for NULL +#include "threads/interrupt.h" // Dependency for intr_frame struct +#include "filesys/file.h" // Dependency for file_close +#include "threads/malloc.h" // Dependency for free +#include "lib/kernel/list.h" // Dependency for list_remove + +void syscall_close(struct intr_frame *f) { + // pop off first int argument from interrupt frame + int file_descriptor = *((int*)f->esp + 1); + // Get file associated with file_descriptor + struct file *file = get_associated_file_pointer(file_descriptor); + if (file == NULL) { // Checking if file is empty or non-existent + f->eax = -1; // Returning a failure state + return; + } + // Close the file using file_close, defined in file.h + file_close(file); + // Remove the file_descriptor + disassociate_file_descriptor(file_descriptor); +} diff --git a/userprog/syscall_create.c b/userprog/syscall_create.c new file mode 100644 index 0000000000000000000000000000000000000000..dc631c0de393243e99bc0f5ed64a49b0c89c6c45 --- /dev/null +++ b/userprog/syscall_create.c @@ -0,0 +1,15 @@ +/* + * The Create System Call + * + * Authored by Joshua Saxby + */ +#include "filesys/filesys.h" +#include "system_calls.h" +#include "threads/interrupt.h" + +void syscall_create(struct intr_frame *f) { + // first argument is syscall code (already handled) + char* filename = (void*)(*((int*)f->esp + 1)); // filename is second argument + unsigned initial_size = *((unsigned*)((int*)f->esp + 2)); // third + f->eax = filesys_create(filename, initial_size); +} diff --git a/userprog/syscall_exec.c b/userprog/syscall_exec.c new file mode 100644 index 0000000000000000000000000000000000000000..94a060b3f85b35ac063246e0d76f040517bb0f4f --- /dev/null +++ b/userprog/syscall_exec.c @@ -0,0 +1,6 @@ +#include "system_calls.h" +#include "threads/interrupt.h" + +void syscall_exec(struct intr_frame *f) { + (void*)0; +} \ No newline at end of file diff --git a/userprog/syscall_exit.c b/userprog/syscall_exit.c new file mode 100644 index 0000000000000000000000000000000000000000..22a63e3f5f6cefb8ddd7bcbc1c4c44221777dc95 --- /dev/null +++ b/userprog/syscall_exit.c @@ -0,0 +1,20 @@ +/* + * Terminates the current user program, returning status to the kernel. If the + * Process’s parent waits for it (see below), this is the status that will be + * Returned. Conventionally, a status of 0 indicates success and nonzero values + * Indicate errors. + * + * Authored by Alex Stratford + */ + +#include "system_calls.h" +#include "threads/interrupt.h" // Dependency for intr_frame struct +#include "threads/thread.h" // Dependency for thread struct + +void syscall_exit(struct intr_frame *f) { + struct thread *current_thread = thread_current(); // Sets current thread + // pop off first int argument from interrupt frame + int exit_code = *((int*)f->esp + 1); + current_thread->exit_code = exit_code; // Returns exit code to kernel + thread_exit(); // Exiting current thread +} diff --git a/userprog/syscall_filesize.c b/userprog/syscall_filesize.c new file mode 100644 index 0000000000000000000000000000000000000000..aff7fe7a80c3666fd4d69ac8d7a35aaab5eb06aa --- /dev/null +++ b/userprog/syscall_filesize.c @@ -0,0 +1,20 @@ +/* + * Returns the size, in bytes, of the file open as fd. + * + * Authored by Alex Stratford + */ +#include <stddef.h> +#include "system_calls.h" +#include "filesys/file.h" + +void syscall_filesize(struct intr_frame *f) { + // pop off first int argument from interrupt frame + int file_descriptor = *((int*)f->esp + 1); + struct file *file = get_associated_file_pointer(file_descriptor); + if (file == NULL) { // Checking if file is empty or non-existent + f->eax -1; // Returning failure state + } + // Using the file_length function in file.h to get the length and store it + int size = file_length(file); + f->eax = size; +} diff --git a/userprog/syscall_halt.c b/userprog/syscall_halt.c new file mode 100644 index 0000000000000000000000000000000000000000..2698c31feafc6afc322f955a021938e95e259937 --- /dev/null +++ b/userprog/syscall_halt.c @@ -0,0 +1,13 @@ +/* + * The Halt System Call + * + * Authored by Joshua Saxby + */ +#include "devices/shutdown.h" +#include "system_calls.h" +#include "threads/interrupt.h" + +void syscall_halt(struct intr_frame *f UNUSED) { + // terminate Pintos right here and right now! + shutdown_power_off(); +} diff --git a/userprog/syscall_open.c b/userprog/syscall_open.c new file mode 100644 index 0000000000000000000000000000000000000000..54631b762fc52947d9d900a9cc722185b2f9334a --- /dev/null +++ b/userprog/syscall_open.c @@ -0,0 +1,32 @@ +/* + * Opens the file called file. Returns a nonnegative integer handle called a + * "file descriptor" (fd), or -1 if the file could not be opened. + * + * Authored by Alex Stratford + */ + + +#include "system_calls.h" +#include <stddef.h> // Dependency for NULL +#include "threads/interrupt.h" // Dependency for intr_frame struct +#include "filesys/file.h" // Dependency for and file struct +#include "filesys/filesys.h" // Dependency for filesys_open + +void syscall_open(struct intr_frame *f) { + // pop off first int argument from interrupt frame + char* file_name = (void*)*((int*)f->esp + 1); + // Described in filesys.h, opens the file + struct file *file = filesys_open(file_name); + if (file == NULL) { // Checking if file is empty or non-existent + f->eax = -1; // Returning a failure state + return; + } + // Described in system_calls.h, get a new file descriptor + int file_descriptor = associate_new_file_descriptor(file); + + if (file_descriptor == -1) { + f->eax = -1; // Returning a failure state + return; + } + f->eax = file_descriptor; // Returning the file descriptor +} diff --git a/userprog/syscall_read.c b/userprog/syscall_read.c new file mode 100644 index 0000000000000000000000000000000000000000..67f7d9858ea87ecc23b717a9b8dee1353d323abe --- /dev/null +++ b/userprog/syscall_read.c @@ -0,0 +1,42 @@ +/* + * The Read System Call + * + * Authored by Joshua Saxby + */ +#include <stddef.h> +#include "devices/input.h" +#include "filesys/file.h" +#include "system_calls.h" +#include "threads/interrupt.h" + +void syscall_read(struct intr_frame *f) { + // first argument is syscall code (already handled) + int fd = *((int*)f->esp + 1); // file descriptor is second argument + char* buffer = (void*)(*((int*)f->esp + 2)); // buffer is third argument + unsigned size = *((unsigned*)((int*)f->esp + 3)); // size to read is fourth + // reading from stdin (keyboard) is a special case + switch (fd) { + case 0: { + // read from keyboard for as many bytes as requested + for (size_t i = 0; i < size; i++) { + *(buffer + i) = input_getc(); + } + f->eax = size; + break; + } + case 1: // stdout + case 2: // stderr + f->eax = -1; // it is a mistake to attempt to read from stdout or stderr + break; + default: { + // otherwise, we need to read from a file denoted by fd + struct file* file_to_read = get_associated_file_pointer(fd); + if (file_to_read == NULL) { + f->eax = -1; // invalid file descriptor + break; + } + f->eax = file_read(file_to_read, buffer, size); + break; + } + } +} diff --git a/userprog/syscall_remove.c b/userprog/syscall_remove.c new file mode 100644 index 0000000000000000000000000000000000000000..0b8d308cc49e759c008275f9b9eaba0c4a5bdab6 --- /dev/null +++ b/userprog/syscall_remove.c @@ -0,0 +1,25 @@ +/* + * Deletes the file called file. Returns true if successful, false otherwise. + * A file may be removed regardless of whether it is open or closed, and + * Removing an open file does not close it. See Removing an Open File, for + * Details. + * + * Authored by Alex Stratford + */ + + +#include "system_calls.h" +#include "threads/interrupt.h" // Dependency for intr_frame struct +#include "filesys/file.h" // Dependency for and file struct +#include "filesys/filesys.h" // Dependency for filesys_remove + +void syscall_remove(struct intr_frame *f) { + // pop off first int argument from interrupt frame + char* file_name = (void*)*((int*)f->esp + 1); + // Described in filesys.h, opens the file + if (filesys_remove(file_name) == false) { // Checking if file is empty or non-existent + f->eax = false; // Returning a failure state + return; + } + f->eax = true; +} diff --git a/userprog/syscall_seek.c b/userprog/syscall_seek.c new file mode 100644 index 0000000000000000000000000000000000000000..9a665a14a14c72a36a04c1fea7b5766130fdf09b --- /dev/null +++ b/userprog/syscall_seek.c @@ -0,0 +1,22 @@ +/* +* Changes the next byte to be read or written in open file fd to position, +* Expressed in bytes from the beginning of the file. (Thus, a position of 0 +* Is the file�s start.) +* +* Authored by Alex Stratford +*/ + +#include "system_calls.h" +#include <stddef.h> // Dependency for NULL +#include "threads/interrupt.h" // Dependency for intr_frame struct +#include "filesys/file.h" // Dependency for file struct and file_seek function + +void syscall_seek(struct intr_frame *f) { + // pop off first int argument from interrupt frame + int file_descriptor = *((int*)f->esp + 1); + // pop off second int argument from interrupt frame + unsigned file_pos = *((unsigned*)((int*)f->esp + 2)); + struct file *file = get_associated_file_pointer(file_descriptor); + // Seek through the file + file_seek(file, file_pos); +} diff --git a/userprog/syscall_tell.c b/userprog/syscall_tell.c new file mode 100644 index 0000000000000000000000000000000000000000..4fa049a1344557df1bbe67642562d89a11f103e3 --- /dev/null +++ b/userprog/syscall_tell.c @@ -0,0 +1,19 @@ +/* + * Returns the current offset into the file that the given file descriptor is at + * + * Authored by Joshua Saxby + */ +#include <stddef.h> +#include "system_calls.h" +#include "filesys/file.h" + +void syscall_tell(struct intr_frame *f) { + // pop off first int argument from interrupt frame + int file_descriptor = *((int*)f->esp + 1); + struct file *file = get_associated_file_pointer(file_descriptor); + /* + * tell() return type is unsigned so we can't return a special error code if + * file descriptor passed is invalid. Instead, we return 0 silently. + */ + f->eax = (file != NULL) ? file_tell(file) : 0; +} diff --git a/userprog/syscall_wait.c b/userprog/syscall_wait.c new file mode 100644 index 0000000000000000000000000000000000000000..6ef4d52385c5be4ccd7352d681e289ad8acdc9e7 --- /dev/null +++ b/userprog/syscall_wait.c @@ -0,0 +1,6 @@ +#include "system_calls.h" +#include "threads/interrupt.h" + +void syscall_wait(struct intr_frame *f) { + (void*)0; +} \ No newline at end of file diff --git a/userprog/syscall_write.c b/userprog/syscall_write.c new file mode 100644 index 0000000000000000000000000000000000000000..9c356db50727391fd00e5e6fa8e2837251227c54 --- /dev/null +++ b/userprog/syscall_write.c @@ -0,0 +1,59 @@ +/* + * The Write System Call + * + * Authored by Joshua Saxby + */ +#include <stdio.h> +#include "filesys/file.h" +#include "lib/kernel/stdio.h" +#include "system_calls.h" +#include "threads/interrupt.h" + +// the maximum number of characters to write to the console in one go +static const size_t CONSOLE_WRITE_MAX_SIZE = 255; + +static void write_to_console(const char* buffer, size_t size); + +void syscall_write(struct intr_frame *f) { + // first argument is syscall code (already handled) + int fd = *((int*)f->esp + 1); // file descriptor is second argument + void* buffer = (void*)(*((int*)f->esp + 2)); // buffer is third argument + unsigned size = *((unsigned*)((int*)f->esp + 3)); // size to write is fourth + // writing to stdout or stderr (fd in {1, 2}) is a special case + switch (fd) { + case 1: // stdin + case 2: // stderr + write_to_console((const char*)buffer, size); + f->eax = size; + break; + default: { + // otherwise, we need to write to a file denoted by fd + struct file* file_to_write = get_associated_file_pointer(fd); + if (file_to_write == NULL) { + f->eax = 0; // invalid file descriptor + break; + } + f->eax = file_write(file_to_write, buffer, size); + break; + } + } +} + +static void write_to_console(const char* buffer, size_t size) { + // refuse to write more than a certain limit of chars at a time to console + if (size <= CONSOLE_WRITE_MAX_SIZE) { + putbuf(buffer, size); + } else { + const char* cursor = buffer; + size_t chars_left = size; + do { + size_t write_amount = ( + chars_left < CONSOLE_WRITE_MAX_SIZE + ? chars_left : CONSOLE_WRITE_MAX_SIZE + ); + putbuf(cursor, write_amount); + cursor += write_amount; + chars_left -= write_amount; + } while (chars_left > 0); + } +} diff --git a/userprog/system_calls.h b/userprog/system_calls.h new file mode 100644 index 0000000000000000000000000000000000000000..49b8145675f486ef12405293fa3d3678426006d5 --- /dev/null +++ b/userprog/system_calls.h @@ -0,0 +1,102 @@ +#include "filesys/file.h" +#include "threads/interrupt.h" + +/* + * Terminates Pintos by calling shutdown_power_off() + * (declared in devices/shutdown.h). + */ +void syscall_halt(struct intr_frame *f); + +/* + * Terminates the current user program, returning status to the kernel. If the + * process's parent waits for it (see below), this is the status that will be + * returned. Conventionally, a status of 0 indicates success and nonzero + * values indicate errors. + */ +void syscall_exit(struct intr_frame *f); + +/* + * Runs the executable whose name is given in cmd_line, passing any given + * arguments, and returns the new process's program id (pid). Must return pid + * -1, which otherwise should not be a valid pid, if the program cannot load or + * run for any reason. Thus, the parent process cannot return from the exec + * until it knows whether the child process successfully loaded its executable. + * You must use appropriate synchronization to ensure this. + */ +void syscall_exec(struct intr_frame *f); + +/* + * Waits for a child process pid and retrieves the child's exit status. + */ +void syscall_wait(struct intr_frame *f); + +/* + * Creates a new file called file initially initial_size bytes in size. + * Returns true if successful, false otherwise. + */ +void syscall_create(struct intr_frame *f); + +/* + * Reads size bytes from the file open as fd into buffer. + * Returns the number of bytes actually read (0 at end of file), or -1 if the + * file could not be read (due to a condition other than end of file). + */ +void syscall_read(struct intr_frame *f); + +/* + * Writes size bytes from buffer to the open file fd. + * Returns the number of bytes actually written, which may be less than size if + * some bytes could not be written. + */ +void syscall_write(struct intr_frame *f); + +/* + * Opens the file called file. Returns a nonnegative integer handle called a + * "file descriptor" (fd), or -1 if the file could not be opened. + */ +void syscall_open(struct intr_frame *f); + +/* + * Returns the size, in bytes, of the file open as fd. + */ +void syscall_filesize(struct intr_frame *f); + +/* + * Deletes the file called file. Returns true if successful, false otherwise. + * A file may be removed regardless of whether it is open or closed, and + * Removing an open file does not close it. See Removing an Open File, for + * Details. + */ +void syscall_remove(struct intr_frame *f); + +/* + * Returns the position of the next byte to be read or written in open file fd, + * expressed in bytes from the beginning of the file. + */ +void syscall_tell(struct intr_frame *f); + +/* +* Changes the next byte to be read or written in open file fd to position, +* Expressed in bytes from the beginning of the file. (Thus, a position of 0 +* Is the file�s start.) +*/ +void syscall_seek(struct intr_frame *f); + +/* + * Closes file descriptor fd. Exiting or terminating a process implicitly closes + * all its open file descriptors, as if by calling this function for each one. + */ +void syscall_close(struct intr_frame *f); + +/* + * special additional stuff for handling file descriptors because they're annoying + */ + +// returns NULL if the given file descriptor does not match a known file +struct file * get_associated_file_pointer(int fd); +// remembers the given file, and returns int of file descriptor +// returns -1 if could not store it (means we've opened too many files) +int associate_new_file_descriptor(struct file* file_pointer); +// disassociates the given file descriptor (and its associated pointer) +// returns false if this failed for some reason +bool disassociate_file_descriptor(int fd);