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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [lib/] [libcpu/] [i386/] [cpu.c] - Blame information for rev 307

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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