diff options
Diffstat (limited to 'target/linux/ubicom32/files/arch/ubicom32/kernel')
34 files changed, 0 insertions, 10907 deletions
diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile b/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile deleted file mode 100644 index 6294fa2eaa..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/Makefile +++ /dev/null @@ -1,64 +0,0 @@ -# -# arch/ubicom32/kernel/Makefile -# Main Makefile for the Ubicom32 arch directory. -# -# (C) Copyright 2009, Ubicom, Inc. -# -# This file is part of the Ubicom32 Linux Kernel Port. -# -# The Ubicom32 Linux Kernel Port is free software: you can redistribute -# it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation, either version 2 of the -# License, or (at your option) any later version. -# -# The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, -# see <http://www.gnu.org/licenses/>. -# -# Ubicom32 implementation derived from (with many thanks): -# arch/m68knommu -# arch/blackfin -# arch/parisc -# - -extra-y := head.o vmlinux.lds - -obj-y += \ - devtree.o \ - dma.o \ - flat.o \ - init_task.o \ - irq.o \ - ldsr.o \ - os_node.o \ - process.o \ - processor.o \ - ptrace.o \ - setup.o \ - signal.o \ - stacktrace.o \ - sys_ubicom32.o \ - syscalltable.o \ - thread.o \ - time.o \ - traps.o \ - ubicom32_context_switch.o \ - ubicom32_ksyms.o \ - ubicom32_syscall.o \ - unaligned_trap.o - -obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_COMEMPCI) += comempci.o -obj-$(CONFIG_SMP) += smp.o topology.o -obj-$(CONFIG_ACCESS_OK_CHECKS_ENABLED) += uaccess.o -obj-$(CONFIG_GENERIC_CLOCKEVENTS) += timer_device.o -obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += timer_broadcast.o - -ifndef CONFIG_GENERIC_CLOCKEVENTS -obj-y += timer_tick.o -endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c deleted file mode 100644 index 639a536a18..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/asm-offsets.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * arch/ubicom32/kernel/asm-offsets.c - * Ubicom32 architecture definitions needed by assembly language modules. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -/* - * This program is used to generate definitions needed by - * assembly language modules. - * - * We use the technique used in the OSF Mach kernel code: - * generate asm statements containing #defines, - * compile this file to assembler, and then extract the - * #defines from the assembly-language output. - */ - -#include <linux/module.h> -#include <linux/stddef.h> -#include <linux/sched.h> -#include <linux/kernel_stat.h> -#include <linux/ptrace.h> -#include <linux/hardirq.h> -#include <asm/bootinfo.h> -#include <asm/irq.h> -#include <asm/thread_info.h> - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define BLANK() asm volatile("\n->" : : ) - -int main(void) -{ - /* offsets into the task struct */ - DEFINE(TASK_STATE, offsetof(struct task_struct, state)); - DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); - DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); - DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); - DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); - DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack)); - DEFINE(TASK_MM, offsetof(struct task_struct, mm)); - DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); - - /* offsets into the kernel_stat struct */ -// DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); - - /* offsets into the irq_cpustat_t struct */ - DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); - - /* offsets into the thread struct */ - DEFINE(THREAD_D10, offsetof(struct thread_struct, d10)); - DEFINE(THREAD_D11, offsetof(struct thread_struct, d11)); - DEFINE(THREAD_D12, offsetof(struct thread_struct, d12)); - DEFINE(THREAD_D13, offsetof(struct thread_struct, d13)); - DEFINE(THREAD_A1, offsetof(struct thread_struct, a1)); - DEFINE(THREAD_A2, offsetof(struct thread_struct, a2)); - DEFINE(THREAD_A5, offsetof(struct thread_struct, a5)); - DEFINE(THREAD_A6, offsetof(struct thread_struct, a6)); - DEFINE(THREAD_SP, offsetof(struct thread_struct, sp)); - - /* offsets into the pt_regs */ - DEFINE(PT_D0, offsetof(struct pt_regs, dn[0])); - DEFINE(PT_D1, offsetof(struct pt_regs, dn[1])); - DEFINE(PT_D2, offsetof(struct pt_regs, dn[2])); - DEFINE(PT_D3, offsetof(struct pt_regs, dn[3])); - DEFINE(PT_D4, offsetof(struct pt_regs, dn[4])); - DEFINE(PT_D5, offsetof(struct pt_regs, dn[5])); - DEFINE(PT_D6, offsetof(struct pt_regs, dn[6])); - DEFINE(PT_D7, offsetof(struct pt_regs, dn[7])); - DEFINE(PT_D8, offsetof(struct pt_regs, dn[8])); - DEFINE(PT_D9, offsetof(struct pt_regs, dn[9])); - DEFINE(PT_D10, offsetof(struct pt_regs, dn[10])); - DEFINE(PT_D11, offsetof(struct pt_regs, dn[11])); - DEFINE(PT_D12, offsetof(struct pt_regs, dn[12])); - DEFINE(PT_D13, offsetof(struct pt_regs, dn[13])); - DEFINE(PT_D14, offsetof(struct pt_regs, dn[14])); - DEFINE(PT_D15, offsetof(struct pt_regs, dn[15])); - DEFINE(PT_A0, offsetof(struct pt_regs, an[0])); - DEFINE(PT_A1, offsetof(struct pt_regs, an[1])); - DEFINE(PT_A2, offsetof(struct pt_regs, an[2])); - DEFINE(PT_A3, offsetof(struct pt_regs, an[3])); - DEFINE(PT_A4, offsetof(struct pt_regs, an[4])); - DEFINE(PT_A5, offsetof(struct pt_regs, an[5])); - DEFINE(PT_A6, offsetof(struct pt_regs, an[6])); - DEFINE(PT_A7, offsetof(struct pt_regs, an[7])); - DEFINE(PT_SP, offsetof(struct pt_regs, an[7])); - - DEFINE(PT_ACC0HI, offsetof(struct pt_regs, acc0[0])); - DEFINE(PT_ACC0LO, offsetof(struct pt_regs, acc0[1])); - DEFINE(PT_MAC_RC16, offsetof(struct pt_regs, mac_rc16)); - - DEFINE(PT_ACC1HI, offsetof(struct pt_regs, acc1[0])); - DEFINE(PT_ACC1LO, offsetof(struct pt_regs, acc1[1])); - - DEFINE(PT_SOURCE3, offsetof(struct pt_regs, source3)); - DEFINE(PT_INST_CNT, offsetof(struct pt_regs, inst_cnt)); - DEFINE(PT_CSR, offsetof(struct pt_regs, csr)); - DEFINE(PT_DUMMY_UNUSED, offsetof(struct pt_regs, dummy_unused)); - - DEFINE(PT_INT_MASK0, offsetof(struct pt_regs, int_mask0)); - DEFINE(PT_INT_MASK1, offsetof(struct pt_regs, int_mask1)); - - DEFINE(PT_PC, offsetof(struct pt_regs, pc)); - - DEFINE(PT_TRAP_CAUSE, offsetof(struct pt_regs, trap_cause)); - - DEFINE(PT_SIZE, sizeof(struct pt_regs)); - - DEFINE(PT_FRAME_TYPE, offsetof(struct pt_regs, frame_type)); - - DEFINE(PT_ORIGINAL_D0, offsetof(struct pt_regs, original_dn_0)); - DEFINE(PT_PREVIOUS_PC, offsetof(struct pt_regs, previous_pc)); - - /* offsets into the kernel_stat struct */ -// DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); - - /* signal defines */ - DEFINE(SIGSEGV, SIGSEGV); - //DEFINE(SEGV_MAPERR, SEGV_MAPERR); - DEFINE(SIGTRAP, SIGTRAP); - //DEFINE(TRAP_TRACE, TRAP_TRACE); - - DEFINE(PT_PTRACED, PT_PTRACED); - DEFINE(PT_DTRACE, PT_DTRACE); - - DEFINE(ASM_THREAD_SIZE, THREAD_SIZE); - - /* Offsets in thread_info structure */ - DEFINE(TI_TASK, offsetof(struct thread_info, task)); - DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); - DEFINE(TI_INTR_NESTING, offsetof(struct thread_info, interrupt_nesting)); - DEFINE(ASM_TIF_NEED_RESCHED, TIF_NEED_RESCHED); - DEFINE(ASM_TIF_SYSCALL_TRACE, TIF_SYSCALL_TRACE); - DEFINE(ASM_TIF_SIGPENDING, TIF_SIGPENDING); - - return 0; -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c deleted file mode 100644 index 1f824d2f15..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/devtree.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * arch/ubicom32/kernel/devtree.c - * Ubicom32 architecture device tree implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <asm/devtree.h> - -/* - * The device tree. - */ -struct devtree_node *devtree; - -/* - * devtree_print() - * Print the device tree. - */ -void devtree_print(void) -{ - struct devtree_node *p = devtree; - printk(KERN_INFO "Device Tree:\n"); - while (p) { - if (p->magic != DEVTREE_NODE_MAGIC) { - printk(KERN_EMERG - "device tree has improper node: %p\n", p); - return; - } - printk(KERN_INFO "\t%p: sendirq=%03d, recvirq=%03d, " - " name=%s\n", p, p->sendirq, p->recvirq, p->name); - p = p->next; - } -} -EXPORT_SYMBOL(devtree_print); - -/* - * devtree_irq() - * Return the IRQ(s) associated with devtree node. - */ -int devtree_irq(struct devtree_node *dn, - unsigned char *sendirq, - unsigned char *recvirq) -{ - if (dn->magic != DEVTREE_NODE_MAGIC) { - printk(KERN_EMERG "improper node: %p\n", dn); - if (sendirq) { - *sendirq = DEVTREE_IRQ_NONE; - } - if (recvirq) { - *recvirq = DEVTREE_IRQ_NONE; - } - return -EFAULT; - } - - /* - * Copy the devtree irq(s) to the output parameters. - */ - if (sendirq) { - *sendirq = dn->sendirq; - } - if (recvirq) { - *recvirq = dn->recvirq; - } - return 0; -} -EXPORT_SYMBOL(devtree_irq); - -/* - * devtree_find_next() - * Provide an iterator for walking the device tree. - */ -struct devtree_node *devtree_find_next(struct devtree_node **cur) -{ - struct devtree_node *p = *cur; - if (!p) { - *cur = devtree; - return devtree; - } - p = p->next; - *cur = p; - return p; -} - -/* - * devtree_find_by_irq() - * Return the node associated with a given irq. - */ -struct devtree_node *devtree_find_by_irq(uint8_t sendirq, uint8_t recvirq) -{ - struct devtree_node *p = devtree; - - if (sendirq == recvirq) { - printk(KERN_EMERG "identical request makes no sense sendirq = " - "%d, recvirq= %d\n", sendirq, recvirq); - return NULL; - } - - while (p) { - if (p->magic != DEVTREE_NODE_MAGIC) { - printk(KERN_EMERG - "device tree has improper node: %p\n", p); - return NULL; - } - - /* - * See if we can find a match on the IRQ(s) specified. - */ - if ((sendirq == p->sendirq) && (recvirq == p->recvirq)) { - return p; - } - - if ((sendirq == DEVTREE_IRQ_DONTCARE) && - (p->recvirq == recvirq)) { - return p; - } - - if ((recvirq == DEVTREE_IRQ_DONTCARE) && - (p->sendirq == sendirq)) { - return p; - } - - p = p->next; - } - return NULL; -} -EXPORT_SYMBOL(devtree_find_by_irq); - -/* - * devtree_find_node() - * Find a node in the device tree by name. - */ -struct devtree_node *devtree_find_node(const char *str) -{ - struct devtree_node *p = devtree; - while (p) { - if (p->magic != DEVTREE_NODE_MAGIC) { - printk(KERN_EMERG - "device tree has improper node: %p\n", p); - return NULL; - } - if (strcmp(p->name, str) == 0) { - return p; - } - p = p->next; - } - return NULL; -} -EXPORT_SYMBOL(devtree_find_node); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c deleted file mode 100644 index f61810532a..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/dma.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * arch/ubicom32/kernel/dma.c - * Ubicom32 architecture dynamic DMA mapping support. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - * - * We never have any address translations to worry about, so this - * is just alloc/free. - */ - -#include <linux/types.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/device.h> -#include <linux/io.h> - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int gfp) -{ - void *ret; - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (dev == NULL || (*dev->dma_mask < 0xffffffff)) - gfp |= GFP_DMA; - ret = (void *)__get_free_pages(gfp, get_order(size)); - - if (ret != NULL) { - memset(ret, 0, size); - *dma_handle = virt_to_phys(ret); - } - return ret; -} - -void dma_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c deleted file mode 100644 index e8eb4595f1..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/flat.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * arch/ubicom32/kernel/flat.c - * Ubicom32 architecture flat executable format support. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/flat.h> - -unsigned long ubicom32_flat_get_addr_from_rp(unsigned long *rp, - u32_t relval, - u32_t flags, - unsigned long *persistent) -{ - u32_t relval_reloc_type = relval >> 27; - u32_t insn = *rp; - - if (*persistent) { - /* - * relval holds the relocation that has to be adjusted. - */ - if (relval == 0) { - *persistent = 0; - } - - return relval; - } - - if (relval_reloc_type == R_UBICOM32_32) { - /* - * insn holds the relocation - */ - return insn; - } - - /* - * We don't know this one. - */ - return 0; -} - -void ubicom32_flat_put_addr_at_rp(unsigned long *rp, - u32_t val, - u32_t relval, - unsigned long *persistent) -{ - u32_t reloc_type = (relval >> 27) & 0x1f; - u32_t insn = *rp; - - /* - * If persistent is set then it contains the relocation type. - */ - if (*persistent) { - /* - * If persistent is set then it contains the relocation type. - */ - reloc_type = (*persistent >> 27) & 0x1f; - } - - switch (reloc_type) { - case R_UBICOM32_32: - /* - * Store the 32 bits as is. - */ - *rp = val; - break; - case R_UBICOM32_HI24: - { - /* - * 24 bit relocation that is part of the MOVEAI - * instruction. The 24 bits come from bits 7 - 30 of the - * relocation. The 24 bits eventually get split into 2 - * fields in the instruction encoding. - * - * - Bits 7 - 27 of the relocation are encoded into bits - * 0 - 20 of the instruction. - * - * - Bits 28 - 30 of the relocation are encoded into bit - * 24 - 26 of the instruction. - */ - u32_t mask = 0x1fffff | (0x7 << 24); - u32_t valid24bits = (val >> 7) & 0xffffff; - u32_t bot_21 = valid24bits & 0x1fffff; - u32_t upper_3_bits = ((valid24bits & 0xe00000) << 3); - insn &= ~mask; - - insn |= bot_21; - insn |= upper_3_bits; - *rp = insn; - } - break; - case R_UBICOM32_LO7_S: - case R_UBICOM32_LO7_2_S: - case R_UBICOM32_LO7_4_S: - { - /* - * Bits 0 - 6 of the relocation are encoded into the - * 7bit unsigned immediate fields of the SOURCE-1 field - * of the instruction. The immediate value is left - * shifted by (0, 1, 2) based on the operand size. - */ - u32_t mask = 0x1f | (0x3 << 8); - u32_t bottom, top; - val &= 0x7f; - if (reloc_type == R_UBICOM32_LO7_2_S) { - val >>= 1; - } else if (reloc_type == R_UBICOM32_LO7_4_S) { - val >>= 2; - } - - bottom = val & 0x1f; - top = val >> 5; - insn &= ~mask; - insn |= bottom; - insn |= (top << 8); - BUG_ON(*rp != insn); - *rp = insn; - break; - } - case R_UBICOM32_LO7_D: - case R_UBICOM32_LO7_2_D: - case R_UBICOM32_LO7_4_D: - { - /* - * Bits 0 - 6 of the relocation are encoded into the - * 7bit unsigned immediate fields of the DESTINATION - * field of the instruction. The immediate value is - * left shifted by (0, 1, 2) based on the operand size. - */ - u32_t mask = (0x1f | (0x3 << 8)) << 16; - u32_t bottom, top; - val &= 0x7f; - if (reloc_type == R_UBICOM32_LO7_2_D) { - val >>= 1; - } else if (reloc_type == R_UBICOM32_LO7_4_D) { - val >>= 2; - } - bottom = (val & 0x1f) << 16; - top = (val >> 5) << 16; - insn &= ~mask; - insn |= bottom; - insn |= (top << 8); - BUG_ON(*rp != insn); - *rp = insn; - break; - } - case R_UBICOM32_LO7_CALLI: - case R_UBICOM32_LO16_CALLI: - { - /* - * Extract the offset for a CALLI instruction. The - * offsets can be either 7 bits or 18 bits. Since all - * instructions in ubicom32 architecture are at work - * aligned addresses the truncated offset is right - * shifted by 2 before being encoded in the instruction. - */ - if (reloc_type == R_UBICOM32_LO7_CALLI) { - val &= 0x7f; - } else { - val &= 0x3ffff; - } - - val >>= 2; - - insn &= ~0x071f071f; - insn |= (val & 0x1f) << 0; - val >>= 5; - insn |= (val & 0x07) << 8; - val >>= 3; - insn |= (val & 0x1f) << 16; - val >>= 5; - insn |= (val & 0x07) << 24; - if (reloc_type == R_UBICOM32_LO7_CALLI) { - BUG_ON(*rp != insn); - } - *rp = insn; - } - break; - } - - if (*persistent) { - *persistent = 0; - } -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S deleted file mode 100644 index 0c60504af5..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/head.S +++ /dev/null @@ -1,273 +0,0 @@ -/* - * arch/ubicom32/kernel/head.S - * <TODO: Replace with short file description> - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/sys.h> -#include <linux/linkage.h> -#include <asm/asm-offsets.h> -#include <asm/page_offset.h> -#define __ASM__ -#include <asm/ip5000.h> - - -#define SRC_AN A3 -#define DST_AN A4 - -#define PARAM_DN D0 -#define TMP_DN D15 -#define TMP2_DN D14 - -/* - * The following code is placed at the start of the Linux section of memory. - * This is the primary entry point for Linux. - * - * However, we also want the syscall entry/exit code to be at a fixed address. - * So we take the primary entry point and reserve 16 bytes. That address is - * where the system_call entry point exists. This 16 bytes basically allows - * us to jump around the system_call entry point code to the actual startup - * code. - * - * Linux Memory Map (see vlinux.lds.S): - * 0x40400000 - Primary Entry Point for Linux (jump around code below). - * 0x40400010 - Old syscall Entry Point. - */ - - .sect .skip_syscall, "ax", @progbits - .global __skip_syscall_section -__skip_syscall_section: - moveai A3, #%hi(_start) - lea.1 A3, %lo(_start)(A3) - ret A3 -/* - * __os_node_offset contains the offset from KERNELBASE to the os_node, it is - * not intended to be used by anything except the boot code. - */ -__os_node_offset: -.long (_os_node - KERNELSTART) - -.text -.global _start - -/* - * start() - * This is the start of the Linux kernel. - */ -_start: - move.4 SCRATCHPAD1, #0 - - -/* - * Setup the range registers... the loader has setup a few, but we will go ahead - * and correct them for our own limits. Note that once set these are never - * changed again. The ranges are as follows - * - * D_RANGE0 - io block (set up by loaded) - * - * I_RANGE0 and D_RANGE1 - kernel/ultra loader address space bottom of ocm-> top - * of ram typically 0x3ffc0000 - 0x440000000 - * I_RANGE1 - kernel / userspace transition area (aka syscalls, context switches) - * typically 0x3FFC0030 - ~0x3FFC0200 - * I_RANGE2 / D_RANGE2 - slab area - * typically 0x40A00000 - ~0x44000000 - * I_RANGE3 - * old system call interface if enabled. - * - * D_RANGE3, D_RANGE4 - unused. - */ - moveai SRC_AN, #%hi(PAGE_OFFSET_RAW) - lea.4 SRC_AN, %lo(PAGE_OFFSET_RAW)(SRC_AN) - move.4 D_RANGE1_LO, SRC_AN - move.4 I_RANGE0_LO, SRC_AN - -; don't try to calculate I_RANGE_HI, see below -; moveai SRC_AN, #%hi(___init_end-4) -; lea.4 SRC_AN, %lo(___init_end-4)(SRC_AN) -; move.4 I_RANGE0_HI, SRC_AN - - moveai SRC_AN, #%hi(SDRAMSTART + CONFIG_MIN_RAMSIZE-4) - lea.4 SRC_AN, %lo(SDRAMSTART + CONFIG_MIN_RAMSIZE-4)(SRC_AN) - move.4 D_RANGE1_HI, SRC_AN - -; for now allow the whole ram to be executable as well so we don't run into problems -; once we load user more code. - move.4 I_RANGE0_HI, SRC_AN - -#ifdef CONFIG_PROTECT_KERNEL -; when kernel protection is enabled, we only open up syscall and non kernel text -; for userspace apps, for now only irange registers registers 1 and 2 are used for userspace. - - ;; syscall range - moveai SRC_AN, #%hi(__syscall_text_run_begin) - lea.4 SRC_AN, %lo(__syscall_text_run_begin)(SRC_AN) - move.4 I_RANGE1_LO, SRC_AN - moveai SRC_AN, #%hi(__syscall_text_run_end) - lea.4 SRC_AN, %lo(__syscall_text_run_end)(SRC_AN) - move.4 I_RANGE1_HI, SRC_AN - - ;; slab instructions - moveai SRC_AN, #%hi(_edata) - lea.4 SRC_AN, %lo(_edata)(SRC_AN) - move.4 I_RANGE2_LO, SRC_AN - ;; End of DDR is already in range0 hi so just copy it. - move.4 I_RANGE2_HI, I_RANGE0_HI - -#ifdef CONFIG_OLD_40400010_SYSTEM_CALL - ;; create a small hole for old syscall location - moveai SRC_AN, #%hi(0x40400000) - lea.4 I_RANGE3_LO, 0x10(SRC_AN) - lea.4 I_RANGE3_HI, 0x14(SRC_AN) -#endif - ;; slab data (same as slab instructions but starting a little earlier). - moveai SRC_AN, #%hi(_data_protection_end) - lea.4 SRC_AN, %lo(_data_protection_end)(SRC_AN) - move.4 D_RANGE2_LO, SRC_AN - move.4 D_RANGE2_HI, I_RANGE0_HI - -;; enable ranges - ;; skip I_RANGE0_EN - move.4 I_RANGE1_EN, #-1 - move.4 I_RANGE2_EN, #-1 -#ifdef CONFIG_OLD_40400010_SYSTEM_CALL - move.4 I_RANGE3_EN, #-1 -#else - move.4 I_RANGE3_EN, #0 -#endif - ;; skip D_RANGE0_EN or D_RANGE1_EN - move.4 D_RANGE2_EN, #-1 - move.4 D_RANGE3_EN, #0 - move.4 D_RANGE4_EN, #0 -#endif - -; -; If __ocm_free_begin is smaller than __ocm_free_end the -; setup OCM text and data ram banks properly -; - moveai DST_AN, #%hi(__ocm_free_begin) - lea.4 TMP_DN, %lo(__ocm_free_begin)(DST_AN) - moveai DST_AN, #%hi(__ocm_free_end) - lea.4 TMP2_DN, %lo(__ocm_free_end)(DST_AN) - sub.4 #0, TMP2_DN, TMP_DN - jmple.f 2f - moveai DST_AN, #%hi(__data_begin) - lea.4 TMP_DN, %lo(__data_begin)(DST_AN) - moveai DST_AN, #%hi(OCMSTART) - lea.4 TMP2_DN, %lo(OCMSTART)(DST_AN) - sub.4 TMP_DN, TMP_DN, TMP2_DN - lsr.4 TMP_DN, TMP_DN, #15 - lsl.4 TMP_DN, #1, TMP_DN - moveai DST_AN, #%hi(OCMC_BASE) - add.4 OCMC_BANK_MASK(DST_AN), #-1, TMP_DN - pipe_flush 0 -2: -; -; Load .ocm_text -; - moveai DST_AN, #%hi(__ocm_text_run_end) - lea.4 TMP_DN, %lo(__ocm_text_run_end)(DST_AN) - moveai DST_AN, #%hi(__ocm_text_run_begin) - lea.4 DST_AN, %lo(__ocm_text_run_begin)(DST_AN) - moveai SRC_AN, #%hi(__ocm_text_load_begin) - lea.4 SRC_AN, %lo(__ocm_text_load_begin)(SRC_AN) - jmpt.t 2f - -1: move.4 (DST_AN)4++, (SRC_AN)4++ - -2: sub.4 #0, DST_AN, TMP_DN - jmpne.t 1b -; -; Load .syscall_text -; - moveai DST_AN, #%hi(__syscall_text_run_end) - lea.4 TMP_DN, %lo(__syscall_text_run_end)(DST_AN) - moveai DST_AN, #%hi(__syscall_text_run_begin) - lea.4 DST_AN, %lo(__syscall_text_run_begin)(DST_AN) - moveai SRC_AN, #%hi(__syscall_text_load_begin) - lea.4 SRC_AN, %lo(__syscall_text_load_begin)(SRC_AN) - jmpt.t 2f - -1: move.4 (DST_AN)4++, (SRC_AN)4++ - -2: sub.4 #0, DST_AN, TMP_DN - jmpne.t 1b - -; -; Load .ocm_data -; - moveai DST_AN, #%hi(__ocm_data_run_end) - lea.4 TMP_DN, %lo(__ocm_data_run_end)(DST_AN) - moveai DST_AN, #%hi(__ocm_data_run_begin) - lea.4 DST_AN, %lo(__ocm_data_run_begin)(DST_AN) - moveai SRC_AN, #%hi(__ocm_data_load_begin) - lea.4 SRC_AN, %lo(__ocm_data_load_begin)(SRC_AN) - jmpt.t 2f - -1: move.4 (DST_AN)4++, (SRC_AN)4++ - -2: sub.4 #0, DST_AN, TMP_DN - jmpne.t 1b - -; Clear .bss -; - moveai SRC_AN, #%hi(_ebss) - lea.4 TMP_DN, %lo(_ebss)(SRC_AN) - moveai DST_AN, #%hi(_sbss) - lea.4 DST_AN, %lo(_sbss)(DST_AN) - jmpt.t 2f - -1: move.4 (DST_AN)4++, #0 - -2: sub.4 #0, DST_AN, TMP_DN - jmpne.t 1b - -; save our parameter to devtree (after clearing .bss) - moveai DST_AN, #%hi(devtree) - lea.4 DST_AN, %lo(devtree)(DST_AN) - move.4 (DST_AN), PARAM_DN - - moveai sp, #%hi(init_thread_union) - lea.4 sp, %lo(init_thread_union)(sp) - movei TMP_DN, #ASM_THREAD_SIZE - add.4 sp, sp, TMP_DN - move.4 -4(sp)++, #0 ; nesting level = 0 - move.4 -4(sp)++, #1 ; KERNEL_THREAD - -;; ip3k-elf-gdb backend now sets scratchpad3 to 1 when either continue -;; or single step commands are issued. scratchpad3 is set to 0 when the -;; debugger detaches from the board. - move.4 TMP_DN, scratchpad3 - lsl.4 TMP_DN, TMP_DN, #0x0 - jmpeq.f _jump_to_start_kernel -_ok_to_set_break_points_in_linux: -;; THREAD_STALL - move.4 mt_dbg_active_clr,#-1 -;; stalling the threads isn't instantaneous.. need to flush the pipe. - pipe_flush 0 - pipe_flush 0 - -_jump_to_start_kernel: - moveai SRC_AN, #%hi(start_kernel) - lea.4 SRC_AN, %lo(start_kernel)(SRC_AN) - ret SRC_AN diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c deleted file mode 100644 index 58baf52709..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/init_task.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * arch/ubicom32/kernel/init_task.c - * Ubicom32 architecture task initialization implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/init_task.h> -#include <linux/fs.h> -#include <linux/mqueue.h> -#include <linux/uaccess.h> -#include <asm/pgtable.h> -#include <linux/version.h> - -///static struct fs_struct init_fs = INIT_FS; -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) -struct mm_struct init_mm = INIT_MM(init_mm); -EXPORT_SYMBOL(init_mm); -#endif - -/* - * 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); - -/* - * 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 having a special - * "init_task" linker map entry.. - */ -union thread_union init_thread_union - __attribute__((__section__(".data.init_task"))) = - { INIT_THREAD_INFO(init_task) }; diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c deleted file mode 100644 index c041f23e25..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/irq.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * arch/ubicom32/kernel/irq.c - * Ubicom32 architecture IRQ support. - * - * (C) Copyright 2009, Ubicom, Inc. - * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com> - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/types.h> -#include <linux/irq.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/kernel_stat.h> -#include <linux/module.h> -#include <linux/seq_file.h> -#include <linux/proc_fs.h> -#include <asm/system.h> -#include <asm/traps.h> -#include <asm/ldsr.h> -#include <asm/ip5000.h> -#include <asm/machdep.h> -#include <asm/asm-offsets.h> -#include <asm/thread.h> -#include <asm/devtree.h> - -unsigned int irq_soft_avail; -static struct irqaction ubicom32_reserve_action[NR_IRQS]; - -#if !defined(CONFIG_DEBUG_IRQMEASURE) -#define IRQ_DECLARE_MEASUREMENT -#define IRQ_MEASUREMENT_START() -#define IRQ_MEASUREMENT_END(irq) -#else -#define IRQ_DECLARE_MEASUREMENT \ - int __diff; \ - unsigned int __tstart; - -#define IRQ_MEASUREMENT_START() \ - __tstart = UBICOM32_IO_TIMER->sysval; - -#define IRQ_MEASUREMENT_END(irq) \ - __diff = (int)UBICOM32_IO_TIMER->sysval - (int)__tstart; \ - irq_measurement_update((irq), __diff); - -/* - * We keep track of the time spent in both irq_enter() - * and irq_exit(). - */ -#define IRQ_WEIGHT 32 - -struct irq_measurement { - volatile unsigned int min; - volatile unsigned int avg; - volatile unsigned int max; -}; - -static DEFINE_SPINLOCK(irq_measurement_lock); - -/* - * Add 1 in for softirq (irq_exit()); - */ -static struct irq_measurement irq_measurements[NR_IRQS + 1]; - -/* - * irq_measurement_update() - * Update an entry in the measurement array for this irq. - */ -static void irq_measurement_update(int irq, int sample) -{ - struct irq_measurement *im = &irq_measurements[irq]; - spin_lock(&irq_measurement_lock); - if ((im->min == 0) || (im->min > sample)) { - im->min = sample; - } - if (im->max < sample) { - im->max = sample; - } - im->avg = ((im->avg * (IRQ_WEIGHT - 1)) + sample) / IRQ_WEIGHT; - spin_unlock(&irq_measurement_lock); -} -#endif - -/* - * irq_kernel_stack_check() - * See if the kernel stack is within STACK_WARN of the end. - */ -static void irq_kernel_stack_check(int irq, struct pt_regs *regs) -{ -#ifdef CONFIG_DEBUG_STACKOVERFLOW - unsigned long sp; - - /* - * Make sure that we are not close to the top of the stack and thus - * can not really service this interrupt. - */ - asm volatile ( - "and.4 %0, SP, %1 \n\t" - : "=d" (sp) - : "d" (THREAD_SIZE - 1) - : "cc" - ); - - if (sp < (sizeof(struct thread_info) + STACK_WARN)) { - printk(KERN_WARNING - "cpu[%d]: possible overflow detected sp remain: %p, " - "irq: %d, regs: %p\n", - thread_get_self(), (void *)sp, irq, regs); - dump_stack(); - } - - if (sp < (sizeof(struct thread_info) + 16)) { - THREAD_STALL; - } -#endif -} - -/* - * irq_get_lsb() - * Get the LSB set in value - */ -static int irq_get_lsb(unsigned int value) -{ - static unsigned char irq_bits[8] = { - 3, 0, 1, 0, 2, 0, 1, 0 - }; - u32_t nextbit = 0; - - value = (value >> nextbit) | (value << ((sizeof(value) * 8) - nextbit)); - - /* - * It's unlikely that we find that we execute the body of this while - * loop. 50% of the time we won't take this at all and then of the - * cases where we do about 50% of those we only execute once. - */ - if (!(value & 0xffff)) { - nextbit += 0x10; - value >>= 16; - } - - if (!(value & 0xff)) { - nextbit += 0x08; - value >>= 8; - } - - if (!(value & 0xf)) { - nextbit += 0x04; - value >>= 4; - } - - nextbit += irq_bits[value & 0x7]; - if (nextbit > 63) { - panic("nextbit out of range: %d\n", nextbit); - } - return nextbit; -} - -/* - * ubicom32_reserve_handler() - * Bogus handler associated with pre-reserved IRQ(s). - */ -static irqreturn_t ubicom32_reserve_handler(int irq, void *dev_id) -{ - BUG(); - return IRQ_HANDLED; -} - -/* - * __irq_disable_vector() - * Disable the interrupt by clearing the appropriate bit in the - * LDSR Mask Register. - */ -static void __irq_disable_vector(unsigned int irq) -{ - ldsr_disable_vector(irq); -} - -/* - * __irq_ack_vector() - * Acknowledge the specific interrupt by clearing the associate bit in - * hardware - */ -static void __irq_ack_vector(unsigned int irq) -{ - if (irq < 32) { - asm volatile ("move.4 INT_CLR0, %0" : : "d" (1 << irq)); - } else { - asm volatile ("move.4 INT_CLR1, %0" : : "d" (1 << (irq - 32))); - } -} - -/* - * __irq_enable_vector() - * Clean and then enable the interrupt by setting the appropriate bit in - * the LDSR Mask Register. - */ -static void __irq_enable_vector(unsigned int irq) -{ - /* - * Acknowledge, really clear the vector. - */ - __irq_ack_vector(irq); - ldsr_enable_vector(irq); -} - -/* - * __irq_mask_vector() - */ -static void __irq_mask_vector(unsigned int irq) -{ - ldsr_mask_vector(irq); -} - -/* - * __irq_unmask_vector() - */ -static void __irq_unmask_vector(unsigned int irq) -{ - ldsr_unmask_vector(irq); -} - -/* - * __irq_end_vector() - * Called once an interrupt is completed (reset the LDSR mask). - */ -static void __irq_end_vector(unsigned int irq) -{ - ldsr_unmask_vector(irq); -} - -#if defined(CONFIG_SMP) -/* - * __irq_set_affinity() - * Set the cpu affinity for this interrupt. - * affinity container allocated at boot - */ -static void __irq_set_affinity(unsigned int irq, const struct cpumask *dest) -{ - smp_set_affinity(irq, dest); - cpumask_copy(irq_desc[irq].affinity, dest); -} -#endif - -/* - * On-Chip Generic Interrupt function handling. - */ -static struct irq_chip ubicom32_irq_chip = { - .name = "Ubicom32", - .startup = NULL, - .shutdown = NULL, - .enable = __irq_enable_vector, - .disable = __irq_disable_vector, - .ack = __irq_ack_vector, - .mask = __irq_mask_vector, - .unmask = __irq_unmask_vector, - .end = __irq_end_vector, -#if defined(CONFIG_SMP) - .set_affinity = __irq_set_affinity, -#endif -}; - -/* - * do_IRQ() - * Primary interface for handling IRQ() requests. - */ -asmlinkage void do_IRQ(int irq, struct pt_regs *regs) -{ - struct pt_regs *oldregs; - struct thread_info *ti = current_thread_info(); - - IRQ_DECLARE_MEASUREMENT; - - /* - * Mark that we are inside of an interrupt and - * that interrupts are disabled. - */ - oldregs = set_irq_regs(regs); - ti->interrupt_nesting++; - trace_hardirqs_off(); - irq_kernel_stack_check(irq, regs); - - /* - * Start the interrupt sequence - */ - irq_enter(); - - /* - * Execute the IRQ handler and any pending SoftIRQ requests. - */ - BUG_ON(!irqs_disabled()); - IRQ_MEASUREMENT_START(); - __do_IRQ(irq); - IRQ_MEASUREMENT_END(irq); - BUG_ON(!irqs_disabled()); - - /* - * TODO: Since IRQ's are disabled when calling irq_exit() - * modify Kconfig to set __ARCH_IRQ_EXIT_IRQS_DISABLED flag. - * This will slightly improve performance by enabling - * softirq handling to avoid disabling/disabled interrupts. - */ - IRQ_MEASUREMENT_START(); - irq_exit(); - IRQ_MEASUREMENT_END(NR_IRQS); - BUG_ON(!irqs_disabled()); - - /* - * Outside of an interrupt (or nested exit). - */ - set_irq_regs(oldregs); - trace_hardirqs_on(); - ti->interrupt_nesting--; -} - -/* - * irq_soft_alloc() - * Allocate a soft IRQ. - */ -int irq_soft_alloc(unsigned int *soft) -{ - if (irq_soft_avail == 0) { - printk(KERN_NOTICE "no soft irqs to allocate\n"); - return -EFAULT; - } - - *soft = irq_get_lsb(irq_soft_avail); - irq_soft_avail &= ~(1 << *soft); - return 0; -} - -/* - * ack_bad_irq() - * Called to handle an bad irq request. - */ -void ack_bad_irq(unsigned int irq) -{ - printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq); - __irq_end_vector(irq); -} - -/* - * show_interrupts() - * Return a string that displays the state of each of the interrupts. - */ -int show_interrupts(struct seq_file *p, void *v) -{ - struct irqaction *ap; - int irq = *((loff_t *) v); - int j; - - if (irq >= NR_IRQS) { - return 0; - } - - if (irq == 0) { - seq_puts(p, " "); - for_each_online_cpu(j) { - seq_printf(p, "CPU%d ", j); - } - seq_putc(p, '\n'); - } - - ap = irq_desc[irq].action; - if (ap) { - seq_printf(p, "%3d: ", irq); - for_each_online_cpu(j) { - seq_printf(p, "%10u ", kstat_irqs_cpu(irq, j)); - } - seq_printf(p, "%14s ", irq_desc[irq].chip->name); - seq_printf(p, "%s", ap->name); - for (ap = ap->next; ap; ap = ap->next) { - seq_printf(p, ", %s", ap->name); - } - seq_putc(p, '\n'); - } - return 0; -} - -#if defined(CONFIG_DEBUG_IRQMEASURE) -static unsigned int irq_cycles_to_micro(unsigned int cycles, unsigned int frequency) -{ - unsigned int micro = (cycles / (frequency / 1000000)); - return micro; -} - -/* - * irq_measurement_show() - * Print out the min, avg, max values for each IRQ - * - * By request, the max value is reset after each dump. - */ -static int irq_measurement_show(struct seq_file *p, void *v) -{ - struct irqaction *ap; - unsigned int freq = processor_frequency(); - int irq = *((loff_t *) v); - - - if (irq == 0) { - seq_puts(p, "\tmin\tavg\tmax\t(micro-seconds)\n"); - } - - if (irq > NR_IRQS) { - return 0; - } - - if (irq == NR_IRQS) { - unsigned int min, avg, max; - spin_lock(&irq_measurement_lock); - min = irq_cycles_to_micro(irq_measurements[irq].min, freq); - avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq); - max = irq_cycles_to_micro(irq_measurements[irq].max, freq); - irq_measurements[irq].max = 0; - spin_unlock(&irq_measurement_lock); - seq_printf(p, " \t%u\t%u\t%u\tsoftirq\n", min, avg, max); - return 0; - } - - ap = irq_desc[irq].action; - if (ap) { - unsigned int min, avg, max; - spin_lock(&irq_measurement_lock); - min = irq_cycles_to_micro(irq_measurements[irq].min, freq); - avg = irq_cycles_to_micro(irq_measurements[irq].avg, freq); - max = irq_cycles_to_micro(irq_measurements[irq].max, freq); - irq_measurements[irq].max = 0; - spin_unlock(&irq_measurement_lock); - seq_printf(p, "%2u:\t%u\t%u\t%u\t%s\n", irq, min, avg, max, ap->name); - } - return 0; -} - -static void *irq_measurement_start(struct seq_file *f, loff_t *pos) -{ - return (*pos <= NR_IRQS) ? pos : NULL; -} - -static void *irq_measurement_next(struct seq_file *f, void *v, loff_t *pos) -{ - (*pos)++; - if (*pos > NR_IRQS) - return NULL; - return pos; -} - -static void irq_measurement_stop(struct seq_file *f, void *v) -{ - /* Nothing to do */ -} - -static const struct seq_operations irq_measurement_seq_ops = { - .start = irq_measurement_start, - .next = irq_measurement_next, - .stop = irq_measurement_stop, - .show = irq_measurement_show, -}; - -static int irq_measurement_open(struct inode *inode, struct file *filp) -{ - return seq_open(filp, &irq_measurement_seq_ops); -} - -static const struct file_operations irq_measurement_fops = { - .open = irq_measurement_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init irq_measurement_init(void) -{ - proc_create("irq_measurements", 0, NULL, &irq_measurement_fops); - return 0; -} -module_init(irq_measurement_init); -#endif - -/* - * init_IRQ(void) - * Initialize the on-chip IRQ subsystem. - */ -void __init init_IRQ(void) -{ - int irq; - struct devtree_node *p = NULL; - struct devtree_node *iter = NULL; - unsigned int mask = 0; - unsigned int reserved = 0; - - /* - * Pull out the list of software interrupts that are avialable to - * Linux and provide an allocation function for them. The first - * 24 interrupts of INT0 are software interrupts. - */ - irq_soft_avail = 0; - if (processor_interrupts(&irq_soft_avail, NULL) < 0) { - printk(KERN_WARNING "No Soft IRQ(s) available\n"); - } - irq_soft_avail &= ((1 << 24) - 1); - - /* - * Initialize all of the on-chip interrupt handling - * to use a common set of interrupt functions. - */ - for (irq = 0; irq < NR_IRQS; irq++) { - irq_desc[irq].status = IRQ_DISABLED; - irq_desc[irq].action = NULL; - irq_desc[irq].depth = 1; - set_irq_chip(irq, &ubicom32_irq_chip); - } - - /* - * The sendirq of a devnode is not registered within Linux but instead - * is used by the software I/O thread. These interrupts are reserved. - * The recvirq is used by Linux and registered by a device driver, these - * are not reserved. - * - * recvirq(s) that are in the software interrupt range are not supposed - * to be marked as reserved. We track this while we scan the device - * nodes. - */ - p = devtree_find_next(&iter); - while (p) { - unsigned char sendirq, recvirq; - devtree_irq(p, &sendirq, &recvirq); - - /* - * If the sendirq is valid, mark that irq as taken by the - * devtree node. - */ - if (sendirq < NR_IRQS) { - ubicom32_reserve_action[sendirq].handler = - ubicom32_reserve_handler; - ubicom32_reserve_action[sendirq].name = p->name; - irq_desc[sendirq].action = - &ubicom32_reserve_action[sendirq]; - mask |= (1 << sendirq); - } - - /* - * Track the relevant recieve IRQ(s) - */ - if (recvirq < 24) { - mask |= (1 << recvirq); - } - - /* - * Move to the next node. - */ - p = devtree_find_next(&iter); - } - - /* - * Remove these bits from the irq_soft_avail list and then use the - * result as the list of pre-reserved IRQ(s). - */ - reserved = ~irq_soft_avail & ~mask; - for (irq = 0; irq < 24; irq++) { - if ((reserved & (1 << irq))) { - ubicom32_reserve_action[irq].handler = - ubicom32_reserve_handler; - ubicom32_reserve_action[irq].name = "reserved"; - irq_desc[irq].action = &ubicom32_reserve_action[irq]; - } - } - - /* - * Initialize the LDSR which is the Ubicom32 programmable - * interrupt controller. - */ - ldsr_init(); - - /* - * The Ubicom trap code needs a 2nd init after IRQ(s) are setup. - */ - trap_init_interrupt(); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c deleted file mode 100644 index a608d74cfe..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/ldsr.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * arch/ubicom32/kernel/ldsr.c - * Ubicom32 architecture Linux Device Services Driver Interface - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - * - * NOTES: - * - * The LDSR is a programmable interrupt controller that is written in software. - * It emulates the behavior of an pic by fielding the interrupts, choosing a - * victim thread to take the interrupt and forcing that thread to take a context - * switch to the appropriate interrupt handler. - * - * Because traps are treated as just a special class of interrupts, the LDSR - * also handles the processing of traps. - * - * Because we compile Linux both UP and SMP, we need the LDSR to use - * architectural locking that is not "compiled out" when compiling UP. For now, - * we use the single atomic bit lock. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/profile.h> -#include <linux/clocksource.h> -#include <linux/types.h> -#include <linux/module.h> -#include <linux/cpumask.h> -#include <linux/bug.h> -#include <linux/delay.h> -#include <asm/ip5000.h> -#include <asm/atomic.h> -#include <asm/machdep.h> -#include <asm/asm-offsets.h> -#include <asm/traps.h> -#include <asm/thread.h> -#include <asm/range-protect.h> - -/* - * One can not print from the LDSR so the best we can do is - * check a condition and stall all of the threads. - */ - -// #define DEBUG_LDSR 1 -#if defined(DEBUG_LDSR) -#define DEBUG_ASSERT(cond) \ - if (!(cond)) { \ - THREAD_STALL; \ - } -#else -#define DEBUG_ASSERT(cond) -#endif - -/* - * Make global so that we can use it in the RFI code in assembly. - */ -unsigned int ldsr_soft_irq_mask; -EXPORT_SYMBOL(ldsr_soft_irq_mask); - -static unsigned int ldsr_suspend_mask; -static unsigned int ldsr_soft_irq; -static unsigned int ldsr_stack_space[1024]; - -static struct ldsr_register_bank { - volatile unsigned int enabled0; - volatile unsigned int enabled1; - volatile unsigned int mask0; - volatile unsigned int mask1; - unsigned int total; - unsigned int retry; - unsigned int backout; -} ldsr_interrupt; - -/* - * Which thread/cpu are we? - */ -static int ldsr_tid = -1; - -#if defined(CONFIG_IRQSTACKS) -/* - * per-CPU IRQ stacks (thread information and stack) - * - * NOTE: Do not use DEFINE_PER_CPU() as it makes it harder - * to find the location of ctx from assembly language. - */ -union irq_ctx { - struct thread_info tinfo; - u32 stack[THREAD_SIZE/sizeof(u32)]; -}; -static union irq_ctx *percpu_irq_ctxs[NR_CPUS]; - -/* - * Storage for the interrupt stack. - */ -#if !defined(CONFIG_IRQSTACKS_USEOCM) -static char percpu_irq_stacks[(NR_CPUS * THREAD_SIZE) + (THREAD_SIZE - 1)]; -#else -/* - * For OCM, the linker will ensure that space is allocated for the stack - * see (vmlinux.lds.S) - */ -static char percpu_irq_stacks[]; -#endif - -#endif - -/* - * Save trap IRQ because we need to un-suspend if it gets set. - */ -static unsigned int ldsr_trap_irq_mask; -static unsigned int ldsr_trap_irq; - -/* - * ret_from_interrupt_to_kernel - * Just restore the context and do nothing else. - */ -asmlinkage void ret_from_interrupt_to_kernel(void)__attribute__((naked)); - -/* - * ret_from_interrupt_to_user - * Call scheduler if needed. Just restore the context. - */ -asmlinkage void ret_from_interrupt_to_user(void)__attribute__((naked)); - -#ifdef DEBUG_LDSR -u32_t old_sp, old_pc, old_a0, old_a5, old_a3; -struct pt_regs copy_regs, *copy_save_area; -#endif - -int __user_mode(unsigned long sp) -{ - - u32_t saved_stack_base = sp & ~(ASM_THREAD_SIZE - 1); -#if defined(CONFIG_IRQSTACKS_USEOCM) - if ((union irq_ctx *)saved_stack_base == percpu_irq_ctxs[smp_processor_id()]) { - /* - * On the interrupt stack. - */ - return 0; - } -#endif - - if (!(u32_t)current) { - return 0; - } - return saved_stack_base != ((u32_t)current->stack); -} - -/* - * ldsr_lock_release() - * Release the LDSR lock. - */ -static void ldsr_lock_release(void) -{ - UBICOM32_UNLOCK(LDSR_LOCK_BIT); -} - -/* - * ldsr_lock_acquire() - * Acquire the LDSR lock, spin if not available. - */ -static void ldsr_lock_acquire(void) -{ - UBICOM32_LOCK(LDSR_LOCK_BIT); -} - -/* - * ldsr_thread_irq_disable() - * Disable interrupts for the specified thread. - */ -static void ldsr_thread_irq_disable(unsigned int tid) -{ - unsigned int mask = (1 << tid); - - asm volatile ( - " or.4 scratchpad1, scratchpad1, %0 \n\t" - : - : "d"(mask) - : "cc" - ); -} - -/* - * ldsr_thread_get_interrupts() - * Get the interrupt state for all threads. - */ -static unsigned long ldsr_thread_get_interrupts(void) -{ - unsigned long ret = 0; - asm volatile ( - " move.4 %0, scratchpad1 \n\t" - : "=r" (ret) - : - ); - return ret; -} - -/* - * ldsr_emulate_and_run() - * Emulate the instruction and then set the thread to run. - */ -static void ldsr_emulate_and_run(unsigned int tid) -{ - unsigned int thread_mask = (1 << tid); - u32_t write_csr = (tid << 15) | (1 << 14); - - /* - * Emulate the unaligned access. - */ - unaligned_emulate(tid); - - /* - * Get the thread back in a running state. - */ - asm volatile ( - " setcsr %0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 trap_cause, #0 \n\t" /* Clear the trap cause - * register */ - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 mt_dbg_active_set, %1 \n\t" /* Activate thread even if - * in dbg/fault state */ - " move.4 mt_active_set, %1 \n\t" /* Restart target - * thread. */ - : - : "r" (write_csr), "d" (thread_mask) - : "cc" - ); - thread_enable_mask(thread_mask); -} - -/* - * ldsr_preemptive_context_save() - * save thread context from another hardware thread. The other thread must - * be stalled. - */ -static inline void ldsr_preemptive_context_save(u32_t thread, - struct pt_regs *regs) -{ - /* - * Save the current state of the specified thread - */ - asm volatile ( - " move.4 a3, %0 \n\t" - - /* set src1 from the target thread */ - " move.4 csr, %1 \n\t" - " setcsr_flush 0 \n\t" - " setcsr_flush 0 \n\t" - - /* copy state from the other thread */ - " move.4 "D(PT_D0)"(a3), d0 \n\t" - " move.4 "D(PT_D1)"(a3), d1 \n\t" - " move.4 "D(PT_D2)"(a3), d2 \n\t" - " move.4 "D(PT_D3)"(a3), d3 \n\t" - " move.4 "D(PT_D4)"(a3), d4 \n\t" - " move.4 "D(PT_D5)"(a3), d5 \n\t" - " move.4 "D(PT_D6)"(a3), d6 \n\t" - " move.4 "D(PT_D7)"(a3), d7 \n\t" - " move.4 "D(PT_D8)"(a3), d8 \n\t" - " move.4 "D(PT_D9)"(a3), d9 \n\t" - " move.4 "D(PT_D10)"(a3), d10 \n\t" - " move.4 "D(PT_D11)"(a3), d11 \n\t" - " move.4 "D(PT_D12)"(a3), d12 \n\t" - " move.4 "D(PT_D13)"(a3), d13 \n\t" - " move.4 "D(PT_D14)"(a3), d14 \n\t" - " move.4 "D(PT_D15)"(a3), d15 \n\t" - " move.4 "D(PT_A0)"(a3), a0 \n\t" - " move.4 "D(PT_A1)"(a3), a1 \n\t" - " move.4 "D(PT_A2)"(a3), a2 \n\t" - " move.4 "D(PT_A3)"(a3), a3 \n\t" - " move.4 "D(PT_A4)"(a3), a4 \n\t" - " move.4 "D(PT_A5)"(a3), a5 \n\t" - " move.4 "D(PT_A6)"(a3), a6 \n\t" - " move.4 "D(PT_SP)"(a3), a7 \n\t" - " move.4 "D(PT_ACC0HI)"(a3), acc0_hi \n\t" - " move.4 "D(PT_ACC0LO)"(a3), acc0_lo \n\t" - " move.4 "D(PT_MAC_RC16)"(a3), mac_rc16 \n\t" - " move.4 "D(PT_ACC1HI)"(a3), acc1_hi \n\t" - " move.4 "D(PT_ACC1LO)"(a3), acc1_lo \n\t" - " move.4 "D(PT_SOURCE3)"(a3), source3 \n\t" - " move.4 "D(PT_INST_CNT)"(a3), inst_cnt \n\t" - " move.4 "D(PT_CSR)"(a3), csr \n\t" - " move.4 "D(PT_DUMMY_UNUSED)"(a3), #0 \n\t" - " move.4 "D(PT_INT_MASK0)"(a3), int_mask0 \n\t" - " move.4 "D(PT_INT_MASK1)"(a3), int_mask1 \n\t" - " move.4 "D(PT_TRAP_CAUSE)"(a3), trap_cause \n\t" - " move.4 "D(PT_PC)"(a3), pc \n\t" - " move.4 "D(PT_PREVIOUS_PC)"(a3), previous_pc \n\t" - /* disable csr thread select */ - " movei csr, #0 \n\t" - " setcsr_flush 0 \n\t" - : - : "r" (regs->dn), "d" ((thread << 9) | (1 << 8)) - : "a3" - ); -} - -/* - * ldsr_rotate_threads() - * Simple round robin algorithm for choosing the next cpu - */ -static int ldsr_rotate_threads(unsigned long cpus) -{ - static unsigned char ldsr_bits[8] = { - 3, 0, 1, 0, 2, 0, 1, 0 - }; - - static int nextbit; - int thisbit; - - /* - * Move the interrupts down so that we consider interrupts from where - * we left off, then take the interrupts we would lose and move them - * to the top half of the interrupts value. - */ - cpus = (cpus >> nextbit) | (cpus << ((sizeof(cpus) * 8) - nextbit)); - - /* - * 50% of the time we won't take this at all and then of the cases where - * we do about 50% of those we only execute once. - */ - if (!(cpus & 0xffff)) { - nextbit += 16; - cpus >>= 16; - } - - if (!(cpus & 0xff)) { - nextbit += 8; - cpus >>= 8; - } - - if (!(cpus & 0xf)) { - nextbit += 4; - cpus >>= 4; - } - - nextbit += ldsr_bits[cpus & 0x7]; - thisbit = (nextbit & ((sizeof(cpus) * 8) - 1)); - nextbit = (thisbit + 1) & ((sizeof(cpus) * 8) - 1); - DEBUG_ASSERT(thisbit < THREAD_ARCHITECTURAL_MAX); - return thisbit; -} - -/* - * ldsr_rotate_interrupts() - * Get rotating next set bit value. - */ -static int ldsr_rotate_interrupts(unsigned long long interrupts) -{ - static unsigned char ldsr_bits[8] = { - 3, 0, 1, 0, 2, 0, 1, 0 - }; - - static int nextbit; - int thisbit; - - /* - * Move the interrupts down so that we consider interrupts from where - * we left off, then take the interrupts we would lose and move them - * to the top half of the interrupts value. - */ - interrupts = (interrupts >> nextbit) | - (interrupts << ((sizeof(interrupts) * 8) - nextbit)); - - /* - * 50% of the time we won't take this at all and then of the cases where - * we do about 50% of those we only execute once. - */ - if (!(interrupts & 0xffffffff)) { - nextbit += 32; - interrupts >>= 32; - } - - if (!(interrupts & 0xffff)) { - nextbit += 16; - interrupts >>= 16; - } - - if (!(interrupts & 0xff)) { - nextbit += 8; - interrupts >>= 8; - } - - if (!(interrupts & 0xf)) { - nextbit += 4; - interrupts >>= 4; - } - - nextbit += ldsr_bits[interrupts & 0x7]; - thisbit = (nextbit & ((sizeof(interrupts) * 8) - 1)); - nextbit = (thisbit + 1) & ((sizeof(interrupts) * 8) - 1); - - DEBUG_ASSERT(thisbit < (sizeof(interrupts) * 8)); - return thisbit; -} - -/* - * ldsr_backout_or_irq() - * - * One way or the other this interrupt is not being - * processed, make sure that it is reset. We are - * not going to call irq_end_vector() so unmask the - * interrupt. - */ -static void ldsr_backout_of_irq(int vector, unsigned long tid_mask) -{ -#if defined(CONFIG_SMP) - if (unlikely(vector == smp_ipi_irq)) { - smp_reset_ipi(tid_mask); - } -#endif - ldsr_unmask_vector(vector); - ldsr_interrupt.backout++; -} - -#if defined(CONFIG_IRQSTACKS) -/* - * ldsr_choose_savearea_and_returnvec() - * Test our current state (user, kernel, interrupt) and set things up. - * - * This version of the function uses 3 stacks and nests interrupts - * on the interrupt stack. - */ -static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec) -{ - struct pt_regs *save_area; - u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); - struct thread_info * ti= (struct thread_info *)sw_ksp[tid]; - -#if defined(CONFIG_SMP) - union irq_ctx *icp = percpu_irq_ctxs[tid]; -#else - union irq_ctx *icp = percpu_irq_ctxs[0]; -#endif - - if (masked_linux_sp == (u32_t)icp) { - /* - * Fault/Interrupt occurred while on the interrupt stack. - */ - save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8); - *pvec = (u32_t)(&ret_from_interrupt_to_kernel); - } else { - /* - * Fault/Interrupt occurred while on user/kernel stack. This is a new - * first use of the interrupt stack. - */ - save_area = (struct pt_regs *) ((char *)icp + sizeof(icp->stack) - sizeof(struct pt_regs) - 8); - if (masked_linux_sp == (u32_t)ti) { - *pvec = (u32_t)(&ret_from_interrupt_to_kernel); - } else { - *pvec = (u32_t)(&ret_from_interrupt_to_user); - } - - /* - * Because the softirq code will execute on the "interrupt" stack, we - * need to maintain the knowledge of what "task" was executing on the - * cpu. This is done by copying the thread_info->task from the cpu - * we are about to context switch into the interrupt contexts thread_info - * structure. - */ - icp->tinfo.task = ti->task; - icp->tinfo.preempt_count = - (icp->tinfo.preempt_count & ~SOFTIRQ_MASK) | - (ti->preempt_count & SOFTIRQ_MASK); - icp->tinfo.interrupt_nesting = 0; - } - save_area->nesting_level = icp->tinfo.interrupt_nesting; - return save_area; -} - -#else -/* - * ldsr_choose_savearea_and_returnvec() - * Test our current state (user, kernel, interrupt) and set things up. - * - * The version of the function uses just the user & kernel stack and - * nests interrupts on the existing kernel stack. - */ -static struct pt_regs *ldsr_choose_savearea_and_returnvec(thread_t tid, u32_t linux_sp, u32_t *pvec) -{ - struct pt_regs *save_area; - u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); - struct thread_info *ti = (struct thread_info *)sw_ksp[tid]; - - if (masked_linux_sp == (u32_t)ti) { - /* - * Fault/Interrupt occurred while on the kernel stack. - */ - save_area = (struct pt_regs *)((char *)linux_sp - sizeof(struct pt_regs) - 8); - *pvec = (u32_t) (&ret_from_interrupt_to_kernel); - } else { - /* - * Fault/Interrupt occurred while on user stack. - */ - ti->interrupt_nesting = 0; - save_area = (struct pt_regs *)((u32_t)ti + THREAD_SIZE - sizeof(struct pt_regs) - 8); - *pvec = (u32_t) (&ret_from_interrupt_to_user); - } - save_area->nesting_level = ti->interrupt_nesting; - return save_area; -} -#endif - -/* - * ldsr_ctxsw_thread() - * Context switch a mainline thread to execute do_IRQ() for the specified - * vector. - */ -static void ldsr_ctxsw_thread(int vector, thread_t tid) -{ - u32_t linux_sp; - u32_t return_vector; - struct pt_regs *save_area, *regs; - u32_t thread_mask = (1 << tid); - u32_t read_csr = ((tid << 9) | (1 << 8)); - u32_t write_csr = (tid << 15) | (1 << 14); - u32_t interrupt_vector = (u32_t)(&do_IRQ); - - unsigned int frame_type = UBICOM32_FRAME_TYPE_INTERRUPT; - - - DEBUG_ASSERT(!thread_is_enabled(tid)); - - /* - * Acquire the necessary global and per thread locks for tid. - * As a side effect, we ensure that the thread has not trapped - * and return true if it has. - */ - if (unlikely(thread_is_trapped(tid))) { - /* - * Read the trap cause, the sp and clear the MT_TRAP bits. - */ - unsigned int cause; - asm volatile ( - " setcsr %3 \n\t" - " setcsr_flush 0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 %0, TRAP_CAUSE \n\t" - " move.4 %1, SP \n\t" - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 MT_BREAK_CLR, %2\n\t" - " move.4 MT_TRAP_CLR, %2 \n\t" - : "=&r" (cause), "=&r" (linux_sp) - : "r" (thread_mask), "m" (read_csr) - ); - - ldsr_backout_of_irq(vector, (1 << tid)); - -#if !defined(CONFIG_UNALIGNED_ACCESS_DISABLED) - /* - * See if the unaligned trap handler can deal with this. - * If so, emulate the instruction and then just restart - * the thread. - */ - if (unaligned_only(cause)) { -#if defined(CONFIG_UNALIGNED_ACCESS_USERSPACE_ONLY) - /* - * Check if this is a kernel stack if so we will not - * handle the trap - */ - u32_t masked_linux_sp = linux_sp & ~(THREAD_SIZE - 1); - if ((masked_linux_sp != (u32_t)sw_ksp[tid]) && - unaligned_only(cause)) { - ldsr_emulate_and_run(tid); - return; - } -#else - ldsr_emulate_and_run(tid); - return; -#endif - - } -#endif - - interrupt_vector = (u32_t)(&trap_handler); - frame_type = UBICOM32_FRAME_TYPE_TRAP; - } else { - /* - * Read the target thread's SP - */ - asm volatile ( - " setcsr %1 \n\t" - " setcsr_flush 0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 %0, SP \n\t" - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - : "=m" (linux_sp) - : "m" (read_csr) - ); - } - - /* - * We are delivering an interrupt, count it. - */ - ldsr_interrupt.total++; - - /* - * At this point, we will definitely force this thread to - * a new context, show its interrupts as disabled. - */ - ldsr_thread_irq_disable(tid); - - /* - * Test our current state (user, kernel, interrupt). Save the - * appropriate data and setup for the return. - */ - save_area = ldsr_choose_savearea_and_returnvec(tid, linux_sp, &return_vector); - - /* - * The pt_regs (save_area) contains the type of thread that we are dealing - * with (KERNEL/NORMAL) and is copied into each pt_regs area. We get this - * from the current tasks kernel pt_regs area that always exists at the - * top of the kernel stack. - */ - regs = (struct pt_regs *)((u32_t)sw_ksp[tid] + THREAD_SIZE - sizeof(struct pt_regs) - 8); - save_area->thread_type = regs->thread_type; - - /* - * Preserve the context of the Linux thread. - */ - ldsr_preemptive_context_save(tid, save_area); - - /* - * Load the fram_type into the save_area. - */ - save_area->frame_type = frame_type; - -#ifdef CONFIG_STOP_ON_TRAP - /* - * Before we get backtrace and showing stacks working well, it sometimes - * helps to enter the debugger when a trap occurs before we change the - * thread to handle the fault. This optional code causes all threads to - * stop on every trap frame. One assumes that GDB connected via the - * mailbox interface will be used to recover from this state. - */ - if (frame_type == UBICOM32_FRAME_TYPE_TRAP) { - THREAD_STALL; - } -#endif - -#ifdef DEBUG_LDSR - copy_regs = *save_area; - copy_save_area = save_area; - - old_a0 = save_area->an[0]; - old_a3 = save_area->an[3]; - old_sp = save_area->an[7]; - old_a5 = save_area->an[5]; - old_pc = save_area->pc; -#endif - - /* - * Now we have to switch the kernel thread to run do_IRQ function. - * Set pc to do_IRQ - * Set d0 to vector - * Set d1 to save_area. - * Set a5 to the proper return vector. - */ - asm volatile ( - " setcsr %0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 d0, %5 \n\t" /* d0 = 0 vector # */ - " move.4 d1, %1 \n\t" /* d1 = save_area */ - " move.4 sp, %1 \n\t" /* sp = save_area */ - " move.4 a5, %2 \n\t" /* a5 = return_vector */ - " move.4 pc, %3 \n\t" /* pc = do_IRQ routine. */ - " move.4 trap_cause, #0 \n\t" /* Clear the trap cause - * register */ - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - " enable_kernel_ranges %4 \n\t" - " move.4 mt_dbg_active_set, %4 \n\t" /* Activate thread even if - * in dbg/fault state */ - " move.4 mt_active_set, %4 \n\t" /* Restart target - * thread. */ - : - : "r" (write_csr), "r" (save_area), - "r" (return_vector), "r" (interrupt_vector), - "d" (thread_mask), "r" (vector) - : "cc" - ); - thread_enable_mask(thread_mask); -} - -/* - * ldsr_deliver_interrupt() - * Deliver the interrupt to one of the threads or all of the threads. - */ -static void ldsr_deliver_interrupt(int vector, - unsigned long deliver_to, - int all) -{ - unsigned long disabled_threads; - unsigned long possible_threads; - unsigned long trapped_threads; - unsigned long global_locks; - - /* - * Disable all of the threads that we might want to send - * this interrupt to. - */ -retry: - DEBUG_ASSERT(deliver_to); - thread_disable_mask(deliver_to); - - /* - * If any threads are in the trap state, we have to service the - * trap for those threads first. - */ - asm volatile ( - "move.4 %0, MT_TRAP \n\t" - : "=r" (trapped_threads) - : - ); - - trapped_threads &= deliver_to; - if (unlikely(trapped_threads)) { - /* - * all traps will be handled, so clear the trap bit before restarting any threads - */ - ubicom32_clear_interrupt(ldsr_trap_irq); - - /* - * Let the remaining untrapped threads, continue. - */ - deliver_to &= ~trapped_threads; - if (deliver_to) { - thread_enable_mask(deliver_to); - } - - /* - * For the trapped threads force them to handle - * a trap. - */ - while (trapped_threads) { - unsigned long which = ffz(~trapped_threads); - trapped_threads &= ~(1 << which); - ldsr_ctxsw_thread(vector, which); - } - return; - } - - /* - * Can we deliver an interrupt to any of the threads? - */ - disabled_threads = ldsr_thread_get_interrupts(); - possible_threads = deliver_to & ~disabled_threads; - if (unlikely(!possible_threads)) { -#if defined(CONFIG_SMP) - /* - * In the SMP case, we can not wait because 1 cpu might be - * sending an IPI to another cpu which is currently blocked. - * The only way to ensure IPI delivery is to backout and - * keep trying. For SMP, we don't sleep until the interrupts - * are delivered. - */ - thread_enable_mask(deliver_to); - ldsr_backout_of_irq(vector, deliver_to); - return; -#else - /* - * In the UP case, we have nothing to do so we should wait. - * - * Since the INT_MASK0 and INT_MASK1 are "re-loaded" before we - * suspend in the outer loop, we do not need to save them here. - * - * We test that we were awakened for our specific interrupts - * because the ldsr mask/unmask operations will force the ldsr - * awake even if the interrupt on the mainline thread is not - * completed. - */ - unsigned int scratch = 0; - thread_enable_mask(deliver_to); - asm volatile ( - " move.4 INT_MASK0, %1 \n\t" - " move.4 INT_MASK1, #0 \n\t" - - "1: suspend \n\t" - " move.4 %0, INT_STAT0 \n\t" - " and.4 %0, %0, %1 \n\t" - " jmpeq.f 1b \n\t" - - " move.4 INT_CLR0, %2 \n\t" - : "+r" (scratch) - : "d" (ldsr_suspend_mask), "r" (ldsr_soft_irq_mask) - : "cc" - ); - - /* - * This delay is sized to coincide with the time it takes a - * thread to complete the exit (see return_from_interrupt). - */ - ldsr_interrupt.retry++; - __delay(10); - goto retry; -#endif - } - - /* - * If any of the global locks are held, we can not deliver any - * interrupts, we spin delay(10) and then try again. If our - * spinning becomes a bottle neck, we will need to suspend but for - * now lets just spin. - */ - asm volatile ( - "move.4 %0, scratchpad1 \n\t" - : "=r" (global_locks) - : - ); - if (unlikely(global_locks & 0xffff0000)) { - thread_enable_mask(deliver_to); - - /* - * This delay is sized to coincide with the average time it - * takes a thread to release a global lock. - */ - ldsr_interrupt.retry++; - __delay(10); - goto retry; - } - - /* - * Deliver to one cpu. - */ - if (!all) { - /* - * Find our victim and then enable everyone else. - */ - unsigned long victim = ldsr_rotate_threads(possible_threads); - DEBUG_ASSERT((deliver_to & (1 << victim))); - DEBUG_ASSERT((possible_threads & (1 << victim))); - - deliver_to &= ~(1 << victim); - if (deliver_to) { - thread_enable_mask(deliver_to); - } - ldsr_ctxsw_thread(vector, victim); - return; - } - - /* - * If we can't deliver to some threads, wake them - * back up and reset things to deliver to them. - */ - deliver_to &= ~possible_threads; - if (unlikely(deliver_to)) { - thread_enable_mask(deliver_to); - ldsr_backout_of_irq(vector, deliver_to); - } - - /* - * Deliver to all possible threads(s). - */ - while (possible_threads) { - unsigned long victim = ffz(~possible_threads); - possible_threads &= ~(1 << victim); - ldsr_ctxsw_thread(vector, victim); - } -} - -/* - * ldsr_thread() - * This thread acts as the interrupt controller for Linux. - */ -static void ldsr_thread(void *arg) -{ - int stat0; - int stat1; - int interrupt0; - int interrupt1; - long long interrupts; - unsigned long cpus; - -#if !defined(CONFIG_SMP) - /* - * In a non-smp configuration, we can not use the cpu(s) arrays because - * there is not a 1-1 correspondence between cpus(s) and our threads. - * Thus we must get a local idea of the mainline threads and use the - * one and only 1 set as the victim. We do this once before the ldsr - * loop. - * - * In the SMP case, we will use the cpu(s) map to determine which cpu(s) - * are valid to send interrupts to. - */ - int victim = 0; - unsigned int mainline = thread_get_mainline(); - if (mainline == 0) { - panic("no mainline Linux threads to interrupt"); - return; - } - victim = ffz(~mainline); - cpus = (1 << victim); -#endif - - while (1) { - /* - * If one changes this code not to reload the INT_MASK(s), you - * need to know that code in the lock waiting above does not - * reset the MASK registers back; so that code will need to be - * changed. - */ - ldsr_lock_acquire(); - asm volatile ( - " move.4 INT_MASK0, %0 \n\t" - " move.4 INT_MASK1, %1 \n\t" - : - : "U4" (ldsr_interrupt.mask0), "U4" (ldsr_interrupt.mask1) - ); - ldsr_lock_release(); - thread_suspend(); - - /* - * Read the interrupt status registers - */ - asm volatile ( - "move.4 %0, INT_STAT0 \n\t" - "move.4 %1, INT_STAT1 \n\t" - : "=r" (stat0), "=r" (stat1) - : - ); - - /* - * We only care about interrupts that we have been told to care - * about. The interrupt must be enabled, unmasked, and have - * occurred in the hardware. - */ - ldsr_lock_acquire(); - interrupt0 = ldsr_interrupt.enabled0 & - ldsr_interrupt.mask0 & stat0; - interrupt1 = ldsr_interrupt.enabled1 & - ldsr_interrupt.mask1 & stat1; - ldsr_lock_release(); - - /* - * For each interrupt in the "snapshot" we will mask the - * interrupt handle the interrupt (typically calling do_IRQ()). - * - * The interrupt is unmasked by desc->chip->end() function in - * the per chip generic interrupt handling code - * (arch/ubicom32/kernel/irq.c).8 - */ - interrupts = ((unsigned long long)interrupt1 << 32) | - interrupt0; - while (interrupts) { - int all = 0; - int vector = ldsr_rotate_interrupts(interrupts); - interrupts &= ~((unsigned long long)1 << vector); - - /* - * Now mask off this vector so that the LDSR ignores - * it until it is acknowledged. - */ - ldsr_mask_vector(vector); -#if !defined(CONFIG_SMP) - ldsr_deliver_interrupt(vector, cpus, all); -#else - cpus = smp_get_affinity(vector, &all); - if (!cpus) { - /* - * No CPU to deliver to so just leave - * the interrupt unmasked and increase - * the backout count. We will eventually - * return and deliver it again. - */ - ldsr_unmask_vector(vector); - ldsr_interrupt.backout++; - continue; - } - ldsr_deliver_interrupt(vector, cpus, all); -#endif - } - } - - /* NOTREACHED */ -} - -/* - * ldsr_mask_vector() - * Temporarily mask the interrupt vector, turn off the bit in the mask - * register. - */ -void ldsr_mask_vector(unsigned int vector) -{ - unsigned int mask; - if (vector < 32) { - mask = ~(1 << vector); - ldsr_lock_acquire(); - ldsr_interrupt.mask0 &= mask; - ldsr_lock_release(); - thread_resume(ldsr_tid); - return; - } - - mask = ~(1 << (vector - 32)); - ldsr_lock_acquire(); - ldsr_interrupt.mask1 &= mask; - ldsr_lock_release(); - thread_resume(ldsr_tid); -} - -/* - * ldsr_unmask_vector() - * Unmask the interrupt vector so that it can be used, turn on the bit in - * the mask register. - * - * Because it is legal for the interrupt path to disable an interrupt, - * the unmasking code must ensure that disabled interrupts are not - * unmasked. - */ -void ldsr_unmask_vector(unsigned int vector) -{ - unsigned int mask; - if (vector < 32) { - mask = (1 << vector); - ldsr_lock_acquire(); - ldsr_interrupt.mask0 |= (mask & ldsr_interrupt.enabled0); - ldsr_lock_release(); - thread_resume(ldsr_tid); - return; - } - - mask = (1 << (vector - 32)); - ldsr_lock_acquire(); - ldsr_interrupt.mask1 |= (mask & ldsr_interrupt.enabled1); - ldsr_lock_release(); - thread_resume(ldsr_tid); -} - -/* - * ldsr_enable_vector() - * The LDSR implements an interrupt controller and has a local (to the - * LDSR) copy of its interrupt mask. - */ -void ldsr_enable_vector(unsigned int vector) -{ - unsigned int mask; - if (vector < 32) { - mask = (1 << vector); - ldsr_lock_acquire(); - ldsr_interrupt.enabled0 |= mask; - ldsr_interrupt.mask0 |= mask; - ldsr_lock_release(); - thread_resume(ldsr_tid); - return; - } - - mask = (1 << (vector - 32)); - ldsr_lock_acquire(); - ldsr_interrupt.enabled1 |= mask; - ldsr_interrupt.mask1 |= mask; - ldsr_lock_release(); - thread_resume(ldsr_tid); -} - -/* - * ldsr_disable_vector() - * The LDSR implements an interrupt controller and has a local (to the - * LDSR) copy of its interrupt mask. - */ -void ldsr_disable_vector(unsigned int vector) -{ - unsigned int mask; - - if (vector < 32) { - mask = ~(1 << vector); - ldsr_lock_acquire(); - ldsr_interrupt.enabled0 &= mask; - ldsr_interrupt.mask0 &= mask; - ldsr_lock_release(); - thread_resume(ldsr_tid); - return; - } - - mask = ~(1 << (vector - 32)); - ldsr_lock_acquire(); - ldsr_interrupt.enabled1 &= mask; - ldsr_interrupt.mask1 &= mask; - ldsr_lock_release(); - thread_resume(ldsr_tid); -} - -/* - * ldsr_get_threadid() - * Return the threadid of the LDSR thread. - */ -thread_t ldsr_get_threadid(void) -{ - return ldsr_tid; -} - -/* - * ldsr_set_trap_irq() - * Save away the trap Soft IRQ - * - * See the per thread lock suspend code above for an explination. - */ -void ldsr_set_trap_irq(unsigned int irq) -{ - ldsr_trap_irq = irq; - ldsr_trap_irq_mask = (1 << irq); - ldsr_suspend_mask |= ldsr_trap_irq_mask; -} - -/* - * ldsr_init() - * Initialize the LDSR (Interrupt Controller) - */ -void ldsr_init(void) -{ -#if defined(CONFIG_IRQSTACKS) - int i; - union irq_ctx *icp; -#endif - - void *stack_high = (void *)ldsr_stack_space; - stack_high += sizeof(ldsr_stack_space); - stack_high -= 8; - - - /* - * Obtain a soft IRQ to use - */ - if (irq_soft_alloc(&ldsr_soft_irq) < 0) { - panic("no software IRQ is available\n"); - return; - } - ldsr_soft_irq_mask |= (1 << ldsr_soft_irq); - ldsr_suspend_mask |= ldsr_soft_irq_mask; - - /* - * Now allocate and start the LDSR thread. - */ - ldsr_tid = thread_alloc(); - if (ldsr_tid < 0) { - panic("no thread available to run LDSR"); - return; - } - -#if defined(CONFIG_IRQSTACKS) - /* - * Initialize the per-cpu irq thread_info structure that - * is at the top of each per-cpu irq stack. - */ - icp = (union irq_ctx *) - (((unsigned long)percpu_irq_stacks + (THREAD_SIZE - 1)) & ~(THREAD_SIZE - 1)); - for (i = 0; i < NR_CPUS; i++) { - struct thread_info *ti = &(icp->tinfo); - ti->task = NULL; - ti->exec_domain = NULL; - ti->cpu = i; - ti->preempt_count = 0; - ti->interrupt_nesting = 0; - percpu_irq_ctxs[i] = icp++; - } -#endif - thread_start(ldsr_tid, ldsr_thread, NULL, - stack_high, THREAD_TYPE_NORMAL); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c deleted file mode 100644 index 3d29dc2b83..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/module.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * arch/ubicom32/kernel/module.c - * Ubicom32 architecture loadable module support. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/moduleloader.h> -#include <linux/bug.h> -#include <linux/elf.h> -#include <linux/vmalloc.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/kernel.h> -#include <asm/ocm-alloc.h> - -#if 0 -#define DEBUGP printk -#else -#define DEBUGP(fmt...) -#endif - -static void _module_free_ocm(struct module *mod) -{ - printk(KERN_INFO "module arch cleanup %s: OCM instruction memory free " - " of %d @%p\n", mod->name, mod->arch.ocm_inst_size, - mod->arch.ocm_inst); - - if (mod->arch.ocm_inst) { - ocm_inst_free(mod->arch.ocm_inst); - mod->arch.ocm_inst = 0; - mod->arch.ocm_inst_size = 0; - } -} - -void *module_alloc(unsigned long size) -{ - if (size == 0) - return NULL; - return vmalloc(size); -} - - -/* Free memory returned from module_alloc */ -void module_free(struct module *mod, void *module_region) -{ - vfree(module_region); - /* FIXME: If module_region == mod->init_region, trim exception - table entries. */ - - /* - * This is expected to be final module free, use this to prune the - * ocm - */ - if (module_region && module_region == mod->module_core) - _module_free_ocm(mod); - -} - -/* - * module_frob_arch_sections() - * Called from kernel/module.c allowing arch specific handling of - * sections/headers. - */ -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod) -{ - Elf_Shdr *s, *sechdrs_end; - void *ocm_inst = NULL; - int ocm_inst_size = 0; - - /* - * Ubicom32 v3 and v4 are almost binary compatible but not completely. - * To be safe check that the module was compiled with the correct -march - * which is flags. - */ -#ifdef CONFIG_UBICOM32_V4 - if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V4) { - printk(KERN_WARNING "Module %s was not compiled for " - "ubicom32v4, elf_flags:%x,\n", - mod->name, hdr->e_flags); - return -ENOEXEC; - } -#elif defined CONFIG_UBICOM32_V3 - if ((hdr->e_flags & 0xFFFF) != EF_UBICOM32_V3) { - printk(KERN_WARNING "Module %s was not compiled for " - "ubicom32v3, elf_flags:%x\n", - mod->name, hdr->e_flags); - return -ENOEXEC; - } -#else -#error Unknown/Unsupported ubicom32 architecture. -#endif - - /* - * XXX: sechdrs are vmalloced in kernel/module.c - * and would be vfreed just after module is loaded, - * so we hack to keep the only information we needed - * in mod->arch to correctly free L1 I/D sram later. - * NOTE: this breaks the semantic of mod->arch structure. - */ - sechdrs_end = sechdrs + hdr->e_shnum; - for (s = sechdrs; s < sechdrs_end; ++s) { - if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) - ocm_inst_size += s->sh_size; - } - - if (!ocm_inst_size) - return 0; - - ocm_inst = ocm_inst_alloc(ocm_inst_size, 0 /* internal */); - if (ocm_inst == NULL) { -#ifdef CONFIG_OCM_MODULES_FALLBACK_TO_DDR - printk(KERN_WARNING - "module %s: OCM instruction memory allocation of %d" - "failed, fallback to DDR\n", mod->name, ocm_inst_size); - return 0; -#else - printk(KERN_ERR - "module %s: OCM instruction memory allocation of %d" - "failed.\n", mod->name, ocm_inst_size); - return -ENOMEM; -#endif - } - - mod->arch.ocm_inst = ocm_inst; - mod->arch.ocm_inst_size = ocm_inst_size; - - printk(KERN_INFO - "module %s: OCM instruction memory allocation of %d @%p\n", - mod->name, mod->arch.ocm_inst_size, mod->arch.ocm_inst); - - for (s = sechdrs; s < sechdrs_end; ++s) { - if (strncmp(".ocm_text", secstrings + s->sh_name, 9) == 0) { - memcpy(ocm_inst, (void *)s->sh_addr, s->sh_size); - s->sh_flags &= ~SHF_ALLOC; - s->sh_addr = (unsigned long)ocm_inst; - ocm_inst += s->sh_size; - } - } - - return 0; -} - -int apply_relocate(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - DEBUGP("Invalid Applying relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - return -EINVAL; -} - -int apply_relocate_add(Elf32_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; - Elf32_Sym *sym; - uint32_t *location; - uint32_t insn; - - DEBUGP("Applying relocate_add section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { - uint32_t v; - const int elf32_rtype = ELF32_R_TYPE(rel[i].r_info); - - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; - /* This is the symbol it is referring to. Note that all - undefined symbols have been resolved. */ - sym = (Elf32_Sym *)sechdrs[symindex].sh_addr - + ELF32_R_SYM(rel[i].r_info); - - v = rel[i].r_addend + sym->st_value; - - - switch (elf32_rtype) { - case R_UBICOM32_32: - { - /* - * Store the 32 bit relocation as is. - */ - *location = v; - break; - } - case R_UBICOM32_HI24: - { - /* - * 24 bit relocation that is part of the MOVEAI - * instruction. The 24 bits come from bits 7 - 30 of the - * relocation. Theses bits eventually get split into 2 - * fields in the instruction encoding. - * - * - Bits 7 - 27 of the relocation are encoded into bits - * 0 - 20 of the instruction. - * - * - Bits 28 - 30 of the relocation are encoded into - * bit 24 - 26 of the instruction. - */ - uint32_t valid24 = (v >> 7) & 0xffffff; - insn = *location; - - insn &= ~(0x1fffff | (0x7 << 24)); - insn |= (valid24 & 0x1fffff); - insn |= ((valid24 & 0xe00000) << 3); - *location = insn; - } - break; - case R_UBICOM32_LO7_S: - case R_UBICOM32_LO7_2_S: - case R_UBICOM32_LO7_4_S: - { - /* - * Bits 0 - 6 of the relocation are encoded into the - * 7bit unsigned immediate fields of the SOURCE-1 field - * of the instruction. The immediate value is left - * shifted by (0, 1, 2) based on the operand size. - */ - uint32_t valid7 = v & 0x7f; - insn = *location; - - if (elf32_rtype == R_UBICOM32_LO7_2_S) { - valid7 >>= 1; - } else if (elf32_rtype == R_UBICOM32_LO7_4_S) { - valid7 >>= 2; - } - - insn &= ~(0x1f | (0x3 << 8)); - insn |= (valid7 & 0x1f); - insn |= ((valid7 & 0x60) << 3); - *location = insn; - } - break; - case R_UBICOM32_LO7_D: - case R_UBICOM32_LO7_2_D: - case R_UBICOM32_LO7_4_D: - { - /* - * Bits 0 - 6 of the relocation are encoded into the - * 7bit unsigned immediate fields of the DESTINATION - * field of the instruction. The immediate value is - * left shifted by (0, 1, 2) based on the operand size. - */ - uint32_t valid7 = v & 0x7f; - insn = *location; - - if (elf32_rtype == R_UBICOM32_LO7_2_D) { - valid7 >>= 1; - } else if (elf32_rtype == R_UBICOM32_LO7_4_D) { - valid7 >>= 2; - } - - insn &= ~((0x1f | (0x3 << 8)) << 16); - insn |= ((valid7 & 0x1f) << 16); - insn |= ((valid7 & 0x60) << 19); - *location = insn; - } - break; - case R_UBICOM32_LO7_CALLI: - case R_UBICOM32_LO16_CALLI: - { - /* - * Extract the offset for a CALLI instruction. The - * offsets can be either 7 bits or 18 bits. Since all - * instructions in ubicom32 architecture are at work - * aligned addresses the truncated offset is right - * shifted by 2 before being encoded in the instruction. - */ - uint32_t val; - if (elf32_rtype == R_UBICOM32_LO7_CALLI) { - val = v & 0x7f; - } else { - val = v & 0x3ffff; - } - - val >>= 2; - - insn = *location; - - insn &= ~0x071f071f; - insn |= (val & 0x1f) << 0; - val >>= 5; - insn |= (val & 0x07) << 8; - val >>= 3; - insn |= (val & 0x1f) << 16; - val >>= 5; - insn |= (val & 0x07) << 24; - *location = insn; - } - break; - case R_UBICOM32_24_PCREL: - { - /* - * Extract 26 bit signed PC relative offset for CALL - * instructions. Since instruction addresses are word - * aligned the offset is right shited by 2 before - * encoding into instruction. - */ - int32_t val = v - (int32_t)location; - - /* - * Check that the top 7 bits are all equal to the sign - * bit (26), i.e all 0's or all 1's. If they are not then - * the absolute difference is greater than 25 bits. - */ - if (((uint32_t)val & 0xFE000000) != 0xFE000000 && - ((uint32_t)val & 0xFE000000) != 0x0) { - /* - * The relocation is beyond our addressable - * range with a 26 bit call. - */ - printk(KERN_ERR "module %s: PC Relative " - "relocation out of range: " - "%u (%x->%x, %x)\n", - me->name, elf32_rtype, - v, (uint32_t) location, val); - return -ENOEXEC; - } - - val = (val & 0x3ffffff) >> 2; - insn = *location; - insn = insn & 0xf8e00000; - - insn |= (val >> 21) << 24; - insn |= (val & 0x1fffff); - *location = insn; - } - break; - case R_UBICOM32_LO16: - case R_UBICOM32_HI16: - { - /* - * 16 bit immediate value that is encoded into bit 0 - - * 15 of the instruction. - */ - uint32_t val; - - if (elf32_rtype == R_UBICOM32_LO16) { - val = v & 0xffff; - } else { - val = (v >> 16) & 0xffff; - } - - insn = *location; - insn &= 0xffff0000; - - insn |= val; - *location = insn; - } - break; - case R_UBICOM32_21_PCREL: - { - /* - * Extract 23 bit signed PC relative offset for JMP<cc> - * instructions. Since instruction addresses are word - * aligned the offset is right shited by 2 before - * encoding into instruction. - */ - int32_t val = v - (int32_t)location; - - val = (val & 0x7fffff) >> 2; - insn = *location; - insn = insn & 0xffe00000; - - insn |= (val >> 21) << 24; - insn |= val; - *location = insn; - } - break; - default: - BUG(); - printk(KERN_ERR "module %s: Unknown relocation: %u\n", - me->name, elf32_rtype); - return -ENOEXEC; - } - } - return 0; -} - -int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *mod) -{ - unsigned int i, strindex = 0, symindex = 0; - char *secstrings; - int err; - - err = module_bug_finalize(hdr, sechdrs, mod); - if (err) - return err; - - if (!mod->arch.ocm_inst) { - /* - * No OCM code, so nothing more to do. - */ - return 0; - } - - secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; - - for (i = 1; i < hdr->e_shnum; i++) { - /* Internal symbols and strings. */ - if (sechdrs[i].sh_type == SHT_SYMTAB) { - symindex = i; - strindex = sechdrs[i].sh_link; - } - } - - for (i = 1; i < hdr->e_shnum; i++) { - const char *strtab = (char *)sechdrs[strindex].sh_addr; - unsigned int info = sechdrs[i].sh_info; - - /* Not a valid relocation section? */ - if (info >= hdr->e_shnum) - continue; - - if ((sechdrs[i].sh_type == SHT_RELA) && - (strncmp(".rela.ocm_text", - secstrings + sechdrs[i].sh_name, 5 + 9) == 0)) { - err = apply_relocate_add((Elf_Shdr *) sechdrs, strtab, - symindex, i, mod); - if (err) - return err; - } - } - - return 0; -} - -void module_arch_cleanup(struct module *mod) -{ - module_bug_cleanup(mod); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c deleted file mode 100644 index 9e014d5cb0..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/os_node.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * arch/ubicom32/kernel/os_node.c - * <TODO: Replace with short file description> - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - */ -#include "linux/types.h" -#include "linux/linkage.h" -#include "linux/uts.h" -#include "linux/utsrelease.h" -#include "linux/version.h" -#include <asm/ocm_size.h> -#include <asm/devtree.h> -#include <asm/ip5000.h> - -extern asmlinkage void *_start; - -/* - * This file provides static information to the boot code allowing it to decide - * if the os is compatible. Thus hopefully enabling the boot code to prevent - * accidentally booting a kernel that has no hope of running. - */ -struct os_node { - struct devtree_node node; - unsigned long version; /* Always 1 */ - unsigned long entry_point; - const char os_name[32]; /* For diagnostic purposes only */ - const char os_version_str[32]; - unsigned long os_version_num; - unsigned long expected_ocm_code_start;/* OS Code */ - unsigned long expected_ocm_data_end; /* OS Data */ - unsigned long expected_ram_start; - unsigned long expected_ram_end; - unsigned long arch_version; - unsigned long expected_os_syscall_begin; - unsigned long expected_os_syscall_end; -}; - - -extern void __os_syscall_begin; -extern void __os_syscall_end; -/* - * The os_node is only referenced by head.S and should never be modified at - * run-time. - */ -asmlinkage const struct os_node _os_node = { - .node = { - .next = NULL, - .name = { "OS" }, - .magic = 0x10203040, - }, - .version = 0x10002, - .entry_point = (unsigned long)&_start, -#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE - .expected_ocm_code_start = OCMSTART + APP_OCM_CODE_SIZE, - .expected_ocm_data_end = OCMEND - APP_OCM_DATA_SIZE, -#else - .expected_ocm_code_start = OCMEND, - .expected_ocm_data_end = OCMEND, -#endif - .os_name = { UTS_SYSNAME }, - .os_version_str = { UTS_RELEASE }, - .os_version_num = LINUX_VERSION_CODE, - .expected_ram_start = KERNELSTART, - .expected_ram_end = SDRAMSTART + CONFIG_MIN_RAMSIZE, - .arch_version = UBICOM32_ARCH_VERSION, - .expected_os_syscall_begin = (unsigned long)&__os_syscall_begin, - .expected_os_syscall_end = (unsigned long)&__os_syscall_end, - - -}; diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c deleted file mode 100644 index 23872fed0f..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/process.c +++ /dev/null @@ -1,634 +0,0 @@ -/* - * arch/ubicom32/kernel/process.c - * Ubicom32 architecture-dependent process handling. - * - * (C) Copyright 2009, Ubicom, Inc. - * Copyright (C) 1995 Hamish Macdonald - * - * 68060 fixes by Jesper Skov - * - * uClinux changes - * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com> - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/fs.h> -#include <linux/pm.h> - -#include <linux/uaccess.h> -#include <asm/system.h> -#include <asm/traps.h> -#include <asm/machdep.h> -#include <asm/setup.h> -#include <asm/pgtable.h> -#include <asm/ip5000.h> -#include <asm/range-protect.h> - -#define DUMP_RANGE_REGISTER(REG, IDX) asm volatile ( \ - " move.4 %0, "REG"_RANGE"IDX"_EN \n\t" \ - " move.4 %1, "REG"_RANGE"IDX"_LO \n\t" \ - " move.4 %2, "REG"_RANGE"IDX"_HI \n\t" \ - : "=d"(en), "=d"(lo), "=d"(hi) \ - ); \ - printk(KERN_NOTICE REG"Range"IDX": en:%08x, range: %08x-%08x\n", \ - (unsigned int)en, \ - (unsigned int)lo, \ - (unsigned int)hi) - -asmlinkage void ret_from_fork(void); - -void (*pm_power_off)(void) = machine_power_off; -EXPORT_SYMBOL(pm_power_off); - -/* machine-dependent / hardware-specific power functions */ -void (*mach_reset)(void); -void (*mach_halt)(void); -void (*mach_power_off)(void); - -/* - * cpu_idle() - * The idle thread. - * - * Our idle loop suspends and is woken up by a timer interrupt. - */ -void cpu_idle(void) -{ - while (1) { - local_irq_disable(); - while (!need_resched()) { - local_irq_enable(); - thread_suspend(); - local_irq_disable(); - } - local_irq_enable(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } -} - -/* - * dump_fpu() - * - * Fill in the fpu structure for a core dump. (just a stub as we don't have - * an fpu) - */ -int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs) -{ - return 1; -} - -/* - * machine_restart() - * Resets the system. - */ -void machine_restart(char *__unused) -{ - /* - * Disable all threads except myself. We can do this - * directly without needing to call smp_send_stop - * because we have a unique architecture where - * one thread can disable one or more other threads. - */ - thread_disable_others(); - - /* - * Call the hardware-specific machine reset function. - */ - if (mach_reset) { - mach_reset(); - } - - printk(KERN_EMERG "System Restarting\n"); - - /* - * Set watchdog to trigger (after 1ms delay) (12 Mhz is the fixed OSC) - */ - UBICOM32_IO_TIMER->tkey = TIMER_TKEYVAL; - UBICOM32_IO_TIMER->wdcom = UBICOM32_IO_TIMER->mptval + - (12000000 / 1000); - UBICOM32_IO_TIMER->wdcfg = 0; - UBICOM32_IO_TIMER->tkey = 0; - - /* - * Wait for watchdog - */ - asm volatile ( - " move.4 MT_EN, #0 \n\t" - " pipe_flush 0 \n\t" - ); - - local_irq_disable(); - for (;;) { - thread_suspend(); - } -} - -/* - * machine_halt() - * Halt the machine. - * - * Similar to machine_power_off, but don't shut off power. Add code - * here to freeze the system for e.g. post-mortem debug purpose when - * possible. This halt has nothing to do with the idle halt. - */ -void machine_halt(void) -{ - /* - * Disable all threads except myself. We can do this - * directly without needing to call smp_send_stop - * because we have a unique architecture where - * one thread can disable one or more other threads. - */ - thread_disable_others(); - - /* - * Call the hardware-specific machine halt function. - */ - if (mach_halt) { - mach_halt(); - } - - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - for (;;) { - thread_suspend(); - } -} - -/* - * machine_power_off() - * Turn the power off, if a power off handler is defined, otherwise, spin - * endlessly. - */ -void machine_power_off(void) -{ - /* - * Disable all threads except myself. We can do this - * directly without needing to call smp_send_stop - * because we have a unique architecture where - * one thread can disable one or more other threads. - */ - thread_disable_others(); - - /* - * Call the hardware-specific machine power off function. - */ - if (mach_power_off) { - mach_power_off(); - } - - printk(KERN_EMERG "System Halted, OK to turn off power\n"); - local_irq_disable(); - for (;;) { - thread_suspend(); - } -} - -/* - * address_is_valid() - * check if an address is valid -- (for read access) - */ -static bool address_is_valid(const void *address) -{ - int addr = (int)address; - unsigned long socm, eocm, sdram, edram; - - if (addr & 3) - return false; - - processor_ocm(&socm, &eocm); - processor_dram(&sdram, &edram); - if (addr >= socm && addr < eocm) - return true; - - if (addr >= sdram && addr < edram) - return true; - - return false; -} - -/* - * vma_path_name_is_valid() - * check if path_name of a vma is a valid string - */ -static bool vma_path_name_is_valid(const char *str) -{ -#define MAX_NAME_LEN 256 - int i = 0; - if (!address_is_valid(str)) - return false; - - for (; i < MAX_NAME_LEN; i++, str++) { - if (*str == '\0') - return true; - } - - return false; -} - -/* - * show_vmas() - * show vma info of a process - */ -void show_vmas(struct task_struct *task) -{ -#ifdef CONFIG_DEBUG_VERBOSE -#define UBICOM32_MAX_VMA_COUNT 1024 - - struct vm_area_struct *vma; - struct file *file; - char *name = ""; - int flags, loop = 0; - - printk(KERN_NOTICE "Start of vma list\n"); - - if (!address_is_valid(task) || !address_is_valid(task->mm)) - goto error; - - vma = task->mm->mmap; - while (vma) { - if (!address_is_valid(vma)) - goto error; - - flags = vma->vm_flags; - file = vma->vm_file; - - if (file) { - /* seems better to use dentry op here, but sanity check is easier this way */ - if (!address_is_valid(file) || !address_is_valid(file->f_path.dentry) || !vma_path_name_is_valid(file->f_path.dentry->d_name.name)) - goto error; - - name = (char *)file->f_path.dentry->d_name.name; - } - - /* Similar to /proc/pid/maps format */ - printk(KERN_NOTICE "%08lx-%08lx %c%c%c%c %08lx %s\n", - vma->vm_start, - vma->vm_end, - flags & VM_READ ? 'r' : '-', - flags & VM_WRITE ? 'w' : '-', - flags & VM_EXEC ? 'x' : '-', - flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', - vma->vm_pgoff << PAGE_SHIFT, - name); - - vma = vma->vm_next; - - if (loop++ > UBICOM32_MAX_VMA_COUNT) - goto error; - } - - printk(KERN_NOTICE "End of vma list\n"); - return; - -error: - printk(KERN_NOTICE "\nCorrupted vma list, abort!\n"); -#endif -} - -/* - * show_regs() - * Print out all of the registers. - */ -void show_regs(struct pt_regs *regs) -{ - unsigned int i; - unsigned int en, lo, hi; - - printk(KERN_NOTICE "regs: %p, tid: %d\n", - (void *)regs, - thread_get_self()); - - printk(KERN_NOTICE "pc: %08x, previous_pc: %08x\n\n", - (unsigned int)regs->pc, - (unsigned int)regs->previous_pc); - - printk(KERN_NOTICE "Data registers\n"); - for (i = 0; i < 16; i++) { - printk("D%02d: %08x, ", i, (unsigned int)regs->dn[i]); - if ((i % 4) == 3) { - printk("\n"); - } - } - printk("\n"); - - printk(KERN_NOTICE "Address registers\n"); - for (i = 0; i < 8; i++) { - printk("A%02d: %08x, ", i, (unsigned int)regs->an[i]); - if ((i % 4) == 3) { - printk("\n"); - } - } - printk("\n"); - - printk(KERN_NOTICE "acc0: %08x-%08x, acc1: %08x-%08x\n", - (unsigned int)regs->acc0[1], - (unsigned int)regs->acc0[0], - (unsigned int)regs->acc1[1], - (unsigned int)regs->acc1[0]); - - printk(KERN_NOTICE "mac_rc16: %08x, source3: %08x\n", - (unsigned int)regs->mac_rc16, - (unsigned int)regs->source3); - - printk(KERN_NOTICE "inst_cnt: %08x, csr: %08x\n", - (unsigned int)regs->inst_cnt, - (unsigned int)regs->csr); - - printk(KERN_NOTICE "int_mask0: %08x, int_mask1: %08x\n", - (unsigned int)regs->int_mask0, - (unsigned int)regs->int_mask1); - - /* - * Dump range registers - */ - DUMP_RANGE_REGISTER("I", "0"); - DUMP_RANGE_REGISTER("I", "1"); - DUMP_RANGE_REGISTER("I", "2"); - DUMP_RANGE_REGISTER("I", "3"); - DUMP_RANGE_REGISTER("D", "0"); - DUMP_RANGE_REGISTER("D", "1"); - DUMP_RANGE_REGISTER("D", "2"); - DUMP_RANGE_REGISTER("D", "3"); - DUMP_RANGE_REGISTER("D", "4"); - - printk(KERN_NOTICE "frame_type: %d, nesting_level: %d, thread_type %d\n\n", - (int)regs->frame_type, - (int)regs->nesting_level, - (int)regs->thread_type); -} - -/* - * kernel_thread_helper() - * On execution d0 will be 0, d1 will be the argument to be passed to the - * kernel function. d2 contains the kernel function that needs to get - * called. d3 will contain address to do_exit which need to get moved - * into a5. On return from fork the child thread d0 will be 0. We call - * this dummy function which in turn loads the argument - */ -asmlinkage void kernel_thread_helper(void); - -/* - * kernel_thread() - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) -{ - struct pt_regs regs; - - memset(®s, 0, sizeof(regs)); - - regs.dn[1] = (unsigned long)arg; - regs.dn[2] = (unsigned long)fn; - regs.dn[3] = (unsigned long)do_exit; - regs.an[5] = (unsigned long)kernel_thread_helper; - regs.pc = (unsigned long)kernel_thread_helper; - regs.nesting_level = 0; - regs.thread_type = KERNEL_THREAD; - - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, - 0, ®s, 0, NULL, NULL); -} -EXPORT_SYMBOL(kernel_thread); - -/* - * flush_thread() - * XXX todo - */ -void flush_thread(void) -{ - /* XXX todo */ -} - -/* - * sys_fork() - * Not implemented on no-mmu. - */ -asmlinkage int sys_fork(struct pt_regs *regs) -{ - /* fork almost works, enough to trick you into looking elsewhere :-( */ - return -EINVAL; -} - -/* - * sys_vfork() - * By the time we get here, the non-volatile registers have also been saved - * on the stack. We do some ugly pointer stuff here.. (see also copy_thread - * which does context copy). - */ -asmlinkage int sys_vfork(struct pt_regs *regs) -{ - unsigned long old_sp = regs->an[7]; - unsigned long old_a5 = regs->an[5]; - unsigned long old_return_address; - long do_fork_return; - - /* - * Read the old retrun address from the stack. - */ - if (copy_from_user(&old_return_address, - (void *)old_sp, sizeof(unsigned long))) { - force_sig(SIGSEGV, current); - return 0; - } - - /* - * Pop the vfork call frame by setting a5 and pc to the old_return - * address and incrementing the stack pointer by 4. - */ - regs->an[5] = old_return_address; - regs->pc = old_return_address; - regs->an[7] += 4; - - do_fork_return = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, - regs->an[7], regs, 0, NULL, NULL); - - /* - * Now we have to test if the return code is an error. If it is an error - * then restore the frame and we will execute error processing in user - * space. Other wise the child and the parent will return to the correct - * places. - */ - if ((unsigned long)(do_fork_return) >= (unsigned long)(-125)) { - /* - * Error case. We need to restore the frame. - */ - regs->an[5] = old_a5; - regs->pc = old_a5; - regs->an[7] = old_sp; - } - - return do_fork_return; -} - -/* - * sys_clone() - * creates a child thread. - */ -asmlinkage int sys_clone(unsigned long clone_flags, - unsigned long newsp, - struct pt_regs *regs) -{ - if (!newsp) - newsp = regs->an[7]; - return do_fork(clone_flags, newsp, regs, 0, - NULL, NULL); -} - -/* - * copy_thread() - * low level thread copy, only used by do_fork in kernel/fork.c - */ -int copy_thread(unsigned long clone_flags, - unsigned long usp, unsigned long topstk, - struct task_struct *p, struct pt_regs *regs) - -{ - struct pt_regs *childregs; - - childregs = (struct pt_regs *) - (task_stack_page(p) + THREAD_SIZE - 8) - 1; - - *childregs = *regs; - - /* - * Set return value for child to be 0. - */ - childregs->dn[0] = 0; - - if (usp) - childregs->an[7] = usp; - else - childregs->an[7] = (unsigned long)task_stack_page(p) + - THREAD_SIZE - 8; - - /* - * Set up the switch_to frame to return to "ret_from_fork" - */ - p->thread.a5 = (unsigned long)ret_from_fork; - p->thread.sp = (unsigned long)childregs; - - return 0; -} - -/* - * sys_execve() - * executes a new program. - */ -asmlinkage int sys_execve(char *name, char **argv, - char **envp, struct pt_regs *regs) -{ - int error; - char *filename; - - lock_kernel(); - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); - asm (" .global sys_execve_complete\n" - " sys_execve_complete:"); -out: - unlock_kernel(); - return error; -} - -/* - * Return saved PC of a blocked thread. - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - return tsk->thread.a5; -} - - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long pc; - - /* - * If we don't have a process, or it is not the current - * one or not RUNNING, it makes no sense to ask for a - * wchan. - */ - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - /* - * TODO: If the process is in the middle of schedule, we - * are supposed to do something different but for now we - * will return the same thing in both situations. - */ - pc = thread_saved_pc(p); - if (in_sched_functions(pc)) - return pc; - return pc; -} - - -/* - * Infrequently used interface to dump task registers to core files. - */ -int dump_task_regs(struct task_struct *task, elf_gregset_t *elfregs) -{ - struct pt_regs *regs = task_pt_regs(task); - *(struct pt_regs *)elfregs = *regs; - - return 1; -} - -/* - * __switch_to is the function that implements the contex save and - * switch within the kernel. Since this is a function call very few - * registers have to be saved to pull this off. d0 holds prev and we - * want to preserve it. prev_switch is a pointer to task->thread - * structure. This is where we will save the register state. next_switch - * is pointer to the next task's thread structure that holds the - * registers. - */ -asmlinkage void *__switch_to(struct task_struct *prev, - struct thread_struct *prev_switch, - struct thread_struct *next_switch) - __attribute__((naked)); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c deleted file mode 100644 index 55d1bdf623..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/processor.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * arch/ubicom32/kernel/processor.c - * Ubicom32 architecture processor info implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/profile.h> -#include <linux/clocksource.h> -#include <linux/types.h> -#include <linux/seq_file.h> -#include <linux/delay.h> -#include <linux/cpu.h> -#include <asm/devtree.h> -#include <asm/processor.h> -#include <asm/cpu.h> -#include <asm/ocm_size.h> - -struct procnode { - struct devtree_node dn; - unsigned int threads; - unsigned int timers; - unsigned int frequency; - unsigned int ddr_frequency; - unsigned int interrupt0; - unsigned int interrupt1; - void *socm; - void *eocm; - void *sdram; - void *edram; - unsigned int arch_version; - void *os_syscall_begin; - void *os_syscall_end; -}; - -struct procnode *pn; - -/* - * show_processorinfo() - * Print the actual processor information. - */ -static void show_processorinfo(struct seq_file *m) -{ - char *cpu, *mmu, *fpu; - unsigned int clockfreq; - unsigned int chipid; - - cpu = CPU; - mmu = "none"; - fpu = "none"; - - asm volatile ( - "move.4 %0, CHIP_ID \n\t" - : "=r" (chipid) - ); - - /* - * General Processor Information. - */ - seq_printf(m, "Vendor:\t\t%s\n", "Ubicom"); - seq_printf(m, "CPU:\t\t%s\n", cpu); - seq_printf(m, "MMU:\t\t%s\n", mmu); - seq_printf(m, "FPU:\t\t%s\n", fpu); - seq_printf(m, "Arch:\t\t%hx\n", chipid >> 16); - seq_printf(m, "Rev:\t\t%hx\n", (chipid & 0xffff)); - - /* - * Now compute the clock frequency in Mhz. - */ - clockfreq = processor_frequency(); - seq_printf(m, "Clock Freq:\t%u.0 MHz\n", - clockfreq / 1000000); - seq_printf(m, "DDR Freq:\t%u.0 MHz\n", - pn ? pn->ddr_frequency / 1000000 : 0); - seq_printf(m, "BogoMips:\t%lu.%02lu\n", - (loops_per_jiffy * HZ) / 500000, - ((loops_per_jiffy * HZ) / 5000) % 100); - seq_printf(m, "Calibration:\t%lu loops\n", (loops_per_jiffy * HZ)); -} - -/* - * show_cpuinfo() - * Get CPU information for use by the procfs. - */ -static int show_cpuinfo(struct seq_file *m, void *v) -{ - unsigned long n = (unsigned long)v - 1; - -#if defined(CONFIG_SMP) - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, n); -#endif - - /* - * Print the general processor information on the first - * call. - */ - if (n == 0) { - show_processorinfo(m); - } - -#if defined(CONFIG_SMP) - /* - * For each hwthread, print if this hwthread is running Linux - * or is an I/O thread. - */ - if (cpu_isset(n, cpu_online_map)) { - seq_printf(m, "cpu[%02lu]:\tthread id - %lu\n", n, p->tid); - } else { - seq_printf(m, "cpu[%02lu]:\toff-line\n", n); - } -#endif - return 0; - -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - unsigned long i = *pos; - - return i < NR_CPUS ? (void *)(i + 1) : NULL; -} - -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} - -static void c_stop(struct seq_file *m, void *v) -{ -} - -const struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - -/* - * processor_timers() - * Returns the timers available to Linux. - */ -unsigned int processor_timers(void) -{ - if (!pn) { - return 0; - } - return pn->timers; -} - -/* - * processor_threads() - * Returns the threads available to Linux. - */ -unsigned int processor_threads(void) -{ - if (!pn) { - return 0; - } - return pn->threads; -} - -/* - * processor_frequency() - * Returns the frequency of the system clock. - */ -unsigned int processor_frequency(void) -{ - if (!pn) { - return 0; - } - return pn->frequency; -} -EXPORT_SYMBOL(processor_frequency); - -/* - * processor_interrupts() - * Return the interrupts that are setup at boot time. - */ -int processor_interrupts(unsigned int *int0, unsigned int *int1) -{ - if (!pn) { - return -EFAULT; - } - - if (int0) { - *int0 = pn->interrupt0; - } - - if (int1) { - *int1 = pn->interrupt1; - } - return 0; -} - -/* - * processor_ocm() - * Returns the start and end of OCM available to Linux. - */ -void processor_ocm(unsigned long *socm, unsigned long *eocm) -{ - *socm = (unsigned long)pn->socm; - *eocm = (unsigned long)pn->eocm; -} - -/* - * processor_dram() - * Returns the start and end of dram available to Linux. - */ -void processor_dram(unsigned long *sdram, unsigned long *edram) -{ - *sdram = (unsigned long)pn->sdram; - *edram = (unsigned long)pn->edram; -} - -/* - * processor_validate_failed() - * Returns the dram available to Linux. - */ -static noinline void processor_validate_failed(void) -{ - while (1) - THREAD_STALL; -} - -/* - * processor_validate() - * Validates the procnode against limitations of this link/built. - */ -static void processor_validate(void) -{ - void *dram_start = (void *)(KERNELSTART); - void *dram_end = (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE); -#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE - void *ocm_code_start = (void *)(OCMSTART + APP_OCM_CODE_SIZE); - void *ocm_data_end = (void *)(OCMEND - APP_OCM_DATA_SIZE); -#endif - extern void __os_syscall_begin; - extern void __os_syscall_end; - int proc_node_valid = 1; - - if (!pn) { - printk(KERN_ERR "ERROR: processor node not found\n"); - goto error; - } - - - if (dram_start < pn->sdram || dram_end > pn->edram) { - printk(KERN_ERR "ERROR: processor dram mismatch %p-%p " - "available but we are expecting %p-%p\n", - pn->sdram, pn->edram, dram_start, dram_end); - proc_node_valid = 0; - } else { - printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n", - pn->sdram, pn->edram, dram_start, dram_end); - } - if (&__os_syscall_begin < pn->os_syscall_begin || - &__os_syscall_end > pn->os_syscall_end) { - printk(KERN_ERR "ERROR: processor syscall area mismatch " - "%p-%p available but we are expecting %p-%p\n", - pn->os_syscall_begin, pn->os_syscall_end, - &__os_syscall_begin, &__os_syscall_end); - proc_node_valid = 0; - } else { - printk(KERN_ERR "processor dram %p-%p, expecting %p-%p\n", - pn->sdram, pn->edram, dram_start, dram_end); - } -#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE - if (ocm_code_start < pn->socm || ocm_data_end > pn->eocm) { - printk(KERN_ERR "ERROR: processor ocm mismatch %p-%p " - "available but we are expecting %p-%p\n", - pn->socm, pn->eocm, ocm_code_start, ocm_data_end); - proc_node_valid = 0; - } else { - printk(KERN_INFO "processor ocm %p-%p, expecting %p-%p\n", - pn->socm, pn->eocm, ocm_code_start, ocm_data_end); - - } -#endif - - if (UBICOM32_ARCH_VERSION != pn->arch_version) { - printk(KERN_ERR "ERROR: processor arch mismatch, kernel" - "compiled for %d found %d\n", - UBICOM32_ARCH_VERSION, pn->arch_version); - proc_node_valid = 0; - } - - if (proc_node_valid) - return; -error: - processor_validate_failed(); -} - -void __init processor_init(void) -{ - /* - * If we do not have a trap node in the device tree, we leave the fault - * handling to the underlying hardware. - */ - pn = (struct procnode *)devtree_find_node("processor"); - - processor_validate(); - - /* - * If necessary correct the initial range registers to cover the - * complete physical space - */ - if (pn->edram > (void *)(SDRAMSTART + CONFIG_MIN_RAMSIZE)) { - printk(KERN_INFO "updating range registers for expanded dram\n"); - asm volatile ( - " move.4 D_RANGE1_HI, %0 \t\n" - " move.4 I_RANGE0_HI, %0 \t\n" -#ifdef CONFIG_PROTECT_KERNEL - " move.4 D_RANGE2_HI, %0 \t\n" - " move.4 I_RANGE2_HI, %0 \t\n" -#endif - : : "a"((unsigned long)pn->edram - 4) - ); - } - -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c deleted file mode 100644 index 18bb39e9d9..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/ptrace.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * arch/ubicom32/kernel/ptrace.c - * Ubicom32 architecture ptrace implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/signal.h> -#include <linux/uaccess.h> - -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/cacheflush.h> -#include <asm/processor.h> - -/* - * ptrace_getregs() - * - * Get all user integer registers. - */ -static inline int ptrace_getregs(struct task_struct *task, void __user *uregs) -{ - struct pt_regs *regs = task_pt_regs(task); - return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; -} - -/* - * ptrace_get_reg() - * - * Get contents of register REGNO in task TASK. - */ -static unsigned long ptrace_get_reg(struct task_struct *task, int regno) -{ - if (regno < sizeof(struct pt_regs)) { - struct pt_regs *pt_regs = task_pt_regs(task); - return *(unsigned long *)((long) pt_regs + regno); - } - - return -EIO; -} - -/* - * ptrace_put_reg() - * Write contents of register REGNO in task TASK. - */ -static int ptrace_put_reg(struct task_struct *task, int regno, - unsigned long data) -{ - if (regno <= sizeof(struct pt_regs) && regno != PT_FRAME_TYPE) { - struct pt_regs *pt_regs = task_pt_regs(task); - *(unsigned long *)((long) pt_regs + regno) = data; - return 0; - } - return -EIO; -} - -/* - * ptrace_disable_single_step() - * Disable Single Step - */ -static int ptrace_disable_single_step(struct task_struct *task) -{ - /* - * Single Step not yet implemented, so must always be disabled - */ - return 0; -} - -/* - * ptrace_disable() - * Make sure the single step bit is not set. - * Called by kernel/ptrace.c when detaching.. - */ -void ptrace_disable(struct task_struct *child) -{ - ptrace_disable_single_step(child); -} - -/* - * arch_ptrace() - * architecture specific ptrace routine. - */ -long arch_ptrace(struct task_struct *child, long request, long addr, long data) -{ - int ret; - switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: - ret = generic_ptrace_peekdata(child, addr, data); - break; - - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if (((unsigned long) addr > PT_INTERP_FDPIC_LOADMAP) - || (addr & 3)) - break; - - tmp = 0; /* Default return condition */ - - ret = -EIO; - if (addr < sizeof(struct pt_regs)) { - tmp = ptrace_get_reg(child, addr); - } else if (addr == PT_TEXT_ADDR) { - tmp = child->mm->start_code; - } else if (addr == PT_TEXT_END_ADDR) { - tmp = child->mm->end_code; - } else if (addr == PT_DATA_ADDR) { - tmp = child->mm->start_data; - } else if (addr == PT_EXEC_FDPIC_LOADMAP) { -#ifdef CONFIG_BINFMT_ELF_FDPIC - tmp = child->mm->context.exec_fdpic_loadmap; -#endif - } else if (addr == PT_INTERP_FDPIC_LOADMAP) { -#ifdef CONFIG_BINFMT_ELF_FDPIC - tmp = child->mm->context.interp_fdpic_loadmap; -#endif - } else { - break; - } - - ret = put_user(tmp, (unsigned long *)data); - break; - } - - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - - /* - * If we just changed some code so we need to - * correct the caches - */ - if (request == PTRACE_POKETEXT && ret == 0) { - flush_icache_range(addr, addr + 4); - } - break; - - case PTRACE_POKEUSR: /* write the word at location addr - * in the USER area */ - ret = -EIO; - - if (((unsigned long) addr > PT_DATA_ADDR) || (addr & 3)) - break; - - if (addr < sizeof(struct pt_regs)) { - ret = ptrace_put_reg(child, addr, data); - } - break; - - case PTRACE_SYSCALL: /* continue and stop at next (return from) - * syscall */ - case PTRACE_CONT: { /* restart after signal. */ - - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - /* make sure the single step bit is not set. */ - ptrace_disable_single_step(child); - wake_up_process(child); - ret = 0; - break; - } - - /* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to exit. - */ - case PTRACE_KILL: { - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* make sure the single step bit is not set. */ - ptrace_disable_single_step(child); - wake_up_process(child); - break; - } - - case PTRACE_DETACH: /* detach a process that was attached. */ - ret = ptrace_detach(child, data); - break; - - case PTRACE_GETREGS: /* Get all gp regs from the child. */ - ptrace_getregs(child, (unsigned long *)data); - ret = 0; - break; - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - int i; - unsigned long tmp; - int count = sizeof(struct pt_regs) / sizeof(unsigned long); - for (i = 0; i < count; i++) { - if (get_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; - break; - } - ptrace_put_reg(child, sizeof(unsigned long) * i, tmp); - data += sizeof(long); - } - ret = 0; - break; - } - - default: - return ptrace_request(child, request, addr, data); - break; - } - return ret; -} -/* - * syscall_trace - * - * called by syscall enter/exit when the TIF_SYSCALL_TRACE bit is set. - */ -asmlinkage void syscall_trace(void) -{ - struct task_struct *cur = current; - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - if (!(cur->ptrace & PT_PTRACED)) - return; - ptrace_notify(SIGTRAP | ((cur->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (cur->exit_code) { - send_sig(cur->exit_code, current, 1); - current->exit_code = 0; - } -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c deleted file mode 100644 index d996ac2b30..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/semaphore.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * arch/ubicom32/kernel/semaphore.c - * Ubicom32 architecture semaphore implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -/* - * Generic semaphore code. Buyer beware. Do your own - * specific changes in <asm/semaphore-helper.h> - */ - -#include <linux/sched.h> -#include <linux/err.h> -#include <linux/init.h> -#include <asm/semaphore-helper.h> - -#ifndef CONFIG_RMW_INSNS -spinlock_t semaphore_wake_lock; -#endif - -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in <asm/semaphore.h> - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - - -#define DOWN_HEAD(task_state) \ - \ - \ - current->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - current->state = (task_state); \ - } \ - current->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __sched __down(struct semaphore *sem) -{ - DECLARE_WAITQUEUE(wait, current); - - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __sched __down_interruptible(struct semaphore *sem) -{ - DECLARE_WAITQUEUE(wait, current); - int ret = 0; - - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, current); - if (ret) { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore *sem) -{ - return waking_non_zero_trylock(sem); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c deleted file mode 100644 index 7357f4ee35..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/setup.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * arch/ubicom32/kernel/setup.c - * Ubicom32 architecture-dependent parts of system setup. - * - * (C) Copyright 2009, Ubicom, Inc. - * Copyright (C) 1999-2007 Greg Ungerer (gerg@snapgear.com) - * Copyright (C) 1998,1999 D. Jeff Dionne <jeff@uClinux.org> - * Copyleft ()) 2000 James D. Schettine {james@telos-systems.com} - * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> - * Copyright (C) 1995 Hamish Macdonald - * Copyright (C) 2000 Lineo Inc. (www.lineo.com) - * Copyright (C) 2001 Lineo, Inc. <www.lineo.com> - * 68VZ328 Fixes/support Evan Stawnyczy <e@lineo.ca> - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/fb.h> -#include <linux/module.h> -#include <linux/console.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/bootmem.h> -#include <linux/seq_file.h> -#include <linux/init.h> - -#include <asm/devtree.h> -#include <asm/setup.h> -#include <asm/irq.h> -#include <asm/machdep.h> -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <asm/ubicom32-common.h> -#include <asm/processor.h> -#include <asm/bootargs.h> -#include <asm/thread.h> - -unsigned long memory_start; -EXPORT_SYMBOL(memory_start); - -unsigned long memory_end; -EXPORT_SYMBOL(memory_end); - -static char __initdata command_line[COMMAND_LINE_SIZE]; -#ifdef CONFIG_CMDLINE_BOOL -static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; -#endif - -extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; - -/* - * setup_arch() - * Setup the architecture dependent portions of the system. - */ -void __init setup_arch(char **cmdline_p) -{ - int bootmap_size; - unsigned long ram_start; - - processor_init(); - bootargs_init(); - - /* - * Use the link for memory_start from the link and the processor - * node for memory_end. - */ - memory_start = PAGE_ALIGN(((unsigned long)&_end)); - processor_dram(&ram_start, &memory_end); - - init_mm.start_code = (unsigned long) &_stext; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) 0; - - /* - * bootexec copies the original default command line to end of memory. - * u-boot can modify it there (i.e. to enable network boot) and the - * kernel picks up the modified version. - * - * mainexec creates a `new default' command_line which is in the - * bootargs devnode. It is updated on every firmware update but - * not used at the moment. - */ - strlcpy(boot_command_line, (char *)(memory_end - COMMAND_LINE_SIZE), COMMAND_LINE_SIZE); - -#ifdef CONFIG_CMDLINE_BOOL -#ifdef CONFIG_CMDLINE_OVERRIDE - strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); -#else - if (builtin_cmdline[0]) { - /* append boot loader cmdline to builtin */ - strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE); - strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE); - strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); - } -#endif -#endif - - strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE); - *cmdline_p = command_line; - - parse_early_param(); - - printk(KERN_INFO "%s Processor, Ubicom, Inc. <www.ubicom.com>\n", CPU); - -#if defined(DEBUG) - printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x " - "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext, - (int) &_sdata, (int) &_edata, - (int) &_sbss, (int) &_ebss); - printk(KERN_DEBUG "MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ", - (int) &_ebss, (int) memory_start, - (int) memory_start, (int) memory_end); -#endif - -#ifdef DEBUG - if (strlen(*cmdline_p)) - printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p); -#endif - -#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE) - conswitchp = &dummy_con; -#endif - - /* - * If we have a device tree, see if we have the nodes we need. - */ - if (devtree) { - devtree_print(); - } - - /* - * From the arm initialization comment: - * - * This doesn't seem to be used by the Linux memory manager any - * more, but is used by ll_rw_block. If we can get rid of it, we - * also get rid of some of the stuff above as well. - * - * Note: max_low_pfn and max_pfn reflect the number of _pages_ in - * the system, not the maximum PFN. - */ - max_pfn = max_low_pfn = (memory_end - PAGE_OFFSET) >> PAGE_SHIFT; - - /* - * Give all the memory to the bootmap allocator, tell it to put the - * boot mem_map at the start of memory. - */ - bootmap_size = init_bootmem_node( - NODE_DATA(0), - memory_start >> PAGE_SHIFT, /* map goes here */ - PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ - memory_end >> PAGE_SHIFT); - /* - * Free the usable memory, we have to make sure we do not free - * the bootmem bitmap so we then reserve it after freeing it :-) - */ - free_bootmem(memory_start, memory_end - memory_start); - reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT); - - /* - * Get kmalloc into gear. - */ - paging_init(); - - /* - * Fix up the thread_info structure, indicate this is a mainline Linux - * thread and setup the sw_ksp(). - */ - sw_ksp[thread_get_self()] = (unsigned int) current_thread_info(); - thread_set_mainline(thread_get_self()); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c deleted file mode 100644 index f6ccbe3a75..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/signal.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * arch/ubicom32/kernel/signal.c - * Ubicom32 architecture signal handling implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * Copyright (C) 1991, 1992 Linus Torvalds - * Linux/m68k support by Hamish Macdonald - * 68060 fixes by Jesper Skov - * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab - * mathemu support by Roman Zippel - * ++roman (07/09/96): implemented signal stacks - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - * - * mathemu support by Roman Zippel - * (Note: fpstate in the signal context is completely ignored for the emulator - * and the internal floating point format is put on stack) - * - * ++roman (07/09/96): implemented signal stacks (specially for tosemu on - * Atari :-) Current limitation: Only one sigstack can be active at one time. - * If a second signal with SA_ONSTACK set arrives while working on a sigstack, - * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested - * signal handlers! - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/syscalls.h> -#include <linux/errno.h> -#include <linux/wait.h> -#include <linux/ptrace.h> -#include <linux/unistd.h> -#include <linux/stddef.h> -#include <linux/highuid.h> -#include <linux/tty.h> -#include <linux/personality.h> -#include <linux/binfmts.h> - -#include <asm/setup.h> -#include <asm/uaccess.h> -#include <asm/pgtable.h> -#include <asm/traps.h> -#include <asm/ucontext.h> - -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -/* - * asm signal return handlers. - */ -void ret_from_user_signal(void); -void ret_from_user_rt_signal(void); -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); - -/* - * Common signal suspend implementation - */ -static int signal_suspend(sigset_t *saveset, struct pt_regs *regs) -{ - regs->dn[0] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (!do_signal(saveset, regs)) { - continue; - } - /* - * If the current frame type is a signal trampoline we are - * actually going to call the signal handler so we return the - * desired d0 as the return value. - */ - if (regs->frame_type == UBICOM32_FRAME_TYPE_SIGTRAMP) { - return regs->dn[0]; - } - return -EINTR; - } - /* - * Should never get here - */ - BUG(); - return 0; -} - -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -asmlinkage int do_sigsuspend(struct pt_regs *regs) -{ - old_sigset_t mask = regs->dn[0]; - sigset_t saveset; - - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - /* - * Call common handler - */ - return signal_suspend(&saveset, regs); -} - -asmlinkage int -do_rt_sigsuspend(struct pt_regs *regs) -{ - sigset_t *unewset = (sigset_t *)regs->dn[0]; - size_t sigsetsize = (size_t)regs->dn[1]; - sigset_t saveset, newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - sigdelsetmask(&newset, ~_BLOCKABLE); - - spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; - current->blocked = newset; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - /* - * Call common handler - */ - return signal_suspend(&saveset, regs); -} - -asmlinkage int -sys_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) - return -EFAULT; - __get_user(new_ka.sa.sa_flags, &act->sa_flags); - __get_user(mask, &act->sa_mask); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) - return -EFAULT; - __put_user(old_ka.sa.sa_flags, &oact->sa_flags); - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } - - return ret; -} - -asmlinkage int -do_sys_sigaltstack(struct pt_regs *regs) -{ - const stack_t *uss = (stack_t *) regs->dn[0]; - stack_t *uoss = (stack_t *)regs->dn[1]; - return do_sigaltstack(uss, uoss, regs->an[7]); -} - -/* - * fdpic_func_descriptor describes sa_handler when the application is FDPIC - */ -struct fdpic_func_descriptor { - unsigned long text; - unsigned long GOT; -}; - -/* - * rt_sigframe is stored on the user stack immediately before (above) - * the signal handlers stack. - */ -struct rt_sigframe -{ - unsigned long syscall_number; /* This holds __NR_rt_sigreturn. */ - unsigned long restore_all_regs; /* This field gets set to 1 if the frame - * type is TRAP or INTERRUPT. */ - siginfo_t *info; - struct ucontext uc; - int sig; - void *pretcode; -}; - -/* - * Do a signal return; undo the signal stack. - */ -asmlinkage int do_sigreturn(unsigned long __unused) -{ - BUG(); - return 0; -} - -asmlinkage int do_rt_sigreturn(struct pt_regs *regs) -{ - unsigned long usp = regs->an[7]; - struct rt_sigframe *frame = (struct rt_sigframe *)(usp); - sigset_t set; - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - - if (copy_from_user(regs, &frame->uc.uc_mcontext, sizeof(struct pt_regs))) - goto badframe; - return regs->dn[0]; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - -static inline void * -get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) -{ - unsigned long usp; - - /* Default to using normal stack. */ - usp = regs->an[7]; - - /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - if (!sas_ss_flags(usp)) - usp = current->sas_ss_sp + current->sas_ss_size; - } - return (void *)((usp - frame_size) & ~0x3); -} - -/* - * signal_trampoline: Defined in ubicom32_syscall.S - */ -asmlinkage void signal_trampoline(void)__attribute__((naked)); - -static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *set, struct pt_regs *regs) -{ - struct rt_sigframe *frame; - int err = 0; - - frame = (struct rt_sigframe *) get_sigframe(ka, regs, sizeof(*frame)); - - /* - * The 'err |=' have been may criticized as bad code style, but I - * strongly suspect that we want this code to be fast. So for - * now it stays as is. - */ - err |= __put_user( ( (current_thread_info()->exec_domain) - && (current_thread_info()->exec_domain->signal_invmap) - && (sig < 32) ) - ? current_thread_info()->exec_domain->signal_invmap[sig] - : sig, &frame->sig); - err |= __put_user(info, &frame->info); - - /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user((void *)current->sas_ss_sp, - &frame->uc.uc_stack.ss_sp); - err |= __put_user(sas_ss_flags(regs->an[7]), - &frame->uc.uc_stack.ss_flags); - err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - err |= __put_user(__NR_rt_sigreturn, &frame->syscall_number); - if ((regs->frame_type == UBICOM32_FRAME_TYPE_TRAP) || - (regs->frame_type == UBICOM32_FRAME_TYPE_INTERRUPT)) { - err |= __put_user(1, &frame->restore_all_regs); - } else { - err |= __put_user(0, &frame->restore_all_regs); - } - err |= copy_to_user (&frame->uc.uc_mcontext.sc_regs, regs, sizeof(struct pt_regs)); - err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); - - if (err) - goto give_sigsegv; - - /* - * Set up registers for signal handler NOTE: Do not modify dn[14], it - * contains the userspace tls pointer, so it important that it carries - * over to the signal handler. - */ - regs->an[7] = (unsigned long)frame; - regs->pc = (unsigned long) signal_trampoline; - regs->an[5] = (unsigned long) signal_trampoline; - regs->dn[0] = sig; - regs->dn[1] = (unsigned long) frame->info; - regs->dn[2] = (unsigned int) &frame->uc; - - /* - * If this is FDPIC then the signal handler is actually a function - * descriptor. - */ - if (current->personality & FDPIC_FUNCPTRS) { - struct fdpic_func_descriptor __user *funcptr = - (struct fdpic_func_descriptor *) ka->sa.sa_handler; - err |= __get_user(regs->dn[3], &funcptr->text); - err |= __get_user(regs->an[0], &funcptr->GOT); - if (err) - goto give_sigsegv; - - /* - * The funcdesc must be in a3 as this is required for the lazy - * resolver in ld.so, if the application is not FDPIC a3 is not - * used. - */ - regs->an[3] = (unsigned long) funcptr; - - } else { - regs->dn[3] = (unsigned long)ka->sa.sa_handler; - regs->an[0] = 0; - } - - regs->frame_type = UBICOM32_FRAME_TYPE_SIGTRAMP; - - return; - -give_sigsegv: - /* user space exception */ - force_sigsegv(sig, current); -} - -static inline void -handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) -{ - switch (regs->dn[0]) { - case -ERESTARTNOHAND: - if (!has_handler) - goto do_restart; - regs->dn[0] = -EINTR; - break; - - case -ERESTARTSYS: - if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { - regs->dn[0] = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - do_restart: - regs->dn[0] = regs->original_dn_0; - regs->pc -= 8; - regs->an[5] -= 8; - break; - } -} - -/* - * OK, we're invoking a handler - */ -static void -handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, - sigset_t *oldset, struct pt_regs *regs) -{ - /* are we from a system call? */ - if (regs->frame_type == -1) - /* If so, check system call restarting.. */ - handle_restart(regs, ka, 1); - - /* set up the stack frame */ - setup_rt_frame(sig, ka, info, oldset, regs); - - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - - 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); -} - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - */ -asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) -{ - struct k_sigaction ka; - siginfo_t info; - int signr; - - /* - * We want the common case to go fast, which - * is why we may in certain cases get here from - * kernel mode. Just return without doing anything - * if so. - */ - if (!user_mode(regs)) - return 1; - - if (!oldset) - oldset = ¤t->blocked; - - signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) { - /* Whee! Actually deliver the signal. */ - handle_signal(signr, &ka, &info, oldset, regs); - return 1; - } - - /* Did we come from a system call? */ - if (regs->frame_type == -1) { - /* Restart the system call - no handlers present */ - handle_restart(regs, NULL, 0); - } - - return 0; -} - -/* - * sys_sigreturn() - * Return handler for signal clean-up. - * - * NOTE: Ubicom32 does not use this syscall. Instead we rely - * on do_rt_sigreturn(). - */ -asmlinkage long sys_sigreturn(void) -{ - return -ENOSYS; -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c deleted file mode 100644 index 4aa27eb444..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/smp.c +++ /dev/null @@ -1,806 +0,0 @@ -/* - * arch/ubicom32/kernel/smp.c - * SMP implementation for Ubicom32 processors. - * - * (C) Copyright 2009, Ubicom, Inc. - * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> - * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> - * Copyright (C) 2001,2004 Grant Grundler <grundler@parisc-linux.org> - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/types.h> -#include <linux/spinlock.h> -#include <linux/slab.h> - -#include <linux/kernel.h> -#include <linux/bootmem.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/smp.h> -#include <linux/kernel_stat.h> -#include <linux/mm.h> -#include <linux/err.h> -#include <linux/delay.h> -#include <linux/bitops.h> -#include <linux/cpu.h> -#include <linux/profile.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/ptrace.h> -#include <linux/unistd.h> -#include <linux/irq.h> - -#include <asm/system.h> -#include <asm/atomic.h> -#include <asm/current.h> -#include <asm/tlbflush.h> -#include <asm/timex.h> -#include <asm/cpu.h> -#include <asm/irq.h> -#include <asm/processor.h> -#include <asm/thread.h> -#include <asm/sections.h> -#include <asm/ip5000.h> - -/* - * Mask the debug printout for IPI because they are too verbose - * for regular debugging. - */ - -// #define DEBUG_SMP 1 -#if !defined(DEBUG_SMP) -#define smp_debug(lvl, ...) -#else -static unsigned int smp_debug_lvl = 50; -#define smp_debug(lvl, printargs...) \ - if (lvl >= smp_debug_lvl) { \ - printk(printargs); \ - } -#endif - -#if !defined(DEBUG_SMP) -#define DEBUG_ASSERT(cond) -#else -#define DEBUG_ASSERT(cond) \ - if (!(cond)) { \ - THREAD_STALL; \ - } -#endif - -/* - * List of IPI Commands (more than one can be set at a time). - */ -enum ipi_message_type { - IPI_NOP, - IPI_RESCHEDULE, - IPI_CALL_FUNC, - IPI_CALL_FUNC_SINGLE, - IPI_CPU_STOP, - IPI_CPU_TIMER, -}; - -/* - * We maintain a hardware thread oriented view of online threads - * and those involved or needing IPI. - */ -static volatile unsigned long smp_online_threads = 0; -static volatile unsigned long smp_needs_ipi = 0; -static volatile unsigned long smp_inside_ipi = 0; -static unsigned long smp_irq_affinity[NR_IRQS]; - -/* - * What do we need to track on a per cpu/thread basis? - */ -DEFINE_PER_CPU(struct cpuinfo_ubicom32, cpu_data); - -/* - * Each thread cpuinfo IPI information is guarded by a lock - * that is kept local to this file. - */ -DEFINE_PER_CPU(spinlock_t, ipi_lock) = SPIN_LOCK_UNLOCKED; - -/* - * The IPI(s) are based on a software IRQ through the LDSR. - */ -unsigned int smp_ipi_irq; - -/* - * Define a spinlock so that only one cpu is able to modify the - * smp_needs_ipi and to set/clear the IRQ at a time. - */ -DEFINE_SPINLOCK(smp_ipi_lock); - -/* - * smp_halt_processor() - * Halt this hardware thread. - */ -static void smp_halt_processor(void) -{ - int cpuid = thread_get_self(); - cpu_clear(smp_processor_id(), cpu_online_map); - local_irq_disable(); - printk(KERN_EMERG "cpu[%d] has halted. It is not OK to turn off power \ - until all cpu's are off.\n", cpuid); - for (;;) { - thread_suspend(); - } -} - -/* - * ipi_interrupt() - * Handle an Interprocessor Interrupt. - */ -static irqreturn_t ipi_interrupt(int irq, void *dev_id) -{ - int cpuid = smp_processor_id(); - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); - unsigned long ops; - - /* - * Count this now; we may make a call that never returns. - */ - p->ipi_count++; - - /* - * We are about to process all ops. If another cpu has stated - * that we need an IPI, we will have already processed it. By - * clearing our smp_needs_ipi, and processing all ops, - * we reduce the number of IPI interrupts. However, this introduces - * the possibility that smp_needs_ipi will be clear and the soft irq - * will have gone off; so we need to make the get_affinity() path - * tolerant of spurious interrupts. - */ - spin_lock(&smp_ipi_lock); - smp_needs_ipi &= ~(1 << p->tid); - spin_unlock(&smp_ipi_lock); - - for (;;) { - /* - * Read the set of IPI commands we should handle. - */ - spinlock_t *lock = &per_cpu(ipi_lock, cpuid); - spin_lock(lock); - ops = p->ipi_pending; - p->ipi_pending = 0; - spin_unlock(lock); - - /* - * If we have no IPI commands to execute, break out. - */ - if (!ops) { - break; - } - - /* - * Execute the set of commands in the ops word, one command - * at a time in no particular order. Strip of each command - * as we execute it. - */ - while (ops) { - unsigned long which = ffz(~ops); - ops &= ~(1 << which); - - BUG_ON(!irqs_disabled()); - switch (which) { - case IPI_NOP: - smp_debug(100, KERN_INFO "cpu[%d]: " - "IPI_NOP\n", cpuid); - break; - - case IPI_RESCHEDULE: - /* - * Reschedule callback. Everything to be - * done is done by the interrupt return path. - */ - smp_debug(200, KERN_INFO "cpu[%d]: " - "IPI_RESCHEDULE\n", cpuid); - break; - - case IPI_CALL_FUNC: - smp_debug(100, KERN_INFO "cpu[%d]: " - "IPI_CALL_FUNC\n", cpuid); - generic_smp_call_function_interrupt(); - break; - - case IPI_CALL_FUNC_SINGLE: - smp_debug(100, KERN_INFO "cpu[%d]: " - "IPI_CALL_FUNC_SINGLE\n", cpuid); - generic_smp_call_function_single_interrupt(); - break; - - case IPI_CPU_STOP: - smp_debug(100, KERN_INFO "cpu[%d]: " - "IPI_CPU_STOP\n", cpuid); - smp_halt_processor(); - break; - -#if !defined(CONFIG_LOCAL_TIMERS) - case IPI_CPU_TIMER: - smp_debug(100, KERN_INFO "cpu[%d]: " - "IPI_CPU_TIMER\n", cpuid); -#if defined(CONFIG_GENERIC_CLOCKEVENTS) - local_timer_interrupt(); -#else - update_process_times(user_mode(get_irq_regs())); - profile_tick(CPU_PROFILING); -#endif -#endif - break; - - default: - printk(KERN_CRIT "cpu[%d]: " - "Unknown IPI: %lu\n", cpuid, which); - - return IRQ_NONE; - } - - /* - * Let in any pending interrupts - */ - BUG_ON(!irqs_disabled()); - local_irq_enable(); - local_irq_disable(); - } - } - return IRQ_HANDLED; -} - -/* - * ipi_send() - * Send an Interprocessor Interrupt. - */ -static void ipi_send(int cpu, enum ipi_message_type op) -{ - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu); - spinlock_t *lock = &per_cpu(ipi_lock, cpu); - unsigned long flags; - - /* - * We protect the setting of the ipi_pending field and ensure - * that the ipi delivery mechanism and interrupt are atomically - * handled. - */ - spin_lock_irqsave(lock, flags); - p->ipi_pending |= 1 << op; - spin_unlock_irqrestore(lock, flags); - - spin_lock_irqsave(&smp_ipi_lock, flags); - smp_needs_ipi |= (1 << p->tid); - ubicom32_set_interrupt(smp_ipi_irq); - spin_unlock_irqrestore(&smp_ipi_lock, flags); - smp_debug(100, KERN_INFO "cpu[%d]: send: %d\n", cpu, op); -} - -/* - * ipi_send_mask - * Send an IPI to each cpu in mask. - */ -static inline void ipi_send_mask(unsigned int op, const struct cpumask mask) -{ - int cpu; - for_each_cpu_mask(cpu, mask) { - ipi_send(cpu, op); - } -} - -/* - * ipi_send_allbutself() - * Send an IPI to all threads but ourselves. - */ -static inline void ipi_send_allbutself(unsigned int op) -{ - int self = smp_processor_id(); - struct cpumask result; - cpumask_copy(&result, &cpu_online_map); - cpu_clear(self, result); - ipi_send_mask(op, result); -} - -/* - * smp_enable_vector() - */ -static void smp_enable_vector(unsigned int irq) -{ - ubicom32_clear_interrupt(smp_ipi_irq); - ldsr_enable_vector(irq); -} - -/* - * smp_disable_vector() - * Disable the interrupt by clearing the appropriate bit in the - * LDSR Mask Register. - */ -static void smp_disable_vector(unsigned int irq) -{ - ldsr_disable_vector(irq); -} - -/* - * smp_mask_vector() - */ -static void smp_mask_vector(unsigned int irq) -{ - ldsr_mask_vector(irq); -} - -/* - * smp_unmask_vector() - */ -static void smp_unmask_vector(unsigned int irq) -{ - ldsr_unmask_vector(irq); -} - -/* - * smp_end_vector() - * Called once an interrupt is completed (reset the LDSR mask). - */ -static void smp_end_vector(unsigned int irq) -{ - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, smp_processor_id()); - spin_lock(&smp_ipi_lock); - smp_inside_ipi &= ~(1 << p->tid); - if (smp_inside_ipi) { - spin_unlock(&smp_ipi_lock); - return; - } - spin_unlock(&smp_ipi_lock); - ldsr_unmask_vector(irq); - smp_debug(100, KERN_INFO "cpu[%d]: unamesk vector\n", smp_processor_id()); -} - -/* - * Special hanlder functions for SMP. - */ -static struct irq_chip ubicom32_smp_chip = { - .name = "UbicoIPI", - .startup = NULL, - .shutdown = NULL, - .enable = smp_enable_vector, - .disable = smp_disable_vector, - .ack = NULL, - .mask = smp_mask_vector, - .unmask = smp_unmask_vector, - .end = smp_end_vector, -}; - -/* - * smp_reset_ipi() - * None of these cpu(s) got their IPI, turn it back on. - * - * Note: This is called by the LDSR which is not a full - * Linux cpu. Thus you must use the raw form of locks - * because lock debugging will not work on the partial - * cpu nature of the LDSR. - */ -void smp_reset_ipi(unsigned long mask) -{ - __raw_spin_lock(&smp_ipi_lock.raw_lock); - smp_needs_ipi |= mask; - smp_inside_ipi &= ~mask; - ubicom32_set_interrupt(smp_ipi_irq); - __raw_spin_unlock(&smp_ipi_lock.raw_lock); - smp_debug(100, KERN_INFO "smp: reset IPIs for: 0x%x\n", mask); -} - -/* - * smp_get_affinity() - * Choose the thread affinity for this interrupt. - * - * Note: This is called by the LDSR which is not a full - * Linux cpu. Thus you must use the raw form of locks - * because lock debugging will not work on the partial - * cpu nature of the LDSR. - */ -unsigned long smp_get_affinity(unsigned int irq, int *all) -{ - unsigned long mask = 0; - - /* - * Most IRQ(s) are delivered in a round robin fashion. - */ - if (irq != smp_ipi_irq) { - unsigned long result = smp_irq_affinity[irq] & smp_online_threads; - DEBUG_ASSERT(result); - *all = 0; - return result; - } - - /* - * This is an IPI request. Return all cpu(s) scheduled for an IPI. - * We also track those cpu(s) that are going to be "receiving" IPI this - * round. When all CPU(s) have called smp_end_vector(), - * we will unmask the IPI interrupt. - */ - __raw_spin_lock(&smp_ipi_lock.raw_lock); - ubicom32_clear_interrupt(smp_ipi_irq); - if (smp_needs_ipi) { - mask = smp_needs_ipi; - smp_inside_ipi |= smp_needs_ipi; - smp_needs_ipi = 0; - } - __raw_spin_unlock(&smp_ipi_lock.raw_lock); - *all = 1; - return mask; -} - -/* - * smp_set_affinity() - * Set the affinity for this irq but store the value in tid(s). - */ -void smp_set_affinity(unsigned int irq, const struct cpumask *dest) -{ - int cpuid; - unsigned long *paffinity = &smp_irq_affinity[irq]; - - /* - * If none specified, all cpus are allowed. - */ - if (cpus_empty(*dest)) { - *paffinity = 0xffffffff; - return; - } - - /* - * Make sure to clear the old value before setting up the - * list. - */ - *paffinity = 0; - for_each_cpu_mask(cpuid, *dest) { - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); - *paffinity |= (1 << p->tid); - } -} - -/* - * smp_send_stop() - * Send a stop request to all CPU but this one. - */ -void smp_send_stop(void) -{ - ipi_send_allbutself(IPI_CPU_STOP); -} - -/* - * smp_send_timer_all() - * Send all cpu(s) but this one, a request to update times. - */ -void smp_send_timer_all(void) -{ - ipi_send_allbutself(IPI_CPU_TIMER); -} - -/* - * smp_timer_broadcast() - * Use an IPI to broadcast a timer message - */ -void smp_timer_broadcast(const struct cpumask *mask) -{ - ipi_send_mask(IPI_CPU_TIMER, *mask); -} - -/* - * smp_send_reschedule() - * Send a reschedule request to the specified cpu. - */ -void smp_send_reschedule(int cpu) -{ - ipi_send(cpu, IPI_RESCHEDULE); -} - -/* - * arch_send_call_function_ipi() - * Cause each cpu in the mask to call the generic function handler. - */ -void arch_send_call_function_ipi_mask(const struct cpumask *mask) -{ - int cpu; - for_each_cpu_mask(cpu, *mask) { - ipi_send(cpu, IPI_CALL_FUNC); - } -} - -/* - * arch_send_call_function_single_ipi() - * Cause the specified cpu to call the generic function handler. - */ -void arch_send_call_function_single_ipi(int cpu) -{ - ipi_send(cpu, IPI_CALL_FUNC_SINGLE); -} - -/* - * setup_profiling_timer() - * Dummy function created to keep Oprofile happy in the SMP case. - */ -int setup_profiling_timer(unsigned int multiplier) -{ - return 0; -} - -/* - * smp_mainline_start() - * Start a slave thread executing a mainline Linux context. - */ -static void __init smp_mainline_start(void *arg) -{ - int cpuid = smp_processor_id(); - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpuid); - - BUG_ON(p->tid != thread_get_self()); - - /* - * Well, support 2.4 linux scheme as well. - */ - if (cpu_test_and_set(cpuid, cpu_online_map)) { - printk(KERN_CRIT "cpu[%d]: already initialized!\n", cpuid); - smp_halt_processor(); - return; - } - - /* - * Initialise the idle task for this CPU - */ - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; - if (current->mm) { - printk(KERN_CRIT "cpu[%d]: idle task already has memory " - "management\n", cpuid); - smp_halt_processor(); - return; - } - - /* - * TODO: X86 does this prior to calling notify, try to understand why? - */ - preempt_disable(); - -#if defined(CONFIG_GENERIC_CLOCKEVENTS) - /* - * Setup a local timer event so that this cpu will get timer interrupts - */ - if (local_timer_setup(cpuid) == -1) { - printk(KERN_CRIT "cpu[%d]: timer alloc failed\n", cpuid); - smp_halt_processor(); - return; - } -#endif - - /* - * Notify those interested that we are up and alive. This must - * be done before interrupts are enabled. It must also be completed - * before the bootstrap cpu returns from __cpu_up() (see comment - * above cpu_set() of the cpu_online_map). - */ - notify_cpu_starting(cpuid); - - /* - * Indicate that this thread is now online and present. Setting - * cpu_online_map has the side effect of allowing the bootstrap - * cpu to continue along; so anything that MUST be done prior to the - * bootstrap cpu returning from __cpu_up() needs to go above here. - */ - cpu_set(cpuid, cpu_online_map); - cpu_set(cpuid, cpu_present_map); - - /* - * Maintain a thread mapping in addition to the cpu mapping. - */ - smp_online_threads |= (1 << p->tid); - - /* - * Enable interrupts for this thread. - */ - local_irq_enable(); - - /* - * Enter the idle loop and wait for a timer to schedule some work. - */ - printk(KERN_INFO "cpu[%d]: entering cpu_idle()\n", cpuid); - cpu_idle(); - - /* Not Reached */ -} - -/* - * smp_cpus_done() - * Called once the kernel_init() has brought up all cpu(s). - */ -void smp_cpus_done(unsigned int cpu_max) -{ - /* Do Nothing */ -} - -/* - * __cpu_up() - * Called to startup a sepcific cpu. - */ -int __cpuinit __cpu_up(unsigned int cpu) -{ - struct task_struct *idle; - unsigned int *stack; - long timeout; - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, cpu); - - /* - * Create an idle task for this CPU. - */ - idle = fork_idle(cpu); - if (IS_ERR(idle)) { - panic("cpu[%d]: fork failed\n", cpu); - return -ENOSYS; - } - task_thread_info(idle)->cpu = cpu; - - /* - * Setup the sw_ksp[] to point to this new task. - */ - sw_ksp[p->tid] = (unsigned int)idle->stack; - stack = (unsigned int *)(sw_ksp[p->tid] + PAGE_SIZE - 8); - - /* - * Cause the specified thread to execute our smp_mainline_start - * function as a TYPE_NORMAL thread. - */ - printk(KERN_INFO "cpu[%d]: launching mainline Linux thread\n", cpu); - if (thread_start(p->tid, smp_mainline_start, (void *)NULL, stack, - THREAD_TYPE_NORMAL) == -1) { - printk(KERN_WARNING "cpu[%d]: failed thread_start\n", cpu); - return -ENOSYS; - } - - /* - * Wait for the thread to start up. The thread will set - * the online bit when it is running. Our caller execpts the - * cpu to be online if we return 0. - */ - for (timeout = 0; timeout < 10000; timeout++) { - if (cpu_online(cpu)) { - break; - } - - udelay(100); - barrier(); - continue; - } - - if (!cpu_online(cpu)) { - printk(KERN_CRIT "cpu[%d]: failed to live after %ld us\n", - cpu, timeout * 100); - return -ENOSYS; - } - - printk(KERN_INFO "cpu[%d]: came alive after %ld us\n", - cpu, timeout * 100); - return 0; -} - -/* - * Data used by setup_irq for the IPI. - */ -static struct irqaction ipi_irq = { - .name = "ipi", - .flags = IRQF_DISABLED | IRQF_PERCPU, - .handler = ipi_interrupt, -}; - -/* - * smp_prepare_cpus() - * Mark threads that are available to Linux as possible cpus(s). - */ -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - int i; - - /* - * We will need a software IRQ to send IPI(s). We will use - * a single software IRQ for all IPI(s). - */ - if (irq_soft_alloc(&smp_ipi_irq) < 0) { - panic("no software IRQ is available\n"); - return; - } - - /* - * For the IPI interrupt, we want to use our own chip definition. - * This allows us to define what happens in SMP IPI without affecting - * the performance of the other interrupts. - * - * Next, Register the IPI interrupt function against the soft IRQ. - */ - set_irq_chip(smp_ipi_irq, &ubicom32_smp_chip); - setup_irq(smp_ipi_irq, &ipi_irq); - - /* - * We use the device tree node to determine how many - * free cpus we will have (up to NR_CPUS) and we indicate - * that those cpus are present. - * - * We need to do this very early in the SMP case - * because the Linux init code uses the cpu_present_map. - */ - for_each_possible_cpu(i) { - thread_t tid; - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, i); - - /* - * Skip the bootstrap cpu - */ - if (i == 0) { - continue; - } - - /* - * If we have a free thread left in the mask, - * indicate that the cpu is present. - */ - tid = thread_alloc(); - if (tid == (thread_t)-1) { - break; - } - - /* - * Save the hardware thread id for this cpu. - */ - p->tid = tid; - cpu_set(i, cpu_present_map); - printk(KERN_INFO "cpu[%d]: added to cpu_present_map - tid: %d\n", i, tid); - } -} - -/* - * smp_prepare_boot_cpu() - * Copy the per_cpu data into the appropriate spot for the bootstrap cpu. - * - * The code in boot_cpu_init() has already set the boot cpu's - * state in the possible, present, and online maps. - */ -void __devinit smp_prepare_boot_cpu(void) -{ - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0); - - smp_online_threads |= (1 << p->tid); - printk(KERN_INFO "cpu[%d]: bootstrap CPU online - tid: %ld\n", - current_thread_info()->cpu, p->tid); -} - -/* - * smp_setup_processor_id() - * Set the current_thread_info() structure cpu value. - * - * We set the value to the true hardware thread value that we are running on. - * NOTE: this function overrides the weak alias function in main.c - */ -void __init smp_setup_processor_id(void) -{ - struct cpuinfo_ubicom32 *p = &per_cpu(cpu_data, 0); - int i; - for_each_cpu_mask(i, CPU_MASK_ALL) - set_cpu_possible(i, true); - - current_thread_info()->cpu = 0; - p->tid = thread_get_self(); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c deleted file mode 100644 index 2a10e3f4f1..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/stacktrace.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * arch/ubicom32/kernel/stacktrace.c - * Ubicom32 architecture stack back trace implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/sched.h> -#include <linux/stacktrace.h> -#include <linux/module.h> -#include <asm/stacktrace.h> -#include <asm/thread.h> -#include <asm/ip5000.h> - -/* - * These symbols are filled in by the linker. - */ -extern unsigned long _stext; -extern unsigned long _etext; - -extern unsigned long __ocm_text_run_begin; -extern unsigned long __data_begin; - -/* - * stacktrace_iterate() - * Walk the stack looking for call and calli instructions on an aligned - * boundary. - * - * Trace must point to the top of the current stack frame. - */ -unsigned long stacktrace_iterate(unsigned long **trace, - unsigned long stext, - unsigned long etext, - unsigned long ocm_stext, - unsigned long ocm_etext, - unsigned long sstack, - unsigned long estack) -{ - unsigned int thread_trap_en, instruction; - unsigned long address; - unsigned int limit = 0; - unsigned long result = 0; - unsigned long *sp = *trace; - - /* - * Exclude the current thread from being monitored for traps. - */ - asm volatile( - " thread_get_self_mask d15 \n\t" - /* save current trap status */ - " and.4 %0, MT_TRAP_EN, d15 \n\t" - " not.4 d15, d15 \n\t" - /* disable trap */ - " and.4 MT_TRAP_EN, MT_TRAP_EN, d15 \n\t" - " pipe_flush 0 \n\t" - : "=r" (thread_trap_en) - : - : "d15", "cc" - ); - - while (limit++ < 256) { - /* - * See if we have a valid stack. - */ - if (!between((unsigned long)sp, sstack, estack)) { -#ifdef TRAP_DEBUG_STACK_TRACE - printk(KERN_EMERG "stack address is out of range - " - "sp: %x, sstack: %x, estack: %x\n", - (unsigned int)sp, (unsigned int)sstack, - (unsigned int)estack); -#endif - result = 0; - *trace = 0; - break; - } - - /* - * Get the value off the stack and back up 4 bytes to what - * should be the address of a call or calli. - */ - address = (*sp++) - 4; - - /* - * If the address is not within the text segment, skip this - * value. - */ - if (!between(address, stext, etext) && - !between(address, ocm_stext, ocm_etext)) { -#ifdef TRAP_DEBUG_STACK_TRACE - printk(KERN_EMERG "not a text address - " - "address: %08x, stext: %08x, etext: %08x\n" - "ocm_stext: %08x, ocm_etext: %08x\n", - (unsigned int)address, - (unsigned int)stext, - (unsigned int)etext, - (unsigned int)ocm_stext, - (unsigned int)ocm_etext); -#endif - continue; - - } - - /* - * If the address is not on an aligned boundary it can not be a - * return address. - */ - if (address & 0x3) { - continue; - } - - /* - * Read the probable instruction. - */ - instruction = *(unsigned int *)address; - - /* - * Is this a call instruction? - */ - if ((instruction & 0xF8000000) == (u32_t)(0x1B << 27)) { -#ifdef TRAP_DEBUG_STACK_TRACE - printk(KERN_EMERG "call inst. result: %x, " - "test: %x\n", (unsigned int)address, - (unsigned int)instruction); -#endif - *trace = sp; - result = address; - break; - } - - /* - * Is this a calli instruction? - */ - if ((instruction & 0xF8000000) == (u32_t)(0x1E << 27)) { -#ifdef TRAP_DEBUG_STACK_TRACE - printk(KERN_EMERG "calli inst. result: %x, " - "test: %x\n", (unsigned int)address, - (unsigned int)instruction); -#endif - *trace = sp; - result = address; - break; - } - } - - /* - * Restore the current thread to be monitored for traps. - */ - if (thread_trap_en) { - asm volatile( - " thread_get_self_mask d15 \n\t" - " or.4 MT_TRAP_EN, MT_TRAP_EN, d15 \n\t" - : - : - : "d15", "cc" - ); - } - return result; -} - -#ifdef CONFIG_STACKTRACE -/* - * stacktrace_save_entries() - * Save stack back trace information into the provided trace structure. - */ -void stacktrace_save_entries(struct task_struct *tsk, - struct stack_trace *trace, - unsigned long sp) -{ - unsigned long code_start = (unsigned long)&_stext; - unsigned long code_end = (unsigned long)&_etext; - unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin; - unsigned long ocm_code_end = (unsigned long)&__data_begin; - unsigned long stack_end = (unsigned long)(tsk->stack + THREAD_SIZE - 8); - unsigned long stack = (unsigned long)sp; - unsigned int idx = 0; - unsigned long *handle; - int skip = trace->skip; - - handle = (unsigned long *)stack; - while (idx < trace->max_entries) { - if (skip) { - skip--; - continue; - } - trace->entries[idx] = stacktrace_iterate(&handle, - code_start, code_end, - ocm_code_start, ocm_code_end, - (unsigned long)stack, stack_end); - if (trace->entries[idx] == 0) { - break; - } - idx++; - } -} - -/* - * save_stack_trace() - * Save the specified amount of the kernel stack trace information - * for the current task. - */ -void save_stack_trace(struct stack_trace *trace) -{ - unsigned long sp = 0; - asm volatile ( - " move.4 %0, SP \n\t" - : "=r" (sp) - ); - stacktrace_save_entries(current, trace, sp); -} -EXPORT_SYMBOL_GPL(save_stack_trace); - -/* - * save_stack_trace_tsk() - * Save the specified amount of the kernel stack trace information - * for the specified task. - * - * Note: We assume the specified task is not currently running. - */ -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) -{ - stacktrace_save_entries(tsk, trace, tsk->thread.sp); -} -EXPORT_SYMBOL_GPL(save_stack_trace_tsk); -#endif /* CONFIG_STACKTRACE */ diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c deleted file mode 100644 index b06f3f3965..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/sys_ubicom32.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * arch/ubicom32/kernel/sys_ubicom32.c - * Ubicom32 architecture system call support implementation. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - * - * This file contains various random system calls that - * have a non-standard calling sequence on the Linux/ubicom32 - * platform. - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/sem.h> -#include <linux/msg.h> -#include <linux/shm.h> -#include <linux/stat.h> -#include <linux/syscalls.h> -#include <linux/mman.h> -#include <linux/file.h> -#include <linux/utsname.h> -#include <linux/ipc.h> -#include <linux/fs.h> -#include <linux/uaccess.h> -#include <linux/unistd.h> - -#include <asm/setup.h> -#include <asm/traps.h> -#include <asm/cacheflush.h> - -/* common code for old and new mmaps */ -static inline long do_mmap2( - unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - int error = -EBADF; - struct file *file = NULL; - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); - - if (file) - fput(file); -out: - return error; -} - -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - -/* - * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to - * handle more than 4 system call parameters, so these system calls - * used a memory block for parameter passing.. - */ - -struct mmap_arg_struct { - unsigned long addr; - unsigned long len; - unsigned long prot; - unsigned long flags; - unsigned long fd; - unsigned long offset; -}; - -asmlinkage int old_mmap(struct mmap_arg_struct *arg) -{ - struct mmap_arg_struct a; - int error = -EFAULT; - - if (copy_from_user(&a, arg, sizeof(a))) - goto out; - - error = -EINVAL; - if (a.offset & ~PAGE_MASK) - goto out; - - a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, - a.offset >> PAGE_SHIFT); -out: - return error; -} - -struct sel_arg_struct { - unsigned long n; - fd_set *inp, *outp, *exp; - struct timeval *tvp; -}; - -asmlinkage int old_select(struct sel_arg_struct *arg) -{ - struct sel_arg_struct a; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - /* sys_select() does the appropriate kernel locking */ - return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); -} - -/* - * sys_ipc() is the de-multiplexer for the SysV IPC calls.. - * - * This is really horribly ugly. - */ -asmlinkage int sys_ipc(uint call, int first, int second, - int third, void *ptr, long fifth) -{ - int version, ret; - - version = call >> 16; /* hack for backward compatibility */ - call &= 0xffff; - - if (call <= SEMCTL) - switch (call) { - case SEMOP: - return sys_semop(first, (struct sembuf *)ptr, second); - case SEMGET: - return sys_semget(first, second, third); - case SEMCTL: { - union semun fourth; - if (!ptr) - return -EINVAL; - if (get_user(fourth.__pad, (void **) ptr)) - return -EFAULT; - return sys_semctl(first, second, third, fourth); - } - default: - return -EINVAL; - } - if (call <= MSGCTL) - switch (call) { - case MSGSND: - return sys_msgsnd(first, (struct msgbuf *) ptr, - second, third); - case MSGRCV: - switch (version) { - case 0: { - struct ipc_kludge tmp; - if (!ptr) - return -EINVAL; - if (copy_from_user(&tmp, - (struct ipc_kludge *)ptr, - sizeof(tmp))) - return -EFAULT; - return sys_msgrcv(first, tmp.msgp, second, - tmp.msgtyp, third); - } - default: - return sys_msgrcv(first, - (struct msgbuf *) ptr, - second, fifth, third); - } - case MSGGET: - return sys_msgget((key_t) first, second); - case MSGCTL: - return sys_msgctl(first, second, - (struct msqid_ds *) ptr); - default: - return -EINVAL; - } - if (call <= SHMCTL) - switch (call) { - case SHMAT: - switch (version) { - default: { - ulong raddr; - ret = do_shmat(first, ptr, second, &raddr); - if (ret) - return ret; - return put_user(raddr, (ulong __user *) third); - } - } - case SHMDT: - return sys_shmdt(ptr); - case SHMGET: - return sys_shmget(first, second, third); - case SHMCTL: - return sys_shmctl(first, second, ptr); - default: - return -ENOSYS; - } - - return -EINVAL; -} - -/* sys_cacheflush -- flush (part of) the processor cache. */ -asmlinkage int -sys_cacheflush(unsigned long addr, int scope, int cache, unsigned long len) -{ - flush_cache_all(); - return 0; -} - -asmlinkage int sys_getpagesize(void) -{ - return PAGE_SIZE; -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S deleted file mode 100644 index 8921fb83da..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/syscalltable.S +++ /dev/null @@ -1,376 +0,0 @@ -/* - * arch/ubicom32/kernel/syscalltable.S - * <TODO: Replace with short file description> - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -/* - * - * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) - * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, Kenneth Albanowski <kjahds@kjahds.com>, - * Copyright (C) 2000 Lineo Inc. (www.lineo.com) - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include <linux/sys.h> -#include <linux/linkage.h> -#include <asm/unistd.h> - -.text -ALIGN - .global sys_call_table -sys_call_table: - .long sys_ni_syscall /* 0 - old "setup()" system call*/ - .long sys_exit - .long sys_fork - .long sys_read - .long sys_write - .long sys_open /* 5 */ - .long sys_close - .long sys_waitpid - .long sys_creat - .long sys_link - .long sys_unlink /* 10 */ - .long execve_intercept - .long sys_chdir - .long sys_time - .long sys_mknod - .long sys_chmod /* 15 */ - .long sys_chown16 - .long sys_ni_syscall /* old break syscall holder */ - .long sys_stat - .long sys_lseek - .long sys_getpid /* 20 */ - .long sys_mount - .long sys_oldumount - .long sys_setuid16 - .long sys_getuid16 - .long sys_stime /* 25 */ - .long sys_ptrace - .long sys_alarm - .long sys_fstat - .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ - .long sys_access - .long sys_nice - .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ - .long sys_sync - .long sys_kill - .long sys_rename - .long sys_mkdir - .long sys_rmdir /* 40 */ - .long sys_dup - .long sys_pipe - .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ - .long sys_setgid16 - .long sys_getgid16 - .long sys_signal - .long sys_geteuid16 - .long sys_getegid16 /* 50 */ - .long sys_acct - .long sys_umount /* recycled never used phys() */ - .long sys_ni_syscall /* old lock syscall holder */ - .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ - .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ - .long sys_ni_syscall - .long sys_umask /* 60 */ - .long sys_chroot - .long sys_ustat - .long sys_dup2 - .long sys_getppid - .long sys_getpgrp /* 65 */ - .long sys_setsid - .long sys_sigaction - .long sys_sgetmask - .long sys_ssetmask - .long sys_setreuid16 /* 70 */ - .long sys_setregid16 - .long sys_sigsuspend - .long sys_sigpending - .long sys_sethostname - .long sys_setrlimit /* 75 */ - .long sys_old_getrlimit - .long sys_getrusage - .long sys_gettimeofday - .long sys_settimeofday - .long sys_getgroups16 /* 80 */ - .long sys_setgroups16 - .long old_select - .long sys_symlink - .long sys_lstat - .long sys_readlink /* 85 */ - .long sys_uselib - .long sys_ni_syscall /* _sys_swapon */ - .long sys_reboot - .long sys_old_readdir - .long old_mmap /* 90 */ - .long sys_munmap - .long sys_truncate - .long sys_ftruncate - .long sys_fchmod - .long sys_fchown16 /* 95 */ - .long sys_getpriority - .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ - .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ni_syscall /* ioperm for i386 */ - .long sys_socketcall - .long sys_syslog - .long sys_setitimer - .long sys_getitimer /* 105 */ - .long sys_newstat - .long sys_newlstat - .long sys_newfstat - .long sys_ni_syscall - .long sys_ni_syscall /* iopl for i386 */ /* 110 */ - .long sys_vhangup - .long sys_ni_syscall /* obsolete idle() syscall */ - .long sys_ni_syscall /* vm86old for i386 */ - .long sys_wait4 - .long sys_ni_syscall /* 115 */ /* _sys_swapoff */ - .long sys_sysinfo - .long sys_ipc - .long sys_fsync - .long sys_sigreturn - .long clone_intercept /* 120 */ - .long sys_setdomainname - .long sys_newuname - .long sys_cacheflush /* modify_ldt for i386 */ - .long sys_adjtimex - .long sys_ni_syscall /* 125 */ /* _sys_mprotect */ - .long sys_sigprocmask - .long sys_ni_syscall /* old "creat_module" */ - .long sys_init_module - .long sys_delete_module - .long sys_ni_syscall /* 130: old "get_kernel_syms" */ - .long sys_quotactl - .long sys_getpgid - .long sys_fchdir - .long sys_bdflush - .long sys_sysfs /* 135 */ - .long sys_personality - .long sys_ni_syscall /* for afs_syscall */ - .long sys_setfsuid16 - .long sys_setfsgid16 - .long sys_llseek /* 140 */ - .long sys_getdents - .long sys_select - .long sys_flock - .long sys_ni_syscall /* _sys_msync */ - .long sys_readv /* 145 */ - .long sys_writev - .long sys_getsid - .long sys_fdatasync - .long sys_sysctl - .long sys_ni_syscall /* 150 */ /* _sys_mlock */ - .long sys_ni_syscall /* _sys_munlock */ - .long sys_ni_syscall /* _sys_mlockall */ - .long sys_ni_syscall /* _sys_munlockall */ - .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ - .long sys_sched_setscheduler - .long sys_sched_getscheduler - .long sys_sched_yield - .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ - .long sys_sched_rr_get_interval - .long sys_nanosleep - .long sys_ni_syscall /* _sys_mremap */ - .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long sys_getpagesize /* _sys_getpagesize */ - .long sys_ni_syscall /* old "query_module" */ - .long sys_poll - .long sys_ni_syscall /* _sys_nfsservctl */ - .long sys_setresgid16 /* 170 */ - .long sys_getresgid16 - .long sys_prctl - .long sys_rt_sigreturn - .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ - .long sys_rt_sigpending - .long sys_rt_sigtimedwait - .long sys_rt_sigqueueinfo - .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ - .long sys_pwrite64 - .long sys_lchown16 - .long sys_getcwd - .long sys_capget - .long sys_capset /* 185 */ - .long sys_sigaltstack - .long sys_sendfile - .long sys_ni_syscall /* streams1 */ - .long sys_ni_syscall /* streams2 */ - .long vfork_intercept /* 190 */ - .long sys_getrlimit - .long sys_mmap2 - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ - .long sys_lstat64 - .long sys_fstat64 - .long sys_chown - .long sys_getuid - .long sys_getgid /* 200 */ - .long sys_geteuid - .long sys_getegid - .long sys_setreuid - .long sys_setregid - .long sys_getgroups /* 205 */ - .long sys_setgroups - .long sys_fchown - .long sys_setresuid - .long sys_getresuid - .long sys_setresgid /* 210 */ - .long sys_getresgid - .long sys_lchown - .long sys_setuid - .long sys_setgid - .long sys_setfsuid /* 215 */ - .long sys_setfsgid - .long sys_pivot_root - .long sys_ni_syscall - .long sys_ni_syscall - .long sys_getdents64 /* 220 */ - .long sys_gettid - .long sys_tkill - .long sys_setxattr - .long sys_lsetxattr - .long sys_fsetxattr /* 225 */ - .long sys_getxattr - .long sys_lgetxattr - .long sys_fgetxattr - .long sys_listxattr - .long sys_llistxattr /* 230 */ - .long sys_flistxattr - .long sys_removexattr - .long sys_lremovexattr - .long sys_fremovexattr - .long sys_futex /* 235 */ - .long sys_sendfile64 - .long sys_ni_syscall /* _sys_mincore */ - .long sys_ni_syscall /* _sys_madvise */ - .long sys_fcntl64 - .long sys_readahead /* 240 */ - .long sys_io_setup - .long sys_io_destroy - .long sys_io_getevents - .long sys_io_submit - .long sys_io_cancel /* 245 */ - .long sys_fadvise64 - .long sys_exit_group - .long sys_lookup_dcookie - .long sys_epoll_create - .long sys_epoll_ctl /* 250 */ - .long sys_epoll_wait - .long sys_ni_syscall /* _sys_remap_file_pages */ - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 255 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 260 */ - .long sys_clock_getres - .long sys_clock_nanosleep - .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 265 */ - .long sys_utimes - .long sys_fadvise64_64 - .long sys_mbind - .long sys_get_mempolicy - .long sys_set_mempolicy /* 270 */ - .long sys_mq_open - .long sys_mq_unlink - .long sys_mq_timedsend - .long sys_mq_timedreceive - .long sys_mq_notify /* 275 */ - .long sys_mq_getsetattr - .long sys_waitid - .long sys_ni_syscall /* for _sys_vserver */ - .long sys_add_key - .long sys_request_key /* 280 */ - .long sys_keyctl - .long sys_ioprio_set - .long sys_ioprio_get - .long sys_inotify_init - .long sys_inotify_add_watch /* 285 */ - .long sys_inotify_rm_watch - .long sys_migrate_pages - .long sys_openat - .long sys_mkdirat - .long sys_mknodat /* 290 */ - .long sys_fchownat - .long sys_futimesat - .long sys_fstatat64 - .long sys_unlinkat - .long sys_renameat /* 295 */ - .long sys_linkat - .long sys_symlinkat - .long sys_readlinkat - .long sys_fchmodat - .long sys_faccessat /* 300 */ - .long sys_ni_syscall /* Reserved for pselect6 */ - .long sys_ni_syscall /* Reserved for ppoll */ - .long sys_unshare - .long sys_set_robust_list - .long sys_get_robust_list /* 305 */ - .long sys_splice - .long sys_sync_file_range - .long sys_tee - .long sys_vmsplice - .long sys_move_pages /* 310 */ - .long sys_sched_setaffinity - .long sys_sched_getaffinity - .long sys_kexec_load - .long sys_getcpu - .long sys_epoll_pwait /* 315 */ - .long sys_utimensat - .long sys_signalfd - .long sys_timerfd_create - .long sys_eventfd - .long sys_fallocate /* 320 */ - .long sys_timerfd_settime - .long sys_timerfd_gettime - .long sys_ni_syscall /* sys_signalfd4 */ - .long sys_ni_syscall /* sys_eventfd2 */ - .long sys_ni_syscall /* sys_epoll_create1 */ - /* 325 */ - .long sys_ni_syscall /* sys_dup3 */ - .long sys_ni_syscall /* sys_pipe2 */ - .long sys_ni_syscall /* sys_inotify_init1 */ - .rept NR_syscalls-(.-sys_call_table)/4 - .long sys_ni_syscall - .endr diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c deleted file mode 100644 index aaa5fbea4e..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/thread.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * arch/ubicom32/kernel/thread.c - * Ubicom32 architecture hardware thread support. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/profile.h> -#include <linux/clocksource.h> -#include <linux/types.h> -#include <asm/ip5000.h> -#include <asm/machdep.h> -#include <asm/asm-offsets.h> -#include <asm/thread.h> - -/* - * TODO: At some point change the name here to be thread_ksp - */ -unsigned int sw_ksp[THREAD_ARCHITECTURAL_MAX]; - -static unsigned int thread_mask = -1; -static unsigned int thread_mainline_mask; - -/* - * thread_entry() - * Returning from the called function will disable the thread. - * - * This could be a naked call to allow for hwthreads that do not have stacks. - * However, with -O0, the code still writes to thex stack, and this was - * corrupting memory just after the callers stack. - */ -static void thread_entry(void *arg, thread_exec_fn_t exec) -{ - /* - * Call thread function - */ - exec(arg); - - /* - * Complete => Disable self - */ - thread_disable(thread_get_self()); -} - -/* - * thread_start() - * Start the specified function on the specified hardware thread. - */ -thread_t thread_start(thread_t thread, - thread_exec_fn_t exec, - void *arg, - unsigned int *sp_high, - thread_type_t type) -{ - /* - * Sanity check - */ - unsigned int enabled, mask, csr; - asm volatile ( - "move.4 %0, MT_EN\n\t" - : "=m" (enabled) - ); - - mask = 1 << thread; - if (enabled & mask) { - printk(KERN_WARNING "request to enable a previously enabled thread\n"); - return (thread_t)-1; - } - - /* - * Update thread state - */ - csr = (thread << 15) | (1 << 14); - asm volatile ( - "setcsr %0 \n\t" - "setcsr_flush 0 \n\t" - - "move.4 A0, #0 \n\t" - "move.4 A1, #0 \n\t" - "move.4 A2, #0 \n\t" - "move.4 A3, #0 \n\t" - "move.4 A4, #0 \n\t" - "move.4 A5, #0 \n\t" - "move.4 A6, #0 \n\t" - "move.4 SP, %4 \n\t" /* A7 is SP */ - - "move.4 D0, %3 \n\t" - "move.4 D1, %2 \n\t" - "move.4 D2, #0 \n\t" - "move.4 D3, #0 \n\t" - "move.4 D4, #0 \n\t" - "move.4 D5, #0 \n\t" - "move.4 D6, #0 \n\t" - "move.4 D7, #0 \n\t" - "move.4 D8, #0 \n\t" - "move.4 D9, #0 \n\t" - "move.4 D10, #0 \n\t" - "move.4 D11, #0 \n\t" - "move.4 D12, #0 \n\t" - "move.4 D13, #0 \n\t" - "move.4 D14, #0 \n\t" - "move.4 D15, #0 \n\t" - - "move.4 INT_MASK0, #0 \n\t" - "move.4 INT_MASK1, #0 \n\t" - "move.4 PC, %1 \n\t" - "setcsr #0 \n\t" - "setcsr_flush 0 \n\t" - : - : "r" (csr), "r" (thread_entry), "r" (exec), - "r" (arg), "r" (sp_high) - ); - - /* - * Apply HRT state - */ - if (type & THREAD_TYPE_HRT) { - asm volatile ( - "or.4 MT_HRT, MT_HRT, %0\n\t" - : - : "d" (mask) - : "cc" - ); - } else { - asm volatile ( - "and.4 MT_HRT, MT_HRT, %0\n\t" - : - : "d" (~mask) - : "cc" - ); - } - - /* - * Set priority - */ - asm volatile ( - "or.4 MT_HPRI, MT_HPRI, %0\n\t" - : - : "d" (mask) - : "cc" - ); - - /* - * Enable thread - */ - asm volatile ( - "move.4 MT_ACTIVE_SET, %0 \n\t" - : - : "d" (mask) - ); - thread_enable_mask(mask); - return thread; -} - -/* - * thread_get_mainline() - * Return a mask of those threads that are Linux mainline threads. - */ -unsigned int thread_get_mainline(void) -{ - return thread_mainline_mask; -} - -/* - * thread_set_mainline() - * Indicate that the specified thread is a Linux mainline thread. - */ -void thread_set_mainline(thread_t tid) -{ - thread_mainline_mask |= (1 << tid); -} - -/* - * thread_alloc() - * Allocate an unused hardware thread. - */ -thread_t thread_alloc(void) -{ - thread_t tid; - - /* - * If this is the first time we are here get the list of unused - * threads from the processor device tree node. - */ - if (thread_mask == -1) { - thread_mask = processor_threads(); - } - - if (!thread_mask) { - return (thread_t)-1; - } - - tid = ffs(thread_mask); - if (tid != 0) { - tid--; - thread_mask &= ~(1 << tid); - return tid; - } - - return (thread_t)-1; -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c deleted file mode 100644 index 4a99284bd0..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/time.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * arch/ubicom32/kernel/time.c - * Initialize the timer list and start the appropriate timers. - * - * (C) Copyright 2009, Ubicom, Inc. - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/profile.h> -#include <linux/smp.h> -#include <asm/ip5000.h> -#include <asm/machdep.h> - -/* - * A bitmap of the timers on the processor indicates - * that the timer is free or in-use. - */ -static unsigned int timers; - -/* - * timer_set() - * Init the specified compare register to go off <n> cycles from now. - */ -void timer_set(int timervector, unsigned int cycles) -{ - int idx = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector); - UBICOM32_IO_TIMER->syscom[idx] = - UBICOM32_IO_TIMER->sysval + cycles; - ldsr_enable_vector(timervector); -} - -/* - * timer_reset() - * Set/reset the timer to go off again. - * - * Because sysval is a continuous timer, this function is able - * to ensure that we do not have clock sku by using the previous - * value in syscom to set the next value for syscom. - * - * Returns the number of ticks that transpired since the last event. - */ -int timer_reset(int timervector, unsigned int cycles) -{ - /* - * Reset the timer in the LDSR thread to go off appropriately. - * - * Use the previous value of the timer to calculate the new stop - * time. This allows us to account for it taking an - * indeterminate amount of time to get here. - */ - const int timer_index = UBICOM32_VECTOR_TO_TIMER_INDEX(timervector); - unsigned int prev = UBICOM32_IO_TIMER->syscom[timer_index]; - unsigned int next = prev + cycles; - int scratchpad3; - int diff; - int ticks = 1; - - /* - * If the difference is negative, we have missed at least one - * timer tick. - * - * TODO: Decide if we want to "ignore" time (as done below) or - * if we want to process time (unevenly) by calling timer_tick() - * lost_ticks times. - */ - while (1) { - /* - * Set our future time first. - */ - UBICOM32_IO_TIMER->syscom[timer_index] = next; - - /* - * Then check if we are really set time in the futrue. - */ - diff = (int)next - (int)UBICOM32_IO_TIMER->sysval; - if (diff >= 0) { - break; - } - - /* - * Oops, we are too slow. Playing catch up. - * - * If the debugger is connected the there is a good - * chance that we lost time because we were in a - * break-point, so in this case we do not print out - * diagnostics. - */ - asm volatile ("move.4 %0, scratchpad3" - : "=r" (scratchpad3)); - if ((scratchpad3 & 0x1) == 0) { - /* - * No debugger attached, print to the console - */ - printk(KERN_EMERG "diff: %d, timer has lost %u " - "ticks [rounded up]\n", - -diff, - (unsigned int)((-diff + cycles - 1) / cycles)); - } - - do { - next += cycles; - diff = (int)next - (int)UBICOM32_IO_TIMER->sysval; - ticks++; - } while (diff < 0); - } - return ticks; -} - -/* - * sched_clock() - * Returns current time in nano-second units. - * - * Notes: - * 1) This is an override for the weak alias in - * kernel/sched_clock.c. - * 2) Do not use xtime_lock as this function is - * sometimes called with xtime_lock held. - * 3) We use a retry algorithm to ensure that - * we get a consistent value. - * 4) sched_clock must be overwritten if IRQ tracing - * is enabled because the default implementation uses - * the xtime_lock sequence while holding xtime_lock. - */ -unsigned long long sched_clock(void) -{ - unsigned long long my_jiffies; - unsigned long jiffies_top; - unsigned long jiffies_bottom; - - do { - jiffies_top = jiffies_64 >> 32; - jiffies_bottom = jiffies_64 & 0xffffffff; - } while (unlikely(jiffies_top != (unsigned long)(jiffies_64 >> 32))); - - my_jiffies = ((unsigned long long)jiffies_top << 32) | (jiffies_bottom); - return (my_jiffies - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ); -} - -/* - * timer_free() - * Free a hardware timer. - */ -void timer_free(int interrupt) -{ - unsigned int bit = interrupt - TIMER_INT(0); - - /* - * The timer had not been allocated. - */ - BUG_ON(timers & (1 << bit)); - timers |= (1 << bit); -} - -/* - * timer_alloc() - * Allocate a hardware timer. - */ -int timer_alloc(void) -{ - unsigned int bit = find_first_bit((unsigned long *)&timers, 32); - if (!bit) { - printk(KERN_WARNING "no more free timers\n"); - return -1; - } - - timers &= ~(1 << bit); - return bit + TIMER_INT(0); -} - -/* - * time_init() - * Time init function. - */ -void time_init(void) -{ - /* - * Find the processor node and determine what timers are - * available for us. - */ - timers = processor_timers(); - if (timers == 0) { - printk(KERN_WARNING "no timers are available for Linux\n"); - return; - } - -#ifdef CONFIG_GENERIC_CLOCKEVENTS - timer_device_init(); -#else - timer_tick_init(); -#endif -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c deleted file mode 100644 index 8f0cdc4d55..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_broadcast.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * arch/ubicom32/kernel/timer_broadcast.c - * Implements a dummy clock event for each cpu. - * - * Copyright (C) 2008 Paul Mundt - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - * arch/arm - * arch/sh - */ -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/smp.h> -#include <linux/jiffies.h> -#include <linux/percpu.h> -#include <linux/clockchips.h> -#include <linux/irq.h> - -static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); - -/* - * The broadcast trick only works when the timer will be used in a periodic mode. - * If the user has configured either NO_HZ or HIGH_RES_TIMERS they must have - * a per cpu timer. - */ -#if defined(CONFIG_NO_HZ) || defined(CONFIG_HIGH_RES_TIMERS) -#error "Tickless and High Resolution Timers require per-CPU local timers: CONFIG_LOCAL_TIMERS" -#endif - -/* - * local_timer_interrupt() - * Used on SMP for local timer interrupt sent via an IPI. - */ -void local_timer_interrupt(void) -{ - struct clock_event_device *dev = &__get_cpu_var(local_clockevent); - - dev->event_handler(dev); -} - -/* - * dummy_timer_set_next_event() - * Cause the timer to go off "cycles" from now. - */ -static int dummy_timer_set_next_event(unsigned long cycles, struct clock_event_device *dev) -{ - return 0; -} - -/* - * dummy_timer_set_mode() - * Do Nothing. - */ -static void dummy_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *clk) -{ -} - -/* - * local_timer_setup() - * Adds a clock event for the specified cpu. - */ -int __cpuinit local_timer_setup(unsigned int cpu) -{ - struct clock_event_device *dev = &per_cpu(local_clockevent, cpu); - - dev->name = "timer-dummy"; - dev->features = CLOCK_EVT_FEAT_DUMMY; - dev->rating = 200; - dev->mult = 1; - dev->set_mode = dummy_timer_set_mode; - dev->set_next_event = dummy_timer_set_next_event; - dev->broadcast = smp_timer_broadcast; - dev->cpumask = cpumask_of_cpu(cpu); - dev->irq = -1; - printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name); - - clockevents_register_device(dev); - return 0; -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c deleted file mode 100644 index 1943cbb9ee..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_device.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * arch/ubicom32/kernel/timer_device.c - * Implements a Ubicom32 clock device and event devices. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/types.h> -#include <linux/clockchips.h> -#include <linux/clocksource.h> -#include <linux/spinlock.h> -#include <asm/ip5000.h> -#include <asm/machdep.h> - -#if defined(CONFIG_SMP) -#include <asm/smp.h> -#endif - -#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) -#define MAX_TIMERS (2 + CONFIG_TIMER_EXTRA_ALLOC) -#else -#define MAX_TIMERS (NR_CPUS + CONFIG_TIMER_EXTRA_ALLOC) -#endif - -#if (MAX_TIMERS > 10) -#error "Ubicom32 only has 10 timers" -#endif - -static unsigned int frequency; -static struct clock_event_device timer_device_devs[MAX_TIMERS]; -static struct irqaction timer_device_irqs[MAX_TIMERS]; -static int timer_device_next_timer = 0; - -DEFINE_SPINLOCK(timer_device_lock); - -/* - * timer_device_set_next_event() - * Cause the timer to go off "cycles" from now. - */ -static int timer_device_set_next_event(unsigned long cycles, struct clock_event_device *dev) -{ - timer_set(dev->irq, cycles); - return 0; -} - -/* - * timer_device_set_mode() - * Handle the mode switch for a clock event device. - */ -static void timer_device_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) -{ - switch (mode) { - case CLOCK_EVT_MODE_SHUTDOWN: - /* - * Make sure the vector is disabled - * until the next event is set. - */ - printk(KERN_NOTICE "timer[%d]: shutdown\n", dev->irq); - ldsr_disable_vector(dev->irq); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* - * Make sure the vector is disabled - * until the next event is set. - */ - printk(KERN_NOTICE "timer[%d]: oneshot\n", dev->irq); - ldsr_disable_vector(dev->irq); - break; - - case CLOCK_EVT_MODE_PERIODIC: - /* - * The periodic request is 1 per jiffies - */ - printk(KERN_NOTICE "timer[%d]: periodic: %d cycles\n", - dev->irq, frequency / CONFIG_HZ); - timer_set(dev->irq, frequency / CONFIG_HZ); - break; - - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_RESUME: - printk(KERN_WARNING "timer[%d]: unimplemented mode: %d\n", - dev->irq, mode); - break; - }; -} - -/* - * timer_device_event() - * Call the device's event handler. - * - * The pointer is initialized by the generic Linux code - * to the function to be called. - */ -static irqreturn_t timer_device_event(int irq, void *dev_id) -{ - struct clock_event_device *dev = (struct clock_event_device *)dev_id; - - if (dev->mode == CLOCK_EVT_MODE_PERIODIC) { - /* - * The periodic request is 1 per jiffies - */ - timer_reset(dev->irq, frequency / CONFIG_HZ); - } else { - /* - * The timer will go off again at the rollover - * point. We must disable the IRQ to prevent - * getting a spurious interrupt. - */ - ldsr_disable_vector(dev->irq); - } - - if (!dev->event_handler) { - printk(KERN_CRIT "no registered event handler\n"); - return IRQ_HANDLED; - } - - dev->event_handler(dev); - return IRQ_HANDLED; -} - -/* - * timer_device_clockbase_read() - * Provide a primary clocksource around the sysval timer. - */ -static cycle_t timer_device_clockbase_read(void) -{ - return (cycle_t)UBICOM32_IO_TIMER->sysval; -} - -/* - * Primary Clock Source Description - * - * We use 24 for the shift factor because we want - * to ensure there are less than 2^24 clocks - * in a jiffie of 10 ms. - */ -static struct clocksource timer_device_clockbase = { - .name = "sysval", - .rating = 400, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .mask = CLOCKSOURCE_MASK(32), - .shift = 24, - .mult = 0, - .read = timer_device_clockbase_read, -}; - -/* - * timer_device_alloc_event() - * Allocate a timer device event. - */ -static int timer_device_alloc_event(const char *name, int cpuid, const struct cpumask *cpumask) -{ - struct clock_event_device *dev; - struct irqaction *action; - - /* - * Are we out of configured timers? - */ - spin_lock(&timer_device_lock); - if (timer_device_next_timer >= MAX_TIMERS) { - spin_unlock(&timer_device_lock); - printk(KERN_WARNING "out of timer event entries\n"); - return -1; - } - dev = &timer_device_devs[timer_device_next_timer]; - action = &timer_device_irqs[timer_device_next_timer]; - timer_device_next_timer++; - spin_unlock(&timer_device_lock); - - /* - * Now allocate a timer to ourselves. - */ - dev->irq = timer_alloc(); - if (dev->irq == -1) { - spin_lock(&timer_device_lock); - timer_device_next_timer--; - spin_unlock(&timer_device_lock); - printk(KERN_WARNING "out of hardware timers\n"); - return -1; - } - - /* - * Init the IRQ action structure. Make sure - * this in place before you register the clock - * event device. - */ - action->name = name; - action->flags = IRQF_DISABLED | IRQF_TIMER; - action->handler = timer_device_event; - //cpumask_copy(&action->mask, mask); - action->dev_id = dev; - setup_irq(dev->irq, action); - irq_set_affinity(dev->irq, cpumask); - ldsr_disable_vector(dev->irq); - - /* - * init clock dev structure. - * - * The min_delta_ns is chosen to ensure that setting next - * event will never be requested with too small of value. - */ - dev->name = name; - dev->rating = timer_device_clockbase.rating; - dev->shift = timer_device_clockbase.shift; - dev->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - dev->set_mode = timer_device_set_mode; - dev->set_next_event = timer_device_set_next_event; - dev->mult = div_sc(frequency, NSEC_PER_SEC, dev->shift); - dev->max_delta_ns = clockevent_delta2ns(0xffffffff, dev); - dev->min_delta_ns = clockevent_delta2ns(100, dev); - //dev->cpumask = mask; - printk(KERN_NOTICE "timer[%d]: %s - created\n", dev->irq, dev->name); - - /* - * Now register the device. - */ - clockevents_register_device(dev); - return dev->irq; -} - -#if defined(CONFIG_LOCAL_TIMERS) -/* - * local_timer_setup() - * Allocation function for creating a per cpu local timer. - */ -int __cpuinit local_timer_setup(unsigned int cpu) -{ - return timer_device_alloc_event("timer-cpu", cpu); -} -#endif - -/* - * timer_device_init() - * Create and init a generic clock driver for Ubicom32. - */ -void timer_device_init(void) -{ - int i; - - /* - * Get the frequency from the processor device tree node or use - * the default if not available. We will store this as the frequency - * of the timer to avoid future calculations. - */ - frequency = processor_frequency(); - if (frequency == 0) { - frequency = CLOCK_TICK_RATE; - } - - /* - * Setup the primary clock source around sysval. Linux does not - * supply a Mhz multiplier so convert down to khz. - */ - timer_device_clockbase.mult = - clocksource_khz2mult(frequency / 1000, - timer_device_clockbase.shift); - if (clocksource_register(&timer_device_clockbase)) { - printk(KERN_ERR "timer: clocksource failed to register\n"); - return; - } - - /* - * Always allocate a primary timer. - */ - timer_device_alloc_event("timer-primary", -1, cpu_all_mask); - -#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) - /* - * If BROADCAST is selected we need to add a broadcast timer. - */ - timer_device_alloc_event("timer-broadcast", -1, cpu_all_mask); -#endif - - /* - * Allocate extra timers that are requested. - */ - for (i = 0; i < CONFIG_TIMER_EXTRA_ALLOC; i++) { - timer_device_alloc_event("timer-extra", -1, cpu_all_mask); - } -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c deleted file mode 100644 index 7a2ad49498..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/timer_tick.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * arch/ubicom32/kernel/timer_tick.c - * Impelemets a perodic timer. - * - * (C) Copyright 2009, Ubicom, Inc. - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/profile.h> - -#include <asm/ip5000.h> -#include <asm/machdep.h> -#if defined(CONFIG_SMP) -#include <asm/smp.h> -#endif - -static unsigned int timervector; -static unsigned int frequency; - -/* - * timer_tick() - * Kernel system timer support. Needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick. - */ -static irqreturn_t timer_tick(int irq, void *dummy) -{ - int ticks; - - BUG_ON(!irqs_disabled()); - ticks = timer_reset(timervector, frequency); - - write_seqlock(&xtime_lock); - do_timer(ticks); - write_sequnlock(&xtime_lock); - - update_process_times(user_mode(get_irq_regs())); - profile_tick(CPU_PROFILING); - -#if defined(CONFIG_SMP) - smp_send_timer_all(); -#endif - return(IRQ_HANDLED); -} - -/* - * Data used by setup_irq for the timer. - */ -static struct irqaction timer_irq = { - .name = "timer", - .flags = IRQF_DISABLED | IRQF_TIMER, - .handler = timer_tick, -}; - -/* - * timer_tick_init() - * Implements a periodic timer - * - * This implementation directly calls the timer_tick() and move - * the Linux kernel forward. This is used when the user has not - * selected GENERIC_CLOCKEVENTS. - */ -void timer_tick_init(void) -{ - /* - * Now allocate a timer to ourselves. - */ - timervector = timer_alloc(); - if (timervector == -1) { - printk(KERN_WARNING "where did the timer go?\n"); - return; - } - - setup_irq(timervector, &timer_irq); - - /* - * Get the frequency from the processor device tree node or use - * the default if not available. We will store this as the frequency - * of the timer to avoid future calculations. - */ - frequency = processor_frequency(); - if (frequency == 0) { - frequency = CLOCK_TICK_RATE; - } - frequency /= CONFIG_HZ; - - printk(KERN_NOTICE "timer will interrupt every: %d cycles\n", frequency); - timer_set(timervector, frequency); -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c deleted file mode 100644 index 0676a16587..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/topology.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * arch/ubicom32/kernel/topology.c - * Ubicom32 architecture sysfs topology information. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/init.h> -#include <linux/smp.h> -#include <linux/cpu.h> -#include <linux/cache.h> - -static struct cpu cpu_devices[NR_CPUS] __read_mostly; - -static int __init topology_init(void) -{ - int num; - - for_each_present_cpu(num) { - cpu_devices[num].hotpluggable = 0; - register_cpu(&cpu_devices[num], num); - } - return 0; -} - -subsys_initcall(topology_init); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c deleted file mode 100644 index 8cb22e25ea..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/traps.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - * arch/ubicom32/kernel/traps.c - * Ubicom32 architecture trap handling support. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -/* - * Sets up all exception vectors - */ -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/a.out.h> -#include <linux/user.h> -#include <linux/string.h> -#include <linux/linkage.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/kallsyms.h> -#include <linux/compiler.h> -#include <linux/stacktrace.h> -#include <linux/personality.h> - -#include <asm/uaccess.h> -#include <asm/stacktrace.h> -#include <asm/devtree.h> -#include <asm/setup.h> -#include <asm/fpu.h> -#include <asm/system.h> -#include <asm/traps.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/machdep.h> -#include <asm/siginfo.h> -#include <asm/ip5000.h> -#include <asm/thread.h> - -#define TRAP_MAX_STACK_DEPTH 20 - -/* - * These symbols are filled in by the linker. - */ -extern unsigned long _stext; -extern unsigned long _etext; - -extern unsigned long __ocm_text_run_begin; -extern unsigned long __data_begin; - -extern void show_vmas(struct task_struct *task); - -const char *trap_cause_strings[] = { - /*0*/ "inst address decode error", - /*1*/ "inst sync error", - /*2*/ "inst illegal", - /*3*/ "src1 address decode error", - /*4*/ "dst address decode error", - /*5*/ "src1 alignment error", - /*6*/ "dst alignment error", - /*7*/ "src1 sync error", - /*8*/ "dst sync error", - /*9*/ "DCAPT error", - /*10*/ "inst range error", - /*11*/ "src1 range error", - /*12*/ "dst range error", -}; - -/* - * The device tree trap node definition. - */ -struct trapnode { - struct devtree_node dn; - unsigned int intthread; -}; - -static struct trapnode *tn;; - -/* - * trap_interrupt_handler() - * Software Interrupt to ensure that a trap is serviced. - */ -static irqreturn_t trap_interrupt_handler(int irq, void *dummy) -{ - /* Do Nothing */ - return IRQ_HANDLED; -} - -/* - * Data used by setup_irq for the timer. - */ -static struct irqaction trap_irq = { - .name = "trap", - .flags = IRQF_DISABLED, - .handler = trap_interrupt_handler, -}; - -/* - * trap_cause_to_str() - * Convert a trap_cause into a series of printk - */ -static void trap_cause_to_str(long status) -{ - int bit; - - if ((status & ((1 << TRAP_CAUSE_TOTAL) - 1)) == 0) { - printk(KERN_NOTICE "decode: UNKNOWN CAUSES\n"); - return; - } - - for (bit = 0; bit < TRAP_CAUSE_TOTAL; bit++) { - if (status & (1 << bit)) { - printk(KERN_NOTICE "\tdecode: %08x %s\n", - 1 << bit, trap_cause_strings[bit]); - } - } -} - -/* - * trap_print_information() - * Print the cause of the trap and additional info. - */ -static void trap_print_information(const char *str, struct pt_regs *regs) -{ - printk(KERN_WARNING "\n"); - - if (current) { - printk(KERN_WARNING "Process %s (pid: %d)\n", - current->comm, current->pid); - } - - if (current && current->mm) { - printk(KERN_NOTICE "text = 0x%p-0x%p data = 0x%p-0x%p\n" - KERN_NOTICE "bss = 0x%p-0x%p user-stack = 0x%p\n" - KERN_NOTICE "\n", - (void *)current->mm->start_code, - (void *)current->mm->end_code, - (void *)current->mm->start_data, - (void *)current->mm->end_data, - (void *)current->mm->end_data, - (void *)current->mm->brk, - (void *)current->mm->start_stack); - } - - printk(KERN_WARNING "%s: Causes: 0x%08x\n", str, - (unsigned int)regs->trap_cause); - trap_cause_to_str(regs->trap_cause); - show_regs(regs); - show_stack(NULL, (unsigned long *)regs->an[7]); - printk(KERN_NOTICE "--- End Trap --- \n"); -} - -/* - * dump_stack() - * Dump the stack of the current task. - */ -void dump_stack(void) -{ - show_stack(NULL, NULL); -} -EXPORT_SYMBOL(dump_stack); - -/* - * show_stack() - * Print out information from the current stack. - */ -void show_stack(struct task_struct *task, unsigned long *sp) -{ - /* - * Allocate just enough entries on the stack. - */ - unsigned int calls[TRAP_MAX_STACK_DEPTH]; - unsigned long code_start; - unsigned long code_end; - unsigned long ocm_code_start = (unsigned long)&__ocm_text_run_begin; - unsigned long ocm_code_end = (unsigned long)&__data_begin; - unsigned long stack_end = (unsigned long)(current->stack + THREAD_SIZE - 8); - unsigned long stack = (unsigned long)sp; - int kernel_stack = 1; - - processor_dram(&code_start, &code_end); - - /* - * Which task are we talking about. - */ - if (!task) { - task = current; - } - - /* - * Find the stack for the task if one was not specified. Otherwise - * use the specified stack. - */ - if (!stack) { - if (task != current) { - stack = task->thread.sp; - stack_end = (unsigned long)task->stack + THREAD_SIZE - 8; - } else { - asm volatile ( - "move.4 %0, SP \n\t" - : "=r" (stack) - ); - } - } - - printk(KERN_NOTICE "Starting backtrace: PID %d '%s'\n", - task->pid, task->comm); - - /* - * We do 2 passes the first pass is Kernel stack is the second - * User stack. - */ - while (kernel_stack) { - unsigned long *handle; - unsigned int i, idx = 0; - struct pt_regs *pt = task_pt_regs(task); - - /* - * If the task is in user mode, reset the start - * and end values for text. - */ - if (__user_mode(stack)) { - if (!(task->personality & FDPIC_FUNCPTRS)) { - printk(KERN_NOTICE " User Stack:\n"); - code_start = task->mm->start_code; - code_end = task->mm->end_code; - } else { - printk(KERN_NOTICE " User Stack (fdpic):\n"); - show_vmas(task); - } - stack_end = task->mm->start_stack; - ocm_code_end = ocm_code_start = 0; - kernel_stack = 0; - } else { - printk(KERN_NOTICE " Kernel Stack:\n"); - } - - /* - * Collect the stack back trace information. - */ - printk(" code[0x%lx-0x%lx]", code_start, code_end); - if (ocm_code_start) { - printk(" ocm_code[0x%lx-0x%lx]", - ocm_code_start, ocm_code_end); - } - printk("\n stack[0x%lx-0x%lx]\n", stack, stack_end); - - handle = (unsigned long*)stack; - while (idx < TRAP_MAX_STACK_DEPTH) { - calls[idx] = stacktrace_iterate(&handle, - code_start, code_end, - ocm_code_start, ocm_code_end, - (unsigned long)stack, stack_end); - if (calls[idx] == 0) { - break; - } - idx++; - } - - /* - * Now print out the data. - */ - printk(KERN_NOTICE " CALL && CALLI on stack:"); - for (i = 0; i < idx; i++) { - printk("%s0x%x, ", (i & 0x3) == 0 ? "\n " : "", - calls[i]); - } - printk(idx == TRAP_MAX_STACK_DEPTH ? "...\n" : "\n"); - - /* - * If we are doing user stack we are done - */ - if (!kernel_stack) { - break; - } - - /* - * Does this kernel stack have a mm (i.e. is it user) - */ - if (!task->mm) { - printk("No mm for userspace stack.\n"); - break; - } - /* - * Get the user-mode stack (if any) - */ - stack = pt->an[7]; - printk(KERN_NOTICE "Userspace stack at 0x%lx frame type %d\n", - stack, (int)pt->frame_type); - if (!__user_mode(stack)) { - break; - } - } -} - -/* - * die_if_kernel() - * Determine if we are in kernel mode and if so print stuff out and die. - */ -void die_if_kernel(char *str, struct pt_regs *regs, long trap_cause) -{ - unsigned int s3value; - - if (user_mode(regs)) { - return; - } - - console_verbose(); - trap_print_information(str, regs); - - /* - * If the debugger is attached via the hardware mailbox protocol, - * go into an infinite loop and the debugger will figure things out. - */ - asm volatile ( - "move.4 %0, scratchpad3" - : "=r" (s3value) - ); - if (s3value) { - asm volatile("1: jmpt.t 1b"); - } - - /* - * Set the debug taint value. - */ - add_taint(TAINT_DIE); - do_exit(SIGSEGV); -} - -/* - * trap_handler() - * Handle traps. - * - * Traps are treated as interrupts and registered with the LDSR. When - * the LDSR takes the interrupt, it will determine if a trap has occurred - * and service the trap prior to servicing the interrupt. - * - * This function is directly called by the LDSR. - */ -void trap_handler(int irq, struct pt_regs *regs) -{ - int sig = SIGSEGV; - siginfo_t info; - unsigned int trap_cause = regs->trap_cause; - - BUG_ON(!irqs_disabled()); - - /* - * test if in kernel and die. - */ - die_if_kernel("Kernel Trap", regs, trap_cause); - - /* - * User process problem, setup a signal for this process - */ - if ((trap_cause & (1 << TRAP_CAUSE_DST_RANGE_ERR)) || - (trap_cause & (1 << TRAP_CAUSE_SRC1_RANGE_ERR)) || - (trap_cause & (1 << TRAP_CAUSE_I_RANGE_ERR))) { - sig = SIGSEGV; - info.si_code = SEGV_MAPERR; - } else if ((trap_cause & (1 << TRAP_CAUSE_DST_MISALIGNED)) || - (trap_cause & (1 << TRAP_CAUSE_SRC1_MISALIGNED))) { - sig = SIGBUS; - info.si_code = BUS_ADRALN; - } else if ((trap_cause & (1 << TRAP_CAUSE_DST_DECODE_ERR)) || - (trap_cause & (1 << TRAP_CAUSE_SRC1_DECODE_ERR))) { - sig = SIGILL; - info.si_code = ILL_ILLOPN; - } else if ((trap_cause & (1 << TRAP_CAUSE_ILLEGAL_INST))) { - /* - * Check for software break point and if found signal trap - * not illegal instruction. - */ - unsigned long instruction; - if (between(regs->pc, KERNELSTART, memory_end) && - (regs->pc & 3) == 0 && - get_user(instruction, (unsigned long *)regs->pc) == 0) { - - /* - * This used to be 0xaabbccdd but it turns out - * that is now valid in ubicom32v4 isa so we - * have switched to 0xfabbccdd - */ - if ((instruction == 0xfabbccdd) || - (instruction == 0xaabbccdd)) { - sig = SIGTRAP; - info.si_code = TRAP_BRKPT; - goto send_signal; - } - } - sig = SIGILL; - info.si_code = ILL_ILLOPC; - } else if ((trap_cause & (1 << TRAP_CAUSE_I_DECODE_ERR))) { - sig = SIGILL; - info.si_code = ILL_ILLOPC; - } else if ((trap_cause & (1 << TRAP_CAUSE_DCAPT))) { - sig = SIGTRAP; - info.si_code = TRAP_TRACE; - } - - /* - * Print a trap information block to the console, do not - * print this above the case because we don't want it - * printed for software break points. - */ - trap_print_information("User Trap", regs); - -send_signal: - - force_sig_info(sig, &info, current); - - /* - * Interrupts are disabled, re-enable them now. - */ - if (!irqs_disabled()) { - printk(KERN_EMERG "interrupts enabled on exit, irq=%d, regs=%p", - irq, regs); - BUG(); - } -} - -/* - * trap_init_interrupt() - * We need a 2nd trap handling init that will occur after init_IRQ(). - */ -void __init trap_init_interrupt(void) -{ - int err; - unsigned char tirq; - struct devtree_node *dn = (struct devtree_node *)tn; - - /* - * Now setup the Software IRQ so that if a trap occurs the LDSR - * is started. The irq is there just to "force" the LDSR to run. - */ - if (!tn) { - printk(KERN_WARNING "trap_init_interrupt skipped.\n"); - return; - } - - err = devtree_irq(dn, NULL, &tirq); - if (err) { - printk(KERN_WARNING "error obtaining trap irq value: %d\n", - err); - return; - } - - if (tirq == DEVTREE_IRQ_NONE) { - printk(KERN_WARNING "trap irq not available: %d\n", tirq); - return; - } - - err = setup_irq(tirq, &trap_irq); - if (err) { - printk(KERN_WARNING "trap irq setup failed: %d\n", err); - return; - } - - /* - * Let ultra know which thread is handling the traps and - * what the interrupt to use is. - */ - tn->intthread = ldsr_get_threadid(); - - /* - * Tell the LDSR about our IRQ so that it will unsuspend - * if one occurs while waiting for the per thread lock. - */ - ldsr_set_trap_irq(tirq); -} - -/* - * trap_init() - * init trap handling - * - * Trap handling is done through the ldsr. Every time an interrupt - * occurs, the LDSR looks for threads that are listed in the TRAP - * register and forces a call to the trap handler. - */ -void __init trap_init(void) -{ - /* - * If we do not have a trap node in the device tree, we leave the fault - * handling to the underlying hardware. - */ - tn = (struct trapnode *)devtree_find_node("traps"); - if (!tn) { - printk(KERN_WARNING "traps are not handled by linux\n"); - return; - } -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c deleted file mode 100644 index 2fe5f5f87c..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/uaccess.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * arch/ubicom32/include/asm/uaccess.c - * User space memory access functions for Ubicom32 architecture. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/string.h> -#include <linux/module.h> - -#include <asm/segment.h> -#include <asm/uaccess.h> - -extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; - -/* - * __access_ok() - * Check that the address is in the current processes. - * - * NOTE: The kernel uses "pretend" user addresses that wind - * up calling access_ok() so this approach has only marginal - * value because you wind up with lots of false positives. - */ -int __access_ok(unsigned long addr, unsigned long size) -{ - // struct vm_area_struct *vma; - - /* - * Don't do anything if we are not a running system yet. - */ - if (system_state != SYSTEM_RUNNING) { - return 1; - } - - /* - * It appears that Linux will call this function even when we are not - * in the context of a user space application that has a VM address - * space. So we must check that current and mm are valid before - * performing the check. - */ - if ((!current) || (!current->mm)) { - return 1; - } - - /* - * We perform some basic checks on the address to ensure that it - * is at least within the range of DRAM. - */ - if ((addr < (int)&_etext) || (addr > memory_end)) { - printk(KERN_WARNING "pid=%d[%s]: range [%lx - %lx] not in memory area: [%lx - %lx]\n", - current->pid, current->comm, - addr, addr + size, - memory_start, memory_end); - return 0; - } - - /* - * For nommu Linux we can check this by looking at the allowed - * memory map for the process. - * - * TODO: Since the kernel passes addresses in it's own space as though - * they were user address, we can not validate the addresses this way. - */ -#if 0 - if (!down_read_trylock(¤t->mm->mmap_sem)) { - return 1; - } - vma = find_vma(current->mm, addr); - if (!vma) { - up_read(¤t->mm->mmap_sem); - printk(KERN_WARNING "pid=%d[%s]: possible invalid acesss on range: [%lx - %lx]\n", - current->pid, current->comm, addr, addr + size); - return 1; - } - if ((addr + size) > vma->vm_end) { - up_read(¤t->mm->mmap_sem); - printk(KERN_WARNING "pid=%d[%s]: possible invalid length on range: [%lx - %lx]\n", - current->pid, current->comm, addr, addr + size); - return 1; - } - up_read(¤t->mm->mmap_sem); -#endif - return 1; -} - -EXPORT_SYMBOL(__access_ok); diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S deleted file mode 100644 index 08db4c057a..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_context_switch.S +++ /dev/null @@ -1,359 +0,0 @@ -/* - * arch/ubicom32/kernel/ubicom32_context_switch.S - * Implements context switch and return functions. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/sys.h> -#include <linux/linkage.h> -#include <asm/asm-offsets.h> -#include <asm/ubicom32-common.h> -#include <asm/ip5000.h> -#include <asm/range-protect.h> - -/* - * begin_restore_context() - * Restore most of the context from sp (struct pt_reg *) - * - * This *can* be called without the global atomic lock. (because sp is - * not restored!) Only d15 and a3 are allowed to be used after this - * before calling complete_restore_context - */ -.macro begin_restore_context - move.4 d0, PT_D0(sp) - move.4 d1, PT_D1(sp) - move.4 d2, PT_D2(sp) - move.4 d3, PT_D3(sp) - move.4 d4, PT_D4(sp) - move.4 d5, PT_D5(sp) - move.4 d6, PT_D6(sp) - move.4 d7, PT_D7(sp) - move.4 d8, PT_D8(sp) - move.4 d9, PT_D9(sp) - move.4 d10, PT_D10(sp) - move.4 d11, PT_D11(sp) - move.4 d12, PT_D12(sp) - move.4 d13, PT_D13(sp) - move.4 d14, PT_D14(sp) -;; move.4 d15, PT_D15(sp) - move.4 a0, PT_A0(sp) - move.4 a1, PT_A1(sp) - move.4 a2, PT_A2(sp) -;; move.4 a3, PT_A3(sp) - move.4 a4, PT_A4(sp) - move.4 a5, PT_A5(sp) - move.4 a6, PT_A6(sp) - move.4 acc0_hi, PT_ACC0HI(sp) - move.4 acc0_lo, PT_ACC0LO(sp) - move.4 mac_rc16, PT_MAC_RC16(sp) - move.4 acc1_hi, PT_ACC1HI(sp) - move.4 acc1_lo, PT_ACC1LO(sp) - move.4 source3, PT_SOURCE3(sp) - move.4 int_mask0, PT_INT_MASK0(sp) - move.4 int_mask1, PT_INT_MASK1(sp) -.endm - -/* - * complete_restore_context() - * Completely restore the context from sp (struct pt_reg *) - * - * Note: Recovered PC and CSR are saved on the stack and are to be - * popped off before returning. - */ -.macro complete_restore_context - move.4 a3, sp - move.4 d15, PT_D15(sp) - move.4 sp, PT_SP(a3) ; Recover Stack pointer from save area - move.4 -4(sp)++, PT_PC(a3) ; Recover saved PC and save to stack - move.4 -4(sp)++, PT_CSR(a3) ; Recover saved csr and save to stack - move.4 a3, PT_A3(a3) -.endm - -/* - * old restore_context macro - */ -.macro restore_context - begin_restore_context - complete_restore_context -.endm - -/* - * ldsr_thread_enable_interrupts() - * An assembly version of the enable interrupts function. - * - * The stack is fair game but all registers MUST be preserved. - * - */ -.macro ldsr_thread_enable_interrupts - move.4 -4(sp)++, d3 ; Push d3 - move.4 -4(sp)++, a3 ; Push a3 - - /* - * Read the ROSR and obtain ~(1 << tid) - */ - lsr.4 d3, rosr, #0x2 ; Move the thread portion of ROSR into d3 - lsl.4 d3, #1, d3 ; perform a (1 << tid) - not.4 d3, d3 ; Negate the value of d3 == ~(1 << threadid) - - /* - * Get the value of the ldsr_soft_irq_mask - */ - moveai a3, #%hi(ldsr_soft_irq_mask) - move.4 a3, %lo(ldsr_soft_irq_mask)(a3) - - /* - * Now re-enable interrupts for this thread and then - * wakeup the LDSR. - */ - and.4 scratchpad1, scratchpad1, d3 - move.4 int_set0, a3 - - /* - * Restore the registers. - */ - move.4 a3, (sp)4++ - move.4 d3, (sp)4++ -.endm - -/* - * ret_from_interrupt_to_kernel() - * RFI function that is where do_IRQ() returns to if the thread was - * in kernel space. - */ - .section .text.ret_from_interrupt_to_kernel, "ax", @progbits - .global ret_from_interrupt_to_kernel -ret_from_interrupt_to_kernel: - begin_restore_context ; Restore the thread context - atomic_lock_acquire ; Enter critical section - complete_restore_context ; Restore the thread context - atomic_lock_release ; Leave critical section - ldsr_thread_enable_interrupts ; enable the threads interrupts - move.4 csr, (sp)4++ ; Restore csr from the stack - ret (sp)4++ - -/* - * ret_from_interrupt_to_user() - * RFI function that is where do_IRQ() returns to if the thread was - * in user space. - * - * TODO: Do we really need the critical section handling in this code? - * - */ - .section .text.ret_from_interrupt_to_user, "ax", @progbits - .global ret_from_interrupt_to_user -ret_from_interrupt_to_user: - ldsr_thread_enable_interrupts ; enable the threads interrupts - /* - * Set a1 to the thread info pointer, no need to save it as we are - * restoring userspace and will never return - */ - movei d0, #(~(ASM_THREAD_SIZE-1)) - and.4 a1, sp, d0 - - /* - * Test if the scheduler needs to be called. - */ - btst TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED - jmpeq.t 2f - call a5, schedule ; Call the scheduler. I will come back here. - - /* - * See if we have pending signals and call do_signal - * if needed. - */ -2: - btst TI_FLAGS(a1), #ASM_TIF_SIGPENDING ; Any signals needed? - jmpeq.t 1f - - /* - * Now call do_signal() - */ - move.4 d0, #0 ; oldset pointer is NULL - move.4 d1, sp ; d1 is the regs pointer - call a5, do_signal ; Call do_signal() - - /* - * Back from do_signal(), re-enter critical section. - */ -1: - begin_restore_context ; Restore the thread context - atomic_lock_acquire ; Enter critical section - call a3, __complete_and_return_to_userspace ; jump to unprotected section - -/* - * restore_all_registers() - * - * restore_all_registers will be the alternate exit route for - * preempted processes that have called a signal handler - * and are returning back to user space. - */ - .section .text.restore_all_registers, "ax", @progbits - .global restore_all_registers -restore_all_registers: - begin_restore_context ; Restore the thread context - atomic_lock_acquire ; Enter critical section - call a3, __complete_and_return_to_userspace - -/* - * __complete_and_return_to_userspace - * - * restores the second half of the context and returns - * You must have the atomic lock when you call this function - */ - .section .kernel_unprotected, "ax", @progbits -__complete_and_return_to_userspace: - disable_kernel_ranges_for_current d15 ; disable kernel ranges - complete_restore_context ; restore previous context - atomic_lock_release ; Leave critical section - move.4 csr, (sp)4++ ; Restore csr from the stack - ret (sp)4++ - -/* - * ret_from_fork() - * Called on the child's return from fork system call. - */ - .section .text.ret_from_fork, "ax", @progbits - .global ret_from_fork -ret_from_fork: - ;;; d0 contains the arg for schedule_tail - ;;; the others we don't care about as they are in PT_REGS (sp) - call a5, schedule_tail - - atomic_lock_acquire ; Enter critical section - - move.4 a3, sp - move.4 d0, PT_D0(a3) ; Restore D0 - move.4 d1, PT_D1(a3) ; Restore D1 - move.4 d2, PT_D2(a3) ; Restore D2 - move.4 d3, PT_D3(a3) ; Restore D3 - move.4 d10, PT_D10(a3) ; Restore D10 - move.4 d11, PT_D11(a3) ; Restore D11 - move.4 d12, PT_D12(a3) ; Restore D12 - move.4 d13, PT_D13(a3) ; Restore D13 - move.4 a1, PT_A1(a3) ; Restore A1 - move.4 a2, PT_A2(a3) ; Restore A2 - move.4 a5, PT_A5(a3) ; Restore A5 - move.4 a6, PT_A6(a3) ; Restore A6 - ;; I think atomic_lock_acquire could be moved here.. - move.4 sp, PT_SP(a3) ; Restore sp - move.4 a4, PT_PC(a3) ; Restore pc in register a4 - move.4 PT_FRAME_TYPE(a3), #0 ; Clear frame_type to indicate it is invalid. - -#ifdef CONFIG_PROTECT_KERNEL - call a3, __ret_from_fork_bottom_half - .section .kernel_unprotected, "ax", @progbits -__ret_from_fork_bottom_half: - disable_kernel_ranges_for_current d15 -#endif - atomic_lock_release ; Leave critical section - calli a4, 0(a4) ; Return. - -/* - * __switch_to() - * - * Call with: - * void *__switch_to(struct task_struct *prev, struct thread_struct *prev_switch, - * struct thread_struct *next_switch) - */ - .section .text.__switch_to, "ax", @progbits - .global __switch_to -__switch_to: - - /* - * Set up register a3 to point to save area. - */ - movea a3, d1 ; a3 now holds prev_switch - move.4 (a3)4++, d10 - move.4 (a3)4++, d11 - move.4 (a3)4++, d12 - move.4 (a3)4++, d13 - move.4 (a3)4++, a1 - move.4 (a3)4++, a2 - move.4 (a3)4++, a5 - move.4 (a3)4++, a6 - move.4 (a3)4++, a7 - - /* - * Set up register a3 to point to restore area. - */ - movea a3, d2 ; a3 now holds next_switch - move.4 d10 , (a3)4++ - move.4 d11 , (a3)4++ - move.4 d12 , (a3)4++ - move.4 d13 , (a3)4++ - move.4 a1 , (a3)4++ - move.4 a2 , (a3)4++ - move.4 a5 , (a3)4++ - move.4 a6 , (a3)4++ - move.4 a7 , (a3)4++ - - /* - * Load the sw_ksp with the proper thread_info pointer. - */ - movei d15, #(~(ASM_THREAD_SIZE-1)) - and.4 a3, sp, d15 ; a3 now has the thread info pointer - moveai a4, #%hi(sw_ksp) - lea.1 a4, %lo(sw_ksp)(a4) ; a4 now has the base address of sw_ksp array - lsr.4 d15, ROSR, #2 ; Thread number - bit's 6 through 31 are zeroes anyway. - move.4 (a4, d15), a3 ; Load the thread info pointer into the hw_ksp array.. - - /* - * We are done with context switch. Time to return.. - */ - calli a5, 0(a5) - .size __switch_to, . - __switch_to - -/* - * ubicom32_emulate_insn() - * Emulates the instruction. - * - * Call with: - * unsigned int ubicom32_emulate_insn(int source1, int source2, int source3, int *save_acc, int *save_csr); - */ - .section .text.ubicom32_emulate_insn, "ax", @progbits - .global ubicom32_emulate_insn - .global trap_emulate -ubicom32_emulate_insn: - movea a3, d3 ; a3 holds save_acc pointer - movea a4, d4 ; a4 hods save_csr pointer - move.4 source3, d2 - move.4 acc0_lo, (a3) - move.4 acc0_hi, 4(a3) - move.4 acc1_lo, 8(a3) - move.4 acc1_hi, 12(a3) - move.4 mac_rc16, 16(a3) - move.4 CSR, (a4) - setcsr_flush 0 - -trap_emulate: - move.4 d0, d1 - setcsr_flush 0 - move.4 (a4), CSR ; Save csr - move.4 (a3), acc0_lo - move.4 4(a3), acc0_hi - move.4 8(a3), acc1_lo - move.4 12(a3), acc1_hi - move.4 16(a3), mac_rc16 - ret a5 - .size ubicom32_emulate_insn, . - ubicom32_emulate_insn diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c deleted file mode 100644 index ea7eb1575a..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_ksyms.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * arch/ubicom32/kernel/ubicom32_ksyms.c - * Ubicom32 architecture compiler support and misc symbols. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/module.h> -#include <linux/linkage.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/user.h> -#include <linux/elfcore.h> -#include <linux/in6.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/semaphore.h> - -#include <asm/setup.h> -#include <asm/machdep.h> -#include <asm/pgalloc.h> -#include <asm/irq.h> -#include <asm/checksum.h> -#include <asm/current.h> - -/* platform dependent support */ - -EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); - -EXPORT_SYMBOL(ip_fast_csum); - - -/* Networking helper routines. */ -EXPORT_SYMBOL(csum_partial_copy_nocheck); - -/* The following are special because they're not called - explicitly (the C compiler generates them). Fortunately, - their interface isn't gonna change any time soon now, so - it's OK to leave it out of version control. */ -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memmove); - -#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 -/* - * libgcc functions - functions that are used internally by the - * compiler... (prototypes are not correct though, but that - * doesn't really matter since they're not versioned). - */ -extern void __ashldi3(void); -extern void __ashrdi3(void); -extern void __divsi3(void); -extern void __divdi3(void); -extern void __lshrdi3(void); -extern void __modsi3(void); -extern void __muldi3(void); -extern void __udivsi3(void); -extern void __umodsi3(void); - -/* gcc lib functions */ -EXPORT_SYMBOL(__ashldi3); -EXPORT_SYMBOL(__ashrdi3); -EXPORT_SYMBOL(__divsi3); -EXPORT_SYMBOL(__divdi3); -EXPORT_SYMBOL(__lshrdi3); -EXPORT_SYMBOL(__modsi3); -EXPORT_SYMBOL(__muldi3); -EXPORT_SYMBOL(__udivsi3); -EXPORT_SYMBOL(__umodsi3); -#else -extern void __libgcc_udivmodsi(void); -extern void __libgcc_divmodsi(void); - -EXPORT_SYMBOL(__libgcc_udivmodsi); -EXPORT_SYMBOL(__libgcc_divmodsi); -#endif diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S deleted file mode 100644 index 870f66c8f4..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/ubicom32_syscall.S +++ /dev/null @@ -1,694 +0,0 @@ -/* - * arch/ubicom32/kernel/ubicom32_syscall.S - * <TODO: Replace with short file description> - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <linux/sys.h> -#include <linux/linkage.h> -#include <linux/unistd.h> - -#include <asm/ubicom32-common.h> -#include <asm/thread_info.h> -#include <asm/asm-offsets.h> -#include <asm/range-protect.h> - -/* - * __old_system_call() - */ - .section .old_syscall_entry.text, "ax", @progbits -#ifdef CONFIG_OLD_40400010_SYSTEM_CALL -__old_system_call: - call a3, system_call - .size __old_system_call, . - __old_system_call ; -#else - /* - * something that will crash the userspace application, but - * should not take down the kernel, if protection is enabled - * this will never even get executed. - */ - .long 0xFABBCCDE ; illegal instruction - bkpt #-1 ; we will never get here -#endif - -/* - * system_call() - */ - .section .syscall_entry.text, "ax", @progbits - .global system_call -system_call: - /* - * Regular ABI rules for function calls apply for syscall. d8 holds - * the syscall number. We will use that to index into the syscall table. - * d0 - d5 hold the parameters. - * - * First we get the current thread_info and swap to the kernel stack. - * This is done by reading the current thread and looking up the ksp - * from the sw_ksp array and storing it in a3. - * - * Then we reserve space for the syscall context a struct pt_regs and - * save it using a4 initially and later as sp. - * Once sp is set to the kernel sp we can leave the critical section. - * - * For the user case the kernel stack will have the following layout. - * - * a3 ksp[0] +-----------------------+ - * | Thread info area | - * | struct thread_info | - * +-----------------------+ - * : : - * | Kernel Stack Area | - * | | - * a4 / sp >>> +-----------------------+ - * | Context save area | - * | struct pt_reg | - * ksp[THREAD_SIZE-8] +-----------------------+ - * | 8 Byte Buffer Zone | - * ksp[THREAD_SIZE] +-----------------------+ - - * - * For kernel syscalls the layout is as follows. - * - * a3 ksp[0] +-----------------------+ - * | Thread info area | - * | struct thread_info | - * +-----------------------+ - * : : - * | Kernel Stack Area | - * | | - * a4 / sp >>> +-----------------------+ - * | Context save area | - * | struct pt_reg | - * sp at syscall entry +-----------------------+ - * | Callers Kernel Stack | - * : : - * - * Once the context is saved we optionally call syscall_trace and setup - * the exit routine and jump to the syscall. - */ - - /* - * load the base address for sw_ksp into a3 - * Note.. we cannot access it just yet as protection is still on. - */ - moveai a3, #%hi(sw_ksp) - lea.1 a3, %lo(sw_ksp)(a3) - - /* - * Enter critical section . - * - * The 'critical' aspects here are the switching the to the ksp and - * changing the protection registers, these both use per thread - * information so we need to protect from a context switch. For now this - * is done using the global atomic lock. - */ - atomic_lock_acquire - - thread_get_self d15 ; Load current thread number -#ifdef CONFIG_PROTECT_KERNEL - lsl.4 d9, #1, d15 ; Convert to thread bit - enable_kernel_ranges d9 -#endif - /* - * in order to reduce the size of code in the syscall section we get - * out of it right now - */ - call a4, __system_call_bottom_half - .size system_call, . - system_call - - .section .text.__system_call_bottom_half, "ax", @progbits -__system_call_bottom_half: - - /* - * We need to Determine if this is a kernel syscall or user syscall. - * Start by loading the pointer for the thread_info structure for the - * current process in to a3. - */ - move.4 a3, (a3, d15) ; a3 = sw_ksp[d15] - - /* - * Now if this is a kernel thread the same value can be a acheived by - * masking off the lower bits on the current stack pointer. - */ - movei d9, #(~(ASM_THREAD_SIZE-1)) ; load mask - and.4 d9, sp, d9 ; apply mask - - /* - * d9 now has the masked version of the sp. If this is identical to - * what is in a3 then don't switch to ksp as we are already in the - * kernel. - */ - sub.4 #0, a3, d9 - - /* - * if d9 and a3 are not equal. We are usespace and have to shift to - * ksp. - */ - jmpne.t 1f - - /* - * Kernel Syscall. - * - * The kernel has called this routine. We have to pdec space for pt_regs - * from sp. - */ - pdec a4, PT_SIZE(sp) ; a4 = ksp - PT_SIZE - jmpt.t 2f - - /* - * Userspace Syscall. - * - * Add THREAD_SIZE and subtract PT_SIZE to create the proper ksp - */ -1: movei d15, #(ASM_THREAD_SIZE - 8 - PT_SIZE) - lea.1 a4, (a3, d15) ; a4 = ksp + d15 - - /* - * Replace user stack pointer with kernel stack pointer (a4) - * Load -1 into frame_type in save area to indicate this is system call - * frame. - */ -2: move.4 PT_A7(a4), a7 ; Save old sp/A7 on kernel stack - move.4 PT_FRAME_TYPE(a4), #-1 ; Set the frame type. - move.4 sp, a4 ; Change to ksp. - /* - * We are now officially back in the kernel! - */ - - /* - * Now that we are on the ksp we can leave the critical section - */ - atomic_lock_release - - /* - * We need to save a0 because we need to be able to restore it in - * the event that we need to handle a signal. It's not generally - * a callee-saved register but is the GOT pointer. - */ - move.4 PT_A0(sp), a0 ; Save A0 on kernel stack - - /* - * We still need to save d10-d13, a1, a2, a5, a6 in the kernel frame - * for this process, we also save the system call params in the case of - * syscall restart. (note a7 was saved above) - */ - move.4 PT_A1(sp), a1 ; Save A1 on kernel stack - move.4 PT_A2(sp), a2 ; Save A2 on kernel stack - move.4 PT_A5(sp), a5 ; Save A5 on kernel stack - move.4 PT_A6(sp), a6 ; Save A6 on kernel stack - move.4 PT_PC(sp), a5 ; Save A5 at the PC location - move.4 PT_D10(sp), d10 ; Save D10 on kernel stack - move.4 PT_D11(sp), d11 ; Save D11 on kernel stack - move.4 PT_D12(sp), d12 ; Save D12 on kernel stack - move.4 PT_D13(sp), d13 ; Save D13 on kernel stack - - /* - * Now save the syscall parameters - */ - move.4 PT_D0(sp), d0 ; Save d0 on kernel stack - move.4 PT_ORIGINAL_D0(sp), d0 ; Save d0 on kernel stack - move.4 PT_D1(sp), d1 ; Save d1 on kernel stack - move.4 PT_D2(sp), d2 ; Save d2 on kernel stack - move.4 PT_D3(sp), d3 ; Save d3 on kernel stack - move.4 PT_D4(sp), d4 ; Save d4 on kernel stack - move.4 PT_D5(sp), d5 ; Save d5 on kernel stack - move.4 PT_D8(sp), d8 ; Save d8 on kernel stack - - /* - * Test if syscalls are being traced and if they are jump to syscall - * trace (it will comeback here) - */ - btst TI_FLAGS(a3), #ASM_TIF_SYSCALL_TRACE - jmpne.f .Lsystem_call__trace -.Lsystem_call__trace_complete: - /* - * Check for a valid call number [ 0 <= syscall_number < NR_syscalls ] - */ - cmpi d8, #0 - jmplt.f 3f - cmpi d8, #NR_syscalls - jmplt.t 4f - - /* - * They have passed an invalid number. Call sys_ni_syscall staring by - * load a4 with the base address of sys_ni_syscall - */ -3: moveai a4, #%hi(sys_ni_syscall) - lea.1 a4, %lo(sys_ni_syscall)(a4) - jmpt.t 5f ; Jump to regular processing - - /* - * Validated syscall, load the syscall table base address into a3 and - * read the syscall ptr out. - */ -4: moveai a3, #%hi(sys_call_table) - lea.1 a3, %lo(sys_call_table)(a3) ; a3 = sys_call_table - move.4 a4, (a3, d8) ; a4 = sys_call_table[d8] - - /* - * Before calling the syscall, setup a5 so that syscall_exit is called - * on return from syscall - */ -5: moveai a5, #%hi(syscall_exit) ; Setup return address - lea.1 a5, %lo(syscall_exit)(a5) ; from system call - - /* - * If the syscall is __NR_rt_rigreturn then we have to test d1 to - * figure out if we have to change change the return routine to restore - * all registers. - */ - cmpi d8, #__NR_rt_sigreturn - jmpeq.f 6f - - /* - * Launch system call (it will return through a5 - syscall_exit) - */ - calli a3, 0(a4) - - /* - * System call is rt_sigreturn. Test d1. If it is 1 we have to - * change the return address to restore_all_registers - */ -6: cmpi d1, #1 - jmpne.t 7f - - moveai a5, #%hi(restore_all_registers) ; Setup return address - lea.1 a5, %lo(restore_all_registers)(a5) ; to restore_all_registers. - - /* - * Launch system call (it will return through a5) - */ -7: calli a3, 0(a4) ; Launch system call - -.Lsystem_call__trace: - /* - * Syscalls are being traced. - * Call syscall_trace, (return here) - */ - call a5, syscall_trace - - /* - * Restore syscall state (it would have been discarded during the - * syscall trace) - */ - move.4 d0, PT_D0(sp) ; Restore d0 from kernel stack - move.4 d1, PT_D1(sp) ; Restore d1 from kernel stack - move.4 d2, PT_D2(sp) ; Restore d2 from kernel stack - move.4 d3, PT_D3(sp) ; Restore d3 from kernel stack - move.4 d4, PT_D4(sp) ; Restore d4 from kernel stack - move.4 d5, PT_D5(sp) ; Restore d5 from kernel stack - /* add this back if we ever have a syscall with 7 args */ - move.4 d8, PT_D8(sp) ; Restore d8 from kernel stack - - /* - * return to syscall - */ - jmpt.t .Lsystem_call__trace_complete - .size __system_call_bottom_half, . - __system_call_bottom_half - -/* - * syscall_exit() - */ - .section .text.syscall_exit - .global syscall_exit -syscall_exit: - /* - * d0 contains the return value. We should move that into the kernel - * stack d0 location. We will be transitioning from kernel to user - * mode. Test the flags and see if we have to call schedule. If we are - * going to truly exit then all that has to be done is that from the - * kernel stack we have to restore d0, a0, a1, a2, a5, a6 and sp (a7)bb - * and then return via a5. - */ - - /* - * Save d0 to pt_regs - */ - move.4 PT_D0(sp), d0 ; Save d0 into the kernel stack - - /* - * load the thread_info structure by masking off the THREAD_SIZE - * bits. - * - * Note: we used to push a1, but now we don't as we are going - * to eventually restore it to the userspace a1. - */ - movei d9, #(~(ASM_THREAD_SIZE-1)) - and.4 a1, sp, d9 - - /* - * Are any interesting bits set on TI flags, if there are jump - * aside to post_processing. - */ - move.4 d9, #(_TIF_SYSCALL_TRACE | _TIF_NEED_RESCHED | _TIF_SIGPENDING) - and.4 #0, TI_FLAGS(a1), d9 - jmpne.f .Lsyscall_exit__post_processing ; jump to handler -.Lsyscall_exit__post_processing_complete: - - move.4 d0, PT_D0(sp) ; Restore D0 from kernel stack - move.4 d1, PT_D1(sp) ; Restore d1 from kernel stack - move.4 d2, PT_D2(sp) ; Restore d2 from kernel stack - move.4 d3, PT_D3(sp) ; Restore d3 from kernel stack - move.4 d4, PT_D4(sp) ; Restore d4 from kernel stack - move.4 d5, PT_D5(sp) ; Restore d5 from kernel stack - move.4 d8, PT_D8(sp) ; Restore d8 from kernel stack - move.4 d10, PT_D10(sp) ; Restore d10 from kernel stack - move.4 d11, PT_D11(sp) ; Restore d11 from kernel stack - move.4 d12, PT_D12(sp) ; Restore d12 from kernel stack - move.4 d13, PT_D13(sp) ; Restore d13 from kernel stack - move.4 a1, PT_A1(sp) ; Restore A1 from kernel stack - move.4 a2, PT_A2(sp) ; Restore A2 from kernel stack - move.4 a5, PT_A5(sp) ; Restore A5 from kernel stack - move.4 a6, PT_A6(sp) ; Restore A6 from kernel stack - move.4 a0, PT_A0(sp) ; Restore A6 from kernel stack - - /* - * this is only for debug, and could be removed for production builds - */ - move.4 PT_FRAME_TYPE(sp), #0 ; invalidate frame_type - -#ifdef CONFIG_PROTECT_KERNEL - - call a4, __syscall_exit_bottom_half - - .section .kernel_unprotected, "ax", @progbits -__syscall_exit_bottom_half: - /* - * Enter critical section - */ - atomic_lock_acquire - disable_kernel_ranges_for_current d15 -#endif - /* - * Lastly restore userspace stack ptr - * - * Note: that when protection is on we need to hold the lock around the - * stack swap as well because otherwise the protection could get - * inadvertently disabled again at the end of a context switch. - */ - move.4 a7, PT_A7(sp) ; Restore A7 from kernel stack - - /* - * We are now officially back in userspace! - */ - -#ifdef CONFIG_PROTECT_KERNEL - /* - * Leave critical section and return to user space. - */ - atomic_lock_release -#endif - calli a5, 0(a5) ; Back to userspace code. - - bkpt #-1 ; we will never get here - - /* - * Post syscall processing. (unlikely part of syscall_exit) - * - * Are we tracing syscalls. If TIF_SYSCALL_TRACE is set, call - * syscall_trace routine and return here. - */ - .section .text.syscall_exit, "ax", @progbits -.Lsyscall_exit__post_processing: - btst TI_FLAGS(a1), #ASM_TIF_SYSCALL_TRACE - jmpeq.t 1f - call a5, syscall_trace - - /* - * Do we need to resched ie call schedule. If TIF_NEED_RESCHED is set, - * call the scheduler, it will come back here. - */ -1: btst TI_FLAGS(a1), #ASM_TIF_NEED_RESCHED - jmpeq.t 2f - call a5, schedule - - /* - * Do we need to post a signal, if TIF_SIGPENDING is set call the - * do_signal. - */ -2: btst TI_FLAGS(a1), #ASM_TIF_SIGPENDING - jmpeq.t .Lsyscall_exit__post_processing_complete - - /* - * setup the do signal call - */ - move.4 d0, #0 ; oldset pointer is NULL - lea.1 d1, (sp) ; d1 is the regs pointer. - call a5, do_signal - - jmpt.t .Lsyscall_exit__post_processing_complete - -/* .size syscall_exit, . - syscall_exit */ - -/* - * kernel_execve() - * kernel_execv is called when we the kernel is starting a - * userspace application. - */ - .section .kernel_unprotected, "ax", @progbits - .global kernel_execve -kernel_execve: - move.4 -4(sp)++, a5 ; Save return address - /* - * Call execve - */ - movei d8, #__NR_execve ; call execve - call a5, system_call - move.4 a5, (sp)4++ - - /* - * protection was enabled again at syscall exit, but we want - * to return to kernel so we enable it again. - */ -#ifdef CONFIG_PROTECT_KERNEL - /* - * We are entering the kernel so we need to disable the protection. - * Enter critical section, disable ranges and leave critical section. - */ - call a3, __enable_kernel_ranges ; and jump back to kernel -#else - ret a5 ; jump back to the kernel -#endif - - .size kernel_execve, . - kernel_execve - -/* - * signal_trampoline() - * - * Deals with transitioning from to userspace signal handlers and returning - * to userspace, only called from the kernel. - * - */ - .section .kernel_unprotected, "ax", @progbits - .global signal_trampoline -signal_trampoline: - /* - * signal_trampoline is called when we are jumping from the kernel to - * the userspace signal handler. - * - * The following registers are relevant. (set setup_rt_frame) - * sp is the user space stack not the kernel stack - * d0 = signal number - * d1 = siginfo_t * - * d2 = ucontext * - * d3 = the user space signal handler - * a0 is set to the GOT if userspace application is FDPIC, otherwise 0 - * a3 is set to the FD for the signal if userspace application is FDPIC - */ -#ifdef CONFIG_PROTECT_KERNEL - /* - * We are leaving the kernel so we need to enable the protection. - * Enter critical section, disable ranges and leave critical section. - */ - atomic_lock_acquire ; Enter critical section - disable_kernel_ranges_for_current d15 ; disable kernel ranges - atomic_lock_release ; Leave critical section -#endif - /* - * The signal handler pointer is in register d3 so tranfer it to a4 and - * call it - */ - movea a4, d3 ; signal handler - calli a5, 0(a4) - - /* - * Return to userspace through rt_syscall which is stored on top of the - * stack d1 contains ret_via_interrupt status. - */ - move.4 d8, (sp) ; d8 (syscall #) = rt_syscall - move.4 d1, 4(sp) ; d1 = ret_via_interrupt - call a5, system_call ; as we are 'in' the kernel - ; we can call kernel_syscall - - bkpt #-1 ; will never get here. - .size signal_trampoline, . - signal_trampoline - -/* - * kernel_thread_helper() - * - * Entry point for kernel threads (only referenced by kernel_thread()). - * - * On execution d0 will be 0, d1 will be the argument to be passed to the - * kernel function. - * d2 contains the kernel function that needs to get called. - * d3 will contain address to do_exit which needs to get moved into a5. - * - * On return from fork the child thread d0 will be 0. We call this dummy - * function which in turn loads the argument - */ - .section .kernel_unprotected, "ax", @progbits - .global kernel_thread_helper -kernel_thread_helper: - /* - * Create a kernel thread. This is called from ret_from_vfork (a - * userspace return routine) so we need to put it in an unprotected - * section and re-enable protection before calling the vector in d2. - */ - -#ifdef CONFIG_PROTECT_KERNEL - /* - * We are entering the kernel so we need to disable the protection. - * Enter critical section, disable ranges and leave critical section. - */ - call a5, __enable_kernel_ranges -#endif - /* - * Move argument for kernel function into d0, and set a5 return address - * (a5) to do_exit and return through a2 - */ - move.4 d0, d1 ; d0 = arg - move.4 a5, d3 ; a5 = do_exit - ret d2 ; call function ptr in d2 - .size kernel_thread_helper, . - kernel_thread_helper - -#ifdef CONFIG_PROTECT_KERNEL - .section .kernel_unprotected, "ax", @progbits -__enable_kernel_ranges: - atomic_lock_acquire ; Enter critical section - enable_kernel_ranges_for_current d15 - atomic_lock_release ; Leave critical section - calli a5, 0(a5) - .size __enable_kernel_ranges, . - __enable_kernel_ranges - -#endif - -/* - * The following system call intercept functions where we setup the - * input to the real system call. In all cases these are just taking - * the current sp which is pointing to pt_regs and pushing it into the - * last arg of the system call. - * - * i.e. the public definition of sys_execv is - * sys_execve( char *name, - * char **argv, - * char **envp ) - * but process.c defines it as - * sys_execve( char *name, - * char **argv, - * char **envp, - * struct pt_regs *regs ) - * - * so execve_intercept needs to populate the 4th arg with pt_regs*, - * which is the stack pointer as we know we must be coming out of - * system_call - * - * The intercept vectors are referenced by syscalltable.S - */ - -/* - * execve_intercept() - */ - .section .text.execve_intercept, "ax", @progbits - .global execve_intercept -execve_intercept: - move.4 d3, sp ; Save pt_regs address - call a3, sys_execve - - .size execve_intercept, . - execve_intercept - -/* - * vfork_intercept() - */ - .section .text.vfork_intercept, "ax", @progbits - .global vfork_intercept -vfork_intercept: - move.4 d0, sp ; Save pt_regs address - call a3, sys_vfork - - .size vfork_intercept, . - vfork_intercept - -/* - * clone_intercept() - */ - .section .text.clone_intercept, "ax", @progbits - .global clone_intercept -clone_intercept: - move.4 d2, sp ; Save pt_regs address - call a3, sys_clone - - .size clone_intercept, . - clone_intercept - -/* - * sys_sigsuspend() - */ - .section .text.sigclone_intercept, "ax", @progbits - .global sys_sigsuspend -sys_sigsuspend: - move.4 d0, sp ; Pass pointer to pt_regs in d0 - call a3, do_sigsuspend - - .size sys_sigsuspend, . - sys_sigsuspend - -/* - * sys_rt_sigsuspend() - */ - .section .text.sys_rt_sigsuspend, "ax", @progbits - .global sys_rt_sigsuspend -sys_rt_sigsuspend: - move.4 d0, sp ; Pass pointer to pt_regs in d0 - call a3, do_rt_sigsuspend - - .size sys_rt_sigsuspend, . - sys_rt_sigsuspend - -/* - * sys_rt_sigreturn() - */ - .section .text.sys_rt_sigreturn, "ax", @progbits - .global sys_rt_sigreturn -sys_rt_sigreturn: - move.4 d0, sp ; Pass pointer to pt_regs in d0 - call a3, do_rt_sigreturn - - .size sys_rt_sigreturn, . - sys_rt_sigreturn - -/* - * sys_sigaltstack() - */ - .section .text.sys_sigaltstack, "ax", @progbits - .global sys_sigaltstack -sys_sigaltstack: - move.4 d0, sp ; Pass pointer to pt_regs in d0 - call a3, do_sys_sigaltstack - - .size sys_sigaltstack, . - sys_sigaltstack diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c b/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c deleted file mode 100644 index d856d061dc..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/unaligned_trap.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * arch/ubicom32/kernel/unaligned_trap.c - * Handle unaligned traps in both user or kernel space. - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <asm/cacheflush.h> -#include <asm/traps.h> - -#define FALSE 0 -#define TRUE 1 - -/* no possible trap */ -#define UNUSED 0 -/* possible source operand trap */ -#define SRC 1 -#define SRC_2 2 -/* possible destination operand trap */ -#define DEST 3 -#define DEST_2 4 -/* can be either source or destination or both */ -#define TWO_OP 5 -#define TWO_OP_2 6 - -/* TODO: What is the real value here, put something in to make it compile for - * now */ -#define MOVE_2 0x0d -#define LSL_2 0x11 -#define LSR_2 0x13 -#define MOVEI 0x19 -#define CMPI 0x18 - -static int op_format[32] = -{ - TWO_OP, /* 0x00 */ - UNUSED, - SRC, - UNUSED, - TWO_OP, /* 0x04 */ - TWO_OP, - SRC, - UNUSED, - TWO_OP_2, /* 0x08 */ - TWO_OP, - TWO_OP_2, - TWO_OP, - TWO_OP_2, /* 0x0C */ - TWO_OP, - TWO_OP_2, - TWO_OP, - TWO_OP, /* 0x10 */ - TWO_OP_2, - TWO_OP, - TWO_OP, - UNUSED, /* 0x14 */ - UNUSED, - UNUSED, - UNUSED, - SRC_2, /* 0x18 */ - DEST_2, - UNUSED, - UNUSED, - UNUSED, /* 0x1C */ - UNUSED, - UNUSED, /* unaligned CALLI will not be fixed. */ - UNUSED -}; - -static int op_0_format[32] = -{ - UNUSED, /* 0x00 */ - UNUSED, - UNUSED, - UNUSED, - UNUSED, /* 0x04 - ret don't fix - bad ret is always wrong */ - UNUSED, - UNUSED, - UNUSED, - UNUSED, /* 0x08 */ - UNUSED, - TWO_OP, - TWO_OP_2, - TWO_OP, /* 0x0c */ - TWO_OP_2, - TWO_OP, - UNUSED, /* .1 can't trap */ - UNUSED, /* 0x10 */ - UNUSED, - SRC, - UNUSED, - UNUSED, /* 0x14 */ - TWO_OP_2, - UNUSED, - UNUSED, - UNUSED, /* 0x18 */ - UNUSED, - UNUSED, - UNUSED, - DEST, /* 0x1c */ - DEST, - DEST, - DEST, /* all lea have 32-bit destination */ -}; - -static int op_2_format[32] = -{ - UNUSED, /* 0x00 */ - UNUSED, - UNUSED, - UNUSED, - UNUSED, /* 0x04 */ - UNUSED, - SRC, - UNUSED, - UNUSED, /* 0x08 crcgen is .1 */ - UNUSED, - UNUSED, - UNUSED, - UNUSED, /* 0x0c */ - UNUSED, - UNUSED, - UNUSED, - SRC, /* 0x10 */ - SRC_2, - SRC, - SRC_2, - SRC, /* 0x14 */ - SRC_2, - SRC, - UNUSED, - UNUSED, /* 0x18 */ - UNUSED, - SRC, - UNUSED, - SRC, /* 0x1c */ - UNUSED, - SRC_2, - UNUSED, -}; - -static int op_6_format[32] = -{ - SRC_2, /* 0x00 */ - SRC_2, - SRC_2, - SRC_2, - SRC_2, /* 0x04 */ - SRC_2, - UNUSED, - SRC_2, - SRC, /* 0x08 MULS.4 */ - SRC_2, - SRC, - UNUSED, - UNUSED, /* 0x0c */ - UNUSED, - UNUSED, - UNUSED, - SRC, /* 0x10 */ - SRC_2, - SRC, - SRC_2, - UNUSED, /* 0x14 */ - UNUSED, - UNUSED, - UNUSED, - UNUSED, /* 0x18 */ - UNUSED, - UNUSED, - UNUSED, - UNUSED, /* 0x1c */ - UNUSED, - UNUSED, - UNUSED, -}; - -/* - * unaligned_get_address() - * get an address using save_an and save_dn registers, and updates save_an - * with side effects - */ -unsigned char *unaligned_get_address(int thread, int specifier, int four_byte, - unsigned int save_an[], - unsigned int save_dn[], int *write_back_an) -{ - unsigned char *address; - - int areg = (specifier >> 5) & 7; - if ((specifier >> 8) == 2) { - int offset = specifier & 0xf; - offset = ((offset << 28) >> 28); - if (likely(four_byte)) { - offset <<= 2; - } else { - offset <<= 1; - } - if (specifier & 0x10) { - address = (unsigned char *)(save_an[areg] + offset); - } else { - address = (unsigned char *)save_an[areg]; - } - save_an[areg] = save_an[areg] + offset; - - /* - * Let caller know An registers have been modified. - */ - *write_back_an = 1; - } else if ((specifier >> 8) == 3) { - int dreg = specifier & 0xf; - if (likely(four_byte)) { - address = (unsigned char *)(save_an[areg] + - (save_dn[dreg] << 2)); - } else { - address = (unsigned char *)(save_an[areg] + - (save_dn[dreg] << 1)); - } - } else { - int offset = ((specifier >> 3) & 0x60) | (specifier & 0x1f); - if (likely(four_byte)) { - address = (unsigned char *)(save_an[areg] + - (offset << 2)); - } else { - address = (unsigned char *)(save_an[areg] + - (offset << 1)); - } - } - - return address; -} - -static int save_dn[16]; -static int save_an[8]; -static int save_acc[5]; - -/* - * unaligned_emulate() - * emulate the instruction at thread's pc that has taken an unaligned data - * trap. - * - * source or destination or both might be unaligned - * the instruction must have a memory source or destination or both - * the emulated instruction is copied and executed in this thread - * - * TODO: Protection is handled outside of this function - * TODO: handling simultaneous unaligned and memory protection traps - * - * Get thread state - * the PC and instruction (and local copy, emulate_inst), and An - * and Dn registers - * All implicit soruce state (source3, CSR, accumulators) - - * if the instruction has a memory source - * Use the instruction, An and Dn registers to form src_address - * get unaligned source data from src_address (usually sign - * extended) - * (2 bytes, with or without sign extension, or 4 bytes) - * modify emulate_inst to use d0 as source - * else - * get the soure operand from one of thread's registers - * if instruction has a memory destination - * Use the instruction, An and Dn registers to form dest_address - * modify emulate_inst to use d0 as destination - * if there was a memory source - * put the source data in thread's d0 - * get the source-2 Dn operand and source 3 operand from thread - * execute modified inst - * (save it, flush caches, set up local values for implicit - * sources, execute, save explicit and implicit results) - * if inst has destination address - * copy result to dest_address, possibly unaligned, 1, 2, or 4 - * bytes - * restore thread's implicit results (modified address registers, CSR, - * accumulators) add 4 to thread's pc - */ -void unaligned_emulate(unsigned int thread) -{ - unsigned int pc; - unsigned int inst; - unsigned int op; - unsigned int subop; - int format; - unsigned int emulate_inst; - int four_byte; - int src_operand, dest_operand; - int save_csr; - int source3; - unsigned int source1; - unsigned int source_data; - unsigned char *dest_address = NULL; - int source2 = 0; - unsigned int result; - unsigned int write_back_an = 0; - unsigned int chip_id_copy; - - extern unsigned int trap_emulate; - extern unsigned int ubicom32_emulate_insn(int source1, int source2, - int source3, int *save_acc, - int *save_csr); - - /* - * get the chip_id - */ - asm volatile ( - " move.4 %0, chip_id \n\t" /* get chip_id. */ - : "=r"(chip_id_copy) - : - ); - - /* - * get the pc - */ - asm volatile ( - " move.4 CSR, %1 \n\t" /* set source thread in - * CSR */ - " setcsr_flush 0 \n\t" - " move.4 %0, pc \n\t" - " move.4 CSR, #0 \n\t" /* restore CSR */ - " setcsr_flush 0 \n\t" - : "=a"(pc) - : "d" ((1 << 8) | (thread << 9)) - : "cc" - ); - - inst = *((unsigned int *)pc); - op = inst >> 27; - if (unlikely(op == 2 || op == 6)) { - subop = (inst >> 21) & 0x1f; - } else { - subop = (inst >> 11) & 0x1f; - } - format = op_format[op]; - emulate_inst = inst; - - if (op == 0) { - format = op_0_format[subop]; - } else if (op == 2) { - format = op_2_format[subop]; - } else if (op == 6) { - format = op_6_format[subop]; - } - - if (unlikely(format == UNUSED)) { - /* - * We are not going to emulate this. Bump PC by 4 and move on. - */ - asm volatile ( - " move.4 CSR, %0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 pc, %1 \n\t" - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - : - : "d"((1 << 14) | (thread << 15)), "d"(pc + 4) - : "cc" - ); - return; - } - - four_byte = (format == TWO_OP || format == DEST || format == SRC); - - /* - * source or destination memory operand needs emulation - */ - src_operand = (format == SRC || - format == SRC_2 || - format == TWO_OP || - format == TWO_OP_2) && - ((inst >> 8) & 7) > 1; - - dest_operand = (format == DEST || - format == DEST_2 || - format == TWO_OP || - format == TWO_OP_2) && - ((inst >> 24) & 7) > 1; - - /* - * get thread's implicit sources (not covered by source context select). - * data and address registers and CSR (for flag bits) and src3 and - * accumulators - */ - asm volatile ( - " move.4 CSR, %2 \n\t" /* set source thread in - * CSR */ - " setcsr_flush 0 \n\t" - " move.4 (%3), d0 \n\t" /* get dn registers */ - " move.4 4(%3), d1 \n\t" - " move.4 8(%3), d2 \n\t" - " move.4 12(%3), d3 \n\t" - " move.4 16(%3), d4 \n\t" - " move.4 20(%3), d5 \n\t" - " move.4 24(%3), d6 \n\t" - " move.4 28(%3), d7 \n\t" - " move.4 32(%3), d8 \n\t" - " move.4 36(%3), d9 \n\t" - " move.4 40(%3), d10 \n\t" - " move.4 44(%3), d11 \n\t" - " move.4 48(%3), d12 \n\t" - " move.4 52(%3), d13 \n\t" - " move.4 56(%3), d14 \n\t" - " move.4 60(%3), d15 \n\t" - " move.4 (%4), a0 \n\t" /* get an registers */ - " move.4 4(%4), a1 \n\t" - " move.4 8(%4), a2 \n\t" - " move.4 12(%4), a3 \n\t" - " move.4 16(%4), a4 \n\t" - " move.4 20(%4), a5 \n\t" - " move.4 24(%4), a6 \n\t" - " move.4 28(%4), a7 \n\t" - " move.4 %0, CSR \n\t" /* get csr and source3 - * implicit operands */ - " move.4 %1, source3 \n\t" - " move.4 (%5), acc0_lo \n\t" /* get accumulators */ - " move.4 4(%5), acc0_hi \n\t" - " move.4 8(%5), acc1_lo \n\t" - " move.4 12(%5), acc1_hi \n\t" - " move.4 16(%5), mac_rc16 \n\t" - " move.4 CSR, #0 \n\t" /* restore CSR */ - " setcsr_flush 0 \n\t" - : "=m"(save_csr), "=m"(source3) - : "d"((1 << 8) | (thread << 9)), - "a"(save_dn), "a"(save_an), "a"(save_acc) - : "cc" - ); - - /* - * turn off thread select bits if they were on - */ - BUG_ON((save_csr & 0x04100) != 0); - if (unlikely(save_csr & 0x04100)) { - /* - * Things are in funny state as thread select bits are on in - * csr. PANIC. - */ - panic("In unaligned trap handler. Trap thread CSR has thread " - "select bits on.\n"); - } - - save_csr = save_csr & 0x1000ff; - - /* - * get the source1 operand - */ - source1 = 0; - if (src_operand) { - unsigned char *src_address; - - /* - * source1 comes from memory - */ - BUG_ON(!(format == TWO_OP || format == TWO_OP_2 || - format == SRC || format == SRC_2)); - src_address = unaligned_get_address(thread, inst & 0x7ff, - four_byte, save_an, - save_dn, &write_back_an); - - /* - * get data (possibly unaligned) - */ - if (likely(four_byte)) { - source_data = (*src_address << 24) | - (*(src_address + 1) << 16) | - (*(src_address + 2) << 8) | - *(src_address + 3); - source1 = source_data; - } else { - source1 = *src_address << 8 | - *(src_address + 1); - - /* - * Source is not extended if the instrution is MOVE.2 or - * if the cpu CHIP_ID >= 0x30000 and the instruction is - * either LSL.2 or LSR.2. All other cases have to be - * sign extended. - */ - if ((!(op == 2 && subop == MOVE_2)) && - (!((chip_id_copy >= 0x30000) && - (subop == LSL_2 || subop == LSR_2)))) { - /* - * Have to sign extend the .2 entry. - */ - source1 = ((unsigned int) - ((signed int) - ((signed short) source1))); - } - } - } else if (likely(op != MOVEI)) { - /* - * source1 comes from a register, using move.4 d0, src1 - * unaligned_emulate_get_source is pointer to code to insert remulated instruction - */ - extern unsigned int unaligned_emulate_get_src; - *((int *)&unaligned_emulate_get_src) &= ~(0x7ff); - *((int *)&unaligned_emulate_get_src) |= (inst & 0x7ff); - flush_dcache_range((unsigned long)(&unaligned_emulate_get_src), - (unsigned long)(&unaligned_emulate_get_src) + 4); - - asm volatile ( - /* source1 uses thread's registers */ - " move.4 CSR, %1 \n\t" - " setcsr_flush 0 \n\t" - "unaligned_emulate_get_src: \n\t" - " move.4 %0, #0 \n\t" - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - : "=d" (source1) - : "d" ((1 << 8) | (thread << 9)) - : "cc" - ); - } - - /* - * get the destination address - */ - if (dest_operand) { - BUG_ON(!(format == TWO_OP || format == TWO_OP_2 || - format == DEST || format == DEST_2)); - dest_address = unaligned_get_address(thread, - ((inst >> 16) & 0x7ff), - four_byte, save_an, - save_dn, &write_back_an); - } - - if (write_back_an) { - /* - * restore any modified An registers - */ - asm volatile ( - " move.4 CSR, %0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 a0, (%1) \n\t" - " move.4 a1, 4(%1) \n\t" - " move.4 a2, 8(%1) \n\t" - " move.4 a3, 12(%1) \n\t" - " move.4 a4, 16(%1) \n\t" - " move.4 a5, 20(%1) \n\t" - " move.4 a6, 24(%1) \n\t" - " move.4 a7, 28(%1) \n\t" - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - : - : "d" ((1 << 14) | (thread << 15)), "a" (save_an) - : "cc" - ); - } - - /* - * get source 2 register if needed, and modify inst to use d1 for - * source-2 source-2 will come from this thread, not the trapping thread - */ - source2 = 0; - if ((op >= 8 && op <= 0x17) || - ((op == 2 || op == 6) && (inst & 0x4000000))) { - int src_dn = (inst >> 11) & 0xf; - source2 = save_dn[src_dn]; - /* - * force the emulated instruction to use d1 for source2 operand - */ - emulate_inst = (emulate_inst & 0xffff07ff) | 0x800; - } - - if (likely(op != MOVEI)) { - /* - * change emulated instruction source1 to d0 - */ - emulate_inst &= ~0x7ff; - emulate_inst |= 1 << 8; - } - - if (unlikely(op == 6 || op == 2)) { - /* - * Set destination to d0 - */ - emulate_inst &= ~(0xf << 16); - } else if (likely(op != CMPI)) { - /* - * Set general destination field to d0. - */ - emulate_inst &= ~(0x7ff << 16); - emulate_inst |= 1 << 24; - } - - /* - * execute emulated instruction d0, to d0, no memory access - * source2 if needed will be in d1 - * source3, CSR, and accumulators are set up before execution - */ - *((unsigned int *)&trap_emulate) = emulate_inst; - flush_dcache_range((unsigned long)(&trap_emulate), - (unsigned long)(&trap_emulate) + 4); - - result = ubicom32_emulate_insn(source1, source2, source3, - save_acc, &save_csr); - - /* - * set the result value - */ - if (dest_operand) { - /* - * copy result to memory - */ - if (four_byte) { - *dest_address++ = - (unsigned char)((result >> 24) & 0xff); - *dest_address++ = - (unsigned char)((result >> 16) & 0xff); - } - *dest_address++ = (unsigned char)((result >> 8) & 0xff); - *dest_address = (unsigned char)(result & 0xff); - } else if (likely(op != CMPI)) { - /* - * copy result to a register, using move.4 dest, result - */ - extern unsigned int unaligned_trap_set_result; - *((unsigned int *)&unaligned_trap_set_result) &= ~0x7ff0000; - - if (op == 2 || op == 6) { - *((unsigned int *)&unaligned_trap_set_result) |= - ((inst & 0x000f0000) | 0x01000000); - } else { - *((unsigned int *)&unaligned_trap_set_result) |= - (inst & 0x7ff0000); - } - flush_dcache_range((unsigned long)&unaligned_trap_set_result, - ((unsigned long)(&unaligned_trap_set_result) + 4)); - - asm volatile ( - /* result uses thread's registers */ - " move.4 CSR, %1 \n\t" - " setcsr_flush 0 \n\t" - "unaligned_trap_set_result: \n\t" - " move.4 #0, %0 \n\t" - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - : - : "d"(result), "d" ((1 << 14) | (thread << 15)) - : "cc" - ); - } - - /* - * bump PC in thread and restore implicit register changes - */ - asm volatile ( - " move.4 CSR, %0 \n\t" - " setcsr_flush 0 \n\t" - " move.4 pc, %1 \n\t" - " move.4 acc0_lo, (%3) \n\t" - " move.4 acc0_hi, 4(%3) \n\t" - " move.4 acc1_lo, 8(%3) \n\t" - " move.4 acc1_hi, 12(%3) \n\t" - " move.4 mac_rc16, 16(%3) \n\t" - " move.4 CSR, %2 \n\t" - " setcsr #0 \n\t" - " setcsr_flush 0 \n\t" - : - : "d"((1 << 14) | (thread << 15)), - "d"(pc + 4), "d"(save_csr), "a"(save_acc) - : "cc" - ); -} - -/* - * unaligned_only() - * Return true if either of the unaligned causes are set (and no others). - */ -int unaligned_only(unsigned int cause) -{ - unsigned int unaligned_cause_mask = - (1 << TRAP_CAUSE_DST_MISALIGNED) | - (1 << TRAP_CAUSE_SRC1_MISALIGNED); - - BUG_ON(cause == 0); - return (cause & unaligned_cause_mask) == cause; -} diff --git a/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S b/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S deleted file mode 100644 index cd646772cf..0000000000 --- a/target/linux/ubicom32/files/arch/ubicom32/kernel/vmlinux.lds.S +++ /dev/null @@ -1,370 +0,0 @@ -/* - * arch/ubicom32/kernel/vmlinux.lds.S - * vmlinux primary linker script - * - * (C) Copyright 2009, Ubicom, Inc. - * - * This file is part of the Ubicom32 Linux Kernel Port. - * - * The Ubicom32 Linux Kernel Port is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 2 of the - * License, or (at your option) any later version. - * - * The Ubicom32 Linux Kernel Port 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 the Ubicom32 Linux Kernel Port. If not, - * see <http://www.gnu.org/licenses/>. - * - * Ubicom32 implementation derived from (with many thanks): - * arch/m68knommu - * arch/blackfin - * arch/parisc - */ -#include <asm-generic/vmlinux.lds.h> -#include <asm/ocm_size.h> -#include <asm/memory_map.h> -#include <asm/thread_info.h> -#include <linux/threads.h> - -/* - * Sanity checks to prevent errors later on that are much harder to understand - */ -#if !defined APP_OCM_CODE_SIZE -#error APP_OCM_CODE_SIZE has not been defined in ocm_size.h -#endif - -#if !defined APP_OCM_DATA_SIZE -#error APP_OCM_DATA_SIZE has not been defined in ocm_size.h -#endif - -/* - * The `free' ocm area that ultra does not use. - */ -#if APP_OCM_CODE_SIZE || APP_OCM_DATA_SIZE -#define OCM_FREE_START (OCMSTART + APP_OCM_CODE_SIZE) -#define OCM_FREE_LENGTH (OCMSIZE - APP_OCM_CODE_SIZE - APP_OCM_DATA_SIZE) -#else -#define OCM_FREE_START OCMEND -#define OCM_FREE_LENGTH 0 -#endif - -/* - * If you want to limit OCM use for text/data or completely disable it - * you can change these values. - */ -#define OCM_TEXT_LENGTH OCM_FREE_LENGTH -#define OCM_DATA_LENGTH OCM_FREE_LENGTH - -#define RAM_START KERNELSTART -#define RAM_LENGTH ((SDRAMSTART + CONFIG_MIN_RAMSIZE) - RAM_START) -#define TEXT ram -#define DATA ram -#define INIT ram -#define BSS ram - -#ifndef DATA_ADDR -#define DATA_ADDR -#endif - -#include <asm-generic/vmlinux.lds.h> - -OUTPUT_ARCH(ubicom32) -ENTRY(_start) - -MEMORY { - ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH - syscall : ORIGIN = OS_SYSCALL_BEGIN, LENGTH = (OS_SYSCALL_END - OS_SYSCALL_BEGIN) - ocm : ORIGIN = OCM_FREE_START, LENGTH = OCM_FREE_LENGTH -} - -jiffies = jiffies_64 + 4; - -/* - * Fixed locations required by gdb coredumps. - * - * Note that the names are what gdb is expecting so renaming will break - * the toolchain. - */ -__ocm_begin = OCMSTART; -__ocm_limit = __ocm_begin + OCMSIZE; -__sdram_begin = SDRAMSTART; -__sdram_limit = __sdram_begin + CONFIG_MIN_RAMSIZE; -__filemedia_begin_addr = FLASHSTART; -__filemedia_end_addr = __filemedia_begin_addr + 0x00800000; - -/* - * For internal diagnostics - */ -__os_syscall_begin = OS_SYSCALL_BEGIN; -__os_syscall_end = OS_SYSCALL_END; - -SECTIONS { - - .fixed_text : { - _begin = .; - *(.skip_syscall) - *(.old_syscall_entry.text) - __fixed_text_end = .; - } > TEXT - . = _begin + SIZEOF(.fixed_text) ; - - /* - * System call text in lower ocm (fixed location, can never change) - */ - __syscall_text_load_begin = .; - __syscall_text_run_begin = OS_SYSCALL_BEGIN; - - .syscall_text __syscall_text_run_begin : AT(__syscall_text_load_begin) { - *(.syscall_entry.text) /* Must be at OS_SYSCALL_BEGIN 0x3ffc0040 */ - *(.kernel_unprotected) - . = ALIGN(4); - __syscall_text_run_end = .; - } > syscall /* .syscall_text */ - . = __syscall_text_load_begin + __syscall_text_run_end - __syscall_text_run_begin ; - __ocm_text_load_begin = .; - __ocm_text_run_begin = OCM_FREE_START ; - .ocm_text __ocm_text_run_begin : AT(__ocm_text_load_begin) { -#if OCM_TEXT_LENGTH - *(.ocm_text) - *(.sched.text) - *(.spinlock.text) -#include <asm/ocm_text.lds.inc> - . = ALIGN(4); -#endif - __ocm_text_run_end = .; - __data_begin = ALIGN(OCM_SECTOR_SIZE); - } > ocm /* .ocm_text */ - - .ocm_module_text __ocm_text_run_end (NOLOAD) : AT(__ocm_text_run_end) { - __ocm_inst_heap_begin = .; - /* Reserve the min requested */ - . += (CONFIG_OCM_MODULES_RESERVATION) * 1024; -#ifdef CONFIG_OCM_MODULES_MAY_CONSUME_REMAINING_CODESPACE - /* Round up to OCM sector size (we cannot use it for data) */ - . = ALIGN(OCM_SECTOR_SIZE); -#endif - __ocm_inst_heap_end = .; - /* update __data_begin */ - __data_begin = ALIGN(OCM_SECTOR_SIZE); - } > ocm /* .ocm_module_text */ - - . = __ocm_text_load_begin + __ocm_text_run_end - __ocm_text_run_begin ; - __ocm_text_load_end = .; - - __ocm_data_load_begin = .; - __ocm_data_run_begin = __data_begin ; -#if OCM_DATA_LENGTH - .ocm_data __ocm_data_run_begin : AT(__ocm_data_load_begin) { -#if defined(CONFIG_IRQSTACKS_USEOCM) - percpu_irq_stacks = .; - . += NR_CPUS * THREAD_SIZE; -#endif - *(.ocm_data) - . = ALIGN(4) ; - __ocm_data_run_end = .; - } > ocm - . = __ocm_data_load_begin + __ocm_data_run_end - __ocm_data_run_begin ; -#else - __ocm_data_run_end = __ocm_data_run_begin; -#endif - __ocm_data_load_end = .; - - __ocm_free_begin = __ocm_data_run_end; - __ocm_free_end = OCM_FREE_START + OCM_FREE_LENGTH; - - .text __ocm_data_load_end : AT(__ocm_data_load_end) { - . = ALIGN(4); - _stext = .; - _text = .; - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - *(.text.lock) - *(.text.__libgcc_udivmodsi) - *(.text.__libgcc_divmodsi) - *(.text.__libgcc_muldi3) - *(.text.__libgcc_udivmoddi) - *(.text.__libgcc_divmoddi) - *(.text.*) -#if OCM_TEXT_LENGTH == 0 - *(.ocm_text) - *(.sched.text) - *(.spinlock.text) -#endif - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - - *(.rodata) *(.rodata.*) - *(__vermagic) /* Kernel version magic */ - *(__markers_strings) - *(.rodata1) - *(.rodata.str1.1) - *(__tracepoints_strings) - - /* PCI quirks */ - __start_pci_fixups_early = . ; - *(.pci_fixup_early) - __end_pci_fixups_early = . ; - __start_pci_fixups_header = . ; - *(.pci_fixup_header) - __end_pci_fixups_header = . ; - __start_pci_fixups_final = . ; - *(.pci_fixup_final) - __end_pci_fixups_final = . ; - __start_pci_fixups_enable = . ; - *(.pci_fixup_enable) - __end_pci_fixups_enable = . ; - __start_pci_fixups_resume = . ; - *(.pci_fixup_resume) - __end_pci_fixups_resume = . ; - __start_pci_fixups_resume_early = . ; - *(.pci_fixup_resume_early) - __end_pci_fixups_resume_early = . ; - __start_pci_fixups_suspend = . ; - *(.pci_fixup_suspend) - __end_pci_fixups_suspend = . ; - - __start_builtin_fw = . ; - *(.builtin_fw) - __end_builtin_fw = . ; - - - /* Kernel symbol table: Normal symbols */ - . = ALIGN(4); - __start___ksymtab = .; - *(__ksymtab) - __stop___ksymtab = .; - - /* Kernel symbol table: GPL-only symbols */ - __start___ksymtab_gpl = .; - *(__ksymtab_gpl) - __stop___ksymtab_gpl = .; - - /* Kernel symbol table: Normal unused symbols */ - __start___ksymtab_unused = .; - *(__ksymtab_unused) - __stop___ksymtab_unused = .; - - /* Kernel symbol table: GPL-only unused symbols */ - __start___ksymtab_unused_gpl = .; - *(__ksymtab_unused_gpl) - __stop___ksymtab_unused_gpl = .; - - /* Kernel symbol table: GPL-future symbols */ - __start___ksymtab_gpl_future = .; - *(__ksymtab_gpl_future) - __stop___ksymtab_gpl_future = .; - - /* Kernel symbol table: Normal symbols */ - __start___kcrctab = .; - *(__kcrctab) - __stop___kcrctab = .; - - /* Kernel symbol table: GPL-only symbols */ - __start___kcrctab_gpl = .; - *(__kcrctab_gpl) - __stop___kcrctab_gpl = .; - - /* Kernel symbol table: GPL-future symbols */ - __start___kcrctab_gpl_future = .; - *(__kcrctab_gpl_future) - __stop___kcrctab_gpl_future = .; - - /* Kernel symbol table: strings */ - *(__ksymtab_strings) - - /* Built-in module parameters */ - . = ALIGN(4) ; - __start___param = .; - *(__param) - __stop___param = .; - - . = ALIGN(4) ; - _etext = . ; - } > TEXT - - .data DATA_ADDR : { - . = ALIGN(4); - _sdata = . ; - DATA_DATA -#if OCM_DATA_LENGTH == 0 - *(.ocm_data) -#endif - . = ALIGN(8192) ; - _data_protection_end = .; - *(.data.init_task) - . = ALIGN(4); - _edata = . ; - } > DATA - - .init : { - . = ALIGN(4096); - __init_begin = .; - _sinittext = .; - INIT_TEXT - _einittext = .; - *(.init.rodata) - INIT_DATA - . = ALIGN(16); - __setup_start = .; - *(.init.setup) - __setup_end = .; - __initcall_start = .; - INITCALLS - __initcall_end = .; - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; - ___security_initcall_start = .; - *(.security_initcall.init) - ___security_initcall_end = .; -#ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(4); - __initramfs_start = .; - *(.init.ramfs) - __initramfs_end = .; -#endif - . = ALIGN(4096); - __per_cpu_start = .; - *(.data.percpu) - *(.data.percpu.shared_aligned) - __per_cpu_end = .; - - . = ALIGN(4096); - __init_end = .; - } > INIT - - .eh_frame : - { - PROVIDE (___eh_frame_begin = .); - *(.eh_frame) - LONG (0); - PROVIDE (___eh_frame_end = .); - } > INIT - - /DISCARD/ : { - EXIT_TEXT - EXIT_DATA - *(.exitcall.exit) - } - - .bss : { - . = ALIGN(4); - _sbss = . ; - *(.bss) - *(COMMON) - . = ALIGN(4) ; - _ebss = . ; - _end = . ; - } > BSS - - NOTES > BSS - -} |