diff --git a/s390x/Makefile b/s390x/Makefile
index 7188daa..abc3242 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -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
 
diff --git a/s390x/gs.c b/s390x/gs.c
new file mode 100644
index 0000000..b9b19dd
--- /dev/null
+++ b/s390x/gs.c
@@ -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();
+}
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index 3943861..ff7eea1 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -52,3 +52,6 @@ file = cmm.elf
 
 [vector]
 file = vector.elf
+
+[gs]
+file = gs.elf
