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