source: mainline/arch/ia32/src/smp/mps.c@ 87cd61f

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

Add map_structure() to automate mapping of memory structures that can span multiple pages and/or cross page boundaries.
Change ACPI map_sdt() to use map_structure().

Small changes in MPS code.
The extra frame allocation for accessing frame 0 is unnecessary as it is possible to access frame 0 from kernel address space.
Zero TSS descriptor in the newly prepared GDT.

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2 * Copyright (C) 2001-2005 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/mps.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#include <arch/bios/bios.h>
50#include <arch/acpi/madt.h>
51
52/*
53 * MultiProcessor Specification detection code.
54 */
55
56#define FS_SIGNATURE 0x5f504d5f
57#define CT_SIGNATURE 0x504d4350
58
59int mps_fs_check(__u8 *base);
60int mps_ct_check(void);
61
62int configure_via_ct(void);
63int configure_via_default(__u8 n);
64
65int ct_processor_entry(struct __processor_entry *pr);
66void ct_bus_entry(struct __bus_entry *bus);
67void ct_io_apic_entry(struct __io_apic_entry *ioa);
68void ct_io_intr_entry(struct __io_intr_entry *iointr);
69void ct_l_intr_entry(struct __l_intr_entry *lintr);
70
71void ct_extended_entries(void);
72
73static struct mps_fs *fs;
74static struct mps_ct *ct;
75
76struct __processor_entry *processor_entries = NULL;
77struct __bus_entry *bus_entries = NULL;
78struct __io_apic_entry *io_apic_entries = NULL;
79struct __io_intr_entry *io_intr_entries = NULL;
80struct __l_intr_entry *l_intr_entries = NULL;
81
82int processor_entry_cnt = 0;
83int bus_entry_cnt = 0;
84int io_apic_entry_cnt = 0;
85int io_intr_entry_cnt = 0;
86int l_intr_entry_cnt = 0;
87
88waitq_t ap_completion_wq;
89waitq_t kmp_completion_wq;
90
91/*
92 * Used to check the integrity of the MP Floating Structure.
93 */
94int mps_fs_check(__u8 *base)
95{
96 int i;
97 __u8 sum;
98
99 for (i = 0, sum = 0; i < 16; i++)
100 sum += base[i];
101
102 return !sum;
103}
104
105/*
106 * Used to check the integrity of the MP Configuration Table.
107 */
108int mps_ct_check(void)
109{
110 __u8 *base = (__u8 *) ct;
111 __u8 *ext = base + ct->base_table_length;
112 __u8 sum;
113 int i;
114
115 /* count the checksum for the base table */
116 for (i=0,sum=0; i < ct->base_table_length; i++)
117 sum += base[i];
118
119 if (sum)
120 return 0;
121
122 /* count the checksum for the extended table */
123 for (i=0,sum=0; i < ct->ext_table_length; i++)
124 sum += ext[i];
125
126 return sum == ct->ext_table_checksum;
127}
128
129void mps_init(void)
130{
131 __u8 *addr[2] = { NULL, (__u8 *) 0xf0000 };
132 int i, j, length[2] = { 1024, 64*1024 };
133
134
135 /*
136 * Find MP Floating Pointer Structure
137 * 1a. search first 1K of EBDA
138 * 1b. if EBDA is undefined, search last 1K of base memory
139 * 2. search 64K starting at 0xf0000
140 */
141
142 addr[0] = (__u8 *) (ebda ? ebda : 639 * 1024);
143 for (i = 0; i < 2; i++) {
144 for (j = 0; j < length[i]; j += 16) {
145 if (*((__u32 *) &addr[i][j]) == FS_SIGNATURE && mps_fs_check(&addr[i][j])) {
146 fs = (struct mps_fs *) &addr[i][j];
147 goto fs_found;
148 }
149 }
150 }
151
152 return;
153
154fs_found:
155 printf("%L: MPS Floating Pointer Structure\n", fs);
156
157 frame_not_free((__address) fs);
158
159 if (fs->config_type == 0 && fs->configuration_table) {
160 if (fs->mpfib2 >> 7) {
161 printf("%s: PIC mode not supported\n", __FUNCTION__);
162 return;
163 }
164
165 ct = fs->configuration_table;
166 frame_not_free((__address) ct);
167 config.cpu_count = configure_via_ct();
168 }
169 else
170 config.cpu_count = configure_via_default(fs->config_type);
171
172 if (config.cpu_count > 1) {
173 map_page_to_frame((__address) l_apic, (__address) l_apic, PAGE_NOT_CACHEABLE, 0);
174 }
175
176
177 /*
178 * Must be initialized outside the kmp thread, since it is waited
179 * on before the kmp thread is created.
180 */
181 waitq_initialize(&kmp_completion_wq);
182 return;
183}
184
185int configure_via_ct(void)
186{
187 __u8 *cur;
188 int i, cnt;
189
190 if (ct->signature != CT_SIGNATURE) {
191 printf("%s: bad ct->signature\n", __FUNCTION__);
192 return 1;
193 }
194 if (!mps_ct_check()) {
195 printf("%s: bad ct checksum\n", __FUNCTION__);
196 return 1;
197 }
198 if (ct->oem_table) {
199 printf("%s: ct->oem_table not supported\n", __FUNCTION__);
200 return 1;
201 }
202
203 l_apic = ct->l_apic;
204
205 cnt = 0;
206 cur = &ct->base_table[0];
207 for (i=0; i < ct->entry_count; i++) {
208 switch (*cur) {
209 /* Processor entry */
210 case 0:
211 processor_entries = processor_entries ? processor_entries : (struct __processor_entry *) cur;
212 processor_entry_cnt++;
213 cnt += ct_processor_entry((struct __processor_entry *) cur);
214 cur += 20;
215 break;
216
217 /* Bus entry */
218 case 1:
219 bus_entries = bus_entries ? bus_entries : (struct __bus_entry *) cur;
220 bus_entry_cnt++;
221 ct_bus_entry((struct __bus_entry *) cur);
222 cur += 8;
223 break;
224
225 /* I/O Apic */
226 case 2:
227 io_apic_entries = io_apic_entries ? io_apic_entries : (struct __io_apic_entry *) cur;
228 io_apic_entry_cnt++;
229 ct_io_apic_entry((struct __io_apic_entry *) cur);
230 cur += 8;
231 break;
232
233 /* I/O Interrupt Assignment */
234 case 3:
235 io_intr_entries = io_intr_entries ? io_intr_entries : (struct __io_intr_entry *) cur;
236 io_intr_entry_cnt++;
237 ct_io_intr_entry((struct __io_intr_entry *) cur);
238 cur += 8;
239 break;
240
241 /* Local Interrupt Assignment */
242 case 4:
243 l_intr_entries = l_intr_entries ? l_intr_entries : (struct __l_intr_entry *) cur;
244 l_intr_entry_cnt++;
245 ct_l_intr_entry((struct __l_intr_entry *) cur);
246 cur += 8;
247 break;
248
249 default:
250 /*
251 * Something is wrong. Fallback to UP mode.
252 */
253
254 printf("%s: ct badness\n", __FUNCTION__);
255 return 1;
256 }
257 }
258
259 /*
260 * Process extended entries.
261 */
262 ct_extended_entries();
263 return cnt;
264}
265
266int configure_via_default(__u8 n)
267{
268 /*
269 * Not yet implemented.
270 */
271 printf("%s: not supported\n", __FUNCTION__);
272 return 1;
273}
274
275
276int ct_processor_entry(struct __processor_entry *pr)
277{
278 /*
279 * Ignore processors which are not marked enabled.
280 */
281 if ((pr->cpu_flags & (1<<0)) == 0)
282 return 0;
283
284 apic_id_mask |= (1<<pr->l_apic_id);
285 return 1;
286}
287
288void ct_bus_entry(struct __bus_entry *bus)
289{
290#ifdef MPSCT_VERBOSE
291 char buf[7];
292 memcopy((__address) bus->bus_type, (__address) buf, 6);
293 buf[6] = 0;
294 printf("bus%d: %s\n", bus->bus_id, buf);
295#endif
296}
297
298void ct_io_apic_entry(struct __io_apic_entry *ioa)
299{
300 static int io_apic_count = 0;
301
302 /* this ioapic is marked unusable */
303 if (ioa->io_apic_flags & 1 == 0)
304 return;
305
306 if (io_apic_count++ > 0) {
307 /*
308 * Multiple IO APIC's are currently not supported.
309 */
310 return;
311 }
312
313 map_page_to_frame((__address) ioa->io_apic, (__address) ioa->io_apic, PAGE_NOT_CACHEABLE, 0);
314
315 io_apic = ioa->io_apic;
316}
317
318//#define MPSCT_VERBOSE
319void ct_io_intr_entry(struct __io_intr_entry *iointr)
320{
321#ifdef MPSCT_VERBOSE
322 switch (iointr->intr_type) {
323 case 0: printf("INT"); break;
324 case 1: printf("NMI"); break;
325 case 2: printf("SMI"); break;
326 case 3: printf("ExtINT"); break;
327 }
328 putchar(',');
329 switch (iointr->poel&3) {
330 case 0: printf("bus-like"); break;
331 case 1: printf("active high"); break;
332 case 2: printf("reserved"); break;
333 case 3: printf("active low"); break;
334 }
335 putchar(',');
336 switch ((iointr->poel>>2)&3) {
337 case 0: printf("bus-like"); break;
338 case 1: printf("edge-triggered"); break;
339 case 2: printf("reserved"); break;
340 case 3: printf("level-triggered"); break;
341 }
342 putchar(',');
343 printf("bus%d,irq%d", iointr->src_bus_id, iointr->src_bus_irq);
344 putchar(',');
345 printf("io_apic%d,pin%d", iointr->dst_io_apic_id, iointr->dst_io_apic_pin);
346 putchar('\n');
347#endif
348}
349
350void ct_l_intr_entry(struct __l_intr_entry *lintr)
351{
352#ifdef MPSCT_VERBOSE
353 switch (lintr->intr_type) {
354 case 0: printf("INT"); break;
355 case 1: printf("NMI"); break;
356 case 2: printf("SMI"); break;
357 case 3: printf("ExtINT"); break;
358 }
359 putchar(',');
360 switch (lintr->poel&3) {
361 case 0: printf("bus-like"); break;
362 case 1: printf("active high"); break;
363 case 2: printf("reserved"); break;
364 case 3: printf("active low"); break;
365 }
366 putchar(',');
367 switch ((lintr->poel>>2)&3) {
368 case 0: printf("bus-like"); break;
369 case 1: printf("edge-triggered"); break;
370 case 2: printf("reserved"); break;
371 case 3: printf("level-triggered"); break;
372 }
373 putchar(',');
374 printf("bus%d,irq%d", lintr->src_bus_id, lintr->src_bus_irq);
375 putchar(',');
376 printf("l_apic%d,pin%d", lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
377 putchar('\n');
378#endif
379}
380
381void ct_extended_entries(void)
382{
383 __u8 *ext = (__u8 *) ct + ct->base_table_length;
384 __u8 *cur;
385
386 for (cur = ext; cur < ext + ct->ext_table_length; cur += cur[CT_EXT_ENTRY_LEN]) {
387 switch (cur[CT_EXT_ENTRY_TYPE]) {
388 default:
389 printf("%L: skipping MP Configuration Table extended entry type %d\n", cur, cur[CT_EXT_ENTRY_TYPE]);
390 break;
391 }
392 }
393}
394
395
396/*
397 * Kernel thread for bringing up application processors. It becomes clear
398 * that we need an arrangement like this (AP's being initialized by a kernel
399 * thread), for a thread has its dedicated stack. (The stack used during the
400 * BSP initialization (prior the very first call to scheduler()) will be used
401 * as an initialization stack for each AP.)
402 */
403void kmp(void *arg)
404{
405 struct __processor_entry *pr;
406 __address src, dst;
407 int i;
408
409 waitq_initialize(&ap_completion_wq);
410
411 /*
412 * Processor entries immediately follow the configuration table header.
413 */
414 pr = processor_entries;
415
416 /*
417 * We need to access data in frame 0.
418 * We boldly make use of kernel address space mapping.
419 */
420
421 /*
422 * Set the warm-reset vector to the real-mode address of 4K-aligned ap_boot()
423 */
424 *((__u16 *) (PA2KA(0x467+0))) = ((__address) ap_boot) >> 4; /* segment */
425 *((__u16 *) (PA2KA(0x467+2))) = 0; /* offset */
426
427 /*
428 * Save 0xa to address 0xf of the CMOS RAM.
429 * BIOS will not do the POST after the INIT signal.
430 */
431 outb(0x70,0xf);
432 outb(0x71,0xa);
433
434 cpu_priority_high();
435
436 pic_disable_irqs(0xffff);
437 apic_init();
438
439 for (i = 0; i < processor_entry_cnt; i++) {
440 struct descriptor *gdt_new;
441
442 /*
443 * Skip processors marked unusable.
444 */
445 if (pr[i].cpu_flags & (1<<0) == 0)
446 continue;
447
448 /*
449 * The bootstrap processor is already up.
450 */
451 if (pr[i].cpu_flags & (1<<1))
452 continue;
453
454 if (pr[i].l_apic_id == l_apic_id()) {
455 printf("%L: bad processor entry #%d, will not send IPI to myself\n", &pr[i], i);
456 continue;
457 }
458
459 /*
460 * Prepare new GDT for CPU in question.
461 */
462 if (!(gdt_new = (struct descriptor *) malloc(GDT_ITEMS*sizeof(struct descriptor))))
463 panic("couldn't allocate memory for GDT\n");
464
465 memcopy(gdt, gdt_new, GDT_ITEMS*sizeof(struct descriptor));
466 memsetb(&gdt_new[TSS_DES], sizeof(struct descriptor), 0);
467 gdtr.base = KA2PA((__address) gdt_new);
468
469 if (l_apic_send_init_ipi(pr[i].l_apic_id)) {
470 /*
471 * There may be just one AP being initialized at
472 * the time. After it comes completely up, it is
473 * supposed to wake us up.
474 */
475 waitq_sleep(&ap_completion_wq);
476 cpu_priority_high();
477 }
478 else {
479 printf("INIT IPI for l_apic%d failed\n", pr[i].l_apic_id);
480 }
481 }
482
483 /*
484 * Wakeup the kinit thread so that
485 * system initialization can go on.
486 */
487 waitq_wakeup(&kmp_completion_wq, WAKEUP_FIRST);
488}
489
490int mps_irq_to_pin(int irq)
491{
492 int i;
493
494 for(i=0;i<io_intr_entry_cnt;i++) {
495 if (io_intr_entries[i].src_bus_irq == irq && io_intr_entries[i].intr_type == 0)
496 return io_intr_entries[i].dst_io_apic_pin;
497 }
498
499 return -1;
500}
501
502#endif /* __SMP__ */
Note: See TracBrowser for help on using the repository browser.