Kernel message nested function scoping
[akaros.git] / kern / arch / riscv / console.c
1 #include <arch/console.h>
2 #include <console.h>
3 #include <pmap.h>
4 #include <atomic.h>
5 #include <smp.h>
6 #include <kmalloc.h>
7 #include <monitor.h>
8 #include <process.h>
9
10 struct magic_mem {
11         volatile uint64_t words[8];
12 };
13 struct fesvr_syscall {
14         struct magic_mem magic_mem;
15         STAILQ_ENTRY(fesvr_syscall) link;
16 };
17 STAILQ_HEAD(fesvr_syscall_tailq, fesvr_syscall);
18
19 spinlock_t fesvr_lock = SPINLOCK_INITIALIZER;
20 struct fesvr_syscall_tailq fesvr_queue;
21 struct magic_mem fesvr_current __attribute__((aligned(64)));
22
23 bool fesvr_busy()
24 {
25         if (mfpcr(PCR_TOHOST))
26         {
27                 assert(core_id() == 0);
28                 return true;
29         }
30         
31         volatile uint64_t* mm = fesvr_current.words;
32         if (mfpcr(PCR_FROMHOST) && mm[6])
33         {
34                 void (*func)(void*, uint64_t*) = (void*)(uintptr_t)mm[6];
35                 void* farg = (void*)(uintptr_t)mm[7];
36                 func(farg, (uint64_t*)mm);
37         }
38         mtpcr(PCR_FROMHOST, 0);
39
40         return false;
41 }
42
43 void fesvr_syscall(long n, long a0, long a1, long a2, long a3,
44                    void (*continuation)(void*, uint64_t*), void* arg)
45 {
46         struct fesvr_syscall* mm = kmalloc(sizeof(struct fesvr_syscall), 0);
47         assert(mm);
48
49         mm->magic_mem.words[0] = n;
50         mm->magic_mem.words[1] = a0;
51         mm->magic_mem.words[2] = a1;
52         mm->magic_mem.words[3] = a2;
53         mm->magic_mem.words[4] = a3;
54         mm->magic_mem.words[6] = (uintptr_t)continuation;
55         mm->magic_mem.words[7] = (uintptr_t)arg;
56
57         spin_lock_irqsave(&fesvr_lock);
58         STAILQ_INSERT_TAIL(&fesvr_queue, mm, link);
59         spin_unlock_irqsave(&fesvr_lock);
60 }
61
62 long fesvr_syscall_sync(long n, long a0, long a1, long a2, long a3)
63 {
64         uintptr_t irq_state = disable_irq();
65         while (fesvr_busy());
66
67         struct magic_mem mm __attribute__((aligned(64)));
68         mm.words[0] = n;
69         mm.words[1] = a0;
70         mm.words[2] = a1;
71         mm.words[3] = a2;
72         mm.words[4] = a3;
73
74         mb();
75         mtpcr(PCR_TOHOST, PADDR(&mm));
76         while (mfpcr(PCR_FROMHOST) == 0);
77         mtpcr(PCR_FROMHOST, 0);
78
79         restore_irq(irq_state);
80         return mm.words[0];
81 }
82
83 void fesvr_die()
84 {
85         fesvr_syscall_sync(FESVR_SYS_exit, 0, 0, 0, 0);
86 }
87
88 // emulate keyboard input with an alarm
89 void keyboard_alarm_init()
90 {
91         void cons_poll(struct alarm_waiter* awaiter)
92         {
93                 static bool cons_polling;
94                 static uint64_t cons_last_polled;
95                 void cont(void* null, uint64_t* magic_mem)
96                 {
97                         for (int i = 0; i < (int)magic_mem[0]; i++)
98                         {
99                                 char c = ((char*)KADDR(magic_mem[2]))[i];
100                                 if (c == 'G')
101                                         send_kernel_message(core_id(), __run_mon, 0, 0, 0, KMSG_ROUTINE);
102                                 else
103                                         send_kernel_message(core_id(), __cons_add_char, (long)&cons_buf,
104                                                             (long)c, 0, KMSG_ROUTINE);
105                         }
106                         cons_polling = false;
107                         cons_last_polled = read_tsc();
108                 }
109
110 #ifdef __CONFIG_DEMO_SLAVE__
111                 if (!fesvr_busy() && STAILQ_EMPTY(&fesvr_queue) && hashtable_count(pid_hash) == 0)
112                 {
113                         uint32_t demo_size = 0, demo_pos = 0;
114                         assert(sizeof(demo_size) == fesvr_syscall_sync(FESVR_SYS_read, 0, PADDR(&demo_size), sizeof(demo_size), 0));
115                         void* demo = kmalloc(demo_size, 0);
116                         assert(demo_size == fesvr_syscall_sync(FESVR_SYS_read, 0, PADDR(demo), demo_size, 0));
117                         struct file* f = do_file_open("/bin/demo", O_CREAT, O_WRONLY);
118                         assert(f);
119                         off_t off = 0;
120                         assert(demo_size == f->f_op->write(f, demo, demo_size, &off));
121                         kref_put(&f->f_kref);
122                         /* this is potentially dangerous.  the compiler will put run_demo on
123                          * the stack if it references any other stack variables.  the
124                          * compiler might be allowed to do so otherwise too. */
125                         void run_demo()
126                         {
127                                 char *argv[2] = {"", "demo"};
128                                 mon_bin_run(2, argv, 0);
129                         }
130                         send_kernel_message(core_id(), run_demo, 0, 0, 0, KMSG_ROUTINE);
131                 }
132 #else
133                 if (!cons_polling && read_tsc() - cons_last_polled >= 100)
134                 {
135                         cons_polling = true;
136                         static char buf[64] __attribute__((aligned(64)));
137                         fesvr_syscall(FESVR_SYS_read_noncanonical, 0, PADDR(buf), sizeof(buf), 0, cont, 0);
138                 }
139 #endif
140
141                 uint64_t usec = 100;
142                 if (!fesvr_busy())
143                 {
144                         spin_lock(&fesvr_lock);
145                         if (!STAILQ_EMPTY(&fesvr_queue))
146                         {
147                                 usec = 10;
148                                 struct fesvr_syscall* s = STAILQ_FIRST(&fesvr_queue);
149                                 fesvr_current = s->magic_mem;
150                                 STAILQ_REMOVE_HEAD(&fesvr_queue, link);
151                                 kfree(s);
152                                 mb();
153                                 mtpcr(PCR_TOHOST, PADDR(&fesvr_current));
154                         }
155                         spin_unlock(&fesvr_lock);
156                 }
157                 else
158                         usec = 10;
159
160                 set_awaiter_rel(awaiter, usec);
161                 set_alarm(&per_cpu_info[core_id()].tchain, awaiter);
162         }
163
164         STAILQ_INIT(&fesvr_queue);
165
166         static struct alarm_waiter awaiter;
167         init_awaiter(&awaiter, cons_poll);
168         set_awaiter_rel(&awaiter, 1);
169         set_alarm(&per_cpu_info[core_id()].tchain, &awaiter);
170 }
171
172 int cons_get_any_char(void)
173 {
174         assert(0);
175 }
176
177 void
178 cons_init(void)
179 {
180 }
181
182 // `High'-level console I/O.  Used by readline and cprintf.
183
184 void
185 cputbuf(const char* str, int len)
186 {
187         extern int booting;
188         if (booting)
189         {
190                 fesvr_syscall_sync(FESVR_SYS_write, 1, PADDR(str), len, 0);
191                 return;
192         }
193
194         void cont(void* buf, uint64_t* mm)
195         {
196                 kfree(buf);
197         }
198
199         char* buf = kmalloc(len, 0);
200         assert(buf);
201         memcpy(buf, str, len);
202         fesvr_syscall(FESVR_SYS_write, 1, PADDR(buf), len, 0, cont, buf);
203 }
204
205 // Low-level console I/O
206
207 void
208 cputchar(int c)
209 {
210         char ch = c;
211         cputbuf(&ch,1);
212 }
213
214 int
215 getchar(void)
216 {
217         char c;
218         kb_get_from_buf(&cons_buf, &c, 1);
219         return c;
220 }
221
222 int
223 iscons(int fdnum)
224 {
225         // used by readline
226         return 1;
227 }