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_config.h" 30 #include "pt_opcodes.h" 31 32 #include "intel-pt.h" 33 34 #include <string.h> 35 #include <stddef.h> 36 37 38 int pt_cpu_errata(struct pt_errata *errata, const struct pt_cpu *cpu) 39 { 40 if (!errata || !cpu) 41 return -pte_invalid; 42 43 memset(errata, 0, sizeof(*errata)); 44 45 /* We don't know about others. */ 46 if (cpu->vendor != pcv_intel) 47 return -pte_bad_cpu; 48 49 switch (cpu->family) { 50 case 0x6: 51 switch (cpu->model) { 52 case 0x3d: 53 case 0x47: 54 case 0x4f: 55 case 0x56: 56 errata->bdm70 = 1; 57 errata->bdm64 = 1; 58 return 0; 59 60 case 0x4e: 61 case 0x5e: 62 case 0x8e: 63 case 0x9e: 64 errata->bdm70 = 1; 65 errata->skd007 = 1; 66 errata->skd022 = 1; 67 errata->skd010 = 1; 68 errata->skl014 = 1; 69 errata->skl168 = 1; 70 return 0; 71 72 case 0x55: 73 case 0x66: 74 case 0x7d: 75 case 0x7e: 76 errata->bdm70 = 1; 77 errata->skl014 = 1; 78 errata->skd022 = 1; 79 return 0; 80 81 case 0x5c: 82 case 0x5f: 83 errata->apl12 = 1; 84 errata->apl11 = 1; 85 return 0; 86 87 case 0x7a: 88 case 0x86: 89 errata->apl11 = 1; 90 return 0; 91 } 92 break; 93 } 94 95 return -pte_bad_cpu; 96 } 97 98 int pt_config_from_user(struct pt_config *config, 99 const struct pt_config *uconfig) 100 { 101 uint8_t *begin, *end; 102 size_t size; 103 104 if (!config) 105 return -pte_internal; 106 107 if (!uconfig) 108 return -pte_invalid; 109 110 size = uconfig->size; 111 if (size < offsetof(struct pt_config, decode)) 112 return -pte_bad_config; 113 114 begin = uconfig->begin; 115 end = uconfig->end; 116 117 if (!begin || !end || end < begin) 118 return -pte_bad_config; 119 120 /* Ignore fields in the user's configuration we don't know; zero out 121 * fields the user didn't know about. 122 */ 123 if (sizeof(*config) <= size) 124 size = sizeof(*config); 125 else 126 memset(((uint8_t *) config) + size, 0, sizeof(*config) - size); 127 128 /* Copy (portions of) the user's configuration. */ 129 memcpy(config, uconfig, size); 130 131 /* We copied user's size - fix it. */ 132 config->size = size; 133 134 return 0; 135 } 136 137 /* The maximum number of filter addresses that fit into the configuration. */ 138 static inline size_t pt_filter_addr_ncfg(void) 139 { 140 return (sizeof(struct pt_conf_addr_filter) - 141 offsetof(struct pt_conf_addr_filter, addr0_a)) / 142 (2 * sizeof(uint64_t)); 143 } 144 145 uint32_t pt_filter_addr_cfg(const struct pt_conf_addr_filter *filter, uint8_t n) 146 { 147 if (!filter) 148 return 0u; 149 150 if (pt_filter_addr_ncfg() <= n) 151 return 0u; 152 153 return (filter->config.addr_cfg >> (4 * n)) & 0xf; 154 } 155 156 uint64_t pt_filter_addr_a(const struct pt_conf_addr_filter *filter, uint8_t n) 157 { 158 const uint64_t *addr; 159 160 if (!filter) 161 return 0ull; 162 163 if (pt_filter_addr_ncfg() <= n) 164 return 0ull; 165 166 addr = &filter->addr0_a; 167 return addr[2 * n]; 168 } 169 170 uint64_t pt_filter_addr_b(const struct pt_conf_addr_filter *filter, uint8_t n) 171 { 172 const uint64_t *addr; 173 174 if (!filter) 175 return 0ull; 176 177 if (pt_filter_addr_ncfg() <= n) 178 return 0ull; 179 180 addr = &filter->addr0_a; 181 return addr[(2 * n) + 1]; 182 } 183 184 static int pt_filter_check_cfg_filter(const struct pt_conf_addr_filter *filter, 185 uint64_t addr) 186 { 187 uint8_t n; 188 189 if (!filter) 190 return -pte_internal; 191 192 for (n = 0; n < pt_filter_addr_ncfg(); ++n) { 193 uint64_t addr_a, addr_b; 194 uint32_t addr_cfg; 195 196 addr_cfg = pt_filter_addr_cfg(filter, n); 197 if (addr_cfg != pt_addr_cfg_filter) 198 continue; 199 200 addr_a = pt_filter_addr_a(filter, n); 201 addr_b = pt_filter_addr_b(filter, n); 202 203 /* Note that both A and B are inclusive. */ 204 if ((addr_a <= addr) && (addr <= addr_b)) 205 return 1; 206 } 207 208 /* No filter hit. If we have at least one FilterEn filter, this means 209 * that tracing is disabled; otherwise, tracing is enabled. 210 */ 211 for (n = 0; n < pt_filter_addr_ncfg(); ++n) { 212 uint32_t addr_cfg; 213 214 addr_cfg = pt_filter_addr_cfg(filter, n); 215 if (addr_cfg == pt_addr_cfg_filter) 216 return 0; 217 } 218 219 return 1; 220 } 221 222 static int pt_filter_check_cfg_stop(const struct pt_conf_addr_filter *filter, 223 uint64_t addr) 224 { 225 uint8_t n; 226 227 if (!filter) 228 return -pte_internal; 229 230 for (n = 0; n < pt_filter_addr_ncfg(); ++n) { 231 uint64_t addr_a, addr_b; 232 uint32_t addr_cfg; 233 234 addr_cfg = pt_filter_addr_cfg(filter, n); 235 if (addr_cfg != pt_addr_cfg_stop) 236 continue; 237 238 addr_a = pt_filter_addr_a(filter, n); 239 addr_b = pt_filter_addr_b(filter, n); 240 241 /* Note that both A and B are inclusive. */ 242 if ((addr_a <= addr) && (addr <= addr_b)) 243 return 0; 244 } 245 246 return 1; 247 } 248 249 int pt_filter_addr_check(const struct pt_conf_addr_filter *filter, 250 uint64_t addr) 251 { 252 int status; 253 254 status = pt_filter_check_cfg_stop(filter, addr); 255 if (status <= 0) 256 return status; 257 258 return pt_filter_check_cfg_filter(filter, addr); 259 } 260