xref: /haiku/src/add-ons/kernel/drivers/misc/mem.c (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2007, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 #include <Drivers.h>
6 #include <KernelExport.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 
11 #define DRIVER_NAME "mem"
12 #define DEVICE_NAME "misc/mem"
13 
14 #define DEVMNT "/dev/"
15 
16 /* also publish /dev/mem */
17 #define PUBLISH_DEV_MEM
18 
19 static status_t mem_open(const char*, uint32, void**);
20 static status_t mem_close(void*);
21 static status_t mem_free(void*);
22 static status_t mem_read(void*, off_t, void*, size_t*);
23 static status_t mem_write(void*, off_t, const void*, size_t*);
24 
25 static area_id mem_map_target(off_t position, size_t length, uint32 protection,
26 	void **virtualAddress);
27 
28 static const char* mem_name[] = {
29 	DEVICE_NAME,
30 #ifdef PUBLISH_DEV_MEM
31 	DRIVER_NAME,
32 #endif
33 	NULL
34 };
35 
36 
37 device_hooks mem_hooks = {
38 	mem_open,
39 	mem_close,
40 	mem_free,
41 	NULL, /*mem_control,*/
42 	mem_read,
43 	mem_write,
44 };
45 
46 int32 api_version = B_CUR_DRIVER_API_VERSION;
47 
48 status_t
49 init_hardware(void)
50 {
51 	return B_OK;
52 }
53 
54 
55 status_t
56 init_driver(void)
57 {
58 	return B_OK;
59 }
60 
61 
62 void
63 uninit_driver(void)
64 {
65 }
66 
67 
68 const char**
69 publish_devices(void)
70 {
71 	return mem_name;
72 }
73 
74 
75 device_hooks*
76 find_device(const char* name)
77 {
78 	return &mem_hooks;
79 }
80 
81 
82 status_t
83 mem_open(const char* name, uint32 flags, void** cookie)
84 {
85 	// not really needed.
86 	*cookie = NULL;
87 	return B_OK;
88 }
89 
90 
91 status_t
92 mem_close(void* cookie)
93 {
94 	return B_OK;
95 }
96 
97 
98 status_t
99 mem_free(void* cookie)
100 {
101 	return B_OK;
102 }
103 
104 
105 status_t
106 mem_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
107 {
108 	void *virtualAddress;
109 	area_id area;
110 
111 	/* check permissions */
112 	if (getuid() != 0 && geteuid() != 0) {
113 		*numBytes = 0;
114 		return EPERM;
115 	}
116 
117 	area = mem_map_target(position, *numBytes, B_READ_AREA, &virtualAddress);
118 	if (area < 0) {
119 		*numBytes = 0;
120 		return area;
121 	}
122 
123 	memcpy(buffer, virtualAddress, *numBytes);
124 	delete_area(area);
125 	return B_OK;
126 }
127 
128 
129 status_t
130 mem_write(void* cookie, off_t position, const void* buffer, size_t* numBytes)
131 {
132 	void *virtualAddress;
133 	area_id area;
134 
135 	/* check permissions */
136 	if (getuid() != 0 && geteuid() != 0) {
137 		*numBytes = 0;
138 		return EPERM;
139 	}
140 
141 	area = mem_map_target(position, *numBytes, B_WRITE_AREA, &virtualAddress);
142 	if (area < 0) {
143 		*numBytes = 0;
144 		return area;
145 	}
146 
147 	memcpy(virtualAddress, buffer, *numBytes);
148 	delete_area(area);
149 	return B_OK;
150 }
151 
152 
153 area_id
154 mem_map_target(off_t position, size_t length, uint32 protection,
155 	void **virtualAddress)
156 {
157 	area_id area;
158 	phys_addr_t physicalAddress;
159 	size_t offset;
160 	size_t size;
161 
162 	/* SIZE_MAX actually but 2G should be enough anyway */
163 	if (length > SSIZE_MAX - B_PAGE_SIZE)
164 		return EINVAL;
165 
166 	/* the first page address */
167 	physicalAddress = (phys_addr_t)position & ~((off_t)B_PAGE_SIZE - 1);
168 
169 	/* offset of target into it */
170 	offset = position - (off_t)physicalAddress;
171 
172 	/* size of the whole mapping (page rounded) */
173 	size = (offset + length + B_PAGE_SIZE - 1) & ~((size_t)B_PAGE_SIZE - 1);
174 	area = map_physical_memory("mem_driver_temp", physicalAddress, size,
175 		B_ANY_KERNEL_ADDRESS, protection, virtualAddress);
176 	if (area < 0)
177 		return area;
178 
179 	*virtualAddress = (void*)((addr_t)(*virtualAddress) + offset);
180 	return area;
181 }
182