summaryrefslogtreecommitdiff
path: root/libipt/src/pt_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'libipt/src/pt_config.c')
-rw-r--r--libipt/src/pt_config.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/libipt/src/pt_config.c b/libipt/src/pt_config.c
new file mode 100644
index 0000000000000..7c14c5eb181f5
--- /dev/null
+++ b/libipt/src/pt_config.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2013-2019, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Intel Corporation nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pt_config.h"
+#include "pt_opcodes.h"
+
+#include "intel-pt.h"
+
+#include <string.h>
+#include <stddef.h>
+
+
+int pt_cpu_errata(struct pt_errata *errata, const struct pt_cpu *cpu)
+{
+ if (!errata || !cpu)
+ return -pte_invalid;
+
+ memset(errata, 0, sizeof(*errata));
+
+ /* We don't know about others. */
+ if (cpu->vendor != pcv_intel)
+ return -pte_bad_cpu;
+
+ switch (cpu->family) {
+ case 0x6:
+ switch (cpu->model) {
+ case 0x3d:
+ case 0x47:
+ case 0x4f:
+ case 0x56:
+ errata->bdm70 = 1;
+ errata->bdm64 = 1;
+ return 0;
+
+ case 0x4e:
+ case 0x5e:
+ case 0x8e:
+ case 0x9e:
+ errata->bdm70 = 1;
+ errata->skd007 = 1;
+ errata->skd022 = 1;
+ errata->skd010 = 1;
+ errata->skl014 = 1;
+ errata->skl168 = 1;
+ return 0;
+
+ case 0x55:
+ case 0x66:
+ case 0x7d:
+ case 0x7e:
+ errata->bdm70 = 1;
+ errata->skl014 = 1;
+ errata->skd022 = 1;
+ return 0;
+
+ case 0x5c:
+ case 0x5f:
+ errata->apl12 = 1;
+ errata->apl11 = 1;
+ return 0;
+
+ case 0x7a:
+ case 0x86:
+ errata->apl11 = 1;
+ return 0;
+ }
+ break;
+ }
+
+ return -pte_bad_cpu;
+}
+
+int pt_config_from_user(struct pt_config *config,
+ const struct pt_config *uconfig)
+{
+ uint8_t *begin, *end;
+ size_t size;
+
+ if (!config)
+ return -pte_internal;
+
+ if (!uconfig)
+ return -pte_invalid;
+
+ size = uconfig->size;
+ if (size < offsetof(struct pt_config, decode))
+ return -pte_bad_config;
+
+ begin = uconfig->begin;
+ end = uconfig->end;
+
+ if (!begin || !end || end < begin)
+ return -pte_bad_config;
+
+ /* Ignore fields in the user's configuration we don't know; zero out
+ * fields the user didn't know about.
+ */
+ if (sizeof(*config) <= size)
+ size = sizeof(*config);
+ else
+ memset(((uint8_t *) config) + size, 0, sizeof(*config) - size);
+
+ /* Copy (portions of) the user's configuration. */
+ memcpy(config, uconfig, size);
+
+ /* We copied user's size - fix it. */
+ config->size = size;
+
+ return 0;
+}
+
+/* The maximum number of filter addresses that fit into the configuration. */
+static inline size_t pt_filter_addr_ncfg(void)
+{
+ return (sizeof(struct pt_conf_addr_filter) -
+ offsetof(struct pt_conf_addr_filter, addr0_a)) /
+ (2 * sizeof(uint64_t));
+}
+
+uint32_t pt_filter_addr_cfg(const struct pt_conf_addr_filter *filter, uint8_t n)
+{
+ if (!filter)
+ return 0u;
+
+ if (pt_filter_addr_ncfg() <= n)
+ return 0u;
+
+ return (filter->config.addr_cfg >> (4 * n)) & 0xf;
+}
+
+uint64_t pt_filter_addr_a(const struct pt_conf_addr_filter *filter, uint8_t n)
+{
+ const uint64_t *addr;
+
+ if (!filter)
+ return 0ull;
+
+ if (pt_filter_addr_ncfg() <= n)
+ return 0ull;
+
+ addr = &filter->addr0_a;
+ return addr[2 * n];
+}
+
+uint64_t pt_filter_addr_b(const struct pt_conf_addr_filter *filter, uint8_t n)
+{
+ const uint64_t *addr;
+
+ if (!filter)
+ return 0ull;
+
+ if (pt_filter_addr_ncfg() <= n)
+ return 0ull;
+
+ addr = &filter->addr0_a;
+ return addr[(2 * n) + 1];
+}
+
+static int pt_filter_check_cfg_filter(const struct pt_conf_addr_filter *filter,
+ uint64_t addr)
+{
+ uint8_t n;
+
+ if (!filter)
+ return -pte_internal;
+
+ for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
+ uint64_t addr_a, addr_b;
+ uint32_t addr_cfg;
+
+ addr_cfg = pt_filter_addr_cfg(filter, n);
+ if (addr_cfg != pt_addr_cfg_filter)
+ continue;
+
+ addr_a = pt_filter_addr_a(filter, n);
+ addr_b = pt_filter_addr_b(filter, n);
+
+ /* Note that both A and B are inclusive. */
+ if ((addr_a <= addr) && (addr <= addr_b))
+ return 1;
+ }
+
+ /* No filter hit. If we have at least one FilterEn filter, this means
+ * that tracing is disabled; otherwise, tracing is enabled.
+ */
+ for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
+ uint32_t addr_cfg;
+
+ addr_cfg = pt_filter_addr_cfg(filter, n);
+ if (addr_cfg == pt_addr_cfg_filter)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int pt_filter_check_cfg_stop(const struct pt_conf_addr_filter *filter,
+ uint64_t addr)
+{
+ uint8_t n;
+
+ if (!filter)
+ return -pte_internal;
+
+ for (n = 0; n < pt_filter_addr_ncfg(); ++n) {
+ uint64_t addr_a, addr_b;
+ uint32_t addr_cfg;
+
+ addr_cfg = pt_filter_addr_cfg(filter, n);
+ if (addr_cfg != pt_addr_cfg_stop)
+ continue;
+
+ addr_a = pt_filter_addr_a(filter, n);
+ addr_b = pt_filter_addr_b(filter, n);
+
+ /* Note that both A and B are inclusive. */
+ if ((addr_a <= addr) && (addr <= addr_b))
+ return 0;
+ }
+
+ return 1;
+}
+
+int pt_filter_addr_check(const struct pt_conf_addr_filter *filter,
+ uint64_t addr)
+{
+ int status;
+
+ status = pt_filter_check_cfg_stop(filter, addr);
+ if (status <= 0)
+ return status;
+
+ return pt_filter_check_cfg_filter(filter, addr);
+}