Subject: Re: [PATCH 2/2] selftests/powerpc: Test unaligned copy and paste

From: Michael Neuling <[email-masked]>
Date: Thu, 09 Jun 2016 17:26:36 +1000

On Thu, 2016-06-09 at 16:02 +1000, Chris Smart wrote:
> Test that an ISA 3.0 compliant machine performing an unaligned copy,
> copy_first, paste or paste_last is sent a SIGBUS.

It's probably overkill but we could check in the signal handler that the
sigbus was on the instruction we actually cared about.  ie something like
this in the sig handler for copy first.

static void sig_handler(int signr, siginfo_t *info, void *ucontext)
{
        ucontext_t *ctx = ucontext;
        unsigned int *pc = ctx->uc_mcontext.gp_regs[PT_NIP];

        if (*pc != COPY(0, buf+1, 1))
	    exit(0); /* we hit the right instruction */

        exit(1);
}

> 
> Signed-off-by: Chris Smart <[email-masked]>
> ---
>  tools/testing/selftests/powerpc/Makefile           |  3 +-
>  .../testing/selftests/powerpc/alignment/.gitignore |  4 ++
>  tools/testing/selftests/powerpc/alignment/Makefile | 11 +++++
>  .../powerpc/alignment/copy_first_unaligned.c       | 46
> ++++++++++++++++++
>  .../selftests/powerpc/alignment/copy_unaligned.c   | 46
> ++++++++++++++++++
>  .../powerpc/alignment/paste_last_unaligned.c       | 47
> ++++++++++++++++++
>  .../selftests/powerpc/alignment/paste_unaligned.c  | 47
> ++++++++++++++++++
>  tools/testing/selftests/powerpc/instructions.h     | 55
> ++++++++++++++++++++++
>  8 files changed, 258 insertions(+), 1 deletion(-)
>  create mode 100644 tools/testing/selftests/powerpc/alignment/.gitignore
>  create mode 100644 tools/testing/selftests/powerpc/alignment/Makefile
>  create mode 100644
> tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c
>  create mode 100644
> tools/testing/selftests/powerpc/alignment/copy_unaligned.c
>  create mode 100644
> tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c
>  create mode 100644
> tools/testing/selftests/powerpc/alignment/paste_unaligned.c
>  create mode 100644 tools/testing/selftests/powerpc/instructions.h
> 
> diff --git a/tools/testing/selftests/powerpc/Makefile
> b/tools/testing/selftests/powerpc/Makefile
> index 4ca83fe80654..3c40c9d0e6c7 100644
> --- a/tools/testing/selftests/powerpc/Makefile
> +++ b/tools/testing/selftests/powerpc/Makefile
> @@ -12,7 +12,8 @@ CFLAGS := -Wall -O2 -Wall -Werror
> -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR) $
>  
>  export CFLAGS
>  
> -SUB_DIRS = benchmarks 		\
> +SUB_DIRS = alignment		\
> +	   benchmarks		\
>  	   copyloops		\
>  	   context_switch	\
>  	   dscr			\
> diff --git a/tools/testing/selftests/powerpc/alignment/.gitignore
> b/tools/testing/selftests/powerpc/alignment/.gitignore
> new file mode 100644
> index 000000000000..147d7cc3c71c
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/alignment/.gitignore
> @@ -0,0 +1,4 @@
> +copy_unaligned
> +copy_first_unaligned
> +paste_unaligned
> +paste_last_unaligned
> diff --git a/tools/testing/selftests/powerpc/alignment/Makefile
> b/tools/testing/selftests/powerpc/alignment/Makefile
> new file mode 100644
> index 000000000000..7f91a5e6ab79
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/alignment/Makefile
> @@ -0,0 +1,11 @@
> +TEST_PROGS := copy_unaligned copy_first_unaligned paste_unaligned
> paste_last_unaligned
> +
> +all: $(TEST_PROGS)
> +
> +$(TEST_PROGS): ../harness.c ../utils.c
> +
> +include ../../lib.mk
> +
> +clean:
> +	rm -f $(TEST_PROGS)
> +
> diff --git
> a/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c
> b/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c
> new file mode 100644
> index 000000000000..48e4f9ab6137
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/alignment/copy_first_unaligned.c
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright 2016, Chris Smart, IBM Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + * Calls to copy_first which are not 128-byte aligned should be
> + * caught and sent a SIGBUS.
> + *
> + */
> +
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "utils.h"
> +#include "instructions.h"
> +
> +static void signal_handler(int signal)
> +{
> +	_exit(0);
> +}
> +
> +int test_copy_first_unaligned(void)
> +{
> +	/* 128 bytes for a full cache line */
> +	char buf[128] __cacheline_aligned;
> +
> +	/* Only run this test on a P9 or later */
> +	SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
> +
> +	/* Register our signal handler with SIGBUS */
> +	signal(SIGBUS, signal_handler);
> +
> +	/* +1 makes buf unaligned */
> +	copy_first(buf+1);
> +
> +	/* We should not get here */
> +	return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	return test_harness(test_copy_first_unaligned,
> "test_copy_first_unaligned");
> +}
> diff --git a/tools/testing/selftests/powerpc/alignment/copy_unaligned.c
> b/tools/testing/selftests/powerpc/alignment/copy_unaligned.c
> new file mode 100644
> index 000000000000..0945d50ea0aa
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/alignment/copy_unaligned.c
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright 2016, Chris Smart, IBM Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + * Calls to copy which are not 128-byte aligned should be caught
> + * and sent a SIGBUS.
> + *
> + */
> +
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "utils.h"
> +#include "instructions.h"
> +
> +static void signal_handler(int signal)
> +{
> +	_exit(0);
> +}
> +
> +int test_copy_unaligned(void)
> +{
> +	/* 128 bytes for a full cache line */
> +	char buf[128] __cacheline_aligned;
> +
> +	/* Only run this test on a P9 or later */
> +	SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
> +
> +	/* Register our signal handler with SIGBUS */
> +	signal(SIGBUS, signal_handler);
> +
> +	/* +1 makes buf unaligned */
> +	copy(buf+1);
> +
> +	/* We should not get here */
> +	return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	return test_harness(test_copy_unaligned, "test_copy_unaligned");
> +}
> diff --git
> a/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c
> b/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c
> new file mode 100644
> index 000000000000..b951ff471b81
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/alignment/paste_last_unaligned.c
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright 2016, Chris Smart, IBM Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + * Calls to paste_last which are not 128-byte aligned should be
> + * caught and sent a SIGBUS.
> + *
> + */
> +
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "utils.h"
> +#include "instructions.h"
> +
> +static void signal_handler(int signal)
> +{
> +	_exit(0);
> +}
> +
> +int test_paste_last_unaligned(void)
> +{
> +	/* 128 bytes for a full cache line */
> +	char buf[128] __cacheline_aligned;
> +
> +	/* Only run this test on a P9 or later */
> +	SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
> +
> +	/* Register our signal handler with SIGBUS */
> +	signal(SIGBUS, signal_handler);
> +
> +	copy(buf);
> +	/* +1 makes buf unaligned */
> +	paste_last(buf+1);
> +
> +	/* We should not get here */
> +	return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	return test_harness(test_paste_last_unaligned,
> "test_paste_last_unaligned");
> +}
> diff --git a/tools/testing/selftests/powerpc/alignment/paste_unaligned.c
> b/tools/testing/selftests/powerpc/alignment/paste_unaligned.c
> new file mode 100644
> index 000000000000..803d892951b9
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/alignment/paste_unaligned.c
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright 2016, Chris Smart, IBM Corporation.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version
> + * 2 of the License, or (at your option) any later version.
> + *
> + * Calls to paste which are not 128-byte aligned should be caught
> + * and sent a SIGBUS.
> + *
> + */
> +
> +#include <signal.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include "utils.h"
> +#include "instructions.h"
> +
> +static void signal_handler(int signal)
> +{
> +	_exit(0);
> +}
> +
> +int test_paste_unaligned(void)
> +{
> +	/* 128 bytes for a full cache line */
> +	char buf[128] __cacheline_aligned;
> +
> +	/* Only run this test on a P9 or later */
> +	SKIP_IF(!have_hwcap2(PPC_FEATURE2_ARCH_3_00));
> +
> +	/* Register our signal handler with SIGBUS */
> +	signal(SIGBUS, signal_handler);
> +
> +	copy(buf);
> +	/* +1 makes buf unaligned */
> +	paste(buf+1);
> +
> +	/* We should not get here */
> +	return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	return test_harness(test_paste_unaligned,
> "test_paste_unaligned");
> +}
> diff --git a/tools/testing/selftests/powerpc/instructions.h
> b/tools/testing/selftests/powerpc/instructions.h
> new file mode 100644
> index 000000000000..54ceafce4fa0
> --- /dev/null
> +++ b/tools/testing/selftests/powerpc/instructions.h
> @@ -0,0 +1,55 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +/* This defines the "copy" instruction from Power ISA 3.0 Book II,
> section 4.4. */
> +#define COPY(RA, RB, L) \
> +	.long (0x7c00060c | (RA) << (31-15) | (RB) << (31-20) | (L) <<
> (31-10))
> +
> +void copy(void *i)
> +{
> +	asm volatile(str(COPY(0, %0, 0))";"
> +			:
> +			: "b" (i)
> +			: "memory"
> +		    );
> +}
> +
> +void copy_first(void *i)
> +{
> +	asm volatile(str(COPY(0, %0, 1))";"
> +			:
> +			: "b" (i)
> +			: "memory"
> +		    );
> +}
> +
> +/* This defines the "paste" instruction from Power ISA 3.0 Book II,
> section 4.4. */
> +#define PASTE(RA, RB, L, RC) \
> +	.long (0x7c00070c | (RA) << (31-15) | (RB) << (31-20) | (L) <<
> (31-10) | (RC) << (31-31))
> +
> +int paste(void *i)
> +{
> +	int cr;
> +
> +	asm volatile(str(PASTE(0, %1, 0, 0))";"
> +			"mfcr %0;"
> +			: "=r" (cr)
> +			: "b" (i)
> +			: "memory"
> +		    );
> +	return cr;
> +}
> +
> +int paste_last(void *i)
> +{
> +	int cr;
> +
> +	asm volatile(str(PASTE(0, %1, 1, 1))";"
> +			"mfcr %0;"
> +			: "=r" (cr)
> +			: "b" (i)
> +			: "memory"
> +		    );
> +	return cr;
> +}
> +