Merge tag 'powerpc-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux

Pull powerpc updates from Michael Ellerman:
 "This is a bit late, partly due to me travelling, and partly due to a
  power outage knocking out some of my test systems *while* I was
  travelling.

   - Initial support for running on a system with an Ultravisor, which
     is software that runs below the hypervisor and protects guests
     against some attacks by the hypervisor.

   - Support for building the kernel to run as a "Secure Virtual
     Machine", ie. as a guest capable of running on a system with an
     Ultravisor.

   - Some changes to our DMA code on bare metal, to allow devices with
     medium sized DMA masks (> 32 && < 59 bits) to use more than 2GB of
     DMA space.

   - Support for firmware assisted crash dumps on bare metal (powernv).

   - Two series fixing bugs in and refactoring our PCI EEH code.

   - A large series refactoring our exception entry code to use gas
     macros, both to make it more readable and also enable some future
     optimisations.

  As well as many cleanups and other minor features & fixups.

  Thanks to: Adam Zerella, Alexey Kardashevskiy, Alistair Popple, Andrew
  Donnellan, Aneesh Kumar K.V, Anju T Sudhakar, Anshuman Khandual,
  Balbir Singh, Benjamin Herrenschmidt, Cédric Le Goater, Christophe
  JAILLET, Christophe Leroy, Christopher M. Riedl, Christoph Hellwig,
  Claudio Carvalho, Daniel Axtens, David Gibson, David Hildenbrand,
  Desnes A. Nunes do Rosario, Ganesh Goudar, Gautham R. Shenoy, Greg
  Kurz, Guerney Hunt, Gustavo Romero, Halil Pasic, Hari Bathini, Joakim
  Tjernlund, Jonathan Neuschafer, Jordan Niethe, Leonardo Bras, Lianbo
  Jiang, Madhavan Srinivasan, Mahesh Salgaonkar, Mahesh Salgaonkar,
  Masahiro Yamada, Maxiwell S. Garcia, Michael Anderson, Nathan
  Chancellor, Nathan Lynch, Naveen N. Rao, Nicholas Piggin, Oliver
  O'Halloran, Qian Cai, Ram Pai, Ravi Bangoria, Reza Arbab, Ryan Grimm,
  Sam Bobroff, Santosh Sivaraj, Segher Boessenkool, Sukadev Bhattiprolu,
  Thiago Bauermann, Thiago Jung Bauermann, Thomas Gleixner, Tom
  Lendacky, Vasant Hegde"

* tag 'powerpc-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux: (264 commits)
  powerpc/mm/mce: Keep irqs disabled during lockless page table walk
  powerpc: Use ftrace_graph_ret_addr() when unwinding
  powerpc/ftrace: Enable HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
  ftrace: Look up the address of return_to_handler() using helpers
  powerpc: dump kernel log before carrying out fadump or kdump
  docs: powerpc: Add missing documentation reference
  powerpc/xmon: Fix output of XIVE IPI
  powerpc/xmon: Improve output of XIVE interrupts
  powerpc/mm/radix: remove useless kernel messages
  powerpc/fadump: support holes in kernel boot memory area
  powerpc/fadump: remove RMA_START and RMA_END macros
  powerpc/fadump: update documentation about option to release opalcore
  powerpc/fadump: consider f/w load area
  powerpc/opalcore: provide an option to invalidate /sys/firmware/opal/core file
  powerpc/opalcore: export /sys/firmware/opal/core for analysing opal crashes
  powerpc/fadump: update documentation about CONFIG_PRESERVE_FA_DUMP
  powerpc/fadump: add support to preserve crash data on FADUMP disabled kernel
  powerpc/fadump: improve how crashed kernel's memory is reserved
  powerpc/fadump: consider reserved ranges while releasing memory
  powerpc/fadump: make crash memory ranges array allocation generic
  ...
This commit is contained in:
Linus Torvalds
2019-09-20 11:48:06 -07:00
247 changed files with 9763 additions and 5475 deletions

View File

@@ -26,6 +26,7 @@ SUB_DIRS = alignment \
switch_endian \
syscalls \
tm \
eeh \
vphn \
math \
ptrace \

View File

