diff --git a/sys/arm/arm/machdep.c b/sys/arm/arm/machdep.c index 34357cde0d51..3af556da6858 100644 --- a/sys/arm/arm/machdep.c +++ b/sys/arm/arm/machdep.c @@ -53,129 +53,43 @@ __FBSDID("$FreeBSD$"); #include -#include -#include -#include #include #include #include #include -#include #include #include -#include #include #include #include -#include #include -#include -#include #include -#include -#include -#include -#include -#if defined(LINUX_BOOT_ABI) -#include -#endif #include #include -#include #include -#include #include #include -#include -#include -#include -#include -#include #include #include #include -#include -#include -#include -#include #include -#include -#include -#include #include -#include #include #include #include #include -#include -#include +#include #include #include #include -#include #ifdef FDT -#include #include -#include +#include #endif -#ifdef DDB -#include - -#if __ARM_ARCH >= 6 - -DB_SHOW_COMMAND(cp15, db_show_cp15) -{ - u_int reg; - - reg = cp15_midr_get(); - db_printf("Cpu ID: 0x%08x\n", reg); - reg = cp15_ctr_get(); - db_printf("Current Cache Lvl ID: 0x%08x\n",reg); - - reg = cp15_sctlr_get(); - db_printf("Ctrl: 0x%08x\n",reg); - reg = cp15_actlr_get(); - db_printf("Aux Ctrl: 0x%08x\n",reg); - - reg = cp15_id_pfr0_get(); - db_printf("Processor Feat 0: 0x%08x\n", reg); - reg = cp15_id_pfr1_get(); - db_printf("Processor Feat 1: 0x%08x\n", reg); - reg = cp15_id_dfr0_get(); - db_printf("Debug Feat 0: 0x%08x\n", reg); - reg = cp15_id_afr0_get(); - db_printf("Auxiliary Feat 0: 0x%08x\n", reg); - reg = cp15_id_mmfr0_get(); - db_printf("Memory Model Feat 0: 0x%08x\n", reg); - reg = cp15_id_mmfr1_get(); - db_printf("Memory Model Feat 1: 0x%08x\n", reg); - reg = cp15_id_mmfr2_get(); - db_printf("Memory Model Feat 2: 0x%08x\n", reg); - reg = cp15_id_mmfr3_get(); - db_printf("Memory Model Feat 3: 0x%08x\n", reg); - reg = cp15_ttbr_get(); - db_printf("TTB0: 0x%08x\n", reg); -} - -DB_SHOW_COMMAND(vtop, db_show_vtop) -{ - u_int reg; - - if (have_addr) { - cp15_ats1cpr_set(addr); - reg = cp15_par_get(); - db_printf("Physical address reg: 0x%08x\n",reg); - } else - db_printf("show vtop \n"); -} -#endif /* __ARM_ARCH >= 6 */ -#endif /* DDB */ - #ifdef DEBUG #define debugf(fmt, args...) printf(fmt, ##args) #else @@ -204,10 +118,7 @@ int _min_bzero_size = 0; extern int *end; #ifdef FDT -static char *loader_envp; - vm_paddr_t pmap_pa; - #if __ARM_ARCH >= 6 vm_offset_t systempage; vm_offset_t irqstack; @@ -220,64 +131,21 @@ vm_offset_t abtstack; * stacks etc.), uprounded to be divisible by 4. */ #define KERNEL_PT_MAX 78 - static struct pv_addr kernel_pt_table[KERNEL_PT_MAX]; - struct pv_addr systempage; static struct pv_addr msgbufpv; struct pv_addr irqstack; struct pv_addr undstack; struct pv_addr abtstack; static struct pv_addr kernelstack; -#endif -#endif +#endif /* __ARM_ARCH >= 6 */ +#endif /* FDT */ -#if defined(LINUX_BOOT_ABI) -#define LBABI_MAX_BANKS 10 - -#define CMDLINE_GUARD "FreeBSD:" -uint32_t board_id; -struct arm_lbabi_tag *atag_list; -char linux_command_line[LBABI_MAX_COMMAND_LINE + 1]; -char atags[LBABI_MAX_COMMAND_LINE * 2]; -uint32_t memstart[LBABI_MAX_BANKS]; -uint32_t memsize[LBABI_MAX_BANKS]; -uint32_t membanks; -#endif #ifdef MULTIDELAY static delay_func *delay_impl; static void *delay_arg; #endif -static uint32_t board_revision; -/* hex representation of uint64_t */ -static char board_serial[32]; - -SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes"); -SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD, - &board_revision, 0, "Board revision"); -SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD, - board_serial, 0, "Board serial"); - -int vfp_exists; -SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, - &vfp_exists, 0, "Floating point support enabled"); - -void -board_set_serial(uint64_t serial) -{ - - snprintf(board_serial, sizeof(board_serial)-1, - "%016jx", serial); -} - -void -board_set_revision(uint32_t revision) -{ - - board_revision = revision; -} - void sendsig(catcher, ksi, mask) sig_t catcher; @@ -569,237 +437,6 @@ DELAY(int usec) } #endif -int -fill_regs(struct thread *td, struct reg *regs) -{ - struct trapframe *tf = td->td_frame; - bcopy(&tf->tf_r0, regs->r, sizeof(regs->r)); - regs->r_sp = tf->tf_usr_sp; - regs->r_lr = tf->tf_usr_lr; - regs->r_pc = tf->tf_pc; - regs->r_cpsr = tf->tf_spsr; - return (0); -} -int -fill_fpregs(struct thread *td, struct fpreg *regs) -{ - bzero(regs, sizeof(*regs)); - return (0); -} - -int -set_regs(struct thread *td, struct reg *regs) -{ - struct trapframe *tf = td->td_frame; - - bcopy(regs->r, &tf->tf_r0, sizeof(regs->r)); - tf->tf_usr_sp = regs->r_sp; - tf->tf_usr_lr = regs->r_lr; - tf->tf_pc = regs->r_pc; - tf->tf_spsr &= ~PSR_FLAGS; - tf->tf_spsr |= regs->r_cpsr & PSR_FLAGS; - return (0); -} - -int -set_fpregs(struct thread *td, struct fpreg *regs) -{ - return (0); -} - -int -fill_dbregs(struct thread *td, struct dbreg *regs) -{ - return (0); -} -int -set_dbregs(struct thread *td, struct dbreg *regs) -{ - return (0); -} - - -static int -ptrace_read_int(struct thread *td, vm_offset_t addr, uint32_t *v) -{ - - if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v)) - return (ENOMEM); - return (0); -} - -static int -ptrace_write_int(struct thread *td, vm_offset_t addr, uint32_t v) -{ - - if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v)) - return (ENOMEM); - return (0); -} - -static u_int -ptrace_get_usr_reg(void *cookie, int reg) -{ - int ret; - struct thread *td = cookie; - - KASSERT(((reg >= 0) && (reg <= ARM_REG_NUM_PC)), - ("reg is outside range")); - - switch(reg) { - case ARM_REG_NUM_PC: - ret = td->td_frame->tf_pc; - break; - case ARM_REG_NUM_LR: - ret = td->td_frame->tf_usr_lr; - break; - case ARM_REG_NUM_SP: - ret = td->td_frame->tf_usr_sp; - break; - default: - ret = *((register_t*)&td->td_frame->tf_r0 + reg); - break; - } - - return (ret); -} - -static u_int -ptrace_get_usr_int(void* cookie, vm_offset_t offset, u_int* val) -{ - struct thread *td = cookie; - u_int error; - - error = ptrace_read_int(td, offset, val); - - return (error); -} - -/** - * This function parses current instruction opcode and decodes - * any possible jump (change in PC) which might occur after - * the instruction is executed. - * - * @param td Thread structure of analysed task - * @param cur_instr Currently executed instruction - * @param alt_next_address Pointer to the variable where - * the destination address of the - * jump instruction shall be stored. - * - * @return <0> when jump is possible - * otherwise - */ -static int -ptrace_get_alternative_next(struct thread *td, uint32_t cur_instr, - uint32_t *alt_next_address) -{ - int error; - - if (inst_branch(cur_instr) || inst_call(cur_instr) || - inst_return(cur_instr)) { - error = arm_predict_branch(td, cur_instr, td->td_frame->tf_pc, - alt_next_address, ptrace_get_usr_reg, ptrace_get_usr_int); - - return (error); - } - - return (EINVAL); -} - -int -ptrace_single_step(struct thread *td) -{ - struct proc *p; - int error, error_alt; - uint32_t cur_instr, alt_next = 0; - - /* TODO: This needs to be updated for Thumb-2 */ - if ((td->td_frame->tf_spsr & PSR_T) != 0) - return (EINVAL); - - KASSERT(td->td_md.md_ptrace_instr == 0, - ("Didn't clear single step")); - KASSERT(td->td_md.md_ptrace_instr_alt == 0, - ("Didn't clear alternative single step")); - p = td->td_proc; - PROC_UNLOCK(p); - - error = ptrace_read_int(td, td->td_frame->tf_pc, - &cur_instr); - if (error) - goto out; - - error = ptrace_read_int(td, td->td_frame->tf_pc + INSN_SIZE, - &td->td_md.md_ptrace_instr); - if (error == 0) { - error = ptrace_write_int(td, td->td_frame->tf_pc + INSN_SIZE, - PTRACE_BREAKPOINT); - if (error) { - td->td_md.md_ptrace_instr = 0; - } else { - td->td_md.md_ptrace_addr = td->td_frame->tf_pc + - INSN_SIZE; - } - } - - error_alt = ptrace_get_alternative_next(td, cur_instr, &alt_next); - if (error_alt == 0) { - error_alt = ptrace_read_int(td, alt_next, - &td->td_md.md_ptrace_instr_alt); - if (error_alt) { - td->td_md.md_ptrace_instr_alt = 0; - } else { - error_alt = ptrace_write_int(td, alt_next, - PTRACE_BREAKPOINT); - if (error_alt) - td->td_md.md_ptrace_instr_alt = 0; - else - td->td_md.md_ptrace_addr_alt = alt_next; - } - } - -out: - PROC_LOCK(p); - return ((error != 0) && (error_alt != 0)); -} - -int -ptrace_clear_single_step(struct thread *td) -{ - struct proc *p; - - /* TODO: This needs to be updated for Thumb-2 */ - if ((td->td_frame->tf_spsr & PSR_T) != 0) - return (EINVAL); - - if (td->td_md.md_ptrace_instr != 0) { - p = td->td_proc; - PROC_UNLOCK(p); - ptrace_write_int(td, td->td_md.md_ptrace_addr, - td->td_md.md_ptrace_instr); - PROC_LOCK(p); - td->td_md.md_ptrace_instr = 0; - } - - if (td->td_md.md_ptrace_instr_alt != 0) { - p = td->td_proc; - PROC_UNLOCK(p); - ptrace_write_int(td, td->td_md.md_ptrace_addr_alt, - td->td_md.md_ptrace_instr_alt); - PROC_LOCK(p); - td->td_md.md_ptrace_instr_alt = 0; - } - - return (0); -} - -int -ptrace_set_pc(struct thread *td, unsigned long addr) -{ - td->td_frame->tf_pc = addr; - return (0); -} - void cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) { @@ -919,9 +556,6 @@ set_mcontext(struct thread *td, mcontext_t *mcp) return (0); } -/* - * MPSAFE - */ int sys_sigreturn(td, uap) struct thread *td; @@ -953,7 +587,6 @@ sys_sigreturn(td, uap) return (EJUSTRETURN); } - /* * Construct a PCB from a trapframe. This is called from kdb_trap() where * we want to start a backtrace from the function that caused us to enter @@ -978,68 +611,6 @@ makectx(struct trapframe *tf, struct pcb *pcb) pcb->pcb_regs.sf_sp = tf->tf_usr_sp; } -/* - * Fake up a boot descriptor table - */ -vm_offset_t -fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr, - size_t dtb_size) -{ -#ifdef DDB - vm_offset_t zstart = 0, zend = 0; -#endif - vm_offset_t lastaddr; - int i = 0; - static uint32_t fake_preload[35]; - - fake_preload[i++] = MODINFO_NAME; - fake_preload[i++] = strlen("kernel") + 1; - strcpy((char*)&fake_preload[i++], "kernel"); - i += 1; - fake_preload[i++] = MODINFO_TYPE; - fake_preload[i++] = strlen("elf kernel") + 1; - strcpy((char*)&fake_preload[i++], "elf kernel"); - i += 2; - fake_preload[i++] = MODINFO_ADDR; - fake_preload[i++] = sizeof(vm_offset_t); - fake_preload[i++] = KERNVIRTADDR; - fake_preload[i++] = MODINFO_SIZE; - fake_preload[i++] = sizeof(uint32_t); - fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR; -#ifdef DDB - if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) { - fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM; - fake_preload[i++] = sizeof(vm_offset_t); - fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4); - fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM; - fake_preload[i++] = sizeof(vm_offset_t); - fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8); - lastaddr = *(uint32_t *)(KERNVIRTADDR + 8); - zend = lastaddr; - zstart = *(uint32_t *)(KERNVIRTADDR + 4); - db_fetch_ksymtab(zstart, zend); - } else -#endif - lastaddr = (vm_offset_t)&end; - if (dtb_ptr != NULL) { - /* Copy DTB to KVA space and insert it into module chain. */ - lastaddr = roundup(lastaddr, sizeof(int)); - fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP; - fake_preload[i++] = sizeof(uint32_t); - fake_preload[i++] = (uint32_t)lastaddr; - memmove((void *)lastaddr, dtb_ptr, dtb_size); - lastaddr += dtb_size; - lastaddr = roundup(lastaddr, sizeof(int)); - } - fake_preload[i++] = 0; - fake_preload[i] = 0; - preload_metadata = (void *)fake_preload; - - init_static_kenv(NULL, 0); - - return (lastaddr); -} - void pcpu0_init(void) { @@ -1050,208 +621,6 @@ pcpu0_init(void) PCPU_SET(curthread, &thread0); } -#if defined(LINUX_BOOT_ABI) - -/* Convert the U-Boot command line into FreeBSD kenv and boot options. */ -static void -cmdline_set_env(char *cmdline, const char *guard) -{ - char *cmdline_next, *env; - size_t size, guard_len; - int i; - - size = strlen(cmdline); - /* Skip leading spaces. */ - for (; isspace(*cmdline) && (size > 0); cmdline++) - size--; - - /* Test and remove guard. */ - if (guard != NULL && guard[0] != '\0') { - guard_len = strlen(guard); - if (strncasecmp(cmdline, guard, guard_len) != 0) - return; - cmdline += guard_len; - size -= guard_len; - } - - /* Skip leading spaces. */ - for (; isspace(*cmdline) && (size > 0); cmdline++) - size--; - - /* Replace ',' with '\0'. */ - /* TODO: implement escaping for ',' character. */ - cmdline_next = cmdline; - while(strsep(&cmdline_next, ",") != NULL) - ; - init_static_kenv(cmdline, 0); - /* Parse boothowto. */ - for (i = 0; howto_names[i].ev != NULL; i++) { - env = kern_getenv(howto_names[i].ev); - if (env != NULL) { - if (strtoul(env, NULL, 10) != 0) - boothowto |= howto_names[i].mask; - freeenv(env); - } - } -} - -vm_offset_t -linux_parse_boot_param(struct arm_boot_params *abp) -{ - struct arm_lbabi_tag *walker; - uint32_t revision; - uint64_t serial; - int size; - vm_offset_t lastaddr; -#ifdef FDT - struct fdt_header *dtb_ptr; - uint32_t dtb_size; -#endif - - /* - * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2 - * is atags or dtb pointer. If all of these aren't satisfied, - * then punt. Unfortunately, it looks like DT enabled kernels - * doesn't uses board type and U-Boot delivers 0 in r1 for them. - */ - if (abp->abp_r0 != 0 || abp->abp_r2 == 0) - return (0); -#ifdef FDT - /* Test if r2 point to valid DTB. */ - dtb_ptr = (struct fdt_header *)abp->abp_r2; - if (fdt_check_header(dtb_ptr) == 0) { - dtb_size = fdt_totalsize(dtb_ptr); - return (fake_preload_metadata(abp, dtb_ptr, dtb_size)); - } -#endif - - board_id = abp->abp_r1; - walker = (struct arm_lbabi_tag *)abp->abp_r2; - - if (ATAG_TAG(walker) != ATAG_CORE) - return 0; - - atag_list = walker; - while (ATAG_TAG(walker) != ATAG_NONE) { - switch (ATAG_TAG(walker)) { - case ATAG_CORE: - break; - case ATAG_MEM: - arm_physmem_hardware_region(walker->u.tag_mem.start, - walker->u.tag_mem.size); - break; - case ATAG_INITRD2: - break; - case ATAG_SERIAL: - serial = walker->u.tag_sn.high; - serial <<= 32; - serial |= walker->u.tag_sn.low; - board_set_serial(serial); - break; - case ATAG_REVISION: - revision = walker->u.tag_rev.rev; - board_set_revision(revision); - break; - case ATAG_CMDLINE: - size = ATAG_SIZE(walker) - - sizeof(struct arm_lbabi_header); - size = min(size, LBABI_MAX_COMMAND_LINE); - strncpy(linux_command_line, walker->u.tag_cmd.command, - size); - linux_command_line[size] = '\0'; - break; - default: - break; - } - walker = ATAG_NEXT(walker); - } - - /* Save a copy for later */ - bcopy(atag_list, atags, - (char *)walker - (char *)atag_list + ATAG_SIZE(walker)); - - lastaddr = fake_preload_metadata(abp, NULL, 0); - cmdline_set_env(linux_command_line, CMDLINE_GUARD); - return lastaddr; -} -#endif - -#if defined(FREEBSD_BOOT_LOADER) -vm_offset_t -freebsd_parse_boot_param(struct arm_boot_params *abp) -{ - vm_offset_t lastaddr = 0; - void *mdp; - void *kmdp; -#ifdef DDB - vm_offset_t ksym_start; - vm_offset_t ksym_end; -#endif - - /* - * Mask metadata pointer: it is supposed to be on page boundary. If - * the first argument (mdp) doesn't point to a valid address the - * bootloader must have passed us something else than the metadata - * ptr, so we give up. Also give up if we cannot find metadta section - * the loader creates that we get all this data out of. - */ - - if ((mdp = (void *)(abp->abp_r0 & ~PAGE_MASK)) == NULL) - return 0; - preload_metadata = mdp; - kmdp = preload_search_by_type("elf kernel"); - if (kmdp == NULL) - return 0; - - boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); - loader_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); - init_static_kenv(loader_envp, 0); - lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t); -#ifdef DDB - ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); - ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); - db_fetch_ksymtab(ksym_start, ksym_end); -#endif - return lastaddr; -} -#endif - -vm_offset_t -default_parse_boot_param(struct arm_boot_params *abp) -{ - vm_offset_t lastaddr; - -#if defined(LINUX_BOOT_ABI) - if ((lastaddr = linux_parse_boot_param(abp)) != 0) - return lastaddr; -#endif -#if defined(FREEBSD_BOOT_LOADER) - if ((lastaddr = freebsd_parse_boot_param(abp)) != 0) - return lastaddr; -#endif - /* Fall back to hardcoded metadata. */ - lastaddr = fake_preload_metadata(abp, NULL, 0); - - return lastaddr; -} - -/* - * Stub version of the boot parameter parsing routine. We are - * called early in initarm, before even VM has been initialized. - * This routine needs to preserve any data that the boot loader - * has passed in before the kernel starts to grow past the end - * of the BSS, traditionally the place boot-loaders put this data. - * - * Since this is called so early, things that depend on the vm system - * being setup (including access to some SoC's serial ports), about - * all that can be done in this routine is to copy the arguments. - * - * This is the default boot parameter parsing routine. Individual - * kernels/boards can override this weak function with one of their - * own. We just fake metadata... - */ -__weak_reference(default_parse_boot_param, parse_boot_param); - /* * Initialize proc0 */ @@ -1269,111 +638,6 @@ init_proc0(vm_offset_t kstack) pcpup->pc_curpcb = thread0.td_pcb; } -int -arm_predict_branch(void *cookie, u_int insn, register_t pc, register_t *new_pc, - u_int (*fetch_reg)(void*, int), u_int (*read_int)(void*, vm_offset_t, u_int*)) -{ - u_int addr, nregs, offset = 0; - int error = 0; - - switch ((insn >> 24) & 0xf) { - case 0x2: /* add pc, reg1, #value */ - case 0x0: /* add pc, reg1, reg2, lsl #offset */ - addr = fetch_reg(cookie, (insn >> 16) & 0xf); - if (((insn >> 16) & 0xf) == 15) - addr += 8; - if (insn & 0x0200000) { - offset = (insn >> 7) & 0x1e; - offset = (insn & 0xff) << (32 - offset) | - (insn & 0xff) >> offset; - } else { - - offset = fetch_reg(cookie, insn & 0x0f); - if ((insn & 0x0000ff0) != 0x00000000) { - if (insn & 0x10) - nregs = fetch_reg(cookie, - (insn >> 8) & 0xf); - else - nregs = (insn >> 7) & 0x1f; - switch ((insn >> 5) & 3) { - case 0: - /* lsl */ - offset = offset << nregs; - break; - case 1: - /* lsr */ - offset = offset >> nregs; - break; - default: - break; /* XXX */ - } - - } - *new_pc = addr + offset; - return (0); - - } - - case 0xa: /* b ... */ - case 0xb: /* bl ... */ - addr = ((insn << 2) & 0x03ffffff); - if (addr & 0x02000000) - addr |= 0xfc000000; - *new_pc = (pc + 8 + addr); - return (0); - case 0x7: /* ldr pc, [pc, reg, lsl #2] */ - addr = fetch_reg(cookie, insn & 0xf); - addr = pc + 8 + (addr << 2); - error = read_int(cookie, addr, &addr); - *new_pc = addr; - return (error); - case 0x1: /* mov pc, reg */ - *new_pc = fetch_reg(cookie, insn & 0xf); - return (0); - case 0x4: - case 0x5: /* ldr pc, [reg] */ - addr = fetch_reg(cookie, (insn >> 16) & 0xf); - /* ldr pc, [reg, #offset] */ - if (insn & (1 << 24)) - offset = insn & 0xfff; - if (insn & 0x00800000) - addr += offset; - else - addr -= offset; - error = read_int(cookie, addr, &addr); - *new_pc = addr; - - return (error); - case 0x8: /* ldmxx reg, {..., pc} */ - case 0x9: - addr = fetch_reg(cookie, (insn >> 16) & 0xf); - nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555); - nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333); - nregs = (nregs + (nregs >> 4)) & 0x0f0f; - nregs = (nregs + (nregs >> 8)) & 0x001f; - switch ((insn >> 23) & 0x3) { - case 0x0: /* ldmda */ - addr = addr - 0; - break; - case 0x1: /* ldmia */ - addr = addr + 0 + ((nregs - 1) << 2); - break; - case 0x2: /* ldmdb */ - addr = addr - 4; - break; - case 0x3: /* ldmib */ - addr = addr + 4 + ((nregs - 1) << 2); - break; - } - error = read_int(cookie, addr, &addr); - *new_pc = addr; - - return (error); - default: - return (EINVAL); - } -} - #if __ARM_ARCH >= 6 void set_stackptrs(int cpu) @@ -1400,146 +664,8 @@ set_stackptrs(int cpu) } #endif -#ifdef EFI -static void -add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr, - int *mrcnt) -{ - struct efi_md *map, *p; - const char *type; - size_t efisz, memory_size; - int ndesc, i, j; - - static const char *types[] = { - "Reserved", - "LoaderCode", - "LoaderData", - "BootServicesCode", - "BootServicesData", - "RuntimeServicesCode", - "RuntimeServicesData", - "ConventionalMemory", - "UnusableMemory", - "ACPIReclaimMemory", - "ACPIMemoryNVS", - "MemoryMappedIO", - "MemoryMappedIOPortSpace", - "PalCode", - "PersistentMemory" - }; - - *mrcnt = 0; - - /* - * Memory map data provided by UEFI via the GetMemoryMap - * Boot Services API. - */ - efisz = roundup2(sizeof(struct efi_map_header), 0x10); - map = (struct efi_md *)((uint8_t *)efihdr + efisz); - - if (efihdr->descriptor_size == 0) - return; - ndesc = efihdr->memory_size / efihdr->descriptor_size; - - if (boothowto & RB_VERBOSE) - printf("%23s %12s %12s %8s %4s\n", - "Type", "Physical", "Virtual", "#Pages", "Attr"); - - memory_size = 0; - for (i = 0, j = 0, p = map; i < ndesc; i++, - p = efi_next_descriptor(p, efihdr->descriptor_size)) { - if (boothowto & RB_VERBOSE) { - if (p->md_type < nitems(types)) - type = types[p->md_type]; - else - type = ""; - printf("%23s %012llx %12p %08llx ", type, p->md_phys, - p->md_virt, p->md_pages); - if (p->md_attr & EFI_MD_ATTR_UC) - printf("UC "); - if (p->md_attr & EFI_MD_ATTR_WC) - printf("WC "); - if (p->md_attr & EFI_MD_ATTR_WT) - printf("WT "); - if (p->md_attr & EFI_MD_ATTR_WB) - printf("WB "); - if (p->md_attr & EFI_MD_ATTR_UCE) - printf("UCE "); - if (p->md_attr & EFI_MD_ATTR_WP) - printf("WP "); - if (p->md_attr & EFI_MD_ATTR_RP) - printf("RP "); - if (p->md_attr & EFI_MD_ATTR_XP) - printf("XP "); - if (p->md_attr & EFI_MD_ATTR_NV) - printf("NV "); - if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE) - printf("MORE_RELIABLE "); - if (p->md_attr & EFI_MD_ATTR_RO) - printf("RO "); - if (p->md_attr & EFI_MD_ATTR_RT) - printf("RUNTIME"); - printf("\n"); - } - - switch (p->md_type) { - case EFI_MD_TYPE_CODE: - case EFI_MD_TYPE_DATA: - case EFI_MD_TYPE_BS_CODE: - case EFI_MD_TYPE_BS_DATA: - case EFI_MD_TYPE_FREE: - /* - * We're allowed to use any entry with these types. - */ - break; - default: - continue; - } - - j++; - if (j >= FDT_MEM_REGIONS) - break; - - mr[j].mr_start = p->md_phys; - mr[j].mr_size = p->md_pages * PAGE_SIZE; - memory_size += mr[j].mr_size; - } - - *mrcnt = j; -} -#endif /* EFI */ #ifdef FDT -static char * -kenv_next(char *cp) -{ - - if (cp != NULL) { - while (*cp != 0) - cp++; - cp++; - if (*cp == 0) - cp = NULL; - } - return (cp); -} - -static void -print_kenv(void) -{ - char *cp; - - debugf("loader passed (static) kenv:\n"); - if (loader_envp == NULL) { - debugf(" no env, null ptr\n"); - return; - } - debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp); - - for (cp = loader_envp; cp != NULL; cp = kenv_next(cp)) - debugf(" %x %s\n", (uint32_t)cp, cp); -} - #if __ARM_ARCH < 6 void * initarm(struct arm_boot_params *abp) @@ -1744,7 +870,7 @@ initarm(struct arm_boot_params *abp) debugf(" arg1 kmdp = 0x%08x\n", (uint32_t)kmdp); debugf(" boothowto = 0x%08x\n", boothowto); debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp); - print_kenv(); + arm_print_kenv(); env = kern_getenv("kernelname"); if (env != NULL) { @@ -1853,16 +979,14 @@ initarm(struct arm_boot_params *abp) panic("OF_init failed with the found device tree"); #if defined(LINUX_BOOT_ABI) - if (loader_envp == NULL && fdt_get_chosen_bootargs(linux_command_line, - LBABI_MAX_COMMAND_LINE) == 0) - cmdline_set_env(linux_command_line, CMDLINE_GUARD); + arm_parse_fdt_bootargs(); #endif #ifdef EFI efihdr = (struct efi_map_header *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_EFI_MAP); if (efihdr != NULL) { - add_efi_map_entries(efihdr, mem_regions, &mem_regions_sz); + arm_add_efi_map_entries(efihdr, mem_regions, &mem_regions_sz); } else #endif { @@ -1952,7 +1076,7 @@ initarm(struct arm_boot_params *abp) debugf(" boothowto = 0x%08x\n", boothowto); debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp); debugf(" lastaddr1: 0x%08x\n", lastaddr); - print_kenv(); + arm_print_kenv(); env = kern_getenv("kernelname"); if (env != NULL) diff --git a/sys/arm/arm/machdep_boot.c b/sys/arm/arm/machdep_boot.c new file mode 100644 index 000000000000..cb2c68203f6e --- /dev/null +++ b/sys/arm/arm/machdep_boot.c @@ -0,0 +1,519 @@ +/*- + * Copyright (c) 2004 Olivier Houchard + * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_platform.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#if defined(LINUX_BOOT_ABI) +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef FDT +#include +#include +#endif + +#ifdef EFI +#include +#endif + +#ifdef DEBUG +#define debugf(fmt, args...) printf(fmt, ##args) +#else +#define debugf(fmt, args...) +#endif + +extern int *end; + +static uint32_t board_revision; +/* hex representation of uint64_t */ +static char board_serial[32]; +static char *loader_envp; + +#if defined(LINUX_BOOT_ABI) +#define LBABI_MAX_BANKS 10 +#define CMDLINE_GUARD "FreeBSD:" +static uint32_t board_id; +static struct arm_lbabi_tag *atag_list; +static char linux_command_line[LBABI_MAX_COMMAND_LINE + 1]; +static char atags[LBABI_MAX_COMMAND_LINE * 2]; +#endif /* defined(LINUX_BOOT_ABI) */ + +SYSCTL_NODE(_hw, OID_AUTO, board, CTLFLAG_RD, 0, "Board attributes"); +SYSCTL_UINT(_hw_board, OID_AUTO, revision, CTLFLAG_RD, + &board_revision, 0, "Board revision"); +SYSCTL_STRING(_hw_board, OID_AUTO, serial, CTLFLAG_RD, + board_serial, 0, "Board serial"); + +int vfp_exists; +SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD, + &vfp_exists, 0, "Floating point support enabled"); + +void +board_set_serial(uint64_t serial) +{ + + snprintf(board_serial, sizeof(board_serial)-1, + "%016jx", serial); +} + +void +board_set_revision(uint32_t revision) +{ + + board_revision = revision; +} + +static char * +kenv_next(char *cp) +{ + + if (cp != NULL) { + while (*cp != 0) + cp++; + cp++; + if (*cp == 0) + cp = NULL; + } + return (cp); +} + +void +arm_print_kenv(void) +{ + char *cp; + + debugf("loader passed (static) kenv:\n"); + if (loader_envp == NULL) { + debugf(" no env, null ptr\n"); + return; + } + debugf(" loader_envp = 0x%08x\n", (uint32_t)loader_envp); + + for (cp = loader_envp; cp != NULL; cp = kenv_next(cp)) + debugf(" %x %s\n", (uint32_t)cp, cp); +} + + +#if defined(LINUX_BOOT_ABI) + +/* Convert the U-Boot command line into FreeBSD kenv and boot options. */ +static void +cmdline_set_env(char *cmdline, const char *guard) +{ + char *cmdline_next, *env; + size_t size, guard_len; + int i; + + size = strlen(cmdline); + /* Skip leading spaces. */ + for (; isspace(*cmdline) && (size > 0); cmdline++) + size--; + + /* Test and remove guard. */ + if (guard != NULL && guard[0] != '\0') { + guard_len = strlen(guard); + if (strncasecmp(cmdline, guard, guard_len) != 0) + return; + cmdline += guard_len; + size -= guard_len; + } + + /* Skip leading spaces. */ + for (; isspace(*cmdline) && (size > 0); cmdline++) + size--; + + /* Replace ',' with '\0'. */ + /* TODO: implement escaping for ',' character. */ + cmdline_next = cmdline; + while(strsep(&cmdline_next, ",") != NULL) + ; + init_static_kenv(cmdline, 0); + /* Parse boothowto. */ + for (i = 0; howto_names[i].ev != NULL; i++) { + env = kern_getenv(howto_names[i].ev); + if (env != NULL) { + if (strtoul(env, NULL, 10) != 0) + boothowto |= howto_names[i].mask; + freeenv(env); + } + } +} + +void arm_parse_fdt_bootargs(void) +{ + +#ifdef FDT + if (loader_envp == NULL && fdt_get_chosen_bootargs(linux_command_line, + LBABI_MAX_COMMAND_LINE) == 0) + cmdline_set_env(linux_command_line, CMDLINE_GUARD); +#endif +} + +static vm_offset_t +linux_parse_boot_param(struct arm_boot_params *abp) +{ + struct arm_lbabi_tag *walker; + uint32_t revision; + uint64_t serial; + int size; + vm_offset_t lastaddr; +#ifdef FDT + struct fdt_header *dtb_ptr; + uint32_t dtb_size; +#endif + + /* + * Linux boot ABI: r0 = 0, r1 is the board type (!= 0) and r2 + * is atags or dtb pointer. If all of these aren't satisfied, + * then punt. Unfortunately, it looks like DT enabled kernels + * doesn't uses board type and U-Boot delivers 0 in r1 for them. + */ + if (abp->abp_r0 != 0 || abp->abp_r2 == 0) + return (0); +#ifdef FDT + /* Test if r2 point to valid DTB. */ + dtb_ptr = (struct fdt_header *)abp->abp_r2; + if (fdt_check_header(dtb_ptr) == 0) { + dtb_size = fdt_totalsize(dtb_ptr); + return (fake_preload_metadata(abp, dtb_ptr, dtb_size)); + } +#endif + + board_id = abp->abp_r1; + walker = (struct arm_lbabi_tag *)abp->abp_r2; + + if (ATAG_TAG(walker) != ATAG_CORE) + return 0; + + atag_list = walker; + while (ATAG_TAG(walker) != ATAG_NONE) { + switch (ATAG_TAG(walker)) { + case ATAG_CORE: + break; + case ATAG_MEM: + arm_physmem_hardware_region(walker->u.tag_mem.start, + walker->u.tag_mem.size); + break; + case ATAG_INITRD2: + break; + case ATAG_SERIAL: + serial = walker->u.tag_sn.high; + serial <<= 32; + serial |= walker->u.tag_sn.low; + board_set_serial(serial); + break; + case ATAG_REVISION: + revision = walker->u.tag_rev.rev; + board_set_revision(revision); + break; + case ATAG_CMDLINE: + size = ATAG_SIZE(walker) - + sizeof(struct arm_lbabi_header); + size = min(size, LBABI_MAX_COMMAND_LINE); + strncpy(linux_command_line, walker->u.tag_cmd.command, + size); + linux_command_line[size] = '\0'; + break; + default: + break; + } + walker = ATAG_NEXT(walker); + } + + /* Save a copy for later */ + bcopy(atag_list, atags, + (char *)walker - (char *)atag_list + ATAG_SIZE(walker)); + + lastaddr = fake_preload_metadata(abp, NULL, 0); + cmdline_set_env(linux_command_line, CMDLINE_GUARD); + return lastaddr; +} +#endif + +#if defined(FREEBSD_BOOT_LOADER) +static vm_offset_t +freebsd_parse_boot_param(struct arm_boot_params *abp) +{ + vm_offset_t lastaddr = 0; + void *mdp; + void *kmdp; +#ifdef DDB + vm_offset_t ksym_start; + vm_offset_t ksym_end; +#endif + + /* + * Mask metadata pointer: it is supposed to be on page boundary. If + * the first argument (mdp) doesn't point to a valid address the + * bootloader must have passed us something else than the metadata + * ptr, so we give up. Also give up if we cannot find metadta section + * the loader creates that we get all this data out of. + */ + + if ((mdp = (void *)(abp->abp_r0 & ~PAGE_MASK)) == NULL) + return 0; + preload_metadata = mdp; + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + return 0; + + boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); + loader_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); + init_static_kenv(loader_envp, 0); + lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t); +#ifdef DDB + ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t); + ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t); + db_fetch_ksymtab(ksym_start, ksym_end); +#endif + return lastaddr; +} +#endif + +vm_offset_t +default_parse_boot_param(struct arm_boot_params *abp) +{ + vm_offset_t lastaddr; + +#if defined(LINUX_BOOT_ABI) + if ((lastaddr = linux_parse_boot_param(abp)) != 0) + return lastaddr; +#endif +#if defined(FREEBSD_BOOT_LOADER) + if ((lastaddr = freebsd_parse_boot_param(abp)) != 0) + return lastaddr; +#endif + /* Fall back to hardcoded metadata. */ + lastaddr = fake_preload_metadata(abp, NULL, 0); + + return lastaddr; +} + +/* + * Stub version of the boot parameter parsing routine. We are + * called early in initarm, before even VM has been initialized. + * This routine needs to preserve any data that the boot loader + * has passed in before the kernel starts to grow past the end + * of the BSS, traditionally the place boot-loaders put this data. + * + * Since this is called so early, things that depend on the vm system + * being setup (including access to some SoC's serial ports), about + * all that can be done in this routine is to copy the arguments. + * + * This is the default boot parameter parsing routine. Individual + * kernels/boards can override this weak function with one of their + * own. We just fake metadata... + */ +__weak_reference(default_parse_boot_param, parse_boot_param); + + +/* + * Fake up a boot descriptor table + */ +vm_offset_t +fake_preload_metadata(struct arm_boot_params *abp __unused, void *dtb_ptr, + size_t dtb_size) +{ +#ifdef DDB + vm_offset_t zstart = 0, zend = 0; +#endif + vm_offset_t lastaddr; + int i = 0; + static uint32_t fake_preload[35]; + + fake_preload[i++] = MODINFO_NAME; + fake_preload[i++] = strlen("kernel") + 1; + strcpy((char*)&fake_preload[i++], "kernel"); + i += 1; + fake_preload[i++] = MODINFO_TYPE; + fake_preload[i++] = strlen("elf kernel") + 1; + strcpy((char*)&fake_preload[i++], "elf kernel"); + i += 2; + fake_preload[i++] = MODINFO_ADDR; + fake_preload[i++] = sizeof(vm_offset_t); + fake_preload[i++] = KERNVIRTADDR; + fake_preload[i++] = MODINFO_SIZE; + fake_preload[i++] = sizeof(uint32_t); + fake_preload[i++] = (uint32_t)&end - KERNVIRTADDR; +#ifdef DDB + if (*(uint32_t *)KERNVIRTADDR == MAGIC_TRAMP_NUMBER) { + fake_preload[i++] = MODINFO_METADATA|MODINFOMD_SSYM; + fake_preload[i++] = sizeof(vm_offset_t); + fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 4); + fake_preload[i++] = MODINFO_METADATA|MODINFOMD_ESYM; + fake_preload[i++] = sizeof(vm_offset_t); + fake_preload[i++] = *(uint32_t *)(KERNVIRTADDR + 8); + lastaddr = *(uint32_t *)(KERNVIRTADDR + 8); + zend = lastaddr; + zstart = *(uint32_t *)(KERNVIRTADDR + 4); + db_fetch_ksymtab(zstart, zend); + } else +#endif + lastaddr = (vm_offset_t)&end; + if (dtb_ptr != NULL) { + /* Copy DTB to KVA space and insert it into module chain. */ + lastaddr = roundup(lastaddr, sizeof(int)); + fake_preload[i++] = MODINFO_METADATA | MODINFOMD_DTBP; + fake_preload[i++] = sizeof(uint32_t); + fake_preload[i++] = (uint32_t)lastaddr; + memmove((void *)lastaddr, dtb_ptr, dtb_size); + lastaddr += dtb_size; + lastaddr = roundup(lastaddr, sizeof(int)); + } + fake_preload[i++] = 0; + fake_preload[i] = 0; + preload_metadata = (void *)fake_preload; + + init_static_kenv(NULL, 0); + + return (lastaddr); +} + +#ifdef EFI +void +arm_add_efi_map_entries(struct efi_map_header *efihdr, struct mem_region *mr, + int *mrcnt) +{ + struct efi_md *map, *p; + const char *type; + size_t efisz, memory_size; + int ndesc, i, j; + + static const char *types[] = { + "Reserved", + "LoaderCode", + "LoaderData", + "BootServicesCode", + "BootServicesData", + "RuntimeServicesCode", + "RuntimeServicesData", + "ConventionalMemory", + "UnusableMemory", + "ACPIReclaimMemory", + "ACPIMemoryNVS", + "MemoryMappedIO", + "MemoryMappedIOPortSpace", + "PalCode", + "PersistentMemory" + }; + + *mrcnt = 0; + + /* + * Memory map data provided by UEFI via the GetMemoryMap + * Boot Services API. + */ + efisz = roundup2(sizeof(struct efi_map_header), 0x10); + map = (struct efi_md *)((uint8_t *)efihdr + efisz); + + if (efihdr->descriptor_size == 0) + return; + ndesc = efihdr->memory_size / efihdr->descriptor_size; + + if (boothowto & RB_VERBOSE) + printf("%23s %12s %12s %8s %4s\n", + "Type", "Physical", "Virtual", "#Pages", "Attr"); + + memory_size = 0; + for (i = 0, j = 0, p = map; i < ndesc; i++, + p = efi_next_descriptor(p, efihdr->descriptor_size)) { + if (boothowto & RB_VERBOSE) { + if (p->md_type < nitems(types)) + type = types[p->md_type]; + else + type = ""; + printf("%23s %012llx %12p %08llx ", type, p->md_phys, + p->md_virt, p->md_pages); + if (p->md_attr & EFI_MD_ATTR_UC) + printf("UC "); + if (p->md_attr & EFI_MD_ATTR_WC) + printf("WC "); + if (p->md_attr & EFI_MD_ATTR_WT) + printf("WT "); + if (p->md_attr & EFI_MD_ATTR_WB) + printf("WB "); + if (p->md_attr & EFI_MD_ATTR_UCE) + printf("UCE "); + if (p->md_attr & EFI_MD_ATTR_WP) + printf("WP "); + if (p->md_attr & EFI_MD_ATTR_RP) + printf("RP "); + if (p->md_attr & EFI_MD_ATTR_XP) + printf("XP "); + if (p->md_attr & EFI_MD_ATTR_NV) + printf("NV "); + if (p->md_attr & EFI_MD_ATTR_MORE_RELIABLE) + printf("MORE_RELIABLE "); + if (p->md_attr & EFI_MD_ATTR_RO) + printf("RO "); + if (p->md_attr & EFI_MD_ATTR_RT) + printf("RUNTIME"); + printf("\n"); + } + + switch (p->md_type) { + case EFI_MD_TYPE_CODE: + case EFI_MD_TYPE_DATA: + case EFI_MD_TYPE_BS_CODE: + case EFI_MD_TYPE_BS_DATA: + case EFI_MD_TYPE_FREE: + /* + * We're allowed to use any entry with these types. + */ + break; + default: + continue; + } + + j++; + if (j >= FDT_MEM_REGIONS) + break; + + mr[j].mr_start = p->md_phys; + mr[j].mr_size = p->md_pages * PAGE_SIZE; + memory_size += mr[j].mr_size; + } + + *mrcnt = j; +} +#endif /* EFI */ diff --git a/sys/arm/arm/machdep_kdb.c b/sys/arm/arm/machdep_kdb.c new file mode 100644 index 000000000000..f70c1f15d245 --- /dev/null +++ b/sys/arm/arm/machdep_kdb.c @@ -0,0 +1,143 @@ +/* $NetBSD: arm32_machdep.c,v 1.44 2004/03/24 15:34:47 atatat Exp $ */ + +/*- + * Copyright (c) 2004 Olivier Houchard + * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "opt_ddb.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include + +#ifdef DDB +#include + +#if __ARM_ARCH >= 6 + +DB_SHOW_COMMAND(cp15, db_show_cp15) +{ + u_int reg; + + reg = cp15_midr_get(); + db_printf("Cpu ID: 0x%08x\n", reg); + reg = cp15_ctr_get(); + db_printf("Current Cache Lvl ID: 0x%08x\n",reg); + + reg = cp15_sctlr_get(); + db_printf("Ctrl: 0x%08x\n",reg); + reg = cp15_actlr_get(); + db_printf("Aux Ctrl: 0x%08x\n",reg); + + reg = cp15_id_pfr0_get(); + db_printf("Processor Feat 0: 0x%08x\n", reg); + reg = cp15_id_pfr1_get(); + db_printf("Processor Feat 1: 0x%08x\n", reg); + reg = cp15_id_dfr0_get(); + db_printf("Debug Feat 0: 0x%08x\n", reg); + reg = cp15_id_afr0_get(); + db_printf("Auxiliary Feat 0: 0x%08x\n", reg); + reg = cp15_id_mmfr0_get(); + db_printf("Memory Model Feat 0: 0x%08x\n", reg); + reg = cp15_id_mmfr1_get(); + db_printf("Memory Model Feat 1: 0x%08x\n", reg); + reg = cp15_id_mmfr2_get(); + db_printf("Memory Model Feat 2: 0x%08x\n", reg); + reg = cp15_id_mmfr3_get(); + db_printf("Memory Model Feat 3: 0x%08x\n", reg); + reg = cp15_ttbr_get(); + db_printf("TTB0: 0x%08x\n", reg); +} + +DB_SHOW_COMMAND(vtop, db_show_vtop) +{ + u_int reg; + + if (have_addr) { + cp15_ats1cpr_set(addr); + reg = cp15_par_get(); + db_printf("Physical address reg: 0x%08x\n",reg); + } else + db_printf("show vtop \n"); +} +#endif /* __ARM_ARCH >= 6 */ +#endif /* DDB */ + +int +fill_regs(struct thread *td, struct reg *regs) +{ + struct trapframe *tf = td->td_frame; + bcopy(&tf->tf_r0, regs->r, sizeof(regs->r)); + regs->r_sp = tf->tf_usr_sp; + regs->r_lr = tf->tf_usr_lr; + regs->r_pc = tf->tf_pc; + regs->r_cpsr = tf->tf_spsr; + return (0); +} +int +fill_fpregs(struct thread *td, struct fpreg *regs) +{ + bzero(regs, sizeof(*regs)); + return (0); +} + +int +set_regs(struct thread *td, struct reg *regs) +{ + struct trapframe *tf = td->td_frame; + + bcopy(regs->r, &tf->tf_r0, sizeof(regs->r)); + tf->tf_usr_sp = regs->r_sp; + tf->tf_usr_lr = regs->r_lr; + tf->tf_pc = regs->r_pc; + tf->tf_spsr &= ~PSR_FLAGS; + tf->tf_spsr |= regs->r_cpsr & PSR_FLAGS; + return (0); +} + +int +set_fpregs(struct thread *td, struct fpreg *regs) +{ + return (0); +} + +int +fill_dbregs(struct thread *td, struct dbreg *regs) +{ + return (0); +} +int +set_dbregs(struct thread *td, struct dbreg *regs) +{ + return (0); +} diff --git a/sys/arm/arm/machdep_ptrace.c b/sys/arm/arm/machdep_ptrace.c new file mode 100644 index 000000000000..5bd07d28eca7 --- /dev/null +++ b/sys/arm/arm/machdep_ptrace.c @@ -0,0 +1,325 @@ +/*- + * Copyright (c) 2004 Olivier Houchard + * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include + +static int +ptrace_read_int(struct thread *td, vm_offset_t addr, uint32_t *v) +{ + + if (proc_readmem(td, td->td_proc, addr, v, sizeof(*v)) != sizeof(*v)) + return (ENOMEM); + return (0); +} + +static int +ptrace_write_int(struct thread *td, vm_offset_t addr, uint32_t v) +{ + + if (proc_writemem(td, td->td_proc, addr, &v, sizeof(v)) != sizeof(v)) + return (ENOMEM); + return (0); +} + +static u_int +ptrace_get_usr_reg(void *cookie, int reg) +{ + int ret; + struct thread *td = cookie; + + KASSERT(((reg >= 0) && (reg <= ARM_REG_NUM_PC)), + ("reg is outside range")); + + switch(reg) { + case ARM_REG_NUM_PC: + ret = td->td_frame->tf_pc; + break; + case ARM_REG_NUM_LR: + ret = td->td_frame->tf_usr_lr; + break; + case ARM_REG_NUM_SP: + ret = td->td_frame->tf_usr_sp; + break; + default: + ret = *((register_t*)&td->td_frame->tf_r0 + reg); + break; + } + + return (ret); +} + +static u_int +ptrace_get_usr_int(void* cookie, vm_offset_t offset, u_int* val) +{ + struct thread *td = cookie; + u_int error; + + error = ptrace_read_int(td, offset, val); + + return (error); +} + +/** + * This function parses current instruction opcode and decodes + * any possible jump (change in PC) which might occur after + * the instruction is executed. + * + * @param td Thread structure of analysed task + * @param cur_instr Currently executed instruction + * @param alt_next_address Pointer to the variable where + * the destination address of the + * jump instruction shall be stored. + * + * @return <0> when jump is possible + * otherwise + */ +static int +ptrace_get_alternative_next(struct thread *td, uint32_t cur_instr, + uint32_t *alt_next_address) +{ + int error; + + if (inst_branch(cur_instr) || inst_call(cur_instr) || + inst_return(cur_instr)) { + error = arm_predict_branch(td, cur_instr, td->td_frame->tf_pc, + alt_next_address, ptrace_get_usr_reg, ptrace_get_usr_int); + + return (error); + } + + return (EINVAL); +} + +int +ptrace_single_step(struct thread *td) +{ + struct proc *p; + int error, error_alt; + uint32_t cur_instr, alt_next = 0; + + /* TODO: This needs to be updated for Thumb-2 */ + if ((td->td_frame->tf_spsr & PSR_T) != 0) + return (EINVAL); + + KASSERT(td->td_md.md_ptrace_instr == 0, + ("Didn't clear single step")); + KASSERT(td->td_md.md_ptrace_instr_alt == 0, + ("Didn't clear alternative single step")); + p = td->td_proc; + PROC_UNLOCK(p); + + error = ptrace_read_int(td, td->td_frame->tf_pc, + &cur_instr); + if (error) + goto out; + + error = ptrace_read_int(td, td->td_frame->tf_pc + INSN_SIZE, + &td->td_md.md_ptrace_instr); + if (error == 0) { + error = ptrace_write_int(td, td->td_frame->tf_pc + INSN_SIZE, + PTRACE_BREAKPOINT); + if (error) { + td->td_md.md_ptrace_instr = 0; + } else { + td->td_md.md_ptrace_addr = td->td_frame->tf_pc + + INSN_SIZE; + } + } + + error_alt = ptrace_get_alternative_next(td, cur_instr, &alt_next); + if (error_alt == 0) { + error_alt = ptrace_read_int(td, alt_next, + &td->td_md.md_ptrace_instr_alt); + if (error_alt) { + td->td_md.md_ptrace_instr_alt = 0; + } else { + error_alt = ptrace_write_int(td, alt_next, + PTRACE_BREAKPOINT); + if (error_alt) + td->td_md.md_ptrace_instr_alt = 0; + else + td->td_md.md_ptrace_addr_alt = alt_next; + } + } + +out: + PROC_LOCK(p); + return ((error != 0) && (error_alt != 0)); +} + +int +ptrace_clear_single_step(struct thread *td) +{ + struct proc *p; + + /* TODO: This needs to be updated for Thumb-2 */ + if ((td->td_frame->tf_spsr & PSR_T) != 0) + return (EINVAL); + + if (td->td_md.md_ptrace_instr != 0) { + p = td->td_proc; + PROC_UNLOCK(p); + ptrace_write_int(td, td->td_md.md_ptrace_addr, + td->td_md.md_ptrace_instr); + PROC_LOCK(p); + td->td_md.md_ptrace_instr = 0; + } + + if (td->td_md.md_ptrace_instr_alt != 0) { + p = td->td_proc; + PROC_UNLOCK(p); + ptrace_write_int(td, td->td_md.md_ptrace_addr_alt, + td->td_md.md_ptrace_instr_alt); + PROC_LOCK(p); + td->td_md.md_ptrace_instr_alt = 0; + } + + return (0); +} + +int +ptrace_set_pc(struct thread *td, unsigned long addr) +{ + td->td_frame->tf_pc = addr; + return (0); +} + +int +arm_predict_branch(void *cookie, u_int insn, register_t pc, register_t *new_pc, + u_int (*fetch_reg)(void*, int), + u_int (*read_int)(void*, vm_offset_t, u_int*)) +{ + u_int addr, nregs, offset = 0; + int error = 0; + + switch ((insn >> 24) & 0xf) { + case 0x2: /* add pc, reg1, #value */ + case 0x0: /* add pc, reg1, reg2, lsl #offset */ + addr = fetch_reg(cookie, (insn >> 16) & 0xf); + if (((insn >> 16) & 0xf) == 15) + addr += 8; + if (insn & 0x0200000) { + offset = (insn >> 7) & 0x1e; + offset = (insn & 0xff) << (32 - offset) | + (insn & 0xff) >> offset; + } else { + + offset = fetch_reg(cookie, insn & 0x0f); + if ((insn & 0x0000ff0) != 0x00000000) { + if (insn & 0x10) + nregs = fetch_reg(cookie, + (insn >> 8) & 0xf); + else + nregs = (insn >> 7) & 0x1f; + switch ((insn >> 5) & 3) { + case 0: + /* lsl */ + offset = offset << nregs; + break; + case 1: + /* lsr */ + offset = offset >> nregs; + break; + default: + break; /* XXX */ + } + + } + *new_pc = addr + offset; + return (0); + + } + + case 0xa: /* b ... */ + case 0xb: /* bl ... */ + addr = ((insn << 2) & 0x03ffffff); + if (addr & 0x02000000) + addr |= 0xfc000000; + *new_pc = (pc + 8 + addr); + return (0); + case 0x7: /* ldr pc, [pc, reg, lsl #2] */ + addr = fetch_reg(cookie, insn & 0xf); + addr = pc + 8 + (addr << 2); + error = read_int(cookie, addr, &addr); + *new_pc = addr; + return (error); + case 0x1: /* mov pc, reg */ + *new_pc = fetch_reg(cookie, insn & 0xf); + return (0); + case 0x4: + case 0x5: /* ldr pc, [reg] */ + addr = fetch_reg(cookie, (insn >> 16) & 0xf); + /* ldr pc, [reg, #offset] */ + if (insn & (1 << 24)) + offset = insn & 0xfff; + if (insn & 0x00800000) + addr += offset; + else + addr -= offset; + error = read_int(cookie, addr, &addr); + *new_pc = addr; + + return (error); + case 0x8: /* ldmxx reg, {..., pc} */ + case 0x9: + addr = fetch_reg(cookie, (insn >> 16) & 0xf); + nregs = (insn & 0x5555) + ((insn >> 1) & 0x5555); + nregs = (nregs & 0x3333) + ((nregs >> 2) & 0x3333); + nregs = (nregs + (nregs >> 4)) & 0x0f0f; + nregs = (nregs + (nregs >> 8)) & 0x001f; + switch ((insn >> 23) & 0x3) { + case 0x0: /* ldmda */ + addr = addr - 0; + break; + case 0x1: /* ldmia */ + addr = addr + 0 + ((nregs - 1) << 2); + break; + case 0x2: /* ldmdb */ + addr = addr - 4; + break; + case 0x3: /* ldmib */ + addr = addr + 4 + ((nregs - 1) << 2); + break; + } + error = read_int(cookie, addr, &addr); + *new_pc = addr; + + return (error); + default: + return (EINVAL); + } +} diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c index ede1df79d00e..2dddd065f348 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -186,9 +186,8 @@ const struct devmap_entry at91_devmap[] = { }; #ifdef LINUX_BOOT_ABI -extern int membanks; -extern int memstart[]; -extern int memsize[]; +static int membanks; +static int memsize[]; #endif long diff --git a/sys/arm/include/machdep.h b/sys/arm/include/machdep.h index 9442b8b2bfd3..b2bc82b72269 100644 --- a/sys/arm/include/machdep.h +++ b/sys/arm/include/machdep.h @@ -33,11 +33,12 @@ void undefinedinstruction_bounce(struct trapframe *); /* Early boot related helper functions */ struct arm_boot_params; vm_offset_t default_parse_boot_param(struct arm_boot_params *abp); -vm_offset_t freebsd_parse_boot_param(struct arm_boot_params *abp); -vm_offset_t linux_parse_boot_param(struct arm_boot_params *abp); vm_offset_t fake_preload_metadata(struct arm_boot_params *abp, void *dtb_ptr, size_t dtb_size); vm_offset_t parse_boot_param(struct arm_boot_params *abp); +void arm_parse_fdt_bootargs(void); +void arm_print_kenv(void); + void arm_generic_initclocks(void); /* Board-specific attributes */ @@ -52,4 +53,11 @@ typedef void delay_func(int, void *); void arm_set_delay(delay_func *, void *); #endif +#ifdef EFI +struct efi_map_header; +struct mem_region; +void arm_add_efi_map_entries(struct efi_map_header *efihdr, + struct mem_region *mr, int *mrcnt); +#endif + #endif /* !_MACHINE_MACHDEP_H_ */ diff --git a/sys/conf/files.arm b/sys/conf/files.arm index e81b6120f7b3..57036bef3c33 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -68,7 +68,10 @@ arm/arm/intr.c optional !intrng kern/subr_intr.c optional intrng arm/arm/locore.S standard no-obj arm/arm/machdep.c standard +arm/arm/machdep_boot.c standard +arm/arm/machdep_kdb.c standard arm/arm/machdep_intr.c standard +arm/arm/machdep_ptrace.c standard arm/arm/mem.c optional mem arm/arm/minidump_machdep.c optional mem arm/arm/mp_machdep.c optional smp