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