xref: /haiku/src/add-ons/kernel/drivers/misc/poke.cpp (revision 4c07199d8201fcf267e90be0d24b76799d03cea6)
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 
21 static status_t poke_open(const char*, uint32, void**);
22 static status_t poke_close(void*);
23 static status_t poke_free(void*);
24 static status_t poke_control(void*, uint32, void*, size_t);
25 static status_t poke_read(void*, off_t, void*, size_t*);
26 static status_t poke_write(void*, off_t, const void*, size_t*);
27 
28 
29 static const char* poke_name[] = {
30     "misc/" POKE_DEVICE_NAME,
31     NULL
32 };
33 
34 
35 device_hooks poke_hooks = {
36 	poke_open,
37 	poke_close,
38 	poke_free,
39 	poke_control,
40 	poke_read,
41 	poke_write,
42 };
43 
44 int32 api_version = B_CUR_DRIVER_API_VERSION;
45 
46 isa_module_info* isa;
47 pci_module_info* pci;
48 
49 
50 status_t
51 init_hardware(void)
52 {
53 	return B_OK;
54 }
55 
56 
57 status_t
58 init_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 
72 void
73 uninit_driver(void)
74 {
75 	put_module(B_ISA_MODULE_NAME);
76 	put_module(B_PCI_MODULE_NAME);
77 }
78 
79 
80 const char**
81 publish_devices(void)
82 {
83 	return poke_name;
84 }
85 
86 
87 device_hooks*
88 find_device(const char* name)
89 {
90 	return &poke_hooks;
91 }
92 
93 
94 //	#pragma mark -
95 
96 
97 status_t
98 poke_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 
118 status_t
119 poke_close(void* cookie)
120 {
121 	return B_OK;
122 }
123 
124 
125 status_t
126 poke_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 
140 status_t
141 poke_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 
329 status_t
330 poke_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
331 {
332 	*numBytes = 0;
333 	return B_NOT_ALLOWED;
334 }
335 
336 
337 status_t
338 poke_write(void* cookie, off_t position, const void* buffer, size_t* numBytes)
339 {
340 	*numBytes = 0;
341 	return B_NOT_ALLOWED;
342 }
343