aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/user
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/user')
-rw-r--r--src/lib/user/console.c94
-rw-r--r--src/lib/user/debug.c25
-rw-r--r--src/lib/user/entry.c10
-rw-r--r--src/lib/user/stdio.h7
-rw-r--r--src/lib/user/syscall.c185
-rw-r--r--src/lib/user/syscall.h49
-rw-r--r--src/lib/user/user.lds57
7 files changed, 427 insertions, 0 deletions
diff --git a/src/lib/user/console.c b/src/lib/user/console.c
new file mode 100644
index 0000000..22bdc8c
--- /dev/null
+++ b/src/lib/user/console.c
@@ -0,0 +1,94 @@
+#include <stdio.h>
+#include <string.h>
+#include <syscall.h>
+#include <syscall-nr.h>
+
+/* The standard vprintf() function,
+ which is like printf() but uses a va_list. */
+int
+vprintf (const char *format, va_list args)
+{
+ return vhprintf (STDOUT_FILENO, format, args);
+}
+
+/* Like printf(), but writes output to the given HANDLE. */
+int
+hprintf (int handle, const char *format, ...)
+{
+ va_list args;
+ int retval;
+
+ va_start (args, format);
+ retval = vhprintf (handle, format, args);
+ va_end (args);
+
+ return retval;
+}
+
+/* Writes string S to the console, followed by a new-line
+ character. */
+int
+puts (const char *s)
+{
+ write (STDOUT_FILENO, s, strlen (s));
+ putchar ('\n');
+
+ return 0;
+}
+
+/* Writes C to the console. */
+int
+putchar (int c)
+{
+ char c2 = c;
+ write (STDOUT_FILENO, &c2, 1);
+ return c;
+}
+
+/* Auxiliary data for vhprintf_helper(). */
+struct vhprintf_aux
+ {
+ char buf[64]; /* Character buffer. */
+ char *p; /* Current position in buffer. */
+ int char_cnt; /* Total characters written so far. */
+ int handle; /* Output file handle. */
+ };
+
+static void add_char (char, void *);
+static void flush (struct vhprintf_aux *);
+
+/* Formats the printf() format specification FORMAT with
+ arguments given in ARGS and writes the output to the given
+ HANDLE. */
+int
+vhprintf (int handle, const char *format, va_list args)
+{
+ struct vhprintf_aux aux;
+ aux.p = aux.buf;
+ aux.char_cnt = 0;
+ aux.handle = handle;
+ __vprintf (format, args, add_char, &aux);
+ flush (&aux);
+ return aux.char_cnt;
+}
+
+/* Adds C to the buffer in AUX, flushing it if the buffer fills
+ up. */
+static void
+add_char (char c, void *aux_)
+{
+ struct vhprintf_aux *aux = aux_;
+ *aux->p++ = c;
+ if (aux->p >= aux->buf + sizeof aux->buf)
+ flush (aux);
+ aux->char_cnt++;
+}
+
+/* Flushes the buffer in AUX. */
+static void
+flush (struct vhprintf_aux *aux)
+{
+ if (aux->p > aux->buf)
+ write (aux->handle, aux->buf, aux->p - aux->buf);
+ aux->p = aux->buf;
+}
diff --git a/src/lib/user/debug.c b/src/lib/user/debug.c
new file mode 100644
index 0000000..f49b874
--- /dev/null
+++ b/src/lib/user/debug.c
@@ -0,0 +1,25 @@
+#include <debug.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <syscall.h>
+
+/* Aborts the user program, printing the source file name, line
+ number, and function name, plus a user-specific message. */
+void
+debug_panic (const char *file, int line, const char *function,
+ const char *message, ...)
+{
+ va_list args;
+
+ printf ("User process ABORT at %s:%d in %s(): ", file, line, function);
+
+ va_start (args, message);
+ vprintf (message, args);
+ printf ("\n");
+ va_end (args);
+
+ debug_backtrace ();
+
+ exit (1);
+}
diff --git a/src/lib/user/entry.c b/src/lib/user/entry.c
new file mode 100644
index 0000000..a707c70
--- /dev/null
+++ b/src/lib/user/entry.c
@@ -0,0 +1,10 @@
+#include <syscall.h>
+
+int main (int, char *[]);
+void _start (int argc, char *argv[]);
+
+void
+_start (int argc, char *argv[])
+{
+ exit (main (argc, argv));
+}
diff --git a/src/lib/user/stdio.h b/src/lib/user/stdio.h
new file mode 100644
index 0000000..b9f3cc6
--- /dev/null
+++ b/src/lib/user/stdio.h
@@ -0,0 +1,7 @@
+#ifndef __LIB_USER_STDIO_H
+#define __LIB_USER_STDIO_H
+
+int hprintf (int, const char *, ...) PRINTF_FORMAT (2, 3);
+int vhprintf (int, const char *, va_list) PRINTF_FORMAT (2, 0);
+
+#endif /* lib/user/stdio.h */
diff --git a/src/lib/user/syscall.c b/src/lib/user/syscall.c
new file mode 100644
index 0000000..2c0d987
--- /dev/null
+++ b/src/lib/user/syscall.c
@@ -0,0 +1,185 @@
+#include <syscall.h>
+#include "../syscall-nr.h"
+
+/* Invokes syscall NUMBER, passing no arguments, and returns the
+ return value as an `int'. */
+#define syscall0(NUMBER) \
+ ({ \
+ int retval; \
+ asm volatile \
+ ("pushl %[number]; int $0x30; addl $4, %%esp" \
+ : "=a" (retval) \
+ : [number] "i" (NUMBER) \
+ : "memory"); \
+ retval; \
+ })
+
+/* Invokes syscall NUMBER, passing argument ARG0, and returns the
+ return value as an `int'. */
+#define syscall1(NUMBER, ARG0) \
+ ({ \
+ int retval; \
+ asm volatile \
+ ("pushl %[arg0]; pushl %[number]; int $0x30; addl $8, %%esp" \
+ : "=a" (retval) \
+ : [number] "i" (NUMBER), \
+ [arg0] "g" (ARG0) \
+ : "memory"); \
+ retval; \
+ })
+
+/* Invokes syscall NUMBER, passing arguments ARG0 and ARG1, and
+ returns the return value as an `int'. */
+#define syscall2(NUMBER, ARG0, ARG1) \
+ ({ \
+ int retval; \
+ asm volatile \
+ ("pushl %[arg1]; pushl %[arg0]; " \
+ "pushl %[number]; int $0x30; addl $12, %%esp" \
+ : "=a" (retval) \
+ : [number] "i" (NUMBER), \
+ [arg0] "g" (ARG0), \
+ [arg1] "g" (ARG1) \
+ : "memory"); \
+ retval; \
+ })
+
+/* Invokes syscall NUMBER, passing arguments ARG0, ARG1, and
+ ARG2, and returns the return value as an `int'. */
+#define syscall3(NUMBER, ARG0, ARG1, ARG2) \
+ ({ \
+ int retval; \
+ asm volatile \
+ ("pushl %[arg2]; pushl %[arg1]; pushl %[arg0]; " \
+ "pushl %[number]; int $0x30; addl $16, %%esp" \
+ : "=a" (retval) \
+ : [number] "i" (NUMBER), \
+ [arg0] "g" (ARG0), \
+ [arg1] "g" (ARG1), \
+ [arg2] "g" (ARG2) \
+ : "memory"); \
+ retval; \
+ })
+
+void
+halt (void)
+{
+ syscall0 (SYS_HALT);
+ NOT_REACHED ();
+}
+
+void
+exit (int status)
+{
+ syscall1 (SYS_EXIT, status);
+ NOT_REACHED ();
+}
+
+pid_t
+exec (const char *file)
+{
+ return (pid_t) syscall1 (SYS_EXEC, file);
+}
+
+int
+wait (pid_t pid)
+{
+ return syscall1 (SYS_WAIT, pid);
+}
+
+bool
+create (const char *file, unsigned initial_size)
+{
+ return syscall2 (SYS_CREATE, file, initial_size);
+}
+
+bool
+remove (const char *file)
+{
+ return syscall1 (SYS_REMOVE, file);
+}
+
+int
+open (const char *file)
+{
+ return syscall1 (SYS_OPEN, file);
+}
+
+int
+filesize (int fd)
+{
+ return syscall1 (SYS_FILESIZE, fd);
+}
+
+int
+read (int fd, void *buffer, unsigned size)
+{
+ return syscall3 (SYS_READ, fd, buffer, size);
+}
+
+int
+write (int fd, const void *buffer, unsigned size)
+{
+ return syscall3 (SYS_WRITE, fd, buffer, size);
+}
+
+void
+seek (int fd, unsigned position)
+{
+ syscall2 (SYS_SEEK, fd, position);
+}
+
+unsigned
+tell (int fd)
+{
+ return syscall1 (SYS_TELL, fd);
+}
+
+void
+close (int fd)
+{
+ syscall1 (SYS_CLOSE, fd);
+}
+
+mapid_t
+mmap (int fd, void *addr)
+{
+ return syscall2 (SYS_MMAP, fd, addr);
+}
+
+void
+munmap (mapid_t mapid)
+{
+ syscall1 (SYS_MUNMAP, mapid);
+}
+
+bool
+chdir (const char *dir)
+{
+ return syscall1 (SYS_CHDIR, dir);
+}
+
+bool
+mkdir (const char *dir)
+{
+ return syscall1 (SYS_MKDIR, dir);
+}
+
+bool
+readdir (int fd, char name[READDIR_MAX_LEN + 1])
+{
+ return syscall2 (SYS_READDIR, fd, name);
+}
+
+bool
+isdir (int fd)
+{
+ return syscall1 (SYS_ISDIR, fd);
+}
+
+int
+inumber (int fd)
+{
+ return syscall1 (SYS_INUMBER, fd);
+}
+
diff --git a/src/lib/user/syscall.h b/src/lib/user/syscall.h
new file mode 100644
index 0000000..a2b44f8
--- /dev/null
+++ b/src/lib/user/syscall.h
@@ -0,0 +1,49 @@
+#ifndef __LIB_USER_SYSCALL_H
+#define __LIB_USER_SYSCALL_H
+
+#include <stdbool.h>
+#include <debug.h>
+
+/* Process identifier. */
+typedef int pid_t;
+#define PID_ERROR ((pid_t) -1)
+
+/* Map region identifier. */
+typedef int mapid_t;
+#define MAP_FAILED ((mapid_t) -1)
+
+/* Maximum characters in a filename written by readdir(). */
+#define READDIR_MAX_LEN 14
+
+/* Typical return values from main() and arguments to exit(). */
+#define EXIT_SUCCESS 0 /* Successful execution. */
+#define EXIT_FAILURE 1 /* Unsuccessful execution. */
+
+/* The basic systemcalls you will implement. */
+void halt (void) NO_RETURN;
+void exit (int status) NO_RETURN;
+pid_t exec (const char *file);
+int wait (pid_t);
+bool create (const char *file, unsigned initial_size);
+bool remove (const char *file);
+int open (const char *file);
+int filesize (int fd);
+int read (int fd, void *buffer, unsigned length);
+int write (int fd, const void *buffer, unsigned length);
+void seek (int fd, unsigned position);
+unsigned tell (int fd);
+void close (int fd);
+
+/* Memory mapping system calls. */
+mapid_t mmap (int fd, void *addr);
+void munmap (mapid_t);
+
+/* Filesystem system calls. */
+bool chdir (const char *dir);
+bool mkdir (const char *dir);
+bool readdir (int fd, char name[READDIR_MAX_LEN + 1]);
+bool isdir (int fd);
+int inumber (int fd);
+
+
+#endif /* lib/user/syscall.h */
diff --git a/src/lib/user/user.lds b/src/lib/user/user.lds
new file mode 100644
index 0000000..cc6d6c0
--- /dev/null
+++ b/src/lib/user/user.lds
@@ -0,0 +1,57 @@
+OUTPUT_FORMAT("elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ __executable_start = 0x08048000 + SIZEOF_HEADERS;
+ . = 0x08048000 + SIZEOF_HEADERS;
+ .text : { *(.text) } = 0x90
+ .rodata : { *(.rodata) }
+
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1));
+ . = DATA_SEGMENT_ALIGN (0x1000, 0x1000);
+
+ .data : { *(.data) }
+ .bss : { *(.bss) }
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+ /DISCARD/ : { *(.eh_frame) }
+}