1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Userland implementation of clock_gettime() for 32 bits processes in a
4 * s390 kernel for use in the vDSO
5 *
6 *  Copyright IBM Corp. 2008
7 *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
8 */
9#include <asm/vdso.h>
10#include <asm/asm-offsets.h>
11#include <asm/unistd.h>
12#include <asm/dwarf.h>
13#include <asm/ptrace.h>
14
15	.text
16	.align 4
17	.globl __kernel_clock_gettime
18	.type  __kernel_clock_gettime,@function
19__kernel_clock_gettime:
20	CFI_STARTPROC
21	ahi	%r15,-16
22	CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD+16
23	CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
24	basr	%r5,0
250:	al	%r5,21f-0b(%r5)			/* get &_vdso_data */
26	chi	%r2,__CLOCK_REALTIME_COARSE
27	je	10f
28	chi	%r2,__CLOCK_REALTIME
29	je	11f
30	chi	%r2,__CLOCK_MONOTONIC_COARSE
31	je	9f
32	chi	%r2,__CLOCK_MONOTONIC
33	jne	19f
34
35	/* CLOCK_MONOTONIC */
361:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
37	tml	%r4,0x0001			/* pending update ? loop */
38	jnz	1b
39	stcke	0(%r15)				/* Store TOD clock */
40	lm	%r0,%r1,1(%r15)
41	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
42	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
43	brc	3,2f
44	ahi	%r0,-1
452:	ms	%r0,__VDSO_TK_MULT(%r5)		/*  * tk->mult */
46	lr	%r2,%r0
47	l	%r0,__VDSO_TK_MULT(%r5)
48	ltr	%r1,%r1
49	mr	%r0,%r0
50	jnm	3f
51	a	%r0,__VDSO_TK_MULT(%r5)
523:	alr	%r0,%r2
53	al	%r0,__VDSO_WTOM_NSEC(%r5)
54	al	%r1,__VDSO_WTOM_NSEC+4(%r5)
55	brc	12,5f
56	ahi	%r0,1
575:	l	%r2,__VDSO_TK_SHIFT(%r5)	/* Timekeeper shift */
58	srdl	%r0,0(%r2)			/*  >> tk->shift */
59	l	%r2,__VDSO_WTOM_SEC+4(%r5)
60	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
61	jne	1b
62	basr	%r5,0
636:	ltr	%r0,%r0
64	jnz	7f
65	cl	%r1,20f-6b(%r5)
66	jl	8f
677:	ahi	%r2,1
68	sl	%r1,20f-6b(%r5)
69	brc	3,6b
70	ahi	%r0,-1
71	j	6b
728:	st	%r2,0(%r3)			/* store tp->tv_sec */
73	st	%r1,4(%r3)			/* store tp->tv_nsec */
74	lhi	%r2,0
75	ahi	%r15,16
76	CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD
77	CFI_RESTORE 15
78	br	%r14
79
80	/* CLOCK_MONOTONIC_COARSE */
81	CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD+16
82	CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
839:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
84	tml	%r4,0x0001			/* pending update ? loop */
85	jnz	9b
86	l	%r2,__VDSO_WTOM_CRS_SEC+4(%r5)
87	l	%r1,__VDSO_WTOM_CRS_NSEC+4(%r5)
88	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
89	jne	9b
90	j	8b
91
92	/* CLOCK_REALTIME_COARSE */
9310:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
94	tml	%r4,0x0001			/* pending update ? loop */
95	jnz	10b
96	l	%r2,__VDSO_XTIME_CRS_SEC+4(%r5)
97	l	%r1,__VDSO_XTIME_CRS_NSEC+4(%r5)
98	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
99	jne	10b
100	j	17f
101
102	/* CLOCK_REALTIME */
10311:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
104	tml	%r4,0x0001			/* pending update ? loop */
105	jnz	11b
106	stcke	0(%r15)				/* Store TOD clock */
107	lm	%r0,%r1,__VDSO_TS_END(%r5)	/* TOD steering end time */
108	s	%r0,1(%r15)			/* no - ts_steering_end */
109	sl	%r1,5(%r15)
110	brc	3,22f
111	ahi	%r0,-1
11222:	ltr	%r0,%r0				/* past end of steering? */
113	jm	24f
114	srdl	%r0,15				/* 1 per 2^16 */
115	tm	__VDSO_TS_DIR+3(%r5),0x01	/* steering direction? */
116	jz	23f
117	lcr	%r0,%r0				/* negative TOD offset */
118	lcr	%r1,%r1
119	je	23f
120	ahi	%r0,-1
12123:	a	%r0,1(%r15)			/* add TOD timestamp */
122	al	%r1,5(%r15)
123	brc	12,25f
124	ahi	%r0,1
125	j	25f
12624:	lm	%r0,%r1,1(%r15)			/* load TOD timestamp */
12725:	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
128	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
129	brc	3,12f
130	ahi	%r0,-1
13112:	ms	%r0,__VDSO_TK_MULT(%r5)		/*  * tk->mult */
132	lr	%r2,%r0
133	l	%r0,__VDSO_TK_MULT(%r5)
134	ltr	%r1,%r1
135	mr	%r0,%r0
136	jnm	13f
137	a	%r0,__VDSO_TK_MULT(%r5)
13813:	alr	%r0,%r2
139	al	%r0,__VDSO_XTIME_NSEC(%r5)	/*  + tk->xtime_nsec */
140	al	%r1,__VDSO_XTIME_NSEC+4(%r5)
141	brc	12,14f
142	ahi	%r0,1
14314:	l	%r2,__VDSO_TK_SHIFT(%r5)	/* Timekeeper shift */
144	srdl	%r0,0(%r2)			/*  >> tk->shift */
145	l	%r2,__VDSO_XTIME_SEC+4(%r5)
146	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
147	jne	11b
148	basr	%r5,0
14915:	ltr	%r0,%r0
150	jnz	16f
151	cl	%r1,20f-15b(%r5)
152	jl	17f
15316:	ahi	%r2,1
154	sl	%r1,20f-15b(%r5)
155	brc	3,15b
156	ahi	%r0,-1
157	j	15b
15817:	st	%r2,0(%r3)			/* store tp->tv_sec */
159	st	%r1,4(%r3)			/* store tp->tv_nsec */
160	lhi	%r2,0
161	ahi	%r15,16
162	CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD
163	CFI_RESTORE 15
164	br	%r14
165
166	/* Fallback to system call */
167	CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD+16
168	CFI_VAL_OFFSET 15, -STACK_FRAME_OVERHEAD
16919:	lhi	%r1,__NR_clock_gettime
170	svc	0
171	ahi	%r15,16
172	CFI_DEF_CFA_OFFSET STACK_FRAME_OVERHEAD
173	CFI_RESTORE 15
174	br	%r14
175	CFI_ENDPROC
176
17720:	.long	1000000000
17821:	.long	_vdso_data - 0b
179	.size	__kernel_clock_gettime,.-__kernel_clock_gettime
180