Path: blob/master/arch/h8300/platform/h8300h/ptrace_h8300h.c
10819 views
/*1* linux/arch/h8300/platform/h8300h/ptrace_h8300h.c2* ptrace cpu depend helper functions3*4* Yoshinori Sato <[email protected]>5*6* This file is subject to the terms and conditions of the GNU General7* Public License. See the file COPYING in the main directory of8* this archive for more details.9*/1011#include <linux/linkage.h>12#include <linux/sched.h>13#include <asm/ptrace.h>1415#define CCR_MASK 0x6f /* mode/imask not set */16#define BREAKINST 0x5730 /* trapa #3 */1718/* Mapping from PT_xxx to the stack offset at which the register is19saved. Notice that usp has no stack-slot and needs to be treated20specially (see get_reg/put_reg below). */21static const int h8300_register_offset[] = {22PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4),23PT_REG(er5), PT_REG(er6), PT_REG(er0), PT_REG(orig_er0),24PT_REG(ccr), PT_REG(pc)25};2627/* read register */28long h8300_get_reg(struct task_struct *task, int regno)29{30switch (regno) {31case PT_USP:32return task->thread.usp + sizeof(long)*2;33case PT_CCR:34return *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);35default:36return *(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]);37}38}3940/* write register */41int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)42{43unsigned short oldccr;44switch (regno) {45case PT_USP:46task->thread.usp = data - sizeof(long)*2;47case PT_CCR:48oldccr = *(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]);49oldccr &= ~CCR_MASK;50data &= CCR_MASK;51data |= oldccr;52*(unsigned short *)(task->thread.esp0 + h8300_register_offset[regno]) = data;53break;54default:55*(unsigned long *)(task->thread.esp0 + h8300_register_offset[regno]) = data;56break;57}58return 0;59}6061/* disable singlestep */62void user_disable_single_step(struct task_struct *child)63{64if((long)child->thread.breakinfo.addr != -1L) {65*child->thread.breakinfo.addr = child->thread.breakinfo.inst;66child->thread.breakinfo.addr = (unsigned short *)-1L;67}68}6970/* calculate next pc */71enum jump_type {none, /* normal instruction */72jabs, /* absolute address jump */73ind, /* indirect address jump */74ret, /* return to subrutine */75reg, /* register indexed jump */76relb, /* pc relative jump (byte offset) */77relw, /* pc relative jump (word offset) */78};7980/* opcode decode table define81ptn: opcode pattern82msk: opcode bitmask83len: instruction length (<0 next table index)84jmp: jump operation mode */85struct optable {86unsigned char bitpattern;87unsigned char bitmask;88signed char length;89signed char type;90} __attribute__((aligned(1),packed));9192#define OPTABLE(ptn,msk,len,jmp) \93{ \94.bitpattern = ptn, \95.bitmask = msk, \96.length = len, \97.type = jmp, \98}99100static const struct optable optable_0[] = {101OPTABLE(0x00,0xff, 1,none), /* 0x00 */102OPTABLE(0x01,0xff,-1,none), /* 0x01 */103OPTABLE(0x02,0xfe, 1,none), /* 0x02-0x03 */104OPTABLE(0x04,0xee, 1,none), /* 0x04-0x05/0x14-0x15 */105OPTABLE(0x06,0xfe, 1,none), /* 0x06-0x07 */106OPTABLE(0x08,0xea, 1,none), /* 0x08-0x09/0x0c-0x0d/0x18-0x19/0x1c-0x1d */107OPTABLE(0x0a,0xee, 1,none), /* 0x0a-0x0b/0x1a-0x1b */108OPTABLE(0x0e,0xee, 1,none), /* 0x0e-0x0f/0x1e-0x1f */109OPTABLE(0x10,0xfc, 1,none), /* 0x10-0x13 */110OPTABLE(0x16,0xfe, 1,none), /* 0x16-0x17 */111OPTABLE(0x20,0xe0, 1,none), /* 0x20-0x3f */112OPTABLE(0x40,0xf0, 1,relb), /* 0x40-0x4f */113OPTABLE(0x50,0xfc, 1,none), /* 0x50-0x53 */114OPTABLE(0x54,0xfd, 1,ret ), /* 0x54/0x56 */115OPTABLE(0x55,0xff, 1,relb), /* 0x55 */116OPTABLE(0x57,0xff, 1,none), /* 0x57 */117OPTABLE(0x58,0xfb, 2,relw), /* 0x58/0x5c */118OPTABLE(0x59,0xfb, 1,reg ), /* 0x59/0x5b */119OPTABLE(0x5a,0xfb, 2,jabs), /* 0x5a/0x5e */120OPTABLE(0x5b,0xfb, 2,ind ), /* 0x5b/0x5f */121OPTABLE(0x60,0xe8, 1,none), /* 0x60-0x67/0x70-0x77 */122OPTABLE(0x68,0xfa, 1,none), /* 0x68-0x69/0x6c-0x6d */123OPTABLE(0x6a,0xfe,-2,none), /* 0x6a-0x6b */124OPTABLE(0x6e,0xfe, 2,none), /* 0x6e-0x6f */125OPTABLE(0x78,0xff, 4,none), /* 0x78 */126OPTABLE(0x79,0xff, 2,none), /* 0x79 */127OPTABLE(0x7a,0xff, 3,none), /* 0x7a */128OPTABLE(0x7b,0xff, 2,none), /* 0x7b */129OPTABLE(0x7c,0xfc, 2,none), /* 0x7c-0x7f */130OPTABLE(0x80,0x80, 1,none), /* 0x80-0xff */131};132133static const struct optable optable_1[] = {134OPTABLE(0x00,0xff,-3,none), /* 0x0100 */135OPTABLE(0x40,0xf0,-3,none), /* 0x0140-0x14f */136OPTABLE(0x80,0xf0, 1,none), /* 0x0180-0x018f */137OPTABLE(0xc0,0xc0, 2,none), /* 0x01c0-0x01ff */138};139140static const struct optable optable_2[] = {141OPTABLE(0x00,0x20, 2,none), /* 0x6a0?/0x6a8?/0x6b0?/0x6b8? */142OPTABLE(0x20,0x20, 3,none), /* 0x6a2?/0x6aa?/0x6b2?/0x6ba? */143};144145static const struct optable optable_3[] = {146OPTABLE(0x69,0xfb, 2,none), /* 0x010069/0x01006d/014069/0x01406d */147OPTABLE(0x6b,0xff,-4,none), /* 0x01006b/0x01406b */148OPTABLE(0x6f,0xff, 3,none), /* 0x01006f/0x01406f */149OPTABLE(0x78,0xff, 5,none), /* 0x010078/0x014078 */150};151152static const struct optable optable_4[] = {153OPTABLE(0x00,0x78, 3,none), /* 0x0100690?/0x01006d0?/0140690/0x01406d0?/0x0100698?/0x01006d8?/0140698?/0x01406d8? */154OPTABLE(0x20,0x78, 4,none), /* 0x0100692?/0x01006d2?/0140692/0x01406d2?/0x010069a?/0x01006da?/014069a?/0x01406da? */155};156157static const struct optables_list {158const struct optable *ptr;159int size;160} optables[] = {161#define OPTABLES(no) \162{ \163.ptr = optable_##no, \164.size = sizeof(optable_##no) / sizeof(struct optable), \165}166OPTABLES(0),167OPTABLES(1),168OPTABLES(2),169OPTABLES(3),170OPTABLES(4),171172};173174const unsigned char condmask[] = {1750x00,0x40,0x01,0x04,0x02,0x08,0x10,0x20176};177178static int isbranch(struct task_struct *task,int reson)179{180unsigned char cond = h8300_get_reg(task, PT_CCR);181/* encode complex conditions */182/* B4: N^V183B5: Z|(N^V)184B6: C|Z */185__asm__("bld #3,%w0\n\t"186"bxor #1,%w0\n\t"187"bst #4,%w0\n\t"188"bor #2,%w0\n\t"189"bst #5,%w0\n\t"190"bld #2,%w0\n\t"191"bor #0,%w0\n\t"192"bst #6,%w0\n\t"193:"=&r"(cond)::"cc");194cond &= condmask[reson >> 1];195if (!(reson & 1))196return cond == 0;197else198return cond != 0;199}200201static unsigned short *getnextpc(struct task_struct *child, unsigned short *pc)202{203const struct optable *op;204unsigned char *fetch_p;205unsigned char inst;206unsigned long addr;207unsigned long *sp;208int op_len,regno;209op = optables[0].ptr;210op_len = optables[0].size;211fetch_p = (unsigned char *)pc;212inst = *fetch_p++;213do {214if ((inst & op->bitmask) == op->bitpattern) {215if (op->length < 0) {216op = optables[-op->length].ptr;217op_len = optables[-op->length].size + 1;218inst = *fetch_p++;219} else {220switch (op->type) {221case none:222return pc + op->length;223case jabs:224addr = *(unsigned long *)pc;225return (unsigned short *)(addr & 0x00ffffff);226case ind:227addr = *pc & 0xff;228return (unsigned short *)(*(unsigned long *)addr);229case ret:230sp = (unsigned long *)h8300_get_reg(child, PT_USP);231/* user stack frames232| er0 | temporary saved233+--------+234| exp | exception stack frames235+--------+236| ret pc | userspace return address237*/238return (unsigned short *)(*(sp+2) & 0x00ffffff);239case reg:240regno = (*pc >> 4) & 0x07;241if (regno == 0)242addr = h8300_get_reg(child, PT_ER0);243else244addr = h8300_get_reg(child, regno-1+PT_ER1);245return (unsigned short *)addr;246case relb:247if (inst == 0x55 || isbranch(child,inst & 0x0f))248pc = (unsigned short *)((unsigned long)pc +249((signed char)(*fetch_p)));250return pc+1; /* skip myself */251case relw:252if (inst == 0x5c || isbranch(child,(*fetch_p & 0xf0) >> 4))253pc = (unsigned short *)((unsigned long)pc +254((signed short)(*(pc+1))));255return pc+2; /* skip myself */256}257}258} else259op++;260} while(--op_len > 0);261return NULL;262}263264/* Set breakpoint(s) to simulate a single step from the current PC. */265266void user_enable_single_step(struct task_struct *child)267{268unsigned short *nextpc;269nextpc = getnextpc(child,(unsigned short *)h8300_get_reg(child, PT_PC));270child->thread.breakinfo.addr = nextpc;271child->thread.breakinfo.inst = *nextpc;272*nextpc = BREAKINST;273}274275asmlinkage void trace_trap(unsigned long bp)276{277if ((unsigned long)current->thread.breakinfo.addr == bp) {278user_disable_single_step(current);279force_sig(SIGTRAP,current);280} else281force_sig(SIGILL,current);282}283284285286