/[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

Annotation of /trunk/dev_bootflash.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide 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 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * Copyright (c) 2006 Christophe Fillot. All rights reserved.
4     *
5 dpavlin 11 * Intel Flash SIMM emulation.
6 dpavlin 1 *
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 dpavlin 11 * TODO: A lot of commands are lacking. Doesn't work with NPE-G2.
15 dpavlin 1 */
16    
17     #include <stdio.h>
18     #include <stdlib.h>
19     #include <string.h>
20     #include <time.h>
21     #include <errno.h>
22    
23 dpavlin 7 #include "cpu.h"
24     #include "vm.h"
25 dpavlin 1 #include "dynamips.h"
26     #include "memory.h"
27     #include "device.h"
28    
29     #define DEBUG_ACCESS 0
30     #define DEBUG_WRITE 0
31    
32 dpavlin 11 /* 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 dpavlin 1 vm_obj_t vm_obj;
90     struct vdevice dev;
91     char *filename;
92 dpavlin 11
93     u_int nr_flash_bits;
94     u_int nr_flash_count;
95     struct flash_data flash[MAX_FLASH];
96 dpavlin 1 };
97    
98 dpavlin 11 /* 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 dpavlin 1
103 dpavlin 11 #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 dpavlin 1 {
137 dpavlin 11 struct flash_model *fm;
138 dpavlin 1
139 dpavlin 11 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 dpavlin 1 if (op_type == MTS_READ)
263 dpavlin 11 *data = 0x00;
264 dpavlin 1
265 dpavlin 11 #if DEBUG_ACCESS
266 dpavlin 1 if (op_type == MTS_READ) {
267 dpavlin 11 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 dpavlin 7
276 dpavlin 11 offset >>= d->offset_shift;
277 dpavlin 1
278 dpavlin 11 /* 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 dpavlin 1 switch(offset) {
362     case 0x00:
363 dpavlin 11 *data = d->id_manufacturer;
364     break;
365     case 0x01:
366     *data = d->id_device;
367     break;
368 dpavlin 1 default:
369 dpavlin 11 *data = 0x00;
370     break;
371 dpavlin 1 }
372 dpavlin 11 } else {
373     flash_cmd(d,offset,*data);
374     }
375     break;
376 dpavlin 1
377 dpavlin 11 /* Block Erase */
378     case FLASH_CMD_BLK_ERASE:
379     if (op_type == MTS_WRITE) {
380 dpavlin 1 #if DEBUG_WRITE
381 dpavlin 11 FLASH_LOG(d,"flash_access(%u): erasing block at offset 0x%8.8x\n"
382     offset);
383 dpavlin 1 #endif
384 dpavlin 11 if ((*data & 0xFF) == 0xD0) {
385     for(i=0;i<d->blk_size;i++)
386     flash_write(d,offset+i,0xFFFF);
387 dpavlin 1
388 dpavlin 11 d->state = FLASH_CMD_BLK_ERASE_DONE;
389     }
390     } else {
391     *data = 0x80;
392 dpavlin 1 }
393     break;
394    
395 dpavlin 11 /* 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 dpavlin 1 break;
403 dpavlin 11 }
404     }
405 dpavlin 1
406 dpavlin 11 /*
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 dpavlin 1
417 dpavlin 11 #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 dpavlin 1
426 dpavlin 11 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 dpavlin 1 }
441 dpavlin 11
442 dpavlin 1 return NULL;
443     }
444    
445     /* Shutdown a bootflash device */
446 dpavlin 11 void dev_bootflash_shutdown(vm_instance_t *vm,struct flashset_data *d)
447 dpavlin 1 {
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 dpavlin 11 int dev_bootflash_init(vm_instance_t *vm,char *name,char *model,
463     m_uint64_t paddr)
464 dpavlin 1 {
465 dpavlin 11 struct flash_model *fm;
466     struct flashset_data *d;
467 dpavlin 1 u_char *ptr;
468    
469 dpavlin 11 /* 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 dpavlin 1 /* Allocate the private data structure */
476     if (!(d = malloc(sizeof(*d)))) {
477 dpavlin 11 vm_error(vm,"bootflash: unable to create device.\n");
478 dpavlin 1 return(-1);
479     }
480    
481     memset(d,0,sizeof(*d));
482 dpavlin 11 d->vm = vm;
483 dpavlin 1
484 dpavlin 11 /* 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 dpavlin 1 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 dpavlin 11 vm_error(vm,"bootflash: unable to create filename.\n");
495 dpavlin 1 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 dpavlin 11 d->dev.phys_len = fm->total_size;
503 dpavlin 1 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 dpavlin 11 vm_error(vm,"bootflash: unable to map file '%s'\n",d->filename);
510 dpavlin 1 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