UbixOS V2 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
41 uInt8 kernel_function(void);
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 {
64 uInt16 limit;
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;
121 uInt8 kernel_function(void) {
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
177 uInt8 cpuInfo() {
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(),
230 ap_trampoline_end();
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);
235 memcpy(0x0, (char *) ap_trampoline_start, ap_trampoline_end - 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
253 uInt32 getEflags() {
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