/[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 1 - (hide annotations)
Sat Oct 6 16:01:44 2007 UTC (13 years ago) by dpavlin
Original Path: upstream/dynamips-0.2.5/mips64.c
File MIME type: text/plain
File size: 23957 byte(s)
import 0.2.5 from upstream

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     printf("[[[ Virtual Breakpoint reached at PC=0x%llx ]]]\n",cpu->pc);
495     mips64_dump_regs(cpu);
496     memlog_dump(cpu);
497     }
498    
499     /* Debugging for register-jump to address 0 */
500     fastcall void mips64_debug_jr0(cpu_mips_t *cpu)
501     {
502     printf("MIPS64: cpu %p jumping to address 0...\n",cpu);
503     mips64_dump_regs(cpu);
504     }
505    
506     /* Dump registers of a MIPS64 processor */
507     void mips64_dump_regs(cpu_mips_t *cpu)
508     {
509     mips_insn_t *ptr,insn;
510     char buffer[80];
511     int i;
512    
513     printf("MIPS64 Registers:\n");
514    
515     for(i=0;i<MIPS64_GPR_NR/2;i++) {
516     printf(" %s ($%2d) = 0x%16.16llx %s ($%2d) = 0x%16.16llx\n",
517     mips64_gpr_reg_names[i*2], i*2, cpu->gpr[i*2],
518     mips64_gpr_reg_names[(i*2)+1], (i*2)+1, cpu->gpr[(i*2)+1]);
519     }
520    
521     printf(" lo = 0x%16.16llx, hi = 0x%16.16llx\n", cpu->lo, cpu->hi);
522     printf(" pc = 0x%16.16llx, ll_bit = %u\n", cpu->pc, cpu->ll_bit);
523    
524     /* Fetch the current instruction */
525     ptr = cpu->mem_op_lookup(cpu,cpu->pc);
526     if (ptr) {
527     insn = vmtoh32(*ptr);
528    
529     if (mips64_dump_insn(buffer,sizeof(buffer),1,cpu->pc,insn) != -1)
530     printf(" Instruction: %s\n",buffer);
531     }
532    
533     printf("\nCP0 Registers:\n");
534    
535     for(i=0;i<MIPS64_CP0_REG_NR/2;i++) {
536     printf(" %-10s ($%2d) = 0x%16.16llx %-10s ($%2d) = 0x%16.16llx\n",
537     mips64_cp0_reg_names[i*2], i*2, cp0_get_reg(cpu,i*2),
538     mips64_cp0_reg_names[(i*2)+1], (i*2)+1, cp0_get_reg(cpu,(i*2)+1));
539     }
540    
541     printf("\n IRQ count: %llu, IRQ false positives: %llu, "
542     "IRQ Pending: %u\n",
543     cpu->irq_count,cpu->irq_fp_count,cpu->irq_pending);
544    
545     printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n",
546     cpu->timer_irq_count,cpu->timer_irq_pending,cpu->timer_drift);
547    
548     printf("\n");
549     }
550    
551     /* Dump a memory block */
552     void mips64_dump_memory(cpu_mips_t *cpu,m_uint64_t vaddr,u_int count)
553     {
554     void *haddr;
555     u_int i;
556    
557     for(i=0;i<count;i++,vaddr+=4)
558     {
559     if ((i & 3) == 0)
560     printf("\n 0x%16.16llx: ",vaddr);
561    
562     haddr = cpu->mem_op_lookup(cpu,vaddr);
563    
564     if (haddr)
565     printf("0x%8.8x ",htovm32(*(m_uint32_t *)haddr));
566     else
567     printf("XXXXXXXXXX ");
568     }
569    
570     printf("\n\n");
571     }
572    
573     /* Dump the stack */
574     void mips64_dump_stack(cpu_mips_t *cpu,u_int count)
575     {
576     printf("MIPS Stack Dump at 0x%16.16llx:",cpu->gpr[MIPS_GPR_SP]);
577     mips64_dump_memory(cpu,cpu->gpr[MIPS_GPR_SP],count);
578     }
579    
580     /* Save the CPU state into a file */
581     int mips64_save_state(cpu_mips_t *cpu,char *filename)
582     {
583     FILE *fd;
584     int i;
585    
586     if (!(fd = fopen(filename,"w"))) {
587     perror("mips64_save_state: fopen");
588     return(-1);
589     }
590    
591     /* pc, lo and hi */
592     fprintf(fd,"pc: %16.16llx\n",cpu->pc);
593     fprintf(fd,"lo: %16.16llx\n",cpu->lo);
594     fprintf(fd,"hi: %16.16llx\n",cpu->hi);
595    
596     /* general purpose registers */
597     for(i=0;i<MIPS64_GPR_NR;i++)
598     fprintf(fd,"%s: %16.16llx\n",
599     mips64_gpr_reg_names[i],cpu->gpr[i]);
600    
601     printf("\n");
602    
603     /* cp0 registers */
604     for(i=0;i<MIPS64_CP0_REG_NR;i++)
605     fprintf(fd,"%s: %16.16llx\n",
606     mips64_cp0_reg_names[i],cpu->cp0.reg[i]);
607    
608     printf("\n");
609    
610     /* cp1 registers */
611     for(i=0;i<MIPS64_CP1_REG_NR;i++)
612     fprintf(fd,"fpu%d: %16.16llx\n",i,cpu->fpu.reg[i]);
613    
614     printf("\n");
615    
616     /* tlb entries */
617     for(i=0;i<cpu->cp0.tlb_entries;i++) {
618     fprintf(fd,"tlb%d_mask: %16.16llx\n",i,cpu->cp0.tlb[i].mask);
619     fprintf(fd,"tlb%d_hi: %16.16llx\n",i,cpu->cp0.tlb[i].hi);
620     fprintf(fd,"tlb%d_lo0: %16.16llx\n",i,cpu->cp0.tlb[i].lo0);
621     fprintf(fd,"tlb%d_lo1: %16.16llx\n",i,cpu->cp0.tlb[i].lo1);
622     }
623    
624     fclose(fd);
625     return(0);
626     }
627    
628     /* Read a 64-bit unsigned integer */
629     static m_uint64_t mips64_hex_u64(char *str,int *err)
630     {
631     m_uint64_t res = 0;
632     u_char c;
633    
634     /* remove leading spaces */
635     while((*str == ' ') || (*str == '\t'))
636     str++;
637    
638     while(*str) {
639     c = *str;
640    
641     if ((c >= '0') && (c <= '9'))
642     res = (res << 4) + (c - '0');
643    
644     if ((c >= 'a') && (c <= 'f'))
645     res = (res << 4) + ((c - 'a') + 10);
646    
647     if ((c >= 'A') && (c <= 'F'))
648     res = (res << 4) + ((c - 'A') + 10);
649    
650     str++;
651     }
652    
653     return(res);
654     }
655    
656     /* Restore the CPU state from a file */
657     int mips64_restore_state(cpu_mips_t *cpu,char *filename)
658     {
659     char buffer[4096],*sep,*value,*ep,*field;
660     size_t len;
661     FILE *fd;
662     int index;
663    
664     if (!(fd = fopen(filename,"r"))) {
665     perror("mips64_restore_state: fopen");
666     return(-1);
667     }
668    
669     while(!feof(fd))
670     {
671     *buffer = 0;
672     fgets(buffer,sizeof(buffer),fd);
673     len = strlen(buffer);
674    
675     if (buffer[len-1] == '\n')
676     buffer[len-1] = 0;
677    
678     sep = strchr(buffer,':');
679     if (!sep) continue;
680    
681     value = sep + 1;
682     *sep = 0;
683    
684     /* gpr ? */
685     if ((index = mips64_get_reg_index(buffer)) != -1) {
686     cpu->gpr[index] = mips64_hex_u64(value,NULL);
687     continue;
688     }
689    
690     /* cp0 register ? */
691     if ((index = cp0_get_reg_index(buffer)) != -1) {
692     cpu->cp0.reg[index] = mips64_hex_u64(value,NULL);
693     continue;
694     }
695    
696     /* cp1 register ? */
697     if ((len > 3) && (!strncmp(buffer,"fpu",3))) {
698     index = atoi(buffer+3);
699     cpu->fpu.reg[index] = mips64_hex_u64(value,NULL);
700     }
701    
702     /* tlb entry ? */
703     if ((len > 3) && (!strncmp(buffer,"tlb",3))) {
704     ep = strchr(buffer,'_');
705    
706     if (ep) {
707     index = atoi(buffer+3);
708     field = ep + 1;
709    
710     if (!strcmp(field,"mask")) {
711     cpu->cp0.tlb[index].mask = mips64_hex_u64(value,NULL);
712     continue;
713     }
714    
715     if (!strcmp(field,"hi")) {
716     cpu->cp0.tlb[index].hi = mips64_hex_u64(value,NULL);
717     continue;
718     }
719    
720     if (!strcmp(field,"lo0")) {
721     cpu->cp0.tlb[index].lo0 = mips64_hex_u64(value,NULL);
722     continue;
723     }
724    
725     if (!strcmp(field,"lo1")) {
726     cpu->cp0.tlb[index].lo1 = mips64_hex_u64(value,NULL);
727     continue;
728     }
729     }
730     }
731    
732     /* pc, lo, hi ? */
733     if (!strcmp(buffer,"pc")) {
734     cpu->pc = mips64_hex_u64(value,NULL);
735     continue;
736     }
737    
738     if (!strcmp(buffer,"lo")) {
739     cpu->lo = mips64_hex_u64(value,NULL);
740     continue;
741     }
742    
743     if (!strcmp(buffer,"hi")) {
744     cpu->hi = mips64_hex_u64(value,NULL);
745     continue;
746     }
747     }
748    
749     cp0_map_all_tlb_to_mts(cpu);
750    
751     mips64_dump_regs(cpu);
752     tlb_dump(cpu);
753    
754     fclose(fd);
755     return(0);
756     }
757    
758     /* Load a raw image into the simulated memory */
759     int mips64_load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr)
760     {
761     struct stat file_info;
762     size_t len,clen;
763     void *haddr;
764     FILE *bfd;
765    
766     if (!(bfd = fopen(filename,"r"))) {
767     perror("fopen");
768     return(-1);
769     }
770    
771     if (fstat(fileno(bfd),&file_info) == -1) {
772     perror("stat");
773     return(-1);
774     }
775    
776     len = file_info.st_size;
777    
778     printf("Loading RAW file '%s' at virtual address 0x%llx (size=%lu)\n",
779     filename,vaddr,(u_long)len);
780    
781     while(len > 0)
782     {
783     haddr = cpu->mem_op_lookup(cpu,vaddr);
784    
785     if (!haddr) {
786     fprintf(stderr,"load_raw_image: invalid load address 0x%llx\n",
787     vaddr);
788     return(-1);
789     }
790    
791     if (len > MIPS_MIN_PAGE_SIZE)
792     clen = MIPS_MIN_PAGE_SIZE;
793     else
794     clen = len;
795    
796     if (fread((u_char *)haddr,clen,1,bfd) != 1)
797     break;
798    
799     vaddr += MIPS_MIN_PAGE_SIZE;
800     len -= clen;
801     }
802    
803     fclose(bfd);
804     return(0);
805     }
806    
807     /* Load an ELF image into the simulated memory */
808     int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,
809     m_uint32_t *entry_point)
810     {
811     m_uint64_t vaddr;
812     void *haddr;
813     Elf32_Ehdr *ehdr;
814     Elf32_Shdr *shdr;
815     Elf_Scn *scn;
816     Elf *img_elf;
817     size_t len,clen;
818     char *name;
819     int i,fd;
820     FILE *bfd;
821    
822     if (!filename)
823     return(-1);
824    
825     #ifdef __CYGWIN__
826     fd = open(filename,O_RDONLY|O_BINARY);
827     #else
828     fd = open(filename,O_RDONLY);
829     #endif
830    
831     if (fd == -1) {
832     perror("load_elf_image: open");
833     return(-1);
834     }
835    
836     if (elf_version(EV_CURRENT) == EV_NONE) {
837     fprintf(stderr,"load_elf_image: library out of date\n");
838     return(-1);
839     }
840    
841     if (!(img_elf = elf_begin(fd,ELF_C_READ,NULL))) {
842     fprintf(stderr,"load_elf_image: elf_begin: %s\n",
843     elf_errmsg(elf_errno()));
844     return(-1);
845     }
846    
847     if (!(ehdr = elf32_getehdr(img_elf))) {
848     fprintf(stderr,"load_elf_image: invalid ELF file\n");
849     return(-1);
850     }
851    
852     printf("Loading ELF file '%s'...\n",filename);
853     bfd = fdopen(fd,"rb");
854    
855     if (!bfd) {
856     perror("load_elf_image: fdopen");
857     return(-1);
858     }
859    
860     for(i=0;i<ehdr->e_shnum;i++) {
861     scn = elf_getscn(img_elf,i);
862    
863     shdr = elf32_getshdr(scn);
864     name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
865     len = shdr->sh_size;
866    
867     if (!(shdr->sh_flags & SHF_ALLOC) || !len)
868     continue;
869    
870     fseek(bfd,shdr->sh_offset,SEEK_SET);
871     vaddr = sign_extend(shdr->sh_addr,32);
872    
873     if (cpu->vm->debug_level > 0) {
874     printf(" * Adding section at virtual address 0x%8.8llx "
875     "(len=0x%8.8lx)\n",vaddr & 0xFFFFFFFF,(u_long)len);
876     }
877    
878     while(len > 0)
879     {
880     haddr = cpu->mem_op_lookup(cpu,vaddr);
881    
882     if (!haddr) {
883     fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n",
884     vaddr);
885     return(-1);
886     }
887    
888     if (len > MIPS_MIN_PAGE_SIZE)
889     clen = MIPS_MIN_PAGE_SIZE;
890     else
891     clen = len;
892    
893     clen = fread((u_char *)haddr,clen,1,bfd);
894    
895     if (clen != 1)
896     break;
897    
898     vaddr += MIPS_MIN_PAGE_SIZE;
899     len -= clen;
900     }
901     }
902    
903     printf("ELF entry point: 0x%x\n",ehdr->e_entry);
904    
905     if (entry_point)
906     *entry_point = ehdr->e_entry;
907    
908     elf_end(img_elf);
909     fclose(bfd);
910     return(0);
911     }
912    
913     /* Symbol lookup */
914     struct symbol *mips64_sym_lookup(cpu_mips_t *cpu,m_uint64_t addr)
915     {
916     return(rbtree_lookup(cpu->sym_tree,&addr));
917     }
918    
919     /* Insert a new symbol */
920     struct symbol *mips64_sym_insert(cpu_mips_t *cpu,char *name,m_uint64_t addr)
921     {
922     struct symbol *sym;
923     size_t len;
924    
925     if (!cpu->sym_tree)
926     return NULL;
927    
928     len = strlen(name);
929    
930     if (!(sym = malloc(len+1+sizeof(*sym))))
931     return NULL;
932    
933     memcpy(sym->name,name,len+1);
934     sym->addr = addr;
935    
936     if (rbtree_insert(cpu->sym_tree,sym,sym) == -1) {
937     free(sym);
938     return NULL;
939     }
940    
941     return sym;
942     }
943    
944     /* Symbol comparison function */
945     static int mips64_sym_compare(m_uint64_t *a1,struct symbol *sym)
946     {
947     if (*a1 > sym->addr)
948     return(1);
949    
950     if (*a1 < sym->addr)
951     return(-1);
952    
953     return(0);
954     }
955    
956     /* Create the symbol tree */
957     int mips64_sym_create_tree(cpu_mips_t *cpu)
958     {
959     cpu->sym_tree = rbtree_create((tree_fcompare)mips64_sym_compare,NULL);
960     return(cpu->sym_tree ? 0 : -1);
961     }
962    
963     /* Load a symbol file */
964     int mips64_sym_load_file(cpu_mips_t *cpu,char *filename)
965     {
966     char buffer[4096],func_name[128];
967     m_uint64_t addr;
968     char sym_type;
969     FILE *fd;
970    
971     if (!cpu->sym_tree && (mips64_sym_create_tree(cpu) == -1)) {
972     fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->id);
973     return(-1);
974     }
975    
976     if (!(fd = fopen(filename,"r"))) {
977     perror("load_sym_file: fopen");
978     return(-1);
979     }
980    
981     while(!feof(fd)) {
982     fgets(buffer,sizeof(buffer),fd);
983    
984     if (sscanf(buffer,"%llx %c %s",&addr,&sym_type,func_name) == 3) {
985     mips64_sym_insert(cpu,func_name,addr);
986     }
987     }
988    
989     fclose(fd);
990     return(0);
991     }

  ViewVC Help
Powered by ViewVC 1.1.26