@@ -37,6 +37,7 @@ void show_help(void)
" replace <name> apply <name> patch and revert all others.\n"
" unload <name> unload name <name> patch.\n"
" load <file> [flags] upload and apply <file> with name as the <file> name\n"
+ " test execute self modifying code livepatch hypervisor tests\n"
" Supported flags:\n"
" --nodeps Disable inter-module buildid dependency check.\n"
" Check only against hypervisor buildid.\n",
@@ -542,6 +543,33 @@ error:
return rc;
}
+static int test_func(int argc, char *argv[])
+{
+ uint32_t results = 0;
+ int rc;
+
+ if ( argc != 0 )
+ {
+ show_help();
+ return -1;
+ }
+
+ rc = xc_test_smoc(xch, XEN_SYSCTL_TEST_SMOC_LP, &results);
+ if ( rc )
+ {
+ fprintf(stderr, "test operation failed: %s\n", strerror(errno));
+ return -1;
+ }
+ if ( (results & XEN_SYSCTL_TEST_SMOC_LP) != XEN_SYSCTL_TEST_SMOC_LP )
+ {
+ fprintf(stderr, "some tests failed: %#x (expected %#x)\n",
+ results, XEN_SYSCTL_TEST_SMOC_LP);
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* These are also functions in action_options that are called in case
* none of the ones in main_options match.
@@ -554,6 +582,7 @@ struct {
{ "list", list_func },
{ "upload", upload_func },
{ "load", load_func },
+ { "test", test_func },
};
int main(int argc, char *argv[])
@@ -3,11 +3,18 @@
#include <xen/types.h>
+#include <public/sysctl.h>
+
int test_smoc(uint32_t selection, uint32_t *results);
+#ifdef CONFIG_LIVEPATCH
+bool cf_check test_lp_insn_replacement(void);
+#endif
+
static inline void execute_selftests(void)
{
- const uint32_t exec_mask = XEN_SYSCTL_TEST_SMOC_ALL;
+ const uint32_t exec_mask = XEN_SYSCTL_TEST_SMOC_ALL &
+ ~XEN_SYSCTL_TEST_SMOC_LP;
uint32_t result;
int rc;
@@ -1 +1,3 @@
obj-y += smoc.o
+obj-$(CONFIG_LIVEPATCH) += smoc-lp.o # for livepatch testing
+extra-$(CONFIG_LIVEPATCH) += smoc-lp-alt.o
new file mode 100644
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <asm/test.h>
+
+/*
+ * Interesting case because `return false` can be encoded as `xor %eax, %eax`,
+ * which is shorter than `return true` which is encoded as a `mov $1, %eax`
+ * instruction (based on code generated by GCC 13.2 at -O2), and also shorter
+ * than the replacement `jmp` instruction.
+ */
+bool cf_check test_lp_insn_replacement(void)
+{
+ return true;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
new file mode 100644
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <asm/test.h>
+
+/*
+ * Interesting case because `return false` can be encoded as `xor %eax, %eax`,
+ * which is shorter than `return true` which is encoded as a `mov $1, %eax`
+ * instruction (based on code generated by GCC 13.2 at -O2), and also shorter
+ * than the replacement `jmp` instruction.
+ */
+bool cf_check test_lp_insn_replacement(void)
+{
+ return false;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
@@ -27,6 +27,10 @@ int test_smoc(uint32_t selection, uint32_t *results)
} static const tests[] = {
{ XEN_SYSCTL_TEST_SMOC_INSN_REPL, &test_insn_replacement,
"alternative instruction replacement" },
+#ifdef CONFIG_LIVEPATCH
+ { XEN_SYSCTL_TEST_SMOC_LP_INSN, &test_lp_insn_replacement,
+ "livepatch instruction replacement" },
+#endif
};
unsigned int i;
@@ -1204,7 +1204,11 @@ struct xen_sysctl_dt_overlay {
struct xen_sysctl_test_smoc {
uint32_t tests; /* IN: bitmap with selected tests to execute. */
#define XEN_SYSCTL_TEST_SMOC_INSN_REPL (1U << 0)
-#define XEN_SYSCTL_TEST_SMOC_ALL (XEN_SYSCTL_TEST_SMOC_INSN_REPL)
+#define XEN_SYSCTL_TEST_SMOC_LP_INSN (1U << 1)
+#define XEN_SYSCTL_TEST_SMOC_ALL (XEN_SYSCTL_TEST_SMOC_INSN_REPL | \
+ XEN_SYSCTL_TEST_SMOC_LP_INSN)
+#define XEN_SYSCTL_TEST_SMOC_LP (XEN_SYSCTL_TEST_SMOC_LP_INSN)
+
uint32_t results; /* OUT: test result: 1 -> success, 0 -> failure. */
};