Lab 3
This commit is contained in:
31
lib/Makefrag
Normal file
31
lib/Makefrag
Normal file
@@ -0,0 +1,31 @@
|
||||
OBJDIRS += lib
|
||||
|
||||
LIB_SRCFILES := lib/console.c \
|
||||
lib/libmain.c \
|
||||
lib/exit.c \
|
||||
lib/panic.c \
|
||||
lib/printf.c \
|
||||
lib/printfmt.c \
|
||||
lib/readline.c \
|
||||
lib/string.c \
|
||||
lib/syscall.c
|
||||
|
||||
|
||||
|
||||
|
||||
LIB_OBJFILES := $(patsubst lib/%.c, $(OBJDIR)/lib/%.o, $(LIB_SRCFILES))
|
||||
LIB_OBJFILES := $(patsubst lib/%.S, $(OBJDIR)/lib/%.o, $(LIB_OBJFILES))
|
||||
|
||||
$(OBJDIR)/lib/%.o: lib/%.c $(OBJDIR)/.vars.USER_CFLAGS
|
||||
@echo + cc[USER] $<
|
||||
@mkdir -p $(@D)
|
||||
$(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/lib/%.o: lib/%.S $(OBJDIR)/.vars.USER_CFLAGS
|
||||
@echo + as[USER] $<
|
||||
@mkdir -p $(@D)
|
||||
$(V)$(CC) -nostdinc $(USER_CFLAGS) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/lib/libjos.a: $(LIB_OBJFILES)
|
||||
@echo + ar $@
|
||||
$(V)$(AR) r $@ $(LIB_OBJFILES)
|
||||
25
lib/console.c
Normal file
25
lib/console.c
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
cputchar(int ch)
|
||||
{
|
||||
char c = ch;
|
||||
|
||||
// Unlike standard Unix's putchar,
|
||||
// the cputchar function _always_ outputs to the system console.
|
||||
sys_cputs(&c, 1);
|
||||
}
|
||||
|
||||
int
|
||||
getchar(void)
|
||||
{
|
||||
int r;
|
||||
// sys_cgetc does not block, but getchar should.
|
||||
while ((r = sys_cgetc()) == 0)
|
||||
;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
35
lib/entry.S
Normal file
35
lib/entry.S
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/memlayout.h>
|
||||
|
||||
.data
|
||||
// Define the global symbols 'envs', 'pages', 'uvpt', and 'uvpd'
|
||||
// so that they can be used in C as if they were ordinary global arrays.
|
||||
.globl envs
|
||||
.set envs, UENVS
|
||||
.globl pages
|
||||
.set pages, UPAGES
|
||||
.globl uvpt
|
||||
.set uvpt, UVPT
|
||||
.globl uvpd
|
||||
.set uvpd, (UVPT+(UVPT>>12)*4)
|
||||
|
||||
|
||||
// Entrypoint - this is where the kernel (or our parent environment)
|
||||
// starts us running when we are initially loaded into a new environment.
|
||||
.text
|
||||
.globl _start
|
||||
_start:
|
||||
// See if we were started with arguments on the stack
|
||||
cmpl $USTACKTOP, %esp
|
||||
jne args_exist
|
||||
|
||||
// If not, push dummy argc/argv arguments.
|
||||
// This happens when we are loaded by the kernel,
|
||||
// because the kernel does not know about passing arguments.
|
||||
pushl $0
|
||||
pushl $0
|
||||
|
||||
args_exist:
|
||||
call libmain
|
||||
1: jmp 1b
|
||||
|
||||
9
lib/exit.c
Normal file
9
lib/exit.c
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
exit(void)
|
||||
{
|
||||
sys_env_destroy(0);
|
||||
}
|
||||
|
||||
28
lib/libmain.c
Normal file
28
lib/libmain.c
Normal file
@@ -0,0 +1,28 @@
|
||||
// Called from entry.S to get us going.
|
||||
// entry.S already took care of defining envs, pages, uvpd, and uvpt.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
extern void umain(int argc, char **argv);
|
||||
|
||||
const volatile struct Env *thisenv;
|
||||
const char *binaryname = "<unknown>";
|
||||
|
||||
void
|
||||
libmain(int argc, char **argv)
|
||||
{
|
||||
// set thisenv to point at our Env structure in envs[].
|
||||
// LAB 3: Your code here.
|
||||
thisenv = 0;
|
||||
|
||||
// save the name of the program so that panic() can use it
|
||||
if (argc > 0)
|
||||
binaryname = argv[0];
|
||||
|
||||
// call user main routine
|
||||
umain(argc, argv);
|
||||
|
||||
// exit gracefully
|
||||
exit();
|
||||
}
|
||||
|
||||
26
lib/panic.c
Normal file
26
lib/panic.c
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
/*
|
||||
* Panic is called on unresolvable fatal errors.
|
||||
* It prints "panic: <message>", then causes a breakpoint exception,
|
||||
* which causes JOS to enter the JOS kernel monitor.
|
||||
*/
|
||||
void
|
||||
_panic(const char *file, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
// Print the panic message
|
||||
cprintf("[%08x] user panic in %s at %s:%d: ",
|
||||
sys_getenvid(), binaryname, file, line);
|
||||
vcprintf(fmt, ap);
|
||||
cprintf("\n");
|
||||
|
||||
// Cause a breakpoint exception
|
||||
while (1)
|
||||
asm volatile("int3");
|
||||
}
|
||||
|
||||
62
lib/printf.c
Normal file
62
lib/printf.c
Normal file
@@ -0,0 +1,62 @@
|
||||
// Implementation of cprintf console output for user environments,
|
||||
// based on printfmt() and the sys_cputs() system call.
|
||||
//
|
||||
// cprintf is a debugging statement, not a generic output statement.
|
||||
// It is very important that it always go to the console, especially when
|
||||
// debugging file descriptor code!
|
||||
|
||||
#include <inc/types.h>
|
||||
#include <inc/stdio.h>
|
||||
#include <inc/stdarg.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
|
||||
// Collect up to 256 characters into a buffer
|
||||
// and perform ONE system call to print all of them,
|
||||
// in order to make the lines output to the console atomic
|
||||
// and prevent interrupts from causing context switches
|
||||
// in the middle of a console output line and such.
|
||||
struct printbuf {
|
||||
int idx; // current buffer index
|
||||
int cnt; // total bytes printed so far
|
||||
char buf[256];
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
putch(int ch, struct printbuf *b)
|
||||
{
|
||||
b->buf[b->idx++] = ch;
|
||||
if (b->idx == 256-1) {
|
||||
sys_cputs(b->buf, b->idx);
|
||||
b->idx = 0;
|
||||
}
|
||||
b->cnt++;
|
||||
}
|
||||
|
||||
int
|
||||
vcprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
struct printbuf b;
|
||||
|
||||
b.idx = 0;
|
||||
b.cnt = 0;
|
||||
vprintfmt((void*)putch, &b, fmt, ap);
|
||||
sys_cputs(b.buf, b.idx);
|
||||
|
||||
return b.cnt;
|
||||
}
|
||||
|
||||
int
|
||||
cprintf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int cnt;
|
||||
|
||||
va_start(ap, fmt);
|
||||
cnt = vcprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
63
lib/syscall.c
Normal file
63
lib/syscall.c
Normal file
@@ -0,0 +1,63 @@
|
||||
// System call stubs.
|
||||
|
||||
#include <inc/syscall.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
static inline int32_t
|
||||
syscall(int num, int check, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
// Generic system call: pass system call number in AX,
|
||||
// up to five parameters in DX, CX, BX, DI, SI.
|
||||
// Interrupt kernel with T_SYSCALL.
|
||||
//
|
||||
// The "volatile" tells the assembler not to optimize
|
||||
// this instruction away just because we don't use the
|
||||
// return value.
|
||||
//
|
||||
// The last clause tells the assembler that this can
|
||||
// potentially change the condition codes and arbitrary
|
||||
// memory locations.
|
||||
|
||||
asm volatile("int %1\n"
|
||||
: "=a" (ret)
|
||||
: "i" (T_SYSCALL),
|
||||
"a" (num),
|
||||
"d" (a1),
|
||||
"c" (a2),
|
||||
"b" (a3),
|
||||
"D" (a4),
|
||||
"S" (a5)
|
||||
: "cc", "memory");
|
||||
|
||||
if(check && ret > 0)
|
||||
panic("syscall %d returned %d (> 0)", num, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
sys_cputs(const char *s, size_t len)
|
||||
{
|
||||
syscall(SYS_cputs, 0, (uint32_t)s, len, 0, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sys_cgetc(void)
|
||||
{
|
||||
return syscall(SYS_cgetc, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sys_env_destroy(envid_t envid)
|
||||
{
|
||||
return syscall(SYS_env_destroy, 1, envid, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
envid_t
|
||||
sys_getenvid(void)
|
||||
{
|
||||
return syscall(SYS_getenvid, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user