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$");
34116173Sobrien
35161310Snetchild#include "opt_compat.h"
36235063Snetchild#include "opt_kdtrace.h"
37161310Snetchild
3814331Speter#include <sys/param.h>
39158311Sambrisko#include <sys/bus.h>
40177785Skib#include <sys/fcntl.h>
41130959Sbde#include <sys/lock.h>
42130959Sbde#include <sys/malloc.h>
43235063Snetchild#include <sys/kernel.h>
44158311Sambrisko#include <sys/linker_set.h>
45130959Sbde#include <sys/mutex.h>
4614331Speter#include <sys/namei.h>
4714331Speter#include <sys/proc.h>
48235063Snetchild#include <sys/sdt.h>
49141472Sjhb#include <sys/syscallsubr.h>
50130959Sbde#include <sys/systm.h>
5114331Speter#include <sys/vnode.h>
5214331Speter
53108541Salfred#include <machine/stdarg.h>
54108541Salfred
5564913Smarcel#include <compat/linux/linux_util.h>
5614331Speter
57293527SdchaginMALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
58293546SdchaginMALLOC_DEFINE(M_EPOLL, "lepoll", "Linux events structures");
59293532SdchaginMALLOC_DEFINE(M_FUTEX, "futex", "Linux futexes");
60293532SdchaginMALLOC_DEFINE(M_FUTEX_WP, "futex wp", "Linux futex waiting proc");
61235063Snetchild
6214331Speterconst char      linux_emul_path[] = "/compat/linux";
6314331Speter
6414331Speter/*
65166944Snetchild * Search an alternate path before passing pathname arguments on to
66166944Snetchild * system calls. Useful for keeping a separate 'emulation tree'.
6714331Speter *
68166944Snetchild * If cflag is set, we check if an attempt can be made to create the
69166944Snetchild * named file, i.e. we check if the directory it should be in exists.
7014331Speter */
7114331Speterint
72235063Snetchildlinux_emul_convpath(struct thread *td, const char *path, enum uio_seg pathseg,
73235063Snetchild    char **pbuf, int cflag, int dfd)
74102803Siedowse{
75235063Snetchild	int retval;
7614331Speter
77235063Snetchild	retval = kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
78235063Snetchild	    cflag, dfd);
79235063Snetchild
80235063Snetchild	return (retval);
8114331Speter}
82108541Salfred
83108541Salfredvoid
84108541Salfredlinux_msg(const struct thread *td, const char *fmt, ...)
85108541Salfred{
86108541Salfred	va_list ap;
87108541Salfred	struct proc *p;
88108541Salfred
89108541Salfred	p = td->td_proc;
90108541Salfred	printf("linux: pid %d (%s): ", (int)p->p_pid, p->p_comm);
91108541Salfred	va_start(ap, fmt);
92108541Salfred	vprintf(fmt, ap);
93108541Salfred	va_end(ap);
94108541Salfred	printf("\n");
95108541Salfred}
96158311Sambrisko
97158311Sambriskostruct device_element
98158311Sambrisko{
99158311Sambrisko	TAILQ_ENTRY(device_element) list;
100158311Sambrisko	struct linux_device_handler entry;
101158311Sambrisko};
102158311Sambrisko
103158311Sambriskostatic TAILQ_HEAD(, device_element) devices =
104158311Sambrisko	TAILQ_HEAD_INITIALIZER(devices);
105158311Sambrisko
106158311Sambriskostatic struct linux_device_handler null_handler =
107158311Sambrisko	{ "mem", "mem", "null", "null", 1, 3, 1};
108158311Sambrisko
109158311SambriskoDATA_SET(linux_device_handler_set, null_handler);
110158311Sambrisko
111158311Sambriskochar *
112158311Sambriskolinux_driver_get_name_dev(device_t dev)
113158311Sambrisko{
114158311Sambrisko	struct device_element *de;
115158311Sambrisko	const char *device_name = device_get_name(dev);
116158311Sambrisko
117293527Sdchagin	if (device_name == NULL)
118158311Sambrisko		return NULL;
119158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
120293527Sdchagin		if (strcmp(device_name, de->entry.bsd_driver_name) == 0)
121158311Sambrisko			return (de->entry.linux_driver_name);
122158311Sambrisko	}
123158311Sambrisko
124293527Sdchagin	return (NULL);
125158311Sambrisko}
126158311Sambrisko
127158311Sambriskoint
128231378Sedlinux_driver_get_major_minor(const char *node, int *major, int *minor)
129158311Sambrisko{
130158311Sambrisko	struct device_element *de;
131158311Sambrisko
132293527Sdchagin	if (node == NULL || major == NULL || minor == NULL)
133158311Sambrisko		return 1;
134179486Sed
135179486Sed	if (strlen(node) > strlen("pts/") &&
136179486Sed	    strncmp(node, "pts/", strlen("pts/")) == 0) {
137179486Sed		unsigned long devno;
138179486Sed
139179486Sed		/*
140179486Sed		 * Linux checks major and minors of the slave device
141179486Sed		 * to make sure it's a pty device, so let's make him
142179486Sed		 * believe it is.
143179486Sed		 */
144179486Sed		devno = strtoul(node + strlen("pts/"), NULL, 10);
145179486Sed		*major = 136 + (devno / 256);
146179486Sed		*minor = devno % 256;
147235063Snetchild
148293527Sdchagin		return (0);
149179486Sed	}
150179486Sed
151158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
152158311Sambrisko		if (strcmp(node, de->entry.bsd_device_name) == 0) {
153158311Sambrisko			*major = de->entry.linux_major;
154158311Sambrisko			*minor = de->entry.linux_minor;
155293527Sdchagin			return (0);
156158311Sambrisko		}
157158311Sambrisko	}
158158311Sambrisko
159293527Sdchagin	return (1);
160158311Sambrisko}
161158311Sambrisko
162158311Sambriskochar *
163158311Sambriskolinux_get_char_devices()
164158311Sambrisko{
165158311Sambrisko	struct device_element *de;
166158311Sambrisko	char *temp, *string, *last;
167158311Sambrisko	char formated[256];
168158311Sambrisko	int current_size = 0, string_size = 1024;
169158311Sambrisko
170184205Sdes	string = malloc(string_size, M_LINUX, M_WAITOK);
171158311Sambrisko	string[0] = '\000';
172158311Sambrisko	last = "";
173158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
174158311Sambrisko		if (!de->entry.linux_char_device)
175158311Sambrisko			continue;
176158311Sambrisko		temp = string;
177158311Sambrisko		if (strcmp(last, de->entry.bsd_driver_name) != 0) {
178158311Sambrisko			last = de->entry.bsd_driver_name;
179158311Sambrisko
180158311Sambrisko			snprintf(formated, sizeof(formated), "%3d %s\n",
181158311Sambrisko				 de->entry.linux_major,
182158311Sambrisko				 de->entry.linux_device_name);
183158311Sambrisko			if (strlen(formated) + current_size
184158311Sambrisko			    >= string_size) {
185158311Sambrisko				string_size *= 2;
186184205Sdes				string = malloc(string_size,
187158311Sambrisko				    M_LINUX, M_WAITOK);
188158311Sambrisko				bcopy(temp, string, current_size);
189184205Sdes				free(temp, M_LINUX);
190158311Sambrisko			}
191158311Sambrisko			strcat(string, formated);
192158311Sambrisko			current_size = strlen(string);
193158311Sambrisko		}
194158311Sambrisko	}
195158311Sambrisko
196293527Sdchagin	return (string);
197158311Sambrisko}
198158311Sambrisko
199158311Sambriskovoid
200158311Sambriskolinux_free_get_char_devices(char *string)
201158311Sambrisko{
202235063Snetchild
203184205Sdes	free(string, M_LINUX);
204158311Sambrisko}
205158311Sambrisko
206158311Sambriskostatic int linux_major_starting = 200;
207158311Sambrisko
208158311Sambriskoint
209158311Sambriskolinux_device_register_handler(struct linux_device_handler *d)
210158311Sambrisko{
211158311Sambrisko	struct device_element *de;
212158311Sambrisko
213293527Sdchagin	if (d == NULL)
214158311Sambrisko		return (EINVAL);
215158311Sambrisko
216235063Snetchild	de = malloc(sizeof(*de), M_LINUX, M_WAITOK);
217158311Sambrisko	if (d->linux_major < 0) {
218158311Sambrisko		d->linux_major = linux_major_starting++;
219158311Sambrisko	}
220158311Sambrisko	bcopy(d, &de->entry, sizeof(*d));
221158311Sambrisko
222158311Sambrisko	/* Add the element to the list, sorted on span. */
223158311Sambrisko	TAILQ_INSERT_TAIL(&devices, de, list);
224158311Sambrisko
225158311Sambrisko	return (0);
226158311Sambrisko}
227158311Sambrisko
228158311Sambriskoint
229158311Sambriskolinux_device_unregister_handler(struct linux_device_handler *d)
230158311Sambrisko{
231158311Sambrisko	struct device_element *de;
232158311Sambrisko
233293527Sdchagin	if (d == NULL)
234158311Sambrisko		return (EINVAL);
235158311Sambrisko
236158311Sambrisko	TAILQ_FOREACH(de, &devices, list) {
237158311Sambrisko		if (bcmp(d, &de->entry, sizeof(*d)) == 0) {
238158311Sambrisko			TAILQ_REMOVE(&devices, de, list);
239184205Sdes			free(de, M_LINUX);
240235063Snetchild
241158311Sambrisko			return (0);
242158311Sambrisko		}
243158311Sambrisko	}
244158311Sambrisko
245158311Sambrisko	return (EINVAL);
246158311Sambrisko}
247