1 /* 2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <arch/system_info.h> 8 9 #include <string.h> 10 11 #include <KernelExport.h> 12 #include <OS.h> 13 14 #include <boot/kernel_args.h> 15 #include <cpu.h> 16 #include <kernel.h> 17 #include <smp.h> 18 19 20 uint32 sCpuType; 21 int32 sCpuRevision; 22 int64 sCpuClockSpeed; 23 24 25 static bool 26 get_cpuid_for(cpuid_info *info, uint32 currentCPU, uint32 eaxRegister, 27 uint32 forCPU) 28 { 29 if (currentCPU != forCPU) 30 return false; 31 32 get_current_cpuid(info, eaxRegister); 33 return true; 34 } 35 36 37 status_t 38 get_cpuid(cpuid_info *info, uint32 eaxRegister, uint32 forCPU) 39 { 40 uint32 numCPUs = (uint32)smp_get_num_cpus(); 41 cpu_status state; 42 43 if (forCPU >= numCPUs) 44 return B_BAD_VALUE; 45 46 // prevent us from being rescheduled 47 state = disable_interrupts(); 48 49 // ToDo: as long as we only run on pentium-class systems, we can assume 50 // that the CPU supports cpuid. 51 52 if (!get_cpuid_for(info, smp_get_current_cpu(), eaxRegister, forCPU)) { 53 smp_send_broadcast_ici(SMP_MSG_CALL_FUNCTION, (addr_t)info, 54 eaxRegister, forCPU, (void *)get_cpuid_for, SMP_MSG_FLAG_SYNC); 55 } 56 57 restore_interrupts(state); 58 return B_OK; 59 } 60 61 62 status_t 63 arch_get_system_info(system_info *info, size_t size) 64 { 65 info->cpu_type = (cpu_types)sCpuType; 66 info->cpu_revision = sCpuRevision; 67 68 // - various cpu_info 69 info->cpu_clock_speed = sCpuClockSpeed; 70 // - bus_clock_speed 71 #ifdef __x86_64__ 72 info->platform_type = B_64_BIT_PC_PLATFORM; 73 #else 74 info->platform_type = B_AT_CLONE_PLATFORM; 75 #endif 76 77 // ToDo: clock speeds could be retrieved via SMBIOS/DMI 78 return B_OK; 79 } 80 81 82 status_t 83 arch_system_info_init(struct kernel_args *args) 84 { 85 // This is what you get if the CPU vendor is not recognized 86 // or the CPU does not support cpuid with eax == 1. 87 uint32 base; 88 uint32 model = 0; 89 cpu_ent *cpu = get_cpu_struct(); 90 91 switch (cpu->arch.vendor) { 92 case VENDOR_INTEL: 93 base = B_CPU_INTEL_x86; 94 break; 95 case VENDOR_AMD: 96 base = B_CPU_AMD_x86; 97 break; 98 case VENDOR_CYRIX: 99 base = B_CPU_CYRIX_x86; 100 break; 101 case VENDOR_UMC: 102 base = B_CPU_INTEL_x86; // XXX 103 break; 104 case VENDOR_NEXGEN: 105 base = B_CPU_INTEL_x86; // XXX 106 break; 107 case VENDOR_CENTAUR: 108 base = B_CPU_VIA_IDT_x86; 109 break; 110 case VENDOR_RISE: 111 base = B_CPU_RISE_x86; 112 break; 113 case VENDOR_TRANSMETA: 114 base = B_CPU_TRANSMETA_x86; 115 break; 116 case VENDOR_NSC: 117 base = B_CPU_NATIONAL_x86; 118 break; 119 default: 120 base = B_CPU_x86; 121 } 122 123 if (base != B_CPU_x86) { 124 if (base == B_CPU_INTEL_x86 125 || (base == B_CPU_AMD_x86 && cpu->arch.family == 0xF)) { 126 model = (cpu->arch.extended_family << 20) 127 + (cpu->arch.extended_model << 16) 128 + (cpu->arch.family << 4) + cpu->arch.model; 129 } else { 130 model = (cpu->arch.family << 4) 131 + cpu->arch.model; 132 // Isn't much useful extended family and model information 133 // yet on other processors. 134 } 135 } 136 137 sCpuRevision = (cpu->arch.extended_family << 18) 138 | (cpu->arch.extended_model << 14) | (cpu->arch.type << 12) 139 | (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping; 140 141 sCpuType = base + model; 142 sCpuClockSpeed = args->arch_args.cpu_clock_speed; 143 return B_OK; 144 } 145 146 147 // #pragma mark - 148 149 150 status_t 151 _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum) 152 { 153 cpuid_info info; 154 status_t status; 155 156 if (!IS_USER_ADDRESS(userInfo)) 157 return B_BAD_ADDRESS; 158 159 status = get_cpuid(&info, eaxRegister, cpuNum); 160 161 if (status == B_OK 162 && user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK) 163 return B_BAD_ADDRESS; 164 165 return status; 166 } 167