xref: /freebsd/tools/test/stress2/misc/rdgsbase.sh (revision 02e9120893770924227138ba49df1edb3896112a)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2017 Konstantin Belousov <kib@FreeBSD.org>
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30# Test scenario for "D12023: Make WRFSBASE and WRGSBASE functional."
31
32[ `uname -m` = "amd64" ] || exit 0
33
34. ../default.cfg
35
36cat > /tmp/rdgsbase.c <<EOF
37/*
38Below is the updated version of the test program.  It is probably most
39useful to run it in parallel with the normal stress jobs.  Please note
40that the program starts two CPU-intensive threads per core, so the
41whole test load would be run 4x slower.
42
43Also, it is very useful to try to run hwpmc measurements in parallel, at
44least for some time.  E.g.,
45	pmcstat -S instructions -T
46in a terminal in parallel with other activities is enough.  I do not need
47any numbers from hwpmc, just the fact that the driver causes the series of
48NMI to adjust the load for testing.
49*/
50
51/* $Id: rdgsbase.c,v 1.9 2017/08/13 16:22:01 kostik Exp kostik $ */
52
53#include <sys/param.h>
54#include <sys/sysctl.h>
55#include <err.h>
56#include <pthread.h>
57#include <signal.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <unistd.h>
61#include <machine/sysarch.h>
62#include <machine/specialreg.h>
63#include <machine/cpufunc.h>
64
65void
66hand(int i __unused) {  /* handler */
67	_exit(0);
68}
69
70static void *
71rungs(void *arg __unused)
72{
73	volatile char x[1024];
74	unsigned i;
75	uint64_t y, oldbase;
76
77	oldbase = rdgsbase();
78	for (i = 0;;) {
79		wrgsbase((uintptr_t)&x[i]);
80		if (rdgsbase() != (uintptr_t)&x[i]) {
81			wrgsbase(oldbase);
82			printf("bug1 %lx %lx\n", rdgsbase(), (uintptr_t)&x[i]);
83			exit(1);
84		}
85		sysarch(AMD64_GET_GSBASE, &y);
86		if (y != (uintptr_t)&x[i]) {
87			wrgsbase(oldbase);
88			printf("bug2 %lx %lx\n", y, (uintptr_t)&x[i]);
89			exit(1);
90		}
91		i++;
92		if (i >= nitems(x))
93			i = 0;
94	}
95	return (NULL);
96}
97
98static void *
99runfs(void *arg __unused)
100{
101	volatile char x[1024];
102	unsigned i;
103	uint64_t y, oldbase;
104
105	oldbase = rdfsbase();
106	for (i = 0;;) {
107		wrfsbase((uintptr_t)&x[i]);
108		if (rdfsbase() != (uintptr_t)&x[i]) {
109			wrfsbase(oldbase);
110			printf("bug3 %lx %lx\n", rdfsbase(), (uintptr_t)&x[i]);
111			exit(1);
112		}
113		sysarch(AMD64_GET_FSBASE, &y);
114		if (y != (uintptr_t)&x[i]) {
115			wrfsbase(oldbase);
116			printf("bug4 %lx %lx\n", y, (uintptr_t)&x[i]);
117			exit(1);
118		}
119		i++;
120		if (i > nitems(x))
121			i = 0;
122	}
123	return (NULL);
124}
125
126static void
127start(int nthreads)
128{
129	pthread_t thrs[nthreads * 2];
130	int error, i;
131
132	for (i = 0; i < nthreads; i++) {
133		error = pthread_create(&thrs[i], NULL, rungs, NULL);
134		if (error != 0)
135			errc(1, error, "pthread_create");
136	}
137	for (; i < 2 * nthreads; i++) {
138		error = pthread_create(&thrs[i], NULL, runfs, NULL);
139		if (error != 0)
140			errc(1, error, "pthread_create");
141	}
142}
143
144int
145main(void)
146{
147	static const int mib[2] = {CTL_HW, HW_NCPU};
148	int error, nthreads;
149	u_int p[4];
150	size_t len;
151
152	do_cpuid(0, p);
153	if (p[0] < 0x7) {
154		fprintf(stderr, "CPU does not support extended functions\n");
155		return (1);
156	}
157	cpuid_count(0x7, 0x0, p);
158	if ((p[1] & CPUID_STDEXT_FSGSBASE) == 0) {
159		fprintf(stderr, "CPU does not support RDGSBASE\n");
160		return (0);
161	}
162
163	len = sizeof(nthreads);
164	error = sysctl(mib, nitems(mib), &nthreads, &len, NULL, 0);
165	if (error == -1)
166		err(1, "sysctl hw.ncpu");
167	signal(SIGALRM, hand);
168	alarm(10);
169	start(nthreads);
170	for (;;)
171		pause();
172}
173EOF
174
175mycc -o /tmp/rdgsbase /tmp/rdgsbase.c -lpthread || exit 1
176rm /tmp/rdgsbase.c
177
178(cd /tmp; /tmp/rdgsbase)
179s=$?
180
181rm -f /tmp/rdgsbase /tmp/rdgsbase.core
182exit $s
183