diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 09:01:44 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 09:01:44 -0700 |
commit | a6b49cb210f878709bdc0bddc16a853f18790d02 (patch) | |
tree | 6147078ef0ce584cb6a8dae7468f060ef5838d12 /arch/microblaze/kernel | |
parent | 2c9871de0ae89a0e2c365ea6e277135fe031d8b4 (diff) | |
parent | bfc8125858d777bd5bdba03a091c07cc2e0e17c0 (diff) | |
download | lwn-a6b49cb210f878709bdc0bddc16a853f18790d02.tar.gz lwn-a6b49cb210f878709bdc0bddc16a853f18790d02.zip |
Merge branch 'for-linus' of git://git.monstr.eu/linux-2.6-microblaze
* 'for-linus' of git://git.monstr.eu/linux-2.6-microblaze: (24 commits)
microblaze: Disable heartbeat/enable emaclite in defconfigs
microblaze: Support simpleImage.dts make target
microblaze: Fix _start symbol to physical address
microblaze: Use LOAD_OFFSET macro to get correct LMA for all sections
microblaze: Create the LOAD_OFFSET macro used to compute VMA vs LMA offsets
microblaze: Copy ppc asm-compat.h for clean handling of constants in asm and C
microblaze: Actually show KiB rather than pages in "Freeing initrd memory:"
microblaze: Support ptrace syscall tracing.
microblaze: Updated CPU version and FPGA family codes in PVR
microblaze: Generate correct signal and siginfo for integer div-by-zero
microblaze: Don't be noisy when userspace causes hardware exceptions
microblaze: Remove ipc.h file which points to non-existing asm-generic file
microblaze: Clear sticky FSR register after generating exception signals
microblaze: Ensure CPU usermode is set on new userspace processes
microblaze: Use correct kbuild variable KBUILD_CFLAGS
microblaze: Save and restore msr in hw exception
microblaze: Add architectural support for USB EHCI host controllers
microblaze: Implement include/asm/syscall.h.
microblaze: Improve checking mechanism for MSR instruction
microblaze: Add checking mechanism for MSR instruction
...
Diffstat (limited to 'arch/microblaze/kernel')
-rw-r--r-- | arch/microblaze/kernel/cpu/cpuinfo.c | 3 | ||||
-rw-r--r-- | arch/microblaze/kernel/entry.S | 72 | ||||
-rw-r--r-- | arch/microblaze/kernel/exceptions.c | 33 | ||||
-rw-r--r-- | arch/microblaze/kernel/head.S | 14 | ||||
-rw-r--r-- | arch/microblaze/kernel/hw_exception_handler.S | 10 | ||||
-rw-r--r-- | arch/microblaze/kernel/process.c | 1 | ||||
-rw-r--r-- | arch/microblaze/kernel/ptrace.c | 62 | ||||
-rw-r--r-- | arch/microblaze/kernel/setup.c | 12 | ||||
-rw-r--r-- | arch/microblaze/kernel/vmlinux.lds.S | 72 |
9 files changed, 205 insertions, 74 deletions
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c index c411c6757deb..3539babc1c18 100644 --- a/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/arch/microblaze/kernel/cpu/cpuinfo.c @@ -28,6 +28,7 @@ const struct cpu_ver_key cpu_ver_lookup[] = { {"7.10.d", 0x0b}, {"7.20.a", 0x0c}, {"7.20.b", 0x0d}, + {"7.20.c", 0x0e}, /* FIXME There is no keycode defined in MBV for these versions */ {"2.10.a", 0x10}, {"3.00.a", 0x20}, @@ -49,6 +50,8 @@ const struct family_string_key family_string_lookup[] = { {"spartan3a", 0xa}, {"spartan3an", 0xb}, {"spartan3adsp", 0xc}, + {"spartan6", 0xd}, + {"virtex6", 0xe}, /* FIXME There is no key code defined for spartan2 */ {"spartan2", 0xf0}, {NULL, 0}, diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index c7353e79f4a2..acc1f05d1e2c 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -308,38 +308,69 @@ C_ENTRY(_user_exception): swi r12, r1, PTO+PT_R0; tovirt(r1,r1) - la r15, r0, ret_from_trap-8 /* where the trap should return need -8 to adjust for rtsd r15, 8*/ /* Jump to the appropriate function for the system call number in r12 * (r12 is not preserved), or return an error if r12 is not valid. The LP * register should point to the location where * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ - /* See if the system call number is valid. */ + + # Step into virtual mode. + set_vms; + addik r11, r0, 3f + rtid r11, 0 + nop +3: + add r11, r0, CURRENT_TASK /* Get current task ptr into r11 */ + lwi r11, r11, TS_THREAD_INFO /* get thread info */ + lwi r11, r11, TI_FLAGS /* get flags in thread info */ + andi r11, r11, _TIF_WORK_SYSCALL_MASK + beqi r11, 4f + + addik r3, r0, -ENOSYS + swi r3, r1, PTO + PT_R3 + brlid r15, do_syscall_trace_enter + addik r5, r1, PTO + PT_R0 + + # do_syscall_trace_enter returns the new syscall nr. + addk r12, r0, r3 + lwi r5, r1, PTO+PT_R5; + lwi r6, r1, PTO+PT_R6; + lwi r7, r1, PTO+PT_R7; + lwi r8, r1, PTO+PT_R8; + lwi r9, r1, PTO+PT_R9; + lwi r10, r1, PTO+PT_R10; +4: +/* Jump to the appropriate function for the system call number in r12 + * (r12 is not preserved), or return an error if r12 is not valid. + * The LP register should point to the location where the called function + * should return. [note that MAKE_SYS_CALL uses label 1] */ + /* See if the system call number is valid */ addi r11, r12, -__NR_syscalls; - bgei r11,1f; + bgei r11,5f; /* Figure out which function to use for this system call. */ /* Note Microblaze barrel shift is optional, so don't rely on it */ add r12, r12, r12; /* convert num -> ptr */ add r12, r12, r12; /* Trac syscalls and stored them to r0_ram */ - lwi r3, r12, 0x400 + TOPHYS(r0_ram) + lwi r3, r12, 0x400 + r0_ram addi r3, r3, 1 - swi r3, r12, 0x400 + TOPHYS(r0_ram) + swi r3, r12, 0x400 + r0_ram + + # Find and jump into the syscall handler. + lwi r12, r12, sys_call_table + /* where the trap should return need -8 to adjust for rtsd r15, 8 */ + la r15, r0, ret_from_trap-8 + bra r12 - lwi r12, r12, TOPHYS(sys_call_table); /* Function ptr */ - /* Make the system call. to r12*/ - set_vms; - rtid r12, 0; - nop; /* The syscall number is invalid, return an error. */ -1: VM_ON; /* RETURN() expects virtual mode*/ +5: addi r3, r0, -ENOSYS; rtsd r15,8; /* looks like a normal subroutine return */ or r0, r0, r0 -/* Entry point used to return from a syscall/trap. */ +/* Entry point used to return from a syscall/trap */ /* We re-enable BIP bit before state restore */ C_ENTRY(ret_from_trap): set_bip; /* Ints masked for state restore*/ @@ -349,6 +380,23 @@ C_ENTRY(ret_from_trap): /* We're returning to user mode, so check for various conditions that * trigger rescheduling. */ + # FIXME: Restructure all these flag checks. + add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ + lwi r11, r11, TS_THREAD_INFO; /* get thread info */ + lwi r11, r11, TI_FLAGS; /* get flags in thread info */ + andi r11, r11, _TIF_WORK_SYSCALL_MASK + beqi r11, 1f + + swi r3, r1, PTO + PT_R3 + swi r4, r1, PTO + PT_R4 + brlid r15, do_syscall_trace_leave + addik r5, r1, PTO + PT_R0 + lwi r3, r1, PTO + PT_R3 + lwi r4, r1, PTO + PT_R4 +1: + + /* We're returning to user mode, so check for various conditions that + * trigger rescheduling. */ /* Get current task ptr into r11 */ add r11, r0, CURRENT_TASK; /* Get current task ptr into r11 */ lwi r11, r11, TS_THREAD_INFO; /* get thread info */ diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c index 0cb64a31e89a..d9f70f83097f 100644 --- a/arch/microblaze/kernel/exceptions.c +++ b/arch/microblaze/kernel/exceptions.c @@ -72,7 +72,8 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, #endif #if 0 - printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x ESR=%08x\n", + printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x " \ + "ESR=%08x\n", type, user_mode(regs) ? "user" : "kernel", fsr, (unsigned int) regs->pc, (unsigned int) regs->esr); #endif @@ -80,42 +81,50 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, switch (type & 0x1F) { case MICROBLAZE_ILL_OPCODE_EXCEPTION: if (user_mode(regs)) { - printk(KERN_WARNING "Illegal opcode exception in user mode.\n"); + pr_debug(KERN_WARNING "Illegal opcode exception " \ + "in user mode.\n"); _exception(SIGILL, regs, ILL_ILLOPC, addr); return; } - printk(KERN_WARNING "Illegal opcode exception in kernel mode.\n"); + printk(KERN_WARNING "Illegal opcode exception " \ + "in kernel mode.\n"); die("opcode exception", regs, SIGBUS); break; case MICROBLAZE_IBUS_EXCEPTION: if (user_mode(regs)) { - printk(KERN_WARNING "Instruction bus error exception in user mode.\n"); + pr_debug(KERN_WARNING "Instruction bus error " \ + "exception in user mode.\n"); _exception(SIGBUS, regs, BUS_ADRERR, addr); return; } - printk(KERN_WARNING "Instruction bus error exception in kernel mode.\n"); + printk(KERN_WARNING "Instruction bus error exception " \ + "in kernel mode.\n"); die("bus exception", regs, SIGBUS); break; case MICROBLAZE_DBUS_EXCEPTION: if (user_mode(regs)) { - printk(KERN_WARNING "Data bus error exception in user mode.\n"); + pr_debug(KERN_WARNING "Data bus error exception " \ + "in user mode.\n"); _exception(SIGBUS, regs, BUS_ADRERR, addr); return; } - printk(KERN_WARNING "Data bus error exception in kernel mode.\n"); + printk(KERN_WARNING "Data bus error exception " \ + "in kernel mode.\n"); die("bus exception", regs, SIGBUS); break; case MICROBLAZE_DIV_ZERO_EXCEPTION: if (user_mode(regs)) { - printk(KERN_WARNING "Divide by zero exception in user mode\n"); - _exception(SIGILL, regs, ILL_ILLOPC, addr); + pr_debug(KERN_WARNING "Divide by zero exception " \ + "in user mode\n"); + _exception(SIGILL, regs, FPE_INTDIV, addr); return; } - printk(KERN_WARNING "Divide by zero exception in kernel mode.\n"); + printk(KERN_WARNING "Divide by zero exception " \ + "in kernel mode.\n"); die("Divide by exception", regs, SIGBUS); break; case MICROBLAZE_FPU_EXCEPTION: - printk(KERN_WARNING "FPU exception\n"); + pr_debug(KERN_WARNING "FPU exception\n"); /* IEEE FP exception */ /* I removed fsr variable and use code var for storing fsr */ if (fsr & FSR_IO) @@ -133,7 +142,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, #ifdef CONFIG_MMU case MICROBLAZE_PRIVILEGED_EXCEPTION: - printk(KERN_WARNING "Privileged exception\n"); + pr_debug(KERN_WARNING "Privileged exception\n"); /* "brk r0,r0" - used as debug breakpoint */ if (get_user(code, (unsigned long *)regs->pc) == 0 && code == 0x980c0000) { diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index e41c6ce2a7be..697ce3007f30 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -54,6 +54,16 @@ ENTRY(_start) mfs r1, rmsr andi r1, r1, ~2 mts rmsr, r1 +/* + * Here is checking mechanism which check if Microblaze has msr instructions + * We load msr and compare it with previous r1 value - if is the same, + * msr instructions works if not - cpu don't have them. + */ + /* r8=0 - I have msr instr, 1 - I don't have them */ + rsubi r0, r0, 1 /* set the carry bit */ + msrclr r0, 0x4 /* try to clear it */ + /* read the carry bit, r8 will be '0' if msrclr exists */ + addik r8, r0, 0 /* r7 may point to an FDT, or there may be one linked in. if it's in r7, we've got to save it away ASAP. @@ -209,8 +219,8 @@ start_here: * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for * the function. */ - la r8, r0, machine_early_init - brald r15, r8 + la r9, r0, machine_early_init + brald r15, r9 nop #ifndef CONFIG_MMU diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 3288c9737671..6b0288ebccd6 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -84,9 +84,10 @@ #define NUM_TO_REG(num) r ## num #ifdef CONFIG_MMU -/* FIXME you can't change first load of MSR because there is - * hardcoded jump bri 4 */ #define RESTORE_STATE \ + lwi r5, r1, 0; \ + mts rmsr, r5; \ + nop; \ lwi r3, r1, PT_R3; \ lwi r4, r1, PT_R4; \ lwi r5, r1, PT_R5; \ @@ -309,6 +310,9 @@ _hw_exception_handler: lwi r31, r0, TOPHYS(PER_CPU(CURRENT_SAVE)) /* get saved current */ #endif + mfs r5, rmsr; + nop + swi r5, r1, 0; mfs r3, resr nop mfs r4, rear; @@ -380,6 +384,8 @@ handle_other_ex: /* Handle Other exceptions here */ addk r8, r17, r0; /* Load exception address */ bralid r15, full_exception; /* Branch to the handler */ nop; + mts r0, rfsr; /* Clear sticky fsr */ + nop /* * Trigger execution of the signal handler by enabling diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 00b12c6d5326..4201c743cc9f 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -235,6 +235,7 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp) regs->pc = pc; regs->r1 = usp; regs->pt_mode = 0; + regs->msr |= MSR_UMS; } #ifdef CONFIG_MMU diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index 53ff39af6a5c..4b3ac32754de 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -29,6 +29,10 @@ #include <linux/sched.h> #include <linux/ptrace.h> #include <linux/signal.h> +#include <linux/elf.h> +#include <linux/audit.h> +#include <linux/seccomp.h> +#include <linux/tracehook.h> #include <linux/errno.h> #include <asm/processor.h> @@ -174,6 +178,64 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return rval; } +asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) +{ + long ret = 0; + + secure_computing(regs->r12); + + if (test_thread_flag(TIF_SYSCALL_TRACE) && + tracehook_report_syscall_entry(regs)) + /* + * Tracing decided this syscall should not happen. + * We'll return a bogus call number to get an ENOSYS + * error, but leave the original number in regs->regs[0]. + */ + ret = -1L; + + if (unlikely(current->audit_context)) + audit_syscall_entry(EM_XILINX_MICROBLAZE, regs->r12, + regs->r5, regs->r6, + regs->r7, regs->r8); + + return ret ?: regs->r12; +} + +asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) +{ + int step; + + if (unlikely(current->audit_context)) + audit_syscall_exit(AUDITSC_RESULT(regs->r3), regs->r3); + + step = test_thread_flag(TIF_SINGLESTEP); + if (step || test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, step); +} + +#if 0 +static asmlinkage void syscall_trace(void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + /* The 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + ptrace_notify(SIGTRAP | ((current->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 (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} +#endif + void ptrace_disable(struct task_struct *child) { /* nothing to do */ diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c index 2a97bf513b64..8c1e0f4dcf18 100644 --- a/arch/microblaze/kernel/setup.c +++ b/arch/microblaze/kernel/setup.c @@ -94,7 +94,7 @@ inline unsigned get_romfs_len(unsigned *addr) #endif /* CONFIG_MTD_UCLINUX_EBSS */ void __init machine_early_init(const char *cmdline, unsigned int ram, - unsigned int fdt) + unsigned int fdt, unsigned int msr) { unsigned long *src, *dst = (unsigned long *)0x0; @@ -157,6 +157,16 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, early_printk("New klimit: 0x%08x\n", (unsigned)klimit); #endif +#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR + if (msr) + early_printk("!!!Your kernel has setup MSR instruction but " + "CPU don't have it %d\n", msr); +#else + if (!msr) + early_printk("!!!Your kernel not setup MSR instruction but " + "CPU have it %d\n", msr); +#endif + for (src = __ivt_start; src < __ivt_end; src++, dst++) *dst = *src; diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index ec5fa91a48d8..e704188d7855 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -12,13 +12,16 @@ OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze") OUTPUT_ARCH(microblaze) ENTRY(_start) +#include <asm/page.h> #include <asm-generic/vmlinux.lds.h> +#include <asm/thread_info.h> jiffies = jiffies_64 + 4; SECTIONS { . = CONFIG_KERNEL_START; - .text : { + _start = CONFIG_KERNEL_BASE_ADDR; + .text : AT(ADDR(.text) - LOAD_OFFSET) { _text = . ; _stext = . ; *(.text .text.*) @@ -33,24 +36,22 @@ SECTIONS { } . = ALIGN (4) ; - _fdt_start = . ; /* place for fdt blob */ - . = . + 0x4000; - _fdt_end = . ; + __fdt_blob : AT(ADDR(__fdt_blob) - LOAD_OFFSET) { + _fdt_start = . ; /* place for fdt blob */ + *(__fdt_blob) ; /* Any link-placed DTB */ + . = _fdt_start + 0x4000; /* Pad up to 16kbyte */ + _fdt_end = . ; + } . = ALIGN(16); RODATA - . = ALIGN(16); - __ex_table : { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } + EXCEPTION_TABLE(16) /* * sdata2 section can go anywhere, but must be word aligned * and SDA2_BASE must point to the middle of it */ - .sdata2 : { + .sdata2 : AT(ADDR(.sdata2) - LOAD_OFFSET) { _ssrw = .; . = ALIGN(4096); /* page aligned when MMU used - origin 0x8 */ *(.sdata2) @@ -61,12 +62,7 @@ SECTIONS { } _sdata = . ; - .data ALIGN (4096) : { /* page aligned when MMU used - origin 0x4 */ - DATA_DATA - CONSTRUCTORS - } - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } + RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE) _edata = . ; /* Reserve some low RAM for r0 based memory references */ @@ -74,18 +70,14 @@ SECTIONS { r0_ram = . ; . = . + 4096; /* a page should be enough */ - /* The initial task */ - . = ALIGN(8192); - .data.init_task : { *(.data.init_task) } - /* Under the microblaze ABI, .sdata and .sbss must be contiguous */ . = ALIGN(8); - .sdata : { + .sdata : AT(ADDR(.sdata) - LOAD_OFFSET) { _ssro = .; *(.sdata) } - .sbss : { + .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { _ssbss = .; *(.sbss) _esbss = .; @@ -96,47 +88,36 @@ SECTIONS { __init_begin = .; - . = ALIGN(4096); - .init.text : { - _sinittext = . ; - INIT_TEXT - _einittext = .; - } + INIT_TEXT_SECTION(PAGE_SIZE) - .init.data : { + .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { INIT_DATA } . = ALIGN(4); - .init.ivt : { + .init.ivt : AT(ADDR(.init.ivt) - LOAD_OFFSET) { __ivt_start = .; *(.init.ivt) __ivt_end = .; } - .init.setup : { - __setup_start = .; - *(.init.setup) - __setup_end = .; + .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { + INIT_SETUP(0) } - .initcall.init : { - __initcall_start = .; - INITCALLS - __initcall_end = .; + .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET ) { + INIT_CALLS } - .con_initcall.init : { - __con_initcall_start = .; - *(.con_initcall.init) - __con_initcall_end = .; + .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { + CON_INITCALL } SECURITY_INIT __init_end_before_initramfs = .; - .init.ramfs ALIGN(4096) : { + .init.ramfs ALIGN(4096) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { __initramfs_start = .; *(.init.ramfs) __initramfs_end = .; @@ -152,7 +133,8 @@ SECTIONS { } __init_end = .; - .bss ALIGN (4096) : { /* page aligned when MMU used */ + .bss ALIGN (4096) : AT(ADDR(.bss) - LOAD_OFFSET) { + /* page aligned when MMU used */ __bss_start = . ; *(.bss*) *(COMMON) |