summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/defs.h9
-rw-r--r--kernel/exec.c4
-rw-r--r--kernel/kalloc.c14
-rw-r--r--kernel/memlayout.h17
-rw-r--r--kernel/printf.c17
-rw-r--r--kernel/proc.c84
-rw-r--r--kernel/proc.h7
-rw-r--r--kernel/riscv.h10
-rw-r--r--kernel/syscall.c66
-rw-r--r--kernel/syscall.h11
-rw-r--r--kernel/sysinfo.c24
-rw-r--r--kernel/sysinfo.h4
-rw-r--r--kernel/sysproc.c65
-rw-r--r--kernel/trap.c23
-rw-r--r--kernel/vm.c27
15 files changed, 375 insertions, 7 deletions
diff --git a/kernel/defs.h b/kernel/defs.h
index a3c962b..04a0276 100644
--- a/kernel/defs.h
+++ b/kernel/defs.h
@@ -8,6 +8,7 @@ struct spinlock;
struct sleeplock;
struct stat;
struct superblock;
+struct sysinfo;
// bio.c
void binit(void);
@@ -63,6 +64,7 @@ void ramdiskrw(struct buf*);
void* kalloc(void);
void kfree(void *);
void kinit(void);
+int get_freemem(void);
// log.c
void initlog(int, struct superblock*);
@@ -80,6 +82,7 @@ int pipewrite(struct pipe*, uint64, int);
void printf(char*, ...);
void panic(char*) __attribute__((noreturn));
void printfinit(void);
+void backtrace(void);
// proc.c
int cpuid(void);
@@ -106,6 +109,8 @@ void yield(void);
int either_copyout(int user_dst, uint64 dst, void *src, uint64 len);
int either_copyin(void *dst, int user_src, uint64 src, uint64 len);
void procdump(void);
+int get_nproc(void);
+int pgaccess(uint64 base, int len, uint64 mask);
// swtch.S
void swtch(struct context*, struct context*);
@@ -141,6 +146,9 @@ int fetchstr(uint64, char*, int);
int fetchaddr(uint64, uint64*);
void syscall();
+// sysinfo.c
+int sys_info(uint64);
+
// trap.c
extern uint ticks;
void trapinit(void);
@@ -173,6 +181,7 @@ uint64 walkaddr(pagetable_t, uint64);
int copyout(pagetable_t, uint64, char *, uint64);
int copyin(pagetable_t, char *, uint64, uint64);
int copyinstr(pagetable_t, char *, uint64, uint64);
+void vmprint(pagetable_t);
// plic.c
void plicinit(void);
diff --git a/kernel/exec.c b/kernel/exec.c
index e18bbb6..35b35f5 100644
--- a/kernel/exec.c
+++ b/kernel/exec.c
@@ -128,6 +128,10 @@ exec(char *path, char **argv)
p->trapframe->sp = sp; // initial stack pointer
proc_freepagetable(oldpagetable, oldsz);
+ if(p->pid == 1){
+ vmprint(p->pagetable);
+ }
+
return argc; // this ends up in a0, the first argument to main(argc, argv)
bad:
diff --git a/kernel/kalloc.c b/kernel/kalloc.c
index 0699e7e..c2fdb86 100644
--- a/kernel/kalloc.c
+++ b/kernel/kalloc.c
@@ -80,3 +80,17 @@ kalloc(void)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}
+
+int
+get_freemem(void)
+{
+ int n;
+ struct run *r;
+
+ acquire(&kmem.lock);
+ for (n = 0, r = kmem.freelist; r; r = r->next)
+ n++;
+ release(&kmem.lock);
+
+ return n * PGSIZE;
+}
diff --git a/kernel/memlayout.h b/kernel/memlayout.h
index cac3cb1..74d2fd4 100644
--- a/kernel/memlayout.h
+++ b/kernel/memlayout.h
@@ -25,6 +25,10 @@
#define VIRTIO0 0x10001000
#define VIRTIO0_IRQ 1
+#ifdef LAB_NET
+#define E1000_IRQ 33
+#endif
+
// core local interruptor (CLINT), which contains the timer.
#define CLINT 0x2000000L
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid))
@@ -34,8 +38,11 @@
#define PLIC 0x0c000000L
#define PLIC_PRIORITY (PLIC + 0x0)
#define PLIC_PENDING (PLIC + 0x1000)
+#define PLIC_MENABLE(hart) (PLIC + 0x2000 + (hart)*0x100)
#define PLIC_SENABLE(hart) (PLIC + 0x2080 + (hart)*0x100)
+#define PLIC_MPRIORITY(hart) (PLIC + 0x200000 + (hart)*0x2000)
#define PLIC_SPRIORITY(hart) (PLIC + 0x201000 + (hart)*0x2000)
+#define PLIC_MCLAIM(hart) (PLIC + 0x200004 + (hart)*0x2000)
#define PLIC_SCLAIM(hart) (PLIC + 0x201004 + (hart)*0x2000)
// the kernel expects there to be RAM
@@ -50,7 +57,7 @@
// map kernel stacks beneath the trampoline,
// each surrounded by invalid guard pages.
-#define KSTACK(p) (TRAMPOLINE - ((p)+1)* 2*PGSIZE)
+#define KSTACK(p) (TRAMPOLINE - (p)*2*PGSIZE - 3*PGSIZE)
// User memory layout.
// Address zero first:
@@ -59,6 +66,14 @@
// fixed-size stack
// expandable heap
// ...
+// USYSCALL (shared with kernel)
// TRAPFRAME (p->trapframe, used by the trampoline)
// TRAMPOLINE (the same page as in the kernel)
#define TRAPFRAME (TRAMPOLINE - PGSIZE)
+#ifdef LAB_PGTBL
+#define USYSCALL (TRAPFRAME - PGSIZE)
+
+struct usyscall {
+ int pid; // Process ID
+};
+#endif
diff --git a/kernel/printf.c b/kernel/printf.c
index 1a50203..509c1c5 100644
--- a/kernel/printf.c
+++ b/kernel/printf.c
@@ -122,6 +122,8 @@ panic(char *s)
printf("panic: ");
printf(s);
printf("\n");
+ backtrace();
+
panicked = 1; // freeze uart output from other CPUs
for(;;)
;
@@ -133,3 +135,18 @@ printfinit(void)
initlock(&pr.lock, "pr");
pr.locking = 1;
}
+
+void
+backtrace(void)
+{
+ uint64 fp = r_fp();
+ printf("backtrace:\n");
+ uint64 stackpg = PGROUNDDOWN(fp);
+ // Whereever fp points to should always live in the stack page
+ while(PGROUNDDOWN(fp) == stackpg){
+ // print the return addr (stored in fp-8)
+ printf("%p\n", *(uint64 *)(fp-8));
+ // load previous (upper stack) fp
+ fp = *(uint64 *)(fp-16);
+ }
+}
diff --git a/kernel/proc.c b/kernel/proc.c
index 58a8a0b..9a9bae9 100644
--- a/kernel/proc.c
+++ b/kernel/proc.c
@@ -39,6 +39,7 @@ proc_mapstacks(pagetable_t kpgtbl)
if(pa == 0)
panic("kalloc");
uint64 va = KSTACK((int) (p - proc));
+ p->alarm_tickspassed = 0;
kvmmap(kpgtbl, va, (uint64)pa, PGSIZE, PTE_R | PTE_W);
}
}
@@ -132,6 +133,25 @@ found:
return 0;
}
+ // Allocate a usyscall page and fill pid.
+ if((p->usyscall = (struct usyscall *)kalloc()) == 0){
+ freeproc(p);
+ release(&p->lock);
+ return 0;
+ }
+ p->usyscall->pid = p->pid;
+
+ // reset sigalarm props
+ p->alarm_interval = 0;
+ p->alarm_handler = 0;
+ p->alarm_tickspassed = 0;
+ p->alarm_caninvoke = 1;
+ if((p->atpfm = (struct trapframe *)kalloc()) == 0){
+ freeproc(p);
+ release(&p->lock);
+ return 0;
+ }
+
// An empty user page table.
p->pagetable = proc_pagetable(p);
if(p->pagetable == 0){
@@ -158,8 +178,18 @@ freeproc(struct proc *p)
if(p->trapframe)
kfree((void*)p->trapframe);
p->trapframe = 0;
+ if(p->usyscall)
+ kfree((void*)p->usyscall);
+ p->usyscall = 0;
if(p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
+ if(p->atpfm)
+ kfree((void*)p->atpfm);
+ p->atpfm = 0;
+ p->alarm_interval = 0;
+ p->alarm_handler = 0;
+ p->alarm_tickspassed = 0;
+ p->alarm_caninvoke = 1;
p->pagetable = 0;
p->sz = 0;
p->pid = 0;
@@ -172,7 +202,7 @@ freeproc(struct proc *p)
}
// Create a user page table for a given process, with no user memory,
-// but with trampoline and trapframe pages.
+// but with trampoline, trapframe and usyscall pages.
pagetable_t
proc_pagetable(struct proc *p)
{
@@ -202,6 +232,14 @@ proc_pagetable(struct proc *p)
return 0;
}
+ // map the usyscall page below the trapframe page, for
+ // ugetpid().
+ if(mappages(pagetable, USYSCALL, PGSIZE,
+ (uint64)(p->usyscall), PTE_R | PTE_U) < 0){
+ uvmunmap(pagetable, USYSCALL, 1, 0);
+ uvmfree(pagetable, 0);
+ return 0;
+ }
return pagetable;
}
@@ -212,6 +250,7 @@ proc_freepagetable(pagetable_t pagetable, uint64 sz)
{
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmunmap(pagetable, TRAPFRAME, 1, 0);
+ uvmunmap(pagetable, USYSCALL, 1, 0);
uvmfree(pagetable, sz);
}
@@ -299,6 +338,9 @@ fork(void)
// copy saved user registers.
*(np->trapframe) = *(p->trapframe);
+ // inherit trace_mask
+ np->trace_mask = p->trace_mask;
+
// Cause fork to return 0 in the child.
np->trapframe->a0 = 0;
@@ -686,3 +728,43 @@ procdump(void)
printf("\n");
}
}
+
+int
+get_nproc(void)
+{
+ int n = 0;
+ struct proc *p;
+
+ for(int i = 0; i < NPROC; i++) {
+ p = &proc[i];
+ acquire(&p->lock);
+ if(p->state != UNUSED)
+ n++;
+ release(&p->lock);
+ }
+
+ return n;
+}
+
+// lab pagetable: report which pages have been accessed (r/w)
+// according to PTE_A and store it in a bit mask (3rd param)
+int
+pgaccess(uint64 base, int len, uint64 mask_addr)
+{
+ struct proc *p = myproc();
+ pagetable_t pgtbl = p->pagetable;
+ pte_t *pte;
+ int mask = 0;
+
+ // iterater thru pages
+ for(int i = 0; i < len; i++) {
+ pte = walk(pgtbl, base + i * PGSIZE, 0);
+ if(*pte & PTE_A) {
+ *pte &= (~PTE_A); // clear PTE_A to avoid setting it forever
+ mask |= (1L << i);
+ }
+ }
+
+ // now copyout the mask to user memory
+ return copyout(pgtbl, mask_addr, (char *)&mask, sizeof(mask));
+}
diff --git a/kernel/proc.h b/kernel/proc.h
index d021857..a195b02 100644
--- a/kernel/proc.h
+++ b/kernel/proc.h
@@ -91,6 +91,7 @@ struct proc {
int killed; // If non-zero, have been killed
int xstate; // Exit status to be returned to parent's wait
int pid; // Process ID
+ int trace_mask; // SYS_trace mask (1 << SYS_xxx)
// wait_lock must be held when using this:
struct proc *parent; // Parent process
@@ -100,8 +101,14 @@ struct proc {
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
+ struct usyscall *usyscall; // data page for usyscall
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
+ int alarm_interval; // sigalarm syscall interval
+ uint64 alarm_handler; // sigalarm syscall handler
+ int alarm_tickspassed; // record how many ticks passed since last sigalarm handler call
+ int alarm_caninvoke; // prevent re-entrant calls to handler
+ struct trapframe *atpfm; // trapframe to resume after handling, must hold p->lock
};
diff --git a/kernel/riscv.h b/kernel/riscv.h
index 20a01db..5ede50a 100644
--- a/kernel/riscv.h
+++ b/kernel/riscv.h
@@ -327,6 +327,15 @@ sfence_vma()
asm volatile("sfence.vma zero, zero");
}
+// read the frame pointer of currently executing func
+static inline uint64
+r_fp()
+{
+ uint64 x;
+ asm volatile("mv %0, s0" : "=r" (x) );
+ return x;
+}
+
typedef uint64 pte_t;
typedef uint64 *pagetable_t; // 512 PTEs
@@ -343,6 +352,7 @@ typedef uint64 *pagetable_t; // 512 PTEs
#define PTE_W (1L << 2)
#define PTE_X (1L << 3)
#define PTE_U (1L << 4) // user can access
+#define PTE_A (1L << 6) // riscv access bit
// shift a physical address to the right place for a PTE.
#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
diff --git a/kernel/syscall.c b/kernel/syscall.c
index ed65409..8392eb4 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -101,6 +101,17 @@ extern uint64 sys_unlink(void);
extern uint64 sys_link(void);
extern uint64 sys_mkdir(void);
extern uint64 sys_close(void);
+extern uint64 sys_trace(void);
+extern uint64 sys_sysinfo(void);
+
+#ifdef LAB_NET
+extern uint64 sys_connect(void);
+#endif
+#ifdef LAB_PGTBL
+extern uint64 sys_pgaccess(void);
+#endif
+extern uint64 sys_sigalarm(void);
+extern uint64 sys_sigreturn(void);
// An array mapping syscall numbers from syscall.h
// to the function that handles the system call.
@@ -126,8 +137,55 @@ static uint64 (*syscalls[])(void) = {
[SYS_link] sys_link,
[SYS_mkdir] sys_mkdir,
[SYS_close] sys_close,
+#ifdef LAB_NET
+[SYS_connect] sys_connect,
+#endif
+#ifdef LAB_PGTBL
+[SYS_pgaccess] sys_pgaccess,
+#endif
+[SYS_trace] sys_trace,
+[SYS_sysinfo] sys_sysinfo,
+[SYS_sigalarm] sys_sigalarm,
+[SYS_sigreturn] sys_sigreturn,
+};
+
+// syscall name maps for SYS_trace:
+static char *syscall_names[] = {
+[SYS_fork] "fork",
+[SYS_exit] "exit",
+[SYS_wait] "wait",
+[SYS_pipe] "pipe",
+[SYS_read] "read",
+[SYS_kill] "kill",
+[SYS_exec] "exec",
+[SYS_fstat] "fstat",
+[SYS_chdir] "chdir",
+[SYS_dup] "dup",
+[SYS_getpid] "getpid",
+[SYS_sbrk] "sbrk",
+[SYS_sleep] "sleep",
+[SYS_uptime] "uptime",
+[SYS_open] "open",
+[SYS_write] "write",
+[SYS_mknod] "mknod",
+[SYS_unlink] "unlink",
+[SYS_link] "link",
+[SYS_mkdir] "mkdir",
+[SYS_close] "close",
+#ifdef LAB_NET
+[SYS_connect] "connect",
+#endif
+#ifdef LAB_PGTBL
+[SYS_pgaccess] "pgaccess",
+#endif
+[SYS_trace] "trace",
+[SYS_sysinfo] "sysinfo",
+[SYS_sigalarm] "sigalarm",
+[SYS_sigreturn] "sigreturn",
};
+
+
void
syscall(void)
{
@@ -139,9 +197,17 @@ syscall(void)
// Use num to lookup the system call function for num, call it,
// and store its return value in p->trapframe->a0
p->trapframe->a0 = syscalls[num]();
+
+ // SYS_trace: match all the syscalls which number < mask asked
+ // p->trace_mask == 1 << SYS_xxx
+ if(p->trace_mask >> num) {
+ printf("%d: syscall %s -> %d\n", p->pid, syscall_names[num], p->trapframe->a0);
+ }
+
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
+
diff --git a/kernel/syscall.h b/kernel/syscall.h
index bc5f356..8da572e 100644
--- a/kernel/syscall.h
+++ b/kernel/syscall.h
@@ -20,3 +20,14 @@
#define SYS_link 19
#define SYS_mkdir 20
#define SYS_close 21
+
+// System calls for labs
+#define SYS_trace 22
+#define SYS_sysinfo 23
+#define SYS_sigalarm 24
+#define SYS_sigreturn 25
+#define SYS_symlink 26
+#define SYS_mmap 27
+#define SYS_munmap 28
+#define SYS_connect 29
+#define SYS_pgaccess 30
diff --git a/kernel/sysinfo.c b/kernel/sysinfo.c
new file mode 100644
index 0000000..c66324d
--- /dev/null
+++ b/kernel/sysinfo.c
@@ -0,0 +1,24 @@
+#include "types.h"
+#include "riscv.h"
+#include "param.h"
+#include "spinlock.h"
+#include "defs.h"
+#include "sysinfo.h"
+#include "proc.h"
+
+// Get current system info
+// addr is a user virtual address, pointing to a struct sysinfo.
+int
+sys_info(uint64 addr) {
+ struct proc *p = myproc();
+ struct sysinfo info;
+
+ // Fill nums into the sysinfo struct
+ info.freemem = get_freemem();
+ info.nproc = get_nproc();
+
+ if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)
+ return -1;
+ return 0;
+}
+
diff --git a/kernel/sysinfo.h b/kernel/sysinfo.h
new file mode 100644
index 0000000..fb878e6
--- /dev/null
+++ b/kernel/sysinfo.h
@@ -0,0 +1,4 @@
+struct sysinfo {
+ uint64 freemem; // amount of free memory (bytes)
+ uint64 nproc; // number of process
+};
diff --git a/kernel/sysproc.c b/kernel/sysproc.c
index 3b4d5bd..fac1d83 100644
--- a/kernel/sysproc.c
+++ b/kernel/sysproc.c
@@ -1,7 +1,7 @@
#include "types.h"
#include "riscv.h"
-#include "defs.h"
#include "param.h"
+#include "defs.h"
#include "memlayout.h"
#include "spinlock.h"
#include "proc.h"
@@ -54,9 +54,8 @@ sys_sleep(void)
int n;
uint ticks0;
+
argint(0, &n);
- if(n < 0)
- n = 0;
acquire(&tickslock);
ticks0 = ticks;
while(ticks - ticks0 < n){
@@ -66,10 +65,29 @@ sys_sleep(void)
}
sleep(&ticks, &tickslock);
}
+
+ backtrace();
+
release(&tickslock);
return 0;
}
+
+#ifdef LAB_PGTBL
+int
+sys_pgaccess(void)
+{
+ uint64 base, mask;
+ int len;
+
+
+ argaddr(0, &base);
+ argint(1, &len);
+ argaddr(2, &mask);
+ return pgaccess(base, len, mask);
+}
+#endif
+
uint64
sys_kill(void)
{
@@ -91,3 +109,44 @@ sys_uptime(void)
release(&tickslock);
return xticks;
}
+
+uint64
+sys_trace(void)
+{
+ argint(0, &myproc()->trace_mask);
+
+ return -(myproc()->trace_mask <= 1);
+}
+
+uint64
+sys_sysinfo(void)
+{
+ uint64 si; // user pointer to struct sysinfo
+
+ argaddr(0, &si);
+ return sys_info(si);
+}
+
+uint64
+sys_sigalarm(void)
+{
+ struct proc *p = myproc();
+ uint64 handler;
+
+ argint(0, &p->alarm_interval);
+ argaddr(1, &handler);
+ p->alarm_handler = handler;
+
+ return 0;
+}
+
+uint64 sys_sigreturn(void)
+{
+ struct proc *p = myproc();
+ // retore saved trapframe to resume
+ memmove(p->trapframe, p->atpfm, sizeof(struct trapframe));
+ p->alarm_tickspassed = 0;
+ p->alarm_caninvoke = 1;
+ // make sure return the original a0 in trapframe to pass test3
+ return p->trapframe->a0;
+}
diff --git a/kernel/trap.c b/kernel/trap.c
index 512c850..eb8009f 100644
--- a/kernel/trap.c
+++ b/kernel/trap.c
@@ -6,6 +6,12 @@
#include "proc.h"
#include "defs.h"
+/*
+ * Always remember that RISC-V disables interrupts when it starts to take a trap,
+ * so there's no need to call intr_off() at the beginning of trap handling.
+ * Reference: xv6-riscv-book 4.5
+ */
+
struct spinlock tickslock;
uint ticks;
@@ -76,9 +82,22 @@ usertrap(void)
if(killed(p))
exit(-1);
- // give up the CPU if this is a timer interrupt.
- if(which_dev == 2)
+ if(which_dev == 2){
+ // timer interrupt
+ if(p->alarm_interval > 0 && p->alarm_caninvoke){
+ // record sigalarm
+ p->alarm_tickspassed++;
+ if(p->alarm_tickspassed == p->alarm_interval){
+ // store original trapframe in p->atpfm
+ memmove(p->atpfm, p->trapframe, sizeof(struct trapframe));
+ p->alarm_tickspassed = 0;
+ p->alarm_caninvoke = 0;
+ p->trapframe->epc = p->alarm_handler;
+ }
+ }
+ // give up the CPU.
yield();
+ }
usertrapret();
}
diff --git a/kernel/vm.c b/kernel/vm.c
index 5c31e87..9c17fe7 100644
--- a/kernel/vm.c
+++ b/kernel/vm.c
@@ -449,3 +449,30 @@ copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
return -1;
}
}
+
+static void
+walkprint(pagetable_t pgtbl, int level)
+{
+ for(int i = 0; i < 512; i++){
+ pte_t pte = pgtbl[i];
+ if(pte & PTE_V){
+ for(int j = 0; j < level; j++){
+ printf(" ..");
+ }
+ printf("%d: pte %p pa %p\n", i, pte, PTE2PA(pte));
+ if((pte & (PTE_R|PTE_W|PTE_X)) == 0){
+ // this PTE points to a lower-level page table.
+ walkprint((pagetable_t)PTE2PA(pte), level+1);
+ }
+ }
+ }
+}
+
+// Print the contents of a page table
+void
+vmprint(pagetable_t pgtbl)
+{
+ printf("page table %p\n", pgtbl);
+
+ walkprint(pgtbl, 1);
+}