@@ -1,13 +1,14 @@
copyuser_64_t0
copyuser_64_t1
copyuser_64_t2
copyuser_power7_t0
copyuser_power7_t1
copyuser_p7_t0
copyuser_p7_t1
memcpy_64_t0
memcpy_64_t1
memcpy_64_t2
memcpy_power7_t0
memcpy_power7_t1
memcpy_p7_t0
memcpy_p7_t1
copyuser_64_exc_t0
copyuser_64_exc_t1
copyuser_64_exc_t2
memcpy_mcsafe_64

View File

@@ -12,7 +12,7 @@ ASFLAGS = $(CFLAGS) -Wa,-mpower4
TEST_GEN_PROGS := copyuser_64_t0 copyuser_64_t1 copyuser_64_t2 \
copyuser_p7_t0 copyuser_p7_t1 \
memcpy_64_t0 memcpy_64_t1 memcpy_64_t2 \
memcpy_p7_t0 memcpy_p7_t1 \
memcpy_p7_t0 memcpy_p7_t1 memcpy_mcsafe_64 \
copyuser_64_exc_t0 copyuser_64_exc_t1 copyuser_64_exc_t2
EXTRA_SOURCES := validate.c ../harness.c stubs.S
@@ -45,6 +45,11 @@ $(OUTPUT)/memcpy_p7_t%: memcpy_power7.S $(EXTRA_SOURCES)
-D SELFTEST_CASE=$(subst memcpy_p7_t,,$(notdir $@)) \
-o $@ $^
$(OUTPUT)/memcpy_mcsafe_64: memcpy_mcsafe_64.S $(EXTRA_SOURCES)
$(CC) $(CPPFLAGS) $(CFLAGS) \
-D COPY_LOOP=test_memcpy_mcsafe \
-o $@ $^
$(OUTPUT)/copyuser_64_exc_t%: copyuser_64.S exc_validate.c ../harness.c \
copy_tofrom_user_reference.S stubs.S
$(CC) $(CPPFLAGS) $(CFLAGS) \

View File

@@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define EXPORT_SYMBOL(x)
#define EXPORT_SYMBOL_GPL(x)
#define EXPORT_SYMBOL_KASAN(x)

View File

@@ -0,0 +1 @@
../../../../../arch/powerpc/lib/memcpy_mcsafe_64.S

View File

@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
noarg:
$(MAKE) -C ../
TEST_PROGS := eeh-basic.sh
TEST_FILES := eeh-functions.sh
top_srcdir = ../../../../..
include ../../lib.mk

View File

@@ -0,0 +1,82 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
. ./eeh-functions.sh
if ! eeh_supported ; then
echo "EEH not supported on this system, skipping"
exit 0;
fi
if [ ! -e "/sys/kernel/debug/powerpc/eeh_dev_check" ] && \
[ ! -e "/sys/kernel/debug/powerpc/eeh_dev_break" ] ; then
echo "debugfs EEH testing files are missing. Is debugfs mounted?"
exit 1;
fi
pre_lspci=`mktemp`
lspci > $pre_lspci
# Bump the max freeze count to something absurd so we don't
# trip over it while breaking things.
echo 5000 > /sys/kernel/debug/powerpc/eeh_max_freezes
# record the devices that we break in here. Assuming everything
# goes to plan we should get them back once the recover process
# is finished.
devices=""
# Build up a list of candidate devices.
for dev in `ls -1 /sys/bus/pci/devices/ | grep '\.0$'` ; do
# skip bridges since we can't recover them (yet...)
if [ -e "/sys/bus/pci/devices/$dev/pci_bus" ] ; then
echo "$dev, Skipped: bridge"
continue;
fi
# Skip VFs for now since we don't have a reliable way
# to break them.
if [ -e "/sys/bus/pci/devices/$dev/physfn" ] ; then
echo "$dev, Skipped: virtfn"
continue;
fi
# Don't inject errosr into an already-frozen PE. This happens with
# PEs that contain multiple PCI devices (e.g. multi-function cards)
# and injecting new errors during the recovery process will probably
# result in the recovery failing and the device being marked as
# failed.
if ! pe_ok $dev ; then
echo "$dev, Skipped: Bad initial PE state"
continue;
fi
echo "$dev, Added"
# Add to this list of device to check
devices="$devices $dev"
done
dev_count="$(echo $devices | wc -w)"
echo "Found ${dev_count} breakable devices..."
failed=0
for dev in $devices ; do
echo "Breaking $dev..."
if ! pe_ok $dev ; then
echo "Skipping $dev, Initial PE state is not ok"
failed="$((failed + 1))"
continue;
fi
if ! eeh_one_dev $dev ; then
failed="$((failed + 1))"
fi
done
echo "$failed devices failed to recover ($dev_count tested)"
lspci | diff -u $pre_lspci -
rm -f $pre_lspci
exit $failed

