1/* dv-nvram.c -- Generic driver for a non volatile ram (battery saved) 2 Copyright (C) 1999, 2000, 2007 Free Software Foundation, Inc. 3 Written by Stephane Carrez (stcarrez@worldnet.fr) 4 (From a driver model Contributed by Cygnus Solutions.) 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 19 */ 20 21 22#include "sim-main.h" 23#include "hw-main.h" 24#include "sim-assert.h" 25 26#include <unistd.h> 27#include <fcntl.h> 28#include <errno.h> 29 30 31/* DEVICE 32 33 nvram - Non Volatile Ram 34 35 36 DESCRIPTION 37 38 Implements a generic battery saved CMOS ram. This ram device does 39 not contain any realtime clock and does not generate any interrupt. 40 The ram content is loaded from a file and saved when it is changed. 41 It is intended to be generic. 42 43 44 PROPERTIES 45 46 reg <base> <length> 47 48 Base and size of the non-volatile ram bank. 49 50 file <path> 51 52 Path where the memory must be saved or loaded when we start. 53 54 mode {map | save-modified | save-all} 55 56 Controls how to load and save the memory content. 57 58 map The file is mapped in memory 59 save-modified The simulator keeps an open file descriptor to 60 the file and saves portion of memory which are 61 modified. 62 save-all The simulator saves the complete memory each time 63 it's modified (it does not keep an open file 64 descriptor). 65 66 67 PORTS 68 69 None. 70 71 72 NOTES 73 74 This device is independent of the Motorola 68hc11. 75 76 */ 77 78 79 80/* static functions */ 81 82/* Control of how to access the ram and save its content. */ 83 84enum nvram_mode 85{ 86 /* Save the complete ram block each time it's changed. 87 We don't keep an open file descriptor. This should be 88 ok for small memory banks. */ 89 NVRAM_SAVE_ALL, 90 91 /* Save only the memory bytes which are modified. 92 This mode means that we have to keep an open file 93 descriptor (O_RDWR). It's good for middle sized memory banks. */ 94 NVRAM_SAVE_MODIFIED, 95 96 /* Map file in memory (not yet implemented). 97 This mode is suitable for large memory banks. We don't allocate 98 a buffer to represent the ram, instead it's mapped in memory 99 with mmap. */ 100 NVRAM_MAP_FILE 101}; 102 103struct nvram 104{ 105 address_word base_address; /* Base address of ram. */ 106 unsigned size; /* Size of ram. */ 107 unsigned8 *data; /* Pointer to ram memory. */ 108 const char *file_name; /* Path of ram file. */ 109 int fd; /* File description of opened ram file. */ 110 enum nvram_mode mode; /* How load/save ram file. */ 111}; 112 113 114 115/* Finish off the partially created hw device. Attach our local 116 callbacks. Wire up our port names etc. */ 117 118static hw_io_read_buffer_method nvram_io_read_buffer; 119static hw_io_write_buffer_method nvram_io_write_buffer; 120 121 122 123static void 124attach_nvram_regs (struct hw *me, struct nvram *controller) 125{ 126 unsigned_word attach_address; 127 int attach_space; 128 unsigned attach_size; 129 reg_property_spec reg; 130 int result, oerrno; 131 132 /* Get ram bank description (base and size). */ 133 if (hw_find_property (me, "reg") == NULL) 134 hw_abort (me, "Missing \"reg\" property"); 135 136 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 137 hw_abort (me, "\"reg\" property must contain one addr/size entry"); 138 139 hw_unit_address_to_attach_address (hw_parent (me), 140 ®.address, 141 &attach_space, 142 &attach_address, 143 me); 144 hw_unit_size_to_attach_size (hw_parent (me), 145 ®.size, 146 &attach_size, me); 147 148 hw_attach_address (hw_parent (me), 0, 149 attach_space, attach_address, attach_size, 150 me); 151 152 controller->mode = NVRAM_SAVE_ALL; 153 controller->base_address = attach_address; 154 controller->size = attach_size; 155 controller->fd = -1; 156 157 /* Get the file where the ram content must be loaded/saved. */ 158 if(hw_find_property (me, "file") == NULL) 159 hw_abort (me, "Missing \"file\" property"); 160 161 controller->file_name = hw_find_string_property (me, "file"); 162 163 /* Get the mode which defines how to save the memory. */ 164 if(hw_find_property (me, "mode") != NULL) 165 { 166 const char *value = hw_find_string_property (me, "mode"); 167 168 if (strcmp (value, "map") == 0) 169 controller->mode = NVRAM_MAP_FILE; 170 else if (strcmp (value, "save-modified") == 0) 171 controller->mode = NVRAM_SAVE_MODIFIED; 172 else if (strcmp (value, "save-all") == 0) 173 controller->mode = NVRAM_SAVE_ALL; 174 else 175 hw_abort (me, "illegal value for mode parameter `%s': " 176 "use map, save-modified or save-all", value); 177 } 178 179 /* Initialize the ram by loading/mapping the file in memory. 180 If the file does not exist, create and give it some content. */ 181 switch (controller->mode) 182 { 183 case NVRAM_MAP_FILE: 184 hw_abort (me, "'map' mode is not yet implemented, use 'save-modified'"); 185 break; 186 187 case NVRAM_SAVE_MODIFIED: 188 case NVRAM_SAVE_ALL: 189 controller->data = (char*) hw_malloc (me, attach_size); 190 if (controller->data == 0) 191 hw_abort (me, "Not enough memory, try to use the mode 'map'"); 192 193 memset (controller->data, 0, attach_size); 194 controller->fd = open (controller->file_name, O_RDWR); 195 if (controller->fd < 0) 196 { 197 controller->fd = open (controller->file_name, 198 O_RDWR | O_CREAT, 0644); 199 if (controller->fd < 0) 200 hw_abort (me, "Cannot open or create file '%s'", 201 controller->file_name); 202 result = write (controller->fd, controller->data, attach_size); 203 if (result != attach_size) 204 { 205 oerrno = errno; 206 hw_free (me, controller->data); 207 close (controller->fd); 208 errno = oerrno; 209 hw_abort (me, "Failed to save the ram content"); 210 } 211 } 212 else 213 { 214 result = read (controller->fd, controller->data, attach_size); 215 if (result != attach_size) 216 { 217 oerrno = errno; 218 hw_free (me, controller->data); 219 close (controller->fd); 220 errno = oerrno; 221 hw_abort (me, "Failed to load the ram content"); 222 } 223 } 224 if (controller->mode == NVRAM_SAVE_ALL) 225 { 226 close (controller->fd); 227 controller->fd = -1; 228 } 229 break; 230 231 default: 232 break; 233 } 234} 235 236 237static void 238nvram_finish (struct hw *me) 239{ 240 struct nvram *controller; 241 242 controller = HW_ZALLOC (me, struct nvram); 243 244 set_hw_data (me, controller); 245 set_hw_io_read_buffer (me, nvram_io_read_buffer); 246 set_hw_io_write_buffer (me, nvram_io_write_buffer); 247 248 /* Attach ourself to our parent bus. */ 249 attach_nvram_regs (me, controller); 250} 251 252 253 254/* generic read/write */ 255 256static unsigned 257nvram_io_read_buffer (struct hw *me, 258 void *dest, 259 int space, 260 unsigned_word base, 261 unsigned nr_bytes) 262{ 263 struct nvram *controller = hw_data (me); 264 265 HW_TRACE ((me, "read 0x%08lx %d [%ld]", 266 (long) base, (int) nr_bytes, 267 (long) (base - controller->base_address))); 268 269 base -= controller->base_address; 270 if (base + nr_bytes > controller->size) 271 nr_bytes = controller->size - base; 272 273 memcpy (dest, &controller->data[base], nr_bytes); 274 return nr_bytes; 275} 276 277 278 279static unsigned 280nvram_io_write_buffer (struct hw *me, 281 const void *source, 282 int space, 283 unsigned_word base, 284 unsigned nr_bytes) 285{ 286 struct nvram *controller = hw_data (me); 287 288 HW_TRACE ((me, "write 0x%08lx %d [%ld]", 289 (long) base, (int) nr_bytes, 290 (long) (base - controller->base_address))); 291 292 base -= controller->base_address; 293 if (base + nr_bytes > controller->size) 294 nr_bytes = controller->size - base; 295 296 switch (controller->mode) 297 { 298 case NVRAM_SAVE_ALL: 299 { 300 int fd, result, oerrno; 301 302 fd = open (controller->file_name, O_WRONLY, 0644); 303 if (fd < 0) 304 { 305 return 0; 306 } 307 308 memcpy (&controller->data[base], source, nr_bytes); 309 result = write (fd, controller->data, controller->size); 310 oerrno = errno; 311 close (fd); 312 errno = oerrno; 313 314 if (result != controller->size) 315 { 316 return 0; 317 } 318 return nr_bytes; 319 } 320 321 case NVRAM_SAVE_MODIFIED: 322 { 323 off_t pos; 324 int result; 325 326 pos = lseek (controller->fd, (off_t) base, SEEK_SET); 327 if (pos != (off_t) base) 328 return 0; 329 330 result = write (controller->fd, source, nr_bytes); 331 if (result < 0) 332 return 0; 333 334 nr_bytes = result; 335 break; 336 } 337 338 default: 339 break; 340 } 341 memcpy (&controller->data[base], source, nr_bytes); 342 return nr_bytes; 343} 344 345 346const struct hw_descriptor dv_nvram_descriptor[] = { 347 { "nvram", nvram_finish, }, 348 { NULL }, 349}; 350 351