diff options
Diffstat (limited to 'arch/hexagon/kernel')
31 files changed, 567 insertions, 620 deletions
diff --git a/arch/hexagon/kernel/Makefile b/arch/hexagon/kernel/Makefile index 3689f3754d0..009228b8611 100644 --- a/arch/hexagon/kernel/Makefile +++ b/arch/hexagon/kernel/Makefile @@ -1,10 +1,9 @@ -extra-y := head.o vmlinux.lds init_task.o +extra-y := head.o vmlinux.lds -obj-$(CONFIG_SMP) += smp.o topology.o +obj-$(CONFIG_SMP) += smp.o obj-y += setup.o irq_cpu.o traps.o syscalltab.o signal.o time.o -obj-y += process.o syscall.o trampoline.o reset.o ptrace.o -obj-y += vdso.o +obj-y += process.o trampoline.o reset.o ptrace.o vdso.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_MODULES) += module.o hexagon_ksyms.o @@ -16,3 +15,5 @@ obj-y += vm_vectors.o obj-$(CONFIG_HAS_DMA) += dma.o obj-$(CONFIG_STACKTRACE) += stacktrace.o + +obj-$(CONFIG_VGA_CONSOLE) += screen_info.o diff --git a/arch/hexagon/kernel/asm-offsets.c b/arch/hexagon/kernel/asm-offsets.c index 89ffa514611..308be68d4fb 100644 --- a/arch/hexagon/kernel/asm-offsets.c +++ b/arch/hexagon/kernel/asm-offsets.c @@ -5,7 +5,7 @@ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com * Copyright (C) 2000 MIPS Technologies, Inc. * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -44,7 +44,8 @@ int main(void) COMMENT("Hexagon pt_regs definitions"); OFFSET(_PT_SYSCALL_NR, pt_regs, syscall_nr); - OFFSET(_PT_UGPGP, pt_regs, ugpgp); + OFFSET(_PT_GPUGP, pt_regs, gpugp); + OFFSET(_PT_CS1CS0, pt_regs, cs1cs0); OFFSET(_PT_R3130, pt_regs, r3130); OFFSET(_PT_R2928, pt_regs, r2928); OFFSET(_PT_R2726, pt_regs, r2726); diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c index e711ace62fd..b74f9bae31a 100644 --- a/arch/hexagon/kernel/dma.c +++ b/arch/hexagon/kernel/dma.c @@ -1,7 +1,7 @@ /* * DMA implementation for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,12 +22,19 @@ #include <linux/bootmem.h> #include <linux/genalloc.h> #include <asm/dma-mapping.h> +#include <linux/module.h> +#include <asm/page.h> struct dma_map_ops *dma_ops; EXPORT_SYMBOL(dma_ops); int bad_dma_address; /* globals are automatically initialized to zero */ +static inline void *dma_addr_to_virt(dma_addr_t dma_addr) +{ + return phys_to_virt((unsigned long) dma_addr); +} + int dma_supported(struct device *dev, u64 mask) { if (mask == DMA_BIT_MASK(32)) @@ -53,11 +60,18 @@ static struct gen_pool *coherent_pool; /* Allocates from a pool of uncached memory that was reserved at boot time */ -void *hexagon_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_addr, gfp_t flag) +static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_addr, gfp_t flag, + struct dma_attrs *attrs) { void *ret; + /* + * Our max_low_pfn should have been backed off by 16MB in + * mm/init.c to create DMA coherent space. Use that as the VA + * for the pool. + */ + if (coherent_pool == NULL) { coherent_pool = gen_pool_create(PAGE_SHIFT, -1); @@ -65,7 +79,7 @@ void *hexagon_dma_alloc_coherent(struct device *dev, size_t size, panic("Can't create %s() memory pool!", __func__); else gen_pool_add(coherent_pool, - (PAGE_OFFSET + (max_low_pfn << PAGE_SHIFT)), + pfn_to_virt(max_low_pfn), hexagon_coherent_pool_size, -1); } @@ -73,7 +87,7 @@ void *hexagon_dma_alloc_coherent(struct device *dev, size_t size, if (ret) { memset(ret, 0, size); - *dma_addr = (dma_addr_t) (ret - PAGE_OFFSET); + *dma_addr = (dma_addr_t) virt_to_phys(ret); } else *dma_addr = ~0; @@ -81,7 +95,7 @@ void *hexagon_dma_alloc_coherent(struct device *dev, size_t size, } static void hexagon_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_addr) + dma_addr_t dma_addr, struct dma_attrs *attrs) { gen_pool_free(coherent_pool, (unsigned long) vaddr, size); } @@ -116,8 +130,8 @@ static int hexagon_map_sg(struct device *hwdev, struct scatterlist *sg, s->dma_length = s->length; - flush_dcache_range(PAGE_OFFSET + s->dma_address, - PAGE_OFFSET + s->dma_address + s->length); + flush_dcache_range(dma_addr_to_virt(s->dma_address), + dma_addr_to_virt(s->dma_address + s->length)); } return nents; @@ -147,11 +161,6 @@ static inline void dma_sync(void *addr, size_t size, } } -static inline void *dma_addr_to_virt(dma_addr_t dma_addr) -{ - return phys_to_virt((unsigned long) dma_addr); -} - /** * hexagon_map_page() - maps an address for device DMA * @dev: pointer to DMA device @@ -202,8 +211,8 @@ static void hexagon_sync_single_for_device(struct device *dev, } struct dma_map_ops hexagon_dma_ops = { - .alloc_coherent = hexagon_dma_alloc_coherent, - .free_coherent = hexagon_free_coherent, + .alloc = hexagon_dma_alloc_coherent, + .free = hexagon_free_coherent, .map_sg = hexagon_map_sg, .map_page = hexagon_map_page, .sync_single_for_cpu = hexagon_sync_single_for_cpu, diff --git a/arch/hexagon/kernel/head.S b/arch/hexagon/kernel/head.S index 8e6b819125a..b9b63d085db 100644 --- a/arch/hexagon/kernel/head.S +++ b/arch/hexagon/kernel/head.S @@ -1,7 +1,7 @@ /* * Early kernel startup code for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * * This program is free software; you can redistribute it and/or modify @@ -25,6 +25,9 @@ #include <asm/mem-layout.h> #include <asm/vm_mmu.h> #include <asm/page.h> +#include <asm/hexagon_vm.h> + +#define SEGTABLE_ENTRIES #0x0e0 __INIT ENTRY(stext) @@ -43,40 +46,93 @@ ENTRY(stext) * Symbol is kernel segment address, but we need * the logical/physical address. */ - r24 = asl(r24, #2) - r24 = lsr(r24, #2) + r25 = pc; + r2.h = #0xffc0; + r2.l = #0x0000; + r25 = and(r2,r25); /* R25 holds PHYS_OFFSET now */ + r1.h = #HI(PAGE_OFFSET); + r1.l = #LO(PAGE_OFFSET); + r24 = sub(r24,r1); /* swapper_pg_dir - PAGE_OFFSET */ + r24 = add(r24,r25); /* + PHYS_OFFSET */ - r0 = r24 + r0 = r24; /* aka __pa(swapper_pg_dir) */ /* - * Initialize a 16MB PTE to make the virtual and physical + * Initialize page dir to make the virtual and physical * addresses where the kernel was loaded be identical. + * Done in 4MB chunks. */ #define PTE_BITS ( __HVM_PTE_R | __HVM_PTE_W | __HVM_PTE_X \ | __HEXAGON_C_WB_L2 << 6 \ | __HVM_PDE_S_4MB) - r1 = pc - r2.H = #0xffc0 - r2.L = #0x0000 - r1 = and(r1,r2) /* round PC to 4MB boundary */ + /* + * Get number of VA=PA entries; only really needed for jump + * to hyperspace; gets blown away immediately after + */ + + { + r1.l = #LO(_end); + r2.l = #LO(stext); + r3 = #1; + } + { + r1.h = #HI(_end); + r2.h = #HI(stext); + r3 = asl(r3, #22); + } + { + r1 = sub(r1, r2); + r3 = add(r3, #-1); + } /* r1 = _end - stext */ + r1 = add(r1, r3); /* + (4M-1) */ + r26 = lsr(r1, #22); /* / 4M = # of entries */ + + r1 = r25; + r2.h = #0xffc0; + r2.l = #0x0000; /* round back down to 4MB boundary */ + r1 = and(r1,r2); r2 = lsr(r1, #22) /* 4MB page number */ r2 = asl(r2, #2) /* times sizeof(PTE) (4bytes) */ r0 = add(r0,r2) /* r0 = address of correct PTE */ r2 = #PTE_BITS r1 = add(r1,r2) /* r1 = 4MB PTE for the first entry */ r2.h = #0x0040 - r2.l = #0x0000 /* 4MB */ - memw(r0 ++ #4) = r1 - r1 = add(r1, r2) + r2.l = #0x0000 /* 4MB increments */ + loop0(1f,r26); +1: memw(r0 ++ #4) = r1 + { r1 = add(r1, r2); } :endloop0 + + /* Also need to overwrite the initial 0xc0000000 entries */ + /* PAGE_OFFSET >> (4MB shift - 4 bytes per entry shift) */ + R1.H = #HI(PAGE_OFFSET >> (22 - 2)) + R1.L = #LO(PAGE_OFFSET >> (22 - 2)) + + r0 = add(r1, r24); /* advance to 0xc0000000 entry */ + r1 = r25; + r2.h = #0xffc0; + r2.l = #0x0000; /* round back down to 4MB boundary */ + r1 = and(r1,r2); /* for huge page */ + r2 = #PTE_BITS + r1 = add(r1,r2); + r2.h = #0x0040 + r2.l = #0x0000 /* 4MB increments */ - r0 = r24 + loop0(1f,SEGTABLE_ENTRIES); +1: + memw(r0 ++ #4) = r1; + { r1 = add(r1,r2); } :endloop0 + + r0 = r24; /* * The subroutine wrapper around the virtual instruction touches * no memory, so we should be able to use it even here. + * Note that in this version, R1 and R2 get "clobbered"; see + * vm_ops.S */ + r1 = #VM_TRANS_TYPE_TABLE call __vmnewmap; /* Jump into virtual address range. */ @@ -90,17 +146,29 @@ ENTRY(stext) __head_s_vaddr_target: /* * Tear down VA=PA translation now that we are running - * in the desgnated kernel segments. + * in kernel virtual space. */ r0 = #__HVM_PDE_S_INVALID - r1 = r24 - loop0(1f,#0x100) + + r1.h = #0xffc0; + r1.l = #0x0000; + r2 = r25; /* phys_offset */ + r2 = and(r1,r2); + + r1.l = #lo(swapper_pg_dir) + r1.h = #hi(swapper_pg_dir) + r2 = lsr(r2, #22) /* 4MB page number */ + r2 = asl(r2, #2) /* times sizeof(PTE) (4bytes) */ + r1 = add(r1,r2); + loop0(1f,r26) + 1: { memw(R1 ++ #4) = R0 }:endloop0 r0 = r24 + r1 = #VM_TRANS_TYPE_TABLE call __vmnewmap /* Go ahead and install the trap0 return so angel calls work */ @@ -143,6 +211,13 @@ __head_s_vaddr_target: r2 = sub(r2,r0); call memset; + /* Set PHYS_OFFSET; should be in R25 */ +#ifdef CONFIG_HEXAGON_PHYS_OFFSET + r0.l = #LO(__phys_offset); + r0.h = #HI(__phys_offset); + memw(r0) = r25; +#endif + /* Time to make the doughnuts. */ call start_kernel diff --git a/arch/hexagon/kernel/hexagon_ksyms.c b/arch/hexagon/kernel/hexagon_ksyms.c index 7f189247180..c041d8ecb1e 100644 --- a/arch/hexagon/kernel/hexagon_ksyms.c +++ b/arch/hexagon/kernel/hexagon_ksyms.c @@ -1,7 +1,7 @@ /* * Export of symbols defined in assembly files and/or libgcc. * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,23 +18,39 @@ * 02110-1301, USA. */ +#include <linux/dma-mapping.h> #include <asm/hexagon_vm.h> +#include <asm/io.h> #include <asm/uaccess.h> +/* Additional functions */ +EXPORT_SYMBOL(__clear_user_hexagon); EXPORT_SYMBOL(__copy_from_user_hexagon); EXPORT_SYMBOL(__copy_to_user_hexagon); +EXPORT_SYMBOL(__iounmap); +EXPORT_SYMBOL(__strnlen_user); EXPORT_SYMBOL(__vmgetie); EXPORT_SYMBOL(__vmsetie); +EXPORT_SYMBOL(__vmyield); +EXPORT_SYMBOL(empty_zero_page); +EXPORT_SYMBOL(ioremap_nocache); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); +/* Additional variables */ +EXPORT_SYMBOL(__phys_offset); +EXPORT_SYMBOL(_dflt_cache_att); +EXPORT_SYMBOL(bad_dma_address); + #define DECLARE_EXPORT(name) \ extern void name(void); EXPORT_SYMBOL(name) /* Symbols found in libgcc that assorted kernel modules need */ DECLARE_EXPORT(__hexagon_memcpy_likely_aligned_min32bytes_mult8bytes); -DECLARE_EXPORT(__hexagon_divsi3); -DECLARE_EXPORT(__hexagon_modsi3); -DECLARE_EXPORT(__hexagon_udivsi3); -DECLARE_EXPORT(__hexagon_umodsi3); +/* Additional functions */ +DECLARE_EXPORT(__divsi3); +DECLARE_EXPORT(__modsi3); +DECLARE_EXPORT(__udivsi3); +DECLARE_EXPORT(__umodsi3); +DECLARE_EXPORT(csum_tcpudp_magic); diff --git a/arch/hexagon/kernel/init_task.c b/arch/hexagon/kernel/init_task.c deleted file mode 100644 index 73283d3edf0..00000000000 --- a/arch/hexagon/kernel/init_task.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Init task definition - * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/init_task.h> -#include <linux/fs.h> -#include <linux/mqueue.h> -#include <asm/thread_info.h> -#include <asm/uaccess.h> -#include <asm/pgtable.h> - -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); - -/* - * Initial thread structure. - * - * We need to make sure that this is 8192-byte aligned due to the - * way process stacks are handled. This is done by making sure - * the linker maps this in the .text segment right after head.S, - * and making head.S ensure the proper alignment. - */ -union thread_union init_thread_union - __attribute__((__section__(".data.init_task"), - __aligned__(THREAD_SIZE))) = { - INIT_THREAD_INFO(init_task) - }; - -/* - * Initial task structure. - * - * All other task structs will be allocated on slabs in fork.c - */ -struct task_struct init_task = INIT_TASK(init_task); -EXPORT_SYMBOL(init_task); diff --git a/arch/hexagon/kernel/irq_cpu.c b/arch/hexagon/kernel/irq_cpu.c index d4416a1a431..85883e1fdc1 100644 --- a/arch/hexagon/kernel/irq_cpu.c +++ b/arch/hexagon/kernel/irq_cpu.c @@ -1,7 +1,7 @@ /* * First-level interrupt controller model for Hexagon. * - * Copyright (c) 2010-2011 Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/kgdb.c b/arch/hexagon/kernel/kgdb.c index fe4aa1bcca5..038580cc5ab 100644 --- a/arch/hexagon/kernel/kgdb.c +++ b/arch/hexagon/kernel/kgdb.c @@ -1,7 +1,7 @@ /* * arch/hexagon/kernel/kgdb.c - Hexagon KGDB Support * - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,6 +18,8 @@ * 02110-1301, USA. */ +#include <linux/irq.h> +#include <linux/sched.h> #include <linux/kdebug.h> #include <linux/kgdb.h> @@ -70,6 +72,8 @@ struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { { "lc1", GDB_SIZEOF_REG, offsetof(struct pt_regs, lc1)}, { " gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp)}, { "ugp", GDB_SIZEOF_REG, offsetof(struct pt_regs, ugp)}, + { "cs0", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs0)}, + { "cs1", GDB_SIZEOF_REG, offsetof(struct pt_regs, cs1)}, { "psp", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmpsp)}, { "elr", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmel)}, { "est", GDB_SIZEOF_REG, offsetof(struct pt_regs, hvmer.vmest)}, diff --git a/arch/hexagon/kernel/module.c b/arch/hexagon/kernel/module.c index 61a76bae366..477d07a5646 100644 --- a/arch/hexagon/kernel/module.c +++ b/arch/hexagon/kernel/module.c @@ -1,7 +1,7 @@ /* * Kernel module loader for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c index 18c4f0b0f4b..0a0dd5c05b4 100644 --- a/arch/hexagon/kernel/process.c +++ b/arch/hexagon/kernel/process.c @@ -1,7 +1,7 @@ /* * Process creation support for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -24,33 +24,7 @@ #include <linux/tick.h> #include <linux/uaccess.h> #include <linux/slab.h> - -/* - * Kernel thread creation. The desired kernel function is "wrapped" - * in the kernel_thread_helper function, which does cleanup - * afterwards. - */ -static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *)) -{ - do_exit(fn(arg)); -} - -int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) -{ - struct pt_regs regs; - - memset(®s, 0, sizeof(regs)); - /* - * Yes, we're exploting illicit knowledge of the ABI here. - */ - regs.r00 = (unsigned long) arg; - regs.r01 = (unsigned long) fn; - pt_set_elr(®s, (unsigned long)kernel_thread_helper); - pt_set_kmode(®s); - - return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); -} -EXPORT_SYMBOL(kernel_thread); +#include <linux/tracehook.h> /* * Program thread launch. Often defined as a macro in processor.h, @@ -78,28 +52,11 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp) * If hardware or VM offer wait termination even though interrupts * are disabled. */ -static void default_idle(void) +void arch_cpu_idle(void) { __vmwait(); -} - -void (*idle_sleep)(void) = default_idle; - -void cpu_idle(void) -{ - while (1) { - tick_nohz_stop_sched_tick(1); - local_irq_disable(); - while (!need_resched()) { - idle_sleep(); - /* interrupts wake us up, but aren't serviced */ - local_irq_enable(); /* service interrupt */ - local_irq_disable(); - } - local_irq_enable(); - tick_nohz_restart_sched_tick(); - schedule(); - } + /* interrupts wake us up, but irqs are still disabled */ + local_irq_enable(); } /* @@ -114,8 +71,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) * Copy architecture-specific thread state */ int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, struct task_struct *p, - struct pt_regs *regs) + unsigned long arg, struct task_struct *p) { struct thread_info *ti = task_thread_info(p); struct hexagon_switch_stack *ss; @@ -125,61 +81,52 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, childregs = (struct pt_regs *) (((unsigned long) ti + THREAD_SIZE) - sizeof(*childregs)); - memcpy(childregs, regs, sizeof(*childregs)); ti->regs = childregs; /* * Establish kernel stack pointer and initial PC for new thread + * Note that unlike the usual situation, we do not copy the + * parent's callee-saved here; those are in pt_regs and whatever + * we leave here will be overridden on return to userland. */ ss = (struct hexagon_switch_stack *) ((unsigned long) childregs - sizeof(*ss)); ss->lr = (unsigned long)ret_from_fork; p->thread.switch_sp = ss; + if (unlikely(p->flags & PF_KTHREAD)) { + memset(childregs, 0, sizeof(struct pt_regs)); + /* r24 <- fn, r25 <- arg */ + ss->r24 = usp; + ss->r25 = arg; + pt_set_kmode(childregs); + return 0; + } + memcpy(childregs, current_pt_regs(), sizeof(*childregs)); + ss->r2524 = 0; - /* If User mode thread, set pt_reg stack pointer as per parameter */ - if (user_mode(childregs)) { + if (usp) pt_set_rte_sp(childregs, usp); - /* Child sees zero return value */ - childregs->r00 = 0; + /* Child sees zero return value */ + childregs->r00 = 0; - /* - * The clone syscall has the C signature: - * int [r0] clone(int flags [r0], - * void *child_frame [r1], - * void *parent_tid [r2], - * void *child_tid [r3], - * void *thread_control_block [r4]); - * ugp is used to provide TLS support. - */ - if (clone_flags & CLONE_SETTLS) - childregs->ugp = childregs->r04; - - /* - * Parent sees new pid -- not necessary, not even possible at - * this point in the fork process - * Might also want to set things like ti->addr_limit - */ - } else { - /* - * If kernel thread, resume stack is kernel stack base. - * Note that this is pointer arithmetic on pt_regs * - */ - pt_set_rte_sp(childregs, (unsigned long)(childregs + 1)); - /* - * We need the current thread_info fast path pointer - * set up in pt_regs. The register to be used is - * parametric for assembler code, but the mechanism - * doesn't drop neatly into C. Needs to be fixed. - */ - childregs->THREADINFO_REG = (unsigned long) ti; - } + /* + * The clone syscall has the C signature: + * int [r0] clone(int flags [r0], + * void *child_frame [r1], + * void *parent_tid [r2], + * void *child_tid [r3], + * void *thread_control_block [r4]); + * ugp is used to provide TLS support. + */ + if (clone_flags & CLONE_SETTLS) + childregs->ugp = childregs->r04; /* - * thread_info pointer is pulled out of task_struct "stack" - * field on switch_to. + * Parent sees new pid -- not necessary, not even possible at + * this point in the fork process + * Might also want to set things like ti->addr_limit */ - p->stack = (void *)ti; return 0; } @@ -234,46 +181,47 @@ unsigned long get_wchan(struct task_struct *p) } /* - * Borrowed from PowerPC -- basically allow smaller kernel stacks if we - * go crazy with the page sizes. + * Required placeholder. */ -#if THREAD_SHIFT < PAGE_SHIFT - -static struct kmem_cache *thread_info_cache; - -struct thread_info *alloc_thread_info_node(struct task_struct *tsk, int node) +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { - struct thread_info *ti; - - ti = kmem_cache_alloc_node(thread_info_cache, GFP_KERNEL, node); - if (unlikely(ti == NULL)) - return NULL; -#ifdef CONFIG_DEBUG_STACK_USAGE - memset(ti, 0, THREAD_SIZE); -#endif - return ti; + return 0; } -void free_thread_info(struct thread_info *ti) -{ - kmem_cache_free(thread_info_cache, ti); -} -/* Weak symbol; called by init/main.c */ +/* + * Called on the exit path of event entry; see vm_entry.S + * + * Interrupts will already be disabled. + * + * Returns 0 if there's no need to re-check for more work. + */ -void thread_info_cache_init(void) +int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) { - thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE, - THREAD_SIZE, 0, NULL); - BUG_ON(thread_info_cache == NULL); -} + if (!(thread_info_flags & _TIF_WORK_MASK)) { + return 0; + } /* shortcut -- no work to be done */ -#endif /* THREAD_SHIFT < PAGE_SHIFT */ + local_irq_enable(); -/* - * Required placeholder. - */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) -{ - return 0; + if (thread_info_flags & _TIF_NEED_RESCHED) { + schedule(); + return 1; + } + + if (thread_info_flags & _TIF_SIGPENDING) { + do_signal(regs); + return 1; + } + + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + return 1; + } + + /* Should not even reach here */ + panic("%s: bad thread_info flags 0x%08x\n", __func__, + thread_info_flags); } diff --git a/arch/hexagon/kernel/ptrace.c b/arch/hexagon/kernel/ptrace.c index bea3f08470f..390a9ad14ca 100644 --- a/arch/hexagon/kernel/ptrace.c +++ b/arch/hexagon/kernel/ptrace.c @@ -1,7 +1,7 @@ /* * Ptrace support for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,10 +28,25 @@ #include <linux/ptrace.h> #include <linux/regset.h> #include <linux/user.h> +#include <linux/elf.h> -#include <asm/system.h> #include <asm/user.h> +#if arch_has_single_step() +/* Both called from ptrace_resume */ +void user_enable_single_step(struct task_struct *child) +{ + pt_set_singlestep(task_pt_regs(child)); + set_tsk_thread_flag(child, TIF_SINGLESTEP); +} + +void user_disable_single_step(struct task_struct *child) +{ + pt_clr_singlestep(task_pt_regs(child)); + clear_tsk_thread_flag(child, TIF_SINGLESTEP); +} +#endif + static int genregs_get(struct task_struct *target, const struct user_regset *regset, unsigned int pos, unsigned int count, @@ -76,6 +91,10 @@ static int genregs_get(struct task_struct *target, dummy = pt_cause(regs); ONEXT(&dummy, cause); ONEXT(&pt_badva(regs), badva); +#if CONFIG_HEXAGON_ARCH_VERSION >=4 + ONEXT(®s->cs0, cs0); + ONEXT(®s->cs1, cs1); +#endif /* Pad the rest with zeros, if needed */ if (!ret) @@ -123,6 +142,11 @@ static int genregs_set(struct task_struct *target, INEXT(&bucket, cause); INEXT(&bucket, badva); +#if CONFIG_HEXAGON_ARCH_VERSION >=4 + INEXT(®s->cs0, cs0); + INEXT(®s->cs1, cs1); +#endif + /* Ignore the rest, if needed */ if (!ret) ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, @@ -159,6 +183,7 @@ static const struct user_regset_view hexagon_user_view = { .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI, .regsets = hexagon_regsets, + .e_flags = ELF_CORE_EFLAGS, .n = ARRAY_SIZE(hexagon_regsets) }; diff --git a/arch/hexagon/kernel/reset.c b/arch/hexagon/kernel/reset.c index 4d72fc58e9b..76483c10130 100644 --- a/arch/hexagon/kernel/reset.c +++ b/arch/hexagon/kernel/reset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -33,6 +33,5 @@ void machine_restart(char *cmd) { } -void pm_power_off(void) -{ -} +void (*pm_power_off)(void) = NULL; +EXPORT_SYMBOL(pm_power_off); diff --git a/arch/hexagon/kernel/screen_info.c b/arch/hexagon/kernel/screen_info.c new file mode 100644 index 00000000000..1e1ceb18baf --- /dev/null +++ b/arch/hexagon/kernel/screen_info.c @@ -0,0 +1,3 @@ +#include <linux/screen_info.h> + +struct screen_info screen_info; diff --git a/arch/hexagon/kernel/setup.c b/arch/hexagon/kernel/setup.c index 1202f78d25c..0e7c1dbb37b 100644 --- a/arch/hexagon/kernel/setup.c +++ b/arch/hexagon/kernel/setup.c @@ -1,7 +1,7 @@ /* * Arch related setup for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,16 +32,13 @@ #include <asm/hexagon_vm.h> #include <asm/vm_mmu.h> #include <asm/time.h> -#ifdef CONFIG_OF -#include <asm/prom.h> -#endif char cmd_line[COMMAND_LINE_SIZE]; static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; int on_simulator; -void __cpuinit calibrate_delay(void) +void calibrate_delay(void) { loops_per_jiffy = thread_freq_mhz * 1000000 / HZ; } @@ -68,6 +65,8 @@ void __init setup_arch(char **cmdline_p) */ __vmsetvec(_K_VM_event_vector); + printk(KERN_INFO "PHYS_OFFSET=0x%08x\n", PHYS_OFFSET); + /* * Simulator has a few differences from the hardware. * For now, check uninitialized-but-mapped memory @@ -128,6 +127,11 @@ static int show_cpuinfo(struct seq_file *m, void *v) { int cpu = (unsigned long) v - 1; +#ifdef CONFIG_SMP + if (!cpu_online(cpu)) + return 0; +#endif + seq_printf(m, "processor\t: %d\n", cpu); seq_printf(m, "model name\t: Hexagon Virtual Machine\n"); seq_printf(m, "BogoMips\t: %lu.%02lu\n", diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index b45be318119..d7c73874b51 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c @@ -1,7 +1,7 @@ /* * Signal support for Hexagon processor * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -20,7 +20,6 @@ #include <linux/linkage.h> #include <linux/syscalls.h> -#include <linux/freezer.h> #include <linux/tracehook.h> #include <asm/registers.h> #include <asm/thread_info.h> @@ -31,8 +30,6 @@ #include <asm/signal.h> #include <asm/vdso.h> -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - struct rt_sigframe { unsigned long tramp[2]; struct siginfo info; @@ -44,6 +41,10 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, { unsigned long sp = regs->r29; + /* check if we would overflow the alt stack */ + if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) + return (void __user __force *)-1UL; + /* Switch to signal stack if appropriate */ if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) sp = current->sas_ss_sp + current->sas_ss_size; @@ -69,7 +70,10 @@ static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) err |= __put_user(regs->preds, &sc->sc_regs.p3_0); err |= __put_user(regs->gp, &sc->sc_regs.gp); err |= __put_user(regs->ugp, &sc->sc_regs.ugp); - +#if CONFIG_HEXAGON_ARCH_VERSION >= 4 + err |= __put_user(regs->cs0, &sc->sc_regs.cs0); + err |= __put_user(regs->cs1, &sc->sc_regs.cs1); +#endif tmp = pt_elr(regs); err |= __put_user(tmp, &sc->sc_regs.pc); tmp = pt_cause(regs); err |= __put_user(tmp, &sc->sc_regs.cause); tmp = pt_badva(regs); err |= __put_user(tmp, &sc->sc_regs.badva); @@ -96,7 +100,10 @@ static int restore_sigcontext(struct pt_regs *regs, err |= __get_user(regs->preds, &sc->sc_regs.p3_0); err |= __get_user(regs->gp, &sc->sc_regs.gp); err |= __get_user(regs->ugp, &sc->sc_regs.ugp); - +#if CONFIG_HEXAGON_ARCH_VERSION >= 4 + err |= __get_user(regs->cs0, &sc->sc_regs.cs0); + err |= __get_user(regs->cs1, &sc->sc_regs.cs1); +#endif err |= __get_user(tmp, &sc->sc_regs.pc); pt_set_elr(regs, tmp); return err; @@ -128,6 +135,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(0x5400c004, &frame->tramp[1]); err |= setup_sigcontext(regs, &frame->uc.uc_mcontext); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + err |= __save_altstack(&frame->uc.uc_stack, user_stack_pointer(regs)); if (err) goto sigsegv; @@ -149,11 +157,9 @@ sigsegv: /* * Setup invocation of signal handler */ -static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, - sigset_t *oldset, struct pt_regs *regs) +static void handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, + struct pt_regs *regs) { - int rc; - /* * If we're handling a signal that aborted a system call, * set up the error return value before adding the signal @@ -186,26 +192,18 @@ static int handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka, * Set up the stack frame; not doing the SA_SIGINFO thing. We * only set up the rt_frame flavor. */ - rc = setup_rt_frame(sig, ka, info, oldset, regs); - /* If there was an error on setup, no signal was delivered. */ - if (rc) - return rc; - - spin_lock_irq(¤t->sighand->siglock); - sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); - if (!(ka->sa.sa_flags & SA_NODEFER)) - sigaddset(¤t->blocked, sig); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs) < 0) + return; - return 0; + signal_delivered(sig, info, ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } /* * Called from return-from-event code. */ -static void do_signal(struct pt_regs *regs) +void do_signal(struct pt_regs *regs) { struct k_sigaction sigact; siginfo_t info; @@ -214,37 +212,17 @@ static void do_signal(struct pt_regs *regs) if (!user_mode(regs)) return; - if (try_to_freeze()) - goto no_signal; - signo = get_signal_to_deliver(&info, &sigact, regs, NULL); if (signo > 0) { - sigset_t *oldset; - - if (test_thread_flag(TIF_RESTORE_SIGMASK)) - oldset = ¤t->saved_sigmask; - else - oldset = ¤t->blocked; - - if (handle_signal(signo, &info, &sigact, oldset, regs) == 0) { - /* - * Successful delivery case. The saved sigmask is - * stored in the signal frame, and will be restored - * by sigreturn. We can clear the TIF flag. - */ - clear_thread_flag(TIF_RESTORE_SIGMASK); - - tracehook_signal_handler(signo, &info, &sigact, regs, - test_thread_flag(TIF_SINGLESTEP)); - } + handle_signal(signo, &info, &sigact, regs); return; } -no_signal: /* - * If we came from a system call, handle the restart. + * No (more) signals; if we came from a system call, handle the restart. */ + if (regs->syscall_nr >= 0) { switch (regs->r00) { case -ERESTARTNOHAND: @@ -264,51 +242,29 @@ no_signal: no_restart: /* If there's no signal to deliver, put the saved sigmask back */ - if (test_thread_flag(TIF_RESTORE_SIGMASK)) { - clear_thread_flag(TIF_RESTORE_SIGMASK); - sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); - } -} - -void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) -{ - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); - - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - if (current->replacement_session_keyring) - key_replace_session_keyring(); - } + restore_saved_sigmask(); } /* * Architecture-specific wrappers for signal-related system calls */ -asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) -{ - struct pt_regs *regs = current_thread_info()->regs; - - return do_sigaltstack(uss, uoss, regs->r29); -} asmlinkage int sys_rt_sigreturn(void) { - struct pt_regs *regs = current_thread_info()->regs; + struct pt_regs *regs = current_pt_regs(); struct rt_sigframe __user *frame; sigset_t blocked; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + frame = (struct rt_sigframe __user *)pt_psp(regs); if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__copy_from_user(&blocked, &frame->uc.uc_sigmask, sizeof(blocked))) goto badframe; - sigdelsetmask(&blocked, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = blocked; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(&blocked); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -316,28 +272,12 @@ asmlinkage int sys_rt_sigreturn(void) /* Restore the user's stack as well */ pt_psp(regs) = regs->r29; - /* - * Leave a trace in the stack frame that this was a sigreturn. - * If the system call is to replay, we've already restored the - * number in the GPR slot and it will be regenerated on the - * new system call trap entry. Note that if restore_sigcontext() - * did something other than a bulk copy of the pt_regs struct, - * we could avoid this assignment by simply not overwriting - * regs->syscall_nr. - */ - regs->syscall_nr = __NR_rt_sigreturn; + regs->syscall_nr = -1; - /* - * If we were meticulous, we'd only call this if we knew that - * we were actually going to use an alternate stack, and we'd - * consider any error to be fatal. What we do here, in common - * with many other architectures, is call it blindly and only - * consider the -EFAULT return case to be proof of a problem. - */ - if (do_sigaltstack(&frame->uc.uc_stack, NULL, pt_psp(regs)) == -EFAULT) + if (restore_altstack(&frame->uc.uc_stack)) goto badframe; - return 0; + return regs->r00; badframe: force_sig(SIGSEGV, current); diff --git a/arch/hexagon/kernel/smp.c b/arch/hexagon/kernel/smp.c index c871a2cffae..ff759f26b96 100644 --- a/arch/hexagon/kernel/smp.c +++ b/arch/hexagon/kernel/smp.c @@ -1,7 +1,7 @@ /* * SMP support for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,15 +28,15 @@ #include <linux/sched.h> #include <linux/smp.h> #include <linux/spinlock.h> +#include <linux/cpu.h> -#include <asm/system.h> /* xchg */ #include <asm/time.h> /* timer_interrupt */ #include <asm/hexagon_vm.h> #define BASE_IPI_IRQ 26 /* - * cpu_possible_map needs to be filled out prior to setup_per_cpu_areas + * cpu_possible_mask needs to be filled out prior to setup_per_cpu_areas * (which is prior to any of our smp_prepare_cpu crap), in order to set * up the... per_cpu areas. */ @@ -64,10 +64,6 @@ static inline void __handle_ipi(unsigned long *ops, struct ipi_data *ipi, generic_smp_call_function_interrupt(); break; - case IPI_CALL_FUNC_SINGLE: - generic_smp_call_function_single_interrupt(); - break; - case IPI_CPU_STOP: /* * call vmstop() @@ -146,7 +142,7 @@ void __init smp_prepare_boot_cpu(void) * to point to current thread info */ -void __cpuinit start_secondary(void) +void start_secondary(void) { unsigned int cpu; unsigned long thread_ptr; @@ -178,12 +174,13 @@ void __cpuinit start_secondary(void) printk(KERN_INFO "%s cpu %d\n", __func__, current_thread_info()->cpu); + notify_cpu_starting(cpu); + set_cpu_online(cpu, true); - while (!cpumask_test_cpu(cpu, cpu_active_mask)) - cpu_relax(); + local_irq_enable(); - cpu_idle(); + cpu_startup_entry(CPUHP_ONLINE); } @@ -193,25 +190,18 @@ void __cpuinit start_secondary(void) * maintains control until "cpu_online(cpu)" is set. */ -int __cpuinit __cpu_up(unsigned int cpu) +int __cpu_up(unsigned int cpu, struct task_struct *idle) { - struct task_struct *idle; - struct thread_info *thread; + struct thread_info *thread = (struct thread_info *)idle->stack; void *stack_start; - /* Create new init task for the CPU */ - idle = fork_idle(cpu); - if (IS_ERR(idle)) - panic(KERN_ERR "fork_idle failed\n"); - - thread = (struct thread_info *)idle->stack; thread->cpu = cpu; /* Boot to the head. */ stack_start = ((void *) thread) + THREAD_SIZE; __vmstart(start_secondary, stack_start); - while (!cpu_isset(cpu, cpu_online_map)) + while (!cpu_online(cpu)) barrier(); return 0; @@ -232,7 +222,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) /* Right now, let's just fake it. */ for (i = 0; i < max_cpus; i++) - cpu_set(i, cpu_present_map); + set_cpu_present(i, true); /* Also need to register the interrupts for IPI */ if (max_cpus > 1) @@ -254,7 +244,7 @@ void smp_send_stop(void) void arch_send_call_function_single_ipi(int cpu) { - send_ipi(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE); + send_ipi(cpumask_of(cpu), IPI_CALL_FUNC); } void arch_send_call_function_ipi_mask(const struct cpumask *mask) @@ -272,5 +262,5 @@ void smp_start_cpus(void) int i; for (i = 0; i < NR_CPUS; i++) - cpu_set(i, cpu_possible_map); + set_cpu_possible(i, true); } diff --git a/arch/hexagon/kernel/stacktrace.c b/arch/hexagon/kernel/stacktrace.c index 11c597b2ac5..f94918b449a 100644 --- a/arch/hexagon/kernel/stacktrace.c +++ b/arch/hexagon/kernel/stacktrace.c @@ -1,7 +1,7 @@ /* * Stacktrace support for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c deleted file mode 100644 index 620dd18197a..00000000000 --- a/arch/hexagon/kernel/syscall.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Hexagon system calls - * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/linkage.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/syscalls.h> -#include <linux/unistd.h> -#include <asm/mman.h> -#include <asm/registers.h> - -/* - * System calls with architecture-specific wrappers. - * See signal.c for signal-related system call wrappers. - */ - -asmlinkage int sys_execve(char __user *ufilename, - const char __user *const __user *argv, - const char __user *const __user *envp) -{ - struct pt_regs *pregs = current_thread_info()->regs; - char *filename; - int retval; - - filename = getname(ufilename); - retval = PTR_ERR(filename); - if (IS_ERR(filename)) - return retval; - - retval = do_execve(filename, argv, envp, pregs); - putname(filename); - - return retval; -} - -asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, - unsigned long parent_tidp, unsigned long child_tidp) -{ - struct pt_regs *pregs = current_thread_info()->regs; - - if (!newsp) - newsp = pregs->SP; - return do_fork(clone_flags, newsp, pregs, 0, (int __user *)parent_tidp, - (int __user *)child_tidp); -} - -/* - * Do a system call from the kernel, so as to have a proper pt_regs - * and recycle the sys_execvpe infrustructure. - */ -int kernel_execve(const char *filename, - const char *const argv[], const char *const envp[]) -{ - register unsigned long __a0 asm("r0") = (unsigned long) filename; - register unsigned long __a1 asm("r1") = (unsigned long) argv; - register unsigned long __a2 asm("r2") = (unsigned long) envp; - int retval; - - __asm__ volatile( - " R6 = #%4;\n" - " trap0(#1);\n" - " %0 = R0;\n" - : "=r" (retval) - : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve) - ); - - return retval; -} -EXPORT_SYMBOL(kernel_execve); diff --git a/arch/hexagon/kernel/syscalltab.c b/arch/hexagon/kernel/syscalltab.c index c550f4177ab..7024b1ddc08 100644 --- a/arch/hexagon/kernel/syscalltab.c +++ b/arch/hexagon/kernel/syscalltab.c @@ -1,7 +1,7 @@ /* * System call table for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/time.c b/arch/hexagon/kernel/time.c index 6bee15c9c11..17fbf45bf15 100644 --- a/arch/hexagon/kernel/time.c +++ b/arch/hexagon/kernel/time.c @@ -1,7 +1,7 @@ /* * Time related functions for Hexagon architecture * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -28,6 +28,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/module.h> #include <asm/timer-regs.h> #include <asm/hexagon_vm.h> @@ -190,9 +191,6 @@ void __init time_init_deferred(void) { struct resource *resource = NULL; struct clock_event_device *ce_dev = &hexagon_clockevent_dev; - struct device_node *dn; - struct resource r; - int err; ce_dev->cpumask = cpu_all_mask; @@ -200,12 +198,10 @@ void __init time_init_deferred(void) resource = rtos_timer_device.resource; /* ioremap here means this has to run later, after paging init */ - rtos_timer = ioremap(resource->start, resource->end - - resource->start + 1); + rtos_timer = ioremap(resource->start, resource_size(resource)); if (!rtos_timer) { - release_mem_region(resource->start, resource->end - - resource->start + 1); + release_mem_region(resource->start, resource_size(resource)); } clocksource_register_khz(&hexagon_clocksource, pcycle_freq_mhz * 1000); @@ -233,6 +229,15 @@ void __init time_init(void) late_time_init = time_init_deferred; } +void __delay(unsigned long cycles) +{ + unsigned long long start = __vmgettime(); + + while ((__vmgettime() - start) < cycles) + cpu_relax(); +} +EXPORT_SYMBOL(__delay); + /* * This could become parametric or perhaps even computed at run-time, * but for now we take the observed simulator jitter. diff --git a/arch/hexagon/kernel/topology.c b/arch/hexagon/kernel/topology.c deleted file mode 100644 index ba447518443..00000000000 --- a/arch/hexagon/kernel/topology.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * CPU topology for Hexagon - * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include <linux/cpu.h> -#include <linux/cpumask.h> -#include <linux/init.h> -#include <linux/node.h> -#include <linux/nodemask.h> -#include <linux/percpu.h> - -/* Swiped from MIPS. */ - -static DEFINE_PER_CPU(struct cpu, cpu_devices); - -static int __init topology_init(void) -{ - int i, ret; - - for_each_present_cpu(i) { - - /* - * register_cpu takes a per_cpu pointer and - * just points it at another per_cpu struct... - */ - - ret = register_cpu(&per_cpu(cpu_devices, i), i); - if (ret) - printk(KERN_WARNING "topology_init: register_cpu %d " - "failed (%d)\n", i, ret); - } - - return 0; -} - -subsys_initcall(topology_init); diff --git a/arch/hexagon/kernel/trampoline.S b/arch/hexagon/kernel/trampoline.S index 06c36c036b9..18110a9056b 100644 --- a/arch/hexagon/kernel/trampoline.S +++ b/arch/hexagon/kernel/trampoline.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/traps.c b/arch/hexagon/kernel/traps.c index f08857d0715..7858663352b 100644 --- a/arch/hexagon/kernel/traps.c +++ b/arch/hexagon/kernel/traps.c @@ -1,7 +1,7 @@ /* * Kernel traps/events for Hexagon processor * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -65,6 +65,10 @@ static const char *ex_name(int ex) return "Write protection fault"; case HVM_GE_C_XMAL: return "Misaligned instruction"; + case HVM_GE_C_WREG: + return "Multiple writes to same register in packet"; + case HVM_GE_C_PCAL: + return "Program counter values that are not properly aligned"; case HVM_GE_C_RMAL: return "Misaligned data load"; case HVM_GE_C_WMAL: @@ -191,14 +195,6 @@ void show_stack(struct task_struct *task, unsigned long *fp) do_show_stack(task, fp, 0); } -void dump_stack(void) -{ - unsigned long *fp; - asm("%0 = r30" : "=r" (fp)); - show_stack(current, fp); -} -EXPORT_SYMBOL(dump_stack); - int die(const char *str, struct pt_regs *regs, long err) { static struct { @@ -225,7 +221,7 @@ int die(const char *str, struct pt_regs *regs, long err) do_show_stack(current, ®s->r30, pt_elr(regs)); bust_spinlocks(0); - add_taint(TAINT_DIE); + add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); spin_unlock_irq(&die.lock); @@ -324,6 +320,12 @@ void do_genex(struct pt_regs *regs) case HVM_GE_C_XMAL: misaligned_instruction(regs); break; + case HVM_GE_C_WREG: + illegal_instruction(regs); + break; + case HVM_GE_C_PCAL: + misaligned_instruction(regs); + break; case HVM_GE_C_RMAL: misaligned_data_load(regs); break; @@ -356,7 +358,6 @@ long sys_syscall(void) void do_trap0(struct pt_regs *regs) { - unsigned long syscallret = 0; syscall_fn syscall; switch (pt_cause(regs)) { @@ -396,21 +397,11 @@ void do_trap0(struct pt_regs *regs) } else { syscall = (syscall_fn) (sys_call_table[regs->syscall_nr]); - syscallret = syscall(regs->r00, regs->r01, + regs->r00 = syscall(regs->r00, regs->r01, regs->r02, regs->r03, regs->r04, regs->r05); } - /* - * If it was a sigreturn system call, don't overwrite - * r0 value in stack frame with return value. - * - * __NR_sigreturn doesn't seem to exist in new unistd.h - */ - - if (regs->syscall_nr != __NR_rt_sigreturn) - regs->r00 = syscallret; - /* allow strace to get the syscall return state */ if (unlikely(test_thread_flag(TIF_SYSCALL_TRACE))) tracehook_report_syscall_exit(regs, 0); @@ -452,3 +443,14 @@ void do_machcheck(struct pt_regs *regs) /* Halt and catch fire */ __vmstop(); } + +/* + * Treat this like the old 0xdb trap. + */ + +void do_debug_exception(struct pt_regs *regs) +{ + regs->hvmer.vmest &= ~HVM_VMEST_CAUSE_MSK; + regs->hvmer.vmest |= (TRAP_DEBUG << HVM_VMEST_CAUSE_SFT); + do_trap0(regs); +} diff --git a/arch/hexagon/kernel/vdso.c b/arch/hexagon/kernel/vdso.c index 16277c33308..0bf5a87e4d0 100644 --- a/arch/hexagon/kernel/vdso.c +++ b/arch/hexagon/kernel/vdso.c @@ -1,7 +1,7 @@ /* * vDSO implementation for Hexagon * - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -21,6 +21,7 @@ #include <linux/err.h> #include <linux/mm.h> #include <linux/vmalloc.h> +#include <linux/binfmts.h> #include <asm/vdso.h> @@ -78,8 +79,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) /* MAYWRITE to allow gdb to COW and set breakpoints. */ ret = install_special_mapping(mm, vdso_base, PAGE_SIZE, VM_READ|VM_EXEC| - VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| - VM_ALWAYSDUMP, + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, &vdso_page); if (ret) diff --git a/arch/hexagon/kernel/vm_entry.S b/arch/hexagon/kernel/vm_entry.S index 5b99066cbc8..67c6ccc1477 100644 --- a/arch/hexagon/kernel/vm_entry.S +++ b/arch/hexagon/kernel/vm_entry.S @@ -1,7 +1,7 @@ /* * Event entry/exit for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -45,48 +45,88 @@ * number in the case where we decode a system call (trap0(#1)). */ +#if CONFIG_HEXAGON_ARCH_VERSION < 4 #define save_pt_regs()\ - memd(R0 + #_PT_R3130) = R31:30; \ + memd(R0 + #_PT_R3130) = R31:30; \ + { memw(R0 + #_PT_R2928) = R28; \ + R31 = memw(R0 + #_PT_ER_VMPSP); }\ + { memw(R0 + #(_PT_R2928 + 4)) = R31; \ + R31 = ugp; } \ + { memd(R0 + #_PT_R2726) = R27:26; \ + R30 = gp ; } \ + memd(R0 + #_PT_R2524) = R25:24; \ + memd(R0 + #_PT_R2322) = R23:22; \ + memd(R0 + #_PT_R2120) = R21:20; \ + memd(R0 + #_PT_R1918) = R19:18; \ + memd(R0 + #_PT_R1716) = R17:16; \ + memd(R0 + #_PT_R1514) = R15:14; \ + memd(R0 + #_PT_R1312) = R13:12; \ + { memd(R0 + #_PT_R1110) = R11:10; \ + R15 = lc0; } \ + { memd(R0 + #_PT_R0908) = R9:8; \ + R14 = sa0; } \ + { memd(R0 + #_PT_R0706) = R7:6; \ + R13 = lc1; } \ + { memd(R0 + #_PT_R0504) = R5:4; \ + R12 = sa1; } \ + { memd(R0 + #_PT_GPUGP) = R31:30; \ + R11 = m1; \ + R2.H = #HI(_THREAD_SIZE); } \ + { memd(R0 + #_PT_LC0SA0) = R15:14; \ + R10 = m0; \ + R2.L = #LO(_THREAD_SIZE); } \ + { memd(R0 + #_PT_LC1SA1) = R13:12; \ + R15 = p3:0; \ + R2 = neg(R2); } \ + { memd(R0 + #_PT_M1M0) = R11:10; \ + R14 = usr; \ + R2 = and(R0,R2); } \ + { memd(R0 + #_PT_PREDSUSR) = R15:14; \ + THREADINFO_REG = R2; } \ + { r24 = memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS); \ + memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R0; \ + R2 = #-1; } \ + { memw(R0 + #_PT_SYSCALL_NR) = R2; \ + R30 = #0; } +#else +/* V4+ */ +/* the # ## # syntax inserts a literal ## */ +#define save_pt_regs()\ + { memd(R0 + #_PT_R3130) = R31:30; \ + R30 = memw(R0 + #_PT_ER_VMPSP); }\ { memw(R0 + #_PT_R2928) = R28; \ - R31 = memw(R0 + #_PT_ER_VMPSP); }\ - { memw(R0 + #(_PT_R2928 + 4)) = R31; \ - R31 = ugp; } \ - { memd(R0 + #_PT_R2726) = R27:26; \ - R30 = gp ; } \ - memd(R0 + #_PT_R2524) = R25:24; \ - memd(R0 + #_PT_R2322) = R23:22; \ - memd(R0 + #_PT_R2120) = R21:20; \ - memd(R0 + #_PT_R1918) = R19:18; \ - memd(R0 + #_PT_R1716) = R17:16; \ - memd(R0 + #_PT_R1514) = R15:14; \ - memd(R0 + #_PT_R1312) = R13:12; \ + memw(R0 + #(_PT_R2928 + 4)) = R30; }\ + { R31:30 = C11:10; \ + memd(R0 + #_PT_R2726) = R27:26; \ + memd(R0 + #_PT_R2524) = R25:24; }\ + { memd(R0 + #_PT_R2322) = R23:22; \ + memd(R0 + #_PT_R2120) = R21:20; }\ + { memd(R0 + #_PT_R1918) = R19:18; \ + memd(R0 + #_PT_R1716) = R17:16; }\ + { memd(R0 + #_PT_R1514) = R15:14; \ + memd(R0 + #_PT_R1312) = R13:12; \ + R17:16 = C13:12; }\ { memd(R0 + #_PT_R1110) = R11:10; \ - R15 = lc0; } \ - { memd(R0 + #_PT_R0908) = R9:8; \ - R14 = sa0; } \ + memd(R0 + #_PT_R0908) = R9:8; \ + R15:14 = C1:0; } \ { memd(R0 + #_PT_R0706) = R7:6; \ - R13 = lc1; } \ - { memd(R0 + #_PT_R0504) = R5:4; \ - R12 = sa1; } \ - { memd(R0 + #_PT_UGPGP) = R31:30; \ - R11 = m1; \ - R2.H = #HI(_THREAD_SIZE); } \ - { memd(R0 + #_PT_LC0SA0) = R15:14; \ - R10 = m0; \ - R2.L = #LO(_THREAD_SIZE); } \ - { memd(R0 + #_PT_LC1SA1) = R13:12; \ - R15 = p3:0; \ - R2 = neg(R2); } \ + memd(R0 + #_PT_R0504) = R5:4; \ + R13:12 = C3:2; } \ + { memd(R0 + #_PT_GPUGP) = R31:30; \ + memd(R0 + #_PT_LC0SA0) = R15:14; \ + R11:10 = C7:6; }\ + { THREADINFO_REG = and(R0, # ## #-_THREAD_SIZE); \ + memd(R0 + #_PT_LC1SA1) = R13:12; \ + R15 = p3:0; }\ { memd(R0 + #_PT_M1M0) = R11:10; \ - R14 = usr; \ - R2 = and(R0,R2); } \ - { memd(R0 + #_PT_PREDSUSR) = R15:14; \ - THREADINFO_REG = R2; } \ + memw(R0 + #_PT_PREDSUSR + 4) = R15; }\ { r24 = memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS); \ memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R0; \ R2 = #-1; } \ { memw(R0 + #_PT_SYSCALL_NR) = R2; \ + memd(R0 + #_PT_CS1CS0) = R17:16; \ R30 = #0; } +#endif /* * Restore registers and thread_info.regs state. THREADINFO_REG @@ -94,6 +134,7 @@ * preserved. Don't restore R29 (SP) until later. */ +#if CONFIG_HEXAGON_ARCH_VERSION < 4 #define restore_pt_regs() \ { memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R24; \ R15:14 = memd(R0 + #_PT_PREDSUSR); } \ @@ -121,11 +162,44 @@ R23:22 = memd(R0 + #_PT_R2322); } \ { R25:24 = memd(R0 + #_PT_R2524); \ R27:26 = memd(R0 + #_PT_R2726); } \ - R31:30 = memd(R0 + #_PT_UGPGP); \ + R31:30 = memd(R0 + #_PT_GPUGP); \ { R28 = memw(R0 + #_PT_R2928); \ ugp = R31; } \ { R31:30 = memd(R0 + #_PT_R3130); \ gp = R30; } +#else +/* V4+ */ +#define restore_pt_regs() \ + { memw(THREADINFO_REG + #_THREAD_INFO_PT_REGS) = R24; \ + R15:14 = memd(R0 + #_PT_PREDSUSR); } \ + { R11:10 = memd(R0 + #_PT_M1M0); \ + R13:12 = memd(R0 + #_PT_LC1SA1); \ + p3:0 = R15; } \ + { R15:14 = memd(R0 + #_PT_LC0SA0); \ + R3:2 = memd(R0 + #_PT_R0302); \ + usr = R14; } \ + { R5:4 = memd(R0 + #_PT_R0504); \ + R7:6 = memd(R0 + #_PT_R0706); \ + C7:6 = R11:10; }\ + { R9:8 = memd(R0 + #_PT_R0908); \ + R11:10 = memd(R0 + #_PT_R1110); \ + C3:2 = R13:12; }\ + { R13:12 = memd(R0 + #_PT_R1312); \ + R15:14 = memd(R0 + #_PT_R1514); \ + C1:0 = R15:14; }\ + { R17:16 = memd(R0 + #_PT_R1716); \ + R19:18 = memd(R0 + #_PT_R1918); } \ + { R21:20 = memd(R0 + #_PT_R2120); \ + R23:22 = memd(R0 + #_PT_R2322); } \ + { R25:24 = memd(R0 + #_PT_R2524); \ + R27:26 = memd(R0 + #_PT_R2726); } \ + R31:30 = memd(R0 + #_PT_CS1CS0); \ + { C13:12 = R31:30; \ + R31:30 = memd(R0 + #_PT_GPUGP) ; \ + R28 = memw(R0 + #_PT_R2928); }\ + { C11:10 = R31:30; \ + R31:30 = memd(R0 + #_PT_R3130); } +#endif /* * Clears off enough space for the rest of pt_regs; evrec is a part @@ -139,6 +213,7 @@ * Need to save off R0, R1, R2, R3 immediately. */ +#if CONFIG_HEXAGON_ARCH_VERSION < 4 #define vm_event_entry(CHandler) \ { \ R29 = add(R29, #-(_PT_REGS_SIZE)); \ @@ -158,6 +233,34 @@ R1.H = #HI(CHandler); \ jump event_dispatch; \ } +#else +/* V4+ */ +/* turn on I$ prefetch early */ +/* the # ## # syntax inserts a literal ## */ +#define vm_event_entry(CHandler) \ + { \ + R29 = add(R29, #-(_PT_REGS_SIZE)); \ + memd(R29 + #(_PT_R0100 + -_PT_REGS_SIZE)) = R1:0; \ + memd(R29 + #(_PT_R0302 + -_PT_REGS_SIZE)) = R3:2; \ + R0 = usr; \ + } \ + { \ + memw(R29 + #_PT_PREDSUSR) = R0; \ + R0 = setbit(R0, #16); \ + } \ + usr = R0; \ + R1:0 = G1:0; \ + { \ + memd(R29 + #_PT_ER_VMEL) = R1:0; \ + R1 = # ## #(CHandler); \ + R3:2 = G3:2; \ + } \ + { \ + R0 = R29; \ + memd(R29 + #_PT_ER_VMPSP) = R3:2; \ + jump event_dispatch; \ + } +#endif .text /* @@ -171,6 +274,9 @@ event_dispatch: callr r1 /* + * Coming back from the C-world, our thread info pointer + * should be in the designated register (usually R19) + * * If we were in kernel mode, we don't need to check scheduler * or signals if CONFIG_PREEMPT is not set. If set, then it has * to jump to a need_resched kind of block. @@ -183,69 +289,68 @@ event_dispatch: #endif /* "Nested control path" -- if the previous mode was kernel */ - R0 = memw(R29 + #_PT_ER_VMEST); - P0 = tstbit(R0, #HVM_VMEST_UM_SFT); - if !P0 jump restore_all; - /* - * Returning from system call, normally coming back from user mode - */ -return_from_syscall: - /* Disable interrupts while checking TIF */ - R0 = #VM_INT_DISABLE - trap1(#HVM_TRAP1_VMSETIE) - - /* - * Coming back from the C-world, our thread info pointer - * should be in the designated register (usually R19) - */ - R1.L = #LO(_TIF_ALLWORK_MASK) { - R1.H = #HI(_TIF_ALLWORK_MASK); - R0 = memw(THREADINFO_REG + #_THREAD_INFO_FLAGS); + R0 = memw(R29 + #_PT_ER_VMEST); + R26.L = #LO(do_work_pending); + } + { + P0 = tstbit(R0, #HVM_VMEST_UM_SFT); + if (!P0.new) jump:nt restore_all; + R26.H = #HI(do_work_pending); + R0 = #VM_INT_DISABLE; } /* - * Compare against the "return to userspace" _TIF_WORK_MASK + * Check also the return from fork/system call, normally coming back from + * user mode + * + * R26 needs to have do_work_pending, and R0 should have VM_INT_DISABLE */ - R1 = and(R1,R0); - { P0 = cmp.eq(R1,#0); if (!P0.new) jump:t work_pending;} - jump restore_all; /* we're outta here! */ -work_pending: +check_work_pending: + /* Disable interrupts while checking TIF */ + trap1(#HVM_TRAP1_VMSETIE) { - P0 = tstbit(R1, #TIF_NEED_RESCHED); - if (!P0.new) jump:nt work_notifysig; + R0 = R29; /* regs should still be at top of stack */ + R1 = memw(THREADINFO_REG + #_THREAD_INFO_FLAGS); + callr R26; } - call schedule - jump return_from_syscall; /* check for more work */ -work_notifysig: - /* this is the part that's kind of fuzzy. */ - R1 = and(R0, #(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME)); - P0 = cmp.eq(R1, #0); - if P0 jump restore_all - R1 = R0; /* unsigned long thread_info_flags */ - R0 = R29; /* regs should still be at top of stack */ - call do_notify_resume + { + P0 = cmp.eq(R0, #0); if (!P0.new) jump:nt check_work_pending; + R0 = #VM_INT_DISABLE; + } restore_all: - /* Disable interrupts, if they weren't already, before reg restore. */ - R0 = #VM_INT_DISABLE + /* + * Disable interrupts, if they weren't already, before reg restore. + * R0 gets preloaded with #VM_INT_DISABLE before we get here. + */ trap1(#HVM_TRAP1_VMSETIE) /* do the setregs here for VM 0.5 */ /* R29 here should already be pointing at pt_regs */ - R1:0 = memd(R29 + #_PT_ER_VMEL); - R3:2 = memd(R29 + #_PT_ER_VMPSP); + { + R1:0 = memd(R29 + #_PT_ER_VMEL); + R3:2 = memd(R29 + #_PT_ER_VMPSP); + } +#if CONFIG_HEXAGON_ARCH_VERSION < 4 trap1(#HVM_TRAP1_VMSETREGS); +#else + G1:0 = R1:0; + G3:2 = R3:2; +#endif R0 = R29 restore_pt_regs() - R1:0 = memd(R29 + #_PT_R0100); - R29 = add(R29, #_PT_REGS_SIZE); + { + R1:0 = memd(R29 + #_PT_R0100); + R29 = add(R29, #_PT_REGS_SIZE); + } trap1(#HVM_TRAP1_VMRTE) /* Notreached */ + .globl _K_enter_genex _K_enter_genex: vm_event_entry(do_genex) @@ -262,8 +367,27 @@ _K_enter_trap0: _K_enter_machcheck: vm_event_entry(do_machcheck) + .globl _K_enter_debug +_K_enter_debug: + vm_event_entry(do_debug_exception) .globl ret_from_fork ret_from_fork: - call schedule_tail - jump return_from_syscall + { + call schedule_tail + R26.H = #HI(do_work_pending); + } + { + P0 = cmp.eq(R24, #0); + R26.L = #LO(do_work_pending); + R0 = #VM_INT_DISABLE; + } + if P0 jump check_work_pending + { + R0 = R25; + callr R24 + } + { + jump check_work_pending + R0 = #VM_INT_DISABLE; + } diff --git a/arch/hexagon/kernel/vm_events.c b/arch/hexagon/kernel/vm_events.c index 986a081e32e..741aaa917cd 100644 --- a/arch/hexagon/kernel/vm_events.c +++ b/arch/hexagon/kernel/vm_events.c @@ -1,7 +1,7 @@ /* * Mostly IRQ support for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,7 +22,6 @@ #include <asm/registers.h> #include <linux/irq.h> #include <linux/hardirq.h> -#include <asm/system.h> /* * show_regs - print pt_regs structure @@ -34,6 +33,8 @@ */ void show_regs(struct pt_regs *regs) { + show_regs_print_info(KERN_EMERG); + printk(KERN_EMERG "restart_r0: \t0x%08lx syscall_nr: %ld\n", regs->restart_r0, regs->syscall_nr); printk(KERN_EMERG "preds: \t\t0x%08lx\n", regs->preds); @@ -43,6 +44,8 @@ void show_regs(struct pt_regs *regs) regs->lc1, regs->sa1, regs->m1); printk(KERN_EMERG "gp: \t0x%08lx ugp: 0x%08lx usr: 0x%08lx\n", regs->gp, regs->ugp, regs->usr); + printk(KERN_EMERG "cs0: \t0x%08lx cs1: 0x%08lx\n", + regs->cs0, regs->cs1); printk(KERN_EMERG "r0: \t0x%08lx %08lx %08lx %08lx\n", regs->r00, regs->r01, regs->r02, diff --git a/arch/hexagon/kernel/vm_init_segtable.S b/arch/hexagon/kernel/vm_init_segtable.S index aebb35b6465..80967f2192b 100644 --- a/arch/hexagon/kernel/vm_init_segtable.S +++ b/arch/hexagon/kernel/vm_init_segtable.S @@ -1,7 +1,7 @@ /* * Initial page table for Linux kernel under Hexagon VM, * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/vm_ops.S b/arch/hexagon/kernel/vm_ops.S index 24d7fcac4ff..9fb77b3f6cf 100644 --- a/arch/hexagon/kernel/vm_ops.S +++ b/arch/hexagon/kernel/vm_ops.S @@ -1,7 +1,7 @@ /* * Hexagon VM instruction support * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/vm_switch.S b/arch/hexagon/kernel/vm_switch.S index 0decf2f58e3..62c6df91b3b 100644 --- a/arch/hexagon/kernel/vm_switch.S +++ b/arch/hexagon/kernel/vm_switch.S @@ -1,7 +1,7 @@ /* * Context switch support for Hexagon * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/arch/hexagon/kernel/vm_vectors.S b/arch/hexagon/kernel/vm_vectors.S index 97a4b50b00d..791a7422dde 100644 --- a/arch/hexagon/kernel/vm_vectors.S +++ b/arch/hexagon/kernel/vm_vectors.S @@ -1,7 +1,7 @@ /* * Event jump tables * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2012,2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -41,7 +41,7 @@ _K_VM_event_vector: jump 1b; /* Reset */ jump _K_enter_machcheck; jump _K_enter_genex; - jump 1b; /* 3 Rsvd */ + jump _K_enter_debug; jump 1b; /* 4 Rsvd */ jump _K_enter_trap0; jump 1b; /* 6 Rsvd */ diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S index 071d3c30edf..44d8c47bae2 100644 --- a/arch/hexagon/kernel/vmlinux.lds.S +++ b/arch/hexagon/kernel/vmlinux.lds.S @@ -1,7 +1,7 @@ /* * Linker script for Hexagon kernel * - * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,8 +18,6 @@ * 02110-1301, USA. */ -#define LOAD_OFFSET PAGE_OFFSET - #include <asm-generic/vmlinux.lds.h> #include <asm/asm-offsets.h> /* Most of the kernel defines are here */ #include <asm/mem-layout.h> /* except for page_offset */ @@ -36,13 +34,9 @@ See asm-generic/sections.h for seemingly required labels. #define PAGE_SIZE _PAGE_SIZE -/* This LOAD_OFFSET is temporary for debugging on the simulator; it may change - for hypervisor pseudo-physical memory. */ - - SECTIONS { - . = PAGE_OFFSET + LOAD_ADDRESS; + . = PAGE_OFFSET; __init_begin = .; HEAD_TEXT_SECTION @@ -52,7 +46,7 @@ SECTIONS . = ALIGN(_PAGE_SIZE); _stext = .; - .text : AT(ADDR(.text) - LOAD_OFFSET) { + .text : AT(ADDR(.text)) { _text = .; TEXT_TEXT SCHED_TEXT |
