diff mbox series

[kvm-unit-tests,v2,3/3] s390x: Rework TEID decoding and usage

Message ID 20220608133303.1532166-4-scgl@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series s390x: Rework TEID decoding and usage | expand

Commit Message

Janis Schoetterl-Glausch June 8, 2022, 1:33 p.m. UTC
The translation-exception identification (TEID) contains information to
identify the cause of certain program exceptions, including translation
exceptions occurring during dynamic address translation, as well as
protection exceptions.
The meaning of fields in the TEID is complex, depending on the exception
occurring and various potentially installed facilities.

Rework the type describing the TEID, in order to ease decoding.
Change the existing code interpreting the TEID and extend it to take the
installed suppression-on-protection facility into account.

Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
---
 lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
 lib/s390x/fault.h         | 30 +++++-------------
 lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
 lib/s390x/interrupt.c     |  2 +-
 s390x/edat.c              | 26 ++++++++++------
 5 files changed, 115 insertions(+), 69 deletions(-)

Comments

Claudio Imbrenda June 8, 2022, 2:03 p.m. UTC | #1
On Wed,  8 Jun 2022 15:33:03 +0200
Janis Schoetterl-Glausch <scgl@linux.ibm.com> wrote:

> The translation-exception identification (TEID) contains information to
> identify the cause of certain program exceptions, including translation
> exceptions occurring during dynamic address translation, as well as
> protection exceptions.
> The meaning of fields in the TEID is complex, depending on the exception
> occurring and various potentially installed facilities.
> 
> Rework the type describing the TEID, in order to ease decoding.
> Change the existing code interpreting the TEID and extend it to take the
> installed suppression-on-protection facility into account.
> 
> Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
> ---
>  lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
>  lib/s390x/fault.h         | 30 +++++-------------
>  lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
>  lib/s390x/interrupt.c     |  2 +-
>  s390x/edat.c              | 26 ++++++++++------
>  5 files changed, 115 insertions(+), 69 deletions(-)
> 
> diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
> index d9ab0bd7..3ca6bf76 100644
> --- a/lib/s390x/asm/interrupt.h
> +++ b/lib/s390x/asm/interrupt.h
> @@ -20,23 +20,56 @@
>  
>  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_f_s		: 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_LAP,
> +	PROT_DAT,
> +	PROT_KEY,
> +	PROT_ACC_LIST,
> +	PROT_LAP,
> +	PROT_IEP,

add:
	PROT_CODE_SIZE,	/* Must always be the last one */

[...]

