# 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