diff --git a/Makefile.build b/Makefile.build index c079897805d7fb75ae1510b92d5e9af7dc59a224..e6010c1faa52d376ce3a2c8856c775272b78cf55 100644 --- a/Makefile.build +++ b/Makefile.build @@ -67,6 +67,7 @@ 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_write.c # No virtual memory code yet. #vm_SRC = vm/file.c # Some file. 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/userprog/syscall.c b/userprog/syscall.c index 24427b28da633af9c2ccc0d118c21e2b04ad4acb..9223e3748ae3129bc70f7f0e099ffddaf1164775 100644 --- a/userprog/syscall.c +++ b/userprog/syscall.c @@ -70,6 +70,9 @@ syscall_handler (struct intr_frame *f UNUSED) case SYSCALL_CREATE: syscall_create(f); break; + case SYSCALL_WRITE: + syscall_write(f); + break; case SYSCALL_OPEN: syscall_open(f); break; @@ -77,5 +80,4 @@ syscall_handler (struct intr_frame *f UNUSED) printf ("WARNING: Invalid Syscall (%d)\n", syscall_number); thread_exit (); } - // TODO: remove this call to exit as we don't want all syscalls to make the thread exit } diff --git a/userprog/syscall_write.c b/userprog/syscall_write.c new file mode 100644 index 0000000000000000000000000000000000000000..98aeb142ddd9b52187ac7dbba13d30a3043bb960 --- /dev/null +++ b/userprog/syscall_write.c @@ -0,0 +1,55 @@ +/* + * 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 = (struct file*)fd; + 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 index 7d74bc4a643531d24018716cc1e831fbd47cc98c..bfb72ad33e577631428c52b61c5b030ff661c2b4 100644 --- a/userprog/system_calls.h +++ b/userprog/system_calls.h @@ -45,6 +45,13 @@ void syscall_open(struct intr_frame *f); */ void syscall_create(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); + /* * NOTE: There are more system calls implemented by Pintos but we are not * implementing them because the assignment brief does not ask of it.