source: rtems/c/src/lib/libcpu/i386/cpu.c @ 362b88e

4.104.114.84.95
Last change on this file since 362b88e was 97d7b068, checked in by Joel Sherrill <joel.sherrill@…>, on 09/21/98 at 00:40:18

Update from Aleksey (Quality Quorum <qqi@…>) to pick up some
patches missing from 980911.

  • Property mode set to 100644
File size: 8.3 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    /* Convert limit into number of entries */
50    limit = (limit + 1) >> 3;
51
52    if(index >= limit) {
53        return 0;
54    }
55       
56    /* Convert limit into number of entries */
57    limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
58 
59    if(index >= limit) {
60        return 0;
61    }
62
63    * ((unsigned int*) &hdl) = (idt_entry_tbl[index].low_offsets_bits |
64                              (idt_entry_tbl[index].high_offsets_bits << 16));
65    return hdl;
66}
67
68int i386_set_idt_entry  (const rtems_raw_irq_connect_data* irq)
69{
70    interrupt_gate_descriptor*  idt_entry_tbl;
71    unsigned                    limit;
72    unsigned int                level;
73
74   
75    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
76
77    /* Convert limit into number of entries */
78    limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
79
80    if (irq->idtIndex >= limit) {
81      return 0;
82    }
83    /*
84     * Check if default handler is actually connected. If not issue an error.
85     * You must first get the current handler via i386_get_current_idt_entry
86     * and then disconnect it using i386_delete_idt_entry.
87     * RATIONALE : to always have the same transition by forcing the user
88     * to get the previous handler before accepting to disconnect.
89     */
90    if (get_hdl_from_vector(irq->idtIndex) != default_raw_irq_entry.hdl) {
91      return 0;
92    }
93
94    _CPU_ISR_Disable(level);
95   
96    raw_irq_table [irq->idtIndex] = *irq;
97    create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl);
98    irq->on(irq);
99   
100    _CPU_ISR_Enable(level);
101    return 1;
102}
103
104void _CPU_ISR_install_vector (unsigned vector,
105                              void* hdl,
106                              void** oldHdl)
107{
108    interrupt_gate_descriptor*  idt_entry_tbl;
109    unsigned                    limit;
110    interrupt_gate_descriptor   new;
111    unsigned int                level;
112   
113    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
114
115    /* Convert limit into number of entries */
116    limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
117
118    if (vector >= limit) {
119      return;
120    }
121    _CPU_ISR_Disable(level)
122    * ((unsigned int *) oldHdl) = idt_entry_tbl[vector].low_offsets_bits |
123        (idt_entry_tbl[vector].high_offsets_bits << 16);
124
125    create_interrupt_gate_descriptor(&new,  hdl);
126    idt_entry_tbl[vector] = new;
127
128    _CPU_ISR_Enable(level);
129}
130                               
131int i386_get_current_idt_entry (rtems_raw_irq_connect_data* irq)
132{
133    interrupt_gate_descriptor*  idt_entry_tbl;
134    unsigned                    limit;
135
136    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
137
138    /* Convert limit into number of entries */
139    limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
140
141    if (irq->idtIndex >= limit) {
142      return 0;
143    }
144    raw_irq_table [irq->idtIndex].hdl = get_hdl_from_vector(irq->idtIndex);
145   
146    *irq = raw_irq_table [irq->idtIndex];
147   
148    return 1;
149}
150
151int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
152{
153    interrupt_gate_descriptor*  idt_entry_tbl;
154    unsigned                    limit;
155    unsigned int                level;
156   
157    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
158
159    /* Convert limit into number of entries */
160    limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
161
162    if (irq->idtIndex >= limit) {
163      return 0;
164    }
165    /*
166     * Check if handler passed is actually connected. If not issue an error.
167     * You must first get the current handler via i386_get_current_idt_entry
168     * and then disconnect it using i386_delete_idt_entry.
169     * RATIONALE : to always have the same transition by forcing the user
170     * to get the previous handler before accepting to disconnect.
171     */
172    if (get_hdl_from_vector(irq->idtIndex) != irq->hdl){
173      return 0;
174    }
175    _CPU_ISR_Disable(level);
176
177    idt_entry_tbl[irq->idtIndex] = default_idt_entry;
178
179    irq->off(irq);
180   
181    raw_irq_table[irq->idtIndex] = default_raw_irq_entry;
182    raw_irq_table[irq->idtIndex].idtIndex = irq->idtIndex;
183
184    _CPU_ISR_Enable(level);
185   
186    return 1;
187}
188
189/*
190 * Caution this function assumes the IDTR has been already set.
191 */
192int i386_init_idt (rtems_raw_irq_global_settings* config)
193{
194    unsigned                    limit;
195    unsigned                    i;
196    unsigned                    level;
197    interrupt_gate_descriptor*  idt_entry_tbl;
198   
199    i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
200
201    /* Convert limit into number of entries */
202    limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
203     
204    if (config->idtSize != limit) {
205      return 0;
206    }
207    /*
208     * store various accelarators
209     */
210    raw_irq_table               = config->rawIrqHdlTbl;
211    local_settings              = config;
212    default_raw_irq_entry       = config->defaultRawEntry;
213
214    _CPU_ISR_Disable(level);
215
216    create_interrupt_gate_descriptor (&default_idt_entry, default_raw_irq_entry.hdl);
217
218    for (i=0; i < limit; i++) {
219      interrupt_gate_descriptor new;
220      create_interrupt_gate_descriptor (&new, raw_irq_table[i].hdl);
221      idt_entry_tbl[i] = new;
222      if (raw_irq_table[i].hdl != default_raw_irq_entry.hdl) {
223        raw_irq_table[i].on(&raw_irq_table[i]);
224      }
225      else {
226        raw_irq_table[i].off(&raw_irq_table[i]);
227      }
228    }
229    _CPU_ISR_Enable(level);
230
231    return 1;
232}
233
234int i386_get_idt_config (rtems_raw_irq_global_settings** config)
235{
236  *config = local_settings;
237  return 1;
238}
239
240/*
241 * Caution this function assumes the GDTR has been already set.
242 */
243int i386_set_gdt_entry (unsigned short segment_selector, unsigned base,
244                        unsigned limit)
245{
246    unsigned                    gdt_limit;
247    unsigned short              tmp_segment = 0;
248    unsigned int                limit_adjusted;
249    segment_descriptors*        gdt_entry_tbl;
250
251     
252    i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
253
254    if (segment_selector > limit) {
255      return 0;
256    }
257    /*
258     * set up limit first
259     */
260    limit_adjusted = limit;
261    if ( limit > 4095 ) {
262      gdt_entry_tbl[segment_selector].granularity = 1;
263      limit_adjusted /= 4096;
264    }
265    gdt_entry_tbl[segment_selector].limit_15_0  = limit_adjusted & 0xffff;
266    gdt_entry_tbl[segment_selector].limit_19_16 = (limit_adjusted >> 16) & 0xf;
267    /*
268     * set up base
269     */
270    gdt_entry_tbl[segment_selector].base_address_15_0  = base & 0xffff;
271    gdt_entry_tbl[segment_selector].base_address_23_16 = (base >> 16) & 0xff;
272    gdt_entry_tbl[segment_selector].base_address_31_24 = (base >> 24) & 0xff;
273    /*
274     * set up descriptor type (this may well becomes a parameter if needed)
275     */
276    gdt_entry_tbl[segment_selector].type                = 2;    /* Data R/W */
277    gdt_entry_tbl[segment_selector].descriptor_type     = 1;    /* Code or Data */
278    gdt_entry_tbl[segment_selector].privilege           = 0;    /* ring 0 */
279    gdt_entry_tbl[segment_selector].present             = 1;    /* not present */
280
281    /*
282    return 1;
283     */
284
285    asm volatile( "movw %%ds,%0 ; movw %0,%%ds
286                   movw %%es,%0 ; movw %0,%%es
287                   movw %%fs,%0 ; movw %0,%%fs
288                   movw %%gs,%0 ; movw %0,%%gs
289                   movw %%ss,%0 ; movw %0,%%ss"
290                   : "=r" (tmp_segment)
291                   : "0"  (tmp_segment)
292                  );
293   
294    return 1;
295}
Note: See TracBrowser for help on using the repository browser.