From 360adee8a5c249f221de43d7d46073391359a4ba Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 15 Dec 2009 05:08:36 +0000 Subject: Blackfin: wire up the various memory related syscalls These all just go to the stub syscall at the moment, so this is largely future proofing. Signed-off-by: Mike Frysinger --- arch/blackfin/mach-common/entry.S | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'arch/blackfin/mach-common/entry.S') diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 01b2f58dfb9..0df7ef200f9 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -1357,7 +1357,7 @@ ENTRY(_sys_call_table) .long _sys_newuname .long _sys_ni_syscall /* old sys_modify_ldt */ .long _sys_adjtimex - .long _sys_ni_syscall /* 125 */ /* sys_mprotect */ + .long _sys_mprotect /* 125 */ .long _sys_ni_syscall /* old sys_sigprocmask */ .long _sys_ni_syscall /* old "creat_module" */ .long _sys_init_module @@ -1376,16 +1376,16 @@ ENTRY(_sys_call_table) .long _sys_getdents .long _sys_ni_syscall /* sys_select */ .long _sys_flock - .long _sys_ni_syscall /* sys_msync */ + .long _sys_msync .long _sys_readv /* 145 */ .long _sys_writev .long _sys_getsid .long _sys_fdatasync .long _sys_sysctl - .long _sys_ni_syscall /* 150 */ /* sys_mlock */ - .long _sys_ni_syscall /* sys_munlock */ - .long _sys_ni_syscall /* sys_mlockall */ - .long _sys_ni_syscall /* sys_munlockall */ + .long _sys_mlock /* 150 */ + .long _sys_munlock + .long _sys_mlockall + .long _sys_munlockall .long _sys_sched_setparam .long _sys_sched_getparam /* 155 */ .long _sys_sched_setscheduler @@ -1450,8 +1450,8 @@ ENTRY(_sys_call_table) .long _sys_setfsuid /* 215 */ .long _sys_setfsgid .long _sys_pivot_root - .long _sys_ni_syscall /* sys_mincore */ - .long _sys_ni_syscall /* sys_madvise */ + .long _sys_mincore + .long _sys_madvise .long _sys_getdents64 /* 220 */ .long _sys_fcntl64 .long _sys_ni_syscall /* reserved for TUX */ @@ -1507,7 +1507,7 @@ ENTRY(_sys_call_table) .long _sys_utimes .long _sys_fadvise64_64 .long _sys_ni_syscall /* vserver */ - .long _sys_ni_syscall /* 275, mbind */ + .long _sys_mbind /* 275 */ .long _sys_ni_syscall /* get_mempolicy */ .long _sys_ni_syscall /* set_mempolicy */ .long _sys_mq_open -- cgit v1.2.3-70-g09d2 From d86bfb1600db38e8387beee0aaab4263cfd728a2 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 7 Jan 2010 04:11:17 +0000 Subject: Blackfin: initial XIP support Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig | 16 ++++++--- arch/blackfin/Makefile | 6 +++- arch/blackfin/boot/Makefile | 23 +++++++++--- arch/blackfin/include/asm/context.S | 10 ++++++ arch/blackfin/include/asm/sections.h | 3 ++ arch/blackfin/kernel/cplb-mpu/cplbinit.c | 9 +++++ arch/blackfin/kernel/cplb-nompu/cplbinit.c | 9 +++++ arch/blackfin/kernel/entry.S | 8 ++--- arch/blackfin/kernel/setup.c | 16 +++++++-- arch/blackfin/kernel/vmlinux.lds.S | 57 ++++++++++++++++++++++++++++++ arch/blackfin/mach-common/entry.S | 17 ++++----- arch/blackfin/mach-common/head.S | 5 +++ arch/blackfin/mach-common/interrupt.S | 10 +++--- 13 files changed, 160 insertions(+), 29 deletions(-) (limited to 'arch/blackfin/mach-common/entry.S') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index c0d6d966ade..f46db59eac8 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -26,9 +26,9 @@ config BLACKFIN select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER select HAVE_IDE - select HAVE_KERNEL_GZIP - select HAVE_KERNEL_BZIP2 - select HAVE_KERNEL_LZMA + select HAVE_KERNEL_GZIP if RAMKERNEL + select HAVE_KERNEL_BZIP2 if RAMKERNEL + select HAVE_KERNEL_LZMA if RAMKERNEL select HAVE_OPROFILE select ARCH_WANT_OPTIONAL_GPIOLIB @@ -407,10 +407,18 @@ config BOOT_LOAD config ROM_BASE hex "Kernel ROM Base" depends on ROMKERNEL - default "0x20040000" + default "0x20040040" range 0x20000000 0x20400000 if !(BF54x || BF561) range 0x20000000 0x30000000 if (BF54x || BF561) help + Make sure your ROM base does not include any file-header + information that is prepended to the kernel. + + For example, the bootable U-Boot format (created with + mkimage) has a 64 byte header (0x40). So while the image + you write to flash might start at say 0x20080000, you have + to add 0x40 to get the kernel's ROM base as it will come + after the header. comment "Clock/PLL Setup" diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile index d4c7177e765..ba84206d055 100644 --- a/arch/blackfin/Makefile +++ b/arch/blackfin/Makefile @@ -14,6 +14,9 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -S GZFLAGS := -9 KBUILD_CFLAGS += $(call cc-option,-mno-fdpic) +ifeq ($(CONFIG_ROMKERNEL),y) +KBUILD_CFLAGS += -mlong-calls +endif KBUILD_AFLAGS += $(call cc-option,-mno-fdpic) CFLAGS_MODULE += -mlong-calls LDFLAGS_MODULE += -m elf32bfin @@ -138,7 +141,7 @@ archclean: INSTALL_PATH ?= /tftpboot boot := arch/$(ARCH)/boot -BOOT_TARGETS = vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma +BOOT_TARGETS = vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma vmImage.xip PHONY += $(BOOT_TARGETS) install KBUILD_IMAGE := $(boot)/vmImage @@ -156,6 +159,7 @@ define archhelp echo ' vmImage.bz2 - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.bz2)' echo '* vmImage.gz - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.gz)' echo ' vmImage.lzma - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.lzma)' + echo ' vmImage.xip - XIP Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.xip)' echo ' install - Install kernel using' echo ' (your) ~/bin/$(INSTALLKERNEL) or' echo ' (distribution) PATH: $(INSTALLKERNEL) or' diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile index e9c48c6f8c1..d1b3d6051fd 100644 --- a/arch/blackfin/boot/Makefile +++ b/arch/blackfin/boot/Makefile @@ -8,14 +8,18 @@ MKIMAGE := $(srctree)/scripts/mkuboot.sh -targets := vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma -extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma +targets := vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma vmImage.xip +extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xip + +UIMAGE_OPTS-y := +UIMAGE_OPTS-$(CONFIG_RAMKERNEL) += -a $(CONFIG_BOOT_LOAD) +UIMAGE_OPTS-$(CONFIG_ROMKERNEL) += -a $(CONFIG_ROM_BASE) -x quiet_cmd_uimage = UIMAGE $@ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \ - -C $(2) -n '$(MACHINE)-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \ + -C $(2) -n '$(MACHINE)-$(KERNELRELEASE)' \ -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \ - -d $< $@ + $(UIMAGE_OPTS-y) -d $< $@ $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) @@ -29,6 +33,12 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE $(call if_changed,lzma) +# The mkimage tool wants 64bytes prepended to the image +quiet_cmd_mk_bin_xip = BIN $@ + cmd_mk_bin_xip = ( printf '%64s' | tr ' ' '\377' ; cat $< ) > $@ +$(obj)/vmlinux.bin.xip: $(obj)/vmlinux.bin FORCE + $(call if_changed,mk_bin_xip) + $(obj)/vmImage.bin: $(obj)/vmlinux.bin $(call if_changed,uimage,none) @@ -41,10 +51,15 @@ $(obj)/vmImage.gz: $(obj)/vmlinux.bin.gz $(obj)/vmImage.lzma: $(obj)/vmlinux.bin.lzma $(call if_changed,uimage,lzma) +$(obj)/vmImage.xip: $(obj)/vmlinux.bin.xip + $(call if_changed,uimage,none) + suffix-y := bin suffix-$(CONFIG_KERNEL_GZIP) := gz suffix-$(CONFIG_KERNEL_BZIP2) := bz2 suffix-$(CONFIG_KERNEL_LZMA) := lzma +suffix-$(CONFIG_ROMKERNEL) := xip + $(obj)/vmImage: $(obj)/vmImage.$(suffix-y) @ln -sf $(notdir $<) $@ diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S index 5dffaf582a2..fada8e974a7 100644 --- a/arch/blackfin/include/asm/context.S +++ b/arch/blackfin/include/asm/context.S @@ -374,3 +374,13 @@ (R7:0, P5:0) = [SP++]; .endm + +.macro pseudo_long_call func:req, scratch:req +#ifdef CONFIG_ROMKERNEL + \scratch\().l = \func; + \scratch\().h = \func; + call (\scratch); +#else + call \func; +#endif +.endm diff --git a/arch/blackfin/include/asm/sections.h b/arch/blackfin/include/asm/sections.h index 42f6c53c59c..14a3e66d916 100644 --- a/arch/blackfin/include/asm/sections.h +++ b/arch/blackfin/include/asm/sections.h @@ -21,6 +21,9 @@ extern unsigned long memory_start, memory_end, physical_mem_end; extern char _stext_l1[], _etext_l1[], _text_l1_lma[], __weak _text_l1_len[]; extern char _sdata_l1[], _edata_l1[], _sbss_l1[], _ebss_l1[], _data_l1_lma[], __weak _data_l1_len[]; +#ifdef CONFIG_ROMKERNEL +extern char _data_lma[], _data_len[], _sinitdata[], _einitdata[], _init_data_lma[], _init_data_len[]; +#endif extern char _sdata_b_l1[], _edata_b_l1[], _sbss_b_l1[], _ebss_b_l1[], _data_b_l1_lma[], __weak _data_b_l1_len[]; extern char _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c index 8d42b9e50df..30fd6417f06 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c @@ -64,6 +64,15 @@ void __init generate_cplb_tables_cpu(unsigned int cpu) icplb_tbl[cpu][i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0); } +#ifdef CONFIG_ROMKERNEL + /* Cover kernel XIP flash area */ + addr = CONFIG_ROM_BASE & ~(4 * 1024 * 1024 - 1); + dcplb_tbl[cpu][i_d].addr = addr; + dcplb_tbl[cpu][i_d++].data = d_data | CPLB_USER_RD; + icplb_tbl[cpu][i_i].addr = addr; + icplb_tbl[cpu][i_i++].data = i_data | CPLB_USER_RD; +#endif + /* Cover L1 memory. One 4M area for code and data each is enough. */ #if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0 dcplb_tbl[cpu][i_d].addr = get_l1_data_a_start_cpu(cpu); diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c index 282a7919821..bfe75af4e8b 100644 --- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c @@ -56,6 +56,15 @@ void __init generate_cplb_tables_cpu(unsigned int cpu) i_tbl[i_i++].data = SDRAM_IGENERIC | PAGE_SIZE_4MB; } +#ifdef CONFIG_ROMKERNEL + /* Cover kernel XIP flash area */ + addr = CONFIG_ROM_BASE & ~(4 * 1024 * 1024 - 1); + d_tbl[i_d].addr = addr; + d_tbl[i_d++].data = SDRAM_DGENERIC | PAGE_SIZE_4MB; + i_tbl[i_i].addr = addr; + i_tbl[i_i++].data = SDRAM_IGENERIC | PAGE_SIZE_4MB; +#endif + /* Cover L1 memory. One 4M area for code and data each is enough. */ if (cpu == 0) { if (L1_DATA_A_LENGTH || L1_DATA_B_LENGTH) { diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S index f27dc2292e1..686478f5f66 100644 --- a/arch/blackfin/kernel/entry.S +++ b/arch/blackfin/kernel/entry.S @@ -44,7 +44,7 @@ ENTRY(_ret_from_fork) sti r4; #endif /* CONFIG_IPIPE */ SP += -12; - call _schedule_tail; + pseudo_long_call _schedule_tail, p5; SP += 12; r0 = [sp + PT_IPEND]; cc = bittst(r0,1); @@ -79,7 +79,7 @@ ENTRY(_sys_vfork) r0 += 24; [--sp] = rets; SP += -12; - call _bfin_vfork; + pseudo_long_call _bfin_vfork, p2; SP += 12; rets = [sp++]; rts; @@ -90,7 +90,7 @@ ENTRY(_sys_clone) r0 += 24; [--sp] = rets; SP += -12; - call _bfin_clone; + pseudo_long_call _bfin_clone, p2; SP += 12; rets = [sp++]; rts; @@ -101,7 +101,7 @@ ENTRY(_sys_rt_sigreturn) r0 += 24; [--sp] = rets; SP += -12; - call _do_rt_sigreturn; + pseudo_long_call _do_rt_sigreturn, p2; SP += 12; rets = [sp++]; rts; diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index a0bc7d3e1bf..b54ba45db5f 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -220,6 +220,16 @@ void __init bfin_relocate_l1_mem(void) memcpy(_stext_l2, _l2_lma, l2_len); } +#ifdef CONFIG_ROMKERNEL +void __init bfin_relocate_xip_data(void) +{ + early_shadow_stamp(); + + memcpy(_sdata, _data_lma, (unsigned long)_data_len - THREAD_SIZE + sizeof(struct thread_info)); + memcpy(_sinitdata, _init_data_lma, (unsigned long)_init_data_len); +} +#endif + /* add_memory_region to memmap */ static void __init add_memory_region(unsigned long long start, unsigned long long size, int type) @@ -504,7 +514,7 @@ static __init void memory_setup(void) #endif unsigned long max_mem; - _rambase = (unsigned long)_stext; + _rambase = CONFIG_BOOT_LOAD; _ramstart = (unsigned long)_end; if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) { @@ -1261,8 +1271,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n", physical_mem_end >> 10, (void *)0, (void *)physical_mem_end); seq_printf(m, "kernel memory\t: %d kB (0x%p -> 0x%p)\n", - ((int)memory_end - (int)_stext) >> 10, - _stext, + ((int)memory_end - (int)_rambase) >> 10, + (void *)_rambase, (void *)memory_end); seq_printf(m, "\n"); diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index be4b1bbb391..984c7817239 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -15,7 +15,12 @@ _jiffies = _jiffies_64; SECTIONS { +#ifdef CONFIG_RAMKERNEL . = CONFIG_BOOT_LOAD; +#else + . = CONFIG_ROM_BASE; +#endif + /* Neither the text, ro_data or bss section need to be aligned * So pack them back to back */ @@ -31,6 +36,12 @@ SECTIONS LOCK_TEXT IRQENTRY_TEXT KPROBES_TEXT +#ifdef CONFIG_ROMKERNEL + __sinittext = .; + INIT_TEXT + __einittext = .; + EXIT_TEXT +#endif *(.text.*) *(.fixup) @@ -50,8 +61,14 @@ SECTIONS /* Just in case the first read only is a 32-bit access */ RO_DATA(4) + __rodata_end = .; +#ifdef CONFIG_ROMKERNEL + . = CONFIG_BOOT_LOAD; + .bss : AT(__rodata_end) +#else .bss : +#endif { . = ALIGN(4); ___bss_start = .; @@ -67,7 +84,11 @@ SECTIONS ___bss_stop = .; } +#if defined(CONFIG_ROMKERNEL) + .data : AT(LOADADDR(.bss) + SIZEOF(.bss)) +#else .data : +#endif { __sdata = .; /* This gets done first, so the glob doesn't suck it in */ @@ -94,6 +115,8 @@ SECTIONS __edata = .; } + __data_lma = LOADADDR(.data); + __data_len = SIZEOF(.data); /* The init section should be last, so when we free it, it goes into * the general memory pool, and (hopefully) will decrease fragmentation @@ -103,6 +126,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); ___init_begin = .; +#ifdef CONFIG_RAMKERNEL INIT_TEXT_SECTION(PAGE_SIZE) /* We have to discard exit text and such at runtime, not link time, to @@ -125,6 +149,35 @@ SECTIONS } .text_l1 L1_CODE_START : AT(LOADADDR(.exit.data) + SIZEOF(.exit.data)) +#else + .init.data : AT(__data_lma + __data_len) + { + __sinitdata = .; + INIT_DATA + INIT_SETUP(16) + INIT_CALLS + CON_INITCALL + SECURITY_INITCALL + INIT_RAM_FS + + . = ALIGN(4); + ___per_cpu_load = .; + ___per_cpu_start = .; + *(.data.percpu.first) + *(.data.percpu.page_aligned) + *(.data.percpu) + *(.data.percpu.shared_aligned) + ___per_cpu_end = .; + + EXIT_DATA + __einitdata = .; + } + __init_data_lma = LOADADDR(.init.data); + __init_data_len = SIZEOF(.init.data); + __init_data_end = .; + + .text_l1 L1_CODE_START : AT(__init_data_lma + __init_data_len) +#endif { . = ALIGN(4); __stext_l1 = .; @@ -205,7 +258,11 @@ SECTIONS /* Force trailing alignment of our init section so that when we * free our init memory, we don't leave behind a partial page. */ +#ifdef CONFIG_RAMKERNEL . = __l2_lma + __l2_len; +#else + . = __init_data_end; +#endif . = ALIGN(PAGE_SIZE); ___init_end = .; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 0df7ef200f9..ccfa7c490ff 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -405,7 +405,7 @@ ENTRY(_double_fault) r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; - call _double_fault_c; + pseudo_long_call _double_fault_c, p5; SP += 12; .L_double_fault_panic: JUMP .L_double_fault_panic @@ -447,7 +447,7 @@ ENTRY(_exception_to_level5) r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; - call _trap_c; + pseudo_long_call _trap_c, p4; SP += 12; /* If interrupts were off during the exception (IPEND[4] = 1), turn them off @@ -551,7 +551,7 @@ ENTRY(_kernel_execve) p0 = sp; sp += -16; [sp + 12] = p0; - call _do_execve; + pseudo_long_call _do_execve, p5; SP += 16; cc = r0 == 0; if ! cc jump .Lexecve_failed; @@ -704,7 +704,7 @@ ENTRY(_system_call) sp += 4; SP += -12; - call _schedule; + pseudo_long_call _schedule, p4; SP += 12; jump .Lresume_userspace_1; @@ -723,7 +723,7 @@ ENTRY(_system_call) r0 = sp; SP += -12; - call _do_notify_resume; + pseudo_long_call _do_notify_resume, p5; SP += 12; .Lsyscall_really_exit: @@ -736,7 +736,7 @@ ENDPROC(_system_call) * this symbol need not be global anyways, so ... */ _sys_trace: - call _syscall_trace; + pseudo_long_call _syscall_trace, p5; /* Execute the appropriate system call */ @@ -760,7 +760,7 @@ _sys_trace: SP += 24; [sp + PT_R0] = r0; - call _syscall_trace; + pseudo_long_call _syscall_trace, p5; jump .Lresume_userspace; ENDPROC(_sys_trace) @@ -1007,7 +1007,8 @@ ENTRY(_schedule_and_signal_from_int) r0 = sp; sp += -12; - call _finish_atomic_sections; + + pseudo_long_call _finish_atomic_sections, p5; sp += 12; jump.s .Lresume_userspace; ENDPROC(_schedule_and_signal_from_int) diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index cf037782c8a..4391621d904 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S @@ -186,6 +186,11 @@ ENTRY(__start) /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ call _bfin_relocate_l1_mem; + +#ifdef CONFIG_ROMKERNEL + call _bfin_relocate_xip_data; +#endif + #ifdef CONFIG_BFIN_KERNEL_CLOCK /* Only use on-chip scratch space for stack when absolutely required * to avoid Anomaly 05000227 ... we know the init_clocks() func only diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 8085ff1cce0..df984960cf9 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -109,10 +109,10 @@ __common_int_entry: cc = r0 == 0; if cc jump .Lcommon_restore_context; #else /* CONFIG_IPIPE */ - call _do_irq; + pseudo_long_call _do_irq, p2; SP += 12; #endif /* CONFIG_IPIPE */ - call _return_from_int; + pseudo_long_call _return_from_int, p2; .Lcommon_restore_context: RESTORE_CONTEXT rti; @@ -168,7 +168,7 @@ ENTRY(_evt_ivhw) r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; - call _trap_c; + pseudo_long_call _trap_c, p5; SP += 12; #ifdef EBIU_ERRMST @@ -179,7 +179,7 @@ ENTRY(_evt_ivhw) w[p0] = r0.l; #endif - call _ret_from_exception; + pseudo_long_call _ret_from_exception, p2; .Lcommon_restore_all_sys: RESTORE_ALL_SYS @@ -223,7 +223,7 @@ ENTRY(_evt_system_call) #ifdef CONFIG_FRAME_POINTER fp = 0; #endif - call _system_call; + pseudo_long_call _system_call, p2; jump .Lcommon_restore_context; ENDPROC(_evt_system_call) -- cgit v1.2.3-70-g09d2 From 441504df6b81302c06010083c8d63b1465ead405 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Tue, 19 Jan 2010 04:35:28 +0000 Subject: Blackfin: add support for irqflags tracing Signed-off-by: Yi Li Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/context.S | 12 ++++++++++++ arch/blackfin/mach-common/entry.S | 15 +++++++++++++++ arch/blackfin/mach-common/interrupt.S | 7 +++++++ 3 files changed, 34 insertions(+) (limited to 'arch/blackfin/mach-common/entry.S') diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S index fada8e974a7..1f9060395a0 100644 --- a/arch/blackfin/include/asm/context.S +++ b/arch/blackfin/include/asm/context.S @@ -72,6 +72,11 @@ sti r0; #else cli r0; +#endif +#ifdef CONFIG_TRACE_IRQFLAGS + sp += -12; + call _trace_hardirqs_off; + sp += 12; #endif [--sp] = RETI; /*orig_pc*/ /* Clear all L registers. */ @@ -279,6 +284,13 @@ RETN = [sp++]; RETX = [sp++]; RETI = [sp++]; + +#ifdef CONFIG_TRACE_IRQFLAGS + sp += -12; + call _trace_hardirqs_on; + sp += 12; +#endif + RETS = [sp++]; #ifdef CONFIG_SMP diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index ccfa7c490ff..1fa414f7852 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -965,6 +965,13 @@ ENTRY(_evt_evt14) sti r0; #else cli r0; +#endif +#ifdef CONFIG_TRACE_IRQFLAGS + [--sp] = rets; + sp += -12; + call _trace_hardirqs_off; + sp += 12; + rets = [sp++]; #endif [--sp] = RETI; SP += 4; @@ -989,6 +996,14 @@ ENTRY(_schedule_and_signal_from_int) p1 = rets; [sp + PT_RESERVED] = p1; +#ifdef CONFIG_TRACE_IRQFLAGS + /* trace_hardirqs_on() checks if all irqs are disabled. But here IRQ 15 + * is turned on, so disable all irqs. */ + cli r0; + sp += -12; + call _trace_hardirqs_on; + sp += 12; +#endif #ifdef CONFIG_SMP GET_PDA(p0, r0); /* Fetch current PDA (can't migrate to other CPU here) */ r0 = [p0 + PDA_IRQFLAGS]; diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index df984960cf9..0a0c088ead8 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -87,6 +87,13 @@ __common_int_entry: sti r1; #else cli r1; +#endif +#ifdef CONFIG_TRACE_IRQFLAGS + [--sp] = r0; + sp += -12; + call _trace_hardirqs_off; + sp += 12; + r0 = [sp++]; #endif [--sp] = RETI; /* orig_pc */ /* Clear all L registers. */ -- cgit v1.2.3-70-g09d2 From e8f263dfd32a784a816fe68956e564f8ede4a9fc Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 26 Jan 2010 07:33:53 +0000 Subject: Blackfin: initial tracehook support Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig | 1 + arch/blackfin/include/asm/ptrace.h | 23 +++++++++ arch/blackfin/include/asm/syscall.h | 96 +++++++++++++++++++++++++++++++++++++ arch/blackfin/kernel/ptrace.c | 66 +++++++------------------ arch/blackfin/kernel/signal.c | 14 ++---- arch/blackfin/mach-common/entry.S | 6 ++- 6 files changed, 144 insertions(+), 62 deletions(-) create mode 100644 arch/blackfin/include/asm/syscall.h (limited to 'arch/blackfin/mach-common/entry.S') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 970df5b5c52..c078849df7f 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -24,6 +24,7 @@ config RWSEM_XCHGADD_ALGORITHM config BLACKFIN def_bool y select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h index c1aebdb981c..aaa1c6c2bc1 100644 --- a/arch/blackfin/include/asm/ptrace.h +++ b/arch/blackfin/include/asm/ptrace.h @@ -24,6 +24,8 @@ #ifndef __ASSEMBLY__ +struct task_struct; + /* this struct defines the way the registers are stored on the stack during a system call. */ @@ -101,9 +103,30 @@ struct pt_regs { master interrupt enable. */ #define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1))) #define instruction_pointer(regs) ((regs)->pc) +#define user_stack_pointer(regs) ((regs)->usp) #define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); +#define arch_has_single_step() (1) +extern void user_enable_single_step(struct task_struct *child); +extern void user_disable_single_step(struct task_struct *child); +/* common code demands this function */ +#define ptrace_disable(child) user_disable_single_step(child) + +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + * + * Note: if a user thread is execve'd from kernel space, the + * kernel stack will not be empty on entry to the kernel, so + * ptracing these tasks will fail. + */ +#define task_pt_regs(task) \ + (struct pt_regs *) \ + ((unsigned long)task_stack_page(task) + \ + (THREAD_SIZE - sizeof(struct pt_regs))) + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/arch/blackfin/include/asm/syscall.h b/arch/blackfin/include/asm/syscall.h new file mode 100644 index 00000000000..4921a4815cc --- /dev/null +++ b/arch/blackfin/include/asm/syscall.h @@ -0,0 +1,96 @@ +/* + * Magic syscall break down functions + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __ASM_BLACKFIN_SYSCALL_H__ +#define __ASM_BLACKFIN_SYSCALL_H__ + +/* + * Blackfin syscalls are simple: + * enter: + * p0: syscall number + * r{0,1,2,3,4,5}: syscall args 0,1,2,3,4,5 + * exit: + * r0: return/error value + */ + +#include +#include +#include + +static inline long +syscall_get_nr(struct task_struct *task, struct pt_regs *regs) +{ + return regs->p0; +} + +static inline void +syscall_rollback(struct task_struct *task, struct pt_regs *regs) +{ + regs->p0 = regs->orig_p0; +} + +static inline long +syscall_get_error(struct task_struct *task, struct pt_regs *regs) +{ + return IS_ERR_VALUE(regs->r0) ? regs->r0 : 0; +} + +static inline long +syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) +{ + return regs->r0; +} + +static inline void +syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, + int error, long val) +{ + regs->r0 = error ? -error : val; +} + +/** + * syscall_get_arguments() + * @task: unused + * @regs: the register layout to extract syscall arguments from + * @i: first syscall argument to extract + * @n: number of syscall arguments to extract + * @args: array to return the syscall arguments in + * + * args[0] gets i'th argument, args[n - 1] gets the i+n-1'th argument + */ +static inline void +syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, unsigned long *args) +{ + /* + * Assume the ptrace layout doesn't change -- r5 is first in memory, + * then r4, ..., then r0. So we simply reverse the ptrace register + * array in memory to store into the args array. + */ + long *aregs = ®s->r0 - i; + + BUG_ON(i > 5 || i + n > 6); + + while (n--) + *args++ = *aregs--; +} + +/* See syscall_get_arguments() comments */ +static inline void +syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, const unsigned long *args) +{ + long *aregs = ®s->r0 - i; + + BUG_ON(i > 5 || i + n > 6); + + while (n--) + *aregs-- = *args++; +} + +#endif diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 92b4ca0b5af..0618b8287e3 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -1,6 +1,6 @@ /* * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * these modifications are Copyright 2004-2009 Analog Devices Inc. + * these modifications are Copyright 2004-2010 Analog Devices Inc. * * Licensed under the GPL-2 */ @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -32,25 +33,6 @@ * in exit.c or in signal.c. */ -/* Find the stack offset for a register, relative to thread.esp0. */ -#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) - -/* - * Get the address of the live pt_regs for the specified task. - * These are saved onto the top kernel stack when the process - * is not running. - * - * Note: if a user thread is execve'd from kernel space, the - * kernel stack will not be empty on entry to the kernel, so - * ptracing these tasks will fail. - */ -static inline struct pt_regs *task_pt_regs(struct task_struct *task) -{ - return (struct pt_regs *) - ((unsigned long)task_stack_page(task) + - (THREAD_SIZE - sizeof(struct pt_regs))); -} - /* * Get contents of register REGNO in task TASK. */ @@ -234,18 +216,13 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_bfin_native_view; } -void ptrace_enable(struct task_struct *child) +void user_enable_single_step(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); regs->syscfg |= SYSCFG_SSSTEP; } -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. - */ -void ptrace_disable(struct task_struct *child) +void user_disable_single_step(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); regs->syscfg &= ~SYSCFG_SSSTEP; @@ -412,27 +389,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -asmlinkage void syscall_trace(void) +asmlinkage int syscall_trace_enter(struct pt_regs *regs) { - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - - if (!(current->ptrace & PT_PTRACED)) - return; - - /* the 0x80 provides a way for the tracing parent to distinguish - * between a syscall stop and SIGTRAP delivery - */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + int ret = 0; + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + ret = tracehook_report_syscall_entry(regs); + + return ret; +} + +asmlinkage void syscall_trace_leave(struct pt_regs *regs) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, 0); } diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index e0fd63e9e38..e60990c0a1f 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Analog Devices Inc. + * Copyright 2004-2010 Analog Devices Inc. * * Licensed under the GPL-2 or later */ @@ -206,16 +206,6 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, regs->r1 = (unsigned long)(&frame->info); regs->r2 = (unsigned long)(&frame->uc); - /* - * Clear the trace flag when entering the signal handler, but - * notify any tracer that was single-stepping it. The tracer - * may want to single-step inside the handler too. - */ - if (regs->syscfg & TRACE_BITS) { - regs->syscfg &= ~TRACE_BITS; - ptrace_notify(SIGTRAP); - } - return 0; give_sigsegv: @@ -315,6 +305,8 @@ asmlinkage void do_signal(struct pt_regs *regs) * clear the TIF_RESTORE_SIGMASK flag */ if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, 1); } return; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 1fa414f7852..0df5b834d34 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -736,7 +736,8 @@ ENDPROC(_system_call) * this symbol need not be global anyways, so ... */ _sys_trace: - pseudo_long_call _syscall_trace, p5; + r0 = sp; + pseudo_long_call _syscall_trace_enter, p5; /* Execute the appropriate system call */ @@ -760,7 +761,8 @@ _sys_trace: SP += 24; [sp + PT_R0] = r0; - pseudo_long_call _syscall_trace, p5; + r0 = sp; + pseudo_long_call _syscall_trace_leave, p5; jump .Lresume_userspace; ENDPROC(_sys_trace) -- cgit v1.2.3-70-g09d2 From 600482c13d3d3612d71f39d8aaec47f63aafa801 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 17 Feb 2010 10:44:22 +0000 Subject: Blackfin: fix single stepping over system calls On Blackfin systems, the hardware single step exception triggers before the system call exception, so we need to save this info to process it later on. Otherwise, single stepping in userspace misses a few insns right after the system call. This is based a bit on the SuperH code added in commit 4b505db9c4c72dbd. Reported-by: Roland McGrath Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/thread_info.h | 2 ++ arch/blackfin/kernel/ptrace.c | 11 +++++++++-- arch/blackfin/kernel/signal.c | 3 ++- arch/blackfin/mach-common/entry.S | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) (limited to 'arch/blackfin/mach-common/entry.S') diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h index 0149c92ceeb..e9a5614cdbb 100644 --- a/arch/blackfin/include/asm/thread_info.h +++ b/arch/blackfin/include/asm/thread_info.h @@ -103,6 +103,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_FREEZE 6 /* is freezing for suspend */ #define TIF_IRQ_SYNC 7 /* sync pipeline stage */ #define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ +#define TIF_SINGLESTEP 9 /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<syscfg |= SYSCFG_SSSTEP; + + set_tsk_thread_flag(child, TIF_SINGLESTEP); } void user_disable_single_step(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); regs->syscfg &= ~SYSCFG_SSSTEP; + + clear_tsk_thread_flag(child, TIF_SINGLESTEP); } long arch_ptrace(struct task_struct *child, long request, long addr, long data) @@ -401,6 +405,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) asmlinkage void syscall_trace_leave(struct pt_regs *regs) { - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, 0); + int step; + + step = test_thread_flag(TIF_SINGLESTEP); + if (step || test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, step); } diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index e60990c0a1f..28d6f28c058 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -306,7 +306,8 @@ asmlinkage void do_signal(struct pt_regs *regs) if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); - tracehook_signal_handler(signr, &info, &ka, regs, 1); + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } return; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 0df5b834d34..0a9e458d0f7 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -642,6 +642,8 @@ ENTRY(_system_call) r7 = [p2+TI_FLAGS]; CC = BITTST(r7,TIF_SYSCALL_TRACE); if CC JUMP _sys_trace; + CC = BITTST(r7,TIF_SINGLESTEP); + if CC JUMP _sys_trace; /* Execute the appropriate system call */ -- cgit v1.2.3-70-g09d2 From 9e228ee9eae97b533d3b3133f76478c70dbd4294 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 12 Feb 2010 07:24:34 +0000 Subject: Blackfin: check for bad syscalls after tracing it We want to report all system calls (even invalid ones) to the tracing layers, so check the NR only after we've notified. Signed-off-by: Mike Frysinger --- arch/blackfin/mach-common/entry.S | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'arch/blackfin/mach-common/entry.S') diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 0a9e458d0f7..6c20044c7f4 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -626,13 +626,6 @@ ENTRY(_system_call) p0 = [sp + PT_ORIG_P0]; #endif /* CONFIG_IPIPE */ - /* Check the System Call */ - r7 = __NR_syscall; - /* System call number is passed in P0 */ - r6 = p0; - cc = r6 < r7; - if ! cc jump .Lbadsys; - /* are we tracing syscalls?*/ r7 = sp; r6.l = lo(ALIGN_PAGE_MASK); @@ -645,6 +638,12 @@ ENTRY(_system_call) CC = BITTST(r7,TIF_SINGLESTEP); if CC JUMP _sys_trace; + /* Make sure the system call # is valid */ + p4 = __NR_syscall; + /* System call number is passed in P0 */ + cc = p4 <= p0; + if cc jump .Lbadsys; + /* Execute the appropriate system call */ p4 = p0; @@ -741,9 +740,14 @@ _sys_trace: r0 = sp; pseudo_long_call _syscall_trace_enter, p5; - /* Execute the appropriate system call */ - + /* Make sure the system call # is valid */ p4 = [SP + PT_P0]; + p3 = __NR_syscall; + cc = p3 <= p4; + r0 = -ENOSYS; + if cc jump .Lsys_trace_badsys; + + /* Execute the appropriate system call */ p5.l = _sys_call_table; p5.h = _sys_call_table; p5 = p5 + (p4 << 2); @@ -761,6 +765,7 @@ _sys_trace: SP += -12; call (p5); SP += 24; +.Lsys_trace_badsys: [sp + PT_R0] = r0; r0 = sp; -- cgit v1.2.3-70-g09d2 From 2943bff69e3728cfd69841537120125f9373bb28 Mon Sep 17 00:00:00 2001 From: Robin Getz Date: Thu, 25 Feb 2010 18:16:52 +0000 Subject: Blackfin: fix anomaly 283 handling with exact hardware error The exact hardware error handling code was added before the workaround for anomaly 283 which caused the anomaly to be triggered in some cases (an infinite core stall). So re-order the code to avoid this. Reported-by: Andrew Rook Signed-off-by: Robin Getz Signed-off-by: Mike Frysinger --- arch/blackfin/mach-common/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/blackfin/mach-common/entry.S') diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 6c20044c7f4..a5847f5d67c 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -482,6 +482,8 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ [--sp] = ASTAT; [--sp] = (R7:6,P5:4); + ANOMALY_283_315_WORKAROUND(p5, r7) + #ifdef CONFIG_EXACT_HWERR /* Make sure all pending read/writes complete. This will ensure any * accesses which could cause hardware errors completes, and signal @@ -492,8 +494,6 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ ssync; #endif - ANOMALY_283_315_WORKAROUND(p5, r7) - #ifdef CONFIG_DEBUG_DOUBLEFAULT /* * Save these registers, as they are only valid in exception context -- cgit v1.2.3-70-g09d2