UbixOS  2.0
smp.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2002-2018 The UbixOS Project.
3  * All rights reserved.
4  *
5  * This was developed by Christopher W. Olsen for the UbixOS Project.
6  *
7  * Redistribution and use in source and binary forms, with or without modification, are permitted
8  * provided that the following conditions are met:
9  *
10  * 1) Redistributions of source code must retain the above copyright notice, this list of
11  * conditions, the following disclaimer and the list of authors.
12  * 2) Redistributions in binary form must reproduce the above copyright notice, this list of
13  * conditions, the following disclaimer and the list of authors in the documentation and/or
14  * other materials provided with the distribution.
15  * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
16  * endorse or promote products derived from this software without specific prior written
17  * permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <ubixos/smp.h>
30 #include <ubixos/spinlock.h>
31 #include <ubixos/kpanic.h>
32 #include <lib/kprintf.h>
33 #include <lib/string.h>
34 #include <sys/io.h>
35 
36 static struct spinLock initSpinLock = SPIN_LOCK_INITIALIZER;
37 static struct spinLock cpuInfoLock = SPIN_LOCK_INITIALIZER;
38 static uInt32 cpus = 0;
39 struct cpuinfo_t cpuinfo[8];
40 
42 uInt8 *vram = (uInt8 *)0xB8000;
43 
44 static inline unsigned int apicRead(address) {
45  return *(volatile unsigned int *) (0xFEE00000 + address);
46 }
47 
48 static inline void apicWrite(unsigned int address,unsigned int data) {
49  *(volatile unsigned int *) (0xFEE00000 + address) = data;
50 }
51 
52 static __inline__ void setDr3 (void *dr3) {
53  register uInt32 value = (uInt32)dr3;
54  __asm__ __volatile__ ("mov %0, %%dr3" :: "r" (value));
55 }
56 
57 static __inline__ uInt32 getDr3 (void) {
58  register uInt32 value;
59  __asm__ __volatile__ ("mov %%dr3, %0" : "=r" (value));
60  return value;
61 }
62 
63 struct gdt_descr {
65  uInt32 *base __attribute__ ((packed));
66 };
67 
68 static void GDT_fixer() {
69  struct gdt_descr gdt_descr;
70  uInt32 *gdt = (uInt32 *)0x20000; // 128KB
71 
72  gdt[0] = 0;
73  gdt[1] = 0;
74  gdt[2] = 0x0000ffff;// seg 0x8 -- DPL 0 4GB code
75  gdt[3] = 0x00cf9a00;
76  gdt[4] = 0x0000ffff;// seg 0x10 -- DPL 0 4GB data
77  gdt[5] = 0x00cf9200;
78  gdt[6] = 0x0000ffff;// seg 0x1b -- DPL 3 4GB code
79  gdt[7] = 0x00cffa00;
80  gdt[8] = 0x0000ffff;// seg 0x23 -- DPL 3 4GB data
81  gdt[9] = 0x00cff200;
82 
83  gdt_descr.limit = 32 * 4;
84  gdt_descr.base = gdt;
85 
86  /*
87  asm("lgdt %0;" : : "m" (gdt_descr));
88  __asm__ __volatile__ ("ljmp %0,$1f; 1:" :: "i" (0x08));
89  __asm__ __volatile__ ("movw %w0,%%ds" :: "r" (0x10));
90  __asm__ __volatile__ ("movw %w0,%%es" :: "r" (0x10));
91  __asm__ __volatile__ ("movw %w0,%%ss" :: "r" (0x10));
92  */
93 }
94 
95 void cpu0_thread(void) {
96  for(;;) {
97  vram[40+640] = kernel_function();
98  vram[42+640]++;
99  }
100 }
101 void cpu1_thread(void) {
102  for(;;) {
103  vram[60+640] = kernel_function();
104  vram[62+640]++;
105  }
106 }
107 void cpu2_thread(void) {
108  for(;;) {
109  vram[80+640] = kernel_function();
110  vram[82+640]++;
111  }
112 }
113 void cpu3_thread(void) {
114  for(;;) {
115  vram[100+640] = kernel_function();
116  vram[102+640]++;
117  }
118 }
119 
120 static struct spinLock bkl = SPIN_LOCK_INITIALIZER;
122  struct cpuinfo_t *cpu;
123 
124  spinLock(&bkl);
125 
126  cpu = (struct cpuinfo_t *)getDr3();
127 
128  spinUnlock(&bkl);
129 
130  return('0' + cpu->id);
131 }
132 
133 void c_ap_boot(void) {
134 
135  while(spinLockLocked(&initSpinLock));
136 
137  switch(cpuInfo()) {
138  case 1:
139  cpu1_thread();
140  break;
141  case 2:
142  cpu2_thread();
143  break;
144  case 3:
145  cpu3_thread();
146  break;
147  }
148 
149  outportByte(0xe9,'5');
150 
151  for(;;) {
152  asm("nop");
153  }
154 }
155 
156 void smpInit() {
157  spinLock(&initSpinLock);
158  GDT_fixer();
159  cpuidDetect();
160  cpuInfo();
161  apicMagic();
162  spinUnlock(&initSpinLock);
163 
164  //cpu0_thread();
165 
166 }
167 
168 void cpuidDetect() {
169  if (!(getEflags() & (1<<21)) ) {
170  setEflags(getEflags() | (1<<21));
171  if( !(getEflags() & (1<<21)) ) {
172  kpanic("CPU doesn't support CPUID, get a newer machine\n");
173  }
174  }
175 }
176 
178  uInt32 data[4],i;
179 
180  if( !(getEflags() & (1<<21)) ) { // If the cpuid bit in eflags not set..
181  setEflags(getEflags() | (1<<21));// ..try and set it to see if it comes on..
182  if( !(getEflags() & (1<<21)) ) { // It didn't.. This CPU suck
183  kpanic("CPU doesn't support CPUID, get a newer machine\n");
184  }
185  }
186 
187  spinLock(&cpuInfoLock);
188  cpuinfo[cpus].ok = 1;
189  cpuinfo[cpus].apic_id = apicRead(0x20) >> 24;
190  cpuinfo[cpus].apic_ver = apicRead(0x30) & 0xFF;
191 
192  cpuid(0,data);
193  *(uInt32 *)&cpuinfo[cpus].ident[0] = data[1];
194  *(uInt32 *)&cpuinfo[cpus].ident[4] = data[3];
195  *(uInt32 *)&cpuinfo[cpus].ident[8] = data[2];
196  cpuinfo[cpus].ident[17] = 0;
197  cpuinfo[cpus].max = data[0];
198 
199  cpuid(1,data);
200  cpuinfo[cpus].signature = data[0];
201  cpuinfo[cpus].feature = data[3];
202 
203  cpuid(0x80000000,data);
204  if(data[0]>=0x80000004) {
205  for(i=0;i<3;i++) {
206  cpuid(0x80000002 + i,data);
207 
208  *(unsigned int *)&cpuinfo[cpus].brand[16*i+0] = data[0];
209  *(unsigned int *)&cpuinfo[cpus].brand[16*i+4] = data[1];
210  *(unsigned int *)&cpuinfo[cpus].brand[16*i+8] = data[2];
211  *(unsigned int *)&cpuinfo[cpus].brand[16*i+12] = data[3];
212  }
213  cpuinfo[cpus].brand[48] = 0;
214  }
215  else {
216  cpuinfo[cpus].brand[0] = 0;
217  }
218 
219  setDr3(&cpuinfo[cpus]); // DR3 always points to the cpu-struct for that CPU (should be thread-struct of current thread)
220  cpuinfo[cpus].id = cpus;
221 
222  cpus++;
223 
224  spinUnlock(&cpuInfoLock);
225 
226  return(cpus - 1);
227 }
228 
229 extern void ap_trampoline_start(),
231 void apicMagic(void) {
232  uInt32 tmp;
233 
234  kprintf("Copying %u bytes from 0x%x to 0x00\n", ap_trampoline_end - ap_trampoline_start, ap_trampoline_start);
236  apicWrite(0x280, 0);
237  apicRead(0x280);
238 
239  apicWrite(0x300, 0x000C4500); // INIT IPI to all CPUs
240  for (tmp = 0; tmp < 800000; tmp++)
241  asm("nop");
242  // Sleep a little (should be 10ms)
243  apicWrite(0x300, 0x000C4600); // INIT SIPI to all CPUs
244  for (tmp = 0; tmp < 800000; tmp++)
245  asm("nop");
246  // Sleep a little (should be 200ms)
247  apicWrite(0x300, 0x000C4600); // Second INIT SIPI
248  for (tmp = 0; tmp < 800000; tmp++)
249  asm("nop");
250  // Sleep a little (should be 200ms)
251 }
252 
254  uInt32 eflags = 0x0;
255  asm(
256  "pushfl \n"
257  "popl %%eax \n"
258  : "=a" (eflags)
259  );
260  return (eflags);
261 }
262 
263 void setEflags(uInt32 eflags) {
264  asm(
265  "pushl %%eax \n"
266  "popfl \n"
267  :
268  : "a" (eflags)
269  );
270 }
271 
272 asm(
273  ".globl cpuid \n"
274  "cpuid: \n"
275  " pushl %ebx \n"
276  " pushl %edi \n"
277  " movl 12(%esp),%eax \n"
278  " movl 16(%esp),%edi \n"
279  " cpuid \n"
280  " movl %eax,0(%edi) \n"
281  " movl %ebx,4(%edi) \n"
282  " movl %ecx,8(%edi) \n"
283  " movl %edx,12(%edi) \n"
284  " popl %edi \n"
285  " popl %ebx \n"
286  " ret \n"
287 );
288 
289 /***
290  END
291  ***/
292 
cpuinfo_t::feature
uInt32 feature
Definition: smp.h:39
getEflags
uInt32 getEflags()
Definition: smp.c:253
smpInit
void smpInit()
Definition: smp.c:156
spinlock.h
uInt32
unsigned long int uInt32
Definition: objgfx30.h:49
cpuinfo_t::max
uInt32 max
Definition: smp.h:40
cpuinfo_t::apic_id
uInt8 apic_id
Definition: smp.h:37
gdt_descr::limit
uInt16 limit
Definition: smp.c:64
smp.h
uInt16
unsigned short int uInt16
Definition: objgfx30.h:48
gdt_descr
Definition: smp.c:63
outportByte
void outportByte(unsigned int, unsigned char)
outputut one byte to specified port
Definition: io.c:72
kernel_function
uInt8 kernel_function(void)
Definition: smp.c:121
spinUnlock
void spinUnlock(spinLock_t *lock)
Definition: spinlock.c:36
apicMagic
void apicMagic(void)
Definition: smp.c:231
cpuinfo_t::ident
char ident[17]
Definition: smp.h:42
SPIN_LOCK_INITIALIZER
#define SPIN_LOCK_INITIALIZER
Definition: spinlock.h:36
ap_trampoline_start
void ap_trampoline_start()
kpanic
void kpanic(const char *fmt,...)
print panic message and halt system
Definition: kpanic.c:41
memcpy
void * memcpy(const void *dst, const void *src, size_t length)
spinLock
void spinLock(spinLock_t *lock)
Definition: spinlock.c:55
kpanic.h
cpuinfo_t::brand
char brand[49]
Definition: smp.h:41
spinLockLocked
int spinLockLocked(spinLock_t *lock)
Definition: spinlock.c:69
cpuinfo_t::signature
uInt32 signature
Definition: smp.h:38
kprintf.h
cpu0_thread
void cpu0_thread(void)
Definition: smp.c:95
uInt8
unsigned char uInt8
Definition: objgfx30.h:47
cpuinfo_t::ok
uInt8 ok
Definition: smp.h:36
cpuinfo_t::id
uInt8 id
Definition: smp.h:35
gdt_descr::__attribute__
uInt32 *base __attribute__((packed))
cpu1_thread
void cpu1_thread(void)
Definition: smp.c:101
cpuid
void cpuid(uInt32, uInt32 *)
cpu3_thread
void cpu3_thread(void)
Definition: smp.c:113
cpuInfo
uInt8 cpuInfo()
Definition: smp.c:177
setEflags
void setEflags(uInt32 eflags)
Definition: smp.c:263
ap_trampoline_end
void ap_trampoline_end()
cpuinfo_t::apic_ver
uInt8 apic_ver
Definition: smp.h:37
spinLock
Definition: spinlock.h:41
cpuidDetect
void cpuidDetect()
Definition: smp.c:168
io.h
cpuinfo
struct cpuinfo_t cpuinfo[8]
Definition: smp.c:39
c_ap_boot
void c_ap_boot(void)
Definition: smp.c:133
vram
uInt8 * vram
Definition: smp.c:42
kprintf
int kprintf(const char *,...)
Definition: kprintf.c:259
cpu2_thread
void cpu2_thread(void)
Definition: smp.c:107
cpuinfo_t
Definition: smp.h:34