We're going to need PSR bit defines and pt_regs. We'll also need pt_regs offsets in assembly code. This patch adapts the Linux kernel's ptrace.h and generated/asm-offsets.h to this framework. It also adapts cp15.h from the kernel, since we'll need bit defines from there too.
Signed-off-by: Andrew Jones <drjo...@redhat.com> Acked-by: Christoffer Dall <christoffer.d...@linaro.org> --- v4: much improved asm-offsets.h generation based on Kbuild --- config/asm-offsets.mak | 41 +++++++++++++++++++ config/config-arm.mak | 9 ++++- lib/arm/.gitignore | 1 + lib/arm/asm-offsets.c | 39 ++++++++++++++++++ lib/arm/asm/asm-offsets.h | 1 + lib/arm/asm/cp15.h | 37 +++++++++++++++++ lib/arm/asm/ptrace.h | 100 ++++++++++++++++++++++++++++++++++++++++++++++ lib/generated/.gitignore | 1 + 8 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 config/asm-offsets.mak create mode 100644 lib/arm/.gitignore create mode 100644 lib/arm/asm-offsets.c create mode 100644 lib/arm/asm/asm-offsets.h create mode 100644 lib/arm/asm/cp15.h create mode 100644 lib/arm/asm/ptrace.h create mode 100644 lib/generated/.gitignore diff --git a/config/asm-offsets.mak b/config/asm-offsets.mak new file mode 100644 index 0000000000000..b2578a6692f33 --- /dev/null +++ b/config/asm-offsets.mak @@ -0,0 +1,41 @@ +# +# asm-offsets adapted from the kernel, see +# Kbuild +# scripts/Kbuild.include +# scripts/Makefile.build +# +# Authors: Andrew Jones <drjo...@redhat.com> +# + +define sed-y + "/^->/{s:->#\(.*\):/* \1 */:; \ + s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ + s:->::; p;}" +endef + +define make_asm_offsets + (set -e; \ + echo "#ifndef __ASM_OFFSETS_H__"; \ + echo "#define __ASM_OFFSETS_H__"; \ + echo "/*"; \ + echo " * Generated file. DO NOT MODIFY."; \ + echo " *"; \ + echo " */"; \ + echo ""; \ + sed -ne $(sed-y) $<; \ + echo ""; \ + echo "#endif" ) > $@ +endef + +$(asm-offsets:.h=.s): $(asm-offsets:.h=.c) + $(CC) $(CFLAGS) -fverbose-asm -S -o $@ $< + +$(asm-offsets): $(asm-offsets:.h=.s) + $(call make_asm_offsets) + cp -f $(asm-offsets) lib/generated + +asm_offsets_clean: + $(RM) $(asm-offsets) $(asm-offsets:.h=.s) \ + $(addprefix lib/generated/,$(notdir $(asm-offsets))) + diff --git a/config/config-arm.mak b/config/config-arm.mak index d150807ec6fe4..ead191f4954f4 100644 --- a/config/config-arm.mak +++ b/config/config-arm.mak @@ -30,6 +30,9 @@ CFLAGS += -Wextra CFLAGS += -O2 CFLAGS += -I lib -I lib/libfdt +asm-offsets = lib/arm/asm-offsets.h +include config/asm-offsets.mak + cflatobjs += \ lib/devicetree.o \ lib/virtio.o \ @@ -57,7 +60,7 @@ FLATLIBS = $(libcflat) $(LIBFDT_archive) $(libgcc) $(libeabi) $(libeabi): $(eabiobjs) $(AR) rcs $@ $^ -arch_clean: libfdt_clean +arch_clean: libfdt_clean asm_offsets_clean $(RM) $(TEST_DIR)/*.{o,flat,elf} $(libeabi) $(eabiobjs) \ $(TEST_DIR)/.*.d lib/arm/.*.d @@ -67,7 +70,9 @@ tests_and_config = $(TEST_DIR)/*.flat $(TEST_DIR)/unittests.cfg cstart.o = $(TEST_DIR)/cstart.o -test_cases: $(tests-common) $(tests) +generated_files = $(asm-offsets) + +test_cases: $(generated_files) $(tests-common) $(tests) $(TEST_DIR)/selftest.elf: $(cstart.o) $(TEST_DIR)/selftest.o diff --git a/lib/arm/.gitignore b/lib/arm/.gitignore new file mode 100644 index 0000000000000..84872bf197c67 --- /dev/null +++ b/lib/arm/.gitignore @@ -0,0 +1 @@ +asm-offsets.[hs] diff --git a/lib/arm/asm-offsets.c b/lib/arm/asm-offsets.c new file mode 100644 index 0000000000000..a9c349d2d427c --- /dev/null +++ b/lib/arm/asm-offsets.c @@ -0,0 +1,39 @@ +/* + * Adapted from arch/arm/kernel/asm-offsets.c + * + * Copyright (C) 2014, Red Hat Inc, Andrew Jones <drjo...@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include "libcflat.h" +#include "asm/ptrace.h" + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) +#define OFFSET(sym, str, mem) DEFINE(sym, offsetof(struct str, mem)) +#define COMMENT(x) asm volatile("\n->#" x) +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + OFFSET(S_R0, pt_regs, ARM_r0); + OFFSET(S_R1, pt_regs, ARM_r1); + OFFSET(S_R2, pt_regs, ARM_r2); + OFFSET(S_R3, pt_regs, ARM_r3); + OFFSET(S_R4, pt_regs, ARM_r4); + OFFSET(S_R5, pt_regs, ARM_r5); + OFFSET(S_R6, pt_regs, ARM_r6); + OFFSET(S_R7, pt_regs, ARM_r7); + OFFSET(S_R8, pt_regs, ARM_r8); + OFFSET(S_R9, pt_regs, ARM_r9); + OFFSET(S_R10, pt_regs, ARM_r10); + OFFSET(S_FP, pt_regs, ARM_fp); + OFFSET(S_IP, pt_regs, ARM_ip); + OFFSET(S_SP, pt_regs, ARM_sp); + OFFSET(S_LR, pt_regs, ARM_lr); + OFFSET(S_PC, pt_regs, ARM_pc); + OFFSET(S_PSR, pt_regs, ARM_cpsr); + OFFSET(S_OLD_R0, pt_regs, ARM_ORIG_r0); + DEFINE(S_FRAME_SIZE, sizeof(struct pt_regs)); + return 0; +} diff --git a/lib/arm/asm/asm-offsets.h b/lib/arm/asm/asm-offsets.h new file mode 100644 index 0000000000000..c2ff2ba6ec417 --- /dev/null +++ b/lib/arm/asm/asm-offsets.h @@ -0,0 +1 @@ +#include "generated/asm-offsets.h" diff --git a/lib/arm/asm/cp15.h b/lib/arm/asm/cp15.h new file mode 100644 index 0000000000000..7690a48f17f1f --- /dev/null +++ b/lib/arm/asm/cp15.h @@ -0,0 +1,37 @@ +#ifndef _ASMARM_CP15_H_ +#define _ASMARM_CP15_H_ +/* + * From the Linux kernel arch/arm/include/asm/cp15.h + * + * CR1 bits (CP#15 CR1) + */ +#define CR_M (1 << 0) /* MMU enable */ +#define CR_A (1 << 1) /* Alignment abort enable */ +#define CR_C (1 << 2) /* Dcache enable */ +#define CR_W (1 << 3) /* Write buffer enable */ +#define CR_P (1 << 4) /* 32-bit exception handler */ +#define CR_D (1 << 5) /* 32-bit data address range */ +#define CR_L (1 << 6) /* Implementation defined */ +#define CR_B (1 << 7) /* Big endian */ +#define CR_S (1 << 8) /* System MMU protection */ +#define CR_R (1 << 9) /* ROM MMU protection */ +#define CR_F (1 << 10) /* Implementation defined */ +#define CR_Z (1 << 11) /* Implementation defined */ +#define CR_I (1 << 12) /* Icache enable */ +#define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */ +#define CR_RR (1 << 14) /* Round Robin cache replacement */ +#define CR_L4 (1 << 15) /* LDR pc can set T bit */ +#define CR_DT (1 << 16) +#define CR_HA (1 << 17) /* Hardware management of Access Flag */ +#define CR_IT (1 << 18) +#define CR_ST (1 << 19) +#define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */ +#define CR_U (1 << 22) /* Unaligned access operation */ +#define CR_XP (1 << 23) /* Extended page tables */ +#define CR_VE (1 << 24) /* Vectored interrupts */ +#define CR_EE (1 << 25) /* Exception (Big) Endian */ +#define CR_TRE (1 << 28) /* TEX remap enable */ +#define CR_AFE (1 << 29) /* Access flag enable */ +#define CR_TE (1 << 30) /* Thumb exception enable */ + +#endif /* _ASMARM_CP15_H_ */ diff --git a/lib/arm/asm/ptrace.h b/lib/arm/asm/ptrace.h new file mode 100644 index 0000000000000..3a4c7532258f6 --- /dev/null +++ b/lib/arm/asm/ptrace.h @@ -0,0 +1,100 @@ +#ifndef _ASMARM_PTRACE_H_ +#define _ASMARM_PTRACE_H_ +/* + * Adapted from Linux kernel headers + * arch/arm/include/asm/ptrace.h + * arch/arm/include/uapi/asm/ptrace.h + */ + +/* + * PSR bits + */ +#define USR_MODE 0x00000010 +#define SVC_MODE 0x00000013 +#define FIQ_MODE 0x00000011 +#define IRQ_MODE 0x00000012 +#define ABT_MODE 0x00000017 +#define HYP_MODE 0x0000001a +#define UND_MODE 0x0000001b +#define SYSTEM_MODE 0x0000001f +#define MODE32_BIT 0x00000010 +#define MODE_MASK 0x0000001f + +#define PSR_T_BIT 0x00000020 /* >= V4T, but not V7M */ +#define PSR_F_BIT 0x00000040 /* >= V4, but not V7M */ +#define PSR_I_BIT 0x00000080 /* >= V4, but not V7M */ +#define PSR_A_BIT 0x00000100 /* >= V6, but not V7M */ +#define PSR_E_BIT 0x00000200 /* >= V6, but not V7M */ +#define PSR_J_BIT 0x01000000 /* >= V5J, but not V7M */ +#define PSR_Q_BIT 0x08000000 /* >= V5E, including V7M */ +#define PSR_V_BIT 0x10000000 +#define PSR_C_BIT 0x20000000 +#define PSR_Z_BIT 0x40000000 +#define PSR_N_BIT 0x80000000 + +/* + * Groups of PSR bits + */ +#define PSR_f 0xff000000 /* Flags */ +#define PSR_s 0x00ff0000 /* Status */ +#define PSR_x 0x0000ff00 /* Extension */ +#define PSR_c 0x000000ff /* Control */ + +/* + * ARMv7 groups of PSR bits + */ +#define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ +#define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ +#define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ +#define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ + +#ifndef __ASSEMBLY__ +#include "libcflat.h" + +struct pt_regs { + unsigned long uregs[18]; +}; + +#define ARM_cpsr uregs[16] +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[17] + +#define user_mode(regs) \ + (((regs)->ARM_cpsr & 0xf) == 0) + +#define processor_mode(regs) \ + ((regs)->ARM_cpsr & MODE_MASK) + +#define interrupts_enabled(regs) \ + (!((regs)->ARM_cpsr & PSR_I_BIT)) + +#define fast_interrupts_enabled(regs) \ + (!((regs)->ARM_cpsr & PSR_F_BIT)) + +#define MAX_REG_OFFSET (offsetof(struct pt_regs, ARM_ORIG_r0)) + +static inline unsigned long regs_get_register(struct pt_regs *regs, + unsigned int offset) +{ + if (offset > MAX_REG_OFFSET) + return 0; + return *(unsigned long *)((unsigned long)regs + offset); +} + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASMARM_PTRACE_H_ */ diff --git a/lib/generated/.gitignore b/lib/generated/.gitignore new file mode 100644 index 0000000000000..72e8ffc0db8aa --- /dev/null +++ b/lib/generated/.gitignore @@ -0,0 +1 @@ +* -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html