Major reorganization in prep for appserver merge
[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* user_memdup(struct proc* p, const void* va, int len)
20 {
21         void* kva = NULL;
22         if(len < 0 || (kva = kmalloc(len,0)) == NULL)
23                 return ERR_PTR(-ENOMEM);
24         if(memcpy_from_user(p,kva,va,len))
25         {
26                 kfree(kva);
27                 return ERR_PTR(-EINVAL);
28         }
29
30         return kva;
31 }
32
33 void* user_memdup_errno(struct proc* p, const void* va, int len)
34 {
35         void* kva = user_memdup(p,va,len);
36         if(IS_ERR(kva))
37         {
38                 set_errno(current_tf,-PTR_ERR(kva));
39                 return NULL;
40         }
41         return kva;
42 }
43
44 void user_memdup_free(struct proc* p, void* va)
45 {
46         kfree(va);
47 }
48
49 char* user_strdup(struct proc* p, const char* va0, int max)
50 {
51         max++;
52         char* kbuf = (char*)kmalloc(PGSIZE,0);
53         if(kbuf == NULL)
54                 return ERR_PTR(-ENOMEM);
55
56         int pos = 0, len = 0;
57         const char* va = va0;
58         while(max > 0 && len == 0)
59         {
60                 int thislen = MIN(PGSIZE-(intptr_t)va%PGSIZE,max);
61                 if(memcpy_from_user(p,kbuf,va,thislen))
62                 {
63                         kfree(kbuf);
64                         return ERR_PTR(-EINVAL);
65                 }
66
67                 const char* nullterm = memchr(kbuf,0,thislen);
68                 if(nullterm)
69                         len = pos+(nullterm-kbuf)+1;
70
71                 pos += thislen;
72                 va += thislen;
73                 max -= thislen;
74         }
75
76         kfree(kbuf);
77         return len ? user_memdup(p,va0,len) : ERR_PTR(-EINVAL);
78 }
79
80 char* user_strdup_errno(struct proc* p, const char* va, int max)
81 {
82         void* kva = user_strdup(p,va,max);
83         if(IS_ERR(kva))
84         {
85                 set_errno(current_tf,-PTR_ERR(kva));
86                 return NULL;
87         }
88         return kva;
89 }
90
91 int memcpy_to_user_errno(struct proc* p, void* dst, const void* src,
92                                 int len)
93 {
94         if(memcpy_to_user(p,dst,src,len))
95         {
96                 set_errno(current_tf,EINVAL);
97                 return -1;
98         }
99         return 0;
100 }
101
102 void* kmalloc_errno(int len)
103 {
104         void* kva = NULL;
105         if(len < 0 || (kva = kmalloc(len,0)) == NULL)
106                 set_errno(current_tf,ENOMEM);
107         return kva;
108 }
109
110 error_t read_page(struct proc* p, int fd, physaddr_t pa, int pgoff)
111 {
112         int errno;
113         int ret = frontend_syscall(p->pid,APPSERVER_SYSCALL_pread,fd,
114                                 pa,PGSIZE,pgoff*PGSIZE,&errno);
115
116         if(ret >= 0)
117                 memset(KADDR(pa)+ret,0,PGSIZE-ret);
118         return ret;
119 }
120
121 error_t open_file(struct proc* p, const char* path, int oflag, int mode)
122 {
123         int errno;
124         return frontend_syscall(p->pid,APPSERVER_SYSCALL_open,PADDR(path),
125                                 oflag,mode,0,&errno);
126 }
127
128 error_t close_file(struct proc* p, int fd)
129 {
130         int errno;
131         return frontend_syscall(p->pid,APPSERVER_SYSCALL_close,fd,0,0,0,&errno);
132 }
133
134 int user_frontend_syscall(struct proc* p, int n, int a0, int a1, int a2, int a3)
135 {
136         int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno);
137         if(errno && p)
138                 set_errno(current_tf,errno);
139         return ret;
140 }
141
142 int32_t frontend_syscall(pid_t pid, int32_t syscall_num, 
143                          uint32_t arg0, uint32_t arg1, 
144                          uint32_t arg2, uint32_t arg3, int32_t* errno)
145 {
146         static spinlock_t lock = SPINLOCK_INITIALIZER;
147         int32_t ret;
148
149         // only one frontend request at a time.
150         // interrupts could try to do frontend requests,
151         // which would deadlock, so disable them
152         spin_lock_irqsave(&lock);
153
154         // write syscall into magic memory
155         magic_mem[7] = 0;
156         magic_mem[1] = syscall_num;
157         magic_mem[2] = arg0;
158         magic_mem[3] = arg1;
159         magic_mem[4] = arg2;
160         magic_mem[5] = arg3;
161         magic_mem[6] = pid;
162         magic_mem[0] = 0x80;
163
164         // wait for front-end response
165         while(magic_mem[7] == 0)
166                 ;
167
168         ret = magic_mem[1];
169         *errno = magic_mem[2];
170
171         spin_unlock_irqsave(&lock);
172
173         return ret;
174 }
175
176 int32_t frontend_nbputch(char ch)
177 {
178         static spinlock_t putch_lock = SPINLOCK_INITIALIZER;
179         spin_lock_irqsave(&putch_lock);
180
181         int ret = -1;
182         if(magic_mem[8] == 0)
183         {
184                 magic_mem[8] = (unsigned int)(unsigned char)ch;
185                 ret = 0;
186         }
187
188         spin_unlock_irqsave(&putch_lock);
189         return ret;
190 }
191
192 int32_t frontend_nbgetch()
193 {
194         static spinlock_t getch_lock = SPINLOCK_INITIALIZER;
195         spin_lock_irqsave(&getch_lock);
196
197         int result = -1;
198         if(magic_mem[9]) 
199         {
200                 result = magic_mem[9];
201                 magic_mem[9] = 0;
202         }
203
204         spin_unlock_irqsave(&getch_lock);
205         return result;
206 }
207
208 void __diediedie(trapframe_t* tf, uint32_t srcid, uint32_t code, uint32_t a1, uint32_t a2)
209 {
210         int32_t errno;
211         frontend_syscall(0,APPSERVER_SYSCALL_exit,(int)code,0,0,0,&errno);
212         while(1);
213 }
214
215 void appserver_die(int code)
216 {
217         int i;
218         for(i = 0; i < num_cpus; i++)
219                 if(i != core_id())
220                         while(send_active_message(i,(amr_t)&__diediedie,(void*)code,0,0));
221
222         // just in case.
223         __diediedie(0,0,code,0,0);
224 }