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:
Linus Torvalds
2008-02-19 15:53:02 -08:00
40 changed files with 1220 additions and 1195 deletions
+1 -1
View File
@@ -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)
+5 -4
View File
@@ -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)
}
+1 -1
View File
@@ -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 \
+1 -1
View File
@@ -2,7 +2,7 @@ OUTPUT_ARCH(xtensa)
SECTIONS
{
.start 0xD0200000 : { *(.start) }
.start 0xD1000000 : { *(.start) }
.text :
{
+15 -2
View File
@@ -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
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
View File
@@ -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],
&regs->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
View File
@@ -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, &regs->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(&regs->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;
}
-5
View File
@@ -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
View File
@@ -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, &regs->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(&regs->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(&current->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;
+9 -11
View File
@@ -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]);
+5 -1
View File
@@ -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(.) ;
}
+3 -4
View File
@@ -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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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