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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (12 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 15841 byte(s)
make working copy

1 dpavlin 7 /*
2     * Cisco router simulation platform.
3     * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4     *
5     * PowerPC (32-bit) generic routines.
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 "cpu.h"
20     #include "dynamips.h"
21     #include "memory.h"
22     #include "device.h"
23     #include "ppc32_mem.h"
24     #include "ppc32_exec.h"
25     #include "ppc32_jit.h"
26    
27     /* Reset a PowerPC CPU */
28     int ppc32_reset(cpu_ppc_t *cpu)
29     {
30     cpu->ia = PPC32_ROM_START;
31     cpu->gpr[1] = PPC32_ROM_SP;
32     cpu->msr = PPC32_MSR_IP;
33    
34     /* Restart the MTS subsystem */
35     ppc32_mem_restart(cpu);
36    
37     /* Flush JIT structures */
38     ppc32_jit_flush(cpu,0);
39     return(0);
40     }
41    
42     /* Initialize a PowerPC processor */
43     int ppc32_init(cpu_ppc_t *cpu)
44     {
45 dpavlin 9 /* Initialize JIT operations */
46     jit_op_init_cpu(cpu->gen);
47    
48 dpavlin 7 /* Initialize idle timer */
49     cpu->gen->idle_max = 1500;
50     cpu->gen->idle_sleep_time = 30000;
51    
52     /* Timer IRQ parameters (default frequency: 250 Hz <=> 4ms period) */
53     cpu->timer_irq_check_itv = 1000;
54     cpu->timer_irq_freq = 250;
55    
56 dpavlin 8 /* Enable/disable direct block jump */
57     cpu->exec_blk_direct_jump = cpu->vm->exec_blk_direct_jump;
58    
59 dpavlin 7 /* Idle loop mutex and condition */
60     pthread_mutex_init(&cpu->gen->idle_mutex,NULL);
61     pthread_cond_init(&cpu->gen->idle_cond,NULL);
62    
63     /* Set the CPU methods */
64     cpu->gen->reg_set = (void *)ppc32_reg_set;
65     cpu->gen->reg_dump = (void *)ppc32_dump_regs;
66     cpu->gen->mmu_dump = (void *)ppc32_dump_mmu;
67     cpu->gen->mmu_raw_dump = (void *)ppc32_dump_mmu;
68     cpu->gen->add_breakpoint = (void *)ppc32_add_breakpoint;
69     cpu->gen->remove_breakpoint = (void *)ppc32_remove_breakpoint;
70     cpu->gen->set_idle_pc = (void *)ppc32_set_idle_pc;
71     cpu->gen->get_idling_pc = (void *)ppc32_get_idling_pc;
72    
73 dpavlin 11 /* zzz */
74     memset(cpu->vtlb,0xFF,sizeof(cpu->vtlb));
75    
76 dpavlin 7 /* Set the startup parameters */
77     ppc32_reset(cpu);
78     return(0);
79     }
80    
81     /* Delete a PowerPC processor */
82     void ppc32_delete(cpu_ppc_t *cpu)
83     {
84     if (cpu) {
85     ppc32_mem_shutdown(cpu);
86     ppc32_jit_shutdown(cpu);
87     }
88     }
89    
90     /* Set the processor version register (PVR) */
91     void ppc32_set_pvr(cpu_ppc_t *cpu,m_uint32_t pvr)
92     {
93     cpu->pvr = pvr;
94     ppc32_mem_restart(cpu);
95     }
96    
97     /* Set idle PC value */
98     void ppc32_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr)
99     {
100     CPU_PPC32(cpu)->idle_pc = (m_uint32_t)addr;
101     }
102    
103     /* Timer IRQ */
104     void *ppc32_timer_irq_run(cpu_ppc_t *cpu)
105     {
106     pthread_mutex_t umutex = PTHREAD_MUTEX_INITIALIZER;
107     pthread_cond_t ucond = PTHREAD_COND_INITIALIZER;
108     struct timespec t_spc;
109     m_tmcnt_t expire;
110     u_int interval;
111     u_int threshold;
112    
113     #if 0
114     while(!cpu->timer_irq_armed)
115     sleep(1);
116     #endif
117    
118     interval = 1000000 / cpu->timer_irq_freq;
119     threshold = cpu->timer_irq_freq * 10;
120     expire = m_gettime_usec() + interval;
121    
122     while(cpu->gen->state != CPU_STATE_HALTED) {
123     pthread_mutex_lock(&umutex);
124     t_spc.tv_sec = expire / 1000000;
125     t_spc.tv_nsec = (expire % 1000000) * 1000;
126     pthread_cond_timedwait(&ucond,&umutex,&t_spc);
127     pthread_mutex_unlock(&umutex);
128    
129     if (likely(!cpu->irq_disable) &&
130     likely(cpu->gen->state == CPU_STATE_RUNNING) &&
131     likely(cpu->msr & PPC32_MSR_EE))
132     {
133     cpu->timer_irq_pending++;
134    
135     if (unlikely(cpu->timer_irq_pending > threshold)) {
136     cpu->timer_irq_pending = 0;
137     cpu->timer_drift++;
138     #if 0
139     printf("Timer IRQ not accurate (%u pending IRQ): "
140     "reduce the \"--timer-irq-check-itv\" parameter "
141     "(current value: %u)\n",
142     cpu->timer_irq_pending,cpu->timer_irq_check_itv);
143     #endif
144     }
145     }
146    
147     expire += interval;
148     }
149    
150     return NULL;
151     }
152    
153     #define IDLE_HASH_SIZE 8192
154    
155     /* Idle PC hash item */
156     struct ppc32_idle_pc_hash {
157     m_uint32_t ia;
158     u_int count;
159     struct ppc32_idle_pc_hash *next;
160     };
161    
162     /* Determine an "idling" PC */
163     int ppc32_get_idling_pc(cpu_gen_t *cpu)
164     {
165     cpu_ppc_t *pcpu = CPU_PPC32(cpu);
166     struct ppc32_idle_pc_hash **pc_hash,*p;
167     struct cpu_idle_pc *res;
168     u_int h_index,res_count;
169     m_uint32_t cur_ia;
170     int i;
171    
172     cpu->idle_pc_prop_count = 0;
173    
174     if (pcpu->idle_pc != 0) {
175     printf("\nYou already use an idle PC, using the calibration would give "
176     "incorrect results.\n");
177     return(-1);
178     }
179    
180     printf("\nPlease wait while gathering statistics...\n");
181    
182     pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct ppc32_idle_pc_hash *));
183    
184     /* Disable IRQ */
185     pcpu->irq_disable = TRUE;
186    
187     /* Take 1000 measures, each mesure every 10ms */
188     for(i=0;i<1000;i++) {
189     cur_ia = pcpu->ia;
190     h_index = (cur_ia >> 2) & (IDLE_HASH_SIZE-1);
191    
192     for(p=pc_hash[h_index];p;p=p->next)
193     if (p->ia == cur_ia) {
194     p->count++;
195     break;
196     }
197    
198     if (!p) {
199     if ((p = malloc(sizeof(*p)))) {
200     p->ia = cur_ia;
201     p->count = 1;
202     p->next = pc_hash[h_index];
203     pc_hash[h_index] = p;
204     }
205     }
206    
207     usleep(10000);
208     }
209    
210     /* Select PCs */
211     for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) {
212     for(p=pc_hash[i];p;p=p->next)
213     if ((p->count >= 20) && (p->count <= 80)) {
214     res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
215    
216     res->pc = p->ia;
217     res->count = p->count;
218    
219     if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES)
220     goto done;
221     }
222     }
223    
224     done:
225     /* Set idle PC */
226     if (cpu->idle_pc_prop_count) {
227     printf("Done. Suggested idling PC:\n");
228    
229     for(i=0;i<cpu->idle_pc_prop_count;i++) {
230     printf(" 0x%llx (count=%u)\n",
231     cpu->idle_pc_prop[i].pc,
232     cpu->idle_pc_prop[i].count);
233     }
234    
235     printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",
236     cpu->idle_pc_prop[0].pc);
237     } else {
238 dpavlin 8 printf("Done. No suggestion for idling PC, dumping the full table:\n");
239    
240     for(i=0;i<IDLE_HASH_SIZE;i++)
241     for(p=pc_hash[i];p;p=p->next) {
242     printf(" 0x%8.8x (%3u)\n",p->ia,p->count);
243    
244     if (cpu->idle_pc_prop_count < CPU_IDLE_PC_MAX_RES) {
245     res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
246    
247     res->pc = p->ia;
248     res->count = p->count;
249     }
250     }
251    
252     printf("\n");
253 dpavlin 7 }
254    
255     /* Re-enable IRQ */
256     pcpu->irq_disable = FALSE;
257     return(0);
258     }
259    
260     #if 0
261     /* Set an IRQ (VM IRQ standard routing) */
262     void ppc32_vm_set_irq(vm_instance_t *vm,u_int irq)
263     {
264     cpu_ppc_t *boot_cpu;
265    
266     boot_cpu = CPU_PPC32(vm->boot_cpu);
267    
268     if (boot_cpu->irq_disable) {
269     boot_cpu->irq_pending = 0;
270     return;
271     }
272    
273     ppc32_set_irq(boot_cpu,irq);
274    
275     if (boot_cpu->irq_idle_preempt[irq])
276     cpu_idle_break_wait(vm->boot_cpu);
277     }
278    
279     /* Clear an IRQ (VM IRQ standard routing) */
280     void ppc32_vm_clear_irq(vm_instance_t *vm,u_int irq)
281     {
282     cpu_ppc_t *boot_cpu;
283    
284     boot_cpu = CPU_PPC32(vm->boot_cpu);
285     ppc32_clear_irq(boot_cpu,irq);
286     }
287     #endif
288    
289     /* Generate an exception */
290     void ppc32_trigger_exception(cpu_ppc_t *cpu,u_int exc_vector)
291     {
292     //printf("TRIGGER_EXCEPTION: saving cpu->ia=0x%8.8x, msr=0x%8.8x\n",
293     // cpu->ia,cpu->msr);
294    
295     /* Save the return instruction address */
296     cpu->srr0 = cpu->ia;
297    
298     if (exc_vector == PPC32_EXC_SYSCALL)
299     cpu->srr0 += sizeof(ppc_insn_t);
300    
301     //printf("SRR0 = 0x%8.8x\n",cpu->srr0);
302    
303     /* Save Machine State Register (MSR) */
304     cpu->srr1 = cpu->msr & PPC32_EXC_SRR1_MASK;
305    
306     //printf("SRR1 = 0x%8.8x\n",cpu->srr1);
307    
308     /* Set the new SRR value */
309     cpu->msr &= ~PPC32_EXC_MSR_MASK;
310     cpu->irq_check = FALSE;
311    
312     //printf("MSR = 0x%8.8x\n",cpu->msr);
313    
314     /* Use bootstrap vectors ? */
315     if (cpu->msr & PPC32_MSR_IP)
316     cpu->ia = 0xFFF00000 + exc_vector;
317     else
318     cpu->ia = exc_vector;
319     }
320    
321     /* Trigger IRQs */
322     fastcall void ppc32_trigger_irq(cpu_ppc_t *cpu)
323     {
324     if (unlikely(cpu->irq_disable)) {
325     cpu->irq_pending = FALSE;
326     cpu->irq_check = FALSE;
327     return;
328     }
329    
330     /* Clear the IRQ check flag */
331     cpu->irq_check = FALSE;
332    
333     if (cpu->irq_pending && (cpu->msr & PPC32_MSR_EE)) {
334     cpu->irq_count++;
335     cpu->irq_pending = FALSE;
336     ppc32_trigger_exception(cpu,PPC32_EXC_EXT);
337     }
338     }
339    
340     /* Trigger the decrementer exception */
341     void ppc32_trigger_timer_irq(cpu_ppc_t *cpu)
342     {
343     cpu->timer_irq_count++;
344    
345     if (cpu->msr & PPC32_MSR_EE)
346     ppc32_trigger_exception(cpu,PPC32_EXC_DEC);
347     }
348    
349     /* Virtual breakpoint */
350     fastcall void ppc32_run_breakpoint(cpu_ppc_t *cpu)
351     {
352     cpu_log(cpu->gen,"BREAKPOINT",
353     "Virtual breakpoint reached at IA=0x%8.8x\n",cpu->ia);
354    
355     printf("[[[ Virtual Breakpoint reached at IA=0x%8.8x LR=0x%8.8x]]]\n",
356     cpu->ia,cpu->lr);
357    
358     ppc32_dump_regs(cpu->gen);
359     }
360    
361     /* Add a virtual breakpoint */
362     int ppc32_add_breakpoint(cpu_gen_t *cpu,m_uint64_t ia)
363     {
364     cpu_ppc_t *pcpu = CPU_PPC32(cpu);
365     int i;
366    
367     for(i=0;i<PPC32_MAX_BREAKPOINTS;i++)
368     if (!pcpu->breakpoints[i])
369     break;
370    
371     if (i == PPC32_MAX_BREAKPOINTS)
372     return(-1);
373    
374     pcpu->breakpoints[i] = ia;
375     pcpu->breakpoints_enabled = TRUE;
376     return(0);
377     }
378    
379     /* Remove a virtual breakpoint */
380     void ppc32_remove_breakpoint(cpu_gen_t *cpu,m_uint64_t ia)
381     {
382     cpu_ppc_t *pcpu = CPU_PPC32(cpu);
383     int i,j;
384    
385     for(i=0;i<PPC32_MAX_BREAKPOINTS;i++)
386     if (pcpu->breakpoints[i] == ia)
387     {
388     for(j=i;j<PPC32_MAX_BREAKPOINTS-1;j++)
389     pcpu->breakpoints[j] = pcpu->breakpoints[j+1];
390    
391     pcpu->breakpoints[PPC32_MAX_BREAKPOINTS-1] = 0;
392     }
393    
394     for(i=0;i<PPC32_MAX_BREAKPOINTS;i++)
395     if (pcpu->breakpoints[i] != 0)
396     return;
397    
398     pcpu->breakpoints_enabled = FALSE;
399     }
400    
401     /* Set a register */
402     void ppc32_reg_set(cpu_gen_t *cpu,u_int reg,m_uint64_t val)
403     {
404     if (reg < PPC32_GPR_NR)
405     CPU_PPC32(cpu)->gpr[reg] = (m_uint32_t)val;
406     }
407    
408     /* Dump registers of a PowerPC processor */
409     void ppc32_dump_regs(cpu_gen_t *cpu)
410     {
411     cpu_ppc_t *pcpu = CPU_PPC32(cpu);
412     int i;
413    
414     printf("PowerPC Registers:\n");
415    
416     for(i=0;i<PPC32_GPR_NR/4;i++) {
417     printf(" $%2d = 0x%8.8x $%2d = 0x%8.8x"
418     " $%2d = 0x%8.8x $%2d = 0x%8.8x\n",
419     i*4, pcpu->gpr[i*4], (i*4)+1, pcpu->gpr[(i*4)+1],
420     (i*4)+2, pcpu->gpr[(i*4)+2], (i*4)+3, pcpu->gpr[(i*4)+3]);
421     }
422    
423     printf("\n");
424     printf(" ia = 0x%8.8x, lr = 0x%8.8x\n", pcpu->ia, pcpu->lr);
425     printf(" cr = 0x%8.8x, msr = 0x%8.8x, xer = 0x%8.8x, dec = 0x%8.8x\n",
426 dpavlin 8 ppc32_get_cr(pcpu), pcpu->msr,
427 dpavlin 7 pcpu->xer | (pcpu->xer_ca << PPC32_XER_CA_BIT),
428     pcpu->dec);
429    
430     printf(" sprg[0] = 0x%8.8x, sprg[1] = 0x%8.8x\n",
431     pcpu->sprg[0],pcpu->sprg[1]);
432    
433     printf(" sprg[2] = 0x%8.8x, sprg[3] = 0x%8.8x\n",
434     pcpu->sprg[2],pcpu->sprg[3]);
435    
436     printf("\n IRQ count: %llu, IRQ false positives: %llu, "
437     "IRQ Pending: %u, IRQ Check: %s\n",
438     pcpu->irq_count,pcpu->irq_fp_count,pcpu->irq_pending,
439     pcpu->irq_check ? "yes" : "no");
440    
441     printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n",
442     pcpu->timer_irq_count,pcpu->timer_irq_pending,pcpu->timer_drift);
443    
444 dpavlin 8 printf(" Device access count: %llu\n",cpu->dev_access_counter);
445    
446 dpavlin 7 printf("\n");
447     }
448    
449     /* Dump BAT registers */
450     static void ppc32_dump_bat(cpu_ppc_t *cpu,int index)
451     {
452     int i;
453    
454     for(i=0;i<PPC32_BAT_NR;i++)
455     printf(" BAT[%d] = 0x%8.8x 0x%8.8x\n",
456     i,cpu->bat[index][i].reg[0],cpu->bat[index][i].reg[1]);
457     }
458    
459     /* Dump MMU registers */
460     void ppc32_dump_mmu(cpu_gen_t *cpu)
461     {
462     cpu_ppc_t *pcpu = CPU_PPC32(cpu);
463     int i;
464    
465     printf("PowerPC MMU Registers:\n");
466    
467     printf(" - IBAT Registers:\n");
468     ppc32_dump_bat(pcpu,PPC32_IBAT_IDX);
469    
470     printf(" - DBAT Registers:\n");
471     ppc32_dump_bat(pcpu,PPC32_DBAT_IDX);
472    
473     printf(" - Segment Registers:\n");
474     for(i=0;i<PPC32_SR_NR;i++)
475     printf(" SR[%d] = 0x%8.8x\n",i,pcpu->sr[i]);
476    
477     printf(" - SDR1: 0x%8.8x\n",pcpu->sdr1);
478     }
479    
480     /* Load a raw image into the simulated memory */
481     int ppc32_load_raw_image(cpu_ppc_t *cpu,char *filename,m_uint32_t vaddr)
482     {
483     struct stat file_info;
484     size_t len,clen;
485     m_uint32_t remain;
486     void *haddr;
487     FILE *bfd;
488    
489     if (!(bfd = fopen(filename,"r"))) {
490     perror("fopen");
491     return(-1);
492     }
493    
494     if (fstat(fileno(bfd),&file_info) == -1) {
495     perror("stat");
496     return(-1);
497     }
498    
499     len = file_info.st_size;
500    
501     printf("Loading RAW file '%s' at virtual address 0x%8.8x (size=%lu)\n",
502     filename,vaddr,(u_long)len);
503    
504     while(len > 0)
505     {
506     haddr = cpu->mem_op_lookup(cpu,vaddr,PPC32_MTS_DCACHE);
507    
508     if (!haddr) {
509     fprintf(stderr,"load_raw_image: invalid load address 0x%8.8x\n",
510     vaddr);
511     return(-1);
512     }
513    
514     if (len > PPC32_MIN_PAGE_SIZE)
515     clen = PPC32_MIN_PAGE_SIZE;
516     else
517     clen = len;
518    
519     remain = MIPS_MIN_PAGE_SIZE;
520     remain -= (vaddr - (vaddr & MIPS_MIN_PAGE_MASK));
521    
522     clen = m_min(clen,remain);
523    
524     if (fread((u_char *)haddr,clen,1,bfd) != 1)
525     break;
526    
527     vaddr += clen;
528     len -= clen;
529     }
530    
531     fclose(bfd);
532     return(0);
533     }
534    
535     /* Load an ELF image into the simulated memory */
536     int ppc32_load_elf_image(cpu_ppc_t *cpu,char *filename,int skip_load,
537     m_uint32_t *entry_point)
538     {
539     m_uint32_t vaddr,remain;
540     void *haddr;
541     Elf32_Ehdr *ehdr;
542     Elf32_Shdr *shdr;
543     Elf_Scn *scn;
544     Elf *img_elf;
545     size_t len,clen;
546     char *name;
547     int i,fd;
548     FILE *bfd;
549    
550     if (!filename)
551     return(-1);
552    
553     #ifdef __CYGWIN__
554     fd = open(filename,O_RDONLY|O_BINARY);
555     #else
556     fd = open(filename,O_RDONLY);
557     #endif
558    
559     if (fd == -1) {
560     perror("load_elf_image: open");
561     return(-1);
562     }
563    
564     if (elf_version(EV_CURRENT) == EV_NONE) {
565     fprintf(stderr,"load_elf_image: library out of date\n");
566     return(-1);
567     }
568    
569     if (!(img_elf = elf_begin(fd,ELF_C_READ,NULL))) {
570     fprintf(stderr,"load_elf_image: elf_begin: %s\n",
571     elf_errmsg(elf_errno()));
572     return(-1);
573     }
574    
575     if (!(ehdr = elf32_getehdr(img_elf))) {
576     fprintf(stderr,"load_elf_image: invalid ELF file\n");
577     return(-1);
578     }
579    
580     printf("Loading ELF file '%s'...\n",filename);
581     bfd = fdopen(fd,"rb");
582    
583     if (!bfd) {
584     perror("load_elf_image: fdopen");
585     return(-1);
586     }
587    
588     if (!skip_load) {
589     for(i=0;i<ehdr->e_shnum;i++) {
590     scn = elf_getscn(img_elf,i);
591    
592     shdr = elf32_getshdr(scn);
593     name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
594     len = shdr->sh_size;
595    
596     if (!(shdr->sh_flags & SHF_ALLOC) || !len)
597     continue;
598    
599     fseek(bfd,shdr->sh_offset,SEEK_SET);
600     vaddr = shdr->sh_addr;
601    
602     if (cpu->vm->debug_level > 0) {
603     printf(" * Adding section at virtual address 0x%8.8x "
604     "(len=0x%8.8lx)\n",vaddr,(u_long)len);
605     }
606    
607     while(len > 0)
608     {
609     haddr = cpu->mem_op_lookup(cpu,vaddr,PPC32_MTS_DCACHE);
610    
611     if (!haddr) {
612     fprintf(stderr,"load_elf_image: invalid load address 0x%x\n",
613     vaddr);
614     return(-1);
615     }
616    
617     if (len > PPC32_MIN_PAGE_SIZE)
618     clen = PPC32_MIN_PAGE_SIZE;
619     else
620     clen = len;
621    
622     remain = PPC32_MIN_PAGE_SIZE;
623     remain -= (vaddr - (vaddr & PPC32_MIN_PAGE_MASK));
624    
625     clen = m_min(clen,remain);
626    
627     if (fread((u_char *)haddr,clen,1,bfd) < 1)
628     break;
629    
630     vaddr += clen;
631     len -= clen;
632     }
633     }
634     } else {
635     printf("ELF loading skipped, using a ghost RAM file.\n");
636     }
637    
638     printf("ELF entry point: 0x%x\n",ehdr->e_entry);
639    
640     if (entry_point)
641     *entry_point = ehdr->e_entry;
642    
643     elf_end(img_elf);
644     fclose(bfd);
645     return(0);
646     }

  ViewVC Help
Powered by ViewVC 1.1.26