source: rtems/c/src/lib/libcpu/i386/cpu.c @ 67a2288

4.104.114.84.95
Last change on this file since 67a2288 was 67a2288, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 23, 1998 at 10:02:34 PM

Patch from Eric VALETTE <valette@…>:

Here is a enhanced version of my previous patch. This patch enables
to potentially share the new interrupt management code for all Intel targets
(pc386, go32 and force386) bsp.

Note : this patch is complete only for pc386. It still needs to

be completed for go32 and force386. I carrefully checked
that anything needed is in for force386 (only some function
name changes for IDT manipulation and GDT segment
manipulation). But anyway I will not be able to test any
of theses targets...

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * cpu.c  - This file contains implementation of C function to
3 *          Instanciate IDT entries. More detailled information can be found
4 *          on Intel site and more precisely in the following book :
5 *
6 *              Pentium Processor familly
7 *              Developper's Manual
8 *
9 *              Volume 3 : Architecture and Programming Manual
10 *
11 * Copyright (C) 1998  Eric Valette (valette@crf.canon.fr)
12 *                     Canon Centre Recherche France.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in found in the file LICENSE in this distribution or at
16 *  http://www.OARcorp.com/rtems/license.html.
17 *
18 * $Id$
19 */
20
21#include <libcpu/cpu.h>
22#include <irq.h>
23
24static rtems_raw_irq_connect_data*      raw_irq_table;
25static rtems_raw_irq_connect_data       default_raw_irq_entry;
26static interrupt_gate_descriptor        default_idt_entry;
27static rtems_raw_irq_global_settings*   local_settings;
28
29void create_interrupt_gate_descriptor (interrupt_gate_descriptor* idtEntry,
30                                       rtems_raw_irq_hdl hdl)
31{
32    idtEntry->low_offsets_bits  = (((unsigned) hdl) & 0xffff);
33    idtEntry->segment_selector  = i386_get_cs(); 
34    idtEntry->fixed_value_bits  = 0;
35    idtEntry->gate_type         = 0xe; 
36    idtEntry->privilege         = 0;
37    idtEntry->present           = 1;
38    idtEntry->high_offsets_bits = ((((unsigned) hdl) >> 16) & 0xffff);
39}
40
41rtems_raw_irq_hdl get_hdl_from_vector(rtems_vector_offset index)
42{
43    rtems_raw_irq_hdl           hdl;
44    interrupt_gate_descriptor*  idt_entry_tbl;
45    unsigned                    limit;
46
47    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
48 
49    * ((unsigned int*) &hdl) = (idt_entry_tbl[index].low_offsets_bits | 
50                              (idt_entry_tbl[index].high_offsets_bits << 16));
51    return hdl;
52}
53
54int i386_set_idt_entry  (const rtems_raw_irq_connect_data* irq)
55{
56    interrupt_gate_descriptor*  idt_entry_tbl;
57    unsigned                    limit;
58    unsigned int                level;
59
60   
61    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
62
63    if (irq->idtIndex > limit) {
64      return 0;
65    }
66    /*
67     * Check if default handler is actually connected. If not issue an error.
68     * You must first get the current handler via i386_get_current_idt_entry
69     * and then disconnect it using i386_delete_idt_entry.
70     * RATIONALE : to always have the same transition by forcing the user
71     * to get the previous handler before accepting to disconnect.
72     */
73    if (get_hdl_from_vector(irq->idtIndex) != default_raw_irq_entry.hdl) {
74      return 0;
75    }
76    _CPU_ISR_Disable(level);
77   
78    raw_irq_table [irq->idtIndex] = *irq;
79    create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl);
80    irq->on(irq);
81   
82    _CPU_ISR_Enable(level);
83    return 1;
84}
85
86void _CPU_ISR_install_vector (unsigned vector,
87                              void* hdl,
88                              void** oldHdl)
89{
90    interrupt_gate_descriptor*  idt_entry_tbl;
91    unsigned                    limit;
92    interrupt_gate_descriptor   new;
93    unsigned int                level;
94   
95    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
96
97    if (vector > limit) {
98      return;
99    }
100    _CPU_ISR_Disable(level)
101    * ((unsigned int *) oldHdl) = idt_entry_tbl[vector].low_offsets_bits |
102        (idt_entry_tbl[vector].high_offsets_bits << 16);
103
104    create_interrupt_gate_descriptor(&new,  hdl);
105    idt_entry_tbl[vector] = new;
106
107    _CPU_ISR_Enable(level);
108}
109                               
110int i386_get_current_idt_entry (rtems_raw_irq_connect_data* irq)
111{
112    interrupt_gate_descriptor*  idt_entry_tbl;
113    unsigned                    limit;
114
115    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
116
117    if (irq->idtIndex > limit) {
118      return 1;
119    }
120    raw_irq_table [irq->idtIndex].hdl = get_hdl_from_vector(irq->idtIndex);
121   
122    *irq = raw_irq_table [irq->idtIndex];
123   
124    return 0;
125}
126
127int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
128{
129    interrupt_gate_descriptor*  idt_entry_tbl;
130    unsigned                    limit;
131    unsigned int                level;
132   
133    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
134
135    if (irq->idtIndex > limit) {
136      return 1;
137    }
138     /*
139     * Check if handler passed is actually connected. If not issue an error.
140     * You must first get the current handler via i386_get_current_idt_entry
141     * and then disconnect it using i386_delete_idt_entry.
142     * RATIONALE : to always have the same transition by forcing the user
143     * to get the previous handler before accepting to disconnect.
144     */
145    if (get_hdl_from_vector(irq->idtIndex) != irq->hdl){
146      return 1;
147    }
148    _CPU_ISR_Disable(level);
149
150    idt_entry_tbl[irq->idtIndex] = default_idt_entry;
151
152    irq->off(irq);
153   
154    raw_irq_table[irq->idtIndex] = default_raw_irq_entry;
155
156    _CPU_ISR_Enable(level);
157   
158    return 0;
159}
160
161/*
162 * Caution this function assumes the IDTR has been already set.
163 */
164int i386_init_idt (rtems_raw_irq_global_settings* config)
165{
166    unsigned                    limit;
167    unsigned                    i;
168    unsigned                    level;
169    interrupt_gate_descriptor*  idt_entry_tbl;
170   
171    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
172
173     
174    if (config->idtSize != limit) {
175      return 1;
176    }
177    /*
178     * store various accelarators
179     */
180    raw_irq_table               = config->rawIrqHdlTbl;
181    local_settings              = config;
182    default_raw_irq_entry       = config->defaultRawEntry;
183
184    _CPU_ISR_Disable(level);
185
186    create_interrupt_gate_descriptor (&default_idt_entry, default_raw_irq_entry.hdl);
187
188    for (i=0; i < limit; i++) {
189      interrupt_gate_descriptor new;
190      create_interrupt_gate_descriptor (&new, raw_irq_table[i].hdl);
191      idt_entry_tbl[i] = new;
192      if (raw_irq_table[i].hdl != default_raw_irq_entry.hdl) {
193        raw_irq_table[i].on(&raw_irq_table[i]);
194      }
195      else {
196        raw_irq_table[i].off(&raw_irq_table[i]);
197      }
198    }
199    _CPU_ISR_Enable(level);
200
201    return 0;
202}
203
204int i386_get_idt_config (rtems_raw_irq_global_settings** config)
205{
206  *config = local_settings;
207  return 0;
208}
209
210/*
211 * Caution this function assumes the GDTR has been already set.
212 */
213int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
214                        unsigned limit)
215{
216    unsigned                    gdt_limit;
217    unsigned short              tmp_segment = 0;
218    unsigned int                limit_adjusted;
219    segment_descriptors*        gdt_entry_tbl;
220
221     
222    i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
223
224    if (segment_selector > limit) {
225      return 1;
226    }
227    /*
228     * set up limit first
229     */
230    limit_adjusted = limit;
231    if ( limit > 4095 ) {
232      gdt_entry_tbl[segment_selector].granularity = 1;
233      limit_adjusted /= 4096;
234    }
235    gdt_entry_tbl[segment_selector].limit_15_0  = limit_adjusted & 0xffff;
236    gdt_entry_tbl[segment_selector].limit_19_16 = (limit_adjusted >> 16) & 0xf;
237    /*
238     * set up base
239     */
240    gdt_entry_tbl[segment_selector].base_address_15_0  = base & 0xffff;
241    gdt_entry_tbl[segment_selector].base_address_23_16 = (base >> 16) & 0xff;
242    gdt_entry_tbl[segment_selector].base_address_31_24 = (base >> 24) & 0xff;
243    /*
244     * set up descriptor type (this may well becomes a parameter if needed)
245     */
246    gdt_entry_tbl[segment_selector].type                = 2;    /* Data R/W */
247    gdt_entry_tbl[segment_selector].descriptor_type     = 1;    /* Code or Data */
248    gdt_entry_tbl[segment_selector].privilege           = 0;    /* ring 0 */
249    gdt_entry_tbl[segment_selector].present             = 1;    /* not present */
250
251    /*
252     * Now, reload all segment registers so the limit takes effect.
253     */
254
255    asm volatile( "movw %%ds,%0 ; movw %0,%%ds
256                   movw %%es,%0 ; movw %0,%%es
257                   movw %%fs,%0 ; movw %0,%%fs
258                   movw %%gs,%0 ; movw %0,%%gs
259                   movw %%ss,%0 ; movw %0,%%ss"
260                   : "=r" (tmp_segment)
261                   : "0"  (tmp_segment)
262                  );
263   
264    return 0;
265}
Note: See TracBrowser for help on using the repository browser.