System Calls cleanup, multiple Processes and context switch
[cortex-from-scratch] / syscall.c
index f6e1cba..2250009 100644 (file)
--- a/syscall.c
+++ b/syscall.c
  * |----------------------------|
  * | SYSTEM CALL       | #     |
  * |--------------------|-------|
- * | THEOS_getenv      |       |
- * | THEOS_killenv     |       |
- * | THEOS_setenv      |       |
- * | THEOS_newenv      |       |
- * | THEOS_cputs       |       |
- * | THEOS_omnigod     |       |
- * | THEOS_brk         |       |
- * | THEOS_time                |       |
- * | THEOS_magic       |       |
+ * | THEOS_INIT                | 1     |
+ * | THEOS_CREATE      | 2     |
+ * | THEOS_DESTROY     | 3     |
+ * | THEOS_SWITCH      | 4     |
+ * | THEOS_GETC                | 5     |
+ * | THEOS_CPUTS       | 6     |
+ * | THEOS_UPTIME      | 7     |
+ * | THEOS_OMNIGOD     | 8     |
+ * | THEOS_TIME                | 9     |
+ * | THEOS_MAGIC       | 99    |
  * |----------------------------|
  *
  * TODO: include in header enum
  * */
 
-
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
 
 #include <sys/robsys.h>
 #include <sys/mmap.h>
+#include <sys/process.h>
 
 #include <lib/stdio.h>
 #include <lib/string.h>
 #include <lib/regfunc.h>
 #include <lib/tinyprintf.h>
 
+enum {
+       THEOS_INIT = 1,
+       THEOS_CREATE,
+       THEOS_DESTROY,
+       THEOS_SWITCH,
+       THEOS_GETC,
+       THEOS_CPUTS,
+       THEOS_UPTIME
+};
 
