source: mainline/arch/ia32/src/smp/mp.c@ c9b8c5c

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c9b8c5c was c9b8c5c, checked in by Jakub Jermar <jakub@…>, 20 years ago

APIC changes and fixes.
Be more robust during MP configuration.

Do not use APIC ID as CPU_ID_ARCH anymore.
Changing APIC ID's is not a good idea.
Use dr0 register instead.

  • Property mode set to 100644
File size: 13.1 KB
Line 
1/*
2 * Copyright (C) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifdef __SMP__
30
31#include <arch/pm.h>
32#include <config.h>
33#include <print.h>
34#include <panic.h>
35#include <arch/smp/mp.h>
36#include <arch/smp/ap.h>
37#include <arch/smp/apic.h>
38#include <func.h>
39#include <arch/types.h>
40#include <typedefs.h>
41#include <synch/waitq.h>
42#include <time/delay.h>
43#include <mm/heap.h>
44#include <mm/page.h>
45#include <mm/frame.h>
46#include <cpu.h>
47#include <arch/i8259.h>
48#include <arch/asm.h>
49
50/*
51 * Multi-Processor Specification detection code.
52 */
53
54#define FS_SIGNATURE 0x5f504d5f
55#define CT_SIGNATURE 0x504d4350
56
57int mp_fs_check(__u8 *base);
58int mp_ct_check(void);
59
60int configure_via_ct(void);
61int configure_via_default(__u8 n);
62
63int ct_processor_entry(struct __processor_entry *pr);
64void ct_bus_entry(struct __bus_entry *bus);
65void ct_io_apic_entry(struct __io_apic_entry *ioa);
66void ct_io_intr_entry(struct __io_intr_entry *iointr);
67void ct_l_intr_entry(struct __l_intr_entry *lintr);
68
69void ct_extended_entries(void);
70
71static struct __mpfs *fs;
72static struct __mpct *ct;
73
74struct __processor_entry *processor_entries = NULL;
75struct __bus_entry *bus_entries = NULL;
76struct __io_apic_entry *io_apic_entries = NULL;
77struct __io_intr_entry *io_intr_entries = NULL;
78struct __l_intr_entry *l_intr_entries = NULL;
79
80int processor_entry_cnt = 0;
81int bus_entry_cnt = 0;
82int io_apic_entry_cnt = 0;
83int io_intr_entry_cnt = 0;
84int l_intr_entry_cnt = 0;
85
86waitq_t ap_completion_wq;
87waitq_t kmp_completion_wq;
88
89/*
90 * Used to check the integrity of the MP Floating Structure.
91 */
92int mp_fs_check(__u8 *base)
93{
94 int i;
95 __u8 sum;
96
97 for (i = 0, sum = 0; i < 16; i++)
98 sum += base[i];
99
100 return !sum;
101}
102
103/*
104 * Used to check the integrity of the MP Configuration Table.
105 */
106int mp_ct_check(void)
107{
108 __u8 *base = (__u8 *) ct;
109 __u8 *ext = base + ct->base_table_length;
110 __u8 sum;
111 int i;
112
113 /* count the checksum for the base table */
114 for (i=0,sum=0; i < ct->base_table_length; i++)
115 sum += base[i];
116
117 if (sum)
118 return 0;
119
120 /* count the checksum for the extended table */
121 for (i=0,sum=0; i < ct->ext_table_length; i++)
122 sum += ext[i];
123
124 return sum == ct->ext_table_checksum;
125}
126
127void mp_init(void)
128{
129 __address addr, frame;
130 int cnt, n;
131
132
133 /*
134 * First place to search the MP Floating Pointer Structure is the Extended
135 * BIOS Data Area. We have to read EBDA segment address from the BIOS Data
136 * Area. Unfortunatelly, this memory is in page 0, which has intentionally no
137 * mapping.
138 */
139 frame = frame_alloc(FRAME_KA);
140 map_page_to_frame(frame,0,PAGE_CACHEABLE,0);
141 addr = *((__u16 *) (frame + 0x40e)) * 16;
142 map_page_to_frame(frame,frame,PAGE_CACHEABLE,0);
143 frame_free(frame);
144
145 /*
146 * EBDA can be undefined. In that case addr would be 0.
147 */
148 if (addr >= 0x1000) {
149 cnt = 1024;
150 while (addr = __u32_search(addr,cnt,FS_SIGNATURE)) {
151 if (mp_fs_check((__u8 *) addr))
152 goto fs_found;
153 addr++;
154 cnt--;
155 }
156 }
157
158 /*
159 * Second place where the MP Floating Pointer Structure may live is the last
160 * kilobyte of base memory.
161 */
162 addr = 639*1024;
163 cnt = 1024;
164 while (addr = __u32_search(addr,cnt,FS_SIGNATURE)) {
165 if (mp_fs_check((__u8 *) addr))
166 goto fs_found;
167 addr++;
168 cnt--;
169 }
170
171 /*
172 * As the last resort, MP Floating Pointer Structure is searched in the BIOS
173 * ROM.
174 */
175 addr = 0xf0000;
176 cnt = 64*1024;
177 while (addr = __u32_search(addr,cnt,FS_SIGNATURE)) {
178 if (mp_fs_check((__u8 *) addr))
179 goto fs_found;
180 addr++;
181 cnt--;
182 }
183
184 return;
185
186fs_found:
187 printf("%L: MP Floating Pointer Structure\n", addr);
188
189 fs = (struct __mpfs *) addr;
190 frame_not_free((__address) fs);
191
192 if (fs->config_type == 0 && fs->configuration_table) {
193 if (fs->mpfib2 >> 7) {
194 printf("mp_init: PIC mode not supported\n");
195 return;
196 }
197
198 ct = fs->configuration_table;
199 frame_not_free((__address) ct);
200 config.cpu_count = configure_via_ct();
201 }
202 else
203 config.cpu_count = configure_via_default(fs->config_type);
204
205 if (config.cpu_count > 1) {
206 map_page_to_frame((__address) l_apic, (__address) l_apic, PAGE_NOT_CACHEABLE, 0);
207 }
208
209
210 /*
211 * Must be initialized outside the kmp thread, since it is waited
212 * on before the kmp thread is created.
213 */
214 waitq_initialize(&kmp_completion_wq);
215 return;
216}
217
218int configure_via_ct(void)
219{
220 __u8 *cur;
221 int i, cnt;
222
223 if (ct->signature != CT_SIGNATURE) {
224 printf("configure_via_ct: bad ct->signature\n");
225 return 1;
226 }
227 if (!mp_ct_check()) {
228 printf("configure_via_ct: bad ct checksum\n");
229 return 1;
230 }
231 if (ct->oem_table) {
232 printf("configure_via_ct: ct->oem_table not supported\n");
233 return 1;
234 }
235
236 l_apic = ct->l_apic;
237
238 cnt = 0;
239 cur = &ct->base_table[0];
240 for (i=0; i < ct->entry_count; i++) {
241 switch (*cur) {
242 /* Processor entry */
243 case 0:
244 processor_entries = processor_entries ? processor_entries : (struct __processor_entry *) cur;
245 processor_entry_cnt++;
246 cnt += ct_processor_entry((struct __processor_entry *) cur);
247 cur += 20;
248 break;
249
250 /* Bus entry */
251 case 1:
252 bus_entries = bus_entries ? bus_entries : (struct __bus_entry *) cur;
253 bus_entry_cnt++;
254 ct_bus_entry((struct __bus_entry *) cur);
255 cur += 8;
256 break;
257
258 /* I/O Apic */
259 case 2:
260 io_apic_entries = io_apic_entries ? io_apic_entries : (struct __io_apic_entry *) cur;
261 io_apic_entry_cnt++;
262 ct_io_apic_entry((struct __io_apic_entry *) cur);
263 cur += 8;
264 break;
265
266 /* I/O Interrupt Assignment */
267 case 3:
268 io_intr_entries = io_intr_entries ? io_intr_entries : (struct __io_intr_entry *) cur;
269 io_intr_entry_cnt++;
270 ct_io_intr_entry((struct __io_intr_entry *) cur);
271 cur += 8;
272 break;
273
274 /* Local Interrupt Assignment */
275 case 4:
276 l_intr_entries = l_intr_entries ? l_intr_entries : (struct __l_intr_entry *) cur;
277 l_intr_entry_cnt++;
278 ct_l_intr_entry((struct __l_intr_entry *) cur);
279 cur += 8;
280 break;
281
282 default:
283 /*
284 * Something is wrong. Fallback to UP mode.
285 */
286
287 printf("configure_via_ct: ct badness\n");
288 return 1;
289 }
290 }
291
292 /*
293 * Process extended entries.
294 */
295 ct_extended_entries();
296 return cnt;
297}
298
299int configure_via_default(__u8 n)
300{
301 /*
302 * Not yet implemented.
303 */
304 printf("configure_via_default: not supported\n");
305 return 1;
306}
307
308
309int ct_processor_entry(struct __processor_entry *pr)
310{
311 /*
312 * Ignore processors which are not marked enabled.
313 */
314 if ((pr->cpu_flags & (1<<0)) == 0)
315 return 0;
316
317 apic_id_mask |= (1<<pr->l_apic_id);
318 return 1;
319}
320
321void ct_bus_entry(struct __bus_entry *bus)
322{
323#ifdef MPCT_VERBOSE
324 char buf[7];
325 memcopy((__address) bus->bus_type, (__address) buf,6);
326 buf[6] = 0;
327 printf("bus%d: %s\n", bus->bus_id, buf);
328#endif
329}
330
331void ct_io_apic_entry(struct __io_apic_entry *ioa)
332{
333 static int io_apic_count = 0;
334
335 /* this ioapic is marked unusable */
336 if (ioa->io_apic_flags & 1 == 0)
337 return;
338
339 if (io_apic_count++ > 0) {
340 /*
341 * Multiple IO APIC's are currently not supported.
342 */
343 return;
344 }
345
346 map_page_to_frame((__address) ioa->io_apic, (__address) ioa->io_apic, PAGE_NOT_CACHEABLE, 0);
347
348 io_apic = ioa->io_apic;
349}
350
351//#define MPCT_VERBOSE
352void ct_io_intr_entry(struct __io_intr_entry *iointr)
353{
354#ifdef MPCT_VERBOSE
355 switch (iointr->intr_type) {
356 case 0: printf("INT"); break;
357 case 1: printf("NMI"); break;
358 case 2: printf("SMI"); break;
359 case 3: printf("ExtINT"); break;
360 }
361 putchar(',');
362 switch (iointr->poel&3) {
363 case 0: printf("bus-like"); break;
364 case 1: printf("active high"); break;
365 case 2: printf("reserved"); break;
366 case 3: printf("active low"); break;
367 }
368 putchar(',');
369 switch ((iointr->poel>>2)&3) {
370 case 0: printf("bus-like"); break;
371 case 1: printf("edge-triggered"); break;
372 case 2: printf("reserved"); break;
373 case 3: printf("level-triggered"); break;
374 }
375 putchar(',');
376 printf("bus%d,irq%d", iointr->src_bus_id, iointr->src_bus_irq);
377 putchar(',');
378 printf("io_apic%d,pin%d", iointr->dst_io_apic_id, iointr->dst_io_apic_pin);
379 putchar('\n');
380#endif
381}
382
383void ct_l_intr_entry(struct __l_intr_entry *lintr)
384{
385#ifdef MPCT_VERBOSE
386 switch (lintr->intr_type) {
387 case 0: printf("INT"); break;
388 case 1: printf("NMI"); break;
389 case 2: printf("SMI"); break;
390 case 3: printf("ExtINT"); break;
391 }
392 putchar(',');
393 switch (lintr->poel&3) {
394 case 0: printf("bus-like"); break;
395 case 1: printf("active high"); break;
396 case 2: printf("reserved"); break;
397 case 3: printf("active low"); break;
398 }
399 putchar(',');
400 switch ((lintr->poel>>2)&3) {
401 case 0: printf("bus-like"); break;
402 case 1: printf("edge-triggered"); break;
403 case 2: printf("reserved"); break;
404 case 3: printf("level-triggered"); break;
405 }
406 putchar(',');
407 printf("bus%d,irq%d", lintr->src_bus_id, lintr->src_bus_irq);
408 putchar(',');
409 printf("l_apic%d,pin%d", lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
410 putchar('\n');
411#endif
412}
413
414void ct_extended_entries(void)
415{
416 __u8 *ext = (__u8 *) ct + ct->base_table_length;
417 __u8 *cur;
418
419 for (cur = ext; cur < ext + ct->ext_table_length; cur += cur[CT_EXT_ENTRY_LEN]) {
420 switch (cur[CT_EXT_ENTRY_TYPE]) {
421 default:
422 printf("%X: skipping MP Configuration Table extended entry type %d\n", cur, cur[CT_EXT_ENTRY_TYPE]);
423 break;
424 }
425 }
426}
427
428/*
429 * Kernel thread for bringing up application processors. It becomes clear
430 * that we need an arrangement like this (AP's being initialized by a kernel
431 * thread), for a thread has its dedicated stack. (The stack used during the
432 * BSP initialization (prior the very first call to scheduler()) will be used
433 * as an initialization stack for each AP.)
434 */
435void kmp(void *arg)
436{
437 struct __processor_entry *pr;
438 __address src, dst;
439 __address frame;
440 int i;
441
442 waitq_initialize(&ap_completion_wq);
443
444 /*
445 * Processor entries immediately follow the configuration table header.
446 */
447 pr = processor_entries;
448
449 /*
450 * Grab a frame and map its address to page 0. This is a hack which
451 * accesses data in frame 0. Note that page 0 is not present because
452 * of nil reference bug catching.
453 */
454 frame = frame_alloc(FRAME_KA);
455 map_page_to_frame(frame,0,PAGE_CACHEABLE,0);
456
457 /*
458 * Set the warm-reset vector to the real-mode address of 4K-aligned ap_boot()
459 */
460 *((__u16 *) (frame + 0x467+0)) = ((__address) ap_boot) >> 4; /* segment */
461 *((__u16 *) (frame + 0x467+2)) = 0x0; /* offset */
462
463 /*
464 * Give back the borrowed frame and restore identity mapping for it.
465 */
466 map_page_to_frame(frame,frame,PAGE_CACHEABLE,0);
467 frame_free(frame);
468
469 /*
470 * Save 0xa to address 0xf of the CMOS RAM.
471 * BIOS will not do the POST after the INIT signal.
472 */
473 outb(0x70,0xf);
474 outb(0x71,0xa);
475
476 cpu_priority_high();
477
478 pic_disable_irqs(0xffff);
479 apic_init();
480
481 for (i = 0; i < processor_entry_cnt; i++) {
482 struct descriptor *gdt_new;
483
484 /*
485 * Skip processors marked unusable.
486 */
487 if (pr[i].cpu_flags & (1<<0) == 0)
488 continue;
489
490 /*
491 * The bootstrap processor is already up.
492 */
493 if (pr[i].cpu_flags & (1<<1))
494 continue;
495
496 if (pr[i].l_apic_id == l_apic_id()) {
497 printf("%X: bad processor entry #%d, will not send IPI to myself\n", &pr[i], i);
498 continue;
499 }
500
501 /*
502 * Prepare new GDT for CPU in question.
503 */
504 if (!(gdt_new = (struct descriptor *) malloc(GDT_ITEMS*sizeof(struct descriptor))))
505 panic(PANIC "couldn't allocate memory for GDT\n");
506
507 memcopy(gdt, gdt_new, GDT_ITEMS*sizeof(struct descriptor));
508 gdtr.base = (__address) gdt_new;
509
510 if (l_apic_send_init_ipi(pr[i].l_apic_id)) {
511 /*
512 * There may be just one AP being initialized at
513 * the time. After it comes completely up, it is
514 * supposed to wake us up.
515 */
516 waitq_sleep(&ap_completion_wq);
517 cpu_priority_high();
518 }
519 else {
520 printf("INIT IPI for l_apic%d failed\n", pr[i].l_apic_id);
521 }
522 }
523
524 /*
525 * Wakeup the kinit thread so that
526 * system initialization can go on.
527 */
528 waitq_wakeup(&kmp_completion_wq, WAKEUP_FIRST);
529}
530
531int mp_irq_to_pin(int irq)
532{
533 int i;
534
535 for(i=0;i<io_intr_entry_cnt;i++) {
536 if (io_intr_entries[i].src_bus_irq == irq && io_intr_entries[i].intr_type == 0)
537 return io_intr_entries[i].dst_io_apic_pin;
538 }
539
540 return -1;
541}
542
543#endif /* __SMP__ */
Note: See TracBrowser for help on using the repository browser.