diff options
Diffstat (limited to 'arch/cris/kernel')
-rw-r--r-- | arch/cris/kernel/Makefile | 15 | ||||
-rw-r--r-- | arch/cris/kernel/crisksyms.c | 103 | ||||
-rw-r--r-- | arch/cris/kernel/irq.c | 297 | ||||
-rw-r--r-- | arch/cris/kernel/module.c | 121 | ||||
-rw-r--r-- | arch/cris/kernel/process.c | 280 | ||||
-rw-r--r-- | arch/cris/kernel/ptrace.c | 119 | ||||
-rw-r--r-- | arch/cris/kernel/semaphore.c | 130 | ||||
-rw-r--r-- | arch/cris/kernel/setup.c | 193 | ||||
-rw-r--r-- | arch/cris/kernel/sys_cris.c | 174 | ||||
-rw-r--r-- | arch/cris/kernel/time.c | 232 | ||||
-rw-r--r-- | arch/cris/kernel/traps.c | 144 |
11 files changed, 1808 insertions, 0 deletions
diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile new file mode 100644 index 000000000000..1546a0e74047 --- /dev/null +++ b/arch/cris/kernel/Makefile @@ -0,0 +1,15 @@ +# $Id: Makefile,v 1.10 2004/05/14 10:18:12 starvik Exp $ +# +# Makefile for the linux kernel. +# + +extra-y := vmlinux.lds + +obj-y := process.o traps.o irq.o ptrace.o setup.o \ + time.o sys_cris.o semaphore.o + +obj-$(CONFIG_MODULES) += crisksyms.o +obj-$(CONFIG_MODULES) += module.o + +clean: + diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c new file mode 100644 index 000000000000..7141bbecd7e4 --- /dev/null +++ b/arch/cris/kernel/crisksyms.c @@ -0,0 +1,103 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/user.h> +#include <linux/elfcore.h> +#include <linux/sched.h> +#include <linux/in6.h> +#include <linux/interrupt.h> +#include <linux/smp_lock.h> +#include <linux/pm.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/tty.h> + +#include <asm/semaphore.h> +#include <asm/processor.h> +#include <asm/uaccess.h> +#include <asm/checksum.h> +#include <asm/io.h> +#include <asm/delay.h> +#include <asm/irq.h> +#include <asm/pgtable.h> +#include <asm/fasttimer.h> + +extern void dump_thread(struct pt_regs *, struct user *); +extern unsigned long get_cmos_time(void); +extern void __Udiv(void); +extern void __Umod(void); +extern void __Div(void); +extern void __Mod(void); +extern void __ashrdi3(void); +extern void iounmap(void *addr); + +/* Platform dependent support */ +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(loops_per_usec); + +/* String functions */ +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memmove); +EXPORT_SYMBOL(strpbrk); +EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(strcpy); +EXPORT_SYMBOL(strchr); +EXPORT_SYMBOL(strcmp); +EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcat); +EXPORT_SYMBOL(strncat); +EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); + +/* Math functions */ +EXPORT_SYMBOL(__Udiv); +EXPORT_SYMBOL(__Umod); +EXPORT_SYMBOL(__Div); +EXPORT_SYMBOL(__Mod); +EXPORT_SYMBOL(__ashrdi3); + +/* Memory functions */ +EXPORT_SYMBOL(__ioremap); +EXPORT_SYMBOL(iounmap); + +/* Semaphore functions */ +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); + +/* Export shadow registers for the CPU I/O pins */ +EXPORT_SYMBOL(genconfig_shadow); +EXPORT_SYMBOL(port_pa_data_shadow); +EXPORT_SYMBOL(port_pa_dir_shadow); +EXPORT_SYMBOL(port_pb_data_shadow); +EXPORT_SYMBOL(port_pb_dir_shadow); +EXPORT_SYMBOL(port_pb_config_shadow); +EXPORT_SYMBOL(port_g_data_shadow); + +/* Userspace access functions */ +EXPORT_SYMBOL(__copy_user_zeroing); +EXPORT_SYMBOL(__copy_user); + +/* Cache flush functions */ +EXPORT_SYMBOL(flush_etrax_cache); +EXPORT_SYMBOL(prepare_rx_descriptor); + +#undef memcpy +#undef memset +extern void * memset(void *, int, __kernel_size_t); +extern void * memcpy(void *, const void *, __kernel_size_t); +EXPORT_SYMBOL(memcpy); +EXPORT_SYMBOL(memset); + +#ifdef CONFIG_ETRAX_FAST_TIMER +/* Fast timer functions */ +EXPORT_SYMBOL(fast_timer_list); +EXPORT_SYMBOL(start_one_shot_timer); +EXPORT_SYMBOL(del_fast_timer); +EXPORT_SYMBOL(schedule_usleep); +#endif + diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c new file mode 100644 index 000000000000..d848b9407457 --- /dev/null +++ b/arch/cris/kernel/irq.c @@ -0,0 +1,297 @@ +/* + * + * linux/arch/cris/kernel/irq.c + * + * Copyright (c) 2000,2001 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + * + * Notice Linux/CRIS: these routines do not care about SMP + * + */ + +/* + * IRQ's are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/ptrace.h> + +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <linux/errno.h> +#include <linux/bitops.h> + +#include <asm/io.h> + +/* Defined in arch specific irq.c */ +extern void arch_setup_irq(int irq); +extern void arch_free_irq(int irq); + +void +disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + + local_save_flags(flags); + local_irq_disable(); + mask_irq(irq_nr); + local_irq_restore(flags); +} + +void +enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + unmask_irq(irq_nr); + local_irq_restore(flags); +} + +unsigned long +probe_irq_on() +{ + return 0; +} + +EXPORT_SYMBOL(probe_irq_on); + +int +probe_irq_off(unsigned long x) +{ + return 0; +} + +EXPORT_SYMBOL(probe_irq_off); + +/* + * Initial irq handlers. + */ + +static struct irqaction *irq_action[NR_IRQS]; + +int show_interrupts(struct seq_file *p, void *v) +{ + int i = *(loff_t *) v; + struct irqaction * action; + unsigned long flags; + + if (i < NR_IRQS) { + local_irq_save(flags); + action = irq_action[i]; + if (!action) + goto skip; + seq_printf(p, "%2d: %10u %c %s", + i, kstat_this_cpu.irqs[i], + (action->flags & SA_INTERRUPT) ? '+' : ' ', + action->name); + for (action = action->next; action; action = action->next) { + seq_printf(p, ",%s %s", + (action->flags & SA_INTERRUPT) ? " +" : "", + action->name); + } + seq_putc(p, '\n'); +skip: + local_irq_restore(flags); + } + return 0; +} + +/* called by the assembler IRQ entry functions defined in irq.h + * to dispatch the interrupts to registred handlers + * interrupts are disabled upon entry - depending on if the + * interrupt was registred with SA_INTERRUPT or not, interrupts + * are re-enabled or not. + */ + +asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +{ + struct irqaction *action; + int do_random, cpu; + int ret, retval = 0; + + cpu = smp_processor_id(); + irq_enter(); + kstat_cpu(cpu).irqs[irq - FIRST_IRQ]++; + action = irq_action[irq - FIRST_IRQ]; + + if (action) { + if (!(action->flags & SA_INTERRUPT)) + local_irq_enable(); + do_random = 0; + do { + ret = action->handler(irq, action->dev_id, regs); + if (ret == IRQ_HANDLED) + do_random |= action->flags; + retval |= ret; + action = action->next; + } while (action); + + if (retval != 1) { + if (retval) { + printk("irq event %d: bogus retval mask %x\n", + irq, retval); + } else { + printk("irq %d: nobody cared\n", irq); + } + } + + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + local_irq_disable(); + } + irq_exit(); +} + +/* this function links in a handler into the chain of handlers for the + given irq, and if the irq has never been registred, the appropriate + handler is entered into the interrupt vector +*/ + +int setup_irq(int irq, struct irqaction * new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + p = irq_action + irq - FIRST_IRQ; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) + return -EBUSY; + + /* Can't share interrupts unless both are same type */ + if ((old->flags ^ new->flags) & SA_INTERRUPT) + return -EBUSY; + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + if (new->flags & SA_SAMPLE_RANDOM) + rand_initialize_irq(irq); + + local_save_flags(flags); + local_irq_disable(); + *p = new; + + if (!shared) { + /* if the irq wasn't registred before, enter it into the vector table + and unmask it physically + */ + arch_setup_irq(irq); + unmask_irq(irq); + } + + local_irq_restore(flags); + return 0; +} + +/* this function is called by a driver to register an irq handler + Valid flags: + SA_INTERRUPT -> it's a fast interrupt, handler called with irq disabled and + no signal checking etc is performed upon exit + SA_SHIRQ -> the interrupt can be shared between different handlers, the handler + is required to check if the irq was "aimed" at it explicitely + SA_RANDOM -> the interrupt will add to the random generators entropy +*/ + +int request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char * devname, + void *dev_id) +{ + int retval; + struct irqaction * action; + + if(!handler) + return -EINVAL; + + /* allocate and fill in a handler structure and setup the irq */ + + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irqflags; + cpus_clear(action->mask); + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + + if (retval) + kfree(action); + return retval; +} + +EXPORT_SYMBOL(request_irq); + +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction * action, **p; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk("Trying to free IRQ%d\n",irq); + return; + } + for (p = irq - FIRST_IRQ + irq_action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + local_save_flags(flags); + local_irq_disable(); + *p = action->next; + if (!irq_action[irq - FIRST_IRQ]) { + mask_irq(irq); + arch_free_irq(irq); + } + local_irq_restore(flags); + kfree(action); + return; + } + printk("Trying to free free IRQ%d\n",irq); +} + +EXPORT_SYMBOL(free_irq); + +void weird_irq(void) +{ + local_irq_disable(); + printk("weird irq\n"); + while(1); +} + +#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) +/* Used by other archs to show/control IRQ steering during SMP */ +void __init +init_irq_proc(void) +{ +} +#endif diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c new file mode 100644 index 000000000000..f1d3e784f30c --- /dev/null +++ b/arch/cris/kernel/module.c @@ -0,0 +1,121 @@ +/* Kernel module help for i386. + Copyright (C) 2001 Rusty Russell. + + This program 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. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt , ...) +#endif + +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. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + + 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); + + /* We add the value into the location given */ + *location += sym->st_value; + } + return 0; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; + + DEBUGP ("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + + for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) { + /* This is where to make the change */ + uint32_t *loc + = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + + rela[i].r_offset); + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + Elf32_Sym *sym + = ((Elf32_Sym *)sechdrs[symindex].sh_addr + + ELF32_R_SYM (rela[i].r_info)); + *loc = sym->st_value + rela[i].r_addend; + } + + return 0; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c new file mode 100644 index 000000000000..9f7cad7c7849 --- /dev/null +++ b/arch/cris/kernel/process.c @@ -0,0 +1,280 @@ +/* $Id: process.c,v 1.17 2004/04/05 13:53:48 starvik Exp $ + * + * linux/arch/cris/kernel/process.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * $Log: process.c,v $ + * Revision 1.17 2004/04/05 13:53:48 starvik + * Merge of Linux 2.6.5 + * + * Revision 1.16 2003/10/27 08:04:33 starvik + * Merge of Linux 2.6.0-test9 + * + * Revision 1.15 2003/09/11 07:29:52 starvik + * Merge of Linux 2.6.0-test5 + * + * Revision 1.14 2003/06/10 10:21:12 johana + * Moved thread_saved_pc() from arch/cris/kernel/process.c to + * subarch specific process.c. arch-v32 has an erp, no irp. + * + * Revision 1.13 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.12 2002/12/11 15:41:11 starvik + * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/kernel + * + * Revision 1.11 2002/12/10 09:00:10 starvik + * Merge of Linux 2.5.51 + * + * Revision 1.10 2002/11/27 08:42:34 starvik + * Argument to user_regs() is thread_info* + * + * Revision 1.9 2002/11/26 09:44:21 starvik + * New threads exits through ret_from_fork (necessary for preemptive scheduling) + * + * Revision 1.8 2002/11/19 14:35:24 starvik + * Changes from linux 2.4 + * Changed struct initializer syntax to the currently prefered notation + * + * Revision 1.7 2002/11/18 07:39:42 starvik + * thread_saved_pc moved here from processor.h + * + * Revision 1.6 2002/11/14 06:51:27 starvik + * Made cpu_idle more similar with other archs + * init_task_union -> init_thread_union + * Updated for new interrupt macros + * sys_clone and do_fork have a new argument, user_tid + * + * Revision 1.5 2002/11/05 06:45:11 starvik + * Merge of Linux 2.5.45 + * + * Revision 1.4 2002/02/05 15:37:44 bjornw + * Need init_task.h + * + * Revision 1.3 2002/01/21 15:22:49 bjornw + * current->counter is gone + * + * Revision 1.22 2001/11/13 09:40:43 orjanf + * Added dump_fpu (needed for core dumps). + * + * Revision 1.21 2001/11/12 18:26:21 pkj + * Fixed compiler warnings. + * + * Revision 1.20 2001/10/03 08:21:39 jonashg + * cause_of_death does not exist if CONFIG_SVINTO_SIM is defined. + * + * Revision 1.19 2001/09/26 11:52:54 bjornw + * INIT_MMAP is gone in 2.4.10 + * + * Revision 1.18 2001/08/21 21:43:51 hp + * Move last watchdog fix inside #ifdef CONFIG_ETRAX_WATCHDOG + * + * Revision 1.17 2001/08/21 13:48:01 jonashg + * Added fix by HP to avoid oops when doing a hard_reset_now. + * + * Revision 1.16 2001/06/21 02:00:40 hp + * * entry.S: Include asm/unistd.h. + * (_sys_call_table): Use section .rodata, not .data. + * (_kernel_thread): Move from... + * * process.c: ... here. + * * entryoffsets.c (VAL): Break out from... + * (OF): Use VAL. + * (LCLONE_VM): New asmified value from CLONE_VM. + * + * Revision 1.15 2001/06/20 16:31:57 hp + * Add comments to describe empty functions according to review. + * + * Revision 1.14 2001/05/29 11:27:59 markusl + * Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled + * + * Revision 1.13 2001/03/20 19:44:06 bjornw + * Use the 7th syscall argument for regs instead of current_regs + * + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include <asm/atomic.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> +#include <asm/irq.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/fs_struct.h> +#include <linux/init_task.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/user.h> +#include <linux/elfcore.h> +#include <linux/mqueue.h> + +//#define DEBUG + +/* + * Initial task structure. Make this a per-architecture thing, + * because different architectures tend to have different + * alignment requirements and potentially different initial + * setup. + */ + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); + +EXPORT_SYMBOL(init_mm); + +/* + * 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) }; + +/* + * 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); + +/* + * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if + * there would ever be a halt sequence (for power save when idle) with + * some largish delay when halting or resuming *and* a driver that can't + * afford that delay. The hlt_counter would then be checked before + * executing the halt sequence, and the driver marks the unhaltable + * region by enable_hlt/disable_hlt. + */ + +static int hlt_counter=0; + +void disable_hlt(void) +{ + hlt_counter++; +} + +EXPORT_SYMBOL(disable_hlt); + +void enable_hlt(void) +{ + hlt_counter--; +} + +EXPORT_SYMBOL(enable_hlt); + +/* + * The following aren't currently used. + */ +void (*pm_idle)(void); + +extern void default_idle(void); + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle (void) +{ + /* endless idle loop with no priority at all */ + while (1) { + while (!need_resched()) { + void (*idle)(void) = pm_idle; + + if (!idle) + idle = default_idle; + + idle(); + } + schedule(); + } + +} + +void hard_reset_now (void); + +void machine_restart(void) +{ + hard_reset_now(); +} + +EXPORT_SYMBOL(machine_restart); + +/* + * 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) +{ +} + +EXPORT_SYMBOL(machine_halt); + +/* If or when software power-off is implemented, add code here. */ + +void machine_power_off(void) +{ +} + +EXPORT_SYMBOL(machine_power_off); + +/* + * When a process does an "exec", machine state like FPU and debug + * registers need to be reset. This is a hook function for that. + * Currently we don't have any such state to reset, so this is empty. + */ + +void flush_thread(void) +{ +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ +#if 0 + int i; + + /* changed the size calculations - should hopefully work better. lbt */ + dump->magic = CMAGIC; + dump->start_code = 0; + dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); + dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; + dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; + dump->u_dsize -= dump->u_tsize; + dump->u_ssize = 0; + for (i = 0; i < 8; i++) + dump->u_debugreg[i] = current->debugreg[i]; + + if (dump->start_stack < TASK_SIZE) + dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; + + dump->regs = *regs; + + dump->u_fpvalid = dump_fpu (regs, &dump->i387); +#endif +} + +/* Fill in the fpu structure for a core dump. */ +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) +{ + return 0; +} diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c new file mode 100644 index 000000000000..e85a2fdd9acf --- /dev/null +++ b/arch/cris/kernel/ptrace.c @@ -0,0 +1,119 @@ +/* + * linux/arch/cris/kernel/ptrace.c + * + * Parts taken from the m68k port. + * + * Copyright (c) 2000, 2001, 2002 Axis Communications AB + * + * Authors: Bjorn Wesen + * + * $Log: ptrace.c,v $ + * Revision 1.9 2003/07/04 12:56:11 tobiasa + * Moved arch-specific code to arch-specific files. + * + * Revision 1.8 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.7 2002/11/27 08:42:34 starvik + * Argument to user_regs() is thread_info* + * + * Revision 1.6 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.5 2002/11/18 07:41:19 starvik + * Removed warning + * + * Revision 1.4 2002/11/11 12:47:28 starvik + * SYSCALL_TRACE has been moved to thread flags + * + * Revision 1.3 2002/02/05 15:37:18 bjornw + * * Add do_notify_resume (replaces do_signal in the callchain) + * * syscall_trace is now do_syscall_trace + * * current->ptrace flag PT_TRACESYS -> PT_SYSCALLTRACE + * * Keep track of the current->work.syscall_trace counter + * + * Revision 1.2 2001/12/18 13:35:20 bjornw + * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). + * + * Revision 1.8 2001/11/12 18:26:21 pkj + * Fixed compiler warnings. + * + * Revision 1.7 2001/09/26 11:53:49 bjornw + * PTRACE_DETACH works more simple in 2.4.10 + * + * Revision 1.6 2001/07/25 16:08:47 bjornw + * PTRACE_ATTACH bulk moved into arch-independent code in 2.4.7 + * + * Revision 1.5 2001/03/26 14:24:28 orjanf + * * Changed loop condition. + * * Added comment documenting non-standard ptrace behaviour. + * + * Revision 1.4 2001/03/20 19:44:41 bjornw + * Use the user_regs macro instead of thread.esp0 + * + * Revision 1.3 2000/12/18 23:45:25 bjornw + * Linux/CRIS first version + * + * + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/user.h> + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/processor.h> + +/* + * Get contents of register REGNO in task TASK. + */ +inline long get_reg(struct task_struct *task, unsigned int regno) +{ + /* USP is a special case, it's not in the pt_regs struct but + * in the tasks thread struct + */ + + if (regno == PT_USP) + return task->thread.usp; + else if (regno < PT_MAX) + return ((unsigned long *)user_regs(task->thread_info))[regno]; + else + return 0; +} + +/* + * Write contents of register REGNO in task TASK. + */ +inline int put_reg(struct task_struct *task, unsigned int regno, + unsigned long data) +{ + if (regno == PT_USP) + task->thread.usp = data; + else if (regno < PT_MAX) + ((unsigned long *)user_regs(task->thread_info))[regno] = data; + else + return -1; + return 0; +} + +/* notification of userspace execution resumption + * - triggered by current->work.notify_resume + */ +extern int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); + + +void do_notify_resume(int canrestart, sigset_t *oldset, struct pt_regs *regs, + __u32 thread_info_flags ) +{ + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(canrestart,oldset,regs); +} diff --git a/arch/cris/kernel/semaphore.c b/arch/cris/kernel/semaphore.c new file mode 100644 index 000000000000..b884263d3cd4 --- /dev/null +++ b/arch/cris/kernel/semaphore.c @@ -0,0 +1,130 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in <asm/semaphore-helper.h> + */ + +#include <linux/sched.h> +#include <linux/init.h> +#include <asm/semaphore-helper.h> + +/* + * 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_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->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) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __sched __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __sched __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + 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/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c new file mode 100644 index 000000000000..6ec2671078bf --- /dev/null +++ b/arch/cris/kernel/setup.c @@ -0,0 +1,193 @@ +/* + * + * linux/arch/cris/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (c) 2001 Axis Communications AB + */ + +/* + * This file handles the architecture-dependent parts of initialization + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/bootmem.h> +#include <asm/pgtable.h> +#include <linux/seq_file.h> +#include <linux/tty.h> + +#include <asm/setup.h> + +/* + * Setup options + */ +struct drive_info_struct { char dummy[32]; } drive_info; +struct screen_info screen_info; + +extern int root_mountflags; +extern char _etext, _edata, _end; + +static char command_line[COMMAND_LINE_SIZE] = { 0, }; + +extern const unsigned long text_start, edata; /* set by the linker script */ +extern unsigned long dram_start, dram_end; + +extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */ + +extern void show_etrax_copyright(void); /* arch-vX/kernel/setup.c */ + +/* This mainly sets up the memory area, and can be really confusing. + * + * The physical DRAM is virtually mapped into dram_start to dram_end + * (usually c0000000 to c0000000 + DRAM size). The physical address is + * given by the macro __pa(). + * + * In this DRAM, the kernel code and data is loaded, in the beginning. + * It really starts at c0004000 to make room for some special pages - + * the start address is text_start. The kernel data ends at _end. After + * this the ROM filesystem is appended (if there is any). + * + * Between this address and dram_end, we have RAM pages usable to the + * boot code and the system. + * + */ + +void __init +setup_arch(char **cmdline_p) +{ + extern void init_etrax_debug(void); + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn; + unsigned long memory_start; + + /* register an initial console printing routine for printk's */ + + init_etrax_debug(); + + /* we should really poll for DRAM size! */ + + high_memory = &dram_end; + + if(romfs_in_flash || !romfs_length) { + /* if we have the romfs in flash, or if there is no rom filesystem, + * our free area starts directly after the BSS + */ + memory_start = (unsigned long) &_end; + } else { + /* otherwise the free area starts after the ROM filesystem */ + printk("ROM fs in RAM, size %lu bytes\n", romfs_length); + memory_start = romfs_start + romfs_length; + } + + /* process 1's initial memory region is the kernel code/data */ + + init_mm.start_code = (unsigned long) &text_start; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + + /* min_low_pfn points to the start of DRAM, start_pfn points + * to the first DRAM pages after the kernel, and max_low_pfn + * to the end of DRAM. + */ + + /* + * partially used pages are not usable - thus + * we are rounding upwards: + */ + + start_pfn = PFN_UP(memory_start); /* usually c0000000 + kernel + romfs */ + max_pfn = PFN_DOWN((unsigned long)high_memory); /* usually c0000000 + dram size */ + + /* + * Initialize the boot-time allocator (start, end) + * + * We give it access to all our DRAM, but we could as well just have + * given it a small slice. No point in doing that though, unless we + * have non-contiguous memory and want the boot-stuff to be in, say, + * the smallest area. + * + * It will put a bitmap of the allocated pages in the beginning + * of the range we give it, but it won't mark the bitmaps pages + * as reserved. We have to do that ourselves below. + * + * We need to use init_bootmem_node instead of init_bootmem + * because our map starts at a quite high address (min_low_pfn). + */ + + max_low_pfn = max_pfn; + min_low_pfn = PAGE_OFFSET >> PAGE_SHIFT; + + bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, + min_low_pfn, + max_low_pfn); + + /* And free all memory not belonging to the kernel (addr, size) */ + + free_bootmem(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn - start_pfn)); + + /* + * Reserve the bootmem bitmap itself as well. We do this in two + * steps (first step was init_bootmem()) because this catches + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + * + * Arguments are start, size + */ + + reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size); + + /* paging_init() sets up the MMU and marks all pages as reserved */ + + paging_init(); + + /* We don't use a command line yet, so just re-initialize it without + saving anything that might be there. */ + + *cmdline_p = command_line; + +#ifdef CONFIG_ETRAX_CMDLINE + strlcpy(command_line, CONFIG_ETRAX_CMDLINE, COMMAND_LINE_SIZE); + command_line[COMMAND_LINE_SIZE - 1] = '\0'; + + /* Save command line for future references. */ + memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE - 1] = '\0'; +#endif + + /* give credit for the CRIS port */ + show_etrax_copyright(); +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + /* We only got one CPU... */ + return *pos < 1 ? (void *)1 : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +extern int show_cpuinfo(struct seq_file *m, void *v); + +struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + + diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c new file mode 100644 index 000000000000..0aa0e0ebb3a9 --- /dev/null +++ b/arch/cris/kernel/sys_cris.c @@ -0,0 +1,174 @@ +/* $Id: sys_cris.c,v 1.6 2004/03/11 11:38:40 starvik Exp $ + * + * linux/arch/cris/kernel/sys_cris.c + * + * This file contains various random system calls that + * have a non-standard calling sequence on some platforms. + * Since we don't have to do any backwards compatibility, our + * versions are done in the most "normal" way possible. + * + */ + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/syscalls.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/sem.h> +#include <linux/msg.h> +#include <linux/shm.h> +#include <linux/stat.h> +#include <linux/mman.h> +#include <linux/file.h> + +#include <asm/uaccess.h> +#include <asm/ipc.h> +#include <asm/segment.h> + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way Unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long __user * fildes) +{ + int fd[2]; + int error; + + lock_kernel(); + error = do_pipe(fd); + unlock_kernel(); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* 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 unsigned long old_mmap(unsigned long __user *args) +{ + unsigned long buffer[6]; + int err = -EFAULT; + + if (copy_from_user(&buffer, args, sizeof(buffer))) + goto out; + + err = -EINVAL; + if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */ + goto out; + + err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5] >> PAGE_SHIFT); +out: + return err; +} + +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); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. (same as arch/i386) + */ + +asmlinkage int sys_ipc (uint call, int first, int second, + int third, void __user *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + case SEMOP: + return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, second, + (const struct timespec __user *)fifth); + + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void * __user *) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf __user *) 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 __user *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf __user *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds __user *) ptr); + + case SHMAT: { + ulong raddr; + ret = do_shmat (first, (char __user *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong __user *) third); + } + case SHMDT: + return sys_shmdt ((char __user *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds __user *) ptr); + default: + return -ENOSYS; + } +} diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c new file mode 100644 index 000000000000..6c28b0e7f7b4 --- /dev/null +++ b/arch/cris/kernel/time.c @@ -0,0 +1,232 @@ +/* $Id: time.c,v 1.14 2004/06/01 05:38:11 starvik Exp $ + * + * linux/arch/cris/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1999, 2000, 2001 Axis Communications AB + * + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1995-03-26 Markus Kuhn + * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 + * precision CMOS clock update + * 1996-05-03 Ingo Molnar + * fixed time warps in do_[slow|fast]_gettimeoffset() + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + * + * Linux/CRIS specific code: + * + * Authors: Bjorn Wesen + * Johan Adolfsson + * + */ + +#include <asm/rtc.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/param.h> +#include <linux/jiffies.h> +#include <linux/bcd.h> +#include <linux/timex.h> +#include <linux/init.h> + +u64 jiffies_64 = INITIAL_JIFFIES; + +EXPORT_SYMBOL(jiffies_64); + +int have_rtc; /* used to remember if we have an RTC or not */; + +#define TICK_SIZE tick + +extern unsigned long wall_jiffies; +extern unsigned long loops_per_jiffy; /* init/main.c */ +unsigned long loops_per_usec; + +extern unsigned long do_slow_gettimeoffset(void); +static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; + +/* + * This version of gettimeofday has near microsecond resolution. + * + * Note: Division is quite slow on CRIS and do_gettimeofday is called + * rather often. Maybe we should do some kind of approximation here + * (a naive approximation would be to divide by 1024). + */ +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + signed long usec, sec; + local_irq_save(flags); + local_irq_disable(); + usec = do_gettimeoffset(); + { + unsigned long lost = jiffies - wall_jiffies; + if (lost) + usec += lost * (1000000 / HZ); + } + + /* + * If time_adjust is negative then NTP is slowing the clock + * so make sure not to go into next possible interval. + * Better to lose some accuracy than have time go backwards.. + */ + if (unlikely(time_adjust < 0) && usec > tickadj) + usec = tickadj; + + sec = xtime.tv_sec; + usec += xtime.tv_nsec / 1000; + local_irq_restore(flags); + + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +EXPORT_SYMBOL(do_gettimeofday); + +int do_settimeofday(struct timespec *tv) +{ + time_t wtm_sec, sec = tv->tv_sec; + long wtm_nsec, nsec = tv->tv_nsec; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + return -EINVAL; + + write_seqlock_irq(&xtime_lock); + /* + * This is revolting. We need to set "xtime" correctly. However, the + * value in this location is the value at the most recent update of + * wall time. Discover what correction gettimeofday() would have + * made, and then undo it! + */ + nsec -= do_gettimeoffset() * NSEC_PER_USEC; + nsec -= (jiffies - wall_jiffies) * TICK_NSEC; + + wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); + wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); + + set_normalized_timespec(&xtime, sec, nsec); + set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_sequnlock_irq(&xtime_lock); + clock_was_set(); + return 0; +} + +EXPORT_SYMBOL(do_settimeofday); + + +/* + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! + */ + +int set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + + printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime); + + if(!have_rtc) + return 0; + + cmos_minutes = CMOS_READ(RTC_MINUTES); + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + return retval; +} + +/* grab the time from the RTC chip */ + +unsigned long +get_cmos_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + + printk(KERN_DEBUG + "rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n", + sec, min, hour, day, mon, year); + + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +/* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME. + * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does. + */ + +void +update_xtime_from_cmos(void) +{ + if(have_rtc) { + xtime.tv_sec = get_cmos_time(); + xtime.tv_nsec = 0; + } +} + +/* + * Scheduler clock - returns current time in nanosec units. + */ +unsigned long long sched_clock(void) +{ + return (unsigned long long)jiffies * (1000000000 / HZ); +} + +static int +__init init_udelay(void) +{ + loops_per_usec = (loops_per_jiffy * HZ) / 1000000; + return 0; +} + +__initcall(init_udelay); diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c new file mode 100644 index 000000000000..d4dfa050e3a5 --- /dev/null +++ b/arch/cris/kernel/traps.c @@ -0,0 +1,144 @@ +/* $Id: traps.c,v 1.9 2004/05/11 12:28:26 starvik Exp $ + * + * linux/arch/cris/traps.c + * + * Here we handle the break vectors not used by the system call + * mechanism, as well as some general stack/register dumping + * things. + * + * Copyright (C) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen + * Hans-Peter Nilsson + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> + +static int kstack_depth_to_print = 24; + +void show_trace(unsigned long * stack) +{ + unsigned long addr, module_start, module_end; + extern char _stext, _etext; + int i; + + printk("\nCall Trace: "); + + i = 1; + module_start = VMALLOC_START; + module_end = VMALLOC_END; + + while (((long) stack & (THREAD_SIZE-1)) != 0) { + if (__get_user (addr, stack)) { + /* This message matches "failing address" marked + s390 in ksymoops, so lines containing it will + not be filtered out by ksymoops. */ + printk ("Failing address 0x%lx\n", (unsigned long)stack); + break; + } + stack++; + + /* + * If the address is either in the text segment of the + * kernel, or in the region which contains vmalloc'ed + * memory, it *may* be the address of a calling + * routine; if so, print it so that someone tracing + * down the cause of the crash will be able to figure + * out the call path that was taken. + */ + if (((addr >= (unsigned long) &_stext) && + (addr <= (unsigned long) &_etext)) || + ((addr >= module_start) && (addr <= module_end))) { + if (i && ((i % 8) == 0)) + printk("\n "); + printk("[<%08lx>] ", addr); + i++; + } + } +} + +/* + * These constants are for searching for possible module text + * segments. MODULE_RANGE is a guess of how much space is likely + * to be vmalloced. + */ + +#define MODULE_RANGE (8*1024*1024) + +/* + * The output (format, strings and order) is adjusted to be usable with + * ksymoops-2.4.1 with some necessary CRIS-specific patches. Please don't + * change it unless you're serious about adjusting ksymoops and syncing + * with the ksymoops maintainer. + */ + +void +show_stack(struct task_struct *task, unsigned long *sp) +{ + unsigned long *stack, addr; + int i; + + /* + * debugging aid: "show_stack(NULL);" prints a + * back trace. + */ + + if(sp == NULL) { + if (task) + sp = (unsigned long*)task->thread.ksp; + else + sp = (unsigned long*)rdsp(); + } + + stack = sp; + + printk("\nStack from %08lx:\n ", (unsigned long)stack); + for(i = 0; i < kstack_depth_to_print; i++) { + if (((long) stack & (THREAD_SIZE-1)) == 0) + break; + if (i && ((i % 8) == 0)) + printk("\n "); + if (__get_user (addr, stack)) { + /* This message matches "failing address" marked + s390 in ksymoops, so lines containing it will + not be filtered out by ksymoops. */ + printk ("Failing address 0x%lx\n", (unsigned long)stack); + break; + } + stack++; + printk("%08lx ", addr); + } + show_trace(sp); +} + +#if 0 +/* displays a short stack trace */ + +int +show_stack() +{ + unsigned long *sp = (unsigned long *)rdusp(); + int i; + printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); + for(i = 0; i < 16; i++) + printk("sp + %d: 0x%08lx\n", i*4, sp[i]); + return 0; +} +#endif + +void dump_stack(void) +{ + show_stack(NULL, NULL); +} + +EXPORT_SYMBOL(dump_stack); + +void __init +trap_init(void) +{ + /* Nothing needs to be done */ +} |