mirror of
https://github.com/SmallPond/MIT6.828_OS.git
synced 2026-04-23 18:29:59 +08:00
LAB 4 IS DONE.
This commit is contained in:
36
lab/lib/Makefrag
Normal file
36
lab/lib/Makefrag
Normal file
@@ -0,0 +1,36 @@
|
||||
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_SRCFILES := $(LIB_SRCFILES) \
|
||||
lib/pgfault.c \
|
||||
lib/pfentry.S \
|
||||
lib/fork.c \
|
||||
lib/ipc.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
lab/lib/console.c
Normal file
25
lab/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)
|
||||
sys_yield();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
36
lab/lib/entry.S
Normal file
36
lab/lib/entry.S
Normal file
@@ -0,0 +1,36 @@
|
||||
#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
|
||||
// 为什么不直接写 >>10 ?
|
||||
.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
lab/lib/exit.c
Normal file
9
lab/lib/exit.c
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
void
|
||||
exit(void)
|
||||
{
|
||||
sys_env_destroy(0);
|
||||
}
|
||||
|
||||
167
lab/lib/fork.c
Normal file
167
lab/lib/fork.c
Normal file
@@ -0,0 +1,167 @@
|
||||
// implement fork from user space
|
||||
|
||||
#include <inc/string.h>
|
||||
#include <inc/lib.h>
|
||||
|
||||
// PTE_COW marks copy-on-write page table entries.
|
||||
// It is one of the bits explicitly allocated to user processes (PTE_AVAIL).
|
||||
#define PTE_COW 0x800
|
||||
|
||||
//
|
||||
// Custom page fault handler - if faulting page is copy-on-write,
|
||||
// map in our own private writable copy.
|
||||
//
|
||||
static void
|
||||
pgfault(struct UTrapframe *utf)
|
||||
{
|
||||
void *addr = (void *) utf->utf_fault_va;
|
||||
uint32_t err = utf->utf_err;
|
||||
int r;
|
||||
|
||||
// Check that the faulting access was (1) a write, and (2) to a
|
||||
// copy-on-write page. If not, panic.
|
||||
// Hint:
|
||||
// Use the read-only page table mappings at uvpt
|
||||
// (see <inc/memlayout.h>).
|
||||
|
||||
// LAB 4: Your code here.
|
||||
if (! ( (err & FEC_WR) && (uvpd[PDX(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_P) && (uvpt[PGNUM(addr)] & PTE_COW)))
|
||||
panic("Neither the fault is a write nor COW page. \n");
|
||||
// Allocate a new page, map it at a temporary location (PFTEMP),
|
||||
// copy the data from the old page to the new page, then move the new
|
||||
// page to the old page's address.
|
||||
// Hint:
|
||||
// You should make three system calls.
|
||||
|
||||
// LAB 4: Your code here.
|
||||
envid_t envid = sys_getenvid();
|
||||
// cprintf("pgfault: envid: %d\n", ENVX(envid));
|
||||
// 临时页暂存
|
||||
if ((r = sys_page_alloc(envid, (void *)PFTEMP, PTE_P| PTE_W|PTE_U)) < 0)
|
||||
panic("pgfault: page allocation fault:%e\n", r);
|
||||
addr = ROUNDDOWN(addr, PGSIZE);
|
||||
memcpy((void *) PFTEMP, (const void *) addr, PGSIZE);
|
||||
if ((r = sys_page_map(envid, (void *) PFTEMP, envid, addr , PTE_P|PTE_W|PTE_U)) < 0 )
|
||||
panic("pgfault: page map failed %e\n", r);
|
||||
|
||||
if ((r = sys_page_unmap(envid, (void *) PFTEMP)) < 0)
|
||||
panic("pgfault: page unmap failed %e\n", r);
|
||||
|
||||
|
||||
|
||||
// panic("pgfault not implemented");
|
||||
}
|
||||
|
||||
//
|
||||
// Map our virtual page pn (address pn*PGSIZE) into the target envid
|
||||
// at the same virtual address. If the page is writable or copy-on-write,
|
||||
// the new mapping must be created copy-on-write, and then our mapping must be
|
||||
// marked copy-on-write as well. (Exercise: Why do we need to mark ours
|
||||
// copy-on-write again if it was already copy-on-write at the beginning of
|
||||
// this function?)
|
||||
//
|
||||
// Returns: 0 on success, < 0 on error.
|
||||
// It is also OK to panic on error.
|
||||
//
|
||||
|
||||
static int
|
||||
duppage(envid_t envid, unsigned pn)
|
||||
{
|
||||
|
||||
// LAB 4: Your code here.
|
||||
pte_t *pte;
|
||||
int ret;
|
||||
// 用户空间的地址较低
|
||||
uint32_t va = pn * PGSIZE;
|
||||
|
||||
|
||||
if ( (uvpt[pn] & PTE_W) || (uvpt[pn] & PTE_COW)) {
|
||||
|
||||
// 子进程标记
|
||||
if ((ret = sys_page_map(thisenv->env_id, (void *) va, envid, (void *) va, PTE_P|PTE_U|PTE_COW)) < 0)
|
||||
return ret;
|
||||
// 父进程标记
|
||||
if ((ret = sys_page_map(thisenv->env_id, (void *)va, thisenv->env_id, (void *)va, PTE_P|PTE_U|PTE_COW)) < 0)
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
// 简单映射
|
||||
if((ret = sys_page_map(thisenv->env_id, (void *) va, envid, (void * )va, PTE_P|PTE_U)) <0 )
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
// panic("duppage not implemented");
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// User-level fork with copy-on-write.
|
||||
// Set up our page fault handler appropriately.
|
||||
// Create a child.
|
||||
// Copy our address space and page fault handler setup to the child.
|
||||
// Then mark the child as runnable and return.
|
||||
//
|
||||
// Returns: child's envid to the parent, 0 to the child, < 0 on error.
|
||||
// It is also OK to panic on error.
|
||||
//
|
||||
// Hint:
|
||||
// Use uvpd, uvpt, and duppage.
|
||||
// Remember to fix "thisenv" in the child process.
|
||||
// Neither user exception stack should ever be marked copy-on-write,
|
||||
// so you must allocate a new page for the child's user exception stack.
|
||||
//
|
||||
envid_t
|
||||
fork(void)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
envid_t envid;
|
||||
int r;
|
||||
size_t i, j, pn;
|
||||
// Set up our page fault handler
|
||||
set_pgfault_handler(pgfault);
|
||||
|
||||
envid = sys_exofork();
|
||||
|
||||
if (envid < 0) {
|
||||
panic("sys_exofork failed: %e", envid);
|
||||
}
|
||||
|
||||
if (envid == 0) {
|
||||
// child
|
||||
thisenv = &envs[ENVX(sys_getenvid())];
|
||||
return 0;
|
||||
}
|
||||
// here is parent !
|
||||
// Copy our address space and page fault handler setup to the child.
|
||||
|
||||
for (pn = PGNUM(UTEXT); pn < PGNUM(USTACKTOP); pn++) {
|
||||
if ( (uvpd[pn >> 10] & PTE_P) && (uvpt[pn] & PTE_P)) {
|
||||
// 页表
|
||||
if ( (r = duppage(envid, pn)) < 0)
|
||||
return r;
|
||||
|
||||
}
|
||||
}
|
||||
// alloc a page and map child exception stack
|
||||
if ((r = sys_page_alloc(envid, (void *)(UXSTACKTOP-PGSIZE), PTE_U | PTE_P | PTE_W)) < 0)
|
||||
return r;
|
||||
extern void _pgfault_upcall(void);
|
||||
if ((r = sys_env_set_pgfault_upcall(envid, _pgfault_upcall)) < 0)
|
||||
return r;
|
||||
|
||||
// Start the child environment running
|
||||
if ((r = sys_env_set_status(envid, ENV_RUNNABLE)) < 0)
|
||||
panic("sys_env_set_status: %e", r);
|
||||
|
||||
return envid;
|
||||
// panic("fork not implemented");
|
||||
}
|
||||
|
||||
// Challenge!
|
||||
int
|
||||
sfork(void)
|
||||
{
|
||||
panic("sfork not implemented");
|
||||
return -E_INVAL;
|
||||
}
|
||||
85
lab/lib/ipc.c
Normal file
85
lab/lib/ipc.c
Normal file
@@ -0,0 +1,85 @@
|
||||
// User-level IPC library routines
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
// Receive a value via IPC and return it.
|
||||
// If 'pg' is nonnull, then any page sent by the sender will be mapped at
|
||||
// that address.
|
||||
// If 'from_env_store' is nonnull, then store the IPC sender's envid in
|
||||
// *from_env_store.
|
||||
// If 'perm_store' is nonnull, then store the IPC sender's page permission
|
||||
// in *perm_store (this is nonzero iff a page was successfully
|
||||
// transferred to 'pg').
|
||||
// If the system call fails, then store 0 in *fromenv and *perm (if
|
||||
// they're nonnull) and return the error.
|
||||
// Otherwise, return the value sent by the sender
|
||||
//
|
||||
// Hint:
|
||||
// Use 'thisenv' to discover the value and who sent it.
|
||||
// If 'pg' is null, pass sys_ipc_recv a value that it will understand
|
||||
// as meaning "no page". (Zero is not the right value, since that's
|
||||
// a perfectly valid place to map a page.)
|
||||
int32_t
|
||||
ipc_recv(envid_t *from_env_store, void *pg, int *perm_store)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
//panic("ipc_recv not implemented");
|
||||
int r;
|
||||
if (!pg)
|
||||
pg = (void *)UTOP;
|
||||
r = sys_ipc_recv(pg);
|
||||
|
||||
|
||||
if (from_env_store)
|
||||
*from_env_store = r < 0? 0:thisenv->env_ipc_from;
|
||||
if (perm_store)
|
||||
*perm_store = r<0? 0:thisenv->env_ipc_perm;
|
||||
if (r < 0)
|
||||
return r;
|
||||
else
|
||||
return thisenv->env_ipc_value;
|
||||
}
|
||||
|
||||
// Send 'val' (and 'pg' with 'perm', if 'pg' is nonnull) to 'toenv'.
|
||||
// This function keeps trying until it succeeds.
|
||||
// It should panic() on any error other than -E_IPC_NOT_RECV.
|
||||
//
|
||||
// Hint:
|
||||
// Use sys_yield() to be CPU-friendly.
|
||||
// If 'pg' is null, pass sys_ipc_try_send a value that it will understand
|
||||
// as meaning "no page". (Zero is not the right value.)
|
||||
void
|
||||
ipc_send(envid_t to_env, uint32_t val, void *pg, int perm)
|
||||
{
|
||||
// LAB 4: Your code here.
|
||||
int r;
|
||||
if (!pg)
|
||||
pg = (void *) UTOP;
|
||||
|
||||
do {
|
||||
r = sys_ipc_try_send(to_env, val, pg, perm);
|
||||
if (r == -E_IPC_NOT_RECV) {
|
||||
// 用户级程序不能直接调用 sched_yeild();
|
||||
sys_yield();
|
||||
|
||||
}
|
||||
else if( (r != -E_IPC_NOT_RECV)&& (r < 0 )) {
|
||||
panic("ipc_send failed %e\n", r);
|
||||
}
|
||||
} while ( r < 0) ;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Find the first environment of the given type. We'll use this to
|
||||
// find special environments.
|
||||
// Returns 0 if no such environment exists.
|
||||
envid_t
|
||||
ipc_find_env(enum EnvType type)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NENV; i++)
|
||||
if (envs[i].env_type == type)
|
||||
return envs[i].env_id;
|
||||
return 0;
|
||||
}
|
||||
28
lab/lib/libmain.c
Normal file
28
lab/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 = &envs[ENVX(sys_getenvid())];
|
||||
|
||||
// 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
lab/lib/panic.c
Normal file
26
lab/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");
|
||||
}
|
||||
|
||||
90
lab/lib/pfentry.S
Normal file
90
lab/lib/pfentry.S
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <inc/mmu.h>
|
||||
#include <inc/memlayout.h>
|
||||
|
||||
// Page fault upcall entrypoint.
|
||||
|
||||
// This is where we ask the kernel to redirect us to whenever we cause
|
||||
// a page fault in user space (see the call to sys_set_pgfault_handler
|
||||
// in pgfault.c).
|
||||
//
|
||||
// When a page fault actually occurs, the kernel switches our ESP to
|
||||
// point to the user exception stack if we're not already on the user
|
||||
// exception stack, and then it pushes a UTrapframe onto our user
|
||||
// exception stack:
|
||||
//
|
||||
// trap-time esp
|
||||
// trap-time eflags
|
||||
// trap-time eip
|
||||
// utf_regs.reg_eax
|
||||
// ...
|
||||
// utf_regs.reg_esi
|
||||
// utf_regs.reg_edi
|
||||
// utf_err (error code)
|
||||
// utf_fault_va <-- %esp
|
||||
//
|
||||
// If this is a recursive fault, the kernel will reserve for us a
|
||||
// blank word above the trap-time esp for scratch work when we unwind
|
||||
// the recursive call.
|
||||
//
|
||||
// We then have call up to the appropriate page fault handler in C
|
||||
// code, pointed to by the global variable '_pgfault_handler'.
|
||||
|
||||
.text
|
||||
.globl _pgfault_upcall
|
||||
_pgfault_upcall:
|
||||
// Call the C page fault handler.
|
||||
pushl %esp // function argument: pointer to UTF
|
||||
movl _pgfault_handler, %eax
|
||||
call *%eax
|
||||
addl $4, %esp // pop function argument 恢复栈
|
||||
|
||||
// Now the C page fault handler has returned and you must return
|
||||
// to the trap time state.
|
||||
// Push trap-time %eip onto the trap-time stack.
|
||||
//
|
||||
// Explanation:
|
||||
// We must prepare the trap-time stack for our eventual return to
|
||||
// re-execute the instruction that faulted.
|
||||
// Unfortunately, we can't return directly from the exception stack:
|
||||
// We can't call 'jmp', since that requires that we load the address
|
||||
// into a register, and all registers must have their trap-time
|
||||
// values after the return.
|
||||
// We can't call 'ret' from the exception stack either, since if we
|
||||
// did, %esp would have the wrong value.
|
||||
// So instead, we push the trap-time %eip onto the *trap-time* stack!
|
||||
// Below we'll switch to that stack and call 'ret', which will
|
||||
// restore %eip to its pre-fault value.
|
||||
//
|
||||
// In the case of a recursive fault on the exception stack,
|
||||
// note that the word we're pushing now will fit in the
|
||||
// blank word that the kernel reserved for us.
|
||||
//
|
||||
// Throughout the remaining code, think carefully about what
|
||||
// registers are available for intermediate calculations. You
|
||||
// may find that you have to rearrange your code in non-obvious
|
||||
// ways as registers become unavailable as scratch space.
|
||||
//
|
||||
// LAB 4: Your code here.
|
||||
// Struct PushRegs size = 32
|
||||
addl $8, %esp // esp+8 -> PushRegs over utf_fault_va utf_err
|
||||
movl 0x20(%esp), %eax // eax = (esp+0x20 -> utf_eip )
|
||||
subl $4, 0x28(%esp) // for trap time eip 保留32bit, esp+48 = utf_esp
|
||||
movl 0x28(%esp), %edx // %edx = utf_esp-4
|
||||
movl %eax, (%edx) // %eax = eip ----> esp-4 以至于ret可以直接读取其继续执行的地址
|
||||
|
||||
// Restore the trap-time registers. After you do this, you
|
||||
// can no longer modify any general-purpose registers.
|
||||
// LAB 4: Your code here.
|
||||
popal // after popal esp->utf_eip
|
||||
// Restore eflags from the stack. After you do this, you can
|
||||
// no longer use arithmetic operations or anything else that
|
||||
// modifies eflags.
|
||||
// LAB 4: Your code here.
|
||||
addl $4, %esp // esp+4 -> utf_eflags
|
||||
popfl
|
||||
// Switch back to the adjusted trap-time stack.
|
||||
// LAB 4: Your code here.
|
||||
popl %esp
|
||||
// Return to re-execute the instruction that faulted.
|
||||
// LAB 4: Your code here.
|
||||
ret // 这里十分巧妙, ret会读取esp指向的第一个内容, 也就是我们第一步写入的eip
|
||||
40
lab/lib/pgfault.c
Normal file
40
lab/lib/pgfault.c
Normal file
@@ -0,0 +1,40 @@
|
||||
// User-level page fault handler support.
|
||||
// Rather than register the C page fault handler directly with the
|
||||
// kernel as the page fault handler, we register the assembly language
|
||||
// wrapper in pfentry.S, which in turns calls the registered C
|
||||
// function.
|
||||
|
||||
#include <inc/lib.h>
|
||||
|
||||
|
||||
// Assembly language pgfault entrypoint defined in lib/pfentry.S.
|
||||
extern void _pgfault_upcall(void);
|
||||
|
||||
// Pointer to currently installed C-language pgfault handler.
|
||||
void (*_pgfault_handler)(struct UTrapframe *utf);
|
||||
|
||||
//
|
||||
// Set the page fault handler function.
|
||||
// If there isn't one yet, _pgfault_handler will be 0.
|
||||
// The first time we register a handler, we need to
|
||||
// allocate an exception stack (one page of memory with its top
|
||||
// at UXSTACKTOP), and tell the kernel to call the assembly-language
|
||||
// _pgfault_upcall routine when a page fault occurs.
|
||||
//
|
||||
void
|
||||
set_pgfault_handler(void (*handler)(struct UTrapframe *utf))
|
||||
{
|
||||
int r;
|
||||
|
||||
if (_pgfault_handler == 0) {
|
||||
// First time through!
|
||||
// LAB 4: Your code here.
|
||||
|
||||
sys_page_alloc(sys_getenvid(), (void *) (UXSTACKTOP - PGSIZE), PTE_SYSCALL);
|
||||
sys_env_set_pgfault_upcall(sys_getenvid(), _pgfault_upcall);
|
||||
// panic("set_pgfault_handler not implemented");
|
||||
}
|
||||
|
||||
// Save handler pointer for assembly to call.
|
||||
_pgfault_handler = handler;
|
||||
}
|
||||
62
lab/lib/printf.c
Normal file
62
lab/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;
|
||||
}
|
||||
|
||||
302
lab/lib/printfmt.c
Normal file
302
lab/lib/printfmt.c
Normal file
@@ -0,0 +1,302 @@
|
||||
// Stripped-down primitive printf-style formatting routines,
|
||||
// used in common by printf, sprintf, fprintf, etc.
|
||||
// This code is also used by both the kernel and user programs.
|
||||
|
||||
#include <inc/types.h>
|
||||
#include <inc/stdio.h>
|
||||
#include <inc/string.h>
|
||||
#include <inc/stdarg.h>
|
||||
#include <inc/error.h>
|
||||
|
||||
/*
|
||||
* Space or zero padding and a field width are supported for the numeric
|
||||
* formats only.
|
||||
*
|
||||
* The special format %e takes an integer error code
|
||||
* and prints a string describing the error.
|
||||
* The integer may be positive or negative,
|
||||
* so that -E_NO_MEM and E_NO_MEM are equivalent.
|
||||
*/
|
||||
|
||||
static const char * const error_string[MAXERROR] =
|
||||
{
|
||||
[E_UNSPECIFIED] = "unspecified error",
|
||||
[E_BAD_ENV] = "bad environment",
|
||||
[E_INVAL] = "invalid parameter",
|
||||
[E_NO_MEM] = "out of memory",
|
||||
[E_NO_FREE_ENV] = "out of environments",
|
||||
[E_FAULT] = "segmentation fault",
|
||||
[E_IPC_NOT_RECV]= "env is not recving",
|
||||
[E_EOF] = "unexpected end of file",
|
||||
};
|
||||
|
||||
/*
|
||||
* Print a number (base <= 16) in reverse order,
|
||||
* using specified putch function and associated pointer putdat.
|
||||
*/
|
||||
static void
|
||||
printnum(void (*putch)(int, void*), void *putdat,
|
||||
unsigned long long num, unsigned base, int width, int padc)
|
||||
{
|
||||
// first recursively print all preceding (more significant) digits
|
||||
if (num >= base) {
|
||||
printnum(putch, putdat, num / base, base, width - 1, padc);
|
||||
} else {
|
||||
// print any needed pad characters before first digit
|
||||
while (--width > 0)
|
||||
putch(padc, putdat);
|
||||
}
|
||||
|
||||
// then print this (the least significant) digit
|
||||
putch("0123456789abcdef"[num % base], putdat);
|
||||
}
|
||||
|
||||
// Get an unsigned int of various possible sizes from a varargs list,
|
||||
// depending on the lflag parameter.
|
||||
static unsigned long long
|
||||
getuint(va_list *ap, int lflag)
|
||||
{
|
||||
if (lflag >= 2)
|
||||
return va_arg(*ap, unsigned long long);
|
||||
else if (lflag)
|
||||
return va_arg(*ap, unsigned long);
|
||||
else
|
||||
return va_arg(*ap, unsigned int);
|
||||
}
|
||||
|
||||
// Same as getuint but signed - can't use getuint
|
||||
// because of sign extension
|
||||
static long long
|
||||
getint(va_list *ap, int lflag)
|
||||
{
|
||||
if (lflag >= 2)
|
||||
return va_arg(*ap, long long);
|
||||
else if (lflag)
|
||||
return va_arg(*ap, long);
|
||||
else
|
||||
return va_arg(*ap, int);
|
||||
}
|
||||
|
||||
|
||||
// Main function to format and print a string.
|
||||
void printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...);
|
||||
|
||||
void
|
||||
vprintfmt(void (*putch)(int, void*), void *putdat, const char *fmt, va_list ap)
|
||||
{
|
||||
register const char *p;
|
||||
register int ch, err;
|
||||
unsigned long long num;
|
||||
int base, lflag, width, precision, altflag;
|
||||
char padc;
|
||||
|
||||
while (1) {
|
||||
while ((ch = *(unsigned char *) fmt++) != '%') {
|
||||
if (ch == '\0')
|
||||
return;
|
||||
putch(ch, putdat);
|
||||
}
|
||||
|
||||
// Process a %-escape sequence
|
||||
padc = ' ';
|
||||
width = -1;
|
||||
precision = -1;
|
||||
lflag = 0;
|
||||
altflag = 0;
|
||||
reswitch:
|
||||
switch (ch = *(unsigned char *) fmt++) {
|
||||
|
||||
// flag to pad on the right
|
||||
case '-':
|
||||
padc = '-';
|
||||
goto reswitch;
|
||||
|
||||
// flag to pad with 0's instead of spaces
|
||||
case '0':
|
||||
padc = '0';
|
||||
goto reswitch;
|
||||
|
||||
// width field
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
for (precision = 0; ; ++fmt) {
|
||||
precision = precision * 10 + ch - '0';
|
||||
ch = *fmt;
|
||||
if (ch < '0' || ch > '9')
|
||||
break;
|
||||
}
|
||||
goto process_precision;
|
||||
|
||||
case '*':
|
||||
precision = va_arg(ap, int);
|
||||
goto process_precision;
|
||||
|
||||
case '.':
|
||||
if (width < 0)
|
||||
width = 0;
|
||||
goto reswitch;
|
||||
|
||||
case '#':
|
||||
altflag = 1;
|
||||
goto reswitch;
|
||||
|
||||
process_precision:
|
||||
if (width < 0)
|
||||
width = precision, precision = -1;
|
||||
goto reswitch;
|
||||
|
||||
// long flag (doubled for long long)
|
||||
case 'l':
|
||||
lflag++;
|
||||
goto reswitch;
|
||||
|
||||
// character
|
||||
case 'c':
|
||||
putch(va_arg(ap, int), putdat);
|
||||
break;
|
||||
|
||||
// error message
|
||||
case 'e':
|
||||
err = va_arg(ap, int);
|
||||
if (err < 0)
|
||||
err = -err;
|
||||
if (err >= MAXERROR || (p = error_string[err]) == NULL)
|
||||
printfmt(putch, putdat, "error %d", err);
|
||||
else
|
||||
printfmt(putch, putdat, "%s", p);
|
||||
break;
|
||||
|
||||
// string
|
||||
case 's':
|
||||
if ((p = va_arg(ap, char *)) == NULL)
|
||||
p = "(null)";
|
||||
if (width > 0 && padc != '-')
|
||||
for (width -= strnlen(p, precision); width > 0; width--)
|
||||
putch(padc, putdat);
|
||||
for (; (ch = *p++) != '\0' && (precision < 0 || --precision >= 0); width--)
|
||||
if (altflag && (ch < ' ' || ch > '~'))
|
||||
putch('?', putdat);
|
||||
else
|
||||
putch(ch, putdat);
|
||||
for (; width > 0; width--)
|
||||
putch(' ', putdat);
|
||||
break;
|
||||
|
||||
// (signed) decimal
|
||||
case 'd':
|
||||
num = getint(&ap, lflag);
|
||||
if ((long long) num < 0) {
|
||||
putch('-', putdat);
|
||||
num = -(long long) num;
|
||||
}
|
||||
base = 10;
|
||||
goto number;
|
||||
|
||||
// unsigned decimal
|
||||
case 'u':
|
||||
num = getuint(&ap, lflag);
|
||||
base = 10;
|
||||
goto number;
|
||||
|
||||
// (unsigned) octal
|
||||
case 'o':
|
||||
// Replace this with your code.
|
||||
putch('X', putdat);
|
||||
putch('X', putdat);
|
||||
putch('X', putdat);
|
||||
break;
|
||||
|
||||
// pointer
|
||||
case 'p':
|
||||
putch('0', putdat);
|
||||
putch('x', putdat);
|
||||
num = (unsigned long long)
|
||||
(uintptr_t) va_arg(ap, void *);
|
||||
base = 16;
|
||||
goto number;
|
||||
|
||||
// (unsigned) hexadecimal
|
||||
case 'x':
|
||||
num = getuint(&ap, lflag);
|
||||
base = 16;
|
||||
number:
|
||||
printnum(putch, putdat, num, base, width, padc);
|
||||
break;
|
||||
|
||||
// escaped '%' character
|
||||
case '%':
|
||||
putch(ch, putdat);
|
||||
break;
|
||||
|
||||
// unrecognized escape sequence - just print it literally
|
||||
default:
|
||||
putch('%', putdat);
|
||||
for (fmt--; fmt[-1] != '%'; fmt--)
|
||||
/* do nothing */;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
printfmt(void (*putch)(int, void*), void *putdat, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintfmt(putch, putdat, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
struct sprintbuf {
|
||||
char *buf;
|
||||
char *ebuf;
|
||||
int cnt;
|
||||
};
|
||||
|
||||
static void
|
||||
sprintputch(int ch, struct sprintbuf *b)
|
||||
{
|
||||
b->cnt++;
|
||||
if (b->buf < b->ebuf)
|
||||
*b->buf++ = ch;
|
||||
}
|
||||
|
||||
int
|
||||
vsnprintf(char *buf, int n, const char *fmt, va_list ap)
|
||||
{
|
||||
struct sprintbuf b = {buf, buf+n-1, 0};
|
||||
|
||||
if (buf == NULL || n < 1)
|
||||
return -E_INVAL;
|
||||
|
||||
// print the string to the buffer
|
||||
vprintfmt((void*)sprintputch, &b, fmt, ap);
|
||||
|
||||
// null terminate the buffer
|
||||
*b.buf = '\0';
|
||||
|
||||
return b.cnt;
|
||||
}
|
||||
|
||||
int
|
||||
snprintf(char *buf, int n, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int rc;
|
||||
|
||||
va_start(ap, fmt);
|
||||
rc = vsnprintf(buf, n, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
38
lab/lib/readline.c
Normal file
38
lab/lib/readline.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <inc/stdio.h>
|
||||
#include <inc/error.h>
|
||||
|
||||
#define BUFLEN 1024
|
||||
static char buf[BUFLEN];
|
||||
|
||||
char *
|
||||
readline(const char *prompt)
|
||||
{
|
||||
int i, c, echoing;
|
||||
|
||||
if (prompt != NULL)
|
||||
cprintf("%s", prompt);
|
||||
|
||||
i = 0;
|
||||
echoing = iscons(0);
|
||||
while (1) {
|
||||
c = getchar();
|
||||
if (c < 0) {
|
||||
cprintf("read error: %e\n", c);
|
||||
return NULL;
|
||||
} else if ((c == '\b' || c == '\x7f') && i > 0) {
|
||||
if (echoing)
|
||||
cputchar('\b');
|
||||
i--;
|
||||
} else if (c >= ' ' && i < BUFLEN-1) {
|
||||
if (echoing)
|
||||
cputchar(c);
|
||||
buf[i++] = c;
|
||||
} else if (c == '\n' || c == '\r') {
|
||||
if (echoing)
|
||||
cputchar('\n');
|
||||
buf[i] = 0;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
285
lab/lib/string.c
Normal file
285
lab/lib/string.c
Normal file
@@ -0,0 +1,285 @@
|
||||
// Basic string routines. Not hardware optimized, but not shabby.
|
||||
|
||||
#include <inc/string.h>
|
||||
|
||||
// Using assembly for memset/memmove
|
||||
// makes some difference on real hardware,
|
||||
// but it makes an even bigger difference on bochs.
|
||||
// Primespipe runs 3x faster this way.
|
||||
#define ASM 1
|
||||
|
||||
int
|
||||
strlen(const char *s)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; *s != '\0'; s++)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
strnlen(const char *s, size_t size)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; size > 0 && *s != '\0'; s++, size--)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
char *
|
||||
strcpy(char *dst, const char *src)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
ret = dst;
|
||||
while ((*dst++ = *src++) != '\0')
|
||||
/* do nothing */;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
strcat(char *dst, const char *src)
|
||||
{
|
||||
int len = strlen(dst);
|
||||
strcpy(dst + len, src);
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *
|
||||
strncpy(char *dst, const char *src, size_t size) {
|
||||
size_t i;
|
||||
char *ret;
|
||||
|
||||
ret = dst;
|
||||
for (i = 0; i < size; i++) {
|
||||
*dst++ = *src;
|
||||
// If strlen(src) < size, null-pad 'dst' out to 'size' chars
|
||||
if (*src != '\0')
|
||||
src++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
char *dst_in;
|
||||
|
||||
dst_in = dst;
|
||||
if (size > 0) {
|
||||
while (--size > 0 && *src != '\0')
|
||||
*dst++ = *src++;
|
||||
*dst = '\0';
|
||||
}
|
||||
return dst - dst_in;
|
||||
}
|
||||
|
||||
int
|
||||
strcmp(const char *p, const char *q)
|
||||
{
|
||||
while (*p && *p == *q)
|
||||
p++, q++;
|
||||
return (int) ((unsigned char) *p - (unsigned char) *q);
|
||||
}
|
||||
|
||||
int
|
||||
strncmp(const char *p, const char *q, size_t n)
|
||||
{
|
||||
while (n > 0 && *p && *p == *q)
|
||||
n--, p++, q++;
|
||||
if (n == 0)
|
||||
return 0;
|
||||
else
|
||||
return (int) ((unsigned char) *p - (unsigned char) *q);
|
||||
}
|
||||
|
||||
// Return a pointer to the first occurrence of 'c' in 's',
|
||||
// or a null pointer if the string has no 'c'.
|
||||
char *
|
||||
strchr(const char *s, char c)
|
||||
{
|
||||
for (; *s; s++)
|
||||
if (*s == c)
|
||||
return (char *) s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return a pointer to the first occurrence of 'c' in 's',
|
||||
// or a pointer to the string-ending null character if the string has no 'c'.
|
||||
char *
|
||||
strfind(const char *s, char c)
|
||||
{
|
||||
for (; *s; s++)
|
||||
if (*s == c)
|
||||
break;
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
#if ASM
|
||||
void *
|
||||
memset(void *v, int c, size_t n)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (n == 0)
|
||||
return v;
|
||||
if ((int)v%4 == 0 && n%4 == 0) {
|
||||
c &= 0xFF;
|
||||
c = (c<<24)|(c<<16)|(c<<8)|c;
|
||||
asm volatile("cld; rep stosl\n"
|
||||
:: "D" (v), "a" (c), "c" (n/4)
|
||||
: "cc", "memory");
|
||||
} else
|
||||
asm volatile("cld; rep stosb\n"
|
||||
:: "D" (v), "a" (c), "c" (n)
|
||||
: "cc", "memory");
|
||||
return v;
|
||||
}
|
||||
|
||||
void *
|
||||
memmove(void *dst, const void *src, size_t n)
|
||||
{
|
||||
const char *s;
|
||||
char *d;
|
||||
|
||||
s = src;
|
||||
d = dst;
|
||||
if (s < d && s + n > d) {
|
||||
s += n;
|
||||
d += n;
|
||||
if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0)
|
||||
asm volatile("std; rep movsl\n"
|
||||
:: "D" (d-4), "S" (s-4), "c" (n/4) : "cc", "memory");
|
||||
else
|
||||
asm volatile("std; rep movsb\n"
|
||||
:: "D" (d-1), "S" (s-1), "c" (n) : "cc", "memory");
|
||||
// Some versions of GCC rely on DF being clear
|
||||
asm volatile("cld" ::: "cc");
|
||||
} else {
|
||||
if ((int)s%4 == 0 && (int)d%4 == 0 && n%4 == 0)
|
||||
asm volatile("cld; rep movsl\n"
|
||||
:: "D" (d), "S" (s), "c" (n/4) : "cc", "memory");
|
||||
else
|
||||
asm volatile("cld; rep movsb\n"
|
||||
:: "D" (d), "S" (s), "c" (n) : "cc", "memory");
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *
|
||||
memset(void *v, int c, size_t n)
|
||||
{
|
||||
char *p;
|
||||
int m;
|
||||
|
||||
p = v;
|
||||
m = n;
|
||||
while (--m >= 0)
|
||||
*p++ = c;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void *
|
||||
memmove(void *dst, const void *src, size_t n)
|
||||
{
|
||||
const char *s;
|
||||
char *d;
|
||||
|
||||
s = src;
|
||||
d = dst;
|
||||
if (s < d && s + n > d) {
|
||||
s += n;
|
||||
d += n;
|
||||
while (n-- > 0)
|
||||
*--d = *--s;
|
||||
} else
|
||||
while (n-- > 0)
|
||||
*d++ = *s++;
|
||||
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *
|
||||
memcpy(void *dst, const void *src, size_t n)
|
||||
{
|
||||
return memmove(dst, src, n);
|
||||
}
|
||||
|
||||
int
|
||||
memcmp(const void *v1, const void *v2, size_t n)
|
||||
{
|
||||
const uint8_t *s1 = (const uint8_t *) v1;
|
||||
const uint8_t *s2 = (const uint8_t *) v2;
|
||||
|
||||
while (n-- > 0) {
|
||||
if (*s1 != *s2)
|
||||
return (int) *s1 - (int) *s2;
|
||||
s1++, s2++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
memfind(const void *s, int c, size_t n)
|
||||
{
|
||||
const void *ends = (const char *) s + n;
|
||||
for (; s < ends; s++)
|
||||
if (*(const unsigned char *) s == (unsigned char) c)
|
||||
break;
|
||||
return (void *) s;
|
||||
}
|
||||
|
||||
long
|
||||
strtol(const char *s, char **endptr, int base)
|
||||
{
|
||||
int neg = 0;
|
||||
long val = 0;
|
||||
|
||||
// gobble initial whitespace
|
||||
while (*s == ' ' || *s == '\t')
|
||||
s++;
|
||||
|
||||
// plus/minus sign
|
||||
if (*s == '+')
|
||||
s++;
|
||||
else if (*s == '-')
|
||||
s++, neg = 1;
|
||||
|
||||
// hex or octal base prefix
|
||||
if ((base == 0 || base == 16) && (s[0] == '0' && s[1] == 'x'))
|
||||
s += 2, base = 16;
|
||||
else if (base == 0 && s[0] == '0')
|
||||
s++, base = 8;
|
||||
else if (base == 0)
|
||||
base = 10;
|
||||
|
||||
// digits
|
||||
while (1) {
|
||||
int dig;
|
||||
|
||||
if (*s >= '0' && *s <= '9')
|
||||
dig = *s - '0';
|
||||
else if (*s >= 'a' && *s <= 'z')
|
||||
dig = *s - 'a' + 10;
|
||||
else if (*s >= 'A' && *s <= 'Z')
|
||||
dig = *s - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
if (dig >= base)
|
||||
break;
|
||||
s++, val = (val * base) + dig;
|
||||
// we don't properly detect overflow!
|
||||
}
|
||||
|
||||
if (endptr)
|
||||
*endptr = (char *) s;
|
||||
return (neg ? -val : val);
|
||||
}
|
||||
|
||||
113
lab/lib/syscall.c
Normal file
113
lab/lib/syscall.c
Normal file
@@ -0,0 +1,113 @@
|
||||
// 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);
|
||||
}
|
||||
|
||||
void
|
||||
sys_yield(void)
|
||||
{
|
||||
syscall(SYS_yield, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sys_page_alloc(envid_t envid, void *va, int perm)
|
||||
{
|
||||
return syscall(SYS_page_alloc, 1, envid, (uint32_t) va, perm, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sys_page_map(envid_t srcenv, void *srcva, envid_t dstenv, void *dstva, int perm)
|
||||
{
|
||||
return syscall(SYS_page_map, 1, srcenv, (uint32_t) srcva, dstenv, (uint32_t) dstva, perm);
|
||||
}
|
||||
|
||||
int
|
||||
sys_page_unmap(envid_t envid, void *va)
|
||||
{
|
||||
return syscall(SYS_page_unmap, 1, envid, (uint32_t) va, 0, 0, 0);
|
||||
}
|
||||
|
||||
// sys_exofork is inlined in lib.h
|
||||
|
||||
int
|
||||
sys_env_set_status(envid_t envid, int status)
|
||||
{
|
||||
return syscall(SYS_env_set_status, 1, envid, status, 0, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sys_env_set_pgfault_upcall(envid_t envid, void *upcall)
|
||||
{
|
||||
return syscall(SYS_env_set_pgfault_upcall, 1, envid, (uint32_t) upcall, 0, 0, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sys_ipc_try_send(envid_t envid, uint32_t value, void *srcva, int perm)
|
||||
{
|
||||
return syscall(SYS_ipc_try_send, 0, envid, value, (uint32_t) srcva, perm, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sys_ipc_recv(void *dstva)
|
||||
{
|
||||
return syscall(SYS_ipc_recv, 1, (uint32_t)dstva, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user