Mailing List Archive

[xen master] xen/arm: add support for run_in_exception_handler()
commit c8d4b6304a5ee22bfd8a207973199b379c36604e
Author: Juergen Gross <jgross@suse.com>
AuthorDate: Sat Jan 16 11:33:37 2021 +0100
Commit: Julien Grall <jgrall@amazon.com>
CommitDate: Sat Jan 23 11:30:32 2021 +0000

xen/arm: add support for run_in_exception_handler()

Add support to run a function in an exception handler for Arm. Do it
as on x86 via a bug_frame, but pass the function pointer via a
register.
This needs to be done that way because GCC will not allow to use
"i" when PIE is enabled (Xen doesn't set the flag but instead rely on
the default value from the compiler).

Use the same BUGFRAME_* #defines as on x86 in order to make a future
common header file more easily achievable.

Signed-off-by: Juergen Gross <jgross@suse.com>
[. julien: Add more details on the issue between "i" and -fpie ]
Acked-by: Julien GralL <jgrall@amazon.com>
---
xen/arch/arm/traps.c | 8 ++++++++
xen/arch/arm/xen.lds.S | 2 ++
xen/common/virtual_region.c | 2 --
xen/include/asm-arm/arm32/bug.h | 2 ++
xen/include/asm-arm/arm64/bug.h | 2 ++
xen/include/asm-arm/bug.h | 32 ++++++++++++++++++++++++++------
6 files changed, 40 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 1af1bb9f1b..d0df33b218 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1236,6 +1236,14 @@ int do_bug_frame(const struct cpu_user_regs *regs, vaddr_t pc)
if ( !bug )
return -ENOENT;

+ if ( id == BUGFRAME_run_fn )
+ {
+ void (*fn)(const struct cpu_user_regs *) = (void *)regs->BUG_FN_REG;
+
+ fn(regs);
+ return 0;
+ }
+
/* WARN, BUG or ASSERT: decode the filename pointer and line number. */
filename = bug_file(bug);
if ( !is_kernel(filename) )
diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
index 6342ac4ead..004b182acb 100644
--- a/xen/arch/arm/xen.lds.S
+++ b/xen/arch/arm/xen.lds.S
@@ -49,6 +49,8 @@ SECTIONS
__stop_bug_frames_1 = .;
*(.bug_frames.2)
__stop_bug_frames_2 = .;
+ *(.bug_frames.3)
+ __stop_bug_frames_3 = .;
*(.rodata)
*(.rodata.*)
*(.data.rel.ro)
diff --git a/xen/common/virtual_region.c b/xen/common/virtual_region.c
index 4fbc02e35a..30b0b4ab9c 100644
--- a/xen/common/virtual_region.c
+++ b/xen/common/virtual_region.c
@@ -123,9 +123,7 @@ void __init setup_virtual_regions(const struct exception_table_entry *start,
__stop_bug_frames_0,
__stop_bug_frames_1,
__stop_bug_frames_2,
-#ifdef CONFIG_X86
__stop_bug_frames_3,
-#endif
NULL
};

diff --git a/xen/include/asm-arm/arm32/bug.h b/xen/include/asm-arm/arm32/bug.h
index 3e66f35969..25cce151dc 100644
--- a/xen/include/asm-arm/arm32/bug.h
+++ b/xen/include/asm-arm/arm32/bug.h
@@ -10,4 +10,6 @@

#define BUG_INSTR ".word " __stringify(BUG_OPCODE)

+#define BUG_FN_REG r0
+
#endif /* __ARM_ARM32_BUG_H__ */
diff --git a/xen/include/asm-arm/arm64/bug.h b/xen/include/asm-arm/arm64/bug.h
index 59f664d7de..5e11c0dfd5 100644
--- a/xen/include/asm-arm/arm64/bug.h
+++ b/xen/include/asm-arm/arm64/bug.h
@@ -6,4 +6,6 @@

#define BUG_INSTR "brk " __stringify(BRK_BUG_FRAME_IMM)

+#define BUG_FN_REG x0
+
#endif /* __ARM_ARM64_BUG_H__ */
diff --git a/xen/include/asm-arm/bug.h b/xen/include/asm-arm/bug.h
index 36c803357c..f4088d0913 100644
--- a/xen/include/asm-arm/bug.h
+++ b/xen/include/asm-arm/bug.h
@@ -26,16 +26,17 @@ struct bug_frame {
#define bug_line(b) ((b)->line)
#define bug_msg(b) ((const char *)(b) + (b)->msg_disp)

-#define BUGFRAME_warn 0
-#define BUGFRAME_bug 1
-#define BUGFRAME_assert 2
+#define BUGFRAME_run_fn 0
+#define BUGFRAME_warn 1
+#define BUGFRAME_bug 2
+#define BUGFRAME_assert 3

-#define BUGFRAME_NR 3
+#define BUGFRAME_NR 4

/* Many versions of GCC doesn't support the asm %c parameter which would
* be preferable to this unpleasantness. We use mergeable string
* sections to avoid multiple copies of the string appearing in the
- * Xen image.
+ * Xen image. BUGFRAME_run_fn needs to be handled separately.
*/
#define BUG_FRAME(type, line, file, has_msg, msg) do { \
BUILD_BUG_ON((line) >> 16); \
@@ -58,6 +59,24 @@ struct bug_frame {
".popsection"); \
} while (0)

+/*
+ * GCC will not allow to use "i" when PIE is enabled (Xen doesn't set the
+ * flag but instead rely on the default value from the compiler). So the
+ * easiest way to implement run_in_exception_handler() is to pass the to
+ * be called function in a fixed register.
+ */
+#define run_in_exception_handler(fn) do { \
+ asm ("mov " __stringify(BUG_FN_REG) ", %0\n" \
+ "1:"BUG_INSTR"\n" \
+ ".pushsection .bug_frames." __stringify(BUGFRAME_run_fn) "," \
+ " \"a\", %%progbits\n" \
+ "2:\n" \
+ ".p2align 2\n" \
+ ".long (1b - 2b)\n" \
+ ".long 0, 0, 0\n" \
+ ".popsection" :: "r" (fn) : __stringify(BUG_FN_REG) ); \
+} while (0)
+
#define WARN() BUG_FRAME(BUGFRAME_warn, __LINE__, __FILE__, 0, "")

#define BUG() do { \
@@ -73,7 +92,8 @@ struct bug_frame {
extern const struct bug_frame __start_bug_frames[],
__stop_bug_frames_0[],
__stop_bug_frames_1[],
- __stop_bug_frames_2[];
+ __stop_bug_frames_2[],
+ __stop_bug_frames_3[];

#endif /* __ARM_BUG_H__ */
/*
--
generated by git-patchbot for /home/xen/git/xen.git#master