From 8d7ec6ee59e78140bf01c7d0d009ea39ab6b3b59 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 20 May 2010 10:56:29 +0200 Subject: microblaze: Fix __copy_to/from_user_inatomic macros __copy_to/from_user_inatomic should call __copy_to/from_user because there is not necessary to check access because of kernel function. might_sleep in copy_to/from_user macros is causing problems in debug sessions too (CONFIG_DEBUG_SPINLOCK_SLEEP). BUG: sleeping function called from invalid context at .../arch/microblaze/include/asm/uaccess.h:388 in_atomic(): 1, irqs_disabled(): 0, pid: 1, name: swapper 1 lock held by swapper/1: #0: (&p->cred_guard_mutex){......}, at: [] prepare_bprm_creds+0x2c/0x88 Kernel Stack: ... Call Trace: [] microblaze_unwind+0x7c/0x94 [] show_stack+0xf4/0x190 [] dump_stack+0x10/0x30 [] __might_sleep+0x12c/0x160 [] file_read_actor+0x1d8/0x2a8 [] generic_file_aio_read+0x6b4/0xa64 [] do_sync_read+0xac/0x110 [] vfs_read+0xc8/0x160 [] kernel_read+0x38/0x64 [] prepare_binprm+0xfc/0x130 [] do_execve+0x228/0x370 [] microblaze_execve+0x58/0xa4 caused by file_read_actor (mm/filemap.c) which calls __copy_to_user_inatomic. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/uaccess.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h index 26460d15b338..d840f4a2d3c9 100644 --- a/arch/microblaze/include/asm/uaccess.h +++ b/arch/microblaze/include/asm/uaccess.h @@ -359,7 +359,7 @@ extern long __user_bad(void); __copy_tofrom_user((__force void __user *)(to), \ (void __user *)(from), (n)) #define __copy_from_user_inatomic(to, from, n) \ - copy_from_user((to), (from), (n)) + __copy_from_user((to), (from), (n)) static inline long copy_from_user(void *to, const void __user *from, unsigned long n) @@ -373,7 +373,7 @@ static inline long copy_from_user(void *to, #define __copy_to_user(to, from, n) \ __copy_tofrom_user((void __user *)(to), \ (__force const void __user *)(from), (n)) -#define __copy_to_user_inatomic(to, from, n) copy_to_user((to), (from), (n)) +#define __copy_to_user_inatomic(to, from, n) __copy_to_user((to), (from), (n)) static inline long copy_to_user(void __user *to, const void *from, unsigned long n) -- cgit v1.2.3-55-g7522 From af58ed854bf7d233988ae037e19f5d89335e0ecc Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 4 Jun 2010 12:57:06 +0200 Subject: microblaze: Fix comment for TLB There is wrong comment for TLB. Early printk uartlite console uses TLB 63. Signed-off-by: Michal Simek --- arch/microblaze/kernel/misc.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S index 0fb5fc6c1fc2..206da3da361f 100644 --- a/arch/microblaze/kernel/misc.S +++ b/arch/microblaze/kernel/misc.S @@ -76,7 +76,7 @@ early_console_reg_tlb_alloc: * the UARTs nice and early. We use a 4k real==virtual mapping. */ ori r4, r0, MICROBLAZE_TLB_SIZE - 1 - mts rtlbx, r4 /* TLB slot 2 */ + mts rtlbx, r4 /* TLB slot 63 */ or r4,r5,r0 andi r4,r4,0xfffff000 -- cgit v1.2.3-55-g7522 From 79e87830faf22ca636b1a1d8f4deb430ea6e1c8b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 4 Jun 2010 13:00:31 +0200 Subject: microblaze: Implement flush_dcache_page macro flush_dcache_page macro is necessary to implement for JFFS2 rootfs support on WB system. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/cacheflush.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h index a6edd356cd08..e9bb567e1b0e 100644 --- a/arch/microblaze/include/asm/cacheflush.h +++ b/arch/microblaze/include/asm/cacheflush.h @@ -17,6 +17,7 @@ /* Somebody depends on this; sigh... */ #include +#include /* Look at Documentation/cachetlb.txt */ @@ -60,7 +61,6 @@ void microblaze_cache_init(void); #define invalidate_icache() mbc->iin(); #define invalidate_icache_range(start, end) mbc->iinr(start, end); - #define flush_icache_user_range(vma, pg, adr, len) flush_icache(); #define flush_icache_page(vma, pg) do { } while (0) @@ -72,9 +72,15 @@ void microblaze_cache_init(void); #define flush_dcache() mbc->dfl(); #define flush_dcache_range(start, end) mbc->dflr(start, end); -#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 -/* D-cache aliasing problem can't happen - cache is between MMU and ram */ -#define flush_dcache_page(page) do { } while (0) +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 +/* MS: We have to implement it because of rootfs-jffs2 issue on WB */ +#define flush_dcache_page(page) \ +do { \ + unsigned long addr = (unsigned long) page_address(page); /* virtual */ \ + addr = (u32)virt_to_phys((void *)addr); \ + flush_dcache_range((unsigned) (addr), (unsigned) (addr) + PAGE_SIZE); \ +} while (0); + #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) -- cgit v1.2.3-55-g7522 From ef78705034763ebdf500695deaed599c481318a7 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 7 Jun 2010 14:18:13 +0200 Subject: microblaze: Remove unused label The label should be remove by 21e1c93631e027136ea4070e7bca600c4ad4f391 Warning message: arch/microblaze/mm/fault.c: In function 'do_page_fault': arch/microblaze/mm/fault.c:229: warning: label 'survive' defined but not used Signed-off-by: Michal Simek --- arch/microblaze/mm/fault.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index bab922993185..b224c650a18d 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -226,7 +226,6 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ -survive: fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); if (unlikely(fault & VM_FAULT_ERROR)) { if (fault & VM_FAULT_OOM) -- cgit v1.2.3-55-g7522 From e05816679b61e47e90d7455a8f6dc6126dc479e3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 27 May 2010 11:17:35 +0200 Subject: microblaze: Sync noMMU and MMU setup_memory Both versions can use the same node to register NODE_DATA(0) Signed-off-by: Michal Simek --- arch/microblaze/mm/init.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c index db5934989926..65eb00419d19 100644 --- a/arch/microblaze/mm/init.c +++ b/arch/microblaze/mm/init.c @@ -134,13 +134,8 @@ void __init setup_memory(void) * for 4GB of memory, using 4kB pages), plus 1 page * (in case the address isn't page-aligned). */ -#ifndef CONFIG_MMU - map_size = init_bootmem_node(NODE_DATA(0), PFN_UP(TOPHYS((u32)klimit)), - min_low_pfn, max_low_pfn); -#else - map_size = init_bootmem_node(&contig_page_data, + map_size = init_bootmem_node(NODE_DATA(0), PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn); -#endif memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size); /* free bootmem is whole main memory */ -- cgit v1.2.3-55-g7522 From 6847ba91a190fe41d21779d6b382b47b2f4c50f4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 24 May 2010 12:13:24 +0200 Subject: microblaze: Fix copy_to_user_page macro copy_to_user_page macro is used in mm/memory.c:access_process_vm function. This function is called from ptrace code (POKETEXT, POKEDATA) which write data to memory. Microblaze handle physical address for caches that's why there is virt_to_phys conversion. There is potential one location which can caused the problem on WB system. The important is take a look at write PTRACEs requests (POKE/TEXT, DATA, USR). Note: Majority of Microblaze PTRACE code is moved to generic location in newer kernel version that's why this solution should work on the newest kernel version too. linux/io.h is in cacheflush because of mm/nommu.c Tested on a WB system - hello world debugging. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/cacheflush.h | 4 +++- arch/microblaze/kernel/ptrace.c | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h index e9bb567e1b0e..7ebd955460d9 100644 --- a/arch/microblaze/include/asm/cacheflush.h +++ b/arch/microblaze/include/asm/cacheflush.h @@ -103,8 +103,10 @@ do { \ #define copy_to_user_page(vma, page, vaddr, dst, src, len) \ do { \ + u32 addr = virt_to_phys(dst); \ + invalidate_icache_range((unsigned) (addr), (unsigned) (addr) + (len));\ memcpy((dst), (src), (len)); \ - flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \ + flush_dcache_range((unsigned) (addr), (unsigned) (addr) + (len));\ } while (0) #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ diff --git a/arch/microblaze/kernel/ptrace.c b/arch/microblaze/kernel/ptrace.c index a4a7770c6140..dc03ffc8174a 100644 --- a/arch/microblaze/kernel/ptrace.c +++ b/arch/microblaze/kernel/ptrace.c @@ -38,6 +38,8 @@ #include #include #include +#include +#include /* Returns the address where the register at REG_OFFS in P is stashed away. */ static microblaze_reg_t *reg_save_addr(unsigned reg_offs, @@ -101,8 +103,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) microblaze_reg_t *reg_addr = reg_save_addr(addr, child); if (request == PTRACE_PEEKUSR) val = *reg_addr; - else + else { +#if 1 *reg_addr = data; +#else + /* MS potential problem on WB system + * Be aware that reg_addr is virtual address + * virt_to_phys conversion is necessary. + * This could be sensible solution. + */ + u32 paddr = virt_to_phys((u32)reg_addr); + invalidate_icache_range(paddr, paddr + 4); + *reg_addr = data; + flush_dcache_range(paddr, paddr + 4); +#endif + } } else rval = -EIO; -- cgit v1.2.3-55-g7522 From 570e3e236efdf5bb4a023ecc3601dad9273a011e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 4 Jun 2010 13:06:27 +0200 Subject: microblaze: Fix sys_clone syscall sys_clone syscall ignored args which this patch mapped to args which are passing from glibc. Here is the origin problem description. "I ran the static libgcc tests (very few of them are there, they are mostly dynamically linked) and some of them fail with an assertion in fork() system call (tid != pid), I looked at the microblaze/entry.S file and it looks suspicious (ignores arguments 3-5)" Arg mapping should be: glibc ARCH_FORK(...) -> do_fork(...) r5 -> r5 (clone_flags) r6 -> r6 (stack_start, use parent->stack if NULL) pt_regs -> r7 (pt_regs) r7 -> r8 (stack_size) r8 -> r9 (parent_tidptr) r9 -> r10 (child_tidptr) Signed-off-by: John Williams Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index c0ede25c5b99..077377a5d0ca 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -476,13 +476,13 @@ C_ENTRY(sys_vfork): C_ENTRY(sys_clone): bnei r6, 1f; /* See if child SP arg (arg 1) is 0. */ - lwi r6, r1, PTO+PT_R1; /* If so, use paret's stack ptr */ -1: la r7, r1, PTO; /* Arg 2: parent context */ - add r8, r0, r0; /* Arg 3: (unused) */ - add r9, r0, r0; /* Arg 4: (unused) */ - add r10, r0, r0; /* Arg 5: (unused) */ - brid do_fork /* Do real work (tail-call) */ - nop; + lwi r6, r1, PTO + PT_R1; /* If so, use paret's stack ptr */ +1: add r10, r0, r9; /* Arg 6: (child_tidptr) */ + add r9, r0, r8; /* Arg 5: (parent_tidptr) */ + add r8, r0, r7; /* Arg 4: (stack_size) */ + la r7, r1, PTO; /* Arg 3: pt_regs */ + brid do_fork /* Do real work (tail-call) */ + nop C_ENTRY(sys_execve): la r8, r1, PTO; /* add user context as 4th arg */ -- cgit v1.2.3-55-g7522 From 0d9ec762af297f1ef38114f9498322d994063802 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 25 May 2010 13:44:38 +0200 Subject: microblaze: Trace hardirqs Add trace_hardirqs_off and trace_hardirqs_on to do_IRQ function. Signed-off-by: Michal Simek --- arch/microblaze/kernel/irq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch') diff --git a/arch/microblaze/kernel/irq.c b/arch/microblaze/kernel/irq.c index 8f120aca123d..598f1fd61c89 100644 --- a/arch/microblaze/kernel/irq.c +++ b/arch/microblaze/kernel/irq.c @@ -37,6 +37,7 @@ void __irq_entry do_IRQ(struct pt_regs *regs) { unsigned int irq; struct pt_regs *old_regs = set_irq_regs(regs); + trace_hardirqs_off(); irq_enter(); irq = get_irq(regs); @@ -53,6 +54,7 @@ next_irq: irq_exit(); set_irq_regs(old_regs); + trace_hardirqs_on(); } int show_interrupts(struct seq_file *p, void *v) -- cgit v1.2.3-55-g7522 From ba9c4f88d747836bf35c3eee36aa18d2e164f493 Mon Sep 17 00:00:00 2001 From: Steven J. Magnani Date: Thu, 13 May 2010 10:48:27 -0500 Subject: microblaze: Allow PAGE_SIZE configuration Allow developer to configure memory page size at compile time. Larger pages can improve performance on some workloads. Based on PowerPC code. Signed-off-by: Steven J. Magnani Signed-off-by: Michal Simek --- arch/microblaze/Kconfig | 30 ++++++++++++++++++++++++++++++ arch/microblaze/include/asm/elf.h | 2 +- arch/microblaze/include/asm/page.h | 12 ++++++++++-- arch/microblaze/kernel/cpu/mb.c | 1 + arch/microblaze/kernel/head.S | 4 ++-- arch/microblaze/kernel/vmlinux.lds.S | 12 ++++++------ 6 files changed, 50 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 505a08592423..a51742190c12 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -223,6 +223,36 @@ config TASK_SIZE hex "Size of user task space" if TASK_SIZE_BOOL default "0x80000000" +choice + prompt "Page size" + default MICROBLAZE_4K_PAGES + depends on ADVANCED_OPTIONS && !MMU + help + Select the kernel logical page size. Increasing the page size + will reduce software overhead at each page boundary, allow + hardware prefetch mechanisms to be more effective, and allow + larger dma transfers increasing IO efficiency and reducing + overhead. However the utilization of memory will increase. + For example, each cached file will using a multiple of the + page size to hold its contents and the difference between the + end of file and the end of page is wasted. + + If unsure, choose 4K_PAGES. + +config MICROBLAZE_4K_PAGES + bool "4k page size" + +config MICROBLAZE_8K_PAGES + bool "8k page size" + +config MICROBLAZE_16K_PAGES + bool "16k page size" + +config MICROBLAZE_32K_PAGES + bool "32k page size" + +endchoice + endmenu source "mm/Kconfig" diff --git a/arch/microblaze/include/asm/elf.h b/arch/microblaze/include/asm/elf.h index 7d4acf2b278e..732caf1be741 100644 --- a/arch/microblaze/include/asm/elf.h +++ b/arch/microblaze/include/asm/elf.h @@ -77,7 +77,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #define ELF_DATA ELFDATA2MSB #endif -#define ELF_EXEC_PAGESIZE 4096 +#define ELF_EXEC_PAGESIZE PAGE_SIZE #define ELF_CORE_COPY_REGS(_dest, _regs) \ diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h index 464ff32bee3d..c12c6dfafd9f 100644 --- a/arch/microblaze/include/asm/page.h +++ b/arch/microblaze/include/asm/page.h @@ -23,8 +23,16 @@ #ifdef __KERNEL__ /* PAGE_SHIFT determines the page size */ -#define PAGE_SHIFT (12) -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#if defined(CONFIG_MICROBLAZE_32K_PAGES) +#define PAGE_SHIFT 15 +#elif defined(CONFIG_MICROBLAZE_16K_PAGES) +#define PAGE_SHIFT 14 +#elif defined(CONFIG_MICROBLAZE_8K_PAGES) +#define PAGE_SHIFT 13 +#else +#define PAGE_SHIFT 12 +#endif +#define PAGE_SIZE (ASM_CONST(1) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) #define LOAD_OFFSET ASM_CONST((CONFIG_KERNEL_START-CONFIG_KERNEL_BASE_ADDR)) diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c index 4216eb1eaa32..7086e3564281 100644 --- a/arch/microblaze/kernel/cpu/mb.c +++ b/arch/microblaze/kernel/cpu/mb.c @@ -126,6 +126,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpuinfo.pvr_user1, cpuinfo.pvr_user2); + count += seq_printf(m, "Page size:\t%lu\n", PAGE_SIZE); return 0; } diff --git a/arch/microblaze/kernel/head.S b/arch/microblaze/kernel/head.S index 1bf739888260..42434008209e 100644 --- a/arch/microblaze/kernel/head.S +++ b/arch/microblaze/kernel/head.S @@ -43,10 +43,10 @@ .global empty_zero_page .align 12 empty_zero_page: - .space 4096 + .space PAGE_SIZE .global swapper_pg_dir swapper_pg_dir: - .space 4096 + .space PAGE_SIZE #endif /* CONFIG_MMU */ diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index db72d7124602..b0de1a6b5513 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -55,7 +55,7 @@ SECTIONS { */ .sdata2 : AT(ADDR(.sdata2) - LOAD_OFFSET) { _ssrw = .; - . = ALIGN(4096); /* page aligned when MMU used - origin 0x8 */ + . = ALIGN(PAGE_SIZE); /* page aligned when MMU used */ *(.sdata2) . = ALIGN(8); _essrw = .; @@ -70,7 +70,7 @@ SECTIONS { /* Reserve some low RAM for r0 based memory references */ . = ALIGN(0x4) ; r0_ram = . ; - . = . + 4096; /* a page should be enough */ + . = . + PAGE_SIZE; /* a page should be enough */ /* Under the microblaze ABI, .sdata and .sbss must be contiguous */ . = ALIGN(8); @@ -120,7 +120,7 @@ SECTIONS { __init_end_before_initramfs = .; - .init.ramfs ALIGN(4096) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { + .init.ramfs ALIGN(PAGE_SIZE) : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { __initramfs_start = .; *(.init.ramfs) __initramfs_end = .; @@ -132,11 +132,11 @@ SECTIONS { * so that __init_end == __bss_start. This will make image.elf * consistent with the image.bin */ - /* . = ALIGN(4096); */ + /* . = ALIGN(PAGE_SIZE); */ } __init_end = .; - .bss ALIGN (4096) : AT(ADDR(.bss) - LOAD_OFFSET) { + .bss ALIGN (PAGE_SIZE) : AT(ADDR(.bss) - LOAD_OFFSET) { /* page aligned when MMU used */ __bss_start = . ; *(.bss*) @@ -145,7 +145,7 @@ SECTIONS { __bss_stop = . ; _ebss = . ; } - . = ALIGN(4096); + . = ALIGN(PAGE_SIZE); _end = .; DISCARDS -- cgit v1.2.3-55-g7522 From ce3266c047389443d5f433d605c769e878cbe46e Mon Sep 17 00:00:00 2001 From: Steven J. Magnani Date: Tue, 27 Apr 2010 12:37:54 -0500 Subject: microblaze: Add stack unwinder Implement intelligent backtracing by searching for stack frame creation, and emitting only return addresses. Use print_hex_dump() to display the entire binary kernel stack. Limitation: MMU kernels are not currently able to trace beyond a system trap (interrupt, syscall, etc.). It is the intent of this patch to provide infrastructure that can be extended to add this capability later. Changes from V1: * Removed checks in find_frame_creation() that prevented location of the frame creation instruction in heavily optimized code * Various formatting/commenting/file location tweaks per review comments * Dropped Kconfig option to enable STACKTRACE as something logically separate Signed-off-by: Steven J. Magnani --- arch/microblaze/include/asm/exceptions.h | 5 + arch/microblaze/include/asm/system.h | 1 - arch/microblaze/include/asm/unwind.h | 29 +++ arch/microblaze/kernel/Makefile | 2 +- arch/microblaze/kernel/entry-nommu.S | 28 +++ arch/microblaze/kernel/entry.S | 27 +++ arch/microblaze/kernel/hw_exception_handler.S | 4 +- arch/microblaze/kernel/stacktrace.c | 44 +--- arch/microblaze/kernel/traps.c | 91 ++++---- arch/microblaze/kernel/unwind.c | 318 ++++++++++++++++++++++++++ 10 files changed, 454 insertions(+), 95 deletions(-) create mode 100644 arch/microblaze/include/asm/unwind.h create mode 100644 arch/microblaze/kernel/unwind.c (limited to 'arch') diff --git a/arch/microblaze/include/asm/exceptions.h b/arch/microblaze/include/asm/exceptions.h index 4c7b5d037c88..fa0e36657fdd 100644 --- a/arch/microblaze/include/asm/exceptions.h +++ b/arch/microblaze/include/asm/exceptions.h @@ -14,6 +14,11 @@ #define _ASM_MICROBLAZE_EXCEPTIONS_H #ifdef __KERNEL__ + +#ifndef CONFIG_MMU +#define EX_HANDLER_STACK_SIZ (4*19) +#endif + #ifndef __ASSEMBLY__ /* Macros to enable and disable HW exceptions in the MSR */ diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h index 48c4f0335e3f..4f8eaea21f88 100644 --- a/arch/microblaze/include/asm/system.h +++ b/arch/microblaze/include/asm/system.h @@ -45,7 +45,6 @@ extern struct task_struct *_switch_to(struct thread_info *prev, #define smp_rmb() rmb() #define smp_wmb() wmb() -void show_trace(struct task_struct *task, unsigned long *stack); void __bad_xchg(volatile void *ptr, int size); static inline unsigned long __xchg(unsigned long x, volatile void *ptr, diff --git a/arch/microblaze/include/asm/unwind.h b/arch/microblaze/include/asm/unwind.h new file mode 100644 index 000000000000..d248b7de4b13 --- /dev/null +++ b/arch/microblaze/include/asm/unwind.h @@ -0,0 +1,29 @@ +/* + * Backtrace support for Microblaze + * + * Copyright (C) 2010 Digital Design Corporation + * + * 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. + */ + +#ifndef __MICROBLAZE_UNWIND_H +#define __MICROBLAZE_UNWIND_H + +struct stack_trace; + +struct trap_handler_info { + unsigned long start_addr; + unsigned long end_addr; + const char *trap_name; +}; +extern struct trap_handler_info microblaze_trap_handlers; + +extern const char _hw_exception_handler; +extern const char ex_handler_unhandled; + +void microblaze_unwind(struct task_struct *task, struct stack_trace *trace); + +#endif /* __MICROBLAZE_UNWIND_H */ + diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index e51bc1520825..d66ddef53c07 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -17,7 +17,7 @@ extra-y := head.o vmlinux.lds obj-y += dma.o exceptions.o \ hw_exception_handler.o init_task.o intc.o irq.o of_device.o \ of_platform.o process.o prom.o prom_parse.o ptrace.o \ - setup.o signal.o sys_microblaze.o timer.o traps.o reset.o + reset.o setup.o signal.o sys_microblaze.o timer.o traps.o unwind.o obj-y += cpu/ diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S index 8cc18cd2cce6..ca84368570b6 100644 --- a/arch/microblaze/kernel/entry-nommu.S +++ b/arch/microblaze/kernel/entry-nommu.S @@ -588,3 +588,31 @@ sys_rt_sigsuspend_wrapper: #include "syscall_table.S" syscall_table_size=(.-sys_call_table) + +type_SYSCALL: + .ascii "SYSCALL\0" +type_IRQ: + .ascii "IRQ\0" +type_IRQ_PREEMPT: + .ascii "IRQ (PREEMPTED)\0" +type_SYSCALL_PREEMPT: + .ascii " SYSCALL (PREEMPTED)\0" + + /* + * Trap decoding for stack unwinder + * Tuples are (start addr, end addr, string) + * If return address lies on [start addr, end addr], + * unwinder displays 'string' + */ + + .align 4 +.global microblaze_trap_handlers +microblaze_trap_handlers: + /* Exact matches come first */ + .word ret_to_user ; .word ret_to_user ; .word type_SYSCALL + .word ret_from_intr; .word ret_from_intr ; .word type_IRQ + /* Fuzzy matches go here */ + .word ret_from_intr; .word no_intr_resched; .word type_IRQ_PREEMPT + .word work_pending ; .word no_work_pending; .word type_SYSCALL_PREEMPT + /* End of table */ + .word 0 ; .word 0 ; .word 0 diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 077377a5d0ca..7a19d8910e3b 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -1127,3 +1127,30 @@ ENTRY(_break) syscall_table_size=(.-sys_call_table) +type_SYSCALL: + .ascii "SYSCALL\0" +type_IRQ: + .ascii "IRQ\0" +type_IRQ_PREEMPT: + .ascii "IRQ (PREEMPTED)\0" +type_SYSCALL_PREEMPT: + .ascii " SYSCALL (PREEMPTED)\0" + + /* + * Trap decoding for stack unwinder + * Tuples are (start addr, end addr, string) + * If return address lies on [start addr, end addr], + * unwinder displays 'string' + */ + + .align 4 +.global microblaze_trap_handlers +microblaze_trap_handlers: + /* Exact matches come first */ + .word ret_from_trap; .word ret_from_trap ; .word type_SYSCALL + .word ret_from_irq ; .word ret_from_irq ; .word type_IRQ + /* Fuzzy matches go here */ + .word ret_from_irq ; .word no_intr_resched ; .word type_IRQ_PREEMPT + .word ret_from_trap; .word TRAP_return ; .word type_SYSCALL_PREEMPT + /* End of table */ + .word 0 ; .word 0 ; .word 0 diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S index 995a2123635b..781195438ee6 100644 --- a/arch/microblaze/kernel/hw_exception_handler.S +++ b/arch/microblaze/kernel/hw_exception_handler.S @@ -78,9 +78,6 @@ #include /* Helpful Macros */ -#ifndef CONFIG_MMU -#define EX_HANDLER_STACK_SIZ (4*19) -#endif #define NUM_TO_REG(num) r ## num #ifdef CONFIG_MMU @@ -988,6 +985,7 @@ ex_unaligned_fixup: .end _unaligned_data_exception #endif /* CONFIG_MMU */ +.global ex_handler_unhandled ex_handler_unhandled: /* FIXME add handle function for unhandled exception - dump register */ bri 0 diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c index 123692f22647..84bc6686102c 100644 --- a/arch/microblaze/kernel/stacktrace.c +++ b/arch/microblaze/kernel/stacktrace.c @@ -14,52 +14,18 @@ #include #include #include +#include -/* FIXME initial support */ void save_stack_trace(struct stack_trace *trace) { - unsigned long *sp; - unsigned long addr; - asm("addik %0, r1, 0" : "=r" (sp)); - - while (!kstack_end(sp)) { - addr = *sp++; - if (__kernel_text_address(addr)) { - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = addr; - - if (trace->nr_entries >= trace->max_entries) - break; - } - } + /* Exclude our helper functions from the trace*/ + trace->skip += 2; + microblaze_unwind(NULL, trace); } EXPORT_SYMBOL_GPL(save_stack_trace); void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) { - unsigned int *sp; - unsigned long addr; - - struct thread_info *ti = task_thread_info(tsk); - - if (tsk == current) - asm("addik %0, r1, 0" : "=r" (sp)); - else - sp = (unsigned int *)ti->cpu_context.r1; - - while (!kstack_end(sp)) { - addr = *sp++; - if (__kernel_text_address(addr)) { - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = addr; - - if (trace->nr_entries >= trace->max_entries) - break; - } - } + microblaze_unwind(tsk, trace); } EXPORT_SYMBOL_GPL(save_stack_trace_tsk); diff --git a/arch/microblaze/kernel/traps.c b/arch/microblaze/kernel/traps.c index 75e49202a5ed..ba034d421ec2 100644 --- a/arch/microblaze/kernel/traps.c +++ b/arch/microblaze/kernel/traps.c @@ -16,13 +16,14 @@ #include #include +#include void trap_init(void) { __enable_hw_exceptions(); } -static unsigned long kstack_depth_to_print = 24; +static unsigned long kstack_depth_to_print; /* 0 == entire stack */ static int __init kstack_setup(char *s) { @@ -30,31 +31,47 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); -void show_trace(struct task_struct *task, unsigned long *stack) +void show_stack(struct task_struct *task, unsigned long *sp) { - unsigned long addr; - - if (!stack) - stack = (unsigned long *)&stack; + unsigned long words_to_show; + u32 fp = (u32) sp; + + if (fp == 0) { + if (task) { + fp = ((struct thread_info *) + (task->stack))->cpu_context.r1; + } else { + /* Pick up caller of dump_stack() */ + fp = (u32)&sp - 8; + } + } - printk(KERN_NOTICE "Call Trace: "); -#ifdef CONFIG_KALLSYMS - printk(KERN_NOTICE "\n"); -#endif - while (!kstack_end(stack)) { - addr = *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 (kernel_text_address(addr)) - print_ip_sym(addr); + words_to_show = (THREAD_SIZE - (fp & (THREAD_SIZE - 1))) >> 2; + if (kstack_depth_to_print && (words_to_show > kstack_depth_to_print)) + words_to_show = kstack_depth_to_print; + + pr_info("Kernel Stack:\n"); + + /* + * Make the first line an 'odd' size if necessary to get + * remaining lines to start at an address multiple of 0x10 + */ + if (fp & 0xF) { + unsigned long line1_words = (0x10 - (fp & 0xF)) >> 2; + if (line1_words < words_to_show) { + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, + 4, (void *)fp, line1_words << 2, 0); + fp += line1_words << 2; + words_to_show -= line1_words; + } } - printk(KERN_NOTICE "\n"); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4, (void *)fp, + words_to_show << 2, 0); + printk(KERN_INFO "\n\n"); + + pr_info("Call Trace:\n"); + microblaze_unwind(task, NULL); + pr_info("\n"); if (!task) task = current; @@ -62,34 +79,6 @@ void show_trace(struct task_struct *task, unsigned long *stack) debug_show_held_locks(task); } -void show_stack(struct task_struct *task, unsigned long *sp) -{ - unsigned long *stack; - int i; - - if (sp == NULL) { - if (task) - sp = (unsigned long *) ((struct thread_info *) - (task->stack))->cpu_context.r1; - else - sp = (unsigned long *)&sp; - } - - stack = sp; - - printk(KERN_INFO "\nStack:\n "); - - for (i = 0; i < kstack_depth_to_print; i++) { - if (kstack_end(sp)) - break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", *sp++); - } - printk("\n"); - show_trace(task, stack); -} - void dump_stack(void) { show_stack(NULL, NULL); diff --git a/arch/microblaze/kernel/unwind.c b/arch/microblaze/kernel/unwind.c new file mode 100644 index 000000000000..fefac5c33586 --- /dev/null +++ b/arch/microblaze/kernel/unwind.c @@ -0,0 +1,318 @@ +/* + * Backtrace support for Microblaze + * + * Copyright (C) 2010 Digital Design Corporation + * + * Based on arch/sh/kernel/cpu/sh5/unwind.c code which is: + * Copyright (C) 2004 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * 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. + */ + +/* #define DEBUG 1 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct stack_trace; + +/* + * On Microblaze, finding the previous stack frame is a little tricky. + * At this writing (3/2010), Microblaze does not support CONFIG_FRAME_POINTERS, + * and even if it did, gcc (4.1.2) does not store the frame pointer at + * a consistent offset within each frame. To determine frame size, it is + * necessary to search for the assembly instruction that creates or reclaims + * the frame and extract the size from it. + * + * Microblaze stores the stack pointer in r1, and creates a frame via + * + * addik r1, r1, -FRAME_SIZE + * + * The frame is reclaimed via + * + * addik r1, r1, FRAME_SIZE + * + * Frame creation occurs at or near the top of a function. + * Depending on the compiler, reclaim may occur at the end, or before + * a mid-function return. + * + * A stack frame is usually not created in a leaf function. + * + */ + +/** + * get_frame_size - Extract the stack adjustment from an + * "addik r1, r1, adjust" instruction + * @instr : Microblaze instruction + * + * Return - Number of stack bytes the instruction reserves or reclaims + */ +inline long get_frame_size(unsigned long instr) +{ + return abs((s16)(instr & 0xFFFF)); +} + +/** + * find_frame_creation - Search backward to find the instruction that creates + * the stack frame (hopefully, for the same function the + * initial PC is in). + * @pc : Program counter at which to begin the search + * + * Return - PC at which stack frame creation occurs + * NULL if this cannot be found, i.e. a leaf function + */ +static unsigned long *find_frame_creation(unsigned long *pc) +{ + int i; + + /* NOTE: Distance to search is arbitrary + * 250 works well for most things, + * 750 picks up things like tcp_recvmsg(), + * 1000 needed for fat_fill_super() + */ + for (i = 0; i < 1000; i++, pc--) { + unsigned long instr; + s16 frame_size; + + if (!kernel_text_address((unsigned long) pc)) + return NULL; + + instr = *pc; + + /* addik r1, r1, foo ? */ + if ((instr & 0xFFFF0000) != 0x30210000) + continue; /* No */ + + frame_size = get_frame_size(instr); + if ((frame_size < 8) || (frame_size & 3)) { + pr_debug(" Invalid frame size %d at 0x%p\n", + frame_size, pc); + return NULL; + } + + pr_debug(" Found frame creation at 0x%p, size %d\n", pc, + frame_size); + return pc; + } + + return NULL; +} + +/** + * lookup_prev_stack_frame - Find the stack frame of the previous function. + * @fp : Frame (stack) pointer for current function + * @pc : Program counter within current function + * @leaf_return : r15 value within current function. If the current function + * is a leaf, this is the caller's return address. + * @pprev_fp : On exit, set to frame (stack) pointer for previous function + * @pprev_pc : On exit, set to current function caller's return address + * + * Return - 0 on success, -EINVAL if the previous frame cannot be found + */ +static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc, + unsigned long leaf_return, + unsigned long *pprev_fp, + unsigned long *pprev_pc) +{ + unsigned long *prologue = NULL; + + /* _switch_to is a special leaf function */ + if (pc != (unsigned long) &_switch_to) + prologue = find_frame_creation((unsigned long *)pc); + + if (prologue) { + long frame_size = get_frame_size(*prologue); + + *pprev_fp = fp + frame_size; + *pprev_pc = *(unsigned long *)fp; + } else { + if (!leaf_return) + return -EINVAL; + *pprev_pc = leaf_return; + *pprev_fp = fp; + } + + /* NOTE: don't check kernel_text_address here, to allow display + * of userland return address + */ + return (!*pprev_pc || (*pprev_pc & 3)) ? -EINVAL : 0; +} + +static void microblaze_unwind_inner(struct task_struct *task, + unsigned long pc, unsigned long fp, + unsigned long leaf_return, + struct stack_trace *trace); + +/** + * unwind_trap - Unwind through a system trap, that stored previous state + * on the stack. + */ +#ifdef CONFIG_MMU +static inline void unwind_trap(struct task_struct *task, unsigned long pc, + unsigned long fp, struct stack_trace *trace) +{ + /* To be implemented */ +} +#else +static inline void unwind_trap(struct task_struct *task, unsigned long pc, + unsigned long fp, struct stack_trace *trace) +{ + const struct pt_regs *regs = (const struct pt_regs *) fp; + microblaze_unwind_inner(task, regs->pc, regs->r1, regs->r15, trace); +} +#endif + +/** + * microblaze_unwind_inner - Unwind the stack from the specified point + * @task : Task whose stack we are to unwind (may be NULL) + * @pc : Program counter from which we start unwinding + * @fp : Frame (stack) pointer from which we start unwinding + * @leaf_return : Value of r15 at pc. If the function is a leaf, this is + * the caller's return address. + * @trace : Where to store stack backtrace (PC values). + * NULL == print backtrace to kernel log + */ +void microblaze_unwind_inner(struct task_struct *task, + unsigned long pc, unsigned long fp, + unsigned long leaf_return, + struct stack_trace *trace) +{ + int ofs = 0; + + pr_debug(" Unwinding with PC=%p, FP=%p\n", (void *)pc, (void *)fp); + if (!pc || !fp || (pc & 3) || (fp & 3)) { + pr_debug(" Invalid state for unwind, aborting\n"); + return; + } + for (; pc != 0;) { + unsigned long next_fp, next_pc = 0; + unsigned long return_to = pc + 2 * sizeof(unsigned long); + const struct trap_handler_info *handler = + µblaze_trap_handlers; + + /* Is previous function the HW exception handler? */ + if ((return_to >= (unsigned long)&_hw_exception_handler) + &&(return_to < (unsigned long)&ex_handler_unhandled)) { + /* + * HW exception handler doesn't save all registers, + * so we open-code a special case of unwind_trap() + */ +#ifndef CONFIG_MMU + const struct pt_regs *regs = + (const struct pt_regs *) fp; +#endif + pr_info("HW EXCEPTION\n"); +#ifndef CONFIG_MMU + microblaze_unwind_inner(task, regs->r17 - 4, + fp + EX_HANDLER_STACK_SIZ, + regs->r15, trace); +#endif + return; + } + + /* Is previous function a trap handler? */ + for (; handler->start_addr; ++handler) { + if ((return_to >= handler->start_addr) + && (return_to <= handler->end_addr)) { + if (!trace) + pr_info("%s\n", handler->trap_name); + unwind_trap(task, pc, fp, trace); + return; + } + } + pc -= ofs; + + if (trace) { +#ifdef CONFIG_STACKTRACE + if (trace->skip > 0) + trace->skip--; + else + trace->entries[trace->nr_entries++] = pc; + + if (trace->nr_entries >= trace->max_entries) + break; +#endif + } else { + /* Have we reached userland? */ + if (unlikely(pc == task_pt_regs(task)->pc)) { + pr_info("[<%p>] PID %lu [%s]\n", + (void *) pc, + (unsigned long) task->pid, + task->comm); + break; + } else + print_ip_sym(pc); + } + + /* Stop when we reach anything not part of the kernel */ + if (!kernel_text_address(pc)) + break; + + if (lookup_prev_stack_frame(fp, pc, leaf_return, &next_fp, + &next_pc) == 0) { + ofs = sizeof(unsigned long); + pc = next_pc & ~3; + fp = next_fp; + leaf_return = 0; + } else { + pr_debug(" Failed to find previous stack frame\n"); + break; + } + + pr_debug(" Next PC=%p, next FP=%p\n", + (void *)next_pc, (void *)next_fp); + } +} + +/** + * microblaze_unwind - Stack unwinder for Microblaze (external entry point) + * @task : Task whose stack we are to unwind (NULL == current) + * @trace : Where to store stack backtrace (PC values). + * NULL == print backtrace to kernel log + */ +void microblaze_unwind(struct task_struct *task, struct stack_trace *trace) +{ + if (task) { + if (task == current) { + const struct pt_regs *regs = task_pt_regs(task); + microblaze_unwind_inner(task, regs->pc, regs->r1, + regs->r15, trace); + } else { + struct thread_info *thread_info = + (struct thread_info *)(task->stack); + const struct cpu_context *cpu_context = + &thread_info->cpu_context; + + microblaze_unwind_inner(task, + (unsigned long) &_switch_to, + cpu_context->r1, + cpu_context->r15, trace); + } + } else { + unsigned long pc, fp; + + __asm__ __volatile__ ("or %0, r1, r0" : "=r" (fp)); + + __asm__ __volatile__ ( + "brlid %0, 0f;" + "nop;" + "0:" + : "=r" (pc) + ); + + /* Since we are not a leaf function, use leaf_return = 0 */ + microblaze_unwind_inner(current, pc, fp, 0, trace); + } +} + -- cgit v1.2.3-55-g7522 From 6f34b08f58f5097bb408e188e09cda75e61ee513 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 16 Apr 2010 09:50:13 +0200 Subject: microblaze: Improve ftrace time measuring I had to comment sched_clock generic function because of broken toolchain. It is fine grain timing. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/setup.h | 2 -- arch/microblaze/kernel/timer.c | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h index 7f31394985e0..782b5c89248e 100644 --- a/arch/microblaze/include/asm/setup.h +++ b/arch/microblaze/include/asm/setup.h @@ -28,8 +28,6 @@ void disable_early_printk(void); void heartbeat(void); void setup_heartbeat(void); -unsigned long long sched_clock(void); - # ifdef CONFIG_MMU extern void mmu_reset(void); extern void early_console_reg_tlb_alloc(unsigned int addr); diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index ed61b2f17719..22e296eb871b 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -235,6 +235,12 @@ static int __init microblaze_clocksource_init(void) return 0; } +/* + * We have to protect accesses before timer initialization + * and return 0 for sched_clock function below. + */ +static int timer_initialized; + void __init time_init(void) { u32 irq, i = 0; @@ -289,4 +295,15 @@ void __init time_init(void) #endif microblaze_clocksource_init(); microblaze_clockevent_init(); + timer_initialized = 1; +} + +unsigned long long notrace sched_clock(void) +{ + if (timer_initialized) { + struct clocksource *cs = &clocksource_microblaze; + cycle_t cyc = cs->read(NULL); + return clocksource_cyc2ns(cyc, cs->mult, cs->shift); + } + return 0; } -- cgit v1.2.3-55-g7522 From d0f140e03e38dc553a0bb61611c15fcede671f23 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 10 Jun 2010 16:02:32 +0200 Subject: microblaze: Do not trace cpu_relax function IRQsoff tracer requires to protect cpu_idle function to get correct timing report. Signed-off-by: Michal Simek --- arch/microblaze/kernel/process.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c index 09bed44dfcd3..ba7c4b16ed35 100644 --- a/arch/microblaze/kernel/process.c +++ b/arch/microblaze/kernel/process.c @@ -76,8 +76,11 @@ __setup("hlt", hlt_setup); void default_idle(void) { if (likely(hlt_counter)) { - while (!need_resched()) - cpu_relax(); + local_irq_disable(); + stop_critical_timings(); + cpu_relax(); + start_critical_timings(); + local_irq_enable(); } else { clear_thread_flag(TIF_POLLING_NRFLAG); smp_mb__after_clear_bit(); -- cgit v1.2.3-55-g7522 From 75842abfd82d4b2ef9bd2ae632ca911e7559a194 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Mon, 12 Jul 2010 15:37:20 +0900 Subject: microblaze: remove unused HAVE_ARCH_PCI_SET_DMA_MASK HAVE_ARCH_PCI_SET_DMA_MASK was removed in 2.6.34 (no architecture has the own implementation of pci_set_dma_mask). Signed-off-by: FUJITA Tomonori Signed-off-by: Michal Simek --- arch/microblaze/include/asm/dma-mapping.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index 18b3731c8509..507389580709 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -79,12 +79,6 @@ static inline int dma_supported(struct device *dev, u64 mask) return ops->dma_supported(dev, mask); } -#ifdef CONFIG_PCI -/* We have our own implementation of pci_set_dma_mask() */ -#define HAVE_ARCH_PCI_SET_DMA_MASK - -#endif - static inline int dma_set_mask(struct device *dev, u64 dma_mask) { struct dma_map_ops *ops = get_dma_ops(dev); -- cgit v1.2.3-55-g7522 From 615748aefa61066e8e5ec9d27521f37037b4c1a7 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 19 Jul 2010 09:37:16 +0200 Subject: microblaze: Enable early printk only for uartlite Microblaze has support for early printk. The second serial driver (uart16550/8250) has no microblaze support for early printk. Signed-off-by: Michal Simek --- arch/microblaze/Kconfig.debug | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/microblaze/Kconfig.debug b/arch/microblaze/Kconfig.debug index 9dc708a7f700..e6e5e0da28c3 100644 --- a/arch/microblaze/Kconfig.debug +++ b/arch/microblaze/Kconfig.debug @@ -10,6 +10,7 @@ source "lib/Kconfig.debug" config EARLY_PRINTK bool "Early printk function for kernel" + depends on SERIAL_UARTLITE_CONSOLE default n help This option turns on/off early printk messages to console. -- cgit v1.2.3-55-g7522 From c8f77436d11190d0d9379f4fb2c6f22a155c8d8e Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 10 Jun 2010 16:04:05 +0200 Subject: microblaze: Decrease time shifting values Lower shifting values ensure that shifted 32bit counter value doesn't exceed 64bit cycle variable too fast. Signed-off-by: Michal Simek --- arch/microblaze/kernel/timer.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c index 22e296eb871b..b1380ae93ae1 100644 --- a/arch/microblaze/kernel/timer.c +++ b/arch/microblaze/kernel/timer.c @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef CONFIG_SELFMOD_TIMER #include @@ -135,7 +136,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode, static struct clock_event_device clockevent_microblaze_timer = { .name = "microblaze_clockevent", .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, - .shift = 24, + .shift = 8, .rating = 300, .set_next_event = microblaze_timer_set_next_event, .set_mode = microblaze_timer_set_mode, @@ -195,7 +196,7 @@ static cycle_t microblaze_cc_read(const struct cyclecounter *cc) static struct cyclecounter microblaze_cc = { .read = microblaze_cc_read, .mask = CLOCKSOURCE_MASK(32), - .shift = 24, + .shift = 8, }; int __init init_microblaze_timecounter(void) @@ -213,7 +214,7 @@ static struct clocksource clocksource_microblaze = { .rating = 300, .read = microblaze_read, .mask = CLOCKSOURCE_MASK(32), - .shift = 24, /* I can shift it */ + .shift = 8, /* I can shift it */ .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -302,7 +303,7 @@ unsigned long long notrace sched_clock(void) { if (timer_initialized) { struct clocksource *cs = &clocksource_microblaze; - cycle_t cyc = cs->read(NULL); + cycle_t cyc = cnt32_to_63(cs->read(NULL)); return clocksource_cyc2ns(cyc, cs->mult, cs->shift); } return 0; -- cgit v1.2.3-55-g7522 From aee04d76d2bfd3539ae7e06c15ee52317db78499 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 27 Jul 2010 12:53:15 +0200 Subject: microblaze: Fix number of pvr regs Microblaze has only 11 pvr regs according manual. Signed-off-by: Michal Simek --- arch/microblaze/include/asm/pvr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/microblaze/include/asm/pvr.h b/arch/microblaze/include/asm/pvr.h index e38abc7714b6..9578666e98ba 100644 --- a/arch/microblaze/include/asm/pvr.h +++ b/arch/microblaze/include/asm/pvr.h @@ -16,7 +16,7 @@ #define PVR_MSR_BIT 0x400 struct pvr_s { - unsigned pvr[16]; + unsigned pvr[12]; }; /* The following taken from Xilinx's standalone BSP pvr.h */ -- cgit v1.2.3-55-g7522 From 61b403af8b0af4225802da60406045faf0e5d612 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 28 Jul 2010 07:58:06 +0200 Subject: microblaze: Cleanup boot/Makefile Remove spaces and use tabs instead. Signed-off-by: Michal Simek --- arch/microblaze/boot/Makefile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 57f50c2371c6..745a7f145fbe 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -35,13 +35,14 @@ quiet_cmd_cp = CP $< $@$2 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) quiet_cmd_strip = STRIP $@ - cmd_strip = $(STRIP) -K _start -K _end -K __log_buf -K _fdt_start vmlinux -o $@ + cmd_strip = $(STRIP) -K _start -K _end -K __log_buf \ + -K _fdt_start vmlinux -o $@ quiet_cmd_uimage = UIMAGE $@.ub - cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \ - -C none -n 'Linux-$(KERNELRELEASE)' \ - -a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \ - -d $@ $@.ub + cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \ + -C none -n 'Linux-$(KERNELRELEASE)' \ + -a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \ + -d $@ $@.ub $(obj)/simpleImage.%: vmlinux FORCE $(call if_changed,cp,.unstrip) -- cgit v1.2.3-55-g7522 From ca28b510163a55df6260652056bfc60c4cf8aca1 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 28 Jul 2010 09:29:11 +0200 Subject: microblaze: Do not use _start in vmlinux _start symbol stores physical address where kernel is. Gdb uses this symbol for their purpose that's why we have to rename it. Signed-off-by: Michal Simek --- arch/microblaze/boot/Makefile | 2 +- arch/microblaze/kernel/vmlinux.lds.S | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile index 745a7f145fbe..be01d78750d9 100644 --- a/arch/microblaze/boot/Makefile +++ b/arch/microblaze/boot/Makefile @@ -35,7 +35,7 @@ quiet_cmd_cp = CP $< $@$2 cmd_cp = cat $< >$@$2 || (rm -f $@ && echo false) quiet_cmd_strip = STRIP $@ - cmd_strip = $(STRIP) -K _start -K _end -K __log_buf \ + cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \ -K _fdt_start vmlinux -o $@ quiet_cmd_uimage = UIMAGE $@.ub diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S index b0de1a6b5513..a09f2962fbec 100644 --- a/arch/microblaze/kernel/vmlinux.lds.S +++ b/arch/microblaze/kernel/vmlinux.lds.S @@ -10,7 +10,7 @@ OUTPUT_FORMAT("elf32-microblaze", "elf32-microblaze", "elf32-microblaze") OUTPUT_ARCH(microblaze) -ENTRY(_start) +ENTRY(microblaze_start) #include #include @@ -20,7 +20,7 @@ jiffies = jiffies_64 + 4; SECTIONS { . = CONFIG_KERNEL_START; - _start = CONFIG_KERNEL_BASE_ADDR; + microblaze_start = CONFIG_KERNEL_BASE_ADDR; .text : AT(ADDR(.text) - LOAD_OFFSET) { _text = . ; _stext = . ; -- cgit v1.2.3-55-g7522 From a4a94dbf20fa2e119cf89615ef21230f9b2f8913 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 13:15:53 +0200 Subject: microblaze: Fix VM_ON and VM_OFF macros Jump behind macro. We don't want to execute nop instruction again. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 7a19d8910e3b..d40a59f9db4b 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -180,15 +180,17 @@ /* turn on virtual protected mode save */ #define VM_ON \ - set_ums; \ + set_ums; \ rted r0, 2f; \ -2: nop; + nop; \ +2: /* turn off virtual protected mode save and user mode save*/ #define VM_OFF \ - clear_vms_ums; \ + clear_vms_ums; \ rted r0, TOPHYS(1f); \ -1: nop; + nop; \ +1: #define SAVE_REGS \ swi r2, r1, PTO+PT_R2; /* Save SDA */ \ -- cgit v1.2.3-55-g7522 From 36f6095419b100479bd3ffabcafe4dac8d918734 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 13:27:43 +0200 Subject: microblaze: Save and restore r3/r4 in SAVE/RESTORE_REGS macros Save and restore R3/R4 registers in macros. This change help to cleanup entry.S. In ret_from_trap function we are saving returning value from syscall to pt_regs on stack that's why we don't need to save and restore these values before kernel functions (schedule, do_signal). Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 48 +++++++----------------------------------- 1 file changed, 8 insertions(+), 40 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index d40a59f9db4b..8f90ce7ecb6c 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -194,6 +194,8 @@ #define SAVE_REGS \ swi r2, r1, PTO+PT_R2; /* Save SDA */ \ + swi r3, r1, PTO+PT_R3; \ + swi r4, r1, PTO+PT_R4; \ swi r5, r1, PTO+PT_R5; \ swi r6, r1, PTO+PT_R6; \ swi r7, r1, PTO+PT_R7; \ @@ -228,6 +230,8 @@ mts rmsr , r11; \ nop; \ lwi r2, r1, PTO+PT_R2; /* restore SDA */ \ + lwi r3, r1, PTO+PT_R3; \ + lwi r4, r1, PTO+PT_R4; \ lwi r5, r1, PTO+PT_R5; \ lwi r6, r1, PTO+PT_R6; \ lwi r7, r1, PTO+PT_R7; \ @@ -379,13 +383,12 @@ C_ENTRY(_user_exception): /* We re-enable BIP bit before state restore */ C_ENTRY(ret_from_trap): set_bip; /* Ints masked for state restore*/ - lwi r11, r1, PTO+PT_MODE; -/* See if returning to kernel mode, if so, skip resched &c. */ - bnei r11, 2f; - swi r3, r1, PTO + PT_R3 swi r4, r1, PTO + PT_R4 + lwi r11, r1, PTO+PT_MODE; +/* See if returning to kernel mode, if so, skip resched &c. */ + bnei r11, 2f; /* We're returning to user mode, so check for various conditions that * trigger rescheduling. */ /* FIXME: Restructure all these flag checks. */ @@ -422,9 +425,6 @@ C_ENTRY(ret_from_trap): /* Finally, return to user state. */ 1: - lwi r3, r1, PTO + PT_R3; /* restore syscall result */ - lwi r4, r1, PTO + PT_R4; - swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ VM_OFF; @@ -522,10 +522,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ \ lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ - /* store return registers separately because \ - * this macros is use for others exceptions */ \ - swi r3, r1, PTO + PT_R3; \ - swi r4, r1, PTO + PT_R4; \ SAVE_REGS \ /* PC, before IRQ/trap - this is one instruction above */ \ swi r17, r1, PTO+PT_PC; \ @@ -543,10 +539,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): tophys(r1,r1); \ \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ - /* store return registers separately because this macros \ - * is use for others exceptions */ \ - swi r3, r1, PTO + PT_R3; \ - swi r4, r1, PTO + PT_R4; \ SAVE_REGS \ /* PC, before IRQ/trap - this is one instruction above FIXME*/ \ swi r17, r1, PTO+PT_PC; \ @@ -689,9 +681,7 @@ C_ENTRY(ret_from_exc): * traps), but signal handlers may want to examine or change the * complete register state. Here we save anything not saved by * the normal entry sequence, so that it may be safely restored - * (in a possibly modified form) after do_signal returns. - * store return registers separately because this macros is use - * for others exceptions */ + * (in a possibly modified form) after do_signal returns. */ la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 0; /* Arg 3: int in_syscall */ bralid r15, do_signal; /* Handle any signals */ @@ -703,8 +693,6 @@ C_ENTRY(ret_from_exc): VM_OFF; tophys(r1,r1); - lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ - lwi r4, r1, PTO+PT_R4; RESTORE_REGS; addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ @@ -713,8 +701,6 @@ C_ENTRY(ret_from_exc): /* Return to kernel state. */ 2: VM_OFF; tophys(r1,r1); - lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ - lwi r4, r1, PTO+PT_R4; RESTORE_REGS; addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ @@ -753,10 +739,6 @@ C_ENTRY(_interrupt): /* save registers */ /* MS: Make room on the stack -> activation record */ addik r1, r1, -STATE_SAVE_SIZE; -/* MS: store return registers separately because - * this macros is use for others exceptions */ - swi r3, r1, PTO + PT_R3; - swi r4, r1, PTO + PT_R4; SAVE_REGS /* MS: store mode */ addi r11, r0, 1; /* MS: Was in kernel-mode. */ @@ -776,8 +758,6 @@ C_ENTRY(_interrupt): tophys(r1,r1); /* save registers */ addik r1, r1, -STATE_SAVE_SIZE; - swi r3, r1, PTO+PT_R3; - swi r4, r1, PTO+PT_R4; SAVE_REGS /* calculate mode */ swi r0, r1, PTO + PT_MODE; @@ -829,8 +809,6 @@ no_intr_resched: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); VM_OFF; tophys(r1,r1); - lwi r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */ - lwi r4, r1, PTO + PT_R4; RESTORE_REGS addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */ lwi r1, r1, PT_R1 - PT_SIZE; @@ -859,8 +837,6 @@ restore: #endif VM_OFF /* MS: turn off MMU */ tophys(r1,r1) - lwi r3, r1, PTO + PT_R3; /* MS: restore saved r3, r4 registers */ - lwi r4, r1, PTO + PT_R4; RESTORE_REGS addik r1, r1, STATE_SAVE_SIZE /* MS: Clean up stack space. */ tovirt(r1,r1); @@ -893,8 +869,6 @@ C_ENTRY(_debug_exception): lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ - swi r3, r1, PTO + PT_R3; - swi r4, r1, PTO + PT_R4; SAVE_REGS; addi r11, r0, 1; /* Was in kernel-mode. */ @@ -910,8 +884,6 @@ C_ENTRY(_debug_exception): tophys(r1,r1); addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ - swi r3, r1, PTO + PT_R3; - swi r4, r1, PTO + PT_R4; SAVE_REGS; swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ @@ -979,8 +951,6 @@ dbtrap_call: rtbd r11, 0; VM_OFF; tophys(r1,r1); - lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ - lwi r4, r1, PTO+PT_R4; RESTORE_REGS addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ @@ -992,8 +962,6 @@ dbtrap_call: rtbd r11, 0; /* Return to kernel state. */ 2: VM_OFF; tophys(r1,r1); - lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ - lwi r4, r1, PTO+PT_R4; RESTORE_REGS addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ -- cgit v1.2.3-55-g7522 From 3fbd93e58e0f3589720798b7c8992a25e4a2d3a4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 13:51:50 +0200 Subject: microblaze: Optimize clear_vms_ums macro We can save two instruction when MSR_VMS and MSR_UMS are setup in one instruction. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 8f90ce7ecb6c..f5fe220954b0 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -92,9 +92,7 @@ .endm .macro clear_vms_ums - msrclr r11, MSR_VMS - nop - msrclr r11, MSR_UMS + msrclr r11, MSR_VMS | MSR_UMS nop .endm #else -- cgit v1.2.3-55-g7522 From 5c0d72b1b35fd0dad7dd70a114df068eadcc1b16 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 14:00:12 +0200 Subject: microblaze: Remove PER_CPU(KM) variable There is a way howto remove Kernel Mode variable. It is easier to parse UMS bit in MSR to find out if I come from kernel or user space. Loading MSR content should be in one cycle and loading PER_CPU variable depends on memory state. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 43 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index f5fe220954b0..9a98f70e4c30 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -275,9 +275,12 @@ C_ENTRY(_user_exception): addi r14, r14, 4 /* return address is 4 byte after call */ swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ - lwi r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/ - beqi r11, 1f; /* Jump ahead if coming from user */ -/* Kernel-mode state save. */ + mfs r11, rmsr + nop + andi r11, r11, MSR_UMS + bnei r11, 1f + +/* Kernel-mode state save - kernel execve */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ tophys(r1,r11); swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ @@ -307,8 +310,6 @@ C_ENTRY(_user_exception): swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ - addi r11, r0, 1; - swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode. */ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* Save away the syscall number. */ swi r12, r1, PTO+PT_R0; @@ -423,7 +424,6 @@ C_ENTRY(ret_from_trap): /* Finally, return to user state. */ 1: - swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ VM_OFF; tophys(r1,r1); @@ -511,8 +511,10 @@ C_ENTRY(sys_rt_sigreturn_wrapper): enable_irq; \ set_ee; \ /* See if already in kernel mode.*/ \ - lwi r11, r0, TOPHYS(PER_CPU(KM)); \ - beqi r11, 1f; /* Jump ahead if coming from user */\ + mfs r11, rmsr; \ + nop; \ + andi r11, r11, MSR_UMS; \ + bnei r11, 1f; \ /* Kernel-mode state save. */ \ /* Reload kernel stack-ptr. */ \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ @@ -544,8 +546,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ - addi r11, r0, 1; \ - swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode.*/\ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); \ /* Save away the syscall number. */ \ swi r0, r1, PTO+PT_R0; \ @@ -686,7 +686,7 @@ C_ENTRY(ret_from_exc): add r6, r0, r0; /* Arg 2: sigset_t *oldset */ /* Finally, return to user state. */ -1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ +1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ VM_OFF; tophys(r1,r1); @@ -724,8 +724,10 @@ C_ENTRY(_interrupt): swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) swi r11, r0, TOPHYS(PER_CPU(R11_SAVE)); /* MS: See if already in kernel mode. */ - lwi r11, r0, TOPHYS(PER_CPU(KM)); - beqi r11, 1f; /* MS: Jump ahead if coming from user */ + mfs r11, rmsr + nop + andi r11, r11, MSR_UMS + bnei r11, 1f /* Kernel-mode state save. */ or r11, r1, r0 @@ -761,10 +763,6 @@ C_ENTRY(_interrupt): swi r0, r1, PTO + PT_MODE; lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; - /* setup kernel mode to KM */ - addi r11, r0, 1; - swi r11, r0, TOPHYS(PER_CPU(KM)); - 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); swi r0, r1, PTO + PT_R0; @@ -803,7 +801,6 @@ ret_from_irq: no_intr_resched: /* Disable interrupts, we are now committed to the state restore */ disable_irq - swi r0, r0, PER_CPU(KM); /* MS: Now officially in user state. */ swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); VM_OFF; tophys(r1,r1); @@ -858,8 +855,10 @@ C_ENTRY(_debug_exception): set_bip; /*equalize initial state for all possible entries*/ clear_eip; enable_irq; - lwi r11, r0, TOPHYS(PER_CPU(KM));/* See if already in kernel mode.*/ - beqi r11, 1f; /* Jump ahead if coming from user */ + mfs r11, rmsr + nop + andi r11, r11, MSR_UMS + bnei r11, 1f /* Kernel-mode state save. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ tophys(r1,r11); @@ -887,8 +886,6 @@ C_ENTRY(_debug_exception): swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ - addi r11, r0, 1; - swi r11, r0, TOPHYS(PER_CPU(KM)); /* Now we're in kernel-mode. */ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* Save away the syscall number. */ swi r0, r1, PTO+PT_R0; @@ -944,7 +941,7 @@ dbtrap_call: rtbd r11, 0; /* Finally, return to user state. */ -1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */ +1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ VM_OFF; tophys(r1,r1); -- cgit v1.2.3-55-g7522 From 96014cc39bffe04429bcd143aa7bbde81f659ee4 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 14:05:43 +0200 Subject: microblaze: Move BIP setup to the end of ret_from_trap/ret_from_exc We don't need to protect by BIP whole ret_from_trap/ret_from_exc code. Only restoring from user/hw exception should be covered. If BIP is setup, IRQ can't occur. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 9a98f70e4c30..4a6cb1d68dd4 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -381,7 +381,6 @@ C_ENTRY(_user_exception): /* 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*/ swi r3, r1, PTO + PT_R3 swi r4, r1, PTO + PT_R4 @@ -423,7 +422,7 @@ C_ENTRY(ret_from_trap): add r6, r0, r0; /* Arg 2: sigset_t *oldset */ /* Finally, return to user state. */ -1: +1: set_bip; /* Ints masked for state restore */ swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ VM_OFF; tophys(r1,r1); @@ -433,7 +432,8 @@ C_ENTRY(ret_from_trap): bri 6f; /* Return to kernel state. */ -2: VM_OFF; +2: set_bip; /* Ints masked for state restore */ + VM_OFF; tophys(r1,r1); RESTORE_REGS; addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ @@ -647,7 +647,6 @@ C_ENTRY(page_fault_instr_trap): /* Entry point used to return from an exception. */ C_ENTRY(ret_from_exc): - set_bip; /* Ints masked for state restore*/ lwi r11, r1, PTO+PT_MODE; bnei r11, 2f; /* See if returning to kernel mode, */ /* ... if so, skip resched &c. */ @@ -686,7 +685,7 @@ C_ENTRY(ret_from_exc): add r6, r0, r0; /* Arg 2: sigset_t *oldset */ /* Finally, return to user state. */ -1: +1: set_bip; /* Ints masked for state restore */ swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ VM_OFF; tophys(r1,r1); @@ -697,7 +696,8 @@ C_ENTRY(ret_from_exc): lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer. */ bri 6f; /* Return to kernel state. */ -2: VM_OFF; +2: set_bip; /* Ints masked for state restore */ + VM_OFF; tophys(r1,r1); RESTORE_REGS; addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ -- cgit v1.2.3-55-g7522 From 63708f635c1702ac512626d7afe558de2b18554a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 14:13:09 +0200 Subject: microblaze: Move stack backup to SAVE_STATE macro Remove code duplicity and move it to SAVE_STATE macro. There is no impact on performance. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 4a6cb1d68dd4..766ff568660c 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -505,6 +505,7 @@ C_ENTRY(sys_rt_sigreturn_wrapper): */ #define SAVE_STATE \ + swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ \ set_bip; /*equalize initial state for all possible entries*/\ clear_eip; \ @@ -552,7 +553,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): tovirt(r1,r1) C_ENTRY(full_exception_trap): - swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ /* adjust exception address for privileged instruction * for finding where is it */ addik r17, r17, -4 @@ -584,7 +584,6 @@ C_ENTRY(full_exception_trap): * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S" */ C_ENTRY(unaligned_data_trap): - swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ SAVE_STATE /* Save registers.*/ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ la r15, r0, ret_from_exc-8 @@ -617,7 +616,6 @@ C_ENTRY(unaligned_data_trap): */ /* data and intruction trap - which is choose is resolved int fault.c */ C_ENTRY(page_fault_data_trap): - swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ SAVE_STATE /* Save registers.*/ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ la r15, r0, ret_from_exc-8 @@ -632,7 +630,6 @@ C_ENTRY(page_fault_data_trap): nop; C_ENTRY(page_fault_instr_trap): - swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ SAVE_STATE /* Save registers.*/ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ la r15, r0, ret_from_exc-8 -- cgit v1.2.3-55-g7522 From be304350ddba60813f8703c481380752ebfd93f9 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 14:15:23 +0200 Subject: microblaze: remove enable_irq from SAVE_STATE macro SAVE_STATE macro is used in hw exceptions high level handling functions. Hw exception doesn't disable IRQ that's why we don't need to reenable it. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 766ff568660c..ed9a331da24f 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -509,7 +509,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ \ set_bip; /*equalize initial state for all possible entries*/\ clear_eip; \ - enable_irq; \ set_ee; \ /* See if already in kernel mode.*/ \ mfs r11, rmsr; \ -- cgit v1.2.3-55-g7522 From b9ea77e2d37013a4e66c9dad2e629998ff300608 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 28 Jul 2010 12:40:02 +0200 Subject: microblaze: trivial: Use la insted of addik la is translated to addik by toolchain. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 64 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index ed9a331da24f..3fee82d6e9a2 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -368,7 +368,7 @@ C_ENTRY(_user_exception): # 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 + addi r15, r0, ret_from_trap-8 bra r12 /* The syscall number is invalid, return an error. */ @@ -416,7 +416,7 @@ C_ENTRY(ret_from_trap): andi r11, r11, _TIF_SIGPENDING; beqi r11, 1f; /* Signals to handle, handle them */ - la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 1; /* Arg 3: int in_syscall */ bralid r15, do_signal; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ @@ -450,7 +450,7 @@ TRAP_return: /* Make global symbol for debugging */ C_ENTRY(sys_fork_wrapper): addi r5, r0, SIGCHLD /* Arg 0: flags */ lwi r6, r1, PTO+PT_R1 /* Arg 1: child SP (use parent's) */ - la r7, r1, PTO /* Arg 2: parent context */ + addik r7, r1, PTO /* Arg 2: parent context */ add r8. r0, r0 /* Arg 3: (unused) */ add r9, r0, r0; /* Arg 4: (unused) */ add r10, r0, r0; /* Arg 5: (unused) */ @@ -472,27 +472,27 @@ C_ENTRY(ret_from_fork): C_ENTRY(sys_vfork): brid microblaze_vfork /* Do real work (tail-call) */ - la r5, r1, PTO + addik r5, r1, PTO C_ENTRY(sys_clone): bnei r6, 1f; /* See if child SP arg (arg 1) is 0. */ lwi r6, r1, PTO + PT_R1; /* If so, use paret's stack ptr */ -1: add r10, r0, r9; /* Arg 6: (child_tidptr) */ - add r9, r0, r8; /* Arg 5: (parent_tidptr) */ - add r8, r0, r7; /* Arg 4: (stack_size) */ - la r7, r1, PTO; /* Arg 3: pt_regs */ - brid do_fork /* Do real work (tail-call) */ - nop +1: addik r7, r1, PTO; /* Arg 2: parent context */ + add r8, r0, r0; /* Arg 3: (unused) */ + add r9, r0, r0; /* Arg 4: (unused) */ + add r10, r0, r0; /* Arg 5: (unused) */ + brid do_fork /* Do real work (tail-call) */ + nop; C_ENTRY(sys_execve): - la r8, r1, PTO; /* add user context as 4th arg */ + addik r8, r1, PTO; /* add user context as 4th arg */ brid microblaze_execve; /* Do real work (tail-call).*/ nop; C_ENTRY(sys_rt_sigreturn_wrapper): swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ swi r4, r1, PTO+PT_R4; - la r5, r1, PTO; /* add user context as 1st arg */ + addik r5, r1, PTO; /* add user context as 1st arg */ brlid r15, sys_rt_sigreturn /* Do real work */ nop; lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ @@ -559,15 +559,15 @@ C_ENTRY(full_exception_trap): /* FIXME this can be store directly in PT_ESR reg. * I tested it but there is a fault */ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ - la r15, r0, ret_from_exc - 8 - la r5, r1, PTO /* parameter struct pt_regs * regs */ + addik r15, r0, ret_from_exc - 8 + addik r5, r1, PTO /* parameter struct pt_regs * regs */ mfs r6, resr nop mfs r7, rfsr; /* save FSR */ nop mts rfsr, r0; /* Clear sticky fsr */ nop - la r12, r0, full_exception + addik r12, r0, full_exception set_vms; rtbd r12, 0; nop; @@ -585,13 +585,13 @@ C_ENTRY(full_exception_trap): C_ENTRY(unaligned_data_trap): SAVE_STATE /* Save registers.*/ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ - la r15, r0, ret_from_exc-8 + addik r15, r0, ret_from_exc-8 mfs r3, resr /* ESR */ nop mfs r4, rear /* EAR */ nop - la r7, r1, PTO /* parameter struct pt_regs * regs */ - la r12, r0, _unaligned_data_exception + addik r7, r1, PTO /* parameter struct pt_regs * regs */ + addik r12, r0, _unaligned_data_exception set_vms; rtbd r12, 0; /* interrupts enabled */ nop; @@ -617,13 +617,13 @@ C_ENTRY(unaligned_data_trap): C_ENTRY(page_fault_data_trap): SAVE_STATE /* Save registers.*/ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ - la r15, r0, ret_from_exc-8 - la r5, r1, PTO /* parameter struct pt_regs * regs */ + addik r15, r0, ret_from_exc-8 + addik r5, r1, PTO /* parameter struct pt_regs * regs */ mfs r6, rear /* parameter unsigned long address */ nop mfs r7, resr /* parameter unsigned long error_code */ nop - la r12, r0, do_page_fault + addik r12, r0, do_page_fault set_vms; rtbd r12, 0; /* interrupts enabled */ nop; @@ -631,12 +631,12 @@ C_ENTRY(page_fault_data_trap): C_ENTRY(page_fault_instr_trap): SAVE_STATE /* Save registers.*/ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ - la r15, r0, ret_from_exc-8 - la r5, r1, PTO /* parameter struct pt_regs * regs */ + addik r15, r0, ret_from_exc-8 + addik r5, r1, PTO /* parameter struct pt_regs * regs */ mfs r6, rear /* parameter unsigned long address */ nop ori r7, r0, 0 /* parameter unsigned long error_code */ - la r12, r0, do_page_fault + addik r12, r0, do_page_fault set_vms; rtbd r12, 0; /* interrupts enabled */ nop; @@ -675,7 +675,7 @@ C_ENTRY(ret_from_exc): * complete register state. Here we save anything not saved by * the normal entry sequence, so that it may be safely restored * (in a possibly modified form) after do_signal returns. */ - la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 0; /* Arg 3: int in_syscall */ bralid r15, do_signal; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ @@ -763,10 +763,10 @@ C_ENTRY(_interrupt): lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); swi r0, r1, PTO + PT_R0; tovirt(r1,r1) - la r5, r1, PTO; + addik r5, r1, PTO; set_vms; - la r11, r0, do_IRQ; - la r15, r0, irq_call; + addik r11, r0, do_IRQ; + addik r15, r0, irq_call; irq_call:rtbd r11, 0; nop; @@ -789,7 +789,7 @@ ret_from_irq: beqid r11, no_intr_resched /* Handle a signal return; Pending signals should be in r18. */ addi r7, r0, 0; /* Arg 3: int in_syscall */ - la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ bralid r15, do_signal; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ @@ -892,8 +892,8 @@ C_ENTRY(_debug_exception): addk r7, r0, r0 /* 3rd param zero */ set_vms; - la r11, r0, send_sig; - la r15, r0, dbtrap_call; + addik r11, r0, send_sig; + addik r15, r0, dbtrap_call; dbtrap_call: rtbd r11, 0; nop; @@ -930,7 +930,7 @@ dbtrap_call: rtbd r11, 0; the normal entry sequence, so that it may be safely restored (in a possibly modified form) after do_signal returns. */ - la r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ + addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 0; /* Arg 3: int in_syscall */ bralid r15, do_signal; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ -- cgit v1.2.3-55-g7522 From 8b110d157c82f3818fc578b633f0cf7ace9efc22 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 17 Jun 2010 16:03:05 +0200 Subject: microblaze: Optimize SAVE_STATE macro It is necessary to setup BIP and EE and clear EIP only for unaligned exception handler. The rest of hw exception handlers don't require it. HW exception occured and we are not in virtual mode. That's why we can do operations protected by EIP. Interrupt, next hw exception or syscall can't occur. EIP is cleared by rted. This change speedup page_fault hw exception handler which is critical path. There is also necessary to save R11 content before flag setup for unaligned exception. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 3fee82d6e9a2..042657165184 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -507,9 +507,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): #define SAVE_STATE \ swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ \ - set_bip; /*equalize initial state for all possible entries*/\ - clear_eip; \ - set_ee; \ /* See if already in kernel mode.*/ \ mfs r11, rmsr; \ nop; \ @@ -569,7 +566,7 @@ C_ENTRY(full_exception_trap): nop addik r12, r0, full_exception set_vms; - rtbd r12, 0; + rted r12, 0; nop; /* @@ -583,6 +580,17 @@ C_ENTRY(full_exception_trap): * The assembler routine is in "arch/microblaze/kernel/hw_exception_handler.S" */ C_ENTRY(unaligned_data_trap): + /* MS: I have to save r11 value and then restore it because + * set_bit, clear_eip, set_ee use r11 as temp register if MSR + * instructions are not used. We don't need to do if MSR instructions + * are used and they use r0 instead of r11. + * I am using ENTRY_SP which should be primary used only for stack + * pointer saving. */ + swi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); + set_bip; /* equalize initial state for all possible entries */ + clear_eip; + set_ee; + lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); SAVE_STATE /* Save registers.*/ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 @@ -625,7 +633,7 @@ C_ENTRY(page_fault_data_trap): nop addik r12, r0, do_page_fault set_vms; - rtbd r12, 0; /* interrupts enabled */ + rted r12, 0; /* interrupts enabled */ nop; C_ENTRY(page_fault_instr_trap): @@ -638,7 +646,7 @@ C_ENTRY(page_fault_instr_trap): ori r7, r0, 0 /* parameter unsigned long error_code */ addik r12, r0, do_page_fault set_vms; - rtbd r12, 0; /* interrupts enabled */ + rted r12, 0; /* interrupts enabled */ nop; /* Entry point used to return from an exception. */ -- cgit v1.2.3-55-g7522 From 06b2864038517905752bdacd95f1f265ef780f3b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 15:25:24 +0200 Subject: microblaze: Simplify _debug_exception function Keep together all arguments for send_sig function. Move returning address to delay slot which is executed. Remove additional send_sig loading. I am using IMM part of rtbd instruction with r0. old solution: addik r11, r0, send_sig rtbd r11, 0 nop new solution: rtbd r0, send_sig nop There is one instruction saving. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 042657165184..04267ca949f0 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -895,15 +895,12 @@ C_ENTRY(_debug_exception): swi r0, r1, PTO+PT_R0; tovirt(r1,r1) + set_vms; addi r5, r0, SIGTRAP /* send the trap signal */ add r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */ addk r7, r0, r0 /* 3rd param zero */ - - set_vms; - addik r11, r0, send_sig; +dbtrap_call: rtbd r0, send_sig; addik r15, r0, dbtrap_call; -dbtrap_call: rtbd r11, 0; - nop; set_bip; /* Ints masked for state restore*/ lwi r11, r1, PTO+PT_MODE; -- cgit v1.2.3-55-g7522 From 0388107dd50eaa52c028312a7cc20177cb95a943 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 15:32:52 +0200 Subject: microblaze: Do not setup BIP in _debug_exception BIP is already setup. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 3 --- 1 file changed, 3 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 04267ca949f0..1f4028049449 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -856,9 +856,6 @@ C_ENTRY(_debug_exception): swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ - set_bip; /*equalize initial state for all possible entries*/ - clear_eip; - enable_irq; mfs r11, rmsr nop andi r11, r11, MSR_UMS -- cgit v1.2.3-55-g7522 From 653e447e113a19fcb54d454b9f5a3bff9979729f Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 14:51:45 +0200 Subject: microblaze: Completely remove working with R11 register We don't need to save R11 register. There is easy way to use only R1 which is saved and restore later. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 62 ++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 1f4028049449..9b8e072d828d 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -273,18 +273,15 @@ C_ENTRY(_user_exception): swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ addi r14, r14, 4 /* return address is 4 byte after call */ - swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ - mfs r11, rmsr + mfs r1, rmsr nop - andi r11, r11, MSR_UMS - bnei r11, 1f + andi r1, r1, MSR_UMS + bnei r1, 1f /* Kernel-mode state save - kernel execve */ - lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ - tophys(r1,r11); - swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ - lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ + lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ + tophys(r1,r1); addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS @@ -296,7 +293,6 @@ C_ENTRY(_user_exception): /* User-mode state save. */ 1: - lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ tophys(r1,r1); lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ @@ -506,18 +502,15 @@ C_ENTRY(sys_rt_sigreturn_wrapper): #define SAVE_STATE \ swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ - swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ \ /* See if already in kernel mode.*/ \ - mfs r11, rmsr; \ + mfs r1, rmsr; \ nop; \ - andi r11, r11, MSR_UMS; \ - bnei r11, 1f; \ + andi r1, r1, MSR_UMS; \ + bnei r1, 1f; \ /* Kernel-mode state save. */ \ /* Reload kernel stack-ptr. */ \ - lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ - tophys(r1,r11); \ - swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ \ - lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\ + lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ + tophys(r1,r1); \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ /* PC, before IRQ/trap - this is one instruction above */ \ @@ -528,13 +521,11 @@ C_ENTRY(sys_rt_sigreturn_wrapper): brid 2f; \ nop; /* Fill delay slot */ \ 1: /* User-mode state save. */ \ - lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */\ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ tophys(r1,r1); \ lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \ addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */\ tophys(r1,r1); \ - \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ /* PC, before IRQ/trap - this is one instruction above FIXME*/ \ @@ -726,20 +717,15 @@ C_ENTRY(_interrupt): /* MS: we are in physical address */ /* Save registers, switch to proper stack, convert SP to virtual.*/ swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) - swi r11, r0, TOPHYS(PER_CPU(R11_SAVE)); /* MS: See if already in kernel mode. */ - mfs r11, rmsr + mfs r1, rmsr nop - andi r11, r11, MSR_UMS - bnei r11, 1f + andi r1, r1, MSR_UMS + bnei r1, 1f /* Kernel-mode state save. */ - or r11, r1, r0 - tophys(r1,r11); /* MS: I have in r1 physical address where stack is */ -/* MS: Save original SP - position PT_R1 to next stack frame 4 *1 - 152*/ - swi r11, r1, (PT_R1 - PT_SIZE); -/* MS: restore r11 because of saving in SAVE_REGS */ - lwi r11, r0, TOPHYS(PER_CPU(R11_SAVE)); + lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) + tophys(r1,r1); /* MS: I have in r1 physical address where stack is */ /* save registers */ /* MS: Make room on the stack -> activation record */ addik r1, r1, -STATE_SAVE_SIZE; @@ -752,8 +738,6 @@ C_ENTRY(_interrupt): 1: /* User-mode state save. */ -/* MS: restore r11 -> FIXME move before SAVE_REG */ - lwi r11, r0, TOPHYS(PER_CPU(R11_SAVE)); /* MS: get the saved current */ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); tophys(r1,r1); @@ -855,16 +839,13 @@ C_ENTRY(_debug_exception): /* BIP bit is set on entry, no interrupts can occur */ swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) - swi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* Save r11 */ - mfs r11, rmsr + mfs r1, rmsr nop - andi r11, r11, MSR_UMS - bnei r11, 1f + andi r1, r1, MSR_UMS + bnei r1, 1f /* Kernel-mode state save. */ - lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ - tophys(r1,r11); - swi r11, r1, (PT_R1-PT_SIZE); /* Save original SP. */ - lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ + lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ + tophys(r1,r1); addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS; @@ -874,7 +855,6 @@ C_ENTRY(_debug_exception): brid 2f; nop; /* Fill delay slot */ 1: /* User-mode state save. */ - lwi r11, r0, TOPHYS(r0_ram + PTO + PT_R11); /* restore r11 */ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ tophys(r1,r1); lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ @@ -887,7 +867,7 @@ C_ENTRY(_debug_exception): swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ -2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); +2: /* Save away the syscall number. */ swi r0, r1, PTO+PT_R0; tovirt(r1,r1) -- cgit v1.2.3-55-g7522 From 40eb0dc456dc3dd3f01da94e1f36085e956f20cc Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 16:04:00 +0200 Subject: microblaze: Remove additional loading We don't need to save r0 to PT_R0. It could be additional operation. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 9b8e072d828d..8f4a45e34a9e 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -535,8 +535,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); \ - /* Save away the syscall number. */ \ - swi r0, r1, PTO+PT_R0; \ tovirt(r1,r1) C_ENTRY(full_exception_trap): @@ -753,7 +751,6 @@ C_ENTRY(_interrupt): swi r11, r1, PTO+PT_R1; 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); - swi r0, r1, PTO + PT_R0; tovirt(r1,r1) addik r5, r1, PTO; set_vms; @@ -868,8 +865,6 @@ C_ENTRY(_debug_exception): lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ 2: - /* Save away the syscall number. */ - swi r0, r1, PTO+PT_R0; tovirt(r1,r1) set_vms; -- cgit v1.2.3-55-g7522 From 06a54604a31f06715a393a4fdd099b03611cce10 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 16:22:01 +0200 Subject: microblaze: Optimize SAVE_STATE macro SAVE_STATE macro could be used for user_exception or interrupt functions. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 8f4a45e34a9e..aa611cd35042 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -513,9 +513,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): tophys(r1,r1); \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ - /* PC, before IRQ/trap - this is one instruction above */ \ - swi r17, r1, PTO+PT_PC; \ - \ addi r11, r0, 1; /* Was in kernel-mode. */ \ swi r11, r1, PTO+PT_MODE; \ brid 2f; \ @@ -528,20 +525,19 @@ C_ENTRY(sys_rt_sigreturn_wrapper): tophys(r1,r1); \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ - /* PC, before IRQ/trap - this is one instruction above FIXME*/ \ - swi r17, r1, PTO+PT_PC; \ - \ swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ -2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); \ - tovirt(r1,r1) +2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); C_ENTRY(full_exception_trap): /* adjust exception address for privileged instruction * for finding where is it */ addik r17, r17, -4 SAVE_STATE /* Save registers */ + /* PC, before IRQ/trap - this is one instruction above */ + swi r17, r1, PTO+PT_PC; + tovirt(r1,r1) /* FIXME this can be store directly in PT_ESR reg. * I tested it but there is a fault */ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ @@ -581,6 +577,9 @@ C_ENTRY(unaligned_data_trap): set_ee; lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); SAVE_STATE /* Save registers.*/ + /* PC, before IRQ/trap - this is one instruction above */ + swi r17, r1, PTO+PT_PC; + tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 mfs r3, resr /* ESR */ @@ -613,6 +612,9 @@ C_ENTRY(unaligned_data_trap): /* data and intruction trap - which is choose is resolved int fault.c */ C_ENTRY(page_fault_data_trap): SAVE_STATE /* Save registers.*/ + /* PC, before IRQ/trap - this is one instruction above */ + swi r17, r1, PTO+PT_PC; + tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 addik r5, r1, PTO /* parameter struct pt_regs * regs */ @@ -627,6 +629,9 @@ C_ENTRY(page_fault_data_trap): C_ENTRY(page_fault_instr_trap): SAVE_STATE /* Save registers.*/ + /* PC, before IRQ/trap - this is one instruction above */ + swi r17, r1, PTO+PT_PC; + tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 addik r5, r1, PTO /* parameter struct pt_regs * regs */ -- cgit v1.2.3-55-g7522 From 77f6d226050e2d8f046e268a9f84ec834172f0de Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 16:39:56 +0200 Subject: microblaze: Remove additional setup for kernel_mode PT_MODE stores information if kernel comes from user or kernel space. If come from user space, PT_MODE contains 0. If come from kernel store, PT_MODE contains non zero value. We don't need to save value 1. I am using r1 register which contains non zero value. This change save one additional instruction. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index aa611cd35042..5318ad375fec 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -286,8 +286,7 @@ C_ENTRY(_user_exception): addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS - addi r11, r0, 1; /* Was in kernel-mode. */ - swi r11, r1, PTO+PT_MODE; /* pt_regs -> kernel mode */ + swi r1, r1, PTO + PT_MODE; /* pt_regs -> kernel mode */ brid 2f; nop; /* Fill delay slot */ @@ -303,7 +302,7 @@ C_ENTRY(_user_exception): addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS - swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ + swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); @@ -380,7 +379,7 @@ C_ENTRY(ret_from_trap): swi r3, r1, PTO + PT_R3 swi r4, r1, PTO + PT_R4 - lwi r11, r1, PTO+PT_MODE; + lwi r11, r1, PTO + PT_MODE; /* See if returning to kernel mode, if so, skip resched &c. */ bnei r11, 2f; /* We're returning to user mode, so check for various conditions that @@ -513,8 +512,7 @@ C_ENTRY(sys_rt_sigreturn_wrapper): tophys(r1,r1); \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ - addi r11, r0, 1; /* Was in kernel-mode. */ \ - swi r11, r1, PTO+PT_MODE; \ + swi r1, r1, PTO+PT_MODE; \ brid 2f; \ nop; /* Fill delay slot */ \ 1: /* User-mode state save. */ \ @@ -525,7 +523,7 @@ C_ENTRY(sys_rt_sigreturn_wrapper): tophys(r1,r1); \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ - swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ \ + swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); @@ -645,7 +643,7 @@ C_ENTRY(page_fault_instr_trap): /* Entry point used to return from an exception. */ C_ENTRY(ret_from_exc): - lwi r11, r1, PTO+PT_MODE; + lwi r11, r1, PTO + PT_MODE; bnei r11, 2f; /* See if returning to kernel mode, */ /* ... if so, skip resched &c. */ @@ -733,9 +731,7 @@ C_ENTRY(_interrupt): /* MS: Make room on the stack -> activation record */ addik r1, r1, -STATE_SAVE_SIZE; SAVE_REGS - /* MS: store mode */ - addi r11, r0, 1; /* MS: Was in kernel-mode. */ - swi r11, r1, PTO + PT_MODE; /* MS: and save it */ + swi r1, r1, PTO + PT_MODE; /* 0 - user mode, 1 - kernel mode */ brid 2f; nop; /* MS: Fill delay slot */ @@ -852,8 +848,7 @@ C_ENTRY(_debug_exception): addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS; - addi r11, r0, 1; /* Was in kernel-mode. */ - swi r11, r1, PTO + PT_MODE; + swi r1, r1, PTO + PT_MODE; brid 2f; nop; /* Fill delay slot */ 1: /* User-mode state save. */ @@ -866,7 +861,7 @@ C_ENTRY(_debug_exception): addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS; - swi r0, r1, PTO+PT_MODE; /* Was in user-mode. */ + swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ 2: @@ -880,7 +875,7 @@ dbtrap_call: rtbd r0, send_sig; addik r15, r0, dbtrap_call; set_bip; /* Ints masked for state restore*/ - lwi r11, r1, PTO+PT_MODE; + lwi r11, r1, PTO + PT_MODE; bnei r11, 2f; /* Get current task ptr into r11 */ -- cgit v1.2.3-55-g7522 From b318067e2c946a560035faf47e24a20e50696cce Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 17:46:27 +0200 Subject: microblaze: Implement clear_ums macro and fix SAVE_STATE macro VMS is always setup because VM mode was before exception/syscall/interrupt. Kernel continues in kernel mode that's why we have to clear UMS bit if kernel comes from user space. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 5318ad375fec..5529f64e97e8 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -91,6 +91,11 @@ nop .endm + .macro clear_ums + msrclr r11, MSR_UMS + nop + .endm + .macro clear_vms_ums msrclr r11, MSR_VMS | MSR_UMS nop @@ -162,6 +167,14 @@ nop .endm + .macro clear_ums + mfs r11, rmsr + nop + andni r11, r11, MSR_UMS + mts rmsr,r11 + nop + .endm + .macro clear_vms_ums mfs r11, rmsr nop @@ -526,6 +539,8 @@ C_ENTRY(sys_rt_sigreturn_wrapper): swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ + /* MS: I am clearing UMS even in case when I come from kernel space */ \ + clear_ums; \ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); C_ENTRY(full_exception_trap): -- cgit v1.2.3-55-g7522 From c318d483b3d9cf68d791b4024760cb171dae1215 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 16:25:31 +0200 Subject: microblaze: Optimize hw exception rutine Remove set_vms because UMS is cleared and VMS is already setup. Optimize function calling which save one additional instruction. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 5529f64e97e8..ff8d9872c774 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -562,10 +562,8 @@ C_ENTRY(full_exception_trap): nop mts rfsr, r0; /* Clear sticky fsr */ nop - addik r12, r0, full_exception - set_vms; - rted r12, 0; - nop; + rted r0, full_exception + nop /* * Unaligned data trap. @@ -599,11 +597,8 @@ C_ENTRY(unaligned_data_trap): nop mfs r4, rear /* EAR */ nop + rtbd r0, _unaligned_data_exception addik r7, r1, PTO /* parameter struct pt_regs * regs */ - addik r12, r0, _unaligned_data_exception - set_vms; - rtbd r12, 0; /* interrupts enabled */ - nop; /* * Page fault traps. @@ -635,10 +630,8 @@ C_ENTRY(page_fault_data_trap): nop mfs r7, resr /* parameter unsigned long error_code */ nop - addik r12, r0, do_page_fault - set_vms; - rted r12, 0; /* interrupts enabled */ - nop; + rted r0, do_page_fault + nop C_ENTRY(page_fault_instr_trap): SAVE_STATE /* Save registers.*/ @@ -650,11 +643,8 @@ C_ENTRY(page_fault_instr_trap): addik r5, r1, PTO /* parameter struct pt_regs * regs */ mfs r6, rear /* parameter unsigned long address */ nop + rted r0, do_page_fault ori r7, r0, 0 /* parameter unsigned long error_code */ - addik r12, r0, do_page_fault - set_vms; - rted r12, 0; /* interrupts enabled */ - nop; /* Entry point used to return from an exception. */ C_ENTRY(ret_from_exc): -- cgit v1.2.3-55-g7522 From 66f7de8634b39fb685556419fc12522e96990d32 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 17:52:47 +0200 Subject: microblaze: entry.S: Macro optimization We are not working with values from MSR that's why we can discard it and use r11 for different purpose without saving/restoring. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index ff8d9872c774..16cb4f1d2338 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -48,56 +48,56 @@ */ #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR .macro clear_bip - msrclr r11, MSR_BIP + msrclr r0, MSR_BIP nop .endm .macro set_bip - msrset r11, MSR_BIP + msrset r0, MSR_BIP nop .endm .macro clear_eip - msrclr r11, MSR_EIP + msrclr r0, MSR_EIP nop .endm .macro set_ee - msrset r11, MSR_EE + msrset r0, MSR_EE nop .endm .macro disable_irq - msrclr r11, MSR_IE + msrclr r0, MSR_IE nop .endm .macro enable_irq - msrset r11, MSR_IE + msrset r0, MSR_IE nop .endm .macro set_ums - msrset r11, MSR_UMS + msrset r0, MSR_UMS nop - msrclr r11, MSR_VMS + msrclr r0, MSR_VMS nop .endm .macro set_vms - msrclr r11, MSR_UMS + msrclr r0, MSR_UMS nop - msrset r11, MSR_VMS + msrset r0, MSR_VMS nop .endm .macro clear_ums - msrclr r11, MSR_UMS + msrclr r0, MSR_UMS nop .endm .macro clear_vms_ums - msrclr r11, MSR_VMS | MSR_UMS + msrclr r0, MSR_VMS | MSR_UMS nop .endm #else -- cgit v1.2.3-55-g7522 From e5d2af2b96696420865a1644c94a0e79e34c6035 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 17:58:26 +0200 Subject: microblaze: Move SAVE_STATE upward SAVE_STATE macro could be used by other rutines too. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 63 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 32 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 16cb4f1d2338..cf4a0aa35c0e 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -269,6 +269,37 @@ lwi r30, r1, PTO+PT_R30; \ lwi r31, r1, PTO+PT_R31; /* Restore cur task reg */ +#define SAVE_STATE \ + swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ + /* See if already in kernel mode.*/ \ + mfs r1, rmsr; \ + nop; \ + andi r1, r1, MSR_UMS; \ + bnei r1, 1f; \ + /* Kernel-mode state save. */ \ + /* Reload kernel stack-ptr. */ \ + lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ + tophys(r1,r1); \ + addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ + SAVE_REGS \ + swi r1, r1, PTO+PT_MODE; \ + brid 2f; \ + nop; /* Fill delay slot */ \ +1: /* User-mode state save. */ \ + lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ + tophys(r1,r1); \ + lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \ + addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */\ + tophys(r1,r1); \ + addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ + SAVE_REGS \ + swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \ + lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ + swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ + /* MS: I am clearing UMS even in case when I come from kernel space */ \ + clear_ums; \ +2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); + .text /* @@ -511,38 +542,6 @@ C_ENTRY(sys_rt_sigreturn_wrapper): /* * HW EXCEPTION rutine start */ - -#define SAVE_STATE \ - swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ - /* See if already in kernel mode.*/ \ - mfs r1, rmsr; \ - nop; \ - andi r1, r1, MSR_UMS; \ - bnei r1, 1f; \ - /* Kernel-mode state save. */ \ - /* Reload kernel stack-ptr. */ \ - lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ - tophys(r1,r1); \ - addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ - SAVE_REGS \ - swi r1, r1, PTO+PT_MODE; \ - brid 2f; \ - nop; /* Fill delay slot */ \ -1: /* User-mode state save. */ \ - lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ - tophys(r1,r1); \ - lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \ - addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */\ - tophys(r1,r1); \ - addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ - SAVE_REGS \ - swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \ - lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ - swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ - /* MS: I am clearing UMS even in case when I come from kernel space */ \ - clear_ums; \ -2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); - C_ENTRY(full_exception_trap): /* adjust exception address for privileged instruction * for finding where is it */ -- cgit v1.2.3-55-g7522 From e7741075b37e2be6693def1ff98487e3aef67874 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 18:00:35 +0200 Subject: microblaze: Do not mix register saving and mode setting Separate reg saving and mode setting. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index cf4a0aa35c0e..8f6b4eea4a6f 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -293,9 +293,9 @@ tophys(r1,r1); \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ - swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ + swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ \ /* MS: I am clearing UMS even in case when I come from kernel space */ \ clear_ums; \ 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); -- cgit v1.2.3-55-g7522 From da23355280d106b1160a0a07028838097b639f0b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 18:02:06 +0200 Subject: microblaze: Save kernel mode in delay slot This change save one instruction if kernel comes from kernel space. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 8f6b4eea4a6f..0747e1d61d55 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -282,9 +282,8 @@ tophys(r1,r1); \ addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ SAVE_REGS \ - swi r1, r1, PTO+PT_MODE; \ brid 2f; \ - nop; /* Fill delay slot */ \ + swi r1, r1, PTO+PT_MODE; \ 1: /* User-mode state save. */ \ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ tophys(r1,r1); \ -- cgit v1.2.3-55-g7522 From 9814cc11e559d982874f6ebac2bc795e33cb0244 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 18:09:29 +0200 Subject: microblaze: Use delay slot in syscall macros Saving instruction with delay slot usage. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 0747e1d61d55..34100a526194 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -411,10 +411,8 @@ C_ENTRY(_user_exception): /* The syscall number is invalid, return an error. */ 5: + rtsd r15, 8; /* looks like a normal subroutine return */ 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 */ /* We re-enable BIP bit before state restore */ @@ -491,9 +489,8 @@ C_ENTRY(sys_fork_wrapper): addik r7, r1, PTO /* Arg 2: parent context */ add r8. r0, r0 /* Arg 3: (unused) */ add r9, r0, r0; /* Arg 4: (unused) */ - add r10, r0, r0; /* Arg 5: (unused) */ brid do_fork /* Do real work (tail-call) */ - nop; + add r10, r0, r0; /* Arg 5: (unused) */ /* This the initial entry point for a new child thread, with an appropriate stack in place that makes it look the the child is in the middle of an @@ -504,9 +501,8 @@ C_ENTRY(ret_from_fork): bralid r15, schedule_tail; /* ...which is schedule_tail's arg */ add r3, r5, r0; /* switch_thread returns the prev task */ /* ( in the delay slot ) */ - add r3, r0, r0; /* Child's fork call should return 0. */ brid ret_from_trap; /* Do normal trap return */ - nop; + add r3, r0, r0; /* Child's fork call should return 0. */ C_ENTRY(sys_vfork): brid microblaze_vfork /* Do real work (tail-call) */ @@ -518,21 +514,18 @@ C_ENTRY(sys_clone): 1: addik r7, r1, PTO; /* Arg 2: parent context */ add r8, r0, r0; /* Arg 3: (unused) */ add r9, r0, r0; /* Arg 4: (unused) */ - add r10, r0, r0; /* Arg 5: (unused) */ brid do_fork /* Do real work (tail-call) */ - nop; + add r10, r0, r0; /* Arg 5: (unused) */ C_ENTRY(sys_execve): - addik r8, r1, PTO; /* add user context as 4th arg */ brid microblaze_execve; /* Do real work (tail-call).*/ - nop; + addik r8, r1, PTO; /* add user context as 4th arg */ C_ENTRY(sys_rt_sigreturn_wrapper): swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ swi r4, r1, PTO+PT_R4; - addik r5, r1, PTO; /* add user context as 1st arg */ brlid r15, sys_rt_sigreturn /* Do real work */ - nop; + addik r5, r1, PTO; /* add user context as 1st arg */ lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */ lwi r4, r1, PTO+PT_R4; bri ret_from_trap /* fall through will not work here due to align */ @@ -553,7 +546,6 @@ C_ENTRY(full_exception_trap): * I tested it but there is a fault */ /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc - 8 - addik r5, r1, PTO /* parameter struct pt_regs * regs */ mfs r6, resr nop mfs r7, rfsr; /* save FSR */ @@ -561,7 +553,7 @@ C_ENTRY(full_exception_trap): mts rfsr, r0; /* Clear sticky fsr */ nop rted r0, full_exception - nop + addik r5, r1, PTO /* parameter struct pt_regs * regs */ /* * Unaligned data trap. @@ -623,13 +615,12 @@ C_ENTRY(page_fault_data_trap): tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 - addik r5, r1, PTO /* parameter struct pt_regs * regs */ mfs r6, rear /* parameter unsigned long address */ nop mfs r7, resr /* parameter unsigned long error_code */ nop rted r0, do_page_fault - nop + addik r5, r1, PTO /* parameter struct pt_regs * regs */ C_ENTRY(page_fault_instr_trap): SAVE_STATE /* Save registers.*/ @@ -638,11 +629,11 @@ C_ENTRY(page_fault_instr_trap): tovirt(r1,r1) /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 - addik r5, r1, PTO /* parameter struct pt_regs * regs */ mfs r6, rear /* parameter unsigned long address */ nop - rted r0, do_page_fault ori r7, r0, 0 /* parameter unsigned long error_code */ + rted r0, do_page_fault + addik r5, r1, PTO /* parameter struct pt_regs * regs */ /* Entry point used to return from an exception. */ C_ENTRY(ret_from_exc): -- cgit v1.2.3-55-g7522 From 287503fabd9910cc77266142c7c8acbdb8efbf6b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 18:16:07 +0200 Subject: microblaze: Put together addik instructions Saving instructions by adding 2/3 addik instructions to one. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 34100a526194..e7abf7426c8c 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -279,8 +279,10 @@ /* Kernel-mode state save. */ \ /* Reload kernel stack-ptr. */ \ lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ - tophys(r1,r1); \ - addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ + /* FIXME: I can add these two lines to one */ \ + /* tophys(r1,r1); */ \ + /* addik r1, r1, -STATE_SAVE_SIZE; */ \ + addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \ SAVE_REGS \ brid 2f; \ swi r1, r1, PTO+PT_MODE; \ @@ -288,9 +290,11 @@ lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */\ tophys(r1,r1); \ lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ \ - addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */\ - tophys(r1,r1); \ - addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */\ + /* MS these three instructions can be added to one */ \ + /* addik r1, r1, THREAD_SIZE; */ \ + /* tophys(r1,r1); */ \ + /* addik r1, r1, -STATE_SAVE_SIZE; */ \ + addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; \ SAVE_REGS \ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); \ swi r11, r1, PTO+PT_R1; /* Store user SP. */ \ -- cgit v1.2.3-55-g7522 From 25f6e59657211b3f7d912520c53fb7d98ebe960b Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 18:29:05 +0200 Subject: microblaze: Fix _user_exception function Saving some instructions. Clear VMS bit if kernel comes from kernel space. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index e7abf7426c8c..4c06e1a46a25 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -352,6 +352,7 @@ C_ENTRY(_user_exception): swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ + clear_ums; 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* Save away the syscall number. */ swi r12, r1, PTO+PT_R0; @@ -363,10 +364,8 @@ C_ENTRY(_user_exception): * register should point to the location where * the called function should return. [note that MAKE_SYS_CALL uses label 1] */ - # Step into virtual mode. - set_vms; - addik r11, r0, 3f - rtid r11, 0 + /* Step into virtual mode */ + rtbd r0, 3f nop 3: lwi r11, CURRENT_TASK, TS_THREAD_INFO /* get thread info */ -- cgit v1.2.3-55-g7522 From 80c5ff6b9b2dd9a2e99d3d6f74df5e6f888d43e9 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 18:50:31 +0200 Subject: microblaze: Fix _interrupt function Save instructions by using delay slot and clear UMS only if kernel comes from user space. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 4c06e1a46a25..f4fda8578551 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -747,15 +747,13 @@ C_ENTRY(_interrupt): swi r0, r1, PTO + PT_MODE; lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; + clear_ums; 2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); tovirt(r1,r1) - addik r5, r1, PTO; - set_vms; - addik r11, r0, do_IRQ; addik r15, r0, irq_call; -irq_call:rtbd r11, 0; - nop; +irq_call:rtbd r0, do_IRQ; + addik r5, r1, PTO; /* MS: we are in virtual mode */ ret_from_irq: -- cgit v1.2.3-55-g7522 From 0a6b08fda6e3229713e779e30028598c067e904d Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 20:49:46 +0200 Subject: microblaze: Move PT_MODE saving to delay slot We can save one more instruction if PT_MODE is saved in delay slot Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index f4fda8578551..6c117ceaabea 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -728,10 +728,8 @@ C_ENTRY(_interrupt): /* MS: Make room on the stack -> activation record */ addik r1, r1, -STATE_SAVE_SIZE; SAVE_REGS - swi r1, r1, PTO + PT_MODE; /* 0 - user mode, 1 - kernel mode */ brid 2f; - nop; /* MS: Fill delay slot */ - + swi r1, r1, PTO + PT_MODE; /* 0 - user mode, 1 - kernel mode */ 1: /* User-mode state save. */ /* MS: get the saved current */ -- cgit v1.2.3-55-g7522 From 0e41c90908881a1b8205c66a66becec7d8d4eb4a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 21:11:49 +0200 Subject: microblaze: Simplify syscall rutine Syscall can be called only from userspace that's why we don't need to check which space kernel come from. Kernel syscall calling is not check and shouldn't come throught this part of code. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 46 +++++++----------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 6c117ceaabea..bf6b2b122485 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -318,42 +318,23 @@ * are masked. This is nice, means we don't have to CLI before state save */ C_ENTRY(_user_exception): - swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ addi r14, r14, 4 /* return address is 4 byte after call */ + swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)) /* save stack */ - mfs r1, rmsr - nop - andi r1, r1, MSR_UMS - bnei r1, 1f - -/* Kernel-mode state save - kernel execve */ - lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ - tophys(r1,r1); - - addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ - SAVE_REGS - - swi r1, r1, PTO + PT_MODE; /* pt_regs -> kernel mode */ - brid 2f; - nop; /* Fill delay slot */ - -/* User-mode state save. */ -1: lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ tophys(r1,r1); lwi r1, r1, TS_THREAD_INFO; /* get stack from task_struct */ -/* calculate kernel stack pointer from task struct 8k */ - addik r1, r1, THREAD_SIZE; - tophys(r1,r1); - - addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ + /* MS these three instructions can be added to one */ + /* addik r1, r1, THREAD_SIZE; */ + /* tophys(r1,r1); */ + /* addik r1, r1, -STATE_SAVE_SIZE; */ + addik r1, r1, THREAD_SIZE + CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; SAVE_REGS - swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ clear_ums; -2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); + lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* Save away the syscall number. */ swi r12, r1, PTO+PT_R0; tovirt(r1,r1) @@ -423,9 +404,6 @@ C_ENTRY(ret_from_trap): swi r3, r1, PTO + PT_R3 swi r4, r1, PTO + PT_R4 - lwi r11, r1, PTO + PT_MODE; -/* See if returning to kernel mode, if so, skip resched &c. */ - bnei r11, 2f; /* We're returning to user mode, so check for various conditions that * trigger rescheduling. */ /* FIXME: Restructure all these flag checks. */ @@ -468,16 +446,6 @@ C_ENTRY(ret_from_trap): RESTORE_REGS; addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ lwi r1, r1, PT_R1 - PT_SIZE;/* Restore user stack pointer. */ - bri 6f; - -/* Return to kernel state. */ -2: set_bip; /* Ints masked for state restore */ - VM_OFF; - tophys(r1,r1); - RESTORE_REGS; - addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ - tovirt(r1,r1); -6: TRAP_return: /* Make global symbol for debugging */ rtbd r14, 0; /* Instructions to return from an IRQ */ nop; -- cgit v1.2.3-55-g7522 From 958063e67b775bc1be85eb3761c85202597a87aa Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 22 Jun 2010 21:18:57 +0200 Subject: microblaze: Remove nop after MSRCLR/SET, MTS, MFS instructions We need to save instruction and the latest Microblaze shouldn't have any problem with it. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 51 ------------------------------------------ 1 file changed, 51 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index bf6b2b122485..397754cd31c9 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -49,138 +49,106 @@ #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR .macro clear_bip msrclr r0, MSR_BIP - nop .endm .macro set_bip msrset r0, MSR_BIP - nop .endm .macro clear_eip msrclr r0, MSR_EIP - nop .endm .macro set_ee msrset r0, MSR_EE - nop .endm .macro disable_irq msrclr r0, MSR_IE - nop .endm .macro enable_irq msrset r0, MSR_IE - nop .endm .macro set_ums msrset r0, MSR_UMS - nop msrclr r0, MSR_VMS - nop .endm .macro set_vms msrclr r0, MSR_UMS - nop msrset r0, MSR_VMS - nop .endm .macro clear_ums msrclr r0, MSR_UMS - nop .endm .macro clear_vms_ums msrclr r0, MSR_VMS | MSR_UMS - nop .endm #else .macro clear_bip mfs r11, rmsr - nop andi r11, r11, ~MSR_BIP mts rmsr, r11 - nop .endm .macro set_bip mfs r11, rmsr - nop ori r11, r11, MSR_BIP mts rmsr, r11 - nop .endm .macro clear_eip mfs r11, rmsr - nop andi r11, r11, ~MSR_EIP mts rmsr, r11 - nop .endm .macro set_ee mfs r11, rmsr - nop ori r11, r11, MSR_EE mts rmsr, r11 - nop .endm .macro disable_irq mfs r11, rmsr - nop andi r11, r11, ~MSR_IE mts rmsr, r11 - nop .endm .macro enable_irq mfs r11, rmsr - nop ori r11, r11, MSR_IE mts rmsr, r11 - nop .endm .macro set_ums mfs r11, rmsr - nop ori r11, r11, MSR_VMS andni r11, r11, MSR_UMS mts rmsr, r11 - nop .endm .macro set_vms mfs r11, rmsr - nop ori r11, r11, MSR_VMS andni r11, r11, MSR_UMS mts rmsr, r11 - nop .endm .macro clear_ums mfs r11, rmsr - nop andni r11, r11, MSR_UMS mts rmsr,r11 - nop .endm .macro clear_vms_ums mfs r11, rmsr - nop andni r11, r11, (MSR_VMS|MSR_UMS) mts rmsr,r11 - nop .endm #endif @@ -233,13 +201,11 @@ swi r30, r1, PTO+PT_R30; \ swi r31, r1, PTO+PT_R31; /* Save current task reg */ \ mfs r11, rmsr; /* save MSR */ \ - nop; \ swi r11, r1, PTO+PT_MSR; #define RESTORE_REGS \ lwi r11, r1, PTO+PT_MSR; \ mts rmsr , r11; \ - nop; \ lwi r2, r1, PTO+PT_R2; /* restore SDA */ \ lwi r3, r1, PTO+PT_R3; \ lwi r4, r1, PTO+PT_R4; \ @@ -273,7 +239,6 @@ swi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* save stack */ \ /* See if already in kernel mode.*/ \ mfs r1, rmsr; \ - nop; \ andi r1, r1, MSR_UMS; \ bnei r1, 1f; \ /* Kernel-mode state save. */ \ @@ -518,11 +483,8 @@ C_ENTRY(full_exception_trap): /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc - 8 mfs r6, resr - nop mfs r7, rfsr; /* save FSR */ - nop mts rfsr, r0; /* Clear sticky fsr */ - nop rted r0, full_exception addik r5, r1, PTO /* parameter struct pt_regs * regs */ @@ -555,9 +517,7 @@ C_ENTRY(unaligned_data_trap): /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 mfs r3, resr /* ESR */ - nop mfs r4, rear /* EAR */ - nop rtbd r0, _unaligned_data_exception addik r7, r1, PTO /* parameter struct pt_regs * regs */ @@ -587,9 +547,7 @@ C_ENTRY(page_fault_data_trap): /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 mfs r6, rear /* parameter unsigned long address */ - nop mfs r7, resr /* parameter unsigned long error_code */ - nop rted r0, do_page_fault addik r5, r1, PTO /* parameter struct pt_regs * regs */ @@ -601,7 +559,6 @@ C_ENTRY(page_fault_instr_trap): /* where the trap should return need -8 to adjust for rtsd r15, 8 */ addik r15, r0, ret_from_exc-8 mfs r6, rear /* parameter unsigned long address */ - nop ori r7, r0, 0 /* parameter unsigned long error_code */ rted r0, do_page_fault addik r5, r1, PTO /* parameter struct pt_regs * regs */ @@ -936,16 +893,12 @@ ENTRY(_switch_to) swi r30, r11, CC_R30 /* special purpose registers */ mfs r12, rmsr - nop swi r12, r11, CC_MSR mfs r12, rear - nop swi r12, r11, CC_EAR mfs r12, resr - nop swi r12, r11, CC_ESR mfs r12, rfsr - nop swi r12, r11, CC_FSR /* update r31, the current-give me pointer to task which will be next */ @@ -984,10 +937,8 @@ ENTRY(_switch_to) /* special purpose registers */ lwi r12, r11, CC_FSR mts rfsr, r12 - nop lwi r12, r11, CC_MSR mts rmsr, r12 - nop rtsd r15, 8 nop @@ -997,10 +948,8 @@ ENTRY(_reset) ENTRY(_break) mfs r5, rmsr - nop swi r5, r0, 0x250 + TOPHYS(r0_ram) mfs r5, resr - nop swi r5, r0, 0x254 + TOPHYS(r0_ram) bri 0 -- cgit v1.2.3-55-g7522 From 751f1605e03533a6279ccf456e938e9595c7d888 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 3 Aug 2010 11:26:51 +0200 Subject: microblaze: Support brki rX, 0x18 for user application debugging This is the first patch which add support for user application debugging through brki rX, 0x18 vector. This patch has side effect which also remove security issue to use brki rX, 0x18 to freeze kernel. Support for old gdb support via priviledged exception (brk r0, r0) is still there. It will be remove in future. Signed-off-by: Michal Simek --- arch/microblaze/kernel/entry.S | 30 ++++++++++++------------------ arch/microblaze/kernel/exceptions.c | 8 +++++++- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 397754cd31c9..5a5cb5842938 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -778,19 +778,22 @@ C_ENTRY(_debug_exception): addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ SAVE_REGS; + swi r17, r1, PTO+PT_R17; + swi r16, r1, PTO+PT_R16; + swi r16, r1, PTO+PT_PC; /* Save LP */ swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ -2: +2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); tovirt(r1,r1) set_vms; - addi r5, r0, SIGTRAP /* send the trap signal */ - add r6, r0, CURRENT_TASK; /* Get current task ptr into r11 */ - addk r7, r0, r0 /* 3rd param zero */ -dbtrap_call: rtbd r0, send_sig; + addik r5, r1, PTO; addik r15, r0, dbtrap_call; +dbtrap_call: /* return point for kernel/user entry */ + rtbd r0, sw_exception + nop set_bip; /* Ints masked for state restore*/ lwi r11, r1, PTO + PT_MODE; @@ -838,6 +841,8 @@ dbtrap_call: rtbd r0, send_sig; tophys(r1,r1); RESTORE_REGS + lwi r17, r1, PTO+PT_R17; + lwi r16, r1, PTO+PT_R16; addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ @@ -854,11 +859,10 @@ dbtrap_call: rtbd r0, send_sig; tovirt(r1,r1); 6: DBTRAP_return: /* Make global symbol for debugging */ - rtbd r14, 0; /* Instructions to return from an IRQ */ + rtbd r16, 0; /* Instructions to return from an IRQ */ nop; - ENTRY(_switch_to) /* prepare return value */ addk r3, r0, CURRENT_TASK @@ -946,13 +950,6 @@ ENTRY(_switch_to) ENTRY(_reset) brai 0x70; /* Jump back to FS-boot */ -ENTRY(_break) - mfs r5, rmsr - swi r5, r0, 0x250 + TOPHYS(r0_ram) - mfs r5, resr - swi r5, r0, 0x254 + TOPHYS(r0_ram) - bri 0 - /* These are compiled and loaded into high memory, then * copied into place in mach_early_setup */ .section .init.ivt, "ax" @@ -964,12 +961,9 @@ ENTRY(_break) nop brai TOPHYS(_user_exception); /* syscall handler */ brai TOPHYS(_interrupt); /* Interrupt handler */ - brai TOPHYS(_break); /* nmi trap handler */ + brai TOPHYS(_debug_exception); /* debug trap handler */ brai TOPHYS(_hw_exception_handler); /* HW exception handler */ - .org 0x60 - brai TOPHYS(_debug_exception); /* debug trap handler*/ - .section .rodata,"a" #include "syscall_table.S" diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c index 02cbdfe5aa8d..e0c6f8c2bd9d 100644 --- a/arch/microblaze/kernel/exceptions.c +++ b/arch/microblaze/kernel/exceptions.c @@ -48,6 +48,12 @@ void die(const char *str, struct pt_regs *fp, long err) do_exit(err); } +/* for user application debugging */ +void sw_exception(struct pt_regs *regs) +{ + _exception(SIGTRAP, regs, TRAP_BRKPT, regs->r16); +} + void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { siginfo_t info; @@ -143,7 +149,7 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, #ifdef CONFIG_MMU case MICROBLAZE_PRIVILEGED_EXCEPTION: pr_debug(KERN_WARNING "Privileged exception\n"); - /* "brk r0,r0" - used as debug breakpoint */ + /* "brk r0,r0" - used as debug breakpoint - old toolchain */ if (get_user(code, (unsigned long *)regs->pc) == 0 && code == 0x980c0000) { _exception(SIGTRAP, regs, TRAP_BRKPT, addr); -- cgit v1.2.3-55-g7522 From 2d5973cb5ac5d04662f86e19a06a4c52fa4c4ae3 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Tue, 3 Aug 2010 11:45:08 +0200 Subject: microblaze: Add KGDB support Kgdb uses brki r16, 0x18 instruction to call low level _debug_exception function which save current state to pt_regs and call microblaze_kgdb_break function. _debug_exception should be called only from the kernel space. User space calling is not supported because user application debugging uses different handling. pt_regs_to_gdb_regs loads additional special registers which can't be changed * Enable KGDB in Kconfig * Remove ancient not-tested KGDB support * Remove ancient _debug_exception code from entry.S Only MMU KGDB support is supported. Signed-off-by: Michal Simek CC: Jason Wessel CC: John Williams CC: Edgar E. Iglesias CC: linux-kernel@vger.kernel.org Acked-by: Jason Wessel --- arch/microblaze/Kconfig | 1 + arch/microblaze/include/asm/exceptions.h | 16 ---- arch/microblaze/include/asm/kgdb.h | 28 ++++++ arch/microblaze/kernel/Makefile | 1 + arch/microblaze/kernel/entry.S | 106 +++++++++++----------- arch/microblaze/kernel/exceptions.c | 1 - arch/microblaze/kernel/kgdb.c | 147 +++++++++++++++++++++++++++++++ arch/microblaze/mm/fault.c | 15 ---- 8 files changed, 234 insertions(+), 81 deletions(-) create mode 100644 arch/microblaze/include/asm/kgdb.h create mode 100644 arch/microblaze/kernel/kgdb.c (limited to 'arch') diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index a51742190c12..be3855250db6 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig @@ -14,6 +14,7 @@ config MICROBLAZE select USB_ARCH_HAS_EHCI select ARCH_WANT_OPTIONAL_GPIOLIB select HAVE_OPROFILE + select HAVE_ARCH_KGDB select HAVE_DMA_ATTRS select HAVE_DMA_API_DEBUG select TRACING_SUPPORT diff --git a/arch/microblaze/include/asm/exceptions.h b/arch/microblaze/include/asm/exceptions.h index fa0e36657fdd..6479097b802b 100644 --- a/arch/microblaze/include/asm/exceptions.h +++ b/arch/microblaze/include/asm/exceptions.h @@ -69,22 +69,6 @@ asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, void die(const char *str, struct pt_regs *fp, long err); void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr); -#if defined(CONFIG_KGDB) -void (*debugger)(struct pt_regs *regs); -int (*debugger_bpt)(struct pt_regs *regs); -int (*debugger_sstep)(struct pt_regs *regs); -int (*debugger_iabr_match)(struct pt_regs *regs); -int (*debugger_dabr_match)(struct pt_regs *regs); -void (*debugger_fault_handler)(struct pt_regs *regs); -#else -#define debugger(regs) do { } while (0) -#define debugger_bpt(regs) 0 -#define debugger_sstep(regs) 0 -#define debugger_iabr_match(regs) 0 -#define debugger_dabr_match(regs) 0 -#define debugger_fault_handler ((void (*)(struct pt_regs *))0) -#endif - #endif /*__ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_MICROBLAZE_EXCEPTIONS_H */ diff --git a/arch/microblaze/include/asm/kgdb.h b/arch/microblaze/include/asm/kgdb.h new file mode 100644 index 000000000000..78b17d40b235 --- /dev/null +++ b/arch/microblaze/include/asm/kgdb.h @@ -0,0 +1,28 @@ +#ifdef __KERNEL__ +#ifndef __MICROBLAZE_KGDB_H__ +#define __MICROBLAZE_KGDB_H__ + +#ifndef __ASSEMBLY__ + +#define CACHE_FLUSH_IS_SAFE 1 +#define BUFMAX 2048 + +/* + * 32 32-bit general purpose registers (r0-r31) + * 6 32-bit special registers (pc, msr, ear, esr, fsr, btr) + * 12 32-bit PVR + * 7 32-bit MMU Regs (redr, rpid, rzpr, rtlbx, rtlbsx, rtlblo, rtlbhi) + * ------ + * 57 registers + */ +#define NUMREGBYTES (57 * 4) + +#define BREAK_INSTR_SIZE 4 +static inline void arch_kgdb_breakpoint(void) +{ + __asm__ __volatile__("brki r16, 0x18;"); +} + +#endif /* __ASSEMBLY__ */ +#endif /* __MICROBLAZE_KGDB_H__ */ +#endif /* __KERNEL__ */ diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile index d66ddef53c07..5eecc9f1fbd9 100644 --- a/arch/microblaze/kernel/Makefile +++ b/arch/microblaze/kernel/Makefile @@ -28,5 +28,6 @@ obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o obj-$(CONFIG_MMU) += misc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount.o +obj-$(CONFIG_KGDB) += kgdb.o obj-y += entry$(MMU).o diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S index 5a5cb5842938..304882e56459 100644 --- a/arch/microblaze/kernel/entry.S +++ b/arch/microblaze/kernel/entry.S @@ -745,11 +745,8 @@ IRQ_return: /* MS: Make global symbol for debugging */ nop /* - * `Debug' trap - * We enter dbtrap in "BIP" (breakpoint) mode. - * So we exit the breakpoint mode with an 'rtbd' and proceed with the - * original dbtrap. - * however, wait to save state first + * Debug trap for KGDB. Enter to _debug_exception by brki r16, 0x18 + * and call handling function with saved pt_regs */ C_ENTRY(_debug_exception): /* BIP bit is set on entry, no interrupts can occur */ @@ -759,18 +756,44 @@ C_ENTRY(_debug_exception): nop andi r1, r1, MSR_UMS bnei r1, 1f - /* Kernel-mode state save. */ +/* MS: Kernel-mode state save - kgdb */ lwi r1, r0, TOPHYS(PER_CPU(ENTRY_SP)); /* Reload kernel stack-ptr*/ - tophys(r1,r1); - addik r1, r1, -STATE_SAVE_SIZE; /* Make room on the stack. */ + /* BIP bit is set on entry, no interrupts can occur */ + addik r1, r1, CONFIG_KERNEL_BASE_ADDR - CONFIG_KERNEL_START - STATE_SAVE_SIZE; SAVE_REGS; + /* save all regs to pt_reg structure */ + swi r0, r1, PTO+PT_R0; /* R0 must be saved too */ + swi r14, r1, PTO+PT_R14 /* rewrite saved R14 value */ + swi r16, r1, PTO+PT_R16 + swi r16, r1, PTO+PT_PC; /* PC and r16 are the same */ + swi r17, r1, PTO+PT_R17 + /* save special purpose registers to pt_regs */ + mfs r11, rear; + swi r11, r1, PTO+PT_EAR; + mfs r11, resr; + swi r11, r1, PTO+PT_ESR; + mfs r11, rfsr; + swi r11, r1, PTO+PT_FSR; + + /* stack pointer is in physical address at it is decrease + * by STATE_SAVE_SIZE but we need to get correct R1 value */ + addik r11, r1, CONFIG_KERNEL_START - CONFIG_KERNEL_BASE_ADDR + STATE_SAVE_SIZE; + swi r11, r1, PTO+PT_R1 + /* MS: r31 - current pointer isn't changed */ + tovirt(r1,r1) +#ifdef CONFIG_KGDB + addi r5, r1, PTO /* pass pt_reg address as the first arg */ + la r15, r0, dbtrap_call; /* return address */ + rtbd r0, microblaze_kgdb_break + nop; +#endif + /* MS: Place handler for brki from kernel space if KGDB is OFF. + * It is very unlikely that another brki instruction is called. */ + bri 0 - swi r1, r1, PTO + PT_MODE; - brid 2f; - nop; /* Fill delay slot */ -1: /* User-mode state save. */ - lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ +/* MS: User-mode state save - gdb */ +1: lwi r1, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); /* get saved current */ tophys(r1,r1); lwi r1, r1, TS_THREAD_INFO; /* get the thread info */ addik r1, r1, THREAD_SIZE; /* calculate kernel stack pointer */ @@ -781,36 +804,32 @@ C_ENTRY(_debug_exception): swi r17, r1, PTO+PT_R17; swi r16, r1, PTO+PT_R16; swi r16, r1, PTO+PT_PC; /* Save LP */ - swi r0, r1, PTO + PT_MODE; /* Was in user-mode. */ lwi r11, r0, TOPHYS(PER_CPU(ENTRY_SP)); swi r11, r1, PTO+PT_R1; /* Store user SP. */ -2: lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); + lwi CURRENT_TASK, r0, TOPHYS(PER_CPU(CURRENT_SAVE)); tovirt(r1,r1) - set_vms; addik r5, r1, PTO; addik r15, r0, dbtrap_call; -dbtrap_call: /* return point for kernel/user entry */ +dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */ rtbd r0, sw_exception nop - set_bip; /* Ints masked for state restore*/ + /* MS: The first instruction for the second part of the gdb/kgdb */ + set_bip; /* Ints masked for state restore */ lwi r11, r1, PTO + PT_MODE; bnei r11, 2f; - +/* MS: Return to user space - gdb */ /* Get current task ptr into r11 */ lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ lwi r11, r11, TI_FLAGS; /* get flags in thread info */ andi r11, r11, _TIF_NEED_RESCHED; beqi r11, 5f; -/* Call the scheduler before returning from a syscall/trap. */ - + /* Call the scheduler before returning from a syscall/trap. */ bralid r15, schedule; /* Call scheduler */ nop; /* delay slot */ - /* XXX Is PT_DTRACE handling needed here? */ - /* XXX m68knommu also checks TASK_STATE & TASK_COUNTER here. */ /* Maybe handle a signal */ 5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */ @@ -818,48 +837,37 @@ dbtrap_call: /* return point for kernel/user entry */ andi r11, r11, _TIF_SIGPENDING; beqi r11, 1f; /* Signals to handle, handle them */ -/* Handle a signal return; Pending signals should be in r18. */ - /* Not all registers are saved by the normal trap/interrupt entry - points (for instance, call-saved registers (because the normal - C-compiler calling sequence in the kernel makes sure they're - preserved), and call-clobbered registers in the case of - traps), but signal handlers may want to examine or change the - complete register state. Here we save anything not saved by - the normal entry sequence, so that it may be safely restored - (in a possibly modified form) after do_signal returns. */ - addik r5, r1, PTO; /* Arg 1: struct pt_regs *regs */ addi r7, r0, 0; /* Arg 3: int in_syscall */ bralid r15, do_signal; /* Handle any signals */ add r6, r0, r0; /* Arg 2: sigset_t *oldset */ - /* Finally, return to user state. */ -1: - swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ +1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */ VM_OFF; tophys(r1,r1); - + /* MS: Restore all regs */ RESTORE_REGS lwi r17, r1, PTO+PT_R17; lwi r16, r1, PTO+PT_R16; - addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ - - - lwi r1, r1, PT_R1 - PT_SIZE; - /* Restore user stack pointer. */ - bri 6f; + addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space */ + lwi r1, r1, PT_R1 - PT_SIZE; /* Restore user stack pointer */ +DBTRAP_return_user: /* MS: Make global symbol for debugging */ + rtbd r16, 0; /* MS: Instructions to return from a debug trap */ + nop; -/* Return to kernel state. */ +/* MS: Return to kernel state - kgdb */ 2: VM_OFF; tophys(r1,r1); + /* MS: Restore all regs */ RESTORE_REGS - addik r1, r1, STATE_SAVE_SIZE /* Clean up stack space. */ - + lwi r14, r1, PTO+PT_R14; + lwi r16, r1, PTO+PT_PC; + lwi r17, r1, PTO+PT_R17; + addik r1, r1, STATE_SAVE_SIZE; /* MS: Clean up stack space */ tovirt(r1,r1); -6: -DBTRAP_return: /* Make global symbol for debugging */ - rtbd r16, 0; /* Instructions to return from an IRQ */ +DBTRAP_return_kernel: /* MS: Make global symbol for debugging */ + rtbd r16, 0; /* MS: Instructions to return from a debug trap */ nop; diff --git a/arch/microblaze/kernel/exceptions.c b/arch/microblaze/kernel/exceptions.c index e0c6f8c2bd9d..b98ee8d0c1cd 100644 --- a/arch/microblaze/kernel/exceptions.c +++ b/arch/microblaze/kernel/exceptions.c @@ -59,7 +59,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) siginfo_t info; if (kernel_mode(regs)) { - debugger(regs); die("Exception in kernel mode", regs, signr); } info.si_signo = signr; diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c new file mode 100644 index 000000000000..bfc006b7f2d8 --- /dev/null +++ b/arch/microblaze/kernel/kgdb.c @@ -0,0 +1,147 @@ +/* + * Microblaze KGDB support + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define GDB_REG 0 +#define GDB_PC 32 +#define GDB_MSR 33 +#define GDB_EAR 34 +#define GDB_ESR 35 +#define GDB_FSR 36 +#define GDB_BTR 37 +#define GDB_PVR 38 +#define GDB_REDR 50 +#define GDB_RPID 51 +#define GDB_RZPR 52 +#define GDB_RTLBX 53 +#define GDB_RTLBSX 54 /* mfs can't read it */ +#define GDB_RTLBLO 55 +#define GDB_RTLBHI 56 + +/* keep pvr separately because it is unchangeble */ +struct pvr_s pvr; + +void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int i; + unsigned long *pt_regb = (unsigned long *)regs; + int temp; + /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ + for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) + gdb_regs[i] = pt_regb[i]; + + /* Branch target register can't be changed */ + __asm__ __volatile__ ("mfs %0, rbtr;" : "=r"(temp) : ); + gdb_regs[GDB_BTR] = temp; + + /* pvr part - we have 11 pvr regs */ + for (i = 0; i < sizeof(struct pvr_s)/4; i++) + gdb_regs[GDB_PVR + i] = pvr.pvr[i]; + + /* read special registers - can't be changed */ + __asm__ __volatile__ ("mfs %0, redr;" : "=r"(temp) : ); + gdb_regs[GDB_REDR] = temp; + __asm__ __volatile__ ("mfs %0, rpid;" : "=r"(temp) : ); + gdb_regs[GDB_RPID] = temp; + __asm__ __volatile__ ("mfs %0, rzpr;" : "=r"(temp) : ); + gdb_regs[GDB_RZPR] = temp; + __asm__ __volatile__ ("mfs %0, rtlbx;" : "=r"(temp) : ); + gdb_regs[GDB_RTLBX] = temp; + __asm__ __volatile__ ("mfs %0, rtlblo;" : "=r"(temp) : ); + gdb_regs[GDB_RTLBLO] = temp; + __asm__ __volatile__ ("mfs %0, rtlbhi;" : "=r"(temp) : ); + gdb_regs[GDB_RTLBHI] = temp; +} + +void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int i; + unsigned long *pt_regb = (unsigned long *)regs; + + /* pt_regs and gdb_regs have the same 37 values. + * The rest of gdb_regs are unused and can't be changed. + * r0 register value can't be changed too. */ + for (i = 1; i < (sizeof(struct pt_regs) / 4) - 1; i++) + pt_regb[i] = gdb_regs[i]; +} + +void microblaze_kgdb_break(struct pt_regs *regs) +{ + if (kgdb_handle_exception(1, SIGTRAP, 0, regs) != 0) + return 0; + + /* Jump over the first arch_kgdb_breakpoint which is barrier to + * get kgdb work. The same solution is used for powerpc */ + if (*(u32 *) (regs->pc) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) + regs->pc += BREAK_INSTR_SIZE; +} + +/* untested */ +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + int i; + unsigned long *pt_regb = (unsigned long *)(p->thread.regs); + + /* registers r0 - r31, pc, msr, ear, esr, fsr + do not save pt_mode */ + for (i = 0; i < (sizeof(struct pt_regs) / 4) - 1; i++) + gdb_regs[i] = pt_regb[i]; + + /* pvr part - we have 11 pvr regs */ + for (i = 0; i < sizeof(struct pvr_s)/4; i++) + gdb_regs[GDB_PVR + i] = pvr.pvr[i]; +} + +void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip) +{ + regs->pc = ip; +} + +int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *regs) +{ + char *ptr; + unsigned long address; + int cpu = smp_processor_id(); + + switch (remcom_in_buffer[0]) { + case 'c': + /* handle the optional parameter */ + ptr = &remcom_in_buffer[1]; + if (kgdb_hex2long(&ptr, &address)) + regs->pc = address; + + return 0; + } + return -1; /* this means that we do not want to exit from the handler */ +} + +int kgdb_arch_init(void) +{ + get_pvr(&pvr); /* Fill PVR structure */ + return 0; +} + +void kgdb_arch_exit(void) +{ + /* Nothing to do */ +} + +/* + * Global data + */ +struct kgdb_arch arch_kgdb_ops = { + .gdb_bpt_instr = {0xba, 0x0c, 0x00, 0x18}, /* brki r16, 0x18 */ +}; diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c index b224c650a18d..57bd2a09610c 100644 --- a/arch/microblaze/mm/fault.c +++ b/arch/microblaze/mm/fault.c @@ -37,10 +37,6 @@ #include #include -#if defined(CONFIG_KGDB) -int debugger_kernel_faults = 1; -#endif - static unsigned long pte_misses; /* updated by do_page_fault() */ static unsigned long pte_errors; /* updated by do_page_fault() */ @@ -81,10 +77,6 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig) } /* kernel has accessed a bad area */ -#if defined(CONFIG_KGDB) - if (debugger_kernel_faults) - debugger(regs); -#endif die("kernel access of bad area", regs, sig); } @@ -115,13 +107,6 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, if ((error_code & 0x13) == 0x13 || (error_code & 0x11) == 0x11) is_write = 0; -#if defined(CONFIG_KGDB) - if (debugger_fault_handler && regs->trap == 0x300) { - debugger_fault_handler(regs); - return; - } -#endif /* CONFIG_KGDB */ - if (unlikely(in_atomic() || !mm)) { if (kernel_mode(regs)) goto bad_area_nosemaphore; -- cgit v1.2.3-55-g7522