Fixed handling of appserver/interrupts
[akaros.git] / kern / src / frontend.c
1 #ifdef __SHARC__
2 #pragma nosharc
3 #endif
4
5 #ifdef __DEPUTY__
6 #pragma nodeputy
7 #endif
8
9 #include <atomic.h>
10 #include <process.h>
11 #include <kmalloc.h>
12 #include <pmap.h>
13 #include <frontend.h>
14 #include <syscall.h>
15 #include <smp.h>
16 #include <slab.h>
17 #include <arch/arch.h>
18
19 volatile int magic_mem[10];
20
21 void
22 frontend_proc_init(struct proc *SAFE p)
23 {
24 #ifdef __CONFIG_APPSERVER__
25         pid_t parent_id = p->ppid, id = p->pid;
26         int32_t errno;
27         if(frontend_syscall(parent_id,APPSERVER_SYSCALL_proc_init,id,0,0,0,&errno))
28                 panic("Front-end server couldn't initialize new process!");
29 #endif
30 }
31
32 void
33 frontend_proc_free(struct proc *SAFE p)
34 {
35 #ifdef __CONFIG_APPSERVER__
36         int32_t errno;
37         if(frontend_syscall(0,APPSERVER_SYSCALL_proc_free,p->pid,0,0,0,&errno))
38                 panic("Front-end server couldn't free process!");
39 #endif
40 }
41
42 void* user_memdup(struct proc* p, const void* va, int len)
43 {
44         void* kva = NULL;
45         if(len < 0 || (kva = kmalloc(len,0)) == NULL)
46                 return ERR_PTR(-ENOMEM);
47         if(memcpy_from_user(p,kva,va,len))
48         {
49                 kfree(kva);
50                 return ERR_PTR(-EINVAL);
51         }
52
53         return kva;
54 }
55
56 void* user_memdup_errno(struct proc* p, const void* va, int len)
57 {
58         void* kva = user_memdup(p,va,len);
59         if(IS_ERR(kva))
60         {
61                 set_errno(current_tf,-PTR_ERR(kva));
62                 return NULL;
63         }
64         return kva;
65 }
66
67 void user_memdup_free(struct proc* p, void* va)
68 {
69         kfree(va);
70 }
71
72 char* user_strdup(struct proc* p, const char* va0, int max)
73 {
74         max++;
75         char* kbuf = (char*)kmalloc(PGSIZE,0);
76         if(kbuf == NULL)
77                 return ERR_PTR(-ENOMEM);
78
79         int pos = 0, len = 0;
80         const char* va = va0;
81         while(max > 0 && len == 0)
82         {
83                 int thislen = MIN(PGSIZE-(uintptr_t)va%PGSIZE,max);
84                 if(memcpy_from_user(p,kbuf,va,thislen))
85                 {
86                         kfree(kbuf);
87                         return ERR_PTR(-EINVAL);
88                 }
89
90                 const char* nullterm = memchr(kbuf,0,thislen);
91                 if(nullterm)
92                         len = pos+(nullterm-kbuf)+1;
93
94                 pos += thislen;
95                 va += thislen;
96                 max -= thislen;
97         }
98
99         kfree(kbuf);
100         return len ? user_memdup(p,va0,len) : ERR_PTR(-EINVAL);
101 }
102
103 char* user_strdup_errno(struct proc* p, const char* va, int max)
104 {
105         void* kva = user_strdup(p,va,max);
106         if(IS_ERR(kva))
107         {
108                 set_errno(current_tf,-PTR_ERR(kva));
109                 return NULL;
110         }
111         return kva;
112 }
113
114 int memcpy_to_user_errno(struct proc* p, void* dst, const void* src,
115                                 int len)
116 {
117         if(memcpy_to_user(p,dst,src,len))
118         {
119                 set_errno(current_tf,EINVAL);
120                 return -1;
121         }
122         return 0;
123 }
124
125 void* kmalloc_errno(int len)
126 {
127         void* kva = NULL;
128         if(len < 0 || (kva = kmalloc(len,0)) == NULL)
129                 set_errno(current_tf,ENOMEM);
130         return kva;
131 }
132
133 struct kmem_cache* struct_file_cache;
134 void file_init()
135 {
136         struct_file_cache = kmem_cache_create("struct_file",
137                                               sizeof(struct file), 8, 0, 0, 0);
138 }
139
140 error_t file_read_page(struct file* f, physaddr_t pa, size_t pgoff)
141 {
142         int ret = frontend_syscall(0,APPSERVER_SYSCALL_pread,f->fd,pa,PGSIZE,
143                                    pgoff*PGSIZE,NULL);
144         if(ret >= 0)
145                 memset(KADDR(pa)+ret,0,PGSIZE-ret);
146         return ret;
147 }
148
149 struct file* file_open_from_fd(struct proc* p, int fd)
150 {
151         struct file* f = NULL;
152         if(!(f = kmem_cache_alloc(struct_file_cache,0)))
153                 goto out;
154
155         f->fd = frontend_syscall(p->pid,APPSERVER_SYSCALL_kdup,fd,0,0,0,NULL);
156         if(f->fd == -1)
157         {
158                 kmem_cache_free(struct_file_cache,f);
159                 f = NULL;
160                 goto out;
161         }
162         spinlock_init(&f->lock);
163         f->refcnt = 1;
164
165 out:
166         return f;
167 }
168
169 struct file* file_open(const char* path, int oflag, int mode)
170 {
171         struct file* f = NULL;
172         // although path is a kernel pointer, it may be below KERNBASE.
173         // fix that if so.
174         char* malloced = NULL;
175         if((uintptr_t)path < KERNBASE)
176         {
177                 size_t len = strlen(path)+1;
178                 malloced = kmalloc(len,0);
179                 if(!malloced)
180                         goto out;
181                 path = memcpy(malloced,path,len);
182         }
183
184         if(!(f = kmem_cache_alloc(struct_file_cache,0)))
185                 goto out;
186
187         f->fd = frontend_syscall(0,APPSERVER_SYSCALL_open,PADDR(path),
188                                  oflag,mode,0,NULL);
189         if(f->fd == -1)
190         {
191                 kmem_cache_free(struct_file_cache,f);
192                 f = NULL;
193                 goto out;
194         }
195         spinlock_init(&f->lock);
196         f->refcnt = 1;
197
198 out:
199         if(malloced)
200                 kfree(malloced);
201         return f;
202 }
203
204 void file_incref(struct file* f)
205 {
206         spin_lock(&f->lock);
207         f->refcnt++;
208         spin_unlock(&f->lock);
209 }
210
211 void file_decref(struct file* f)
212 {
213         // if you decref too many times, you'll clobber memory :(
214         spin_lock(&f->lock);
215         if(--f->refcnt == 0)
216         {
217                 int ret = frontend_syscall(0,APPSERVER_SYSCALL_close,f->fd,0,0,0,NULL);
218                 assert(ret == 0);
219                 kmem_cache_free(struct_file_cache,f);
220         }
221         else
222                 spin_unlock(&f->lock);
223 }
224
225 int frontend_syscall_errno(struct proc* p, int n, int a0, int a1, int a2, int a3)
226 {
227         int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno);
228         if(errno && p)
229                 set_errno(current_tf,errno);
230         return ret;
231 }
232
233 int32_t frontend_syscall(pid_t pid, int32_t syscall_num, 
234                          uint32_t arg0, uint32_t arg1, 
235                          uint32_t arg2, uint32_t arg3, int32_t* errno)
236 {
237 #ifndef __CONFIG_APPSERVER__
238         warn("No appserver support, requested syscall %d for proc %d", syscall_num,
239              pid);
240         if(errno)
241                 *errno = ENOSYS;
242         return -1;
243 #endif
244
245 #ifdef __i386__
246         assert(irq_is_enabled());
247 #endif
248
249         static spinlock_t lock = SPINLOCK_INITIALIZER;
250         int32_t ret;
251
252         // only one frontend request at a time.
253         // interrupts could try to do frontend requests,
254         // which would deadlock, so disable them
255         spin_lock(&lock);
256
257         // write syscall into magic memory
258         magic_mem[7] = 0;
259         magic_mem[1] = syscall_num;
260         magic_mem[2] = arg0;
261         magic_mem[3] = arg1;
262         magic_mem[4] = arg2;
263         magic_mem[5] = arg3;
264         magic_mem[6] = pid;
265         magic_mem[0] = 0x80;
266
267         // wait for front-end response
268         while(magic_mem[7] == 0)
269                 ;
270
271         ret = magic_mem[1];
272         if(errno)
273                 *errno = magic_mem[2];
274
275         spin_unlock(&lock);
276
277         return ret;
278 }
279
280 void __diediedie(trapframe_t* tf, uint32_t srcid, uint32_t code, uint32_t a1, uint32_t a2)
281 {
282         int32_t errno;
283         frontend_syscall(0,APPSERVER_SYSCALL_exit,(int)code,0,0,0,&errno);
284         while(1);
285 }
286
287 void appserver_die(int code)
288 {
289         int i;
290         for(i = 0; i < num_cpus; i++)
291                 if(i != core_id())
292                         while(send_kernel_message(i,(amr_t)&__diediedie,(void*)code,0,0,
293                                                   KMSG_IMMEDIATE));
294
295         // just in case.
296         __diediedie(0,0,code,0,0);
297 }