mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-10-29 07:18:51 +01:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
19
tools/perf/arch/x86/Makefile
Normal file
19
tools/perf/arch/x86/Makefile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
ifndef NO_DWARF
|
||||
PERF_HAVE_DWARF_REGS := 1
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
|
||||
endif
|
||||
ifndef NO_LIBUNWIND
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libunwind.o
|
||||
endif
|
||||
ifndef NO_LIBDW_DWARF_UNWIND
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/unwind-libdw.o
|
||||
endif
|
||||
ifndef NO_DWARF_UNWIND
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/regs_load.o
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/tests/dwarf-unwind.o
|
||||
endif
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/header.o
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/tsc.o
|
||||
LIB_H += arch/$(ARCH)/util/tsc.h
|
||||
HAVE_KVM_STAT_SUPPORT := 1
|
||||
LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/kvm-stat.o
|
||||
86
tools/perf/arch/x86/include/perf_regs.h
Normal file
86
tools/perf/arch/x86/include/perf_regs.h
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#ifndef ARCH_PERF_REGS_H
|
||||
#define ARCH_PERF_REGS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/perf_regs.h>
|
||||
|
||||
void perf_regs_load(u64 *regs);
|
||||
|
||||
#ifndef HAVE_ARCH_X86_64_SUPPORT
|
||||
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
|
||||
#define PERF_REGS_MAX PERF_REG_X86_32_MAX
|
||||
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_32
|
||||
#else
|
||||
#define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
|
||||
(1ULL << PERF_REG_X86_ES) | \
|
||||
(1ULL << PERF_REG_X86_FS) | \
|
||||
(1ULL << PERF_REG_X86_GS))
|
||||
#define PERF_REGS_MASK (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~REG_NOSUPPORT)
|
||||
#define PERF_REGS_MAX PERF_REG_X86_64_MAX
|
||||
#define PERF_SAMPLE_REGS_ABI PERF_SAMPLE_REGS_ABI_64
|
||||
#endif
|
||||
#define PERF_REG_IP PERF_REG_X86_IP
|
||||
#define PERF_REG_SP PERF_REG_X86_SP
|
||||
|
||||
static inline const char *perf_reg_name(int id)
|
||||
{
|
||||
switch (id) {
|
||||
case PERF_REG_X86_AX:
|
||||
return "AX";
|
||||
case PERF_REG_X86_BX:
|
||||
return "BX";
|
||||
case PERF_REG_X86_CX:
|
||||
return "CX";
|
||||
case PERF_REG_X86_DX:
|
||||
return "DX";
|
||||
case PERF_REG_X86_SI:
|
||||
return "SI";
|
||||
case PERF_REG_X86_DI:
|
||||
return "DI";
|
||||
case PERF_REG_X86_BP:
|
||||
return "BP";
|
||||
case PERF_REG_X86_SP:
|
||||
return "SP";
|
||||
case PERF_REG_X86_IP:
|
||||
return "IP";
|
||||
case PERF_REG_X86_FLAGS:
|
||||
return "FLAGS";
|
||||
case PERF_REG_X86_CS:
|
||||
return "CS";
|
||||
case PERF_REG_X86_SS:
|
||||
return "SS";
|
||||
case PERF_REG_X86_DS:
|
||||
return "DS";
|
||||
case PERF_REG_X86_ES:
|
||||
return "ES";
|
||||
case PERF_REG_X86_FS:
|
||||
return "FS";
|
||||
case PERF_REG_X86_GS:
|
||||
return "GS";
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
case PERF_REG_X86_R8:
|
||||
return "R8";
|
||||
case PERF_REG_X86_R9:
|
||||
return "R9";
|
||||
case PERF_REG_X86_R10:
|
||||
return "R10";
|
||||
case PERF_REG_X86_R11:
|
||||
return "R11";
|
||||
case PERF_REG_X86_R12:
|
||||
return "R12";
|
||||
case PERF_REG_X86_R13:
|
||||
return "R13";
|
||||
case PERF_REG_X86_R14:
|
||||
return "R14";
|
||||
case PERF_REG_X86_R15:
|
||||
return "R15";
|
||||
#endif /* HAVE_ARCH_X86_64_SUPPORT */
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* ARCH_PERF_REGS_H */
|
||||
61
tools/perf/arch/x86/tests/dwarf-unwind.c
Normal file
61
tools/perf/arch/x86/tests/dwarf-unwind.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include <string.h>
|
||||
#include "perf_regs.h"
|
||||
#include "thread.h"
|
||||
#include "map.h"
|
||||
#include "event.h"
|
||||
#include "debug.h"
|
||||
#include "tests/tests.h"
|
||||
|
||||
#define STACK_SIZE 8192
|
||||
|
||||
static int sample_ustack(struct perf_sample *sample,
|
||||
struct thread *thread, u64 *regs)
|
||||
{
|
||||
struct stack_dump *stack = &sample->user_stack;
|
||||
struct map *map;
|
||||
unsigned long sp;
|
||||
u64 stack_size, *buf;
|
||||
|
||||
buf = malloc(STACK_SIZE);
|
||||
if (!buf) {
|
||||
pr_debug("failed to allocate sample uregs data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp = (unsigned long) regs[PERF_REG_X86_SP];
|
||||
|
||||
map = map_groups__find(thread->mg, MAP__VARIABLE, (u64) sp);
|
||||
if (!map) {
|
||||
pr_debug("failed to get stack map\n");
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
stack_size = map->end - sp;
|
||||
stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
|
||||
|
||||
memcpy(buf, (void *) sp, stack_size);
|
||||
stack->data = (char *) buf;
|
||||
stack->size = stack_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test__arch_unwind_sample(struct perf_sample *sample,
|
||||
struct thread *thread)
|
||||
{
|
||||
struct regs_dump *regs = &sample->user_regs;
|
||||
u64 *buf;
|
||||
|
||||
buf = malloc(sizeof(u64) * PERF_REGS_MAX);
|
||||
if (!buf) {
|
||||
pr_debug("failed to allocate sample uregs data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
perf_regs_load(buf);
|
||||
regs->abi = PERF_SAMPLE_REGS_ABI;
|
||||
regs->regs = buf;
|
||||
regs->mask = PERF_REGS_MASK;
|
||||
|
||||
return sample_ustack(sample, thread, buf);
|
||||
}
|
||||
98
tools/perf/arch/x86/tests/regs_load.S
Normal file
98
tools/perf/arch/x86/tests/regs_load.S
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#include <linux/linkage.h>
|
||||
|
||||
#define AX 0
|
||||
#define BX 1 * 8
|
||||
#define CX 2 * 8
|
||||
#define DX 3 * 8
|
||||
#define SI 4 * 8
|
||||
#define DI 5 * 8
|
||||
#define BP 6 * 8
|
||||
#define SP 7 * 8
|
||||
#define IP 8 * 8
|
||||
#define FLAGS 9 * 8
|
||||
#define CS 10 * 8
|
||||
#define SS 11 * 8
|
||||
#define DS 12 * 8
|
||||
#define ES 13 * 8
|
||||
#define FS 14 * 8
|
||||
#define GS 15 * 8
|
||||
#define R8 16 * 8
|
||||
#define R9 17 * 8
|
||||
#define R10 18 * 8
|
||||
#define R11 19 * 8
|
||||
#define R12 20 * 8
|
||||
#define R13 21 * 8
|
||||
#define R14 22 * 8
|
||||
#define R15 23 * 8
|
||||
|
||||
.text
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
ENTRY(perf_regs_load)
|
||||
movq %rax, AX(%rdi)
|
||||
movq %rbx, BX(%rdi)
|
||||
movq %rcx, CX(%rdi)
|
||||
movq %rdx, DX(%rdi)
|
||||
movq %rsi, SI(%rdi)
|
||||
movq %rdi, DI(%rdi)
|
||||
movq %rbp, BP(%rdi)
|
||||
|
||||
leaq 8(%rsp), %rax /* exclude this call. */
|
||||
movq %rax, SP(%rdi)
|
||||
|
||||
movq 0(%rsp), %rax
|
||||
movq %rax, IP(%rdi)
|
||||
|
||||
movq $0, FLAGS(%rdi)
|
||||
movq $0, CS(%rdi)
|
||||
movq $0, SS(%rdi)
|
||||
movq $0, DS(%rdi)
|
||||
movq $0, ES(%rdi)
|
||||
movq $0, FS(%rdi)
|
||||
movq $0, GS(%rdi)
|
||||
|
||||
movq %r8, R8(%rdi)
|
||||
movq %r9, R9(%rdi)
|
||||
movq %r10, R10(%rdi)
|
||||
movq %r11, R11(%rdi)
|
||||
movq %r12, R12(%rdi)
|
||||
movq %r13, R13(%rdi)
|
||||
movq %r14, R14(%rdi)
|
||||
movq %r15, R15(%rdi)
|
||||
ret
|
||||
ENDPROC(perf_regs_load)
|
||||
#else
|
||||
ENTRY(perf_regs_load)
|
||||
push %edi
|
||||
movl 8(%esp), %edi
|
||||
movl %eax, AX(%edi)
|
||||
movl %ebx, BX(%edi)
|
||||
movl %ecx, CX(%edi)
|
||||
movl %edx, DX(%edi)
|
||||
movl %esi, SI(%edi)
|
||||
pop %eax
|
||||
movl %eax, DI(%edi)
|
||||
movl %ebp, BP(%edi)
|
||||
|
||||
leal 4(%esp), %eax /* exclude this call. */
|
||||
movl %eax, SP(%edi)
|
||||
|
||||
movl 0(%esp), %eax
|
||||
movl %eax, IP(%edi)
|
||||
|
||||
movl $0, FLAGS(%edi)
|
||||
movl $0, CS(%edi)
|
||||
movl $0, SS(%edi)
|
||||
movl $0, DS(%edi)
|
||||
movl $0, ES(%edi)
|
||||
movl $0, FS(%edi)
|
||||
movl $0, GS(%edi)
|
||||
ret
|
||||
ENDPROC(perf_regs_load)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We need to provide note.GNU-stack section, saying that we want
|
||||
* NOT executable stack. Otherwise the final linking will assume that
|
||||
* the ELF stack should not be restricted at all and set it RWX.
|
||||
*/
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
75
tools/perf/arch/x86/util/dwarf-regs.c
Normal file
75
tools/perf/arch/x86/util/dwarf-regs.c
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* dwarf-regs.c : Mapping of DWARF debug register numbers into register names.
|
||||
* Extracted from probe-finder.c
|
||||
*
|
||||
* Written by Masami Hiramatsu <mhiramat@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <dwarf-regs.h>
|
||||
|
||||
/*
|
||||
* Generic dwarf analysis helpers
|
||||
*/
|
||||
|
||||
#define X86_32_MAX_REGS 8
|
||||
const char *x86_32_regs_table[X86_32_MAX_REGS] = {
|
||||
"%ax",
|
||||
"%cx",
|
||||
"%dx",
|
||||
"%bx",
|
||||
"$stack", /* Stack address instead of %sp */
|
||||
"%bp",
|
||||
"%si",
|
||||
"%di",
|
||||
};
|
||||
|
||||
#define X86_64_MAX_REGS 16
|
||||
const char *x86_64_regs_table[X86_64_MAX_REGS] = {
|
||||
"%ax",
|
||||
"%dx",
|
||||
"%cx",
|
||||
"%bx",
|
||||
"%si",
|
||||
"%di",
|
||||
"%bp",
|
||||
"%sp",
|
||||
"%r8",
|
||||
"%r9",
|
||||
"%r10",
|
||||
"%r11",
|
||||
"%r12",
|
||||
"%r13",
|
||||
"%r14",
|
||||
"%r15",
|
||||
};
|
||||
|
||||
/* TODO: switching by dwarf address size */
|
||||
#ifdef __x86_64__
|
||||
#define ARCH_MAX_REGS X86_64_MAX_REGS
|
||||
#define arch_regs_table x86_64_regs_table
|
||||
#else
|
||||
#define ARCH_MAX_REGS X86_32_MAX_REGS
|
||||
#define arch_regs_table x86_32_regs_table
|
||||
#endif
|
||||
|
||||
/* Return architecture dependent register string (for kprobe-tracer) */
|
||||
const char *get_arch_regstr(unsigned int n)
|
||||
{
|
||||
return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
|
||||
}
|
||||
59
tools/perf/arch/x86/util/header.c
Normal file
59
tools/perf/arch/x86/util/header.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../util/header.h"
|
||||
|
||||
static inline void
|
||||
cpuid(unsigned int op, unsigned int *a, unsigned int *b, unsigned int *c,
|
||||
unsigned int *d)
|
||||
{
|
||||
__asm__ __volatile__ (".byte 0x53\n\tcpuid\n\t"
|
||||
"movl %%ebx, %%esi\n\t.byte 0x5b"
|
||||
: "=a" (*a),
|
||||
"=S" (*b),
|
||||
"=c" (*c),
|
||||
"=d" (*d)
|
||||
: "a" (op));
|
||||
}
|
||||
|
||||
int
|
||||
get_cpuid(char *buffer, size_t sz)
|
||||
{
|
||||
unsigned int a, b, c, d, lvl;
|
||||
int family = -1, model = -1, step = -1;
|
||||
int nb;
|
||||
char vendor[16];
|
||||
|
||||
cpuid(0, &lvl, &b, &c, &d);
|
||||
strncpy(&vendor[0], (char *)(&b), 4);
|
||||
strncpy(&vendor[4], (char *)(&d), 4);
|
||||
strncpy(&vendor[8], (char *)(&c), 4);
|
||||
vendor[12] = '\0';
|
||||
|
||||
if (lvl >= 1) {
|
||||
cpuid(1, &a, &b, &c, &d);
|
||||
|
||||
family = (a >> 8) & 0xf; /* bits 11 - 8 */
|
||||
model = (a >> 4) & 0xf; /* Bits 7 - 4 */
|
||||
step = a & 0xf;
|
||||
|
||||
/* extended family */
|
||||
if (family == 0xf)
|
||||
family += (a >> 20) & 0xff;
|
||||
|
||||
/* extended model */
|
||||
if (family >= 0x6)
|
||||
model += ((a >> 16) & 0xf) << 4;
|
||||
}
|
||||
nb = scnprintf(buffer, sz, "%s,%u,%u,%u$", vendor, family, model, step);
|
||||
|
||||
/* look for end marker to ensure the entire data fit */
|
||||
if (strchr(buffer, '$')) {
|
||||
buffer[nb-1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
156
tools/perf/arch/x86/util/kvm-stat.c
Normal file
156
tools/perf/arch/x86/util/kvm-stat.c
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
#include "../../util/kvm-stat.h"
|
||||
#include <asm/kvm_perf.h>
|
||||
|
||||
define_exit_reasons_table(vmx_exit_reasons, VMX_EXIT_REASONS);
|
||||
define_exit_reasons_table(svm_exit_reasons, SVM_EXIT_REASONS);
|
||||
|
||||
static struct kvm_events_ops exit_events = {
|
||||
.is_begin_event = exit_event_begin,
|
||||
.is_end_event = exit_event_end,
|
||||
.decode_key = exit_event_decode_key,
|
||||
.name = "VM-EXIT"
|
||||
};
|
||||
|
||||
/*
|
||||
* For the mmio events, we treat:
|
||||
* the time of MMIO write: kvm_mmio(KVM_TRACE_MMIO_WRITE...) -> kvm_entry
|
||||
* the time of MMIO read: kvm_exit -> kvm_mmio(KVM_TRACE_MMIO_READ...).
|
||||
*/
|
||||
static void mmio_event_get_key(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
struct event_key *key)
|
||||
{
|
||||
key->key = perf_evsel__intval(evsel, sample, "gpa");
|
||||
key->info = perf_evsel__intval(evsel, sample, "type");
|
||||
}
|
||||
|
||||
#define KVM_TRACE_MMIO_READ_UNSATISFIED 0
|
||||
#define KVM_TRACE_MMIO_READ 1
|
||||
#define KVM_TRACE_MMIO_WRITE 2
|
||||
|
||||
static bool mmio_event_begin(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample, struct event_key *key)
|
||||
{
|
||||
/* MMIO read begin event in kernel. */
|
||||
if (kvm_exit_event(evsel))
|
||||
return true;
|
||||
|
||||
/* MMIO write begin event in kernel. */
|
||||
if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
|
||||
perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_WRITE) {
|
||||
mmio_event_get_key(evsel, sample, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
|
||||
struct event_key *key)
|
||||
{
|
||||
/* MMIO write end event in kernel. */
|
||||
if (kvm_entry_event(evsel))
|
||||
return true;
|
||||
|
||||
/* MMIO read end event in kernel.*/
|
||||
if (!strcmp(evsel->name, "kvm:kvm_mmio") &&
|
||||
perf_evsel__intval(evsel, sample, "type") == KVM_TRACE_MMIO_READ) {
|
||||
mmio_event_get_key(evsel, sample, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
|
||||
struct event_key *key,
|
||||
char *decode)
|
||||
{
|
||||
scnprintf(decode, DECODE_STR_LEN, "%#lx:%s",
|
||||
(unsigned long)key->key,
|
||||
key->info == KVM_TRACE_MMIO_WRITE ? "W" : "R");
|
||||
}
|
||||
|
||||
static struct kvm_events_ops mmio_events = {
|
||||
.is_begin_event = mmio_event_begin,
|
||||
.is_end_event = mmio_event_end,
|
||||
.decode_key = mmio_event_decode_key,
|
||||
.name = "MMIO Access"
|
||||
};
|
||||
|
||||
/* The time of emulation pio access is from kvm_pio to kvm_entry. */
|
||||
static void ioport_event_get_key(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample,
|
||||
struct event_key *key)
|
||||
{
|
||||
key->key = perf_evsel__intval(evsel, sample, "port");
|
||||
key->info = perf_evsel__intval(evsel, sample, "rw");
|
||||
}
|
||||
|
||||
static bool ioport_event_begin(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample,
|
||||
struct event_key *key)
|
||||
{
|
||||
if (!strcmp(evsel->name, "kvm:kvm_pio")) {
|
||||
ioport_event_get_key(evsel, sample, key);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ioport_event_end(struct perf_evsel *evsel,
|
||||
struct perf_sample *sample __maybe_unused,
|
||||
struct event_key *key __maybe_unused)
|
||||
{
|
||||
return kvm_entry_event(evsel);
|
||||
}
|
||||
|
||||
static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
|
||||
struct event_key *key,
|
||||
char *decode)
|
||||
{
|
||||
scnprintf(decode, DECODE_STR_LEN, "%#llx:%s",
|
||||
(unsigned long long)key->key,
|
||||
key->info ? "POUT" : "PIN");
|
||||
}
|
||||
|
||||
static struct kvm_events_ops ioport_events = {
|
||||
.is_begin_event = ioport_event_begin,
|
||||
.is_end_event = ioport_event_end,
|
||||
.decode_key = ioport_event_decode_key,
|
||||
.name = "IO Port Access"
|
||||
};
|
||||
|
||||
const char * const kvm_events_tp[] = {
|
||||
"kvm:kvm_entry",
|
||||
"kvm:kvm_exit",
|
||||
"kvm:kvm_mmio",
|
||||
"kvm:kvm_pio",
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct kvm_reg_events_ops kvm_reg_events_ops[] = {
|
||||
{ .name = "vmexit", .ops = &exit_events },
|
||||
{ .name = "mmio", .ops = &mmio_events },
|
||||
{ .name = "ioport", .ops = &ioport_events },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
const char * const kvm_skip_events[] = {
|
||||
"HLT",
|
||||
NULL,
|
||||
};
|
||||
|
||||
int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid)
|
||||
{
|
||||
if (strstr(cpuid, "Intel")) {
|
||||
kvm->exit_reasons = vmx_exit_reasons;
|
||||
kvm->exit_reasons_isa = "VMX";
|
||||
} else if (strstr(cpuid, "AMD")) {
|
||||
kvm->exit_reasons = svm_exit_reasons;
|
||||
kvm->exit_reasons_isa = "SVM";
|
||||
} else
|
||||
return -ENOTSUP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
48
tools/perf/arch/x86/util/tsc.c
Normal file
48
tools/perf/arch/x86/util/tsc.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
#include "../../perf.h"
|
||||
#include <linux/types.h>
|
||||
#include "../../util/debug.h"
|
||||
#include "../../util/tsc.h"
|
||||
#include "tsc.h"
|
||||
|
||||
int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
|
||||
struct perf_tsc_conversion *tc)
|
||||
{
|
||||
bool cap_user_time_zero;
|
||||
u32 seq;
|
||||
int i = 0;
|
||||
|
||||
while (1) {
|
||||
seq = pc->lock;
|
||||
rmb();
|
||||
tc->time_mult = pc->time_mult;
|
||||
tc->time_shift = pc->time_shift;
|
||||
tc->time_zero = pc->time_zero;
|
||||
cap_user_time_zero = pc->cap_user_time_zero;
|
||||
rmb();
|
||||
if (pc->lock == seq && !(seq & 1))
|
||||
break;
|
||||
if (++i > 10000) {
|
||||
pr_debug("failed to get perf_event_mmap_page lock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cap_user_time_zero)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 rdtsc(void)
|
||||
{
|
||||
unsigned int low, high;
|
||||
|
||||
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
||||
|
||||
return low | ((u64)high) << 32;
|
||||
}
|
||||
17
tools/perf/arch/x86/util/tsc.h
Normal file
17
tools/perf/arch/x86/util/tsc.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
|
||||
#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct perf_tsc_conversion {
|
||||
u16 time_shift;
|
||||
u32 time_mult;
|
||||
u64 time_zero;
|
||||
};
|
||||
|
||||
struct perf_event_mmap_page;
|
||||
|
||||
int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
|
||||
struct perf_tsc_conversion *tc);
|
||||
|
||||
#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
|
||||
51
tools/perf/arch/x86/util/unwind-libdw.c
Normal file
51
tools/perf/arch/x86/util/unwind-libdw.c
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <elfutils/libdwfl.h>
|
||||
#include "../../util/unwind-libdw.h"
|
||||
#include "../../util/perf_regs.h"
|
||||
|
||||
bool libdw__arch_set_initial_registers(Dwfl_Thread *thread, void *arg)
|
||||
{
|
||||
struct unwind_info *ui = arg;
|
||||
struct regs_dump *user_regs = &ui->sample->user_regs;
|
||||
Dwarf_Word dwarf_regs[17];
|
||||
unsigned nregs;
|
||||
|
||||
#define REG(r) ({ \
|
||||
Dwarf_Word val = 0; \
|
||||
perf_reg_value(&val, user_regs, PERF_REG_X86_##r); \
|
||||
val; \
|
||||
})
|
||||
|
||||
if (user_regs->abi == PERF_SAMPLE_REGS_ABI_32) {
|
||||
dwarf_regs[0] = REG(AX);
|
||||
dwarf_regs[1] = REG(CX);
|
||||
dwarf_regs[2] = REG(DX);
|
||||
dwarf_regs[3] = REG(BX);
|
||||
dwarf_regs[4] = REG(SP);
|
||||
dwarf_regs[5] = REG(BP);
|
||||
dwarf_regs[6] = REG(SI);
|
||||
dwarf_regs[7] = REG(DI);
|
||||
dwarf_regs[8] = REG(IP);
|
||||
nregs = 9;
|
||||
} else {
|
||||
dwarf_regs[0] = REG(AX);
|
||||
dwarf_regs[1] = REG(DX);
|
||||
dwarf_regs[2] = REG(CX);
|
||||
dwarf_regs[3] = REG(BX);
|
||||
dwarf_regs[4] = REG(SI);
|
||||
dwarf_regs[5] = REG(DI);
|
||||
dwarf_regs[6] = REG(BP);
|
||||
dwarf_regs[7] = REG(SP);
|
||||
dwarf_regs[8] = REG(R8);
|
||||
dwarf_regs[9] = REG(R9);
|
||||
dwarf_regs[10] = REG(R10);
|
||||
dwarf_regs[11] = REG(R11);
|
||||
dwarf_regs[12] = REG(R12);
|
||||
dwarf_regs[13] = REG(R13);
|
||||
dwarf_regs[14] = REG(R14);
|
||||
dwarf_regs[15] = REG(R15);
|
||||
dwarf_regs[16] = REG(IP);
|
||||
nregs = 17;
|
||||
}
|
||||
|
||||
return dwfl_thread_state_registers(thread, 0, nregs, dwarf_regs);
|
||||
}
|
||||
112
tools/perf/arch/x86/util/unwind-libunwind.c
Normal file
112
tools/perf/arch/x86/util/unwind-libunwind.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <libunwind.h>
|
||||
#include "perf_regs.h"
|
||||
#include "../../util/unwind.h"
|
||||
#include "../../util/debug.h"
|
||||
|
||||
#ifdef HAVE_ARCH_X86_64_SUPPORT
|
||||
int libunwind__arch_reg_id(int regnum)
|
||||
{
|
||||
int id;
|
||||
|
||||
switch (regnum) {
|
||||
case UNW_X86_64_RAX:
|
||||
id = PERF_REG_X86_AX;
|
||||
break;
|
||||
case UNW_X86_64_RDX:
|
||||
id = PERF_REG_X86_DX;
|
||||
break;
|
||||
case UNW_X86_64_RCX:
|
||||
id = PERF_REG_X86_CX;
|
||||
break;
|
||||
case UNW_X86_64_RBX:
|
||||
id = PERF_REG_X86_BX;
|
||||
break;
|
||||
case UNW_X86_64_RSI:
|
||||
id = PERF_REG_X86_SI;
|
||||
break;
|
||||
case UNW_X86_64_RDI:
|
||||
id = PERF_REG_X86_DI;
|
||||
break;
|
||||
case UNW_X86_64_RBP:
|
||||
id = PERF_REG_X86_BP;
|
||||
break;
|
||||
case UNW_X86_64_RSP:
|
||||
id = PERF_REG_X86_SP;
|
||||
break;
|
||||
case UNW_X86_64_R8:
|
||||
id = PERF_REG_X86_R8;
|
||||
break;
|
||||
case UNW_X86_64_R9:
|
||||
id = PERF_REG_X86_R9;
|
||||
break;
|
||||
case UNW_X86_64_R10:
|
||||
id = PERF_REG_X86_R10;
|
||||
break;
|
||||
case UNW_X86_64_R11:
|
||||
id = PERF_REG_X86_R11;
|
||||
break;
|
||||
case UNW_X86_64_R12:
|
||||
id = PERF_REG_X86_R12;
|
||||
break;
|
||||
case UNW_X86_64_R13:
|
||||
id = PERF_REG_X86_R13;
|
||||
break;
|
||||
case UNW_X86_64_R14:
|
||||
id = PERF_REG_X86_R14;
|
||||
break;
|
||||
case UNW_X86_64_R15:
|
||||
id = PERF_REG_X86_R15;
|
||||
break;
|
||||
case UNW_X86_64_RIP:
|
||||
id = PERF_REG_X86_IP;
|
||||
break;
|
||||
default:
|
||||
pr_err("unwind: invalid reg id %d\n", regnum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
#else
|
||||
int libunwind__arch_reg_id(int regnum)
|
||||
{
|
||||
int id;
|
||||
|
||||
switch (regnum) {
|
||||
case UNW_X86_EAX:
|
||||
id = PERF_REG_X86_AX;
|
||||
break;
|
||||
case UNW_X86_EDX:
|
||||
id = PERF_REG_X86_DX;
|
||||
break;
|
||||
case UNW_X86_ECX:
|
||||
id = PERF_REG_X86_CX;
|
||||
break;
|
||||
case UNW_X86_EBX:
|
||||
id = PERF_REG_X86_BX;
|
||||
break;
|
||||
case UNW_X86_ESI:
|
||||
id = PERF_REG_X86_SI;
|
||||
break;
|
||||
case UNW_X86_EDI:
|
||||
id = PERF_REG_X86_DI;
|
||||
break;
|
||||
case UNW_X86_EBP:
|
||||
id = PERF_REG_X86_BP;
|
||||
break;
|
||||
case UNW_X86_ESP:
|
||||
id = PERF_REG_X86_SP;
|
||||
break;
|
||||
case UNW_X86_EIP:
|
||||
id = PERF_REG_X86_IP;
|
||||
break;
|
||||
default:
|
||||
pr_err("unwind: invalid reg id %d\n", regnum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
#endif /* HAVE_ARCH_X86_64_SUPPORT */
|
||||
Loading…
Add table
Add a link
Reference in a new issue