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
23static status_t mem_open(const char*, uint32, void**);
24static status_t mem_close(void*);
25static status_t mem_free(void*);
26static status_t mem_read(void*, off_t, void*, size_t*);
27static status_t mem_write(void*, off_t, const void*, size_t*);
28
29static area_id mem_map_target(off_t position, size_t length, uint32 protection,
30	void **virtualAddress);
31
32static const char* mem_name[] = {
33	DEVICE_NAME,
34#ifdef PUBLISH_DEV_MEM
35	DRIVER_NAME,
36#endif
37	NULL
38};
39
40
41device_hooks mem_hooks = {
42	mem_open,
43	mem_close,
44	mem_free,
45	NULL, /*mem_control,*/
46	mem_read,
47	mem_write,
48};
49
50int32 api_version = B_CUR_DRIVER_API_VERSION;
51
52
53status_t
54init_hardware(void)
55{
56	return B_OK;
57}
58
59
60status_t
61init_driver(void)
62{
63	return B_OK;
64}
65
66
67void
68uninit_driver(void)
69{
70}
71
72
73const char**
74publish_devices(void)
75{
76	return mem_name;
77}
78
79
80device_hooks*
81find_device(const char* name)
82{
83	return &mem_hooks;
84}
85
86
87status_t
88mem_open(const char* name, uint32 flags, void** cookie)
89{
90	// not really needed.
91	*cookie = NULL;
92	return B_OK;
93}
94
95
96status_t
97mem_close(void* cookie)
98{
99	return B_OK;
100}
101
102
103status_t
104mem_free(void* cookie)
105{
106	return B_OK;
107}
108
109
110status_t
111mem_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
137status_t
138mem_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
164area_id
165mem_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