@@ -20,23 +20,57 @@
union teid {
unsigned long val;
- struct {
- unsigned long addr:52;
- unsigned long fetch:1;
- unsigned long store:1;
- unsigned long reserved:6;
- unsigned long acc_list_prot:1;
- /*
- * depending on the exception and the installed facilities,
- * the m field can indicate several different things,
- * including whether the exception was triggered by a MVPG
- * instruction, or whether the addr field is meaningful
- */
- unsigned long m:1;
- unsigned long asce_id:2;
+ union {
+ /* common fields DAT exc & protection exc */
+ struct {
+ uint64_t addr : 52 - 0;
+ uint64_t acc_exc_fetch_store : 54 - 52;
+ uint64_t side_effect_acc : 55 - 54;
+ uint64_t /* reserved */ : 62 - 55;
+ uint64_t asce_id : 64 - 62;
+ };
+ /* DAT exc */
+ struct {
+ uint64_t /* pad */ : 61 - 0;
+ uint64_t dat_move_page : 62 - 61;
+ };
+ /* suppression on protection */
+ struct {
+ uint64_t /* pad */ : 60 - 0;
+ uint64_t sop_acc_list : 61 - 60;
+ uint64_t sop_teid_predictable : 62 - 61;
+ };
+ /* enhanced suppression on protection 2 */
+ struct {
+ uint64_t /* pad */ : 56 - 0;
+ uint64_t esop2_prot_code_0 : 57 - 56;
+ uint64_t /* pad */ : 60 - 57;
+ uint64_t esop2_prot_code_1 : 61 - 60;
+ uint64_t esop2_prot_code_2 : 62 - 61;
+ };
};
};
+enum prot_code {
+ PROT_KEY_OR_LAP,
+ PROT_DAT,
+ PROT_KEY,
+ PROT_ACC_LIST,
+ PROT_LAP,
+ PROT_IEP,
+ PROT_NUM_CODES /* Must always be last */
+};
+
+static inline enum prot_code teid_esop2_prot_code(union teid teid)
+{
+ int code = (teid.esop2_prot_code_0 << 2 |
+ teid.esop2_prot_code_1 << 1 |
+ teid.esop2_prot_code_2);
+
+ assert(code < PROT_NUM_CODES);
+ return (enum prot_code)code;
+}
+
void register_pgm_cleanup_func(void (*f)(void));
void handle_pgm_int(struct stack_frame_int *stack);
void handle_ext_int(struct stack_frame_int *stack);
@@ -11,32 +11,16 @@
#define _S390X_FAULT_H_
#include <bitops.h>
+#include <asm/facility.h>
+#include <asm/interrupt.h>
/* Instruction execution prevention, i.e. no-execute, 101 */
-static inline bool prot_is_iep(uint64_t teid)
+static inline bool prot_is_iep(union teid teid)
{
- if (test_bit_inv(56, &teid) && !test_bit_inv(60, &teid) && test_bit_inv(61, &teid))
- return true;
-
- return false;
-}
-
-/* Standard DAT exception, 001 */
-static inline bool prot_is_datp(uint64_t teid)
-{
- if (!test_bit_inv(56, &teid) && !test_bit_inv(60, &teid) && test_bit_inv(61, &teid))
- return true;
-
- return false;
-}
-
-/* Low-address protection exception, 100 */
-static inline bool prot_is_lap(uint64_t teid)
-{
- if (test_bit_inv(56, &teid) && !test_bit_inv(60, &teid) && !test_bit_inv(61, &teid))
- return true;
-
- return false;
+ if (!test_facility(130))
+ return false;
+ /* IEP installed -> ESOP2 installed */
+ return teid_esop2_prot_code(teid) == PROT_IEP;
}
void print_decode_teid(uint64_t teid);
@@ -13,35 +13,51 @@
#include <asm/page.h>
#include <fault.h>
-/* Decodes the protection exceptions we'll most likely see */
-static void print_decode_pgm_prot(uint64_t teid)
-{
- if (prot_is_lap(teid)) {
- printf("Type: LAP\n");
- return;
- }
- if (prot_is_iep(teid)) {
- printf("Type: IEP\n");
- return;
- }
+static void print_decode_pgm_prot(union teid teid)
+{
+ switch (get_supp_on_prot_facility()) {
+ case SOP_NONE:
+ case SOP_BASIC:
+ printf("Type: ?\n"); /* modern/relevant machines have ESOP */
+ break;
+ case SOP_ENHANCED_1:
+ if (teid.sop_teid_predictable) {/* implies access list or DAT */
+ if (teid.sop_acc_list)
+ printf("Type: ACC\n");
+ else
+ printf("Type: DAT\n");
+ } else {
+ printf("Type: KEY or LAP\n");
+ }
+ break;
+ case SOP_ENHANCED_2: {
+ static const char * const prot_str[] = {
+ "KEY or LAP",
+ "DAT",
+ "KEY",
+ "ACC",
+ "LAP",
+ "IEP",
+ };
+ _Static_assert(ARRAY_SIZE(prot_str) == PROT_NUM_CODES);
+ int prot_code = teid_esop2_prot_code(teid);
- if (prot_is_datp(teid)) {
- printf("Type: DAT\n");
- return;
+ printf("Type: %s\n", prot_str[prot_code]);
+ }
}
}
-void print_decode_teid(uint64_t teid)
+void print_decode_teid(uint64_t raw_teid)
{
- int asce_id = teid & 3;
+ union teid teid = { .val = raw_teid };
bool dat = lowcore.pgm_old_psw.mask & PSW_MASK_DAT;
printf("Memory exception information:\n");
printf("DAT: %s\n", dat ? "on" : "off");
printf("AS: ");
- switch (asce_id) {
+ switch (teid.asce_id) {
case AS_PRIM:
printf("Primary\n");
break;
@@ -65,10 +81,10 @@ void print_decode_teid(uint64_t teid)
*/
if ((lowcore.pgm_int_code == PGM_INT_CODE_SECURE_STOR_ACCESS ||
lowcore.pgm_int_code == PGM_INT_CODE_SECURE_STOR_VIOLATION) &&
- !test_bit_inv(61, &teid)) {
- printf("Address: %lx, unpredictable\n ", teid & PAGE_MASK);
+ !teid.sop_teid_predictable) {
+ printf("Address: %lx, unpredictable\n ", raw_teid & PAGE_MASK);
return;
}
- printf("TEID: %lx\n", teid);
- printf("Address: %lx\n\n", teid & PAGE_MASK);
+ printf("TEID: %lx\n", raw_teid);
+ printf("Address: %lx\n\n", raw_teid & PAGE_MASK);
}
@@ -77,7 +77,7 @@ static void fixup_pgm_int(struct stack_frame_int *stack)
break;
case PGM_INT_CODE_PROTECTION:
/* Handling for iep.c test case. */
- if (prot_is_iep(lowcore.trans_exc_id))
+ if (prot_is_iep((union teid) { .val = lowcore.trans_exc_id }))
/*
* We branched to the instruction that caused
* the exception so we can use the return
@@ -26,8 +26,8 @@ static void *root, *mem, *m;
volatile unsigned int *p;
/*
- * Check if a non-access-list protection exception happened for the given
- * address, in the primary address space.
+ * Check if the exception is consistent with DAT protection and has the correct
+ * address and primary address space.
*/
static bool check_pgm_prot(void *ptr)
{
@@ -37,14 +37,19 @@ static bool check_pgm_prot(void *ptr)
return false;
teid.val = lowcore.trans_exc_id;
-
- /*
- * depending on the presence of the ESOP feature, the rest of the
- * field might or might not be meaningful when the m field is 0.
- */
- if (!teid.m)
- return true;
- return (!teid.acc_list_prot && !teid.asce_id &&
+ switch (get_supp_on_prot_facility()) {
+ case SOP_NONE:
+ case SOP_BASIC:
+ assert(false); /* let's ignore ancient/irrelevant machines */
+ case SOP_ENHANCED_1:
+ if (!teid.sop_teid_predictable) /* implies key or low addr */
+ return false;
+ break;
+ case SOP_ENHANCED_2:
+ if (teid_esop2_prot_code(teid) != PROT_DAT)
+ return false;
+ }
+ return (!teid.sop_acc_list && !teid.asce_id &&
(teid.addr == ((unsigned long)ptr >> PAGE_SHIFT)));
}