-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Original port to early 2.6 kernel using TI COFF toolchain. Brought up to date by Mark Salter <msalter@redhat.com> Signed-off-by: Aurelien Jacquiot <a-jacquiot@ti.com> Signed-off-by: Mark Salter <msalter@redhat.com> Acked-by: Arnd Bergmann <arnd@arndb.de>
- Loading branch information
Aurelien Jacquiot
authored and
Mark Salter
committed
Oct 6, 2011
1 parent
64236ac
commit 52679b2
Showing
2 changed files
with
361 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/* | ||
* Copyright (C) 2004, 2006, 2009, 2010 Texas Instruments Incorporated | ||
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) | ||
* | ||
* Updated for 2.6.34: Mark Salter <msalter@redhat.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
#ifndef _ASM_C6X_PTRACE_H | ||
#define _ASM_C6X_PTRACE_H | ||
|
||
#define BKPT_OPCODE 0x56454314 /* illegal opcode */ | ||
|
||
#ifdef _BIG_ENDIAN | ||
#define PT_LO(odd, even) odd | ||
#define PT_HI(odd, even) even | ||
#else | ||
#define PT_LO(odd, even) even | ||
#define PT_HI(odd, even) odd | ||
#endif | ||
|
||
#define PT_A4_ORG PT_LO(1, 0) | ||
#define PT_TSR PT_HI(1, 0) | ||
#define PT_ILC PT_LO(3, 2) | ||
#define PT_RILC PT_HI(3, 2) | ||
#define PT_CSR PT_LO(5, 4) | ||
#define PT_PC PT_HI(5, 4) | ||
#define PT_B16 PT_LO(7, 6) | ||
#define PT_B17 PT_HI(7, 6) | ||
#define PT_B18 PT_LO(9, 8) | ||
#define PT_B19 PT_HI(9, 8) | ||
#define PT_B20 PT_LO(11, 10) | ||
#define PT_B21 PT_HI(11, 10) | ||
#define PT_B22 PT_LO(13, 12) | ||
#define PT_B23 PT_HI(13, 12) | ||
#define PT_B24 PT_LO(15, 14) | ||
#define PT_B25 PT_HI(15, 14) | ||
#define PT_B26 PT_LO(17, 16) | ||
#define PT_B27 PT_HI(17, 16) | ||
#define PT_B28 PT_LO(19, 18) | ||
#define PT_B29 PT_HI(19, 18) | ||
#define PT_B30 PT_LO(21, 20) | ||
#define PT_B31 PT_HI(21, 20) | ||
#define PT_B0 PT_LO(23, 22) | ||
#define PT_B1 PT_HI(23, 22) | ||
#define PT_B2 PT_LO(25, 24) | ||
#define PT_B3 PT_HI(25, 24) | ||
#define PT_B4 PT_LO(27, 26) | ||
#define PT_B5 PT_HI(27, 26) | ||
#define PT_B6 PT_LO(29, 28) | ||
#define PT_B7 PT_HI(29, 28) | ||
#define PT_B8 PT_LO(31, 30) | ||
#define PT_B9 PT_HI(31, 30) | ||
#define PT_B10 PT_LO(33, 32) | ||
#define PT_B11 PT_HI(33, 32) | ||
#define PT_B12 PT_LO(35, 34) | ||
#define PT_B13 PT_HI(35, 34) | ||
#define PT_A16 PT_LO(37, 36) | ||
#define PT_A17 PT_HI(37, 36) | ||
#define PT_A18 PT_LO(39, 38) | ||
#define PT_A19 PT_HI(39, 38) | ||
#define PT_A20 PT_LO(41, 40) | ||
#define PT_A21 PT_HI(41, 40) | ||
#define PT_A22 PT_LO(43, 42) | ||
#define PT_A23 PT_HI(43, 42) | ||
#define PT_A24 PT_LO(45, 44) | ||
#define PT_A25 PT_HI(45, 44) | ||
#define PT_A26 PT_LO(47, 46) | ||
#define PT_A27 PT_HI(47, 46) | ||
#define PT_A28 PT_LO(49, 48) | ||
#define PT_A29 PT_HI(49, 48) | ||
#define PT_A30 PT_LO(51, 50) | ||
#define PT_A31 PT_HI(51, 50) | ||
#define PT_A0 PT_LO(53, 52) | ||
#define PT_A1 PT_HI(53, 52) | ||
#define PT_A2 PT_LO(55, 54) | ||
#define PT_A3 PT_HI(55, 54) | ||
#define PT_A4 PT_LO(57, 56) | ||
#define PT_A5 PT_HI(57, 56) | ||
#define PT_A6 PT_LO(59, 58) | ||
#define PT_A7 PT_HI(59, 58) | ||
#define PT_A8 PT_LO(61, 60) | ||
#define PT_A9 PT_HI(61, 60) | ||
#define PT_A10 PT_LO(63, 62) | ||
#define PT_A11 PT_HI(63, 62) | ||
#define PT_A12 PT_LO(65, 64) | ||
#define PT_A13 PT_HI(65, 64) | ||
#define PT_A14 PT_LO(67, 66) | ||
#define PT_A15 PT_HI(67, 66) | ||
#define PT_B14 PT_LO(69, 68) | ||
#define PT_B15 PT_HI(69, 68) | ||
|
||
#define NR_PTREGS 70 | ||
|
||
#define PT_DP PT_B14 /* Data Segment Pointer (B14) */ | ||
#define PT_SP PT_B15 /* Stack Pointer (B15) */ | ||
|
||
#ifndef __ASSEMBLY__ | ||
|
||
#ifdef _BIG_ENDIAN | ||
#define REG_PAIR(odd, even) unsigned long odd; unsigned long even | ||
#else | ||
#define REG_PAIR(odd, even) unsigned long even; unsigned long odd | ||
#endif | ||
|
||
/* | ||
* this struct defines the way the registers are stored on the | ||
* stack during a system call. fields defined with REG_PAIR | ||
* are saved and restored using double-word memory operations | ||
* which means the word ordering of the pair depends on endianess. | ||
*/ | ||
struct pt_regs { | ||
REG_PAIR(tsr, orig_a4); | ||
REG_PAIR(rilc, ilc); | ||
REG_PAIR(pc, csr); | ||
|
||
REG_PAIR(b17, b16); | ||
REG_PAIR(b19, b18); | ||
REG_PAIR(b21, b20); | ||
REG_PAIR(b23, b22); | ||
REG_PAIR(b25, b24); | ||
REG_PAIR(b27, b26); | ||
REG_PAIR(b29, b28); | ||
REG_PAIR(b31, b30); | ||
|
||
REG_PAIR(b1, b0); | ||
REG_PAIR(b3, b2); | ||
REG_PAIR(b5, b4); | ||
REG_PAIR(b7, b6); | ||
REG_PAIR(b9, b8); | ||
REG_PAIR(b11, b10); | ||
REG_PAIR(b13, b12); | ||
|
||
REG_PAIR(a17, a16); | ||
REG_PAIR(a19, a18); | ||
REG_PAIR(a21, a20); | ||
REG_PAIR(a23, a22); | ||
REG_PAIR(a25, a24); | ||
REG_PAIR(a27, a26); | ||
REG_PAIR(a29, a28); | ||
REG_PAIR(a31, a30); | ||
|
||
REG_PAIR(a1, a0); | ||
REG_PAIR(a3, a2); | ||
REG_PAIR(a5, a4); | ||
REG_PAIR(a7, a6); | ||
REG_PAIR(a9, a8); | ||
REG_PAIR(a11, a10); | ||
REG_PAIR(a13, a12); | ||
|
||
REG_PAIR(a15, a14); | ||
REG_PAIR(sp, dp); | ||
}; | ||
|
||
#ifdef __KERNEL__ | ||
|
||
#include <linux/linkage.h> | ||
|
||
#define user_mode(regs) ((((regs)->tsr) & 0x40) != 0) | ||
|
||
#define instruction_pointer(regs) ((regs)->pc) | ||
#define profile_pc(regs) instruction_pointer(regs) | ||
#define user_stack_pointer(regs) ((regs)->sp) | ||
|
||
extern void show_regs(struct pt_regs *); | ||
|
||
extern asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs); | ||
extern asmlinkage void syscall_trace_exit(struct pt_regs *regs); | ||
|
||
#endif /* __KERNEL__ */ | ||
#endif /* __ASSEMBLY__ */ | ||
#endif /* _ASM_C6X_PTRACE_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
/* | ||
* Port on Texas Instruments TMS320C6x architecture | ||
* | ||
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated | ||
* Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com) | ||
* | ||
* Updated for 2.6.34: Mark Salter <msalter@redhat.com> | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License version 2 as | ||
* published by the Free Software Foundation. | ||
*/ | ||
#include <linux/ptrace.h> | ||
#include <linux/tracehook.h> | ||
#include <linux/regset.h> | ||
#include <linux/elf.h> | ||
|
||
#include <asm/cacheflush.h> | ||
|
||
#define PT_REG_SIZE (sizeof(struct pt_regs)) | ||
|
||
/* | ||
* Called by kernel/ptrace.c when detaching. | ||
*/ | ||
void ptrace_disable(struct task_struct *child) | ||
{ | ||
/* nothing to do */ | ||
} | ||
|
||
/* | ||
* Get a register number from live pt_regs for the specified task. | ||
*/ | ||
static inline long get_reg(struct task_struct *task, int regno) | ||
{ | ||
long *addr = (long *)task_pt_regs(task); | ||
|
||
if (regno == PT_TSR || regno == PT_CSR) | ||
return 0; | ||
|
||
return addr[regno]; | ||
} | ||
|
||
/* | ||
* Write contents of register REGNO in task TASK. | ||
*/ | ||
static inline int put_reg(struct task_struct *task, | ||
int regno, | ||
unsigned long data) | ||
{ | ||
unsigned long *addr = (unsigned long *)task_pt_regs(task); | ||
|
||
if (regno != PT_TSR && regno != PT_CSR) | ||
addr[regno] = data; | ||
|
||
return 0; | ||
} | ||
|
||
/* regset get/set implementations */ | ||
|
||
static int gpr_get(struct task_struct *target, | ||
const struct user_regset *regset, | ||
unsigned int pos, unsigned int count, | ||
void *kbuf, void __user *ubuf) | ||
{ | ||
struct pt_regs *regs = task_pt_regs(target); | ||
|
||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
regs, | ||
0, sizeof(*regs)); | ||
} | ||
|
||
static int gpr_set(struct task_struct *target, | ||
const struct user_regset *regset, | ||
unsigned int pos, unsigned int count, | ||
const void *kbuf, const void __user *ubuf) | ||
{ | ||
int ret; | ||
struct pt_regs *regs = task_pt_regs(target); | ||
|
||
/* Don't copyin TSR or CSR */ | ||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
®s, | ||
0, PT_TSR * sizeof(long)); | ||
if (ret) | ||
return ret; | ||
|
||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
PT_TSR * sizeof(long), | ||
(PT_TSR + 1) * sizeof(long)); | ||
if (ret) | ||
return ret; | ||
|
||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
®s, | ||
(PT_TSR + 1) * sizeof(long), | ||
PT_CSR * sizeof(long)); | ||
if (ret) | ||
return ret; | ||
|
||
ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, | ||
PT_CSR * sizeof(long), | ||
(PT_CSR + 1) * sizeof(long)); | ||
if (ret) | ||
return ret; | ||
|
||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
®s, | ||
(PT_CSR + 1) * sizeof(long), -1); | ||
return ret; | ||
} | ||
|
||
enum c6x_regset { | ||
REGSET_GPR, | ||
}; | ||
|
||
static const struct user_regset c6x_regsets[] = { | ||
[REGSET_GPR] = { | ||
.core_note_type = NT_PRSTATUS, | ||
.n = ELF_NGREG, | ||
.size = sizeof(u32), | ||
.align = sizeof(u32), | ||
.get = gpr_get, | ||
.set = gpr_set | ||
}, | ||
}; | ||
|
||
static const struct user_regset_view user_c6x_native_view = { | ||
.name = "tic6x", | ||
.e_machine = EM_TI_C6000, | ||
.regsets = c6x_regsets, | ||
.n = ARRAY_SIZE(c6x_regsets), | ||
}; | ||
|
||
const struct user_regset_view *task_user_regset_view(struct task_struct *task) | ||
{ | ||
return &user_c6x_native_view; | ||
} | ||
|
||
/* | ||
* Perform ptrace request | ||
*/ | ||
long arch_ptrace(struct task_struct *child, long request, | ||
unsigned long addr, unsigned long data) | ||
{ | ||
int ret = 0; | ||
|
||
switch (request) { | ||
/* | ||
* write the word at location addr. | ||
*/ | ||
case PTRACE_POKETEXT: | ||
ret = generic_ptrace_pokedata(child, addr, data); | ||
if (ret == 0 && request == PTRACE_POKETEXT) | ||
flush_icache_range(addr, addr + 4); | ||
break; | ||
default: | ||
ret = ptrace_request(child, request, addr, data); | ||
break; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
/* | ||
* handle tracing of system call entry | ||
* - return the revised system call number or ULONG_MAX to cause ENOSYS | ||
*/ | ||
asmlinkage unsigned long syscall_trace_entry(struct pt_regs *regs) | ||
{ | ||
if (tracehook_report_syscall_entry(regs)) | ||
/* tracing decided this syscall should not happen, so | ||
* We'll return a bogus call number to get an ENOSYS | ||
* error, but leave the original number in | ||
* regs->orig_a4 | ||
*/ | ||
return ULONG_MAX; | ||
|
||
return regs->b0; | ||
} | ||
|
||
/* | ||
* handle tracing of system call exit | ||
*/ | ||
asmlinkage void syscall_trace_exit(struct pt_regs *regs) | ||
{ | ||
tracehook_report_syscall_exit(regs, 0); | ||
} |