1 |
/* |
2 |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2006 Christophe Fillot (cf@utc.fr) |
4 |
* |
5 |
* PowerPC VM experimentations. |
6 |
*/ |
7 |
|
8 |
#include <stdio.h> |
9 |
#include <stdlib.h> |
10 |
#include <string.h> |
11 |
#include <unistd.h> |
12 |
#include <sys/types.h> |
13 |
#include <assert.h> |
14 |
|
15 |
#include "cpu.h" |
16 |
#include "vm.h" |
17 |
#include "dynamips.h" |
18 |
#include "memory.h" |
19 |
#include "device.h" |
20 |
#include "dev_rom.h" |
21 |
#include "pci_io.h" |
22 |
#include "dev_vtty.h" |
23 |
#include "registry.h" |
24 |
#include "net.h" |
25 |
#include "ppc32_mem.h" |
26 |
#include "ppc32_vmtest.h" |
27 |
|
28 |
static struct ppc32_bat_prog bat_array[] = { |
29 |
{ PPC32_IBAT_IDX, 0, 0xfff0001e, 0xfff00001 }, |
30 |
{ PPC32_IBAT_IDX, 1, 0x00001ffe, 0x00000001 }, |
31 |
{ PPC32_IBAT_IDX, 2, 0x00000000, 0xee3e0072 }, |
32 |
{ PPC32_IBAT_IDX, 3, 0x80001ffe, 0x80000001 }, |
33 |
|
34 |
{ PPC32_DBAT_IDX, 0, 0x80001ffe, 0x80000042 }, |
35 |
{ PPC32_DBAT_IDX, 1, 0x00001ffe, 0x0000002a }, |
36 |
{ PPC32_DBAT_IDX, 2, 0x60001ffe, 0x6000002a }, |
37 |
{ PPC32_DBAT_IDX, 3, 0xfc0007fe, 0xfc00002a }, |
38 |
{ -1, -1, 0, 0 }, |
39 |
}; |
40 |
|
41 |
/* Create a new router instance */ |
42 |
static int ppc32_vmtest_create_instance(vm_instance_t *vm) |
43 |
{ |
44 |
vm->ram_size = PPC32_VMTEST_DEFAULT_RAM_SIZE; |
45 |
return(0); |
46 |
} |
47 |
|
48 |
/* Free resources used by a test instance */ |
49 |
static int ppc32_vmtest_delete_instance(vm_instance_t *vm) |
50 |
{ |
51 |
/* Stop all CPUs */ |
52 |
if (vm->cpu_group != NULL) { |
53 |
vm_stop(vm); |
54 |
|
55 |
if (cpu_group_sync_state(vm->cpu_group) == -1) { |
56 |
vm_error(vm,"unable to sync with system CPUs.\n"); |
57 |
return(FALSE); |
58 |
} |
59 |
} |
60 |
|
61 |
/* Free all resources used by VM */ |
62 |
vm_free(vm); |
63 |
return(TRUE); |
64 |
} |
65 |
|
66 |
/* Set IRQ line */ |
67 |
static void ppc32_vmtest_set_irq(vm_instance_t *vm,u_int irq) |
68 |
{ |
69 |
cpu_ppc_t *cpu = CPU_PPC32(vm->boot_cpu); |
70 |
|
71 |
cpu->irq_check = cpu->irq_pending = TRUE; |
72 |
} |
73 |
|
74 |
/* Clear IRQ line */ |
75 |
static void ppc32_vmtest_clear_irq(vm_instance_t *vm,u_int irq) |
76 |
{ |
77 |
cpu_ppc_t *cpu = CPU_PPC32(vm->boot_cpu); |
78 |
|
79 |
cpu->irq_check = cpu->irq_pending = FALSE; |
80 |
} |
81 |
|
82 |
/* Initialize the PPC32 VM test Platform */ |
83 |
static int ppc32_vmtest_init_platform(vm_instance_t *vm) |
84 |
{ |
85 |
cpu_ppc_t *cpu0; |
86 |
cpu_gen_t *gen0; |
87 |
|
88 |
/* Create Console and AUX ports */ |
89 |
vm_init_vtty(vm); |
90 |
|
91 |
/* Create a CPU group */ |
92 |
vm->cpu_group = cpu_group_create("System CPU"); |
93 |
|
94 |
/* Initialize the virtual PowerPC processor */ |
95 |
if (!(gen0 = cpu_create(vm,CPU_TYPE_PPC32,0))) { |
96 |
vm_error(vm,"unable to create CPU0!\n"); |
97 |
return(-1); |
98 |
} |
99 |
|
100 |
cpu0 = CPU_PPC32(gen0); |
101 |
|
102 |
/* Enable as PowerPC 405 */ |
103 |
//ppc32_set_pvr(cpu0,PPC32_PVR_405 | 0x0102); |
104 |
|
105 |
/* Add this CPU to the system CPU group */ |
106 |
cpu_group_add(vm->cpu_group,gen0); |
107 |
vm->boot_cpu = gen0; |
108 |
|
109 |
/* Set IRQ vectors */ |
110 |
vm->set_irq = ppc32_vmtest_set_irq; |
111 |
vm->clear_irq = ppc32_vmtest_clear_irq; |
112 |
|
113 |
#if 0 |
114 |
{ |
115 |
vm_obj_t *obj; |
116 |
/* Initialize ROM (as a Flash) */ |
117 |
if (!(obj = dev_flash_init(vm,"rom",0xFF000000,16*1048576))) |
118 |
return(-1); |
119 |
|
120 |
dev_flash_copy_data(obj,0x0F00000,ppc32_microcode,ppc32_microcode_len); |
121 |
} |
122 |
#endif |
123 |
|
124 |
//dev_bootflash_init(vm,"bootflash",0xFF000000,8*1048576); |
125 |
|
126 |
#if 1 |
127 |
/* Initialize ROM */ |
128 |
if (!vm->rom_filename) { |
129 |
/* use embedded ROM */ |
130 |
dev_rom_init(vm,"rom",0xFFF00000,512*1024, |
131 |
ppc32_microcode,ppc32_microcode_len); |
132 |
} else { |
133 |
/* use alternate ROM */ |
134 |
dev_ram_init(vm,"rom",TRUE,TRUE,NULL,FALSE, |
135 |
0xFFF00000,512*1024); |
136 |
} |
137 |
#endif |
138 |
|
139 |
dev_ram_init(vm,"nvram",TRUE,FALSE,NULL,FALSE, |
140 |
0x67c00000,vm->nvram_size*4096); |
141 |
|
142 |
dev_ns16552_init(vm,0xffe00000,0x1000,0,0,vm->vtty_con,vm->vtty_aux); |
143 |
|
144 |
/* Remote emulator control */ |
145 |
dev_remote_control_init(vm,0xf6000000,0x1000); |
146 |
|
147 |
/* Initialize RAM */ |
148 |
vm_ram_init(vm,0x00000000); |
149 |
|
150 |
/* RAM aliasing */ |
151 |
dev_create_ram_alias(vm,"ram_alias","ram",0x80000000,vm->ram_size*1048576); |
152 |
|
153 |
/* Display the device list */ |
154 |
dev_show_list(vm); |
155 |
return(0); |
156 |
} |
157 |
|
158 |
/* Boot the RAW image */ |
159 |
static int ppc32_vmtest_boot_raw(vm_instance_t *vm) |
160 |
{ |
161 |
cpu_ppc_t *cpu; |
162 |
|
163 |
if (!vm->boot_cpu) |
164 |
return(-1); |
165 |
|
166 |
/* Suspend CPU activity since we will restart directly from ROM */ |
167 |
vm_suspend(vm); |
168 |
|
169 |
/* Check that CPU activity is really suspended */ |
170 |
if (cpu_group_sync_state(vm->cpu_group) == -1) { |
171 |
vm_error(vm,"unable to sync with system CPUs.\n"); |
172 |
return(-1); |
173 |
} |
174 |
|
175 |
/* Reset the boot CPU */ |
176 |
cpu = CPU_PPC32(vm->boot_cpu); |
177 |
ppc32_reset(cpu); |
178 |
|
179 |
/* Load RAW image */ |
180 |
if (ppc32_load_raw_image(cpu,vm->ios_image,0xFFF00000) < 0) { |
181 |
vm_error(vm,"failed to load RAW image '%s'.\n",vm->ios_image); |
182 |
return(-1); |
183 |
} |
184 |
|
185 |
cpu->ia = 0xFFF00100; |
186 |
cpu->gpr[1] = 0x2000; |
187 |
|
188 |
/* Launch the simulation */ |
189 |
printf("\nPPC32_VMTEST '%s': starting simulation (CPU0 IA=0x%8.8x), " |
190 |
"JIT %sabled.\n", |
191 |
vm->name,cpu->ia,vm->jit_use ? "en":"dis"); |
192 |
|
193 |
vm_log(vm,"PPC32_VMTEST_BOOT", |
194 |
"starting instance (CPU0 IA=0x%8.8x,JIT %s)\n", |
195 |
cpu->ia,vm->jit_use ? "on":"off"); |
196 |
|
197 |
/* Start main CPU */ |
198 |
if (vm->ghost_status != VM_GHOST_RAM_GENERATE) { |
199 |
vm->status = VM_STATUS_RUNNING; |
200 |
cpu_start(vm->boot_cpu); |
201 |
} else { |
202 |
vm->status = VM_STATUS_SHUTDOWN; |
203 |
} |
204 |
return(0); |
205 |
} |
206 |
|
207 |
/* Boot the ELF image */ |
208 |
static int ppc32_vmtest_boot_elf(vm_instance_t *vm) |
209 |
{ |
210 |
m_uint32_t rom_entry_point; |
211 |
cpu_ppc_t *cpu; |
212 |
|
213 |
if (!vm->boot_cpu) |
214 |
return(-1); |
215 |
|
216 |
/* Suspend CPU activity since we will restart directly from ROM */ |
217 |
vm_suspend(vm); |
218 |
|
219 |
/* Check that CPU activity is really suspended */ |
220 |
if (cpu_group_sync_state(vm->cpu_group) == -1) { |
221 |
vm_error(vm,"unable to sync with system CPUs.\n"); |
222 |
return(-1); |
223 |
} |
224 |
|
225 |
/* Reset the boot CPU */ |
226 |
cpu = CPU_PPC32(vm->boot_cpu); |
227 |
ppc32_reset(cpu); |
228 |
|
229 |
/* Load ROM (ELF image or embedded) */ |
230 |
cpu = CPU_PPC32(vm->boot_cpu); |
231 |
rom_entry_point = (m_uint32_t)PPC32_ROM_START; |
232 |
|
233 |
if ((vm->rom_filename != NULL) && |
234 |
(ppc32_load_elf_image(cpu,vm->rom_filename,0,&rom_entry_point) < 0)) |
235 |
{ |
236 |
vm_error(vm,"unable to load alternate ROM '%s', " |
237 |
"fallback to embedded ROM.\n\n",vm->rom_filename); |
238 |
vm->rom_filename = NULL; |
239 |
} |
240 |
|
241 |
/* Load ELF image */ |
242 |
if (ppc32_load_elf_image(cpu,vm->ios_image, |
243 |
(vm->ghost_status == VM_GHOST_RAM_USE), |
244 |
&vm->ios_entry_point) < 0) |
245 |
{ |
246 |
vm_error(vm,"failed to load ELF image '%s'.\n",vm->ios_image); |
247 |
return(-1); |
248 |
} |
249 |
|
250 |
/* Launch the simulation */ |
251 |
printf("\nPPC32_VMTEST '%s': starting simulation (CPU0 IA=0x%8.8x), " |
252 |
"JIT %sabled.\n", |
253 |
vm->name,cpu->ia,vm->jit_use ? "en":"dis"); |
254 |
|
255 |
vm_log(vm,"PPC32_VMTEST_BOOT", |
256 |
"starting instance (CPU0 IA=0x%8.8x,JIT %s)\n", |
257 |
cpu->ia,vm->jit_use ? "on":"off"); |
258 |
|
259 |
/* Start main CPU */ |
260 |
if (vm->ghost_status != VM_GHOST_RAM_GENERATE) { |
261 |
vm->status = VM_STATUS_RUNNING; |
262 |
cpu_start(vm->boot_cpu); |
263 |
} else { |
264 |
vm->status = VM_STATUS_SHUTDOWN; |
265 |
} |
266 |
return(0); |
267 |
} |
268 |
|
269 |
/* Initialize a test instance */ |
270 |
static int ppc32_vmtest_init_instance(vm_instance_t *vm) |
271 |
{ |
272 |
/* Initialize the test platform */ |
273 |
if (ppc32_vmtest_init_platform(vm) == -1) { |
274 |
vm_error(vm,"unable to initialize the platform hardware.\n"); |
275 |
return(-1); |
276 |
} |
277 |
|
278 |
/* Load BAT registers */ |
279 |
ppc32_load_bat_array(CPU_PPC32(vm->boot_cpu),bat_array); |
280 |
|
281 |
return(ppc32_vmtest_boot_elf(vm)); |
282 |
} |
283 |
|
284 |
/* Stop a test instance */ |
285 |
static int ppc32_vmtest_stop_instance(vm_instance_t *vm) |
286 |
{ |
287 |
printf("\nPPC32_VMTEST '%s': stopping simulation.\n",vm->name); |
288 |
vm_log(vm,"PPC32_VMTEST_STOP","stopping simulation.\n"); |
289 |
|
290 |
/* Stop all CPUs */ |
291 |
if (vm->cpu_group != NULL) { |
292 |
vm_stop(vm); |
293 |
|
294 |
if (cpu_group_sync_state(vm->cpu_group) == -1) { |
295 |
vm_error(vm,"unable to sync with system CPUs.\n"); |
296 |
return(-1); |
297 |
} |
298 |
} |
299 |
|
300 |
/* Free resources that were used during execution to emulate hardware */ |
301 |
vm_hardware_shutdown(vm); |
302 |
return(0); |
303 |
} |
304 |
|
305 |
/* Platform definition */ |
306 |
static vm_platform_t ppc32_vmtest_platform = { |
307 |
"ppc32_test", "PPC32_VMTEST", "PPC32_TEST", |
308 |
ppc32_vmtest_create_instance, |
309 |
ppc32_vmtest_delete_instance, |
310 |
ppc32_vmtest_init_instance, |
311 |
ppc32_vmtest_stop_instance, |
312 |
NULL, |
313 |
NULL, |
314 |
NULL, |
315 |
NULL, |
316 |
NULL, |
317 |
NULL, |
318 |
NULL, |
319 |
}; |
320 |
|
321 |
/* Register the ppc32_vmtest platform */ |
322 |
int ppc32_vmtest_platform_register(void) |
323 |
{ |
324 |
return(vm_platform_register(&ppc32_vmtest_platform)); |
325 |
} |