aboutsummaryrefslogtreecommitdiff
path: root/pk
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@s141.Millennium.Berkeley.EDU>2010-08-18 18:24:55 -0700
committerAndrew Waterman <waterman@s141.Millennium.Berkeley.EDU>2010-08-18 18:24:55 -0700
commit29cc0dc9854c66f12bd65e12516f68ccd9a741da (patch)
tree23bd8147007d3d0fbb005f578f395e71f7d7d18d /pk
parente97220c9bf519b8e0f0b131a4f868331c4d526fb (diff)
downloadpk-29cc0dc9854c66f12bd65e12516f68ccd9a741da.zip
pk-29cc0dc9854c66f12bd65e12516f68ccd9a741da.tar.gz
pk-29cc0dc9854c66f12bd65e12516f68ccd9a741da.tar.bz2
[pk,fesvr] improved proxykernel build system
Now uses a modified MCPPBS. Add --host=riscv to configure path. Front-end server now just searches PATH for riscv-pk, so just install the pk to somewhere in your path.
Diffstat (limited to 'pk')
-rw-r--r--pk/Makefile18
-rw-r--r--pk/atomic.h43
-rw-r--r--pk/boot.S23
-rw-r--r--pk/entry.S130
-rw-r--r--pk/file.c133
-rw-r--r--pk/file.h30
-rw-r--r--pk/frontend.c26
-rw-r--r--pk/frontend.h8
-rw-r--r--pk/handlers.c58
-rw-r--r--pk/pcr.h23
-rwxr-xr-xpk/pkbin0 -> 184993 bytes
-rw-r--r--pk/pk.ac0
-rw-r--r--pk/pk.c158
-rw-r--r--pk/pk.h39
-rw-r--r--pk/pk.ld186
-rw-r--r--pk/pk.mk.in20
-rw-r--r--pk/riscv-pk.c6
-rw-r--r--pk/syscall.c129
18 files changed, 1030 insertions, 0 deletions
diff --git a/pk/Makefile b/pk/Makefile
new file mode 100644
index 0000000..6a1accd
--- /dev/null
+++ b/pk/Makefile
@@ -0,0 +1,18 @@
+CFLAGS := -O2 -std=gnu99 -G 0
+CC := riscv-gcc $(CFLAGS)
+
+TARGETS := pk
+
+all: $(TARGETS)
+
+pk: boot.o entry.o pk.o syscall.o file.o frontend.o handlers.o pk.ld
+ $(CC) -o pk entry.o pk.o syscall.o file.o frontend.o handlers.o -T pk.ld
+
+%.o: %.c *.h
+ $(CC) -c $<
+
+%.o: %.S *.h
+ $(CC) -c $<
+
+clean:
+ rm -f *.o $(TARGETS)
diff --git a/pk/atomic.h b/pk/atomic.h
new file mode 100644
index 0000000..3294b6c
--- /dev/null
+++ b/pk/atomic.h
@@ -0,0 +1,43 @@
+#ifndef _RISCV_ATOMIC_H
+#define _RISCV_ATOMIC_H
+
+typedef struct { long val; } atomic_t;
+typedef struct { atomic_t lock; } spinlock_t;
+#define SPINLOCK_INIT {{0}}
+
+static inline long atomic_add(atomic_t* a, long inc)
+{
+ long old = a->val;
+ a->val += inc;
+ return old;
+}
+
+static inline long atomic_swap(atomic_t* a, long val)
+{
+ long old = a->val;
+ a->val = val;
+ return old;
+}
+
+static inline void atomic_set(atomic_t* a, long val)
+{
+ a->val = val;
+}
+
+static inline long atomic_read(atomic_t* a)
+{
+ return a->val;
+}
+
+static inline void spinlock_lock(spinlock_t* lock)
+{
+ while(atomic_read(&lock->lock))
+ while(atomic_swap(&lock->lock,-1));
+}
+
+static inline void spinlock_unlock(spinlock_t* lock)
+{
+ atomic_set(&lock->lock,0);
+}
+
+#endif
diff --git a/pk/boot.S b/pk/boot.S
new file mode 100644
index 0000000..0619671
--- /dev/null
+++ b/pk/boot.S
@@ -0,0 +1,23 @@
+#include "pcr.h"
+
+ .section boottext
+ .global __start
+ .ent __start
+__start:
+
+ # set up SR
+ li $t0, SR_S | SR_PS | SR_ET | SR_UX | SR_KX
+ mtpcr $t0, $0
+
+ # set up trap table
+ la $t0, trap_table
+ mtpcr $t0, $3
+
+ # set up stack
+ la $sp,stack_top-64
+
+ # call into kernel
+ la $t0, boot
+ jr $t0
+
+ .end __start
diff --git a/pk/entry.S b/pk/entry.S
new file mode 100644
index 0000000..db49a98
--- /dev/null
+++ b/pk/entry.S
@@ -0,0 +1,130 @@
+ .text
+ .set noat
+ .ent save_tf
+save_tf: # write the trap frame onto the stack
+ # save gprs
+ sd $1,8($k1)
+ sd $2,16($k1)
+ sd $3,24($k1)
+ sd $4,32($k1)
+ sd $5,40($k1)
+ sd $6,48($k1)
+ sd $7,56($k1)
+ sd $8,64($k1)
+ sd $9,72($k1)
+ sd $10,80($k1)
+ sd $11,88($k1)
+ sd $12,96($k1)
+ sd $13,104($k1)
+ sd $14,112($k1)
+ sd $15,120($k1)
+ sd $16,128($k1)
+ sd $17,136($k1)
+ sd $18,144($k1)
+ sd $19,152($k1)
+ sd $20,160($k1)
+ sd $21,168($k1)
+ sd $22,176($k1)
+ sd $23,184($k1)
+ sd $24,192($k1)
+ sd $25,200($k1)
+ sd $28,224($k1)
+ sd $29,232($k1)
+ sd $30,240($k1)
+ sd $k0,248($k1) # $ra is actually in $k0
+ # get sr, epc, badvaddr
+ mfpcr $t0,$0 # sr
+ sd $t0,256($k1)
+ mfpcr $t0,$1 # epc
+ sd $t0,264($k1)
+ mfpcr $t0,$2 # badvaddr
+ sd $t0,272($k1)
+ jr $ra
+ .end save_tf
+
+ .globl pop_tf
+ .ent pop_tf
+pop_tf: # write the trap frame onto the stack
+ # restore gprs
+ ld $t0,256($a0) # restore sr, which should disable interrupts
+ mtpcr $t0,$0
+
+ move $k0,$a0
+ ld $1,8($k0)
+ ld $2,16($k0)
+ ld $3,24($k0)
+ ld $4,32($k0)
+ ld $5,40($k0)
+ ld $6,48($k0)
+ ld $7,56($k0)
+ ld $8,64($k0)
+ ld $9,72($k0)
+ ld $10,80($k0)
+ ld $11,88($k0)
+ ld $12,96($k0)
+ ld $13,104($k0)
+ ld $14,112($k0)
+ ld $15,120($k0)
+ ld $16,128($k0)
+ ld $17,136($k0)
+ ld $18,144($k0)
+ ld $19,152($k0)
+ ld $20,160($k0)
+ ld $21,168($k0)
+ ld $22,176($k0)
+ ld $23,184($k0)
+ ld $24,192($k0)
+ ld $25,200($k0)
+ ld $28,224($k0)
+ ld $29,232($k0)
+ ld $30,240($k0)
+ ld $31,248($k0)
+
+ # gtfo!
+ ld $k0,264($k0)
+ mtpcr $k0,$1
+ eret
+ .end pop_tf
+
+
+
+ #define TRAP_TABLE_ENTRY(x) \
+ .align 7; \
+ move $k0,$ra; \
+ la $k1,stack_top-320; \
+ jal save_tf; \
+ move $sp,$k1; \
+ move $a0,$k1; \
+ ei; \
+ jal x; \
+ unimp
+
+ .align 12
+ .global trap_table
+ .ent trap_table
+trap_table:
+ TRAP_TABLE_ENTRY(handle_illegal_instruction)
+ TRAP_TABLE_ENTRY(handle_privileged_instruction)
+ TRAP_TABLE_ENTRY(handle_fp_disabled)
+ TRAP_TABLE_ENTRY(handle_badtrap)
+ TRAP_TABLE_ENTRY(handle_misaligned_fetch)
+ TRAP_TABLE_ENTRY(handle_misaligned_ldst)
+ TRAP_TABLE_ENTRY(handle_fault_fetch)
+ TRAP_TABLE_ENTRY(handle_fault_ldst)
+ TRAP_TABLE_ENTRY(handle_syscall)
+ TRAP_TABLE_ENTRY(handle_breakpoint)
+ TRAP_TABLE_ENTRY(handle_badtrap)
+ TRAP_TABLE_ENTRY(handle_badtrap)
+ TRAP_TABLE_ENTRY(handle_badtrap)
+ TRAP_TABLE_ENTRY(handle_badtrap)
+ TRAP_TABLE_ENTRY(handle_badtrap)
+ TRAP_TABLE_ENTRY(handle_badtrap)
+ .align 12
+ .end trap_table
+
+ .bss
+ .global stack_bot
+ .global stack_top
+stack_bot:
+ .skip 4096
+stack_top:
diff --git a/pk/file.c b/pk/file.c
new file mode 100644
index 0000000..fd063d9
--- /dev/null
+++ b/pk/file.c
@@ -0,0 +1,133 @@
+#include <string.h>
+#include <errno.h>
+#include "file.h"
+#include "pk.h"
+#include "frontend.h"
+
+#define MAX_FDS 1000
+file_t* fds[MAX_FDS];
+#define MAX_FILES 1000
+file_t files[MAX_FILES] = {[0 ... MAX_FILES-1] = {-1,{0}}};
+file_t *stdout, *stdin, *stderr;
+
+static void file_incref(file_t* f)
+{
+ atomic_add(&f->refcnt,1);
+}
+
+static void file_decref(file_t* f)
+{
+ if(atomic_add(&f->refcnt,-1) == 2)
+ {
+ if(f->kfd != -1)
+ {
+ frontend_syscall(SYS_close,f->kfd,0,0,0);
+ f->kfd = -1;
+ }
+ atomic_add(&f->refcnt,-1); // I think this could just be atomic_set(..,0)
+ }
+}
+
+static file_t* file_get_free()
+{
+ for(int i = 0; i < MAX_FILES; i++)
+ {
+ if(atomic_read(&files[i].refcnt) == 0)
+ {
+ if(atomic_add(&files[i].refcnt,1) == 0)
+ {
+ atomic_add(&files[i].refcnt,1);
+ return &files[i];
+ }
+ file_decref(&files[i]);
+ }
+ }
+ return NULL;
+}
+
+static int fd_get_free()
+{
+ for(int i = 0; i < MAX_FDS; i++)
+ if(fds[i] == NULL)
+ return i;
+ return -1;
+}
+
+int file_dup(file_t* f)
+{
+ int fd = fd_get_free();
+ if(fd == -1)
+ return -1;
+ file_incref(f);
+ fds[fd] = f;
+ return fd;
+}
+
+void file_init()
+{
+ stdin = file_get_free();
+ stdout = file_get_free();
+ stderr = file_get_free();
+ kassert(stdin && stdout && stderr);
+
+ stdin->kfd = 0;
+ stdout->kfd = 1;
+ stderr->kfd = 2;
+
+ kassert(file_dup(stdin) == 0);
+ kassert(file_dup(stdout) == 1);
+ kassert(file_dup(stderr) == 2);
+}
+
+file_t* file_get(int fd)
+{
+ return fd < 0 || fd >= MAX_FDS ? NULL : fds[fd];
+}
+
+sysret_t file_open(const char* fn, size_t len, int flags, int mode)
+{
+ file_t* f = file_get_free();
+ if(!f)
+ return (sysret_t){-1,ENOMEM};
+
+ sysret_t ret = frontend_syscall(SYS_open,(long)fn,len,flags,mode);
+ if(ret.result != -1)
+ {
+ f->kfd = ret.result;
+ ret.result = (long)f;
+ }
+ else
+ file_decref(f);
+
+ return ret;
+}
+
+int fd_close(int fd)
+{
+ file_t* f = file_get(fd);
+ if(!f)
+ return -1;
+ fds[fd] = NULL;
+ file_decref(f);
+ return 0;
+}
+
+sysret_t file_read(file_t* f, void* buf, size_t size)
+{
+ return frontend_syscall(SYS_read,f->kfd,(long)buf,size,0);
+}
+
+sysret_t file_write(file_t* f, const void* buf, size_t size)
+{
+ return frontend_syscall(SYS_write,f->kfd,(long)buf,size,0);
+}
+
+sysret_t file_stat(file_t* f, struct stat* s)
+{
+ return frontend_syscall(SYS_fstat,f->kfd,(long)s,0,0);
+}
+
+sysret_t file_lseek(file_t* f, size_t ptr, int dir)
+{
+ return frontend_syscall(SYS_fstat,f->kfd,ptr,dir,0);
+}
diff --git a/pk/file.h b/pk/file.h
new file mode 100644
index 0000000..95bf02c
--- /dev/null
+++ b/pk/file.h
@@ -0,0 +1,30 @@
+#ifndef _FILE_H
+#define _FILE_H
+
+#include <sys/stat.h>
+#include <machine/syscall.h>
+#include "atomic.h"
+
+typedef struct file
+{
+ int kfd; // file descriptor on the appserver side
+ atomic_t refcnt;
+} file_t;
+
+extern file_t *stdin, *stdout, *stderr;
+
+file_t* file_get(int fd);
+sysret_t file_open(const char* fn, size_t len, int flags, int mode);
+int file_dup(file_t*);
+
+sysret_t file_write(file_t* f, const void* buf, size_t n);
+sysret_t file_read(file_t* f, void* buf, size_t n);
+sysret_t file_stat(file_t* f, struct stat* s);
+sysret_t file_lseek(file_t* f, size_t ptr, int dir);
+int fd_close(int fd);
+
+void file_init();
+
+#define cons_write(buf,sz) file_write(stdout,buf,sz)
+
+#endif
diff --git a/pk/frontend.c b/pk/frontend.c
new file mode 100644
index 0000000..c4e799b
--- /dev/null
+++ b/pk/frontend.c
@@ -0,0 +1,26 @@
+#include "pk.h"
+#include "atomic.h"
+#include "frontend.h"
+#include "pcr.h"
+
+sysret_t frontend_syscall(long n, long a0, long a1, long a2, long a3)
+{
+ static volatile long magic_mem[8];
+
+ static spinlock_t lock = SPINLOCK_INIT;
+ spinlock_lock(&lock);
+
+ magic_mem[0] = n;
+ magic_mem[1] = a0;
+ magic_mem[2] = a1;
+ magic_mem[3] = a2;
+ magic_mem[4] = a3;
+
+ mtpcr(magic_mem,16);
+ while(mfpcr(17) == 0);
+
+ sysret_t ret = {magic_mem[0],magic_mem[1]};
+
+ spinlock_unlock(&lock);
+ return ret;
+}
diff --git a/pk/frontend.h b/pk/frontend.h
new file mode 100644
index 0000000..86a8917
--- /dev/null
+++ b/pk/frontend.h
@@ -0,0 +1,8 @@
+#ifndef _RISCV_FRONTEND_H
+#define _RISCV_FRONTEND_H
+
+#include <machine/syscall.h>
+
+sysret_t frontend_syscall(long n, long a0, long a1, long a2, long a3);
+
+#endif
diff --git a/pk/handlers.c b/pk/handlers.c
new file mode 100644
index 0000000..6cc5958
--- /dev/null
+++ b/pk/handlers.c
@@ -0,0 +1,58 @@
+#include "pcr.h"
+#include "pk.h"
+
+void handle_breakpoint(trapframe_t* tf)
+{
+ printk("Breakpoint\n");
+ dump_tf(tf);
+ tf->epc += 4;
+ pop_tf(tf);
+}
+
+void handle_fp_disabled(trapframe_t* tf)
+{
+ tf->sr |= SR_EF;
+ pop_tf(tf);
+}
+
+void handle_badtrap(trapframe_t* tf)
+{
+ dump_tf(tf);
+ panic("Bad trap vector!");
+}
+
+void handle_privileged_instruction(trapframe_t* tf)
+{
+ dump_tf(tf);
+ panic("A privileged instruction was executed!");
+}
+
+void handle_illegal_instruction(trapframe_t* tf)
+{
+ dump_tf(tf);
+ panic("An illegal instruction was executed!");
+}
+
+void handle_misaligned_fetch(trapframe_t* tf)
+{
+ dump_tf(tf);
+ panic("Misaligned instruction access!");
+}
+
+void handle_misaligned_ldst(trapframe_t* tf)
+{
+ dump_tf(tf);
+ panic("Misaligned data access!");
+}
+
+void handle_fault_fetch(trapframe_t* tf)
+{
+ dump_tf(tf);
+ panic("Faulting instruction access!");
+}
+
+void handle_fault_ldst(trapframe_t* tf)
+{
+ dump_tf(tf);
+ panic("Faulting data access!");
+}
diff --git a/pk/pcr.h b/pk/pcr.h
new file mode 100644
index 0000000..23e6185
--- /dev/null
+++ b/pk/pcr.h
@@ -0,0 +1,23 @@
+#ifndef _RISCV_COP0_H
+#define _RISCV_COP0_H
+
+#define SR_ET 0x0000000000000001
+#define SR_PS 0x0000000000000004
+#define SR_S 0x0000000000000008
+#define SR_EF 0x0000000000000010
+#define SR_UX 0x0000000000000020
+#define SR_KX 0x0000000000000040
+#define SR_IM 0x000000000000FF00
+
+#ifndef __ASSEMBLER__
+
+#define mtpcr(val,reg) ({ long __tmp = (long)(val); \
+ asm volatile ("mtpcr %0,$%1"::"r"(__tmp),"i"(reg)); })
+
+#define mfpcr(reg) ({ long __tmp; \
+ asm volatile ("mfpcr %0,$%1" : "=r"(__tmp) : "i"(reg)); \
+ __tmp; })
+
+#endif
+
+#endif
diff --git a/pk/pk b/pk/pk
new file mode 100755
index 0000000..4deb79e
--- /dev/null
+++ b/pk/pk
Binary files differ
diff --git a/pk/pk.ac b/pk/pk.ac
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pk/pk.ac
diff --git a/pk/pk.c b/pk/pk.c
new file mode 100644
index 0000000..2f0ba17
--- /dev/null
+++ b/pk/pk.c
@@ -0,0 +1,158 @@
+#include "pcr.h"
+#include "pk.h"
+#include "file.h"
+#include "frontend.h"
+#include <stdarg.h>
+#include <stdbool.h>
+#include <string.h>
+
+static void vsprintk(char* out, const char* s, va_list vl)
+{
+ bool format = false;
+ bool longarg = false;
+ for( ; *s; s++)
+ {
+ if(format)
+ {
+ switch(*s)
+ {
+ case 'l':
+ longarg = true;
+ break;
+ case 'x':
+ {
+ long n = longarg ? va_arg(vl,long) : va_arg(vl,int);
+ for(int i = 2*(longarg ? sizeof(long) : sizeof(int))-1; i >= 0; i--)
+ {
+ int d = (n >> (4*i)) & 0xF;
+ *out++ = (d < 10 ? '0'+d : 'A'+d-10);
+ }
+ longarg = false;
+ format = false;
+ break;
+ }
+ case 'd':
+ {
+ long n = longarg ? va_arg(vl,long) : va_arg(vl,int);
+ if(n < 0)
+ {
+ n = -n;
+ *out++ = '-';
+ }
+ long digits = 1;
+ for(long nn = n ; nn /= 10; digits++);
+ for(int i = digits-1; i >= 0; i--)
+ {
+ out[i] = '0' + n%10;
+ n /= 10;
+ }
+ out += digits;
+ longarg = false;
+ format = false;
+ break;
+ }
+ case 's':
+ {
+ const char* s2 = va_arg(vl,const char*);
+ while(*s2)
+ *out++ = *s2++;
+ longarg = false;
+ format = false;
+ break;
+ }
+ case 'c':
+ {
+ *out++ = (char)va_arg(vl,int);
+ longarg = false;
+ format = false;
+ break;
+ }
+ default:
+ panic("bad fmt");
+ }
+ }
+ else if(*s == '%')
+ format = true;
+ else
+ *out++ = *s;
+ }
+ *out++ = '\0';
+}
+
+void printk(const char* s, ...)
+{
+ va_list vl;
+ va_start(vl,s);
+
+ char out[1024]; // XXX
+ vsprintk(out,s,vl);
+ cons_write(out,strlen(out));
+
+ va_end(vl);
+}
+
+void sprintk(char* out, const char* s, ...)
+{
+ va_list vl;
+ va_start(vl,s);
+
+ vsprintk(out,s,vl);
+
+ va_end(vl);
+}
+
+void dump_tf(trapframe_t* tf)
+{
+ static const char* regnames[] = {
+ "z ", "at", "v0", "v1", "a0", "a1", "a2", "a3",
+ "a4", "a5", "a6", "a7", "t4", "t5", "t6", "t7",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
+ };
+
+ tf->gpr[0] = 0;
+
+ for(int i = 0; i < 32; i+=4)
+ {
+ for(int j = 0; j < 4; j++)
+ printk("%s %lx%c",regnames[i+j],tf->gpr[i+j],j < 3 ? ' ' : '\n');
+ }
+ printk("sr %lx pc %lx va %lx\n",tf->sr,tf->epc,tf->badvaddr);
+}
+
+void init_tf(trapframe_t* tf, long pc, long sp)
+{
+ memset(tf,0,sizeof(*tf));
+ tf->sr = SR_S | SR_KX | SR_UX; // SR_PS=0 (usermode); SR_ET=0
+ tf->gpr[29] = USER_MEM_SIZE-USER_MAINVARS_SIZE;
+ tf->epc = USER_START;
+}
+
+void bss_init()
+{
+ extern char edata,end;
+ memset(&edata,0,&end-&edata);
+}
+
+void mainvars_init()
+{
+ sysret_t r = frontend_syscall(SYS_getmainvars,
+ USER_MEM_SIZE-USER_MAINVARS_SIZE, USER_MAINVARS_SIZE, 0, 0);
+
+ kassert(r.result == 0);
+}
+
+void jump_usrstart()
+{
+ trapframe_t tf;
+ init_tf(&tf, USER_START, USER_MEM_SIZE-USER_MAINVARS_SIZE);
+ pop_tf(&tf);
+}
+
+void boot()
+{
+ bss_init();
+ file_init();
+ mainvars_init();
+ jump_usrstart();
+}
diff --git a/pk/pk.h b/pk/pk.h
new file mode 100644
index 0000000..dfe68f7
--- /dev/null
+++ b/pk/pk.h
@@ -0,0 +1,39 @@
+#ifndef _PK_H
+#define _PK_H
+
+typedef struct
+{
+ long gpr[32];
+ long sr;
+ long epc;
+ long badvaddr;
+} trapframe_t;
+
+#define USER_MEM_SIZE 0x70000000
+#define USER_MAINVARS_SIZE 0x1000
+#define USER_START 0x10000
+
+#define panic(s,...) do { printk(s"\n", ##__VA_ARGS__); sys_exit(-1); } while(0)
+#define kassert(cond) do { if(!(cond)) panic("assertion failed: "#cond); } while(0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void printk(const char* s, ...);
+void init_tf(trapframe_t*, long pc, long sp);
+void pop_tf(trapframe_t*);
+void dump_tf(trapframe_t*);
+
+void unhandled_trap(trapframe_t*);
+void handle_syscall(trapframe_t*);
+void handle_breakpoint(trapframe_t*);
+void boot();
+
+void sys_exit(int code) __attribute__((noreturn));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pk/pk.ld b/pk/pk.ld
new file mode 100644
index 0000000..f1ec715
--- /dev/null
+++ b/pk/pk.ld
@@ -0,0 +1,186 @@
+OUTPUT_ARCH( "mips:riscv" )
+
+ENTRY( __start )
+
+GROUP( -lc -lgloss -lgcc )
+
+
+SECTIONS
+{
+
+ /*--------------------------------------------------------------------*/
+ /* Code and read-only segment */
+ /*--------------------------------------------------------------------*/
+
+ /* Begining of code and text segment */
+ . = 0x00000000;
+ .boottext :
+ {
+ *(.boottext)
+ }
+
+ . = 0x70000000;
+ _ftext = .;
+ PROVIDE( eprol = . );
+
+ /* text: Program code section */
+ .text :
+ {
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ }
+
+ /* init: Code to execute before main (called by crt1.S) */
+ .init :
+ {
+ KEEP( *(.init) )
+ }
+
+ /* fini: Code to execute after main (called by crt1.S) */
+ .fini :
+ {
+ KEEP( *(.fini) )
+ }
+
+ /* rodata: Read-only data */
+ .rodata :
+ {
+ *(.rdata)
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r.*)
+ }
+
+ /* End of code and read-only segment */
+ PROVIDE( etext = . );
+ _etext = .;
+
+ /*--------------------------------------------------------------------*/
+ /* Global constructor/destructor segement */
+ /*--------------------------------------------------------------------*/
+ /* The .ctors/.dtors sections are special sections which contain a
+ list of constructor/destructor function pointers. crtbegin.o
+ includes code in a .init section which goes through the .ctors list
+ and calls each constuctor. crtend.o includes code in a .fini
+ section which goes through the .dtors list and calls each
+ destructor. crtbegin.o includes a special null pointer in its own
+ .ctors/.dtors sections which acts as a start indicator for those
+ lists. crtend.o also includes a special null pointer in its own
+ .ctors/.dtors sections which acts as an end indictor. The linker
+ commands below are setup so that crtbegin.o's .ctors/.dtors
+ sections are always first and crtend.o's .ctors/.dtors sections are
+ always last. This is the only way the list of functions will have
+ the begin and end indicators in the right place. */
+
+ /* ctors : Array of global constructor function pointers */
+ .ctors :
+ {
+ KEEP( *crtbegin.o(.ctors) )
+ KEEP( *(EXCLUDE_FILE(*crtend.o) .ctors) )
+ KEEP( *(SORT(.ctors.*)) )
+ KEEP( *(.ctors) )
+ }
+
+ /* dtors : Array of global destructor function pointers */
+ .dtors :
+ {
+ KEEP( *crtbegin.o(.dtors) )
+ KEEP( *(EXCLUDE_FILE(*crtend.o) .dtors) )
+ KEEP( *(SORT(.dtors.*)) )
+ KEEP( *(.dtors) )
+ }
+
+ /*--------------------------------------------------------------------*/
+ /* Other misc gcc segments (this was in idt32.ld) */
+ /*--------------------------------------------------------------------*/
+ /* I am not quite sure about these sections but it seems they are for
+ C++ exception handling. I think .jcr is for "Java Class
+ Registration" but it seems to end up in C++ binaries as well. */
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : { KEEP( *(.eh_frame) ) }
+ .gcc_except_table : { *(.gcc_except_table) }
+ .jcr : { KEEP (*(.jcr)) }
+
+ /*--------------------------------------------------------------------*/
+ /* Initialized data segment */
+ /*--------------------------------------------------------------------*/
+
+ /* Start of initialized data segment */
+ . = ALIGN(16);
+ _fdata = .;
+
+ /* data: Writable data */
+ .data :
+ {
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ }
+
+ /* lit4: Single precision floating point constants created by gas */
+ .lit4 :
+ {
+ *(.lit4)
+ }
+
+ /* lit8: Double precision floating point constants created by gas */
+ .lit8 :
+ {
+ *(.lit8)
+ }
+
+ /* End of initialized data segment */
+ . = ALIGN(4);
+ PROVIDE( edata = . );
+ _edata = .;
+
+ /*--------------------------------------------------------------------*/
+ /* Uninitialized data segment */
+ /*--------------------------------------------------------------------*/
+
+ /* Start of uninitialized data segment */
+ . = .;
+ _fbss = .;
+
+ /* sbss: Uninitialized writeable small data section */
+ . = .;
+ _sbss_start = .;
+ .sbss :
+ {
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb.*)
+ *(.scommon)
+ }
+
+ /* bss: Uninitialized writeable data section */
+ . = .;
+ _bss_start = .;
+ .bss :
+ {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b.*)
+ *(COMMON)
+ }
+
+ /* End of uninitialized data segment (used by syscalls.c for heap) */
+ PROVIDE( end = . );
+ _end = .;
+
+ /*--------------------------------------------------------------------*/
+ /* Special gcc sections (this was in idt32.ld) */
+ /*--------------------------------------------------------------------*/
+
+ .mdebug.abi32 0 : { KEEP(*(.mdebug.abi32)) }
+ .mdebug.abiN32 0 : { KEEP(*(.mdebug.abiN32)) }
+ .mdebug.abi64 0 : { KEEP(*(.mdebug.abi64)) }
+ .mdebug.abiO64 0 : { KEEP(*(.mdebug.abiO64)) }
+ .mdebug.eabi32 0 : { KEEP(*(.mdebug.eabi32)) }
+ .mdebug.eabi64 0 : { KEEP(*(.mdebug.eabi64)) }
+ .gcc_compiled_long32 0 : { KEEP(*(.gcc_compiled_long32)) }
+ .gcc_compiled_long64 0 : { KEEP(*(.gcc_compiled_long64)) }
+
+}
diff --git a/pk/pk.mk.in b/pk/pk.mk.in
new file mode 100644
index 0000000..a89ee2b
--- /dev/null
+++ b/pk/pk.mk.in
@@ -0,0 +1,20 @@
+pk_subproject_deps = \
+
+pk_hdrs = \
+ pk.h \
+
+pk_srcs = \
+ pk.c \
+ file.c \
+ syscall.c \
+ handlers.c \
+ frontend.c \
+
+pk_asm_srcs = \
+ entry.S \
+ boot.S \
+
+pk_test_srcs =
+
+pk_install_prog_srcs = \
+ riscv-pk.c \
diff --git a/pk/riscv-pk.c b/pk/riscv-pk.c
new file mode 100644
index 0000000..b25b339
--- /dev/null
+++ b/pk/riscv-pk.c
@@ -0,0 +1,6 @@
+// force the linker to pull in our __start from boot.S.
+void* dummy()
+{
+ extern void __start();
+ return &__start;
+}
diff --git a/pk/syscall.c b/pk/syscall.c
new file mode 100644
index 0000000..f14c2e4
--- /dev/null
+++ b/pk/syscall.c
@@ -0,0 +1,129 @@
+#include <machine/syscall.h>
+#include <string.h>
+#include <errno.h>
+#include "pk.h"
+#include "file.h"
+#include "frontend.h"
+
+typedef sysret_t (*syscall_t)(long,long,long,long,long);
+
+void sys_exit(int code)
+{
+ frontend_syscall(SYS_exit,code,0,0,0);
+ panic("exit didn't exit!");
+}
+
+sysret_t sys_read(int fd, char* buf, size_t n)
+{
+ sysret_t r = {-1,EBADF};
+ file_t* f = file_get(fd);
+ if(!f)
+ return r;
+
+ return file_read(f,buf,n);
+}
+
+sysret_t sys_write(int fd, const char* buf, size_t n)
+{
+ sysret_t r = {-1,EBADF};
+ file_t* f = file_get(fd);
+ if(!f)
+ return r;
+
+ return file_write(f,buf,n);
+}
+
+sysret_t sys_open(const char* name, size_t len, int flags, int mode)
+{
+ sysret_t ret = file_open(name, len, flags, mode);
+ if(ret.result == -1)
+ return ret;
+
+ if((ret.result = file_dup((file_t*)ret.result)) == -1)
+ ret.err = ENOMEM;
+
+ return ret;
+}
+
+sysret_t sys_close(int fd)
+{
+ return (sysret_t){fd_close(fd),EBADF};
+}
+
+sysret_t sys_fstat(int fd, void* st)
+{
+ sysret_t r = {-1,EBADF};
+ file_t* f = file_get(fd);
+ if(!f)
+ return r;
+
+ return file_stat(f,st);
+}
+
+sysret_t sys_lseek(int fd, size_t ptr, int dir)
+{
+ sysret_t r = {-1,EBADF};
+ file_t* f = file_get(fd);
+ if(!f)
+ return r;
+
+ return file_lseek(f,ptr,dir);
+}
+
+sysret_t sys_stat(const char* name, size_t len, void* st)
+{
+ return frontend_syscall(SYS_stat,(long)name,len,(long)st,0);
+}
+
+sysret_t sys_lstat(const char* name, size_t len, void* st)
+{
+ return frontend_syscall(SYS_lstat,(long)name,len,(long)st,0);
+}
+
+sysret_t sys_link(const char* old_name, size_t old_len,
+ const char* new_name, size_t new_len)
+{
+ return frontend_syscall(SYS_link,(long)old_name,old_len,
+ (long)new_name,new_len);
+}
+
+sysret_t sys_unlink(const char* name, size_t len)
+{
+ return frontend_syscall(SYS_unlink,(long)name,len,0,0);
+}
+
+void handle_syscall(trapframe_t* tf)
+{
+ const static void* syscall_table[] = {
+ [SYS_exit] = sys_exit,
+ [SYS_read] = sys_read,
+ [SYS_write] = sys_write,
+ [SYS_open] = sys_open,
+ [SYS_close] = sys_close,
+ [SYS_fstat] = sys_fstat,
+ [SYS_lseek] = sys_lseek,
+ [SYS_stat] = sys_stat,
+ [SYS_lstat] = sys_lstat,
+ [SYS_link] = sys_link,
+ [SYS_unlink] = sys_unlink,
+ };
+
+ syscall_t p;
+ unsigned long n = tf->gpr[2];
+ if(n >= sizeof(syscall_table)/sizeof(void*) || !syscall_table[n])
+ {
+ dump_tf(tf);
+ panic("bad syscall #%ld!",n);
+ }
+ else
+ p = (syscall_t)syscall_table[n];
+
+ sysret_t ret = p(tf->gpr[4],tf->gpr[5],tf->gpr[6],tf->gpr[7],n);
+ tf->gpr[2] = ret.result;
+ tf->gpr[3] = ret.result == -1 ? ret.err : 0;
+
+ //printk("syscall %d (%x,%x,%x,%x) from %x == %d\n",n,tf->gpr[4],tf->gpr[5],tf->gpr[6],tf->gpr[7],tf->gpr[31],tf->gpr[2]);
+
+ tf->epc += 4;
+ pop_tf(tf);
+}