From nobody Thu Apr 2 01:08:26 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1774983899; cv=none; d=zohomail.com; s=zohoarc; b=KXzn+422jH5EwCz5MZI80h0dirCrLRhyWEpHHZcr/ks9D1IHfUxUs0VuaIGLa6ZOG0bT6Qvd/LM5Nr/PQlL4OmR8ZDf9gm45Lfh+KSfCcj+iQeTfshvk/7PXdGSDXLxhGFx3nyiaOysxSWoVRFyoumllHyUYFjRbhQnhCklwEBo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1774983899; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Nt869+EoqKBeJ1+vQp/e7NBob2COQX9inHC/KN2XaZ0=; b=YmPQT0mx69Z/ITUp3//VOvI4oHppzjjfo6kSMqGkVxvV9WkIBcACz0r57rJLOA4pE8nu38aob6sS40nSoAbncR85LOWMZGrQYj5ZA3VczSD7iLsPg8mbcn7+Lx6zCuG1dYm8WPxgqvq0FRfuzd5VQ2HXXvRl2fv3EVPdq75QUbc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1774983899577538.4127290338771; Tue, 31 Mar 2026 12:04:59 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1269258.1558347 (Exim 4.92) (envelope-from ) id 1w7eO7-0004kn-Qi; Tue, 31 Mar 2026 19:04:31 +0000 Received: by outflank-mailman (output) from mailman id 1269258.1558347; Tue, 31 Mar 2026 19:04:31 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1w7eO7-0004kf-Nv; Tue, 31 Mar 2026 19:04:31 +0000 Received: by outflank-mailman (input) for mailman id 1269258; Tue, 31 Mar 2026 19:04:30 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) id 1w7eO6-0004XO-9p for xen-devel@lists.xenproject.org; Tue, 31 Mar 2026 19:04:30 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1w7eO5-0042Cg-IU for xen-devel@lists.xenproject.org; Tue, 31 Mar 2026 21:04:29 +0200 Received: from [10.42.69.5] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 69cc1a93-5cb7-0a2a0a5109dd-0a2a4505ed50-44 for ; Tue, 31 Mar 2026 21:04:29 +0200 Received: from [209.85.128.45] (helo=mail-wm1-f45.google.com) by tlsNG-c201ff.mxtls.expurgate.net with ESMTPS (eXpurgate 4.55.2) (envelope-from ) id 69cc1abd-5aeb-0a2a45050019-d155802dd169-3 for ; Tue, 31 Mar 2026 21:04:29 +0200 Received: by mail-wm1-f45.google.com with SMTP id 5b1f17b1804b1-4853e1ce427so74749095e9.3 for ; Tue, 31 Mar 2026 12:04:29 -0700 (PDT) Received: from fedora (user-109-243-69-121.play-internet.pl. [109.243.69.121]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4887e80a6ebsm66704905e9.6.2026.03.31.12.04.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Mar 2026 12:04:28 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=20251104 header.d=gmail.com header.i="@gmail.com" header.h="Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774983869; x=1775588669; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Nt869+EoqKBeJ1+vQp/e7NBob2COQX9inHC/KN2XaZ0=; b=UMkObwboCxrUBhe1t0ckBDjMcYVnKr9kZOB1iJA9J/h9QJVbP1yTi+2HPacA7M+9zv 7Q+Fj2TSakAwckXIzjAv2Y17uCdTtCVHXJPtOQQnD9NhW8nVmzi3Aeoo2T4iEVBpzaTm WHkx9ee29l/NJ4jyRJhRCfZpPY8FH8BVpW1P4MWhqRMBFSiA0vy3Fr9RHTg0XWKWNXUx gcUknjGbN0urpQ6wyzVvQVPDnsR60x7O591+JFhlNAnGetx0rfPeEOBpSBDICyzmjwO7 lkPqcLx6Q6mUPOsbCk8RPyxAonp3JN34eFJWgYiFvpyFVbVi4XiuVWcsjONiuwx4Jf8r xJEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774983869; x=1775588669; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=Nt869+EoqKBeJ1+vQp/e7NBob2COQX9inHC/KN2XaZ0=; b=aBKxJB/BHyy5U/JrVbnsCJFZqp9x4EkwB0iisVXWt2t7E0nFZMrpON2Fi7KUWfqzMO k/CnWwxa88rRtS4GV3bf7e0TYOYKERFcnuJJc/cG8ODmXJX4HK9SjwhwcUQsclKwJ4zb +XqQ3suAqdp+4HOJamBLK8HhBhZUk7lW3Zy0lAj1eMvbqDDwTB22XNCyxyrundm3vNCH mpUc8Bm9nhUHAPbcwdkShExkP8rGO0uHMGw5iQSvVmpmtP+kd2NI0JQ45/n/EochtLr2 V/EYEhYuE9KxfWRHYOifiZfL8ip5zkH9F+qhcqWhEPSxVVTKbpax/exBGgFOKEJCh37N BRHA== X-Gm-Message-State: AOJu0YyuvaHCryNGeF1TkvjZBEgIcS+QVBUwP/AQwvQE7KFE64IsM+po jnPFW3EnEM6eOzpkc6SZVzLslf46Kh9IiK9SQ0bSxjQyy+rZgb7gMAdpiqiNsg== X-Gm-Gg: ATEYQzx/EDp/4F1L90xKzfCRbhboYsDJHSIxP8b1I9KsL+TBmWcBWDughPMCQm091dJ kX99EgyZ0LYAJ0rd3S0JK9jw4u8OhhAdrRR6ErDlmyCGWEHxrimef/Oef3oGvybb5Vxo3hXQRAi tB/69GTtdjNEvbHJQVC9X2/ikSPSOUaMOMyHLxvX7Aqt1CmeqKR2xM80Qv7J6iSZoTcgcaGlk6e oGh3fj2JL+9afoVPYiiWD3KfZeCAnym11/0/tfUywiOwrA0DwuvBhc0hfN4qKhjcJq2qwrNo68J GfVrYwh1LjAUfSQnf5cd8paI3BfS6GNuSmPVu8p7j92kG2Nlbu+SNyOgKDYq8xzQXDIvpqrXPNG pzE3NVS6M6NzGpYyAKPODMVwV9xN1olata061MF1k2OUx59jfyBWO2XcVH05seEw87Q4PL2fPgz HygbM19xsbt059Sh+Jk/Tjrxg7IQ5IzB02v7ko1Zu/tLhwxGrLzALuaAm6ZyDYl40+Yw== X-Received: by 2002:a05:600c:5303:b0:485:34b3:8587 with SMTP id 5b1f17b1804b1-48883562deamr9647415e9.10.1774983868536; Tue, 31 Mar 2026 12:04:28 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Romain Caritey , Oleksii Kurochko , Alistair Francis , Connor Davis , Andrew Cooper , Anthony PERARD , Michal Orzel , Jan Beulich , Julien Grall , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Stefano Stabellini Subject: [PATCH v2 1/4] xen/riscv: add exception table support Date: Tue, 31 Mar 2026 21:04:16 +0200 Message-ID: X-Mailer: git-send-email 2.53.0 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-c201ff/1774983869-22484488-AF78F8D6/10/73395122804 X-purgate-type: spam X-purgate-size: 11353 X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1774983901179158500 Content-Type: text/plain; charset="utf-8" Introduce exception table handling for RISC-V so faults from selected instructions can be recovered via fixup handlers instead of being treated as fatal. Add the RISC-V exception table format, sorting at boot to allow binary search used furthuer, and lookup from the trap handler. Update the linker script to emit the .ex_table section using introduced common EX_TABLE macro shared with other architectures. Also, reduce __start___ex_table alignment from 8 to 4 bytes to match the natural alignment of struct exception_table_entry, which contains two int32_t fields. Add inclusion of asm/extable.h to asm/bug.h to deal with compilation issue of common/virtual_region.c, which require declaration of __start___ex_table and __stop___ex_table. This implementation is based on Linux 6.16. Signed-off-by: Oleksii Kurochko --- Changes in v2: - Corrected the name for __start_ex_table identifier in the commit message. - Droped plural where extables is used. - Added inclusuion of to deal with compilation (nothing declares __start___ex_table and __stop___ex_table) of common/virtual_reg= ion.c. - Use long for delta variable inside swap_ex in extable.c. - To take into acoount live-patching code: - s/sort_extable/sort_exception_tables. - Introduce sort_exception_table() as liveaptch code requires it and re-use it inside sort_exception_tables(). - Drop cmp_ex_search() and rename cmp_ex_sort() to cmp_ex(). Rename local variable l and r inside cmp_ex(). - Identation fixes. - prefer sizeof() over sizeof() in calls of bsearch() and sort(). - Return back defintion of asm_extable() for __ASSEMBLER__ case. - Correct the comment above declaration of struct exception_table_entry. - Drop else in do_trap() before "if ( fixup_exception() )" to visually sepa= rate the set of checks. - Align start of exception table section by 4-bytes as exception table stru= ct contains two 4 bytes integers. - Make extable.o compile unconditionally. - Drop ifdef HAS_EX_TABLE in extable.h as extable.o is always compiled. - Drop ifdef around defintion of EX_TABLE. - Drop __init for cmp_ex as it is now used in fixup_exception() which isn't marked as __init. - Return void instead of bool for ex_handler_fixup() as this function always returns true. - Update the comment above defintion of struct exception_table_entry() to be more accurate. - Add inclusion of asm/extable.h to asm/bug.h to deal with compilation issue of common/virtual_region.c, which require declaration of __start___ex_tab= le and __stop___ex_table. --- xen/arch/riscv/Kconfig | 1 + xen/arch/riscv/Makefile | 1 + xen/arch/riscv/extable.c | 85 ++++++++++++++++++++++++++++ xen/arch/riscv/include/asm/bug.h | 2 + xen/arch/riscv/include/asm/extable.h | 58 +++++++++++++++++++ xen/arch/riscv/setup.c | 3 + xen/arch/riscv/traps.c | 5 ++ xen/arch/riscv/xen.lds.S | 3 + xen/arch/x86/xen.lds.S | 6 +- xen/include/xen/xen.lds.h | 6 ++ 10 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 xen/arch/riscv/extable.c create mode 100644 xen/arch/riscv/include/asm/extable.h diff --git a/xen/arch/riscv/Kconfig b/xen/arch/riscv/Kconfig index 89876b32175d..a5e87c1757f7 100644 --- a/xen/arch/riscv/Kconfig +++ b/xen/arch/riscv/Kconfig @@ -4,6 +4,7 @@ config RISCV select GENERIC_BUG_FRAME select GENERIC_UART_INIT select HAS_DEVICE_TREE_DISCOVERY + select HAS_EX_TABLE select HAS_PMAP select HAS_UBSAN select HAS_VMAP diff --git a/xen/arch/riscv/Makefile b/xen/arch/riscv/Makefile index ffbd7062e214..04f02ad89cba 100644 --- a/xen/arch/riscv/Makefile +++ b/xen/arch/riscv/Makefile @@ -3,6 +3,7 @@ obj-y +=3D cpufeature.o obj-y +=3D domain.o obj-$(CONFIG_EARLY_PRINTK) +=3D early_printk.o obj-y +=3D entry.o +obj-y +=3D extable.o obj-y +=3D imsic.o obj-y +=3D intc.o obj-y +=3D irq.o diff --git a/xen/arch/riscv/extable.c b/xen/arch/riscv/extable.c new file mode 100644 index 000000000000..882ae9508d19 --- /dev/null +++ b/xen/arch/riscv/extable.c @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define EX_FIELD(ptr, field) ((unsigned long)&(ptr)->field + (ptr)->field) + +static inline unsigned long ex_insn(const struct exception_table_entry *ex) +{ + return EX_FIELD(ex, insn); +} + +static inline unsigned long ex_fixup(const struct exception_table_entry *e= x) +{ + return EX_FIELD(ex, fixup); +} + +static void __init cf_check swap_ex(void *a, void *b) +{ + struct exception_table_entry *x =3D a, *y =3D b, tmp; + long delta =3D b - a; + + tmp =3D *x; + x->insn =3D y->insn + delta; + y->insn =3D tmp.insn - delta; + + x->fixup =3D y->fixup + delta; + y->fixup =3D tmp.fixup - delta; +} + +static int cf_check cmp_ex(const void *a, const void *b) +{ + const unsigned long insn_a =3D ex_insn(a); + const unsigned long insn_b =3D ex_insn(b); + + /* avoid overflow */ + return (insn_a > insn_b) - (insn_a < insn_b); +} + +void init_or_livepatch sort_exception_table(struct exception_table_entry *= start, + const struct exception_table_entry *stop) +{ + sort(start, stop - start, sizeof(*start), cmp_ex, swap_ex); +} + +void __init sort_exception_tables(void) +{ + sort_exception_table(__start___ex_table, __stop___ex_table); +} + +static void ex_handler_fixup(const struct exception_table_entry *ex, + struct cpu_user_regs *regs) +{ + regs->sepc =3D ex_fixup(ex); +} + +bool fixup_exception(struct cpu_user_regs *regs) +{ + unsigned long pc =3D regs->sepc; + const struct virtual_region *region =3D find_text_region(pc); + const struct exception_table_entry *ex; + struct exception_table_entry key; + + if ( !region || !region->ex ) + return false; + + key.insn =3D pc - (unsigned long)&key.insn; + + ex =3D bsearch(&key, region->ex, region->ex_end - region->ex, sizeof(k= ey), + cmp_ex); + + if ( !ex ) + return false; + + ex_handler_fixup(ex, regs); + + return true; +} diff --git a/xen/arch/riscv/include/asm/bug.h b/xen/arch/riscv/include/asm/= bug.h index 6ec8adc528a9..e6f286881662 100644 --- a/xen/arch/riscv/include/asm/bug.h +++ b/xen/arch/riscv/include/asm/bug.h @@ -9,6 +9,8 @@ =20 #ifndef __ASSEMBLER__ =20 +#include + #define BUG_INSTR "unimp" =20 /* diff --git a/xen/arch/riscv/include/asm/extable.h b/xen/arch/riscv/include/= asm/extable.h new file mode 100644 index 000000000000..4f50f84e69f2 --- /dev/null +++ b/xen/arch/riscv/include/asm/extable.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef ASM__RISCV__ASM_EXTABLE_H +#define ASM__RISCV__ASM_EXTABLE_H + +#ifdef __ASSEMBLER__ + +#define ASM_EXTABLE(insn, fixup) \ + .pushsection .ex_table, "a"; \ + .balign 4; \ + .long ((insn) - .); \ + .long ((fixup) - .); \ + .popsection; + +.macro asm_extable, insn, fixup + ASM_EXTABLE(\insn, \fixup) +.endm + +#else /* __ASSEMBLER__ */ + +#include +#include + +struct cpu_user_regs; + +#define ASM_EXTABLE(insn, fixup) \ + ".pushsection .ex_table, \"a\"\n" \ + ".balign 4\n" \ + ".long ((" #insn ") - .)\n" \ + ".long ((" #fixup ") - .)\n" \ + ".popsection\n" + +/* + * The exception table consists of pairs of relative offsets: the first + * is the relative offset to an instruction that is allowed to fault, + * and the second is the relative offset at which the program should + * continue. No general-purpose registers are modified by the exception + * handling mechanism itself, so it is up to the fixup code to handle + * any necessary state cleanup. + * + * The exception table and fixup code live out of line with the main + * instruction path. This means when everything is well, we don't even + * have to jump over them. Further, they do not intrude on our cache or + * tlb entries. + */ +struct exception_table_entry { + int32_t insn, fixup; +}; + +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +void sort_exception_tables(void); +bool fixup_exception(struct cpu_user_regs *regs); + +#endif /* __ASSEMBLY__ */ + +#endif /* ASM__RISCV__ASM_EXTABLE_H */ diff --git a/xen/arch/riscv/setup.c b/xen/arch/riscv/setup.c index cae49bb29626..56a0907a855f 100644 --- a/xen/arch/riscv/setup.c +++ b/xen/arch/riscv/setup.c @@ -19,6 +19,7 @@ =20 #include =20 +#include #include #include #include @@ -81,6 +82,8 @@ void __init noreturn start_xen(unsigned long bootcpu_id, =20 smp_prepare_boot_cpu(); =20 + sort_exception_tables(); + set_cpuid_to_hartid(0, bootcpu_id); =20 trap_init(); diff --git a/xen/arch/riscv/traps.c b/xen/arch/riscv/traps.c index 326f2be62823..d35c013e1399 100644 --- a/xen/arch/riscv/traps.c +++ b/xen/arch/riscv/traps.c @@ -12,6 +12,7 @@ #include #include =20 +#include #include #include #include @@ -217,6 +218,10 @@ void do_trap(struct cpu_user_regs *cpu_regs) =20 break; } + + if ( fixup_exception(cpu_regs) ) + break; + fallthrough; default: if ( cause & CAUSE_IRQ_FLAG ) diff --git a/xen/arch/riscv/xen.lds.S b/xen/arch/riscv/xen.lds.S index 331a7d63d3c9..65f136dce9f7 100644 --- a/xen/arch/riscv/xen.lds.S +++ b/xen/arch/riscv/xen.lds.S @@ -74,6 +74,9 @@ SECTIONS .data.ro_after_init : { __ro_after_init_start =3D .; *(.data.ro_after_init) + + EX_TABLE + . =3D ALIGN(PAGE_SIZE); __ro_after_init_end =3D .; } : text diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index c326538ebbb2..b9e888e5962f 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -113,11 +113,7 @@ SECTIONS __ro_after_init_start =3D .; *(.data.ro_after_init) =20 - . =3D ALIGN(8); - /* Exception table */ - __start___ex_table =3D .; - *(.ex_table) - __stop___ex_table =3D .; + EX_TABLE =20 . =3D ALIGN(PAGE_SIZE); __ro_after_init_end =3D .; diff --git a/xen/include/xen/xen.lds.h b/xen/include/xen/xen.lds.h index 136849ecd515..ea11e3fb6213 100644 --- a/xen/include/xen/xen.lds.h +++ b/xen/include/xen/xen.lds.h @@ -219,4 +219,10 @@ #define VPCI_ARRAY #endif =20 +#define EX_TABLE \ + . =3D ALIGN(4); \ + __start___ex_table =3D .; \ + *(.ex_table) \ + __stop___ex_table =3D .; + #endif /* __XEN_LDS_H__ */ --=20 2.53.0