make risc-v front-end syscalls asynchronous
authorAndrew Waterman <waterman@eecs.berkeley.edu>
Fri, 18 May 2012 23:53:50 +0000 (16:53 -0700)
committerAndrew Waterman <waterman@eecs.berkeley.edu>
Fri, 18 May 2012 23:53:50 +0000 (16:53 -0700)
also add DEMO mode, where the system waits for
ELFs to be sent over stdin and executes them

Makeconfig
Makelocal.template
kern/arch/riscv/console.c

index 8851c31..722382e 100644 (file)
@@ -3,6 +3,7 @@
 # To enable any of these options, add a line like the following to your Makelocal
 # CFLAGS += $(CONFIG_APPSERVER)
 CONFIG_APPSERVER:=                 -D__CONFIG_APPSERVER__
+CONFIG_DEMO_SLAVE:=                -D__CONFIG_DEMO_SLAVE__
 CONFIG_ARSC_SERVER:=               -D__CONFIG_ARSC_SERVER__
 
 # Kernel configuration parameters
index 573ff19..c44725d 100644 (file)
@@ -1,5 +1,6 @@
 # General Purpose configuration parameters
 #CFLAGS += $(CONFIG_APPSERVER)
+#CFLAGS += $(CONFIG_DEMO_SLAVE)
 
 # Kernel configuration parameters
 #KERN_CFLAGS += $(CONFIG_KFS)
index 64d63bf..747fd94 100644 (file)
 #include <pmap.h>
 #include <atomic.h>
 #include <smp.h>
-
-static volatile uint64_t magic_mem[MAX_NUM_CPUS][8] __attribute__((aligned(64)));
-
-static bool fesvr_busy()
+#include <kmalloc.h>
+#include <monitor.h>
+#include <process.h>
+
+struct magic_mem {
+       volatile uint64_t words[8];
+};
+struct fesvr_syscall {
+       struct magic_mem magic_mem;
+       STAILQ_ENTRY(fesvr_syscall) link;
+};
+STAILQ_HEAD(fesvr_syscall_tailq, fesvr_syscall);
+
+spinlock_t fesvr_lock = SPINLOCK_INITIALIZER;
+struct fesvr_syscall_tailq fesvr_queue;
+struct magic_mem fesvr_current __attribute__((aligned(64)));
+
+bool fesvr_busy()
 {
        if (mfpcr(PCR_TOHOST))
+       {
+               assert(core_id() == 0);
                return true;
+       }
        
-       volatile uint64_t* mm = magic_mem[core_id()];
+       volatile uint64_t* mm = fesvr_current.words;
        if (mfpcr(PCR_FROMHOST) && mm[6])
        {
                void (*func)(void*, uint64_t*) = (void*)(uintptr_t)mm[6];
                void* farg = (void*)(uintptr_t)mm[7];
                func(farg, (uint64_t*)mm);
        }
+       mtpcr(PCR_FROMHOST, 0);
 
        return false;
 }
 
-int fesvr_syscall(long n, long a0, long a1, long a2, long a3,
-                  void (*continuation)(void*, uint64_t*), void* arg)
+void fesvr_syscall(long n, long a0, long a1, long a2, long a3,
+                   void (*continuation)(void*, uint64_t*), void* arg)
 {
-       int ret = -1;
-       uintptr_t irq_state = disable_irq();
+       struct fesvr_syscall* mm = kmalloc(sizeof(struct fesvr_syscall), 0);
+       assert(mm);
+
+       mm->magic_mem.words[0] = n;
+       mm->magic_mem.words[1] = a0;
+       mm->magic_mem.words[2] = a1;
+       mm->magic_mem.words[3] = a2;
+       mm->magic_mem.words[4] = a3;
+       mm->magic_mem.words[6] = (uintptr_t)continuation;
+       mm->magic_mem.words[7] = (uintptr_t)arg;
+
+       spin_lock_irqsave(&fesvr_lock);
+       STAILQ_INSERT_TAIL(&fesvr_queue, mm, link);
+       spin_unlock_irqsave(&fesvr_lock);
+}
 
-       if (fesvr_busy())
-               goto out;
+long fesvr_syscall_sync(long n, long a0, long a1, long a2, long a3)
+{
+       uintptr_t irq_state = disable_irq();
+       while (fesvr_busy());
 
-       volatile uint64_t* mm = magic_mem[core_id()];
-       mm[0] = n;
-       mm[1] = a0;
-       mm[2] = a1;
-       mm[3] = a2;
-       mm[4] = a3;
-       mm[6] = (uintptr_t)continuation;
-       mm[7] = (uintptr_t)arg;
+       struct magic_mem mm __attribute__((aligned(64)));
+       mm.words[0] = n;
+       mm.words[1] = a0;
+       mm.words[2] = a1;
+       mm.words[3] = a2;
+       mm.words[4] = a3;
 
        mb();
-       mtpcr(PCR_TOHOST, PADDR(mm));
-  
-       ret = 0;
-out:
+       mtpcr(PCR_TOHOST, PADDR(&mm));
+       while (mfpcr(PCR_FROMHOST) == 0);
+       mtpcr(PCR_FROMHOST, 0);
+
        restore_irq(irq_state);
-       return ret;
+       return mm.words[0];
 }
 
-void
-fesvr_die()
+void fesvr_die()
 {
-       while (fesvr_syscall(FESVR_SYS_exit, 0, 0, 0, 0, 0, 0) < 0);
+       fesvr_syscall_sync(FESVR_SYS_exit, 0, 0, 0, 0);
 }
 
