diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/m68knommu/kernel |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/m68knommu/kernel')
-rw-r--r-- | arch/m68knommu/kernel/Makefile | 11 | ||||
-rw-r--r-- | arch/m68knommu/kernel/asm-offsets.c | 101 | ||||
-rw-r--r-- | arch/m68knommu/kernel/comempci.c | 989 | ||||
-rw-r--r-- | arch/m68knommu/kernel/dma.c | 36 | ||||
-rw-r--r-- | arch/m68knommu/kernel/entry.S | 143 | ||||
-rw-r--r-- | arch/m68knommu/kernel/init_task.c | 43 | ||||
-rw-r--r-- | arch/m68knommu/kernel/m68k_ksyms.c | 104 | ||||
-rw-r--r-- | arch/m68knommu/kernel/module.c | 128 | ||||
-rw-r--r-- | arch/m68knommu/kernel/process.c | 442 | ||||
-rw-r--r-- | arch/m68knommu/kernel/ptrace.c | 383 | ||||
-rw-r--r-- | arch/m68knommu/kernel/semaphore.c | 134 | ||||
-rw-r--r-- | arch/m68knommu/kernel/setup.c | 347 | ||||
-rw-r--r-- | arch/m68knommu/kernel/signal.c | 788 | ||||
-rw-r--r-- | arch/m68knommu/kernel/sys_m68k.c | 208 | ||||
-rw-r--r-- | arch/m68knommu/kernel/syscalltable.S | 308 | ||||
-rw-r--r-- | arch/m68knommu/kernel/time.c | 198 | ||||
-rw-r--r-- | arch/m68knommu/kernel/traps.c | 320 | ||||
-rw-r--r-- | arch/m68knommu/kernel/vmlinux.lds.S | 348 |
18 files changed, 5031 insertions, 0 deletions
diff --git a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile new file mode 100644 index 000000000000..1c6cd1ab571e --- /dev/null +++ b/arch/m68knommu/kernel/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # Makefile for arch/m68knommu/kernel. | ||
3 | # | ||
4 | |||
5 | extra-y := vmlinux.lds | ||
6 | |||
7 | obj-y += dma.o entry.o init_task.o m68k_ksyms.o process.o ptrace.o semaphore.o \ | ||
8 | setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o | ||
9 | |||
10 | obj-$(CONFIG_MODULES) += module.o | ||
11 | obj-$(CONFIG_COMEMPCI) += comempci.o | ||
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c new file mode 100644 index 000000000000..cd3ffe12653e --- /dev/null +++ b/arch/m68knommu/kernel/asm-offsets.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * This program is used to generate definitions needed by | ||
3 | * assembly language modules. | ||
4 | * | ||
5 | * We use the technique used in the OSF Mach kernel code: | ||
6 | * generate asm statements containing #defines, | ||
7 | * compile this file to assembler, and then extract the | ||
8 | * #defines from the assembly-language output. | ||
9 | */ | ||
10 | |||
11 | #include <linux/stddef.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/kernel_stat.h> | ||
14 | #include <linux/ptrace.h> | ||
15 | #include <linux/hardirq.h> | ||
16 | #include <asm/bootinfo.h> | ||
17 | #include <asm/irq.h> | ||
18 | #include <asm/thread_info.h> | ||
19 | |||
20 | #define DEFINE(sym, val) \ | ||
21 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
22 | |||
23 | #define BLANK() asm volatile("\n->" : : ) | ||
24 | |||
25 | int main(void) | ||
26 | { | ||
27 | /* offsets into the task struct */ | ||
28 | DEFINE(TASK_STATE, offsetof(struct task_struct, state)); | ||
29 | DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); | ||
30 | DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); | ||
31 | DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked)); | ||
32 | DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); | ||
33 | DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info)); | ||
34 | DEFINE(TASK_MM, offsetof(struct task_struct, mm)); | ||
35 | DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); | ||
36 | |||
37 | /* offsets into the kernel_stat struct */ | ||
38 | DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); | ||
39 | |||
40 | /* offsets into the irq_cpustat_t struct */ | ||
41 | DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); | ||
42 | |||
43 | /* offsets into the thread struct */ | ||
44 | DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); | ||
45 | DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); | ||
46 | DEFINE(THREAD_SR, offsetof(struct thread_struct, sr)); | ||
47 | DEFINE(THREAD_FS, offsetof(struct thread_struct, fs)); | ||
48 | DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp)); | ||
49 | DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0)); | ||
50 | DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp)); | ||
51 | DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl)); | ||
52 | DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate)); | ||
53 | |||
54 | /* offsets into the pt_regs */ | ||
55 | DEFINE(PT_D0, offsetof(struct pt_regs, d0)); | ||
56 | DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0)); | ||
57 | DEFINE(PT_D1, offsetof(struct pt_regs, d1)); | ||
58 | DEFINE(PT_D2, offsetof(struct pt_regs, d2)); | ||
59 | DEFINE(PT_D3, offsetof(struct pt_regs, d3)); | ||
60 | DEFINE(PT_D4, offsetof(struct pt_regs, d4)); | ||
61 | DEFINE(PT_D5, offsetof(struct pt_regs, d5)); | ||
62 | DEFINE(PT_A0, offsetof(struct pt_regs, a0)); | ||
63 | DEFINE(PT_A1, offsetof(struct pt_regs, a1)); | ||
64 | DEFINE(PT_A2, offsetof(struct pt_regs, a2)); | ||
65 | DEFINE(PT_PC, offsetof(struct pt_regs, pc)); | ||
66 | DEFINE(PT_SR, offsetof(struct pt_regs, sr)); | ||
67 | |||
68 | #ifdef CONFIG_COLDFIRE | ||
69 | /* bitfields are a bit difficult */ | ||
70 | DEFINE(PT_FORMATVEC, offsetof(struct pt_regs, sr) - 2); | ||
71 | #else | ||
72 | /* bitfields are a bit difficult */ | ||
73 | DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); | ||
74 | /* offsets into the irq_handler struct */ | ||
75 | DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); | ||
76 | DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id)); | ||
77 | DEFINE(IRQ_NEXT, offsetof(struct irq_node, next)); | ||
78 | #endif | ||
79 | |||
80 | /* offsets into the kernel_stat struct */ | ||
81 | DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); | ||
82 | |||
83 | /* signal defines */ | ||
84 | DEFINE(SIGSEGV, SIGSEGV); | ||
85 | DEFINE(SEGV_MAPERR, SEGV_MAPERR); | ||
86 | DEFINE(SIGTRAP, SIGTRAP); | ||
87 | DEFINE(TRAP_TRACE, TRAP_TRACE); | ||
88 | |||
89 | DEFINE(PT_PTRACED, PT_PTRACED); | ||
90 | DEFINE(PT_DTRACE, PT_DTRACE); | ||
91 | |||
92 | DEFINE(THREAD_SIZE, THREAD_SIZE); | ||
93 | |||
94 | /* Offsets in thread_info structure */ | ||
95 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | ||
96 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); | ||
97 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | ||
98 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
diff --git a/arch/m68knommu/kernel/comempci.c b/arch/m68knommu/kernel/comempci.c new file mode 100644 index 000000000000..8670938f1107 --- /dev/null +++ b/arch/m68knommu/kernel/comempci.c | |||
@@ -0,0 +1,989 @@ | |||
1 | /*****************************************************************************/ | ||
2 | |||
3 | /* | ||
4 | * comemlite.c -- PCI access code for embedded CO-MEM Lite PCI controller. | ||
5 | * | ||
6 | * (C) Copyright 1999-2003, Greg Ungerer (gerg@snapgear.com). | ||
7 | * (C) Copyright 2000, Lineo (www.lineo.com) | ||
8 | */ | ||
9 | |||
10 | /*****************************************************************************/ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/ptrace.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <asm/coldfire.h> | ||
21 | #include <asm/mcfsim.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <asm/anchor.h> | ||
24 | |||
25 | #ifdef CONFIG_eLIA | ||
26 | #include <asm/elia.h> | ||
27 | #endif | ||
28 | |||
29 | /*****************************************************************************/ | ||
30 | |||
31 | /* | ||
32 | * Debug configuration defines. DEBUGRES sets debugging output for | ||
33 | * the resource allocation phase. DEBUGPCI traces on pcibios_ function | ||
34 | * calls, and DEBUGIO traces all accesses to devices on the PCI bus. | ||
35 | */ | ||
36 | /*#define DEBUGRES 1*/ | ||
37 | /*#define DEBUGPCI 1*/ | ||
38 | /*#define DEBUGIO 1*/ | ||
39 | |||
40 | /*****************************************************************************/ | ||
41 | |||
42 | /* | ||
43 | * PCI markers for bus present and active slots. | ||
44 | */ | ||
45 | int pci_bus_is_present = 0; | ||
46 | unsigned long pci_slotmask = 0; | ||
47 | |||
48 | /* | ||
49 | * We may or may not need to swap the bytes of PCI bus tranfers. | ||
50 | * The endianess is re-roder automatically by the CO-MEM, but it | ||
51 | * will get the wrong byte order for a pure data stream. | ||
52 | */ | ||
53 | #define pci_byteswap 0 | ||
54 | |||
55 | |||
56 | /* | ||
57 | * Resource tracking. The CO-MEM part creates a virtual address | ||
58 | * space that all the PCI devices live in - it is not in any way | ||
59 | * directly mapped into the ColdFire address space. So we can | ||
60 | * really assign any resources we like to devices, as long as | ||
61 | * they do not clash with other PCI devices. | ||
62 | */ | ||
63 | unsigned int pci_iobase = PCIBIOS_MIN_IO; /* Arbitrary start address */ | ||
64 | unsigned int pci_membase = PCIBIOS_MIN_MEM; /* Arbitrary start address */ | ||
65 | |||
66 | #define PCI_MINIO 0x100 /* 256 byte minimum I/O */ | ||
67 | #define PCI_MINMEM 0x00010000 /* 64k minimum chunk */ | ||
68 | |||
69 | /* | ||
70 | * The CO-MEM's shared memory segment is visible inside the PCI | ||
71 | * memory address space. We need to keep track of the address that | ||
72 | * this is mapped at, to setup the bus masters pointers. | ||
73 | */ | ||
74 | unsigned int pci_shmemaddr; | ||
75 | |||
76 | /*****************************************************************************/ | ||
77 | |||
78 | void pci_interrupt(int irq, void *id, struct pt_regs *fp); | ||
79 | |||
80 | /*****************************************************************************/ | ||
81 | |||
82 | /* | ||
83 | * Some platforms have custom ways of reseting the PCI bus. | ||
84 | */ | ||
85 | |||
86 | void pci_resetbus(void) | ||
87 | { | ||
88 | #ifdef CONFIG_eLIA | ||
89 | int i; | ||
90 | |||
91 | #ifdef DEBUGPCI | ||
92 | printk(KERN_DEBUG "pci_resetbus()\n"); | ||
93 | #endif | ||
94 | |||
95 | *((volatile unsigned short *) (MCF_MBAR+MCFSIM_PADDR)) |= eLIA_PCIRESET; | ||
96 | for (i = 0; (i < 1000); i++) { | ||
97 | *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = | ||
98 | (ppdata | eLIA_PCIRESET); | ||
99 | } | ||
100 | |||
101 | |||
102 | *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = ppdata; | ||
103 | #endif | ||
104 | } | ||
105 | |||
106 | /*****************************************************************************/ | ||
107 | |||
108 | int pcibios_assign_resource_slot(int slot) | ||
109 | { | ||
110 | volatile unsigned long *rp; | ||
111 | volatile unsigned char *ip; | ||
112 | unsigned int idsel, addr, val, align, i; | ||
113 | int bar; | ||
114 | |||
115 | #ifdef DEBUGPCI | ||
116 | printk(KERN_INFO "pcibios_assign_resource_slot(slot=%x)\n", slot); | ||
117 | #endif | ||
118 | |||
119 | rp = (volatile unsigned long *) COMEM_BASE; | ||
120 | idsel = COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
121 | |||
122 | /* Try to assign resource to each BAR */ | ||
123 | for (bar = 0; (bar < 6); bar++) { | ||
124 | addr = COMEM_PCIBUS + PCI_BASE_ADDRESS_0 + (bar * 4); | ||
125 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
126 | val = rp[LREG(addr)]; | ||
127 | #ifdef DEBUGRES | ||
128 | printk(KERN_DEBUG "-----------------------------------" | ||
129 | "-------------------------------------\n"); | ||
130 | printk(KERN_DEBUG "BAR[%d]: read=%08x ", bar, val); | ||
131 | #endif | ||
132 | |||
133 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
134 | rp[LREG(addr)] = 0xffffffff; | ||
135 | |||
136 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
137 | val = rp[LREG(addr)]; | ||
138 | #ifdef DEBUGRES | ||
139 | printk(KERN_DEBUG "write=%08x ", val); | ||
140 | #endif | ||
141 | if (val == 0) { | ||
142 | #ifdef DEBUGRES | ||
143 | printk(KERN_DEBUG "\n"); | ||
144 | #endif | ||
145 | continue; | ||
146 | } | ||
147 | |||
148 | /* Determine space required by BAR */ | ||
149 | /* FIXME: this should go backwords from 0x80000000... */ | ||
150 | for (i = 0; (i < 32); i++) { | ||
151 | if ((0x1 << i) & (val & 0xfffffffc)) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | #ifdef DEBUGRES | ||
156 | printk(KERN_DEBUG "size=%08x(%d)\n", (0x1 << i), i); | ||
157 | #endif | ||
158 | i = 0x1 << i; | ||
159 | |||
160 | /* Assign a resource */ | ||
161 | if (val & PCI_BASE_ADDRESS_SPACE_IO) { | ||
162 | if (i < PCI_MINIO) | ||
163 | i = PCI_MINIO; | ||
164 | #ifdef DEBUGRES | ||
165 | printk(KERN_DEBUG "BAR[%d]: IO size=%08x iobase=%08x\n", | ||
166 | bar, i, pci_iobase); | ||
167 | #endif | ||
168 | if (i > 0xffff) { | ||
169 | /* Invalid size?? */ | ||
170 | val = 0 | PCI_BASE_ADDRESS_SPACE_IO; | ||
171 | #ifdef DEBUGRES | ||
172 | printk(KERN_DEBUG "BAR[%d]: too big for IO??\n", bar); | ||
173 | #endif | ||
174 | } else { | ||
175 | /* Check for un-alignment */ | ||
176 | if ((align = pci_iobase % i)) | ||
177 | pci_iobase += (i - align); | ||
178 | val = pci_iobase | PCI_BASE_ADDRESS_SPACE_IO; | ||
179 | pci_iobase += i; | ||
180 | } | ||
181 | } else { | ||
182 | if (i < PCI_MINMEM) | ||
183 | i = PCI_MINMEM; | ||
184 | #ifdef DEBUGRES | ||
185 | printk(KERN_DEBUG "BAR[%d]: MEMORY size=%08x membase=%08x\n", | ||
186 | bar, i, pci_membase); | ||
187 | #endif | ||
188 | /* Check for un-alignment */ | ||
189 | if ((align = pci_membase % i)) | ||
190 | pci_membase += (i - align); | ||
191 | val = pci_membase | PCI_BASE_ADDRESS_SPACE_MEMORY; | ||
192 | pci_membase += i; | ||
193 | } | ||
194 | |||
195 | /* Write resource back into BAR register */ | ||
196 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
197 | rp[LREG(addr)] = val; | ||
198 | #ifdef DEBUGRES | ||
199 | printk(KERN_DEBUG "BAR[%d]: assigned bar=%08x\n", bar, val); | ||
200 | #endif | ||
201 | } | ||
202 | |||
203 | #ifdef DEBUGRES | ||
204 | printk(KERN_DEBUG "-----------------------------------" | ||
205 | "-------------------------------------\n"); | ||
206 | #endif | ||
207 | |||
208 | /* Assign IRQ if one is wanted... */ | ||
209 | ip = (volatile unsigned char *) (COMEM_BASE + COMEM_PCIBUS); | ||
210 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
211 | |||
212 | addr = (PCI_INTERRUPT_PIN & 0xfc) + (~PCI_INTERRUPT_PIN & 0x03); | ||
213 | if (ip[addr]) { | ||
214 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
215 | addr = (PCI_INTERRUPT_LINE & 0xfc)+(~PCI_INTERRUPT_LINE & 0x03); | ||
216 | ip[addr] = 25; | ||
217 | #ifdef DEBUGRES | ||
218 | printk(KERN_DEBUG "IRQ LINE=25\n"); | ||
219 | #endif | ||
220 | } | ||
221 | |||
222 | return(0); | ||
223 | } | ||
224 | |||
225 | /*****************************************************************************/ | ||
226 | |||
227 | int pcibios_enable_slot(int slot) | ||
228 | { | ||
229 | volatile unsigned long *rp; | ||
230 | volatile unsigned short *wp; | ||
231 | unsigned int idsel, addr; | ||
232 | unsigned short cmd; | ||
233 | |||
234 | #ifdef DEBUGPCI | ||
235 | printk(KERN_DEBUG "pcibios_enbale_slot(slot=%x)\n", slot); | ||
236 | #endif | ||
237 | |||
238 | rp = (volatile unsigned long *) COMEM_BASE; | ||
239 | wp = (volatile unsigned short *) COMEM_BASE; | ||
240 | idsel = COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
241 | |||
242 | /* Get current command settings */ | ||
243 | addr = COMEM_PCIBUS + PCI_COMMAND; | ||
244 | addr = (addr & ~0x3) + (~addr & 0x02); | ||
245 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel; | ||
246 | cmd = wp[WREG(addr)]; | ||
247 | /*val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);*/ | ||
248 | |||
249 | /* Enable I/O and memory accesses to this device */ | ||
250 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel; | ||
251 | cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | ||
252 | wp[WREG(addr)] = cmd; | ||
253 | |||
254 | return(0); | ||
255 | } | ||
256 | |||
257 | /*****************************************************************************/ | ||
258 | |||
259 | void pcibios_assign_resources(void) | ||
260 | { | ||
261 | volatile unsigned long *rp; | ||
262 | unsigned long sel, id; | ||
263 | int slot; | ||
264 | |||
265 | rp = (volatile unsigned long *) COMEM_BASE; | ||
266 | |||
267 | /* | ||
268 | * Do a quick scan of the PCI bus and see what is here. | ||
269 | */ | ||
270 | for (slot = COMEM_MINDEV; (slot <= COMEM_MAXDEV); slot++) { | ||
271 | sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
272 | rp[LREG(COMEM_DAHBASE)] = sel; | ||
273 | rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */ | ||
274 | id = rp[LREG(COMEM_PCIBUS)]; | ||
275 | if ((id != 0) && ((id & 0xffff0000) != (sel & 0xffff0000))) { | ||
276 | printk(KERN_INFO "PCI: slot=%d id=%08x\n", slot, (int) id); | ||
277 | pci_slotmask |= 0x1 << slot; | ||
278 | pcibios_assign_resource_slot(slot); | ||
279 | pcibios_enable_slot(slot); | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | /*****************************************************************************/ | ||
285 | |||
286 | int pcibios_init(void) | ||
287 | { | ||
288 | volatile unsigned long *rp; | ||
289 | unsigned long sel, id; | ||
290 | int slot; | ||
291 | |||
292 | #ifdef DEBUGPCI | ||
293 | printk(KERN_DEBUG "pcibios_init()\n"); | ||
294 | #endif | ||
295 | |||
296 | pci_resetbus(); | ||
297 | |||
298 | /* | ||
299 | * Do some sort of basic check to see if the CO-MEM part | ||
300 | * is present... This works ok, but I think we really need | ||
301 | * something better... | ||
302 | */ | ||
303 | rp = (volatile unsigned long *) COMEM_BASE; | ||
304 | if ((rp[LREG(COMEM_LBUSCFG)] & 0xff) != 0x50) { | ||
305 | printk(KERN_INFO "PCI: no PCI bus present\n"); | ||
306 | return(0); | ||
307 | } | ||
308 | |||
309 | #ifdef COMEM_BRIDGEDEV | ||
310 | /* | ||
311 | * Setup the PCI bridge device first. It needs resources too, | ||
312 | * so that bus masters can get to its shared memory. | ||
313 | */ | ||
314 | slot = COMEM_BRIDGEDEV; | ||
315 | sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16)); | ||
316 | rp[LREG(COMEM_DAHBASE)] = sel; | ||
317 | rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */ | ||
318 | id = rp[LREG(COMEM_PCIBUS)]; | ||
319 | if ((id == 0) || ((id & 0xffff0000) == (sel & 0xffff0000))) { | ||
320 | printk(KERN_INFO "PCI: no PCI bus bridge present\n"); | ||
321 | return(0); | ||
322 | } | ||
323 | |||
324 | printk(KERN_INFO "PCI: bridge device at slot=%d id=%08x\n", slot, (int) id); | ||
325 | pci_slotmask |= 0x1 << slot; | ||
326 | pci_shmemaddr = pci_membase; | ||
327 | pcibios_assign_resource_slot(slot); | ||
328 | pcibios_enable_slot(slot); | ||
329 | #endif | ||
330 | |||
331 | pci_bus_is_present = 1; | ||
332 | |||
333 | /* Get PCI irq for local vectoring */ | ||
334 | if (request_irq(COMEM_IRQ, pci_interrupt, 0, "PCI bridge", NULL)) { | ||
335 | printk(KERN_WARNING "PCI: failed to acquire interrupt %d\n", COMEM_IRQ); | ||
336 | } else { | ||
337 | mcf_autovector(COMEM_IRQ); | ||
338 | } | ||
339 | |||
340 | pcibios_assign_resources(); | ||
341 | |||
342 | return(0); | ||
343 | } | ||
344 | |||
345 | /*****************************************************************************/ | ||
346 | |||
347 | char *pcibios_setup(char *option) | ||
348 | { | ||
349 | /* Nothing for us to handle. */ | ||
350 | return(option); | ||
351 | } | ||
352 | /*****************************************************************************/ | ||
353 | |||
354 | void pcibios_fixup_bus(struct pci_bus *b) | ||
355 | { | ||
356 | } | ||
357 | |||
358 | /*****************************************************************************/ | ||
359 | |||
360 | void pcibios_align_resource(void *data, struct resource *res, unsigned long size, unsigned long align) | ||
361 | { | ||
362 | } | ||
363 | |||
364 | /*****************************************************************************/ | ||
365 | |||
366 | int pcibios_enable_device(struct pci_dev *dev, int mask) | ||
367 | { | ||
368 | int slot; | ||
369 | |||
370 | slot = PCI_SLOT(dev->devfn); | ||
371 | if ((dev->bus == 0) && (pci_slotmask & (1 << slot))) | ||
372 | pcibios_enable_slot(slot); | ||
373 | return(0); | ||
374 | } | ||
375 | |||
376 | /*****************************************************************************/ | ||
377 | |||
378 | void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *r, int resource) | ||
379 | { | ||
380 | printk(KERN_WARNING "%s(%d): no support for changing PCI resources...\n", | ||
381 | __FILE__, __LINE__); | ||
382 | } | ||
383 | |||
384 | |||
385 | /*****************************************************************************/ | ||
386 | |||
387 | /* | ||
388 | * Local routines to interrcept the standard I/O and vector handling | ||
389 | * code. Don't include this 'till now - initialization code above needs | ||
390 | * access to the real code too. | ||
391 | */ | ||
392 | #include <asm/mcfpci.h> | ||
393 | |||
394 | /*****************************************************************************/ | ||
395 | |||
396 | void pci_outb(unsigned char val, unsigned int addr) | ||
397 | { | ||
398 | volatile unsigned long *rp; | ||
399 | volatile unsigned char *bp; | ||
400 | |||
401 | #ifdef DEBUGIO | ||
402 | printk(KERN_DEBUG "pci_outb(val=%02x,addr=%x)\n", val, addr); | ||
403 | #endif | ||
404 | |||
405 | rp = (volatile unsigned long *) COMEM_BASE; | ||
406 | bp = (volatile unsigned char *) COMEM_BASE; | ||
407 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); | ||
408 | addr = (addr & ~0x3) + (~addr & 0x03); | ||
409 | bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; | ||
410 | } | ||
411 | |||
412 | /*****************************************************************************/ | ||
413 | |||
414 | void pci_outw(unsigned short val, unsigned int addr) | ||
415 | { | ||
416 | volatile unsigned long *rp; | ||
417 | volatile unsigned short *sp; | ||
418 | |||
419 | #ifdef DEBUGIO | ||
420 | printk(KERN_DEBUG "pci_outw(val=%04x,addr=%x)\n", val, addr); | ||
421 | #endif | ||
422 | |||
423 | rp = (volatile unsigned long *) COMEM_BASE; | ||
424 | sp = (volatile unsigned short *) COMEM_BASE; | ||
425 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); | ||
426 | addr = (addr & ~0x3) + (~addr & 0x02); | ||
427 | if (pci_byteswap) | ||
428 | val = ((val & 0xff) << 8) | ((val >> 8) & 0xff); | ||
429 | sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; | ||
430 | } | ||
431 | |||
432 | /*****************************************************************************/ | ||
433 | |||
434 | void pci_outl(unsigned int val, unsigned int addr) | ||
435 | { | ||
436 | volatile unsigned long *rp; | ||
437 | volatile unsigned int *lp; | ||
438 | |||
439 | #ifdef DEBUGIO | ||
440 | printk(KERN_DEBUG "pci_outl(val=%08x,addr=%x)\n", val, addr); | ||
441 | #endif | ||
442 | |||
443 | rp = (volatile unsigned long *) COMEM_BASE; | ||
444 | lp = (volatile unsigned int *) COMEM_BASE; | ||
445 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr); | ||
446 | |||
447 | if (pci_byteswap) | ||
448 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
449 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
450 | |||
451 | lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val; | ||
452 | } | ||
453 | |||
454 | /*****************************************************************************/ | ||
455 | |||
456 | unsigned long pci_blmask[] = { | ||
457 | 0x000000e0, | ||
458 | 0x000000d0, | ||
459 | 0x000000b0, | ||
460 | 0x00000070 | ||
461 | }; | ||
462 | |||
463 | unsigned char pci_inb(unsigned int addr) | ||
464 | { | ||
465 | volatile unsigned long *rp; | ||
466 | volatile unsigned char *bp; | ||
467 | unsigned long r; | ||
468 | unsigned char val; | ||
469 | |||
470 | #ifdef DEBUGIO | ||
471 | printk(KERN_DEBUG "pci_inb(addr=%x)\n", addr); | ||
472 | #endif | ||
473 | |||
474 | rp = (volatile unsigned long *) COMEM_BASE; | ||
475 | bp = (volatile unsigned char *) COMEM_BASE; | ||
476 | |||
477 | r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_blmask[(addr & 0x3)]; | ||
478 | rp[LREG(COMEM_DAHBASE)] = r; | ||
479 | |||
480 | addr = (addr & ~0x3) + (~addr & 0x3); | ||
481 | val = bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; | ||
482 | return(val); | ||
483 | } | ||
484 | |||
485 | /*****************************************************************************/ | ||
486 | |||
487 | unsigned long pci_bwmask[] = { | ||
488 | 0x000000c0, | ||
489 | 0x000000c0, | ||
490 | 0x00000030, | ||
491 | 0x00000030 | ||
492 | }; | ||
493 | |||
494 | unsigned short pci_inw(unsigned int addr) | ||
495 | { | ||
496 | volatile unsigned long *rp; | ||
497 | volatile unsigned short *sp; | ||
498 | unsigned long r; | ||
499 | unsigned short val; | ||
500 | |||
501 | #ifdef DEBUGIO | ||
502 | printk(KERN_DEBUG "pci_inw(addr=%x)", addr); | ||
503 | #endif | ||
504 | |||
505 | rp = (volatile unsigned long *) COMEM_BASE; | ||
506 | r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_bwmask[(addr & 0x3)]; | ||
507 | rp[LREG(COMEM_DAHBASE)] = r; | ||
508 | |||
509 | sp = (volatile unsigned short *) COMEM_BASE; | ||
510 | addr = (addr & ~0x3) + (~addr & 0x02); | ||
511 | val = sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; | ||
512 | if (pci_byteswap) | ||
513 | val = ((val & 0xff) << 8) | ((val >> 8) & 0xff); | ||
514 | #ifdef DEBUGIO | ||
515 | printk(KERN_DEBUG "=%04x\n", val); | ||
516 | #endif | ||
517 | return(val); | ||
518 | } | ||
519 | |||
520 | /*****************************************************************************/ | ||
521 | |||
522 | unsigned int pci_inl(unsigned int addr) | ||
523 | { | ||
524 | volatile unsigned long *rp; | ||
525 | volatile unsigned int *lp; | ||
526 | unsigned int val; | ||
527 | |||
528 | #ifdef DEBUGIO | ||
529 | printk(KERN_DEBUG "pci_inl(addr=%x)", addr); | ||
530 | #endif | ||
531 | |||
532 | rp = (volatile unsigned long *) COMEM_BASE; | ||
533 | lp = (volatile unsigned int *) COMEM_BASE; | ||
534 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(addr); | ||
535 | val = lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))]; | ||
536 | |||
537 | if (pci_byteswap) | ||
538 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
539 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
540 | |||
541 | #ifdef DEBUGIO | ||
542 | printk(KERN_DEBUG "=%08x\n", val); | ||
543 | #endif | ||
544 | return(val); | ||
545 | } | ||
546 | |||
547 | /*****************************************************************************/ | ||
548 | |||
549 | void pci_outsb(void *addr, void *buf, int len) | ||
550 | { | ||
551 | volatile unsigned long *rp; | ||
552 | volatile unsigned char *bp; | ||
553 | unsigned char *dp = (unsigned char *) buf; | ||
554 | unsigned int a = (unsigned int) addr; | ||
555 | |||
556 | #ifdef DEBUGIO | ||
557 | printk(KERN_DEBUG "pci_outsb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
558 | #endif | ||
559 | |||
560 | rp = (volatile unsigned long *) COMEM_BASE; | ||
561 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); | ||
562 | |||
563 | a = (a & ~0x3) + (~a & 0x03); | ||
564 | bp = (volatile unsigned char *) | ||
565 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
566 | |||
567 | while (len--) | ||
568 | *bp = *dp++; | ||
569 | } | ||
570 | |||
571 | /*****************************************************************************/ | ||
572 | |||
573 | void pci_outsw(void *addr, void *buf, int len) | ||
574 | { | ||
575 | volatile unsigned long *rp; | ||
576 | volatile unsigned short *wp; | ||
577 | unsigned short w, *dp = (unsigned short *) buf; | ||
578 | unsigned int a = (unsigned int) addr; | ||
579 | |||
580 | #ifdef DEBUGIO | ||
581 | printk(KERN_DEBUG "pci_outsw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
582 | #endif | ||
583 | |||
584 | rp = (volatile unsigned long *) COMEM_BASE; | ||
585 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); | ||
586 | |||
587 | a = (a & ~0x3) + (~a & 0x2); | ||
588 | wp = (volatile unsigned short *) | ||
589 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
590 | |||
591 | while (len--) { | ||
592 | w = *dp++; | ||
593 | if (pci_byteswap) | ||
594 | w = ((w & 0xff) << 8) | ((w >> 8) & 0xff); | ||
595 | *wp = w; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | /*****************************************************************************/ | ||
600 | |||
601 | void pci_outsl(void *addr, void *buf, int len) | ||
602 | { | ||
603 | volatile unsigned long *rp; | ||
604 | volatile unsigned long *lp; | ||
605 | unsigned long l, *dp = (unsigned long *) buf; | ||
606 | unsigned int a = (unsigned int) addr; | ||
607 | |||
608 | #ifdef DEBUGIO | ||
609 | printk(KERN_DEBUG "pci_outsl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
610 | #endif | ||
611 | |||
612 | rp = (volatile unsigned long *) COMEM_BASE; | ||
613 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a); | ||
614 | |||
615 | lp = (volatile unsigned long *) | ||
616 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
617 | |||
618 | while (len--) { | ||
619 | l = *dp++; | ||
620 | if (pci_byteswap) | ||
621 | l = (l << 24) | ((l & 0x0000ff00) << 8) | | ||
622 | ((l & 0x00ff0000) >> 8) | (l >> 24); | ||
623 | *lp = l; | ||
624 | } | ||
625 | } | ||
626 | |||
627 | /*****************************************************************************/ | ||
628 | |||
629 | void pci_insb(void *addr, void *buf, int len) | ||
630 | { | ||
631 | volatile unsigned long *rp; | ||
632 | volatile unsigned char *bp; | ||
633 | unsigned char *dp = (unsigned char *) buf; | ||
634 | unsigned int a = (unsigned int) addr; | ||
635 | |||
636 | #ifdef DEBUGIO | ||
637 | printk(KERN_DEBUG "pci_insb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
638 | #endif | ||
639 | |||
640 | rp = (volatile unsigned long *) COMEM_BASE; | ||
641 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); | ||
642 | |||
643 | a = (a & ~0x3) + (~a & 0x03); | ||
644 | bp = (volatile unsigned char *) | ||
645 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
646 | |||
647 | while (len--) | ||
648 | *dp++ = *bp; | ||
649 | } | ||
650 | |||
651 | /*****************************************************************************/ | ||
652 | |||
653 | void pci_insw(void *addr, void *buf, int len) | ||
654 | { | ||
655 | volatile unsigned long *rp; | ||
656 | volatile unsigned short *wp; | ||
657 | unsigned short w, *dp = (unsigned short *) buf; | ||
658 | unsigned int a = (unsigned int) addr; | ||
659 | |||
660 | #ifdef DEBUGIO | ||
661 | printk(KERN_DEBUG "pci_insw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
662 | #endif | ||
663 | |||
664 | rp = (volatile unsigned long *) COMEM_BASE; | ||
665 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); | ||
666 | |||
667 | a = (a & ~0x3) + (~a & 0x2); | ||
668 | wp = (volatile unsigned short *) | ||
669 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
670 | |||
671 | while (len--) { | ||
672 | w = *wp; | ||
673 | if (pci_byteswap) | ||
674 | w = ((w & 0xff) << 8) | ((w >> 8) & 0xff); | ||
675 | *dp++ = w; | ||
676 | } | ||
677 | } | ||
678 | |||
679 | /*****************************************************************************/ | ||
680 | |||
681 | void pci_insl(void *addr, void *buf, int len) | ||
682 | { | ||
683 | volatile unsigned long *rp; | ||
684 | volatile unsigned long *lp; | ||
685 | unsigned long l, *dp = (unsigned long *) buf; | ||
686 | unsigned int a = (unsigned int) addr; | ||
687 | |||
688 | #ifdef DEBUGIO | ||
689 | printk(KERN_DEBUG "pci_insl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len); | ||
690 | #endif | ||
691 | |||
692 | rp = (volatile unsigned long *) COMEM_BASE; | ||
693 | rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a); | ||
694 | |||
695 | lp = (volatile unsigned long *) | ||
696 | (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a)); | ||
697 | |||
698 | while (len--) { | ||
699 | l = *lp; | ||
700 | if (pci_byteswap) | ||
701 | l = (l << 24) | ((l & 0x0000ff00) << 8) | | ||
702 | ((l & 0x00ff0000) >> 8) | (l >> 24); | ||
703 | *dp++ = l; | ||
704 | } | ||
705 | } | ||
706 | |||
707 | /*****************************************************************************/ | ||
708 | |||
709 | struct pci_localirqlist { | ||
710 | void (*handler)(int, void *, struct pt_regs *); | ||
711 | const char *device; | ||
712 | void *dev_id; | ||
713 | }; | ||
714 | |||
715 | struct pci_localirqlist pci_irqlist[COMEM_MAXPCI]; | ||
716 | |||
717 | /*****************************************************************************/ | ||
718 | |||
719 | int pci_request_irq(unsigned int irq, | ||
720 | void (*handler)(int, void *, struct pt_regs *), | ||
721 | unsigned long flags, const char *device, void *dev_id) | ||
722 | { | ||
723 | int i; | ||
724 | |||
725 | #ifdef DEBUGIO | ||
726 | printk(KERN_DEBUG "pci_request_irq(irq=%d,handler=%x,flags=%x,device=%s," | ||
727 | "dev_id=%x)\n", irq, (int) handler, (int) flags, device, | ||
728 | (int) dev_id); | ||
729 | #endif | ||
730 | |||
731 | /* Check if this interrupt handler is already lodged */ | ||
732 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
733 | if (pci_irqlist[i].handler == handler) | ||
734 | return(0); | ||
735 | } | ||
736 | |||
737 | /* Find a free spot to put this handler */ | ||
738 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
739 | if (pci_irqlist[i].handler == 0) { | ||
740 | pci_irqlist[i].handler = handler; | ||
741 | pci_irqlist[i].device = device; | ||
742 | pci_irqlist[i].dev_id = dev_id; | ||
743 | return(0); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | /* Couldn't fit?? */ | ||
748 | return(1); | ||
749 | } | ||
750 | |||
751 | /*****************************************************************************/ | ||
752 | |||
753 | void pci_free_irq(unsigned int irq, void *dev_id) | ||
754 | { | ||
755 | int i; | ||
756 | |||
757 | #ifdef DEBUGIO | ||
758 | printk(KERN_DEBUG "pci_free_irq(irq=%d,dev_id=%x)\n", irq, (int) dev_id); | ||
759 | #endif | ||
760 | |||
761 | if (dev_id == (void *) NULL) | ||
762 | return; | ||
763 | |||
764 | /* Check if this interrupt handler is lodged */ | ||
765 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
766 | if (pci_irqlist[i].dev_id == dev_id) { | ||
767 | pci_irqlist[i].handler = NULL; | ||
768 | pci_irqlist[i].device = NULL; | ||
769 | pci_irqlist[i].dev_id = NULL; | ||
770 | break; | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | /*****************************************************************************/ | ||
776 | |||
777 | void pci_interrupt(int irq, void *id, struct pt_regs *fp) | ||
778 | { | ||
779 | int i; | ||
780 | |||
781 | #ifdef DEBUGIO | ||
782 | printk(KERN_DEBUG "pci_interrupt(irq=%d,id=%x,fp=%x)\n", irq, (int) id, (int) fp); | ||
783 | #endif | ||
784 | |||
785 | for (i = 0; (i < COMEM_MAXPCI); i++) { | ||
786 | if (pci_irqlist[i].handler) | ||
787 | (*pci_irqlist[i].handler)(irq,pci_irqlist[i].dev_id,fp); | ||
788 | } | ||
789 | } | ||
790 | |||
791 | /*****************************************************************************/ | ||
792 | |||
793 | /* | ||
794 | * The shared memory region is broken up into contiguous 512 byte | ||
795 | * regions for easy allocation... This is not an optimal solution | ||
796 | * but it makes allocation and freeing regions really easy. | ||
797 | */ | ||
798 | |||
799 | #define PCI_MEMSLOTSIZE 512 | ||
800 | #define PCI_MEMSLOTS (COMEM_SHMEMSIZE / PCI_MEMSLOTSIZE) | ||
801 | |||
802 | char pci_shmemmap[PCI_MEMSLOTS]; | ||
803 | |||
804 | |||
805 | void *pci_bmalloc(int size) | ||
806 | { | ||
807 | int i, j, nrslots; | ||
808 | |||
809 | #ifdef DEBUGIO | ||
810 | printk(KERN_DEBUG "pci_bmalloc(size=%d)\n", size); | ||
811 | #endif | ||
812 | |||
813 | if (size <= 0) | ||
814 | return((void *) NULL); | ||
815 | |||
816 | nrslots = (size - 1) / PCI_MEMSLOTSIZE; | ||
817 | |||
818 | for (i = 0; (i < (PCI_MEMSLOTS-nrslots)); i++) { | ||
819 | if (pci_shmemmap[i] == 0) { | ||
820 | for (j = i+1; (j < (i+nrslots)); j++) { | ||
821 | if (pci_shmemmap[j]) | ||
822 | goto restart; | ||
823 | } | ||
824 | |||
825 | for (j = i; (j <= i+nrslots); j++) | ||
826 | pci_shmemmap[j] = 1; | ||
827 | break; | ||
828 | } | ||
829 | restart: | ||
830 | } | ||
831 | |||
832 | return((void *) (COMEM_BASE + COMEM_SHMEM + (i * PCI_MEMSLOTSIZE))); | ||
833 | } | ||
834 | |||
835 | /*****************************************************************************/ | ||
836 | |||
837 | void pci_bmfree(void *mp, int size) | ||
838 | { | ||
839 | int i, j, nrslots; | ||
840 | |||
841 | #ifdef DEBUGIO | ||
842 | printk(KERN_DEBUG "pci_bmfree(mp=%x,size=%d)\n", (int) mp, size); | ||
843 | #endif | ||
844 | |||
845 | nrslots = size / PCI_MEMSLOTSIZE; | ||
846 | i = (((unsigned long) mp) - (COMEM_BASE + COMEM_SHMEM)) / | ||
847 | PCI_MEMSLOTSIZE; | ||
848 | |||
849 | for (j = i; (j < (i+nrslots)); j++) | ||
850 | pci_shmemmap[j] = 0; | ||
851 | } | ||
852 | |||
853 | /*****************************************************************************/ | ||
854 | |||
855 | unsigned long pci_virt_to_bus(volatile void *address) | ||
856 | { | ||
857 | unsigned long l; | ||
858 | |||
859 | #ifdef DEBUGIO | ||
860 | printk(KERN_DEBUG "pci_virt_to_bus(address=%x)", (int) address); | ||
861 | #endif | ||
862 | |||
863 | l = ((unsigned long) address) - COMEM_BASE; | ||
864 | #ifdef DEBUGIO | ||
865 | printk(KERN_DEBUG "=%x\n", (int) (l+pci_shmemaddr)); | ||
866 | #endif | ||
867 | return(l + pci_shmemaddr); | ||
868 | } | ||
869 | |||
870 | /*****************************************************************************/ | ||
871 | |||
872 | void *pci_bus_to_virt(unsigned long address) | ||
873 | { | ||
874 | unsigned long l; | ||
875 | |||
876 | #ifdef DEBUGIO | ||
877 | printk(KERN_DEBUG "pci_bus_to_virt(address=%x)", (int) address); | ||
878 | #endif | ||
879 | |||
880 | l = address - pci_shmemaddr; | ||
881 | #ifdef DEBUGIO | ||
882 | printk(KERN_DEBUG "=%x\n", (int) (address + COMEM_BASE)); | ||
883 | #endif | ||
884 | return((void *) (address + COMEM_BASE)); | ||
885 | } | ||
886 | |||
887 | /*****************************************************************************/ | ||
888 | |||
889 | void pci_bmcpyto(void *dst, void *src, int len) | ||
890 | { | ||
891 | unsigned long *dp, *sp, val; | ||
892 | unsigned char *dcp, *scp; | ||
893 | int i, j; | ||
894 | |||
895 | #ifdef DEBUGIO | ||
896 | printk(KERN_DEBUG "pci_bmcpyto(dst=%x,src=%x,len=%d)\n", (int)dst, (int)src, len); | ||
897 | #endif | ||
898 | |||
899 | dp = (unsigned long *) dst; | ||
900 | sp = (unsigned long *) src; | ||
901 | i = len >> 2; | ||
902 | |||
903 | #if 0 | ||
904 | printk(KERN_INFO "DATA:"); | ||
905 | scp = (unsigned char *) sp; | ||
906 | for (i = 0; (i < len); i++) { | ||
907 | if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i); | ||
908 | printk(KERN_INFO "%02x ", *scp++); | ||
909 | } | ||
910 | printk(KERN_INFO "\n"); | ||
911 | #endif | ||
912 | |||
913 | for (j = 0; (i >= 0); i--, j++) { | ||
914 | val = *sp++; | ||
915 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
916 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
917 | *dp++ = val; | ||
918 | } | ||
919 | |||
920 | if (len & 0x3) { | ||
921 | dcp = (unsigned char *) dp; | ||
922 | scp = ((unsigned char *) sp) + 3; | ||
923 | for (i = 0; (i < (len & 0x3)); i++) | ||
924 | *dcp++ = *scp--; | ||
925 | } | ||
926 | } | ||
927 | |||
928 | /*****************************************************************************/ | ||
929 | |||
930 | void pci_bmcpyfrom(void *dst, void *src, int len) | ||
931 | { | ||
932 | unsigned long *dp, *sp, val; | ||
933 | unsigned char *dcp, *scp; | ||
934 | int i; | ||
935 | |||
936 | #ifdef DEBUGIO | ||
937 | printk(KERN_DEBUG "pci_bmcpyfrom(dst=%x,src=%x,len=%d)\n",(int)dst,(int)src,len); | ||
938 | #endif | ||
939 | |||
940 | dp = (unsigned long *) dst; | ||
941 | sp = (unsigned long *) src; | ||
942 | i = len >> 2; | ||
943 | |||
944 | for (; (i >= 0); i--) { | ||
945 | val = *sp++; | ||
946 | val = (val << 24) | ((val & 0x0000ff00) << 8) | | ||
947 | ((val & 0x00ff0000) >> 8) | (val >> 24); | ||
948 | *dp++ = val; | ||
949 | } | ||
950 | |||
951 | if (len & 0x3) { | ||
952 | dcp = ((unsigned char *) dp) + 3; | ||
953 | scp = (unsigned char *) sp; | ||
954 | for (i = 0; (i < (len & 0x3)); i++) | ||
955 | *dcp++ = *scp--; | ||
956 | } | ||
957 | |||
958 | #if 0 | ||
959 | printk(KERN_INFO "DATA:"); | ||
960 | dcp = (unsigned char *) dst; | ||
961 | for (i = 0; (i < len); i++) { | ||
962 | if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i); | ||
963 | printk(KERN_INFO "%02x ", *dcp++); | ||
964 | } | ||
965 | printk(KERN_INFO "\n"); | ||
966 | #endif | ||
967 | } | ||
968 | |||
969 | /*****************************************************************************/ | ||
970 | |||
971 | void *pci_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_addr) | ||
972 | { | ||
973 | void *mp; | ||
974 | if ((mp = pci_bmalloc(size)) != NULL) { | ||
975 | dma_addr = mp - (COMEM_BASE + COMEM_SHMEM); | ||
976 | return(mp); | ||
977 | } | ||
978 | *dma_addr = (dma_addr_t) NULL; | ||
979 | return(NULL); | ||
980 | } | ||
981 | |||
982 | /*****************************************************************************/ | ||
983 | |||
984 | void pci_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, dma_addr_t dma_addr) | ||
985 | { | ||
986 | pci_bmfree(cpu_addr, size); | ||
987 | } | ||
988 | |||
989 | /*****************************************************************************/ | ||
diff --git a/arch/m68knommu/kernel/dma.c b/arch/m68knommu/kernel/dma.c new file mode 100644 index 000000000000..14b19c4161f4 --- /dev/null +++ b/arch/m68knommu/kernel/dma.c | |||
@@ -0,0 +1,36 @@ | |||
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/mm.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/pci.h> | ||
12 | #include <asm/io.h> | ||
13 | |||
14 | void *dma_alloc_coherent(struct device *dev, size_t size, | ||
15 | dma_addr_t *dma_handle, int gfp) | ||
16 | { | ||
17 | void *ret; | ||
18 | /* ignore region specifiers */ | ||
19 | gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); | ||
20 | |||
21 | if (dev == NULL || (*dev->dma_mask < 0xffffffff)) | ||
22 | gfp |= GFP_DMA; | ||
23 | ret = (void *)__get_free_pages(gfp, get_order(size)); | ||
24 | |||
25 | if (ret != NULL) { | ||
26 | memset(ret, 0, size); | ||
27 | *dma_handle = virt_to_phys(ret); | ||
28 | } | ||
29 | return ret; | ||
30 | } | ||
31 | |||
32 | void dma_free_coherent(struct device *dev, size_t size, | ||
33 | void *vaddr, dma_addr_t dma_handle) | ||
34 | { | ||
35 | free_pages((unsigned long)vaddr, get_order(size)); | ||
36 | } | ||
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S new file mode 100644 index 000000000000..8b1f47239b9a --- /dev/null +++ b/arch/m68knommu/kernel/entry.S | |||
@@ -0,0 +1,143 @@ | |||
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/config.h> | ||
28 | #include <linux/sys.h> | ||
29 | #include <linux/linkage.h> | ||
30 | #include <asm/thread_info.h> | ||
31 | #include <asm/errno.h> | ||
32 | #include <asm/setup.h> | ||
33 | #include <asm/segment.h> | ||
34 | #include <asm/asm-offsets.h> | ||
35 | #include <asm/entry.h> | ||
36 | |||
37 | .text | ||
38 | |||
39 | .globl buserr | ||
40 | .globl trap | ||
41 | .globl ret_from_exception | ||
42 | .globl ret_from_signal | ||
43 | .globl sys_fork | ||
44 | .globl sys_clone | ||
45 | .globl sys_vfork | ||
46 | |||
47 | ENTRY(buserr) | ||
48 | SAVE_ALL | ||
49 | moveq #-1,%d0 | ||
50 | movel %d0,%sp@(PT_ORIG_D0) | ||
51 | movel %sp,%sp@- /* stack frame pointer argument */ | ||
52 | jsr buserr_c | ||
53 | addql #4,%sp | ||
54 | jra ret_from_exception | ||
55 | |||
56 | ENTRY(trap) | ||
57 | SAVE_ALL | ||
58 | moveq #-1,%d0 | ||
59 | movel %d0,%sp@(PT_ORIG_D0) | ||
60 | movel %sp,%sp@- /* stack frame pointer argument */ | ||
61 | jsr trap_c | ||
62 | addql #4,%sp | ||
63 | jra ret_from_exception | ||
64 | |||
65 | #ifdef TRAP_DBG_INTERRUPT | ||
66 | |||
67 | .globl dbginterrupt | ||
68 | ENTRY(dbginterrupt) | ||
69 | SAVE_ALL | ||
70 | moveq #-1,%d0 | ||
71 | movel %d0,%sp@(PT_ORIG_D0) | ||
72 | movel %sp,%sp@- /* stack frame pointer argument */ | ||
73 | jsr dbginterrupt_c | ||
74 | addql #4,%sp | ||
75 | jra ret_from_exception | ||
76 | #endif | ||
77 | |||
78 | ENTRY(reschedule) | ||
79 | /* save top of frame */ | ||
80 | pea %sp@ | ||
81 | jbsr set_esp0 | ||
82 | addql #4,%sp | ||
83 | pea ret_from_exception | ||
84 | jmp schedule | ||
85 | |||
86 | ENTRY(ret_from_fork) | ||
87 | movel %d1,%sp@- | ||
88 | jsr schedule_tail | ||
89 | addql #4,%sp | ||
90 | jra ret_from_exception | ||
91 | |||
92 | ENTRY(sys_fork) | ||
93 | SAVE_SWITCH_STACK | ||
94 | pea %sp@(SWITCH_STACK_SIZE) | ||
95 | jbsr m68k_fork | ||
96 | addql #4,%sp | ||
97 | RESTORE_SWITCH_STACK | ||
98 | rts | ||
99 | |||
100 | ENTRY(sys_vfork) | ||
101 | SAVE_SWITCH_STACK | ||
102 | pea %sp@(SWITCH_STACK_SIZE) | ||
103 | jbsr m68k_vfork | ||
104 | addql #4,%sp | ||
105 | RESTORE_SWITCH_STACK | ||
106 | rts | ||
107 | |||
108 | ENTRY(sys_clone) | ||
109 | SAVE_SWITCH_STACK | ||
110 | pea %sp@(SWITCH_STACK_SIZE) | ||
111 | jbsr m68k_clone | ||
112 | addql #4,%sp | ||
113 | RESTORE_SWITCH_STACK | ||
114 | rts | ||
115 | |||
116 | ENTRY(sys_sigsuspend) | ||
117 | SAVE_SWITCH_STACK | ||
118 | pea %sp@(SWITCH_STACK_SIZE) | ||
119 | jbsr do_sigsuspend | ||
120 | addql #4,%sp | ||
121 | RESTORE_SWITCH_STACK | ||
122 | rts | ||
123 | |||
124 | ENTRY(sys_rt_sigsuspend) | ||
125 | SAVE_SWITCH_STACK | ||
126 | pea %sp@(SWITCH_STACK_SIZE) | ||
127 | jbsr do_rt_sigsuspend | ||
128 | addql #4,%sp | ||
129 | RESTORE_SWITCH_STACK | ||
130 | rts | ||
131 | |||
132 | ENTRY(sys_sigreturn) | ||
133 | SAVE_SWITCH_STACK | ||
134 | jbsr do_sigreturn | ||
135 | RESTORE_SWITCH_STACK | ||
136 | rts | ||
137 | |||
138 | ENTRY(sys_rt_sigreturn) | ||
139 | SAVE_SWITCH_STACK | ||
140 | jbsr do_rt_sigreturn | ||
141 | RESTORE_SWITCH_STACK | ||
142 | rts | ||
143 | |||
diff --git a/arch/m68knommu/kernel/init_task.c b/arch/m68knommu/kernel/init_task.c new file mode 100644 index 000000000000..3897043a126a --- /dev/null +++ b/arch/m68knommu/kernel/init_task.c | |||
@@ -0,0 +1,43 @@ | |||
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 | |||
15 | static struct fs_struct init_fs = INIT_FS; | ||
16 | static struct files_struct init_files = INIT_FILES; | ||
17 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
18 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
19 | struct mm_struct init_mm = INIT_MM(init_mm); | ||
20 | |||
21 | EXPORT_SYMBOL(init_mm); | ||
22 | |||
23 | /* | ||
24 | * Initial task structure. | ||
25 | * | ||
26 | * All other task structs will be allocated on slabs in fork.c | ||
27 | */ | ||
28 | __asm__(".align 4"); | ||
29 | struct task_struct init_task = INIT_TASK(init_task); | ||
30 | |||
31 | EXPORT_SYMBOL(init_task); | ||
32 | |||
33 | /* | ||
34 | * Initial thread structure. | ||
35 | * | ||
36 | * We need to make sure that this is 8192-byte aligned due to the | ||
37 | * way process stacks are handled. This is done by having a special | ||
38 | * "init_task" linker map entry.. | ||
39 | */ | ||
40 | union thread_union init_thread_union | ||
41 | __attribute__((__section__(".data.init_task"))) = | ||
42 | { INIT_THREAD_INFO(init_task) }; | ||
43 | |||
diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c new file mode 100644 index 000000000000..e93a5ad56496 --- /dev/null +++ b/arch/m68knommu/kernel/m68k_ksyms.c | |||
@@ -0,0 +1,104 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/linkage.h> | ||
3 | #include <linux/sched.h> | ||
4 | #include <linux/string.h> | ||
5 | #include <linux/mm.h> | ||
6 | #include <linux/user.h> | ||
7 | #include <linux/elfcore.h> | ||
8 | #include <linux/in6.h> | ||
9 | #include <linux/interrupt.h> | ||
10 | #include <linux/config.h> | ||
11 | |||
12 | #include <asm/setup.h> | ||
13 | #include <asm/machdep.h> | ||
14 | #include <asm/pgalloc.h> | ||
15 | #include <asm/irq.h> | ||
16 | #include <asm/io.h> | ||
17 | #include <asm/semaphore.h> | ||
18 | #include <asm/checksum.h> | ||
19 | #include <asm/current.h> | ||
20 | |||
21 | extern void dump_thread(struct pt_regs *, struct user *); | ||
22 | extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); | ||
23 | |||
24 | /* platform dependent support */ | ||
25 | |||
26 | EXPORT_SYMBOL(__ioremap); | ||
27 | EXPORT_SYMBOL(iounmap); | ||
28 | EXPORT_SYMBOL(dump_fpu); | ||
29 | EXPORT_SYMBOL(dump_thread); | ||
30 | EXPORT_SYMBOL(strnlen); | ||
31 | EXPORT_SYMBOL(strrchr); | ||
32 | EXPORT_SYMBOL(strstr); | ||
33 | EXPORT_SYMBOL(strchr); | ||
34 | EXPORT_SYMBOL(strcat); | ||
35 | EXPORT_SYMBOL(strlen); | ||
36 | EXPORT_SYMBOL(strcmp); | ||
37 | EXPORT_SYMBOL(strncmp); | ||
38 | |||
39 | EXPORT_SYMBOL(ip_fast_csum); | ||
40 | |||
41 | EXPORT_SYMBOL(mach_enable_irq); | ||
42 | EXPORT_SYMBOL(mach_disable_irq); | ||
43 | EXPORT_SYMBOL(kernel_thread); | ||
44 | |||
45 | /* Networking helper routines. */ | ||
46 | EXPORT_SYMBOL(csum_partial_copy); | ||
47 | |||
48 | /* The following are special because they're not called | ||
49 | explicitly (the C compiler generates them). Fortunately, | ||
50 | their interface isn't gonna change any time soon now, so | ||
51 | it's OK to leave it out of version control. */ | ||
52 | EXPORT_SYMBOL(memcpy); | ||
53 | EXPORT_SYMBOL(memset); | ||
54 | EXPORT_SYMBOL(memcmp); | ||
55 | EXPORT_SYMBOL(memscan); | ||
56 | EXPORT_SYMBOL(memmove); | ||
57 | |||
58 | EXPORT_SYMBOL(__down_failed); | ||
59 | EXPORT_SYMBOL(__down_failed_interruptible); | ||
60 | EXPORT_SYMBOL(__down_failed_trylock); | ||
61 | EXPORT_SYMBOL(__up_wakeup); | ||
62 | |||
63 | EXPORT_SYMBOL(get_wchan); | ||
64 | |||
65 | /* | ||
66 | * libgcc functions - functions that are used internally by the | ||
67 | * compiler... (prototypes are not correct though, but that | ||
68 | * doesn't really matter since they're not versioned). | ||
69 | */ | ||
70 | extern void __ashldi3(void); | ||
71 | extern void __ashrdi3(void); | ||
72 | extern void __divsi3(void); | ||
73 | extern void __lshrdi3(void); | ||
74 | extern void __modsi3(void); | ||
75 | extern void __muldi3(void); | ||
76 | extern void __mulsi3(void); | ||
77 | extern void __udivsi3(void); | ||
78 | extern void __umodsi3(void); | ||
79 | |||
80 | /* gcc lib functions */ | ||
81 | EXPORT_SYMBOL(__ashldi3); | ||
82 | EXPORT_SYMBOL(__ashrdi3); | ||
83 | EXPORT_SYMBOL(__divsi3); | ||
84 | EXPORT_SYMBOL(__lshrdi3); | ||
85 | EXPORT_SYMBOL(__modsi3); | ||
86 | EXPORT_SYMBOL(__muldi3); | ||
87 | EXPORT_SYMBOL(__mulsi3); | ||
88 | EXPORT_SYMBOL(__udivsi3); | ||
89 | EXPORT_SYMBOL(__umodsi3); | ||
90 | |||
91 | EXPORT_SYMBOL(is_in_rom); | ||
92 | |||
93 | #ifdef CONFIG_COLDFIRE | ||
94 | extern unsigned int *dma_device_address; | ||
95 | extern unsigned long dma_base_addr, _ramend; | ||
96 | EXPORT_SYMBOL(dma_base_addr); | ||
97 | EXPORT_SYMBOL(dma_device_address); | ||
98 | EXPORT_SYMBOL(_ramend); | ||
99 | |||
100 | extern asmlinkage void trap(void); | ||
101 | extern void *_ramvec; | ||
102 | EXPORT_SYMBOL(trap); | ||
103 | EXPORT_SYMBOL(_ramvec); | ||
104 | #endif /* CONFIG_COLDFIRE */ | ||
diff --git a/arch/m68knommu/kernel/module.c b/arch/m68knommu/kernel/module.c new file mode 100644 index 000000000000..3b1a2ff61ddc --- /dev/null +++ b/arch/m68knommu/kernel/module.c | |||
@@ -0,0 +1,128 @@ | |||
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 | |||
14 | void *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 */ | ||
23 | void module_free(struct module *mod, void *module_region) | ||
24 | { | ||
25 | vfree(module_region); | ||
26 | /* FIXME: If module_region == mod->init_region, trim exception | ||
27 | table entries. */ | ||
28 | } | ||
29 | |||
30 | /* We don't need anything special. */ | ||
31 | int module_frob_arch_sections(Elf_Ehdr *hdr, | ||
32 | Elf_Shdr *sechdrs, | ||
33 | char *secstrings, | ||
34 | struct module *mod) | ||
35 | { | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | int apply_relocate(Elf32_Shdr *sechdrs, | ||
40 | const char *strtab, | ||
41 | unsigned int symindex, | ||
42 | unsigned int relsec, | ||
43 | struct module *me) | ||
44 | { | ||
45 | unsigned int i; | ||
46 | Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; | ||
47 | Elf32_Sym *sym; | ||
48 | uint32_t *location; | ||
49 | |||
50 | DEBUGP("Applying relocate section %u to %u\n", relsec, | ||
51 | sechdrs[relsec].sh_info); | ||
52 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
53 | /* This is where to make the change */ | ||
54 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
55 | + rel[i].r_offset; | ||
56 | /* This is the symbol it is referring to. Note that all | ||
57 | undefined symbols have been resolved. */ | ||
58 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
59 | + ELF32_R_SYM(rel[i].r_info); | ||
60 | |||
61 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
62 | case R_68K_32: | ||
63 | /* We add the value into the location given */ | ||
64 | *location += sym->st_value; | ||
65 | break; | ||
66 | case R_68K_PC32: | ||
67 | /* Add the value, subtract its postition */ | ||
68 | *location += sym->st_value - (uint32_t)location; | ||
69 | break; | ||
70 | default: | ||
71 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | ||
72 | me->name, ELF32_R_TYPE(rel[i].r_info)); | ||
73 | return -ENOEXEC; | ||
74 | } | ||
75 | } | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | int apply_relocate_add(Elf32_Shdr *sechdrs, | ||
80 | const char *strtab, | ||
81 | unsigned int symindex, | ||
82 | unsigned int relsec, | ||
83 | struct module *me) | ||
84 | { | ||
85 | unsigned int i; | ||
86 | Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr; | ||
87 | Elf32_Sym *sym; | ||
88 | uint32_t *location; | ||
89 | |||
90 | DEBUGP("Applying relocate_add section %u to %u\n", relsec, | ||
91 | sechdrs[relsec].sh_info); | ||
92 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
93 | /* This is where to make the change */ | ||
94 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
95 | + rel[i].r_offset; | ||
96 | /* This is the symbol it is referring to. Note that all | ||
97 | undefined symbols have been resolved. */ | ||
98 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
99 | + ELF32_R_SYM(rel[i].r_info); | ||
100 | |||
101 | switch (ELF32_R_TYPE(rel[i].r_info)) { | ||
102 | case R_68K_32: | ||
103 | /* We add the value into the location given */ | ||
104 | *location = rel[i].r_addend + sym->st_value; | ||
105 | break; | ||
106 | case R_68K_PC32: | ||
107 | /* Add the value, subtract its postition */ | ||
108 | *location = rel[i].r_addend + sym->st_value - (uint32_t)location; | ||
109 | break; | ||
110 | default: | ||
111 | printk(KERN_ERR "module %s: Unknown relocation: %u\n", | ||
112 | me->name, ELF32_R_TYPE(rel[i].r_info)); | ||
113 | return -ENOEXEC; | ||
114 | } | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | int module_finalize(const Elf_Ehdr *hdr, | ||
120 | const Elf_Shdr *sechdrs, | ||
121 | struct module *me) | ||
122 | { | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | void module_arch_cleanup(struct module *mod) | ||
127 | { | ||
128 | } | ||
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c new file mode 100644 index 000000000000..2b6c9d32b7a6 --- /dev/null +++ b/arch/m68knommu/kernel/process.c | |||
@@ -0,0 +1,442 @@ | |||
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/config.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/mm.h> | ||
22 | #include <linux/smp.h> | ||
23 | #include <linux/smp_lock.h> | ||
24 | #include <linux/stddef.h> | ||
25 | #include <linux/unistd.h> | ||
26 | #include <linux/ptrace.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/user.h> | ||
29 | #include <linux/a.out.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/reboot.h> | ||
32 | |||
33 | #include <asm/uaccess.h> | ||
34 | #include <asm/system.h> | ||
35 | #include <asm/traps.h> | ||
36 | #include <asm/machdep.h> | ||
37 | #include <asm/setup.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | |||
40 | asmlinkage void ret_from_fork(void); | ||
41 | |||
42 | |||
43 | /* | ||
44 | * The idle loop on an m68knommu.. | ||
45 | */ | ||
46 | void default_idle(void) | ||
47 | { | ||
48 | while(1) { | ||
49 | if (need_resched()) | ||
50 | __asm__("stop #0x2000" : : : "cc"); | ||
51 | schedule(); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | void (*idle)(void) = default_idle; | ||
56 | |||
57 | /* | ||
58 | * The idle thread. There's no useful work to be | ||
59 | * done, so just try to conserve power and have a | ||
60 | * low exit latency (ie sit in a loop waiting for | ||
61 | * somebody to say that they'd like to reschedule) | ||
62 | */ | ||
63 | void cpu_idle(void) | ||
64 | { | ||
65 | /* endless idle loop with no priority at all */ | ||
66 | idle(); | ||
67 | } | ||
68 | |||
69 | void machine_restart(char * __unused) | ||
70 | { | ||
71 | if (mach_reset) | ||
72 | mach_reset(); | ||
73 | for (;;); | ||
74 | } | ||
75 | |||
76 | EXPORT_SYMBOL(machine_restart); | ||
77 | |||
78 | void machine_halt(void) | ||
79 | { | ||
80 | if (mach_halt) | ||
81 | mach_halt(); | ||
82 | for (;;); | ||
83 | } | ||
84 | |||
85 | EXPORT_SYMBOL(machine_halt); | ||
86 | |||
87 | void machine_power_off(void) | ||
88 | { | ||
89 | if (mach_power_off) | ||
90 | mach_power_off(); | ||
91 | for (;;); | ||
92 | } | ||
93 | |||
94 | EXPORT_SYMBOL(machine_power_off); | ||
95 | |||
96 | void show_regs(struct pt_regs * regs) | ||
97 | { | ||
98 | printk(KERN_NOTICE "\n"); | ||
99 | printk(KERN_NOTICE "Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", | ||
100 | regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); | ||
101 | printk(KERN_NOTICE "ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", | ||
102 | regs->orig_d0, regs->d0, regs->a2, regs->a1); | ||
103 | printk(KERN_NOTICE "A0: %08lx D5: %08lx D4: %08lx\n", | ||
104 | regs->a0, regs->d5, regs->d4); | ||
105 | printk(KERN_NOTICE "D3: %08lx D2: %08lx D1: %08lx\n", | ||
106 | regs->d3, regs->d2, regs->d1); | ||
107 | if (!(regs->sr & PS_S)) | ||
108 | printk(KERN_NOTICE "USP: %08lx\n", rdusp()); | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Create a kernel thread | ||
113 | */ | ||
114 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
115 | { | ||
116 | int retval; | ||
117 | long clone_arg = flags | CLONE_VM; | ||
118 | mm_segment_t fs; | ||
119 | |||
120 | fs = get_fs(); | ||
121 | set_fs(KERNEL_DS); | ||
122 | |||
123 | __asm__ __volatile__ ( | ||
124 | "movel %%sp, %%d2\n\t" | ||
125 | "movel %5, %%d1\n\t" | ||
126 | "movel %1, %%d0\n\t" | ||
127 | "trap #0\n\t" | ||
128 | "cmpl %%sp, %%d2\n\t" | ||
129 | "jeq 1f\n\t" | ||
130 | "movel %3, %%sp@-\n\t" | ||
131 | "jsr %4@\n\t" | ||
132 | "movel %2, %%d0\n\t" | ||
133 | "trap #0\n" | ||
134 | "1:\n\t" | ||
135 | "movel %%d0, %0\n" | ||
136 | : "=d" (retval) | ||
137 | : "i" (__NR_clone), | ||
138 | "i" (__NR_exit), | ||
139 | "a" (arg), | ||
140 | "a" (fn), | ||
141 | "a" (clone_arg) | ||
142 | : "cc", "%d0", "%d1", "%d2"); | ||
143 | |||
144 | set_fs(fs); | ||
145 | return retval; | ||
146 | } | ||
147 | |||
148 | void flush_thread(void) | ||
149 | { | ||
150 | #ifdef CONFIG_FPU | ||
151 | unsigned long zero = 0; | ||
152 | #endif | ||
153 | set_fs(USER_DS); | ||
154 | current->thread.fs = __USER_DS; | ||
155 | #ifdef CONFIG_FPU | ||
156 | if (!FPU_IS_EMU) | ||
157 | asm volatile (".chip 68k/68881\n\t" | ||
158 | "frestore %0@\n\t" | ||
159 | ".chip 68k" : : "a" (&zero)); | ||
160 | #endif | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * "m68k_fork()".. By the time we get here, the | ||
165 | * non-volatile registers have also been saved on the | ||
166 | * stack. We do some ugly pointer stuff here.. (see | ||
167 | * also copy_thread) | ||
168 | */ | ||
169 | |||
170 | asmlinkage int m68k_fork(struct pt_regs *regs) | ||
171 | { | ||
172 | /* fork almost works, enough to trick you into looking elsewhere :-( */ | ||
173 | return(-EINVAL); | ||
174 | } | ||
175 | |||
176 | asmlinkage int m68k_vfork(struct pt_regs *regs) | ||
177 | { | ||
178 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
179 | } | ||
180 | |||
181 | asmlinkage int m68k_clone(struct pt_regs *regs) | ||
182 | { | ||
183 | unsigned long clone_flags; | ||
184 | unsigned long newsp; | ||
185 | |||
186 | /* syscall2 puts clone_flags in d1 and usp in d2 */ | ||
187 | clone_flags = regs->d1; | ||
188 | newsp = regs->d2; | ||
189 | if (!newsp) | ||
190 | newsp = rdusp(); | ||
191 | return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); | ||
192 | } | ||
193 | |||
194 | int copy_thread(int nr, unsigned long clone_flags, | ||
195 | unsigned long usp, unsigned long topstk, | ||
196 | struct task_struct * p, struct pt_regs * regs) | ||
197 | { | ||
198 | struct pt_regs * childregs; | ||
199 | struct switch_stack * childstack, *stack; | ||
200 | unsigned long stack_offset, *retp; | ||
201 | |||
202 | stack_offset = THREAD_SIZE - sizeof(struct pt_regs); | ||
203 | childregs = (struct pt_regs *) ((unsigned long) p->thread_info + stack_offset); | ||
204 | |||
205 | *childregs = *regs; | ||
206 | childregs->d0 = 0; | ||
207 | |||
208 | retp = ((unsigned long *) regs); | ||
209 | stack = ((struct switch_stack *) retp) - 1; | ||
210 | |||
211 | childstack = ((struct switch_stack *) childregs) - 1; | ||
212 | *childstack = *stack; | ||
213 | childstack->retpc = (unsigned long)ret_from_fork; | ||
214 | |||
215 | p->thread.usp = usp; | ||
216 | p->thread.ksp = (unsigned long)childstack; | ||
217 | /* | ||
218 | * Must save the current SFC/DFC value, NOT the value when | ||
219 | * the parent was last descheduled - RGH 10-08-96 | ||
220 | */ | ||
221 | p->thread.fs = get_fs().seg; | ||
222 | |||
223 | #ifdef CONFIG_FPU | ||
224 | if (!FPU_IS_EMU) { | ||
225 | /* Copy the current fpu state */ | ||
226 | asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); | ||
227 | |||
228 | if (p->thread.fpstate[0]) | ||
229 | asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" | ||
230 | "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" | ||
231 | : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) | ||
232 | : "memory"); | ||
233 | /* Restore the state in case the fpu was busy */ | ||
234 | asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); | ||
235 | } | ||
236 | #endif | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | /* Fill in the fpu structure for a core dump. */ | ||
242 | |||
243 | int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu) | ||
244 | { | ||
245 | #ifdef CONFIG_FPU | ||
246 | char fpustate[216]; | ||
247 | |||
248 | if (FPU_IS_EMU) { | ||
249 | int i; | ||
250 | |||
251 | memcpy(fpu->fpcntl, current->thread.fpcntl, 12); | ||
252 | memcpy(fpu->fpregs, current->thread.fp, 96); | ||
253 | /* Convert internal fpu reg representation | ||
254 | * into long double format | ||
255 | */ | ||
256 | for (i = 0; i < 24; i += 3) | ||
257 | fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | | ||
258 | ((fpu->fpregs[i] & 0x0000ffff) << 16); | ||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | /* First dump the fpu context to avoid protocol violation. */ | ||
263 | asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); | ||
264 | if (!fpustate[0]) | ||
265 | return 0; | ||
266 | |||
267 | asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" | ||
268 | :: "m" (fpu->fpcntl[0]) | ||
269 | : "memory"); | ||
270 | asm volatile ("fmovemx %/fp0-%/fp7,%0" | ||
271 | :: "m" (fpu->fpregs[0]) | ||
272 | : "memory"); | ||
273 | #endif | ||
274 | return 1; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * fill in the user structure for a core dump.. | ||
279 | */ | ||
280 | void dump_thread(struct pt_regs * regs, struct user * dump) | ||
281 | { | ||
282 | struct switch_stack *sw; | ||
283 | |||
284 | /* changed the size calculations - should hopefully work better. lbt */ | ||
285 | dump->magic = CMAGIC; | ||
286 | dump->start_code = 0; | ||
287 | dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); | ||
288 | dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; | ||
289 | dump->u_dsize = ((unsigned long) (current->mm->brk + | ||
290 | (PAGE_SIZE-1))) >> PAGE_SHIFT; | ||
291 | dump->u_dsize -= dump->u_tsize; | ||
292 | dump->u_ssize = 0; | ||
293 | |||
294 | if (dump->start_stack < TASK_SIZE) | ||
295 | dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; | ||
296 | |||
297 | dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); | ||
298 | sw = ((struct switch_stack *)regs) - 1; | ||
299 | dump->regs.d1 = regs->d1; | ||
300 | dump->regs.d2 = regs->d2; | ||
301 | dump->regs.d3 = regs->d3; | ||
302 | dump->regs.d4 = regs->d4; | ||
303 | dump->regs.d5 = regs->d5; | ||
304 | dump->regs.d6 = sw->d6; | ||
305 | dump->regs.d7 = sw->d7; | ||
306 | dump->regs.a0 = regs->a0; | ||
307 | dump->regs.a1 = regs->a1; | ||
308 | dump->regs.a2 = regs->a2; | ||
309 | dump->regs.a3 = sw->a3; | ||
310 | dump->regs.a4 = sw->a4; | ||
311 | dump->regs.a5 = sw->a5; | ||
312 | dump->regs.a6 = sw->a6; | ||
313 | dump->regs.d0 = regs->d0; | ||
314 | dump->regs.orig_d0 = regs->orig_d0; | ||
315 | dump->regs.stkadj = regs->stkadj; | ||
316 | dump->regs.sr = regs->sr; | ||
317 | dump->regs.pc = regs->pc; | ||
318 | dump->regs.fmtvec = (regs->format << 12) | regs->vector; | ||
319 | /* dump floating point stuff */ | ||
320 | dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp); | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * Generic dumping code. Used for panic and debug. | ||
325 | */ | ||
326 | void dump(struct pt_regs *fp) | ||
327 | { | ||
328 | unsigned long *sp; | ||
329 | unsigned char *tp; | ||
330 | int i; | ||
331 | |||
332 | printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); | ||
333 | printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); | ||
334 | |||
335 | if (current->mm) { | ||
336 | printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", | ||
337 | (int) current->mm->start_code, | ||
338 | (int) current->mm->end_code, | ||
339 | (int) current->mm->start_data, | ||
340 | (int) current->mm->end_data, | ||
341 | (int) current->mm->end_data, | ||
342 | (int) current->mm->brk); | ||
343 | printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", | ||
344 | (int) current->mm->start_stack, | ||
345 | (int)(((unsigned long) current) + THREAD_SIZE)); | ||
346 | } | ||
347 | |||
348 | printk(KERN_EMERG "PC: %08lx\n", fp->pc); | ||
349 | printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp); | ||
350 | printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | ||
351 | fp->d0, fp->d1, fp->d2, fp->d3); | ||
352 | printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | ||
353 | fp->d4, fp->d5, fp->a0, fp->a1); | ||
354 | printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %08x\n", (unsigned int) rdusp(), | ||
355 | (unsigned int) fp); | ||
356 | |||
357 | printk(KERN_EMERG "\nCODE:"); | ||
358 | tp = ((unsigned char *) fp->pc) - 0x20; | ||
359 | for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { | ||
360 | if ((i % 0x10) == 0) | ||
361 | printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); | ||
362 | printk(KERN_EMERG "%08x ", (int) *sp++); | ||
363 | } | ||
364 | printk(KERN_EMERG "\n"); | ||
365 | |||
366 | printk(KERN_EMERG "\nKERNEL STACK:"); | ||
367 | tp = ((unsigned char *) fp) - 0x40; | ||
368 | for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { | ||
369 | if ((i % 0x10) == 0) | ||
370 | printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); | ||
371 | printk(KERN_EMERG "%08x ", (int) *sp++); | ||
372 | } | ||
373 | printk(KERN_EMERG "\n"); | ||
374 | printk(KERN_EMERG "\n"); | ||
375 | |||
376 | printk(KERN_EMERG "\nUSER STACK:"); | ||
377 | tp = (unsigned char *) (rdusp() - 0x10); | ||
378 | for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { | ||
379 | if ((i % 0x10) == 0) | ||
380 | printk(KERN_EMERG "\n%08x: ", (int) (tp + i)); | ||
381 | printk(KERN_EMERG "%08x ", (int) *sp++); | ||
382 | } | ||
383 | printk(KERN_EMERG "\n\n"); | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * sys_execve() executes a new program. | ||
388 | */ | ||
389 | asmlinkage int sys_execve(char *name, char **argv, char **envp) | ||
390 | { | ||
391 | int error; | ||
392 | char * filename; | ||
393 | struct pt_regs *regs = (struct pt_regs *) &name; | ||
394 | |||
395 | lock_kernel(); | ||
396 | filename = getname(name); | ||
397 | error = PTR_ERR(filename); | ||
398 | if (IS_ERR(filename)) | ||
399 | goto out; | ||
400 | error = do_execve(filename, argv, envp, regs); | ||
401 | putname(filename); | ||
402 | out: | ||
403 | unlock_kernel(); | ||
404 | return error; | ||
405 | } | ||
406 | |||
407 | unsigned long get_wchan(struct task_struct *p) | ||
408 | { | ||
409 | unsigned long fp, pc; | ||
410 | unsigned long stack_page; | ||
411 | int count = 0; | ||
412 | if (!p || p == current || p->state == TASK_RUNNING) | ||
413 | return 0; | ||
414 | |||
415 | stack_page = (unsigned long)p; | ||
416 | fp = ((struct switch_stack *)p->thread.ksp)->a6; | ||
417 | do { | ||
418 | if (fp < stack_page+sizeof(struct thread_info) || | ||
419 | fp >= 8184+stack_page) | ||
420 | return 0; | ||
421 | pc = ((unsigned long *)fp)[1]; | ||
422 | if (!in_sched_functions(pc)) | ||
423 | return pc; | ||
424 | fp = *(unsigned long *) fp; | ||
425 | } while (count++ < 16); | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * Return saved PC of a blocked thread. | ||
431 | */ | ||
432 | unsigned long thread_saved_pc(struct task_struct *tsk) | ||
433 | { | ||
434 | struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; | ||
435 | |||
436 | /* Check whether the thread is blocked in resume() */ | ||
437 | if (in_sched_functions(sw->retpc)) | ||
438 | return ((unsigned long *)sw->a6)[1]; | ||
439 | else | ||
440 | return sw->retpc; | ||
441 | } | ||
442 | |||
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c new file mode 100644 index 000000000000..15cf79080b15 --- /dev/null +++ b/arch/m68knommu/kernel/ptrace.c | |||
@@ -0,0 +1,383 @@ | |||
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/smp_lock.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/user.h> | ||
21 | #include <linux/config.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). */ | ||
48 | static 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 | */ | ||
59 | static 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 < sizeof(regoff)/sizeof(regoff[0])) | ||
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 | */ | ||
75 | static 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 < sizeof(regoff)/sizeof(regoff[0])) | ||
83 | addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); | ||
84 | else | ||
85 | return -1; | ||
86 | *addr = data; | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Called by kernel/ptrace.c when detaching.. | ||
92 | * | ||
93 | * Make sure the single step bit is not set. | ||
94 | */ | ||
95 | void ptrace_disable(struct task_struct *child) | ||
96 | { | ||
97 | unsigned long tmp; | ||
98 | /* make sure the single step bit is not set. */ | ||
99 | tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); | ||
100 | put_reg(child, PT_SR, tmp); | ||
101 | } | ||
102 | |||
103 | asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | ||
104 | { | ||
105 | struct task_struct *child; | ||
106 | int ret; | ||
107 | |||
108 | lock_kernel(); | ||
109 | ret = -EPERM; | ||
110 | if (request == PTRACE_TRACEME) { | ||
111 | /* are we already being traced? */ | ||
112 | if (current->ptrace & PT_PTRACED) | ||
113 | goto out; | ||
114 | /* set the ptrace bit in the process flags. */ | ||
115 | current->ptrace |= PT_PTRACED; | ||
116 | ret = 0; | ||
117 | goto out; | ||
118 | } | ||
119 | ret = -ESRCH; | ||
120 | read_lock(&tasklist_lock); | ||
121 | child = find_task_by_pid(pid); | ||
122 | if (child) | ||
123 | get_task_struct(child); | ||
124 | read_unlock(&tasklist_lock); | ||
125 | if (!child) | ||
126 | goto out; | ||
127 | |||
128 | ret = -EPERM; | ||
129 | if (pid == 1) /* you may not mess with init */ | ||
130 | goto out_tsk; | ||
131 | |||
132 | if (request == PTRACE_ATTACH) { | ||
133 | ret = ptrace_attach(child); | ||
134 | goto out_tsk; | ||
135 | } | ||
136 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | ||
137 | if (ret < 0) | ||
138 | goto out_tsk; | ||
139 | |||
140 | switch (request) { | ||
141 | /* when I and D space are separate, these will need to be fixed. */ | ||
142 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | ||
143 | case PTRACE_PEEKDATA: { | ||
144 | unsigned long tmp; | ||
145 | int copied; | ||
146 | |||
147 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | ||
148 | ret = -EIO; | ||
149 | if (copied != sizeof(tmp)) | ||
150 | break; | ||
151 | ret = put_user(tmp,(unsigned long *) data); | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | /* read the word at location addr in the USER area. */ | ||
156 | case PTRACE_PEEKUSR: { | ||
157 | unsigned long tmp; | ||
158 | |||
159 | ret = -EIO; | ||
160 | if ((addr & 3) || addr < 0 || | ||
161 | addr > sizeof(struct user) - 3) | ||
162 | break; | ||
163 | |||
164 | tmp = 0; /* Default return condition */ | ||
165 | addr = addr >> 2; /* temporary hack. */ | ||
166 | ret = -EIO; | ||
167 | if (addr < 19) { | ||
168 | tmp = get_reg(child, addr); | ||
169 | if (addr == PT_SR) | ||
170 | tmp >>= 16; | ||
171 | } else if (addr >= 21 && addr < 49) { | ||
172 | tmp = child->thread.fp[addr - 21]; | ||
173 | #ifdef CONFIG_M68KFPU_EMU | ||
174 | /* Convert internal fpu reg representation | ||
175 | * into long double format | ||
176 | */ | ||
177 | if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) | ||
178 | tmp = ((tmp & 0xffff0000) << 15) | | ||
179 | ((tmp & 0x0000ffff) << 16); | ||
180 | #endif | ||
181 | } else if (addr == 49) { | ||
182 | tmp = child->mm->start_code; | ||
183 | } else if (addr == 50) { | ||
184 | tmp = child->mm->start_data; | ||
185 | } else if (addr == 51) { | ||
186 | tmp = child->mm->end_code; | ||
187 | } else | ||
188 | break; | ||
189 | ret = put_user(tmp,(unsigned long *) data); | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | /* when I and D space are separate, this will have to be fixed. */ | ||
194 | case PTRACE_POKETEXT: /* write the word at location addr. */ | ||
195 | case PTRACE_POKEDATA: | ||
196 | ret = 0; | ||
197 | if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) | ||
198 | break; | ||
199 | ret = -EIO; | ||
200 | break; | ||
201 | |||
202 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | ||
203 | ret = -EIO; | ||
204 | if ((addr & 3) || addr < 0 || | ||
205 | addr > sizeof(struct user) - 3) | ||
206 | break; | ||
207 | |||
208 | addr = addr >> 2; /* temporary hack. */ | ||
209 | |||
210 | if (addr == PT_SR) { | ||
211 | data &= SR_MASK; | ||
212 | data <<= 16; | ||
213 | data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); | ||
214 | } | ||
215 | if (addr < 19) { | ||
216 | if (put_reg(child, addr, data)) | ||
217 | break; | ||
218 | ret = 0; | ||
219 | break; | ||
220 | } | ||
221 | if (addr >= 21 && addr < 48) | ||
222 | { | ||
223 | #ifdef CONFIG_M68KFPU_EMU | ||
224 | /* Convert long double format | ||
225 | * into internal fpu reg representation | ||
226 | */ | ||
227 | if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { | ||
228 | data = (unsigned long)data << 15; | ||
229 | data = (data & 0xffff0000) | | ||
230 | ((data & 0x0000ffff) >> 1); | ||
231 | } | ||
232 | #endif | ||
233 | child->thread.fp[addr - 21] = data; | ||
234 | ret = 0; | ||
235 | } | ||
236 | break; | ||
237 | |||
238 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | ||
239 | case PTRACE_CONT: { /* restart after signal. */ | ||
240 | long tmp; | ||
241 | |||
242 | ret = -EIO; | ||
243 | if ((unsigned long) data > _NSIG) | ||
244 | break; | ||
245 | if (request == PTRACE_SYSCALL) | ||
246 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
247 | else | ||
248 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
249 | child->exit_code = data; | ||
250 | /* make sure the single step bit is not set. */ | ||
251 | tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); | ||
252 | put_reg(child, PT_SR, tmp); | ||
253 | wake_up_process(child); | ||
254 | ret = 0; | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * make the child exit. Best I can do is send it a sigkill. | ||
260 | * perhaps it should be put in the status that it wants to | ||
261 | * exit. | ||
262 | */ | ||
263 | case PTRACE_KILL: { | ||
264 | long tmp; | ||
265 | |||
266 | ret = 0; | ||
267 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
268 | break; | ||
269 | child->exit_code = SIGKILL; | ||
270 | /* make sure the single step bit is not set. */ | ||
271 | tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); | ||
272 | put_reg(child, PT_SR, tmp); | ||
273 | wake_up_process(child); | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | case PTRACE_SINGLESTEP: { /* set the trap flag. */ | ||
278 | long tmp; | ||
279 | |||
280 | ret = -EIO; | ||
281 | if ((unsigned long) data > _NSIG) | ||
282 | break; | ||
283 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
284 | tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); | ||
285 | put_reg(child, PT_SR, tmp); | ||
286 | |||
287 | child->exit_code = data; | ||
288 | /* give it a chance to run. */ | ||
289 | wake_up_process(child); | ||
290 | ret = 0; | ||
291 | break; | ||
292 | } | ||
293 | |||
294 | case PTRACE_DETACH: /* detach a process that was attached. */ | ||
295 | ret = ptrace_detach(child, data); | ||
296 | break; | ||
297 | |||
298 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ | ||
299 | int i; | ||
300 | unsigned long tmp; | ||
301 | for (i = 0; i < 19; i++) { | ||
302 | tmp = get_reg(child, i); | ||
303 | if (i == PT_SR) | ||
304 | tmp >>= 16; | ||
305 | if (put_user(tmp, (unsigned long *) data)) { | ||
306 | ret = -EFAULT; | ||
307 | break; | ||
308 | } | ||
309 | data += sizeof(long); | ||
310 | } | ||
311 | ret = 0; | ||
312 | break; | ||
313 | } | ||
314 | |||
315 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ | ||
316 | int i; | ||
317 | unsigned long tmp; | ||
318 | for (i = 0; i < 19; i++) { | ||
319 | if (get_user(tmp, (unsigned long *) data)) { | ||
320 | ret = -EFAULT; | ||
321 | break; | ||
322 | } | ||
323 | if (i == PT_SR) { | ||
324 | tmp &= SR_MASK; | ||
325 | tmp <<= 16; | ||
326 | tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); | ||
327 | } | ||
328 | put_reg(child, i, tmp); | ||
329 | data += sizeof(long); | ||
330 | } | ||
331 | ret = 0; | ||
332 | break; | ||
333 | } | ||
334 | |||
335 | #ifdef PTRACE_GETFPREGS | ||
336 | case PTRACE_GETFPREGS: { /* Get the child FPU state. */ | ||
337 | ret = 0; | ||
338 | if (copy_to_user((void *)data, &child->thread.fp, | ||
339 | sizeof(struct user_m68kfp_struct))) | ||
340 | ret = -EFAULT; | ||
341 | break; | ||
342 | } | ||
343 | #endif | ||
344 | |||
345 | #ifdef PTRACE_SETFPREGS | ||
346 | case PTRACE_SETFPREGS: { /* Set the child FPU state. */ | ||
347 | ret = 0; | ||
348 | if (copy_from_user(&child->thread.fp, (void *)data, | ||
349 | sizeof(struct user_m68kfp_struct))) | ||
350 | ret = -EFAULT; | ||
351 | break; | ||
352 | } | ||
353 | #endif | ||
354 | |||
355 | default: | ||
356 | ret = -EIO; | ||
357 | break; | ||
358 | } | ||
359 | out_tsk: | ||
360 | put_task_struct(child); | ||
361 | out: | ||
362 | unlock_kernel(); | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | asmlinkage void syscall_trace(void) | ||
367 | { | ||
368 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
369 | return; | ||
370 | if (!(current->ptrace & PT_PTRACED)) | ||
371 | return; | ||
372 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
373 | ? 0x80 : 0)); | ||
374 | /* | ||
375 | * this isn't the same as continuing with a signal, but it will do | ||
376 | * for normal use. strace only continues with a signal if the | ||
377 | * stopping signal is not SIGTRAP. -brl | ||
378 | */ | ||
379 | if (current->exit_code) { | ||
380 | send_sig(current->exit_code, current, 1); | ||
381 | current->exit_code = 0; | ||
382 | } | ||
383 | } | ||
diff --git a/arch/m68knommu/kernel/semaphore.c b/arch/m68knommu/kernel/semaphore.c new file mode 100644 index 000000000000..c083f4772add --- /dev/null +++ b/arch/m68knommu/kernel/semaphore.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * Generic semaphore code. Buyer beware. Do your own | ||
3 | * specific changes in <asm/semaphore-helper.h> | ||
4 | */ | ||
5 | |||
6 | #include <linux/config.h> | ||
7 | #include <linux/sched.h> | ||
8 | #include <linux/err.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <asm/semaphore-helper.h> | ||
11 | |||
12 | #ifndef CONFIG_RMW_INSNS | ||
13 | spinlock_t semaphore_wake_lock; | ||
14 | #endif | ||
15 | |||
16 | /* | ||
17 | * Semaphores are implemented using a two-way counter: | ||
18 | * The "count" variable is decremented for each process | ||
19 | * that tries to sleep, while the "waking" variable is | ||
20 | * incremented when the "up()" code goes to wake up waiting | ||
21 | * processes. | ||
22 | * | ||
23 | * Notably, the inline "up()" and "down()" functions can | ||
24 | * efficiently test if they need to do any extra work (up | ||
25 | * needs to do something only if count was negative before | ||
26 | * the increment operation. | ||
27 | * | ||
28 | * waking_non_zero() (from asm/semaphore.h) must execute | ||
29 | * atomically. | ||
30 | * | ||
31 | * When __up() is called, the count was negative before | ||
32 | * incrementing it, and we need to wake up somebody. | ||
33 | * | ||
34 | * This routine adds one to the count of processes that need to | ||
35 | * wake up and exit. ALL waiting processes actually wake up but | ||
36 | * only the one that gets to the "waking" field first will gate | ||
37 | * through and acquire the semaphore. The others will go back | ||
38 | * to sleep. | ||
39 | * | ||
40 | * Note that these functions are only called when there is | ||
41 | * contention on the lock, and as such all this is the | ||
42 | * "non-critical" part of the whole semaphore business. The | ||
43 | * critical part is the inline stuff in <asm/semaphore.h> | ||
44 | * where we want to avoid any extra jumps and calls. | ||
45 | */ | ||
46 | void __up(struct semaphore *sem) | ||
47 | { | ||
48 | wake_one_more(sem); | ||
49 | wake_up(&sem->wait); | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * Perform the "down" function. Return zero for semaphore acquired, | ||
54 | * return negative for signalled out of the function. | ||
55 | * | ||
56 | * If called from __down, the return is ignored and the wait loop is | ||
57 | * not interruptible. This means that a task waiting on a semaphore | ||
58 | * using "down()" cannot be killed until someone does an "up()" on | ||
59 | * the semaphore. | ||
60 | * | ||
61 | * If called from __down_interruptible, the return value gets checked | ||
62 | * upon return. If the return value is negative then the task continues | ||
63 | * with the negative value in the return register (it can be tested by | ||
64 | * the caller). | ||
65 | * | ||
66 | * Either form may be used in conjunction with "up()". | ||
67 | * | ||
68 | */ | ||
69 | |||
70 | |||
71 | #define DOWN_HEAD(task_state) \ | ||
72 | \ | ||
73 | \ | ||
74 | current->state = (task_state); \ | ||
75 | add_wait_queue(&sem->wait, &wait); \ | ||
76 | \ | ||
77 | /* \ | ||
78 | * Ok, we're set up. sem->count is known to be less than zero \ | ||
79 | * so we must wait. \ | ||
80 | * \ | ||
81 | * We can let go the lock for purposes of waiting. \ | ||
82 | * We re-acquire it after awaking so as to protect \ | ||
83 | * all semaphore operations. \ | ||
84 | * \ | ||
85 | * If "up()" is called before we call waking_non_zero() then \ | ||
86 | * we will catch it right away. If it is called later then \ | ||
87 | * we will have to go through a wakeup cycle to catch it. \ | ||
88 | * \ | ||
89 | * Multiple waiters contend for the semaphore lock to see \ | ||
90 | * who gets to gate through and who has to wait some more. \ | ||
91 | */ \ | ||
92 | for (;;) { | ||
93 | |||
94 | #define DOWN_TAIL(task_state) \ | ||
95 | current->state = (task_state); \ | ||
96 | } \ | ||
97 | current->state = TASK_RUNNING; \ | ||
98 | remove_wait_queue(&sem->wait, &wait); | ||
99 | |||
100 | void __sched __down(struct semaphore * sem) | ||
101 | { | ||
102 | DECLARE_WAITQUEUE(wait, current); | ||
103 | |||
104 | DOWN_HEAD(TASK_UNINTERRUPTIBLE) | ||
105 | if (waking_non_zero(sem)) | ||
106 | break; | ||
107 | schedule(); | ||
108 | DOWN_TAIL(TASK_UNINTERRUPTIBLE) | ||
109 | } | ||
110 | |||
111 | int __sched __down_interruptible(struct semaphore * sem) | ||
112 | { | ||
113 | DECLARE_WAITQUEUE(wait, current); | ||
114 | int ret = 0; | ||
115 | |||
116 | DOWN_HEAD(TASK_INTERRUPTIBLE) | ||
117 | |||
118 | ret = waking_non_zero_interruptible(sem, current); | ||
119 | if (ret) | ||
120 | { | ||
121 | if (ret == 1) | ||
122 | /* ret != 0 only if we get interrupted -arca */ | ||
123 | ret = 0; | ||
124 | break; | ||
125 | } | ||
126 | schedule(); | ||
127 | DOWN_TAIL(TASK_INTERRUPTIBLE) | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | int __down_trylock(struct semaphore * sem) | ||
132 | { | ||
133 | return waking_non_zero_trylock(sem); | ||
134 | } | ||
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c new file mode 100644 index 000000000000..557238596dcb --- /dev/null +++ b/arch/m68knommu/kernel/setup.c | |||
@@ -0,0 +1,347 @@ | |||
1 | /* | ||
2 | * linux/arch/m68knommu/kernel/setup.c | ||
3 | * | ||
4 | * Copyright (C) 1999-2004 Greg Ungerer (gerg@snapgear.com) | ||
5 | * Copyright (C) 1998,1999 D. Jeff Dionne <jeff@lineo.ca> | ||
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/config.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/fb.h> | ||
26 | #include <linux/console.h> | ||
27 | #include <linux/genhd.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/major.h> | ||
31 | #include <linux/bootmem.h> | ||
32 | #include <linux/seq_file.h> | ||
33 | #include <linux/root_dev.h> | ||
34 | #include <linux/init.h> | ||
35 | |||
36 | #include <asm/setup.h> | ||
37 | #include <asm/irq.h> | ||
38 | #include <asm/machdep.h> | ||
39 | |||
40 | #ifdef CONFIG_BLK_DEV_INITRD | ||
41 | #include <asm/pgtable.h> | ||
42 | #endif | ||
43 | |||
44 | unsigned long rom_length; | ||
45 | unsigned long memory_start; | ||
46 | unsigned long memory_end; | ||
47 | |||
48 | char command_line[COMMAND_LINE_SIZE]; | ||
49 | |||
50 | /* setup some dummy routines */ | ||
51 | static void dummy_waitbut(void) | ||
52 | { | ||
53 | } | ||
54 | |||
55 | void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) = NULL; | ||
56 | void (*mach_tick)( void ) = NULL; | ||
57 | /* machine dependent keyboard functions */ | ||
58 | int (*mach_keyb_init) (void) = NULL; | ||
59 | int (*mach_kbdrate) (struct kbd_repeat *) = NULL; | ||
60 | void (*mach_kbd_leds) (unsigned int) = NULL; | ||
61 | /* machine dependent irq functions */ | ||
62 | void (*mach_init_IRQ) (void) = NULL; | ||
63 | irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) = NULL; | ||
64 | void (*mach_enable_irq) (unsigned int) = NULL; | ||
65 | void (*mach_disable_irq) (unsigned int) = NULL; | ||
66 | int (*mach_get_irq_list) (struct seq_file *, void *) = NULL; | ||
67 | void (*mach_process_int) (int irq, struct pt_regs *fp) = NULL; | ||
68 | void (*mach_trap_init) (void); | ||
69 | /* machine dependent timer functions */ | ||
70 | unsigned long (*mach_gettimeoffset) (void) = NULL; | ||
71 | void (*mach_gettod) (int*, int*, int*, int*, int*, int*) = NULL; | ||
72 | int (*mach_hwclk) (int, struct hwclk_time*) = NULL; | ||
73 | int (*mach_set_clock_mmss) (unsigned long) = NULL; | ||
74 | void (*mach_mksound)( unsigned int count, unsigned int ticks ) = NULL; | ||
75 | void (*mach_reset)( void ) = NULL; | ||
76 | void (*waitbut)(void) = dummy_waitbut; | ||
77 | void (*mach_debug_init)(void) = NULL; | ||
78 | void (*mach_halt)( void ) = NULL; | ||
79 | void (*mach_power_off)( void ) = NULL; | ||
80 | |||
81 | |||
82 | #ifdef CONFIG_M68000 | ||
83 | #define CPU "MC68000" | ||
84 | #endif | ||
85 | #ifdef CONFIG_M68328 | ||
86 | #define CPU "MC68328" | ||
87 | #endif | ||
88 | #ifdef CONFIG_M68EZ328 | ||
89 | #define CPU "MC68EZ328" | ||
90 | #endif | ||
91 | #ifdef CONFIG_M68VZ328 | ||
92 | #define CPU "MC68VZ328" | ||
93 | #endif | ||
94 | #ifdef CONFIG_M68332 | ||
95 | #define CPU "MC68332" | ||
96 | #endif | ||
97 | #ifdef CONFIG_M68360 | ||
98 | #define CPU "MC68360" | ||
99 | #endif | ||
100 | #if defined(CONFIG_M5206) | ||
101 | #define CPU "COLDFIRE(m5206)" | ||
102 | #endif | ||
103 | #if defined(CONFIG_M5206e) | ||
104 | #define CPU "COLDFIRE(m5206e)" | ||
105 | #endif | ||
106 | #if defined(CONFIG_M5249) | ||
107 | #define CPU "COLDFIRE(m5249)" | ||
108 | #endif | ||
109 | #if defined(CONFIG_M527x) | ||
110 | #define CPU "COLDFIRE(m5270/5271/5274/5275)" | ||
111 | #endif | ||
112 | #if defined(CONFIG_M5272) | ||
113 | #define CPU "COLDFIRE(m5272)" | ||
114 | #endif | ||
115 | #if defined(CONFIG_M528x) | ||
116 | #define CPU "COLDFIRE(m5280/5282)" | ||
117 | #endif | ||
118 | #if defined(CONFIG_M5307) | ||
119 | #define CPU "COLDFIRE(m5307)" | ||
120 | #endif | ||
121 | #if defined(CONFIG_M5407) | ||
122 | #define CPU "COLDFIRE(m5407)" | ||
123 | #endif | ||
124 | #ifndef CPU | ||
125 | #define CPU "UNKOWN" | ||
126 | #endif | ||
127 | |||
128 | /* (es) */ | ||
129 | /* note: why is this defined here? the must be a better place to put this */ | ||
130 | #if defined( CONFIG_TELOS) || defined( CONFIG_UCDIMM ) || defined( CONFIG_UCSIMM ) || defined(CONFIG_DRAGEN2) || (defined( CONFIG_PILOT ) && defined( CONFIG_M68328 )) | ||
131 | #define CAT_ROMARRAY | ||
132 | #endif | ||
133 | /* (/es) */ | ||
134 | |||
135 | extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end; | ||
136 | extern int _ramstart, _ramend; | ||
137 | |||
138 | void setup_arch(char **cmdline_p) | ||
139 | { | ||
140 | int bootmap_size; | ||
141 | |||
142 | #if defined(CAT_ROMARRAY) && defined(DEBUG) | ||
143 | extern int __data_rom_start; | ||
144 | extern int __data_start; | ||
145 | int *romarray = (int *)((int) &__data_rom_start + | ||
146 | (int)&_edata - (int)&__data_start); | ||
147 | #endif | ||
148 | |||
149 | memory_start = PAGE_ALIGN(_ramstart); | ||
150 | memory_end = _ramend; /* by now the stack is part of the init task */ | ||
151 | |||
152 | init_mm.start_code = (unsigned long) &_stext; | ||
153 | init_mm.end_code = (unsigned long) &_etext; | ||
154 | init_mm.end_data = (unsigned long) &_edata; | ||
155 | init_mm.brk = (unsigned long) 0; | ||
156 | |||
157 | config_BSP(&command_line[0], sizeof(command_line)); | ||
158 | |||
159 | printk(KERN_INFO "\x0F\r\n\nuClinux/" CPU "\n"); | ||
160 | |||
161 | #ifdef CONFIG_UCDIMM | ||
162 | printk(KERN_INFO "uCdimm by Lineo, Inc. <www.lineo.com>\n"); | ||
163 | #endif | ||
164 | #ifdef CONFIG_M68VZ328 | ||
165 | printk(KERN_INFO "M68VZ328 support by Evan Stawnyczy <e@lineo.ca>\n"); | ||
166 | #endif | ||
167 | #ifdef CONFIG_COLDFIRE | ||
168 | printk(KERN_INFO "COLDFIRE port done by Greg Ungerer, gerg@snapgear.com\n"); | ||
169 | #ifdef CONFIG_M5307 | ||
170 | printk(KERN_INFO "Modified for M5307 by Dave Miller, dmiller@intellistor.com\n"); | ||
171 | #endif | ||
172 | #ifdef CONFIG_ELITE | ||
173 | printk(KERN_INFO "Modified for M5206eLITE by Rob Scott, rscott@mtrob.fdns.net\n"); | ||
174 | #endif | ||
175 | #ifdef CONFIG_TELOS | ||
176 | printk(KERN_INFO "Modified for Omnia ToolVox by James D. Schettine, james@telos-systems.com\n"); | ||
177 | #endif | ||
178 | #endif | ||
179 | printk(KERN_INFO "Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n"); | ||
180 | |||
181 | #if defined( CONFIG_PILOT ) && defined( CONFIG_M68328 ) | ||
182 | printk(KERN_INFO "TRG SuperPilot FLASH card support <info@trgnet.com>\n"); | ||
183 | #endif | ||
184 | |||
185 | #if defined( CONFIG_PILOT ) && defined( CONFIG_M68EZ328 ) | ||
186 | printk(KERN_INFO "PalmV support by Lineo Inc. <jeff@uclinux.com>\n"); | ||
187 | #endif | ||
188 | |||
189 | #ifdef CONFIG_M68EZ328ADS | ||
190 | printk(KERN_INFO "M68EZ328ADS board support (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>\n"); | ||
191 | #endif | ||
192 | |||
193 | #ifdef CONFIG_ALMA_ANS | ||
194 | printk(KERN_INFO "Alma Electronics board support (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>\n"); | ||
195 | #endif | ||
196 | #if defined (CONFIG_M68360) | ||
197 | printk(KERN_INFO "QUICC port done by SED Systems <hamilton@sedsystems.ca>,\n"); | ||
198 | printk(KERN_INFO "based on 2.0.38 port by Lineo Inc. <mleslie@lineo.com>.\n"); | ||
199 | #endif | ||
200 | #ifdef CONFIG_DRAGEN2 | ||
201 | printk(KERN_INFO "DragonEngine II board support by Georges Menie\n"); | ||
202 | #endif | ||
203 | |||
204 | #ifdef DEBUG | ||
205 | printk(KERN_DEBUG "KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x " | ||
206 | "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext, | ||
207 | (int) &_sdata, (int) &_edata, | ||
208 | (int) &_sbss, (int) &_ebss); | ||
209 | printk(KERN_DEBUG "KERNEL -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x " | ||
210 | "STACK=0x%06x-0x%06x\n", | ||
211 | #ifdef CAT_ROMARRAY | ||
212 | (int) romarray, ((int) romarray) + romarray[2], | ||
213 | #else | ||
214 | (int) &_ebss, (int) memory_start, | ||
215 | #endif | ||
216 | (int) memory_start, (int) memory_end, | ||
217 | (int) memory_end, (int) _ramend); | ||
218 | #endif | ||
219 | |||
220 | /* Keep a copy of command line */ | ||
221 | *cmdline_p = &command_line[0]; | ||
222 | memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); | ||
223 | saved_command_line[COMMAND_LINE_SIZE-1] = 0; | ||
224 | |||
225 | #ifdef DEBUG | ||
226 | if (strlen(*cmdline_p)) | ||
227 | printk(KERN_DEBUG "Command line: '%s'\n", *cmdline_p); | ||
228 | #endif | ||
229 | |||
230 | #if defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_DUMMY_CONSOLE) | ||
231 | conswitchp = &dummy_con; | ||
232 | #endif | ||
233 | |||
234 | /* | ||
235 | * Give all the memory to the bootmap allocator, tell it to put the | ||
236 | * boot mem_map at the start of memory. | ||
237 | */ | ||
238 | bootmap_size = init_bootmem_node( | ||
239 | NODE_DATA(0), | ||
240 | memory_start >> PAGE_SHIFT, /* map goes here */ | ||
241 | PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */ | ||
242 | memory_end >> PAGE_SHIFT); | ||
243 | /* | ||
244 | * Free the usable memory, we have to make sure we do not free | ||
245 | * the bootmem bitmap so we then reserve it after freeing it :-) | ||
246 | */ | ||
247 | free_bootmem(memory_start, memory_end - memory_start); | ||
248 | reserve_bootmem(memory_start, bootmap_size); | ||
249 | |||
250 | /* | ||
251 | * Get kmalloc into gear. | ||
252 | */ | ||
253 | paging_init(); | ||
254 | } | ||
255 | |||
256 | int get_cpuinfo(char * buffer) | ||
257 | { | ||
258 | char *cpu, *mmu, *fpu; | ||
259 | u_long clockfreq; | ||
260 | |||
261 | cpu = CPU; | ||
262 | mmu = "none"; | ||
263 | fpu = "none"; | ||
264 | |||
265 | #ifdef CONFIG_COLDFIRE | ||
266 | clockfreq = (loops_per_jiffy*HZ)*3; | ||
267 | #else | ||
268 | clockfreq = (loops_per_jiffy*HZ)*16; | ||
269 | #endif | ||
270 | |||
271 | return(sprintf(buffer, "CPU:\t\t%s\n" | ||
272 | "MMU:\t\t%s\n" | ||
273 | "FPU:\t\t%s\n" | ||
274 | "Clocking:\t%lu.%1luMHz\n" | ||
275 | "BogoMips:\t%lu.%02lu\n" | ||
276 | "Calibration:\t%lu loops\n", | ||
277 | cpu, mmu, fpu, | ||
278 | clockfreq/1000000,(clockfreq/100000)%10, | ||
279 | (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, | ||
280 | (loops_per_jiffy*HZ))); | ||
281 | |||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Get CPU information for use by the procfs. | ||
286 | */ | ||
287 | |||
288 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
289 | { | ||
290 | char *cpu, *mmu, *fpu; | ||
291 | u_long clockfreq; | ||
292 | |||
293 | cpu = CPU; | ||
294 | mmu = "none"; | ||
295 | fpu = "none"; | ||
296 | |||
297 | #ifdef CONFIG_COLDFIRE | ||
298 | clockfreq = (loops_per_jiffy*HZ)*3; | ||
299 | #else | ||
300 | clockfreq = (loops_per_jiffy*HZ)*16; | ||
301 | #endif | ||
302 | |||
303 | seq_printf(m, "CPU:\t\t%s\n" | ||
304 | "MMU:\t\t%s\n" | ||
305 | "FPU:\t\t%s\n" | ||
306 | "Clocking:\t%lu.%1luMHz\n" | ||
307 | "BogoMips:\t%lu.%02lu\n" | ||
308 | "Calibration:\t%lu loops\n", | ||
309 | cpu, mmu, fpu, | ||
310 | clockfreq/1000000,(clockfreq/100000)%10, | ||
311 | (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100, | ||
312 | (loops_per_jiffy*HZ)); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
318 | { | ||
319 | return *pos < NR_CPUS ? ((void *) 0x12345678) : NULL; | ||
320 | } | ||
321 | |||
322 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
323 | { | ||
324 | ++*pos; | ||
325 | return c_start(m, pos); | ||
326 | } | ||
327 | |||
328 | static void c_stop(struct seq_file *m, void *v) | ||
329 | { | ||
330 | } | ||
331 | |||
332 | struct seq_operations cpuinfo_op = { | ||
333 | .start = c_start, | ||
334 | .next = c_next, | ||
335 | .stop = c_stop, | ||
336 | .show = show_cpuinfo, | ||
337 | }; | ||
338 | |||
339 | void arch_gettod(int *year, int *mon, int *day, int *hour, | ||
340 | int *min, int *sec) | ||
341 | { | ||
342 | if (mach_gettod) | ||
343 | mach_gettod(year, mon, day, hour, min, sec); | ||
344 | else | ||
345 | *year = *mon = *day = *hour = *min = *sec = 0; | ||
346 | } | ||
347 | |||
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c new file mode 100644 index 000000000000..30dceb59a462 --- /dev/null +++ b/arch/m68knommu/kernel/signal.c | |||
@@ -0,0 +1,788 @@ | |||
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 | |||
54 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); | ||
55 | |||
56 | /* | ||
57 | * Atomically swap in the new signal mask, and wait for a signal. | ||
58 | */ | ||
59 | asmlinkage int do_sigsuspend(struct pt_regs *regs) | ||
60 | { | ||
61 | old_sigset_t mask = regs->d3; | ||
62 | sigset_t saveset; | ||
63 | |||
64 | mask &= _BLOCKABLE; | ||
65 | spin_lock_irq(¤t->sighand->siglock); | ||
66 | saveset = current->blocked; | ||
67 | siginitset(¤t->blocked, mask); | ||
68 | recalc_sigpending(); | ||
69 | spin_unlock_irq(¤t->sighand->siglock); | ||
70 | |||
71 | regs->d0 = -EINTR; | ||
72 | while (1) { | ||
73 | current->state = TASK_INTERRUPTIBLE; | ||
74 | schedule(); | ||
75 | if (do_signal(&saveset, regs)) | ||
76 | return -EINTR; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | asmlinkage int | ||
81 | do_rt_sigsuspend(struct pt_regs *regs) | ||
82 | { | ||
83 | sigset_t *unewset = (sigset_t *)regs->d1; | ||
84 | size_t sigsetsize = (size_t)regs->d2; | ||
85 | sigset_t saveset, newset; | ||
86 | |||
87 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
88 | if (sigsetsize != sizeof(sigset_t)) | ||
89 | return -EINVAL; | ||
90 | |||
91 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
92 | return -EFAULT; | ||
93 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
94 | |||
95 | spin_lock_irq(¤t->sighand->siglock); | ||
96 | saveset = current->blocked; | ||
97 | current->blocked = newset; | ||
98 | recalc_sigpending(); | ||
99 | spin_unlock_irq(¤t->sighand->siglock); | ||
100 | |||
101 | regs->d0 = -EINTR; | ||
102 | while (1) { | ||
103 | current->state = TASK_INTERRUPTIBLE; | ||
104 | schedule(); | ||
105 | if (do_signal(&saveset, regs)) | ||
106 | return -EINTR; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | asmlinkage int | ||
111 | sys_sigaction(int sig, const struct old_sigaction *act, | ||
112 | struct old_sigaction *oact) | ||
113 | { | ||
114 | struct k_sigaction new_ka, old_ka; | ||
115 | int ret; | ||
116 | |||
117 | if (act) { | ||
118 | old_sigset_t mask; | ||
119 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
120 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
121 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
122 | return -EFAULT; | ||
123 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
124 | __get_user(mask, &act->sa_mask); | ||
125 | siginitset(&new_ka.sa.sa_mask, mask); | ||
126 | } | ||
127 | |||
128 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
129 | |||
130 | if (!ret && oact) { | ||
131 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
132 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
133 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
134 | return -EFAULT; | ||
135 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
136 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
137 | } | ||
138 | |||
139 | return ret; | ||
140 | } | ||
141 | |||
142 | asmlinkage int | ||
143 | sys_sigaltstack(const stack_t *uss, stack_t *uoss) | ||
144 | { | ||
145 | return do_sigaltstack(uss, uoss, rdusp()); | ||
146 | } | ||
147 | |||
148 | |||
149 | /* | ||
150 | * Do a signal return; undo the signal stack. | ||
151 | * | ||
152 | * Keep the return code on the stack quadword aligned! | ||
153 | * That makes the cache flush below easier. | ||
154 | */ | ||
155 | |||
156 | struct sigframe | ||
157 | { | ||
158 | char *pretcode; | ||
159 | int sig; | ||
160 | int code; | ||
161 | struct sigcontext *psc; | ||
162 | char retcode[8]; | ||
163 | unsigned long extramask[_NSIG_WORDS-1]; | ||
164 | struct sigcontext sc; | ||
165 | }; | ||
166 | |||
167 | struct rt_sigframe | ||
168 | { | ||
169 | char *pretcode; | ||
170 | int sig; | ||
171 | struct siginfo *pinfo; | ||
172 | void *puc; | ||
173 | char retcode[8]; | ||
174 | struct siginfo info; | ||
175 | struct ucontext uc; | ||
176 | }; | ||
177 | |||
178 | #ifdef CONFIG_FPU | ||
179 | |||
180 | static unsigned char fpu_version = 0; /* version number of fpu, set by setup_frame */ | ||
181 | |||
182 | static inline int restore_fpu_state(struct sigcontext *sc) | ||
183 | { | ||
184 | int err = 1; | ||
185 | |||
186 | if (FPU_IS_EMU) { | ||
187 | /* restore registers */ | ||
188 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); | ||
189 | memcpy(current->thread.fp, sc->sc_fpregs, 24); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | if (sc->sc_fpstate[0]) { | ||
194 | /* Verify the frame format. */ | ||
195 | if (sc->sc_fpstate[0] != fpu_version) | ||
196 | goto out; | ||
197 | |||
198 | __asm__ volatile (".chip 68k/68881\n\t" | ||
199 | "fmovemx %0,%/fp0-%/fp1\n\t" | ||
200 | "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" | ||
201 | ".chip 68k" | ||
202 | : /* no outputs */ | ||
203 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); | ||
204 | } | ||
205 | __asm__ volatile (".chip 68k/68881\n\t" | ||
206 | "frestore %0\n\t" | ||
207 | ".chip 68k" : : "m" (*sc->sc_fpstate)); | ||
208 | err = 0; | ||
209 | |||
210 | out: | ||
211 | return err; | ||
212 | } | ||
213 | |||
214 | #define FPCONTEXT_SIZE 216 | ||
215 | #define uc_fpstate uc_filler[0] | ||
216 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] | ||
217 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] | ||
218 | |||
219 | static inline int rt_restore_fpu_state(struct ucontext *uc) | ||
220 | { | ||
221 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
222 | int context_size = 0; | ||
223 | fpregset_t fpregs; | ||
224 | int err = 1; | ||
225 | |||
226 | if (FPU_IS_EMU) { | ||
227 | /* restore fpu control register */ | ||
228 | if (__copy_from_user(current->thread.fpcntl, | ||
229 | &uc->uc_mcontext.fpregs.f_pcr, 12)) | ||
230 | goto out; | ||
231 | /* restore all other fpu register */ | ||
232 | if (__copy_from_user(current->thread.fp, | ||
233 | uc->uc_mcontext.fpregs.f_fpregs, 96)) | ||
234 | goto out; | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) | ||
239 | goto out; | ||
240 | if (fpstate[0]) { | ||
241 | context_size = fpstate[1]; | ||
242 | |||
243 | /* Verify the frame format. */ | ||
244 | if (fpstate[0] != fpu_version) | ||
245 | goto out; | ||
246 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, | ||
247 | sizeof(fpregs))) | ||
248 | goto out; | ||
249 | __asm__ volatile (".chip 68k/68881\n\t" | ||
250 | "fmovemx %0,%/fp0-%/fp7\n\t" | ||
251 | "fmoveml %1,%/fpcr/%/fpsr/%/fpiar\n\t" | ||
252 | ".chip 68k" | ||
253 | : /* no outputs */ | ||
254 | : "m" (*fpregs.f_fpregs), | ||
255 | "m" (fpregs.f_pcr)); | ||
256 | } | ||
257 | if (context_size && | ||
258 | __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, | ||
259 | context_size)) | ||
260 | goto out; | ||
261 | __asm__ volatile (".chip 68k/68881\n\t" | ||
262 | "frestore %0\n\t" | ||
263 | ".chip 68k" : : "m" (*fpstate)); | ||
264 | err = 0; | ||
265 | |||
266 | out: | ||
267 | return err; | ||
268 | } | ||
269 | |||
270 | #endif | ||
271 | |||
272 | static inline int | ||
273 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, | ||
274 | int *pd0) | ||
275 | { | ||
276 | int formatvec; | ||
277 | struct sigcontext context; | ||
278 | int err = 0; | ||
279 | |||
280 | /* get previous context */ | ||
281 | if (copy_from_user(&context, usc, sizeof(context))) | ||
282 | goto badframe; | ||
283 | |||
284 | /* restore passed registers */ | ||
285 | regs->d1 = context.sc_d1; | ||
286 | regs->a0 = context.sc_a0; | ||
287 | regs->a1 = context.sc_a1; | ||
288 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
289 | regs->pc = context.sc_pc; | ||
290 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
291 | wrusp(context.sc_usp); | ||
292 | formatvec = context.sc_formatvec; | ||
293 | regs->format = formatvec >> 12; | ||
294 | regs->vector = formatvec & 0xfff; | ||
295 | |||
296 | #ifdef CONFIG_FPU | ||
297 | err = restore_fpu_state(&context); | ||
298 | #endif | ||
299 | |||
300 | *pd0 = context.sc_d0; | ||
301 | return err; | ||
302 | |||
303 | badframe: | ||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | static inline int | ||
308 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | ||
309 | struct ucontext *uc, int *pd0) | ||
310 | { | ||
311 | int temp; | ||
312 | greg_t *gregs = uc->uc_mcontext.gregs; | ||
313 | unsigned long usp; | ||
314 | int err; | ||
315 | |||
316 | err = __get_user(temp, &uc->uc_mcontext.version); | ||
317 | if (temp != MCONTEXT_VERSION) | ||
318 | goto badframe; | ||
319 | /* restore passed registers */ | ||
320 | err |= __get_user(regs->d0, &gregs[0]); | ||
321 | err |= __get_user(regs->d1, &gregs[1]); | ||
322 | err |= __get_user(regs->d2, &gregs[2]); | ||
323 | err |= __get_user(regs->d3, &gregs[3]); | ||
324 | err |= __get_user(regs->d4, &gregs[4]); | ||
325 | err |= __get_user(regs->d5, &gregs[5]); | ||
326 | err |= __get_user(sw->d6, &gregs[6]); | ||
327 | err |= __get_user(sw->d7, &gregs[7]); | ||
328 | err |= __get_user(regs->a0, &gregs[8]); | ||
329 | err |= __get_user(regs->a1, &gregs[9]); | ||
330 | err |= __get_user(regs->a2, &gregs[10]); | ||
331 | err |= __get_user(sw->a3, &gregs[11]); | ||
332 | err |= __get_user(sw->a4, &gregs[12]); | ||
333 | err |= __get_user(sw->a5, &gregs[13]); | ||
334 | err |= __get_user(sw->a6, &gregs[14]); | ||
335 | err |= __get_user(usp, &gregs[15]); | ||
336 | wrusp(usp); | ||
337 | err |= __get_user(regs->pc, &gregs[16]); | ||
338 | err |= __get_user(temp, &gregs[17]); | ||
339 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | ||
340 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
341 | regs->format = temp >> 12; | ||
342 | regs->vector = temp & 0xfff; | ||
343 | |||
344 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | ||
345 | goto badframe; | ||
346 | |||
347 | *pd0 = regs->d0; | ||
348 | return err; | ||
349 | |||
350 | badframe: | ||
351 | return 1; | ||
352 | } | ||
353 | |||
354 | asmlinkage int do_sigreturn(unsigned long __unused) | ||
355 | { | ||
356 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
357 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
358 | unsigned long usp = rdusp(); | ||
359 | struct sigframe *frame = (struct sigframe *)(usp - 4); | ||
360 | sigset_t set; | ||
361 | int d0; | ||
362 | |||
363 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
364 | goto badframe; | ||
365 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || | ||
366 | (_NSIG_WORDS > 1 && | ||
367 | __copy_from_user(&set.sig[1], &frame->extramask, | ||
368 | sizeof(frame->extramask)))) | ||
369 | goto badframe; | ||
370 | |||
371 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
372 | spin_lock_irq(¤t->sighand->siglock); | ||
373 | current->blocked = set; | ||
374 | recalc_sigpending(); | ||
375 | spin_unlock_irq(¤t->sighand->siglock); | ||
376 | |||
377 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) | ||
378 | goto badframe; | ||
379 | return d0; | ||
380 | |||
381 | badframe: | ||
382 | force_sig(SIGSEGV, current); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | asmlinkage int do_rt_sigreturn(unsigned long __unused) | ||
387 | { | ||
388 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
389 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
390 | unsigned long usp = rdusp(); | ||
391 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); | ||
392 | sigset_t set; | ||
393 | int d0; | ||
394 | |||
395 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
396 | goto badframe; | ||
397 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
398 | goto badframe; | ||
399 | |||
400 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
401 | spin_lock_irq(¤t->sighand->siglock); | ||
402 | current->blocked = set; | ||
403 | recalc_sigpending(); | ||
404 | spin_unlock_irq(¤t->sighand->siglock); | ||
405 | |||
406 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) | ||
407 | goto badframe; | ||
408 | return d0; | ||
409 | |||
410 | badframe: | ||
411 | force_sig(SIGSEGV, current); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | #ifdef CONFIG_FPU | ||
416 | /* | ||
417 | * Set up a signal frame. | ||
418 | */ | ||
419 | |||
420 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) | ||
421 | { | ||
422 | if (FPU_IS_EMU) { | ||
423 | /* save registers */ | ||
424 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); | ||
425 | memcpy(sc->sc_fpregs, current->thread.fp, 24); | ||
426 | return; | ||
427 | } | ||
428 | |||
429 | __asm__ volatile (".chip 68k/68881\n\t" | ||
430 | "fsave %0\n\t" | ||
431 | ".chip 68k" | ||
432 | : : "m" (*sc->sc_fpstate) : "memory"); | ||
433 | |||
434 | if (sc->sc_fpstate[0]) { | ||
435 | fpu_version = sc->sc_fpstate[0]; | ||
436 | __asm__ volatile (".chip 68k/68881\n\t" | ||
437 | "fmovemx %/fp0-%/fp1,%0\n\t" | ||
438 | "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" | ||
439 | ".chip 68k" | ||
440 | : /* no outputs */ | ||
441 | : "m" (*sc->sc_fpregs), | ||
442 | "m" (*sc->sc_fpcntl) | ||
443 | : "memory"); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) | ||
448 | { | ||
449 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
450 | int context_size = 0; | ||
451 | int err = 0; | ||
452 | |||
453 | if (FPU_IS_EMU) { | ||
454 | /* save fpu control register */ | ||
455 | err |= copy_to_user(&uc->uc_mcontext.fpregs.f_pcr, | ||
456 | current->thread.fpcntl, 12); | ||
457 | /* save all other fpu register */ | ||
458 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, | ||
459 | current->thread.fp, 96); | ||
460 | return err; | ||
461 | } | ||
462 | |||
463 | __asm__ volatile (".chip 68k/68881\n\t" | ||
464 | "fsave %0\n\t" | ||
465 | ".chip 68k" | ||
466 | : : "m" (*fpstate) : "memory"); | ||
467 | |||
468 | err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); | ||
469 | if (fpstate[0]) { | ||
470 | fpregset_t fpregs; | ||
471 | context_size = fpstate[1]; | ||
472 | fpu_version = fpstate[0]; | ||
473 | __asm__ volatile (".chip 68k/68881\n\t" | ||
474 | "fmovemx %/fp0-%/fp7,%0\n\t" | ||
475 | "fmoveml %/fpcr/%/fpsr/%/fpiar,%1\n\t" | ||
476 | ".chip 68k" | ||
477 | : /* no outputs */ | ||
478 | : "m" (*fpregs.f_fpregs), | ||
479 | "m" (fpregs.f_pcr) | ||
480 | : "memory"); | ||
481 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, | ||
482 | sizeof(fpregs)); | ||
483 | } | ||
484 | if (context_size) | ||
485 | err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, | ||
486 | context_size); | ||
487 | return err; | ||
488 | } | ||
489 | |||
490 | #endif | ||
491 | |||
492 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | ||
493 | unsigned long mask) | ||
494 | { | ||
495 | sc->sc_mask = mask; | ||
496 | sc->sc_usp = rdusp(); | ||
497 | sc->sc_d0 = regs->d0; | ||
498 | sc->sc_d1 = regs->d1; | ||
499 | sc->sc_a0 = regs->a0; | ||
500 | sc->sc_a1 = regs->a1; | ||
501 | sc->sc_sr = regs->sr; | ||
502 | sc->sc_pc = regs->pc; | ||
503 | sc->sc_formatvec = regs->format << 12 | regs->vector; | ||
504 | #ifdef CONFIG_FPU | ||
505 | save_fpu_state(sc, regs); | ||
506 | #endif | ||
507 | } | ||
508 | |||
509 | static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) | ||
510 | { | ||
511 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
512 | greg_t *gregs = uc->uc_mcontext.gregs; | ||
513 | int err = 0; | ||
514 | |||
515 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); | ||
516 | err |= __put_user(regs->d0, &gregs[0]); | ||
517 | err |= __put_user(regs->d1, &gregs[1]); | ||
518 | err |= __put_user(regs->d2, &gregs[2]); | ||
519 | err |= __put_user(regs->d3, &gregs[3]); | ||
520 | err |= __put_user(regs->d4, &gregs[4]); | ||
521 | err |= __put_user(regs->d5, &gregs[5]); | ||
522 | err |= __put_user(sw->d6, &gregs[6]); | ||
523 | err |= __put_user(sw->d7, &gregs[7]); | ||
524 | err |= __put_user(regs->a0, &gregs[8]); | ||
525 | err |= __put_user(regs->a1, &gregs[9]); | ||
526 | err |= __put_user(regs->a2, &gregs[10]); | ||
527 | err |= __put_user(sw->a3, &gregs[11]); | ||
528 | err |= __put_user(sw->a4, &gregs[12]); | ||
529 | err |= __put_user(sw->a5, &gregs[13]); | ||
530 | err |= __put_user(sw->a6, &gregs[14]); | ||
531 | err |= __put_user(rdusp(), &gregs[15]); | ||
532 | err |= __put_user(regs->pc, &gregs[16]); | ||
533 | err |= __put_user(regs->sr, &gregs[17]); | ||
534 | #ifdef CONFIG_FPU | ||
535 | err |= rt_save_fpu_state(uc, regs); | ||
536 | #endif | ||
537 | return err; | ||
538 | } | ||
539 | |||
540 | static inline void push_cache (unsigned long vaddr) | ||
541 | { | ||
542 | } | ||
543 | |||
544 | static inline void * | ||
545 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | ||
546 | { | ||
547 | unsigned long usp; | ||
548 | |||
549 | /* Default to using normal stack. */ | ||
550 | usp = rdusp(); | ||
551 | |||
552 | /* This is the X/Open sanctioned signal stack switching. */ | ||
553 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
554 | if (!on_sig_stack(usp)) | ||
555 | usp = current->sas_ss_sp + current->sas_ss_size; | ||
556 | } | ||
557 | return (void *)((usp - frame_size) & -8UL); | ||
558 | } | ||
559 | |||
560 | static void setup_frame (int sig, struct k_sigaction *ka, | ||
561 | sigset_t *set, struct pt_regs *regs) | ||
562 | { | ||
563 | struct sigframe *frame; | ||
564 | struct sigcontext context; | ||
565 | int err = 0; | ||
566 | |||
567 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
568 | |||
569 | err |= __put_user((current_thread_info()->exec_domain | ||
570 | && current_thread_info()->exec_domain->signal_invmap | ||
571 | && sig < 32 | ||
572 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
573 | : sig), | ||
574 | &frame->sig); | ||
575 | |||
576 | err |= __put_user(regs->vector, &frame->code); | ||
577 | err |= __put_user(&frame->sc, &frame->psc); | ||
578 | |||
579 | if (_NSIG_WORDS > 1) | ||
580 | err |= copy_to_user(frame->extramask, &set->sig[1], | ||
581 | sizeof(frame->extramask)); | ||
582 | |||
583 | setup_sigcontext(&context, regs, set->sig[0]); | ||
584 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); | ||
585 | |||
586 | /* Set up to return from userspace. */ | ||
587 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
588 | /* moveq #,d0; trap #0 */ | ||
589 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), | ||
590 | (long *)(frame->retcode)); | ||
591 | |||
592 | if (err) | ||
593 | goto give_sigsegv; | ||
594 | |||
595 | push_cache ((unsigned long) &frame->retcode); | ||
596 | |||
597 | /* Set up registers for signal handler */ | ||
598 | wrusp ((unsigned long) frame); | ||
599 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
600 | |||
601 | adjust_stack: | ||
602 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
603 | if (regs->stkadj) { | ||
604 | struct pt_regs *tregs = | ||
605 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
606 | #if DEBUG | ||
607 | printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj); | ||
608 | #endif | ||
609 | /* This must be copied with decreasing addresses to | ||
610 | handle overlaps. */ | ||
611 | tregs->vector = 0; | ||
612 | tregs->format = 0; | ||
613 | tregs->pc = regs->pc; | ||
614 | tregs->sr = regs->sr; | ||
615 | } | ||
616 | return; | ||
617 | |||
618 | give_sigsegv: | ||
619 | force_sigsegv(sig, current); | ||
620 | goto adjust_stack; | ||
621 | } | ||
622 | |||
623 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | ||
624 | sigset_t *set, struct pt_regs *regs) | ||
625 | { | ||
626 | struct rt_sigframe *frame; | ||
627 | int err = 0; | ||
628 | |||
629 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
630 | |||
631 | err |= __put_user((current_thread_info()->exec_domain | ||
632 | && current_thread_info()->exec_domain->signal_invmap | ||
633 | && sig < 32 | ||
634 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
635 | : sig), | ||
636 | &frame->sig); | ||
637 | err |= __put_user(&frame->info, &frame->pinfo); | ||
638 | err |= __put_user(&frame->uc, &frame->puc); | ||
639 | err |= copy_siginfo_to_user(&frame->info, info); | ||
640 | |||
641 | /* Create the ucontext. */ | ||
642 | err |= __put_user(0, &frame->uc.uc_flags); | ||
643 | err |= __put_user(0, &frame->uc.uc_link); | ||
644 | err |= __put_user((void *)current->sas_ss_sp, | ||
645 | &frame->uc.uc_stack.ss_sp); | ||
646 | err |= __put_user(sas_ss_flags(rdusp()), | ||
647 | &frame->uc.uc_stack.ss_flags); | ||
648 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
649 | err |= rt_setup_ucontext(&frame->uc, regs); | ||
650 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
651 | |||
652 | /* Set up to return from userspace. */ | ||
653 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
654 | /* moveq #,d0; notb d0; trap #0 */ | ||
655 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), | ||
656 | (long *)(frame->retcode + 0)); | ||
657 | err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); | ||
658 | |||
659 | if (err) | ||
660 | goto give_sigsegv; | ||
661 | |||
662 | push_cache ((unsigned long) &frame->retcode); | ||
663 | |||
664 | /* Set up registers for signal handler */ | ||
665 | wrusp ((unsigned long) frame); | ||
666 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
667 | |||
668 | adjust_stack: | ||
669 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
670 | if (regs->stkadj) { | ||
671 | struct pt_regs *tregs = | ||
672 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
673 | #if DEBUG | ||
674 | printk(KERN_DEBUG "Performing stackadjust=%04x\n", regs->stkadj); | ||
675 | #endif | ||
676 | /* This must be copied with decreasing addresses to | ||
677 | handle overlaps. */ | ||
678 | tregs->vector = 0; | ||
679 | tregs->format = 0; | ||
680 | tregs->pc = regs->pc; | ||
681 | tregs->sr = regs->sr; | ||
682 | } | ||
683 | return; | ||
684 | |||
685 | give_sigsegv: | ||
686 | force_sigsegv(sig, current); | ||
687 | goto adjust_stack; | ||
688 | } | ||
689 | |||
690 | static inline void | ||
691 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) | ||
692 | { | ||
693 | switch (regs->d0) { | ||
694 | case -ERESTARTNOHAND: | ||
695 | if (!has_handler) | ||
696 | goto do_restart; | ||
697 | regs->d0 = -EINTR; | ||
698 | break; | ||
699 | |||
700 | case -ERESTARTSYS: | ||
701 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { | ||
702 | regs->d0 = -EINTR; | ||
703 | break; | ||
704 | } | ||
705 | /* fallthrough */ | ||
706 | case -ERESTARTNOINTR: | ||
707 | do_restart: | ||
708 | regs->d0 = regs->orig_d0; | ||
709 | regs->pc -= 2; | ||
710 | break; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | /* | ||
715 | * OK, we're invoking a handler | ||
716 | */ | ||
717 | static void | ||
718 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
719 | sigset_t *oldset, struct pt_regs *regs) | ||
720 | { | ||
721 | /* are we from a system call? */ | ||
722 | if (regs->orig_d0 >= 0) | ||
723 | /* If so, check system call restarting.. */ | ||
724 | handle_restart(regs, ka, 1); | ||
725 | |||
726 | /* set up the stack frame */ | ||
727 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
728 | setup_rt_frame(sig, ka, info, oldset, regs); | ||
729 | else | ||
730 | setup_frame(sig, ka, oldset, regs); | ||
731 | |||
732 | if (ka->sa.sa_flags & SA_ONESHOT) | ||
733 | ka->sa.sa_handler = SIG_DFL; | ||
734 | |||
735 | if (!(ka->sa.sa_flags & SA_NODEFER)) { | ||
736 | spin_lock_irq(¤t->sighand->siglock); | ||
737 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
738 | sigaddset(¤t->blocked,sig); | ||
739 | recalc_sigpending(); | ||
740 | spin_unlock_irq(¤t->sighand->siglock); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | /* | ||
745 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
746 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
747 | * mistake. | ||
748 | */ | ||
749 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) | ||
750 | { | ||
751 | struct k_sigaction ka; | ||
752 | siginfo_t info; | ||
753 | int signr; | ||
754 | |||
755 | /* | ||
756 | * We want the common case to go fast, which | ||
757 | * is why we may in certain cases get here from | ||
758 | * kernel mode. Just return without doing anything | ||
759 | * if so. | ||
760 | */ | ||
761 | if (!user_mode(regs)) | ||
762 | return 1; | ||
763 | |||
764 | if (!oldset) | ||
765 | oldset = ¤t->blocked; | ||
766 | |||
767 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
768 | if (signr > 0) { | ||
769 | /* Whee! Actually deliver the signal. */ | ||
770 | handle_signal(signr, &ka, &info, oldset, regs); | ||
771 | return 1; | ||
772 | } | ||
773 | |||
774 | /* Did we come from a system call? */ | ||
775 | if (regs->orig_d0 >= 0) { | ||
776 | /* Restart the system call - no handlers present */ | ||
777 | if (regs->d0 == -ERESTARTNOHAND | ||
778 | || regs->d0 == -ERESTARTSYS | ||
779 | || regs->d0 == -ERESTARTNOINTR) { | ||
780 | regs->d0 = regs->orig_d0; | ||
781 | regs->pc -= 2; | ||
782 | } else if (regs->d0 == -ERESTART_RESTARTBLOCK) { | ||
783 | regs->d0 = __NR_restart_syscall; | ||
784 | regs->pc -= 2; | ||
785 | } | ||
786 | } | ||
787 | return 0; | ||
788 | } | ||
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c new file mode 100644 index 000000000000..d87e1e0a1336 --- /dev/null +++ b/arch/m68knommu/kernel/sys_m68k.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * linux/arch/m68knommu/kernel/sys_m68k.c | ||
3 | * | ||
4 | * This file contains various random system calls that | ||
5 | * have a non-standard calling sequence on the Linux/m68k | ||
6 | * platform. | ||
7 | */ | ||
8 | |||
9 | #include <linux/errno.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/smp.h> | ||
13 | #include <linux/smp_lock.h> | ||
14 | #include <linux/sem.h> | ||
15 | #include <linux/msg.h> | ||
16 | #include <linux/shm.h> | ||
17 | #include <linux/stat.h> | ||
18 | #include <linux/syscalls.h> | ||
19 | #include <linux/mman.h> | ||
20 | #include <linux/file.h> | ||
21 | #include <linux/utsname.h> | ||
22 | |||
23 | #include <asm/setup.h> | ||
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/cachectl.h> | ||
26 | #include <asm/traps.h> | ||
27 | #include <asm/ipc.h> | ||
28 | #include <asm/cacheflush.h> | ||
29 | |||
30 | /* | ||
31 | * sys_pipe() is the normal C calling standard for creating | ||
32 | * a pipe. It's not the way unix traditionally does this, though. | ||
33 | */ | ||
34 | asmlinkage int sys_pipe(unsigned long * fildes) | ||
35 | { | ||
36 | int fd[2]; | ||
37 | int error; | ||
38 | |||
39 | error = do_pipe(fd); | ||
40 | if (!error) { | ||
41 | if (copy_to_user(fildes, fd, 2*sizeof(int))) | ||
42 | error = -EFAULT; | ||
43 | } | ||
44 | return error; | ||
45 | } | ||
46 | |||
47 | /* common code for old and new mmaps */ | ||
48 | static inline long do_mmap2( | ||
49 | unsigned long addr, unsigned long len, | ||
50 | unsigned long prot, unsigned long flags, | ||
51 | unsigned long fd, unsigned long pgoff) | ||
52 | { | ||
53 | int error = -EBADF; | ||
54 | struct file * file = NULL; | ||
55 | |||
56 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
57 | if (!(flags & MAP_ANONYMOUS)) { | ||
58 | file = fget(fd); | ||
59 | if (!file) | ||
60 | goto out; | ||
61 | } | ||
62 | |||
63 | down_write(¤t->mm->mmap_sem); | ||
64 | error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
65 | up_write(¤t->mm->mmap_sem); | ||
66 | |||
67 | if (file) | ||
68 | fput(file); | ||
69 | out: | ||
70 | return error; | ||
71 | } | ||
72 | |||
73 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | ||
74 | unsigned long prot, unsigned long flags, | ||
75 | unsigned long fd, unsigned long pgoff) | ||
76 | { | ||
77 | return do_mmap2(addr, len, prot, flags, fd, pgoff); | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * Perform the select(nd, in, out, ex, tv) and mmap() system | ||
82 | * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to | ||
83 | * handle more than 4 system call parameters, so these system calls | ||
84 | * used a memory block for parameter passing.. | ||
85 | */ | ||
86 | |||
87 | struct mmap_arg_struct { | ||
88 | unsigned long addr; | ||
89 | unsigned long len; | ||
90 | unsigned long prot; | ||
91 | unsigned long flags; | ||
92 | unsigned long fd; | ||
93 | unsigned long offset; | ||
94 | }; | ||
95 | |||
96 | asmlinkage int old_mmap(struct mmap_arg_struct *arg) | ||
97 | { | ||
98 | struct mmap_arg_struct a; | ||
99 | int error = -EFAULT; | ||
100 | |||
101 | if (copy_from_user(&a, arg, sizeof(a))) | ||
102 | goto out; | ||
103 | |||
104 | error = -EINVAL; | ||
105 | if (a.offset & ~PAGE_MASK) | ||
106 | goto out; | ||
107 | |||
108 | a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
109 | |||
110 | error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); | ||
111 | out: | ||
112 | return error; | ||
113 | } | ||
114 | |||
115 | struct sel_arg_struct { | ||
116 | unsigned long n; | ||
117 | fd_set *inp, *outp, *exp; | ||
118 | struct timeval *tvp; | ||
119 | }; | ||
120 | |||
121 | asmlinkage int old_select(struct sel_arg_struct *arg) | ||
122 | { | ||
123 | struct sel_arg_struct a; | ||
124 | |||
125 | if (copy_from_user(&a, arg, sizeof(a))) | ||
126 | return -EFAULT; | ||
127 | /* sys_select() does the appropriate kernel locking */ | ||
128 | return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | ||
133 | * | ||
134 | * This is really horribly ugly. | ||
135 | */ | ||
136 | asmlinkage int sys_ipc (uint call, int first, int second, | ||
137 | int third, void *ptr, long fifth) | ||
138 | { | ||
139 | int version; | ||
140 | |||
141 | version = call >> 16; /* hack for backward compatibility */ | ||
142 | call &= 0xffff; | ||
143 | |||
144 | if (call <= SEMCTL) | ||
145 | switch (call) { | ||
146 | case SEMOP: | ||
147 | return sys_semop (first, (struct sembuf *)ptr, second); | ||
148 | case SEMGET: | ||
149 | return sys_semget (first, second, third); | ||
150 | case SEMCTL: { | ||
151 | union semun fourth; | ||
152 | if (!ptr) | ||
153 | return -EINVAL; | ||
154 | if (get_user(fourth.__pad, (void **) ptr)) | ||
155 | return -EFAULT; | ||
156 | return sys_semctl (first, second, third, fourth); | ||
157 | } | ||
158 | default: | ||
159 | return -EINVAL; | ||
160 | } | ||
161 | if (call <= MSGCTL) | ||
162 | switch (call) { | ||
163 | case MSGSND: | ||
164 | return sys_msgsnd (first, (struct msgbuf *) ptr, | ||
165 | second, third); | ||
166 | case MSGRCV: | ||
167 | switch (version) { | ||
168 | case 0: { | ||
169 | struct ipc_kludge tmp; | ||
170 | if (!ptr) | ||
171 | return -EINVAL; | ||
172 | if (copy_from_user (&tmp, | ||
173 | (struct ipc_kludge *)ptr, | ||
174 | sizeof (tmp))) | ||
175 | return -EFAULT; | ||
176 | return sys_msgrcv (first, tmp.msgp, second, | ||
177 | tmp.msgtyp, third); | ||
178 | } | ||
179 | default: | ||
180 | return sys_msgrcv (first, | ||
181 | (struct msgbuf *) ptr, | ||
182 | second, fifth, third); | ||
183 | } | ||
184 | case MSGGET: | ||
185 | return sys_msgget ((key_t) first, second); | ||
186 | case MSGCTL: | ||
187 | return sys_msgctl (first, second, | ||
188 | (struct msqid_ds *) ptr); | ||
189 | default: | ||
190 | return -EINVAL; | ||
191 | } | ||
192 | |||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | /* sys_cacheflush -- flush (part of) the processor cache. */ | ||
197 | asmlinkage int | ||
198 | sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) | ||
199 | { | ||
200 | flush_cache_all(); | ||
201 | return(0); | ||
202 | } | ||
203 | |||
204 | asmlinkage int sys_getpagesize(void) | ||
205 | { | ||
206 | return PAGE_SIZE; | ||
207 | } | ||
208 | |||
diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S new file mode 100644 index 000000000000..897deaa06b01 --- /dev/null +++ b/arch/m68knommu/kernel/syscalltable.S | |||
@@ -0,0 +1,308 @@ | |||
1 | /* | ||
2 | * linux/arch/m68knommu/kernel/syscalltable.S | ||
3 | * | ||
4 | * Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com) | ||
5 | * | ||
6 | * Based on older entry.S files, the following copyrights apply: | ||
7 | * | ||
8 | * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, | ||
9 | * Kenneth Albanowski <kjahds@kjahds.com>, | ||
10 | * Copyright (C) 2000 Lineo Inc. (www.lineo.com) | ||
11 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/sys.h> | ||
16 | #include <linux/linkage.h> | ||
17 | #include <asm/unistd.h> | ||
18 | |||
19 | .text | ||
20 | ALIGN | ||
21 | ENTRY(sys_call_table) | ||
22 | .long sys_ni_syscall /* 0 - old "setup()" system call*/ | ||
23 | .long sys_exit | ||
24 | .long sys_fork | ||
25 | .long sys_read | ||
26 | .long sys_write | ||
27 | .long sys_open /* 5 */ | ||
28 | .long sys_close | ||
29 | .long sys_waitpid | ||
30 | .long sys_creat | ||
31 | .long sys_link | ||
32 | .long sys_unlink /* 10 */ | ||
33 | .long sys_execve | ||
34 | .long sys_chdir | ||
35 | .long sys_time | ||
36 | .long sys_mknod | ||
37 | .long sys_chmod /* 15 */ | ||
38 | .long sys_chown16 | ||
39 | .long sys_ni_syscall /* old break syscall holder */ | ||
40 | .long sys_stat | ||
41 | .long sys_lseek | ||
42 | .long sys_getpid /* 20 */ | ||
43 | .long sys_mount | ||
44 | .long sys_oldumount | ||
45 | .long sys_setuid16 | ||
46 | .long sys_getuid16 | ||
47 | .long sys_stime /* 25 */ | ||
48 | .long sys_ptrace | ||
49 | .long sys_alarm | ||
50 | .long sys_fstat | ||
51 | .long sys_pause | ||
52 | .long sys_utime /* 30 */ | ||
53 | .long sys_ni_syscall /* old stty syscall holder */ | ||
54 | .long sys_ni_syscall /* old gtty syscall holder */ | ||
55 | .long sys_access | ||
56 | .long sys_nice | ||
57 | .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ | ||
58 | .long sys_sync | ||
59 | .long sys_kill | ||
60 | .long sys_rename | ||
61 | .long sys_mkdir | ||
62 | .long sys_rmdir /* 40 */ | ||
63 | .long sys_dup | ||
64 | .long sys_pipe | ||
65 | .long sys_times | ||
66 | .long sys_ni_syscall /* old prof syscall holder */ | ||
67 | .long sys_brk /* 45 */ | ||
68 | .long sys_setgid16 | ||
69 | .long sys_getgid16 | ||
70 | .long sys_signal | ||
71 | .long sys_geteuid16 | ||
72 | .long sys_getegid16 /* 50 */ | ||
73 | .long sys_acct | ||
74 | .long sys_umount /* recycled never used phys() */ | ||
75 | .long sys_ni_syscall /* old lock syscall holder */ | ||
76 | .long sys_ioctl | ||
77 | .long sys_fcntl /* 55 */ | ||
78 | .long sys_ni_syscall /* old mpx syscall holder */ | ||
79 | .long sys_setpgid | ||
80 | .long sys_ni_syscall /* old ulimit syscall holder */ | ||
81 | .long sys_ni_syscall | ||
82 | .long sys_umask /* 60 */ | ||
83 | .long sys_chroot | ||
84 | .long sys_ustat | ||
85 | .long sys_dup2 | ||
86 | .long sys_getppid | ||
87 | .long sys_getpgrp /* 65 */ | ||
88 | .long sys_setsid | ||
89 | .long sys_sigaction | ||
90 | .long sys_sgetmask | ||
91 | .long sys_ssetmask | ||
92 | .long sys_setreuid16 /* 70 */ | ||
93 | .long sys_setregid16 | ||
94 | .long sys_sigsuspend | ||
95 | .long sys_sigpending | ||
96 | .long sys_sethostname | ||
97 | .long sys_setrlimit /* 75 */ | ||
98 | .long sys_old_getrlimit | ||
99 | .long sys_getrusage | ||
100 | .long sys_gettimeofday | ||
101 | .long sys_settimeofday | ||
102 | .long sys_getgroups16 /* 80 */ | ||
103 | .long sys_setgroups16 | ||
104 | .long old_select | ||
105 | .long sys_symlink | ||
106 | .long sys_lstat | ||
107 | .long sys_readlink /* 85 */ | ||
108 | .long sys_uselib | ||
109 | .long sys_ni_syscall /* sys_swapon */ | ||
110 | .long sys_reboot | ||
111 | .long old_readdir | ||
112 | .long old_mmap /* 90 */ | ||
113 | .long sys_munmap | ||
114 | .long sys_truncate | ||
115 | .long sys_ftruncate | ||
116 | .long sys_fchmod | ||
117 | .long sys_fchown16 /* 95 */ | ||
118 | .long sys_getpriority | ||
119 | .long sys_setpriority | ||
120 | .long sys_ni_syscall /* old profil syscall holder */ | ||
121 | .long sys_statfs | ||
122 | .long sys_fstatfs /* 100 */ | ||
123 | .long sys_ni_syscall /* ioperm for i386 */ | ||
124 | .long sys_socketcall | ||
125 | .long sys_syslog | ||
126 | .long sys_setitimer | ||
127 | .long sys_getitimer /* 105 */ | ||
128 | .long sys_newstat | ||
129 | .long sys_newlstat | ||
130 | .long sys_newfstat | ||
131 | .long sys_ni_syscall | ||
132 | .long sys_ni_syscall /* iopl for i386 */ /* 110 */ | ||
133 | .long sys_vhangup | ||
134 | .long sys_ni_syscall /* obsolete idle() syscall */ | ||
135 | .long sys_ni_syscall /* vm86old for i386 */ | ||
136 | .long sys_wait4 | ||
137 | .long sys_ni_syscall /* 115 */ /* sys_swapoff */ | ||
138 | .long sys_sysinfo | ||
139 | .long sys_ipc | ||
140 | .long sys_fsync | ||
141 | .long sys_sigreturn | ||
142 | .long sys_clone /* 120 */ | ||
143 | .long sys_setdomainname | ||
144 | .long sys_newuname | ||
145 | .long sys_cacheflush /* modify_ldt for i386 */ | ||
146 | .long sys_adjtimex | ||
147 | .long sys_ni_syscall /* 125 */ /* sys_mprotect */ | ||
148 | .long sys_sigprocmask | ||
149 | .long sys_ni_syscall /* old "creat_module" */ | ||
150 | .long sys_init_module | ||
151 | .long sys_delete_module | ||
152 | .long sys_ni_syscall /* 130: old "get_kernel_syms" */ | ||
153 | .long sys_quotactl | ||
154 | .long sys_getpgid | ||
155 | .long sys_fchdir | ||
156 | .long sys_bdflush | ||
157 | .long sys_sysfs /* 135 */ | ||
158 | .long sys_personality | ||
159 | .long sys_ni_syscall /* for afs_syscall */ | ||
160 | .long sys_setfsuid16 | ||
161 | .long sys_setfsgid16 | ||
162 | .long sys_llseek /* 140 */ | ||
163 | .long sys_getdents | ||
164 | .long sys_select | ||
165 | .long sys_flock | ||
166 | .long sys_ni_syscall /* sys_msync */ | ||
167 | .long sys_readv /* 145 */ | ||
168 | .long sys_writev | ||
169 | .long sys_getsid | ||
170 | .long sys_fdatasync | ||
171 | .long sys_sysctl | ||
172 | .long sys_ni_syscall /* 150 */ /* sys_mlock */ | ||
173 | .long sys_ni_syscall /* sys_munlock */ | ||
174 | .long sys_ni_syscall /* sys_mlockall */ | ||
175 | .long sys_ni_syscall /* sys_munlockall */ | ||
176 | .long sys_sched_setparam | ||
177 | .long sys_sched_getparam /* 155 */ | ||
178 | .long sys_sched_setscheduler | ||
179 | .long sys_sched_getscheduler | ||
180 | .long sys_sched_yield | ||
181 | .long sys_sched_get_priority_max | ||
182 | .long sys_sched_get_priority_min /* 160 */ | ||
183 | .long sys_sched_rr_get_interval | ||
184 | .long sys_nanosleep | ||
185 | .long sys_ni_syscall /* sys_mremap */ | ||
186 | .long sys_setresuid16 | ||
187 | .long sys_getresuid16 /* 165 */ | ||
188 | .long sys_getpagesize /* sys_getpagesize */ | ||
189 | .long sys_ni_syscall /* old "query_module" */ | ||
190 | .long sys_poll | ||
191 | .long sys_ni_syscall /* sys_nfsservctl */ | ||
192 | .long sys_setresgid16 /* 170 */ | ||
193 | .long sys_getresgid16 | ||
194 | .long sys_prctl | ||
195 | .long sys_rt_sigreturn | ||
196 | .long sys_rt_sigaction | ||
197 | .long sys_rt_sigprocmask /* 175 */ | ||
198 | .long sys_rt_sigpending | ||
199 | .long sys_rt_sigtimedwait | ||
200 | .long sys_rt_sigqueueinfo | ||
201 | .long sys_rt_sigsuspend | ||
202 | .long sys_pread64 /* 180 */ | ||
203 | .long sys_pwrite64 | ||
204 | .long sys_lchown16 | ||
205 | .long sys_getcwd | ||
206 | .long sys_capget | ||
207 | .long sys_capset /* 185 */ | ||
208 | .long sys_sigaltstack | ||
209 | .long sys_sendfile | ||
210 | .long sys_ni_syscall /* streams1 */ | ||
211 | .long sys_ni_syscall /* streams2 */ | ||
212 | .long sys_vfork /* 190 */ | ||
213 | .long sys_getrlimit | ||
214 | .long sys_mmap2 | ||
215 | .long sys_truncate64 | ||
216 | .long sys_ftruncate64 | ||
217 | .long sys_stat64 /* 195 */ | ||
218 | .long sys_lstat64 | ||
219 | .long sys_fstat64 | ||
220 | .long sys_chown | ||
221 | .long sys_getuid | ||
222 | .long sys_getgid /* 200 */ | ||
223 | .long sys_geteuid | ||
224 | .long sys_getegid | ||
225 | .long sys_setreuid | ||
226 | .long sys_setregid | ||
227 | .long sys_getgroups /* 205 */ | ||
228 | .long sys_setgroups | ||
229 | .long sys_fchown | ||
230 | .long sys_setresuid | ||
231 | .long sys_getresuid | ||
232 | .long sys_setresgid /* 210 */ | ||
233 | .long sys_getresgid | ||
234 | .long sys_lchown | ||
235 | .long sys_setuid | ||
236 | .long sys_setgid | ||
237 | .long sys_setfsuid /* 215 */ | ||
238 | .long sys_setfsgid | ||
239 | .long sys_pivot_root | ||
240 | .long sys_ni_syscall | ||
241 | .long sys_ni_syscall | ||
242 | .long sys_getdents64 /* 220 */ | ||
243 | .long sys_gettid | ||
244 | .long sys_tkill | ||
245 | .long sys_setxattr | ||
246 | .long sys_lsetxattr | ||
247 | .long sys_fsetxattr /* 225 */ | ||
248 | .long sys_getxattr | ||
249 | .long sys_lgetxattr | ||
250 | .long sys_fgetxattr | ||
251 | .long sys_listxattr | ||
252 | .long sys_llistxattr /* 230 */ | ||
253 | .long sys_flistxattr | ||
254 | .long sys_removexattr | ||
255 | .long sys_lremovexattr | ||
256 | .long sys_fremovexattr | ||
257 | .long sys_futex /* 235 */ | ||
258 | .long sys_sendfile64 | ||
259 | .long sys_ni_syscall /* sys_mincore */ | ||
260 | .long sys_ni_syscall /* sys_madvise */ | ||
261 | .long sys_fcntl64 | ||
262 | .long sys_readahead /* 240 */ | ||
263 | .long sys_io_setup | ||
264 | .long sys_io_destroy | ||
265 | .long sys_io_getevents | ||
266 | .long sys_io_submit | ||
267 | .long sys_io_cancel /* 245 */ | ||
268 | .long sys_fadvise64 | ||
269 | .long sys_exit_group | ||
270 | .long sys_lookup_dcookie | ||
271 | .long sys_epoll_create | ||
272 | .long sys_epoll_ctl /* 250 */ | ||
273 | .long sys_epoll_wait | ||
274 | .long sys_ni_syscall /* sys_remap_file_pages */ | ||
275 | .long sys_set_tid_address | ||
276 | .long sys_timer_create | ||
277 | .long sys_timer_settime /* 255 */ | ||
278 | .long sys_timer_gettime | ||
279 | .long sys_timer_getoverrun | ||
280 | .long sys_timer_delete | ||
281 | .long sys_clock_settime | ||
282 | .long sys_clock_gettime /* 260 */ | ||
283 | .long sys_clock_getres | ||
284 | .long sys_clock_nanosleep | ||
285 | .long sys_statfs64 | ||
286 | .long sys_fstatfs64 | ||
287 | .long sys_tgkill /* 265 */ | ||
288 | .long sys_utimes | ||
289 | .long sys_fadvise64_64 | ||
290 | .long sys_mbind | ||
291 | .long sys_get_mempolicy | ||
292 | .long sys_set_mempolicy /* 270 */ | ||
293 | .long sys_mq_open | ||
294 | .long sys_mq_unlink | ||
295 | .long sys_mq_timedsend | ||
296 | .long sys_mq_timedreceive | ||
297 | .long sys_mq_notify /* 275 */ | ||
298 | .long sys_mq_getsetattr | ||
299 | .long sys_waitid | ||
300 | .long sys_ni_syscall /* sys_setaltroot */ | ||
301 | .long sys_ni_syscall /* sys_add_key */ | ||
302 | .long sys_ni_syscall /* 280 */ /* sys_request_key */ | ||
303 | .long sys_ni_syscall /* sys_keyctl */ | ||
304 | |||
305 | .rept NR_syscalls-(.-sys_call_table)/4 | ||
306 | .long sys_ni_syscall | ||
307 | .endr | ||
308 | |||
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c new file mode 100644 index 000000000000..5c3ca671627c --- /dev/null +++ b/arch/m68knommu/kernel/time.c | |||
@@ -0,0 +1,198 @@ | |||
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/config.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/param.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/profile.h> | ||
22 | #include <linux/time.h> | ||
23 | #include <linux/timex.h> | ||
24 | |||
25 | #include <asm/machdep.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #define TICK_SIZE (tick_nsec / 1000) | ||
29 | |||
30 | u64 jiffies_64 = INITIAL_JIFFIES; | ||
31 | |||
32 | EXPORT_SYMBOL(jiffies_64); | ||
33 | |||
34 | extern unsigned long wall_jiffies; | ||
35 | |||
36 | |||
37 | static inline int set_rtc_mmss(unsigned long nowtime) | ||
38 | { | ||
39 | if (mach_set_clock_mmss) | ||
40 | return mach_set_clock_mmss (nowtime); | ||
41 | return -1; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * timer_interrupt() needs to keep up the real-time clock, | ||
46 | * as well as call the "do_timer()" routine every clocktick | ||
47 | */ | ||
48 | static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) | ||
49 | { | ||
50 | /* last time the cmos clock got updated */ | ||
51 | static long last_rtc_update=0; | ||
52 | |||
53 | /* may need to kick the hardware timer */ | ||
54 | if (mach_tick) | ||
55 | mach_tick(); | ||
56 | |||
57 | write_seqlock(&xtime_lock); | ||
58 | |||
59 | do_timer(regs); | ||
60 | #ifndef CONFIG_SMP | ||
61 | update_process_times(user_mode(regs)); | ||
62 | #endif | ||
63 | if (current->pid) | ||
64 | profile_tick(CPU_PROFILING, regs); | ||
65 | |||
66 | /* | ||
67 | * If we have an externally synchronized Linux clock, then update | ||
68 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | ||
69 | * called as close as possible to 500 ms before the new second starts. | ||
70 | */ | ||
71 | if ((time_status & STA_UNSYNC) == 0 && | ||
72 | xtime.tv_sec > last_rtc_update + 660 && | ||
73 | (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && | ||
74 | (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { | ||
75 | if (set_rtc_mmss(xtime.tv_sec) == 0) | ||
76 | last_rtc_update = xtime.tv_sec; | ||
77 | else | ||
78 | last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ | ||
79 | } | ||
80 | #ifdef CONFIG_HEARTBEAT | ||
81 | /* use power LED as a heartbeat instead -- much more useful | ||
82 | for debugging -- based on the version for PReP by Cort */ | ||
83 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
84 | if (mach_heartbeat) { | ||
85 | static unsigned cnt = 0, period = 0, dist = 0; | ||
86 | |||
87 | if (cnt == 0 || cnt == dist) | ||
88 | mach_heartbeat( 1 ); | ||
89 | else if (cnt == 7 || cnt == dist+7) | ||
90 | mach_heartbeat( 0 ); | ||
91 | |||
92 | if (++cnt > period) { | ||
93 | cnt = 0; | ||
94 | /* The hyperbolic function below modifies the heartbeat period | ||
95 | * length in dependency of the current (5min) load. It goes | ||
96 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
97 | * f(inf)->30. */ | ||
98 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
99 | dist = period / 4; | ||
100 | } | ||
101 | } | ||
102 | #endif /* CONFIG_HEARTBEAT */ | ||
103 | |||
104 | write_sequnlock(&xtime_lock); | ||
105 | return(IRQ_HANDLED); | ||
106 | } | ||
107 | |||
108 | void time_init(void) | ||
109 | { | ||
110 | unsigned int year, mon, day, hour, min, sec; | ||
111 | |||
112 | extern void arch_gettod(int *year, int *mon, int *day, int *hour, | ||
113 | int *min, int *sec); | ||
114 | |||
115 | arch_gettod(&year, &mon, &day, &hour, &min, &sec); | ||
116 | |||
117 | if ((year += 1900) < 1970) | ||
118 | year += 100; | ||
119 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
120 | xtime.tv_nsec = 0; | ||
121 | wall_to_monotonic.tv_sec = -xtime.tv_sec; | ||
122 | |||
123 | mach_sched_init(timer_interrupt); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * This version of gettimeofday has near microsecond resolution. | ||
128 | */ | ||
129 | void do_gettimeofday(struct timeval *tv) | ||
130 | { | ||
131 | unsigned long flags; | ||
132 | unsigned long lost, seq; | ||
133 | unsigned long usec, sec; | ||
134 | |||
135 | do { | ||
136 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | ||
137 | usec = mach_gettimeoffset ? mach_gettimeoffset() : 0; | ||
138 | lost = jiffies - wall_jiffies; | ||
139 | if (lost) | ||
140 | usec += lost * (1000000 / HZ); | ||
141 | sec = xtime.tv_sec; | ||
142 | usec += (xtime.tv_nsec / 1000); | ||
143 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | ||
144 | |||
145 | while (usec >= 1000000) { | ||
146 | usec -= 1000000; | ||
147 | sec++; | ||
148 | } | ||
149 | |||
150 | tv->tv_sec = sec; | ||
151 | tv->tv_usec = usec; | ||
152 | } | ||
153 | |||
154 | EXPORT_SYMBOL(do_gettimeofday); | ||
155 | |||
156 | int do_settimeofday(struct timespec *tv) | ||
157 | { | ||
158 | time_t wtm_sec, sec = tv->tv_sec; | ||
159 | long wtm_nsec, nsec = tv->tv_nsec; | ||
160 | |||
161 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
162 | return -EINVAL; | ||
163 | |||
164 | write_seqlock_irq(&xtime_lock); | ||
165 | /* | ||
166 | * This is revolting. We need to set the xtime.tv_usec | ||
167 | * correctly. However, the value in this location is | ||
168 | * is value at the last tick. | ||
169 | * Discover what correction gettimeofday | ||
170 | * would have done, and then undo it! | ||
171 | */ | ||
172 | if (mach_gettimeoffset) | ||
173 | nsec -= (mach_gettimeoffset() * 1000); | ||
174 | |||
175 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
176 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
177 | |||
178 | set_normalized_timespec(&xtime, sec, nsec); | ||
179 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
180 | |||
181 | time_adjust = 0; /* stop active adjtime() */ | ||
182 | time_status |= STA_UNSYNC; | ||
183 | time_maxerror = NTP_PHASE_LIMIT; | ||
184 | time_esterror = NTP_PHASE_LIMIT; | ||
185 | write_sequnlock_irq(&xtime_lock); | ||
186 | clock_was_set(); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * Scheduler clock - returns current time in nanosec units. | ||
192 | */ | ||
193 | unsigned long long sched_clock(void) | ||
194 | { | ||
195 | return (unsigned long long)jiffies * (1000000000 / HZ); | ||
196 | } | ||
197 | |||
198 | EXPORT_SYMBOL(do_settimeofday); | ||
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c new file mode 100644 index 000000000000..ad7dc6347f19 --- /dev/null +++ b/arch/m68knommu/kernel/traps.c | |||
@@ -0,0 +1,320 @@ | |||
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/config.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/signal.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/a.out.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 | |||
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 | |||
41 | static char *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 | |||
63 | void __init trap_init(void) | ||
64 | { | ||
65 | if (mach_trap_init) | ||
66 | mach_trap_init(); | ||
67 | } | ||
68 | |||
69 | void die_if_kernel(char *str, struct pt_regs *fp, int nr) | ||
70 | { | ||
71 | if (!(fp->sr & PS_S)) | ||
72 | return; | ||
73 | |||
74 | console_verbose(); | ||
75 | printk(KERN_EMERG "%s: %08x\n",str,nr); | ||
76 | printk(KERN_EMERG "PC: [<%08lx>]\nSR: %04x SP: %p a2: %08lx\n", | ||
77 | fp->pc, fp->sr, fp, fp->a2); | ||
78 | printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | ||
79 | fp->d0, fp->d1, fp->d2, fp->d3); | ||
80 | printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | ||
81 | fp->d4, fp->d5, fp->a0, fp->a1); | ||
82 | |||
83 | printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", | ||
84 | current->comm, current->pid, PAGE_SIZE+(unsigned long)current); | ||
85 | show_stack(NULL, (unsigned long *)fp); | ||
86 | do_exit(SIGSEGV); | ||
87 | } | ||
88 | |||
89 | asmlinkage void buserr_c(struct frame *fp) | ||
90 | { | ||
91 | /* Only set esp0 if coming from user mode */ | ||
92 | if (user_mode(&fp->ptregs)) | ||
93 | current->thread.esp0 = (unsigned long) fp; | ||
94 | |||
95 | #if DEBUG | ||
96 | printk (KERN_DEBUG "*** Bus Error *** Format is %x\n", fp->ptregs.format); | ||
97 | #endif | ||
98 | |||
99 | die_if_kernel("bad frame format",&fp->ptregs,0); | ||
100 | #if DEBUG | ||
101 | printk(KERN_DEBUG "Unknown SIGSEGV - 4\n"); | ||
102 | #endif | ||
103 | force_sig(SIGSEGV, current); | ||
104 | } | ||
105 | |||
106 | |||
107 | int kstack_depth_to_print = 48; | ||
108 | |||
109 | void show_stack(struct task_struct *task, unsigned long *esp) | ||
110 | { | ||
111 | unsigned long *stack, *endstack, addr; | ||
112 | extern char _start, _etext; | ||
113 | int i; | ||
114 | |||
115 | if (esp == NULL) | ||
116 | esp = (unsigned long *) &esp; | ||
117 | |||
118 | stack = esp; | ||
119 | addr = (unsigned long) esp; | ||
120 | endstack = (unsigned long *) PAGE_ALIGN(addr); | ||
121 | |||
122 | printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack); | ||
123 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
124 | if (stack + 1 > endstack) | ||
125 | break; | ||
126 | if (i % 8 == 0) | ||
127 | printk(KERN_EMERG "\n "); | ||
128 | printk(KERN_EMERG " %08lx", *stack++); | ||
129 | } | ||
130 | |||
131 | printk(KERN_EMERG "\nCall Trace:"); | ||
132 | i = 0; | ||
133 | while (stack + 1 <= endstack) { | ||
134 | addr = *stack++; | ||
135 | /* | ||
136 | * If the address is either in the text segment of the | ||
137 | * kernel, or in the region which contains vmalloc'ed | ||
138 | * memory, it *may* be the address of a calling | ||
139 | * routine; if so, print it so that someone tracing | ||
140 | * down the cause of the crash will be able to figure | ||
141 | * out the call path that was taken. | ||
142 | */ | ||
143 | if (((addr >= (unsigned long) &_start) && | ||
144 | (addr <= (unsigned long) &_etext))) { | ||
145 | if (i % 4 == 0) | ||
146 | printk(KERN_EMERG "\n "); | ||
147 | printk(KERN_EMERG " [<%08lx>]", addr); | ||
148 | i++; | ||
149 | } | ||
150 | } | ||
151 | printk(KERN_EMERG "\n"); | ||
152 | } | ||
153 | |||
154 | void bad_super_trap(struct frame *fp) | ||
155 | { | ||
156 | console_verbose(); | ||
157 | if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) | ||
158 | printk (KERN_WARNING "*** %s *** FORMAT=%X\n", | ||
159 | vec_names[(fp->ptregs.vector) >> 2], | ||
160 | fp->ptregs.format); | ||
161 | else | ||
162 | printk (KERN_WARNING "*** Exception %d *** FORMAT=%X\n", | ||
163 | (fp->ptregs.vector) >> 2, | ||
164 | fp->ptregs.format); | ||
165 | printk (KERN_WARNING "Current process id is %d\n", current->pid); | ||
166 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | ||
167 | } | ||
168 | |||
169 | asmlinkage void trap_c(struct frame *fp) | ||
170 | { | ||
171 | int sig; | ||
172 | siginfo_t info; | ||
173 | |||
174 | if (fp->ptregs.sr & PS_S) { | ||
175 | if ((fp->ptregs.vector >> 2) == VEC_TRACE) { | ||
176 | /* traced a trapping instruction */ | ||
177 | current->ptrace |= PT_DTRACE; | ||
178 | } else | ||
179 | bad_super_trap(fp); | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | /* send the appropriate signal to the user program */ | ||
184 | switch ((fp->ptregs.vector) >> 2) { | ||
185 | case VEC_ADDRERR: | ||
186 | info.si_code = BUS_ADRALN; | ||
187 | sig = SIGBUS; | ||
188 | break; | ||
189 | case VEC_ILLEGAL: | ||
190 | case VEC_LINE10: | ||
191 | case VEC_LINE11: | ||
192 | info.si_code = ILL_ILLOPC; | ||
193 | sig = SIGILL; | ||
194 | break; | ||
195 | case VEC_PRIV: | ||
196 | info.si_code = ILL_PRVOPC; | ||
197 | sig = SIGILL; | ||
198 | break; | ||
199 | case VEC_COPROC: | ||
200 | info.si_code = ILL_COPROC; | ||
201 | sig = SIGILL; | ||
202 | break; | ||
203 | case VEC_TRAP1: /* gdbserver breakpoint */ | ||
204 | fp->ptregs.pc -= 2; | ||
205 | info.si_code = TRAP_TRACE; | ||
206 | sig = SIGTRAP; | ||
207 | break; | ||
208 | case VEC_TRAP2: | ||
209 | case VEC_TRAP3: | ||
210 | case VEC_TRAP4: | ||
211 | case VEC_TRAP5: | ||
212 | case VEC_TRAP6: | ||
213 | case VEC_TRAP7: | ||
214 | case VEC_TRAP8: | ||
215 | case VEC_TRAP9: | ||
216 | case VEC_TRAP10: | ||
217 | case VEC_TRAP11: | ||
218 | case VEC_TRAP12: | ||
219 | case VEC_TRAP13: | ||
220 | case VEC_TRAP14: | ||
221 | info.si_code = ILL_ILLTRP; | ||
222 | sig = SIGILL; | ||
223 | break; | ||
224 | case VEC_FPBRUC: | ||
225 | case VEC_FPOE: | ||
226 | case VEC_FPNAN: | ||
227 | info.si_code = FPE_FLTINV; | ||
228 | sig = SIGFPE; | ||
229 | break; | ||
230 | case VEC_FPIR: | ||
231 | info.si_code = FPE_FLTRES; | ||
232 | sig = SIGFPE; | ||
233 | break; | ||
234 | case VEC_FPDIVZ: | ||
235 | info.si_code = FPE_FLTDIV; | ||
236 | sig = SIGFPE; | ||
237 | break; | ||
238 | case VEC_FPUNDER: | ||
239 | info.si_code = FPE_FLTUND; | ||
240 | sig = SIGFPE; | ||
241 | break; | ||
242 | case VEC_FPOVER: | ||
243 | info.si_code = FPE_FLTOVF; | ||
244 | sig = SIGFPE; | ||
245 | break; | ||
246 | case VEC_ZERODIV: | ||
247 | info.si_code = FPE_INTDIV; | ||
248 | sig = SIGFPE; | ||
249 | break; | ||
250 | case VEC_CHK: | ||
251 | case VEC_TRAP: | ||
252 | info.si_code = FPE_INTOVF; | ||
253 | sig = SIGFPE; | ||
254 | break; | ||
255 | case VEC_TRACE: /* ptrace single step */ | ||
256 | info.si_code = TRAP_TRACE; | ||
257 | sig = SIGTRAP; | ||
258 | break; | ||
259 | case VEC_TRAP15: /* breakpoint */ | ||
260 | info.si_code = TRAP_BRKPT; | ||
261 | sig = SIGTRAP; | ||
262 | break; | ||
263 | default: | ||
264 | info.si_code = ILL_ILLOPC; | ||
265 | sig = SIGILL; | ||
266 | break; | ||
267 | } | ||
268 | info.si_signo = sig; | ||
269 | info.si_errno = 0; | ||
270 | switch (fp->ptregs.format) { | ||
271 | default: | ||
272 | info.si_addr = (void *) fp->ptregs.pc; | ||
273 | break; | ||
274 | case 2: | ||
275 | info.si_addr = (void *) fp->un.fmt2.iaddr; | ||
276 | break; | ||
277 | case 7: | ||
278 | info.si_addr = (void *) fp->un.fmt7.effaddr; | ||
279 | break; | ||
280 | case 9: | ||
281 | info.si_addr = (void *) fp->un.fmt9.iaddr; | ||
282 | break; | ||
283 | case 10: | ||
284 | info.si_addr = (void *) fp->un.fmta.daddr; | ||
285 | break; | ||
286 | case 11: | ||
287 | info.si_addr = (void *) fp->un.fmtb.daddr; | ||
288 | break; | ||
289 | } | ||
290 | force_sig_info (sig, &info, current); | ||
291 | } | ||
292 | |||
293 | asmlinkage void set_esp0(unsigned long ssp) | ||
294 | { | ||
295 | current->thread.esp0 = ssp; | ||
296 | } | ||
297 | |||
298 | |||
299 | /* | ||
300 | * The architecture-independent backtrace generator | ||
301 | */ | ||
302 | void dump_stack(void) | ||
303 | { | ||
304 | unsigned long stack; | ||
305 | |||
306 | show_stack(current, &stack); | ||
307 | } | ||
308 | |||
309 | #ifdef CONFIG_M68KFPU_EMU | ||
310 | asmlinkage void fpemu_signal(int signal, int code, void *addr) | ||
311 | { | ||
312 | siginfo_t info; | ||
313 | |||
314 | info.si_signo = signal; | ||
315 | info.si_errno = 0; | ||
316 | info.si_code = code; | ||
317 | info.si_addr = addr; | ||
318 | force_sig_info(signal, &info, current); | ||
319 | } | ||
320 | #endif | ||
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..31cb12892da5 --- /dev/null +++ b/arch/m68knommu/kernel/vmlinux.lds.S | |||
@@ -0,0 +1,348 @@ | |||
1 | /* | ||
2 | * vmlinux.lds.S -- master linker script for m68knommu arch | ||
3 | * | ||
4 | * (C) Copyright 2002-2004, Greg Ungerer <gerg@snapgear.com> | ||
5 | * | ||
6 | * This ends up looking compilcated, because of the number of | ||
7 | * address variations for ram and rom/flash layouts. The real | ||
8 | * work of the linker script is all at the end, and reasonably | ||
9 | * strait forward. | ||
10 | */ | ||
11 | |||
12 | #include <linux/config.h> | ||
13 | #include <asm-generic/vmlinux.lds.h> | ||
14 | |||
15 | /* | ||
16 | * Original Palm pilot (same for Xcopilot). | ||
17 | * There is really only a rom target for this. | ||
18 | */ | ||
19 | #ifdef CONFIG_PILOT3 | ||
20 | #define ROMVEC_START 0x10c00000 | ||
21 | #define ROMVEC_LENGTH 0x10400 | ||
22 | #define ROM_START 0x10c10400 | ||
23 | #define ROM_LENGTH 0xfec00 | ||
24 | #define ROM_END 0x10d00000 | ||
25 | #define RAMVEC_START 0x00000000 | ||
26 | #define RAMVEC_LENGTH 0x400 | ||
27 | #define RAM_START 0x10000400 | ||
28 | #define RAM_LENGTH 0xffc00 | ||
29 | #define RAM_END 0x10100000 | ||
30 | #define _ramend _ram_end_notused | ||
31 | #define DATA_ADDR RAM_START | ||
32 | #endif | ||
33 | |||
34 | /* | ||
35 | * Same setup on both the uCsimm and uCdimm. | ||
36 | */ | ||
37 | #if defined(CONFIG_UCSIMM) || defined(CONFIG_UCDIMM) | ||
38 | #ifdef CONFIG_RAMKERNEL | ||
39 | #define ROMVEC_START 0x10c10000 | ||
40 | #define ROMVEC_LENGTH 0x400 | ||
41 | #define ROM_START 0x10c10400 | ||
42 | #define ROM_LENGTH 0x1efc00 | ||
43 | #define ROM_END 0x10e00000 | ||
44 | #define RAMVEC_START 0x00000000 | ||
45 | #define RAMVEC_LENGTH 0x400 | ||
46 | #define RAM_START 0x00020400 | ||
47 | #define RAM_LENGTH 0x7dfc00 | ||
48 | #define RAM_END 0x00800000 | ||
49 | #endif | ||
50 | #ifdef CONFIG_ROMKERNEL | ||
51 | #define ROMVEC_START 0x10c10000 | ||
52 | #define ROMVEC_LENGTH 0x400 | ||
53 | #define ROM_START 0x10c10400 | ||
54 | #define ROM_LENGTH 0x1efc00 | ||
55 | #define ROM_END 0x10e00000 | ||
56 | #define RAMVEC_START 0x00000000 | ||
57 | #define RAMVEC_LENGTH 0x400 | ||
58 | #define RAM_START 0x00020000 | ||
59 | #define RAM_LENGTH 0x600000 | ||
60 | #define RAM_END 0x00800000 | ||
61 | #endif | ||
62 | #ifdef CONFIG_HIMEMKERNEL | ||
63 | #define ROMVEC_START 0x00600000 | ||
64 | #define ROMVEC_LENGTH 0x400 | ||
65 | #define ROM_START 0x00600400 | ||
66 | #define ROM_LENGTH 0x1efc00 | ||
67 | #define ROM_END 0x007f0000 | ||
68 | #define RAMVEC_START 0x00000000 | ||
69 | #define RAMVEC_LENGTH 0x400 | ||
70 | #define RAM_START 0x00020000 | ||
71 | #define RAM_LENGTH 0x5e0000 | ||
72 | #define RAM_END 0x00600000 | ||
73 | #endif | ||
74 | #endif | ||
75 | |||
76 | #ifdef CONFIG_DRAGEN2 | ||
77 | #define RAM_START 0x10000 | ||
78 | #define RAM_LENGTH 0x7f0000 | ||
79 | #endif | ||
80 | |||
81 | #ifdef CONFIG_UCQUICC | ||
82 | #define ROMVEC_START 0x00000000 | ||
83 | #define ROMVEC_LENGTH 0x404 | ||
84 | #define ROM_START 0x00000404 | ||
85 | #define ROM_LENGTH 0x1ff6fc | ||
86 | #define ROM_END 0x00200000 | ||
87 | #define RAMVEC_START 0x00200000 | ||
88 | #define RAMVEC_LENGTH 0x404 | ||
89 | #define RAM_START 0x00200404 | ||
90 | #define RAM_LENGTH 0x1ff6fc | ||
91 | #define RAM_END 0x00400000 | ||
92 | #endif | ||
93 | |||
94 | /* | ||
95 | * The standard Arnewsh 5206 board only has 1MiB of ram. Not normally | ||
96 | * enough to be useful. Assume the user has fitted something larger, | ||
97 | * at least 4MiB in size. No point in not letting the kernel completely | ||
98 | * link, it will be obvious if it is too big when they go to load it. | ||
99 | */ | ||
100 | #if defined(CONFIG_ARN5206) | ||
101 | #define RAM_START 0x10000 | ||
102 | #define RAM_LENGTH 0x3f0000 | ||
103 | #endif | ||
104 | |||
105 | /* | ||
106 | * The Motorola 5206eLITE board only has 1MiB of static RAM. | ||
107 | */ | ||
108 | #if defined(CONFIG_ELITE) | ||
109 | #define RAM_START 0x30020000 | ||
110 | #define RAM_END 0xe0000 | ||
111 | #endif | ||
112 | |||
113 | /* | ||
114 | * All the Motorola eval boards have the same basic arrangement. | ||
115 | * The end of RAM will vary depending on how much ram is fitted, | ||
116 | * but this isn't important here, we assume at least 4MiB. | ||
117 | */ | ||
118 | #if defined(CONFIG_M5206eC3) || defined(CONFIG_M5249C3) || \ | ||
119 | defined(CONFIG_M5272C3) || defined(CONFIG_M5307C3) || \ | ||
120 | defined(CONFIG_ARN5307) || defined(CONFIG_M5407C3) || \ | ||
121 | defined(CONFIG_M5271EVB) || defined(CONFIG_M5275EVB) | ||
122 | #define RAM_START 0x20000 | ||
123 | #define RAM_LENGTH 0x3e0000 | ||
124 | #endif | ||
125 | |||
126 | /* | ||
127 | * The senTec COBRA5272 board has nearly the same memory layout as | ||
128 | * the M5272C3. We assume 16MiB ram. | ||
129 | */ | ||
130 | #if defined(CONFIG_COBRA5272) | ||
131 | #define RAM_START 0x20000 | ||
132 | #define RAM_LENGTH 0xfe0000 | ||
133 | #endif | ||
134 | |||
135 | #if defined(CONFIG_M5282EVB) | ||
136 | #define RAM_START 0x10000 | ||
137 | #define RAM_LENGTH 0x3f0000 | ||
138 | #endif | ||
139 | |||
140 | /* | ||
141 | * The senTec COBRA5282 board has the same memory layout as the M5282EVB. | ||
142 | */ | ||
143 | #if defined(CONFIG_COBRA5282) | ||
144 | #define RAM_START 0x10000 | ||
145 | #define RAM_LENGTH 0x3f0000 | ||
146 | #endif | ||
147 | |||
148 | /* | ||
149 | * These flash boot boards use all of ram for operation. Again the | ||
150 | * actual memory size is not important here, assume at least 4MiB. | ||
151 | * They currently have no support for running in flash. | ||
152 | */ | ||
153 | #if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \ | ||
154 | defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \ | ||
155 | defined(CONFIG_HW_FEITH) | ||
156 | #define RAM_START 0x400 | ||
157 | #define RAM_LENGTH 0x3ffc00 | ||
158 | #endif | ||
159 | |||
160 | /* | ||
161 | * Sneha Boards mimimun memmory | ||
162 | * The end of RAM will vary depending on how much ram is fitted, | ||
163 | * but this isn't important here, we assume at least 4MiB. | ||
164 | */ | ||
165 | #if defined(CONFIG_CPU16B) | ||
166 | #define RAM_START 0x20000 | ||
167 | #define RAM_LENGTH 0x3e0000 | ||
168 | #endif | ||
169 | |||
170 | |||
171 | #if defined(CONFIG_RAMKERNEL) | ||
172 | #define TEXT ram | ||
173 | #define DATA ram | ||
174 | #define INIT ram | ||
175 | #define BSS ram | ||
176 | #endif | ||
177 | #if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL) | ||
178 | #define TEXT rom | ||
179 | #define DATA ram | ||
180 | #define INIT ram | ||
181 | #define BSS ram | ||
182 | #endif | ||
183 | |||
184 | #ifndef DATA_ADDR | ||
185 | #define DATA_ADDR | ||
186 | #endif | ||
187 | |||
188 | |||
189 | OUTPUT_ARCH(m68k) | ||
190 | ENTRY(_start) | ||
191 | |||
192 | MEMORY { | ||
193 | #ifdef RAMVEC_START | ||
194 | ramvec : ORIGIN = RAMVEC_START, LENGTH = RAMVEC_LENGTH | ||
195 | #endif | ||
196 | ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH | ||
197 | #ifdef RAM_END | ||
198 | eram : ORIGIN = RAM_END, LENGTH = 0 | ||
199 | #endif | ||
200 | #ifdef ROM_START | ||
201 | romvec : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH | ||
202 | rom : ORIGIN = ROM_START, LENGTH = ROM_LENGTH | ||
203 | erom : ORIGIN = ROM_END, LENGTH = 0 | ||
204 | #endif | ||
205 | } | ||
206 | |||
207 | jiffies = jiffies_64 + 4; | ||
208 | |||
209 | SECTIONS { | ||
210 | |||
211 | #ifdef ROMVEC_START | ||
212 | . = ROMVEC_START ; | ||
213 | .romvec : { | ||
214 | __rom_start = . ; | ||
215 | _romvec = .; | ||
216 | *(.data.initvect) | ||
217 | } > romvec | ||
218 | #endif | ||
219 | |||
220 | .text : { | ||
221 | _stext = . ; | ||
222 | *(.text) | ||
223 | SCHED_TEXT | ||
224 | *(.text.lock) | ||
225 | |||
226 | . = ALIGN(16); /* Exception table */ | ||
227 | __start___ex_table = .; | ||
228 | *(__ex_table) | ||
229 | __stop___ex_table = .; | ||
230 | |||
231 | *(.rodata) *(.rodata.*) | ||
232 | *(__vermagic) /* Kernel version magic */ | ||
233 | *(.rodata1) | ||
234 | *(.rodata.str1.1) | ||
235 | |||
236 | /* Kernel symbol table: Normal symbols */ | ||
237 | . = ALIGN(4); | ||
238 | __start___ksymtab = .; | ||
239 | *(__ksymtab) | ||
240 | __stop___ksymtab = .; | ||
241 | |||
242 | /* Kernel symbol table: GPL-only symbols */ | ||
243 | __start___ksymtab_gpl = .; | ||
244 | *(__ksymtab_gpl) | ||
245 | __stop___ksymtab_gpl = .; | ||
246 | |||
247 | /* Kernel symbol table: Normal symbols */ | ||
248 | __start___kcrctab = .; | ||
249 | *(__kcrctab) | ||
250 | __stop___kcrctab = .; | ||
251 | |||
252 | /* Kernel symbol table: GPL-only symbols */ | ||
253 | __start___kcrctab_gpl = .; | ||
254 | *(__kcrctab_gpl) | ||
255 | __stop___kcrctab_gpl = .; | ||
256 | |||
257 | /* Kernel symbol table: strings */ | ||
258 | *(__ksymtab_strings) | ||
259 | |||
260 | /* Built-in module parameters */ | ||
261 | __start___param = .; | ||
262 | *(__param) | ||
263 | __stop___param = .; | ||
264 | |||
265 | . = ALIGN(4) ; | ||
266 | _etext = . ; | ||
267 | } > TEXT | ||
268 | |||
269 | #ifdef ROM_END | ||
270 | . = ROM_END ; | ||
271 | .erom : { | ||
272 | __rom_end = . ; | ||
273 | } > erom | ||
274 | #endif | ||
275 | #ifdef RAMVEC_START | ||
276 | . = RAMVEC_START ; | ||
277 | .ramvec : { | ||
278 | __ramvec = .; | ||
279 | } > ramvec | ||
280 | #endif | ||
281 | |||
282 | .data DATA_ADDR : { | ||
283 | . = ALIGN(4); | ||
284 | _sdata = . ; | ||
285 | *(.data) | ||
286 | . = ALIGN(8192) ; | ||
287 | *(.data.init_task) | ||
288 | _edata = . ; | ||
289 | } > DATA | ||
290 | |||
291 | .init : { | ||
292 | . = ALIGN(4096); | ||
293 | __init_begin = .; | ||
294 | _sinittext = .; | ||
295 | *(.init.text) | ||
296 | _einittext = .; | ||
297 | *(.init.data) | ||
298 | . = ALIGN(16); | ||
299 | __setup_start = .; | ||
300 | *(.init.setup) | ||
301 | __setup_end = .; | ||
302 | __initcall_start = .; | ||
303 | *(.initcall1.init) | ||
304 | *(.initcall2.init) | ||
305 | *(.initcall3.init) | ||
306 | *(.initcall4.init) | ||
307 | *(.initcall5.init) | ||
308 | *(.initcall6.init) | ||
309 | *(.initcall7.init) | ||
310 | __initcall_end = .; | ||
311 | __con_initcall_start = .; | ||
312 | *(.con_initcall.init) | ||
313 | __con_initcall_end = .; | ||
314 | __security_initcall_start = .; | ||
315 | *(.security_initcall.init) | ||
316 | __security_initcall_end = .; | ||
317 | . = ALIGN(4); | ||
318 | __initramfs_start = .; | ||
319 | *(.init.ramfs) | ||
320 | __initramfs_end = .; | ||
321 | . = ALIGN(4096); | ||
322 | __init_end = .; | ||
323 | } > INIT | ||
324 | |||
325 | /DISCARD/ : { | ||
326 | *(.exit.text) | ||
327 | *(.exit.data) | ||
328 | *(.exitcall.exit) | ||
329 | } | ||
330 | |||
331 | .bss : { | ||
332 | . = ALIGN(4); | ||
333 | _sbss = . ; | ||
334 | *(.bss) | ||
335 | *(COMMON) | ||
336 | . = ALIGN(4) ; | ||
337 | _ebss = . ; | ||
338 | } > BSS | ||
339 | |||
340 | #ifdef RAM_END | ||
341 | . = RAM_END ; | ||
342 | .eram : { | ||
343 | __ramend = . ; | ||
344 | _ramend = . ; | ||
345 | } > eram | ||
346 | #endif | ||
347 | } | ||
348 | |||