1/*
2 * Copyright 2005, Oscar Lesta. All rights reserved.
3 * Copyright 2018-2023, Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6#include "poke.h"
7
8#include <Drivers.h>
9#include <KernelExport.h>
10#include <ISA.h>
11#include <PCI.h>
12
13#include <team.h>
14#include <vm/vm.h>
15
16#if defined(__i386__) || defined(__x86_64__)
17#include <thread.h>
18#endif
19
20
21static status_t poke_open(const char*, uint32, void**);
22static status_t poke_close(void*);
23static status_t poke_free(void*);
24static status_t poke_control(void*, uint32, void*, size_t);
25static status_t poke_read(void*, off_t, void*, size_t*);
26static status_t poke_write(void*, off_t, const void*, size_t*);
27
28
29static const char* poke_name[] = {
30    "misc/" POKE_DEVICE_NAME,
31    NULL
32};
33
34
35device_hooks poke_hooks = {
36	poke_open,
37	poke_close,
38	poke_free,
39	poke_control,
40	poke_read,
41	poke_write,
42};
43
44int32 api_version = B_CUR_DRIVER_API_VERSION;
45
46isa_module_info* isa;
47pci_module_info* pci;
48
49
50status_t
51init_hardware(void)
52{
53	return B_OK;
54}
55
56
57status_t
58init_driver(void)
59{
60	if (get_module(B_ISA_MODULE_NAME, (module_info**)&isa) < B_OK)
61		return ENOSYS;
62
63	if (get_module(B_PCI_MODULE_NAME, (module_info**)&pci) < B_OK) {
64		put_module(B_ISA_MODULE_NAME);
65		return ENOSYS;
66	}
67
68	return B_OK;
69}
70
71
72void
73uninit_driver(void)
74{
75	put_module(B_ISA_MODULE_NAME);
76	put_module(B_PCI_MODULE_NAME);
77}
78
79
80const char**
81publish_devices(void)
82{
83	return poke_name;
84}
85
86
87device_hooks*
88find_device(const char* name)
89{
90	return &poke_hooks;
91}
92
93
94//	#pragma mark -
95
96
97status_t
98poke_open(const char* name, uint32 flags, void** cookie)
99{
100	*cookie = NULL;
101
102	if (getuid() != 0 && geteuid() != 0)
103		return EPERM;
104
105#if defined(__i386__) || defined(__x86_64__)
106	/* on x86, raise the IOPL so that outb/inb will work */
107	iframe* frame = x86_get_user_iframe();
108	int iopl = 3;
109	frame->flags &= ~X86_EFLAGS_IO_PRIVILEG_LEVEL;
110	frame->flags |= (iopl << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT)
111		& X86_EFLAGS_IO_PRIVILEG_LEVEL;
112#endif
113
114	return B_OK;
115}
116
117
118status_t
119poke_close(void* cookie)
120{
121	return B_OK;
122}
123
124
125status_t
126poke_free(void* cookie)
127{
128#if defined(__i386__) || defined(__x86_64__)
129	iframe* frame = x86_get_user_iframe();
130	int iopl = 0;
131	frame->flags &= ~X86_EFLAGS_IO_PRIVILEG_LEVEL;
132	frame->flags |= (iopl << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT)
133		& X86_EFLAGS_IO_PRIVILEG_LEVEL;
134#endif
135
136	return B_OK;
137}
138
139
140status_t
141poke_control(void* cookie, uint32 op, void* arg, size_t length)
142{
143	switch (op) {
144		case POKE_PORT_READ:
145		{
146			status_t result = B_OK;
147			port_io_args ioctl;
148			if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
149				return B_BAD_ADDRESS;
150			if (ioctl.signature != POKE_SIGNATURE)
151				return B_BAD_VALUE;
152
153			switch (ioctl.size) {
154				case 1:
155					ioctl.value = isa->read_io_8(ioctl.port);
156				break;
157				case 2:
158					ioctl.value = isa->read_io_16(ioctl.port);
159				break;
160				case 4:
161					ioctl.value = isa->read_io_32(ioctl.port);
162				break;
163				default:
164					result = B_BAD_VALUE;
165			}
166
167			if (user_memcpy(arg, &ioctl, sizeof(port_io_args)) != B_OK)
168				return B_BAD_ADDRESS;
169			return result;
170		}
171
172		case POKE_PORT_WRITE:
173		{
174			status_t result = B_OK;
175			port_io_args ioctl;
176			if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
177				return B_BAD_ADDRESS;
178			if (ioctl.signature != POKE_SIGNATURE)
179				return B_BAD_VALUE;
180
181			switch (ioctl.size) {
182				case 1:
183					isa->write_io_8(ioctl.port, ioctl.value);
184					break;
185				case 2:
186					isa->write_io_16(ioctl.port, ioctl.value);
187					break;
188				case 4:
189					isa->write_io_32(ioctl.port, ioctl.value);
190					break;
191				default:
192					result = B_BAD_VALUE;
193			}
194
195			return result;
196		}
197
198		case POKE_PORT_INDEXED_READ:
199		{
200			port_io_args ioctl;
201			if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
202				return B_BAD_ADDRESS;
203			if (ioctl.signature != POKE_SIGNATURE)
204				return B_BAD_VALUE;
205
206			isa->write_io_8(ioctl.port, ioctl.size);
207			ioctl.value = isa->read_io_8(ioctl.port + 1);
208
209			if (user_memcpy(arg, &ioctl, sizeof(port_io_args)) != B_OK)
210				return B_BAD_ADDRESS;
211			return B_OK;
212		}
213
214		case POKE_PORT_INDEXED_WRITE:
215		{
216			port_io_args ioctl;
217			if (user_memcpy(&ioctl, arg, sizeof(port_io_args)) != B_OK)
218				return B_BAD_ADDRESS;
219			if (ioctl.signature != POKE_SIGNATURE)
220				return B_BAD_VALUE;
221
222			isa->write_io_8(ioctl.port, ioctl.size);
223			isa->write_io_8(ioctl.port + 1, ioctl.value);
224			return B_OK;
225		}
226
227		case POKE_PCI_READ_CONFIG:
228		{
229			pci_io_args ioctl;
230			if (user_memcpy(&ioctl, arg, sizeof(pci_io_args)) != B_OK)
231				return B_BAD_ADDRESS;
232			if (ioctl.signature != POKE_SIGNATURE)
233				return B_BAD_VALUE;
234
235			ioctl.value = pci->read_pci_config(ioctl.bus, ioctl.device,
236				ioctl.function, ioctl.offset, ioctl.size);
237			if (user_memcpy(arg, &ioctl, sizeof(pci_io_args)) != B_OK)
238				return B_BAD_ADDRESS;
239			return B_OK;
240		}
241
242		case POKE_PCI_WRITE_CONFIG:
243		{
244			pci_io_args ioctl;
245			if (user_memcpy(&ioctl, arg, sizeof(pci_io_args)) != B_OK)
246				return B_BAD_ADDRESS;
247			if (ioctl.signature != POKE_SIGNATURE)
248				return B_BAD_VALUE;
249
250			pci->write_pci_config(ioctl.bus, ioctl.device, ioctl.function,
251				ioctl.offset, ioctl.size, ioctl.value);
252			return B_OK;
253		}
254
255		case POKE_GET_NTH_PCI_INFO:
256		{
257			pci_info_args ioctl;
258			if (user_memcpy(&ioctl, arg, sizeof(pci_info_args)) != B_OK)
259				return B_BAD_ADDRESS;
260			if (ioctl.signature != POKE_SIGNATURE)
261				return B_BAD_VALUE;
262
263			pci_info info;
264			ioctl.status = pci->get_nth_pci_info(ioctl.index, &info);
265
266			if (user_memcpy(ioctl.info, &info, sizeof(pci_info)) != B_OK)
267				return B_BAD_ADDRESS;
268			if (user_memcpy(arg, &ioctl, sizeof(pci_info_args)) != B_OK)
269				return B_BAD_ADDRESS;
270			return B_OK;
271		}
272
273		case POKE_GET_PHYSICAL_ADDRESS:
274		{
275			mem_map_args ioctl;
276			if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK)
277				return B_BAD_ADDRESS;
278			physical_entry table;
279			status_t result;
280
281			if (ioctl.signature != POKE_SIGNATURE)
282				return B_BAD_VALUE;
283
284			result = get_memory_map(ioctl.address, ioctl.size, &table, 1);
285			ioctl.physical_address = table.address;
286			ioctl.size = table.size;
287			if (user_memcpy(arg, &ioctl, sizeof(mem_map_args)) != B_OK)
288				return B_BAD_ADDRESS;
289			return result;
290		}
291
292		case POKE_MAP_MEMORY:
293		{
294			mem_map_args ioctl;
295			if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK)
296				return B_BAD_ADDRESS;
297			if (ioctl.signature != POKE_SIGNATURE)
298				return B_BAD_VALUE;
299
300			char name[B_OS_NAME_LENGTH];
301			if (user_strlcpy(name, ioctl.name, B_OS_NAME_LENGTH) < B_OK)
302				return B_BAD_ADDRESS;
303
304			ioctl.area = vm_map_physical_memory(team_get_current_team_id(), name,
305				(void**)&ioctl.address, ioctl.flags, ioctl.size, ioctl.protection,
306				ioctl.physical_address, false);
307
308			if (user_memcpy(arg, &ioctl, sizeof(mem_map_args)) != B_OK)
309				return B_BAD_ADDRESS;
310			return ioctl.area;
311		}
312
313		case POKE_UNMAP_MEMORY:
314		{
315			mem_map_args ioctl;
316			if (user_memcpy(&ioctl, arg, sizeof(mem_map_args)) != B_OK)
317				return B_BAD_ADDRESS;
318			if (ioctl.signature != POKE_SIGNATURE)
319				return B_BAD_VALUE;
320
321			return _user_delete_area(ioctl.area);
322		}
323	}
324
325	return B_BAD_VALUE;
326}
327
328
329status_t
330poke_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
331{
332	*numBytes = 0;
333	return B_NOT_ALLOWED;
334}
335
336
337status_t
338poke_write(void* cookie, off_t position, const void* buffer, size_t* numBytes)
339{
340	*numBytes = 0;
341	return B_NOT_ALLOWED;
342}
343