xref: /titanic_50/usr/src/lib/commpage/i386/cp_subr.s (revision 263f549e5da8b32c4922f586afb365b8ae388a6c)
1*263f549eSPatrick Mooney/*
2*263f549eSPatrick Mooney * This file and its contents are supplied under the terms of the
3*263f549eSPatrick Mooney * Common Development and Distribution License ("CDDL"), version 1.0.
4*263f549eSPatrick Mooney * You may only use this file in accordance with the terms of version
5*263f549eSPatrick Mooney * 1.0 of the CDDL.
6*263f549eSPatrick Mooney *
7*263f549eSPatrick Mooney * A full copy of the text of the CDDL should have accompanied this
8*263f549eSPatrick Mooney * source.  A copy of the CDDL is also available via the Internet at
9*263f549eSPatrick Mooney * http://www.illumos.org/license/CDDL.
10*263f549eSPatrick Mooney */
11*263f549eSPatrick Mooney
12*263f549eSPatrick Mooney/*
13*263f549eSPatrick Mooney * Copyright 2016 Joyent, Inc.
14*263f549eSPatrick Mooney */
15*263f549eSPatrick Mooney
16*263f549eSPatrick Mooney#include <sys/asm_linkage.h>
17*263f549eSPatrick Mooney#include <sys/segments.h>
18*263f549eSPatrick Mooney#include <sys/time_impl.h>
19*263f549eSPatrick Mooney#include <sys/tsc.h>
20*263f549eSPatrick Mooney#include <cp_offsets.h>
21*263f549eSPatrick Mooney
22*263f549eSPatrick Mooney#define	GETCPU_GDT_OFFSET	SEL_GDT(GDT_CPUID, SEL_UPL)
23*263f549eSPatrick Mooney
24*263f549eSPatrick Mooney	.file	"cp_subr.s"
25*263f549eSPatrick Mooney
26*263f549eSPatrick Mooney/*
27*263f549eSPatrick Mooney * hrtime_t
28*263f549eSPatrick Mooney * __cp_tsc_read(uint_t cp_tsc_type)
29*263f549eSPatrick Mooney *
30*263f549eSPatrick Mooney * Stack usage: 0x18 bytes
31*263f549eSPatrick Mooney */
32*263f549eSPatrick Mooney	ENTRY_NP(__cp_tsc_read)
33*263f549eSPatrick Mooney	pushl	%ebp
34*263f549eSPatrick Mooney	movl	%esp, %ebp
35*263f549eSPatrick Mooney	pushl	%edi
36*263f549eSPatrick Mooney	pushl	%esi
37*263f549eSPatrick Mooney	subl	$0x4, %esp
38*263f549eSPatrick Mooney
39*263f549eSPatrick Mooney	movl	0x8(%ebp), %edi
40*263f549eSPatrick Mooney	movl	CP_TSC_TYPE(%edi), %eax
41*263f549eSPatrick Mooney	movl	CP_TSC_NCPU(%edi), %esi
42*263f549eSPatrick Mooney	cmpl	$TSC_TSCP, %eax
43*263f549eSPatrick Mooney	jne	3f
44*263f549eSPatrick Mooney	rdtscp
45*263f549eSPatrick Mooney	cmpl	$0, %esi
46*263f549eSPatrick Mooney	jne	2f
47*263f549eSPatrick Mooney1:
48*263f549eSPatrick Mooney	addl	$0x4, %esp
49*263f549eSPatrick Mooney	popl	%esi
50*263f549eSPatrick Mooney	popl	%edi
51*263f549eSPatrick Mooney	leave
52*263f549eSPatrick Mooney	ret
53*263f549eSPatrick Mooney2:
54*263f549eSPatrick Mooney	/*
55*263f549eSPatrick Mooney	 * When cp_tsc_ncpu is non-zero, it indicates the length of the
56*263f549eSPatrick Mooney	 * cp_tsc_sync_tick_delta array, which contains per-CPU offsets for the
57*263f549eSPatrick Mooney	 * TSC.  The CPU ID furnished by the IA32_TSC_AUX register via rdtscp
58*263f549eSPatrick Mooney	 * is used to look up an offset value in that array and apply it to the
59*263f549eSPatrick Mooney	 * TSC reading.
60*263f549eSPatrick Mooney	 */
61*263f549eSPatrick Mooney	leal	CP_TSC_SYNC_TICK_DELTA(%edi), %esi
62*263f549eSPatrick Mooney	leal	(%esi, %ecx, 8), %ecx
63*263f549eSPatrick Mooney	addl	(%ecx), %eax
64*263f549eSPatrick Mooney	adcl	0x4(%ecx), %edx
65*263f549eSPatrick Mooney	jmp	1b
66*263f549eSPatrick Mooney
67*263f549eSPatrick Mooney3:
68*263f549eSPatrick Mooney	cmpl	$0, %esi
69*263f549eSPatrick Mooney	je	4f
70*263f549eSPatrick Mooney	mov	$GETCPU_GDT_OFFSET, %eax
71*263f549eSPatrick Mooney	lsl	%ax, %eax
72*263f549eSPatrick Mooney	movl	%eax, (%esp)
73*263f549eSPatrick Mooney	movl	CP_TSC_TYPE(%edi), %eax
74*263f549eSPatrick Mooney
75*263f549eSPatrick Mooney4:
76*263f549eSPatrick Mooney	cmpl	$TSC_RDTSC_MFENCE, %eax
77*263f549eSPatrick Mooney	jne	5f
78*263f549eSPatrick Mooney	mfence
79*263f549eSPatrick Mooney	rdtsc
80*263f549eSPatrick Mooney	jmp	8f
81*263f549eSPatrick Mooney
82*263f549eSPatrick Mooney5:
83*263f549eSPatrick Mooney	cmpl	$TSC_RDTSC_LFENCE, %eax
84*263f549eSPatrick Mooney	jne	6f
85*263f549eSPatrick Mooney	lfence
86*263f549eSPatrick Mooney	rdtsc
87*263f549eSPatrick Mooney	jmp	8f
88*263f549eSPatrick Mooney
89*263f549eSPatrick Mooney6:
90*263f549eSPatrick Mooney	cmpl	$TSC_RDTSC_CPUID, %eax
91*263f549eSPatrick Mooney	jne	7f
92*263f549eSPatrick Mooney	pushl	%ebx
93*263f549eSPatrick Mooney	xorl	%eax, %eax
94*263f549eSPatrick Mooney	cpuid
95*263f549eSPatrick Mooney	rdtsc
96*263f549eSPatrick Mooney	popl	%ebx
97*263f549eSPatrick Mooney	jmp	8f
98*263f549eSPatrick Mooney
99*263f549eSPatrick Mooney7:
100*263f549eSPatrick Mooney	/*
101*263f549eSPatrick Mooney	 * Other protections should have prevented this function from being
102*263f549eSPatrick Mooney	 * called in the first place.  The only sane action is to abort.
103*263f549eSPatrick Mooney	 * The easiest means in this context is via SIGILL.
104*263f549eSPatrick Mooney	 */
105*263f549eSPatrick Mooney	ud2a
106*263f549eSPatrick Mooney
107*263f549eSPatrick Mooney8:
108*263f549eSPatrick Mooney
109*263f549eSPatrick Mooney	cmpl	$0, %esi
110*263f549eSPatrick Mooney	je	1b
111*263f549eSPatrick Mooney	/*
112*263f549eSPatrick Mooney	 * With a TSC reading in-hand, confirm that the thread has not migrated
113*263f549eSPatrick Mooney	 * since the cpu_id was first checked.
114*263f549eSPatrick Mooney	 */
115*263f549eSPatrick Mooney	movl	$GETCPU_GDT_OFFSET, %ecx
116*263f549eSPatrick Mooney	lsl	%cx, %ecx
117*263f549eSPatrick Mooney	movl	(%esp), %esi
118*263f549eSPatrick Mooney	cmpl	%ecx, %esi
119*263f549eSPatrick Mooney	je	9f
120*263f549eSPatrick Mooney	/*
121*263f549eSPatrick Mooney	 * There was a CPU migration, perform another reading.
122*263f549eSPatrick Mooney	 */
123*263f549eSPatrick Mooney	movl	%eax, (%esp)
124*263f549eSPatrick Mooney	movl	CP_TSC_NCPU(%edi), %esi
125*263f549eSPatrick Mooney	movl	CP_TSC_TYPE(%edi), %eax
126*263f549eSPatrick Mooney	jmp	4b
127*263f549eSPatrick Mooney
128*263f549eSPatrick Mooney9:
129*263f549eSPatrick Mooney	/* Grab the per-cpu offset and add it to the TSC result */
130*263f549eSPatrick Mooney	leal	CP_TSC_SYNC_TICK_DELTA(%edi), %esi
131*263f549eSPatrick Mooney	leal	(%esi, %ecx, 8), %ecx
132*263f549eSPatrick Mooney	addl	(%ecx), %eax
133*263f549eSPatrick Mooney	adcl	0x4(%ecx), %edx
134*263f549eSPatrick Mooney	jmp	1b
135*263f549eSPatrick Mooney	SET_SIZE(__cp_tsc_read)
136*263f549eSPatrick Mooney
137*263f549eSPatrick Mooney/*
138*263f549eSPatrick Mooney * uint_t
139*263f549eSPatrick Mooney * __cp_getcpu(uint_t cp_tsc_type)
140*263f549eSPatrick Mooney */
141*263f549eSPatrick Mooney	ENTRY_NP(__cp_getcpu)
142*263f549eSPatrick Mooney	/*
143*263f549eSPatrick Mooney	 * If RDTSCP is available, it is a quick way to grab the cpu_id which
144*263f549eSPatrick Mooney	 * is stored in the TSC_AUX MSR by the kernel.
145*263f549eSPatrick Mooney	 */
146*263f549eSPatrick Mooney	movl	4(%esp), %eax
147*263f549eSPatrick Mooney	movl	CP_TSC_TYPE(%eax), %eax
148*263f549eSPatrick Mooney	cmpl	$TSC_TSCP, %eax
149*263f549eSPatrick Mooney	jne	1f
150*263f549eSPatrick Mooney	rdtscp
151*263f549eSPatrick Mooney	movl	%ecx, %eax
152*263f549eSPatrick Mooney	ret
153*263f549eSPatrick Mooney1:
154*263f549eSPatrick Mooney	mov	$GETCPU_GDT_OFFSET, %eax
155*263f549eSPatrick Mooney	lsl	%ax, %eax
156*263f549eSPatrick Mooney	ret
157*263f549eSPatrick Mooney	SET_SIZE(__cp_getcpu)
158