Splits x86 into 32 and 64 bit (XCC)
[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 #include <arch/arch.h>
18
19 volatile int magic_mem[10];
20
21 void
22 frontend_proc_init(struct proc *SAFE p)
23 {
24 #ifdef CONFIG_APPSERVER
25         pid_t parent_id = p->ppid, id = p->pid;
26         int32_t errno;
27         if(frontend_syscall(parent_id,APPSERVER_SYSCALL_proc_init,id,0,0,0,&errno))
28                 panic("Front-end server couldn't initialize new process!");
29 #endif
30 }
31
32 void
33 frontend_proc_free(struct proc *SAFE p)
34 {
35 #ifdef CONFIG_APPSERVER
36         int32_t errno;
37         if(frontend_syscall(0,APPSERVER_SYSCALL_proc_free,p->pid,0,0,0,&errno))
38                 panic("Front-end server couldn't free process!");
39 #endif
40 }
41
42 struct kmem_cache* struct_file_cache;
43 void file_init()
44 {
45         struct_file_cache = kmem_cache_create("struct_file",
46                                               sizeof(struct file), 8, 0, 0, 0);
47 }
48
49 /* will zero anything in the page after the EOF */
50 error_t file_read_page(struct file* f, physaddr_t pa, size_t pgoff)
51 {
52         int ret = frontend_syscall(0,APPSERVER_SYSCALL_pread,f->fd,pa,PGSIZE,
53                                    pgoff*PGSIZE,NULL);
54         if(ret >= 0)
55                 memset(KADDR(pa)+ret,0,PGSIZE-ret);
56         return ret;
57 }
58
59 struct file* file_open_from_fd(struct proc* p, int fd)
60 {
61         struct file* f = NULL;
62         if(!(f = kmem_cache_alloc(struct_file_cache,0)))
63                 goto out;
64
65         f->fd = frontend_syscall(p->pid,APPSERVER_SYSCALL_kdup,fd,0,0,0,NULL);
66         if(f->fd == -1)
67         {
68                 kmem_cache_free(struct_file_cache,f);
69                 f = NULL;
70                 goto out;
71         }
72         spinlock_init(&f->lock);
73         f->refcnt = 1;
74
75 out:
76         return f;
77 }
78
79 struct file* file_open(const char* path, int oflag, int mode)
80 {
81         struct file* f = NULL;
82         // although path is a kernel pointer, it may be below KERNBASE.
83         // fix that if so.
84         char* malloced = NULL;
85         if((uintptr_t)path < KERNBASE)
86         {
87                 size_t len = strlen(path)+1;
88                 malloced = kmalloc(len,0);
89                 if(!malloced)
90                         goto out;
91                 path = memcpy(malloced,path,len);
92         }
93
94         if(!(f = kmem_cache_alloc(struct_file_cache,0)))
95                 goto out;
96
97         f->fd = frontend_syscall(0,APPSERVER_SYSCALL_open,PADDR(path),
98                                  oflag,mode,0,NULL);
99         if(f->fd == -1)
100         {
101                 kmem_cache_free(struct_file_cache,f);
102                 f = NULL;
103                 goto out;
104         }
105         spinlock_init(&f->lock);
106         f->refcnt = 1;
107
108 out:
109         if(malloced)
110                 kfree(malloced);
111         return f;
112 }
113
114 void file_incref(struct file* f)
115 {
116         spin_lock(&f->lock);
117         f->refcnt++;
118         spin_unlock(&f->lock);
119 }
120
121 void file_decref(struct file* f)
122 {
123         // if you decref too many times, you'll clobber memory :(
124         spin_lock(&f->lock);
125         if(--f->refcnt == 0)
126         {
127                 int ret = frontend_syscall(0,APPSERVER_SYSCALL_close,f->fd,0,0,0,NULL);
128                 assert(ret == 0);
129                 kmem_cache_free(struct_file_cache,f);
130         }
131         else
132                 spin_unlock(&f->lock);
133 }
134
135 int frontend_syscall_errno(struct proc* p, int n, int a0, int a1, int a2, int a3)
136 {
137         int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno);
138         if(errno && p)
139                 set_errno(errno);
140         return ret;
141 }
142
143 int32_t frontend_syscall(pid_t pid, int32_t syscall_num, 
144                          uint32_t arg0, uint32_t arg1, 
145                          uint32_t arg2, uint32_t arg3, int32_t* errno)
146 {
147 #ifndef CONFIG_APPSERVER
148         warn("No appserver support, requested syscall %d for proc %d", syscall_num,
149              pid);
150         if(errno)
151                 *errno = ENOSYS;
152         return -1;
153 #endif
154
155 #ifdef CONFIG_X86
156         if (!irq_is_enabled())
157                 warn("IRQ is disabled in frontend_syscall %d for proc %d\n", syscall_num, pid);
158 #endif
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(&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(&lock);
187
188         return ret;
189 }
190
191 void __diediedie(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(uintptr_t code)
199 {
200         int i;
201         for(i = 0; i < num_cpus; i++)
202                 if(i != core_id())
203                         while(send_kernel_message(i, (amr_t)&__diediedie, code, 0, 0,
204                                                   KMSG_IMMEDIATE));
205
206         // just in case.
207         __diediedie(0, code, 0, 0);
208 }