/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Sat Oct 6 16:05:34 2007 UTC (13 years ago) by dpavlin
Original Path: upstream/dynamips-0.2.6-RC2/mips64.c
File MIME type: text/plain
File size: 25065 byte(s)
dynamips-0.2.6-RC2

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 dpavlin 3 cpu->idle_count = 0;
150 dpavlin 1 }
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 dpavlin 3 #define IDLE_HASH_SIZE 8192
197    
198 dpavlin 1 /* Idle PC hash item */
199 dpavlin 3 struct mips64_idle_pc_hash {
200 dpavlin 1 m_uint64_t pc;
201     u_int count;
202 dpavlin 3 struct mips64_idle_pc_hash *next;
203 dpavlin 1 };
204    
205     /* Determine an "idling" PC */
206     int mips64_get_idling_pc(cpu_mips_t *cpu)
207     {
208 dpavlin 3 struct mips64_idle_pc_hash **pc_hash,*p;
209     struct mips64_idle_pc *res;
210 dpavlin 1 u_int h_index,res_count;
211     m_uint64_t cur_pc;
212     int i;
213    
214 dpavlin 3 cpu->idle_pc_prop_count = 0;
215    
216 dpavlin 1 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 dpavlin 3 res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
257 dpavlin 1
258 dpavlin 3 res->pc = p->pc;
259     res->count = p->count;
260    
261     if (cpu->idle_pc_prop_count >= MIPS64_IDLE_PC_MAX_RES)
262 dpavlin 1 goto done;
263     }
264     }
265    
266     done:
267     /* Set idle PC */
268 dpavlin 3 if (cpu->idle_pc_prop_count) {
269 dpavlin 1 printf("Done. Suggested idling PC:\n");
270    
271 dpavlin 3 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 dpavlin 1 printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",
278 dpavlin 3 cpu->idle_pc_prop[0].pc);
279 dpavlin 1 } 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 dpavlin 2 printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",
501     cpu->pc,cpu->gpr[MIPS_GPR_RA]);
502    
503 dpavlin 1 mips64_dump_regs(cpu);
504     memlog_dump(cpu);
505     }
506    
507 dpavlin 2 /* 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 dpavlin 1 /* 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