Warning, cross-references for /kernel/smp/apic.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include "arch/i386.h"
0019 #include "kernel.h"
0020 #include "mem/mem.h"
0021 #include "smp/smp.h"
0022 #include "smp/apic.h"
0023 #include "smp/spinlock.h"
0024 #include "util/printf.h"
0025
0026 #define APIC_BROADCAST_ID 0xFF
0027
0028
0029 #define LAPIC_ADDR_DEFAULT 0xFEE00000uL
0030 #define IOAPIC_ADDR_DEFAULT 0xFEC00000uL
0031
0032 uint32 mp_LAPIC_addr = LAPIC_ADDR_DEFAULT;
0033 #define MP_LAPIC_READ(x) (*((volatile uint32 *) (mp_LAPIC_addr+(x))))
0034 #define MP_LAPIC_WRITE(x,y) (*((volatile uint32 *) (mp_LAPIC_addr+(x))) = (y))
0035
0036 uint32 mp_IOAPIC_addr = IOAPIC_ADDR_DEFAULT;
0037 mp_IOAPIC_info mp_IOAPICs[MAX_IOAPICS];
0038 uint32 mp_num_IOAPICs = 0;
0039 #define MP_IOAPIC_READ(x) (*((volatile uint32 *) (mp_IOAPIC_addr+(x))))
0040 #define MP_IOAPIC_WRITE(x,y) (*((volatile uint32 *) (mp_IOAPIC_addr+(x))) = (y))
0041
0042
0043
0044
0045
0046
0047
0048
0049 int
0050 LAPIC_send_ipi (uint32 dest, uint32 v)
0051 {
0052 int timeout, send_status;
0053
0054
0055
0056 asm volatile ("pushfl");
0057 asm volatile ("cli");
0058
0059 MP_LAPIC_WRITE (LAPIC_ICR + 0x10, dest << 24);
0060 MP_LAPIC_WRITE (LAPIC_ICR, v);
0061
0062
0063
0064 timeout = 0;
0065 do {
0066 send_status = MP_LAPIC_READ (LAPIC_ICR) & LAPIC_ICR_STATUS_PEND;
0067 } while (send_status && (timeout++ < 1000));
0068
0069 asm volatile ("popfl");
0070
0071 return (timeout < 1000);
0072 }
0073
0074 void
0075 LAPIC_init(void)
0076 {
0077 MP_LAPIC_WRITE (LAPIC_TPR, 0x00);
0078 MP_LAPIC_WRITE (LAPIC_LVTT, 0x10000);
0079 MP_LAPIC_WRITE (LAPIC_LVTPC, 0x10000);
0080 MP_LAPIC_WRITE (LAPIC_LVT0, 0x08700);
0081 MP_LAPIC_WRITE (LAPIC_LVT1, 0x00400);
0082 MP_LAPIC_WRITE (LAPIC_LVTE, 0x10000);
0083 MP_LAPIC_WRITE (LAPIC_SPIV, 0x0010F);
0084
0085
0086 MP_LAPIC_WRITE (LAPIC_LVT1, 0x00400);
0087 MP_LAPIC_WRITE (LAPIC_LVTE, 0x10000);
0088 }
0089
0090 void
0091 LAPIC_set_task_priority(uint8 prio)
0092 {
0093 MP_LAPIC_WRITE (LAPIC_TPR, prio);
0094 }
0095
0096 uint32
0097 LAPIC_clear_error(void)
0098 {
0099 MP_LAPIC_WRITE (LAPIC_ESR, 0);
0100 return MP_LAPIC_READ (LAPIC_ESR);
0101 }
0102
0103 uint8
0104 LAPIC_get_physical_ID (void)
0105 {
0106 if (mp_ISA_PC)
0107 return 0;
0108 else
0109 return (MP_LAPIC_READ (LAPIC_ID) >> 0x18) & 0xF;
0110 }
0111
0112 void
0113 send_eoi (void)
0114 {
0115 if (mp_apic_mode) {
0116 MP_LAPIC_WRITE (LAPIC_EOI, 0);
0117 } else {
0118 outb (0x20, 0x20);
0119 }
0120 }
0121
0122 void
0123 LAPIC_start_timer (uint32 count)
0124 {
0125 MP_LAPIC_WRITE (LAPIC_TICR, count);
0126 }
0127
0128 void
0129 LAPIC_set_logical_destination(uint32 log_dest) {
0130 MP_LAPIC_WRITE (LAPIC_LDR, log_dest);
0131 MP_LAPIC_WRITE (LAPIC_DFR, -1);
0132 }
0133
0134 void
0135 LAPIC_enable_timer(uint8 vec, bool periodic, uint8 divisor)
0136 {
0137 uint8 div_flag = 0xB;
0138
0139 switch(divisor) {
0140 case 1: div_flag = 0xB; break;
0141 case 2: div_flag = 0x0; break;
0142 case 4: div_flag = 0x1; break;
0143 case 8: div_flag = 0x2; break;
0144 case 16: div_flag = 0x3; break;
0145 case 32: div_flag = 0x8; break;
0146 case 64: div_flag = 0x9; break;
0147 case 128: div_flag = 0xA; break;
0148 default: break;
0149 }
0150
0151 if (periodic)
0152 MP_LAPIC_WRITE (LAPIC_LVTT, (1<<17) | (uint32)vec);
0153 else
0154 MP_LAPIC_WRITE (LAPIC_LVTT, (uint32)vec);
0155 MP_LAPIC_WRITE (LAPIC_TDCR, div_flag);
0156 }
0157
0158 void
0159 LAPIC_disable_timer(void)
0160 {
0161 MP_LAPIC_WRITE (LAPIC_LVTT, (1<<16));
0162 }
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 extern volatile uint32 tick;
0182 static void
0183 smp_setup_LAPIC_timer_int (void)
0184 {
0185
0186 tick++;
0187
0188 outb (0x20, 0x20);
0189
0190
0191
0192
0193
0194
0195 asm volatile ("leave");
0196 asm volatile ("iret");
0197 }
0198
0199 static void
0200 smp_LAPIC_timer_irq_handler (void)
0201 {
0202
0203
0204 MP_LAPIC_WRITE (LAPIC_EOI, 0);
0205 asm volatile ("leave");
0206 asm volatile ("iret");
0207 }
0208
0209
0210 uint32 cpu_bus_freq = 0;
0211 uint64 tsc_freq = 0;
0212
0213
0214
0215 void
0216 LAPIC_measure_timer (void)
0217 {
0218 idt_descriptor old_timer, old_3f;
0219 uint32 value, start, count;
0220 uint32 tsc_start_hi, tsc_start_lo, tsc_value_hi, tsc_value_lo;
0221
0222
0223
0224
0225 disable_idt ();
0226
0227
0228 get_idt_descriptor (0x20, &old_timer);
0229 get_idt_descriptor (0x3f, &old_3f);
0230
0231 set_idt_descriptor_by_addr (0x20, (void *) &smp_setup_LAPIC_timer_int, 0x3);
0232 set_idt_descriptor_by_addr (0x3f, (void *) &smp_LAPIC_timer_irq_handler,
0233 0x3);
0234
0235 MP_LAPIC_WRITE (LAPIC_LVTT, 0x3f);
0236 MP_LAPIC_WRITE (LAPIC_TDCR, 0x0B);
0237
0238
0239 value = tick;
0240 asm volatile ("sti");
0241
0242 while (tick == value)
0243 asm volatile ("pause");
0244 start = tick;
0245 MP_LAPIC_WRITE (LAPIC_TICR, 0xFFFFFFFF);
0246 asm volatile ("rdtsc":"=a" (tsc_start_lo), "=d" (tsc_start_hi));
0247
0248 while (tick == start)
0249 asm volatile ("pause");
0250 asm volatile ("cli");
0251 asm volatile ("rdtsc":"=a" (tsc_value_lo), "=d" (tsc_value_hi));
0252 MP_LAPIC_WRITE (LAPIC_LVTT, 0x10000);
0253 count = MP_LAPIC_READ (LAPIC_TCCR);
0254
0255
0256 set_idt_descriptor (0x20, &old_timer);
0257 set_idt_descriptor (0x3f, &old_3f);
0258
0259 cpu_bus_freq = (0xFFFFFFFF - count) * HZ;
0260 com1_printf ("CPU bus frequency = 0x%X\n", cpu_bus_freq);
0261 tsc_freq = (((uint64) tsc_value_hi) << 32) | ((uint64) tsc_value_lo);
0262 tsc_freq -= ((uint64) tsc_start_hi) << 32;
0263 tsc_freq -= (uint64) tsc_start_lo;
0264 tsc_freq *= HZ;
0265 com1_printf ("TSC frequency = 0x%X 0x%X\n", (uint32) (tsc_freq >> 32),
0266 (uint32) tsc_freq);
0267
0268
0269 enable_idt ();
0270 }
0271
0272
0273
0274
0275
0276
0277 void
0278 IOAPIC_init (void)
0279 {
0280 int i, j;
0281
0282 outb (0xFF, 0x21);
0283 outb (0xFF, 0xA1);
0284
0285
0286
0287
0288 for (i = 0; i < mp_num_IOAPICs; i++) {
0289 for (j = 0; j < mp_IOAPICs[i].numGSIs; j++) {
0290 IOAPIC_write64 (IOAPIC_REDIR + (j * 2), 0x0000000000010000LL);
0291 }
0292 }
0293
0294
0295 IOAPIC_map_GSI (IRQ_to_GSI (mp_ISA_bus_id, 0), 0x20, 0xFF00000000000800LL);
0296
0297 #ifndef NO_IMCR_REDIRECT
0298 outb (0x70, 0x22);
0299 outb (0x01, 0x23);
0300 #endif
0301
0302 }
0303
0304 uint64
0305 IOAPIC_read64 (uint8 reg)
0306 {
0307 uint32 high, low;
0308 uint64 retval;
0309 MP_IOAPIC_WRITE (IOAPIC_REGSEL, reg + 1);
0310 high = MP_IOAPIC_READ (IOAPIC_RW);
0311 MP_IOAPIC_WRITE (IOAPIC_REGSEL, reg);
0312 low = MP_IOAPIC_READ (IOAPIC_RW);
0313 retval = (uint64) high << 32;
0314 retval |= (uint64) low;
0315 return retval;
0316 }
0317
0318 void
0319 IOAPIC_write64 (uint8 reg, uint64 v)
0320 {
0321
0322 MP_IOAPIC_WRITE (IOAPIC_REGSEL, reg);
0323 MP_IOAPIC_WRITE (IOAPIC_RW, 0x10000);
0324
0325 MP_IOAPIC_WRITE (IOAPIC_REGSEL, reg + 1);
0326 MP_IOAPIC_WRITE (IOAPIC_RW, (uint32) (v >> 32));
0327
0328 MP_IOAPIC_WRITE (IOAPIC_REGSEL, reg);
0329 MP_IOAPIC_WRITE (IOAPIC_RW, (uint32) (v & 0xFFFFFFFF));
0330 }
0331
0332 uint32
0333 IOAPIC_num_entries(void)
0334 {
0335 MP_IOAPIC_WRITE (IOAPIC_REGSEL, 0x1);
0336 return APIC_MAXREDIR (MP_IOAPIC_READ (IOAPIC_RW)) + 1;
0337 }
0338
0339 mp_IOAPIC_info *
0340 IOAPIC_lookup (uint8 id)
0341 {
0342 int i;
0343 for (i = 0; i < mp_num_IOAPICs; i++) {
0344 if (mp_IOAPICs[i].id == id)
0345 return &mp_IOAPICs[i];
0346 }
0347 panic ("IOAPIC_lookup failed.");
0348 }
0349
0350 int
0351 IOAPIC_map_GSI (uint32 GSI, uint8 vector, uint64 flags)
0352 {
0353 int i;
0354 uint32 old_addr = 0;
0355
0356 if (mp_ISA_PC)
0357 return -1;
0358
0359
0360 for (i = 0; i < mp_num_IOAPICs; i++) {
0361 if (mp_IOAPICs[i].startGSI <= GSI &&
0362 GSI < mp_IOAPICs[i].startGSI + mp_IOAPICs[i].numGSIs) {
0363 old_addr = mp_IOAPIC_addr;
0364
0365 mp_IOAPIC_addr = mp_IOAPICs[i].address;
0366
0367 GSI -= mp_IOAPICs[i].startGSI;
0368 break;
0369 }
0370 }
0371 if (!old_addr)
0372 return -1;
0373
0374 IOAPIC_write64 (IOAPIC_REDIR + (GSI * 2), flags | vector);
0375
0376
0377 mp_IOAPIC_addr = old_addr;
0378 return GSI;
0379 }
0380
0381 int
0382 IOAPIC_get_GSI_mapping (uint32 GSI, uint8 *vector, uint64 *flags)
0383 {
0384 int i;
0385 uint32 old_addr = 0;
0386
0387 if (mp_ISA_PC)
0388 return -1;
0389
0390
0391 for (i = 0; i < mp_num_IOAPICs; i++) {
0392 if (mp_IOAPICs[i].startGSI <= GSI &&
0393 GSI < mp_IOAPICs[i].startGSI + mp_IOAPICs[i].numGSIs) {
0394 old_addr = mp_IOAPIC_addr;
0395
0396 mp_IOAPIC_addr = mp_IOAPICs[i].address;
0397
0398 GSI -= mp_IOAPICs[i].startGSI;
0399 break;
0400 }
0401 }
0402 if (!old_addr)
0403 return -1;
0404
0405 u64 entry = IOAPIC_read64 (IOAPIC_REDIR + (GSI * 2));
0406
0407 if (flags)
0408 *flags = entry & (~0xFFULL);
0409 if (vector)
0410 *vector = (u8) (entry & (0xFFULL));
0411
0412
0413 mp_IOAPIC_addr = old_addr;
0414 return GSI;
0415 }
0416
0417 void
0418 IOAPIC_dump_entries (void)
0419 {
0420 int i, j;
0421 u32 old_addr = mp_IOAPIC_addr;
0422 for (i=0;i<mp_num_IOAPICs;i++) {
0423 mp_IOAPIC_addr = mp_IOAPICs[i].address;
0424 for (j=0; j<mp_IOAPICs[i].numGSIs; j++) {
0425 logger_printf ("IOAPIC[%d][%d]=0x%llX\n",
0426 i, j, IOAPIC_read64 (IOAPIC_REDIR + (j * 2)));
0427 }
0428 }
0429 mp_IOAPIC_addr = old_addr;
0430 }
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441