diff --git a/devicemodel/tools/acrntrace/Makefile b/devicemodel/tools/acrntrace/Makefile new file mode 100644 index 000000000..1b03c0278 --- /dev/null +++ b/devicemodel/tools/acrntrace/Makefile @@ -0,0 +1,5 @@ +all: + gcc -o acrntrace acrntrace.c sbuf.c -I. -lpthread + +clean: + rm acrntrace diff --git a/devicemodel/tools/acrntrace/acrntrace.c b/devicemodel/tools/acrntrace/acrntrace.c new file mode 100644 index 000000000..2c9f7e4f3 --- /dev/null +++ b/devicemodel/tools/acrntrace/acrntrace.c @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acrntrace.h" +#include "trace_event.h" + +/* for opt */ +static uint64_t period = 10000; +static const char optString[] = "t:hc"; +static const char dev_name[] = "/dev/acrn_trace"; + +static uint32_t flags; +static char trace_file_dir[TRACE_FILE_DIR_LEN]; + +static reader_struct *reader; +static int pcpu_num = 0; + +static void display_usage(void) +{ + printf("acrntrace - tool to collect ACRN trace data\n" + "[Usage] acrntrace [-t] [period in msec] [-ch]\n\n" + "[Options]\n" + "\t-h: print this message\n" + "\t-t: period_in_ms: specify polling interval [1-999]\n" + "\t-c: clear the buffered old data\n"); +} + +static int parse_opt(int argc, char *argv[]) +{ + int opt, ret; + + while ((opt = getopt(argc, argv, optString)) != -1) { + switch (opt) { + case 't': + ret = atoi(optarg); + if (ret <= 0 || ret >=1000) { + pr_err("'-t' require integer between [1-999]\n"); + return -EINVAL; + } + period = ret * 1000; + pr_dbg("Period is %lu\n", period); + break; + case 'c': + flags |= FLAG_CLEAR_BUF; + break; + case 'h': + display_usage(); + return -EINVAL; + default: + /* Undefined operation. */ + display_usage(); + return -EINVAL; + } + }; + return 0; +} + +static int shell_cmd(const char *cmd, char *outbuf, int len) +{ + FILE *ptr; + char cmd_buf[256]; + int ret; + + if (!outbuf) + return system(cmd); + + memset(cmd_buf, 0, sizeof(cmd_buf)); + memset(outbuf, 0, len); + snprintf(cmd_buf, sizeof(cmd_buf), "%s 2>&1", cmd); + ptr = popen(cmd_buf, "re"); + if (!ptr) + return -1; + + ret = fread(outbuf, 1, len, ptr); + pclose(ptr); + + return ret; +} + +static int get_cpu_num(void) +{ + + char cmd[128]; + char buf[16]; + int ret; + + snprintf(cmd, sizeof(cmd), "ls %s_* | wc -l", dev_name); + + ret = shell_cmd(cmd, buf, sizeof(buf)); + if (ret <= 0) { + pr_err("Faile to get cpu number, use default 4\n"); + return PCPU_NUM; + } + + ret = atoi(buf); + if (ret <= 0) { + pr_err("Wrong cpu number, use default 4\n"); + return PCPU_NUM; + } + + return ret; +} + +static double get_cpu_freq(void) +{ + char cmd[] = + "cat /proc/cpuinfo | grep -m 1 \"cpu MHz\" | awk '{print $4}'"; + char buf[16]; + int ret; + double freq = 0; + + ret = shell_cmd(cmd, buf, sizeof(buf)); + + if (ret <= 0) { + pr_err("Faile to get cpu freq, use default 1920MHz\n"); + return 1920.00; + } + + freq = atof(buf); + if (freq <= 0) { + pr_err("Invalid cpu freq string, use default 1920MHz\n"); + return 1920.00; + } + + return freq; +} + +static int create_trace_file_dir(char *dir) +{ + int status; + char cmd[CMD_MAX_LEN]; + char time_str[TIME_STR_LEN]; + time_t timep; + struct tm *p; + + time(&timep); + p = localtime(&timep); + snprintf(time_str, TIME_STR_LEN, "%d%02d%02d-%02d%02d%02d", + (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, + p->tm_hour, p->tm_min, p->tm_sec); + pr_info("start tracing at %s\n", time_str); + + snprintf(dir, TRACE_FILE_DIR_LEN, "%s%s", TRACE_FILE_ROOT, time_str); + + memset(cmd, 0, CMD_MAX_LEN); + snprintf(cmd, CMD_MAX_LEN, "%s %s", "mkdir -p ", dir); + + status = system(cmd); + if (-1 == status) + return -1; /* failed to execute sh */ + + pr_dbg("dir %s creted\n", dir); + + return WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE; +} + +/* function executed in each consumer thread */ +static void reader_fn(param_t * param) +{ + int ret; + uint32_t cpuid = param->cpuid; + FILE *fp = param->trace_filep; + shared_buf_t *sbuf = param->sbuf; + trace_ev_t e; + + pr_dbg("reader thread[%lu] created for FILE*[0x%p]\n", + pthread_self(), fp); + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + + /* Clear the old data in sbuf */ + if (flags & FLAG_CLEAR_BUF) + sbuf_clear_buffered(sbuf); + + /* write cpu freq to the first line of output file */ + fprintf(fp, "CPU Freq: %f\n", get_cpu_freq()); + + while (1) { + do { + ret = sbuf_get(sbuf, (void *)&e); + if (ret == 0) + break; + else if (ret < 0) { + pr_err("sbuf[%u] read error: %d\n", cpuid, ret); + return; + } + + fprintf(fp, "%u | %lu | ", cpuid, e.tsc); + switch (e.id) { + /* defined in trace_event.h */ + /* for each ev type */ + ALL_CASES; + } + } while (ret > 0); + + usleep(period); + } +} + +static int create_reader(reader_struct * reader, uint32_t cpu) +{ + char trace_file_name[TRACE_FILE_NAME_LEN]; + + snprintf(reader->dev_name, DEV_PATH_LEN, "%s_%u", dev_name, cpu); + reader->param.cpuid = cpu; + + reader->dev_fd = open(reader->dev_name, O_RDWR); + if (reader->dev_fd < 0) { + pr_err("Failed to open %s, err %d\n", reader->dev_name, errno); + reader->dev_fd = 0; + return -1; + } + + reader->param.sbuf = mmap(NULL, MMAP_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, reader->dev_fd, 0); + if (reader->param.sbuf == MAP_FAILED) { + pr_err("mmap failed for cpu%d, errno %d\n", cpu, errno); + reader->param.sbuf = NULL; + return -2; + } + + pr_dbg("sbuf[%d]:\nmagic_num: %lx\nele_num: %u\n ele_size: %u\n", + cpu, reader->param.sbuf->magic, reader->param.sbuf->ele_num, + reader->param.sbuf->ele_size); + + snprintf(trace_file_name, TRACE_FILE_NAME_LEN, "%s/%d", trace_file_dir, + cpu); + reader->param.trace_filep = fopen(trace_file_name, "w+"); + if (!reader->param.trace_filep) { + pr_err("Failed to open %s, err %d\n", trace_file_name, errno); + return -3; + } + + pr_info("trace data file %s created for %s\n", + trace_file_name, reader->dev_name); + + if (pthread_create(&reader->thrd, NULL, + (void *)&reader_fn, &reader->param)) { + pr_err("failed to create reader thread, %d\n", cpu); + return -4; + } + + return 0; +} + +static void destory_reader(reader_struct * reader) +{ + if (reader->thrd) { + pthread_cancel(reader->thrd); + if (pthread_join(reader->thrd, NULL) != 0) + pr_err("failed to cancel thread[%lu]\n", reader->thrd); + else + reader->thrd = 0; + } + + if (reader->param.sbuf) { + munmap(reader->param.sbuf, MMAP_SIZE); + reader->param.sbuf = NULL; + } + + if (reader->dev_fd) { + close(reader->dev_fd); + reader->dev_fd = 0; + } + + if (reader->param.trace_filep) { + fflush(reader->param.trace_filep); + fclose(reader->param.trace_filep); + reader->param.trace_filep = NULL; + } +} + +static void handle_on_exit(void) +{ + uint32_t cpu; + + /* if nothing to release */ + if (!(flags & FLAG_TO_REL)) + return; + + pr_info("exiting - to release resources...\n"); + + foreach_cpu(cpu) + destory_reader(&reader[cpu]); +} + +static void signal_exit_handler(int sig) +{ + pr_info("exit on signal %d\n", sig); + exit(0); +} + +int main(int argc, char *argv[]) +{ + uint32_t cpu = 0; + + /* parse options */ + if (parse_opt(argc, argv)) + exit(EXIT_FAILURE); + + /* how many cpus */ + pcpu_num = get_cpu_num(); + reader = malloc(sizeof(reader_struct) * pcpu_num); + if (!reader) { + pr_err("Failed to allocate reader memory\n"); + exit(EXIT_FAILURE); + } + memset(reader, 0, sizeof(reader_struct) * pcpu_num); + + /* create dir for trace file */ + if (create_trace_file_dir(trace_file_dir)) { + pr_err("Failed to create dir for trace files\n"); + exit(EXIT_FAILURE); + } + + atexit(handle_on_exit); + + /* acquair res for each trace dev */ + flags |= FLAG_TO_REL; + foreach_cpu(cpu) + if (create_reader(&reader[cpu], cpu) < 0) + goto out_free; + + /* for kill exit handling */ + signal(SIGTERM, signal_exit_handler); + signal(SIGINT, signal_exit_handler); + + /* wait for user input to stop */ + printf("q to quit:\n"); + while (getchar() != 'q') + printf("q to quit:\n"); + + out_free: + foreach_cpu(cpu) + destory_reader(&reader[cpu]); + + free(reader); + flags &= ~FLAG_TO_REL; + + return EXIT_SUCCESS; +} diff --git a/devicemodel/tools/acrntrace/acrntrace.h b/devicemodel/tools/acrntrace/acrntrace.h new file mode 100644 index 000000000..de434882d --- /dev/null +++ b/devicemodel/tools/acrntrace/acrntrace.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * 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 "sbuf.h" + +#define PCPU_NUM 4 +#define TRACE_ELEMENT_SIZE 32 /* byte */ +#define TRACE_ELEMENT_NUM ((4 * 1024 * 1024 - 64) / TRACE_ELEMENT_SIZE) +#define PAGE_SIZE 4096 +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define MMAP_SIZE (4 * 1024 * 1024) +/* +#define MMAP_SIZE ((TRACE_ELEMENT_SIZE * TRACE_ELEMENT_NUM \ + + PAGE_SIZE - 1) & PAGE_MASK) +*/ +#define TRACE_FILE_NAME_LEN 36 +#define TRACE_FILE_DIR_LEN (TRACE_FILE_NAME_LEN - 2) +#define TRACE_FILE_ROOT "/tmp/acrntrace/" +#define DEV_PATH_LEN 18 +#define TIME_STR_LEN 16 +#define CMD_MAX_LEN 48 + +#define pr_fmt(fmt) "acrntrace: " fmt +#define pr_info(fmt, ...) printf(pr_fmt(fmt), ##__VA_ARGS__) +#define pr_err(fmt, ...) printf(pr_fmt(fmt), ##__VA_ARGS__) + +#ifdef DEBUG +#define pr_dbg(fmt, ...) printf(pr_fmt(fmt), ##__VA_ARGS__) +#else +#define pr_dbg(fmt, ...) +#endif + +/* + * flags: + * FLAG_TO_REL - resources need to be release + * FLAG_CLEAR_BUF - to clear buffered old data + */ +#define FLAG_TO_REL (1UL << 0) +#define FLAG_CLEAR_BUF (1UL << 1) + +#define foreach_cpu(cpu) \ + for ((cpu) = 0; (cpu) < (pcpu_num); (cpu)++) + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned long uint64_t; + +typedef struct { + uint64_t tsc; + uint64_t id; + union { + struct { + uint32_t a, b, c, d; + }; + struct { + uint8_t a1, a2, a3, a4; + uint8_t b1, b2, b3, b4; + uint8_t c1, c2, c3, c4; + uint8_t d1, d2, d3, d4; + }; + struct { + uint64_t e; + uint64_t f; + }; + char str[16]; + }; +} trace_ev_t; + +typedef struct { + uint32_t cpuid; + int exit_flag; + FILE *trace_filep; + shared_buf_t *sbuf; + pthread_mutex_t *sbuf_lock; +} param_t; + +typedef struct { + int dev_fd; + char dev_name[DEV_PATH_LEN]; + pthread_t thrd; + param_t param; +} reader_struct; diff --git a/devicemodel/tools/acrntrace/sbuf.c b/devicemodel/tools/acrntrace/sbuf.c new file mode 100644 index 000000000..09ee30e40 --- /dev/null +++ b/devicemodel/tools/acrntrace/sbuf.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * 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 +#include +#include +#include "sbuf.h" + +static inline bool sbuf_is_empty(shared_buf_t *sbuf) +{ + return (sbuf->head == sbuf->tail); +} + +static inline uint32_t sbuf_next_ptr(uint32_t pos, + uint32_t span, uint32_t scope) +{ + pos += span; + pos = (pos >= scope) ? (pos - scope) : pos; + return pos; +} + +int sbuf_get(shared_buf_t *sbuf, uint8_t *data) +{ + const void *from; + + if ((sbuf == NULL) || (data == NULL)) + return -EINVAL; + + if (sbuf_is_empty(sbuf)) { + /* no data available */ + return 0; + } + + from = (void *)sbuf + SBUF_HEAD_SIZE + sbuf->head; + + memcpy(data, from, sbuf->ele_size); + + sbuf->head = sbuf_next_ptr(sbuf->head, sbuf->ele_size, sbuf->size); + + return sbuf->ele_size; +} + +int sbuf_clear_buffered(shared_buf_t *sbuf) +{ + if (sbuf == NULL) + return -EINVAL; + + sbuf->head = sbuf->tail; + + return 0; +} diff --git a/devicemodel/tools/acrntrace/sbuf.h b/devicemodel/tools/acrntrace/sbuf.h new file mode 100644 index 000000000..bd8de128a --- /dev/null +++ b/devicemodel/tools/acrntrace/sbuf.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * 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. + */ + +#ifndef SHARED_BUF_H +#define SHARED_BUF_H + +#include + +#define SBUF_MAGIC 0x5aa57aa71aa13aa3 +#define SBUF_MAX_SIZE (1ULL << 22) +#define SBUF_HEAD_SIZE 64 + +/* sbuf flags */ +#define OVERRUN_CNT_EN (1ULL << 0) /* whether overrun counting is enabled */ +#define OVERWRITE_EN (1ULL << 1) /* whether overwrite is enabled */ + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned long uint64_t; + +/** + * (sbuf) head + buf (store (ele_num - 1) elements at most) + * buffer empty: tail == head + * buffer full: (tail + ele_size) % size == head + * + * Base of memory for elements + * | + * | + * --------------------------------------------------------------------------------------- + * | shared_buf_t | raw data (ele_size)| raw date (ele_size) | ... | raw data (ele_size) | + * --------------------------------------------------------------------------------------- + * | + * | + * shared_buf_t *buf + */ + +/* Make sure sizeof(shared_buf_t) == SBUF_HEAD_SIZE */ +typedef struct shared_buf { + uint64_t magic; + uint32_t ele_num; /* number of elements */ + uint32_t ele_size; /* sizeof of elements */ + uint32_t head; /* offset from base, to read */ + uint32_t tail; /* offset from base, to write */ + uint64_t flags; + uint32_t overrun_cnt; /* count of overrun */ + uint32_t size; /* ele_num * ele_size */ + uint32_t padding[6]; +} shared_buf_t; + +static inline void sbuf_clear_flags(shared_buf_t *sbuf, uint64_t flags) +{ + sbuf->flags &= ~flags; +} + +static inline void sbuf_set_flags(shared_buf_t *sbuf, uint64_t flags) +{ + sbuf->flags = flags; +} + +static inline void sbuf_add_flags(shared_buf_t *sbuf, uint64_t flags) +{ + sbuf->flags |= flags; +} + +int sbuf_get(shared_buf_t *sbuf, uint8_t *data); +int sbuf_clear_buffered(shared_buf_t *sbuf); +#endif /* SHARED_BUF_H */ diff --git a/devicemodel/tools/acrntrace/trace_event.h b/devicemodel/tools/acrntrace/trace_event.h new file mode 100644 index 000000000..2c70ff92b --- /dev/null +++ b/devicemodel/tools/acrntrace/trace_event.h @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * 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. + */ + +#ifndef TRACE_EVENT_H +#define TRACE_EVENT_H + +#define GEN_CASE(id) case (id):{ id##_FMT; break; } + +/* TIMER */ +#define TRACE_TIMER_ACTION_ADDED 0x1 +#define TRACE_TIMER_ACTION_PCKUP 0x2 +#define TRACE_TIMER_ACTION_UPDAT 0x3 +#define TRACE_TIMER_IRQ 0x4 + +#define TRACE_VM_EXIT 0x10 +#define TRACE_VM_ENTER 0X11 +#define TRC_VMEXIT_ENTRY 0x10000 + +#define TRC_VMEXIT_EXCEPTION_OR_NMI (TRC_VMEXIT_ENTRY + 0x00000000) +#define TRC_VMEXIT_EXTERNAL_INTERRUPT (TRC_VMEXIT_ENTRY + 0x00000001) +#define TRC_VMEXIT_INTERRUPT_WINDOW (TRC_VMEXIT_ENTRY + 0x00000002) +#define TRC_VMEXIT_CPUID (TRC_VMEXIT_ENTRY + 0x00000004) +#define TRC_VMEXIT_RDTSC (TRC_VMEXIT_ENTRY + 0x00000010) +#define TRC_VMEXIT_VMCALL (TRC_VMEXIT_ENTRY + 0x00000012) +#define TRC_VMEXIT_CR_ACCESS (TRC_VMEXIT_ENTRY + 0x0000001C) +#define TRC_VMEXIT_IO_INSTRUCTION (TRC_VMEXIT_ENTRY + 0x0000001E) +#define TRC_VMEXIT_RDMSR (TRC_VMEXIT_ENTRY + 0x0000001F) +#define TRC_VMEXIT_WRMSR (TRC_VMEXIT_ENTRY + 0x00000020) +#define TRC_VMEXIT_EPT_VIOLATION (TRC_VMEXIT_ENTRY + 0x00000030) +#define TRC_VMEXIT_EPT_MISCONFIGURATION (TRC_VMEXIT_ENTRY + 0x00000031) +#define TRC_VMEXIT_RDTSCP (TRC_VMEXIT_ENTRY + 0x00000033) +#define TRC_VMEXIT_APICV_WRITE (TRC_VMEXIT_ENTRY + 0x00000038) +#define TRC_VMEXIT_APICV_ACCESS (TRC_VMEXIT_ENTRY + 0x00000039) +#define TRC_VMEXIT_APICV_VIRT_EOI (TRC_VMEXIT_ENTRY + 0x0000003A) + +#define TRC_VMEXIT_UNHANDLED 0x20000 + +#define TRACE_CUSTOM 0xFC +#define TRACE_FUNC_ENTER 0xFD +#define TRACE_FUNC_EXIT 0xFE +#define TRACE_STR 0xFF +/* TRACE_EVENTID_MAX 256 */ + +#define PR(fmt, ...) fprintf((fp), fmt, ##__VA_ARGS__); + +#define TRACE_TIMER_ACTION_ADDED_FMT \ +{PR("TIMER_ACTION ADDED: ID %d, deadline %lx total %d\n", \ + (e).a, ((uint64_t)((e).c)<<32)|(e).b, (e).d); } + +#define TRACE_TIMER_ACTION_PCKUP_FMT \ +{PR("TIMER_ACTION PCKUP: ID %d, deadline %lx total %d\n", \ + (e).a, ((uint64_t)((e).c)<<32)|(e).b, (e).d); } + +#define TRACE_TIMER_ACTION_UPDAT_FMT \ +{PR("TIMER_ACTION UPDAT: ID %d, deadline %lx total %d\n", \ + (e).a, ((unsigned long)((e).c)<<32)|(e).b, (e).d); } + +#define TRACE_TIMER_IRQ_FMT \ +PR("TIMER_IRQ total: %lx\n", (e).e) + +#define TRACE_CUSTOM_FMT \ +PR("CUSTOM: 0x%lx 0x%lx\n", (e).e, (e).f) + +#define TRACE_FUNC_ENTER_FMT \ +PR("ENTER: %s\n", (e).str) + +#define TRACE_FUNC_EXIT_FMT \ +PR("EXIT : %s\n", (e).str) + +#define TRACE_STR_FMT \ +PR("STR: %s\n", (e).str) + +#define TRACE_VM_EXIT_FMT \ +PR("VM_EXIT: exit_reason 0x%016lx, guest_rip 0x%016lx\n", \ + (e).e, (e).f) + +#define TRACE_VM_ENTER_FMT \ +PR("VM_ENTER:\n") + +#define TRC_VMEXIT_EXCEPTION_OR_NMI_FMT \ +PR("VMEXIT_EXCEPTION_OR_NMI: \ + vec 0x%08x, err_code 0x%08x, type %d\n", \ + (e).a, (e).b, (e).c) + +#define TRC_VMEXIT_EXTERNAL_INTERRUPT_FMT \ +PR("VMEXIT_EXTERNAL_INTERRUPT: vec 0x%08lx\n", (e).e) + +#define TRC_VMEXIT_INTERRUPT_WINDOW_FMT \ +PR("VMEXIT_INTERRUPT_WINDOW:\n") + +#define TRC_VMEXIT_CPUID_FMT \ +PR("VMEXIT_CPUID: vcpuid %lu\n", (e).e) + +#define TRC_VMEXIT_RDTSC_FMT \ +PR("VMEXIT_RDTSC: host_tsc 0x%016lx, tsc_offset 0x%016lx\n", \ + (e).e, (e).f) + +#define TRC_VMEXIT_VMCALL_FMT \ +PR("VMEXIT_VMCALL: vmid %lu, hypercall_id %lu\n", \ + (e).e, (e).f) + +#define TRC_VMEXIT_CR_ACCESS_FMT \ +PR("VMEXIT_CR_ACCESS: op %s, rn_nr %lu\n", \ + (e).e?"Read":"Write", (e).f) + +#define TRC_VMEXIT_IO_INSTRUCTION_FMT \ +PR("VMEXIT_IO_INSTRUCTION: \ + port %u, dir %u, sz %u, cur_ctx_idx %u\n", \ + (e).a, (e).b, (e).c, (e).d) + +#define TRC_VMEXIT_RDMSR_FMT \ +PR("VMEXIT_RDMSR: msr 0x%08lx, val 0x%08lx\n", \ + (e).e, (e).f) + +#define TRC_VMEXIT_WRMSR_FMT \ +PR("VMEXIT_WRMSR: msr 0x%08lx, val 0x%08lx\n", \ + (e).e, (e).f) + +#define TRC_VMEXIT_EPT_VIOLATION_FMT \ +PR("VMEXIT_EPT_VIOLATION: qual 0x%016lx, gpa 0x%016lx\n", \ + (e).e, (e).f) + +#define TRC_VMEXIT_EPT_MISCONFIGURATION_FMT \ +PR("VMEXIT_EPT_MISCONFIGURATION:\n") + +#define TRC_VMEXIT_RDTSCP_FMT \ +PR("VMEXIT_RDTSCP: guest_tsc 0x%lx, tsc_aux 0x%lx\n", \ + (e).e, (e).f) + +#define TRC_VMEXIT_APICV_WRITE_FMT \ +PR("VMEXIT_APICV_WRITE: offset 0x%lx\n", (e).e) + +#define TRC_VMEXIT_APICV_ACCESS_FMT \ +PR("VMEXIT_APICV_ACCESS:\n") + +#define TRC_VMEXIT_APICV_VIRT_EOI_FMT \ +PR("VMEXIT_APICV_VIRT_EOI: vec 0x%08lx\n", (e).e) + +#define TRC_VMEXIT_UNHANDLED_FMT \ +PR("VMEXIT_UNHANDLED: 0x%08lx\n", (e).e) + +#define ALL_CASES \ + GEN_CASE(TRACE_TIMER_ACTION_ADDED); \ + GEN_CASE(TRACE_TIMER_ACTION_PCKUP); \ + GEN_CASE(TRACE_TIMER_ACTION_UPDAT); \ + GEN_CASE(TRACE_TIMER_IRQ); \ + GEN_CASE(TRACE_CUSTOM); \ + GEN_CASE(TRACE_STR); \ + GEN_CASE(TRACE_FUNC_ENTER); \ + GEN_CASE(TRACE_FUNC_EXIT); \ + GEN_CASE(TRACE_VM_EXIT); \ + GEN_CASE(TRACE_VM_ENTER); \ + GEN_CASE(TRC_VMEXIT_EXCEPTION_OR_NMI); \ + GEN_CASE(TRC_VMEXIT_EXTERNAL_INTERRUPT);\ + GEN_CASE(TRC_VMEXIT_INTERRUPT_WINDOW); \ + GEN_CASE(TRC_VMEXIT_CPUID); \ + GEN_CASE(TRC_VMEXIT_RDTSC); \ + GEN_CASE(TRC_VMEXIT_VMCALL); \ + GEN_CASE(TRC_VMEXIT_CR_ACCESS); \ + GEN_CASE(TRC_VMEXIT_IO_INSTRUCTION); \ + GEN_CASE(TRC_VMEXIT_RDMSR); \ + GEN_CASE(TRC_VMEXIT_WRMSR); \ + GEN_CASE(TRC_VMEXIT_EPT_VIOLATION); \ + GEN_CASE(TRC_VMEXIT_EPT_MISCONFIGURATION);\ + GEN_CASE(TRC_VMEXIT_RDTSCP); \ + GEN_CASE(TRC_VMEXIT_APICV_WRITE); \ + GEN_CASE(TRC_VMEXIT_APICV_ACCESS); \ + GEN_CASE(TRC_VMEXIT_APICV_VIRT_EOI); \ + GEN_CASE(TRC_VMEXIT_UNHANDLED); \ + +#endif /* TRACE_EVENT_H */