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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations)
Sat Oct 6 16:29:14 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 15782 byte(s)
dynamips-0.2.7

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

  ViewVC Help
Powered by ViewVC 1.1.26