Add the kernel support for Thumb-2. It is only supported on ARMv7 as the
main ARMv6 target, the Raspberry Pi, doesn't support Thumb-2. This as been tested with a Thumb-2 userland, however building one is currently unsupported as there are known toolchain issues breaking some binaries. Further work will also be needed to decide on the method of selecting which instruction set to build for, and to benchmark both to find how building everything as Thumb-2 will affect performance. Relnotes: yes
This commit is contained in:
parent
8465de8e6c
commit
ae4fa2223a
@ -364,7 +364,6 @@ END(data_abort_entry)
|
||||
* on exit (without transitioning back through the undefined mode stack).
|
||||
*/
|
||||
ASENTRY_NP(undefined_entry)
|
||||
sub lr, lr, #4 /* Adjust the lr. Transition to scv32 */
|
||||
PUSHFRAMEINSVC /* mode stack, build trapframe there. */
|
||||
adr lr, exception_exit /* Return from handler via standard */
|
||||
mov r0, sp /* exception exit routine. Pass the */
|
||||
|
@ -87,6 +87,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_pager.h>
|
||||
|
||||
#include <machine/acle-compat.h>
|
||||
#include <machine/armreg.h>
|
||||
#include <machine/atags.h>
|
||||
#include <machine/cpu.h>
|
||||
@ -337,6 +338,13 @@ sendsig(catcher, ksi, mask)
|
||||
tf->tf_pc = (register_t)catcher;
|
||||
tf->tf_usr_sp = (register_t)fp;
|
||||
tf->tf_usr_lr = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode));
|
||||
/* Set the mode to enter in the signal handler */
|
||||
#if __ARM_ARCH >= 7
|
||||
if ((register_t)catcher & 1)
|
||||
tf->tf_spsr |= PSR_T;
|
||||
else
|
||||
tf->tf_spsr &= ~PSR_T;
|
||||
#endif
|
||||
|
||||
CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr,
|
||||
tf->tf_usr_sp);
|
||||
@ -626,6 +634,10 @@ ptrace_single_step(struct thread *td)
|
||||
struct proc *p;
|
||||
int error;
|
||||
|
||||
/* 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"));
|
||||
p = td->td_proc;
|
||||
@ -649,6 +661,10 @@ 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) {
|
||||
p = td->td_proc;
|
||||
PROC_UNLOCK(p);
|
||||
|
@ -171,16 +171,7 @@ swi_handler(struct trapframe *frame)
|
||||
td->td_frame = frame;
|
||||
|
||||
td->td_pticks = 0;
|
||||
/*
|
||||
* Make sure the program counter is correctly aligned so we
|
||||
* don't take an alignment fault trying to read the opcode.
|
||||
* XXX: Fix for Thumb mode
|
||||
*/
|
||||
if (__predict_false(((frame->tf_pc - INSN_SIZE) & 3) != 0)) {
|
||||
call_trapsignal(td, SIGILL, 0);
|
||||
userret(td, frame);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable interrupts if they were enabled before the exception.
|
||||
* Since all syscalls *should* come from user mode it will always
|
||||
|
@ -86,6 +86,19 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/db_machdep.h>
|
||||
#endif
|
||||
|
||||
#define ARM_COPROC_INSN(insn) (((insn) & (1 << 27)) != 0)
|
||||
#define ARM_VFP_INSN(insn) ((((insn) & 0xfe000000) == 0xf2000000) || \
|
||||
(((insn) & 0xff100000) == 0xf4000000))
|
||||
#define ARM_COPROC(insn) (((insn) >> 8) & 0xf)
|
||||
|
||||
#define THUMB_32BIT_INSN(insn) ((insn) >= 0xe800)
|
||||
#define THUMB_COPROC_INSN(insn) (((insn) & (3 << 26)) == (3 << 26))
|
||||
#define THUMB_COPROC_UNDEFINED(insn) (((insn) & 0x3e << 20) == 0)
|
||||
#define THUMB_VFP_INSN(insn) (((insn) & (3 << 24)) == (3 << 24))
|
||||
#define THUMB_COPROC(insn) (((insn) >> 8) & 0xf)
|
||||
|
||||
#define COPROC_VFP 10
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
int (*dtrace_invop_jump_addr)(struct trapframe *);
|
||||
#endif
|
||||
@ -179,6 +192,7 @@ undefinedinstruction(struct trapframe *frame)
|
||||
int fault_code;
|
||||
int coprocessor;
|
||||
struct undefined_handler *uh;
|
||||
int error;
|
||||
#ifdef VERBOSE_ARM32
|
||||
int s;
|
||||
#endif
|
||||
@ -192,6 +206,12 @@ undefinedinstruction(struct trapframe *frame)
|
||||
|
||||
PCPU_INC(cnt.v_trap);
|
||||
|
||||
#if __ARM_ARCH >= 7
|
||||
if ((frame->tf_spsr & PSR_T) != 0)
|
||||
frame->tf_pc -= THUMB_INSN_SIZE;
|
||||
else
|
||||
#endif
|
||||
frame->tf_pc -= INSN_SIZE;
|
||||
fault_pc = frame->tf_pc;
|
||||
|
||||
/*
|
||||
@ -200,11 +220,72 @@ undefinedinstruction(struct trapframe *frame)
|
||||
*/
|
||||
td = curthread == NULL ? &thread0 : curthread;
|
||||
|
||||
/*
|
||||
* Make sure the program counter is correctly aligned so we
|
||||
* don't take an alignment fault trying to read the opcode.
|
||||
*/
|
||||
if (__predict_false((fault_pc & 3) != 0)) {
|
||||
coprocessor = 0;
|
||||
if ((frame->tf_spsr & PSR_T) == 0) {
|
||||
/*
|
||||
* Make sure the program counter is correctly aligned so we
|
||||
* don't take an alignment fault trying to read the opcode.
|
||||
*/
|
||||
if (__predict_false((fault_pc & 3) != 0)) {
|
||||
ksiginfo_init_trap(&ksi);
|
||||
ksi.ksi_signo = SIGILL;
|
||||
ksi.ksi_code = ILL_ILLADR;
|
||||
ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc;
|
||||
trapsignal(td, &ksi);
|
||||
userret(td, frame);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should use fuword() here .. but in the interests of
|
||||
* squeezing every bit of speed we will just use ReadWord().
|
||||
* We know the instruction can be read as was just executed
|
||||
* so this will never fail unless the kernel is screwed up
|
||||
* in which case it does not really matter does it ?
|
||||
*/
|
||||
|
||||
fault_instruction = *(u_int32_t *)fault_pc;
|
||||
|
||||
/* Check for coprocessor instruction */
|
||||
|
||||
/*
|
||||
* According to the datasheets you only need to look at bit
|
||||
* 27 of the instruction to tell the difference between and
|
||||
* undefined instruction and a coprocessor instruction
|
||||
* following an undefined instruction trap.
|
||||
*/
|
||||
|
||||
if (ARM_COPROC_INSN(fault_instruction))
|
||||
coprocessor = ARM_COPROC(fault_instruction);
|
||||
else { /* check for special instructions */
|
||||
if (ARM_VFP_INSN(fault_instruction))
|
||||
coprocessor = COPROC_VFP; /* vfp / simd */
|
||||
}
|
||||
} else {
|
||||
#if __ARM_ARCH >= 7
|
||||
fault_instruction = *(uint16_t *)fault_pc;
|
||||
if (THUMB_32BIT_INSN(fault_instruction)) {
|
||||
fault_instruction <<= 16;
|
||||
fault_instruction |= *(uint16_t *)(fault_pc + 2);
|
||||
|
||||
/*
|
||||
* Is it a Coprocessor, Advanced SIMD, or
|
||||
* Floating-point instruction.
|
||||
*/
|
||||
if (THUMB_COPROC_INSN(fault_instruction)) {
|
||||
if (THUMB_COPROC_UNDEFINED(fault_instruction)) {
|
||||
/* undefined insn */
|
||||
} else if (THUMB_VFP_INSN(fault_instruction))
|
||||
coprocessor = COPROC_VFP;
|
||||
else
|
||||
coprocessor =
|
||||
THUMB_COPROC(fault_instruction);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* No support for Thumb-2 on this cpu
|
||||
*/
|
||||
ksiginfo_init_trap(&ksi);
|
||||
ksi.ksi_signo = SIGILL;
|
||||
ksi.ksi_code = ILL_ILLADR;
|
||||
@ -212,41 +293,8 @@ undefinedinstruction(struct trapframe *frame)
|
||||
trapsignal(td, &ksi);
|
||||
userret(td, frame);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Should use fuword() here .. but in the interests of squeezing every
|
||||
* bit of speed we will just use ReadWord(). We know the instruction
|
||||
* can be read as was just executed so this will never fail unless the
|
||||
* kernel is screwed up in which case it does not really matter does
|
||||
* it ?
|
||||
*/
|
||||
|
||||
fault_instruction = *(u_int32_t *)fault_pc;
|
||||
|
||||
/* Update vmmeter statistics */
|
||||
#if 0
|
||||
uvmexp.traps++;
|
||||
#endif
|
||||
/* Check for coprocessor instruction */
|
||||
|
||||
/*
|
||||
* According to the datasheets you only need to look at bit 27 of the
|
||||
* instruction to tell the difference between and undefined
|
||||
* instruction and a coprocessor instruction following an undefined
|
||||
* instruction trap.
|
||||
*/
|
||||
|
||||
coprocessor = 0;
|
||||
if ((fault_instruction & (1 << 27)) != 0)
|
||||
coprocessor = (fault_instruction >> 8) & 0x0f;
|
||||
#ifdef VFP
|
||||
else { /* check for special instructions */
|
||||
if (((fault_instruction & 0xfe000000) == 0xf2000000) ||
|
||||
((fault_instruction & 0xff100000) == 0xf4000000))
|
||||
coprocessor = 10; /* vfp / simd */
|
||||
}
|
||||
#endif /* VFP */
|
||||
|
||||
if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
|
||||
/*
|
||||
@ -264,13 +312,24 @@ undefinedinstruction(struct trapframe *frame)
|
||||
fault_code) == 0)
|
||||
break;
|
||||
|
||||
if (fault_code & FAULT_USER && fault_instruction == PTRACE_BREAKPOINT) {
|
||||
PROC_LOCK(td->td_proc);
|
||||
_PHOLD(td->td_proc);
|
||||
ptrace_clear_single_step(td);
|
||||
_PRELE(td->td_proc);
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
return;
|
||||
if (fault_code & FAULT_USER) {
|
||||
/* TODO: No support for ptrace from Thumb-2 */
|
||||
if ((frame->tf_spsr & PSR_T) == 0 &&
|
||||
fault_instruction == PTRACE_BREAKPOINT) {
|
||||
PROC_LOCK(td->td_proc);
|
||||
_PHOLD(td->td_proc);
|
||||
error = ptrace_clear_single_step(td);
|
||||
_PRELE(td->td_proc);
|
||||
PROC_UNLOCK(td->td_proc);
|
||||
if (error != 0) {
|
||||
ksiginfo_init_trap(&ksi);
|
||||
ksi.ksi_signo = SIGILL;
|
||||
ksi.ksi_code = ILL_ILLOPC;
|
||||
ksi.ksi_addr = (u_int32_t *)(intptr_t) fault_pc;
|
||||
trapsignal(td, &ksi);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (uh == NULL && (fault_code & FAULT_USER)) {
|
||||
|
@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/uma.h>
|
||||
#include <vm/uma_int.h>
|
||||
|
||||
#include <machine/acle-compat.h>
|
||||
#include <machine/md_var.h>
|
||||
#include <machine/vfp.h>
|
||||
|
||||
@ -204,7 +205,12 @@ cpu_set_syscall_retval(struct thread *td, int error)
|
||||
/*
|
||||
* Reconstruct the pc to point at the swi.
|
||||
*/
|
||||
frame->tf_pc -= INSN_SIZE;
|
||||
#if __ARM_ARCH >= 7
|
||||
if ((frame->tf_spsr & PSR_T) != 0)
|
||||
frame->tf_pc -= THUMB_INSN_SIZE;
|
||||
else
|
||||
#endif
|
||||
frame->tf_pc -= INSN_SIZE;
|
||||
break;
|
||||
case EJUSTRETURN:
|
||||
/* nothing to do */
|
||||
|
Loading…
Reference in New Issue
Block a user