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