Subversion Repositories HelenOS

Rev

Rev 1787 | Rev 2071 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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