frontend_syscall now accepts NULL for &errno
[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 read_page(struct proc* p, int fd, physaddr_t pa, int pgoff)
128 {
129         int ret = frontend_syscall(p ? p->pid : 0,APPSERVER_SYSCALL_pread,fd,
130                                 pa,PGSIZE,pgoff*PGSIZE,NULL);
131
132         if(ret >= 0)
133                 memset(KADDR(pa)+ret,0,PGSIZE-ret);
134         return ret;
135 }
136
137 error_t open_file(struct proc* p, const char* path, int oflag, int mode)
138 {
139         return frontend_syscall(p->pid,APPSERVER_SYSCALL_open,PADDR(path),
140                                 oflag,mode,0,NULL);
141 }
142
143 error_t close_file(struct proc* p, int fd)
144 {
145         return frontend_syscall(p->pid,APPSERVER_SYSCALL_close,fd,0,0,0,NULL);
146 }
147
148 int frontend_syscall_errno(struct proc* p, int n, int a0, int a1, int a2, int a3)
149 {
150         int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno);
151         if(errno && p)
152                 set_errno(current_tf,errno);
153         return ret;
154 }
155
156 int32_t frontend_syscall(pid_t pid, int32_t syscall_num, 
157                          uint32_t arg0, uint32_t arg1, 
158                          uint32_t arg2, uint32_t arg3, int32_t* errno)
159 {
160         static spinlock_t lock = SPINLOCK_INITIALIZER;
161         int32_t ret;
162
163         // only one frontend request at a time.
164         // interrupts could try to do frontend requests,
165         // which would deadlock, so disable them
166         spin_lock_irqsave(&lock);
167
168         // write syscall into magic memory
169         magic_mem[7] = 0;
170         magic_mem[1] = syscall_num;
171         magic_mem[2] = arg0;
172         magic_mem[3] = arg1;
173         magic_mem[4] = arg2;
174         magic_mem[5] = arg3;
175         magic_mem[6] = pid;
176         magic_mem[0] = 0x80;
177
178         // wait for front-end response
179         while(magic_mem[7] == 0)
180                 ;
181
182         ret = magic_mem[1];
183         if(errno)
184                 *errno = magic_mem[2];
185
186         spin_unlock_irqsave(&lock);
187
188         return ret;
189 }
190
191 void __diediedie(trapframe_t* tf, uint32_t srcid, uint32_t code, uint32_t a1, uint32_t a2)
192 {
193         int32_t errno;
194         frontend_syscall(0,APPSERVER_SYSCALL_exit,(int)code,0,0,0,&errno);
195         while(1);
196 }
197
198 void appserver_die(int code)
199 {
200         int i;
201         for(i = 0; i < num_cpus; i++)
202                 if(i != core_id())
203                         while(send_active_message(i,(amr_t)&__diediedie,(void*)code,0,0));
204
205         // just in case.
206         __diediedie(0,0,code,0,0);
207 }