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

Last change on this file was c5429fe, checked in by Jakub Jermar <jakub@…>, 7 years ago

Disambiguate architecture specific doxygroups

  • Property mode set to 100644
File size: 10.4 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
[c5429fe]29/** @addtogroup kernel_ia32
[b45c443]30 * @{
31 */
32/** @file
33 */
34
[5f85c91]35#ifdef CONFIG_SMP
[f761f1eb]36
37#include <config.h>
[b2fa1204]38#include <log.h>
[ed0dd65]39#include <arch/smp/mps.h>
[397c77f]40#include <arch/smp/apic.h>
[a26ddd1]41#include <arch/smp/smp.h>
[63e27ef]42#include <assert.h>
[b2e121a]43#include <halt.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
[dc0b964]54#define FS_SIGNATURE UINT32_C(0x5f504d5f)
55#define CT_SIGNATURE UINT32_C(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
[0a79ad9]74static uint8_t mps_cpu_apic_id(size_t i)
[a26ddd1]75{
[63e27ef]76 assert(i < processor_entry_cnt);
[a35b458]77
[fe32163]78 return processor_entries[i].l_apic_id;
[a26ddd1]79}
80
[0a79ad9]81static bool mps_cpu_enabled(size_t i)
[a26ddd1]82{
[63e27ef]83 assert(i < processor_entry_cnt);
[a35b458]84
[fe32163]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;
[a35b458]92
[c81132d]93 return ((processor_entries[i].cpu_flags & 0x01) == 0x01);
[a26ddd1]94}
95
[0a79ad9]96static bool mps_cpu_bootstrap(size_t i)
[a26ddd1]97{
[63e27ef]98 assert(i < processor_entry_cnt);
[a35b458]99
[c81132d]100 return ((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;
[a35b458]106
[fe32163]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 }
[a35b458]112
[fe32163]113 return -1;
[a26ddd1]114}
115
[fe32163]116/** Implementation of IA-32 SMP configuration interface.
117 *
118 */
119struct smp_config_operations mps_config_operations = {
[0a79ad9]120 .cpu_enabled = mps_cpu_enabled,
121 .cpu_bootstrap = mps_cpu_bootstrap,
122 .cpu_apic_id = mps_cpu_apic_id,
[fe32163]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;
[a35b458]133
[f761f1eb]134 for (i = 0, sum = 0; i < 16; i++)
[7f043c0]135 sum = (uint8_t) (sum + base[i]);
[a35b458]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;
[a35b458]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]);
[a35b458]153
[f761f1eb]154 if (sum)
[fe32163]155 return false;
[a35b458]156
[fe32163]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]);
[a35b458]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;
[a35b458]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];
[a35b458]179
[9756131]180 memcpy((void *) buf, (void *) bus->bus_type, 6);
[f761f1eb]181 buf[6] = 0;
[a35b458]182
[b2fa1204]183 log(LF_ARCH, LVL_DEBUG, "MPS: bus=%" PRIu8 " (%s)", 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;
[a35b458]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 }
[a35b458]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
[b2fa1204]207 log_begin(LF_ARCH, LVL_DEBUG);
208 log_printf("MPS: ");
[a35b458]209
[f761f1eb]210 switch (iointr->intr_type) {
[4bb31f7]211 case 0:
[b2fa1204]212 log_printf("INT");
[4bb31f7]213 break;
214 case 1:
[b2fa1204]215 log_printf("NMI");
[4bb31f7]216 break;
217 case 2:
[b2fa1204]218 log_printf("SMI");
[4bb31f7]219 break;
220 case 3:
[b2fa1204]221 log_printf("ExtINT");
[4bb31f7]222 break;
[f761f1eb]223 }
[a35b458]224
[b2fa1204]225 log_printf(", ");
[a35b458]226
[4bb31f7]227 switch (iointr->poel & 3) {
228 case 0:
[b2fa1204]229 log_printf("bus-like");
[4bb31f7]230 break;
231 case 1:
[b2fa1204]232 log_printf("active high");
[4bb31f7]233 break;
234 case 2:
[b2fa1204]235 log_printf("reserved");
[4bb31f7]236 break;
237 case 3:
[b2fa1204]238 log_printf("active low");
[4bb31f7]239 break;
[f761f1eb]240 }
[a35b458]241
[b2fa1204]242 log_printf(", ");
[a35b458]243
[4bb31f7]244 switch ((iointr->poel >> 2) & 3) {
245 case 0:
[b2fa1204]246 log_printf("bus-like");
[4bb31f7]247 break;
248 case 1:
[b2fa1204]249 log_printf("edge-triggered");
[4bb31f7]250 break;
251 case 2:
[b2fa1204]252 log_printf("reserved");
[4bb31f7]253 break;
254 case 3:
[b2fa1204]255 log_printf("level-triggered");
[4bb31f7]256 break;
[f761f1eb]257 }
[a35b458]258
[1433ecda]259 log_printf(", bus=%" PRIu8 " irq=%" PRIu8 " io_apic=%" PRIu8 " pin=%"
[b2fa1204]260 PRIu8, iointr->src_bus_id, iointr->src_bus_irq,
[fe32163]261 iointr->dst_io_apic_id, iointr->dst_io_apic_pin);
[b2fa1204]262 log_end();
[f761f1eb]263#endif
264}
265
[fe32163]266static void ct_l_intr_entry(struct __l_intr_entry *lintr
267 __attribute__((unused)))
[f761f1eb]268{
[ed0dd65]269#ifdef MPSCT_VERBOSE
[b2fa1204]270 log_begin(LF_ARCH, LVL_DEBUG);
271 log_printf("MPS: ");
[a35b458]272
[f761f1eb]273 switch (lintr->intr_type) {
[4bb31f7]274 case 0:
[b2fa1204]275 log_printf("INT");
[fe32163]276 break;
[4bb31f7]277 case 1:
[b2fa1204]278 log_printf("NMI");
[fe32163]279 break;
[4bb31f7]280 case 2:
[b2fa1204]281 log_printf("SMI");
[fe32163]282 break;
[4bb31f7]283 case 3:
[b2fa1204]284 log_printf("ExtINT");
[fe32163]285 break;
[f761f1eb]286 }
[a35b458]287
[b2fa1204]288 log_printf(", ");
[a35b458]289
[4bb31f7]290 switch (lintr->poel & 3) {
291 case 0:
[b2fa1204]292 log_printf("bus-like");
[fe32163]293 break;
[4bb31f7]294 case 1:
[b2fa1204]295 log_printf("active high");
[fe32163]296 break;
[4bb31f7]297 case 2:
[b2fa1204]298 log_printf("reserved");
[fe32163]299 break;
[4bb31f7]300 case 3:
[b2fa1204]301 log_printf("active low");
[fe32163]302 break;
[f761f1eb]303 }
[a35b458]304
[b2fa1204]305 log_printf(", ");
[a35b458]306
[4bb31f7]307 switch ((lintr->poel >> 2) & 3) {
308 case 0:
[b2fa1204]309 log_printf("bus-like");
[fe32163]310 break;
[4bb31f7]311 case 1:
[b2fa1204]312 log_printf("edge-triggered");
[fe32163]313 break;
[4bb31f7]314 case 2:
[b2fa1204]315 log_printf("reserved");
[fe32163]316 break;
[4bb31f7]317 case 3:
[b2fa1204]318 log_printf("level-triggered");
[fe32163]319 break;
[f761f1eb]320 }
[a35b458]321
[1433ecda]322 log_printf(", bus=%" PRIu8 " irq=%" PRIu8 " l_apic=%" PRIu8 " pin=%"
[b2fa1204]323 PRIu8, lintr->src_bus_id, lintr->src_bus_irq,
[fe32163]324 lintr->dst_l_apic_id, lintr->dst_l_apic_pin);
[b2fa1204]325 log_end();
[f761f1eb]326#endif
327}
328
[fe32163]329static void ct_extended_entries(void)
[f761f1eb]330{
[7f1c620]331 uint8_t *ext = (uint8_t *) ct + ct->base_table_length;
332 uint8_t *cur;
[a35b458]333
[4bb31f7]334 for (cur = ext; cur < ext + ct->ext_table_length;
335 cur += cur[CT_EXT_ENTRY_LEN]) {
[8a78e68]336 switch (cur[CT_EXT_ENTRY_TYPE]) {
[4bb31f7]337 default:
[b2fa1204]338 log(LF_ARCH, LVL_NOTE, "MPS: Skipping MP Configuration"
339 " Table extended entry type %" PRIu8,
340 cur[CT_EXT_ENTRY_TYPE]);
[fe32163]341 }
342 }
343}
344
345static void configure_via_ct(void)
346{
347 if (ct->signature != CT_SIGNATURE) {
[b2fa1204]348 log(LF_ARCH, LVL_WARN, "MPS: Wrong ct->signature");
[fe32163]349 return;
350 }
[a35b458]351
[fe32163]352 if (!mps_ct_check()) {
[b2fa1204]353 log(LF_ARCH, LVL_WARN, "MPS: Wrong ct checksum");
[fe32163]354 return;
355 }
[a35b458]356
[fe32163]357 if (ct->oem_table) {
[b2fa1204]358 log(LF_ARCH, LVL_WARN, "MPS: ct->oem_table not supported");
[fe32163]359 return;
360 }
[a35b458]361
[fe32163]362 l_apic = (uint32_t *) (uintptr_t) ct->l_apic;
[a35b458]363
[fe32163]364 uint8_t *cur = &ct->base_table[0];
365 uint16_t i;
[a35b458]366
[fe32163]367 for (i = 0; i < ct->entry_count; i++) {
368 switch (*cur) {
369 case 0: /* Processor entry */
370 processor_entries = processor_entries ?
371 processor_entries :
372 (struct __processor_entry *) cur;
373 processor_entry_cnt++;
374 ct_processor_entry((struct __processor_entry *) cur);
375 cur += 20;
376 break;
377 case 1: /* Bus entry */
378 bus_entries = bus_entries ?
379 bus_entries : (struct __bus_entry *) cur;
380 bus_entry_cnt++;
381 ct_bus_entry((struct __bus_entry *) cur);
382 cur += 8;
383 break;
384 case 2: /* I/O APIC */
385 io_apic_entries = io_apic_entries ?
386 io_apic_entries : (struct __io_apic_entry *) cur;
387 io_apic_entry_cnt++;
388 ct_io_apic_entry((struct __io_apic_entry *) cur);
389 cur += 8;
[4bb31f7]390 break;
[fe32163]391 case 3: /* I/O Interrupt Assignment */
392 io_intr_entries = io_intr_entries ?
393 io_intr_entries : (struct __io_intr_entry *) cur;
394 io_intr_entry_cnt++;
395 ct_io_intr_entry((struct __io_intr_entry *) cur);
396 cur += 8;
397 break;
398 case 4: /* Local Interrupt Assignment */
399 l_intr_entries = l_intr_entries ?
400 l_intr_entries : (struct __l_intr_entry *) cur;
401 l_intr_entry_cnt++;
402 ct_l_intr_entry((struct __l_intr_entry *) cur);
403 cur += 8;
404 break;
405 default:
406 /*
407 * Something is wrong. Fallback to UP mode.
408 */
[b2fa1204]409 log(LF_ARCH, LVL_WARN, "MPS: ct badness %" PRIu8, *cur);
[fe32163]410 return;
[8a78e68]411 }
412 }
[a35b458]413
[fe32163]414 /*
415 * Process extended entries.
416 */
417 ct_extended_entries();
[f761f1eb]418}
419
[fe32163]420static void configure_via_default(uint8_t n __attribute__((unused)))
[f761f1eb]421{
[fe32163]422 /*
423 * Not yet implemented.
424 */
[b2fa1204]425 log(LF_ARCH, LVL_WARN, "MPS: Default configuration not supported");
[fe32163]426}
427
428void mps_init(void)
429{
430 uint8_t *addr[2] = { NULL, (uint8_t *) PA2KA(0xf0000) };
[3802fcd]431 unsigned int i;
[fe32163]432 unsigned int j;
433 unsigned int length[2] = { 1024, 64 * 1024 };
[a35b458]434
[fe32163]435 /*
436 * Find MP Floating Pointer Structure
437 * 1a. search first 1K of EBDA
438 * 1b. if EBDA is undefined, search last 1K of base memory
439 * 2. search 64K starting at 0xf0000
440 */
[a35b458]441
[fe32163]442 addr[0] = (uint8_t *) PA2KA(ebda ? ebda : 639 * 1024);
443 for (i = 0; i < 2; i++) {
444 for (j = 0; j < length[i]; j += 16) {
445 if ((*((uint32_t *) &addr[i][j]) ==
446 FS_SIGNATURE) && (mps_fs_check(&addr[i][j]))) {
447 fs = (struct mps_fs *) &addr[i][j];
448 goto fs_found;
449 }
450 }
[f761f1eb]451 }
[a35b458]452
[fe32163]453 return;
[a35b458]454
[fe32163]455fs_found:
[b2fa1204]456 log(LF_ARCH, LVL_NOTE, "%p: MPS Floating Pointer Structure", fs);
[a35b458]457
[fe32163]458 if ((fs->config_type == 0) && (fs->configuration_table)) {
459 if (fs->mpfib2 >> 7) {
[b2fa1204]460 log(LF_ARCH, LVL_WARN, "MPS: PIC mode not supported\n");
[fe32163]461 return;
462 }
[a35b458]463
[fe32163]464 ct = (struct mps_ct *) PA2KA((uintptr_t) fs->configuration_table);
465 configure_via_ct();
466 } else
467 configure_via_default(fs->config_type);
[a35b458]468
[fe32163]469 if (processor_entry_cnt > 0)
470 config.cpu_count = processor_entry_cnt;
[f761f1eb]471}
472
[5f85c91]473#endif /* CONFIG_SMP */
[b45c443]474
[06e1e95]475/** @}
[b45c443]476 */
Note: See TracBrowser for help on using the repository browser.