00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
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; 
00072 
00073   gdt[0] = 0;
00074   gdt[1] = 0;
00075   gdt[2] = 0x0000ffff; 
00076   gdt[3] = 0x00cf9a00;
00077   gdt[4] = 0x0000ffff; 
00078   gdt[5] = 0x00cf9200;
00079   gdt[6] = 0x0000ffff; 
00080   gdt[7] = 0x00cffa00;
00081   gdt[8] = 0x0000ffff; 
00082   gdt[9] = 0x00cff200;
00083 
00084   gdt_descr.limit = 32 * 4;
00085   gdt_descr.base  = gdt;
00086 
00087   
00088 
00089 
00090 
00091 
00092 
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   
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)) ) {       
00186     setEflags(getEflags() | (1<<21));   
00187     if( !(getEflags() & (1<<21)) ) {     
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]); 
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);  
00243   for(tmp=0;tmp<800000;tmp++) asm("nop"); 
00244   apicWrite(0x300,0x000C4600);  
00245   for(tmp=0;tmp<800000;tmp++) asm("nop"); 
00246   apicWrite(0x300,0x000C4600);  
00247   for(tmp=0;tmp<800000;tmp++) asm("nop"); 
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 
00290 
00291