xref: /netbsd-src/external/gpl3/gdb/dist/sim/m68hc11/dv-nvram.c (revision 9b2a9e00295c5af9c57a466f299054d5910e47d6)
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, &reg))
140     hw_abort (me, "\"reg\" property must contain one addr/size entry");
141 
142   hw_unit_address_to_attach_address (hw_parent (me),
143 				     &reg.address,
144 				     &attach_space,
145 				     &attach_address,
146 				     me);
147   hw_unit_size_to_attach_size (hw_parent (me),
148 			       &reg.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