/[dynamips]/trunk/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 /trunk/mips64.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Sat Oct 6 16:06:49 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC3/mips64.c
File MIME type: text/plain
File size: 25242 byte(s)
dynamips-0.2.6-RC3

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 dpavlin 4 mts_set_addr_mode(cpu,64);
71 dpavlin 1 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 dpavlin 4 cpu->idle_sleep_time = 30000;
89 dpavlin 1
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 dpavlin 3 cpu->idle_count = 0;
148 dpavlin 1 }
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 dpavlin 3 #define IDLE_HASH_SIZE 8192
195    
196 dpavlin 1 /* Idle PC hash item */
197 dpavlin 3 struct mips64_idle_pc_hash {
198 dpavlin 1 m_uint64_t pc;
199     u_int count;
200 dpavlin 3 struct mips64_idle_pc_hash *next;
201 dpavlin 1 };
202    
203     /* Determine an "idling" PC */
204     int mips64_get_idling_pc(cpu_mips_t *cpu)
205     {
206 dpavlin 3 struct mips64_idle_pc_hash **pc_hash,*p;
207     struct mips64_idle_pc *res;
208 dpavlin 1 u_int h_index,res_count;
209     m_uint64_t cur_pc;
210     int i;
211    
212 dpavlin 3 cpu->idle_pc_prop_count = 0;
213    
214 dpavlin 1 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 dpavlin 3 res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
255 dpavlin 1
256 dpavlin 3 res->pc = p->pc;
257     res->count = p->count;
258    
259     if (cpu->idle_pc_prop_count >= MIPS64_IDLE_PC_MAX_RES)
260 dpavlin 1 goto done;
261     }
262     }
263    
264     done:
265     /* Set idle PC */
266 dpavlin 3 if (cpu->idle_pc_prop_count) {
267 dpavlin 1 printf("Done. Suggested idling PC:\n");
268    
269 dpavlin 3 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 dpavlin 1 printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",
276 dpavlin 3 cpu->idle_pc_prop[0].pc);
277 dpavlin 1 } 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 dpavlin 2 printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",
499     cpu->pc,cpu->gpr[MIPS_GPR_RA]);
500    
501 dpavlin 1 mips64_dump_regs(cpu);
502     memlog_dump(cpu);
503     }
504    
505 dpavlin 2 /* 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 dpavlin 1 /* 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 dpavlin 4 int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load,
853 dpavlin 1 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 dpavlin 4 if (!skip_load) {
905     for(i=0;i<ehdr->e_shnum;i++) {
906     scn = elf_getscn(img_elf,i);
907 dpavlin 1
908 dpavlin 4 shdr = elf32_getshdr(scn);
909     name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
910     len = shdr->sh_size;
911 dpavlin 1
912 dpavlin 4 if (!(shdr->sh_flags & SHF_ALLOC) || !len)
913     continue;
914 dpavlin 1
915 dpavlin 4 fseek(bfd,shdr->sh_offset,SEEK_SET);
916     vaddr = sign_extend(shdr->sh_addr,32);
917 dpavlin 1
918 dpavlin 4 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 dpavlin 1
927 dpavlin 4 if (!haddr) {
928     fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n",
929     vaddr);
930     return(-1);
931     }
932 dpavlin 1
933 dpavlin 4 if (len > MIPS_MIN_PAGE_SIZE)
934     clen = MIPS_MIN_PAGE_SIZE;
935     else
936     clen = len;
937 dpavlin 1
938 dpavlin 4 clen = fread((u_char *)haddr,clen,1,bfd);
939 dpavlin 1
940 dpavlin 4 if (clen != 1)
941     break;
942 dpavlin 1
943 dpavlin 4 vaddr += MIPS_MIN_PAGE_SIZE;
944     len -= clen;
945     }
946 dpavlin 1 }
947 dpavlin 4 } else {
948     printf("ELF loading skipped, using a ghost RAM file.\n");
949 dpavlin 1 }
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