/* Update network interrupt status */ static inline void dev_c2600_iofpga_net_update_irq(struct c2600_iofpga_data *d) { if (d->net_irq_status) { vm_set_irq(d->router->vm,C2600_NETIO_IRQ); } else { vm_clear_irq(d->router->vm,C2600_NETIO_IRQ); } }
/* Process remote control char */ static void remote_control(vtty_t *vtty,u_char c) { vm_instance_t *vm = vtty->vm; cpu_gen_t *cpu0; cpu0 = vm->boot_cpu; /* Specific commands for the different CPU models */ if (cpu0) { switch(cpu0->type) { case CPU_TYPE_MIPS64: if (remote_control_mips64(vtty,c,CPU_MIPS64(cpu0))) return; break; case CPU_TYPE_PPC32: if (remote_control_ppc32(vtty,c,CPU_PPC32(cpu0))) return; break; } } switch(c) { /* Show the object list */ case 'o': vm_object_dump(vm); break; /* Stop the MIPS VM */ case 'q': vm->status = VM_STATUS_SHUTDOWN; break; /* Reboot the C7200 */ case 'k': #if 0 if (vm->type == VM_TYPE_C7200) c7200_boot_ios(VM_C7200(vm)); #endif break; /* Show the device list */ case 'd': dev_show_list(vm); pci_dev_show_list(vm->pci_bus[0]); pci_dev_show_list(vm->pci_bus[1]); break; /* Show info about Port Adapters or Network Modules */ case 'p': vm_slot_show_all_info(vm); break; /* Dump the MIPS registers */ case 'r': if (cpu0) cpu0->reg_dump(cpu0); break; /* Dump the latest memory accesses */ case 'm': if (cpu0) memlog_dump(cpu0); break; /* Suspend CPU emulation */ case 's': vm_suspend(vm); break; /* Resume CPU emulation */ case 'u': vm_resume(vm); break; /* Dump the MMU information */ case 't': if (cpu0) cpu0->mmu_dump(cpu0); break; /* Dump the MMU information (raw mode) */ case 'z': if (cpu0) cpu0->mmu_raw_dump(cpu0); break; /* Memory translation cache statistics */ case 'l': if (cpu0) cpu0->mts_show_stats(cpu0); break; /* Extract the configuration from the NVRAM */ case 'c': vm_ios_save_config(vm); break; /* Determine an idle pointer counter */ case 'i': if (cpu0) cpu0->get_idling_pc(cpu0); break; /* Experimentations / Tests */ case 'x': #if 0 if (cpu0) { /* IRQ triggering */ vm_set_irq(vm,6); //CPU_MIPS64(cpu0)->irq_disable = TRUE; } #endif #ifdef USE_UNSTABLE tsg_show_stats(); #endif break; case 'y': if (cpu0) { /* IRQ clearing */ vm_clear_irq(vm,6); } break; /* Twice Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */ case 0x1d: case 0xb3: vtty_store(vtty,c); break; default: printf("\n\nInstance %s (ID %d)\n\n",vm->name,vm->instance_id); printf("o - Show the VM object list\n" "d - Show the device list\n" "r - Dump CPU registers\n" "t - Dump MMU information\n" "z - Dump MMU information (raw mode)\n" "m - Dump the latest memory accesses\n" "s - Suspend CPU emulation\n" "u - Resume CPU emulation\n" "q - Quit the emulator\n" "k - Reboot the virtual machine\n" "b - Show info about JIT compiled pages\n" "l - MTS cache statistics\n" "c - Write IOS configuration to disk\n" "j - Non-JIT mode statistics\n" "i - Determine an idling pointer counter\n" "x - Experimentations (can crash the box!)\n" "^] - Send ^]\n" "Other - This help\n"); } }
/* * dev_ns16552_access() */ void *dev_ns16552_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 ns16552_data *d = dev->priv_data; int channel = 0; u_char odata; if (op_type == MTS_READ) *data = 0; #if DEBUG_ACCESS if (op_type == MTS_READ) { cpu_log(cpu,"NS16552","read from 0x%x, pc=0x%llx\n", offset,cpu_get_pc(cpu)); } else { cpu_log(cpu,"NS16552","write to 0x%x, value=0x%llx, pc=0x%llx\n", offset,*data,cpu_get_pc(cpu)); } #endif offset >>= d->reg_div; if (offset >= 0x08) channel = 1; // From the NS16552V datasheet, the following is known about the registers // Bit 4 is channel // Value 0 Receive or transmit buffer // Value 1 Interrupt enable // Value 2 Interrupt identification (READ), FIFO Config (Write) // Value 3 Line Control (Appears in IOS) // 0x1 - Word Length Selector bit 0 // 0x2 - Word Length Selector bit 1 // 0x4 - Num stop bits // 0x8 - Parity Enable // 0x16 - Parity even // 0x32 - Stick Parity // 0x64 - Set Break // 0x128 - Division Latch // Value 4 Modem Control (Appears in IOS) // Value 5 Line status // Value 6 Modem Status // Value 7 Scratch switch(offset) { /* Receiver Buffer Reg. (RBR) / Transmitting Holding Reg. (THR) */ case 0x00: case 0x08: if (d->div_latch == 0) { if (op_type == MTS_WRITE) { vtty_put_char(d->channel[channel].vtty,(char)*data); if (d->channel[channel].ier & IER_ETXRDY) vm_set_irq(d->vm,d->irq); d->channel[channel].output = TRUE; } else *data = vtty_get_char(d->channel[channel].vtty); } else { if (op_type == MTS_WRITE) d->baud_divisor = ((*data) & 0x00ff) | (d->baud_divisor & 0xff00); } break; /* Interrupt Enable Register (IER) */ case 0x01: case 0x09: if (d->div_latch == 0) { if (op_type == MTS_READ) { *data = d->channel[channel].ier; } else { d->channel[channel].ier = *data & 0xFF; if ((*data & 0x02) == 0) { /* transmit holding register */ d->channel[channel].vtty->managed_flush = TRUE; vtty_flush(d->channel[channel].vtty); } } } else { if (op_type == MTS_WRITE) d->baud_divisor = (((*data) & 0xff)<<8)|(d->baud_divisor & 0xff); } break; /* Interrupt Ident Register (IIR) */ case 0x02: case 0x0A: if (d->div_latch == 0) { vm_clear_irq(d->vm,d->irq); if (op_type == MTS_READ) { odata = IIR_NPENDING; if (vtty_is_char_avail(d->channel[channel].vtty)) { odata = IIR_RXRDY; } else { if (d->channel[channel].output) { odata = IIR_TXRDY; d->channel[channel].output = 0; } } *data = odata; } } break; case 0x03: case 0x0B: if (op_type == MTS_READ) { *data = d->line_control_reg; } else { d->line_control_reg = (uint)*data; uint bits = 5; __maybe_unused char *stop = "1"; __maybe_unused char *parity = "no "; __maybe_unused char *parityeven = "odd"; if (*data & LCR_WRL0) bits+=1; if (*data & LCR_WRL1) bits+=2; if (*data & LCR_NUMSTOP) { if ( bits >= 6) { stop = "2"; } else { stop = "1.5"; } } if (*data & LCR_PARITYON) parity=""; //Parity on if (*data & LCR_PARITYEV) parityeven="even"; // DIV LATCH changes the behavior of 0x0,0x1,and 0x2 if (*data & LCR_DIVLATCH) { d->div_latch = 1; } else { __maybe_unused uint baud; d->div_latch = 0; // 1200 divisor was 192 // 9600 divisor was 24 // 19200 divisor was 12 // Suggests a crystal of 3686400 hz if (d->baud_divisor > 0) { baud = 3686400 / (d->baud_divisor * 16); } else { baud = 0; } } } break; case 0x04: case 0x0C: if (op_type != MTS_READ) { __maybe_unused char *f1 = ""; __maybe_unused char *f2 = ""; __maybe_unused char *f3 = ""; __maybe_unused char *f4 = ""; __maybe_unused char *f5 = ""; if (*data & MCR_DTR) f1 = "DTR "; if (*data & MCR_RTS) f2 = "RTS "; if (*data & MCR_OUT1) f3 = "OUT1 "; if (*data & MCR_OUT2) f4 = "OUT2 "; if (*data & MCR_LOOP) f5 = "LOOP "; } break; /* Line Status Register (LSR) */ case 0x05: case 0x0D: if (op_type == MTS_READ) { odata = 0; if (vtty_is_char_avail(d->channel[channel].vtty)) odata |= LSR_RXRDY; odata |= LSR_TXRDY|LSR_TXEMPTY; *data = odata; } break; #if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,"NS16552","read from addr 0x%x, pc=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu, "NS16552","write to addr 0x%x, value=0x%llx, " "pc=0x%llx (size=%u)\n", offset,*data,cpu_get_pc(cpu),op_size); } #endif } return NULL; }
/* * dev_c3660_iofpga_access() */ static void * dev_c3660_iofpga_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 c3600_iofpga_data *d = dev->priv_data; u_int slot; if (op_type == MTS_READ) *data = 0x0; #if DEBUG_ACCESS if (offset != 0x0c) { if (op_type == MTS_READ) { cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,"IO_FPGA", "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),*data,op_size); } } #endif switch(offset) { /* * 0x7d00 is written here regularly. * Some kind of hardware watchdog ? */ case 0x0000c: break; /* Probably flash protection (if 0, no write access allowed) */ case 0x00008: if (op_type == MTS_READ) *data = 0xFF; break; /* Bootflash of 8 Mb */ case 0x0000a: if (op_type == MTS_READ) *data = 0x1000; break; /* NM presence - slots 1 to 4 */ case 0x10006: if (op_type == MTS_READ) *data = nm_get_status_2(d,0); break; /* NM presence - slot 5 to 6 */ case 0x10008: if (op_type == MTS_READ) *data = nm_get_status_2(d,1); break; /* Fan status, PS presence */ case 0x10018: if (op_type == MTS_READ) *data = 0x0000; break; /* unknown, read by env monitor */ case 0x1001a: if (op_type == MTS_READ) *data = 0x0000; break; /* board temperature */ case 0x30004: if (op_type == MTS_READ) { *data = 32 + 1; } break; /* sh c3600: Per Slot Intr Mask */ case 0x10016: if (op_type == MTS_READ) *data = 0x12; break; /* sh c3600: OIR fsm state slot's (12) */ case 0x10020: if (op_type == MTS_READ) *data = 0x00; break; /* sh c3600: OIR fsm state slot's (34) */ case 0x10022: if (op_type == MTS_READ) *data = 0x00; break; /* sh c3600: OIR fsm state slot's (56) */ case 0x10024: if (op_type == MTS_READ) *data = 0x00; break; /* * Backplane EEPROM. * * Bit 7: 0=Telco chassis, 1=Enterprise chassis. */ case 0x10000: if (op_type == MTS_WRITE) nmc93cX6_write(&d->router->mb_eeprom_group,(u_int)(*data)); else *data = nmc93cX6_read(&d->router->mb_eeprom_group) | 0x80; break; /* NM EEPROMs - slots 1 to 6 */ case 0x1000a: case 0x1000b: case 0x1000c: case 0x1000d: case 0x1000e: case 0x1000f: slot = (offset - 0x1000a) + 1; if (op_type == MTS_WRITE) { nmc93cX6_write(&d->router->c3660_nm_eeprom_group[slot], (u_int)(*data)); } else { *data = nmc93cX6_read(&d->router->c3660_nm_eeprom_group[slot]); } break; /* NM EEPROM - slot 0 */ case 0x20006: if (op_type == MTS_WRITE) { nmc93cX6_write(&d->router->c3660_nm_eeprom_group[0], (u_int)(*data)); } else { *data = nmc93cX6_read(&d->router->c3660_nm_eeprom_group[0]); } break; /* Unknown EEPROMs ? */ case 0x20000: case 0x20002: case 0x20004: if (op_type == MTS_READ) *data = 0xFFFF; break; /* IO Mask (displayed by "show c3600") */ case 0x20008: if (op_type == MTS_READ) *data = d->io_mask; else d->io_mask = *data; break; /* 0: 3640, 4 << 5: 3620, 3 << 5: 3660 */ case 0x30000: if (op_type == MTS_READ) *data = 3 << 5; break; /* ??? */ case 0x30008: if (op_type == MTS_READ) *data = 0xFF; break; /* * Read at net interrupt (size 4). * It seems that there are 4 lines per slot. * * Bit 24-27: slot 1 * Bit 16-19: slot 2 * Bit 28-31: slot 3 * Bit 20-23: slot 4 * Bit 08-11: slot 5 * Bit 00-03: slot 6 * * Other bits are unknown. */ case 0x10010: if (op_type == MTS_READ) *data = d->net_irq_status[0]; break; /* * Read at net interrupt (size 1) * * Bit 7-6: we get "Unexpected AIM interrupt on AIM slot 1". * Bit 5-4: we get "Unexpected AIM interrupt on AIM slot 0". * Bit 0-3: net interrupt for slot 0. */ case 0x20010: if (op_type == MTS_READ) *data = d->net_irq_status[1]; break; /* * Read when a PA Management interrupt is triggered. * * If not 0, we get: * "Error: Unexpected NM Interrupt received from slot: x" */ case 0x10014: if (op_type == MTS_READ) *data = 0x00; vm_clear_irq(d->router->vm,C3600_NM_MGMT_IRQ); break; /* * Read when an external interrupt is triggered. * * Bit 4: 1 = %UNKNOWN-1-GT64010: Unknown fatal interrupt(s) * Bit 6: 1 = %OIRINT: OIR Event has occurred oir_ctrl 1000 oir_stat FFFF * * oir_ctrl = register 0x10004 * oir_stat = register 0x10006 */ case 0x2000a: if (op_type == MTS_READ) *data = 0x54; vm_clear_irq(d->router->vm,C3600_EXT_IRQ); break; #if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,"IO_FPGA", "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,"IO_FPGA", "write to unknown addr 0x%x, value=0x%llx, " "pc=0x%llx (size=%u)\n", offset,*data,cpu_get_pc(cpu),op_size); } #endif } return NULL; }
/* * dev_c3620_c3640_iofpga_access() */ static void * dev_c3620_c3640_iofpga_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 c3600_iofpga_data *d = dev->priv_data; if (op_type == MTS_READ) *data = 0x0; #if DEBUG_ACCESS if (offset != 0x0c) { if (op_type == MTS_READ) { cpu_log(cpu,"IO_FPGA","reading reg 0x%x at pc=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,"IO_FPGA", "writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),*data,op_size); } } #endif switch(offset) { /* Probably flash protection (if 0, no write access allowed) */ case 0x00008: if (op_type == MTS_READ) *data = 0xFF; break; /* Bootflash of 8 Mb */ case 0x0000a: if (op_type == MTS_READ) *data = 0x1000; break; /* * 0x7d00 is written here regularly. * Some kind of hardware watchdog ? */ case 0x0000c: break; /* Mainboard EEPROM */ case 0x0000e: if (op_type == MTS_WRITE) nmc93cX6_write(&d->router->mb_eeprom_group,(u_int)(*data)); else *data = nmc93cX6_read(&d->router->mb_eeprom_group); break; case 0x10004: /* ??? OIR control ??? */ if (op_type == MTS_READ) { *data = 0x0000; } break; /* * Network modules presence. * * Bit 0: 0 = NM in slot 0 is valid * Bit 1: 0 = NM in slot 1 is valid * Bit 2: 0 = NM in slot 2 is valid * Bit 3: 0 = NM in slot 3 is valid * * Very well explained on Cisco website: * http://www.cisco.com/en/US/customer/products/hw/routers/ps274/products_tech_note09186a0080109510.shtml */ case 0x10006: if (op_type == MTS_READ) *data = nm_get_status_1(d); break; /* * NM EEPROMs. */ case 0x10008: if (op_type == MTS_WRITE) { d->eeprom_slot = *data & 0x03; nm_eeprom_select(d,d->eeprom_slot); nmc93cX6_write(&d->router->nm_eeprom_group,*data); } else { *data = nmc93cX6_read(&d->router->nm_eeprom_group); } break; /* Network interrupt status */ case 0x20000: /* slot 1 */ if (op_type == MTS_READ) *data = d->net_irq_status[0] >> 24; break; case 0x20001: /* slot 0 */ if (op_type == MTS_READ) *data = d->net_irq_status[0] >> 16; break; case 0x20002: /* slot 3 */ if (op_type == MTS_READ) *data = d->net_irq_status[0] >> 8; break; case 0x20003: /* slot 2 */ if (op_type == MTS_READ) *data = d->net_irq_status[0]; break; /* * Read when a PA Management interrupt is triggered. * * If not 0, we get: * "Error: Unexpected NM Interrupt received from slot: x" */ case 0x20004: if (op_type == MTS_READ) *data = 0x00; vm_clear_irq(d->router->vm,C3600_NM_MGMT_IRQ); break; /* * Read when an external interrupt is triggered. * * Bit 4: 1 = %UNKNOWN-1-GT64010: Unknown fatal interrupt(s) * Bit 6: 1 = %OIRINT: OIR Event has occurred oir_ctrl 1000 oir_stat FFFF * * oir_ctrl = register 0x10004 * oir_stat = register 0x10006 */ case 0x20006: if (op_type == MTS_READ) *data = 0x00; vm_clear_irq(d->router->vm,C3600_EXT_IRQ); break; /* IO Mask (displayed by "show c3600") */ case 0x20008: if (op_type == MTS_READ) *data = d->io_mask; else d->io_mask = *data; break; /* * Platform type ? * 0: 3640, 4 << 5: 3620, 3 << 5: 3660 */ case 0x30000: if (op_type == MTS_READ) { switch(c3600_chassis_get_id(d->router)) { case 3620: *data = 4 << 5; break; case 3640: *data = 0 << 5; break; case 3660: *data = 3 << 5; break; default: *data = 0; } } break; /* ??? */ case 0x30002: if (op_type == MTS_WRITE) { d->sel = *data; } else { //*data = d->sel; } break; /* * Environmental parameters, determined with "sh env all". * * Bit 0: 0 = overtemperature condition. * Bit 4: 0 = RPS present. * Bit 5: 0 = Input Voltage status failure. * Bit 6: 1 = Thermal status failure. * Bit 7: 1 = DC Output Voltage status failure. */ case 0x30004: if (op_type == MTS_READ) { *data = 32 + 1; } break; #if DEBUG_UNKNOWN default: if (op_type == MTS_READ) { cpu_log(cpu,"IO_FPGA", "read from unknown addr 0x%x, pc=0x%llx (size=%u)\n", offset,cpu_get_pc(cpu),op_size); } else { cpu_log(cpu,"IO_FPGA", "write to unknown addr 0x%x, value=0x%llx, " "pc=0x%llx (size=%u)\n", offset,*data,cpu_get_pc(cpu),op_size); } #endif } return NULL; }