> +	case SOP_ENHANCED_2: {
> +		static const char * const prot_str[] = {

static const char * const prot_str[PROT_CODE_SIZE] = {

so you have the guarantee that this has the right size, and you will
get a compile error if a new value is added to the enum but not here

and at this point I think it might make more sense to move this right
after the enum itself

> +			"KEY or LAP",
> +			"DAT",
> +			"KEY",
> +			"ACC",
> +			"LAP",
> +			"IEP",
> +		};
> +		int prot_code = teid_esop2_prot_code(teid);

enum prot_code prot_code = teid_esop2_prot_code(teid);

>  
> -	if (prot_is_datp(teid)) {
> -		printf("Type: DAT\n");
> -		return;
> +		assert(0 <= prot_code && prot_code < ARRAY_SIZE(prot_str));

then you can remove this assert ^

> +		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;
> @@ -57,7 +78,7 @@ void print_decode_teid(uint64_t teid)
>  	}
>  
>  	if (lowcore.pgm_int_code == PGM_INT_CODE_PROTECTION)
> -		print_decode_pgm_prot(teid);
> +		print_decode_pgm_prot(teid, dat);
>  
>  	/*
>  	 * If teid bit 61 is off for these two exception the reported
> @@ -65,10 +86,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);
>  }
> diff --git a/lib/s390x/interrupt.c b/lib/s390x/interrupt.c
> index 6da20c44..ac3d1ecd 100644
> --- a/lib/s390x/interrupt.c
> +++ b/lib/s390x/interrupt.c
> @@ -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
> diff --git a/s390x/edat.c b/s390x/edat.c
> index c6c25042..89ff4f51 100644
> --- a/s390x/edat.c
> +++ b/s390x/edat.c
> @@ -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,22 @@ 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)
> +	switch (get_supp_on_prot_facility()) {
> +	case SOP_NONE:
>  		return true;
> -	return (!teid.acc_list_prot && !teid.asce_id &&
> +	case SOP_BASIC:
> +		if (!teid.sop_teid_predictable)
> +			return true;
> +		break;
> +	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)));
>  }
>
Janis Schoetterl-Glausch June 8, 2022, 3:55 p.m. UTC | #2
On 6/8/22 16:03, Claudio Imbrenda wrote:
> On Wed,  8 Jun 2022 15:33:03 +0200
> Janis Schoetterl-Glausch <scgl@linux.ibm.com> wrote:
> 
>> The translation-exception identification (TEID) contains information to
>> identify the cause of certain program exceptions, including translation
>> exceptions occurring during dynamic address translation, as well as
>> protection exceptions.
>> The meaning of fields in the TEID is complex, depending on the exception
>> occurring and various potentially installed facilities.
>>
>> Rework the type describing the TEID, in order to ease decoding.
>> Change the existing code interpreting the TEID and extend it to take the
>> installed suppression-on-protection facility into account.
>>
>> Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
>> ---
>>  lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
>>  lib/s390x/fault.h         | 30 +++++-------------
>>  lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
>>  lib/s390x/interrupt.c     |  2 +-
>>  s390x/edat.c              | 26 ++++++++++------
>>  5 files changed, 115 insertions(+), 69 deletions(-)
>>
>> diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
>> index d9ab0bd7..3ca6bf76 100644
>> --- a/lib/s390x/asm/interrupt.h
>> +++ b/lib/s390x/asm/interrupt.h
>> @@ -20,23 +20,56 @@
>>  

[...]

>>  
>> +enum prot_code {
>> +	PROT_KEY_LAP,
>> +	PROT_DAT,
>> +	PROT_KEY,
>> +	PROT_ACC_LIST,
>> +	PROT_LAP,
>> +	PROT_IEP,
> 
> add:
> 	PROT_CODE_SIZE,	/* Must always be the last one */
> 
> [...]
> 
>> +	case SOP_ENHANCED_2: {
>> +		static const char * const prot_str[] = {
> 
> static const char * const prot_str[PROT_CODE_SIZE] = {
> 
> so you have the guarantee that this has the right size, and you will
> get a compile error if a new value is added to the enum but not here

Will I? It would just initialize missing elements with NULL, no?
> 
> and at this point I think it might make more sense to move this right
> after the enum itself
> 
>> +			"KEY or LAP",
>> +			"DAT",
>> +			"KEY",
>> +			"ACC",
>> +			"LAP",
>> +			"IEP",
>> +		};
>> +		int prot_code = teid_esop2_prot_code(teid);
> 
> enum prot_code prot_code = teid_esop2_prot_code(teid)> 
>>  
>> -	if (prot_is_datp(teid)) {
>> -		printf("Type: DAT\n");
>> -		return;
>> +		assert(0 <= prot_code && prot_code < ARRAY_SIZE(prot_str));
> 
> then you can remove this assert ^
> 
>> +		printf("Type: %s\n", prot_str[prot_code]);
>> +		}
>>  	}
>>  }
>>  
[...]
Claudio Imbrenda June 8, 2022, 4:40 p.m. UTC | #3
On Wed, 8 Jun 2022 17:55:08 +0200
Janis Schoetterl-Glausch <scgl@linux.ibm.com> wrote:

> On 6/8/22 16:03, Claudio Imbrenda wrote:
> > On Wed,  8 Jun 2022 15:33:03 +0200
> > Janis Schoetterl-Glausch <scgl@linux.ibm.com> wrote:
> >   
> >> The translation-exception identification (TEID) contains information to
> >> identify the cause of certain program exceptions, including translation
> >> exceptions occurring during dynamic address translation, as well as
> >> protection exceptions.
> >> The meaning of fields in the TEID is complex, depending on the exception
> >> occurring and various potentially installed facilities.
> >>
> >> Rework the type describing the TEID, in order to ease decoding.
> >> Change the existing code interpreting the TEID and extend it to take the
> >> installed suppression-on-protection facility into account.
> >>
> >> Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
> >> ---
> >>  lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
> >>  lib/s390x/fault.h         | 30 +++++-------------
> >>  lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
> >>  lib/s390x/interrupt.c     |  2 +-
> >>  s390x/edat.c              | 26 ++++++++++------
> >>  5 files changed, 115 insertions(+), 69 deletions(-)
> >>
> >> diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
> >> index d9ab0bd7..3ca6bf76 100644
> >> --- a/lib/s390x/asm/interrupt.h
> >> +++ b/lib/s390x/asm/interrupt.h
> >> @@ -20,23 +20,56 @@
> >>    
> 
> [...]
> 
> >>  
> >> +enum prot_code {
> >> +	PROT_KEY_LAP,
> >> +	PROT_DAT,
> >> +	PROT_KEY,
> >> +	PROT_ACC_LIST,
> >> +	PROT_LAP,
> >> +	PROT_IEP,  
> > 
> > add:
> > 	PROT_CODE_SIZE,	/* Must always be the last one */
> > 
> > [...]
> >   
> >> +	case SOP_ENHANCED_2: {
> >> +		static const char * const prot_str[] = {  
> > 
> > static const char * const prot_str[PROT_CODE_SIZE] = {
> > 
> > so you have the guarantee that this has the right size, and you will
> > get a compile error if a new value is added to the enum but not here  
> 
> Will I? It would just initialize missing elements with NULL, no?

hmm makes sense, somehow I was convinced you would at least get a
warning, probably a case of -ENOCOFFEE

in any case, if you add the "SIZE" element at the end (and especially
if you also move the array right after the enum) there should be no
issues to keep the two in sync.

even better, you can put a
_Static_assert(ARRAY_SIZE(prot_str) == PROT_CODE_SIZE);

> > 
> > and at this point I think it might make more sense to move this right
> > after the enum itself
> >   
> >> +			"KEY or LAP",
> >> +			"DAT",
> >> +			"KEY",
> >> +			"ACC",
> >> +			"LAP",
> >> +			"IEP",
> >> +		};
> >> +		int prot_code = teid_esop2_prot_code(teid);  
> > 
> > enum prot_code prot_code = teid_esop2_prot_code(teid)>   
> >>  
> >> -	if (prot_is_datp(teid)) {
> >> -		printf("Type: DAT\n");
> >> -		return;
> >> +		assert(0 <= prot_code && prot_code < ARRAY_SIZE(prot_str));  
> > 
> > then you can remove this assert ^
> >   
> >> +		printf("Type: %s\n", prot_str[prot_code]);
> >> +		}
> >>  	}
> >>  }
> >>    
> [...]
Janosch Frank June 10, 2022, 9:31 a.m. UTC | #4
On 6/8/22 15:33, Janis Schoetterl-Glausch wrote:
> The translation-exception identification (TEID) contains information to
> identify the cause of certain program exceptions, including translation
> exceptions occurring during dynamic address translation, as well as
> protection exceptions.
> The meaning of fields in the TEID is complex, depending on the exception
> occurring and various potentially installed facilities.
> 
> Rework the type describing the TEID, in order to ease decoding.
> Change the existing code interpreting the TEID and extend it to take the
> installed suppression-on-protection facility into account.
> 
> Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
> ---
>   lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
>   lib/s390x/fault.h         | 30 +++++-------------
>   lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
>   lib/s390x/interrupt.c     |  2 +-
>   s390x/edat.c              | 26 ++++++++++------
>   5 files changed, 115 insertions(+), 69 deletions(-)
> 
> diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
> index d9ab0bd7..3ca6bf76 100644
> --- a/lib/s390x/asm/interrupt.h
> +++ b/lib/s390x/asm/interrupt.h
> @@ -20,23 +20,56 @@
>   
>   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_f_s		: 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;
> +		};

Quite messy, would it be more readable to unionize the fields that overlap?

>   	};
>   };
>   
> +enum prot_code {
> +	PROT_KEY_LAP,

That's key OR LAP, right?

> +	PROT_DAT,
> +	PROT_KEY,
> +	PROT_ACC_LIST,
> +	PROT_LAP,
> +	PROT_IEP,
> +};
> +