-static void cons_polled(void* null, uint64_t* magic_mem)
+// emulate keyboard input with an alarm
+void keyboard_alarm_init()
 {
-       for (int i = 0; i < (int)magic_mem[0]; i++)
+       void cons_poll(struct alarm_waiter* awaiter)
        {
-               char c = ((char*)KADDR(magic_mem[2]))[i];
-               if (c == 'G')
-                       send_kernel_message(core_id(), __run_mon, 0, 0, 0, KMSG_ROUTINE);
+               static bool cons_polling;
+               static uint64_t cons_last_polled;
+               void cont(void* null, uint64_t* magic_mem)
+               {
+                       for (int i = 0; i < (int)magic_mem[0]; i++)
+                       {
+                               char c = ((char*)KADDR(magic_mem[2]))[i];
+                               if (c == 'G')
+                                       send_kernel_message(core_id(), __run_mon, 0, 0, 0, KMSG_ROUTINE);
+                               else
+                                       send_kernel_message(core_id(), __cons_add_char, (long)&cons_buf,
+                                                           (long)c, 0, KMSG_ROUTINE);
+                       }
+                       cons_polling = false;
+                       cons_last_polled = read_tsc();
+               }
+
+#ifdef __CONFIG_DEMO_SLAVE__
+               if (!fesvr_busy() && STAILQ_EMPTY(&fesvr_queue) && hashtable_count(pid_hash) == 0)
+               {
+                       uint32_t demo_size = 0, demo_pos = 0;
+                       assert(sizeof(demo_size) == fesvr_syscall_sync(FESVR_SYS_read, 0, PADDR(&demo_size), sizeof(demo_size), 0));
+                       void* demo = kmalloc(demo_size, 0);
+                       assert(demo_size == fesvr_syscall_sync(FESVR_SYS_read, 0, PADDR(demo), demo_size, 0));
+                       struct file* f = do_file_open("/bin/demo", O_CREAT, O_WRONLY);
+                       assert(f);
+                       off_t off = 0;
+                       assert(demo_size == f->f_op->write(f, demo, demo_size, &off));
+                       kref_put(&f->f_kref);
+                       void run_demo()
+                       {
+                               char *argv[2] = {"", "demo"};
+                               mon_bin_run(2, argv, 0);
+                       }
+                       send_kernel_message(core_id(), run_demo, 0, 0, 0, KMSG_ROUTINE);
+               }
+#else
+               if (!cons_polling && read_tsc() - cons_last_polled >= 100)
+               {
+                       cons_polling = true;
+                       static char buf[64] __attribute__((aligned(64)));
+                       fesvr_syscall(FESVR_SYS_read_noncanonical, 0, PADDR(buf), sizeof(buf), 0, cont, 0);
+               }
+#endif
+
+               uint64_t usec = 100;
+               if (!fesvr_busy())
+               {
+                       spin_lock(&fesvr_lock);
+                       if (!STAILQ_EMPTY(&fesvr_queue))
+                       {
+                               usec = 10;
+                               struct fesvr_syscall* s = STAILQ_FIRST(&fesvr_queue);
+                               fesvr_current = s->magic_mem;
+                               STAILQ_REMOVE_HEAD(&fesvr_queue, link);
+                               kfree(s);
+                               mb();
+                               mtpcr(PCR_TOHOST, PADDR(&fesvr_current));
+                       }
+                       spin_unlock(&fesvr_lock);
+               }
                else
-                       send_kernel_message(core_id(), __cons_add_char, (long)&cons_buf,
-                                           (long)c, 0, KMSG_ROUTINE);
-       }
-}
+                       usec = 10;
 
-static struct alarm_waiter keyboard_waiter;
+               set_awaiter_rel(awaiter, usec);
+               set_alarm(&per_cpu_info[core_id()].tchain, awaiter);
+       }
 
-static void cons_poll(struct alarm_waiter* awaiter)
-{
-       static char buf[64] __attribute__((aligned(64)));
-       fesvr_syscall(FESVR_SYS_read_noncanonical, 0, PADDR(buf), sizeof(buf), 0, cons_polled, 0);
+       STAILQ_INIT(&fesvr_queue);
 
-       set_awaiter_rel(&keyboard_waiter, 100);
-       set_alarm(&per_cpu_info[core_id()].tchain, &keyboard_waiter);
-}
-
-// emulate keyboard input with an alarm
-void keyboard_alarm_init()
-{
-       init_awaiter(&keyboard_waiter, cons_poll);
-       set_awaiter_rel(&keyboard_waiter, 1);
-       set_alarm(&per_cpu_info[core_id()].tchain, &keyboard_waiter);
+       static struct alarm_waiter awaiter;
+       init_awaiter(&awaiter, cons_poll);
+       set_awaiter_rel(&awaiter, 1);
+       set_alarm(&per_cpu_info[core_id()].tchain, &awaiter);
 }
 
 int cons_get_any_char(void)
@@ -102,13 +181,22 @@ cons_init(void)
 void
 cputbuf(const char* str, int len)
 {
-       static char bufs[MAX_NUM_CPUS][1024] __attribute__((aligned(64)));
-       assert(len <= sizeof(bufs[0]));
+       extern int booting;
+       if (booting)
+       {
+               fesvr_syscall_sync(FESVR_SYS_write, 1, PADDR(str), len, 0);
+               return;
+       }
 
-       char* buf = bufs[core_id()];
-       while (fesvr_busy());
+       void cont(void* buf, uint64_t* mm)
+       {
+               kfree(buf);
+       }
+
+       char* buf = kmalloc(len, 0);
+       assert(buf);
        memcpy(buf, str, len);
-       while (fesvr_syscall(FESVR_SYS_write, 1, PADDR(buf), len, 0, 0, 0) < 0);
+       fesvr_syscall(FESVR_SYS_write, 1, PADDR(buf), len, 0, cont, buf);
 }
 
 // Low-level console I/O