diff --git a/gdb/s390-linux-nat.c b/gdb/s390-linux-nat.c
index b395529..720e3d6 100644
--- a/gdb/s390-linux-nat.c
+++ b/gdb/s390-linux-nat.c
@@ -54,6 +54,7 @@ static int have_regset_last_break = 0;
 static int have_regset_system_call = 0;
 static int have_regset_tdb = 0;
 static int have_regset_vxrs = 0;
+static int have_regset_gs = 0;
 
 /* Register map for 32-bit executables running under a 64-bit
    kernel.  */
@@ -406,6 +407,18 @@ s390_linux_fetch_inferior_registers (struct target_ops *ops,
 	fetch_regset (regcache, tid, NT_S390_VXRS_HIGH, 16 * 16,
 		      &s390_vxrs_high_regset);
     }
+
+  if (have_regset_gs)
+    {
+      if (regnum == -1 || (regnum >= S390_GSD_REGNUM
+			   && regnum <= S390_GSEPLA_REGNUM))
+	fetch_regset (regcache, tid, NT_S390_GS_CB, 4 * 8,
+		      &s390_gs_regset);
+      if (regnum == -1 || (regnum >= S390_BC_GSD_REGNUM
+			   && regnum <= S390_BC_GSEPLA_REGNUM))
+	fetch_regset (regcache, tid, NT_S390_GS_BC, 4 * 8,
+		      &s390_gsbc_regset);
+    }
 }
 
 /* Store register REGNUM back into the child process.  If REGNUM is
@@ -974,8 +987,12 @@ s390_read_description (struct target_ops *ops)
       && check_regset (tid, NT_S390_VXRS_LOW, 16 * 8)
       && check_regset (tid, NT_S390_VXRS_HIGH, 16 * 16);
 
+    have_regset_gs = (check_regset (tid, NT_S390_GS_CB, 4 * 8)
+		      && check_regset (tid, NT_S390_GS_BC, 4 * 8));
+
     if (s390_target_wordsize () == 8)
-      return (have_regset_vxrs ?
+      return (have_regset_gs ? tdesc_s390x_gs_linux64 :
+	      have_regset_vxrs ?
 	      (have_regset_tdb ? tdesc_s390x_tevx_linux64 :
 	       tdesc_s390x_vx_linux64) :
 	      have_regset_tdb ? tdesc_s390x_te_linux64 :
@@ -984,7 +1001,8 @@ s390_read_description (struct target_ops *ops)
 	      tdesc_s390x_linux64);
 
     if (hwcap & HWCAP_S390_HIGH_GPRS)
-      return (have_regset_vxrs ?
+      return (have_regset_gs ? tdesc_s390_gs_linux64 :
+	      have_regset_vxrs ?
 	      (have_regset_tdb ? tdesc_s390_tevx_linux64 :
 	       tdesc_s390_vx_linux64) :
 	      have_regset_tdb ? tdesc_s390_te_linux64 :
diff --git a/gdb/s390-linux-tdep.c b/gdb/s390-linux-tdep.c
index a6882fb..a6a6d5d 100644
--- a/gdb/s390-linux-tdep.c
+++ b/gdb/s390-linux-tdep.c
@@ -69,12 +69,14 @@
 #include "features/s390-te-linux64.c"
 #include "features/s390-vx-linux64.c"
 #include "features/s390-tevx-linux64.c"
+#include "features/s390-gs-linux64.c"
 #include "features/s390x-linux64.c"
 #include "features/s390x-linux64v1.c"
 #include "features/s390x-linux64v2.c"
 #include "features/s390x-te-linux64.c"
 #include "features/s390x-vx-linux64.c"
 #include "features/s390x-tevx-linux64.c"
+#include "features/s390x-gs-linux64.c"
 
 #define XML_SYSCALL_FILENAME_S390 "syscalls/s390-linux.xml"
 #define XML_SYSCALL_FILENAME_S390X "syscalls/s390x-linux.xml"
@@ -113,6 +115,7 @@ struct gdbarch_tdep
   int have_linux_v1;
   int have_linux_v2;
   int have_tdb;
+  bool have_gs;
 };
 
 
@@ -834,6 +837,24 @@ static const struct regcache_map_entry s390_regmap_vxrs_high[] =
     { 0 }
   };
 
+static const struct regcache_map_entry s390_regmap_gs[] =
+  {
+    { 1, REGCACHE_MAP_SKIP, 8 },
+    { 1, S390_GSD_REGNUM, 8 },
+    { 1, S390_GSSM_REGNUM, 8 },
+    { 1, S390_GSEPLA_REGNUM, 8 },
+    { 0 }
+  };
+
+static const struct regcache_map_entry s390_regmap_gsbc[] =
+  {
+    { 1, REGCACHE_MAP_SKIP, 8 },
+    { 1, S390_BC_GSD_REGNUM, 8 },
+    { 1, S390_BC_GSSM_REGNUM, 8 },
+    { 1, S390_BC_GSEPLA_REGNUM, 8 },
+    { 0 }
+  };
+
 
 /* Supply the TDB regset.  Like regcache_supply_regset, but invalidate
    the TDB registers unless the TDB format field is valid.  */
