net: tcp: Use timestamps for the RTTM
[akaros.git] / kern / src / frontend.c
1 #include <atomic.h>
2 #include <process.h>
3 #include <kmalloc.h>
4 #include <pmap.h>
5 #include <frontend.h>
6 #include <syscall.h>
7 #include <smp.h>
8 #include <slab.h>
9 #include <arch/arch.h>
10
11 volatile int magic_mem[10];
12
13 void
14 frontend_proc_init(struct proc *p)
15 {
16 #ifdef CONFIG_APPSERVER
17         pid_t parent_id = p->ppid, id = p->pid;
18         int32_t errno;
19         if(frontend_syscall(parent_id,APPSERVER_SYSCALL_proc_init,id,0,0,0,&errno))
20                 panic("Front-end server couldn't initialize new process!");
21 #endif
22 }
23
24 void
25 frontend_proc_free(struct proc *p)
26 {
27 #ifdef CONFIG_APPSERVER
28         int32_t errno;
29         if(frontend_syscall(0,APPSERVER_SYSCALL_proc_free,p->pid,0,0,0,&errno))
30                 panic("Front-end server couldn't free process!");
31 #endif
32 }
33
34 struct kmem_cache* struct_file_cache;
35 void file_init()
36 {
37         struct_file_cache = kmem_cache_create("struct_file",
38                                               sizeof(struct file), 8, 0,
39                                               NULL, 0, 0, NULL);
40 }
41
42 /* will zero anything in the page after the EOF */
43 error_t file_read_page(struct file* f, physaddr_t pa, size_t pgoff)
44 {
45         int ret = frontend_syscall(0,APPSERVER_SYSCALL_pread,f->fd,pa,PGSIZE,
46                                    pgoff*PGSIZE,NULL);
47         if(ret >= 0)
48                 memset(KADDR(pa)+ret,0,PGSIZE-ret);
49         return ret;
50 }
51
52 struct file* file_open_from_fd(struct proc* p, int fd)
53 {
54         struct file* f = NULL;
55         if(!(f = kmem_cache_alloc(struct_file_cache,0)))
56                 goto out;
57
58         f->fd = frontend_syscall(p->pid,APPSERVER_SYSCALL_kdup,fd,0,0,0,NULL);
59         if(f->fd == -1)
60         {
61                 kmem_cache_free(struct_file_cache,f);
62                 f = NULL;
63                 goto out;
64         }
65         spinlock_init(&f->lock);
66         f->refcnt = 1;
67
68 out:
69         return f;
70 }
71
72 struct file* file_open(const char* path, int oflag, int mode)
73 {
74         struct file* f = NULL;
75         // although path is a kernel pointer, it may be below KERNBASE.
76         // fix that if so.
77         char* malloced = NULL;
78         if((uintptr_t)path < KERNBASE)
79         {
80                 size_t len = strlen(path)+1;
81                 malloced = kmalloc(len,0);
82                 if(!malloced)
83                         goto out;
84                 path = memcpy(malloced,path,len);
85         }
86
87         if(!(f = kmem_cache_alloc(struct_file_cache,0)))
88                 goto out;
89
90         f->fd = frontend_syscall(0,APPSERVER_SYSCALL_open,PADDR(path),
91                                  oflag,mode,0,NULL);
92         if(f->fd == -1)
93         {
94                 kmem_cache_free(struct_file_cache,f);
95                 f = NULL;
96                 goto out;
97         }
98         spinlock_init(&f->lock);
99         f->refcnt = 1;
100
101 out:
102         if(malloced)
103                 kfree(malloced);
104         return f;
105 }
106
107 void file_incref(struct file* f)
108 {
109         spin_lock(&f->lock);
110         f->refcnt++;
111         spin_unlock(&f->lock);
112 }
113
114 void file_decref(struct file* f)
115 {
116         // if you decref too many times, you'll clobber memory :(
117         spin_lock(&f->lock);
118         if(--f->refcnt == 0)
119         {
120                 int ret = frontend_syscall(0,APPSERVER_SYSCALL_close,f->fd,0,0,0,NULL);
121                 assert(ret == 0);
122                 kmem_cache_free(struct_file_cache,f);
123         }
124         else
125                 spin_unlock(&f->lock);
126 }
127
128 int frontend_syscall_errno(struct proc* p, int n, int a0, int a1, int a2, int a3)
129 {
130         int errno, ret = frontend_syscall(p->pid,n,a0,a1,a2,a3,&errno);
131         if(errno && p)
132                 set_errno(errno);
133         return ret;
134 }
135
136 int32_t frontend_syscall(pid_t pid, int32_t syscall_num,
137                          uint32_t arg0, uint32_t arg1,
138                          uint32_t arg2, uint32_t arg3, int32_t* errno)
139 {
140 #ifndef CONFIG_APPSERVER
141         warn("No appserver support, requested syscall %d for proc %d", syscall_num,
142              pid);
143         if(errno)
144                 *errno = ENOSYS;
145         return -1;
146 #endif
147
148 #ifdef CONFIG_X86
149         if (!irq_is_enabled())
150                 warn("IRQ is disabled in frontend_syscall %d for proc %d\n", syscall_num, pid);
151 #endif
152
153         static spinlock_t lock = SPINLOCK_INITIALIZER;
154         int32_t ret;
155
156         // only one frontend request at a time.
157         // interrupts could try to do frontend requests,
158         // which would deadlock, so disable them
159         spin_lock(&lock);
160
161         // write syscall into magic memory
162         magic_mem[7] = 0;
163         magic_mem[1] = syscall_num;
164         magic_mem[2] = arg0;
165         magic_mem[3] = arg1;
166         magic_mem[4] = arg2;
167         magic_mem[5] = arg3;
168         magic_mem[6] = pid;
169         magic_mem[0] = 0x80;
170
171         // wait for front-end response
172         while(magic_mem[7] == 0)
173                 ;
174
175         ret = magic_mem[1];
176         if(errno)
177                 *errno = magic_mem[2];
178
179         spin_unlock(&lock);
180
181         return ret;
182 }
183
184 void __diediedie(uint32_t srcid, uint32_t code, uint32_t a1, uint32_t a2)
185 {
186         int32_t errno;
187         frontend_syscall(0,APPSERVER_SYSCALL_exit,(int)code,0,0,0,&errno);
188         while(1);
189 }
190
191 void appserver_die(uintptr_t code)
192 {
193         int i;
194         for(i = 0; i < num_cores; i++)
195                 if(i != core_id())
196                         while(send_kernel_message(i, (amr_t)&__diediedie, code, 0, 0,
197                                                   KMSG_IMMEDIATE));
198
199         // just in case.
200         __diediedie(0, code, 0, 0);
201 }