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