162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <errno.h>
362306a36Sopenharmony_ci#include <linux/unistd.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <sys/ptrace.h>
662306a36Sopenharmony_ci#include <sys/syscall.h>
762306a36Sopenharmony_ci#include <unistd.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <sysdep/tls.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#ifndef PTRACE_GET_THREAD_AREA
1262306a36Sopenharmony_ci#define PTRACE_GET_THREAD_AREA 25
1362306a36Sopenharmony_ci#endif
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#ifndef PTRACE_SET_THREAD_AREA
1662306a36Sopenharmony_ci#define PTRACE_SET_THREAD_AREA 26
1762306a36Sopenharmony_ci#endif
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* Checks whether host supports TLS, and sets *tls_min according to the value
2062306a36Sopenharmony_ci * valid on the host.
2162306a36Sopenharmony_ci * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */
2262306a36Sopenharmony_civoid check_host_supports_tls(int *supports_tls, int *tls_min)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	/* Values for x86 and x86_64.*/
2562306a36Sopenharmony_ci	int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64};
2662306a36Sopenharmony_ci	int i;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(val); i++) {
2962306a36Sopenharmony_ci		user_desc_t info;
3062306a36Sopenharmony_ci		info.entry_number = val[i];
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci		if (syscall(__NR_get_thread_area, &info) == 0) {
3362306a36Sopenharmony_ci			*tls_min = val[i];
3462306a36Sopenharmony_ci			*supports_tls = 1;
3562306a36Sopenharmony_ci			return;
3662306a36Sopenharmony_ci		} else {
3762306a36Sopenharmony_ci			if (errno == EINVAL)
3862306a36Sopenharmony_ci				continue;
3962306a36Sopenharmony_ci			else if (errno == ENOSYS)
4062306a36Sopenharmony_ci				*supports_tls = 0;
4162306a36Sopenharmony_ci			return;
4262306a36Sopenharmony_ci		}
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	*supports_tls = 0;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ciint os_set_thread_area(user_desc_t *info, int pid)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	int ret;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number,
5362306a36Sopenharmony_ci		     (unsigned long) info);
5462306a36Sopenharmony_ci	if (ret < 0)
5562306a36Sopenharmony_ci		ret = -errno;
5662306a36Sopenharmony_ci	return ret;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ciint os_get_thread_area(user_desc_t *info, int pid)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	int ret;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number,
6462306a36Sopenharmony_ci		     (unsigned long) info);
6562306a36Sopenharmony_ci	if (ret < 0)
6662306a36Sopenharmony_ci		ret = -errno;
6762306a36Sopenharmony_ci	return ret;
6862306a36Sopenharmony_ci}
69