From 8a37f520523df971bd3f926d8bd45ead37e857e8 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 25 May 2010 16:16:40 +0900 Subject: sh: handle early calls to return_address() when using dwarf unwinder. The dwarf unwinder ties in to an early initcall, but it's possible that return_address() calls will be made prior to that. This implements some additional error handling in to the dwarf unwinder as well as an exit path in the return_address() case to bail out if the unwinder hasn't come up yet. This fixes a NULL pointer deref in early boot when mempool_alloc() blows up on the not-yet-ready mempool via dwarf_unwind_stack(). Signed-off-by: Paul Mundt --- arch/sh/kernel/dwarf.c | 19 +++++++++++++++++-- arch/sh/kernel/return_address.c | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'arch/sh/kernel') diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 886d7d83ace3..49c09c7d5b77 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c @@ -49,6 +49,8 @@ static DEFINE_SPINLOCK(dwarf_fde_lock); static struct dwarf_cie *cached_cie; +static unsigned int dwarf_unwinder_ready; + /** * dwarf_frame_alloc_reg - allocate memory for a DWARF register * @frame: the DWARF frame whose list of registers we insert on @@ -581,6 +583,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc, struct dwarf_reg *reg; unsigned long addr; + /* + * If we've been called in to before initialization has + * completed, bail out immediately. + */ + if (!dwarf_unwinder_ready) + return NULL; + /* * If we're starting at the top of the stack we need get the * contents of a physical register to get the CFA in order to @@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod) */ static int __init dwarf_unwinder_init(void) { - int err; + int err = -ENOMEM; dwarf_frame_cachep = kmem_cache_create("dwarf_frames", sizeof(struct dwarf_frame), 0, @@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void) mempool_alloc_slab, mempool_free_slab, dwarf_frame_cachep); + if (!dwarf_frame_pool) + goto out; dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, mempool_alloc_slab, mempool_free_slab, dwarf_reg_cachep); + if (!dwarf_reg_pool) + goto out; err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL); if (err) @@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void) if (err) goto out; + dwarf_unwinder_ready = 1; + return 0; out: printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err); dwarf_unwinder_cleanup(); - return -EINVAL; + return err; } early_initcall(dwarf_unwinder_init); diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c index cbf1dd5372b2..5124aeb28c3f 100644 --- a/arch/sh/kernel/return_address.c +++ b/arch/sh/kernel/return_address.c @@ -24,6 +24,8 @@ void *return_address(unsigned int depth) struct dwarf_frame *tmp; tmp = dwarf_unwind_stack(ra, frame); + if (!tmp) + return NULL; if (frame) dwarf_free_frame(frame); -- cgit v1.2.3 From 86e4dd5add77ab809f5427391dfabb8f78cbcb58 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Tue, 25 May 2010 20:06:13 +0900 Subject: sh: support for platforms without PIO. This extends some of the existing special casing for HAS_IOPORT platforms and gets it to the point where platforms can begin to conditionally select it. The major changes here are that the PIO routines themselves go away completely, including all of the machvec port mapping wrappers. With this in place it's possible for any non-machvec abusing platform to disable PIO completely. At present this is left as an opt-in until the abusers are the odd ones out instead of the majority. Signed-off-by: Paul Mundt --- arch/sh/kernel/Makefile | 3 ++- arch/sh/kernel/io.c | 22 ---------------------- arch/sh/kernel/io_generic.c | 20 ++++++++++++++++++++ arch/sh/kernel/io_trapped.c | 4 ++++ arch/sh/kernel/machvec.c | 17 +++++++++++------ 5 files changed, 37 insertions(+), 29 deletions(-) (limited to 'arch/sh/kernel') diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 650b92f00ee5..e25f3c69525d 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile @@ -12,7 +12,7 @@ endif CFLAGS_REMOVE_return_address.o = -pg obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \ - idle.o io.o io_generic.o irq.o \ + idle.o io.o irq.o \ irq_$(BITS).o machvec.o nmi_debug.o process.o \ process_$(BITS).o ptrace_$(BITS).o \ reboot.o return_address.o \ @@ -39,6 +39,7 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o obj-$(CONFIG_HIBERNATION) += swsusp.o obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o +obj-$(CONFIG_HAS_IOPORT) += io_generic.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c index 4770c241c679..5c51b794ba2a 100644 --- a/arch/sh/kernel/io.c +++ b/arch/sh/kernel/io.c @@ -112,25 +112,3 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count) } } EXPORT_SYMBOL(memset_io); - -#ifndef CONFIG_GENERIC_IOMAP - -void __iomem *ioport_map(unsigned long port, unsigned int nr) -{ - void __iomem *ret; - - ret = __ioport_map_trapped(port, nr); - if (ret) - return ret; - - return __ioport_map(port, nr); -} -EXPORT_SYMBOL(ioport_map); - -void ioport_unmap(void __iomem *addr) -{ - sh_mv.mv_ioport_unmap(addr); -} -EXPORT_SYMBOL(ioport_unmap); - -#endif /* CONFIG_GENERIC_IOMAP */ diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index e1e1dbd19557..447d78f666f9 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c @@ -158,3 +158,23 @@ void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) void generic_ioport_unmap(void __iomem *addr) { } + +#ifndef CONFIG_GENERIC_IOMAP +void __iomem *ioport_map(unsigned long port, unsigned int nr) +{ + void __iomem *ret; + + ret = __ioport_map_trapped(port, nr); + if (ret) + return ret; + + return __ioport_map(port, nr); +} +EXPORT_SYMBOL(ioport_map); + +void ioport_unmap(void __iomem *addr) +{ + sh_mv.mv_ioport_unmap(addr); +} +EXPORT_SYMBOL(ioport_unmap); +#endif /* CONFIG_GENERIC_IOMAP */ diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index 4a8bb4eeb8ad..2947d2bd1291 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c @@ -91,10 +91,14 @@ int register_trapped_io(struct trapped_io *tiop) tiop->magic = IO_TRAPPED_MAGIC; INIT_LIST_HEAD(&tiop->list); spin_lock_irq(&trapped_lock); +#ifdef CONFIG_HAS_IOPORT if (flags & IORESOURCE_IO) list_add(&tiop->list, &trapped_io); +#endif +#ifdef CONFIG_HAS_IOMEM if (flags & IORESOURCE_MEM) list_add(&tiop->list, &trapped_mem); +#endif spin_unlock_irq(&trapped_lock); return 0; diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c index 85cfaf916fdc..9f9bb63616ad 100644 --- a/arch/sh/kernel/machvec.c +++ b/arch/sh/kernel/machvec.c @@ -118,6 +118,14 @@ void __init sh_mv_setup(void) sh_mv.mv_##elem = generic_##elem; \ } while (0) +#ifdef CONFIG_HAS_IOPORT + +#ifdef P2SEG + __set_io_port_base(P2SEG); +#else + __set_io_port_base(0); +#endif + mv_set(inb); mv_set(inw); mv_set(inl); mv_set(outb); mv_set(outw); mv_set(outl); @@ -129,16 +137,13 @@ void __init sh_mv_setup(void) mv_set(ioport_map); mv_set(ioport_unmap); + +#endif + mv_set(irq_demux); mv_set(mode_pins); mv_set(mem_init); if (!sh_mv.mv_nr_irqs) sh_mv.mv_nr_irqs = NR_IRQS; - -#ifdef P2SEG - __set_io_port_base(P2SEG); -#else - __set_io_port_base(0); -#endif } -- cgit v1.2.3