frontend-link code quality improvements
[akaros.git] / kern / arch / sparc / 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 <pmap.h>
11 #include <arch/frontend.h>
12 #include <smp.h>
13
14 volatile int magic_mem[10];
15
16 int32_t frontend_syscall_from_user(env_t* p, int32_t syscall_num, uint32_t arg0, uint32_t arg1, uint32_t arg2)
17 {
18         int32_t ret;
19         #define KBUFSIZE 1024
20         char buf[KBUFSIZE];
21
22         switch(syscall_num)
23         {
24                 case RAMP_SYSCALL_write:
25                         arg2 = arg2 > KBUFSIZE ? KBUFSIZE : arg2;
26                         if(memcpy_from_user(p,buf,(void*)arg1,arg2))
27                                 return -1;
28                         arg1 = PADDR((uint32_t)buf);
29
30                         extern spinlock_t output_lock;
31                         spin_lock(&output_lock);
32
33                         if(arg0 == 1 || arg0 == 2)
34                         {
35                                 int i;
36                                 for(i = 0; i < arg2; i++)
37                                         cputchar(buf[i]);
38                                 ret = arg2;
39                         }
40                         else
41                                 ret = frontend_syscall(syscall_num,arg0,arg1,arg2);
42
43                         spin_unlock(&output_lock);
44
45                         break;
46
47                 case RAMP_SYSCALL_open:
48                         if(memcpy_from_user(p,buf,(void*)arg0,KBUFSIZE))
49                                 return -1;
50                         arg0 = PADDR((uint32_t)buf);
51                         ret = frontend_syscall(syscall_num,arg0,arg1,arg2);
52                         break;
53
54                 case RAMP_SYSCALL_fstat:
55                         ret = frontend_syscall(syscall_num,arg0,PADDR((uint32_t)buf),arg2);
56                         if(memcpy_to_user(p,(void*)arg1,buf,64))
57                                 return -1;
58                         break;
59
60                 case RAMP_SYSCALL_read:
61                         arg2 = arg2 > KBUFSIZE ? KBUFSIZE : arg2;
62                         if(arg2 <= 0)
63                                 return arg2 < 0 ? -1 : 0;
64
65                         if(arg0 == 0)
66                         {
67                                 int ch = getchar();
68                                 buf[0] = (char)ch;
69                                 ret = 1;
70                         }
71                         else
72                                 ret = frontend_syscall(syscall_num,arg0,PADDR((uint32_t)buf),arg2);
73
74                         if(ret > 0 && memcpy_to_user(p,(void*)arg1,buf,arg2))
75                                 return -1;
76                         return ret;
77
78                 case RAMP_SYSCALL_getch:
79                         return frontend_syscall(RAMP_SYSCALL_getch,0,0,0);
80
81                 case RAMP_SYSCALL_gettimeofday:
82                 {
83                         struct timeval
84                         {
85                                 size_t tv_sec;
86                                 size_t tv_usec;
87                         };
88
89                         static spinlock_t gettimeofday_lock = 0;
90                         static size_t t0 = 0;
91                         spin_lock(&gettimeofday_lock);
92
93                         if(!t0)
94                         {
95                                 volatile struct timeval tp;
96                                 ret = frontend_syscall(RAMP_SYSCALL_gettimeofday,(int)PADDR((uint32_t)&tp),0,0);
97                                 if(ret == 0)
98                                         t0 = tp.tv_sec;
99                         }
100                         else ret = 0;
101
102                         spin_unlock(&gettimeofday_lock);
103
104                         if(ret == 0)
105                         {
106                                 struct timeval tp;
107                                 long long dt = read_tsc();
108                                 tp.tv_sec = t0 + dt/system_timing.tsc_freq;
109                                 tp.tv_usec = (dt % system_timing.tsc_freq)*1000000/system_timing.tsc_freq;
110
111                                 ret = memcpy_to_user(p,(void*)arg0,&tp,sizeof(tp));
112                         }
113                 }
114                 default:
115                         ret = -1;
116                         break;
117         }
118
119         return ret;
120 }
121
122 int32_t frontend_syscall(int32_t syscall_num, uint32_t arg0, uint32_t arg1, uint32_t arg2)
123 {
124         static spinlock_t lock = 0;
125         int32_t ret;
126
127         // only one frontend request at a time.
128         // interrupts could try to do frontend requests,
129         // which would deadlock, so disable them
130         spin_lock_irqsave(&lock);
131
132         // write syscall into magic memory
133         magic_mem[7] = 0;
134         magic_mem[1] = syscall_num;
135         magic_mem[2] = arg0;
136         magic_mem[3] = arg1;
137         magic_mem[4] = arg2;
138         magic_mem[0] = 0x80;
139
140         // wait for front-end response
141         while(magic_mem[7] == 0)
142                 ;
143
144         ret = magic_mem[1];
145
146         spin_unlock_irqsave(&lock);
147
148         return ret;
149 }
150
151 int32_t sys_nbputch(char ch)
152 {
153         static spinlock_t putch_lock = 0;
154         spin_lock_irqsave(&putch_lock);
155
156         int ret = -1;
157         if(magic_mem[8] == 0)
158         {
159                 magic_mem[8] = (unsigned int)(unsigned char)ch;
160                 ret = 0;
161         }
162
163         spin_unlock_irqsave(&putch_lock);
164         return ret;
165 }
166
167 int32_t sys_nbgetch()
168 {
169         static spinlock_t getch_lock = 0;
170         spin_lock_irqsave(&getch_lock);
171
172         int result = -1;
173         if(magic_mem[9]) 
174         {
175                 result = magic_mem[9];
176                 magic_mem[9] = 0;
177         }
178
179         spin_unlock_irqsave(&getch_lock);
180         return result;
181 }
182
183 void __diediedie(trapframe_t* tf, uint32_t srcid, uint32_t code, uint32_t a1, uint32_t a2)
184 {
185         frontend_syscall(RAMP_SYSCALL_exit,(int)code,0,0);
186         while(1);
187 }
188
189 void appserver_die(int code)
190 {
191         int i;
192         for(i = 0; i < num_cpus; i++)
193                 if(i != core_id())
194                         while(send_active_message(i,(amr_t)&__diediedie,(void*)code,0,0));
195
196         // just in case.
197         __diediedie(0,0,code,0,0);
198 }