Implement page fault for lazy loading executables, w/ G
This commit is contained in:
94
tests/devices/src/lib/user/console.c
Normal file
94
tests/devices/src/lib/user/console.c
Normal file
@@ -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;
|
||||
}
|
||||
25
tests/devices/src/lib/user/debug.c
Normal file
25
tests/devices/src/lib/user/debug.c
Normal file
@@ -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);
|
||||
}
|
||||
10
tests/devices/src/lib/user/entry.c
Normal file
10
tests/devices/src/lib/user/entry.c
Normal file
@@ -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));
|
||||
}
|
||||
7
tests/devices/src/lib/user/stdio.h
Normal file
7
tests/devices/src/lib/user/stdio.h
Normal file
@@ -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 */
|
||||
184
tests/devices/src/lib/user/syscall.c
Normal file
184
tests/devices/src/lib/user/syscall.c
Normal file
@@ -0,0 +1,184 @@
|
||||
#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[FNAME_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);
|
||||
}
|
||||
46
tests/devices/src/lib/user/syscall.h
Normal file
46
tests/devices/src/lib/user/syscall.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef __LIB_USER_SYSCALL_H
|
||||
#define __LIB_USER_SYSCALL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <debug.h>
|
||||
#include "../../filesys/file.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)
|
||||
|
||||
/* Typical return values from main() and arguments to exit(). */
|
||||
#define EXIT_SUCCESS 0 /* Successful execution. */
|
||||
#define EXIT_FAILURE 1 /* Unsuccessful execution. */
|
||||
|
||||
/* Tasks 2 and later. */
|
||||
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);
|
||||
|
||||
/* Task 3 and optionally task 4. */
|
||||
mapid_t mmap (int fd, void *addr);
|
||||
void munmap (mapid_t);
|
||||
|
||||
/* Task 4 only. */
|
||||
bool chdir (const char *dir);
|
||||
bool mkdir (const char *dir);
|
||||
bool readdir (int fd, char name[FNAME_MAX_LEN + 1]);
|
||||
bool isdir (int fd);
|
||||
int inumber (int fd);
|
||||
|
||||
#endif /* lib/user/syscall.h */
|
||||
57
tests/devices/src/lib/user/user.lds
Normal file
57
tests/devices/src/lib/user/user.lds
Normal file
@@ -0,0 +1,57 @@
|
||||
OUTPUT_FORMAT("elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
/* Read-only sections, merged into text segment, at fixed start offset. */
|
||||
__executable_start = 0x08048000;
|
||||
. = 0x08048000;
|
||||
.text : { *(.text) }
|
||||
.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) }
|
||||
}
|
||||
Reference in New Issue
Block a user