📄 dev_bootflash.c
字号:
/* * Cisco router simulation platform. * Copyright (c) 2006 Christophe Fillot. All rights reserved. * * Intel Flash SIMM emulation. * * Intelligent ID Codes: * 28F008SA: 0x89A2 (1 Mb) * 28F016SA: 0x89A0 (2 Mb) * * Manuals: * http://www.ortodoxism.ro/datasheets/Intel/mXvsysv.pdf * * TODO: A lot of commands are lacking. Doesn't work with NPE-G2. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <errno.h>#include "cpu.h"#include "vm.h"#include "dynamips.h"#include "memory.h"#include "device.h"#define DEBUG_ACCESS 0#define DEBUG_WRITE 0/* Flash command states */enum { FLASH_CMD_READ_ARRAY = 0, FLASH_CMD_READ_ID, FLASH_CMD_READ_QUERY, FLASH_CMD_READ_STATUS, FLASH_CMD_WRITE_BUF_CNT, FLASH_CMD_WRITE_BUF_DATA, FLASH_CMD_WRITE_BUF_CONFIRM, FLASH_CMD_WB_PROG, FLASH_CMD_WB_PROG_DONE, FLASH_CMD_BLK_ERASE, FLASH_CMD_BLK_ERASE_DONE, FLASH_CMD_CONFIG,};/* Flash access mode (byte or word) */enum { FLASH_MODE_BYTE = 1, FLASH_MODE_WORD = 2,};#define MAX_FLASH 4#define FLASH_BUF_SIZE 32/* Forward declarations */struct flash_data;struct flashset_data;/* Flash model */struct flash_model { char *name; u_int total_size; u_int mode; u_int nr_flash_bits; u_int blk_size; u_int id_manufacturer; u_int id_device;};/* Flash internal data */struct flash_data { u_int mode,offset_shift,state,blk_size; m_uint8_t id_manufacturer,id_device; m_uint8_t status_reg; struct flashset_data *flash_set; u_int flash_pos; /* Write buffer */ u_int wb_offset,wb_count,wb_remain; u_int wbuf[FLASH_BUF_SIZE];};/* Flashset private data */struct flashset_data { vm_instance_t *vm; vm_obj_t vm_obj; struct vdevice dev; char *filename; u_int mode; u_int nr_flash_bits; u_int nr_flash_count; struct flash_data flash[MAX_FLASH];};/* Log a Flash message */#define FLASH_LOG(d,msg...) vm_log((d)->flash_set->vm, \ (d)->flash_set->dev.name, \ msg)#define BPTR(d,offset) (((u_char *)(d)->dev.host_addr) + offset)/* Some Flash models */static struct flash_model flash_models[] = { /* C1700 4 Mb bootflash: 1x28F320 in word mode */ { "c1700-bootflash-4mb",4 * 1048576,FLASH_MODE_WORD,0,0x10000,0x89,0x14 }, /* C1700 8 Mb bootflash: 1x28F640 in word mode */ { "c1700-bootflash-8mb",8 * 1048576,FLASH_MODE_WORD,0,0x10000,0x89,0x15 }, /* C3600 8 Mb bootflash: 4x28F016SA in byte mode */ { "c3600-bootflash-8mb",8 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA0 }, /* C7200 4 Mb bootflash: 4x28F008SA in byte mode */ { "c7200-bootflash-4mb",4 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA2 }, /* C7200 8 Mb bootflash: 4x28F016SA in byte mode */ { "c7200-bootflash-8mb",8 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA0 }, /* * C7200 64 Mb bootflash: 4x128 Mb Intel flash in byte mode * (for NPE-G2 but doesn't work now). */ { "c7200-bootflash-64mb",64 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0x18 }, /* C2600 8 Mb bootflash: 4x28F016SA in byte mode */ { "c2600-bootflash-8mb",8 * 1048576,FLASH_MODE_BYTE,2,0x10000,0x89,0xA0 }, { NULL, 0, 0, 0, 0, 0 },};/* Flash model lookup */static struct flash_model *flash_model_find(char *name){ struct flash_model *fm; for(fm=&flash_models[0];fm->name!=NULL;fm++) if (!strcmp(fm->name,name)) return fm; return NULL;}/* Initialize a flashset */static int flashset_init(struct flashset_data *d, u_int mode,u_int nr_flash_bits,u_int blk_size, m_uint8_t id_manufacturer,m_uint8_t id_device){ struct flash_data *flash; u_int i,offset_shift; d->mode = mode; d->nr_flash_bits = nr_flash_bits; d->nr_flash_count = 1 << d->nr_flash_bits; switch(mode) { case FLASH_MODE_BYTE: offset_shift = 0; break; case FLASH_MODE_WORD: offset_shift = 1; break; default: return(-1); } for(i=0;i<d->nr_flash_count;i++) { flash = &d->flash[i]; flash->mode = mode; flash->offset_shift = offset_shift; flash->state = FLASH_CMD_READ_ARRAY; flash->id_manufacturer = id_manufacturer; flash->id_device = id_device; flash->flash_set = d; flash->flash_pos = i; flash->blk_size = blk_size; } return(0);}/* Read a byte from a Flash */static int flash_read(struct flash_data *d,u_int offset,u_int *data){ u_int real_offset; real_offset = (offset << (d->flash_set->nr_flash_bits)) + d->flash_pos; if (d->mode == FLASH_MODE_BYTE) { *data = *BPTR(d->flash_set,real_offset); } else { *data = *BPTR(d->flash_set,(real_offset << 1)) << 8; *data |= *BPTR(d->flash_set,(real_offset << 1)+1); } return(0);}/* Write a byte to a Flash */static int flash_write(struct flash_data *d,u_int offset,u_int data){ u_int real_offset; real_offset = (offset << (d->flash_set->nr_flash_bits)) + d->flash_pos; if (d->mode == FLASH_MODE_BYTE) { *BPTR(d->flash_set,real_offset) = data; } else { *BPTR(d->flash_set,(real_offset << 1)) = data >> 8; *BPTR(d->flash_set,(real_offset << 1)+1) = data & 0xFF; } return(0);}/* Set machine state given a command */static void flash_cmd(struct flash_data *d,u_int offset,u_int cmd){ cmd = cmd & 0xFF; switch(cmd) { case 0x40: case 0x10: d->state = FLASH_CMD_WB_PROG; break; case 0xe8: d->state = FLASH_CMD_WRITE_BUF_CNT; d->wb_offset = offset; d->wb_count = d->wb_remain = 0; break; case 0x70: d->state = FLASH_CMD_READ_STATUS; break; case 0x50: d->status_reg = 0; d->state = FLASH_CMD_READ_ARRAY; break; case 0x90: d->state = FLASH_CMD_READ_ID; break; case 0x20: d->state = FLASH_CMD_BLK_ERASE; break; case 0xff: d->state = FLASH_CMD_READ_ARRAY; break; default: FLASH_LOG(d,"flash_cmd(%u): command 0x%2.2x not implemented\n", d->flash_pos,(u_int)cmd); }}/* Generic Flash access */static void flash_access(struct flash_data *d,m_uint32_t offset,u_int op_type, u_int *data){ u_int i; if (op_type == MTS_READ) *data = 0x00;#if DEBUG_ACCESS if (op_type == MTS_READ) { FLASH_LOG(d,"flash_access(%u): read access to offset 0x%8.8x " "(state=%u)\n",d->flash_pos,offset,d->state); } else { FLASH_LOG(d,"flash_access(%u): write access to offset 0x%8.8x, " "data=0x%4.4x (state=%u)\n", d->flash_pos,offset,*data,d->state); }#endif offset >>= d->offset_shift; /* State machine for Flash commands */ switch(d->state) { case FLASH_CMD_READ_ARRAY: if (op_type == MTS_READ) { flash_read(d,offset,data); return; } /* Command Write */ flash_cmd(d,offset,*data); break; /* Write byte/word */ case FLASH_CMD_WB_PROG: if (op_type == MTS_WRITE) { flash_write(d,offset,*data); d->state = FLASH_CMD_WB_PROG_DONE; } break; /* Write byte/word (done) */ case FLASH_CMD_WB_PROG_DONE: if (op_type == MTS_WRITE) { flash_cmd(d,offset,*data); } else { *data = 0x80; } break; /* Write buffer (count) */ case FLASH_CMD_WRITE_BUF_CNT: if (op_type == MTS_WRITE) { d->wb_count = d->wb_remain = (*data & 0x1F) + 1; d->state = FLASH_CMD_WRITE_BUF_DATA; } else { *data = 0x80; } break; /* Write buffer (data) */ case FLASH_CMD_WRITE_BUF_DATA: if (op_type == MTS_WRITE) { if ((offset >= d->wb_offset) && (offset < (d->wb_offset + d->wb_count))) { d->wbuf[offset - d->wb_offset] = *data; d->wb_remain--; if (!d->wb_remain) d->state = FLASH_CMD_WRITE_BUF_CONFIRM; } } else { *data = 0x80; } break; /* Write buffer (confirm) */ case FLASH_CMD_WRITE_BUF_CONFIRM: if (op_type == MTS_WRITE) { if ((*data & 0xFF) == 0xD0) { for(i=0;i<d->wb_count;i++) flash_write(d,d->wb_offset+i,d->wbuf[i]); } else { /* XXX Error */ } d->state = FLASH_CMD_READ_ARRAY; } else { *data = 0x80; } break; /* Read status register */ case FLASH_CMD_READ_STATUS: if (op_type == MTS_READ) *data = 0x80; //d->status_reg; d->state = FLASH_CMD_READ_ARRAY; break; /* Read identifier codes */ case FLASH_CMD_READ_ID: if (op_type == MTS_READ) { switch(offset) { case 0x00: *data = d->id_manufacturer; break; case 0x01: *data = d->id_device; break; default: *data = 0x00; break; } } else { flash_cmd(d,offset,*data); } break; /* Block Erase */ case FLASH_CMD_BLK_ERASE: if (op_type == MTS_WRITE) {#if DEBUG_WRITE FLASH_LOG(d,"flash_access(%u): erasing block at offset 0x%8.8x\n" offset);#endif if ((*data & 0xFF) == 0xD0) { for(i=0;i<d->blk_size;i++) flash_write(d,offset+i,0xFFFF); d->state = FLASH_CMD_BLK_ERASE_DONE; } } else { *data = 0x80; } break; /* Block Erase Done */ case FLASH_CMD_BLK_ERASE_DONE: if (op_type == MTS_WRITE) { flash_cmd(d,offset,*data); } else { *data = 0x80; } break; }}/* * dev_bootflash_access() */void *dev_bootflash_access(cpu_gen_t *cpu,struct vdevice *dev, m_uint32_t offset,u_int op_size,u_int op_type, m_uint64_t *data){ struct flashset_data *d = dev->priv_data; u_int flash_data[8]; u_int i,fi,d_off;#if DEBUG_ACCESS if (op_type == MTS_READ) cpu_log(cpu,dev->name,"read access to offset = 0x%x, pc = 0x%llx\n", offset,cpu_get_pc(cpu)); else cpu_log(cpu,dev->name,"write access to vaddr = 0x%x, pc = 0x%llx, " "val = 0x%llx\n",offset,cpu_get_pc(cpu),*data);#endif if (op_type == MTS_READ) { *data = 0; for(i=0;i<op_size;i+=d->mode) { fi = (offset+i) & (d->nr_flash_count-1); flash_access(&d->flash[fi],((offset+i) >> d->nr_flash_bits),op_type, &flash_data[i]); d_off = (op_size - i - d->mode) << 3; *data |= (m_uint64_t)flash_data[i] << d_off; } } else { for(i=0;i<op_size;i+=d->mode) { fi = (offset+i) & (d->nr_flash_count-1); d_off = (op_size - i - d->mode) << 3; flash_data[i] = *data >> d_off; flash_access(&d->flash[fi],((offset+i) >> d->nr_flash_bits),op_type, &flash_data[i]); } } return NULL;}/* Shutdown a bootflash device */void dev_bootflash_shutdown(vm_instance_t *vm,struct flashset_data *d){ if (d != NULL) { /* Remove the device */ dev_remove(vm,&d->dev); /* We don't remove the file, since it used as permanent storage */ if (d->filename) free(d->filename); /* Free the structure itself */ free(d); }}/* Create a 8 Mb bootflash */int dev_bootflash_init(vm_instance_t *vm,char *name,char *model, m_uint64_t paddr){ struct flash_model *fm; struct flashset_data *d; u_char *ptr; /* Find the flash model */ if (!(fm = flash_model_find(model))) { vm_error(vm,"bootflash: unable to find model '%s'\n",model); return(-1); } /* Allocate the private data structure */ if (!(d = malloc(sizeof(*d)))) { vm_error(vm,"bootflash: unable to create device.\n"); return(-1); } memset(d,0,sizeof(*d)); d->vm = vm; /* Initialize flash based on model properties */ flashset_init(d,fm->mode,fm->nr_flash_bits,fm->blk_size, fm->id_manufacturer,fm->id_device); vm_object_init(&d->vm_obj); d->vm_obj.name = name; d->vm_obj.data = d; d->vm_obj.shutdown = (vm_shutdown_t)dev_bootflash_shutdown; if (!(d->filename = vm_build_filename(vm,name))) { vm_error(vm,"bootflash: unable to create filename.\n"); goto err_filename; } dev_init(&d->dev); d->dev.name = name; d->dev.priv_data = d; d->dev.phys_addr = paddr; d->dev.phys_len = fm->total_size; d->dev.handler = dev_bootflash_access; d->dev.fd = memzone_create_file(d->filename,d->dev.phys_len,&ptr); d->dev.host_addr = (m_iptr_t)ptr; d->dev.flags = VDEVICE_FLAG_NO_MTS_MMAP; if (d->dev.fd == -1) { vm_error(vm,"bootflash: unable to map file '%s'\n",d->filename); goto err_fd_create; } /* Map this device to the VM */ vm_bind_device(vm,&d->dev); vm_object_add(vm,&d->vm_obj); return(0); err_fd_create: free(d->filename); err_filename: free(d); return(-1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -