162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2015, Cyril Bur, IBM Corp.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "basic_asm.h"
762306a36Sopenharmony_ci#include "gpr_asm.h"
862306a36Sopenharmony_ci#include "fpu_asm.h"
962306a36Sopenharmony_ci#include "vmx_asm.h"
1062306a36Sopenharmony_ci#include "vsx_asm.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci * Large caveat here being that the caller cannot expect the
1462306a36Sopenharmony_ci * signal to always be sent! The hardware can (AND WILL!) abort
1562306a36Sopenharmony_ci * the transaction between the tbegin and the tsuspend (however
1662306a36Sopenharmony_ci * unlikely it seems or infrequently it actually happens).
1762306a36Sopenharmony_ci * You have been warned.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci/* long tm_signal_self(pid_t pid, long *gprs, double *fps, vector *vms, vector *vss); */
2062306a36Sopenharmony_ciFUNC_START(tm_signal_self_context_load)
2162306a36Sopenharmony_ci	PUSH_BASIC_STACK(512)
2262306a36Sopenharmony_ci	/*
2362306a36Sopenharmony_ci	 * Don't strictly need to save and restore as it depends on if
2462306a36Sopenharmony_ci	 * we're going to use them, however this reduces messy logic
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci	PUSH_VMX(STACK_FRAME_LOCAL(5,0),r8)
2762306a36Sopenharmony_ci	PUSH_FPU(512)
2862306a36Sopenharmony_ci	PUSH_NVREGS_BELOW_FPU(512)
2962306a36Sopenharmony_ci	std r3, STACK_FRAME_PARAM(0)(sp) /* pid */
3062306a36Sopenharmony_ci	std r4, STACK_FRAME_PARAM(1)(sp) /* gps */
3162306a36Sopenharmony_ci	std r5, STACK_FRAME_PARAM(2)(sp) /* fps */
3262306a36Sopenharmony_ci	std r6, STACK_FRAME_PARAM(3)(sp) /* vms */
3362306a36Sopenharmony_ci	std r7, STACK_FRAME_PARAM(4)(sp) /* vss */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(1)(sp)
3662306a36Sopenharmony_ci	cmpdi r3, 0
3762306a36Sopenharmony_ci	beq skip_gpr_lc
3862306a36Sopenharmony_ci	bl load_gpr
3962306a36Sopenharmony_ciskip_gpr_lc:
4062306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(2)(sp)
4162306a36Sopenharmony_ci	cmpdi	r3, 0
4262306a36Sopenharmony_ci	beq	skip_fpu_lc
4362306a36Sopenharmony_ci	bl load_fpu
4462306a36Sopenharmony_ciskip_fpu_lc:
4562306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(3)(sp)
4662306a36Sopenharmony_ci	cmpdi r3, 0
4762306a36Sopenharmony_ci	beq	skip_vmx_lc
4862306a36Sopenharmony_ci	bl load_vmx
4962306a36Sopenharmony_ciskip_vmx_lc:
5062306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(4)(sp)
5162306a36Sopenharmony_ci	cmpdi	r3, 0
5262306a36Sopenharmony_ci	beq	skip_vsx_lc
5362306a36Sopenharmony_ci	bl load_vsx
5462306a36Sopenharmony_ciskip_vsx_lc:
5562306a36Sopenharmony_ci	/*
5662306a36Sopenharmony_ci	 * Set r3 (return value) before tbegin. Use the pid as a known
5762306a36Sopenharmony_ci	 * 'all good' return value, zero is used to indicate a non-doomed
5862306a36Sopenharmony_ci	 * transaction.
5962306a36Sopenharmony_ci	 */
6062306a36Sopenharmony_ci	ld	r3, STACK_FRAME_PARAM(0)(sp)
6162306a36Sopenharmony_ci	tbegin.
6262306a36Sopenharmony_ci	beq	1f
6362306a36Sopenharmony_ci	tsuspend. /* Can't enter a syscall transactionally */
6462306a36Sopenharmony_ci	ld	r3, STACK_FRAME_PARAM(1)(sp)
6562306a36Sopenharmony_ci	cmpdi	r3, 0
6662306a36Sopenharmony_ci	beq skip_gpr_lt
6762306a36Sopenharmony_ci	/* Get the second half of the array */
6862306a36Sopenharmony_ci	addi	r3, r3, 8 * 18
6962306a36Sopenharmony_ci	bl load_gpr
7062306a36Sopenharmony_ciskip_gpr_lt:
7162306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(2)(sp)
7262306a36Sopenharmony_ci	cmpdi	r3, 0
7362306a36Sopenharmony_ci	beq	skip_fpu_lt
7462306a36Sopenharmony_ci	/* Get the second half of the array */
7562306a36Sopenharmony_ci	addi	r3, r3, 8 * 18
7662306a36Sopenharmony_ci	bl load_fpu
7762306a36Sopenharmony_ciskip_fpu_lt:
7862306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(3)(sp)
7962306a36Sopenharmony_ci	cmpdi r3, 0
8062306a36Sopenharmony_ci	beq	skip_vmx_lt
8162306a36Sopenharmony_ci	/* Get the second half of the array */
8262306a36Sopenharmony_ci	addi	r3, r3, 16 * 12
8362306a36Sopenharmony_ci	bl load_vmx
8462306a36Sopenharmony_ciskip_vmx_lt:
8562306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(4)(sp)
8662306a36Sopenharmony_ci	cmpdi	r3, 0
8762306a36Sopenharmony_ci	beq	skip_vsx_lt
8862306a36Sopenharmony_ci	/* Get the second half of the array */
8962306a36Sopenharmony_ci	addi	r3, r3, 16 * 12
9062306a36Sopenharmony_ci	bl load_vsx
9162306a36Sopenharmony_ciskip_vsx_lt:
9262306a36Sopenharmony_ci	li	r0, 37 /* sys_kill */
9362306a36Sopenharmony_ci	ld r3, STACK_FRAME_PARAM(0)(sp) /* pid */
9462306a36Sopenharmony_ci	li r4, 10 /* SIGUSR1 */
9562306a36Sopenharmony_ci	sc /* Taking the signal will doom the transaction */
9662306a36Sopenharmony_ci	tabort. 0
9762306a36Sopenharmony_ci	tresume. /* Be super sure we abort */
9862306a36Sopenharmony_ci	/*
9962306a36Sopenharmony_ci	 * This will cause us to resume doomed transaction and cause
10062306a36Sopenharmony_ci	 * hardware to cleanup, we'll end up at 1: anything between
10162306a36Sopenharmony_ci	 * tresume. and 1: shouldn't ever run.
10262306a36Sopenharmony_ci	 */
10362306a36Sopenharmony_ci	li r3, 0
10462306a36Sopenharmony_ci	1:
10562306a36Sopenharmony_ci	POP_VMX(STACK_FRAME_LOCAL(5,0),r4)
10662306a36Sopenharmony_ci	POP_FPU(512)
10762306a36Sopenharmony_ci	POP_NVREGS_BELOW_FPU(512)
10862306a36Sopenharmony_ci	POP_BASIC_STACK(512)
10962306a36Sopenharmony_ci	blr
11062306a36Sopenharmony_ciFUNC_END(tm_signal_self_context_load)
111