OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [hal/] [synth/] [arch/] [current/] [src/] [synth_intr.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.