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/m68k/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/m68k/kernel')
-rw-r--r-- | arch/m68k/kernel/Makefile | 18 | ||||
-rw-r--r-- | arch/m68k/kernel/asm-offsets.c | 109 | ||||
-rw-r--r-- | arch/m68k/kernel/bios32.c | 515 | ||||
-rw-r--r-- | arch/m68k/kernel/entry.S | 712 | ||||
-rw-r--r-- | arch/m68k/kernel/head.S | 3940 | ||||
-rw-r--r-- | arch/m68k/kernel/ints.c | 281 | ||||
-rw-r--r-- | arch/m68k/kernel/m68k_ksyms.c | 88 | ||||
-rw-r--r-- | arch/m68k/kernel/module.c | 128 | ||||
-rw-r--r-- | arch/m68k/kernel/process.c | 405 | ||||
-rw-r--r-- | arch/m68k/kernel/ptrace.c | 393 | ||||
-rw-r--r-- | arch/m68k/kernel/semaphore.c | 133 | ||||
-rw-r--r-- | arch/m68k/kernel/setup.c | 545 | ||||
-rw-r--r-- | arch/m68k/kernel/signal.c | 1025 | ||||
-rw-r--r-- | arch/m68k/kernel/sun3-head.S | 104 | ||||
-rw-r--r-- | arch/m68k/kernel/sys_m68k.c | 671 | ||||
-rw-r--r-- | arch/m68k/kernel/time.c | 187 | ||||
-rw-r--r-- | arch/m68k/kernel/traps.c | 1227 | ||||
-rw-r--r-- | arch/m68k/kernel/vmlinux-std.lds | 95 | ||||
-rw-r--r-- | arch/m68k/kernel/vmlinux-sun3.lds | 95 | ||||
-rw-r--r-- | arch/m68k/kernel/vmlinux.lds.S | 11 |
20 files changed, 10682 insertions, 0 deletions
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile new file mode 100644 index 000000000000..458925c471a1 --- /dev/null +++ b/arch/m68k/kernel/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | # | ||
2 | # Makefile for the linux kernel. | ||
3 | # | ||
4 | |||
5 | ifndef CONFIG_SUN3 | ||
6 | extra-y := head.o | ||
7 | else | ||
8 | extra-y := sun3-head.o | ||
9 | endif | ||
10 | extra-y += vmlinux.lds | ||
11 | |||
12 | obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \ | ||
13 | sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o | ||
14 | |||
15 | obj-$(CONFIG_PCI) += bios32.o | ||
16 | obj-$(CONFIG_MODULES) += module.o | ||
17 | |||
18 | EXTRA_AFLAGS := -traditional | ||
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c new file mode 100644 index 000000000000..cee3317b8665 --- /dev/null +++ b/arch/m68k/kernel/asm-offsets.c | |||
@@ -0,0 +1,109 @@ | |||
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 <asm/bootinfo.h> | ||
15 | #include <asm/irq.h> | ||
16 | #include <asm/amigahw.h> | ||
17 | #include <linux/font.h> | ||
18 | |||
19 | #define DEFINE(sym, val) \ | ||
20 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
21 | |||
22 | int main(void) | ||
23 | { | ||
24 | /* offsets into the task struct */ | ||
25 | DEFINE(TASK_STATE, offsetof(struct task_struct, state)); | ||
26 | DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags)); | ||
27 | DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace)); | ||
28 | DEFINE(TASK_WORK, offsetof(struct task_struct, thread.work)); | ||
29 | DEFINE(TASK_NEEDRESCHED, offsetof(struct task_struct, thread.work.need_resched)); | ||
30 | DEFINE(TASK_SYSCALL_TRACE, offsetof(struct task_struct, thread.work.syscall_trace)); | ||
31 | DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, thread.work.sigpending)); | ||
32 | DEFINE(TASK_NOTIFY_RESUME, offsetof(struct task_struct, thread.work.notify_resume)); | ||
33 | DEFINE(TASK_THREAD, offsetof(struct task_struct, thread)); | ||
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 thread struct */ | ||
38 | DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp)); | ||
39 | DEFINE(THREAD_USP, offsetof(struct thread_struct, usp)); | ||
40 | DEFINE(THREAD_SR, offsetof(struct thread_struct, sr)); | ||
41 | DEFINE(THREAD_FS, offsetof(struct thread_struct, fs)); | ||
42 | DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp)); | ||
43 | DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0)); | ||
44 | DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp)); | ||
45 | DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl)); | ||
46 | DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate)); | ||
47 | |||
48 | /* offsets into the pt_regs */ | ||
49 | DEFINE(PT_D0, offsetof(struct pt_regs, d0)); | ||
50 | DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0)); | ||
51 | DEFINE(PT_D1, offsetof(struct pt_regs, d1)); | ||
52 | DEFINE(PT_D2, offsetof(struct pt_regs, d2)); | ||
53 | DEFINE(PT_D3, offsetof(struct pt_regs, d3)); | ||
54 | DEFINE(PT_D4, offsetof(struct pt_regs, d4)); | ||
55 | DEFINE(PT_D5, offsetof(struct pt_regs, d5)); | ||
56 | DEFINE(PT_A0, offsetof(struct pt_regs, a0)); | ||
57 | DEFINE(PT_A1, offsetof(struct pt_regs, a1)); | ||
58 | DEFINE(PT_A2, offsetof(struct pt_regs, a2)); | ||
59 | DEFINE(PT_PC, offsetof(struct pt_regs, pc)); | ||
60 | DEFINE(PT_SR, offsetof(struct pt_regs, sr)); | ||
61 | /* bitfields are a bit difficult */ | ||
62 | DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4); | ||
63 | |||
64 | /* offsets into the irq_handler struct */ | ||
65 | DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler)); | ||
66 | DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id)); | ||
67 | DEFINE(IRQ_NEXT, offsetof(struct irq_node, next)); | ||
68 | |||
69 | /* offsets into the kernel_stat struct */ | ||
70 | DEFINE(STAT_IRQ, offsetof(struct kernel_stat, irqs)); | ||
71 | |||
72 | /* offsets into the irq_cpustat_t struct */ | ||
73 | DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending)); | ||
74 | |||
75 | /* offsets into the bi_record struct */ | ||
76 | DEFINE(BIR_TAG, offsetof(struct bi_record, tag)); | ||
77 | DEFINE(BIR_SIZE, offsetof(struct bi_record, size)); | ||
78 | DEFINE(BIR_DATA, offsetof(struct bi_record, data)); | ||
79 | |||
80 | /* offsets into font_desc (drivers/video/console/font.h) */ | ||
81 | DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx)); | ||
82 | DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name)); | ||
83 | DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width)); | ||
84 | DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height)); | ||
85 | DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data)); | ||
86 | DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref)); | ||
87 | |||
88 | /* signal defines */ | ||
89 | DEFINE(SIGSEGV, SIGSEGV); | ||
90 | DEFINE(SEGV_MAPERR, SEGV_MAPERR); | ||
91 | DEFINE(SIGTRAP, SIGTRAP); | ||
92 | DEFINE(TRAP_TRACE, TRAP_TRACE); | ||
93 | |||
94 | /* offsets into the custom struct */ | ||
95 | DEFINE(CUSTOMBASE, &custom); | ||
96 | DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar)); | ||
97 | DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr)); | ||
98 | DEFINE(C_INTENA, offsetof(struct CUSTOM, intena)); | ||
99 | DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq)); | ||
100 | DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr)); | ||
101 | DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat)); | ||
102 | DEFINE(C_SERPER, offsetof(struct CUSTOM, serper)); | ||
103 | DEFINE(CIAABASE, &ciaa); | ||
104 | DEFINE(CIABBASE, &ciab); | ||
105 | DEFINE(C_PRA, offsetof(struct CIA, pra)); | ||
106 | DEFINE(ZTWOBASE, zTwoBase); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c new file mode 100644 index 000000000000..a901685eb6a9 --- /dev/null +++ b/arch/m68k/kernel/bios32.c | |||
@@ -0,0 +1,515 @@ | |||
1 | /* | ||
2 | * bios32.c - PCI BIOS functions for m68k systems. | ||
3 | * | ||
4 | * Written by Wout Klaren. | ||
5 | * | ||
6 | * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger. | ||
7 | */ | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/kernel.h> | ||
12 | |||
13 | #if 0 | ||
14 | # define DBG_DEVS(args) printk args | ||
15 | #else | ||
16 | # define DBG_DEVS(args) | ||
17 | #endif | ||
18 | |||
19 | #ifdef CONFIG_PCI | ||
20 | |||
21 | /* | ||
22 | * PCI support for Linux/m68k. Currently only the Hades is supported. | ||
23 | * | ||
24 | * The support for PCI bridges in the DEC Alpha version has | ||
25 | * been removed in this version. | ||
26 | */ | ||
27 | |||
28 | #include <linux/pci.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/mm.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | #include <asm/pci.h> | ||
34 | #include <asm/uaccess.h> | ||
35 | |||
36 | #define KB 1024 | ||
37 | #define MB (1024*KB) | ||
38 | #define GB (1024*MB) | ||
39 | |||
40 | #define MAJOR_REV 0 | ||
41 | #define MINOR_REV 5 | ||
42 | |||
43 | /* | ||
44 | * Align VAL to ALIGN, which must be a power of two. | ||
45 | */ | ||
46 | |||
47 | #define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1)) | ||
48 | |||
49 | /* | ||
50 | * Offsets relative to the I/O and memory base addresses from where resources | ||
51 | * are allocated. | ||
52 | */ | ||
53 | |||
54 | #define IO_ALLOC_OFFSET 0x00004000 | ||
55 | #define MEM_ALLOC_OFFSET 0x04000000 | ||
56 | |||
57 | /* | ||
58 | * Declarations of hardware specific initialisation functions. | ||
59 | */ | ||
60 | |||
61 | extern struct pci_bus_info *init_hades_pci(void); | ||
62 | |||
63 | /* | ||
64 | * Bus info structure of the PCI bus. A pointer to this structure is | ||
65 | * put in the sysdata member of the pci_bus structure. | ||
66 | */ | ||
67 | |||
68 | static struct pci_bus_info *bus_info; | ||
69 | |||
70 | static int pci_modify = 1; /* If set, layout the PCI bus ourself. */ | ||
71 | static int skip_vga; /* If set do not modify base addresses | ||
72 | of vga cards.*/ | ||
73 | static int disable_pci_burst; /* If set do not allow PCI bursts. */ | ||
74 | |||
75 | static unsigned int io_base; | ||
76 | static unsigned int mem_base; | ||
77 | |||
78 | /* | ||
79 | * static void disable_dev(struct pci_dev *dev) | ||
80 | * | ||
81 | * Disable PCI device DEV so that it does not respond to I/O or memory | ||
82 | * accesses. | ||
83 | * | ||
84 | * Parameters: | ||
85 | * | ||
86 | * dev - device to disable. | ||
87 | */ | ||
88 | |||
89 | static void __init disable_dev(struct pci_dev *dev) | ||
90 | { | ||
91 | unsigned short cmd; | ||
92 | |||
93 | if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) || | ||
94 | (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) || | ||
95 | (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga) | ||
96 | return; | ||
97 | |||
98 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
99 | |||
100 | cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER); | ||
101 | pci_write_config_word(dev, PCI_COMMAND, cmd); | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * static void layout_dev(struct pci_dev *dev) | ||
106 | * | ||
107 | * Layout memory and I/O for a device. | ||
108 | * | ||
109 | * Parameters: | ||
110 | * | ||
111 | * device - device to layout memory and I/O for. | ||
112 | */ | ||
113 | |||
114 | static void __init layout_dev(struct pci_dev *dev) | ||
115 | { | ||
116 | unsigned short cmd; | ||
117 | unsigned int base, mask, size, reg; | ||
118 | unsigned int alignto; | ||
119 | int i; | ||
120 | |||
121 | /* | ||
122 | * Skip video cards if requested. | ||
123 | */ | ||
124 | |||
125 | if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) || | ||
126 | (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) || | ||
127 | (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga) | ||
128 | return; | ||
129 | |||
130 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||
131 | |||
132 | for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++) | ||
133 | { | ||
134 | /* | ||
135 | * Figure out how much space and of what type this | ||
136 | * device wants. | ||
137 | */ | ||
138 | |||
139 | pci_write_config_dword(dev, reg, 0xffffffff); | ||
140 | pci_read_config_dword(dev, reg, &base); | ||
141 | |||
142 | if (!base) | ||
143 | { | ||
144 | /* this base-address register is unused */ | ||
145 | dev->resource[i].start = 0; | ||
146 | dev->resource[i].end = 0; | ||
147 | dev->resource[i].flags = 0; | ||
148 | continue; | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * We've read the base address register back after | ||
153 | * writing all ones and so now we must decode it. | ||
154 | */ | ||
155 | |||
156 | if (base & PCI_BASE_ADDRESS_SPACE_IO) | ||
157 | { | ||
158 | /* | ||
159 | * I/O space base address register. | ||
160 | */ | ||
161 | |||
162 | cmd |= PCI_COMMAND_IO; | ||
163 | |||
164 | base &= PCI_BASE_ADDRESS_IO_MASK; | ||
165 | mask = (~base << 1) | 0x1; | ||
166 | size = (mask & base) & 0xffffffff; | ||
167 | |||
168 | /* | ||
169 | * Align to multiple of size of minimum base. | ||
170 | */ | ||
171 | |||
172 | alignto = max_t(unsigned int, 0x040, size); | ||
173 | base = ALIGN(io_base, alignto); | ||
174 | io_base = base + size; | ||
175 | pci_write_config_dword(dev, reg, base | PCI_BASE_ADDRESS_SPACE_IO); | ||
176 | |||
177 | dev->resource[i].start = base; | ||
178 | dev->resource[i].end = dev->resource[i].start + size - 1; | ||
179 | dev->resource[i].flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; | ||
180 | |||
181 | DBG_DEVS(("layout_dev: IO address: %lX\n", base)); | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | unsigned int type; | ||
186 | |||
187 | /* | ||
188 | * Memory space base address register. | ||
189 | */ | ||
190 | |||
191 | cmd |= PCI_COMMAND_MEMORY; | ||
192 | type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK; | ||
193 | base &= PCI_BASE_ADDRESS_MEM_MASK; | ||
194 | mask = (~base << 1) | 0x1; | ||
195 | size = (mask & base) & 0xffffffff; | ||
196 | switch (type) | ||
197 | { | ||
198 | case PCI_BASE_ADDRESS_MEM_TYPE_32: | ||
199 | case PCI_BASE_ADDRESS_MEM_TYPE_64: | ||
200 | break; | ||
201 | |||
202 | case PCI_BASE_ADDRESS_MEM_TYPE_1M: | ||
203 | printk("bios32 WARNING: slot %d, function %d " | ||
204 | "requests memory below 1MB---don't " | ||
205 | "know how to do that.\n", | ||
206 | PCI_SLOT(dev->devfn), | ||
207 | PCI_FUNC(dev->devfn)); | ||
208 | continue; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Align to multiple of size of minimum base. | ||
213 | */ | ||
214 | |||
215 | alignto = max_t(unsigned int, 0x1000, size); | ||
216 | base = ALIGN(mem_base, alignto); | ||
217 | mem_base = base + size; | ||
218 | pci_write_config_dword(dev, reg, base); | ||
219 | |||
220 | dev->resource[i].start = base; | ||
221 | dev->resource[i].end = dev->resource[i].start + size - 1; | ||
222 | dev->resource[i].flags = IORESOURCE_MEM; | ||
223 | |||
224 | if (type == PCI_BASE_ADDRESS_MEM_TYPE_64) | ||
225 | { | ||
226 | /* | ||
227 | * 64-bit address, set the highest 32 bits | ||
228 | * to zero. | ||
229 | */ | ||
230 | |||
231 | reg += 4; | ||
232 | pci_write_config_dword(dev, reg, 0); | ||
233 | |||
234 | i++; | ||
235 | dev->resource[i].start = 0; | ||
236 | dev->resource[i].end = 0; | ||
237 | dev->resource[i].flags = 0; | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * Enable device: | ||
244 | */ | ||
245 | |||
246 | if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED || | ||
247 | dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA || | ||
248 | dev->class >> 8 == PCI_CLASS_DISPLAY_VGA || | ||
249 | dev->class >> 8 == PCI_CLASS_DISPLAY_XGA) | ||
250 | { | ||
251 | /* | ||
252 | * All of these (may) have I/O scattered all around | ||
253 | * and may not use i/o-base address registers at all. | ||
254 | * So we just have to always enable I/O to these | ||
255 | * devices. | ||
256 | */ | ||
257 | cmd |= PCI_COMMAND_IO; | ||
258 | } | ||
259 | |||
260 | pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER); | ||
261 | |||
262 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, (disable_pci_burst) ? 0 : 32); | ||
263 | |||
264 | if (bus_info != NULL) | ||
265 | bus_info->conf_device(dev); /* Machine dependent configuration. */ | ||
266 | |||
267 | DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n", | ||
268 | dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class)); | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * static void layout_bus(struct pci_bus *bus) | ||
273 | * | ||
274 | * Layout memory and I/O for all devices on the given bus. | ||
275 | * | ||
276 | * Parameters: | ||
277 | * | ||
278 | * bus - bus. | ||
279 | */ | ||
280 | |||
281 | static void __init layout_bus(struct pci_bus *bus) | ||
282 | { | ||
283 | unsigned int bio, bmem; | ||
284 | struct pci_dev *dev; | ||
285 | |||
286 | DBG_DEVS(("layout_bus: starting bus %d\n", bus->number)); | ||
287 | |||
288 | if (!bus->devices && !bus->children) | ||
289 | return; | ||
290 | |||
291 | /* | ||
292 | * Align the current bases on appropriate boundaries (4K for | ||
293 | * IO and 1MB for memory). | ||
294 | */ | ||
295 | |||
296 | bio = io_base = ALIGN(io_base, 4*KB); | ||
297 | bmem = mem_base = ALIGN(mem_base, 1*MB); | ||
298 | |||
299 | /* | ||
300 | * PCI devices might have been setup by a PCI BIOS emulation | ||
301 | * running under TOS. In these cases there is a | ||
302 | * window during which two devices may have an overlapping | ||
303 | * address range. To avoid this causing trouble, we first | ||
304 | * turn off the I/O and memory address decoders for all PCI | ||
305 | * devices. They'll be re-enabled only once all address | ||
306 | * decoders are programmed consistently. | ||
307 | */ | ||
308 | |||
309 | DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number)); | ||
310 | |||
311 | for (dev = bus->devices; dev; dev = dev->sibling) | ||
312 | { | ||
313 | if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || | ||
314 | (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) | ||
315 | disable_dev(dev); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Allocate space to each device: | ||
320 | */ | ||
321 | |||
322 | DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number)); | ||
323 | |||
324 | for (dev = bus->devices; dev; dev = dev->sibling) | ||
325 | { | ||
326 | if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) || | ||
327 | (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA)) | ||
328 | layout_dev(dev); | ||
329 | } | ||
330 | |||
331 | DBG_DEVS(("layout_bus: bus %d finished\n", bus->number)); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * static void pcibios_fixup(void) | ||
336 | * | ||
337 | * Layout memory and I/O of all devices on the PCI bus if 'pci_modify' is | ||
338 | * true. This might be necessary because not every m68k machine with a PCI | ||
339 | * bus has a PCI BIOS. This function should be called right after | ||
340 | * pci_scan_bus() in pcibios_init(). | ||
341 | */ | ||
342 | |||
343 | static void __init pcibios_fixup(void) | ||
344 | { | ||
345 | if (pci_modify) | ||
346 | { | ||
347 | /* | ||
348 | * Set base addresses for allocation of I/O and memory space. | ||
349 | */ | ||
350 | |||
351 | io_base = bus_info->io_space.start + IO_ALLOC_OFFSET; | ||
352 | mem_base = bus_info->mem_space.start + MEM_ALLOC_OFFSET; | ||
353 | |||
354 | /* | ||
355 | * Scan the tree, allocating PCI memory and I/O space. | ||
356 | */ | ||
357 | |||
358 | layout_bus(pci_bus_b(pci_root.next)); | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * Fix interrupt assignments, etc. | ||
363 | */ | ||
364 | |||
365 | bus_info->fixup(pci_modify); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * static void pcibios_claim_resources(struct pci_bus *bus) | ||
370 | * | ||
371 | * Claim all resources that are assigned to devices on the given bus. | ||
372 | * | ||
373 | * Parameters: | ||
374 | * | ||
375 | * bus - bus. | ||
376 | */ | ||
377 | |||
378 | static void __init pcibios_claim_resources(struct pci_bus *bus) | ||
379 | { | ||
380 | struct pci_dev *dev; | ||
381 | int i; | ||
382 | |||
383 | while (bus) | ||
384 | { | ||
385 | for (dev = bus->devices; (dev != NULL); dev = dev->sibling) | ||
386 | { | ||
387 | for (i = 0; i < PCI_NUM_RESOURCES; i++) | ||
388 | { | ||
389 | struct resource *r = &dev->resource[i]; | ||
390 | struct resource *pr; | ||
391 | struct pci_bus_info *bus_info = (struct pci_bus_info *) dev->sysdata; | ||
392 | |||
393 | if ((r->start == 0) || (r->parent != NULL)) | ||
394 | continue; | ||
395 | #if 1 | ||
396 | if (r->flags & IORESOURCE_IO) | ||
397 | pr = &bus_info->io_space; | ||
398 | else | ||
399 | pr = &bus_info->mem_space; | ||
400 | #else | ||
401 | if (r->flags & IORESOURCE_IO) | ||
402 | pr = &ioport_resource; | ||
403 | else | ||
404 | pr = &iomem_resource; | ||
405 | #endif | ||
406 | if (request_resource(pr, r) < 0) | ||
407 | { | ||
408 | printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", i, dev->name); | ||
409 | } | ||
410 | } | ||
411 | } | ||
412 | |||
413 | if (bus->children) | ||
414 | pcibios_claim_resources(bus->children); | ||
415 | |||
416 | bus = bus->next; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * int pcibios_assign_resource(struct pci_dev *dev, int i) | ||
422 | * | ||
423 | * Assign a new address to a PCI resource. | ||
424 | * | ||
425 | * Parameters: | ||
426 | * | ||
427 | * dev - device. | ||
428 | * i - resource. | ||
429 | * | ||
430 | * Result: 0 if successful. | ||
431 | */ | ||
432 | |||
433 | int __init pcibios_assign_resource(struct pci_dev *dev, int i) | ||
434 | { | ||
435 | struct resource *r = &dev->resource[i]; | ||
436 | struct resource *pr = pci_find_parent_resource(dev, r); | ||
437 | unsigned long size = r->end + 1; | ||
438 | |||
439 | if (!pr) | ||
440 | return -EINVAL; | ||
441 | |||
442 | if (r->flags & IORESOURCE_IO) | ||
443 | { | ||
444 | if (size > 0x100) | ||
445 | return -EFBIG; | ||
446 | |||
447 | if (allocate_resource(pr, r, size, bus_info->io_space.start + | ||
448 | IO_ALLOC_OFFSET, bus_info->io_space.end, 1024)) | ||
449 | return -EBUSY; | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | if (allocate_resource(pr, r, size, bus_info->mem_space.start + | ||
454 | MEM_ALLOC_OFFSET, bus_info->mem_space.end, size)) | ||
455 | return -EBUSY; | ||
456 | } | ||
457 | |||
458 | if (i < 6) | ||
459 | pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, r->start); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | void __init pcibios_fixup_bus(struct pci_bus *bus) | ||
465 | { | ||
466 | struct pci_dev *dev; | ||
467 | void *sysdata; | ||
468 | |||
469 | sysdata = (bus->parent) ? bus->parent->sysdata : bus->sysdata; | ||
470 | |||
471 | for (dev = bus->devices; (dev != NULL); dev = dev->sibling) | ||
472 | dev->sysdata = sysdata; | ||
473 | } | ||
474 | |||
475 | void __init pcibios_init(void) | ||
476 | { | ||
477 | printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV); | ||
478 | |||
479 | bus_info = NULL; | ||
480 | #ifdef CONFIG_HADES | ||
481 | if (MACH_IS_HADES) | ||
482 | bus_info = init_hades_pci(); | ||
483 | #endif | ||
484 | if (bus_info != NULL) | ||
485 | { | ||
486 | printk("PCI: Probing PCI hardware\n"); | ||
487 | pci_scan_bus(0, bus_info->m68k_pci_ops, bus_info); | ||
488 | pcibios_fixup(); | ||
489 | pcibios_claim_resources(pci_root); | ||
490 | } | ||
491 | else | ||
492 | printk("PCI: No PCI bus detected\n"); | ||
493 | } | ||
494 | |||
495 | char * __init pcibios_setup(char *str) | ||
496 | { | ||
497 | if (!strcmp(str, "nomodify")) | ||
498 | { | ||
499 | pci_modify = 0; | ||
500 | return NULL; | ||
501 | } | ||
502 | else if (!strcmp(str, "skipvga")) | ||
503 | { | ||
504 | skip_vga = 1; | ||
505 | return NULL; | ||
506 | } | ||
507 | else if (!strcmp(str, "noburst")) | ||
508 | { | ||
509 | disable_pci_burst = 1; | ||
510 | return NULL; | ||
511 | } | ||
512 | |||
513 | return str; | ||
514 | } | ||
515 | #endif /* CONFIG_PCI */ | ||
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S new file mode 100644 index 000000000000..e964015a31dc --- /dev/null +++ b/arch/m68k/kernel/entry.S | |||
@@ -0,0 +1,712 @@ | |||
1 | /* -*- mode: asm -*- | ||
2 | * | ||
3 | * linux/arch/m68k/kernel/entry.S | ||
4 | * | ||
5 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file README.legal in the main directory of this archive | ||
9 | * for more details. | ||
10 | * | ||
11 | * Linux/m68k support by Hamish Macdonald | ||
12 | * | ||
13 | * 68060 fixes by Jesper Skov | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * entry.S contains the system-call and fault low-level handling routines. | ||
19 | * This also contains the timer-interrupt handler, as well as all interrupts | ||
20 | * and faults that can result in a task-switch. | ||
21 | * | ||
22 | * NOTE: This code handles signal-recognition, which happens every time | ||
23 | * after a timer-interrupt and after each system call. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | /* | ||
28 | * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so | ||
29 | * all pointers that used to be 'current' are now entry | ||
30 | * number 0 in the 'current_set' list. | ||
31 | * | ||
32 | * 6/05/00 RZ: addedd writeback completion after return from sighandler | ||
33 | * for 68040 | ||
34 | */ | ||
35 | |||
36 | #include <linux/config.h> | ||
37 | #include <linux/linkage.h> | ||
38 | #include <asm/entry.h> | ||
39 | #include <asm/errno.h> | ||
40 | #include <asm/setup.h> | ||
41 | #include <asm/segment.h> | ||
42 | #include <asm/traps.h> | ||
43 | #include <asm/unistd.h> | ||
44 | |||
45 | #include <asm/offsets.h> | ||
46 | |||
47 | .globl system_call, buserr, trap | ||
48 | .globl resume, ret_from_exception | ||
49 | .globl ret_from_signal | ||
50 | .globl inthandler, sys_call_table | ||
51 | .globl sys_fork, sys_clone, sys_vfork | ||
52 | .globl ret_from_interrupt, bad_interrupt | ||
53 | |||
54 | .text | ||
55 | ENTRY(buserr) | ||
56 | SAVE_ALL_INT | ||
57 | GET_CURRENT(%d0) | ||
58 | movel %sp,%sp@- | stack frame pointer argument | ||
59 | bsrl buserr_c | ||
60 | addql #4,%sp | ||
61 | jra ret_from_exception | ||
62 | |||
63 | ENTRY(trap) | ||
64 | SAVE_ALL_INT | ||
65 | GET_CURRENT(%d0) | ||
66 | movel %sp,%sp@- | stack frame pointer argument | ||
67 | bsrl trap_c | ||
68 | addql #4,%sp | ||
69 | jra ret_from_exception | ||
70 | |||
71 | | After a fork we jump here directly from resume, | ||
72 | | so that %d1 contains the previous task | ||
73 | | schedule_tail now used regardless of CONFIG_SMP | ||
74 | ENTRY(ret_from_fork) | ||
75 | movel %d1,%sp@- | ||
76 | jsr schedule_tail | ||
77 | addql #4,%sp | ||
78 | jra ret_from_exception | ||
79 | |||
80 | badsys: | ||
81 | movel #-ENOSYS,%sp@(PT_D0) | ||
82 | jra ret_from_exception | ||
83 | |||
84 | do_trace: | ||
85 | movel #-ENOSYS,%sp@(PT_D0) | needed for strace | ||
86 | subql #4,%sp | ||
87 | SAVE_SWITCH_STACK | ||
88 | jbsr syscall_trace | ||
89 | RESTORE_SWITCH_STACK | ||
90 | addql #4,%sp | ||
91 | movel %sp@(PT_ORIG_D0),%d1 | ||
92 | movel #-ENOSYS,%d0 | ||
93 | cmpl #NR_syscalls,%d1 | ||
94 | jcc 1f | ||
95 | jbsr @(sys_call_table,%d1:l:4)@(0) | ||
96 | 1: movel %d0,%sp@(PT_D0) | save the return value | ||
97 | subql #4,%sp | dummy return address | ||
98 | SAVE_SWITCH_STACK | ||
99 | jbsr syscall_trace | ||
100 | |||
101 | ret_from_signal: | ||
102 | RESTORE_SWITCH_STACK | ||
103 | addql #4,%sp | ||
104 | /* on 68040 complete pending writebacks if any */ | ||
105 | #ifdef CONFIG_M68040 | ||
106 | bfextu %sp@(PT_VECTOR){#0,#4},%d0 | ||
107 | subql #7,%d0 | bus error frame ? | ||
108 | jbne 1f | ||
109 | movel %sp,%sp@- | ||
110 | jbsr berr_040cleanup | ||
111 | addql #4,%sp | ||
112 | 1: | ||
113 | #endif | ||
114 | jra ret_from_exception | ||
115 | |||
116 | ENTRY(system_call) | ||
117 | SAVE_ALL_SYS | ||
118 | |||
119 | GET_CURRENT(%d1) | ||
120 | | save top of frame | ||
121 | movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) | ||
122 | |||
123 | tstb %curptr@(TASK_SYSCALL_TRACE) | ||
124 | jne do_trace | ||
125 | cmpl #NR_syscalls,%d0 | ||
126 | jcc badsys | ||
127 | jbsr @(sys_call_table,%d0:l:4)@(0) | ||
128 | movel %d0,%sp@(PT_D0) | save the return value | ||
129 | |||
130 | |oriw #0x0700,%sr | ||
131 | movel %curptr@(TASK_WORK),%d0 | ||
132 | jne syscall_exit_work | ||
133 | 1: RESTORE_ALL | ||
134 | |||
135 | syscall_exit_work: | ||
136 | btst #5,%sp@(PT_SR) | check if returning to kernel | ||
137 | bnes 1b | if so, skip resched, signals | ||
138 | tstw %d0 | ||
139 | jeq do_signal_return | ||
140 | tstb %d0 | ||
141 | jne do_delayed_trace | ||
142 | |||
143 | pea resume_userspace | ||
144 | jmp schedule | ||
145 | |||
146 | ret_from_exception: | ||
147 | btst #5,%sp@(PT_SR) | check if returning to kernel | ||
148 | bnes 1f | if so, skip resched, signals | ||
149 | | only allow interrupts when we are really the last one on the | ||
150 | | kernel stack, otherwise stack overflow can occur during | ||
151 | | heavy interrupt load | ||
152 | andw #ALLOWINT,%sr | ||
153 | |||
154 | resume_userspace: | ||
155 | movel %curptr@(TASK_WORK),%d0 | ||
156 | lsrl #8,%d0 | ||
157 | jne exit_work | ||
158 | 1: RESTORE_ALL | ||
159 | |||
160 | exit_work: | ||
161 | | save top of frame | ||
162 | movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) | ||
163 | tstb %d0 | ||
164 | jeq do_signal_return | ||
165 | |||
166 | pea resume_userspace | ||
167 | jmp schedule | ||
168 | |||
169 | do_signal_return: | ||
170 | |andw #ALLOWINT,%sr | ||
171 | subql #4,%sp | dummy return address | ||
172 | SAVE_SWITCH_STACK | ||
173 | pea %sp@(SWITCH_STACK_SIZE) | ||
174 | clrl %sp@- | ||
175 | bsrl do_signal | ||
176 | addql #8,%sp | ||
177 | RESTORE_SWITCH_STACK | ||
178 | addql #4,%sp | ||
179 | jbra resume_userspace | ||
180 | |||
181 | do_delayed_trace: | ||
182 | bclr #7,%sp@(PT_SR) | clear trace bit in SR | ||
183 | pea 1 | send SIGTRAP | ||
184 | movel %curptr,%sp@- | ||
185 | pea LSIGTRAP | ||
186 | jbsr send_sig | ||
187 | addql #8,%sp | ||
188 | addql #4,%sp | ||
189 | jbra resume_userspace | ||
190 | |||
191 | |||
192 | #if 0 | ||
193 | #ifdef CONFIG_AMIGA | ||
194 | ami_inthandler: | ||
195 | addql #1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT | ||
196 | SAVE_ALL_INT | ||
197 | GET_CURRENT(%d0) | ||
198 | |||
199 | bfextu %sp@(PT_VECTOR){#4,#12},%d0 | ||
200 | movel %d0,%a0 | ||
201 | addql #1,%a0@(kstat+STAT_IRQ-VECOFF(VEC_SPUR)) | ||
202 | movel %a0@(autoirq_list-VECOFF(VEC_SPUR)),%a0 | ||
203 | |||
204 | | amiga vector int handler get the req mask instead of irq vector | ||
205 | lea CUSTOMBASE,%a1 | ||
206 | movew %a1@(C_INTREQR),%d0 | ||
207 | andw %a1@(C_INTENAR),%d0 | ||
208 | |||
209 | | prepare stack (push frame pointer, dev_id & req mask) | ||
210 | pea %sp@ | ||
211 | movel %a0@(IRQ_DEVID),%sp@- | ||
212 | movel %d0,%sp@- | ||
213 | pea %pc@(ret_from_interrupt:w) | ||
214 | jbra @(IRQ_HANDLER,%a0)@(0) | ||
215 | |||
216 | ENTRY(nmi_handler) | ||
217 | rte | ||
218 | #endif | ||
219 | #endif | ||
220 | |||
221 | /* | ||
222 | ** This is the main interrupt handler, responsible for calling process_int() | ||
223 | */ | ||
224 | inthandler: | ||
225 | SAVE_ALL_INT | ||
226 | GET_CURRENT(%d0) | ||
227 | addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2) | ||
228 | | put exception # in d0 | ||
229 | bfextu %sp@(PT_VECTOR){#4,#10},%d0 | ||
230 | |||
231 | movel %sp,%sp@- | ||
232 | movel %d0,%sp@- | put vector # on stack | ||
233 | #if defined(MACH_Q40_ONLY) && defined(CONFIG_BLK_DEV_FD) | ||
234 | btstb #4,0xff000000 | Q40 floppy needs very special treatment ... | ||
235 | jbeq 1f | ||
236 | btstb #3,0xff000004 | ||
237 | jbeq 1f | ||
238 | jbsr floppy_hardint | ||
239 | jbra 3f | ||
240 | 1: | ||
241 | #endif | ||
242 | jbsr process_int | process the IRQ | ||
243 | 3: addql #8,%sp | pop parameters off stack | ||
244 | |||
245 | ret_from_interrupt: | ||
246 | subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+2) | ||
247 | jeq 1f | ||
248 | 2: | ||
249 | RESTORE_ALL | ||
250 | 1: | ||
251 | moveq #(~ALLOWINT>>8)&0xff,%d0 | ||
252 | andb %sp@(PT_SR),%d0 | ||
253 | jne 2b | ||
254 | |||
255 | /* check if we need to do software interrupts */ | ||
256 | tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING | ||
257 | jeq ret_from_exception | ||
258 | pea ret_from_exception | ||
259 | jra do_softirq | ||
260 | |||
261 | |||
262 | /* Handler for uninitialized and spurious interrupts */ | ||
263 | |||
264 | bad_interrupt: | ||
265 | addql #1,num_spurious | ||
266 | rte | ||
267 | |||
268 | ENTRY(sys_fork) | ||
269 | SAVE_SWITCH_STACK | ||
270 | pea %sp@(SWITCH_STACK_SIZE) | ||
271 | jbsr m68k_fork | ||
272 | addql #4,%sp | ||
273 | RESTORE_SWITCH_STACK | ||
274 | rts | ||
275 | |||
276 | ENTRY(sys_clone) | ||
277 | SAVE_SWITCH_STACK | ||
278 | pea %sp@(SWITCH_STACK_SIZE) | ||
279 | jbsr m68k_clone | ||
280 | addql #4,%sp | ||
281 | RESTORE_SWITCH_STACK | ||
282 | rts | ||
283 | |||
284 | ENTRY(sys_vfork) | ||
285 | SAVE_SWITCH_STACK | ||
286 | pea %sp@(SWITCH_STACK_SIZE) | ||
287 | jbsr m68k_vfork | ||
288 | addql #4,%sp | ||
289 | RESTORE_SWITCH_STACK | ||
290 | rts | ||
291 | |||
292 | ENTRY(sys_sigsuspend) | ||
293 | SAVE_SWITCH_STACK | ||
294 | pea %sp@(SWITCH_STACK_SIZE) | ||
295 | jbsr do_sigsuspend | ||
296 | addql #4,%sp | ||
297 | RESTORE_SWITCH_STACK | ||
298 | rts | ||
299 | |||
300 | ENTRY(sys_rt_sigsuspend) | ||
301 | SAVE_SWITCH_STACK | ||
302 | pea %sp@(SWITCH_STACK_SIZE) | ||
303 | jbsr do_rt_sigsuspend | ||
304 | addql #4,%sp | ||
305 | RESTORE_SWITCH_STACK | ||
306 | rts | ||
307 | |||
308 | ENTRY(sys_sigreturn) | ||
309 | SAVE_SWITCH_STACK | ||
310 | jbsr do_sigreturn | ||
311 | RESTORE_SWITCH_STACK | ||
312 | rts | ||
313 | |||
314 | ENTRY(sys_rt_sigreturn) | ||
315 | SAVE_SWITCH_STACK | ||
316 | jbsr do_rt_sigreturn | ||
317 | RESTORE_SWITCH_STACK | ||
318 | rts | ||
319 | |||
320 | resume: | ||
321 | /* | ||
322 | * Beware - when entering resume, prev (the current task) is | ||
323 | * in a0, next (the new task) is in a1,so don't change these | ||
324 | * registers until their contents are no longer needed. | ||
325 | */ | ||
326 | |||
327 | /* save sr */ | ||
328 | movew %sr,%a0@(TASK_THREAD+THREAD_SR) | ||
329 | |||
330 | /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ | ||
331 | movec %sfc,%d0 | ||
332 | movew %d0,%a0@(TASK_THREAD+THREAD_FS) | ||
333 | |||
334 | /* save usp */ | ||
335 | /* it is better to use a movel here instead of a movew 8*) */ | ||
336 | movec %usp,%d0 | ||
337 | movel %d0,%a0@(TASK_THREAD+THREAD_USP) | ||
338 | |||
339 | /* save non-scratch registers on stack */ | ||
340 | SAVE_SWITCH_STACK | ||
341 | |||
342 | /* save current kernel stack pointer */ | ||
343 | movel %sp,%a0@(TASK_THREAD+THREAD_KSP) | ||
344 | |||
345 | /* save floating point context */ | ||
346 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
347 | #ifdef CONFIG_M68KFPU_EMU | ||
348 | tstl m68k_fputype | ||
349 | jeq 3f | ||
350 | #endif | ||
351 | fsave %a0@(TASK_THREAD+THREAD_FPSTATE) | ||
352 | |||
353 | #if defined(CONFIG_M68060) | ||
354 | #if !defined(CPU_M68060_ONLY) | ||
355 | btst #3,m68k_cputype+3 | ||
356 | beqs 1f | ||
357 | #endif | ||
358 | /* The 060 FPU keeps status in bits 15-8 of the first longword */ | ||
359 | tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2) | ||
360 | jeq 3f | ||
361 | #if !defined(CPU_M68060_ONLY) | ||
362 | jra 2f | ||
363 | #endif | ||
364 | #endif /* CONFIG_M68060 */ | ||
365 | #if !defined(CPU_M68060_ONLY) | ||
366 | 1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE) | ||
367 | jeq 3f | ||
368 | #endif | ||
369 | 2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG) | ||
370 | fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL) | ||
371 | 3: | ||
372 | #endif /* CONFIG_M68KFPU_EMU_ONLY */ | ||
373 | /* Return previous task in %d1 */ | ||
374 | movel %curptr,%d1 | ||
375 | |||
376 | /* switch to new task (a1 contains new task) */ | ||
377 | movel %a1,%curptr | ||
378 | |||
379 | /* restore floating point context */ | ||
380 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
381 | #ifdef CONFIG_M68KFPU_EMU | ||
382 | tstl m68k_fputype | ||
383 | jeq 4f | ||
384 | #endif | ||
385 | #if defined(CONFIG_M68060) | ||
386 | #if !defined(CPU_M68060_ONLY) | ||
387 | btst #3,m68k_cputype+3 | ||
388 | beqs 1f | ||
389 | #endif | ||
390 | /* The 060 FPU keeps status in bits 15-8 of the first longword */ | ||
391 | tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2) | ||
392 | jeq 3f | ||
393 | #if !defined(CPU_M68060_ONLY) | ||
394 | jra 2f | ||
395 | #endif | ||
396 | #endif /* CONFIG_M68060 */ | ||
397 | #if !defined(CPU_M68060_ONLY) | ||
398 | 1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE) | ||
399 | jeq 3f | ||
400 | #endif | ||
401 | 2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7 | ||
402 | fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar | ||
403 | 3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE) | ||
404 | 4: | ||
405 | #endif /* CONFIG_M68KFPU_EMU_ONLY */ | ||
406 | |||
407 | /* restore the kernel stack pointer */ | ||
408 | movel %a1@(TASK_THREAD+THREAD_KSP),%sp | ||
409 | |||
410 | /* restore non-scratch registers */ | ||
411 | RESTORE_SWITCH_STACK | ||
412 | |||
413 | /* restore user stack pointer */ | ||
414 | movel %a1@(TASK_THREAD+THREAD_USP),%a0 | ||
415 | movel %a0,%usp | ||
416 | |||
417 | /* restore fs (sfc,%dfc) */ | ||
418 | movew %a1@(TASK_THREAD+THREAD_FS),%a0 | ||
419 | movec %a0,%sfc | ||
420 | movec %a0,%dfc | ||
421 | |||
422 | /* restore status register */ | ||
423 | movew %a1@(TASK_THREAD+THREAD_SR),%sr | ||
424 | |||
425 | rts | ||
426 | |||
427 | .data | ||
428 | ALIGN | ||
429 | sys_call_table: | ||
430 | .long sys_ni_syscall /* 0 - old "setup()" system call*/ | ||
431 | .long sys_exit | ||
432 | .long sys_fork | ||
433 | .long sys_read | ||
434 | .long sys_write | ||
435 | .long sys_open /* 5 */ | ||
436 | .long sys_close | ||
437 | .long sys_waitpid | ||
438 | .long sys_creat | ||
439 | .long sys_link | ||
440 | .long sys_unlink /* 10 */ | ||
441 | .long sys_execve | ||
442 | .long sys_chdir | ||
443 | .long sys_time | ||
444 | .long sys_mknod | ||
445 | .long sys_chmod /* 15 */ | ||
446 | .long sys_chown16 | ||
447 | .long sys_ni_syscall /* old break syscall holder */ | ||
448 | .long sys_stat | ||
449 | .long sys_lseek | ||
450 | .long sys_getpid /* 20 */ | ||
451 | .long sys_mount | ||
452 | .long sys_oldumount | ||
453 | .long sys_setuid16 | ||
454 | .long sys_getuid16 | ||
455 | .long sys_stime /* 25 */ | ||
456 | .long sys_ptrace | ||
457 | .long sys_alarm | ||
458 | .long sys_fstat | ||
459 | .long sys_pause | ||
460 | .long sys_utime /* 30 */ | ||
461 | .long sys_ni_syscall /* old stty syscall holder */ | ||
462 | .long sys_ni_syscall /* old gtty syscall holder */ | ||
463 | .long sys_access | ||
464 | .long sys_nice | ||
465 | .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */ | ||
466 | .long sys_sync | ||
467 | .long sys_kill | ||
468 | .long sys_rename | ||
469 | .long sys_mkdir | ||
470 | .long sys_rmdir /* 40 */ | ||
471 | .long sys_dup | ||
472 | .long sys_pipe | ||
473 | .long sys_times | ||
474 | .long sys_ni_syscall /* old prof syscall holder */ | ||
475 | .long sys_brk /* 45 */ | ||
476 | .long sys_setgid16 | ||
477 | .long sys_getgid16 | ||
478 | .long sys_signal | ||
479 | .long sys_geteuid16 | ||
480 | .long sys_getegid16 /* 50 */ | ||
481 | .long sys_acct | ||
482 | .long sys_umount /* recycled never used phys() */ | ||
483 | .long sys_ni_syscall /* old lock syscall holder */ | ||
484 | .long sys_ioctl | ||
485 | .long sys_fcntl /* 55 */ | ||
486 | .long sys_ni_syscall /* old mpx syscall holder */ | ||
487 | .long sys_setpgid | ||
488 | .long sys_ni_syscall /* old ulimit syscall holder */ | ||
489 | .long sys_ni_syscall | ||
490 | .long sys_umask /* 60 */ | ||
491 | .long sys_chroot | ||
492 | .long sys_ustat | ||
493 | .long sys_dup2 | ||
494 | .long sys_getppid | ||
495 | .long sys_getpgrp /* 65 */ | ||
496 | .long sys_setsid | ||
497 | .long sys_sigaction | ||
498 | .long sys_sgetmask | ||
499 | .long sys_ssetmask | ||
500 | .long sys_setreuid16 /* 70 */ | ||
501 | .long sys_setregid16 | ||
502 | .long sys_sigsuspend | ||
503 | .long sys_sigpending | ||
504 | .long sys_sethostname | ||
505 | .long sys_setrlimit /* 75 */ | ||
506 | .long sys_old_getrlimit | ||
507 | .long sys_getrusage | ||
508 | .long sys_gettimeofday | ||
509 | .long sys_settimeofday | ||
510 | .long sys_getgroups16 /* 80 */ | ||
511 | .long sys_setgroups16 | ||
512 | .long old_select | ||
513 | .long sys_symlink | ||
514 | .long sys_lstat | ||
515 | .long sys_readlink /* 85 */ | ||
516 | .long sys_uselib | ||
517 | .long sys_swapon | ||
518 | .long sys_reboot | ||
519 | .long old_readdir | ||
520 | .long old_mmap /* 90 */ | ||
521 | .long sys_munmap | ||
522 | .long sys_truncate | ||
523 | .long sys_ftruncate | ||
524 | .long sys_fchmod | ||
525 | .long sys_fchown16 /* 95 */ | ||
526 | .long sys_getpriority | ||
527 | .long sys_setpriority | ||
528 | .long sys_ni_syscall /* old profil syscall holder */ | ||
529 | .long sys_statfs | ||
530 | .long sys_fstatfs /* 100 */ | ||
531 | .long sys_ni_syscall /* ioperm for i386 */ | ||
532 | .long sys_socketcall | ||
533 | .long sys_syslog | ||
534 | .long sys_setitimer | ||
535 | .long sys_getitimer /* 105 */ | ||
536 | .long sys_newstat | ||
537 | .long sys_newlstat | ||
538 | .long sys_newfstat | ||
539 | .long sys_ni_syscall | ||
540 | .long sys_ni_syscall /* 110 */ /* iopl for i386 */ | ||
541 | .long sys_vhangup | ||
542 | .long sys_ni_syscall /* obsolete idle() syscall */ | ||
543 | .long sys_ni_syscall /* vm86old for i386 */ | ||
544 | .long sys_wait4 | ||
545 | .long sys_swapoff /* 115 */ | ||
546 | .long sys_sysinfo | ||
547 | .long sys_ipc | ||
548 | .long sys_fsync | ||
549 | .long sys_sigreturn | ||
550 | .long sys_clone /* 120 */ | ||
551 | .long sys_setdomainname | ||
552 | .long sys_newuname | ||
553 | .long sys_cacheflush /* modify_ldt for i386 */ | ||
554 | .long sys_adjtimex | ||
555 | .long sys_mprotect /* 125 */ | ||
556 | .long sys_sigprocmask | ||
557 | .long sys_ni_syscall /* old "create_module" */ | ||
558 | .long sys_init_module | ||
559 | .long sys_delete_module | ||
560 | .long sys_ni_syscall /* 130 - old "get_kernel_syms" */ | ||
561 | .long sys_quotactl | ||
562 | .long sys_getpgid | ||
563 | .long sys_fchdir | ||
564 | .long sys_bdflush | ||
565 | .long sys_sysfs /* 135 */ | ||
566 | .long sys_personality | ||
567 | .long sys_ni_syscall /* for afs_syscall */ | ||
568 | .long sys_setfsuid16 | ||
569 | .long sys_setfsgid16 | ||
570 | .long sys_llseek /* 140 */ | ||
571 | .long sys_getdents | ||
572 | .long sys_select | ||
573 | .long sys_flock | ||
574 | .long sys_msync | ||
575 | .long sys_readv /* 145 */ | ||
576 | .long sys_writev | ||
577 | .long sys_getsid | ||
578 | .long sys_fdatasync | ||
579 | .long sys_sysctl | ||
580 | .long sys_mlock /* 150 */ | ||
581 | .long sys_munlock | ||
582 | .long sys_mlockall | ||
583 | .long sys_munlockall | ||
584 | .long sys_sched_setparam | ||
585 | .long sys_sched_getparam /* 155 */ | ||
586 | .long sys_sched_setscheduler | ||
587 | .long sys_sched_getscheduler | ||
588 | .long sys_sched_yield | ||
589 | .long sys_sched_get_priority_max | ||
590 | .long sys_sched_get_priority_min /* 160 */ | ||
591 | .long sys_sched_rr_get_interval | ||
592 | .long sys_nanosleep | ||
593 | .long sys_mremap | ||
594 | .long sys_setresuid16 | ||
595 | .long sys_getresuid16 /* 165 */ | ||
596 | .long sys_getpagesize | ||
597 | .long sys_ni_syscall /* old sys_query_module */ | ||
598 | .long sys_poll | ||
599 | .long sys_nfsservctl | ||
600 | .long sys_setresgid16 /* 170 */ | ||
601 | .long sys_getresgid16 | ||
602 | .long sys_prctl | ||
603 | .long sys_rt_sigreturn | ||
604 | .long sys_rt_sigaction | ||
605 | .long sys_rt_sigprocmask /* 175 */ | ||
606 | .long sys_rt_sigpending | ||
607 | .long sys_rt_sigtimedwait | ||
608 | .long sys_rt_sigqueueinfo | ||
609 | .long sys_rt_sigsuspend | ||
610 | .long sys_pread64 /* 180 */ | ||
611 | .long sys_pwrite64 | ||
612 | .long sys_lchown16; | ||
613 | .long sys_getcwd | ||
614 | .long sys_capget | ||
615 | .long sys_capset /* 185 */ | ||
616 | .long sys_sigaltstack | ||
617 | .long sys_sendfile | ||
618 | .long sys_ni_syscall /* streams1 */ | ||
619 | .long sys_ni_syscall /* streams2 */ | ||
620 | .long sys_vfork /* 190 */ | ||
621 | .long sys_getrlimit | ||
622 | .long sys_mmap2 | ||
623 | .long sys_truncate64 | ||
624 | .long sys_ftruncate64 | ||
625 | .long sys_stat64 /* 195 */ | ||
626 | .long sys_lstat64 | ||
627 | .long sys_fstat64 | ||
628 | .long sys_chown | ||
629 | .long sys_getuid | ||
630 | .long sys_getgid /* 200 */ | ||
631 | .long sys_geteuid | ||
632 | .long sys_getegid | ||
633 | .long sys_setreuid | ||
634 | .long sys_setregid | ||
635 | .long sys_getgroups /* 205 */ | ||
636 | .long sys_setgroups | ||
637 | .long sys_fchown | ||
638 | .long sys_setresuid | ||
639 | .long sys_getresuid | ||
640 | .long sys_setresgid /* 210 */ | ||
641 | .long sys_getresgid | ||
642 | .long sys_lchown | ||
643 | .long sys_setuid | ||
644 | .long sys_setgid | ||
645 | .long sys_setfsuid /* 215 */ | ||
646 | .long sys_setfsgid | ||
647 | .long sys_pivot_root | ||
648 | .long sys_ni_syscall | ||
649 | .long sys_ni_syscall | ||
650 | .long sys_getdents64 /* 220 */ | ||
651 | .long sys_gettid | ||
652 | .long sys_tkill | ||
653 | .long sys_setxattr | ||
654 | .long sys_lsetxattr | ||
655 | .long sys_fsetxattr /* 225 */ | ||
656 | .long sys_getxattr | ||
657 | .long sys_lgetxattr | ||
658 | .long sys_fgetxattr | ||
659 | .long sys_listxattr | ||
660 | .long sys_llistxattr /* 230 */ | ||
661 | .long sys_flistxattr | ||
662 | .long sys_removexattr | ||
663 | .long sys_lremovexattr | ||
664 | .long sys_fremovexattr | ||
665 | .long sys_futex /* 235 */ | ||
666 | .long sys_sendfile64 | ||
667 | .long sys_mincore | ||
668 | .long sys_madvise | ||
669 | .long sys_fcntl64 | ||
670 | .long sys_readahead /* 240 */ | ||
671 | .long sys_io_setup | ||
672 | .long sys_io_destroy | ||
673 | .long sys_io_getevents | ||
674 | .long sys_io_submit | ||
675 | .long sys_io_cancel /* 245 */ | ||
676 | .long sys_fadvise64 | ||
677 | .long sys_exit_group | ||
678 | .long sys_lookup_dcookie | ||
679 | .long sys_epoll_create | ||
680 | .long sys_epoll_ctl /* 250 */ | ||
681 | .long sys_epoll_wait | ||
682 | .long sys_remap_file_pages | ||
683 | .long sys_set_tid_address | ||
684 | .long sys_timer_create | ||
685 | .long sys_timer_settime /* 255 */ | ||
686 | .long sys_timer_gettime | ||
687 | .long sys_timer_getoverrun | ||
688 | .long sys_timer_delete | ||
689 | .long sys_clock_settime | ||
690 | .long sys_clock_gettime /* 260 */ | ||
691 | .long sys_clock_getres | ||
692 | .long sys_clock_nanosleep | ||
693 | .long sys_statfs64 | ||
694 | .long sys_fstatfs64 | ||
695 | .long sys_tgkill /* 265 */ | ||
696 | .long sys_utimes | ||
697 | .long sys_fadvise64_64 | ||
698 | .long sys_mbind | ||
699 | .long sys_get_mempolicy | ||
700 | .long sys_set_mempolicy /* 270 */ | ||
701 | .long sys_mq_open | ||
702 | .long sys_mq_unlink | ||
703 | .long sys_mq_timedsend | ||
704 | .long sys_mq_timedreceive | ||
705 | .long sys_mq_notify /* 275 */ | ||
706 | .long sys_mq_getsetattr | ||
707 | .long sys_waitid | ||
708 | .long sys_ni_syscall /* for sys_vserver */ | ||
709 | .long sys_add_key | ||
710 | .long sys_request_key /* 280 */ | ||
711 | .long sys_keyctl | ||
712 | |||
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S new file mode 100644 index 000000000000..7cd6de17c20d --- /dev/null +++ b/arch/m68k/kernel/head.S | |||
@@ -0,0 +1,3940 @@ | |||
1 | /* -*- mode: asm -*- | ||
2 | ** | ||
3 | ** head.S -- This file contains the initial boot code for the | ||
4 | ** Linux/68k kernel. | ||
5 | ** | ||
6 | ** Copyright 1993 by Hamish Macdonald | ||
7 | ** | ||
8 | ** 68040 fixes by Michael Rausch | ||
9 | ** 68060 fixes by Roman Hodek | ||
10 | ** MMU cleanup by Randy Thelen | ||
11 | ** Final MMU cleanup by Roman Zippel | ||
12 | ** | ||
13 | ** Atari support by Andreas Schwab, using ideas of Robert de Vries | ||
14 | ** and Bjoern Brauel | ||
15 | ** VME Support by Richard Hirst | ||
16 | ** | ||
17 | ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE | ||
18 | ** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari | ||
19 | ** ++ Bjoern & Roman: ATARI-68040 support for the Medusa | ||
20 | ** 95/11/18 Richard Hirst: Added MVME166 support | ||
21 | ** 96/04/26 Guenther Kelleter: fixed identity mapping for Falcon with | ||
22 | ** Magnum- and FX-alternate ram | ||
23 | ** 98/04/25 Phil Blundell: added HP300 support | ||
24 | ** 1998/08/30 David Kilzer: Added support for font_desc structures | ||
25 | ** for linux-2.1.115 | ||
26 | ** 9/02/11 Richard Zidlicky: added Q40 support (initial vesion 99/01/01) | ||
27 | ** 2004/05/13 Kars de Jong: Finalised HP300 support | ||
28 | ** | ||
29 | ** This file is subject to the terms and conditions of the GNU General Public | ||
30 | ** License. See the file README.legal in the main directory of this archive | ||
31 | ** for more details. | ||
32 | ** | ||
33 | */ | ||
34 | |||
35 | /* | ||
36 | * Linux startup code. | ||
37 | * | ||
38 | * At this point, the boot loader has: | ||
39 | * Disabled interrupts | ||
40 | * Disabled caches | ||
41 | * Put us in supervisor state. | ||
42 | * | ||
43 | * The kernel setup code takes the following steps: | ||
44 | * . Raise interrupt level | ||
45 | * . Set up initial kernel memory mapping. | ||
46 | * . This sets up a mapping of the 4M of memory the kernel is located in. | ||
47 | * . It also does a mapping of any initial machine specific areas. | ||
48 | * . Enable the MMU | ||
49 | * . Enable cache memories | ||
50 | * . Jump to kernel startup | ||
51 | * | ||
52 | * Much of the file restructuring was to accomplish: | ||
53 | * 1) Remove register dependency through-out the file. | ||
54 | * 2) Increase use of subroutines to perform functions | ||
55 | * 3) Increase readability of the code | ||
56 | * | ||
57 | * Of course, readability is a subjective issue, so it will never be | ||
58 | * argued that that goal was accomplished. It was merely a goal. | ||
59 | * A key way to help make code more readable is to give good | ||
60 | * documentation. So, the first thing you will find is exaustive | ||
61 | * write-ups on the structure of the file, and the features of the | ||
62 | * functional subroutines. | ||
63 | * | ||
64 | * General Structure: | ||
65 | * ------------------ | ||
66 | * Without a doubt the single largest chunk of head.S is spent | ||
67 | * mapping the kernel and I/O physical space into the logical range | ||
68 | * for the kernel. | ||
69 | * There are new subroutines and data structures to make MMU | ||
70 | * support cleaner and easier to understand. | ||
71 | * First, you will find a routine call "mmu_map" which maps | ||
72 | * a logical to a physical region for some length given a cache | ||
73 | * type on behalf of the caller. This routine makes writing the | ||
74 | * actual per-machine specific code very simple. | ||
75 | * A central part of the code, but not a subroutine in itself, | ||
76 | * is the mmu_init code which is broken down into mapping the kernel | ||
77 | * (the same for all machines) and mapping machine-specific I/O | ||
78 | * regions. | ||
79 | * Also, there will be a description of engaging the MMU and | ||
80 | * caches. | ||
81 | * You will notice that there is a chunk of code which | ||
82 | * can emit the entire MMU mapping of the machine. This is present | ||
83 | * only in debug modes and can be very helpful. | ||
84 | * Further, there is a new console driver in head.S that is | ||
85 | * also only engaged in debug mode. Currently, it's only supported | ||
86 | * on the Macintosh class of machines. However, it is hoped that | ||
87 | * others will plug-in support for specific machines. | ||
88 | * | ||
89 | * ###################################################################### | ||
90 | * | ||
91 | * mmu_map | ||
92 | * ------- | ||
93 | * mmu_map was written for two key reasons. First, it was clear | ||
94 | * that it was very difficult to read the previous code for mapping | ||
95 | * regions of memory. Second, the Macintosh required such extensive | ||
96 | * memory allocations that it didn't make sense to propagate the | ||
97 | * existing code any further. | ||
98 | * mmu_map requires some parameters: | ||
99 | * | ||
100 | * mmu_map (logical, physical, length, cache_type) | ||
101 | * | ||
102 | * While this essentially describes the function in the abstract, you'll | ||
103 | * find more indepth description of other parameters at the implementation site. | ||
104 | * | ||
105 | * mmu_get_root_table_entry | ||
106 | * ------------------------ | ||
107 | * mmu_get_ptr_table_entry | ||
108 | * ----------------------- | ||
109 | * mmu_get_page_table_entry | ||
110 | * ------------------------ | ||
111 | * | ||
112 | * These routines are used by other mmu routines to get a pointer into | ||
113 | * a table, if necessary a new table is allocated. These routines are working | ||
114 | * basically like pmd_alloc() and pte_alloc() in <asm/pgtable.h>. The root | ||
115 | * table needs of course only to be allocated once in mmu_get_root_table_entry, | ||
116 | * so that here also some mmu specific initialization is done. The second page | ||
117 | * at the start of the kernel (the first page is unmapped later) is used for | ||
118 | * the kernel_pg_dir. It must be at a position known at link time (as it's used | ||
119 | * to initialize the init task struct) and since it needs special cache | ||
120 | * settings, it's the easiest to use this page, the rest of the page is used | ||
121 | * for further pointer tables. | ||
122 | * mmu_get_page_table_entry allocates always a whole page for page tables, this | ||
123 | * means 1024 pages and so 4MB of memory can be mapped. It doesn't make sense | ||
124 | * to manage page tables in smaller pieces as nearly all mappings have that | ||
125 | * size. | ||
126 | * | ||
127 | * ###################################################################### | ||
128 | * | ||
129 | * | ||
130 | * ###################################################################### | ||
131 | * | ||
132 | * mmu_engage | ||
133 | * ---------- | ||
134 | * Thanks to a small helping routine enabling the mmu got quite simple | ||
135 | * and there is only one way left. mmu_engage makes a complete a new mapping | ||
136 | * that only includes the absolute necessary to be able to jump to the final | ||
137 | * postion and to restore the original mapping. | ||
138 | * As this code doesn't need a transparent translation register anymore this | ||
139 | * means all registers are free to be used by machines that needs them for | ||
140 | * other purposes. | ||
141 | * | ||
142 | * ###################################################################### | ||
143 | * | ||
144 | * mmu_print | ||
145 | * --------- | ||
146 | * This algorithm will print out the page tables of the system as | ||
147 | * appropriate for an 030 or an 040. This is useful for debugging purposes | ||
148 | * and as such is enclosed in #ifdef MMU_PRINT/#endif clauses. | ||
149 | * | ||
150 | * ###################################################################### | ||
151 | * | ||
152 | * console_init | ||
153 | * ------------ | ||
154 | * The console is also able to be turned off. The console in head.S | ||
155 | * is specifically for debugging and can be very useful. It is surrounded by | ||
156 | * #ifdef CONSOLE/#endif clauses so it doesn't have to ship in known-good | ||
157 | * kernels. It's basic algorithm is to determine the size of the screen | ||
158 | * (in height/width and bit depth) and then use that information for | ||
159 | * displaying an 8x8 font or an 8x16 (widthxheight). I prefer the 8x8 for | ||
160 | * debugging so I can see more good data. But it was trivial to add support | ||
161 | * for both fonts, so I included it. | ||
162 | * Also, the algorithm for plotting pixels is abstracted so that in | ||
163 | * theory other platforms could add support for different kinds of frame | ||
164 | * buffers. This could be very useful. | ||
165 | * | ||
166 | * console_put_penguin | ||
167 | * ------------------- | ||
168 | * An important part of any Linux bring up is the penguin and there's | ||
169 | * nothing like getting the Penguin on the screen! This algorithm will work | ||
170 | * on any machine for which there is a console_plot_pixel. | ||
171 | * | ||
172 | * console_scroll | ||
173 | * -------------- | ||
174 | * My hope is that the scroll algorithm does the right thing on the | ||
175 | * various platforms, but it wouldn't be hard to add the test conditions | ||
176 | * and new code if it doesn't. | ||
177 | * | ||
178 | * console_putc | ||
179 | * ------------- | ||
180 | * | ||
181 | * ###################################################################### | ||
182 | * | ||
183 | * Register usage has greatly simplified within head.S. Every subroutine | ||
184 | * saves and restores all registers that it modifies (except it returns a | ||
185 | * value in there of course). So the only register that needs to be initialized | ||
186 | * is the stack pointer. | ||
187 | * All other init code and data is now placed in the init section, so it will | ||
188 | * be automatically freed at the end of the kernel initialization. | ||
189 | * | ||
190 | * ###################################################################### | ||
191 | * | ||
192 | * options | ||
193 | * ------- | ||
194 | * There are many options available in a build of this file. I've | ||
195 | * taken the time to describe them here to save you the time of searching | ||
196 | * for them and trying to understand what they mean. | ||
197 | * | ||
198 | * CONFIG_xxx: These are the obvious machine configuration defines created | ||
199 | * during configuration. These are defined in include/linux/autoconf.h. | ||
200 | * | ||
201 | * CONSOLE: There is support for head.S console in this file. This | ||
202 | * console can talk to a Mac frame buffer, but could easily be extrapolated | ||
203 | * to extend it to support other platforms. | ||
204 | * | ||
205 | * TEST_MMU: This is a test harness for running on any given machine but | ||
206 | * getting an MMU dump for another class of machine. The classes of machines | ||
207 | * that can be tested are any of the makes (Atari, Amiga, Mac, VME, etc.) | ||
208 | * and any of the models (030, 040, 060, etc.). | ||
209 | * | ||
210 | * NOTE: TEST_MMU is NOT permanent! It is scheduled to be removed | ||
211 | * When head.S boots on Atari, Amiga, Macintosh, and VME | ||
212 | * machines. At that point the underlying logic will be | ||
213 | * believed to be solid enough to be trusted, and TEST_MMU | ||
214 | * can be dropped. Do note that that will clean up the | ||
215 | * head.S code significantly as large blocks of #if/#else | ||
216 | * clauses can be removed. | ||
217 | * | ||
218 | * MMU_NOCACHE_KERNEL: On the Macintosh platform there was an inquiry into | ||
219 | * determing why devices don't appear to work. A test case was to remove | ||
220 | * the cacheability of the kernel bits. | ||
221 | * | ||
222 | * MMU_PRINT: There is a routine built into head.S that can display the | ||
223 | * MMU data structures. It outputs its result through the serial_putc | ||
224 | * interface. So where ever that winds up driving data, that's where the | ||
225 | * mmu struct will appear. On the Macintosh that's typically the console. | ||
226 | * | ||
227 | * SERIAL_DEBUG: There are a series of putc() macro statements | ||
228 | * scattered through out the code to give progress of status to the | ||
229 | * person sitting at the console. This constant determines whether those | ||
230 | * are used. | ||
231 | * | ||
232 | * DEBUG: This is the standard DEBUG flag that can be set for building | ||
233 | * the kernel. It has the effect adding additional tests into | ||
234 | * the code. | ||
235 | * | ||
236 | * FONT_6x11: | ||
237 | * FONT_8x8: | ||
238 | * FONT_8x16: | ||
239 | * In theory these could be determined at run time or handed | ||
240 | * over by the booter. But, let's be real, it's a fine hard | ||
241 | * coded value. (But, you will notice the code is run-time | ||
242 | * flexible!) A pointer to the font's struct font_desc | ||
243 | * is kept locally in Lconsole_font. It is used to determine | ||
244 | * font size information dynamically. | ||
245 | * | ||
246 | * Atari constants: | ||
247 | * USE_PRINTER: Use the printer port for serial debug. | ||
248 | * USE_SCC_B: Use the SCC port A (Serial2) for serial debug. | ||
249 | * USE_SCC_A: Use the SCC port B (Modem2) for serial debug. | ||
250 | * USE_MFP: Use the ST-MFP port (Modem1) for serial debug. | ||
251 | * | ||
252 | * Macintosh constants: | ||
253 | * MAC_SERIAL_DEBUG: Turns on serial debug output for the Macintosh. | ||
254 | * MAC_USE_SCC_A: Use the SCC port A (modem) for serial debug. | ||
255 | * MAC_USE_SCC_B: Use the SCC port B (printer) for serial debug (default). | ||
256 | */ | ||
257 | |||
258 | #include <linux/config.h> | ||
259 | #include <linux/linkage.h> | ||
260 | #include <linux/init.h> | ||
261 | #include <asm/bootinfo.h> | ||
262 | #include <asm/setup.h> | ||
263 | #include <asm/entry.h> | ||
264 | #include <asm/pgtable.h> | ||
265 | #include <asm/page.h> | ||
266 | #include <asm/offsets.h> | ||
267 | |||
268 | #ifdef CONFIG_MAC | ||
269 | |||
270 | #include <asm/machw.h> | ||
271 | |||
272 | /* | ||
273 | * Macintosh console support | ||
274 | */ | ||
275 | |||
276 | #define CONSOLE | ||
277 | #define CONSOLE_PENGUIN | ||
278 | |||
279 | /* | ||
280 | * Macintosh serial debug support; outputs boot info to the printer | ||
281 | * and/or modem serial ports | ||
282 | */ | ||
283 | #undef MAC_SERIAL_DEBUG | ||
284 | |||
285 | /* | ||
286 | * Macintosh serial debug port selection; define one or both; | ||
287 | * requires MAC_SERIAL_DEBUG to be defined | ||
288 | */ | ||
289 | #define MAC_USE_SCC_A /* Macintosh modem serial port */ | ||
290 | #define MAC_USE_SCC_B /* Macintosh printer serial port */ | ||
291 | |||
292 | #endif /* CONFIG_MAC */ | ||
293 | |||
294 | #undef MMU_PRINT | ||
295 | #undef MMU_NOCACHE_KERNEL | ||
296 | #define SERIAL_DEBUG | ||
297 | #undef DEBUG | ||
298 | |||
299 | /* | ||
300 | * For the head.S console, there are three supported fonts, 6x11, 8x16 and 8x8. | ||
301 | * The 8x8 font is harder to read but fits more on the screen. | ||
302 | */ | ||
303 | #define FONT_8x8 /* default */ | ||
304 | /* #define FONT_8x16 */ /* 2nd choice */ | ||
305 | /* #define FONT_6x11 */ /* 3rd choice */ | ||
306 | |||
307 | .globl kernel_pg_dir | ||
308 | .globl availmem | ||
309 | .globl m68k_pgtable_cachemode | ||
310 | .globl m68k_supervisor_cachemode | ||
311 | #ifdef CONFIG_MVME16x | ||
312 | .globl mvme_bdid | ||
313 | #endif | ||
314 | #ifdef CONFIG_Q40 | ||
315 | .globl q40_mem_cptr | ||
316 | #endif | ||
317 | |||
318 | CPUTYPE_040 = 1 /* indicates an 040 */ | ||
319 | CPUTYPE_060 = 2 /* indicates an 060 */ | ||
320 | CPUTYPE_0460 = 3 /* if either above are set, this is set */ | ||
321 | CPUTYPE_020 = 4 /* indicates an 020 */ | ||
322 | |||
323 | /* Translation control register */ | ||
324 | TC_ENABLE = 0x8000 | ||
325 | TC_PAGE8K = 0x4000 | ||
326 | TC_PAGE4K = 0x0000 | ||
327 | |||
328 | /* Transparent translation registers */ | ||
329 | TTR_ENABLE = 0x8000 /* enable transparent translation */ | ||
330 | TTR_ANYMODE = 0x4000 /* user and kernel mode access */ | ||
331 | TTR_KERNELMODE = 0x2000 /* only kernel mode access */ | ||
332 | TTR_USERMODE = 0x0000 /* only user mode access */ | ||
333 | TTR_CI = 0x0400 /* inhibit cache */ | ||
334 | TTR_RW = 0x0200 /* read/write mode */ | ||
335 | TTR_RWM = 0x0100 /* read/write mask */ | ||
336 | TTR_FCB2 = 0x0040 /* function code base bit 2 */ | ||
337 | TTR_FCB1 = 0x0020 /* function code base bit 1 */ | ||
338 | TTR_FCB0 = 0x0010 /* function code base bit 0 */ | ||
339 | TTR_FCM2 = 0x0004 /* function code mask bit 2 */ | ||
340 | TTR_FCM1 = 0x0002 /* function code mask bit 1 */ | ||
341 | TTR_FCM0 = 0x0001 /* function code mask bit 0 */ | ||
342 | |||
343 | /* Cache Control registers */ | ||
344 | CC6_ENABLE_D = 0x80000000 /* enable data cache (680[46]0) */ | ||
345 | CC6_FREEZE_D = 0x40000000 /* freeze data cache (68060) */ | ||
346 | CC6_ENABLE_SB = 0x20000000 /* enable store buffer (68060) */ | ||
347 | CC6_PUSH_DPI = 0x10000000 /* disable CPUSH invalidation (68060) */ | ||
348 | CC6_HALF_D = 0x08000000 /* half-cache mode for data cache (68060) */ | ||
349 | CC6_ENABLE_B = 0x00800000 /* enable branch cache (68060) */ | ||
350 | CC6_CLRA_B = 0x00400000 /* clear all entries in branch cache (68060) */ | ||
351 | CC6_CLRU_B = 0x00200000 /* clear user entries in branch cache (68060) */ | ||
352 | CC6_ENABLE_I = 0x00008000 /* enable instruction cache (680[46]0) */ | ||
353 | CC6_FREEZE_I = 0x00004000 /* freeze instruction cache (68060) */ | ||
354 | CC6_HALF_I = 0x00002000 /* half-cache mode for instruction cache (68060) */ | ||
355 | CC3_ALLOC_WRITE = 0x00002000 /* write allocate mode(68030) */ | ||
356 | CC3_ENABLE_DB = 0x00001000 /* enable data burst (68030) */ | ||
357 | CC3_CLR_D = 0x00000800 /* clear data cache (68030) */ | ||
358 | CC3_CLRE_D = 0x00000400 /* clear entry in data cache (68030) */ | ||
359 | CC3_FREEZE_D = 0x00000200 /* freeze data cache (68030) */ | ||
360 | CC3_ENABLE_D = 0x00000100 /* enable data cache (68030) */ | ||
361 | CC3_ENABLE_IB = 0x00000010 /* enable instruction burst (68030) */ | ||
362 | CC3_CLR_I = 0x00000008 /* clear instruction cache (68030) */ | ||
363 | CC3_CLRE_I = 0x00000004 /* clear entry in instruction cache (68030) */ | ||
364 | CC3_FREEZE_I = 0x00000002 /* freeze instruction cache (68030) */ | ||
365 | CC3_ENABLE_I = 0x00000001 /* enable instruction cache (68030) */ | ||
366 | |||
367 | /* Miscellaneous definitions */ | ||
368 | PAGESIZE = 4096 | ||
369 | PAGESHIFT = 12 | ||
370 | |||
371 | ROOT_TABLE_SIZE = 128 | ||
372 | PTR_TABLE_SIZE = 128 | ||
373 | PAGE_TABLE_SIZE = 64 | ||
374 | ROOT_INDEX_SHIFT = 25 | ||
375 | PTR_INDEX_SHIFT = 18 | ||
376 | PAGE_INDEX_SHIFT = 12 | ||
377 | |||
378 | #ifdef DEBUG | ||
379 | /* When debugging use readable names for labels */ | ||
380 | #ifdef __STDC__ | ||
381 | #define L(name) .head.S.##name | ||
382 | #else | ||
383 | #define L(name) .head.S./**/name | ||
384 | #endif | ||
385 | #else | ||
386 | #ifdef __STDC__ | ||
387 | #define L(name) .L##name | ||
388 | #else | ||
389 | #define L(name) .L/**/name | ||
390 | #endif | ||
391 | #endif | ||
392 | |||
393 | /* The __INITDATA stuff is a no-op when ftrace or kgdb are turned on */ | ||
394 | #ifndef __INITDATA | ||
395 | #define __INITDATA .data | ||
396 | #define __FINIT .previous | ||
397 | #endif | ||
398 | |||
399 | /* Several macros to make the writing of subroutines easier: | ||
400 | * - func_start marks the beginning of the routine which setups the frame | ||
401 | * register and saves the registers, it also defines another macro | ||
402 | * to automatically restore the registers again. | ||
403 | * - func_return marks the end of the routine and simply calls the prepared | ||
404 | * macro to restore registers and jump back to the caller. | ||
405 | * - func_define generates another macro to automatically put arguments | ||
406 | * onto the stack call the subroutine and cleanup the stack again. | ||
407 | */ | ||
408 | |||
409 | /* Within subroutines these macros can be used to access the arguments | ||
410 | * on the stack. With STACK some allocated memory on the stack can be | ||
411 | * accessed and ARG0 points to the return address (used by mmu_engage). | ||
412 | */ | ||
413 | #define STACK %a6@(stackstart) | ||
414 | #define ARG0 %a6@(4) | ||
415 | #define ARG1 %a6@(8) | ||
416 | #define ARG2 %a6@(12) | ||
417 | #define ARG3 %a6@(16) | ||
418 | #define ARG4 %a6@(20) | ||
419 | |||
420 | .macro func_start name,saveregs,stack=0 | ||
421 | L(\name): | ||
422 | linkw %a6,#-\stack | ||
423 | moveml \saveregs,%sp@- | ||
424 | .set stackstart,-\stack | ||
425 | |||
426 | .macro func_return_\name | ||
427 | moveml %sp@+,\saveregs | ||
428 | unlk %a6 | ||
429 | rts | ||
430 | .endm | ||
431 | .endm | ||
432 | |||
433 | .macro func_return name | ||
434 | func_return_\name | ||
435 | .endm | ||
436 | |||
437 | .macro func_call name | ||
438 | jbsr L(\name) | ||
439 | .endm | ||
440 | |||
441 | .macro move_stack nr,arg1,arg2,arg3,arg4 | ||
442 | .if \nr | ||
443 | move_stack "(\nr-1)",\arg2,\arg3,\arg4 | ||
444 | movel \arg1,%sp@- | ||
445 | .endif | ||
446 | .endm | ||
447 | |||
448 | .macro func_define name,nr=0 | ||
449 | .macro \name arg1,arg2,arg3,arg4 | ||
450 | move_stack \nr,\arg1,\arg2,\arg3,\arg4 | ||
451 | func_call \name | ||
452 | .if \nr | ||
453 | lea %sp@(\nr*4),%sp | ||
454 | .endif | ||
455 | .endm | ||
456 | .endm | ||
457 | |||
458 | func_define mmu_map,4 | ||
459 | func_define mmu_map_tt,4 | ||
460 | func_define mmu_fixup_page_mmu_cache,1 | ||
461 | func_define mmu_temp_map,2 | ||
462 | func_define mmu_engage | ||
463 | func_define mmu_get_root_table_entry,1 | ||
464 | func_define mmu_get_ptr_table_entry,2 | ||
465 | func_define mmu_get_page_table_entry,2 | ||
466 | func_define mmu_print | ||
467 | func_define get_new_page | ||
468 | #if defined(CONFIG_HP300) || defined(CONFIG_APOLLO) | ||
469 | func_define set_leds | ||
470 | #endif | ||
471 | |||
472 | .macro mmu_map_eq arg1,arg2,arg3 | ||
473 | mmu_map \arg1,\arg1,\arg2,\arg3 | ||
474 | .endm | ||
475 | |||
476 | .macro get_bi_record record | ||
477 | pea \record | ||
478 | func_call get_bi_record | ||
479 | addql #4,%sp | ||
480 | .endm | ||
481 | |||
482 | func_define serial_putc,1 | ||
483 | func_define console_putc,1 | ||
484 | |||
485 | func_define console_init | ||
486 | func_define console_put_stats | ||
487 | func_define console_put_penguin | ||
488 | func_define console_plot_pixel,3 | ||
489 | func_define console_scroll | ||
490 | |||
491 | .macro putc ch | ||
492 | #if defined(CONSOLE) || defined(SERIAL_DEBUG) | ||
493 | pea \ch | ||
494 | #endif | ||
495 | #ifdef CONSOLE | ||
496 | func_call console_putc | ||
497 | #endif | ||
498 | #ifdef SERIAL_DEBUG | ||
499 | func_call serial_putc | ||
500 | #endif | ||
501 | #if defined(CONSOLE) || defined(SERIAL_DEBUG) | ||
502 | addql #4,%sp | ||
503 | #endif | ||
504 | .endm | ||
505 | |||
506 | .macro dputc ch | ||
507 | #ifdef DEBUG | ||
508 | putc \ch | ||
509 | #endif | ||
510 | .endm | ||
511 | |||
512 | func_define putn,1 | ||
513 | |||
514 | .macro dputn nr | ||
515 | #ifdef DEBUG | ||
516 | putn \nr | ||
517 | #endif | ||
518 | .endm | ||
519 | |||
520 | .macro puts string | ||
521 | #if defined(CONSOLE) || defined(SERIAL_DEBUG) | ||
522 | __INITDATA | ||
523 | .Lstr\@: | ||
524 | .string "\string" | ||
525 | __FINIT | ||
526 | pea %pc@(.Lstr\@) | ||
527 | func_call puts | ||
528 | addql #4,%sp | ||
529 | #endif | ||
530 | .endm | ||
531 | |||
532 | .macro dputs string | ||
533 | #ifdef DEBUG | ||
534 | puts "\string" | ||
535 | #endif | ||
536 | .endm | ||
537 | |||
538 | #define is_not_amiga(lab) cmpl &MACH_AMIGA,%pc@(m68k_machtype); jne lab | ||
539 | #define is_not_atari(lab) cmpl &MACH_ATARI,%pc@(m68k_machtype); jne lab | ||
540 | #define is_not_mac(lab) cmpl &MACH_MAC,%pc@(m68k_machtype); jne lab | ||
541 | #define is_not_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jne lab | ||
542 | #define is_not_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jne lab | ||
543 | #define is_not_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jne lab | ||
544 | #define is_mvme147(lab) cmpl &MACH_MVME147,%pc@(m68k_machtype); jeq lab | ||
545 | #define is_mvme16x(lab) cmpl &MACH_MVME16x,%pc@(m68k_machtype); jeq lab | ||
546 | #define is_bvme6000(lab) cmpl &MACH_BVME6000,%pc@(m68k_machtype); jeq lab | ||
547 | #define is_not_hp300(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); jne lab | ||
548 | #define is_not_apollo(lab) cmpl &MACH_APOLLO,%pc@(m68k_machtype); jne lab | ||
549 | #define is_not_q40(lab) cmpl &MACH_Q40,%pc@(m68k_machtype); jne lab | ||
550 | #define is_not_sun3x(lab) cmpl &MACH_SUN3X,%pc@(m68k_machtype); jne lab | ||
551 | |||
552 | #define hasnt_leds(lab) cmpl &MACH_HP300,%pc@(m68k_machtype); \ | ||
553 | jeq 42f; \ | ||
554 | cmpl &MACH_APOLLO,%pc@(m68k_machtype); \ | ||
555 | jne lab ;\ | ||
556 | 42:\ | ||
557 | |||
558 | #define is_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jne lab | ||
559 | #define is_not_040_or_060(lab) btst &CPUTYPE_0460,%pc@(L(cputype)+3); jeq lab | ||
560 | #define is_040(lab) btst &CPUTYPE_040,%pc@(L(cputype)+3); jne lab | ||
561 | #define is_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jne lab | ||
562 | #define is_not_060(lab) btst &CPUTYPE_060,%pc@(L(cputype)+3); jeq lab | ||
563 | #define is_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jne lab | ||
564 | #define is_not_020(lab) btst &CPUTYPE_020,%pc@(L(cputype)+3); jeq lab | ||
565 | |||
566 | /* On the HP300 we use the on-board LEDs for debug output before | ||
567 | the console is running. Writing a 1 bit turns the corresponding LED | ||
568 | _off_ - on the 340 bit 7 is towards the back panel of the machine. */ | ||
569 | .macro leds mask | ||
570 | #if defined(CONFIG_HP300) || defined(CONFIG_APOLLO) | ||
571 | hasnt_leds(.Lled\@) | ||
572 | pea \mask | ||
573 | func_call set_leds | ||
574 | addql #4,%sp | ||
575 | .Lled\@: | ||
576 | #endif | ||
577 | .endm | ||
578 | |||
579 | .text | ||
580 | ENTRY(_stext) | ||
581 | /* | ||
582 | * Version numbers of the bootinfo interface | ||
583 | * The area from _stext to _start will later be used as kernel pointer table | ||
584 | */ | ||
585 | bras 1f /* Jump over bootinfo version numbers */ | ||
586 | |||
587 | .long BOOTINFOV_MAGIC | ||
588 | .long MACH_AMIGA, AMIGA_BOOTI_VERSION | ||
589 | .long MACH_ATARI, ATARI_BOOTI_VERSION | ||
590 | .long MACH_MVME147, MVME147_BOOTI_VERSION | ||
591 | .long MACH_MVME16x, MVME16x_BOOTI_VERSION | ||
592 | .long MACH_BVME6000, BVME6000_BOOTI_VERSION | ||
593 | .long MACH_MAC, MAC_BOOTI_VERSION | ||
594 | .long MACH_Q40, Q40_BOOTI_VERSION | ||
595 | .long MACH_HP300, HP300_BOOTI_VERSION | ||
596 | .long 0 | ||
597 | 1: jra __start | ||
598 | |||
599 | .equ kernel_pg_dir,_stext | ||
600 | |||
601 | .equ .,_stext+PAGESIZE | ||
602 | |||
603 | ENTRY(_start) | ||
604 | jra __start | ||
605 | __INIT | ||
606 | ENTRY(__start) | ||
607 | /* | ||
608 | * Setup initial stack pointer | ||
609 | */ | ||
610 | lea %pc@(_stext),%sp | ||
611 | |||
612 | /* | ||
613 | * Record the CPU and machine type. | ||
614 | */ | ||
615 | get_bi_record BI_MACHTYPE | ||
616 | lea %pc@(m68k_machtype),%a1 | ||
617 | movel %a0@,%a1@ | ||
618 | |||
619 | get_bi_record BI_FPUTYPE | ||
620 | lea %pc@(m68k_fputype),%a1 | ||
621 | movel %a0@,%a1@ | ||
622 | |||
623 | get_bi_record BI_MMUTYPE | ||
624 | lea %pc@(m68k_mmutype),%a1 | ||
625 | movel %a0@,%a1@ | ||
626 | |||
627 | get_bi_record BI_CPUTYPE | ||
628 | lea %pc@(m68k_cputype),%a1 | ||
629 | movel %a0@,%a1@ | ||
630 | |||
631 | leds 0x1 | ||
632 | |||
633 | #ifdef CONFIG_MAC | ||
634 | /* | ||
635 | * For Macintosh, we need to determine the display parameters early (at least | ||
636 | * while debugging it). | ||
637 | */ | ||
638 | |||
639 | is_not_mac(L(test_notmac)) | ||
640 | |||
641 | get_bi_record BI_MAC_VADDR | ||
642 | lea %pc@(L(mac_videobase)),%a1 | ||
643 | movel %a0@,%a1@ | ||
644 | |||
645 | get_bi_record BI_MAC_VDEPTH | ||
646 | lea %pc@(L(mac_videodepth)),%a1 | ||
647 | movel %a0@,%a1@ | ||
648 | |||
649 | get_bi_record BI_MAC_VDIM | ||
650 | lea %pc@(L(mac_dimensions)),%a1 | ||
651 | movel %a0@,%a1@ | ||
652 | |||
653 | get_bi_record BI_MAC_VROW | ||
654 | lea %pc@(L(mac_rowbytes)),%a1 | ||
655 | movel %a0@,%a1@ | ||
656 | |||
657 | #ifdef MAC_SERIAL_DEBUG | ||
658 | get_bi_record BI_MAC_SCCBASE | ||
659 | lea %pc@(L(mac_sccbase)),%a1 | ||
660 | movel %a0@,%a1@ | ||
661 | #endif /* MAC_SERIAL_DEBUG */ | ||
662 | |||
663 | #if 0 | ||
664 | /* | ||
665 | * Clear the screen | ||
666 | */ | ||
667 | lea %pc@(L(mac_videobase)),%a0 | ||
668 | movel %a0@,%a1 | ||
669 | lea %pc@(L(mac_dimensions)),%a0 | ||
670 | movel %a0@,%d1 | ||
671 | swap %d1 /* #rows is high bytes */ | ||
672 | andl #0xFFFF,%d1 /* rows */ | ||
673 | subl #10,%d1 | ||
674 | lea %pc@(L(mac_rowbytes)),%a0 | ||
675 | loopy2: | ||
676 | movel %a0@,%d0 | ||
677 | subql #1,%d0 | ||
678 | loopx2: | ||
679 | moveb #0x55, %a1@+ | ||
680 | dbra %d0,loopx2 | ||
681 | dbra %d1,loopy2 | ||
682 | #endif | ||
683 | |||
684 | L(test_notmac): | ||
685 | #endif /* CONFIG_MAC */ | ||
686 | |||
687 | |||
688 | /* | ||
689 | * There are ultimately two pieces of information we want for all kinds of | ||
690 | * processors CpuType and CacheBits. The CPUTYPE was passed in from booter | ||
691 | * and is converted here from a booter type definition to a separate bit | ||
692 | * number which allows for the standard is_0x0 macro tests. | ||
693 | */ | ||
694 | movel %pc@(m68k_cputype),%d0 | ||
695 | /* | ||
696 | * Assume it's an 030 | ||
697 | */ | ||
698 | clrl %d1 | ||
699 | |||
700 | /* | ||
701 | * Test the BootInfo cputype for 060 | ||
702 | */ | ||
703 | btst #CPUB_68060,%d0 | ||
704 | jeq 1f | ||
705 | bset #CPUTYPE_060,%d1 | ||
706 | bset #CPUTYPE_0460,%d1 | ||
707 | jra 3f | ||
708 | 1: | ||
709 | /* | ||
710 | * Test the BootInfo cputype for 040 | ||
711 | */ | ||
712 | btst #CPUB_68040,%d0 | ||
713 | jeq 2f | ||
714 | bset #CPUTYPE_040,%d1 | ||
715 | bset #CPUTYPE_0460,%d1 | ||
716 | jra 3f | ||
717 | 2: | ||
718 | /* | ||
719 | * Test the BootInfo cputype for 020 | ||
720 | */ | ||
721 | btst #CPUB_68020,%d0 | ||
722 | jeq 3f | ||
723 | bset #CPUTYPE_020,%d1 | ||
724 | jra 3f | ||
725 | 3: | ||
726 | /* | ||
727 | * Record the cpu type | ||
728 | */ | ||
729 | lea %pc@(L(cputype)),%a0 | ||
730 | movel %d1,%a0@ | ||
731 | |||
732 | /* | ||
733 | * NOTE: | ||
734 | * | ||
735 | * Now the macros are valid: | ||
736 | * is_040_or_060 | ||
737 | * is_not_040_or_060 | ||
738 | * is_040 | ||
739 | * is_060 | ||
740 | * is_not_060 | ||
741 | */ | ||
742 | |||
743 | /* | ||
744 | * Determine the cache mode for pages holding MMU tables | ||
745 | * and for supervisor mode, unused for '020 and '030 | ||
746 | */ | ||
747 | clrl %d0 | ||
748 | clrl %d1 | ||
749 | |||
750 | is_not_040_or_060(L(save_cachetype)) | ||
751 | |||
752 | /* | ||
753 | * '040 or '060 | ||
754 | * d1 := cacheable write-through | ||
755 | * NOTE: The 68040 manual strongly recommends non-cached for MMU tables, | ||
756 | * but we have been using write-through since at least 2.0.29 so I | ||
757 | * guess it is OK. | ||
758 | */ | ||
759 | #ifdef CONFIG_060_WRITETHROUGH | ||
760 | /* | ||
761 | * If this is a 68060 board using drivers with cache coherency | ||
762 | * problems, then supervisor memory accesses need to be write-through | ||
763 | * also; otherwise, we want copyback. | ||
764 | */ | ||
765 | |||
766 | is_not_060(1f) | ||
767 | movel #_PAGE_CACHE040W,%d0 | ||
768 | jra L(save_cachetype) | ||
769 | #endif /* CONFIG_060_WRITETHROUGH */ | ||
770 | 1: | ||
771 | movew #_PAGE_CACHE040,%d0 | ||
772 | |||
773 | movel #_PAGE_CACHE040W,%d1 | ||
774 | |||
775 | L(save_cachetype): | ||
776 | /* Save cache mode for supervisor mode and page tables | ||
777 | */ | ||
778 | lea %pc@(m68k_supervisor_cachemode),%a0 | ||
779 | movel %d0,%a0@ | ||
780 | lea %pc@(m68k_pgtable_cachemode),%a0 | ||
781 | movel %d1,%a0@ | ||
782 | |||
783 | /* | ||
784 | * raise interrupt level | ||
785 | */ | ||
786 | movew #0x2700,%sr | ||
787 | |||
788 | /* | ||
789 | If running on an Atari, determine the I/O base of the | ||
790 | serial port and test if we are running on a Medusa or Hades. | ||
791 | This test is necessary here, because on the Hades the serial | ||
792 | port is only accessible in the high I/O memory area. | ||
793 | |||
794 | The test whether it is a Medusa is done by writing to the byte at | ||
795 | phys. 0x0. This should result in a bus error on all other machines. | ||
796 | |||
797 | ...should, but doesn't. The Afterburner040 for the Falcon has the | ||
798 | same behaviour (0x0..0x7 are no ROM shadow). So we have to do | ||
799 | another test to distinguish Medusa and AB040. This is a | ||
800 | read attempt for 0x00ff82fe phys. that should bus error on a Falcon | ||
801 | (+AB040), but is in the range where the Medusa always asserts DTACK. | ||
802 | |||
803 | The test for the Hades is done by reading address 0xb0000000. This | ||
804 | should give a bus error on the Medusa. | ||
805 | */ | ||
806 | |||
807 | #ifdef CONFIG_ATARI | ||
808 | is_not_atari(L(notypetest)) | ||
809 | |||
810 | /* get special machine type (Medusa/Hades/AB40) */ | ||
811 | moveq #0,%d3 /* default if tag doesn't exist */ | ||
812 | get_bi_record BI_ATARI_MCH_TYPE | ||
813 | tstl %d0 | ||
814 | jbmi 1f | ||
815 | movel %a0@,%d3 | ||
816 | lea %pc@(atari_mch_type),%a0 | ||
817 | movel %d3,%a0@ | ||
818 | 1: | ||
819 | /* On the Hades, the iobase must be set up before opening the | ||
820 | * serial port. There are no I/O regs at 0x00ffxxxx at all. */ | ||
821 | moveq #0,%d0 | ||
822 | cmpl #ATARI_MACH_HADES,%d3 | ||
823 | jbne 1f | ||
824 | movel #0xff000000,%d0 /* Hades I/O base addr: 0xff000000 */ | ||
825 | 1: lea %pc@(L(iobase)),%a0 | ||
826 | movel %d0,%a0@ | ||
827 | |||
828 | L(notypetest): | ||
829 | #endif | ||
830 | |||
831 | #ifdef CONFIG_VME | ||
832 | is_mvme147(L(getvmetype)) | ||
833 | is_bvme6000(L(getvmetype)) | ||
834 | is_not_mvme16x(L(gvtdone)) | ||
835 | |||
836 | /* See if the loader has specified the BI_VME_TYPE tag. Recent | ||
837 | * versions of VMELILO and TFTPLILO do this. We have to do this | ||
838 | * early so we know how to handle console output. If the tag | ||
839 | * doesn't exist then we use the Bug for output on MVME16x. | ||
840 | */ | ||
841 | L(getvmetype): | ||
842 | get_bi_record BI_VME_TYPE | ||
843 | tstl %d0 | ||
844 | jbmi 1f | ||
845 | movel %a0@,%d3 | ||
846 | lea %pc@(vme_brdtype),%a0 | ||
847 | movel %d3,%a0@ | ||
848 | 1: | ||
849 | #ifdef CONFIG_MVME16x | ||
850 | is_not_mvme16x(L(gvtdone)) | ||
851 | |||
852 | /* Need to get the BRD_ID info to differentiate between 162, 167, | ||
853 | * etc. This is available as a BI_VME_BRDINFO tag with later | ||
854 | * versions of VMELILO and TFTPLILO, otherwise we call the Bug. | ||
855 | */ | ||
856 | get_bi_record BI_VME_BRDINFO | ||
857 | tstl %d0 | ||
858 | jpl 1f | ||
859 | |||
860 | /* Get pointer to board ID data from Bug */ | ||
861 | movel %d2,%sp@- | ||
862 | trap #15 | ||
863 | .word 0x70 /* trap 0x70 - .BRD_ID */ | ||
864 | movel %sp@+,%a0 | ||
865 | 1: | ||
866 | lea %pc@(mvme_bdid),%a1 | ||
867 | /* Structure is 32 bytes long */ | ||
868 | movel %a0@+,%a1@+ | ||
869 | movel %a0@+,%a1@+ | ||
870 | movel %a0@+,%a1@+ | ||
871 | movel %a0@+,%a1@+ | ||
872 | movel %a0@+,%a1@+ | ||
873 | movel %a0@+,%a1@+ | ||
874 | movel %a0@+,%a1@+ | ||
875 | movel %a0@+,%a1@+ | ||
876 | #endif | ||
877 | |||
878 | L(gvtdone): | ||
879 | |||
880 | #endif | ||
881 | |||
882 | #ifdef CONFIG_HP300 | ||
883 | is_not_hp300(L(nothp)) | ||
884 | |||
885 | /* Get the address of the UART for serial debugging */ | ||
886 | get_bi_record BI_HP300_UART_ADDR | ||
887 | tstl %d0 | ||
888 | jbmi 1f | ||
889 | movel %a0@,%d3 | ||
890 | lea %pc@(L(uartbase)),%a0 | ||
891 | movel %d3,%a0@ | ||
892 | get_bi_record BI_HP300_UART_SCODE | ||
893 | tstl %d0 | ||
894 | jbmi 1f | ||
895 | movel %a0@,%d3 | ||
896 | lea %pc@(L(uart_scode)),%a0 | ||
897 | movel %d3,%a0@ | ||
898 | 1: | ||
899 | L(nothp): | ||
900 | #endif | ||
901 | |||
902 | /* | ||
903 | * Initialize serial port | ||
904 | */ | ||
905 | jbsr L(serial_init) | ||
906 | |||
907 | /* | ||
908 | * Initialize console | ||
909 | */ | ||
910 | #ifdef CONFIG_MAC | ||
911 | is_not_mac(L(nocon)) | ||
912 | #ifdef CONSOLE | ||
913 | console_init | ||
914 | #ifdef CONSOLE_PENGUIN | ||
915 | console_put_penguin | ||
916 | #endif /* CONSOLE_PENGUIN */ | ||
917 | console_put_stats | ||
918 | #endif /* CONSOLE */ | ||
919 | L(nocon): | ||
920 | #endif /* CONFIG_MAC */ | ||
921 | |||
922 | |||
923 | putc '\n' | ||
924 | putc 'A' | ||
925 | leds 0x2 | ||
926 | dputn %pc@(L(cputype)) | ||
927 | dputn %pc@(m68k_supervisor_cachemode) | ||
928 | dputn %pc@(m68k_pgtable_cachemode) | ||
929 | dputc '\n' | ||
930 | |||
931 | /* | ||
932 | * Save physical start address of kernel | ||
933 | */ | ||
934 | lea %pc@(L(phys_kernel_start)),%a0 | ||
935 | lea %pc@(_stext),%a1 | ||
936 | subl #_stext,%a1 | ||
937 | addl #PAGE_OFFSET,%a1 | ||
938 | movel %a1,%a0@ | ||
939 | |||
940 | putc 'B' | ||
941 | |||
942 | leds 0x4 | ||
943 | |||
944 | /* | ||
945 | * mmu_init | ||
946 | * | ||
947 | * This block of code does what's necessary to map in the various kinds | ||
948 | * of machines for execution of Linux. | ||
949 | * First map the first 4 MB of kernel code & data | ||
950 | */ | ||
951 | |||
952 | mmu_map #PAGE_OFFSET,%pc@(L(phys_kernel_start)),#4*1024*1024,\ | ||
953 | %pc@(m68k_supervisor_cachemode) | ||
954 | |||
955 | putc 'C' | ||
956 | |||
957 | #ifdef CONFIG_AMIGA | ||
958 | |||
959 | L(mmu_init_amiga): | ||
960 | |||
961 | is_not_amiga(L(mmu_init_not_amiga)) | ||
962 | /* | ||
963 | * mmu_init_amiga | ||
964 | */ | ||
965 | |||
966 | putc 'D' | ||
967 | |||
968 | is_not_040_or_060(1f) | ||
969 | |||
970 | /* | ||
971 | * 040: Map the 16Meg range physical 0x0 upto logical 0x8000.0000 | ||
972 | */ | ||
973 | mmu_map #0x80000000,#0,#0x01000000,#_PAGE_NOCACHE_S | ||
974 | /* | ||
975 | * Map the Zorro III I/O space with transparent translation | ||
976 | * for frame buffer memory etc. | ||
977 | */ | ||
978 | mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE_S | ||
979 | |||
980 | jbra L(mmu_init_done) | ||
981 | |||
982 | 1: | ||
983 | /* | ||
984 | * 030: Map the 32Meg range physical 0x0 upto logical 0x8000.0000 | ||
985 | */ | ||
986 | mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 | ||
987 | mmu_map_tt #1,#0x40000000,#0x20000000,#_PAGE_NOCACHE030 | ||
988 | |||
989 | jbra L(mmu_init_done) | ||
990 | |||
991 | L(mmu_init_not_amiga): | ||
992 | #endif | ||
993 | |||
994 | #ifdef CONFIG_ATARI | ||
995 | |||
996 | L(mmu_init_atari): | ||
997 | |||
998 | is_not_atari(L(mmu_init_not_atari)) | ||
999 | |||
1000 | putc 'E' | ||
1001 | |||
1002 | /* On the Atari, we map the I/O region (phys. 0x00ffxxxx) by mapping | ||
1003 | the last 16 MB of virtual address space to the first 16 MB (i.e. | ||
1004 | 0xffxxxxxx -> 0x00xxxxxx). For this, an additional pointer table is | ||
1005 | needed. I/O ranges are marked non-cachable. | ||
1006 | |||
1007 | For the Medusa it is better to map the I/O region transparently | ||
1008 | (i.e. 0xffxxxxxx -> 0xffxxxxxx), because some I/O registers are | ||
1009 | accessible only in the high area. | ||
1010 | |||
1011 | On the Hades all I/O registers are only accessible in the high | ||
1012 | area. | ||
1013 | */ | ||
1014 | |||
1015 | /* I/O base addr for non-Medusa, non-Hades: 0x00000000 */ | ||
1016 | moveq #0,%d0 | ||
1017 | movel %pc@(atari_mch_type),%d3 | ||
1018 | cmpl #ATARI_MACH_MEDUSA,%d3 | ||
1019 | jbeq 2f | ||
1020 | cmpl #ATARI_MACH_HADES,%d3 | ||
1021 | jbne 1f | ||
1022 | 2: movel #0xff000000,%d0 /* Medusa/Hades base addr: 0xff000000 */ | ||
1023 | 1: movel %d0,%d3 | ||
1024 | |||
1025 | is_040_or_060(L(spata68040)) | ||
1026 | |||
1027 | /* Map everything non-cacheable, though not all parts really | ||
1028 | * need to disable caches (crucial only for 0xff8000..0xffffff | ||
1029 | * (standard I/O) and 0xf00000..0xf3ffff (IDE)). The remainder | ||
1030 | * isn't really used, except for sometimes peeking into the | ||
1031 | * ROMs (mirror at phys. 0x0), so caching isn't necessary for | ||
1032 | * this. */ | ||
1033 | mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE030 | ||
1034 | |||
1035 | jbra L(mmu_init_done) | ||
1036 | |||
1037 | L(spata68040): | ||
1038 | |||
1039 | mmu_map #0xff000000,%d3,#0x01000000,#_PAGE_NOCACHE_S | ||
1040 | |||
1041 | jbra L(mmu_init_done) | ||
1042 | |||
1043 | L(mmu_init_not_atari): | ||
1044 | #endif | ||
1045 | |||
1046 | #ifdef CONFIG_Q40 | ||
1047 | is_not_q40(L(notq40)) | ||
1048 | /* | ||
1049 | * add transparent mapping for 0xff00 0000 - 0xffff ffff | ||
1050 | * non-cached serialized etc.. | ||
1051 | * this includes master chip, DAC, RTC and ISA ports | ||
1052 | * 0xfe000000-0xfeffffff is for screen and ROM | ||
1053 | */ | ||
1054 | |||
1055 | putc 'Q' | ||
1056 | |||
1057 | mmu_map_tt #0,#0xfe000000,#0x01000000,#_PAGE_CACHE040W | ||
1058 | mmu_map_tt #1,#0xff000000,#0x01000000,#_PAGE_NOCACHE_S | ||
1059 | |||
1060 | jbra L(mmu_init_done) | ||
1061 | |||
1062 | L(notq40): | ||
1063 | #endif | ||
1064 | |||
1065 | #ifdef CONFIG_HP300 | ||
1066 | is_not_hp300(L(nothp300)) | ||
1067 | |||
1068 | /* On the HP300, we map the ROM, INTIO and DIO regions (phys. 0x00xxxxxx) | ||
1069 | * by mapping 32MB (on 020/030) or 16 MB (on 040) from 0xf0xxxxxx -> 0x00xxxxxx). | ||
1070 | * The ROM mapping is needed because the LEDs are mapped there too. | ||
1071 | */ | ||
1072 | |||
1073 | is_040(1f) | ||
1074 | |||
1075 | /* | ||
1076 | * 030: Map the 32Meg range physical 0x0 upto logical 0xf000.0000 | ||
1077 | */ | ||
1078 | mmu_map #0xf0000000,#0,#0x02000000,#_PAGE_NOCACHE030 | ||
1079 | |||
1080 | jbra L(mmu_init_done) | ||
1081 | |||
1082 | 1: | ||
1083 | /* | ||
1084 | * 040: Map the 16Meg range physical 0x0 upto logical 0xf000.0000 | ||
1085 | */ | ||
1086 | mmu_map #0xf0000000,#0,#0x01000000,#_PAGE_NOCACHE_S | ||
1087 | |||
1088 | jbra L(mmu_init_done) | ||
1089 | |||
1090 | L(nothp300): | ||
1091 | #endif /* CONFIG_HP300 */ | ||
1092 | |||
1093 | #ifdef CONFIG_MVME147 | ||
1094 | |||
1095 | is_not_mvme147(L(not147)) | ||
1096 | |||
1097 | /* | ||
1098 | * On MVME147 we have already created kernel page tables for | ||
1099 | * 4MB of RAM at address 0, so now need to do a transparent | ||
1100 | * mapping of the top of memory space. Make it 0.5GByte for now, | ||
1101 | * so we can access on-board i/o areas. | ||
1102 | */ | ||
1103 | |||
1104 | mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE030 | ||
1105 | |||
1106 | jbra L(mmu_init_done) | ||
1107 | |||
1108 | L(not147): | ||
1109 | #endif /* CONFIG_MVME147 */ | ||
1110 | |||
1111 | #ifdef CONFIG_MVME16x | ||
1112 | |||
1113 | is_not_mvme16x(L(not16x)) | ||
1114 | |||
1115 | /* | ||
1116 | * On MVME16x we have already created kernel page tables for | ||
1117 | * 4MB of RAM at address 0, so now need to do a transparent | ||
1118 | * mapping of the top of memory space. Make it 0.5GByte for now. | ||
1119 | * Supervisor only access, so transparent mapping doesn't | ||
1120 | * clash with User code virtual address space. | ||
1121 | * this covers IO devices, PROM and SRAM. The PROM and SRAM | ||
1122 | * mapping is needed to allow 167Bug to run. | ||
1123 | * IO is in the range 0xfff00000 to 0xfffeffff. | ||
1124 | * PROM is 0xff800000->0xffbfffff and SRAM is | ||
1125 | * 0xffe00000->0xffe1ffff. | ||
1126 | */ | ||
1127 | |||
1128 | mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S | ||
1129 | |||
1130 | jbra L(mmu_init_done) | ||
1131 | |||
1132 | L(not16x): | ||
1133 | #endif /* CONFIG_MVME162 | CONFIG_MVME167 */ | ||
1134 | |||
1135 | #ifdef CONFIG_BVME6000 | ||
1136 | |||
1137 | is_not_bvme6000(L(not6000)) | ||
1138 | |||
1139 | /* | ||
1140 | * On BVME6000 we have already created kernel page tables for | ||
1141 | * 4MB of RAM at address 0, so now need to do a transparent | ||
1142 | * mapping of the top of memory space. Make it 0.5GByte for now, | ||
1143 | * so we can access on-board i/o areas. | ||
1144 | * Supervisor only access, so transparent mapping doesn't | ||
1145 | * clash with User code virtual address space. | ||
1146 | */ | ||
1147 | |||
1148 | mmu_map_tt #1,#0xe0000000,#0x20000000,#_PAGE_NOCACHE_S | ||
1149 | |||
1150 | jbra L(mmu_init_done) | ||
1151 | |||
1152 | L(not6000): | ||
1153 | #endif /* CONFIG_BVME6000 */ | ||
1154 | |||
1155 | /* | ||
1156 | * mmu_init_mac | ||
1157 | * | ||
1158 | * The Macintosh mappings are less clear. | ||
1159 | * | ||
1160 | * Even as of this writing, it is unclear how the | ||
1161 | * Macintosh mappings will be done. However, as | ||
1162 | * the first author of this code I'm proposing the | ||
1163 | * following model: | ||
1164 | * | ||
1165 | * Map the kernel (that's already done), | ||
1166 | * Map the I/O (on most machines that's the | ||
1167 | * 0x5000.0000 ... 0x5300.0000 range, | ||
1168 | * Map the video frame buffer using as few pages | ||
1169 | * as absolutely (this requirement mostly stems from | ||
1170 | * the fact that when the frame buffer is at | ||
1171 | * 0x0000.0000 then we know there is valid RAM just | ||
1172 | * above the screen that we don't want to waste!). | ||
1173 | * | ||
1174 | * By the way, if the frame buffer is at 0x0000.0000 | ||
1175 | * then the Macintosh is known as an RBV based Mac. | ||
1176 | * | ||
1177 | * By the way 2, the code currently maps in a bunch of | ||
1178 | * regions. But I'd like to cut that out. (And move most | ||
1179 | * of the mappings up into the kernel proper ... or only | ||
1180 | * map what's necessary.) | ||
1181 | */ | ||
1182 | |||
1183 | #ifdef CONFIG_MAC | ||
1184 | |||
1185 | L(mmu_init_mac): | ||
1186 | |||
1187 | is_not_mac(L(mmu_init_not_mac)) | ||
1188 | |||
1189 | putc 'F' | ||
1190 | |||
1191 | is_not_040_or_060(1f) | ||
1192 | |||
1193 | moveq #_PAGE_NOCACHE_S,%d3 | ||
1194 | jbra 2f | ||
1195 | 1: | ||
1196 | moveq #_PAGE_NOCACHE030,%d3 | ||
1197 | 2: | ||
1198 | /* | ||
1199 | * Mac Note: screen address of logical 0xF000.0000 -> <screen physical> | ||
1200 | * we simply map the 4MB that contains the videomem | ||
1201 | */ | ||
1202 | |||
1203 | movel #VIDEOMEMMASK,%d0 | ||
1204 | andl %pc@(L(mac_videobase)),%d0 | ||
1205 | |||
1206 | mmu_map #VIDEOMEMBASE,%d0,#VIDEOMEMSIZE,%d3 | ||
1207 | /* ROM from 4000 0000 to 4200 0000 (only for mac_reset()) */ | ||
1208 | mmu_map_eq #0x40000000,#0x02000000,%d3 | ||
1209 | /* IO devices (incl. serial port) from 5000 0000 to 5300 0000 */ | ||
1210 | mmu_map_eq #0x50000000,#0x03000000,%d3 | ||
1211 | /* Nubus slot space (video at 0xF0000000, rom at 0xF0F80000) */ | ||
1212 | mmu_map_tt #1,#0xf8000000,#0x08000000,%d3 | ||
1213 | |||
1214 | jbra L(mmu_init_done) | ||
1215 | |||
1216 | L(mmu_init_not_mac): | ||
1217 | #endif | ||
1218 | |||
1219 | #ifdef CONFIG_SUN3X | ||
1220 | is_not_sun3x(L(notsun3x)) | ||
1221 | |||
1222 | /* oh, the pain.. We're gonna want the prom code after | ||
1223 | * starting the MMU, so we copy the mappings, translating | ||
1224 | * from 8k -> 4k pages as we go. | ||
1225 | */ | ||
1226 | |||
1227 | /* copy maps from 0xfee00000 to 0xff000000 */ | ||
1228 | movel #0xfee00000, %d0 | ||
1229 | moveq #ROOT_INDEX_SHIFT, %d1 | ||
1230 | lsrl %d1,%d0 | ||
1231 | mmu_get_root_table_entry %d0 | ||
1232 | |||
1233 | movel #0xfee00000, %d0 | ||
1234 | moveq #PTR_INDEX_SHIFT, %d1 | ||
1235 | lsrl %d1,%d0 | ||
1236 | andl #PTR_TABLE_SIZE-1, %d0 | ||
1237 | mmu_get_ptr_table_entry %a0,%d0 | ||
1238 | |||
1239 | movel #0xfee00000, %d0 | ||
1240 | moveq #PAGE_INDEX_SHIFT, %d1 | ||
1241 | lsrl %d1,%d0 | ||
1242 | andl #PAGE_TABLE_SIZE-1, %d0 | ||
1243 | mmu_get_page_table_entry %a0,%d0 | ||
1244 | |||
1245 | /* this is where the prom page table lives */ | ||
1246 | movel 0xfefe00d4, %a1 | ||
1247 | movel %a1@, %a1 | ||
1248 | |||
1249 | movel #((0x200000 >> 13)-1), %d1 | ||
1250 | |||
1251 | 1: | ||
1252 | movel %a1@+, %d3 | ||
1253 | movel %d3,%a0@+ | ||
1254 | addl #0x1000,%d3 | ||
1255 | movel %d3,%a0@+ | ||
1256 | |||
1257 | dbra %d1,1b | ||
1258 | |||
1259 | /* setup tt1 for I/O */ | ||
1260 | mmu_map_tt #1,#0x40000000,#0x40000000,#_PAGE_NOCACHE_S | ||
1261 | jbra L(mmu_init_done) | ||
1262 | |||
1263 | L(notsun3x): | ||
1264 | #endif | ||
1265 | |||
1266 | #ifdef CONFIG_APOLLO | ||
1267 | is_not_apollo(L(notapollo)) | ||
1268 | |||
1269 | putc 'P' | ||
1270 | mmu_map #0x80000000,#0,#0x02000000,#_PAGE_NOCACHE030 | ||
1271 | |||
1272 | L(notapollo): | ||
1273 | jbra L(mmu_init_done) | ||
1274 | #endif | ||
1275 | |||
1276 | L(mmu_init_done): | ||
1277 | |||
1278 | putc 'G' | ||
1279 | leds 0x8 | ||
1280 | |||
1281 | /* | ||
1282 | * mmu_fixup | ||
1283 | * | ||
1284 | * On the 040 class machines, all pages that are used for the | ||
1285 | * mmu have to be fixed up. According to Motorola, pages holding mmu | ||
1286 | * tables should be non-cacheable on a '040 and write-through on a | ||
1287 | * '060. But analysis of the reasons for this, and practical | ||
1288 | * experience, showed that write-through also works on a '040. | ||
1289 | * | ||
1290 | * Allocated memory so far goes from kernel_end to memory_start that | ||
1291 | * is used for all kind of tables, for that the cache attributes | ||
1292 | * are now fixed. | ||
1293 | */ | ||
1294 | L(mmu_fixup): | ||
1295 | |||
1296 | is_not_040_or_060(L(mmu_fixup_done)) | ||
1297 | |||
1298 | #ifdef MMU_NOCACHE_KERNEL | ||
1299 | jbra L(mmu_fixup_done) | ||
1300 | #endif | ||
1301 | |||
1302 | /* first fix the page at the start of the kernel, that | ||
1303 | * contains also kernel_pg_dir. | ||
1304 | */ | ||
1305 | movel %pc@(L(phys_kernel_start)),%d0 | ||
1306 | subl #PAGE_OFFSET,%d0 | ||
1307 | lea %pc@(_stext),%a0 | ||
1308 | subl %d0,%a0 | ||
1309 | mmu_fixup_page_mmu_cache %a0 | ||
1310 | |||
1311 | movel %pc@(L(kernel_end)),%a0 | ||
1312 | subl %d0,%a0 | ||
1313 | movel %pc@(L(memory_start)),%a1 | ||
1314 | subl %d0,%a1 | ||
1315 | bra 2f | ||
1316 | 1: | ||
1317 | mmu_fixup_page_mmu_cache %a0 | ||
1318 | addw #PAGESIZE,%a0 | ||
1319 | 2: | ||
1320 | cmpl %a0,%a1 | ||
1321 | jgt 1b | ||
1322 | |||
1323 | L(mmu_fixup_done): | ||
1324 | |||
1325 | #ifdef MMU_PRINT | ||
1326 | mmu_print | ||
1327 | #endif | ||
1328 | |||
1329 | /* | ||
1330 | * mmu_engage | ||
1331 | * | ||
1332 | * This chunk of code performs the gruesome task of engaging the MMU. | ||
1333 | * The reason its gruesome is because when the MMU becomes engaged it | ||
1334 | * maps logical addresses to physical addresses. The Program Counter | ||
1335 | * register is then passed through the MMU before the next instruction | ||
1336 | * is fetched (the instruction following the engage MMU instruction). | ||
1337 | * This may mean one of two things: | ||
1338 | * 1. The Program Counter falls within the logical address space of | ||
1339 | * the kernel of which there are two sub-possibilities: | ||
1340 | * A. The PC maps to the correct instruction (logical PC == physical | ||
1341 | * code location), or | ||
1342 | * B. The PC does not map through and the processor will read some | ||
1343 | * data (or instruction) which is not the logically next instr. | ||
1344 | * As you can imagine, A is good and B is bad. | ||
1345 | * Alternatively, | ||
1346 | * 2. The Program Counter does not map through the MMU. The processor | ||
1347 | * will take a Bus Error. | ||
1348 | * Clearly, 2 is bad. | ||
1349 | * It doesn't take a wiz kid to figure you want 1.A. | ||
1350 | * This code creates that possibility. | ||
1351 | * There are two possible 1.A. states (we now ignore the other above states): | ||
1352 | * A. The kernel is located at physical memory addressed the same as | ||
1353 | * the logical memory for the kernel, i.e., 0x01000. | ||
1354 | * B. The kernel is located some where else. e.g., 0x0400.0000 | ||
1355 | * | ||
1356 | * Under some conditions the Macintosh can look like A or B. | ||
1357 | * [A friend and I once noted that Apple hardware engineers should be | ||
1358 | * wacked twice each day: once when they show up at work (as in, Whack!, | ||
1359 | * "This is for the screwy hardware we know you're going to design today."), | ||
1360 | * and also at the end of the day (as in, Whack! "I don't know what | ||
1361 | * you designed today, but I'm sure it wasn't good."). -- rst] | ||
1362 | * | ||
1363 | * This code works on the following premise: | ||
1364 | * If the kernel start (%d5) is within the first 16 Meg of RAM, | ||
1365 | * then create a mapping for the kernel at logical 0x8000.0000 to | ||
1366 | * the physical location of the pc. And, create a transparent | ||
1367 | * translation register for the first 16 Meg. Then, after the MMU | ||
1368 | * is engaged, the PC can be moved up into the 0x8000.0000 range | ||
1369 | * and then the transparent translation can be turned off and then | ||
1370 | * the PC can jump to the correct logical location and it will be | ||
1371 | * home (finally). This is essentially the code that the Amiga used | ||
1372 | * to use. Now, it's generalized for all processors. Which means | ||
1373 | * that a fresh (but temporary) mapping has to be created. The mapping | ||
1374 | * is made in page 0 (an as of yet unused location -- except for the | ||
1375 | * stack!). This temporary mapping will only require 1 pointer table | ||
1376 | * and a single page table (it can map 256K). | ||
1377 | * | ||
1378 | * OK, alternatively, imagine that the Program Counter is not within | ||
1379 | * the first 16 Meg. Then, just use Transparent Translation registers | ||
1380 | * to do the right thing. | ||
1381 | * | ||
1382 | * Last, if _start is already at 0x01000, then there's nothing special | ||
1383 | * to do (in other words, in a degenerate case of the first case above, | ||
1384 | * do nothing). | ||
1385 | * | ||
1386 | * Let's do it. | ||
1387 | * | ||
1388 | * | ||
1389 | */ | ||
1390 | |||
1391 | putc 'H' | ||
1392 | |||
1393 | mmu_engage | ||
1394 | |||
1395 | /* | ||
1396 | * After this point no new memory is allocated and | ||
1397 | * the start of available memory is stored in availmem. | ||
1398 | * (The bootmem allocator requires now the physicall address.) | ||
1399 | */ | ||
1400 | |||
1401 | movel L(memory_start),availmem | ||
1402 | |||
1403 | #ifdef CONFIG_AMIGA | ||
1404 | is_not_amiga(1f) | ||
1405 | /* fixup the Amiga custom register location before printing */ | ||
1406 | clrl L(custom) | ||
1407 | 1: | ||
1408 | #endif | ||
1409 | |||
1410 | #ifdef CONFIG_ATARI | ||
1411 | is_not_atari(1f) | ||
1412 | /* fixup the Atari iobase register location before printing */ | ||
1413 | movel #0xff000000,L(iobase) | ||
1414 | 1: | ||
1415 | #endif | ||
1416 | |||
1417 | #ifdef CONFIG_MAC | ||
1418 | is_not_mac(1f) | ||
1419 | movel #~VIDEOMEMMASK,%d0 | ||
1420 | andl L(mac_videobase),%d0 | ||
1421 | addl #VIDEOMEMBASE,%d0 | ||
1422 | movel %d0,L(mac_videobase) | ||
1423 | #if defined(CONSOLE) | ||
1424 | movel %pc@(L(phys_kernel_start)),%d0 | ||
1425 | subl #PAGE_OFFSET,%d0 | ||
1426 | subl %d0,L(console_font) | ||
1427 | subl %d0,L(console_font_data) | ||
1428 | #endif | ||
1429 | #ifdef MAC_SERIAL_DEBUG | ||
1430 | orl #0x50000000,L(mac_sccbase) | ||
1431 | #endif | ||
1432 | 1: | ||
1433 | #endif | ||
1434 | |||
1435 | #ifdef CONFIG_HP300 | ||
1436 | is_not_hp300(1f) | ||
1437 | /* | ||
1438 | * Fix up the iobase register to point to the new location of the LEDs. | ||
1439 | */ | ||
1440 | movel #0xf0000000,L(iobase) | ||
1441 | |||
1442 | /* | ||
1443 | * Energise the FPU and caches. | ||
1444 | */ | ||
1445 | is_040(1f) | ||
1446 | movel #0x60,0xf05f400c | ||
1447 | jbra 2f | ||
1448 | |||
1449 | /* | ||
1450 | * 040: slightly different, apparently. | ||
1451 | */ | ||
1452 | 1: movew #0,0xf05f400e | ||
1453 | movew #0x64,0xf05f400e | ||
1454 | 2: | ||
1455 | #endif | ||
1456 | |||
1457 | #ifdef CONFIG_SUN3X | ||
1458 | is_not_sun3x(1f) | ||
1459 | |||
1460 | /* enable copro */ | ||
1461 | oriw #0x4000,0x61000000 | ||
1462 | 1: | ||
1463 | #endif | ||
1464 | |||
1465 | #ifdef CONFIG_APOLLO | ||
1466 | is_not_apollo(1f) | ||
1467 | |||
1468 | /* | ||
1469 | * Fix up the iobase before printing | ||
1470 | */ | ||
1471 | movel #0x80000000,L(iobase) | ||
1472 | 1: | ||
1473 | #endif | ||
1474 | |||
1475 | putc 'I' | ||
1476 | leds 0x10 | ||
1477 | |||
1478 | /* | ||
1479 | * Enable caches | ||
1480 | */ | ||
1481 | |||
1482 | is_not_040_or_060(L(cache_not_680460)) | ||
1483 | |||
1484 | L(cache680460): | ||
1485 | .chip 68040 | ||
1486 | nop | ||
1487 | cpusha %bc | ||
1488 | nop | ||
1489 | |||
1490 | is_060(L(cache68060)) | ||
1491 | |||
1492 | movel #CC6_ENABLE_D+CC6_ENABLE_I,%d0 | ||
1493 | /* MMU stuff works in copyback mode now, so enable the cache */ | ||
1494 | movec %d0,%cacr | ||
1495 | jra L(cache_done) | ||
1496 | |||
1497 | L(cache68060): | ||
1498 | movel #CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0 | ||
1499 | /* MMU stuff works in copyback mode now, so enable the cache */ | ||
1500 | movec %d0,%cacr | ||
1501 | /* enable superscalar dispatch in PCR */ | ||
1502 | moveq #1,%d0 | ||
1503 | .chip 68060 | ||
1504 | movec %d0,%pcr | ||
1505 | |||
1506 | jbra L(cache_done) | ||
1507 | L(cache_not_680460): | ||
1508 | L(cache68030): | ||
1509 | .chip 68030 | ||
1510 | movel #CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0 | ||
1511 | movec %d0,%cacr | ||
1512 | |||
1513 | jra L(cache_done) | ||
1514 | .chip 68k | ||
1515 | L(cache_done): | ||
1516 | |||
1517 | putc 'J' | ||
1518 | |||
1519 | /* | ||
1520 | * Setup initial stack pointer | ||
1521 | */ | ||
1522 | lea init_task,%curptr | ||
1523 | lea init_thread_union+THREAD_SIZE,%sp | ||
1524 | |||
1525 | putc 'K' | ||
1526 | |||
1527 | subl %a6,%a6 /* clear a6 for gdb */ | ||
1528 | |||
1529 | /* | ||
1530 | * The new 64bit printf support requires an early exception initialization. | ||
1531 | */ | ||
1532 | jbsr base_trap_init | ||
1533 | |||
1534 | /* jump to the kernel start */ | ||
1535 | |||
1536 | putc '\n' | ||
1537 | leds 0x55 | ||
1538 | |||
1539 | jbsr start_kernel | ||
1540 | |||
1541 | /* | ||
1542 | * Find a tag record in the bootinfo structure | ||
1543 | * The bootinfo structure is located right after the kernel bss | ||
1544 | * Returns: d0: size (-1 if not found) | ||
1545 | * a0: data pointer (end-of-records if not found) | ||
1546 | */ | ||
1547 | func_start get_bi_record,%d1 | ||
1548 | |||
1549 | movel ARG1,%d0 | ||
1550 | lea %pc@(_end),%a0 | ||
1551 | 1: tstw %a0@(BIR_TAG) | ||
1552 | jeq 3f | ||
1553 | cmpw %a0@(BIR_TAG),%d0 | ||
1554 | jeq 2f | ||
1555 | addw %a0@(BIR_SIZE),%a0 | ||
1556 | jra 1b | ||
1557 | 2: moveq #0,%d0 | ||
1558 | movew %a0@(BIR_SIZE),%d0 | ||
1559 | lea %a0@(BIR_DATA),%a0 | ||
1560 | jra 4f | ||
1561 | 3: moveq #-1,%d0 | ||
1562 | lea %a0@(BIR_SIZE),%a0 | ||
1563 | 4: | ||
1564 | func_return get_bi_record | ||
1565 | |||
1566 | |||
1567 | /* | ||
1568 | * MMU Initialization Begins Here | ||
1569 | * | ||
1570 | * The structure of the MMU tables on the 68k machines | ||
1571 | * is thus: | ||
1572 | * Root Table | ||
1573 | * Logical addresses are translated through | ||
1574 | * a hierarchical translation mechanism where the high-order | ||
1575 | * seven bits of the logical address (LA) are used as an | ||
1576 | * index into the "root table." Each entry in the root | ||
1577 | * table has a bit which specifies if it's a valid pointer to a | ||
1578 | * pointer table. Each entry defines a 32KMeg range of memory. | ||
1579 | * If an entry is invalid then that logical range of 32M is | ||
1580 | * invalid and references to that range of memory (when the MMU | ||
1581 | * is enabled) will fault. If the entry is valid, then it does | ||
1582 | * one of two things. On 040/060 class machines, it points to | ||
1583 | * a pointer table which then describes more finely the memory | ||
1584 | * within that 32M range. On 020/030 class machines, a technique | ||
1585 | * called "early terminating descriptors" are used. This technique | ||
1586 | * allows an entire 32Meg to be described by a single entry in the | ||
1587 | * root table. Thus, this entry in the root table, contains the | ||
1588 | * physical address of the memory or I/O at the logical address | ||
1589 | * which the entry represents and it also contains the necessary | ||
1590 | * cache bits for this region. | ||
1591 | * | ||
1592 | * Pointer Tables | ||
1593 | * Per the Root Table, there will be one or more | ||
1594 | * pointer tables. Each pointer table defines a 32M range. | ||
1595 | * Not all of the 32M range need be defined. Again, the next | ||
1596 | * seven bits of the logical address are used an index into | ||
1597 | * the pointer table to point to page tables (if the pointer | ||
1598 | * is valid). There will undoubtedly be more than one | ||
1599 | * pointer table for the kernel because each pointer table | ||
1600 | * defines a range of only 32M. Valid pointer table entries | ||
1601 | * point to page tables, or are early terminating entries | ||
1602 | * themselves. | ||
1603 | * | ||
1604 | * Page Tables | ||
1605 | * Per the Pointer Tables, each page table entry points | ||
1606 | * to the physical page in memory that supports the logical | ||
1607 | * address that translates to the particular index. | ||
1608 | * | ||
1609 | * In short, the Logical Address gets translated as follows: | ||
1610 | * bits 31..26 - index into the Root Table | ||
1611 | * bits 25..18 - index into the Pointer Table | ||
1612 | * bits 17..12 - index into the Page Table | ||
1613 | * bits 11..0 - offset into a particular 4K page | ||
1614 | * | ||
1615 | * The algorithms which follows do one thing: they abstract | ||
1616 | * the MMU hardware. For example, there are three kinds of | ||
1617 | * cache settings that are relevant. Either, memory is | ||
1618 | * being mapped in which case it is either Kernel Code (or | ||
1619 | * the RamDisk) or it is MMU data. On the 030, the MMU data | ||
1620 | * option also describes the kernel. Or, I/O is being mapped | ||
1621 | * in which case it has its own kind of cache bits. There | ||
1622 | * are constants which abstract these notions from the code that | ||
1623 | * actually makes the call to map some range of memory. | ||
1624 | * | ||
1625 | * | ||
1626 | * | ||
1627 | */ | ||
1628 | |||
1629 | #ifdef MMU_PRINT | ||
1630 | /* | ||
1631 | * mmu_print | ||
1632 | * | ||
1633 | * This algorithm will print out the current MMU mappings. | ||
1634 | * | ||
1635 | * Input: | ||
1636 | * %a5 points to the root table. Everything else is calculated | ||
1637 | * from this. | ||
1638 | */ | ||
1639 | |||
1640 | #define mmu_next_valid 0 | ||
1641 | #define mmu_start_logical 4 | ||
1642 | #define mmu_next_logical 8 | ||
1643 | #define mmu_start_physical 12 | ||
1644 | #define mmu_next_physical 16 | ||
1645 | |||
1646 | #define MMU_PRINT_INVALID -1 | ||
1647 | #define MMU_PRINT_VALID 1 | ||
1648 | #define MMU_PRINT_UNINITED 0 | ||
1649 | |||
1650 | #define putZc(z,n) jbne 1f; putc z; jbra 2f; 1: putc n; 2: | ||
1651 | |||
1652 | func_start mmu_print,%a0-%a6/%d0-%d7 | ||
1653 | |||
1654 | movel %pc@(L(kernel_pgdir_ptr)),%a5 | ||
1655 | lea %pc@(L(mmu_print_data)),%a0 | ||
1656 | movel #MMU_PRINT_UNINITED,%a0@(mmu_next_valid) | ||
1657 | |||
1658 | is_not_040_or_060(mmu_030_print) | ||
1659 | |||
1660 | mmu_040_print: | ||
1661 | puts "\nMMU040\n" | ||
1662 | puts "rp:" | ||
1663 | putn %a5 | ||
1664 | putc '\n' | ||
1665 | #if 0 | ||
1666 | /* | ||
1667 | * The following #if/#endif block is a tight algorithm for dumping the 040 | ||
1668 | * MMU Map in gory detail. It really isn't that practical unless the | ||
1669 | * MMU Map algorithm appears to go awry and you need to debug it at the | ||
1670 | * entry per entry level. | ||
1671 | */ | ||
1672 | movel #ROOT_TABLE_SIZE,%d5 | ||
1673 | #if 0 | ||
1674 | movel %a5@+,%d7 | Burn an entry to skip the kernel mappings, | ||
1675 | subql #1,%d5 | they (might) work | ||
1676 | #endif | ||
1677 | 1: tstl %d5 | ||
1678 | jbeq mmu_print_done | ||
1679 | subq #1,%d5 | ||
1680 | movel %a5@+,%d7 | ||
1681 | btst #1,%d7 | ||
1682 | jbeq 1b | ||
1683 | |||
1684 | 2: putn %d7 | ||
1685 | andil #0xFFFFFE00,%d7 | ||
1686 | movel %d7,%a4 | ||
1687 | movel #PTR_TABLE_SIZE,%d4 | ||
1688 | putc ' ' | ||
1689 | 3: tstl %d4 | ||
1690 | jbeq 11f | ||
1691 | subq #1,%d4 | ||
1692 | movel %a4@+,%d7 | ||
1693 | btst #1,%d7 | ||
1694 | jbeq 3b | ||
1695 | |||
1696 | 4: putn %d7 | ||
1697 | andil #0xFFFFFF00,%d7 | ||
1698 | movel %d7,%a3 | ||
1699 | movel #PAGE_TABLE_SIZE,%d3 | ||
1700 | 5: movel #8,%d2 | ||
1701 | 6: tstl %d3 | ||
1702 | jbeq 31f | ||
1703 | subq #1,%d3 | ||
1704 | movel %a3@+,%d6 | ||
1705 | btst #0,%d6 | ||
1706 | jbeq 6b | ||
1707 | 7: tstl %d2 | ||
1708 | jbeq 8f | ||
1709 | subq #1,%d2 | ||
1710 | putc ' ' | ||
1711 | jbra 91f | ||
1712 | 8: putc '\n' | ||
1713 | movel #8+1+8+1+1,%d2 | ||
1714 | 9: putc ' ' | ||
1715 | dbra %d2,9b | ||
1716 | movel #7,%d2 | ||
1717 | 91: putn %d6 | ||
1718 | jbra 6b | ||
1719 | |||
1720 | 31: putc '\n' | ||
1721 | movel #8+1,%d2 | ||
1722 | 32: putc ' ' | ||
1723 | dbra %d2,32b | ||
1724 | jbra 3b | ||
1725 | |||
1726 | 11: putc '\n' | ||
1727 | jbra 1b | ||
1728 | #endif /* MMU 040 Dumping code that's gory and detailed */ | ||
1729 | |||
1730 | lea %pc@(kernel_pg_dir),%a5 | ||
1731 | movel %a5,%a0 /* a0 has the address of the root table ptr */ | ||
1732 | movel #0x00000000,%a4 /* logical address */ | ||
1733 | moveql #0,%d0 | ||
1734 | 40: | ||
1735 | /* Increment the logical address and preserve in d5 */ | ||
1736 | movel %a4,%d5 | ||
1737 | addil #PAGESIZE<<13,%d5 | ||
1738 | movel %a0@+,%d6 | ||
1739 | btst #1,%d6 | ||
1740 | jbne 41f | ||
1741 | jbsr mmu_print_tuple_invalidate | ||
1742 | jbra 48f | ||
1743 | 41: | ||
1744 | movel #0,%d1 | ||
1745 | andil #0xfffffe00,%d6 | ||
1746 | movel %d6,%a1 | ||
1747 | 42: | ||
1748 | movel %a4,%d5 | ||
1749 | addil #PAGESIZE<<6,%d5 | ||
1750 | movel %a1@+,%d6 | ||
1751 | btst #1,%d6 | ||
1752 | jbne 43f | ||
1753 | jbsr mmu_print_tuple_invalidate | ||
1754 | jbra 47f | ||
1755 | 43: | ||
1756 | movel #0,%d2 | ||
1757 | andil #0xffffff00,%d6 | ||
1758 | movel %d6,%a2 | ||
1759 | 44: | ||
1760 | movel %a4,%d5 | ||
1761 | addil #PAGESIZE,%d5 | ||
1762 | movel %a2@+,%d6 | ||
1763 | btst #0,%d6 | ||
1764 | jbne 45f | ||
1765 | jbsr mmu_print_tuple_invalidate | ||
1766 | jbra 46f | ||
1767 | 45: | ||
1768 | moveml %d0-%d1,%sp@- | ||
1769 | movel %a4,%d0 | ||
1770 | movel %d6,%d1 | ||
1771 | andil #0xfffff4e0,%d1 | ||
1772 | lea %pc@(mmu_040_print_flags),%a6 | ||
1773 | jbsr mmu_print_tuple | ||
1774 | moveml %sp@+,%d0-%d1 | ||
1775 | 46: | ||
1776 | movel %d5,%a4 | ||
1777 | addq #1,%d2 | ||
1778 | cmpib #64,%d2 | ||
1779 | jbne 44b | ||
1780 | 47: | ||
1781 | movel %d5,%a4 | ||
1782 | addq #1,%d1 | ||
1783 | cmpib #128,%d1 | ||
1784 | jbne 42b | ||
1785 | 48: | ||
1786 | movel %d5,%a4 /* move to the next logical address */ | ||
1787 | addq #1,%d0 | ||
1788 | cmpib #128,%d0 | ||
1789 | jbne 40b | ||
1790 | |||
1791 | .chip 68040 | ||
1792 | movec %dtt1,%d0 | ||
1793 | movel %d0,%d1 | ||
1794 | andiw #0x8000,%d1 /* is it valid ? */ | ||
1795 | jbeq 1f /* No, bail out */ | ||
1796 | |||
1797 | movel %d0,%d1 | ||
1798 | andil #0xff000000,%d1 /* Get the address */ | ||
1799 | putn %d1 | ||
1800 | puts "==" | ||
1801 | putn %d1 | ||
1802 | |||
1803 | movel %d0,%d6 | ||
1804 | jbsr mmu_040_print_flags_tt | ||
1805 | 1: | ||
1806 | movec %dtt0,%d0 | ||
1807 | movel %d0,%d1 | ||
1808 | andiw #0x8000,%d1 /* is it valid ? */ | ||
1809 | jbeq 1f /* No, bail out */ | ||
1810 | |||
1811 | movel %d0,%d1 | ||
1812 | andil #0xff000000,%d1 /* Get the address */ | ||
1813 | putn %d1 | ||
1814 | puts "==" | ||
1815 | putn %d1 | ||
1816 | |||
1817 | movel %d0,%d6 | ||
1818 | jbsr mmu_040_print_flags_tt | ||
1819 | 1: | ||
1820 | .chip 68k | ||
1821 | |||
1822 | jbra mmu_print_done | ||
1823 | |||
1824 | mmu_040_print_flags: | ||
1825 | btstl #10,%d6 | ||
1826 | putZc(' ','G') /* global bit */ | ||
1827 | btstl #7,%d6 | ||
1828 | putZc(' ','S') /* supervisor bit */ | ||
1829 | mmu_040_print_flags_tt: | ||
1830 | btstl #6,%d6 | ||
1831 | jbne 3f | ||
1832 | putc 'C' | ||
1833 | btstl #5,%d6 | ||
1834 | putZc('w','c') /* write through or copy-back */ | ||
1835 | jbra 4f | ||
1836 | 3: | ||
1837 | putc 'N' | ||
1838 | btstl #5,%d6 | ||
1839 | putZc('s',' ') /* serialized non-cacheable, or non-cacheable */ | ||
1840 | 4: | ||
1841 | rts | ||
1842 | |||
1843 | mmu_030_print_flags: | ||
1844 | btstl #6,%d6 | ||
1845 | putZc('C','I') /* write through or copy-back */ | ||
1846 | rts | ||
1847 | |||
1848 | mmu_030_print: | ||
1849 | puts "\nMMU030\n" | ||
1850 | puts "\nrp:" | ||
1851 | putn %a5 | ||
1852 | putc '\n' | ||
1853 | movel %a5,%d0 | ||
1854 | andil #0xfffffff0,%d0 | ||
1855 | movel %d0,%a0 | ||
1856 | movel #0x00000000,%a4 /* logical address */ | ||
1857 | movel #0,%d0 | ||
1858 | 30: | ||
1859 | movel %a4,%d5 | ||
1860 | addil #PAGESIZE<<13,%d5 | ||
1861 | movel %a0@+,%d6 | ||
1862 | btst #1,%d6 /* is it a table ptr? */ | ||
1863 | jbne 31f /* yes */ | ||
1864 | btst #0,%d6 /* is it early terminating? */ | ||
1865 | jbeq 1f /* no */ | ||
1866 | jbsr mmu_030_print_helper | ||
1867 | jbra 38f | ||
1868 | 1: | ||
1869 | jbsr mmu_print_tuple_invalidate | ||
1870 | jbra 38f | ||
1871 | 31: | ||
1872 | movel #0,%d1 | ||
1873 | andil #0xfffffff0,%d6 | ||
1874 | movel %d6,%a1 | ||
1875 | 32: | ||
1876 | movel %a4,%d5 | ||
1877 | addil #PAGESIZE<<6,%d5 | ||
1878 | movel %a1@+,%d6 | ||
1879 | btst #1,%d6 /* is it a table ptr? */ | ||
1880 | jbne 33f /* yes */ | ||
1881 | btst #0,%d6 /* is it a page descriptor? */ | ||
1882 | jbeq 1f /* no */ | ||
1883 | jbsr mmu_030_print_helper | ||
1884 | jbra 37f | ||
1885 | 1: | ||
1886 | jbsr mmu_print_tuple_invalidate | ||
1887 | jbra 37f | ||
1888 | 33: | ||
1889 | movel #0,%d2 | ||
1890 | andil #0xfffffff0,%d6 | ||
1891 | movel %d6,%a2 | ||
1892 | 34: | ||
1893 | movel %a4,%d5 | ||
1894 | addil #PAGESIZE,%d5 | ||
1895 | movel %a2@+,%d6 | ||
1896 | btst #0,%d6 | ||
1897 | jbne 35f | ||
1898 | jbsr mmu_print_tuple_invalidate | ||
1899 | jbra 36f | ||
1900 | 35: | ||
1901 | jbsr mmu_030_print_helper | ||
1902 | 36: | ||
1903 | movel %d5,%a4 | ||
1904 | addq #1,%d2 | ||
1905 | cmpib #64,%d2 | ||
1906 | jbne 34b | ||
1907 | 37: | ||
1908 | movel %d5,%a4 | ||
1909 | addq #1,%d1 | ||
1910 | cmpib #128,%d1 | ||
1911 | jbne 32b | ||
1912 | 38: | ||
1913 | movel %d5,%a4 /* move to the next logical address */ | ||
1914 | addq #1,%d0 | ||
1915 | cmpib #128,%d0 | ||
1916 | jbne 30b | ||
1917 | |||
1918 | mmu_print_done: | ||
1919 | puts "\n\n" | ||
1920 | |||
1921 | func_return mmu_print | ||
1922 | |||
1923 | |||
1924 | mmu_030_print_helper: | ||
1925 | moveml %d0-%d1,%sp@- | ||
1926 | movel %a4,%d0 | ||
1927 | movel %d6,%d1 | ||
1928 | lea %pc@(mmu_030_print_flags),%a6 | ||
1929 | jbsr mmu_print_tuple | ||
1930 | moveml %sp@+,%d0-%d1 | ||
1931 | rts | ||
1932 | |||
1933 | mmu_print_tuple_invalidate: | ||
1934 | moveml %a0/%d7,%sp@- | ||
1935 | |||
1936 | lea %pc@(L(mmu_print_data)),%a0 | ||
1937 | tstl %a0@(mmu_next_valid) | ||
1938 | jbmi mmu_print_tuple_invalidate_exit | ||
1939 | |||
1940 | movel #MMU_PRINT_INVALID,%a0@(mmu_next_valid) | ||
1941 | |||
1942 | putn %a4 | ||
1943 | |||
1944 | puts "##\n" | ||
1945 | |||
1946 | mmu_print_tuple_invalidate_exit: | ||
1947 | moveml %sp@+,%a0/%d7 | ||
1948 | rts | ||
1949 | |||
1950 | |||
1951 | mmu_print_tuple: | ||
1952 | moveml %d0-%d7/%a0,%sp@- | ||
1953 | |||
1954 | lea %pc@(L(mmu_print_data)),%a0 | ||
1955 | |||
1956 | tstl %a0@(mmu_next_valid) | ||
1957 | jble mmu_print_tuple_print | ||
1958 | |||
1959 | cmpl %a0@(mmu_next_physical),%d1 | ||
1960 | jbeq mmu_print_tuple_increment | ||
1961 | |||
1962 | mmu_print_tuple_print: | ||
1963 | putn %d0 | ||
1964 | puts "->" | ||
1965 | putn %d1 | ||
1966 | |||
1967 | movel %d1,%d6 | ||
1968 | jbsr %a6@ | ||
1969 | |||
1970 | mmu_print_tuple_record: | ||
1971 | movel #MMU_PRINT_VALID,%a0@(mmu_next_valid) | ||
1972 | |||
1973 | movel %d1,%a0@(mmu_next_physical) | ||
1974 | |||
1975 | mmu_print_tuple_increment: | ||
1976 | movel %d5,%d7 | ||
1977 | subl %a4,%d7 | ||
1978 | addl %d7,%a0@(mmu_next_physical) | ||
1979 | |||
1980 | mmu_print_tuple_exit: | ||
1981 | moveml %sp@+,%d0-%d7/%a0 | ||
1982 | rts | ||
1983 | |||
1984 | mmu_print_machine_cpu_types: | ||
1985 | puts "machine: " | ||
1986 | |||
1987 | is_not_amiga(1f) | ||
1988 | puts "amiga" | ||
1989 | jbra 9f | ||
1990 | 1: | ||
1991 | is_not_atari(2f) | ||
1992 | puts "atari" | ||
1993 | jbra 9f | ||
1994 | 2: | ||
1995 | is_not_mac(3f) | ||
1996 | puts "macintosh" | ||
1997 | jbra 9f | ||
1998 | 3: puts "unknown" | ||
1999 | 9: putc '\n' | ||
2000 | |||
2001 | puts "cputype: 0" | ||
2002 | is_not_060(1f) | ||
2003 | putc '6' | ||
2004 | jbra 9f | ||
2005 | 1: | ||
2006 | is_not_040_or_060(2f) | ||
2007 | putc '4' | ||
2008 | jbra 9f | ||
2009 | 2: putc '3' | ||
2010 | 9: putc '0' | ||
2011 | putc '\n' | ||
2012 | |||
2013 | rts | ||
2014 | #endif /* MMU_PRINT */ | ||
2015 | |||
2016 | /* | ||
2017 | * mmu_map_tt | ||
2018 | * | ||
2019 | * This is a specific function which works on all 680x0 machines. | ||
2020 | * On 030, 040 & 060 it will attempt to use Transparent Translation | ||
2021 | * registers (tt1). | ||
2022 | * On 020 it will call the standard mmu_map which will use early | ||
2023 | * terminating descriptors. | ||
2024 | */ | ||
2025 | func_start mmu_map_tt,%d0/%d1/%a0,4 | ||
2026 | |||
2027 | dputs "mmu_map_tt:" | ||
2028 | dputn ARG1 | ||
2029 | dputn ARG2 | ||
2030 | dputn ARG3 | ||
2031 | dputn ARG4 | ||
2032 | dputc '\n' | ||
2033 | |||
2034 | is_020(L(do_map)) | ||
2035 | |||
2036 | /* Extract the highest bit set | ||
2037 | */ | ||
2038 | bfffo ARG3{#0,#32},%d1 | ||
2039 | cmpw #8,%d1 | ||
2040 | jcc L(do_map) | ||
2041 | |||
2042 | /* And get the mask | ||
2043 | */ | ||
2044 | moveq #-1,%d0 | ||
2045 | lsrl %d1,%d0 | ||
2046 | lsrl #1,%d0 | ||
2047 | |||
2048 | /* Mask the address | ||
2049 | */ | ||
2050 | movel %d0,%d1 | ||
2051 | notl %d1 | ||
2052 | andl ARG2,%d1 | ||
2053 | |||
2054 | /* Generate the upper 16bit of the tt register | ||
2055 | */ | ||
2056 | lsrl #8,%d0 | ||
2057 | orl %d0,%d1 | ||
2058 | clrw %d1 | ||
2059 | |||
2060 | is_040_or_060(L(mmu_map_tt_040)) | ||
2061 | |||
2062 | /* set 030 specific bits (read/write access for supervisor mode | ||
2063 | * (highest function code set, lower two bits masked)) | ||
2064 | */ | ||
2065 | orw #TTR_ENABLE+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d1 | ||
2066 | movel ARG4,%d0 | ||
2067 | btst #6,%d0 | ||
2068 | jeq 1f | ||
2069 | orw #TTR_CI,%d1 | ||
2070 | |||
2071 | 1: lea STACK,%a0 | ||
2072 | dputn %d1 | ||
2073 | movel %d1,%a0@ | ||
2074 | .chip 68030 | ||
2075 | tstl ARG1 | ||
2076 | jne 1f | ||
2077 | pmove %a0@,%tt0 | ||
2078 | jra 2f | ||
2079 | 1: pmove %a0@,%tt1 | ||
2080 | 2: .chip 68k | ||
2081 | jra L(mmu_map_tt_done) | ||
2082 | |||
2083 | /* set 040 specific bits | ||
2084 | */ | ||
2085 | L(mmu_map_tt_040): | ||
2086 | orw #TTR_ENABLE+TTR_KERNELMODE,%d1 | ||
2087 | orl ARG4,%d1 | ||
2088 | dputn %d1 | ||
2089 | |||
2090 | .chip 68040 | ||
2091 | tstl ARG1 | ||
2092 | jne 1f | ||
2093 | movec %d1,%itt0 | ||
2094 | movec %d1,%dtt0 | ||
2095 | jra 2f | ||
2096 | 1: movec %d1,%itt1 | ||
2097 | movec %d1,%dtt1 | ||
2098 | 2: .chip 68k | ||
2099 | |||
2100 | jra L(mmu_map_tt_done) | ||
2101 | |||
2102 | L(do_map): | ||
2103 | mmu_map_eq ARG2,ARG3,ARG4 | ||
2104 | |||
2105 | L(mmu_map_tt_done): | ||
2106 | |||
2107 | func_return mmu_map_tt | ||
2108 | |||
2109 | /* | ||
2110 | * mmu_map | ||
2111 | * | ||
2112 | * This routine will map a range of memory using a pointer | ||
2113 | * table and allocating the pages on the fly from the kernel. | ||
2114 | * The pointer table does not have to be already linked into | ||
2115 | * the root table, this routine will do that if necessary. | ||
2116 | * | ||
2117 | * NOTE | ||
2118 | * This routine will assert failure and use the serial_putc | ||
2119 | * routines in the case of a run-time error. For example, | ||
2120 | * if the address is already mapped. | ||
2121 | * | ||
2122 | * NOTE-2 | ||
2123 | * This routine will use early terminating descriptors | ||
2124 | * where possible for the 68020+68851 and 68030 type | ||
2125 | * processors. | ||
2126 | */ | ||
2127 | func_start mmu_map,%d0-%d4/%a0-%a4 | ||
2128 | |||
2129 | dputs "\nmmu_map:" | ||
2130 | dputn ARG1 | ||
2131 | dputn ARG2 | ||
2132 | dputn ARG3 | ||
2133 | dputn ARG4 | ||
2134 | dputc '\n' | ||
2135 | |||
2136 | /* Get logical address and round it down to 256KB | ||
2137 | */ | ||
2138 | movel ARG1,%d0 | ||
2139 | andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0 | ||
2140 | movel %d0,%a3 | ||
2141 | |||
2142 | /* Get the end address | ||
2143 | */ | ||
2144 | movel ARG1,%a4 | ||
2145 | addl ARG3,%a4 | ||
2146 | subql #1,%a4 | ||
2147 | |||
2148 | /* Get physical address and round it down to 256KB | ||
2149 | */ | ||
2150 | movel ARG2,%d0 | ||
2151 | andl #-(PAGESIZE*PAGE_TABLE_SIZE),%d0 | ||
2152 | movel %d0,%a2 | ||
2153 | |||
2154 | /* Add page attributes to the physical address | ||
2155 | */ | ||
2156 | movel ARG4,%d0 | ||
2157 | orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0 | ||
2158 | addw %d0,%a2 | ||
2159 | |||
2160 | dputn %a2 | ||
2161 | dputn %a3 | ||
2162 | dputn %a4 | ||
2163 | |||
2164 | is_not_040_or_060(L(mmu_map_030)) | ||
2165 | |||
2166 | addw #_PAGE_GLOBAL040,%a2 | ||
2167 | /* | ||
2168 | * MMU 040 & 060 Support | ||
2169 | * | ||
2170 | * The MMU usage for the 040 and 060 is different enough from | ||
2171 | * the 030 and 68851 that there is separate code. This comment | ||
2172 | * block describes the data structures and algorithms built by | ||
2173 | * this code. | ||
2174 | * | ||
2175 | * The 040 does not support early terminating descriptors, as | ||
2176 | * the 030 does. Therefore, a third level of table is needed | ||
2177 | * for the 040, and that would be the page table. In Linux, | ||
2178 | * page tables are allocated directly from the memory above the | ||
2179 | * kernel. | ||
2180 | * | ||
2181 | */ | ||
2182 | |||
2183 | L(mmu_map_040): | ||
2184 | /* Calculate the offset into the root table | ||
2185 | */ | ||
2186 | movel %a3,%d0 | ||
2187 | moveq #ROOT_INDEX_SHIFT,%d1 | ||
2188 | lsrl %d1,%d0 | ||
2189 | mmu_get_root_table_entry %d0 | ||
2190 | |||
2191 | /* Calculate the offset into the pointer table | ||
2192 | */ | ||
2193 | movel %a3,%d0 | ||
2194 | moveq #PTR_INDEX_SHIFT,%d1 | ||
2195 | lsrl %d1,%d0 | ||
2196 | andl #PTR_TABLE_SIZE-1,%d0 | ||
2197 | mmu_get_ptr_table_entry %a0,%d0 | ||
2198 | |||
2199 | /* Calculate the offset into the page table | ||
2200 | */ | ||
2201 | movel %a3,%d0 | ||
2202 | moveq #PAGE_INDEX_SHIFT,%d1 | ||
2203 | lsrl %d1,%d0 | ||
2204 | andl #PAGE_TABLE_SIZE-1,%d0 | ||
2205 | mmu_get_page_table_entry %a0,%d0 | ||
2206 | |||
2207 | /* The page table entry must not no be busy | ||
2208 | */ | ||
2209 | tstl %a0@ | ||
2210 | jne L(mmu_map_error) | ||
2211 | |||
2212 | /* Do the mapping and advance the pointers | ||
2213 | */ | ||
2214 | movel %a2,%a0@ | ||
2215 | 2: | ||
2216 | addw #PAGESIZE,%a2 | ||
2217 | addw #PAGESIZE,%a3 | ||
2218 | |||
2219 | /* Ready with mapping? | ||
2220 | */ | ||
2221 | lea %a3@(-1),%a0 | ||
2222 | cmpl %a0,%a4 | ||
2223 | jhi L(mmu_map_040) | ||
2224 | jra L(mmu_map_done) | ||
2225 | |||
2226 | L(mmu_map_030): | ||
2227 | /* Calculate the offset into the root table | ||
2228 | */ | ||
2229 | movel %a3,%d0 | ||
2230 | moveq #ROOT_INDEX_SHIFT,%d1 | ||
2231 | lsrl %d1,%d0 | ||
2232 | mmu_get_root_table_entry %d0 | ||
2233 | |||
2234 | /* Check if logical address 32MB aligned, | ||
2235 | * so we can try to map it once | ||
2236 | */ | ||
2237 | movel %a3,%d0 | ||
2238 | andl #(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1)&(-ROOT_TABLE_SIZE),%d0 | ||
2239 | jne 1f | ||
2240 | |||
2241 | /* Is there enough to map for 32MB at once | ||
2242 | */ | ||
2243 | lea %a3@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE-1),%a1 | ||
2244 | cmpl %a1,%a4 | ||
2245 | jcs 1f | ||
2246 | |||
2247 | addql #1,%a1 | ||
2248 | |||
2249 | /* The root table entry must not no be busy | ||
2250 | */ | ||
2251 | tstl %a0@ | ||
2252 | jne L(mmu_map_error) | ||
2253 | |||
2254 | /* Do the mapping and advance the pointers | ||
2255 | */ | ||
2256 | dputs "early term1" | ||
2257 | dputn %a2 | ||
2258 | dputn %a3 | ||
2259 | dputn %a1 | ||
2260 | dputc '\n' | ||
2261 | movel %a2,%a0@ | ||
2262 | |||
2263 | movel %a1,%a3 | ||
2264 | lea %a2@(PTR_TABLE_SIZE*PAGE_TABLE_SIZE*PAGESIZE),%a2 | ||
2265 | jra L(mmu_mapnext_030) | ||
2266 | 1: | ||
2267 | /* Calculate the offset into the pointer table | ||
2268 | */ | ||
2269 | movel %a3,%d0 | ||
2270 | moveq #PTR_INDEX_SHIFT,%d1 | ||
2271 | lsrl %d1,%d0 | ||
2272 | andl #PTR_TABLE_SIZE-1,%d0 | ||
2273 | mmu_get_ptr_table_entry %a0,%d0 | ||
2274 | |||
2275 | /* The pointer table entry must not no be busy | ||
2276 | */ | ||
2277 | tstl %a0@ | ||
2278 | jne L(mmu_map_error) | ||
2279 | |||
2280 | /* Do the mapping and advance the pointers | ||
2281 | */ | ||
2282 | dputs "early term2" | ||
2283 | dputn %a2 | ||
2284 | dputn %a3 | ||
2285 | dputc '\n' | ||
2286 | movel %a2,%a0@ | ||
2287 | |||
2288 | addl #PAGE_TABLE_SIZE*PAGESIZE,%a2 | ||
2289 | addl #PAGE_TABLE_SIZE*PAGESIZE,%a3 | ||
2290 | |||
2291 | L(mmu_mapnext_030): | ||
2292 | /* Ready with mapping? | ||
2293 | */ | ||
2294 | lea %a3@(-1),%a0 | ||
2295 | cmpl %a0,%a4 | ||
2296 | jhi L(mmu_map_030) | ||
2297 | jra L(mmu_map_done) | ||
2298 | |||
2299 | L(mmu_map_error): | ||
2300 | |||
2301 | dputs "mmu_map error:" | ||
2302 | dputn %a2 | ||
2303 | dputn %a3 | ||
2304 | dputc '\n' | ||
2305 | |||
2306 | L(mmu_map_done): | ||
2307 | |||
2308 | func_return mmu_map | ||
2309 | |||
2310 | /* | ||
2311 | * mmu_fixup | ||
2312 | * | ||
2313 | * On the 040 class machines, all pages that are used for the | ||
2314 | * mmu have to be fixed up. | ||
2315 | */ | ||
2316 | |||
2317 | func_start mmu_fixup_page_mmu_cache,%d0/%a0 | ||
2318 | |||
2319 | dputs "mmu_fixup_page_mmu_cache" | ||
2320 | dputn ARG1 | ||
2321 | |||
2322 | /* Calculate the offset into the root table | ||
2323 | */ | ||
2324 | movel ARG1,%d0 | ||
2325 | moveq #ROOT_INDEX_SHIFT,%d1 | ||
2326 | lsrl %d1,%d0 | ||
2327 | mmu_get_root_table_entry %d0 | ||
2328 | |||
2329 | /* Calculate the offset into the pointer table | ||
2330 | */ | ||
2331 | movel ARG1,%d0 | ||
2332 | moveq #PTR_INDEX_SHIFT,%d1 | ||
2333 | lsrl %d1,%d0 | ||
2334 | andl #PTR_TABLE_SIZE-1,%d0 | ||
2335 | mmu_get_ptr_table_entry %a0,%d0 | ||
2336 | |||
2337 | /* Calculate the offset into the page table | ||
2338 | */ | ||
2339 | movel ARG1,%d0 | ||
2340 | moveq #PAGE_INDEX_SHIFT,%d1 | ||
2341 | lsrl %d1,%d0 | ||
2342 | andl #PAGE_TABLE_SIZE-1,%d0 | ||
2343 | mmu_get_page_table_entry %a0,%d0 | ||
2344 | |||
2345 | movel %a0@,%d0 | ||
2346 | andil #_CACHEMASK040,%d0 | ||
2347 | orl %pc@(m68k_pgtable_cachemode),%d0 | ||
2348 | movel %d0,%a0@ | ||
2349 | |||
2350 | dputc '\n' | ||
2351 | |||
2352 | func_return mmu_fixup_page_mmu_cache | ||
2353 | |||
2354 | /* | ||
2355 | * mmu_temp_map | ||
2356 | * | ||
2357 | * create a temporary mapping to enable the mmu, | ||
2358 | * this we don't need any transparation translation tricks. | ||
2359 | */ | ||
2360 | |||
2361 | func_start mmu_temp_map,%d0/%d1/%a0/%a1 | ||
2362 | |||
2363 | dputs "mmu_temp_map" | ||
2364 | dputn ARG1 | ||
2365 | dputn ARG2 | ||
2366 | dputc '\n' | ||
2367 | |||
2368 | lea %pc@(L(temp_mmap_mem)),%a1 | ||
2369 | |||
2370 | /* Calculate the offset in the root table | ||
2371 | */ | ||
2372 | movel ARG2,%d0 | ||
2373 | moveq #ROOT_INDEX_SHIFT,%d1 | ||
2374 | lsrl %d1,%d0 | ||
2375 | mmu_get_root_table_entry %d0 | ||
2376 | |||
2377 | /* Check if the table is temporary allocated, so we have to reuse it | ||
2378 | */ | ||
2379 | movel %a0@,%d0 | ||
2380 | cmpl %pc@(L(memory_start)),%d0 | ||
2381 | jcc 1f | ||
2382 | |||
2383 | /* Temporary allocate a ptr table and insert it into the root table | ||
2384 | */ | ||
2385 | movel %a1@,%d0 | ||
2386 | addl #PTR_TABLE_SIZE*4,%a1@ | ||
2387 | orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0 | ||
2388 | movel %d0,%a0@ | ||
2389 | dputs " (new)" | ||
2390 | 1: | ||
2391 | dputn %d0 | ||
2392 | /* Mask the root table entry for the ptr table | ||
2393 | */ | ||
2394 | andw #-ROOT_TABLE_SIZE,%d0 | ||
2395 | movel %d0,%a0 | ||
2396 | |||
2397 | /* Calculate the offset into the pointer table | ||
2398 | */ | ||
2399 | movel ARG2,%d0 | ||
2400 | moveq #PTR_INDEX_SHIFT,%d1 | ||
2401 | lsrl %d1,%d0 | ||
2402 | andl #PTR_TABLE_SIZE-1,%d0 | ||
2403 | lea %a0@(%d0*4),%a0 | ||
2404 | dputn %a0 | ||
2405 | |||
2406 | /* Check if a temporary page table is already allocated | ||
2407 | */ | ||
2408 | movel %a0@,%d0 | ||
2409 | jne 1f | ||
2410 | |||
2411 | /* Temporary allocate a page table and insert it into the ptr table | ||
2412 | */ | ||
2413 | movel %a1@,%d0 | ||
2414 | /* The 512 should be PAGE_TABLE_SIZE*4, but that violates the | ||
2415 | alignment restriction for pointer tables on the '0[46]0. */ | ||
2416 | addl #512,%a1@ | ||
2417 | orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0 | ||
2418 | movel %d0,%a0@ | ||
2419 | dputs " (new)" | ||
2420 | 1: | ||
2421 | dputn %d0 | ||
2422 | /* Mask the ptr table entry for the page table | ||
2423 | */ | ||
2424 | andw #-PTR_TABLE_SIZE,%d0 | ||
2425 | movel %d0,%a0 | ||
2426 | |||
2427 | /* Calculate the offset into the page table | ||
2428 | */ | ||
2429 | movel ARG2,%d0 | ||
2430 | moveq #PAGE_INDEX_SHIFT,%d1 | ||
2431 | lsrl %d1,%d0 | ||
2432 | andl #PAGE_TABLE_SIZE-1,%d0 | ||
2433 | lea %a0@(%d0*4),%a0 | ||
2434 | dputn %a0 | ||
2435 | |||
2436 | /* Insert the address into the page table | ||
2437 | */ | ||
2438 | movel ARG1,%d0 | ||
2439 | andw #-PAGESIZE,%d0 | ||
2440 | orw #_PAGE_PRESENT+_PAGE_ACCESSED+_PAGE_DIRTY,%d0 | ||
2441 | movel %d0,%a0@ | ||
2442 | dputn %d0 | ||
2443 | |||
2444 | dputc '\n' | ||
2445 | |||
2446 | func_return mmu_temp_map | ||
2447 | |||
2448 | func_start mmu_engage,%d0-%d2/%a0-%a3 | ||
2449 | |||
2450 | moveq #ROOT_TABLE_SIZE-1,%d0 | ||
2451 | /* Temporarily use a different root table. */ | ||
2452 | lea %pc@(L(kernel_pgdir_ptr)),%a0 | ||
2453 | movel %a0@,%a2 | ||
2454 | movel %pc@(L(memory_start)),%a1 | ||
2455 | movel %a1,%a0@ | ||
2456 | movel %a2,%a0 | ||
2457 | 1: | ||
2458 | movel %a0@+,%a1@+ | ||
2459 | dbra %d0,1b | ||
2460 | |||
2461 | lea %pc@(L(temp_mmap_mem)),%a0 | ||
2462 | movel %a1,%a0@ | ||
2463 | |||
2464 | movew #PAGESIZE-1,%d0 | ||
2465 | 1: | ||
2466 | clrl %a1@+ | ||
2467 | dbra %d0,1b | ||
2468 | |||
2469 | lea %pc@(1b),%a0 | ||
2470 | movel #1b,%a1 | ||
2471 | /* Skip temp mappings if phys == virt */ | ||
2472 | cmpl %a0,%a1 | ||
2473 | jeq 1f | ||
2474 | |||
2475 | mmu_temp_map %a0,%a0 | ||
2476 | mmu_temp_map %a0,%a1 | ||
2477 | |||
2478 | addw #PAGESIZE,%a0 | ||
2479 | addw #PAGESIZE,%a1 | ||
2480 | mmu_temp_map %a0,%a0 | ||
2481 | mmu_temp_map %a0,%a1 | ||
2482 | 1: | ||
2483 | movel %pc@(L(memory_start)),%a3 | ||
2484 | movel %pc@(L(phys_kernel_start)),%d2 | ||
2485 | |||
2486 | is_not_040_or_060(L(mmu_engage_030)) | ||
2487 | |||
2488 | L(mmu_engage_040): | ||
2489 | .chip 68040 | ||
2490 | nop | ||
2491 | cinva %bc | ||
2492 | nop | ||
2493 | pflusha | ||
2494 | nop | ||
2495 | movec %a3,%srp | ||
2496 | movel #TC_ENABLE+TC_PAGE4K,%d0 | ||
2497 | movec %d0,%tc /* enable the MMU */ | ||
2498 | jmp 1f:l | ||
2499 | 1: nop | ||
2500 | movec %a2,%srp | ||
2501 | nop | ||
2502 | cinva %bc | ||
2503 | nop | ||
2504 | pflusha | ||
2505 | .chip 68k | ||
2506 | jra L(mmu_engage_cleanup) | ||
2507 | |||
2508 | L(mmu_engage_030_temp): | ||
2509 | .space 12 | ||
2510 | L(mmu_engage_030): | ||
2511 | .chip 68030 | ||
2512 | lea %pc@(L(mmu_engage_030_temp)),%a0 | ||
2513 | movel #0x80000002,%a0@ | ||
2514 | movel %a3,%a0@(4) | ||
2515 | movel #0x0808,%d0 | ||
2516 | movec %d0,%cacr | ||
2517 | pmove %a0@,%srp | ||
2518 | pflusha | ||
2519 | /* | ||
2520 | * enable,super root enable,4096 byte pages,7 bit root index, | ||
2521 | * 7 bit pointer index, 6 bit page table index. | ||
2522 | */ | ||
2523 | movel #0x82c07760,%a0@(8) | ||
2524 | pmove %a0@(8),%tc /* enable the MMU */ | ||
2525 | jmp 1f:l | ||
2526 | 1: movel %a2,%a0@(4) | ||
2527 | movel #0x0808,%d0 | ||
2528 | movec %d0,%cacr | ||
2529 | pmove %a0@,%srp | ||
2530 | pflusha | ||
2531 | .chip 68k | ||
2532 | |||
2533 | L(mmu_engage_cleanup): | ||
2534 | subl #PAGE_OFFSET,%d2 | ||
2535 | subl %d2,%a2 | ||
2536 | movel %a2,L(kernel_pgdir_ptr) | ||
2537 | subl %d2,%fp | ||
2538 | subl %d2,%sp | ||
2539 | subl %d2,ARG0 | ||
2540 | |||
2541 | func_return mmu_engage | ||
2542 | |||
2543 | func_start mmu_get_root_table_entry,%d0/%a1 | ||
2544 | |||
2545 | #if 0 | ||
2546 | dputs "mmu_get_root_table_entry:" | ||
2547 | dputn ARG1 | ||
2548 | dputs " =" | ||
2549 | #endif | ||
2550 | |||
2551 | movel %pc@(L(kernel_pgdir_ptr)),%a0 | ||
2552 | tstl %a0 | ||
2553 | jne 2f | ||
2554 | |||
2555 | dputs "\nmmu_init:" | ||
2556 | |||
2557 | /* Find the start of free memory, get_bi_record does this for us, | ||
2558 | * as the bootinfo structure is located directly behind the kernel | ||
2559 | * and and we simply search for the last entry. | ||
2560 | */ | ||
2561 | get_bi_record BI_LAST | ||
2562 | addw #PAGESIZE-1,%a0 | ||
2563 | movel %a0,%d0 | ||
2564 | andw #-PAGESIZE,%d0 | ||
2565 | |||
2566 | dputn %d0 | ||
2567 | |||
2568 | lea %pc@(L(memory_start)),%a0 | ||
2569 | movel %d0,%a0@ | ||
2570 | lea %pc@(L(kernel_end)),%a0 | ||
2571 | movel %d0,%a0@ | ||
2572 | |||
2573 | /* we have to return the first page at _stext since the init code | ||
2574 | * in mm/init.c simply expects kernel_pg_dir there, the rest of | ||
2575 | * page is used for further ptr tables in get_ptr_table. | ||
2576 | */ | ||
2577 | lea %pc@(_stext),%a0 | ||
2578 | lea %pc@(L(mmu_cached_pointer_tables)),%a1 | ||
2579 | movel %a0,%a1@ | ||
2580 | addl #ROOT_TABLE_SIZE*4,%a1@ | ||
2581 | |||
2582 | lea %pc@(L(mmu_num_pointer_tables)),%a1 | ||
2583 | addql #1,%a1@ | ||
2584 | |||
2585 | /* clear the page | ||
2586 | */ | ||
2587 | movel %a0,%a1 | ||
2588 | movew #PAGESIZE/4-1,%d0 | ||
2589 | 1: | ||
2590 | clrl %a1@+ | ||
2591 | dbra %d0,1b | ||
2592 | |||
2593 | lea %pc@(L(kernel_pgdir_ptr)),%a1 | ||
2594 | movel %a0,%a1@ | ||
2595 | |||
2596 | dputn %a0 | ||
2597 | dputc '\n' | ||
2598 | 2: | ||
2599 | movel ARG1,%d0 | ||
2600 | lea %a0@(%d0*4),%a0 | ||
2601 | |||
2602 | #if 0 | ||
2603 | dputn %a0 | ||
2604 | dputc '\n' | ||
2605 | #endif | ||
2606 | |||
2607 | func_return mmu_get_root_table_entry | ||
2608 | |||
2609 | |||
2610 | |||
2611 | func_start mmu_get_ptr_table_entry,%d0/%a1 | ||
2612 | |||
2613 | #if 0 | ||
2614 | dputs "mmu_get_ptr_table_entry:" | ||
2615 | dputn ARG1 | ||
2616 | dputn ARG2 | ||
2617 | dputs " =" | ||
2618 | #endif | ||
2619 | |||
2620 | movel ARG1,%a0 | ||
2621 | movel %a0@,%d0 | ||
2622 | jne 2f | ||
2623 | |||
2624 | /* Keep track of the number of pointer tables we use | ||
2625 | */ | ||
2626 | dputs "\nmmu_get_new_ptr_table:" | ||
2627 | lea %pc@(L(mmu_num_pointer_tables)),%a0 | ||
2628 | movel %a0@,%d0 | ||
2629 | addql #1,%a0@ | ||
2630 | |||
2631 | /* See if there is a free pointer table in our cache of pointer tables | ||
2632 | */ | ||
2633 | lea %pc@(L(mmu_cached_pointer_tables)),%a1 | ||
2634 | andw #7,%d0 | ||
2635 | jne 1f | ||
2636 | |||
2637 | /* Get a new pointer table page from above the kernel memory | ||
2638 | */ | ||
2639 | get_new_page | ||
2640 | movel %a0,%a1@ | ||
2641 | 1: | ||
2642 | /* There is an unused pointer table in our cache... use it | ||
2643 | */ | ||
2644 | movel %a1@,%d0 | ||
2645 | addl #PTR_TABLE_SIZE*4,%a1@ | ||
2646 | |||
2647 | dputn %d0 | ||
2648 | dputc '\n' | ||
2649 | |||
2650 | /* Insert the new pointer table into the root table | ||
2651 | */ | ||
2652 | movel ARG1,%a0 | ||
2653 | orw #_PAGE_TABLE+_PAGE_ACCESSED,%d0 | ||
2654 | movel %d0,%a0@ | ||
2655 | 2: | ||
2656 | /* Extract the pointer table entry | ||
2657 | */ | ||
2658 | andw #-PTR_TABLE_SIZE,%d0 | ||
2659 | movel %d0,%a0 | ||
2660 | movel ARG2,%d0 | ||
2661 | lea %a0@(%d0*4),%a0 | ||
2662 | |||
2663 | #if 0 | ||
2664 | dputn %a0 | ||
2665 | dputc '\n' | ||
2666 | #endif | ||
2667 | |||
2668 | func_return mmu_get_ptr_table_entry | ||
2669 | |||
2670 | |||
2671 | func_start mmu_get_page_table_entry,%d0/%a1 | ||
2672 | |||
2673 | #if 0 | ||
2674 | dputs "mmu_get_page_table_entry:" | ||
2675 | dputn ARG1 | ||
2676 | dputn ARG2 | ||
2677 | dputs " =" | ||
2678 | #endif | ||
2679 | |||
2680 | movel ARG1,%a0 | ||
2681 | movel %a0@,%d0 | ||
2682 | jne 2f | ||
2683 | |||
2684 | /* If the page table entry doesn't exist, we allocate a complete new | ||
2685 | * page and use it as one continues big page table which can cover | ||
2686 | * 4MB of memory, nearly almost all mappings have that alignment. | ||
2687 | */ | ||
2688 | get_new_page | ||
2689 | addw #_PAGE_TABLE+_PAGE_ACCESSED,%a0 | ||
2690 | |||
2691 | /* align pointer table entry for a page of page tables | ||
2692 | */ | ||
2693 | movel ARG1,%d0 | ||
2694 | andw #-(PAGESIZE/PAGE_TABLE_SIZE),%d0 | ||
2695 | movel %d0,%a1 | ||
2696 | |||
2697 | /* Insert the page tables into the pointer entries | ||
2698 | */ | ||
2699 | moveq #PAGESIZE/PAGE_TABLE_SIZE/4-1,%d0 | ||
2700 | 1: | ||
2701 | movel %a0,%a1@+ | ||
2702 | lea %a0@(PAGE_TABLE_SIZE*4),%a0 | ||
2703 | dbra %d0,1b | ||
2704 | |||
2705 | /* Now we can get the initialized pointer table entry | ||
2706 | */ | ||
2707 | movel ARG1,%a0 | ||
2708 | movel %a0@,%d0 | ||
2709 | 2: | ||
2710 | /* Extract the page table entry | ||
2711 | */ | ||
2712 | andw #-PAGE_TABLE_SIZE,%d0 | ||
2713 | movel %d0,%a0 | ||
2714 | movel ARG2,%d0 | ||
2715 | lea %a0@(%d0*4),%a0 | ||
2716 | |||
2717 | #if 0 | ||
2718 | dputn %a0 | ||
2719 | dputc '\n' | ||
2720 | #endif | ||
2721 | |||
2722 | func_return mmu_get_page_table_entry | ||
2723 | |||
2724 | /* | ||
2725 | * get_new_page | ||
2726 | * | ||
2727 | * Return a new page from the memory start and clear it. | ||
2728 | */ | ||
2729 | func_start get_new_page,%d0/%a1 | ||
2730 | |||
2731 | dputs "\nget_new_page:" | ||
2732 | |||
2733 | /* allocate the page and adjust memory_start | ||
2734 | */ | ||
2735 | lea %pc@(L(memory_start)),%a0 | ||
2736 | movel %a0@,%a1 | ||
2737 | addl #PAGESIZE,%a0@ | ||
2738 | |||
2739 | /* clear the new page | ||
2740 | */ | ||
2741 | movel %a1,%a0 | ||
2742 | movew #PAGESIZE/4-1,%d0 | ||
2743 | 1: | ||
2744 | clrl %a1@+ | ||
2745 | dbra %d0,1b | ||
2746 | |||
2747 | dputn %a0 | ||
2748 | dputc '\n' | ||
2749 | |||
2750 | func_return get_new_page | ||
2751 | |||
2752 | |||
2753 | |||
2754 | /* | ||
2755 | * Debug output support | ||
2756 | * Atarians have a choice between the parallel port, the serial port | ||
2757 | * from the MFP or a serial port of the SCC | ||
2758 | */ | ||
2759 | |||
2760 | #ifdef CONFIG_MAC | ||
2761 | |||
2762 | L(scc_initable_mac): | ||
2763 | .byte 9,12 /* Reset */ | ||
2764 | .byte 4,0x44 /* x16, 1 stopbit, no parity */ | ||
2765 | .byte 3,0xc0 /* receiver: 8 bpc */ | ||
2766 | .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */ | ||
2767 | .byte 9,0 /* no interrupts */ | ||
2768 | .byte 10,0 /* NRZ */ | ||
2769 | .byte 11,0x50 /* use baud rate generator */ | ||
2770 | .byte 12,10,13,0 /* 9600 baud */ | ||
2771 | .byte 14,1 /* Baud rate generator enable */ | ||
2772 | .byte 3,0xc1 /* enable receiver */ | ||
2773 | .byte 5,0xea /* enable transmitter */ | ||
2774 | .byte -1 | ||
2775 | .even | ||
2776 | #endif | ||
2777 | |||
2778 | #ifdef CONFIG_ATARI | ||
2779 | /* #define USE_PRINTER */ | ||
2780 | /* #define USE_SCC_B */ | ||
2781 | /* #define USE_SCC_A */ | ||
2782 | #define USE_MFP | ||
2783 | |||
2784 | #if defined(USE_SCC_A) || defined(USE_SCC_B) | ||
2785 | #define USE_SCC | ||
2786 | /* Initialisation table for SCC */ | ||
2787 | L(scc_initable): | ||
2788 | .byte 9,12 /* Reset */ | ||
2789 | .byte 4,0x44 /* x16, 1 stopbit, no parity */ | ||
2790 | .byte 3,0xc0 /* receiver: 8 bpc */ | ||
2791 | .byte 5,0xe2 /* transmitter: 8 bpc, assert dtr/rts */ | ||
2792 | .byte 9,0 /* no interrupts */ | ||
2793 | .byte 10,0 /* NRZ */ | ||
2794 | .byte 11,0x50 /* use baud rate generator */ | ||
2795 | .byte 12,24,13,0 /* 9600 baud */ | ||
2796 | .byte 14,2,14,3 /* use master clock for BRG, enable */ | ||
2797 | .byte 3,0xc1 /* enable receiver */ | ||
2798 | .byte 5,0xea /* enable transmitter */ | ||
2799 | .byte -1 | ||
2800 | .even | ||
2801 | #endif | ||
2802 | |||
2803 | #ifdef USE_PRINTER | ||
2804 | |||
2805 | LPSG_SELECT = 0xff8800 | ||
2806 | LPSG_READ = 0xff8800 | ||
2807 | LPSG_WRITE = 0xff8802 | ||
2808 | LPSG_IO_A = 14 | ||
2809 | LPSG_IO_B = 15 | ||
2810 | LPSG_CONTROL = 7 | ||
2811 | LSTMFP_GPIP = 0xfffa01 | ||
2812 | LSTMFP_DDR = 0xfffa05 | ||
2813 | LSTMFP_IERB = 0xfffa09 | ||
2814 | |||
2815 | #elif defined(USE_SCC_B) | ||
2816 | |||
2817 | LSCC_CTRL = 0xff8c85 | ||
2818 | LSCC_DATA = 0xff8c87 | ||
2819 | |||
2820 | #elif defined(USE_SCC_A) | ||
2821 | |||
2822 | LSCC_CTRL = 0xff8c81 | ||
2823 | LSCC_DATA = 0xff8c83 | ||
2824 | |||
2825 | #elif defined(USE_MFP) | ||
2826 | |||
2827 | LMFP_UCR = 0xfffa29 | ||
2828 | LMFP_TDCDR = 0xfffa1d | ||
2829 | LMFP_TDDR = 0xfffa25 | ||
2830 | LMFP_TSR = 0xfffa2d | ||
2831 | LMFP_UDR = 0xfffa2f | ||
2832 | |||
2833 | #endif | ||
2834 | #endif /* CONFIG_ATARI */ | ||
2835 | |||
2836 | /* | ||
2837 | * Serial port output support. | ||
2838 | */ | ||
2839 | |||
2840 | /* | ||
2841 | * Initialize serial port hardware for 9600/8/1 | ||
2842 | */ | ||
2843 | func_start serial_init,%d0/%d1/%a0/%a1 | ||
2844 | /* | ||
2845 | * Some of the register usage that follows | ||
2846 | * CONFIG_AMIGA | ||
2847 | * a0 = pointer to boot info record | ||
2848 | * d0 = boot info offset | ||
2849 | * CONFIG_ATARI | ||
2850 | * a0 = address of SCC | ||
2851 | * a1 = Liobase address/address of scc_initable | ||
2852 | * d0 = init data for serial port | ||
2853 | * CONFIG_MAC | ||
2854 | * a0 = address of SCC | ||
2855 | * a1 = address of scc_initable_mac | ||
2856 | * d0 = init data for serial port | ||
2857 | */ | ||
2858 | |||
2859 | #ifdef CONFIG_AMIGA | ||
2860 | #define SERIAL_DTR 7 | ||
2861 | #define SERIAL_CNTRL CIABBASE+C_PRA | ||
2862 | |||
2863 | is_not_amiga(1f) | ||
2864 | lea %pc@(L(custom)),%a0 | ||
2865 | movel #-ZTWOBASE,%a0@ | ||
2866 | bclr #SERIAL_DTR,SERIAL_CNTRL-ZTWOBASE | ||
2867 | get_bi_record BI_AMIGA_SERPER | ||
2868 | movew %a0@,CUSTOMBASE+C_SERPER-ZTWOBASE | ||
2869 | | movew #61,CUSTOMBASE+C_SERPER-ZTWOBASE | ||
2870 | 1: | ||
2871 | #endif | ||
2872 | #ifdef CONFIG_ATARI | ||
2873 | is_not_atari(4f) | ||
2874 | movel %pc@(L(iobase)),%a1 | ||
2875 | #if defined(USE_PRINTER) | ||
2876 | bclr #0,%a1@(LSTMFP_IERB) | ||
2877 | bclr #0,%a1@(LSTMFP_DDR) | ||
2878 | moveb #LPSG_CONTROL,%a1@(LPSG_SELECT) | ||
2879 | moveb #0xff,%a1@(LPSG_WRITE) | ||
2880 | moveb #LPSG_IO_B,%a1@(LPSG_SELECT) | ||
2881 | clrb %a1@(LPSG_WRITE) | ||
2882 | moveb #LPSG_IO_A,%a1@(LPSG_SELECT) | ||
2883 | moveb %a1@(LPSG_READ),%d0 | ||
2884 | bset #5,%d0 | ||
2885 | moveb %d0,%a1@(LPSG_WRITE) | ||
2886 | #elif defined(USE_SCC) | ||
2887 | lea %a1@(LSCC_CTRL),%a0 | ||
2888 | lea %pc@(L(scc_initable)),%a1 | ||
2889 | 2: moveb %a1@+,%d0 | ||
2890 | jmi 3f | ||
2891 | moveb %d0,%a0@ | ||
2892 | moveb %a1@+,%a0@ | ||
2893 | jra 2b | ||
2894 | 3: clrb %a0@ | ||
2895 | #elif defined(USE_MFP) | ||
2896 | bclr #1,%a1@(LMFP_TSR) | ||
2897 | moveb #0x88,%a1@(LMFP_UCR) | ||
2898 | andb #0x70,%a1@(LMFP_TDCDR) | ||
2899 | moveb #2,%a1@(LMFP_TDDR) | ||
2900 | orb #1,%a1@(LMFP_TDCDR) | ||
2901 | bset #1,%a1@(LMFP_TSR) | ||
2902 | #endif | ||
2903 | jra L(serial_init_done) | ||
2904 | 4: | ||
2905 | #endif | ||
2906 | #ifdef CONFIG_MAC | ||
2907 | is_not_mac(L(serial_init_not_mac)) | ||
2908 | #ifdef MAC_SERIAL_DEBUG | ||
2909 | #if !defined(MAC_USE_SCC_A) && !defined(MAC_USE_SCC_B) | ||
2910 | #define MAC_USE_SCC_B | ||
2911 | #endif | ||
2912 | #define mac_scc_cha_b_ctrl_offset 0x0 | ||
2913 | #define mac_scc_cha_a_ctrl_offset 0x2 | ||
2914 | #define mac_scc_cha_b_data_offset 0x4 | ||
2915 | #define mac_scc_cha_a_data_offset 0x6 | ||
2916 | |||
2917 | #ifdef MAC_USE_SCC_A | ||
2918 | /* Initialize channel A */ | ||
2919 | movel %pc@(L(mac_sccbase)),%a0 | ||
2920 | lea %pc@(L(scc_initable_mac)),%a1 | ||
2921 | 5: moveb %a1@+,%d0 | ||
2922 | jmi 6f | ||
2923 | moveb %d0,%a0@(mac_scc_cha_a_ctrl_offset) | ||
2924 | moveb %a1@+,%a0@(mac_scc_cha_a_ctrl_offset) | ||
2925 | jra 5b | ||
2926 | 6: | ||
2927 | #endif /* MAC_USE_SCC_A */ | ||
2928 | |||
2929 | #ifdef MAC_USE_SCC_B | ||
2930 | /* Initialize channel B */ | ||
2931 | #ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */ | ||
2932 | movel %pc@(L(mac_sccbase)),%a0 | ||
2933 | #endif /* MAC_USE_SCC_A */ | ||
2934 | lea %pc@(L(scc_initable_mac)),%a1 | ||
2935 | 7: moveb %a1@+,%d0 | ||
2936 | jmi 8f | ||
2937 | moveb %d0,%a0@(mac_scc_cha_b_ctrl_offset) | ||
2938 | moveb %a1@+,%a0@(mac_scc_cha_b_ctrl_offset) | ||
2939 | jra 7b | ||
2940 | 8: | ||
2941 | #endif /* MAC_USE_SCC_B */ | ||
2942 | #endif /* MAC_SERIAL_DEBUG */ | ||
2943 | |||
2944 | jra L(serial_init_done) | ||
2945 | L(serial_init_not_mac): | ||
2946 | #endif /* CONFIG_MAC */ | ||
2947 | |||
2948 | #ifdef CONFIG_Q40 | ||
2949 | is_not_q40(2f) | ||
2950 | /* debug output goes into SRAM, so we don't do it unless requested | ||
2951 | - check for '%LX$' signature in SRAM */ | ||
2952 | lea %pc@(q40_mem_cptr),%a1 | ||
2953 | move.l #0xff020010,%a1@ /* must be inited - also used by debug=mem */ | ||
2954 | move.l #0xff020000,%a1 | ||
2955 | cmp.b #'%',%a1@ | ||
2956 | bne 2f /*nodbg*/ | ||
2957 | addq.w #4,%a1 | ||
2958 | cmp.b #'L',%a1@ | ||
2959 | bne 2f /*nodbg*/ | ||
2960 | addq.w #4,%a1 | ||
2961 | cmp.b #'X',%a1@ | ||
2962 | bne 2f /*nodbg*/ | ||
2963 | addq.w #4,%a1 | ||
2964 | cmp.b #'$',%a1@ | ||
2965 | bne 2f /*nodbg*/ | ||
2966 | /* signature OK */ | ||
2967 | lea %pc@(L(q40_do_debug)),%a1 | ||
2968 | tas %a1@ | ||
2969 | /*nodbg: q40_do_debug is 0 by default*/ | ||
2970 | 2: | ||
2971 | #endif | ||
2972 | |||
2973 | #ifdef CONFIG_APOLLO | ||
2974 | /* We count on the PROM initializing SIO1 */ | ||
2975 | #endif | ||
2976 | |||
2977 | #ifdef CONFIG_HP300 | ||
2978 | /* We count on the boot loader initialising the UART */ | ||
2979 | #endif | ||
2980 | |||
2981 | L(serial_init_done): | ||
2982 | func_return serial_init | ||
2983 | |||
2984 | /* | ||
2985 | * Output character on serial port. | ||
2986 | */ | ||
2987 | func_start serial_putc,%d0/%d1/%a0/%a1 | ||
2988 | |||
2989 | movel ARG1,%d0 | ||
2990 | cmpib #'\n',%d0 | ||
2991 | jbne 1f | ||
2992 | |||
2993 | /* A little safe recursion is good for the soul */ | ||
2994 | serial_putc #'\r' | ||
2995 | 1: | ||
2996 | |||
2997 | #ifdef CONFIG_AMIGA | ||
2998 | is_not_amiga(2f) | ||
2999 | andw #0x00ff,%d0 | ||
3000 | oriw #0x0100,%d0 | ||
3001 | movel %pc@(L(custom)),%a0 | ||
3002 | movew %d0,%a0@(CUSTOMBASE+C_SERDAT) | ||
3003 | 1: movew %a0@(CUSTOMBASE+C_SERDATR),%d0 | ||
3004 | andw #0x2000,%d0 | ||
3005 | jeq 1b | ||
3006 | jra L(serial_putc_done) | ||
3007 | 2: | ||
3008 | #endif | ||
3009 | |||
3010 | #ifdef CONFIG_MAC | ||
3011 | is_not_mac(5f) | ||
3012 | |||
3013 | #ifdef MAC_SERIAL_DEBUG | ||
3014 | |||
3015 | #ifdef MAC_USE_SCC_A | ||
3016 | movel %pc@(L(mac_sccbase)),%a1 | ||
3017 | 3: btst #2,%a1@(mac_scc_cha_a_ctrl_offset) | ||
3018 | jeq 3b | ||
3019 | moveb %d0,%a1@(mac_scc_cha_a_data_offset) | ||
3020 | #endif /* MAC_USE_SCC_A */ | ||
3021 | |||
3022 | #ifdef MAC_USE_SCC_B | ||
3023 | #ifndef MAC_USE_SCC_A /* Load mac_sccbase only if needed */ | ||
3024 | movel %pc@(L(mac_sccbase)),%a1 | ||
3025 | #endif /* MAC_USE_SCC_A */ | ||
3026 | 4: btst #2,%a1@(mac_scc_cha_b_ctrl_offset) | ||
3027 | jeq 4b | ||
3028 | moveb %d0,%a1@(mac_scc_cha_b_data_offset) | ||
3029 | #endif /* MAC_USE_SCC_B */ | ||
3030 | |||
3031 | #endif /* MAC_SERIAL_DEBUG */ | ||
3032 | |||
3033 | jra L(serial_putc_done) | ||
3034 | 5: | ||
3035 | #endif /* CONFIG_MAC */ | ||
3036 | |||
3037 | #ifdef CONFIG_ATARI | ||
3038 | is_not_atari(4f) | ||
3039 | movel %pc@(L(iobase)),%a1 | ||
3040 | #if defined(USE_PRINTER) | ||
3041 | 3: btst #0,%a1@(LSTMFP_GPIP) | ||
3042 | jne 3b | ||
3043 | moveb #LPSG_IO_B,%a1@(LPSG_SELECT) | ||
3044 | moveb %d0,%a1@(LPSG_WRITE) | ||
3045 | moveb #LPSG_IO_A,%a1@(LPSG_SELECT) | ||
3046 | moveb %a1@(LPSG_READ),%d0 | ||
3047 | bclr #5,%d0 | ||
3048 | moveb %d0,%a1@(LPSG_WRITE) | ||
3049 | nop | ||
3050 | nop | ||
3051 | bset #5,%d0 | ||
3052 | moveb %d0,%a1@(LPSG_WRITE) | ||
3053 | #elif defined(USE_SCC) | ||
3054 | 3: btst #2,%a1@(LSCC_CTRL) | ||
3055 | jeq 3b | ||
3056 | moveb %d0,%a1@(LSCC_DATA) | ||
3057 | #elif defined(USE_MFP) | ||
3058 | 3: btst #7,%a1@(LMFP_TSR) | ||
3059 | jeq 3b | ||
3060 | moveb %d0,%a1@(LMFP_UDR) | ||
3061 | #endif | ||
3062 | jra L(serial_putc_done) | ||
3063 | 4: | ||
3064 | #endif /* CONFIG_ATARI */ | ||
3065 | |||
3066 | #ifdef CONFIG_MVME147 | ||
3067 | is_not_mvme147(2f) | ||
3068 | 1: btst #2,M147_SCC_CTRL_A | ||
3069 | jeq 1b | ||
3070 | moveb %d0,M147_SCC_DATA_A | ||
3071 | jbra L(serial_putc_done) | ||
3072 | 2: | ||
3073 | #endif | ||
3074 | |||
3075 | #ifdef CONFIG_MVME16x | ||
3076 | is_not_mvme16x(2f) | ||
3077 | /* | ||
3078 | * If the loader gave us a board type then we can use that to | ||
3079 | * select an appropriate output routine; otherwise we just use | ||
3080 | * the Bug code. If we haev to use the Bug that means the Bug | ||
3081 | * workspace has to be valid, which means the Bug has to use | ||
3082 | * the SRAM, which is non-standard. | ||
3083 | */ | ||
3084 | moveml %d0-%d7/%a2-%a6,%sp@- | ||
3085 | movel vme_brdtype,%d1 | ||
3086 | jeq 1f | No tag - use the Bug | ||
3087 | cmpi #VME_TYPE_MVME162,%d1 | ||
3088 | jeq 6f | ||
3089 | cmpi #VME_TYPE_MVME172,%d1 | ||
3090 | jne 5f | ||
3091 | /* 162/172; it's an SCC */ | ||
3092 | 6: btst #2,M162_SCC_CTRL_A | ||
3093 | nop | ||
3094 | nop | ||
3095 | nop | ||
3096 | jeq 6b | ||
3097 | moveb #8,M162_SCC_CTRL_A | ||
3098 | nop | ||
3099 | nop | ||
3100 | nop | ||
3101 | moveb %d0,M162_SCC_CTRL_A | ||
3102 | jra 3f | ||
3103 | 5: | ||
3104 | /* 166/167/177; it's a CD2401 */ | ||
3105 | moveb #0,M167_CYCAR | ||
3106 | moveb M167_CYIER,%d2 | ||
3107 | moveb #0x02,M167_CYIER | ||
3108 | 7: | ||
3109 | btst #5,M167_PCSCCTICR | ||
3110 | jeq 7b | ||
3111 | moveb M167_PCTPIACKR,%d1 | ||
3112 | moveb M167_CYLICR,%d1 | ||
3113 | jeq 8f | ||
3114 | moveb #0x08,M167_CYTEOIR | ||
3115 | jra 7b | ||
3116 | 8: | ||
3117 | moveb %d0,M167_CYTDR | ||
3118 | moveb #0,M167_CYTEOIR | ||
3119 | moveb %d2,M167_CYIER | ||
3120 | jra 3f | ||
3121 | 1: | ||
3122 | moveb %d0,%sp@- | ||
3123 | trap #15 | ||
3124 | .word 0x0020 /* TRAP 0x020 */ | ||
3125 | 3: | ||
3126 | moveml %sp@+,%d0-%d7/%a2-%a6 | ||
3127 | jbra L(serial_putc_done) | ||
3128 | 2: | ||
3129 | #endif /* CONFIG_MVME16x */ | ||
3130 | |||
3131 | #ifdef CONFIG_BVME6000 | ||
3132 | is_not_bvme6000(2f) | ||
3133 | /* | ||
3134 | * The BVME6000 machine has a serial port ... | ||
3135 | */ | ||
3136 | 1: btst #2,BVME_SCC_CTRL_A | ||
3137 | jeq 1b | ||
3138 | moveb %d0,BVME_SCC_DATA_A | ||
3139 | jbra L(serial_putc_done) | ||
3140 | 2: | ||
3141 | #endif | ||
3142 | |||
3143 | #ifdef CONFIG_SUN3X | ||
3144 | is_not_sun3x(2f) | ||
3145 | movel %d0,-(%sp) | ||
3146 | movel 0xFEFE0018,%a1 | ||
3147 | jbsr (%a1) | ||
3148 | addq #4,%sp | ||
3149 | jbra L(serial_putc_done) | ||
3150 | 2: | ||
3151 | #endif | ||
3152 | |||
3153 | #ifdef CONFIG_Q40 | ||
3154 | is_not_q40(2f) | ||
3155 | tst.l %pc@(L(q40_do_debug)) /* only debug if requested */ | ||
3156 | beq 2f | ||
3157 | lea %pc@(q40_mem_cptr),%a1 | ||
3158 | move.l %a1@,%a0 | ||
3159 | move.b %d0,%a0@ | ||
3160 | addq.l #4,%a0 | ||
3161 | move.l %a0,%a1@ | ||
3162 | jbra L(serial_putc_done) | ||
3163 | 2: | ||
3164 | #endif | ||
3165 | |||
3166 | #ifdef CONFIG_APOLLO | ||
3167 | is_not_apollo(2f) | ||
3168 | movl %pc@(L(iobase)),%a1 | ||
3169 | moveb %d0,%a1@(LTHRB0) | ||
3170 | 1: moveb %a1@(LSRB0),%d0 | ||
3171 | andb #0x4,%d0 | ||
3172 | beq 1b | ||
3173 | jbra L(serial_putc_done) | ||
3174 | 2: | ||
3175 | #endif | ||
3176 | |||
3177 | #ifdef CONFIG_HP300 | ||
3178 | is_not_hp300(3f) | ||
3179 | movl %pc@(L(iobase)),%a1 | ||
3180 | addl %pc@(L(uartbase)),%a1 | ||
3181 | movel %pc@(L(uart_scode)),%d1 /* Check the scode */ | ||
3182 | jmi 3f /* Unset? Exit */ | ||
3183 | cmpi #256,%d1 /* APCI scode? */ | ||
3184 | jeq 2f | ||
3185 | 1: moveb %a1@(DCALSR),%d1 /* Output to DCA */ | ||
3186 | andb #0x20,%d1 | ||
3187 | beq 1b | ||
3188 | moveb %d0,%a1@(DCADATA) | ||
3189 | jbra L(serial_putc_done) | ||
3190 | 2: moveb %a1@(APCILSR),%d1 /* Output to APCI */ | ||
3191 | andb #0x20,%d1 | ||
3192 | beq 2b | ||
3193 | moveb %d0,%a1@(APCIDATA) | ||
3194 | jbra L(serial_putc_done) | ||
3195 | 3: | ||
3196 | #endif | ||
3197 | |||
3198 | L(serial_putc_done): | ||
3199 | func_return serial_putc | ||
3200 | |||
3201 | /* | ||
3202 | * Output a string. | ||
3203 | */ | ||
3204 | func_start puts,%d0/%a0 | ||
3205 | |||
3206 | movel ARG1,%a0 | ||
3207 | jra 2f | ||
3208 | 1: | ||
3209 | #ifdef CONSOLE | ||
3210 | console_putc %d0 | ||
3211 | #endif | ||
3212 | #ifdef SERIAL_DEBUG | ||
3213 | serial_putc %d0 | ||
3214 | #endif | ||
3215 | 2: moveb %a0@+,%d0 | ||
3216 | jne 1b | ||
3217 | |||
3218 | func_return puts | ||
3219 | |||
3220 | /* | ||
3221 | * Output number in hex notation. | ||
3222 | */ | ||
3223 | |||
3224 | func_start putn,%d0-%d2 | ||
3225 | |||
3226 | putc ' ' | ||
3227 | |||
3228 | movel ARG1,%d0 | ||
3229 | moveq #7,%d1 | ||
3230 | 1: roll #4,%d0 | ||
3231 | move %d0,%d2 | ||
3232 | andb #0x0f,%d2 | ||
3233 | addb #'0',%d2 | ||
3234 | cmpb #'9',%d2 | ||
3235 | jls 2f | ||
3236 | addb #'A'-('9'+1),%d2 | ||
3237 | 2: | ||
3238 | #ifdef CONSOLE | ||
3239 | console_putc %d2 | ||
3240 | #endif | ||
3241 | #ifdef SERIAL_DEBUG | ||
3242 | serial_putc %d2 | ||
3243 | #endif | ||
3244 | dbra %d1,1b | ||
3245 | |||
3246 | func_return putn | ||
3247 | |||
3248 | #ifdef CONFIG_MAC | ||
3249 | /* | ||
3250 | * mac_serial_print | ||
3251 | * | ||
3252 | * This routine takes its parameters on the stack. It then | ||
3253 | * turns around and calls the internal routine. This routine | ||
3254 | * is used until the Linux console driver initializes itself. | ||
3255 | * | ||
3256 | * The calling parameters are: | ||
3257 | * void mac_serial_print(const char *str); | ||
3258 | * | ||
3259 | * This routine does NOT understand variable arguments only | ||
3260 | * simple strings! | ||
3261 | */ | ||
3262 | ENTRY(mac_serial_print) | ||
3263 | moveml %d0/%a0,%sp@- | ||
3264 | #if 1 | ||
3265 | move %sr,%sp@- | ||
3266 | ori #0x0700,%sr | ||
3267 | #endif | ||
3268 | movel %sp@(10),%a0 /* fetch parameter */ | ||
3269 | jra 2f | ||
3270 | 1: serial_putc %d0 | ||
3271 | 2: moveb %a0@+,%d0 | ||
3272 | jne 1b | ||
3273 | #if 1 | ||
3274 | move %sp@+,%sr | ||
3275 | #endif | ||
3276 | moveml %sp@+,%d0/%a0 | ||
3277 | rts | ||
3278 | #endif /* CONFIG_MAC */ | ||
3279 | |||
3280 | #if defined(CONFIG_HP300) || defined(CONFIG_APOLLO) | ||
3281 | func_start set_leds,%d0/%a0 | ||
3282 | movel ARG1,%d0 | ||
3283 | #ifdef CONFIG_HP300 | ||
3284 | is_not_hp300(1f) | ||
3285 | movel %pc@(L(iobase)),%a0 | ||
3286 | moveb %d0,%a0@(0x1ffff) | ||
3287 | jra 2f | ||
3288 | #endif | ||
3289 | 1: | ||
3290 | #ifdef CONFIG_APOLLO | ||
3291 | movel %pc@(L(iobase)),%a0 | ||
3292 | lsll #8,%d0 | ||
3293 | eorw #0xff00,%d0 | ||
3294 | moveb %d0,%a0@(LCPUCTRL) | ||
3295 | #endif | ||
3296 | 2: | ||
3297 | func_return set_leds | ||
3298 | #endif | ||
3299 | |||
3300 | #ifdef CONSOLE | ||
3301 | /* | ||
3302 | * For continuity, see the data alignment | ||
3303 | * to which this structure is tied. | ||
3304 | */ | ||
3305 | #define Lconsole_struct_cur_column 0 | ||
3306 | #define Lconsole_struct_cur_row 4 | ||
3307 | #define Lconsole_struct_num_columns 8 | ||
3308 | #define Lconsole_struct_num_rows 12 | ||
3309 | #define Lconsole_struct_left_edge 16 | ||
3310 | #define Lconsole_struct_penguin_putc 20 | ||
3311 | |||
3312 | func_start console_init,%a0-%a4/%d0-%d7 | ||
3313 | /* | ||
3314 | * Some of the register usage that follows | ||
3315 | * a0 = pointer to boot_info | ||
3316 | * a1 = pointer to screen | ||
3317 | * a2 = pointer to Lconsole_globals | ||
3318 | * d3 = pixel width of screen | ||
3319 | * d4 = pixel height of screen | ||
3320 | * (d3,d4) ~= (x,y) of a point just below | ||
3321 | * and to the right of the screen | ||
3322 | * NOT on the screen! | ||
3323 | * d5 = number of bytes per scan line | ||
3324 | * d6 = number of bytes on the entire screen | ||
3325 | */ | ||
3326 | |||
3327 | lea %pc@(L(console_globals)),%a2 | ||
3328 | movel %pc@(L(mac_videobase)),%a1 | ||
3329 | movel %pc@(L(mac_rowbytes)),%d5 | ||
3330 | movel %pc@(L(mac_dimensions)),%d3 /* -> low byte */ | ||
3331 | movel %d3,%d4 | ||
3332 | swap %d4 /* -> high byte */ | ||
3333 | andl #0xffff,%d3 /* d3 = screen width in pixels */ | ||
3334 | andl #0xffff,%d4 /* d4 = screen height in pixels */ | ||
3335 | |||
3336 | movel %d5,%d6 | ||
3337 | | subl #20,%d6 | ||
3338 | mulul %d4,%d6 /* scan line bytes x num scan lines */ | ||
3339 | divul #8,%d6 /* we'll clear 8 bytes at a time */ | ||
3340 | moveq #-1,%d0 /* Mac_black */ | ||
3341 | subq #1,%d6 | ||
3342 | |||
3343 | L(console_clear_loop): | ||
3344 | movel %d0,%a1@+ | ||
3345 | movel %d0,%a1@+ | ||
3346 | dbra %d6,L(console_clear_loop) | ||
3347 | |||
3348 | /* Calculate font size */ | ||
3349 | |||
3350 | #if defined(FONT_8x8) && defined(CONFIG_FONT_8x8) | ||
3351 | lea %pc@(font_vga_8x8),%a0 | ||
3352 | #elif defined(FONT_8x16) && defined(CONFIG_FONT_8x16) | ||
3353 | lea %pc@(font_vga_8x16),%a0 | ||
3354 | #elif defined(FONT_6x11) && defined(CONFIG_FONT_6x11) | ||
3355 | lea %pc@(font_vga_6x11),%a0 | ||
3356 | #elif defined(CONFIG_FONT_8x8) /* default */ | ||
3357 | lea %pc@(font_vga_8x8),%a0 | ||
3358 | #else /* no compiled-in font */ | ||
3359 | lea 0,%a0 | ||
3360 | #endif | ||
3361 | |||
3362 | /* | ||
3363 | * At this point we make a shift in register usage | ||
3364 | * a1 = address of console_font pointer | ||
3365 | */ | ||
3366 | lea %pc@(L(console_font)),%a1 | ||
3367 | movel %a0,%a1@ /* store pointer to struct fbcon_font_desc in console_font */ | ||
3368 | tstl %a0 | ||
3369 | jeq 1f | ||
3370 | lea %pc@(L(console_font_data)),%a4 | ||
3371 | movel %a0@(FONT_DESC_DATA),%d0 | ||
3372 | subl #L(console_font),%a1 | ||
3373 | addl %a1,%d0 | ||
3374 | movel %d0,%a4@ | ||
3375 | |||
3376 | /* | ||
3377 | * Calculate global maxs | ||
3378 | * Note - we can use either an | ||
3379 | * 8 x 16 or 8 x 8 character font | ||
3380 | * 6 x 11 also supported | ||
3381 | */ | ||
3382 | /* ASSERT: a0 = contents of Lconsole_font */ | ||
3383 | movel %d3,%d0 /* screen width in pixels */ | ||
3384 | divul %a0@(FONT_DESC_WIDTH),%d0 /* d0 = max num chars per row */ | ||
3385 | |||
3386 | movel %d4,%d1 /* screen height in pixels */ | ||
3387 | divul %a0@(FONT_DESC_HEIGHT),%d1 /* d1 = max num rows */ | ||
3388 | |||
3389 | movel %d0,%a2@(Lconsole_struct_num_columns) | ||
3390 | movel %d1,%a2@(Lconsole_struct_num_rows) | ||
3391 | |||
3392 | /* | ||
3393 | * Clear the current row and column | ||
3394 | */ | ||
3395 | clrl %a2@(Lconsole_struct_cur_column) | ||
3396 | clrl %a2@(Lconsole_struct_cur_row) | ||
3397 | clrl %a2@(Lconsole_struct_left_edge) | ||
3398 | |||
3399 | /* | ||
3400 | * Initialization is complete | ||
3401 | */ | ||
3402 | 1: | ||
3403 | func_return console_init | ||
3404 | |||
3405 | func_start console_put_stats,%a0/%d7 | ||
3406 | /* | ||
3407 | * Some of the register usage that follows | ||
3408 | * a0 = pointer to boot_info | ||
3409 | * d7 = value of boot_info fields | ||
3410 | */ | ||
3411 | puts "\nMacLinux\n\n" | ||
3412 | |||
3413 | #ifdef SERIAL_DEBUG | ||
3414 | puts " vidaddr:" | ||
3415 | putn %pc@(L(mac_videobase)) /* video addr. */ | ||
3416 | |||
3417 | puts "\n _stext:" | ||
3418 | lea %pc@(_stext),%a0 | ||
3419 | putn %a0 | ||
3420 | |||
3421 | puts "\nbootinfo:" | ||
3422 | lea %pc@(_end),%a0 | ||
3423 | putn %a0 | ||
3424 | |||
3425 | puts "\ncpuid:" | ||
3426 | putn %pc@(L(cputype)) | ||
3427 | putc '\n' | ||
3428 | |||
3429 | #ifdef MAC_SERIAL_DEBUG | ||
3430 | putn %pc@(L(mac_sccbase)) | ||
3431 | putc '\n' | ||
3432 | #endif | ||
3433 | # if defined(MMU_PRINT) | ||
3434 | jbsr mmu_print_machine_cpu_types | ||
3435 | # endif /* MMU_PRINT */ | ||
3436 | #endif /* SERIAL_DEBUG */ | ||
3437 | |||
3438 | func_return console_put_stats | ||
3439 | |||
3440 | #ifdef CONSOLE_PENGUIN | ||
3441 | func_start console_put_penguin,%a0-%a1/%d0-%d7 | ||
3442 | /* | ||
3443 | * Get 'that_penguin' onto the screen in the upper right corner | ||
3444 | * penguin is 64 x 74 pixels, align against right edge of screen | ||
3445 | */ | ||
3446 | lea %pc@(L(mac_dimensions)),%a0 | ||
3447 | movel %a0@,%d0 | ||
3448 | andil #0xffff,%d0 | ||
3449 | subil #64,%d0 /* snug up against the right edge */ | ||
3450 | clrl %d1 /* start at the top */ | ||
3451 | movel #73,%d7 | ||
3452 | lea %pc@(L(that_penguin)),%a1 | ||
3453 | L(console_penguin_row): | ||
3454 | movel #31,%d6 | ||
3455 | L(console_penguin_pixel_pair): | ||
3456 | moveb %a1@,%d2 | ||
3457 | lsrb #4,%d2 | ||
3458 | console_plot_pixel %d0,%d1,%d2 | ||
3459 | addq #1,%d0 | ||
3460 | moveb %a1@+,%d2 | ||
3461 | console_plot_pixel %d0,%d1,%d2 | ||
3462 | addq #1,%d0 | ||
3463 | dbra %d6,L(console_penguin_pixel_pair) | ||
3464 | |||
3465 | subil #64,%d0 | ||
3466 | addq #1,%d1 | ||
3467 | dbra %d7,L(console_penguin_row) | ||
3468 | |||
3469 | func_return console_put_penguin | ||
3470 | |||
3471 | /* include penguin bitmap */ | ||
3472 | L(that_penguin): | ||
3473 | #include "../mac/mac_penguin.S" | ||
3474 | #endif | ||
3475 | |||
3476 | /* | ||
3477 | * Calculate source and destination addresses | ||
3478 | * output a1 = dest | ||
3479 | * a2 = source | ||
3480 | */ | ||
3481 | |||
3482 | func_start console_scroll,%a0-%a4/%d0-%d7 | ||
3483 | lea %pc@(L(mac_videobase)),%a0 | ||
3484 | movel %a0@,%a1 | ||
3485 | movel %a1,%a2 | ||
3486 | lea %pc@(L(mac_rowbytes)),%a0 | ||
3487 | movel %a0@,%d5 | ||
3488 | movel %pc@(L(console_font)),%a0 | ||
3489 | tstl %a0 | ||
3490 | jeq 1f | ||
3491 | mulul %a0@(FONT_DESC_HEIGHT),%d5 /* account for # scan lines per character */ | ||
3492 | addal %d5,%a2 | ||
3493 | |||
3494 | /* | ||
3495 | * Get dimensions | ||
3496 | */ | ||
3497 | lea %pc@(L(mac_dimensions)),%a0 | ||
3498 | movel %a0@,%d3 | ||
3499 | movel %d3,%d4 | ||
3500 | swap %d4 | ||
3501 | andl #0xffff,%d3 /* d3 = screen width in pixels */ | ||
3502 | andl #0xffff,%d4 /* d4 = screen height in pixels */ | ||
3503 | |||
3504 | /* | ||
3505 | * Calculate number of bytes to move | ||
3506 | */ | ||
3507 | lea %pc@(L(mac_rowbytes)),%a0 | ||
3508 | movel %a0@,%d6 | ||
3509 | movel %pc@(L(console_font)),%a0 | ||
3510 | subl %a0@(FONT_DESC_HEIGHT),%d4 /* we're not scrolling the top row! */ | ||
3511 | mulul %d4,%d6 /* scan line bytes x num scan lines */ | ||
3512 | divul #32,%d6 /* we'll move 8 longs at a time */ | ||
3513 | subq #1,%d6 | ||
3514 | |||
3515 | L(console_scroll_loop): | ||
3516 | movel %a2@+,%a1@+ | ||
3517 | movel %a2@+,%a1@+ | ||
3518 | movel %a2@+,%a1@+ | ||
3519 | movel %a2@+,%a1@+ | ||
3520 | movel %a2@+,%a1@+ | ||
3521 | movel %a2@+,%a1@+ | ||
3522 | movel %a2@+,%a1@+ | ||
3523 | movel %a2@+,%a1@+ | ||
3524 | dbra %d6,L(console_scroll_loop) | ||
3525 | |||
3526 | lea %pc@(L(mac_rowbytes)),%a0 | ||
3527 | movel %a0@,%d6 | ||
3528 | movel %pc@(L(console_font)),%a0 | ||
3529 | mulul %a0@(FONT_DESC_HEIGHT),%d6 /* scan line bytes x font height */ | ||
3530 | divul #32,%d6 /* we'll move 8 words at a time */ | ||
3531 | subq #1,%d6 | ||
3532 | |||
3533 | moveq #-1,%d0 | ||
3534 | L(console_scroll_clear_loop): | ||
3535 | movel %d0,%a1@+ | ||
3536 | movel %d0,%a1@+ | ||
3537 | movel %d0,%a1@+ | ||
3538 | movel %d0,%a1@+ | ||
3539 | movel %d0,%a1@+ | ||
3540 | movel %d0,%a1@+ | ||
3541 | movel %d0,%a1@+ | ||
3542 | movel %d0,%a1@+ | ||
3543 | dbra %d6,L(console_scroll_clear_loop) | ||
3544 | |||
3545 | 1: | ||
3546 | func_return console_scroll | ||
3547 | |||
3548 | |||
3549 | func_start console_putc,%a0/%a1/%d0-%d7 | ||
3550 | |||
3551 | is_not_mac(L(console_exit)) | ||
3552 | tstl %pc@(L(console_font)) | ||
3553 | jeq L(console_exit) | ||
3554 | |||
3555 | /* Output character in d7 on console. | ||
3556 | */ | ||
3557 | movel ARG1,%d7 | ||
3558 | cmpib #'\n',%d7 | ||
3559 | jbne 1f | ||
3560 | |||
3561 | /* A little safe recursion is good for the soul */ | ||
3562 | console_putc #'\r' | ||
3563 | 1: | ||
3564 | lea %pc@(L(console_globals)),%a0 | ||
3565 | |||
3566 | cmpib #10,%d7 | ||
3567 | jne L(console_not_lf) | ||
3568 | movel %a0@(Lconsole_struct_cur_row),%d0 | ||
3569 | addil #1,%d0 | ||
3570 | movel %d0,%a0@(Lconsole_struct_cur_row) | ||
3571 | movel %a0@(Lconsole_struct_num_rows),%d1 | ||
3572 | cmpl %d1,%d0 | ||
3573 | jcs 1f | ||
3574 | subil #1,%d0 | ||
3575 | movel %d0,%a0@(Lconsole_struct_cur_row) | ||
3576 | console_scroll | ||
3577 | 1: | ||
3578 | jra L(console_exit) | ||
3579 | |||
3580 | L(console_not_lf): | ||
3581 | cmpib #13,%d7 | ||
3582 | jne L(console_not_cr) | ||
3583 | clrl %a0@(Lconsole_struct_cur_column) | ||
3584 | jra L(console_exit) | ||
3585 | |||
3586 | L(console_not_cr): | ||
3587 | cmpib #1,%d7 | ||
3588 | jne L(console_not_home) | ||
3589 | clrl %a0@(Lconsole_struct_cur_row) | ||
3590 | clrl %a0@(Lconsole_struct_cur_column) | ||
3591 | jra L(console_exit) | ||
3592 | |||
3593 | /* | ||
3594 | * At this point we know that the %d7 character is going to be | ||
3595 | * rendered on the screen. Register usage is - | ||
3596 | * a0 = pointer to console globals | ||
3597 | * a1 = font data | ||
3598 | * d0 = cursor column | ||
3599 | * d1 = cursor row to draw the character | ||
3600 | * d7 = character number | ||
3601 | */ | ||
3602 | L(console_not_home): | ||
3603 | movel %a0@(Lconsole_struct_cur_column),%d0 | ||
3604 | addql #1,%a0@(Lconsole_struct_cur_column) | ||
3605 | movel %a0@(Lconsole_struct_num_columns),%d1 | ||
3606 | cmpl %d1,%d0 | ||
3607 | jcs 1f | ||
3608 | console_putc #'\n' /* recursion is OK! */ | ||
3609 | 1: | ||
3610 | movel %a0@(Lconsole_struct_cur_row),%d1 | ||
3611 | |||
3612 | /* | ||
3613 | * At this point we make a shift in register usage | ||
3614 | * a0 = address of pointer to font data (fbcon_font_desc) | ||
3615 | */ | ||
3616 | movel %pc@(L(console_font)),%a0 | ||
3617 | movel %pc@(L(console_font_data)),%a1 /* Load fbcon_font_desc.data into a1 */ | ||
3618 | andl #0x000000ff,%d7 | ||
3619 | /* ASSERT: a0 = contents of Lconsole_font */ | ||
3620 | mulul %a0@(FONT_DESC_HEIGHT),%d7 /* d7 = index into font data */ | ||
3621 | addl %d7,%a1 /* a1 = points to char image */ | ||
3622 | |||
3623 | /* | ||
3624 | * At this point we make a shift in register usage | ||
3625 | * d0 = pixel coordinate, x | ||
3626 | * d1 = pixel coordinate, y | ||
3627 | * d2 = (bit 0) 1/0 for white/black (!) pixel on screen | ||
3628 | * d3 = font scan line data (8 pixels) | ||
3629 | * d6 = count down for the font's pixel width (8) | ||
3630 | * d7 = count down for the font's pixel count in height | ||
3631 | */ | ||
3632 | /* ASSERT: a0 = contents of Lconsole_font */ | ||
3633 | mulul %a0@(FONT_DESC_WIDTH),%d0 | ||
3634 | mulul %a0@(FONT_DESC_HEIGHT),%d1 | ||
3635 | movel %a0@(FONT_DESC_HEIGHT),%d7 /* Load fbcon_font_desc.height into d7 */ | ||
3636 | subq #1,%d7 | ||
3637 | L(console_read_char_scanline): | ||
3638 | moveb %a1@+,%d3 | ||
3639 | |||
3640 | /* ASSERT: a0 = contents of Lconsole_font */ | ||
3641 | movel %a0@(FONT_DESC_WIDTH),%d6 /* Load fbcon_font_desc.width into d6 */ | ||
3642 | subql #1,%d6 | ||
3643 | |||
3644 | L(console_do_font_scanline): | ||
3645 | lslb #1,%d3 | ||
3646 | scsb %d2 /* convert 1 bit into a byte */ | ||
3647 | console_plot_pixel %d0,%d1,%d2 | ||
3648 | addq #1,%d0 | ||
3649 | dbra %d6,L(console_do_font_scanline) | ||
3650 | |||
3651 | /* ASSERT: a0 = contents of Lconsole_font */ | ||
3652 | subl %a0@(FONT_DESC_WIDTH),%d0 | ||
3653 | addq #1,%d1 | ||
3654 | dbra %d7,L(console_read_char_scanline) | ||
3655 | |||
3656 | L(console_exit): | ||
3657 | func_return console_putc | ||
3658 | |||
3659 | /* | ||
3660 | * Input: | ||
3661 | * d0 = x coordinate | ||
3662 | * d1 = y coordinate | ||
3663 | * d2 = (bit 0) 1/0 for white/black (!) | ||
3664 | * All registers are preserved | ||
3665 | */ | ||
3666 | func_start console_plot_pixel,%a0-%a1/%d0-%d4 | ||
3667 | |||
3668 | movel %pc@(L(mac_videobase)),%a1 | ||
3669 | movel %pc@(L(mac_videodepth)),%d3 | ||
3670 | movel ARG1,%d0 | ||
3671 | movel ARG2,%d1 | ||
3672 | mulul %pc@(L(mac_rowbytes)),%d1 | ||
3673 | movel ARG3,%d2 | ||
3674 | |||
3675 | /* | ||
3676 | * Register usage: | ||
3677 | * d0 = x coord becomes byte offset into frame buffer | ||
3678 | * d1 = y coord | ||
3679 | * d2 = black or white (0/1) | ||
3680 | * d3 = video depth | ||
3681 | * d4 = temp of x (d0) for many bit depths | ||
3682 | */ | ||
3683 | L(test_1bit): | ||
3684 | cmpb #1,%d3 | ||
3685 | jbne L(test_2bit) | ||
3686 | movel %d0,%d4 /* we need the low order 3 bits! */ | ||
3687 | divul #8,%d0 | ||
3688 | addal %d0,%a1 | ||
3689 | addal %d1,%a1 | ||
3690 | andb #7,%d4 | ||
3691 | eorb #7,%d4 /* reverse the x-coordinate w/ screen-bit # */ | ||
3692 | andb #1,%d2 | ||
3693 | jbne L(white_1) | ||
3694 | bsetb %d4,%a1@ | ||
3695 | jbra L(console_plot_pixel_exit) | ||
3696 | L(white_1): | ||
3697 | bclrb %d4,%a1@ | ||
3698 | jbra L(console_plot_pixel_exit) | ||
3699 | |||
3700 | L(test_2bit): | ||
3701 | cmpb #2,%d3 | ||
3702 | jbne L(test_4bit) | ||
3703 | movel %d0,%d4 /* we need the low order 2 bits! */ | ||
3704 | divul #4,%d0 | ||
3705 | addal %d0,%a1 | ||
3706 | addal %d1,%a1 | ||
3707 | andb #3,%d4 | ||
3708 | eorb #3,%d4 /* reverse the x-coordinate w/ screen-bit # */ | ||
3709 | lsll #1,%d4 /* ! */ | ||
3710 | andb #1,%d2 | ||
3711 | jbne L(white_2) | ||
3712 | bsetb %d4,%a1@ | ||
3713 | addq #1,%d4 | ||
3714 | bsetb %d4,%a1@ | ||
3715 | jbra L(console_plot_pixel_exit) | ||
3716 | L(white_2): | ||
3717 | bclrb %d4,%a1@ | ||
3718 | addq #1,%d4 | ||
3719 | bclrb %d4,%a1@ | ||
3720 | jbra L(console_plot_pixel_exit) | ||
3721 | |||
3722 | L(test_4bit): | ||
3723 | cmpb #4,%d3 | ||
3724 | jbne L(test_8bit) | ||
3725 | movel %d0,%d4 /* we need the low order bit! */ | ||
3726 | divul #2,%d0 | ||
3727 | addal %d0,%a1 | ||
3728 | addal %d1,%a1 | ||
3729 | andb #1,%d4 | ||
3730 | eorb #1,%d4 | ||
3731 | lsll #2,%d4 /* ! */ | ||
3732 | andb #1,%d2 | ||
3733 | jbne L(white_4) | ||
3734 | bsetb %d4,%a1@ | ||
3735 | addq #1,%d4 | ||
3736 | bsetb %d4,%a1@ | ||
3737 | addq #1,%d4 | ||
3738 | bsetb %d4,%a1@ | ||
3739 | addq #1,%d4 | ||
3740 | bsetb %d4,%a1@ | ||
3741 | jbra L(console_plot_pixel_exit) | ||
3742 | L(white_4): | ||
3743 | bclrb %d4,%a1@ | ||
3744 | addq #1,%d4 | ||
3745 | bclrb %d4,%a1@ | ||
3746 | addq #1,%d4 | ||
3747 | bclrb %d4,%a1@ | ||
3748 | addq #1,%d4 | ||
3749 | bclrb %d4,%a1@ | ||
3750 | jbra L(console_plot_pixel_exit) | ||
3751 | |||
3752 | L(test_8bit): | ||
3753 | cmpb #8,%d3 | ||
3754 | jbne L(test_16bit) | ||
3755 | addal %d0,%a1 | ||
3756 | addal %d1,%a1 | ||
3757 | andb #1,%d2 | ||
3758 | jbne L(white_8) | ||
3759 | moveb #0xff,%a1@ | ||
3760 | jbra L(console_plot_pixel_exit) | ||
3761 | L(white_8): | ||
3762 | clrb %a1@ | ||
3763 | jbra L(console_plot_pixel_exit) | ||
3764 | |||
3765 | L(test_16bit): | ||
3766 | cmpb #16,%d3 | ||
3767 | jbne L(console_plot_pixel_exit) | ||
3768 | addal %d0,%a1 | ||
3769 | addal %d0,%a1 | ||
3770 | addal %d1,%a1 | ||
3771 | andb #1,%d2 | ||
3772 | jbne L(white_16) | ||
3773 | clrw %a1@ | ||
3774 | jbra L(console_plot_pixel_exit) | ||
3775 | L(white_16): | ||
3776 | movew #0x0fff,%a1@ | ||
3777 | jbra L(console_plot_pixel_exit) | ||
3778 | |||
3779 | L(console_plot_pixel_exit): | ||
3780 | func_return console_plot_pixel | ||
3781 | #endif /* CONSOLE */ | ||
3782 | |||
3783 | #if 0 | ||
3784 | /* | ||
3785 | * This is some old code lying around. I don't believe | ||
3786 | * it's used or important anymore. My guess is it contributed | ||
3787 | * to getting to this point, but it's done for now. | ||
3788 | * It was still in the 2.1.77 head.S, so it's still here. | ||
3789 | * (And still not used!) | ||
3790 | */ | ||
3791 | L(showtest): | ||
3792 | moveml %a0/%d7,%sp@- | ||
3793 | puts "A=" | ||
3794 | putn %a1 | ||
3795 | |||
3796 | .long 0xf0119f15 | ptestr #5,%a1@,#7,%a0 | ||
3797 | |||
3798 | puts "DA=" | ||
3799 | putn %a0 | ||
3800 | |||
3801 | puts "D=" | ||
3802 | putn %a0@ | ||
3803 | |||
3804 | puts "S=" | ||
3805 | lea %pc@(L(mmu)),%a0 | ||
3806 | .long 0xf0106200 | pmove %psr,%a0@ | ||
3807 | clrl %d7 | ||
3808 | movew %a0@,%d7 | ||
3809 | putn %d7 | ||
3810 | |||
3811 | putc '\n' | ||
3812 | moveml %sp@+,%a0/%d7 | ||
3813 | rts | ||
3814 | #endif /* 0 */ | ||
3815 | |||
3816 | __INITDATA | ||
3817 | .align 4 | ||
3818 | |||
3819 | #if defined(CONFIG_ATARI) || defined(CONFIG_AMIGA) || \ | ||
3820 | defined(CONFIG_HP300) || defined(CONFIG_APOLLO) | ||
3821 | L(custom): | ||
3822 | L(iobase): | ||
3823 | .long 0 | ||
3824 | #endif | ||
3825 | |||
3826 | #if defined(CONSOLE) | ||
3827 | L(console_globals): | ||
3828 | .long 0 /* cursor column */ | ||
3829 | .long 0 /* cursor row */ | ||
3830 | .long 0 /* max num columns */ | ||
3831 | .long 0 /* max num rows */ | ||
3832 | .long 0 /* left edge */ | ||
3833 | .long 0 /* mac putc */ | ||
3834 | L(console_font): | ||
3835 | .long 0 /* pointer to console font (struct font_desc) */ | ||
3836 | L(console_font_data): | ||
3837 | .long 0 /* pointer to console font data */ | ||
3838 | #endif /* CONSOLE */ | ||
3839 | |||
3840 | #if defined(MMU_PRINT) | ||
3841 | L(mmu_print_data): | ||
3842 | .long 0 /* valid flag */ | ||
3843 | .long 0 /* start logical */ | ||
3844 | .long 0 /* next logical */ | ||
3845 | .long 0 /* start physical */ | ||
3846 | .long 0 /* next physical */ | ||
3847 | #endif /* MMU_PRINT */ | ||
3848 | |||
3849 | L(cputype): | ||
3850 | .long 0 | ||
3851 | L(mmu_cached_pointer_tables): | ||
3852 | .long 0 | ||
3853 | L(mmu_num_pointer_tables): | ||
3854 | .long 0 | ||
3855 | L(phys_kernel_start): | ||
3856 | .long 0 | ||
3857 | L(kernel_end): | ||
3858 | .long 0 | ||
3859 | L(memory_start): | ||
3860 | .long 0 | ||
3861 | L(kernel_pgdir_ptr): | ||
3862 | .long 0 | ||
3863 | L(temp_mmap_mem): | ||
3864 | .long 0 | ||
3865 | |||
3866 | #if defined (CONFIG_MVME147) | ||
3867 | M147_SCC_CTRL_A = 0xfffe3002 | ||
3868 | M147_SCC_DATA_A = 0xfffe3003 | ||
3869 | #endif | ||
3870 | |||
3871 | #if defined (CONFIG_MVME16x) | ||
3872 | M162_SCC_CTRL_A = 0xfff45005 | ||
3873 | M167_CYCAR = 0xfff450ee | ||
3874 | M167_CYIER = 0xfff45011 | ||
3875 | M167_CYLICR = 0xfff45026 | ||
3876 | M167_CYTEOIR = 0xfff45085 | ||
3877 | M167_CYTDR = 0xfff450f8 | ||
3878 | M167_PCSCCTICR = 0xfff4201e | ||
3879 | M167_PCTPIACKR = 0xfff42025 | ||
3880 | #endif | ||
3881 | |||
3882 | #if defined (CONFIG_BVME6000) | ||
3883 | BVME_SCC_CTRL_A = 0xffb0000b | ||
3884 | BVME_SCC_DATA_A = 0xffb0000f | ||
3885 | #endif | ||
3886 | |||
3887 | #if defined(CONFIG_MAC) | ||
3888 | L(mac_booter_data): | ||
3889 | .long 0 | ||
3890 | L(mac_videobase): | ||
3891 | .long 0 | ||
3892 | L(mac_videodepth): | ||
3893 | .long 0 | ||
3894 | L(mac_dimensions): | ||
3895 | .long 0 | ||
3896 | L(mac_rowbytes): | ||
3897 | .long 0 | ||
3898 | #ifdef MAC_SERIAL_DEBUG | ||
3899 | L(mac_sccbase): | ||
3900 | .long 0 | ||
3901 | #endif /* MAC_SERIAL_DEBUG */ | ||
3902 | #endif | ||
3903 | |||
3904 | #if defined (CONFIG_APOLLO) | ||
3905 | LSRB0 = 0x10412 | ||
3906 | LTHRB0 = 0x10416 | ||
3907 | LCPUCTRL = 0x10100 | ||
3908 | #endif | ||
3909 | |||
3910 | #if defined(CONFIG_HP300) | ||
3911 | DCADATA = 0x11 | ||
3912 | DCALSR = 0x1b | ||
3913 | APCIDATA = 0x00 | ||
3914 | APCILSR = 0x14 | ||
3915 | L(uartbase): | ||
3916 | .long 0 | ||
3917 | L(uart_scode): | ||
3918 | .long -1 | ||
3919 | #endif | ||
3920 | |||
3921 | __FINIT | ||
3922 | .data | ||
3923 | .align 4 | ||
3924 | |||
3925 | availmem: | ||
3926 | .long 0 | ||
3927 | m68k_pgtable_cachemode: | ||
3928 | .long 0 | ||
3929 | m68k_supervisor_cachemode: | ||
3930 | .long 0 | ||
3931 | #if defined(CONFIG_MVME16x) | ||
3932 | mvme_bdid: | ||
3933 | .long 0,0,0,0,0,0,0,0 | ||
3934 | #endif | ||
3935 | #if defined(CONFIG_Q40) | ||
3936 | q40_mem_cptr: | ||
3937 | .long 0 | ||
3938 | L(q40_do_debug): | ||
3939 | .long 0 | ||
3940 | #endif | ||
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c new file mode 100644 index 000000000000..514d323ad536 --- /dev/null +++ b/arch/m68k/kernel/ints.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file COPYING in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * 07/03/96: Timer initialization, and thus mach_sched_init(), | ||
9 | * removed from request_irq() and moved to init_time(). | ||
10 | * We should therefore consider renaming our add_isr() and | ||
11 | * remove_isr() to request_irq() and free_irq() | ||
12 | * respectively, so they are compliant with the other | ||
13 | * architectures. /Jes | ||
14 | * 11/07/96: Changed all add_/remove_isr() to request_/free_irq() calls. | ||
15 | * Removed irq list support, if any machine needs an irq server | ||
16 | * it must implement this itself (as it's already done), instead | ||
17 | * only default handler are used with mach_default_handler. | ||
18 | * request_irq got some flags different from other architectures: | ||
19 | * - IRQ_FLG_REPLACE : Replace an existing handler (the default one | ||
20 | * can be replaced without this flag) | ||
21 | * - IRQ_FLG_LOCK : handler can't be replaced | ||
22 | * There are other machine depending flags, see there | ||
23 | * If you want to replace a default handler you should know what | ||
24 | * you're doing, since it might handle different other irq sources | ||
25 | * which must be served /Roman Zippel | ||
26 | */ | ||
27 | |||
28 | #include <linux/config.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/types.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/kernel_stat.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/init.h> | ||
35 | |||
36 | #include <asm/setup.h> | ||
37 | #include <asm/system.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/traps.h> | ||
40 | #include <asm/page.h> | ||
41 | #include <asm/machdep.h> | ||
42 | |||
43 | #ifdef CONFIG_Q40 | ||
44 | #include <asm/q40ints.h> | ||
45 | #endif | ||
46 | |||
47 | /* table for system interrupt handlers */ | ||
48 | static irq_handler_t irq_list[SYS_IRQS]; | ||
49 | |||
50 | static const char *default_names[SYS_IRQS] = { | ||
51 | [0] = "spurious int", | ||
52 | [1] = "int1 handler", | ||
53 | [2] = "int2 handler", | ||
54 | [3] = "int3 handler", | ||
55 | [4] = "int4 handler", | ||
56 | [5] = "int5 handler", | ||
57 | [6] = "int6 handler", | ||
58 | [7] = "int7 handler" | ||
59 | }; | ||
60 | |||
61 | /* The number of spurious interrupts */ | ||
62 | volatile unsigned int num_spurious; | ||
63 | |||
64 | #define NUM_IRQ_NODES 100 | ||
65 | static irq_node_t nodes[NUM_IRQ_NODES]; | ||
66 | |||
67 | static void dummy_enable_irq(unsigned int irq); | ||
68 | static void dummy_disable_irq(unsigned int irq); | ||
69 | static int dummy_request_irq(unsigned int irq, | ||
70 | irqreturn_t (*handler) (int, void *, struct pt_regs *), | ||
71 | unsigned long flags, const char *devname, void *dev_id); | ||
72 | static void dummy_free_irq(unsigned int irq, void *dev_id); | ||
73 | |||
74 | void (*enable_irq) (unsigned int) = dummy_enable_irq; | ||
75 | void (*disable_irq) (unsigned int) = dummy_disable_irq; | ||
76 | |||
77 | int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *), | ||
78 | unsigned long, const char *, void *) = dummy_request_irq; | ||
79 | void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; | ||
80 | |||
81 | void init_irq_proc(void); | ||
82 | |||
83 | /* | ||
84 | * void init_IRQ(void) | ||
85 | * | ||
86 | * Parameters: None | ||
87 | * | ||
88 | * Returns: Nothing | ||
89 | * | ||
90 | * This function should be called during kernel startup to initialize | ||
91 | * the IRQ handling routines. | ||
92 | */ | ||
93 | |||
94 | void __init init_IRQ(void) | ||
95 | { | ||
96 | int i; | ||
97 | |||
98 | for (i = 0; i < SYS_IRQS; i++) { | ||
99 | if (mach_default_handler) | ||
100 | irq_list[i].handler = (*mach_default_handler)[i]; | ||
101 | irq_list[i].flags = 0; | ||
102 | irq_list[i].dev_id = NULL; | ||
103 | irq_list[i].devname = default_names[i]; | ||
104 | } | ||
105 | |||
106 | for (i = 0; i < NUM_IRQ_NODES; i++) | ||
107 | nodes[i].handler = NULL; | ||
108 | |||
109 | mach_init_IRQ (); | ||
110 | } | ||
111 | |||
112 | irq_node_t *new_irq_node(void) | ||
113 | { | ||
114 | irq_node_t *node; | ||
115 | short i; | ||
116 | |||
117 | for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) | ||
118 | if (!node->handler) | ||
119 | return node; | ||
120 | |||
121 | printk ("new_irq_node: out of nodes\n"); | ||
122 | return NULL; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * We will keep these functions until I have convinced Linus to move | ||
127 | * the declaration of them from include/linux/sched.h to | ||
128 | * include/asm/irq.h. | ||
129 | */ | ||
130 | int request_irq(unsigned int irq, | ||
131 | irqreturn_t (*handler) (int, void *, struct pt_regs *), | ||
132 | unsigned long flags, const char *devname, void *dev_id) | ||
133 | { | ||
134 | return mach_request_irq(irq, handler, flags, devname, dev_id); | ||
135 | } | ||
136 | |||
137 | EXPORT_SYMBOL(request_irq); | ||
138 | |||
139 | void free_irq(unsigned int irq, void *dev_id) | ||
140 | { | ||
141 | mach_free_irq(irq, dev_id); | ||
142 | } | ||
143 | |||
144 | EXPORT_SYMBOL(free_irq); | ||
145 | |||
146 | int cpu_request_irq(unsigned int irq, | ||
147 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
148 | unsigned long flags, const char *devname, void *dev_id) | ||
149 | { | ||
150 | if (irq < IRQ1 || irq > IRQ7) { | ||
151 | printk("%s: Incorrect IRQ %d from %s\n", | ||
152 | __FUNCTION__, irq, devname); | ||
153 | return -ENXIO; | ||
154 | } | ||
155 | |||
156 | #if 0 | ||
157 | if (!(irq_list[irq].flags & IRQ_FLG_STD)) { | ||
158 | if (irq_list[irq].flags & IRQ_FLG_LOCK) { | ||
159 | printk("%s: IRQ %d from %s is not replaceable\n", | ||
160 | __FUNCTION__, irq, irq_list[irq].devname); | ||
161 | return -EBUSY; | ||
162 | } | ||
163 | if (!(flags & IRQ_FLG_REPLACE)) { | ||
164 | printk("%s: %s can't replace IRQ %d from %s\n", | ||
165 | __FUNCTION__, devname, irq, irq_list[irq].devname); | ||
166 | return -EBUSY; | ||
167 | } | ||
168 | } | ||
169 | #endif | ||
170 | |||
171 | irq_list[irq].handler = handler; | ||
172 | irq_list[irq].flags = flags; | ||
173 | irq_list[irq].dev_id = dev_id; | ||
174 | irq_list[irq].devname = devname; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | void cpu_free_irq(unsigned int irq, void *dev_id) | ||
179 | { | ||
180 | if (irq < IRQ1 || irq > IRQ7) { | ||
181 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | if (irq_list[irq].dev_id != dev_id) | ||
186 | printk("%s: Removing probably wrong IRQ %d from %s\n", | ||
187 | __FUNCTION__, irq, irq_list[irq].devname); | ||
188 | |||
189 | irq_list[irq].handler = (*mach_default_handler)[irq]; | ||
190 | irq_list[irq].flags = 0; | ||
191 | irq_list[irq].dev_id = NULL; | ||
192 | irq_list[irq].devname = default_names[irq]; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Do we need these probe functions on the m68k? | ||
197 | * | ||
198 | * ... may be useful with ISA devices | ||
199 | */ | ||
200 | unsigned long probe_irq_on (void) | ||
201 | { | ||
202 | #ifdef CONFIG_Q40 | ||
203 | if (MACH_IS_Q40) | ||
204 | return q40_probe_irq_on(); | ||
205 | #endif | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | EXPORT_SYMBOL(probe_irq_on); | ||
210 | |||
211 | int probe_irq_off (unsigned long irqs) | ||
212 | { | ||
213 | #ifdef CONFIG_Q40 | ||
214 | if (MACH_IS_Q40) | ||
215 | return q40_probe_irq_off(irqs); | ||
216 | #endif | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | EXPORT_SYMBOL(probe_irq_off); | ||
221 | |||
222 | static void dummy_enable_irq(unsigned int irq) | ||
223 | { | ||
224 | printk("calling uninitialized enable_irq()\n"); | ||
225 | } | ||
226 | |||
227 | static void dummy_disable_irq(unsigned int irq) | ||
228 | { | ||
229 | printk("calling uninitialized disable_irq()\n"); | ||
230 | } | ||
231 | |||
232 | static int dummy_request_irq(unsigned int irq, | ||
233 | irqreturn_t (*handler) (int, void *, struct pt_regs *), | ||
234 | unsigned long flags, const char *devname, void *dev_id) | ||
235 | { | ||
236 | printk("calling uninitialized request_irq()\n"); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static void dummy_free_irq(unsigned int irq, void *dev_id) | ||
241 | { | ||
242 | printk("calling uninitialized disable_irq()\n"); | ||
243 | } | ||
244 | |||
245 | asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) | ||
246 | { | ||
247 | if (vec >= VEC_INT1 && vec <= VEC_INT7 && !MACH_IS_BVME6000) { | ||
248 | vec -= VEC_SPUR; | ||
249 | kstat_cpu(0).irqs[vec]++; | ||
250 | irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); | ||
251 | } else { | ||
252 | if (mach_process_int) | ||
253 | mach_process_int(vec, fp); | ||
254 | else | ||
255 | panic("Can't process interrupt vector %ld\n", vec); | ||
256 | return; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | int show_interrupts(struct seq_file *p, void *v) | ||
261 | { | ||
262 | int i = *(loff_t *) v; | ||
263 | |||
264 | /* autovector interrupts */ | ||
265 | if (i < SYS_IRQS) { | ||
266 | if (mach_default_handler) { | ||
267 | seq_printf(p, "auto %2d: %10u ", i, | ||
268 | i ? kstat_cpu(0).irqs[i] : num_spurious); | ||
269 | seq_puts(p, " "); | ||
270 | seq_printf(p, "%s\n", irq_list[i].devname); | ||
271 | } | ||
272 | } else if (i == SYS_IRQS) | ||
273 | mach_get_irq_list(p, v); | ||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | void init_irq_proc(void) | ||
278 | { | ||
279 | /* Insert /proc/irq driver here */ | ||
280 | } | ||
281 | |||
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c new file mode 100644 index 000000000000..fe837e31afbf --- /dev/null +++ b/arch/m68k/kernel/m68k_ksyms.c | |||
@@ -0,0 +1,88 @@ | |||
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 | |||
20 | asmlinkage long long __ashldi3 (long long, int); | ||
21 | asmlinkage long long __ashrdi3 (long long, int); | ||
22 | asmlinkage long long __lshrdi3 (long long, int); | ||
23 | asmlinkage long long __muldi3 (long long, long long); | ||
24 | extern char m68k_debug_device[]; | ||
25 | |||
26 | extern void dump_thread(struct pt_regs *, struct user *); | ||
27 | |||
28 | /* platform dependent support */ | ||
29 | |||
30 | EXPORT_SYMBOL(m68k_machtype); | ||
31 | EXPORT_SYMBOL(m68k_cputype); | ||
32 | EXPORT_SYMBOL(m68k_is040or060); | ||
33 | EXPORT_SYMBOL(m68k_realnum_memory); | ||
34 | EXPORT_SYMBOL(m68k_memory); | ||
35 | #ifndef CONFIG_SUN3 | ||
36 | EXPORT_SYMBOL(cache_push); | ||
37 | EXPORT_SYMBOL(cache_clear); | ||
38 | #ifndef CONFIG_SINGLE_MEMORY_CHUNK | ||
39 | EXPORT_SYMBOL(mm_vtop); | ||
40 | EXPORT_SYMBOL(mm_ptov); | ||
41 | EXPORT_SYMBOL(mm_end_of_chunk); | ||
42 | #else | ||
43 | EXPORT_SYMBOL(m68k_memoffset); | ||
44 | #endif /* !CONFIG_SINGLE_MEMORY_CHUNK */ | ||
45 | EXPORT_SYMBOL(__ioremap); | ||
46 | EXPORT_SYMBOL(iounmap); | ||
47 | EXPORT_SYMBOL(kernel_set_cachemode); | ||
48 | #endif /* !CONFIG_SUN3 */ | ||
49 | EXPORT_SYMBOL(m68k_debug_device); | ||
50 | EXPORT_SYMBOL(mach_hwclk); | ||
51 | EXPORT_SYMBOL(mach_get_ss); | ||
52 | EXPORT_SYMBOL(mach_get_rtc_pll); | ||
53 | EXPORT_SYMBOL(mach_set_rtc_pll); | ||
54 | #ifdef CONFIG_INPUT_M68K_BEEP_MODULE | ||
55 | EXPORT_SYMBOL(mach_beep); | ||
56 | #endif | ||
57 | EXPORT_SYMBOL(dump_fpu); | ||
58 | EXPORT_SYMBOL(dump_thread); | ||
59 | EXPORT_SYMBOL(strnlen); | ||
60 | EXPORT_SYMBOL(strrchr); | ||
61 | EXPORT_SYMBOL(strstr); | ||
62 | EXPORT_SYMBOL(strpbrk); | ||
63 | EXPORT_SYMBOL(enable_irq); | ||
64 | EXPORT_SYMBOL(disable_irq); | ||
65 | EXPORT_SYMBOL(kernel_thread); | ||
66 | #ifdef CONFIG_VME | ||
67 | EXPORT_SYMBOL(vme_brdtype); | ||
68 | #endif | ||
69 | |||
70 | /* The following are special because they're not called | ||
71 | explicitly (the C compiler generates them). Fortunately, | ||
72 | their interface isn't gonna change any time soon now, so | ||
73 | it's OK to leave it out of version control. */ | ||
74 | EXPORT_SYMBOL(__ashldi3); | ||
75 | EXPORT_SYMBOL(__ashrdi3); | ||
76 | EXPORT_SYMBOL(__lshrdi3); | ||
77 | EXPORT_SYMBOL(memcpy); | ||
78 | EXPORT_SYMBOL(memset); | ||
79 | EXPORT_SYMBOL(memcmp); | ||
80 | EXPORT_SYMBOL(memscan); | ||
81 | EXPORT_SYMBOL(__muldi3); | ||
82 | |||
83 | EXPORT_SYMBOL(__down_failed); | ||
84 | EXPORT_SYMBOL(__down_failed_interruptible); | ||
85 | EXPORT_SYMBOL(__down_failed_trylock); | ||
86 | EXPORT_SYMBOL(__up_wakeup); | ||
87 | |||
88 | EXPORT_SYMBOL(get_wchan); | ||
diff --git a/arch/m68k/kernel/module.c b/arch/m68k/kernel/module.c new file mode 100644 index 000000000000..3b1a2ff61ddc --- /dev/null +++ b/arch/m68k/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/m68k/kernel/process.c b/arch/m68k/kernel/process.c new file mode 100644 index 000000000000..93b043e2a435 --- /dev/null +++ b/arch/m68k/kernel/process.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/process.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Hamish Macdonald | ||
5 | * | ||
6 | * 68060 fixes by Jesper Skov | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file handles the architecture-dependent parts of process handling.. | ||
11 | */ | ||
12 | |||
13 | #include <linux/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/mm.h> | ||
19 | #include <linux/smp.h> | ||
20 | #include <linux/smp_lock.h> | ||
21 | #include <linux/stddef.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/ptrace.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/user.h> | ||
26 | #include <linux/a.out.h> | ||
27 | #include <linux/reboot.h> | ||
28 | #include <linux/init_task.h> | ||
29 | #include <linux/mqueue.h> | ||
30 | |||
31 | #include <asm/uaccess.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/traps.h> | ||
34 | #include <asm/machdep.h> | ||
35 | #include <asm/setup.h> | ||
36 | #include <asm/pgtable.h> | ||
37 | |||
38 | /* | ||
39 | * Initial task/thread structure. Make this a per-architecture thing, | ||
40 | * because different architectures tend to have different | ||
41 | * alignment requirements and potentially different initial | ||
42 | * setup. | ||
43 | */ | ||
44 | static struct fs_struct init_fs = INIT_FS; | ||
45 | static struct files_struct init_files = INIT_FILES; | ||
46 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
47 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
48 | struct mm_struct init_mm = INIT_MM(init_mm); | ||
49 | |||
50 | EXPORT_SYMBOL(init_mm); | ||
51 | |||
52 | union thread_union init_thread_union | ||
53 | __attribute__((section(".data.init_task"), aligned(THREAD_SIZE))) | ||
54 | = { INIT_THREAD_INFO(init_task) }; | ||
55 | |||
56 | /* initial task structure */ | ||
57 | struct task_struct init_task = INIT_TASK(init_task); | ||
58 | |||
59 | EXPORT_SYMBOL(init_task); | ||
60 | |||
61 | asmlinkage void ret_from_fork(void); | ||
62 | |||
63 | |||
64 | /* | ||
65 | * Return saved PC from a blocked thread | ||
66 | */ | ||
67 | unsigned long thread_saved_pc(struct task_struct *tsk) | ||
68 | { | ||
69 | struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; | ||
70 | /* Check whether the thread is blocked in resume() */ | ||
71 | if (in_sched_functions(sw->retpc)) | ||
72 | return ((unsigned long *)sw->a6)[1]; | ||
73 | else | ||
74 | return sw->retpc; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * The idle loop on an m68k.. | ||
79 | */ | ||
80 | void default_idle(void) | ||
81 | { | ||
82 | if (!need_resched()) | ||
83 | #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES) | ||
84 | /* block out HSYNC on the atari (falcon) */ | ||
85 | __asm__("stop #0x2200" : : : "cc"); | ||
86 | #else | ||
87 | __asm__("stop #0x2000" : : : "cc"); | ||
88 | #endif | ||
89 | } | ||
90 | |||
91 | void (*idle)(void) = default_idle; | ||
92 | |||
93 | /* | ||
94 | * The idle thread. There's no useful work to be | ||
95 | * done, so just try to conserve power and have a | ||
96 | * low exit latency (ie sit in a loop waiting for | ||
97 | * somebody to say that they'd like to reschedule) | ||
98 | */ | ||
99 | void cpu_idle(void) | ||
100 | { | ||
101 | /* endless idle loop with no priority at all */ | ||
102 | while (1) { | ||
103 | while (!need_resched()) | ||
104 | idle(); | ||
105 | schedule(); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void machine_restart(char * __unused) | ||
110 | { | ||
111 | if (mach_reset) | ||
112 | mach_reset(); | ||
113 | for (;;); | ||
114 | } | ||
115 | |||
116 | EXPORT_SYMBOL(machine_restart); | ||
117 | |||
118 | void machine_halt(void) | ||
119 | { | ||
120 | if (mach_halt) | ||
121 | mach_halt(); | ||
122 | for (;;); | ||
123 | } | ||
124 | |||
125 | EXPORT_SYMBOL(machine_halt); | ||
126 | |||
127 | void machine_power_off(void) | ||
128 | { | ||
129 | if (mach_power_off) | ||
130 | mach_power_off(); | ||
131 | for (;;); | ||
132 | } | ||
133 | |||
134 | EXPORT_SYMBOL(machine_power_off); | ||
135 | |||
136 | void show_regs(struct pt_regs * regs) | ||
137 | { | ||
138 | printk("\n"); | ||
139 | printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", | ||
140 | regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); | ||
141 | printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", | ||
142 | regs->orig_d0, regs->d0, regs->a2, regs->a1); | ||
143 | printk("A0: %08lx D5: %08lx D4: %08lx\n", | ||
144 | regs->a0, regs->d5, regs->d4); | ||
145 | printk("D3: %08lx D2: %08lx D1: %08lx\n", | ||
146 | regs->d3, regs->d2, regs->d1); | ||
147 | if (!(regs->sr & PS_S)) | ||
148 | printk("USP: %08lx\n", rdusp()); | ||
149 | } | ||
150 | |||
151 | /* | ||
152 | * Create a kernel thread | ||
153 | */ | ||
154 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
155 | { | ||
156 | int pid; | ||
157 | mm_segment_t fs; | ||
158 | |||
159 | fs = get_fs(); | ||
160 | set_fs (KERNEL_DS); | ||
161 | |||
162 | { | ||
163 | register long retval __asm__ ("d0"); | ||
164 | register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; | ||
165 | |||
166 | retval = __NR_clone; | ||
167 | __asm__ __volatile__ | ||
168 | ("clrl %%d2\n\t" | ||
169 | "trap #0\n\t" /* Linux/m68k system call */ | ||
170 | "tstl %0\n\t" /* child or parent */ | ||
171 | "jne 1f\n\t" /* parent - jump */ | ||
172 | "lea %%sp@(%c7),%6\n\t" /* reload current */ | ||
173 | "movel %6@,%6\n\t" | ||
174 | "movel %3,%%sp@-\n\t" /* push argument */ | ||
175 | "jsr %4@\n\t" /* call fn */ | ||
176 | "movel %0,%%d1\n\t" /* pass exit value */ | ||
177 | "movel %2,%%d0\n\t" /* exit */ | ||
178 | "trap #0\n" | ||
179 | "1:" | ||
180 | : "+d" (retval) | ||
181 | : "i" (__NR_clone), "i" (__NR_exit), | ||
182 | "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), | ||
183 | "i" (-THREAD_SIZE) | ||
184 | : "d2"); | ||
185 | |||
186 | pid = retval; | ||
187 | } | ||
188 | |||
189 | set_fs (fs); | ||
190 | return pid; | ||
191 | } | ||
192 | |||
193 | void flush_thread(void) | ||
194 | { | ||
195 | unsigned long zero = 0; | ||
196 | set_fs(USER_DS); | ||
197 | current->thread.fs = __USER_DS; | ||
198 | if (!FPU_IS_EMU) | ||
199 | asm volatile (".chip 68k/68881\n\t" | ||
200 | "frestore %0@\n\t" | ||
201 | ".chip 68k" : : "a" (&zero)); | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * "m68k_fork()".. By the time we get here, the | ||
206 | * non-volatile registers have also been saved on the | ||
207 | * stack. We do some ugly pointer stuff here.. (see | ||
208 | * also copy_thread) | ||
209 | */ | ||
210 | |||
211 | asmlinkage int m68k_fork(struct pt_regs *regs) | ||
212 | { | ||
213 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
214 | } | ||
215 | |||
216 | asmlinkage int m68k_vfork(struct pt_regs *regs) | ||
217 | { | ||
218 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, | ||
219 | NULL, NULL); | ||
220 | } | ||
221 | |||
222 | asmlinkage int m68k_clone(struct pt_regs *regs) | ||
223 | { | ||
224 | unsigned long clone_flags; | ||
225 | unsigned long newsp; | ||
226 | int *parent_tidptr, *child_tidptr; | ||
227 | |||
228 | /* syscall2 puts clone_flags in d1 and usp in d2 */ | ||
229 | clone_flags = regs->d1; | ||
230 | newsp = regs->d2; | ||
231 | parent_tidptr = (int *)regs->d3; | ||
232 | child_tidptr = (int *)regs->d4; | ||
233 | if (!newsp) | ||
234 | newsp = rdusp(); | ||
235 | return do_fork(clone_flags, newsp, regs, 0, | ||
236 | parent_tidptr, child_tidptr); | ||
237 | } | ||
238 | |||
239 | int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | ||
240 | unsigned long unused, | ||
241 | struct task_struct * p, struct pt_regs * regs) | ||
242 | { | ||
243 | struct pt_regs * childregs; | ||
244 | struct switch_stack * childstack, *stack; | ||
245 | unsigned long stack_offset, *retp; | ||
246 | |||
247 | stack_offset = THREAD_SIZE - sizeof(struct pt_regs); | ||
248 | childregs = (struct pt_regs *) ((unsigned long) (p->thread_info) + stack_offset); | ||
249 | |||
250 | *childregs = *regs; | ||
251 | childregs->d0 = 0; | ||
252 | |||
253 | retp = ((unsigned long *) regs); | ||
254 | stack = ((struct switch_stack *) retp) - 1; | ||
255 | |||
256 | childstack = ((struct switch_stack *) childregs) - 1; | ||
257 | *childstack = *stack; | ||
258 | childstack->retpc = (unsigned long)ret_from_fork; | ||
259 | |||
260 | p->thread.usp = usp; | ||
261 | p->thread.ksp = (unsigned long)childstack; | ||
262 | /* | ||
263 | * Must save the current SFC/DFC value, NOT the value when | ||
264 | * the parent was last descheduled - RGH 10-08-96 | ||
265 | */ | ||
266 | p->thread.fs = get_fs().seg; | ||
267 | |||
268 | if (!FPU_IS_EMU) { | ||
269 | /* Copy the current fpu state */ | ||
270 | asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); | ||
271 | |||
272 | if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) | ||
273 | asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" | ||
274 | "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" | ||
275 | : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) | ||
276 | : "memory"); | ||
277 | /* Restore the state in case the fpu was busy */ | ||
278 | asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* Fill in the fpu structure for a core dump. */ | ||
285 | |||
286 | int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) | ||
287 | { | ||
288 | char fpustate[216]; | ||
289 | |||
290 | if (FPU_IS_EMU) { | ||
291 | int i; | ||
292 | |||
293 | memcpy(fpu->fpcntl, current->thread.fpcntl, 12); | ||
294 | memcpy(fpu->fpregs, current->thread.fp, 96); | ||
295 | /* Convert internal fpu reg representation | ||
296 | * into long double format | ||
297 | */ | ||
298 | for (i = 0; i < 24; i += 3) | ||
299 | fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | | ||
300 | ((fpu->fpregs[i] & 0x0000ffff) << 16); | ||
301 | return 1; | ||
302 | } | ||
303 | |||
304 | /* First dump the fpu context to avoid protocol violation. */ | ||
305 | asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); | ||
306 | if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) | ||
307 | return 0; | ||
308 | |||
309 | asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" | ||
310 | :: "m" (fpu->fpcntl[0]) | ||
311 | : "memory"); | ||
312 | asm volatile ("fmovemx %/fp0-%/fp7,%0" | ||
313 | :: "m" (fpu->fpregs[0]) | ||
314 | : "memory"); | ||
315 | return 1; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * fill in the user structure for a core dump.. | ||
320 | */ | ||
321 | void dump_thread(struct pt_regs * regs, struct user * dump) | ||
322 | { | ||
323 | struct switch_stack *sw; | ||
324 | |||
325 | /* changed the size calculations - should hopefully work better. lbt */ | ||
326 | dump->magic = CMAGIC; | ||
327 | dump->start_code = 0; | ||
328 | dump->start_stack = rdusp() & ~(PAGE_SIZE - 1); | ||
329 | dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; | ||
330 | dump->u_dsize = ((unsigned long) (current->mm->brk + | ||
331 | (PAGE_SIZE-1))) >> PAGE_SHIFT; | ||
332 | dump->u_dsize -= dump->u_tsize; | ||
333 | dump->u_ssize = 0; | ||
334 | |||
335 | if (dump->start_stack < TASK_SIZE) | ||
336 | dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; | ||
337 | |||
338 | dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump); | ||
339 | sw = ((struct switch_stack *)regs) - 1; | ||
340 | dump->regs.d1 = regs->d1; | ||
341 | dump->regs.d2 = regs->d2; | ||
342 | dump->regs.d3 = regs->d3; | ||
343 | dump->regs.d4 = regs->d4; | ||
344 | dump->regs.d5 = regs->d5; | ||
345 | dump->regs.d6 = sw->d6; | ||
346 | dump->regs.d7 = sw->d7; | ||
347 | dump->regs.a0 = regs->a0; | ||
348 | dump->regs.a1 = regs->a1; | ||
349 | dump->regs.a2 = regs->a2; | ||
350 | dump->regs.a3 = sw->a3; | ||
351 | dump->regs.a4 = sw->a4; | ||
352 | dump->regs.a5 = sw->a5; | ||
353 | dump->regs.a6 = sw->a6; | ||
354 | dump->regs.d0 = regs->d0; | ||
355 | dump->regs.orig_d0 = regs->orig_d0; | ||
356 | dump->regs.stkadj = regs->stkadj; | ||
357 | dump->regs.sr = regs->sr; | ||
358 | dump->regs.pc = regs->pc; | ||
359 | dump->regs.fmtvec = (regs->format << 12) | regs->vector; | ||
360 | /* dump floating point stuff */ | ||
361 | dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp); | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * sys_execve() executes a new program. | ||
366 | */ | ||
367 | asmlinkage int sys_execve(char *name, char **argv, char **envp) | ||
368 | { | ||
369 | int error; | ||
370 | char * filename; | ||
371 | struct pt_regs *regs = (struct pt_regs *) &name; | ||
372 | |||
373 | lock_kernel(); | ||
374 | filename = getname(name); | ||
375 | error = PTR_ERR(filename); | ||
376 | if (IS_ERR(filename)) | ||
377 | goto out; | ||
378 | error = do_execve(filename, argv, envp, regs); | ||
379 | putname(filename); | ||
380 | out: | ||
381 | unlock_kernel(); | ||
382 | return error; | ||
383 | } | ||
384 | |||
385 | unsigned long get_wchan(struct task_struct *p) | ||
386 | { | ||
387 | unsigned long fp, pc; | ||
388 | unsigned long stack_page; | ||
389 | int count = 0; | ||
390 | if (!p || p == current || p->state == TASK_RUNNING) | ||
391 | return 0; | ||
392 | |||
393 | stack_page = (unsigned long)(p->thread_info); | ||
394 | fp = ((struct switch_stack *)p->thread.ksp)->a6; | ||
395 | do { | ||
396 | if (fp < stack_page+sizeof(struct thread_info) || | ||
397 | fp >= 8184+stack_page) | ||
398 | return 0; | ||
399 | pc = ((unsigned long *)fp)[1]; | ||
400 | if (!in_sched_functions(pc)) | ||
401 | return pc; | ||
402 | fp = *(unsigned long *) fp; | ||
403 | } while (count++ < 16); | ||
404 | return 0; | ||
405 | } | ||
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c new file mode 100644 index 000000000000..0beb53333ba3 --- /dev/null +++ b/arch/m68k/kernel/ptrace.c | |||
@@ -0,0 +1,393 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/ptrace.c | ||
3 | * | ||
4 | * Copyright (C) 1994 by Hamish Macdonald | ||
5 | * Taken from linux/kernel/ptrace.c and modified for M680x0. | ||
6 | * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General | ||
9 | * Public License. See the file COPYING in the main directory of | ||
10 | * this archive for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/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 | [0] = PT_REG(d1), | ||
50 | [1] = PT_REG(d2), | ||
51 | [2] = PT_REG(d3), | ||
52 | [3] = PT_REG(d4), | ||
53 | [4] = PT_REG(d5), | ||
54 | [5] = SW_REG(d6), | ||
55 | [6] = SW_REG(d7), | ||
56 | [7] = PT_REG(a0), | ||
57 | [8] = PT_REG(a1), | ||
58 | [9] = PT_REG(a2), | ||
59 | [10] = SW_REG(a3), | ||
60 | [11] = SW_REG(a4), | ||
61 | [12] = SW_REG(a5), | ||
62 | [13] = SW_REG(a6), | ||
63 | [14] = PT_REG(d0), | ||
64 | [15] = -1, | ||
65 | [16] = PT_REG(orig_d0), | ||
66 | [17] = PT_REG(sr), | ||
67 | [18] = PT_REG(pc), | ||
68 | }; | ||
69 | |||
70 | /* | ||
71 | * Get contents of register REGNO in task TASK. | ||
72 | */ | ||
73 | static inline long get_reg(struct task_struct *task, int regno) | ||
74 | { | ||
75 | unsigned long *addr; | ||
76 | |||
77 | if (regno == PT_USP) | ||
78 | addr = &task->thread.usp; | ||
79 | else if (regno < sizeof(regoff)/sizeof(regoff[0])) | ||
80 | addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); | ||
81 | else | ||
82 | return 0; | ||
83 | return *addr; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Write contents of register REGNO in task TASK. | ||
88 | */ | ||
89 | static inline int put_reg(struct task_struct *task, int regno, | ||
90 | unsigned long data) | ||
91 | { | ||
92 | unsigned long *addr; | ||
93 | |||
94 | if (regno == PT_USP) | ||
95 | addr = &task->thread.usp; | ||
96 | else if (regno < sizeof(regoff)/sizeof(regoff[0])) | ||
97 | addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); | ||
98 | else | ||
99 | return -1; | ||
100 | *addr = data; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Called by kernel/ptrace.c when detaching.. | ||
106 | * | ||
107 | * Make sure the single step bit is not set. | ||
108 | */ | ||
109 | void ptrace_disable(struct task_struct *child) | ||
110 | { | ||
111 | unsigned long tmp; | ||
112 | /* make sure the single step bit is not set. */ | ||
113 | tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); | ||
114 | put_reg(child, PT_SR, tmp); | ||
115 | child->thread.work.delayed_trace = 0; | ||
116 | child->thread.work.syscall_trace = 0; | ||
117 | } | ||
118 | |||
119 | asmlinkage int sys_ptrace(long request, long pid, long addr, long data) | ||
120 | { | ||
121 | struct task_struct *child; | ||
122 | int ret; | ||
123 | |||
124 | lock_kernel(); | ||
125 | ret = -EPERM; | ||
126 | if (request == PTRACE_TRACEME) { | ||
127 | /* are we already being traced? */ | ||
128 | if (current->ptrace & PT_PTRACED) | ||
129 | goto out; | ||
130 | /* set the ptrace bit in the process flags. */ | ||
131 | current->ptrace |= PT_PTRACED; | ||
132 | ret = 0; | ||
133 | goto out; | ||
134 | } | ||
135 | ret = -ESRCH; | ||
136 | read_lock(&tasklist_lock); | ||
137 | child = find_task_by_pid(pid); | ||
138 | if (child) | ||
139 | get_task_struct(child); | ||
140 | read_unlock(&tasklist_lock); | ||
141 | if (!child) | ||
142 | goto out; | ||
143 | |||
144 | ret = -EPERM; | ||
145 | if (pid == 1) /* you may not mess with init */ | ||
146 | goto out_tsk; | ||
147 | |||
148 | if (request == PTRACE_ATTACH) { | ||
149 | ret = ptrace_attach(child); | ||
150 | goto out_tsk; | ||
151 | } | ||
152 | |||
153 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | ||
154 | if (ret < 0) | ||
155 | goto out_tsk; | ||
156 | |||
157 | switch (request) { | ||
158 | /* when I and D space are separate, these will need to be fixed. */ | ||
159 | case PTRACE_PEEKTEXT: /* read word at location addr. */ | ||
160 | case PTRACE_PEEKDATA: { | ||
161 | unsigned long tmp; | ||
162 | int copied; | ||
163 | |||
164 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | ||
165 | ret = -EIO; | ||
166 | if (copied != sizeof(tmp)) | ||
167 | break; | ||
168 | ret = put_user(tmp,(unsigned long *) data); | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | /* read the word at location addr in the USER area. */ | ||
173 | case PTRACE_PEEKUSR: { | ||
174 | unsigned long tmp; | ||
175 | |||
176 | ret = -EIO; | ||
177 | if ((addr & 3) || addr < 0 || | ||
178 | addr > sizeof(struct user) - 3) | ||
179 | break; | ||
180 | |||
181 | tmp = 0; /* Default return condition */ | ||
182 | addr = addr >> 2; /* temporary hack. */ | ||
183 | ret = -EIO; | ||
184 | if (addr < 19) { | ||
185 | tmp = get_reg(child, addr); | ||
186 | if (addr == PT_SR) | ||
187 | tmp >>= 16; | ||
188 | } else if (addr >= 21 && addr < 49) { | ||
189 | tmp = child->thread.fp[addr - 21]; | ||
190 | #ifdef CONFIG_M68KFPU_EMU | ||
191 | /* Convert internal fpu reg representation | ||
192 | * into long double format | ||
193 | */ | ||
194 | if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) | ||
195 | tmp = ((tmp & 0xffff0000) << 15) | | ||
196 | ((tmp & 0x0000ffff) << 16); | ||
197 | #endif | ||
198 | } else | ||
199 | break; | ||
200 | ret = put_user(tmp,(unsigned long *) data); | ||
201 | break; | ||
202 | } | ||
203 | |||
204 | /* when I and D space are separate, this will have to be fixed. */ | ||
205 | case PTRACE_POKETEXT: /* write the word at location addr. */ | ||
206 | case PTRACE_POKEDATA: | ||
207 | ret = 0; | ||
208 | if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) | ||
209 | break; | ||
210 | ret = -EIO; | ||
211 | break; | ||
212 | |||
213 | case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ | ||
214 | ret = -EIO; | ||
215 | if ((addr & 3) || addr < 0 || | ||
216 | addr > sizeof(struct user) - 3) | ||
217 | break; | ||
218 | |||
219 | addr = addr >> 2; /* temporary hack. */ | ||
220 | |||
221 | if (addr == PT_SR) { | ||
222 | data &= SR_MASK; | ||
223 | data <<= 16; | ||
224 | data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); | ||
225 | } | ||
226 | if (addr < 19) { | ||
227 | if (put_reg(child, addr, data)) | ||
228 | break; | ||
229 | ret = 0; | ||
230 | break; | ||
231 | } | ||
232 | if (addr >= 21 && addr < 48) | ||
233 | { | ||
234 | #ifdef CONFIG_M68KFPU_EMU | ||
235 | /* Convert long double format | ||
236 | * into internal fpu reg representation | ||
237 | */ | ||
238 | if (FPU_IS_EMU && (addr < 45) && !(addr % 3)) { | ||
239 | data = (unsigned long)data << 15; | ||
240 | data = (data & 0xffff0000) | | ||
241 | ((data & 0x0000ffff) >> 1); | ||
242 | } | ||
243 | #endif | ||
244 | child->thread.fp[addr - 21] = data; | ||
245 | ret = 0; | ||
246 | } | ||
247 | break; | ||
248 | |||
249 | case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ | ||
250 | case PTRACE_CONT: { /* restart after signal. */ | ||
251 | long tmp; | ||
252 | |||
253 | ret = -EIO; | ||
254 | if ((unsigned long) data > _NSIG) | ||
255 | break; | ||
256 | if (request == PTRACE_SYSCALL) { | ||
257 | child->thread.work.syscall_trace = ~0; | ||
258 | } else { | ||
259 | child->thread.work.syscall_trace = 0; | ||
260 | } | ||
261 | child->exit_code = data; | ||
262 | /* make sure the single step bit is not set. */ | ||
263 | tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); | ||
264 | put_reg(child, PT_SR, tmp); | ||
265 | child->thread.work.delayed_trace = 0; | ||
266 | wake_up_process(child); | ||
267 | ret = 0; | ||
268 | break; | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * make the child exit. Best I can do is send it a sigkill. | ||
273 | * perhaps it should be put in the status that it wants to | ||
274 | * exit. | ||
275 | */ | ||
276 | case PTRACE_KILL: { | ||
277 | long tmp; | ||
278 | |||
279 | ret = 0; | ||
280 | if (child->exit_state == EXIT_ZOMBIE) /* already dead */ | ||
281 | break; | ||
282 | child->exit_code = SIGKILL; | ||
283 | /* make sure the single step bit is not set. */ | ||
284 | tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16); | ||
285 | put_reg(child, PT_SR, tmp); | ||
286 | child->thread.work.delayed_trace = 0; | ||
287 | wake_up_process(child); | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | case PTRACE_SINGLESTEP: { /* set the trap flag. */ | ||
292 | long tmp; | ||
293 | |||
294 | ret = -EIO; | ||
295 | if ((unsigned long) data > _NSIG) | ||
296 | break; | ||
297 | child->thread.work.syscall_trace = 0; | ||
298 | tmp = get_reg(child, PT_SR) | (TRACE_BITS << 16); | ||
299 | put_reg(child, PT_SR, tmp); | ||
300 | child->thread.work.delayed_trace = 1; | ||
301 | |||
302 | child->exit_code = data; | ||
303 | /* give it a chance to run. */ | ||
304 | wake_up_process(child); | ||
305 | ret = 0; | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | case PTRACE_DETACH: /* detach a process that was attached. */ | ||
310 | ret = ptrace_detach(child, data); | ||
311 | break; | ||
312 | |||
313 | case PTRACE_GETREGS: { /* Get all gp regs from the child. */ | ||
314 | int i; | ||
315 | unsigned long tmp; | ||
316 | for (i = 0; i < 19; i++) { | ||
317 | tmp = get_reg(child, i); | ||
318 | if (i == PT_SR) | ||
319 | tmp >>= 16; | ||
320 | if (put_user(tmp, (unsigned long *) data)) { | ||
321 | ret = -EFAULT; | ||
322 | break; | ||
323 | } | ||
324 | data += sizeof(long); | ||
325 | } | ||
326 | ret = 0; | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | case PTRACE_SETREGS: { /* Set all gp regs in the child. */ | ||
331 | int i; | ||
332 | unsigned long tmp; | ||
333 | for (i = 0; i < 19; i++) { | ||
334 | if (get_user(tmp, (unsigned long *) data)) { | ||
335 | ret = -EFAULT; | ||
336 | break; | ||
337 | } | ||
338 | if (i == PT_SR) { | ||
339 | tmp &= SR_MASK; | ||
340 | tmp <<= 16; | ||
341 | tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); | ||
342 | } | ||
343 | put_reg(child, i, tmp); | ||
344 | data += sizeof(long); | ||
345 | } | ||
346 | ret = 0; | ||
347 | break; | ||
348 | } | ||
349 | |||
350 | case PTRACE_GETFPREGS: { /* Get the child FPU state. */ | ||
351 | ret = 0; | ||
352 | if (copy_to_user((void *)data, &child->thread.fp, | ||
353 | sizeof(struct user_m68kfp_struct))) | ||
354 | ret = -EFAULT; | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | case PTRACE_SETFPREGS: { /* Set the child FPU state. */ | ||
359 | ret = 0; | ||
360 | if (copy_from_user(&child->thread.fp, (void *)data, | ||
361 | sizeof(struct user_m68kfp_struct))) | ||
362 | ret = -EFAULT; | ||
363 | break; | ||
364 | } | ||
365 | |||
366 | default: | ||
367 | ret = ptrace_request(child, request, addr, data); | ||
368 | break; | ||
369 | } | ||
370 | out_tsk: | ||
371 | put_task_struct(child); | ||
372 | out: | ||
373 | unlock_kernel(); | ||
374 | return ret; | ||
375 | } | ||
376 | |||
377 | asmlinkage void syscall_trace(void) | ||
378 | { | ||
379 | if (!current->thread.work.delayed_trace && | ||
380 | !current->thread.work.syscall_trace) | ||
381 | return; | ||
382 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
383 | ? 0x80 : 0)); | ||
384 | /* | ||
385 | * this isn't the same as continuing with a signal, but it will do | ||
386 | * for normal use. strace only continues with a signal if the | ||
387 | * stopping signal is not SIGTRAP. -brl | ||
388 | */ | ||
389 | if (current->exit_code) { | ||
390 | send_sig(current->exit_code, current, 1); | ||
391 | current->exit_code = 0; | ||
392 | } | ||
393 | } | ||
diff --git a/arch/m68k/kernel/semaphore.c b/arch/m68k/kernel/semaphore.c new file mode 100644 index 000000000000..1ebb79baaa8c --- /dev/null +++ b/arch/m68k/kernel/semaphore.c | |||
@@ -0,0 +1,133 @@ | |||
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/init.h> | ||
9 | #include <asm/semaphore-helper.h> | ||
10 | |||
11 | #ifndef CONFIG_RMW_INSNS | ||
12 | spinlock_t semaphore_wake_lock; | ||
13 | #endif | ||
14 | |||
15 | /* | ||
16 | * Semaphores are implemented using a two-way counter: | ||
17 | * The "count" variable is decremented for each process | ||
18 | * that tries to sleep, while the "waking" variable is | ||
19 | * incremented when the "up()" code goes to wake up waiting | ||
20 | * processes. | ||
21 | * | ||
22 | * Notably, the inline "up()" and "down()" functions can | ||
23 | * efficiently test if they need to do any extra work (up | ||
24 | * needs to do something only if count was negative before | ||
25 | * the increment operation. | ||
26 | * | ||
27 | * waking_non_zero() (from asm/semaphore.h) must execute | ||
28 | * atomically. | ||
29 | * | ||
30 | * When __up() is called, the count was negative before | ||
31 | * incrementing it, and we need to wake up somebody. | ||
32 | * | ||
33 | * This routine adds one to the count of processes that need to | ||
34 | * wake up and exit. ALL waiting processes actually wake up but | ||
35 | * only the one that gets to the "waking" field first will gate | ||
36 | * through and acquire the semaphore. The others will go back | ||
37 | * to sleep. | ||
38 | * | ||
39 | * Note that these functions are only called when there is | ||
40 | * contention on the lock, and as such all this is the | ||
41 | * "non-critical" part of the whole semaphore business. The | ||
42 | * critical part is the inline stuff in <asm/semaphore.h> | ||
43 | * where we want to avoid any extra jumps and calls. | ||
44 | */ | ||
45 | void __up(struct semaphore *sem) | ||
46 | { | ||
47 | wake_one_more(sem); | ||
48 | wake_up(&sem->wait); | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Perform the "down" function. Return zero for semaphore acquired, | ||
53 | * return negative for signalled out of the function. | ||
54 | * | ||
55 | * If called from __down, the return is ignored and the wait loop is | ||
56 | * not interruptible. This means that a task waiting on a semaphore | ||
57 | * using "down()" cannot be killed until someone does an "up()" on | ||
58 | * the semaphore. | ||
59 | * | ||
60 | * If called from __down_interruptible, the return value gets checked | ||
61 | * upon return. If the return value is negative then the task continues | ||
62 | * with the negative value in the return register (it can be tested by | ||
63 | * the caller). | ||
64 | * | ||
65 | * Either form may be used in conjunction with "up()". | ||
66 | * | ||
67 | */ | ||
68 | |||
69 | |||
70 | #define DOWN_HEAD(task_state) \ | ||
71 | \ | ||
72 | \ | ||
73 | current->state = (task_state); \ | ||
74 | add_wait_queue(&sem->wait, &wait); \ | ||
75 | \ | ||
76 | /* \ | ||
77 | * Ok, we're set up. sem->count is known to be less than zero \ | ||
78 | * so we must wait. \ | ||
79 | * \ | ||
80 | * We can let go the lock for purposes of waiting. \ | ||
81 | * We re-acquire it after awaking so as to protect \ | ||
82 | * all semaphore operations. \ | ||
83 | * \ | ||
84 | * If "up()" is called before we call waking_non_zero() then \ | ||
85 | * we will catch it right away. If it is called later then \ | ||
86 | * we will have to go through a wakeup cycle to catch it. \ | ||
87 | * \ | ||
88 | * Multiple waiters contend for the semaphore lock to see \ | ||
89 | * who gets to gate through and who has to wait some more. \ | ||
90 | */ \ | ||
91 | for (;;) { | ||
92 | |||
93 | #define DOWN_TAIL(task_state) \ | ||
94 | current->state = (task_state); \ | ||
95 | } \ | ||
96 | current->state = TASK_RUNNING; \ | ||
97 | remove_wait_queue(&sem->wait, &wait); | ||
98 | |||
99 | void __sched __down(struct semaphore * sem) | ||
100 | { | ||
101 | DECLARE_WAITQUEUE(wait, current); | ||
102 | |||
103 | DOWN_HEAD(TASK_UNINTERRUPTIBLE) | ||
104 | if (waking_non_zero(sem)) | ||
105 | break; | ||
106 | schedule(); | ||
107 | DOWN_TAIL(TASK_UNINTERRUPTIBLE) | ||
108 | } | ||
109 | |||
110 | int __sched __down_interruptible(struct semaphore * sem) | ||
111 | { | ||
112 | DECLARE_WAITQUEUE(wait, current); | ||
113 | int ret = 0; | ||
114 | |||
115 | DOWN_HEAD(TASK_INTERRUPTIBLE) | ||
116 | |||
117 | ret = waking_non_zero_interruptible(sem, current); | ||
118 | if (ret) | ||
119 | { | ||
120 | if (ret == 1) | ||
121 | /* ret != 0 only if we get interrupted -arca */ | ||
122 | ret = 0; | ||
123 | break; | ||
124 | } | ||
125 | schedule(); | ||
126 | DOWN_TAIL(TASK_INTERRUPTIBLE) | ||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | int __down_trylock(struct semaphore * sem) | ||
131 | { | ||
132 | return waking_non_zero_trylock(sem); | ||
133 | } | ||
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c new file mode 100644 index 000000000000..d6ca99242e5a --- /dev/null +++ b/arch/m68k/kernel/setup.c | |||
@@ -0,0 +1,545 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/setup.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Hamish Macdonald | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This file handles the architecture-dependent parts of system setup | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/console.h> | ||
19 | #include <linux/genhd.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/bootmem.h> | ||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/initrd.h> | ||
27 | |||
28 | #include <asm/bootinfo.h> | ||
29 | #include <asm/setup.h> | ||
30 | #include <asm/irq.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/machdep.h> | ||
33 | #ifdef CONFIG_AMIGA | ||
34 | #include <asm/amigahw.h> | ||
35 | #endif | ||
36 | #ifdef CONFIG_ATARI | ||
37 | #include <asm/atarihw.h> | ||
38 | #include <asm/atari_stram.h> | ||
39 | #endif | ||
40 | #ifdef CONFIG_SUN3X | ||
41 | #include <asm/dvma.h> | ||
42 | #endif | ||
43 | |||
44 | unsigned long m68k_machtype; | ||
45 | unsigned long m68k_cputype; | ||
46 | unsigned long m68k_fputype; | ||
47 | unsigned long m68k_mmutype; | ||
48 | #ifdef CONFIG_VME | ||
49 | unsigned long vme_brdtype; | ||
50 | #endif | ||
51 | |||
52 | int m68k_is040or060; | ||
53 | |||
54 | extern int end; | ||
55 | extern unsigned long availmem; | ||
56 | |||
57 | int m68k_num_memory; | ||
58 | int m68k_realnum_memory; | ||
59 | unsigned long m68k_memoffset; | ||
60 | struct mem_info m68k_memory[NUM_MEMINFO]; | ||
61 | |||
62 | static struct mem_info m68k_ramdisk; | ||
63 | |||
64 | static char m68k_command_line[CL_SIZE]; | ||
65 | |||
66 | char m68k_debug_device[6] = ""; | ||
67 | |||
68 | void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL; | ||
69 | /* machine dependent irq functions */ | ||
70 | void (*mach_init_IRQ) (void) __initdata = NULL; | ||
71 | irqreturn_t (*(*mach_default_handler)[]) (int, void *, struct pt_regs *); | ||
72 | void (*mach_get_model) (char *model); | ||
73 | int (*mach_get_hardware_list) (char *buffer); | ||
74 | int (*mach_get_irq_list) (struct seq_file *, void *); | ||
75 | irqreturn_t (*mach_process_int) (int, struct pt_regs *); | ||
76 | /* machine dependent timer functions */ | ||
77 | unsigned long (*mach_gettimeoffset) (void); | ||
78 | int (*mach_hwclk) (int, struct rtc_time*); | ||
79 | int (*mach_set_clock_mmss) (unsigned long); | ||
80 | unsigned int (*mach_get_ss)(void); | ||
81 | int (*mach_get_rtc_pll)(struct rtc_pll_info *); | ||
82 | int (*mach_set_rtc_pll)(struct rtc_pll_info *); | ||
83 | void (*mach_reset)( void ); | ||
84 | void (*mach_halt)( void ); | ||
85 | void (*mach_power_off)( void ); | ||
86 | long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */ | ||
87 | #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) | ||
88 | void (*mach_floppy_setup) (char *, int *) __initdata = NULL; | ||
89 | #endif | ||
90 | #ifdef CONFIG_HEARTBEAT | ||
91 | void (*mach_heartbeat) (int); | ||
92 | EXPORT_SYMBOL(mach_heartbeat); | ||
93 | #endif | ||
94 | #ifdef CONFIG_M68K_L2_CACHE | ||
95 | void (*mach_l2_flush) (int); | ||
96 | #endif | ||
97 | #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) | ||
98 | void (*mach_beep)(unsigned int, unsigned int); | ||
99 | #endif | ||
100 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | ||
101 | int isa_type; | ||
102 | int isa_sex; | ||
103 | #endif | ||
104 | |||
105 | extern int amiga_parse_bootinfo(const struct bi_record *); | ||
106 | extern int atari_parse_bootinfo(const struct bi_record *); | ||
107 | extern int mac_parse_bootinfo(const struct bi_record *); | ||
108 | extern int q40_parse_bootinfo(const struct bi_record *); | ||
109 | extern int bvme6000_parse_bootinfo(const struct bi_record *); | ||
110 | extern int mvme16x_parse_bootinfo(const struct bi_record *); | ||
111 | extern int mvme147_parse_bootinfo(const struct bi_record *); | ||
112 | extern int hp300_parse_bootinfo(const struct bi_record *); | ||
113 | |||
114 | extern void config_amiga(void); | ||
115 | extern void config_atari(void); | ||
116 | extern void config_mac(void); | ||
117 | extern void config_sun3(void); | ||
118 | extern void config_apollo(void); | ||
119 | extern void config_mvme147(void); | ||
120 | extern void config_mvme16x(void); | ||
121 | extern void config_bvme6000(void); | ||
122 | extern void config_hp300(void); | ||
123 | extern void config_q40(void); | ||
124 | extern void config_sun3x(void); | ||
125 | |||
126 | extern void mac_debugging_short (int, short); | ||
127 | extern void mac_debugging_long (int, long); | ||
128 | |||
129 | #define MASK_256K 0xfffc0000 | ||
130 | |||
131 | extern void paging_init(void); | ||
132 | |||
133 | static void __init m68k_parse_bootinfo(const struct bi_record *record) | ||
134 | { | ||
135 | while (record->tag != BI_LAST) { | ||
136 | int unknown = 0; | ||
137 | const unsigned long *data = record->data; | ||
138 | switch (record->tag) { | ||
139 | case BI_MACHTYPE: | ||
140 | case BI_CPUTYPE: | ||
141 | case BI_FPUTYPE: | ||
142 | case BI_MMUTYPE: | ||
143 | /* Already set up by head.S */ | ||
144 | break; | ||
145 | |||
146 | case BI_MEMCHUNK: | ||
147 | if (m68k_num_memory < NUM_MEMINFO) { | ||
148 | m68k_memory[m68k_num_memory].addr = data[0]; | ||
149 | m68k_memory[m68k_num_memory].size = data[1]; | ||
150 | m68k_num_memory++; | ||
151 | } else | ||
152 | printk("m68k_parse_bootinfo: too many memory chunks\n"); | ||
153 | break; | ||
154 | |||
155 | case BI_RAMDISK: | ||
156 | m68k_ramdisk.addr = data[0]; | ||
157 | m68k_ramdisk.size = data[1]; | ||
158 | break; | ||
159 | |||
160 | case BI_COMMAND_LINE: | ||
161 | strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line)); | ||
162 | break; | ||
163 | |||
164 | default: | ||
165 | if (MACH_IS_AMIGA) | ||
166 | unknown = amiga_parse_bootinfo(record); | ||
167 | else if (MACH_IS_ATARI) | ||
168 | unknown = atari_parse_bootinfo(record); | ||
169 | else if (MACH_IS_MAC) | ||
170 | unknown = mac_parse_bootinfo(record); | ||
171 | else if (MACH_IS_Q40) | ||
172 | unknown = q40_parse_bootinfo(record); | ||
173 | else if (MACH_IS_BVME6000) | ||
174 | unknown = bvme6000_parse_bootinfo(record); | ||
175 | else if (MACH_IS_MVME16x) | ||
176 | unknown = mvme16x_parse_bootinfo(record); | ||
177 | else if (MACH_IS_MVME147) | ||
178 | unknown = mvme147_parse_bootinfo(record); | ||
179 | else if (MACH_IS_HP300) | ||
180 | unknown = hp300_parse_bootinfo(record); | ||
181 | else | ||
182 | unknown = 1; | ||
183 | } | ||
184 | if (unknown) | ||
185 | printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", | ||
186 | record->tag); | ||
187 | record = (struct bi_record *)((unsigned long)record+record->size); | ||
188 | } | ||
189 | |||
190 | m68k_realnum_memory = m68k_num_memory; | ||
191 | #ifdef CONFIG_SINGLE_MEMORY_CHUNK | ||
192 | if (m68k_num_memory > 1) { | ||
193 | printk("Ignoring last %i chunks of physical memory\n", | ||
194 | (m68k_num_memory - 1)); | ||
195 | m68k_num_memory = 1; | ||
196 | } | ||
197 | m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; | ||
198 | #endif | ||
199 | } | ||
200 | |||
201 | void __init setup_arch(char **cmdline_p) | ||
202 | { | ||
203 | extern int _etext, _edata, _end; | ||
204 | #ifndef CONFIG_SUN3 | ||
205 | unsigned long endmem, startmem; | ||
206 | #endif | ||
207 | int i; | ||
208 | char *p, *q; | ||
209 | |||
210 | /* The bootinfo is located right after the kernel bss */ | ||
211 | m68k_parse_bootinfo((const struct bi_record *)&_end); | ||
212 | |||
213 | if (CPU_IS_040) | ||
214 | m68k_is040or060 = 4; | ||
215 | else if (CPU_IS_060) | ||
216 | m68k_is040or060 = 6; | ||
217 | |||
218 | /* FIXME: m68k_fputype is passed in by Penguin booter, which can | ||
219 | * be confused by software FPU emulation. BEWARE. | ||
220 | * We should really do our own FPU check at startup. | ||
221 | * [what do we do with buggy 68LC040s? if we have problems | ||
222 | * with them, we should add a test to check_bugs() below] */ | ||
223 | #ifndef CONFIG_M68KFPU_EMU_ONLY | ||
224 | /* clear the fpu if we have one */ | ||
225 | if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { | ||
226 | volatile int zero = 0; | ||
227 | asm __volatile__ ("frestore %0" : : "m" (zero)); | ||
228 | } | ||
229 | #endif | ||
230 | |||
231 | if (CPU_IS_060) { | ||
232 | u32 pcr; | ||
233 | |||
234 | asm (".chip 68060; movec %%pcr,%0; .chip 68k" | ||
235 | : "=d" (pcr)); | ||
236 | if (((pcr >> 8) & 0xff) <= 5) { | ||
237 | printk("Enabling workaround for errata I14\n"); | ||
238 | asm (".chip 68060; movec %0,%%pcr; .chip 68k" | ||
239 | : : "d" (pcr | 0x20)); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | init_mm.start_code = PAGE_OFFSET; | ||
244 | init_mm.end_code = (unsigned long) &_etext; | ||
245 | init_mm.end_data = (unsigned long) &_edata; | ||
246 | init_mm.brk = (unsigned long) &_end; | ||
247 | |||
248 | *cmdline_p = m68k_command_line; | ||
249 | memcpy(saved_command_line, *cmdline_p, CL_SIZE); | ||
250 | |||
251 | /* Parse the command line for arch-specific options. | ||
252 | * For the m68k, this is currently only "debug=xxx" to enable printing | ||
253 | * certain kernel messages to some machine-specific device. | ||
254 | */ | ||
255 | for( p = *cmdline_p; p && *p; ) { | ||
256 | i = 0; | ||
257 | if (!strncmp( p, "debug=", 6 )) { | ||
258 | strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) ); | ||
259 | if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0; | ||
260 | i = 1; | ||
261 | } | ||
262 | #ifdef CONFIG_ATARI | ||
263 | /* This option must be parsed very early */ | ||
264 | if (!strncmp( p, "switches=", 9 )) { | ||
265 | extern void atari_switches_setup( const char *, int ); | ||
266 | atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ? | ||
267 | (q - (p+9)) : strlen(p+9) ); | ||
268 | i = 1; | ||
269 | } | ||
270 | #endif | ||
271 | |||
272 | if (i) { | ||
273 | /* option processed, delete it */ | ||
274 | if ((q = strchr( p, ' ' ))) | ||
275 | strcpy( p, q+1 ); | ||
276 | else | ||
277 | *p = 0; | ||
278 | } else { | ||
279 | if ((p = strchr( p, ' ' ))) ++p; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | switch (m68k_machtype) { | ||
284 | #ifdef CONFIG_AMIGA | ||
285 | case MACH_AMIGA: | ||
286 | config_amiga(); | ||
287 | break; | ||
288 | #endif | ||
289 | #ifdef CONFIG_ATARI | ||
290 | case MACH_ATARI: | ||
291 | config_atari(); | ||
292 | break; | ||
293 | #endif | ||
294 | #ifdef CONFIG_MAC | ||
295 | case MACH_MAC: | ||
296 | config_mac(); | ||
297 | break; | ||
298 | #endif | ||
299 | #ifdef CONFIG_SUN3 | ||
300 | case MACH_SUN3: | ||
301 | config_sun3(); | ||
302 | break; | ||
303 | #endif | ||
304 | #ifdef CONFIG_APOLLO | ||
305 | case MACH_APOLLO: | ||
306 | config_apollo(); | ||
307 | break; | ||
308 | #endif | ||
309 | #ifdef CONFIG_MVME147 | ||
310 | case MACH_MVME147: | ||
311 | config_mvme147(); | ||
312 | break; | ||
313 | #endif | ||
314 | #ifdef CONFIG_MVME16x | ||
315 | case MACH_MVME16x: | ||
316 | config_mvme16x(); | ||
317 | break; | ||
318 | #endif | ||
319 | #ifdef CONFIG_BVME6000 | ||
320 | case MACH_BVME6000: | ||
321 | config_bvme6000(); | ||
322 | break; | ||
323 | #endif | ||
324 | #ifdef CONFIG_HP300 | ||
325 | case MACH_HP300: | ||
326 | config_hp300(); | ||
327 | break; | ||
328 | #endif | ||
329 | #ifdef CONFIG_Q40 | ||
330 | case MACH_Q40: | ||
331 | config_q40(); | ||
332 | break; | ||
333 | #endif | ||
334 | #ifdef CONFIG_SUN3X | ||
335 | case MACH_SUN3X: | ||
336 | config_sun3x(); | ||
337 | break; | ||
338 | #endif | ||
339 | default: | ||
340 | panic ("No configuration setup"); | ||
341 | } | ||
342 | |||
343 | #ifndef CONFIG_SUN3 | ||
344 | startmem= m68k_memory[0].addr; | ||
345 | endmem = startmem + m68k_memory[0].size; | ||
346 | high_memory = (void *)PAGE_OFFSET; | ||
347 | for (i = 0; i < m68k_num_memory; i++) { | ||
348 | m68k_memory[i].size &= MASK_256K; | ||
349 | if (m68k_memory[i].addr < startmem) | ||
350 | startmem = m68k_memory[i].addr; | ||
351 | if (m68k_memory[i].addr+m68k_memory[i].size > endmem) | ||
352 | endmem = m68k_memory[i].addr+m68k_memory[i].size; | ||
353 | high_memory += m68k_memory[i].size; | ||
354 | } | ||
355 | |||
356 | availmem += init_bootmem_node(NODE_DATA(0), availmem >> PAGE_SHIFT, | ||
357 | startmem >> PAGE_SHIFT, endmem >> PAGE_SHIFT); | ||
358 | |||
359 | for (i = 0; i < m68k_num_memory; i++) | ||
360 | free_bootmem(m68k_memory[i].addr, m68k_memory[i].size); | ||
361 | |||
362 | reserve_bootmem(m68k_memory[0].addr, availmem - m68k_memory[0].addr); | ||
363 | |||
364 | #ifdef CONFIG_BLK_DEV_INITRD | ||
365 | if (m68k_ramdisk.size) { | ||
366 | reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size); | ||
367 | initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); | ||
368 | initrd_end = initrd_start + m68k_ramdisk.size; | ||
369 | printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end); | ||
370 | } | ||
371 | #endif | ||
372 | |||
373 | #ifdef CONFIG_ATARI | ||
374 | if (MACH_IS_ATARI) | ||
375 | atari_stram_reserve_pages((void *)availmem); | ||
376 | #endif | ||
377 | #ifdef CONFIG_SUN3X | ||
378 | if (MACH_IS_SUN3X) { | ||
379 | dvma_init(); | ||
380 | } | ||
381 | #endif | ||
382 | |||
383 | #endif /* !CONFIG_SUN3 */ | ||
384 | |||
385 | paging_init(); | ||
386 | |||
387 | /* set ISA defs early as possible */ | ||
388 | #if defined(CONFIG_ISA) && defined(MULTI_ISA) | ||
389 | #if defined(CONFIG_Q40) | ||
390 | if (MACH_IS_Q40) { | ||
391 | isa_type = Q40_ISA; | ||
392 | isa_sex = 0; | ||
393 | } | ||
394 | #elif defined(CONFIG_GG2) | ||
395 | if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){ | ||
396 | isa_type = GG2_ISA; | ||
397 | isa_sex = 0; | ||
398 | } | ||
399 | #elif defined(CONFIG_AMIGA_PCMCIA) | ||
400 | if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){ | ||
401 | isa_type = AG_ISA; | ||
402 | isa_sex = 1; | ||
403 | } | ||
404 | #endif | ||
405 | #endif | ||
406 | } | ||
407 | |||
408 | static int show_cpuinfo(struct seq_file *m, void *v) | ||
409 | { | ||
410 | const char *cpu, *mmu, *fpu; | ||
411 | unsigned long clockfreq, clockfactor; | ||
412 | |||
413 | #define LOOP_CYCLES_68020 (8) | ||
414 | #define LOOP_CYCLES_68030 (8) | ||
415 | #define LOOP_CYCLES_68040 (3) | ||
416 | #define LOOP_CYCLES_68060 (1) | ||
417 | |||
418 | if (CPU_IS_020) { | ||
419 | cpu = "68020"; | ||
420 | clockfactor = LOOP_CYCLES_68020; | ||
421 | } else if (CPU_IS_030) { | ||
422 | cpu = "68030"; | ||
423 | clockfactor = LOOP_CYCLES_68030; | ||
424 | } else if (CPU_IS_040) { | ||
425 | cpu = "68040"; | ||
426 | clockfactor = LOOP_CYCLES_68040; | ||
427 | } else if (CPU_IS_060) { | ||
428 | cpu = "68060"; | ||
429 | clockfactor = LOOP_CYCLES_68060; | ||
430 | } else { | ||
431 | cpu = "680x0"; | ||
432 | clockfactor = 0; | ||
433 | } | ||
434 | |||
435 | #ifdef CONFIG_M68KFPU_EMU_ONLY | ||
436 | fpu="none(soft float)"; | ||
437 | #else | ||
438 | if (m68k_fputype & FPU_68881) | ||
439 | fpu = "68881"; | ||
440 | else if (m68k_fputype & FPU_68882) | ||
441 | fpu = "68882"; | ||
442 | else if (m68k_fputype & FPU_68040) | ||
443 | fpu = "68040"; | ||
444 | else if (m68k_fputype & FPU_68060) | ||
445 | fpu = "68060"; | ||
446 | else if (m68k_fputype & FPU_SUNFPA) | ||
447 | fpu = "Sun FPA"; | ||
448 | else | ||
449 | fpu = "none"; | ||
450 | #endif | ||
451 | |||
452 | if (m68k_mmutype & MMU_68851) | ||
453 | mmu = "68851"; | ||
454 | else if (m68k_mmutype & MMU_68030) | ||
455 | mmu = "68030"; | ||
456 | else if (m68k_mmutype & MMU_68040) | ||
457 | mmu = "68040"; | ||
458 | else if (m68k_mmutype & MMU_68060) | ||
459 | mmu = "68060"; | ||
460 | else if (m68k_mmutype & MMU_SUN3) | ||
461 | mmu = "Sun-3"; | ||
462 | else if (m68k_mmutype & MMU_APOLLO) | ||
463 | mmu = "Apollo"; | ||
464 | else | ||
465 | mmu = "unknown"; | ||
466 | |||
467 | clockfreq = loops_per_jiffy*HZ*clockfactor; | ||
468 | |||
469 | seq_printf(m, "CPU:\t\t%s\n" | ||
470 | "MMU:\t\t%s\n" | ||
471 | "FPU:\t\t%s\n" | ||
472 | "Clocking:\t%lu.%1luMHz\n" | ||
473 | "BogoMips:\t%lu.%02lu\n" | ||
474 | "Calibration:\t%lu loops\n", | ||
475 | cpu, mmu, fpu, | ||
476 | clockfreq/1000000,(clockfreq/100000)%10, | ||
477 | loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, | ||
478 | loops_per_jiffy); | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
483 | { | ||
484 | return *pos < 1 ? (void *)1 : NULL; | ||
485 | } | ||
486 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
487 | { | ||
488 | ++*pos; | ||
489 | return NULL; | ||
490 | } | ||
491 | static void c_stop(struct seq_file *m, void *v) | ||
492 | { | ||
493 | } | ||
494 | struct seq_operations cpuinfo_op = { | ||
495 | .start = c_start, | ||
496 | .next = c_next, | ||
497 | .stop = c_stop, | ||
498 | .show = show_cpuinfo, | ||
499 | }; | ||
500 | |||
501 | int get_hardware_list(char *buffer) | ||
502 | { | ||
503 | int len = 0; | ||
504 | char model[80]; | ||
505 | unsigned long mem; | ||
506 | int i; | ||
507 | |||
508 | if (mach_get_model) | ||
509 | mach_get_model(model); | ||
510 | else | ||
511 | strcpy(model, "Unknown m68k"); | ||
512 | |||
513 | len += sprintf(buffer+len, "Model:\t\t%s\n", model); | ||
514 | for (mem = 0, i = 0; i < m68k_num_memory; i++) | ||
515 | mem += m68k_memory[i].size; | ||
516 | len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); | ||
517 | |||
518 | if (mach_get_hardware_list) | ||
519 | len += mach_get_hardware_list(buffer+len); | ||
520 | |||
521 | return(len); | ||
522 | } | ||
523 | |||
524 | |||
525 | #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) | ||
526 | void __init floppy_setup(char *str, int *ints) | ||
527 | { | ||
528 | if (mach_floppy_setup) | ||
529 | mach_floppy_setup (str, ints); | ||
530 | } | ||
531 | |||
532 | #endif | ||
533 | |||
534 | void check_bugs(void) | ||
535 | { | ||
536 | #ifndef CONFIG_M68KFPU_EMU | ||
537 | if (m68k_fputype == 0) { | ||
538 | printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " | ||
539 | "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); | ||
540 | printk( KERN_EMERG "Upgrade your hardware or join the FPU " | ||
541 | "emulation project\n" ); | ||
542 | panic( "no FPU" ); | ||
543 | } | ||
544 | #endif /* !CONFIG_M68KFPU_EMU */ | ||
545 | } | ||
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c new file mode 100644 index 000000000000..9c636a4c238d --- /dev/null +++ b/arch/m68k/kernel/signal.c | |||
@@ -0,0 +1,1025 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/signal.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Linux/m68k support by Hamish Macdonald | ||
13 | * | ||
14 | * 68060 fixes by Jesper Skov | ||
15 | * | ||
16 | * 1997-12-01 Modified for POSIX.1b signals by Andreas Schwab | ||
17 | * | ||
18 | * mathemu support by Roman Zippel | ||
19 | * (Note: fpstate in the signal context is completely ignored for the emulator | ||
20 | * and the internal floating point format is put on stack) | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * ++roman (07/09/96): implemented signal stacks (specially for tosemu on | ||
25 | * Atari :-) Current limitation: Only one sigstack can be active at one time. | ||
26 | * If a second signal with SA_ONSTACK set arrives while working on a sigstack, | ||
27 | * SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested | ||
28 | * signal handlers! | ||
29 | */ | ||
30 | |||
31 | #include <linux/sched.h> | ||
32 | #include <linux/mm.h> | ||
33 | #include <linux/kernel.h> | ||
34 | #include <linux/signal.h> | ||
35 | #include <linux/syscalls.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/wait.h> | ||
38 | #include <linux/ptrace.h> | ||
39 | #include <linux/unistd.h> | ||
40 | #include <linux/stddef.h> | ||
41 | #include <linux/highuid.h> | ||
42 | #include <linux/personality.h> | ||
43 | #include <linux/tty.h> | ||
44 | #include <linux/binfmts.h> | ||
45 | |||
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 | const int frame_extra_sizes[16] = { | ||
57 | [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */ | ||
58 | [2] = sizeof(((struct frame *)0)->un.fmt2), | ||
59 | [3] = sizeof(((struct frame *)0)->un.fmt3), | ||
60 | [4] = sizeof(((struct frame *)0)->un.fmt4), | ||
61 | [5] = -1, /* sizeof(((struct frame *)0)->un.fmt5), */ | ||
62 | [6] = -1, /* sizeof(((struct frame *)0)->un.fmt6), */ | ||
63 | [7] = sizeof(((struct frame *)0)->un.fmt7), | ||
64 | [8] = -1, /* sizeof(((struct frame *)0)->un.fmt8), */ | ||
65 | [9] = sizeof(((struct frame *)0)->un.fmt9), | ||
66 | [10] = sizeof(((struct frame *)0)->un.fmta), | ||
67 | [11] = sizeof(((struct frame *)0)->un.fmtb), | ||
68 | [12] = -1, /* sizeof(((struct frame *)0)->un.fmtc), */ | ||
69 | [13] = -1, /* sizeof(((struct frame *)0)->un.fmtd), */ | ||
70 | [14] = -1, /* sizeof(((struct frame *)0)->un.fmte), */ | ||
71 | [15] = -1, /* sizeof(((struct frame *)0)->un.fmtf), */ | ||
72 | }; | ||
73 | |||
74 | /* | ||
75 | * Atomically swap in the new signal mask, and wait for a signal. | ||
76 | */ | ||
77 | asmlinkage int do_sigsuspend(struct pt_regs *regs) | ||
78 | { | ||
79 | old_sigset_t mask = regs->d3; | ||
80 | sigset_t saveset; | ||
81 | |||
82 | mask &= _BLOCKABLE; | ||
83 | saveset = current->blocked; | ||
84 | siginitset(¤t->blocked, mask); | ||
85 | recalc_sigpending(); | ||
86 | |||
87 | regs->d0 = -EINTR; | ||
88 | while (1) { | ||
89 | current->state = TASK_INTERRUPTIBLE; | ||
90 | schedule(); | ||
91 | if (do_signal(&saveset, regs)) | ||
92 | return -EINTR; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | asmlinkage int | ||
97 | do_rt_sigsuspend(struct pt_regs *regs) | ||
98 | { | ||
99 | sigset_t *unewset = (sigset_t *)regs->d1; | ||
100 | size_t sigsetsize = (size_t)regs->d2; | ||
101 | sigset_t saveset, newset; | ||
102 | |||
103 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
104 | if (sigsetsize != sizeof(sigset_t)) | ||
105 | return -EINVAL; | ||
106 | |||
107 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
108 | return -EFAULT; | ||
109 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
110 | |||
111 | saveset = current->blocked; | ||
112 | current->blocked = newset; | ||
113 | recalc_sigpending(); | ||
114 | |||
115 | regs->d0 = -EINTR; | ||
116 | while (1) { | ||
117 | current->state = TASK_INTERRUPTIBLE; | ||
118 | schedule(); | ||
119 | if (do_signal(&saveset, regs)) | ||
120 | return -EINTR; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | asmlinkage int | ||
125 | sys_sigaction(int sig, const struct old_sigaction *act, | ||
126 | struct old_sigaction *oact) | ||
127 | { | ||
128 | struct k_sigaction new_ka, old_ka; | ||
129 | int ret; | ||
130 | |||
131 | if (act) { | ||
132 | old_sigset_t mask; | ||
133 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
134 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
135 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
136 | return -EFAULT; | ||
137 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
138 | __get_user(mask, &act->sa_mask); | ||
139 | siginitset(&new_ka.sa.sa_mask, mask); | ||
140 | } | ||
141 | |||
142 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
143 | |||
144 | if (!ret && oact) { | ||
145 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
146 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
147 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
148 | return -EFAULT; | ||
149 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
150 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
151 | } | ||
152 | |||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | asmlinkage int | ||
157 | sys_sigaltstack(const stack_t *uss, stack_t *uoss) | ||
158 | { | ||
159 | return do_sigaltstack(uss, uoss, rdusp()); | ||
160 | } | ||
161 | |||
162 | |||
163 | /* | ||
164 | * Do a signal return; undo the signal stack. | ||
165 | * | ||
166 | * Keep the return code on the stack quadword aligned! | ||
167 | * That makes the cache flush below easier. | ||
168 | */ | ||
169 | |||
170 | struct sigframe | ||
171 | { | ||
172 | char *pretcode; | ||
173 | int sig; | ||
174 | int code; | ||
175 | struct sigcontext *psc; | ||
176 | char retcode[8]; | ||
177 | unsigned long extramask[_NSIG_WORDS-1]; | ||
178 | struct sigcontext sc; | ||
179 | }; | ||
180 | |||
181 | struct rt_sigframe | ||
182 | { | ||
183 | char *pretcode; | ||
184 | int sig; | ||
185 | struct siginfo *pinfo; | ||
186 | void *puc; | ||
187 | char retcode[8]; | ||
188 | struct siginfo info; | ||
189 | struct ucontext uc; | ||
190 | }; | ||
191 | |||
192 | |||
193 | static unsigned char fpu_version; /* version number of fpu, set by setup_frame */ | ||
194 | |||
195 | static inline int restore_fpu_state(struct sigcontext *sc) | ||
196 | { | ||
197 | int err = 1; | ||
198 | |||
199 | if (FPU_IS_EMU) { | ||
200 | /* restore registers */ | ||
201 | memcpy(current->thread.fpcntl, sc->sc_fpcntl, 12); | ||
202 | memcpy(current->thread.fp, sc->sc_fpregs, 24); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | ||
207 | /* Verify the frame format. */ | ||
208 | if (!CPU_IS_060 && (sc->sc_fpstate[0] != fpu_version)) | ||
209 | goto out; | ||
210 | if (CPU_IS_020_OR_030) { | ||
211 | if (m68k_fputype & FPU_68881 && | ||
212 | !(sc->sc_fpstate[1] == 0x18 || sc->sc_fpstate[1] == 0xb4)) | ||
213 | goto out; | ||
214 | if (m68k_fputype & FPU_68882 && | ||
215 | !(sc->sc_fpstate[1] == 0x38 || sc->sc_fpstate[1] == 0xd4)) | ||
216 | goto out; | ||
217 | } else if (CPU_IS_040) { | ||
218 | if (!(sc->sc_fpstate[1] == 0x00 || | ||
219 | sc->sc_fpstate[1] == 0x28 || | ||
220 | sc->sc_fpstate[1] == 0x60)) | ||
221 | goto out; | ||
222 | } else if (CPU_IS_060) { | ||
223 | if (!(sc->sc_fpstate[3] == 0x00 || | ||
224 | sc->sc_fpstate[3] == 0x60 || | ||
225 | sc->sc_fpstate[3] == 0xe0)) | ||
226 | goto out; | ||
227 | } else | ||
228 | goto out; | ||
229 | |||
230 | __asm__ volatile (".chip 68k/68881\n\t" | ||
231 | "fmovemx %0,%%fp0-%%fp1\n\t" | ||
232 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | ||
233 | ".chip 68k" | ||
234 | : /* no outputs */ | ||
235 | : "m" (*sc->sc_fpregs), "m" (*sc->sc_fpcntl)); | ||
236 | } | ||
237 | __asm__ volatile (".chip 68k/68881\n\t" | ||
238 | "frestore %0\n\t" | ||
239 | ".chip 68k" : : "m" (*sc->sc_fpstate)); | ||
240 | err = 0; | ||
241 | |||
242 | out: | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | #define FPCONTEXT_SIZE 216 | ||
247 | #define uc_fpstate uc_filler[0] | ||
248 | #define uc_formatvec uc_filler[FPCONTEXT_SIZE/4] | ||
249 | #define uc_extra uc_filler[FPCONTEXT_SIZE/4+1] | ||
250 | |||
251 | static inline int rt_restore_fpu_state(struct ucontext *uc) | ||
252 | { | ||
253 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
254 | int context_size = CPU_IS_060 ? 8 : 0; | ||
255 | fpregset_t fpregs; | ||
256 | int err = 1; | ||
257 | |||
258 | if (FPU_IS_EMU) { | ||
259 | /* restore fpu control register */ | ||
260 | if (__copy_from_user(current->thread.fpcntl, | ||
261 | uc->uc_mcontext.fpregs.f_fpcntl, 12)) | ||
262 | goto out; | ||
263 | /* restore all other fpu register */ | ||
264 | if (__copy_from_user(current->thread.fp, | ||
265 | uc->uc_mcontext.fpregs.f_fpregs, 96)) | ||
266 | goto out; | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | if (__get_user(*(long *)fpstate, (long *)&uc->uc_fpstate)) | ||
271 | goto out; | ||
272 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | ||
273 | if (!CPU_IS_060) | ||
274 | context_size = fpstate[1]; | ||
275 | /* Verify the frame format. */ | ||
276 | if (!CPU_IS_060 && (fpstate[0] != fpu_version)) | ||
277 | goto out; | ||
278 | if (CPU_IS_020_OR_030) { | ||
279 | if (m68k_fputype & FPU_68881 && | ||
280 | !(context_size == 0x18 || context_size == 0xb4)) | ||
281 | goto out; | ||
282 | if (m68k_fputype & FPU_68882 && | ||
283 | !(context_size == 0x38 || context_size == 0xd4)) | ||
284 | goto out; | ||
285 | } else if (CPU_IS_040) { | ||
286 | if (!(context_size == 0x00 || | ||
287 | context_size == 0x28 || | ||
288 | context_size == 0x60)) | ||
289 | goto out; | ||
290 | } else if (CPU_IS_060) { | ||
291 | if (!(fpstate[3] == 0x00 || | ||
292 | fpstate[3] == 0x60 || | ||
293 | fpstate[3] == 0xe0)) | ||
294 | goto out; | ||
295 | } else | ||
296 | goto out; | ||
297 | if (__copy_from_user(&fpregs, &uc->uc_mcontext.fpregs, | ||
298 | sizeof(fpregs))) | ||
299 | goto out; | ||
300 | __asm__ volatile (".chip 68k/68881\n\t" | ||
301 | "fmovemx %0,%%fp0-%%fp7\n\t" | ||
302 | "fmoveml %1,%%fpcr/%%fpsr/%%fpiar\n\t" | ||
303 | ".chip 68k" | ||
304 | : /* no outputs */ | ||
305 | : "m" (*fpregs.f_fpregs), | ||
306 | "m" (*fpregs.f_fpcntl)); | ||
307 | } | ||
308 | if (context_size && | ||
309 | __copy_from_user(fpstate + 4, (long *)&uc->uc_fpstate + 1, | ||
310 | context_size)) | ||
311 | goto out; | ||
312 | __asm__ volatile (".chip 68k/68881\n\t" | ||
313 | "frestore %0\n\t" | ||
314 | ".chip 68k" : : "m" (*fpstate)); | ||
315 | err = 0; | ||
316 | |||
317 | out: | ||
318 | return err; | ||
319 | } | ||
320 | |||
321 | static inline int | ||
322 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *usc, void *fp, | ||
323 | int *pd0) | ||
324 | { | ||
325 | int fsize, formatvec; | ||
326 | struct sigcontext context; | ||
327 | int err; | ||
328 | |||
329 | /* get previous context */ | ||
330 | if (copy_from_user(&context, usc, sizeof(context))) | ||
331 | goto badframe; | ||
332 | |||
333 | /* restore passed registers */ | ||
334 | regs->d1 = context.sc_d1; | ||
335 | regs->a0 = context.sc_a0; | ||
336 | regs->a1 = context.sc_a1; | ||
337 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
338 | regs->pc = context.sc_pc; | ||
339 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
340 | wrusp(context.sc_usp); | ||
341 | formatvec = context.sc_formatvec; | ||
342 | regs->format = formatvec >> 12; | ||
343 | regs->vector = formatvec & 0xfff; | ||
344 | |||
345 | err = restore_fpu_state(&context); | ||
346 | |||
347 | fsize = frame_extra_sizes[regs->format]; | ||
348 | if (fsize < 0) { | ||
349 | /* | ||
350 | * user process trying to return with weird frame format | ||
351 | */ | ||
352 | #ifdef DEBUG | ||
353 | printk("user process returning with weird frame format\n"); | ||
354 | #endif | ||
355 | goto badframe; | ||
356 | } | ||
357 | |||
358 | /* OK. Make room on the supervisor stack for the extra junk, | ||
359 | * if necessary. | ||
360 | */ | ||
361 | |||
362 | if (fsize) { | ||
363 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
364 | regs->d0 = context.sc_d0; | ||
365 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | ||
366 | __asm__ __volatile__ | ||
367 | (" movel %0,%/a0\n\t" | ||
368 | " subl %1,%/a0\n\t" /* make room on stack */ | ||
369 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | ||
370 | /* move switch_stack and pt_regs */ | ||
371 | "1: movel %0@+,%/a0@+\n\t" | ||
372 | " dbra %2,1b\n\t" | ||
373 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | ||
374 | " lsrl #2,%1\n\t" | ||
375 | " subql #1,%1\n\t" | ||
376 | "2: movesl %4@+,%2\n\t" | ||
377 | "3: movel %2,%/a0@+\n\t" | ||
378 | " dbra %1,2b\n\t" | ||
379 | " bral ret_from_signal\n" | ||
380 | "4:\n" | ||
381 | ".section __ex_table,\"a\"\n" | ||
382 | " .align 4\n" | ||
383 | " .long 2b,4b\n" | ||
384 | " .long 3b,4b\n" | ||
385 | ".previous" | ||
386 | : /* no outputs, it doesn't ever return */ | ||
387 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | ||
388 | "n" (frame_offset), "a" (fp) | ||
389 | : "a0"); | ||
390 | #undef frame_offset | ||
391 | /* | ||
392 | * If we ever get here an exception occurred while | ||
393 | * building the above stack-frame. | ||
394 | */ | ||
395 | goto badframe; | ||
396 | } | ||
397 | |||
398 | *pd0 = context.sc_d0; | ||
399 | return err; | ||
400 | |||
401 | badframe: | ||
402 | return 1; | ||
403 | } | ||
404 | |||
405 | static inline int | ||
406 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | ||
407 | struct ucontext *uc, int *pd0) | ||
408 | { | ||
409 | int fsize, temp; | ||
410 | greg_t *gregs = uc->uc_mcontext.gregs; | ||
411 | unsigned long usp; | ||
412 | int err; | ||
413 | |||
414 | err = __get_user(temp, &uc->uc_mcontext.version); | ||
415 | if (temp != MCONTEXT_VERSION) | ||
416 | goto badframe; | ||
417 | /* restore passed registers */ | ||
418 | err |= __get_user(regs->d0, &gregs[0]); | ||
419 | err |= __get_user(regs->d1, &gregs[1]); | ||
420 | err |= __get_user(regs->d2, &gregs[2]); | ||
421 | err |= __get_user(regs->d3, &gregs[3]); | ||
422 | err |= __get_user(regs->d4, &gregs[4]); | ||
423 | err |= __get_user(regs->d5, &gregs[5]); | ||
424 | err |= __get_user(sw->d6, &gregs[6]); | ||
425 | err |= __get_user(sw->d7, &gregs[7]); | ||
426 | err |= __get_user(regs->a0, &gregs[8]); | ||
427 | err |= __get_user(regs->a1, &gregs[9]); | ||
428 | err |= __get_user(regs->a2, &gregs[10]); | ||
429 | err |= __get_user(sw->a3, &gregs[11]); | ||
430 | err |= __get_user(sw->a4, &gregs[12]); | ||
431 | err |= __get_user(sw->a5, &gregs[13]); | ||
432 | err |= __get_user(sw->a6, &gregs[14]); | ||
433 | err |= __get_user(usp, &gregs[15]); | ||
434 | wrusp(usp); | ||
435 | err |= __get_user(regs->pc, &gregs[16]); | ||
436 | err |= __get_user(temp, &gregs[17]); | ||
437 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | ||
438 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
439 | err |= __get_user(temp, &uc->uc_formatvec); | ||
440 | regs->format = temp >> 12; | ||
441 | regs->vector = temp & 0xfff; | ||
442 | |||
443 | err |= rt_restore_fpu_state(uc); | ||
444 | |||
445 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | ||
446 | goto badframe; | ||
447 | |||
448 | fsize = frame_extra_sizes[regs->format]; | ||
449 | if (fsize < 0) { | ||
450 | /* | ||
451 | * user process trying to return with weird frame format | ||
452 | */ | ||
453 | #ifdef DEBUG | ||
454 | printk("user process returning with weird frame format\n"); | ||
455 | #endif | ||
456 | goto badframe; | ||
457 | } | ||
458 | |||
459 | /* OK. Make room on the supervisor stack for the extra junk, | ||
460 | * if necessary. | ||
461 | */ | ||
462 | |||
463 | if (fsize) { | ||
464 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | ||
465 | __asm__ __volatile__ | ||
466 | (" movel %0,%/a0\n\t" | ||
467 | " subl %1,%/a0\n\t" /* make room on stack */ | ||
468 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | ||
469 | /* move switch_stack and pt_regs */ | ||
470 | "1: movel %0@+,%/a0@+\n\t" | ||
471 | " dbra %2,1b\n\t" | ||
472 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | ||
473 | " lsrl #2,%1\n\t" | ||
474 | " subql #1,%1\n\t" | ||
475 | "2: movesl %4@+,%2\n\t" | ||
476 | "3: movel %2,%/a0@+\n\t" | ||
477 | " dbra %1,2b\n\t" | ||
478 | " bral ret_from_signal\n" | ||
479 | "4:\n" | ||
480 | ".section __ex_table,\"a\"\n" | ||
481 | " .align 4\n" | ||
482 | " .long 2b,4b\n" | ||
483 | " .long 3b,4b\n" | ||
484 | ".previous" | ||
485 | : /* no outputs, it doesn't ever return */ | ||
486 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | ||
487 | "n" (frame_offset), "a" (&uc->uc_extra) | ||
488 | : "a0"); | ||
489 | #undef frame_offset | ||
490 | /* | ||
491 | * If we ever get here an exception occurred while | ||
492 | * building the above stack-frame. | ||
493 | */ | ||
494 | goto badframe; | ||
495 | } | ||
496 | |||
497 | *pd0 = regs->d0; | ||
498 | return err; | ||
499 | |||
500 | badframe: | ||
501 | return 1; | ||
502 | } | ||
503 | |||
504 | asmlinkage int do_sigreturn(unsigned long __unused) | ||
505 | { | ||
506 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
507 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
508 | unsigned long usp = rdusp(); | ||
509 | struct sigframe *frame = (struct sigframe *)(usp - 4); | ||
510 | sigset_t set; | ||
511 | int d0; | ||
512 | |||
513 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
514 | goto badframe; | ||
515 | if (__get_user(set.sig[0], &frame->sc.sc_mask) || | ||
516 | (_NSIG_WORDS > 1 && | ||
517 | __copy_from_user(&set.sig[1], &frame->extramask, | ||
518 | sizeof(frame->extramask)))) | ||
519 | goto badframe; | ||
520 | |||
521 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
522 | current->blocked = set; | ||
523 | recalc_sigpending(); | ||
524 | |||
525 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) | ||
526 | goto badframe; | ||
527 | return d0; | ||
528 | |||
529 | badframe: | ||
530 | force_sig(SIGSEGV, current); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | asmlinkage int do_rt_sigreturn(unsigned long __unused) | ||
535 | { | ||
536 | struct switch_stack *sw = (struct switch_stack *) &__unused; | ||
537 | struct pt_regs *regs = (struct pt_regs *) (sw + 1); | ||
538 | unsigned long usp = rdusp(); | ||
539 | struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4); | ||
540 | sigset_t set; | ||
541 | int d0; | ||
542 | |||
543 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
544 | goto badframe; | ||
545 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
546 | goto badframe; | ||
547 | |||
548 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
549 | current->blocked = set; | ||
550 | recalc_sigpending(); | ||
551 | |||
552 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) | ||
553 | goto badframe; | ||
554 | return d0; | ||
555 | |||
556 | badframe: | ||
557 | force_sig(SIGSEGV, current); | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | /* | ||
562 | * Set up a signal frame. | ||
563 | */ | ||
564 | |||
565 | static inline void save_fpu_state(struct sigcontext *sc, struct pt_regs *regs) | ||
566 | { | ||
567 | if (FPU_IS_EMU) { | ||
568 | /* save registers */ | ||
569 | memcpy(sc->sc_fpcntl, current->thread.fpcntl, 12); | ||
570 | memcpy(sc->sc_fpregs, current->thread.fp, 24); | ||
571 | return; | ||
572 | } | ||
573 | |||
574 | __asm__ volatile (".chip 68k/68881\n\t" | ||
575 | "fsave %0\n\t" | ||
576 | ".chip 68k" | ||
577 | : : "m" (*sc->sc_fpstate) : "memory"); | ||
578 | |||
579 | if (CPU_IS_060 ? sc->sc_fpstate[2] : sc->sc_fpstate[0]) { | ||
580 | fpu_version = sc->sc_fpstate[0]; | ||
581 | if (CPU_IS_020_OR_030 && | ||
582 | regs->vector >= (VEC_FPBRUC * 4) && | ||
583 | regs->vector <= (VEC_FPNAN * 4)) { | ||
584 | /* Clear pending exception in 68882 idle frame */ | ||
585 | if (*(unsigned short *) sc->sc_fpstate == 0x1f38) | ||
586 | sc->sc_fpstate[0x38] |= 1 << 3; | ||
587 | } | ||
588 | __asm__ volatile (".chip 68k/68881\n\t" | ||
589 | "fmovemx %%fp0-%%fp1,%0\n\t" | ||
590 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | ||
591 | ".chip 68k" | ||
592 | : "=m" (*sc->sc_fpregs), | ||
593 | "=m" (*sc->sc_fpcntl) | ||
594 | : /* no inputs */ | ||
595 | : "memory"); | ||
596 | } | ||
597 | } | ||
598 | |||
599 | static inline int rt_save_fpu_state(struct ucontext *uc, struct pt_regs *regs) | ||
600 | { | ||
601 | unsigned char fpstate[FPCONTEXT_SIZE]; | ||
602 | int context_size = CPU_IS_060 ? 8 : 0; | ||
603 | int err = 0; | ||
604 | |||
605 | if (FPU_IS_EMU) { | ||
606 | /* save fpu control register */ | ||
607 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpcntl, | ||
608 | current->thread.fpcntl, 12); | ||
609 | /* save all other fpu register */ | ||
610 | err |= copy_to_user(uc->uc_mcontext.fpregs.f_fpregs, | ||
611 | current->thread.fp, 96); | ||
612 | return err; | ||
613 | } | ||
614 | |||
615 | __asm__ volatile (".chip 68k/68881\n\t" | ||
616 | "fsave %0\n\t" | ||
617 | ".chip 68k" | ||
618 | : : "m" (*fpstate) : "memory"); | ||
619 | |||
620 | err |= __put_user(*(long *)fpstate, (long *)&uc->uc_fpstate); | ||
621 | if (CPU_IS_060 ? fpstate[2] : fpstate[0]) { | ||
622 | fpregset_t fpregs; | ||
623 | if (!CPU_IS_060) | ||
624 | context_size = fpstate[1]; | ||
625 | fpu_version = fpstate[0]; | ||
626 | if (CPU_IS_020_OR_030 && | ||
627 | regs->vector >= (VEC_FPBRUC * 4) && | ||
628 | regs->vector <= (VEC_FPNAN * 4)) { | ||
629 | /* Clear pending exception in 68882 idle frame */ | ||
630 | if (*(unsigned short *) fpstate == 0x1f38) | ||
631 | fpstate[0x38] |= 1 << 3; | ||
632 | } | ||
633 | __asm__ volatile (".chip 68k/68881\n\t" | ||
634 | "fmovemx %%fp0-%%fp7,%0\n\t" | ||
635 | "fmoveml %%fpcr/%%fpsr/%%fpiar,%1\n\t" | ||
636 | ".chip 68k" | ||
637 | : "=m" (*fpregs.f_fpregs), | ||
638 | "=m" (*fpregs.f_fpcntl) | ||
639 | : /* no inputs */ | ||
640 | : "memory"); | ||
641 | err |= copy_to_user(&uc->uc_mcontext.fpregs, &fpregs, | ||
642 | sizeof(fpregs)); | ||
643 | } | ||
644 | if (context_size) | ||
645 | err |= copy_to_user((long *)&uc->uc_fpstate + 1, fpstate + 4, | ||
646 | context_size); | ||
647 | return err; | ||
648 | } | ||
649 | |||
650 | static void setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | ||
651 | unsigned long mask) | ||
652 | { | ||
653 | sc->sc_mask = mask; | ||
654 | sc->sc_usp = rdusp(); | ||
655 | sc->sc_d0 = regs->d0; | ||
656 | sc->sc_d1 = regs->d1; | ||
657 | sc->sc_a0 = regs->a0; | ||
658 | sc->sc_a1 = regs->a1; | ||
659 | sc->sc_sr = regs->sr; | ||
660 | sc->sc_pc = regs->pc; | ||
661 | sc->sc_formatvec = regs->format << 12 | regs->vector; | ||
662 | save_fpu_state(sc, regs); | ||
663 | } | ||
664 | |||
665 | static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs) | ||
666 | { | ||
667 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
668 | greg_t *gregs = uc->uc_mcontext.gregs; | ||
669 | int err = 0; | ||
670 | |||
671 | err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version); | ||
672 | err |= __put_user(regs->d0, &gregs[0]); | ||
673 | err |= __put_user(regs->d1, &gregs[1]); | ||
674 | err |= __put_user(regs->d2, &gregs[2]); | ||
675 | err |= __put_user(regs->d3, &gregs[3]); | ||
676 | err |= __put_user(regs->d4, &gregs[4]); | ||
677 | err |= __put_user(regs->d5, &gregs[5]); | ||
678 | err |= __put_user(sw->d6, &gregs[6]); | ||
679 | err |= __put_user(sw->d7, &gregs[7]); | ||
680 | err |= __put_user(regs->a0, &gregs[8]); | ||
681 | err |= __put_user(regs->a1, &gregs[9]); | ||
682 | err |= __put_user(regs->a2, &gregs[10]); | ||
683 | err |= __put_user(sw->a3, &gregs[11]); | ||
684 | err |= __put_user(sw->a4, &gregs[12]); | ||
685 | err |= __put_user(sw->a5, &gregs[13]); | ||
686 | err |= __put_user(sw->a6, &gregs[14]); | ||
687 | err |= __put_user(rdusp(), &gregs[15]); | ||
688 | err |= __put_user(regs->pc, &gregs[16]); | ||
689 | err |= __put_user(regs->sr, &gregs[17]); | ||
690 | err |= __put_user((regs->format << 12) | regs->vector, &uc->uc_formatvec); | ||
691 | err |= rt_save_fpu_state(uc, regs); | ||
692 | return err; | ||
693 | } | ||
694 | |||
695 | static inline void push_cache (unsigned long vaddr) | ||
696 | { | ||
697 | /* | ||
698 | * Using the old cache_push_v() was really a big waste. | ||
699 | * | ||
700 | * What we are trying to do is to flush 8 bytes to ram. | ||
701 | * Flushing 2 cache lines of 16 bytes is much cheaper than | ||
702 | * flushing 1 or 2 pages, as previously done in | ||
703 | * cache_push_v(). | ||
704 | * Jes | ||
705 | */ | ||
706 | if (CPU_IS_040) { | ||
707 | unsigned long temp; | ||
708 | |||
709 | __asm__ __volatile__ (".chip 68040\n\t" | ||
710 | "nop\n\t" | ||
711 | "ptestr (%1)\n\t" | ||
712 | "movec %%mmusr,%0\n\t" | ||
713 | ".chip 68k" | ||
714 | : "=r" (temp) | ||
715 | : "a" (vaddr)); | ||
716 | |||
717 | temp &= PAGE_MASK; | ||
718 | temp |= vaddr & ~PAGE_MASK; | ||
719 | |||
720 | __asm__ __volatile__ (".chip 68040\n\t" | ||
721 | "nop\n\t" | ||
722 | "cpushl %%bc,(%0)\n\t" | ||
723 | ".chip 68k" | ||
724 | : : "a" (temp)); | ||
725 | } | ||
726 | else if (CPU_IS_060) { | ||
727 | unsigned long temp; | ||
728 | __asm__ __volatile__ (".chip 68060\n\t" | ||
729 | "plpar (%0)\n\t" | ||
730 | ".chip 68k" | ||
731 | : "=a" (temp) | ||
732 | : "0" (vaddr)); | ||
733 | __asm__ __volatile__ (".chip 68060\n\t" | ||
734 | "cpushl %%bc,(%0)\n\t" | ||
735 | ".chip 68k" | ||
736 | : : "a" (temp)); | ||
737 | } | ||
738 | else { | ||
739 | /* | ||
740 | * 68030/68020 have no writeback cache; | ||
741 | * still need to clear icache. | ||
742 | * Note that vaddr is guaranteed to be long word aligned. | ||
743 | */ | ||
744 | unsigned long temp; | ||
745 | asm volatile ("movec %%cacr,%0" : "=r" (temp)); | ||
746 | temp += 4; | ||
747 | asm volatile ("movec %0,%%caar\n\t" | ||
748 | "movec %1,%%cacr" | ||
749 | : : "r" (vaddr), "r" (temp)); | ||
750 | asm volatile ("movec %0,%%caar\n\t" | ||
751 | "movec %1,%%cacr" | ||
752 | : : "r" (vaddr + 4), "r" (temp)); | ||
753 | } | ||
754 | } | ||
755 | |||
756 | static inline void * | ||
757 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | ||
758 | { | ||
759 | unsigned long usp; | ||
760 | |||
761 | /* Default to using normal stack. */ | ||
762 | usp = rdusp(); | ||
763 | |||
764 | /* This is the X/Open sanctioned signal stack switching. */ | ||
765 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
766 | if (!on_sig_stack(usp)) | ||
767 | usp = current->sas_ss_sp + current->sas_ss_size; | ||
768 | } | ||
769 | return (void *)((usp - frame_size) & -8UL); | ||
770 | } | ||
771 | |||
772 | static void setup_frame (int sig, struct k_sigaction *ka, | ||
773 | sigset_t *set, struct pt_regs *regs) | ||
774 | { | ||
775 | struct sigframe *frame; | ||
776 | int fsize = frame_extra_sizes[regs->format]; | ||
777 | struct sigcontext context; | ||
778 | int err = 0; | ||
779 | |||
780 | if (fsize < 0) { | ||
781 | #ifdef DEBUG | ||
782 | printk ("setup_frame: Unknown frame format %#x\n", | ||
783 | regs->format); | ||
784 | #endif | ||
785 | goto give_sigsegv; | ||
786 | } | ||
787 | |||
788 | frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); | ||
789 | |||
790 | if (fsize) { | ||
791 | err |= copy_to_user (frame + 1, regs + 1, fsize); | ||
792 | regs->stkadj = fsize; | ||
793 | } | ||
794 | |||
795 | err |= __put_user((current_thread_info()->exec_domain | ||
796 | && current_thread_info()->exec_domain->signal_invmap | ||
797 | && sig < 32 | ||
798 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
799 | : sig), | ||
800 | &frame->sig); | ||
801 | |||
802 | err |= __put_user(regs->vector, &frame->code); | ||
803 | err |= __put_user(&frame->sc, &frame->psc); | ||
804 | |||
805 | if (_NSIG_WORDS > 1) | ||
806 | err |= copy_to_user(frame->extramask, &set->sig[1], | ||
807 | sizeof(frame->extramask)); | ||
808 | |||
809 | setup_sigcontext(&context, regs, set->sig[0]); | ||
810 | err |= copy_to_user (&frame->sc, &context, sizeof(context)); | ||
811 | |||
812 | /* Set up to return from userspace. */ | ||
813 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
814 | /* moveq #,d0; trap #0 */ | ||
815 | err |= __put_user(0x70004e40 + (__NR_sigreturn << 16), | ||
816 | (long *)(frame->retcode)); | ||
817 | |||
818 | if (err) | ||
819 | goto give_sigsegv; | ||
820 | |||
821 | push_cache ((unsigned long) &frame->retcode); | ||
822 | |||
823 | /* Set up registers for signal handler */ | ||
824 | wrusp ((unsigned long) frame); | ||
825 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
826 | |||
827 | adjust_stack: | ||
828 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
829 | if (regs->stkadj) { | ||
830 | struct pt_regs *tregs = | ||
831 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
832 | #ifdef DEBUG | ||
833 | printk("Performing stackadjust=%04x\n", regs->stkadj); | ||
834 | #endif | ||
835 | /* This must be copied with decreasing addresses to | ||
836 | handle overlaps. */ | ||
837 | tregs->vector = 0; | ||
838 | tregs->format = 0; | ||
839 | tregs->pc = regs->pc; | ||
840 | tregs->sr = regs->sr; | ||
841 | } | ||
842 | return; | ||
843 | |||
844 | give_sigsegv: | ||
845 | force_sigsegv(sig, current); | ||
846 | goto adjust_stack; | ||
847 | } | ||
848 | |||
849 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | ||
850 | sigset_t *set, struct pt_regs *regs) | ||
851 | { | ||
852 | struct rt_sigframe *frame; | ||
853 | int fsize = frame_extra_sizes[regs->format]; | ||
854 | int err = 0; | ||
855 | |||
856 | if (fsize < 0) { | ||
857 | #ifdef DEBUG | ||
858 | printk ("setup_frame: Unknown frame format %#x\n", | ||
859 | regs->format); | ||
860 | #endif | ||
861 | goto give_sigsegv; | ||
862 | } | ||
863 | |||
864 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
865 | |||
866 | if (fsize) { | ||
867 | err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); | ||
868 | regs->stkadj = fsize; | ||
869 | } | ||
870 | |||
871 | err |= __put_user((current_thread_info()->exec_domain | ||
872 | && current_thread_info()->exec_domain->signal_invmap | ||
873 | && sig < 32 | ||
874 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
875 | : sig), | ||
876 | &frame->sig); | ||
877 | err |= __put_user(&frame->info, &frame->pinfo); | ||
878 | err |= __put_user(&frame->uc, &frame->puc); | ||
879 | err |= copy_siginfo_to_user(&frame->info, info); | ||
880 | |||
881 | /* Create the ucontext. */ | ||
882 | err |= __put_user(0, &frame->uc.uc_flags); | ||
883 | err |= __put_user(0, &frame->uc.uc_link); | ||
884 | err |= __put_user((void *)current->sas_ss_sp, | ||
885 | &frame->uc.uc_stack.ss_sp); | ||
886 | err |= __put_user(sas_ss_flags(rdusp()), | ||
887 | &frame->uc.uc_stack.ss_flags); | ||
888 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
889 | err |= rt_setup_ucontext(&frame->uc, regs); | ||
890 | err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
891 | |||
892 | /* Set up to return from userspace. */ | ||
893 | err |= __put_user(frame->retcode, &frame->pretcode); | ||
894 | /* moveq #,d0; notb d0; trap #0 */ | ||
895 | err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16), | ||
896 | (long *)(frame->retcode + 0)); | ||
897 | err |= __put_user(0x4e40, (short *)(frame->retcode + 4)); | ||
898 | |||
899 | if (err) | ||
900 | goto give_sigsegv; | ||
901 | |||
902 | push_cache ((unsigned long) &frame->retcode); | ||
903 | |||
904 | /* Set up registers for signal handler */ | ||
905 | wrusp ((unsigned long) frame); | ||
906 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
907 | |||
908 | adjust_stack: | ||
909 | /* Prepare to skip over the extra stuff in the exception frame. */ | ||
910 | if (regs->stkadj) { | ||
911 | struct pt_regs *tregs = | ||
912 | (struct pt_regs *)((ulong)regs + regs->stkadj); | ||
913 | #ifdef DEBUG | ||
914 | printk("Performing stackadjust=%04x\n", regs->stkadj); | ||
915 | #endif | ||
916 | /* This must be copied with decreasing addresses to | ||
917 | handle overlaps. */ | ||
918 | tregs->vector = 0; | ||
919 | tregs->format = 0; | ||
920 | tregs->pc = regs->pc; | ||
921 | tregs->sr = regs->sr; | ||
922 | } | ||
923 | return; | ||
924 | |||
925 | give_sigsegv: | ||
926 | force_sigsegv(sig, current); | ||
927 | goto adjust_stack; | ||
928 | } | ||
929 | |||
930 | static inline void | ||
931 | handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) | ||
932 | { | ||
933 | switch (regs->d0) { | ||
934 | case -ERESTARTNOHAND: | ||
935 | if (!has_handler) | ||
936 | goto do_restart; | ||
937 | regs->d0 = -EINTR; | ||
938 | break; | ||
939 | |||
940 | case -ERESTARTSYS: | ||
941 | if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) { | ||
942 | regs->d0 = -EINTR; | ||
943 | break; | ||
944 | } | ||
945 | /* fallthrough */ | ||
946 | case -ERESTARTNOINTR: | ||
947 | do_restart: | ||
948 | regs->d0 = regs->orig_d0; | ||
949 | regs->pc -= 2; | ||
950 | break; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | ||
955 | { | ||
956 | if (regs->orig_d0 < 0) | ||
957 | return; | ||
958 | switch (regs->d0) { | ||
959 | case -ERESTARTNOHAND: | ||
960 | case -ERESTARTSYS: | ||
961 | case -ERESTARTNOINTR: | ||
962 | regs->d0 = regs->orig_d0; | ||
963 | regs->orig_d0 = -1; | ||
964 | regs->pc -= 2; | ||
965 | break; | ||
966 | } | ||
967 | } | ||
968 | |||
969 | /* | ||
970 | * OK, we're invoking a handler | ||
971 | */ | ||
972 | static void | ||
973 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
974 | sigset_t *oldset, struct pt_regs *regs) | ||
975 | { | ||
976 | /* are we from a system call? */ | ||
977 | if (regs->orig_d0 >= 0) | ||
978 | /* If so, check system call restarting.. */ | ||
979 | handle_restart(regs, ka, 1); | ||
980 | |||
981 | /* set up the stack frame */ | ||
982 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
983 | setup_rt_frame(sig, ka, info, oldset, regs); | ||
984 | else | ||
985 | setup_frame(sig, ka, oldset, regs); | ||
986 | |||
987 | if (ka->sa.sa_flags & SA_ONESHOT) | ||
988 | ka->sa.sa_handler = SIG_DFL; | ||
989 | |||
990 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
991 | if (!(ka->sa.sa_flags & SA_NODEFER)) | ||
992 | sigaddset(¤t->blocked,sig); | ||
993 | recalc_sigpending(); | ||
994 | } | ||
995 | |||
996 | /* | ||
997 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
998 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
999 | * mistake. | ||
1000 | */ | ||
1001 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) | ||
1002 | { | ||
1003 | siginfo_t info; | ||
1004 | struct k_sigaction ka; | ||
1005 | int signr; | ||
1006 | |||
1007 | current->thread.esp0 = (unsigned long) regs; | ||
1008 | |||
1009 | if (!oldset) | ||
1010 | oldset = ¤t->blocked; | ||
1011 | |||
1012 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
1013 | if (signr > 0) { | ||
1014 | /* Whee! Actually deliver the signal. */ | ||
1015 | handle_signal(signr, &ka, &info, oldset, regs); | ||
1016 | return 1; | ||
1017 | } | ||
1018 | |||
1019 | /* Did we come from a system call? */ | ||
1020 | if (regs->orig_d0 >= 0) | ||
1021 | /* Restart the system call - no handlers present */ | ||
1022 | handle_restart(regs, NULL, 0); | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
diff --git a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S new file mode 100644 index 000000000000..bffd69a4a1ab --- /dev/null +++ b/arch/m68k/kernel/sun3-head.S | |||
@@ -0,0 +1,104 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | |||
3 | #include <asm/entry.h> | ||
4 | #include <asm/page.h> | ||
5 | #include <asm/contregs.h> | ||
6 | #include <asm/sun3-head.h> | ||
7 | |||
8 | PSL_HIGHIPL = 0x2700 | ||
9 | NBSG = 0x20000 | ||
10 | ICACHE_ONLY = 0x00000009 | ||
11 | CACHES_OFF = 0x00000008 | actually a clear and disable --m | ||
12 | #define MAS_STACK INT_STACK | ||
13 | ROOT_TABLE_SIZE = 128 | ||
14 | PAGESIZE = 8192 | ||
15 | SUN3_INVALID_PMEG = 255 | ||
16 | .globl bootup_user_stack | ||
17 | .globl bootup_kernel_stack | ||
18 | .globl pg0 | ||
19 | .globl swapper_pg_dir | ||
20 | .globl kernel_pmd_table | ||
21 | .globl availmem | ||
22 | .global m68k_pgtable_cachemode | ||
23 | .global kpt | ||
24 | | todo: all these should be in bss! | ||
25 | swapper_pg_dir: .skip 0x2000 | ||
26 | pg0: .skip 0x2000 | ||
27 | kernel_pmd_table: .skip 0x2000 | ||
28 | |||
29 | .globl kernel_pg_dir | ||
30 | .equ kernel_pg_dir,kernel_pmd_table | ||
31 | |||
32 | .section .head | ||
33 | ENTRY(_stext) | ||
34 | ENTRY(_start) | ||
35 | |||
36 | /* Firstly, disable interrupts and set up function codes. */ | ||
37 | movew #PSL_HIGHIPL, %sr | ||
38 | moveq #FC_CONTROL, %d0 | ||
39 | movec %d0, %sfc | ||
40 | movec %d0, %dfc | ||
41 | |||
42 | /* Make sure we're in context zero. */ | ||
43 | moveq #0, %d0 | ||
44 | movsb %d0, AC_CONTEXT | ||
45 | |||
46 | /* map everything the bootloader left us into high memory, clean up the | ||
47 | excess later */ | ||
48 | lea (AC_SEGMAP+0),%a0 | ||
49 | lea (AC_SEGMAP+KERNBASE),%a1 | ||
50 | 1: | ||
51 | movsb %a0@, %d1 | ||
52 | movsb %d1, %a1@ | ||
53 | cmpib #SUN3_INVALID_PMEG, %d1 | ||
54 | beq 2f | ||
55 | addl #NBSG,%a0 | ||
56 | addl #NBSG,%a1 | ||
57 | jmp 1b | ||
58 | |||
59 | 2: | ||
60 | |||
61 | /* Disable caches and jump to high code. */ | ||
62 | moveq #ICACHE_ONLY,%d0 | Cache disabled until we're ready to enable it | ||
63 | movc %d0, %cacr | is this the right value? (yes --m) | ||
64 | jmp 1f:l | ||
65 | |||
66 | /* Following code executes at high addresses (0xE000xxx). */ | ||
67 | 1: lea init_task,%curptr | get initial thread... | ||
68 | lea init_thread_union+THREAD_SIZE,%sp | ...and its stack. | ||
69 | |||
70 | /* copy bootinfo records from the loader to _end */ | ||
71 | lea _end, %a1 | ||
72 | lea BI_START, %a0 | ||
73 | /* number of longs to copy */ | ||
74 | movel %a0@, %d0 | ||
75 | 1: addl #4, %a0 | ||
76 | movel %a0@, %a1@ | ||
77 | addl #4, %a1 | ||
78 | dbf %d0, 1b | ||
79 | |||
80 | /* Point MSP at an invalid page to trap if it's used. --m */ | ||
81 | movl #(PAGESIZE),%d0 | ||
82 | movc %d0,%msp | ||
83 | moveq #-1,%d0 | ||
84 | movsb %d0,(AC_SEGMAP+0x0) | ||
85 | |||
86 | jbsr sun3_init | ||
87 | |||
88 | jbsr base_trap_init | ||
89 | |||
90 | jbsr start_kernel | ||
91 | trap #15 | ||
92 | |||
93 | .data | ||
94 | .even | ||
95 | kpt: | ||
96 | .long 0 | ||
97 | availmem: | ||
98 | .long 0 | ||
99 | | todo: remove next two. --m | ||
100 | is_medusa: | ||
101 | .long 0 | ||
102 | m68k_pgtable_cachemode: | ||
103 | .long 0 | ||
104 | |||
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c new file mode 100644 index 000000000000..2ed7b783f654 --- /dev/null +++ b/arch/m68k/kernel/sys_m68k.c | |||
@@ -0,0 +1,671 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/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/page.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 | #if 0 | ||
116 | struct mmap_arg_struct64 { | ||
117 | __u32 addr; | ||
118 | __u32 len; | ||
119 | __u32 prot; | ||
120 | __u32 flags; | ||
121 | __u64 offset; /* 64 bits */ | ||
122 | __u32 fd; | ||
123 | }; | ||
124 | |||
125 | asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) | ||
126 | { | ||
127 | int error = -EFAULT; | ||
128 | struct file * file = NULL; | ||
129 | struct mmap_arg_struct64 a; | ||
130 | unsigned long pgoff; | ||
131 | |||
132 | if (copy_from_user(&a, arg, sizeof(a))) | ||
133 | return -EFAULT; | ||
134 | |||
135 | if ((long)a.offset & ~PAGE_MASK) | ||
136 | return -EINVAL; | ||
137 | |||
138 | pgoff = a.offset >> PAGE_SHIFT; | ||
139 | if ((a.offset >> PAGE_SHIFT) != pgoff) | ||
140 | return -EINVAL; | ||
141 | |||
142 | if (!(a.flags & MAP_ANONYMOUS)) { | ||
143 | error = -EBADF; | ||
144 | file = fget(a.fd); | ||
145 | if (!file) | ||
146 | goto out; | ||
147 | } | ||
148 | a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
149 | |||
150 | down_write(¤t->mm->mmap_sem); | ||
151 | error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); | ||
152 | up_write(¤t->mm->mmap_sem); | ||
153 | if (file) | ||
154 | fput(file); | ||
155 | out: | ||
156 | return error; | ||
157 | } | ||
158 | #endif | ||
159 | |||
160 | struct sel_arg_struct { | ||
161 | unsigned long n; | ||
162 | fd_set *inp, *outp, *exp; | ||
163 | struct timeval *tvp; | ||
164 | }; | ||
165 | |||
166 | asmlinkage int old_select(struct sel_arg_struct *arg) | ||
167 | { | ||
168 | struct sel_arg_struct a; | ||
169 | |||
170 | if (copy_from_user(&a, arg, sizeof(a))) | ||
171 | return -EFAULT; | ||
172 | /* sys_select() does the appropriate kernel locking */ | ||
173 | return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | ||
178 | * | ||
179 | * This is really horribly ugly. | ||
180 | */ | ||
181 | asmlinkage int sys_ipc (uint call, int first, int second, | ||
182 | int third, void *ptr, long fifth) | ||
183 | { | ||
184 | int version, ret; | ||
185 | |||
186 | version = call >> 16; /* hack for backward compatibility */ | ||
187 | call &= 0xffff; | ||
188 | |||
189 | if (call <= SEMCTL) | ||
190 | switch (call) { | ||
191 | case SEMOP: | ||
192 | return sys_semop (first, (struct sembuf *)ptr, second); | ||
193 | case SEMGET: | ||
194 | return sys_semget (first, second, third); | ||
195 | case SEMCTL: { | ||
196 | union semun fourth; | ||
197 | if (!ptr) | ||
198 | return -EINVAL; | ||
199 | if (get_user(fourth.__pad, (void **) ptr)) | ||
200 | return -EFAULT; | ||
201 | return sys_semctl (first, second, third, fourth); | ||
202 | } | ||
203 | default: | ||
204 | return -ENOSYS; | ||
205 | } | ||
206 | if (call <= MSGCTL) | ||
207 | switch (call) { | ||
208 | case MSGSND: | ||
209 | return sys_msgsnd (first, (struct msgbuf *) ptr, | ||
210 | second, third); | ||
211 | case MSGRCV: | ||
212 | switch (version) { | ||
213 | case 0: { | ||
214 | struct ipc_kludge tmp; | ||
215 | if (!ptr) | ||
216 | return -EINVAL; | ||
217 | if (copy_from_user (&tmp, | ||
218 | (struct ipc_kludge *)ptr, | ||
219 | sizeof (tmp))) | ||
220 | return -EFAULT; | ||
221 | return sys_msgrcv (first, tmp.msgp, second, | ||
222 | tmp.msgtyp, third); | ||
223 | } | ||
224 | default: | ||
225 | return sys_msgrcv (first, | ||
226 | (struct msgbuf *) ptr, | ||
227 | second, fifth, third); | ||
228 | } | ||
229 | case MSGGET: | ||
230 | return sys_msgget ((key_t) first, second); | ||
231 | case MSGCTL: | ||
232 | return sys_msgctl (first, second, | ||
233 | (struct msqid_ds *) ptr); | ||
234 | default: | ||
235 | return -ENOSYS; | ||
236 | } | ||
237 | if (call <= SHMCTL) | ||
238 | switch (call) { | ||
239 | case SHMAT: | ||
240 | switch (version) { | ||
241 | default: { | ||
242 | ulong raddr; | ||
243 | ret = do_shmat (first, (char *) ptr, | ||
244 | second, &raddr); | ||
245 | if (ret) | ||
246 | return ret; | ||
247 | return put_user (raddr, (ulong *) third); | ||
248 | } | ||
249 | } | ||
250 | case SHMDT: | ||
251 | return sys_shmdt ((char *)ptr); | ||
252 | case SHMGET: | ||
253 | return sys_shmget (first, second, third); | ||
254 | case SHMCTL: | ||
255 | return sys_shmctl (first, second, | ||
256 | (struct shmid_ds *) ptr); | ||
257 | default: | ||
258 | return -ENOSYS; | ||
259 | } | ||
260 | |||
261 | return -EINVAL; | ||
262 | } | ||
263 | |||
264 | /* Convert virtual (user) address VADDR to physical address PADDR */ | ||
265 | #define virt_to_phys_040(vaddr) \ | ||
266 | ({ \ | ||
267 | unsigned long _mmusr, _paddr; \ | ||
268 | \ | ||
269 | __asm__ __volatile__ (".chip 68040\n\t" \ | ||
270 | "ptestr (%1)\n\t" \ | ||
271 | "movec %%mmusr,%0\n\t" \ | ||
272 | ".chip 68k" \ | ||
273 | : "=r" (_mmusr) \ | ||
274 | : "a" (vaddr)); \ | ||
275 | _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \ | ||
276 | _paddr; \ | ||
277 | }) | ||
278 | |||
279 | static inline int | ||
280 | cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len) | ||
281 | { | ||
282 | unsigned long paddr, i; | ||
283 | |||
284 | switch (scope) | ||
285 | { | ||
286 | case FLUSH_SCOPE_ALL: | ||
287 | switch (cache) | ||
288 | { | ||
289 | case FLUSH_CACHE_DATA: | ||
290 | /* This nop is needed for some broken versions of the 68040. */ | ||
291 | __asm__ __volatile__ ("nop\n\t" | ||
292 | ".chip 68040\n\t" | ||
293 | "cpusha %dc\n\t" | ||
294 | ".chip 68k"); | ||
295 | break; | ||
296 | case FLUSH_CACHE_INSN: | ||
297 | __asm__ __volatile__ ("nop\n\t" | ||
298 | ".chip 68040\n\t" | ||
299 | "cpusha %ic\n\t" | ||
300 | ".chip 68k"); | ||
301 | break; | ||
302 | default: | ||
303 | case FLUSH_CACHE_BOTH: | ||
304 | __asm__ __volatile__ ("nop\n\t" | ||
305 | ".chip 68040\n\t" | ||
306 | "cpusha %bc\n\t" | ||
307 | ".chip 68k"); | ||
308 | break; | ||
309 | } | ||
310 | break; | ||
311 | |||
312 | case FLUSH_SCOPE_LINE: | ||
313 | /* Find the physical address of the first mapped page in the | ||
314 | address range. */ | ||
315 | if ((paddr = virt_to_phys_040(addr))) { | ||
316 | paddr += addr & ~(PAGE_MASK | 15); | ||
317 | len = (len + (addr & 15) + 15) >> 4; | ||
318 | } else { | ||
319 | unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK); | ||
320 | |||
321 | if (len <= tmp) | ||
322 | return 0; | ||
323 | addr += tmp; | ||
324 | len -= tmp; | ||
325 | tmp = PAGE_SIZE; | ||
326 | for (;;) | ||
327 | { | ||
328 | if ((paddr = virt_to_phys_040(addr))) | ||
329 | break; | ||
330 | if (len <= tmp) | ||
331 | return 0; | ||
332 | addr += tmp; | ||
333 | len -= tmp; | ||
334 | } | ||
335 | len = (len + 15) >> 4; | ||
336 | } | ||
337 | i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4; | ||
338 | while (len--) | ||
339 | { | ||
340 | switch (cache) | ||
341 | { | ||
342 | case FLUSH_CACHE_DATA: | ||
343 | __asm__ __volatile__ ("nop\n\t" | ||
344 | ".chip 68040\n\t" | ||
345 | "cpushl %%dc,(%0)\n\t" | ||
346 | ".chip 68k" | ||
347 | : : "a" (paddr)); | ||
348 | break; | ||
349 | case FLUSH_CACHE_INSN: | ||
350 | __asm__ __volatile__ ("nop\n\t" | ||
351 | ".chip 68040\n\t" | ||
352 | "cpushl %%ic,(%0)\n\t" | ||
353 | ".chip 68k" | ||
354 | : : "a" (paddr)); | ||
355 | break; | ||
356 | default: | ||
357 | case FLUSH_CACHE_BOTH: | ||
358 | __asm__ __volatile__ ("nop\n\t" | ||
359 | ".chip 68040\n\t" | ||
360 | "cpushl %%bc,(%0)\n\t" | ||
361 | ".chip 68k" | ||
362 | : : "a" (paddr)); | ||
363 | break; | ||
364 | } | ||
365 | if (!--i && len) | ||
366 | { | ||
367 | /* | ||
368 | * No need to page align here since it is done by | ||
369 | * virt_to_phys_040(). | ||
370 | */ | ||
371 | addr += PAGE_SIZE; | ||
372 | i = PAGE_SIZE / 16; | ||
373 | /* Recompute physical address when crossing a page | ||
374 | boundary. */ | ||
375 | for (;;) | ||
376 | { | ||
377 | if ((paddr = virt_to_phys_040(addr))) | ||
378 | break; | ||
379 | if (len <= i) | ||
380 | return 0; | ||
381 | len -= i; | ||
382 | addr += PAGE_SIZE; | ||
383 | } | ||
384 | } | ||
385 | else | ||
386 | paddr += 16; | ||
387 | } | ||
388 | break; | ||
389 | |||
390 | default: | ||
391 | case FLUSH_SCOPE_PAGE: | ||
392 | len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1); | ||
393 | for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) | ||
394 | { | ||
395 | if (!(paddr = virt_to_phys_040(addr))) | ||
396 | continue; | ||
397 | switch (cache) | ||
398 | { | ||
399 | case FLUSH_CACHE_DATA: | ||
400 | __asm__ __volatile__ ("nop\n\t" | ||
401 | ".chip 68040\n\t" | ||
402 | "cpushp %%dc,(%0)\n\t" | ||
403 | ".chip 68k" | ||
404 | : : "a" (paddr)); | ||
405 | break; | ||
406 | case FLUSH_CACHE_INSN: | ||
407 | __asm__ __volatile__ ("nop\n\t" | ||
408 | ".chip 68040\n\t" | ||
409 | "cpushp %%ic,(%0)\n\t" | ||
410 | ".chip 68k" | ||
411 | : : "a" (paddr)); | ||
412 | break; | ||
413 | default: | ||
414 | case FLUSH_CACHE_BOTH: | ||
415 | __asm__ __volatile__ ("nop\n\t" | ||
416 | ".chip 68040\n\t" | ||
417 | "cpushp %%bc,(%0)\n\t" | ||
418 | ".chip 68k" | ||
419 | : : "a" (paddr)); | ||
420 | break; | ||
421 | } | ||
422 | } | ||
423 | break; | ||
424 | } | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | #define virt_to_phys_060(vaddr) \ | ||
429 | ({ \ | ||
430 | unsigned long paddr; \ | ||
431 | __asm__ __volatile__ (".chip 68060\n\t" \ | ||
432 | "plpar (%0)\n\t" \ | ||
433 | ".chip 68k" \ | ||
434 | : "=a" (paddr) \ | ||
435 | : "0" (vaddr)); \ | ||
436 | (paddr); /* XXX */ \ | ||
437 | }) | ||
438 | |||
439 | static inline int | ||
440 | cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len) | ||
441 | { | ||
442 | unsigned long paddr, i; | ||
443 | |||
444 | /* | ||
445 | * 68060 manual says: | ||
446 | * cpush %dc : flush DC, remains valid (with our %cacr setup) | ||
447 | * cpush %ic : invalidate IC | ||
448 | * cpush %bc : flush DC + invalidate IC | ||
449 | */ | ||
450 | switch (scope) | ||
451 | { | ||
452 | case FLUSH_SCOPE_ALL: | ||
453 | switch (cache) | ||
454 | { | ||
455 | case FLUSH_CACHE_DATA: | ||
456 | __asm__ __volatile__ (".chip 68060\n\t" | ||
457 | "cpusha %dc\n\t" | ||
458 | ".chip 68k"); | ||
459 | break; | ||
460 | case FLUSH_CACHE_INSN: | ||
461 | __asm__ __volatile__ (".chip 68060\n\t" | ||
462 | "cpusha %ic\n\t" | ||
463 | ".chip 68k"); | ||
464 | break; | ||
465 | default: | ||
466 | case FLUSH_CACHE_BOTH: | ||
467 | __asm__ __volatile__ (".chip 68060\n\t" | ||
468 | "cpusha %bc\n\t" | ||
469 | ".chip 68k"); | ||
470 | break; | ||
471 | } | ||
472 | break; | ||
473 | |||
474 | case FLUSH_SCOPE_LINE: | ||
475 | /* Find the physical address of the first mapped page in the | ||
476 | address range. */ | ||
477 | len += addr & 15; | ||
478 | addr &= -16; | ||
479 | if (!(paddr = virt_to_phys_060(addr))) { | ||
480 | unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK); | ||
481 | |||
482 | if (len <= tmp) | ||
483 | return 0; | ||
484 | addr += tmp; | ||
485 | len -= tmp; | ||
486 | tmp = PAGE_SIZE; | ||
487 | for (;;) | ||
488 | { | ||
489 | if ((paddr = virt_to_phys_060(addr))) | ||
490 | break; | ||
491 | if (len <= tmp) | ||
492 | return 0; | ||
493 | addr += tmp; | ||
494 | len -= tmp; | ||
495 | } | ||
496 | } | ||
497 | len = (len + 15) >> 4; | ||
498 | i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4; | ||
499 | while (len--) | ||
500 | { | ||
501 | switch (cache) | ||
502 | { | ||
503 | case FLUSH_CACHE_DATA: | ||
504 | __asm__ __volatile__ (".chip 68060\n\t" | ||
505 | "cpushl %%dc,(%0)\n\t" | ||
506 | ".chip 68k" | ||
507 | : : "a" (paddr)); | ||
508 | break; | ||
509 | case FLUSH_CACHE_INSN: | ||
510 | __asm__ __volatile__ (".chip 68060\n\t" | ||
511 | "cpushl %%ic,(%0)\n\t" | ||
512 | ".chip 68k" | ||
513 | : : "a" (paddr)); | ||
514 | break; | ||
515 | default: | ||
516 | case FLUSH_CACHE_BOTH: | ||
517 | __asm__ __volatile__ (".chip 68060\n\t" | ||
518 | "cpushl %%bc,(%0)\n\t" | ||
519 | ".chip 68k" | ||
520 | : : "a" (paddr)); | ||
521 | break; | ||
522 | } | ||
523 | if (!--i && len) | ||
524 | { | ||
525 | |||
526 | /* | ||
527 | * We just want to jump to the first cache line | ||
528 | * in the next page. | ||
529 | */ | ||
530 | addr += PAGE_SIZE; | ||
531 | addr &= PAGE_MASK; | ||
532 | |||
533 | i = PAGE_SIZE / 16; | ||
534 | /* Recompute physical address when crossing a page | ||
535 | boundary. */ | ||
536 | for (;;) | ||
537 | { | ||
538 | if ((paddr = virt_to_phys_060(addr))) | ||
539 | break; | ||
540 | if (len <= i) | ||
541 | return 0; | ||
542 | len -= i; | ||
543 | addr += PAGE_SIZE; | ||
544 | } | ||
545 | } | ||
546 | else | ||
547 | paddr += 16; | ||
548 | } | ||
549 | break; | ||
550 | |||
551 | default: | ||
552 | case FLUSH_SCOPE_PAGE: | ||
553 | len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1); | ||
554 | addr &= PAGE_MASK; /* Workaround for bug in some | ||
555 | revisions of the 68060 */ | ||
556 | for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE) | ||
557 | { | ||
558 | if (!(paddr = virt_to_phys_060(addr))) | ||
559 | continue; | ||
560 | switch (cache) | ||
561 | { | ||
562 | case FLUSH_CACHE_DATA: | ||
563 | __asm__ __volatile__ (".chip 68060\n\t" | ||
564 | "cpushp %%dc,(%0)\n\t" | ||
565 | ".chip 68k" | ||
566 | : : "a" (paddr)); | ||
567 | break; | ||
568 | case FLUSH_CACHE_INSN: | ||
569 | __asm__ __volatile__ (".chip 68060\n\t" | ||
570 | "cpushp %%ic,(%0)\n\t" | ||
571 | ".chip 68k" | ||
572 | : : "a" (paddr)); | ||
573 | break; | ||
574 | default: | ||
575 | case FLUSH_CACHE_BOTH: | ||
576 | __asm__ __volatile__ (".chip 68060\n\t" | ||
577 | "cpushp %%bc,(%0)\n\t" | ||
578 | ".chip 68k" | ||
579 | : : "a" (paddr)); | ||
580 | break; | ||
581 | } | ||
582 | } | ||
583 | break; | ||
584 | } | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | /* sys_cacheflush -- flush (part of) the processor cache. */ | ||
589 | asmlinkage int | ||
590 | sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) | ||
591 | { | ||
592 | struct vm_area_struct *vma; | ||
593 | int ret = -EINVAL; | ||
594 | |||
595 | lock_kernel(); | ||
596 | if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL || | ||
597 | cache & ~FLUSH_CACHE_BOTH) | ||
598 | goto out; | ||
599 | |||
600 | if (scope == FLUSH_SCOPE_ALL) { | ||
601 | /* Only the superuser may explicitly flush the whole cache. */ | ||
602 | ret = -EPERM; | ||
603 | if (!capable(CAP_SYS_ADMIN)) | ||
604 | goto out; | ||
605 | } else { | ||
606 | /* | ||
607 | * Verify that the specified address region actually belongs | ||
608 | * to this process. | ||
609 | */ | ||
610 | vma = find_vma (current->mm, addr); | ||
611 | ret = -EINVAL; | ||
612 | /* Check for overflow. */ | ||
613 | if (addr + len < addr) | ||
614 | goto out; | ||
615 | if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end) | ||
616 | goto out; | ||
617 | } | ||
618 | |||
619 | if (CPU_IS_020_OR_030) { | ||
620 | if (scope == FLUSH_SCOPE_LINE && len < 256) { | ||
621 | unsigned long cacr; | ||
622 | __asm__ ("movec %%cacr, %0" : "=r" (cacr)); | ||
623 | if (cache & FLUSH_CACHE_INSN) | ||
624 | cacr |= 4; | ||
625 | if (cache & FLUSH_CACHE_DATA) | ||
626 | cacr |= 0x400; | ||
627 | len >>= 2; | ||
628 | while (len--) { | ||
629 | __asm__ __volatile__ ("movec %1, %%caar\n\t" | ||
630 | "movec %0, %%cacr" | ||
631 | : /* no outputs */ | ||
632 | : "r" (cacr), "r" (addr)); | ||
633 | addr += 4; | ||
634 | } | ||
635 | } else { | ||
636 | /* Flush the whole cache, even if page granularity requested. */ | ||
637 | unsigned long cacr; | ||
638 | __asm__ ("movec %%cacr, %0" : "=r" (cacr)); | ||
639 | if (cache & FLUSH_CACHE_INSN) | ||
640 | cacr |= 8; | ||
641 | if (cache & FLUSH_CACHE_DATA) | ||
642 | cacr |= 0x800; | ||
643 | __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr)); | ||
644 | } | ||
645 | ret = 0; | ||
646 | goto out; | ||
647 | } else { | ||
648 | /* | ||
649 | * 040 or 060: don't blindly trust 'scope', someone could | ||
650 | * try to flush a few megs of memory. | ||
651 | */ | ||
652 | |||
653 | if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE) | ||
654 | scope=FLUSH_SCOPE_PAGE; | ||
655 | if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL) | ||
656 | scope=FLUSH_SCOPE_ALL; | ||
657 | if (CPU_IS_040) { | ||
658 | ret = cache_flush_040 (addr, scope, cache, len); | ||
659 | } else if (CPU_IS_060) { | ||
660 | ret = cache_flush_060 (addr, scope, cache, len); | ||
661 | } | ||
662 | } | ||
663 | out: | ||
664 | unlock_kernel(); | ||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | asmlinkage int sys_getpagesize(void) | ||
669 | { | ||
670 | return PAGE_SIZE; | ||
671 | } | ||
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c new file mode 100644 index 000000000000..e47e19588525 --- /dev/null +++ b/arch/m68k/kernel/time.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/time.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
5 | * | ||
6 | * This file contains the m68k-specific time handling details. | ||
7 | * Most of the stuff is located in the machine specific files. | ||
8 | * | ||
9 | * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 | ||
10 | * "A Kernel Model for Precision Timekeeping" by Dave Mills | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> /* CONFIG_HEARTBEAT */ | ||
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/rtc.h> | ||
22 | |||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/io.h> | ||
25 | |||
26 | #include <linux/time.h> | ||
27 | #include <linux/timex.h> | ||
28 | #include <linux/profile.h> | ||
29 | |||
30 | u64 jiffies_64 = INITIAL_JIFFIES; | ||
31 | |||
32 | EXPORT_SYMBOL(jiffies_64); | ||
33 | |||
34 | static inline int set_rtc_mmss(unsigned long nowtime) | ||
35 | { | ||
36 | if (mach_set_clock_mmss) | ||
37 | return mach_set_clock_mmss (nowtime); | ||
38 | return -1; | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * timer_interrupt() needs to keep up the real-time clock, | ||
43 | * as well as call the "do_timer()" routine every clocktick | ||
44 | */ | ||
45 | static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs) | ||
46 | { | ||
47 | do_timer(regs); | ||
48 | #ifndef CONFIG_SMP | ||
49 | update_process_times(user_mode(regs)); | ||
50 | #endif | ||
51 | profile_tick(CPU_PROFILING, regs); | ||
52 | |||
53 | #ifdef CONFIG_HEARTBEAT | ||
54 | /* use power LED as a heartbeat instead -- much more useful | ||
55 | for debugging -- based on the version for PReP by Cort */ | ||
56 | /* acts like an actual heart beat -- ie thump-thump-pause... */ | ||
57 | if (mach_heartbeat) { | ||
58 | static unsigned cnt = 0, period = 0, dist = 0; | ||
59 | |||
60 | if (cnt == 0 || cnt == dist) | ||
61 | mach_heartbeat( 1 ); | ||
62 | else if (cnt == 7 || cnt == dist+7) | ||
63 | mach_heartbeat( 0 ); | ||
64 | |||
65 | if (++cnt > period) { | ||
66 | cnt = 0; | ||
67 | /* The hyperbolic function below modifies the heartbeat period | ||
68 | * length in dependency of the current (5min) load. It goes | ||
69 | * through the points f(0)=126, f(1)=86, f(5)=51, | ||
70 | * f(inf)->30. */ | ||
71 | period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; | ||
72 | dist = period / 4; | ||
73 | } | ||
74 | } | ||
75 | #endif /* CONFIG_HEARTBEAT */ | ||
76 | return IRQ_HANDLED; | ||
77 | } | ||
78 | |||
79 | void time_init(void) | ||
80 | { | ||
81 | struct rtc_time time; | ||
82 | |||
83 | if (mach_hwclk) { | ||
84 | mach_hwclk(0, &time); | ||
85 | |||
86 | if ((time.tm_year += 1900) < 1970) | ||
87 | time.tm_year += 100; | ||
88 | xtime.tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, | ||
89 | time.tm_hour, time.tm_min, time.tm_sec); | ||
90 | xtime.tv_nsec = 0; | ||
91 | } | ||
92 | wall_to_monotonic.tv_sec = -xtime.tv_sec; | ||
93 | |||
94 | mach_sched_init(timer_interrupt); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * This version of gettimeofday has near microsecond resolution. | ||
99 | */ | ||
100 | void do_gettimeofday(struct timeval *tv) | ||
101 | { | ||
102 | unsigned long flags; | ||
103 | extern unsigned long wall_jiffies; | ||
104 | unsigned long seq; | ||
105 | unsigned long usec, sec, lost; | ||
106 | unsigned long max_ntp_tick = tick_usec - tickadj; | ||
107 | |||
108 | do { | ||
109 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | ||
110 | |||
111 | usec = mach_gettimeoffset(); | ||
112 | lost = jiffies - wall_jiffies; | ||
113 | |||
114 | /* | ||
115 | * If time_adjust is negative then NTP is slowing the clock | ||
116 | * so make sure not to go into next possible interval. | ||
117 | * Better to lose some accuracy than have time go backwards.. | ||
118 | */ | ||
119 | if (unlikely(time_adjust < 0)) { | ||
120 | usec = min(usec, max_ntp_tick); | ||
121 | |||
122 | if (lost) | ||
123 | usec += lost * max_ntp_tick; | ||
124 | } | ||
125 | else if (unlikely(lost)) | ||
126 | usec += lost * tick_usec; | ||
127 | |||
128 | sec = xtime.tv_sec; | ||
129 | usec += xtime.tv_nsec/1000; | ||
130 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | ||
131 | |||
132 | |||
133 | while (usec >= 1000000) { | ||
134 | usec -= 1000000; | ||
135 | sec++; | ||
136 | } | ||
137 | |||
138 | tv->tv_sec = sec; | ||
139 | tv->tv_usec = usec; | ||
140 | } | ||
141 | |||
142 | EXPORT_SYMBOL(do_gettimeofday); | ||
143 | |||
144 | int do_settimeofday(struct timespec *tv) | ||
145 | { | ||
146 | time_t wtm_sec, sec = tv->tv_sec; | ||
147 | long wtm_nsec, nsec = tv->tv_nsec; | ||
148 | extern unsigned long wall_jiffies; | ||
149 | |||
150 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
151 | return -EINVAL; | ||
152 | |||
153 | write_seqlock_irq(&xtime_lock); | ||
154 | /* This is revolting. We need to set the xtime.tv_nsec | ||
155 | * correctly. However, the value in this location is | ||
156 | * is value at the last tick. | ||
157 | * Discover what correction gettimeofday | ||
158 | * would have done, and then undo it! | ||
159 | */ | ||
160 | nsec -= 1000 * (mach_gettimeoffset() + | ||
161 | (jiffies - wall_jiffies) * (1000000 / HZ)); | ||
162 | |||
163 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
164 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
165 | |||
166 | set_normalized_timespec(&xtime, sec, nsec); | ||
167 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
168 | |||
169 | time_adjust = 0; /* stop active adjtime() */ | ||
170 | time_status |= STA_UNSYNC; | ||
171 | time_maxerror = NTP_PHASE_LIMIT; | ||
172 | time_esterror = NTP_PHASE_LIMIT; | ||
173 | write_sequnlock_irq(&xtime_lock); | ||
174 | clock_was_set(); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | EXPORT_SYMBOL(do_settimeofday); | ||
179 | |||
180 | /* | ||
181 | * Scheduler clock - returns current time in ns units. | ||
182 | */ | ||
183 | unsigned long long sched_clock(void) | ||
184 | { | ||
185 | return (unsigned long long)jiffies*(1000000000/HZ); | ||
186 | } | ||
187 | |||
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c new file mode 100644 index 000000000000..deb36e8b04a2 --- /dev/null +++ b/arch/m68k/kernel/traps.c | |||
@@ -0,0 +1,1227 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/traps.c | ||
3 | * | ||
4 | * Copyright (C) 1993, 1994 by Hamish Macdonald | ||
5 | * | ||
6 | * 68040 fixes by Michael Rausch | ||
7 | * 68040 fixes by Martin Apel | ||
8 | * 68040 fixes and writeback by Richard Zidlicky | ||
9 | * 68060 fixes by Roman Hodek | ||
10 | * 68060 fixes by Jesper Skov | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive | ||
14 | * for more details. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Sets up all exception vectors | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/signal.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/a.out.h> | ||
28 | #include <linux/user.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/linkage.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/ptrace.h> | ||
33 | #include <linux/kallsyms.h> | ||
34 | |||
35 | #include <asm/setup.h> | ||
36 | #include <asm/fpu.h> | ||
37 | #include <asm/system.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | #include <asm/traps.h> | ||
40 | #include <asm/pgalloc.h> | ||
41 | #include <asm/machdep.h> | ||
42 | #include <asm/siginfo.h> | ||
43 | |||
44 | /* assembler routines */ | ||
45 | asmlinkage void system_call(void); | ||
46 | asmlinkage void buserr(void); | ||
47 | asmlinkage void trap(void); | ||
48 | asmlinkage void inthandler(void); | ||
49 | asmlinkage void nmihandler(void); | ||
50 | #ifdef CONFIG_M68KFPU_EMU | ||
51 | asmlinkage void fpu_emu(void); | ||
52 | #endif | ||
53 | |||
54 | e_vector vectors[256] = { | ||
55 | [VEC_BUSERR] = buserr, | ||
56 | [VEC_ADDRERR] = trap, | ||
57 | [VEC_ILLEGAL] = trap, | ||
58 | [VEC_ZERODIV] = trap, | ||
59 | [VEC_CHK] = trap, | ||
60 | [VEC_TRAP] = trap, | ||
61 | [VEC_PRIV] = trap, | ||
62 | [VEC_TRACE] = trap, | ||
63 | [VEC_LINE10] = trap, | ||
64 | [VEC_LINE11] = trap, | ||
65 | [VEC_RESV12] = trap, | ||
66 | [VEC_COPROC] = trap, | ||
67 | [VEC_FORMAT] = trap, | ||
68 | [VEC_UNINT] = trap, | ||
69 | [VEC_RESV16] = trap, | ||
70 | [VEC_RESV17] = trap, | ||
71 | [VEC_RESV18] = trap, | ||
72 | [VEC_RESV19] = trap, | ||
73 | [VEC_RESV20] = trap, | ||
74 | [VEC_RESV21] = trap, | ||
75 | [VEC_RESV22] = trap, | ||
76 | [VEC_RESV23] = trap, | ||
77 | [VEC_SPUR] = inthandler, | ||
78 | [VEC_INT1] = inthandler, | ||
79 | [VEC_INT2] = inthandler, | ||
80 | [VEC_INT3] = inthandler, | ||
81 | [VEC_INT4] = inthandler, | ||
82 | [VEC_INT5] = inthandler, | ||
83 | [VEC_INT6] = inthandler, | ||
84 | [VEC_INT7] = inthandler, | ||
85 | [VEC_SYS] = system_call, | ||
86 | [VEC_TRAP1] = trap, | ||
87 | [VEC_TRAP2] = trap, | ||
88 | [VEC_TRAP3] = trap, | ||
89 | [VEC_TRAP4] = trap, | ||
90 | [VEC_TRAP5] = trap, | ||
91 | [VEC_TRAP6] = trap, | ||
92 | [VEC_TRAP7] = trap, | ||
93 | [VEC_TRAP8] = trap, | ||
94 | [VEC_TRAP9] = trap, | ||
95 | [VEC_TRAP10] = trap, | ||
96 | [VEC_TRAP11] = trap, | ||
97 | [VEC_TRAP12] = trap, | ||
98 | [VEC_TRAP13] = trap, | ||
99 | [VEC_TRAP14] = trap, | ||
100 | [VEC_TRAP15] = trap, | ||
101 | }; | ||
102 | |||
103 | /* nmi handler for the Amiga */ | ||
104 | asm(".text\n" | ||
105 | __ALIGN_STR "\n" | ||
106 | "nmihandler: rte"); | ||
107 | |||
108 | /* | ||
109 | * this must be called very early as the kernel might | ||
110 | * use some instruction that are emulated on the 060 | ||
111 | */ | ||
112 | void __init base_trap_init(void) | ||
113 | { | ||
114 | if(MACH_IS_SUN3X) { | ||
115 | extern e_vector *sun3x_prom_vbr; | ||
116 | |||
117 | __asm__ volatile ("movec %%vbr, %0" : "=r" ((void*)sun3x_prom_vbr)); | ||
118 | } | ||
119 | |||
120 | /* setup the exception vector table */ | ||
121 | __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); | ||
122 | |||
123 | if (CPU_IS_060) { | ||
124 | /* set up ISP entry points */ | ||
125 | asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); | ||
126 | |||
127 | vectors[VEC_UNIMPII] = unimp_vec; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | void __init trap_init (void) | ||
132 | { | ||
133 | int i; | ||
134 | |||
135 | for (i = 48; i < 64; i++) | ||
136 | if (!vectors[i]) | ||
137 | vectors[i] = trap; | ||
138 | |||
139 | for (i = 64; i < 256; i++) | ||
140 | vectors[i] = inthandler; | ||
141 | |||
142 | #ifdef CONFIG_M68KFPU_EMU | ||
143 | if (FPU_IS_EMU) | ||
144 | vectors[VEC_LINE11] = fpu_emu; | ||
145 | #endif | ||
146 | |||
147 | if (CPU_IS_040 && !FPU_IS_EMU) { | ||
148 | /* set up FPSP entry points */ | ||
149 | asmlinkage void dz_vec(void) asm ("dz"); | ||
150 | asmlinkage void inex_vec(void) asm ("inex"); | ||
151 | asmlinkage void ovfl_vec(void) asm ("ovfl"); | ||
152 | asmlinkage void unfl_vec(void) asm ("unfl"); | ||
153 | asmlinkage void snan_vec(void) asm ("snan"); | ||
154 | asmlinkage void operr_vec(void) asm ("operr"); | ||
155 | asmlinkage void bsun_vec(void) asm ("bsun"); | ||
156 | asmlinkage void fline_vec(void) asm ("fline"); | ||
157 | asmlinkage void unsupp_vec(void) asm ("unsupp"); | ||
158 | |||
159 | vectors[VEC_FPDIVZ] = dz_vec; | ||
160 | vectors[VEC_FPIR] = inex_vec; | ||
161 | vectors[VEC_FPOVER] = ovfl_vec; | ||
162 | vectors[VEC_FPUNDER] = unfl_vec; | ||
163 | vectors[VEC_FPNAN] = snan_vec; | ||
164 | vectors[VEC_FPOE] = operr_vec; | ||
165 | vectors[VEC_FPBRUC] = bsun_vec; | ||
166 | vectors[VEC_LINE11] = fline_vec; | ||
167 | vectors[VEC_FPUNSUP] = unsupp_vec; | ||
168 | } | ||
169 | |||
170 | if (CPU_IS_060 && !FPU_IS_EMU) { | ||
171 | /* set up IFPSP entry points */ | ||
172 | asmlinkage void snan_vec(void) asm ("_060_fpsp_snan"); | ||
173 | asmlinkage void operr_vec(void) asm ("_060_fpsp_operr"); | ||
174 | asmlinkage void ovfl_vec(void) asm ("_060_fpsp_ovfl"); | ||
175 | asmlinkage void unfl_vec(void) asm ("_060_fpsp_unfl"); | ||
176 | asmlinkage void dz_vec(void) asm ("_060_fpsp_dz"); | ||
177 | asmlinkage void inex_vec(void) asm ("_060_fpsp_inex"); | ||
178 | asmlinkage void fline_vec(void) asm ("_060_fpsp_fline"); | ||
179 | asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp"); | ||
180 | asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd"); | ||
181 | |||
182 | vectors[VEC_FPNAN] = snan_vec; | ||
183 | vectors[VEC_FPOE] = operr_vec; | ||
184 | vectors[VEC_FPOVER] = ovfl_vec; | ||
185 | vectors[VEC_FPUNDER] = unfl_vec; | ||
186 | vectors[VEC_FPDIVZ] = dz_vec; | ||
187 | vectors[VEC_FPIR] = inex_vec; | ||
188 | vectors[VEC_LINE11] = fline_vec; | ||
189 | vectors[VEC_FPUNSUP] = unsupp_vec; | ||
190 | vectors[VEC_UNIMPEA] = effadd_vec; | ||
191 | } | ||
192 | |||
193 | /* if running on an amiga, make the NMI interrupt do nothing */ | ||
194 | if (MACH_IS_AMIGA) { | ||
195 | vectors[VEC_INT7] = nmihandler; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | |||
200 | static const char *vec_names[] = { | ||
201 | [VEC_RESETSP] = "RESET SP", | ||
202 | [VEC_RESETPC] = "RESET PC", | ||
203 | [VEC_BUSERR] = "BUS ERROR", | ||
204 | [VEC_ADDRERR] = "ADDRESS ERROR", | ||
205 | [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION", | ||
206 | [VEC_ZERODIV] = "ZERO DIVIDE", | ||
207 | [VEC_CHK] = "CHK", | ||
208 | [VEC_TRAP] = "TRAPcc", | ||
209 | [VEC_PRIV] = "PRIVILEGE VIOLATION", | ||
210 | [VEC_TRACE] = "TRACE", | ||
211 | [VEC_LINE10] = "LINE 1010", | ||
212 | [VEC_LINE11] = "LINE 1111", | ||
213 | [VEC_RESV12] = "UNASSIGNED RESERVED 12", | ||
214 | [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION", | ||
215 | [VEC_FORMAT] = "FORMAT ERROR", | ||
216 | [VEC_UNINT] = "UNINITIALIZED INTERRUPT", | ||
217 | [VEC_RESV16] = "UNASSIGNED RESERVED 16", | ||
218 | [VEC_RESV17] = "UNASSIGNED RESERVED 17", | ||
219 | [VEC_RESV18] = "UNASSIGNED RESERVED 18", | ||
220 | [VEC_RESV19] = "UNASSIGNED RESERVED 19", | ||
221 | [VEC_RESV20] = "UNASSIGNED RESERVED 20", | ||
222 | [VEC_RESV21] = "UNASSIGNED RESERVED 21", | ||
223 | [VEC_RESV22] = "UNASSIGNED RESERVED 22", | ||
224 | [VEC_RESV23] = "UNASSIGNED RESERVED 23", | ||
225 | [VEC_SPUR] = "SPURIOUS INTERRUPT", | ||
226 | [VEC_INT1] = "LEVEL 1 INT", | ||
227 | [VEC_INT2] = "LEVEL 2 INT", | ||
228 | [VEC_INT3] = "LEVEL 3 INT", | ||
229 | [VEC_INT4] = "LEVEL 4 INT", | ||
230 | [VEC_INT5] = "LEVEL 5 INT", | ||
231 | [VEC_INT6] = "LEVEL 6 INT", | ||
232 | [VEC_INT7] = "LEVEL 7 INT", | ||
233 | [VEC_SYS] = "SYSCALL", | ||
234 | [VEC_TRAP1] = "TRAP #1", | ||
235 | [VEC_TRAP2] = "TRAP #2", | ||
236 | [VEC_TRAP3] = "TRAP #3", | ||
237 | [VEC_TRAP4] = "TRAP #4", | ||
238 | [VEC_TRAP5] = "TRAP #5", | ||
239 | [VEC_TRAP6] = "TRAP #6", | ||
240 | [VEC_TRAP7] = "TRAP #7", | ||
241 | [VEC_TRAP8] = "TRAP #8", | ||
242 | [VEC_TRAP9] = "TRAP #9", | ||
243 | [VEC_TRAP10] = "TRAP #10", | ||
244 | [VEC_TRAP11] = "TRAP #11", | ||
245 | [VEC_TRAP12] = "TRAP #12", | ||
246 | [VEC_TRAP13] = "TRAP #13", | ||
247 | [VEC_TRAP14] = "TRAP #14", | ||
248 | [VEC_TRAP15] = "TRAP #15", | ||
249 | [VEC_FPBRUC] = "FPCP BSUN", | ||
250 | [VEC_FPIR] = "FPCP INEXACT", | ||
251 | [VEC_FPDIVZ] = "FPCP DIV BY 0", | ||
252 | [VEC_FPUNDER] = "FPCP UNDERFLOW", | ||
253 | [VEC_FPOE] = "FPCP OPERAND ERROR", | ||
254 | [VEC_FPOVER] = "FPCP OVERFLOW", | ||
255 | [VEC_FPNAN] = "FPCP SNAN", | ||
256 | [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION", | ||
257 | [VEC_MMUCFG] = "MMU CONFIGURATION ERROR", | ||
258 | [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR", | ||
259 | [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR", | ||
260 | [VEC_RESV59] = "UNASSIGNED RESERVED 59", | ||
261 | [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60", | ||
262 | [VEC_UNIMPII] = "UNASSIGNED RESERVED 61", | ||
263 | [VEC_RESV62] = "UNASSIGNED RESERVED 62", | ||
264 | [VEC_RESV63] = "UNASSIGNED RESERVED 63", | ||
265 | }; | ||
266 | |||
267 | static const char *space_names[] = { | ||
268 | [0] = "Space 0", | ||
269 | [USER_DATA] = "User Data", | ||
270 | [USER_PROGRAM] = "User Program", | ||
271 | #ifndef CONFIG_SUN3 | ||
272 | [3] = "Space 3", | ||
273 | #else | ||
274 | [FC_CONTROL] = "Control", | ||
275 | #endif | ||
276 | [4] = "Space 4", | ||
277 | [SUPER_DATA] = "Super Data", | ||
278 | [SUPER_PROGRAM] = "Super Program", | ||
279 | [CPU_SPACE] = "CPU" | ||
280 | }; | ||
281 | |||
282 | void die_if_kernel(char *,struct pt_regs *,int); | ||
283 | asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, | ||
284 | unsigned long error_code); | ||
285 | int send_fault_sig(struct pt_regs *regs); | ||
286 | |||
287 | asmlinkage void trap_c(struct frame *fp); | ||
288 | |||
289 | #if defined (CONFIG_M68060) | ||
290 | static inline void access_error060 (struct frame *fp) | ||
291 | { | ||
292 | unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ | ||
293 | |||
294 | #ifdef DEBUG | ||
295 | printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr); | ||
296 | #endif | ||
297 | |||
298 | if (fslw & MMU060_BPE) { | ||
299 | /* branch prediction error -> clear branch cache */ | ||
300 | __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" | ||
301 | "orl #0x00400000,%/d0\n\t" | ||
302 | "movec %/d0,%/cacr" | ||
303 | : : : "d0" ); | ||
304 | /* return if there's no other error */ | ||
305 | if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE)) | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { | ||
310 | unsigned long errorcode; | ||
311 | unsigned long addr = fp->un.fmt4.effaddr; | ||
312 | |||
313 | if (fslw & MMU060_MA) | ||
314 | addr = (addr + PAGE_SIZE - 1) & PAGE_MASK; | ||
315 | |||
316 | errorcode = 1; | ||
317 | if (fslw & MMU060_DESC_ERR) { | ||
318 | __flush_tlb040_one(addr); | ||
319 | errorcode = 0; | ||
320 | } | ||
321 | if (fslw & MMU060_W) | ||
322 | errorcode |= 2; | ||
323 | #ifdef DEBUG | ||
324 | printk("errorcode = %d\n", errorcode ); | ||
325 | #endif | ||
326 | do_page_fault(&fp->ptregs, addr, errorcode); | ||
327 | } else if (fslw & (MMU060_SEE)){ | ||
328 | /* Software Emulation Error. | ||
329 | * fault during mem_read/mem_write in ifpsp060/os.S | ||
330 | */ | ||
331 | send_fault_sig(&fp->ptregs); | ||
332 | } else if (!(fslw & (MMU060_RE|MMU060_WE)) || | ||
333 | send_fault_sig(&fp->ptregs) > 0) { | ||
334 | printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); | ||
335 | printk( "68060 access error, fslw=%lx\n", fslw ); | ||
336 | trap_c( fp ); | ||
337 | } | ||
338 | } | ||
339 | #endif /* CONFIG_M68060 */ | ||
340 | |||
341 | #if defined (CONFIG_M68040) | ||
342 | static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) | ||
343 | { | ||
344 | unsigned long mmusr; | ||
345 | mm_segment_t old_fs = get_fs(); | ||
346 | |||
347 | set_fs(MAKE_MM_SEG(wbs)); | ||
348 | |||
349 | if (iswrite) | ||
350 | asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr)); | ||
351 | else | ||
352 | asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr)); | ||
353 | |||
354 | asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); | ||
355 | |||
356 | set_fs(old_fs); | ||
357 | |||
358 | return mmusr; | ||
359 | } | ||
360 | |||
361 | static inline int do_040writeback1(unsigned short wbs, unsigned long wba, | ||
362 | unsigned long wbd) | ||
363 | { | ||
364 | int res = 0; | ||
365 | mm_segment_t old_fs = get_fs(); | ||
366 | |||
367 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
368 | set_fs(MAKE_MM_SEG(wbs)); | ||
369 | |||
370 | switch (wbs & WBSIZ_040) { | ||
371 | case BA_SIZE_BYTE: | ||
372 | res = put_user(wbd & 0xff, (char *)wba); | ||
373 | break; | ||
374 | case BA_SIZE_WORD: | ||
375 | res = put_user(wbd & 0xffff, (short *)wba); | ||
376 | break; | ||
377 | case BA_SIZE_LONG: | ||
378 | res = put_user(wbd, (int *)wba); | ||
379 | break; | ||
380 | } | ||
381 | |||
382 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
383 | set_fs(old_fs); | ||
384 | |||
385 | |||
386 | #ifdef DEBUG | ||
387 | printk("do_040writeback1, res=%d\n",res); | ||
388 | #endif | ||
389 | |||
390 | return res; | ||
391 | } | ||
392 | |||
393 | /* after an exception in a writeback the stack frame corresponding | ||
394 | * to that exception is discarded, set a few bits in the old frame | ||
395 | * to simulate what it should look like | ||
396 | */ | ||
397 | static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs) | ||
398 | { | ||
399 | fp->un.fmt7.faddr = wba; | ||
400 | fp->un.fmt7.ssw = wbs & 0xff; | ||
401 | if (wba != current->thread.faddr) | ||
402 | fp->un.fmt7.ssw |= MA_040; | ||
403 | } | ||
404 | |||
405 | static inline void do_040writebacks(struct frame *fp) | ||
406 | { | ||
407 | int res = 0; | ||
408 | #if 0 | ||
409 | if (fp->un.fmt7.wb1s & WBV_040) | ||
410 | printk("access_error040: cannot handle 1st writeback. oops.\n"); | ||
411 | #endif | ||
412 | |||
413 | if ((fp->un.fmt7.wb2s & WBV_040) && | ||
414 | !(fp->un.fmt7.wb2s & WBTT_040)) { | ||
415 | res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, | ||
416 | fp->un.fmt7.wb2d); | ||
417 | if (res) | ||
418 | fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s); | ||
419 | else | ||
420 | fp->un.fmt7.wb2s = 0; | ||
421 | } | ||
422 | |||
423 | /* do the 2nd wb only if the first one was successful (except for a kernel wb) */ | ||
424 | if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { | ||
425 | res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, | ||
426 | fp->un.fmt7.wb3d); | ||
427 | if (res) | ||
428 | { | ||
429 | fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s); | ||
430 | |||
431 | fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; | ||
432 | fp->un.fmt7.wb3s &= (~WBV_040); | ||
433 | fp->un.fmt7.wb2a = fp->un.fmt7.wb3a; | ||
434 | fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; | ||
435 | } | ||
436 | else | ||
437 | fp->un.fmt7.wb3s = 0; | ||
438 | } | ||
439 | |||
440 | if (res) | ||
441 | send_fault_sig(&fp->ptregs); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * called from sigreturn(), must ensure userspace code didn't | ||
446 | * manipulate exception frame to circumvent protection, then complete | ||
447 | * pending writebacks | ||
448 | * we just clear TM2 to turn it into an userspace access | ||
449 | */ | ||
450 | asmlinkage void berr_040cleanup(struct frame *fp) | ||
451 | { | ||
452 | fp->un.fmt7.wb2s &= ~4; | ||
453 | fp->un.fmt7.wb3s &= ~4; | ||
454 | |||
455 | do_040writebacks(fp); | ||
456 | } | ||
457 | |||
458 | static inline void access_error040(struct frame *fp) | ||
459 | { | ||
460 | unsigned short ssw = fp->un.fmt7.ssw; | ||
461 | unsigned long mmusr; | ||
462 | |||
463 | #ifdef DEBUG | ||
464 | printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); | ||
465 | printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, | ||
466 | fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); | ||
467 | printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", | ||
468 | fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, | ||
469 | fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); | ||
470 | #endif | ||
471 | |||
472 | if (ssw & ATC_040) { | ||
473 | unsigned long addr = fp->un.fmt7.faddr; | ||
474 | unsigned long errorcode; | ||
475 | |||
476 | /* | ||
477 | * The MMU status has to be determined AFTER the address | ||
478 | * has been corrected if there was a misaligned access (MA). | ||
479 | */ | ||
480 | if (ssw & MA_040) | ||
481 | addr = (addr + 7) & -8; | ||
482 | |||
483 | /* MMU error, get the MMUSR info for this access */ | ||
484 | mmusr = probe040(!(ssw & RW_040), addr, ssw); | ||
485 | #ifdef DEBUG | ||
486 | printk("mmusr = %lx\n", mmusr); | ||
487 | #endif | ||
488 | errorcode = 1; | ||
489 | if (!(mmusr & MMU_R_040)) { | ||
490 | /* clear the invalid atc entry */ | ||
491 | __flush_tlb040_one(addr); | ||
492 | errorcode = 0; | ||
493 | } | ||
494 | |||
495 | /* despite what documentation seems to say, RMW | ||
496 | * accesses have always both the LK and RW bits set */ | ||
497 | if (!(ssw & RW_040) || (ssw & LK_040)) | ||
498 | errorcode |= 2; | ||
499 | |||
500 | if (do_page_fault(&fp->ptregs, addr, errorcode)) { | ||
501 | #ifdef DEBUG | ||
502 | printk("do_page_fault() !=0 \n"); | ||
503 | #endif | ||
504 | if (user_mode(&fp->ptregs)){ | ||
505 | /* delay writebacks after signal delivery */ | ||
506 | #ifdef DEBUG | ||
507 | printk(".. was usermode - return\n"); | ||
508 | #endif | ||
509 | return; | ||
510 | } | ||
511 | /* disable writeback into user space from kernel | ||
512 | * (if do_page_fault didn't fix the mapping, | ||
513 | * the writeback won't do good) | ||
514 | */ | ||
515 | #ifdef DEBUG | ||
516 | printk(".. disabling wb2\n"); | ||
517 | #endif | ||
518 | if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) | ||
519 | fp->un.fmt7.wb2s &= ~WBV_040; | ||
520 | } | ||
521 | } else if (send_fault_sig(&fp->ptregs) > 0) { | ||
522 | printk("68040 access error, ssw=%x\n", ssw); | ||
523 | trap_c(fp); | ||
524 | } | ||
525 | |||
526 | do_040writebacks(fp); | ||
527 | } | ||
528 | #endif /* CONFIG_M68040 */ | ||
529 | |||
530 | #if defined(CONFIG_SUN3) | ||
531 | #include <asm/sun3mmu.h> | ||
532 | |||
533 | extern int mmu_emu_handle_fault (unsigned long, int, int); | ||
534 | |||
535 | /* sun3 version of bus_error030 */ | ||
536 | |||
537 | static inline void bus_error030 (struct frame *fp) | ||
538 | { | ||
539 | unsigned char buserr_type = sun3_get_buserr (); | ||
540 | unsigned long addr, errorcode; | ||
541 | unsigned short ssw = fp->un.fmtb.ssw; | ||
542 | extern unsigned long _sun3_map_test_start, _sun3_map_test_end; | ||
543 | |||
544 | #ifdef DEBUG | ||
545 | if (ssw & (FC | FB)) | ||
546 | printk ("Instruction fault at %#010lx\n", | ||
547 | ssw & FC ? | ||
548 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
549 | : | ||
550 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
551 | if (ssw & DF) | ||
552 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
553 | ssw & RW ? "read" : "write", | ||
554 | fp->un.fmtb.daddr, | ||
555 | space_names[ssw & DFC], fp->ptregs.pc); | ||
556 | #endif | ||
557 | |||
558 | /* | ||
559 | * Check if this page should be demand-mapped. This needs to go before | ||
560 | * the testing for a bad kernel-space access (demand-mapping applies | ||
561 | * to kernel accesses too). | ||
562 | */ | ||
563 | |||
564 | if ((ssw & DF) | ||
565 | && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { | ||
566 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) | ||
567 | return; | ||
568 | } | ||
569 | |||
570 | /* Check for kernel-space pagefault (BAD). */ | ||
571 | if (fp->ptregs.sr & PS_S) { | ||
572 | /* kernel fault must be a data fault to user space */ | ||
573 | if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { | ||
574 | // try checking the kernel mappings before surrender | ||
575 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) | ||
576 | return; | ||
577 | /* instruction fault or kernel data fault! */ | ||
578 | if (ssw & (FC | FB)) | ||
579 | printk ("Instruction fault at %#010lx\n", | ||
580 | fp->ptregs.pc); | ||
581 | if (ssw & DF) { | ||
582 | /* was this fault incurred testing bus mappings? */ | ||
583 | if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) && | ||
584 | (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) { | ||
585 | send_fault_sig(&fp->ptregs); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
590 | ssw & RW ? "read" : "write", | ||
591 | fp->un.fmtb.daddr, | ||
592 | space_names[ssw & DFC], fp->ptregs.pc); | ||
593 | } | ||
594 | printk ("BAD KERNEL BUSERR\n"); | ||
595 | |||
596 | die_if_kernel("Oops", &fp->ptregs,0); | ||
597 | force_sig(SIGKILL, current); | ||
598 | return; | ||
599 | } | ||
600 | } else { | ||
601 | /* user fault */ | ||
602 | if (!(ssw & (FC | FB)) && !(ssw & DF)) | ||
603 | /* not an instruction fault or data fault! BAD */ | ||
604 | panic ("USER BUSERR w/o instruction or data fault"); | ||
605 | } | ||
606 | |||
607 | |||
608 | /* First handle the data fault, if any. */ | ||
609 | if (ssw & DF) { | ||
610 | addr = fp->un.fmtb.daddr; | ||
611 | |||
612 | // errorcode bit 0: 0 -> no page 1 -> protection fault | ||
613 | // errorcode bit 1: 0 -> read fault 1 -> write fault | ||
614 | |||
615 | // (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault | ||
616 | // (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault | ||
617 | |||
618 | if (buserr_type & SUN3_BUSERR_PROTERR) | ||
619 | errorcode = 0x01; | ||
620 | else if (buserr_type & SUN3_BUSERR_INVALID) | ||
621 | errorcode = 0x00; | ||
622 | else { | ||
623 | #ifdef DEBUG | ||
624 | printk ("*** unexpected busfault type=%#04x\n", buserr_type); | ||
625 | printk ("invalid %s access at %#lx from pc %#lx\n", | ||
626 | !(ssw & RW) ? "write" : "read", addr, | ||
627 | fp->ptregs.pc); | ||
628 | #endif | ||
629 | die_if_kernel ("Oops", &fp->ptregs, buserr_type); | ||
630 | force_sig (SIGBUS, current); | ||
631 | return; | ||
632 | } | ||
633 | |||
634 | //todo: wtf is RM bit? --m | ||
635 | if (!(ssw & RW) || ssw & RM) | ||
636 | errorcode |= 0x02; | ||
637 | |||
638 | /* Handle page fault. */ | ||
639 | do_page_fault (&fp->ptregs, addr, errorcode); | ||
640 | |||
641 | /* Retry the data fault now. */ | ||
642 | return; | ||
643 | } | ||
644 | |||
645 | /* Now handle the instruction fault. */ | ||
646 | |||
647 | /* Get the fault address. */ | ||
648 | if (fp->ptregs.format == 0xA) | ||
649 | addr = fp->ptregs.pc + 4; | ||
650 | else | ||
651 | addr = fp->un.fmtb.baddr; | ||
652 | if (ssw & FC) | ||
653 | addr -= 2; | ||
654 | |||
655 | if (buserr_type & SUN3_BUSERR_INVALID) { | ||
656 | if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) | ||
657 | do_page_fault (&fp->ptregs, addr, 0); | ||
658 | } else { | ||
659 | #ifdef DEBUG | ||
660 | printk ("protection fault on insn access (segv).\n"); | ||
661 | #endif | ||
662 | force_sig (SIGSEGV, current); | ||
663 | } | ||
664 | } | ||
665 | #else | ||
666 | #if defined(CPU_M68020_OR_M68030) | ||
667 | static inline void bus_error030 (struct frame *fp) | ||
668 | { | ||
669 | volatile unsigned short temp; | ||
670 | unsigned short mmusr; | ||
671 | unsigned long addr, errorcode; | ||
672 | unsigned short ssw = fp->un.fmtb.ssw; | ||
673 | #ifdef DEBUG | ||
674 | unsigned long desc; | ||
675 | |||
676 | printk ("pid = %x ", current->pid); | ||
677 | printk ("SSW=%#06x ", ssw); | ||
678 | |||
679 | if (ssw & (FC | FB)) | ||
680 | printk ("Instruction fault at %#010lx\n", | ||
681 | ssw & FC ? | ||
682 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
683 | : | ||
684 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
685 | if (ssw & DF) | ||
686 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
687 | ssw & RW ? "read" : "write", | ||
688 | fp->un.fmtb.daddr, | ||
689 | space_names[ssw & DFC], fp->ptregs.pc); | ||
690 | #endif | ||
691 | |||
692 | /* ++andreas: If a data fault and an instruction fault happen | ||
693 | at the same time map in both pages. */ | ||
694 | |||
695 | /* First handle the data fault, if any. */ | ||
696 | if (ssw & DF) { | ||
697 | addr = fp->un.fmtb.daddr; | ||
698 | |||
699 | #ifdef DEBUG | ||
700 | asm volatile ("ptestr %3,%2@,#7,%0\n\t" | ||
701 | "pmove %%psr,%1@" | ||
702 | : "=a&" (desc) | ||
703 | : "a" (&temp), "a" (addr), "d" (ssw)); | ||
704 | #else | ||
705 | asm volatile ("ptestr %2,%1@,#7\n\t" | ||
706 | "pmove %%psr,%0@" | ||
707 | : : "a" (&temp), "a" (addr), "d" (ssw)); | ||
708 | #endif | ||
709 | mmusr = temp; | ||
710 | |||
711 | #ifdef DEBUG | ||
712 | printk("mmusr is %#x for addr %#lx in task %p\n", | ||
713 | mmusr, addr, current); | ||
714 | printk("descriptor address is %#lx, contents %#lx\n", | ||
715 | __va(desc), *(unsigned long *)__va(desc)); | ||
716 | #endif | ||
717 | |||
718 | errorcode = (mmusr & MMU_I) ? 0 : 1; | ||
719 | if (!(ssw & RW) || (ssw & RM)) | ||
720 | errorcode |= 2; | ||
721 | |||
722 | if (mmusr & (MMU_I | MMU_WP)) { | ||
723 | if (ssw & 4) { | ||
724 | printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
725 | ssw & RW ? "read" : "write", | ||
726 | fp->un.fmtb.daddr, | ||
727 | space_names[ssw & DFC], fp->ptregs.pc); | ||
728 | goto buserr; | ||
729 | } | ||
730 | /* Don't try to do anything further if an exception was | ||
731 | handled. */ | ||
732 | if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) | ||
733 | return; | ||
734 | } else if (!(mmusr & MMU_I)) { | ||
735 | /* probably a 020 cas fault */ | ||
736 | if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0) | ||
737 | printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); | ||
738 | } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
739 | printk("invalid %s access at %#lx from pc %#lx\n", | ||
740 | !(ssw & RW) ? "write" : "read", addr, | ||
741 | fp->ptregs.pc); | ||
742 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
743 | force_sig(SIGSEGV, current); | ||
744 | return; | ||
745 | } else { | ||
746 | #if 0 | ||
747 | static volatile long tlong; | ||
748 | #endif | ||
749 | |||
750 | printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", | ||
751 | !(ssw & RW) ? "write" : "read", addr, | ||
752 | fp->ptregs.pc, ssw); | ||
753 | asm volatile ("ptestr #1,%1@,#0\n\t" | ||
754 | "pmove %%psr,%0@" | ||
755 | : /* no outputs */ | ||
756 | : "a" (&temp), "a" (addr)); | ||
757 | mmusr = temp; | ||
758 | |||
759 | printk ("level 0 mmusr is %#x\n", mmusr); | ||
760 | #if 0 | ||
761 | asm volatile ("pmove %%tt0,%0@" | ||
762 | : /* no outputs */ | ||
763 | : "a" (&tlong)); | ||
764 | printk("tt0 is %#lx, ", tlong); | ||
765 | asm volatile ("pmove %%tt1,%0@" | ||
766 | : /* no outputs */ | ||
767 | : "a" (&tlong)); | ||
768 | printk("tt1 is %#lx\n", tlong); | ||
769 | #endif | ||
770 | #ifdef DEBUG | ||
771 | printk("Unknown SIGSEGV - 1\n"); | ||
772 | #endif | ||
773 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
774 | force_sig(SIGSEGV, current); | ||
775 | return; | ||
776 | } | ||
777 | |||
778 | /* setup an ATC entry for the access about to be retried */ | ||
779 | if (!(ssw & RW) || (ssw & RM)) | ||
780 | asm volatile ("ploadw %1,%0@" : /* no outputs */ | ||
781 | : "a" (addr), "d" (ssw)); | ||
782 | else | ||
783 | asm volatile ("ploadr %1,%0@" : /* no outputs */ | ||
784 | : "a" (addr), "d" (ssw)); | ||
785 | } | ||
786 | |||
787 | /* Now handle the instruction fault. */ | ||
788 | |||
789 | if (!(ssw & (FC|FB))) | ||
790 | return; | ||
791 | |||
792 | if (fp->ptregs.sr & PS_S) { | ||
793 | printk("Instruction fault at %#010lx\n", | ||
794 | fp->ptregs.pc); | ||
795 | buserr: | ||
796 | printk ("BAD KERNEL BUSERR\n"); | ||
797 | die_if_kernel("Oops",&fp->ptregs,0); | ||
798 | force_sig(SIGKILL, current); | ||
799 | return; | ||
800 | } | ||
801 | |||
802 | /* get the fault address */ | ||
803 | if (fp->ptregs.format == 10) | ||
804 | addr = fp->ptregs.pc + 4; | ||
805 | else | ||
806 | addr = fp->un.fmtb.baddr; | ||
807 | if (ssw & FC) | ||
808 | addr -= 2; | ||
809 | |||
810 | if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) | ||
811 | /* Insn fault on same page as data fault. But we | ||
812 | should still create the ATC entry. */ | ||
813 | goto create_atc_entry; | ||
814 | |||
815 | #ifdef DEBUG | ||
816 | asm volatile ("ptestr #1,%2@,#7,%0\n\t" | ||
817 | "pmove %%psr,%1@" | ||
818 | : "=a&" (desc) | ||
819 | : "a" (&temp), "a" (addr)); | ||
820 | #else | ||
821 | asm volatile ("ptestr #1,%1@,#7\n\t" | ||
822 | "pmove %%psr,%0@" | ||
823 | : : "a" (&temp), "a" (addr)); | ||
824 | #endif | ||
825 | mmusr = temp; | ||
826 | |||
827 | #ifdef DEBUG | ||
828 | printk ("mmusr is %#x for addr %#lx in task %p\n", | ||
829 | mmusr, addr, current); | ||
830 | printk ("descriptor address is %#lx, contents %#lx\n", | ||
831 | __va(desc), *(unsigned long *)__va(desc)); | ||
832 | #endif | ||
833 | |||
834 | if (mmusr & MMU_I) | ||
835 | do_page_fault (&fp->ptregs, addr, 0); | ||
836 | else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
837 | printk ("invalid insn access at %#lx from pc %#lx\n", | ||
838 | addr, fp->ptregs.pc); | ||
839 | #ifdef DEBUG | ||
840 | printk("Unknown SIGSEGV - 2\n"); | ||
841 | #endif | ||
842 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
843 | force_sig(SIGSEGV, current); | ||
844 | return; | ||
845 | } | ||
846 | |||
847 | create_atc_entry: | ||
848 | /* setup an ATC entry for the access about to be retried */ | ||
849 | asm volatile ("ploadr #2,%0@" : /* no outputs */ | ||
850 | : "a" (addr)); | ||
851 | } | ||
852 | #endif /* CPU_M68020_OR_M68030 */ | ||
853 | #endif /* !CONFIG_SUN3 */ | ||
854 | |||
855 | asmlinkage void buserr_c(struct frame *fp) | ||
856 | { | ||
857 | /* Only set esp0 if coming from user mode */ | ||
858 | if (user_mode(&fp->ptregs)) | ||
859 | current->thread.esp0 = (unsigned long) fp; | ||
860 | |||
861 | #ifdef DEBUG | ||
862 | printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); | ||
863 | #endif | ||
864 | |||
865 | switch (fp->ptregs.format) { | ||
866 | #if defined (CONFIG_M68060) | ||
867 | case 4: /* 68060 access error */ | ||
868 | access_error060 (fp); | ||
869 | break; | ||
870 | #endif | ||
871 | #if defined (CONFIG_M68040) | ||
872 | case 0x7: /* 68040 access error */ | ||
873 | access_error040 (fp); | ||
874 | break; | ||
875 | #endif | ||
876 | #if defined (CPU_M68020_OR_M68030) | ||
877 | case 0xa: | ||
878 | case 0xb: | ||
879 | bus_error030 (fp); | ||
880 | break; | ||
881 | #endif | ||
882 | default: | ||
883 | die_if_kernel("bad frame format",&fp->ptregs,0); | ||
884 | #ifdef DEBUG | ||
885 | printk("Unknown SIGSEGV - 4\n"); | ||
886 | #endif | ||
887 | force_sig(SIGSEGV, current); | ||
888 | } | ||
889 | } | ||
890 | |||
891 | |||
892 | static int kstack_depth_to_print = 48; | ||
893 | |||
894 | void show_trace(unsigned long *stack) | ||
895 | { | ||
896 | unsigned long *endstack; | ||
897 | unsigned long addr; | ||
898 | int i; | ||
899 | |||
900 | printk("Call Trace:"); | ||
901 | addr = (unsigned long)stack + THREAD_SIZE - 1; | ||
902 | endstack = (unsigned long *)(addr & -THREAD_SIZE); | ||
903 | i = 0; | ||
904 | while (stack + 1 <= endstack) { | ||
905 | addr = *stack++; | ||
906 | /* | ||
907 | * If the address is either in the text segment of the | ||
908 | * kernel, or in the region which contains vmalloc'ed | ||
909 | * memory, it *may* be the address of a calling | ||
910 | * routine; if so, print it so that someone tracing | ||
911 | * down the cause of the crash will be able to figure | ||
912 | * out the call path that was taken. | ||
913 | */ | ||
914 | if (__kernel_text_address(addr)) { | ||
915 | #ifndef CONFIG_KALLSYMS | ||
916 | if (i % 5 == 0) | ||
917 | printk("\n "); | ||
918 | #endif | ||
919 | printk(" [<%08lx>]", addr); | ||
920 | print_symbol(" %s\n", addr); | ||
921 | i++; | ||
922 | } | ||
923 | } | ||
924 | printk("\n"); | ||
925 | } | ||
926 | |||
927 | void show_registers(struct pt_regs *regs) | ||
928 | { | ||
929 | struct frame *fp = (struct frame *)regs; | ||
930 | unsigned long addr; | ||
931 | int i; | ||
932 | |||
933 | addr = (unsigned long)&fp->un; | ||
934 | printk("Frame format=%X ", fp->ptregs.format); | ||
935 | switch (fp->ptregs.format) { | ||
936 | case 0x2: | ||
937 | printk("instr addr=%08lx\n", fp->un.fmt2.iaddr); | ||
938 | addr += sizeof(fp->un.fmt2); | ||
939 | break; | ||
940 | case 0x3: | ||
941 | printk("eff addr=%08lx\n", fp->un.fmt3.effaddr); | ||
942 | addr += sizeof(fp->un.fmt3); | ||
943 | break; | ||
944 | case 0x4: | ||
945 | printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n" | ||
946 | : "eff addr=%08lx pc=%08lx\n"), | ||
947 | fp->un.fmt4.effaddr, fp->un.fmt4.pc); | ||
948 | addr += sizeof(fp->un.fmt4); | ||
949 | break; | ||
950 | case 0x7: | ||
951 | printk("eff addr=%08lx ssw=%04x faddr=%08lx\n", | ||
952 | fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr); | ||
953 | printk("wb 1 stat/addr/data: %04x %08lx %08lx\n", | ||
954 | fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0); | ||
955 | printk("wb 2 stat/addr/data: %04x %08lx %08lx\n", | ||
956 | fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); | ||
957 | printk("wb 3 stat/addr/data: %04x %08lx %08lx\n", | ||
958 | fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); | ||
959 | printk("push data: %08lx %08lx %08lx %08lx\n", | ||
960 | fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2, | ||
961 | fp->un.fmt7.pd3); | ||
962 | addr += sizeof(fp->un.fmt7); | ||
963 | break; | ||
964 | case 0x9: | ||
965 | printk("instr addr=%08lx\n", fp->un.fmt9.iaddr); | ||
966 | addr += sizeof(fp->un.fmt9); | ||
967 | break; | ||
968 | case 0xa: | ||
969 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
970 | fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb, | ||
971 | fp->un.fmta.daddr, fp->un.fmta.dobuf); | ||
972 | addr += sizeof(fp->un.fmta); | ||
973 | break; | ||
974 | case 0xb: | ||
975 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
976 | fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb, | ||
977 | fp->un.fmtb.daddr, fp->un.fmtb.dobuf); | ||
978 | printk("baddr=%08lx dibuf=%08lx ver=%x\n", | ||
979 | fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver); | ||
980 | addr += sizeof(fp->un.fmtb); | ||
981 | break; | ||
982 | default: | ||
983 | printk("\n"); | ||
984 | } | ||
985 | show_stack(NULL, (unsigned long *)addr); | ||
986 | |||
987 | printk("Code: "); | ||
988 | for (i = 0; i < 10; i++) | ||
989 | printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); | ||
990 | printk ("\n"); | ||
991 | } | ||
992 | |||
993 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
994 | { | ||
995 | unsigned long *endstack; | ||
996 | int i; | ||
997 | |||
998 | if (!stack) { | ||
999 | if (task) | ||
1000 | stack = (unsigned long *)task->thread.esp0; | ||
1001 | else | ||
1002 | stack = (unsigned long *)&stack; | ||
1003 | } | ||
1004 | endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); | ||
1005 | |||
1006 | printk("Stack from %08lx:", (unsigned long)stack); | ||
1007 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
1008 | if (stack + 1 > endstack) | ||
1009 | break; | ||
1010 | if (i % 8 == 0) | ||
1011 | printk("\n "); | ||
1012 | printk(" %08lx", *stack++); | ||
1013 | } | ||
1014 | printk("\n"); | ||
1015 | show_trace(stack); | ||
1016 | } | ||
1017 | |||
1018 | /* | ||
1019 | * The architecture-independent backtrace generator | ||
1020 | */ | ||
1021 | void dump_stack(void) | ||
1022 | { | ||
1023 | unsigned long stack; | ||
1024 | |||
1025 | show_trace(&stack); | ||
1026 | } | ||
1027 | |||
1028 | EXPORT_SYMBOL(dump_stack); | ||
1029 | |||
1030 | void bad_super_trap (struct frame *fp) | ||
1031 | { | ||
1032 | console_verbose(); | ||
1033 | if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) | ||
1034 | printk ("*** %s *** FORMAT=%X\n", | ||
1035 | vec_names[(fp->ptregs.vector) >> 2], | ||
1036 | fp->ptregs.format); | ||
1037 | else | ||
1038 | printk ("*** Exception %d *** FORMAT=%X\n", | ||
1039 | (fp->ptregs.vector) >> 2, | ||
1040 | fp->ptregs.format); | ||
1041 | if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) { | ||
1042 | unsigned short ssw = fp->un.fmtb.ssw; | ||
1043 | |||
1044 | printk ("SSW=%#06x ", ssw); | ||
1045 | |||
1046 | if (ssw & RC) | ||
1047 | printk ("Pipe stage C instruction fault at %#010lx\n", | ||
1048 | (fp->ptregs.format) == 0xA ? | ||
1049 | fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2); | ||
1050 | if (ssw & RB) | ||
1051 | printk ("Pipe stage B instruction fault at %#010lx\n", | ||
1052 | (fp->ptregs.format) == 0xA ? | ||
1053 | fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
1054 | if (ssw & DF) | ||
1055 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
1056 | ssw & RW ? "read" : "write", | ||
1057 | fp->un.fmtb.daddr, space_names[ssw & DFC], | ||
1058 | fp->ptregs.pc); | ||
1059 | } | ||
1060 | printk ("Current process id is %d\n", current->pid); | ||
1061 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | ||
1062 | } | ||
1063 | |||
1064 | asmlinkage void trap_c(struct frame *fp) | ||
1065 | { | ||
1066 | int sig; | ||
1067 | siginfo_t info; | ||
1068 | |||
1069 | if (fp->ptregs.sr & PS_S) { | ||
1070 | if ((fp->ptregs.vector >> 2) == VEC_TRACE) { | ||
1071 | /* traced a trapping instruction */ | ||
1072 | current->ptrace |= PT_DTRACE; | ||
1073 | } else | ||
1074 | bad_super_trap(fp); | ||
1075 | return; | ||
1076 | } | ||
1077 | |||
1078 | /* send the appropriate signal to the user program */ | ||
1079 | switch ((fp->ptregs.vector) >> 2) { | ||
1080 | case VEC_ADDRERR: | ||
1081 | info.si_code = BUS_ADRALN; | ||
1082 | sig = SIGBUS; | ||
1083 | break; | ||
1084 | case VEC_ILLEGAL: | ||
1085 | case VEC_LINE10: | ||
1086 | case VEC_LINE11: | ||
1087 | info.si_code = ILL_ILLOPC; | ||
1088 | sig = SIGILL; | ||
1089 | break; | ||
1090 | case VEC_PRIV: | ||
1091 | info.si_code = ILL_PRVOPC; | ||
1092 | sig = SIGILL; | ||
1093 | break; | ||
1094 | case VEC_COPROC: | ||
1095 | info.si_code = ILL_COPROC; | ||
1096 | sig = SIGILL; | ||
1097 | break; | ||
1098 | case VEC_TRAP1: | ||
1099 | case VEC_TRAP2: | ||
1100 | case VEC_TRAP3: | ||
1101 | case VEC_TRAP4: | ||
1102 | case VEC_TRAP5: | ||
1103 | case VEC_TRAP6: | ||
1104 | case VEC_TRAP7: | ||
1105 | case VEC_TRAP8: | ||
1106 | case VEC_TRAP9: | ||
1107 | case VEC_TRAP10: | ||
1108 | case VEC_TRAP11: | ||
1109 | case VEC_TRAP12: | ||
1110 | case VEC_TRAP13: | ||
1111 | case VEC_TRAP14: | ||
1112 | info.si_code = ILL_ILLTRP; | ||
1113 | sig = SIGILL; | ||
1114 | break; | ||
1115 | case VEC_FPBRUC: | ||
1116 | case VEC_FPOE: | ||
1117 | case VEC_FPNAN: | ||
1118 | info.si_code = FPE_FLTINV; | ||
1119 | sig = SIGFPE; | ||
1120 | break; | ||
1121 | case VEC_FPIR: | ||
1122 | info.si_code = FPE_FLTRES; | ||
1123 | sig = SIGFPE; | ||
1124 | break; | ||
1125 | case VEC_FPDIVZ: | ||
1126 | info.si_code = FPE_FLTDIV; | ||
1127 | sig = SIGFPE; | ||
1128 | break; | ||
1129 | case VEC_FPUNDER: | ||
1130 | info.si_code = FPE_FLTUND; | ||
1131 | sig = SIGFPE; | ||
1132 | break; | ||
1133 | case VEC_FPOVER: | ||
1134 | info.si_code = FPE_FLTOVF; | ||
1135 | sig = SIGFPE; | ||
1136 | break; | ||
1137 | case VEC_ZERODIV: | ||
1138 | info.si_code = FPE_INTDIV; | ||
1139 | sig = SIGFPE; | ||
1140 | break; | ||
1141 | case VEC_CHK: | ||
1142 | case VEC_TRAP: | ||
1143 | info.si_code = FPE_INTOVF; | ||
1144 | sig = SIGFPE; | ||
1145 | break; | ||
1146 | case VEC_TRACE: /* ptrace single step */ | ||
1147 | info.si_code = TRAP_TRACE; | ||
1148 | sig = SIGTRAP; | ||
1149 | break; | ||
1150 | case VEC_TRAP15: /* breakpoint */ | ||
1151 | info.si_code = TRAP_BRKPT; | ||
1152 | sig = SIGTRAP; | ||
1153 | break; | ||
1154 | default: | ||
1155 | info.si_code = ILL_ILLOPC; | ||
1156 | sig = SIGILL; | ||
1157 | break; | ||
1158 | } | ||
1159 | info.si_signo = sig; | ||
1160 | info.si_errno = 0; | ||
1161 | switch (fp->ptregs.format) { | ||
1162 | default: | ||
1163 | info.si_addr = (void *) fp->ptregs.pc; | ||
1164 | break; | ||
1165 | case 2: | ||
1166 | info.si_addr = (void *) fp->un.fmt2.iaddr; | ||
1167 | break; | ||
1168 | case 7: | ||
1169 | info.si_addr = (void *) fp->un.fmt7.effaddr; | ||
1170 | break; | ||
1171 | case 9: | ||
1172 | info.si_addr = (void *) fp->un.fmt9.iaddr; | ||
1173 | break; | ||
1174 | case 10: | ||
1175 | info.si_addr = (void *) fp->un.fmta.daddr; | ||
1176 | break; | ||
1177 | case 11: | ||
1178 | info.si_addr = (void *) fp->un.fmtb.daddr; | ||
1179 | break; | ||
1180 | } | ||
1181 | force_sig_info (sig, &info, current); | ||
1182 | } | ||
1183 | |||
1184 | void die_if_kernel (char *str, struct pt_regs *fp, int nr) | ||
1185 | { | ||
1186 | if (!(fp->sr & PS_S)) | ||
1187 | return; | ||
1188 | |||
1189 | console_verbose(); | ||
1190 | printk("%s: %08x\n",str,nr); | ||
1191 | print_modules(); | ||
1192 | printk("PC: [<%08lx>]",fp->pc); | ||
1193 | print_symbol(" %s\n", fp->pc); | ||
1194 | printk("\nSR: %04x SP: %p a2: %08lx\n", | ||
1195 | fp->sr, fp, fp->a2); | ||
1196 | printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | ||
1197 | fp->d0, fp->d1, fp->d2, fp->d3); | ||
1198 | printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | ||
1199 | fp->d4, fp->d5, fp->a0, fp->a1); | ||
1200 | |||
1201 | printk("Process %s (pid: %d, stackpage=%08lx)\n", | ||
1202 | current->comm, current->pid, PAGE_SIZE+(unsigned long)current); | ||
1203 | show_stack(NULL, (unsigned long *)fp); | ||
1204 | do_exit(SIGSEGV); | ||
1205 | } | ||
1206 | |||
1207 | /* | ||
1208 | * This function is called if an error occur while accessing | ||
1209 | * user-space from the fpsp040 code. | ||
1210 | */ | ||
1211 | asmlinkage void fpsp040_die(void) | ||
1212 | { | ||
1213 | do_exit(SIGSEGV); | ||
1214 | } | ||
1215 | |||
1216 | #ifdef CONFIG_M68KFPU_EMU | ||
1217 | asmlinkage void fpemu_signal(int signal, int code, void *addr) | ||
1218 | { | ||
1219 | siginfo_t info; | ||
1220 | |||
1221 | info.si_signo = signal; | ||
1222 | info.si_errno = 0; | ||
1223 | info.si_code = code; | ||
1224 | info.si_addr = addr; | ||
1225 | force_sig_info(signal, &info, current); | ||
1226 | } | ||
1227 | #endif | ||
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds new file mode 100644 index 000000000000..e58654f3f8dd --- /dev/null +++ b/arch/m68k/kernel/vmlinux-std.lds | |||
@@ -0,0 +1,95 @@ | |||
1 | /* ld script to make m68k Linux kernel */ | ||
2 | |||
3 | #include <asm-generic/vmlinux.lds.h> | ||
4 | |||
5 | OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") | ||
6 | OUTPUT_ARCH(m68k) | ||
7 | ENTRY(_start) | ||
8 | jiffies = jiffies_64 + 4; | ||
9 | SECTIONS | ||
10 | { | ||
11 | . = 0x1000; | ||
12 | _text = .; /* Text and read-only data */ | ||
13 | .text : { | ||
14 | *(.text) | ||
15 | SCHED_TEXT | ||
16 | *(.fixup) | ||
17 | *(.gnu.warning) | ||
18 | } :text = 0x4e75 | ||
19 | |||
20 | . = ALIGN(16); /* Exception table */ | ||
21 | __start___ex_table = .; | ||
22 | __ex_table : { *(__ex_table) } | ||
23 | __stop___ex_table = .; | ||
24 | |||
25 | RODATA | ||
26 | |||
27 | _etext = .; /* End of text section */ | ||
28 | |||
29 | .data : { /* Data */ | ||
30 | *(.data) | ||
31 | CONSTRUCTORS | ||
32 | } | ||
33 | |||
34 | .bss : { *(.bss) } /* BSS */ | ||
35 | |||
36 | . = ALIGN(16); | ||
37 | .data.cacheline_aligned : { *(.data.cacheline_aligned) } :data | ||
38 | |||
39 | _edata = .; /* End of data section */ | ||
40 | |||
41 | /* will be freed after init */ | ||
42 | . = ALIGN(4096); /* Init code and data */ | ||
43 | __init_begin = .; | ||
44 | .init.text : { | ||
45 | _sinittext = .; | ||
46 | *(.init.text) | ||
47 | _einittext = .; | ||
48 | } | ||
49 | .init.data : { *(.init.data) } | ||
50 | . = ALIGN(16); | ||
51 | __setup_start = .; | ||
52 | .init.setup : { *(.init.setup) } | ||
53 | __setup_end = .; | ||
54 | __initcall_start = .; | ||
55 | .initcall.init : { | ||
56 | *(.initcall1.init) | ||
57 | *(.initcall2.init) | ||
58 | *(.initcall3.init) | ||
59 | *(.initcall4.init) | ||
60 | *(.initcall5.init) | ||
61 | *(.initcall6.init) | ||
62 | *(.initcall7.init) | ||
63 | } | ||
64 | __initcall_end = .; | ||
65 | __con_initcall_start = .; | ||
66 | .con_initcall.init : { *(.con_initcall.init) } | ||
67 | __con_initcall_end = .; | ||
68 | SECURITY_INIT | ||
69 | . = ALIGN(8192); | ||
70 | __initramfs_start = .; | ||
71 | .init.ramfs : { *(.init.ramfs) } | ||
72 | __initramfs_end = .; | ||
73 | . = ALIGN(8192); | ||
74 | __init_end = .; | ||
75 | |||
76 | .data.init_task : { *(.data.init_task) } /* The initial task and kernel stack */ | ||
77 | |||
78 | _end = . ; | ||
79 | |||
80 | /* Sections to be discarded */ | ||
81 | /DISCARD/ : { | ||
82 | *(.exit.text) | ||
83 | *(.exit.data) | ||
84 | *(.exitcall.exit) | ||
85 | } | ||
86 | |||
87 | /* Stabs debugging sections. */ | ||
88 | .stab 0 : { *(.stab) } | ||
89 | .stabstr 0 : { *(.stabstr) } | ||
90 | .stab.excl 0 : { *(.stab.excl) } | ||
91 | .stab.exclstr 0 : { *(.stab.exclstr) } | ||
92 | .stab.index 0 : { *(.stab.index) } | ||
93 | .stab.indexstr 0 : { *(.stab.indexstr) } | ||
94 | .comment 0 : { *(.comment) } | ||
95 | } | ||
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds new file mode 100644 index 000000000000..cc37e8d3c1e2 --- /dev/null +++ b/arch/m68k/kernel/vmlinux-sun3.lds | |||
@@ -0,0 +1,95 @@ | |||
1 | /* ld script to make m68k Linux kernel */ | ||
2 | |||
3 | #include <asm-generic/vmlinux.lds.h> | ||
4 | |||
5 | OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k") | ||
6 | OUTPUT_ARCH(m68k) | ||
7 | ENTRY(_start) | ||
8 | jiffies = jiffies_64 + 4; | ||
9 | SECTIONS | ||
10 | { | ||
11 | . = 0xE004000; | ||
12 | _text = .; /* Text and read-only data */ | ||
13 | .text : { | ||
14 | *(.head) | ||
15 | *(.text) | ||
16 | SCHED_TEXT | ||
17 | *(.fixup) | ||
18 | *(.gnu.warning) | ||
19 | } :text = 0x4e75 | ||
20 | RODATA | ||
21 | |||
22 | _etext = .; /* End of text section */ | ||
23 | |||
24 | .data : { /* Data */ | ||
25 | *(.data) | ||
26 | CONSTRUCTORS | ||
27 | . = ALIGN(16); /* Exception table */ | ||
28 | __start___ex_table = .; | ||
29 | *(__ex_table) | ||
30 | __stop___ex_table = .; | ||
31 | } :data | ||
32 | /* End of data goes *here* so that freeing init code works properly. */ | ||
33 | _edata = .; | ||
34 | |||
35 | /* will be freed after init */ | ||
36 | . = ALIGN(8192); /* Init code and data */ | ||
37 | __init_begin = .; | ||
38 | .init.text : { | ||
39 | _sinittext = .; | ||
40 | *(.init.text) | ||
41 | _einittext = .; | ||
42 | } | ||
43 | .init.data : { *(.init.data) } | ||
44 | . = ALIGN(16); | ||
45 | __setup_start = .; | ||
46 | .init.setup : { *(.init.setup) } | ||
47 | __setup_end = .; | ||
48 | __initcall_start = .; | ||
49 | .initcall.init : { | ||
50 | *(.initcall1.init) | ||
51 | *(.initcall2.init) | ||
52 | *(.initcall3.init) | ||
53 | *(.initcall4.init) | ||
54 | *(.initcall5.init) | ||
55 | *(.initcall6.init) | ||
56 | *(.initcall7.init) | ||
57 | } | ||
58 | __initcall_end = .; | ||
59 | __con_initcall_start = .; | ||
60 | .con_initcall.init : { *(.con_initcall.init) } | ||
61 | __con_initcall_end = .; | ||
62 | SECURITY_INIT | ||
63 | . = ALIGN(8192); | ||
64 | __initramfs_start = .; | ||
65 | .init.ramfs : { *(.init.ramfs) } | ||
66 | __initramfs_end = .; | ||
67 | . = ALIGN(8192); | ||
68 | __init_end = .; | ||
69 | .init.task : { *(init_task) } | ||
70 | |||
71 | |||
72 | .bss : { *(.bss) } /* BSS */ | ||
73 | |||
74 | _end = . ; | ||
75 | |||
76 | /* Sections to be discarded */ | ||
77 | /DISCARD/ : { | ||
78 | *(.exit.text) | ||
79 | *(.exit.data) | ||
80 | *(.exitcall.exit) | ||
81 | } | ||
82 | |||
83 | .crap : { | ||
84 | /* Stabs debugging sections. */ | ||
85 | *(.stab) | ||
86 | *(.stabstr) | ||
87 | *(.stab.excl) | ||
88 | *(.stab.exclstr) | ||
89 | *(.stab.index) | ||
90 | *(.stab.indexstr) | ||
91 | *(.comment) | ||
92 | *(.note) | ||
93 | } | ||
94 | |||
95 | } | ||
diff --git a/arch/m68k/kernel/vmlinux.lds.S b/arch/m68k/kernel/vmlinux.lds.S new file mode 100644 index 000000000000..497b924f3c86 --- /dev/null +++ b/arch/m68k/kernel/vmlinux.lds.S | |||
@@ -0,0 +1,11 @@ | |||
1 | #include <linux/config.h> | ||
2 | PHDRS | ||
3 | { | ||
4 | text PT_LOAD FILEHDR PHDRS FLAGS (7); | ||
5 | data PT_LOAD FLAGS (7); | ||
6 | } | ||
7 | #ifdef CONFIG_SUN3 | ||
8 | #include "vmlinux-sun3.lds" | ||
9 | #else | ||
10 | #include "vmlinux-std.lds" | ||
11 | #endif | ||