diff options
Diffstat (limited to 'arch/h8300/kernel')
-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/setup.c | 17 | ||||
-rw-r--r-- | arch/h8300/kernel/signal.c | 8 | ||||
-rw-r--r-- | arch/h8300/kernel/sim-console.c | 67 | ||||
-rw-r--r-- | arch/h8300/kernel/traps.c | 20 | ||||
-rw-r--r-- | arch/h8300/kernel/vmlinux.lds.S | 4 |
8 files changed, 185 insertions, 87 deletions
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/setup.c b/arch/h8300/kernel/setup.c index 0fd1fe65c0b8..c8c25a4e9e48 100644 --- a/arch/h8300/kernel/setup.c +++ b/arch/h8300/kernel/setup.c @@ -20,8 +20,6 @@ #include <linux/bootmem.h> #include <linux/seq_file.h> #include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/module.h> #include <linux/of.h> #include <linux/of_fdt.h> #include <linux/of_platform.h> @@ -29,6 +27,7 @@ #include <linux/clk-provider.h> #include <linux/memblock.h> #include <linux/screen_info.h> +#include <linux/clocksource.h> #include <asm/setup.h> #include <asm/irq.h> @@ -136,11 +135,6 @@ void __init setup_arch(char **cmdline_p) parse_early_param(); bootmem_init(); -#if defined(CONFIG_H8300H_SIM) || defined(CONFIG_H8S_SIM) - sim_console_register(); -#endif - - early_platform_driver_probe("earlyprintk", 1, 0); /* * get kmalloc into gear */ @@ -206,14 +200,14 @@ device_initcall(device_probe); #define get_wait(base, addr) ({ \ int baddr; \ baddr = ((addr) / 0x200000 * 2); \ - w *= (ctrl_inw((unsigned long)(base) + 2) & (3 << baddr)) + 1; \ + w *= (readw((base) + 2) & (3 << baddr)) + 1; \ }) #endif #if defined(CONFIG_CPU_H8S) #define get_wait(base, addr) ({ \ int baddr; \ baddr = ((addr) / 0x200000 * 16); \ - w *= (ctrl_inl((unsigned long)(base) + 2) & (7 << baddr)) + 1; \ + w *= (readl((base) + 2) & (7 << baddr)) + 1; \ }) #endif @@ -227,8 +221,8 @@ static __init int access_timing(void) bsc = of_find_compatible_node(NULL, NULL, "renesas,h8300-bsc"); base = of_iomap(bsc, 0); - w = (ctrl_inb((unsigned long)base + 0) & bit)?2:1; - if (ctrl_inb((unsigned long)base + 1) & bit) + w = (readb(base + 0) & bit)?2:1; + if (readb(base + 1) & bit) w *= get_wait(base, addr); else w *= 2; @@ -252,4 +246,5 @@ void __init calibrate_delay(void) void __init time_init(void) { of_clk_init(NULL); + clocksource_probe(); } 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/sim-console.c b/arch/h8300/kernel/sim-console.c index a15edf0565d9..46138f55a9ea 100644 --- a/arch/h8300/kernel/sim-console.c +++ b/arch/h8300/kernel/sim-console.c @@ -1,79 +1,30 @@ /* - * arch/h8300/kernel/early_printk.c + * arch/h8300/kernel/sim-console.c * - * Copyright (C) 2009 Yoshinori Sato <ysato@users.sourceforge.jp> + * 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/console.h> -#include <linux/tty.h> #include <linux/init.h> -#include <linux/io.h> -#include <linux/platform_device.h> +#include <linux/serial_core.h> -static void sim_write(struct console *co, const char *ptr, - unsigned len) +static void sim_write(struct console *con, const char *s, unsigned n) { register const int fd __asm__("er0") = 1; /* stdout */ - register const char *_ptr __asm__("er1") = ptr; - register const unsigned _len __asm__("er2") = len; + register const char *_ptr __asm__("er1") = s; + register const unsigned _len __asm__("er2") = n; __asm__(".byte 0x5e,0x00,0x00,0xc7\n\t" /* jsr @0xc7 (sys_write) */ : : "g"(fd), "g"(_ptr), "g"(_len)); } -static struct console sim_console = { - .name = "sim_console", - .write = sim_write, - .setup = NULL, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static char sim_console_buf[32]; - -static int sim_probe(struct platform_device *pdev) -{ - if (sim_console.data) - return -EEXIST; - - if (!strstr(sim_console_buf, "keep")) - sim_console.flags |= CON_BOOT; - - register_console(&sim_console); - return 0; -} - -static int sim_remove(struct platform_device *pdev) +static int __init sim_setup(struct earlycon_device *device, const char *opt) { + device->con->write = sim_write; return 0; } -static struct platform_driver sim_driver = { - .probe = sim_probe, - .remove = sim_remove, - .driver = { - .name = "h8300-sim", - .owner = THIS_MODULE, - }, -}; - -early_platform_init_buffer("earlyprintk", &sim_driver, - sim_console_buf, ARRAY_SIZE(sim_console_buf)); - -static struct platform_device sim_console_device = { - .name = "h8300-sim", - .id = 0, -}; - -static struct platform_device *devices[] __initdata = { - &sim_console_device, -}; - -void __init sim_console_register(void) -{ - early_platform_add_devices(devices, - ARRAY_SIZE(devices)); -} +EARLYCON_DECLARE(h8sim, sim_setup); 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/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S index 7c302dcf5249..cb5dfb02c88d 100644 --- a/arch/h8300/kernel/vmlinux.lds.S +++ b/arch/h8300/kernel/vmlinux.lds.S @@ -1,5 +1,6 @@ #include <asm-generic/vmlinux.lds.h> #include <asm/page.h> +#include <asm/thread_info.h> #define ROMTOP 0x000000 #define RAMTOP 0x400000 @@ -42,11 +43,10 @@ SECTIONS . = RAMTOP; _ramstart = .; #define ADDR(x) ROMEND -#else #endif _sdata = . ; __data_start = . ; - RW_DATA_SECTION(0,0,0) + RW_DATA_SECTION(0, PAGE_SIZE, THREAD_SIZE) #if defined(CONFIG_ROMKERNEL) #undef ADDR #endif |