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