From: James S. <jsi...@us...> - 2001-11-02 00:57:50
|
Update of /cvsroot/linuxconsole/ruby/linux/arch/arm/kernel In directory usw-pr-cvs1:/tmp/cvs-serv5606/linux/arch/arm/kernel Modified Files: setup.c traps.c Log Message: Synced as much as possible to ARM tree. Index: setup.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/arch/arm/kernel/setup.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- setup.c 2001/08/26 16:02:27 1.4 +++ setup.c 2001/11/02 00:57:43 1.5 @@ -258,10 +258,10 @@ struct resource *res; int i; - kernel_code.start = __virt_to_bus(init_mm.start_code); - kernel_code.end = __virt_to_bus(init_mm.end_code - 1); - kernel_data.start = __virt_to_bus(init_mm.end_code); - kernel_data.end = __virt_to_bus(init_mm.brk - 1); + kernel_code.start = __virt_to_phys(init_mm.start_code); + kernel_code.end = __virt_to_phys(init_mm.end_code - 1); + kernel_data.start = __virt_to_phys(init_mm.end_code); + kernel_data.end = __virt_to_phys(init_mm.brk - 1); for (i = 0; i < mi->nr_banks; i++) { unsigned long virt_start, virt_end; @@ -338,7 +338,7 @@ } meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start; meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size; - meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(tag->u.mem.start); + meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(tag->u.mem.start); meminfo.nr_banks += 1; return 0; @@ -510,9 +510,44 @@ init_arch_irq = mdesc->init_irq; } -int get_cpuinfo(char * buffer) +static const char *hwcap_str[] = { + "swp", + "half", + "thumb", + "26bit", + "fastmult", + "fpa", + "vfp", + "edsp", + NULL +}; + +/* + * get_cpuinfo - Get information on one CPU for use by the procfs. + * + * Prints info on the next CPU into buffer. Beware, doesn't check for + * buffer overflow. Current implementation of procfs assumes that the + * resulting data is <= 1K. + * + * Args: + * buffer -- you guessed it, the data buffer + * cpu_np -- Input: next cpu to get (start at 0). Output: Updated. + * + * Returns number of bytes written to buffer. + */ + +int get_cpuinfo(char *buffer, unsigned *cpu_np) { char *p = buffer; + unsigned n; + int i; + + /* No SMP at the moment, so just toggle 0/1 */ + n = *cpu_np; + *cpu_np = 1; + if (n != 0) { + return (0); + } p += sprintf(p, "Processor\t: %s %s rev %d (%s)\n", proc_info.manufacturer, proc_info.cpu_name, @@ -521,6 +556,15 @@ p += sprintf(p, "BogoMIPS\t: %lu.%02lu\n", loops_per_jiffy / (500000/HZ), (loops_per_jiffy / (5000/HZ)) % 100); + + /* dump out the processor features */ + p += sprintf(p, "Features\t: "); + + for (i = 0; hwcap_str[i]; i++) + if (elf_hwcap & (1 << i)) + p += sprintf(p, "%s ", hwcap_str[i]); + + p += sprintf(p, "\n\n"); p += sprintf(p, "Hardware\t: %s\n", machine_name); Index: traps.c =================================================================== RCS file: /cvsroot/linuxconsole/ruby/linux/arch/arm/kernel/traps.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- traps.c 2001/09/02 23:27:15 1.1 +++ traps.c 2001/11/02 00:57:43 1.2 @@ -19,8 +19,10 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/spinlock.h> +#include <linux/personality.h> #include <linux/ptrace.h> #include <linux/elf.h> +#include <linux/interrupt.h> #include <linux/init.h> #include <asm/atomic.h> @@ -175,7 +177,7 @@ printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, 4096+(unsigned long)tsk); - if (!user_mode(regs)) { + if (!user_mode(regs) || in_interrupt()) { mm_segment_t fs; /* @@ -208,12 +210,19 @@ asmlinkage void do_undefinstr(int address, struct pt_regs *regs, int mode) { - unsigned long addr = instruction_pointer(regs); + unsigned long *pc; siginfo_t info; + /* + * According to the ARM ARM, PC is 2 or 4 bytes ahead, depending + * whether we're in Thumb mode or not. + */ + regs->ARM_pc -= thumb_mode(regs) ? 2 : 4; + pc = (unsigned long *)instruction_pointer(regs); + #ifdef CONFIG_DEBUG_USER - printk(KERN_INFO "%s (%d): undefined instruction: pc=%08lx\n", - current->comm, current->pid, addr); + printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", + current->comm, current->pid, pc); dump_instr(regs); #endif @@ -223,13 +232,14 @@ info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; - info.si_addr = (void *)addr; + info.si_addr = pc; force_sig_info(SIGILL, &info, current); die_if_kernel("Oops - undefined instruction", regs, mode); } +#ifdef CONFIG_CPU_26 asmlinkage void do_excpt(int address, struct pt_regs *regs, int mode) { siginfo_t info; @@ -252,6 +262,7 @@ die_if_kernel("Oops - address exception", regs, mode); } +#endif asmlinkage void do_unexp_fiq (struct pt_regs *regs) { @@ -269,33 +280,84 @@ */ asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) { + unsigned int vectors = vectors_base(); + mm_segment_t fs; + console_verbose(); printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n", handler[reason], processor_modes[proc_mode]); /* + * We need to switch to kernel mode so that we can + * use __get_user to safely read from kernel space. + * Note that we now dump the code first, just in case + * the backtrace kills us. + */ + fs = get_fs(); + set_fs(KERNEL_DS); + + /* * Dump out the vectors and stub routines. Maybe a better solution * would be to dump them out only if we detect that they are corrupted. */ printk(KERN_CRIT "Vectors:\n"); - dump_mem(0, 0x40); + dump_mem(vectors, 0x40); printk(KERN_CRIT "Stubs:\n"); - dump_mem(0x200, 0x4b8); + dump_mem(vectors + 0x200, 0x4b8); + set_fs(fs); + die("Oops", regs, 0); cli(); panic("bad mode"); } +static int bad_syscall(int n, struct pt_regs *regs) +{ + siginfo_t info; + + /* You might think just testing `handler' would be enough, but PER_LINUX + * points it to no_lcall7 to catch undercover SVr4 binaries. Gutted. + */ + if (current->personality != PER_LINUX && current->exec_domain->handler) { + /* Hand it off to iBCS. The extra parameter and consequent type + * forcing is necessary because of the weird ARM calling convention. + */ + current->exec_domain->handler(n, regs); + return regs->ARM_r0; + } + +#ifdef CONFIG_DEBUG_USER + printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", + current->pid, current->comm, n); + dump_instr(regs); +#endif + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLTRP; + info.si_addr = (void *)instruction_pointer(regs) - + (thumb_mode(regs) ? 2 : 4); + + force_sig_info(SIGILL, &info, current); + die_if_kernel("Oops", regs, n); + return regs->ARM_r0; +} + /* - * Handle some more esoteric system calls + * Handle all unrecognised system calls. + * 0x9f0000 - 0x9fffff are some more esoteric system calls */ +#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE) asmlinkage int arm_syscall(int no, struct pt_regs *regs) { siginfo_t info; - switch (no) { + if ((no >> 16) != 0x9f) + return bad_syscall(no, regs); + + switch (no & 0xffff) { case 0: /* branch through 0 */ info.si_signo = SIGSEGV; info.si_errno = 0; @@ -305,9 +367,9 @@ force_sig_info(SIGSEGV, &info, current); die_if_kernel("branch through zero", regs, 0); - break; + return 0; - case 1: /* SWI BREAK_POINT */ + case NR(breakpoint): /* SWI BREAK_POINT */ /* * The PC is always left pointing at the next * instruction. Fix this. @@ -318,17 +380,50 @@ info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; - info.si_addr = (void *)instruction_pointer(regs); + info.si_addr = (void *)instruction_pointer(regs) - + (thumb_mode(regs) ? 2 : 4); force_sig_info(SIGTRAP, &info, current); return regs->ARM_r0; - case 2: /* sys_cacheflush */ #ifdef CONFIG_CPU_32 - /* r0 = start, r1 = end, r2 = flags */ + /* + * Flush a region from virtual address 'r0' to virtual address 'r1' + * _inclusive_. There is no alignment requirement on either address; + * user space does not need to know the hardware cache layout. + * + * r2 contains flags. It should ALWAYS be passed as ZERO until it + * is defined to be something else. For now we ignore it, but may + * the fires of hell burn in your belly if you break this rule. ;) + * + * (at a later date, we may want to allow this call to not flush + * various aspects of the cache. Passing '0' will guarantee that + * everything necessary gets flushed to maintain consistency in + * the specified region). + */ + case NR(cacheflush): cpu_cache_clean_invalidate_range(regs->ARM_r0, regs->ARM_r1, 1); -#endif + return 0; + + case NR(usr26): + if (!(elf_hwcap & HWCAP_26BIT)) + break; + regs->ARM_cpsr &= ~0x10; + return regs->ARM_r0; + + case NR(usr32): + if (!(elf_hwcap & HWCAP_26BIT)) + break; + regs->ARM_cpsr |= 0x10; + return regs->ARM_r0; +#else + case NR(cacheflush): + return 0; + + case NR(usr26): + case NR(usr32): break; +#endif default: /* Calls 9f00xx..9f07ff are defined to return -ENOSYS @@ -337,45 +432,29 @@ a feature is supported. */ if (no <= 0x7ff) return -ENOSYS; -#ifdef CONFIG_DEBUG_USER - /* experience shows that these seem to indicate that - * something catastrophic has happened - */ - printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); - dump_instr(regs); - if (user_mode(regs)) { - show_regs(regs); - c_backtrace(regs->ARM_fp, processor_mode(regs)); - } -#endif - force_sig(SIGILL, current); - die_if_kernel("Oops", regs, no); break; } - return 0; -} - -asmlinkage void deferred(int n, struct pt_regs *regs) -{ - /* You might think just testing `handler' would be enough, but PER_LINUX - * points it to no_lcall7 to catch undercover SVr4 binaries. Gutted. - */ - if (current->personality != PER_LINUX && current->exec_domain->handler) { - /* Hand it off to iBCS. The extra parameter and consequent type - * forcing is necessary because of the weird ARM calling convention. - */ - void (*handler)(int nr, struct pt_regs *regs) = (void *)current->exec_domain->handler; - (*handler)(n, regs); - return; - } - #ifdef CONFIG_DEBUG_USER - printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", - current->pid, current->comm, n); + /* + * experience shows that these seem to indicate that + * something catastrophic has happened + */ + printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); dump_instr(regs); + if (user_mode(regs)) { + show_regs(regs); + c_backtrace(regs->ARM_fp, processor_mode(regs)); + } #endif - force_sig(SIGILL, current); - die_if_kernel("Oops", regs, n); + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLTRP; + info.si_addr = (void *)instruction_pointer(regs) - + (thumb_mode(regs) ? 2 : 4); + + force_sig_info(SIGILL, &info, current); + die_if_kernel("Oops", regs, no); + return 0; } void __bad_xchg(volatile void *ptr, int size) @@ -467,7 +546,7 @@ __trap_init((void *)vectors_base()); if (vectors_base() != 0) - printk("Relocating machine vectors to 0x%08x\n", + printk(KERN_DEBUG "Relocating machine vectors to 0x%08x\n", vectors_base()); #ifdef CONFIG_CPU_32 modify_domain(DOMAIN_USER, DOMAIN_CLIENT); |