mirror of
https://github.com/suyu-emu/horinux.git
synced 2026-09-21 14:15:21 -07:00
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/czankel/xtensa-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/czankel/xtensa-2.6: (29 commits) [XTENSA] Allow debugger to modify the WINDOWBASE register. [XTENSA] Fix makefile to work with binutils-2.18. [XTENSA] Fix register corruption for certain processor configurations [XTENSA] Fix cache flush macro for D$/I$ aliasing/non-aliasing [XTENSA] Exclude thread-global registers from the xtregs structures. [XTENSA] Add support for the sa_restorer function [XTENSA] Add support for configurable registers and coprocessors [XTENSA] Clean up stat structs. [XTENSA] Use preprocessor to generate the linker script for the ELF boot image [XTENSA] Add missing RELOCATE_ENTRY for debug vector [XTENSA] Add volatile keyword to asm statements accessing counter registers [XTENSA] Remove unused code [XTENSA] Fix modules for non-exec processor configurations [XTENSA] Add missing cast in elf.h ELF_CORE_COPY_REGS() [XTENSA] Fix comments regarding the number of frames to save [XTENSA] Add missing a2 register restore in register spill routine [XTENSA] adjust boot linker script start addresses [XTENSA] Remove oldmask from sigcontext and fix register flush [XTENSA] Clean up elf-gregset. [XTENSA] Fix icache flush for cache aliasing ...
This commit is contained in:
@@ -59,7 +59,7 @@ LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
|
||||
head-y := arch/xtensa/kernel/head.o
|
||||
core-y += arch/xtensa/kernel/ arch/xtensa/mm/
|
||||
ifneq ($(PLATFORM),)
|
||||
core-y += arch/xtensa/platform-$(PLATFORM)/
|
||||
core-y += arch/xtensa/platforms/$(PLATFORM)/
|
||||
endif
|
||||
libs-y += arch/xtensa/lib/ $(LIBGCC)
|
||||
|
||||
|
||||
@@ -14,25 +14,26 @@ OBJCOPY_ARGS := -O elf32-xtensa-le
|
||||
endif
|
||||
|
||||
export OBJCOPY_ARGS
|
||||
export CPPFLAGS_boot.lds += -P -C
|
||||
|
||||
boot-y := bootstrap.o
|
||||
|
||||
OBJS := $(addprefix $(obj)/,$(boot-y))
|
||||
|
||||
Image: vmlinux $(OBJS)
|
||||
$(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
|
||||
Image: vmlinux $(OBJS) arch/$(ARCH)/boot/boot-elf/boot.lds
|
||||
$(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \
|
||||
vmlinux vmlinux.tmp
|
||||
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
|
||||
--add-section image=vmlinux.tmp \
|
||||
--set-section-flags image=contents,alloc,load,load,data \
|
||||
$(OBJS) $@.tmp
|
||||
$(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
|
||||
-T $(srctree)/arch/$(ARCH)/boot/boot-elf/boot.ld \
|
||||
-T arch/$(ARCH)/boot/boot-elf/boot.lds \
|
||||
-o arch/$(ARCH)/boot/$@.elf $@.tmp
|
||||
rm -f $@.tmp vmlinux.tmp
|
||||
|
||||
Image.initrd: vmlinux $(OBJS)
|
||||
$(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
|
||||
$(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \
|
||||
--add-section .initrd=arch/$(ARCH)/boot/ramdisk \
|
||||
--set-section-flags .initrd=contents,alloc,load,load,data \
|
||||
vmlinux vmlinux.tmp
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <asm/variant/core.h>
|
||||
OUTPUT_ARCH(xtensa)
|
||||
ENTRY(_ResetVector)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
@@ -61,7 +63,7 @@ SECTIONS
|
||||
_end = .;
|
||||
_param_start = .;
|
||||
|
||||
.ResetVector.text 0xfe000020 :
|
||||
.ResetVector.text XCHAL_RESET_VECTOR_VADDR :
|
||||
{
|
||||
*(.ResetVector.text)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ LIBS := arch/xtensa/boot/lib/lib.a arch/xtensa/lib/lib.a
|
||||
LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
|
||||
|
||||
zImage: vmlinux $(OBJS) $(LIBS)
|
||||
$(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
|
||||
$(OBJCOPY) --strip-all -R .comment -R .note.gnu.build-id -O binary \
|
||||
vmlinux vmlinux.tmp
|
||||
gzip -vf9 vmlinux.tmp
|
||||
$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
|
||||
|
||||
@@ -2,7 +2,7 @@ OUTPUT_ARCH(xtensa)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.start 0xD0200000 : { *(.start) }
|
||||
.start 0xD1000000 : { *(.start) }
|
||||
|
||||
.text :
|
||||
{
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
|
||||
@@ -64,6 +63,8 @@ int main(void)
|
||||
DEFINE(PT_SIZE, sizeof(struct pt_regs));
|
||||
DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
|
||||
DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
|
||||
DEFINE(PT_XTREGS_OPT, offsetof(struct pt_regs, xtregs_opt));
|
||||
DEFINE(XTREGS_OPT_SIZE, sizeof(xtregs_opt_t));
|
||||
|
||||
/* struct task_struct */
|
||||
DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
|
||||
@@ -77,7 +78,19 @@ int main(void)
|
||||
/* struct thread_info (offset from start_struct) */
|
||||
DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
|
||||
DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
|
||||
DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
|
||||
DEFINE(THREAD_CPENABLE, offsetof (struct thread_info, cpenable));
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
DEFINE(THREAD_XTREGS_CP0, offsetof (struct thread_info, xtregs_cp));
|
||||
DEFINE(THREAD_XTREGS_CP1, offsetof (struct thread_info, xtregs_cp));
|
||||
DEFINE(THREAD_XTREGS_CP2, offsetof (struct thread_info, xtregs_cp));
|
||||
DEFINE(THREAD_XTREGS_CP3, offsetof (struct thread_info, xtregs_cp));
|
||||
DEFINE(THREAD_XTREGS_CP4, offsetof (struct thread_info, xtregs_cp));
|
||||
DEFINE(THREAD_XTREGS_CP5, offsetof (struct thread_info, xtregs_cp));
|
||||
DEFINE(THREAD_XTREGS_CP6, offsetof (struct thread_info, xtregs_cp));
|
||||
DEFINE(THREAD_XTREGS_CP7, offsetof (struct thread_info, xtregs_cp));
|
||||
#endif
|
||||
DEFINE(THREAD_XTREGS_USER, offsetof (struct thread_info, xtregs_user));
|
||||
DEFINE(XTREGS_USER_SIZE, sizeof(xtregs_user_t));
|
||||
DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
|
||||
|
||||
/* struct mm_struct */
|
||||
|
||||
+296
-161
@@ -8,193 +8,328 @@
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2003 - 2005 Tensilica Inc.
|
||||
*
|
||||
* Marc Gauthier <marc@tensilica.com> <marc@alumni.uwaterloo.ca>
|
||||
* Copyright (C) 2003 - 2007 Tensilica Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module contains a table that describes the layout of the various
|
||||
* custom registers and states associated with each coprocessor, as well
|
||||
* as those not associated with any coprocessor ("extra state").
|
||||
* This table is included with core dumps and is available via the ptrace
|
||||
* interface, allowing the layout of such register/state information to
|
||||
* be modified in the kernel without affecting the debugger. Each
|
||||
* register or state is identified using a 32-bit "libdb target number"
|
||||
* assigned when the Xtensa processor is generated.
|
||||
*/
|
||||
|
||||
#include <linux/linkage.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/coprocessor.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/signal.h>
|
||||
#include <asm/tlbflush.h>
|
||||
|
||||
#if XCHAL_HAVE_CP
|
||||
/*
|
||||
* Entry condition:
|
||||
*
|
||||
* a0: trashed, original value saved on stack (PT_AREG0)
|
||||
* a1: a1
|
||||
* a2: new stack pointer, original in DEPC
|
||||
* a3: dispatch table
|
||||
* depc: a2, original value saved on stack (PT_DEPC)
|
||||
* excsave_1: a3
|
||||
*
|
||||
* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
|
||||
* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
|
||||
*/
|
||||
|
||||
#define CP_LAST ((XCHAL_CP_MAX - 1) * COPROCESSOR_INFO_SIZE)
|
||||
/* IO protection is currently unsupported. */
|
||||
|
||||
ENTRY(release_coprocessors)
|
||||
ENTRY(fast_io_protect)
|
||||
wsr a0, EXCSAVE_1
|
||||
movi a0, unrecoverable_exception
|
||||
callx0 a0
|
||||
|
||||
entry a1, 16
|
||||
# a2: task
|
||||
movi a3, 1 << XCHAL_CP_MAX # a3: coprocessor-bit
|
||||
movi a4, coprocessor_info+CP_LAST # a4: owner-table
|
||||
# a5: tmp
|
||||
movi a6, 0 # a6: 0
|
||||
rsil a7, LOCKLEVEL # a7: PS
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
|
||||
1: /* Check if task is coprocessor owner of coprocessor[i]. */
|
||||
/*
|
||||
* Macros for lazy context switch.
|
||||
*/
|
||||
|
||||
l32i a5, a4, COPROCESSOR_INFO_OWNER
|
||||
srli a3, a3, 1
|
||||
#define SAVE_CP_REGS(x) \
|
||||
.align 4; \
|
||||
.Lsave_cp_regs_cp##x: \
|
||||
.if XTENSA_HAVE_COPROCESSOR(x); \
|
||||
xchal_cp##x##_store a2 a4 a5 a6 a7; \
|
||||
.endif; \
|
||||
jx a0
|
||||
|
||||
#define SAVE_CP_REGS_TAB(x) \
|
||||
.if XTENSA_HAVE_COPROCESSOR(x); \
|
||||
.long .Lsave_cp_regs_cp##x - .Lsave_cp_regs_jump_table; \
|
||||
.else; \
|
||||
.long 0; \
|
||||
.endif; \
|
||||
.long THREAD_XTREGS_CP##x
|
||||
|
||||
|
||||
#define LOAD_CP_REGS(x) \
|
||||
.align 4; \
|
||||
.Lload_cp_regs_cp##x: \
|
||||
.if XTENSA_HAVE_COPROCESSOR(x); \
|
||||
xchal_cp##x##_load a2 a4 a5 a6 a7; \
|
||||
.endif; \
|
||||
jx a0
|
||||
|
||||
#define LOAD_CP_REGS_TAB(x) \
|
||||
.if XTENSA_HAVE_COPROCESSOR(x); \
|
||||
.long .Lload_cp_regs_cp##x - .Lload_cp_regs_jump_table; \
|
||||
.else; \
|
||||
.long 0; \
|
||||
.endif; \
|
||||
.long THREAD_XTREGS_CP##x
|
||||
|
||||
SAVE_CP_REGS(0)
|
||||
SAVE_CP_REGS(1)
|
||||
SAVE_CP_REGS(2)
|
||||
SAVE_CP_REGS(3)
|
||||
SAVE_CP_REGS(4)
|
||||
SAVE_CP_REGS(5)
|
||||
SAVE_CP_REGS(6)
|
||||
SAVE_CP_REGS(7)
|
||||
|
||||
LOAD_CP_REGS(0)
|
||||
LOAD_CP_REGS(1)
|
||||
LOAD_CP_REGS(2)
|
||||
LOAD_CP_REGS(3)
|
||||
LOAD_CP_REGS(4)
|
||||
LOAD_CP_REGS(5)
|
||||
LOAD_CP_REGS(6)
|
||||
LOAD_CP_REGS(7)
|
||||
|
||||
.align 4
|
||||
.Lsave_cp_regs_jump_table:
|
||||
SAVE_CP_REGS_TAB(0)
|
||||
SAVE_CP_REGS_TAB(1)
|
||||
SAVE_CP_REGS_TAB(2)
|
||||
SAVE_CP_REGS_TAB(3)
|
||||
SAVE_CP_REGS_TAB(4)
|
||||
SAVE_CP_REGS_TAB(5)
|
||||
SAVE_CP_REGS_TAB(6)
|
||||
SAVE_CP_REGS_TAB(7)
|
||||
|
||||
.Lload_cp_regs_jump_table:
|
||||
LOAD_CP_REGS_TAB(0)
|
||||
LOAD_CP_REGS_TAB(1)
|
||||
LOAD_CP_REGS_TAB(2)
|
||||
LOAD_CP_REGS_TAB(3)
|
||||
LOAD_CP_REGS_TAB(4)
|
||||
LOAD_CP_REGS_TAB(5)
|
||||
LOAD_CP_REGS_TAB(6)
|
||||
LOAD_CP_REGS_TAB(7)
|
||||
|
||||
/*
|
||||
* coprocessor_save(buffer, index)
|
||||
* a2 a3
|
||||
* coprocessor_load(buffer, index)
|
||||
* a2 a3
|
||||
*
|
||||
* Save or load coprocessor registers for coprocessor 'index'.
|
||||
* The register values are saved to or loaded from them 'buffer' address.
|
||||
*
|
||||
* Note that these functions don't update the coprocessor_owner information!
|
||||
*
|
||||
*/
|
||||
|
||||
ENTRY(coprocessor_save)
|
||||
entry a1, 32
|
||||
s32i a0, a1, 0
|
||||
movi a0, .Lsave_cp_regs_jump_table
|
||||
addx8 a3, a3, a0
|
||||
l32i a3, a3, 0
|
||||
beqz a3, 1f
|
||||
addi a4, a4, -8
|
||||
beq a2, a5, 1b
|
||||
|
||||
/* Found an entry: Clear entry CPENABLE bit to disable CP. */
|
||||
|
||||
rsr a5, CPENABLE
|
||||
s32i a6, a4, COPROCESSOR_INFO_OWNER
|
||||
xor a5, a3, a5
|
||||
wsr a5, CPENABLE
|
||||
|
||||
bnez a3, 1b
|
||||
|
||||
1: wsr a7, PS
|
||||
rsync
|
||||
add a0, a0, a3
|
||||
callx0 a0
|
||||
1: l32i a0, a1, 0
|
||||
retw
|
||||
|
||||
|
||||
ENTRY(disable_coprocessor)
|
||||
entry sp, 16
|
||||
rsil a7, LOCKLEVEL
|
||||
rsr a3, CPENABLE
|
||||
movi a4, 1
|
||||
ssl a2
|
||||
sll a4, a4
|
||||
and a4, a3, a4
|
||||
xor a3, a3, a4
|
||||
wsr a3, CPENABLE
|
||||
wsr a7, PS
|
||||
rsync
|
||||
ENTRY(coprocessor_load)
|
||||
entry a1, 32
|
||||
s32i a0, a1, 0
|
||||
movi a0, .Lload_cp_regs_jump_table
|
||||
addx4 a3, a3, a0
|
||||
l32i a3, a3, 0
|
||||
beqz a3, 1f
|
||||
add a0, a0, a3
|
||||
callx0 a0
|
||||
1: l32i a0, a1, 0
|
||||
retw
|
||||
|
||||
ENTRY(enable_coprocessor)
|
||||
entry sp, 16
|
||||
rsil a7, LOCKLEVEL
|
||||
rsr a3, CPENABLE
|
||||
movi a4, 1
|
||||
ssl a2
|
||||
sll a4, a4
|
||||
or a3, a3, a4
|
||||
wsr a3, CPENABLE
|
||||
wsr a7, PS
|
||||
rsync
|
||||
retw
|
||||
|
||||
|
||||
ENTRY(save_coprocessor_extra)
|
||||
entry sp, 16
|
||||
xchal_extra_store_funcbody
|
||||
retw
|
||||
|
||||
ENTRY(restore_coprocessor_extra)
|
||||
entry sp, 16
|
||||
xchal_extra_load_funcbody
|
||||
retw
|
||||
|
||||
ENTRY(save_coprocessor_registers)
|
||||
entry sp, 16
|
||||
xchal_cpi_store_funcbody
|
||||
retw
|
||||
|
||||
ENTRY(restore_coprocessor_registers)
|
||||
entry sp, 16
|
||||
xchal_cpi_load_funcbody
|
||||
retw
|
||||
|
||||
|
||||
/*
|
||||
* The Xtensa compile-time HAL (core.h) XCHAL_*_SA_CONTENTS_LIBDB macros
|
||||
* describe the contents of coprocessor & extra save areas in terms of
|
||||
* undefined CONTENTS_LIBDB_{SREG,UREG,REGF} macros. We define these
|
||||
* latter macros here; they expand into a table of the format we want.
|
||||
* The general format is:
|
||||
* coprocessor_flush(struct task_info*, index)
|
||||
* a2 a3
|
||||
* coprocessor_restore(struct task_info*, index)
|
||||
* a2 a3
|
||||
*
|
||||
* CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum,
|
||||
* bitmask, rsv2, rsv3)
|
||||
* CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum,
|
||||
* bitmask, rsv2, rsv3)
|
||||
* CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index,
|
||||
* numentries, contentsize, regname_base,
|
||||
* regfile_name, rsv2, rsv3)
|
||||
* Save or load coprocessor registers for coprocessor 'index'.
|
||||
* The register values are saved to or loaded from the coprocessor area
|
||||
* inside the task_info structure.
|
||||
*
|
||||
* Note that these functions don't update the coprocessor_owner information!
|
||||
*
|
||||
* For this table, we only care about the <libdbnum>, <offset> and <size>
|
||||
* fields.
|
||||
*/
|
||||
|
||||
/* Map all XCHAL CONTENTS macros to the reg_entry asm macro defined below: */
|
||||
|
||||
#define CONTENTS_LIBDB_SREG(libdbnum,offset,size,align,rsv1,name,sregnum, \
|
||||
bitmask, rsv2, rsv3) \
|
||||
reg_entry libdbnum, offset, size ;
|
||||
#define CONTENTS_LIBDB_UREG(libdbnum,offset,size,align,rsv1,name,uregnum, \
|
||||
bitmask, rsv2, rsv3) \
|
||||
reg_entry libdbnum, offset, size ;
|
||||
#define CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, \
|
||||
numentries, contentsize, regname_base, \
|
||||
regfile_name, rsv2, rsv3) \
|
||||
reg_entry libdbnum, offset, size ;
|
||||
ENTRY(coprocessor_flush)
|
||||
entry a1, 32
|
||||
s32i a0, a1, 0
|
||||
movi a0, .Lsave_cp_regs_jump_table
|
||||
addx8 a3, a3, a0
|
||||
l32i a4, a3, 4
|
||||
l32i a3, a3, 0
|
||||
add a2, a2, a4
|
||||
beqz a3, 1f
|
||||
add a0, a0, a3
|
||||
callx0 a0
|
||||
1: l32i a0, a1, 0
|
||||
retw
|
||||
|
||||
/* A single table entry: */
|
||||
.macro reg_entry libdbnum, offset, size
|
||||
.ifne (__last_offset-(__last_group_offset+\offset))
|
||||
/* padding entry */
|
||||
.word (0xFC000000+__last_offset-(__last_group_offset+\offset))
|
||||
.endif
|
||||
.word \libdbnum /* actual entry */
|
||||
.set __last_offset, __last_group_offset+\offset+\size
|
||||
.endm /* reg_entry */
|
||||
|
||||
|
||||
/* Table entry that marks the beginning of a group (coprocessor or "extra"): */
|
||||
.macro reg_group cpnum, num_entries, align
|
||||
.set __last_group_offset, (__last_offset + \align- 1) & -\align
|
||||
.ifne \num_entries
|
||||
.word 0xFD000000+(\cpnum<<16)+\num_entries
|
||||
.endif
|
||||
.endm /* reg_group */
|
||||
ENTRY(coprocessor_restore)
|
||||
entry a1, 32
|
||||
s32i a0, a1, 0
|
||||
movi a0, .Lload_cp_regs_jump_table
|
||||
addx4 a3, a3, a0
|
||||
l32i a4, a3, 4
|
||||
l32i a3, a3, 0
|
||||
add a2, a2, a4
|
||||
beqz a3, 1f
|
||||
add a0, a0, a3
|
||||
callx0 a0
|
||||
1: l32i a0, a1, 0
|
||||
retw
|
||||
|
||||
/*
|
||||
* Register info tables.
|
||||
* Entry condition:
|
||||
*
|
||||
* a0: trashed, original value saved on stack (PT_AREG0)
|
||||
* a1: a1
|
||||
* a2: new stack pointer, original in DEPC
|
||||
* a3: dispatch table
|
||||
* depc: a2, original value saved on stack (PT_DEPC)
|
||||
* excsave_1: a3
|
||||
*
|
||||
* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
|
||||
* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
|
||||
*/
|
||||
|
||||
.section .rodata, "a"
|
||||
.globl _xtensa_reginfo_tables
|
||||
.globl _xtensa_reginfo_table_size
|
||||
.align 4
|
||||
_xtensa_reginfo_table_size:
|
||||
.word _xtensa_reginfo_table_end - _xtensa_reginfo_tables
|
||||
ENTRY(fast_coprocessor_double)
|
||||
wsr a0, EXCSAVE_1
|
||||
movi a0, unrecoverable_exception
|
||||
callx0 a0
|
||||
|
||||
_xtensa_reginfo_tables:
|
||||
.set __last_offset, 0
|
||||
reg_group 0xFF, XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM, XCHAL_EXTRA_SA_ALIGN
|
||||
XCHAL_EXTRA_SA_CONTENTS_LIBDB
|
||||
reg_group 0, XCHAL_CP0_SA_CONTENTS_LIBDB_NUM, XCHAL_CP0_SA_ALIGN
|
||||
XCHAL_CP0_SA_CONTENTS_LIBDB
|
||||
reg_group 1, XCHAL_CP1_SA_CONTENTS_LIBDB_NUM, XCHAL_CP1_SA_ALIGN
|
||||
XCHAL_CP1_SA_CONTENTS_LIBDB
|
||||
reg_group 2, XCHAL_CP2_SA_CONTENTS_LIBDB_NUM, XCHAL_CP2_SA_ALIGN
|
||||
XCHAL_CP2_SA_CONTENTS_LIBDB
|
||||
reg_group 3, XCHAL_CP3_SA_CONTENTS_LIBDB_NUM, XCHAL_CP3_SA_ALIGN
|
||||
XCHAL_CP3_SA_CONTENTS_LIBDB
|
||||
reg_group 4, XCHAL_CP4_SA_CONTENTS_LIBDB_NUM, XCHAL_CP4_SA_ALIGN
|
||||
XCHAL_CP4_SA_CONTENTS_LIBDB
|
||||
reg_group 5, XCHAL_CP5_SA_CONTENTS_LIBDB_NUM, XCHAL_CP5_SA_ALIGN
|
||||
XCHAL_CP5_SA_CONTENTS_LIBDB
|
||||
reg_group 6, XCHAL_CP6_SA_CONTENTS_LIBDB_NUM, XCHAL_CP6_SA_ALIGN
|
||||
XCHAL_CP6_SA_CONTENTS_LIBDB
|
||||
reg_group 7, XCHAL_CP7_SA_CONTENTS_LIBDB_NUM, XCHAL_CP7_SA_ALIGN
|
||||
XCHAL_CP7_SA_CONTENTS_LIBDB
|
||||
.word 0xFC000000 /* invalid register number,marks end of table*/
|
||||
_xtensa_reginfo_table_end:
|
||||
#endif
|
||||
|
||||
ENTRY(fast_coprocessor)
|
||||
|
||||
/* Save remaining registers a1-a3 and SAR */
|
||||
|
||||
xsr a3, EXCSAVE_1
|
||||
s32i a3, a2, PT_AREG3
|
||||
rsr a3, SAR
|
||||
s32i a1, a2, PT_AREG1
|
||||
s32i a3, a2, PT_SAR
|
||||
mov a1, a2
|
||||
rsr a2, DEPC
|
||||
s32i a2, a1, PT_AREG2
|
||||
|
||||
/*
|
||||
* The hal macros require up to 4 temporary registers. We use a3..a6.
|
||||
*/
|
||||
|
||||
s32i a4, a1, PT_AREG4
|
||||
s32i a5, a1, PT_AREG5
|
||||
s32i a6, a1, PT_AREG6
|
||||
|
||||
/* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */
|
||||
|
||||
rsr a3, EXCCAUSE
|
||||
addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED
|
||||
|
||||
/* Set corresponding CPENABLE bit -> (sar:cp-index, a3: 1<<cp-index)*/
|
||||
|
||||
ssl a3 # SAR: 32 - coprocessor_number
|
||||
movi a2, 1
|
||||
rsr a0, CPENABLE
|
||||
sll a2, a2
|
||||
or a0, a0, a2
|
||||
wsr a0, CPENABLE
|
||||
rsync
|
||||
|
||||
/* Retrieve previous owner. (a3 still holds CP number) */
|
||||
|
||||
movi a0, coprocessor_owner # list of owners
|
||||
addx4 a0, a3, a0 # entry for CP
|
||||
l32i a4, a0, 0
|
||||
|
||||
beqz a4, 1f # skip 'save' if no previous owner
|
||||
|
||||
/* Disable coprocessor for previous owner. (a2 = 1 << CP number) */
|
||||
|
||||
l32i a5, a4, THREAD_CPENABLE
|
||||
xor a5, a5, a2 # (1 << cp-id) still in a2
|
||||
s32i a5, a4, THREAD_CPENABLE
|
||||
|
||||
/*
|
||||
* Get context save area and 'call' save routine.
|
||||
* (a4 still holds previous owner (thread_info), a3 CP number)
|
||||
*/
|
||||
|
||||
movi a5, .Lsave_cp_regs_jump_table
|
||||
movi a0, 2f # a0: 'return' address
|
||||
addx8 a3, a3, a5 # a3: coprocessor number
|
||||
l32i a2, a3, 4 # a2: xtregs offset
|
||||
l32i a3, a3, 0 # a3: jump offset
|
||||
add a2, a2, a4
|
||||
add a4, a3, a5 # a4: address of save routine
|
||||
jx a4
|
||||
|
||||
/* Note that only a0 and a1 were preserved. */
|
||||
|
||||
2: rsr a3, EXCCAUSE
|
||||
addi a3, a3, -EXCCAUSE_COPROCESSOR0_DISABLED
|
||||
movi a0, coprocessor_owner
|
||||
addx4 a0, a3, a0
|
||||
|
||||
/* Set new 'owner' (a0 points to the CP owner, a3 contains the CP nr) */
|
||||
|
||||
1: GET_THREAD_INFO (a4, a1)
|
||||
s32i a4, a0, 0
|
||||
|
||||
/* Get context save area and 'call' load routine. */
|
||||
|
||||
movi a5, .Lload_cp_regs_jump_table
|
||||
movi a0, 1f
|
||||
addx8 a3, a3, a5
|
||||
l32i a2, a3, 4 # a2: xtregs offset
|
||||
l32i a3, a3, 0 # a3: jump offset
|
||||
add a2, a2, a4
|
||||
add a4, a3, a5
|
||||
jx a4
|
||||
|
||||
/* Restore all registers and return from exception handler. */
|
||||
|
||||
1: l32i a6, a1, PT_AREG6
|
||||
l32i a5, a1, PT_AREG5
|
||||
l32i a4, a1, PT_AREG4
|
||||
|
||||
l32i a0, a1, PT_SAR
|
||||
l32i a3, a1, PT_AREG3
|
||||
l32i a2, a1, PT_AREG2
|
||||
wsr a0, SAR
|
||||
l32i a0, a1, PT_AREG0
|
||||
l32i a1, a1, PT_AREG1
|
||||
|
||||
rfe
|
||||
|
||||
.data
|
||||
ENTRY(coprocessor_owner)
|
||||
.fill XCHAL_CP_MAX, 4, 0
|
||||
|
||||
#endif /* XTENSA_HAVE_COPROCESSORS */
|
||||
|
||||
|
||||
+90
-273
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@ void *module_alloc(unsigned long size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
return vmalloc(size);
|
||||
return vmalloc_exec(size);
|
||||
}
|
||||
|
||||
void module_free(struct module *mod, void *module_region)
|
||||
|
||||
+99
-207
@@ -52,6 +52,55 @@ void (*pm_power_off)(void) = NULL;
|
||||
EXPORT_SYMBOL(pm_power_off);
|
||||
|
||||
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
|
||||
void coprocessor_release_all(struct thread_info *ti)
|
||||
{
|
||||
unsigned long cpenable;
|
||||
int i;
|
||||
|
||||
/* Make sure we don't switch tasks during this operation. */
|
||||
|
||||
preempt_disable();
|
||||
|
||||
/* Walk through all cp owners and release it for the requested one. */
|
||||
|
||||
cpenable = ti->cpenable;
|
||||
|
||||
for (i = 0; i < XCHAL_CP_MAX; i++) {
|
||||
if (coprocessor_owner[i] == ti) {
|
||||
coprocessor_owner[i] = 0;
|
||||
cpenable &= ~(1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
ti->cpenable = cpenable;
|
||||
coprocessor_clear_cpenable();
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
void coprocessor_flush_all(struct thread_info *ti)
|
||||
{
|
||||
unsigned long cpenable;
|
||||
int i;
|
||||
|
||||
preempt_disable();
|
||||
|
||||
cpenable = ti->cpenable;
|
||||
|
||||
for (i = 0; i < XCHAL_CP_MAX; i++) {
|
||||
if ((cpenable & 1) != 0 && coprocessor_owner[i] == ti)
|
||||
coprocessor_flush(ti, i);
|
||||
cpenable >>= 1;
|
||||
}
|
||||
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Powermanagement idle function, if any is provided by the platform.
|
||||
*/
|
||||
@@ -71,15 +120,36 @@ void cpu_idle(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Free current thread data structures etc..
|
||||
* This is called when the thread calls exit().
|
||||
*/
|
||||
|
||||
void exit_thread(void)
|
||||
{
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
coprocessor_release_all(current_thread_info());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush thread state. This is called when a thread does an execve()
|
||||
* Note that we flush coprocessor registers for the case execve fails.
|
||||
*/
|
||||
void flush_thread(void)
|
||||
{
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
struct thread_info *ti = current_thread_info();
|
||||
coprocessor_flush_all(ti);
|
||||
coprocessor_release_all(ti);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called before the thread is copied.
|
||||
*/
|
||||
void prepare_to_copy(struct task_struct *tsk)
|
||||
{
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
coprocessor_flush_all(task_thread_info(tsk));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -107,6 +177,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
|
||||
struct task_struct * p, struct pt_regs * regs)
|
||||
{
|
||||
struct pt_regs *childregs;
|
||||
struct thread_info *ti;
|
||||
unsigned long tos;
|
||||
int user_mode = user_mode(regs);
|
||||
|
||||
@@ -128,13 +199,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
|
||||
p->set_child_tid = p->clear_child_tid = NULL;
|
||||
p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
|
||||
p->thread.sp = (unsigned long)childregs;
|
||||
|
||||
if (user_mode(regs)) {
|
||||
|
||||
int len = childregs->wmask & ~0xf;
|
||||
childregs->areg[1] = usp;
|
||||
memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
|
||||
®s->areg[XCHAL_NUM_AREGS - len/4], len);
|
||||
|
||||
// FIXME: we need to set THREADPTR in thread_info...
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
childregs->areg[2] = childregs->areg[6];
|
||||
|
||||
@@ -142,6 +214,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
|
||||
/* In kernel space, we start a new thread with a new stack. */
|
||||
childregs->wmask = 1;
|
||||
}
|
||||
|
||||
#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
|
||||
ti = task_thread_info(p);
|
||||
ti->cpenable = 0;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -179,10 +257,6 @@ unsigned long get_wchan(struct task_struct *p)
|
||||
}
|
||||
|
||||
/*
|
||||
* do_copy_regs() gathers information from 'struct pt_regs' and
|
||||
* 'current->thread.areg[]' to fill in the xtensa_gregset_t
|
||||
* structure.
|
||||
*
|
||||
* xtensa_gregset_t and 'struct pt_regs' are vastly different formats
|
||||
* of processor registers. Besides different ordering,
|
||||
* xtensa_gregset_t contains non-live register information that
|
||||
@@ -191,18 +265,19 @@ unsigned long get_wchan(struct task_struct *p)
|
||||
*
|
||||
*/
|
||||
|
||||
void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
|
||||
struct task_struct *tsk)
|
||||
void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
|
||||
{
|
||||
int i, n, wb_offset;
|
||||
unsigned long wb, ws, wm;
|
||||
int live, last;
|
||||
|
||||
elfregs->xchal_config_id0 = XCHAL_HW_CONFIGID0;
|
||||
elfregs->xchal_config_id1 = XCHAL_HW_CONFIGID1;
|
||||
wb = regs->windowbase;
|
||||
ws = regs->windowstart;
|
||||
wm = regs->wmask;
|
||||
ws = ((ws >> wb) | (ws << (WSBITS - wb))) & ((1 << WSBITS) - 1);
|
||||
|
||||
__asm__ __volatile__ ("rsr %0, 176\n" : "=a" (i));
|
||||
elfregs->cpux = i;
|
||||
__asm__ __volatile__ ("rsr %0, 208\n" : "=a" (i));
|
||||
elfregs->cpuy = i;
|
||||
/* Don't leak any random bits. */
|
||||
|
||||
memset(elfregs, 0, sizeof (elfregs));
|
||||
|
||||
/* Note: PS.EXCM is not set while user task is running; its
|
||||
* being set in regs->ps is for exception handling convenience.
|
||||
@@ -210,204 +285,22 @@ void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
|
||||
|
||||
elfregs->pc = regs->pc;
|
||||
elfregs->ps = (regs->ps & ~(1 << PS_EXCM_BIT));
|
||||
elfregs->exccause = regs->exccause;
|
||||
elfregs->excvaddr = regs->excvaddr;
|
||||
elfregs->windowbase = regs->windowbase;
|
||||
elfregs->windowstart = regs->windowstart;
|
||||
elfregs->lbeg = regs->lbeg;
|
||||
elfregs->lend = regs->lend;
|
||||
elfregs->lcount = regs->lcount;
|
||||
elfregs->sar = regs->sar;
|
||||
elfregs->syscall = regs->syscall;
|
||||
elfregs->windowstart = ws;
|
||||
|
||||
/* Copy register file.
|
||||
* The layout looks like this:
|
||||
*
|
||||
* | a0 ... a15 | Z ... Z | arX ... arY |
|
||||
* current window unused saved frames
|
||||
*/
|
||||
|
||||
memset (elfregs->ar, 0, sizeof(elfregs->ar));
|
||||
|
||||
wb_offset = regs->windowbase * 4;
|
||||
n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
|
||||
|
||||
n = (regs->wmask >> 4) * 4;
|
||||
|
||||
for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
|
||||
elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
|
||||
live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
|
||||
last = XCHAL_NUM_AREGS - (wm >> 4) * 4;
|
||||
memcpy(elfregs->a, regs->areg, live * 4);
|
||||
memcpy(elfregs->a + last, regs->areg + last, (wm >> 4) * 16);
|
||||
}
|
||||
|
||||
void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
|
||||
int dump_fpu(void)
|
||||
{
|
||||
do_copy_regs ((xtensa_gregset_t *)elfregs, regs, current);
|
||||
}
|
||||
|
||||
|
||||
/* The inverse of do_copy_regs(). No error or sanity checking. */
|
||||
|
||||
void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
int i, n, wb_offset;
|
||||
|
||||
/* Note: PS.EXCM is not set while user task is running; it
|
||||
* needs to be set in regs->ps is for exception handling convenience.
|
||||
*/
|
||||
|
||||
regs->pc = elfregs->pc;
|
||||
regs->ps = (elfregs->ps | (1 << PS_EXCM_BIT));
|
||||
regs->exccause = elfregs->exccause;
|
||||
regs->excvaddr = elfregs->excvaddr;
|
||||
regs->windowbase = elfregs->windowbase;
|
||||
regs->windowstart = elfregs->windowstart;
|
||||
regs->lbeg = elfregs->lbeg;
|
||||
regs->lend = elfregs->lend;
|
||||
regs->lcount = elfregs->lcount;
|
||||
regs->sar = elfregs->sar;
|
||||
regs->syscall = elfregs->syscall;
|
||||
|
||||
/* Clear everything. */
|
||||
|
||||
memset (regs->areg, 0, sizeof(regs->areg));
|
||||
|
||||
/* Copy regs from live window frame. */
|
||||
|
||||
wb_offset = regs->windowbase * 4;
|
||||
n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
|
||||
|
||||
n = (regs->wmask >> 4) * 4;
|
||||
|
||||
for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
|
||||
regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* do_save_fpregs() gathers information from 'struct pt_regs' and
|
||||
* 'current->thread' to fill in the elf_fpregset_t structure.
|
||||
*
|
||||
* Core files and ptrace use elf_fpregset_t.
|
||||
*/
|
||||
|
||||
void do_save_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
#if XCHAL_HAVE_CP
|
||||
|
||||
extern unsigned char _xtensa_reginfo_tables[];
|
||||
extern unsigned _xtensa_reginfo_table_size;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
/* Before dumping coprocessor state from memory,
|
||||
* ensure any live coprocessor contents for this
|
||||
* task are first saved to memory:
|
||||
*/
|
||||
local_irq_save(flags);
|
||||
|
||||
for (i = 0; i < XCHAL_CP_MAX; i++) {
|
||||
if (tsk == coprocessor_info[i].owner) {
|
||||
enable_coprocessor(i);
|
||||
save_coprocessor_registers(
|
||||
tsk->thread.cp_save+coprocessor_info[i].offset,i);
|
||||
disable_coprocessor(i);
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* Now dump coprocessor & extra state: */
|
||||
memcpy((unsigned char*)fpregs,
|
||||
_xtensa_reginfo_tables, _xtensa_reginfo_table_size);
|
||||
memcpy((unsigned char*)fpregs + _xtensa_reginfo_table_size,
|
||||
tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* The inverse of do_save_fpregs().
|
||||
* Copies coprocessor and extra state from fpregs into regs and tsk->thread.
|
||||
* Returns 0 on success, non-zero if layout doesn't match.
|
||||
*/
|
||||
|
||||
int do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
|
||||
struct task_struct *tsk)
|
||||
{
|
||||
#if XCHAL_HAVE_CP
|
||||
|
||||
extern unsigned char _xtensa_reginfo_tables[];
|
||||
extern unsigned _xtensa_reginfo_table_size;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
/* Make sure save area layouts match.
|
||||
* FIXME: in the future we could allow restoring from
|
||||
* a different layout of the same registers, by comparing
|
||||
* fpregs' table with _xtensa_reginfo_tables and matching
|
||||
* entries and copying registers one at a time.
|
||||
* Not too sure yet whether that's very useful.
|
||||
*/
|
||||
|
||||
if( memcmp((unsigned char*)fpregs,
|
||||
_xtensa_reginfo_tables, _xtensa_reginfo_table_size) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Before restoring coprocessor state from memory,
|
||||
* ensure any live coprocessor contents for this
|
||||
* task are first invalidated.
|
||||
*/
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
for (i = 0; i < XCHAL_CP_MAX; i++) {
|
||||
if (tsk == coprocessor_info[i].owner) {
|
||||
enable_coprocessor(i);
|
||||
save_coprocessor_registers(
|
||||
tsk->thread.cp_save+coprocessor_info[i].offset,i);
|
||||
coprocessor_info[i].owner = 0;
|
||||
disable_coprocessor(i);
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* Now restore coprocessor & extra state: */
|
||||
|
||||
memcpy(tsk->thread.cp_save,
|
||||
(unsigned char*)fpregs + _xtensa_reginfo_table_size,
|
||||
XTENSA_CP_EXTRA_SIZE);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Fill in the CP structure for a core dump for a particular task.
|
||||
*/
|
||||
|
||||
int
|
||||
dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r)
|
||||
{
|
||||
return 0; /* no coprocessors active on this processor */
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the CP structure for a core dump.
|
||||
* This includes any FPU coprocessor.
|
||||
* Here, we dump all coprocessors, and other ("extra") custom state.
|
||||
*
|
||||
* This function is called by elf_core_dump() in fs/binfmt_elf.c
|
||||
* (in which case 'regs' comes from calls to do_coredump, see signals.c).
|
||||
*/
|
||||
int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
|
||||
{
|
||||
return dump_task_fpu(regs, current, r);
|
||||
}
|
||||
|
||||
asmlinkage
|
||||
long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
|
||||
@@ -421,8 +314,8 @@ long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
|
||||
}
|
||||
|
||||
/*
|
||||
* * xtensa_execve() executes a new program.
|
||||
* */
|
||||
* xtensa_execve() executes a new program.
|
||||
*/
|
||||
|
||||
asmlinkage
|
||||
long xtensa_execve(char __user *name, char __user * __user *argv,
|
||||
@@ -437,7 +330,6 @@ long xtensa_execve(char __user *name, char __user * __user *argv,
|
||||
error = PTR_ERR(filename);
|
||||
if (IS_ERR(filename))
|
||||
goto out;
|
||||
// FIXME: release coprocessor??
|
||||
error = do_execve(filename, argv, envp, regs);
|
||||
if (error == 0) {
|
||||
task_lock(current);
|
||||
|
||||
+198
-173
@@ -4,7 +4,7 @@
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2001 - 2005 Tensilica Inc.
|
||||
* Copyright (C) 2001 - 2007 Tensilica Inc.
|
||||
*
|
||||
* Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
|
||||
* Chris Zankel <chris@zankel.net>
|
||||
@@ -28,14 +28,10 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/elf.h>
|
||||
|
||||
#define TEST_KERNEL // verify kernel operations FIXME: remove
|
||||
|
||||
#include <asm/coprocessor.h>
|
||||
|
||||
/*
|
||||
* Called by kernel/ptrace.c when detaching..
|
||||
*
|
||||
* Make sure single step bits etc are not set.
|
||||
* Called by kernel/ptrace.c when detaching to disable single stepping.
|
||||
*/
|
||||
|
||||
void ptrace_disable(struct task_struct *child)
|
||||
@@ -43,136 +39,237 @@ void ptrace_disable(struct task_struct *child)
|
||||
/* Nothing to do.. */
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
int ptrace_getregs(struct task_struct *child, void __user *uregs)
|
||||
{
|
||||
int ret = -EPERM;
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
xtensa_gregset_t __user *gregset = uregs;
|
||||
unsigned long wm = regs->wmask;
|
||||
unsigned long wb = regs->windowbase;
|
||||
int live, i;
|
||||
|
||||
switch (request) {
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
case PTRACE_PEEKDATA:
|
||||
ret = generic_ptrace_peekdata(child, addr, data);
|
||||
goto out;
|
||||
if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
|
||||
return -EIO;
|
||||
|
||||
/* Read the word at location addr in the USER area. */
|
||||
__put_user(regs->pc, &gregset->pc);
|
||||
__put_user(regs->ps & ~(1 << PS_EXCM_BIT), &gregset->ps);
|
||||
__put_user(regs->lbeg, &gregset->lbeg);
|
||||
__put_user(regs->lend, &gregset->lend);
|
||||
__put_user(regs->lcount, &gregset->lcount);
|
||||
__put_user(regs->windowstart, &gregset->windowstart);
|
||||
__put_user(regs->windowbase, &gregset->windowbase);
|
||||
|
||||
case PTRACE_PEEKUSR:
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
unsigned long tmp;
|
||||
live = (wm & 2) ? 4 : (wm & 4) ? 8 : (wm & 8) ? 12 : 16;
|
||||
|
||||
regs = task_pt_regs(child);
|
||||
tmp = 0; /* Default return value. */
|
||||
for (i = 0; i < live; i++)
|
||||
__put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
|
||||
for (i = XCHAL_NUM_AREGS - (wm >> 4) * 4; i < XCHAL_NUM_AREGS; i++)
|
||||
__put_user(regs->areg[i],gregset->a+((wb*4+i)%XCHAL_NUM_AREGS));
|
||||
|
||||
switch(addr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ptrace_setregs(struct task_struct *child, void __user *uregs)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
xtensa_gregset_t *gregset = uregs;
|
||||
const unsigned long ps_mask = PS_CALLINC_MASK | PS_OWB_MASK;
|
||||
unsigned long ps;
|
||||
unsigned long wb;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, uregs, sizeof(xtensa_gregset_t)))
|
||||
return -EIO;
|
||||
|
||||
__get_user(regs->pc, &gregset->pc);
|
||||
__get_user(ps, &gregset->ps);
|
||||
__get_user(regs->lbeg, &gregset->lbeg);
|
||||
__get_user(regs->lend, &gregset->lend);
|
||||
__get_user(regs->lcount, &gregset->lcount);
|
||||
__get_user(regs->windowstart, &gregset->windowstart);
|
||||
__get_user(wb, &gregset->windowbase);
|
||||
|
||||
regs->ps = (regs->ps & ~ps_mask) | (ps & ps_mask) | (1 << PS_EXCM_BIT);
|
||||
|
||||
if (wb >= XCHAL_NUM_AREGS / 4)
|
||||
return -EFAULT;
|
||||
|
||||
regs->windowbase = wb;
|
||||
|
||||
if (wb != 0 && __copy_from_user(regs->areg + XCHAL_NUM_AREGS - wb * 4,
|
||||
gregset->a, wb * 16))
|
||||
return -EFAULT;
|
||||
|
||||
if (__copy_from_user(regs->areg, gregset->a + wb*4, (WSBITS-wb) * 16))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ptrace_getxregs(struct task_struct *child, void __user *uregs)
|
||||
{
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
struct thread_info *ti = task_thread_info(child);
|
||||
elf_xtregs_t __user *xtregs = uregs;
|
||||
int ret = 0;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, uregs, sizeof(elf_xtregs_t)))
|
||||
return -EIO;
|
||||
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
/* Flush all coprocessor registers to memory. */
|
||||
coprocessor_flush_all(ti);
|
||||
ret |= __copy_to_user(&xtregs->cp0, &ti->xtregs_cp,
|
||||
sizeof(xtregs_coprocessor_t));
|
||||
#endif
|
||||
ret |= __copy_to_user(&xtregs->opt, ®s->xtregs_opt,
|
||||
sizeof(xtregs->opt));
|
||||
ret |= __copy_to_user(&xtregs->user,&ti->xtregs_user,
|
||||
sizeof(xtregs->user));
|
||||
|
||||
return ret ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
int ptrace_setxregs(struct task_struct *child, void __user *uregs)
|
||||
{
|
||||
struct thread_info *ti = task_thread_info(child);
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
elf_xtregs_t *xtregs = uregs;
|
||||
int ret = 0;
|
||||
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
/* Flush all coprocessors before we overwrite them. */
|
||||
coprocessor_flush_all(ti);
|
||||
coprocessor_release_all(ti);
|
||||
|
||||
ret |= __copy_from_user(&ti->xtregs_cp, &xtregs->cp0,
|
||||
sizeof(xtregs_coprocessor_t));
|
||||
#endif
|
||||
ret |= __copy_from_user(®s->xtregs_opt, &xtregs->opt,
|
||||
sizeof(xtregs->opt));
|
||||
ret |= __copy_from_user(&ti->xtregs_user, &xtregs->user,
|
||||
sizeof(xtregs->user));
|
||||
|
||||
return ret ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
int ptrace_peekusr(struct task_struct *child, long regno, long __user *ret)
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
unsigned long tmp;
|
||||
|
||||
regs = task_pt_regs(child);
|
||||
tmp = 0; /* Default return value. */
|
||||
|
||||
switch(regno) {
|
||||
|
||||
case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
|
||||
{
|
||||
int ar = addr - REG_AR_BASE - regs->windowbase * 4;
|
||||
ar &= (XCHAL_NUM_AREGS - 1);
|
||||
if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
|
||||
tmp = regs->areg[ar];
|
||||
else
|
||||
ret = -EIO;
|
||||
tmp = regs->areg[regno - REG_AR_BASE];
|
||||
break;
|
||||
}
|
||||
|
||||
case REG_A_BASE ... REG_A_BASE + 15:
|
||||
tmp = regs->areg[addr - REG_A_BASE];
|
||||
tmp = regs->areg[regno - REG_A_BASE];
|
||||
break;
|
||||
|
||||
case REG_PC:
|
||||
tmp = regs->pc;
|
||||
break;
|
||||
|
||||
case REG_PS:
|
||||
/* Note: PS.EXCM is not set while user task is running;
|
||||
* its being set in regs is for exception handling
|
||||
* convenience. */
|
||||
tmp = (regs->ps & ~(1 << PS_EXCM_BIT));
|
||||
break;
|
||||
|
||||
case REG_WB:
|
||||
tmp = regs->windowbase;
|
||||
break;
|
||||
break; /* tmp = 0 */
|
||||
|
||||
case REG_WS:
|
||||
tmp = regs->windowstart;
|
||||
{
|
||||
unsigned long wb = regs->windowbase;
|
||||
unsigned long ws = regs->windowstart;
|
||||
tmp = ((ws>>wb) | (ws<<(WSBITS-wb))) & ((1<<WSBITS)-1);
|
||||
break;
|
||||
}
|
||||
case REG_LBEG:
|
||||
tmp = regs->lbeg;
|
||||
break;
|
||||
|
||||
case REG_LEND:
|
||||
tmp = regs->lend;
|
||||
break;
|
||||
|
||||
case REG_LCOUNT:
|
||||
tmp = regs->lcount;
|
||||
break;
|
||||
|
||||
case REG_SAR:
|
||||
tmp = regs->sar;
|
||||
break;
|
||||
case REG_DEPC:
|
||||
tmp = regs->depc;
|
||||
break;
|
||||
case REG_EXCCAUSE:
|
||||
tmp = regs->exccause;
|
||||
break;
|
||||
case REG_EXCVADDR:
|
||||
tmp = regs->excvaddr;
|
||||
break;
|
||||
|
||||
case SYSCALL_NR:
|
||||
tmp = regs->syscall;
|
||||
break;
|
||||
default:
|
||||
tmp = 0;
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
ret = put_user(tmp, (unsigned long *) data);
|
||||
goto out;
|
||||
}
|
||||
|
||||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
return put_user(tmp, ret);
|
||||
}
|
||||
|
||||
int ptrace_pokeusr(struct task_struct *child, long regno, long val)
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
regs = task_pt_regs(child);
|
||||
|
||||
switch (regno) {
|
||||
case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
|
||||
regs->areg[regno - REG_AR_BASE] = val;
|
||||
break;
|
||||
|
||||
case REG_A_BASE ... REG_A_BASE + 15:
|
||||
regs->areg[regno - REG_A_BASE] = val;
|
||||
break;
|
||||
|
||||
case REG_PC:
|
||||
regs->pc = val;
|
||||
break;
|
||||
|
||||
case SYSCALL_NR:
|
||||
regs->syscall = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
{
|
||||
int ret = -EPERM;
|
||||
|
||||
switch (request) {
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
case PTRACE_PEEKDATA:
|
||||
ret = generic_ptrace_peekdata(child, addr, data);
|
||||
break;
|
||||
|
||||
case PTRACE_PEEKUSR: /* read register specified by addr. */
|
||||
ret = ptrace_peekusr(child, addr, (void __user *) data);
|
||||
break;
|
||||
|
||||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||||
case PTRACE_POKEDATA:
|
||||
ret = generic_ptrace_pokedata(child, addr, data);
|
||||
goto out;
|
||||
|
||||
case PTRACE_POKEUSR:
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
regs = task_pt_regs(child);
|
||||
|
||||
switch (addr) {
|
||||
case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
|
||||
{
|
||||
int ar = addr - REG_AR_BASE - regs->windowbase * 4;
|
||||
if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
|
||||
regs->areg[ar & (XCHAL_NUM_AREGS - 1)] = data;
|
||||
else
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
case REG_A_BASE ... REG_A_BASE + 15:
|
||||
regs->areg[addr - REG_A_BASE] = data;
|
||||
break;
|
||||
case REG_PC:
|
||||
regs->pc = data;
|
||||
break;
|
||||
case SYSCALL_NR:
|
||||
regs->syscall = data;
|
||||
break;
|
||||
#ifdef TEST_KERNEL
|
||||
case REG_WB:
|
||||
regs->windowbase = data;
|
||||
break;
|
||||
case REG_WS:
|
||||
regs->windowstart = data;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* The rest are not allowed. */
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_POKEUSR: /* write register specified by addr. */
|
||||
ret = ptrace_pokeusr(child, addr, data);
|
||||
break;
|
||||
|
||||
/* continue and stop at next (return from) syscall */
|
||||
|
||||
case PTRACE_SYSCALL:
|
||||
case PTRACE_CONT: /* restart after signal. */
|
||||
{
|
||||
@@ -217,98 +314,26 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
break;
|
||||
|
||||
case PTRACE_GETREGS:
|
||||
{
|
||||
/* 'data' points to user memory in which to write.
|
||||
* Mainly due to the non-live register values, we
|
||||
* reformat the register values into something more
|
||||
* standard. For convenience, we use the handy
|
||||
* elf_gregset_t format. */
|
||||
|
||||
xtensa_gregset_t format;
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
|
||||
do_copy_regs (&format, regs, child);
|
||||
|
||||
/* Now, copy to user space nice and easy... */
|
||||
ret = 0;
|
||||
if (copy_to_user((void *)data, &format, sizeof(elf_gregset_t)))
|
||||
ret = -EFAULT;
|
||||
ret = ptrace_getregs(child, (void __user *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS:
|
||||
{
|
||||
/* 'data' points to user memory that contains the new
|
||||
* values in the elf_gregset_t format. */
|
||||
|
||||
xtensa_gregset_t format;
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
|
||||
if (copy_from_user(&format,(void *)data,sizeof(elf_gregset_t))){
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
/* FIXME: Perhaps we want some sanity checks on
|
||||
* these user-space values? See ARM version. Are
|
||||
* debuggers a security concern? */
|
||||
|
||||
do_restore_regs (&format, regs, child);
|
||||
|
||||
ret = 0;
|
||||
ret = ptrace_setregs(child, (void __user *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETFPREGS:
|
||||
{
|
||||
/* 'data' points to user memory in which to write.
|
||||
* For convenience, we use the handy
|
||||
* elf_fpregset_t format. */
|
||||
|
||||
elf_fpregset_t fpregs;
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
|
||||
do_save_fpregs (&fpregs, regs, child);
|
||||
|
||||
/* Now, copy to user space nice and easy... */
|
||||
ret = 0;
|
||||
if (copy_to_user((void *)data, &fpregs, sizeof(elf_fpregset_t)))
|
||||
ret = -EFAULT;
|
||||
|
||||
case PTRACE_GETXTREGS:
|
||||
ret = ptrace_getxregs(child, (void __user *) data);
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETFPREGS:
|
||||
{
|
||||
/* 'data' points to user memory that contains the new
|
||||
* values in the elf_fpregset_t format.
|
||||
*/
|
||||
elf_fpregset_t fpregs;
|
||||
struct pt_regs *regs = task_pt_regs(child);
|
||||
|
||||
ret = 0;
|
||||
if (copy_from_user(&fpregs, (void *)data, sizeof(elf_fpregset_t))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (do_restore_fpregs (&fpregs, regs, child))
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETFPREGSIZE:
|
||||
/* 'data' points to 'unsigned long' set to the size
|
||||
* of elf_fpregset_t
|
||||
*/
|
||||
ret = put_user(sizeof(elf_fpregset_t), (unsigned long *) data);
|
||||
case PTRACE_SETXTREGS:
|
||||
ret = ptrace_setxregs(child, (void __user *) data);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,11 +60,6 @@ struct ide_ops *ide_ops;
|
||||
extern struct rtc_ops no_rtc_ops;
|
||||
struct rtc_ops *rtc_ops;
|
||||
|
||||
#ifdef CONFIG_PC_KEYB
|
||||
extern struct kbd_ops no_kbd_ops;
|
||||
struct kbd_ops *kbd_ops;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_INITRD
|
||||
extern void *initrd_start;
|
||||
extern void *initrd_end;
|
||||
|
||||
+55
-34
@@ -35,13 +35,17 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
|
||||
|
||||
extern struct task_struct *coproc_owners[];
|
||||
|
||||
extern void release_all_cp (struct task_struct *);
|
||||
|
||||
struct rt_sigframe
|
||||
{
|
||||
struct siginfo info;
|
||||
struct ucontext uc;
|
||||
cp_state_t cpstate;
|
||||
struct {
|
||||
xtregs_opt_t opt;
|
||||
xtregs_user_t user;
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
xtregs_coprocessor_t cp;
|
||||
#endif
|
||||
} xtregs;
|
||||
unsigned char retcode[6];
|
||||
unsigned int window[4];
|
||||
};
|
||||
@@ -49,8 +53,6 @@ struct rt_sigframe
|
||||
/*
|
||||
* Flush register windows stored in pt_regs to stack.
|
||||
* Returns 1 for errors.
|
||||
*
|
||||
* Note that windowbase, windowstart, and wmask are not updated!
|
||||
*/
|
||||
|
||||
int
|
||||
@@ -116,6 +118,9 @@ flush_window_regs_user(struct pt_regs *regs)
|
||||
base += inc;
|
||||
}
|
||||
|
||||
regs->wmask = 1;
|
||||
regs->windowstart = 1 << wb;
|
||||
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
@@ -131,9 +136,10 @@ errout:
|
||||
*/
|
||||
|
||||
static int
|
||||
setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate,
|
||||
struct pt_regs *regs, unsigned long mask)
|
||||
setup_sigcontext(struct rt_sigframe __user *frame, struct pt_regs *regs)
|
||||
{
|
||||
struct sigcontext __user *sc = &frame->uc.uc_mcontext;
|
||||
struct thread_info *ti = current_thread_info();
|
||||
int err = 0;
|
||||
|
||||
#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
|
||||
@@ -147,23 +153,32 @@ setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate,
|
||||
|
||||
err |= flush_window_regs_user(regs);
|
||||
err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4);
|
||||
err |= __put_user(0, &sc->sc_xtregs);
|
||||
|
||||
// err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
#if XCHAL_HAVE_CP
|
||||
# error Coprocessors unsupported
|
||||
err |= save_cpextra(cpstate);
|
||||
err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate);
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
coprocessor_flush_all(ti);
|
||||
coprocessor_release_all(ti);
|
||||
err |= __copy_to_user(&frame->xtregs.cp, &ti->xtregs_cp,
|
||||
sizeof (frame->xtregs.cp));
|
||||
#endif
|
||||
/* non-iBCS2 extensions.. */
|
||||
err |= __put_user(mask, &sc->oldmask);
|
||||
err |= __copy_to_user(&frame->xtregs.opt, ®s->xtregs_opt,
|
||||
sizeof (xtregs_opt_t));
|
||||
err |= __copy_to_user(&frame->xtregs.user, &ti->xtregs_user,
|
||||
sizeof (xtregs_user_t));
|
||||
|
||||
err |= __put_user(err ? NULL : &frame->xtregs, &sc->sc_xtregs);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
|
||||
restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame)
|
||||
{
|
||||
struct sigcontext __user *sc = &frame->uc.uc_mcontext;
|
||||
struct thread_info *ti = current_thread_info();
|
||||
unsigned int err = 0;
|
||||
unsigned long ps;
|
||||
|
||||
@@ -181,6 +196,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
|
||||
regs->windowbase = 0;
|
||||
regs->windowstart = 1;
|
||||
|
||||
regs->syscall = -1; /* disable syscall checks */
|
||||
|
||||
/* For PS, restore only PS.CALLINC.
|
||||
* Assume that all other bits are either the same as for the signal
|
||||
* handler, or the user mode value doesn't matter (e.g. PS.OWB).
|
||||
@@ -196,8 +213,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
|
||||
|
||||
err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4);
|
||||
|
||||
#if XCHAL_HAVE_CP
|
||||
# error Coprocessors unsupported
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* The signal handler may have used coprocessors in which
|
||||
* case they are still enabled. We disable them to force a
|
||||
* reloading of the original task's CP state by the lazy
|
||||
@@ -205,20 +223,20 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
|
||||
* Also, we essentially discard any coprocessor state that the
|
||||
* signal handler created. */
|
||||
|
||||
if (!err) {
|
||||
struct task_struct *tsk = current;
|
||||
release_all_cp(tsk);
|
||||
err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate,
|
||||
XTENSA_CP_EXTRA_SIZE);
|
||||
}
|
||||
#if XTENSA_HAVE_COPROCESSORS
|
||||
coprocessor_release_all(ti);
|
||||
err |= __copy_from_user(&ti->xtregs_cp, &frame->xtregs.cp,
|
||||
sizeof (frame->xtregs.cp));
|
||||
#endif
|
||||
err |= __copy_from_user(&ti->xtregs_user, &frame->xtregs.user,
|
||||
sizeof (xtregs_user_t));
|
||||
err |= __copy_from_user(®s->xtregs_opt, &frame->xtregs.opt,
|
||||
sizeof (xtregs_opt_t));
|
||||
|
||||
regs->syscall = -1; /* disable syscall checks */
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Do a signal return; undo the signal stack.
|
||||
*/
|
||||
@@ -247,7 +265,7 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3,
|
||||
recalc_sigpending();
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
|
||||
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
|
||||
if (restore_sigcontext(regs, frame))
|
||||
goto badframe;
|
||||
|
||||
ret = regs->areg[2];
|
||||
@@ -360,18 +378,22 @@ static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
err |= __put_user(sas_ss_flags(regs->areg[1]),
|
||||
&frame->uc.uc_stack.ss_flags);
|
||||
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate,
|
||||
regs, set->sig[0]);
|
||||
err |= setup_sigcontext(frame, regs);
|
||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||
|
||||
/* Create sys_rt_sigreturn syscall in stack frame */
|
||||
if (ka->sa.sa_flags & SA_RESTORER) {
|
||||
ra = (unsigned long)ka->sa.sa_restorer;
|
||||
} else {
|
||||
|
||||
err |= gen_return_code(frame->retcode);
|
||||
/* Create sys_rt_sigreturn syscall in stack frame */
|
||||
|
||||
if (err) {
|
||||
goto give_sigsegv;
|
||||
err |= gen_return_code(frame->retcode);
|
||||
|
||||
if (err) {
|
||||
goto give_sigsegv;
|
||||
}
|
||||
ra = (unsigned long) frame->retcode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create signal handler execution context.
|
||||
@@ -385,7 +407,6 @@ static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||
/* Set up a stack frame for a call4
|
||||
* Note: PS.CALLINC is set to one by start_thread
|
||||
*/
|
||||
ra = (unsigned long) frame->retcode;
|
||||
regs->areg[4] = (((unsigned long) ra) & 0x3fffffff) | 0x40000000;
|
||||
regs->areg[6] = (unsigned long) signal;
|
||||
regs->areg[7] = (unsigned long) &frame->info;
|
||||
|
||||
@@ -118,28 +118,28 @@ static dispatch_init_table_t __initdata dispatch_init_table[] = {
|
||||
{ EXCCAUSE_STORE_CACHE_ATTRIBUTE, 0, do_page_fault },
|
||||
{ EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0, do_page_fault },
|
||||
/* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */
|
||||
#if (XCHAL_CP_MASK & 1)
|
||||
#if XTENSA_HAVE_COPROCESSOR(0)
|
||||
COPROCESSOR(0),
|
||||
#endif
|
||||
#if (XCHAL_CP_MASK & 2)
|
||||
#if XTENSA_HAVE_COPROCESSOR(1)
|
||||
COPROCESSOR(1),
|
||||
#endif
|
||||
#if (XCHAL_CP_MASK & 4)
|
||||
#if XTENSA_HAVE_COPROCESSOR(2)
|
||||
COPROCESSOR(2),
|
||||
#endif
|
||||
#if (XCHAL_CP_MASK & 8)
|
||||
#if XTENSA_HAVE_COPROCESSOR(3)
|
||||
COPROCESSOR(3),
|
||||
#endif
|
||||
#if (XCHAL_CP_MASK & 16)
|
||||
#if XTENSA_HAVE_COPROCESSOR(4)
|
||||
COPROCESSOR(4),
|
||||
#endif
|
||||
#if (XCHAL_CP_MASK & 32)
|
||||
#if XTENSA_HAVE_COPROCESSOR(5)
|
||||
COPROCESSOR(5),
|
||||
#endif
|
||||
#if (XCHAL_CP_MASK & 64)
|
||||
#if XTENSA_HAVE_COPROCESSOR(6)
|
||||
COPROCESSOR(6),
|
||||
#endif
|
||||
#if (XCHAL_CP_MASK & 128)
|
||||
#if XTENSA_HAVE_COPROCESSOR(7)
|
||||
COPROCESSOR(7),
|
||||
#endif
|
||||
{ EXCCAUSE_MAPPED_DEBUG, 0, do_debug },
|
||||
@@ -349,9 +349,7 @@ void show_regs(struct pt_regs * regs)
|
||||
|
||||
wmask = regs->wmask & ~1;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (wmask & (1 << (i / 4)))
|
||||
break;
|
||||
for (i = 0; i < 16; i++) {
|
||||
if ((i % 8) == 0)
|
||||
printk ("\n" KERN_INFO "a%02d: ", i);
|
||||
printk("%08lx ", regs->areg[i]);
|
||||
|
||||
@@ -136,7 +136,9 @@ SECTIONS
|
||||
__init_begin = .;
|
||||
.init.text : {
|
||||
_sinittext = .;
|
||||
*(.init.literal) INIT_TEXT
|
||||
*(.init.literal) *(.cpuinit.literal)
|
||||
*(.devinit.literal) *(.meminit.literal)
|
||||
INIT_TEXT
|
||||
_einittext = .;
|
||||
}
|
||||
|
||||
@@ -161,6 +163,8 @@ SECTIONS
|
||||
.DoubleExceptionVector.literal);
|
||||
RELOCATE_ENTRY(_DoubleExceptionVector_text,
|
||||
.DoubleExceptionVector.text);
|
||||
RELOCATE_ENTRY(_DebugInterruptVector_text,
|
||||
.DebugInterruptVector.text);
|
||||
|
||||
__boot_reloc_table_end = ABSOLUTE(.) ;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <linux/swap.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/bootparam.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/tlb.h>
|
||||
@@ -181,9 +180,9 @@ update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
|
||||
#else
|
||||
if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)
|
||||
&& (vma->vm_flags & VM_EXEC) != 0) {
|
||||
unsigned long vaddr = addr & PAGE_MASK;
|
||||
__flush_dcache_page(vaddr);
|
||||
__invalidate_icache_page(vaddr);
|
||||
unsigned long paddr = (unsigned long) page_address(page);
|
||||
__flush_dcache_page(paddr);
|
||||
__invalidate_icache_page(paddr);
|
||||
set_bit(PG_arch_1, &page->flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -309,7 +309,7 @@ void show_mem(void)
|
||||
|
||||
struct kmem_cache *pgtable_cache __read_mostly;
|
||||
|
||||
static void pgd_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
|
||||
static void pgd_ctor(struct kmem_cache *cache, void* addr)
|
||||
{
|
||||
pte_t* ptep = (pte_t*)addr;
|
||||
int i;
|
||||
|
||||
@@ -295,7 +295,7 @@ ENTRY(__tlbtemp_mapping_itlb)
|
||||
ENTRY(__invalidate_icache_page_alias)
|
||||
entry sp, 16
|
||||
|
||||
addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
|
||||
addi a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE)
|
||||
mov a4, a2
|
||||
witlb a6, a2
|
||||
isync
|
||||
|
||||
@@ -43,6 +43,7 @@ static DEFINE_SPINLOCK(timer_lock);
|
||||
|
||||
int errno;
|
||||
|
||||
static int __simc (int a, int b, int c, int d, int e, int f) __attribute__((__noinline__));
|
||||
static int __simc (int a, int b, int c, int d, int e, int f)
|
||||
{
|
||||
int ret;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user