@@ -905,6 +926,18 @@ const struct regset s390_vxrs_high_regset = {
   regcache_collect_regset
 };
 
+const struct regset s390_gs_regset = {
+  s390_regmap_gs,
+  regcache_supply_regset,
+  regcache_collect_regset
+};
+
+const struct regset s390_gsbc_regset = {
+  s390_regmap_gsbc,
+  regcache_supply_regset,
+  regcache_collect_regset
+};
+
 /* Iterate over supported core file register note sections. */
 
 static void
@@ -951,6 +984,23 @@ s390_iterate_over_regset_sections (struct gdbarch *gdbarch,
       cb (".reg-s390-vxrs-high", 16 * 16, &s390_vxrs_high_regset,
 	  "s390 vector registers 16-31", cb_data);
     }
+
+  /* Iterate over the guarded-storage regsets if in "read" mode, or if
+     their registers are available.  */
+  if (tdep->have_gs)
+    {
+      if (regcache == NULL
+	  || REG_VALID == regcache_register_status (regcache,
+						    S390_GSD_REGNUM))
+	cb (".reg-s390-gs-cb", 4 * 8, &s390_gs_regset,
+	    "s390 guarded-storage registers", cb_data);
+
+      if (regcache == NULL
+	  || REG_VALID == regcache_register_status (regcache,
+						    S390_BC_GSD_REGNUM))
+	cb (".reg-s390-gs-bc", 4 * 8, &s390_gsbc_regset,
+	    "s390 guarded-storage broadcast control", cb_data);
+    }
 }
 
 static const struct target_desc *
