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