-/* the function gets called for 
- * */
-__attribute__ ((naked))
-void * __svc_handler__(int x) {
 
-       uint8_t svc_nr;
-
-       asm volatile (
-       "tst lr, #4" "\n\t"
-       "ite eq" "\n\t"
-       "mrseq r0, msp" "\n\t"
-       "mrsne r0, psp" "\n\t"
-       "ldr r0, [r0, #24]" "\n\t"
-       "ldrb %0, [r0, #-2]" : "=r" (svc_nr) );
+static int sys_uptime() {
 
-       printf("SYSTEM CALL NR: %d", svc_nr);
+       int uptime = *RTC_CNTL;
+       return uptime;
+}
 
-       for(;;);
+/* Context switch routine, saves stack pointer of 
+ * the current process, loads the stack pointer
+ * of the next.
+ *
+ * Other registers and flags (i.e. PSR, PC are popped
+ * by exit of this system call.
+ * Precondition: Usage of PSP   */
+int sys_switch(process_t * currp, process_t * newp) {
+
+       uint32_t tmp_stackptr = 0xFFFFFFFF;
+       asm volatile("mrs %0, psp" : "=r" (tmp_stackptr));
+       currp->stackptr = tmp_stackptr; 
+
+       asm volatile("msr psp, %0" : : "r" (newp->stackptr) ); // load new pointer 
+       uint32_t chk_stackptr;
+       asm volatile("mrs %0, psp" : "=r" (chk_stackptr));
+       //asm volatile("isb");
+       //printf("OLD: %x\n", currp->stackptr);
+       //printf("NEW: %x\n", newp->stackptr);
+       //printf("CHK: %x\n", chk_stackptr);
 
-       volatile uint32_t * sp;
-       
-       asm volatile (
-       "tst lr, #4" "\n\t" 
-       "ite eq" "\n\t"
-       "mrseq %0, msp" "\n\t" 
-       "mrsne r0, psp" : "=r" (sp) );
+       return 0;
 
+}
 
-       for (int i = 0; (sp + i) < 0x20010000; i++) {
-               printf("ADDRESS: %p, VALUE: %x\n", (sp + i), *(sp + i));
-       }
+int sys_init(process_t * p) {
 
-       for (;;);       
-       //asm ("mov %0, pc" : "=r" (link_register));
-       //printf("%x\n", link_register);
-       
-       volatile uint32_t * svc_number = (uint32_t *) 0x20022222;
-       *svc_number = sp[-6];
-       //              = sp[6];
-       //uint8_t tmp  = link_register[-2];
-       printf("SVC nr: %x", *svc_number);
-       //printf("%d, %d, %d, %d, %d, %d\n", msp[6], msp[0], msp[1], msp[2], msp[3], msp[4]);
-       
-       for (;;);
-       //return NULL;  
+       asm volatile("msr psp, %0" : : "r" (p->stackptr));      
        return 0;
-
 }
 
-void syscall(unsigned int * args) {
+static int sys_stub() {
 
-       uint32_t svc_number = 99;
-       printf("SYSCALL NR: %x", svc_number);
-
-       for(;;);
-       /* switch(SYSCALL_NO) {
-               case THEOS_cputs:
-                       kernel_cputs(a1, a2);
-                       break;
-               default:
-                       for (;;);
-       } */
+       return 0;
 
 }
 
-void syscall_init() {
-
-
-       /* SVC is located at position 11 in the interrupt vector table  */
-//     extern void * _syscall;
-       extern void * hardfault;
+/*
+ * This is a so-called first interrupt handler
+ * The naked attribute makes sure the compiler doesn't
+ * places registers on the stack */
 
-       ivt_set_gate(11, __svc_handler__, 0);
+/* 
+ * SVC is similar to an exception or interrupt
+ * A stack frame is pushed on entry and popped
+ * on exit BY PROCESSOR. Please see in-function command */
 
+__attribute__ ((naked))
+void * _svc_handler(void) {
 
-}
+       uint32_t * callee_sp;
 
-static void kernel_cputs(char * s, size_t l) {
+       /* Test whether system call was invoked from supervisor (use MSP) or
+        * user (use PSP) mode */
+       asm volatile (
+       "tst lr, #4" "\n\t"
+       "ite eq" "\n\t"
+       "mrseq %0, msp" "\n\t"
+       "mrsne %0, psp" "\n\t"
+       "push {lr}" "\n\t"
+       "push {r4-r11}" : "=r" (callee_sp));
+
+       /* An exception (or interrupt) before entering this handler
+        * places the following on the stack 
+        * 
+        * R0 <- args[0]
+        * R1 <- args[1]
+        * R2 
+        * R3
+        * R12
+        * LR <- Not a real LR, A certain 'mask'
+        * PC <- placed at callee_sp[6], see description below
+        * PSR <- Status of processor before call
+        *
+        * PC contains the return address that will continue after this SVC handler
+        * is finised. The previous address (the svc # call) is at PC - 2, the
+        * first byte contains the svc number.
+        * */
+
+       uint8_t svc_nr = ((char *) callee_sp[6])[-2];
+       int ret = -1;
+
+       switch(svc_nr) {
+               case THEOS_INIT:
+                       sys_init((process_t *) callee_sp[0]);
+                       asm volatile (
+                               "ldr r0, =0xFFFFFFFD" "\n\t"
+                               "mov lr, r0" "\n\t"
+                               "bx lr");
+                       break;
+               case THEOS_SWITCH:
+                       sys_switch((process_t *) callee_sp[0], (process_t *) callee_sp[1]);
+                       //asm volatile (
+                       //      "ldr r0, =0xFFFFFFFD" "\n\t"
+                       //      "mov lr, r0" "\n\t"
+                       //      "bx lr");
+                       
+                       break;
+               case THEOS_CPUTS:  
+                       break;
+               case THEOS_GETC:
+                       break;
+               case THEOS_UPTIME:
+                       ret = sys_uptime();
+                       break;
+               default:
+                       break;
+       }
 
-       // TODO
-}
+       //printf("SYSTEM CALL NR: %d\n", svc_nr);
+       /* Check arguments, placed in r0, r1, r2 
+        * (can get more if you save the stack) */
+       //uint32_t arg1 = callee_sp[0];
+       //uint32_t arg2 = callee_sp[1];
+       //uint32_t arg3 = callee_sp[2];
+       //printf("ARGUMENTS: %x, %x, %x\n", arg1, arg2, arg3);
 
+       /* Return value in r0 for callee */
+       callee_sp[0] = ret;
 
-void kernel_omnigod() {
+       asm volatile ("pop {r4-r11}");
+       /* exception return, 0xFFFFFFFX (<-- last value is flag
+        * and gives the processor information to return to what */
+       asm volatile ("pop {lr}"); 
+       asm volatile ("bx lr");
 
-       /* */
 
 }
 
+void syscall_init() {
+       /* SVC is located at position 11 in the interrupt vector table  */
+       ivt_set_gate(11, _svc_handler, 0);
+}