source: mainline/kernel/arch/ia32/src/smp/mps.c@ 4edd57fd

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4edd57fd was 4edd57fd, checked in by Martin Decky <martin@…>, 15 years ago

the limit in the APIC driver is on CPU ids, not APIC ids
(however, I believe that there is still some unfortunate change of even a deeper confusion somewhere ..)

  • Property mode set to 100644
File size: 10.1 KB
RevLine 
[f761f1eb]1/*
[4bb31f7]2 * Copyright (c) 2008 Jakub Jermar
[f761f1eb]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
[fe32163]29/** @addtogroup ia32
[b45c443]30 * @{
31 */
32/** @file
33 */
34
[5f85c91]35#ifdef CONFIG_SMP
[f761f1eb]36
37#include <config.h>
38#include <print.h>
[a26ddd1]39#include <debug.h>
[ed0dd65]40#include <arch/smp/mps.h>
[397c77f]41#include <arch/smp/apic.h>
[a26ddd1]42#include <arch/smp/smp.h>
[f761f1eb]43#include <func.h>
[d99c1d2]44#include <typedefs.h>
[f761f1eb]45#include <cpu.h>
46#include <arch/asm.h>
[dba84ff]47#include <arch/bios/bios.h>
[9c0a9b3]48#include <mm/frame.h>
[f761f1eb]49
50/*
[ed0dd65]51 * MultiProcessor Specification detection code.
[f761f1eb]52 */
53
[fe32163]54#define FS_SIGNATURE 0x5f504d5f
55#define CT_SIGNATURE 0x504d4350
[f761f1eb]56
[ed0dd65]57static struct mps_fs *fs;
58static struct mps_ct *ct;
[f761f1eb]59
[fe32163]60static struct __processor_entry *processor_entries = NULL;
61static struct __bus_entry *bus_entries = NULL;
62static struct __io_apic_entry *io_apic_entries = NULL;
63static struct __io_intr_entry *io_intr_entries = NULL;
64static struct __l_intr_entry *l_intr_entries = NULL;
[f761f1eb]65
[fe32163]66static size_t io_apic_cnt = 0;
[f761f1eb]67
[fe32163]68static size_t processor_entry_cnt = 0;
69static size_t bus_entry_cnt = 0;
70static size_t io_apic_entry_cnt = 0;
71static size_t io_intr_entry_cnt = 0;
72static size_t l_intr_entry_cnt = 0;
[a26ddd1]73
[fe32163]74static uint8_t get_cpu_apic_id(size_t i)
[a26ddd1]75{
[fe32163]76 ASSERT(i < processor_entry_cnt);
77
78 return processor_entries[i].l_apic_id;
[a26ddd1]79}
80
[fe32163]81static bool is_cpu_enabled(size_t i)
[a26ddd1]82{
83 ASSERT(i < processor_entry_cnt);
[fe32163]84
85 /*
86 * FIXME: The current local APIC driver limits usable
[4edd57fd]87 * CPU IDs to 8.
[fe32163]88 *
89 */
[4edd57fd]90 if (i > 7)
[fe32163]91 return false;
92
[7f043c0]93 return (bool) ((processor_entries[i].cpu_flags & 0x01) == 0x01);
[a26ddd1]94}
95
[fe32163]96static bool is_bsp(size_t i)
[a26ddd1]97{
98 ASSERT(i < processor_entry_cnt);
[fe32163]99
[7f043c0]100 return (bool) ((processor_entries[i].cpu_flags & 0x02) == 0x02);
[a26ddd1]101}
102
[fe32163]103static int mps_irq_to_pin(unsigned int irq)
[a26ddd1]104{
[fe32163]105 size_t i;
106
107 for (i = 0; i < io_intr_entry_cnt; i++) {
108 if (io_intr_entries[i].src_bus_irq == irq &&
109 io_intr_entries[i].intr_type == 0)
110 return io_intr_entries[i].dst_io_apic_pin;
111 }
112
113 return -1;
[a26ddd1]114}
115
[fe32163]116/** Implementation of IA-32 SMP configuration interface.
117 *
118 */
119struct smp_config_operations mps_config_operations = {
120 .cpu_enabled = is_cpu_enabled,
121 .cpu_bootstrap = is_bsp,
122 .cpu_apic_id = get_cpu_apic_id,
123 .irq_to_pin = mps_irq_to_pin
124};
[a26ddd1]125
[fe32163]126/** Check the integrity of the MP Floating Structure.
127 *
[f761f1eb]128 */
[fe32163]129static bool mps_fs_check(uint8_t *base)
[f761f1eb]130{
[3802fcd]131 unsigned int i;
[7f1c620]132 uint8_t sum;
[f761f1eb]133
134 for (i = 0, sum = 0; i < 16; i++)
[7f043c0]135 sum = (uint8_t) (sum + base[i]);
[f761f1eb]136
[fe32163]137 return (sum == 0);
[f761f1eb]138}
139
[fe32163]140/** Check the integrity of the MP Configuration Table.
141 *
[f761f1eb]142 */
[fe32163]143static bool mps_ct_check(void)
[f761f1eb]144{
[7f1c620]145 uint8_t *base = (uint8_t *) ct;
146 uint8_t *ext = base + ct->base_table_length;
147 uint8_t sum;
[fe32163]148 uint16_t i;
[f761f1eb]149
[fe32163]150 /* Compute the checksum for the base table */
151 for (i = 0, sum = 0; i < ct->base_table_length; i++)
[7f043c0]152 sum = (uint8_t) (sum + base[i]);
[fe32163]153
[f761f1eb]154 if (sum)
[fe32163]155 return false;
156
157 /* Compute the checksum for the extended table */
[4bb31f7]158 for (i = 0, sum = 0; i < ct->ext_table_length; i++)
[7f043c0]159 sum = (uint8_t) (sum + ext[i]);
[f761f1eb]160
[fe32163]161 return (sum == ct->ext_table_checksum);
[f761f1eb]162}
163
[fe32163]164static void ct_processor_entry(struct __processor_entry *pr)
[f761f1eb]165{
166 /*
167 * Ignore processors which are not marked enabled.
168 */
[4bb31f7]169 if ((pr->cpu_flags & (1 << 0)) == 0)
[fe32163]170 return;
[f761f1eb]171
[fe32163]172 apic_id_mask |= (1 << pr->l_apic_id);
[f761f1eb]173}
174
[fe32163]175static void ct_bus_entry(struct __bus_entry *bus __attribute__((unused)))
[f761f1eb]176{
[ed0dd65]177#ifdef MPSCT_VERBOSE
[f761f1eb]178 char buf[7];
[fe32163]179
[9756131]180 memcpy((void *) buf, (void *) bus->bus_type, 6);
[f761f1eb]181 buf[6] = 0;
[fe32163]182
183 printf("MPS: bus=%" PRIu8 " (%s)\n", bus->bus_id, buf);
[f761f1eb]184#endif
185}
186
[fe32163]187static void ct_io_apic_entry(struct __io_apic_entry *ioa)
[f761f1eb]188{
[fe32163]189 /* This I/O APIC is marked unusable */
[5a95b25]190 if ((ioa->io_apic_flags & 1) == 0)
[f761f1eb]191 return;
192
[fe32163]193 if (io_apic_cnt++ > 0) {
[f761f1eb]194 /*
[fe32163]195 * Multiple I/O APICs are currently not supported.
[f761f1eb]196 */
197 return;
198 }
199
[fe32163]200 io_apic = (uint32_t *) (uintptr_t) ioa->io_apic;
[f761f1eb]201}
202
[fe32163]203static void ct_io_intr_entry(struct __io_intr_entry *iointr
204 __attribute__((unused)))
[f761f1eb]205{
[ed0dd65]206#ifdef MPSCT_VERBOSE
[fe32163]207 printf("MPS: ");
208
[f761f1eb]209 switch (iointr->intr_type) {
[4bb31f7]210 case 0:
211 printf("INT");
212 break;
213 case 1:
214 printf("NMI");
215 break;
216 case 2:
217 printf("SMI");
218 break;
219 case 3:
220 printf("ExtINT");
221 break;
[f761f1eb]222 }
[fe32163]223
224 printf(", ");
225
[4bb31f7]226 switch (iointr->poel & 3) {
227 case 0:
228 printf("bus-like");
229 break;
230 case 1:
231 printf("active high");
232 break;
233 case 2:
234 printf("reserved");
235 break;
236 case 3:
237 printf("active low");
238 break;
[f761f1eb]239 }
[fe32163]240
241 printf(", ");
242
[4bb31f7]243 switch ((iointr->poel >> 2) & 3) {
244 case 0:
245 printf("bus-like");
246 break;
247 case 1:
248 printf("edge-triggered");
249 break;
250 case 2:
251 printf("reserved");
252 break;
253 case 3:
254 printf("level-triggered");
255 break;
[f761f1eb]256 }
[fe32163]257
258 printf(", bus=%" PRIu8 " irq=%" PRIu8 " io_apic=%" PRIu8" pin=%"
259 PRIu8 "\n", iointr->src_bus_id, iointr->src_bus_irq,
260 iointr->dst_io_apic_id, iointr->dst_io_apic_pin);
[f761f1eb]261#endif
262}
263
[fe32163]264static void ct_l_intr_entry(struct __l_intr_entry *lintr
265 __attribute__((unused)))
[f761f1eb]266{
[ed0dd65]267#ifdef MPSCT_VERBOSE
[fe32163]268 printf("MPS: ");
269
[f761f1eb]270 switch (lintr->intr_type) {
[4bb31f7]271 case 0:
[fe32163]272 printf("INT");
273 break;
[4bb31f7]274 case 1:
[fe32163]275 printf("NMI");
276 break;
[4bb31f7]277 case 2:
[fe32163]278 printf("SMI");
279 break;
[4bb31f7]280 case 3:
[fe32163]281 printf("ExtINT");
282 break;
[f761f1eb]283 }
[fe32163]284
285 printf(", ");
286
[4bb31f7]287 switch (lintr->poel & 3) {
288 case 0:
[fe32163]289 printf("bus-like");
290 break;
[4bb31f7]291 case 1:
[fe32163]292 printf("active high");
293 break;
[4bb31f7]294 case 2:
[fe32163]295 printf("reserved");
296 break;
[4bb31f7]297 case 3:
[fe32163]298 printf("active low");
299 break;
[f761f1eb]300 }
[fe32163]301
302 printf(", ");
303
[4bb31f7]304 switch ((lintr->poel >> 2) & 3) {
305 case 0:
[fe32163]306 printf("bus-like");
307 break;
[4bb31f7]308 case 1:
[fe32163]309 printf("edge-triggered");
310 break;
[4bb31f7]311 case 2:
[fe32163]312 printf("reserved");
313 break;
[4bb31f7]314 case 3:
[fe32163]315 printf("level-triggered");
316 break;
[f761f1eb]317 }
[fe32163]318
319 printf(", bus=%" PRIu8 " irq=%" PRIu8 " l_apic=%" PRIu8" pin=%"
320 PRIu8 "\n", lintr->src_bus_id, lintr->src_bus_irq,
321 lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
[f761f1eb]322#endif
323}
324
[fe32163]325static void ct_extended_entries(void)
[f761f1eb]326{
[7f1c620]327 uint8_t *ext = (uint8_t *) ct + ct->base_table_length;
328 uint8_t *cur;
[fe32163]329
[4bb31f7]330 for (cur = ext; cur < ext + ct->ext_table_length;
331 cur += cur[CT_EXT_ENTRY_LEN]) {
[8a78e68]332 switch (cur[CT_EXT_ENTRY_TYPE]) {
[4bb31f7]333 default:
[fe32163]334 printf("MPS: Skipping MP Configuration Table extended "
335 "entry type %" PRIu8 "\n", cur[CT_EXT_ENTRY_TYPE]);
336 }
337 }
338}
339
340static void configure_via_ct(void)
341{
342 if (ct->signature != CT_SIGNATURE) {
343 printf("MPS: Wrong ct->signature\n");
344 return;
345 }
346
347 if (!mps_ct_check()) {
348 printf("MPS: Wrong ct checksum\n");
349 return;
350 }
351
352 if (ct->oem_table) {
353 printf("MPS: ct->oem_table not supported\n");
354 return;
355 }
356
357 l_apic = (uint32_t *) (uintptr_t) ct->l_apic;
358
359 uint8_t *cur = &ct->base_table[0];
360 uint16_t i;
361
362 for (i = 0; i < ct->entry_count; i++) {
363 switch (*cur) {
364 case 0: /* Processor entry */
365 processor_entries = processor_entries ?
366 processor_entries :
367 (struct __processor_entry *) cur;
368 processor_entry_cnt++;
369 ct_processor_entry((struct __processor_entry *) cur);
370 cur += 20;
371 break;
372 case 1: /* Bus entry */
373 bus_entries = bus_entries ?
374 bus_entries : (struct __bus_entry *) cur;
375 bus_entry_cnt++;
376 ct_bus_entry((struct __bus_entry *) cur);
377 cur += 8;
378 break;
379 case 2: /* I/O APIC */
380 io_apic_entries = io_apic_entries ?
381 io_apic_entries : (struct __io_apic_entry *) cur;
382 io_apic_entry_cnt++;
383 ct_io_apic_entry((struct __io_apic_entry *) cur);
384 cur += 8;
[4bb31f7]385 break;
[fe32163]386 case 3: /* I/O Interrupt Assignment */
387 io_intr_entries = io_intr_entries ?
388 io_intr_entries : (struct __io_intr_entry *) cur;
389 io_intr_entry_cnt++;
390 ct_io_intr_entry((struct __io_intr_entry *) cur);
391 cur += 8;
392 break;
393 case 4: /* Local Interrupt Assignment */
394 l_intr_entries = l_intr_entries ?
395 l_intr_entries : (struct __l_intr_entry *) cur;
396 l_intr_entry_cnt++;
397 ct_l_intr_entry((struct __l_intr_entry *) cur);
398 cur += 8;
399 break;
400 default:
401 /*
402 * Something is wrong. Fallback to UP mode.
403 */
404 printf("MPS: ct badness %" PRIu8 "\n", *cur);
405 return;
[8a78e68]406 }
407 }
[fe32163]408
409 /*
410 * Process extended entries.
411 */
412 ct_extended_entries();
[f761f1eb]413}
414
[fe32163]415static void configure_via_default(uint8_t n __attribute__((unused)))
[f761f1eb]416{
[fe32163]417 /*
418 * Not yet implemented.
419 */
420 printf("MPS: Default configuration not supported\n");
421}
422
423void mps_init(void)
424{
425 uint8_t *addr[2] = { NULL, (uint8_t *) PA2KA(0xf0000) };
[3802fcd]426 unsigned int i;
[fe32163]427 unsigned int j;
428 unsigned int length[2] = { 1024, 64 * 1024 };
[f761f1eb]429
[fe32163]430 /*
431 * Find MP Floating Pointer Structure
432 * 1a. search first 1K of EBDA
433 * 1b. if EBDA is undefined, search last 1K of base memory
434 * 2. search 64K starting at 0xf0000
435 */
436
437 addr[0] = (uint8_t *) PA2KA(ebda ? ebda : 639 * 1024);
438 for (i = 0; i < 2; i++) {
439 for (j = 0; j < length[i]; j += 16) {
440 if ((*((uint32_t *) &addr[i][j]) ==
441 FS_SIGNATURE) && (mps_fs_check(&addr[i][j]))) {
442 fs = (struct mps_fs *) &addr[i][j];
443 goto fs_found;
444 }
445 }
[f761f1eb]446 }
447
[fe32163]448 return;
449
450fs_found:
451 printf("%p: MPS Floating Pointer Structure\n", fs);
452
453 if ((fs->config_type == 0) && (fs->configuration_table)) {
454 if (fs->mpfib2 >> 7) {
455 printf("MPS: PIC mode not supported\n");
456 return;
457 }
458
459 ct = (struct mps_ct *) PA2KA((uintptr_t) fs->configuration_table);
460 configure_via_ct();
461 } else
462 configure_via_default(fs->config_type);
463
464 if (processor_entry_cnt > 0)
465 config.cpu_count = processor_entry_cnt;
[f761f1eb]466}
467
[5f85c91]468#endif /* CONFIG_SMP */
[b45c443]469
[06e1e95]470/** @}
[b45c443]471 */
Note: See TracBrowser for help on using the repository browser.