SIM_RC sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env) { SIM_CPU *cpu = STATE_CPU (sd, 0); SIM_ADDR addr; /* Set the PC. */ if (abfd != NULL) addr = bfd_get_start_address (abfd); else addr = 0; sim_pc_set (cpu, addr); /* Standalone mode (i.e. `bfin-...-run`) will take care of the argv for us in sim_open() -> sim_parse_args(). But in debug mode (i.e. 'target sim' with `bfin-...-gdb`), we need to handle it. */ if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) { freeargv (STATE_PROG_ARGV (sd)); STATE_PROG_ARGV (sd) = dupargv (argv); } switch (STATE_ENVIRONMENT (sd)) { case USER_ENVIRONMENT: bfin_user_init (sd, cpu, abfd, (void *)argv, (void *)env); break; case OPERATING_ENVIRONMENT: bfin_os_init (sd, cpu, (void *)argv); break; default: bfin_virtual_init (sd, cpu); break; } return SIM_RC_OK; }
static SIM_RC standard_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg, int is_command) { int i,n; switch ((STANDARD_OPTIONS) opt) { case OPTION_VERBOSE: STATE_VERBOSE_P (sd) = 1; break; #ifdef SIM_HAVE_BIENDIAN case OPTION_ENDIAN: if (strcmp (arg, "big") == 0) { if (WITH_TARGET_BYTE_ORDER == LITTLE_ENDIAN) { sim_io_eprintf (sd, "Simulator compiled for little endian only.\n"); return SIM_RC_FAIL; } /* FIXME:wip: Need to set something in STATE_CONFIG. */ current_target_byte_order = BIG_ENDIAN; } else if (strcmp (arg, "little") == 0) { if (WITH_TARGET_BYTE_ORDER == BIG_ENDIAN) { sim_io_eprintf (sd, "Simulator compiled for big endian only.\n"); return SIM_RC_FAIL; } /* FIXME:wip: Need to set something in STATE_CONFIG. */ current_target_byte_order = LITTLE_ENDIAN; } else { sim_io_eprintf (sd, "Invalid endian specification `%s'\n", arg); return SIM_RC_FAIL; } break; #endif case OPTION_ENVIRONMENT: if (strcmp (arg, "user") == 0) STATE_ENVIRONMENT (sd) = USER_ENVIRONMENT; else if (strcmp (arg, "virtual") == 0) STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT; else if (strcmp (arg, "operating") == 0) STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT; else { sim_io_eprintf (sd, "Invalid environment specification `%s'\n", arg); return SIM_RC_FAIL; } if (WITH_ENVIRONMENT != ALL_ENVIRONMENT && WITH_ENVIRONMENT != STATE_ENVIRONMENT (sd)) { char *type; switch (WITH_ENVIRONMENT) { case USER_ENVIRONMENT: type = "user"; break; case VIRTUAL_ENVIRONMENT: type = "virtual"; break; case OPERATING_ENVIRONMENT: type = "operating"; break; } sim_io_eprintf (sd, "Simulator compiled for the %s environment only.\n", type); return SIM_RC_FAIL; } break; case OPTION_ALIGNMENT: if (strcmp (arg, "strict") == 0) { if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == STRICT_ALIGNMENT) { current_alignment = STRICT_ALIGNMENT; break; } } else if (strcmp (arg, "nonstrict") == 0) { if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == NONSTRICT_ALIGNMENT) { current_alignment = NONSTRICT_ALIGNMENT; break; } } else if (strcmp (arg, "forced") == 0) { if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == FORCED_ALIGNMENT) { current_alignment = FORCED_ALIGNMENT; break; } } else { sim_io_eprintf (sd, "Invalid alignment specification `%s'\n", arg); return SIM_RC_FAIL; } switch (WITH_ALIGNMENT) { case STRICT_ALIGNMENT: sim_io_eprintf (sd, "Simulator compiled for strict alignment only.\n"); break; case NONSTRICT_ALIGNMENT: sim_io_eprintf (sd, "Simulator compiled for nonstrict alignment only.\n"); break; case FORCED_ALIGNMENT: sim_io_eprintf (sd, "Simulator compiled for forced alignment only.\n"); break; } return SIM_RC_FAIL; case OPTION_DEBUG: if (! WITH_DEBUG) sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n"); else { for (n = 0; n < MAX_NR_PROCESSORS; ++n) for (i = 0; i < MAX_DEBUG_VALUES; ++i) CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[i] = 1; } break; case OPTION_DEBUG_INSN : if (! WITH_DEBUG) sim_io_eprintf (sd, "Debugging not compiled in, `--debug-insn' ignored\n"); else { for (n = 0; n < MAX_NR_PROCESSORS; ++n) CPU_DEBUG_FLAGS (STATE_CPU (sd, n))[DEBUG_INSN_IDX] = 1; } break; case OPTION_DEBUG_FILE : if (! WITH_DEBUG) sim_io_eprintf (sd, "Debugging not compiled in, `--debug-file' ignored\n"); else { FILE *f = fopen (arg, "w"); if (f == NULL) { sim_io_eprintf (sd, "Unable to open debug output file `%s'\n", arg); return SIM_RC_FAIL; } for (n = 0; n < MAX_NR_PROCESSORS; ++n) CPU_DEBUG_FILE (STATE_CPU (sd, n)) = f; } break; #ifdef SIM_H8300 /* FIXME: Can be moved to h8300 dir. */ case OPTION_H8300: set_h8300h (1,0); break; case OPTION_H8300S: set_h8300h (1,1); break; #endif #ifdef SIM_HAVE_FLATMEM case OPTION_MEM_SIZE: { unsigned long ul = strtol (arg, NULL, 0); /* 16384: some minimal amount */ if (! isdigit (arg[0]) || ul < 16384) { sim_io_eprintf (sd, "Invalid memory size `%s'", arg); return SIM_RC_FAIL; } STATE_MEM_SIZE (sd) = ul; } break; #endif case OPTION_DO_COMMAND: sim_do_command (sd, arg); break; case OPTION_ARCHITECTURE: { const struct bfd_arch_info *ap = bfd_scan_arch (arg); if (ap == NULL) { sim_io_eprintf (sd, "Architecture `%s' unknown\n", arg); return SIM_RC_FAIL; } STATE_ARCHITECTURE (sd) = ap; break; } case OPTION_ARCHITECTURE_INFO: { const char **list = bfd_arch_list(); const char **lp; if (list == NULL) abort (); sim_io_printf (sd, "Possible architectures:"); for (lp = list; *lp != NULL; lp++) sim_io_printf (sd, " %s", *lp); sim_io_printf (sd, "\n"); free (list); break; } case OPTION_TARGET: { STATE_TARGET (sd) = xstrdup (arg); break; } case OPTION_LOAD_LMA: { STATE_LOAD_AT_LMA_P (sd) = 1; break; } case OPTION_LOAD_VMA: { STATE_LOAD_AT_LMA_P (sd) = 0; break; } case OPTION_HELP: sim_print_help (sd, is_command); if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) exit (0); /* FIXME: 'twould be nice to do something similar if gdb. */ break; } return SIM_RC_OK; }
static bool bfin_fdpic_load (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd, bu32 *sp, bu32 *elf_addrs, char **ldso_path) { bool ret; int i; Elf_Internal_Ehdr *iehdr; Elf32_External_Ehdr ehdr; Elf_Internal_Phdr *phdrs; unsigned char *data; long phdr_size; int phdrc; bu32 nsegs; bu32 max_load_addr; unsigned char null[4] = { 0, 0, 0, 0 }; ret = false; *ldso_path = NULL; /* See if this an FDPIC ELF. */ phdrs = NULL; if (!abfd) goto skip_fdpic_init; if (bfd_seek (abfd, 0, SEEK_SET) != 0) goto skip_fdpic_init; if (bfd_bread (&ehdr, sizeof (ehdr), abfd) != sizeof (ehdr)) goto skip_fdpic_init; iehdr = elf_elfheader (abfd); if (!(iehdr->e_flags & EF_BFIN_FDPIC)) goto skip_fdpic_init; if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) sim_io_printf (sd, "Loading FDPIC ELF %s\n Load base: %#x\n ELF entry: %#x\n", bfd_get_filename (abfd), fdpic_load_offset, elf_addrs[0]); /* Grab the Program Headers to set up the loadsegs on the stack. */ phdr_size = bfd_get_elf_phdr_upper_bound (abfd); if (phdr_size == -1) goto skip_fdpic_init; phdrs = xmalloc (phdr_size); phdrc = bfd_get_elf_phdrs (abfd, phdrs); if (phdrc == -1) goto skip_fdpic_init; /* Push the Ehdr onto the stack. */ *sp -= sizeof (ehdr); elf_addrs[3] = *sp; sim_write (sd, *sp, (void *)&ehdr, sizeof (ehdr)); if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) sim_io_printf (sd, " Elf_Ehdr: %#x\n", *sp); /* Since we're relocating things ourselves, we need to relocate the start address as well. */ elf_addrs[0] = bfd_get_start_address (abfd) + fdpic_load_offset; /* And the Exec's Phdrs onto the stack. */ if (STATE_PROG_BFD (sd) == abfd) { elf_addrs[4] = elf_addrs[0]; phdr_size = iehdr->e_phentsize * iehdr->e_phnum; if (bfd_seek (abfd, iehdr->e_phoff, SEEK_SET) != 0) goto skip_fdpic_init; data = xmalloc (phdr_size); if (bfd_bread (data, phdr_size, abfd) != phdr_size) goto skip_fdpic_init; *sp -= phdr_size; elf_addrs[1] = *sp; elf_addrs[2] = phdrc; sim_write (sd, *sp, data, phdr_size); free (data); if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) sim_io_printf (sd, " Elf_Phdrs: %#x\n", *sp); } /* Now push all the loadsegs. */ nsegs = 0; max_load_addr = 0; for (i = phdrc; i >= 0; --i) if (phdrs[i].p_type == PT_LOAD) { Elf_Internal_Phdr *p = &phdrs[i]; bu32 paddr, vaddr, memsz, filesz; paddr = p->p_paddr + fdpic_load_offset; vaddr = p->p_vaddr; memsz = p->p_memsz; filesz = p->p_filesz; if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) sim_io_printf (sd, " PHDR %i: vma %#x lma %#x filesz %#x memsz %#x\n", i, vaddr, paddr, filesz, memsz); data = xmalloc (memsz); if (memsz != filesz) memset (data + filesz, 0, memsz - filesz); if (bfd_seek (abfd, p->p_offset, SEEK_SET) == 0 && bfd_bread (data, filesz, abfd) == filesz) sim_write (sd, paddr, data, memsz); free (data); max_load_addr = MAX (paddr + memsz, max_load_addr); *sp -= 12; sim_write (sd, *sp+0, (void *)&paddr, 4); /* loadseg.addr */ sim_write (sd, *sp+4, (void *)&vaddr, 4); /* loadseg.p_vaddr */ sim_write (sd, *sp+8, (void *)&memsz, 4); /* loadseg.p_memsz */ ++nsegs; } else if (phdrs[i].p_type == PT_DYNAMIC) { elf_addrs[5] = phdrs[i].p_paddr + fdpic_load_offset; if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) sim_io_printf (sd, " PT_DYNAMIC: %#x\n", elf_addrs[5]); } else if (phdrs[i].p_type == PT_INTERP) { uint32_t off = phdrs[i].p_offset; uint32_t len = phdrs[i].p_filesz; *ldso_path = xmalloc (len); if (bfd_seek (abfd, off, SEEK_SET) != 0 || bfd_bread (*ldso_path, len, abfd) != len) { free (*ldso_path); *ldso_path = NULL; } else if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) sim_io_printf (sd, " PT_INTERP: %s\n", *ldso_path); } /* Update the load offset with a few extra pages. */ fdpic_load_offset = ALIGN (MAX (max_load_addr, fdpic_load_offset), 0x10000); fdpic_load_offset += 0x10000; /* Push the summary loadmap info onto the stack last. */ *sp -= 4; sim_write (sd, *sp+0, null, 2); /* loadmap.version */ sim_write (sd, *sp+2, (void *)&nsegs, 2); /* loadmap.nsegs */ ret = true; skip_fdpic_init: free (phdrs); return ret; }
void sim_resume (SIM_DESC sd, int step, int siggnal) { sim_engine *engine = STATE_ENGINE (sd); jmp_buf buf; int jmpval; ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER); /* we only want to be single stepping the simulator once */ if (engine->stepper != NULL) { sim_events_deschedule (sd, engine->stepper); engine->stepper = NULL; } if (step) engine->stepper = sim_events_schedule (sd, 1, has_stepped, sd); sim_module_resume (sd); #if WITH_SCACHE if (USING_SCACHE_P (sd)) scache_flush (sd); #endif /* run/resume the simulator */ sim_engine_set_run_state (sd, sim_running, 0); engine->jmpbuf = &buf; jmpval = setjmp (buf); if (jmpval == sim_engine_start_jmpval || jmpval == sim_engine_restart_jmpval) { int last_cpu_nr = sim_engine_last_cpu_nr (sd); int next_cpu_nr = sim_engine_next_cpu_nr (sd); int nr_cpus = sim_engine_nr_cpus (sd); /* ??? Setting max_insns to 0 allows pbb/jit code to run wild and is useful if all one wants to do is run a benchmark. Need some better way to identify this case. */ int max_insns = (step ? 1 : (nr_cpus == 1 /*&& wip:no-events*/ /* Don't do this if running under gdb, need to poll ui for events. */ && STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE) ? 0 : 8); /*FIXME: magic number*/ int fast_p = STATE_RUN_FAST_P (sd); sim_events_preprocess (sd, last_cpu_nr >= nr_cpus, next_cpu_nr >= nr_cpus); if (next_cpu_nr >= nr_cpus) next_cpu_nr = 0; if (nr_cpus == 1) engine_run_1 (sd, max_insns, fast_p); else engine_run_n (sd, next_cpu_nr, nr_cpus, max_insns, fast_p); } #if 1 /*wip*/ else { /* Account for the last insn executed. */ SIM_CPU *cpu = STATE_CPU (sd, sim_engine_last_cpu_nr (sd)); ++ CPU_INSN_COUNT (cpu); CGEN_TRACE_INSN_FINI (cpu, NULL, 1); } #endif engine->jmpbuf = NULL; { int i; int nr_cpus = sim_engine_nr_cpus (sd); #if 0 /*wip,ignore*/ /* If the loop exits, either we single-stepped or @cpu@_engine_stop was called. */ if (step) sim_engine_set_run_state (sd, sim_stopped, SIM_SIGTRAP); else sim_engine_set_run_state (sd, pending_reason, pending_sigrc); #endif for (i = 0; i < nr_cpus; ++i) { SIM_CPU *cpu = STATE_CPU (sd, i); PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) += CPU_INSN_COUNT (cpu); } } sim_module_suspend (sd); }
void cec_exception (SIM_CPU *cpu, int excp) { SIM_DESC sd = CPU_STATE (cpu); int sigrc = -1; TRACE_EVENTS (cpu, "processing exception %#x in EVT%i", excp, cec_get_ivg (cpu)); /* Ideally what would happen here for real hardware exceptions (not fake sim ones) is that: - For service exceptions (excp <= 0x11): RETX is the _next_ PC which can be tricky with jumps/hardware loops/... - For error exceptions (excp > 0x11): RETX is the _current_ PC (i.e. the one causing the exception) - PC is loaded with EVT3 MMR - ILAT/IPEND in CEC is updated depending on current IVG level - the fault address MMRs get updated with data/instruction info - Execution continues on in the EVT3 handler */ /* Handle simulator exceptions first. */ switch (excp) { case VEC_SIM_HLT: excp_to_sim_halt (sim_exited, 0); return; case VEC_SIM_ABORT: excp_to_sim_halt (sim_exited, 1); return; case VEC_SIM_TRAP: /* GDB expects us to step over EMUEXCPT. */ /* XXX: What about hwloops and EMUEXCPT at the end? Pretty sure gdb doesn't handle this already... */ SET_PCREG (PCREG + 2); /* Only trap when we are running in gdb. */ if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) excp_to_sim_halt (sim_stopped, SIM_SIGTRAP); return; case VEC_SIM_DBGA: /* If running in gdb, simply trap. */ if (STATE_OPEN_KIND (sd) == SIM_OPEN_DEBUG) excp_to_sim_halt (sim_stopped, SIM_SIGTRAP); else excp_to_sim_halt (sim_exited, 2); } if (excp <= 0x3f) { SET_EXCAUSE (excp); if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT) { /* ICPLB regs always get updated. */ /* XXX: Should optimize this call path ... */ if (excp != VEC_MISALI_I && excp != VEC_MISALI_D && excp != VEC_CPLB_I_M && excp != VEC_CPLB_M && excp != VEC_CPLB_I_VL && excp != VEC_CPLB_VL && excp != VEC_CPLB_I_MHIT && excp != VEC_CPLB_MHIT) mmu_log_ifault (cpu); _cec_raise (cpu, CEC_STATE (cpu), IVG_EVX); /* We need to restart the engine so that we don't return and continue processing this bad insn. */ if (EXCAUSE >= 0x20) sim_engine_restart (sd, cpu, NULL, PCREG); return; } } TRACE_EVENTS (cpu, "running virtual exception handler"); switch (excp) { case VEC_SYS: bfin_syscall (cpu); break; case VEC_EXCPT01: /* Userspace gdb breakpoint. */ sigrc = SIM_SIGTRAP; break; case VEC_UNDEF_I: /* Undefined instruction. */ sigrc = SIM_SIGILL; break; case VEC_ILL_RES: /* Illegal supervisor resource. */ case VEC_MISALI_I: /* Misaligned instruction. */ sigrc = SIM_SIGBUS; break; case VEC_CPLB_M: case VEC_CPLB_I_M: sigrc = SIM_SIGSEGV; break; default: sim_io_eprintf (sd, "Unhandled exception %#x at 0x%08x (%s)\n", excp, PCREG, excp_decoded[excp]); sigrc = SIM_SIGILL; break; } if (sigrc != -1) excp_to_sim_halt (sim_stopped, sigrc); }