@@ -8,6 +8,7 @@ tests += $(TEST_DIR)/diag10.elf
tests += $(TEST_DIR)/pfmf.elf
tests += $(TEST_DIR)/cmm.elf
tests += $(TEST_DIR)/vector.elf
+tests += $(TEST_DIR)/gs.elf
all: directories test_cases
new file mode 100644
@@ -0,0 +1,170 @@
+/*
+ * Tests guarded storage support.
+ *
+ * Copyright 2018 IBM Corp.
+ *
+ * Authors:
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Janosch Frank <frankja@de.ibm.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.
+ */
+#include <libcflat.h>
+#include <asm/page.h>
+#include <asm/facility.h>
+#include <asm/interrupt.h>
+#include <asm-generic/barrier.h>
+
+struct gs_cb {
+ uint64_t reserved;
+ uint64_t gsd;
+ uint64_t gssm;
+ uint64_t gs_epl_a;
+};
+
+struct gs_epl {
+ uint8_t pad1;
+ union {
+ uint8_t gs_eam;
+ struct {
+ uint8_t : 6;
+ uint8_t e : 1;
+ uint8_t b : 1;
+ };
+ };
+ union {
+ uint8_t gs_eci;
+ struct {
+ uint8_t tx : 1;
+ uint8_t cx : 1;
+ uint8_t : 5;
+ uint8_t in : 1;
+ };
+ };
+ union {
+ uint8_t gs_eai;
+ struct {
+ uint8_t : 1;
+ uint8_t t : 1;
+ uint8_t as : 2;
+ uint8_t ar : 4;
+ };
+ };
+ uint32_t pad2;
+ uint64_t gs_eha;
+ uint64_t gs_eia;
+ uint64_t gs_eoa;
+ uint64_t gs_eir;
+ uint64_t gs_era;
+};
+
+static volatile int guarded = 0;
+static struct gs_cb gs_cb;
+static struct gs_epl gs_epl;
+static unsigned long gs_area = 0x2000000;
+
+static inline void load_gs_cb(struct gs_cb *gs_cb)
+{
+ asm volatile(".insn rxy,0xe3000000004d,0,%0" : : "Q" (*gs_cb));
+}
+
+static inline void store_gs_cb(struct gs_cb *gs_cb)
+{
+ asm volatile(".insn rxy,0xe30000000049,0,%0" : : "Q" (*gs_cb));
+}
+
+static inline unsigned long load_guarded(unsigned long *p)
+{
+ unsigned long v;
+
+ asm(".insn rxy,0xe3000000004c, %0,%1"
+ : "=d" (v)
+ : "m" (*p)
+ : "r14", "memory");
+ return v;
+}
+
+/* guarded-storage event handler and finally it calls gs_handler */
+extern void gs_handler_asm(void);
+ asm(".globl gs_handler_asm\n"
+ "gs_handler_asm:\n"
+ " lgr %r14,%r15\n" /* Save current stack address in r14 */
+ " aghi %r15,-320\n" /* Allocate stack frame */
+ " stmg %r0,%r13,192(%r15)\n" /* Store regs to save area */
+ " stg %r14,312(%r15)\n"
+ " la %r2,160(%r15)\n" /* Store gscb address in this_cb */
+ " .insn rxy,0xe30000000049,0,160(%r15)\n" /* stgsc */
+ " lg %r14,24(%r2)\n" /* Get GSEPLA from GSCB*/
+ " lg %r14,40(%r14)\n" /* Get GSERA from GSEPL*/
+ " stg %r14,304(%r15)\n" /* Store GSERA in r14 of reg save area */
+ " brasl %r14,gs_handler\n" /* Jump to gs_handler */
+ " lmg %r0,%r15,192(%r15)\n" /* Restore regs */
+ " aghi %r14, 6\n" /* Add lgg instr len to GSERA */
+ " br %r14\n" /* Jump to next instruction after lgg */
+ " .size gs_handler_asm,.-gs_handler_asm\n");
+
+void gs_handler(struct gs_cb *this_cb)
+{
+ guarded = 1;
+ struct gs_epl *gs_epl = (struct gs_epl *) this_cb->gs_epl_a;
+ printf("gs_handler called for %016lx at %016lx\n",
+ gs_epl->gs_eir, gs_epl->gs_eia);
+}
+
+/* Test if load guarded gets intercepted. */
+static void test_load(void)
+{
+ unsigned long v;
+
+ guarded = 0;
+ v = load_guarded(&gs_area);
+ report("load guarded %ld", guarded, v);
+ guarded = 0;
+}
+
+/* Test gs instructions without enablement resulting in an exception */
+static void test_special(void)
+{
+ expect_pgm_int();
+ load_gs_cb(&gs_cb);
+ check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
+ expect_pgm_int();
+ store_gs_cb(&gs_cb);
+ check_pgm_int_code(PGM_INT_CODE_SPECIAL_OPERATION);
+}
+
+static void init(void)
+{
+ /* Enable control bit for gs */
+ ctl_set_bit(2, 4);
+
+ /* Setup gs registers to guard the gs_area */
+ gs_cb.gsd = gs_area | 25;
+
+ /* Check all 512kb slots for events */
+ gs_cb.gssm = 0xffffffffffffffffULL;
+ gs_cb.gs_epl_a = (unsigned long) &gs_epl;
+
+ /* Register handler */
+ gs_epl.gs_eha = (unsigned long) gs_handler_asm;
+ load_gs_cb(&gs_cb);
+}
+
+int main(void)
+{
+ bool has_gs = test_facility(133);
+
+ report_prefix_push("gs");
+ report_xfail("Guarded storage available", !has_gs, has_gs);
+ if (!has_gs)
+ goto done;
+
+ test_special();
+ init();
+ test_load();
+
+done:
+ report_prefix_pop();
+ return report_summary();
+}
@@ -52,3 +52,6 @@ file = cmm.elf
[vector]
file = vector.elf
+
+[gs]
+file = gs.elf