View File

@@ -0,0 +1,76 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
pe_ok() {
local dev="$1"
local path="/sys/bus/pci/devices/$dev/eeh_pe_state"
if ! [ -e "$path" ] ; then
return 1;
fi
local fw_state="$(cut -d' ' -f1 < $path)"
local sw_state="$(cut -d' ' -f2 < $path)"
# If EEH_PE_ISOLATED or EEH_PE_RECOVERING are set then the PE is in an
# error state or being recovered. Either way, not ok.
if [ "$((sw_state & 0x3))" -ne 0 ] ; then
return 1
fi
# A functioning PE should have the EEH_STATE_MMIO_ACTIVE and
# EEH_STATE_DMA_ACTIVE flags set. For some goddamn stupid reason
# the platform backends set these when the PE is in reset. The
# RECOVERING check above should stop any false positives though.
if [ "$((fw_state & 0x18))" -ne "$((0x18))" ] ; then
return 1
fi
return 0;
}
eeh_supported() {
test -e /proc/powerpc/eeh && \
grep -q 'EEH Subsystem is enabled' /proc/powerpc/eeh
}
eeh_one_dev() {
local dev="$1"
# Using this function from the command line is sometimes useful for
# testing so check that the argument is a well-formed sysfs device
# name.
if ! test -e /sys/bus/pci/devices/$dev/ ; then
echo "Error: '$dev' must be a sysfs device name (DDDD:BB:DD.F)"
return 1;
fi
# Break it
echo $dev >/sys/kernel/debug/powerpc/eeh_dev_break
# Force an EEH device check. If the kernel has already
# noticed the EEH (due to a driver poll or whatever), this
# is a no-op.
echo $dev >/sys/kernel/debug/powerpc/eeh_dev_check
# Enforce a 30s timeout for recovery. Even the IPR, which is infamously
# slow to reset, should recover within 30s.
max_wait=30
for i in `seq 0 ${max_wait}` ; do
if pe_ok $dev ; then
break;
fi
echo "$dev, waited $i/${max_wait}"
sleep 1
done
if ! pe_ok $dev ; then
echo "$dev, Failed to recover!"
return 1;
fi
echo "$dev, Recovered after $i seconds"
return 0;
}

View File

@@ -10,3 +10,6 @@ ptrace-tm-spd-vsx
ptrace-tm-spr
ptrace-hwbreak
perf-hwbreak
core-pkey
ptrace-pkey
ptrace-syscall

View File

@@ -0,0 +1 @@
rfi_flush

View File

@@ -1 +1,4 @@
memcmp
memcmp_64
memcmp_32
strlen
strlen_32

View File

@@ -5,10 +5,11 @@
* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
* delivered while the thread was in a transaction.
* delivered while the thread was in a transaction (referred too as
* first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
* context passed to the signal handler. The speculated state can be
* accessed with the uc_link pointer.
* context passed to the signal handler (first context). The speculated
* state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
@@ -28,17 +29,20 @@
#define MAX_ATTEMPT 500000
#define NV_FPU_REGS 18
#define NV_FPU_REGS 18 /* Number of non-volatile FP registers */
#define FPR14 14 /* First non-volatile FP register to check in f14-31 subset */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
/* Be sure there are 2x as many as there are NV FPU regs (2x18) */
/* Test only non-volatile registers, i.e. 18 fpr registers from f14 to f31 */
static double fps[] = {
/* First context will be set with these values, i.e. non-speculative */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
/* Second context will be set with these values, i.e. speculative */
-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
};
static sig_atomic_t fail;
static sig_atomic_t fail, broken;
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
@@ -46,11 +50,24 @@ static void signal_usr1(int signum, siginfo_t *info, void *uc)
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
for (i = 0; i < NV_FPU_REGS && !fail; i++) {
fail = (ucp->uc_mcontext.fp_regs[i + 14] != fps[i]);
fail |= (tm_ucp->uc_mcontext.fp_regs[i + 14] != fps[i + NV_FPU_REGS]);
if (fail)
printf("Failed on %d FP %g or %g\n", i, ucp->uc_mcontext.fp_regs[i + 14], tm_ucp->uc_mcontext.fp_regs[i + 14]);
for (i = 0; i < NV_FPU_REGS; i++) {
/* Check first context. Print all mismatches. */
fail = (ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[i]);
if (fail) {
broken = 1;
printf("FPR%d (1st context) == %g instead of %g (expected)\n",
FPR14 + i, ucp->uc_mcontext.fp_regs[FPR14 + i], fps[i]);
}
}
for (i = 0; i < NV_FPU_REGS; i++) {
/* Check second context. Print all mismatches. */
fail = (tm_ucp->uc_mcontext.fp_regs[FPR14 + i] != fps[NV_FPU_REGS + i]);
if (fail) {
broken = 1;
printf("FPR%d (2nd context) == %g instead of %g (expected)\n",
FPR14 + i, tm_ucp->uc_mcontext.fp_regs[FPR14 + i], fps[NV_FPU_REGS + i]);
}
}
}
@@ -72,13 +89,19 @@ static int tm_signal_context_chk_fpu()
}
i = 0;
while (i < MAX_ATTEMPT && !fail) {
while (i < MAX_ATTEMPT && !broken) {
/*
* tm_signal_self_context_load will set both first and second
* contexts accordingly to the values passed through non-NULL
* array pointers to it, in that case 'fps', and invoke the
* signal handler installed for SIGUSR1.
*/
rc = tm_signal_self_context_load(pid, NULL, fps, NULL, NULL);
FAIL_IF(rc != pid);
i++;
}
return fail;
return (broken);
}
int main(void)

