aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/m68k/kernel
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'arch/m68k/kernel')
-rw-r--r--arch/m68k/kernel/Makefile18
-rw-r--r--arch/m68k/kernel/Makefile_mm17
-rw-r--r--arch/m68k/kernel/Makefile_no10
-rw-r--r--arch/m68k/kernel/asm-offsets.c35
-rw-r--r--arch/m68k/kernel/dma.c135
-rw-r--r--arch/m68k/kernel/dma_mm.c130
-rw-r--r--arch/m68k/kernel/dma_no.c74
-rw-r--r--arch/m68k/kernel/entry.S774
-rw-r--r--arch/m68k/kernel/entry_mm.S409
-rw-r--r--arch/m68k/kernel/entry_no.S133
-rw-r--r--arch/m68k/kernel/head.S12
-rw-r--r--arch/m68k/kernel/init_task.c36
-rw-r--r--arch/m68k/kernel/irq.c30
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c16
-rw-r--r--arch/m68k/kernel/module.c156
-rw-r--r--arch/m68k/kernel/module_mm.c155
-rw-r--r--arch/m68k/kernel/module_no.c126
-rw-r--r--arch/m68k/kernel/process.c356
-rw-r--r--arch/m68k/kernel/process_mm.c354
-rw-r--r--arch/m68k/kernel/process_no.c406
-rw-r--r--arch/m68k/kernel/ptrace.c281
-rw-r--r--arch/m68k/kernel/ptrace_mm.c277
-rw-r--r--arch/m68k/kernel/ptrace_no.c255
-rw-r--r--arch/m68k/kernel/setup.c535
-rw-r--r--arch/m68k/kernel/setup_mm.c533
-rw-r--r--arch/m68k/kernel/setup_no.c317
-rw-r--r--arch/m68k/kernel/signal.c1048
-rw-r--r--arch/m68k/kernel/signal_mm.c1017
-rw-r--r--arch/m68k/kernel/signal_no.c765
-rw-r--r--arch/m68k/kernel/sys_m68k.c105
-rw-r--r--arch/m68k/kernel/syscalltable.S368
-rw-r--r--arch/m68k/kernel/time.c119
-rw-r--r--arch/m68k/kernel/time_mm.c114
-rw-r--r--arch/m68k/kernel/time_no.c87
-rw-r--r--arch/m68k/kernel/traps.c1204
-rw-r--r--arch/m68k/kernel/traps_mm.c1207
-rw-r--r--arch/m68k/kernel/traps_no.c365
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds2
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds1
-rw-r--r--arch/m68k/kernel/vmlinux.lds.S11
-rw-r--r--arch/m68k/kernel/vmlinux.lds_mm.S10
-rw-r--r--arch/m68k/kernel/vmlinux.lds_no.S188
42 files changed, 7529 insertions, 4662 deletions
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 55d5d6b680a2..c482ebc9dd54 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -1,17 +1,5 @@
1# 1ifdef CONFIG_MMU
2# Makefile for the linux kernel. 2include arch/m68k/kernel/Makefile_mm
3#
4
5ifndef CONFIG_SUN3
6 extra-y := head.o
7else 3else
8 extra-y := sun3-head.o 4include arch/m68k/kernel/Makefile_no
9endif 5endif
10extra-y += vmlinux.lds
11
12obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
13 sys_m68k.o time.o setup.o m68k_ksyms.o devres.o
14
15devres-y = ../../../kernel/irq/devres.o
16
17obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm
new file mode 100644
index 000000000000..aced67804579
--- /dev/null
+++ b/arch/m68k/kernel/Makefile_mm
@@ -0,0 +1,17 @@
1#
2# Makefile for the linux kernel.
3#
4
5ifndef CONFIG_SUN3
6 extra-y := head.o
7else
8 extra-y := sun3-head.o
9endif
10extra-y += vmlinux.lds
11
12obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
13 sys_m68k.o time.o setup.o m68k_ksyms.o devres.o syscalltable.o
14
15devres-y = ../../../kernel/irq/devres.o
16
17obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
diff --git a/arch/m68k/kernel/Makefile_no b/arch/m68k/kernel/Makefile_no
new file mode 100644
index 000000000000..37c3fc074c0a
--- /dev/null
+++ b/arch/m68k/kernel/Makefile_no
@@ -0,0 +1,10 @@
1#
2# Makefile for arch/m68knommu/kernel.
3#
4
5extra-y := vmlinux.lds
6
7obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \
8 setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
9
10obj-$(CONFIG_MODULES) += module.o
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index 73e5e581245b..983fed9d469b 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -22,16 +22,10 @@
22int main(void) 22int main(void)
23{ 23{
24 /* offsets into the task struct */ 24 /* offsets into the task struct */
25 DEFINE(TASK_STATE, offsetof(struct task_struct, state));
26 DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
27 DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
28 DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); 25 DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
29 DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
30 DEFINE(TASK_MM, offsetof(struct task_struct, mm)); 26 DEFINE(TASK_MM, offsetof(struct task_struct, mm));
31 DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); 27 DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
32#ifdef CONFIG_MMU
33 DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info)); 28 DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
34#endif
35 29
36 /* offsets into the thread struct */ 30 /* offsets into the thread struct */
37 DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); 31 DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
@@ -61,20 +55,24 @@ int main(void)
61 DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2)); 55 DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
62 DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc)); 56 DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
63 DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr)); 57 DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
58
64 /* bitfields are a bit difficult */ 59 /* bitfields are a bit difficult */
60#ifdef CONFIG_COLDFIRE
61 DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
62#else
65 DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4); 63 DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
66 64#endif
67 /* offsets into the irq_handler struct */
68 DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
69 DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
70 DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
71
72 /* offsets into the kernel_stat struct */
73 DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs));
74 65
75 /* offsets into the irq_cpustat_t struct */ 66 /* offsets into the irq_cpustat_t struct */
76 DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); 67 DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
77 68
69 /* signal defines */
70 DEFINE(LSIGSEGV, SIGSEGV);
71 DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
72 DEFINE(LSIGTRAP, SIGTRAP);
73 DEFINE(LTRAP_TRACE, TRAP_TRACE);
74
75#ifdef CONFIG_MMU
78 /* offsets into the bi_record struct */ 76 /* offsets into the bi_record struct */
79 DEFINE(BIR_TAG, offsetof(struct bi_record, tag)); 77 DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
80 DEFINE(BIR_SIZE, offsetof(struct bi_record, size)); 78 DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
@@ -88,12 +86,6 @@ int main(void)
88 DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data)); 86 DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
89 DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref)); 87 DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
90 88
91 /* signal defines */
92 DEFINE(LSIGSEGV, SIGSEGV);
93 DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
94 DEFINE(LSIGTRAP, SIGTRAP);
95 DEFINE(LTRAP_TRACE, TRAP_TRACE);
96
97 /* offsets into the custom struct */ 89 /* offsets into the custom struct */
98 DEFINE(CUSTOMBASE, &amiga_custom); 90 DEFINE(CUSTOMBASE, &amiga_custom);
99 DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar)); 91 DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
@@ -107,6 +99,7 @@ int main(void)
107 DEFINE(CIABBASE, &ciab); 99 DEFINE(CIABBASE, &ciab);
108 DEFINE(C_PRA, offsetof(struct CIA, pra)); 100 DEFINE(C_PRA, offsetof(struct CIA, pra));
109 DEFINE(ZTWOBASE, zTwoBase); 101 DEFINE(ZTWOBASE, zTwoBase);
102#endif
110 103
111 return 0; 104 return 0;
112} 105}
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
index 4bbb3c2a8880..90e8cb726c8c 100644
--- a/arch/m68k/kernel/dma.c
+++ b/arch/m68k/kernel/dma.c
@@ -1,130 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * This file is subject to the terms and conditions of the GNU General Public 2#include "dma_mm.c"
3 * License. See the file COPYING in the main directory of this archive 3#else
4 * for more details. 4#include "dma_no.c"
5 */ 5#endif
6
7#undef DEBUG
8
9#include <linux/dma-mapping.h>
10#include <linux/device.h>
11#include <linux/kernel.h>
12#include <linux/scatterlist.h>
13#include <linux/slab.h>
14#include <linux/vmalloc.h>
15
16#include <asm/pgalloc.h>
17
18void *dma_alloc_coherent(struct device *dev, size_t size,
19 dma_addr_t *handle, gfp_t flag)
20{
21 struct page *page, **map;
22 pgprot_t pgprot;
23 void *addr;
24 int i, order;
25
26 pr_debug("dma_alloc_coherent: %d,%x\n", size, flag);
27
28 size = PAGE_ALIGN(size);
29 order = get_order(size);
30
31 page = alloc_pages(flag, order);
32 if (!page)
33 return NULL;
34
35 *handle = page_to_phys(page);
36 map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA);
37 if (!map) {
38 __free_pages(page, order);
39 return NULL;
40 }
41 split_page(page, order);
42
43 order = 1 << order;
44 size >>= PAGE_SHIFT;
45 map[0] = page;
46 for (i = 1; i < size; i++)
47 map[i] = page + i;
48 for (; i < order; i++)
49 __free_page(page + i);
50 pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
51 if (CPU_IS_040_OR_060)
52 pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
53 else
54 pgprot_val(pgprot) |= _PAGE_NOCACHE030;
55 addr = vmap(map, size, VM_MAP, pgprot);
56 kfree(map);
57
58 return addr;
59}
60EXPORT_SYMBOL(dma_alloc_coherent);
61
62void dma_free_coherent(struct device *dev, size_t size,
63 void *addr, dma_addr_t handle)
64{
65 pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
66 vfree(addr);
67}
68EXPORT_SYMBOL(dma_free_coherent);
69
70void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
71 size_t size, enum dma_data_direction dir)
72{
73 switch (dir) {
74 case DMA_TO_DEVICE:
75 cache_push(handle, size);
76 break;
77 case DMA_FROM_DEVICE:
78 cache_clear(handle, size);
79 break;
80 default:
81 if (printk_ratelimit())
82 printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
83 break;
84 }
85}
86EXPORT_SYMBOL(dma_sync_single_for_device);
87
88void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
89 enum dma_data_direction dir)
90{
91 int i;
92
93 for (i = 0; i < nents; sg++, i++)
94 dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
95}
96EXPORT_SYMBOL(dma_sync_sg_for_device);
97
98dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
99 enum dma_data_direction dir)
100{
101 dma_addr_t handle = virt_to_bus(addr);
102
103 dma_sync_single_for_device(dev, handle, size, dir);
104 return handle;
105}
106EXPORT_SYMBOL(dma_map_single);
107
108dma_addr_t dma_map_page(struct device *dev, struct page *page,
109 unsigned long offset, size_t size,
110 enum dma_data_direction dir)
111{
112 dma_addr_t handle = page_to_phys(page) + offset;
113
114 dma_sync_single_for_device(dev, handle, size, dir);
115 return handle;
116}
117EXPORT_SYMBOL(dma_map_page);
118
119int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
120 enum dma_data_direction dir)
121{
122 int i;
123
124 for (i = 0; i < nents; sg++, i++) {
125 sg->dma_address = sg_phys(sg);
126 dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
127 }
128 return nents;
129}
130EXPORT_SYMBOL(dma_map_sg);
diff --git a/arch/m68k/kernel/dma_mm.c b/arch/m68k/kernel/dma_mm.c
new file mode 100644
index 000000000000..4bbb3c2a8880
--- /dev/null
+++ b/arch/m68k/kernel/dma_mm.c
@@ -0,0 +1,130 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file COPYING in the main directory of this archive
4 * for more details.
5 */
6
7#undef DEBUG
8
9#include <linux/dma-mapping.h>
10#include <linux/device.h>
11#include <linux/kernel.h>
12#include <linux/scatterlist.h>
13#include <linux/slab.h>
14#include <linux/vmalloc.h>
15
16#include <asm/pgalloc.h>
17
18void *dma_alloc_coherent(struct device *dev, size_t size,
19 dma_addr_t *handle, gfp_t flag)
20{
21 struct page *page, **map;
22 pgprot_t pgprot;
23 void *addr;
24 int i, order;
25
26 pr_debug("dma_alloc_coherent: %d,%x\n", size, flag);
27
28 size = PAGE_ALIGN(size);
29 order = get_order(size);
30
31 page = alloc_pages(flag, order);
32 if (!page)
33 return NULL;
34
35 *handle = page_to_phys(page);
36 map = kmalloc(sizeof(struct page *) << order, flag & ~__GFP_DMA);
37 if (!map) {
38 __free_pages(page, order);
39 return NULL;
40 }
41 split_page(page, order);
42
43 order = 1 << order;
44 size >>= PAGE_SHIFT;
45 map[0] = page;
46 for (i = 1; i < size; i++)
47 map[i] = page + i;
48 for (; i < order; i++)
49 __free_page(page + i);
50 pgprot = __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
51 if (CPU_IS_040_OR_060)
52 pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
53 else
54 pgprot_val(pgprot) |= _PAGE_NOCACHE030;
55 addr = vmap(map, size, VM_MAP, pgprot);
56 kfree(map);
57
58 return addr;
59}
60EXPORT_SYMBOL(dma_alloc_coherent);
61
62void dma_free_coherent(struct device *dev, size_t size,
63 void *addr, dma_addr_t handle)
64{
65 pr_debug("dma_free_coherent: %p, %x\n", addr, handle);
66 vfree(addr);
67}
68EXPORT_SYMBOL(dma_free_coherent);
69
70void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
71 size_t size, enum dma_data_direction dir)
72{
73 switch (dir) {
74 case DMA_TO_DEVICE:
75 cache_push(handle, size);
76 break;
77 case DMA_FROM_DEVICE:
78 cache_clear(handle, size);
79 break;
80 default:
81 if (printk_ratelimit())
82 printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
83 break;
84 }
85}
86EXPORT_SYMBOL(dma_sync_single_for_device);
87
88void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents,
89 enum dma_data_direction dir)
90{
91 int i;
92
93 for (i = 0; i < nents; sg++, i++)
94 dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
95}
96EXPORT_SYMBOL(dma_sync_sg_for_device);
97
98dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
99 enum dma_data_direction dir)
100{
101 dma_addr_t handle = virt_to_bus(addr);
102
103 dma_sync_single_for_device(dev, handle, size, dir);
104 return handle;
105}
106EXPORT_SYMBOL(dma_map_single);
107
108dma_addr_t dma_map_page(struct device *dev, struct page *page,
109 unsigned long offset, size_t size,
110 enum dma_data_direction dir)
111{
112 dma_addr_t handle = page_to_phys(page) + offset;
113
114 dma_sync_single_for_device(dev, handle, size, dir);
115 return handle;
116}
117EXPORT_SYMBOL(dma_map_page);
118
119int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
120 enum dma_data_direction dir)
121{
122 int i;
123
124 for (i = 0; i < nents; sg++, i++) {
125 sg->dma_address = sg_phys(sg);
126 dma_sync_single_for_device(dev, sg->dma_address, sg->length, dir);
127 }
128 return nents;
129}
130EXPORT_SYMBOL(dma_map_sg);
diff --git a/arch/m68k/kernel/dma_no.c b/arch/m68k/kernel/dma_no.c
new file mode 100644
index 000000000000..fc61541aeb71
--- /dev/null
+++ b/arch/m68k/kernel/dma_no.c
@@ -0,0 +1,74 @@
1/*
2 * Dynamic DMA mapping support.
3 *
4 * We never have any address translations to worry about, so this
5 * is just alloc/free.
6 */
7
8#include <linux/types.h>
9#include <linux/gfp.h>
10#include <linux/mm.h>
11#include <linux/device.h>
12#include <linux/dma-mapping.h>
13#include <asm/cacheflush.h>
14
15void *dma_alloc_coherent(struct device *dev, size_t size,
16 dma_addr_t *dma_handle, gfp_t gfp)
17{
18 void *ret;
19 /* ignore region specifiers */
20 gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
21
22 if (dev == NULL || (*dev->dma_mask < 0xffffffff))
23 gfp |= GFP_DMA;
24 ret = (void *)__get_free_pages(gfp, get_order(size));
25
26 if (ret != NULL) {
27 memset(ret, 0, size);
28 *dma_handle = virt_to_phys(ret);
29 }
30 return ret;
31}
32
33void dma_free_coherent(struct device *dev, size_t size,
34 void *vaddr, dma_addr_t dma_handle)
35{
36 free_pages((unsigned long)vaddr, get_order(size));
37}
38
39void dma_sync_single_for_device(struct device *dev, dma_addr_t handle,
40 size_t size, enum dma_data_direction dir)
41{
42 switch (dir) {
43 case DMA_TO_DEVICE:
44 flush_dcache_range(handle, size);
45 break;
46 case DMA_FROM_DEVICE:
47 /* Should be clear already */
48 break;
49 default:
50 if (printk_ratelimit())
51 printk("dma_sync_single_for_device: unsupported dir %u\n", dir);
52 break;
53 }
54}
55
56EXPORT_SYMBOL(dma_sync_single_for_device);
57dma_addr_t dma_map_single(struct device *dev, void *addr, size_t size,
58 enum dma_data_direction dir)
59{
60 dma_addr_t handle = virt_to_phys(addr);
61 flush_dcache_range(handle, size);
62 return handle;
63}
64EXPORT_SYMBOL(dma_map_single);
65
66dma_addr_t dma_map_page(struct device *dev, struct page *page,
67 unsigned long offset, size_t size,
68 enum dma_data_direction dir)
69{
70 dma_addr_t handle = page_to_phys(page) + offset;
71 dma_sync_single_for_device(dev, handle, size, dir);
72 return handle;
73}
74EXPORT_SYMBOL(dma_map_page);
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 6360c437dcf5..081cf96f243b 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -1,771 +1,5 @@
1/* -*- mode: asm -*- 1#ifdef CONFIG_MMU
2 * 2#include "entry_mm.S"
3 * linux/arch/m68k/kernel/entry.S 3#else
4 * 4#include "entry_no.S"
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file README.legal in the main directory of this archive
9 * for more details.
10 *
11 * Linux/m68k support by Hamish Macdonald
12 *
13 * 68060 fixes by Jesper Skov
14 *
15 */
16
17/*
18 * entry.S contains the system-call and fault low-level handling routines.
19 * This also contains the timer-interrupt handler, as well as all interrupts
20 * and faults that can result in a task-switch.
21 *
22 * NOTE: This code handles signal-recognition, which happens every time
23 * after a timer-interrupt and after each system call.
24 *
25 */
26
27/*
28 * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
29 * all pointers that used to be 'current' are now entry
30 * number 0 in the 'current_set' list.
31 *
32 * 6/05/00 RZ: addedd writeback completion after return from sighandler
33 * for 68040
34 */
35
36#include <linux/linkage.h>
37#include <asm/entry.h>
38#include <asm/errno.h>
39#include <asm/setup.h>
40#include <asm/segment.h>
41#include <asm/traps.h>
42#include <asm/unistd.h>
43
44#include <asm/asm-offsets.h>
45
46.globl system_call, buserr, trap, resume
47.globl sys_call_table
48.globl sys_fork, sys_clone, sys_vfork
49.globl ret_from_interrupt, bad_interrupt
50.globl auto_irqhandler_fixup
51.globl user_irqvec_fixup, user_irqhandler_fixup
52
53.text
54ENTRY(buserr)
55 SAVE_ALL_INT
56 GET_CURRENT(%d0)
57 movel %sp,%sp@- | stack frame pointer argument
58 bsrl buserr_c
59 addql #4,%sp
60 jra .Lret_from_exception
61
62ENTRY(trap)
63 SAVE_ALL_INT
64 GET_CURRENT(%d0)
65 movel %sp,%sp@- | stack frame pointer argument
66 bsrl trap_c
67 addql #4,%sp
68 jra .Lret_from_exception
69
70 | After a fork we jump here directly from resume,
71 | so that %d1 contains the previous task
72 | schedule_tail now used regardless of CONFIG_SMP
73ENTRY(ret_from_fork)
74 movel %d1,%sp@-
75 jsr schedule_tail
76 addql #4,%sp
77 jra .Lret_from_exception
78
79do_trace_entry:
80 movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
81 subql #4,%sp
82 SAVE_SWITCH_STACK
83 jbsr syscall_trace
84 RESTORE_SWITCH_STACK
85 addql #4,%sp
86 movel %sp@(PT_OFF_ORIG_D0),%d0
87 cmpl #NR_syscalls,%d0
88 jcs syscall
89badsys:
90 movel #-ENOSYS,%sp@(PT_OFF_D0)
91 jra ret_from_syscall
92
93do_trace_exit:
94 subql #4,%sp
95 SAVE_SWITCH_STACK
96 jbsr syscall_trace
97 RESTORE_SWITCH_STACK
98 addql #4,%sp
99 jra .Lret_from_exception
100
101ENTRY(ret_from_signal)
102 RESTORE_SWITCH_STACK
103 addql #4,%sp
104/* on 68040 complete pending writebacks if any */
105#ifdef CONFIG_M68040
106 bfextu %sp@(PT_OFF_FORMATVEC){#0,#4},%d0
107 subql #7,%d0 | bus error frame ?
108 jbne 1f
109 movel %sp,%sp@-
110 jbsr berr_040cleanup
111 addql #4,%sp
1121:
113#endif 5#endif
114 jra .Lret_from_exception
115
116ENTRY(system_call)
117 SAVE_ALL_SYS
118
119 GET_CURRENT(%d1)
120 | save top of frame
121 movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
122
123 | syscall trace?
124 tstb %curptr@(TASK_INFO+TINFO_FLAGS+2)
125 jmi do_trace_entry
126 cmpl #NR_syscalls,%d0
127 jcc badsys
128syscall:
129 jbsr @(sys_call_table,%d0:l:4)@(0)
130 movel %d0,%sp@(PT_OFF_D0) | save the return value
131ret_from_syscall:
132 |oriw #0x0700,%sr
133 movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
134 jne syscall_exit_work
1351: RESTORE_ALL
136
137syscall_exit_work:
138 btst #5,%sp@(PT_OFF_SR) | check if returning to kernel
139 bnes 1b | if so, skip resched, signals
140 lslw #1,%d0
141 jcs do_trace_exit
142 jmi do_delayed_trace
143 lslw #8,%d0
144 jmi do_signal_return
145 pea resume_userspace
146 jra schedule
147
148
149ENTRY(ret_from_exception)
150.Lret_from_exception:
151 btst #5,%sp@(PT_OFF_SR) | check if returning to kernel
152 bnes 1f | if so, skip resched, signals
153 | only allow interrupts when we are really the last one on the
154 | kernel stack, otherwise stack overflow can occur during
155 | heavy interrupt load
156 andw #ALLOWINT,%sr
157
158resume_userspace:
159 moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0
160 jne exit_work
1611: RESTORE_ALL
162
163exit_work:
164 | save top of frame
165 movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
166 lslb #1,%d0
167 jmi do_signal_return
168 pea resume_userspace
169 jra schedule
170
171
172do_signal_return:
173 |andw #ALLOWINT,%sr
174 subql #4,%sp | dummy return address
175 SAVE_SWITCH_STACK
176 pea %sp@(SWITCH_STACK_SIZE)
177 clrl %sp@-
178 bsrl do_signal
179 addql #8,%sp
180 RESTORE_SWITCH_STACK
181 addql #4,%sp
182 tstl %d0
183 jeq resume_userspace
184 | when single stepping into handler stop at the first insn
185 btst #6,%curptr@(TASK_INFO+TINFO_FLAGS+2)
186 jeq resume_userspace
187
188do_delayed_trace:
189 bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR
190 pea 1 | send SIGTRAP
191 movel %curptr,%sp@-
192 pea LSIGTRAP
193 jbsr send_sig
194 addql #8,%sp
195 addql #4,%sp
196 jbra resume_userspace
197
198
199/* This is the main interrupt handler for autovector interrupts */
200
201ENTRY(auto_inthandler)
202 SAVE_ALL_INT
203 GET_CURRENT(%d0)
204 addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
205 | put exception # in d0
206 bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
207 subw #VEC_SPUR,%d0
208
209 movel %sp,%sp@-
210 movel %d0,%sp@- | put vector # on stack
211auto_irqhandler_fixup = . + 2
212 jsr __m68k_handle_int | process the IRQ
213 addql #8,%sp | pop parameters off stack
214
215ret_from_interrupt:
216 subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
217 jeq ret_from_last_interrupt
2182: RESTORE_ALL
219
220 ALIGN
221ret_from_last_interrupt:
222 moveq #(~ALLOWINT>>8)&0xff,%d0
223 andb %sp@(PT_OFF_SR),%d0
224 jne 2b
225
226 /* check if we need to do software interrupts */
227 tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING
228 jeq .Lret_from_exception
229 pea ret_from_exception
230 jra do_softirq
231
232/* Handler for user defined interrupt vectors */
233
234ENTRY(user_inthandler)
235 SAVE_ALL_INT
236 GET_CURRENT(%d0)
237 addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
238 | put exception # in d0
239 bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
240user_irqvec_fixup = . + 2
241 subw #VEC_USER,%d0
242
243 movel %sp,%sp@-
244 movel %d0,%sp@- | put vector # on stack
245user_irqhandler_fixup = . + 2
246 jsr __m68k_handle_int | process the IRQ
247 addql #8,%sp | pop parameters off stack
248
249 subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
250 jeq ret_from_last_interrupt
251 RESTORE_ALL
252
253/* Handler for uninitialized and spurious interrupts */
254
255ENTRY(bad_inthandler)
256 SAVE_ALL_INT
257 GET_CURRENT(%d0)
258 addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
259
260 movel %sp,%sp@-
261 jsr handle_badint
262 addql #4,%sp
263
264 subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
265 jeq ret_from_last_interrupt
266 RESTORE_ALL
267
268
269ENTRY(sys_fork)
270 SAVE_SWITCH_STACK
271 pea %sp@(SWITCH_STACK_SIZE)
272 jbsr m68k_fork
273 addql #4,%sp
274 RESTORE_SWITCH_STACK
275 rts
276
277ENTRY(sys_clone)
278 SAVE_SWITCH_STACK
279 pea %sp@(SWITCH_STACK_SIZE)
280 jbsr m68k_clone
281 addql #4,%sp
282 RESTORE_SWITCH_STACK
283 rts
284
285ENTRY(sys_vfork)
286 SAVE_SWITCH_STACK
287 pea %sp@(SWITCH_STACK_SIZE)
288 jbsr m68k_vfork
289 addql #4,%sp
290 RESTORE_SWITCH_STACK
291 rts
292
293ENTRY(sys_sigsuspend)
294 SAVE_SWITCH_STACK
295 pea %sp@(SWITCH_STACK_SIZE)
296 jbsr do_sigsuspend
297 addql #4,%sp
298 RESTORE_SWITCH_STACK
299 rts
300
301ENTRY(sys_rt_sigsuspend)
302 SAVE_SWITCH_STACK
303 pea %sp@(SWITCH_STACK_SIZE)
304 jbsr do_rt_sigsuspend
305 addql #4,%sp
306 RESTORE_SWITCH_STACK
307 rts
308
309ENTRY(sys_sigreturn)
310 SAVE_SWITCH_STACK
311 jbsr do_sigreturn
312 RESTORE_SWITCH_STACK
313 rts
314
315ENTRY(sys_rt_sigreturn)
316 SAVE_SWITCH_STACK
317 jbsr do_rt_sigreturn
318 RESTORE_SWITCH_STACK
319 rts
320
321resume:
322 /*
323 * Beware - when entering resume, prev (the current task) is
324 * in a0, next (the new task) is in a1,so don't change these
325 * registers until their contents are no longer needed.
326 */
327
328 /* save sr */
329 movew %sr,%a0@(TASK_THREAD+THREAD_SR)
330
331 /* save fs (sfc,%dfc) (may be pointing to kernel memory) */
332 movec %sfc,%d0
333 movew %d0,%a0@(TASK_THREAD+THREAD_FS)
334
335 /* save usp */
336 /* it is better to use a movel here instead of a movew 8*) */
337 movec %usp,%d0
338 movel %d0,%a0@(TASK_THREAD+THREAD_USP)
339
340 /* save non-scratch registers on stack */
341 SAVE_SWITCH_STACK
342
343 /* save current kernel stack pointer */
344 movel %sp,%a0@(TASK_THREAD+THREAD_KSP)
345
346 /* save floating point context */
347#ifndef CONFIG_M68KFPU_EMU_ONLY
348#ifdef CONFIG_M68KFPU_EMU
349 tstl m68k_fputype
350 jeq 3f
351#endif
352 fsave %a0@(TASK_THREAD+THREAD_FPSTATE)
353
354#if defined(CONFIG_M68060)
355#if !defined(CPU_M68060_ONLY)
356 btst #3,m68k_cputype+3
357 beqs 1f
358#endif
359 /* The 060 FPU keeps status in bits 15-8 of the first longword */
360 tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2)
361 jeq 3f
362#if !defined(CPU_M68060_ONLY)
363 jra 2f
364#endif
365#endif /* CONFIG_M68060 */
366#if !defined(CPU_M68060_ONLY)
3671: tstb %a0@(TASK_THREAD+THREAD_FPSTATE)
368 jeq 3f
369#endif
3702: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
371 fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
3723:
373#endif /* CONFIG_M68KFPU_EMU_ONLY */
374 /* Return previous task in %d1 */
375 movel %curptr,%d1
376
377 /* switch to new task (a1 contains new task) */
378 movel %a1,%curptr
379
380 /* restore floating point context */
381#ifndef CONFIG_M68KFPU_EMU_ONLY
382#ifdef CONFIG_M68KFPU_EMU
383 tstl m68k_fputype
384 jeq 4f
385#endif
386#if defined(CONFIG_M68060)
387#if !defined(CPU_M68060_ONLY)
388 btst #3,m68k_cputype+3
389 beqs 1f
390#endif
391 /* The 060 FPU keeps status in bits 15-8 of the first longword */
392 tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2)
393 jeq 3f
394#if !defined(CPU_M68060_ONLY)
395 jra 2f
396#endif
397#endif /* CONFIG_M68060 */
398#if !defined(CPU_M68060_ONLY)
3991: tstb %a1@(TASK_THREAD+THREAD_FPSTATE)
400 jeq 3f
401#endif
4022: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
403 fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
4043: frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
4054:
406#endif /* CONFIG_M68KFPU_EMU_ONLY */
407
408 /* restore the kernel stack pointer */
409 movel %a1@(TASK_THREAD+THREAD_KSP),%sp
410
411 /* restore non-scratch registers */
412 RESTORE_SWITCH_STACK
413
414 /* restore user stack pointer */
415 movel %a1@(TASK_THREAD+THREAD_USP),%a0
416 movel %a0,%usp
417
418 /* restore fs (sfc,%dfc) */
419 movew %a1@(TASK_THREAD+THREAD_FS),%a0
420 movec %a0,%sfc
421 movec %a0,%dfc
422
423 /* restore status register */
424 movew %a1@(TASK_THREAD+THREAD_SR),%sr
425
426 rts
427
428.data
429ALIGN
430sys_call_table:
431 .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
432 .long sys_exit
433 .long sys_fork
434 .long sys_read
435 .long sys_write
436 .long sys_open /* 5 */
437 .long sys_close
438 .long sys_waitpid
439 .long sys_creat
440 .long sys_link
441 .long sys_unlink /* 10 */
442 .long sys_execve
443 .long sys_chdir
444 .long sys_time
445 .long sys_mknod
446 .long sys_chmod /* 15 */
447 .long sys_chown16
448 .long sys_ni_syscall /* old break syscall holder */
449 .long sys_stat
450 .long sys_lseek
451 .long sys_getpid /* 20 */
452 .long sys_mount
453 .long sys_oldumount
454 .long sys_setuid16
455 .long sys_getuid16
456 .long sys_stime /* 25 */
457 .long sys_ptrace
458 .long sys_alarm
459 .long sys_fstat
460 .long sys_pause
461 .long sys_utime /* 30 */
462 .long sys_ni_syscall /* old stty syscall holder */
463 .long sys_ni_syscall /* old gtty syscall holder */
464 .long sys_access
465 .long sys_nice
466 .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
467 .long sys_sync
468 .long sys_kill
469 .long sys_rename
470 .long sys_mkdir
471 .long sys_rmdir /* 40 */
472 .long sys_dup
473 .long sys_pipe
474 .long sys_times
475 .long sys_ni_syscall /* old prof syscall holder */
476 .long sys_brk /* 45 */
477 .long sys_setgid16
478 .long sys_getgid16
479 .long sys_signal
480 .long sys_geteuid16
481 .long sys_getegid16 /* 50 */
482 .long sys_acct
483 .long sys_umount /* recycled never used phys() */
484 .long sys_ni_syscall /* old lock syscall holder */
485 .long sys_ioctl
486 .long sys_fcntl /* 55 */
487 .long sys_ni_syscall /* old mpx syscall holder */
488 .long sys_setpgid
489 .long sys_ni_syscall /* old ulimit syscall holder */
490 .long sys_ni_syscall
491 .long sys_umask /* 60 */
492 .long sys_chroot
493 .long sys_ustat
494 .long sys_dup2
495 .long sys_getppid
496 .long sys_getpgrp /* 65 */
497 .long sys_setsid
498 .long sys_sigaction
499 .long sys_sgetmask
500 .long sys_ssetmask
501 .long sys_setreuid16 /* 70 */
502 .long sys_setregid16
503 .long sys_sigsuspend
504 .long sys_sigpending
505 .long sys_sethostname
506 .long sys_setrlimit /* 75 */
507 .long sys_old_getrlimit
508 .long sys_getrusage
509 .long sys_gettimeofday
510 .long sys_settimeofday
511 .long sys_getgroups16 /* 80 */
512 .long sys_setgroups16
513 .long sys_old_select
514 .long sys_symlink
515 .long sys_lstat
516 .long sys_readlink /* 85 */
517 .long sys_uselib
518 .long sys_swapon
519 .long sys_reboot
520 .long sys_old_readdir
521 .long sys_old_mmap /* 90 */
522 .long sys_munmap
523 .long sys_truncate
524 .long sys_ftruncate
525 .long sys_fchmod
526 .long sys_fchown16 /* 95 */
527 .long sys_getpriority
528 .long sys_setpriority
529 .long sys_ni_syscall /* old profil syscall holder */
530 .long sys_statfs
531 .long sys_fstatfs /* 100 */
532 .long sys_ni_syscall /* ioperm for i386 */
533 .long sys_socketcall
534 .long sys_syslog
535 .long sys_setitimer
536 .long sys_getitimer /* 105 */
537 .long sys_newstat
538 .long sys_newlstat
539 .long sys_newfstat
540 .long sys_ni_syscall
541 .long sys_ni_syscall /* 110 */ /* iopl for i386 */
542 .long sys_vhangup
543 .long sys_ni_syscall /* obsolete idle() syscall */
544 .long sys_ni_syscall /* vm86old for i386 */
545 .long sys_wait4
546 .long sys_swapoff /* 115 */
547 .long sys_sysinfo
548 .long sys_ipc
549 .long sys_fsync
550 .long sys_sigreturn
551 .long sys_clone /* 120 */
552 .long sys_setdomainname
553 .long sys_newuname
554 .long sys_cacheflush /* modify_ldt for i386 */
555 .long sys_adjtimex
556 .long sys_mprotect /* 125 */
557 .long sys_sigprocmask
558 .long sys_ni_syscall /* old "create_module" */
559 .long sys_init_module
560 .long sys_delete_module
561 .long sys_ni_syscall /* 130 - old "get_kernel_syms" */
562 .long sys_quotactl
563 .long sys_getpgid
564 .long sys_fchdir
565 .long sys_bdflush
566 .long sys_sysfs /* 135 */
567 .long sys_personality
568 .long sys_ni_syscall /* for afs_syscall */
569 .long sys_setfsuid16
570 .long sys_setfsgid16
571 .long sys_llseek /* 140 */
572 .long sys_getdents
573 .long sys_select
574 .long sys_flock
575 .long sys_msync
576 .long sys_readv /* 145 */
577 .long sys_writev
578 .long sys_getsid
579 .long sys_fdatasync
580 .long sys_sysctl
581 .long sys_mlock /* 150 */
582 .long sys_munlock
583 .long sys_mlockall
584 .long sys_munlockall
585 .long sys_sched_setparam
586 .long sys_sched_getparam /* 155 */
587 .long sys_sched_setscheduler
588 .long sys_sched_getscheduler
589 .long sys_sched_yield
590 .long sys_sched_get_priority_max
591 .long sys_sched_get_priority_min /* 160 */
592 .long sys_sched_rr_get_interval
593 .long sys_nanosleep
594 .long sys_mremap
595 .long sys_setresuid16
596 .long sys_getresuid16 /* 165 */
597 .long sys_getpagesize
598 .long sys_ni_syscall /* old sys_query_module */
599 .long sys_poll
600 .long sys_nfsservctl
601 .long sys_setresgid16 /* 170 */
602 .long sys_getresgid16
603 .long sys_prctl
604 .long sys_rt_sigreturn
605 .long sys_rt_sigaction
606 .long sys_rt_sigprocmask /* 175 */
607 .long sys_rt_sigpending
608 .long sys_rt_sigtimedwait
609 .long sys_rt_sigqueueinfo
610 .long sys_rt_sigsuspend
611 .long sys_pread64 /* 180 */
612 .long sys_pwrite64
613 .long sys_lchown16;
614 .long sys_getcwd
615 .long sys_capget
616 .long sys_capset /* 185 */
617 .long sys_sigaltstack
618 .long sys_sendfile
619 .long sys_ni_syscall /* streams1 */
620 .long sys_ni_syscall /* streams2 */
621 .long sys_vfork /* 190 */
622 .long sys_getrlimit
623 .long sys_mmap2
624 .long sys_truncate64
625 .long sys_ftruncate64
626 .long sys_stat64 /* 195 */
627 .long sys_lstat64
628 .long sys_fstat64
629 .long sys_chown
630 .long sys_getuid
631 .long sys_getgid /* 200 */
632 .long sys_geteuid
633 .long sys_getegid
634 .long sys_setreuid
635 .long sys_setregid
636 .long sys_getgroups /* 205 */
637 .long sys_setgroups
638 .long sys_fchown
639 .long sys_setresuid
640 .long sys_getresuid
641 .long sys_setresgid /* 210 */
642 .long sys_getresgid
643 .long sys_lchown
644 .long sys_setuid
645 .long sys_setgid
646 .long sys_setfsuid /* 215 */
647 .long sys_setfsgid
648 .long sys_pivot_root
649 .long sys_ni_syscall
650 .long sys_ni_syscall
651 .long sys_getdents64 /* 220 */
652 .long sys_gettid
653 .long sys_tkill
654 .long sys_setxattr
655 .long sys_lsetxattr
656 .long sys_fsetxattr /* 225 */
657 .long sys_getxattr
658 .long sys_lgetxattr
659 .long sys_fgetxattr
660 .long sys_listxattr
661 .long sys_llistxattr /* 230 */
662 .long sys_flistxattr
663 .long sys_removexattr
664 .long sys_lremovexattr
665 .long sys_fremovexattr
666 .long sys_futex /* 235 */
667 .long sys_sendfile64
668 .long sys_mincore
669 .long sys_madvise
670 .long sys_fcntl64
671 .long sys_readahead /* 240 */
672 .long sys_io_setup
673 .long sys_io_destroy
674 .long sys_io_getevents
675 .long sys_io_submit
676 .long sys_io_cancel /* 245 */
677 .long sys_fadvise64
678 .long sys_exit_group
679 .long sys_lookup_dcookie
680 .long sys_epoll_create
681 .long sys_epoll_ctl /* 250 */
682 .long sys_epoll_wait
683 .long sys_remap_file_pages
684 .long sys_set_tid_address
685 .long sys_timer_create
686 .long sys_timer_settime /* 255 */
687 .long sys_timer_gettime
688 .long sys_timer_getoverrun
689 .long sys_timer_delete
690 .long sys_clock_settime
691 .long sys_clock_gettime /* 260 */
692 .long sys_clock_getres
693 .long sys_clock_nanosleep
694 .long sys_statfs64
695 .long sys_fstatfs64
696 .long sys_tgkill /* 265 */
697 .long sys_utimes
698 .long sys_fadvise64_64
699 .long sys_mbind
700 .long sys_get_mempolicy
701 .long sys_set_mempolicy /* 270 */
702 .long sys_mq_open
703 .long sys_mq_unlink
704 .long sys_mq_timedsend
705 .long sys_mq_timedreceive
706 .long sys_mq_notify /* 275 */
707 .long sys_mq_getsetattr
708 .long sys_waitid
709 .long sys_ni_syscall /* for sys_vserver */
710 .long sys_add_key
711 .long sys_request_key /* 280 */
712 .long sys_keyctl
713 .long sys_ioprio_set
714 .long sys_ioprio_get
715 .long sys_inotify_init
716 .long sys_inotify_add_watch /* 285 */
717 .long sys_inotify_rm_watch
718 .long sys_migrate_pages
719 .long sys_openat
720 .long sys_mkdirat
721 .long sys_mknodat /* 290 */
722 .long sys_fchownat
723 .long sys_futimesat
724 .long sys_fstatat64
725 .long sys_unlinkat
726 .long sys_renameat /* 295 */
727 .long sys_linkat
728 .long sys_symlinkat
729 .long sys_readlinkat
730 .long sys_fchmodat
731 .long sys_faccessat /* 300 */
732 .long sys_ni_syscall /* Reserved for pselect6 */
733 .long sys_ni_syscall /* Reserved for ppoll */
734 .long sys_unshare
735 .long sys_set_robust_list
736 .long sys_get_robust_list /* 305 */
737 .long sys_splice
738 .long sys_sync_file_range
739 .long sys_tee
740 .long sys_vmsplice
741 .long sys_move_pages /* 310 */
742 .long sys_sched_setaffinity
743 .long sys_sched_getaffinity
744 .long sys_kexec_load
745 .long sys_getcpu
746 .long sys_epoll_pwait /* 315 */
747 .long sys_utimensat
748 .long sys_signalfd
749 .long sys_timerfd_create
750 .long sys_eventfd
751 .long sys_fallocate /* 320 */
752 .long sys_timerfd_settime
753 .long sys_timerfd_gettime
754 .long sys_signalfd4
755 .long sys_eventfd2
756 .long sys_epoll_create1 /* 325 */
757 .long sys_dup3
758 .long sys_pipe2
759 .long sys_inotify_init1
760 .long sys_preadv
761 .long sys_pwritev /* 330 */
762 .long sys_rt_tgsigqueueinfo
763 .long sys_perf_event_open
764 .long sys_get_thread_area
765 .long sys_set_thread_area
766 .long sys_atomic_cmpxchg_32 /* 335 */
767 .long sys_atomic_barrier
768 .long sys_fanotify_init
769 .long sys_fanotify_mark
770 .long sys_prlimit64
771
diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S
new file mode 100644
index 000000000000..bd0ec05263b2
--- /dev/null
+++ b/arch/m68k/kernel/entry_mm.S
@@ -0,0 +1,409 @@
1/* -*- mode: asm -*-
2 *
3 * linux/arch/m68k/kernel/entry.S
4 *
5 * Copyright (C) 1991, 1992 Linus Torvalds
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file README.legal in the main directory of this archive
9 * for more details.
10 *
11 * Linux/m68k support by Hamish Macdonald
12 *
13 * 68060 fixes by Jesper Skov
14 *
15 */
16
17/*
18 * entry.S contains the system-call and fault low-level handling routines.
19 * This also contains the timer-interrupt handler, as well as all interrupts
20 * and faults that can result in a task-switch.
21 *
22 * NOTE: This code handles signal-recognition, which happens every time
23 * after a timer-interrupt and after each system call.
24 *
25 */
26
27/*
28 * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
29 * all pointers that used to be 'current' are now entry
30 * number 0 in the 'current_set' list.
31 *
32 * 6/05/00 RZ: addedd writeback completion after return from sighandler
33 * for 68040
34 */
35
36#include <linux/linkage.h>
37#include <asm/entry.h>
38#include <asm/errno.h>
39#include <asm/setup.h>
40#include <asm/segment.h>
41#include <asm/traps.h>
42#include <asm/unistd.h>
43
44#include <asm/asm-offsets.h>
45
46.globl system_call, buserr, trap, resume
47.globl sys_call_table
48.globl sys_fork, sys_clone, sys_vfork
49.globl ret_from_interrupt, bad_interrupt
50.globl auto_irqhandler_fixup
51.globl user_irqvec_fixup, user_irqhandler_fixup
52
53.text
54ENTRY(buserr)
55 SAVE_ALL_INT
56 GET_CURRENT(%d0)
57 movel %sp,%sp@- | stack frame pointer argument
58 bsrl buserr_c
59 addql #4,%sp
60 jra .Lret_from_exception
61
62ENTRY(trap)
63 SAVE_ALL_INT
64 GET_CURRENT(%d0)
65 movel %sp,%sp@- | stack frame pointer argument
66 bsrl trap_c
67 addql #4,%sp
68 jra .Lret_from_exception
69
70 | After a fork we jump here directly from resume,
71 | so that %d1 contains the previous task
72 | schedule_tail now used regardless of CONFIG_SMP
73ENTRY(ret_from_fork)
74 movel %d1,%sp@-
75 jsr schedule_tail
76 addql #4,%sp
77 jra .Lret_from_exception
78
79do_trace_entry:
80 movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
81 subql #4,%sp
82 SAVE_SWITCH_STACK
83 jbsr syscall_trace
84 RESTORE_SWITCH_STACK
85 addql #4,%sp
86 movel %sp@(PT_OFF_ORIG_D0),%d0
87 cmpl #NR_syscalls,%d0
88 jcs syscall
89badsys:
90 movel #-ENOSYS,%sp@(PT_OFF_D0)
91 jra ret_from_syscall
92
93do_trace_exit:
94 subql #4,%sp
95 SAVE_SWITCH_STACK
96 jbsr syscall_trace
97 RESTORE_SWITCH_STACK
98 addql #4,%sp
99 jra .Lret_from_exception
100
101ENTRY(ret_from_signal)
102 tstb %curptr@(TASK_INFO+TINFO_FLAGS+2)
103 jge 1f
104 jbsr syscall_trace
1051: RESTORE_SWITCH_STACK
106 addql #4,%sp
107/* on 68040 complete pending writebacks if any */
108#ifdef CONFIG_M68040
109 bfextu %sp@(PT_OFF_FORMATVEC){#0,#4},%d0
110 subql #7,%d0 | bus error frame ?
111 jbne 1f
112 movel %sp,%sp@-
113 jbsr berr_040cleanup
114 addql #4,%sp
1151:
116#endif
117 jra .Lret_from_exception
118
119ENTRY(system_call)
120 SAVE_ALL_SYS
121
122 GET_CURRENT(%d1)
123 | save top of frame
124 movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
125
126 | syscall trace?
127 tstb %curptr@(TASK_INFO+TINFO_FLAGS+2)
128 jmi do_trace_entry
129 cmpl #NR_syscalls,%d0
130 jcc badsys
131syscall:
132 jbsr @(sys_call_table,%d0:l:4)@(0)
133 movel %d0,%sp@(PT_OFF_D0) | save the return value
134ret_from_syscall:
135 |oriw #0x0700,%sr
136 movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0
137 jne syscall_exit_work
1381: RESTORE_ALL
139
140syscall_exit_work:
141 btst #5,%sp@(PT_OFF_SR) | check if returning to kernel
142 bnes 1b | if so, skip resched, signals
143 lslw #1,%d0
144 jcs do_trace_exit
145 jmi do_delayed_trace
146 lslw #8,%d0
147 jmi do_signal_return
148 pea resume_userspace
149 jra schedule
150
151
152ENTRY(ret_from_exception)
153.Lret_from_exception:
154 btst #5,%sp@(PT_OFF_SR) | check if returning to kernel
155 bnes 1f | if so, skip resched, signals
156 | only allow interrupts when we are really the last one on the
157 | kernel stack, otherwise stack overflow can occur during
158 | heavy interrupt load
159 andw #ALLOWINT,%sr
160
161resume_userspace:
162 moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0
163 jne exit_work
1641: RESTORE_ALL
165
166exit_work:
167 | save top of frame
168 movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
169 lslb #1,%d0
170 jmi do_signal_return
171 pea resume_userspace
172 jra schedule
173
174
175do_signal_return:
176 |andw #ALLOWINT,%sr
177 subql #4,%sp | dummy return address
178 SAVE_SWITCH_STACK
179 pea %sp@(SWITCH_STACK_SIZE)
180 bsrl do_signal
181 addql #4,%sp
182 RESTORE_SWITCH_STACK
183 addql #4,%sp
184 jbra resume_userspace
185
186do_delayed_trace:
187 bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR
188 pea 1 | send SIGTRAP
189 movel %curptr,%sp@-
190 pea LSIGTRAP
191 jbsr send_sig
192 addql #8,%sp
193 addql #4,%sp
194 jbra resume_userspace
195
196
197/* This is the main interrupt handler for autovector interrupts */
198
199ENTRY(auto_inthandler)
200 SAVE_ALL_INT
201 GET_CURRENT(%d0)
202 addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
203 | put exception # in d0
204 bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
205 subw #VEC_SPUR,%d0
206
207 movel %sp,%sp@-
208 movel %d0,%sp@- | put vector # on stack
209auto_irqhandler_fixup = . + 2
210 jsr __m68k_handle_int | process the IRQ
211 addql #8,%sp | pop parameters off stack
212
213ret_from_interrupt:
214 subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
215 jeq ret_from_last_interrupt
2162: RESTORE_ALL
217
218 ALIGN
219ret_from_last_interrupt:
220 moveq #(~ALLOWINT>>8)&0xff,%d0
221 andb %sp@(PT_OFF_SR),%d0
222 jne 2b
223
224 /* check if we need to do software interrupts */
225 tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING
226 jeq .Lret_from_exception
227 pea ret_from_exception
228 jra do_softirq
229
230/* Handler for user defined interrupt vectors */
231
232ENTRY(user_inthandler)
233 SAVE_ALL_INT
234 GET_CURRENT(%d0)
235 addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
236 | put exception # in d0
237 bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
238user_irqvec_fixup = . + 2
239 subw #VEC_USER,%d0
240
241 movel %sp,%sp@-
242 movel %d0,%sp@- | put vector # on stack
243user_irqhandler_fixup = . + 2
244 jsr __m68k_handle_int | process the IRQ
245 addql #8,%sp | pop parameters off stack
246
247 subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
248 jeq ret_from_last_interrupt
249 RESTORE_ALL
250
251/* Handler for uninitialized and spurious interrupts */
252
253ENTRY(bad_inthandler)
254 SAVE_ALL_INT
255 GET_CURRENT(%d0)
256 addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
257
258 movel %sp,%sp@-
259 jsr handle_badint
260 addql #4,%sp
261
262 subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
263 jeq ret_from_last_interrupt
264 RESTORE_ALL
265
266
267ENTRY(sys_fork)
268 SAVE_SWITCH_STACK
269 pea %sp@(SWITCH_STACK_SIZE)
270 jbsr m68k_fork
271 addql #4,%sp
272 RESTORE_SWITCH_STACK
273 rts
274
275ENTRY(sys_clone)
276 SAVE_SWITCH_STACK
277 pea %sp@(SWITCH_STACK_SIZE)
278 jbsr m68k_clone
279 addql #4,%sp
280 RESTORE_SWITCH_STACK
281 rts
282
283ENTRY(sys_vfork)
284 SAVE_SWITCH_STACK
285 pea %sp@(SWITCH_STACK_SIZE)
286 jbsr m68k_vfork
287 addql #4,%sp
288 RESTORE_SWITCH_STACK
289 rts
290
291ENTRY(sys_sigreturn)
292 SAVE_SWITCH_STACK
293 jbsr do_sigreturn
294 RESTORE_SWITCH_STACK
295 rts
296
297ENTRY(sys_rt_sigreturn)
298 SAVE_SWITCH_STACK
299 jbsr do_rt_sigreturn
300 RESTORE_SWITCH_STACK
301 rts
302
303resume:
304 /*
305 * Beware - when entering resume, prev (the current task) is
306 * in a0, next (the new task) is in a1,so don't change these
307 * registers until their contents are no longer needed.
308 */
309
310 /* save sr */
311 movew %sr,%a0@(TASK_THREAD+THREAD_SR)
312
313 /* save fs (sfc,%dfc) (may be pointing to kernel memory) */
314 movec %sfc,%d0
315 movew %d0,%a0@(TASK_THREAD+THREAD_FS)
316
317 /* save usp */
318 /* it is better to use a movel here instead of a movew 8*) */
319 movec %usp,%d0
320 movel %d0,%a0@(TASK_THREAD+THREAD_USP)
321
322 /* save non-scratch registers on stack */
323 SAVE_SWITCH_STACK
324
325 /* save current kernel stack pointer */
326 movel %sp,%a0@(TASK_THREAD+THREAD_KSP)
327
328 /* save floating point context */
329#ifndef CONFIG_M68KFPU_EMU_ONLY
330#ifdef CONFIG_M68KFPU_EMU
331 tstl m68k_fputype
332 jeq 3f
333#endif
334 fsave %a0@(TASK_THREAD+THREAD_FPSTATE)
335
336#if defined(CONFIG_M68060)
337#if !defined(CPU_M68060_ONLY)
338 btst #3,m68k_cputype+3
339 beqs 1f
340#endif
341 /* The 060 FPU keeps status in bits 15-8 of the first longword */
342 tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2)
343 jeq 3f
344#if !defined(CPU_M68060_ONLY)
345 jra 2f
346#endif
347#endif /* CONFIG_M68060 */
348#if !defined(CPU_M68060_ONLY)
3491: tstb %a0@(TASK_THREAD+THREAD_FPSTATE)
350 jeq 3f
351#endif
3522: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
353 fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
3543:
355#endif /* CONFIG_M68KFPU_EMU_ONLY */
356 /* Return previous task in %d1 */
357 movel %curptr,%d1
358
359 /* switch to new task (a1 contains new task) */
360 movel %a1,%curptr
361
362 /* restore floating point context */
363#ifndef CONFIG_M68KFPU_EMU_ONLY
364#ifdef CONFIG_M68KFPU_EMU
365 tstl m68k_fputype
366 jeq 4f
367#endif
368#if defined(CONFIG_M68060)
369#if !defined(CPU_M68060_ONLY)
370 btst #3,m68k_cputype+3
371 beqs 1f
372#endif
373 /* The 060 FPU keeps status in bits 15-8 of the first longword */
374 tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2)
375 jeq 3f
376#if !defined(CPU_M68060_ONLY)
377 jra 2f
378#endif
379#endif /* CONFIG_M68060 */
380#if !defined(CPU_M68060_ONLY)
3811: tstb %a1@(TASK_THREAD+THREAD_FPSTATE)
382 jeq 3f
383#endif
3842: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
385 fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
3863: frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
3874:
388#endif /* CONFIG_M68KFPU_EMU_ONLY */
389
390 /* restore the kernel stack pointer */
391 movel %a1@(TASK_THREAD+THREAD_KSP),%sp
392
393 /* restore non-scratch registers */
394 RESTORE_SWITCH_STACK
395
396 /* restore user stack pointer */
397 movel %a1@(TASK_THREAD+THREAD_USP),%a0
398 movel %a0,%usp
399
400 /* restore fs (sfc,%dfc) */
401 movew %a1@(TASK_THREAD+THREAD_FS),%a0
402 movec %a0,%sfc
403 movec %a0,%dfc
404
405 /* restore status register */
406 movew %a1@(TASK_THREAD+THREAD_SR),%sr
407
408 rts
409
diff --git a/arch/m68k/kernel/entry_no.S b/arch/m68k/kernel/entry_no.S
new file mode 100644
index 000000000000..5f0f6b598b5a
--- /dev/null
+++ b/arch/m68k/kernel/entry_no.S
@@ -0,0 +1,133 @@
1/*
2 * linux/arch/m68knommu/kernel/entry.S
3 *
4 * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
5 * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
6 * Kenneth Albanowski <kjahds@kjahds.com>,
7 * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
8 *
9 * Based on:
10 *
11 * linux/arch/m68k/kernel/entry.S
12 *
13 * Copyright (C) 1991, 1992 Linus Torvalds
14 *
15 * This file is subject to the terms and conditions of the GNU General Public
16 * License. See the file README.legal in the main directory of this archive
17 * for more details.
18 *
19 * Linux/m68k support by Hamish Macdonald
20 *
21 * 68060 fixes by Jesper Skov
22 * ColdFire support by Greg Ungerer (gerg@snapgear.com)
23 * 5307 fixes by David W. Miller
24 * linux 2.4 support David McCullough <davidm@snapgear.com>
25 */
26
27#include <linux/linkage.h>
28#include <asm/errno.h>
29#include <asm/setup.h>
30#include <asm/segment.h>
31#include <asm/asm-offsets.h>
32#include <asm/entry.h>
33#include <asm/unistd.h>
34
35.text
36
37.globl buserr
38.globl trap
39.globl ret_from_exception
40.globl ret_from_signal
41.globl sys_fork
42.globl sys_clone
43.globl sys_vfork
44
45ENTRY(buserr)
46 SAVE_ALL
47 moveq #-1,%d0
48 movel %d0,%sp@(PT_OFF_ORIG_D0)
49 movel %sp,%sp@- /* stack frame pointer argument */
50 jsr buserr_c
51 addql #4,%sp
52 jra ret_from_exception
53
54ENTRY(trap)
55 SAVE_ALL
56 moveq #-1,%d0
57 movel %d0,%sp@(PT_OFF_ORIG_D0)
58 movel %sp,%sp@- /* stack frame pointer argument */
59 jsr trap_c
60 addql #4,%sp
61 jra ret_from_exception
62
63#ifdef TRAP_DBG_INTERRUPT
64
65.globl dbginterrupt
66ENTRY(dbginterrupt)
67 SAVE_ALL
68 moveq #-1,%d0
69 movel %d0,%sp@(PT_OFF_ORIG_D0)
70 movel %sp,%sp@- /* stack frame pointer argument */
71 jsr dbginterrupt_c
72 addql #4,%sp
73 jra ret_from_exception
74#endif
75
76ENTRY(reschedule)
77 /* save top of frame */
78 pea %sp@
79 jbsr set_esp0
80 addql #4,%sp
81 pea ret_from_exception
82 jmp schedule
83
84ENTRY(ret_from_fork)
85 movel %d1,%sp@-
86 jsr schedule_tail
87 addql #4,%sp
88 jra ret_from_exception
89
90ENTRY(sys_fork)
91 SAVE_SWITCH_STACK
92 pea %sp@(SWITCH_STACK_SIZE)
93 jbsr m68k_fork
94 addql #4,%sp
95 RESTORE_SWITCH_STACK
96 rts
97
98ENTRY(sys_vfork)
99 SAVE_SWITCH_STACK
100 pea %sp@(SWITCH_STACK_SIZE)
101 jbsr m68k_vfork
102 addql #4,%sp
103 RESTORE_SWITCH_STACK
104 rts
105
106ENTRY(sys_clone)
107 SAVE_SWITCH_STACK
108 pea %sp@(SWITCH_STACK_SIZE)
109 jbsr m68k_clone
110 addql #4,%sp
111 RESTORE_SWITCH_STACK
112 rts
113
114ENTRY(sys_sigreturn)
115 SAVE_SWITCH_STACK
116 jbsr do_sigreturn
117 RESTORE_SWITCH_STACK
118 rts
119
120ENTRY(sys_rt_sigreturn)
121 SAVE_SWITCH_STACK
122 jbsr do_rt_sigreturn
123 RESTORE_SWITCH_STACK
124 rts
125
126ENTRY(ret_from_user_signal)
127 moveq #__NR_sigreturn,%d0
128 trap #0
129
130ENTRY(ret_from_user_rt_signal)
131 movel #__NR_rt_sigreturn,%d0
132 trap #0
133
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index ef54128baa0b..27622b3273c1 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -134,7 +134,7 @@
134 * Thanks to a small helping routine enabling the mmu got quite simple 134 * Thanks to a small helping routine enabling the mmu got quite simple
135 * and there is only one way left. mmu_engage makes a complete a new mapping 135 * and there is only one way left. mmu_engage makes a complete a new mapping
136 * that only includes the absolute necessary to be able to jump to the final 136 * that only includes the absolute necessary to be able to jump to the final
137 * postion and to restore the original mapping. 137 * position and to restore the original mapping.
138 * As this code doesn't need a transparent translation register anymore this 138 * As this code doesn't need a transparent translation register anymore this
139 * means all registers are free to be used by machines that needs them for 139 * means all registers are free to be used by machines that needs them for
140 * other purposes. 140 * other purposes.
@@ -969,7 +969,7 @@ L(mmu_init_amiga):
969 is_not_040_or_060(1f) 969 is_not_040_or_060(1f)
970 970
971 /* 971 /*
972 * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000 972 * 040: Map the 16Meg range physical 0x0 up to logical 0x8000.0000
973 */ 973 */
974 mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S 974 mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S
975 /* 975 /*
@@ -982,7 +982,7 @@ L(mmu_init_amiga):
982 982
9831: 9831:
984 /* 984 /*
985 * 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000 985 * 030: Map the 32Meg range physical 0x0 up to logical 0x8000.0000
986 */ 986 */
987 mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 987 mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030
988 mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030 988 mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030
@@ -1074,7 +1074,7 @@ L(notq40):
1074 is_040(1f) 1074 is_040(1f)
1075 1075
1076 /* 1076 /*
1077 * 030: Map the 32Meg range physical 0x0 upto logical 0xf000.0000 1077 * 030: Map the 32Meg range physical 0x0 up to logical 0xf000.0000
1078 */ 1078 */
1079 mmu_map #0xf0000000,#0,#0x02000000,#_PAGE_NOCACHE030 1079 mmu_map #0xf0000000,#0,#0x02000000,#_PAGE_NOCACHE030
1080 1080
@@ -1082,7 +1082,7 @@ L(notq40):
1082 1082
10831: 10831:
1084 /* 1084 /*
1085 * 040: Map the 16Meg range physical 0x0 upto logical 0xf000.0000 1085 * 040: Map the 16Meg range physical 0x0 up to logical 0xf000.0000
1086 */ 1086 */
1087 mmu_map #0xf0000000,#0,#0x01000000,#_PAGE_NOCACHE_S 1087 mmu_map #0xf0000000,#0,#0x01000000,#_PAGE_NOCACHE_S
1088 1088
@@ -3078,7 +3078,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1
3078 /* 3078 /*
3079 * If the loader gave us a board type then we can use that to 3079 * If the loader gave us a board type then we can use that to
3080 * select an appropriate output routine; otherwise we just use 3080 * select an appropriate output routine; otherwise we just use
3081 * the Bug code. If we haev to use the Bug that means the Bug 3081 * the Bug code. If we have to use the Bug that means the Bug
3082 * workspace has to be valid, which means the Bug has to use 3082 * workspace has to be valid, which means the Bug has to use
3083 * the SRAM, which is non-standard. 3083 * the SRAM, which is non-standard.
3084 */ 3084 */
diff --git a/arch/m68k/kernel/init_task.c b/arch/m68k/kernel/init_task.c
new file mode 100644
index 000000000000..cbf9dc3cc51d
--- /dev/null
+++ b/arch/m68k/kernel/init_task.c
@@ -0,0 +1,36 @@
1/*
2 * linux/arch/m68knommu/kernel/init_task.c
3 */
4#include <linux/mm.h>
5#include <linux/module.h>
6#include <linux/sched.h>
7#include <linux/init.h>
8#include <linux/init_task.h>
9#include <linux/fs.h>
10#include <linux/mqueue.h>
11
12#include <asm/uaccess.h>
13#include <asm/pgtable.h>
14
15static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
16static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
17/*
18 * Initial task structure.
19 *
20 * All other task structs will be allocated on slabs in fork.c
21 */
22__asm__(".align 4");
23struct task_struct init_task = INIT_TASK(init_task);
24
25EXPORT_SYMBOL(init_task);
26
27/*
28 * Initial thread structure.
29 *
30 * We need to make sure that this is 8192-byte aligned due to the
31 * way process stacks are handled. This is done by having a special
32 * "init_task" linker map entry..
33 */
34union thread_union init_thread_union __init_task_data =
35 { INIT_THREAD_INFO(init_task) };
36
diff --git a/arch/m68k/kernel/irq.c b/arch/m68k/kernel/irq.c
new file mode 100644
index 000000000000..544b8717d499
--- /dev/null
+++ b/arch/m68k/kernel/irq.c
@@ -0,0 +1,30 @@
1/*
2 * irq.c
3 *
4 * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/types.h>
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/kernel_stat.h>
15#include <linux/interrupt.h>
16#include <linux/irq.h>
17#include <linux/seq_file.h>
18#include <asm/system.h>
19#include <asm/traps.h>
20
21asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
22{
23 struct pt_regs *oldregs = set_irq_regs(regs);
24
25 irq_enter();
26 generic_handle_irq(irq);
27 irq_exit();
28
29 set_irq_regs(oldregs);
30}
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index d900e77e5363..1b7a14d1a000 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -14,3 +14,19 @@ EXPORT_SYMBOL(__ashrdi3);
14EXPORT_SYMBOL(__lshrdi3); 14EXPORT_SYMBOL(__lshrdi3);
15EXPORT_SYMBOL(__muldi3); 15EXPORT_SYMBOL(__muldi3);
16 16
17#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
18/*
19 * Simpler 68k and ColdFire parts also need a few other gcc functions.
20 */
21extern long long __divsi3(long long, long long);
22extern long long __modsi3(long long, long long);
23extern long long __mulsi3(long long, long long);
24extern long long __udivsi3(long long, long long);
25extern long long __umodsi3(long long, long long);
26
27EXPORT_SYMBOL(__divsi3);
28EXPORT_SYMBOL(__modsi3);
29EXPORT_SYMBOL(__mulsi3);
30EXPORT_SYMBOL(__udivsi3);
31EXPORT_SYMBOL(__umodsi3);
32#endif
diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c
index cd6bcb1c957e..7ea203ce6b1a 100644
--- a/arch/m68k/kernel/module.c
+++ b/arch/m68k/kernel/module.c
@@ -1,155 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * This file is subject to the terms and conditions of the GNU General Public 2#include "module_mm.c"
3 * License. See the file COPYING in the main directory of this archive
4 * for more details.
5 */
6
7#include <linux/moduleloader.h>
8#include <linux/elf.h>
9#include <linux/vmalloc.h>
10#include <linux/fs.h>
11#include <linux/string.h>
12#include <linux/kernel.h>
13
14#if 0
15#define DEBUGP printk
16#else 3#else
17#define DEBUGP(fmt...) 4#include "module_no.c"
18#endif 5#endif
19
20#ifdef CONFIG_MODULES
21
22void *module_alloc(unsigned long size)
23{
24 if (size == 0)
25 return NULL;
26 return vmalloc(size);
27}
28
29
30/* Free memory returned from module_alloc */
31void module_free(struct module *mod, void *module_region)
32{
33 vfree(module_region);
34}
35
36/* We don't need anything special. */
37int module_frob_arch_sections(Elf_Ehdr *hdr,
38 Elf_Shdr *sechdrs,
39 char *secstrings,
40 struct module *mod)
41{
42 return 0;
43}
44
45int apply_relocate(Elf32_Shdr *sechdrs,
46 const char *strtab,
47 unsigned int symindex,
48 unsigned int relsec,
49 struct module *me)
50{
51 unsigned int i;
52 Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
53 Elf32_Sym *sym;
54 uint32_t *location;
55
56 DEBUGP("Applying relocate section %u to %u\n", relsec,
57 sechdrs[relsec].sh_info);
58 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
59 /* This is where to make the change */
60 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
61 + rel[i].r_offset;
62 /* This is the symbol it is referring to. Note that all
63 undefined symbols have been resolved. */
64 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
65 + ELF32_R_SYM(rel[i].r_info);
66
67 switch (ELF32_R_TYPE(rel[i].r_info)) {
68 case R_68K_32:
69 /* We add the value into the location given */
70 *location += sym->st_value;
71 break;
72 case R_68K_PC32:
73 /* Add the value, subtract its postition */
74 *location += sym->st_value - (uint32_t)location;
75 break;
76 default:
77 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
78 me->name, ELF32_R_TYPE(rel[i].r_info));
79 return -ENOEXEC;
80 }
81 }
82 return 0;
83}
84
85int apply_relocate_add(Elf32_Shdr *sechdrs,
86 const char *strtab,
87 unsigned int symindex,
88 unsigned int relsec,
89 struct module *me)
90{
91 unsigned int i;
92 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
93 Elf32_Sym *sym;
94 uint32_t *location;
95
96 DEBUGP("Applying relocate_add section %u to %u\n", relsec,
97 sechdrs[relsec].sh_info);
98 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
99 /* This is where to make the change */
100 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
101 + rel[i].r_offset;
102 /* This is the symbol it is referring to. Note that all
103 undefined symbols have been resolved. */
104 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
105 + ELF32_R_SYM(rel[i].r_info);
106
107 switch (ELF32_R_TYPE(rel[i].r_info)) {
108 case R_68K_32:
109 /* We add the value into the location given */
110 *location = rel[i].r_addend + sym->st_value;
111 break;
112 case R_68K_PC32:
113 /* Add the value, subtract its postition */
114 *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
115 break;
116 default:
117 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
118 me->name, ELF32_R_TYPE(rel[i].r_info));
119 return -ENOEXEC;
120 }
121 }
122 return 0;
123}
124
125int module_finalize(const Elf_Ehdr *hdr,
126 const Elf_Shdr *sechdrs,
127 struct module *mod)
128{
129 module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
130
131 return 0;
132}
133
134void module_arch_cleanup(struct module *mod)
135{
136}
137
138#endif /* CONFIG_MODULES */
139
140void module_fixup(struct module *mod, struct m68k_fixup_info *start,
141 struct m68k_fixup_info *end)
142{
143 struct m68k_fixup_info *fixup;
144
145 for (fixup = start; fixup < end; fixup++) {
146 switch (fixup->type) {
147 case m68k_fixup_memoffset:
148 *(u32 *)fixup->addr = m68k_memoffset;
149 break;
150 case m68k_fixup_vnode_shift:
151 *(u16 *)fixup->addr += m68k_virt_to_node_shift;
152 break;
153 }
154 }
155}
diff --git a/arch/m68k/kernel/module_mm.c b/arch/m68k/kernel/module_mm.c
new file mode 100644
index 000000000000..cd6bcb1c957e
--- /dev/null
+++ b/arch/m68k/kernel/module_mm.c
@@ -0,0 +1,155 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file COPYING in the main directory of this archive
4 * for more details.
5 */
6
7#include <linux/moduleloader.h>
8#include <linux/elf.h>
9#include <linux/vmalloc.h>
10#include <linux/fs.h>
11#include <linux/string.h>
12#include <linux/kernel.h>
13
14#if 0
15#define DEBUGP printk
16#else
17#define DEBUGP(fmt...)
18#endif
19
20#ifdef CONFIG_MODULES
21
22void *module_alloc(unsigned long size)
23{
24 if (size == 0)
25 return NULL;
26 return vmalloc(size);
27}
28
29
30/* Free memory returned from module_alloc */
31void module_free(struct module *mod, void *module_region)
32{
33 vfree(module_region);
34}
35
36/* We don't need anything special. */
37int module_frob_arch_sections(Elf_Ehdr *hdr,
38 Elf_Shdr *sechdrs,
39 char *secstrings,
40 struct module *mod)
41{
42 return 0;
43}
44
45int apply_relocate(Elf32_Shdr *sechdrs,
46 const char *strtab,
47 unsigned int symindex,
48 unsigned int relsec,
49 struct module *me)
50{
51 unsigned int i;
52 Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
53 Elf32_Sym *sym;
54 uint32_t *location;
55
56 DEBUGP("Applying relocate section %u to %u\n", relsec,
57 sechdrs[relsec].sh_info);
58 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
59 /* This is where to make the change */
60 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
61 + rel[i].r_offset;
62 /* This is the symbol it is referring to. Note that all
63 undefined symbols have been resolved. */
64 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
65 + ELF32_R_SYM(rel[i].r_info);
66
67 switch (ELF32_R_TYPE(rel[i].r_info)) {
68 case R_68K_32:
69 /* We add the value into the location given */
70 *location += sym->st_value;
71 break;
72 case R_68K_PC32:
73 /* Add the value, subtract its postition */
74 *location += sym->st_value - (uint32_t)location;
75 break;
76 default:
77 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
78 me->name, ELF32_R_TYPE(rel[i].r_info));
79 return -ENOEXEC;
80 }
81 }
82 return 0;
83}
84
85int apply_relocate_add(Elf32_Shdr *sechdrs,
86 const char *strtab,
87 unsigned int symindex,
88 unsigned int relsec,
89 struct module *me)
90{
91 unsigned int i;
92 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
93 Elf32_Sym *sym;
94 uint32_t *location;
95
96 DEBUGP("Applying relocate_add section %u to %u\n", relsec,
97 sechdrs[relsec].sh_info);
98 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
99 /* This is where to make the change */
100 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
101 + rel[i].r_offset;
102 /* This is the symbol it is referring to. Note that all
103 undefined symbols have been resolved. */
104 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
105 + ELF32_R_SYM(rel[i].r_info);
106
107 switch (ELF32_R_TYPE(rel[i].r_info)) {
108 case R_68K_32:
109 /* We add the value into the location given */
110 *location = rel[i].r_addend + sym->st_value;
111 break;
112 case R_68K_PC32:
113 /* Add the value, subtract its postition */
114 *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
115 break;
116 default:
117 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
118 me->name, ELF32_R_TYPE(rel[i].r_info));
119 return -ENOEXEC;
120 }
121 }
122 return 0;
123}
124
125int module_finalize(const Elf_Ehdr *hdr,
126 const Elf_Shdr *sechdrs,
127 struct module *mod)
128{
129 module_fixup(mod, mod->arch.fixup_start, mod->arch.fixup_end);
130
131 return 0;
132}
133
134void module_arch_cleanup(struct module *mod)
135{
136}
137
138#endif /* CONFIG_MODULES */
139
140void module_fixup(struct module *mod, struct m68k_fixup_info *start,
141 struct m68k_fixup_info *end)
142{
143 struct m68k_fixup_info *fixup;
144
145 for (fixup = start; fixup < end; fixup++) {
146 switch (fixup->type) {
147 case m68k_fixup_memoffset:
148 *(u32 *)fixup->addr = m68k_memoffset;
149 break;
150 case m68k_fixup_vnode_shift:
151 *(u16 *)fixup->addr += m68k_virt_to_node_shift;
152 break;
153 }
154 }
155}
diff --git a/arch/m68k/kernel/module_no.c b/arch/m68k/kernel/module_no.c
new file mode 100644
index 000000000000..d11ffae7956a
--- /dev/null
+++ b/arch/m68k/kernel/module_no.c
@@ -0,0 +1,126 @@
1#include <linux/moduleloader.h>
2#include <linux/elf.h>
3#include <linux/vmalloc.h>
4#include <linux/fs.h>
5#include <linux/string.h>
6#include <linux/kernel.h>
7
8#if 0
9#define DEBUGP printk
10#else
11#define DEBUGP(fmt...)
12#endif
13
14void *module_alloc(unsigned long size)
15{
16 if (size == 0)
17 return NULL;
18 return vmalloc(size);
19}
20
21
22/* Free memory returned from module_alloc */
23void module_free(struct module *mod, void *module_region)
24{
25 vfree(module_region);
26}
27
28/* We don't need anything special. */
29int module_frob_arch_sections(Elf_Ehdr *hdr,
30 Elf_Shdr *sechdrs,
31 char *secstrings,
32 struct module *mod)
33{
34 return 0;
35}
36
37int apply_relocate(Elf32_Shdr *sechdrs,
38 const char *strtab,
39 unsigned int symindex,
40 unsigned int relsec,
41 struct module *me)
42{
43 unsigned int i;
44 Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr;
45 Elf32_Sym *sym;
46 uint32_t *location;
47
48 DEBUGP("Applying relocate section %u to %u\n", relsec,
49 sechdrs[relsec].sh_info);
50 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
51 /* This is where to make the change */
52 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
53 + rel[i].r_offset;
54 /* This is the symbol it is referring to. Note that all
55 undefined symbols have been resolved. */
56 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
57 + ELF32_R_SYM(rel[i].r_info);
58
59 switch (ELF32_R_TYPE(rel[i].r_info)) {
60 case R_68K_32:
61 /* We add the value into the location given */
62 *location += sym->st_value;
63 break;
64 case R_68K_PC32:
65 /* Add the value, subtract its postition */
66 *location += sym->st_value - (uint32_t)location;
67 break;
68 default:
69 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
70 me->name, ELF32_R_TYPE(rel[i].r_info));
71 return -ENOEXEC;
72 }
73 }
74 return 0;
75}
76
77int apply_relocate_add(Elf32_Shdr *sechdrs,
78 const char *strtab,
79 unsigned int symindex,
80 unsigned int relsec,
81 struct module *me)
82{
83 unsigned int i;
84 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
85 Elf32_Sym *sym;
86 uint32_t *location;
87
88 DEBUGP("Applying relocate_add section %u to %u\n", relsec,
89 sechdrs[relsec].sh_info);
90 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
91 /* This is where to make the change */
92 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
93 + rel[i].r_offset;
94 /* This is the symbol it is referring to. Note that all
95 undefined symbols have been resolved. */
96 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
97 + ELF32_R_SYM(rel[i].r_info);
98
99 switch (ELF32_R_TYPE(rel[i].r_info)) {
100 case R_68K_32:
101 /* We add the value into the location given */
102 *location = rel[i].r_addend + sym->st_value;
103 break;
104 case R_68K_PC32:
105 /* Add the value, subtract its postition */
106 *location = rel[i].r_addend + sym->st_value - (uint32_t)location;
107 break;
108 default:
109 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
110 me->name, ELF32_R_TYPE(rel[i].r_info));
111 return -ENOEXEC;
112 }
113 }
114 return 0;
115}
116
117int module_finalize(const Elf_Ehdr *hdr,
118 const Elf_Shdr *sechdrs,
119 struct module *me)
120{
121 return 0;
122}
123
124void module_arch_cleanup(struct module *mod)
125{
126}
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 18732ab23292..6cf4bd6e34f8 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -1,355 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * linux/arch/m68k/kernel/process.c 2#include "process_mm.c"
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 *
6 * 68060 fixes by Jesper Skov
7 */
8
9/*
10 * This file handles the architecture-dependent parts of process handling..
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/slab.h>
19#include <linux/fs.h>
20#include <linux/smp.h>
21#include <linux/smp_lock.h>
22#include <linux/stddef.h>
23#include <linux/unistd.h>
24#include <linux/ptrace.h>
25#include <linux/user.h>
26#include <linux/reboot.h>
27#include <linux/init_task.h>
28#include <linux/mqueue.h>
29
30#include <asm/uaccess.h>
31#include <asm/system.h>
32#include <asm/traps.h>
33#include <asm/machdep.h>
34#include <asm/setup.h>
35#include <asm/pgtable.h>
36
37/*
38 * Initial task/thread structure. Make this a per-architecture thing,
39 * because different architectures tend to have different
40 * alignment requirements and potentially different initial
41 * setup.
42 */
43static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
44static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
45union thread_union init_thread_union __init_task_data
46 __attribute__((aligned(THREAD_SIZE))) =
47 { INIT_THREAD_INFO(init_task) };
48
49/* initial task structure */
50struct task_struct init_task = INIT_TASK(init_task);
51
52EXPORT_SYMBOL(init_task);
53
54asmlinkage void ret_from_fork(void);
55
56
57/*
58 * Return saved PC from a blocked thread
59 */
60unsigned long thread_saved_pc(struct task_struct *tsk)
61{
62 struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
63 /* Check whether the thread is blocked in resume() */
64 if (in_sched_functions(sw->retpc))
65 return ((unsigned long *)sw->a6)[1];
66 else
67 return sw->retpc;
68}
69
70/*
71 * The idle loop on an m68k..
72 */
73static void default_idle(void)
74{
75 if (!need_resched())
76#if defined(MACH_ATARI_ONLY)
77 /* block out HSYNC on the atari (falcon) */
78 __asm__("stop #0x2200" : : : "cc");
79#else 3#else
80 __asm__("stop #0x2000" : : : "cc"); 4#include "process_no.c"
81#endif 5#endif
82}
83
84void (*idle)(void) = default_idle;
85
86/*
87 * The idle thread. There's no useful work to be
88 * done, so just try to conserve power and have a
89 * low exit latency (ie sit in a loop waiting for
90 * somebody to say that they'd like to reschedule)
91 */
92void cpu_idle(void)
93{
94 /* endless idle loop with no priority at all */
95 while (1) {
96 while (!need_resched())
97 idle();
98 preempt_enable_no_resched();
99 schedule();
100 preempt_disable();
101 }
102}
103
104void machine_restart(char * __unused)
105{
106 if (mach_reset)
107 mach_reset();
108 for (;;);
109}
110
111void machine_halt(void)
112{
113 if (mach_halt)
114 mach_halt();
115 for (;;);
116}
117
118void machine_power_off(void)
119{
120 if (mach_power_off)
121 mach_power_off();
122 for (;;);
123}
124
125void (*pm_power_off)(void) = machine_power_off;
126EXPORT_SYMBOL(pm_power_off);
127
128void show_regs(struct pt_regs * regs)
129{
130 printk("\n");
131 printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
132 regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
133 printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
134 regs->orig_d0, regs->d0, regs->a2, regs->a1);
135 printk("A0: %08lx D5: %08lx D4: %08lx\n",
136 regs->a0, regs->d5, regs->d4);
137 printk("D3: %08lx D2: %08lx D1: %08lx\n",
138 regs->d3, regs->d2, regs->d1);
139 if (!(regs->sr & PS_S))
140 printk("USP: %08lx\n", rdusp());
141}
142
143/*
144 * Create a kernel thread
145 */
146int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
147{
148 int pid;
149 mm_segment_t fs;
150
151 fs = get_fs();
152 set_fs (KERNEL_DS);
153
154 {
155 register long retval __asm__ ("d0");
156 register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
157
158 retval = __NR_clone;
159 __asm__ __volatile__
160 ("clrl %%d2\n\t"
161 "trap #0\n\t" /* Linux/m68k system call */
162 "tstl %0\n\t" /* child or parent */
163 "jne 1f\n\t" /* parent - jump */
164 "lea %%sp@(%c7),%6\n\t" /* reload current */
165 "movel %6@,%6\n\t"
166 "movel %3,%%sp@-\n\t" /* push argument */
167 "jsr %4@\n\t" /* call fn */
168 "movel %0,%%d1\n\t" /* pass exit value */
169 "movel %2,%%d0\n\t" /* exit */
170 "trap #0\n"
171 "1:"
172 : "+d" (retval)
173 : "i" (__NR_clone), "i" (__NR_exit),
174 "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
175 "i" (-THREAD_SIZE)
176 : "d2");
177
178 pid = retval;
179 }
180
181 set_fs (fs);
182 return pid;
183}
184EXPORT_SYMBOL(kernel_thread);
185
186void flush_thread(void)
187{
188 unsigned long zero = 0;
189 set_fs(USER_DS);
190 current->thread.fs = __USER_DS;
191 if (!FPU_IS_EMU)
192 asm volatile (".chip 68k/68881\n\t"
193 "frestore %0@\n\t"
194 ".chip 68k" : : "a" (&zero));
195}
196
197/*
198 * "m68k_fork()".. By the time we get here, the
199 * non-volatile registers have also been saved on the
200 * stack. We do some ugly pointer stuff here.. (see
201 * also copy_thread)
202 */
203
204asmlinkage int m68k_fork(struct pt_regs *regs)
205{
206 return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
207}
208
209asmlinkage int m68k_vfork(struct pt_regs *regs)
210{
211 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
212 NULL, NULL);
213}
214
215asmlinkage int m68k_clone(struct pt_regs *regs)
216{
217 unsigned long clone_flags;
218 unsigned long newsp;
219 int __user *parent_tidptr, *child_tidptr;
220
221 /* syscall2 puts clone_flags in d1 and usp in d2 */
222 clone_flags = regs->d1;
223 newsp = regs->d2;
224 parent_tidptr = (int __user *)regs->d3;
225 child_tidptr = (int __user *)regs->d4;
226 if (!newsp)
227 newsp = rdusp();
228 return do_fork(clone_flags, newsp, regs, 0,
229 parent_tidptr, child_tidptr);
230}
231
232int copy_thread(unsigned long clone_flags, unsigned long usp,
233 unsigned long unused,
234 struct task_struct * p, struct pt_regs * regs)
235{
236 struct pt_regs * childregs;
237 struct switch_stack * childstack, *stack;
238 unsigned long *retp;
239
240 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
241
242 *childregs = *regs;
243 childregs->d0 = 0;
244
245 retp = ((unsigned long *) regs);
246 stack = ((struct switch_stack *) retp) - 1;
247
248 childstack = ((struct switch_stack *) childregs) - 1;
249 *childstack = *stack;
250 childstack->retpc = (unsigned long)ret_from_fork;
251
252 p->thread.usp = usp;
253 p->thread.ksp = (unsigned long)childstack;
254
255 if (clone_flags & CLONE_SETTLS)
256 task_thread_info(p)->tp_value = regs->d5;
257
258 /*
259 * Must save the current SFC/DFC value, NOT the value when
260 * the parent was last descheduled - RGH 10-08-96
261 */
262 p->thread.fs = get_fs().seg;
263
264 if (!FPU_IS_EMU) {
265 /* Copy the current fpu state */
266 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
267
268 if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
269 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
270 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
271 : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
272 : "memory");
273 /* Restore the state in case the fpu was busy */
274 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
275 }
276
277 return 0;
278}
279
280/* Fill in the fpu structure for a core dump. */
281
282int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
283{
284 char fpustate[216];
285
286 if (FPU_IS_EMU) {
287 int i;
288
289 memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
290 memcpy(fpu->fpregs, current->thread.fp, 96);
291 /* Convert internal fpu reg representation
292 * into long double format
293 */
294 for (i = 0; i < 24; i += 3)
295 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
296 ((fpu->fpregs[i] & 0x0000ffff) << 16);
297 return 1;
298 }
299
300 /* First dump the fpu context to avoid protocol violation. */
301 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
302 if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
303 return 0;
304
305 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
306 :: "m" (fpu->fpcntl[0])
307 : "memory");
308 asm volatile ("fmovemx %/fp0-%/fp7,%0"
309 :: "m" (fpu->fpregs[0])
310 : "memory");
311 return 1;
312}
313EXPORT_SYMBOL(dump_fpu);
314
315/*
316 * sys_execve() executes a new program.
317 */
318asmlinkage int sys_execve(const char __user *name,
319 const char __user *const __user *argv,
320 const char __user *const __user *envp)
321{
322 int error;
323 char * filename;
324 struct pt_regs *regs = (struct pt_regs *) &name;
325
326 filename = getname(name);
327 error = PTR_ERR(filename);
328 if (IS_ERR(filename))
329 return error;
330 error = do_execve(filename, argv, envp, regs);
331 putname(filename);
332 return error;
333}
334
335unsigned long get_wchan(struct task_struct *p)
336{
337 unsigned long fp, pc;
338 unsigned long stack_page;
339 int count = 0;
340 if (!p || p == current || p->state == TASK_RUNNING)
341 return 0;
342
343 stack_page = (unsigned long)task_stack_page(p);
344 fp = ((struct switch_stack *)p->thread.ksp)->a6;
345 do {
346 if (fp < stack_page+sizeof(struct thread_info) ||
347 fp >= 8184+stack_page)
348 return 0;
349 pc = ((unsigned long *)fp)[1];
350 if (!in_sched_functions(pc))
351 return pc;
352 fp = *(unsigned long *) fp;
353 } while (count++ < 16);
354 return 0;
355}
diff --git a/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c
new file mode 100644
index 000000000000..c2a1fc23dd75
--- /dev/null
+++ b/arch/m68k/kernel/process_mm.c
@@ -0,0 +1,354 @@
1/*
2 * linux/arch/m68k/kernel/process.c
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 *
6 * 68060 fixes by Jesper Skov
7 */
8
9/*
10 * This file handles the architecture-dependent parts of process handling..
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/mm.h>
18#include <linux/slab.h>
19#include <linux/fs.h>
20#include <linux/smp.h>
21#include <linux/stddef.h>
22#include <linux/unistd.h>
23#include <linux/ptrace.h>
24#include <linux/user.h>
25#include <linux/reboot.h>
26#include <linux/init_task.h>
27#include <linux/mqueue.h>
28
29#include <asm/uaccess.h>
30#include <asm/system.h>
31#include <asm/traps.h>
32#include <asm/machdep.h>
33#include <asm/setup.h>
34#include <asm/pgtable.h>
35
36/*
37 * Initial task/thread structure. Make this a per-architecture thing,
38 * because different architectures tend to have different
39 * alignment requirements and potentially different initial
40 * setup.
41 */
42static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
43static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
44union thread_union init_thread_union __init_task_data
45 __attribute__((aligned(THREAD_SIZE))) =
46 { INIT_THREAD_INFO(init_task) };
47
48/* initial task structure */
49struct task_struct init_task = INIT_TASK(init_task);
50
51EXPORT_SYMBOL(init_task);
52
53asmlinkage void ret_from_fork(void);
54
55
56/*
57 * Return saved PC from a blocked thread
58 */
59unsigned long thread_saved_pc(struct task_struct *tsk)
60{
61 struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
62 /* Check whether the thread is blocked in resume() */
63 if (in_sched_functions(sw->retpc))
64 return ((unsigned long *)sw->a6)[1];
65 else
66 return sw->retpc;
67}
68
69/*
70 * The idle loop on an m68k..
71 */
72static void default_idle(void)
73{
74 if (!need_resched())
75#if defined(MACH_ATARI_ONLY)
76 /* block out HSYNC on the atari (falcon) */
77 __asm__("stop #0x2200" : : : "cc");
78#else
79 __asm__("stop #0x2000" : : : "cc");
80#endif
81}
82
83void (*idle)(void) = default_idle;
84
85/*
86 * The idle thread. There's no useful work to be
87 * done, so just try to conserve power and have a
88 * low exit latency (ie sit in a loop waiting for
89 * somebody to say that they'd like to reschedule)
90 */
91void cpu_idle(void)
92{
93 /* endless idle loop with no priority at all */
94 while (1) {
95 while (!need_resched())
96 idle();
97 preempt_enable_no_resched();
98 schedule();
99 preempt_disable();
100 }
101}
102
103void machine_restart(char * __unused)
104{
105 if (mach_reset)
106 mach_reset();
107 for (;;);
108}
109
110void machine_halt(void)
111{
112 if (mach_halt)
113 mach_halt();
114 for (;;);
115}
116
117void machine_power_off(void)
118{
119 if (mach_power_off)
120 mach_power_off();
121 for (;;);
122}
123
124void (*pm_power_off)(void) = machine_power_off;
125EXPORT_SYMBOL(pm_power_off);
126
127void show_regs(struct pt_regs * regs)
128{
129 printk("\n");
130 printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
131 regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
132 printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
133 regs->orig_d0, regs->d0, regs->a2, regs->a1);
134 printk("A0: %08lx D5: %08lx D4: %08lx\n",
135 regs->a0, regs->d5, regs->d4);
136 printk("D3: %08lx D2: %08lx D1: %08lx\n",
137 regs->d3, regs->d2, regs->d1);
138 if (!(regs->sr & PS_S))
139 printk("USP: %08lx\n", rdusp());
140}
141
142/*
143 * Create a kernel thread
144 */
145int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
146{
147 int pid;
148 mm_segment_t fs;
149
150 fs = get_fs();
151 set_fs (KERNEL_DS);
152
153 {
154 register long retval __asm__ ("d0");
155 register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED;
156
157 retval = __NR_clone;
158 __asm__ __volatile__
159 ("clrl %%d2\n\t"
160 "trap #0\n\t" /* Linux/m68k system call */
161 "tstl %0\n\t" /* child or parent */
162 "jne 1f\n\t" /* parent - jump */
163 "lea %%sp@(%c7),%6\n\t" /* reload current */
164 "movel %6@,%6\n\t"
165 "movel %3,%%sp@-\n\t" /* push argument */
166 "jsr %4@\n\t" /* call fn */
167 "movel %0,%%d1\n\t" /* pass exit value */
168 "movel %2,%%d0\n\t" /* exit */
169 "trap #0\n"
170 "1:"
171 : "+d" (retval)
172 : "i" (__NR_clone), "i" (__NR_exit),
173 "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
174 "i" (-THREAD_SIZE)
175 : "d2");
176
177 pid = retval;
178 }
179
180 set_fs (fs);
181 return pid;
182}
183EXPORT_SYMBOL(kernel_thread);
184
185void flush_thread(void)
186{
187 unsigned long zero = 0;
188 set_fs(USER_DS);
189 current->thread.fs = __USER_DS;
190 if (!FPU_IS_EMU)
191 asm volatile (".chip 68k/68881\n\t"
192 "frestore %0@\n\t"
193 ".chip 68k" : : "a" (&zero));
194}
195
196/*
197 * "m68k_fork()".. By the time we get here, the
198 * non-volatile registers have also been saved on the
199 * stack. We do some ugly pointer stuff here.. (see
200 * also copy_thread)
201 */
202
203asmlinkage int m68k_fork(struct pt_regs *regs)
204{
205 return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL);
206}
207
208asmlinkage int m68k_vfork(struct pt_regs *regs)
209{
210 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0,
211 NULL, NULL);
212}
213
214asmlinkage int m68k_clone(struct pt_regs *regs)
215{
216 unsigned long clone_flags;
217 unsigned long newsp;
218 int __user *parent_tidptr, *child_tidptr;
219
220 /* syscall2 puts clone_flags in d1 and usp in d2 */
221 clone_flags = regs->d1;
222 newsp = regs->d2;
223 parent_tidptr = (int __user *)regs->d3;
224 child_tidptr = (int __user *)regs->d4;
225 if (!newsp)
226 newsp = rdusp();
227 return do_fork(clone_flags, newsp, regs, 0,
228 parent_tidptr, child_tidptr);
229}
230
231int copy_thread(unsigned long clone_flags, unsigned long usp,
232 unsigned long unused,
233 struct task_struct * p, struct pt_regs * regs)
234{
235 struct pt_regs * childregs;
236 struct switch_stack * childstack, *stack;
237 unsigned long *retp;
238
239 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
240
241 *childregs = *regs;
242 childregs->d0 = 0;
243
244 retp = ((unsigned long *) regs);
245 stack = ((struct switch_stack *) retp) - 1;
246
247 childstack = ((struct switch_stack *) childregs) - 1;
248 *childstack = *stack;
249 childstack->retpc = (unsigned long)ret_from_fork;
250
251 p->thread.usp = usp;
252 p->thread.ksp = (unsigned long)childstack;
253
254 if (clone_flags & CLONE_SETTLS)
255 task_thread_info(p)->tp_value = regs->d5;
256
257 /*
258 * Must save the current SFC/DFC value, NOT the value when
259 * the parent was last descheduled - RGH 10-08-96
260 */
261 p->thread.fs = get_fs().seg;
262
263 if (!FPU_IS_EMU) {
264 /* Copy the current fpu state */
265 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
266
267 if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2])
268 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
269 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
270 : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
271 : "memory");
272 /* Restore the state in case the fpu was busy */
273 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
274 }
275
276 return 0;
277}
278
279/* Fill in the fpu structure for a core dump. */
280
281int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
282{
283 char fpustate[216];
284
285 if (FPU_IS_EMU) {
286 int i;
287
288 memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
289 memcpy(fpu->fpregs, current->thread.fp, 96);
290 /* Convert internal fpu reg representation
291 * into long double format
292 */
293 for (i = 0; i < 24; i += 3)
294 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
295 ((fpu->fpregs[i] & 0x0000ffff) << 16);
296 return 1;
297 }
298
299 /* First dump the fpu context to avoid protocol violation. */
300 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
301 if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2])
302 return 0;
303
304 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
305 :: "m" (fpu->fpcntl[0])
306 : "memory");
307 asm volatile ("fmovemx %/fp0-%/fp7,%0"
308 :: "m" (fpu->fpregs[0])
309 : "memory");
310 return 1;
311}
312EXPORT_SYMBOL(dump_fpu);
313
314/*
315 * sys_execve() executes a new program.
316 */
317asmlinkage int sys_execve(const char __user *name,
318 const char __user *const __user *argv,
319 const char __user *const __user *envp)
320{
321 int error;
322 char * filename;
323 struct pt_regs *regs = (struct pt_regs *) &name;
324
325 filename = getname(name);
326 error = PTR_ERR(filename);
327 if (IS_ERR(filename))
328 return error;
329 error = do_execve(filename, argv, envp, regs);
330 putname(filename);
331 return error;
332}
333
334unsigned long get_wchan(struct task_struct *p)
335{
336 unsigned long fp, pc;
337 unsigned long stack_page;
338 int count = 0;
339 if (!p || p == current || p->state == TASK_RUNNING)
340 return 0;
341
342 stack_page = (unsigned long)task_stack_page(p);
343 fp = ((struct switch_stack *)p->thread.ksp)->a6;
344 do {
345 if (fp < stack_page+sizeof(struct thread_info) ||
346 fp >= 8184+stack_page)
347 return 0;
348 pc = ((unsigned long *)fp)[1];
349 if (!in_sched_functions(pc))
350 return pc;
351 fp = *(unsigned long *) fp;
352 } while (count++ < 16);
353 return 0;
354}
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c
new file mode 100644
index 000000000000..9b86ad11c68e
--- /dev/null
+++ b/arch/m68k/kernel/process_no.c
@@ -0,0 +1,406 @@
1/*
2 * linux/arch/m68knommu/kernel/process.c
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 *
6 * 68060 fixes by Jesper Skov
7 *
8 * uClinux changes
9 * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com>
10 */
11
12/*
13 * This file handles the architecture-dependent parts of process handling..
14 */
15
16#include <linux/module.h>
17#include <linux/errno.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/smp.h>
22#include <linux/stddef.h>
23#include <linux/unistd.h>
24#include <linux/ptrace.h>
25#include <linux/user.h>
26#include <linux/interrupt.h>
27#include <linux/reboot.h>
28#include <linux/fs.h>
29#include <linux/slab.h>
30
31#include <asm/uaccess.h>
32#include <asm/system.h>
33#include <asm/traps.h>
34#include <asm/machdep.h>
35#include <asm/setup.h>
36#include <asm/pgtable.h>
37
38asmlinkage void ret_from_fork(void);
39
40/*
41 * The following aren't currently used.
42 */
43void (*pm_idle)(void);
44EXPORT_SYMBOL(pm_idle);
45
46void (*pm_power_off)(void);
47EXPORT_SYMBOL(pm_power_off);
48
49/*
50 * The idle loop on an m68knommu..
51 */
52static void default_idle(void)
53{
54 local_irq_disable();
55 while (!need_resched()) {
56 /* This stop will re-enable interrupts */
57 __asm__("stop #0x2000" : : : "cc");
58 local_irq_disable();
59 }
60 local_irq_enable();
61}
62
63void (*idle)(void) = default_idle;
64
65/*
66 * The idle thread. There's no useful work to be
67 * done, so just try to conserve power and have a
68 * low exit latency (ie sit in a loop waiting for
69 * somebody to say that they'd like to reschedule)
70 */
71void cpu_idle(void)
72{
73 /* endless idle loop with no priority at all */
74 while (1) {
75 idle();
76 preempt_enable_no_resched();
77 schedule();
78 preempt_disable();
79 }
80}
81
82void machine_restart(char * __unused)
83{
84 if (mach_reset)
85 mach_reset();
86 for (;;);
87}
88
89void machine_halt(void)
90{
91 if (mach_halt)
92 mach_halt();
93 for (;;);
94}
95
96void machine_power_off(void)
97{
98 if (mach_power_off)
99 mach_power_off();
100 for (;;);
101}
102
103void show_regs(struct pt_regs * regs)
104{
105 printk(KERN_NOTICE "\n");
106 printk(KERN_NOTICE "Format %02x Vector: %04x PC: %08lx Status: %04x %s\n",
107 regs->format, regs->vector, regs->pc, regs->sr, print_tainted());
108 printk(KERN_NOTICE "ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n",
109 regs->orig_d0, regs->d0, regs->a2, regs->a1);
110 printk(KERN_NOTICE "A0: %08lx D5: %08lx D4: %08lx\n",
111 regs->a0, regs->d5, regs->d4);
112 printk(KERN_NOTICE "D3: %08lx D2: %08lx D1: %08lx\n",
113 regs->d3, regs->d2, regs->d1);
114 if (!(regs->sr & PS_S))
115 printk(KERN_NOTICE "USP: %08lx\n", rdusp());
116}
117
118/*
119 * Create a kernel thread
120 */
121int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
122{
123 int retval;
124 long clone_arg = flags | CLONE_VM;
125 mm_segment_t fs;
126
127 fs = get_fs();
128 set_fs(KERNEL_DS);
129
130 __asm__ __volatile__ (
131 "movel %%sp, %%d2\n\t"
132 "movel %5, %%d1\n\t"
133 "movel %1, %%d0\n\t"
134 "trap #0\n\t"
135 "cmpl %%sp, %%d2\n\t"
136 "jeq 1f\n\t"
137 "movel %3, %%sp@-\n\t"
138 "jsr %4@\n\t"
139 "movel %2, %%d0\n\t"
140 "trap #0\n"
141 "1:\n\t"
142 "movel %%d0, %0\n"
143 : "=d" (retval)
144 : "i" (__NR_clone),
145 "i" (__NR_exit),
146 "a" (arg),
147 "a" (fn),
148 "a" (clone_arg)
149 : "cc", "%d0", "%d1", "%d2");
150
151 set_fs(fs);
152 return retval;
153}
154EXPORT_SYMBOL(kernel_thread);
155
156void flush_thread(void)
157{
158#ifdef CONFIG_FPU
159 unsigned long zero = 0;
160#endif
161 set_fs(USER_DS);
162 current->thread.fs = __USER_DS;
163#ifdef CONFIG_FPU
164 if (!FPU_IS_EMU)
165 asm volatile (".chip 68k/68881\n\t"
166 "frestore %0@\n\t"
167 ".chip 68k" : : "a" (&zero));
168#endif
169}
170
171/*
172 * "m68k_fork()".. By the time we get here, the
173 * non-volatile registers have also been saved on the
174 * stack. We do some ugly pointer stuff here.. (see
175 * also copy_thread)
176 */
177
178asmlinkage int m68k_fork(struct pt_regs *regs)
179{
180 /* fork almost works, enough to trick you into looking elsewhere :-( */
181 return(-EINVAL);
182}
183
184asmlinkage int m68k_vfork(struct pt_regs *regs)
185{
186 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL);
187}
188
189asmlinkage int m68k_clone(struct pt_regs *regs)
190{
191 unsigned long clone_flags;
192 unsigned long newsp;
193
194 /* syscall2 puts clone_flags in d1 and usp in d2 */
195 clone_flags = regs->d1;
196 newsp = regs->d2;
197 if (!newsp)
198 newsp = rdusp();
199 return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
200}
201
202int copy_thread(unsigned long clone_flags,
203 unsigned long usp, unsigned long topstk,
204 struct task_struct * p, struct pt_regs * regs)
205{
206 struct pt_regs * childregs;
207 struct switch_stack * childstack, *stack;
208 unsigned long *retp;
209
210 childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
211
212 *childregs = *regs;
213 childregs->d0 = 0;
214
215 retp = ((unsigned long *) regs);
216 stack = ((struct switch_stack *) retp) - 1;
217
218 childstack = ((struct switch_stack *) childregs) - 1;
219 *childstack = *stack;
220 childstack->retpc = (unsigned long)ret_from_fork;
221
222 p->thread.usp = usp;
223 p->thread.ksp = (unsigned long)childstack;
224
225 if (clone_flags & CLONE_SETTLS)
226 task_thread_info(p)->tp_value = regs->d5;
227
228 /*
229 * Must save the current SFC/DFC value, NOT the value when
230 * the parent was last descheduled - RGH 10-08-96
231 */
232 p->thread.fs = get_fs().seg;
233
234#ifdef CONFIG_FPU
235 if (!FPU_IS_EMU) {
236 /* Copy the current fpu state */
237 asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory");
238
239 if (p->thread.fpstate[0])
240 asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t"
241 "fmoveml %/fpiar/%/fpcr/%/fpsr,%1"
242 : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0])
243 : "memory");
244 /* Restore the state in case the fpu was busy */
245 asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0]));
246 }
247#endif
248
249 return 0;
250}
251
252/* Fill in the fpu structure for a core dump. */
253
254int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
255{
256#ifdef CONFIG_FPU
257 char fpustate[216];
258
259 if (FPU_IS_EMU) {
260 int i;
261
262 memcpy(fpu->fpcntl, current->thread.fpcntl, 12);
263 memcpy(fpu->fpregs, current->thread.fp, 96);
264 /* Convert internal fpu reg representation
265 * into long double format
266 */
267 for (i = 0; i < 24; i += 3)
268 fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) |
269 ((fpu->fpregs[i] & 0x0000ffff) << 16);
270 return 1;
271 }
272
273 /* First dump the fpu context to avoid protocol violation. */
274 asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory");
275 if (!fpustate[0])
276 return 0;
277
278 asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0"
279 :: "m" (fpu->fpcntl[0])
280 : "memory");
281 asm volatile ("fmovemx %/fp0-%/fp7,%0"
282 :: "m" (fpu->fpregs[0])
283 : "memory");
284#endif
285 return 1;
286}
287EXPORT_SYMBOL(dump_fpu);
288
289/*
290 * Generic dumping code. Used for panic and debug.
291 */
292void dump(struct pt_regs *fp)
293{
294 unsigned long *sp;
295 unsigned char *tp;
296 int i;
297
298 printk(KERN_EMERG "\nCURRENT PROCESS:\n\n");
299 printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid);
300
301 if (current->mm) {
302 printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
303 (int) current->mm->start_code,
304 (int) current->mm->end_code,
305 (int) current->mm->start_data,
306 (int) current->mm->end_data,
307 (int) current->mm->end_data,
308 (int) current->mm->brk);
309 printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n",
310 (int) current->mm->start_stack,
311 (int)(((unsigned long) current) + THREAD_SIZE));
312 }
313
314 printk(KERN_EMERG "PC: %08lx\n", fp->pc);
315 printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp);
316 printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
317 fp->d0, fp->d1, fp->d2, fp->d3);
318 printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
319 fp->d4, fp->d5, fp->a0, fp->a1);
320 printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %p\n",
321 (unsigned int) rdusp(), fp);
322
323 printk(KERN_EMERG "\nCODE:");
324 tp = ((unsigned char *) fp->pc) - 0x20;
325 for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) {
326 if ((i % 0x10) == 0)
327 printk(KERN_EMERG "%p: ", tp + i);
328 printk("%08x ", (int) *sp++);
329 }
330 printk(KERN_EMERG "\n");
331
332 printk(KERN_EMERG "KERNEL STACK:");
333 tp = ((unsigned char *) fp) - 0x40;
334 for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
335 if ((i % 0x10) == 0)
336 printk(KERN_EMERG "%p: ", tp + i);
337 printk("%08x ", (int) *sp++);
338 }
339 printk(KERN_EMERG "\n");
340
341 printk(KERN_EMERG "USER STACK:");
342 tp = (unsigned char *) (rdusp() - 0x10);
343 for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
344 if ((i % 0x10) == 0)
345 printk(KERN_EMERG "%p: ", tp + i);
346 printk("%08x ", (int) *sp++);
347 }
348 printk(KERN_EMERG "\n");
349}
350
351/*
352 * sys_execve() executes a new program.
353 */
354asmlinkage int sys_execve(const char *name,
355 const char *const *argv,
356 const char *const *envp)
357{
358 int error;
359 char * filename;
360 struct pt_regs *regs = (struct pt_regs *) &name;
361
362 filename = getname(name);
363 error = PTR_ERR(filename);
364 if (IS_ERR(filename))
365 return error;
366 error = do_execve(filename, argv, envp, regs);
367 putname(filename);
368 return error;
369}
370
371unsigned long get_wchan(struct task_struct *p)
372{
373 unsigned long fp, pc;
374 unsigned long stack_page;
375 int count = 0;
376 if (!p || p == current || p->state == TASK_RUNNING)
377 return 0;
378
379 stack_page = (unsigned long)p;
380 fp = ((struct switch_stack *)p->thread.ksp)->a6;
381 do {
382 if (fp < stack_page+sizeof(struct thread_info) ||
383 fp >= THREAD_SIZE-8+stack_page)
384 return 0;
385 pc = ((unsigned long *)fp)[1];
386 if (!in_sched_functions(pc))
387 return pc;
388 fp = *(unsigned long *) fp;
389 } while (count++ < 16);
390 return 0;
391}
392
393/*
394 * Return saved PC of a blocked thread.
395 */
396unsigned long thread_saved_pc(struct task_struct *tsk)
397{
398 struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp;
399
400 /* Check whether the thread is blocked in resume() */
401 if (in_sched_functions(sw->retpc))
402 return ((unsigned long *)sw->a6)[1];
403 else
404 return sw->retpc;
405}
406
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 616e59752c29..07a417550e94 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -1,276 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * linux/arch/m68k/kernel/ptrace.c 2#include "ptrace_mm.c"
3 * 3#else
4 * Copyright (C) 1994 by Hamish Macdonald 4#include "ptrace_no.c"
5 * Taken from linux/kernel/ptrace.c and modified for M680x0. 5#endif
6 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of
10 * this archive for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/errno.h>
18#include <linux/ptrace.h>
19#include <linux/user.h>
20#include <linux/signal.h>
21
22#include <asm/uaccess.h>
23#include <asm/page.h>
24#include <asm/pgtable.h>
25#include <asm/system.h>
26#include <asm/processor.h>
27
28/*
29 * does not yet catch signals sent when the child dies.
30 * in exit.c or in signal.c.
31 */
32
33/* determines which bits in the SR the user has access to. */
34/* 1 = access 0 = no access */
35#define SR_MASK 0x001f
36
37/* sets the trace bits. */
38#define TRACE_BITS 0xC000
39#define T1_BIT 0x8000
40#define T0_BIT 0x4000
41
42/* Find the stack offset for a register, relative to thread.esp0. */
43#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
44#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
45 - sizeof(struct switch_stack))
46/* Mapping from PT_xxx to the stack offset at which the register is
47 saved. Notice that usp has no stack-slot and needs to be treated
48 specially (see get_reg/put_reg below). */
49static const int regoff[] = {
50 [0] = PT_REG(d1),
51 [1] = PT_REG(d2),
52 [2] = PT_REG(d3),
53 [3] = PT_REG(d4),
54 [4] = PT_REG(d5),
55 [5] = SW_REG(d6),
56 [6] = SW_REG(d7),
57 [7] = PT_REG(a0),
58 [8] = PT_REG(a1),
59 [9] = PT_REG(a2),
60 [10] = SW_REG(a3),
61 [11] = SW_REG(a4),
62 [12] = SW_REG(a5),
63 [13] = SW_REG(a6),
64 [14] = PT_REG(d0),
65 [15] = -1,
66 [16] = PT_REG(orig_d0),
67 [17] = PT_REG(sr),
68 [18] = PT_REG(pc),
69};
70
71/*
72 * Get contents of register REGNO in task TASK.
73 */
74static inline long get_reg(struct task_struct *task, int regno)
75{
76 unsigned long *addr;
77
78 if (regno == PT_USP)
79 addr = &task->thread.usp;
80 else if (regno < ARRAY_SIZE(regoff))
81 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
82 else
83 return 0;
84 /* Need to take stkadj into account. */
85 if (regno == PT_SR || regno == PT_PC) {
86 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
87 addr = (unsigned long *) ((unsigned long)addr + stkadj);
88 /* The sr is actually a 16 bit register. */
89 if (regno == PT_SR)
90 return *(unsigned short *)addr;
91 }
92 return *addr;
93}
94
95/*
96 * Write contents of register REGNO in task TASK.
97 */
98static inline int put_reg(struct task_struct *task, int regno,
99 unsigned long data)
100{
101 unsigned long *addr;
102
103 if (regno == PT_USP)
104 addr = &task->thread.usp;
105 else if (regno < ARRAY_SIZE(regoff))
106 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
107 else
108 return -1;
109 /* Need to take stkadj into account. */
110 if (regno == PT_SR || regno == PT_PC) {
111 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
112 addr = (unsigned long *) ((unsigned long)addr + stkadj);
113 /* The sr is actually a 16 bit register. */
114 if (regno == PT_SR) {
115 *(unsigned short *)addr = data;
116 return 0;
117 }
118 }
119 *addr = data;
120 return 0;
121}
122
123/*
124 * Make sure the single step bit is not set.
125 */
126static inline void singlestep_disable(struct task_struct *child)
127{
128 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
129 put_reg(child, PT_SR, tmp);
130 clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
131}
132
133/*
134 * Called by kernel/ptrace.c when detaching..
135 */
136void ptrace_disable(struct task_struct *child)
137{
138 singlestep_disable(child);
139}
140
141void user_enable_single_step(struct task_struct *child)
142{
143 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
144 put_reg(child, PT_SR, tmp | T1_BIT);
145 set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
146}
147
148void user_enable_block_step(struct task_struct *child)
149{
150 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
151 put_reg(child, PT_SR, tmp | T0_BIT);
152}
153
154void user_disable_single_step(struct task_struct *child)
155{
156 singlestep_disable(child);
157}
158
159long arch_ptrace(struct task_struct *child, long request, long addr, long data)
160{
161 unsigned long tmp;
162 int i, ret = 0;
163
164 switch (request) {
165 /* read the word at location addr in the USER area. */
166 case PTRACE_PEEKUSR:
167 if (addr & 3)
168 goto out_eio;
169 addr >>= 2; /* temporary hack. */
170
171 if (addr >= 0 && addr < 19) {
172 tmp = get_reg(child, addr);
173 } else if (addr >= 21 && addr < 49) {
174 tmp = child->thread.fp[addr - 21];
175 /* Convert internal fpu reg representation
176 * into long double format
177 */
178 if (FPU_IS_EMU && (addr < 45) && !(addr % 3))
179 tmp = ((tmp & 0xffff0000) << 15) |
180 ((tmp & 0x0000ffff) << 16);
181 } else
182 goto out_eio;
183 ret = put_user(tmp, (unsigned long *)data);
184 break;
185
186 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
187 if (addr & 3)
188 goto out_eio;
189 addr >>= 2; /* temporary hack. */
190
191 if (addr == PT_SR) {
192 data &= SR_MASK;
193 data |= get_reg(child, PT_SR) & ~SR_MASK;
194 }
195 if (addr >= 0 && addr < 19) {
196 if (put_reg(child, addr, data))
197 goto out_eio;
198 } else if (addr >= 21 && addr < 48) {
199 /* Convert long double format
200 * into internal fpu reg representation
201 */
202 if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) {
203 data = (unsigned long)data << 15;
204 data = (data & 0xffff0000) |
205 ((data & 0x0000ffff) >> 1);
206 }
207 child->thread.fp[addr - 21] = data;
208 } else
209 goto out_eio;
210 break;
211
212 case PTRACE_GETREGS: /* Get all gp regs from the child. */
213 for (i = 0; i < 19; i++) {
214 tmp = get_reg(child, i);
215 ret = put_user(tmp, (unsigned long *)data);
216 if (ret)
217 break;
218 data += sizeof(long);
219 }
220 break;
221
222 case PTRACE_SETREGS: /* Set all gp regs in the child. */
223 for (i = 0; i < 19; i++) {
224 ret = get_user(tmp, (unsigned long *)data);
225 if (ret)
226 break;
227 if (i == PT_SR) {
228 tmp &= SR_MASK;
229 tmp |= get_reg(child, PT_SR) & ~SR_MASK;
230 }
231 put_reg(child, i, tmp);
232 data += sizeof(long);
233 }
234 break;
235
236 case PTRACE_GETFPREGS: /* Get the child FPU state. */
237 if (copy_to_user((void *)data, &child->thread.fp,
238 sizeof(struct user_m68kfp_struct)))
239 ret = -EFAULT;
240 break;
241
242 case PTRACE_SETFPREGS: /* Set the child FPU state. */
243 if (copy_from_user(&child->thread.fp, (void *)data,
244 sizeof(struct user_m68kfp_struct)))
245 ret = -EFAULT;
246 break;
247
248 case PTRACE_GET_THREAD_AREA:
249 ret = put_user(task_thread_info(child)->tp_value,
250 (unsigned long __user *)data);
251 break;
252
253 default:
254 ret = ptrace_request(child, request, addr, data);
255 break;
256 }
257
258 return ret;
259out_eio:
260 return -EIO;
261}
262
263asmlinkage void syscall_trace(void)
264{
265 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
266 ? 0x80 : 0));
267 /*
268 * this isn't the same as continuing with a signal, but it will do
269 * for normal use. strace only continues with a signal if the
270 * stopping signal is not SIGTRAP. -brl
271 */
272 if (current->exit_code) {
273 send_sig(current->exit_code, current, 1);
274 current->exit_code = 0;
275 }
276}
diff --git a/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c
new file mode 100644
index 000000000000..0b252683cefb
--- /dev/null
+++ b/arch/m68k/kernel/ptrace_mm.c
@@ -0,0 +1,277 @@
1/*
2 * linux/arch/m68k/kernel/ptrace.c
3 *
4 * Copyright (C) 1994 by Hamish Macdonald
5 * Taken from linux/kernel/ptrace.c and modified for M680x0.
6 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of
10 * this archive for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/errno.h>
18#include <linux/ptrace.h>
19#include <linux/user.h>
20#include <linux/signal.h>
21
22#include <asm/uaccess.h>
23#include <asm/page.h>
24#include <asm/pgtable.h>
25#include <asm/system.h>
26#include <asm/processor.h>
27
28/*
29 * does not yet catch signals sent when the child dies.
30 * in exit.c or in signal.c.
31 */
32
33/* determines which bits in the SR the user has access to. */
34/* 1 = access 0 = no access */
35#define SR_MASK 0x001f
36
37/* sets the trace bits. */
38#define TRACE_BITS 0xC000
39#define T1_BIT 0x8000
40#define T0_BIT 0x4000
41
42/* Find the stack offset for a register, relative to thread.esp0. */
43#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
44#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
45 - sizeof(struct switch_stack))
46/* Mapping from PT_xxx to the stack offset at which the register is
47 saved. Notice that usp has no stack-slot and needs to be treated
48 specially (see get_reg/put_reg below). */
49static const int regoff[] = {
50 [0] = PT_REG(d1),
51 [1] = PT_REG(d2),
52 [2] = PT_REG(d3),
53 [3] = PT_REG(d4),
54 [4] = PT_REG(d5),
55 [5] = SW_REG(d6),
56 [6] = SW_REG(d7),
57 [7] = PT_REG(a0),
58 [8] = PT_REG(a1),
59 [9] = PT_REG(a2),
60 [10] = SW_REG(a3),
61 [11] = SW_REG(a4),
62 [12] = SW_REG(a5),
63 [13] = SW_REG(a6),
64 [14] = PT_REG(d0),
65 [15] = -1,
66 [16] = PT_REG(orig_d0),
67 [17] = PT_REG(sr),
68 [18] = PT_REG(pc),
69};
70
71/*
72 * Get contents of register REGNO in task TASK.
73 */
74static inline long get_reg(struct task_struct *task, int regno)
75{
76 unsigned long *addr;
77
78 if (regno == PT_USP)
79 addr = &task->thread.usp;
80 else if (regno < ARRAY_SIZE(regoff))
81 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
82 else
83 return 0;
84 /* Need to take stkadj into account. */
85 if (regno == PT_SR || regno == PT_PC) {
86 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
87 addr = (unsigned long *) ((unsigned long)addr + stkadj);
88 /* The sr is actually a 16 bit register. */
89 if (regno == PT_SR)
90 return *(unsigned short *)addr;
91 }
92 return *addr;
93}
94
95/*
96 * Write contents of register REGNO in task TASK.
97 */
98static inline int put_reg(struct task_struct *task, int regno,
99 unsigned long data)
100{
101 unsigned long *addr;
102
103 if (regno == PT_USP)
104 addr = &task->thread.usp;
105 else if (regno < ARRAY_SIZE(regoff))
106 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
107 else
108 return -1;
109 /* Need to take stkadj into account. */
110 if (regno == PT_SR || regno == PT_PC) {
111 long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj));
112 addr = (unsigned long *) ((unsigned long)addr + stkadj);
113 /* The sr is actually a 16 bit register. */
114 if (regno == PT_SR) {
115 *(unsigned short *)addr = data;
116 return 0;
117 }
118 }
119 *addr = data;
120 return 0;
121}
122
123/*
124 * Make sure the single step bit is not set.
125 */
126static inline void singlestep_disable(struct task_struct *child)
127{
128 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
129 put_reg(child, PT_SR, tmp);
130 clear_tsk_thread_flag(child, TIF_DELAYED_TRACE);
131}
132
133/*
134 * Called by kernel/ptrace.c when detaching..
135 */
136void ptrace_disable(struct task_struct *child)
137{
138 singlestep_disable(child);
139}
140
141void user_enable_single_step(struct task_struct *child)
142{
143 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
144 put_reg(child, PT_SR, tmp | T1_BIT);
145 set_tsk_thread_flag(child, TIF_DELAYED_TRACE);
146}
147
148void user_enable_block_step(struct task_struct *child)
149{
150 unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS;
151 put_reg(child, PT_SR, tmp | T0_BIT);
152}
153
154void user_disable_single_step(struct task_struct *child)
155{
156 singlestep_disable(child);
157}
158
159long arch_ptrace(struct task_struct *child, long request,
160 unsigned long addr, unsigned long data)
161{
162 unsigned long tmp;
163 int i, ret = 0;
164 int regno = addr >> 2; /* temporary hack. */
165 unsigned long __user *datap = (unsigned long __user *) data;
166
167 switch (request) {
168 /* read the word at location addr in the USER area. */
169 case PTRACE_PEEKUSR:
170 if (addr & 3)
171 goto out_eio;
172
173 if (regno >= 0 && regno < 19) {
174 tmp = get_reg(child, regno);
175 } else if (regno >= 21 && regno < 49) {
176 tmp = child->thread.fp[regno - 21];
177 /* Convert internal fpu reg representation
178 * into long double format
179 */
180 if (FPU_IS_EMU && (regno < 45) && !(regno % 3))
181 tmp = ((tmp & 0xffff0000) << 15) |
182 ((tmp & 0x0000ffff) << 16);
183 } else
184 goto out_eio;
185 ret = put_user(tmp, datap);
186 break;
187
188 case PTRACE_POKEUSR:
189 /* write the word at location addr in the USER area */
190 if (addr & 3)
191 goto out_eio;
192
193 if (regno == PT_SR) {
194 data &= SR_MASK;
195 data |= get_reg(child, PT_SR) & ~SR_MASK;
196 }
197 if (regno >= 0 && regno < 19) {
198 if (put_reg(child, regno, data))
199 goto out_eio;
200 } else if (regno >= 21 && regno < 48) {
201 /* Convert long double format
202 * into internal fpu reg representation
203 */
204 if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) {
205 data <<= 15;
206 data = (data & 0xffff0000) |
207 ((data & 0x0000ffff) >> 1);
208 }
209 child->thread.fp[regno - 21] = data;
210 } else
211 goto out_eio;
212 break;
213
214 case PTRACE_GETREGS: /* Get all gp regs from the child. */
215 for (i = 0; i < 19; i++) {
216 tmp = get_reg(child, i);
217 ret = put_user(tmp, datap);
218 if (ret)
219 break;
220 datap++;
221 }
222 break;
223
224 case PTRACE_SETREGS: /* Set all gp regs in the child. */
225 for (i = 0; i < 19; i++) {
226 ret = get_user(tmp, datap);
227 if (ret)
228 break;
229 if (i == PT_SR) {
230 tmp &= SR_MASK;
231 tmp |= get_reg(child, PT_SR) & ~SR_MASK;
232 }
233 put_reg(child, i, tmp);
234 datap++;
235 }
236 break;
237
238 case PTRACE_GETFPREGS: /* Get the child FPU state. */
239 if (copy_to_user(datap, &child->thread.fp,
240 sizeof(struct user_m68kfp_struct)))
241 ret = -EFAULT;
242 break;
243
244 case PTRACE_SETFPREGS: /* Set the child FPU state. */
245 if (copy_from_user(&child->thread.fp, datap,
246 sizeof(struct user_m68kfp_struct)))
247 ret = -EFAULT;
248 break;
249
250 case PTRACE_GET_THREAD_AREA:
251 ret = put_user(task_thread_info(child)->tp_value, datap);
252 break;
253
254 default:
255 ret = ptrace_request(child, request, addr, data);
256 break;
257 }
258
259 return ret;
260out_eio:
261 return -EIO;
262}
263
264asmlinkage void syscall_trace(void)
265{
266 ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
267 ? 0x80 : 0));
268 /*
269 * this isn't the same as continuing with a signal, but it will do
270 * for normal use. strace only continues with a signal if the
271 * stopping signal is not SIGTRAP. -brl
272 */
273 if (current->exit_code) {
274 send_sig(current->exit_code, current, 1);
275 current->exit_code = 0;
276 }
277}
diff --git a/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c
new file mode 100644
index 000000000000..6709fb707335
--- /dev/null
+++ b/arch/m68k/kernel/ptrace_no.c
@@ -0,0 +1,255 @@
1/*
2 * linux/arch/m68knommu/kernel/ptrace.c
3 *
4 * Copyright (C) 1994 by Hamish Macdonald
5 * Taken from linux/kernel/ptrace.c and modified for M680x0.
6 * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
7 *
8 * This file is subject to the terms and conditions of the GNU General
9 * Public License. See the file COPYING in the main directory of
10 * this archive for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/errno.h>
18#include <linux/ptrace.h>
19#include <linux/user.h>
20#include <linux/signal.h>
21#include <linux/tracehook.h>
22
23#include <asm/uaccess.h>
24#include <asm/page.h>
25#include <asm/pgtable.h>
26#include <asm/system.h>
27#include <asm/processor.h>
28
29/*
30 * does not yet catch signals sent when the child dies.
31 * in exit.c or in signal.c.
32 */
33
34/* determines which bits in the SR the user has access to. */
35/* 1 = access 0 = no access */
36#define SR_MASK 0x001f
37
38/* sets the trace bits. */
39#define TRACE_BITS 0x8000
40
41/* Find the stack offset for a register, relative to thread.esp0. */
42#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
43#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \
44 - sizeof(struct switch_stack))
45/* Mapping from PT_xxx to the stack offset at which the register is
46 saved. Notice that usp has no stack-slot and needs to be treated
47 specially (see get_reg/put_reg below). */
48static int regoff[] = {
49 PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4),
50 PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0),
51 PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4),
52 SW_REG(a5), SW_REG(a6), PT_REG(d0), -1,
53 PT_REG(orig_d0), PT_REG(sr), PT_REG(pc),
54};
55
56/*
57 * Get contents of register REGNO in task TASK.
58 */
59static inline long get_reg(struct task_struct *task, int regno)
60{
61 unsigned long *addr;
62
63 if (regno == PT_USP)
64 addr = &task->thread.usp;
65 else if (regno < ARRAY_SIZE(regoff))
66 addr = (unsigned long *)(task->thread.esp0 + regoff[regno]);
67 else
68 return 0;
69 return *addr;
70}
71
72/*
73 * Write contents of register REGNO in task TASK.
74 */
75static inline int put_reg(struct task_struct *task, int regno,
76 unsigned long data)
77{
78 unsigned long *addr;
79
80 if (regno == PT_USP)
81 addr = &task->thread.usp;
82 else if (regno < ARRAY_SIZE(regoff))
83 addr = (unsigned long *) (task->thread.esp0 + regoff[regno]);
84 else
85 return -1;
86 *addr = data;
87 return 0;
88}
89
90void user_enable_single_step(struct task_struct *task)
91{
92 unsigned long srflags;
93 srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16);
94 put_reg(task, PT_SR, srflags);
95}
96
97void user_disable_single_step(struct task_struct *task)
98{
99 unsigned long srflags;
100 srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16);
101 put_reg(task, PT_SR, srflags);
102}
103
104/*
105 * Called by kernel/ptrace.c when detaching..
106 *
107 * Make sure the single step bit is not set.
108 */
109void ptrace_disable(struct task_struct *child)
110{
111 /* make sure the single step bit is not set. */
112 user_disable_single_step(child);
113}
114
115long arch_ptrace(struct task_struct *child, long request,
116 unsigned long addr, unsigned long data)
117{
118 int ret;
119 int regno = addr >> 2;
120 unsigned long __user *datap = (unsigned long __user *) data;
121
122 switch (request) {
123 /* read the word at location addr in the USER area. */
124 case PTRACE_PEEKUSR: {
125 unsigned long tmp;
126
127 ret = -EIO;
128 if ((addr & 3) || addr > sizeof(struct user) - 3)
129 break;
130
131 tmp = 0; /* Default return condition */
132 ret = -EIO;
133 if (regno < 19) {
134 tmp = get_reg(child, regno);
135 if (regno == PT_SR)
136 tmp >>= 16;
137 } else if (regno >= 21 && regno < 49) {
138 tmp = child->thread.fp[regno - 21];
139 } else if (regno == 49) {
140 tmp = child->mm->start_code;
141 } else if (regno == 50) {
142 tmp = child->mm->start_data;
143 } else if (regno == 51) {
144 tmp = child->mm->end_code;
145 } else
146 break;
147 ret = put_user(tmp, datap);
148 break;
149 }
150
151 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
152 ret = -EIO;
153 if ((addr & 3) || addr > sizeof(struct user) - 3)
154 break;
155
156 if (regno == PT_SR) {
157 data &= SR_MASK;
158 data <<= 16;
159 data |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
160 }
161 if (regno < 19) {
162 if (put_reg(child, regno, data))
163 break;
164 ret = 0;
165 break;
166 }
167 if (regno >= 21 && regno < 48)
168 {
169 child->thread.fp[regno - 21] = data;
170 ret = 0;
171 }
172 break;
173
174 case PTRACE_GETREGS: { /* Get all gp regs from the child. */
175 int i;
176 unsigned long tmp;
177 for (i = 0; i < 19; i++) {
178 tmp = get_reg(child, i);
179 if (i == PT_SR)
180 tmp >>= 16;
181 if (put_user(tmp, datap)) {
182 ret = -EFAULT;
183 break;
184 }
185 datap++;
186 }
187 ret = 0;
188 break;
189 }
190
191 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
192 int i;
193 unsigned long tmp;
194 for (i = 0; i < 19; i++) {
195 if (get_user(tmp, datap)) {
196 ret = -EFAULT;
197 break;
198 }
199 if (i == PT_SR) {
200 tmp &= SR_MASK;
201 tmp <<= 16;
202 tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16);
203 }
204 put_reg(child, i, tmp);
205 datap++;
206 }
207 ret = 0;
208 break;
209 }
210
211#ifdef PTRACE_GETFPREGS
212 case PTRACE_GETFPREGS: { /* Get the child FPU state. */
213 ret = 0;
214 if (copy_to_user(datap, &child->thread.fp,
215 sizeof(struct user_m68kfp_struct)))
216 ret = -EFAULT;
217 break;
218 }
219#endif
220
221#ifdef PTRACE_SETFPREGS
222 case PTRACE_SETFPREGS: { /* Set the child FPU state. */
223 ret = 0;
224 if (copy_from_user(&child->thread.fp, datap,
225 sizeof(struct user_m68kfp_struct)))
226 ret = -EFAULT;
227 break;
228 }
229#endif
230
231 case PTRACE_GET_THREAD_AREA:
232 ret = put_user(task_thread_info(child)->tp_value, datap);
233 break;
234
235 default:
236 ret = ptrace_request(child, request, addr, data);
237 break;
238 }
239 return ret;
240}
241
242asmlinkage int syscall_trace_enter(void)
243{
244 int ret = 0;
245
246 if (test_thread_flag(TIF_SYSCALL_TRACE))
247 ret = tracehook_report_syscall_entry(task_pt_regs(current));
248 return ret;
249}
250
251asmlinkage void syscall_trace_leave(void)
252{
253 if (test_thread_flag(TIF_SYSCALL_TRACE))
254 tracehook_report_syscall_exit(task_pt_regs(current), 0);
255}
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index 303730afb1c9..4bf129f1d2e2 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -1,534 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * linux/arch/m68k/kernel/setup.c 2#include "setup_mm.c"
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 */
6
7/*
8 * This file handles the architecture-dependent parts of system setup
9 */
10
11#include <linux/kernel.h>
12#include <linux/mm.h>
13#include <linux/sched.h>
14#include <linux/delay.h>
15#include <linux/interrupt.h>
16#include <linux/fs.h>
17#include <linux/console.h>
18#include <linux/genhd.h>
19#include <linux/errno.h>
20#include <linux/string.h>
21#include <linux/init.h>
22#include <linux/bootmem.h>
23#include <linux/proc_fs.h>
24#include <linux/seq_file.h>
25#include <linux/module.h>
26#include <linux/initrd.h>
27
28#include <asm/bootinfo.h>
29#include <asm/sections.h>
30#include <asm/setup.h>
31#include <asm/fpu.h>
32#include <asm/irq.h>
33#include <asm/io.h>
34#include <asm/machdep.h>
35#ifdef CONFIG_AMIGA
36#include <asm/amigahw.h>
37#endif
38#ifdef CONFIG_ATARI
39#include <asm/atarihw.h>
40#include <asm/atari_stram.h>
41#endif
42#ifdef CONFIG_SUN3X
43#include <asm/dvma.h>
44#endif
45
46#if !FPSTATESIZE || !NR_IRQS
47#warning No CPU/platform type selected, your kernel will not work!
48#warning Are you building an allnoconfig kernel?
49#endif
50
51unsigned long m68k_machtype;
52EXPORT_SYMBOL(m68k_machtype);
53unsigned long m68k_cputype;
54EXPORT_SYMBOL(m68k_cputype);
55unsigned long m68k_fputype;
56unsigned long m68k_mmutype;
57EXPORT_SYMBOL(m68k_mmutype);
58#ifdef CONFIG_VME
59unsigned long vme_brdtype;
60EXPORT_SYMBOL(vme_brdtype);
61#endif
62
63int m68k_is040or060;
64EXPORT_SYMBOL(m68k_is040or060);
65
66extern unsigned long availmem;
67
68int m68k_num_memory;
69EXPORT_SYMBOL(m68k_num_memory);
70int m68k_realnum_memory;
71EXPORT_SYMBOL(m68k_realnum_memory);
72unsigned long m68k_memoffset;
73struct mem_info m68k_memory[NUM_MEMINFO];
74EXPORT_SYMBOL(m68k_memory);
75
76struct mem_info m68k_ramdisk;
77
78static char m68k_command_line[CL_SIZE];
79
80void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
81/* machine dependent irq functions */
82void (*mach_init_IRQ) (void) __initdata = NULL;
83void (*mach_get_model) (char *model);
84void (*mach_get_hardware_list) (struct seq_file *m);
85/* machine dependent timer functions */
86unsigned long (*mach_gettimeoffset) (void);
87int (*mach_hwclk) (int, struct rtc_time*);
88EXPORT_SYMBOL(mach_hwclk);
89int (*mach_set_clock_mmss) (unsigned long);
90unsigned int (*mach_get_ss)(void);
91int (*mach_get_rtc_pll)(struct rtc_pll_info *);
92int (*mach_set_rtc_pll)(struct rtc_pll_info *);
93EXPORT_SYMBOL(mach_get_ss);
94EXPORT_SYMBOL(mach_get_rtc_pll);
95EXPORT_SYMBOL(mach_set_rtc_pll);
96void (*mach_reset)( void );
97void (*mach_halt)( void );
98void (*mach_power_off)( void );
99long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
100#ifdef CONFIG_HEARTBEAT
101void (*mach_heartbeat) (int);
102EXPORT_SYMBOL(mach_heartbeat);
103#endif
104#ifdef CONFIG_M68K_L2_CACHE
105void (*mach_l2_flush) (int);
106#endif
107#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
108void (*mach_beep)(unsigned int, unsigned int);
109EXPORT_SYMBOL(mach_beep);
110#endif
111#if defined(CONFIG_ISA) && defined(MULTI_ISA)
112int isa_type;
113int isa_sex;
114EXPORT_SYMBOL(isa_type);
115EXPORT_SYMBOL(isa_sex);
116#endif
117
118extern int amiga_parse_bootinfo(const struct bi_record *);
119extern int atari_parse_bootinfo(const struct bi_record *);
120extern int mac_parse_bootinfo(const struct bi_record *);
121extern int q40_parse_bootinfo(const struct bi_record *);
122extern int bvme6000_parse_bootinfo(const struct bi_record *);
123extern int mvme16x_parse_bootinfo(const struct bi_record *);
124extern int mvme147_parse_bootinfo(const struct bi_record *);
125extern int hp300_parse_bootinfo(const struct bi_record *);
126extern int apollo_parse_bootinfo(const struct bi_record *);
127
128extern void config_amiga(void);
129extern void config_atari(void);
130extern void config_mac(void);
131extern void config_sun3(void);
132extern void config_apollo(void);
133extern void config_mvme147(void);
134extern void config_mvme16x(void);
135extern void config_bvme6000(void);
136extern void config_hp300(void);
137extern void config_q40(void);
138extern void config_sun3x(void);
139
140#define MASK_256K 0xfffc0000
141
142extern void paging_init(void);
143
144static void __init m68k_parse_bootinfo(const struct bi_record *record)
145{
146 while (record->tag != BI_LAST) {
147 int unknown = 0;
148 const unsigned long *data = record->data;
149
150 switch (record->tag) {
151 case BI_MACHTYPE:
152 case BI_CPUTYPE:
153 case BI_FPUTYPE:
154 case BI_MMUTYPE:
155 /* Already set up by head.S */
156 break;
157
158 case BI_MEMCHUNK:
159 if (m68k_num_memory < NUM_MEMINFO) {
160 m68k_memory[m68k_num_memory].addr = data[0];
161 m68k_memory[m68k_num_memory].size = data[1];
162 m68k_num_memory++;
163 } else
164 printk("m68k_parse_bootinfo: too many memory chunks\n");
165 break;
166
167 case BI_RAMDISK:
168 m68k_ramdisk.addr = data[0];
169 m68k_ramdisk.size = data[1];
170 break;
171
172 case BI_COMMAND_LINE:
173 strlcpy(m68k_command_line, (const char *)data,
174 sizeof(m68k_command_line));
175 break;
176
177 default:
178 if (MACH_IS_AMIGA)
179 unknown = amiga_parse_bootinfo(record);
180 else if (MACH_IS_ATARI)
181 unknown = atari_parse_bootinfo(record);
182 else if (MACH_IS_MAC)
183 unknown = mac_parse_bootinfo(record);
184 else if (MACH_IS_Q40)
185 unknown = q40_parse_bootinfo(record);
186 else if (MACH_IS_BVME6000)
187 unknown = bvme6000_parse_bootinfo(record);
188 else if (MACH_IS_MVME16x)
189 unknown = mvme16x_parse_bootinfo(record);
190 else if (MACH_IS_MVME147)
191 unknown = mvme147_parse_bootinfo(record);
192 else if (MACH_IS_HP300)
193 unknown = hp300_parse_bootinfo(record);
194 else if (MACH_IS_APOLLO)
195 unknown = apollo_parse_bootinfo(record);
196 else
197 unknown = 1;
198 }
199 if (unknown)
200 printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
201 record->tag);
202 record = (struct bi_record *)((unsigned long)record +
203 record->size);
204 }
205
206 m68k_realnum_memory = m68k_num_memory;
207#ifdef CONFIG_SINGLE_MEMORY_CHUNK
208 if (m68k_num_memory > 1) {
209 printk("Ignoring last %i chunks of physical memory\n",
210 (m68k_num_memory - 1));
211 m68k_num_memory = 1;
212 }
213#endif
214}
215
216void __init setup_arch(char **cmdline_p)
217{
218 int i;
219
220 /* The bootinfo is located right after the kernel bss */
221 m68k_parse_bootinfo((const struct bi_record *)_end);
222
223 if (CPU_IS_040)
224 m68k_is040or060 = 4;
225 else if (CPU_IS_060)
226 m68k_is040or060 = 6;
227
228 /* FIXME: m68k_fputype is passed in by Penguin booter, which can
229 * be confused by software FPU emulation. BEWARE.
230 * We should really do our own FPU check at startup.
231 * [what do we do with buggy 68LC040s? if we have problems
232 * with them, we should add a test to check_bugs() below] */
233#ifndef CONFIG_M68KFPU_EMU_ONLY
234 /* clear the fpu if we have one */
235 if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
236 volatile int zero = 0;
237 asm volatile ("frestore %0" : : "m" (zero));
238 }
239#endif
240
241 if (CPU_IS_060) {
242 u32 pcr;
243
244 asm (".chip 68060; movec %%pcr,%0; .chip 68k"
245 : "=d" (pcr));
246 if (((pcr >> 8) & 0xff) <= 5) {
247 printk("Enabling workaround for errata I14\n");
248 asm (".chip 68060; movec %0,%%pcr; .chip 68k"
249 : : "d" (pcr | 0x20));
250 }
251 }
252
253 init_mm.start_code = PAGE_OFFSET;
254 init_mm.end_code = (unsigned long)_etext;
255 init_mm.end_data = (unsigned long)_edata;
256 init_mm.brk = (unsigned long)_end;
257
258 *cmdline_p = m68k_command_line;
259 memcpy(boot_command_line, *cmdline_p, CL_SIZE);
260
261 parse_early_param();
262
263#ifdef CONFIG_DUMMY_CONSOLE
264 conswitchp = &dummy_con;
265#endif
266
267 switch (m68k_machtype) {
268#ifdef CONFIG_AMIGA
269 case MACH_AMIGA:
270 config_amiga();
271 break;
272#endif
273#ifdef CONFIG_ATARI
274 case MACH_ATARI:
275 config_atari();
276 break;
277#endif
278#ifdef CONFIG_MAC
279 case MACH_MAC:
280 config_mac();
281 break;
282#endif
283#ifdef CONFIG_SUN3
284 case MACH_SUN3:
285 config_sun3();
286 break;
287#endif
288#ifdef CONFIG_APOLLO
289 case MACH_APOLLO:
290 config_apollo();
291 break;
292#endif
293#ifdef CONFIG_MVME147
294 case MACH_MVME147:
295 config_mvme147();
296 break;
297#endif
298#ifdef CONFIG_MVME16x
299 case MACH_MVME16x:
300 config_mvme16x();
301 break;
302#endif
303#ifdef CONFIG_BVME6000
304 case MACH_BVME6000:
305 config_bvme6000();
306 break;
307#endif
308#ifdef CONFIG_HP300
309 case MACH_HP300:
310 config_hp300();
311 break;
312#endif
313#ifdef CONFIG_Q40
314 case MACH_Q40:
315 config_q40();
316 break;
317#endif
318#ifdef CONFIG_SUN3X
319 case MACH_SUN3X:
320 config_sun3x();
321 break;
322#endif
323 default:
324 panic("No configuration setup");
325 }
326
327 paging_init();
328
329#ifndef CONFIG_SUN3
330 for (i = 1; i < m68k_num_memory; i++)
331 free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
332 m68k_memory[i].size);
333#ifdef CONFIG_BLK_DEV_INITRD
334 if (m68k_ramdisk.size) {
335 reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
336 m68k_ramdisk.addr, m68k_ramdisk.size,
337 BOOTMEM_DEFAULT);
338 initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
339 initrd_end = initrd_start + m68k_ramdisk.size;
340 printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
341 }
342#endif
343
344#ifdef CONFIG_ATARI
345 if (MACH_IS_ATARI)
346 atari_stram_reserve_pages((void *)availmem);
347#endif
348#ifdef CONFIG_SUN3X
349 if (MACH_IS_SUN3X) {
350 dvma_init();
351 }
352#endif
353
354#endif /* !CONFIG_SUN3 */
355
356/* set ISA defs early as possible */
357#if defined(CONFIG_ISA) && defined(MULTI_ISA)
358 if (MACH_IS_Q40) {
359 isa_type = ISA_TYPE_Q40;
360 isa_sex = 0;
361 }
362#ifdef CONFIG_GG2
363 if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) {
364 isa_type = ISA_TYPE_GG2;
365 isa_sex = 0;
366 }
367#endif
368#ifdef CONFIG_AMIGA_PCMCIA
369 if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
370 isa_type = ISA_TYPE_AG;
371 isa_sex = 1;
372 }
373#endif
374#endif
375}
376
377static int show_cpuinfo(struct seq_file *m, void *v)
378{
379 const char *cpu, *mmu, *fpu;
380 unsigned long clockfreq, clockfactor;
381
382#define LOOP_CYCLES_68020 (8)
383#define LOOP_CYCLES_68030 (8)
384#define LOOP_CYCLES_68040 (3)
385#define LOOP_CYCLES_68060 (1)
386
387 if (CPU_IS_020) {
388 cpu = "68020";
389 clockfactor = LOOP_CYCLES_68020;
390 } else if (CPU_IS_030) {
391 cpu = "68030";
392 clockfactor = LOOP_CYCLES_68030;
393 } else if (CPU_IS_040) {
394 cpu = "68040";
395 clockfactor = LOOP_CYCLES_68040;
396 } else if (CPU_IS_060) {
397 cpu = "68060";
398 clockfactor = LOOP_CYCLES_68060;
399 } else {
400 cpu = "680x0";
401 clockfactor = 0;
402 }
403
404#ifdef CONFIG_M68KFPU_EMU_ONLY
405 fpu = "none(soft float)";
406#else 3#else
407 if (m68k_fputype & FPU_68881) 4#include "setup_no.c"
408 fpu = "68881";
409 else if (m68k_fputype & FPU_68882)
410 fpu = "68882";
411 else if (m68k_fputype & FPU_68040)
412 fpu = "68040";
413 else if (m68k_fputype & FPU_68060)
414 fpu = "68060";
415 else if (m68k_fputype & FPU_SUNFPA)
416 fpu = "Sun FPA";
417 else
418 fpu = "none";
419#endif
420
421 if (m68k_mmutype & MMU_68851)
422 mmu = "68851";
423 else if (m68k_mmutype & MMU_68030)
424 mmu = "68030";
425 else if (m68k_mmutype & MMU_68040)
426 mmu = "68040";
427 else if (m68k_mmutype & MMU_68060)
428 mmu = "68060";
429 else if (m68k_mmutype & MMU_SUN3)
430 mmu = "Sun-3";
431 else if (m68k_mmutype & MMU_APOLLO)
432 mmu = "Apollo";
433 else
434 mmu = "unknown";
435
436 clockfreq = loops_per_jiffy * HZ * clockfactor;
437
438 seq_printf(m, "CPU:\t\t%s\n"
439 "MMU:\t\t%s\n"
440 "FPU:\t\t%s\n"
441 "Clocking:\t%lu.%1luMHz\n"
442 "BogoMips:\t%lu.%02lu\n"
443 "Calibration:\t%lu loops\n",
444 cpu, mmu, fpu,
445 clockfreq/1000000,(clockfreq/100000)%10,
446 loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
447 loops_per_jiffy);
448 return 0;
449}
450
451static void *c_start(struct seq_file *m, loff_t *pos)
452{
453 return *pos < 1 ? (void *)1 : NULL;
454}
455static void *c_next(struct seq_file *m, void *v, loff_t *pos)
456{
457 ++*pos;
458 return NULL;
459}
460static void c_stop(struct seq_file *m, void *v)
461{
462}
463const struct seq_operations cpuinfo_op = {
464 .start = c_start,
465 .next = c_next,
466 .stop = c_stop,
467 .show = show_cpuinfo,
468};
469
470#ifdef CONFIG_PROC_HARDWARE
471static int hardware_proc_show(struct seq_file *m, void *v)
472{
473 char model[80];
474 unsigned long mem;
475 int i;
476
477 if (mach_get_model)
478 mach_get_model(model);
479 else
480 strcpy(model, "Unknown m68k");
481
482 seq_printf(m, "Model:\t\t%s\n", model);
483 for (mem = 0, i = 0; i < m68k_num_memory; i++)
484 mem += m68k_memory[i].size;
485 seq_printf(m, "System Memory:\t%ldK\n", mem >> 10);
486
487 if (mach_get_hardware_list)
488 mach_get_hardware_list(m);
489
490 return 0;
491}
492
493static int hardware_proc_open(struct inode *inode, struct file *file)
494{
495 return single_open(file, hardware_proc_show, NULL);
496}
497
498static const struct file_operations hardware_proc_fops = {
499 .open = hardware_proc_open,
500 .read = seq_read,
501 .llseek = seq_lseek,
502 .release = single_release,
503};
504
505static int __init proc_hardware_init(void)
506{
507 proc_create("hardware", 0, NULL, &hardware_proc_fops);
508 return 0;
509}
510module_init(proc_hardware_init);
511#endif 5#endif
512
513void check_bugs(void)
514{
515#ifndef CONFIG_M68KFPU_EMU
516 if (m68k_fputype == 0) {
517 printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
518 "WHICH IS REQUIRED BY LINUX/M68K ***\n");
519 printk(KERN_EMERG "Upgrade your hardware or join the FPU "
520 "emulation project\n");
521 panic("no FPU");
522 }
523#endif /* !CONFIG_M68KFPU_EMU */
524}
525
526#ifdef CONFIG_ADB
527static int __init adb_probe_sync_enable (char *str) {
528 extern int __adb_probe_sync;
529 __adb_probe_sync = 1;
530 return 1;
531}
532
533__setup("adb_sync", adb_probe_sync_enable);
534#endif /* CONFIG_ADB */
diff --git a/arch/m68k/kernel/setup_mm.c b/arch/m68k/kernel/setup_mm.c
new file mode 100644
index 000000000000..334d83640376
--- /dev/null
+++ b/arch/m68k/kernel/setup_mm.c
@@ -0,0 +1,533 @@
1/*
2 * linux/arch/m68k/kernel/setup.c
3 *
4 * Copyright (C) 1995 Hamish Macdonald
5 */
6
7/*
8 * This file handles the architecture-dependent parts of system setup
9 */
10
11#include <linux/kernel.h>
12#include <linux/mm.h>
13#include <linux/sched.h>
14#include <linux/delay.h>
15#include <linux/interrupt.h>
16#include <linux/fs.h>
17#include <linux/console.h>
18#include <linux/genhd.h>
19#include <linux/errno.h>
20#include <linux/string.h>
21#include <linux/init.h>
22#include <linux/bootmem.h>
23#include <linux/proc_fs.h>
24#include <linux/seq_file.h>
25#include <linux/module.h>
26#include <linux/initrd.h>
27
28#include <asm/bootinfo.h>
29#include <asm/sections.h>
30#include <asm/setup.h>
31#include <asm/fpu.h>
32#include <asm/irq.h>
33#include <asm/io.h>
34#include <asm/machdep.h>
35#ifdef CONFIG_AMIGA
36#include <asm/amigahw.h>
37#endif
38#ifdef CONFIG_ATARI
39#include <asm/atarihw.h>
40#include <asm/atari_stram.h>
41#endif
42#ifdef CONFIG_SUN3X
43#include <asm/dvma.h>
44#endif
45#include <asm/natfeat.h>
46
47#if !FPSTATESIZE || !NR_IRQS
48#warning No CPU/platform type selected, your kernel will not work!
49#warning Are you building an allnoconfig kernel?
50#endif
51
52unsigned long m68k_machtype;
53EXPORT_SYMBOL(m68k_machtype);
54unsigned long m68k_cputype;
55EXPORT_SYMBOL(m68k_cputype);
56unsigned long m68k_fputype;
57unsigned long m68k_mmutype;
58EXPORT_SYMBOL(m68k_mmutype);
59#ifdef CONFIG_VME
60unsigned long vme_brdtype;
61EXPORT_SYMBOL(vme_brdtype);
62#endif
63
64int m68k_is040or060;
65EXPORT_SYMBOL(m68k_is040or060);
66
67extern unsigned long availmem;
68
69int m68k_num_memory;
70EXPORT_SYMBOL(m68k_num_memory);
71int m68k_realnum_memory;
72EXPORT_SYMBOL(m68k_realnum_memory);
73unsigned long m68k_memoffset;
74struct mem_info m68k_memory[NUM_MEMINFO];
75EXPORT_SYMBOL(m68k_memory);
76
77struct mem_info m68k_ramdisk;
78
79static char m68k_command_line[CL_SIZE];
80
81void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
82/* machine dependent irq functions */
83void (*mach_init_IRQ) (void) __initdata = NULL;
84void (*mach_get_model) (char *model);
85void (*mach_get_hardware_list) (struct seq_file *m);
86/* machine dependent timer functions */
87unsigned long (*mach_gettimeoffset) (void);
88int (*mach_hwclk) (int, struct rtc_time*);
89EXPORT_SYMBOL(mach_hwclk);
90int (*mach_set_clock_mmss) (unsigned long);
91unsigned int (*mach_get_ss)(void);
92int (*mach_get_rtc_pll)(struct rtc_pll_info *);
93int (*mach_set_rtc_pll)(struct rtc_pll_info *);
94EXPORT_SYMBOL(mach_get_ss);
95EXPORT_SYMBOL(mach_get_rtc_pll);
96EXPORT_SYMBOL(mach_set_rtc_pll);
97void (*mach_reset)( void );
98void (*mach_halt)( void );
99void (*mach_power_off)( void );
100long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
101#ifdef CONFIG_HEARTBEAT
102void (*mach_heartbeat) (int);
103EXPORT_SYMBOL(mach_heartbeat);
104#endif
105#ifdef CONFIG_M68K_L2_CACHE
106void (*mach_l2_flush) (int);
107#endif
108#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
109void (*mach_beep)(unsigned int, unsigned int);
110EXPORT_SYMBOL(mach_beep);
111#endif
112#if defined(CONFIG_ISA) && defined(MULTI_ISA)
113int isa_type;
114int isa_sex;
115EXPORT_SYMBOL(isa_type);
116EXPORT_SYMBOL(isa_sex);
117#endif
118
119extern int amiga_parse_bootinfo(const struct bi_record *);
120extern int atari_parse_bootinfo(const struct bi_record *);
121extern int mac_parse_bootinfo(const struct bi_record *);
122extern int q40_parse_bootinfo(const struct bi_record *);
123extern int bvme6000_parse_bootinfo(const struct bi_record *);
124extern int mvme16x_parse_bootinfo(const struct bi_record *);
125extern int mvme147_parse_bootinfo(const struct bi_record *);
126extern int hp300_parse_bootinfo(const struct bi_record *);
127extern int apollo_parse_bootinfo(const struct bi_record *);
128
129extern void config_amiga(void);
130extern void config_atari(void);
131extern void config_mac(void);
132extern void config_sun3(void);
133extern void config_apollo(void);
134extern void config_mvme147(void);
135extern void config_mvme16x(void);
136extern void config_bvme6000(void);
137extern void config_hp300(void);
138extern void config_q40(void);
139extern void config_sun3x(void);
140
141#define MASK_256K 0xfffc0000
142
143extern void paging_init(void);
144
145static void __init m68k_parse_bootinfo(const struct bi_record *record)
146{
147 while (record->tag != BI_LAST) {
148 int unknown = 0;
149 const unsigned long *data = record->data;
150
151 switch (record->tag) {
152 case BI_MACHTYPE:
153 case BI_CPUTYPE:
154 case BI_FPUTYPE:
155 case BI_MMUTYPE:
156 /* Already set up by head.S */
157 break;
158
159 case BI_MEMCHUNK:
160 if (m68k_num_memory < NUM_MEMINFO) {
161 m68k_memory[m68k_num_memory].addr = data[0];
162 m68k_memory[m68k_num_memory].size = data[1];
163 m68k_num_memory++;
164 } else
165 printk("m68k_parse_bootinfo: too many memory chunks\n");
166 break;
167
168 case BI_RAMDISK:
169 m68k_ramdisk.addr = data[0];
170 m68k_ramdisk.size = data[1];
171 break;
172
173 case BI_COMMAND_LINE:
174 strlcpy(m68k_command_line, (const char *)data,
175 sizeof(m68k_command_line));
176 break;
177
178 default:
179 if (MACH_IS_AMIGA)
180 unknown = amiga_parse_bootinfo(record);
181 else if (MACH_IS_ATARI)
182 unknown = atari_parse_bootinfo(record);
183 else if (MACH_IS_MAC)
184 unknown = mac_parse_bootinfo(record);
185 else if (MACH_IS_Q40)
186 unknown = q40_parse_bootinfo(record);
187 else if (MACH_IS_BVME6000)
188 unknown = bvme6000_parse_bootinfo(record);
189 else if (MACH_IS_MVME16x)
190 unknown = mvme16x_parse_bootinfo(record);
191 else if (MACH_IS_MVME147)
192 unknown = mvme147_parse_bootinfo(record);
193 else if (MACH_IS_HP300)
194 unknown = hp300_parse_bootinfo(record);
195 else if (MACH_IS_APOLLO)
196 unknown = apollo_parse_bootinfo(record);
197 else
198 unknown = 1;
199 }
200 if (unknown)
201 printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
202 record->tag);
203 record = (struct bi_record *)((unsigned long)record +
204 record->size);
205 }
206
207 m68k_realnum_memory = m68k_num_memory;
208#ifdef CONFIG_SINGLE_MEMORY_CHUNK
209 if (m68k_num_memory > 1) {
210 printk("Ignoring last %i chunks of physical memory\n",
211 (m68k_num_memory - 1));
212 m68k_num_memory = 1;
213 }
214#endif
215}
216
217void __init setup_arch(char **cmdline_p)
218{
219 int i;
220
221 /* The bootinfo is located right after the kernel bss */
222 m68k_parse_bootinfo((const struct bi_record *)_end);
223
224 if (CPU_IS_040)
225 m68k_is040or060 = 4;
226 else if (CPU_IS_060)
227 m68k_is040or060 = 6;
228
229 /* FIXME: m68k_fputype is passed in by Penguin booter, which can
230 * be confused by software FPU emulation. BEWARE.
231 * We should really do our own FPU check at startup.
232 * [what do we do with buggy 68LC040s? if we have problems
233 * with them, we should add a test to check_bugs() below] */
234#ifndef CONFIG_M68KFPU_EMU_ONLY
235 /* clear the fpu if we have one */
236 if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
237 volatile int zero = 0;
238 asm volatile ("frestore %0" : : "m" (zero));
239 }
240#endif
241
242 if (CPU_IS_060) {
243 u32 pcr;
244
245 asm (".chip 68060; movec %%pcr,%0; .chip 68k"
246 : "=d" (pcr));
247 if (((pcr >> 8) & 0xff) <= 5) {
248 printk("Enabling workaround for errata I14\n");
249 asm (".chip 68060; movec %0,%%pcr; .chip 68k"
250 : : "d" (pcr | 0x20));
251 }
252 }
253
254 init_mm.start_code = PAGE_OFFSET;
255 init_mm.end_code = (unsigned long)_etext;
256 init_mm.end_data = (unsigned long)_edata;
257 init_mm.brk = (unsigned long)_end;
258
259 *cmdline_p = m68k_command_line;
260 memcpy(boot_command_line, *cmdline_p, CL_SIZE);
261
262 parse_early_param();
263
264#ifdef CONFIG_DUMMY_CONSOLE
265 conswitchp = &dummy_con;
266#endif
267
268 switch (m68k_machtype) {
269#ifdef CONFIG_AMIGA
270 case MACH_AMIGA:
271 config_amiga();
272 break;
273#endif
274#ifdef CONFIG_ATARI
275 case MACH_ATARI:
276 config_atari();
277 break;
278#endif
279#ifdef CONFIG_MAC
280 case MACH_MAC:
281 config_mac();
282 break;
283#endif
284#ifdef CONFIG_SUN3
285 case MACH_SUN3:
286 config_sun3();
287 break;
288#endif
289#ifdef CONFIG_APOLLO
290 case MACH_APOLLO:
291 config_apollo();
292 break;
293#endif
294#ifdef CONFIG_MVME147
295 case MACH_MVME147:
296 config_mvme147();
297 break;
298#endif
299#ifdef CONFIG_MVME16x
300 case MACH_MVME16x:
301 config_mvme16x();
302 break;
303#endif
304#ifdef CONFIG_BVME6000
305 case MACH_BVME6000:
306 config_bvme6000();
307 break;
308#endif
309#ifdef CONFIG_HP300
310 case MACH_HP300:
311 config_hp300();
312 break;
313#endif
314#ifdef CONFIG_Q40
315 case MACH_Q40:
316 config_q40();
317 break;
318#endif
319#ifdef CONFIG_SUN3X
320 case MACH_SUN3X:
321 config_sun3x();
322 break;
323#endif
324 default:
325 panic("No configuration setup");
326 }
327
328#ifdef CONFIG_NATFEAT
329 nf_init();
330#endif
331
332 paging_init();
333
334#ifndef CONFIG_SUN3
335 for (i = 1; i < m68k_num_memory; i++)
336 free_bootmem_node(NODE_DATA(i), m68k_memory[i].addr,
337 m68k_memory[i].size);
338#ifdef CONFIG_BLK_DEV_INITRD
339 if (m68k_ramdisk.size) {
340 reserve_bootmem_node(__virt_to_node(phys_to_virt(m68k_ramdisk.addr)),
341 m68k_ramdisk.addr, m68k_ramdisk.size,
342 BOOTMEM_DEFAULT);
343 initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
344 initrd_end = initrd_start + m68k_ramdisk.size;
345 printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
346 }
347#endif
348
349#ifdef CONFIG_ATARI
350 if (MACH_IS_ATARI)
351 atari_stram_reserve_pages((void *)availmem);
352#endif
353#ifdef CONFIG_SUN3X
354 if (MACH_IS_SUN3X) {
355 dvma_init();
356 }
357#endif
358
359#endif /* !CONFIG_SUN3 */
360
361/* set ISA defs early as possible */
362#if defined(CONFIG_ISA) && defined(MULTI_ISA)
363 if (MACH_IS_Q40) {
364 isa_type = ISA_TYPE_Q40;
365 isa_sex = 0;
366 }
367#ifdef CONFIG_AMIGA_PCMCIA
368 if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
369 isa_type = ISA_TYPE_AG;
370 isa_sex = 1;
371 }
372#endif
373#endif
374}
375
376static int show_cpuinfo(struct seq_file *m, void *v)
377{
378 const char *cpu, *mmu, *fpu;
379 unsigned long clockfreq, clockfactor;
380
381#define LOOP_CYCLES_68020 (8)
382#define LOOP_CYCLES_68030 (8)
383#define LOOP_CYCLES_68040 (3)
384#define LOOP_CYCLES_68060 (1)
385
386 if (CPU_IS_020) {
387 cpu = "68020";
388 clockfactor = LOOP_CYCLES_68020;
389 } else if (CPU_IS_030) {
390 cpu = "68030";
391 clockfactor = LOOP_CYCLES_68030;
392 } else if (CPU_IS_040) {
393 cpu = "68040";
394 clockfactor = LOOP_CYCLES_68040;
395 } else if (CPU_IS_060) {
396 cpu = "68060";
397 clockfactor = LOOP_CYCLES_68060;
398 } else {
399 cpu = "680x0";
400 clockfactor = 0;
401 }
402
403#ifdef CONFIG_M68KFPU_EMU_ONLY
404 fpu = "none(soft float)";
405#else
406 if (m68k_fputype & FPU_68881)
407 fpu = "68881";
408 else if (m68k_fputype & FPU_68882)
409 fpu = "68882";
410 else if (m68k_fputype & FPU_68040)
411 fpu = "68040";
412 else if (m68k_fputype & FPU_68060)
413 fpu = "68060";
414 else if (m68k_fputype & FPU_SUNFPA)
415 fpu = "Sun FPA";
416 else
417 fpu = "none";
418#endif
419
420 if (m68k_mmutype & MMU_68851)
421 mmu = "68851";
422 else if (m68k_mmutype & MMU_68030)
423 mmu = "68030";
424 else if (m68k_mmutype & MMU_68040)
425 mmu = "68040";
426 else if (m68k_mmutype & MMU_68060)
427 mmu = "68060";
428 else if (m68k_mmutype & MMU_SUN3)
429 mmu = "Sun-3";
430 else if (m68k_mmutype & MMU_APOLLO)
431 mmu = "Apollo";
432 else
433 mmu = "unknown";
434
435 clockfreq = loops_per_jiffy * HZ * clockfactor;
436
437 seq_printf(m, "CPU:\t\t%s\n"
438 "MMU:\t\t%s\n"
439 "FPU:\t\t%s\n"
440 "Clocking:\t%lu.%1luMHz\n"
441 "BogoMips:\t%lu.%02lu\n"
442 "Calibration:\t%lu loops\n",
443 cpu, mmu, fpu,
444 clockfreq/1000000,(clockfreq/100000)%10,
445 loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
446 loops_per_jiffy);
447 return 0;
448}
449
450static void *c_start(struct seq_file *m, loff_t *pos)
451{
452 return *pos < 1 ? (void *)1 : NULL;
453}
454static void *c_next(struct seq_file *m, void *v, loff_t *pos)
455{
456 ++*pos;
457 return NULL;
458}
459static void c_stop(struct seq_file *m, void *v)
460{
461}
462const struct seq_operations cpuinfo_op = {
463 .start = c_start,
464 .next = c_next,
465 .stop = c_stop,
466 .show = show_cpuinfo,
467};
468
469#ifdef CONFIG_PROC_HARDWARE
470static int hardware_proc_show(struct seq_file *m, void *v)
471{
472 char model[80];
473 unsigned long mem;
474 int i;
475
476 if (mach_get_model)
477 mach_get_model(model);
478 else
479 strcpy(model, "Unknown m68k");
480
481 seq_printf(m, "Model:\t\t%s\n", model);
482 for (mem = 0, i = 0; i < m68k_num_memory; i++)
483 mem += m68k_memory[i].size;
484 seq_printf(m, "System Memory:\t%ldK\n", mem >> 10);
485
486 if (mach_get_hardware_list)
487 mach_get_hardware_list(m);
488
489 return 0;
490}
491
492static int hardware_proc_open(struct inode *inode, struct file *file)
493{
494 return single_open(file, hardware_proc_show, NULL);
495}
496
497static const struct file_operations hardware_proc_fops = {
498 .open = hardware_proc_open,
499 .read = seq_read,
500 .llseek = seq_lseek,
501 .release = single_release,
502};
503
504static int __init proc_hardware_init(void)
505{
506 proc_create("hardware", 0, NULL, &hardware_proc_fops);
507 return 0;
508}
509module_init(proc_hardware_init);
510#endif
511
512void check_bugs(void)
513{
514#ifndef CONFIG_M68KFPU_EMU
515 if (m68k_fputype == 0) {
516 printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
517 "WHICH IS REQUIRED BY LINUX/M68K ***\n");
518 printk(KERN_EMERG "Upgrade your hardware or join the FPU "
519 "emulation project\n");
520 panic("no FPU");
521 }
522#endif /* !CONFIG_M68KFPU_EMU */
523}
524
525#ifdef CONFIG_ADB
526static int __init adb_probe_sync_enable (char *str) {
527 extern int __adb_probe_sync;
528 __adb_probe_sync = 1;
529 return 1;
530}
531
532__setup("adb_sync", adb_probe_sync_enable);
533#endif /* CONFIG_ADB */
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
new file mode 100644
index 000000000000..16b2de7f5101
--- /dev/null
+++ b/arch/m68k/kernel/setup_no.c
@@ -0,0 +1,317 @@
1/*
2 * linux/arch/m68knommu/kernel/setup.c
3 *
4 * Copyright (C) 1999-2007 Greg Ungerer (gerg@snapgear.com)
5 * Copyright (C) 1998,1999 D. Jeff Dionne <jeff@uClinux.org>
6 * Copyleft ()) 2000 James D. Schettine {james@telos-systems.com}
7 * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
8 * Copyright (C) 1995 Hamish Macdonald
9 * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
10 * Copyright (C) 2001 Lineo, Inc. <www.lineo.com>
11 *
12 * 68VZ328 Fixes/support Evan Stawnyczy <e@lineo.ca>
13 */
14
15/*
16 * This file handles the architecture-dependent parts of system setup
17 */
18
19#include <linux/kernel.h>
20#include <linux/sched.h>
21#include <linux/delay.h>
22#include <linux/interrupt.h>
23#include <linux/fb.h>
24#include <linux/module.h>
25#include <linux/mm.h>
26#include <linux/console.h>
27#include <linux/errno.h>
28#include <linux/string.h>
29#include <linux/bootmem.h>
30#include <linux/seq_file.h>
31#include <linux/init.h>
32#include <linux/initrd.h>
33#include <linux/root_dev.h>
34
35#include <asm/setup.h>
36#include <asm/irq.h>
37#include <asm/machdep.h>
38#include <asm/pgtable.h>
39
40unsigned long memory_start;
41unsigned long memory_end;
42
43EXPORT_SYMBOL(memory_start);
44EXPORT_SYMBOL(memory_end);
45
46char __initdata command_line[COMMAND_LINE_SIZE];
47
48/* machine dependent timer functions */
49void (*mach_gettod)(int*, int*, int*, int*, int*, int*);
50int (*mach_set_clock_mmss)(unsigned long);
51
52/* machine dependent reboot functions */
53void (*mach_reset)(void);
54void (*mach_halt)(void);
55void (*mach_power_off)(void);
56
57#ifdef CONFIG_M68328
58#define CPU_NAME "MC68328"
59#endif
60#ifdef CONFIG_M68EZ328
61#define CPU_NAME "MC68EZ328"
62#endif
63#ifdef CONFIG_M68VZ328
64#define CPU_NAME "MC68VZ328"
65#endif
66#ifdef CONFIG_M68360
67#define CPU_NAME "MC68360"
68#endif
69#ifndef CPU_NAME
70#define CPU_NAME "UNKNOWN"
71#endif
72
73/*
74 * Different cores have different instruction execution timings.
75 * The old/traditional 68000 cores are basically all the same, at 16.
76 * The ColdFire cores vary a little, their values are defined in their
77 * headers. We default to the standard 68000 value here.
78 */
79#ifndef CPU_INSTR_PER_JIFFY
80#define CPU_INSTR_PER_JIFFY 16
81#endif
82
83extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
84extern int _ramstart, _ramend;
85
86#if defined(CONFIG_UBOOT)
87/*
88 * parse_uboot_commandline
89 *
90 * Copies u-boot commandline arguments and store them in the proper linux
91 * variables.
92 *
93 * Assumes:
94 * _init_sp global contains the address in the stack pointer when the
95 * kernel starts (see head.S::_start)
96 *
97 * U-Boot calling convention:
98 * (*kernel) (kbd, initrd_start, initrd_end, cmd_start, cmd_end);
99 *
100 * _init_sp can be parsed as such
101 *
102 * _init_sp+00 = u-boot cmd after jsr into kernel (skip)
103 * _init_sp+04 = &kernel board_info (residual data)
104 * _init_sp+08 = &initrd_start
105 * _init_sp+12 = &initrd_end
106 * _init_sp+16 = &cmd_start
107 * _init_sp+20 = &cmd_end
108 *
109 * This also assumes that the memory locations pointed to are still
110 * unmodified. U-boot places them near the end of external SDRAM.
111 *
112 * Argument(s):
113 * commandp = the linux commandline arg container to fill.
114 * size = the sizeof commandp.
115 *
116 * Returns:
117 */
118void parse_uboot_commandline(char *commandp, int size)
119{
120 extern unsigned long _init_sp;
121 unsigned long *sp;
122 unsigned long uboot_kbd;
123 unsigned long uboot_initrd_start, uboot_initrd_end;
124 unsigned long uboot_cmd_start, uboot_cmd_end;
125
126
127 sp = (unsigned long *)_init_sp;
128 uboot_kbd = sp[1];
129 uboot_initrd_start = sp[2];
130 uboot_initrd_end = sp[3];
131 uboot_cmd_start = sp[4];
132 uboot_cmd_end = sp[5];
133
134 if (uboot_cmd_start && uboot_cmd_end)
135 strncpy(commandp, (const char *)uboot_cmd_start, size);
136#if defined(CONFIG_BLK_DEV_INITRD)
137 if (uboot_initrd_start && uboot_initrd_end &&
138 (uboot_initrd_end > uboot_initrd_start)) {
139 initrd_start = uboot_initrd_start;
140 initrd_end = uboot_initrd_end;
141 ROOT_DEV = Root_RAM0;
142 printk(KERN_INFO "initrd at 0x%lx:0x%lx\n",
143 initrd_start, initrd_end);
144 }
145#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
146}
147#endif /* #if defined(CONFIG_UBOOT) */
148
149void __init setup_arch(char **cmdline_p)
150{
151 int bootmap_size;
152
153 memory_start = PAGE_ALIGN(_ramstart);
154 memory_end = _ramend;
155
156 init_mm.start_code = (unsigned long) &_stext;
157 init_mm.end_code = (unsigned long) &_etext;
158 init_mm.end_data = (unsigned long) &_edata;
159 init_mm.brk = (unsigned long) 0;
160
161 config_BSP(&command_line[0], sizeof(command_line));
162
163#if defined(CONFIG_BOOTPARAM)
164 strncpy(&command_line[0], CONFIG_BOOTPARAM_STRING, sizeof(command_line));
165 command_line[sizeof(command_line) - 1] = 0;
166#endif /* CONFIG_BOOTPARAM */
167
168#if defined(CONFIG_UBOOT)
169 /* CONFIG_UBOOT and CONFIG_BOOTPARAM defined, concatenate cmdline */
170 #if defined(CONFIG_BOOTPARAM)
171 /* Add the whitespace separator */
172 command_line[strlen(CONFIG_BOOTPARAM_STRING)] = ' ';
173 /* Parse uboot command line into the rest of the buffer */
174 parse_uboot_commandline(
175 &command_line[(strlen(CONFIG_BOOTPARAM_STRING)+1)],
176 (sizeof(command_line) -
177 (strlen(CONFIG_BOOTPARAM_STRING)+1)));
178 /* Only CONFIG_UBOOT defined, create cmdline */
179 #else
180 parse_uboot_commandline(&command_line[0], sizeof(command_line));
181 #endif /* CONFIG_BOOTPARAM */
182 command_line[sizeof(command_line) - 1] = 0;
183#endif /* CONFIG_UBOOT */
184
185 printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU_NAME "\n");
186
187#ifdef CONFIG_UCDIMM
188 printk(KERN_INFO "uCdimm by Lineo, Inc. <www.lineo.com>\n");
189#endif
190#ifdef CONFIG_M68VZ328
191 printk(KERN_INFO "M68VZ328 support by Evan Stawnyczy <e@lineo.ca>\n");
192#endif
193#ifdef CONFIG_COLDFIRE
194 printk(KERN_INFO "COLDFIRE port done by Greg Ungerer, gerg@snapgear.com\n");
195#ifdef CONFIG_M5307
196 printk(KERN_INFO "Modified for M5307 by Dave Miller, dmiller@intellistor.com\n");
197#endif
198#ifdef CONFIG_ELITE
199 printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n");
200#endif
201#endif
202 printk(KERN_INFO "Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n");
203
204#if defined( CONFIG_PILOT ) && defined( CONFIG_M68328 )
205 printk(KERN_INFO "TRG SuperPilot FLASH card support <info@trgnet.com>\n");
206#endif
207#if defined( CONFIG_PILOT ) && defined( CONFIG_M68EZ328 )
208 printk(KERN_INFO "PalmV support by Lineo Inc. <jeff@uclinux.com>\n");
209#endif
210#if defined (CONFIG_M68360)
211 printk(KERN_INFO "QUICC port done by SED Systems <hamilton@sedsystems.ca>,\n");
212 printk(KERN_INFO "based on 2.0.38 port by Lineo Inc. <mleslie@lineo.com>.\n");
213#endif
214#ifdef CONFIG_DRAGEN2
215 printk(KERN_INFO "DragonEngine II board support by Georges Menie\n");
216#endif
217#ifdef CONFIG_M5235EVB
218 printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
219#endif
220
221 pr_debug("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
222 "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
223 (int) &_sdata, (int) &_edata,
224 (int) &_sbss, (int) &_ebss);
225 pr_debug("MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
226 (int) &_ebss, (int) memory_start,
227 (int) memory_start, (int) memory_end);
228
229 /* Keep a copy of command line */
230 *cmdline_p = &command_line[0];
231 memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
232 boot_command_line[COMMAND_LINE_SIZE-1] = 0;
233
234#if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE)
235 conswitchp = &dummy_con;
236#endif
237
238 /*
239 * Give all the memory to the bootmap allocator, tell it to put the
240 * boot mem_map at the start of memory.
241 */
242 bootmap_size = init_bootmem_node(
243 NODE_DATA(0),
244 memory_start >> PAGE_SHIFT, /* map goes here */
245 PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */
246 memory_end >> PAGE_SHIFT);
247 /*
248 * Free the usable memory, we have to make sure we do not free
249 * the bootmem bitmap so we then reserve it after freeing it :-)
250 */
251 free_bootmem(memory_start, memory_end - memory_start);
252 reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
253
254#if defined(CONFIG_UBOOT) && defined(CONFIG_BLK_DEV_INITRD)
255 if ((initrd_start > 0) && (initrd_start < initrd_end) &&
256 (initrd_end < memory_end))
257 reserve_bootmem(initrd_start, initrd_end - initrd_start,
258 BOOTMEM_DEFAULT);
259#endif /* if defined(CONFIG_BLK_DEV_INITRD) */
260
261 /*
262 * Get kmalloc into gear.
263 */
264 paging_init();
265}
266
267/*
268 * Get CPU information for use by the procfs.
269 */
270static int show_cpuinfo(struct seq_file *m, void *v)
271{
272 char *cpu, *mmu, *fpu;
273 u_long clockfreq;
274
275 cpu = CPU_NAME;
276 mmu = "none";
277 fpu = "none";
278 clockfreq = (loops_per_jiffy * HZ) * CPU_INSTR_PER_JIFFY;
279
280 seq_printf(m, "CPU:\t\t%s\n"
281 "MMU:\t\t%s\n"
282 "FPU:\t\t%s\n"
283 "Clocking:\t%lu.%1luMHz\n"
284 "BogoMips:\t%lu.%02lu\n"
285 "Calibration:\t%lu loops\n",
286 cpu, mmu, fpu,
287 clockfreq / 1000000,
288 (clockfreq / 100000) % 10,
289 (loops_per_jiffy * HZ) / 500000,
290 ((loops_per_jiffy * HZ) / 5000) % 100,
291 (loops_per_jiffy * HZ));
292
293 return 0;
294}
295
296static void *c_start(struct seq_file *m, loff_t *pos)
297{
298 return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL;
299}
300
301static void *c_next(struct seq_file *m, void *v, loff_t *pos)
302{
303 ++*pos;
304 return c_start(m, pos);
305}
306
307static void c_stop(struct seq_file *m, void *v)
308{
309}
310
311const struct seq_operations cpuinfo_op = {
312 .start = c_start,
313 .next = c_next,
314 .stop = c_stop,
315 .show = show_cpuinfo,
316};
317
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 4b387538706f..2e25713e2ead 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -1,1047 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * linux/arch/m68k/kernel/signal.c 2#include "signal_mm.c"
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11/*
12 * Linux/m68k support by Hamish Macdonald
13 *
14 * 68060 fixes by Jesper Skov
15 *
16 * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
17 *
18 * mathemu support by Roman Zippel
19 * (Note: fpstate in the signal context is completely ignored for the emulator
20 * and the internal floating point format is put on stack)
21 */
22
23/*
24 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
25 * Atari :-) Current limitation: Only one sigstack can be active at one time.
26 * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
27 * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
28 * signal handlers!
29 */
30
31#include <linux/sched.h>
32#include <linux/mm.h>
33#include <linux/kernel.h>
34#include <linux/signal.h>
35#include <linux/syscalls.h>
36#include <linux/errno.h>
37#include <linux/wait.h>
38#include <linux/ptrace.h>
39#include <linux/unistd.h>
40#include <linux/stddef.h>
41#include <linux/highuid.h>
42#include <linux/personality.h>
43#include <linux/tty.h>
44#include <linux/binfmts.h>
45
46#include <asm/setup.h>
47#include <asm/uaccess.h>
48#include <asm/pgtable.h>
49#include <asm/traps.h>
50#include <asm/ucontext.h>
51
52#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
53
54asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
55
56const int frame_extra_sizes[16] = {
57 [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */
58 [2] = sizeof(((struct frame *)0)->un.fmt2),
59 [3] = sizeof(((struct frame *)0)->un.fmt3),
60 [4] = sizeof(((struct frame *)0)->un.fmt4),
61 [5] = -1, /* sizeof(((struct frame *)0)->un.fmt5), */
62 [6] = -1, /* sizeof(((struct frame *)0)->un.fmt6), */
63 [7] = sizeof(((struct frame *)0)->un.fmt7),
64 [8] = -1, /* sizeof(((struct frame *)0)->un.fmt8), */
65 [9] = sizeof(((struct frame *)0)->un.fmt9),
66 [10] = sizeof(((struct frame *)0)->un.fmta),
67 [11] = sizeof(((struct frame *)0)->un.fmtb),
68 [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */
69 [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */
70 [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */
71 [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */
72};
73
74/*
75 * Atomically swap in the new signal mask, and wait for a signal.
76 */
77asmlinkage int do_sigsuspend(struct pt_regs *regs)
78{
79 old_sigset_t mask = regs->d3;
80 sigset_t saveset;
81
82 mask &= _BLOCKABLE;
83 saveset = current->blocked;
84 siginitset(&current->blocked, mask);
85 recalc_sigpending();
86
87 regs->d0 = -EINTR;
88 while (1) {
89 current->state = TASK_INTERRUPTIBLE;
90 schedule();
91 if (do_signal(&saveset, regs))
92 return -EINTR;
93 }
94}
95
96asmlinkage int
97do_rt_sigsuspend(struct pt_regs *regs)
98{
99 sigset_t __user *unewset = (sigset_t __user *)regs->d1;
100 size_t sigsetsize = (size_t)regs->d2;
101 sigset_t saveset, newset;
102
103 /* XXX: Don't preclude handling different sized sigset_t's. */
104 if (sigsetsize != sizeof(sigset_t))
105 return -EINVAL;
106
107 if (copy_from_user(&newset, unewset, sizeof(newset)))
108 return -EFAULT;
109 sigdelsetmask(&newset, ~_BLOCKABLE);
110
111 saveset = current->blocked;
112 current->blocked = newset;
113 recalc_sigpending();
114
115 regs->d0 = -EINTR;
116 while (1) {
117 current->state = TASK_INTERRUPTIBLE;
118 schedule();
119 if (do_signal(&saveset, regs))
120 return -EINTR;
121 }
122}
123
124asmlinkage int
125sys_sigaction(int sig, const struct old_sigaction __user *act,
126 struct old_sigaction __user *oact)
127{
128 struct k_sigaction new_ka, old_ka;
129 int ret;
130
131 if (act) {
132 old_sigset_t mask;
133 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
134 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
135 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
136 return -EFAULT;
137 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
138 __get_user(mask, &act->sa_mask);
139 siginitset(&new_ka.sa.sa_mask, mask);
140 }
141
142 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
143
144 if (!ret && oact) {
145 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
146 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
147 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
148 return -EFAULT;
149 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
150 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
151 }
152
153 return ret;
154}
155
156asmlinkage int
157sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
158{
159 return do_sigaltstack(uss, uoss, rdusp());
160}
161
162
163/*
164 * Do a signal return; undo the signal stack.
165 *
166 * Keep the return code on the stack quadword aligned!
167 * That makes the cache flush below easier.
168 */
169
170struct sigframe
171{
172 char __user *pretcode;
173 int sig;
174 int code;
175 struct sigcontext __user *psc;
176 char retcode[8];
177 unsigned long extramask[_NSIG_WORDS-1];
178 struct sigcontext sc;
179};
180
181struct rt_sigframe
182{
183 char __user *pretcode;
184 int sig;
185 struct siginfo __user *pinfo;
186 void __user *puc;
187 char retcode[8];
188 struct siginfo info;
189 struct ucontext uc;
190};
191
192
193static unsigned char fpu_version; /* version number of fpu, set by setup_frame */
194
195static inline int restore_fpu_state(struct sigcontext *sc)
196{
197 int err = 1;
198
199 if (FPU_IS_EMU) {
200 /* restore registers */
201 memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
202 memcpy(current->thread.fp, sc->sc_fpregs, 24);
203 return 0;
204 }
205
206 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
207 /* Verify the frame format. */
208 if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
209 goto out;
210 if (CPU_IS_020_OR_030) {
211 if (m68k_fputype & FPU_68881 &&
212 !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
213 goto out;
214 if (m68k_fputype & FPU_68882 &&
215 !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
216 goto out;
217 } else if (CPU_IS_040) {
218 if (!(sc->sc_fpstate[1] == 0x00 ||
219 sc->sc_fpstate[1] == 0x28 ||
220 sc->sc_fpstate[1] == 0x60))
221 goto out;
222 } else if (CPU_IS_060) {
223 if (!(sc->sc_fpstate[3] == 0x00 ||
224 sc->sc_fpstate[3] == 0x60 ||
225 sc->sc_fpstate[3] == 0xe0))
226 goto out;
227 } else
228 goto out;
229
230 __asm__ volatile (".chip 68k/68881\n\t"
231 "fmovemx %0,%%fp0-%%fp1\n\t"
232 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
233 ".chip 68k"
234 : /* no outputs */
235 : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
236 }
237 __asm__ volatile (".chip 68k/68881\n\t"
238 "frestore %0\n\t"
239 ".chip 68k" : : "m" (*sc->sc_fpstate));
240 err = 0;
241
242out:
243 return err;
244}
245
246#define FPCONTEXT_SIZE 216
247#define uc_fpstate uc_filler[0]
248#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
249#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
250
251static inline int rt_restore_fpu_state(struct ucontext __user *uc)
252{
253 unsigned char fpstate[FPCONTEXT_SIZE];
254 int context_size = CPU_IS_060 ? 8 : 0;
255 fpregset_t fpregs;
256 int err = 1;
257
258 if (FPU_IS_EMU) {
259 /* restore fpu control register */
260 if (__copy_from_user(current->thread.fpcntl,
261 uc->uc_mcontext.fpregs.f_fpcntl, 12))
262 goto out;
263 /* restore all other fpu register */
264 if (__copy_from_user(current->thread.fp,
265 uc->uc_mcontext.fpregs.f_fpregs, 96))
266 goto out;
267 return 0;
268 }
269
270 if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
271 goto out;
272 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
273 if (!CPU_IS_060)
274 context_size = fpstate[1];
275 /* Verify the frame format. */
276 if (!CPU_IS_060 && (fpstate[0] != fpu_version))
277 goto out;
278 if (CPU_IS_020_OR_030) {
279 if (m68k_fputype & FPU_68881 &&
280 !(context_size == 0x18 || context_size == 0xb4))
281 goto out;
282 if (m68k_fputype & FPU_68882 &&
283 !(context_size == 0x38 || context_size == 0xd4))
284 goto out;
285 } else if (CPU_IS_040) {
286 if (!(context_size == 0x00 ||
287 context_size == 0x28 ||
288 context_size == 0x60))
289 goto out;
290 } else if (CPU_IS_060) {
291 if (!(fpstate[3] == 0x00 ||
292 fpstate[3] == 0x60 ||
293 fpstate[3] == 0xe0))
294 goto out;
295 } else
296 goto out;
297 if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
298 sizeof(fpregs)))
299 goto out;
300 __asm__ volatile (".chip 68k/68881\n\t"
301 "fmovemx %0,%%fp0-%%fp7\n\t"
302 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
303 ".chip 68k"
304 : /* no outputs */
305 : "m" (*fpregs.f_fpregs),
306 "m" (*fpregs.f_fpcntl));
307 }
308 if (context_size &&
309 __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
310 context_size))
311 goto out;
312 __asm__ volatile (".chip 68k/68881\n\t"
313 "frestore %0\n\t"
314 ".chip 68k" : : "m" (*fpstate));
315 err = 0;
316
317out:
318 return err;
319}
320
321static inline int
322restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp,
323 int *pd0)
324{
325 int fsize, formatvec;
326 struct sigcontext context;
327 int err;
328
329 /* Always make any pending restarted system calls return -EINTR */
330 current_thread_info()->restart_block.fn = do_no_restart_syscall;
331
332 /* get previous context */
333 if (copy_from_user(&context, usc, sizeof(context)))
334 goto badframe;
335
336 /* restore passed registers */
337 regs->d1 = context.sc_d1;
338 regs->a0 = context.sc_a0;
339 regs->a1 = context.sc_a1;
340 regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
341 regs->pc = context.sc_pc;
342 regs->orig_d0 = -1; /* disable syscall checks */
343 wrusp(context.sc_usp);
344 formatvec = context.sc_formatvec;
345 regs->format = formatvec >> 12;
346 regs->vector = formatvec & 0xfff;
347
348 err = restore_fpu_state(&context);
349
350 fsize = frame_extra_sizes[regs->format];
351 if (fsize < 0) {
352 /*
353 * user process trying to return with weird frame format
354 */
355#ifdef DEBUG
356 printk("user process returning with weird frame format\n");
357#endif
358 goto badframe;
359 }
360
361 /* OK. Make room on the supervisor stack for the extra junk,
362 * if necessary.
363 */
364
365 if (fsize) {
366 struct switch_stack *sw = (struct switch_stack *)regs - 1;
367 regs->d0 = context.sc_d0;
368#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
369 __asm__ __volatile__
370 (" movel %0,%/a0\n\t"
371 " subl %1,%/a0\n\t" /* make room on stack */
372 " movel %/a0,%/sp\n\t" /* set stack pointer */
373 /* move switch_stack and pt_regs */
374 "1: movel %0@+,%/a0@+\n\t"
375 " dbra %2,1b\n\t"
376 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
377 " lsrl #2,%1\n\t"
378 " subql #1,%1\n\t"
379 "2: movesl %4@+,%2\n\t"
380 "3: movel %2,%/a0@+\n\t"
381 " dbra %1,2b\n\t"
382 " bral ret_from_signal\n"
383 "4:\n"
384 ".section __ex_table,\"a\"\n"
385 " .align 4\n"
386 " .long 2b,4b\n"
387 " .long 3b,4b\n"
388 ".previous"
389 : /* no outputs, it doesn't ever return */
390 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
391 "n" (frame_offset), "a" (fp)
392 : "a0");
393#undef frame_offset
394 /*
395 * If we ever get here an exception occurred while
396 * building the above stack-frame.
397 */
398 goto badframe;
399 }
400
401 *pd0 = context.sc_d0;
402 return err;
403
404badframe:
405 return 1;
406}
407
408static inline int
409rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
410 struct ucontext __user *uc, int *pd0)
411{
412 int fsize, temp;
413 greg_t __user *gregs = uc->uc_mcontext.gregs;
414 unsigned long usp;
415 int err;
416
417 /* Always make any pending restarted system calls return -EINTR */
418 current_thread_info()->restart_block.fn = do_no_restart_syscall;
419
420 err = __get_user(temp, &uc->uc_mcontext.version);
421 if (temp != MCONTEXT_VERSION)
422 goto badframe;
423 /* restore passed registers */
424 err |= __get_user(regs->d0, &gregs[0]);
425 err |= __get_user(regs->d1, &gregs[1]);
426 err |= __get_user(regs->d2, &gregs[2]);
427 err |= __get_user(regs->d3, &gregs[3]);
428 err |= __get_user(regs->d4, &gregs[4]);
429 err |= __get_user(regs->d5, &gregs[5]);
430 err |= __get_user(sw->d6, &gregs[6]);
431 err |= __get_user(sw->d7, &gregs[7]);
432 err |= __get_user(regs->a0, &gregs[8]);
433 err |= __get_user(regs->a1, &gregs[9]);
434 err |= __get_user(regs->a2, &gregs[10]);
435 err |= __get_user(sw->a3, &gregs[11]);
436 err |= __get_user(sw->a4, &gregs[12]);
437 err |= __get_user(sw->a5, &gregs[13]);
438 err |= __get_user(sw->a6, &gregs[14]);
439 err |= __get_user(usp, &gregs[15]);
440 wrusp(usp);
441 err |= __get_user(regs->pc, &gregs[16]);
442 err |= __get_user(temp, &gregs[17]);
443 regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
444 regs->orig_d0 = -1; /* disable syscall checks */
445 err |= __get_user(temp, &uc->uc_formatvec);
446 regs->format = temp >> 12;
447 regs->vector = temp & 0xfff;
448
449 err |= rt_restore_fpu_state(uc);
450
451 if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
452 goto badframe;
453
454 fsize = frame_extra_sizes[regs->format];
455 if (fsize < 0) {
456 /*
457 * user process trying to return with weird frame format
458 */
459#ifdef DEBUG
460 printk("user process returning with weird frame format\n");
461#endif
462 goto badframe;
463 }
464
465 /* OK. Make room on the supervisor stack for the extra junk,
466 * if necessary.
467 */
468
469 if (fsize) {
470#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
471 __asm__ __volatile__
472 (" movel %0,%/a0\n\t"
473 " subl %1,%/a0\n\t" /* make room on stack */
474 " movel %/a0,%/sp\n\t" /* set stack pointer */
475 /* move switch_stack and pt_regs */
476 "1: movel %0@+,%/a0@+\n\t"
477 " dbra %2,1b\n\t"
478 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
479 " lsrl #2,%1\n\t"
480 " subql #1,%1\n\t"
481 "2: movesl %4@+,%2\n\t"
482 "3: movel %2,%/a0@+\n\t"
483 " dbra %1,2b\n\t"
484 " bral ret_from_signal\n"
485 "4:\n"
486 ".section __ex_table,\"a\"\n"
487 " .align 4\n"
488 " .long 2b,4b\n"
489 " .long 3b,4b\n"
490 ".previous"
491 : /* no outputs, it doesn't ever return */
492 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
493 "n" (frame_offset), "a" (&uc->uc_extra)
494 : "a0");
495#undef frame_offset
496 /*
497 * If we ever get here an exception occurred while
498 * building the above stack-frame.
499 */
500 goto badframe;
501 }
502
503 *pd0 = regs->d0;
504 return err;
505
506badframe:
507 return 1;
508}
509
510asmlinkage int do_sigreturn(unsigned long __unused)
511{
512 struct switch_stack *sw = (struct switch_stack *) &__unused;
513 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
514 unsigned long usp = rdusp();
515 struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
516 sigset_t set;
517 int d0;
518
519 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
520 goto badframe;
521 if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
522 (_NSIG_WORDS > 1 &&
523 __copy_from_user(&set.sig[1], &frame->extramask,
524 sizeof(frame->extramask))))
525 goto badframe;
526
527 sigdelsetmask(&set, ~_BLOCKABLE);
528 current->blocked = set;
529 recalc_sigpending();
530
531 if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
532 goto badframe;
533 return d0;
534
535badframe:
536 force_sig(SIGSEGV, current);
537 return 0;
538}
539
540asmlinkage int do_rt_sigreturn(unsigned long __unused)
541{
542 struct switch_stack *sw = (struct switch_stack *) &__unused;
543 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
544 unsigned long usp = rdusp();
545 struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
546 sigset_t set;
547 int d0;
548
549 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
550 goto badframe;
551 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
552 goto badframe;
553
554 sigdelsetmask(&set, ~_BLOCKABLE);
555 current->blocked = set;
556 recalc_sigpending();
557
558 if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
559 goto badframe;
560 return d0;
561
562badframe:
563 force_sig(SIGSEGV, current);
564 return 0;
565}
566
567/*
568 * Set up a signal frame.
569 */
570
571static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
572{
573 if (FPU_IS_EMU) {
574 /* save registers */
575 memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
576 memcpy(sc->sc_fpregs, current->thread.fp, 24);
577 return;
578 }
579
580 __asm__ volatile (".chip 68k/68881\n\t"
581 "fsave %0\n\t"
582 ".chip 68k"
583 : : "m" (*sc->sc_fpstate) : "memory");
584
585 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
586 fpu_version = sc->sc_fpstate[0];
587 if (CPU_IS_020_OR_030 &&
588 regs->vector >= (VEC_FPBRUC * 4) &&
589 regs->vector <= (VEC_FPNAN * 4)) {
590 /* Clear pending exception in 68882 idle frame */
591 if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
592 sc->sc_fpstate[0x38] |= 1 << 3;
593 }
594 __asm__ volatile (".chip 68k/68881\n\t"
595 "fmovemx %%fp0-%%fp1,%0\n\t"
596 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
597 ".chip 68k"
598 : "=m" (*sc->sc_fpregs),
599 "=m" (*sc->sc_fpcntl)
600 : /* no inputs */
601 : "memory");
602 }
603}
604
605static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
606{
607 unsigned char fpstate[FPCONTEXT_SIZE];
608 int context_size = CPU_IS_060 ? 8 : 0;
609 int err = 0;
610
611 if (FPU_IS_EMU) {
612 /* save fpu control register */
613 err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
614 current->thread.fpcntl, 12);
615 /* save all other fpu register */
616 err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
617 current->thread.fp, 96);
618 return err;
619 }
620
621 __asm__ volatile (".chip 68k/68881\n\t"
622 "fsave %0\n\t"
623 ".chip 68k"
624 : : "m" (*fpstate) : "memory");
625
626 err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
627 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
628 fpregset_t fpregs;
629 if (!CPU_IS_060)
630 context_size = fpstate[1];
631 fpu_version = fpstate[0];
632 if (CPU_IS_020_OR_030 &&
633 regs->vector >= (VEC_FPBRUC * 4) &&
634 regs->vector <= (VEC_FPNAN * 4)) {
635 /* Clear pending exception in 68882 idle frame */
636 if (*(unsigned short *) fpstate == 0x1f38)
637 fpstate[0x38] |= 1 << 3;
638 }
639 __asm__ volatile (".chip 68k/68881\n\t"
640 "fmovemx %%fp0-%%fp7,%0\n\t"
641 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
642 ".chip 68k"
643 : "=m" (*fpregs.f_fpregs),
644 "=m" (*fpregs.f_fpcntl)
645 : /* no inputs */
646 : "memory");
647 err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
648 sizeof(fpregs));
649 }
650 if (context_size)
651 err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
652 context_size);
653 return err;
654}
655
656static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
657 unsigned long mask)
658{
659 sc->sc_mask = mask;
660 sc->sc_usp = rdusp();
661 sc->sc_d0 = regs->d0;
662 sc->sc_d1 = regs->d1;
663 sc->sc_a0 = regs->a0;
664 sc->sc_a1 = regs->a1;
665 sc->sc_sr = regs->sr;
666 sc->sc_pc = regs->pc;
667 sc->sc_formatvec = regs->format << 12 | regs->vector;
668 save_fpu_state(sc, regs);
669}
670
671static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
672{
673 struct switch_stack *sw = (struct switch_stack *)regs - 1;
674 greg_t __user *gregs = uc->uc_mcontext.gregs;
675 int err = 0;
676
677 err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
678 err |= __put_user(regs->d0, &gregs[0]);
679 err |= __put_user(regs->d1, &gregs[1]);
680 err |= __put_user(regs->d2, &gregs[2]);
681 err |= __put_user(regs->d3, &gregs[3]);
682 err |= __put_user(regs->d4, &gregs[4]);
683 err |= __put_user(regs->d5, &gregs[5]);
684 err |= __put_user(sw->d6, &gregs[6]);
685 err |= __put_user(sw->d7, &gregs[7]);
686 err |= __put_user(regs->a0, &gregs[8]);
687 err |= __put_user(regs->a1, &gregs[9]);
688 err |= __put_user(regs->a2, &gregs[10]);
689 err |= __put_user(sw->a3, &gregs[11]);
690 err |= __put_user(sw->a4, &gregs[12]);
691 err |= __put_user(sw->a5, &gregs[13]);
692 err |= __put_user(sw->a6, &gregs[14]);
693 err |= __put_user(rdusp(), &gregs[15]);
694 err |= __put_user(regs->pc, &gregs[16]);
695 err |= __put_user(regs->sr, &gregs[17]);
696 err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
697 err |= rt_save_fpu_state(uc, regs);
698 return err;
699}
700
701static inline void push_cache (unsigned long vaddr)
702{
703 /*
704 * Using the old cache_push_v() was really a big waste.
705 *
706 * What we are trying to do is to flush 8 bytes to ram.
707 * Flushing 2 cache lines of 16 bytes is much cheaper than
708 * flushing 1 or 2 pages, as previously done in
709 * cache_push_v().
710 * Jes
711 */
712 if (CPU_IS_040) {
713 unsigned long temp;
714
715 __asm__ __volatile__ (".chip 68040\n\t"
716 "nop\n\t"
717 "ptestr (%1)\n\t"
718 "movec %%mmusr,%0\n\t"
719 ".chip 68k"
720 : "=r" (temp)
721 : "a" (vaddr));
722
723 temp &= PAGE_MASK;
724 temp |= vaddr & ~PAGE_MASK;
725
726 __asm__ __volatile__ (".chip 68040\n\t"
727 "nop\n\t"
728 "cpushl %%bc,(%0)\n\t"
729 ".chip 68k"
730 : : "a" (temp));
731 }
732 else if (CPU_IS_060) {
733 unsigned long temp;
734 __asm__ __volatile__ (".chip 68060\n\t"
735 "plpar (%0)\n\t"
736 ".chip 68k"
737 : "=a" (temp)
738 : "0" (vaddr));
739 __asm__ __volatile__ (".chip 68060\n\t"
740 "cpushl %%bc,(%0)\n\t"
741 ".chip 68k"
742 : : "a" (temp));
743 }
744 else {
745 /*
746 * 68030/68020 have no writeback cache;
747 * still need to clear icache.
748 * Note that vaddr is guaranteed to be long word aligned.
749 */
750 unsigned long temp;
751 asm volatile ("movec %%cacr,%0" : "=r" (temp));
752 temp += 4;
753 asm volatile ("movec %0,%%caar\n\t"
754 "movec %1,%%cacr"
755 : : "r" (vaddr), "r" (temp));
756 asm volatile ("movec %0,%%caar\n\t"
757 "movec %1,%%cacr"
758 : : "r" (vaddr + 4), "r" (temp));
759 }
760}
761
762static inline void __user *
763get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
764{
765 unsigned long usp;
766
767 /* Default to using normal stack. */
768 usp = rdusp();
769
770 /* This is the X/Open sanctioned signal stack switching. */
771 if (ka->sa.sa_flags & SA_ONSTACK) {
772 if (!sas_ss_flags(usp))
773 usp = current->sas_ss_sp + current->sas_ss_size;
774 }
775 return (void __user *)((usp - frame_size) & -8UL);
776}
777
778static void setup_frame (int sig, struct k_sigaction *ka,
779 sigset_t *set, struct pt_regs *regs)
780{
781 struct sigframe __user *frame;
782 int fsize = frame_extra_sizes[regs->format];
783 struct sigcontext context;
784 int err = 0;
785
786 if (fsize < 0) {
787#ifdef DEBUG
788 printk ("setup_frame: Unknown frame format %#x\n",
789 regs->format);
790#endif
791 goto give_sigsegv;
792 }
793
794 frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
795
796 if (fsize) {
797 err |= copy_to_user (frame + 1, regs + 1, fsize);
798 regs->stkadj = fsize;
799 }
800
801 err |= __put_user((current_thread_info()->exec_domain
802 && current_thread_info()->exec_domain->signal_invmap
803 && sig < 32
804 ? current_thread_info()->exec_domain->signal_invmap[sig]
805 : sig),
806 &frame->sig);
807
808 err |= __put_user(regs->vector, &frame->code);
809 err |= __put_user(&frame->sc, &frame->psc);
810
811 if (_NSIG_WORDS > 1)
812 err |= copy_to_user(frame->extramask, &set->sig[1],
813 sizeof(frame->extramask));
814
815 setup_sigcontext(&context, regs, set->sig[0]);
816 err |= copy_to_user (&frame->sc, &context, sizeof(context));
817
818 /* Set up to return from userspace. */
819 err |= __put_user(frame->retcode, &frame->pretcode);
820 /* moveq #,d0; trap #0 */
821 err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
822 (long __user *)(frame->retcode));
823
824 if (err)
825 goto give_sigsegv;
826
827 push_cache ((unsigned long) &frame->retcode);
828
829 /* Set up registers for signal handler */
830 wrusp ((unsigned long) frame);
831 regs->pc = (unsigned long) ka->sa.sa_handler;
832
833adjust_stack:
834 /* Prepare to skip over the extra stuff in the exception frame. */
835 if (regs->stkadj) {
836 struct pt_regs *tregs =
837 (struct pt_regs *)((ulong)regs + regs->stkadj);
838#ifdef DEBUG
839 printk("Performing stackadjust=%04x\n", regs->stkadj);
840#endif
841 /* This must be copied with decreasing addresses to
842 handle overlaps. */
843 tregs->vector = 0;
844 tregs->format = 0;
845 tregs->pc = regs->pc;
846 tregs->sr = regs->sr;
847 }
848 return;
849
850give_sigsegv:
851 force_sigsegv(sig, current);
852 goto adjust_stack;
853}
854
855static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
856 sigset_t *set, struct pt_regs *regs)
857{
858 struct rt_sigframe __user *frame;
859 int fsize = frame_extra_sizes[regs->format];
860 int err = 0;
861
862 if (fsize < 0) {
863#ifdef DEBUG
864 printk ("setup_frame: Unknown frame format %#x\n",
865 regs->format);
866#endif
867 goto give_sigsegv;
868 }
869
870 frame = get_sigframe(ka, regs, sizeof(*frame));
871
872 if (fsize) {
873 err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
874 regs->stkadj = fsize;
875 }
876
877 err |= __put_user((current_thread_info()->exec_domain
878 && current_thread_info()->exec_domain->signal_invmap
879 && sig < 32
880 ? current_thread_info()->exec_domain->signal_invmap[sig]
881 : sig),
882 &frame->sig);
883 err |= __put_user(&frame->info, &frame->pinfo);
884 err |= __put_user(&frame->uc, &frame->puc);
885 err |= copy_siginfo_to_user(&frame->info, info);
886
887 /* Create the ucontext. */
888 err |= __put_user(0, &frame->uc.uc_flags);
889 err |= __put_user(NULL, &frame->uc.uc_link);
890 err |= __put_user((void __user *)current->sas_ss_sp,
891 &frame->uc.uc_stack.ss_sp);
892 err |= __put_user(sas_ss_flags(rdusp()),
893 &frame->uc.uc_stack.ss_flags);
894 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
895 err |= rt_setup_ucontext(&frame->uc, regs);
896 err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
897
898 /* Set up to return from userspace. */
899 err |= __put_user(frame->retcode, &frame->pretcode);
900#ifdef __mcoldfire__
901 /* movel #__NR_rt_sigreturn,d0; trap #0 */
902 err |= __put_user(0x203c0000, (long __user *)(frame->retcode + 0));
903 err |= __put_user(0x00004e40 + (__NR_rt_sigreturn << 16),
904 (long __user *)(frame->retcode + 4));
905#else 3#else
906 /* moveq #,d0; notb d0; trap #0 */ 4#include "signal_no.c"
907 err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
908 (long __user *)(frame->retcode + 0));
909 err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
910#endif
911
912 if (err)
913 goto give_sigsegv;
914
915 push_cache ((unsigned long) &frame->retcode);
916
917 /* Set up registers for signal handler */
918 wrusp ((unsigned long) frame);
919 regs->pc = (unsigned long) ka->sa.sa_handler;
920
921adjust_stack:
922 /* Prepare to skip over the extra stuff in the exception frame. */
923 if (regs->stkadj) {
924 struct pt_regs *tregs =
925 (struct pt_regs *)((ulong)regs + regs->stkadj);
926#ifdef DEBUG
927 printk("Performing stackadjust=%04x\n", regs->stkadj);
928#endif 5#endif
929 /* This must be copied with decreasing addresses to
930 handle overlaps. */
931 tregs->vector = 0;
932 tregs->format = 0;
933 tregs->pc = regs->pc;
934 tregs->sr = regs->sr;
935 }
936 return;
937
938give_sigsegv:
939 force_sigsegv(sig, current);
940 goto adjust_stack;
941}
942
943static inline void
944handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
945{
946 switch (regs->d0) {
947 case -ERESTARTNOHAND:
948 if (!has_handler)
949 goto do_restart;
950 regs->d0 = -EINTR;
951 break;
952
953 case -ERESTART_RESTARTBLOCK:
954 if (!has_handler) {
955 regs->d0 = __NR_restart_syscall;
956 regs->pc -= 2;
957 break;
958 }
959 regs->d0 = -EINTR;
960 break;
961
962 case -ERESTARTSYS:
963 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
964 regs->d0 = -EINTR;
965 break;
966 }
967 /* fallthrough */
968 case -ERESTARTNOINTR:
969 do_restart:
970 regs->d0 = regs->orig_d0;
971 regs->pc -= 2;
972 break;
973 }
974}
975
976void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
977{
978 if (regs->orig_d0 < 0)
979 return;
980 switch (regs->d0) {
981 case -ERESTARTNOHAND:
982 case -ERESTARTSYS:
983 case -ERESTARTNOINTR:
984 regs->d0 = regs->orig_d0;
985 regs->orig_d0 = -1;
986 regs->pc -= 2;
987 break;
988 }
989}
990
991/*
992 * OK, we're invoking a handler
993 */
994static void
995handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
996 sigset_t *oldset, struct pt_regs *regs)
997{
998 /* are we from a system call? */
999 if (regs->orig_d0 >= 0)
1000 /* If so, check system call restarting.. */
1001 handle_restart(regs, ka, 1);
1002
1003 /* set up the stack frame */
1004 if (ka->sa.sa_flags & SA_SIGINFO)
1005 setup_rt_frame(sig, ka, info, oldset, regs);
1006 else
1007 setup_frame(sig, ka, oldset, regs);
1008
1009 if (ka->sa.sa_flags & SA_ONESHOT)
1010 ka->sa.sa_handler = SIG_DFL;
1011
1012 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
1013 if (!(ka->sa.sa_flags & SA_NODEFER))
1014 sigaddset(&current->blocked,sig);
1015 recalc_sigpending();
1016}
1017
1018/*
1019 * Note that 'init' is a special process: it doesn't get signals it doesn't
1020 * want to handle. Thus you cannot kill init even with a SIGKILL even by
1021 * mistake.
1022 */
1023asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs)
1024{
1025 siginfo_t info;
1026 struct k_sigaction ka;
1027 int signr;
1028
1029 current->thread.esp0 = (unsigned long) regs;
1030
1031 if (!oldset)
1032 oldset = &current->blocked;
1033
1034 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
1035 if (signr > 0) {
1036 /* Whee! Actually deliver the signal. */
1037 handle_signal(signr, &ka, &info, oldset, regs);
1038 return 1;
1039 }
1040
1041 /* Did we come from a system call? */
1042 if (regs->orig_d0 >= 0)
1043 /* Restart the system call - no handlers present */
1044 handle_restart(regs, NULL, 0);
1045
1046 return 0;
1047}
diff --git a/arch/m68k/kernel/signal_mm.c b/arch/m68k/kernel/signal_mm.c
new file mode 100644
index 000000000000..a0afc239304e
--- /dev/null
+++ b/arch/m68k/kernel/signal_mm.c
@@ -0,0 +1,1017 @@
1/*
2 * linux/arch/m68k/kernel/signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11/*
12 * Linux/m68k support by Hamish Macdonald
13 *
14 * 68060 fixes by Jesper Skov
15 *
16 * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
17 *
18 * mathemu support by Roman Zippel
19 * (Note: fpstate in the signal context is completely ignored for the emulator
20 * and the internal floating point format is put on stack)
21 */
22
23/*
24 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
25 * Atari :-) Current limitation: Only one sigstack can be active at one time.
26 * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
27 * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
28 * signal handlers!
29 */
30
31#include <linux/sched.h>
32#include <linux/mm.h>
33#include <linux/kernel.h>
34#include <linux/signal.h>
35#include <linux/syscalls.h>
36#include <linux/errno.h>
37#include <linux/wait.h>
38#include <linux/ptrace.h>
39#include <linux/unistd.h>
40#include <linux/stddef.h>
41#include <linux/highuid.h>
42#include <linux/personality.h>
43#include <linux/tty.h>
44#include <linux/binfmts.h>
45#include <linux/module.h>
46
47#include <asm/setup.h>
48#include <asm/uaccess.h>
49#include <asm/pgtable.h>
50#include <asm/traps.h>
51#include <asm/ucontext.h>
52
53#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
54
55static const int frame_extra_sizes[16] = {
56 [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */
57 [2] = sizeof(((struct frame *)0)->un.fmt2),
58 [3] = sizeof(((struct frame *)0)->un.fmt3),
59 [4] = sizeof(((struct frame *)0)->un.fmt4),
60 [5] = -1, /* sizeof(((struct frame *)0)->un.fmt5), */
61 [6] = -1, /* sizeof(((struct frame *)0)->un.fmt6), */
62 [7] = sizeof(((struct frame *)0)->un.fmt7),
63 [8] = -1, /* sizeof(((struct frame *)0)->un.fmt8), */
64 [9] = sizeof(((struct frame *)0)->un.fmt9),
65 [10] = sizeof(((struct frame *)0)->un.fmta),
66 [11] = sizeof(((struct frame *)0)->un.fmtb),
67 [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */
68 [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */
69 [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */
70 [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */
71};
72
73int handle_kernel_fault(struct pt_regs *regs)
74{
75 const struct exception_table_entry *fixup;
76 struct pt_regs *tregs;
77
78 /* Are we prepared to handle this kernel fault? */
79 fixup = search_exception_tables(regs->pc);
80 if (!fixup)
81 return 0;
82
83 /* Create a new four word stack frame, discarding the old one. */
84 regs->stkadj = frame_extra_sizes[regs->format];
85 tregs = (struct pt_regs *)((long)regs + regs->stkadj);
86 tregs->vector = regs->vector;
87 tregs->format = 0;
88 tregs->pc = fixup->fixup;
89 tregs->sr = regs->sr;
90
91 return 1;
92}
93
94/*
95 * Atomically swap in the new signal mask, and wait for a signal.
96 */
97asmlinkage int
98sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
99{
100 mask &= _BLOCKABLE;
101 spin_lock_irq(&current->sighand->siglock);
102 current->saved_sigmask = current->blocked;
103 siginitset(&current->blocked, mask);
104 recalc_sigpending();
105 spin_unlock_irq(&current->sighand->siglock);
106
107 current->state = TASK_INTERRUPTIBLE;
108 schedule();
109 set_restore_sigmask();
110
111 return -ERESTARTNOHAND;
112}
113
114asmlinkage int
115sys_sigaction(int sig, const struct old_sigaction __user *act,
116 struct old_sigaction __user *oact)
117{
118 struct k_sigaction new_ka, old_ka;
119 int ret;
120
121 if (act) {
122 old_sigset_t mask;
123 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
124 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
125 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
126 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
127 __get_user(mask, &act->sa_mask))
128 return -EFAULT;
129 siginitset(&new_ka.sa.sa_mask, mask);
130 }
131
132 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
133
134 if (!ret && oact) {
135 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
136 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
137 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
138 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
139 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
140 return -EFAULT;
141 }
142
143 return ret;
144}
145
146asmlinkage int
147sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
148{
149 return do_sigaltstack(uss, uoss, rdusp());
150}
151
152
153/*
154 * Do a signal return; undo the signal stack.
155 *
156 * Keep the return code on the stack quadword aligned!
157 * That makes the cache flush below easier.
158 */
159
160struct sigframe
161{
162 char __user *pretcode;
163 int sig;
164 int code;
165 struct sigcontext __user *psc;
166 char retcode[8];
167 unsigned long extramask[_NSIG_WORDS-1];
168 struct sigcontext sc;
169};
170
171struct rt_sigframe
172{
173 char __user *pretcode;
174 int sig;
175 struct siginfo __user *pinfo;
176 void __user *puc;
177 char retcode[8];
178 struct siginfo info;
179 struct ucontext uc;
180};
181
182
183static unsigned char fpu_version; /* version number of fpu, set by setup_frame */
184
185static inline int restore_fpu_state(struct sigcontext *sc)
186{
187 int err = 1;
188
189 if (FPU_IS_EMU) {
190 /* restore registers */
191 memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
192 memcpy(current->thread.fp, sc->sc_fpregs, 24);
193 return 0;
194 }
195
196 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
197 /* Verify the frame format. */
198 if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version))
199 goto out;
200 if (CPU_IS_020_OR_030) {
201 if (m68k_fputype & FPU_68881 &&
202 !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4))
203 goto out;
204 if (m68k_fputype & FPU_68882 &&
205 !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4))
206 goto out;
207 } else if (CPU_IS_040) {
208 if (!(sc->sc_fpstate[1] == 0x00 ||
209 sc->sc_fpstate[1] == 0x28 ||
210 sc->sc_fpstate[1] == 0x60))
211 goto out;
212 } else if (CPU_IS_060) {
213 if (!(sc->sc_fpstate[3] == 0x00 ||
214 sc->sc_fpstate[3] == 0x60 ||
215 sc->sc_fpstate[3] == 0xe0))
216 goto out;
217 } else
218 goto out;
219
220 __asm__ volatile (".chip 68k/68881\n\t"
221 "fmovemx %0,%%fp0-%%fp1\n\t"
222 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
223 ".chip 68k"
224 : /* no outputs */
225 : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
226 }
227 __asm__ volatile (".chip 68k/68881\n\t"
228 "frestore %0\n\t"
229 ".chip 68k" : : "m" (*sc->sc_fpstate));
230 err = 0;
231
232out:
233 return err;
234}
235
236#define FPCONTEXT_SIZE 216
237#define uc_fpstate uc_filler[0]
238#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
239#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
240
241static inline int rt_restore_fpu_state(struct ucontext __user *uc)
242{
243 unsigned char fpstate[FPCONTEXT_SIZE];
244 int context_size = CPU_IS_060 ? 8 : 0;
245 fpregset_t fpregs;
246 int err = 1;
247
248 if (FPU_IS_EMU) {
249 /* restore fpu control register */
250 if (__copy_from_user(current->thread.fpcntl,
251 uc->uc_mcontext.fpregs.f_fpcntl, 12))
252 goto out;
253 /* restore all other fpu register */
254 if (__copy_from_user(current->thread.fp,
255 uc->uc_mcontext.fpregs.f_fpregs, 96))
256 goto out;
257 return 0;
258 }
259
260 if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
261 goto out;
262 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
263 if (!CPU_IS_060)
264 context_size = fpstate[1];
265 /* Verify the frame format. */
266 if (!CPU_IS_060 && (fpstate[0] != fpu_version))
267 goto out;
268 if (CPU_IS_020_OR_030) {
269 if (m68k_fputype & FPU_68881 &&
270 !(context_size == 0x18 || context_size == 0xb4))
271 goto out;
272 if (m68k_fputype & FPU_68882 &&
273 !(context_size == 0x38 || context_size == 0xd4))
274 goto out;
275 } else if (CPU_IS_040) {
276 if (!(context_size == 0x00 ||
277 context_size == 0x28 ||
278 context_size == 0x60))
279 goto out;
280 } else if (CPU_IS_060) {
281 if (!(fpstate[3] == 0x00 ||
282 fpstate[3] == 0x60 ||
283 fpstate[3] == 0xe0))
284 goto out;
285 } else
286 goto out;
287 if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
288 sizeof(fpregs)))
289 goto out;
290 __asm__ volatile (".chip 68k/68881\n\t"
291 "fmovemx %0,%%fp0-%%fp7\n\t"
292 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
293 ".chip 68k"
294 : /* no outputs */
295 : "m" (*fpregs.f_fpregs),
296 "m" (*fpregs.f_fpcntl));
297 }
298 if (context_size &&
299 __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
300 context_size))
301 goto out;
302 __asm__ volatile (".chip 68k/68881\n\t"
303 "frestore %0\n\t"
304 ".chip 68k" : : "m" (*fpstate));
305 err = 0;
306
307out:
308 return err;
309}
310
311static int mangle_kernel_stack(struct pt_regs *regs, int formatvec,
312 void __user *fp)
313{
314 int fsize = frame_extra_sizes[formatvec >> 12];
315 if (fsize < 0) {
316 /*
317 * user process trying to return with weird frame format
318 */
319#ifdef DEBUG
320 printk("user process returning with weird frame format\n");
321#endif
322 return 1;
323 }
324 if (!fsize) {
325 regs->format = formatvec >> 12;
326 regs->vector = formatvec & 0xfff;
327 } else {
328 struct switch_stack *sw = (struct switch_stack *)regs - 1;
329 unsigned long buf[fsize / 2]; /* yes, twice as much */
330
331 /* that'll make sure that expansion won't crap over data */
332 if (copy_from_user(buf + fsize / 4, fp, fsize))
333 return 1;
334
335 /* point of no return */
336 regs->format = formatvec >> 12;
337 regs->vector = formatvec & 0xfff;
338#define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack))
339 __asm__ __volatile__
340 (" movel %0,%/a0\n\t"
341 " subl %1,%/a0\n\t" /* make room on stack */
342 " movel %/a0,%/sp\n\t" /* set stack pointer */
343 /* move switch_stack and pt_regs */
344 "1: movel %0@+,%/a0@+\n\t"
345 " dbra %2,1b\n\t"
346 " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */
347 " lsrl #2,%1\n\t"
348 " subql #1,%1\n\t"
349 /* copy to the gap we'd made */
350 "2: movel %4@+,%/a0@+\n\t"
351 " dbra %1,2b\n\t"
352 " bral ret_from_signal\n"
353 : /* no outputs, it doesn't ever return */
354 : "a" (sw), "d" (fsize), "d" (frame_offset/4-1),
355 "n" (frame_offset), "a" (buf + fsize/4)
356 : "a0");
357#undef frame_offset
358 }
359 return 0;
360}
361
362static inline int
363restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp)
364{
365 int formatvec;
366 struct sigcontext context;
367 int err;
368
369 /* Always make any pending restarted system calls return -EINTR */
370 current_thread_info()->restart_block.fn = do_no_restart_syscall;
371
372 /* get previous context */
373 if (copy_from_user(&context, usc, sizeof(context)))
374 goto badframe;
375
376 /* restore passed registers */
377 regs->d0 = context.sc_d0;
378 regs->d1 = context.sc_d1;
379 regs->a0 = context.sc_a0;
380 regs->a1 = context.sc_a1;
381 regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
382 regs->pc = context.sc_pc;
383 regs->orig_d0 = -1; /* disable syscall checks */
384 wrusp(context.sc_usp);
385 formatvec = context.sc_formatvec;
386
387 err = restore_fpu_state(&context);
388
389 if (err || mangle_kernel_stack(regs, formatvec, fp))
390 goto badframe;
391
392 return 0;
393
394badframe:
395 return 1;
396}
397
398static inline int
399rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
400 struct ucontext __user *uc)
401{
402 int temp;
403 greg_t __user *gregs = uc->uc_mcontext.gregs;
404 unsigned long usp;
405 int err;
406
407 /* Always make any pending restarted system calls return -EINTR */
408 current_thread_info()->restart_block.fn = do_no_restart_syscall;
409
410 err = __get_user(temp, &uc->uc_mcontext.version);
411 if (temp != MCONTEXT_VERSION)
412 goto badframe;
413 /* restore passed registers */
414 err |= __get_user(regs->d0, &gregs[0]);
415 err |= __get_user(regs->d1, &gregs[1]);
416 err |= __get_user(regs->d2, &gregs[2]);
417 err |= __get_user(regs->d3, &gregs[3]);
418 err |= __get_user(regs->d4, &gregs[4]);
419 err |= __get_user(regs->d5, &gregs[5]);
420 err |= __get_user(sw->d6, &gregs[6]);
421 err |= __get_user(sw->d7, &gregs[7]);
422 err |= __get_user(regs->a0, &gregs[8]);
423 err |= __get_user(regs->a1, &gregs[9]);
424 err |= __get_user(regs->a2, &gregs[10]);
425 err |= __get_user(sw->a3, &gregs[11]);
426 err |= __get_user(sw->a4, &gregs[12]);
427 err |= __get_user(sw->a5, &gregs[13]);
428 err |= __get_user(sw->a6, &gregs[14]);
429 err |= __get_user(usp, &gregs[15]);
430 wrusp(usp);
431 err |= __get_user(regs->pc, &gregs[16]);
432 err |= __get_user(temp, &gregs[17]);
433 regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
434 regs->orig_d0 = -1; /* disable syscall checks */
435 err |= __get_user(temp, &uc->uc_formatvec);
436
437 err |= rt_restore_fpu_state(uc);
438
439 if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
440 goto badframe;
441
442 if (mangle_kernel_stack(regs, temp, &uc->uc_extra))
443 goto badframe;
444
445 return 0;
446
447badframe:
448 return 1;
449}
450
451asmlinkage int do_sigreturn(unsigned long __unused)
452{
453 struct switch_stack *sw = (struct switch_stack *) &__unused;
454 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
455 unsigned long usp = rdusp();
456 struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
457 sigset_t set;
458
459 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
460 goto badframe;
461 if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
462 (_NSIG_WORDS > 1 &&
463 __copy_from_user(&set.sig[1], &frame->extramask,
464 sizeof(frame->extramask))))
465 goto badframe;
466
467 sigdelsetmask(&set, ~_BLOCKABLE);
468 current->blocked = set;
469 recalc_sigpending();
470
471 if (restore_sigcontext(regs, &frame->sc, frame + 1))
472 goto badframe;
473 return regs->d0;
474
475badframe:
476 force_sig(SIGSEGV, current);
477 return 0;
478}
479
480asmlinkage int do_rt_sigreturn(unsigned long __unused)
481{
482 struct switch_stack *sw = (struct switch_stack *) &__unused;
483 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
484 unsigned long usp = rdusp();
485 struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
486 sigset_t set;
487
488 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
489 goto badframe;
490 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
491 goto badframe;
492
493 sigdelsetmask(&set, ~_BLOCKABLE);
494 current->blocked = set;
495 recalc_sigpending();
496
497 if (rt_restore_ucontext(regs, sw, &frame->uc))
498 goto badframe;
499 return regs->d0;
500
501badframe:
502 force_sig(SIGSEGV, current);
503 return 0;
504}
505
506/*
507 * Set up a signal frame.
508 */
509
510static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
511{
512 if (FPU_IS_EMU) {
513 /* save registers */
514 memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
515 memcpy(sc->sc_fpregs, current->thread.fp, 24);
516 return;
517 }
518
519 __asm__ volatile (".chip 68k/68881\n\t"
520 "fsave %0\n\t"
521 ".chip 68k"
522 : : "m" (*sc->sc_fpstate) : "memory");
523
524 if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) {
525 fpu_version = sc->sc_fpstate[0];
526 if (CPU_IS_020_OR_030 &&
527 regs->vector >= (VEC_FPBRUC * 4) &&
528 regs->vector <= (VEC_FPNAN * 4)) {
529 /* Clear pending exception in 68882 idle frame */
530 if (*(unsigned short *) sc->sc_fpstate == 0x1f38)
531 sc->sc_fpstate[0x38] |= 1 << 3;
532 }
533 __asm__ volatile (".chip 68k/68881\n\t"
534 "fmovemx %%fp0-%%fp1,%0\n\t"
535 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
536 ".chip 68k"
537 : "=m" (*sc->sc_fpregs),
538 "=m" (*sc->sc_fpcntl)
539 : /* no inputs */
540 : "memory");
541 }
542}
543
544static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
545{
546 unsigned char fpstate[FPCONTEXT_SIZE];
547 int context_size = CPU_IS_060 ? 8 : 0;
548 int err = 0;
549
550 if (FPU_IS_EMU) {
551 /* save fpu control register */
552 err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl,
553 current->thread.fpcntl, 12);
554 /* save all other fpu register */
555 err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
556 current->thread.fp, 96);
557 return err;
558 }
559
560 __asm__ volatile (".chip 68k/68881\n\t"
561 "fsave %0\n\t"
562 ".chip 68k"
563 : : "m" (*fpstate) : "memory");
564
565 err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
566 if (CPU_IS_060 ? fpstate[2] : fpstate[0]) {
567 fpregset_t fpregs;
568 if (!CPU_IS_060)
569 context_size = fpstate[1];
570 fpu_version = fpstate[0];
571 if (CPU_IS_020_OR_030 &&
572 regs->vector >= (VEC_FPBRUC * 4) &&
573 regs->vector <= (VEC_FPNAN * 4)) {
574 /* Clear pending exception in 68882 idle frame */
575 if (*(unsigned short *) fpstate == 0x1f38)
576 fpstate[0x38] |= 1 << 3;
577 }
578 __asm__ volatile (".chip 68k/68881\n\t"
579 "fmovemx %%fp0-%%fp7,%0\n\t"
580 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
581 ".chip 68k"
582 : "=m" (*fpregs.f_fpregs),
583 "=m" (*fpregs.f_fpcntl)
584 : /* no inputs */
585 : "memory");
586 err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
587 sizeof(fpregs));
588 }
589 if (context_size)
590 err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
591 context_size);
592 return err;
593}
594
595static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
596 unsigned long mask)
597{
598 sc->sc_mask = mask;
599 sc->sc_usp = rdusp();
600 sc->sc_d0 = regs->d0;
601 sc->sc_d1 = regs->d1;
602 sc->sc_a0 = regs->a0;
603 sc->sc_a1 = regs->a1;
604 sc->sc_sr = regs->sr;
605 sc->sc_pc = regs->pc;
606 sc->sc_formatvec = regs->format << 12 | regs->vector;
607 save_fpu_state(sc, regs);
608}
609
610static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
611{
612 struct switch_stack *sw = (struct switch_stack *)regs - 1;
613 greg_t __user *gregs = uc->uc_mcontext.gregs;
614 int err = 0;
615
616 err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
617 err |= __put_user(regs->d0, &gregs[0]);
618 err |= __put_user(regs->d1, &gregs[1]);
619 err |= __put_user(regs->d2, &gregs[2]);
620 err |= __put_user(regs->d3, &gregs[3]);
621 err |= __put_user(regs->d4, &gregs[4]);
622 err |= __put_user(regs->d5, &gregs[5]);
623 err |= __put_user(sw->d6, &gregs[6]);
624 err |= __put_user(sw->d7, &gregs[7]);
625 err |= __put_user(regs->a0, &gregs[8]);
626 err |= __put_user(regs->a1, &gregs[9]);
627 err |= __put_user(regs->a2, &gregs[10]);
628 err |= __put_user(sw->a3, &gregs[11]);
629 err |= __put_user(sw->a4, &gregs[12]);
630 err |= __put_user(sw->a5, &gregs[13]);
631 err |= __put_user(sw->a6, &gregs[14]);
632 err |= __put_user(rdusp(), &gregs[15]);
633 err |= __put_user(regs->pc, &gregs[16]);
634 err |= __put_user(regs->sr, &gregs[17]);
635 err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec);
636 err |= rt_save_fpu_state(uc, regs);
637 return err;
638}
639
640static inline void push_cache (unsigned long vaddr)
641{
642 /*
643 * Using the old cache_push_v() was really a big waste.
644 *
645 * What we are trying to do is to flush 8 bytes to ram.
646 * Flushing 2 cache lines of 16 bytes is much cheaper than
647 * flushing 1 or 2 pages, as previously done in
648 * cache_push_v().
649 * Jes
650 */
651 if (CPU_IS_040) {
652 unsigned long temp;
653
654 __asm__ __volatile__ (".chip 68040\n\t"
655 "nop\n\t"
656 "ptestr (%1)\n\t"
657 "movec %%mmusr,%0\n\t"
658 ".chip 68k"
659 : "=r" (temp)
660 : "a" (vaddr));
661
662 temp &= PAGE_MASK;
663 temp |= vaddr & ~PAGE_MASK;
664
665 __asm__ __volatile__ (".chip 68040\n\t"
666 "nop\n\t"
667 "cpushl %%bc,(%0)\n\t"
668 ".chip 68k"
669 : : "a" (temp));
670 }
671 else if (CPU_IS_060) {
672 unsigned long temp;
673 __asm__ __volatile__ (".chip 68060\n\t"
674 "plpar (%0)\n\t"
675 ".chip 68k"
676 : "=a" (temp)
677 : "0" (vaddr));
678 __asm__ __volatile__ (".chip 68060\n\t"
679 "cpushl %%bc,(%0)\n\t"
680 ".chip 68k"
681 : : "a" (temp));
682 }
683 else {
684 /*
685 * 68030/68020 have no writeback cache;
686 * still need to clear icache.
687 * Note that vaddr is guaranteed to be long word aligned.
688 */
689 unsigned long temp;
690 asm volatile ("movec %%cacr,%0" : "=r" (temp));
691 temp += 4;
692 asm volatile ("movec %0,%%caar\n\t"
693 "movec %1,%%cacr"
694 : : "r" (vaddr), "r" (temp));
695 asm volatile ("movec %0,%%caar\n\t"
696 "movec %1,%%cacr"
697 : : "r" (vaddr + 4), "r" (temp));
698 }
699}
700
701static inline void __user *
702get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
703{
704 unsigned long usp;
705
706 /* Default to using normal stack. */
707 usp = rdusp();
708
709 /* This is the X/Open sanctioned signal stack switching. */
710 if (ka->sa.sa_flags & SA_ONSTACK) {
711 if (!sas_ss_flags(usp))
712 usp = current->sas_ss_sp + current->sas_ss_size;
713 }
714 return (void __user *)((usp - frame_size) & -8UL);
715}
716
717static int setup_frame (int sig, struct k_sigaction *ka,
718 sigset_t *set, struct pt_regs *regs)
719{
720 struct sigframe __user *frame;
721 int fsize = frame_extra_sizes[regs->format];
722 struct sigcontext context;
723 int err = 0;
724
725 if (fsize < 0) {
726#ifdef DEBUG
727 printk ("setup_frame: Unknown frame format %#x\n",
728 regs->format);
729#endif
730 goto give_sigsegv;
731 }
732
733 frame = get_sigframe(ka, regs, sizeof(*frame) + fsize);
734
735 if (fsize)
736 err |= copy_to_user (frame + 1, regs + 1, fsize);
737
738 err |= __put_user((current_thread_info()->exec_domain
739 && current_thread_info()->exec_domain->signal_invmap
740 && sig < 32
741 ? current_thread_info()->exec_domain->signal_invmap[sig]
742 : sig),
743 &frame->sig);
744
745 err |= __put_user(regs->vector, &frame->code);
746 err |= __put_user(&frame->sc, &frame->psc);
747
748 if (_NSIG_WORDS > 1)
749 err |= copy_to_user(frame->extramask, &set->sig[1],
750 sizeof(frame->extramask));
751
752 setup_sigcontext(&context, regs, set->sig[0]);
753 err |= copy_to_user (&frame->sc, &context, sizeof(context));
754
755 /* Set up to return from userspace. */
756 err |= __put_user(frame->retcode, &frame->pretcode);
757 /* moveq #,d0; trap #0 */
758 err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
759 (long __user *)(frame->retcode));
760
761 if (err)
762 goto give_sigsegv;
763
764 push_cache ((unsigned long) &frame->retcode);
765
766 /*
767 * Set up registers for signal handler. All the state we are about
768 * to destroy is successfully copied to sigframe.
769 */
770 wrusp ((unsigned long) frame);
771 regs->pc = (unsigned long) ka->sa.sa_handler;
772
773 /*
774 * This is subtle; if we build more than one sigframe, all but the
775 * first one will see frame format 0 and have fsize == 0, so we won't
776 * screw stkadj.
777 */
778 if (fsize)
779 regs->stkadj = fsize;
780
781 /* Prepare to skip over the extra stuff in the exception frame. */
782 if (regs->stkadj) {
783 struct pt_regs *tregs =
784 (struct pt_regs *)((ulong)regs + regs->stkadj);
785#ifdef DEBUG
786 printk("Performing stackadjust=%04x\n", regs->stkadj);
787#endif
788 /* This must be copied with decreasing addresses to
789 handle overlaps. */
790 tregs->vector = 0;
791 tregs->format = 0;
792 tregs->pc = regs->pc;
793 tregs->sr = regs->sr;
794 }
795 return 0;
796
797give_sigsegv:
798 force_sigsegv(sig, current);
799 return err;
800}
801
802static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
803 sigset_t *set, struct pt_regs *regs)
804{
805 struct rt_sigframe __user *frame;
806 int fsize = frame_extra_sizes[regs->format];
807 int err = 0;
808
809 if (fsize < 0) {
810#ifdef DEBUG
811 printk ("setup_frame: Unknown frame format %#x\n",
812 regs->format);
813#endif
814 goto give_sigsegv;
815 }
816
817 frame = get_sigframe(ka, regs, sizeof(*frame));
818
819 if (fsize)
820 err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize);
821
822 err |= __put_user((current_thread_info()->exec_domain
823 && current_thread_info()->exec_domain->signal_invmap
824 && sig < 32
825 ? current_thread_info()->exec_domain->signal_invmap[sig]
826 : sig),
827 &frame->sig);
828 err |= __put_user(&frame->info, &frame->pinfo);
829 err |= __put_user(&frame->uc, &frame->puc);
830 err |= copy_siginfo_to_user(&frame->info, info);
831
832 /* Create the ucontext. */
833 err |= __put_user(0, &frame->uc.uc_flags);
834 err |= __put_user(NULL, &frame->uc.uc_link);
835 err |= __put_user((void __user *)current->sas_ss_sp,
836 &frame->uc.uc_stack.ss_sp);
837 err |= __put_user(sas_ss_flags(rdusp()),
838 &frame->uc.uc_stack.ss_flags);
839 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
840 err |= rt_setup_ucontext(&frame->uc, regs);
841 err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
842
843 /* Set up to return from userspace. */
844 err |= __put_user(frame->retcode, &frame->pretcode);
845#ifdef __mcoldfire__
846 /* movel #__NR_rt_sigreturn,d0; trap #0 */
847 err |= __put_user(0x203c0000, (long __user *)(frame->retcode + 0));
848 err |= __put_user(0x00004e40 + (__NR_rt_sigreturn << 16),
849 (long __user *)(frame->retcode + 4));
850#else
851 /* moveq #,d0; notb d0; trap #0 */
852 err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
853 (long __user *)(frame->retcode + 0));
854 err |= __put_user(0x4e40, (short __user *)(frame->retcode + 4));
855#endif
856
857 if (err)
858 goto give_sigsegv;
859
860 push_cache ((unsigned long) &frame->retcode);
861
862 /*
863 * Set up registers for signal handler. All the state we are about
864 * to destroy is successfully copied to sigframe.
865 */
866 wrusp ((unsigned long) frame);
867 regs->pc = (unsigned long) ka->sa.sa_handler;
868
869 /*
870 * This is subtle; if we build more than one sigframe, all but the
871 * first one will see frame format 0 and have fsize == 0, so we won't
872 * screw stkadj.
873 */
874 if (fsize)
875 regs->stkadj = fsize;
876
877 /* Prepare to skip over the extra stuff in the exception frame. */
878 if (regs->stkadj) {
879 struct pt_regs *tregs =
880 (struct pt_regs *)((ulong)regs + regs->stkadj);
881#ifdef DEBUG
882 printk("Performing stackadjust=%04x\n", regs->stkadj);
883#endif
884 /* This must be copied with decreasing addresses to
885 handle overlaps. */
886 tregs->vector = 0;
887 tregs->format = 0;
888 tregs->pc = regs->pc;
889 tregs->sr = regs->sr;
890 }
891 return 0;
892
893give_sigsegv:
894 force_sigsegv(sig, current);
895 return err;
896}
897
898static inline void
899handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
900{
901 switch (regs->d0) {
902 case -ERESTARTNOHAND:
903 if (!has_handler)
904 goto do_restart;
905 regs->d0 = -EINTR;
906 break;
907
908 case -ERESTART_RESTARTBLOCK:
909 if (!has_handler) {
910 regs->d0 = __NR_restart_syscall;
911 regs->pc -= 2;
912 break;
913 }
914 regs->d0 = -EINTR;
915 break;
916
917 case -ERESTARTSYS:
918 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
919 regs->d0 = -EINTR;
920 break;
921 }
922 /* fallthrough */
923 case -ERESTARTNOINTR:
924 do_restart:
925 regs->d0 = regs->orig_d0;
926 regs->pc -= 2;
927 break;
928 }
929}
930
931void ptrace_signal_deliver(struct pt_regs *regs, void *cookie)
932{
933 if (regs->orig_d0 < 0)
934 return;
935 switch (regs->d0) {
936 case -ERESTARTNOHAND:
937 case -ERESTARTSYS:
938 case -ERESTARTNOINTR:
939 regs->d0 = regs->orig_d0;
940 regs->orig_d0 = -1;
941 regs->pc -= 2;
942 break;
943 }
944}
945
946/*
947 * OK, we're invoking a handler
948 */
949static void
950handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
951 sigset_t *oldset, struct pt_regs *regs)
952{
953 int err;
954 /* are we from a system call? */
955 if (regs->orig_d0 >= 0)
956 /* If so, check system call restarting.. */
957 handle_restart(regs, ka, 1);
958
959 /* set up the stack frame */
960 if (ka->sa.sa_flags & SA_SIGINFO)
961 err = setup_rt_frame(sig, ka, info, oldset, regs);
962 else
963 err = setup_frame(sig, ka, oldset, regs);
964
965 if (err)
966 return;
967
968 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
969 if (!(ka->sa.sa_flags & SA_NODEFER))
970 sigaddset(&current->blocked,sig);
971 recalc_sigpending();
972
973 if (test_thread_flag(TIF_DELAYED_TRACE)) {
974 regs->sr &= ~0x8000;
975 send_sig(SIGTRAP, current, 1);
976 }
977
978 clear_thread_flag(TIF_RESTORE_SIGMASK);
979}
980
981/*
982 * Note that 'init' is a special process: it doesn't get signals it doesn't
983 * want to handle. Thus you cannot kill init even with a SIGKILL even by
984 * mistake.
985 */
986asmlinkage void do_signal(struct pt_regs *regs)
987{
988 siginfo_t info;
989 struct k_sigaction ka;
990 int signr;
991 sigset_t *oldset;
992
993 current->thread.esp0 = (unsigned long) regs;
994
995 if (test_thread_flag(TIF_RESTORE_SIGMASK))
996 oldset = &current->saved_sigmask;
997 else
998 oldset = &current->blocked;
999
1000 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
1001 if (signr > 0) {
1002 /* Whee! Actually deliver the signal. */
1003 handle_signal(signr, &ka, &info, oldset, regs);
1004 return;
1005 }
1006
1007 /* Did we come from a system call? */
1008 if (regs->orig_d0 >= 0)
1009 /* Restart the system call - no handlers present */
1010 handle_restart(regs, NULL, 0);
1011
1012 /* If there's no signal to deliver, we just restore the saved mask. */
1013 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
1014 clear_thread_flag(TIF_RESTORE_SIGMASK);
1015 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
1016 }
1017}
diff --git a/arch/m68k/kernel/signal_no.c b/arch/m68k/kernel/signal_no.c
new file mode 100644
index 000000000000..36a81bb6835a
--- /dev/null
+++ b/arch/m68k/kernel/signal_no.c
@@ -0,0 +1,765 @@
1/*
2 * linux/arch/m68knommu/kernel/signal.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11/*
12 * Linux/m68k support by Hamish Macdonald
13 *
14 * 68060 fixes by Jesper Skov
15 *
16 * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab
17 *
18 * mathemu support by Roman Zippel
19 * (Note: fpstate in the signal context is completely ignored for the emulator
20 * and the internal floating point format is put on stack)
21 */
22
23/*
24 * ++roman (07/09/96): implemented signal stacks (specially for tosemu on
25 * Atari :-) Current limitation: Only one sigstack can be active at one time.
26 * If a second signal with SA_ONSTACK set arrives while working on a sigstack,
27 * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
28 * signal handlers!
29 */
30
31#include <linux/sched.h>
32#include <linux/mm.h>
33#include <linux/kernel.h>
34#include <linux/signal.h>
35#include <linux/syscalls.h>
36#include <linux/errno.h>
37#include <linux/wait.h>
38#include <linux/ptrace.h>
39#include <linux/unistd.h>
40#include <linux/stddef.h>
41#include <linux/highuid.h>
42#include <linux/tty.h>
43#include <linux/personality.h>
44#include <linux/binfmts.h>
45
46#include <asm/setup.h>
47#include <asm/uaccess.h>
48#include <asm/pgtable.h>
49#include <asm/traps.h>
50#include <asm/ucontext.h>
51
52#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
53
54void ret_from_user_signal(void);
55void ret_from_user_rt_signal(void);
56
57/*
58 * Atomically swap in the new signal mask, and wait for a signal.
59 */
60asmlinkage int
61sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
62{
63 mask &= _BLOCKABLE;
64 spin_lock_irq(&current->sighand->siglock);
65 current->saved_sigmask = current->blocked;
66 siginitset(&current->blocked, mask);
67 recalc_sigpending();
68 spin_unlock_irq(&current->sighand->siglock);
69
70 current->state = TASK_INTERRUPTIBLE;
71 schedule();
72 set_restore_sigmask();
73
74 return -ERESTARTNOHAND;
75}
76
77asmlinkage int
78sys_sigaction(int sig, const struct old_sigaction __user *act,
79 struct old_sigaction __user *oact)
80{
81 struct k_sigaction new_ka, old_ka;
82 int ret;
83
84 if (act) {
85 old_sigset_t mask;
86 if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
87 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
88 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
89 __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
90 __get_user(mask, &act->sa_mask))
91 return -EFAULT;
92 siginitset(&new_ka.sa.sa_mask, mask);
93 }
94
95 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
96
97 if (!ret && oact) {
98 if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
99 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
100 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
101 __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
102 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
103 return -EFAULT;
104 }
105
106 return ret;
107}
108
109asmlinkage int
110sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
111{
112 return do_sigaltstack(uss, uoss, rdusp());
113}
114
115
116/*
117 * Do a signal return; undo the signal stack.
118 *
119 * Keep the return code on the stack quadword aligned!
120 * That makes the cache flush below easier.
121 */
122
123struct sigframe
124{
125 char __user *pretcode;
126 int sig;
127 int code;
128 struct sigcontext __user *psc;
129 char retcode[8];
130 unsigned long extramask[_NSIG_WORDS-1];
131 struct sigcontext sc;
132};
133
134struct rt_sigframe
135{
136 char __user *pretcode;
137 int sig;
138 struct siginfo __user *pinfo;
139 void __user *puc;
140 char retcode[8];
141 struct siginfo info;
142 struct ucontext uc;
143};
144
145#ifdef CONFIG_FPU
146
147static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */
148
149static inline int restore_fpu_state(struct sigcontext *sc)
150{
151 int err = 1;
152
153 if (FPU_IS_EMU) {
154 /* restore registers */
155 memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12);
156 memcpy(current->thread.fp, sc->sc_fpregs, 24);
157 return 0;
158 }
159
160 if (sc->sc_fpstate[0]) {
161 /* Verify the frame format. */
162 if (sc->sc_fpstate[0] != fpu_version)
163 goto out;
164
165 __asm__ volatile (".chip 68k/68881\n\t"
166 "fmovemx %0,%%fp0-%%fp1\n\t"
167 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
168 ".chip 68k"
169 : /* no outputs */
170 : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl));
171 }
172 __asm__ volatile (".chip 68k/68881\n\t"
173 "frestore %0\n\t"
174 ".chip 68k" : : "m" (*sc->sc_fpstate));
175 err = 0;
176
177out:
178 return err;
179}
180
181#define FPCONTEXT_SIZE 216
182#define uc_fpstate uc_filler[0]
183#define uc_formatvec uc_filler[FPCONTEXT_SIZE/4]
184#define uc_extra uc_filler[FPCONTEXT_SIZE/4+1]
185
186static inline int rt_restore_fpu_state(struct ucontext __user *uc)
187{
188 unsigned char fpstate[FPCONTEXT_SIZE];
189 int context_size = 0;
190 fpregset_t fpregs;
191 int err = 1;
192
193 if (FPU_IS_EMU) {
194 /* restore fpu control register */
195 if (__copy_from_user(current->thread.fpcntl,
196 uc->uc_mcontext.fpregs.f_fpcntl, 12))
197 goto out;
198 /* restore all other fpu register */
199 if (__copy_from_user(current->thread.fp,
200 uc->uc_mcontext.fpregs.f_fpregs, 96))
201 goto out;
202 return 0;
203 }
204
205 if (__get_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate))
206 goto out;
207 if (fpstate[0]) {
208 context_size = fpstate[1];
209
210 /* Verify the frame format. */
211 if (fpstate[0] != fpu_version)
212 goto out;
213 if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs,
214 sizeof(fpregs)))
215 goto out;
216 __asm__ volatile (".chip 68k/68881\n\t"
217 "fmovemx %0,%%fp0-%%fp7\n\t"
218 "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t"
219 ".chip 68k"
220 : /* no outputs */
221 : "m" (*fpregs.f_fpregs),
222 "m" (*fpregs.f_fpcntl));
223 }
224 if (context_size &&
225 __copy_from_user(fpstate + 4, (long __user *)&uc->uc_fpstate + 1,
226 context_size))
227 goto out;
228 __asm__ volatile (".chip 68k/68881\n\t"
229 "frestore %0\n\t"
230 ".chip 68k" : : "m" (*fpstate));
231 err = 0;
232
233out:
234 return err;
235}
236
237#endif
238
239static inline int
240restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp,
241 int *pd0)
242{
243 int formatvec;
244 struct sigcontext context;
245 int err = 0;
246
247 /* Always make any pending restarted system calls return -EINTR */
248 current_thread_info()->restart_block.fn = do_no_restart_syscall;
249
250 /* get previous context */
251 if (copy_from_user(&context, usc, sizeof(context)))
252 goto badframe;
253
254 /* restore passed registers */
255 regs->d1 = context.sc_d1;
256 regs->a0 = context.sc_a0;
257 regs->a1 = context.sc_a1;
258 ((struct switch_stack *)regs - 1)->a5 = context.sc_a5;
259 regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff);
260 regs->pc = context.sc_pc;
261 regs->orig_d0 = -1; /* disable syscall checks */
262 wrusp(context.sc_usp);
263 formatvec = context.sc_formatvec;
264 regs->format = formatvec >> 12;
265 regs->vector = formatvec & 0xfff;
266
267#ifdef CONFIG_FPU
268 err = restore_fpu_state(&context);
269#endif
270
271 *pd0 = context.sc_d0;
272 return err;
273
274badframe:
275 return 1;
276}
277
278static inline int
279rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw,
280 struct ucontext __user *uc, int *pd0)
281{
282 int temp;
283 greg_t __user *gregs = uc->uc_mcontext.gregs;
284 unsigned long usp;
285 int err;
286
287 /* Always make any pending restarted system calls return -EINTR */
288 current_thread_info()->restart_block.fn = do_no_restart_syscall;
289
290 err = __get_user(temp, &uc->uc_mcontext.version);
291 if (temp != MCONTEXT_VERSION)
292 goto badframe;
293 /* restore passed registers */
294 err |= __get_user(regs->d0, &gregs[0]);
295 err |= __get_user(regs->d1, &gregs[1]);
296 err |= __get_user(regs->d2, &gregs[2]);
297 err |= __get_user(regs->d3, &gregs[3]);
298 err |= __get_user(regs->d4, &gregs[4]);
299 err |= __get_user(regs->d5, &gregs[5]);
300 err |= __get_user(sw->d6, &gregs[6]);
301 err |= __get_user(sw->d7, &gregs[7]);
302 err |= __get_user(regs->a0, &gregs[8]);
303 err |= __get_user(regs->a1, &gregs[9]);
304 err |= __get_user(regs->a2, &gregs[10]);
305 err |= __get_user(sw->a3, &gregs[11]);
306 err |= __get_user(sw->a4, &gregs[12]);
307 err |= __get_user(sw->a5, &gregs[13]);
308 err |= __get_user(sw->a6, &gregs[14]);
309 err |= __get_user(usp, &gregs[15]);
310 wrusp(usp);
311 err |= __get_user(regs->pc, &gregs[16]);
312 err |= __get_user(temp, &gregs[17]);
313 regs->sr = (regs->sr & 0xff00) | (temp & 0xff);
314 regs->orig_d0 = -1; /* disable syscall checks */
315 regs->format = temp >> 12;
316 regs->vector = temp & 0xfff;
317
318 if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT)
319 goto badframe;
320
321 *pd0 = regs->d0;
322 return err;
323
324badframe:
325 return 1;
326}
327
328asmlinkage int do_sigreturn(unsigned long __unused)
329{
330 struct switch_stack *sw = (struct switch_stack *) &__unused;
331 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
332 unsigned long usp = rdusp();
333 struct sigframe __user *frame = (struct sigframe __user *)(usp - 4);
334 sigset_t set;
335 int d0;
336
337 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
338 goto badframe;
339 if (__get_user(set.sig[0], &frame->sc.sc_mask) ||
340 (_NSIG_WORDS > 1 &&
341 __copy_from_user(&set.sig[1], &frame->extramask,
342 sizeof(frame->extramask))))
343 goto badframe;
344
345 sigdelsetmask(&set, ~_BLOCKABLE);
346 spin_lock_irq(&current->sighand->siglock);
347 current->blocked = set;
348 recalc_sigpending();
349 spin_unlock_irq(&current->sighand->siglock);
350
351 if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0))
352 goto badframe;
353 return d0;
354
355badframe:
356 force_sig(SIGSEGV, current);
357 return 0;
358}
359
360asmlinkage int do_rt_sigreturn(unsigned long __unused)
361{
362 struct switch_stack *sw = (struct switch_stack *) &__unused;
363 struct pt_regs *regs = (struct pt_regs *) (sw + 1);
364 unsigned long usp = rdusp();
365 struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4);
366 sigset_t set;
367 int d0;
368
369 if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
370 goto badframe;
371 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
372 goto badframe;
373
374 sigdelsetmask(&set, ~_BLOCKABLE);
375 spin_lock_irq(&current->sighand->siglock);
376 current->blocked = set;
377 recalc_sigpending();
378 spin_unlock_irq(&current->sighand->siglock);
379
380 if (rt_restore_ucontext(regs, sw, &frame->uc, &d0))
381 goto badframe;
382 return d0;
383
384badframe:
385 force_sig(SIGSEGV, current);
386 return 0;
387}
388
389#ifdef CONFIG_FPU
390/*
391 * Set up a signal frame.
392 */
393
394static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs)
395{
396 if (FPU_IS_EMU) {
397 /* save registers */
398 memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12);
399 memcpy(sc->sc_fpregs, current->thread.fp, 24);
400 return;
401 }
402
403 __asm__ volatile (".chip 68k/68881\n\t"
404 "fsave %0\n\t"
405 ".chip 68k"
406 : : "m" (*sc->sc_fpstate) : "memory");
407
408 if (sc->sc_fpstate[0]) {
409 fpu_version = sc->sc_fpstate[0];
410 __asm__ volatile (".chip 68k/68881\n\t"
411 "fmovemx %%fp0-%%fp1,%0\n\t"
412 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
413 ".chip 68k"
414 : "=m" (*sc->sc_fpregs),
415 "=m" (*sc->sc_fpcntl)
416 : /* no inputs */
417 : "memory");
418 }
419}
420
421static inline int rt_save_fpu_state(struct ucontext __user *uc, struct pt_regs *regs)
422{
423 unsigned char fpstate[FPCONTEXT_SIZE];
424 int context_size = 0;
425 int err = 0;
426
427 if (FPU_IS_EMU) {
428 /* save fpu control register */
429 err |= copy_to_user(uc->uc_mcontext.fpregs.f_pcntl,
430 current->thread.fpcntl, 12);
431 /* save all other fpu register */
432 err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs,
433 current->thread.fp, 96);
434 return err;
435 }
436
437 __asm__ volatile (".chip 68k/68881\n\t"
438 "fsave %0\n\t"
439 ".chip 68k"
440 : : "m" (*fpstate) : "memory");
441
442 err |= __put_user(*(long *)fpstate, (long __user *)&uc->uc_fpstate);
443 if (fpstate[0]) {
444 fpregset_t fpregs;
445 context_size = fpstate[1];
446 fpu_version = fpstate[0];
447 __asm__ volatile (".chip 68k/68881\n\t"
448 "fmovemx %%fp0-%%fp7,%0\n\t"
449 "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t"
450 ".chip 68k"
451 : "=m" (*fpregs.f_fpregs),
452 "=m" (*fpregs.f_fpcntl)
453 : /* no inputs */
454 : "memory");
455 err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs,
456 sizeof(fpregs));
457 }
458 if (context_size)
459 err |= copy_to_user((long __user *)&uc->uc_fpstate + 1, fpstate + 4,
460 context_size);
461 return err;
462}
463
464#endif
465
466static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
467 unsigned long mask)
468{
469 sc->sc_mask = mask;
470 sc->sc_usp = rdusp();
471 sc->sc_d0 = regs->d0;
472 sc->sc_d1 = regs->d1;
473 sc->sc_a0 = regs->a0;
474 sc->sc_a1 = regs->a1;
475 sc->sc_a5 = ((struct switch_stack *)regs - 1)->a5;
476 sc->sc_sr = regs->sr;
477 sc->sc_pc = regs->pc;
478 sc->sc_formatvec = regs->format << 12 | regs->vector;
479#ifdef CONFIG_FPU
480 save_fpu_state(sc, regs);
481#endif
482}
483
484static inline int rt_setup_ucontext(struct ucontext __user *uc, struct pt_regs *regs)
485{
486 struct switch_stack *sw = (struct switch_stack *)regs - 1;
487 greg_t __user *gregs = uc->uc_mcontext.gregs;
488 int err = 0;
489
490 err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
491 err |= __put_user(regs->d0, &gregs[0]);
492 err |= __put_user(regs->d1, &gregs[1]);
493 err |= __put_user(regs->d2, &gregs[2]);
494 err |= __put_user(regs->d3, &gregs[3]);
495 err |= __put_user(regs->d4, &gregs[4]);
496 err |= __put_user(regs->d5, &gregs[5]);
497 err |= __put_user(sw->d6, &gregs[6]);
498 err |= __put_user(sw->d7, &gregs[7]);
499 err |= __put_user(regs->a0, &gregs[8]);
500 err |= __put_user(regs->a1, &gregs[9]);
501 err |= __put_user(regs->a2, &gregs[10]);
502 err |= __put_user(sw->a3, &gregs[11]);
503 err |= __put_user(sw->a4, &gregs[12]);
504 err |= __put_user(sw->a5, &gregs[13]);
505 err |= __put_user(sw->a6, &gregs[14]);
506 err |= __put_user(rdusp(), &gregs[15]);
507 err |= __put_user(regs->pc, &gregs[16]);
508 err |= __put_user(regs->sr, &gregs[17]);
509#ifdef CONFIG_FPU
510 err |= rt_save_fpu_state(uc, regs);
511#endif
512 return err;
513}
514
515static inline void __user *
516get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
517{
518 unsigned long usp;
519
520 /* Default to using normal stack. */
521 usp = rdusp();
522
523 /* This is the X/Open sanctioned signal stack switching. */
524 if (ka->sa.sa_flags & SA_ONSTACK) {
525 if (!sas_ss_flags(usp))
526 usp = current->sas_ss_sp + current->sas_ss_size;
527 }
528 return (void __user *)((usp - frame_size) & -8UL);
529}
530
531static int setup_frame (int sig, struct k_sigaction *ka,
532 sigset_t *set, struct pt_regs *regs)
533{
534 struct sigframe __user *frame;
535 struct sigcontext context;
536 int err = 0;
537
538 frame = get_sigframe(ka, regs, sizeof(*frame));
539
540 err |= __put_user((current_thread_info()->exec_domain
541 && current_thread_info()->exec_domain->signal_invmap
542 && sig < 32
543 ? current_thread_info()->exec_domain->signal_invmap[sig]
544 : sig),
545 &frame->sig);
546
547 err |= __put_user(regs->vector, &frame->code);
548 err |= __put_user(&frame->sc, &frame->psc);
549
550 if (_NSIG_WORDS > 1)
551 err |= copy_to_user(frame->extramask, &set->sig[1],
552 sizeof(frame->extramask));
553
554 setup_sigcontext(&context, regs, set->sig[0]);
555 err |= copy_to_user (&frame->sc, &context, sizeof(context));
556
557 /* Set up to return from userspace. */
558 err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
559
560 if (err)
561 goto give_sigsegv;
562
563 /* Set up registers for signal handler */
564 wrusp ((unsigned long) frame);
565 regs->pc = (unsigned long) ka->sa.sa_handler;
566 ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
567 regs->format = 0x4; /*set format byte to make stack appear modulo 4
568 which it will be when doing the rte */
569
570adjust_stack:
571 /* Prepare to skip over the extra stuff in the exception frame. */
572 if (regs->stkadj) {
573 struct pt_regs *tregs =
574 (struct pt_regs *)((ulong)regs + regs->stkadj);
575#if defined(DEBUG)
576 printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
577#endif
578 /* This must be copied with decreasing addresses to
579 handle overlaps. */
580 tregs->vector = 0;
581 tregs->format = 0;
582 tregs->pc = regs->pc;
583 tregs->sr = regs->sr;
584 }
585 return err;
586
587give_sigsegv:
588 force_sigsegv(sig, current);
589 goto adjust_stack;
590}
591
592static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
593 sigset_t *set, struct pt_regs *regs)
594{
595 struct rt_sigframe __user *frame;
596 int err = 0;
597
598 frame = get_sigframe(ka, regs, sizeof(*frame));
599
600 err |= __put_user((current_thread_info()->exec_domain
601 && current_thread_info()->exec_domain->signal_invmap
602 && sig < 32
603 ? current_thread_info()->exec_domain->signal_invmap[sig]
604 : sig),
605 &frame->sig);
606 err |= __put_user(&frame->info, &frame->pinfo);
607 err |= __put_user(&frame->uc, &frame->puc);
608 err |= copy_siginfo_to_user(&frame->info, info);
609
610 /* Create the ucontext. */
611 err |= __put_user(0, &frame->uc.uc_flags);
612 err |= __put_user(NULL, &frame->uc.uc_link);
613 err |= __put_user((void __user *)current->sas_ss_sp,
614 &frame->uc.uc_stack.ss_sp);
615 err |= __put_user(sas_ss_flags(rdusp()),
616 &frame->uc.uc_stack.ss_flags);
617 err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
618 err |= rt_setup_ucontext(&frame->uc, regs);
619 err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
620
621 /* Set up to return from userspace. */
622 err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
623
624 if (err)
625 goto give_sigsegv;
626
627 /* Set up registers for signal handler */
628 wrusp ((unsigned long) frame);
629 regs->pc = (unsigned long) ka->sa.sa_handler;
630 ((struct switch_stack *)regs - 1)->a5 = current->mm->start_data;
631 regs->format = 0x4; /*set format byte to make stack appear modulo 4
632 which it will be when doing the rte */
633
634adjust_stack:
635 /* Prepare to skip over the extra stuff in the exception frame. */
636 if (regs->stkadj) {
637 struct pt_regs *tregs =
638 (struct pt_regs *)((ulong)regs + regs->stkadj);
639#if defined(DEBUG)
640 printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj);
641#endif
642 /* This must be copied with decreasing addresses to
643 handle overlaps. */
644 tregs->vector = 0;
645 tregs->format = 0;
646 tregs->pc = regs->pc;
647 tregs->sr = regs->sr;
648 }
649 return err;
650
651give_sigsegv:
652 force_sigsegv(sig, current);
653 goto adjust_stack;
654}
655
656static inline void
657handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
658{
659 switch (regs->d0) {
660 case -ERESTARTNOHAND:
661 if (!has_handler)
662 goto do_restart;
663 regs->d0 = -EINTR;
664 break;
665
666 case -ERESTART_RESTARTBLOCK:
667 if (!has_handler) {
668 regs->d0 = __NR_restart_syscall;
669 regs->pc -= 2;
670 break;
671 }
672 regs->d0 = -EINTR;
673 break;
674
675 case -ERESTARTSYS:
676 if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
677 regs->d0 = -EINTR;
678 break;
679 }
680 /* fallthrough */
681 case -ERESTARTNOINTR:
682 do_restart:
683 regs->d0 = regs->orig_d0;
684 regs->pc -= 2;
685 break;
686 }
687}
688
689/*
690 * OK, we're invoking a handler
691 */
692static void
693handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
694 sigset_t *oldset, struct pt_regs *regs)
695{
696 int err;
697 /* are we from a system call? */
698 if (regs->orig_d0 >= 0)
699 /* If so, check system call restarting.. */
700 handle_restart(regs, ka, 1);
701
702 /* set up the stack frame */
703 if (ka->sa.sa_flags & SA_SIGINFO)
704 err = setup_rt_frame(sig, ka, info, oldset, regs);
705 else
706 err = setup_frame(sig, ka, oldset, regs);
707
708 if (err)
709 return;
710
711 spin_lock_irq(&current->sighand->siglock);
712 sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
713 if (!(ka->sa.sa_flags & SA_NODEFER))
714 sigaddset(&current->blocked,sig);
715 recalc_sigpending();
716 spin_unlock_irq(&current->sighand->siglock);
717
718 clear_thread_flag(TIF_RESTORE_SIGMASK);
719}
720
721/*
722 * Note that 'init' is a special process: it doesn't get signals it doesn't
723 * want to handle. Thus you cannot kill init even with a SIGKILL even by
724 * mistake.
725 */
726asmlinkage void do_signal(struct pt_regs *regs)
727{
728 struct k_sigaction ka;
729 siginfo_t info;
730 int signr;
731 sigset_t *oldset;
732
733 /*
734 * We want the common case to go fast, which
735 * is why we may in certain cases get here from
736 * kernel mode. Just return without doing anything
737 * if so.
738 */
739 if (!user_mode(regs))
740 return;
741
742 if (test_thread_flag(TIF_RESTORE_SIGMASK))
743 oldset = &current->saved_sigmask;
744 else
745 oldset = &current->blocked;
746
747 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
748 if (signr > 0) {
749 /* Whee! Actually deliver the signal. */
750 handle_signal(signr, &ka, &info, oldset, regs);
751 return;
752 }
753
754 /* Did we come from a system call? */
755 if (regs->orig_d0 >= 0) {
756 /* Restart the system call - no handlers present */
757 handle_restart(regs, NULL, 0);
758 }
759
760 /* If there's no signal to deliver, we just restore the saved mask. */
761 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
762 clear_thread_flag(TIF_RESTORE_SIGMASK);
763 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
764 }
765}
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 2f431ece7b5f..8623f8dc16f8 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -12,7 +12,6 @@
12#include <linux/mm.h> 12#include <linux/mm.h>
13#include <linux/fs.h> 13#include <linux/fs.h>
14#include <linux/smp.h> 14#include <linux/smp.h>
15#include <linux/smp_lock.h>
16#include <linux/sem.h> 15#include <linux/sem.h>
17#include <linux/msg.h> 16#include <linux/msg.h>
18#include <linux/shm.h> 17#include <linux/shm.h>
@@ -28,7 +27,10 @@
28#include <asm/traps.h> 27#include <asm/traps.h>
29#include <asm/page.h> 28#include <asm/page.h>
30#include <asm/unistd.h> 29#include <asm/unistd.h>
31#include <linux/elf.h> 30#include <asm/cacheflush.h>
31
32#ifdef CONFIG_MMU
33
32#include <asm/tlb.h> 34#include <asm/tlb.h>
33 35
34asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, 36asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
@@ -377,7 +379,6 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
377 struct vm_area_struct *vma; 379 struct vm_area_struct *vma;
378 int ret = -EINVAL; 380 int ret = -EINVAL;
379 381
380 lock_kernel();
381 if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL || 382 if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
382 cache & ~FLUSH_CACHE_BOTH) 383 cache & ~FLUSH_CACHE_BOTH)
383 goto out; 384 goto out;
@@ -446,43 +447,9 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
446 } 447 }
447 } 448 }
448out: 449out:
449 unlock_kernel();
450 return ret; 450 return ret;
451} 451}
452 452
453asmlinkage int sys_getpagesize(void)
454{
455 return PAGE_SIZE;
456}
457
458/*
459 * Do a system call from kernel instead of calling sys_execve so we
460 * end up with proper pt_regs.
461 */
462int kernel_execve(const char *filename,
463 const char *const argv[],
464 const char *const envp[])
465{
466 register long __res asm ("%d0") = __NR_execve;
467 register long __a asm ("%d1") = (long)(filename);
468 register long __b asm ("%d2") = (long)(argv);
469 register long __c asm ("%d3") = (long)(envp);
470 asm volatile ("trap #0" : "+d" (__res)
471 : "d" (__a), "d" (__b), "d" (__c));
472 return __res;
473}
474
475asmlinkage unsigned long sys_get_thread_area(void)
476{
477 return current_thread_info()->tp_value;
478}
479
480asmlinkage int sys_set_thread_area(unsigned long tp)
481{
482 current_thread_info()->tp_value = tp;
483 return 0;
484}
485
486/* This syscall gets its arguments in A0 (mem), D2 (oldval) and 453/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
487 D1 (newval). */ 454 D1 (newval). */
488asmlinkage int 455asmlinkage int
@@ -542,6 +509,70 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
542 } 509 }
543} 510}
544 511
512#else
513
514/* sys_cacheflush -- flush (part of) the processor cache. */
515asmlinkage int
516sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
517{
518 flush_cache_all();
519 return 0;
520}
521
522/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
523 D1 (newval). */
524asmlinkage int
525sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
526 unsigned long __user * mem)
527{
528 struct mm_struct *mm = current->mm;
529 unsigned long mem_value;
530
531 down_read(&mm->mmap_sem);
532
533 mem_value = *mem;
534 if (mem_value == oldval)
535 *mem = newval;
536
537 up_read(&mm->mmap_sem);
538 return mem_value;
539}
540
541#endif /* CONFIG_MMU */
542
543asmlinkage int sys_getpagesize(void)
544{
545 return PAGE_SIZE;
546}
547
548/*
549 * Do a system call from kernel instead of calling sys_execve so we
550 * end up with proper pt_regs.
551 */
552int kernel_execve(const char *filename,
553 const char *const argv[],
554 const char *const envp[])
555{
556 register long __res asm ("%d0") = __NR_execve;
557 register long __a asm ("%d1") = (long)(filename);
558 register long __b asm ("%d2") = (long)(argv);
559 register long __c asm ("%d3") = (long)(envp);
560 asm volatile ("trap #0" : "+d" (__res)
561 : "d" (__a), "d" (__b), "d" (__c));
562 return __res;
563}
564
565asmlinkage unsigned long sys_get_thread_area(void)
566{
567 return current_thread_info()->tp_value;
568}
569
570asmlinkage int sys_set_thread_area(unsigned long tp)
571{
572 current_thread_info()->tp_value = tp;
573 return 0;
574}
575
545asmlinkage int sys_atomic_barrier(void) 576asmlinkage int sys_atomic_barrier(void)
546{ 577{
547 /* no code needed for uniprocs */ 578 /* no code needed for uniprocs */
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
new file mode 100644
index 000000000000..00d1452f9571
--- /dev/null
+++ b/arch/m68k/kernel/syscalltable.S
@@ -0,0 +1,368 @@
1/*
2 * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
3 *
4 * Based on older entry.S files, the following copyrights apply:
5 *
6 * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
7 * Kenneth Albanowski <kjahds@kjahds.com>,
8 * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
9 * Copyright (C) 1991, 1992 Linus Torvalds
10 *
11 * Linux/m68k support by Hamish Macdonald
12 */
13
14#include <linux/linkage.h>
15
16#ifndef CONFIG_MMU
17#define sys_mmap2 sys_mmap_pgoff
18#endif
19
20.section .rodata
21ALIGN
22ENTRY(sys_call_table)
23 .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
24 .long sys_exit
25 .long sys_fork
26 .long sys_read
27 .long sys_write
28 .long sys_open /* 5 */
29 .long sys_close
30 .long sys_waitpid
31 .long sys_creat
32 .long sys_link
33 .long sys_unlink /* 10 */
34 .long sys_execve
35 .long sys_chdir
36 .long sys_time
37 .long sys_mknod
38 .long sys_chmod /* 15 */
39 .long sys_chown16
40 .long sys_ni_syscall /* old break syscall holder */
41 .long sys_stat
42 .long sys_lseek
43 .long sys_getpid /* 20 */
44 .long sys_mount
45 .long sys_oldumount
46 .long sys_setuid16
47 .long sys_getuid16
48 .long sys_stime /* 25 */
49 .long sys_ptrace
50 .long sys_alarm
51 .long sys_fstat
52 .long sys_pause
53 .long sys_utime /* 30 */
54 .long sys_ni_syscall /* old stty syscall holder */
55 .long sys_ni_syscall /* old gtty syscall holder */
56 .long sys_access
57 .long sys_nice
58 .long sys_ni_syscall /* 35 - old ftime syscall holder */
59 .long sys_sync
60 .long sys_kill
61 .long sys_rename
62 .long sys_mkdir
63 .long sys_rmdir /* 40 */
64 .long sys_dup
65 .long sys_pipe
66 .long sys_times
67 .long sys_ni_syscall /* old prof syscall holder */
68 .long sys_brk /* 45 */
69 .long sys_setgid16
70 .long sys_getgid16
71 .long sys_signal
72 .long sys_geteuid16
73 .long sys_getegid16 /* 50 */
74 .long sys_acct
75 .long sys_umount /* recycled never used phys() */
76 .long sys_ni_syscall /* old lock syscall holder */
77 .long sys_ioctl
78 .long sys_fcntl /* 55 */
79 .long sys_ni_syscall /* old mpx syscall holder */
80 .long sys_setpgid
81 .long sys_ni_syscall /* old ulimit syscall holder */
82 .long sys_ni_syscall
83 .long sys_umask /* 60 */
84 .long sys_chroot
85 .long sys_ustat
86 .long sys_dup2
87 .long sys_getppid
88 .long sys_getpgrp /* 65 */
89 .long sys_setsid
90 .long sys_sigaction
91 .long sys_sgetmask
92 .long sys_ssetmask
93 .long sys_setreuid16 /* 70 */
94 .long sys_setregid16
95 .long sys_sigsuspend
96 .long sys_sigpending
97 .long sys_sethostname
98 .long sys_setrlimit /* 75 */
99 .long sys_old_getrlimit
100 .long sys_getrusage
101 .long sys_gettimeofday
102 .long sys_settimeofday
103 .long sys_getgroups16 /* 80 */
104 .long sys_setgroups16
105 .long sys_old_select
106 .long sys_symlink
107 .long sys_lstat
108 .long sys_readlink /* 85 */
109 .long sys_uselib
110 .long sys_swapon
111 .long sys_reboot
112 .long sys_old_readdir
113 .long sys_old_mmap /* 90 */
114 .long sys_munmap
115 .long sys_truncate
116 .long sys_ftruncate
117 .long sys_fchmod
118 .long sys_fchown16 /* 95 */
119 .long sys_getpriority
120 .long sys_setpriority
121 .long sys_ni_syscall /* old profil syscall holder */
122 .long sys_statfs
123 .long sys_fstatfs /* 100 */
124 .long sys_ni_syscall /* ioperm for i386 */
125 .long sys_socketcall
126 .long sys_syslog
127 .long sys_setitimer
128 .long sys_getitimer /* 105 */
129 .long sys_newstat
130 .long sys_newlstat
131 .long sys_newfstat
132 .long sys_ni_syscall
133 .long sys_ni_syscall /* 110 - iopl for i386 */
134 .long sys_vhangup
135 .long sys_ni_syscall /* obsolete idle() syscall */
136 .long sys_ni_syscall /* vm86old for i386 */
137 .long sys_wait4
138 .long sys_swapoff /* 115 */
139 .long sys_sysinfo
140 .long sys_ipc
141 .long sys_fsync
142 .long sys_sigreturn
143 .long sys_clone /* 120 */
144 .long sys_setdomainname
145 .long sys_newuname
146 .long sys_cacheflush /* modify_ldt for i386 */
147 .long sys_adjtimex
148 .long sys_mprotect /* 125 */
149 .long sys_sigprocmask
150 .long sys_ni_syscall /* old "create_module" */
151 .long sys_init_module
152 .long sys_delete_module
153 .long sys_ni_syscall /* 130 - old "get_kernel_syms" */
154 .long sys_quotactl
155 .long sys_getpgid
156 .long sys_fchdir
157 .long sys_bdflush
158 .long sys_sysfs /* 135 */
159 .long sys_personality
160 .long sys_ni_syscall /* for afs_syscall */
161 .long sys_setfsuid16
162 .long sys_setfsgid16
163 .long sys_llseek /* 140 */
164 .long sys_getdents
165 .long sys_select
166 .long sys_flock
167 .long sys_msync
168 .long sys_readv /* 145 */
169 .long sys_writev
170 .long sys_getsid
171 .long sys_fdatasync
172 .long sys_sysctl
173 .long sys_mlock /* 150 */
174 .long sys_munlock
175 .long sys_mlockall
176 .long sys_munlockall
177 .long sys_sched_setparam
178 .long sys_sched_getparam /* 155 */
179 .long sys_sched_setscheduler
180 .long sys_sched_getscheduler
181 .long sys_sched_yield
182 .long sys_sched_get_priority_max
183 .long sys_sched_get_priority_min /* 160 */
184 .long sys_sched_rr_get_interval
185 .long sys_nanosleep
186 .long sys_mremap
187 .long sys_setresuid16
188 .long sys_getresuid16 /* 165 */
189 .long sys_getpagesize
190 .long sys_ni_syscall /* old "query_module" */
191 .long sys_poll
192 .long sys_nfsservctl
193 .long sys_setresgid16 /* 170 */
194 .long sys_getresgid16
195 .long sys_prctl
196 .long sys_rt_sigreturn
197 .long sys_rt_sigaction
198 .long sys_rt_sigprocmask /* 175 */
199 .long sys_rt_sigpending
200 .long sys_rt_sigtimedwait
201 .long sys_rt_sigqueueinfo
202 .long sys_rt_sigsuspend
203 .long sys_pread64 /* 180 */
204 .long sys_pwrite64
205 .long sys_lchown16
206 .long sys_getcwd
207 .long sys_capget
208 .long sys_capset /* 185 */
209 .long sys_sigaltstack
210 .long sys_sendfile
211 .long sys_ni_syscall /* streams1 */
212 .long sys_ni_syscall /* streams2 */
213 .long sys_vfork /* 190 */
214 .long sys_getrlimit
215 .long sys_mmap2
216 .long sys_truncate64
217 .long sys_ftruncate64
218 .long sys_stat64 /* 195 */
219 .long sys_lstat64
220 .long sys_fstat64
221 .long sys_chown
222 .long sys_getuid
223 .long sys_getgid /* 200 */
224 .long sys_geteuid
225 .long sys_getegid
226 .long sys_setreuid
227 .long sys_setregid
228 .long sys_getgroups /* 205 */
229 .long sys_setgroups
230 .long sys_fchown
231 .long sys_setresuid
232 .long sys_getresuid
233 .long sys_setresgid /* 210 */
234 .long sys_getresgid
235 .long sys_lchown
236 .long sys_setuid
237 .long sys_setgid
238 .long sys_setfsuid /* 215 */
239 .long sys_setfsgid
240 .long sys_pivot_root
241 .long sys_ni_syscall
242 .long sys_ni_syscall
243 .long sys_getdents64 /* 220 */
244 .long sys_gettid
245 .long sys_tkill
246 .long sys_setxattr
247 .long sys_lsetxattr
248 .long sys_fsetxattr /* 225 */
249 .long sys_getxattr
250 .long sys_lgetxattr
251 .long sys_fgetxattr
252 .long sys_listxattr
253 .long sys_llistxattr /* 230 */
254 .long sys_flistxattr
255 .long sys_removexattr
256 .long sys_lremovexattr
257 .long sys_fremovexattr
258 .long sys_futex /* 235 */
259 .long sys_sendfile64
260 .long sys_mincore
261 .long sys_madvise
262 .long sys_fcntl64
263 .long sys_readahead /* 240 */
264 .long sys_io_setup
265 .long sys_io_destroy
266 .long sys_io_getevents
267 .long sys_io_submit
268 .long sys_io_cancel /* 245 */
269 .long sys_fadvise64
270 .long sys_exit_group
271 .long sys_lookup_dcookie
272 .long sys_epoll_create
273 .long sys_epoll_ctl /* 250 */
274 .long sys_epoll_wait
275 .long sys_remap_file_pages
276 .long sys_set_tid_address
277 .long sys_timer_create
278 .long sys_timer_settime /* 255 */
279 .long sys_timer_gettime
280 .long sys_timer_getoverrun
281 .long sys_timer_delete
282 .long sys_clock_settime
283 .long sys_clock_gettime /* 260 */
284 .long sys_clock_getres
285 .long sys_clock_nanosleep
286 .long sys_statfs64
287 .long sys_fstatfs64
288 .long sys_tgkill /* 265 */
289 .long sys_utimes
290 .long sys_fadvise64_64
291 .long sys_mbind
292 .long sys_get_mempolicy
293 .long sys_set_mempolicy /* 270 */
294 .long sys_mq_open
295 .long sys_mq_unlink
296 .long sys_mq_timedsend
297 .long sys_mq_timedreceive
298 .long sys_mq_notify /* 275 */
299 .long sys_mq_getsetattr
300 .long sys_waitid
301 .long sys_ni_syscall /* for sys_vserver */
302 .long sys_add_key
303 .long sys_request_key /* 280 */
304 .long sys_keyctl
305 .long sys_ioprio_set
306 .long sys_ioprio_get
307 .long sys_inotify_init
308 .long sys_inotify_add_watch /* 285 */
309 .long sys_inotify_rm_watch
310 .long sys_migrate_pages
311 .long sys_openat
312 .long sys_mkdirat
313 .long sys_mknodat /* 290 */
314 .long sys_fchownat
315 .long sys_futimesat
316 .long sys_fstatat64
317 .long sys_unlinkat
318 .long sys_renameat /* 295 */
319 .long sys_linkat
320 .long sys_symlinkat
321 .long sys_readlinkat
322 .long sys_fchmodat
323 .long sys_faccessat /* 300 */
324 .long sys_pselect6
325 .long sys_ppoll
326 .long sys_unshare
327 .long sys_set_robust_list
328 .long sys_get_robust_list /* 305 */
329 .long sys_splice
330 .long sys_sync_file_range
331 .long sys_tee
332 .long sys_vmsplice
333 .long sys_move_pages /* 310 */
334 .long sys_sched_setaffinity
335 .long sys_sched_getaffinity
336 .long sys_kexec_load
337 .long sys_getcpu
338 .long sys_epoll_pwait /* 315 */
339 .long sys_utimensat
340 .long sys_signalfd
341 .long sys_timerfd_create
342 .long sys_eventfd
343 .long sys_fallocate /* 320 */
344 .long sys_timerfd_settime
345 .long sys_timerfd_gettime
346 .long sys_signalfd4
347 .long sys_eventfd2
348 .long sys_epoll_create1 /* 325 */
349 .long sys_dup3
350 .long sys_pipe2
351 .long sys_inotify_init1
352 .long sys_preadv
353 .long sys_pwritev /* 330 */
354 .long sys_rt_tgsigqueueinfo
355 .long sys_perf_event_open
356 .long sys_get_thread_area
357 .long sys_set_thread_area
358 .long sys_atomic_cmpxchg_32 /* 335 */
359 .long sys_atomic_barrier
360 .long sys_fanotify_init
361 .long sys_fanotify_mark
362 .long sys_prlimit64
363 .long sys_name_to_handle_at /* 340 */
364 .long sys_open_by_handle_at
365 .long sys_clock_adjtime
366 .long sys_syncfs
367 .long sys_setns
368
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 4926b3856c15..a5cf40c26de5 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -1,116 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * linux/arch/m68k/kernel/time.c 2#include "time_mm.c"
3 * 3#else
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds 4#include "time_no.c"
5 *
6 * This file contains the m68k-specific time handling details.
7 * Most of the stuff is located in the machine specific files.
8 *
9 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
10 * "A Kernel Model for Precision Timekeeping" by Dave Mills
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/param.h>
18#include <linux/string.h>
19#include <linux/mm.h>
20#include <linux/rtc.h>
21#include <linux/platform_device.h>
22
23#include <asm/machdep.h>
24#include <asm/io.h>
25#include <asm/irq_regs.h>
26
27#include <linux/time.h>
28#include <linux/timex.h>
29#include <linux/profile.h>
30
31static inline int set_rtc_mmss(unsigned long nowtime)
32{
33 if (mach_set_clock_mmss)
34 return mach_set_clock_mmss (nowtime);
35 return -1;
36}
37
38/*
39 * timer_interrupt() needs to keep up the real-time clock,
40 * as well as call the "do_timer()" routine every clocktick
41 */
42static irqreturn_t timer_interrupt(int irq, void *dummy)
43{
44 do_timer(1);
45#ifndef CONFIG_SMP
46 update_process_times(user_mode(get_irq_regs()));
47#endif 5#endif
48 profile_tick(CPU_PROFILING);
49
50#ifdef CONFIG_HEARTBEAT
51 /* use power LED as a heartbeat instead -- much more useful
52 for debugging -- based on the version for PReP by Cort */
53 /* acts like an actual heart beat -- ie thump-thump-pause... */
54 if (mach_heartbeat) {
55 static unsigned cnt = 0, period = 0, dist = 0;
56
57 if (cnt == 0 || cnt == dist)
58 mach_heartbeat( 1 );
59 else if (cnt == 7 || cnt == dist+7)
60 mach_heartbeat( 0 );
61
62 if (++cnt > period) {
63 cnt = 0;
64 /* The hyperbolic function below modifies the heartbeat period
65 * length in dependency of the current (5min) load. It goes
66 * through the points f(0)=126, f(1)=86, f(5)=51,
67 * f(inf)->30. */
68 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
69 dist = period / 4;
70 }
71 }
72#endif /* CONFIG_HEARTBEAT */
73 return IRQ_HANDLED;
74}
75
76void read_persistent_clock(struct timespec *ts)
77{
78 struct rtc_time time;
79 ts->tv_sec = 0;
80 ts->tv_nsec = 0;
81
82 if (mach_hwclk) {
83 mach_hwclk(0, &time);
84
85 if ((time.tm_year += 1900) < 1970)
86 time.tm_year += 100;
87 ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
88 time.tm_hour, time.tm_min, time.tm_sec);
89 }
90}
91
92void __init time_init(void)
93{
94 mach_sched_init(timer_interrupt);
95}
96
97u32 arch_gettimeoffset(void)
98{
99 return mach_gettimeoffset() * 1000;
100}
101
102static int __init rtc_init(void)
103{
104 struct platform_device *pdev;
105
106 if (!mach_hwclk)
107 return -ENODEV;
108
109 pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
110 if (IS_ERR(pdev))
111 return PTR_ERR(pdev);
112
113 return 0;
114}
115
116module_init(rtc_init);
diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c
new file mode 100644
index 000000000000..18b34ee5db3b
--- /dev/null
+++ b/arch/m68k/kernel/time_mm.c
@@ -0,0 +1,114 @@
1/*
2 * linux/arch/m68k/kernel/time.c
3 *
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5 *
6 * This file contains the m68k-specific time handling details.
7 * Most of the stuff is located in the machine specific files.
8 *
9 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
10 * "A Kernel Model for Precision Timekeeping" by Dave Mills
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/param.h>
18#include <linux/string.h>
19#include <linux/mm.h>
20#include <linux/rtc.h>
21#include <linux/platform_device.h>
22
23#include <asm/machdep.h>
24#include <asm/io.h>
25#include <asm/irq_regs.h>
26
27#include <linux/time.h>
28#include <linux/timex.h>
29#include <linux/profile.h>
30
31static inline int set_rtc_mmss(unsigned long nowtime)
32{
33 if (mach_set_clock_mmss)
34 return mach_set_clock_mmss (nowtime);
35 return -1;
36}
37
38/*
39 * timer_interrupt() needs to keep up the real-time clock,
40 * as well as call the "xtime_update()" routine every clocktick
41 */
42static irqreturn_t timer_interrupt(int irq, void *dummy)
43{
44 xtime_update(1);
45 update_process_times(user_mode(get_irq_regs()));
46 profile_tick(CPU_PROFILING);
47
48#ifdef CONFIG_HEARTBEAT
49 /* use power LED as a heartbeat instead -- much more useful
50 for debugging -- based on the version for PReP by Cort */
51 /* acts like an actual heart beat -- ie thump-thump-pause... */
52 if (mach_heartbeat) {
53 static unsigned cnt = 0, period = 0, dist = 0;
54
55 if (cnt == 0 || cnt == dist)
56 mach_heartbeat( 1 );
57 else if (cnt == 7 || cnt == dist+7)
58 mach_heartbeat( 0 );
59
60 if (++cnt > period) {
61 cnt = 0;
62 /* The hyperbolic function below modifies the heartbeat period
63 * length in dependency of the current (5min) load. It goes
64 * through the points f(0)=126, f(1)=86, f(5)=51,
65 * f(inf)->30. */
66 period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
67 dist = period / 4;
68 }
69 }
70#endif /* CONFIG_HEARTBEAT */
71 return IRQ_HANDLED;
72}
73
74void read_persistent_clock(struct timespec *ts)
75{
76 struct rtc_time time;
77 ts->tv_sec = 0;
78 ts->tv_nsec = 0;
79
80 if (mach_hwclk) {
81 mach_hwclk(0, &time);
82
83 if ((time.tm_year += 1900) < 1970)
84 time.tm_year += 100;
85 ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday,
86 time.tm_hour, time.tm_min, time.tm_sec);
87 }
88}
89
90void __init time_init(void)
91{
92 mach_sched_init(timer_interrupt);
93}
94
95u32 arch_gettimeoffset(void)
96{
97 return mach_gettimeoffset() * 1000;
98}
99
100static int __init rtc_init(void)
101{
102 struct platform_device *pdev;
103
104 if (!mach_hwclk)
105 return -ENODEV;
106
107 pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
108 if (IS_ERR(pdev))
109 return PTR_ERR(pdev);
110
111 return 0;
112}
113
114module_init(rtc_init);
diff --git a/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c
new file mode 100644
index 000000000000..6623909f70e6
--- /dev/null
+++ b/arch/m68k/kernel/time_no.c
@@ -0,0 +1,87 @@
1/*
2 * linux/arch/m68knommu/kernel/time.c
3 *
4 * Copyright (C) 1991, 1992, 1995 Linus Torvalds
5 *
6 * This file contains the m68k-specific time handling details.
7 * Most of the stuff is located in the machine specific files.
8 *
9 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
10 * "A Kernel Model for Precision Timekeeping" by Dave Mills
11 */
12
13#include <linux/errno.h>
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kernel.h>
17#include <linux/param.h>
18#include <linux/string.h>
19#include <linux/mm.h>
20#include <linux/profile.h>
21#include <linux/time.h>
22#include <linux/timex.h>
23
24#include <asm/machdep.h>
25#include <asm/irq_regs.h>
26
27#define TICK_SIZE (tick_nsec / 1000)
28
29static inline int set_rtc_mmss(unsigned long nowtime)
30{
31 if (mach_set_clock_mmss)
32 return mach_set_clock_mmss (nowtime);
33 return -1;
34}
35
36#ifndef CONFIG_GENERIC_CLOCKEVENTS
37/*
38 * timer_interrupt() needs to keep up the real-time clock,
39 * as well as call the "xtime_update()" routine every clocktick
40 */
41irqreturn_t arch_timer_interrupt(int irq, void *dummy)
42{
43
44 if (current->pid)
45 profile_tick(CPU_PROFILING);
46
47 xtime_update(1);
48
49 update_process_times(user_mode(get_irq_regs()));
50
51 return(IRQ_HANDLED);
52}
53#endif
54
55static unsigned long read_rtc_mmss(void)
56{
57 unsigned int year, mon, day, hour, min, sec;
58
59 if (mach_gettod) {
60 mach_gettod(&year, &mon, &day, &hour, &min, &sec);
61 if ((year += 1900) < 1970)
62 year += 100;
63 } else {
64 year = 1970;
65 mon = day = 1;
66 hour = min = sec = 0;
67 }
68
69
70 return mktime(year, mon, day, hour, min, sec);
71}
72
73void read_persistent_clock(struct timespec *ts)
74{
75 ts->tv_sec = read_rtc_mmss();
76 ts->tv_nsec = 0;
77}
78
79int update_persistent_clock(struct timespec now)
80{
81 return set_rtc_mmss(now.tv_sec);
82}
83
84void time_init(void)
85{
86 hw_timer_init();
87}
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index ada4f4cca811..c98add3f5f0f 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -1,1203 +1,5 @@
1/* 1#ifdef CONFIG_MMU
2 * linux/arch/m68k/kernel/traps.c 2#include "traps_mm.c"
3 *
4 * Copyright (C) 1993, 1994 by Hamish Macdonald
5 *
6 * 68040 fixes by Michael Rausch
7 * 68040 fixes by Martin Apel
8 * 68040 fixes and writeback by Richard Zidlicky
9 * 68060 fixes by Roman Hodek
10 * 68060 fixes by Jesper Skov
11 *
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive
14 * for more details.
15 */
16
17/*
18 * Sets up all exception vectors
19 */
20
21#include <linux/sched.h>
22#include <linux/signal.h>
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/module.h>
26#include <linux/user.h>
27#include <linux/string.h>
28#include <linux/linkage.h>
29#include <linux/init.h>
30#include <linux/ptrace.h>
31#include <linux/kallsyms.h>
32
33#include <asm/setup.h>
34#include <asm/fpu.h>
35#include <asm/system.h>
36#include <asm/uaccess.h>
37#include <asm/traps.h>
38#include <asm/pgalloc.h>
39#include <asm/machdep.h>
40#include <asm/siginfo.h>
41
42/* assembler routines */
43asmlinkage void system_call(void);
44asmlinkage void buserr(void);
45asmlinkage void trap(void);
46asmlinkage void nmihandler(void);
47#ifdef CONFIG_M68KFPU_EMU
48asmlinkage void fpu_emu(void);
49#endif
50
51e_vector vectors[256] = {
52 [VEC_BUSERR] = buserr,
53 [VEC_SYS] = system_call,
54};
55
56/* nmi handler for the Amiga */
57asm(".text\n"
58 __ALIGN_STR "\n"
59 "nmihandler: rte");
60
61/*
62 * this must be called very early as the kernel might
63 * use some instruction that are emulated on the 060
64 */
65void __init base_trap_init(void)
66{
67 if(MACH_IS_SUN3X) {
68 extern e_vector *sun3x_prom_vbr;
69
70 __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
71 }
72
73 /* setup the exception vector table */
74 __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
75
76 if (CPU_IS_060) {
77 /* set up ISP entry points */
78 asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
79
80 vectors[VEC_UNIMPII] = unimp_vec;
81 }
82}
83
84void __init trap_init (void)
85{
86 int i;
87
88 for (i = VEC_SPUR; i <= VEC_INT7; i++)
89 vectors[i] = bad_inthandler;
90
91 for (i = 0; i < VEC_USER; i++)
92 if (!vectors[i])
93 vectors[i] = trap;
94
95 for (i = VEC_USER; i < 256; i++)
96 vectors[i] = bad_inthandler;
97
98#ifdef CONFIG_M68KFPU_EMU
99 if (FPU_IS_EMU)
100 vectors[VEC_LINE11] = fpu_emu;
101#endif
102
103 if (CPU_IS_040 && !FPU_IS_EMU) {
104 /* set up FPSP entry points */
105 asmlinkage void dz_vec(void) asm ("dz");
106 asmlinkage void inex_vec(void) asm ("inex");
107 asmlinkage void ovfl_vec(void) asm ("ovfl");
108 asmlinkage void unfl_vec(void) asm ("unfl");
109 asmlinkage void snan_vec(void) asm ("snan");
110 asmlinkage void operr_vec(void) asm ("operr");
111 asmlinkage void bsun_vec(void) asm ("bsun");
112 asmlinkage void fline_vec(void) asm ("fline");
113 asmlinkage void unsupp_vec(void) asm ("unsupp");
114
115 vectors[VEC_FPDIVZ] = dz_vec;
116 vectors[VEC_FPIR] = inex_vec;
117 vectors[VEC_FPOVER] = ovfl_vec;
118 vectors[VEC_FPUNDER] = unfl_vec;
119 vectors[VEC_FPNAN] = snan_vec;
120 vectors[VEC_FPOE] = operr_vec;
121 vectors[VEC_FPBRUC] = bsun_vec;
122 vectors[VEC_LINE11] = fline_vec;
123 vectors[VEC_FPUNSUP] = unsupp_vec;
124 }
125
126 if (CPU_IS_060 && !FPU_IS_EMU) {
127 /* set up IFPSP entry points */
128 asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan");
129 asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr");
130 asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl");
131 asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl");
132 asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz");
133 asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex");
134 asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline");
135 asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp");
136 asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd");
137
138 vectors[VEC_FPNAN] = snan_vec6;
139 vectors[VEC_FPOE] = operr_vec6;
140 vectors[VEC_FPOVER] = ovfl_vec6;
141 vectors[VEC_FPUNDER] = unfl_vec6;
142 vectors[VEC_FPDIVZ] = dz_vec6;
143 vectors[VEC_FPIR] = inex_vec6;
144 vectors[VEC_LINE11] = fline_vec6;
145 vectors[VEC_FPUNSUP] = unsupp_vec6;
146 vectors[VEC_UNIMPEA] = effadd_vec6;
147 }
148
149 /* if running on an amiga, make the NMI interrupt do nothing */
150 if (MACH_IS_AMIGA) {
151 vectors[VEC_INT7] = nmihandler;
152 }
153}
154
155
156static const char *vec_names[] = {
157 [VEC_RESETSP] = "RESET SP",
158 [VEC_RESETPC] = "RESET PC",
159 [VEC_BUSERR] = "BUS ERROR",
160 [VEC_ADDRERR] = "ADDRESS ERROR",
161 [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION",
162 [VEC_ZERODIV] = "ZERO DIVIDE",
163 [VEC_CHK] = "CHK",
164 [VEC_TRAP] = "TRAPcc",
165 [VEC_PRIV] = "PRIVILEGE VIOLATION",
166 [VEC_TRACE] = "TRACE",
167 [VEC_LINE10] = "LINE 1010",
168 [VEC_LINE11] = "LINE 1111",
169 [VEC_RESV12] = "UNASSIGNED RESERVED 12",
170 [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION",
171 [VEC_FORMAT] = "FORMAT ERROR",
172 [VEC_UNINT] = "UNINITIALIZED INTERRUPT",
173 [VEC_RESV16] = "UNASSIGNED RESERVED 16",
174 [VEC_RESV17] = "UNASSIGNED RESERVED 17",
175 [VEC_RESV18] = "UNASSIGNED RESERVED 18",
176 [VEC_RESV19] = "UNASSIGNED RESERVED 19",
177 [VEC_RESV20] = "UNASSIGNED RESERVED 20",
178 [VEC_RESV21] = "UNASSIGNED RESERVED 21",
179 [VEC_RESV22] = "UNASSIGNED RESERVED 22",
180 [VEC_RESV23] = "UNASSIGNED RESERVED 23",
181 [VEC_SPUR] = "SPURIOUS INTERRUPT",
182 [VEC_INT1] = "LEVEL 1 INT",
183 [VEC_INT2] = "LEVEL 2 INT",
184 [VEC_INT3] = "LEVEL 3 INT",
185 [VEC_INT4] = "LEVEL 4 INT",
186 [VEC_INT5] = "LEVEL 5 INT",
187 [VEC_INT6] = "LEVEL 6 INT",
188 [VEC_INT7] = "LEVEL 7 INT",
189 [VEC_SYS] = "SYSCALL",
190 [VEC_TRAP1] = "TRAP #1",
191 [VEC_TRAP2] = "TRAP #2",
192 [VEC_TRAP3] = "TRAP #3",
193 [VEC_TRAP4] = "TRAP #4",
194 [VEC_TRAP5] = "TRAP #5",
195 [VEC_TRAP6] = "TRAP #6",
196 [VEC_TRAP7] = "TRAP #7",
197 [VEC_TRAP8] = "TRAP #8",
198 [VEC_TRAP9] = "TRAP #9",
199 [VEC_TRAP10] = "TRAP #10",
200 [VEC_TRAP11] = "TRAP #11",
201 [VEC_TRAP12] = "TRAP #12",
202 [VEC_TRAP13] = "TRAP #13",
203 [VEC_TRAP14] = "TRAP #14",
204 [VEC_TRAP15] = "TRAP #15",
205 [VEC_FPBRUC] = "FPCP BSUN",
206 [VEC_FPIR] = "FPCP INEXACT",
207 [VEC_FPDIVZ] = "FPCP DIV BY 0",
208 [VEC_FPUNDER] = "FPCP UNDERFLOW",
209 [VEC_FPOE] = "FPCP OPERAND ERROR",
210 [VEC_FPOVER] = "FPCP OVERFLOW",
211 [VEC_FPNAN] = "FPCP SNAN",
212 [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION",
213 [VEC_MMUCFG] = "MMU CONFIGURATION ERROR",
214 [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR",
215 [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR",
216 [VEC_RESV59] = "UNASSIGNED RESERVED 59",
217 [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60",
218 [VEC_UNIMPII] = "UNASSIGNED RESERVED 61",
219 [VEC_RESV62] = "UNASSIGNED RESERVED 62",
220 [VEC_RESV63] = "UNASSIGNED RESERVED 63",
221};
222
223static const char *space_names[] = {
224 [0] = "Space 0",
225 [USER_DATA] = "User Data",
226 [USER_PROGRAM] = "User Program",
227#ifndef CONFIG_SUN3
228 [3] = "Space 3",
229#else 3#else
230 [FC_CONTROL] = "Control", 4#include "traps_no.c"
231#endif
232 [4] = "Space 4",
233 [SUPER_DATA] = "Super Data",
234 [SUPER_PROGRAM] = "Super Program",
235 [CPU_SPACE] = "CPU"
236};
237
238void die_if_kernel(char *,struct pt_regs *,int);
239asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
240 unsigned long error_code);
241int send_fault_sig(struct pt_regs *regs);
242
243asmlinkage void trap_c(struct frame *fp);
244
245#if defined (CONFIG_M68060)
246static inline void access_error060 (struct frame *fp)
247{
248 unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
249
250#ifdef DEBUG
251 printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr);
252#endif
253
254 if (fslw & MMU060_BPE) {
255 /* branch prediction error -> clear branch cache */
256 __asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
257 "orl #0x00400000,%/d0\n\t"
258 "movec %/d0,%/cacr"
259 : : : "d0" );
260 /* return if there's no other error */
261 if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE))
262 return;
263 }
264
265 if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
266 unsigned long errorcode;
267 unsigned long addr = fp->un.fmt4.effaddr;
268
269 if (fslw & MMU060_MA)
270 addr = (addr + PAGE_SIZE - 1) & PAGE_MASK;
271
272 errorcode = 1;
273 if (fslw & MMU060_DESC_ERR) {
274 __flush_tlb040_one(addr);
275 errorcode = 0;
276 }
277 if (fslw & MMU060_W)
278 errorcode |= 2;
279#ifdef DEBUG
280 printk("errorcode = %d\n", errorcode );
281#endif
282 do_page_fault(&fp->ptregs, addr, errorcode);
283 } else if (fslw & (MMU060_SEE)){
284 /* Software Emulation Error.
285 * fault during mem_read/mem_write in ifpsp060/os.S
286 */
287 send_fault_sig(&fp->ptregs);
288 } else if (!(fslw & (MMU060_RE|MMU060_WE)) ||
289 send_fault_sig(&fp->ptregs) > 0) {
290 printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr);
291 printk( "68060 access error, fslw=%lx\n", fslw );
292 trap_c( fp );
293 }
294}
295#endif /* CONFIG_M68060 */
296
297#if defined (CONFIG_M68040)
298static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
299{
300 unsigned long mmusr;
301 mm_segment_t old_fs = get_fs();
302
303 set_fs(MAKE_MM_SEG(wbs));
304
305 if (iswrite)
306 asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr));
307 else
308 asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr));
309
310 asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr));
311
312 set_fs(old_fs);
313
314 return mmusr;
315}
316
317static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
318 unsigned long wbd)
319{
320 int res = 0;
321 mm_segment_t old_fs = get_fs();
322
323 /* set_fs can not be moved, otherwise put_user() may oops */
324 set_fs(MAKE_MM_SEG(wbs));
325
326 switch (wbs & WBSIZ_040) {
327 case BA_SIZE_BYTE:
328 res = put_user(wbd & 0xff, (char __user *)wba);
329 break;
330 case BA_SIZE_WORD:
331 res = put_user(wbd & 0xffff, (short __user *)wba);
332 break;
333 case BA_SIZE_LONG:
334 res = put_user(wbd, (int __user *)wba);
335 break;
336 }
337
338 /* set_fs can not be moved, otherwise put_user() may oops */
339 set_fs(old_fs);
340
341
342#ifdef DEBUG
343 printk("do_040writeback1, res=%d\n",res);
344#endif
345
346 return res;
347}
348
349/* after an exception in a writeback the stack frame corresponding
350 * to that exception is discarded, set a few bits in the old frame
351 * to simulate what it should look like
352 */
353static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs)
354{
355 fp->un.fmt7.faddr = wba;
356 fp->un.fmt7.ssw = wbs & 0xff;
357 if (wba != current->thread.faddr)
358 fp->un.fmt7.ssw |= MA_040;
359}
360
361static inline void do_040writebacks(struct frame *fp)
362{
363 int res = 0;
364#if 0
365 if (fp->un.fmt7.wb1s & WBV_040)
366 printk("access_error040: cannot handle 1st writeback. oops.\n");
367#endif
368
369 if ((fp->un.fmt7.wb2s & WBV_040) &&
370 !(fp->un.fmt7.wb2s & WBTT_040)) {
371 res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
372 fp->un.fmt7.wb2d);
373 if (res)
374 fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s);
375 else
376 fp->un.fmt7.wb2s = 0;
377 }
378
379 /* do the 2nd wb only if the first one was successful (except for a kernel wb) */
380 if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
381 res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
382 fp->un.fmt7.wb3d);
383 if (res)
384 {
385 fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s);
386
387 fp->un.fmt7.wb2s = fp->un.fmt7.wb3s;
388 fp->un.fmt7.wb3s &= (~WBV_040);
389 fp->un.fmt7.wb2a = fp->un.fmt7.wb3a;
390 fp->un.fmt7.wb2d = fp->un.fmt7.wb3d;
391 }
392 else
393 fp->un.fmt7.wb3s = 0;
394 }
395
396 if (res)
397 send_fault_sig(&fp->ptregs);
398}
399
400/*
401 * called from sigreturn(), must ensure userspace code didn't
402 * manipulate exception frame to circumvent protection, then complete
403 * pending writebacks
404 * we just clear TM2 to turn it into a userspace access
405 */
406asmlinkage void berr_040cleanup(struct frame *fp)
407{
408 fp->un.fmt7.wb2s &= ~4;
409 fp->un.fmt7.wb3s &= ~4;
410
411 do_040writebacks(fp);
412}
413
414static inline void access_error040(struct frame *fp)
415{
416 unsigned short ssw = fp->un.fmt7.ssw;
417 unsigned long mmusr;
418
419#ifdef DEBUG
420 printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
421 printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,
422 fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
423 printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n",
424 fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
425 fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
426#endif
427
428 if (ssw & ATC_040) {
429 unsigned long addr = fp->un.fmt7.faddr;
430 unsigned long errorcode;
431
432 /*
433 * The MMU status has to be determined AFTER the address
434 * has been corrected if there was a misaligned access (MA).
435 */
436 if (ssw & MA_040)
437 addr = (addr + 7) & -8;
438
439 /* MMU error, get the MMUSR info for this access */
440 mmusr = probe040(!(ssw & RW_040), addr, ssw);
441#ifdef DEBUG
442 printk("mmusr = %lx\n", mmusr);
443#endif
444 errorcode = 1;
445 if (!(mmusr & MMU_R_040)) {
446 /* clear the invalid atc entry */
447 __flush_tlb040_one(addr);
448 errorcode = 0;
449 }
450
451 /* despite what documentation seems to say, RMW
452 * accesses have always both the LK and RW bits set */
453 if (!(ssw & RW_040) || (ssw & LK_040))
454 errorcode |= 2;
455
456 if (do_page_fault(&fp->ptregs, addr, errorcode)) {
457#ifdef DEBUG
458 printk("do_page_fault() !=0\n");
459#endif
460 if (user_mode(&fp->ptregs)){
461 /* delay writebacks after signal delivery */
462#ifdef DEBUG
463 printk(".. was usermode - return\n");
464#endif
465 return;
466 }
467 /* disable writeback into user space from kernel
468 * (if do_page_fault didn't fix the mapping,
469 * the writeback won't do good)
470 */
471disable_wb:
472#ifdef DEBUG
473 printk(".. disabling wb2\n");
474#endif
475 if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr)
476 fp->un.fmt7.wb2s &= ~WBV_040;
477 if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr)
478 fp->un.fmt7.wb3s &= ~WBV_040;
479 }
480 } else {
481 /* In case of a bus error we either kill the process or expect
482 * the kernel to catch the fault, which then is also responsible
483 * for cleaning up the mess.
484 */
485 current->thread.signo = SIGBUS;
486 current->thread.faddr = fp->un.fmt7.faddr;
487 if (send_fault_sig(&fp->ptregs) >= 0)
488 printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw,
489 fp->un.fmt7.faddr);
490 goto disable_wb;
491 }
492
493 do_040writebacks(fp);
494}
495#endif /* CONFIG_M68040 */
496
497#if defined(CONFIG_SUN3)
498#include <asm/sun3mmu.h>
499
500extern int mmu_emu_handle_fault (unsigned long, int, int);
501
502/* sun3 version of bus_error030 */
503
504static inline void bus_error030 (struct frame *fp)
505{
506 unsigned char buserr_type = sun3_get_buserr ();
507 unsigned long addr, errorcode;
508 unsigned short ssw = fp->un.fmtb.ssw;
509 extern unsigned long _sun3_map_test_start, _sun3_map_test_end;
510
511#ifdef DEBUG
512 if (ssw & (FC | FB))
513 printk ("Instruction fault at %#010lx\n",
514 ssw & FC ?
515 fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
516 :
517 fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
518 if (ssw & DF)
519 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
520 ssw & RW ? "read" : "write",
521 fp->un.fmtb.daddr,
522 space_names[ssw & DFC], fp->ptregs.pc);
523#endif
524
525 /*
526 * Check if this page should be demand-mapped. This needs to go before
527 * the testing for a bad kernel-space access (demand-mapping applies
528 * to kernel accesses too).
529 */
530
531 if ((ssw & DF)
532 && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
533 if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
534 return;
535 }
536
537 /* Check for kernel-space pagefault (BAD). */
538 if (fp->ptregs.sr & PS_S) {
539 /* kernel fault must be a data fault to user space */
540 if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
541 // try checking the kernel mappings before surrender
542 if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
543 return;
544 /* instruction fault or kernel data fault! */
545 if (ssw & (FC | FB))
546 printk ("Instruction fault at %#010lx\n",
547 fp->ptregs.pc);
548 if (ssw & DF) {
549 /* was this fault incurred testing bus mappings? */
550 if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) &&
551 (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) {
552 send_fault_sig(&fp->ptregs);
553 return;
554 }
555
556 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
557 ssw & RW ? "read" : "write",
558 fp->un.fmtb.daddr,
559 space_names[ssw & DFC], fp->ptregs.pc);
560 }
561 printk ("BAD KERNEL BUSERR\n");
562
563 die_if_kernel("Oops", &fp->ptregs,0);
564 force_sig(SIGKILL, current);
565 return;
566 }
567 } else {
568 /* user fault */
569 if (!(ssw & (FC | FB)) && !(ssw & DF))
570 /* not an instruction fault or data fault! BAD */
571 panic ("USER BUSERR w/o instruction or data fault");
572 }
573
574
575 /* First handle the data fault, if any. */
576 if (ssw & DF) {
577 addr = fp->un.fmtb.daddr;
578
579// errorcode bit 0: 0 -> no page 1 -> protection fault
580// errorcode bit 1: 0 -> read fault 1 -> write fault
581
582// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault
583// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault
584
585 if (buserr_type & SUN3_BUSERR_PROTERR)
586 errorcode = 0x01;
587 else if (buserr_type & SUN3_BUSERR_INVALID)
588 errorcode = 0x00;
589 else {
590#ifdef DEBUG
591 printk ("*** unexpected busfault type=%#04x\n", buserr_type);
592 printk ("invalid %s access at %#lx from pc %#lx\n",
593 !(ssw & RW) ? "write" : "read", addr,
594 fp->ptregs.pc);
595#endif
596 die_if_kernel ("Oops", &fp->ptregs, buserr_type);
597 force_sig (SIGBUS, current);
598 return;
599 }
600
601//todo: wtf is RM bit? --m
602 if (!(ssw & RW) || ssw & RM)
603 errorcode |= 0x02;
604
605 /* Handle page fault. */
606 do_page_fault (&fp->ptregs, addr, errorcode);
607
608 /* Retry the data fault now. */
609 return;
610 }
611
612 /* Now handle the instruction fault. */
613
614 /* Get the fault address. */
615 if (fp->ptregs.format == 0xA)
616 addr = fp->ptregs.pc + 4;
617 else
618 addr = fp->un.fmtb.baddr;
619 if (ssw & FC)
620 addr -= 2;
621
622 if (buserr_type & SUN3_BUSERR_INVALID) {
623 if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
624 do_page_fault (&fp->ptregs, addr, 0);
625 } else {
626#ifdef DEBUG
627 printk ("protection fault on insn access (segv).\n");
628#endif
629 force_sig (SIGSEGV, current);
630 }
631}
632#else
633#if defined(CPU_M68020_OR_M68030)
634static inline void bus_error030 (struct frame *fp)
635{
636 volatile unsigned short temp;
637 unsigned short mmusr;
638 unsigned long addr, errorcode;
639 unsigned short ssw = fp->un.fmtb.ssw;
640#ifdef DEBUG
641 unsigned long desc;
642
643 printk ("pid = %x ", current->pid);
644 printk ("SSW=%#06x ", ssw);
645
646 if (ssw & (FC | FB))
647 printk ("Instruction fault at %#010lx\n",
648 ssw & FC ?
649 fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
650 :
651 fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
652 if (ssw & DF)
653 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
654 ssw & RW ? "read" : "write",
655 fp->un.fmtb.daddr,
656 space_names[ssw & DFC], fp->ptregs.pc);
657#endif
658
659 /* ++andreas: If a data fault and an instruction fault happen
660 at the same time map in both pages. */
661
662 /* First handle the data fault, if any. */
663 if (ssw & DF) {
664 addr = fp->un.fmtb.daddr;
665
666#ifdef DEBUG
667 asm volatile ("ptestr %3,%2@,#7,%0\n\t"
668 "pmove %%psr,%1@"
669 : "=a&" (desc)
670 : "a" (&temp), "a" (addr), "d" (ssw));
671#else
672 asm volatile ("ptestr %2,%1@,#7\n\t"
673 "pmove %%psr,%0@"
674 : : "a" (&temp), "a" (addr), "d" (ssw));
675#endif
676 mmusr = temp;
677
678#ifdef DEBUG
679 printk("mmusr is %#x for addr %#lx in task %p\n",
680 mmusr, addr, current);
681 printk("descriptor address is %#lx, contents %#lx\n",
682 __va(desc), *(unsigned long *)__va(desc));
683#endif
684
685 errorcode = (mmusr & MMU_I) ? 0 : 1;
686 if (!(ssw & RW) || (ssw & RM))
687 errorcode |= 2;
688
689 if (mmusr & (MMU_I | MMU_WP)) {
690 if (ssw & 4) {
691 printk("Data %s fault at %#010lx in %s (pc=%#lx)\n",
692 ssw & RW ? "read" : "write",
693 fp->un.fmtb.daddr,
694 space_names[ssw & DFC], fp->ptregs.pc);
695 goto buserr;
696 }
697 /* Don't try to do anything further if an exception was
698 handled. */
699 if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
700 return;
701 } else if (!(mmusr & MMU_I)) {
702 /* probably a 020 cas fault */
703 if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0)
704 printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr);
705 } else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
706 printk("invalid %s access at %#lx from pc %#lx\n",
707 !(ssw & RW) ? "write" : "read", addr,
708 fp->ptregs.pc);
709 die_if_kernel("Oops",&fp->ptregs,mmusr);
710 force_sig(SIGSEGV, current);
711 return;
712 } else {
713#if 0
714 static volatile long tlong;
715#endif
716
717 printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
718 !(ssw & RW) ? "write" : "read", addr,
719 fp->ptregs.pc, ssw);
720 asm volatile ("ptestr #1,%1@,#0\n\t"
721 "pmove %%psr,%0@"
722 : /* no outputs */
723 : "a" (&temp), "a" (addr));
724 mmusr = temp;
725
726 printk ("level 0 mmusr is %#x\n", mmusr);
727#if 0
728 asm volatile ("pmove %%tt0,%0@"
729 : /* no outputs */
730 : "a" (&tlong));
731 printk("tt0 is %#lx, ", tlong);
732 asm volatile ("pmove %%tt1,%0@"
733 : /* no outputs */
734 : "a" (&tlong));
735 printk("tt1 is %#lx\n", tlong);
736#endif
737#ifdef DEBUG
738 printk("Unknown SIGSEGV - 1\n");
739#endif
740 die_if_kernel("Oops",&fp->ptregs,mmusr);
741 force_sig(SIGSEGV, current);
742 return;
743 }
744
745 /* setup an ATC entry for the access about to be retried */
746 if (!(ssw & RW) || (ssw & RM))
747 asm volatile ("ploadw %1,%0@" : /* no outputs */
748 : "a" (addr), "d" (ssw));
749 else
750 asm volatile ("ploadr %1,%0@" : /* no outputs */
751 : "a" (addr), "d" (ssw));
752 }
753
754 /* Now handle the instruction fault. */
755
756 if (!(ssw & (FC|FB)))
757 return;
758
759 if (fp->ptregs.sr & PS_S) {
760 printk("Instruction fault at %#010lx\n",
761 fp->ptregs.pc);
762 buserr:
763 printk ("BAD KERNEL BUSERR\n");
764 die_if_kernel("Oops",&fp->ptregs,0);
765 force_sig(SIGKILL, current);
766 return;
767 }
768
769 /* get the fault address */
770 if (fp->ptregs.format == 10)
771 addr = fp->ptregs.pc + 4;
772 else
773 addr = fp->un.fmtb.baddr;
774 if (ssw & FC)
775 addr -= 2;
776
777 if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
778 /* Insn fault on same page as data fault. But we
779 should still create the ATC entry. */
780 goto create_atc_entry;
781
782#ifdef DEBUG
783 asm volatile ("ptestr #1,%2@,#7,%0\n\t"
784 "pmove %%psr,%1@"
785 : "=a&" (desc)
786 : "a" (&temp), "a" (addr));
787#else
788 asm volatile ("ptestr #1,%1@,#7\n\t"
789 "pmove %%psr,%0@"
790 : : "a" (&temp), "a" (addr));
791#endif
792 mmusr = temp;
793
794#ifdef DEBUG
795 printk ("mmusr is %#x for addr %#lx in task %p\n",
796 mmusr, addr, current);
797 printk ("descriptor address is %#lx, contents %#lx\n",
798 __va(desc), *(unsigned long *)__va(desc));
799#endif
800
801 if (mmusr & MMU_I)
802 do_page_fault (&fp->ptregs, addr, 0);
803 else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
804 printk ("invalid insn access at %#lx from pc %#lx\n",
805 addr, fp->ptregs.pc);
806#ifdef DEBUG
807 printk("Unknown SIGSEGV - 2\n");
808#endif
809 die_if_kernel("Oops",&fp->ptregs,mmusr);
810 force_sig(SIGSEGV, current);
811 return;
812 }
813
814create_atc_entry:
815 /* setup an ATC entry for the access about to be retried */
816 asm volatile ("ploadr #2,%0@" : /* no outputs */
817 : "a" (addr));
818}
819#endif /* CPU_M68020_OR_M68030 */
820#endif /* !CONFIG_SUN3 */
821
822asmlinkage void buserr_c(struct frame *fp)
823{
824 /* Only set esp0 if coming from user mode */
825 if (user_mode(&fp->ptregs))
826 current->thread.esp0 = (unsigned long) fp;
827
828#ifdef DEBUG
829 printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
830#endif
831
832 switch (fp->ptregs.format) {
833#if defined (CONFIG_M68060)
834 case 4: /* 68060 access error */
835 access_error060 (fp);
836 break;
837#endif
838#if defined (CONFIG_M68040)
839 case 0x7: /* 68040 access error */
840 access_error040 (fp);
841 break;
842#endif
843#if defined (CPU_M68020_OR_M68030)
844 case 0xa:
845 case 0xb:
846 bus_error030 (fp);
847 break;
848#endif
849 default:
850 die_if_kernel("bad frame format",&fp->ptregs,0);
851#ifdef DEBUG
852 printk("Unknown SIGSEGV - 4\n");
853#endif
854 force_sig(SIGSEGV, current);
855 }
856}
857
858
859static int kstack_depth_to_print = 48;
860
861void show_trace(unsigned long *stack)
862{
863 unsigned long *endstack;
864 unsigned long addr;
865 int i;
866
867 printk("Call Trace:");
868 addr = (unsigned long)stack + THREAD_SIZE - 1;
869 endstack = (unsigned long *)(addr & -THREAD_SIZE);
870 i = 0;
871 while (stack + 1 <= endstack) {
872 addr = *stack++;
873 /*
874 * If the address is either in the text segment of the
875 * kernel, or in the region which contains vmalloc'ed
876 * memory, it *may* be the address of a calling
877 * routine; if so, print it so that someone tracing
878 * down the cause of the crash will be able to figure
879 * out the call path that was taken.
880 */
881 if (__kernel_text_address(addr)) {
882#ifndef CONFIG_KALLSYMS
883 if (i % 5 == 0)
884 printk("\n ");
885#endif
886 printk(" [<%08lx>] %pS\n", addr, (void *)addr);
887 i++;
888 }
889 }
890 printk("\n");
891}
892
893void show_registers(struct pt_regs *regs)
894{
895 struct frame *fp = (struct frame *)regs;
896 mm_segment_t old_fs = get_fs();
897 u16 c, *cp;
898 unsigned long addr;
899 int i;
900
901 print_modules();
902 printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc);
903 printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2);
904 printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
905 regs->d0, regs->d1, regs->d2, regs->d3);
906 printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
907 regs->d4, regs->d5, regs->a0, regs->a1);
908
909 printk("Process %s (pid: %d, task=%p)\n",
910 current->comm, task_pid_nr(current), current);
911 addr = (unsigned long)&fp->un;
912 printk("Frame format=%X ", regs->format);
913 switch (regs->format) {
914 case 0x2:
915 printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
916 addr += sizeof(fp->un.fmt2);
917 break;
918 case 0x3:
919 printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
920 addr += sizeof(fp->un.fmt3);
921 break;
922 case 0x4:
923 printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
924 : "eff addr=%08lx pc=%08lx\n"),
925 fp->un.fmt4.effaddr, fp->un.fmt4.pc);
926 addr += sizeof(fp->un.fmt4);
927 break;
928 case 0x7:
929 printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
930 fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
931 printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
932 fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
933 printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
934 fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
935 printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
936 fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
937 printk("push data: %08lx %08lx %08lx %08lx\n",
938 fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
939 fp->un.fmt7.pd3);
940 addr += sizeof(fp->un.fmt7);
941 break;
942 case 0x9:
943 printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
944 addr += sizeof(fp->un.fmt9);
945 break;
946 case 0xa:
947 printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
948 fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
949 fp->un.fmta.daddr, fp->un.fmta.dobuf);
950 addr += sizeof(fp->un.fmta);
951 break;
952 case 0xb:
953 printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
954 fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
955 fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
956 printk("baddr=%08lx dibuf=%08lx ver=%x\n",
957 fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
958 addr += sizeof(fp->un.fmtb);
959 break;
960 default:
961 printk("\n");
962 }
963 show_stack(NULL, (unsigned long *)addr);
964
965 printk("Code:");
966 set_fs(KERNEL_DS);
967 cp = (u16 *)regs->pc;
968 for (i = -8; i < 16; i++) {
969 if (get_user(c, cp + i) && i >= 0) {
970 printk(" Bad PC value.");
971 break;
972 }
973 printk(i ? " %04x" : " <%04x>", c);
974 }
975 set_fs(old_fs);
976 printk ("\n");
977}
978
979void show_stack(struct task_struct *task, unsigned long *stack)
980{
981 unsigned long *p;
982 unsigned long *endstack;
983 int i;
984
985 if (!stack) {
986 if (task)
987 stack = (unsigned long *)task->thread.esp0;
988 else
989 stack = (unsigned long *)&stack;
990 }
991 endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
992
993 printk("Stack from %08lx:", (unsigned long)stack);
994 p = stack;
995 for (i = 0; i < kstack_depth_to_print; i++) {
996 if (p + 1 > endstack)
997 break;
998 if (i % 8 == 0)
999 printk("\n ");
1000 printk(" %08lx", *p++);
1001 }
1002 printk("\n");
1003 show_trace(stack);
1004}
1005
1006/*
1007 * The architecture-independent backtrace generator
1008 */
1009void dump_stack(void)
1010{
1011 unsigned long stack;
1012
1013 show_trace(&stack);
1014}
1015
1016EXPORT_SYMBOL(dump_stack);
1017
1018void bad_super_trap (struct frame *fp)
1019{
1020 console_verbose();
1021 if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
1022 printk ("*** %s *** FORMAT=%X\n",
1023 vec_names[(fp->ptregs.vector) >> 2],
1024 fp->ptregs.format);
1025 else
1026 printk ("*** Exception %d *** FORMAT=%X\n",
1027 (fp->ptregs.vector) >> 2,
1028 fp->ptregs.format);
1029 if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) {
1030 unsigned short ssw = fp->un.fmtb.ssw;
1031
1032 printk ("SSW=%#06x ", ssw);
1033
1034 if (ssw & RC)
1035 printk ("Pipe stage C instruction fault at %#010lx\n",
1036 (fp->ptregs.format) == 0xA ?
1037 fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
1038 if (ssw & RB)
1039 printk ("Pipe stage B instruction fault at %#010lx\n",
1040 (fp->ptregs.format) == 0xA ?
1041 fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
1042 if (ssw & DF)
1043 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
1044 ssw & RW ? "read" : "write",
1045 fp->un.fmtb.daddr, space_names[ssw & DFC],
1046 fp->ptregs.pc);
1047 }
1048 printk ("Current process id is %d\n", task_pid_nr(current));
1049 die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
1050}
1051
1052asmlinkage void trap_c(struct frame *fp)
1053{
1054 int sig;
1055 siginfo_t info;
1056
1057 if (fp->ptregs.sr & PS_S) {
1058 if ((fp->ptregs.vector >> 2) == VEC_TRACE) {
1059 /* traced a trapping instruction */
1060 } else
1061 bad_super_trap(fp);
1062 return;
1063 }
1064
1065 /* send the appropriate signal to the user program */
1066 switch ((fp->ptregs.vector) >> 2) {
1067 case VEC_ADDRERR:
1068 info.si_code = BUS_ADRALN;
1069 sig = SIGBUS;
1070 break;
1071 case VEC_ILLEGAL:
1072 case VEC_LINE10:
1073 case VEC_LINE11:
1074 info.si_code = ILL_ILLOPC;
1075 sig = SIGILL;
1076 break;
1077 case VEC_PRIV:
1078 info.si_code = ILL_PRVOPC;
1079 sig = SIGILL;
1080 break;
1081 case VEC_COPROC:
1082 info.si_code = ILL_COPROC;
1083 sig = SIGILL;
1084 break;
1085 case VEC_TRAP1:
1086 case VEC_TRAP2:
1087 case VEC_TRAP3:
1088 case VEC_TRAP4:
1089 case VEC_TRAP5:
1090 case VEC_TRAP6:
1091 case VEC_TRAP7:
1092 case VEC_TRAP8:
1093 case VEC_TRAP9:
1094 case VEC_TRAP10:
1095 case VEC_TRAP11:
1096 case VEC_TRAP12:
1097 case VEC_TRAP13:
1098 case VEC_TRAP14:
1099 info.si_code = ILL_ILLTRP;
1100 sig = SIGILL;
1101 break;
1102 case VEC_FPBRUC:
1103 case VEC_FPOE:
1104 case VEC_FPNAN:
1105 info.si_code = FPE_FLTINV;
1106 sig = SIGFPE;
1107 break;
1108 case VEC_FPIR:
1109 info.si_code = FPE_FLTRES;
1110 sig = SIGFPE;
1111 break;
1112 case VEC_FPDIVZ:
1113 info.si_code = FPE_FLTDIV;
1114 sig = SIGFPE;
1115 break;
1116 case VEC_FPUNDER:
1117 info.si_code = FPE_FLTUND;
1118 sig = SIGFPE;
1119 break;
1120 case VEC_FPOVER:
1121 info.si_code = FPE_FLTOVF;
1122 sig = SIGFPE;
1123 break;
1124 case VEC_ZERODIV:
1125 info.si_code = FPE_INTDIV;
1126 sig = SIGFPE;
1127 break;
1128 case VEC_CHK:
1129 case VEC_TRAP:
1130 info.si_code = FPE_INTOVF;
1131 sig = SIGFPE;
1132 break;
1133 case VEC_TRACE: /* ptrace single step */
1134 info.si_code = TRAP_TRACE;
1135 sig = SIGTRAP;
1136 break;
1137 case VEC_TRAP15: /* breakpoint */
1138 info.si_code = TRAP_BRKPT;
1139 sig = SIGTRAP;
1140 break;
1141 default:
1142 info.si_code = ILL_ILLOPC;
1143 sig = SIGILL;
1144 break;
1145 }
1146 info.si_signo = sig;
1147 info.si_errno = 0;
1148 switch (fp->ptregs.format) {
1149 default:
1150 info.si_addr = (void *) fp->ptregs.pc;
1151 break;
1152 case 2:
1153 info.si_addr = (void *) fp->un.fmt2.iaddr;
1154 break;
1155 case 7:
1156 info.si_addr = (void *) fp->un.fmt7.effaddr;
1157 break;
1158 case 9:
1159 info.si_addr = (void *) fp->un.fmt9.iaddr;
1160 break;
1161 case 10:
1162 info.si_addr = (void *) fp->un.fmta.daddr;
1163 break;
1164 case 11:
1165 info.si_addr = (void *) fp->un.fmtb.daddr;
1166 break;
1167 }
1168 force_sig_info (sig, &info, current);
1169}
1170
1171void die_if_kernel (char *str, struct pt_regs *fp, int nr)
1172{
1173 if (!(fp->sr & PS_S))
1174 return;
1175
1176 console_verbose();
1177 printk("%s: %08x\n",str,nr);
1178 show_registers(fp);
1179 add_taint(TAINT_DIE);
1180 do_exit(SIGSEGV);
1181}
1182
1183/*
1184 * This function is called if an error occur while accessing
1185 * user-space from the fpsp040 code.
1186 */
1187asmlinkage void fpsp040_die(void)
1188{
1189 do_exit(SIGSEGV);
1190}
1191
1192#ifdef CONFIG_M68KFPU_EMU
1193asmlinkage void fpemu_signal(int signal, int code, void *addr)
1194{
1195 siginfo_t info;
1196
1197 info.si_signo = signal;
1198 info.si_errno = 0;
1199 info.si_code = code;
1200 info.si_addr = addr;
1201 force_sig_info(signal, &info, current);
1202}
1203#endif 5#endif
diff --git a/arch/m68k/kernel/traps_mm.c b/arch/m68k/kernel/traps_mm.c
new file mode 100644
index 000000000000..4022bbc28878
--- /dev/null
+++ b/arch/m68k/kernel/traps_mm.c
@@ -0,0 +1,1207 @@
1/*
2 * linux/arch/m68k/kernel/traps.c
3 *
4 * Copyright (C) 1993, 1994 by Hamish Macdonald
5 *
6 * 68040 fixes by Michael Rausch
7 * 68040 fixes by Martin Apel
8 * 68040 fixes and writeback by Richard Zidlicky
9 * 68060 fixes by Roman Hodek
10 * 68060 fixes by Jesper Skov
11 *
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive
14 * for more details.
15 */
16
17/*
18 * Sets up all exception vectors
19 */
20
21#include <linux/sched.h>
22#include <linux/signal.h>
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/module.h>
26#include <linux/user.h>
27#include <linux/string.h>
28#include <linux/linkage.h>
29#include <linux/init.h>
30#include <linux/ptrace.h>
31#include <linux/kallsyms.h>
32
33#include <asm/setup.h>
34#include <asm/fpu.h>
35#include <asm/system.h>
36#include <asm/uaccess.h>
37#include <asm/traps.h>
38#include <asm/pgalloc.h>
39#include <asm/machdep.h>
40#include <asm/siginfo.h>
41
42/* assembler routines */
43asmlinkage void system_call(void);
44asmlinkage void buserr(void);
45asmlinkage void trap(void);
46asmlinkage void nmihandler(void);
47#ifdef CONFIG_M68KFPU_EMU
48asmlinkage void fpu_emu(void);
49#endif
50
51e_vector vectors[256];
52
53/* nmi handler for the Amiga */
54asm(".text\n"
55 __ALIGN_STR "\n"
56 "nmihandler: rte");
57
58/*
59 * this must be called very early as the kernel might
60 * use some instruction that are emulated on the 060
61 * and so we're prepared for early probe attempts (e.g. nf_init).
62 */
63void __init base_trap_init(void)
64{
65 if (MACH_IS_SUN3X) {
66 extern e_vector *sun3x_prom_vbr;
67
68 __asm__ volatile ("movec %%vbr, %0" : "=r" (sun3x_prom_vbr));
69 }
70
71 /* setup the exception vector table */
72 __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
73
74 if (CPU_IS_060) {
75 /* set up ISP entry points */
76 asmlinkage void unimp_vec(void) asm ("_060_isp_unimp");
77
78 vectors[VEC_UNIMPII] = unimp_vec;
79 }
80
81 vectors[VEC_BUSERR] = buserr;
82 vectors[VEC_ILLEGAL] = trap;
83 vectors[VEC_SYS] = system_call;
84}
85
86void __init trap_init (void)
87{
88 int i;
89
90 for (i = VEC_SPUR; i <= VEC_INT7; i++)
91 vectors[i] = bad_inthandler;
92
93 for (i = 0; i < VEC_USER; i++)
94 if (!vectors[i])
95 vectors[i] = trap;
96
97 for (i = VEC_USER; i < 256; i++)
98 vectors[i] = bad_inthandler;
99
100#ifdef CONFIG_M68KFPU_EMU
101 if (FPU_IS_EMU)
102 vectors[VEC_LINE11] = fpu_emu;
103#endif
104
105 if (CPU_IS_040 && !FPU_IS_EMU) {
106 /* set up FPSP entry points */
107 asmlinkage void dz_vec(void) asm ("dz");
108 asmlinkage void inex_vec(void) asm ("inex");
109 asmlinkage void ovfl_vec(void) asm ("ovfl");
110 asmlinkage void unfl_vec(void) asm ("unfl");
111 asmlinkage void snan_vec(void) asm ("snan");
112 asmlinkage void operr_vec(void) asm ("operr");
113 asmlinkage void bsun_vec(void) asm ("bsun");
114 asmlinkage void fline_vec(void) asm ("fline");
115 asmlinkage void unsupp_vec(void) asm ("unsupp");
116
117 vectors[VEC_FPDIVZ] = dz_vec;
118 vectors[VEC_FPIR] = inex_vec;
119 vectors[VEC_FPOVER] = ovfl_vec;
120 vectors[VEC_FPUNDER] = unfl_vec;
121 vectors[VEC_FPNAN] = snan_vec;
122 vectors[VEC_FPOE] = operr_vec;
123 vectors[VEC_FPBRUC] = bsun_vec;
124 vectors[VEC_LINE11] = fline_vec;
125 vectors[VEC_FPUNSUP] = unsupp_vec;
126 }
127
128 if (CPU_IS_060 && !FPU_IS_EMU) {
129 /* set up IFPSP entry points */
130 asmlinkage void snan_vec6(void) asm ("_060_fpsp_snan");
131 asmlinkage void operr_vec6(void) asm ("_060_fpsp_operr");
132 asmlinkage void ovfl_vec6(void) asm ("_060_fpsp_ovfl");
133 asmlinkage void unfl_vec6(void) asm ("_060_fpsp_unfl");
134 asmlinkage void dz_vec6(void) asm ("_060_fpsp_dz");
135 asmlinkage void inex_vec6(void) asm ("_060_fpsp_inex");
136 asmlinkage void fline_vec6(void) asm ("_060_fpsp_fline");
137 asmlinkage void unsupp_vec6(void) asm ("_060_fpsp_unsupp");
138 asmlinkage void effadd_vec6(void) asm ("_060_fpsp_effadd");
139
140 vectors[VEC_FPNAN] = snan_vec6;
141 vectors[VEC_FPOE] = operr_vec6;
142 vectors[VEC_FPOVER] = ovfl_vec6;
143 vectors[VEC_FPUNDER] = unfl_vec6;
144 vectors[VEC_FPDIVZ] = dz_vec6;
145 vectors[VEC_FPIR] = inex_vec6;
146 vectors[VEC_LINE11] = fline_vec6;
147 vectors[VEC_FPUNSUP] = unsupp_vec6;
148 vectors[VEC_UNIMPEA] = effadd_vec6;
149 }
150
151 /* if running on an amiga, make the NMI interrupt do nothing */
152 if (MACH_IS_AMIGA) {
153 vectors[VEC_INT7] = nmihandler;
154 }
155}
156
157
158static const char *vec_names[] = {
159 [VEC_RESETSP] = "RESET SP",
160 [VEC_RESETPC] = "RESET PC",
161 [VEC_BUSERR] = "BUS ERROR",
162 [VEC_ADDRERR] = "ADDRESS ERROR",
163 [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION",
164 [VEC_ZERODIV] = "ZERO DIVIDE",
165 [VEC_CHK] = "CHK",
166 [VEC_TRAP] = "TRAPcc",
167 [VEC_PRIV] = "PRIVILEGE VIOLATION",
168 [VEC_TRACE] = "TRACE",
169 [VEC_LINE10] = "LINE 1010",
170 [VEC_LINE11] = "LINE 1111",
171 [VEC_RESV12] = "UNASSIGNED RESERVED 12",
172 [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION",
173 [VEC_FORMAT] = "FORMAT ERROR",
174 [VEC_UNINT] = "UNINITIALIZED INTERRUPT",
175 [VEC_RESV16] = "UNASSIGNED RESERVED 16",
176 [VEC_RESV17] = "UNASSIGNED RESERVED 17",
177 [VEC_RESV18] = "UNASSIGNED RESERVED 18",
178 [VEC_RESV19] = "UNASSIGNED RESERVED 19",
179 [VEC_RESV20] = "UNASSIGNED RESERVED 20",
180 [VEC_RESV21] = "UNASSIGNED RESERVED 21",
181 [VEC_RESV22] = "UNASSIGNED RESERVED 22",
182 [VEC_RESV23] = "UNASSIGNED RESERVED 23",
183 [VEC_SPUR] = "SPURIOUS INTERRUPT",
184 [VEC_INT1] = "LEVEL 1 INT",
185 [VEC_INT2] = "LEVEL 2 INT",
186 [VEC_INT3] = "LEVEL 3 INT",
187 [VEC_INT4] = "LEVEL 4 INT",
188 [VEC_INT5] = "LEVEL 5 INT",
189 [VEC_INT6] = "LEVEL 6 INT",
190 [VEC_INT7] = "LEVEL 7 INT",
191 [VEC_SYS] = "SYSCALL",
192 [VEC_TRAP1] = "TRAP #1",
193 [VEC_TRAP2] = "TRAP #2",
194 [VEC_TRAP3] = "TRAP #3",
195 [VEC_TRAP4] = "TRAP #4",
196 [VEC_TRAP5] = "TRAP #5",
197 [VEC_TRAP6] = "TRAP #6",
198 [VEC_TRAP7] = "TRAP #7",
199 [VEC_TRAP8] = "TRAP #8",
200 [VEC_TRAP9] = "TRAP #9",
201 [VEC_TRAP10] = "TRAP #10",
202 [VEC_TRAP11] = "TRAP #11",
203 [VEC_TRAP12] = "TRAP #12",
204 [VEC_TRAP13] = "TRAP #13",
205 [VEC_TRAP14] = "TRAP #14",
206 [VEC_TRAP15] = "TRAP #15",
207 [VEC_FPBRUC] = "FPCP BSUN",
208 [VEC_FPIR] = "FPCP INEXACT",
209 [VEC_FPDIVZ] = "FPCP DIV BY 0",
210 [VEC_FPUNDER] = "FPCP UNDERFLOW",
211 [VEC_FPOE] = "FPCP OPERAND ERROR",
212 [VEC_FPOVER] = "FPCP OVERFLOW",
213 [VEC_FPNAN] = "FPCP SNAN",
214 [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION",
215 [VEC_MMUCFG] = "MMU CONFIGURATION ERROR",
216 [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR",
217 [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR",
218 [VEC_RESV59] = "UNASSIGNED RESERVED 59",
219 [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60",
220 [VEC_UNIMPII] = "UNASSIGNED RESERVED 61",
221 [VEC_RESV62] = "UNASSIGNED RESERVED 62",
222 [VEC_RESV63] = "UNASSIGNED RESERVED 63",
223};
224
225static const char *space_names[] = {
226 [0] = "Space 0",
227 [USER_DATA] = "User Data",
228 [USER_PROGRAM] = "User Program",
229#ifndef CONFIG_SUN3
230 [3] = "Space 3",
231#else
232 [FC_CONTROL] = "Control",
233#endif
234 [4] = "Space 4",
235 [SUPER_DATA] = "Super Data",
236 [SUPER_PROGRAM] = "Super Program",
237 [CPU_SPACE] = "CPU"
238};
239
240void die_if_kernel(char *,struct pt_regs *,int);
241asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
242 unsigned long error_code);
243int send_fault_sig(struct pt_regs *regs);
244
245asmlinkage void trap_c(struct frame *fp);
246
247#if defined (CONFIG_M68060)
248static inline void access_error060 (struct frame *fp)
249{
250 unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */
251
252#ifdef DEBUG
253 printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr);
254#endif
255
256 if (fslw & MMU060_BPE) {
257 /* branch prediction error -> clear branch cache */
258 __asm__ __volatile__ ("movec %/cacr,%/d0\n\t"
259 "orl #0x00400000,%/d0\n\t"
260 "movec %/d0,%/cacr"
261 : : : "d0" );
262 /* return if there's no other error */
263 if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE))
264 return;
265 }
266
267 if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) {
268 unsigned long errorcode;
269 unsigned long addr = fp->un.fmt4.effaddr;
270
271 if (fslw & MMU060_MA)
272 addr = (addr + PAGE_SIZE - 1) & PAGE_MASK;
273
274 errorcode = 1;
275 if (fslw & MMU060_DESC_ERR) {
276 __flush_tlb040_one(addr);
277 errorcode = 0;
278 }
279 if (fslw & MMU060_W)
280 errorcode |= 2;
281#ifdef DEBUG
282 printk("errorcode = %d\n", errorcode );
283#endif
284 do_page_fault(&fp->ptregs, addr, errorcode);
285 } else if (fslw & (MMU060_SEE)){
286 /* Software Emulation Error.
287 * fault during mem_read/mem_write in ifpsp060/os.S
288 */
289 send_fault_sig(&fp->ptregs);
290 } else if (!(fslw & (MMU060_RE|MMU060_WE)) ||
291 send_fault_sig(&fp->ptregs) > 0) {
292 printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr);
293 printk( "68060 access error, fslw=%lx\n", fslw );
294 trap_c( fp );
295 }
296}
297#endif /* CONFIG_M68060 */
298
299#if defined (CONFIG_M68040)
300static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs)
301{
302 unsigned long mmusr;
303 mm_segment_t old_fs = get_fs();
304
305 set_fs(MAKE_MM_SEG(wbs));
306
307 if (iswrite)
308 asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr));
309 else
310 asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr));
311
312 asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr));
313
314 set_fs(old_fs);
315
316 return mmusr;
317}
318
319static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
320 unsigned long wbd)
321{
322 int res = 0;
323 mm_segment_t old_fs = get_fs();
324
325 /* set_fs can not be moved, otherwise put_user() may oops */
326 set_fs(MAKE_MM_SEG(wbs));
327
328 switch (wbs & WBSIZ_040) {
329 case BA_SIZE_BYTE:
330 res = put_user(wbd & 0xff, (char __user *)wba);
331 break;
332 case BA_SIZE_WORD:
333 res = put_user(wbd & 0xffff, (short __user *)wba);
334 break;
335 case BA_SIZE_LONG:
336 res = put_user(wbd, (int __user *)wba);
337 break;
338 }
339
340 /* set_fs can not be moved, otherwise put_user() may oops */
341 set_fs(old_fs);
342
343
344#ifdef DEBUG
345 printk("do_040writeback1, res=%d\n",res);
346#endif
347
348 return res;
349}
350
351/* after an exception in a writeback the stack frame corresponding
352 * to that exception is discarded, set a few bits in the old frame
353 * to simulate what it should look like
354 */
355static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs)
356{
357 fp->un.fmt7.faddr = wba;
358 fp->un.fmt7.ssw = wbs & 0xff;
359 if (wba != current->thread.faddr)
360 fp->un.fmt7.ssw |= MA_040;
361}
362
363static inline void do_040writebacks(struct frame *fp)
364{
365 int res = 0;
366#if 0
367 if (fp->un.fmt7.wb1s & WBV_040)
368 printk("access_error040: cannot handle 1st writeback. oops.\n");
369#endif
370
371 if ((fp->un.fmt7.wb2s & WBV_040) &&
372 !(fp->un.fmt7.wb2s & WBTT_040)) {
373 res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a,
374 fp->un.fmt7.wb2d);
375 if (res)
376 fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s);
377 else
378 fp->un.fmt7.wb2s = 0;
379 }
380
381 /* do the 2nd wb only if the first one was successful (except for a kernel wb) */
382 if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) {
383 res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a,
384 fp->un.fmt7.wb3d);
385 if (res)
386 {
387 fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s);
388
389 fp->un.fmt7.wb2s = fp->un.fmt7.wb3s;
390 fp->un.fmt7.wb3s &= (~WBV_040);
391 fp->un.fmt7.wb2a = fp->un.fmt7.wb3a;
392 fp->un.fmt7.wb2d = fp->un.fmt7.wb3d;
393 }
394 else
395 fp->un.fmt7.wb3s = 0;
396 }
397
398 if (res)
399 send_fault_sig(&fp->ptregs);
400}
401
402/*
403 * called from sigreturn(), must ensure userspace code didn't
404 * manipulate exception frame to circumvent protection, then complete
405 * pending writebacks
406 * we just clear TM2 to turn it into a userspace access
407 */
408asmlinkage void berr_040cleanup(struct frame *fp)
409{
410 fp->un.fmt7.wb2s &= ~4;
411 fp->un.fmt7.wb3s &= ~4;
412
413 do_040writebacks(fp);
414}
415
416static inline void access_error040(struct frame *fp)
417{
418 unsigned short ssw = fp->un.fmt7.ssw;
419 unsigned long mmusr;
420
421#ifdef DEBUG
422 printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr);
423 printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s,
424 fp->un.fmt7.wb2s, fp->un.fmt7.wb3s);
425 printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n",
426 fp->un.fmt7.wb2a, fp->un.fmt7.wb3a,
427 fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);
428#endif
429
430 if (ssw & ATC_040) {
431 unsigned long addr = fp->un.fmt7.faddr;
432 unsigned long errorcode;
433
434 /*
435 * The MMU status has to be determined AFTER the address
436 * has been corrected if there was a misaligned access (MA).
437 */
438 if (ssw & MA_040)
439 addr = (addr + 7) & -8;
440
441 /* MMU error, get the MMUSR info for this access */
442 mmusr = probe040(!(ssw & RW_040), addr, ssw);
443#ifdef DEBUG
444 printk("mmusr = %lx\n", mmusr);
445#endif
446 errorcode = 1;
447 if (!(mmusr & MMU_R_040)) {
448 /* clear the invalid atc entry */
449 __flush_tlb040_one(addr);
450 errorcode = 0;
451 }
452
453 /* despite what documentation seems to say, RMW
454 * accesses have always both the LK and RW bits set */
455 if (!(ssw & RW_040) || (ssw & LK_040))
456 errorcode |= 2;
457
458 if (do_page_fault(&fp->ptregs, addr, errorcode)) {
459#ifdef DEBUG
460 printk("do_page_fault() !=0\n");
461#endif
462 if (user_mode(&fp->ptregs)){
463 /* delay writebacks after signal delivery */
464#ifdef DEBUG
465 printk(".. was usermode - return\n");
466#endif
467 return;
468 }
469 /* disable writeback into user space from kernel
470 * (if do_page_fault didn't fix the mapping,
471 * the writeback won't do good)
472 */
473disable_wb:
474#ifdef DEBUG
475 printk(".. disabling wb2\n");
476#endif
477 if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr)
478 fp->un.fmt7.wb2s &= ~WBV_040;
479 if (fp->un.fmt7.wb3a == fp->un.fmt7.faddr)
480 fp->un.fmt7.wb3s &= ~WBV_040;
481 }
482 } else {
483 /* In case of a bus error we either kill the process or expect
484 * the kernel to catch the fault, which then is also responsible
485 * for cleaning up the mess.
486 */
487 current->thread.signo = SIGBUS;
488 current->thread.faddr = fp->un.fmt7.faddr;
489 if (send_fault_sig(&fp->ptregs) >= 0)
490 printk("68040 bus error (ssw=%x, faddr=%lx)\n", ssw,
491 fp->un.fmt7.faddr);
492 goto disable_wb;
493 }
494
495 do_040writebacks(fp);
496}
497#endif /* CONFIG_M68040 */
498
499#if defined(CONFIG_SUN3)
500#include <asm/sun3mmu.h>
501
502extern int mmu_emu_handle_fault (unsigned long, int, int);
503
504/* sun3 version of bus_error030 */
505
506static inline void bus_error030 (struct frame *fp)
507{
508 unsigned char buserr_type = sun3_get_buserr ();
509 unsigned long addr, errorcode;
510 unsigned short ssw = fp->un.fmtb.ssw;
511 extern unsigned long _sun3_map_test_start, _sun3_map_test_end;
512
513#ifdef DEBUG
514 if (ssw & (FC | FB))
515 printk ("Instruction fault at %#010lx\n",
516 ssw & FC ?
517 fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
518 :
519 fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
520 if (ssw & DF)
521 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
522 ssw & RW ? "read" : "write",
523 fp->un.fmtb.daddr,
524 space_names[ssw & DFC], fp->ptregs.pc);
525#endif
526
527 /*
528 * Check if this page should be demand-mapped. This needs to go before
529 * the testing for a bad kernel-space access (demand-mapping applies
530 * to kernel accesses too).
531 */
532
533 if ((ssw & DF)
534 && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
535 if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
536 return;
537 }
538
539 /* Check for kernel-space pagefault (BAD). */
540 if (fp->ptregs.sr & PS_S) {
541 /* kernel fault must be a data fault to user space */
542 if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
543 // try checking the kernel mappings before surrender
544 if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
545 return;
546 /* instruction fault or kernel data fault! */
547 if (ssw & (FC | FB))
548 printk ("Instruction fault at %#010lx\n",
549 fp->ptregs.pc);
550 if (ssw & DF) {
551 /* was this fault incurred testing bus mappings? */
552 if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) &&
553 (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) {
554 send_fault_sig(&fp->ptregs);
555 return;
556 }
557
558 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
559 ssw & RW ? "read" : "write",
560 fp->un.fmtb.daddr,
561 space_names[ssw & DFC], fp->ptregs.pc);
562 }
563 printk ("BAD KERNEL BUSERR\n");
564
565 die_if_kernel("Oops", &fp->ptregs,0);
566 force_sig(SIGKILL, current);
567 return;
568 }
569 } else {
570 /* user fault */
571 if (!(ssw & (FC | FB)) && !(ssw & DF))
572 /* not an instruction fault or data fault! BAD */
573 panic ("USER BUSERR w/o instruction or data fault");
574 }
575
576
577 /* First handle the data fault, if any. */
578 if (ssw & DF) {
579 addr = fp->un.fmtb.daddr;
580
581// errorcode bit 0: 0 -> no page 1 -> protection fault
582// errorcode bit 1: 0 -> read fault 1 -> write fault
583
584// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault
585// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault
586
587 if (buserr_type & SUN3_BUSERR_PROTERR)
588 errorcode = 0x01;
589 else if (buserr_type & SUN3_BUSERR_INVALID)
590 errorcode = 0x00;
591 else {
592#ifdef DEBUG
593 printk ("*** unexpected busfault type=%#04x\n", buserr_type);
594 printk ("invalid %s access at %#lx from pc %#lx\n",
595 !(ssw & RW) ? "write" : "read", addr,
596 fp->ptregs.pc);
597#endif
598 die_if_kernel ("Oops", &fp->ptregs, buserr_type);
599 force_sig (SIGBUS, current);
600 return;
601 }
602
603//todo: wtf is RM bit? --m
604 if (!(ssw & RW) || ssw & RM)
605 errorcode |= 0x02;
606
607 /* Handle page fault. */
608 do_page_fault (&fp->ptregs, addr, errorcode);
609
610 /* Retry the data fault now. */
611 return;
612 }
613
614 /* Now handle the instruction fault. */
615
616 /* Get the fault address. */
617 if (fp->ptregs.format == 0xA)
618 addr = fp->ptregs.pc + 4;
619 else
620 addr = fp->un.fmtb.baddr;
621 if (ssw & FC)
622 addr -= 2;
623
624 if (buserr_type & SUN3_BUSERR_INVALID) {
625 if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
626 do_page_fault (&fp->ptregs, addr, 0);
627 } else {
628#ifdef DEBUG
629 printk ("protection fault on insn access (segv).\n");
630#endif
631 force_sig (SIGSEGV, current);
632 }
633}
634#else
635#if defined(CPU_M68020_OR_M68030)
636static inline void bus_error030 (struct frame *fp)
637{
638 volatile unsigned short temp;
639 unsigned short mmusr;
640 unsigned long addr, errorcode;
641 unsigned short ssw = fp->un.fmtb.ssw;
642#ifdef DEBUG
643 unsigned long desc;
644
645 printk ("pid = %x ", current->pid);
646 printk ("SSW=%#06x ", ssw);
647
648 if (ssw & (FC | FB))
649 printk ("Instruction fault at %#010lx\n",
650 ssw & FC ?
651 fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
652 :
653 fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
654 if (ssw & DF)
655 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
656 ssw & RW ? "read" : "write",
657 fp->un.fmtb.daddr,
658 space_names[ssw & DFC], fp->ptregs.pc);
659#endif
660
661 /* ++andreas: If a data fault and an instruction fault happen
662 at the same time map in both pages. */
663
664 /* First handle the data fault, if any. */
665 if (ssw & DF) {
666 addr = fp->un.fmtb.daddr;
667
668#ifdef DEBUG
669 asm volatile ("ptestr %3,%2@,#7,%0\n\t"
670 "pmove %%psr,%1@"
671 : "=a&" (desc)
672 : "a" (&temp), "a" (addr), "d" (ssw));
673#else
674 asm volatile ("ptestr %2,%1@,#7\n\t"
675 "pmove %%psr,%0@"
676 : : "a" (&temp), "a" (addr), "d" (ssw));
677#endif
678 mmusr = temp;
679
680#ifdef DEBUG
681 printk("mmusr is %#x for addr %#lx in task %p\n",
682 mmusr, addr, current);
683 printk("descriptor address is %#lx, contents %#lx\n",
684 __va(desc), *(unsigned long *)__va(desc));
685#endif
686
687 errorcode = (mmusr & MMU_I) ? 0 : 1;
688 if (!(ssw & RW) || (ssw & RM))
689 errorcode |= 2;
690
691 if (mmusr & (MMU_I | MMU_WP)) {
692 if (ssw & 4) {
693 printk("Data %s fault at %#010lx in %s (pc=%#lx)\n",
694 ssw & RW ? "read" : "write",
695 fp->un.fmtb.daddr,
696 space_names[ssw & DFC], fp->ptregs.pc);
697 goto buserr;
698 }
699 /* Don't try to do anything further if an exception was
700 handled. */
701 if (do_page_fault (&fp->ptregs, addr, errorcode) < 0)
702 return;
703 } else if (!(mmusr & MMU_I)) {
704 /* probably a 020 cas fault */
705 if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0)
706 printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr);
707 } else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
708 printk("invalid %s access at %#lx from pc %#lx\n",
709 !(ssw & RW) ? "write" : "read", addr,
710 fp->ptregs.pc);
711 die_if_kernel("Oops",&fp->ptregs,mmusr);
712 force_sig(SIGSEGV, current);
713 return;
714 } else {
715#if 0
716 static volatile long tlong;
717#endif
718
719 printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n",
720 !(ssw & RW) ? "write" : "read", addr,
721 fp->ptregs.pc, ssw);
722 asm volatile ("ptestr #1,%1@,#0\n\t"
723 "pmove %%psr,%0@"
724 : /* no outputs */
725 : "a" (&temp), "a" (addr));
726 mmusr = temp;
727
728 printk ("level 0 mmusr is %#x\n", mmusr);
729#if 0
730 asm volatile ("pmove %%tt0,%0@"
731 : /* no outputs */
732 : "a" (&tlong));
733 printk("tt0 is %#lx, ", tlong);
734 asm volatile ("pmove %%tt1,%0@"
735 : /* no outputs */
736 : "a" (&tlong));
737 printk("tt1 is %#lx\n", tlong);
738#endif
739#ifdef DEBUG
740 printk("Unknown SIGSEGV - 1\n");
741#endif
742 die_if_kernel("Oops",&fp->ptregs,mmusr);
743 force_sig(SIGSEGV, current);
744 return;
745 }
746
747 /* setup an ATC entry for the access about to be retried */
748 if (!(ssw & RW) || (ssw & RM))
749 asm volatile ("ploadw %1,%0@" : /* no outputs */
750 : "a" (addr), "d" (ssw));
751 else
752 asm volatile ("ploadr %1,%0@" : /* no outputs */
753 : "a" (addr), "d" (ssw));
754 }
755
756 /* Now handle the instruction fault. */
757
758 if (!(ssw & (FC|FB)))
759 return;
760
761 if (fp->ptregs.sr & PS_S) {
762 printk("Instruction fault at %#010lx\n",
763 fp->ptregs.pc);
764 buserr:
765 printk ("BAD KERNEL BUSERR\n");
766 die_if_kernel("Oops",&fp->ptregs,0);
767 force_sig(SIGKILL, current);
768 return;
769 }
770
771 /* get the fault address */
772 if (fp->ptregs.format == 10)
773 addr = fp->ptregs.pc + 4;
774 else
775 addr = fp->un.fmtb.baddr;
776 if (ssw & FC)
777 addr -= 2;
778
779 if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0)
780 /* Insn fault on same page as data fault. But we
781 should still create the ATC entry. */
782 goto create_atc_entry;
783
784#ifdef DEBUG
785 asm volatile ("ptestr #1,%2@,#7,%0\n\t"
786 "pmove %%psr,%1@"
787 : "=a&" (desc)
788 : "a" (&temp), "a" (addr));
789#else
790 asm volatile ("ptestr #1,%1@,#7\n\t"
791 "pmove %%psr,%0@"
792 : : "a" (&temp), "a" (addr));
793#endif
794 mmusr = temp;
795
796#ifdef DEBUG
797 printk ("mmusr is %#x for addr %#lx in task %p\n",
798 mmusr, addr, current);
799 printk ("descriptor address is %#lx, contents %#lx\n",
800 __va(desc), *(unsigned long *)__va(desc));
801#endif
802
803 if (mmusr & MMU_I)
804 do_page_fault (&fp->ptregs, addr, 0);
805 else if (mmusr & (MMU_B|MMU_L|MMU_S)) {
806 printk ("invalid insn access at %#lx from pc %#lx\n",
807 addr, fp->ptregs.pc);
808#ifdef DEBUG
809 printk("Unknown SIGSEGV - 2\n");
810#endif
811 die_if_kernel("Oops",&fp->ptregs,mmusr);
812 force_sig(SIGSEGV, current);
813 return;
814 }
815
816create_atc_entry:
817 /* setup an ATC entry for the access about to be retried */
818 asm volatile ("ploadr #2,%0@" : /* no outputs */
819 : "a" (addr));
820}
821#endif /* CPU_M68020_OR_M68030 */
822#endif /* !CONFIG_SUN3 */
823
824asmlinkage void buserr_c(struct frame *fp)
825{
826 /* Only set esp0 if coming from user mode */
827 if (user_mode(&fp->ptregs))
828 current->thread.esp0 = (unsigned long) fp;
829
830#ifdef DEBUG
831 printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format);
832#endif
833
834 switch (fp->ptregs.format) {
835#if defined (CONFIG_M68060)
836 case 4: /* 68060 access error */
837 access_error060 (fp);
838 break;
839#endif
840#if defined (CONFIG_M68040)
841 case 0x7: /* 68040 access error */
842 access_error040 (fp);
843 break;
844#endif
845#if defined (CPU_M68020_OR_M68030)
846 case 0xa:
847 case 0xb:
848 bus_error030 (fp);
849 break;
850#endif
851 default:
852 die_if_kernel("bad frame format",&fp->ptregs,0);
853#ifdef DEBUG
854 printk("Unknown SIGSEGV - 4\n");
855#endif
856 force_sig(SIGSEGV, current);
857 }
858}
859
860
861static int kstack_depth_to_print = 48;
862
863void show_trace(unsigned long *stack)
864{
865 unsigned long *endstack;
866 unsigned long addr;
867 int i;
868
869 printk("Call Trace:");
870 addr = (unsigned long)stack + THREAD_SIZE - 1;
871 endstack = (unsigned long *)(addr & -THREAD_SIZE);
872 i = 0;
873 while (stack + 1 <= endstack) {
874 addr = *stack++;
875 /*
876 * If the address is either in the text segment of the
877 * kernel, or in the region which contains vmalloc'ed
878 * memory, it *may* be the address of a calling
879 * routine; if so, print it so that someone tracing
880 * down the cause of the crash will be able to figure
881 * out the call path that was taken.
882 */
883 if (__kernel_text_address(addr)) {
884#ifndef CONFIG_KALLSYMS
885 if (i % 5 == 0)
886 printk("\n ");
887#endif
888 printk(" [<%08lx>] %pS\n", addr, (void *)addr);
889 i++;
890 }
891 }
892 printk("\n");
893}
894
895void show_registers(struct pt_regs *regs)
896{
897 struct frame *fp = (struct frame *)regs;
898 mm_segment_t old_fs = get_fs();
899 u16 c, *cp;
900 unsigned long addr;
901 int i;
902
903 print_modules();
904 printk("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc);
905 printk("SR: %04x SP: %p a2: %08lx\n", regs->sr, regs, regs->a2);
906 printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
907 regs->d0, regs->d1, regs->d2, regs->d3);
908 printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
909 regs->d4, regs->d5, regs->a0, regs->a1);
910
911 printk("Process %s (pid: %d, task=%p)\n",
912 current->comm, task_pid_nr(current), current);
913 addr = (unsigned long)&fp->un;
914 printk("Frame format=%X ", regs->format);
915 switch (regs->format) {
916 case 0x2:
917 printk("instr addr=%08lx\n", fp->un.fmt2.iaddr);
918 addr += sizeof(fp->un.fmt2);
919 break;
920 case 0x3:
921 printk("eff addr=%08lx\n", fp->un.fmt3.effaddr);
922 addr += sizeof(fp->un.fmt3);
923 break;
924 case 0x4:
925 printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n"
926 : "eff addr=%08lx pc=%08lx\n"),
927 fp->un.fmt4.effaddr, fp->un.fmt4.pc);
928 addr += sizeof(fp->un.fmt4);
929 break;
930 case 0x7:
931 printk("eff addr=%08lx ssw=%04x faddr=%08lx\n",
932 fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr);
933 printk("wb 1 stat/addr/data: %04x %08lx %08lx\n",
934 fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0);
935 printk("wb 2 stat/addr/data: %04x %08lx %08lx\n",
936 fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d);
937 printk("wb 3 stat/addr/data: %04x %08lx %08lx\n",
938 fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d);
939 printk("push data: %08lx %08lx %08lx %08lx\n",
940 fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2,
941 fp->un.fmt7.pd3);
942 addr += sizeof(fp->un.fmt7);
943 break;
944 case 0x9:
945 printk("instr addr=%08lx\n", fp->un.fmt9.iaddr);
946 addr += sizeof(fp->un.fmt9);
947 break;
948 case 0xa:
949 printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
950 fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb,
951 fp->un.fmta.daddr, fp->un.fmta.dobuf);
952 addr += sizeof(fp->un.fmta);
953 break;
954 case 0xb:
955 printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n",
956 fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb,
957 fp->un.fmtb.daddr, fp->un.fmtb.dobuf);
958 printk("baddr=%08lx dibuf=%08lx ver=%x\n",
959 fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver);
960 addr += sizeof(fp->un.fmtb);
961 break;
962 default:
963 printk("\n");
964 }
965 show_stack(NULL, (unsigned long *)addr);
966
967 printk("Code:");
968 set_fs(KERNEL_DS);
969 cp = (u16 *)regs->pc;
970 for (i = -8; i < 16; i++) {
971 if (get_user(c, cp + i) && i >= 0) {
972 printk(" Bad PC value.");
973 break;
974 }
975 printk(i ? " %04x" : " <%04x>", c);
976 }
977 set_fs(old_fs);
978 printk ("\n");
979}
980
981void show_stack(struct task_struct *task, unsigned long *stack)
982{
983 unsigned long *p;
984 unsigned long *endstack;
985 int i;
986
987 if (!stack) {
988 if (task)
989 stack = (unsigned long *)task->thread.esp0;
990 else
991 stack = (unsigned long *)&stack;
992 }
993 endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE);
994
995 printk("Stack from %08lx:", (unsigned long)stack);
996 p = stack;
997 for (i = 0; i < kstack_depth_to_print; i++) {
998 if (p + 1 > endstack)
999 break;
1000 if (i % 8 == 0)
1001 printk("\n ");
1002 printk(" %08lx", *p++);
1003 }
1004 printk("\n");
1005 show_trace(stack);
1006}
1007
1008/*
1009 * The architecture-independent backtrace generator
1010 */
1011void dump_stack(void)
1012{
1013 unsigned long stack;
1014
1015 show_trace(&stack);
1016}
1017
1018EXPORT_SYMBOL(dump_stack);
1019
1020void bad_super_trap (struct frame *fp)
1021{
1022 console_verbose();
1023 if (fp->ptregs.vector < 4 * ARRAY_SIZE(vec_names))
1024 printk ("*** %s *** FORMAT=%X\n",
1025 vec_names[(fp->ptregs.vector) >> 2],
1026 fp->ptregs.format);
1027 else
1028 printk ("*** Exception %d *** FORMAT=%X\n",
1029 (fp->ptregs.vector) >> 2,
1030 fp->ptregs.format);
1031 if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) {
1032 unsigned short ssw = fp->un.fmtb.ssw;
1033
1034 printk ("SSW=%#06x ", ssw);
1035
1036 if (ssw & RC)
1037 printk ("Pipe stage C instruction fault at %#010lx\n",
1038 (fp->ptregs.format) == 0xA ?
1039 fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2);
1040 if (ssw & RB)
1041 printk ("Pipe stage B instruction fault at %#010lx\n",
1042 (fp->ptregs.format) == 0xA ?
1043 fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
1044 if (ssw & DF)
1045 printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
1046 ssw & RW ? "read" : "write",
1047 fp->un.fmtb.daddr, space_names[ssw & DFC],
1048 fp->ptregs.pc);
1049 }
1050 printk ("Current process id is %d\n", task_pid_nr(current));
1051 die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
1052}
1053
1054asmlinkage void trap_c(struct frame *fp)
1055{
1056 int sig;
1057 siginfo_t info;
1058
1059 if (fp->ptregs.sr & PS_S) {
1060 if (fp->ptregs.vector == VEC_TRACE << 2) {
1061 /* traced a trapping instruction on a 68020/30,
1062 * real exception will be executed afterwards.
1063 */
1064 } else if (!handle_kernel_fault(&fp->ptregs))
1065 bad_super_trap(fp);
1066 return;
1067 }
1068
1069 /* send the appropriate signal to the user program */
1070 switch ((fp->ptregs.vector) >> 2) {
1071 case VEC_ADDRERR:
1072 info.si_code = BUS_ADRALN;
1073 sig = SIGBUS;
1074 break;
1075 case VEC_ILLEGAL:
1076 case VEC_LINE10:
1077 case VEC_LINE11:
1078 info.si_code = ILL_ILLOPC;
1079 sig = SIGILL;
1080 break;
1081 case VEC_PRIV:
1082 info.si_code = ILL_PRVOPC;
1083 sig = SIGILL;
1084 break;
1085 case VEC_COPROC:
1086 info.si_code = ILL_COPROC;
1087 sig = SIGILL;
1088 break;
1089 case VEC_TRAP1:
1090 case VEC_TRAP2:
1091 case VEC_TRAP3:
1092 case VEC_TRAP4:
1093 case VEC_TRAP5:
1094 case VEC_TRAP6:
1095 case VEC_TRAP7:
1096 case VEC_TRAP8:
1097 case VEC_TRAP9:
1098 case VEC_TRAP10:
1099 case VEC_TRAP11:
1100 case VEC_TRAP12:
1101 case VEC_TRAP13:
1102 case VEC_TRAP14:
1103 info.si_code = ILL_ILLTRP;
1104 sig = SIGILL;
1105 break;
1106 case VEC_FPBRUC:
1107 case VEC_FPOE:
1108 case VEC_FPNAN:
1109 info.si_code = FPE_FLTINV;
1110 sig = SIGFPE;
1111 break;
1112 case VEC_FPIR:
1113 info.si_code = FPE_FLTRES;
1114 sig = SIGFPE;
1115 break;
1116 case VEC_FPDIVZ:
1117 info.si_code = FPE_FLTDIV;
1118 sig = SIGFPE;
1119 break;
1120 case VEC_FPUNDER:
1121 info.si_code = FPE_FLTUND;
1122 sig = SIGFPE;
1123 break;
1124 case VEC_FPOVER:
1125 info.si_code = FPE_FLTOVF;
1126 sig = SIGFPE;
1127 break;
1128 case VEC_ZERODIV:
1129 info.si_code = FPE_INTDIV;
1130 sig = SIGFPE;
1131 break;
1132 case VEC_CHK:
1133 case VEC_TRAP:
1134 info.si_code = FPE_INTOVF;
1135 sig = SIGFPE;
1136 break;
1137 case VEC_TRACE: /* ptrace single step */
1138 info.si_code = TRAP_TRACE;
1139 sig = SIGTRAP;
1140 break;
1141 case VEC_TRAP15: /* breakpoint */
1142 info.si_code = TRAP_BRKPT;
1143 sig = SIGTRAP;
1144 break;
1145 default:
1146 info.si_code = ILL_ILLOPC;
1147 sig = SIGILL;
1148 break;
1149 }
1150 info.si_signo = sig;
1151 info.si_errno = 0;
1152 switch (fp->ptregs.format) {
1153 default:
1154 info.si_addr = (void *) fp->ptregs.pc;
1155 break;
1156 case 2:
1157 info.si_addr = (void *) fp->un.fmt2.iaddr;
1158 break;
1159 case 7:
1160 info.si_addr = (void *) fp->un.fmt7.effaddr;
1161 break;
1162 case 9:
1163 info.si_addr = (void *) fp->un.fmt9.iaddr;
1164 break;
1165 case 10:
1166 info.si_addr = (void *) fp->un.fmta.daddr;
1167 break;
1168 case 11:
1169 info.si_addr = (void *) fp->un.fmtb.daddr;
1170 break;
1171 }
1172 force_sig_info (sig, &info, current);
1173}
1174
1175void die_if_kernel (char *str, struct pt_regs *fp, int nr)
1176{
1177 if (!(fp->sr & PS_S))
1178 return;
1179
1180 console_verbose();
1181 printk("%s: %08x\n",str,nr);
1182 show_registers(fp);
1183 add_taint(TAINT_DIE);
1184 do_exit(SIGSEGV);
1185}
1186
1187/*
1188 * This function is called if an error occur while accessing
1189 * user-space from the fpsp040 code.
1190 */
1191asmlinkage void fpsp040_die(void)
1192{
1193 do_exit(SIGSEGV);
1194}
1195
1196#ifdef CONFIG_M68KFPU_EMU
1197asmlinkage void fpemu_signal(int signal, int code, void *addr)
1198{
1199 siginfo_t info;
1200
1201 info.si_signo = signal;
1202 info.si_errno = 0;
1203 info.si_code = code;
1204 info.si_addr = addr;
1205 force_sig_info(signal, &info, current);
1206}
1207#endif
diff --git a/arch/m68k/kernel/traps_no.c b/arch/m68k/kernel/traps_no.c
new file mode 100644
index 000000000000..a768008dfd06
--- /dev/null
+++ b/arch/m68k/kernel/traps_no.c
@@ -0,0 +1,365 @@
1/*
2 * linux/arch/m68knommu/kernel/traps.c
3 *
4 * Copyright (C) 1993, 1994 by Hamish Macdonald
5 *
6 * 68040 fixes by Michael Rausch
7 * 68040 fixes by Martin Apel
8 * 68060 fixes by Roman Hodek
9 * 68060 fixes by Jesper Skov
10 *
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file COPYING in the main directory of this archive
13 * for more details.
14 */
15
16/*
17 * Sets up all exception vectors
18 */
19#include <linux/sched.h>
20#include <linux/signal.h>
21#include <linux/kernel.h>
22#include <linux/mm.h>
23#include <linux/module.h>
24#include <linux/types.h>
25#include <linux/user.h>
26#include <linux/string.h>
27#include <linux/linkage.h>
28#include <linux/init.h>
29#include <linux/ptrace.h>
30#include <linux/kallsyms.h>
31
32#include <asm/setup.h>
33#include <asm/fpu.h>
34#include <asm/system.h>
35#include <asm/uaccess.h>
36#include <asm/traps.h>
37#include <asm/pgtable.h>
38#include <asm/machdep.h>
39#include <asm/siginfo.h>
40
41static char const * const vec_names[] = {
42 "RESET SP", "RESET PC", "BUS ERROR", "ADDRESS ERROR",
43 "ILLEGAL INSTRUCTION", "ZERO DIVIDE", "CHK", "TRAPcc",
44 "PRIVILEGE VIOLATION", "TRACE", "LINE 1010", "LINE 1111",
45 "UNASSIGNED RESERVED 12", "COPROCESSOR PROTOCOL VIOLATION",
46 "FORMAT ERROR", "UNINITIALIZED INTERRUPT",
47 "UNASSIGNED RESERVED 16", "UNASSIGNED RESERVED 17",
48 "UNASSIGNED RESERVED 18", "UNASSIGNED RESERVED 19",
49 "UNASSIGNED RESERVED 20", "UNASSIGNED RESERVED 21",
50 "UNASSIGNED RESERVED 22", "UNASSIGNED RESERVED 23",
51 "SPURIOUS INTERRUPT", "LEVEL 1 INT", "LEVEL 2 INT", "LEVEL 3 INT",
52 "LEVEL 4 INT", "LEVEL 5 INT", "LEVEL 6 INT", "LEVEL 7 INT",
53 "SYSCALL", "TRAP #1", "TRAP #2", "TRAP #3",
54 "TRAP #4", "TRAP #5", "TRAP #6", "TRAP #7",
55 "TRAP #8", "TRAP #9", "TRAP #10", "TRAP #11",
56 "TRAP #12", "TRAP #13", "TRAP #14", "TRAP #15",
57 "FPCP BSUN", "FPCP INEXACT", "FPCP DIV BY 0", "FPCP UNDERFLOW",
58 "FPCP OPERAND ERROR", "FPCP OVERFLOW", "FPCP SNAN",
59 "FPCP UNSUPPORTED OPERATION",
60 "MMU CONFIGURATION ERROR"
61};
62
63void __init trap_init(void)
64{
65}
66
67void die_if_kernel(char *str, struct pt_regs *fp, int nr)
68{
69 if (!(fp->sr & PS_S))
70 return;
71
72 console_verbose();
73 printk(KERN_EMERG "%s: %08x\n",str,nr);
74 printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n",
75 fp->pc, fp->sr, fp, fp->a2);
76 printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
77 fp->d0, fp->d1, fp->d2, fp->d3);
78 printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
79 fp->d4, fp->d5, fp->a0, fp->a1);
80
81 printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
82 current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
83 show_stack(NULL, (unsigned long *)(fp + 1));
84 add_taint(TAINT_DIE);
85 do_exit(SIGSEGV);
86}
87
88asmlinkage void buserr_c(struct frame *fp)
89{
90 /* Only set esp0 if coming from user mode */
91 if (user_mode(&fp->ptregs))
92 current->thread.esp0 = (unsigned long) fp;
93
94#if defined(DEBUG)
95 printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format);
96#endif
97
98 die_if_kernel("bad frame format",&fp->ptregs,0);
99#if defined(DEBUG)
100 printk(KERN_DEBUG "Unknown SIGSEGV - 4\n");
101#endif
102 force_sig(SIGSEGV, current);
103}
104
105static void print_this_address(unsigned long addr, int i)
106{
107#ifdef CONFIG_KALLSYMS
108 printk(KERN_EMERG " [%08lx] ", addr);
109 print_symbol(KERN_CONT "%s\n", addr);
110#else
111 if (i % 5)
112 printk(KERN_CONT " [%08lx] ", addr);
113 else
114 printk(KERN_EMERG " [%08lx] ", addr);
115 i++;
116#endif
117}
118
119int kstack_depth_to_print = 48;
120
121static void __show_stack(struct task_struct *task, unsigned long *stack)
122{
123 unsigned long *endstack, addr;
124#ifdef CONFIG_FRAME_POINTER
125 unsigned long *last_stack;
126#endif
127 int i;
128
129 if (!stack)
130 stack = (unsigned long *)task->thread.ksp;
131
132 addr = (unsigned long) stack;
133 endstack = (unsigned long *) PAGE_ALIGN(addr);
134
135 printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
136 for (i = 0; i < kstack_depth_to_print; i++) {
137 if (stack + 1 + i > endstack)
138 break;
139 if (i % 8 == 0)
140 printk(KERN_EMERG " ");
141 printk(KERN_CONT " %08lx", *(stack + i));
142 }
143 printk("\n");
144 i = 0;
145
146#ifdef CONFIG_FRAME_POINTER
147 printk(KERN_EMERG "Call Trace:\n");
148
149 last_stack = stack - 1;
150 while (stack <= endstack && stack > last_stack) {
151
152 addr = *(stack + 1);
153 print_this_address(addr, i);
154 i++;
155
156 last_stack = stack;
157 stack = (unsigned long *)*stack;
158 }
159 printk("\n");
160#else
161 printk(KERN_EMERG "Call Trace with CONFIG_FRAME_POINTER disabled:\n");
162 while (stack <= endstack) {
163 addr = *stack++;
164 /*
165 * If the address is either in the text segment of the kernel,
166 * or in a region which is occupied by a module then it *may*
167 * be the address of a calling routine; if so, print it so that
168 * someone tracing down the cause of the crash will be able to
169 * figure out the call path that was taken.
170 */
171 if (__kernel_text_address(addr)) {
172 print_this_address(addr, i);
173 i++;
174 }
175 }
176 printk(KERN_CONT "\n");
177#endif
178}
179
180void bad_super_trap(struct frame *fp)
181{
182 int vector = (fp->ptregs.vector >> 2) & 0xff;
183
184 console_verbose();
185 if (vector < ARRAY_SIZE(vec_names))
186 printk (KERN_WARNING "*** %s *** FORMAT=%X\n",
187 vec_names[vector],
188 fp->ptregs.format);
189 else
190 printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n",
191 vector,
192 fp->ptregs.format);
193 printk (KERN_WARNING "Current process id is %d\n", current->pid);
194 die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0);
195}
196
197asmlinkage void trap_c(struct frame *fp)
198{
199 int sig;
200 int vector = (fp->ptregs.vector >> 2) & 0xff;
201 siginfo_t info;
202
203 if (fp->ptregs.sr & PS_S) {
204 if (vector == VEC_TRACE) {
205 /* traced a trapping instruction */
206 } else
207 bad_super_trap(fp);
208 return;
209 }
210
211 /* send the appropriate signal to the user program */
212 switch (vector) {
213 case VEC_ADDRERR:
214 info.si_code = BUS_ADRALN;
215 sig = SIGBUS;
216 break;
217 case VEC_ILLEGAL:
218 case VEC_LINE10:
219 case VEC_LINE11:
220 info.si_code = ILL_ILLOPC;
221 sig = SIGILL;
222 break;
223 case VEC_PRIV:
224 info.si_code = ILL_PRVOPC;
225 sig = SIGILL;
226 break;
227 case VEC_COPROC:
228 info.si_code = ILL_COPROC;
229 sig = SIGILL;
230 break;
231 case VEC_TRAP1: /* gdbserver breakpoint */
232 fp->ptregs.pc -= 2;
233 info.si_code = TRAP_TRACE;
234 sig = SIGTRAP;
235 break;
236 case VEC_TRAP2:
237 case VEC_TRAP3:
238 case VEC_TRAP4:
239 case VEC_TRAP5:
240 case VEC_TRAP6:
241 case VEC_TRAP7:
242 case VEC_TRAP8:
243 case VEC_TRAP9:
244 case VEC_TRAP10:
245 case VEC_TRAP11:
246 case VEC_TRAP12:
247 case VEC_TRAP13:
248 case VEC_TRAP14:
249 info.si_code = ILL_ILLTRP;
250 sig = SIGILL;
251 break;
252 case VEC_FPBRUC:
253 case VEC_FPOE:
254 case VEC_FPNAN:
255 info.si_code = FPE_FLTINV;
256 sig = SIGFPE;
257 break;
258 case VEC_FPIR:
259 info.si_code = FPE_FLTRES;
260 sig = SIGFPE;
261 break;
262 case VEC_FPDIVZ:
263 info.si_code = FPE_FLTDIV;
264 sig = SIGFPE;
265 break;
266 case VEC_FPUNDER:
267 info.si_code = FPE_FLTUND;
268 sig = SIGFPE;
269 break;
270 case VEC_FPOVER:
271 info.si_code = FPE_FLTOVF;
272 sig = SIGFPE;
273 break;
274 case VEC_ZERODIV:
275 info.si_code = FPE_INTDIV;
276 sig = SIGFPE;
277 break;
278 case VEC_CHK:
279 case VEC_TRAP:
280 info.si_code = FPE_INTOVF;
281 sig = SIGFPE;
282 break;
283 case VEC_TRACE: /* ptrace single step */
284 info.si_code = TRAP_TRACE;
285 sig = SIGTRAP;
286 break;
287 case VEC_TRAP15: /* breakpoint */
288 info.si_code = TRAP_BRKPT;
289 sig = SIGTRAP;
290 break;
291 default:
292 info.si_code = ILL_ILLOPC;
293 sig = SIGILL;
294 break;
295 }
296 info.si_signo = sig;
297 info.si_errno = 0;
298 switch (fp->ptregs.format) {
299 default:
300 info.si_addr = (void *) fp->ptregs.pc;
301 break;
302 case 2:
303 info.si_addr = (void *) fp->un.fmt2.iaddr;
304 break;
305 case 7:
306 info.si_addr = (void *) fp->un.fmt7.effaddr;
307 break;
308 case 9:
309 info.si_addr = (void *) fp->un.fmt9.iaddr;
310 break;
311 case 10:
312 info.si_addr = (void *) fp->un.fmta.daddr;
313 break;
314 case 11:
315 info.si_addr = (void *) fp->un.fmtb.daddr;
316 break;
317 }
318 force_sig_info (sig, &info, current);
319}
320
321asmlinkage void set_esp0(unsigned long ssp)
322{
323 current->thread.esp0 = ssp;
324}
325
326/*
327 * The architecture-independent backtrace generator
328 */
329void dump_stack(void)
330{
331 /*
332 * We need frame pointers for this little trick, which works as follows:
333 *
334 * +------------+ 0x00
335 * | Next SP | -> 0x0c
336 * +------------+ 0x04
337 * | Caller |
338 * +------------+ 0x08
339 * | Local vars | -> our stack var
340 * +------------+ 0x0c
341 * | Next SP | -> 0x18, that is what we pass to show_stack()
342 * +------------+ 0x10
343 * | Caller |
344 * +------------+ 0x14
345 * | Local vars |
346 * +------------+ 0x18
347 * | ... |
348 * +------------+
349 */
350
351 unsigned long *stack;
352
353 stack = (unsigned long *)&stack;
354 stack++;
355 __show_stack(current, stack);
356}
357EXPORT_SYMBOL(dump_stack);
358
359void show_stack(struct task_struct *task, unsigned long *stack)
360{
361 if (!stack && !task)
362 dump_stack();
363 else
364 __show_stack(task, stack);
365}
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 878be5f38cad..d0993594f558 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -25,6 +25,8 @@ SECTIONS
25 25
26 EXCEPTION_TABLE(16) 26 EXCEPTION_TABLE(16)
27 27
28 _sdata = .; /* Start of data section */
29
28 RODATA 30 RODATA
29 31
30 RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) 32 RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index 1ad6b7ad2c17..8080469ee6c1 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -25,6 +25,7 @@ SECTIONS
25 _etext = .; /* End of text section */ 25 _etext = .; /* End of text section */
26 26
27 EXCEPTION_TABLE(16) :data 27 EXCEPTION_TABLE(16) :data
28 _sdata = .; /* Start of rw data section */
28 RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) :data 29 RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) :data
29 /* End of data goes *here* so that freeing init code works properly. */ 30 /* End of data goes *here* so that freeing init code works properly. */
30 _edata = .; 31 _edata = .;
diff --git a/arch/m68k/kernel/vmlinux.lds.S b/arch/m68k/kernel/vmlinux.lds.S
index 99ba315bd0a8..030dabf0bc53 100644
--- a/arch/m68k/kernel/vmlinux.lds.S
+++ b/arch/m68k/kernel/vmlinux.lds.S
@@ -1,10 +1,5 @@
1PHDRS 1#ifdef CONFIG_MMU
2{ 2#include "vmlinux.lds_mm.S"
3 text PT_LOAD FILEHDR PHDRS FLAGS (7);
4 data PT_LOAD FLAGS (7);
5}
6#ifdef CONFIG_SUN3
7#include "vmlinux-sun3.lds"
8#else 3#else
9#include "vmlinux-std.lds" 4#include "vmlinux.lds_no.S"
10#endif 5#endif
diff --git a/arch/m68k/kernel/vmlinux.lds_mm.S b/arch/m68k/kernel/vmlinux.lds_mm.S
new file mode 100644
index 000000000000..99ba315bd0a8
--- /dev/null
+++ b/arch/m68k/kernel/vmlinux.lds_mm.S
@@ -0,0 +1,10 @@
1PHDRS
2{
3 text PT_LOAD FILEHDR PHDRS FLAGS (7);
4 data PT_LOAD FLAGS (7);
5}
6#ifdef CONFIG_SUN3
7#include "vmlinux-sun3.lds"
8#else
9#include "vmlinux-std.lds"
10#endif
diff --git a/arch/m68k/kernel/vmlinux.lds_no.S b/arch/m68k/kernel/vmlinux.lds_no.S
new file mode 100644
index 000000000000..7dc4087a9545
--- /dev/null
+++ b/arch/m68k/kernel/vmlinux.lds_no.S
@@ -0,0 +1,188 @@
1/*
2 * vmlinux.lds.S -- master linker script for m68knommu arch
3 *
4 * (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com>
5 *
6 * This linker script is equipped to build either ROM loaded or RAM
7 * run kernels.
8 */
9
10#include <asm-generic/vmlinux.lds.h>
11#include <asm/page.h>
12#include <asm/thread_info.h>
13
14#if defined(CONFIG_RAMKERNEL)
15#define RAM_START CONFIG_KERNELBASE
16#define RAM_LENGTH (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE)
17#define TEXT ram
18#define DATA ram
19#define INIT ram
20#define BSSS ram
21#endif
22#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL)
23#define RAM_START CONFIG_RAMBASE
24#define RAM_LENGTH CONFIG_RAMSIZE
25#define ROMVEC_START CONFIG_ROMVEC
26#define ROMVEC_LENGTH CONFIG_ROMVECSIZE
27#define ROM_START CONFIG_ROMSTART
28#define ROM_LENGTH CONFIG_ROMSIZE
29#define TEXT rom
30#define DATA ram
31#define INIT ram
32#define BSSS ram
33#endif
34
35#ifndef DATA_ADDR
36#define DATA_ADDR
37#endif
38
39
40OUTPUT_ARCH(m68k)
41ENTRY(_start)
42
43MEMORY {
44 ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH
45#ifdef ROM_START
46 romvec : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH
47 rom : ORIGIN = ROM_START, LENGTH = ROM_LENGTH
48#endif
49}
50
51jiffies = jiffies_64 + 4;
52
53SECTIONS {
54
55#ifdef ROMVEC_START
56 . = ROMVEC_START ;
57 .romvec : {
58 __rom_start = . ;
59 _romvec = .;
60 *(.data..initvect)
61 } > romvec
62#endif
63
64 .text : {
65 _text = .;
66 _stext = . ;
67 HEAD_TEXT
68 TEXT_TEXT
69 SCHED_TEXT
70 LOCK_TEXT
71 *(.text..lock)
72
73 . = ALIGN(16); /* Exception table */
74 __start___ex_table = .;
75 *(__ex_table)
76 __stop___ex_table = .;
77
78 *(.rodata) *(.rodata.*)
79 *(__vermagic) /* Kernel version magic */
80 *(__markers_strings)
81 *(.rodata1)
82 *(.rodata.str1.1)
83
84 /* Kernel symbol table: Normal symbols */
85 . = ALIGN(4);
86 __start___ksymtab = .;
87 *(SORT(___ksymtab+*))
88 __stop___ksymtab = .;
89
90 /* Kernel symbol table: GPL-only symbols */
91 __start___ksymtab_gpl = .;
92 *(SORT(___ksymtab_gpl+*))
93 __stop___ksymtab_gpl = .;
94
95 /* Kernel symbol table: Normal unused symbols */
96 __start___ksymtab_unused = .;
97 *(SORT(___ksymtab_unused+*))
98 __stop___ksymtab_unused = .;
99
100 /* Kernel symbol table: GPL-only unused symbols */
101 __start___ksymtab_unused_gpl = .;
102 *(SORT(___ksymtab_unused_gpl+*))
103 __stop___ksymtab_unused_gpl = .;
104
105 /* Kernel symbol table: GPL-future symbols */
106 __start___ksymtab_gpl_future = .;
107 *(SORT(___ksymtab_gpl_future+*))
108 __stop___ksymtab_gpl_future = .;
109
110 /* Kernel symbol table: Normal symbols */
111 __start___kcrctab = .;
112 *(SORT(___kcrctab+*))
113 __stop___kcrctab = .;
114
115 /* Kernel symbol table: GPL-only symbols */
116 __start___kcrctab_gpl = .;
117 *(SORT(___kcrctab_gpl+*))
118 __stop___kcrctab_gpl = .;
119
120 /* Kernel symbol table: Normal unused symbols */
121 __start___kcrctab_unused = .;
122 *(SORT(___kcrctab_unused+*))
123 __stop___kcrctab_unused = .;
124
125 /* Kernel symbol table: GPL-only unused symbols */
126 __start___kcrctab_unused_gpl = .;
127 *(SORT(___kcrctab_unused_gpl+*))
128 __stop___kcrctab_unused_gpl = .;
129
130 /* Kernel symbol table: GPL-future symbols */
131 __start___kcrctab_gpl_future = .;
132 *(SORT(___kcrctab_gpl_future+*))
133 __stop___kcrctab_gpl_future = .;
134
135 /* Kernel symbol table: strings */
136 *(__ksymtab_strings)
137
138 /* Built-in module parameters */
139 . = ALIGN(4) ;
140 __start___param = .;
141 *(__param)
142 __stop___param = .;
143
144 /* Built-in module versions */
145 . = ALIGN(4) ;
146 __start___modver = .;
147 *(__modver)
148 __stop___modver = .;
149
150 . = ALIGN(4) ;
151 _etext = . ;
152 } > TEXT
153
154 .data DATA_ADDR : {
155 . = ALIGN(4);
156 _sdata = . ;
157 DATA_DATA
158 CACHELINE_ALIGNED_DATA(32)
159 PAGE_ALIGNED_DATA(PAGE_SIZE)
160 *(.data..shared_aligned)
161 INIT_TASK_DATA(THREAD_SIZE)
162 _edata = . ;
163 } > DATA
164
165 .init.text : {
166 . = ALIGN(PAGE_SIZE);
167 __init_begin = .;
168 } > INIT
169 INIT_TEXT_SECTION(PAGE_SIZE) > INIT
170 INIT_DATA_SECTION(16) > INIT
171 .init.data : {
172 . = ALIGN(PAGE_SIZE);
173 __init_end = .;
174 } > INIT
175
176 .bss : {
177 . = ALIGN(4);
178 _sbss = . ;
179 *(.bss)
180 *(COMMON)
181 . = ALIGN(4) ;
182 _ebss = . ;
183 _end = . ;
184 } > BSSS
185
186 DISCARDS
187}
188