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, ¶meter); 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