1 /* 2 * Copyright (c) 2013-2019, Intel Corporation 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * * Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * * Neither the name of Intel Corporation nor the names of its contributors 13 * may be used to endorse or promote products derived from this software 14 * without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "pt_cpu.h" 30 #include "pt_cpuid.h" 31 32 #include "intel-pt.h" 33 34 #include <limits.h> 35 #include <stdlib.h> 36 37 38 static const char * const cpu_vendors[] = { 39 "", 40 "GenuineIntel" 41 }; 42 43 enum { 44 pt_cpuid_vendor_size = 12 45 }; 46 47 union cpu_vendor { 48 /* The raw data returned from cpuid. */ 49 struct { 50 uint32_t ebx; 51 uint32_t edx; 52 uint32_t ecx; 53 } cpuid; 54 55 /* The resulting vendor string. */ 56 char vendor_string[pt_cpuid_vendor_size]; 57 }; 58 59 static enum pt_cpu_vendor cpu_vendor(void) 60 { 61 union cpu_vendor vendor; 62 uint32_t eax; 63 size_t i; 64 65 memset(&vendor, 0, sizeof(vendor)); 66 eax = 0; 67 68 pt_cpuid(0u, &eax, &vendor.cpuid.ebx, &vendor.cpuid.ecx, 69 &vendor.cpuid.edx); 70 71 for (i = 0; i < sizeof(cpu_vendors)/sizeof(*cpu_vendors); i++) 72 if (strncmp(vendor.vendor_string, 73 cpu_vendors[i], pt_cpuid_vendor_size) == 0) 74 return (enum pt_cpu_vendor) i; 75 76 return pcv_unknown; 77 } 78 79 static uint32_t cpu_info(void) 80 { 81 uint32_t eax, ebx, ecx, edx; 82 83 eax = 0; 84 ebx = 0; 85 ecx = 0; 86 edx = 0; 87 pt_cpuid(1u, &eax, &ebx, &ecx, &edx); 88 89 return eax; 90 } 91 92 int pt_cpu_parse(struct pt_cpu *cpu, const char *s) 93 { 94 const char sep = '/'; 95 char *endptr; 96 long family, model, stepping; 97 98 if (!cpu || !s) 99 return -pte_invalid; 100 101 family = strtol(s, &endptr, 0); 102 if (s == endptr || *endptr == '\0' || *endptr != sep) 103 return -pte_invalid; 104 105 if (family < 0 || family > USHRT_MAX) 106 return -pte_invalid; 107 108 /* skip separator */ 109 s = endptr + 1; 110 111 model = strtol(s, &endptr, 0); 112 if (s == endptr || (*endptr != '\0' && *endptr != sep)) 113 return -pte_invalid; 114 115 if (model < 0 || model > UCHAR_MAX) 116 return -pte_invalid; 117 118 if (*endptr == '\0') 119 /* stepping was omitted, it defaults to 0 */ 120 stepping = 0; 121 else { 122 /* skip separator */ 123 s = endptr + 1; 124 125 stepping = strtol(s, &endptr, 0); 126 if (*endptr != '\0') 127 return -pte_invalid; 128 129 if (stepping < 0 || stepping > UCHAR_MAX) 130 return -pte_invalid; 131 } 132 133 cpu->vendor = pcv_intel; 134 cpu->family = (uint16_t) family; 135 cpu->model = (uint8_t) model; 136 cpu->stepping = (uint8_t) stepping; 137 138 return 0; 139 } 140 141 int pt_cpu_read(struct pt_cpu *cpu) 142 { 143 uint32_t info; 144 uint16_t family; 145 146 if (!cpu) 147 return -pte_invalid; 148 149 cpu->vendor = cpu_vendor(); 150 151 info = cpu_info(); 152 153 cpu->family = family = (info>>8) & 0xf; 154 if (family == 0xf) 155 cpu->family += (info>>20) & 0xf; 156 157 cpu->model = (info>>4) & 0xf; 158 if (family == 0x6 || family == 0xf) 159 cpu->model += (info>>12) & 0xf0; 160 161 cpu->stepping = (info>>0) & 0xf; 162 163 return 0; 164 } 165