88fab2f4461280cd06fca3df9f7e57e02cc45f44
[deliverable/binutils-gdb.git] / sim / m68hc11 / dv-nvram.c
1 /* dv-nvram.c -- Generic driver for a non volatile ram (battery saved)
2 Copyright (C) 1999-2021 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 unsigned8 *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
This page took 0.039214 seconds and 3 git commands to generate.