@@ -959,7 +1009,7 @@ s390_core_read_description (struct gdbarch *gdbarch,
 {
   asection *section = bfd_get_section_by_name (abfd, ".reg");
   CORE_ADDR hwcap = 0;
-  int high_gprs, v1, v2, te, vx;
+  bool high_gprs, v1, v2, te, vx, gs;
 
   target_auxv_search (target, AT_HWCAP, &hwcap);
   if (!section)
@@ -971,12 +1021,14 @@ s390_core_read_description (struct gdbarch *gdbarch,
   v2 = (bfd_get_section_by_name (abfd, ".reg-s390-system-call") != NULL);
   vx = (hwcap & HWCAP_S390_VX);
   te = (hwcap & HWCAP_S390_TE);
+  gs = (hwcap & HWCAP_S390_GS);
 
   switch (bfd_section_size (abfd, section))
     {
     case s390_sizeof_gregset:
       if (high_gprs)
-	return (te && vx ? tdesc_s390_tevx_linux64 :
+	return (gs ? tdesc_s390_gs_linux64 :
+		te && vx ? tdesc_s390_tevx_linux64 :
 		vx ? tdesc_s390_vx_linux64 :
 		te ? tdesc_s390_te_linux64 :
 		v2 ? tdesc_s390_linux64v2 :
@@ -986,7 +1038,8 @@ s390_core_read_description (struct gdbarch *gdbarch,
 		v1 ? tdesc_s390_linux32v1 : tdesc_s390_linux32);
 
     case s390x_sizeof_gregset:
-      return (te && vx ? tdesc_s390x_tevx_linux64 :
+      return (gs ? tdesc_s390x_gs_linux64 :
+	      te && vx ? tdesc_s390x_tevx_linux64 :
 	      vx ? tdesc_s390x_vx_linux64 :
 	      te ? tdesc_s390x_te_linux64 :
 	      v2 ? tdesc_s390x_linux64v2 :
@@ -7767,6 +7820,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   int have_linux_v2 = 0;
   int have_tdb = 0;
   int have_vx = 0;
+  int have_gs = 0;
   int first_pseudo_reg, last_pseudo_reg;
   static const char *const stap_register_prefixes[] = { "%", NULL };
   static const char *const stap_register_indirection_prefixes[] = { "(",
@@ -7834,6 +7888,12 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24",
 	"v25", "v26", "v27", "v28", "v29", "v30", "v31",
       };
+      static const char *const gs_cb[] = {
+	"gsd", "gssm", "gsepla",
+      };
+      static const char *const gs_bc[] = {
+	"bc_gsd", "bc_gssm", "bc_gsepla",
+      };
       const struct tdesc_feature *feature;
       int i, valid_p = 1;
 
@@ -7937,6 +7997,29 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	  have_vx = 1;
 	}
 
+      /* Guarded-storage registers.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.s390.gs");
+      if (feature)
+	{
+	  for (i = 0; i < 3; i++)
+	    valid_p &= tdesc_numbered_register (feature, tdesc_data,
+						S390_GSD_REGNUM + i,
+						gs_cb[i]);
+	  have_gs = 1;
+	}
+
+      /* Guarded-storage broadcast control.  */
+      feature = tdesc_find_feature (tdesc, "org.gnu.gdb.s390.gsbc");
+      if (feature)
+	{
+	  valid_p &= have_gs;
+
+	  for (i = 0; i < 3; i++)
+	    valid_p &= tdesc_numbered_register (feature, tdesc_data,
+						S390_BC_GSD_REGNUM + i,
+						gs_bc[i]);
+	}
+
       if (!valid_p)
 	{
 	  tdesc_data_cleanup (tdesc_data);
@@ -7970,6 +8053,8 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 	continue;
       if ((tdep->gpr_full_regnum != -1) != have_upper)
 	continue;
+      if (tdep->have_gs != have_gs)
+	continue;
       if (tdesc_data != NULL)
 	tdesc_data_cleanup (tdesc_data);
       return arches->gdbarch;
@@ -7982,6 +8067,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   tdep->have_linux_v1 = have_linux_v1;
   tdep->have_linux_v2 = have_linux_v2;
   tdep->have_tdb = have_tdb;
+  tdep->have_gs = have_gs;
   gdbarch = gdbarch_alloc (&info, tdep);
 
   set_gdbarch_believe_pcc_promotion (gdbarch, 0);
@@ -8157,10 +8243,12 @@ _initialize_s390_tdep (void)
   initialize_tdesc_s390_te_linux64 ();
   initialize_tdesc_s390_vx_linux64 ();
   initialize_tdesc_s390_tevx_linux64 ();
+  initialize_tdesc_s390_gs_linux64 ();
   initialize_tdesc_s390x_linux64 ();
   initialize_tdesc_s390x_linux64v1 ();
   initialize_tdesc_s390x_linux64v2 ();
   initialize_tdesc_s390x_te_linux64 ();
   initialize_tdesc_s390x_vx_linux64 ();
   initialize_tdesc_s390x_tevx_linux64 ();
+  initialize_tdesc_s390x_gs_linux64 ();
 }
diff --git a/gdb/s390-linux-tdep.h b/gdb/s390-linux-tdep.h
index 4f818b4..e895530 100644
--- a/gdb/s390-linux-tdep.h
+++ b/gdb/s390-linux-tdep.h
@@ -33,6 +33,10 @@
 #define HWCAP_S390_VX 2048
 #endif
 
+#ifndef HWCAP_S390_GS
+#define HWCAP_S390_GS 16384
+#endif
+
 /* Register information.  */
 
 /* Program Status Word.  */
@@ -166,8 +170,14 @@
 #define S390_V29_REGNUM 119
 #define S390_V30_REGNUM 120
 #define S390_V31_REGNUM 121
+#define S390_GSD_REGNUM 122
+#define S390_GSSM_REGNUM 123
+#define S390_GSEPLA_REGNUM 124
+#define S390_BC_GSD_REGNUM 125
+#define S390_BC_GSSM_REGNUM 126
+#define S390_BC_GSEPLA_REGNUM 127
 /* Total.  */
-#define S390_NUM_REGS 122
+#define S390_NUM_REGS 128
 
 /* Special register usage.  */
 #define S390_SP_REGNUM S390_R15_REGNUM
@@ -198,6 +208,8 @@ extern const struct regset s390_tdb_regset;
 #define s390_sizeof_tdbregset 0x100
 extern const struct regset s390_vxrs_low_regset;
 extern const struct regset s390_vxrs_high_regset;
+extern const struct regset s390_gs_regset;
+extern const struct regset s390_gsbc_regset;
 
 /* GNU/Linux target descriptions.  */
 extern struct target_desc *tdesc_s390_linux32;
@@ -209,11 +221,13 @@ extern struct target_desc *tdesc_s390_linux64v2;
 extern struct target_desc *tdesc_s390_te_linux64;
 extern struct target_desc *tdesc_s390_vx_linux64;
 extern struct target_desc *tdesc_s390_tevx_linux64;
+extern struct target_desc *tdesc_s390_gs_linux64;
 extern struct target_desc *tdesc_s390x_linux64;
 extern struct target_desc *tdesc_s390x_linux64v1;
 extern struct target_desc *tdesc_s390x_linux64v2;
 extern struct target_desc *tdesc_s390x_te_linux64;
 extern struct target_desc *tdesc_s390x_vx_linux64;
 extern struct target_desc *tdesc_s390x_tevx_linux64;
+extern struct target_desc *tdesc_s390x_gs_linux64;
 
 #endif
