summaryrefslogtreecommitdiff
path: root/debugger/eudb.c
diff options
context:
space:
mode:
Diffstat (limited to 'debugger/eudb.c')
-rw-r--r--debugger/eudb.c602
1 files changed, 0 insertions, 602 deletions
diff --git a/debugger/eudb.c b/debugger/eudb.c
deleted file mode 100644
index 866d4b52..00000000
--- a/debugger/eudb.c
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * Copyright © 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- * Authors:
- * Ben Widawsky <ben@bwidawsk.net>
- *
- * Notes:
- *
- */
-
-#include <signal.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <strings.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/un.h>
-#include <sys/socket.h>
-#include "drm.h"
-#include "i915_drm.h"
-#include "drmtest.h"
-#include "intel_chipset.h"
-#include "intel_bufmgr.h"
-#include "intel_io.h"
-#include "intel_batchbuffer.h"
-#include "intel_debug.h"
-#include "debug.h"
-
-#define EU_ATT 0x7810
-#define EU_ATT_CLR 0x7830
-
-#define RSVD_EU -1
-#define RSVD_THREAD -1
-#define RSVD_ID EUID(-1, -1, -1)
-
-enum {
- EBAD_SHMEM,
- EBAD_PROTOCOL,
- EBAD_MAGIC,
- EBAD_WRITE
-};
-
-struct debuggee {
- int euid;
- int tid;
- int fd;
- int clr;
- uint32_t reg;
-};
-
-struct debugger {
- struct debuggee *debuggees;
- int num_threads;
- int real_num_threads;
- int threads_per_eu;
-} *eu_info;
-
-drm_intel_bufmgr *bufmgr;
-struct intel_batchbuffer *batch;
-drm_intel_bo *scratch_bo;
-
-int handle;
-int drm_fd;
-int debug_fd = 0;
-const char *debug_file = "dump_debug.bin";
-int debug;
-int clear_waits;
-int shutting_down = 0;
-struct intel_debug_handshake dh;
-int force_clear = 0;
-uint32_t old_td_ctl;
-
-/*
- * The docs are wrong about the attention clear bits. The clear bits are
- * provided as part of the structure in case they change in future generations.
- */
-#define EUID(eu, td, clear) \
- { .euid = eu, .tid = td, .reg = EU_ATT, .fd = -1, .clr = clear }
-#define EUID2(eu, td, clear) \
- { .euid = eu, .tid = td, .reg = EU_ATT + 4, .fd = -1, .clr = clear }
-struct debuggee gt1_debug_ids[] = {
- RSVD_ID, RSVD_ID,
- RSVD_ID, EUID(6, 3, 28), EUID(6, 2, 27), EUID(6, 1, 26), EUID(6, 0, 25),
- RSVD_ID, EUID(5, 3, 23), EUID(5, 2, 22), EUID(5, 1, 21), EUID(5, 0, 20),
- RSVD_ID, EUID(4, 3, 18), EUID(4, 2, 17), EUID(4, 1, 16), EUID(4, 0, 15),
- RSVD_ID, EUID(2, 3, 13), EUID(2, 2, 12), EUID(2, 1, 11), EUID(2, 0, 10),
- RSVD_ID, EUID(1, 3, 8), EUID(1, 2, 7), EUID(1, 1, 6), EUID(1, 0, 5),
- RSVD_ID, EUID(0, 3, 3), EUID(0, 2, 2), EUID(0, 1, 1), EUID(0, 0, 0)
-};
-
-struct debuggee gt2_debug_ids[] = {
- EUID(8, 1, 31), EUID(8, 0, 30),
- EUID(6, 4, 29), EUID(6, 3, 28), EUID(6, 2, 27), EUID(6, 1, 26), EUID(6, 0, 25),
- EUID(5, 4, 24), EUID(5, 3, 23), EUID(5, 2, 22), EUID(5, 1, 21), EUID(5, 0, 20),
- EUID(4, 4, 19), EUID(4, 3, 18), EUID(4, 2, 17), EUID(4, 1, 16), EUID(4, 0, 15),
- EUID(2, 4, 14), EUID(2, 3, 13), EUID(2, 2, 12), EUID(2, 1, 11), EUID(2, 0, 10),
- EUID(1, 4, 9), EUID(1, 3, 8), EUID(1, 2, 7), EUID(1, 1, 6), EUID(1, 0, 5),
- EUID(0, 4, 4), EUID(0, 3, 3), EUID(0, 2, 2), EUID(0, 1, 1), EUID(0, 0, 0),
- RSVD_ID, RSVD_ID, RSVD_ID, RSVD_ID,
- EUID2(14, 4, 27), EUID2(14, 3, 26), EUID2(14, 2, 25), EUID2(14, 1, 24), EUID2(14, 0, 23),
- EUID2(13, 4, 22), EUID2(13, 3, 21), EUID2(13, 2, 20), EUID2(13, 1, 19), EUID2(13, 0, 18),
- EUID2(12, 4, 17), EUID2(12, 3, 16), EUID2(12, 2, 15), EUID2(12, 1, 14), EUID2(12, 0, 13),
- EUID2(10, 4, 12), EUID2(10, 3, 11), EUID2(10, 2, 10), EUID2(10, 1, 9), EUID2(10, 0, 8),
- EUID2(9, 4, 7), EUID2(9, 3, 6), EUID2(9, 2, 5), EUID2(9, 1, 4), EUID2(9, 0, 3),
- EUID2(8, 4, 2), EUID2(8, 3, 1), EUID2(8, 2, 0)
-};
-
-struct debugger gt1 = {
- .debuggees = gt1_debug_ids,
- .num_threads = 32,
- .real_num_threads = 24,
- .threads_per_eu = 4
-};
-
-struct debugger gt2 = {
- .debuggees = gt2_debug_ids,
- .num_threads = 64,
- .real_num_threads = 60,
- .threads_per_eu = 5
-};
-
-static void
-dump_debug(void *buf, size_t count) {
- if (!debug_fd)
- debug_fd = open(debug_file, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXO);
-
- if (write(debug_fd, buf, count) == -1)
- fprintf(stderr, "Error writing to debug file: %s\n",
- strerror(errno));
-}
-
-static volatile void *
-map_debug_buffer(void) {
- int ret;
-
- ret = drm_intel_bo_map(scratch_bo, 0);
- assert(ret == 0);
- return scratch_bo->virtual;
-}
-
-static void
-unmap_debug_buffer(void) {
- drm_intel_bo_unmap(scratch_bo);
-}
-
-static int
-wait_for_attn(int timeout, int *out_bits) {
- int step = 1;
- int eus_waiting = 0;
- int i,j;
-
- if (timeout <= 0) {
- timeout = 1;
- step = 0;
- }
-
- for (i = 0; i < timeout; i += step) {
- for (j = 0; j < 8; j += 4) {
- uint32_t attn = intel_register_read(EU_ATT + j);
- if (attn) {
- int bit = 0;
- while( (bit = ffs(attn)) != 0) {
- bit--; // ffs is 1 based
- assert(bit >= 0);
- out_bits[eus_waiting] = bit + (j * 8);
- attn &= ~(1 << bit);
- eus_waiting++;
- }
- }
- }
-
- if (intel_register_read(EU_ATT + 8) ||
- intel_register_read(EU_ATT + 0xc)) {
- fprintf(stderr, "Unknown attention bits\n");
- }
-
- if (eus_waiting || shutting_down)
- break;
- }
-
- return eus_waiting;
-}
-
-#define eu_fd(bit) eu_info->debuggees[bit].fd
-#define eu_id(bit) eu_info->debuggees[bit].euid
-#define eu_tid(bit) eu_info->debuggees[bit].tid
-static struct eu_state *
-find_eu_shmem(int bit, volatile uint8_t *buf) {
- struct eu_state *eu;
- int mem_tid, mem_euid, i;
-
- for(i = 0; i < eu_info->num_threads; i++) {
- eu = (struct eu_state *)(buf + i * dh.per_thread_scratch);
- mem_tid = eu->sr0 & 0x7;
- mem_euid = (eu->sr0 >> 8) & 0xf;
- if (mem_tid == eu_tid(bit) && mem_euid == eu_id(bit))
- break;
- eu = NULL;
- }
-
- return eu;
-}
-
-#define GRF_CMP(a, b) memcmp(a, b, sizeof(grf))
-#define GRF_CPY(a, b) memcpy(a, b, sizeof(grf))
-static int
-verify(struct eu_state *eu) {
- if (GRF_CMP(eu->version, protocol_version)) {
- if (debug) {
- printf("Bad EU protocol version %x %x\n",
- ((uint32_t *)&eu->version)[0],
- DEBUG_PROTOCOL_VERSION);
- dump_debug((void *)eu, sizeof(*eu));
- }
- return -EBAD_PROTOCOL;
- }
-
- if (GRF_CMP(eu->state_magic, eu_msg)) {
- if (debug) {
- printf("Bad EU state magic %x %x\n",
- ((uint32_t *)&eu->state_magic)[0],
- ((uint32_t *)&eu->state_magic)[1]);
- dump_debug((void *)eu, sizeof(*eu));
- }
- return -EBAD_MAGIC;
- } else {
- GRF_CPY(eu->state_magic, cpu_ack);
- }
-
- eu->sr0 = RSVD_EU << 8 | RSVD_THREAD;
- return 0;
-}
-
-static int
-collect_data(int bit, volatile uint8_t *buf) {
- struct eu_state *eu;
- ssize_t num;
- int ret;
-
- assert(eu_id(bit) != RSVD_EU);
-
- if (eu_fd(bit) == -1) {
- char name[128];
- sprintf(name, "dump_eu_%02d_%d.bin", eu_id(bit), eu_tid(bit));
- eu_fd(bit) = open(name, O_CREAT | O_WRONLY | O_TRUNC, S_IRWXO);
- if (eu_fd(bit) == -1)
- return -1;
- }
-
- eu = find_eu_shmem(bit, buf);
-
- if (eu == NULL) {
- if (debug)
- printf("Bad offset %d %d\n", eu_id(bit), eu_tid(bit));
- return -EBAD_SHMEM;
- }
-
- ret = verify(eu);
- if (ret)
- return ret;
-
- num = write(eu_fd(bit), (void *)eu, sizeof(*eu));
- if (num != sizeof(*eu)) {
- perror("unhandled write failure");
- return EBAD_WRITE;
- }
-
-
- return 0;
-}
-
-static void
-clear_attn(int bit) {
-#if 0
-/*
- * This works but doesn't allow for easily changed clearing bits
- */
-static void
-clear_attn_old(int bit) {
- int bit_to_clear = bit % 32;
- bit_to_clear = 31 - bit_to_clear;
- intel_register_write(0x7830 + (bit/32) * 4, 0);
- intel_register_write(0x7830 + (bit/32) * 4, 1 << bit_to_clear);
-}
-#else
- if (!force_clear) {
- int bit_to_clear;
- bit_to_clear = eu_info->debuggees[bit].clr;
- intel_register_write(EU_ATT_CLR + (bit/32) * 4, 0);
- intel_register_write(EU_ATT_CLR + (bit/32) * 4, 1 << bit_to_clear);
- } else {
- intel_register_write(EU_ATT_CLR + 0, 0);
- intel_register_write(EU_ATT_CLR + 4, 0);
- intel_register_write(EU_ATT_CLR + 0, 0xffffffff);
- intel_register_write(EU_ATT_CLR + 4, 0xffffffff);
- }
-#endif
-}
-
-static void
-db_shutdown(int sig) {
- shutting_down = 1;
- printf("Shutting down...\n");
-}
-
-static void __attribute__((noreturn))
-die(int reason) {
- int i = 0;
-
- intel_register_write(EU_ATT_CLR, 0);
- intel_register_write(EU_ATT_CLR + 4, 0);
-
- if (debug_fd)
- close(debug_fd);
-
- for (i = 0; i < eu_info->num_threads; i++) {
- if (eu_info->debuggees[i].fd != -1)
- close(eu_info->debuggees[i].fd);
- }
-
- unmap_debug_buffer();
-
- if (old_td_ctl)
- intel_register_write(TD_CTL, old_td_ctl);
- intel_register_access_fini();
- exit(reason);
-}
-
-static int
-identify_device(int devid) {
- if (!IS_SANDYBRIDGE(devid))
- return -ENODEV;
-
- switch (intel_gt(devid)) {
- case 0:
- eu_info = &gt1;
- break;
- case 1:
- eu_info = &gt2;
- break;
- default:
- return 1;
- }
-
- return 0;
-}
-
-static void
-parse_data(const char *file_name) {
- struct eu_state *eu_state = NULL;
- struct stat st;
- int fd = -1;
- int ret, i, elements;
-
- fd = open(file_name, O_RDONLY);
- if (fd == -1) {
- perror("open");
- goto out;
- }
-
- ret = fstat(fd, &st);
- if (ret == -1) {
- perror("fstat");
- goto out;
- }
-
- elements = st.st_size / sizeof(struct eu_state);
- if (elements == 0) {
- fprintf(stderr, "File not big enough for 1 entry\n");
- goto out;
- }
-
- eu_state = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (eu_state == MAP_FAILED) {
- perror("mmap");
- goto out;
- }
-
- for(i = 0; i < elements; i++) {
- printf("AIP: ");
- printf("%x\n", ((uint32_t *)eu_state[i].cr0)[2]);
- }
-out:
- if (eu_state)
- munmap(eu_state, st.st_size);
- if (fd != -1)
- close(fd);
-}
-
-static int
-wait_for_scratch_bo(void) {
- struct sockaddr_un addr;
- uint32_t version;
- int fd, ret, dh_handle = -1;
-
- assert(sizeof(version) == sizeof(dh.version));
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd == -1)
- return -1;
-
- /* Clean up previous runs */
- remove(SHADER_DEBUG_SOCKET);
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, SHADER_DEBUG_SOCKET, sizeof(addr.sun_path) - 1);
-
- ret = bind(fd, (const struct sockaddr *)&addr, sizeof(addr));
- if (ret == -1) {
- perror("listen");
- return -1;
- }
-
- ret = listen(fd, 1);
- if (ret == -1) {
- perror("listen");
- goto done;
- }
-
- while(1) {
- int client_fd;
- size_t count;
- char ack[] = DEBUG_HANDSHAKE_ACK;
-
- client_fd = accept(fd, NULL, NULL);
- if (client_fd == -1) {
- perror("accept");
- goto done;
- }
-
- count = read(client_fd, &version, sizeof(version));
- if (count != sizeof(version)) {
- perror("read version");
- goto loop_out;
- }
-
- if (version != DEBUG_HANDSHAKE_VERSION) {
- fprintf(stderr, "Bad debug handshake\n");
- goto loop_out;
- }
-
- count = read(client_fd, ((char *)&dh) + 1, sizeof(dh) - 1);
- if (count != sizeof(dh) - 1) {
- perror("read handshake");
- goto loop_out;
- }
-
- count = write(client_fd, ack, sizeof(ack));
- if (count != sizeof(ack)) {
- perror("write ack");
- goto loop_out;
- }
- dh_handle = dh.flink_handle;
- if (debug > 0) {
- printf("Handshake completed successfully\n"
- "\tprotocol version = %d\n"
- "\tflink handle = %d\n"
- "\tper thread scratch = %x\n", version,
- dh.flink_handle, dh.per_thread_scratch);
- }
-
- loop_out:
- close(client_fd);
- break;
- }
-
-done:
- close(fd);
- return dh_handle;
-}
-
-static void
-setup_hw_bits(void)
-{
- intel_register_write(INST_PM, GEN6_GLOBAL_DEBUG_ENABLE |
- GEN6_GLOBAL_DEBUG_ENABLE << 16);
- old_td_ctl = intel_register_read(GEN6_TD_CTL);
- intel_register_write(GEN6_TD_CTL, GEN6_TD_CTL_FORCE_TD_BKPT);
-}
-
-int main(int argc, char* argv[]) {
- struct pci_device *pci_dev;
- volatile uint8_t *scratch = NULL;
- int bits[64];
- int devid = -1, opt;
-
- while ((opt = getopt(argc, argv, "cdr:pf?h")) != -1) {
- switch (opt) {
- case 'c':
- clear_waits = 1;
- break;
- case 'd':
- debug = 1;
- break;
- case 'r':
- parse_data(optarg);
- exit(0);
- break;
- case 'p':
- devid = atoi(optarg);
- break;
- case 'f':
- force_clear = 1;
- break;
- case '?':
- case 'h':
- default:
- exit(0);
- }
- }
-
- pci_dev = intel_get_pci_device();
- if (devid == -1)
- devid = pci_dev->device_id;
- if (identify_device(devid)) {
- abort();
- }
-
- assert(intel_register_access_init(pci_dev, 1) == 0);
-
- memset(bits, -1, sizeof(bits));
- /*
- * These events have to occur before the SR runs, or we need
- * non-blocking versions of the functions.
- */
- if (!clear_waits) {
- int dh_handle;
- drm_fd = drm_open_driver(DRIVER_INTEL);
- bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
-
- setup_hw_bits();
-
- /* We are probably root, make files world friendly */
- umask(0);
- dh_handle = wait_for_scratch_bo();
- if (dh_handle == -1) {
- printf("No handle from mesa, please enter manually: ");
- if (fscanf(stdin, "%1d", &dh_handle) == 0)
- exit(1);
- }
- scratch_bo = intel_bo_gem_create_from_name(bufmgr, "scratch", dh_handle);
- if (scratch_bo == NULL) {
- fprintf(stderr, "Couldn't flink buffer\n");
- abort();
- }
- signal(SIGINT, db_shutdown);
- printf("Press Ctrl-C to stop\n");
- } else {
- int time = force_clear ? 0 : 20000;
- while (wait_for_attn(time, bits)) {
- clear_attn(bits[0]);
- memset(bits, -1, sizeof(bits));
- }
- die(0);
- }
-
- scratch = map_debug_buffer();
- while (shutting_down == 0) {
- int num_events, i;
-
- memset(bits, -1, sizeof(bits));
- num_events = wait_for_attn(-1, bits);
- if (num_events == 0)
- break;
-
- for (i = 0; i < num_events; i++) {
- assert(bits[i] < 64 && bits[i] >= 0);
- if (collect_data(bits[i], scratch)) {
- bits[i] = -1;
- continue;
- }
- clear_attn(bits[i]);
- }
- }
-
- die(0);
- return 0;
-}