summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/boot/entry.S2
-rw-r--r--src/kernel/fdt.cc22
-rw-r--r--src/kernel/mm/vm.cc27
-rw-r--r--src/kernel/proc/proc.cc293
-rw-r--r--src/kernel/spinlock.cc107
-rw-r--r--src/kernel/syscall.cc133
-rw-r--r--src/kernel/trap/handler.cc35
-rw-r--r--src/lib/string.cc71
8 files changed, 564 insertions, 126 deletions
diff --git a/src/boot/entry.S b/src/boot/entry.S
index a3c212a..924d7d6 100644
--- a/src/boot/entry.S
+++ b/src/boot/entry.S
@@ -5,6 +5,8 @@ _start:
la t0, g_dtb_addr
sd a1, 0(t0)
+ mv tp, a0
+
la sp, stack_top
call kernel_main
diff --git a/src/kernel/fdt.cc b/src/kernel/fdt.cc
index 93922a7..1863086 100644
--- a/src/kernel/fdt.cc
+++ b/src/kernel/fdt.cc
@@ -1,6 +1,7 @@
#include "common/types.h"
#include "drivers/uart.h"
#include "kernel/config.h"
+#include "lib/string.h"
inline uint32_t bswap(uint32_t x)
{
@@ -29,27 +30,6 @@ struct fdt_header
#define FDT_NOP 4
#define FDT_END 9
-int strcmp(const char* s1, const char* s2)
-{
- while (*s1 && (*s1 == *s2))
- {
- s1++;
- s2++;
- }
- return *(const unsigned char*)s1 - *(const unsigned char*)s2;
-}
-
-int memcmp(const void *ptr1, const void *ptr2, uint32 num)
-{
- const unsigned char *p1 = (const unsigned char *)ptr1;
- const unsigned char *p2 = (const unsigned char *)ptr2;
- for (uint32 i = 0; i < num; i++)
- {
- if (p1[i] != p2[i])
- return p1[i] - p2[i];
- }
- return 0;
-}
void fdt_init(uint64 dtb)
{
diff --git a/src/kernel/mm/vm.cc b/src/kernel/mm/vm.cc
index a38ee84..735a486 100644
--- a/src/kernel/mm/vm.cc
+++ b/src/kernel/mm/vm.cc
@@ -4,33 +4,8 @@
#include "drivers/uart.h"
#include "common/types.h"
#include "kernel/config.h"
+#include "lib/string.h"
-void *memset(void *dst, int c, uint n)
-{
- char *cdst = (char *)dst;
- for (uint i = 0; i < n; i++)
- cdst[i] = c;
- return dst;
-}
-
-void *memmove(void *dst, const void *src, uint n)
-{
- const char *s = (const char *)src;
- char *d = (char *)dst;
- if (s < d && s + n > d)
- {
- s += n;
- d += n;
- while (n-- > 0)
- *--d = *--s;
- }
- else
- {
- while (n-- > 0)
- *d++ = *s++;
- }
- return dst;
-}
extern char text_start[];
extern char text_end[];
diff --git a/src/kernel/proc/proc.cc b/src/kernel/proc/proc.cc
index 1240bee..15a28b4 100644
--- a/src/kernel/proc/proc.cc
+++ b/src/kernel/proc/proc.cc
@@ -6,6 +6,8 @@
#include "common/types.h"
#include "kernel/riscv.h"
#include "kernel/config.h"
+#include "kernel/spinlock.h"
+#include "lib/string.h"
#define NPROC 10
@@ -13,18 +15,14 @@ extern "C" void swtch(struct Context *old_ctx, struct Context *new_ctx);
extern char uservec[];
extern "C" void userret(uint64, uint64);
extern char trampoline[];
-extern void *memset(void *dst, int c, uint n);
struct Proc procs[NPROC];
struct Context main_context;
struct Proc *current_proc = nullptr;
+struct spinlock proc_lock;
+
+int nextpid = 1;
-void str_copy(char *dst, const char *src)
-{
- while (*src)
- *dst++ = *src++;
- *dst = 0;
-}
uchar initcode[] = {
0x13, 0x05, 0x50, 0x05, // li a0, 85 ('U')
@@ -35,6 +33,7 @@ uchar initcode[] = {
struct Proc *myproc()
{
+ // 简化处理
return current_proc;
}
@@ -42,10 +41,10 @@ void usertrapret()
{
struct Proc *p = myproc();
- asm volatile("csrc sstatus, %0" : : "r"(SSTATUS_SIE));
+ intr_off();
uint64 trampoline_uservec = TRAMPOLINE + (uservec - trampoline);
- asm volatile("csrw stvec, %0" : : "r"(trampoline_uservec));
+ w_stvec(trampoline_uservec);
p->tf->kernel_satp = r_satp();
p->tf->kernel_sp = (uint64)p->kstack + PGSIZE;
@@ -68,16 +67,120 @@ void usertrapret()
void forkret()
{
//....
+ Spinlock::release(&proc_lock);
+ Drivers::uart_puts("[Proc] forkret: jumping to user.\n");
+ usertrapret();
+}
+static Proc *allocproc()
+{
+ struct Proc* p;
+ Spinlock::acquire(&proc_lock);
+ for (p = procs; p < &procs[NPROC]; p++)
+ {
+ if (p->state == UNUSED)
+ {
+ goto found;
+ }
+ }
- usertrapret();
+ Spinlock::release(&proc_lock);
+ return 0;
+
+found:
+ p->state = USED;
+ p->pid = nextpid++;
+
+ if ((p->tf = (struct Trapframe *)PMM::alloc_page()) == 0)
+ {
+ p->state = UNUSED;
+ Spinlock::release(&proc_lock);
+ return 0;
+ }
+ if ((p->kstack = PMM::alloc_page()) == 0)
+ {
+ PMM::free_page(p->tf);
+ p->state = UNUSED;
+ Spinlock::release(&proc_lock);
+ return 0;
+ }
+ memset(p->kstack, 0, PGSIZE);
+
+ memset(&p->context, 0, sizeof(p->context));
+ p->context.ra = (uint64)forkret;
+ p->context.sp = (uint64)p->kstack + PGSIZE;
+
+ Spinlock::release(&proc_lock);
+ return p;
+}
+
+static void freeproc(struct Proc *p)
+{
+ if (p->tf)
+ PMM::free_page(p->tf);
+ p->tf = 0;
+
+ if (p->kstack)
+ PMM::free_page(p->kstack);
+ p->kstack = 0;
+
+ if (p->pagetable)
+ VM::uvmfree(p->pagetable, p->sz);
+ p->pagetable = 0;
+
+ p->sz = 0;
+ p->pid = 0;
+ p->parent = 0;
+ p->name[0] = 0;
+ p->chan = 0;
+ p->state = UNUSED;
+}
+
+int fork()
+{
+ int pid;
+ struct Proc *np;
+ struct Proc *p = myproc();
+
+ if ((np = allocproc()) == 0)
+ {
+ return -1;
+ }
+
+ np->pagetable = VM::uvmcreate();
+ if (VM::uvmcopy(p->pagetable, np->pagetable, p->sz) < 0)
+ {
+ PMM::free_page(np->kstack);
+ PMM::free_page(np->tf);
+ Spinlock::acquire(&proc_lock);
+ np->state = UNUSED;
+ Spinlock::release(&proc_lock);
+ return -1;
+ }
+ np->sz = p->sz;
+
+ *(np->tf) = *(p->tf);
+
+ np->tf->a0 = 0;
+
+ strcpy(np->name, p->name);
+ np->parent = p;
+
+ Spinlock::acquire(&proc_lock);
+ np->state = RUNNABLE;
+ pid = np->pid;
+ Spinlock::release(&proc_lock);
+
+ return pid;
}
namespace ProcManager
{
void init()
{
+ Spinlock::init(&proc_lock, "proc");
+
for (int i = 0; i < NPROC; i++)
{
procs[i].state = UNUSED;
@@ -116,7 +219,7 @@ namespace ProcManager
p->context.sp = (uint64)p->kstack + 4096;
p->state = RUNNABLE;
- str_copy(p->name, name);
+ strcpy(p->name, name);
Drivers::uart_puts("[Proc] Created thread: ");
Drivers::uart_puts(name);
@@ -126,11 +229,13 @@ namespace ProcManager
void yield()
{
struct Proc *p = myproc();
+ Spinlock::acquire(&proc_lock);
if (p && p->state == RUNNING)
{
p->state = RUNNABLE;
swtch(&p->context, &main_context);
}
+ Spinlock::release(&proc_lock);
}
void scheduler()
@@ -140,18 +245,15 @@ namespace ProcManager
for (;;)
{
- int nothing_found = 1;
-
intr_on();
+ Spinlock::acquire(&proc_lock);
+
for (p = procs; p < &procs[NPROC]; p++)
{
if (p->state == RUNNABLE)
{
- nothing_found = 0;
-
p->state = RUNNING;
-
current_proc = p;
swtch(&main_context, &p->context);
@@ -159,80 +261,147 @@ namespace ProcManager
current_proc = nullptr;
}
}
- if (nothing_found)
- {
- asm volatile("wfi");
- }
+ Spinlock::release(&proc_lock);
}
}
void user_init()
{
- struct Proc *p = nullptr;
- for(int i = 0; i < NPROC; ++i)
- {
- if(procs[i].state == UNUSED)
- {
- p = &procs[i];
- p->pid = i + 1;
- break;
- }
- }
+ struct Proc *p;
+ p = allocproc();
if (!p)
{
- Drivers::uart_puts("user_init: no free procs\n");
+ Drivers::uart_puts("user_init: failed\n");
return;
}
- p->kstack = PMM::alloc_page();
- if (p->kstack == 0)
+ p->pagetable = VM::uvmcreate();
+ VM::uvminit(p->pagetable, initcode, sizeof(initcode));
+ p->sz = PGSIZE;
+
+ if (VM::mappages(p->pagetable, TRAPFRAME, PGSIZE,
+ (uint64)p->tf, PTE_R | PTE_W) < 0)
{
- Drivers::uart_puts("user_init: kstack alloc failed\n");
+ Drivers::uart_puts("user_init: map trapframe failed\n");
return;
}
- p->tf = (struct Trapframe*)PMM::alloc_page();
+
+ p->tf->epc = 0;
+ p->tf->sp = PGSIZE;
- if (p->tf == 0)
+ strcpy(p->name, "initcode");
+
+
+ Spinlock::acquire(&proc_lock);
+ p->state = RUNNABLE;
+ Spinlock::release(&proc_lock);
+
+ Drivers::uart_puts("[Proc] user_init success. PID: 1\n");
+ }
+
+ void sleep(void *chan, struct spinlock *lk)
+ {
+ struct Proc *p = myproc();
+ if(lk != &proc_lock)
{
- Drivers::uart_puts("user_init: tf alloc failed\n");
- return;
+ Drivers::uart_puts("sleep: lock mismatch\n");
+ while (1)
+ ;
}
- memset(p->tf, 0, PGSIZE);
+ p->chan = chan;
+ p->state = SLEEPING;
- p->pagetable = VM::uvmcreate();
+ swtch(&p->context, &main_context);
- // if (VM::mappages(p->pagetable, TRAMPOLINE, PGSIZE,
- // (uint64)trampoline, PTE_R | PTE_X) < 0)
- // {
- // Drivers::uart_puts("user_init: map trampoline failed\n");
- // return;
- // }
+ p->chan = 0;
+ }
- if (VM::mappages(p->pagetable, TRAPFRAME, PGSIZE,
- (uint64)p->tf, PTE_R | PTE_W) < 0)
+ void wakeup(void *chan)
+ {
+ for(struct Proc *p = procs; p < &procs[NPROC]; p++)
{
- Drivers::uart_puts("user_init: map trapframe failed\n");
- return;
+ if (p->state == SLEEPING && p->chan == chan)
+ {
+ p->state = RUNNABLE;
+ }
}
+ }
- VM::uvminit(p->pagetable, initcode, sizeof(initcode));
- p->sz = PGSIZE;
+ void exit(int status)
+ {
+ struct Proc *p = myproc();
+ struct Proc *initproc = &procs[0];
- p->tf->epc = 0;
- p->tf->sp = PGSIZE;
+ if (p == initproc)
+ {
+ Drivers::uart_puts("init exiting!\n");
+ while (1)
+ ;
+ }
- memset(&p->context, 0, sizeof(p->context));
- p->context.ra = (uint64)forkret;
- p->context.sp = (uint64)p->kstack + PGSIZE;
+ Spinlock::acquire(&proc_lock);
- p->state = RUNNABLE;
+ for (struct Proc *pp = procs; pp < &procs[NPROC]; pp++)
+ {
+ if (pp->parent == p)
+ {
+ pp->parent = initproc;
+ wakeup(initproc);
+ }
+ }
- const char *name = "initcode";
- for (int i = 0; name[i] && i < 15; i++)
- p->name[i] = name[i];
+ wakeup(p->parent);
- Drivers::uart_puts("[Proc] user_init success. PID: 1\n");
+ p->xstate = status;
+ p->state = ZOMBIE;
+
+ swtch(&p->context, &main_context);
+
+ while(1);
+ }
+
+ int wait(uint64 addr)
+ {
+ struct Proc* np;
+ int havekids, pid;
+ struct Proc *p = myproc();
+
+ Spinlock::acquire(&proc_lock);
+
+ for(;;)
+ {
+ havekids = 0;
+ for (np = procs; np < &procs[NPROC]; np++)
+ {
+ if (np->parent == p)
+ {
+ havekids = 1;
+ if (np->state == ZOMBIE)
+ {
+ // Found one
+ pid = np->pid;
+ if (addr != 0)
+ {
+ // copyout(p->pagetable, addr, (char*)&np->xstate, sizeof(np->xstate));
+ // 暂时不做 copyout
+ }
+ freeproc(np);
+ Spinlock::release(&proc_lock);
+ return pid;
+ }
+ }
+ }
+ if (!havekids || p->state == ZOMBIE)
+ {
+ Spinlock::release(&proc_lock);
+ return -1;
+ }
+ sleep(p, &proc_lock);
+ }
}
+
+
+
} \ No newline at end of file
diff --git a/src/kernel/spinlock.cc b/src/kernel/spinlock.cc
new file mode 100644
index 0000000..210e0b9
--- /dev/null
+++ b/src/kernel/spinlock.cc
@@ -0,0 +1,107 @@
+#include "kernel/spinlock.h"
+#include "kernel/riscv.h"
+#include "kernel/proc.h"
+#include "drivers/uart.h"
+#include "common/types.h"
+
+#define NCPU 8
+
+namespace Spinlock
+{
+ int g_noff[NCPU];
+
+ int g_intena[NCPU];
+
+ int cpuid()
+ {
+ return r_tp();
+ }
+
+ void init(struct spinlock *lk, char* name)
+ {
+ lk->name = name;
+ lk->locked = 0;
+ lk->cpu_id = -1;
+ }
+
+ void push_off()
+ {
+ int old = intr_get();
+ intr_off();
+
+ int id = cpuid();
+ if (g_noff[id] == 0)
+ {
+ g_intena[id] = old;
+ }
+ g_noff[id] += 1;
+ }
+
+ void pop_off()
+ {
+ int id = cpuid();
+ if (intr_get())
+ Drivers::uart_puts("pop_off - interruptible\n");
+
+ if (g_noff[id] < 1)
+ Drivers::uart_puts("pop_off - count error\n");
+
+ g_noff[id] -= 1;
+
+ if (g_noff[id] == 0 && g_intena[id])
+ {
+ intr_on();
+ }
+ }
+
+ int holding(struct spinlock *lk)
+ {
+ int r;
+ push_off();
+ r = (lk->locked && lk->cpu_id == cpuid());
+ pop_off();
+ return r;
+ }
+
+ void acquire(struct spinlock *lk)
+ {
+ push_off();
+
+ if(holding(lk))
+ {
+ Drivers::uart_puts("acquire: panic - recursive lock ");
+ Drivers::uart_puts(lk->name);
+ Drivers::uart_puts("\n");
+ while (1)
+ ;
+ }
+
+ while (__sync_lock_test_and_set(&lk->locked, 1) != 0)
+ {
+ // 自旋等待
+ }
+
+ __sync_synchronize();
+
+ lk->cpu_id = cpuid();
+ }
+
+ void release(struct spinlock *lk)
+ {
+ if (!holding(lk))
+ {
+ Drivers::uart_puts("release: panic - not holding\n");
+ while (1)
+ ;
+ }
+
+ lk->cpu_id = -1;
+
+ __sync_synchronize();
+
+ __sync_lock_release(&lk->locked);
+
+ pop_off();
+ }
+
+} // namespace Spinlock
diff --git a/src/kernel/syscall.cc b/src/kernel/syscall.cc
new file mode 100644
index 0000000..97b283b
--- /dev/null
+++ b/src/kernel/syscall.cc
@@ -0,0 +1,133 @@
+#include "kernel/syscall.h"
+#include "common/types.h"
+#include "kernel/proc.h"
+#include "kernel/riscv.h"
+#include "drivers/uart.h"
+#include "kernel/timer.h"
+
+extern int fork();
+
+namespace ProcManager
+{
+ void exit(int status);
+ int wait(uint64 addr);
+}
+
+uint64 argraw(int n)
+{
+ struct Proc *p = myproc();
+ switch (n)
+ {
+ case 0:
+ return p->tf->a0;
+ case 1:
+ return p->tf->a1;
+ case 2:
+ return p->tf->a2;
+ case 3:
+ return p->tf->a3;
+ case 4:
+ return p->tf->a4;
+ case 5:
+ return p->tf->a5;
+ }
+ return -1;
+}
+
+int argint(int n, int *ip)
+{
+ *ip = argraw(n);
+ return 0;
+}
+
+uint64 sys_exit()
+{
+ int n;
+ if (argint(0, &n) < 0)
+ return -1;
+ ProcManager::exit(n);
+ return 0;
+}
+
+uint64 sys_fork()
+{
+ return fork();
+}
+
+uint64 sys_wait()
+{
+ uint64 p;
+ p = argraw(0);
+ return ProcManager::wait(p);
+}
+
+uint64 sys_getpid()
+{
+ return myproc()->pid;
+}
+
+uint64 sys_putc()
+{
+ char c = (char)argraw(0);
+ Drivers::uart_putc(c);
+ return 0;
+}
+
+uint64 sys_write()
+{
+ // 简单模拟
+ int fd;
+ uint64 p;
+ int n;
+
+ if (argint(0, &fd) < 0 || argint(2, &n) < 0)
+ return -1;
+ p = argraw(1); // buffer address
+
+ if (fd == 1)
+ {
+ struct Proc *proc = myproc();
+ // 这里应该有 vm copyin 检查,暂时直接访问物理内存
+ (void)p; // 消除 unused variable 警告
+
+ return n;
+ }
+ return -1;
+}
+
+void syscall()
+{
+ struct Proc *p = myproc();
+ int num = p->tf->a7;
+ uint64 ret = -1;
+
+ switch (num)
+ {
+ case SYS_putc:
+ ret = sys_putc();
+ break;
+ case SYS_fork:
+ ret = sys_fork();
+ break;
+ case SYS_exit:
+ ret = sys_exit();
+ break;
+ case SYS_wait:
+ ret = sys_wait();
+ break;
+ case SYS_getpid:
+ ret = sys_getpid();
+ break;
+ case SYS_write:
+ ret = sys_write();
+ break;
+ default:
+ Drivers::uart_puts("Unknown Syscall ID: ");
+ Drivers::print_hex(num);
+ Drivers::uart_puts("\n");
+ ret = -1;
+ break;
+ }
+
+ p->tf->a0 = ret;
+} \ No newline at end of file
diff --git a/src/kernel/trap/handler.cc b/src/kernel/trap/handler.cc
index 4bb8c06..14ef4c5 100644
--- a/src/kernel/trap/handler.cc
+++ b/src/kernel/trap/handler.cc
@@ -3,8 +3,11 @@
#include "drivers/uart.h"
#include "kernel/proc.h"
#include "kernel/timer.h"
+#include "kernel/syscall.h"
+#include "kernel/riscv.h"
extern void usertrapret();
+extern void forkret();
void panic(const char *s)
{
@@ -71,10 +74,10 @@ namespace Trap
switch (scause)
{
case 8:
- Drivers::uart_puts("[Syscall] ecall for User Mode\n");
- tf->epc += 4;
+ Drivers::uart_puts("[Syscall] ecall from Kernel Mode? Panic.\n");
+ panic("Kernel Ecall");
break;
-
+
case 12:
case 13:
case 15:
@@ -136,9 +139,12 @@ extern "C" void usertrap()
struct Proc *p = myproc();
extern struct Proc procs[];
- for(int i = 0; i < 10; ++i)
- if(procs[i].state == RUNNING)
- p = &procs[i];
+ if (!p)
+ {
+ for (int i = 0; i < 10; ++i)
+ if (procs[i].state == RUNNING)
+ p = &procs[i];
+ }
uint64 sepc;
asm volatile("csrr %0, sepc" : "=r"(sepc));
@@ -146,31 +152,26 @@ extern "C" void usertrap()
if(scause == 8)
{
+ intr_on();
p->tf->epc += 4;
- uint64 syscall_num = p->tf->a7;
+ syscall();
- if (syscall_num == 1)
- {
- char c = (char)p->tf->a0;
- Drivers::uart_putc(c);
- }
- else
- {
- Drivers::uart_puts("Unknown Syscall\n");
- }
+ intr_off();
}
else if ((scause & (1L << 63)) && (scause & 0xF) == 5)
{
+ Drivers::uart_puts("\nTick\n");
Timer::set_next_trigger();
ProcManager::yield();
}
else
{
Drivers::uart_puts("Unexpected User Trap!\n");
+ Drivers::print_hex(scause);
while (1)
;
}
- forkret();
+ usertrapret();
} \ No newline at end of file
diff --git a/src/lib/string.cc b/src/lib/string.cc
new file mode 100644
index 0000000..bbd079d
--- /dev/null
+++ b/src/lib/string.cc
@@ -0,0 +1,71 @@
+#include "lib/string.h"
+
+void *memset(void *dst, int c, uint n)
+{
+ char *cdst = (char *)dst;
+ for (uint i = 0; i < n; i++)
+ cdst[i] = c;
+ return dst;
+}
+
+int memcmp(const void *v1, const void *v2, uint n)
+{
+ const uchar *s1 = (const uchar *)v1;
+ const uchar *s2 = (const uchar *)v2;
+ while (n-- > 0)
+ {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ s1++, s2++;
+ }
+ return 0;
+}
+
+void *memmove(void *dst, const void *src, uint n)
+{
+ const char *s = (const char *)src;
+ char *d = (char *)dst;
+ if (s < d && s + n > d)
+ {
+ s += n;
+ d += n;
+ while (n-- > 0)
+ *--d = *--s;
+ }
+ else
+ {
+ while (n-- > 0)
+ *d++ = *s++;
+ }
+ return dst;
+}
+
+void *memcpy(void *dst, const void *src, uint n)
+{
+ return memmove(dst, src, n);
+}
+
+void strcpy(char *dst, const char *src)
+{
+ while (*src)
+ *dst++ = *src++;
+ *dst = 0;
+}
+
+int strlen(const char *s)
+{
+ int n = 0;
+ while (s[n])
+ n++;
+ return n;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+ while (*s1 && (*s1 == *s2))
+ {
+ s1++;
+ s2++;
+ }
+ return *(const unsigned char *)s1 - *(const unsigned char *)s2;
+}