File indexing completed on 2025-05-11 08:23:41
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <rtems/score/cpu.h>
0020 #include <bsp/irq.h>
0021 #include <bsp/tblsizes.h>
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_idt_access_lock, "rtems_idt_access_lock" );
0032
0033 static rtems_raw_irq_connect_data* raw_irq_table;
0034 static rtems_raw_irq_connect_data default_raw_irq_entry;
0035 static interrupt_gate_descriptor default_idt_entry;
0036 static rtems_raw_irq_global_settings* local_settings;
0037
0038 void create_interrupt_gate_descriptor (interrupt_gate_descriptor* idtEntry,
0039 rtems_raw_irq_hdl hdl)
0040 {
0041 idtEntry->low_offsets_bits = (((unsigned) hdl) & 0xffff);
0042 idtEntry->segment_selector = i386_get_cs();
0043 idtEntry->fixed_value_bits = 0;
0044 idtEntry->gate_type = 0xe;
0045 idtEntry->privilege = 0;
0046 idtEntry->present = 1;
0047 idtEntry->high_offsets_bits = ((((unsigned) hdl) >> 16) & 0xffff);
0048 }
0049
0050 rtems_raw_irq_hdl get_hdl_from_vector(rtems_vector_offset index)
0051 {
0052 uint32_t hdl;
0053 interrupt_gate_descriptor* idt_entry_tbl;
0054 unsigned limit;
0055
0056 i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
0057
0058
0059 limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
0060
0061 if(index >= limit) {
0062 return 0;
0063 }
0064
0065 hdl = (idt_entry_tbl[index].low_offsets_bits |
0066 (idt_entry_tbl[index].high_offsets_bits << 16));
0067 return (rtems_raw_irq_hdl) hdl;
0068 }
0069
0070 int i386_set_idt_entry (const rtems_raw_irq_connect_data* irq)
0071 {
0072 interrupt_gate_descriptor* idt_entry_tbl;
0073 unsigned limit;
0074 rtems_interrupt_lock_context lock_context;
0075
0076 i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
0077
0078
0079 limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
0080
0081 if (irq->idtIndex >= limit) {
0082 return 0;
0083 }
0084
0085
0086
0087
0088
0089
0090
0091 if (get_hdl_from_vector(irq->idtIndex) != default_raw_irq_entry.hdl) {
0092 return 0;
0093 }
0094
0095 rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
0096
0097 raw_irq_table [irq->idtIndex] = *irq;
0098 create_interrupt_gate_descriptor (&idt_entry_tbl[irq->idtIndex], irq->hdl);
0099 if (irq->on)
0100 irq->on(irq);
0101
0102 rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
0103 return 1;
0104 }
0105
0106 void _CPU_ISR_install_vector (uint32_t vector,
0107 CPU_ISR_handler hdl,
0108 CPU_ISR_handler * oldHdl)
0109 {
0110 interrupt_gate_descriptor* idt_entry_tbl;
0111 unsigned limit;
0112 interrupt_gate_descriptor new;
0113 rtems_interrupt_lock_context lock_context;
0114
0115 i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
0116
0117
0118 limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
0119
0120 if (vector >= limit) {
0121 return;
0122 }
0123 rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
0124 *oldHdl = (CPU_ISR_handler) (idt_entry_tbl[vector].low_offsets_bits |
0125 (idt_entry_tbl[vector].high_offsets_bits << 16));
0126
0127 create_interrupt_gate_descriptor(&new, hdl);
0128 idt_entry_tbl[vector] = new;
0129
0130 rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
0131 }
0132
0133 int i386_get_current_idt_entry (rtems_raw_irq_connect_data* irq)
0134 {
0135 interrupt_gate_descriptor* idt_entry_tbl;
0136 unsigned limit;
0137
0138 i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
0139
0140
0141 limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
0142
0143 if (irq->idtIndex >= limit) {
0144 return 0;
0145 }
0146 raw_irq_table [irq->idtIndex].hdl = get_hdl_from_vector(irq->idtIndex);
0147
0148 *irq = raw_irq_table [irq->idtIndex];
0149
0150 return 1;
0151 }
0152
0153 int i386_delete_idt_entry (const rtems_raw_irq_connect_data* irq)
0154 {
0155 interrupt_gate_descriptor* idt_entry_tbl;
0156 unsigned limit;
0157 rtems_interrupt_lock_context lock_context;
0158
0159 i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
0160
0161
0162 limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
0163
0164 if (irq->idtIndex >= limit) {
0165 return 0;
0166 }
0167
0168
0169
0170
0171
0172
0173
0174 if (get_hdl_from_vector(irq->idtIndex) != irq->hdl){
0175 return 0;
0176 }
0177 rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
0178
0179 idt_entry_tbl[irq->idtIndex] = default_idt_entry;
0180
0181 if (irq->off)
0182 irq->off(irq);
0183
0184 raw_irq_table[irq->idtIndex] = default_raw_irq_entry;
0185 raw_irq_table[irq->idtIndex].idtIndex = irq->idtIndex;
0186
0187 rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
0188
0189 return 1;
0190 }
0191
0192
0193
0194
0195 int i386_init_idt (rtems_raw_irq_global_settings* config)
0196 {
0197 unsigned limit;
0198 unsigned i;
0199 rtems_interrupt_lock_context lock_context;
0200 interrupt_gate_descriptor* idt_entry_tbl;
0201
0202 i386_get_info_from_IDTR (&idt_entry_tbl, &limit);
0203
0204
0205 limit = (limit + 1) / sizeof(interrupt_gate_descriptor);
0206
0207 if (config->idtSize != limit) {
0208 return 0;
0209 }
0210
0211
0212
0213 raw_irq_table = config->rawIrqHdlTbl;
0214 local_settings = config;
0215 default_raw_irq_entry = config->defaultRawEntry;
0216
0217 rtems_interrupt_lock_acquire(&rtems_idt_access_lock, &lock_context);
0218
0219 create_interrupt_gate_descriptor (&default_idt_entry, default_raw_irq_entry.hdl);
0220
0221 for (i=0; i < limit; i++) {
0222 interrupt_gate_descriptor new;
0223 create_interrupt_gate_descriptor (&new, raw_irq_table[i].hdl);
0224 idt_entry_tbl[i] = new;
0225 if (raw_irq_table[i].hdl != default_raw_irq_entry.hdl) {
0226 raw_irq_table[i].on(&raw_irq_table[i]);
0227 }
0228 else {
0229 raw_irq_table[i].off(&raw_irq_table[i]);
0230 }
0231 }
0232 rtems_interrupt_lock_release(&rtems_idt_access_lock, &lock_context);
0233
0234 return 1;
0235 }
0236
0237 int i386_get_idt_config (rtems_raw_irq_global_settings** config)
0238 {
0239 *config = local_settings;
0240 return 1;
0241 }
0242
0243 uint32_t i386_raw_gdt_entry (uint16_t segment_selector_index,
0244 segment_descriptors* sd)
0245 {
0246 uint16_t gdt_limit;
0247 uint16_t tmp_segment = 0;
0248 segment_descriptors* gdt_entry_tbl;
0249 uint8_t present;
0250
0251 i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
0252
0253 if (segment_selector_index >= (gdt_limit+1)/8) {
0254
0255 return 0;
0256 }
0257 if (segment_selector_index == 0) {
0258
0259 return 0;
0260 }
0261
0262
0263 present = sd->present;
0264 sd->present = 0;
0265 gdt_entry_tbl[segment_selector_index].present = 0;
0266 RTEMS_COMPILER_MEMORY_BARRIER();
0267 gdt_entry_tbl[segment_selector_index] = *sd;
0268 RTEMS_COMPILER_MEMORY_BARRIER();
0269 gdt_entry_tbl[segment_selector_index].present = present;
0270 sd->present = present;
0271
0272
0273
0274 __asm__ volatile( "movw %%ds,%0 ; movw %0,%%ds\n\t"
0275 "movw %%es,%0 ; movw %0,%%es\n\t"
0276 "movw %%fs,%0 ; movw %0,%%fs\n\t"
0277 "movw %%gs,%0 ; movw %0,%%gs\n\t"
0278 "movw %%ss,%0 ; movw %0,%%ss"
0279 : "=r" (tmp_segment)
0280 : "0" (tmp_segment)
0281 );
0282 return 1;
0283 }
0284
0285 void i386_fill_segment_desc_base(uint32_t base,
0286 segment_descriptors* sd)
0287 {
0288 sd->base_address_15_0 = base & 0xffff;
0289 sd->base_address_23_16 = (base >> 16) & 0xff;
0290 sd->base_address_31_24 = (base >> 24) & 0xff;
0291 }
0292
0293 void i386_fill_segment_desc_limit(uint32_t limit,
0294 segment_descriptors* sd)
0295 {
0296 sd->granularity = 0;
0297 if (limit > 65535) {
0298 sd->granularity = 1;
0299 limit /= 4096;
0300 }
0301 sd->limit_15_0 = limit & 0xffff;
0302 sd->limit_19_16 = (limit >> 16) & 0xf;
0303 }
0304
0305
0306
0307
0308 uint32_t i386_set_gdt_entry (uint16_t segment_selector_index, uint32_t base,
0309 uint32_t limit)
0310 {
0311 segment_descriptors gdt_entry;
0312 memset(&gdt_entry, 0, sizeof(gdt_entry));
0313
0314 i386_fill_segment_desc_limit(limit, &gdt_entry);
0315 i386_fill_segment_desc_base(base, &gdt_entry);
0316
0317
0318
0319 gdt_entry.type = 2;
0320 gdt_entry.descriptor_type = 1;
0321 gdt_entry.privilege = 0;
0322 gdt_entry.present = 1;
0323
0324
0325
0326
0327 return i386_raw_gdt_entry(segment_selector_index, &gdt_entry);
0328 }
0329
0330 uint16_t i386_next_empty_gdt_entry ()
0331 {
0332 uint16_t gdt_limit;
0333 segment_descriptors* gdt_entry_tbl;
0334
0335 static uint16_t segment_selector_index = NUM_SYSTEM_GDT_DESCRIPTORS - 1;
0336
0337 segment_selector_index += 1;
0338 i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
0339 if (segment_selector_index >= (gdt_limit+1)/8) {
0340 return 0;
0341 }
0342 return segment_selector_index;
0343 }
0344
0345 uint16_t i386_cpy_gdt_entry(uint16_t segment_selector_index,
0346 segment_descriptors* struct_to_fill)
0347 {
0348 uint16_t gdt_limit;
0349 segment_descriptors* gdt_entry_tbl;
0350
0351 i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
0352
0353 if (segment_selector_index >= (gdt_limit+1)/8) {
0354 return 0;
0355 }
0356
0357 *struct_to_fill = gdt_entry_tbl[segment_selector_index];
0358 return segment_selector_index;
0359 }
0360
0361 segment_descriptors* i386_get_gdt_entry(uint16_t segment_selector_index)
0362 {
0363 uint16_t gdt_limit;
0364 segment_descriptors* gdt_entry_tbl;
0365
0366 i386_get_info_from_GDTR (&gdt_entry_tbl, &gdt_limit);
0367
0368 if (segment_selector_index >= (gdt_limit+1)/8) {
0369 return 0;
0370 }
0371 return &gdt_entry_tbl[segment_selector_index];
0372 }
0373
0374 uint32_t i386_limit_gdt_entry(segment_descriptors* gdt_entry)
0375 {
0376 uint32_t lim = (gdt_entry->limit_15_0 + (gdt_entry->limit_19_16<<16));
0377 if (gdt_entry->granularity) {
0378 return lim*4096+4095;
0379 }
0380 return lim;
0381 }