/[dynamips]/upstream/dynamips-0.2.6-RC2/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-RC2/mips64.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Sat Oct 6 16:05:34 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 25065 byte(s)
dynamips-0.2.6-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26