View File

@@ -5,10 +5,11 @@
* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
* delivered while the thread was in a transaction.
* delivered while the thread was in a transaction (referred too as
* first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
* context passed to the signal handler. The speculated state can be
* accessed with the uc_link pointer.
* context passed to the signal handler (first context). The speculated
* state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
@@ -28,14 +29,22 @@
#define MAX_ATTEMPT 500000
#define NV_GPR_REGS 18
#define NV_GPR_REGS 18 /* Number of non-volatile GPR registers */
#define R14 14 /* First non-volatile register to check in r14-r31 subset */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
static sig_atomic_t fail;
static sig_atomic_t fail, broken;
static long gps[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18};
/* Test only non-volatile general purpose registers, i.e. r14-r31 */
static long gprs[] = {
/* First context will be set with these values, i.e. non-speculative */
/* R14, R15, ... */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
/* Second context will be set with these values, i.e. speculative */
/* R14, R15, ... */
-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18
};
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
@@ -43,12 +52,24 @@ static void signal_usr1(int signum, siginfo_t *info, void *uc)
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
for (i = 0; i < NV_GPR_REGS && !fail; i++) {
fail = (ucp->uc_mcontext.gp_regs[i + 14] != gps[i]);
fail |= (tm_ucp->uc_mcontext.gp_regs[i + 14] != gps[i + NV_GPR_REGS]);
if (fail)
printf("Failed on %d GPR %lu or %lu\n", i,
ucp->uc_mcontext.gp_regs[i + 14], tm_ucp->uc_mcontext.gp_regs[i + 14]);
/* Check first context. Print all mismatches. */
for (i = 0; i < NV_GPR_REGS; i++) {
fail = (ucp->uc_mcontext.gp_regs[R14 + i] != gprs[i]);
if (fail) {
broken = 1;
printf("GPR%d (1st context) == %lu instead of %lu (expected)\n",
R14 + i, ucp->uc_mcontext.gp_regs[R14 + i], gprs[i]);
}
}
/* Check second context. Print all mismatches. */
for (i = 0; i < NV_GPR_REGS; i++) {
fail = (tm_ucp->uc_mcontext.gp_regs[R14 + i] != gprs[NV_GPR_REGS + i]);
if (fail) {
broken = 1;
printf("GPR%d (2nd context) == %lu instead of %lu (expected)\n",
R14 + i, tm_ucp->uc_mcontext.gp_regs[R14 + i], gprs[NV_GPR_REGS + i]);
}
}
}
@@ -70,13 +91,19 @@ static int tm_signal_context_chk_gpr()
}
i = 0;
while (i < MAX_ATTEMPT && !fail) {
rc = tm_signal_self_context_load(pid, gps, NULL, NULL, NULL);
while (i < MAX_ATTEMPT && !broken) {
/*
* tm_signal_self_context_load will set both first and second
* contexts accordingly to the values passed through non-NULL
* array pointers to it, in that case 'gprs', and invoke the
* signal handler installed for SIGUSR1.
*/
rc = tm_signal_self_context_load(pid, gprs, NULL, NULL, NULL);
FAIL_IF(rc != pid);
i++;
}
return fail;
return broken;
}
int main(void)

