2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
5 Desc: Initialize the interface to the "hardware".
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
31 #include <proto/exec.h>
35 static struct Task
* lastTask
;
38 /* Don't do any debugging. At 50Hz its far too quick to read anyway :-) */
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 */
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] =
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)
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
)
95 #if !AROS_NESTING_SUPERVISOR
96 /* Hmm, interrupts are nesting, not a good idea... */
100 fprintf(stderr
, "Illegal Supervisor %d\n", supervisor
);
108 AROS_ATOMIC_INC(supervisor
);
113 fprintf(stderr
,"********* sighandler: sig %d already active **********\n", sig
);
119 sigactive
[sig
] = TRUE
;
121 /* Map the Unix signal to an Amiga signal. */
122 iv
= &SysBase
->IntVects
[sig2tab
[sig
]];
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)
135 A5 - Interrupt Code vector
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
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
];
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
)
185 AROS_ATOMIC_DEC(SysBase
->IDNestCnt
);
188 /* Has an interrupt told us to dispatch when leaving */
190 #if AROS_NESTING_SUPERVISOR
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.
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... */
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
216 if (SysBase
->IDNestCnt
< 0)
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() */
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
)
242 Alert(AT_DeadEnd
|AN_StackProbe
);
247 if (lastTask
!= SysBase
->ThisTask
)
249 fprintf (stderr
, "TT %s\n", SysBase
->ThisTask
->tc_Node
.ln_Name
);
250 lastTask
= SysBase
->ThisTask
;
254 #if AROS_NESTING_SUPERVISOR
255 // Enable(); commented out, as causes problems with IDNestCnt. Getting completely out of range.
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
)
269 Alert(AT_DeadEnd
|AN_StackProbe
);
272 /* Restore the signaled context. */
273 RESTOREREGS(SysBase
->ThisTask
,sc
);
275 SysBase
->ThisTask
->tc_State
= TS_RUN
;
279 /* Leave the interrupt. */
281 AROS_ATOMIC_DEC(supervisor
);
283 sigactive
[sig
] = FALSE
;
288 static void traphandler(int sig
, sigcontext_t
*sc
)
290 int trapNum
= sig2tab
[sig
];
293 /* Something VERY bad has happened */
296 fprintf(stderr
, "Double TRAP! Aborting!\n");
304 fprintf(stderr
,"Illegal Supervisor %d - Inside TRAP\n", supervisor
);
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
));
317 /* Set up the kernel. */
321 struct itimerval interval
;
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
;
330 sa
.sa_restorer
= NULL
;
333 /* Initialize the translation table */
334 bzero(sig2tab
, sizeof(sig2tab
));
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] );
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
;
354 sa
.sa_handler
= (SIGHANDLER_T
)SIGHANDLER
;
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
);