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
14	.text
15	.align 4
16	.globl __kernel_clock_gettime
17	.type  __kernel_clock_gettime,@function
18__kernel_clock_gettime:
19	CFI_STARTPROC
20	ahi	%r15,-16
21	CFI_DEF_CFA_OFFSET 176
22	CFI_VAL_OFFSET 15, -160
23	basr	%r5,0
240:	al	%r5,21f-0b(%r5)			/* get &_vdso_data */
25	chi	%r2,__CLOCK_REALTIME_COARSE
26	je	10f
27	chi	%r2,__CLOCK_REALTIME
28	je	11f
29	chi	%r2,__CLOCK_MONOTONIC_COARSE
30	je	9f
31	chi	%r2,__CLOCK_MONOTONIC
32	jne	19f
33
34	/* CLOCK_MONOTONIC */
351:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
36	tml	%r4,0x0001			/* pending update ? loop */
37	jnz	1b
38	stcke	0(%r15)				/* Store TOD clock */
39	lm	%r0,%r1,1(%r15)
40	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
41	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
42	brc	3,2f
43	ahi	%r0,-1
442:	ms	%r0,__VDSO_TK_MULT(%r5)		/*  * tk->mult */
45	lr	%r2,%r0
46	l	%r0,__VDSO_TK_MULT(%r5)
47	ltr	%r1,%r1
48	mr	%r0,%r0
49	jnm	3f
50	a	%r0,__VDSO_TK_MULT(%r5)
513:	alr	%r0,%r2
52	al	%r0,__VDSO_WTOM_NSEC(%r5)
53	al	%r1,__VDSO_WTOM_NSEC+4(%r5)
54	brc	12,5f
55	ahi	%r0,1
565:	l	%r2,__VDSO_TK_SHIFT(%r5)	/* Timekeeper shift */
57	srdl	%r0,0(%r2)			/*  >> tk->shift */
58	l	%r2,__VDSO_WTOM_SEC+4(%r5)
59	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
60	jne	1b
61	basr	%r5,0
626:	ltr	%r0,%r0
63	jnz	7f
64	cl	%r1,20f-6b(%r5)
65	jl	8f
667:	ahi	%r2,1
67	sl	%r1,20f-6b(%r5)
68	brc	3,6b
69	ahi	%r0,-1
70	j	6b
718:	st	%r2,0(%r3)			/* store tp->tv_sec */
72	st	%r1,4(%r3)			/* store tp->tv_nsec */
73	lhi	%r2,0
74	ahi	%r15,16
75	CFI_DEF_CFA_OFFSET 160
76	CFI_RESTORE 15
77	br	%r14
78
79	/* CLOCK_MONOTONIC_COARSE */
80	CFI_DEF_CFA_OFFSET 176
81	CFI_VAL_OFFSET 15, -160
829:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
83	tml	%r4,0x0001			/* pending update ? loop */
84	jnz	9b
85	l	%r2,__VDSO_WTOM_CRS_SEC+4(%r5)
86	l	%r1,__VDSO_WTOM_CRS_NSEC+4(%r5)
87	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
88	jne	9b
89	j	8b
90
91	/* CLOCK_REALTIME_COARSE */
9210:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
93	tml	%r4,0x0001			/* pending update ? loop */
94	jnz	10b
95	l	%r2,__VDSO_XTIME_CRS_SEC+4(%r5)
96	l	%r1,__VDSO_XTIME_CRS_NSEC+4(%r5)
97	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
98	jne	10b
99	j	17f
100
101	/* CLOCK_REALTIME */
10211:	l	%r4,__VDSO_UPD_COUNT+4(%r5)	/* load update counter */
103	tml	%r4,0x0001			/* pending update ? loop */
104	jnz	11b
105	stcke	0(%r15)				/* Store TOD clock */
106	lm	%r0,%r1,__VDSO_TS_END(%r5)	/* TOD steering end time */
107	s	%r0,1(%r15)			/* no - ts_steering_end */
108	sl	%r1,5(%r15)
109	brc	3,22f
110	ahi	%r0,-1
11122:	ltr	%r0,%r0				/* past end of steering? */
112	jm	24f
113	srdl	%r0,15				/* 1 per 2^16 */
114	tm	__VDSO_TS_DIR+3(%r5),0x01	/* steering direction? */
115	jz	23f
116	lcr	%r0,%r0				/* negative TOD offset */
117	lcr	%r1,%r1
118	je	23f
119	ahi	%r0,-1
12023:	a	%r0,1(%r15)			/* add TOD timestamp */
121	al	%r1,5(%r15)
122	brc	12,25f
123	ahi	%r0,1
124	j	25f
12524:	lm	%r0,%r1,1(%r15)			/* load TOD timestamp */
12625:	s	%r0,__VDSO_XTIME_STAMP(%r5)	/* TOD - cycle_last */
127	sl	%r1,__VDSO_XTIME_STAMP+4(%r5)
128	brc	3,12f
129	ahi	%r0,-1
13012:	ms	%r0,__VDSO_TK_MULT(%r5)		/*  * tk->mult */
131	lr	%r2,%r0
132	l	%r0,__VDSO_TK_MULT(%r5)
133	ltr	%r1,%r1
134	mr	%r0,%r0
135	jnm	13f
136	a	%r0,__VDSO_TK_MULT(%r5)
13713:	alr	%r0,%r2
138	al	%r0,__VDSO_XTIME_NSEC(%r5)	/*  + tk->xtime_nsec */
139	al	%r1,__VDSO_XTIME_NSEC+4(%r5)
140	brc	12,14f
141	ahi	%r0,1
14214:	l	%r2,__VDSO_TK_SHIFT(%r5)	/* Timekeeper shift */
143	srdl	%r0,0(%r2)			/*  >> tk->shift */
144	l	%r2,__VDSO_XTIME_SEC+4(%r5)
145	cl	%r4,__VDSO_UPD_COUNT+4(%r5)	/* check update counter */
146	jne	11b
147	basr	%r5,0
14815:	ltr	%r0,%r0
149	jnz	16f
150	cl	%r1,20f-15b(%r5)
151	jl	17f
15216:	ahi	%r2,1
153	sl	%r1,20f-15b(%r5)
154	brc	3,15b
155	ahi	%r0,-1
156	j	15b
15717:	st	%r2,0(%r3)			/* store tp->tv_sec */
158	st	%r1,4(%r3)			/* store tp->tv_nsec */
159	lhi	%r2,0
160	ahi	%r15,16
161	CFI_DEF_CFA_OFFSET 160
162	CFI_RESTORE 15
163	br	%r14
164
165	/* Fallback to system call */
166	CFI_DEF_CFA_OFFSET 176
167	CFI_VAL_OFFSET 15, -160
16819:	lhi	%r1,__NR_clock_gettime
169	svc	0
170	ahi	%r15,16
171	CFI_DEF_CFA_OFFSET 160
172	CFI_RESTORE 15
173	br	%r14
174	CFI_ENDPROC
175
17620:	.long	1000000000
17721:	.long	_vdso_data - 0b
178	.size	__kernel_clock_gettime,.-__kernel_clock_gettime
179