smp.c

Go to the documentation of this file.
00001 /*****************************************************************************************
00002  Copyright (c) 2002 The UbixOS Project
00003  All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are
00006 permitted provided that the following conditions are met:
00007 
00008 Redistributions of source code must retain the above copyright notice, this list of
00009 conditions, the following disclaimer and the list of authors.  Redistributions in binary
00010 form must reproduce the above copyright notice, this list of conditions, the following
00011 disclaimer and the list of authors in the documentation and/or other materials provided
00012 with the distribution. Neither the name of the UbixOS Project nor the names of its
00013 contributors may be used to endorse or promote products derived from this software
00014 without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
00017 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00018 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
00019 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00020 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00021 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00022 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
00023 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00024 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025 
00026  $Id: smp_8c-source.html 88 2016-01-12 00:11:29Z reddawg $
00027 
00028 *****************************************************************************************/
00029 
00030 #include <ubixos/smp.h>
00031 #include <ubixos/spinlock.h>
00032 #include <ubixos/kpanic.h>
00033 #include <lib/kprintf.h>
00034 #include <lib/string.h>
00035 #include <sys/io.h>
00036 
00037 static spinLock_t initSpinLock = SPIN_LOCK_INITIALIZER;
00038 static spinLock_t cpuInfoLock = SPIN_LOCK_INITIALIZER;
00039 static uInt32 cpus = 0;
00040 struct cpuinfo_t cpuinfo[8];
00041 
00042 uInt8 kernel_function(void);
00043 uInt8 *vram = (uInt8 *)0xB8000;
00044 
00045 static inline unsigned int apicRead(address) {
00046   return *(volatile unsigned int *) (0xFEE00000 + address);
00047   }
00048 
00049 static inline void apicWrite(unsigned int address,unsigned int data) {
00050   *(volatile unsigned int *) (0xFEE00000 + address) = data;
00051   }
00052 
00053 static __inline__ void setDr3 (void *dr3) {
00054   register uInt32 value = (uInt32)dr3;
00055   __asm__ __volatile__ ("mov %0, %%dr3" :: "r" (value));
00056   }
00057 
00058 static __inline__ uInt32 getDr3 (void) {
00059   register uInt32 value;
00060   __asm__ __volatile__ ("mov %%dr3, %0" : "=r" (value));
00061   return value;
00062   }
00063 
00064 struct gdt_descr {
00065   uInt16  limit;
00066   uInt32 *base __attribute__ ((packed));
00067 };
00068 
00069 static void GDT_fixer() {
00070   struct gdt_descr  gdt_descr;
00071   uInt32 *gdt = (uInt32 *)0x20000; // 128KB
00072 
00073   gdt[0] = 0;
00074   gdt[1] = 0;
00075   gdt[2] = 0x0000ffff; // seg 0x8  -- DPL 0 4GB code
00076   gdt[3] = 0x00cf9a00;
00077   gdt[4] = 0x0000ffff; // seg 0x10 -- DPL 0 4GB data
00078   gdt[5] = 0x00cf9200;
00079   gdt[6] = 0x0000ffff; // seg 0x1b -- DPL 3 4GB code
00080   gdt[7] = 0x00cffa00;
00081   gdt[8] = 0x0000ffff; // seg 0x23 -- DPL 3 4GB data
00082   gdt[9] = 0x00cff200;
00083 
00084   gdt_descr.limit = 32 * 4;
00085   gdt_descr.base  = gdt;
00086 
00087   /*
00088   asm("lgdt %0;" : : "m" (gdt_descr));
00089   __asm__ __volatile__ ("ljmp %0,$1f; 1:" :: "i" (0x08));
00090   __asm__ __volatile__ ("movw %w0,%%ds" :: "r" (0x10));
00091   __asm__ __volatile__ ("movw %w0,%%es" :: "r" (0x10));
00092   __asm__ __volatile__ ("movw %w0,%%ss" :: "r" (0x10));
00093   */
00094   }
00095 
00096 
00097 void cpu0_thread(void) {
00098   for(;;) {
00099     vram[40+640] = kernel_function();
00100     vram[42+640]++;
00101   }
00102 }
00103 void cpu1_thread(void) {
00104   for(;;) {
00105     vram[60+640] = kernel_function();
00106     vram[62+640]++;
00107   }
00108 }
00109 void cpu2_thread(void) {
00110   for(;;) {
00111     vram[80+640] = kernel_function();
00112     vram[82+640]++;
00113   }
00114 }
00115 void cpu3_thread(void) {
00116   for(;;) {
00117     vram[100+640] = kernel_function();
00118     vram[102+640]++;
00119   }
00120 }
00121 
00122 static spinLock_t bkl = SPIN_LOCK_INITIALIZER;
00123 uInt8 kernel_function(void) {
00124   struct cpuinfo_t *cpu;
00125 
00126   spinLock(&bkl);
00127 
00128 
00129   cpu = (struct cpuinfo_t *)getDr3();
00130 
00131   spinUnlock(&bkl);
00132 
00133   return('0' + cpu->id);
00134 }
00135 
00136 
00137 void c_ap_boot(void) {
00138 
00139   while(spinLockLocked(&initSpinLock));
00140 
00141   switch(cpuInfo()) {
00142   case 1:
00143     cpu1_thread();
00144     break;
00145   case 2:
00146     cpu2_thread();
00147     break;
00148   case 3:
00149     cpu3_thread();
00150     break;
00151   }
00152 
00153   outportByte(0xe9,'5');
00154 
00155   for(;;) {
00156     asm("nop");
00157   }
00158 }
00159 
00160 
00161 void smpInit() {
00162   spinLock(&initSpinLock);
00163   GDT_fixer();
00164   cpuidDetect();
00165   cpuInfo();
00166   apicMagic();
00167   spinUnlock(&initSpinLock);
00168 
00169   //cpu0_thread(); 
00170  
00171   }
00172 
00173 void cpuidDetect() {
00174   if (!(getEflags() & (1<<21)) ) {
00175     setEflags(getEflags() | (1<<21));
00176     if( !(getEflags() & (1<<21)) ) {
00177       kpanic("CPU doesn't support CPUID, get a newer machine\n");
00178       }
00179     }
00180   }
00181 
00182 uInt8 cpuInfo() {
00183   uInt32 data[4],i;
00184 
00185   if( !(getEflags() & (1<<21)) ) {       // If the cpuid bit in eflags not set..
00186     setEflags(getEflags() | (1<<21));   // ..try and set it to see if it comes on..
00187     if( !(getEflags() & (1<<21)) ) {     // It didn't.. This CPU suck
00188       kpanic("CPU doesn't support CPUID, get a newer machine\n");
00189     }
00190   }
00191 
00192   spinLock(&cpuInfoLock);
00193   cpuinfo[cpus].ok = 1;
00194   cpuinfo[cpus].apic_id  = apicRead(0x20) >> 24;
00195   cpuinfo[cpus].apic_ver = apicRead(0x30) & 0xFF;
00196 
00197   cpuid(0,data);
00198   *(uInt32 *)&cpuinfo[cpus].ident[0] = data[1];
00199   *(uInt32 *)&cpuinfo[cpus].ident[4] = data[3];
00200   *(uInt32 *)&cpuinfo[cpus].ident[8] = data[2];
00201   cpuinfo[cpus].ident[17] = 0;
00202   cpuinfo[cpus].max = data[0];
00203 
00204   cpuid(1,data);
00205   cpuinfo[cpus].signature = data[0];
00206   cpuinfo[cpus].feature   = data[3];
00207 
00208   cpuid(0x80000000,data);
00209   if(data[0]>=0x80000004) {
00210     for(i=0;i<3;i++) {
00211       cpuid(0x80000002 + i,data);
00212 
00213       *(unsigned int *)&cpuinfo[cpus].brand[16*i+0]  = data[0];
00214       *(unsigned int *)&cpuinfo[cpus].brand[16*i+4]  = data[1];
00215       *(unsigned int *)&cpuinfo[cpus].brand[16*i+8]  = data[2];
00216       *(unsigned int *)&cpuinfo[cpus].brand[16*i+12] = data[3];
00217     }
00218     cpuinfo[cpus].brand[48] = 0;
00219   } else {
00220     cpuinfo[cpus].brand[0] = 0;
00221   }
00222 
00223   setDr3(&cpuinfo[cpus]); // DR3 always points to the cpu-struct for that CPU (should be thread-struct of current thread)
00224   cpuinfo[cpus].id = cpus;
00225 
00226   cpus++;
00227 
00228   spinUnlock(&cpuInfoLock);
00229 
00230   return(cpus - 1);
00231   }
00232 
00233 extern void ap_trampoline_start(),ap_trampoline_end();
00234 void apicMagic(void) {
00235   uInt32 tmp;
00236 
00237   kprintf("Copying %u bytes from 0x%x to 0x00\n",ap_trampoline_end - ap_trampoline_start,ap_trampoline_start);
00238   memcpy(0x0,(char *)ap_trampoline_start,ap_trampoline_end - ap_trampoline_start);
00239   apicWrite(0x280,0);
00240   apicRead(0x280);
00241 
00242   apicWrite(0x300,0x000C4500);  // INIT IPI to all CPUs
00243   for(tmp=0;tmp<800000;tmp++) asm("nop"); // Sleep a little (should be 10ms)
00244   apicWrite(0x300,0x000C4600);  // INIT SIPI to all CPUs
00245   for(tmp=0;tmp<800000;tmp++) asm("nop"); // Sleep a little (should be 200ms)
00246   apicWrite(0x300,0x000C4600);  // Second INIT SIPI
00247   for(tmp=0;tmp<800000;tmp++) asm("nop"); // Sleep a little (should be 200ms)
00248   }
00249 
00250 
00251 
00252 uInt32 getEflags() {
00253   uInt32 eflags = 0x0;
00254   asm(
00255     "pushfl     \n"
00256     "popl %%eax \n"
00257     : "=a" (eflags)
00258     );
00259   return(eflags);
00260   }
00261 
00262 void setEflags(uInt32 eflags) {
00263   asm(
00264     "pushl %%eax \n"
00265     "popfl       \n"
00266     :
00267     : "a" (eflags)
00268     );
00269   }
00270 
00271 asm(
00272   ".globl cpuid            \n"
00273   "cpuid:                  \n"
00274   "  pushl   %ebx          \n"
00275   "  pushl   %edi          \n"
00276   "  movl    12(%esp),%eax \n"
00277   "  movl    16(%esp),%edi \n"
00278   "  cpuid                 \n"
00279   "  movl    %eax,0(%edi)  \n"
00280   "  movl    %ebx,4(%edi)  \n"
00281   "  movl    %ecx,8(%edi)  \n"
00282   "  movl    %edx,12(%edi) \n"
00283   "  popl    %edi          \n"
00284   "  popl    %ebx          \n"
00285   "  ret                   \n"
00286   );
00287  
00288 /***
00289  END
00290  ***/
00291 

Generated on Fri Dec 15 11:18:55 2006 for UbixOS V2 by  doxygen 1.4.7