From patchwork Tue Mar 15 17:56:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Rzeszutek Wilk X-Patchwork-Id: 8591081 Return-Path: X-Original-To: patchwork-xen-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E2CFAC0553 for ; Tue, 15 Mar 2016 18:02:21 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 460872037F for ; Tue, 15 Mar 2016 18:02:20 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C3E8720357 for ; Tue, 15 Mar 2016 18:02:17 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1aftGm-0001Sl-K9; Tue, 15 Mar 2016 18:00:36 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1aftGk-0001JQ-KT for xen-devel@lists.xenproject.org; Tue, 15 Mar 2016 18:00:34 +0000 Received: from [85.158.139.211] by server-4.bemta-5.messagelabs.com id AD/71-20731-1CD48E65; Tue, 15 Mar 2016 18:00:33 +0000 X-Env-Sender: konrad@char.us.oracle.com X-Msg-Ref: server-13.tower-206.messagelabs.com!1458064831!28949465!1 X-Originating-IP: [156.151.31.81] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogMTU2LjE1MS4zMS44MSA9PiAyODgzMzk=\n X-StarScan-Received: X-StarScan-Version: 8.11; banners=-,-,- X-VirusChecked: Checked Received: (qmail 37008 invoked from network); 15 Mar 2016 18:00:32 -0000 Received: from userp1040.oracle.com (HELO userp1040.oracle.com) (156.151.31.81) by server-13.tower-206.messagelabs.com with DHE-RSA-AES256-GCM-SHA384 encrypted SMTP; 15 Mar 2016 18:00:32 -0000 Received: from aserv0022.oracle.com (aserv0022.oracle.com [141.146.126.234]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id u2FI0JQ1011543 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Tue, 15 Mar 2016 18:00:20 GMT Received: from userv0122.oracle.com (userv0122.oracle.com [156.151.31.75]) by aserv0022.oracle.com (8.13.8/8.13.8) with ESMTP id u2FI0JRo013508 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); Tue, 15 Mar 2016 18:00:19 GMT Received: from abhmp0006.oracle.com (abhmp0006.oracle.com [141.146.116.12]) by userv0122.oracle.com (8.14.4/8.14.4) with ESMTP id u2FI0IJO001353; Tue, 15 Mar 2016 18:00:18 GMT Received: from char.us.oracle.com (/10.137.176.158) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 15 Mar 2016 11:00:18 -0700 Received: by char.us.oracle.com (Postfix, from userid 1000) id D50C76A00C6; Tue, 15 Mar 2016 13:59:08 -0400 (EDT) From: Konrad Rzeszutek Wilk To: xen-devel@lists.xenproject.org, ross.lagerwall@citrix.com, konrad@kernel.org, andrew.cooper3@citrix.com, mpohlack@amazon.de, sasha.levin@oracle.com Date: Tue, 15 Mar 2016 13:56:29 -0400 Message-Id: <1458064616-23101-8-git-send-email-konrad.wilk@oracle.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1458064616-23101-1-git-send-email-konrad.wilk@oracle.com> References: <1458064616-23101-1-git-send-email-konrad.wilk@oracle.com> X-Source-IP: aserv0022.oracle.com [141.146.126.234] Cc: Keir Fraser , Julien Grall , Stefano Stabellini , Jan Beulich , Konrad Rzeszutek Wilk Subject: [Xen-devel] [PATCH v4 07/34] arm/x86: Use struct virtual_region to do bug, symbol, and (x86) exception tables X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP lookup. During execution of the hypervisor we have two regions of executable code - stext -> _etext, and _sinittext -> _einitext. The later is not needed after bootup. We also have various built-in macros and functions to search in between those two swaths depending on the state of the system. That is either for bug_frames, exceptions (x86) or symbol names for the instruction. With xSplice in the picture - we need a mechansim for new payloads to searched as well for all of this. Originally we had extra 'if (xsplice)...' but that gets a bit tiring and does not hook up nicely. This 'struct virtual_region' and virtual_region_list provide a mechanism to search for the bug_frames,exception table, and symbol names entries without having various calls in other sub-components in the system. Code which wishes to participate in bug_frames and exception table entries search has to only use two public APIs: - register_virtual_region - unregister_virtual_region to let the core code know. Furthermore there are also overrides via the .skip function. There are three possible flags that can be passed in - depending on what kind of search is being done. A return of 1 means skip this region. If the .skip is NULL the region will be considered. The ->lookup_symbol will only be used if ->skip returns 1 for CHECKING_SYMBOLS (and of course if it points to a function). Otherwise the default internal symbol lookup mechanism is used. Suggested-by: Andrew Cooper Signed-off-by: Konrad Rzeszutek Wilk --- Cc: Stefano Stabellini Cc: Julien Grall Cc: Keir Fraser Cc: Jan Beulich Cc: Andrew Cooper --- --- xen/arch/arm/traps.c | 45 ++++++++++----- xen/arch/x86/extable.c | 16 +++++- xen/arch/x86/setup.c | 3 +- xen/arch/x86/traps.c | 46 +++++++++------ xen/common/Makefile | 1 + xen/common/bug_ex_symbols.c | 119 +++++++++++++++++++++++++++++++++++++++ xen/common/symbols.c | 29 +++++++++- xen/include/xen/bug_ex_symbols.h | 74 ++++++++++++++++++++++++ xen/include/xen/kernel.h | 2 + xen/include/xen/symbols.h | 9 +++ 10 files changed, 307 insertions(+), 37 deletions(-) create mode 100644 xen/common/bug_ex_symbols.c create mode 100644 xen/include/xen/bug_ex_symbols.h diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 31d2115..b62c91f 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -16,6 +16,7 @@ * GNU General Public License for more details. */ +#include #include #include #include @@ -101,6 +102,8 @@ integer_param("debug_stack_lines", debug_stack_lines); void init_traps(void) { + setup_virtual_regions(); + /* Setup Hyp vector base */ WRITE_SYSREG((vaddr_t)hyp_traps_vector, VBAR_EL2); @@ -1077,27 +1080,39 @@ void do_unexpected_trap(const char *msg, struct cpu_user_regs *regs) int do_bug_frame(struct cpu_user_regs *regs, vaddr_t pc) { - const struct bug_frame *bug; + const struct bug_frame *bug = NULL; const char *prefix = "", *filename, *predicate; unsigned long fixup; - int id, lineno; - static const struct bug_frame *const stop_frames[] = { - __stop_bug_frames_0, - __stop_bug_frames_1, - __stop_bug_frames_2, - NULL - }; + int id = -1, lineno; + struct virtual_region *region; - for ( bug = __start_bug_frames, id = 0; stop_frames[id]; ++bug ) + list_for_each_entry( region, &virtual_region_list, list ) { - while ( unlikely(bug == stop_frames[id]) ) - ++id; + unsigned int i; - if ( ((vaddr_t)bug_loc(bug)) == pc ) - break; - } + if ( region->skip && region->skip(CHECKING_BUG_FRAME, region->priv) ) + continue; + + if ( pc < region->start || pc > region->end ) + continue; - if ( !stop_frames[id] ) + for ( id = 0; id < BUGFRAME_NR; id++ ) + { + const struct bug_frame *b = NULL; + + for ( i = 0, b = region->frame[id].bugs; + i < region->frame[id].n_bugs; b++, i++ ) + { + if ( ((vaddr_t)bug_loc(b)) == pc ) + { + bug = b; + goto found; + } + } + } + } + found: + if ( !bug ) return -ENOENT; /* WARN, BUG or ASSERT: decode the filename pointer and line number. */ diff --git a/xen/arch/x86/extable.c b/xen/arch/x86/extable.c index 89b5bcb..6e083a8 100644 --- a/xen/arch/x86/extable.c +++ b/xen/arch/x86/extable.c @@ -1,6 +1,8 @@ +#include #include #include +#include #include #include #include @@ -80,8 +82,18 @@ search_one_table(const struct exception_table_entry *first, unsigned long search_exception_table(unsigned long addr) { - return search_one_table( - __start___ex_table, __stop___ex_table-1, addr); + struct virtual_region *region; + + list_for_each_entry( region, &virtual_region_list, list ) + { + if ( region->skip && region->skip(CHECKING_EXCEPTION, region->priv) ) + continue; + + if ( (addr >= region->start) && (addr < region->end) ) + return search_one_table(region->ex, region->ex_end-1, addr); + } + + return 0; } unsigned long diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index a8bf2c9..115e6fd 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -614,8 +615,8 @@ void __init noreturn __start_xen(unsigned long mbi_p) load_system_tables(); smp_prepare_boot_cpu(); - sort_exception_tables(); + setup_virtual_regions(); /* Full exception support from here on in. */ loader = (mbi->flags & MBI_LOADERNAME) diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 564a107..eeada97 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -24,6 +24,7 @@ * Gareth Hughes , May 2000 */ +#include #include #include #include @@ -1132,18 +1133,12 @@ static int emulate_forced_invalid_op(struct cpu_user_regs *regs) void do_invalid_op(struct cpu_user_regs *regs) { - const struct bug_frame *bug; + const struct bug_frame *bug = NULL; u8 bug_insn[2]; const char *prefix = "", *filename, *predicate, *eip = (char *)regs->eip; unsigned long fixup; - int id, lineno; - static const struct bug_frame *const stop_frames[] = { - __stop_bug_frames_0, - __stop_bug_frames_1, - __stop_bug_frames_2, - __stop_bug_frames_3, - NULL - }; + int id = -1, lineno; + struct virtual_region *region; DEBUGGER_trap_entry(TRAP_invalid_op, regs); @@ -1160,16 +1155,35 @@ void do_invalid_op(struct cpu_user_regs *regs) memcmp(bug_insn, "\xf\xb", sizeof(bug_insn)) ) goto die; - for ( bug = __start_bug_frames, id = 0; stop_frames[id]; ++bug ) + list_for_each_entry( region, &virtual_region_list, list ) { - while ( unlikely(bug == stop_frames[id]) ) - ++id; - if ( bug_loc(bug) == eip ) - break; + unsigned int i; + + if ( region->skip && region->skip(CHECKING_BUG_FRAME, region->priv) ) + continue; + + if ( regs->eip < region->start || regs->eip > region->end ) + continue; + + for ( id = 0; id < BUGFRAME_NR; id++ ) + { + const struct bug_frame *b = NULL; + + for ( i = 0, b = region->frame[id].bugs; + i < region->frame[id].n_bugs; b++, i++ ) + { + if ( bug_loc(b) == eip ) + { + bug = b; + goto found; + } + } + } } - if ( !stop_frames[id] ) - goto die; + found: + if ( !bug ) + goto die; eip += sizeof(bug_insn); if ( id == BUGFRAME_run_fn ) { diff --git a/xen/common/Makefile b/xen/common/Makefile index 82625a5..76d7b07 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -1,4 +1,5 @@ obj-y += bitmap.o +obj-y += bug_ex_symbols.o obj-$(CONFIG_CORE_PARKING) += core_parking.o obj-y += cpu.o obj-y += cpupool.o diff --git a/xen/common/bug_ex_symbols.c b/xen/common/bug_ex_symbols.c new file mode 100644 index 0000000..77bb72b --- /dev/null +++ b/xen/common/bug_ex_symbols.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. + * + */ + +#include +#include +#include +#include +#include + +extern char __stext[]; + +struct virtual_region kernel_text = { + .list = LIST_HEAD_INIT(kernel_text.list), + .start = (unsigned long)_stext, + .end = (unsigned long)_etext, +#ifdef CONFIG_X86 + .ex = (struct exception_table_entry *)__start___ex_table, + .ex_end = (struct exception_table_entry *)__stop___ex_table, +#endif +}; + +/* + * The kernel_inittext should only be used when system_state + * is booting. Otherwise all accesses should be ignored. + */ +static bool_t ignore_if_active(unsigned int flag, unsigned long priv) +{ + return (system_state >= SYS_STATE_active); +} + +/* + * Becomes irrelevant when __init sections are cleared. + */ +struct virtual_region kernel_inittext = { + .list = LIST_HEAD_INIT(kernel_inittext.list), + .skip = ignore_if_active, + .start = (unsigned long)_sinittext, + .end = (unsigned long)_einittext, +#ifdef CONFIG_X86 + /* Even if they are __init their exception entry still gets stuck here. */ + .ex = (struct exception_table_entry *)__start___ex_table, + .ex_end = (struct exception_table_entry *)__stop___ex_table, +#endif +}; + +/* + * No locking. Additions are done either at startup (when there is only + * one CPU) or when all CPUs are running without IRQs. + * + * Deletions are big tricky. We MUST make sure all but one CPU + * are running cpu_relax(). + * + */ +LIST_HEAD(virtual_region_list); + +int register_virtual_region(struct virtual_region *r) +{ + ASSERT(!local_irq_is_enabled()); + + list_add_tail(&r->list, &virtual_region_list); + return 0; +} + +void unregister_virtual_region(struct virtual_region *r) +{ + ASSERT(!local_irq_is_enabled()); + + list_del_init(&r->list); +} + +void __init setup_virtual_regions(void) +{ + ssize_t sz; + unsigned int i, idx; + static const struct bug_frame *const stop_frames[] = { + __start_bug_frames, + __stop_bug_frames_0, + __stop_bug_frames_1, + __stop_bug_frames_2, +#ifdef CONFIG_X86 + __stop_bug_frames_3, +#endif + NULL + }; + +#ifdef CONFIG_X86 + sort_exception_tables(); +#endif + + /* N.B. idx != i */ + for ( idx = 0, i = 1; stop_frames[i]; i++, idx++ ) + { + struct bug_frame *s; + + s = (struct bug_frame *)stop_frames[i-1]; + sz = stop_frames[i] - s; + + kernel_text.frame[idx].n_bugs = sz; + kernel_text.frame[idx].bugs = s; + + kernel_inittext.frame[idx].n_bugs = sz; + kernel_inittext.frame[idx].bugs = s; + } + + register_virtual_region(&kernel_text); + register_virtual_region(&kernel_inittext); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/symbols.c b/xen/common/symbols.c index a59c59d..2cc416e 100644 --- a/xen/common/symbols.c +++ b/xen/common/symbols.c @@ -10,6 +10,7 @@ * compression (see tools/symbols.c for a more complete description) */ +#include #include #include #include @@ -95,10 +96,28 @@ static unsigned int get_symbol_offset(unsigned long pos) return name - symbols_names; } +bool_t __is_active_kernel_text(unsigned long addr, symbols_lookup_t *cb) +{ + struct virtual_region *region; + + list_for_each_entry( region, &virtual_region_list, list ) + { + if ( region->skip && region->skip(CHECKING_SYMBOL, region->priv) ) + continue; + + if ( addr >= region->start && addr < region->end ) + { + if ( cb && region->symbols_lookup ) + *cb = region->symbols_lookup; + return 1; + } + } + return 0; +} + bool_t is_active_kernel_text(unsigned long addr) { - return (is_kernel_text(addr) || - (system_state < SYS_STATE_active && is_kernel_inittext(addr))); + return __is_active_kernel_text(addr, NULL); } const char *symbols_lookup(unsigned long addr, @@ -108,13 +127,17 @@ const char *symbols_lookup(unsigned long addr, { unsigned long i, low, high, mid; unsigned long symbol_end = 0; + symbols_lookup_t symbol_lookup = NULL; namebuf[KSYM_NAME_LEN] = 0; namebuf[0] = 0; - if (!is_active_kernel_text(addr)) + if (!__is_active_kernel_text(addr, &symbol_lookup)) return NULL; + if (symbol_lookup) + return (symbol_lookup)(addr, symbolsize, offset, namebuf); + /* do a binary search on the sorted symbols_addresses array */ low = 0; high = symbols_num_syms; diff --git a/xen/include/xen/bug_ex_symbols.h b/xen/include/xen/bug_ex_symbols.h new file mode 100644 index 0000000..6f3401b --- /dev/null +++ b/xen/include/xen/bug_ex_symbols.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. + * + */ + +#ifndef __BUG_EX_SYMBOL_LIST__ +#define __BUG_EX_SYMBOL_LIST__ + +#include +#include +#include + +#ifdef CONFIG_X86 +#include +#endif +#include + +struct virtual_region +{ + struct list_head list; + +#define CHECKING_SYMBOL (1<<1) +#define CHECKING_BUG_FRAME (1<<2) +#define CHECKING_EXCEPTION (1<<3) + /* + * Whether to skip this region for particular searches. The flag + * can be CHECKING_[SYMBOL|BUG_FRAMES|EXCEPTION]. + * + * If the function returns 1 this region will be skipped. + */ + bool_t (*skip)(unsigned int flag, unsigned long priv); + + unsigned long start; /* Virtual address start. */ + unsigned long end; /* Virtual address start. */ + + /* + * If ->skip returns false for CHECKING_SYMBOL we will use + * 'symbols_lookup' callback to retrieve the name of the + * addr between start and end. If this is NULL the + * default lookup mechanism is used (the skip value is + * ignored). + */ + symbols_lookup_t symbols_lookup; + + struct { + struct bug_frame *bugs; /* The pointer to array of bug frames. */ + ssize_t n_bugs; /* The number of them. */ + } frame[BUGFRAME_NR]; + +#ifdef CONFIG_X86 + struct exception_table_entry *ex; + struct exception_table_entry *ex_end; +#endif + + unsigned long priv; /* To be used by above funcionts if need to. */ +}; + +extern struct list_head virtual_region_list; + +extern void setup_virtual_regions(void); +extern int register_virtual_region(struct virtual_region *r); +extern void unregister_virtual_region(struct virtual_region *r); + +#endif /* __BUG_EX_SYMBOL_LIST__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/kernel.h b/xen/include/xen/kernel.h index 548b64d..8cf7af7 100644 --- a/xen/include/xen/kernel.h +++ b/xen/include/xen/kernel.h @@ -65,12 +65,14 @@ 1; \ }) + extern char _start[], _end[], start[]; #define is_kernel(p) ({ \ char *__p = (char *)(unsigned long)(p); \ (__p >= _start) && (__p < _end); \ }) +/* For symbols_lookup usage. */ extern char _stext[], _etext[]; #define is_kernel_text(p) ({ \ char *__p = (char *)(unsigned long)(p); \ diff --git a/xen/include/xen/symbols.h b/xen/include/xen/symbols.h index 1fa0537..fe9ed8f 100644 --- a/xen/include/xen/symbols.h +++ b/xen/include/xen/symbols.h @@ -5,6 +5,15 @@ #define KSYM_NAME_LEN 127 +/* + * Typedef for the callback functions that symbols_lookup + * can call if virtual_region_list has an callback for it. + */ +typedef const char *(*symbols_lookup_t)(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset, + char *namebuf); + /* Lookup an address. */ const char *symbols_lookup(unsigned long addr, unsigned long *symbolsize,