1 |
786 |
skrzyp |
//=============================================================================
|
2 |
|
|
//
|
3 |
|
|
// synth_intr.c
|
4 |
|
|
//
|
5 |
|
|
// Interrupt and clock code for the Linux synthetic target.
|
6 |
|
|
//
|
7 |
|
|
//=============================================================================
|
8 |
|
|
// ####ECOSGPLCOPYRIGHTBEGIN####
|
9 |
|
|
// -------------------------------------------
|
10 |
|
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
11 |
|
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
|
12 |
|
|
//
|
13 |
|
|
// eCos is free software; you can redistribute it and/or modify it under
|
14 |
|
|
// the terms of the GNU General Public License as published by the Free
|
15 |
|
|
// Software Foundation; either version 2 or (at your option) any later
|
16 |
|
|
// version.
|
17 |
|
|
//
|
18 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT
|
19 |
|
|
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
20 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
21 |
|
|
// for more details.
|
22 |
|
|
//
|
23 |
|
|
// You should have received a copy of the GNU General Public License
|
24 |
|
|
// along with eCos; if not, write to the Free Software Foundation, Inc.,
|
25 |
|
|
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
26 |
|
|
//
|
27 |
|
|
// As a special exception, if other files instantiate templates or use
|
28 |
|
|
// macros or inline functions from this file, or you compile this file
|
29 |
|
|
// and link it with other works to produce a work based on this file,
|
30 |
|
|
// this file does not by itself cause the resulting work to be covered by
|
31 |
|
|
// the GNU General Public License. However the source code for this file
|
32 |
|
|
// must still be made available in accordance with section (3) of the GNU
|
33 |
|
|
// General Public License v2.
|
34 |
|
|
//
|
35 |
|
|
// This exception does not invalidate any other reasons why a work based
|
36 |
|
|
// on this file might be covered by the GNU General Public License.
|
37 |
|
|
// -------------------------------------------
|
38 |
|
|
// ####ECOSGPLCOPYRIGHTEND####
|
39 |
|
|
//=============================================================================
|
40 |
|
|
//#####DESCRIPTIONBEGIN####
|
41 |
|
|
//
|
42 |
|
|
// Author(s): bartv
|
43 |
|
|
// Contributors: bartv, asl
|
44 |
|
|
// Date: 2001-03-30
|
45 |
|
|
// Purpose: Implement the interrupt subsystem for the synthetic target
|
46 |
|
|
//####DESCRIPTIONEND####
|
47 |
|
|
//=============================================================================
|
48 |
|
|
|
49 |
|
|
// sigprocmask handling.
|
50 |
|
|
//
|
51 |
|
|
// In the synthetic target interrupts and exceptions are based around
|
52 |
|
|
// POSIX sighandlers. When the clock ticks a SIGALRM signal is raised.
|
53 |
|
|
// When the I/O auxiliary wants to raise some other interrupt, it
|
54 |
|
|
// sends a SIGIO signal. When an exception occurs this results in
|
55 |
|
|
// signals like SIGILL and SIGSEGV. This implies an implementation
|
56 |
|
|
// where the VSR is the signal handler. Disabling interrupts would
|
57 |
|
|
// then mean using sigprocmask() to block certain signals, and
|
58 |
|
|
// enabling interrupts means unblocking those signals.
|
59 |
|
|
//
|
60 |
|
|
// However there are a few problems. One of these is performance: some
|
61 |
|
|
// bits of the system such as buffered tracing make very extensive use
|
62 |
|
|
// of enabling and disabling interrupts, so making a sigprocmask
|
63 |
|
|
// system call each time adds a lot of overhead. More seriously, there
|
64 |
|
|
// is a subtle discrepancy between POSIX signal handling and hardware
|
65 |
|
|
// interrupts. Signal handlers are expected to return, and then the
|
66 |
|
|
// system automatically passes control back to the foreground thread.
|
67 |
|
|
// In the process, the sigprocmask is manipulated before invoking the
|
68 |
|
|
// signal handler and restored afterwards. Interrupt handlers are
|
69 |
|
|
// different: it is quite likely that an interrupt results in another
|
70 |
|
|
// eCos thread being activated, so the signal handler does not
|
71 |
|
|
// actually return until the interrupted thread gets another chance to
|
72 |
|
|
// run.
|
73 |
|
|
//
|
74 |
|
|
// The second problem can be addressed by making the sigprocmask part
|
75 |
|
|
// of the thread state, saving and restoring it as part of a context
|
76 |
|
|
// switch (c.f. siglongjmp()). This matches quite nicely onto typical
|
77 |
|
|
// real hardware, where there might be a flag inside some control
|
78 |
|
|
// register that controls whether or not interrupts are enabled.
|
79 |
|
|
// However this adds more system calls to context switch overhead.
|
80 |
|
|
//
|
81 |
|
|
// The alternative approach is to implement interrupt enabling and
|
82 |
|
|
// disabling in software. The sigprocmask is manipulated only once,
|
83 |
|
|
// during initialization, such that certain signals are allowed
|
84 |
|
|
// through and others are blocked. When a signal is raised the signal
|
85 |
|
|
// handler will always be invoked, but it will decide in software
|
86 |
|
|
// whether or not the signal should be processed immediately. This
|
87 |
|
|
// alternative approach does not correspond particularly well with
|
88 |
|
|
// real hardware: effectively the VSR is always allowed to run.
|
89 |
|
|
// However for typical applications this will not really matter, and
|
90 |
|
|
// the performance gains outweigh the discrepancy.
|
91 |
|
|
//
|
92 |
|
|
// Nested interrupts and interrupt priorities can be implemented in
|
93 |
|
|
// software, specifically by manipulating the current mask of blocked
|
94 |
|
|
// interrupts. This is not currently implemented.
|
95 |
|
|
//
|
96 |
|
|
// At first glance it might seem that an interrupt stack could be
|
97 |
|
|
// implemented trivially using sigaltstack. This does not quite work:
|
98 |
|
|
// signal handlers do not always return immediately, so the system
|
99 |
|
|
// does not get a chance to clean up the signal handling stack. A
|
100 |
|
|
// separate interrupt stack is possible but would have to be
|
101 |
|
|
// implemented here, in software, e.g. by having the signal handler
|
102 |
|
|
// invoke the VSR on that stack. Unfortunately the system may have
|
103 |
|
|
// pushed quite a lot of state on to the current stack already when
|
104 |
|
|
// raising the signal, so things could get messy.
|
105 |
|
|
|
106 |
|
|
// ----------------------------------------------------------------------------
|
107 |
|
|
#include <pkgconf/hal.h>
|
108 |
|
|
#include <pkgconf/hal_synth.h>
|
109 |
|
|
|
110 |
|
|
// There are various dependencies on the kernel, e.g. how exceptions
|
111 |
|
|
// should be handled.
|
112 |
|
|
#include <pkgconf/system.h>
|
113 |
|
|
#ifdef CYGPKG_KERNEL
|
114 |
|
|
# include <pkgconf/kernel.h>
|
115 |
|
|
#endif
|
116 |
|
|
|
117 |
|
|
#include <cyg/infra/cyg_type.h> // base types
|
118 |
|
|
#include <cyg/infra/diag.h>
|
119 |
|
|
#include <cyg/hal/hal_arch.h>
|
120 |
|
|
#include <cyg/hal/hal_intr.h>
|
121 |
|
|
#include <cyg/hal/hal_io.h>
|
122 |
|
|
#include <cyg/infra/cyg_ass.h> // Assertions are safe in the synthetic target
|
123 |
|
|
|
124 |
|
|
#include "synth_protocol.h"
|
125 |
|
|
|
126 |
|
|
// ----------------------------------------------------------------------------
|
127 |
|
|
// Statics.
|
128 |
|
|
|
129 |
|
|
// The bogomips rating, used by HAL_DELAY_US()
|
130 |
|
|
int hal_bogomips;
|
131 |
|
|
|
132 |
|
|
// Are interrupts currently enabled?
|
133 |
|
|
volatile cyg_bool_t hal_interrupts_enabled = false;
|
134 |
|
|
|
135 |
|
|
// These flags are updated by the signal handler when a signal comes in
|
136 |
|
|
// and interrupts are disabled.
|
137 |
|
|
static volatile cyg_bool_t synth_sigio_pending = false;
|
138 |
|
|
static volatile cyg_bool_t synth_sigalrm_pending = false;
|
139 |
|
|
|
140 |
|
|
// The current VSR, to be invoked by the signal handler. This allows
|
141 |
|
|
// application code to install an alternative VSR, without that VSR
|
142 |
|
|
// having to check for interrupts being disabled and updating the
|
143 |
|
|
// pending flags. Effectively, the VSR is only invoked when interrupts
|
144 |
|
|
// are enabled.
|
145 |
|
|
static void (*synth_VSR)(void) = (void (*)(void)) 0;
|
146 |
|
|
|
147 |
|
|
// The current ISR status and mask registers, or rather software
|
148 |
|
|
// emulations thereof. These are not static since application-specific
|
149 |
|
|
// VSRs may want to examine/manipulate these. They are also not
|
150 |
|
|
// exported in any header file, forcing people writing such VSRs to
|
151 |
|
|
// know what they are doing.
|
152 |
|
|
volatile cyg_uint32 synth_pending_isrs = 0;
|
153 |
|
|
volatile cyg_uint32 synth_masked_isrs = 0xFFFFFFFF;
|
154 |
|
|
|
155 |
|
|
// The vector of interrupt handlers.
|
156 |
|
|
typedef struct synth_isr_handler {
|
157 |
|
|
cyg_ISR_t* isr;
|
158 |
|
|
CYG_ADDRWORD data;
|
159 |
|
|
CYG_ADDRESS obj;
|
160 |
|
|
cyg_priority_t pri;
|
161 |
|
|
} synth_isr_handler;
|
162 |
|
|
static synth_isr_handler synth_isr_handlers[CYGNUM_HAL_ISR_COUNT];
|
163 |
|
|
|
164 |
|
|
static void synth_alrm_sighandler(int);
|
165 |
|
|
static void synth_io_sighandler(int);
|
166 |
|
|
|
167 |
|
|
// ----------------------------------------------------------------------------
|
168 |
|
|
// Basic ISR and VSR handling.
|
169 |
|
|
|
170 |
|
|
// The default ISR handler. The system should never receive an interrupt it
|
171 |
|
|
// does not know how to handle.
|
172 |
|
|
static cyg_uint32
|
173 |
|
|
synth_default_isr(cyg_vector_t vector, cyg_addrword_t data)
|
174 |
|
|
{
|
175 |
|
|
CYG_UNUSED_PARAM(cyg_vector_t, vector);
|
176 |
|
|
CYG_UNUSED_PARAM(cyg_addrword_t, data);
|
177 |
|
|
CYG_FAIL("Default isr handler should never get invoked");
|
178 |
|
|
return CYG_ISR_HANDLED;
|
179 |
|
|
}
|
180 |
|
|
|
181 |
|
|
// The VSR is invoked
|
182 |
|
|
// 1) directly by a SIGALRM or SIGIO signal handler, if interrupts
|
183 |
|
|
// were enabled.
|
184 |
|
|
// 2) indirectly by hal_enable_interrupts(), if a signal happened
|
185 |
|
|
// while interrupts were disabled. hal_enable_interrupts()
|
186 |
|
|
// will have re-invoked the signal handler.
|
187 |
|
|
//
|
188 |
|
|
// On entry interrupts are disabled, and there should be one or more
|
189 |
|
|
// pending ISRs which are not masked off.
|
190 |
|
|
//
|
191 |
|
|
// The implementation is as per the HAL specification, where
|
192 |
|
|
// applicable.
|
193 |
|
|
|
194 |
|
|
static void
|
195 |
|
|
synth_default_vsr(void)
|
196 |
|
|
{
|
197 |
|
|
int isr_vector;
|
198 |
|
|
cyg_uint32 isr_result;
|
199 |
|
|
|
200 |
|
|
CYG_ASSERT(!hal_interrupts_enabled, "VSRs should only be invoked when interrupts are disabled");
|
201 |
|
|
CYG_ASSERT(0 != (synth_pending_isrs & ~synth_masked_isrs), "VSRs should only be invoked when an interrupt is pending");
|
202 |
|
|
|
203 |
|
|
// No need to save the cpu state. Either we are in a signal
|
204 |
|
|
// handler and the system has done that for us, or we are called
|
205 |
|
|
// synchronously via enable_interrupts.
|
206 |
|
|
|
207 |
|
|
// Increment the kernel scheduler lock, if the kernel is present.
|
208 |
|
|
// This prevents context switching while interrupt handling is in
|
209 |
|
|
// progress.
|
210 |
|
|
#ifdef CYGFUN_HAL_COMMON_KERNEL_SUPPORT
|
211 |
|
|
cyg_scheduler_lock();
|
212 |
|
|
#endif
|
213 |
|
|
|
214 |
|
|
// Do not switch to an interrupt stack - functionality is not
|
215 |
|
|
// implemented
|
216 |
|
|
|
217 |
|
|
// Do not allow nested interrupts - functionality is not
|
218 |
|
|
// implemented.
|
219 |
|
|
|
220 |
|
|
// Decode the actual external interrupt being delivered. This is
|
221 |
|
|
// determined from the pending and masked variables. Only one isr
|
222 |
|
|
// source can be handled here, since interrupt_end must be invoked
|
223 |
|
|
// with details of that interrupt. Multiple pending interrupts
|
224 |
|
|
// will be handled by a recursive call
|
225 |
|
|
HAL_LSBIT_INDEX(isr_vector, (synth_pending_isrs & ~synth_masked_isrs));
|
226 |
|
|
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= isr_vector) && (isr_vector <= CYGNUM_HAL_ISR_MAX), "ISR vector must be valid");
|
227 |
|
|
|
228 |
|
|
isr_result = (*synth_isr_handlers[isr_vector].isr)(isr_vector, synth_isr_handlers[isr_vector].data);
|
229 |
|
|
|
230 |
|
|
// Do not switch back from the interrupt stack, there isn't one.
|
231 |
|
|
|
232 |
|
|
// Interrupts were not enabled before, so they must be enabled
|
233 |
|
|
// now. This may result in a recursive invocation if other IRQs
|
234 |
|
|
// are still pending. The ISR should have either acknowledged or
|
235 |
|
|
// masked the current interrupt source, to prevent a recursive
|
236 |
|
|
// call for the current interrupt.
|
237 |
|
|
hal_enable_interrupts();
|
238 |
|
|
|
239 |
|
|
// Now call interrupt_end() with the result of the isr and the
|
240 |
|
|
// ISR's object This may return straightaway, or it may result in
|
241 |
|
|
// a context switch to another thread. In the latter case, when
|
242 |
|
|
// the current thread is reactivated we end up back here. The
|
243 |
|
|
// third argument should be a pointer to the saved state, but that
|
244 |
|
|
// is only relevant for thread-aware debugging which is not yet
|
245 |
|
|
// supported by the synthetic target.
|
246 |
|
|
{
|
247 |
|
|
extern void interrupt_end(cyg_uint32, CYG_ADDRESS, HAL_SavedRegisters*);
|
248 |
|
|
interrupt_end(isr_result, synth_isr_handlers[isr_vector].obj, (HAL_SavedRegisters*) 0);
|
249 |
|
|
}
|
250 |
|
|
|
251 |
|
|
// Restore machine state and return to the interrupted thread.
|
252 |
|
|
// That requires no effort here.
|
253 |
|
|
}
|
254 |
|
|
|
255 |
|
|
// Enabling interrupts. If a SIGALRM or SIGIO arrived at an inconvenient
|
256 |
|
|
// time, e.g. when already interacting with the auxiliary, then these
|
257 |
|
|
// will have been left pending and must be serviced now. Next, enabling
|
258 |
|
|
// interrupts means checking the interrupt pending and mask registers
|
259 |
|
|
// and seeing if the VSR should be invoked.
|
260 |
|
|
void
|
261 |
|
|
hal_enable_interrupts(void)
|
262 |
|
|
{
|
263 |
|
|
hal_interrupts_enabled = true;
|
264 |
|
|
if (synth_sigalrm_pending) {
|
265 |
|
|
synth_sigalrm_pending = false;
|
266 |
|
|
synth_alrm_sighandler(CYG_HAL_SYS_SIGALRM);
|
267 |
|
|
}
|
268 |
|
|
if (synth_sigio_pending) {
|
269 |
|
|
synth_sigio_pending = false;
|
270 |
|
|
synth_io_sighandler(CYG_HAL_SYS_SIGIO);
|
271 |
|
|
}
|
272 |
|
|
|
273 |
|
|
// The interrupt mask "register" may have been modified while
|
274 |
|
|
// interrupts were disabled. If there are pending interrupts,
|
275 |
|
|
// invoke the VSR. The VSR must be invoked with interrupts
|
276 |
|
|
// disabled, and will return with interrupts enabled.
|
277 |
|
|
// An alternative implementation that might be more accurate
|
278 |
|
|
// is to raise a signal, e.g. SIGUSR1. That way all interrupts
|
279 |
|
|
// come in via the system's signal handling mechanism, and
|
280 |
|
|
// it might be possible to do something useful with saved contexts
|
281 |
|
|
// etc., facilitating thread-aware debugging.
|
282 |
|
|
if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {
|
283 |
|
|
hal_interrupts_enabled = false;
|
284 |
|
|
(*synth_VSR)();
|
285 |
|
|
CYG_ASSERT( hal_interrupts_enabled, "Interrupts should still be enabled on return from the VSR");
|
286 |
|
|
}
|
287 |
|
|
}
|
288 |
|
|
|
289 |
|
|
// ----------------------------------------------------------------------------
|
290 |
|
|
// Other interrupt-related routines. Mostly these just involve
|
291 |
|
|
// updating some of the statics, but they may be called while
|
292 |
|
|
// interrupts are still enabled so care has to be taken.
|
293 |
|
|
|
294 |
|
|
cyg_bool_t
|
295 |
|
|
hal_interrupt_in_use(cyg_vector_t vec)
|
296 |
|
|
{
|
297 |
|
|
CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only attach to valid ISR vectors");
|
298 |
|
|
return synth_default_isr != synth_isr_handlers[vec].isr;
|
299 |
|
|
}
|
300 |
|
|
|
301 |
|
|
void
|
302 |
|
|
hal_interrupt_attach(cyg_vector_t vec, cyg_ISR_t* isr, CYG_ADDRWORD data, CYG_ADDRESS obj)
|
303 |
|
|
{
|
304 |
|
|
CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only attach to valid ISR vectors");
|
305 |
|
|
CYG_CHECK_FUNC_PTR( isr, "A valid ISR must be supplied");
|
306 |
|
|
// The object cannot be validated, it may be NULL if chained
|
307 |
|
|
// interrupts are enabled.
|
308 |
|
|
CYG_ASSERT( synth_isr_handlers[vec].isr == &synth_default_isr, "Only one ISR can be attached to a vector at the HAL level");
|
309 |
|
|
CYG_ASSERT( (false == hal_interrupts_enabled) || (0 != (synth_masked_isrs & (0x01 << vec))), "ISRs should only be attached when it is safe");
|
310 |
|
|
|
311 |
|
|
// The priority will have been installed shortly before this call.
|
312 |
|
|
synth_isr_handlers[vec].isr = isr;
|
313 |
|
|
synth_isr_handlers[vec].data = data;
|
314 |
|
|
synth_isr_handlers[vec].obj = obj;
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
void
|
318 |
|
|
hal_interrupt_detach(cyg_vector_t vec, cyg_ISR_t* isr)
|
319 |
|
|
{
|
320 |
|
|
CYG_ASSERT( (CYGNUM_HAL_ISR_MIN <= vec) && (vec <= CYGNUM_HAL_ISR_MAX), "Can only detach from valid ISR vectors");
|
321 |
|
|
CYG_CHECK_FUNC_PTR( isr, "A valid ISR must be supplied");
|
322 |
|
|
CYG_ASSERT( isr != &synth_default_isr, "An ISR must be attached before it can be detached");
|
323 |
|
|
CYG_ASSERT( (false == hal_interrupts_enabled) || (0 != (synth_masked_isrs & (0x01 << vec))), "ISRs should only be detached when it is safe");
|
324 |
|
|
|
325 |
|
|
// The Cyg_Interrupt destructor does an unconditional detach, even if the
|
326 |
|
|
// isr is not currently attached.
|
327 |
|
|
if (isr == synth_isr_handlers[vec].isr) {
|
328 |
|
|
synth_isr_handlers[vec].isr = &synth_default_isr;
|
329 |
|
|
synth_isr_handlers[vec].data = (CYG_ADDRWORD) 0;
|
330 |
|
|
synth_isr_handlers[vec].obj = (CYG_ADDRESS) 0;
|
331 |
|
|
}
|
332 |
|
|
|
333 |
|
|
// The priority is not updated here. This should be ok, if another
|
334 |
|
|
// isr is attached then the appropriate priority will be installed
|
335 |
|
|
// first.
|
336 |
|
|
}
|
337 |
|
|
|
338 |
|
|
void (*hal_vsr_get(cyg_vector_t vec))(void)
|
339 |
|
|
{
|
340 |
|
|
CYG_ASSERT( (CYGNUM_HAL_VSR_MIN <= vec) && (vec <= CYGNUM_HAL_VSR_MAX), "Can only get valid VSR vectors");
|
341 |
|
|
return synth_VSR;
|
342 |
|
|
}
|
343 |
|
|
|
344 |
|
|
void
|
345 |
|
|
hal_vsr_set(cyg_vector_t vec, void (*new_vsr)(void), void (**old_vsrp)(void))
|
346 |
|
|
{
|
347 |
|
|
cyg_bool_t old;
|
348 |
|
|
|
349 |
|
|
CYG_ASSERT( (CYGNUM_HAL_VSR_MIN <= vec) && (vec <= CYGNUM_HAL_VSR_MAX), "Can only get valid VSR vectors");
|
350 |
|
|
CYG_CHECK_FUNC_PTR( new_vsr, "A valid VSR must be supplied");
|
351 |
|
|
|
352 |
|
|
// There is a theoretical possibility of two hal_vsr_set calls at
|
353 |
|
|
// the same time. The old and new VSRs must be kept in synch.
|
354 |
|
|
HAL_DISABLE_INTERRUPTS(old);
|
355 |
|
|
if (0 != old_vsrp) {
|
356 |
|
|
*old_vsrp = synth_VSR;
|
357 |
|
|
}
|
358 |
|
|
synth_VSR = new_vsr;
|
359 |
|
|
HAL_RESTORE_INTERRUPTS(old);
|
360 |
|
|
}
|
361 |
|
|
|
362 |
|
|
void
|
363 |
|
|
hal_interrupt_mask(cyg_vector_t which)
|
364 |
|
|
{
|
365 |
|
|
CYG_PRECONDITION( !hal_interrupts_enabled, "Interrupts should be disabled on entry to hal_interrupt_mask");
|
366 |
|
|
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
|
367 |
|
|
synth_masked_isrs |= (0x01 << which);
|
368 |
|
|
}
|
369 |
|
|
|
370 |
|
|
void
|
371 |
|
|
hal_interrupt_unmask(cyg_vector_t which)
|
372 |
|
|
{
|
373 |
|
|
CYG_PRECONDITION( !hal_interrupts_enabled, "Interrupts should be disabled on entry to hal_interrupt_unmask");
|
374 |
|
|
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
|
375 |
|
|
synth_masked_isrs &= ~(0x01 << which);
|
376 |
|
|
}
|
377 |
|
|
|
378 |
|
|
void
|
379 |
|
|
hal_interrupt_acknowledge(cyg_vector_t which)
|
380 |
|
|
{
|
381 |
|
|
cyg_bool_t old;
|
382 |
|
|
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
|
383 |
|
|
|
384 |
|
|
// Acknowledging an interrupt means clearing the bit in the
|
385 |
|
|
// interrupt pending "register".
|
386 |
|
|
// NOTE: does the auxiliary need to keep track of this? Probably
|
387 |
|
|
// not, the auxiliary can just raise SIGIO whenever a device wants
|
388 |
|
|
// attention. There may be a trade off here between additional
|
389 |
|
|
// communication and unnecessary SIGIOs.
|
390 |
|
|
HAL_DISABLE_INTERRUPTS(old);
|
391 |
|
|
synth_pending_isrs &= ~(0x01 << which);
|
392 |
|
|
HAL_RESTORE_INTERRUPTS(old);
|
393 |
|
|
}
|
394 |
|
|
|
395 |
|
|
void
|
396 |
|
|
hal_interrupt_configure(cyg_vector_t which, cyg_bool_t level, cyg_bool_t up)
|
397 |
|
|
{
|
398 |
|
|
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
|
399 |
|
|
// The synthetic target does not currently distinguish between
|
400 |
|
|
// level and edge interrupts. Possibly this information will have
|
401 |
|
|
// to be passed on to the auxiliary in future.
|
402 |
|
|
CYG_UNUSED_PARAM(cyg_vector_t, which);
|
403 |
|
|
CYG_UNUSED_PARAM(cyg_bool_t, level);
|
404 |
|
|
CYG_UNUSED_PARAM(cyg_bool_t, up);
|
405 |
|
|
}
|
406 |
|
|
|
407 |
|
|
void
|
408 |
|
|
hal_interrupt_set_level(cyg_vector_t which, cyg_priority_t level)
|
409 |
|
|
{
|
410 |
|
|
CYG_ASSERT((CYGNUM_HAL_ISR_MIN <= which) && (which <= CYGNUM_HAL_ISR_MAX), "A valid ISR vector must be supplied");
|
411 |
|
|
// The legal values for priorities are not defined at this time.
|
412 |
|
|
// Manipulating the interrupt priority level currently has no
|
413 |
|
|
// effect. The information is stored anyway, for future use.
|
414 |
|
|
synth_isr_handlers[which].pri = level;
|
415 |
|
|
}
|
416 |
|
|
|
417 |
|
|
// ----------------------------------------------------------------------------
|
418 |
|
|
// Exception handling. Typically this involves calling into the kernel,
|
419 |
|
|
// translating the POSIX signal number into a HAL exception number. In
|
420 |
|
|
// practice these signals will generally be caught in the debugger and
|
421 |
|
|
// will not have to be handled by eCos itself.
|
422 |
|
|
|
423 |
|
|
static void
|
424 |
|
|
synth_exception_sighandler(int sig)
|
425 |
|
|
{
|
426 |
|
|
CYG_WORD ecos_exception_number = 0;
|
427 |
|
|
cyg_bool_t old;
|
428 |
|
|
|
429 |
|
|
// There is no need to save state, that will have been done by the
|
430 |
|
|
// system as part of the signal delivery process.
|
431 |
|
|
|
432 |
|
|
// Disable interrupts. Performing e.g. an interaction with the
|
433 |
|
|
// auxiliary after a SIGSEGV is dubious.
|
434 |
|
|
HAL_DISABLE_INTERRUPTS(old);
|
435 |
|
|
|
436 |
|
|
// Now decode the signal and turn it into an eCos exception.
|
437 |
|
|
switch(sig) {
|
438 |
|
|
case CYG_HAL_SYS_SIGILL:
|
439 |
|
|
ecos_exception_number = CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION;
|
440 |
|
|
break;
|
441 |
|
|
case CYG_HAL_SYS_SIGBUS:
|
442 |
|
|
case CYG_HAL_SYS_SIGSEGV:
|
443 |
|
|
ecos_exception_number = CYGNUM_HAL_EXCEPTION_DATA_ACCESS;
|
444 |
|
|
break;
|
445 |
|
|
case CYG_HAL_SYS_SIGFPE:
|
446 |
|
|
ecos_exception_number = CYGNUM_HAL_EXCEPTION_FPU;
|
447 |
|
|
break;
|
448 |
|
|
default:
|
449 |
|
|
CYG_FAIL("Unknown signal");
|
450 |
|
|
break;
|
451 |
|
|
}
|
452 |
|
|
|
453 |
|
|
#ifdef CYGPKG_KERNEL_EXCEPTIONS
|
454 |
|
|
// Deliver the signal, usually to the kernel, possibly to the
|
455 |
|
|
// common HAL. The second argument should be the current
|
456 |
|
|
// savestate, but that is not readily accessible.
|
457 |
|
|
cyg_hal_deliver_exception(ecos_exception_number, (CYG_ADDRWORD) 0);
|
458 |
|
|
|
459 |
|
|
// It is now necessary to restore the machine state, including
|
460 |
|
|
// interrupts. In theory higher level code may have manipulated
|
461 |
|
|
// the machine state to prevent any recurrence of the exception.
|
462 |
|
|
// In practice the machine state is not readily accessible.
|
463 |
|
|
HAL_RESTORE_INTERRUPTS(old);
|
464 |
|
|
#else
|
465 |
|
|
CYG_FAIL("Exception!!!");
|
466 |
|
|
for (;;);
|
467 |
|
|
#endif
|
468 |
|
|
}
|
469 |
|
|
|
470 |
|
|
// ----------------------------------------------------------------------------
|
471 |
|
|
// The clock support. This can be implemented using the setitimer()
|
472 |
|
|
// and getitimer() calls. The kernel will install a suitable interrupt
|
473 |
|
|
// handler for CYGNUM_HAL_INTERRUPT_RTC, but it depends on the HAL
|
474 |
|
|
// for low-level manipulation of the clock hardware.
|
475 |
|
|
//
|
476 |
|
|
// There is a problem with HAL_CLOCK_READ(). The obvious
|
477 |
|
|
// implementation would use getitimer(), but that has the wrong
|
478 |
|
|
// behaviour: it is intended for fairly coarse intervals and works in
|
479 |
|
|
// terms of system clock ticks, as opposed to a fine-grained
|
480 |
|
|
// implementation that actually examines the system clock. Instead use
|
481 |
|
|
// gettimeofday().
|
482 |
|
|
|
483 |
|
|
static struct cyg_hal_sys_timeval synth_clock = { 0, 0 };
|
484 |
|
|
|
485 |
|
|
void
|
486 |
|
|
hal_clock_initialize(cyg_uint32 period)
|
487 |
|
|
{
|
488 |
|
|
struct cyg_hal_sys_itimerval timer;
|
489 |
|
|
|
490 |
|
|
// Needed for hal_clock_read(), if HAL_CLOCK_READ() is used before
|
491 |
|
|
// the first clock interrupt.
|
492 |
|
|
cyg_hal_sys_gettimeofday(&synth_clock, (struct cyg_hal_sys_timezone*) 0);
|
493 |
|
|
|
494 |
|
|
// The synthetic target clock resolution is in microseconds. A typical
|
495 |
|
|
// value for the period will be 10000, corresponding to one timer
|
496 |
|
|
// interrupt every 10ms. Set up a timer to interrupt in period us,
|
497 |
|
|
// and again every period us after that.
|
498 |
|
|
CYG_ASSERT( period < 1000000, "Clock interrupts should happen at least once per second");
|
499 |
|
|
timer.hal_it_interval.hal_tv_sec = 0;
|
500 |
|
|
timer.hal_it_interval.hal_tv_usec = period;
|
501 |
|
|
timer.hal_it_value.hal_tv_sec = 0;
|
502 |
|
|
timer.hal_it_value.hal_tv_usec = period;
|
503 |
|
|
|
504 |
|
|
if (0 != cyg_hal_sys_setitimer(CYG_HAL_SYS_ITIMER_REAL, &timer, (struct cyg_hal_sys_itimerval*) 0)) {
|
505 |
|
|
CYG_FAIL("Failed to initialize the clock itimer");
|
506 |
|
|
}
|
507 |
|
|
}
|
508 |
|
|
|
509 |
|
|
static void
|
510 |
|
|
synth_alrm_sighandler(int sig)
|
511 |
|
|
{
|
512 |
|
|
CYG_PRECONDITION((CYG_HAL_SYS_SIGALRM == sig), "Only SIGALRM should be handled here");
|
513 |
|
|
|
514 |
|
|
if (!hal_interrupts_enabled) {
|
515 |
|
|
synth_sigalrm_pending = true;
|
516 |
|
|
return;
|
517 |
|
|
}
|
518 |
|
|
|
519 |
|
|
// Interrupts were enabled, but must be blocked before any further processing.
|
520 |
|
|
hal_interrupts_enabled = false;
|
521 |
|
|
|
522 |
|
|
// Update the cached value of the clock for hal_clock_read()
|
523 |
|
|
cyg_hal_sys_gettimeofday(&synth_clock, (struct cyg_hal_sys_timezone*) 0);
|
524 |
|
|
|
525 |
|
|
// Update the interrupt status "register" to match pending interrupts
|
526 |
|
|
// A timer signal means that IRQ 0 needs attention.
|
527 |
|
|
synth_pending_isrs |= 0x01;
|
528 |
|
|
|
529 |
|
|
// If any of the pending interrupts are not masked, invoke the
|
530 |
|
|
// VSR. That will reenable interrupts.
|
531 |
|
|
if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {
|
532 |
|
|
(*synth_VSR)();
|
533 |
|
|
} else {
|
534 |
|
|
hal_interrupts_enabled = true;
|
535 |
|
|
}
|
536 |
|
|
|
537 |
|
|
// The VSR will have invoked interrupt_end() with interrupts
|
538 |
|
|
// enabled, and they should still be enabled.
|
539 |
|
|
CYG_ASSERT( hal_interrupts_enabled, "Interrupts should still be enabled on return from the VSR");
|
540 |
|
|
}
|
541 |
|
|
|
542 |
|
|
// Implementing hal_clock_read(). gettimeofday() in conjunction with
|
543 |
|
|
// synth_clock gives the time since the last clock tick in
|
544 |
|
|
// microseconds, the correct unit for the synthetic target.
|
545 |
|
|
cyg_uint32
|
546 |
|
|
hal_clock_read(void)
|
547 |
|
|
{
|
548 |
|
|
int elapsed;
|
549 |
|
|
struct cyg_hal_sys_timeval now;
|
550 |
|
|
cyg_hal_sys_gettimeofday(&now, (struct cyg_hal_sys_timezone*) 0);
|
551 |
|
|
|
552 |
|
|
elapsed = (1000000 * (now.hal_tv_sec - synth_clock.hal_tv_sec)) + (now.hal_tv_usec - synth_clock.hal_tv_usec);
|
553 |
|
|
return elapsed;
|
554 |
|
|
}
|
555 |
|
|
|
556 |
|
|
// ----------------------------------------------------------------------------
|
557 |
|
|
// The signal handler for SIGIO. This can also be invoked by
|
558 |
|
|
// hal_enable_interrupts() to catch up with any signals that arrived
|
559 |
|
|
// while interrupts were disabled. SIGIO is raised by the auxiliary
|
560 |
|
|
// when it requires attention, i.e. when one or more of the devices
|
561 |
|
|
// want to raise an interrupt. Finding out exactly which interrupt(s)
|
562 |
|
|
// are currently pending in the auxiliary requires communication with
|
563 |
|
|
// the auxiliary.
|
564 |
|
|
//
|
565 |
|
|
// If interrupts are currently disabled then the signal cannot be
|
566 |
|
|
// handled immediately. In particular SIGIO cannot be handled because
|
567 |
|
|
// there may already be ongoing communication with the auxiliary.
|
568 |
|
|
// Instead some volatile flags are used to keep track of which signals
|
569 |
|
|
// were raised while interrupts were disabled.
|
570 |
|
|
//
|
571 |
|
|
// It might be better to perform the interaction with the auxiliary
|
572 |
|
|
// as soon as possible, i.e. either in the SIGIO handler or when the
|
573 |
|
|
// current communication completes. That way the mask of pending
|
574 |
|
|
// interrupts would remain up to date even when interrupts are
|
575 |
|
|
// disabled, thus allowing applications to run in polled mode.
|
576 |
|
|
|
577 |
|
|
// A little utility called when the auxiliary has been asked to exit,
|
578 |
|
|
// implicitly affecting this application as well. The sole purpose
|
579 |
|
|
// of this function is to put a suitably-named function on the stack
|
580 |
|
|
// to make it more obvious from inside gdb what is happening.
|
581 |
|
|
static void
|
582 |
|
|
synth_io_handle_shutdown_request_from_auxiliary(void)
|
583 |
|
|
{
|
584 |
|
|
cyg_hal_sys_exit(0);
|
585 |
|
|
}
|
586 |
|
|
|
587 |
|
|
static void
|
588 |
|
|
synth_io_sighandler(int sig)
|
589 |
|
|
{
|
590 |
|
|
CYG_PRECONDITION((CYG_HAL_SYS_SIGIO == sig), "Only SIGIO should be handled here");
|
591 |
|
|
|
592 |
|
|
if (!hal_interrupts_enabled) {
|
593 |
|
|
synth_sigio_pending = true;
|
594 |
|
|
return;
|
595 |
|
|
}
|
596 |
|
|
|
597 |
|
|
// Interrupts were enabled, but must be blocked before any further processing.
|
598 |
|
|
hal_interrupts_enabled = false;
|
599 |
|
|
|
600 |
|
|
// Update the interrupt status "register" to match pending interrupts
|
601 |
|
|
// Contact the auxiliary to find out what interrupts are currently pending there.
|
602 |
|
|
// If there is no auxiliary at present, e.g. because it has just terminated
|
603 |
|
|
// and things are generally somewhat messy, ignore it.
|
604 |
|
|
//
|
605 |
|
|
// This code also deals with the case where the user has requested program
|
606 |
|
|
// termination. It would be wrong for the auxiliary to just exit, since the
|
607 |
|
|
// application could not distinguish that case from a crash. Instead the
|
608 |
|
|
// auxiliary can optionally return an additional byte of data, and if that
|
609 |
|
|
// byte actually gets sent then that indicates pending termination.
|
610 |
|
|
if (synth_auxiliary_running) {
|
611 |
|
|
int result;
|
612 |
|
|
int actual_len;
|
613 |
|
|
unsigned char dummy[1];
|
614 |
|
|
synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_GET_IRQPENDING, 0, 0,
|
615 |
|
|
(const unsigned char*) 0, 0, // The auxiliary does not need any additional data
|
616 |
|
|
&result, dummy, &actual_len, 1);
|
617 |
|
|
synth_pending_isrs |= result;
|
618 |
|
|
if (actual_len) {
|
619 |
|
|
// The auxiliary has been asked to terminate by the user. This
|
620 |
|
|
// request has now been passed on to the eCos application.
|
621 |
|
|
synth_io_handle_shutdown_request_from_auxiliary();
|
622 |
|
|
}
|
623 |
|
|
}
|
624 |
|
|
|
625 |
|
|
// If any of the pending interrupts are not masked, invoke the VSR
|
626 |
|
|
if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {
|
627 |
|
|
(*synth_VSR)();
|
628 |
|
|
} else {
|
629 |
|
|
hal_interrupts_enabled = true;
|
630 |
|
|
}
|
631 |
|
|
|
632 |
|
|
// The VSR will have invoked interrupt_end() with interrupts
|
633 |
|
|
// enabled, and they should still be enabled.
|
634 |
|
|
CYG_ASSERT( hal_interrupts_enabled, "Interrupts should still be enabled on return from the VSR");
|
635 |
|
|
}
|
636 |
|
|
|
637 |
|
|
// ----------------------------------------------------------------------------
|
638 |
|
|
// Here we define an action to do in the idle thread. For the
|
639 |
|
|
// synthetic target it makes no sense to spin eating processor time
|
640 |
|
|
// that other processes could make use of. Instead we call select. The
|
641 |
|
|
// itimer will still go off and kick the scheduler back into life,
|
642 |
|
|
// giving us an escape path from the select. There is one problem: in
|
643 |
|
|
// some configurations, e.g. when preemption is disabled, the idle
|
644 |
|
|
// thread must yield continuously rather than blocking.
|
645 |
|
|
void
|
646 |
|
|
hal_idle_thread_action(cyg_uint32 loop_count)
|
647 |
|
|
{
|
648 |
|
|
#ifndef CYGIMP_HAL_IDLE_THREAD_SPIN
|
649 |
|
|
cyg_hal_sys__newselect(0,
|
650 |
|
|
(struct cyg_hal_sys_fd_set*) 0,
|
651 |
|
|
(struct cyg_hal_sys_fd_set*) 0,
|
652 |
|
|
(struct cyg_hal_sys_fd_set*) 0,
|
653 |
|
|
(struct cyg_hal_sys_timeval*) 0);
|
654 |
|
|
#endif
|
655 |
|
|
CYG_UNUSED_PARAM(cyg_uint32, loop_count);
|
656 |
|
|
}
|
657 |
|
|
|
658 |
|
|
// ----------------------------------------------------------------------------
|
659 |
|
|
// The I/O auxiliary.
|
660 |
|
|
//
|
661 |
|
|
// I/O happens via an auxiliary process. During startup this code attempts
|
662 |
|
|
// to locate and execute a program ecosynth which should be installed in
|
663 |
|
|
// ../libexec/ecosynth relative to some directory on the search path.
|
664 |
|
|
// Subsequent I/O operations involve interacting with this auxiliary.
|
665 |
|
|
|
666 |
|
|
#define MAKESTRING1(a) #a
|
667 |
|
|
#define MAKESTRING2(a) MAKESTRING1(a)
|
668 |
|
|
#define AUXILIARY "../libexec/ecos/hal/synth/arch/" MAKESTRING2(CYGPKG_HAL_SYNTH) "/ecosynth"
|
669 |
|
|
|
670 |
|
|
// Is the auxiliary up and running?
|
671 |
|
|
cyg_bool synth_auxiliary_running = false;
|
672 |
|
|
|
673 |
|
|
// The pipes to and from the auxiliary.
|
674 |
|
|
static int to_aux = -1;
|
675 |
|
|
static int from_aux = -1;
|
676 |
|
|
|
677 |
|
|
// Attempt to start up the auxiliary. Note that this happens early on
|
678 |
|
|
// during system initialization so it is "known" that the world is
|
679 |
|
|
// still simple, e.g. that no other files have been opened.
|
680 |
|
|
static void
|
681 |
|
|
synth_start_auxiliary(void)
|
682 |
|
|
{
|
683 |
|
|
#define BUFSIZE 256
|
684 |
|
|
char filename[BUFSIZE];
|
685 |
|
|
const char* path = 0;
|
686 |
|
|
int i, j;
|
687 |
|
|
cyg_bool found = false;
|
688 |
|
|
int to_aux_pipe[2];
|
689 |
|
|
int from_aux_pipe[2];
|
690 |
|
|
int child;
|
691 |
|
|
int aux_version;
|
692 |
|
|
#if 1
|
693 |
|
|
// Check for a command line argument -io. Only run the auxiliary if this
|
694 |
|
|
// argument is provided, i.e. default to traditional behaviour.
|
695 |
|
|
for (i = 1; i < cyg_hal_sys_argc; i++) {
|
696 |
|
|
const char* tmp = cyg_hal_sys_argv[i];
|
697 |
|
|
if ('-' == *tmp) {
|
698 |
|
|
// Arguments beyond -- are reserved for use by the application,
|
699 |
|
|
// and should not be interpreted by the HAL itself or by ecosynth.
|
700 |
|
|
if (('-' == tmp[1]) && ('\0' == tmp[2])) {
|
701 |
|
|
break;
|
702 |
|
|
}
|
703 |
|
|
tmp++;
|
704 |
|
|
if ('-' == *tmp) {
|
705 |
|
|
// Do not distinguish between -io and --io
|
706 |
|
|
tmp++;
|
707 |
|
|
}
|
708 |
|
|
if (('i' == tmp[0]) && ('o' == tmp[1]) && ('\0' == tmp[2])) {
|
709 |
|
|
found = 1;
|
710 |
|
|
break;
|
711 |
|
|
}
|
712 |
|
|
}
|
713 |
|
|
}
|
714 |
|
|
if (!found) {
|
715 |
|
|
return;
|
716 |
|
|
}
|
717 |
|
|
#else
|
718 |
|
|
// Check for a command line argument -ni or -nio. Always run the
|
719 |
|
|
// auxiliary unless this argument is given, i.e. default to full
|
720 |
|
|
// I/O support.
|
721 |
|
|
for (i = 1; i < cyg_hal_sys_argc; i++) {
|
722 |
|
|
const char* tmp = cyg_hal_sys_argv[i];
|
723 |
|
|
if ('-' == *tmp) {
|
724 |
|
|
if (('-' == tmp[1]) && ('\0' == tmp[2])) {
|
725 |
|
|
break;
|
726 |
|
|
}
|
727 |
|
|
tmp++;
|
728 |
|
|
if ('-' == *tmp) {
|
729 |
|
|
tmp++;
|
730 |
|
|
}
|
731 |
|
|
if ('n' == *tmp) {
|
732 |
|
|
tmp++;
|
733 |
|
|
if ('i' == *tmp) {
|
734 |
|
|
tmp++;
|
735 |
|
|
if ('\0' == *tmp) {
|
736 |
|
|
found = 1; // -ni or --ni
|
737 |
|
|
break;
|
738 |
|
|
}
|
739 |
|
|
if (('o' == *tmp) && ('\0' == tmp[1])) {
|
740 |
|
|
found = 1; // -nio or --nio
|
741 |
|
|
break;
|
742 |
|
|
}
|
743 |
|
|
}
|
744 |
|
|
}
|
745 |
|
|
}
|
746 |
|
|
}
|
747 |
|
|
if (found) {
|
748 |
|
|
return;
|
749 |
|
|
}
|
750 |
|
|
#endif
|
751 |
|
|
|
752 |
|
|
// The auxiliary must be found relative to the current search path,
|
753 |
|
|
// so look for a PATH= environment variable.
|
754 |
|
|
for (i = 0; (0 == path) && (0 != cyg_hal_sys_environ[i]); i++) {
|
755 |
|
|
const char *var = cyg_hal_sys_environ[i];
|
756 |
|
|
if (('P' == var[0]) && ('A' == var[1]) && ('T' == var[2]) && ('H' == var[3]) && ('=' == var[4])) {
|
757 |
|
|
path = var + 5;
|
758 |
|
|
}
|
759 |
|
|
}
|
760 |
|
|
if (0 == path) {
|
761 |
|
|
// Very unlikely, but just in case.
|
762 |
|
|
path = ".:/bin:/usr/bin";
|
763 |
|
|
}
|
764 |
|
|
|
765 |
|
|
found = 0;
|
766 |
|
|
while (!found && ('\0' != *path)) { // for every entry in the path
|
767 |
|
|
char *tmp = AUXILIARY;
|
768 |
|
|
|
769 |
|
|
j = 0;
|
770 |
|
|
|
771 |
|
|
// As a special case, an empty string in the path corresponds to the
|
772 |
|
|
// current directory.
|
773 |
|
|
if (':' == *path) {
|
774 |
|
|
filename[j++] = '.';
|
775 |
|
|
path++;
|
776 |
|
|
} else {
|
777 |
|
|
while ((j < BUFSIZE) && ('\0' != *path) && (':' != *path)) {
|
778 |
|
|
filename[j++] = *path++;
|
779 |
|
|
}
|
780 |
|
|
// If not at the end of the search path, move on to the next entry.
|
781 |
|
|
if ('\0' != *path) {
|
782 |
|
|
while ((':' != *path) && ('\0' != *path)) {
|
783 |
|
|
path++;
|
784 |
|
|
}
|
785 |
|
|
if (':' == *path) {
|
786 |
|
|
path++;
|
787 |
|
|
}
|
788 |
|
|
}
|
789 |
|
|
}
|
790 |
|
|
// Now append a directory separator, and then the name of the executable.
|
791 |
|
|
if (j < BUFSIZE) {
|
792 |
|
|
filename[j++] = '/';
|
793 |
|
|
}
|
794 |
|
|
while ((j < BUFSIZE) && ('\0' != *tmp)) {
|
795 |
|
|
filename[j++] = *tmp++;
|
796 |
|
|
}
|
797 |
|
|
// If there has been a buffer overflow, skip this entry.
|
798 |
|
|
if (j == BUFSIZE) {
|
799 |
|
|
filename[BUFSIZE-1] = '\0';
|
800 |
|
|
diag_printf("Warning: buffer limit reached while searching PATH for the I/O auxiliary.\n");
|
801 |
|
|
diag_printf(" : skipping current entry.\n");
|
802 |
|
|
} else {
|
803 |
|
|
// filename now contains a possible match for the auxiliary.
|
804 |
|
|
filename[j++] = '\0';
|
805 |
|
|
if (0 == cyg_hal_sys_access(filename, CYG_HAL_SYS_X_OK)) {
|
806 |
|
|
found = true;
|
807 |
|
|
}
|
808 |
|
|
}
|
809 |
|
|
}
|
810 |
|
|
#undef BUFSIZE
|
811 |
|
|
|
812 |
|
|
if (!found) {
|
813 |
|
|
diag_printf("Error: unable to find the I/O auxiliary program on the current search PATH\n");
|
814 |
|
|
diag_printf(" : please install the appropriate host-side tools.\n");
|
815 |
|
|
cyg_hal_sys_exit(1);
|
816 |
|
|
}
|
817 |
|
|
|
818 |
|
|
// An apparently valid executable exists (or at the very least it existed...),
|
819 |
|
|
// so create the pipes that will be used for communication.
|
820 |
|
|
if ((0 != cyg_hal_sys_pipe(to_aux_pipe)) ||
|
821 |
|
|
(0 != cyg_hal_sys_pipe(from_aux_pipe))) {
|
822 |
|
|
diag_printf("Error: unable to set up pipes for communicating with the I/O auxiliary.\n");
|
823 |
|
|
cyg_hal_sys_exit(1);
|
824 |
|
|
}
|
825 |
|
|
|
826 |
|
|
// Time to fork().
|
827 |
|
|
child = cyg_hal_sys_fork();
|
828 |
|
|
if (child < 0) {
|
829 |
|
|
diag_printf("Error: failed to fork() process for the I/O auxiliary.\n");
|
830 |
|
|
cyg_hal_sys_exit(1);
|
831 |
|
|
} else if (child == 0) {
|
832 |
|
|
cyg_bool found_dotdot;
|
833 |
|
|
// There should not be any problems rearranging the file descriptors as desired...
|
834 |
|
|
cyg_bool unexpected_error = 0;
|
835 |
|
|
|
836 |
|
|
// In the child process. Close unwanted file descriptors, then some dup2'ing,
|
837 |
|
|
// and execve() the I/O auxiliary. The auxiliary will inherit stdin,
|
838 |
|
|
// stdout and stderr from the eCos application, so that functions like
|
839 |
|
|
// printf() work as expected. In addition fd 3 will be the pipe from
|
840 |
|
|
// the eCos application and fd 4 the pipe to the application. It is possible
|
841 |
|
|
// that the eCos application was run from some process other than a shell
|
842 |
|
|
// and hence that file descriptors 3 and 4 are already in use, but that is not
|
843 |
|
|
// supported. One possible workaround would be to close all file descriptors
|
844 |
|
|
// >= 3, another would be to munge the argument vector passing the file
|
845 |
|
|
// descriptors actually being used.
|
846 |
|
|
unexpected_error |= (0 != cyg_hal_sys_close(to_aux_pipe[1]));
|
847 |
|
|
unexpected_error |= (0 != cyg_hal_sys_close(from_aux_pipe[0]));
|
848 |
|
|
|
849 |
|
|
if (3 != to_aux_pipe[0]) {
|
850 |
|
|
if (3 == from_aux_pipe[1]) {
|
851 |
|
|
// Because to_aux_pipe[] was set up first it should have received file descriptors 3 and 4.
|
852 |
|
|
diag_printf("Internal error: file descriptors have been allocated in an unusual order.\n");
|
853 |
|
|
cyg_hal_sys_exit(1);
|
854 |
|
|
} else {
|
855 |
|
|
unexpected_error |= (3 != cyg_hal_sys_dup2(to_aux_pipe[0], 3));
|
856 |
|
|
unexpected_error |= (0 != cyg_hal_sys_close(to_aux_pipe[0]));
|
857 |
|
|
}
|
858 |
|
|
}
|
859 |
|
|
if (4 != from_aux_pipe[1]) {
|
860 |
|
|
unexpected_error |= (4 != cyg_hal_sys_dup2(from_aux_pipe[1], 4));
|
861 |
|
|
unexpected_error |= (0 != cyg_hal_sys_close(from_aux_pipe[1]));
|
862 |
|
|
}
|
863 |
|
|
if (unexpected_error) {
|
864 |
|
|
diag_printf("Error: internal error in auxiliary process, failed to manipulate pipes.\n");
|
865 |
|
|
cyg_hal_sys_exit(1);
|
866 |
|
|
}
|
867 |
|
|
// The arguments passed to the auxiliary are mostly those for
|
868 |
|
|
// the synthetic target application, except for argv[0] which
|
869 |
|
|
// is replaced with the auxiliary's pathname. The latter
|
870 |
|
|
// currently holds at least one ../, and cleaning this up is
|
871 |
|
|
// useful.
|
872 |
|
|
//
|
873 |
|
|
// If the argument vector contains -- then that and subsequent
|
874 |
|
|
// arguments are not passed to the auxiliary. Instead such
|
875 |
|
|
// arguments are reserved for use by the application.
|
876 |
|
|
do {
|
877 |
|
|
int len;
|
878 |
|
|
for (len = 0; '\0' != filename[len]; len++)
|
879 |
|
|
;
|
880 |
|
|
found_dotdot = false;
|
881 |
|
|
for (i = 0; i < (len - 4); i++) {
|
882 |
|
|
if (('/' == filename[i]) && ('.' == filename[i+1]) && ('.' == filename[i+2]) && ('/' == filename[i+3])) {
|
883 |
|
|
j = i + 3;
|
884 |
|
|
for ( --i; (i >= 0) && ('/' != filename[i]); i--) {
|
885 |
|
|
CYG_EMPTY_STATEMENT;
|
886 |
|
|
}
|
887 |
|
|
if (i >= 0) {
|
888 |
|
|
found_dotdot = true;
|
889 |
|
|
do {
|
890 |
|
|
i++; j++;
|
891 |
|
|
filename[i] = filename[j];
|
892 |
|
|
} while ('\0' != filename[i]);
|
893 |
|
|
}
|
894 |
|
|
}
|
895 |
|
|
}
|
896 |
|
|
} while(found_dotdot);
|
897 |
|
|
|
898 |
|
|
cyg_hal_sys_argv[0] = filename;
|
899 |
|
|
|
900 |
|
|
for (i = 1; i < cyg_hal_sys_argc; i++) {
|
901 |
|
|
const char* tmp = cyg_hal_sys_argv[i];
|
902 |
|
|
if (('-' == tmp[0]) && ('-' == tmp[1]) && ('\0' == tmp[2])) {
|
903 |
|
|
cyg_hal_sys_argv[i] = (const char*) 0;
|
904 |
|
|
break;
|
905 |
|
|
}
|
906 |
|
|
}
|
907 |
|
|
cyg_hal_sys_execve(filename, cyg_hal_sys_argv, cyg_hal_sys_environ);
|
908 |
|
|
|
909 |
|
|
// An execute error has occurred. Report this here, then exit. The
|
910 |
|
|
// parent will detect a close on the pipe without having received
|
911 |
|
|
// any data, and it will assume that a suitable diagnostic will have
|
912 |
|
|
// been displayed already.
|
913 |
|
|
diag_printf("Error: failed to execute the I/O auxiliary.\n");
|
914 |
|
|
cyg_hal_sys_exit(1);
|
915 |
|
|
} else {
|
916 |
|
|
int rc;
|
917 |
|
|
char buf[1];
|
918 |
|
|
|
919 |
|
|
// Still executing the eCos application.
|
920 |
|
|
// Do some cleaning-up.
|
921 |
|
|
to_aux = to_aux_pipe[1];
|
922 |
|
|
from_aux = from_aux_pipe[0];
|
923 |
|
|
if ((0 != cyg_hal_sys_close(to_aux_pipe[0])) ||
|
924 |
|
|
(0 != cyg_hal_sys_close(from_aux_pipe[1]))) {
|
925 |
|
|
diag_printf("Error: internal error in main process, failed to manipulate pipes.\n");
|
926 |
|
|
cyg_hal_sys_exit(1);
|
927 |
|
|
}
|
928 |
|
|
|
929 |
|
|
// It is now a good idea to block until the auxiliary is
|
930 |
|
|
// ready, i.e. give it a chance to read in its configuration
|
931 |
|
|
// files, load appropriate scripts, pop up windows, ... This
|
932 |
|
|
// may take a couple of seconds or so. Once the auxiliary is
|
933 |
|
|
// ready it will write a single byte down the pipe. This is
|
934 |
|
|
// the only time that the auxiliary will write other than when
|
935 |
|
|
// responding to a request.
|
936 |
|
|
do {
|
937 |
|
|
rc = cyg_hal_sys_read(from_aux, buf, 1);
|
938 |
|
|
} while (-CYG_HAL_SYS_EINTR == rc);
|
939 |
|
|
|
940 |
|
|
if (1 != rc) {
|
941 |
|
|
// The auxiliary has not started up successfully, so exit
|
942 |
|
|
// immediately. It should have generated appropriate
|
943 |
|
|
// diagnostics.
|
944 |
|
|
cyg_hal_sys_exit(1);
|
945 |
|
|
}
|
946 |
|
|
}
|
947 |
|
|
|
948 |
|
|
// At this point the auxiliary is up and running. It should not
|
949 |
|
|
// generate any interrupts just yet since none of the devices have
|
950 |
|
|
// been initialized. Remember that the auxiliary is now running,
|
951 |
|
|
// so that the initialization routines for those devices can
|
952 |
|
|
// figure out that they should interact with the auxiliary rather
|
953 |
|
|
// than attempt anything manually.
|
954 |
|
|
synth_auxiliary_running = true;
|
955 |
|
|
|
956 |
|
|
// Make sure that the auxiliary is the right version.
|
957 |
|
|
synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_GET_VERSION, 0, 0,
|
958 |
|
|
(const unsigned char*) 0, 0,
|
959 |
|
|
&aux_version, (unsigned char*) 0, (int*) 0, 0);
|
960 |
|
|
if (SYNTH_AUXILIARY_PROTOCOL_VERSION != aux_version) {
|
961 |
|
|
synth_auxiliary_running = false;
|
962 |
|
|
diag_printf("Error: an incorrect version of the I/O auxiliary is installed\n"
|
963 |
|
|
" Expected version %d, actual version %d\n"
|
964 |
|
|
" Installed binary is %s\n",
|
965 |
|
|
SYNTH_AUXILIARY_PROTOCOL_VERSION, aux_version, filename);
|
966 |
|
|
cyg_hal_sys_exit(1);
|
967 |
|
|
}
|
968 |
|
|
}
|
969 |
|
|
|
970 |
|
|
// Write a request to the I/O auxiliary, and optionally get back a
|
971 |
|
|
// reply. The dev_id is 0 for messages intended for the auxiliary
|
972 |
|
|
// itself, for example a device instantiation or a request for the
|
973 |
|
|
// current interrupt sate. Otherwise it identifies a specific device.
|
974 |
|
|
// The request code is specific to the device, and the two optional
|
975 |
|
|
// arguments are specific to the request.
|
976 |
|
|
void
|
977 |
|
|
synth_auxiliary_xchgmsg(int devid, int reqcode, int arg1, int arg2,
|
978 |
|
|
const unsigned char* txdata, int txlen,
|
979 |
|
|
int* result,
|
980 |
|
|
unsigned char* rxdata, int* actual_rxlen, int rxlen)
|
981 |
|
|
{
|
982 |
|
|
unsigned char request[SYNTH_REQUEST_LENGTH];
|
983 |
|
|
unsigned char reply[SYNTH_REPLY_LENGTH];
|
984 |
|
|
int rc;
|
985 |
|
|
int reply_rxlen;
|
986 |
|
|
cyg_bool_t old_isrstate;
|
987 |
|
|
|
988 |
|
|
CYG_ASSERT(devid >= 0, "A valid device id should be supplied");
|
989 |
|
|
CYG_ASSERT((0 == txlen) || ((const unsigned char*)0 != txdata), "Data transmits require a transmit buffer");
|
990 |
|
|
CYG_ASSERT((0 == rxlen) || ((unsigned char*)0 != rxdata), "Data receives require a receive buffer");
|
991 |
|
|
CYG_ASSERT((0 == rxlen) || ((int*)0 != result), "If a reply is expected then space must be allocated");
|
992 |
|
|
|
993 |
|
|
// I/O interactions with the auxiliary must be atomic: a context switch in
|
994 |
|
|
// between sending the header and the actual data would be bad.
|
995 |
|
|
HAL_DISABLE_INTERRUPTS(old_isrstate);
|
996 |
|
|
|
997 |
|
|
// The auxiliary should be running for the duration of this
|
998 |
|
|
// exchange. However the auxiliary can disappear asynchronously,
|
999 |
|
|
// so it is not possible for higher-level code to be sure that the
|
1000 |
|
|
// auxiliary is still running.
|
1001 |
|
|
//
|
1002 |
|
|
// If the auxiliary disappears during this call then usually this
|
1003 |
|
|
// will cause a SIGCHILD or SIGPIPE, both of which result in
|
1004 |
|
|
// termination. The exception is when the auxiliary decides to
|
1005 |
|
|
// shut down stdout for some reason without exiting - that has to
|
1006 |
|
|
// be detected in the read loop.
|
1007 |
|
|
if (synth_auxiliary_running) {
|
1008 |
|
|
request[SYNTH_REQUEST_DEVID_OFFSET + 0] = (devid >> 0) & 0x0FF;
|
1009 |
|
|
request[SYNTH_REQUEST_DEVID_OFFSET + 1] = (devid >> 8) & 0x0FF;
|
1010 |
|
|
request[SYNTH_REQUEST_DEVID_OFFSET + 2] = (devid >> 16) & 0x0FF;
|
1011 |
|
|
request[SYNTH_REQUEST_DEVID_OFFSET + 3] = (devid >> 24) & 0x0FF;
|
1012 |
|
|
request[SYNTH_REQUEST_REQUEST_OFFSET + 0] = (reqcode >> 0) & 0x0FF;
|
1013 |
|
|
request[SYNTH_REQUEST_REQUEST_OFFSET + 1] = (reqcode >> 8) & 0x0FF;
|
1014 |
|
|
request[SYNTH_REQUEST_REQUEST_OFFSET + 2] = (reqcode >> 16) & 0x0FF;
|
1015 |
|
|
request[SYNTH_REQUEST_REQUEST_OFFSET + 3] = (reqcode >> 24) & 0x0FF;
|
1016 |
|
|
request[SYNTH_REQUEST_ARG1_OFFSET + 0] = (arg1 >> 0) & 0x0FF;
|
1017 |
|
|
request[SYNTH_REQUEST_ARG1_OFFSET + 1] = (arg1 >> 8) & 0x0FF;
|
1018 |
|
|
request[SYNTH_REQUEST_ARG1_OFFSET + 2] = (arg1 >> 16) & 0x0FF;
|
1019 |
|
|
request[SYNTH_REQUEST_ARG1_OFFSET + 3] = (arg1 >> 24) & 0x0FF;
|
1020 |
|
|
request[SYNTH_REQUEST_ARG2_OFFSET + 0] = (arg2 >> 0) & 0x0FF;
|
1021 |
|
|
request[SYNTH_REQUEST_ARG2_OFFSET + 1] = (arg2 >> 8) & 0x0FF;
|
1022 |
|
|
request[SYNTH_REQUEST_ARG2_OFFSET + 2] = (arg2 >> 16) & 0x0FF;
|
1023 |
|
|
request[SYNTH_REQUEST_ARG2_OFFSET + 3] = (arg2 >> 24) & 0x0FF;
|
1024 |
|
|
request[SYNTH_REQUEST_TXLEN_OFFSET + 0] = (txlen >> 0) & 0x0FF;
|
1025 |
|
|
request[SYNTH_REQUEST_TXLEN_OFFSET + 1] = (txlen >> 8) & 0x0FF;
|
1026 |
|
|
request[SYNTH_REQUEST_TXLEN_OFFSET + 2] = (txlen >> 16) & 0x0FF;
|
1027 |
|
|
request[SYNTH_REQUEST_TXLEN_OFFSET + 3] = (txlen >> 24) & 0x0FF;
|
1028 |
|
|
request[SYNTH_REQUEST_RXLEN_OFFSET + 0] = (rxlen >> 0) & 0x0FF;
|
1029 |
|
|
request[SYNTH_REQUEST_RXLEN_OFFSET + 1] = (rxlen >> 8) & 0x0FF;
|
1030 |
|
|
request[SYNTH_REQUEST_RXLEN_OFFSET + 2] = (rxlen >> 16) & 0x0FF;
|
1031 |
|
|
request[SYNTH_REQUEST_RXLEN_OFFSET + 3] = ((rxlen >> 24) & 0x0FF) | (((int*)0 != result) ? 0x080 : 0);
|
1032 |
|
|
|
1033 |
|
|
// sizeof(synth_auxiliary_request) < PIPE_BUF (4096) so a single write should be atomic,
|
1034 |
|
|
// subject only to incoming clock or SIGIO or child-related signals.
|
1035 |
|
|
do {
|
1036 |
|
|
rc = cyg_hal_sys_write(to_aux, (const void*) &request, SYNTH_REQUEST_LENGTH);
|
1037 |
|
|
} while (-CYG_HAL_SYS_EINTR == rc);
|
1038 |
|
|
|
1039 |
|
|
// Is there any more data to be sent?
|
1040 |
|
|
if (0 < txlen) {
|
1041 |
|
|
int sent = 0;
|
1042 |
|
|
CYG_LOOP_INVARIANT(synth_auxiliary_running, "The auxiliary cannot just disappear");
|
1043 |
|
|
|
1044 |
|
|
while (sent < txlen) {
|
1045 |
|
|
rc = cyg_hal_sys_write(to_aux, (const void*) &(txdata[sent]), txlen - sent);
|
1046 |
|
|
if (-CYG_HAL_SYS_EINTR == rc) {
|
1047 |
|
|
continue;
|
1048 |
|
|
} else if (rc < 0) {
|
1049 |
|
|
diag_printf("Internal error: unexpected result %d when sending buffer to auxiliary.\n", rc);
|
1050 |
|
|
diag_printf(" : this application is exiting immediately.\n");
|
1051 |
|
|
cyg_hal_sys_exit(1);
|
1052 |
|
|
} else {
|
1053 |
|
|
sent += rc;
|
1054 |
|
|
}
|
1055 |
|
|
}
|
1056 |
|
|
CYG_ASSERT(sent <= txlen, "Amount of data sent should not exceed requested size");
|
1057 |
|
|
}
|
1058 |
|
|
|
1059 |
|
|
// The auxiliary can now process this entire request. Is a reply expected?
|
1060 |
|
|
if ((int*)0 != result) {
|
1061 |
|
|
// The basic reply is also only a small number of bytes, so should be atomic.
|
1062 |
|
|
do {
|
1063 |
|
|
rc = cyg_hal_sys_read(from_aux, (void*) &reply, SYNTH_REPLY_LENGTH);
|
1064 |
|
|
} while (-CYG_HAL_SYS_EINTR == rc);
|
1065 |
|
|
if (rc <= 0) {
|
1066 |
|
|
if (rc < 0) {
|
1067 |
|
|
diag_printf("Internal error: unexpected result %d when receiving data from auxiliary.\n", rc);
|
1068 |
|
|
} else {
|
1069 |
|
|
diag_printf("Internal error: EOF detected on pipe from auxiliary.\n");
|
1070 |
|
|
}
|
1071 |
|
|
diag_printf(" : this application is exiting immediately.\n");
|
1072 |
|
|
cyg_hal_sys_exit(1);
|
1073 |
|
|
}
|
1074 |
|
|
CYG_ASSERT(SYNTH_REPLY_LENGTH == rc, "The correct amount of data should have been read");
|
1075 |
|
|
|
1076 |
|
|
// Replies are packed in Tcl and assumed to be two 32-bit
|
1077 |
|
|
// little-endian integers.
|
1078 |
|
|
*result = (reply[SYNTH_REPLY_RESULT_OFFSET + 3] << 24) |
|
1079 |
|
|
(reply[SYNTH_REPLY_RESULT_OFFSET + 2] << 16) |
|
1080 |
|
|
(reply[SYNTH_REPLY_RESULT_OFFSET + 1] << 8) |
|
1081 |
|
|
(reply[SYNTH_REPLY_RESULT_OFFSET + 0] << 0);
|
1082 |
|
|
reply_rxlen = (reply[SYNTH_REPLY_RXLEN_OFFSET + 3] << 24) |
|
1083 |
|
|
(reply[SYNTH_REPLY_RXLEN_OFFSET + 2] << 16) |
|
1084 |
|
|
(reply[SYNTH_REPLY_RXLEN_OFFSET + 1] << 8) |
|
1085 |
|
|
(reply[SYNTH_REPLY_RXLEN_OFFSET + 0] << 0);
|
1086 |
|
|
|
1087 |
|
|
CYG_ASSERT(reply_rxlen <= rxlen, "The auxiliary should not be sending more data than was requested.");
|
1088 |
|
|
|
1089 |
|
|
if ((int*)0 != actual_rxlen) {
|
1090 |
|
|
*actual_rxlen = reply_rxlen;
|
1091 |
|
|
}
|
1092 |
|
|
if (reply_rxlen) {
|
1093 |
|
|
int received = 0;
|
1094 |
|
|
|
1095 |
|
|
while (received < reply_rxlen) {
|
1096 |
|
|
rc = cyg_hal_sys_read(from_aux, (void*) &(rxdata[received]), reply_rxlen - received);
|
1097 |
|
|
if (-CYG_HAL_SYS_EINTR == rc) {
|
1098 |
|
|
continue;
|
1099 |
|
|
} else if (rc <= 0) {
|
1100 |
|
|
if (rc < 0) {
|
1101 |
|
|
diag_printf("Internal error: unexpected result %d when receiving data from auxiliary.\n", rc);
|
1102 |
|
|
} else {
|
1103 |
|
|
diag_printf("Internal error: EOF detected on pipe from auxiliary.\n");
|
1104 |
|
|
}
|
1105 |
|
|
diag_printf(" : this application is exiting immediately.\n");
|
1106 |
|
|
} else {
|
1107 |
|
|
received += rc;
|
1108 |
|
|
}
|
1109 |
|
|
}
|
1110 |
|
|
CYG_ASSERT(received == reply_rxlen, "Amount received should be exact");
|
1111 |
|
|
}
|
1112 |
|
|
}
|
1113 |
|
|
}
|
1114 |
|
|
|
1115 |
|
|
HAL_RESTORE_INTERRUPTS(old_isrstate);
|
1116 |
|
|
}
|
1117 |
|
|
|
1118 |
|
|
// Instantiate a device. This takes arguments such as
|
1119 |
|
|
// devs/eth/synth/ecosynth, current, ethernet, eth0, and 200x100 If
|
1120 |
|
|
// the package and version are NULL strings then the device being
|
1121 |
|
|
// initialized is application-specific and does not belong to any
|
1122 |
|
|
// particular package.
|
1123 |
|
|
int
|
1124 |
|
|
synth_auxiliary_instantiate(const char* pkg, const char* version, const char* devtype, const char* devinst, const char* devdata)
|
1125 |
|
|
{
|
1126 |
|
|
int result = -1;
|
1127 |
|
|
unsigned char buf[512 + 1];
|
1128 |
|
|
const char* str;
|
1129 |
|
|
int index;
|
1130 |
|
|
|
1131 |
|
|
CYG_ASSERT((const char*)0 != devtype, "Device instantiations must specify a valid device type");
|
1132 |
|
|
CYG_ASSERT((((const char*)0 != pkg) && ((const char*)0 != version)) || \
|
1133 |
|
|
(((const char*)0 == pkg) && ((const char*)0 == version)), "If a package is specified then the version must be supplied as well");
|
1134 |
|
|
|
1135 |
|
|
index = 0;
|
1136 |
|
|
str = pkg;
|
1137 |
|
|
if ((const char*)0 == str) {
|
1138 |
|
|
str = "";
|
1139 |
|
|
}
|
1140 |
|
|
while ( (index < 512) && ('\0' != *str) ) {
|
1141 |
|
|
buf[index++] = *str++;
|
1142 |
|
|
}
|
1143 |
|
|
if (index < 512) buf[index++] = '\0';
|
1144 |
|
|
str = version;
|
1145 |
|
|
if ((const char*)0 == str) {
|
1146 |
|
|
str = "";
|
1147 |
|
|
}
|
1148 |
|
|
while ((index < 512) && ('\0' != *str) ) {
|
1149 |
|
|
buf[index++] = *str++;
|
1150 |
|
|
}
|
1151 |
|
|
if (index < 512) buf[index++] = '\0';
|
1152 |
|
|
for (str = devtype; (index < 512) && ('\0' != *str); ) {
|
1153 |
|
|
buf[index++] = *str++;
|
1154 |
|
|
}
|
1155 |
|
|
if (index < 512) buf[index++] = '\0';
|
1156 |
|
|
if ((const char*)0 != devinst) {
|
1157 |
|
|
for (str = devinst; (index < 512) && ('\0' != *str); ) {
|
1158 |
|
|
buf[index++] = *str++;
|
1159 |
|
|
}
|
1160 |
|
|
}
|
1161 |
|
|
if (index < 512) buf[index++] = '\0';
|
1162 |
|
|
if ((const char*)0 != devdata) {
|
1163 |
|
|
for (str = devdata; (index < 512) && ('\0' != *str); ) {
|
1164 |
|
|
buf[index++] = *str++;
|
1165 |
|
|
}
|
1166 |
|
|
}
|
1167 |
|
|
if (index < 512) {
|
1168 |
|
|
buf[index++] = '\0';
|
1169 |
|
|
} else {
|
1170 |
|
|
diag_printf("Internal error: buffer overflow constructing instantiate request for auxiliary.\n");
|
1171 |
|
|
diag_printf(" : this application is exiting immediately.\n");
|
1172 |
|
|
cyg_hal_sys_exit(1);
|
1173 |
|
|
}
|
1174 |
|
|
|
1175 |
|
|
if (synth_auxiliary_running) {
|
1176 |
|
|
synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_INSTANTIATE, 0, 0,
|
1177 |
|
|
buf, index,
|
1178 |
|
|
&result,
|
1179 |
|
|
(unsigned char*) 0, (int *) 0, 0);
|
1180 |
|
|
}
|
1181 |
|
|
return result;
|
1182 |
|
|
}
|
1183 |
|
|
|
1184 |
|
|
// ----------------------------------------------------------------------------
|
1185 |
|
|
// SIGPIPE and SIGCHLD are special, related to the auxiliary process.
|
1186 |
|
|
//
|
1187 |
|
|
// A SIGPIPE can only happen when the application is writing to the
|
1188 |
|
|
// auxiliary, which only happens inside synth_auxiliary_xchgmsg() (this
|
1189 |
|
|
// assumes that no other code is writing down a pipe, e.g. to interact
|
1190 |
|
|
// with a process other than the standard I/O auxiliary). Either the
|
1191 |
|
|
// auxiliary has explicitly closed the pipe, which it is not supposed
|
1192 |
|
|
// to do, or more likely it has exited. Either way, there is little
|
1193 |
|
|
// point in continuing - unless we already know that the system is
|
1194 |
|
|
// shutting down.
|
1195 |
|
|
static void
|
1196 |
|
|
synth_pipe_sighandler(int sig)
|
1197 |
|
|
{
|
1198 |
|
|
CYG_ASSERT(CYG_HAL_SYS_SIGPIPE == sig, "The right signal handler should be invoked");
|
1199 |
|
|
if (synth_auxiliary_running) {
|
1200 |
|
|
synth_auxiliary_running = false;
|
1201 |
|
|
diag_printf("Internal error: communication with the I/O auxiliary has been lost.\n");
|
1202 |
|
|
diag_printf(" : this application is exiting immediately.\n");
|
1203 |
|
|
cyg_hal_sys_exit(1);
|
1204 |
|
|
}
|
1205 |
|
|
}
|
1206 |
|
|
|
1207 |
|
|
// Similarly it is assumed that there will be no child processes other than
|
1208 |
|
|
// the auxiliary. Therefore a SIGCHLD indicates that the auxiliary has
|
1209 |
|
|
// terminated unexpectedly. This is bad: normal termination involves
|
1210 |
|
|
// the application exiting and the auxiliary terminating in response,
|
1211 |
|
|
// not the other way around.
|
1212 |
|
|
//
|
1213 |
|
|
// As a special case, if it is known that the auxiliary is not currently
|
1214 |
|
|
// usable then the signal is ignored. This copes with the situation where
|
1215 |
|
|
// the auxiliary has just been fork()'d but has failed to initialize, or
|
1216 |
|
|
// alternatively where the whole system is in the process of shutting down
|
1217 |
|
|
// cleanly and it happens that the auxiliary got there first.
|
1218 |
|
|
static void
|
1219 |
|
|
synth_chld_sighandler(int sig)
|
1220 |
|
|
{
|
1221 |
|
|
CYG_ASSERT(CYG_HAL_SYS_SIGCHLD == sig, "The right signal handler should be invoked");
|
1222 |
|
|
if (synth_auxiliary_running) {
|
1223 |
|
|
synth_auxiliary_running = false;
|
1224 |
|
|
diag_printf("Internal error: the I/O auxiliary has terminated unexpectedly.\n");
|
1225 |
|
|
diag_printf(" : this application is exiting immediately.\n");
|
1226 |
|
|
cyg_hal_sys_exit(1);
|
1227 |
|
|
}
|
1228 |
|
|
}
|
1229 |
|
|
|
1230 |
|
|
// ----------------------------------------------------------------------------
|
1231 |
|
|
// Initialization
|
1232 |
|
|
|
1233 |
|
|
void
|
1234 |
|
|
synth_hardware_init(void)
|
1235 |
|
|
{
|
1236 |
|
|
struct cyg_hal_sys_sigaction action;
|
1237 |
|
|
struct cyg_hal_sys_sigset_t blocked;
|
1238 |
|
|
int i;
|
1239 |
|
|
|
1240 |
|
|
// Set up a sigprocmask to block all signals except the ones we
|
1241 |
|
|
// particularly want to handle. However do not block the tty
|
1242 |
|
|
// signals - the ability to ctrl-C a program is important.
|
1243 |
|
|
CYG_HAL_SYS_SIGFILLSET(&blocked);
|
1244 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGILL);
|
1245 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGBUS);
|
1246 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGFPE);
|
1247 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGSEGV);
|
1248 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGPIPE);
|
1249 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGCHLD);
|
1250 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGALRM);
|
1251 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGIO);
|
1252 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGHUP);
|
1253 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGINT);
|
1254 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGQUIT);
|
1255 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGTERM);
|
1256 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGCONT);
|
1257 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGSTOP);
|
1258 |
|
|
CYG_HAL_SYS_SIGDELSET(&blocked, CYG_HAL_SYS_SIGTSTP);
|
1259 |
|
|
|
1260 |
|
|
if (0 != cyg_hal_sys_sigprocmask(CYG_HAL_SYS_SIG_SETMASK, &blocked, (cyg_hal_sys_sigset_t*) 0)) {
|
1261 |
|
|
CYG_FAIL("Failed to initialize sigprocmask");
|
1262 |
|
|
}
|
1263 |
|
|
|
1264 |
|
|
// Now set up the VSR and ISR statics
|
1265 |
|
|
synth_VSR = &synth_default_vsr;
|
1266 |
|
|
for (i = 0; i < CYGNUM_HAL_ISR_COUNT; i++) {
|
1267 |
|
|
synth_isr_handlers[i].isr = &synth_default_isr;
|
1268 |
|
|
synth_isr_handlers[i].data = (CYG_ADDRWORD) 0;
|
1269 |
|
|
synth_isr_handlers[i].obj = (CYG_ADDRESS) 0;
|
1270 |
|
|
synth_isr_handlers[i].pri = CYGNUM_HAL_ISR_COUNT;
|
1271 |
|
|
}
|
1272 |
|
|
|
1273 |
|
|
// Install signal handlers for SIGIO and SIGALRM, the two signals
|
1274 |
|
|
// that may cause the VSR to run. SA_NODEFER is important: it
|
1275 |
|
|
// means that the current signal will not be blocked while the
|
1276 |
|
|
// signal handler is running. Combined with a mask of 0, it means
|
1277 |
|
|
// that the sigprocmask does not change when a signal handler is
|
1278 |
|
|
// invoked, giving eCos the flexibility to switch to other threads
|
1279 |
|
|
// instead of having the signal handler return immediately.
|
1280 |
|
|
action.hal_mask = 0;
|
1281 |
|
|
action.hal_flags = CYG_HAL_SYS_SA_NODEFER;
|
1282 |
|
|
action.hal_handler = &synth_alrm_sighandler;
|
1283 |
|
|
action.hal_restorer = (void (*)(void)) 0;
|
1284 |
|
|
#ifdef CYG_HAL_SYS_SIGACTION_ADJUST
|
1285 |
|
|
CYG_HAL_SYS_SIGACTION_ADJUST(CYG_HAL_SYS_SIGALRM, &action);
|
1286 |
|
|
#endif
|
1287 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGALRM, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1288 |
|
|
CYG_FAIL("Failed to install signal handler for SIGALRM");
|
1289 |
|
|
}
|
1290 |
|
|
action.hal_handler = &synth_io_sighandler;
|
1291 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGIO, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1292 |
|
|
CYG_FAIL("Failed to install signal handler for SIGIO");
|
1293 |
|
|
}
|
1294 |
|
|
|
1295 |
|
|
// Install handlers for the various exceptions. For now these also
|
1296 |
|
|
// operate with unchanged sigprocmasks, allowing nested
|
1297 |
|
|
// exceptions. It is not clear that this is entirely a good idea,
|
1298 |
|
|
// but in practice these exceptions will usually be handled by gdb
|
1299 |
|
|
// anyway.
|
1300 |
|
|
action.hal_handler = &synth_exception_sighandler;
|
1301 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGILL, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1302 |
|
|
CYG_FAIL("Failed to install signal handler for SIGILL");
|
1303 |
|
|
}
|
1304 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGBUS, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1305 |
|
|
CYG_FAIL("Failed to install signal handler for SIGBUS");
|
1306 |
|
|
}
|
1307 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGFPE, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1308 |
|
|
CYG_FAIL("Failed to install signal handler for SIGFPE");
|
1309 |
|
|
}
|
1310 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGSEGV, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1311 |
|
|
CYG_FAIL("Failed to install signal handler for SIGSEGV");
|
1312 |
|
|
}
|
1313 |
|
|
|
1314 |
|
|
// Also cope with SIGCHLD and SIGPIPE. SIGCHLD indicates that the
|
1315 |
|
|
// auxiliary has terminated, which is a bad thing. SIGPIPE
|
1316 |
|
|
// indicates that a write to the auxiliary has terminated, but
|
1317 |
|
|
// the error condition was caught at a different stage.
|
1318 |
|
|
action.hal_handler = &synth_pipe_sighandler;
|
1319 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGPIPE, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1320 |
|
|
CYG_FAIL("Failed to install signal handler for SIGPIPE");
|
1321 |
|
|
}
|
1322 |
|
|
action.hal_handler = &synth_chld_sighandler;
|
1323 |
|
|
action.hal_flags |= CYG_HAL_SYS_SA_NOCLDSTOP | CYG_HAL_SYS_SA_NOCLDWAIT;
|
1324 |
|
|
if (0 != cyg_hal_sys_sigaction(CYG_HAL_SYS_SIGCHLD, &action, (struct cyg_hal_sys_sigaction*) 0)) {
|
1325 |
|
|
CYG_FAIL("Failed to install signal handler for SIGCHLD");
|
1326 |
|
|
}
|
1327 |
|
|
|
1328 |
|
|
// Determine the processor's bogomips rating. This adds some
|
1329 |
|
|
// start-up overhead to all applications, even if HAL_DELAY_US()
|
1330 |
|
|
// is not used. However doing it on demand in the first call
|
1331 |
|
|
// to HAL_DELAY_US() would risk running out of file descriptors.
|
1332 |
|
|
{
|
1333 |
|
|
int fd;
|
1334 |
|
|
char buf[4096]; // much larger than current /proc/cpuinfo, but still small enough for synthetic target stacks
|
1335 |
|
|
int read;
|
1336 |
|
|
int i;
|
1337 |
|
|
|
1338 |
|
|
fd = cyg_hal_sys_open("/proc/cpuinfo", CYG_HAL_SYS_O_RDONLY, 0);
|
1339 |
|
|
if (fd < 0) {
|
1340 |
|
|
CYG_FAIL("Failed to open /proc/cpuinfo, needed for BogoMips rating");
|
1341 |
|
|
}
|
1342 |
|
|
read = cyg_hal_sys_read(fd, buf, 4096);
|
1343 |
|
|
cyg_hal_sys_close(fd);
|
1344 |
|
|
|
1345 |
|
|
for (i = 0; i < read; i++) {
|
1346 |
|
|
if ((buf[i ] == 'b') && (buf[i+1] == 'o') && (buf[i+2] == 'g') && (buf[i+3] == 'o') &&
|
1347 |
|
|
(buf[i+4] == 'm') && (buf[i+5] == 'i') && (buf[i+6] == 'p') && (buf[i+7] == 's')) {
|
1348 |
|
|
|
1349 |
|
|
for ( i += 8; (i < read) && ((buf[i] < '1') || (buf[i] > '9')); i++) {
|
1350 |
|
|
;
|
1351 |
|
|
}
|
1352 |
|
|
// Only bother with the integer part of the rating
|
1353 |
|
|
for ( ; (i < read) && (buf[i] >= '0') && (buf[i] <= '9'); i++) {
|
1354 |
|
|
hal_bogomips = (10 * hal_bogomips) + (buf[i] - '0');
|
1355 |
|
|
}
|
1356 |
|
|
break;
|
1357 |
|
|
}
|
1358 |
|
|
}
|
1359 |
|
|
if (0 == hal_bogomips) {
|
1360 |
|
|
CYG_FAIL("Failed to find bogomips entry in /proc/cpuinfo");
|
1361 |
|
|
}
|
1362 |
|
|
}
|
1363 |
|
|
|
1364 |
|
|
// Start up the auxiliary process.
|
1365 |
|
|
synth_start_auxiliary();
|
1366 |
|
|
|
1367 |
|
|
// All done. At this stage interrupts are still disabled, no ISRs
|
1368 |
|
|
// have been installed, and the clock is not yet ticking.
|
1369 |
|
|
// Exceptions can come in and will be processed normally. SIGIO
|
1370 |
|
|
// and SIGALRM could come in, but nothing has yet been done
|
1371 |
|
|
// to make that happen.
|
1372 |
|
|
}
|
1373 |
|
|
|
1374 |
|
|
// Second-stage hardware init. This is called after all C++ static
|
1375 |
|
|
// constructors have been run, which should mean that all device
|
1376 |
|
|
// drivers have been initialized and will have performed appropriate
|
1377 |
|
|
// interactions with the I/O auxiliary. There should now be a
|
1378 |
|
|
// message exchange with the auxiliary to let it know that there will
|
1379 |
|
|
// not be any more devices, allowing it to remove unwanted frames,
|
1380 |
|
|
// run the user's mainrc.tcl script, and so on. Also this is the
|
1381 |
|
|
// time that the various toplevels get mapped on to the display.
|
1382 |
|
|
//
|
1383 |
|
|
// This request blocks until the auxiliary is ready. The return value
|
1384 |
|
|
// indicates whether or not any errors occurred on the auxiliary side,
|
1385 |
|
|
// and that those errors have not been suppressed using --keep-going
|
1386 |
|
|
|
1387 |
|
|
void
|
1388 |
|
|
synth_hardware_init2(void)
|
1389 |
|
|
{
|
1390 |
|
|
if (synth_auxiliary_running) {
|
1391 |
|
|
int result;
|
1392 |
|
|
synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_CONSTRUCTORS_DONE,
|
1393 |
|
|
0, 0, (const unsigned char*) 0, 0,
|
1394 |
|
|
&result,
|
1395 |
|
|
(unsigned char*) 0, (int*) 0, 0);
|
1396 |
|
|
if ( !result ) {
|
1397 |
|
|
cyg_hal_sys_exit(1);
|
1398 |
|
|
}
|
1399 |
|
|
}
|
1400 |
|
|
}
|