smp.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <smp/smp.h>
00036 #include <arch/smp/smp.h>
00037 #include <arch/smp/mps.h>
00038 #include <arch/smp/ap.h>
00039 #include <arch/boot/boot.h>
00040 #include <genarch/acpi/acpi.h>
00041 #include <genarch/acpi/madt.h>
00042 #include <config.h>
00043 #include <synch/waitq.h>
00044 #include <synch/synch.h>
00045 #include <arch/pm.h>
00046 #include <func.h>
00047 #include <panic.h>
00048 #include <debug.h>
00049 #include <arch/asm.h>
00050 #include <mm/frame.h>
00051 #include <mm/page.h>
00052 #include <mm/slab.h>
00053 #include <mm/as.h>
00054 #include <print.h>
00055 #include <memstr.h>
00056 #include <arch/drivers/i8259.h>
00057 
00058 #ifdef CONFIG_SMP
00059 
00060 static struct smp_config_operations *ops = NULL;
00061 
00062 void smp_init(void)
00063 {
00064         int status;
00065         __address l_apic_address, io_apic_address;
00066 
00067         if (acpi_madt) {
00068                 acpi_madt_parse();
00069                 ops = &madt_config_operations;
00070         }
00071         if (config.cpu_count == 1) {
00072                 mps_init();
00073                 ops = &mps_config_operations;
00074         }
00075 
00076         l_apic_address = PA2KA(PFN2ADDR(frame_alloc_rc(ONE_FRAME, FRAME_ATOMIC | FRAME_KA, &status)));
00077         if (status != FRAME_OK)
00078                 panic("cannot allocate address for l_apic\n");
00079 
00080         io_apic_address = PA2KA(PFN2ADDR(frame_alloc_rc(ONE_FRAME, FRAME_ATOMIC | FRAME_KA, &status)));
00081         if (status != FRAME_OK)
00082                 panic("cannot allocate address for io_apic\n");
00083 
00084         if (config.cpu_count > 1) {             
00085                 page_mapping_insert(AS_KERNEL, l_apic_address, (__address) l_apic, 
00086                                   PAGE_NOT_CACHEABLE);
00087                 page_mapping_insert(AS_KERNEL, io_apic_address, (__address) io_apic,
00088                                   PAGE_NOT_CACHEABLE);
00089                                   
00090                 l_apic = (__u32 *) l_apic_address;
00091                 io_apic = (__u32 *) io_apic_address;
00092         }
00093 }
00094 
00095 /*
00096  * Kernel thread for bringing up application processors. It becomes clear
00097  * that we need an arrangement like this (AP's being initialized by a kernel
00098  * thread), for a thread has its dedicated stack. (The stack used during the
00099  * BSP initialization (prior the very first call to scheduler()) will be used
00100  * as an initialization stack for each AP.)
00101  */
00102 void kmp(void *arg)
00103 {
00104         int i;
00105         
00106         ASSERT(ops != NULL);
00107 
00108         waitq_initialize(&ap_completion_wq);
00109 
00110         /*
00111          * We need to access data in frame 0.
00112          * We boldly make use of kernel address space mapping.
00113          */
00114 
00115         /*
00116          * Set the warm-reset vector to the real-mode address of 4K-aligned ap_boot()
00117          */
00118         *((__u16 *) (PA2KA(0x467+0))) =  ((__address) ap_boot) >> 4;    /* segment */
00119         *((__u16 *) (PA2KA(0x467+2))) =  0;                             /* offset */
00120         
00121         /*
00122          * Save 0xa to address 0xf of the CMOS RAM.
00123          * BIOS will not do the POST after the INIT signal.
00124          */
00125         outb(0x70,0xf);
00126         outb(0x71,0xa);
00127 
00128         pic_disable_irqs(0xffff);
00129         apic_init();
00130 
00131         for (i = 0; i < ops->cpu_count(); i++) {
00132                 struct descriptor *gdt_new;
00133         
00134                 /*
00135                  * Skip processors marked unusable.
00136                  */
00137                 if (!ops->cpu_enabled(i))
00138                         continue;
00139 
00140                 /*
00141                  * The bootstrap processor is already up.
00142                  */
00143                 if (ops->cpu_bootstrap(i))
00144                         continue;
00145 
00146                 if (ops->cpu_apic_id(i) == l_apic_id()) {
00147                         printf("%s: bad processor entry #%d, will not send IPI to myself\n", __FUNCTION__, i);
00148                         continue;
00149                 }
00150                 
00151                 /*
00152                  * Prepare new GDT for CPU in question.
00153                  */
00154                 if (!(gdt_new = (struct descriptor *) malloc(GDT_ITEMS*sizeof(struct descriptor), FRAME_ATOMIC)))
00155                         panic("couldn't allocate memory for GDT\n");
00156 
00157                 memcpy(gdt_new, gdt, GDT_ITEMS * sizeof(struct descriptor));
00158                 memsetb((__address)(&gdt_new[TSS_DES]), sizeof(struct descriptor), 0);
00159                 protected_ap_gdtr.limit = GDT_ITEMS * sizeof(struct descriptor);
00160                 protected_ap_gdtr.base = KA2PA((__address) gdt_new);
00161                 gdtr.base = (__address) gdt_new;
00162 
00163                 if (l_apic_send_init_ipi(ops->cpu_apic_id(i))) {
00164                         /*
00165                          * There may be just one AP being initialized at
00166                          * the time. After it comes completely up, it is
00167                          * supposed to wake us up.
00168                          */
00169                         if (waitq_sleep_timeout(&ap_completion_wq, 1000000, SYNCH_FLAGS_NONE) == ESYNCH_TIMEOUT)
00170                                 printf("%s: waiting for cpu%d (APIC ID = %d) timed out\n", __FUNCTION__, config.cpu_active > i ? config.cpu_active : i, ops->cpu_apic_id(i));
00171                 } else
00172                         printf("INIT IPI for l_apic%d failed\n", ops->cpu_apic_id(i));
00173         }
00174 }
00175 
00176 int smp_irq_to_pin(int irq)
00177 {
00178         ASSERT(ops != NULL);
00179         return ops->irq_to_pin(irq);
00180 }
00181 
00182 #endif /* CONFIG_SMP */
00183 

Generated on Sun Jun 18 16:38:50 2006 for HelenOS Kernel (ia32) by  doxygen 1.4.6