/[dynamips]/upstream/dynamips-0.2.6-RC1/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

Annotation of /upstream/dynamips-0.2.6-RC1/mips64.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations)
Sat Oct 6 16:03:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24831 byte(s)
import dynamips-0.2.6-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26