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 54 init_hardware(void) 55 { 56 return B_OK; 57 } 58 59 60 status_t 61 init_driver(void) 62 { 63 return B_OK; 64 } 65 66 67 void 68 uninit_driver(void) 69 { 70 } 71 72 73 const char** 74 publish_devices(void) 75 { 76 return mem_name; 77 } 78 79 80 device_hooks* 81 find_device(const char* name) 82 { 83 return &mem_hooks; 84 } 85 86 87 status_t 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 97 mem_close(void* cookie) 98 { 99 return B_OK; 100 } 101 102 103 status_t 104 mem_free(void* cookie) 105 { 106 return B_OK; 107 } 108 109 110 status_t 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 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 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