From 384740dc49ea651ba350704d13ff6be9976e37fe Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 16 Sep 2008 19:48:51 +0200 Subject: MIPS: Move headfiles to new location below arch/mips/include Signed-off-by: Ralf Baechle --- arch/mips/include/asm/processor.h | 263 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 arch/mips/include/asm/processor.h (limited to 'arch/mips/include/asm/processor.h') diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h new file mode 100644 index 00000000000..a1e4453469f --- /dev/null +++ b/arch/mips/include/asm/processor.h @@ -0,0 +1,263 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1994 Waldorf GMBH + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003 Ralf Baechle + * Copyright (C) 1996 Paul M. Antoine + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + */ +#ifndef _ASM_PROCESSOR_H +#define _ASM_PROCESSOR_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +/* + * Return current * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +/* + * System setup and hardware flags.. + */ +extern void (*cpu_wait)(void); + +extern unsigned int vced_count, vcei_count; + +#ifdef CONFIG_32BIT +/* + * User space process size: 2GB. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. + */ +#define TASK_SIZE 0x7fff8000UL +#define STACK_TOP TASK_SIZE + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE ((TASK_SIZE / 3) & ~(PAGE_SIZE)) +#endif + +#ifdef CONFIG_64BIT +/* + * User space process size: 1TB. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. TASK_SIZE + * is limited to 1TB by the R4000 architecture; R10000 and better can + * support 16TB; the architectural reserve for future expansion is + * 8192EB ... + */ +#define TASK_SIZE32 0x7fff8000UL +#define TASK_SIZE 0x10000000000UL +#define STACK_TOP \ + (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE \ + (test_thread_flag(TIF_32BIT_ADDR) ? \ + PAGE_ALIGN(TASK_SIZE32 / 3) : PAGE_ALIGN(TASK_SIZE / 3)) +#define TASK_SIZE_OF(tsk) \ + (test_tsk_thread_flag(tsk, TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE) +#endif + +#ifdef __KERNEL__ +#define STACK_TOP_MAX TASK_SIZE +#endif + +#define NUM_FPU_REGS 32 + +typedef __u64 fpureg_t; + +/* + * It would be nice to add some more fields for emulator statistics, but there + * are a number of fixed offsets in offset.h and elsewhere that would have to + * be recalculated by hand. So the additional information will be private to + * the FPU emulator for now. See asm-mips/fpu_emulator.h. + */ + +struct mips_fpu_struct { + fpureg_t fpr[NUM_FPU_REGS]; + unsigned int fcr31; +}; + +#define NUM_DSP_REGS 6 + +typedef __u32 dspreg_t; + +struct mips_dsp_state { + dspreg_t dspr[NUM_DSP_REGS]; + unsigned int dspcontrol; +}; + +#define INIT_CPUMASK { \ + {0,} \ +} + +typedef struct { + unsigned long seg; +} mm_segment_t; + +#define ARCH_MIN_TASKALIGN 8 + +struct mips_abi; + +/* + * If you change thread_struct remember to change the #defines below too! + */ +struct thread_struct { + /* Saved main processor registers. */ + unsigned long reg16; + unsigned long reg17, reg18, reg19, reg20, reg21, reg22, reg23; + unsigned long reg29, reg30, reg31; + + /* Saved cp0 stuff. */ + unsigned long cp0_status; + + /* Saved fpu/fpu emulator stuff. */ + struct mips_fpu_struct fpu; +#ifdef CONFIG_MIPS_MT_FPAFF + /* Emulated instruction count */ + unsigned long emulated_fp; + /* Saved per-thread scheduler affinity mask */ + cpumask_t user_cpus_allowed; +#endif /* CONFIG_MIPS_MT_FPAFF */ + + /* Saved state of the DSP ASE, if available. */ + struct mips_dsp_state dsp; + + /* Other stuff associated with the thread. */ + unsigned long cp0_badvaddr; /* Last user fault */ + unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ + unsigned long error_code; + unsigned long trap_no; + unsigned long irix_trampoline; /* Wheee... */ + unsigned long irix_oldctx; + struct mips_abi *abi; +}; + +#ifdef CONFIG_MIPS_MT_FPAFF +#define FPAFF_INIT \ + .emulated_fp = 0, \ + .user_cpus_allowed = INIT_CPUMASK, +#else +#define FPAFF_INIT +#endif /* CONFIG_MIPS_MT_FPAFF */ + +#define INIT_THREAD { \ + /* \ + * Saved main processor registers \ + */ \ + .reg16 = 0, \ + .reg17 = 0, \ + .reg18 = 0, \ + .reg19 = 0, \ + .reg20 = 0, \ + .reg21 = 0, \ + .reg22 = 0, \ + .reg23 = 0, \ + .reg29 = 0, \ + .reg30 = 0, \ + .reg31 = 0, \ + /* \ + * Saved cp0 stuff \ + */ \ + .cp0_status = 0, \ + /* \ + * Saved FPU/FPU emulator stuff \ + */ \ + .fpu = { \ + .fpr = {0,}, \ + .fcr31 = 0, \ + }, \ + /* \ + * FPU affinity state (null if not FPAFF) \ + */ \ + FPAFF_INIT \ + /* \ + * Saved DSP stuff \ + */ \ + .dsp = { \ + .dspr = {0, }, \ + .dspcontrol = 0, \ + }, \ + /* \ + * Other stuff associated with the process \ + */ \ + .cp0_badvaddr = 0, \ + .cp0_baduaddr = 0, \ + .error_code = 0, \ + .trap_no = 0, \ + .irix_trampoline = 0, \ + .irix_oldctx = 0, \ +} + +struct task_struct; + +/* Free all resources held by a thread. */ +#define release_thread(thread) do { } while(0) + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while (0) + +extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); + +extern unsigned long thread_saved_pc(struct task_struct *tsk); + +/* + * Do necessary setup to start up a newly executed thread. + */ +extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); + +unsigned long get_wchan(struct task_struct *p); + +#define __KSTK_TOS(tsk) ((unsigned long)task_stack_page(tsk) + THREAD_SIZE - 32) +#define task_pt_regs(tsk) ((struct pt_regs *)__KSTK_TOS(tsk) - 1) +#define KSTK_EIP(tsk) (task_pt_regs(tsk)->cp0_epc) +#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[29]) +#define KSTK_STATUS(tsk) (task_pt_regs(tsk)->cp0_status) + +#define cpu_relax() barrier() + +/* + * Return_address is a replacement for __builtin_return_address(count) + * which on certain architectures cannot reasonably be implemented in GCC + * (MIPS, Alpha) or is unuseable with -fomit-frame-pointer (i386). + * Note that __builtin_return_address(x>=1) is forbidden because GCC + * aborts compilation on some CPUs. It's simply not possible to unwind + * some CPU's stackframes. + * + * __builtin_return_address works only for non-leaf functions. We avoid the + * overhead of a function call by forcing the compiler to save the return + * address register on the stack. + */ +#define return_address() ({__asm__ __volatile__("":::"$31");__builtin_return_address(0);}) + +#ifdef CONFIG_CPU_HAS_PREFETCH + +#define ARCH_HAS_PREFETCH + +static inline void prefetch(const void *addr) +{ + __asm__ __volatile__( + " .set mips4 \n" + " pref %0, (%1) \n" + " .set mips0 \n" + : + : "i" (Pref_Load), "r" (addr)); +} + +#endif + +#endif /* _ASM_PROCESSOR_H */ -- cgit v1.2.3-70-g09d2 From 6aa3524c182c01b8b8b7c21c4da20c742a9b4d86 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 23 Sep 2008 00:05:54 -0700 Subject: MIPS: Add HARDWARE_WATCHPOINTS definitions and support code. This is the main support code for the patch. Here we just add the code, the following patches hook it up. Signed-off-by: David Daney Signed-off-by: Ralf Baechle create mode 100644 arch/mips/include/asm/watch.h create mode 100644 arch/mips/kernel/watch.c --- arch/mips/include/asm/cpu-info.h | 6 ++ arch/mips/include/asm/processor.h | 20 ++++ arch/mips/include/asm/thread_info.h | 2 + arch/mips/include/asm/watch.h | 32 ++++++ arch/mips/kernel/Makefile | 2 +- arch/mips/kernel/watch.c | 188 ++++++++++++++++++++++++++++++++++++ 6 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 arch/mips/include/asm/watch.h create mode 100644 arch/mips/kernel/watch.c (limited to 'arch/mips/include/asm/processor.h') diff --git a/arch/mips/include/asm/cpu-info.h b/arch/mips/include/asm/cpu-info.h index 2de73dbb2e9..744cd8fb107 100644 --- a/arch/mips/include/asm/cpu-info.h +++ b/arch/mips/include/asm/cpu-info.h @@ -12,6 +12,8 @@ #ifndef __ASM_CPU_INFO_H #define __ASM_CPU_INFO_H +#include + #include /* @@ -69,6 +71,10 @@ struct cpuinfo_mips { int tc_id; /* Thread Context number */ #endif void *data; /* Additional data */ + unsigned int watch_reg_count; /* Number that exist */ + unsigned int watch_reg_use_cnt; /* Usable by ptrace */ +#define NUM_WATCH_REGS 4 + u16 watch_reg_masks[NUM_WATCH_REGS]; } __attribute__((aligned(SMP_CACHE_BYTES))); extern struct cpuinfo_mips cpu_data[]; diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index a1e4453469f..18ee58e3944 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -105,6 +105,19 @@ struct mips_dsp_state { {0,} \ } +struct mips3264_watch_reg_state { + /* The width of watchlo is 32 in a 32 bit kernel and 64 in a + 64 bit kernel. We use unsigned long as it has the same + property. */ + unsigned long watchlo[NUM_WATCH_REGS]; + /* Only the mask and IRW bits from watchhi. */ + u16 watchhi[NUM_WATCH_REGS]; +}; + +union mips_watch_reg_state { + struct mips3264_watch_reg_state mips3264; +}; + typedef struct { unsigned long seg; } mm_segment_t; @@ -137,6 +150,9 @@ struct thread_struct { /* Saved state of the DSP ASE, if available. */ struct mips_dsp_state dsp; + /* Saved watch register state, if available. */ + union mips_watch_reg_state watch; + /* Other stuff associated with the thread. */ unsigned long cp0_badvaddr; /* Last user fault */ unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ @@ -192,6 +208,10 @@ struct thread_struct { .dspr = {0, }, \ .dspcontrol = 0, \ }, \ + /* \ + * saved watch register stuff \ + */ \ + .watch = {{{0,},},}, \ /* \ * Other stuff associated with the process \ */ \ diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index bb3060699df..3f76de73c94 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -124,6 +124,7 @@ register struct thread_info *__current_thread_info __asm__("$28"); #define TIF_32BIT_REGS 22 /* also implies 16/32 fprs */ #define TIF_32BIT_ADDR 23 /* 32-bit address space (o32/n32) */ #define TIF_FPUBOUND 24 /* thread bound to FPU-full CPU set */ +#define TIF_LOAD_WATCH 25 /* If set, load watch registers */ #define TIF_SYSCALL_TRACE 31 /* syscall trace active */ #define _TIF_SYSCALL_TRACE (1< + +#include + +void mips_install_watch_registers(void); +void mips_read_watch_registers(void); +void mips_clear_watch_registers(void); +void mips_probe_watch_registers(struct cpuinfo_mips *c); + +#ifdef CONFIG_HARDWARE_WATCHPOINTS +#define __restore_watch() do { \ + if (unlikely(test_bit(TIF_LOAD_WATCH, \ + ¤t_thread_info()->flags))) { \ + mips_install_watch_registers(); \ + } \ +} while (0) + +#else +#define __restore_watch() do {} while (0) +#endif + +#endif /* _ASM_WATCH_H */ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 25775cb5400..d9da7112aaf 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \ ptrace.o reset.o setup.o signal.o syscall.o \ - time.o topology.o traps.o unaligned.o + time.o topology.o traps.o unaligned.o watch.o obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o obj-$(CONFIG_CEVT_R4K) += cevt-r4k.o diff --git a/arch/mips/kernel/watch.c b/arch/mips/kernel/watch.c new file mode 100644 index 00000000000..c1540696803 --- /dev/null +++ b/arch/mips/kernel/watch.c @@ -0,0 +1,188 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2008 David Daney + */ + +#include + +#include +#include + +/* + * Install the watch registers for the current thread. A maximum of + * four registers are installed although the machine may have more. + */ +void mips_install_watch_registers(void) +{ + struct mips3264_watch_reg_state *watches = + ¤t->thread.watch.mips3264; + switch (current_cpu_data.watch_reg_use_cnt) { + default: + BUG(); + case 4: + write_c0_watchlo3(watches->watchlo[3]); + /* Write 1 to the I, R, and W bits to clear them, and + 1 to G so all ASIDs are trapped. */ + write_c0_watchhi3(0x40000007 | watches->watchhi[3]); + case 3: + write_c0_watchlo2(watches->watchlo[2]); + write_c0_watchhi2(0x40000007 | watches->watchhi[2]); + case 2: + write_c0_watchlo1(watches->watchlo[1]); + write_c0_watchhi1(0x40000007 | watches->watchhi[1]); + case 1: + write_c0_watchlo0(watches->watchlo[0]); + write_c0_watchhi0(0x40000007 | watches->watchhi[0]); + } +} + +/* + * Read back the watchhi registers so the user space debugger has + * access to the I, R, and W bits. A maximum of four registers are + * read although the machine may have more. + */ +void mips_read_watch_registers(void) +{ + struct mips3264_watch_reg_state *watches = + ¤t->thread.watch.mips3264; + switch (current_cpu_data.watch_reg_use_cnt) { + default: + BUG(); + case 4: + watches->watchhi[3] = (read_c0_watchhi3() & 0x0fff); + case 3: + watches->watchhi[2] = (read_c0_watchhi2() & 0x0fff); + case 2: + watches->watchhi[1] = (read_c0_watchhi1() & 0x0fff); + case 1: + watches->watchhi[0] = (read_c0_watchhi0() & 0x0fff); + } + if (current_cpu_data.watch_reg_use_cnt == 1 && + (watches->watchhi[0] & 7) == 0) { + /* Pathological case of release 1 architecture that + * doesn't set the condition bits. We assume that + * since we got here, the watch condition was met and + * signal that the conditions requested in watchlo + * were met. */ + watches->watchhi[0] |= (watches->watchlo[0] & 7); + } + } + +/* + * Disable all watch registers. Although only four registers are + * installed, all are cleared to eliminate the possibility of endless + * looping in the watch handler. + */ +void mips_clear_watch_registers(void) +{ + switch (current_cpu_data.watch_reg_count) { + default: + BUG(); + case 8: + write_c0_watchlo7(0); + case 7: + write_c0_watchlo6(0); + case 6: + write_c0_watchlo5(0); + case 5: + write_c0_watchlo4(0); + case 4: + write_c0_watchlo3(0); + case 3: + write_c0_watchlo2(0); + case 2: + write_c0_watchlo1(0); + case 1: + write_c0_watchlo0(0); + } +} + +__cpuinit void mips_probe_watch_registers(struct cpuinfo_mips *c) +{ + unsigned int t; + + if ((c->options & MIPS_CPU_WATCH) == 0) + return; + /* + * Check which of the I,R and W bits are supported, then + * disable the register. + */ + write_c0_watchlo0(7); + t = read_c0_watchlo0(); + write_c0_watchlo0(0); + c->watch_reg_masks[0] = t & 7; + + /* Write the mask bits and read them back to determine which + * can be used. */ + c->watch_reg_count = 1; + c->watch_reg_use_cnt = 1; + t = read_c0_watchhi0(); + write_c0_watchhi0(t | 0xff8); + t = read_c0_watchhi0(); + c->watch_reg_masks[0] |= (t & 0xff8); + if ((t & 0x80000000) == 0) + return; + + write_c0_watchlo1(7); + t = read_c0_watchlo1(); + write_c0_watchlo1(0); + c->watch_reg_masks[1] = t & 7; + + c->watch_reg_count = 2; + c->watch_reg_use_cnt = 2; + t = read_c0_watchhi1(); + write_c0_watchhi1(t | 0xff8); + t = read_c0_watchhi1(); + c->watch_reg_masks[1] |= (t & 0xff8); + if ((t & 0x80000000) == 0) + return; + + write_c0_watchlo2(7); + t = read_c0_watchlo2(); + write_c0_watchlo2(0); + c->watch_reg_masks[2] = t & 7; + + c->watch_reg_count = 3; + c->watch_reg_use_cnt = 3; + t = read_c0_watchhi2(); + write_c0_watchhi2(t | 0xff8); + t = read_c0_watchhi2(); + c->watch_reg_masks[2] |= (t & 0xff8); + if ((t & 0x80000000) == 0) + return; + + write_c0_watchlo3(7); + t = read_c0_watchlo3(); + write_c0_watchlo3(0); + c->watch_reg_masks[3] = t & 7; + + c->watch_reg_count = 4; + c->watch_reg_use_cnt = 4; + t = read_c0_watchhi3(); + write_c0_watchhi3(t | 0xff8); + t = read_c0_watchhi3(); + c->watch_reg_masks[3] |= (t & 0xff8); + if ((t & 0x80000000) == 0) + return; + + /* We use at most 4, but probe and report up to 8. */ + c->watch_reg_count = 5; + t = read_c0_watchhi4(); + if ((t & 0x80000000) == 0) + return; + + c->watch_reg_count = 6; + t = read_c0_watchhi5(); + if ((t & 0x80000000) == 0) + return; + + c->watch_reg_count = 7; + t = read_c0_watchhi6(); + if ((t & 0x80000000) == 0) + return; + + c->watch_reg_count = 8; +} -- cgit v1.2.3-70-g09d2