/[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 8 - (hide annotations)
Sat Oct 6 16:24:54 2007 UTC (12 years, 1 month ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC2/ppc32.c
File MIME type: text/plain
File size: 15716 byte(s)
dynamips-0.2.7-RC2

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

  ViewVC Help
Powered by ViewVC 1.1.26