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