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