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

Diff of /trunk/dev_bootflash.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

upstream/dynamips-0.2.7/dev_bootflash.c revision 10 by dpavlin, Sat Oct 6 16:29:14 2007 UTC upstream/dynamips-0.2.8-RC1/dev_bootflash.c revision 11 by dpavlin, Sat Oct 6 16:33:40 2007 UTC
# Line 2  Line 2 
2   * Cisco router simulation platform.   * Cisco router simulation platform.
3   * Copyright (c) 2006 Christophe Fillot.  All rights reserved.   * Copyright (c) 2006 Christophe Fillot.  All rights reserved.
4   *   *
5   * Intel Flash SIMM emulation (28F008SA/28F016SA)   * Intel Flash SIMM emulation.
6   *   *
7   * Intelligent ID Codes:   * Intelligent ID Codes:
8   *   28F008SA: 0x89A2 (1 Mb)   *   28F008SA: 0x89A2 (1 Mb)
# Line 11  Line 11 
11   * Manuals:   * Manuals:
12   *    http://www.ortodoxism.ro/datasheets/Intel/mXvsysv.pdf   *    http://www.ortodoxism.ro/datasheets/Intel/mXvsysv.pdf
13   *   *
14   * This code is working but is far from perfect. The four assembled circuits   * TODO: A lot of commands are lacking. Doesn't work with NPE-G2.
  * should be managed independently.  
  *  
  * Here, we emulate a group of four 28F016SA, for a total size of 8 Mb.  
  * If you need to change this, the Flash SIMM register must also be changed.  
  * (TODO: a CLI option + generic code).  
