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