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
get_cpuid_for(cpuid_info * info,uint32 currentCPU,uint32 eaxRegister,uint32 forCPU)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
get_cpuid(cpuid_info * info,uint32 eaxRegister,uint32 forCPU)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
arch_system_info_init(struct kernel_args * args)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;
103*2e69f2b0SJérôme Duval if (cpu->arch.vendor == VENDOR_INTEL) {
104*2e69f2b0SJérôme Duval cpuid_info cpuid;
105*2e69f2b0SJérôme Duval get_current_cpuid(&cpuid, 0, 0);
106*2e69f2b0SJérôme Duval uint32 maxBasicLeaf = cpuid.eax_0.max_eax;
107*2e69f2b0SJérôme Duval if (maxBasicLeaf >= 0x16) {
108*2e69f2b0SJérôme Duval get_current_cpuid(&cpuid, 0x16, 0);
109*2e69f2b0SJérôme Duval if (cpuid.regs.eax != 0) {
110*2e69f2b0SJérôme Duval sCPUClockSpeed = cpuid.regs.eax * 1000000LL;
111*2e69f2b0SJérôme Duval dprintf("found clock speed with CPUID.16h\n");
112*2e69f2b0SJérôme Duval }
113*2e69f2b0SJérôme Duval }
114*2e69f2b0SJérôme Duval }
115bd185b41SIngo Weinhold return B_OK;
116bd185b41SIngo Weinhold }
117bd185b41SIngo Weinhold
118bd185b41SIngo Weinhold
1191bc7045fSPawel Dziepak void
arch_fill_topology_node(cpu_topology_node_info * node,int32 cpu)1201bc7045fSPawel Dziepak arch_fill_topology_node(cpu_topology_node_info* node, int32 cpu)
1211bc7045fSPawel Dziepak {
1221bc7045fSPawel Dziepak switch (node->type) {
1231bc7045fSPawel Dziepak case B_TOPOLOGY_ROOT:
1245ffbe7d7SAugustin Cavalier #if __i386__
1251bc7045fSPawel Dziepak node->data.root.platform = B_CPU_x86;
1261bc7045fSPawel Dziepak #elif __x86_64__
1271bc7045fSPawel Dziepak node->data.root.platform = B_CPU_x86_64;
1281bc7045fSPawel Dziepak #else
1291bc7045fSPawel Dziepak node->data.root.platform = B_CPU_UNKNOWN;
1301bc7045fSPawel Dziepak #endif
1311bc7045fSPawel Dziepak break;
1321bc7045fSPawel Dziepak
1331bc7045fSPawel Dziepak case B_TOPOLOGY_PACKAGE:
1341bc7045fSPawel Dziepak node->data.package.vendor = sCPUVendor;
1351bc7045fSPawel Dziepak node->data.package.cache_line_size = CACHE_LINE_SIZE;
1361bc7045fSPawel Dziepak break;
1371bc7045fSPawel Dziepak
1381bc7045fSPawel Dziepak case B_TOPOLOGY_CORE:
1391bc7045fSPawel Dziepak node->data.core.model = sCPUModel;
1401bc7045fSPawel Dziepak node->data.core.default_frequency = sCPUClockSpeed;
1411bc7045fSPawel Dziepak break;
1421bc7045fSPawel Dziepak
1431bc7045fSPawel Dziepak default:
1441bc7045fSPawel Dziepak break;
1451bc7045fSPawel Dziepak }
1461bc7045fSPawel Dziepak }
1471bc7045fSPawel Dziepak
1481bc7045fSPawel Dziepak
14922fdfc44SJérôme Duval static void
get_frequency_for(void * _frequency,int cpu)1504106e3f1SJérôme Duval get_frequency_for(void *_frequency, int cpu)
15122fdfc44SJérôme Duval {
15222fdfc44SJérôme Duval uint64 *frequency = (uint64*)_frequency;
15322fdfc44SJérôme Duval
1544106e3f1SJérôme Duval bigtime_t timestamp = gCPU[cpu].arch.perf_timestamp;
1554106e3f1SJérôme Duval bigtime_t timestamp2 = system_time();
1564106e3f1SJérôme Duval if (timestamp2 - timestamp < 100) {
1574106e3f1SJérôme Duval *frequency = gCPU[cpu].arch.frequency;
1584106e3f1SJérôme Duval return;
1594106e3f1SJérôme Duval }
16022fdfc44SJérôme Duval
1614106e3f1SJérôme Duval uint64 mperf = gCPU[cpu].arch.mperf_prev;
1624106e3f1SJérôme Duval uint64 aperf = gCPU[cpu].arch.aperf_prev;
16322fdfc44SJérôme Duval uint64 mperf2 = x86_read_msr(IA32_MSR_MPERF);
16422fdfc44SJérôme Duval uint64 aperf2 = x86_read_msr(IA32_MSR_APERF);
16522fdfc44SJérôme Duval
16622fdfc44SJérôme Duval if (mperf2 == mperf)
16722fdfc44SJérôme Duval *frequency = 0;
1684106e3f1SJérôme Duval else {
16922fdfc44SJérôme Duval *frequency = (aperf2 - aperf) * sCPUClockSpeed / (mperf2 - mperf);
1704106e3f1SJérôme Duval gCPU[cpu].arch.mperf_prev = mperf2;
1714106e3f1SJérôme Duval gCPU[cpu].arch.aperf_prev = aperf2;
1724106e3f1SJérôme Duval gCPU[cpu].arch.perf_timestamp = timestamp2;
1734106e3f1SJérôme Duval gCPU[cpu].arch.frequency = *frequency;
1744106e3f1SJérôme Duval }
17522fdfc44SJérôme Duval }
17622fdfc44SJérôme Duval
17722fdfc44SJérôme Duval
17822fdfc44SJérôme Duval status_t
arch_get_frequency(uint64 * frequency,int32 cpu)17922fdfc44SJérôme Duval arch_get_frequency(uint64 *frequency, int32 cpu)
18022fdfc44SJérôme Duval {
18122fdfc44SJérôme Duval if (x86_check_feature(IA32_FEATURE_APERFMPERF, FEATURE_6_ECX))
18222fdfc44SJérôme Duval call_single_cpu_sync(cpu, get_frequency_for, frequency);
18322fdfc44SJérôme Duval else
18422fdfc44SJérôme Duval *frequency = sCPUClockSpeed;
18522fdfc44SJérôme Duval
18622fdfc44SJérôme Duval return B_OK;
18722fdfc44SJérôme Duval }
18822fdfc44SJérôme Duval
18922fdfc44SJérôme Duval
190bd185b41SIngo Weinhold // #pragma mark -
191bd185b41SIngo Weinhold
192bd185b41SIngo Weinhold
193bd185b41SIngo Weinhold status_t
_user_get_cpuid(cpuid_info * userInfo,uint32 eaxRegister,uint32 cpuNum)194bd185b41SIngo Weinhold _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum)
195bd185b41SIngo Weinhold {
196bd185b41SIngo Weinhold cpuid_info info;
197bd185b41SIngo Weinhold status_t status;
198bd185b41SIngo Weinhold
199bd185b41SIngo Weinhold if (!IS_USER_ADDRESS(userInfo))
200bd185b41SIngo Weinhold return B_BAD_ADDRESS;
201bd185b41SIngo Weinhold
202bd185b41SIngo Weinhold status = get_cpuid(&info, eaxRegister, cpuNum);
203bd185b41SIngo Weinhold
204bd185b41SIngo Weinhold if (status == B_OK
205bd185b41SIngo Weinhold && user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK)
206bd185b41SIngo Weinhold return B_BAD_ADDRESS;
207bd185b41SIngo Weinhold
208bd185b41SIngo Weinhold return status;
209bd185b41SIngo Weinhold }
2101bc7045fSPawel Dziepak
211