/[dynamips]/upstream/dynamips-0.2.6-RC3/mips64.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/dynamips-0.2.6-RC3/mips64.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Sat Oct 6 16:06:49 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 25242 byte(s)
dynamips-0.2.6-RC3

1 /*
2 * Cisco 7200 (Predator) simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * XXX TODO: proper context save/restore for CPUs.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/mman.h>
15 #include <fcntl.h>
16 #include <assert.h>
17
18 #include "rbtree.h"
19 #include "mips64.h"
20 #include "dynamips.h"
21 #include "cp0.h"
22 #include "mips64_exec.h"
23 #include "memory.h"
24 #include "device.h"
25
26 /* MIPS general purpose registers names */
27 char *mips64_gpr_reg_names[MIPS64_GPR_NR] = {
28 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3",
29 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
30 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
31 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra",
32 };
33
34 /* Cacheability and Coherency Attribute */
35 static int cca_cache_status[8] = {
36 1, 1, 0, 1, 0, 1, 0, 0,
37 };
38
39 /* Get register index given its name */
40 int mips64_get_reg_index(char *name)
41 {
42 int i;
43
44 for(i=0;i<MIPS64_GPR_NR;i++)
45 if (!strcmp(mips64_gpr_reg_names[i],name))
46 return(i);
47
48 return(-1);
49 }
50
51 /* Get cacheability info */
52 int mips64_cca_cached(m_uint8_t val)
53 {
54 return(cca_cache_status[val & 0x03]);
55 }
56
57 /* Reset a MIPS64 CPU */
58 int mips64_reset(cpu_mips_t *cpu)
59 {
60 cpu->pc = MIPS_ROM_PC;
61 cpu->gpr[MIPS_GPR_SP] = MIPS_ROM_SP;
62 cpu->cp0.reg[MIPS_CP0_STATUS] = MIPS_CP0_STATUS_BEV;
63 cpu->cp0.reg[MIPS_CP0_CAUSE] = 0;
64 cpu->cp0.reg[MIPS_CP0_CONFIG] = 0x00c08ff0ULL;
65
66 /* Clear the complete TLB */
67 memset(&cpu->cp0.tlb,0,MIPS64_TLB_MAX_ENTRIES*sizeof(tlb_entry_t));
68
69 /* Restart the MTS subsystem */
70 mts_set_addr_mode(cpu,64);
71 cpu->mts_rebuild(cpu);
72
73 /* Flush JIT structures */
74 mips64_jit_flush(cpu,0);
75 return(0);
76 }
77
78 /* Initialize a MIPS64 processor */
79 int mips64_init(cpu_mips_t *cpu)
80 {
81 cpu->state = MIPS_CPU_SUSPENDED;
82 cpu->addr_bus_mask = 0xFFFFFFFFFFFFFFFFULL;
83 cpu->cp0.reg[MIPS_CP0_PRID] = MIPS_PRID_R4600;
84 cpu->cp0.tlb_entries = MIPS64_TLB_STD_ENTRIES;
85
86 /* Initialize idle timer */
87 cpu->idle_max = 1500;
88 cpu->idle_sleep_time = 30000;
89
90 /* Timer IRQ parameters (default frequency: 250 Hz <=> 4ms period) */
91 cpu->timer_irq_check_itv = 1000;
92 cpu->timer_irq_freq = 250;
93
94 /* Enable fast memory operations */
95 cpu->fast_memop = TRUE;
96
97 /* Create the IRQ lock (for non-jit architectures) */
98 pthread_mutex_init(&cpu->irq_lock,NULL);
99
100 /* Idle loop mutex and condition */
101 pthread_mutex_init(&cpu->idle_mutex,NULL);
102 pthread_cond_init(&cpu->idle_cond,NULL);
103
104 /* Set the startup parameters */
105 mips64_reset(cpu);
106 return(0);
107 }
108
109 /* Delete a MIPS64 processor */
110 void mips64_delete(cpu_mips_t *cpu)
111 {
112 if (cpu) {
113 mts_shutdown(cpu);
114 mips64_jit_shutdown(cpu);
115 free(cpu);
116 }
117 }
118
119 /* Set the CPU PRID register */
120 void mips64_set_prid(cpu_mips_t *cpu,m_uint32_t prid)
121 {
122 cpu->cp0.reg[MIPS_CP0_PRID] = prid;
123
124 if ((prid == MIPS_PRID_R7000) || (prid == MIPS_PRID_BCM1250))
125 cpu->cp0.tlb_entries = MIPS64_TLB_MAX_ENTRIES;
126 }
127
128 /* Virtual idle loop */
129 void mips64_idle_loop(cpu_mips_t *cpu)
130 {
131 struct timespec t_spc;
132 m_tmcnt_t expire;
133
134 expire = m_gettime_usec() + cpu->idle_sleep_time;
135
136 pthread_mutex_lock(&cpu->idle_mutex);
137 t_spc.tv_sec = expire / 1000000;
138 t_spc.tv_nsec = (expire % 1000000) * 1000;
139 pthread_cond_timedwait(&cpu->idle_cond,&cpu->idle_mutex,&t_spc);
140 pthread_mutex_unlock(&cpu->idle_mutex);
141 }
142
143 /* Break idle wait state */
144 void mips64_idle_break_wait(cpu_mips_t *cpu)
145 {
146 pthread_cond_signal(&cpu->idle_cond);
147 cpu->idle_count = 0;
148 }
149
150 /* Timer IRQ */
151 void *mips64_timer_irq_run(cpu_mips_t *cpu)
152 {
153 pthread_mutex_t umutex = PTHREAD_MUTEX_INITIALIZER;
154 pthread_cond_t ucond = PTHREAD_COND_INITIALIZER;
155 struct timespec t_spc;
156 m_tmcnt_t expire;
157 u_int interval;
158 u_int threshold;
159
160 interval = 1000000 / cpu->timer_irq_freq;
161 threshold = cpu->timer_irq_freq * 10;
162 expire = m_gettime_usec() + interval;
163
164 while(cpu->state != MIPS_CPU_HALTED) {
165 pthread_mutex_lock(&umutex);
166 t_spc.tv_sec = expire / 1000000;
167 t_spc.tv_nsec = (expire % 1000000) * 1000;
168 pthread_cond_timedwait(&ucond,&umutex,&t_spc);
169 pthread_mutex_unlock(&umutex);
170
171 if (likely(!cpu->irq_disable) &&
172 likely(cpu->state == MIPS_CPU_RUNNING))
173 {
174 cpu->timer_irq_pending++;
175
176 if (unlikely(cpu->timer_irq_pending > threshold)) {
177 cpu->timer_irq_pending = 0;
178 cpu->timer_drift++;
179 #if 0
180 printf("Timer IRQ not accurate (%u pending IRQ): "
181 "reduce the \"--timer-irq-check-itv\" parameter "
182 "(current value: %u)\n",
183 cpu->timer_irq_pending,cpu->timer_irq_check_itv);
184 #endif
185 }
186 }
187
188 expire += interval;
189 }
190
191 return NULL;
192 }
193
194 #define IDLE_HASH_SIZE 8192
195
196 /* Idle PC hash item */
197 struct mips64_idle_pc_hash {
198 m_uint64_t pc;
199 u_int count;
200 struct mips64_idle_pc_hash *next;
201 };
202
203 /* Determine an "idling" PC */
204 int mips64_get_idling_pc(cpu_mips_t *cpu)
205 {
206 struct mips64_idle_pc_hash **pc_hash,*p;
207 struct mips64_idle_pc *res;
208 u_int h_index,res_count;
209 m_uint64_t cur_pc;
210 int i;
211
212 cpu->idle_pc_prop_count = 0;
213
214 if (cpu->idle_pc != 0) {
215 printf("\nYou already use an idle PC, using the calibration would give "
216 "incorrect results.\n");
217 return(-1);
218 }
219
220 printf("\nPlease wait while gathering statistics...\n");
221
222 pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc *));
223
224 /* Disable IRQ */
225 cpu->irq_disable = TRUE;
226
227 /* Take 1000 measures, each mesure every 10ms */
228 for(i=0;i<1000;i++) {
229 cur_pc = cpu->pc;
230 h_index = (cur_pc >> 2) & (IDLE_HASH_SIZE-1);
231
232 for(p=pc_hash[h_index];p;p=p->next)
233 if (p->pc == cur_pc) {
234 p->count++;
235 break;
236 }
237
238 if (!p) {
239 if ((p = malloc(sizeof(*p)))) {
240 p->pc = cur_pc;
241 p->count = 1;
242 p->next = pc_hash[h_index];
243 pc_hash[h_index] = p;
244 }
245 }
246
247 usleep(10000);
248 }
249
250 /* Select PCs */
251 for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) {
252 for(p=pc_hash[i];p;p=p->next)
253 if ((p->count >= 20) && (p->count <= 80)) {
254 res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
255
256 res->pc = p->pc;
257 res->count = p->count;
258
259 if (cpu->idle_pc_prop_count >= MIPS64_IDLE_PC_MAX_RES)
260 goto done;
261 }
262 }
263
264 done:
265 /* Set idle PC */
266 if (cpu->idle_pc_prop_count) {
267 printf("Done. Suggested idling PC:\n");
268
269 for(i=0;i<cpu->idle_pc_prop_count;i++) {
270 printf(" 0x%llx (count=%u)\n",
271 cpu->idle_pc_prop[i].pc,
272 cpu->idle_pc_prop[i].count);
273 }
274
275 printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",
276 cpu->idle_pc_prop[0].pc);
277 } else {
278 printf("Done. No suggestion for idling PC\n");
279 }
280
281 /* Re-enable IRQ */
282 cpu->irq_disable = FALSE;
283 return(0);
284 }
285
286 /* Update the IRQ flag (inline) */
287 static forced_inline int mips64_update_irq_flag_fast(cpu_mips_t *cpu)
288 {
289 mips_cp0_t *cp0 = &cpu->cp0;
290 m_uint32_t imask,sreg_mask;
291 m_uint32_t cause;
292
293 cpu->irq_pending = FALSE;
294
295 cause = cp0->reg[MIPS_CP0_CAUSE] & ~MIPS_CP0_CAUSE_IMASK;
296 cp0->reg[MIPS_CP0_CAUSE] = cause | cpu->irq_cause;
297
298 sreg_mask = MIPS_CP0_STATUS_IE|MIPS_CP0_STATUS_EXL|MIPS_CP0_STATUS_ERL;
299
300 if ((cp0->reg[MIPS_CP0_STATUS] & sreg_mask) == MIPS_CP0_STATUS_IE) {
301 imask = cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_IMASK;
302 if (unlikely(cp0->reg[MIPS_CP0_CAUSE] & imask)) {
303 cpu->irq_pending = TRUE;
304 return(TRUE);
305 }
306 }
307
308 return(FALSE);
309 }
310
311 /* Update the IRQ flag */
312 void mips64_update_irq_flag(cpu_mips_t *cpu)
313 {
314 mips64_update_irq_flag_fast(cpu);
315 }
316
317 /* Generate an exception */
318 void mips64_trigger_exception(cpu_mips_t *cpu,u_int exc_code,int bd_slot)
319 {
320 mips_cp0_t *cp0 = &cpu->cp0;
321 m_uint64_t cause,vector;
322
323 /* we don't set EPC if EXL is set */
324 if (!(cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))
325 {
326 cp0->reg[MIPS_CP0_EPC] = cpu->pc;
327
328 /* keep IM, set exception code and bd slot */
329 cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;
330
331 if (bd_slot)
332 cause |= MIPS_CP0_CAUSE_BD_SLOT;
333 else
334 cause &= ~MIPS_CP0_CAUSE_BD_SLOT;
335
336 cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);
337 cp0->reg[MIPS_CP0_CAUSE] = cause;
338
339 /* XXX properly set vector */
340 vector = 0x180ULL;
341 }
342 else
343 {
344 /* keep IM and set exception code */
345 cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;
346 cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);
347 cp0->reg[MIPS_CP0_CAUSE] = cause;
348
349 /* set vector */
350 vector = 0x180ULL;
351 }
352
353 /* Set EXL bit in status register */
354 cp0->reg[MIPS_CP0_STATUS] |= MIPS_CP0_STATUS_EXL;
355
356 /* Use bootstrap vectors ? */
357 if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_BEV)
358 cpu->pc = 0xffffffffbfc00200ULL + vector;
359 else
360 cpu->pc = 0xffffffff80000000ULL + vector;
361
362 /* Clear the pending IRQ flag */
363 cpu->irq_pending = 0;
364 }
365
366 /*
367 * Increment count register and trigger the timer IRQ if value in compare
368 * register is the same.
369 */
370 fastcall void mips64_exec_inc_cp0_cnt(cpu_mips_t *cpu)
371 {
372 cpu->cp0_virt_cnt_reg++;
373
374 #if 0 /* TIMER_IRQ */
375 mips_cp0_t *cp0 = &cpu->cp0;
376
377 if (unlikely((cpu->cp0_virt_cnt_reg == cpu->cp0_virt_cmp_reg))) {
378 cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];
379 mips64_set_irq(cpu,7);
380 mips64_update_irq_flag_fast(cpu);
381 }
382 #endif
383 }
384
385 /* Trigger the Timer IRQ */
386 fastcall void mips64_trigger_timer_irq(cpu_mips_t *cpu)
387 {
388 mips_cp0_t *cp0 = &cpu->cp0;
389
390 cpu->timer_irq_count++;
391
392 cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];
393 mips64_set_irq(cpu,7);
394 mips64_update_irq_flag_fast(cpu);
395 }
396
397 /* Execute ERET instruction */
398 fastcall void mips64_exec_eret(cpu_mips_t *cpu)
399 {
400 mips_cp0_t *cp0 = &cpu->cp0;
401
402 if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_ERL) {
403 cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_ERL;
404 cpu->pc = cp0->reg[MIPS_CP0_ERR_EPC];
405 } else {
406 cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_EXL;
407 cpu->pc = cp0->reg[MIPS_CP0_EPC];
408 }
409
410 /* We have to clear the LLbit */
411 cpu->ll_bit = 0;
412
413 /* Update the pending IRQ flag */
414 mips64_update_irq_flag_fast(cpu);
415 }
416
417 /* Execute SYSCALL instruction */
418 fastcall void mips64_exec_syscall(cpu_mips_t *cpu)
419 {
420 #if DEBUG_SYSCALL
421 printf("MIPS64: SYSCALL at PC=0x%llx (RA=0x%llx)\n"
422 " a0=0x%llx, a1=0x%llx, a2=0x%llx, a3=0x%llx\n",
423 cpu->pc, cpu->gpr[MIPS_GPR_RA],
424 cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1],
425 cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]);
426 #endif
427
428 /* XXX TODO: Branch Delay slot */
429 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_SYSCALL,0);
430 }
431
432 /* Execute BREAK instruction */
433 fastcall void mips64_exec_break(cpu_mips_t *cpu,u_int code)
434 {
435 printf("MIPS64: BREAK instruction (code=%u)\n",code);
436 mips64_dump_regs(cpu);
437
438 /* XXX TODO: Branch Delay slot */
439 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_BP,0);
440 }
441
442 /* Trigger a Trap Exception */
443 fastcall void mips64_trigger_trap_exception(cpu_mips_t *cpu)
444 {
445 /* XXX TODO: Branch Delay slot */
446 printf("MIPS64: TRAP exception, CPU=%p\n",cpu);
447 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_TRAP,0);
448 }
449
450 /* Trigger IRQs */
451 fastcall void mips64_trigger_irq(cpu_mips_t *cpu)
452 {
453 if (unlikely(cpu->irq_disable)) {
454 cpu->irq_pending = 0;
455 return;
456 }
457
458 cpu->irq_count++;
459 if (mips64_update_irq_flag_fast(cpu))
460 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_INTERRUPT,0);
461 else
462 cpu->irq_fp_count++;
463 }
464
465 /* DMFC1 */
466 fastcall void mips64_exec_dmfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
467 {
468 cpu->gpr[gp_reg] = cpu->fpu.reg[cp1_reg];
469 }
470
471 /* DMTC1 */
472 fastcall void mips64_exec_dmtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
473 {
474 cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg];
475 }
476
477 /* MFC1 */
478 fastcall void mips64_exec_mfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
479 {
480 m_int64_t val;
481
482 val = cpu->fpu.reg[cp1_reg] & 0xffffffff;
483 cpu->gpr[gp_reg] = sign_extend(val,32);
484 }
485
486 /* MTC1 */
487 fastcall void mips64_exec_mtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
488 {
489 cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg] & 0xffffffff;
490 }
491
492 /* Virtual breakpoint */
493 fastcall void mips64_run_breakpoint(cpu_mips_t *cpu)
494 {
495 cpu_log(cpu,"BREAKPOINT",
496 "Virtual breakpoint reached at PC=0x%llx\n",cpu->pc);
497
498 printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",
499 cpu->pc,cpu->gpr[MIPS_GPR_RA]);
500
501 mips64_dump_regs(cpu);
502 memlog_dump(cpu);
503 }
504
505 /* Add a virtual breakpoint */
506 int mips64_add_breakpoint(cpu_mips_t *cpu,m_uint64_t pc)
507 {
508 int i;
509
510 for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
511 if (!cpu->breakpoints[i])
512 break;
513
514 if (i == MIPS64_MAX_BREAKPOINTS)
515 return(-1);
516
517 cpu->breakpoints[i] = pc;
518 cpu->breakpoints_enabled = TRUE;
519 return(0);
520 }
521
522 /* Remove a virtual breakpoint */
523 void mips64_remove_breakpoint(cpu_mips_t *cpu,m_uint64_t pc)
524 {
525 int i,j;
526
527 for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
528 if (cpu->breakpoints[i] == pc)
529 {
530 for(j=i;j<MIPS64_MAX_BREAKPOINTS-1;j++)
531 cpu->breakpoints[j] = cpu->breakpoints[j+1];
532
533 cpu->breakpoints[MIPS64_MAX_BREAKPOINTS-1] = 0;
534 }
535
536 for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
537 if (cpu->breakpoints[i] != 0)
538 return;
539
540 cpu->breakpoints_enabled = TRUE;
541 }
542
543 /* Debugging for register-jump to address 0 */
544 fastcall void mips64_debug_jr0(cpu_mips_t *cpu)
545 {
546 printf("MIPS64: cpu %p jumping to address 0...\n",cpu);
547 mips64_dump_regs(cpu);
548 }
549
550 /* Dump registers of a MIPS64 processor */
551 void mips64_dump_regs(cpu_mips_t *cpu)
552 {
553 mips_insn_t *ptr,insn;
554 char buffer[80];
555 int i;
556
557 printf("MIPS64 Registers:\n");
558
559 for(i=0;i<MIPS64_GPR_NR/2;i++) {
560 printf(" %s ($%2d) = 0x%16.16llx %s ($%2d) = 0x%16.16llx\n",
561 mips64_gpr_reg_names[i*2], i*2, cpu->gpr[i*2],
562 mips64_gpr_reg_names[(i*2)+1], (i*2)+1, cpu->gpr[(i*2)+1]);
563 }
564
565 printf(" lo = 0x%16.16llx, hi = 0x%16.16llx\n", cpu->lo, cpu->hi);
566 printf(" pc = 0x%16.16llx, ll_bit = %u\n", cpu->pc, cpu->ll_bit);
567
568 /* Fetch the current instruction */
569 ptr = cpu->mem_op_lookup(cpu,cpu->pc);
570 if (ptr) {
571 insn = vmtoh32(*ptr);
572
573 if (mips64_dump_insn(buffer,sizeof(buffer),1,cpu->pc,insn) != -1)
574 printf(" Instruction: %s\n",buffer);
575 }
576
577 printf("\nCP0 Registers:\n");
578
579 for(i=0;i<MIPS64_CP0_REG_NR/2;i++) {
580 printf(" %-10s ($%2d) = 0x%16.16llx %-10s ($%2d) = 0x%16.16llx\n",
581 mips64_cp0_reg_names[i*2], i*2, cp0_get_reg(cpu,i*2),
582 mips64_cp0_reg_names[(i*2)+1], (i*2)+1, cp0_get_reg(cpu,(i*2)+1));
583 }
584
585 printf("\n IRQ count: %llu, IRQ false positives: %llu, "
586 "IRQ Pending: %u\n",
587 cpu->irq_count,cpu->irq_fp_count,cpu->irq_pending);
588
589 printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n",
590 cpu->timer_irq_count,cpu->timer_irq_pending,cpu->timer_drift);
591
592 printf("\n");
593 }
594
595 /* Dump a memory block */
596 void mips64_dump_memory(cpu_mips_t *cpu,m_uint64_t vaddr,u_int count)
597 {
598 void *haddr;
599 u_int i;
600
601 for(i=0;i<count;i++,vaddr+=4)
602 {
603 if ((i & 3) == 0)
604 printf("\n 0x%16.16llx: ",vaddr);
605
606 haddr = cpu->mem_op_lookup(cpu,vaddr);
607
608 if (haddr)
609 printf("0x%8.8x ",htovm32(*(m_uint32_t *)haddr));
610 else
611 printf("XXXXXXXXXX ");
612 }
613
614 printf("\n\n");
615 }
616
617 /* Dump the stack */
618 void mips64_dump_stack(cpu_mips_t *cpu,u_int count)
619 {
620 printf("MIPS Stack Dump at 0x%16.16llx:",cpu->gpr[MIPS_GPR_SP]);
621 mips64_dump_memory(cpu,cpu->gpr[MIPS_GPR_SP],count);
622 }
623
624 /* Save the CPU state into a file */
625 int mips64_save_state(cpu_mips_t *cpu,char *filename)
626 {
627 FILE *fd;
628 int i;
629
630 if (!(fd = fopen(filename,"w"))) {
631 perror("mips64_save_state: fopen");
632 return(-1);
633 }
634
635 /* pc, lo and hi */
636 fprintf(fd,"pc: %16.16llx\n",cpu->pc);
637 fprintf(fd,"lo: %16.16llx\n",cpu->lo);
638 fprintf(fd,"hi: %16.16llx\n",cpu->hi);
639
640 /* general purpose registers */
641 for(i=0;i<MIPS64_GPR_NR;i++)
642 fprintf(fd,"%s: %16.16llx\n",
643 mips64_gpr_reg_names[i],cpu->gpr[i]);
644
645 printf("\n");
646
647 /* cp0 registers */
648 for(i=0;i<MIPS64_CP0_REG_NR;i++)
649 fprintf(fd,"%s: %16.16llx\n",
650 mips64_cp0_reg_names[i],cpu->cp0.reg[i]);
651
652 printf("\n");
653
654 /* cp1 registers */
655 for(i=0;i<MIPS64_CP1_REG_NR;i++)
656 fprintf(fd,"fpu%d: %16.16llx\n",i,cpu->fpu.reg[i]);
657
658 printf("\n");
659
660 /* tlb entries */
661 for(i=0;i<cpu->cp0.tlb_entries;i++) {
662 fprintf(fd,"tlb%d_mask: %16.16llx\n",i,cpu->cp0.tlb[i].mask);
663 fprintf(fd,"tlb%d_hi: %16.16llx\n",i,cpu->cp0.tlb[i].hi);
664 fprintf(fd,"tlb%d_lo0: %16.16llx\n",i,cpu->cp0.tlb[i].lo0);
665 fprintf(fd,"tlb%d_lo1: %16.16llx\n",i,cpu->cp0.tlb[i].lo1);
666 }
667
668 fclose(fd);
669 return(0);
670 }
671
672 /* Read a 64-bit unsigned integer */
673 static m_uint64_t mips64_hex_u64(char *str,int *err)
674 {
675 m_uint64_t res = 0;
676 u_char c;
677
678 /* remove leading spaces */
679 while((*str == ' ') || (*str == '\t'))
680 str++;
681
682 while(*str) {
683 c = *str;
684
685 if ((c >= '0') && (c <= '9'))
686 res = (res << 4) + (c - '0');
687
688 if ((c >= 'a') && (c <= 'f'))
689 res = (res << 4) + ((c - 'a') + 10);
690
691 if ((c >= 'A') && (c <= 'F'))
692 res = (res << 4) + ((c - 'A') + 10);
693
694 str++;
695 }
696
697 return(res);
698 }
699
700 /* Restore the CPU state from a file */
701 int mips64_restore_state(cpu_mips_t *cpu,char *filename)
702 {
703 char buffer[4096],*sep,*value,*ep,*field;
704 size_t len;
705 FILE *fd;
706 int index;
707
708 if (!(fd = fopen(filename,"r"))) {
709 perror("mips64_restore_state: fopen");
710 return(-1);
711 }
712
713 while(!feof(fd))
714 {
715 *buffer = 0;
716 fgets(buffer,sizeof(buffer),fd);
717 len = strlen(buffer);
718
719 if (buffer[len-1] == '\n')
720 buffer[len-1] = 0;
721
722 sep = strchr(buffer,':');
723 if (!sep) continue;
724
725 value = sep + 1;
726 *sep = 0;
727
728 /* gpr ? */
729 if ((index = mips64_get_reg_index(buffer)) != -1) {
730 cpu->gpr[index] = mips64_hex_u64(value,NULL);
731 continue;
732 }
733
734 /* cp0 register ? */
735 if ((index = cp0_get_reg_index(buffer)) != -1) {
736 cpu->cp0.reg[index] = mips64_hex_u64(value,NULL);
737 continue;
738 }
739
740 /* cp1 register ? */
741 if ((len > 3) && (!strncmp(buffer,"fpu",3))) {
742 index = atoi(buffer+3);
743 cpu->fpu.reg[index] = mips64_hex_u64(value,NULL);
744 }
745
746 /* tlb entry ? */
747 if ((len > 3) && (!strncmp(buffer,"tlb",3))) {
748 ep = strchr(buffer,'_');
749
750 if (ep) {
751 index = atoi(buffer+3);
752 field = ep + 1;
753
754 if (!strcmp(field,"mask")) {
755 cpu->cp0.tlb[index].mask = mips64_hex_u64(value,NULL);
756 continue;
757 }
758
759 if (!strcmp(field,"hi")) {
760 cpu->cp0.tlb[index].hi = mips64_hex_u64(value,NULL);
761 continue;
762 }
763
764 if (!strcmp(field,"lo0")) {
765 cpu->cp0.tlb[index].lo0 = mips64_hex_u64(value,NULL);
766 continue;
767 }
768
769 if (!strcmp(field,"lo1")) {
770 cpu->cp0.tlb[index].lo1 = mips64_hex_u64(value,NULL);
771 continue;
772 }
773 }
774 }
775
776 /* pc, lo, hi ? */
777 if (!strcmp(buffer,"pc")) {
778 cpu->pc = mips64_hex_u64(value,NULL);
779 continue;
780 }
781
782 if (!strcmp(buffer,"lo")) {
783 cpu->lo = mips64_hex_u64(value,NULL);
784 continue;
785 }
786
787 if (!strcmp(buffer,"hi")) {
788 cpu->hi = mips64_hex_u64(value,NULL);
789 continue;
790 }
791 }
792
793 cp0_map_all_tlb_to_mts(cpu);
794
795 mips64_dump_regs(cpu);
796 tlb_dump(cpu);
797
798 fclose(fd);
799 return(0);
800 }
801
802 /* Load a raw image into the simulated memory */
803 int mips64_load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr)
804 {
805 struct stat file_info;
806 size_t len,clen;
807 void *haddr;
808 FILE *bfd;
809
810 if (!(bfd = fopen(filename,"r"))) {
811 perror("fopen");
812 return(-1);
813 }
814
815 if (fstat(fileno(bfd),&file_info) == -1) {
816 perror("stat");
817 return(-1);
818 }
819
820 len = file_info.st_size;
821
822 printf("Loading RAW file '%s' at virtual address 0x%llx (size=%lu)\n",
823 filename,vaddr,(u_long)len);
824
825 while(len > 0)
826 {
827 haddr = cpu->mem_op_lookup(cpu,vaddr);
828
829 if (!haddr) {
830 fprintf(stderr,"load_raw_image: invalid load address 0x%llx\n",
831 vaddr);
832 return(-1);
833 }
834
835 if (len > MIPS_MIN_PAGE_SIZE)
836 clen = MIPS_MIN_PAGE_SIZE;
837 else
838 clen = len;
839
840 if (fread((u_char *)haddr,clen,1,bfd) != 1)
841 break;
842
843 vaddr += MIPS_MIN_PAGE_SIZE;
844 len -= clen;
845 }
846
847 fclose(bfd);
848 return(0);
849 }
850
851 /* Load an ELF image into the simulated memory */
852 int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load,
853 m_uint32_t *entry_point)
854 {
855 m_uint64_t vaddr;
856 void *haddr;
857 Elf32_Ehdr *ehdr;
858 Elf32_Shdr *shdr;
859 Elf_Scn *scn;
860 Elf *img_elf;
861 size_t len,clen;
862 char *name;
863 int i,fd;
864 FILE *bfd;
865
866 if (!filename)
867 return(-1);
868
869 #ifdef __CYGWIN__
870 fd = open(filename,O_RDONLY|O_BINARY);
871 #else
872 fd = open(filename,O_RDONLY);
873 #endif
874
875 if (fd == -1) {
876 perror("load_elf_image: open");
877 return(-1);
878 }
879
880 if (elf_version(EV_CURRENT) == EV_NONE) {
881 fprintf(stderr,"load_elf_image: library out of date\n");
882 return(-1);
883 }
884
885 if (!(img_elf = elf_begin(fd,ELF_C_READ,NULL))) {
886 fprintf(stderr,"load_elf_image: elf_begin: %s\n",
887 elf_errmsg(elf_errno()));
888 return(-1);
889 }
890
891 if (!(ehdr = elf32_getehdr(img_elf))) {
892 fprintf(stderr,"load_elf_image: invalid ELF file\n");
893 return(-1);
894 }
895
896 printf("Loading ELF file '%s'...\n",filename);
897 bfd = fdopen(fd,"rb");
898
899 if (!bfd) {
900 perror("load_elf_image: fdopen");
901 return(-1);
902 }
903
904 if (!skip_load) {
905 for(i=0;i<ehdr->e_shnum;i++) {
906 scn = elf_getscn(img_elf,i);
907
908 shdr = elf32_getshdr(scn);
909 name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
910 len = shdr->sh_size;
911
912 if (!(shdr->sh_flags & SHF_ALLOC) || !len)
913 continue;
914
915 fseek(bfd,shdr->sh_offset,SEEK_SET);
916 vaddr = sign_extend(shdr->sh_addr,32);
917
918 if (cpu->vm->debug_level > 0) {
919 printf(" * Adding section at virtual address 0x%8.8llx "
920 "(len=0x%8.8lx)\n",vaddr & 0xFFFFFFFF,(u_long)len);
921 }
922
923 while(len > 0)
924 {
925 haddr = cpu->mem_op_lookup(cpu,vaddr);
926
927 if (!haddr) {
928 fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n",
929 vaddr);
930 return(-1);
931 }
932
933 if (len > MIPS_MIN_PAGE_SIZE)
934 clen = MIPS_MIN_PAGE_SIZE;
935 else
936 clen = len;
937
938 clen = fread((u_char *)haddr,clen,1,bfd);
939
940 if (clen != 1)
941 break;
942
943 vaddr += MIPS_MIN_PAGE_SIZE;
944 len -= clen;
945 }
946 }
947 } else {
948 printf("ELF loading skipped, using a ghost RAM file.\n");
949 }
950
951 printf("ELF entry point: 0x%x\n",ehdr->e_entry);
952
953 if (entry_point)
954 *entry_point = ehdr->e_entry;
955
956 elf_end(img_elf);
957 fclose(bfd);
958 return(0);
959 }
960
961 /* Symbol lookup */
962 struct symbol *mips64_sym_lookup(cpu_mips_t *cpu,m_uint64_t addr)
963 {
964 return(rbtree_lookup(cpu->sym_tree,&addr));
965 }
966
967 /* Insert a new symbol */
968 struct symbol *mips64_sym_insert(cpu_mips_t *cpu,char *name,m_uint64_t addr)
969 {
970 struct symbol *sym;
971 size_t len;
972
973 if (!cpu->sym_tree)
974 return NULL;
975
976 len = strlen(name);
977
978 if (!(sym = malloc(len+1+sizeof(*sym))))
979 return NULL;
980
981 memcpy(sym->name,name,len+1);
982 sym->addr = addr;
983
984 if (rbtree_insert(cpu->sym_tree,sym,sym) == -1) {
985 free(sym);
986 return NULL;
987 }
988
989 return sym;
990 }
991
992 /* Symbol comparison function */
993 static int mips64_sym_compare(m_uint64_t *a1,struct symbol *sym)
994 {
995 if (*a1 > sym->addr)
996 return(1);
997
998 if (*a1 < sym->addr)
999 return(-1);
1000
1001 return(0);
1002 }
1003
1004 /* Create the symbol tree */
1005 int mips64_sym_create_tree(cpu_mips_t *cpu)
1006 {
1007 cpu->sym_tree = rbtree_create((tree_fcompare)mips64_sym_compare,NULL);
1008 return(cpu->sym_tree ? 0 : -1);
1009 }
1010
1011 /* Load a symbol file */
1012 int mips64_sym_load_file(cpu_mips_t *cpu,char *filename)
1013 {
1014 char buffer[4096],func_name[128];
1015 m_uint64_t addr;
1016 char sym_type;
1017 FILE *fd;
1018
1019 if (!cpu->sym_tree && (mips64_sym_create_tree(cpu) == -1)) {
1020 fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->id);
1021 return(-1);
1022 }
1023
1024 if (!(fd = fopen(filename,"r"))) {
1025 perror("load_sym_file: fopen");
1026 return(-1);
1027 }
1028
1029 while(!feof(fd)) {
1030 fgets(buffer,sizeof(buffer),fd);
1031
1032 if (sscanf(buffer,"%llx %c %s",&addr,&sym_type,func_name) == 3) {
1033 mips64_sym_insert(cpu,func_name,addr);
1034 }
1035 }
1036
1037 fclose(fd);
1038 return(0);
1039 }

  ViewVC Help
Powered by ViewVC 1.1.26