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