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