View File

@@ -5,10 +5,11 @@
* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
* delivered while the thread was in a transaction.
* delivered while the thread was in a transaction (referred too as
* first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
* context passed to the signal handler. The speculated state can be
* accessed with the uc_link pointer.
* context passed to the signal handler (first context). The speculated
* state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
@@ -29,18 +30,24 @@
#define MAX_ATTEMPT 500000
#define NV_VMX_REGS 12
#define NV_VMX_REGS 12 /* Number of non-volatile VMX registers */
#define VMX20 20 /* First non-volatile register to check in vr20-31 subset */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
static sig_atomic_t fail;
static sig_atomic_t fail, broken;
/* Test only non-volatile registers, i.e. 12 vmx registers from vr20 to vr31 */
vector int vms[] = {
{1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
/* First context will be set with these values, i.e. non-speculative */
/* VMX20 , VMX21 , ... */
{ 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12},
{13,14,15,16},{17,18,19,20},{21,22,23,24},
{25,26,27,28},{29,30,31,32},{33,34,35,36},
{37,38,39,40},{41,42,43,44},{45,46,47,48},
{-1, -2, -3, -4}, {-5, -6, -7, -8}, {-9, -10,-11,-12},
/* Second context will be set with these values, i.e. speculative */
/* VMX20 , VMX21 , ... */
{ -1, -2, -3, -4},{ -5, -6, -7, -8},{ -9,-10,-11,-12},
{-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
{-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
{-37,-38,-39,-40},{-41,-42,-43,-44},{-45,-46,-47,-48}
@@ -48,26 +55,43 @@ vector int vms[] = {
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
int i;
int i, j;
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
for (i = 0; i < NV_VMX_REGS && !fail; i++) {
fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[i + 20],
for (i = 0; i < NV_VMX_REGS; i++) {
/* Check first context. Print all mismatches. */
fail = memcmp(ucp->uc_mcontext.v_regs->vrregs[VMX20 + i],
&vms[i], sizeof(vector int));
fail |= memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[i + 20],
&vms[i + NV_VMX_REGS], sizeof (vector int));
if (fail) {
int j;
fprintf(stderr, "Failed on %d vmx 0x", i);
broken = 1;
printf("VMX%d (1st context) == 0x", VMX20 + i);
/* Print actual value in first context. */
for (j = 0; j < 4; j++)
fprintf(stderr, "%04x", ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
fprintf(stderr, " vs 0x");
for (j = 0 ; j < 4; j++)
fprintf(stderr, "%04x", tm_ucp->uc_mcontext.v_regs->vrregs[i + 20][j]);
fprintf(stderr, "\n");
printf("%08x", ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]);
printf(" instead of 0x");
/* Print expected value. */
for (j = 0; j < 4; j++)
printf("%08x", vms[i][j]);
printf(" (expected)\n");
}
}
for (i = 0; i < NV_VMX_REGS; i++) {
/* Check second context. Print all mismatches. */
fail = memcmp(tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i],
&vms[NV_VMX_REGS + i], sizeof (vector int));
if (fail) {
broken = 1;
printf("VMX%d (2nd context) == 0x", NV_VMX_REGS + i);
/* Print actual value in second context. */
for (j = 0; j < 4; j++)
printf("%08x", tm_ucp->uc_mcontext.v_regs->vrregs[VMX20 + i][j]);
printf(" instead of 0x");
/* Print expected value. */
for (j = 0; j < 4; j++)
printf("%08x", vms[NV_VMX_REGS + i][j]);
printf(" (expected)\n");
}
}
}
@@ -90,13 +114,19 @@ static int tm_signal_context_chk()
}
i = 0;
while (i < MAX_ATTEMPT && !fail) {
while (i < MAX_ATTEMPT && !broken) {
/*
* tm_signal_self_context_load will set both first and second
* contexts accordingly to the values passed through non-NULL
* array pointers to it, in that case 'vms', and invoke the
* signal handler installed for SIGUSR1.
*/
rc = tm_signal_self_context_load(pid, NULL, NULL, vms, NULL);
FAIL_IF(rc != pid);
i++;
}
return fail;
return (broken);
}
int main(void)

View File

@@ -5,10 +5,11 @@
* Test the kernel's signal frame code.
*
* The kernel sets up two sets of ucontexts if the signal was to be
* delivered while the thread was in a transaction.
* delivered while the thread was in a transaction (referred too as
* first and second contexts).
* Expected behaviour is that the checkpointed state is in the user
* context passed to the signal handler. The speculated state can be
* accessed with the uc_link pointer.
* context passed to the signal handler (first context). The speculated
* state can be accessed with the uc_link pointer (second context).
*
* The rationale for this is that if TM unaware code (which linked
* against TM libs) installs a signal handler it will not know of the
@@ -29,17 +30,24 @@
#define MAX_ATTEMPT 500000
#define NV_VSX_REGS 12
#define NV_VSX_REGS 12 /* Number of VSX registers to check. */
#define VSX20 20 /* First VSX register to check in vsr20-vsr31 subset */
#define FPR20 20 /* FPR20 overlaps VSX20 most significant doubleword */
long tm_signal_self_context_load(pid_t pid, long *gprs, double *fps, vector int *vms, vector int *vss);
static sig_atomic_t fail;
static sig_atomic_t fail, broken;
vector int vss[] = {
{1, 2, 3, 4 },{5, 6, 7, 8 },{9, 10,11,12},
/* Test only 12 vsx registers from vsr20 to vsr31 */
vector int vsxs[] = {
/* First context will be set with these values, i.e. non-speculative */
/* VSX20 , VSX21 , ... */
{ 1, 2, 3, 4},{ 5, 6, 7, 8},{ 9,10,11,12},
{13,14,15,16},{17,18,19,20},{21,22,23,24},
{25,26,27,28},{29,30,31,32},{33,34,35,36},
{37,38,39,40},{41,42,43,44},{45,46,47,48},
/* Second context will be set with these values, i.e. speculative */
/* VSX20 , VSX21 , ... */
{-1, -2, -3, -4 },{-5, -6, -7, -8 },{-9, -10,-11,-12},
{-13,-14,-15,-16},{-17,-18,-19,-20},{-21,-22,-23,-24},
{-25,-26,-27,-28},{-29,-30,-31,-32},{-33,-34,-35,-36},
@@ -48,41 +56,91 @@ vector int vss[] = {
static void signal_usr1(int signum, siginfo_t *info, void *uc)
{
int i;
uint8_t vsc[sizeof(vector int)];
uint8_t vst[sizeof(vector int)];
int i, j;
uint8_t vsx[sizeof(vector int)];
uint8_t vsx_tm[sizeof(vector int)];
ucontext_t *ucp = uc;
ucontext_t *tm_ucp = ucp->uc_link;
/*
* The other half of the VSX regs will be after v_regs.
* FP registers and VMX registers overlap the VSX registers.
*
* FP registers (f0-31) overlap the most significant 64 bits of VSX
* registers vsr0-31, whilst VMX registers vr0-31, being 128-bit like
* the VSX registers, overlap fully the other half of VSX registers,
* i.e. vr0-31 overlaps fully vsr32-63.
*
* Due to compatibility and historical reasons (VMX/Altivec support
* appeared first on the architecture), VMX registers vr0-31 (so VSX
* half vsr32-63 too) are stored right after the v_regs pointer, in an
* area allocated for 'vmx_reverse' array (please see
* arch/powerpc/include/uapi/asm/sigcontext.h for details about the
* mcontext_t structure on Power).
*
* The other VSX half (vsr0-31) is hence stored below vr0-31/vsr32-63
* registers, but only the least significant 64 bits of vsr0-31. The
* most significant 64 bits of vsr0-31 (f0-31), as it overlaps the FP
* registers, is kept in fp_regs.
*
* v_regs is a 16 byte aligned pointer at the start of vmx_reserve
* (vmx_reserve may or may not be 16 aligned) where the v_regs structure
* exists, so v_regs points to where vr0-31 / vsr32-63 registers are
* fully stored. Since v_regs type is elf_vrregset_t, v_regs + 1
* skips all the slots used to store vr0-31 / vsr32-64 and points to
* part of one VSX half, i.e. v_regs + 1 points to the least significant
* 64 bits of vsr0-31. The other part of this half (the most significant
* part of vsr0-31) is stored in fp_regs.
*
* In short, vmx_reserve array holds everything. v_regs is a 16
* byte aligned pointer at the start of vmx_reserve (vmx_reserve
* may or may not be 16 aligned) where the v_regs structure exists.
* (half of) The VSX regsters are directly after v_regs so the
* easiest way to find them below.
*/
/* Get pointer to least significant doubleword of vsr0-31 */
long *vsx_ptr = (long *)(ucp->uc_mcontext.v_regs + 1);
long *tm_vsx_ptr = (long *)(tm_ucp->uc_mcontext.v_regs + 1);
for (i = 0; i < NV_VSX_REGS && !fail; i++) {
memcpy(vsc, &ucp->uc_mcontext.fp_regs[i + 20], 8);
memcpy(vsc + 8, &vsx_ptr[20 + i], 8);
fail = memcmp(vsc, &vss[i], sizeof(vector int));
memcpy(vst, &tm_ucp->uc_mcontext.fp_regs[i + 20], 8);
memcpy(vst + 8, &tm_vsx_ptr[20 + i], 8);
fail |= memcmp(vst, &vss[i + NV_VSX_REGS], sizeof(vector int));
/* Check first context. Print all mismatches. */
for (i = 0; i < NV_VSX_REGS; i++) {
/*
* Copy VSX most significant doubleword from fp_regs and
* copy VSX least significant one from 64-bit slots below
* saved VMX registers.
*/
memcpy(vsx, &ucp->uc_mcontext.fp_regs[FPR20 + i], 8);
memcpy(vsx + 8, &vsx_ptr[VSX20 + i], 8);
fail = memcmp(vsx, &vsxs[i], sizeof(vector int));
if (fail) {
int j;
broken = 1;
printf("VSX%d (1st context) == 0x", VSX20 + i);
for (j = 0; j < 16; j++)
printf("%02x", vsx[j]);
printf(" instead of 0x");
for (j = 0; j < 4; j++)
printf("%08x", vsxs[i][j]);
printf(" (expected)\n");
}
}
fprintf(stderr, "Failed on %d vsx 0x", i);
/* Check second context. Print all mismatches. */
for (i = 0; i < NV_VSX_REGS; i++) {
/*
* Copy VSX most significant doubleword from fp_regs and
* copy VSX least significant one from 64-bit slots below
* saved VMX registers.
*/
memcpy(vsx_tm, &tm_ucp->uc_mcontext.fp_regs[FPR20 + i], 8);
memcpy(vsx_tm + 8, &tm_vsx_ptr[VSX20 + i], 8);
fail = memcmp(vsx_tm, &vsxs[NV_VSX_REGS + i], sizeof(vector int));
if (fail) {
broken = 1;
printf("VSX%d (2nd context) == 0x", VSX20 + i);
for (j = 0; j < 16; j++)
fprintf(stderr, "%02x", vsc[j]);
fprintf(stderr, " vs 0x");
for (j = 0; j < 16; j++)
fprintf(stderr, "%02x", vst[j]);
fprintf(stderr, "\n");
printf("%02x", vsx_tm[j]);
printf(" instead of 0x");
for (j = 0; j < 4; j++)
printf("%08x", vsxs[NV_VSX_REGS + i][j]);
printf("(expected)\n");
}
}
}
@@ -105,13 +163,19 @@ static int tm_signal_context_chk()
}
i = 0;
while (i < MAX_ATTEMPT && !fail) {
rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vss);
while (i < MAX_ATTEMPT && !broken) {
/*
* tm_signal_self_context_load will set both first and second
* contexts accordingly to the values passed through non-NULL
* array pointers to it, in that case 'vsxs', and invoke the
* signal handler installed for SIGUSR1.
*/
rc = tm_signal_self_context_load(pid, NULL, NULL, NULL, vsxs);
FAIL_IF(rc != pid);
i++;
}
return fail;
return (broken);
}
int main(void)

View File

@@ -55,7 +55,8 @@ static inline bool failure_is_unavailable(void)
static inline bool failure_is_reschedule(void)
{
if ((failure_code() & TM_CAUSE_RESCHED) == TM_CAUSE_RESCHED ||
(failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED)
(failure_code() & TM_CAUSE_KVM_RESCHED) == TM_CAUSE_KVM_RESCHED ||
(failure_code() & TM_CAUSE_KVM_FAC_UNAV) == TM_CAUSE_KVM_FAC_UNAV)
return true;
return false;