added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / all-unix / exec / kernel.c
blob2638d188fc74f50f65f017d75cf503e39e74912e
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Initialize the interface to the "hardware".
6 Lang: english
7 */
9 #include <exec_intern.h>
11 #include <exec/types.h>
12 #include <exec/interrupts.h>
13 #include <exec/execbase.h>
14 #include <exec/alerts.h>
15 #include <aros/asmcall.h>
16 #include <aros/atomic.h>
17 #include <aros/debug.h>
18 #include <aros/config.h>
19 #include <hardware/intbits.h>
21 #define timeval sys_timeval
22 #include <sigcore.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <signal.h>
27 #include <sys/time.h>
28 #include <stdlib.h>
29 #undef timeval
31 #include <proto/exec.h>
33 #define DEBUG_TT 0
34 #if DEBUG_TT
35 static struct Task * lastTask;
36 #endif
38 /* Don't do any debugging. At 50Hz its far too quick to read anyway :-) */
39 #define NOISY 0
41 /* Try and emulate the Amiga hardware interrupts */
42 static int sig2tab[NSIG];
43 sigset_t sig_int_mask; /* Mask of signals that Disable() block */
44 int intrap;
45 LONG supervisor;
47 static BOOL sigactive[NSIG];
50 These tables are used to map signals to interrupts
51 and trap. There are two tables for the two different kinds
52 of events. We also remove all the signals in sig2trap from
53 the interrupt disable mask.
55 static const int sig2int[][2] =
57 { SIGALRM, INTB_TIMERTICK },
58 { SIGUSR1, INTB_SOFTINT },
59 { SIGIO, INTB_DSKBLK }
62 static const int sig2trap[][2] =
64 { SIGBUS, 2 },
65 { SIGSEGV, 3 },
66 { SIGILL, 4 },
67 #ifdef SIGEMT
68 { SIGEMT, 13 },
69 #endif
70 { SIGFPE, 13 }
73 /* On TF_EXCEPT make Exec_Exception being called. */
74 extern void AROS_SLIB_ENTRY(Exception, Exec)();
76 /* This is from sigcore.h - it brings in the definition of the
77 systems initial signal handler, which simply calls
78 sighandler(int signum, sigcontext_t sigcontext)
80 GLOBAL_SIGNAL_INIT
82 /* sighandler() Handle the signals:
83 You can either turn them into interrupts, or alternatively,
84 you can turn them into traps (eg software failures)
86 static void sighandler(int sig, sigcontext_t * sc)
88 struct IntVector *iv;
90 if(sig == SIGINT)
92 exit(0);
95 #if !AROS_NESTING_SUPERVISOR
96 /* Hmm, interrupts are nesting, not a good idea... */
97 if(supervisor)
99 #if NOISY
100 fprintf(stderr, "Illegal Supervisor %d\n", supervisor);
101 fflush(stderr);
102 #endif
104 return;
106 #endif
108 AROS_ATOMIC_INC(supervisor);
110 if (sigactive[sig])
112 #if NOISY
113 fprintf(stderr,"********* sighandler: sig %d already active **********\n", sig);
114 fflush(stderr);
115 #endif
117 return;
119 sigactive[sig] = TRUE;
121 /* Map the Unix signal to an Amiga signal. */
122 iv = &SysBase->IntVects[sig2tab[sig]];
124 if (iv->iv_Code)
126 /* Call it. I call with all these parameters for a reason.
128 In my `Amiga ROM Kernel Reference Manual: Libraries and
129 Devices' (the 1.3 version), interrupt servers are called
130 with the following 5 parameters.
132 D1 - Mask of INTENAR and INTREQR
133 A0 - 0xDFF000 (base of custom chips)
134 A1 - Interrupt Data
135 A5 - Interrupt Code vector
136 A6 - SysBase
138 It is quite possible that some code uses all of these, so
139 I must supply them here. Obviously I will dummy some of these
140 though.
143 /* If iv->iv_Code calls Disable()/Enable() we could end up
144 having the signals unblocked, which then can cause nesting
145 signals which we do not want. Therefore prevent this from
146 happening by doing this manual Disable()ing/Enable()ing,
147 ie. inc/dec of SysBase->IDNestCnt. */
149 AROS_ATOMIC_INC(SysBase->IDNestCnt);
151 AROS_UFC5(void, iv->iv_Code,
152 AROS_UFCA(ULONG, 0, D1),
153 AROS_UFCA(ULONG, 0, A0),
154 AROS_UFCA(APTR, iv->iv_Data, A1),
155 AROS_UFCA(APTR, iv->iv_Code, A5),
156 AROS_UFCA(struct ExecBase *, SysBase, A6)
159 /* If this was 100 Hz VBlank timer, emulate 50 Hz VBlank timer if
160 we are on an even 100 Hz tick count */
162 if (sig2tab[sig] == INTB_TIMERTICK)
164 static int tick_counter;
166 if ((tick_counter % SysBase->PowerSupplyFrequency) == 0)
168 iv = &SysBase->IntVects[INTB_VERTB];
169 if (iv->iv_Code)
171 AROS_UFC5(void, iv->iv_Code,
172 AROS_UFCA(ULONG, 0, D1),
173 AROS_UFCA(ULONG, 0, A0),
174 AROS_UFCA(APTR, iv->iv_Data, A1),
175 AROS_UFCA(APTR, iv->iv_Code, A5),
176 AROS_UFCA(struct ExecBase *, SysBase, A6)
182 tick_counter++;
185 AROS_ATOMIC_DEC(SysBase->IDNestCnt);
188 /* Has an interrupt told us to dispatch when leaving */
190 #if AROS_NESTING_SUPERVISOR
191 if (supervisor == 1)
192 #endif
193 if (SysBase->AttnResched & ARF_AttnDispatch)
195 #if AROS_NESTING_SUPERVISOR
196 // Disable(); commented out, as causes problems with IDNestCnt. Getting completely out of range.
197 #endif
198 UWORD u = (UWORD) ~(ARF_AttnDispatch);
199 AROS_ATOMIC_AND(SysBase->AttnResched, u);
201 /* Save registers for this task (if there is one...) */
202 if (SysBase->ThisTask && SysBase->ThisTask->tc_State != TS_REMOVED)
204 SAVEREGS(SysBase->ThisTask, sc);
207 /* Tell exec that we have actually switched tasks... */
208 Dispatch ();
210 /* Get the registers of the old task */
211 RESTOREREGS(SysBase->ThisTask, sc);
213 /* Make sure that the state of the interrupts is what the task
214 expects.
216 if (SysBase->IDNestCnt < 0)
217 SC_ENABLE(sc);
218 else
219 SC_DISABLE(sc);
221 /* Ok, the next step is to either drop back to the new task, or
222 give it its Exception() if it wants one... */
224 if (SysBase->ThisTask->tc_Flags & TF_EXCEPT)
226 /* Exec_Exception will Enable() */
227 Disable();
228 /* Make room for the current cpu context. */
229 SysBase->ThisTask->tc_SPReg -= SIZEOF_ALL_REGISTERS;
230 GetCpuContext(SysBase->ThisTask)->sc = SysBase->ThisTask->tc_SPReg;
231 /* Copy current cpu context. */
232 memcpy(SysBase->ThisTask->tc_SPReg, GetCpuContext(SysBase->ThisTask), SIZEOF_ALL_REGISTERS);
233 /* Manipulate the current cpu context so Exec_Exception gets
234 excecuted after we leave the kernel resp. the signal handler. */
235 SP(sc) = (unsigned long) SysBase->ThisTask->tc_SPReg;
236 PC(sc) = (unsigned long) AROS_SLIB_ENTRY(Exception, Exec);
237 SETUP_EXCEPTION(sc, SysBase);
239 if (SysBase->ThisTask->tc_SPReg <= SysBase->ThisTask->tc_SPLower)
241 /* POW! */
242 Alert(AT_DeadEnd|AN_StackProbe);
246 #if DEBUG_TT
247 if (lastTask != SysBase->ThisTask)
249 fprintf (stderr, "TT %s\n", SysBase->ThisTask->tc_Node.ln_Name);
250 lastTask = SysBase->ThisTask;
252 #endif
254 #if AROS_NESTING_SUPERVISOR
255 // Enable(); commented out, as causes problems with IDNestCnt. Getting completely out of range.
256 #endif
259 /* Are we returning from Exec_Exception? Then restore the saved cpu context. */
260 if (SysBase->ThisTask && SysBase->ThisTask->tc_State == TS_EXCEPT)
262 SysBase->ThisTask->tc_SPReg = GetCpuContext(SysBase->ThisTask)->sc;
263 memcpy(GetCpuContext(SysBase->ThisTask), SysBase->ThisTask->tc_SPReg, SIZEOF_ALL_REGISTERS);
264 SysBase->ThisTask->tc_SPReg += SIZEOF_ALL_REGISTERS;
266 if (SysBase->ThisTask->tc_SPReg > SysBase->ThisTask->tc_SPUpper)
268 /* POW! */
269 Alert(AT_DeadEnd|AN_StackProbe);
272 /* Restore the signaled context. */
273 RESTOREREGS(SysBase->ThisTask,sc);
275 SysBase->ThisTask->tc_State = TS_RUN;
276 Enable();
279 /* Leave the interrupt. */
281 AROS_ATOMIC_DEC(supervisor);
283 sigactive[sig] = FALSE;
285 } /* sighandler */
287 #if 0
288 static void traphandler(int sig, sigcontext_t *sc)
290 int trapNum = sig2tab[sig];
291 struct Task *this;
293 /* Something VERY bad has happened */
294 if( intrap )
296 fprintf(stderr, "Double TRAP! Aborting!\n");
297 fflush(stderr);
298 abort();
300 intrap++;
302 if( supervisor )
304 fprintf(stderr,"Illegal Supervisor %d - Inside TRAP\n", supervisor);
305 fflush(stderr);
308 /* This is the task that caused the trap... */
309 this = SysBase->ThisTask;
310 AROS_UFC1(void, this->tc_TrapCode,
311 AROS_UFCA(ULONG, trapNum, D0));
313 intrap--;
315 #endif
317 /* Set up the kernel. */
318 void InitCore(void)
321 struct itimerval interval;
322 int i;
323 struct sigaction sa;
325 /* We only want signal that we can handle at the moment */
326 sigfillset(&sa.sa_mask);
327 sigfillset(&sig_int_mask);
328 sa.sa_flags = SA_RESTART;
329 #ifdef __linux__
330 sa.sa_restorer = NULL;
331 #endif
333 /* Initialize the translation table */
334 bzero(sig2tab, sizeof(sig2tab));
335 supervisor = 0;
336 intrap = 0;
338 #if 1
339 /* These ones we consider as processor traps */
340 //sa.sa_handler = (SIGHANDLER_T)TRAPHANDLER;
341 for(i=0; i < (sizeof(sig2trap) / sizeof(sig2trap[0])); i++)
343 sig2tab[sig2trap[i][0]] = sig2trap[i][1];
344 // sigaction( sig2trap[i][0], &sa, NULL);
345 sigdelset( &sig_int_mask, sig2trap[i][0] );
347 #endif
349 /* We want to be signalled - make these interrupts. */
350 #ifdef SIGCORE_NEED_SA_SIGINFO
351 sa.sa_sigaction = (void *)SIGHANDLER;
352 sa.sa_flags |= SA_SIGINFO;
353 #else
354 sa.sa_handler = (SIGHANDLER_T)SIGHANDLER;
355 #endif
356 sa.sa_mask = sig_int_mask;
357 for(i=0; i < (sizeof(sig2int) / sizeof(sig2int[0])); i++)
359 sig2tab[sig2int[i][0]] = sig2int[i][1];
360 sigaction( sig2int[i][0], &sa, NULL );
362 sigaction( SIGINT, &sa, NULL );
364 /* Set up the "pseudo" vertical blank interrupt. */
365 interval.it_interval.tv_sec = interval.it_value.tv_sec = 0;
366 interval.it_interval.tv_usec =
367 interval.it_value.tv_usec = 1000000 / (SysBase->VBlankFrequency * SysBase->PowerSupplyFrequency);
369 setitimer(ITIMER_REAL, &interval, NULL);