diff options
-rw-r--r-- | Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt | 2 | ||||
-rw-r--r-- | arch/h8300/Kconfig | 3 | ||||
-rw-r--r-- | arch/h8300/boot/compressed/Makefile | 11 | ||||
-rw-r--r-- | arch/h8300/boot/compressed/misc.c | 6 | ||||
-rw-r--r-- | arch/h8300/boot/compressed/vmlinux.lds | 4 | ||||
-rw-r--r-- | arch/h8300/include/asm/io.h | 8 | ||||
-rw-r--r-- | arch/h8300/include/asm/kgdb.h | 45 | ||||
-rw-r--r-- | arch/h8300/include/asm/traps.h | 2 | ||||
-rw-r--r-- | arch/h8300/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/h8300/kernel/entry.S | 19 | ||||
-rw-r--r-- | arch/h8300/kernel/kgdb.c | 135 | ||||
-rw-r--r-- | arch/h8300/kernel/signal.c | 8 | ||||
-rw-r--r-- | arch/h8300/kernel/traps.c | 20 | ||||
-rw-r--r-- | drivers/irqchip/irq-renesas-h8s.c | 10 |
14 files changed, 244 insertions, 31 deletions
diff --git a/Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt b/Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt index 36c2b528245c..399e0da22348 100644 --- a/Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt +++ b/Documentation/devicetree/bindings/clock/renesas,h8300-div-clock.txt @@ -2,7 +2,7 @@ Required Properties: - - compatible: Must be "renesas,sh73a0-h8300-div-clock" + - compatible: Must be "renesas,h8300-div-clock" - clocks: Reference to the parent clocks ("extal1" and "extal2") diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig index 2e20333cbce9..cd1f754c1336 100644 --- a/arch/h8300/Kconfig +++ b/arch/h8300/Kconfig @@ -18,6 +18,9 @@ config H8300 select HAVE_DMA_ATTRS select CLKSRC_OF select H8300_TMR8 + select HAVE_KERNEL_GZIP + select HAVE_KERNEL_LZO + select HAVE_ARCH_KGDB config RWSEM_GENERIC_SPINLOCK def_bool y diff --git a/arch/h8300/boot/compressed/Makefile b/arch/h8300/boot/compressed/Makefile index d7bc3fa7f2c6..7643633f1330 100644 --- a/arch/h8300/boot/compressed/Makefile +++ b/arch/h8300/boot/compressed/Makefile @@ -28,11 +28,16 @@ $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) -$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE - $(call if_changed,gzip) +suffix-$(CONFIG_KERNEL_GZIP) := gzip +suffix-$(CONFIG_KERNEL_LZO) := lzo + +$(obj)/vmlinux.bin.$(suffix-y): $(obj)/vmlinux.bin FORCE + $(call if_changed,$(suffix-y)) LDFLAGS_piggy.o := -r --format binary --oformat elf32-h8300-linux -T OBJCOPYFLAGS := -O binary -$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE $(call if_changed,ld) + +CFLAGS_misc.o = -O0 diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c index 6029c5351895..9f64fe8f29ff 100644 --- a/arch/h8300/boot/compressed/misc.c +++ b/arch/h8300/boot/compressed/misc.c @@ -32,7 +32,13 @@ extern char output[]; #define HEAP_SIZE 0x10000 +#ifdef CONFIG_KERNEL_GZIP #include "../../../../lib/decompress_inflate.c" +#endif + +#ifdef CONFIG_KERNEL_LZO +#include "../../../../lib/decompress_unlzo.c" +#endif void *memset(void *s, int c, size_t n) { diff --git a/arch/h8300/boot/compressed/vmlinux.lds b/arch/h8300/boot/compressed/vmlinux.lds index 44fd209db88a..ad848a72fd3f 100644 --- a/arch/h8300/boot/compressed/vmlinux.lds +++ b/arch/h8300/boot/compressed/vmlinux.lds @@ -13,16 +13,18 @@ SECTIONS { *(.rodata) } + . = ALIGN(0x4) ; .data : { + . = ALIGN(0x4) ; __sdata = . ; ___data_start = . ; *(.data.*) } + . = ALIGN(0x4) ; .bss : { - . = ALIGN(0x4) ; __sbss = . ; *(.bss*) . = ALIGN(0x4) ; diff --git a/arch/h8300/include/asm/io.h b/arch/h8300/include/asm/io.h index f0e14f3a800d..2e221c5f0203 100644 --- a/arch/h8300/include/asm/io.h +++ b/arch/h8300/include/asm/io.h @@ -44,17 +44,17 @@ static inline void __raw_writel(u32 b, const volatile void __iomem *addr) static inline void ctrl_bclr(int b, void __iomem *addr) { if (__builtin_constant_p(b)) - __asm__("bclr %1,%0" : "+WU"(*addr): "i"(b)); + __asm__("bclr %1,%0" : "+WU"(*(u8 *)addr): "i"(b)); else - __asm__("bclr %w1,%0" : "+WU"(*addr): "r"(b)); + __asm__("bclr %w1,%0" : "+WU"(*(u8 *)addr): "r"(b)); } static inline void ctrl_bset(int b, void __iomem *addr) { if (__builtin_constant_p(b)) - __asm__("bset %1,%0" : "+WU"(*addr): "i"(b)); + __asm__("bset %1,%0" : "+WU"(*(u8 *)addr): "i"(b)); else - __asm__("bset %w1,%0" : "+WU"(*addr): "r"(b)); + __asm__("bset %w1,%0" : "+WU"(*(u8 *)addr): "r"(b)); } #include <asm-generic/io.h> diff --git a/arch/h8300/include/asm/kgdb.h b/arch/h8300/include/asm/kgdb.h new file mode 100644 index 000000000000..726ff8fdfc18 --- /dev/null +++ b/arch/h8300/include/asm/kgdb.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 Yoshinori Sato <ysato@users.sourceforge.jp> + * + * 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. + */ + +#ifndef _ASM_H8300_KGDB_H +#define _ASM_H8300_KGDB_H + +#define CACHE_FLUSH_IS_SAFE 1 +#define BUFMAX 2048 + +enum regnames { + GDB_ER0, GDB_ER1, GDB_ER2, GDB_ER3, + GDB_ER4, GDB_ER5, GDB_ER6, GDB_SP, + GDB_CCR, GDB_PC, + GDB_CYCLLE, +#if defined(CONFIG_CPU_H8S) + GDB_EXR, +#endif + GDB_TICK, GDB_INST, +#if defined(CONFIG_CPU_H8S) + GDB_MACH, GDB_MACL, +#endif + /* do not change the last entry or anything below! */ + GDB_NUMREGBYTES, /* number of registers */ +}; + +#define GDB_SIZEOF_REG sizeof(u32) +#if defined(CONFIG_CPU_H8300H) +#define DBG_MAX_REG_NUM (13) +#elif defined(CONFIG_CPU_H8S) +#define DBG_MAX_REG_NUM (14) +#endif +#define NUMREGBYTES (DBG_MAX_REG_NUM * GDB_SIZEOF_REG) + +#define BREAK_INSTR_SIZE 2 +static inline void arch_kgdb_breakpoint(void) +{ + __asm__ __volatile__("trapa #2"); +} + +#endif /* _ASM_H8300_KGDB_H */ diff --git a/arch/h8300/include/asm/traps.h b/arch/h8300/include/asm/traps.h index aa34e75fd767..15e701130b27 100644 --- a/arch/h8300/include/asm/traps.h +++ b/arch/h8300/include/asm/traps.h @@ -36,6 +36,6 @@ extern unsigned long *_interrupt_redirect_table; extern char _start, _etext; #define check_kernel_text(addr) \ ((addr >= (unsigned long)(&_start)) && \ - (addr < (unsigned long)(&_etext))) + (addr < (unsigned long)(&_etext)) && !(addr & 1)) #endif /* _H8300_TRAPS_H */ diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile index 5bc33f2fcc08..253f8e322ecc 100644 --- a/arch/h8300/kernel/Makefile +++ b/arch/h8300/kernel/Makefile @@ -17,3 +17,5 @@ obj-$(CONFIG_H8S_SIM) += sim-console.o obj-$(CONFIG_CPU_H8300H) += ptrace_h.o obj-$(CONFIG_CPU_H8S) += ptrace_s.o + +obj-$(CONFIG_KGDB) += kgdb.o diff --git a/arch/h8300/kernel/entry.S b/arch/h8300/kernel/entry.S index 797dfa8ddeb2..4f67d4b350d5 100644 --- a/arch/h8300/kernel/entry.S +++ b/arch/h8300/kernel/entry.S @@ -188,7 +188,11 @@ _interrupt_redirect_table: jsr @_interrupt_entry /* NMI */ jmp @_system_call /* TRAPA #0 (System call) */ .long 0 +#if defined(CONFIG_KGDB) + jmp @_kgdb_trap +#else .long 0 +#endif jmp @_trace_break /* TRAPA #3 (breakpoint) */ .rept INTERRUPTS-12 jsr @_interrupt_entry @@ -242,6 +246,7 @@ _system_call: /* save top of frame */ mov.l sp,er0 jsr @set_esp0 + andc #0x3f,ccr mov.l sp,er2 and.w #0xe000,r2 mov.l @(TI_FLAGS:16,er2),er2 @@ -405,6 +410,20 @@ _nmi: mov.l @sp+, er0 jmp @_interrupt_entry +#if defined(CONFIG_KGDB) +_kgdb_trap: + subs #4,sp + SAVE_ALL + mov.l sp,er0 + add.l #LRET,er0 + mov.l er0,@(LSP,sp) + jsr @set_esp0 + mov.l sp,er0 + subs #4,er0 + jsr @h8300_kgdb_trap + jmp @ret_from_exception +#endif + .section .bss _sw_ksp: .space 4 diff --git a/arch/h8300/kernel/kgdb.c b/arch/h8300/kernel/kgdb.c new file mode 100644 index 000000000000..602e478afbd5 --- /dev/null +++ b/arch/h8300/kernel/kgdb.c @@ -0,0 +1,135 @@ +/* + * H8/300 KGDB support + * + * Copyright (C) 2015 Yoshinori Sato <ysato@users.sourceforge.jp> + * + * 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. + */ + +#include <linux/ptrace.h> +#include <linux/kgdb.h> +#include <linux/kdebug.h> +#include <linux/io.h> + +struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { + { "er0", GDB_SIZEOF_REG, offsetof(struct pt_regs, er0) }, + { "er1", GDB_SIZEOF_REG, offsetof(struct pt_regs, er1) }, + { "er2", GDB_SIZEOF_REG, offsetof(struct pt_regs, er2) }, + { "er3", GDB_SIZEOF_REG, offsetof(struct pt_regs, er3) }, + { "er4", GDB_SIZEOF_REG, offsetof(struct pt_regs, er4) }, + { "er5", GDB_SIZEOF_REG, offsetof(struct pt_regs, er5) }, + { "er6", GDB_SIZEOF_REG, offsetof(struct pt_regs, er6) }, + { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp) }, + { "ccr", GDB_SIZEOF_REG, offsetof(struct pt_regs, ccr) }, + { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, pc) }, + { "cycles", GDB_SIZEOF_REG, -1 }, +#if defined(CONFIG_CPU_H8S) + { "exr", GDB_SIZEOF_REG, offsetof(struct pt_regs, exr) }, +#endif + { "tick", GDB_SIZEOF_REG, -1 }, + { "inst", GDB_SIZEOF_REG, -1 }, +}; + +char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) +{ + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return NULL; + + switch (regno) { + case GDB_CCR: +#if defined(CONFIG_CPU_H8S) + case GDB_EXR: +#endif + *(u32 *)mem = *(u16 *)((void *)regs + + dbg_reg_def[regno].offset); + break; + default: + if (dbg_reg_def[regno].offset >= 0) + memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, + dbg_reg_def[regno].size); + else + memset(mem, 0, dbg_reg_def[regno].size); + break; + } + return dbg_reg_def[regno].name; +} + +int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) +{ + if (regno >= DBG_MAX_REG_NUM || regno < 0) + return -EINVAL; + + switch (regno) { + case GDB_CCR: +#if defined(CONFIG_CPU_H8S) + case GDB_EXR: +#endif + *(u16 *)((void *)regs + + dbg_reg_def[regno].offset) = *(u32 *)mem; + break; + default: + memcpy((void *)regs + dbg_reg_def[regno].offset, mem, + dbg_reg_def[regno].size); + } + return 0; +} + +asmlinkage void h8300_kgdb_trap(struct pt_regs *regs) +{ + regs->pc &= 0x00ffffff; + if (kgdb_handle_exception(10, SIGTRAP, 0, regs)) + return; + if (*(u16 *)(regs->pc) == *(u16 *)&arch_kgdb_ops.gdb_bpt_instr) + regs->pc += BREAK_INSTR_SIZE; + regs->pc |= regs->ccr << 24; +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + memset((char *)gdb_regs, 0, NUMREGBYTES); + gdb_regs[GDB_SP] = p->thread.ksp; + gdb_regs[GDB_PC] = KSTK_EIP(p); +} + +void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) +{ + regs->pc = pc; +} + +int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *regs) +{ + char *ptr; + unsigned long addr; + + switch (remcom_in_buffer[0]) { + case 's': + case 'c': + /* handle the optional parameters */ + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &addr)) + regs->pc = addr; + + return 0; + } + + return -1; /* this means that we do not want to exit from the handler */ +} + +int kgdb_arch_init(void) +{ + return 0; +} + +void kgdb_arch_exit(void) +{ + /* Nothing to do */ +} + +const struct kgdb_arch arch_kgdb_ops = { + /* Breakpoint instruction: trapa #2 */ + .gdb_bpt_instr = { 0x57, 0x20 }, +}; diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 380fffd081b2..ad1f81f574e5 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -95,7 +95,7 @@ restore_sigcontext(struct sigcontext *usc, int *pd0) regs->ccr |= ccr; regs->orig_er0 = -1; /* disable syscall checks */ err |= __get_user(usp, &usc->sc_usp); - wrusp(usp); + regs->sp = usp; err |= __get_user(er0, &usc->sc_er0); *pd0 = er0; @@ -180,7 +180,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, return -EFAULT; /* Set up to return from userspace. */ - ret = frame->retcode; + ret = (unsigned char *)&frame->retcode; if (ksig->ka.sa.sa_flags & SA_RESTORER) ret = (unsigned char *)(ksig->ka.sa.sa_restorer); else { @@ -196,8 +196,8 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, return -EFAULT; /* Set up registers for signal handler */ - wrusp((unsigned long) frame); - regs->pc = (unsigned long) ksig->ka.sa.sa_handler; + regs->sp = (unsigned long)frame; + regs->pc = (unsigned long)ksig->ka.sa.sa_handler; regs->er0 = ksig->sig; regs->er1 = (unsigned long)&(frame->info); regs->er2 = (unsigned long)&frame->uc; diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c index 1b2d7cdd6591..044a36125846 100644 --- a/arch/h8300/kernel/traps.c +++ b/arch/h8300/kernel/traps.c @@ -125,17 +125,18 @@ void show_stack(struct task_struct *task, unsigned long *esp) pr_info("Stack from %08lx:", (unsigned long)stack); for (i = 0; i < kstack_depth_to_print; i++) { - if (((unsigned long)stack & (THREAD_SIZE - 1)) == 0) + if (((unsigned long)stack & (THREAD_SIZE - 1)) >= + THREAD_SIZE-4) break; if (i % 8 == 0) - pr_info("\n "); - pr_info(" %08lx", *stack++); + pr_info(" "); + pr_cont(" %08lx", *stack++); } - pr_info("\nCall Trace:"); + pr_info("\nCall Trace:\n"); i = 0; stack = esp; - while (((unsigned long)stack & (THREAD_SIZE - 1)) != 0) { + while (((unsigned long)stack & (THREAD_SIZE - 1)) < THREAD_SIZE-4) { addr = *stack++; /* * If the address is either in the text segment of the @@ -147,15 +148,10 @@ void show_stack(struct task_struct *task, unsigned long *esp) */ if (check_kernel_text(addr)) { if (i % 4 == 0) - pr_info("\n "); - pr_info(" [<%08lx>]", addr); + pr_info(" "); + pr_cont(" [<%08lx>]", addr); i++; } } pr_info("\n"); } - -void show_trace_task(struct task_struct *tsk) -{ - show_stack(tsk, (unsigned long *)tsk->thread.esp0); -} diff --git a/drivers/irqchip/irq-renesas-h8s.c b/drivers/irqchip/irq-renesas-h8s.c index 8098ead1eb22..af8c6c61c824 100644 --- a/drivers/irqchip/irq-renesas-h8s.c +++ b/drivers/irqchip/irq-renesas-h8s.c @@ -40,8 +40,8 @@ static void h8s_disable_irq(struct irq_data *data) addr = IPRA + ((ipr_table[irq - 16] & 0xf0) >> 3); pos = (ipr_table[irq - 16] & 0x0f) * 4; pri = ~(0x000f << pos); - pri &= ctrl_inw(addr); - ctrl_outw(pri, addr); + pri &= readw(addr); + writew(pri, addr); } static void h8s_enable_irq(struct irq_data *data) @@ -54,9 +54,9 @@ static void h8s_enable_irq(struct irq_data *data) addr = IPRA + ((ipr_table[irq - 16] & 0xf0) >> 3); pos = (ipr_table[irq - 16] & 0x0f) * 4; pri = ~(0x000f << pos); - pri &= ctrl_inw(addr); + pri &= readw(addr); pri |= 1 << pos; - ctrl_outw(pri, addr); + writew(pri, addr); } struct irq_chip h8s_irq_chip = { @@ -90,7 +90,7 @@ static int __init h8s_intc_of_init(struct device_node *intc, /* All interrupt priority is 0 (disable) */ /* IPRA to IPRK */ for (n = 0; n <= 'k' - 'a'; n++) - ctrl_outw(0x0000, IPRA + (n * 2)); + writew(0x0000, IPRA + (n * 2)); domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL); BUG_ON(!domain); |