diff mbox

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

Message ID 20160609060223.GA26308@distroguy.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Chris Smart June 9, 2016, 6:02 a.m. UTC
Test that an ISA 3.0 compliant machine performing an unaligned copy,
copy_first, paste or paste_last is sent a SIGBUS.

Signed-off-by: Chris Smart <chris@distroguy.com>
---
 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

Comments

Michael Neuling June 9, 2016, 7:26 a.m. UTC | #1
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 <chris@distroguy.com>
> ---
>  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;
> +}
> +
Michael Ellerman June 9, 2016, 10:50 a.m. UTC | #2
On Thu, 2016-06-09 at 17:26 +1000, Michael Neuling wrote:
> 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];
 
You're a hard taskmaster.

For it to build on 32-bit BE, you'll need:

    #if defined(__powerpc64__)
    pc = ctx->uc_mcontext.gp_regs[PT_NIP];
    #else
    pc = ctx->uc_mcontext.uc_regs->gregs[PT_NIP]
    #endif

cheers
diff mbox

Patch

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;
+}
+