1 /*
2  * Cisco router simulation platform.
3  * Copyright (C) 2006 Christophe Fillot.  All rights reserved.
4  *
5  * Remote control module.
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdarg.h>
12 #include <unistd.h>
13 #include <time.h>
14 #include <errno.h>
15 #include <pthread.h>
16 #include <assert.h>
17 
18 #include "utils.h"
19 #include "cpu.h"
20 #include "vm.h"
21 #include "dynamips.h"
22 #include "memory.h"
23 #include "device.h"
24 #include "net.h"
25 #include "net_io.h"
26 #include "registry.h"
27 #include "ptask.h"
28 #include "dev_c7200.h"
29 #include "dev_c3600.h"
30 #include "dev_c2691.h"
31 #include "dev_c3725.h"
32 #include "dev_c3745.h"
33 #include "dev_c2600.h"
34 
35 #define DEBUG_ACCESS 0
36 
37 #define ROMMON_SET_VAR   0x01
38 #define ROMMON_GET_VAR   0x02
39 #define ROMMON_CLEAR_VAR_STAT  0x03
40 
41 /* Remote control private data */
42 struct remote_data {
43    vm_obj_t vm_obj;
44    struct vdevice dev;
45 
46    /* Console buffer */
47    char con_buffer[512];
48    u_int con_buf_pos;
49 
50    /* ROMMON variables buffer */
51    char var_buffer[512];
52    u_int var_buf_pos;
53    u_int var_status;
54 
55    /* Position for cookie reading */
56    u_int cookie_pos;
57 };
58 
59 /*
60  * dev_remote_control_access()
61  */
dev_remote_control_access(cpu_gen_t * cpu,struct vdevice * dev,m_uint32_t offset,u_int op_size,u_int op_type,m_uint64_t * data)62 void *dev_remote_control_access(cpu_gen_t *cpu,struct vdevice *dev,
63                                 m_uint32_t offset,u_int op_size,u_int op_type,
64                                 m_uint64_t *data)
65 {
66    vm_instance_t *vm = cpu->vm;
67    struct remote_data *d = dev->priv_data;
68    struct vdevice *storage_dev;
69    size_t len;
70 
71    if (op_type == MTS_READ)
72       *data = 0;
73 
74 #if DEBUG_ACCESS
75    if (op_type == MTS_READ) {
76       cpu_log(cpu,"REMOTE","reading reg 0x%x at pc=0x%llx\n",
77               offset,cpu_get_pc(cpu));
78    } else {
79       cpu_log(cpu,"REMOTE","writing reg 0x%x at pc=0x%llx, data=0x%llx\n",
80               offset,cpu_get_pc(cpu),*data);
81    }
82 #endif
83 
84    switch(offset) {
85       /* ROM Identification tag */
86       case 0x000:
87          if (op_type == MTS_READ)
88             *data = ROM_ID;
89          break;
90 
91       /* CPU ID */
92       case 0x004:
93          if (op_type == MTS_READ)
94             *data = cpu->id;
95          break;
96 
97       /* Display CPU registers */
98       case 0x008:
99          if (op_type == MTS_WRITE)
100             cpu->reg_dump(cpu);
101          break;
102 
103       /* Display CPU memory info */
104       case 0x00c:
105          if (op_type == MTS_WRITE)
106             cpu->mmu_dump(cpu);
107          break;
108 
109       /* Reserved/Unused */
110       case 0x010:
111          break;
112 
113       /* RAM size */
114       case 0x014:
115          if (op_type == MTS_READ)
116             *data = vm->ram_size - vm->ram_res_size;
117          break;
118 
119       /* ROM size */
120       case 0x018:
121          if (op_type == MTS_READ)
122             *data = vm->rom_size;
123          break;
124 
125       /* NVRAM size */
126       case 0x01c:
127          if (op_type == MTS_READ)
128             *data = vm->nvram_size;
129          break;
130 
131       /* IOMEM size */
132       case 0x020:
133         if (op_type == MTS_READ)
134             *data = vm->iomem_size;
135          break;
136 
137       /* Config Register */
138       case 0x024:
139          if (op_type == MTS_READ)
140             *data = vm->conf_reg;
141          break;
142 
143       /* ELF entry point */
144       case 0x028:
145          if (op_type == MTS_READ)
146             *data = vm->ios_entry_point;
147          break;
148 
149       /* ELF machine id */
150       case 0x02c:
151          if (op_type == MTS_READ)
152             *data = vm->elf_machine_id;
153          break;
154 
155       /* Restart IOS Image */
156       case 0x030:
157          /* not implemented */
158          break;
159 
160       /* Stop the virtual machine */
161       case 0x034:
162          vm->status = VM_STATUS_SHUTDOWN;
163          break;
164 
165       /* Debugging/Log message: /!\ physical address */
166       case 0x038:
167          if (op_type == MTS_WRITE) {
168             len = physmem_strlen(vm,*data);
169             if (len < sizeof(d->con_buffer)) {
170                physmem_copy_from_vm(vm,d->con_buffer,*data,len+1);
171                vm_log(vm,"ROM",d->con_buffer);
172             }
173          }
174          break;
175 
176       /* Console Buffering */
177       case 0x03c:
178          if (op_type == MTS_WRITE) {
179             if (d->con_buf_pos < (sizeof(d->con_buffer)-1)) {
180                d->con_buffer[d->con_buf_pos++] = *data & 0xFF;
181                d->con_buffer[d->con_buf_pos] = 0;
182 
183                if (d->con_buffer[d->con_buf_pos-1] == '\n') {
184                   vm_log(vm,"ROM","%s",d->con_buffer);
185                   d->con_buf_pos = 0;
186                }
187             } else
188                d->con_buf_pos = 0;
189          }
190          break;
191 
192       /* Console output */
193       case 0x040:
194          if (op_type == MTS_WRITE)
195             vtty_put_char(vm->vtty_con,(char)*data);
196          break;
197 
198       /* NVRAM address */
199       case 0x044:
200          if (op_type == MTS_READ) {
201             if ((storage_dev = dev_get_by_name(vm,"nvram")))
202                *data = storage_dev->phys_addr;
203 
204             if ((storage_dev = dev_get_by_name(vm,"ssa")))
205                *data = storage_dev->phys_addr;
206 
207             if (cpu->type == CPU_TYPE_MIPS64)
208                *data += MIPS_KSEG1_BASE;
209          }
210          break;
211 
212       /* IO memory size for Smart-Init (C3600, others ?) */
213       case 0x048:
214          if (op_type == MTS_READ)
215             *data = vm->nm_iomem_size;
216          break;
217 
218       /* Cookie position selector */
219       case 0x04c:
220          if (op_type == MTS_READ)
221             *data = d->cookie_pos;
222          else
223             d->cookie_pos = *data;
224          break;
225 
226       /* Cookie data */
227       case 0x050:
228          if ((op_type == MTS_READ) && (d->cookie_pos < 64))
229             *data = vm->chassis_cookie[d->cookie_pos];
230          break;
231 
232       /* ROMMON variable */
233       case 0x054:
234          if (op_type == MTS_WRITE) {
235             if (d->var_buf_pos < (sizeof(d->var_buffer)-1)) {
236                d->var_buffer[d->var_buf_pos++] = *data & 0xFF;
237                d->var_buffer[d->var_buf_pos] = 0;
238             } else
239                d->var_buf_pos = 0;
240          } else {
241             if (d->var_buf_pos < (sizeof(d->var_buffer)-1)) {
242                *data = d->var_buffer[d->var_buf_pos++];
243             } else {
244                d->var_buf_pos = 0;
245                *data = 0;
246             }
247          }
248          break;
249 
250       /* ROMMON variable command */
251       case 0x058:
252          if (op_type == MTS_WRITE) {
253             switch(*data & 0xFF) {
254                case ROMMON_SET_VAR:
255                   d->var_status = rommon_var_add_str(&vm->rommon_vars,
256                                                      d->var_buffer);
257                   d->var_buf_pos = 0;
258                   break;
259                case ROMMON_GET_VAR:
260                   d->var_status = rommon_var_get(&vm->rommon_vars,
261                                                  d->var_buffer,
262                                                  d->var_buffer,
263                                                  sizeof(d->var_buffer));
264                   d->var_buf_pos = 0;
265                   break;
266                case ROMMON_CLEAR_VAR_STAT:
267                   d->var_buf_pos = 0;
268                   break;
269                default:
270                   d->var_status = -1;
271             }
272          } else {
273             *data = d->var_status;
274          }
275          break;
276    }
277 
278    return NULL;
279 }
280 
281 /* Shutdown a remote control device */
dev_remote_control_shutdown(vm_instance_t * vm,struct remote_data * d)282 void dev_remote_control_shutdown(vm_instance_t *vm,struct remote_data *d)
283 {
284    if (d != NULL) {
285       dev_remove(vm,&d->dev);
286       free(d);
287    }
288 }
289 
290 /* remote control device */
dev_remote_control_init(vm_instance_t * vm,m_uint64_t paddr,m_uint32_t len)291 int dev_remote_control_init(vm_instance_t *vm,m_uint64_t paddr,m_uint32_t len)
292 {
293    struct remote_data *d;
294 
295    if (!(d = malloc(sizeof(*d)))) {
296       fprintf(stderr,"Remote Control: unable to create device.\n");
297       return(-1);
298    }
299 
300    memset(d,0,sizeof(*d));
301 
302    vm_object_init(&d->vm_obj);
303    d->vm_obj.name = "remote_ctrl";
304    d->vm_obj.data = d;
305    d->vm_obj.shutdown = (vm_shutdown_t)dev_remote_control_shutdown;
306 
307    dev_init(&d->dev);
308    d->dev.name      = "remote_ctrl";
309    d->dev.phys_addr = paddr;
310    d->dev.phys_len  = len;
311    d->dev.handler   = dev_remote_control_access;
312    d->dev.priv_data = d;
313 
314    /* Map this device to the VM */
315    vm_bind_device(vm,&d->dev);
316    vm_object_add(vm,&d->vm_obj);
317    return(0);
318 }
319