/* * Similar to get_user, do some address checking, then dereference * Return true on sucess, false on bad address */ static bool get_instruction(unsigned short *val, unsigned short *address) { unsigned long addr; addr = (unsigned long)address; /* Check for odd addresses */ if (addr & 0x1) return false; /* Check that things do not wrap around */ if (addr > (addr + 2)) return false; /* * Since we are in exception context, we need to do a little address checking * We need to make sure we are only accessing valid memory, and * we don't read something in the async space that can hang forever */ if ((addr >= FIXED_CODE_START && (addr + 2) <= physical_mem_end) || #if L2_LENGTH != 0 (addr >= L2_START && (addr + 2) <= (L2_START + L2_LENGTH)) || #endif (addr >= BOOT_ROM_START && (addr + 2) <= (BOOT_ROM_START + BOOT_ROM_LENGTH)) || #if L1_DATA_A_LENGTH != 0 (addr >= L1_DATA_A_START && (addr + 2) <= (L1_DATA_A_START + L1_DATA_A_LENGTH)) || #endif #if L1_DATA_B_LENGTH != 0 (addr >= L1_DATA_B_START && (addr + 2) <= (L1_DATA_B_START + L1_DATA_B_LENGTH)) || #endif (addr >= L1_SCRATCH_START && (addr + 2) <= (L1_SCRATCH_START + L1_SCRATCH_LENGTH)) || (!(bfin_read_EBIU_AMBCTL0() & B0RDYEN) && addr >= ASYNC_BANK0_BASE && (addr + 2) <= (ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE)) || (!(bfin_read_EBIU_AMBCTL0() & B1RDYEN) && addr >= ASYNC_BANK1_BASE && (addr + 2) <= (ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE)) || (!(bfin_read_EBIU_AMBCTL1() & B2RDYEN) && addr >= ASYNC_BANK2_BASE && (addr + 2) <= (ASYNC_BANK2_BASE + ASYNC_BANK1_SIZE)) || (!(bfin_read_EBIU_AMBCTL1() & B3RDYEN) && addr >= ASYNC_BANK3_BASE && (addr + 2) <= (ASYNC_BANK3_BASE + ASYNC_BANK1_SIZE))) { *val = *address; return true; } #if L1_CODE_LENGTH != 0 if (addr >= L1_CODE_START && (addr + 2) <= (L1_CODE_START + L1_CODE_LENGTH)) { isram_memcpy(val, address, 2); return true; } #endif return false; }
long probe_kernel_write(void *dst, const void *src, size_t size) { unsigned long ldst = (unsigned long)dst; int mem_type; mem_type = validate_memory_access_address(ldst, size); if (mem_type < 0) return mem_type; if (ldst >= SYSMMR_BASE) { if (size == 2 && ldst % 2 == 0) { u16 mmr; memcpy(&mmr, src, sizeof(mmr)); bfin_write16(dst, mmr); return 0; } else if (size == 4 && ldst % 4 == 0) { u32 mmr; memcpy(&mmr, src, sizeof(mmr)); bfin_write32(dst, mmr); return 0; } } else { switch (mem_type) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: return __probe_kernel_write(dst, src, size); case BFIN_MEM_ACCESS_DMA: if (dma_memcpy(dst, src, size)) return 0; break; case BFIN_MEM_ACCESS_ITEST: if (isram_memcpy(dst, src, size)) return 0; break; } } return -EFAULT; }
long probe_kernel_read(void *dst, const void *src, size_t size) { unsigned long lsrc = (unsigned long)src; int mem_type; mem_type = validate_memory_access_address(lsrc, size); if (mem_type < 0) return mem_type; if (lsrc >= SYSMMR_BASE) { if (size == 2 && lsrc % 2 == 0) { u16 mmr = bfin_read16(src); memcpy(dst, &mmr, sizeof(mmr)); return 0; } else if (size == 4 && lsrc % 4 == 0) { u32 mmr = bfin_read32(src); memcpy(dst, &mmr, sizeof(mmr)); return 0; } } else { switch (mem_type) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: return __probe_kernel_read(dst, src, size); case BFIN_MEM_ACCESS_DMA: if (dma_memcpy(dst, src, size)) return 0; break; case BFIN_MEM_ACCESS_ITEST: if (isram_memcpy(dst, src, size)) return 0; break; } } return -EFAULT; }
bool get_mem16(unsigned short *val, unsigned short *address) { unsigned long addr = (unsigned long)address; if (addr & 0x1) return false; switch (bfin_mem_access_type(addr, 2)) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: *val = *address; return true; case BFIN_MEM_ACCESS_DMA: dma_memcpy(val, address, 2); return true; case BFIN_MEM_ACCESS_ITEST: isram_memcpy(val, address, 2); return true; default: return false; } }
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, unsigned int relsec, struct module *mod) { unsigned int i; Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; unsigned long location, value, size; pr_debug("applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ location = sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ sym = (Elf32_Sym *) sechdrs[symindex].sh_addr + ELF32_R_SYM(rel[i].r_info); value = sym->st_value; value += rel[i].r_addend; #ifdef CONFIG_SMP if (location >= COREB_L1_DATA_A_START) { pr_err("cannot relocate in L1: %u (SMP kernel)\n", ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; } #endif pr_debug("location is %lx, value is %lx type is %d\n", location, value, ELF32_R_TYPE(rel[i].r_info)); switch (ELF32_R_TYPE(rel[i].r_info)) { case R_BFIN_HUIMM16: value >>= 16; case R_BFIN_LUIMM16: case R_BFIN_RIMM16: size = 2; break; case R_BFIN_BYTE4_DATA: size = 4; break; case R_BFIN_PCREL24: case R_BFIN_PCREL24_JUMP_L: case R_BFIN_PCREL12_JUMP: case R_BFIN_PCREL12_JUMP_S: case R_BFIN_PCREL10: pr_err("unsupported relocation: %u (no -mlong-calls?)\n", ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; default: pr_err("unknown relocation: %u\n", ELF32_R_TYPE(rel[i].r_info)); return -ENOEXEC; } switch (bfin_mem_access_type(location, size)) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: memcpy((void *)location, &value, size); break; case BFIN_MEM_ACCESS_DMA: dma_memcpy((void *)location, &value, size); break; case BFIN_MEM_ACCESS_ITEST: isram_memcpy((void *)location, &value, size); break; default: pr_err("invalid relocation for %#lx\n", location); return -ENOEXEC; } } return 0; }
long arch_ptrace(struct task_struct *child, long request, long addr, long data) { int ret; unsigned long __user *datap = (unsigned long __user *)data; void *paddr = (void *)addr; switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKDATA: pr_debug("ptrace: PEEKDATA\n"); /* fall through */ case PTRACE_PEEKTEXT: /* read word at location addr. */ { unsigned long tmp = 0; int copied = 0, to_copy = sizeof(tmp); ret = -EIO; pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr, to_copy); if (is_user_addr_valid(child, addr, to_copy) < 0) break; pr_debug("ptrace: user address is valid\n"); switch (bfin_mem_access_type(addr, to_copy)) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: copied = access_process_vm(child, addr, &tmp, to_copy, 0); if (copied) break; /* hrm, why didn't that work ... maybe no mapping */ if (addr >= FIXED_CODE_START && addr + to_copy <= FIXED_CODE_END) { copy_from_user_page(0, 0, 0, &tmp, paddr, to_copy); copied = to_copy; } else if (addr >= BOOT_ROM_START) { memcpy(&tmp, paddr, to_copy); copied = to_copy; } break; case BFIN_MEM_ACCESS_DMA: if (safe_dma_memcpy(&tmp, paddr, to_copy)) copied = to_copy; break; case BFIN_MEM_ACCESS_ITEST: if (isram_memcpy(&tmp, paddr, to_copy)) copied = to_copy; break; default: copied = 0; break; } pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); if (copied == to_copy) ret = put_user(tmp, datap); break; } /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKEDATA: pr_debug("ptrace: PTRACE_PEEKDATA\n"); /* fall through */ case PTRACE_POKETEXT: /* write the word at location addr. */ { int copied = 0, to_copy = sizeof(data); ret = -EIO; pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n", addr, to_copy, data); if (is_user_addr_valid(child, addr, to_copy) < 0) break; pr_debug("ptrace: user address is valid\n"); switch (bfin_mem_access_type(addr, to_copy)) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: copied = access_process_vm(child, addr, &data, to_copy, 1); break; case BFIN_MEM_ACCESS_DMA: if (safe_dma_memcpy(paddr, &data, to_copy)) copied = to_copy; break; case BFIN_MEM_ACCESS_ITEST: if (isram_memcpy(paddr, &data, to_copy)) copied = to_copy; break; default: copied = 0; break; } pr_debug("ptrace: copied size %d\n", copied); if (copied == to_copy) ret = 0; break; } case PTRACE_PEEKUSR: switch (addr) { #ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */ case PT_FDPIC_EXEC: request = PTRACE_GETFDPIC; addr = PTRACE_GETFDPIC_EXEC; goto case_default; case PT_FDPIC_INTERP: request = PTRACE_GETFDPIC; addr = PTRACE_GETFDPIC_INTERP; goto case_default; #endif default: ret = get_reg(child, addr, datap); } pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr, data, ret); break; case PTRACE_POKEUSR: ret = put_reg(child, addr, data); pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr, data, ret); break; case PTRACE_GETREGS: pr_debug("ptrace: PTRACE_GETREGS\n"); return copy_regset_to_user(child, &user_bfin_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), (void __user *)data); case PTRACE_SETREGS: pr_debug("ptrace: PTRACE_SETREGS\n"); return copy_regset_from_user(child, &user_bfin_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), (const void __user *)data); case_default: default: ret = ptrace_request(child, request, addr, data); break; } return ret; }
long arch_ptrace(struct task_struct *child, long request, unsigned long addr, unsigned long data) { int ret; unsigned long __user *datap = (unsigned long __user *)data; void *paddr = (void *)addr; switch (request) { case PTRACE_PEEKDATA: pr_debug("ptrace: PEEKDATA\n"); case PTRACE_PEEKTEXT: { unsigned long tmp = 0; int copied = 0, to_copy = sizeof(tmp); ret = -EIO; pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + %i\n", addr, to_copy); if (is_user_addr_valid(child, addr, to_copy) < 0) break; pr_debug("ptrace: user address is valid\n"); switch (bfin_mem_access_type(addr, to_copy)) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: copied = access_process_vm(child, addr, &tmp, to_copy, 0); if (copied) break; if (addr >= FIXED_CODE_START && addr + to_copy <= FIXED_CODE_END) { copy_from_user_page(0, 0, 0, &tmp, paddr, to_copy); copied = to_copy; } else if (addr >= BOOT_ROM_START) { memcpy(&tmp, paddr, to_copy); copied = to_copy; } break; case BFIN_MEM_ACCESS_DMA: if (safe_dma_memcpy(&tmp, paddr, to_copy)) copied = to_copy; break; case BFIN_MEM_ACCESS_ITEST: if (isram_memcpy(&tmp, paddr, to_copy)) copied = to_copy; break; default: copied = 0; break; } pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); if (copied == to_copy) ret = put_user(tmp, datap); break; } case PTRACE_POKEDATA: pr_debug("ptrace: PTRACE_PEEKDATA\n"); case PTRACE_POKETEXT: { int copied = 0, to_copy = sizeof(data); ret = -EIO; pr_debug("ptrace: POKETEXT at addr 0x%08lx + %i bytes %lx\n", addr, to_copy, data); if (is_user_addr_valid(child, addr, to_copy) < 0) break; pr_debug("ptrace: user address is valid\n"); switch (bfin_mem_access_type(addr, to_copy)) { case BFIN_MEM_ACCESS_CORE: case BFIN_MEM_ACCESS_CORE_ONLY: copied = access_process_vm(child, addr, &data, to_copy, 1); break; case BFIN_MEM_ACCESS_DMA: if (safe_dma_memcpy(paddr, &data, to_copy)) copied = to_copy; break; case BFIN_MEM_ACCESS_ITEST: if (isram_memcpy(paddr, &data, to_copy)) copied = to_copy; break; default: copied = 0; break; } pr_debug("ptrace: copied size %d\n", copied); if (copied == to_copy) ret = 0; break; } case PTRACE_PEEKUSR: switch (addr) { #ifdef CONFIG_BINFMT_ELF_FDPIC case PT_FDPIC_EXEC: request = PTRACE_GETFDPIC; addr = PTRACE_GETFDPIC_EXEC; goto case_default; case PT_FDPIC_INTERP: request = PTRACE_GETFDPIC; addr = PTRACE_GETFDPIC_INTERP; goto case_default; #endif default: ret = get_reg(child, addr, datap); } pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr, data, ret); break; case PTRACE_POKEUSR: ret = put_reg(child, addr, data); pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr, data, ret); break; case PTRACE_GETREGS: pr_debug("ptrace: PTRACE_GETREGS\n"); return copy_regset_to_user(child, &user_bfin_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), datap); case PTRACE_SETREGS: pr_debug("ptrace: PTRACE_SETREGS\n"); return copy_regset_from_user(child, &user_bfin_native_view, REGSET_GENERAL, 0, sizeof(struct pt_regs), datap); case_default: default: ret = ptrace_request(child, request, addr, data); break; } return ret; }