new file mode 100644
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 Red Hat Inc
+ *
+ * Authors:
+ * David Hildenbrand <david@redhat.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+#ifndef _ASM_S390X_FLOAT_H_
+#define _ASM_S390X_FLOAT_H_
+
+static inline void set_fpc(uint32_t fpc)
+{
+ asm volatile(" lfpc %0\n" : : "Q"(fpc) );
+}
+
+static inline uint32_t get_fpc(void)
+{
+ uint32_t fpc;
+
+ asm volatile(" stfpc %0\n" : "=Q"(fpc));
+
+ return fpc;
+}
+
+static inline uint8_t get_fpc_dxc()
+{
+ return get_fpc() >> 8;
+}
+
+static inline void set_fpc_dxc(uint8_t dxc)
+{
+ uint32_t fpc = get_fpc();
+
+ fpc = (fpc & ~0xff00) | ((uint32_t)dxc) << 8;
+
+ set_fpc(fpc);
+}
+
+static inline void afp_enable(void)
+{
+ ctl_set_bit(0, 63 - 45);
+}
+
+static inline void afp_disable(void)
+{
+ ctl_clear_bit(0, 63 - 45);
+}
+
+#endif
@@ -13,6 +13,9 @@
#include <libcflat.h>
#include <asm/cpacf.h>
#include <asm/interrupt.h>
+#include <asm/float.h>
+
+struct lowcore *lc = NULL;
static inline void __test_spm_ipm(uint8_t cc, uint8_t key)
{
@@ -257,6 +260,36 @@ static void test_prno(void)
__test_basic_cpacf_opcode(CPACF_PRNO);
}
+static void test_dxc(void)
+{
+ /* DXC (0xff) is to be stored in LC and FPC on a trap (CGRT) with AFP */
+ lc->dxc_vxc = 0x12345678;
+ set_fpc_dxc(0);
+
+ expect_pgm_int();
+ asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n"
+ : : "r"(0) : "memory");
+ check_pgm_int_code(PGM_INT_CODE_DATA);
+
+ report("dxc in LC", lc->dxc_vxc == 0xff);
+ report("dxc in FPC", get_fpc_dxc() == 0xff);
+
+ /* DXC (0xff) is to be stored in LC only on a trap (CGRT) without AFP */
+ lc->dxc_vxc = 0x12345678;
+ set_fpc_dxc(0);
+
+ expect_pgm_int();
+ /* temporarily disable AFP */
+ afp_disable();
+ asm volatile(" .insn rrf,0xb9600000,%0,%0,8,0\n"
+ : : "r"(0) : "memory");
+ afp_enable();
+ check_pgm_int_code(PGM_INT_CODE_DATA);
+
+ report("dxc in LC", lc->dxc_vxc == 0xff);
+ report("dxc not in FPC", get_fpc_dxc() == 0);
+}
+
static struct {
const char *name;
void (*func)(void);
@@ -273,6 +306,7 @@ static struct {
{ "pcc", test_pcc },
{ "kmctr", test_kmctr },
{ "prno", test_prno },
+ { "dxc", test_dxc },
{ NULL, NULL }
};