1139743Simp/*-
214331Speter * Copyright (c) 1994 Christos Zoulas
314331Speter * Copyright (c) 1995 Frank van der Linden
414331Speter * Copyright (c) 1995 Scott Bartram
514331Speter * All rights reserved.
614331Speter *
714331Speter * Redistribution and use in source and binary forms, with or without
814331Speter * modification, are permitted provided that the following conditions
914331Speter * are met:
1014331Speter * 1. Redistributions of source code must retain the above copyright
1114331Speter *    notice, this list of conditions and the following disclaimer.
1214331Speter * 2. Redistributions in binary form must reproduce the above copyright
1314331Speter *    notice, this list of conditions and the following disclaimer in the
1414331Speter *    documentation and/or other materials provided with the distribution.
1514331Speter * 3. The name of the author may not be used to endorse or promote products
1614331Speter *    derived from this software without specific prior written permission
1714331Speter *
1814331Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1914331Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2014331Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2114331Speter * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2214331Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2314331Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2414331Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2514331Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2614331Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2714331Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2814331Speter *
2914331Speter *	from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp
3014331Speter */
3114331Speter
32116173Sobrien#include <sys/cdefs.h>
33116173Sobrien__FBSDID("$FreeBSD: stable/11/sys/compat/linux/linux_util.c 346819 2019-04-28 13:23:52Z dchagin $");
34116173Sobrien
35161310Snetchild#include "opt_compat.h"
36161310Snetchild
3714331Speter#include <sys/param.h>
38158311Sambrisko#include <sys/bus.h>
39177785Skib#include <sys/fcntl.h>
40130959Sbde#include <sys/lock.h>
41130959Sbde#include <sys/malloc.h>
42235063Snetchild#include <sys/kernel.h>
43158311Sambrisko#include <sys/linker_set.h>
44130959Sbde#include <sys/mutex.h>
4514331Speter#include <sys/namei.h>
4614331Speter#include <sys/proc.h>
47235063Snetchild#include <sys/sdt.h>
48141472Sjhb#include <sys/syscallsubr.h>
49130959Sbde#include <sys/systm.h>
5014331Speter#include <sys/vnode.h>
5114331Speter
52108541Salfred#include <machine/stdarg.h>
53108541Salfred
5464913Smarcel#include <compat/linux/linux_util.h>
5514331Speter
56283421SdchaginMALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
57283441SdchaginMALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures");
58283427SdchaginMALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes");
59283427SdchaginMALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futex waiting proc");
60235063Snetchild
6114331Speterconst char      linux_emul_path[] = "/compat/linux";
6214331Speter
6314331Speter/*
64166944Snetchild * Search an alternate path before passing pathname arguments on to
65166944Snetchild * system calls. Useful for keeping a separate 'emulation tree'.
6614331Speter *
67166944Snetchild * If cflag is set, we check if an attempt can be made to create the
68166944Snetchild * named file, i.e. we check if the directory it should be in exists.
6914331Speter */
7014331Speterint
71235063Snetchildlinux_emul_convpath(struct thread *td, const char *path, enum uio_seg pathseg,
72235063Snetchild    char **pbuf, int cflag, int dfd)
73102803Siedowse{
74235063Snetchild	int retval;
7514331Speter
76235063Snetchild	retval = kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
77235063Snetchild	    cflag, dfd);
78235063Snetchild
79235063Snetchild	return (retval);
8014331Speter}
81108541Salfred
82108541Salfredvoid
83108541Salfredlinux_msg(const struct thread *td, const char *fmt, ...)
84108541Salfred{
85108541Salfred	va_list ap;
86108541Salfred	struct proc *p;
87108541Salfred
88108541Salfred	p = td->td_proc;
89108541Salfred	printf("linux: pid %d (%s): ", (int)p->p_pid, p->p_comm);
90108541Salfred	va_start(ap, fmt);
91108541Salfred	vprintf(fmt, ap);
92108541Salfred	va_end(ap);
93108541Salfred	printf("\n");
94108541Salfred}
95158311Sambrisko
96158311Sambriskostruct device_element
97158311Sambrisko{
98158311Sambrisko	TAILQ_ENTRY(device_element) list;
99158311Sambrisko	struct linux_device_handler entry;
100158311Sambrisko};
101158311Sambrisko
102158311Sambriskostatic TAILQ_HEAD(, device_element) devices =
103158311Sambrisko	TAILQ_HEAD_INITIALIZER(devices);
104158311Sambrisko
105158311Sambriskostatic struct linux_device_handler null_handler =
106158311Sambrisko	{ "mem", "mem", "null", "null", 1, 3, 1};
107158311Sambrisko
108158311SambriskoDATA_SET(linux_device_handler_set, null_handler);
109158311Sambrisko
110158311Sambriskochar *
111158311Sambriskolinux_driver_get_name_dev(device_t dev)
112158311Sambrisko{
113158311Sambrisko	struct device_element *de;
114158311Sambrisko	const char *device_name = device_get_name(dev);
115158311Sambrisko
116283421Sdchagin	if (device_name == NULL)
117346819Sdchagin		return (NULL);
118158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
119283421Sdchagin		if (strcmp(device_name, de->entry.bsd_driver_name) == 0)
120158311Sambrisko			return (de->entry.linux_driver_name);
121158311Sambrisko	}
122158311Sambrisko
123283421Sdchagin	return (NULL);
124158311Sambrisko}
125158311Sambrisko
126158311Sambriskoint
127231378Sedlinux_driver_get_major_minor(const char *node, int *major, int *minor)
128158311Sambrisko{
129158311Sambrisko	struct device_element *de;
130325015Stijl	unsigned long devno;
131325015Stijl	size_t sz;
132158311Sambrisko
133283421Sdchagin	if (node == NULL || major == NULL || minor == NULL)
134346819Sdchagin		return (1);
135179486Sed
136325015Stijl	sz = sizeof("pts/") - 1;
137325015Stijl	if (strncmp(node, "pts/", sz) == 0 && node[sz] != '\0') {
138179486Sed		/*
139179486Sed		 * Linux checks major and minors of the slave device
140179486Sed		 * to make sure it's a pty device, so let's make him
141179486Sed		 * believe it is.
142179486Sed		 */
143325015Stijl		devno = strtoul(node + sz, NULL, 10);
144179486Sed		*major = 136 + (devno / 256);
145179486Sed		*minor = devno % 256;
146325015Stijl		return (0);
147325015Stijl	}
148235063Snetchild
149325015Stijl	sz = sizeof("dri/card") - 1;
150325015Stijl	if (strncmp(node, "dri/card", sz) == 0 && node[sz] != '\0') {
151325015Stijl		devno = strtoul(node + sz, NULL, 10);
152325015Stijl		*major = 226 + (devno / 256);
153325015Stijl		*minor = devno % 256;
154283421Sdchagin		return (0);
155179486Sed	}
156325015Stijl	sz = sizeof("dri/controlD") - 1;
157325015Stijl	if (strncmp(node, "dri/controlD", sz) == 0 && node[sz] != '\0') {
158325015Stijl		devno = strtoul(node + sz, NULL, 10);
159325015Stijl		*major = 226 + (devno / 256);
160325015Stijl		*minor = devno % 256;
161325015Stijl		return (0);
162325015Stijl	}
163325015Stijl	sz = sizeof("dri/renderD") - 1;
164325015Stijl	if (strncmp(node, "dri/renderD", sz) == 0 && node[sz] != '\0') {
165325015Stijl		devno = strtoul(node + sz, NULL, 10);
166325015Stijl		*major = 226 + (devno / 256);
167325015Stijl		*minor = devno % 256;
168325015Stijl		return (0);
169325015Stijl	}
170325015Stijl	sz = sizeof("drm/") - 1;
171325015Stijl	if (strncmp(node, "drm/", sz) == 0 && node[sz] != '\0') {
172325015Stijl		devno = strtoul(node + sz, NULL, 10);
173325015Stijl		*major = 226 + (devno / 256);
174325015Stijl		*minor = devno % 256;
175325015Stijl		return (0);
176325015Stijl	}
177179486Sed
178158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
179158311Sambrisko		if (strcmp(node, de->entry.bsd_device_name) == 0) {
180158311Sambrisko			*major = de->entry.linux_major;
181158311Sambrisko			*minor = de->entry.linux_minor;
182283421Sdchagin			return (0);
183158311Sambrisko		}
184158311Sambrisko	}
185158311Sambrisko
186283421Sdchagin	return (1);
187158311Sambrisko}
188158311Sambrisko
189158311Sambriskochar *
190158311Sambriskolinux_get_char_devices()
191158311Sambrisko{
192158311Sambrisko	struct device_element *de;
193158311Sambrisko	char *temp, *string, *last;
194158311Sambrisko	char formated[256];
195158311Sambrisko	int current_size = 0, string_size = 1024;
196158311Sambrisko
197184205Sdes	string = malloc(string_size, M_LINUX, M_WAITOK);
198158311Sambrisko	string[0] = '\000';
199158311Sambrisko	last = "";
200158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
201158311Sambrisko		if (!de->entry.linux_char_device)
202158311Sambrisko			continue;
203158311Sambrisko		temp = string;
204158311Sambrisko		if (strcmp(last, de->entry.bsd_driver_name) != 0) {
205158311Sambrisko			last = de->entry.bsd_driver_name;
206158311Sambrisko
207158311Sambrisko			snprintf(formated, sizeof(formated), "%3d %s\n",
208158311Sambrisko				 de->entry.linux_major,
209158311Sambrisko				 de->entry.linux_device_name);
210158311Sambrisko			if (strlen(formated) + current_size
211158311Sambrisko			    >= string_size) {
212158311Sambrisko				string_size *= 2;
213184205Sdes				string = malloc(string_size,
214158311Sambrisko				    M_LINUX, M_WAITOK);
215158311Sambrisko				bcopy(temp, string, current_size);
216184205Sdes				free(temp, M_LINUX);
217158311Sambrisko			}
218158311Sambrisko			strcat(string, formated);
219158311Sambrisko			current_size = strlen(string);
220158311Sambrisko		}
221158311Sambrisko	}
222158311Sambrisko
223283421Sdchagin	return (string);
224158311Sambrisko}
225158311Sambrisko
226158311Sambriskovoid
227158311Sambriskolinux_free_get_char_devices(char *string)
228158311Sambrisko{
229235063Snetchild
230184205Sdes	free(string, M_LINUX);
231158311Sambrisko}
232158311Sambrisko
233158311Sambriskostatic int linux_major_starting = 200;
234158311Sambrisko
235158311Sambriskoint
236158311Sambriskolinux_device_register_handler(struct linux_device_handler *d)
237158311Sambrisko{
238158311Sambrisko	struct device_element *de;
239158311Sambrisko
240283421Sdchagin	if (d == NULL)
241158311Sambrisko		return (EINVAL);
242158311Sambrisko
243235063Snetchild	de = malloc(sizeof(*de), M_LINUX, M_WAITOK);
244158311Sambrisko	if (d->linux_major < 0) {
245158311Sambrisko		d->linux_major = linux_major_starting++;
246158311Sambrisko	}
247158311Sambrisko	bcopy(d, &de->entry, sizeof(*d));
248158311Sambrisko
249158311Sambrisko	/* Add the element to the list, sorted on span. */
250158311Sambrisko	TAILQ_INSERT_TAIL(&devices, de, list);
251158311Sambrisko
252158311Sambrisko	return (0);
253158311Sambrisko}
254158311Sambrisko
255158311Sambriskoint
256158311Sambriskolinux_device_unregister_handler(struct linux_device_handler *d)
257158311Sambrisko{
258158311Sambrisko	struct device_element *de;
259158311Sambrisko
260283421Sdchagin	if (d == NULL)
261158311Sambrisko		return (EINVAL);
262158311Sambrisko
263158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
264158311Sambrisko		if (bcmp(d, &de->entry, sizeof(*d)) == 0) {
265158311Sambrisko			TAILQ_REMOVE(&devices, de, list);
266184205Sdes			free(de, M_LINUX);
267235063Snetchild
268158311Sambrisko			return (0);
269158311Sambrisko		}
270158311Sambrisko	}
271158311Sambrisko
272158311Sambrisko	return (EINVAL);
273158311Sambrisko}
274