merge from gcc
[external/binutils.git] / sim / m68hc11 / dv-nvram.c
1 /*  dv-nvram.c -- Generic driver for a non volatile ram (battery saved)
2     Copyright (C) 1999, 2000, 2007, 2008, 2009, 2010
3     Free Software Foundation, Inc.
4     Written by Stephane Carrez (stcarrez@worldnet.fr)
5     (From a driver model Contributed by Cygnus Solutions.)
6     
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 3 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
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
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
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
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
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