Yes, I like that more than my quick fixes :-)

> +static void print_decode_pgm_prot(union teid teid, bool dat)
> +{
> +	switch (get_supp_on_prot_facility()) {
> +	case SOP_NONE:
> +		printf("Type: ?\n");
> +		break;
> +	case SOP_BASIC:
> +		if (teid.sop_teid_predictable && dat && teid.sop_acc_list)
> +			printf("Type: ACC\n");
> +		else
> +			printf("Type: ?\n");
> +		break;

I'm wondering if we should cut off the two possibilities above to make 
it a bit more sane. The SOP facility is about my age now and ESOP1 has 
been introduced with z10 if I'm not mistaken so it's not young either.

Do we have tests that require SOP/no-SOP?
Janis Schoetterl-Glausch June 10, 2022, 10:37 a.m. UTC | #5
On 6/10/22 11:31, Janosch Frank wrote:
> On 6/8/22 15:33, Janis Schoetterl-Glausch wrote:
>> The translation-exception identification (TEID) contains information to
>> identify the cause of certain program exceptions, including translation
>> exceptions occurring during dynamic address translation, as well as
>> protection exceptions.
>> The meaning of fields in the TEID is complex, depending on the exception
>> occurring and various potentially installed facilities.
>>
>> Rework the type describing the TEID, in order to ease decoding.
>> Change the existing code interpreting the TEID and extend it to take the
>> installed suppression-on-protection facility into account.
>>
>> Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
>> ---
>>   lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
>>   lib/s390x/fault.h         | 30 +++++-------------
>>   lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
>>   lib/s390x/interrupt.c     |  2 +-
>>   s390x/edat.c              | 26 ++++++++++------
>>   5 files changed, 115 insertions(+), 69 deletions(-)
>>
>> diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
>> index d9ab0bd7..3ca6bf76 100644
>> --- a/lib/s390x/asm/interrupt.h
>> +++ b/lib/s390x/asm/interrupt.h
>> @@ -20,23 +20,56 @@
>>     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_f_s        : 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;
>> +        };
> 
> Quite messy, would it be more readable to unionize the fields that overlap?

Not sure, I prefer this because it reflects the structure of the PoP,
where there is a section for DAT exceptions, SOP, ESOP1, ESOP2.
It's not exactly like this in the code because I factored out common fields,
and I removed the struct for ESOP1 because it was mostly redundant with SOP.
> 
>>       };
>>   };
>>   +enum prot_code {
>> +    PROT_KEY_LAP,
> 
> That's key OR LAP, right?

Yes, do you want me to make that explicit?
> 
>> +    PROT_DAT,
>> +    PROT_KEY,
>> +    PROT_ACC_LIST,
>> +    PROT_LAP,
>> +    PROT_IEP,
>> +};
>> +
> 
> Yes, I like that more than my quick fixes :-)
> 
>> +static void print_decode_pgm_prot(union teid teid, bool dat)
>> +{
>> +    switch (get_supp_on_prot_facility()) {
>> +    case SOP_NONE:
>> +        printf("Type: ?\n");
>> +        break;
>> +    case SOP_BASIC:
>> +        if (teid.sop_teid_predictable && dat && teid.sop_acc_list)
>> +            printf("Type: ACC\n");
>> +        else
>> +            printf("Type: ?\n");
>> +        break;
> 
> I'm wondering if we should cut off the two possibilities above to make it a bit more sane. The SOP facility is about my age now and ESOP1 has been introduced with z10 if I'm not mistaken so it's not young either.

So

case SOP_NONE:
case SOP_BASIC:
	assert(false);

?
	
> 
> Do we have tests that require SOP/no-SOP?

No, just going for correctness.
Janosch Frank June 10, 2022, 12:10 p.m. UTC | #6
On 6/10/22 12:37, Janis Schoetterl-Glausch wrote:
> On 6/10/22 11:31, Janosch Frank wrote:
>> On 6/8/22 15:33, Janis Schoetterl-Glausch wrote:
>>> The translation-exception identification (TEID) contains information to
>>> identify the cause of certain program exceptions, including translation
>>> exceptions occurring during dynamic address translation, as well as
>>> protection exceptions.
>>> The meaning of fields in the TEID is complex, depending on the exception
>>> occurring and various potentially installed facilities.
>>>
>>> Rework the type describing the TEID, in order to ease decoding.
>>> Change the existing code interpreting the TEID and extend it to take the
>>> installed suppression-on-protection facility into account.
>>>
>>> Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
>>> ---
>>>    lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
>>>    lib/s390x/fault.h         | 30 +++++-------------
>>>    lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
>>>    lib/s390x/interrupt.c     |  2 +-
>>>    s390x/edat.c              | 26 ++++++++++------
>>>    5 files changed, 115 insertions(+), 69 deletions(-)
>>>
>>> diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
>>> index d9ab0bd7..3ca6bf76 100644
>>> --- a/lib/s390x/asm/interrupt.h
>>> +++ b/lib/s390x/asm/interrupt.h
>>> @@ -20,23 +20,56 @@
>>>      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_f_s        : 54 - 52;

I'd either name it acc_exc_fs or spell it out properly.

>>> +            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;
>>> +        };
>>
>> Quite messy, would it be more readable to unionize the fields that overlap?
> 
> Not sure, I prefer this because it reflects the structure of the PoP,
> where there is a section for DAT exceptions, SOP, ESOP1, ESOP2.
> It's not exactly like this in the code because I factored out common fields,
> and I removed the struct for ESOP1 because it was mostly redundant with SOP.

Well, the rest of the code is readable and I can compare the struct to 
the POP so I'm okish with this.

>>
>>>        };
>>>    };
>>>    +enum prot_code {
>>> +    PROT_KEY_LAP,
>>
>> That's key OR LAP, right?
> 
> Yes, do you want me to make that explicit?

Yes

>>
>>> +    PROT_DAT,
>>> +    PROT_KEY,
>>> +    PROT_ACC_LIST,
>>> +    PROT_LAP,
>>> +    PROT_IEP,
>>> +};
>>> +
>>
>> Yes, I like that more than my quick fixes :-)
>>
>>> +static void print_decode_pgm_prot(union teid teid, bool dat)
>>> +{
>>> +    switch (get_supp_on_prot_facility()) {
>>> +    case SOP_NONE:
>>> +        printf("Type: ?\n");
>>> +        break;
>>> +    case SOP_BASIC:
>>> +        if (teid.sop_teid_predictable && dat && teid.sop_acc_list)
>>> +            printf("Type: ACC\n");
>>> +        else
>>> +            printf("Type: ?\n");
>>> +        break;
>>
>> I'm wondering if we should cut off the two possibilities above to make it a bit more sane. The SOP facility is about my age now and ESOP1 has been introduced with z10 if I'm not mistaken so it's not young either.
> 
> So
> 
> case SOP_NONE:
> case SOP_BASIC:
> 	assert(false);
> 
> ?

I'd check (e)sop on initialization and abort early so we never need to 
worry about it in other files.

> 	
>>
>> Do we have tests that require SOP/no-SOP?
> 
> No, just going for correctness.
>
Janis Schoetterl-Glausch June 13, 2022, 12:40 p.m. UTC | #7
On Fri, 2022-06-10 at 14:10 +0200, Janosch Frank wrote:
> On 6/10/22 12:37, Janis Schoetterl-Glausch wrote:
> > On 6/10/22 11:31, Janosch Frank wrote:
> > > On 6/8/22 15:33, Janis Schoetterl-Glausch wrote:
> > > > The translation-exception identification (TEID) contains information to
> > > > identify the cause of certain program exceptions, including translation
> > > > exceptions occurring during dynamic address translation, as well as
> > > > protection exceptions.
> > > > The meaning of fields in the TEID is complex, depending on the exception
> > > > occurring and various potentially installed facilities.
> > > > 
> > > > Rework the type describing the TEID, in order to ease decoding.
> > > > Change the existing code interpreting the TEID and extend it to take the
> > > > installed suppression-on-protection facility into account.
> > > > 
> > > > Signed-off-by: Janis Schoetterl-Glausch <scgl@linux.ibm.com>
> > > > ---
> > > >    lib/s390x/asm/interrupt.h | 61 +++++++++++++++++++++++++++---------
> > > >    lib/s390x/fault.h         | 30 +++++-------------
> > > >    lib/s390x/fault.c         | 65 ++++++++++++++++++++++++++-------------
> > > >    lib/s390x/interrupt.c     |  2 +-
> > > >    s390x/edat.c              | 26 ++++++++++------
> > > >    5 files changed, 115 insertions(+), 69 deletions(-)
> > > 

[...]

> > > > +static void print_decode_pgm_prot(union teid teid, bool dat)
> > > > +{
> > > > +    switch (get_supp_on_prot_facility()) {
> > > > +    case SOP_NONE:
> > > > +        printf("Type: ?\n");
> > > > +        break;
> > > > +    case SOP_BASIC:
> > > > +        if (teid.sop_teid_predictable && dat && teid.sop_acc_list)
> > > > +            printf("Type: ACC\n");
> > > > +        else
> > > > +            printf("Type: ?\n");
> > > > +        break;
> > > 
> > > I'm wondering if we should cut off the two possibilities above to make it a bit more sane. The SOP facility is about my age now and ESOP1 has been introduced with z10 if I'm not mistaken so it's not young either.
> > 
> > So
> > 
> > case SOP_NONE:
> > case SOP_BASIC:
> > 	assert(false);
> > 
> > ?
> 
> I'd check (e)sop on initialization and abort early so we never need to 
> worry about it in other files.

We could just ignore those cases since we don't depend on them for the
tests to function. Breaking all tests seems disproportional to me.
> 
> > 	
> > > 
> > > Do we have tests that require SOP/no-SOP?
> > 
> > No, just going for correctness.
> > 
>
diff mbox series

Patch

diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
index d9ab0bd7..3ca6bf76 100644
--- a/lib/s390x/asm/interrupt.h
+++ b/lib/s390x/asm/interrupt.h
@@ -20,23 +20,56 @@ 
 
 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_f_s		: 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_LAP,
+	PROT_DAT,
+	PROT_KEY,
+	PROT_ACC_LIST,
+	PROT_LAP,
+	PROT_IEP,
+};
+
+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 < 6);
+	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);
diff --git a/lib/s390x/fault.h b/lib/s390x/fault.h
index 726da2f0..867997f2 100644
--- a/lib/s390x/fault.h
+++ b/lib/s390x/fault.h
@@ -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);
diff --git a/lib/s390x/fault.c b/lib/s390x/fault.c
index efa62fcb..b75152f5 100644
--- a/lib/s390x/fault.c
+++ b/lib/s390x/fault.c
@@ -13,35 +13,56 @@ 
 #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, bool dat)