15   */   */
16    
17  #include <stdio.h>  #include <stdio.h>
# Line 34  Line 29 
29  #define DEBUG_ACCESS  0  #define DEBUG_ACCESS  0
30  #define DEBUG_WRITE   0  #define DEBUG_WRITE   0
31    
32  /* Bootflash private data */  /* Flash command states */
33  struct bootflash_data {  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;     vm_obj_t vm_obj;
90     struct vdevice dev;     struct vdevice dev;
    m_uint32_t cui_cmd,blk_cmd;  
    m_uint32_t status;  
91     char *filename;     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  #define BPTR(d,offset) (((char *)d->dev.host_addr) + offset)  /* 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()   * dev_bootflash_access()
# Line 52  void *dev_bootflash_access(cpu_gen_t *cp Line 410  void *dev_bootflash_access(cpu_gen_t *cp
410                             m_uint32_t offset,u_int op_size,u_int op_type,                             m_uint32_t offset,u_int op_size,u_int op_type,
411                             m_uint64_t *data)                             m_uint64_t *data)
412  {  {
413     struct bootflash_data *d = dev->priv_data;     struct flashset_data *d = dev->priv_data;
414       u_int flash_data[MAX_FLASH];
415       u_int i;
416    
417  #if DEBUG_ACCESS  #if DEBUG_ACCESS
418     if (op_type == MTS_READ)     if (op_type == MTS_READ)
419        cpu_log(cpu,dev->name,"read  access to offset = 0x%x, pc = 0x%llx "        cpu_log(cpu,dev->name,"read  access to offset = 0x%x, pc = 0x%llx\n",
420                "(stat=%u,cui_cmd=0x%x)\n",                offset,cpu_get_pc(cpu));
               offset,cpu_get_pc(cpu),d->status,d->cui_cmd);  
421     else     else
422        cpu_log(cpu,dev->name,"write access to vaddr = 0x%x, pc = 0x%llx, "        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);                "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);
# Line 67  void *dev_bootflash_access(cpu_gen_t *cp Line 426  void *dev_bootflash_access(cpu_gen_t *cp
426     if (op_type == MTS_READ) {     if (op_type == MTS_READ) {
427        *data = 0;        *data = 0;
428    
429        /* Read Array mode */        for(i=0;i<d->nr_flash_count;i++) {
430        if (d->status == 0)           flash_access(&d->flash[i],(offset >> d->nr_flash_bits),op_type,
431           return(BPTR(d,offset));                        &flash_data[i]);
432             *data |= flash_data[i] << (8 * (d->nr_flash_count - i - 1));
433        switch(d->cui_cmd) {        }
434           /* Intelligent identifier */     } else {
435           case 0x90909090:        for(i=0;i<d->nr_flash_count;i++) {
436              switch(offset) {           flash_data[i] = *data >> (8 * (d->nr_flash_count - i - 1));
437                 case 0x00:           flash_access(&d->flash[i],(offset >> d->nr_flash_bits),op_type,
438                    *data = 0x89898989;   /* manufacturer code */                        &flash_data[i]);
                   return NULL;  
                case 0x04:  
                   *data = 0xA0A0A0A0;   /* device code */  
                   return NULL;  
                default:  
                   cpu_log(cpu,dev->name,  
                           "Reading Intelligent ID Code at offset = 0x%x ?\n",  
                           offset);  
                   *data = 0x00000000;  
                   return NULL;  
             }  
             break;  
               
          /* Read Status Register */  
          case 0x70707070:  
             *data = 0x80808080;  
             return NULL;  
439        }        }
         
       /* Default: status register */  
       *data = 0x80808080;  
       return NULL;  
    }  
   
    /* write mode */  
    if (d->blk_cmd == 0x40404040) {  
 #if DEBUG_WRITE  
       cpu_log(cpu,dev->name,"Writing 0x%llx at offset=0x%x\n",*data,offset);  
 #endif  
       d->blk_cmd = 0;  
       d->cui_cmd = 0;  
       d->status = 1;  
       return(BPTR(d,offset));  
    }  
   
    switch(*data) {  
       /* Erase Setup */  
       case 0x20202020:  
          d->blk_cmd = *data;  
          break;  
           
       /* Erase Confirm */  
       case 0xd0d0d0d0:  
          if ((d->blk_cmd == 0x20202020) && !(offset & 0x3FFFF)) {  
             memset(BPTR(d,offset),0xFF,0x40000);  
             d->blk_cmd = 0;  
             d->cui_cmd = 0;  
             d->status = 1;  
          }  
          break;  
   
       /* Byte Write Setup (XXX ugly hack) */  
       case 0x40404040:  
       case 0x40ffffff:  
       case 0x4040ffff:  
       case 0x404040ff:  
       case 0xff404040:  
       case 0xffff4040:  
       case 0xffffff40:  
          d->blk_cmd = 0x40404040;  
          break;  
   
       /* Reset */  
       case 0xffffffff:  
          d->status = 0;  
          break;  
   
       /* Intelligent Identifier and Read Status register */  
       case 0x90909090:  
       case 0x70707070:  
          d->status = 1;  
          d->cui_cmd = *data;  
          break;  
   
       default:  
          cpu_log(cpu,dev->name,  
                  "default write case at offset=0x%7.7x, val=0x%llx\n",  
                  offset,*data);  
440     }     }
441      
442     return NULL;     return NULL;
443  }  }
444    
445  /* Shutdown a bootflash device */  /* Shutdown a bootflash device */
446  void dev_bootflash_shutdown(vm_instance_t *vm,struct bootflash_data *d)  void dev_bootflash_shutdown(vm_instance_t *vm,struct flashset_data *d)
447  {  {
448     if (d != NULL) {     if (d != NULL) {
449        /* Remove the device */        /* Remove the device */
# Line 177  void dev_bootflash_shutdown(vm_instance_ Line 459  void dev_bootflash_shutdown(vm_instance_
459  }  }
460    
461  /* Create a 8 Mb bootflash */  /* Create a 8 Mb bootflash */
462  int dev_bootflash_init(vm_instance_t *vm,char *name,  int dev_bootflash_init(vm_instance_t *vm,char *name,char *model,
463                         m_uint64_t paddr,m_uint32_t len)                         m_uint64_t paddr)
464  {    {  
465     struct bootflash_data *d;     struct flash_model *fm;
466       struct flashset_data *d;
467     u_char *ptr;     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 */     /* Allocate the private data structure */
476     if (!(d = malloc(sizeof(*d)))) {     if (!(d = malloc(sizeof(*d)))) {
477        fprintf(stderr,"Bootflash: unable to create device.\n");        vm_error(vm,"bootflash: unable to create device.\n");
478        return(-1);        return(-1);
479     }     }
480    
481     memset(d,0,sizeof(*d));     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);     vm_object_init(&d->vm_obj);
489     d->vm_obj.name = name;     d->vm_obj.name = name;
# Line 197  int dev_bootflash_init(vm_instance_t *vm Line 491  int dev_bootflash_init(vm_instance_t *vm
491     d->vm_obj.shutdown = (vm_shutdown_t)dev_bootflash_shutdown;     d->vm_obj.shutdown = (vm_shutdown_t)dev_bootflash_shutdown;
492    
493     if (!(d->filename = vm_build_filename(vm,name))) {     if (!(d->filename = vm_build_filename(vm,name))) {
494        fprintf(stderr,"Bootflash: unable to create filename.\n");        vm_error(vm,"bootflash: unable to create filename.\n");
495        goto err_filename;        goto err_filename;
496     }     }
497    
# Line 205  int dev_bootflash_init(vm_instance_t *vm Line 499  int dev_bootflash_init(vm_instance_t *vm
499     d->dev.name      = name;     d->dev.name      = name;
500     d->dev.priv_data = d;     d->dev.priv_data = d;
501     d->dev.phys_addr = paddr;     d->dev.phys_addr = paddr;
502     d->dev.phys_len  = len;     d->dev.phys_len  = fm->total_size;
503     d->dev.handler   = dev_bootflash_access;     d->dev.handler   = dev_bootflash_access;
504     d->dev.fd        = memzone_create_file(d->filename,d->dev.phys_len,&ptr);     d->dev.fd        = memzone_create_file(d->filename,d->dev.phys_len,&ptr);
505     d->dev.host_addr = (m_iptr_t)ptr;     d->dev.host_addr = (m_iptr_t)ptr;
506     d->dev.flags     = VDEVICE_FLAG_NO_MTS_MMAP;     d->dev.flags     = VDEVICE_FLAG_NO_MTS_MMAP;
507    
508     if (d->dev.fd == -1) {     if (d->dev.fd == -1) {
509        fprintf(stderr,"Bootflash: unable to map file '%s'\n",d->filename);        vm_error(vm,"bootflash: unable to map file '%s'\n",d->filename);
510        goto err_fd_create;        goto err_fd_create;
511     }     }
512    

Legend:
Removed from v.10  
changed lines
  Added in v.11

  ViewVC Help
Powered by ViewVC 1.1.26