source: soft/giet_vm/sys/kernel_init.c @ 166

Last change on this file since 166 was 166, checked in by alain, 12 years ago

Introducing support for IOMMU

File size: 22.4 KB
Line 
1///////////////////////////////////////////////////////////////////////////////////
2// File     : kernel_init.c
3// Date     : 26/05/2012
4// Authors  : alain greiner & mohamed karaoui
5// Copyright (c) UPMC-LIP6
6////////////////////////////////////////////////////////////////////////////////////
7// The kernel_init.c files is part of the GIET-VM nano-kernel.
8// It contains the kernel entry point for the second phase of system initialisation:
9// all processors are jumping to _kernel_init, but P[0] is first because other
10// processors are blocked until P[0] complete initilisation of task contexts,
11// vobjs and peripherals.
12// All procs in this phase have their MMU activated, because each processor P[i]
13// must initialise registers SP, SR, PTPR and EPC with informations stored
14// in _scheduler[i].
15////////////////////////////////////////////////////////////////////////////////////
16
17#include <common.h>
18#include <ctx_handler.h>
19#include <sys_handler.h>
20#include <mapping_info.h>
21#include <giet_config.h>
22#include <mips32_registers.h>
23#include <irq_handler.h>
24#include <vm_handler.h>
25#include <hwr_mapping.h>
26#include <mwmr_channel.h>
27#include <barrier.h>
28#include <drivers.h>
29
30#define in_kinit __attribute__((section (".kinit")))
31 
32///////////////////////////////////////////////////////////////////////////////////
33// declarations required to avoid forward references
34///////////////////////////////////////////////////////////////////////////////////
35
36void    _kernel_vobjs_init(unsigned int*);
37void    _kernel_tasks_init(unsigned int*);
38void    _kernel_peripherals_init(void);
39void    _kernel_interrupt_vector_init(void);
40void    _kernel_start_all_procs(void);
41
42//////////////////////////////////////////////////////////////////////////////////
43// This function is the entry point for the second step of the boot sequence.
44//////////////////////////////////////////////////////////////////////////////////
45in_kinit void _kernel_init()
46{
47    // array of pointers on the page tables (used for task context initialisation)
48    unsigned int        kernel_ptabs[GIET_NB_VSPACE_MAX]; 
49
50    // values to be written in registers
51    unsigned int        sp_value;
52    unsigned int        sr_value;
53    unsigned int        ptpr_value;
54    unsigned int        epc_value;
55
56    unsigned int        pid =   _procid();
57
58    // only processor 0 executes system initialisation
59    if ( pid == 0 )
60    {
61        _kernel_vobjs_init(kernel_ptabs);
62        _kernel_tasks_init(kernel_ptabs);
63        _kernel_interrupt_vector_init();
64        _kernel_peripherals_init();
65        _kernel_start_all_procs();
66    }
67
68    // each processor initialises it's SP, SR, PTPR, and EPC registers
69    // from values defined in _scheduler[pid], starts it's private
70    // context switch timer (if there is more than one task allocated)
71    // and jumps to user code.
72    // It does nothing, and keep idle if no task allocated.
73
74    static_scheduler_t*  sched = &_scheduler[pid];
75
76    if ( sched->tasks )         // at leat one task allocated
77    {
78        // initialise registers
79        sp_value   = sched->context[0][CTX_SP_ID];
80        sr_value   = sched->context[0][CTX_SR_ID];
81        ptpr_value = sched->context[0][CTX_PTPR_ID];
82        epc_value  = sched->context[0][CTX_EPC_ID];
83
84        // start TICK timer
85        if ( sched->tasks > 1 )
86        {
87            unsigned int cluster_id = pid / NB_PROCS;
88            unsigned int proc_id    = pid % NB_PROCS;
89           _timer_write( cluster_id, proc_id, TIMER_PERIOD, GIET_TICK_VALUE );
90           _timer_write( cluster_id, proc_id, TIMER_MODE  , 0x3 );
91        }
92    }
93    else                                        // no task allocated
94    {
95        _get_lock( &_tty_put_lock );
96        _puts("\n No task allocated to processor ");
97        _putw( pid );
98        _puts(" => keep idle\n");
99        _release_lock ( &_tty_put_lock );
100
101        // enable interrupts in kernel mode
102        asm volatile ( "li         $26, 0xFF01  \n"
103                       "mtc0   $26, $12     \n" 
104                       ::: "$26" );
105
106                // infinite loop in kernel mode
107        while (1) asm volatile("nop");
108    }
109
110    asm volatile (
111       "move    $29,    %0              \n"             /* SP <= ctx[CTX_SP_ID] */
112       "mtc0    %1,             $12             \n"             /* SR <= ctx[CTX_SR_ID] */
113       "mtc2    %2,             $0              \n"             /* PTPR <= ctx[CTX_PTPR_ID] */
114       "mtc0    %3,             $14             \n"             /* EPC <= ctx[CTX_EPC_ID] */
115       "eret                                    \n"             /* jump to user code */
116       "nop                                             \n"
117       :
118       : "r"(sp_value), "r"(sr_value), "r"(ptpr_value), "r"(epc_value) );
119
120} // end _kernel_init()
121
122//////////////////////////////////////////////////////////////////////////////////
123// This function wakeup all processors.
124// It should be executed by P[0] when the kernel initialisation is done.
125//////////////////////////////////////////////////////////////////////////////////
126in_kinit void _kernel_start_all_procs()
127{
128    mapping_header_t*   header = (mapping_header_t*)&seg_mapping_base; 
129
130    _puts("\n[INIT] Starting parallel execution at cycle : ");
131    _putw( _proctime() );
132    _puts("\n");
133
134    header->signature = OUT_MAPPING_SIGNATURE;
135}
136
137//////////////////////////////////////////////////////////////////////////////////
138// _eret()
139// The address of this function is used to initialise the return address (RA)
140// in all task contexts (when the task has never been executed.
141//////////////////////////////////////////////////////////////////////////////////
142in_kinit void _eret()
143{
144    asm volatile("eret \n"
145                 "nop");
146}
147
148///////////////////////////////////////////////////////////////////////////////
149// This function maps a given task, defined in a given vspace
150// on the processor allocated in the mapping_info structure,
151// and initialises the task context.
152// There is one scheduler per processor, and processor can be shared
153// by several applications running in different vspaces.
154// There is one private context array handled by each scheduler.
155//
156// The following values must be initialised in all task contexts:
157// - sp     stack pointer = stack_base + stack_length
158// - ra     return address = &_eret
159// - epc    start address = start_vector[task->startid]
160// - sr     status register = OxFF13
161// - tty    TTY terminal index (global index)
162// - fb     FB_DMA channel index (global index)
163// - ptpr   page table base address / 8K
164// - mode   mmu_mode = 0xF (TLBs and caches activated)
165////////////////////////////////////////////////////////////////////////////////
166in_kinit void _task_map( unsigned int   task_id,    // global index
167                                         unsigned int   vspace_id,  // global index
168                         unsigned int   tty_id,         // TTY index
169                         unsigned int   fb_id,          // FB index
170                         unsigned int   pt_base )   // page table base adddress
171{
172    mapping_header_t*   header = (mapping_header_t*)&seg_mapping_base; 
173
174    mapping_task_t*     task   = _get_task_base(header);
175    mapping_vspace_t*   vspace = _get_vspace_base(header);
176    mapping_vobj_t*     vobj   = _get_vobj_base( header );
177
178    // values to be initialised in task context
179    unsigned int                ra = (unsigned int)&_eret;
180    unsigned int                sr   = 0x0000FF13; 
181    unsigned int                tty  = tty_id; 
182    unsigned int                fb   = fb_id;   
183    unsigned int                ptpr = pt_base >> 13;
184    unsigned int                mode = 0xF;
185    unsigned int                sp;
186    unsigned int                epc;     
187
188    // compute epc value
189    // Get the (virtual) base address of the start_vector that
190    // contains the start addresses for all tasks defined in a vspace.
191    mapping_vobj_t* vobj_data = &vobj[vspace[vspace_id].vobj_offset + 
192                                      vspace[vspace_id].start_offset]; 
193    unsigned int* start_vector = (unsigned int*)vobj_data->vaddr;
194    epc  = start_vector[task[task_id].startid];
195
196    // compute sp value
197    // Get the vobj containing the stack
198    unsigned int vobj_id = task[task_id].vobjlocid + vspace[vspace_id].vobj_offset;
199    sp = vobj[vobj_id].vaddr + vobj[vobj_id].length;
200
201    // compute global processor index
202    unsigned int proc_id = task[task_id].clusterid * NB_PROCS + task[task_id].proclocid;
203
204    // compute and check local task index
205    unsigned int ltid = _scheduler[proc_id].tasks;
206    if ( ltid >= GIET_NB_TASKS_MAX )
207    {
208        _puts("\n[INIT ERROR] : too much tasks allocated to processor ");
209        _putw( proc_id );
210        _puts("\n");
211        _exit();
212    }
213   
214    // update number of tasks allocated to scheduler
215    _scheduler[proc_id].tasks = ltid + 1;
216
217    // initializes the task context
218    _scheduler[proc_id].context[ltid][CTX_SR_ID]    = sr;
219    _scheduler[proc_id].context[ltid][CTX_SP_ID]    = sp;
220    _scheduler[proc_id].context[ltid][CTX_RA_ID]    = ra;
221    _scheduler[proc_id].context[ltid][CTX_EPC_ID]   = epc;
222    _scheduler[proc_id].context[ltid][CTX_TTY_ID]   = tty;
223        _scheduler[proc_id].context[ltid][CTX_FBDMA_ID] = fb;
224    _scheduler[proc_id].context[ltid][CTX_PTPR_ID]  = ptpr;
225    _scheduler[proc_id].context[ltid][CTX_MODE_ID]  = mode;
226    _scheduler[proc_id].context[ltid][CTX_TASK_ID]  = task_id;
227   
228#if INIT_DEBUG
229_puts("Task ");
230_puts( task[task_id].name );
231_puts(" allocated to processor ");
232_putw( proc_id );
233_puts(" / ltid = ");
234_putw( ltid );
235_puts("\n");
236
237_puts("  - SR          = ");
238_putw( sr );
239_puts("  saved at ");
240_putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_SR_ID] );
241_puts("\n");
242
243_puts("  - RA          = ");
244_putw( ra );
245_puts("  saved at ");
246_putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_RA_ID] );
247_puts("\n");
248
249_puts("  - SP          = ");
250_putw( sp );
251_puts("  saved at ");
252_putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_SP_ID] );
253_puts("\n");
254
255_puts("  - EPC         = ");
256_putw( epc );
257_puts("  saved at ");
258_putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_EPC_ID] );
259_puts("\n");
260
261_puts("  - TTY         = ");
262_putw( tty );
263_puts("  saved at ");
264_putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_TTY_ID] );
265_puts("\n");
266
267_puts("  - FB          = ");
268_putw( fb );
269_puts("  saved at ");
270_putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_FBDMA_ID] );
271_puts("\n");
272
273_puts("  - PTPR        = ");
274_putw( ptpr<<13 );
275_puts("  saved at ");
276_putw( (unsigned int)&_scheduler[proc_id].context[ltid][CTX_PTPR_ID] );
277_puts("\n");
278#endif
279
280} // end _task_map()
281
282///////////////////////////////////////////////////////////////////////////////
283// This function initializes all private vobjs defined in the vspaces,
284// such as mwmr channels, barriers and locks, depending on the vobj type.
285// (Most of the vobjs are not known, and not initialised by the compiler).
286// This function initialises the kernel_ptabs[] array indexed by the vspace_id,
287// and containint the base addresses of all page tables.
288// This kernel_ptabs[] array is used to initialise the task contexts.
289///////////////////////////////////////////////////////////////////////////////
290in_kinit void _kernel_vobjs_init( unsigned int* kernel_ptabs )
291{
292    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
293    mapping_vspace_t*   vspace  = _get_vspace_base( header );     
294    mapping_vobj_t*     vobj    = _get_vobj_base( header );
295
296    unsigned int        vspace_id; 
297    unsigned int        vobj_id;
298
299    // loop on the vspaces
300    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
301    {
302        char ptab_found = 0;
303
304#if INIT_DEBUG
305_puts("[INIT] --- vobjs initialisation in vspace "); 
306_puts(vspace[vspace_id].name);
307_puts("\n");
308#endif
309        // loop on the vobjs
310            for(vobj_id= vspace[vspace_id].vobj_offset; 
311                        vobj_id < (vspace[vspace_id].vobj_offset+ vspace[vspace_id].vobjs);
312                        vobj_id++)
313            {
314            switch( vobj[vobj_id].type )
315            {
316                case VOBJ_TYPE_PTAB:    // initialise page table pointers array
317                {
318                    ptab_found = 1;
319                    kernel_ptabs[vspace_id] = vobj[vobj_id].paddr;
320
321#if INIT_DEBUG
322_puts("[INIT]   PTAB address = "); 
323_putw(kernel_ptabs[vspace_id]); 
324_puts("\n");
325#endif
326                    break;
327                }
328                case VOBJ_TYPE_MWMR:    // storage capacity is (vobj.length/4 - 5) words
329                        {
330                    mwmr_channel_t* mwmr = (mwmr_channel_t*)(vobj[vobj_id].vaddr);
331                    mwmr->ptw   = 0;
332                    mwmr->ptr   = 0;
333                    mwmr->sts   = 0;
334                    mwmr->depth = (vobj[vobj_id].length>>2) - 5;
335                    mwmr->lock  = 0;
336#if INIT_DEBUG
337_puts("[INIT]   MWMR channel ");
338_puts( vobj->name);
339_puts(" / depth = ");
340_putw( mwmr->depth );
341_puts("\n");
342#endif
343                    break;
344                }
345                case VOBJ_TYPE_ELF:             // initialisation done by the loader
346                {
347
348#if INIT_DEBUG
349_puts("[INIT]   ELF section "); 
350_puts( vobj->name);
351_puts(" / length = ");
352_putw( vobj->length ); 
353_puts("\n");
354#endif
355                     break;
356                }
357                case VOBJ_TYPE_BARRIER: // init is the number of participants
358                {
359                    giet_barrier_t* barrier = (giet_barrier_t*)(vobj[vobj_id].vaddr);
360                    barrier->count = 0;
361                    barrier->init  = vobj[vobj_id].init;
362#if INIT_DEBUG
363_puts("   BARRIER "); 
364_puts( vobj->name);
365_puts(" / init_value = ");
366_putw( barrier->init );
367_puts("\n");
368#endif
369                    break;
370                }
371                case VOBJ_TYPE_LOCK:    // init is "not taken"
372                {
373                    unsigned int* lock = (unsigned int*)(vobj[vobj_id].vaddr);
374                    *lock = 0;
375#if INIT_DEBUG
376_puts("   LOCK "); 
377_puts( vobj->name);
378_puts("\n");
379#endif
380                    break;
381                }
382                case VOBJ_TYPE_BUFFER:  // nothing to do
383                {
384
385#if INIT_DEBUG
386_puts("   BUFFER "); 
387_puts( vobj->name);
388_puts(" / length = ");
389_putw( vobj->length ); 
390_puts("\n");
391#endif
392                    break;
393                }
394                default:
395                {
396                    _puts("\n[INIT ERROR] illegal vobj of name ");
397                    _puts(vobj->name);
398                    _puts(" / in vspace = ");
399                    _puts(vobj->name);
400                    _puts("\n ");
401                    _exit();
402                }
403            } // end switch type
404        } // end loop on vobjs
405        if( !ptab_found )
406        {
407            _puts("\n[INIT ERROR] Missing PTAB for vspace ");
408            _putw( vspace_id );
409            _exit();
410        }
411    } // end loop on vspaces
412
413    _puts("\n[INIT] Vobjs initialisation completed at cycle : ");
414    _putw( _proctime() );
415    _puts("\n");
416
417} // end _vobjs_init()
418
419///////////////////////////////////////////////////////////////////////////////
420// This function initialises all task contexts and processors schedulers.
421// It sets the default values for all schedulers (tasks <= 0, current <= 0).
422// Finally, it scan all tasks in all vspaces to initialise the schedulers,
423// and the tasks contexts, as defined in the mapping_info data structure.
424// A global TTY index and a global FB channel are allocated if required.
425// TTY[0] is reserved for the kernel.
426///////////////////////////////////////////////////////////////////////////////
427in_kinit void _kernel_tasks_init(unsigned int* ptabs)
428{
429    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
430    mapping_cluster_t*  cluster = _get_cluster_base( header );
431    mapping_vspace_t*   vspace  = _get_vspace_base( header );     
432    mapping_task_t*     task    = _get_task_base( header );
433
434    unsigned int        base_tty_id = 1;     // TTY index allocator
435    unsigned int        base_fb_id  = 0;     // FB channel index allocator
436
437    unsigned int        cluster_id; 
438    unsigned int        proc_id; 
439    unsigned int        vspace_id; 
440    unsigned int        task_id;
441
442    // initialise the schedulers (not done by the compiler)
443    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
444    {
445        for ( proc_id = 0 ; proc_id < cluster[cluster_id].procs ; proc_id++ )
446        {
447            if ( proc_id >= NB_PROCS )
448            {
449                _puts("\n[INIT ERROR] The number of processors in cluster ");
450                _putw( cluster_id );
451                _puts(" is larger than NB_PROCS \n");
452                _exit();
453            }
454            _scheduler[cluster_id*NB_PROCS+proc_id].tasks   = 0;
455            _scheduler[cluster_id*NB_PROCS+proc_id].current = 0;
456        }
457    }
458
459    // loop on the virtual spaces
460    for ( vspace_id = 0 ; vspace_id < header->vspaces ; vspace_id++ )
461    {
462
463#if INIT_DEBUG
464_puts("\n[INIT] mapping tasks in vspace ");
465_puts(vspace[vspace_id].name);
466_puts("\n");
467#endif
468        // loop on the tasks
469        for ( task_id = vspace[vspace_id].task_offset ; 
470              task_id < (vspace[vspace_id].task_offset + vspace[vspace_id].tasks) ; 
471              task_id++ )
472        {
473            unsigned int        tty_id = 0xFFFFFFFF;
474            unsigned int        fb_id  = 0xFFFFFFFF;
475            if ( task[task_id].use_tty ) 
476            {
477                tty_id = base_tty_id;
478                base_tty_id++;
479            }
480            if ( task[task_id].use_fb  ) 
481            {
482                fb_id = base_fb_id;
483                base_fb_id++;
484            }
485            _task_map( task_id,                         // global task index
486                       vspace_id,                       // vspace index
487                       tty_id,                          // global tty index
488                       fb_id,                           // global fbdma index
489                       ptabs[vspace_id] );      // page table pointer
490        } // end loop on tasks
491    } // end oop on vspaces
492
493    _puts("\n[INIT] Task Contexts initialisation completed at cycle ");
494    _putw( _proctime() );
495    _puts("\n");
496
497#if INIT_DEBUG
498for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
499{
500    _puts("\nCluster ");
501    _putw( cluster_id );
502    _puts("\n");
503    for ( proc_id = 0 ; proc_id < cluster[cluster_id].procs ; proc_id++ )
504    {
505        unsigned int ltid;              // local task index
506        unsigned int gtid;              // global task index
507        unsigned int pid = cluster_id * NB_PROCS + proc_id;
508       
509        _puts(" - processor ");
510        _putw( pid );
511        _puts("\n");
512        for ( ltid = 0 ; ltid < _scheduler[pid].tasks ; ltid++ )
513        {
514            gtid = _scheduler[pid].context[ltid][CTX_TASK_ID];
515            _puts("    task : ");
516            _puts( task[gtid].name );
517            _puts("\n");
518        }
519    }
520}
521#endif
522
523} // end _kernel_task_init()
524
525////////////////////////////////////////////////////////////////////////////////
526// This function intializes the external periherals such as the IOB component
527// (I/O bridge, containing the IOMMU, the IOC (external disk controller),
528// the NIC (external network controller), the FBDMA (frame buffer controller),
529////////////////////////////////////////////////////////////////////////////////
530in_kinit void _kernel_peripherals_init()
531{
532    // IOC peripheral initialisation
533    // we simply activate the IOC interrupts...
534    unsigned int*       ioc_address = (unsigned int*)&seg_ioc_base;
535
536    ioc_address[BLOCK_DEVICE_IRQ_ENABLE] = 1;
537   
538    // IOB peripheral
539    if ( GIET_IOMMU_ACTIVE )
540    {
541        unsigned int*   iob_address = (unsigned int*)&seg_iob_base;
542        unsigned int    icu_address = (unsigned int)&seg_icu_base;
543
544        // define IPI address mapping the IOC interrupt ...TODO...
545
546        // set IOMMU page table address
547        iob_address[IOB_IOMMU_PTPR] = (unsigned int)(&_iommu_ptab);   
548
549        // activate IOMMU
550        iob_address[IOB_IOMMU_ACTIVE] = 1;   
551    }
552
553    _puts("\n[INIT] Peripherals initialisation completed at cycle ");
554    _putw( _proctime() );
555    _puts("\n");
556
557} // end _kernel_peripherals_init()
558
559////////////////////////////////////////////////////////////////////////////////
560// This function intialises the interrupt vector, and initialises
561// the ICU mask registers for all processors in all clusters.
562// It strongly depends on the actual peripheral hardware wiring.
563// In this peculiar version, all clusters are identical,
564// the number of processors per cluster cannot be larger than 8.
565// Processor 0 handle all interrupts corresponding to TTYs, DMAs and IOC
566// (ICU inputs from from IRQ[8] to IRQ[31]). Only the 8 TIMER interrupts
567// (ICU iputs IRQ[0] to IRQ[7]), that are used for context switching
568// are distributed to the 8 processors.
569////////////////////////////////////////////////////////////////////////////////
570in_kinit void _kernel_interrupt_vector_init()
571{
572    mapping_header_t*   header  = (mapping_header_t*)&seg_mapping_base; 
573    mapping_cluster_t*  cluster = _get_cluster_base( header );
574
575    unsigned int cluster_id;
576    unsigned int proc_id;
577
578    // ICU mask values (up to 8 processors per cluster)
579    unsigned int icu_mask[8] = { 0xFFFFFF01,
580                                 0x00000002,
581                                 0x00000004,
582                                 0x00000008,
583                                 0x00000010,
584                                 0x00000020,
585                                 0x00000040,
586                                 0x00000080 };
587
588    // initialise ICUs for each processor in each cluster
589    for ( cluster_id = 0 ; cluster_id < header->clusters ; cluster_id++ )
590    {
591        for ( proc_id = 0 ; proc_id < cluster[cluster_id].procs ; proc_id++ )
592        {
593            _icu_write( cluster_id, proc_id, ICU_MASK_SET, icu_mask[proc_id] ); 
594        }
595    }
596
597    // initialize Interrupt vector
598
599    _interrupt_vector[0]   = &_isr_switch;
600    _interrupt_vector[1]   = &_isr_switch;
601    _interrupt_vector[2]   = &_isr_switch;
602    _interrupt_vector[3]   = &_isr_switch;
603    _interrupt_vector[4]   = &_isr_switch;
604    _interrupt_vector[5]   = &_isr_switch;
605    _interrupt_vector[6]   = &_isr_switch;
606    _interrupt_vector[7]   = &_isr_switch;
607
608    _interrupt_vector[8]   = &_isr_dma_0;
609    _interrupt_vector[9]   = &_isr_dma_1;
610    _interrupt_vector[10]  = &_isr_dma_2;
611    _interrupt_vector[11]  = &_isr_dma_3;
612    _interrupt_vector[12]  = &_isr_dma_4;
613    _interrupt_vector[13]  = &_isr_dma_5;
614    _interrupt_vector[14]  = &_isr_dma_6;
615    _interrupt_vector[15]  = &_isr_dma_7;
616
617    _interrupt_vector[16]  = &_isr_tty_get_0;
618    _interrupt_vector[17]  = &_isr_tty_get_1;
619    _interrupt_vector[18]  = &_isr_tty_get_2;
620    _interrupt_vector[19]  = &_isr_tty_get_3;
621    _interrupt_vector[20]  = &_isr_tty_get_4;
622    _interrupt_vector[21]  = &_isr_tty_get_5;
623    _interrupt_vector[22]  = &_isr_tty_get_6;
624    _interrupt_vector[23]  = &_isr_tty_get_7;
625    _interrupt_vector[24]  = &_isr_tty_get_8;
626    _interrupt_vector[25]  = &_isr_tty_get_9;
627    _interrupt_vector[26]  = &_isr_tty_get_10;
628    _interrupt_vector[27]  = &_isr_tty_get_11;
629    _interrupt_vector[28]  = &_isr_tty_get_12;
630    _interrupt_vector[29]  = &_isr_tty_get_13;
631    _interrupt_vector[30]  = &_isr_tty_get_14;
632
633    _interrupt_vector[31]  = &_isr_ioc;
634
635    _puts("\n[INIT] Interrupt vector initialisation completed at cycle ");
636    _putw( _proctime() );
637    _puts("\n");
638
639} // end _kernel_interrup_vector_init()
Note: See TracBrowser for help on using the repository browser.