basic scheduling, basic syscall, (added .data copy)
[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_DESTROY      | 2     |
14  * | THEOS_RESCHED      | 3     |
15  * | THEOS_GETC         | 4     |
16  * | THEOS_CPUTS        | 5     |
17  * | THEOS_UPTIME       | 6     |
18  * | THEOS_OMNIGOD      | 7     |
19  * | THEOS_TIME         | 8     |
20  * | THEOS_MAGIC        | 99    |
21  * |----------------------------|
22  *
23  * TODO: include in header enum
24  * */
25
26 #include <stdbool.h>
27 #include <stddef.h>
28 #include <stdint.h>
29
30 #include <sys/robsys.h>
31 #include <sys/mmap.h>
32 #include <sys/process.h>
33
34 #include <lib/stdio.h>
35 #include <lib/string.h>
36 #include <lib/regfunc.h>
37 #include <lib/tinyprintf.h>
38
39 enum {
40         THEOS_INIT = 1,
41         THEOS_CREATE,
42         THEOS_DESTROY,
43         THEOS_SWITCH,
44         THEOS_GETC,
45         THEOS_CPUTS,
46         THEOS_UPTIME
47 };
48
49
50 static int sys_uptime() {
51
52         int uptime = *RTC_CNTL;
53         return uptime;
54 }
55
56 /* Context switch routine, saves stack pointer of 
57  * the current process, loads the stack pointer
58  * of the next.
59  *
60  * Other registers and flags (i.e. PSR, PC are popped
61  * by exit of this system call.
62  * Precondition: Usage of PSP   */
63 int sys_switch(process_t * currp, process_t * newp) {
64
65         uint32_t tmp_stackptr = 0xFFFFFFFF;
66         asm volatile("mrs %0, psp" : "=r" (tmp_stackptr));
67         currp->stackptr = tmp_stackptr; 
68
69         asm volatile("msr psp, %0" : : "r" (newp->stackptr) ); // load new pointer 
70         uint32_t chk_stackptr;
71         asm volatile("mrs %0, psp" : "=r" (chk_stackptr));
72         //asm volatile("isb");
73         printf("OLD: %x\n", currp->stackptr);
74         printf("NEW: %x\n", newp->stackptr);
75         printf("CHK: %x\n", chk_stackptr);
76         //for(;;);
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