diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-08-24 22:49:17 +0900 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-24 22:49:17 +0900 |
commit | 12cceb6251c2cd23e936b25eca66be99ba41b081 (patch) | |
tree | b7f62853e67b305519c375162760422fbfc81b8e /arch/sh/kernel | |
parent | f13327864f94c3a0e6acca923df537d20059639f (diff) | |
parent | 05ecd5a1f76c183cca381705b3adb7d77c9a0439 (diff) |
Merge branch 'sh/st-integration'
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/cpu/irq/ipr.c | 1 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh3/entry.S | 2 | ||||
-rw-r--r-- | arch/sh/kernel/entry-common.S | 5 | ||||
-rw-r--r-- | arch/sh/kernel/io.c | 97 | ||||
-rw-r--r-- | arch/sh/kernel/io_generic.c | 50 | ||||
-rw-r--r-- | arch/sh/kernel/irq.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/kgdb.c | 2 | ||||
-rw-r--r-- | arch/sh/kernel/process_32.c | 20 | ||||
-rw-r--r-- | arch/sh/kernel/setup.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/signal_32.c | 12 | ||||
-rw-r--r-- | arch/sh/kernel/sys_sh.c | 43 | ||||
-rw-r--r-- | arch/sh/kernel/syscalls_32.S | 2 | ||||
-rw-r--r-- | arch/sh/kernel/syscalls_64.S | 2 | ||||
-rw-r--r-- | arch/sh/kernel/traps_32.c | 188 |
14 files changed, 337 insertions, 95 deletions
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c index 808d99a48ef..c1508a90fc6 100644 --- a/arch/sh/kernel/cpu/irq/ipr.c +++ b/arch/sh/kernel/cpu/irq/ipr.c @@ -35,6 +35,7 @@ static void disable_ipr_irq(unsigned int irq) unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx]; /* Set the priority in IPR to 0 */ __raw_writew(__raw_readw(addr) & (0xffff ^ (0xf << p->shift)), addr); + (void)__raw_readw(addr); /* Read back to flush write posting */ } static void enable_ipr_irq(unsigned int irq) diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 8c19e21847d..9421ec715fd 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -257,7 +257,7 @@ restore_all: ! ! Calculate new SR value mov k3, k2 ! original SR value - mov #0xf0, k1 + mov #0xfffffff0, k1 extu.b k1, k1 not k1, k1 and k1, k2 ! Mask original SR value diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 700477601c6..68d9223b145 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S @@ -98,8 +98,9 @@ need_resched: mov #OFF_SR, r0 mov.l @(r0,r15), r0 ! get status register - and #0xf0, r0 ! interrupts off (exception path)? - cmp/eq #0xf0, r0 + shlr r0 + and #(0xf0>>1), r0 ! interrupts off (exception path)? + cmp/eq #(0xf0>>1), r0 bt noresched mov.l 3f, r0 jsr @r0 ! call preempt_schedule_irq diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c index 4f85fffaa55..4770c241c67 100644 --- a/arch/sh/kernel/io.c +++ b/arch/sh/kernel/io.c @@ -1,12 +1,9 @@ /* - * linux/arch/sh/kernel/io.c + * arch/sh/kernel/io.c - Machine independent I/O functions. * - * Copyright (C) 2000 Stuart Menefy + * Copyright (C) 2000 - 2009 Stuart Menefy * Copyright (C) 2005 Paul Mundt * - * Provide real functions which expand to whatever the header file defined. - * Also definitions of machine independent IO functions. - * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. @@ -18,33 +15,87 @@ /* * Copy data from IO memory space to "real" memory space. - * This needs to be optimized. */ void memcpy_fromio(void *to, const volatile void __iomem *from, unsigned long count) { - unsigned char *p = to; - while (count) { - count--; - *p = readb(from); - p++; - from++; - } + /* + * Would it be worthwhile doing byte and long transfers first + * to try and get aligned? + */ +#ifdef CONFIG_CPU_SH4 + if ((count >= 0x20) && + (((u32)to & 0x1f) == 0) && (((u32)from & 0x3) == 0)) { + int tmp2, tmp3, tmp4, tmp5, tmp6; + + __asm__ __volatile__( + "1: \n\t" + "mov.l @%7+, r0 \n\t" + "mov.l @%7+, %2 \n\t" + "movca.l r0, @%0 \n\t" + "mov.l @%7+, %3 \n\t" + "mov.l @%7+, %4 \n\t" + "mov.l @%7+, %5 \n\t" + "mov.l @%7+, %6 \n\t" + "mov.l @%7+, r7 \n\t" + "mov.l @%7+, r0 \n\t" + "mov.l %2, @(0x04,%0) \n\t" + "mov #0x20, %2 \n\t" + "mov.l %3, @(0x08,%0) \n\t" + "sub %2, %1 \n\t" + "mov.l %4, @(0x0c,%0) \n\t" + "cmp/hi %1, %2 ! T if 32 > count \n\t" + "mov.l %5, @(0x10,%0) \n\t" + "mov.l %6, @(0x14,%0) \n\t" + "mov.l r7, @(0x18,%0) \n\t" + "mov.l r0, @(0x1c,%0) \n\t" + "bf.s 1b \n\t" + " add #0x20, %0 \n\t" + : "=&r" (to), "=&r" (count), + "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4), + "=&r" (tmp5), "=&r" (tmp6), "=&r" (from) + : "7"(from), "0" (to), "1" (count) + : "r0", "r7", "t", "memory"); + } +#endif + + if ((((u32)to | (u32)from) & 0x3) == 0) { + for (; count > 3; count -= 4) { + *(u32 *)to = *(volatile u32 *)from; + to += 4; + from += 4; + } + } + + for (; count > 0; count--) { + *(u8 *)to = *(volatile u8 *)from; + to++; + from++; + } + + mb(); } EXPORT_SYMBOL(memcpy_fromio); /* * Copy data from "real" memory space to IO memory space. - * This needs to be optimized. */ void memcpy_toio(volatile void __iomem *to, const void *from, unsigned long count) { - const unsigned char *p = from; - while (count) { - count--; - writeb(*p, to); - p++; - to++; - } + if ((((u32)to | (u32)from) & 0x3) == 0) { + for ( ; count > 3; count -= 4) { + *(volatile u32 *)to = *(u32 *)from; + to += 4; + from += 4; + } + } + + for (; count > 0; count--) { + *(volatile u8 *)to = *(u8 *)from; + to++; + from++; + } + + mb(); } EXPORT_SYMBOL(memcpy_toio); @@ -62,6 +113,8 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count) } EXPORT_SYMBOL(memset_io); +#ifndef CONFIG_GENERIC_IOMAP + void __iomem *ioport_map(unsigned long port, unsigned int nr) { void __iomem *ret; @@ -79,3 +132,5 @@ void ioport_unmap(void __iomem *addr) sh_mv.mv_ioport_unmap(addr); } EXPORT_SYMBOL(ioport_unmap); + +#endif /* CONFIG_GENERIC_IOMAP */ diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index 5a7f554d9ca..4ff50723928 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c @@ -73,35 +73,19 @@ u32 generic_inl_p(unsigned long port) void generic_insb(unsigned long port, void *dst, unsigned long count) { - volatile u8 *port_addr; - u8 *buf = dst; - - port_addr = (volatile u8 __force *)__ioport_map(port, 1); - while (count--) - *buf++ = *port_addr; + __raw_readsb(__ioport_map(port, 1), dst, count); + dummy_read(); } void generic_insw(unsigned long port, void *dst, unsigned long count) { - volatile u16 *port_addr; - u16 *buf = dst; - - port_addr = (volatile u16 __force *)__ioport_map(port, 2); - while (count--) - *buf++ = *port_addr; - + __raw_readsw(__ioport_map(port, 2), dst, count); dummy_read(); } void generic_insl(unsigned long port, void *dst, unsigned long count) { - volatile u32 *port_addr; - u32 *buf = dst; - - port_addr = (volatile u32 __force *)__ioport_map(port, 4); - while (count--) - *buf++ = *port_addr; - + __raw_readsl(__ioport_map(port, 4), dst, count); dummy_read(); } @@ -145,37 +129,19 @@ void generic_outl_p(u32 b, unsigned long port) */ void generic_outsb(unsigned long port, const void *src, unsigned long count) { - volatile u8 *port_addr; - const u8 *buf = src; - - port_addr = (volatile u8 __force *)__ioport_map(port, 1); - - while (count--) - *port_addr = *buf++; + __raw_writesb(__ioport_map(port, 1), src, count); + dummy_read(); } void generic_outsw(unsigned long port, const void *src, unsigned long count) { - volatile u16 *port_addr; - const u16 *buf = src; - - port_addr = (volatile u16 __force *)__ioport_map(port, 2); - - while (count--) - *port_addr = *buf++; - + __raw_writesw(__ioport_map(port, 2), src, count); dummy_read(); } void generic_outsl(unsigned long port, const void *src, unsigned long count) { - volatile u32 *port_addr; - const u32 *buf = src; - - port_addr = (volatile u32 __force *)__ioport_map(port, 4); - while (count--) - *port_addr = *buf++; - + __raw_writesl(__ioport_map(port, 4), src, count); dummy_read(); } diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 278c68c6048..d1053392e28 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -114,7 +114,7 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs) #endif irq_enter(); - irq = irq_demux(intc_evt2irq(irq)); + irq = irq_demux(evt2irq(irq)); #ifdef CONFIG_IRQSTACKS curctx = (union irq_ctx *)current_thread_info(); diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c index 305aad742ae..d29de7864f3 100644 --- a/arch/sh/kernel/kgdb.c +++ b/arch/sh/kernel/kgdb.c @@ -195,8 +195,6 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) regs->gbr = gdb_regs[GDB_GBR]; regs->mach = gdb_regs[GDB_MACH]; regs->macl = gdb_regs[GDB_MACL]; - - __asm__ __volatile__ ("ldc %0, vbr" : : "r" (gdb_regs[GDB_VBR])); } void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 9fee977f176..0673c4746be 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -32,15 +32,35 @@ #include <asm/ubc.h> #include <asm/fpu.h> #include <asm/syscalls.h> +#include <asm/watchdog.h> int ubc_usercnt = 0; +#ifdef CONFIG_32BIT +static void watchdog_trigger_immediate(void) +{ + sh_wdt_write_cnt(0xFF); + sh_wdt_write_csr(0xC2); +} + +void machine_restart(char * __unused) +{ + local_irq_disable(); + + /* Use watchdog timer to trigger reset */ + watchdog_trigger_immediate(); + + while (1) + cpu_sleep(); +} +#else void machine_restart(char * __unused) { /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ asm volatile("ldc %0, sr\n\t" "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001)); } +#endif void machine_halt(void) { diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 212e6bddaeb..d13bbafb4e1 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -404,10 +404,14 @@ void __init setup_arch(char **cmdline_p) if (!memory_end) memory_end = memory_start + __MEMORY_SIZE; -#ifdef CONFIG_CMDLINE_BOOL +#ifdef CONFIG_CMDLINE_OVERWRITE strlcpy(command_line, CONFIG_CMDLINE, sizeof(command_line)); #else strlcpy(command_line, COMMAND_LINE, sizeof(command_line)); +#ifdef CONFIG_CMDLINE_EXTEND + strlcat(command_line, " ", sizeof(command_line)); + strlcat(command_line, CONFIG_CMDLINE, sizeof(command_line)); +#endif #endif /* Save unparsed command line copy for /proc/cmdline */ diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index b5afbec1db5..6010750c90b 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -41,6 +41,16 @@ struct fdpic_func_descriptor { }; /* + * The following define adds a 64 byte gap between the signal + * stack frame and previous contents of the stack. This allows + * frame unwinding in a function epilogue but only if a frame + * pointer is used in the function. This is necessary because + * current gcc compilers (<4.3) do not generate unwind info on + * SH for function epilogues. + */ +#define UNWINDGUARD 64 + +/* * Atomically swap in the new signal mask, and wait for a signal. */ asmlinkage int @@ -327,7 +337,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) sp = current->sas_ss_sp + current->sas_ss_size; } - return (void __user *)((sp - frame_size) & -8ul); + return (void __user *)((sp - (frame_size+UNWINDGUARD)) & -8ul); } /* These symbols are defined with the addresses in the vsyscall page. diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 90d00e47264..8aa5d1ceaf1 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -25,6 +25,8 @@ #include <asm/syscalls.h> #include <asm/uaccess.h> #include <asm/unistd.h> +#include <asm/cacheflush.h> +#include <asm/cachectl.h> static inline long do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, @@ -179,6 +181,47 @@ asmlinkage int sys_ipc(uint call, int first, int second, return -EINVAL; } +/* sys_cacheflush -- flush (part of) the processor cache. */ +asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len, int op) +{ + struct vm_area_struct *vma; + + if ((op <= 0) || (op > (CACHEFLUSH_D_PURGE|CACHEFLUSH_I))) + return -EINVAL; + + /* + * Verify that the specified address region actually belongs + * to this process. + */ + if (addr + len < addr) + return -EFAULT; + + down_read(¤t->mm->mmap_sem); + vma = find_vma (current->mm, addr); + if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) { + up_read(¤t->mm->mmap_sem); + return -EFAULT; + } + + switch (op & CACHEFLUSH_D_PURGE) { + case CACHEFLUSH_D_INVAL: + __flush_invalidate_region((void *)addr, len); + break; + case CACHEFLUSH_D_WB: + __flush_wback_region((void *)addr, len); + break; + case CACHEFLUSH_D_PURGE: + __flush_purge_region((void *)addr, len); + break; + } + + if (op & CACHEFLUSH_I) + flush_cache_all(); + + up_read(¤t->mm->mmap_sem); + return 0; +} + asmlinkage int sys_uname(struct old_utsname __user *name) { int err; diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index f9e21fa2f59..16ba225ede8 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -139,7 +139,7 @@ ENTRY(sys_call_table) .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_ni_syscall /* sys_modify_ldt */ + .long sys_cacheflush /* x86: sys_modify_ldt */ .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index bf420b616ae..af6fb7410c2 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -143,7 +143,7 @@ sys_call_table: .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_ni_syscall /* sys_modify_ldt */ + .long sys_cacheflush /* x86: sys_modify_ldt */ .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 05a04b6df84..c581dc31d92 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -24,6 +24,7 @@ #include <linux/kdebug.h> #include <linux/kexec.h> #include <linux/limits.h> +#include <linux/proc_fs.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/fpu.h> @@ -44,6 +45,87 @@ #define TRAP_ILLEGAL_SLOT_INST 13 #endif +static unsigned long se_user; +static unsigned long se_sys; +static unsigned long se_skipped; +static unsigned long se_half; +static unsigned long se_word; +static unsigned long se_dword; +static unsigned long se_multi; +/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not + valid! */ +static int se_usermode = 3; +/* 0: no warning 1: print a warning message */ +static int se_kernmode_warn = 1; + +#ifdef CONFIG_PROC_FS +static const char *se_usermode_action[] = { + "ignored", + "warn", + "fixup", + "fixup+warn", + "signal", + "signal+warn" +}; + +static int +proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + char *p = page; + int len; + + p += sprintf(p, "User:\t\t%lu\n", se_user); + p += sprintf(p, "System:\t\t%lu\n", se_sys); + p += sprintf(p, "Skipped:\t%lu\n", se_skipped); + p += sprintf(p, "Half:\t\t%lu\n", se_half); + p += sprintf(p, "Word:\t\t%lu\n", se_word); + p += sprintf(p, "DWord:\t\t%lu\n", se_dword); + p += sprintf(p, "Multi:\t\t%lu\n", se_multi); + p += sprintf(p, "User faults:\t%i (%s)\n", se_usermode, + se_usermode_action[se_usermode]); + p += sprintf(p, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, + se_kernmode_warn ? "+warn" : ""); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} + +static int proc_alignment_write(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + char mode; + + if (count > 0) { + if (get_user(mode, buffer)) + return -EFAULT; + if (mode >= '0' && mode <= '5') + se_usermode = mode - '0'; + } + return count; +} + +static int proc_alignment_kern_write(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + char mode; + + if (count > 0) { + if (get_user(mode, buffer)) + return -EFAULT; + if (mode >= '0' && mode <= '1') + se_kernmode_warn = mode - '0'; + } + return count; +} +#endif + static void dump_mem(const char *str, unsigned long bottom, unsigned long top) { unsigned long p; @@ -194,6 +276,13 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs, count = 1<<(instruction&3); + switch (count) { + case 1: se_half += 1; break; + case 2: se_word += 1; break; + case 4: se_dword += 1; break; + case 8: se_multi += 1; break; /* ??? */ + } + ret = -EFAULT; switch (instruction>>12) { case 0: /* mov.[bwl] to/from memory via r0+rn */ @@ -359,13 +448,6 @@ static inline int handle_delayslot(struct pt_regs *regs, #define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) -/* - * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit - * opcodes.. - */ - -static int handle_unaligned_notify_count = 10; - int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, struct mem_access *ma) { @@ -375,15 +457,13 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, index = (instruction>>8)&15; /* 0x0F00 */ rm = regs->regs[index]; - /* shout about the first ten userspace fixups */ - if (user_mode(regs) && handle_unaligned_notify_count>0) { - handle_unaligned_notify_count--; - - printk(KERN_NOTICE "Fixing up unaligned userspace access " + /* shout about fixups */ + if (printk_ratelimit()) + printk(KERN_NOTICE "Fixing up unaligned %s access " "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", + user_mode(regs) ? "userspace" : "kernel", current->comm, task_pid_nr(current), (void *)regs->pc, instruction); - } ret = -EFAULT; switch (instruction&0xF000) { @@ -539,6 +619,36 @@ asmlinkage void do_address_error(struct pt_regs *regs, local_irq_enable(); + se_user += 1; + +#ifndef CONFIG_CPU_SH2A + set_fs(USER_DS); + if (copy_from_user(&instruction, (u16 *)(regs->pc & ~1), 2)) { + set_fs(oldfs); + goto uspace_segv; + } + set_fs(oldfs); + + /* shout about userspace fixups */ + if (se_usermode & 1) + printk(KERN_NOTICE "Unaligned userspace access " + "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", + current->comm, current->pid, (void *)regs->pc, + instruction); +#endif + + if (se_usermode & 2) + goto fixup; + + if (se_usermode & 4) + goto uspace_segv; + else { + /* ignore */ + regs->pc += instruction_size(instruction); + return; + } + +fixup: /* bad PC is not something we can fix */ if (regs->pc & 1) { si_code = BUS_ADRALN; @@ -546,15 +656,6 @@ asmlinkage void do_address_error(struct pt_regs *regs, } set_fs(USER_DS); - if (copy_from_user(&instruction, (void __user *)(regs->pc), - sizeof(instruction))) { - /* Argh. Fault on the instruction itself. - This should never happen non-SMP - */ - set_fs(oldfs); - goto uspace_segv; - } - tmp = handle_unaligned_access(instruction, regs, &user_mem_access); set_fs(oldfs); @@ -572,6 +673,14 @@ uspace_segv: info.si_addr = (void __user *)address; force_sig_info(SIGBUS, &info, current); } else { + se_sys += 1; + + if (se_kernmode_warn) + printk(KERN_NOTICE "Unaligned kernel access " + "on behalf of \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", + current->comm, current->pid, (void *)regs->pc, + instruction); + if (regs->pc & 1) die("unaligned program counter", regs, error_code); @@ -881,3 +990,38 @@ void dump_stack(void) show_stack(NULL, NULL); } EXPORT_SYMBOL(dump_stack); + +#ifdef CONFIG_PROC_FS +/* + * This needs to be done after sysctl_init, otherwise sys/ will be + * overwritten. Actually, this shouldn't be in sys/ at all since + * it isn't a sysctl, and it doesn't contain sysctl information. + * We now locate it in /proc/cpu/alignment instead. + */ +static int __init alignment_init(void) +{ + struct proc_dir_entry *dir, *res; + + dir = proc_mkdir("cpu", NULL); + if (!dir) + return -ENOMEM; + + res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, dir); + if (!res) + return -ENOMEM; + + res->read_proc = proc_alignment_read; + res->write_proc = proc_alignment_write; + + res = create_proc_entry("kernel_alignment", S_IWUSR | S_IRUGO, dir); + if (!res) + return -ENOMEM; + + res->read_proc = proc_alignment_read; + res->write_proc = proc_alignment_kern_write; + + return 0; +} + +fs_initcall(alignment_init); +#endif |