Commit 6b33e68a authored by Nico Boehr's avatar Nico Boehr Committed by Janosch Frank
Browse files

s390/entry: sort out physical vs virtual pointers usage in sie64a



Fix virtual vs physical address confusion (which currently are the
same).

sie_block is accessed in entry.S and passed it to hardware, which is why
both its physical and virtual address are needed. To avoid every caller
having to do the virtual-physical conversion, add a new function sie64a()
which converts the virtual address to physical.

Signed-off-by: default avatarNico Boehr <nrb@linux.ibm.com>
Reviewed-by: default avatarAlexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: default avatarClaudio Imbrenda <imbrenda@linux.ibm.com>
Link: https://lore.kernel.org/r/20221020143159.294605-3-nrb@linux.ibm.com


Message-Id: <20221020143159.294605-3-nrb@linux.ibm.com>
Signed-off-by: default avatarJanosch Frank <frankja@linux.ibm.com>
parent 079f0c21
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -1017,7 +1017,13 @@ void kvm_arch_crypto_clear_masks(struct kvm *kvm);
void kvm_arch_crypto_set_masks(struct kvm *kvm, unsigned long *apm,
			       unsigned long *aqm, unsigned long *adm);

extern int sie64a(struct kvm_s390_sie_block *, u64 *);
int __sie64a(phys_addr_t sie_block_phys, struct kvm_s390_sie_block *sie_block, u64 *rsa);

static inline int sie64a(struct kvm_s390_sie_block *sie_block, u64 *rsa)
{
	return __sie64a(virt_to_phys(sie_block), sie_block, rsa);
}

extern char sie_exit;

extern int kvm_s390_gisc_register(struct kvm *kvm, u32 gisc);
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ struct stack_frame {
			unsigned long sie_savearea;
			unsigned long sie_reason;
			unsigned long sie_flags;
			unsigned long sie_control_block_phys;
		};
	};
	unsigned long gprs[10];
+1 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ int main(void)
	OFFSET(__SF_SIE_SAVEAREA, stack_frame, sie_savearea);
	OFFSET(__SF_SIE_REASON, stack_frame, sie_reason);
	OFFSET(__SF_SIE_FLAGS, stack_frame, sie_flags);
	OFFSET(__SF_SIE_CONTROL_PHYS, stack_frame, sie_control_block_phys);
	DEFINE(STACK_FRAME_OVERHEAD, sizeof(struct stack_frame));
	BLANK();
	/* idle data offsets */
+15 −11
Original line number Diff line number Diff line
@@ -225,18 +225,20 @@ ENDPROC(__switch_to)

#if IS_ENABLED(CONFIG_KVM)
/*
 * sie64a calling convention:
 * %r2 pointer to sie control block
 * %r3 guest register save area
 * __sie64a calling convention:
 * %r2 pointer to sie control block phys
 * %r3 pointer to sie control block virt
 * %r4 guest register save area
 */
ENTRY(sie64a)
ENTRY(__sie64a)
	stmg	%r6,%r14,__SF_GPRS(%r15)	# save kernel registers
	lg	%r12,__LC_CURRENT
	stg	%r2,__SF_SIE_CONTROL(%r15)	# save control block pointer
	stg	%r3,__SF_SIE_SAVEAREA(%r15)	# save guest register save area
	stg	%r2,__SF_SIE_CONTROL_PHYS(%r15)	# save sie block physical..
	stg	%r3,__SF_SIE_CONTROL(%r15)	# ...and virtual addresses
	stg	%r4,__SF_SIE_SAVEAREA(%r15)	# save guest register save area
	xc	__SF_SIE_REASON(8,%r15),__SF_SIE_REASON(%r15) # reason code = 0
	mvc	__SF_SIE_FLAGS(8,%r15),__TI_flags(%r12) # copy thread flags
	lmg	%r0,%r13,0(%r3)			# load guest gprs 0-13
	lmg	%r0,%r13,0(%r4)			# load guest gprs 0-13
	lg	%r14,__LC_GMAP			# get gmap pointer
	ltgr	%r14,%r14
	jz	.Lsie_gmap
@@ -248,6 +250,7 @@ ENTRY(sie64a)
	jnz	.Lsie_skip
	TSTMSK	__LC_CPU_FLAGS,_CIF_FPU
	jo	.Lsie_skip			# exit if fp/vx regs changed
	lg	%r14,__SF_SIE_CONTROL_PHYS(%r15)	# get sie block phys addr
	BPEXIT	__SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
.Lsie_entry:
	sie	0(%r14)
@@ -258,13 +261,14 @@ ENTRY(sie64a)
	BPOFF
	BPENTER	__SF_SIE_FLAGS(%r15),(_TIF_ISOLATE_BP|_TIF_ISOLATE_BP_GUEST)
.Lsie_skip:
	lg	%r14,__SF_SIE_CONTROL(%r15)	# get control block pointer
	ni	__SIE_PROG0C+3(%r14),0xfe	# no longer in SIE
	lctlg	%c1,%c1,__LC_KERNEL_ASCE	# load primary asce
.Lsie_done:
# some program checks are suppressing. C code (e.g. do_protection_exception)
# will rewind the PSW by the ILC, which is often 4 bytes in case of SIE. There
# are some corner cases (e.g. runtime instrumentation) where ILC is unpredictable.
# Other instructions between sie64a and .Lsie_done should not cause program
# Other instructions between __sie64a and .Lsie_done should not cause program
# interrupts. So lets use 3 nops as a landing pad for all possible rewinds.
.Lrewind_pad6:
	nopr	7
@@ -293,8 +297,8 @@ sie_exit:
	EX_TABLE(.Lrewind_pad4,.Lsie_fault)
	EX_TABLE(.Lrewind_pad2,.Lsie_fault)
	EX_TABLE(sie_exit,.Lsie_fault)
ENDPROC(sie64a)
EXPORT_SYMBOL(sie64a)
ENDPROC(__sie64a)
EXPORT_SYMBOL(__sie64a)
EXPORT_SYMBOL(sie_exit)
#endif

@@ -373,7 +377,7 @@ ENTRY(pgm_check_handler)
	j	3f			# -> fault in user space
.Lpgm_skip_asce:
#if IS_ENABLED(CONFIG_KVM)
	# cleanup critical section for program checks in sie64a
	# cleanup critical section for program checks in __sie64a
	OUTSIDE	%r9,.Lsie_gmap,.Lsie_done,1f
	SIEEXIT
	lghi	%r10,_PIF_GUEST_FAULT