From f84f52a5c15db7d14a534815f27253b001735183 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Thu, 5 Jan 2012 15:51:13 +1000 Subject: m68knommu: clean up linker script There is a lot of years of collected cruft in the m68knommu linker script. Clean it all up and use the well defined linker script support macros. Support is maintained for building both ROM/FLASH based and RAM based setups. No major changes to section layouts, though the rodata section is now lumped in with the read/write data section. Signed-off-by: Greg Ungerer --- arch/m68k/kernel/vmlinux-nommu.lds | 200 +++++++++---------------------------- 1 file changed, 49 insertions(+), 151 deletions(-) (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds index 8e66ccb..40e02d9 100644 --- a/arch/m68k/kernel/vmlinux-nommu.lds +++ b/arch/m68k/kernel/vmlinux-nommu.lds @@ -1,195 +1,93 @@ /* * vmlinux.lds.S -- master linker script for m68knommu arch * - * (C) Copyright 2002-2006, Greg Ungerer + * (C) Copyright 2002-2012, Greg Ungerer * * This linker script is equipped to build either ROM loaded or RAM * run kernels. */ -#include -#include -#include - #if defined(CONFIG_RAMKERNEL) -#define RAM_START CONFIG_KERNELBASE -#define RAM_LENGTH (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE) -#define TEXT ram -#define DATA ram -#define INIT ram -#define BSSS ram -#endif -#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL) -#define RAM_START CONFIG_RAMBASE -#define RAM_LENGTH CONFIG_RAMSIZE -#define ROMVEC_START CONFIG_ROMVEC -#define ROMVEC_LENGTH CONFIG_ROMVECSIZE -#define ROM_START CONFIG_ROMSTART -#define ROM_LENGTH CONFIG_ROMSIZE -#define TEXT rom -#define DATA ram -#define INIT ram -#define BSSS ram +#define KTEXT_ADDR CONFIG_KERNELBASE #endif - -#ifndef DATA_ADDR -#define DATA_ADDR +#if defined(CONFIG_ROMKERNEL) +#define KTEXT_ADDR CONFIG_ROMSTART +#define KDATA_ADDR CONFIG_KERNELBASE +#define LOAD_OFFSET KDATA_ADDR + (ADDR(.text) + SIZEOF(.text)) #endif +#include +#include +#include OUTPUT_ARCH(m68k) ENTRY(_start) -MEMORY { - ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH -#ifdef ROM_START - romvec : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH - rom : ORIGIN = ROM_START, LENGTH = ROM_LENGTH -#endif -} - jiffies = jiffies_64 + 4; SECTIONS { -#ifdef ROMVEC_START - . = ROMVEC_START ; +#ifdef CONFIG_ROMVEC + . = CONFIG_ROMVEC; .romvec : { - __rom_start = . ; + __rom_start = .; _romvec = .; + *(.romvec) *(.data..initvect) - } > romvec + } #endif + . = KTEXT_ADDR; + + _text = .; + _stext = .; .text : { - _text = .; - _stext = . ; HEAD_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT - *(.text..lock) *(.fixup) + . = ALIGN(16); + } + _etext = .; + +#ifdef KDATA_ADDR + . = KDATA_ADDR; +#endif + + _sdata = .; + RO_DATA_SECTION(PAGE_SIZE) + RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) + _edata = .; - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - - *(.rodata) *(.rodata.*) - *(__vermagic) /* Kernel version magic */ - *(.rodata1) - *(.rodata.str1.1) - - /* Kernel symbol table: Normal symbols */ - . = ALIGN(4); - __start___ksymtab = .; - *(SORT(___ksymtab+*)) - __stop___ksymtab = .; - - /* Kernel symbol table: GPL-only symbols */ - __start___ksymtab_gpl = .; - *(SORT(___ksymtab_gpl+*)) - __stop___ksymtab_gpl = .; - - /* Kernel symbol table: Normal unused symbols */ - __start___ksymtab_unused = .; - *(SORT(___ksymtab_unused+*)) - __stop___ksymtab_unused = .; - - /* Kernel symbol table: GPL-only unused symbols */ - __start___ksymtab_unused_gpl = .; - *(SORT(___ksymtab_unused_gpl+*)) - __stop___ksymtab_unused_gpl = .; - - /* Kernel symbol table: GPL-future symbols */ - __start___ksymtab_gpl_future = .; - *(SORT(___ksymtab_gpl_future+*)) - __stop___ksymtab_gpl_future = .; - - /* Kernel symbol table: Normal symbols */ - __start___kcrctab = .; - *(SORT(___kcrctab+*)) - __stop___kcrctab = .; - - /* Kernel symbol table: GPL-only symbols */ - __start___kcrctab_gpl = .; - *(SORT(___kcrctab_gpl+*)) - __stop___kcrctab_gpl = .; - - /* Kernel symbol table: Normal unused symbols */ - __start___kcrctab_unused = .; - *(SORT(___kcrctab_unused+*)) - __stop___kcrctab_unused = .; - - /* Kernel symbol table: GPL-only unused symbols */ - __start___kcrctab_unused_gpl = .; - *(SORT(___kcrctab_unused_gpl+*)) - __stop___kcrctab_unused_gpl = .; - - /* Kernel symbol table: GPL-future symbols */ - __start___kcrctab_gpl_future = .; - *(SORT(___kcrctab_gpl_future+*)) - __stop___kcrctab_gpl_future = .; - - /* Kernel symbol table: strings */ - *(__ksymtab_strings) - - /* Built-in module parameters */ - . = ALIGN(4) ; - __start___param = .; - *(__param) - __stop___param = .; - - /* Built-in module versions */ - . = ALIGN(4) ; - __start___modver = .; - *(__modver) - __stop___modver = .; - - . = ALIGN(4) ; - _etext = . ; - } > TEXT - - .data DATA_ADDR : { - . = ALIGN(4); - _sdata = . ; - DATA_DATA - CACHELINE_ALIGNED_DATA(32) - PAGE_ALIGNED_DATA(PAGE_SIZE) - *(.data..shared_aligned) - INIT_TASK_DATA(THREAD_SIZE) - _edata = . ; - } > DATA + EXCEPTION_TABLE(16) + NOTES + . = ALIGN(PAGE_SIZE); + __init_begin = .; + INIT_TEXT_SECTION(PAGE_SIZE) + INIT_DATA_SECTION(16) + PERCPU_SECTION(16) .m68k_fixup : { __start_fixup = .; *(.m68k_fixup) __stop_fixup = .; - } > DATA - NOTES > DATA - - .init.text : { - . = ALIGN(PAGE_SIZE); - __init_begin = .; - } > INIT - INIT_TEXT_SECTION(PAGE_SIZE) > INIT - INIT_DATA_SECTION(16) > INIT + } .init.data : { . = ALIGN(PAGE_SIZE); __init_end = .; - } > INIT - - .bss : { - . = ALIGN(4); - _sbss = . ; - *(.bss) - *(COMMON) - . = ALIGN(4) ; - _ebss = . ; - _end = . ; - } > BSSS + } + + _sbss = .; + BSS_SECTION(0, 0, 0) + _ebss = .; + + _end = .; + + STABS_DEBUG + .comment 0 : { *(.comment) } + /* Sections to be discarded */ DISCARDS } -- cgit v1.1 From 9517746131f62294ddd922bcd288415be5104c23 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Mon, 23 Jan 2012 13:25:56 +1000 Subject: m68knommu: make persistent clock code consistent with m68k The read_persistent_clock() code is different on m68knommu, for really no reason. With a few changes to support function names and some code re-organization the code can be made the same. This will make it easier to merge the arch/m68k/kernel/time.c for m68k and m68knommu in a future patch. Signed-off-by: Greg Ungerer --- arch/m68k/kernel/setup_no.c | 2 ++ arch/m68k/kernel/time_no.c | 36 ++++++++++++------------------------ 2 files changed, 14 insertions(+), 24 deletions(-) (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index ca3df0d..8394b56 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ char __initdata command_line[COMMAND_LINE_SIZE]; /* machine dependent timer functions */ int (*mach_set_clock_mmss)(unsigned long); +int (*mach_hwclk) (int, struct rtc_time*); /* machine dependent reboot functions */ void (*mach_reset)(void); diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c index 3ef0f77..ca3b3b4 100644 --- a/arch/m68k/kernel/time_no.c +++ b/arch/m68k/kernel/time_no.c @@ -20,15 +20,11 @@ #include #include #include +#include #include #include -#define TICK_SIZE (tick_nsec / 1000) - -/* machine dependent timer functions */ -void (*mach_gettod)(int*, int*, int*, int*, int*, int*); - static inline int set_rtc_mmss(unsigned long nowtime) { if (mach_set_clock_mmss) @@ -55,28 +51,20 @@ irqreturn_t arch_timer_interrupt(int irq, void *dummy) } #endif -static unsigned long read_rtc_mmss(void) -{ - unsigned int year, mon, day, hour, min, sec; - - if (mach_gettod) { - mach_gettod(&year, &mon, &day, &hour, &min, &sec); - if ((year += 1900) < 1970) - year += 100; - } else { - year = 1970; - mon = day = 1; - hour = min = sec = 0; - } - - - return mktime(year, mon, day, hour, min, sec); -} - void read_persistent_clock(struct timespec *ts) { - ts->tv_sec = read_rtc_mmss(); + struct rtc_time time; + ts->tv_sec = 0; ts->tv_nsec = 0; + + if (mach_hwclk) { + mach_hwclk(0, &time); + + if ((time.tm_year += 1900) < 1970) + time.tm_year += 100; + ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, + time.tm_hour, time.tm_min, time.tm_sec); + } } int update_persistent_clock(struct timespec now) -- cgit v1.1 From 35aefb2645d1ae7576699b2d7b66d6c9503113fc Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Mon, 23 Jan 2012 15:34:58 +1000 Subject: m68knommu: modify timer init code to make it consistent with m68k code With a few small changes we can make the m68knommu timer init code the same as the m68k code. By using the mach_sched_init function pointer and reworking the current timer initializers to keep track of the common m68k timer_interrupt() handler we end up with almost identical code for m68knommu. This will allow us to more easily merge the mmu and non-mmu m68k time.c in future patches. Signed-off-by: Greg Ungerer --- arch/m68k/kernel/setup_no.c | 1 + arch/m68k/kernel/time_no.c | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index 8394b56..7dc186b 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -48,6 +48,7 @@ EXPORT_SYMBOL(memory_end); char __initdata command_line[COMMAND_LINE_SIZE]; /* machine dependent timer functions */ +void (*mach_sched_init)(irq_handler_t handler) __initdata = NULL; int (*mach_set_clock_mmss)(unsigned long); int (*mach_hwclk) (int, struct rtc_time*); diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c index ca3b3b4..5fa42f1 100644 --- a/arch/m68k/kernel/time_no.c +++ b/arch/m68k/kernel/time_no.c @@ -32,12 +32,11 @@ static inline int set_rtc_mmss(unsigned long nowtime) return -1; } -#ifndef CONFIG_GENERIC_CLOCKEVENTS /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "xtime_update()" routine every clocktick */ -irqreturn_t arch_timer_interrupt(int irq, void *dummy) +static irqreturn_t timer_interrupt(int irq, void *dummy) { if (current->pid) @@ -49,7 +48,6 @@ irqreturn_t arch_timer_interrupt(int irq, void *dummy) return(IRQ_HANDLED); } -#endif void read_persistent_clock(struct timespec *ts) { @@ -72,7 +70,7 @@ int update_persistent_clock(struct timespec now) return set_rtc_mmss(now.tv_sec); } -void time_init(void) +void __init time_init(void) { - hw_timer_init(); + mach_sched_init(timer_interrupt); } -- cgit v1.1 From b6c58e8af0d1188ce826bb35444f11752000e5e1 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 22 Feb 2012 13:41:11 +1000 Subject: m68knommu: remove unused CONFIG_GENERIC_CMOS_UPDATE option The CONFIG_GENERIC_CMOS_UPDATE switch is always enabled for the non-MMU m68k case. But the underlying code to support it, update_persistent_clock(), doesn't end up doing anything on the currently supported non-MMU platforms. No platforms supply the necessary function support for writing back the RTC. So lets remove this option and support code. This also brings m68knommu in line with the m68k, which doesn't enabled this switch either. Signed-off-by: Greg Ungerer --- arch/m68k/kernel/time_no.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c index 5fa42f1..87c7acd 100644 --- a/arch/m68k/kernel/time_no.c +++ b/arch/m68k/kernel/time_no.c @@ -65,11 +65,6 @@ void read_persistent_clock(struct timespec *ts) } } -int update_persistent_clock(struct timespec now) -{ - return set_rtc_mmss(now.tv_sec); -} - void __init time_init(void) { mach_sched_init(timer_interrupt); -- cgit v1.1 From fa7f9e7fade84571800977782b04e07cb0a5dae3 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Mon, 23 Jan 2012 16:23:33 +1000 Subject: m68k: merge mmu and non-mmu versions of time.c There is only trivial differences between the mmu time_mm.c and non-mmu time_no.c files. Merge them back into a single time.c. Signed-off-by: Greg Ungerer Acked-by: Geert Uytterhoeven --- arch/m68k/kernel/time.c | 123 +++++++++++++++++++++++++++++++++++++++++++-- arch/m68k/kernel/time_mm.c | 114 ----------------------------------------- arch/m68k/kernel/time_no.c | 71 -------------------------- 3 files changed, 118 insertions(+), 190 deletions(-) delete mode 100644 arch/m68k/kernel/time_mm.c delete mode 100644 arch/m68k/kernel/time_no.c (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 75ab79b..adfcefb 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -1,5 +1,118 @@ -#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE) -#include "time_mm.c" -#else -#include "time_no.c" -#endif +/* + * linux/arch/m68k/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the m68k-specific time handling details. + * Most of the stuff is located in the machine specific files. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +static inline int set_rtc_mmss(unsigned long nowtime) +{ + if (mach_set_clock_mmss) + return mach_set_clock_mmss (nowtime); + return -1; +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "xtime_update()" routine every clocktick + */ +static irqreturn_t timer_interrupt(int irq, void *dummy) +{ + xtime_update(1); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); + +#ifdef CONFIG_HEARTBEAT + /* use power LED as a heartbeat instead -- much more useful + for debugging -- based on the version for PReP by Cort */ + /* acts like an actual heart beat -- ie thump-thump-pause... */ + if (mach_heartbeat) { + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<tv_sec = 0; + ts->tv_nsec = 0; + + if (mach_hwclk) { + mach_hwclk(0, &time); + + if ((time.tm_year += 1900) < 1970) + time.tm_year += 100; + ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, + time.tm_hour, time.tm_min, time.tm_sec); + } +} + +void __init time_init(void) +{ + mach_sched_init(timer_interrupt); +} + +#ifdef CONFIG_M68KCLASSIC + +u32 arch_gettimeoffset(void) +{ + return mach_gettimeoffset() * 1000; +} + +static int __init rtc_init(void) +{ + struct platform_device *pdev; + + if (!mach_hwclk) + return -ENODEV; + + pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} + +module_init(rtc_init); + +#endif /* CONFIG_M68KCLASSIC */ diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c deleted file mode 100644 index 18b34ee..0000000 --- a/arch/m68k/kernel/time_mm.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * linux/arch/m68k/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * This file contains the m68k-specific time handling details. - * Most of the stuff is located in the machine specific files. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -static inline int set_rtc_mmss(unsigned long nowtime) -{ - if (mach_set_clock_mmss) - return mach_set_clock_mmss (nowtime); - return -1; -} - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "xtime_update()" routine every clocktick - */ -static irqreturn_t timer_interrupt(int irq, void *dummy) -{ - xtime_update(1); - update_process_times(user_mode(get_irq_regs())); - profile_tick(CPU_PROFILING); - -#ifdef CONFIG_HEARTBEAT - /* use power LED as a heartbeat instead -- much more useful - for debugging -- based on the version for PReP by Cort */ - /* acts like an actual heart beat -- ie thump-thump-pause... */ - if (mach_heartbeat) { - static unsigned cnt = 0, period = 0, dist = 0; - - if (cnt == 0 || cnt == dist) - mach_heartbeat( 1 ); - else if (cnt == 7 || cnt == dist+7) - mach_heartbeat( 0 ); - - if (++cnt > period) { - cnt = 0; - /* The hyperbolic function below modifies the heartbeat period - * length in dependency of the current (5min) load. It goes - * through the points f(0)=126, f(1)=86, f(5)=51, - * f(inf)->30. */ - period = ((672<tv_sec = 0; - ts->tv_nsec = 0; - - if (mach_hwclk) { - mach_hwclk(0, &time); - - if ((time.tm_year += 1900) < 1970) - time.tm_year += 100; - ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, - time.tm_hour, time.tm_min, time.tm_sec); - } -} - -void __init time_init(void) -{ - mach_sched_init(timer_interrupt); -} - -u32 arch_gettimeoffset(void) -{ - return mach_gettimeoffset() * 1000; -} - -static int __init rtc_init(void) -{ - struct platform_device *pdev; - - if (!mach_hwclk) - return -ENODEV; - - pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - return 0; -} - -module_init(rtc_init); diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c deleted file mode 100644 index 87c7acd..0000000 --- a/arch/m68k/kernel/time_no.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * This file contains the m68k-specific time handling details. - * Most of the stuff is located in the machine specific files. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static inline int set_rtc_mmss(unsigned long nowtime) -{ - if (mach_set_clock_mmss) - return mach_set_clock_mmss (nowtime); - return -1; -} - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "xtime_update()" routine every clocktick - */ -static irqreturn_t timer_interrupt(int irq, void *dummy) -{ - - if (current->pid) - profile_tick(CPU_PROFILING); - - xtime_update(1); - - update_process_times(user_mode(get_irq_regs())); - - return(IRQ_HANDLED); -} - -void read_persistent_clock(struct timespec *ts) -{ - struct rtc_time time; - ts->tv_sec = 0; - ts->tv_nsec = 0; - - if (mach_hwclk) { - mach_hwclk(0, &time); - - if ((time.tm_year += 1900) < 1970) - time.tm_year += 100; - ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, - time.tm_hour, time.tm_min, time.tm_sec); - } -} - -void __init time_init(void) -{ - mach_sched_init(timer_interrupt); -} -- cgit v1.1 From 397ac99c6cef38cdf260440635c8873f51109c34 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Wed, 22 Feb 2012 13:51:22 +1000 Subject: m68k: remove dead timer code The set_rtc_mmss() function is defined "static inline" but is never used in this file. Remove it. Signed-off-by: Greg Ungerer Acked-by: Geert Uytterhoeven --- arch/m68k/kernel/time.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index adfcefb..d7deb7f 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -28,13 +28,6 @@ #include #include -static inline int set_rtc_mmss(unsigned long nowtime) -{ - if (mach_set_clock_mmss) - return mach_set_clock_mmss (nowtime); - return -1; -} - /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "xtime_update()" routine every clocktick -- cgit v1.1 From 43dec91f4dbf4adbd2ffc9a86e34fa76ab1f5a05 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Tue, 24 Jan 2012 16:16:35 +1000 Subject: m68k: merge the mmu and non-mmu versions of ptrace.c Most of the code in the non-mmu ptrace_no.c file is the same as the mmu version ptrace_mm.c. So merge them back into a single file. Signed-off-by: Greg Ungerer Acked-by: Geert Uytterhoeven --- arch/m68k/kernel/ptrace.c | 306 ++++++++++++++++++++++++++++++++++++++++++- arch/m68k/kernel/ptrace_mm.c | 295 ----------------------------------------- arch/m68k/kernel/ptrace_no.c | 255 ------------------------------------ 3 files changed, 303 insertions(+), 553 deletions(-) delete mode 100644 arch/m68k/kernel/ptrace_mm.c delete mode 100644 arch/m68k/kernel/ptrace_no.c (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 07a4175..149a05f 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -1,5 +1,305 @@ +/* + * linux/arch/m68k/kernel/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * 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 +#include +#include + +#include +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SR the user has access to. */ +/* 1 = access 0 = no access */ +#define SR_MASK 0x001f + +/* sets the trace bits. */ +#define TRACE_BITS 0xC000 +#define T1_BIT 0x8000 +#define T0_BIT 0x4000 + +/* Find the stack offset for a register, relative to thread.esp0. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) +#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ + - sizeof(struct switch_stack)) +/* Mapping from PT_xxx to the stack offset at which the register is + saved. Notice that usp has no stack-slot and needs to be treated + specially (see get_reg/put_reg below). */ +static const int regoff[] = { + [0] = PT_REG(d1), + [1] = PT_REG(d2), + [2] = PT_REG(d3), + [3] = PT_REG(d4), + [4] = PT_REG(d5), + [5] = SW_REG(d6), + [6] = SW_REG(d7), + [7] = PT_REG(a0), + [8] = PT_REG(a1), + [9] = PT_REG(a2), + [10] = SW_REG(a3), + [11] = SW_REG(a4), + [12] = SW_REG(a5), + [13] = SW_REG(a6), + [14] = PT_REG(d0), + [15] = -1, + [16] = PT_REG(orig_d0), + [17] = PT_REG(sr), + [18] = PT_REG(pc), +}; + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return 0; + /* Need to take stkadj into account. */ + if (regno == PT_SR || regno == PT_PC) { + long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); + addr = (unsigned long *) ((unsigned long)addr + stkadj); + /* The sr is actually a 16 bit register. */ + if (regno == PT_SR) + return *(unsigned short *)addr; + } + return *addr; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return -1; + /* Need to take stkadj into account. */ + if (regno == PT_SR || regno == PT_PC) { + long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); + addr = (unsigned long *) ((unsigned long)addr + stkadj); + /* The sr is actually a 16 bit register. */ + if (regno == PT_SR) { + *(unsigned short *)addr = data; + return 0; + } + } + *addr = data; + return 0; +} + +/* + * Make sure the single step bit is not set. + */ +static inline void singlestep_disable(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp); + clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); +} + +/* + * Called by kernel/ptrace.c when detaching.. + */ +void ptrace_disable(struct task_struct *child) +{ + singlestep_disable(child); +} + +void user_enable_single_step(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp | T1_BIT); + set_tsk_thread_flag(child, TIF_DELAYED_TRACE); +} + #ifdef CONFIG_MMU -#include "ptrace_mm.c" -#else -#include "ptrace_no.c" +void user_enable_block_step(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp | T0_BIT); +} #endif + +void user_disable_single_step(struct task_struct *child) +{ + singlestep_disable(child); +} + +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) +{ + unsigned long tmp; + int i, ret = 0; + int regno = addr >> 2; /* temporary hack. */ + unsigned long __user *datap = (unsigned long __user *) data; + + switch (request) { + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: + if (addr & 3) + goto out_eio; + + if (regno >= 0 && regno < 19) { + tmp = get_reg(child, regno); + } else if (regno >= 21 && regno < 49) { + tmp = child->thread.fp[regno - 21]; + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); +#ifndef CONFIG_MMU + } else if (regno == 49) { + tmp = child->mm->start_code; + } else if (regno == 50) { + tmp = child->mm->start_data; + } else if (regno == 51) { + tmp = child->mm->end_code; +#endif + } else + goto out_eio; + ret = put_user(tmp, datap); + break; + + case PTRACE_POKEUSR: + /* write the word at location addr in the USER area */ + if (addr & 3) + goto out_eio; + + if (regno == PT_SR) { + data &= SR_MASK; + data |= get_reg(child, PT_SR) & ~SR_MASK; + } + if (regno >= 0 && regno < 19) { + if (put_reg(child, regno, data)) + goto out_eio; + } else if (regno >= 21 && regno < 48) { + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { + data <<= 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } + child->thread.fp[regno - 21] = data; + } else + goto out_eio; + break; + + case PTRACE_GETREGS: /* Get all gp regs from the child. */ + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + ret = put_user(tmp, datap); + if (ret) + break; + datap++; + } + break; + + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + for (i = 0; i < 19; i++) { + ret = get_user(tmp, datap); + if (ret) + break; + if (i == PT_SR) { + tmp &= SR_MASK; + tmp |= get_reg(child, PT_SR) & ~SR_MASK; + } + put_reg(child, i, tmp); + datap++; + } + break; + + case PTRACE_GETFPREGS: /* Get the child FPU state. */ + if (copy_to_user(datap, &child->thread.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + case PTRACE_SETFPREGS: /* Set the child FPU state. */ + if (copy_from_user(&child->thread.fp, datap, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + case PTRACE_GET_THREAD_AREA: + ret = put_user(task_thread_info(child)->tp_value, datap); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +out_eio: + return -EIO; +} + +asmlinkage void syscall_trace(void) +{ + 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; + } +} + +#ifdef CONFIG_COLDFIRE +asmlinkage int syscall_trace_enter(void) +{ + int ret = 0; + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + ret = tracehook_report_syscall_entry(task_pt_regs(current)); + return ret; +} + +asmlinkage void syscall_trace_leave(void) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(task_pt_regs(current), 0); +} +#endif /* CONFIG_COLDFIRE */ diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c deleted file mode 100644 index 7bc999b..0000000 --- a/arch/m68k/kernel/ptrace_mm.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * linux/arch/m68k/kernel/ptrace.c - * - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * 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 -#include -#include - -#include -#include -#include -#include -#include - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* determines which bits in the SR the user has access to. */ -/* 1 = access 0 = no access */ -#define SR_MASK 0x001f - -/* sets the trace bits. */ -#define TRACE_BITS 0xC000 -#define T1_BIT 0x8000 -#define T0_BIT 0x4000 - -/* Find the stack offset for a register, relative to thread.esp0. */ -#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) -#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ - - sizeof(struct switch_stack)) -/* Mapping from PT_xxx to the stack offset at which the register is - saved. Notice that usp has no stack-slot and needs to be treated - specially (see get_reg/put_reg below). */ -static const int regoff[] = { - [0] = PT_REG(d1), - [1] = PT_REG(d2), - [2] = PT_REG(d3), - [3] = PT_REG(d4), - [4] = PT_REG(d5), - [5] = SW_REG(d6), - [6] = SW_REG(d7), - [7] = PT_REG(a0), - [8] = PT_REG(a1), - [9] = PT_REG(a2), - [10] = SW_REG(a3), - [11] = SW_REG(a4), - [12] = SW_REG(a5), - [13] = SW_REG(a6), - [14] = PT_REG(d0), - [15] = -1, - [16] = PT_REG(orig_d0), - [17] = PT_REG(sr), - [18] = PT_REG(pc), -}; - -/* - * Get contents of register REGNO in task TASK. - */ -static inline long get_reg(struct task_struct *task, int regno) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return 0; - /* Need to take stkadj into account. */ - if (regno == PT_SR || regno == PT_PC) { - long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); - addr = (unsigned long *) ((unsigned long)addr + stkadj); - /* The sr is actually a 16 bit register. */ - if (regno == PT_SR) - return *(unsigned short *)addr; - } - return *addr; -} - -/* - * Write contents of register REGNO in task TASK. - */ -static inline int put_reg(struct task_struct *task, int regno, - unsigned long data) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return -1; - /* Need to take stkadj into account. */ - if (regno == PT_SR || regno == PT_PC) { - long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); - addr = (unsigned long *) ((unsigned long)addr + stkadj); - /* The sr is actually a 16 bit register. */ - if (regno == PT_SR) { - *(unsigned short *)addr = data; - return 0; - } - } - *addr = data; - return 0; -} - -/* - * Make sure the single step bit is not set. - */ -static inline void singlestep_disable(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp); - clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); -} - -/* - * Called by kernel/ptrace.c when detaching.. - */ -void ptrace_disable(struct task_struct *child) -{ - singlestep_disable(child); -} - -void user_enable_single_step(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp | T1_BIT); - set_tsk_thread_flag(child, TIF_DELAYED_TRACE); -} - -void user_enable_block_step(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp | T0_BIT); -} - -void user_disable_single_step(struct task_struct *child) -{ - singlestep_disable(child); -} - -long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - unsigned long tmp; - int i, ret = 0; - int regno = addr >> 2; /* temporary hack. */ - unsigned long __user *datap = (unsigned long __user *) data; - - switch (request) { - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: - if (addr & 3) - goto out_eio; - - if (regno >= 0 && regno < 19) { - tmp = get_reg(child, regno); - } else if (regno >= 21 && regno < 49) { - tmp = child->thread.fp[regno - 21]; - /* Convert internal fpu reg representation - * into long double format - */ - if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) - tmp = ((tmp & 0xffff0000) << 15) | - ((tmp & 0x0000ffff) << 16); - } else - goto out_eio; - ret = put_user(tmp, datap); - break; - - case PTRACE_POKEUSR: - /* write the word at location addr in the USER area */ - if (addr & 3) - goto out_eio; - - if (regno == PT_SR) { - data &= SR_MASK; - data |= get_reg(child, PT_SR) & ~SR_MASK; - } - if (regno >= 0 && regno < 19) { - if (put_reg(child, regno, data)) - goto out_eio; - } else if (regno >= 21 && regno < 48) { - /* Convert long double format - * into internal fpu reg representation - */ - if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { - data <<= 15; - data = (data & 0xffff0000) | - ((data & 0x0000ffff) >> 1); - } - child->thread.fp[regno - 21] = data; - } else - goto out_eio; - break; - - case PTRACE_GETREGS: /* Get all gp regs from the child. */ - for (i = 0; i < 19; i++) { - tmp = get_reg(child, i); - ret = put_user(tmp, datap); - if (ret) - break; - datap++; - } - break; - - case PTRACE_SETREGS: /* Set all gp regs in the child. */ - for (i = 0; i < 19; i++) { - ret = get_user(tmp, datap); - if (ret) - break; - if (i == PT_SR) { - tmp &= SR_MASK; - tmp |= get_reg(child, PT_SR) & ~SR_MASK; - } - put_reg(child, i, tmp); - datap++; - } - break; - - case PTRACE_GETFPREGS: /* Get the child FPU state. */ - if (copy_to_user(datap, &child->thread.fp, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - - case PTRACE_SETFPREGS: /* Set the child FPU state. */ - if (copy_from_user(&child->thread.fp, datap, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - - case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, datap); - break; - - default: - ret = ptrace_request(child, request, addr, data); - break; - } - - return ret; -out_eio: - return -EIO; -} - -asmlinkage void syscall_trace(void) -{ - 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; - } -} - -#ifdef CONFIG_COLDFIRE -asmlinkage int syscall_trace_enter(void) -{ - int ret = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ret = tracehook_report_syscall_entry(task_pt_regs(current)); - return ret; -} - -asmlinkage void syscall_trace_leave(void) -{ - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(task_pt_regs(current), 0); -} -#endif /* CONFIG_COLDFIRE */ diff --git a/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c deleted file mode 100644 index 6709fb7..0000000 --- a/arch/m68k/kernel/ptrace_no.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/ptrace.c - * - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * 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 -#include -#include - -#include -#include -#include -#include -#include - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* determines which bits in the SR the user has access to. */ -/* 1 = access 0 = no access */ -#define SR_MASK 0x001f - -/* sets the trace bits. */ -#define TRACE_BITS 0x8000 - -/* Find the stack offset for a register, relative to thread.esp0. */ -#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) -#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ - - sizeof(struct switch_stack)) -/* Mapping from PT_xxx to the stack offset at which the register is - saved. Notice that usp has no stack-slot and needs to be treated - specially (see get_reg/put_reg below). */ -static int regoff[] = { - PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4), - PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0), - PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4), - SW_REG(a5), SW_REG(a6), PT_REG(d0), -1, - PT_REG(orig_d0), PT_REG(sr), PT_REG(pc), -}; - -/* - * Get contents of register REGNO in task TASK. - */ -static inline long get_reg(struct task_struct *task, int regno) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return 0; - return *addr; -} - -/* - * Write contents of register REGNO in task TASK. - */ -static inline int put_reg(struct task_struct *task, int regno, - unsigned long data) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); - else - return -1; - *addr = data; - return 0; -} - -void user_enable_single_step(struct task_struct *task) -{ - unsigned long srflags; - srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16); - put_reg(task, PT_SR, srflags); -} - -void user_disable_single_step(struct task_struct *task) -{ - unsigned long srflags; - srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16); - put_reg(task, PT_SR, srflags); -} - -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. - */ -void ptrace_disable(struct task_struct *child) -{ - /* make sure the single step bit is not set. */ - user_disable_single_step(child); -} - -long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - int ret; - int regno = addr >> 2; - unsigned long __user *datap = (unsigned long __user *) data; - - switch (request) { - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || addr > sizeof(struct user) - 3) - break; - - tmp = 0; /* Default return condition */ - ret = -EIO; - if (regno < 19) { - tmp = get_reg(child, regno); - if (regno == PT_SR) - tmp >>= 16; - } else if (regno >= 21 && regno < 49) { - tmp = child->thread.fp[regno - 21]; - } else if (regno == 49) { - tmp = child->mm->start_code; - } else if (regno == 50) { - tmp = child->mm->start_data; - } else if (regno == 51) { - tmp = child->mm->end_code; - } else - break; - ret = put_user(tmp, datap); - break; - } - - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr > sizeof(struct user) - 3) - break; - - if (regno == PT_SR) { - data &= SR_MASK; - data <<= 16; - data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); - } - if (regno < 19) { - if (put_reg(child, regno, data)) - break; - ret = 0; - break; - } - if (regno >= 21 && regno < 48) - { - child->thread.fp[regno - 21] = data; - ret = 0; - } - break; - - case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - int i; - unsigned long tmp; - for (i = 0; i < 19; i++) { - tmp = get_reg(child, i); - if (i == PT_SR) - tmp >>= 16; - if (put_user(tmp, datap)) { - ret = -EFAULT; - break; - } - datap++; - } - ret = 0; - break; - } - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - int i; - unsigned long tmp; - for (i = 0; i < 19; i++) { - if (get_user(tmp, datap)) { - ret = -EFAULT; - break; - } - if (i == PT_SR) { - tmp &= SR_MASK; - tmp <<= 16; - tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); - } - put_reg(child, i, tmp); - datap++; - } - ret = 0; - break; - } - -#ifdef PTRACE_GETFPREGS - case PTRACE_GETFPREGS: { /* Get the child FPU state. */ - ret = 0; - if (copy_to_user(datap, &child->thread.fp, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - } -#endif - -#ifdef PTRACE_SETFPREGS - case PTRACE_SETFPREGS: { /* Set the child FPU state. */ - ret = 0; - if (copy_from_user(&child->thread.fp, datap, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - } -#endif - - case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, datap); - break; - - default: - ret = ptrace_request(child, request, addr, data); - break; - } - return ret; -} - -asmlinkage int syscall_trace_enter(void) -{ - int ret = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ret = tracehook_report_syscall_entry(task_pt_regs(current)); - return ret; -} - -asmlinkage void syscall_trace_leave(void) -{ - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(task_pt_regs(current), 0); -} -- cgit v1.1 From fde3944141c70b264aace92334b297a05233e179 Mon Sep 17 00:00:00 2001 From: Greg Ungerer Date: Thu, 9 Feb 2012 14:18:46 +1000 Subject: m68k: merge the MMU and non-MMU versions of process.c The MMU and non-MMU varients of the m68k arch process.c code are pretty much the same. Only a few minor details differ between the two. The majority of the difference is to deal with having or wanting hardware FPU support. So merge them back into a single process.c file. Signed-off-by: Greg Ungerer Acked-by: Geert Uytterhoeven --- arch/m68k/kernel/process.c | 379 ++++++++++++++++++++++++++++++++++++++- arch/m68k/kernel/process_mm.c | 369 -------------------------------------- arch/m68k/kernel/process_no.c | 406 ------------------------------------------ 3 files changed, 377 insertions(+), 777 deletions(-) delete mode 100644 arch/m68k/kernel/process_mm.c delete mode 100644 arch/m68k/kernel/process_no.c (limited to 'arch/m68k/kernel') diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 6cf4bd6..f053e24 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -1,5 +1,380 @@ +/* + * linux/arch/m68k/kernel/process.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * 68060 fixes by Jesper Skov + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +asmlinkage void ret_from_fork(void); + + +/* + * Return saved PC from a blocked thread + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; + /* Check whether the thread is blocked in resume() */ + if (in_sched_functions(sw->retpc)) + return ((unsigned long *)sw->a6)[1]; + else + return sw->retpc; +} + +/* + * The idle loop on an m68k.. + */ +static void default_idle(void) +{ + if (!need_resched()) +#if defined(MACH_ATARI_ONLY) + /* block out HSYNC on the atari (falcon) */ + __asm__("stop #0x2200" : : : "cc"); +#else + __asm__("stop #0x2000" : : : "cc"); +#endif +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + while (!need_resched()) + idle(); + preempt_enable_no_resched(); + schedule(); + preempt_disable(); + } +} + +void machine_restart(char * __unused) +{ + if (mach_reset) + mach_reset(); + for (;;); +} + +void machine_halt(void) +{ + if (mach_halt) + mach_halt(); + for (;;); +} + +void machine_power_off(void) +{ + if (mach_power_off) + mach_power_off(); + for (;;); +} + +void (*pm_power_off)(void) = machine_power_off; +EXPORT_SYMBOL(pm_power_off); + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", + regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); + printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", + regs->orig_d0, regs->d0, regs->a2, regs->a1); + printk("A0: %08lx D5: %08lx D4: %08lx\n", + regs->a0, regs->d5, regs->d4); + printk("D3: %08lx D2: %08lx D1: %08lx\n", + regs->d3, regs->d2, regs->d1); + if (!(regs->sr & PS_S)) + printk("USP: %08lx\n", rdusp()); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + int pid; + mm_segment_t fs; + + fs = get_fs(); + set_fs (KERNEL_DS); + + { + register long retval __asm__ ("d0"); + register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; + + retval = __NR_clone; + __asm__ __volatile__ + ("clrl %%d2\n\t" + "trap #0\n\t" /* Linux/m68k system call */ + "tstl %0\n\t" /* child or parent */ + "jne 1f\n\t" /* parent - jump */ +#ifdef CONFIG_MMU + "lea %%sp@(%c7),%6\n\t" /* reload current */ + "movel %6@,%6\n\t" +#endif + "movel %3,%%sp@-\n\t" /* push argument */ + "jsr %4@\n\t" /* call fn */ + "movel %0,%%d1\n\t" /* pass exit value */ + "movel %2,%%d0\n\t" /* exit */ + "trap #0\n" + "1:" + : "+d" (retval) + : "i" (__NR_clone), "i" (__NR_exit), + "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), + "i" (-THREAD_SIZE) + : "d2"); + + pid = retval; + } + + set_fs (fs); + return pid; +} +EXPORT_SYMBOL(kernel_thread); + +void flush_thread(void) +{ + current->thread.fs = __USER_DS; +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) { + unsigned long zero = 0; + asm volatile("frestore %0": :"m" (zero)); + } +#endif +} + +/* + * "m68k_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int m68k_fork(struct pt_regs *regs) +{ #ifdef CONFIG_MMU -#include "process_mm.c" + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); #else -#include "process_no.c" + return -EINVAL; #endif +} + +asmlinkage int m68k_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, + NULL, NULL); +} + +asmlinkage int m68k_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + + /* syscall2 puts clone_flags in d1 and usp in d2 */ + clone_flags = regs->d1; + newsp = regs->d2; + parent_tidptr = (int __user *)regs->d3; + child_tidptr = (int __user *)regs->d4; + if (!newsp) + newsp = rdusp(); + return do_fork(clone_flags, newsp, regs, 0, + parent_tidptr, child_tidptr); +} + +int copy_thread(unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct switch_stack * childstack, *stack; + unsigned long *retp; + + childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; + + *childregs = *regs; + childregs->d0 = 0; + + retp = ((unsigned long *) regs); + stack = ((struct switch_stack *) retp) - 1; + + childstack = ((struct switch_stack *) childregs) - 1; + *childstack = *stack; + childstack->retpc = (unsigned long)ret_from_fork; + + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childstack; + + if (clone_flags & CLONE_SETTLS) + task_thread_info(p)->tp_value = regs->d5; + + /* + * Must save the current SFC/DFC value, NOT the value when + * the parent was last descheduled - RGH 10-08-96 + */ + p->thread.fs = get_fs().seg; + +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); + + if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) { + if (CPU_IS_COLDFIRE) { + asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t" + "fmovel %/fpiar,%1\n\t" + "fmovel %/fpcr,%2\n\t" + "fmovel %/fpsr,%3" + : + : "m" (p->thread.fp[0]), + "m" (p->thread.fpcntl[0]), + "m" (p->thread.fpcntl[1]), + "m" (p->thread.fpcntl[2]) + : "memory"); + } else { + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : + : "m" (p->thread.fp[0]), + "m" (p->thread.fpcntl[0]) + : "memory"); + } + } + + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); + } +#endif /* CONFIG_FPU */ + + return 0; +} + +/* Fill in the fpu structure for a core dump. */ +#ifdef CONFIG_FPU +int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) +{ + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->thread.fpcntl, 12); + memcpy(fpu->fpregs, current->thread.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } + + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) + return 0; + + if (CPU_IS_COLDFIRE) { + asm volatile ("fmovel %/fpiar,%0\n\t" + "fmovel %/fpcr,%1\n\t" + "fmovel %/fpsr,%2\n\t" + "fmovemd %/fp0-%/fp7,%3" + : + : "m" (fpu->fpcntl[0]), + "m" (fpu->fpcntl[1]), + "m" (fpu->fpcntl[2]), + "m" (fpu->fpregs[0]) + : "memory"); + } else { + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + : + : "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovemx %/fp0-%/fp7,%0" + : + : "m" (fpu->fpregs[0]) + : "memory"); + } + + return 1; +} +EXPORT_SYMBOL(dump_fpu); +#endif /* CONFIG_FPU */ + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) +{ + int error; + char * filename; + struct pt_regs *regs = (struct pt_regs *) &name; + + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + return error; + error = do_execve(filename, argv, envp, regs); + putname(filename); + return error; +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)task_stack_page(p); + fp = ((struct switch_stack *)p->thread.ksp)->a6; + do { + if (fp < stack_page+sizeof(struct thread_info) || + fp >= 8184+stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + if (!in_sched_functions(pc)) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); + return 0; +} diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c deleted file mode 100644 index 099283e..0000000 --- a/arch/m68k/kernel/process_mm.c +++ /dev/null @@ -1,369 +0,0 @@ -/* - * linux/arch/m68k/kernel/process.c - * - * Copyright (C) 1995 Hamish Macdonald - * - * 68060 fixes by Jesper Skov - */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -asmlinkage void ret_from_fork(void); - - -/* - * Return saved PC from a blocked thread - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; - /* Check whether the thread is blocked in resume() */ - if (in_sched_functions(sw->retpc)) - return ((unsigned long *)sw->a6)[1]; - else - return sw->retpc; -} - -/* - * The idle loop on an m68k.. - */ -static void default_idle(void) -{ - if (!need_resched()) -#if defined(MACH_ATARI_ONLY) - /* block out HSYNC on the atari (falcon) */ - __asm__("stop #0x2200" : : : "cc"); -#else - __asm__("stop #0x2000" : : : "cc"); -#endif -} - -void (*idle)(void) = default_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ - /* endless idle loop with no priority at all */ - while (1) { - while (!need_resched()) - idle(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } -} - -void machine_restart(char * __unused) -{ - if (mach_reset) - mach_reset(); - for (;;); -} - -void machine_halt(void) -{ - if (mach_halt) - mach_halt(); - for (;;); -} - -void machine_power_off(void) -{ - if (mach_power_off) - mach_power_off(); - for (;;); -} - -void (*pm_power_off)(void) = machine_power_off; -EXPORT_SYMBOL(pm_power_off); - -void show_regs(struct pt_regs * regs) -{ - printk("\n"); - printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", - regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); - printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", - regs->orig_d0, regs->d0, regs->a2, regs->a1); - printk("A0: %08lx D5: %08lx D4: %08lx\n", - regs->a0, regs->d5, regs->d4); - printk("D3: %08lx D2: %08lx D1: %08lx\n", - regs->d3, regs->d2, regs->d1); - if (!(regs->sr & PS_S)) - printk("USP: %08lx\n", rdusp()); -} - -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int pid; - mm_segment_t fs; - - fs = get_fs(); - set_fs (KERNEL_DS); - - { - register long retval __asm__ ("d0"); - register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; - - retval = __NR_clone; - __asm__ __volatile__ - ("clrl %%d2\n\t" - "trap #0\n\t" /* Linux/m68k system call */ - "tstl %0\n\t" /* child or parent */ - "jne 1f\n\t" /* parent - jump */ - "lea %%sp@(%c7),%6\n\t" /* reload current */ - "movel %6@,%6\n\t" - "movel %3,%%sp@-\n\t" /* push argument */ - "jsr %4@\n\t" /* call fn */ - "movel %0,%%d1\n\t" /* pass exit value */ - "movel %2,%%d0\n\t" /* exit */ - "trap #0\n" - "1:" - : "+d" (retval) - : "i" (__NR_clone), "i" (__NR_exit), - "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), - "i" (-THREAD_SIZE) - : "d2"); - - pid = retval; - } - - set_fs (fs); - return pid; -} -EXPORT_SYMBOL(kernel_thread); - -void flush_thread(void) -{ - unsigned long zero = 0; - - current->thread.fs = __USER_DS; - if (!FPU_IS_EMU) - asm volatile("frestore %0": :"m" (zero)); -} - -/* - * "m68k_fork()".. By the time we get here, the - * non-volatile registers have also been saved on the - * stack. We do some ugly pointer stuff here.. (see - * also copy_thread) - */ - -asmlinkage int m68k_fork(struct pt_regs *regs) -{ - return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); -} - -asmlinkage int m68k_vfork(struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, - NULL, NULL); -} - -asmlinkage int m68k_clone(struct pt_regs *regs) -{ - unsigned long clone_flags; - unsigned long newsp; - int __user *parent_tidptr, *child_tidptr; - - /* syscall2 puts clone_flags in d1 and usp in d2 */ - clone_flags = regs->d1; - newsp = regs->d2; - parent_tidptr = (int __user *)regs->d3; - child_tidptr = (int __user *)regs->d4; - if (!newsp) - newsp = rdusp(); - return do_fork(clone_flags, newsp, regs, 0, - parent_tidptr, child_tidptr); -} - -int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, - struct task_struct * p, struct pt_regs * regs) -{ - struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long *retp; - - childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - - *childregs = *regs; - childregs->d0 = 0; - - retp = ((unsigned long *) regs); - stack = ((struct switch_stack *) retp) - 1; - - childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->retpc = (unsigned long)ret_from_fork; - - p->thread.usp = usp; - p->thread.ksp = (unsigned long)childstack; - - if (clone_flags & CLONE_SETTLS) - task_thread_info(p)->tp_value = regs->d5; - - /* - * Must save the current SFC/DFC value, NOT the value when - * the parent was last descheduled - RGH 10-08-96 - */ - p->thread.fs = get_fs().seg; - - if (!FPU_IS_EMU) { - /* Copy the current fpu state */ - asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); - - if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) { - if (CPU_IS_COLDFIRE) { - asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t" - "fmovel %/fpiar,%1\n\t" - "fmovel %/fpcr,%2\n\t" - "fmovel %/fpsr,%3" - : - : "m" (p->thread.fp[0]), - "m" (p->thread.fpcntl[0]), - "m" (p->thread.fpcntl[1]), - "m" (p->thread.fpcntl[2]) - : "memory"); - } else { - asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" - "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" - : - : "m" (p->thread.fp[0]), - "m" (p->thread.fpcntl[0]) - : "memory"); - } - } - - /* Restore the state in case the fpu was busy */ - asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); - } - - return 0; -} - -/* Fill in the fpu structure for a core dump. */ - -int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) -{ - char fpustate[216]; - - if (FPU_IS_EMU) { - int i; - - memcpy(fpu->fpcntl, current->thread.fpcntl, 12); - memcpy(fpu->fpregs, current->thread.fp, 96); - /* Convert internal fpu reg representation - * into long double format - */ - for (i = 0; i < 24; i += 3) - fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | - ((fpu->fpregs[i] & 0x0000ffff) << 16); - return 1; - } - - /* First dump the fpu context to avoid protocol violation. */ - asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) - return 0; - - if (CPU_IS_COLDFIRE) { - asm volatile ("fmovel %/fpiar,%0\n\t" - "fmovel %/fpcr,%1\n\t" - "fmovel %/fpsr,%2\n\t" - "fmovemd %/fp0-%/fp7,%3" - : - : "m" (fpu->fpcntl[0]), - "m" (fpu->fpcntl[1]), - "m" (fpu->fpcntl[2]), - "m" (fpu->fpregs[0]) - : "memory"); - } else { - asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" - : - : "m" (fpu->fpcntl[0]) - : "memory"); - asm volatile ("fmovemx %/fp0-%/fp7,%0" - : - : "m" (fpu->fpregs[0]) - : "memory"); - } - - return 1; -} -EXPORT_SYMBOL(dump_fpu); - -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char __user *name, - const char __user *const __user *argv, - const char __user *const __user *envp) -{ - int error; - char * filename; - struct pt_regs *regs = (struct pt_regs *) &name; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, regs); - putname(filename); - return error; -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long fp, pc; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - stack_page = (unsigned long)task_stack_page(p); - fp = ((struct switch_stack *)p->thread.ksp)->a6; - do { - if (fp < stack_page+sizeof(struct thread_info) || - fp >= 8184+stack_page) - return 0; - pc = ((unsigned long *)fp)[1]; - if (!in_sched_functions(pc)) - return pc; - fp = *(unsigned long *) fp; - } while (count++ < 16); - return 0; -} diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c deleted file mode 100644 index 5e1078c..0000000 --- a/arch/m68k/kernel/process_no.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/process.c - * - * Copyright (C) 1995 Hamish Macdonald - * - * 68060 fixes by Jesper Skov - * - * uClinux changes - * Copyright (C) 2000-2002, David McCullough - */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -asmlinkage void ret_from_fork(void); - -/* - * The following aren't currently used. - */ -void (*pm_idle)(void); -EXPORT_SYMBOL(pm_idle); - -void (*pm_power_off)(void); -EXPORT_SYMBOL(pm_power_off); - -/* - * The idle loop on an m68knommu.. - */ -static void default_idle(void) -{ - local_irq_disable(); - while (!need_resched()) { - /* This stop will re-enable interrupts */ - __asm__("stop #0x2000" : : : "cc"); - local_irq_disable(); - } - local_irq_enable(); -} - -void (*idle)(void) = default_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ - /* endless idle loop with no priority at all */ - while (1) { - idle(); - preempt_enable_no_resched(); - schedule(); - preempt_disable(); - } -} - -void machine_restart(char * __unused) -{ - if (mach_reset) - mach_reset(); - for (;;); -} - -void machine_halt(void) -{ - if (mach_halt) - mach_halt(); - for (;;); -} - -void machine_power_off(void) -{ - if (mach_power_off) - mach_power_off(); - for (;;); -} - -void show_regs(struct pt_regs * regs) -{ - printk(KERN_NOTICE "\n"); - printk(KERN_NOTICE "Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", - regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); - printk(KERN_NOTICE "ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", - regs->orig_d0, regs->d0, regs->a2, regs->a1); - printk(KERN_NOTICE "A0: %08lx D5: %08lx D4: %08lx\n", - regs->a0, regs->d5, regs->d4); - printk(KERN_NOTICE "D3: %08lx D2: %08lx D1: %08lx\n", - regs->d3, regs->d2, regs->d1); - if (!(regs->sr & PS_S)) - printk(KERN_NOTICE "USP: %08lx\n", rdusp()); -} - -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int retval; - long clone_arg = flags | CLONE_VM; - mm_segment_t fs; - - fs = get_fs(); - set_fs(KERNEL_DS); - - __asm__ __volatile__ ( - "movel %%sp, %%d2\n\t" - "movel %5, %%d1\n\t" - "movel %1, %%d0\n\t" - "trap #0\n\t" - "cmpl %%sp, %%d2\n\t" - "jeq 1f\n\t" - "movel %3, %%sp@-\n\t" - "jsr %4@\n\t" - "movel %2, %%d0\n\t" - "trap #0\n" - "1:\n\t" - "movel %%d0, %0\n" - : "=d" (retval) - : "i" (__NR_clone), - "i" (__NR_exit), - "a" (arg), - "a" (fn), - "a" (clone_arg) - : "cc", "%d0", "%d1", "%d2"); - - set_fs(fs); - return retval; -} -EXPORT_SYMBOL(kernel_thread); - -void flush_thread(void) -{ -#ifdef CONFIG_FPU - unsigned long zero = 0; -#endif - - current->thread.fs = __USER_DS; -#ifdef CONFIG_FPU - if (!FPU_IS_EMU) - asm volatile (".chip 68k/68881\n\t" - "frestore %0\n\t" - ".chip 68k" : : "m" (zero)); -#endif -} - -/* - * "m68k_fork()".. By the time we get here, the - * non-volatile registers have also been saved on the - * stack. We do some ugly pointer stuff here.. (see - * also copy_thread) - */ - -asmlinkage int m68k_fork(struct pt_regs *regs) -{ - /* fork almost works, enough to trick you into looking elsewhere :-( */ - return(-EINVAL); -} - -asmlinkage int m68k_vfork(struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); -} - -asmlinkage int m68k_clone(struct pt_regs *regs) -{ - unsigned long clone_flags; - unsigned long newsp; - - /* syscall2 puts clone_flags in d1 and usp in d2 */ - clone_flags = regs->d1; - newsp = regs->d2; - if (!newsp) - newsp = rdusp(); - return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); -} - -int copy_thread(unsigned long clone_flags, - unsigned long usp, unsigned long topstk, - struct task_struct * p, struct pt_regs * regs) -{ - struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long *retp; - - childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - - *childregs = *regs; - childregs->d0 = 0; - - retp = ((unsigned long *) regs); - stack = ((struct switch_stack *) retp) - 1; - - childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->retpc = (unsigned long)ret_from_fork; - - p->thread.usp = usp; - p->thread.ksp = (unsigned long)childstack; - - if (clone_flags & CLONE_SETTLS) - task_thread_info(p)->tp_value = regs->d5; - - /* - * Must save the current SFC/DFC value, NOT the value when - * the parent was last descheduled - RGH 10-08-96 - */ - p->thread.fs = get_fs().seg; - -#ifdef CONFIG_FPU - if (!FPU_IS_EMU) { - /* Copy the current fpu state */ - asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); - - if (p->thread.fpstate[0]) - asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" - "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" - : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) - : "memory"); - /* Restore the state in case the fpu was busy */ - asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); - } -#endif - - return 0; -} - -/* Fill in the fpu structure for a core dump. */ - -int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu) -{ -#ifdef CONFIG_FPU - char fpustate[216]; - - if (FPU_IS_EMU) { - int i; - - memcpy(fpu->fpcntl, current->thread.fpcntl, 12); - memcpy(fpu->fpregs, current->thread.fp, 96); - /* Convert internal fpu reg representation - * into long double format - */ - for (i = 0; i < 24; i += 3) - fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | - ((fpu->fpregs[i] & 0x0000ffff) << 16); - return 1; - } - - /* First dump the fpu context to avoid protocol violation. */ - asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if (!fpustate[0]) - return 0; - - asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" - :: "m" (fpu->fpcntl[0]) - : "memory"); - asm volatile ("fmovemx %/fp0-%/fp7,%0" - :: "m" (fpu->fpregs[0]) - : "memory"); -#endif - return 1; -} -EXPORT_SYMBOL(dump_fpu); - -/* - * Generic dumping code. Used for panic and debug. - */ -void dump(struct pt_regs *fp) -{ - unsigned long *sp; - unsigned char *tp; - int i; - - printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); - printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); - - if (current->mm) { - printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", - (int) current->mm->start_code, - (int) current->mm->end_code, - (int) current->mm->start_data, - (int) current->mm->end_data, - (int) current->mm->end_data, - (int) current->mm->brk); - printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", - (int) current->mm->start_stack, - (int)(((unsigned long) current) + THREAD_SIZE)); - } - - printk(KERN_EMERG "PC: %08lx\n", fp->pc); - printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp); - printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", - fp->d0, fp->d1, fp->d2, fp->d3); - printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", - fp->d4, fp->d5, fp->a0, fp->a1); - printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %p\n", - (unsigned int) rdusp(), fp); - - printk(KERN_EMERG "\nCODE:"); - tp = ((unsigned char *) fp->pc) - 0x20; - for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { - if ((i % 0x10) == 0) - printk(KERN_EMERG "%p: ", tp + i); - printk("%08x ", (int) *sp++); - } - printk(KERN_EMERG "\n"); - - printk(KERN_EMERG "KERNEL STACK:"); - tp = ((unsigned char *) fp) - 0x40; - for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { - if ((i % 0x10) == 0) - printk(KERN_EMERG "%p: ", tp + i); - printk("%08x ", (int) *sp++); - } - printk(KERN_EMERG "\n"); - - printk(KERN_EMERG "USER STACK:"); - tp = (unsigned char *) (rdusp() - 0x10); - for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { - if ((i % 0x10) == 0) - printk(KERN_EMERG "%p: ", tp + i); - printk("%08x ", (int) *sp++); - } - printk(KERN_EMERG "\n"); -} - -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char *name, - const char *const *argv, - const char *const *envp) -{ - int error; - char * filename; - struct pt_regs *regs = (struct pt_regs *) &name; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, regs); - putname(filename); - return error; -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long fp, pc; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - stack_page = (unsigned long)p; - fp = ((struct switch_stack *)p->thread.ksp)->a6; - do { - if (fp < stack_page+sizeof(struct thread_info) || - fp >= THREAD_SIZE-8+stack_page) - return 0; - pc = ((unsigned long *)fp)[1]; - if (!in_sched_functions(pc)) - return pc; - fp = *(unsigned long *) fp; - } while (count++ < 16); - return 0; -} - -/* - * Return saved PC of a blocked thread. - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; - - /* Check whether the thread is blocked in resume() */ - if (in_sched_functions(sw->retpc)) - return ((unsigned long *)sw->a6)[1]; - else - return sw->retpc; -} - -- cgit v1.1