1/* 2 * Copyright (c) 2015 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <cpuid_internal.h> 11 12/* 13 * =============================================================================== 14 * library internal, global variables 15 * =============================================================================== 16 */ 17 18///< maximum input value for basic CPUID information 19uint32_t cpuid_g_max_input_basic = 0; 20 21///< maximum input value for extended CPUID information 22uint32_t cpuid_g_max_input_extended = 0; 23 24///< the vendor of the core this code is executed 25cpuid_vendor_t cpuid_g_vendor = CPUID_VENDOR_UNKNOWN; 26 27///< function pointer table for vendor specific handlers 28struct cpuid_functions cpuid_fn; 29 30///< cpu cache names in readable representation 31char *cpuid_cache_names[4][4] = { 32 {""}, 33 {"", "l1i","l1d","l1"}, 34 {"", "l2i","l2d","l2"}, 35 {"", "l3i","l3d","l3"} 36}; 37 38/* 39 * =============================================================================== 40 * library initialization 41 * =============================================================================== 42 */ 43 44/** 45 * \brief initializes the cpuid library to handle vendor specific stuff 46 */ 47errval_t cpuid_init(void) 48{ 49 cpuid_g_vendor = cpuid_vendor(); 50 51 assert(cpuid_fn.proc_max_input_basic); 52 cpuid_g_max_input_basic = cpuid_fn.proc_max_input_basic(); 53 cpuid_g_max_input_extended = cpuid_fn.proc_max_input_extended(); 54 55 CPUID_PRINTF("initializing for %s CPU. Max input = [0x%08" PRIx32 " / 0x%08" 56 PRIx32"]\n", cpuid_vendor_string(), cpuid_g_max_input_basic, 57 cpuid_g_max_input_extended); 58 59 return SYS_ERR_OK; 60} 61 62 63/* 64 * =============================================================================== 65 * vendor information 66 * =============================================================================== 67 */ 68 69/** 70 * \brief reads the CPU vendor string and returns the vendor information 71 * 72 * \return CPU vendor information CPUID_VENDOR_* 73 * 74 * This function also updates the function table pointer based on the read values 75 */ 76cpuid_vendor_t cpuid_vendor(void) 77{ 78 if (cpuid_intel_check_vendor()) { 79 cpuid_intel_set_handlers(&cpuid_fn); 80 return CPUID_VENDOR_INTEL; 81 } else if (cpuid_amd_check_vendor()) { 82 cpuid_amd_set_handlers(&cpuid_fn); 83 return CPUID_VENDOR_AMD; 84 } 85 return CPUID_VENDOR_UNKNOWN; 86} 87 88/** 89 * \brief returns a string representation of the vendor 90 * 91 * \return string representation of the vendor 92 */ 93char *cpuid_vendor_string(void) 94{ 95 switch(cpuid_g_vendor) { 96 case CPUID_VENDOR_AMD : 97 return "amd"; 98 break; 99 case CPUID_VENDOR_INTEL : 100 return "intel"; 101 break; 102 default: 103 return "unknown"; 104 } 105} 106 107 108/* 109 * =============================================================================== 110 * basic processor information 111 * =============================================================================== 112 */ 113 114/** 115 * \brief obtains the family information from the CPU 116 * 117 * \param memory to fill in the family information 118 */ 119errval_t cpuid_proc_family(struct cpuid_proc_family *fmly) 120{ 121 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 122 return CPUID_ERR_UNKNOWN_VENDOR; 123 } 124 assert(cpuid_fn.proc_family); 125 126 return cpuid_fn.proc_family(fmly); 127} 128 129/** 130 * \brief obtains the processor name 131 * 132 * \param buf buffer where to store the processor name string 133 * \param len length of the buffer 134 */ 135errval_t cpuid_proc_name(char *buf, size_t len) 136{ 137 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 138 return CPUID_ERR_UNKNOWN_VENDOR; 139 } 140 assert(cpuid_fn.proc_name); 141 142 return cpuid_fn.proc_name(buf, len); 143} 144 145/** 146 * \brief returns the maximum input value for basic CPUID functions 147 * 148 * \return integer representing the maximum input 149 */ 150uint32_t cpuid_proc_max_input_basic(void) 151{ 152 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 153 return 0; 154 } 155 cpuid_g_max_input_basic = cpuid_fn.proc_max_input_basic(); 156 157 return cpuid_g_max_input_basic; 158} 159 160/** 161 * \brief returns the maximum input value for extended CPUID functions 162 * 163 * \return integer representing the maximum input 164 */ 165uint32_t cpuid_proc_max_input_extended(void) 166{ 167 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 168 return 0; 169 } 170 cpuid_g_max_input_extended = cpuid_fn.proc_max_input_extended(); 171 172 return cpuid_g_max_input_extended; 173} 174 175/** 176 * \brief obtains the processor frequency information 177 * 178 * \param fi returned frequency information 179 * 180 * \returns SYS_ERR_OK on success 181 * CPUID_ERR_*on failure 182 */ 183errval_t cpuid_frequency_info(struct cpuid_freqinfo *fi) 184{ 185 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 186 return 0; 187 } 188 assert(cpuid_fn.frequency_info); 189 190 return cpuid_fn.frequency_info(fi); 191} 192 193/* 194 * =============================================================================== 195 * cache topology information 196 * =============================================================================== 197 */ 198 199/** 200 * \brief calculates the system coherency size (cacheline size) 201 * 202 * \returns the coherency size of the core in bytes 203 */ 204uint16_t cpuid_system_coherency_size(void) 205{ 206 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 207 return CPUID_ERR_UNKNOWN_VENDOR; 208 } 209 assert(cpuid_fn.cache_line_size); 210 211 return cpuid_fn.cache_line_size(); 212} 213 214/** 215 * \brief obtains cache parameters for a given index 216 * 217 * \param ci memory to be filled in with information 218 * \param idx index of the cache to obtain information for 219 * 220 * \return SYS_ERR_OK on success 221 * CPUID_ERR_NO_SUCH_INDEX if there is no cache associated with the index 222 */ 223errval_t cpuid_cache_info(struct cpuid_cacheinfo *ci, uint32_t idx) 224{ 225 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 226 return CPUID_ERR_UNKNOWN_VENDOR; 227 } 228 assert(cpuid_fn.cache_info); 229 230 return cpuid_fn.cache_info(ci, idx); 231} 232 233/** 234 * \brief returns a string representation of the cache type 235 * 236 * \param ct type of the cache 237 * 238 * \return cache name string 239 */ 240char *cpuid_cache_type_string(cpuid_cachetype_t ct) 241{ 242 switch(ct) { 243 case CPUID_CACHE_TYPE_DATA: 244 return "data"; 245 break; 246 case CPUID_CACHE_TYPE_INSTR: 247 return "instr"; 248 break; 249 case CPUID_CACHE_TYPE_UNIFIED: 250 return "unified"; 251 break; 252 default: 253 return "invalid"; 254 break; 255 } 256} 257 258 259/* 260 * =============================================================================== 261 * TLB information 262 * =============================================================================== 263 */ 264 265/** 266 * \brief obtains the TLB topology information 267 * 268 * \param ti 269 * \param idx 270 * 271 * \returns SYS_ERR_OK on success 272 * CPUID_ERR_* on failure 273 */ 274errval_t cpuid_tlb_info(struct cpuid_tlbinfo *ti, uint32_t idx) 275{ 276 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 277 return CPUID_ERR_UNKNOWN_VENDOR; 278 } 279 assert(cpuid_fn.tlb_info); 280 281 return cpuid_fn.tlb_info(ti, idx); 282} 283 284/* 285 * =============================================================================== 286 * thread and topology information 287 * =============================================================================== 288 */ 289 290 291/** 292 * \brief obtains the topology information for a given thread 293 * 294 * \param ti returns the thread information 295 * 296 * \return SYS_ERR_OK on success 297 * CPUID_ERR_* on failure 298 */ 299errval_t cpuid_thread_info(struct cpuid_threadinfo *ti) 300{ 301 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 302 return CPUID_ERR_UNKNOWN_VENDOR; 303 } 304 assert(cpuid_fn.thread_info); 305 306 return cpuid_fn.thread_info(ti); 307} 308 309/** 310 * \brief obtains topology information from the CPU 311 * 312 * \param topo pointer to store the information 313 * \param idx topology level index 314 * 315 * \return SYS_ERR_OK on success 316 * CPUID_ERR_* on failure 317 */ 318errval_t cpuid_topology_info(struct cpuid_topologyinfo *topo, uint8_t idx) 319{ 320 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 321 return CPUID_ERR_UNKNOWN_VENDOR; 322 } 323 assert(cpuid_fn.topology_info); 324 325 return cpuid_fn.topology_info(topo, idx); 326} 327 328 329/* 330 * =============================================================================== 331 * feature information 332 * =============================================================================== 333 */ 334/** 335 * \brief obtains the CPU's feature information 336 * 337 * \param fi structure to be filled in 338 * 339 * \return SYS_ERR_OK on success 340 * CPUID_ERR_* on failure 341 */ 342errval_t cpuid_feature_info(struct cpuid_featureinfo *fi) 343{ 344 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 345 return CPUID_ERR_UNKNOWN_VENDOR; 346 } 347 assert(cpuid_fn.feature_info); 348 349 return cpuid_fn.feature_info(fi); 350} 351 352 353/* 354 * =============================================================================== 355 * address space information 356 * =============================================================================== 357 */ 358 359/** 360 * \brief obtains the address space size information of the CPU 361 * 362 * \param ai struct to be filled in with adderss space information 363 * 364 * \returns SYS_ERR_OK on susccess 365 * CPUID_ERR_* on failure 366 */ 367errval_t cpuid_address_space_info(struct cpuid_adressspaceinfo *ai) 368{ 369 if (cpuid_g_vendor == CPUID_VENDOR_UNKNOWN) { 370 return CPUID_ERR_UNKNOWN_VENDOR; 371 } 372 assert(cpuid_fn.address_space_info); 373 374 return cpuid_fn.address_space_info(ai); 375} 376