__u8 __reserved[4096] __attribute__((__aligned__(16)));
 };
 
+/*
+ * Allocation of __reserved[]:
+ * (Note: records do not necessarily occur in the order shown here.)
+ *
+ *     size            description
+ *
+ *     0x210           fpsimd_context
+ *      0x10           esr_context
+ *      0x10           terminator (null _aarch64_ctx)
+ *
+ *     0xdd0           (reserved for future allocation)
+ *
+ * New records that can exceed this space need to be opt-in for userspace, so
+ * that an expanded signal frame is not generated unexpectedly.  The mechanism
+ * for opting in will depend on the extension that generates each new record.
+ * The above table documents the maximum set and sizes of records than can be
+ * generated when userspace does not opt in for any such extension.
+ */
+
 /*
  * Header to be used at the beginning of structures extending the user
  * context. Such structures must be placed after the rt_sigframe on the stack
 
        return round_up(max(user->size, sizeof(struct rt_sigframe)), 16);
 }
 
+/*
+ * Allocate space for an optional record of <size> bytes in the user
+ * signal frame.  The offset from the signal frame base address to the
+ * allocated block is assigned to *offset.
+ */
+static int sigframe_alloc(struct rt_sigframe_user_layout *user,
+                         unsigned long *offset, size_t size)
+{
+       size_t padded_size = round_up(size, 16);
+
+       *offset = user->size;
+       user->size += padded_size;
+
+       return 0;
+}
+
 static void __user *apply_user_offset(
        struct rt_sigframe_user_layout const *user, unsigned long offset)
 {
 /* Determine the layout of optional records in the signal frame */
 static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 {
-       user->fpsimd_offset = user->size;
-       user->size += round_up(sizeof(struct fpsimd_context), 16);
+       int err;
+
+       err = sigframe_alloc(user, &user->fpsimd_offset,
+                            sizeof(struct fpsimd_context));
+       if (err)
+               return err;
 
        /* fault information, if valid */
        if (current->thread.fault_code) {
-               user->esr_offset = user->size;
-               user->size += round_up(sizeof(struct esr_context), 16);
+               err = sigframe_alloc(user, &user->esr_offset,
+                                    sizeof(struct esr_context));
+               if (err)
+                       return err;
        }
 
-       /* set the "end" magic */
-       user->end_offset = user->size;
+       /*
+        * Allocate space for the terminator record.
+        * HACK: here we undo the reservation of space for the end record.
+        * This bodge should be replaced with a cleaner approach later on.
+        */
+       user->limit = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved) +
+               sizeof(user->sigframe->uc.uc_mcontext.__reserved);
 
-       return 0;
+       err = sigframe_alloc(user, &user->end_offset,
+                            sizeof(struct _aarch64_ctx));
+       return err;
 }