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
init_hardware(void)51 init_hardware(void)
52 {
53 return B_OK;
54 }
55
56
57 status_t
init_driver(void)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
uninit_driver(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**
publish_devices(void)81 publish_devices(void)
82 {
83 return poke_name;
84 }
85
86
87 device_hooks*
find_device(const char * name)88 find_device(const char* name)
89 {
90 return &poke_hooks;
91 }
92
93
94 // #pragma mark -
95
96
97 status_t
poke_open(const char * name,uint32 flags,void ** cookie)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
poke_close(void * cookie)119 poke_close(void* cookie)
120 {
121 return B_OK;
122 }
123
124
125 status_t
poke_free(void * cookie)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
poke_control(void * cookie,uint32 op,void * arg,size_t length)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
poke_read(void * cookie,off_t position,void * buffer,size_t * numBytes)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
poke_write(void * cookie,off_t position,const void * buffer,size_t * numBytes)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