1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*
3 * Copyright 2015, Cyril Bur, IBM Corp.
4 */
5
6#include "basic_asm.h"
7#include "vmx_asm.h"
8
9# Should be safe from C, only touches r4, r5 and v0,v1,v2
10FUNC_START(check_vmx)
11	PUSH_BASIC_STACK(32)
12	mr r4,r3
13	li	r3,1 # assume a bad result
14	li	r5,0
15	lvx	v0,r5,r4
16	vcmpequd.	v1,v0,v20
17	vmr	v2,v1
18
19	addi	r5,r5,16
20	lvx	v0,r5,r4
21	vcmpequd.	v1,v0,v21
22	vand	v2,v2,v1
23
24	addi	r5,r5,16
25	lvx	v0,r5,r4
26	vcmpequd.	v1,v0,v22
27	vand	v2,v2,v1
28
29	addi	r5,r5,16
30	lvx	v0,r5,r4
31	vcmpequd.	v1,v0,v23
32	vand	v2,v2,v1
33
34	addi	r5,r5,16
35	lvx	v0,r5,r4
36	vcmpequd.	v1,v0,v24
37	vand	v2,v2,v1
38
39	addi	r5,r5,16
40	lvx	v0,r5,r4
41	vcmpequd.	v1,v0,v25
42	vand	v2,v2,v1
43
44	addi	r5,r5,16
45	lvx	v0,r5,r4
46	vcmpequd.	v1,v0,v26
47	vand	v2,v2,v1
48
49	addi	r5,r5,16
50	lvx	v0,r5,r4
51	vcmpequd.	v1,v0,v27
52	vand	v2,v2,v1
53
54	addi	r5,r5,16
55	lvx	v0,r5,r4
56	vcmpequd.	v1,v0,v28
57	vand	v2,v2,v1
58
59	addi	r5,r5,16
60	lvx	v0,r5,r4
61	vcmpequd.	v1,v0,v29
62	vand	v2,v2,v1
63
64	addi	r5,r5,16
65	lvx	v0,r5,r4
66	vcmpequd.	v1,v0,v30
67	vand	v2,v2,v1
68
69	addi	r5,r5,16
70	lvx	v0,r5,r4
71	vcmpequd.	v1,v0,v31
72	vand	v2,v2,v1
73
74	li	r5,STACK_FRAME_LOCAL(0,0)
75	stvx	v2,r5,sp
76	ldx	r0,r5,sp
77	cmpdi	r0,0xffffffffffffffff
78	bne	1f
79	li	r3,0
801:	POP_BASIC_STACK(32)
81	blr
82FUNC_END(check_vmx)
83
84# Safe from C
85FUNC_START(test_vmx)
86	# r3 holds pointer to where to put the result of fork
87	# r4 holds pointer to the pid
88	# v20-v31 are non-volatile
89	PUSH_BASIC_STACK(512)
90	std	r3,STACK_FRAME_PARAM(0)(sp) # Address of varray
91	std r4,STACK_FRAME_PARAM(1)(sp) # address of pid
92	PUSH_VMX(STACK_FRAME_LOCAL(2,0),r4)
93
94	bl load_vmx
95	nop
96
97	li	r0,__NR_fork
98	sc
99	# Pass the result of fork back to the caller
100	ld	r9,STACK_FRAME_PARAM(1)(sp)
101	std	r3,0(r9)
102
103	ld r3,STACK_FRAME_PARAM(0)(sp)
104	bl check_vmx
105	nop
106
107	POP_VMX(STACK_FRAME_LOCAL(2,0),r4)
108	POP_BASIC_STACK(512)
109	blr
110FUNC_END(test_vmx)
111
112# int preempt_vmx(vector int *varray, int *threads_starting, int *running)
113# On starting will (atomically) decrement threads_starting as a signal that
114# the VMX have been loaded with varray. Will proceed to check the validity of
115# the VMX registers while running is not zero.
116FUNC_START(preempt_vmx)
117	PUSH_BASIC_STACK(512)
118	std r3,STACK_FRAME_PARAM(0)(sp) # vector int *varray
119	std r4,STACK_FRAME_PARAM(1)(sp) # int *threads_starting
120	std r5,STACK_FRAME_PARAM(2)(sp) # int *running
121	# VMX need to write to 16 byte aligned addresses, skip STACK_FRAME_LOCAL(3,0)
122	PUSH_VMX(STACK_FRAME_LOCAL(4,0),r4)
123
124	bl load_vmx
125	nop
126
127	sync
128	# Atomic DEC
129	ld r3,STACK_FRAME_PARAM(1)(sp)
1301:	lwarx r4,0,r3
131	addi r4,r4,-1
132	stwcx. r4,0,r3
133	bne- 1b
134
1352:	ld r3,STACK_FRAME_PARAM(0)(sp)
136	bl check_vmx
137	nop
138	cmpdi r3,0
139	bne 3f
140	ld r4,STACK_FRAME_PARAM(2)(sp)
141	ld r5,0(r4)
142	cmpwi r5,0
143	bne 2b
144
1453:	POP_VMX(STACK_FRAME_LOCAL(4,0),r4)
146	POP_BASIC_STACK(512)
147	blr
148FUNC_END(preempt_vmx)
149