xref: /haiku/src/add-ons/kernel/bus_managers/random/driver.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2002-2013, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Jérôme Duval, korli@berlios.de
7  *		Axel Dörfler, axeld@pinc-software.de
8  *		David Reid
9  */
10 
11 
12 #include <stdio.h>
13 
14 #include <device_manager.h>
15 #include <Drivers.h>
16 #include <generic_syscall.h>
17 #include <kernel.h>
18 #include <malloc.h>
19 #include <random_defs.h>
20 #include <string.h>
21 #include <util/AutoLock.h>
22 
23 #include "yarrow_rng.h"
24 
25 
26 //#define TRACE_DRIVER
27 #ifdef TRACE_DRIVER
28 #	define TRACE(x...) dprintf("random: " x)
29 #else
30 #	define TRACE(x...) ;
31 #endif
32 #define CALLED() 			TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
33 
34 
35 #define	RANDOM_DRIVER_MODULE_NAME "bus_managers/random/driver_v1"
36 #define RANDOM_DEVICE_MODULE_NAME "bus_managers/random/device_v1"
37 
38 
39 static mutex sRandomLock;
40 static void *sRandomCookie;
41 device_manager_info* gDeviceManager;
42 
43 
44 typedef struct {
45 	device_node*			node;
46 } random_driver_info;
47 
48 
49 static status_t
50 random_queue_randomness(uint64 value)
51 {
52 	MutexLocker locker(&sRandomLock);
53 	RANDOM_ENQUEUE(value);
54 	return B_OK;
55 }
56 
57 
58 //	#pragma mark - device module API
59 
60 
61 static status_t
62 random_init_device(void* _info, void** _cookie)
63 {
64 	return B_OK;
65 }
66 
67 
68 static void
69 random_uninit_device(void* _cookie)
70 {
71 }
72 
73 
74 static status_t
75 random_open(void *deviceCookie, const char *name, int flags, void **cookie)
76 {
77 	TRACE("open(\"%s\")\n", name);
78 	return B_OK;
79 }
80 
81 
82 static status_t
83 random_read(void *cookie, off_t position, void *_buffer, size_t *_numBytes)
84 {
85 	TRACE("read(%lld,, %ld)\n", position, *_numBytes);
86 
87 	MutexLocker locker(&sRandomLock);
88 	return RANDOM_READ(sRandomCookie, _buffer, _numBytes);
89 }
90 
91 
92 static status_t
93 random_write(void *cookie, off_t position, const void *buffer, size_t *_numBytes)
94 {
95 	TRACE("write(%lld,, %ld)\n", position, *_numBytes);
96 	MutexLocker locker(&sRandomLock);
97 	return RANDOM_WRITE(sRandomCookie, buffer, _numBytes);
98 }
99 
100 
101 static status_t
102 random_control(void *cookie, uint32 op, void *arg, size_t length)
103 {
104 	TRACE("ioctl(%ld)\n", op);
105 	return B_ERROR;
106 }
107 
108 
109 static status_t
110 random_generic_syscall(const char* subsystem, uint32 function, void* buffer,
111 	size_t bufferSize)
112 {
113 	switch (function) {
114 		case RANDOM_GET_ENTROPY:
115 		{
116 			random_get_entropy_args args;
117 			if (bufferSize != sizeof(args) || !IS_USER_ADDRESS(buffer))
118 				return B_BAD_VALUE;
119 
120 			if (user_memcpy(&args, buffer, sizeof(args)) != B_OK)
121 				return B_BAD_ADDRESS;
122 			if (!IS_USER_ADDRESS(args.buffer))
123 				return B_BAD_ADDRESS;
124 
125 			status_t result = random_read(NULL, 0, args.buffer, &args.length);
126 			if (result < 0)
127 				return result;
128 
129 			return user_memcpy(buffer, &args, sizeof(args));
130 		}
131 	}
132 	return B_BAD_HANDLER;
133 }
134 
135 
136 static status_t
137 random_close(void *cookie)
138 {
139 	TRACE("close()\n");
140 	return B_OK;
141 }
142 
143 
144 static status_t
145 random_free(void *cookie)
146 {
147 	TRACE("free()\n");
148 	return B_OK;
149 }
150 
151 
152 static status_t
153 random_select(void *cookie, uint8 event, selectsync *sync)
154 {
155 	TRACE("select()\n");
156 
157 	if (event == B_SELECT_READ) {
158 		/* tell there is already data to read */
159 		notify_select_event(sync, event);
160 	} else if (event == B_SELECT_WRITE) {
161 		/* we're now writable */
162 		notify_select_event(sync, event);
163 	}
164 	return B_OK;
165 }
166 
167 
168 static status_t
169 random_deselect(void *cookie, uint8 event, selectsync *sync)
170 {
171 	TRACE("deselect()\n");
172 	return B_OK;
173 }
174 
175 
176 //	#pragma mark - driver module API
177 
178 
179 static float
180 random_supports_device(device_node *parent)
181 {
182 	CALLED();
183 	const char *bus;
184 
185 	// make sure parent is really device root
186 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
187 		return -1;
188 
189 	if (strcmp(bus, "root"))
190 		return 0.0;
191 
192 	return 1.0;
193 }
194 
195 
196 static status_t
197 random_register_device(device_node *node)
198 {
199 	CALLED();
200 
201 	// ready to register
202 	device_attr attrs[] = {
203 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { .string = "Random" }},
204 		{ B_DEVICE_FLAGS, B_UINT32_TYPE, { .ui32 = B_KEEP_DRIVER_LOADED }},
205 		{ NULL }
206 	};
207 
208 	return gDeviceManager->register_node(node, RANDOM_DRIVER_MODULE_NAME,
209 		attrs, NULL, NULL);
210 }
211 
212 
213 static status_t
214 random_init_driver(device_node *node, void **cookie)
215 {
216 	CALLED();
217 
218 	random_driver_info* info = (random_driver_info*)malloc(
219 		sizeof(random_driver_info));
220 	if (info == NULL)
221 		return B_NO_MEMORY;
222 
223 	mutex_init(&sRandomLock, "/dev/random lock");
224 	RANDOM_INIT();
225 
226 	memset(info, 0, sizeof(*info));
227 
228 	info->node = node;
229 
230 	register_generic_syscall(RANDOM_SYSCALLS, random_generic_syscall, 1, 0);
231 
232 	*cookie = info;
233 	return B_OK;
234 }
235 
236 
237 static void
238 random_uninit_driver(void *_cookie)
239 {
240 	CALLED();
241 
242 	unregister_generic_syscall(RANDOM_SYSCALLS, 1);
243 
244 	RANDOM_UNINIT();
245 
246 	mutex_destroy(&sRandomLock);
247 
248 	random_driver_info* info = (random_driver_info*)_cookie;
249 	free(info);
250 }
251 
252 
253 static status_t
254 random_register_child_devices(void* _cookie)
255 {
256 	CALLED();
257 	random_driver_info* info = (random_driver_info*)_cookie;
258 	status_t status = gDeviceManager->publish_device(info->node, "random",
259 		RANDOM_DEVICE_MODULE_NAME);
260 	if (status == B_OK) {
261 		gDeviceManager->publish_device(info->node, "urandom",
262 			RANDOM_DEVICE_MODULE_NAME);
263 	}
264 	return status;
265 }
266 
267 
268 //	#pragma mark -
269 
270 
271 module_dependency module_dependencies[] = {
272 	{B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager},
273 	{}
274 };
275 
276 
277 struct device_module_info sRandomDevice = {
278 	{
279 		RANDOM_DEVICE_MODULE_NAME,
280 		0,
281 		NULL
282 	},
283 
284 	random_init_device,
285 	random_uninit_device,
286 	NULL, // remove,
287 
288 	random_open,
289 	random_close,
290 	random_free,
291 	random_read,
292 	random_write,
293 	NULL,
294 	random_control,
295 
296 	random_select,
297 	random_deselect,
298 };
299 
300 
301 struct driver_module_info sRandomDriver = {
302 	{
303 		RANDOM_DRIVER_MODULE_NAME,
304 		0,
305 		NULL
306 	},
307 
308 	random_supports_device,
309 	random_register_device,
310 	random_init_driver,
311 	random_uninit_driver,
312 	random_register_child_devices,
313 	NULL,	// rescan
314 	NULL,	// removed
315 };
316 
317 
318 random_for_controller_interface sRandomForControllerModule = {
319 	{
320 		{
321 			RANDOM_FOR_CONTROLLER_MODULE_NAME,
322 			0,
323 			NULL
324 		},
325 
326 		NULL, // supported devices
327 		NULL,
328 		NULL,
329 		NULL,
330 		NULL
331 	},
332 
333 	random_queue_randomness,
334 };
335 
336 
337 module_info* modules[] = {
338 	(module_info*)&sRandomDriver,
339 	(module_info*)&sRandomDevice,
340 	(module_info*)&sRandomForControllerModule,
341 	NULL
342 };
343