/[dynamips]/trunk/dev_bootflash.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/dev_bootflash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 13464 byte(s)
make working copy

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2006 Christophe Fillot. All rights reserved.
4 *
5 * Intel Flash SIMM emulation.
6 *
7 * Intelligent ID Codes:
8 * 28F008SA: 0x89A2 (1 Mb)
9 * 28F016SA: 0x89A0 (2 Mb)
10 *
11 * Manuals:
12 * http://www.ortodoxism.ro/datasheets/Intel/mXvsysv.pdf
13 *
14 * TODO: A lot of commands are lacking. Doesn't work with NPE-G2.
15 */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 #include <errno.h>
22
23 #include "cpu.h"
24 #include "vm.h"
25 #include "dynamips.h"
26 #include "memory.h"
27 #include "device.h"
28
29 #define DEBUG_ACCESS 0
30 #define DEBUG_WRITE 0
31
32 /* Flash command states */
33 enum {
34 FLASH_CMD_READ_ARRAY = 0,
35 FLASH_CMD_READ_ID,
36 FLASH_CMD_READ_QUERY,
37 FLASH_CMD_READ_STATUS,
38 FLASH_CMD_WRITE_BUF_CNT,
39 FLASH_CMD_WRITE_BUF_DATA,
40 FLASH_CMD_WRITE_BUF_CONFIRM,
41 FLASH_CMD_WB_PROG,
42 FLASH_CMD_WB_PROG_DONE,
43 FLASH_CMD_BLK_ERASE,
44 FLASH_CMD_BLK_ERASE_DONE,
45 FLASH_CMD_CONFIG,
46 };
47
48 /* Flash access mode (byte or word) */
49 enum {
50 FLASH_MODE_BYTE,
51 FLASH_MODE_WORD,
52 };
53
54 #define MAX_FLASH 4
55 #define FLASH_BUF_SIZE 32
56
57 /* Forward declarations */
58 struct flash_data;
59 struct flashset_data;
60
61 /* Flash model */
62 struct flash_model {
63 char *name;
64 u_int total_size;
65 u_int mode;
66 u_int nr_flash_bits;
67 u_int blk_size;
68 u_int id_manufacturer;
69 u_int id_device;
70 };
71
72 /* Flash internal data */
73 struct flash_data {
74 u_int mode,offset_shift,state,blk_size;
75 m_uint8_t id_manufacturer,id_device;
76 m_uint8_t status_reg;
77
78 struct flashset_data *flash_set;
79 u_int flash_pos;
80
81 /* Write buffer */
82 u_int wb_offset,wb_count,wb_remain;
83 u_int wbuf[FLASH_BUF_SIZE];
84 };
85
86 /* Flashset private data */
87 struct flashset_data {
88 vm_instance_t *vm;
89 vm_obj_t vm_obj;
90 struct vdevice dev;
91 char *filename;
92
93 u_int nr_flash_bits;
94 u_int nr_flash_count;
95 struct flash_data flash[MAX_FLASH];
96 };
97
98 /* Log a Flash message */
99 #define FLASH_LOG(d,msg...) vm_log((d)->flash_set->vm, \
100 (d)->flash_set->dev.name, \
101 msg)
102
103 #define BPTR(d,offset) (((u_char *)(d)->dev.host_addr) + offset)
104
105 /* Some Flash models */
106 static struct flash_model flash_models[] = {
107 /* C1700 4 Mb bootflash: 1x28F320 in word mode */
108 { "c1700-bootflash-4mb",4 * 1048576,FLASH_MODE_WORD,0,0x10000,0x89,0x14 },
109
110 /* C1700 8 Mb bootflash: 1x28F640 in word mode */
111 { "c1700-bootflash-8mb",8 * 1048576,FLASH_MODE_WORD,0,0x10000,0x89,0x15 },
112
113 /* C3600 8 Mb bootflash: 4x28F016SA in byte mode */
114 { "c3600-bootflash-8mb",8 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA0 },
115
116 /* C7200 4 Mb bootflash: 4x28F008SA in byte mode */
117 { "c7200-bootflash-4mb",4 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA2 },
118
119 /* C7200 8 Mb bootflash: 4x28F016SA in byte mode */
120 { "c7200-bootflash-8mb",8 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA0 },
121
122 /*
123 * C7200 64 Mb bootflash: 4x128 Mb Intel flash in byte mode
124 * (for NPE-G2 but doesn't work now).
125 */
126 { "c7200-bootflash-64mb",64 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0x18 },
127
128 /* C2600 8 Mb bootflash: 4x28F016SA in byte mode */
129 { "c2600-bootflash-8mb",8 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA0 },
130
131 { NULL, 0, 0, 0, 0, 0 },
132 };
133
134 /* Flash model lookup */
135 static struct flash_model *flash_model_find(char *name)
136 {
137 struct flash_model *fm;
138
139 for(fm=&flash_models[0];fm->name!=NULL;fm++)
140 if (!strcmp(fm->name,name))
141 return fm;
142
143 return NULL;
144 }
145
146 /* Initialize a flashset */
147 static int flashset_init(struct flashset_data *d,
148 u_int mode,u_int nr_flash_bits,u_int blk_size,
149 m_uint8_t id_manufacturer,m_uint8_t id_device)
150 {
151 struct flash_data *flash;
152 u_int i,offset_shift;
153
154 d->nr_flash_bits = nr_flash_bits;
155 d->nr_flash_count = 1 << d->nr_flash_bits;
156
157 switch(mode) {
158 case FLASH_MODE_BYTE:
159 offset_shift = 0;
160 break;
161 case FLASH_MODE_WORD:
162 offset_shift = 1;
163 break;
164 default:
165 return(-1);
166 }
167
168 for(i=0;i<d->nr_flash_count;i++) {
169 flash = &d->flash[i];
170
171 flash->mode = mode;
172 flash->offset_shift = offset_shift;
173 flash->state = FLASH_CMD_READ_ARRAY;
174
175 flash->id_manufacturer = id_manufacturer;
176 flash->id_device = id_device;
177
178 flash->flash_set = d;
179 flash->flash_pos = i;
180
181 flash->blk_size = blk_size;
182 }
183
184 return(0);
185 }
186
187 /* Read a byte from a Flash */
188 static int flash_read(struct flash_data *d,u_int offset,u_int *data)
189 {
190 u_int real_offset;
191
192 real_offset = (offset << (d->flash_set->nr_flash_bits)) + d->flash_pos;
193
194 if (d->mode == FLASH_MODE_BYTE) {
195 *data = *BPTR(d->flash_set,real_offset);
196 } else {
197 *data = *BPTR(d->flash_set,(real_offset << 1)) << 8;
198 *data |= *BPTR(d->flash_set,(real_offset << 1)+1);
199 }
200 return(0);
201 }
202
203 /* Write a byte to a Flash */
204 static int flash_write(struct flash_data *d,u_int offset,u_int data)
205 {
206 u_int real_offset;
207
208 real_offset = (offset << (d->flash_set->nr_flash_bits)) + d->flash_pos;
209
210 if (d->mode == FLASH_MODE_BYTE) {
211 *BPTR(d->flash_set,real_offset) = data;
212 } else {
213 *BPTR(d->flash_set,(real_offset << 1)) = data >> 8;
214 *BPTR(d->flash_set,(real_offset << 1)+1) = data & 0xFF;
215 }
216 return(0);
217 }
218
219 /* Set machine state given a command */
220 static void flash_cmd(struct flash_data *d,u_int offset,u_int cmd)
221 {
222 cmd = cmd & 0xFF;
223
224 switch(cmd) {
225 case 0x40:
226 case 0x10:
227 d->state = FLASH_CMD_WB_PROG;
228 break;
229 case 0xe8:
230 d->state = FLASH_CMD_WRITE_BUF_CNT;
231 d->wb_offset = offset;
232 d->wb_count = d->wb_remain = 0;
233 break;
234 case 0x70:
235 d->state = FLASH_CMD_READ_STATUS;
236 break;
237 case 0x50:
238 d->status_reg = 0;
239 d->state = FLASH_CMD_READ_ARRAY;
240 break;
241 case 0x90:
242 d->state = FLASH_CMD_READ_ID;
243 break;
244 case 0x20:
245 d->state = FLASH_CMD_BLK_ERASE;
246 break;
247 case 0xff:
248 d->state = FLASH_CMD_READ_ARRAY;
249 break;
250 default:
251 FLASH_LOG(d,"flash_cmd(%u): command 0x%2.2x not implemented\n",
252 d->flash_pos,(u_int)cmd);
253 }
254 }
255
256 /* Generic Flash access */
257 static void flash_access(struct flash_data *d,m_uint32_t offset,u_int op_type,
258 u_int *data)
259 {
260 u_int i;
261
262 if (op_type == MTS_READ)
263 *data = 0x00;
264
265 #if DEBUG_ACCESS
266 if (op_type == MTS_READ) {
267 FLASH_LOG(d,"flash_access(%u): read access to offset 0x%8.8x "
268 "(state=%u)\n",d->flash_pos,offset,d->state);
269 } else {
270 FLASH_LOG(d,"flash_access(%u): write access to offset 0x%8.8x, "
271 "data=0x%4.4x (state=%u)\n",
272 d->flash_pos,offset,*data,d->state);
273 }
274 #endif
275
276 offset >>= d->offset_shift;
277
278 /* State machine for Flash commands */
279 switch(d->state) {
280 case FLASH_CMD_READ_ARRAY:
281 if (op_type == MTS_READ) {
282 flash_read(d,offset,data);
283 return;
284 }
285
286 /* Command Write */
287 flash_cmd(d,offset,*data);
288 break;
289
290 /* Write byte/word */
291 case FLASH_CMD_WB_PROG:
292 if (op_type == MTS_WRITE) {
293 flash_write(d,offset,*data);
294 d->state = FLASH_CMD_WB_PROG_DONE;
295 }
296 break;
297
298 /* Write byte/word (done) */
299 case FLASH_CMD_WB_PROG_DONE:
300 if (op_type == MTS_WRITE) {
301 flash_cmd(d,offset,*data);
302 } else {
303 *data = 0x80;
304 }
305 break;
306
307 /* Write buffer (count) */
308 case FLASH_CMD_WRITE_BUF_CNT:
309 if (op_type == MTS_WRITE) {
310 d->wb_count = d->wb_remain = (*data & 0x1F) + 1;
311 d->state = FLASH_CMD_WRITE_BUF_DATA;
312 } else {
313 *data = 0x80;
314 }
315 break;
316
317 /* Write buffer (data) */
318 case FLASH_CMD_WRITE_BUF_DATA:
319 if (op_type == MTS_WRITE) {
320 if ((offset >= d->wb_offset) &&
321 (offset < (d->wb_offset + d->wb_count)))
322 {
323 d->wbuf[offset - d->wb_offset] = *data;
324 d->wb_remain--;
325
326 if (!d->wb_remain)
327 d->state = FLASH_CMD_WRITE_BUF_CONFIRM;
328 }
329 } else {
330 *data = 0x80;
331 }
332 break;
333
334 /* Write buffer (confirm) */
335 case FLASH_CMD_WRITE_BUF_CONFIRM:
336 if (op_type == MTS_WRITE) {
337 if ((*data & 0xFF) == 0xD0) {
338 for(i=0;i<d->wb_count;i++)
339 flash_write(d,d->wb_offset+i,d->wbuf[i]);
340 } else {
341 /* XXX Error */
342 }
343
344 d->state = FLASH_CMD_READ_ARRAY;
345 } else {
346 *data = 0x80;
347 }
348 break;
349
350 /* Read status register */
351 case FLASH_CMD_READ_STATUS:
352 if (op_type == MTS_READ)
353 *data = 0x80; //d->status_reg;
354
355 d->state = FLASH_CMD_READ_ARRAY;
356 break;
357
358 /* Read identifier codes */
359 case FLASH_CMD_READ_ID:
360 if (op_type == MTS_READ) {
361 switch(offset) {
362 case 0x00:
363 *data = d->id_manufacturer;
364 break;
365 case 0x01:
366 *data = d->id_device;
367 break;
368 default:
369 *data = 0x00;
370 break;
371 }
372 } else {
373 flash_cmd(d,offset,*data);
374 }
375 break;
376
377 /* Block Erase */
378 case FLASH_CMD_BLK_ERASE:
379 if (op_type == MTS_WRITE) {
380 #if DEBUG_WRITE
381 FLASH_LOG(d,"flash_access(%u): erasing block at offset 0x%8.8x\n"
382 offset);
383 #endif
384 if ((*data & 0xFF) == 0xD0) {
385 for(i=0;i<d->blk_size;i++)
386 flash_write(d,offset+i,0xFFFF);
387
388 d->state = FLASH_CMD_BLK_ERASE_DONE;
389 }
390 } else {
391 *data = 0x80;
392 }
393 break;
394
395 /* Block Erase Done */
396 case FLASH_CMD_BLK_ERASE_DONE:
397 if (op_type == MTS_WRITE) {
398 flash_cmd(d,offset,*data);
399 } else {
400 *data = 0x80;
401 }
402 break;
403 }
404 }
405
406 /*
407 * dev_bootflash_access()
408 */
409 void *dev_bootflash_access(cpu_gen_t *cpu,struct vdevice *dev,
410 m_uint32_t offset,u_int op_size,u_int op_type,
411 m_uint64_t *data)
412 {
413 struct flashset_data *d = dev->priv_data;
414 u_int flash_data[MAX_FLASH];
415 u_int i;
416
417 #if DEBUG_ACCESS
418 if (op_type == MTS_READ)
419 cpu_log(cpu,dev->name,"read access to offset = 0x%x, pc = 0x%llx\n",
420 offset,cpu_get_pc(cpu));
421 else
422 cpu_log(cpu,dev->name,"write access to vaddr = 0x%x, pc = 0x%llx, "
423 "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
424 #endif
425
426 if (op_type == MTS_READ) {
427 *data = 0;
428
429 for(i=0;i<d->nr_flash_count;i++) {
430 flash_access(&d->flash[i],(offset >> d->nr_flash_bits),op_type,
431 &flash_data[i]);
432 *data |= flash_data[i] << (8 * (d->nr_flash_count - i - 1));
433 }
434 } else {
435 for(i=0;i<d->nr_flash_count;i++) {
436 flash_data[i] = *data >> (8 * (d->nr_flash_count - i - 1));
437 flash_access(&d->flash[i],(offset >> d->nr_flash_bits),op_type,
438 &flash_data[i]);
439 }
440 }
441
442 return NULL;
443 }
444
445 /* Shutdown a bootflash device */
446 void dev_bootflash_shutdown(vm_instance_t *vm,struct flashset_data *d)
447 {
448 if (d != NULL) {
449 /* Remove the device */
450 dev_remove(vm,&d->dev);
451
452 /* We don't remove the file, since it used as permanent storage */
453 if (d->filename)
454 free(d->filename);
455
456 /* Free the structure itself */
457 free(d);
458 }
459 }
460
461 /* Create a 8 Mb bootflash */
462 int dev_bootflash_init(vm_instance_t *vm,char *name,char *model,
463 m_uint64_t paddr)
464 {
465 struct flash_model *fm;
466 struct flashset_data *d;
467 u_char *ptr;
468
469 /* Find the flash model */
470 if (!(fm = flash_model_find(model))) {
471 vm_error(vm,"bootflash: unable to find model '%s'\n",model);
472 return(-1);
473 }
474
475 /* Allocate the private data structure */
476 if (!(d = malloc(sizeof(*d)))) {
477 vm_error(vm,"bootflash: unable to create device.\n");
478 return(-1);
479 }
480
481 memset(d,0,sizeof(*d));
482 d->vm = vm;
483
484 /* Initialize flash based on model properties */
485 flashset_init(d,fm->mode,fm->nr_flash_bits,fm->blk_size,
486 fm->id_manufacturer,fm->id_device);
487
488 vm_object_init(&d->vm_obj);
489 d->vm_obj.name = name;
490 d->vm_obj.data = d;
491 d->vm_obj.shutdown = (vm_shutdown_t)dev_bootflash_shutdown;
492
493 if (!(d->filename = vm_build_filename(vm,name))) {
494 vm_error(vm,"bootflash: unable to create filename.\n");
495 goto err_filename;
496 }
497
498 dev_init(&d->dev);
499 d->dev.name = name;
500 d->dev.priv_data = d;
501 d->dev.phys_addr = paddr;
502 d->dev.phys_len = fm->total_size;
503 d->dev.handler = dev_bootflash_access;
504 d->dev.fd = memzone_create_file(d->filename,d->dev.phys_len,&ptr);
505 d->dev.host_addr = (m_iptr_t)ptr;
506 d->dev.flags = VDEVICE_FLAG_NO_MTS_MMAP;
507
508 if (d->dev.fd == -1) {
509 vm_error(vm,"bootflash: unable to map file '%s'\n",d->filename);
510 goto err_fd_create;
511 }
512
513 /* Map this device to the VM */
514 vm_bind_device(vm,&d->dev);
515 vm_object_add(vm,&d->vm_obj);
516 return(0);
517
518 err_fd_create:
519 free(d->filename);
520 err_filename:
521 free(d);
522 return(-1);
523 }

  ViewVC Help
Powered by ViewVC 1.1.26