3636#include <linux/kfence.h>
3737#include <asm/asm-extable.h>
3838#include <asm/asm-offsets.h>
39+ #include <asm/ptrace.h>
40+ #include <asm/fault.h>
3941#include <asm/diag.h>
4042#include <asm/gmap.h>
4143#include <asm/irq.h>
4244#include <asm/facility.h>
4345#include <asm/uv.h>
4446#include "../kernel/entry.h"
4547
46- #define __FAIL_ADDR_MASK -4096L
47-
4848/*
4949 * Allocate private vm_fault_reason from top.
5050 * Please make sure it won't collide with vm_fault_reason.
@@ -76,11 +76,9 @@ early_initcall(fault_init);
7676 */
7777static enum fault_type get_fault_type (struct pt_regs * regs )
7878{
79- unsigned long trans_exc_code ;
79+ union teid teid = { . val = regs -> int_parm_long } ;
8080
81- trans_exc_code = regs -> int_parm_long & 3 ;
82- /* Primary address space */
83- if (likely (trans_exc_code == 0 )) {
81+ if (likely (teid .as == PSW_BITS_AS_PRIMARY )) {
8482 if (user_mode (regs ))
8583 return USER_FAULT ;
8684 if (!IS_ENABLED (CONFIG_PGSTE ))
@@ -89,28 +87,28 @@ static enum fault_type get_fault_type(struct pt_regs *regs)
8987 return GMAP_FAULT ;
9088 return KERNEL_FAULT ;
9189 }
92- if (trans_exc_code == 2 )
90+ if (teid . as == PSW_BITS_AS_SECONDARY )
9391 return USER_FAULT ;
9492 /* Access register mode, not used in the kernel */
95- if (trans_exc_code == 1 )
93+ if (teid . as == PSW_BITS_AS_ACCREG )
9694 return USER_FAULT ;
9795 /* Home space -> access via kernel ASCE */
9896 return KERNEL_FAULT ;
9997}
10098
10199static unsigned long get_fault_address (struct pt_regs * regs )
102100{
103- unsigned long trans_exc_code = regs -> int_parm_long ;
101+ union teid teid = { . val = regs -> int_parm_long } ;
104102
105- return trans_exc_code & __FAIL_ADDR_MASK ;
103+ return teid . addr * PAGE_SIZE ;
106104}
107105
108106static __always_inline bool fault_is_write (struct pt_regs * regs )
109107{
110- unsigned long trans_exc_code = regs -> int_parm_long ;
108+ union teid teid = { . val = regs -> int_parm_long } ;
111109
112110 if (static_branch_likely (& have_store_indication ))
113- return ( trans_exc_code & 0xc00 ) == 0x400 ;
111+ return teid . fsi == TEID_FSI_STORE ;
114112 return false;
115113}
116114
@@ -176,22 +174,23 @@ static void dump_pagetable(unsigned long asce, unsigned long address)
176174
177175static void dump_fault_info (struct pt_regs * regs )
178176{
177+ union teid teid = { .val = regs -> int_parm_long };
179178 unsigned long asce ;
180179
181180 pr_alert ("Failing address: %016lx TEID: %016lx\n" ,
182- get_fault_address (regs ), regs -> int_parm_long );
181+ get_fault_address (regs ), teid . val );
183182 pr_alert ("Fault in " );
184- switch (regs -> int_parm_long & 3 ) {
185- case 3 :
183+ switch (teid . as ) {
184+ case PSW_BITS_AS_HOME :
186185 pr_cont ("home space " );
187186 break ;
188- case 2 :
187+ case PSW_BITS_AS_SECONDARY :
189188 pr_cont ("secondary space " );
190189 break ;
191- case 1 :
190+ case PSW_BITS_AS_ACCREG :
192191 pr_cont ("access register " );
193192 break ;
194- case 0 :
193+ case PSW_BITS_AS_PRIMARY :
195194 pr_cont ("primary space " );
196195 break ;
197196 }
@@ -497,11 +496,10 @@ static inline vm_fault_t do_exception(struct pt_regs *regs, int access)
497496
498497void do_protection_exception (struct pt_regs * regs )
499498{
500- unsigned long trans_exc_code ;
499+ union teid teid = { . val = regs -> int_parm_long } ;
501500 vm_fault_t fault ;
502501 int access ;
503502
504- trans_exc_code = regs -> int_parm_long ;
505503 /*
506504 * Protection exceptions are suppressing, decrement psw address.
507505 * The exception to this rule are aborted transactions, for these
@@ -514,13 +512,12 @@ void do_protection_exception(struct pt_regs *regs)
514512 * as a special case because the translation exception code
515513 * field is not guaranteed to contain valid data in this case.
516514 */
517- if (unlikely (!( trans_exc_code & 4 ) )) {
515+ if (unlikely (!teid . b61 )) {
518516 do_low_address (regs );
519517 return ;
520518 }
521- if (unlikely (MACHINE_HAS_NX && (trans_exc_code & 0x80 ))) {
522- regs -> int_parm_long = (trans_exc_code & ~PAGE_MASK ) |
523- (regs -> psw .addr & PAGE_MASK );
519+ if (unlikely (MACHINE_HAS_NX && teid .b56 )) {
520+ regs -> int_parm_long = (teid .addr * PAGE_SIZE ) | (regs -> psw .addr & PAGE_MASK );
524521 access = VM_EXEC ;
525522 fault = VM_FAULT_BADACCESS ;
526523 } else {
@@ -548,6 +545,7 @@ NOKPROBE_SYMBOL(do_dat_exception);
548545
549546void do_secure_storage_access (struct pt_regs * regs )
550547{
548+ union teid teid = { .val = regs -> int_parm_long };
551549 unsigned long addr = get_fault_address (regs );
552550 struct vm_area_struct * vma ;
553551 struct mm_struct * mm ;
@@ -561,8 +559,7 @@ void do_secure_storage_access(struct pt_regs *regs)
561559 * process. Bit 61 is not reliable without the misc UV feature,
562560 * therefore this needs to be checked too.
563561 */
564- if (uv_has_feature (BIT_UV_FEAT_MISC ) &&
565- !test_bit_inv (61 , & regs -> int_parm_long )) {
562+ if (uv_has_feature (BIT_UV_FEAT_MISC ) && !teid .b61 ) {
566563 /*
567564 * When this happens, userspace did something that it
568565 * was not supposed to do, e.g. branching into secure
0 commit comments