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, (uint32)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 info->platform_type = B_AT_CLONE_PLATFORM; 72 73 // ToDo: clock speeds could be retrieved via SMBIOS/DMI 74 return B_OK; 75 } 76 77 78 status_t 79 arch_system_info_init(struct kernel_args *args) 80 { 81 // This is what you get if the CPU vendor is not recognized 82 // or the CPU does not support cpuid with eax == 1. 83 uint32 base; 84 uint32 model = 0; 85 cpu_ent *cpu = get_cpu_struct(); 86 87 switch (cpu->arch.vendor) { 88 case VENDOR_INTEL: 89 base = B_CPU_INTEL_x86; 90 break; 91 case VENDOR_AMD: 92 base = B_CPU_AMD_x86; 93 break; 94 case VENDOR_CYRIX: 95 base = B_CPU_CYRIX_x86; 96 break; 97 case VENDOR_UMC: 98 base = B_CPU_INTEL_x86; // XXX 99 break; 100 case VENDOR_NEXGEN: 101 base = B_CPU_INTEL_x86; // XXX 102 break; 103 case VENDOR_CENTAUR: 104 base = B_CPU_VIA_IDT_x86; 105 break; 106 case VENDOR_RISE: 107 base = B_CPU_RISE_x86; 108 break; 109 case VENDOR_TRANSMETA: 110 base = B_CPU_TRANSMETA_x86; 111 break; 112 case VENDOR_NSC: 113 base = B_CPU_NATIONAL_x86; 114 break; 115 default: 116 base = B_CPU_x86; 117 } 118 119 if (base != B_CPU_x86) { 120 if (base == B_CPU_INTEL_x86 121 || (base == B_CPU_AMD_x86 && cpu->arch.family == 0xF)) { 122 model = (cpu->arch.extended_family << 20) 123 + (cpu->arch.extended_model << 16) 124 + (cpu->arch.family << 4) + cpu->arch.model; 125 } else { 126 model = (cpu->arch.family << 4) 127 + cpu->arch.model; 128 // Isn't much useful extended family and model information 129 // yet on other processors. 130 } 131 } 132 133 sCpuRevision = (cpu->arch.extended_family << 18) 134 | (cpu->arch.extended_model << 14) | (cpu->arch.type << 12) 135 | (cpu->arch.family << 8) | (cpu->arch.model << 4) | cpu->arch.stepping; 136 137 sCpuType = base + model; 138 sCpuClockSpeed = args->arch_args.cpu_clock_speed; 139 return B_OK; 140 } 141 142 143 // #pragma mark - 144 145 146 status_t 147 _user_get_cpuid(cpuid_info *userInfo, uint32 eaxRegister, uint32 cpuNum) 148 { 149 cpuid_info info; 150 status_t status; 151 152 if (!IS_USER_ADDRESS(userInfo)) 153 return B_BAD_ADDRESS; 154 155 status = get_cpuid(&info, eaxRegister, cpuNum); 156 157 if (status == B_OK 158 && user_memcpy(userInfo, &info, sizeof(cpuid_info)) < B_OK) 159 return B_BAD_ADDRESS; 160 161 return status; 162 } 163