📄 dev_c2600.c
字号:
/* * Cisco router simulation platform. * Copyright (c) 2006 Christophe Fillot (cf@utc.fr) * * Generic Cisco 2600 routines and definitions (EEPROM,...). */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <assert.h>#include "cpu.h"#include "vm.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "ppc32_mem.h"#include "pci_io.h"#include "cisco_eeprom.h"#include "dev_mpc860.h"#include "dev_rom.h"#include "dev_c2600.h"#include "dev_c2600_iofpga.h"#include "dev_vtty.h"#include "registry.h"/* ======================================================================== *//* EEPROM definitions *//* ======================================================================== *//* Cisco 2600 mainboard EEPROM */static m_uint16_t eeprom_c2600_mb_data[] = { 0x0101, 0x0404, 0x0000, 0x0000, 0x4320, 0x00FF, 0x0091, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x3030, 0x3000, 0x0030, 0x3030, 0x3002, 0x0200, 0x0000, 0x0000, 0x00FF, 0xFFFF, 0x5006, 0x490B, 0x1709, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,};struct c2600_mb_id { char *name; char *mb_driver; m_uint16_t id; int xm_model; int supported;};struct c2600_mb_id c2600_mainboard_id[] = { { "2610" , "CISCO2600-MB-1E" , 0x0091, FALSE, TRUE }, { "2611" , "CISCO2600-MB-2E" , 0x0092, FALSE, TRUE }, { "2620" , "CISCO2600-MB-1FE" , 0x0094, FALSE, TRUE }, { "2621" , "CISCO2600-MB-2FE" , 0x00a2, FALSE, TRUE }, { "2610XM" , "CISCO2600-MB-1FE" , 0x036a, TRUE, TRUE }, { "2611XM" , "CISCO2600-MB-2FE" , 0x036b, TRUE, FALSE }, { "2620XM" , "CISCO2600-MB-1FE" , 0x036c, TRUE, TRUE }, { "2621XM" , "CISCO2600-MB-2FE" , 0x036d, TRUE, FALSE }, { "2650XM" , "CISCO2600-MB-1FE" , 0x036e, TRUE, TRUE }, { "2651XM" , "CISCO2600-MB-2FE" , 0x036f, TRUE, FALSE }, { NULL , NULL , 0x0000, FALSE, FALSE },};/* ======================================================================== *//* Network Module Drivers *//* ======================================================================== */static struct cisco_card_driver *nm_drivers[] = { &dev_c2600_mb1e_eth_driver, &dev_c2600_mb2e_eth_driver, &dev_c2600_mb1fe_eth_driver, &dev_c2600_mb2fe_eth_driver, &dev_c2600_nm_1e_driver, &dev_c2600_nm_4e_driver, &dev_c2600_nm_1fe_tx_driver, &dev_c2600_nm_16esw_driver, &dev_c2600_nm_nam_driver, &dev_c2600_nm_cids_driver, NULL,};/* ======================================================================== *//* Cisco 2600 router instances *//* ======================================================================== *//* Initialize default parameters for a C2600 */static void c2600_init_defaults(c2600_t *router);/* Read a byte from the NVRAM */static inline m_uint8_t nvram_read_byte(u_char *base,u_int offset){ m_uint8_t *ptr; ptr = (m_uint8_t *)base + (offset << 2); return(*ptr);}/* Write a byte to the NVRAM */static inline void nvram_write_byte(u_char *base,u_int offset,m_uint8_t val){ m_uint8_t *ptr; ptr = (m_uint8_t *)base + (offset << 2); *ptr = val;}/* Read a 16-bit value from NVRAM */static m_uint16_t nvram_read16(u_char *base,u_int offset){ m_uint16_t val; val = nvram_read_byte(base,offset) << 8; val |= nvram_read_byte(base,offset+1); return(val);}/* Write a 16-bit value to NVRAM */static void nvram_write16(u_char *base,u_int offset,m_uint16_t val){ nvram_write_byte(base,offset,val >> 8); nvram_write_byte(base,offset+1,val & 0xFF);}/* Read a 32-bit value from NVRAM */static m_uint32_t nvram_read32(u_char *base,u_int offset){ m_uint32_t val; val = nvram_read_byte(base,offset) << 24; val |= nvram_read_byte(base,offset+1) << 16; val |= nvram_read_byte(base,offset+2) << 8; val |= nvram_read_byte(base,offset+3); return(val);}/* Write a 32-bit value to NVRAM */static void nvram_write32(u_char *base,u_int offset,m_uint32_t val){ nvram_write_byte(base,offset,val >> 24); nvram_write_byte(base,offset+1,val >> 16); nvram_write_byte(base,offset+2,val >> 8); nvram_write_byte(base,offset+3,val & 0xFF);}/* Read a buffer from NVRAM */static void nvram_memcpy_from(u_char *base,u_int offset,u_char *data,u_int len){ u_int i; for(i=0;i<len;i++) { *data = nvram_read_byte(base,offset+i); data++; }}/* Write a buffer from NVRAM */static void nvram_memcpy_to(u_char *base,u_int offset,u_char *data,u_int len){ u_int i; for(i=0;i<len;i++) { nvram_write_byte(base,offset+i,*data); data++; }}/* Directly extract the configuration from the NVRAM device */ssize_t c2600_nvram_extract_config(vm_instance_t *vm,u_char **buffer){ u_char *base_ptr; u_int ios_ptr,cfg_ptr,end_ptr; m_uint32_t start,nvlen; m_uint16_t magic1,magic2; struct vdevice *nvram_dev; off_t nvram_size; int fd; if ((nvram_dev = dev_get_by_name(vm,"nvram"))) dev_sync(nvram_dev); fd = vm_mmap_open_file(vm,"nvram",&base_ptr,&nvram_size); if (fd == -1) return(-1); ios_ptr = vm->nvram_rom_space; end_ptr = nvram_size; if ((ios_ptr + 0x30) >= end_ptr) { vm_error(vm,"NVRAM file too small\n"); return(-1); } magic1 = nvram_read16(base_ptr,ios_ptr+0x06); magic2 = nvram_read16(base_ptr,ios_ptr+0x08); if ((magic1 != 0xF0A5) || (magic2 != 0xABCD)) { vm_error(vm,"unable to find IOS magic numbers (0x%x,0x%x)!\n", magic1,magic2); return(-1); } start = nvram_read32(base_ptr,ios_ptr+0x10) + 1; nvlen = nvram_read32(base_ptr,ios_ptr+0x18); printf("START = 0x%8.8x, LEN = 0x%8.8x\n",start,nvlen); printf("END = 0x%8.8x\n",nvram_read32(base_ptr,ios_ptr+0x14)); if (!(*buffer = malloc(nvlen+1))) { vm_error(vm,"unable to allocate config buffer (%u bytes)\n",nvlen); return(-1); } cfg_ptr = ios_ptr + start + 0x08; if ((cfg_ptr + nvlen) > end_ptr) { vm_error(vm,"NVRAM file too small\n"); return(-1); } nvram_memcpy_from(base_ptr,cfg_ptr,*buffer,nvlen-1); (*buffer)[nvlen-1] = 0; return(nvlen-1);}/* Compute NVRAM checksum */static m_uint16_t c2600_nvram_cksum(u_char *base_ptr,u_int offset,size_t count){ m_uint32_t sum = 0; while(count > 1) { sum = sum + nvram_read16(base_ptr,offset); offset += 2; count -= sizeof(m_uint16_t); } if (count > 0) sum = sum + ((nvram_read16(base_ptr,offset) & 0xFF) << 8); while(sum>>16) sum = (sum & 0xffff) + (sum >> 16); return(~sum);}/* Directly push the IOS configuration to the NVRAM device */int c2600_nvram_push_config(vm_instance_t *vm,u_char *buffer,size_t len){ m_uint32_t cfg_offset,cklen,tmp,ios_ptr,cfg_ptr; m_uint16_t cksum; u_char *base_ptr; int fd; fd = vm_mmap_create_file(vm,"nvram",vm->nvram_size*4096,&base_ptr); if (fd == -1) return(-1); cfg_offset = 0x2c; ios_ptr = vm->nvram_rom_space; cfg_ptr = ios_ptr + cfg_offset; /* Write IOS tag, uncompressed config... */ nvram_write16(base_ptr,ios_ptr+0x06,0xF0A5); nvram_write16(base_ptr,ios_ptr+0x08,0xABCD); nvram_write16(base_ptr,ios_ptr+0x0a,0x0001); nvram_write16(base_ptr,ios_ptr+0x0c,0x0000); nvram_write16(base_ptr,ios_ptr+0x0e,0x0c04); /* Store file contents to NVRAM */ nvram_memcpy_to(base_ptr,cfg_ptr,buffer,len); /* Write config addresses + size */ tmp = cfg_offset - 0x08; nvram_write32(base_ptr,ios_ptr+0x10,tmp); nvram_write32(base_ptr,ios_ptr+0x14,tmp + len); nvram_write32(base_ptr,ios_ptr+0x18,len); /* Compute the checksum */ cklen = (vm->nvram_size*1024) - (vm->nvram_rom_space + 0x08); cksum = c2600_nvram_cksum(base_ptr,ios_ptr+0x08,cklen); nvram_write16(base_ptr,ios_ptr+0x0c,cksum); vm_mmap_close_file(fd,base_ptr,vm->nvram_size*4096); return(0);}/* Check for empty config */int c2600_nvram_check_empty_config(vm_instance_t *vm){ struct vdevice *dev; m_uint64_t addr; m_uint32_t len; if (!(dev = dev_get_by_name(vm,"nvram"))) return(-1); addr = dev->phys_addr + (vm->nvram_rom_space << 2); len = dev->phys_len - (vm->nvram_rom_space << 2); while(len > 0) { if (physmem_copy_u32_from_vm(vm,addr) != 0) return(0); addr += sizeof(m_uint32_t); len -= sizeof(m_uint32_t); } /* Empty NVRAM */ vm->conf_reg |= 0x0040; printf("NVRAM is empty, setting config register to 0x%x\n",vm->conf_reg); return(0);}/* Create a new router instance */static int c2600_create_instance(vm_instance_t *vm){ c2600_t *router; if (!(router = malloc(sizeof(*router)))) { fprintf(stderr,"C2600 '%s': Unable to create new instance!\n",vm->name); return(-1); } memset(router,0,sizeof(*router)); router->vm = vm; vm->hw_data = router; c2600_init_defaults(router); return(0);}/* Free resources used by a router instance */static int c2600_delete_instance(vm_instance_t *vm){ c2600_t *router = VM_C2600(vm); int i; /* Stop all CPUs */ if (vm->cpu_group != NULL) { vm_stop(vm); if (cpu_group_sync_state(vm->cpu_group) == -1) { vm_error(vm,"unable to sync with system CPUs.\n"); return(FALSE); } } /* Remove NIO bindings */ for(i=0;i<vm->nr_slots;i++) vm_slot_remove_all_nio_bindings(vm,i); /* Shutdown all Network Modules */ vm_slot_shutdown_all(vm); /* Free mainboard EEPROM */ cisco_eeprom_free(&router->mb_eeprom); /* Free all resources used by VM */ vm_free(vm); /* Free the router structure */ free(router); return(TRUE);}/* Save configuration of a C2600 instance */void c2600_save_config(vm_instance_t *vm,FILE *fd){ c2600_t *router = VM_C2600(vm); fprintf(fd,"c2600 set_chassis %s %s\n\n",vm->name,router->mainboard_type);}/* Get WIC device address for the specified onboard port */int c2600_get_onboard_wic_addr(u_int slot,m_uint64_t *phys_addr){ if (slot >= C2600_MAX_WIC_BAYS) return(-1); *phys_addr = C2600_WIC_ADDR + (slot * C2600_WIC_SIZE); return(0);}/* Set EEPROM for the specified slot */int c2600_set_slot_eeprom(c2600_t *router,u_int slot, struct cisco_eeprom *eeprom){ switch(slot) { case 1: router->nm_eeprom_group.eeprom[0] = eeprom; return(0); default: return(-1); }}/* Get slot/port corresponding to specified network IRQ */static inline void c2600_net_irq_get_slot_port(u_int irq,u_int *slot,u_int *port){ irq -= C2600_NETIO_IRQ_BASE; *port = irq & C2600_NETIO_IRQ_PORT_MASK; *slot = irq >> C2600_NETIO_IRQ_PORT_BITS;}/* Get network IRQ for specified slot/port */u_int c2600_net_irq_for_slot_port(u_int slot,u_int port){ u_int irq; irq = (slot << C2600_NETIO_IRQ_PORT_BITS) + port; irq += C2600_NETIO_IRQ_BASE; return(irq);}/* Find Cisco 2600 Mainboard info */static struct c2600_mb_id *c2600_get_mb_info(char *mainboard_type){ int i; for(i=0;c2600_mainboard_id[i].name;i++) if (!strcmp(c2600_mainboard_id[i].name,mainboard_type)) return(&c2600_mainboard_id[i]); return NULL;}/* Show all available mainboards */void c2600_mainboard_show_drivers(void){ int i; printf("Available C2600 chassis drivers:\n"); for(i=0;c2600_mainboard_id[i].name;i++) printf(" * %s %s\n", c2600_mainboard_id[i].name, !c2600_mainboard_id[i].supported ? "(NOT WORKING)" : ""); printf("\n");}/* Show the list of available NM drivers */void c2600_nm_show_drivers(void){ int i; printf("Available C2600 Network Module drivers:\n"); for(i=0;nm_drivers[i];i++) { printf(" * %s %s\n", nm_drivers[i]->dev_type, !nm_drivers[i]->supported ? "(NOT WORKING)" : ""); } printf("\n");}/* Set the base MAC address of the chassis */static int c2600_burn_mac_addr(c2600_t *router,n_eth_addr_t *addr){ int i; for(i=0;i<3;i++) { router->vm->chassis_cookie[i+1] = addr->eth_addr_byte[i*2] << 8; router->vm->chassis_cookie[i+1] |= addr->eth_addr_byte[(i*2)+1]; } return(0);}/* Set mainboard type */int c2600_mainboard_set_type(c2600_t *router,char *mainboard_type){ struct c2600_mb_id *mb_info; if (router->vm->status == VM_STATUS_RUNNING) { vm_error(router->vm,"unable to change mainboard type when online.\n"); return(-1); } if (!(mb_info = c2600_get_mb_info(mainboard_type))) { vm_error(router->vm,"unknown mainboard '%s'\n",mainboard_type); return(-1); } router->mainboard_type = mainboard_type; router->xm_model = mb_info->xm_model;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -