summaryrefslogtreecommitdiffstats
path: root/lib/user
diff options
context:
space:
mode:
Diffstat (limited to 'lib/user')
-rw-r--r--lib/user/console.c94
-rw-r--r--lib/user/debug.c25
-rw-r--r--lib/user/entry.c10
-rw-r--r--lib/user/stdio.h7
-rw-r--r--lib/user/syscall.c184
-rw-r--r--lib/user/syscall.h48
-rw-r--r--lib/user/user.lds57
7 files changed, 425 insertions, 0 deletions
diff --git a/lib/user/console.c b/lib/user/console.c
new file mode 100644
index 0000000..22bdc8c
--- /dev/null
+++ b/lib/user/console.c
@@ -0,0 +1,94 @@
1#include <stdio.h>
2#include <string.h>
3#include <syscall.h>
4#include <syscall-nr.h>
5
6/* The standard vprintf() function,
7 which is like printf() but uses a va_list. */
8int
9vprintf (const char *format, va_list args)
10{
11 return vhprintf (STDOUT_FILENO, format, args);
12}
13
14/* Like printf(), but writes output to the given HANDLE. */
15int
16hprintf (int handle, const char *format, ...)
17{
18 va_list args;
19 int retval;
20
21 va_start (args, format);
22 retval = vhprintf (handle, format, args);
23 va_end (args);
24
25 return retval;
26}
27
28/* Writes string S to the console, followed by a new-line
29 character. */
30int
31puts (const char *s)
32{
33 write (STDOUT_FILENO, s, strlen (s));
34 putchar ('\n');
35
36 return 0;
37}
38
39/* Writes C to the console. */
40int
41putchar (int c)
42{
43 char c2 = c;
44 write (STDOUT_FILENO, &c2, 1);
45 return c;
46}
47
48/* Auxiliary data for vhprintf_helper(). */
49struct vhprintf_aux
50 {
51 char buf[64]; /* Character buffer. */
52 char *p; /* Current position in buffer. */
53 int char_cnt; /* Total characters written so far. */
54 int handle; /* Output file handle. */
55 };
56
57static void add_char (char, void *);
58static void flush (struct vhprintf_aux *);
59
60/* Formats the printf() format specification FORMAT with
61 arguments given in ARGS and writes the output to the given
62 HANDLE. */
63int
64vhprintf (int handle, const char *format, va_list args)
65{
66 struct vhprintf_aux aux;
67 aux.p = aux.buf;
68 aux.char_cnt = 0;
69 aux.handle = handle;
70 __vprintf (format, args, add_char, &aux);
71 flush (&aux);
72 return aux.char_cnt;
73}
74
75/* Adds C to the buffer in AUX, flushing it if the buffer fills
76 up. */
77static void
78add_char (char c, void *aux_)
79{
80 struct vhprintf_aux *aux = aux_;
81 *aux->p++ = c;
82 if (aux->p >= aux->buf + sizeof aux->buf)
83 flush (aux);
84 aux->char_cnt++;
85}
86
87/* Flushes the buffer in AUX. */
88static void
89flush (struct vhprintf_aux *aux)
90{
91 if (aux->p > aux->buf)
92 write (aux->handle, aux->buf, aux->p - aux->buf);
93 aux->p = aux->buf;
94}
diff --git a/lib/user/debug.c b/lib/user/debug.c
new file mode 100644
index 0000000..f49b874
--- /dev/null
+++ b/lib/user/debug.c
@@ -0,0 +1,25 @@
1#include <debug.h>
2#include <stdarg.h>
3#include <stdbool.h>
4#include <stdio.h>
5#include <syscall.h>
6
7/* Aborts the user program, printing the source file name, line
8 number, and function name, plus a user-specific message. */
9void
10debug_panic (const char *file, int line, const char *function,
11 const char *message, ...)
12{
13 va_list args;
14
15 printf ("User process ABORT at %s:%d in %s(): ", file, line, function);
16
17 va_start (args, message);
18 vprintf (message, args);
19 printf ("\n");
20 va_end (args);
21
22 debug_backtrace ();
23
24 exit (1);
25}
diff --git a/lib/user/entry.c b/lib/user/entry.c
new file mode 100644
index 0000000..a707c70
--- /dev/null
+++ b/lib/user/entry.c
@@ -0,0 +1,10 @@
1#include <syscall.h>
2
3int main (int, char *[]);
4void _start (int argc, char *argv[]);
5
6void
7_start (int argc, char *argv[])
8{
9 exit (main (argc, argv));
10}
diff --git a/lib/user/stdio.h b/lib/user/stdio.h
new file mode 100644
index 0000000..b9f3cc6
--- /dev/null
+++ b/lib/user/stdio.h
@@ -0,0 +1,7 @@
1#ifndef __LIB_USER_STDIO_H
2#define __LIB_USER_STDIO_H
3
4int hprintf (int, const char *, ...) PRINTF_FORMAT (2, 3);
5int vhprintf (int, const char *, va_list) PRINTF_FORMAT (2, 0);
6
7#endif /* lib/user/stdio.h */
diff --git a/lib/user/syscall.c b/lib/user/syscall.c
new file mode 100644
index 0000000..0a467f8
--- /dev/null
+++ b/lib/user/syscall.c
@@ -0,0 +1,184 @@
1#include <syscall.h>
2#include "../syscall-nr.h"
3
4/* Invokes syscall NUMBER, passing no arguments, and returns the
5 return value as an `int'. */
6#define syscall0(NUMBER) \
7 ({ \
8 int retval; \
9 asm volatile \
10 ("pushl %[number]; int $0x30; addl $4, %%esp" \
11 : "=a" (retval) \
12 : [number] "i" (NUMBER) \
13 : "memory"); \
14 retval; \
15 })
16
17/* Invokes syscall NUMBER, passing argument ARG0, and returns the
18 return value as an `int'. */
19#define syscall1(NUMBER, ARG0) \
20 ({ \
21 int retval; \
22 asm volatile \
23 ("pushl %[arg0]; pushl %[number]; int $0x30; addl $8, %%esp" \
24 : "=a" (retval) \
25 : [number] "i" (NUMBER), \
26 [arg0] "g" (ARG0) \
27 : "memory"); \
28 retval; \
29 })
30
31/* Invokes syscall NUMBER, passing arguments ARG0 and ARG1, and
32 returns the return value as an `int'. */
33#define syscall2(NUMBER, ARG0, ARG1) \
34 ({ \
35 int retval; \
36 asm volatile \
37 ("pushl %[arg1]; pushl %[arg0]; " \
38 "pushl %[number]; int $0x30; addl $12, %%esp" \
39 : "=a" (retval) \
40 : [number] "i" (NUMBER), \
41 [arg0] "r" (ARG0), \
42 [arg1] "r" (ARG1) \
43 : "memory"); \
44 retval; \
45 })
46
47/* Invokes syscall NUMBER, passing arguments ARG0, ARG1, and
48 ARG2, and returns the return value as an `int'. */
49#define syscall3(NUMBER, ARG0, ARG1, ARG2) \
50 ({ \
51 int retval; \
52 asm volatile \
53 ("pushl %[arg2]; pushl %[arg1]; pushl %[arg0]; " \
54 "pushl %[number]; int $0x30; addl $16, %%esp" \
55 : "=a" (retval) \
56 : [number] "i" (NUMBER), \
57 [arg0] "r" (ARG0), \
58 [arg1] "r" (ARG1), \
59 [arg2] "r" (ARG2) \
60 : "memory"); \
61 retval; \
62 })
63
64void
65halt (void)
66{
67 syscall0 (SYS_HALT);
68 NOT_REACHED ();
69}
70
71void
72exit (int status)
73{
74 syscall1 (SYS_EXIT, status);
75 NOT_REACHED ();
76}
77
78pid_t
79exec (const char *cmd_line)
80{
81 return (pid_t) syscall1 (SYS_EXEC, cmd_line);
82}
83
84int
85wait (pid_t pid)
86{
87 return syscall1 (SYS_WAIT, pid);
88}
89
90bool
91create (const char *file, unsigned initial_size)
92{
93 return syscall2 (SYS_CREATE, file, initial_size);
94}
95
96bool
97remove (const char *file)
98{
99 return syscall1 (SYS_REMOVE, file);
100}
101
102int
103open (const char *file)
104{
105 return syscall1 (SYS_OPEN, file);
106}
107
108int
109filesize (int fd)
110{
111 return syscall1 (SYS_FILESIZE, fd);
112}
113
114int
115read (int fd, void *buffer, unsigned size)
116{
117 return syscall3 (SYS_READ, fd, buffer, size);
118}
119
120int
121write (int fd, const void *buffer, unsigned size)
122{
123 return syscall3 (SYS_WRITE, fd, buffer, size);
124}
125
126void
127seek (int fd, unsigned position)
128{
129 syscall2 (SYS_SEEK, fd, position);
130}
131
132unsigned
133tell (int fd)
134{
135 return syscall1 (SYS_TELL, fd);
136}
137
138void
139close (int fd)
140{
141 syscall1 (SYS_CLOSE, fd);
142}
143
144mapid_t
145mmap (int fd, void *addr)
146{
147 return syscall2 (SYS_MMAP, fd, addr);
148}
149
150void
151munmap (mapid_t mapid)
152{
153 syscall1 (SYS_MUNMAP, mapid);
154}
155
156bool
157chdir (const char *dir)
158{
159 return syscall1 (SYS_CHDIR, dir);
160}
161
162bool
163mkdir (const char *dir)
164{
165 return syscall1 (SYS_MKDIR, dir);
166}
167
168bool
169readdir (int fd, char name[READDIR_MAX_LEN + 1])
170{
171 return syscall2 (SYS_READDIR, fd, name);
172}
173
174bool
175isdir (int fd)
176{
177 return syscall1 (SYS_ISDIR, fd);
178}
179
180int
181inumber (int fd)
182{
183 return syscall1 (SYS_INUMBER, fd);
184}
diff --git a/lib/user/syscall.h b/lib/user/syscall.h
new file mode 100644
index 0000000..a1bcf0b
--- /dev/null
+++ b/lib/user/syscall.h
@@ -0,0 +1,48 @@
1#ifndef __LIB_USER_SYSCALL_H
2#define __LIB_USER_SYSCALL_H
3
4#include <stdbool.h>
5#include <debug.h>
6
7/* Process identifier. */
8typedef int pid_t;
9#define PID_ERROR ((pid_t) -1)
10
11/* Map region identifier. */
12typedef int mapid_t;
13#define MAP_FAILED ((mapid_t) -1)
14
15/* Maximum characters in a filename written by readdir(). */
16#define READDIR_MAX_LEN 14
17
18/* Typical return values from main() and arguments to exit(). */
19#define EXIT_SUCCESS 0 /* Successful execution. */
20#define EXIT_FAILURE 1 /* Unsuccessful execution. */
21
22/* Projects 2 and later. */
23void halt (void) NO_RETURN;
24void exit (int status) NO_RETURN;
25pid_t exec (const char *cmd_line);
26int wait (pid_t);
27bool create (const char *file, unsigned initial_size);
28bool remove (const char *file);
29int open (const char *file);
30int filesize (int fd);
31int read (int fd, void *buffer, unsigned length);
32int write (int fd, const void *buffer, unsigned length);
33void seek (int fd, unsigned position);
34unsigned tell (int fd);
35void close (int fd);
36
37/* Project 3 and optionally project 4. */
38mapid_t mmap (int fd, void *addr);
39void munmap (mapid_t);
40
41/* Project 4 only. */
42bool chdir (const char *dir);
43bool mkdir (const char *dir);
44bool readdir (int fd, char name[READDIR_MAX_LEN + 1]);
45bool isdir (int fd);
46int inumber (int fd);
47
48#endif /* lib/user/syscall.h */
diff --git a/lib/user/user.lds b/lib/user/user.lds
new file mode 100644
index 0000000..cc6d6c0
--- /dev/null
+++ b/lib/user/user.lds
@@ -0,0 +1,57 @@
1OUTPUT_FORMAT("elf32-i386")
2OUTPUT_ARCH(i386)
3ENTRY(_start)
4
5SECTIONS
6{
7 /* Read-only sections, merged into text segment: */
8 __executable_start = 0x08048000 + SIZEOF_HEADERS;
9 . = 0x08048000 + SIZEOF_HEADERS;
10 .text : { *(.text) } = 0x90
11 .rodata : { *(.rodata) }
12
13 /* Adjust the address for the data segment. We want to adjust up to
14 the same address within the page on the next page up. */
15 . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1));
16 . = DATA_SEGMENT_ALIGN (0x1000, 0x1000);
17
18 .data : { *(.data) }
19 .bss : { *(.bss) }
20
21 /* Stabs debugging sections. */
22 .stab 0 : { *(.stab) }
23 .stabstr 0 : { *(.stabstr) }
24 .stab.excl 0 : { *(.stab.excl) }
25 .stab.exclstr 0 : { *(.stab.exclstr) }
26 .stab.index 0 : { *(.stab.index) }
27 .stab.indexstr 0 : { *(.stab.indexstr) }
28 .comment 0 : { *(.comment) }
29
30 /* DWARF debug sections.
31 Symbols in the DWARF debugging sections are relative to the beginning
32 of the section so we begin them at 0. */
33 /* DWARF 1 */
34 .debug 0 : { *(.debug) }
35 .line 0 : { *(.line) }
36 /* GNU DWARF 1 extensions */
37 .debug_srcinfo 0 : { *(.debug_srcinfo) }
38 .debug_sfnames 0 : { *(.debug_sfnames) }
39 /* DWARF 1.1 and DWARF 2 */
40 .debug_aranges 0 : { *(.debug_aranges) }
41 .debug_pubnames 0 : { *(.debug_pubnames) }
42 /* DWARF 2 */
43 .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
44 .debug_abbrev 0 : { *(.debug_abbrev) }
45 .debug_line 0 : { *(.debug_line) }
46 .debug_frame 0 : { *(.debug_frame) }
47 .debug_str 0 : { *(.debug_str) }
48 .debug_loc 0 : { *(.debug_loc) }
49 .debug_macinfo 0 : { *(.debug_macinfo) }
50 /* SGI/MIPS DWARF 2 extensions */
51 .debug_weaknames 0 : { *(.debug_weaknames) }
52 .debug_funcnames 0 : { *(.debug_funcnames) }
53 .debug_typenames 0 : { *(.debug_typenames) }
54 .debug_varnames 0 : { *(.debug_varnames) }
55 /DISCARD/ : { *(.note.GNU-stack) }
56 /DISCARD/ : { *(.eh_frame) }
57}