xref: /haiku/src/system/kernel/arch/x86/arch_cpu.cpp (revision adb0d19d561947362090081e81d90dde59142026)
1 /*
2  * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 
10 #include <cpu.h>
11 
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 
16 #include <ACPI.h>
17 
18 #include <boot_device.h>
19 #include <commpage.h>
20 #include <debug.h>
21 #include <elf.h>
22 #include <smp.h>
23 #include <tls.h>
24 #include <vm.h>
25 #include <vm_address_space.h>
26 #include <vm_types.h>
27 
28 #include <arch_system_info.h>
29 #include <arch/x86/selector.h>
30 #include <boot/kernel_args.h>
31 
32 #include "interrupts.h"
33 #include "x86_paging.h"
34 
35 
36 #define DUMP_FEATURE_STRING 1
37 
38 
39 /* cpu vendor info */
40 struct cpu_vendor_info {
41 	const char *vendor;
42 	const char *ident_string[2];
43 };
44 
45 static const struct cpu_vendor_info vendor_info[VENDOR_NUM] = {
46 	{ "Intel", { "GenuineIntel" } },
47 	{ "AMD", { "AuthenticAMD" } },
48 	{ "Cyrix", { "CyrixInstead" } },
49 	{ "UMC", { "UMC UMC UMC" } },
50 	{ "NexGen", { "NexGenDriven" } },
51 	{ "Centaur", { "CentaurHauls" } },
52 	{ "Rise", { "RiseRiseRise" } },
53 	{ "Transmeta", { "GenuineTMx86", "TransmetaCPU" } },
54 	{ "NSC", { "Geode by NSC" } },
55 };
56 
57 #define CR0_CACHE_DISABLE		(1UL << 30)
58 #define CR0_NOT_WRITE_THROUGH	(1UL << 29)
59 #define CR0_FPU_EMULATION		(1UL << 2)
60 #define CR0_MONITOR_FPU			(1UL << 1)
61 
62 #define CR4_OS_FXSR				(1UL << 9)
63 #define CR4_OS_XMM_EXCEPTION	(1UL << 10)
64 
65 struct set_mtrr_parameter {
66 	int32	index;
67 	uint64	base;
68 	uint64	length;
69 	uint8	type;
70 };
71 
72 
73 extern "C" void reboot(void);
74 	// from arch_x86.S
75 
76 void (*gX86SwapFPUFunc)(void *oldState, const void *newState);
77 bool gHasSSE = false;
78 
79 static uint32 sCpuRendezvous;
80 static uint32 sCpuRendezvous2;
81 
82 segment_descriptor *gGDT = NULL;
83 
84 /* Some specials for the double fault handler */
85 //static struct tss sDoubleFaultTSS;
86 static uint32 sDoubleFaultStack[10240];
87 
88 static x86_cpu_module_info *sCpuModule;
89 
90 
91 extern "C" void memcpy_generic(void* dest, const void* source, size_t count);
92 extern int memcpy_generic_end;
93 extern "C" void memset_generic(void* dest, int value, size_t count);
94 extern int memset_generic_end;
95 
96 x86_optimized_functions gOptimizedFunctions = {
97 	memcpy_generic,
98 	&memcpy_generic_end,
99 	memset_generic,
100 	&memset_generic_end
101 };
102 
103 
104 static status_t
105 acpi_shutdown(void)
106 {
107 	if (debug_debugger_running())
108 		return B_ERROR;
109 
110 	acpi_module_info* acpi;
111 	if (get_module(B_ACPI_MODULE_NAME, (module_info**)&acpi) != B_OK)
112 		return B_NOT_SUPPORTED;
113 
114 	status_t status = acpi->prepare_sleep_state(ACPI_POWER_STATE_OFF, NULL, 0);
115 	if (status == B_OK) {
116 		//cpu_status state = disable_interrupts();
117 		status = acpi->enter_sleep_state(ACPI_POWER_STATE_OFF);
118 		//restore_interrupts(state);
119 	}
120 
121 	put_module(B_ACPI_MODULE_NAME);
122 	return status;
123 }
124 
125 
126 /*!	Disable CPU caches, and invalidate them. */
127 static void
128 disable_caches()
129 {
130 	x86_write_cr0((x86_read_cr0() | CR0_CACHE_DISABLE) & ~CR0_NOT_WRITE_THROUGH);
131 	wbinvd();
132 	arch_cpu_global_TLB_invalidate();
133 }
134 
135 
136 /*!	Invalidate CPU caches, and enable them. */
137 static void
138 enable_caches()
139 {
140 	wbinvd();
141 	arch_cpu_global_TLB_invalidate();
142 	x86_write_cr0(x86_read_cr0() & ~(CR0_CACHE_DISABLE | CR0_NOT_WRITE_THROUGH));
143 }
144 
145 
146 static void
147 set_mtrr(void *_parameter, int cpu)
148 {
149 	struct set_mtrr_parameter *parameter = (struct set_mtrr_parameter *)_parameter;
150 
151 	// wait until all CPUs have arrived here
152 	smp_cpu_rendezvous(&sCpuRendezvous, cpu);
153 
154 	disable_caches();
155 
156 	sCpuModule->set_mtrr(parameter->index, parameter->base, parameter->length,
157 		parameter->type);
158 
159 	enable_caches();
160 
161 	// wait until all CPUs have arrived here
162 	smp_cpu_rendezvous(&sCpuRendezvous2, cpu);
163 }
164 
165 
166 static void
167 init_mtrrs(void *_unused, int cpu)
168 {
169 	// wait until all CPUs have arrived here
170 	smp_cpu_rendezvous(&sCpuRendezvous, cpu);
171 
172 	disable_caches();
173 
174 	sCpuModule->init_mtrrs();
175 
176 	enable_caches();
177 
178 	// wait until all CPUs have arrived here
179 	smp_cpu_rendezvous(&sCpuRendezvous2, cpu);
180 }
181 
182 
183 uint32
184 x86_count_mtrrs(void)
185 {
186 	if (sCpuModule == NULL)
187 		return 0;
188 
189 	return sCpuModule->count_mtrrs();
190 }
191 
192 
193 void
194 x86_set_mtrr(uint32 index, uint64 base, uint64 length, uint8 type)
195 {
196 	struct set_mtrr_parameter parameter;
197 	parameter.index = index;
198 	parameter.base = base;
199 	parameter.length = length;
200 	parameter.type = type;
201 
202 	sCpuRendezvous = sCpuRendezvous2 = 0;
203 	call_all_cpus(&set_mtrr, &parameter);
204 }
205 
206 
207 status_t
208 x86_get_mtrr(uint32 index, uint64 *_base, uint64 *_length, uint8 *_type)
209 {
210 	// the MTRRs are identical on all CPUs, so it doesn't matter
211 	// on which CPU this runs
212 	return sCpuModule->get_mtrr(index, _base, _length, _type);
213 }
214 
215 
216 extern "C" void
217 init_sse(void)
218 {
219 	if (!x86_check_feature(IA32_FEATURE_SSE, FEATURE_COMMON)
220 		|| !x86_check_feature(IA32_FEATURE_FXSR, FEATURE_COMMON)) {
221 		// we don't have proper SSE support
222 		return;
223 	}
224 
225 	// enable OS support for SSE
226 	x86_write_cr4(x86_read_cr4() | CR4_OS_FXSR | CR4_OS_XMM_EXCEPTION);
227 	x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU));
228 
229 	gX86SwapFPUFunc = i386_fxsave_swap;
230 	gHasSSE = true;
231 }
232 
233 
234 static void
235 load_tss(int cpu)
236 {
237 	short seg = ((TSS_BASE_SEGMENT + cpu) << 3) | DPL_KERNEL;
238 	asm("movw  %0, %%ax;"
239 		"ltr %%ax;" : : "r" (seg) : "eax");
240 }
241 
242 
243 static void
244 init_double_fault(int cpuNum)
245 {
246 	/* set up the double fault tss */
247 	/* TODO: Axel - fix SMP support */
248 	struct tss *tss = &gCPU[cpuNum].arch.double_fault_tss;
249 
250 	memset(tss, 0, sizeof(struct tss));
251 	tss->sp0 = (uint32)sDoubleFaultStack + sizeof(sDoubleFaultStack);
252 	tss->ss0 = KERNEL_DATA_SEG;
253 	read_cr3(tss->cr3);
254 		// copy the current cr3 to the double fault cr3
255 	tss->eip = (uint32)&double_fault;
256 	tss->es = KERNEL_DATA_SEG;
257 	tss->cs = KERNEL_CODE_SEG;
258 	tss->ss = KERNEL_DATA_SEG;
259 	tss->esp = tss->sp0;
260 	tss->ds = KERNEL_DATA_SEG;
261 	tss->fs = KERNEL_DATA_SEG;
262 	tss->gs = KERNEL_DATA_SEG;
263 	tss->ldt_seg_selector = 0;
264 	tss->io_map_base = sizeof(struct tss);
265 
266 	// add TSS descriptor for this new TSS
267 	set_tss_descriptor(&gGDT[DOUBLE_FAULT_TSS_BASE_SEGMENT + cpuNum],
268 		(addr_t)tss, sizeof(struct tss));
269 }
270 
271 
272 #if DUMP_FEATURE_STRING
273 static void
274 dump_feature_string(int currentCPU, cpu_ent *cpu)
275 {
276 	char features[256];
277 	features[0] = 0;
278 
279 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_FPU)
280 		strlcat(features, "fpu ", sizeof(features));
281 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_VME)
282 		strlcat(features, "vme ", sizeof(features));
283 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_DE)
284 		strlcat(features, "de ", sizeof(features));
285 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_PSE)
286 		strlcat(features, "pse ", sizeof(features));
287 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_TSC)
288 		strlcat(features, "tsc ", sizeof(features));
289 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_MSR)
290 		strlcat(features, "msr ", sizeof(features));
291 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_PAE)
292 		strlcat(features, "pae ", sizeof(features));
293 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_MCE)
294 		strlcat(features, "mce ", sizeof(features));
295 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_CX8)
296 		strlcat(features, "cx8 ", sizeof(features));
297 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_APIC)
298 		strlcat(features, "apic ", sizeof(features));
299 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_SEP)
300 		strlcat(features, "sep ", sizeof(features));
301 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_MTRR)
302 		strlcat(features, "mtrr ", sizeof(features));
303 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_PGE)
304 		strlcat(features, "pge ", sizeof(features));
305 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_MCA)
306 		strlcat(features, "mca ", sizeof(features));
307 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_CMOV)
308 		strlcat(features, "cmov ", sizeof(features));
309 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_PAT)
310 		strlcat(features, "pat ", sizeof(features));
311 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_PSE36)
312 		strlcat(features, "pse36 ", sizeof(features));
313 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_PSN)
314 		strlcat(features, "psn ", sizeof(features));
315 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_CLFSH)
316 		strlcat(features, "clfsh ", sizeof(features));
317 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_DS)
318 		strlcat(features, "ds ", sizeof(features));
319 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_ACPI)
320 		strlcat(features, "acpi ", sizeof(features));
321 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_MMX)
322 		strlcat(features, "mmx ", sizeof(features));
323 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_FXSR)
324 		strlcat(features, "fxsr ", sizeof(features));
325 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_SSE)
326 		strlcat(features, "sse ", sizeof(features));
327 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_SSE2)
328 		strlcat(features, "sse2 ", sizeof(features));
329 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_SS)
330 		strlcat(features, "ss ", sizeof(features));
331 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_HTT)
332 		strlcat(features, "htt ", sizeof(features));
333 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_TM)
334 		strlcat(features, "tm ", sizeof(features));
335 	if (cpu->arch.feature[FEATURE_COMMON] & IA32_FEATURE_PBE)
336 		strlcat(features, "pbe ", sizeof(features));
337 	if (cpu->arch.feature[FEATURE_EXT] & IA32_FEATURE_EXT_SSE3)
338 		strlcat(features, "sse3 ", sizeof(features));
339 	if (cpu->arch.feature[FEATURE_EXT] & IA32_FEATURE_EXT_MONITOR)
340 		strlcat(features, "monitor ", sizeof(features));
341 	if (cpu->arch.feature[FEATURE_EXT] & IA32_FEATURE_EXT_DSCPL)
342 		strlcat(features, "dscpl ", sizeof(features));
343 	if (cpu->arch.feature[FEATURE_EXT] & IA32_FEATURE_EXT_EST)
344 		strlcat(features, "est ", sizeof(features));
345 	if (cpu->arch.feature[FEATURE_EXT] & IA32_FEATURE_EXT_TM2)
346 		strlcat(features, "tm2 ", sizeof(features));
347 	if (cpu->arch.feature[FEATURE_EXT] & IA32_FEATURE_EXT_CNXTID)
348 		strlcat(features, "cnxtid ", sizeof(features));
349 	if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_SYSCALL)
350 		strlcat(features, "syscall ", sizeof(features));
351 	if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_NX)
352 		strlcat(features, "nx ", sizeof(features));
353 	if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_MMXEXT)
354 		strlcat(features, "mmxext ", sizeof(features));
355 	if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_FFXSR)
356 		strlcat(features, "ffxsr ", sizeof(features));
357 	if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_LONG)
358 		strlcat(features, "long ", sizeof(features));
359 	if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_3DNOWEXT)
360 		strlcat(features, "3dnowext ", sizeof(features));
361 	if (cpu->arch.feature[FEATURE_EXT_AMD] & IA32_FEATURE_AMD_EXT_3DNOW)
362 		strlcat(features, "3dnow ", sizeof(features));
363 
364 	dprintf("CPU %d: features: %s\n", currentCPU, features);
365 }
366 #endif	// DUMP_FEATURE_STRING
367 
368 
369 static int
370 detect_cpu(int currentCPU)
371 {
372 	cpu_ent *cpu = get_cpu_struct();
373 	char vendorString[17];
374 	cpuid_info cpuid;
375 
376 	// clear out the cpu info data
377 	cpu->arch.vendor = VENDOR_UNKNOWN;
378 	cpu->arch.vendor_name = "UNKNOWN VENDOR";
379 	cpu->arch.feature[FEATURE_COMMON] = 0;
380 	cpu->arch.feature[FEATURE_EXT] = 0;
381 	cpu->arch.feature[FEATURE_EXT_AMD] = 0;
382 	cpu->arch.model_name[0] = 0;
383 
384 	// print some fun data
385 	get_current_cpuid(&cpuid, 0);
386 
387 	// build the vendor string
388 	memset(vendorString, 0, sizeof(vendorString));
389 	memcpy(vendorString, cpuid.eax_0.vendor_id, sizeof(cpuid.eax_0.vendor_id));
390 
391 	// get the family, model, stepping
392 	get_current_cpuid(&cpuid, 1);
393 	cpu->arch.type = cpuid.eax_1.type;
394 	cpu->arch.family = cpuid.eax_1.family;
395 	cpu->arch.extended_family = cpuid.eax_1.extended_family;
396 	cpu->arch.model = cpuid.eax_1.model;
397 	cpu->arch.extended_model = cpuid.eax_1.extended_model;
398 	cpu->arch.stepping = cpuid.eax_1.stepping;
399 	dprintf("CPU %d: type %d family %d extended_family %d model %d "
400 		"extended_model %d stepping %d, string '%s'\n",
401 		currentCPU, cpu->arch.type, cpu->arch.family,
402 		cpu->arch.extended_family, cpu->arch.model,
403 		cpu->arch.extended_model, cpu->arch.stepping, vendorString);
404 
405 	// figure out what vendor we have here
406 
407 	for (int32 i = 0; i < VENDOR_NUM; i++) {
408 		if (vendor_info[i].ident_string[0]
409 			&& !strcmp(vendorString, vendor_info[i].ident_string[0])) {
410 			cpu->arch.vendor = (x86_vendors)i;
411 			cpu->arch.vendor_name = vendor_info[i].vendor;
412 			break;
413 		}
414 		if (vendor_info[i].ident_string[1]
415 			&& !strcmp(vendorString, vendor_info[i].ident_string[1])) {
416 			cpu->arch.vendor = (x86_vendors)i;
417 			cpu->arch.vendor_name = vendor_info[i].vendor;
418 			break;
419 		}
420 	}
421 
422 	// see if we can get the model name
423 	get_current_cpuid(&cpuid, 0x80000000);
424 	if (cpuid.eax_0.max_eax >= 0x80000004) {
425 		// build the model string (need to swap ecx/edx data before copying)
426 		unsigned int temp;
427 		memset(cpu->arch.model_name, 0, sizeof(cpu->arch.model_name));
428 		get_current_cpuid(&cpuid, 0x80000002);
429 		temp = cpuid.regs.edx; cpuid.regs.edx = cpuid.regs.ecx; cpuid.regs.ecx = temp;
430 		memcpy(cpu->arch.model_name, cpuid.as_chars, sizeof(cpuid.as_chars));
431 		get_current_cpuid(&cpuid, 0x80000003);
432 		temp = cpuid.regs.edx; cpuid.regs.edx = cpuid.regs.ecx; cpuid.regs.ecx = temp;
433 		memcpy(cpu->arch.model_name + 16, cpuid.as_chars, sizeof(cpuid.as_chars));
434 		get_current_cpuid(&cpuid, 0x80000004);
435 		temp = cpuid.regs.edx; cpuid.regs.edx = cpuid.regs.ecx; cpuid.regs.ecx = temp;
436 		memcpy(cpu->arch.model_name + 32, cpuid.as_chars, sizeof(cpuid.as_chars));
437 
438 		// some cpus return a right-justified string
439 		int32 i = 0;
440 		while (cpu->arch.model_name[i] == ' ')
441 			i++;
442 		if (i > 0) {
443 			memmove(cpu->arch.model_name, &cpu->arch.model_name[i],
444 				strlen(&cpu->arch.model_name[i]) + 1);
445 		}
446 
447 		dprintf("CPU %d: vendor '%s' model name '%s'\n",
448 			currentCPU, cpu->arch.vendor_name, cpu->arch.model_name);
449 	} else {
450 		strcpy(cpu->arch.model_name, "unknown");
451 	}
452 
453 	// load feature bits
454 	get_current_cpuid(&cpuid, 1);
455 	cpu->arch.feature[FEATURE_COMMON] = cpuid.eax_1.features; // edx
456 	cpu->arch.feature[FEATURE_EXT] = cpuid.eax_1.extended_features; // ecx
457 	if (cpu->arch.vendor == VENDOR_AMD) {
458 		get_current_cpuid(&cpuid, 0x80000001);
459 		cpu->arch.feature[FEATURE_EXT_AMD] = cpuid.regs.edx; // edx
460 	}
461 
462 #if DUMP_FEATURE_STRING
463 	dump_feature_string(currentCPU, cpu);
464 #endif
465 
466 	return 0;
467 }
468 
469 
470 bool
471 x86_check_feature(uint32 feature, enum x86_feature_type type)
472 {
473 	cpu_ent *cpu = get_cpu_struct();
474 
475 #if 0
476 	int i;
477 	dprintf("x86_check_feature: feature 0x%x, type %d\n", feature, type);
478 	for (i = 0; i < FEATURE_NUM; i++) {
479 		dprintf("features %d: 0x%x\n", i, cpu->arch.feature[i]);
480 	}
481 #endif
482 
483 	return (cpu->arch.feature[type] & feature) != 0;
484 }
485 
486 
487 void*
488 x86_get_double_fault_stack(int32 cpu, size_t* _size)
489 {
490 	*_size = sizeof(sDoubleFaultStack);
491 	return sDoubleFaultStack;
492 }
493 
494 
495 //	#pragma mark -
496 
497 
498 status_t
499 arch_cpu_preboot_init_percpu(kernel_args *args, int cpu)
500 {
501 	x86_write_cr0(x86_read_cr0() & ~(CR0_FPU_EMULATION | CR0_MONITOR_FPU));
502 	gX86SwapFPUFunc = i386_fnsave_swap;
503 
504 	return B_OK;
505 }
506 
507 
508 status_t
509 arch_cpu_init_percpu(kernel_args *args, int cpu)
510 {
511 	detect_cpu(cpu);
512 
513 	// load the TSS for this cpu
514 	// note the main cpu gets initialized in arch_cpu_init_post_vm()
515 	if (cpu != 0)
516 		load_tss(cpu);
517 
518 	return 0;
519 }
520 
521 status_t
522 arch_cpu_init(kernel_args *args)
523 {
524 	__x86_setup_system_time(args->arch_args.system_time_cv_factor);
525 
526 	return B_OK;
527 }
528 
529 
530 status_t
531 arch_cpu_init_post_vm(kernel_args *args)
532 {
533 	uint32 i;
534 
535 	// account for the segment descriptors
536 
537 	gGDT = (segment_descriptor *)args->arch_args.vir_gdt;
538 	create_area("gdt", (void **)&gGDT, B_EXACT_ADDRESS, B_PAGE_SIZE,
539 		B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
540 
541 	// currently taken out of the build, because it's not yet used (and assumes
542 	// (a fixed number of used GDT entries)
543 	//i386_selector_init(gGDT);  // pass the new gdt
544 
545 
546 	vm_translation_map_arch_info* kernelArchTranslationMap
547 		= vm_kernel_address_space()->translation_map.arch_data;
548 
549 	// setup task-state segments
550 	for (i = 0; i < args->num_cpus; i++) {
551 		// initialize the regular and double fault tss stored in the per-cpu
552 		// structure
553 		memset(&gCPU[i].arch.tss, 0, sizeof(struct tss));
554 		gCPU[i].arch.tss.ss0 = KERNEL_DATA_SEG;
555 		gCPU[i].arch.tss.io_map_base = sizeof(struct tss);
556 
557 		// add TSS descriptor for this new TSS
558 		set_tss_descriptor(&gGDT[TSS_BASE_SEGMENT + i],
559 			(addr_t)&gCPU[i].arch.tss, sizeof(struct tss));
560 
561 		// initialize the double fault tss
562 		init_double_fault(i);
563 
564 		// init active translation map
565 		gCPU[i].arch.active_translation_map = kernelArchTranslationMap;
566 		kernelArchTranslationMap->AddReference();
567 	}
568 
569 	// set the current hardware task on cpu 0
570 	load_tss(0);
571 
572 	x86_set_task_gate(8, DOUBLE_FAULT_TSS_BASE_SEGMENT << 3);
573 
574 	// setup TLS descriptors (one for every CPU)
575 
576 	for (i = 0; i < args->num_cpus; i++) {
577 		set_segment_descriptor(&gGDT[TLS_BASE_SEGMENT + i], 0, TLS_SIZE,
578 			DT_DATA_WRITEABLE, DPL_USER);
579 	}
580 
581 	// setup SSE2/3 support
582 	init_sse();
583 
584 	return B_OK;
585 }
586 
587 
588 status_t
589 arch_cpu_init_post_modules(kernel_args *args)
590 {
591 	// initialize CPU module
592 
593 	void *cookie = open_module_list("cpu");
594 
595 	while (true) {
596 		char name[B_FILE_NAME_LENGTH];
597 		size_t nameLength = sizeof(name);
598 
599 		if (read_next_module_name(cookie, name, &nameLength) != B_OK
600 			|| get_module(name, (module_info **)&sCpuModule) == B_OK)
601 			break;
602 	}
603 
604 	close_module_list(cookie);
605 
606 	// initialize MTRRs if available
607 	if (x86_count_mtrrs() > 0) {
608 		sCpuRendezvous = sCpuRendezvous2 = 0;
609 		call_all_cpus(&init_mtrrs, NULL);
610 	}
611 
612 	// get optimized functions from the CPU module
613 	if (sCpuModule != NULL && sCpuModule->get_optimized_functions != NULL) {
614 		x86_optimized_functions functions;
615 		memset(&functions, 0, sizeof(functions));
616 
617 		sCpuModule->get_optimized_functions(&functions);
618 
619 		if (functions.memcpy != NULL) {
620 			gOptimizedFunctions.memcpy = functions.memcpy;
621 			gOptimizedFunctions.memcpy_end = functions.memcpy_end;
622 		}
623 
624 		if (functions.memset != NULL) {
625 			gOptimizedFunctions.memset = functions.memset;
626 			gOptimizedFunctions.memset_end = functions.memset_end;
627 		}
628 	}
629 
630 	// put the optimized functions into the commpage
631 	size_t memcpyLen = (addr_t)gOptimizedFunctions.memcpy_end
632 		- (addr_t)gOptimizedFunctions.memcpy;
633 	fill_commpage_entry(COMMPAGE_ENTRY_X86_MEMCPY,
634 		(const void*)gOptimizedFunctions.memcpy, memcpyLen);
635 	size_t memsetLen = (addr_t)gOptimizedFunctions.memset_end
636 		- (addr_t)gOptimizedFunctions.memset;
637 	fill_commpage_entry(COMMPAGE_ENTRY_X86_MEMSET,
638 		(const void*)gOptimizedFunctions.memset, memsetLen);
639 
640 	// add the functions to the commpage image
641 	image_id image = get_commpage_image();
642 	elf_add_memory_image_symbol(image, "commpage_memcpy",
643 		((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_MEMCPY], memcpyLen,
644 		B_SYMBOL_TYPE_TEXT);
645 	elf_add_memory_image_symbol(image, "commpage_memset",
646 		((addr_t*)USER_COMMPAGE_ADDR)[COMMPAGE_ENTRY_X86_MEMSET], memsetLen,
647 		B_SYMBOL_TYPE_TEXT);
648 
649 	return B_OK;
650 }
651 
652 
653 void
654 i386_set_tss_and_kstack(addr_t kstack)
655 {
656 	get_cpu_struct()->arch.tss.sp0 = kstack;
657 }
658 
659 void
660 arch_cpu_global_TLB_invalidate(void)
661 {
662 	uint32 flags = x86_read_cr4();
663 
664 	if (flags & IA32_CR4_GLOBAL_PAGES) {
665 		// disable and reenable the global pages to flush all TLBs regardless
666 		// of the global page bit
667 		x86_write_cr4(flags & ~IA32_CR4_GLOBAL_PAGES);
668 		x86_write_cr4(flags | IA32_CR4_GLOBAL_PAGES);
669 	} else
670 		arch_cpu_user_TLB_invalidate();
671 }
672 
673 
674 void
675 arch_cpu_invalidate_TLB_range(addr_t start, addr_t end)
676 {
677 	int32 num_pages = end / B_PAGE_SIZE - start / B_PAGE_SIZE;
678 	while (num_pages-- >= 0) {
679 		invalidate_TLB(start);
680 		start += B_PAGE_SIZE;
681 	}
682 }
683 
684 
685 void
686 arch_cpu_invalidate_TLB_list(addr_t pages[], int num_pages)
687 {
688 	int i;
689 	for (i = 0; i < num_pages; i++) {
690 		invalidate_TLB(pages[i]);
691 	}
692 }
693 
694 ssize_t
695 arch_cpu_user_strlcpy(char *to, const char *from, size_t size, addr_t *faultHandler)
696 {
697 	int fromLength = 0;
698 	addr_t oldFaultHandler = *faultHandler;
699 
700 	// this check is to trick the gcc4 compiler and have it keep the error label
701 	if (to == NULL && size > 0)
702 		goto error;
703 
704 	*faultHandler = (addr_t)&&error;
705 
706 	if (size > 0) {
707 		to[--size] = '\0';
708 		// copy
709 		for ( ; size; size--, fromLength++, to++, from++) {
710 			if ((*to = *from) == '\0')
711 				break;
712 		}
713 	}
714 	// count any leftover from chars
715 	while (*from++ != '\0') {
716 		fromLength++;
717 	}
718 
719 	*faultHandler = oldFaultHandler;
720 	return fromLength;
721 
722 error:
723 	*faultHandler = oldFaultHandler;
724 	return B_BAD_ADDRESS;
725 }
726 
727 
728 status_t
729 arch_cpu_user_memset(void *s, char c, size_t count, addr_t *faultHandler)
730 {
731 	char *xs = (char *)s;
732 	addr_t oldFaultHandler = *faultHandler;
733 
734 	// this check is to trick the gcc4 compiler and have it keep the error label
735 	if (s == NULL)
736 		goto error;
737 
738 	*faultHandler = (addr_t)&&error;
739 
740 	while (count--)
741 		*xs++ = c;
742 
743 	*faultHandler = oldFaultHandler;
744 	return 0;
745 
746 error:
747 	*faultHandler = oldFaultHandler;
748 	return B_BAD_ADDRESS;
749 }
750 
751 
752 status_t
753 arch_cpu_shutdown(bool rebootSystem)
754 {
755 	if (!rebootSystem) {
756 		status_t status = acpi_shutdown();
757 		if (status != B_OK)
758 			status = apm_shutdown();
759 
760 		return status;
761 	}
762 
763 	cpu_status state = disable_interrupts();
764 
765 	// try to reset the system using the keyboard controller
766 	out8(0xfe, 0x64);
767 
768 	// Give some time to the controller to do its job (0.5s)
769 	snooze(500000);
770 
771 	// if that didn't help, try it this way
772 	reboot();
773 
774 	restore_interrupts(state);
775 	return B_ERROR;
776 }
777 
778 
779 void
780 arch_cpu_idle(void)
781 {
782 	asm("hlt");
783 }
784 
785 
786 void
787 arch_cpu_sync_icache(void *address, size_t length)
788 {
789 	// instruction cache is always consistent on x86
790 }
791 
792 
793 void
794 arch_cpu_memory_read_barrier(void)
795 {
796 	asm volatile ("lock;" : : : "memory");
797 	asm volatile ("addl $0,0(%%esp);" : : : "memory");
798 }
799 
800 
801 void
802 arch_cpu_memory_write_barrier(void)
803 {
804 	asm volatile ("lock;" : : : "memory");
805 	asm volatile ("addl $0,0(%%esp);" : : : "memory");
806 }
807 
808