System Calls cleanup, multiple Processes and context switch
[cortex-from-scratch] / syscall.c
1 /* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL
2  * 
3  * $LOG$
4  * 2019/9/20 - ROBIN KRENS      
5  * Initial version 
6  * 
7  * $DESCRIPTION$
8  * 
9  * |----------------------------|
10  * | SYSTEM CALL        | #     |
11  * |--------------------|-------|
12  * | THEOS_INIT         | 1     |
13  * | THEOS_CREATE       | 2     |
14  * | THEOS_DESTROY      | 3     |
15  * | THEOS_SWITCH       | 4     |
16  * | THEOS_GETC         | 5     |
17  * | THEOS_CPUTS        | 6     |
18  * | THEOS_UPTIME       | 7     |
19  * | THEOS_OMNIGOD      | 8     |
20  * | THEOS_TIME         | 9     |
21  * | THEOS_MAGIC        | 99    |
22  * |----------------------------|
23  *
24  * TODO: include in header enum
25  * */
26
27 #include <stdbool.h>
28 #include <stddef.h>
29 #include <stdint.h>
30
31 #include <sys/robsys.h>
32 #include <sys/mmap.h>
33 #include <sys/process.h>
34
35 #include <lib/stdio.h>
36 #include <lib/string.h>
37 #include <lib/regfunc.h>
38 #include <lib/tinyprintf.h>
39
40 enum {
41         THEOS_INIT = 1,
42         THEOS_CREATE,
43         THEOS_DESTROY,
44         THEOS_SWITCH,
45         THEOS_GETC,
46         THEOS_CPUTS,
47         THEOS_UPTIME
48 };
49
50
51 static int sys_uptime() {
52
53         int uptime = *RTC_CNTL;
54         return uptime;
55 }
56
57 /* Context switch routine, saves stack pointer of 
58  * the current process, loads the stack pointer
59  * of the next.
60  *
61  * Other registers and flags (i.e. PSR, PC are popped
62  * by exit of this system call.
63  * Precondition: Usage of PSP   */
64 int sys_switch(process_t * currp, process_t * newp) {
65
66         uint32_t tmp_stackptr = 0xFFFFFFFF;
67         asm volatile("mrs %0, psp" : "=r" (tmp_stackptr));
68         currp->stackptr = tmp_stackptr; 
69
70         asm volatile("msr psp, %0" : : "r" (newp->stackptr) ); // load new pointer 
71         uint32_t chk_stackptr;
72         asm volatile("mrs %0, psp" : "=r" (chk_stackptr));
73         //asm volatile("isb");
74         //printf("OLD: %x\n", currp->stackptr);
75         //printf("NEW: %x\n", newp->stackptr);
76         //printf("CHK: %x\n", chk_stackptr);
77
78         return 0;
79
80 }
81
82 int sys_init(process_t * p) {
83
84         asm volatile("msr psp, %0" : : "r" (p->stackptr));      
85         return 0;
86 }
87
88 static int sys_stub() {
89
90         return 0;
91
92 }
93
94 /*
95  * This is a so-called first interrupt handler
96  * The naked attribute makes sure the compiler doesn't
97  * places registers on the stack */
98
99 /* 
100  * SVC is similar to an exception or interrupt
101  * A stack frame is pushed on entry and popped
102  * on exit BY PROCESSOR. Please see in-function command */
103
104 __attribute__ ((naked))
105 void * _svc_handler(void) {
106
107         uint32_t * callee_sp;
108
109         /* Test whether system call was invoked from supervisor (use MSP) or
110          * user (use PSP) mode */
111         asm volatile (
112         "tst lr, #4" "\n\t"
113         "ite eq" "\n\t"
114         "mrseq %0, msp" "\n\t"
115         "mrsne %0, psp" "\n\t"
116         "push {lr}" "\n\t"
117         "push {r4-r11}" : "=r" (callee_sp));
118
119         /* An exception (or interrupt) before entering this handler
120          * places the following on the stack 
121          * 
122          * R0 <- args[0]
123          * R1 <- args[1]
124          * R2 
125          * R3
126          * R12
127          * LR <- Not a real LR, A certain 'mask'
128          * PC <- placed at callee_sp[6], see description below
129          * PSR <- Status of processor before call
130          *
131          * PC contains the return address that will continue after this SVC handler
132          * is finised. The previous address (the svc # call) is at PC - 2, the
133          * first byte contains the svc number.
134          * */
135
136         uint8_t svc_nr = ((char *) callee_sp[6])[-2];
137         int ret = -1;
138
139         switch(svc_nr) {
140                 case THEOS_INIT:
141                         sys_init((process_t *) callee_sp[0]);
142                         asm volatile (
143                                 "ldr r0, =0xFFFFFFFD" "\n\t"
144                                 "mov lr, r0" "\n\t"
145                                 "bx lr");
146                         break;
147                 case THEOS_SWITCH:
148                         sys_switch((process_t *) callee_sp[0], (process_t *) callee_sp[1]);
149                         //asm volatile (
150                         //      "ldr r0, =0xFFFFFFFD" "\n\t"
151                         //      "mov lr, r0" "\n\t"
152                         //      "bx lr");
153                         
154                         break;
155                 case THEOS_CPUTS:  
156                         break;
157                 case THEOS_GETC:
158                         break;
159                 case THEOS_UPTIME:
160                         ret = sys_uptime();
161                         break;
162                 default:
163                         break;
164         }
165
166         //printf("SYSTEM CALL NR: %d\n", svc_nr);
167         /* Check arguments, placed in r0, r1, r2 
168          * (can get more if you save the stack) */
169         //uint32_t arg1 = callee_sp[0];
170         //uint32_t arg2 = callee_sp[1];
171         //uint32_t arg3 = callee_sp[2];
172         //printf("ARGUMENTS: %x, %x, %x\n", arg1, arg2, arg3);
173
174         /* Return value in r0 for callee */
175         callee_sp[0] = ret;
176
177         asm volatile ("pop {r4-r11}");
178         /* exception return, 0xFFFFFFFX (<-- last value is flag
179          * and gives the processor information to return to what */
180         asm volatile ("pop {lr}"); 
181         asm volatile ("bx lr");
182
183
184 }
185
186 void syscall_init() {
187         /* SVC is located at position 11 in the interrupt vector table  */
188         ivt_set_gate(11, _svc_handler, 0);
189 }
190
191