1bd185b41SIngo Weinhold /* 2bd185b41SIngo Weinhold * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3bd185b41SIngo Weinhold * Distributed under the terms of the MIT License. 4bd185b41SIngo Weinhold */ 5bd185b41SIngo Weinhold 6bd185b41SIngo Weinhold 7bd185b41SIngo Weinhold #include <arch/system_info.h> 8bd185b41SIngo Weinhold 9bd185b41SIngo Weinhold #include <string.h> 10bd185b41SIngo Weinhold 11bd185b41SIngo Weinhold #include <KernelExport.h> 12bd185b41SIngo Weinhold #include <OS.h> 13bd185b41SIngo Weinhold 14bd185b41SIngo Weinhold #include <boot/kernel_args.h> 15bd185b41SIngo Weinhold #include <cpu.h> 16bd185b41SIngo Weinhold #include <kernel.h> 17bd185b41SIngo Weinhold #include <smp.h> 18bd185b41SIngo Weinhold 19bd185b41SIngo Weinhold 201bc7045fSPawel Dziepak enum cpu_vendor sCPUVendor; 211bc7045fSPawel Dziepak uint32 sCPUModel; 221bc7045fSPawel Dziepak int64 sCPUClockSpeed; 23bd185b41SIngo Weinhold 24bd185b41SIngo Weinhold 25bd185b41SIngo Weinhold static bool 26bd185b41SIngo Weinhold get_cpuid_for(cpuid_info *info, uint32 currentCPU, uint32 eaxRegister, 27bd185b41SIngo Weinhold uint32 forCPU) 28bd185b41SIngo Weinhold { 29bd185b41SIngo Weinhold if (currentCPU != forCPU) 30bd185b41SIngo Weinhold return false; 31bd185b41SIngo Weinhold 324110b730SPawel Dziepak get_current_cpuid(info, eaxRegister, 0); 33bd185b41SIngo Weinhold return true; 34bd185b41SIngo Weinhold } 35bd185b41SIngo Weinhold 36bd185b41SIngo Weinhold 37bd185b41SIngo Weinhold status_t 38bd185b41SIngo Weinhold get_cpuid(cpuid_info *info, uint32 eaxRegister, uint32 forCPU) 39bd185b41SIngo Weinhold { 40bd185b41SIngo Weinhold uint32 numCPUs = (uint32)smp_get_num_cpus(); 41bd185b41SIngo Weinhold cpu_status state; 42bd185b41SIngo Weinhold 43bd185b41SIngo Weinhold if (forCPU >= numCPUs) 44bd185b41SIngo Weinhold return B_BAD_VALUE; 45bd185b41SIngo Weinhold 46bd185b41SIngo Weinhold // prevent us from being rescheduled 47bd185b41SIngo Weinhold state = disable_interrupts(); 48bd185b41SIngo Weinhold 49bd185b41SIngo Weinhold // ToDo: as long as we only run on pentium-class systems, we can assume 50bd185b41SIngo Weinhold // that the CPU supports cpuid. 51bd185b41SIngo Weinhold 52bd185b41SIngo Weinhold if (!get_cpuid_for(info, smp_get_current_cpu(), eaxRegister, forCPU)) { 5311d3892dSAlex Smith smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (addr_t)info, 54bd185b41SIngo Weinhold eaxRegister, forCPU, (void *)get_cpuid_for, SMP_MSG_FLAG_SYNC); 55bd185b41SIngo Weinhold } 56bd185b41SIngo Weinhold 57bd185b41SIngo Weinhold restore_interrupts(state); 58bd185b41SIngo Weinhold return B_OK; 59bd185b41SIngo Weinhold } 60bd185b41SIngo Weinhold 61bd185b41SIngo Weinhold 62bd185b41SIngo Weinhold status_t 63bd185b41SIngo Weinhold arch_system_info_init(struct kernel_args *args) 64bd185b41SIngo Weinhold { 651bc7045fSPawel Dziepak // So far we don't have to care about heterogeneous x86 platforms. 66bd185b41SIngo Weinhold cpu_ent* cpu = get_cpu_struct(); 67bd185b41SIngo Weinhold 68bd185b41SIngo Weinhold switch (cpu->arch.vendor) { 69bd185b41SIngo Weinhold case VENDOR_AMD: 701bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_AMD; 71bd185b41SIngo Weinhold break; 72bd185b41SIngo Weinhold case VENDOR_CENTAUR: 731bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_VIA; 74bd185b41SIngo Weinhold break; 751bc7045fSPawel Dziepak case VENDOR_CYRIX: 761bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_CYRIX; 77bd185b41SIngo Weinhold break; 781bc7045fSPawel Dziepak case VENDOR_INTEL: 791bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_INTEL; 80bd185b41SIngo Weinhold break; 81bd185b41SIngo Weinhold case VENDOR_NSC: 821bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_NATIONAL_SEMICONDUCTOR; 831bc7045fSPawel Dziepak break; 841bc7045fSPawel Dziepak case VENDOR_RISE: 851bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_RISE; 861bc7045fSPawel Dziepak break; 871bc7045fSPawel Dziepak case VENDOR_TRANSMETA: 881bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_TRANSMETA; 89bd185b41SIngo Weinhold break; 90357b9d3cSJérôme Duval case VENDOR_HYGON: 91357b9d3cSJérôme Duval sCPUVendor = B_CPU_VENDOR_HYGON; 92357b9d3cSJérôme Duval break; 93bd185b41SIngo Weinhold default: 941bc7045fSPawel Dziepak sCPUVendor = B_CPU_VENDOR_UNKNOWN; 951bc7045fSPawel Dziepak break; 96bd185b41SIngo Weinhold } 97bd185b41SIngo Weinhold 981bc7045fSPawel Dziepak sCPUModel = (cpu->arch.extended_family << 20) 991bc7045fSPawel Dziepak | (cpu->arch.extended_model << 16) | (cpu->arch.type << 12) 100bd185b41SIngo Weinhold | (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping; 101bd185b41SIngo Weinhold 1021bc7045fSPawel Dziepak sCPUClockSpeed = args->arch_args.cpu_clock_speed; 103bd185b41SIngo Weinhold return B_OK; 104bd185b41SIngo Weinhold } 105bd185b41SIngo Weinhold 106bd185b41SIngo Weinhold 1071bc7045fSPawel Dziepak void 1081bc7045fSPawel Dziepak arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu) 1091bc7045fSPawel Dziepak { 1101bc7045fSPawel Dziepak switch (node->type) { 1111bc7045fSPawel Dziepak case B_TOPOLOGY_ROOT: 1125ffbe7d7SAugustin Cavalier #if __i386__ 1131bc7045fSPawel Dziepak node->data.root.platform = B_CPU_x86; 1141bc7045fSPawel Dziepak #elif __x86_64__ 1151bc7045fSPawel Dziepak node->data.root.platform = B_CPU_x86_64; 1161bc7045fSPawel Dziepak #else 1171bc7045fSPawel Dziepak node->data.root.platform = B_CPU_UNKNOWN; 1181bc7045fSPawel Dziepak #endif 1191bc7045fSPawel Dziepak break; 1201bc7045fSPawel Dziepak 1211bc7045fSPawel Dziepak case B_TOPOLOGY_PACKAGE: 1221bc7045fSPawel Dziepak node->data.package.vendor = sCPUVendor; 1231bc7045fSPawel Dziepak node->data.package.cache_line_size = CACHE_LINE_SIZE; 1241bc7045fSPawel Dziepak break; 1251bc7045fSPawel Dziepak 1261bc7045fSPawel Dziepak case B_TOPOLOGY_CORE: 1271bc7045fSPawel Dziepak node->data.core.model = sCPUModel; 1281bc7045fSPawel Dziepak node->data.core.default_frequency = sCPUClockSpeed; 1291bc7045fSPawel Dziepak break; 1301bc7045fSPawel Dziepak 1311bc7045fSPawel Dziepak default: 1321bc7045fSPawel Dziepak break; 1331bc7045fSPawel Dziepak } 1341bc7045fSPawel Dziepak } 1351bc7045fSPawel Dziepak 1361bc7045fSPawel Dziepak 13722fdfc44SJérôme Duval static void 138*4106e3f1SJérôme Duval get_frequency_for(void *_frequency, int cpu) 13922fdfc44SJérôme Duval { 14022fdfc44SJérôme Duval uint64 *frequency = (uint64*)_frequency; 14122fdfc44SJérôme Duval 142*4106e3f1SJérôme Duval bigtime_t timestamp = gCPU[cpu].arch.perf_timestamp; 143*4106e3f1SJérôme Duval bigtime_t timestamp2 = system_time(); 144*4106e3f1SJérôme Duval if (timestamp2 - timestamp < 100) { 145*4106e3f1SJérôme Duval *frequency = gCPU[cpu].arch.frequency; 146*4106e3f1SJérôme Duval return; 147*4106e3f1SJérôme Duval } 14822fdfc44SJérôme Duval 149*4106e3f1SJérôme Duval uint64 mperf = gCPU[cpu].arch.mperf_prev; 150*4106e3f1SJérôme Duval uint64 aperf = gCPU[cpu].arch.aperf_prev; 15122fdfc44SJérôme Duval uint64 mperf2 = x86_read_msr(IA32_MSR_MPERF); 15222fdfc44SJérôme Duval uint64 aperf2 = x86_read_msr(IA32_MSR_APERF); 15322fdfc44SJérôme Duval 15422fdfc44SJérôme Duval if (mperf2 == mperf) 15522fdfc44SJérôme Duval *frequency = 0; 156*4106e3f1SJérôme Duval else { 15722fdfc44SJérôme Duval *frequency = (aperf2 - aperf) * sCPUClockSpeed / (mperf2 - mperf); 158*4106e3f1SJérôme Duval gCPU[cpu].arch.mperf_prev = mperf2; 159*4106e3f1SJérôme Duval gCPU[cpu].arch.aperf_prev = aperf2; 160*4106e3f1SJérôme Duval gCPU[cpu].arch.perf_timestamp = timestamp2; 161*4106e3f1SJérôme Duval gCPU[cpu].arch.frequency = *frequency; 162*4106e3f1SJérôme Duval } 16322fdfc44SJérôme Duval } 16422fdfc44SJérôme Duval 16522fdfc44SJérôme Duval 16622fdfc44SJérôme Duval status_t 16722fdfc44SJérôme Duval arch_get_frequency(uint64 *frequency, int32 cpu) 16822fdfc44SJérôme Duval { 16922fdfc44SJérôme Duval if (x86_check_feature(IA32_FEATURE_APERFMPERF, FEATURE_6_ECX)) 17022fdfc44SJérôme Duval call_single_cpu_sync(cpu, get_frequency_for, frequency); 17122fdfc44SJérôme Duval else 17222fdfc44SJérôme Duval *frequency = sCPUClockSpeed; 17322fdfc44SJérôme Duval 17422fdfc44SJérôme Duval return B_OK; 17522fdfc44SJérôme Duval } 17622fdfc44SJérôme Duval 17722fdfc44SJérôme Duval 178bd185b41SIngo Weinhold // #pragma mark - 179bd185b41SIngo Weinhold 180bd185b41SIngo Weinhold 181bd185b41SIngo Weinhold status_t 182bd185b41SIngo Weinhold _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum) 183bd185b41SIngo Weinhold { 184bd185b41SIngo Weinhold cpuid_info info; 185bd185b41SIngo Weinhold status_t status; 186bd185b41SIngo Weinhold 187bd185b41SIngo Weinhold if (!IS_USER_ADDRESS(userInfo)) 188bd185b41SIngo Weinhold return B_BAD_ADDRESS; 189bd185b41SIngo Weinhold 190bd185b41SIngo Weinhold status = get_cpuid(&info, eaxRegister, cpuNum); 191bd185b41SIngo Weinhold 192bd185b41SIngo Weinhold if (status == B_OK 193bd185b41SIngo Weinhold && user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK) 194bd185b41SIngo Weinhold return B_BAD_ADDRESS; 195bd185b41SIngo Weinhold 196bd185b41SIngo Weinhold return status; 197bd185b41SIngo Weinhold } 1981bc7045fSPawel Dziepak 199