+{
+	switch (get_supp_on_prot_facility()) {
+	case SOP_NONE:
+		printf("Type: ?\n");
+		break;
+	case SOP_BASIC:
+		if (teid.sop_teid_predictable && dat && teid.sop_acc_list)
+			printf("Type: ACC\n");
+		else
+			printf("Type: ?\n");
+		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",
+		};
+		int prot_code = teid_esop2_prot_code(teid);
 
-	if (prot_is_datp(teid)) {
-		printf("Type: DAT\n");
-		return;
+		assert(0 <= prot_code && prot_code < ARRAY_SIZE(prot_str));
+		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;
@@ -57,7 +78,7 @@  void print_decode_teid(uint64_t teid)
 	}
 
 	if (lowcore.pgm_int_code == PGM_INT_CODE_PROTECTION)
-		print_decode_pgm_prot(teid);
+		print_decode_pgm_prot(teid, dat);
 
 	/*
 	 * If teid bit 61 is off for these two exception the reported
@@ -65,10 +86,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);
 }
diff --git a/lib/s390x/interrupt.c b/lib/s390x/interrupt.c
index 6da20c44..ac3d1ecd 100644
--- a/lib/s390x/interrupt.c
+++ b/lib/s390x/interrupt.c
@@ -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
diff --git a/s390x/edat.c b/s390x/edat.c
index c6c25042..89ff4f51 100644
--- a/s390x/edat.c
+++ b/s390x/edat.c
@@ -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,22 @@  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)
+	switch (get_supp_on_prot_facility()) {
+	case SOP_NONE:
 		return true;
-	return (!teid.acc_list_prot && !teid.asce_id &&
+	case SOP_BASIC:
+		if (!teid.sop_teid_predictable)
+			return true;
+		break;
+	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)));
 }