On Fri, 2016-08-12 at 19:19 +0200, Andrew Jones wrote: > On Wed, Aug 10, 2016 at 11:59:37AM +1000, Suraj Jitindar Singh wrote: > > > > On Power machines if a guest cedes while a tm transaction is in the > > suspended state then the checkpointed state of the vcpu may be lost > > and we > > lose the cpu in the host. > > > > Add a file for tm tests "powerpc/tm.c" and add a test to check if > > the fix > > has been applied to the host kernel. If this fix hasn't been > > applied then > > the test will never complete and the cpu will be lost. Otherwise > > the test > > should succeed. Since this has the ability to mess things up in the > > host > > mark this test as don't run by default. > > > > Based on initial work done by: Cyril Bur <cyril.bur@xxxxxxxxxxx> > > > > Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@xxxxxxxxx> > > --- > > lib/powerpc/asm/hcall.h | 1 + > > powerpc/Makefile.common | 3 +- > > powerpc/tm.c | 176 > > ++++++++++++++++++++++++++++++++++++++++++++++++ > > powerpc/unittests.cfg | 6 ++ > > 4 files changed, 185 insertions(+), 1 deletion(-) > > create mode 100644 powerpc/tm.c > > > > diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h > > index 99bce79..80aa3e3 100644 > > --- a/lib/powerpc/asm/hcall.h > > +++ b/lib/powerpc/asm/hcall.h > > @@ -18,6 +18,7 @@ > > #define H_SET_SPRG0 0x24 > > #define H_SET_DABR 0x28 > > #define H_PAGE_INIT 0x2c > > +#define H_CEDE 0xE0 > > #define H_PUT_TERM_CHAR 0x58 > > #define H_RANDOM 0x300 > > #define H_SET_MODE 0x31C > > diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common > > index 677030a..93e4f66 100644 > > --- a/powerpc/Makefile.common > > +++ b/powerpc/Makefile.common > > @@ -8,7 +8,8 @@ tests-common = \ > > $(TEST_DIR)/selftest.elf \ > > $(TEST_DIR)/spapr_hcall.elf \ > > $(TEST_DIR)/rtas.elf \ > > - $(TEST_DIR)/emulator.elf > > + $(TEST_DIR)/emulator.elf \ > > + $(TEST_DIR)/tm.elf > > > > all: $(TEST_DIR)/boot_rom.bin test_cases > > > > diff --git a/powerpc/tm.c b/powerpc/tm.c > > new file mode 100644 > > index 0000000..7f675ff > > --- /dev/null > > +++ b/powerpc/tm.c > > @@ -0,0 +1,176 @@ > > +/* > > + * Transactional Memory Unit Tests > > + * > > + * Copyright 2016 Suraj Jitindar Singh, IBM. > > + * > > + * This work is licensed under the terms of the GNU LGPL, version > > 2. > > + */ > > +#include <libcflat.h> > > +#include <libfdt/libfdt.h> > > +#include <devicetree.h> > > +#include <util.h> > > +#include <alloc.h> > above four includes aren't used Looks like these are left over from when I had all the code in this file, I'll remove these. > > > > > +#include <asm/hcall.h> > > +#include <asm/ppc_asm.h> > ppc_asm.h unused Ok > > > > > +#include <asm/processor.h> > > +#include <asm/handlers.h> > > +#include <asm/smp.h> > > + > > +#define US_TO_CYCLES(us) (us << 9) > > + > > +/* > > + * Get decrementer value > > + */ > > +static uint64_t get_dec(void) > > +{ > > + uint64_t dec = 0; > > + > > + asm volatile ( "mfdec %[dec]" : [dec] "+r" (dec) > > + : > > + : > > + ); > > + > > + return dec; > > +} > > + > > +/* > > + * Sleep for <us> micro-seconds (must be less than 4 seconds) > > + */ > > +static void sleep(uint64_t us) > > +{ > > + uint64_t expire_time, dec, cycles = US_TO_CYCLES(us); > > + > > + if (cycles > 0x7FFFFFFF) > > + cycles = 0x7FFFFFFF; > > + > > + if (cycles > (dec = get_dec())) { > > + expire_time = 0x7FFFFFFF + dec - cycles; > > + while (get_dec() < dec) > > + ; > > + } else { > > + expire_time = dec - cycles; > > + } > > + > > + while (get_dec() > expire_time) > > + ; > > +} > You may want to rename this to udelay (like the kernel's naming and > make them available to all powerpc unit tests by adding them to > processor.c. See (not yet merged) patch [*] where I do that for ARM. > > [*] https://github.com/rhdrjones/kvm-unit- > tests/commit/40f1d91930b3deebdd81d59438083ebcf2ac49e6 I'll take a look. That name is much better. > > > > > + > > +static int h_cede(void) > > +{ > > + register uint64_t r3 asm("r3") = H_CEDE; > > + > > + asm volatile ( "sc 1" : "+r"(r3) > > + : > > + : "r0", "r4", "r5", "r6", "r7", > > "r8", "r9", > > + "r10", "r11", "r12", "xer", "ctr", > > "cc" > > + ); > > + > > + return r3; > > +} > > + > > +/* > > + * Enable transactional memory > > + * Returns: 0 - Failure > > + * 1 - Success > TRUE/FALSE Ok > > > > > + */ > > +static bool enable_tm(void) > > +{ > > + uint64_t msr = 0; > > + > > + asm volatile ( "mfmsr %[msr]" : [msr] "+r" (msr) > > + : > > + : > > + ); > > + > > + msr |= (((uint64_t) 1) << 32); > > + > > + asm volatile ( "mtmsrd %1\n\t" > > + "mfmsr %0" : "+r" (msr) > > + : "r" (msr) > > + : > > + ); > > + > > + return !!(msr & (((uint64_t) 1) << 32)); > > +} > > + > > +/* > > + * Test H_CEDE call while transactional memory transaction is > > suspended > > + * > > + * WARNING: This tests for a known vulnerability in which the host > > may go down. > > + * Probably best not to run this if your host going down is going > > to cause > > + * problems. > > + * > > + * If the test passes then your kernel probably has the necessary > > patch. > > + * If the test fails then the H_CEDE call was unsuccessful and the > > + * vulnerability wasn't tested. > > + * If the test hits the vulnerability then it will never complete > > or report and > > + * the qemu process will block indefinately. RCU stalls will be > > detected on the > > + * cpu and any process scheduled on the lost cpu will also block > > indefinitely. > > + */ > > +static void test_h_cede_tm(int argc, char **argv) > > +{ > > + bool pass = true; > > + int i; > > + > > + if (argc > 2) > > + report_abort("Unsupported argument: '%s'", > > argv[2]); > > + > > + handle_exception(0x900, &dec_except_handler, NULL); > > + > > + if (!start_all_cpus(&halt, 0)) > > + report_abort("Failed to start secondary cpus"); > > + > > + if (!enable_tm()) > > + report_abort("Failed to enable tm"); > > + > > + /* > > + * Begin a transaction and guarantee we are in the suspend > > state > > + * before continuing > > + */ > > + asm volatile ( "1: tbegin.\n\t" > > + "beq 2f\n\t" > > + "tsuspend.\n\t" > > + "2: tcheck cr0\n\t" > > + "bf 2,1b" : > > + : > > + : "cr0" > > + ); > > + > > + for (i = 0; i < 500 && pass; i++) { > > + uint64_t rval = h_cede(); > > + > > + if (rval != H_SUCCESS) > > + pass = false; > > + sleep(5000); > > + } > > + > > + report("H_CEDE TM", pass); > > +} > > + > > +struct { > > + const char *name; > > + void (*func)(int argc, char **argv); > > +} hctests[] = { > > + { "h_cede_tm", test_h_cede_tm }, > > + { NULL, NULL } > > +}; > > + > > +int main(int argc, char **argv) > > +{ > > + bool all = false; > nit: initialization unnecessary Ok > > > > > + int i; > > + > > + report_prefix_push("tm"); > > + > > + all = (argc == 1 || (argc == 2 && !strcmp(argv[1], > > "all"))); > nit: outer braces unnecessary (and not preferred) Ok > > > > > + > > + for (i = 0; hctests[i].name != NULL; i++) { > > + if (all || strcmp(argv[1], hctests[i].name) == 0) > > { > > + report_prefix_push(hctests[i].name); > > + hctests[i].func(argc, argv); > > + report_prefix_pop(); > > + } > > + } > > + > > + return report_summary(); > > +} > > diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg > > index 0098cb6..20dbde6 100644 > > --- a/powerpc/unittests.cfg > > +++ b/powerpc/unittests.cfg > > @@ -53,3 +53,9 @@ groups = rtas > > > > [emulator] > > file = emulator.elf > > + > > +[h_cede_tm] > > +file = tm.elf > > +smp = 2,threads=2 > > +extra_params = -append "h_cede_tm" > > +groups = nodefault,h_cede_tm Thanks for the review -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html