Commit fca5dcd4835ed09bb1a48a355344aff7a25c76e0
1 parent
3825ac0ee6
Exists in
master
and in
7 other branches
powerpc: Simplify and clean up the xmon terminal I/O
This factors out the common bits of arch/powerpc/xmon/start_*.c into a new nonstdio.c, and removes some stuff that was supposed to make xmon's I/O routines somewhat stdio-like but was never used. It also makes the parsing of the xmon= command line option common, so that ppc32 can now use xmon={off,on,early} also. Signed-off-by: Paul Mackerras <paulus@samba.org>
Showing 12 changed files with 236 additions and 729 deletions Inline Diff
- arch/powerpc/kernel/setup-common.c
- arch/powerpc/kernel/setup_32.c
- arch/powerpc/kernel/setup_64.c
- arch/powerpc/xmon/Makefile
- arch/powerpc/xmon/nonstdio.c
- arch/powerpc/xmon/nonstdio.h
- arch/powerpc/xmon/start_32.c
- arch/powerpc/xmon/start_64.c
- arch/powerpc/xmon/start_8xx.c
- arch/powerpc/xmon/subr_prf.c
- arch/powerpc/xmon/xmon.c
- include/asm-powerpc/xmon.h
arch/powerpc/kernel/setup-common.c
1 | /* | 1 | /* |
2 | * Common boot and setup code for both 32-bit and 64-bit. | 2 | * Common boot and setup code for both 32-bit and 64-bit. |
3 | * Extracted from arch/powerpc/kernel/setup_64.c. | 3 | * Extracted from arch/powerpc/kernel/setup_64.c. |
4 | * | 4 | * |
5 | * Copyright (C) 2001 PPC64 Team, IBM Corp | 5 | * Copyright (C) 2001 PPC64 Team, IBM Corp |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | #include <linux/config.h> | 12 | #include <linux/config.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/string.h> | 14 | #include <linux/string.h> |
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/reboot.h> | 18 | #include <linux/reboot.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/initrd.h> | 20 | #include <linux/initrd.h> |
21 | #include <linux/ide.h> | 21 | #include <linux/ide.h> |
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/ioport.h> | 23 | #include <linux/ioport.h> |
24 | #include <linux/console.h> | 24 | #include <linux/console.h> |
25 | #include <linux/utsname.h> | 25 | #include <linux/utsname.h> |
26 | #include <linux/tty.h> | 26 | #include <linux/tty.h> |
27 | #include <linux/root_dev.h> | 27 | #include <linux/root_dev.h> |
28 | #include <linux/notifier.h> | 28 | #include <linux/notifier.h> |
29 | #include <linux/cpu.h> | 29 | #include <linux/cpu.h> |
30 | #include <linux/unistd.h> | 30 | #include <linux/unistd.h> |
31 | #include <linux/serial.h> | 31 | #include <linux/serial.h> |
32 | #include <linux/serial_8250.h> | 32 | #include <linux/serial_8250.h> |
33 | #include <asm/io.h> | 33 | #include <asm/io.h> |
34 | #include <asm/prom.h> | 34 | #include <asm/prom.h> |
35 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
36 | #include <asm/pgtable.h> | 36 | #include <asm/pgtable.h> |
37 | #include <asm/smp.h> | 37 | #include <asm/smp.h> |
38 | #include <asm/elf.h> | 38 | #include <asm/elf.h> |
39 | #include <asm/machdep.h> | 39 | #include <asm/machdep.h> |
40 | #include <asm/time.h> | 40 | #include <asm/time.h> |
41 | #include <asm/cputable.h> | 41 | #include <asm/cputable.h> |
42 | #include <asm/sections.h> | 42 | #include <asm/sections.h> |
43 | #include <asm/btext.h> | 43 | #include <asm/btext.h> |
44 | #include <asm/nvram.h> | 44 | #include <asm/nvram.h> |
45 | #include <asm/setup.h> | 45 | #include <asm/setup.h> |
46 | #include <asm/system.h> | 46 | #include <asm/system.h> |
47 | #include <asm/rtas.h> | 47 | #include <asm/rtas.h> |
48 | #include <asm/iommu.h> | 48 | #include <asm/iommu.h> |
49 | #include <asm/serial.h> | 49 | #include <asm/serial.h> |
50 | #include <asm/cache.h> | 50 | #include <asm/cache.h> |
51 | #include <asm/page.h> | 51 | #include <asm/page.h> |
52 | #include <asm/mmu.h> | 52 | #include <asm/mmu.h> |
53 | #include <asm/lmb.h> | 53 | #include <asm/lmb.h> |
54 | #include <asm/xmon.h> | ||
54 | 55 | ||
55 | #undef DEBUG | 56 | #undef DEBUG |
56 | 57 | ||
57 | #ifdef DEBUG | 58 | #ifdef DEBUG |
58 | #define DBG(fmt...) udbg_printf(fmt) | 59 | #define DBG(fmt...) udbg_printf(fmt) |
59 | #else | 60 | #else |
60 | #define DBG(fmt...) | 61 | #define DBG(fmt...) |
61 | #endif | 62 | #endif |
62 | 63 | ||
63 | /* | 64 | /* |
64 | * This still seems to be needed... -- paulus | 65 | * This still seems to be needed... -- paulus |
65 | */ | 66 | */ |
66 | struct screen_info screen_info = { | 67 | struct screen_info screen_info = { |
67 | .orig_x = 0, | 68 | .orig_x = 0, |
68 | .orig_y = 25, | 69 | .orig_y = 25, |
69 | .orig_video_cols = 80, | 70 | .orig_video_cols = 80, |
70 | .orig_video_lines = 25, | 71 | .orig_video_lines = 25, |
71 | .orig_video_isVGA = 1, | 72 | .orig_video_isVGA = 1, |
72 | .orig_video_points = 16 | 73 | .orig_video_points = 16 |
73 | }; | 74 | }; |
74 | 75 | ||
75 | #ifdef __DO_IRQ_CANON | 76 | #ifdef __DO_IRQ_CANON |
76 | /* XXX should go elsewhere eventually */ | 77 | /* XXX should go elsewhere eventually */ |
77 | int ppc_do_canonicalize_irqs; | 78 | int ppc_do_canonicalize_irqs; |
78 | EXPORT_SYMBOL(ppc_do_canonicalize_irqs); | 79 | EXPORT_SYMBOL(ppc_do_canonicalize_irqs); |
79 | #endif | 80 | #endif |
80 | 81 | ||
81 | /* also used by kexec */ | 82 | /* also used by kexec */ |
82 | void machine_shutdown(void) | 83 | void machine_shutdown(void) |
83 | { | 84 | { |
84 | if (ppc_md.nvram_sync) | 85 | if (ppc_md.nvram_sync) |
85 | ppc_md.nvram_sync(); | 86 | ppc_md.nvram_sync(); |
86 | } | 87 | } |
87 | 88 | ||
88 | void machine_restart(char *cmd) | 89 | void machine_restart(char *cmd) |
89 | { | 90 | { |
90 | machine_shutdown(); | 91 | machine_shutdown(); |
91 | ppc_md.restart(cmd); | 92 | ppc_md.restart(cmd); |
92 | #ifdef CONFIG_SMP | 93 | #ifdef CONFIG_SMP |
93 | smp_send_stop(); | 94 | smp_send_stop(); |
94 | #endif | 95 | #endif |
95 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 96 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
96 | local_irq_disable(); | 97 | local_irq_disable(); |
97 | while (1) ; | 98 | while (1) ; |
98 | } | 99 | } |
99 | 100 | ||
100 | void machine_power_off(void) | 101 | void machine_power_off(void) |
101 | { | 102 | { |
102 | machine_shutdown(); | 103 | machine_shutdown(); |
103 | ppc_md.power_off(); | 104 | ppc_md.power_off(); |
104 | #ifdef CONFIG_SMP | 105 | #ifdef CONFIG_SMP |
105 | smp_send_stop(); | 106 | smp_send_stop(); |
106 | #endif | 107 | #endif |
107 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 108 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
108 | local_irq_disable(); | 109 | local_irq_disable(); |
109 | while (1) ; | 110 | while (1) ; |
110 | } | 111 | } |
111 | /* Used by the G5 thermal driver */ | 112 | /* Used by the G5 thermal driver */ |
112 | EXPORT_SYMBOL_GPL(machine_power_off); | 113 | EXPORT_SYMBOL_GPL(machine_power_off); |
113 | 114 | ||
114 | void (*pm_power_off)(void) = machine_power_off; | 115 | void (*pm_power_off)(void) = machine_power_off; |
115 | EXPORT_SYMBOL_GPL(pm_power_off); | 116 | EXPORT_SYMBOL_GPL(pm_power_off); |
116 | 117 | ||
117 | void machine_halt(void) | 118 | void machine_halt(void) |
118 | { | 119 | { |
119 | machine_shutdown(); | 120 | machine_shutdown(); |
120 | ppc_md.halt(); | 121 | ppc_md.halt(); |
121 | #ifdef CONFIG_SMP | 122 | #ifdef CONFIG_SMP |
122 | smp_send_stop(); | 123 | smp_send_stop(); |
123 | #endif | 124 | #endif |
124 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 125 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
125 | local_irq_disable(); | 126 | local_irq_disable(); |
126 | while (1) ; | 127 | while (1) ; |
127 | } | 128 | } |
128 | 129 | ||
129 | 130 | ||
130 | #ifdef CONFIG_TAU | 131 | #ifdef CONFIG_TAU |
131 | extern u32 cpu_temp(unsigned long cpu); | 132 | extern u32 cpu_temp(unsigned long cpu); |
132 | extern u32 cpu_temp_both(unsigned long cpu); | 133 | extern u32 cpu_temp_both(unsigned long cpu); |
133 | #endif /* CONFIG_TAU */ | 134 | #endif /* CONFIG_TAU */ |
134 | 135 | ||
135 | #ifdef CONFIG_SMP | 136 | #ifdef CONFIG_SMP |
136 | DEFINE_PER_CPU(unsigned int, pvr); | 137 | DEFINE_PER_CPU(unsigned int, pvr); |
137 | #endif | 138 | #endif |
138 | 139 | ||
139 | static int show_cpuinfo(struct seq_file *m, void *v) | 140 | static int show_cpuinfo(struct seq_file *m, void *v) |
140 | { | 141 | { |
141 | unsigned long cpu_id = (unsigned long)v - 1; | 142 | unsigned long cpu_id = (unsigned long)v - 1; |
142 | unsigned int pvr; | 143 | unsigned int pvr; |
143 | unsigned short maj; | 144 | unsigned short maj; |
144 | unsigned short min; | 145 | unsigned short min; |
145 | 146 | ||
146 | if (cpu_id == NR_CPUS) { | 147 | if (cpu_id == NR_CPUS) { |
147 | #if defined(CONFIG_SMP) && defined(CONFIG_PPC32) | 148 | #if defined(CONFIG_SMP) && defined(CONFIG_PPC32) |
148 | unsigned long bogosum = 0; | 149 | unsigned long bogosum = 0; |
149 | int i; | 150 | int i; |
150 | for (i = 0; i < NR_CPUS; ++i) | 151 | for (i = 0; i < NR_CPUS; ++i) |
151 | if (cpu_online(i)) | 152 | if (cpu_online(i)) |
152 | bogosum += loops_per_jiffy; | 153 | bogosum += loops_per_jiffy; |
153 | seq_printf(m, "total bogomips\t: %lu.%02lu\n", | 154 | seq_printf(m, "total bogomips\t: %lu.%02lu\n", |
154 | bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); | 155 | bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); |
155 | #endif /* CONFIG_SMP && CONFIG_PPC32 */ | 156 | #endif /* CONFIG_SMP && CONFIG_PPC32 */ |
156 | seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); | 157 | seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); |
157 | 158 | ||
158 | if (ppc_md.show_cpuinfo != NULL) | 159 | if (ppc_md.show_cpuinfo != NULL) |
159 | ppc_md.show_cpuinfo(m); | 160 | ppc_md.show_cpuinfo(m); |
160 | 161 | ||
161 | return 0; | 162 | return 0; |
162 | } | 163 | } |
163 | 164 | ||
164 | /* We only show online cpus: disable preempt (overzealous, I | 165 | /* We only show online cpus: disable preempt (overzealous, I |
165 | * knew) to prevent cpu going down. */ | 166 | * knew) to prevent cpu going down. */ |
166 | preempt_disable(); | 167 | preempt_disable(); |
167 | if (!cpu_online(cpu_id)) { | 168 | if (!cpu_online(cpu_id)) { |
168 | preempt_enable(); | 169 | preempt_enable(); |
169 | return 0; | 170 | return 0; |
170 | } | 171 | } |
171 | 172 | ||
172 | #ifdef CONFIG_SMP | 173 | #ifdef CONFIG_SMP |
173 | pvr = per_cpu(pvr, cpu_id); | 174 | pvr = per_cpu(pvr, cpu_id); |
174 | #else | 175 | #else |
175 | pvr = mfspr(SPRN_PVR); | 176 | pvr = mfspr(SPRN_PVR); |
176 | #endif | 177 | #endif |
177 | maj = (pvr >> 8) & 0xFF; | 178 | maj = (pvr >> 8) & 0xFF; |
178 | min = pvr & 0xFF; | 179 | min = pvr & 0xFF; |
179 | 180 | ||
180 | seq_printf(m, "processor\t: %lu\n", cpu_id); | 181 | seq_printf(m, "processor\t: %lu\n", cpu_id); |
181 | seq_printf(m, "cpu\t\t: "); | 182 | seq_printf(m, "cpu\t\t: "); |
182 | 183 | ||
183 | if (cur_cpu_spec->pvr_mask) | 184 | if (cur_cpu_spec->pvr_mask) |
184 | seq_printf(m, "%s", cur_cpu_spec->cpu_name); | 185 | seq_printf(m, "%s", cur_cpu_spec->cpu_name); |
185 | else | 186 | else |
186 | seq_printf(m, "unknown (%08x)", pvr); | 187 | seq_printf(m, "unknown (%08x)", pvr); |
187 | 188 | ||
188 | #ifdef CONFIG_ALTIVEC | 189 | #ifdef CONFIG_ALTIVEC |
189 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | 190 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) |
190 | seq_printf(m, ", altivec supported"); | 191 | seq_printf(m, ", altivec supported"); |
191 | #endif /* CONFIG_ALTIVEC */ | 192 | #endif /* CONFIG_ALTIVEC */ |
192 | 193 | ||
193 | seq_printf(m, "\n"); | 194 | seq_printf(m, "\n"); |
194 | 195 | ||
195 | #ifdef CONFIG_TAU | 196 | #ifdef CONFIG_TAU |
196 | if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) { | 197 | if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) { |
197 | #ifdef CONFIG_TAU_AVERAGE | 198 | #ifdef CONFIG_TAU_AVERAGE |
198 | /* more straightforward, but potentially misleading */ | 199 | /* more straightforward, but potentially misleading */ |
199 | seq_printf(m, "temperature \t: %u C (uncalibrated)\n", | 200 | seq_printf(m, "temperature \t: %u C (uncalibrated)\n", |
200 | cpu_temp(cpu_id)); | 201 | cpu_temp(cpu_id)); |
201 | #else | 202 | #else |
202 | /* show the actual temp sensor range */ | 203 | /* show the actual temp sensor range */ |
203 | u32 temp; | 204 | u32 temp; |
204 | temp = cpu_temp_both(cpu_id); | 205 | temp = cpu_temp_both(cpu_id); |
205 | seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n", | 206 | seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n", |
206 | temp & 0xff, temp >> 16); | 207 | temp & 0xff, temp >> 16); |
207 | #endif | 208 | #endif |
208 | } | 209 | } |
209 | #endif /* CONFIG_TAU */ | 210 | #endif /* CONFIG_TAU */ |
210 | 211 | ||
211 | /* | 212 | /* |
212 | * Assume here that all clock rates are the same in a | 213 | * Assume here that all clock rates are the same in a |
213 | * smp system. -- Cort | 214 | * smp system. -- Cort |
214 | */ | 215 | */ |
215 | if (ppc_proc_freq) | 216 | if (ppc_proc_freq) |
216 | seq_printf(m, "clock\t\t: %lu.%06luMHz\n", | 217 | seq_printf(m, "clock\t\t: %lu.%06luMHz\n", |
217 | ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); | 218 | ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); |
218 | 219 | ||
219 | if (ppc_md.show_percpuinfo != NULL) | 220 | if (ppc_md.show_percpuinfo != NULL) |
220 | ppc_md.show_percpuinfo(m, cpu_id); | 221 | ppc_md.show_percpuinfo(m, cpu_id); |
221 | 222 | ||
222 | /* If we are a Freescale core do a simple check so | 223 | /* If we are a Freescale core do a simple check so |
223 | * we dont have to keep adding cases in the future */ | 224 | * we dont have to keep adding cases in the future */ |
224 | if (PVR_VER(pvr) & 0x8000) { | 225 | if (PVR_VER(pvr) & 0x8000) { |
225 | maj = PVR_MAJ(pvr); | 226 | maj = PVR_MAJ(pvr); |
226 | min = PVR_MIN(pvr); | 227 | min = PVR_MIN(pvr); |
227 | } else { | 228 | } else { |
228 | switch (PVR_VER(pvr)) { | 229 | switch (PVR_VER(pvr)) { |
229 | case 0x0020: /* 403 family */ | 230 | case 0x0020: /* 403 family */ |
230 | maj = PVR_MAJ(pvr) + 1; | 231 | maj = PVR_MAJ(pvr) + 1; |
231 | min = PVR_MIN(pvr); | 232 | min = PVR_MIN(pvr); |
232 | break; | 233 | break; |
233 | case 0x1008: /* 740P/750P ?? */ | 234 | case 0x1008: /* 740P/750P ?? */ |
234 | maj = ((pvr >> 8) & 0xFF) - 1; | 235 | maj = ((pvr >> 8) & 0xFF) - 1; |
235 | min = pvr & 0xFF; | 236 | min = pvr & 0xFF; |
236 | break; | 237 | break; |
237 | default: | 238 | default: |
238 | maj = (pvr >> 8) & 0xFF; | 239 | maj = (pvr >> 8) & 0xFF; |
239 | min = pvr & 0xFF; | 240 | min = pvr & 0xFF; |
240 | break; | 241 | break; |
241 | } | 242 | } |
242 | } | 243 | } |
243 | 244 | ||
244 | seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", | 245 | seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", |
245 | maj, min, PVR_VER(pvr), PVR_REV(pvr)); | 246 | maj, min, PVR_VER(pvr), PVR_REV(pvr)); |
246 | 247 | ||
247 | #ifdef CONFIG_PPC32 | 248 | #ifdef CONFIG_PPC32 |
248 | seq_printf(m, "bogomips\t: %lu.%02lu\n", | 249 | seq_printf(m, "bogomips\t: %lu.%02lu\n", |
249 | loops_per_jiffy / (500000/HZ), | 250 | loops_per_jiffy / (500000/HZ), |
250 | (loops_per_jiffy / (5000/HZ)) % 100); | 251 | (loops_per_jiffy / (5000/HZ)) % 100); |
251 | #endif | 252 | #endif |
252 | 253 | ||
253 | #ifdef CONFIG_SMP | 254 | #ifdef CONFIG_SMP |
254 | seq_printf(m, "\n"); | 255 | seq_printf(m, "\n"); |
255 | #endif | 256 | #endif |
256 | 257 | ||
257 | preempt_enable(); | 258 | preempt_enable(); |
258 | return 0; | 259 | return 0; |
259 | } | 260 | } |
260 | 261 | ||
261 | static void *c_start(struct seq_file *m, loff_t *pos) | 262 | static void *c_start(struct seq_file *m, loff_t *pos) |
262 | { | 263 | { |
263 | unsigned long i = *pos; | 264 | unsigned long i = *pos; |
264 | 265 | ||
265 | return i <= NR_CPUS ? (void *)(i + 1) : NULL; | 266 | return i <= NR_CPUS ? (void *)(i + 1) : NULL; |
266 | } | 267 | } |
267 | 268 | ||
268 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | 269 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) |
269 | { | 270 | { |
270 | ++*pos; | 271 | ++*pos; |
271 | return c_start(m, pos); | 272 | return c_start(m, pos); |
272 | } | 273 | } |
273 | 274 | ||
274 | static void c_stop(struct seq_file *m, void *v) | 275 | static void c_stop(struct seq_file *m, void *v) |
275 | { | 276 | { |
276 | } | 277 | } |
277 | 278 | ||
278 | struct seq_operations cpuinfo_op = { | 279 | struct seq_operations cpuinfo_op = { |
279 | .start =c_start, | 280 | .start =c_start, |
280 | .next = c_next, | 281 | .next = c_next, |
281 | .stop = c_stop, | 282 | .stop = c_stop, |
282 | .show = show_cpuinfo, | 283 | .show = show_cpuinfo, |
283 | }; | 284 | }; |
284 | 285 | ||
285 | #ifdef CONFIG_PPC_MULTIPLATFORM | 286 | #ifdef CONFIG_PPC_MULTIPLATFORM |
286 | static int __init set_preferred_console(void) | 287 | static int __init set_preferred_console(void) |
287 | { | 288 | { |
288 | struct device_node *prom_stdout = NULL; | 289 | struct device_node *prom_stdout = NULL; |
289 | char *name; | 290 | char *name; |
290 | u32 *spd; | 291 | u32 *spd; |
291 | int offset = 0; | 292 | int offset = 0; |
292 | 293 | ||
293 | DBG(" -> set_preferred_console()\n"); | 294 | DBG(" -> set_preferred_console()\n"); |
294 | 295 | ||
295 | /* The user has requested a console so this is already set up. */ | 296 | /* The user has requested a console so this is already set up. */ |
296 | if (strstr(saved_command_line, "console=")) { | 297 | if (strstr(saved_command_line, "console=")) { |
297 | DBG(" console was specified !\n"); | 298 | DBG(" console was specified !\n"); |
298 | return -EBUSY; | 299 | return -EBUSY; |
299 | } | 300 | } |
300 | 301 | ||
301 | if (!of_chosen) { | 302 | if (!of_chosen) { |
302 | DBG(" of_chosen is NULL !\n"); | 303 | DBG(" of_chosen is NULL !\n"); |
303 | return -ENODEV; | 304 | return -ENODEV; |
304 | } | 305 | } |
305 | /* We are getting a weird phandle from OF ... */ | 306 | /* We are getting a weird phandle from OF ... */ |
306 | /* ... So use the full path instead */ | 307 | /* ... So use the full path instead */ |
307 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | 308 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); |
308 | if (name == NULL) { | 309 | if (name == NULL) { |
309 | DBG(" no linux,stdout-path !\n"); | 310 | DBG(" no linux,stdout-path !\n"); |
310 | return -ENODEV; | 311 | return -ENODEV; |
311 | } | 312 | } |
312 | prom_stdout = of_find_node_by_path(name); | 313 | prom_stdout = of_find_node_by_path(name); |
313 | if (!prom_stdout) { | 314 | if (!prom_stdout) { |
314 | DBG(" can't find stdout package %s !\n", name); | 315 | DBG(" can't find stdout package %s !\n", name); |
315 | return -ENODEV; | 316 | return -ENODEV; |
316 | } | 317 | } |
317 | DBG("stdout is %s\n", prom_stdout->full_name); | 318 | DBG("stdout is %s\n", prom_stdout->full_name); |
318 | 319 | ||
319 | name = (char *)get_property(prom_stdout, "name", NULL); | 320 | name = (char *)get_property(prom_stdout, "name", NULL); |
320 | if (!name) { | 321 | if (!name) { |
321 | DBG(" stdout package has no name !\n"); | 322 | DBG(" stdout package has no name !\n"); |
322 | goto not_found; | 323 | goto not_found; |
323 | } | 324 | } |
324 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); | 325 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); |
325 | 326 | ||
326 | if (0) | 327 | if (0) |
327 | ; | 328 | ; |
328 | #ifdef CONFIG_SERIAL_8250_CONSOLE | 329 | #ifdef CONFIG_SERIAL_8250_CONSOLE |
329 | else if (strcmp(name, "serial") == 0) { | 330 | else if (strcmp(name, "serial") == 0) { |
330 | int i; | 331 | int i; |
331 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); | 332 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); |
332 | if (i > 8) { | 333 | if (i > 8) { |
333 | switch (reg[1]) { | 334 | switch (reg[1]) { |
334 | case 0x3f8: | 335 | case 0x3f8: |
335 | offset = 0; | 336 | offset = 0; |
336 | break; | 337 | break; |
337 | case 0x2f8: | 338 | case 0x2f8: |
338 | offset = 1; | 339 | offset = 1; |
339 | break; | 340 | break; |
340 | case 0x898: | 341 | case 0x898: |
341 | offset = 2; | 342 | offset = 2; |
342 | break; | 343 | break; |
343 | case 0x890: | 344 | case 0x890: |
344 | offset = 3; | 345 | offset = 3; |
345 | break; | 346 | break; |
346 | default: | 347 | default: |
347 | /* We dont recognise the serial port */ | 348 | /* We dont recognise the serial port */ |
348 | goto not_found; | 349 | goto not_found; |
349 | } | 350 | } |
350 | } | 351 | } |
351 | } | 352 | } |
352 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | 353 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ |
353 | #ifdef CONFIG_PPC_PSERIES | 354 | #ifdef CONFIG_PPC_PSERIES |
354 | else if (strcmp(name, "vty") == 0) { | 355 | else if (strcmp(name, "vty") == 0) { |
355 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); | 356 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); |
356 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); | 357 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); |
357 | 358 | ||
358 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { | 359 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { |
359 | /* Host Virtual Serial Interface */ | 360 | /* Host Virtual Serial Interface */ |
360 | switch (reg[0]) { | 361 | switch (reg[0]) { |
361 | case 0x30000000: | 362 | case 0x30000000: |
362 | offset = 0; | 363 | offset = 0; |
363 | break; | 364 | break; |
364 | case 0x30000001: | 365 | case 0x30000001: |
365 | offset = 1; | 366 | offset = 1; |
366 | break; | 367 | break; |
367 | default: | 368 | default: |
368 | goto not_found; | 369 | goto not_found; |
369 | } | 370 | } |
370 | of_node_put(prom_stdout); | 371 | of_node_put(prom_stdout); |
371 | DBG("Found hvsi console at offset %d\n", offset); | 372 | DBG("Found hvsi console at offset %d\n", offset); |
372 | return add_preferred_console("hvsi", offset, NULL); | 373 | return add_preferred_console("hvsi", offset, NULL); |
373 | } else { | 374 | } else { |
374 | /* pSeries LPAR virtual console */ | 375 | /* pSeries LPAR virtual console */ |
375 | of_node_put(prom_stdout); | 376 | of_node_put(prom_stdout); |
376 | DBG("Found hvc console\n"); | 377 | DBG("Found hvc console\n"); |
377 | return add_preferred_console("hvc", 0, NULL); | 378 | return add_preferred_console("hvc", 0, NULL); |
378 | } | 379 | } |
379 | } | 380 | } |
380 | #endif /* CONFIG_PPC_PSERIES */ | 381 | #endif /* CONFIG_PPC_PSERIES */ |
381 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE | 382 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE |
382 | else if (strcmp(name, "ch-a") == 0) | 383 | else if (strcmp(name, "ch-a") == 0) |
383 | offset = 0; | 384 | offset = 0; |
384 | else if (strcmp(name, "ch-b") == 0) | 385 | else if (strcmp(name, "ch-b") == 0) |
385 | offset = 1; | 386 | offset = 1; |
386 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ | 387 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ |
387 | else | 388 | else |
388 | goto not_found; | 389 | goto not_found; |
389 | of_node_put(prom_stdout); | 390 | of_node_put(prom_stdout); |
390 | 391 | ||
391 | DBG("Found serial console at ttyS%d\n", offset); | 392 | DBG("Found serial console at ttyS%d\n", offset); |
392 | 393 | ||
393 | if (spd) { | 394 | if (spd) { |
394 | static char __initdata opt[16]; | 395 | static char __initdata opt[16]; |
395 | sprintf(opt, "%d", *spd); | 396 | sprintf(opt, "%d", *spd); |
396 | return add_preferred_console("ttyS", offset, opt); | 397 | return add_preferred_console("ttyS", offset, opt); |
397 | } else | 398 | } else |
398 | return add_preferred_console("ttyS", offset, NULL); | 399 | return add_preferred_console("ttyS", offset, NULL); |
399 | 400 | ||
400 | not_found: | 401 | not_found: |
401 | DBG("No preferred console found !\n"); | 402 | DBG("No preferred console found !\n"); |
402 | of_node_put(prom_stdout); | 403 | of_node_put(prom_stdout); |
403 | return -ENODEV; | 404 | return -ENODEV; |
404 | } | 405 | } |
405 | console_initcall(set_preferred_console); | 406 | console_initcall(set_preferred_console); |
406 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 407 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
407 | 408 | ||
408 | void __init check_for_initrd(void) | 409 | void __init check_for_initrd(void) |
409 | { | 410 | { |
410 | #ifdef CONFIG_BLK_DEV_INITRD | 411 | #ifdef CONFIG_BLK_DEV_INITRD |
411 | unsigned long *prop; | 412 | unsigned long *prop; |
412 | 413 | ||
413 | DBG(" -> check_for_initrd()\n"); | 414 | DBG(" -> check_for_initrd()\n"); |
414 | 415 | ||
415 | if (of_chosen) { | 416 | if (of_chosen) { |
416 | prop = (unsigned long *)get_property(of_chosen, | 417 | prop = (unsigned long *)get_property(of_chosen, |
417 | "linux,initrd-start", NULL); | 418 | "linux,initrd-start", NULL); |
418 | if (prop != NULL) { | 419 | if (prop != NULL) { |
419 | initrd_start = (unsigned long)__va(*prop); | 420 | initrd_start = (unsigned long)__va(*prop); |
420 | prop = (unsigned long *)get_property(of_chosen, | 421 | prop = (unsigned long *)get_property(of_chosen, |
421 | "linux,initrd-end", NULL); | 422 | "linux,initrd-end", NULL); |
422 | if (prop != NULL) { | 423 | if (prop != NULL) { |
423 | initrd_end = (unsigned long)__va(*prop); | 424 | initrd_end = (unsigned long)__va(*prop); |
424 | initrd_below_start_ok = 1; | 425 | initrd_below_start_ok = 1; |
425 | } else | 426 | } else |
426 | initrd_start = 0; | 427 | initrd_start = 0; |
427 | } | 428 | } |
428 | } | 429 | } |
429 | 430 | ||
430 | /* If we were passed an initrd, set the ROOT_DEV properly if the values | 431 | /* If we were passed an initrd, set the ROOT_DEV properly if the values |
431 | * look sensible. If not, clear initrd reference. | 432 | * look sensible. If not, clear initrd reference. |
432 | */ | 433 | */ |
433 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && | 434 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && |
434 | initrd_end > initrd_start) | 435 | initrd_end > initrd_start) |
435 | ROOT_DEV = Root_RAM0; | 436 | ROOT_DEV = Root_RAM0; |
436 | else { | 437 | else { |
437 | printk("Bogus initrd %08lx %08lx\n", initrd_start, initrd_end); | 438 | printk("Bogus initrd %08lx %08lx\n", initrd_start, initrd_end); |
438 | initrd_start = initrd_end = 0; | 439 | initrd_start = initrd_end = 0; |
439 | } | 440 | } |
440 | 441 | ||
441 | if (initrd_start) | 442 | if (initrd_start) |
442 | printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); | 443 | printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); |
443 | 444 | ||
444 | DBG(" <- check_for_initrd()\n"); | 445 | DBG(" <- check_for_initrd()\n"); |
445 | #endif /* CONFIG_BLK_DEV_INITRD */ | 446 | #endif /* CONFIG_BLK_DEV_INITRD */ |
446 | } | 447 | } |
447 | 448 | ||
448 | #ifdef CONFIG_SMP | 449 | #ifdef CONFIG_SMP |
449 | 450 | ||
450 | /** | 451 | /** |
451 | * setup_cpu_maps - initialize the following cpu maps: | 452 | * setup_cpu_maps - initialize the following cpu maps: |
452 | * cpu_possible_map | 453 | * cpu_possible_map |
453 | * cpu_present_map | 454 | * cpu_present_map |
454 | * cpu_sibling_map | 455 | * cpu_sibling_map |
455 | * | 456 | * |
456 | * Having the possible map set up early allows us to restrict allocations | 457 | * Having the possible map set up early allows us to restrict allocations |
457 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. | 458 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. |
458 | * | 459 | * |
459 | * We do not initialize the online map here; cpus set their own bits in | 460 | * We do not initialize the online map here; cpus set their own bits in |
460 | * cpu_online_map as they come up. | 461 | * cpu_online_map as they come up. |
461 | * | 462 | * |
462 | * This function is valid only for Open Firmware systems. finish_device_tree | 463 | * This function is valid only for Open Firmware systems. finish_device_tree |
463 | * must be called before using this. | 464 | * must be called before using this. |
464 | * | 465 | * |
465 | * While we're here, we may as well set the "physical" cpu ids in the paca. | 466 | * While we're here, we may as well set the "physical" cpu ids in the paca. |
466 | */ | 467 | */ |
467 | void __init smp_setup_cpu_maps(void) | 468 | void __init smp_setup_cpu_maps(void) |
468 | { | 469 | { |
469 | struct device_node *dn = NULL; | 470 | struct device_node *dn = NULL; |
470 | int cpu = 0; | 471 | int cpu = 0; |
471 | int swap_cpuid = 0; | 472 | int swap_cpuid = 0; |
472 | 473 | ||
473 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { | 474 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { |
474 | int *intserv; | 475 | int *intserv; |
475 | int j, len = sizeof(u32), nthreads = 1; | 476 | int j, len = sizeof(u32), nthreads = 1; |
476 | 477 | ||
477 | intserv = (int *)get_property(dn, "ibm,ppc-interrupt-server#s", | 478 | intserv = (int *)get_property(dn, "ibm,ppc-interrupt-server#s", |
478 | &len); | 479 | &len); |
479 | if (intserv) | 480 | if (intserv) |
480 | nthreads = len / sizeof(int); | 481 | nthreads = len / sizeof(int); |
481 | else { | 482 | else { |
482 | intserv = (int *) get_property(dn, "reg", NULL); | 483 | intserv = (int *) get_property(dn, "reg", NULL); |
483 | if (!intserv) | 484 | if (!intserv) |
484 | intserv = &cpu; /* assume logical == phys */ | 485 | intserv = &cpu; /* assume logical == phys */ |
485 | } | 486 | } |
486 | 487 | ||
487 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { | 488 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { |
488 | cpu_set(cpu, cpu_present_map); | 489 | cpu_set(cpu, cpu_present_map); |
489 | set_hard_smp_processor_id(cpu, intserv[j]); | 490 | set_hard_smp_processor_id(cpu, intserv[j]); |
490 | 491 | ||
491 | if (intserv[j] == boot_cpuid_phys) | 492 | if (intserv[j] == boot_cpuid_phys) |
492 | swap_cpuid = cpu; | 493 | swap_cpuid = cpu; |
493 | cpu_set(cpu, cpu_possible_map); | 494 | cpu_set(cpu, cpu_possible_map); |
494 | cpu++; | 495 | cpu++; |
495 | } | 496 | } |
496 | } | 497 | } |
497 | 498 | ||
498 | /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that | 499 | /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that |
499 | * boot cpu is logical 0. | 500 | * boot cpu is logical 0. |
500 | */ | 501 | */ |
501 | if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { | 502 | if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { |
502 | u32 tmp; | 503 | u32 tmp; |
503 | tmp = get_hard_smp_processor_id(0); | 504 | tmp = get_hard_smp_processor_id(0); |
504 | set_hard_smp_processor_id(0, boot_cpuid_phys); | 505 | set_hard_smp_processor_id(0, boot_cpuid_phys); |
505 | set_hard_smp_processor_id(swap_cpuid, tmp); | 506 | set_hard_smp_processor_id(swap_cpuid, tmp); |
506 | } | 507 | } |
507 | 508 | ||
508 | #ifdef CONFIG_PPC64 | 509 | #ifdef CONFIG_PPC64 |
509 | /* | 510 | /* |
510 | * On pSeries LPAR, we need to know how many cpus | 511 | * On pSeries LPAR, we need to know how many cpus |
511 | * could possibly be added to this partition. | 512 | * could possibly be added to this partition. |
512 | */ | 513 | */ |
513 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && | 514 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && |
514 | (dn = of_find_node_by_path("/rtas"))) { | 515 | (dn = of_find_node_by_path("/rtas"))) { |
515 | int num_addr_cell, num_size_cell, maxcpus; | 516 | int num_addr_cell, num_size_cell, maxcpus; |
516 | unsigned int *ireg; | 517 | unsigned int *ireg; |
517 | 518 | ||
518 | num_addr_cell = prom_n_addr_cells(dn); | 519 | num_addr_cell = prom_n_addr_cells(dn); |
519 | num_size_cell = prom_n_size_cells(dn); | 520 | num_size_cell = prom_n_size_cells(dn); |
520 | 521 | ||
521 | ireg = (unsigned int *) | 522 | ireg = (unsigned int *) |
522 | get_property(dn, "ibm,lrdr-capacity", NULL); | 523 | get_property(dn, "ibm,lrdr-capacity", NULL); |
523 | 524 | ||
524 | if (!ireg) | 525 | if (!ireg) |
525 | goto out; | 526 | goto out; |
526 | 527 | ||
527 | maxcpus = ireg[num_addr_cell + num_size_cell]; | 528 | maxcpus = ireg[num_addr_cell + num_size_cell]; |
528 | 529 | ||
529 | /* Double maxcpus for processors which have SMT capability */ | 530 | /* Double maxcpus for processors which have SMT capability */ |
530 | if (cpu_has_feature(CPU_FTR_SMT)) | 531 | if (cpu_has_feature(CPU_FTR_SMT)) |
531 | maxcpus *= 2; | 532 | maxcpus *= 2; |
532 | 533 | ||
533 | if (maxcpus > NR_CPUS) { | 534 | if (maxcpus > NR_CPUS) { |
534 | printk(KERN_WARNING | 535 | printk(KERN_WARNING |
535 | "Partition configured for %d cpus, " | 536 | "Partition configured for %d cpus, " |
536 | "operating system maximum is %d.\n", | 537 | "operating system maximum is %d.\n", |
537 | maxcpus, NR_CPUS); | 538 | maxcpus, NR_CPUS); |
538 | maxcpus = NR_CPUS; | 539 | maxcpus = NR_CPUS; |
539 | } else | 540 | } else |
540 | printk(KERN_INFO "Partition configured for %d cpus.\n", | 541 | printk(KERN_INFO "Partition configured for %d cpus.\n", |
541 | maxcpus); | 542 | maxcpus); |
542 | 543 | ||
543 | for (cpu = 0; cpu < maxcpus; cpu++) | 544 | for (cpu = 0; cpu < maxcpus; cpu++) |
544 | cpu_set(cpu, cpu_possible_map); | 545 | cpu_set(cpu, cpu_possible_map); |
545 | out: | 546 | out: |
546 | of_node_put(dn); | 547 | of_node_put(dn); |
547 | } | 548 | } |
548 | 549 | ||
549 | /* | 550 | /* |
550 | * Do the sibling map; assume only two threads per processor. | 551 | * Do the sibling map; assume only two threads per processor. |
551 | */ | 552 | */ |
552 | for_each_cpu(cpu) { | 553 | for_each_cpu(cpu) { |
553 | cpu_set(cpu, cpu_sibling_map[cpu]); | 554 | cpu_set(cpu, cpu_sibling_map[cpu]); |
554 | if (cpu_has_feature(CPU_FTR_SMT)) | 555 | if (cpu_has_feature(CPU_FTR_SMT)) |
555 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); | 556 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); |
556 | } | 557 | } |
557 | 558 | ||
558 | systemcfg->processorCount = num_present_cpus(); | 559 | systemcfg->processorCount = num_present_cpus(); |
559 | #endif /* CONFIG_PPC64 */ | 560 | #endif /* CONFIG_PPC64 */ |
560 | } | 561 | } |
561 | #endif /* CONFIG_SMP */ | 562 | #endif /* CONFIG_SMP */ |
563 | |||
564 | #ifdef CONFIG_XMON | ||
565 | static int __init early_xmon(char *p) | ||
566 | { | ||
567 | /* ensure xmon is enabled */ | ||
568 | if (p) { | ||
569 | if (strncmp(p, "on", 2) == 0) | ||
570 | xmon_init(1); | ||
571 | if (strncmp(p, "off", 3) == 0) | ||
572 | xmon_init(0); | ||
573 | if (strncmp(p, "early", 5) != 0) | ||
574 | return 0; | ||
575 | } | ||
576 | xmon_init(1); | ||
577 | debugger(NULL); | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | early_param("xmon", early_xmon); | ||
582 | #endif | ||
562 | 583 |
arch/powerpc/kernel/setup_32.c
1 | /* | 1 | /* |
2 | * Common prep/pmac/chrp boot and setup code. | 2 | * Common prep/pmac/chrp boot and setup code. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/config.h> | 5 | #include <linux/config.h> |
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
7 | #include <linux/string.h> | 7 | #include <linux/string.h> |
8 | #include <linux/sched.h> | 8 | #include <linux/sched.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
11 | #include <linux/reboot.h> | 11 | #include <linux/reboot.h> |
12 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
13 | #include <linux/initrd.h> | 13 | #include <linux/initrd.h> |
14 | #include <linux/ide.h> | 14 | #include <linux/ide.h> |
15 | #include <linux/tty.h> | 15 | #include <linux/tty.h> |
16 | #include <linux/bootmem.h> | 16 | #include <linux/bootmem.h> |
17 | #include <linux/seq_file.h> | 17 | #include <linux/seq_file.h> |
18 | #include <linux/root_dev.h> | 18 | #include <linux/root_dev.h> |
19 | #include <linux/cpu.h> | 19 | #include <linux/cpu.h> |
20 | #include <linux/console.h> | 20 | #include <linux/console.h> |
21 | 21 | ||
22 | #include <asm/residual.h> | 22 | #include <asm/residual.h> |
23 | #include <asm/io.h> | 23 | #include <asm/io.h> |
24 | #include <asm/prom.h> | 24 | #include <asm/prom.h> |
25 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
26 | #include <asm/pgtable.h> | 26 | #include <asm/pgtable.h> |
27 | #include <asm/setup.h> | 27 | #include <asm/setup.h> |
28 | #include <asm/amigappc.h> | 28 | #include <asm/amigappc.h> |
29 | #include <asm/smp.h> | 29 | #include <asm/smp.h> |
30 | #include <asm/elf.h> | 30 | #include <asm/elf.h> |
31 | #include <asm/cputable.h> | 31 | #include <asm/cputable.h> |
32 | #include <asm/bootx.h> | 32 | #include <asm/bootx.h> |
33 | #include <asm/btext.h> | 33 | #include <asm/btext.h> |
34 | #include <asm/machdep.h> | 34 | #include <asm/machdep.h> |
35 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
36 | #include <asm/system.h> | 36 | #include <asm/system.h> |
37 | #include <asm/pmac_feature.h> | 37 | #include <asm/pmac_feature.h> |
38 | #include <asm/sections.h> | 38 | #include <asm/sections.h> |
39 | #include <asm/nvram.h> | 39 | #include <asm/nvram.h> |
40 | #include <asm/xmon.h> | 40 | #include <asm/xmon.h> |
41 | #include <asm/time.h> | 41 | #include <asm/time.h> |
42 | 42 | ||
43 | #define DBG(fmt...) | 43 | #define DBG(fmt...) |
44 | 44 | ||
45 | #if defined CONFIG_KGDB | 45 | #if defined CONFIG_KGDB |
46 | #include <asm/kgdb.h> | 46 | #include <asm/kgdb.h> |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | extern void platform_init(void); | 49 | extern void platform_init(void); |
50 | extern void bootx_init(unsigned long r4, unsigned long phys); | 50 | extern void bootx_init(unsigned long r4, unsigned long phys); |
51 | 51 | ||
52 | extern void ppc6xx_idle(void); | 52 | extern void ppc6xx_idle(void); |
53 | extern void power4_idle(void); | 53 | extern void power4_idle(void); |
54 | 54 | ||
55 | boot_infos_t *boot_infos; | 55 | boot_infos_t *boot_infos; |
56 | struct ide_machdep_calls ppc_ide_md; | 56 | struct ide_machdep_calls ppc_ide_md; |
57 | 57 | ||
58 | /* XXX should go elsewhere */ | 58 | /* XXX should go elsewhere */ |
59 | int __irq_offset_value; | 59 | int __irq_offset_value; |
60 | EXPORT_SYMBOL(__irq_offset_value); | 60 | EXPORT_SYMBOL(__irq_offset_value); |
61 | 61 | ||
62 | int boot_cpuid; | 62 | int boot_cpuid; |
63 | EXPORT_SYMBOL_GPL(boot_cpuid); | 63 | EXPORT_SYMBOL_GPL(boot_cpuid); |
64 | int boot_cpuid_phys; | 64 | int boot_cpuid_phys; |
65 | 65 | ||
66 | unsigned long ISA_DMA_THRESHOLD; | 66 | unsigned long ISA_DMA_THRESHOLD; |
67 | unsigned int DMA_MODE_READ; | 67 | unsigned int DMA_MODE_READ; |
68 | unsigned int DMA_MODE_WRITE; | 68 | unsigned int DMA_MODE_WRITE; |
69 | 69 | ||
70 | int have_of = 1; | 70 | int have_of = 1; |
71 | 71 | ||
72 | #ifdef CONFIG_PPC_MULTIPLATFORM | 72 | #ifdef CONFIG_PPC_MULTIPLATFORM |
73 | int _machine = 0; | 73 | int _machine = 0; |
74 | 74 | ||
75 | extern void prep_init(void); | 75 | extern void prep_init(void); |
76 | extern void pmac_init(void); | 76 | extern void pmac_init(void); |
77 | extern void chrp_init(void); | 77 | extern void chrp_init(void); |
78 | 78 | ||
79 | dev_t boot_dev; | 79 | dev_t boot_dev; |
80 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 80 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
81 | 81 | ||
82 | #ifdef CONFIG_MAGIC_SYSRQ | 82 | #ifdef CONFIG_MAGIC_SYSRQ |
83 | unsigned long SYSRQ_KEY = 0x54; | 83 | unsigned long SYSRQ_KEY = 0x54; |
84 | #endif /* CONFIG_MAGIC_SYSRQ */ | 84 | #endif /* CONFIG_MAGIC_SYSRQ */ |
85 | 85 | ||
86 | #ifdef CONFIG_VGA_CONSOLE | 86 | #ifdef CONFIG_VGA_CONSOLE |
87 | unsigned long vgacon_remap_base; | 87 | unsigned long vgacon_remap_base; |
88 | #endif | 88 | #endif |
89 | 89 | ||
90 | struct machdep_calls ppc_md; | 90 | struct machdep_calls ppc_md; |
91 | EXPORT_SYMBOL(ppc_md); | 91 | EXPORT_SYMBOL(ppc_md); |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * These are used in binfmt_elf.c to put aux entries on the stack | 94 | * These are used in binfmt_elf.c to put aux entries on the stack |
95 | * for each elf executable being started. | 95 | * for each elf executable being started. |
96 | */ | 96 | */ |
97 | int dcache_bsize; | 97 | int dcache_bsize; |
98 | int icache_bsize; | 98 | int icache_bsize; |
99 | int ucache_bsize; | 99 | int ucache_bsize; |
100 | 100 | ||
101 | /* | 101 | /* |
102 | * We're called here very early in the boot. We determine the machine | 102 | * We're called here very early in the boot. We determine the machine |
103 | * type and call the appropriate low-level setup functions. | 103 | * type and call the appropriate low-level setup functions. |
104 | * -- Cort <cort@fsmlabs.com> | 104 | * -- Cort <cort@fsmlabs.com> |
105 | * | 105 | * |
106 | * Note that the kernel may be running at an address which is different | 106 | * Note that the kernel may be running at an address which is different |
107 | * from the address that it was linked at, so we must use RELOC/PTRRELOC | 107 | * from the address that it was linked at, so we must use RELOC/PTRRELOC |
108 | * to access static data (including strings). -- paulus | 108 | * to access static data (including strings). -- paulus |
109 | */ | 109 | */ |
110 | unsigned long __init early_init(unsigned long dt_ptr) | 110 | unsigned long __init early_init(unsigned long dt_ptr) |
111 | { | 111 | { |
112 | unsigned long offset = reloc_offset(); | 112 | unsigned long offset = reloc_offset(); |
113 | 113 | ||
114 | /* First zero the BSS -- use memset_io, some platforms don't have | 114 | /* First zero the BSS -- use memset_io, some platforms don't have |
115 | * caches on yet */ | 115 | * caches on yet */ |
116 | memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start); | 116 | memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start); |
117 | 117 | ||
118 | /* | 118 | /* |
119 | * Identify the CPU type and fix up code sections | 119 | * Identify the CPU type and fix up code sections |
120 | * that depend on which cpu we have. | 120 | * that depend on which cpu we have. |
121 | */ | 121 | */ |
122 | identify_cpu(offset, 0); | 122 | identify_cpu(offset, 0); |
123 | do_cpu_ftr_fixups(offset); | 123 | do_cpu_ftr_fixups(offset); |
124 | 124 | ||
125 | return KERNELBASE + offset; | 125 | return KERNELBASE + offset; |
126 | } | 126 | } |
127 | 127 | ||
128 | #ifdef CONFIG_PPC_MULTIPLATFORM | 128 | #ifdef CONFIG_PPC_MULTIPLATFORM |
129 | /* | 129 | /* |
130 | * The PPC_MULTIPLATFORM version of platform_init... | 130 | * The PPC_MULTIPLATFORM version of platform_init... |
131 | */ | 131 | */ |
132 | void __init platform_init(void) | 132 | void __init platform_init(void) |
133 | { | 133 | { |
134 | /* if we didn't get any bootinfo telling us what we are... */ | 134 | /* if we didn't get any bootinfo telling us what we are... */ |
135 | if (_machine == 0) { | 135 | if (_machine == 0) { |
136 | /* prep boot loader tells us if we're prep or not */ | 136 | /* prep boot loader tells us if we're prep or not */ |
137 | if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) | 137 | if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) |
138 | _machine = _MACH_prep; | 138 | _machine = _MACH_prep; |
139 | } | 139 | } |
140 | 140 | ||
141 | #ifdef CONFIG_PPC_PREP | 141 | #ifdef CONFIG_PPC_PREP |
142 | /* not much more to do here, if prep */ | 142 | /* not much more to do here, if prep */ |
143 | if (_machine == _MACH_prep) { | 143 | if (_machine == _MACH_prep) { |
144 | prep_init(); | 144 | prep_init(); |
145 | return; | 145 | return; |
146 | } | 146 | } |
147 | #endif | 147 | #endif |
148 | 148 | ||
149 | #ifdef CONFIG_ADB | 149 | #ifdef CONFIG_ADB |
150 | if (strstr(cmd_line, "adb_sync")) { | 150 | if (strstr(cmd_line, "adb_sync")) { |
151 | extern int __adb_probe_sync; | 151 | extern int __adb_probe_sync; |
152 | __adb_probe_sync = 1; | 152 | __adb_probe_sync = 1; |
153 | } | 153 | } |
154 | #endif /* CONFIG_ADB */ | 154 | #endif /* CONFIG_ADB */ |
155 | 155 | ||
156 | switch (_machine) { | 156 | switch (_machine) { |
157 | #ifdef CONFIG_PPC_PMAC | 157 | #ifdef CONFIG_PPC_PMAC |
158 | case _MACH_Pmac: | 158 | case _MACH_Pmac: |
159 | pmac_init(); | 159 | pmac_init(); |
160 | break; | 160 | break; |
161 | #endif | 161 | #endif |
162 | #ifdef CONFIG_PPC_CHRP | 162 | #ifdef CONFIG_PPC_CHRP |
163 | case _MACH_chrp: | 163 | case _MACH_chrp: |
164 | chrp_init(); | 164 | chrp_init(); |
165 | break; | 165 | break; |
166 | #endif | 166 | #endif |
167 | } | 167 | } |
168 | } | 168 | } |
169 | #endif | 169 | #endif |
170 | 170 | ||
171 | /* | 171 | /* |
172 | * Find out what kind of machine we're on and save any data we need | 172 | * Find out what kind of machine we're on and save any data we need |
173 | * from the early boot process (devtree is copied on pmac by prom_init()). | 173 | * from the early boot process (devtree is copied on pmac by prom_init()). |
174 | * This is called very early on the boot process, after a minimal | 174 | * This is called very early on the boot process, after a minimal |
175 | * MMU environment has been set up but before MMU_init is called. | 175 | * MMU environment has been set up but before MMU_init is called. |
176 | */ | 176 | */ |
177 | void __init machine_init(unsigned long dt_ptr, unsigned long phys) | 177 | void __init machine_init(unsigned long dt_ptr, unsigned long phys) |
178 | { | 178 | { |
179 | early_init_devtree(__va(dt_ptr)); | 179 | early_init_devtree(__va(dt_ptr)); |
180 | 180 | ||
181 | #ifdef CONFIG_CMDLINE | 181 | #ifdef CONFIG_CMDLINE |
182 | strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); | 182 | strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); |
183 | #endif /* CONFIG_CMDLINE */ | 183 | #endif /* CONFIG_CMDLINE */ |
184 | 184 | ||
185 | platform_init(); | 185 | platform_init(); |
186 | 186 | ||
187 | #ifdef CONFIG_6xx | 187 | #ifdef CONFIG_6xx |
188 | ppc_md.power_save = ppc6xx_idle; | 188 | ppc_md.power_save = ppc6xx_idle; |
189 | #endif | 189 | #endif |
190 | 190 | ||
191 | if (ppc_md.progress) | 191 | if (ppc_md.progress) |
192 | ppc_md.progress("id mach(): done", 0x200); | 192 | ppc_md.progress("id mach(): done", 0x200); |
193 | } | 193 | } |
194 | 194 | ||
195 | #ifdef CONFIG_BOOKE_WDT | 195 | #ifdef CONFIG_BOOKE_WDT |
196 | /* Checks wdt=x and wdt_period=xx command-line option */ | 196 | /* Checks wdt=x and wdt_period=xx command-line option */ |
197 | int __init early_parse_wdt(char *p) | 197 | int __init early_parse_wdt(char *p) |
198 | { | 198 | { |
199 | if (p && strncmp(p, "0", 1) != 0) | 199 | if (p && strncmp(p, "0", 1) != 0) |
200 | booke_wdt_enabled = 1; | 200 | booke_wdt_enabled = 1; |
201 | 201 | ||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | early_param("wdt", early_parse_wdt); | 204 | early_param("wdt", early_parse_wdt); |
205 | 205 | ||
206 | int __init early_parse_wdt_period (char *p) | 206 | int __init early_parse_wdt_period (char *p) |
207 | { | 207 | { |
208 | if (p) | 208 | if (p) |
209 | booke_wdt_period = simple_strtoul(p, NULL, 0); | 209 | booke_wdt_period = simple_strtoul(p, NULL, 0); |
210 | 210 | ||
211 | return 0; | 211 | return 0; |
212 | } | 212 | } |
213 | early_param("wdt_period", early_parse_wdt_period); | 213 | early_param("wdt_period", early_parse_wdt_period); |
214 | #endif /* CONFIG_BOOKE_WDT */ | 214 | #endif /* CONFIG_BOOKE_WDT */ |
215 | 215 | ||
216 | /* Checks "l2cr=xxxx" command-line option */ | 216 | /* Checks "l2cr=xxxx" command-line option */ |
217 | int __init ppc_setup_l2cr(char *str) | 217 | int __init ppc_setup_l2cr(char *str) |
218 | { | 218 | { |
219 | if (cpu_has_feature(CPU_FTR_L2CR)) { | 219 | if (cpu_has_feature(CPU_FTR_L2CR)) { |
220 | unsigned long val = simple_strtoul(str, NULL, 0); | 220 | unsigned long val = simple_strtoul(str, NULL, 0); |
221 | printk(KERN_INFO "l2cr set to %lx\n", val); | 221 | printk(KERN_INFO "l2cr set to %lx\n", val); |
222 | _set_L2CR(0); /* force invalidate by disable cache */ | 222 | _set_L2CR(0); /* force invalidate by disable cache */ |
223 | _set_L2CR(val); /* and enable it */ | 223 | _set_L2CR(val); /* and enable it */ |
224 | } | 224 | } |
225 | return 1; | 225 | return 1; |
226 | } | 226 | } |
227 | __setup("l2cr=", ppc_setup_l2cr); | 227 | __setup("l2cr=", ppc_setup_l2cr); |
228 | 228 | ||
229 | #ifdef CONFIG_GENERIC_NVRAM | 229 | #ifdef CONFIG_GENERIC_NVRAM |
230 | 230 | ||
231 | /* Generic nvram hooks used by drivers/char/gen_nvram.c */ | 231 | /* Generic nvram hooks used by drivers/char/gen_nvram.c */ |
232 | unsigned char nvram_read_byte(int addr) | 232 | unsigned char nvram_read_byte(int addr) |
233 | { | 233 | { |
234 | if (ppc_md.nvram_read_val) | 234 | if (ppc_md.nvram_read_val) |
235 | return ppc_md.nvram_read_val(addr); | 235 | return ppc_md.nvram_read_val(addr); |
236 | return 0xff; | 236 | return 0xff; |
237 | } | 237 | } |
238 | EXPORT_SYMBOL(nvram_read_byte); | 238 | EXPORT_SYMBOL(nvram_read_byte); |
239 | 239 | ||
240 | void nvram_write_byte(unsigned char val, int addr) | 240 | void nvram_write_byte(unsigned char val, int addr) |
241 | { | 241 | { |
242 | if (ppc_md.nvram_write_val) | 242 | if (ppc_md.nvram_write_val) |
243 | ppc_md.nvram_write_val(addr, val); | 243 | ppc_md.nvram_write_val(addr, val); |
244 | } | 244 | } |
245 | EXPORT_SYMBOL(nvram_write_byte); | 245 | EXPORT_SYMBOL(nvram_write_byte); |
246 | 246 | ||
247 | void nvram_sync(void) | 247 | void nvram_sync(void) |
248 | { | 248 | { |
249 | if (ppc_md.nvram_sync) | 249 | if (ppc_md.nvram_sync) |
250 | ppc_md.nvram_sync(); | 250 | ppc_md.nvram_sync(); |
251 | } | 251 | } |
252 | EXPORT_SYMBOL(nvram_sync); | 252 | EXPORT_SYMBOL(nvram_sync); |
253 | 253 | ||
254 | #endif /* CONFIG_NVRAM */ | 254 | #endif /* CONFIG_NVRAM */ |
255 | 255 | ||
256 | static struct cpu cpu_devices[NR_CPUS]; | 256 | static struct cpu cpu_devices[NR_CPUS]; |
257 | 257 | ||
258 | int __init ppc_init(void) | 258 | int __init ppc_init(void) |
259 | { | 259 | { |
260 | int i; | 260 | int i; |
261 | 261 | ||
262 | /* clear the progress line */ | 262 | /* clear the progress line */ |
263 | if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); | 263 | if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); |
264 | 264 | ||
265 | /* register CPU devices */ | 265 | /* register CPU devices */ |
266 | for (i = 0; i < NR_CPUS; i++) | 266 | for (i = 0; i < NR_CPUS; i++) |
267 | if (cpu_possible(i)) | 267 | if (cpu_possible(i)) |
268 | register_cpu(&cpu_devices[i], i, NULL); | 268 | register_cpu(&cpu_devices[i], i, NULL); |
269 | 269 | ||
270 | /* call platform init */ | 270 | /* call platform init */ |
271 | if (ppc_md.init != NULL) { | 271 | if (ppc_md.init != NULL) { |
272 | ppc_md.init(); | 272 | ppc_md.init(); |
273 | } | 273 | } |
274 | return 0; | 274 | return 0; |
275 | } | 275 | } |
276 | 276 | ||
277 | arch_initcall(ppc_init); | 277 | arch_initcall(ppc_init); |
278 | 278 | ||
279 | /* Warning, IO base is not yet inited */ | 279 | /* Warning, IO base is not yet inited */ |
280 | void __init setup_arch(char **cmdline_p) | 280 | void __init setup_arch(char **cmdline_p) |
281 | { | 281 | { |
282 | extern char *klimit; | 282 | extern char *klimit; |
283 | extern void do_init_bootmem(void); | 283 | extern void do_init_bootmem(void); |
284 | 284 | ||
285 | /* so udelay does something sensible, assume <= 1000 bogomips */ | 285 | /* so udelay does something sensible, assume <= 1000 bogomips */ |
286 | loops_per_jiffy = 500000000 / HZ; | 286 | loops_per_jiffy = 500000000 / HZ; |
287 | 287 | ||
288 | unflatten_device_tree(); | 288 | unflatten_device_tree(); |
289 | check_for_initrd(); | 289 | check_for_initrd(); |
290 | finish_device_tree(); | 290 | finish_device_tree(); |
291 | 291 | ||
292 | smp_setup_cpu_maps(); | 292 | smp_setup_cpu_maps(); |
293 | 293 | ||
294 | #ifdef CONFIG_BOOTX_TEXT | 294 | #ifdef CONFIG_BOOTX_TEXT |
295 | init_boot_display(); | 295 | init_boot_display(); |
296 | #endif | 296 | #endif |
297 | 297 | ||
298 | #ifdef CONFIG_PPC_PMAC | 298 | #ifdef CONFIG_PPC_PMAC |
299 | /* This could be called "early setup arch", it must be done | 299 | /* This could be called "early setup arch", it must be done |
300 | * now because xmon need it | 300 | * now because xmon need it |
301 | */ | 301 | */ |
302 | if (_machine == _MACH_Pmac) | 302 | if (_machine == _MACH_Pmac) |
303 | pmac_feature_init(); /* New cool way */ | 303 | pmac_feature_init(); /* New cool way */ |
304 | #endif | 304 | #endif |
305 | 305 | ||
306 | #ifdef CONFIG_XMON | 306 | #ifdef CONFIG_XMON_DEFAULT |
307 | xmon_map_scc(); | 307 | xmon_init(1); |
308 | if (strstr(cmd_line, "xmon")) { | 308 | #endif |
309 | xmon_init(1); | ||
310 | debugger(NULL); | ||
311 | } | ||
312 | #endif /* CONFIG_XMON */ | ||
313 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); | ||
314 | 309 | ||
315 | #if defined(CONFIG_KGDB) | 310 | #if defined(CONFIG_KGDB) |
316 | if (ppc_md.kgdb_map_scc) | 311 | if (ppc_md.kgdb_map_scc) |
317 | ppc_md.kgdb_map_scc(); | 312 | ppc_md.kgdb_map_scc(); |
318 | set_debug_traps(); | 313 | set_debug_traps(); |
319 | if (strstr(cmd_line, "gdb")) { | 314 | if (strstr(cmd_line, "gdb")) { |
320 | if (ppc_md.progress) | 315 | if (ppc_md.progress) |
321 | ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); | 316 | ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); |
322 | printk("kgdb breakpoint activated\n"); | 317 | printk("kgdb breakpoint activated\n"); |
323 | breakpoint(); | 318 | breakpoint(); |
324 | } | 319 | } |
325 | #endif | 320 | #endif |
326 | 321 | ||
327 | /* | 322 | /* |
328 | * Set cache line size based on type of cpu as a default. | 323 | * Set cache line size based on type of cpu as a default. |
329 | * Systems with OF can look in the properties on the cpu node(s) | 324 | * Systems with OF can look in the properties on the cpu node(s) |
330 | * for a possibly more accurate value. | 325 | * for a possibly more accurate value. |
331 | */ | 326 | */ |
332 | if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) { | 327 | if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) { |
333 | dcache_bsize = cur_cpu_spec->dcache_bsize; | 328 | dcache_bsize = cur_cpu_spec->dcache_bsize; |
334 | icache_bsize = cur_cpu_spec->icache_bsize; | 329 | icache_bsize = cur_cpu_spec->icache_bsize; |
335 | ucache_bsize = 0; | 330 | ucache_bsize = 0; |
336 | } else | 331 | } else |
337 | ucache_bsize = dcache_bsize = icache_bsize | 332 | ucache_bsize = dcache_bsize = icache_bsize |
338 | = cur_cpu_spec->dcache_bsize; | 333 | = cur_cpu_spec->dcache_bsize; |
339 | 334 | ||
340 | /* reboot on panic */ | 335 | /* reboot on panic */ |
341 | panic_timeout = 180; | 336 | panic_timeout = 180; |
342 | 337 | ||
343 | init_mm.start_code = PAGE_OFFSET; | 338 | init_mm.start_code = PAGE_OFFSET; |
344 | init_mm.end_code = (unsigned long) _etext; | 339 | init_mm.end_code = (unsigned long) _etext; |
345 | init_mm.end_data = (unsigned long) _edata; | 340 | init_mm.end_data = (unsigned long) _edata; |
346 | init_mm.brk = (unsigned long) klimit; | 341 | init_mm.brk = (unsigned long) klimit; |
347 | 342 | ||
348 | /* Save unparsed command line copy for /proc/cmdline */ | 343 | /* Save unparsed command line copy for /proc/cmdline */ |
349 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | 344 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); |
350 | *cmdline_p = cmd_line; | 345 | *cmdline_p = cmd_line; |
351 | 346 | ||
352 | parse_early_param(); | 347 | parse_early_param(); |
353 | 348 | ||
354 | /* set up the bootmem stuff with available memory */ | 349 | /* set up the bootmem stuff with available memory */ |
355 | do_init_bootmem(); | 350 | do_init_bootmem(); |
356 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); | 351 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); |
357 | 352 | ||
358 | #ifdef CONFIG_PPC_OCP | 353 | #ifdef CONFIG_PPC_OCP |
359 | /* Initialize OCP device list */ | 354 | /* Initialize OCP device list */ |
360 | ocp_early_init(); | 355 | ocp_early_init(); |
361 | if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab); | 356 | if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab); |
362 | #endif | 357 | #endif |
363 | 358 | ||
364 | #ifdef CONFIG_DUMMY_CONSOLE | 359 | #ifdef CONFIG_DUMMY_CONSOLE |
365 | conswitchp = &dummy_con; | 360 | conswitchp = &dummy_con; |
366 | #endif | 361 | #endif |
367 | 362 | ||
368 | ppc_md.setup_arch(); | 363 | ppc_md.setup_arch(); |
369 | if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); | 364 | if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); |
370 | 365 | ||
371 | paging_init(); | 366 | paging_init(); |
372 | 367 | ||
373 | /* this is for modules since _machine can be a define -- Cort */ | 368 | /* this is for modules since _machine can be a define -- Cort */ |
374 | ppc_md.ppc_machine = _machine; | 369 | ppc_md.ppc_machine = _machine; |
375 | } | 370 | } |
376 | 371 |
arch/powerpc/kernel/setup_64.c
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * Common boot and setup code. | 3 | * Common boot and setup code. |
4 | * | 4 | * |
5 | * Copyright (C) 2001 PPC64 Team, IBM Corp | 5 | * Copyright (C) 2001 PPC64 Team, IBM Corp |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version | 9 | * as published by the Free Software Foundation; either version |
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #undef DEBUG | 13 | #undef DEBUG |
14 | 14 | ||
15 | #include <linux/config.h> | 15 | #include <linux/config.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/string.h> | 17 | #include <linux/string.h> |
18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/reboot.h> | 21 | #include <linux/reboot.h> |
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/initrd.h> | 23 | #include <linux/initrd.h> |
24 | #include <linux/ide.h> | 24 | #include <linux/ide.h> |
25 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
26 | #include <linux/ioport.h> | 26 | #include <linux/ioport.h> |
27 | #include <linux/console.h> | 27 | #include <linux/console.h> |
28 | #include <linux/utsname.h> | 28 | #include <linux/utsname.h> |
29 | #include <linux/tty.h> | 29 | #include <linux/tty.h> |
30 | #include <linux/root_dev.h> | 30 | #include <linux/root_dev.h> |
31 | #include <linux/notifier.h> | 31 | #include <linux/notifier.h> |
32 | #include <linux/cpu.h> | 32 | #include <linux/cpu.h> |
33 | #include <linux/unistd.h> | 33 | #include <linux/unistd.h> |
34 | #include <linux/serial.h> | 34 | #include <linux/serial.h> |
35 | #include <linux/serial_8250.h> | 35 | #include <linux/serial_8250.h> |
36 | #include <asm/io.h> | 36 | #include <asm/io.h> |
37 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
38 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
39 | #include <asm/pgtable.h> | 39 | #include <asm/pgtable.h> |
40 | #include <asm/smp.h> | 40 | #include <asm/smp.h> |
41 | #include <asm/elf.h> | 41 | #include <asm/elf.h> |
42 | #include <asm/machdep.h> | 42 | #include <asm/machdep.h> |
43 | #include <asm/paca.h> | 43 | #include <asm/paca.h> |
44 | #include <asm/time.h> | 44 | #include <asm/time.h> |
45 | #include <asm/cputable.h> | 45 | #include <asm/cputable.h> |
46 | #include <asm/sections.h> | 46 | #include <asm/sections.h> |
47 | #include <asm/btext.h> | 47 | #include <asm/btext.h> |
48 | #include <asm/nvram.h> | 48 | #include <asm/nvram.h> |
49 | #include <asm/setup.h> | 49 | #include <asm/setup.h> |
50 | #include <asm/system.h> | 50 | #include <asm/system.h> |
51 | #include <asm/rtas.h> | 51 | #include <asm/rtas.h> |
52 | #include <asm/iommu.h> | 52 | #include <asm/iommu.h> |
53 | #include <asm/serial.h> | 53 | #include <asm/serial.h> |
54 | #include <asm/cache.h> | 54 | #include <asm/cache.h> |
55 | #include <asm/page.h> | 55 | #include <asm/page.h> |
56 | #include <asm/mmu.h> | 56 | #include <asm/mmu.h> |
57 | #include <asm/lmb.h> | 57 | #include <asm/lmb.h> |
58 | #include <asm/iseries/it_lp_naca.h> | 58 | #include <asm/iseries/it_lp_naca.h> |
59 | #include <asm/firmware.h> | 59 | #include <asm/firmware.h> |
60 | #include <asm/systemcfg.h> | 60 | #include <asm/systemcfg.h> |
61 | #include <asm/xmon.h> | 61 | #include <asm/xmon.h> |
62 | #include <asm/udbg.h> | 62 | #include <asm/udbg.h> |
63 | 63 | ||
64 | #ifdef DEBUG | 64 | #ifdef DEBUG |
65 | #define DBG(fmt...) udbg_printf(fmt) | 65 | #define DBG(fmt...) udbg_printf(fmt) |
66 | #else | 66 | #else |
67 | #define DBG(fmt...) | 67 | #define DBG(fmt...) |
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Here are some early debugging facilities. You can enable one | 71 | * Here are some early debugging facilities. You can enable one |
72 | * but your kernel will not boot on anything else if you do so | 72 | * but your kernel will not boot on anything else if you do so |
73 | */ | 73 | */ |
74 | 74 | ||
75 | /* This one is for use on LPAR machines that support an HVC console | 75 | /* This one is for use on LPAR machines that support an HVC console |
76 | * on vterm 0 | 76 | * on vterm 0 |
77 | */ | 77 | */ |
78 | extern void udbg_init_debug_lpar(void); | 78 | extern void udbg_init_debug_lpar(void); |
79 | /* This one is for use on Apple G5 machines | 79 | /* This one is for use on Apple G5 machines |
80 | */ | 80 | */ |
81 | extern void udbg_init_pmac_realmode(void); | 81 | extern void udbg_init_pmac_realmode(void); |
82 | /* That's RTAS panel debug */ | 82 | /* That's RTAS panel debug */ |
83 | extern void call_rtas_display_status_delay(unsigned char c); | 83 | extern void call_rtas_display_status_delay(unsigned char c); |
84 | /* Here's maple real mode debug */ | 84 | /* Here's maple real mode debug */ |
85 | extern void udbg_init_maple_realmode(void); | 85 | extern void udbg_init_maple_realmode(void); |
86 | 86 | ||
87 | #define EARLY_DEBUG_INIT() do {} while(0) | 87 | #define EARLY_DEBUG_INIT() do {} while(0) |
88 | 88 | ||
89 | #if 0 | 89 | #if 0 |
90 | #define EARLY_DEBUG_INIT() udbg_init_debug_lpar() | 90 | #define EARLY_DEBUG_INIT() udbg_init_debug_lpar() |
91 | #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() | 91 | #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() |
92 | #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() | 92 | #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() |
93 | #define EARLY_DEBUG_INIT() \ | 93 | #define EARLY_DEBUG_INIT() \ |
94 | do { udbg_putc = call_rtas_display_status_delay; } while(0) | 94 | do { udbg_putc = call_rtas_display_status_delay; } while(0) |
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | /* extern void *stab; */ | 97 | /* extern void *stab; */ |
98 | extern unsigned long klimit; | 98 | extern unsigned long klimit; |
99 | 99 | ||
100 | extern void mm_init_ppc64(void); | 100 | extern void mm_init_ppc64(void); |
101 | extern void stab_initialize(unsigned long stab); | 101 | extern void stab_initialize(unsigned long stab); |
102 | extern void htab_initialize(void); | 102 | extern void htab_initialize(void); |
103 | extern void early_init_devtree(void *flat_dt); | 103 | extern void early_init_devtree(void *flat_dt); |
104 | extern void unflatten_device_tree(void); | 104 | extern void unflatten_device_tree(void); |
105 | 105 | ||
106 | int have_of = 1; | 106 | int have_of = 1; |
107 | int boot_cpuid = 0; | 107 | int boot_cpuid = 0; |
108 | int boot_cpuid_phys = 0; | 108 | int boot_cpuid_phys = 0; |
109 | dev_t boot_dev; | 109 | dev_t boot_dev; |
110 | u64 ppc64_pft_size; | 110 | u64 ppc64_pft_size; |
111 | 111 | ||
112 | struct ppc64_caches ppc64_caches; | 112 | struct ppc64_caches ppc64_caches; |
113 | EXPORT_SYMBOL_GPL(ppc64_caches); | 113 | EXPORT_SYMBOL_GPL(ppc64_caches); |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * These are used in binfmt_elf.c to put aux entries on the stack | 116 | * These are used in binfmt_elf.c to put aux entries on the stack |
117 | * for each elf executable being started. | 117 | * for each elf executable being started. |
118 | */ | 118 | */ |
119 | int dcache_bsize; | 119 | int dcache_bsize; |
120 | int icache_bsize; | 120 | int icache_bsize; |
121 | int ucache_bsize; | 121 | int ucache_bsize; |
122 | 122 | ||
123 | /* The main machine-dep calls structure | 123 | /* The main machine-dep calls structure |
124 | */ | 124 | */ |
125 | struct machdep_calls ppc_md; | 125 | struct machdep_calls ppc_md; |
126 | EXPORT_SYMBOL(ppc_md); | 126 | EXPORT_SYMBOL(ppc_md); |
127 | 127 | ||
128 | #ifdef CONFIG_MAGIC_SYSRQ | 128 | #ifdef CONFIG_MAGIC_SYSRQ |
129 | unsigned long SYSRQ_KEY; | 129 | unsigned long SYSRQ_KEY; |
130 | #endif /* CONFIG_MAGIC_SYSRQ */ | 130 | #endif /* CONFIG_MAGIC_SYSRQ */ |
131 | 131 | ||
132 | 132 | ||
133 | static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); | 133 | static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); |
134 | static struct notifier_block ppc64_panic_block = { | 134 | static struct notifier_block ppc64_panic_block = { |
135 | .notifier_call = ppc64_panic_event, | 135 | .notifier_call = ppc64_panic_event, |
136 | .priority = INT_MIN /* may not return; must be done last */ | 136 | .priority = INT_MIN /* may not return; must be done last */ |
137 | }; | 137 | }; |
138 | 138 | ||
139 | #ifdef CONFIG_SMP | 139 | #ifdef CONFIG_SMP |
140 | 140 | ||
141 | static int smt_enabled_cmdline; | 141 | static int smt_enabled_cmdline; |
142 | 142 | ||
143 | /* Look for ibm,smt-enabled OF option */ | 143 | /* Look for ibm,smt-enabled OF option */ |
144 | static void check_smt_enabled(void) | 144 | static void check_smt_enabled(void) |
145 | { | 145 | { |
146 | struct device_node *dn; | 146 | struct device_node *dn; |
147 | char *smt_option; | 147 | char *smt_option; |
148 | 148 | ||
149 | /* Allow the command line to overrule the OF option */ | 149 | /* Allow the command line to overrule the OF option */ |
150 | if (smt_enabled_cmdline) | 150 | if (smt_enabled_cmdline) |
151 | return; | 151 | return; |
152 | 152 | ||
153 | dn = of_find_node_by_path("/options"); | 153 | dn = of_find_node_by_path("/options"); |
154 | 154 | ||
155 | if (dn) { | 155 | if (dn) { |
156 | smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); | 156 | smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); |
157 | 157 | ||
158 | if (smt_option) { | 158 | if (smt_option) { |
159 | if (!strcmp(smt_option, "on")) | 159 | if (!strcmp(smt_option, "on")) |
160 | smt_enabled_at_boot = 1; | 160 | smt_enabled_at_boot = 1; |
161 | else if (!strcmp(smt_option, "off")) | 161 | else if (!strcmp(smt_option, "off")) |
162 | smt_enabled_at_boot = 0; | 162 | smt_enabled_at_boot = 0; |
163 | } | 163 | } |
164 | } | 164 | } |
165 | } | 165 | } |
166 | 166 | ||
167 | /* Look for smt-enabled= cmdline option */ | 167 | /* Look for smt-enabled= cmdline option */ |
168 | static int __init early_smt_enabled(char *p) | 168 | static int __init early_smt_enabled(char *p) |
169 | { | 169 | { |
170 | smt_enabled_cmdline = 1; | 170 | smt_enabled_cmdline = 1; |
171 | 171 | ||
172 | if (!p) | 172 | if (!p) |
173 | return 0; | 173 | return 0; |
174 | 174 | ||
175 | if (!strcmp(p, "on") || !strcmp(p, "1")) | 175 | if (!strcmp(p, "on") || !strcmp(p, "1")) |
176 | smt_enabled_at_boot = 1; | 176 | smt_enabled_at_boot = 1; |
177 | else if (!strcmp(p, "off") || !strcmp(p, "0")) | 177 | else if (!strcmp(p, "off") || !strcmp(p, "0")) |
178 | smt_enabled_at_boot = 0; | 178 | smt_enabled_at_boot = 0; |
179 | 179 | ||
180 | return 0; | 180 | return 0; |
181 | } | 181 | } |
182 | early_param("smt-enabled", early_smt_enabled); | 182 | early_param("smt-enabled", early_smt_enabled); |
183 | 183 | ||
184 | #else | 184 | #else |
185 | #define check_smt_enabled() | 185 | #define check_smt_enabled() |
186 | #endif /* CONFIG_SMP */ | 186 | #endif /* CONFIG_SMP */ |
187 | 187 | ||
188 | extern struct machdep_calls pSeries_md; | 188 | extern struct machdep_calls pSeries_md; |
189 | extern struct machdep_calls pmac_md; | 189 | extern struct machdep_calls pmac_md; |
190 | extern struct machdep_calls maple_md; | 190 | extern struct machdep_calls maple_md; |
191 | extern struct machdep_calls cell_md; | 191 | extern struct machdep_calls cell_md; |
192 | extern struct machdep_calls iseries_md; | 192 | extern struct machdep_calls iseries_md; |
193 | 193 | ||
194 | /* Ultimately, stuff them in an elf section like initcalls... */ | 194 | /* Ultimately, stuff them in an elf section like initcalls... */ |
195 | static struct machdep_calls __initdata *machines[] = { | 195 | static struct machdep_calls __initdata *machines[] = { |
196 | #ifdef CONFIG_PPC_PSERIES | 196 | #ifdef CONFIG_PPC_PSERIES |
197 | &pSeries_md, | 197 | &pSeries_md, |
198 | #endif /* CONFIG_PPC_PSERIES */ | 198 | #endif /* CONFIG_PPC_PSERIES */ |
199 | #ifdef CONFIG_PPC_PMAC | 199 | #ifdef CONFIG_PPC_PMAC |
200 | &pmac_md, | 200 | &pmac_md, |
201 | #endif /* CONFIG_PPC_PMAC */ | 201 | #endif /* CONFIG_PPC_PMAC */ |
202 | #ifdef CONFIG_PPC_MAPLE | 202 | #ifdef CONFIG_PPC_MAPLE |
203 | &maple_md, | 203 | &maple_md, |
204 | #endif /* CONFIG_PPC_MAPLE */ | 204 | #endif /* CONFIG_PPC_MAPLE */ |
205 | #ifdef CONFIG_PPC_CELL | 205 | #ifdef CONFIG_PPC_CELL |
206 | &cell_md, | 206 | &cell_md, |
207 | #endif | 207 | #endif |
208 | #ifdef CONFIG_PPC_ISERIES | 208 | #ifdef CONFIG_PPC_ISERIES |
209 | &iseries_md, | 209 | &iseries_md, |
210 | #endif | 210 | #endif |
211 | NULL | 211 | NULL |
212 | }; | 212 | }; |
213 | 213 | ||
214 | /* | 214 | /* |
215 | * Early initialization entry point. This is called by head.S | 215 | * Early initialization entry point. This is called by head.S |
216 | * with MMU translation disabled. We rely on the "feature" of | 216 | * with MMU translation disabled. We rely on the "feature" of |
217 | * the CPU that ignores the top 2 bits of the address in real | 217 | * the CPU that ignores the top 2 bits of the address in real |
218 | * mode so we can access kernel globals normally provided we | 218 | * mode so we can access kernel globals normally provided we |
219 | * only toy with things in the RMO region. From here, we do | 219 | * only toy with things in the RMO region. From here, we do |
220 | * some early parsing of the device-tree to setup out LMB | 220 | * some early parsing of the device-tree to setup out LMB |
221 | * data structures, and allocate & initialize the hash table | 221 | * data structures, and allocate & initialize the hash table |
222 | * and segment tables so we can start running with translation | 222 | * and segment tables so we can start running with translation |
223 | * enabled. | 223 | * enabled. |
224 | * | 224 | * |
225 | * It is this function which will call the probe() callback of | 225 | * It is this function which will call the probe() callback of |
226 | * the various platform types and copy the matching one to the | 226 | * the various platform types and copy the matching one to the |
227 | * global ppc_md structure. Your platform can eventually do | 227 | * global ppc_md structure. Your platform can eventually do |
228 | * some very early initializations from the probe() routine, but | 228 | * some very early initializations from the probe() routine, but |
229 | * this is not recommended, be very careful as, for example, the | 229 | * this is not recommended, be very careful as, for example, the |
230 | * device-tree is not accessible via normal means at this point. | 230 | * device-tree is not accessible via normal means at this point. |
231 | */ | 231 | */ |
232 | 232 | ||
233 | void __init early_setup(unsigned long dt_ptr) | 233 | void __init early_setup(unsigned long dt_ptr) |
234 | { | 234 | { |
235 | struct paca_struct *lpaca = get_paca(); | 235 | struct paca_struct *lpaca = get_paca(); |
236 | static struct machdep_calls **mach; | 236 | static struct machdep_calls **mach; |
237 | 237 | ||
238 | /* | 238 | /* |
239 | * Enable early debugging if any specified (see top of | 239 | * Enable early debugging if any specified (see top of |
240 | * this file) | 240 | * this file) |
241 | */ | 241 | */ |
242 | EARLY_DEBUG_INIT(); | 242 | EARLY_DEBUG_INIT(); |
243 | 243 | ||
244 | DBG(" -> early_setup()\n"); | 244 | DBG(" -> early_setup()\n"); |
245 | 245 | ||
246 | /* | 246 | /* |
247 | * Do early initializations using the flattened device | 247 | * Do early initializations using the flattened device |
248 | * tree, like retreiving the physical memory map or | 248 | * tree, like retreiving the physical memory map or |
249 | * calculating/retreiving the hash table size | 249 | * calculating/retreiving the hash table size |
250 | */ | 250 | */ |
251 | early_init_devtree(__va(dt_ptr)); | 251 | early_init_devtree(__va(dt_ptr)); |
252 | 252 | ||
253 | /* | 253 | /* |
254 | * Iterate all ppc_md structures until we find the proper | 254 | * Iterate all ppc_md structures until we find the proper |
255 | * one for the current machine type | 255 | * one for the current machine type |
256 | */ | 256 | */ |
257 | DBG("Probing machine type for platform %x...\n", | 257 | DBG("Probing machine type for platform %x...\n", |
258 | systemcfg->platform); | 258 | systemcfg->platform); |
259 | 259 | ||
260 | for (mach = machines; *mach; mach++) { | 260 | for (mach = machines; *mach; mach++) { |
261 | if ((*mach)->probe(systemcfg->platform)) | 261 | if ((*mach)->probe(systemcfg->platform)) |
262 | break; | 262 | break; |
263 | } | 263 | } |
264 | /* What can we do if we didn't find ? */ | 264 | /* What can we do if we didn't find ? */ |
265 | if (*mach == NULL) { | 265 | if (*mach == NULL) { |
266 | DBG("No suitable machine found !\n"); | 266 | DBG("No suitable machine found !\n"); |
267 | for (;;); | 267 | for (;;); |
268 | } | 268 | } |
269 | ppc_md = **mach; | 269 | ppc_md = **mach; |
270 | 270 | ||
271 | DBG("Found, Initializing memory management...\n"); | 271 | DBG("Found, Initializing memory management...\n"); |
272 | 272 | ||
273 | /* | 273 | /* |
274 | * Initialize the MMU Hash table and create the linear mapping | 274 | * Initialize the MMU Hash table and create the linear mapping |
275 | * of memory. Has to be done before stab/slb initialization as | 275 | * of memory. Has to be done before stab/slb initialization as |
276 | * this is currently where the page size encoding is obtained | 276 | * this is currently where the page size encoding is obtained |
277 | */ | 277 | */ |
278 | htab_initialize(); | 278 | htab_initialize(); |
279 | 279 | ||
280 | /* | 280 | /* |
281 | * Initialize stab / SLB management except on iSeries | 281 | * Initialize stab / SLB management except on iSeries |
282 | */ | 282 | */ |
283 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) { | 283 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) { |
284 | if (cpu_has_feature(CPU_FTR_SLB)) | 284 | if (cpu_has_feature(CPU_FTR_SLB)) |
285 | slb_initialize(); | 285 | slb_initialize(); |
286 | else | 286 | else |
287 | stab_initialize(lpaca->stab_real); | 287 | stab_initialize(lpaca->stab_real); |
288 | } | 288 | } |
289 | 289 | ||
290 | DBG(" <- early_setup()\n"); | 290 | DBG(" <- early_setup()\n"); |
291 | } | 291 | } |
292 | 292 | ||
293 | 293 | ||
294 | #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) | 294 | #if defined(CONFIG_SMP) || defined(CONFIG_KEXEC) |
295 | void smp_release_cpus(void) | 295 | void smp_release_cpus(void) |
296 | { | 296 | { |
297 | extern unsigned long __secondary_hold_spinloop; | 297 | extern unsigned long __secondary_hold_spinloop; |
298 | 298 | ||
299 | DBG(" -> smp_release_cpus()\n"); | 299 | DBG(" -> smp_release_cpus()\n"); |
300 | 300 | ||
301 | /* All secondary cpus are spinning on a common spinloop, release them | 301 | /* All secondary cpus are spinning on a common spinloop, release them |
302 | * all now so they can start to spin on their individual paca | 302 | * all now so they can start to spin on their individual paca |
303 | * spinloops. For non SMP kernels, the secondary cpus never get out | 303 | * spinloops. For non SMP kernels, the secondary cpus never get out |
304 | * of the common spinloop. | 304 | * of the common spinloop. |
305 | * This is useless but harmless on iSeries, secondaries are already | 305 | * This is useless but harmless on iSeries, secondaries are already |
306 | * waiting on their paca spinloops. */ | 306 | * waiting on their paca spinloops. */ |
307 | 307 | ||
308 | __secondary_hold_spinloop = 1; | 308 | __secondary_hold_spinloop = 1; |
309 | mb(); | 309 | mb(); |
310 | 310 | ||
311 | DBG(" <- smp_release_cpus()\n"); | 311 | DBG(" <- smp_release_cpus()\n"); |
312 | } | 312 | } |
313 | #else | 313 | #else |
314 | #define smp_release_cpus() | 314 | #define smp_release_cpus() |
315 | #endif /* CONFIG_SMP || CONFIG_KEXEC */ | 315 | #endif /* CONFIG_SMP || CONFIG_KEXEC */ |
316 | 316 | ||
317 | /* | 317 | /* |
318 | * Initialize some remaining members of the ppc64_caches and systemcfg structures | 318 | * Initialize some remaining members of the ppc64_caches and systemcfg structures |
319 | * (at least until we get rid of them completely). This is mostly some | 319 | * (at least until we get rid of them completely). This is mostly some |
320 | * cache informations about the CPU that will be used by cache flush | 320 | * cache informations about the CPU that will be used by cache flush |
321 | * routines and/or provided to userland | 321 | * routines and/or provided to userland |
322 | */ | 322 | */ |
323 | static void __init initialize_cache_info(void) | 323 | static void __init initialize_cache_info(void) |
324 | { | 324 | { |
325 | struct device_node *np; | 325 | struct device_node *np; |
326 | unsigned long num_cpus = 0; | 326 | unsigned long num_cpus = 0; |
327 | 327 | ||
328 | DBG(" -> initialize_cache_info()\n"); | 328 | DBG(" -> initialize_cache_info()\n"); |
329 | 329 | ||
330 | for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { | 330 | for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { |
331 | num_cpus += 1; | 331 | num_cpus += 1; |
332 | 332 | ||
333 | /* We're assuming *all* of the CPUs have the same | 333 | /* We're assuming *all* of the CPUs have the same |
334 | * d-cache and i-cache sizes... -Peter | 334 | * d-cache and i-cache sizes... -Peter |
335 | */ | 335 | */ |
336 | 336 | ||
337 | if ( num_cpus == 1 ) { | 337 | if ( num_cpus == 1 ) { |
338 | u32 *sizep, *lsizep; | 338 | u32 *sizep, *lsizep; |
339 | u32 size, lsize; | 339 | u32 size, lsize; |
340 | const char *dc, *ic; | 340 | const char *dc, *ic; |
341 | 341 | ||
342 | /* Then read cache informations */ | 342 | /* Then read cache informations */ |
343 | if (systemcfg->platform == PLATFORM_POWERMAC) { | 343 | if (systemcfg->platform == PLATFORM_POWERMAC) { |
344 | dc = "d-cache-block-size"; | 344 | dc = "d-cache-block-size"; |
345 | ic = "i-cache-block-size"; | 345 | ic = "i-cache-block-size"; |
346 | } else { | 346 | } else { |
347 | dc = "d-cache-line-size"; | 347 | dc = "d-cache-line-size"; |
348 | ic = "i-cache-line-size"; | 348 | ic = "i-cache-line-size"; |
349 | } | 349 | } |
350 | 350 | ||
351 | size = 0; | 351 | size = 0; |
352 | lsize = cur_cpu_spec->dcache_bsize; | 352 | lsize = cur_cpu_spec->dcache_bsize; |
353 | sizep = (u32 *)get_property(np, "d-cache-size", NULL); | 353 | sizep = (u32 *)get_property(np, "d-cache-size", NULL); |
354 | if (sizep != NULL) | 354 | if (sizep != NULL) |
355 | size = *sizep; | 355 | size = *sizep; |
356 | lsizep = (u32 *) get_property(np, dc, NULL); | 356 | lsizep = (u32 *) get_property(np, dc, NULL); |
357 | if (lsizep != NULL) | 357 | if (lsizep != NULL) |
358 | lsize = *lsizep; | 358 | lsize = *lsizep; |
359 | if (sizep == 0 || lsizep == 0) | 359 | if (sizep == 0 || lsizep == 0) |
360 | DBG("Argh, can't find dcache properties ! " | 360 | DBG("Argh, can't find dcache properties ! " |
361 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 361 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
362 | 362 | ||
363 | systemcfg->dcache_size = ppc64_caches.dsize = size; | 363 | systemcfg->dcache_size = ppc64_caches.dsize = size; |
364 | systemcfg->dcache_line_size = | 364 | systemcfg->dcache_line_size = |
365 | ppc64_caches.dline_size = lsize; | 365 | ppc64_caches.dline_size = lsize; |
366 | ppc64_caches.log_dline_size = __ilog2(lsize); | 366 | ppc64_caches.log_dline_size = __ilog2(lsize); |
367 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; | 367 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; |
368 | 368 | ||
369 | size = 0; | 369 | size = 0; |
370 | lsize = cur_cpu_spec->icache_bsize; | 370 | lsize = cur_cpu_spec->icache_bsize; |
371 | sizep = (u32 *)get_property(np, "i-cache-size", NULL); | 371 | sizep = (u32 *)get_property(np, "i-cache-size", NULL); |
372 | if (sizep != NULL) | 372 | if (sizep != NULL) |
373 | size = *sizep; | 373 | size = *sizep; |
374 | lsizep = (u32 *)get_property(np, ic, NULL); | 374 | lsizep = (u32 *)get_property(np, ic, NULL); |
375 | if (lsizep != NULL) | 375 | if (lsizep != NULL) |
376 | lsize = *lsizep; | 376 | lsize = *lsizep; |
377 | if (sizep == 0 || lsizep == 0) | 377 | if (sizep == 0 || lsizep == 0) |
378 | DBG("Argh, can't find icache properties ! " | 378 | DBG("Argh, can't find icache properties ! " |
379 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 379 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
380 | 380 | ||
381 | systemcfg->icache_size = ppc64_caches.isize = size; | 381 | systemcfg->icache_size = ppc64_caches.isize = size; |
382 | systemcfg->icache_line_size = | 382 | systemcfg->icache_line_size = |
383 | ppc64_caches.iline_size = lsize; | 383 | ppc64_caches.iline_size = lsize; |
384 | ppc64_caches.log_iline_size = __ilog2(lsize); | 384 | ppc64_caches.log_iline_size = __ilog2(lsize); |
385 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; | 385 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; |
386 | } | 386 | } |
387 | } | 387 | } |
388 | 388 | ||
389 | /* Add an eye catcher and the systemcfg layout version number */ | 389 | /* Add an eye catcher and the systemcfg layout version number */ |
390 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); | 390 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); |
391 | systemcfg->version.major = SYSTEMCFG_MAJOR; | 391 | systemcfg->version.major = SYSTEMCFG_MAJOR; |
392 | systemcfg->version.minor = SYSTEMCFG_MINOR; | 392 | systemcfg->version.minor = SYSTEMCFG_MINOR; |
393 | systemcfg->processor = mfspr(SPRN_PVR); | 393 | systemcfg->processor = mfspr(SPRN_PVR); |
394 | 394 | ||
395 | DBG(" <- initialize_cache_info()\n"); | 395 | DBG(" <- initialize_cache_info()\n"); |
396 | } | 396 | } |
397 | 397 | ||
398 | 398 | ||
399 | /* | 399 | /* |
400 | * Do some initial setup of the system. The parameters are those which | 400 | * Do some initial setup of the system. The parameters are those which |
401 | * were passed in from the bootloader. | 401 | * were passed in from the bootloader. |
402 | */ | 402 | */ |
403 | void __init setup_system(void) | 403 | void __init setup_system(void) |
404 | { | 404 | { |
405 | DBG(" -> setup_system()\n"); | 405 | DBG(" -> setup_system()\n"); |
406 | 406 | ||
407 | /* | 407 | /* |
408 | * Unflatten the device-tree passed by prom_init or kexec | 408 | * Unflatten the device-tree passed by prom_init or kexec |
409 | */ | 409 | */ |
410 | unflatten_device_tree(); | 410 | unflatten_device_tree(); |
411 | 411 | ||
412 | /* | 412 | /* |
413 | * Fill the ppc64_caches & systemcfg structures with informations | 413 | * Fill the ppc64_caches & systemcfg structures with informations |
414 | * retreived from the device-tree. Need to be called before | 414 | * retreived from the device-tree. Need to be called before |
415 | * finish_device_tree() since the later requires some of the | 415 | * finish_device_tree() since the later requires some of the |
416 | * informations filled up here to properly parse the interrupt | 416 | * informations filled up here to properly parse the interrupt |
417 | * tree. | 417 | * tree. |
418 | * It also sets up the cache line sizes which allows to call | 418 | * It also sets up the cache line sizes which allows to call |
419 | * routines like flush_icache_range (used by the hash init | 419 | * routines like flush_icache_range (used by the hash init |
420 | * later on). | 420 | * later on). |
421 | */ | 421 | */ |
422 | initialize_cache_info(); | 422 | initialize_cache_info(); |
423 | 423 | ||
424 | #ifdef CONFIG_PPC_RTAS | 424 | #ifdef CONFIG_PPC_RTAS |
425 | /* | 425 | /* |
426 | * Initialize RTAS if available | 426 | * Initialize RTAS if available |
427 | */ | 427 | */ |
428 | rtas_initialize(); | 428 | rtas_initialize(); |
429 | #endif /* CONFIG_PPC_RTAS */ | 429 | #endif /* CONFIG_PPC_RTAS */ |
430 | 430 | ||
431 | /* | 431 | /* |
432 | * Check if we have an initrd provided via the device-tree | 432 | * Check if we have an initrd provided via the device-tree |
433 | */ | 433 | */ |
434 | check_for_initrd(); | 434 | check_for_initrd(); |
435 | 435 | ||
436 | /* | 436 | /* |
437 | * Do some platform specific early initializations, that includes | 437 | * Do some platform specific early initializations, that includes |
438 | * setting up the hash table pointers. It also sets up some interrupt-mapping | 438 | * setting up the hash table pointers. It also sets up some interrupt-mapping |
439 | * related options that will be used by finish_device_tree() | 439 | * related options that will be used by finish_device_tree() |
440 | */ | 440 | */ |
441 | ppc_md.init_early(); | 441 | ppc_md.init_early(); |
442 | 442 | ||
443 | /* | 443 | /* |
444 | * "Finish" the device-tree, that is do the actual parsing of | 444 | * "Finish" the device-tree, that is do the actual parsing of |
445 | * some of the properties like the interrupt map | 445 | * some of the properties like the interrupt map |
446 | */ | 446 | */ |
447 | finish_device_tree(); | 447 | finish_device_tree(); |
448 | 448 | ||
449 | #ifdef CONFIG_BOOTX_TEXT | 449 | #ifdef CONFIG_BOOTX_TEXT |
450 | init_boot_display(); | 450 | init_boot_display(); |
451 | #endif | 451 | #endif |
452 | 452 | ||
453 | /* | 453 | /* |
454 | * Initialize xmon | 454 | * Initialize xmon |
455 | */ | 455 | */ |
456 | #ifdef CONFIG_XMON_DEFAULT | 456 | #ifdef CONFIG_XMON_DEFAULT |
457 | xmon_init(1); | 457 | xmon_init(1); |
458 | #endif | 458 | #endif |
459 | /* | 459 | /* |
460 | * Register early console | 460 | * Register early console |
461 | */ | 461 | */ |
462 | register_early_udbg_console(); | 462 | register_early_udbg_console(); |
463 | 463 | ||
464 | /* Save unparsed command line copy for /proc/cmdline */ | 464 | /* Save unparsed command line copy for /proc/cmdline */ |
465 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | 465 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); |
466 | 466 | ||
467 | parse_early_param(); | 467 | parse_early_param(); |
468 | 468 | ||
469 | check_smt_enabled(); | 469 | check_smt_enabled(); |
470 | smp_setup_cpu_maps(); | 470 | smp_setup_cpu_maps(); |
471 | 471 | ||
472 | /* Release secondary cpus out of their spinloops at 0x60 now that | 472 | /* Release secondary cpus out of their spinloops at 0x60 now that |
473 | * we can map physical -> logical CPU ids | 473 | * we can map physical -> logical CPU ids |
474 | */ | 474 | */ |
475 | smp_release_cpus(); | 475 | smp_release_cpus(); |
476 | 476 | ||
477 | printk("Starting Linux PPC64 %s\n", system_utsname.version); | 477 | printk("Starting Linux PPC64 %s\n", system_utsname.version); |
478 | 478 | ||
479 | printk("-----------------------------------------------------\n"); | 479 | printk("-----------------------------------------------------\n"); |
480 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); | 480 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); |
481 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); | 481 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); |
482 | printk("systemcfg = 0x%p\n", systemcfg); | 482 | printk("systemcfg = 0x%p\n", systemcfg); |
483 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); | 483 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); |
484 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); | 484 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); |
485 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); | 485 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); |
486 | printk("ppc64_caches.dcache_line_size = 0x%x\n", | 486 | printk("ppc64_caches.dcache_line_size = 0x%x\n", |
487 | ppc64_caches.dline_size); | 487 | ppc64_caches.dline_size); |
488 | printk("ppc64_caches.icache_line_size = 0x%x\n", | 488 | printk("ppc64_caches.icache_line_size = 0x%x\n", |
489 | ppc64_caches.iline_size); | 489 | ppc64_caches.iline_size); |
490 | printk("htab_address = 0x%p\n", htab_address); | 490 | printk("htab_address = 0x%p\n", htab_address); |
491 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); | 491 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); |
492 | printk("-----------------------------------------------------\n"); | 492 | printk("-----------------------------------------------------\n"); |
493 | 493 | ||
494 | mm_init_ppc64(); | 494 | mm_init_ppc64(); |
495 | 495 | ||
496 | DBG(" <- setup_system()\n"); | 496 | DBG(" <- setup_system()\n"); |
497 | } | 497 | } |
498 | 498 | ||
499 | static int ppc64_panic_event(struct notifier_block *this, | 499 | static int ppc64_panic_event(struct notifier_block *this, |
500 | unsigned long event, void *ptr) | 500 | unsigned long event, void *ptr) |
501 | { | 501 | { |
502 | ppc_md.panic((char *)ptr); /* May not return */ | 502 | ppc_md.panic((char *)ptr); /* May not return */ |
503 | return NOTIFY_DONE; | 503 | return NOTIFY_DONE; |
504 | } | 504 | } |
505 | 505 | ||
506 | #ifdef CONFIG_IRQSTACKS | 506 | #ifdef CONFIG_IRQSTACKS |
507 | static void __init irqstack_early_init(void) | 507 | static void __init irqstack_early_init(void) |
508 | { | 508 | { |
509 | unsigned int i; | 509 | unsigned int i; |
510 | 510 | ||
511 | /* | 511 | /* |
512 | * interrupt stacks must be under 256MB, we cannot afford to take | 512 | * interrupt stacks must be under 256MB, we cannot afford to take |
513 | * SLB misses on them. | 513 | * SLB misses on them. |
514 | */ | 514 | */ |
515 | for_each_cpu(i) { | 515 | for_each_cpu(i) { |
516 | softirq_ctx[i] = (struct thread_info *) | 516 | softirq_ctx[i] = (struct thread_info *) |
517 | __va(lmb_alloc_base(THREAD_SIZE, | 517 | __va(lmb_alloc_base(THREAD_SIZE, |
518 | THREAD_SIZE, 0x10000000)); | 518 | THREAD_SIZE, 0x10000000)); |
519 | hardirq_ctx[i] = (struct thread_info *) | 519 | hardirq_ctx[i] = (struct thread_info *) |
520 | __va(lmb_alloc_base(THREAD_SIZE, | 520 | __va(lmb_alloc_base(THREAD_SIZE, |
521 | THREAD_SIZE, 0x10000000)); | 521 | THREAD_SIZE, 0x10000000)); |
522 | } | 522 | } |
523 | } | 523 | } |
524 | #else | 524 | #else |
525 | #define irqstack_early_init() | 525 | #define irqstack_early_init() |
526 | #endif | 526 | #endif |
527 | 527 | ||
528 | /* | 528 | /* |
529 | * Stack space used when we detect a bad kernel stack pointer, and | 529 | * Stack space used when we detect a bad kernel stack pointer, and |
530 | * early in SMP boots before relocation is enabled. | 530 | * early in SMP boots before relocation is enabled. |
531 | */ | 531 | */ |
532 | static void __init emergency_stack_init(void) | 532 | static void __init emergency_stack_init(void) |
533 | { | 533 | { |
534 | unsigned long limit; | 534 | unsigned long limit; |
535 | unsigned int i; | 535 | unsigned int i; |
536 | 536 | ||
537 | /* | 537 | /* |
538 | * Emergency stacks must be under 256MB, we cannot afford to take | 538 | * Emergency stacks must be under 256MB, we cannot afford to take |
539 | * SLB misses on them. The ABI also requires them to be 128-byte | 539 | * SLB misses on them. The ABI also requires them to be 128-byte |
540 | * aligned. | 540 | * aligned. |
541 | * | 541 | * |
542 | * Since we use these as temporary stacks during secondary CPU | 542 | * Since we use these as temporary stacks during secondary CPU |
543 | * bringup, we need to get at them in real mode. This means they | 543 | * bringup, we need to get at them in real mode. This means they |
544 | * must also be within the RMO region. | 544 | * must also be within the RMO region. |
545 | */ | 545 | */ |
546 | limit = min(0x10000000UL, lmb.rmo_size); | 546 | limit = min(0x10000000UL, lmb.rmo_size); |
547 | 547 | ||
548 | for_each_cpu(i) | 548 | for_each_cpu(i) |
549 | paca[i].emergency_sp = | 549 | paca[i].emergency_sp = |
550 | __va(lmb_alloc_base(HW_PAGE_SIZE, 128, limit)) + HW_PAGE_SIZE; | 550 | __va(lmb_alloc_base(HW_PAGE_SIZE, 128, limit)) + HW_PAGE_SIZE; |
551 | } | 551 | } |
552 | 552 | ||
553 | /* | 553 | /* |
554 | * Called from setup_arch to initialize the bitmap of available | 554 | * Called from setup_arch to initialize the bitmap of available |
555 | * syscalls in the systemcfg page | 555 | * syscalls in the systemcfg page |
556 | */ | 556 | */ |
557 | void __init setup_syscall_map(void) | 557 | void __init setup_syscall_map(void) |
558 | { | 558 | { |
559 | unsigned int i, count64 = 0, count32 = 0; | 559 | unsigned int i, count64 = 0, count32 = 0; |
560 | extern unsigned long *sys_call_table; | 560 | extern unsigned long *sys_call_table; |
561 | extern unsigned long sys_ni_syscall; | 561 | extern unsigned long sys_ni_syscall; |
562 | 562 | ||
563 | 563 | ||
564 | for (i = 0; i < __NR_syscalls; i++) { | 564 | for (i = 0; i < __NR_syscalls; i++) { |
565 | if (sys_call_table[i*2] != sys_ni_syscall) { | 565 | if (sys_call_table[i*2] != sys_ni_syscall) { |
566 | count64++; | 566 | count64++; |
567 | systemcfg->syscall_map_64[i >> 5] |= | 567 | systemcfg->syscall_map_64[i >> 5] |= |
568 | 0x80000000UL >> (i & 0x1f); | 568 | 0x80000000UL >> (i & 0x1f); |
569 | } | 569 | } |
570 | if (sys_call_table[i*2+1] != sys_ni_syscall) { | 570 | if (sys_call_table[i*2+1] != sys_ni_syscall) { |
571 | count32++; | 571 | count32++; |
572 | systemcfg->syscall_map_32[i >> 5] |= | 572 | systemcfg->syscall_map_32[i >> 5] |= |
573 | 0x80000000UL >> (i & 0x1f); | 573 | 0x80000000UL >> (i & 0x1f); |
574 | } | 574 | } |
575 | } | 575 | } |
576 | printk(KERN_INFO "Syscall map setup, %d 32-bit and %d 64-bit syscalls\n", | 576 | printk(KERN_INFO "Syscall map setup, %d 32-bit and %d 64-bit syscalls\n", |
577 | count32, count64); | 577 | count32, count64); |
578 | } | 578 | } |
579 | 579 | ||
580 | /* | 580 | /* |
581 | * Called into from start_kernel, after lock_kernel has been called. | 581 | * Called into from start_kernel, after lock_kernel has been called. |
582 | * Initializes bootmem, which is unsed to manage page allocation until | 582 | * Initializes bootmem, which is unsed to manage page allocation until |
583 | * mem_init is called. | 583 | * mem_init is called. |
584 | */ | 584 | */ |
585 | void __init setup_arch(char **cmdline_p) | 585 | void __init setup_arch(char **cmdline_p) |
586 | { | 586 | { |
587 | extern void do_init_bootmem(void); | 587 | extern void do_init_bootmem(void); |
588 | 588 | ||
589 | ppc64_boot_msg(0x12, "Setup Arch"); | 589 | ppc64_boot_msg(0x12, "Setup Arch"); |
590 | 590 | ||
591 | *cmdline_p = cmd_line; | 591 | *cmdline_p = cmd_line; |
592 | 592 | ||
593 | /* | 593 | /* |
594 | * Set cache line size based on type of cpu as a default. | 594 | * Set cache line size based on type of cpu as a default. |
595 | * Systems with OF can look in the properties on the cpu node(s) | 595 | * Systems with OF can look in the properties on the cpu node(s) |
596 | * for a possibly more accurate value. | 596 | * for a possibly more accurate value. |
597 | */ | 597 | */ |
598 | dcache_bsize = ppc64_caches.dline_size; | 598 | dcache_bsize = ppc64_caches.dline_size; |
599 | icache_bsize = ppc64_caches.iline_size; | 599 | icache_bsize = ppc64_caches.iline_size; |
600 | 600 | ||
601 | /* reboot on panic */ | 601 | /* reboot on panic */ |
602 | panic_timeout = 180; | 602 | panic_timeout = 180; |
603 | 603 | ||
604 | if (ppc_md.panic) | 604 | if (ppc_md.panic) |
605 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); | 605 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); |
606 | 606 | ||
607 | init_mm.start_code = PAGE_OFFSET; | 607 | init_mm.start_code = PAGE_OFFSET; |
608 | init_mm.end_code = (unsigned long) _etext; | 608 | init_mm.end_code = (unsigned long) _etext; |
609 | init_mm.end_data = (unsigned long) _edata; | 609 | init_mm.end_data = (unsigned long) _edata; |
610 | init_mm.brk = klimit; | 610 | init_mm.brk = klimit; |
611 | 611 | ||
612 | irqstack_early_init(); | 612 | irqstack_early_init(); |
613 | emergency_stack_init(); | 613 | emergency_stack_init(); |
614 | 614 | ||
615 | stabs_alloc(); | 615 | stabs_alloc(); |
616 | 616 | ||
617 | /* set up the bootmem stuff with available memory */ | 617 | /* set up the bootmem stuff with available memory */ |
618 | do_init_bootmem(); | 618 | do_init_bootmem(); |
619 | sparse_init(); | 619 | sparse_init(); |
620 | 620 | ||
621 | /* initialize the syscall map in systemcfg */ | 621 | /* initialize the syscall map in systemcfg */ |
622 | setup_syscall_map(); | 622 | setup_syscall_map(); |
623 | 623 | ||
624 | #ifdef CONFIG_DUMMY_CONSOLE | 624 | #ifdef CONFIG_DUMMY_CONSOLE |
625 | conswitchp = &dummy_con; | 625 | conswitchp = &dummy_con; |
626 | #endif | 626 | #endif |
627 | 627 | ||
628 | ppc_md.setup_arch(); | 628 | ppc_md.setup_arch(); |
629 | 629 | ||
630 | /* Use the default idle loop if the platform hasn't provided one. */ | 630 | /* Use the default idle loop if the platform hasn't provided one. */ |
631 | if (NULL == ppc_md.idle_loop) { | 631 | if (NULL == ppc_md.idle_loop) { |
632 | ppc_md.idle_loop = default_idle; | 632 | ppc_md.idle_loop = default_idle; |
633 | printk(KERN_INFO "Using default idle loop\n"); | 633 | printk(KERN_INFO "Using default idle loop\n"); |
634 | } | 634 | } |
635 | 635 | ||
636 | paging_init(); | 636 | paging_init(); |
637 | ppc64_boot_msg(0x15, "Setup Done"); | 637 | ppc64_boot_msg(0x15, "Setup Done"); |
638 | } | 638 | } |
639 | 639 | ||
640 | 640 | ||
641 | /* ToDo: do something useful if ppc_md is not yet setup. */ | 641 | /* ToDo: do something useful if ppc_md is not yet setup. */ |
642 | #define PPC64_LINUX_FUNCTION 0x0f000000 | 642 | #define PPC64_LINUX_FUNCTION 0x0f000000 |
643 | #define PPC64_IPL_MESSAGE 0xc0000000 | 643 | #define PPC64_IPL_MESSAGE 0xc0000000 |
644 | #define PPC64_TERM_MESSAGE 0xb0000000 | 644 | #define PPC64_TERM_MESSAGE 0xb0000000 |
645 | 645 | ||
646 | static void ppc64_do_msg(unsigned int src, const char *msg) | 646 | static void ppc64_do_msg(unsigned int src, const char *msg) |
647 | { | 647 | { |
648 | if (ppc_md.progress) { | 648 | if (ppc_md.progress) { |
649 | char buf[128]; | 649 | char buf[128]; |
650 | 650 | ||
651 | sprintf(buf, "%08X\n", src); | 651 | sprintf(buf, "%08X\n", src); |
652 | ppc_md.progress(buf, 0); | 652 | ppc_md.progress(buf, 0); |
653 | snprintf(buf, 128, "%s", msg); | 653 | snprintf(buf, 128, "%s", msg); |
654 | ppc_md.progress(buf, 0); | 654 | ppc_md.progress(buf, 0); |
655 | } | 655 | } |
656 | } | 656 | } |
657 | 657 | ||
658 | /* Print a boot progress message. */ | 658 | /* Print a boot progress message. */ |
659 | void ppc64_boot_msg(unsigned int src, const char *msg) | 659 | void ppc64_boot_msg(unsigned int src, const char *msg) |
660 | { | 660 | { |
661 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); | 661 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); |
662 | printk("[boot]%04x %s\n", src, msg); | 662 | printk("[boot]%04x %s\n", src, msg); |
663 | } | 663 | } |
664 | 664 | ||
665 | /* Print a termination message (print only -- does not stop the kernel) */ | 665 | /* Print a termination message (print only -- does not stop the kernel) */ |
666 | void ppc64_terminate_msg(unsigned int src, const char *msg) | 666 | void ppc64_terminate_msg(unsigned int src, const char *msg) |
667 | { | 667 | { |
668 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); | 668 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); |
669 | printk("[terminate]%04x %s\n", src, msg); | 669 | printk("[terminate]%04x %s\n", src, msg); |
670 | } | 670 | } |
671 | 671 | ||
672 | #ifndef CONFIG_PPC_ISERIES | 672 | #ifndef CONFIG_PPC_ISERIES |
673 | /* | 673 | /* |
674 | * This function can be used by platforms to "find" legacy serial ports. | 674 | * This function can be used by platforms to "find" legacy serial ports. |
675 | * It works for "serial" nodes under an "isa" node, and will try to | 675 | * It works for "serial" nodes under an "isa" node, and will try to |
676 | * respect the "ibm,aix-loc" property if any. It works with up to 8 | 676 | * respect the "ibm,aix-loc" property if any. It works with up to 8 |
677 | * ports. | 677 | * ports. |
678 | */ | 678 | */ |
679 | 679 | ||
680 | #define MAX_LEGACY_SERIAL_PORTS 8 | 680 | #define MAX_LEGACY_SERIAL_PORTS 8 |
681 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; | 681 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; |
682 | static unsigned int old_serial_count; | 682 | static unsigned int old_serial_count; |
683 | 683 | ||
684 | void __init generic_find_legacy_serial_ports(u64 *physport, | 684 | void __init generic_find_legacy_serial_ports(u64 *physport, |
685 | unsigned int *default_speed) | 685 | unsigned int *default_speed) |
686 | { | 686 | { |
687 | struct device_node *np; | 687 | struct device_node *np; |
688 | u32 *sizeprop; | 688 | u32 *sizeprop; |
689 | 689 | ||
690 | struct isa_reg_property { | 690 | struct isa_reg_property { |
691 | u32 space; | 691 | u32 space; |
692 | u32 address; | 692 | u32 address; |
693 | u32 size; | 693 | u32 size; |
694 | }; | 694 | }; |
695 | struct pci_reg_property { | 695 | struct pci_reg_property { |
696 | struct pci_address addr; | 696 | struct pci_address addr; |
697 | u32 size_hi; | 697 | u32 size_hi; |
698 | u32 size_lo; | 698 | u32 size_lo; |
699 | }; | 699 | }; |
700 | 700 | ||
701 | DBG(" -> generic_find_legacy_serial_port()\n"); | 701 | DBG(" -> generic_find_legacy_serial_port()\n"); |
702 | 702 | ||
703 | *physport = 0; | 703 | *physport = 0; |
704 | if (default_speed) | 704 | if (default_speed) |
705 | *default_speed = 0; | 705 | *default_speed = 0; |
706 | 706 | ||
707 | np = of_find_node_by_path("/"); | 707 | np = of_find_node_by_path("/"); |
708 | if (!np) | 708 | if (!np) |
709 | return; | 709 | return; |
710 | 710 | ||
711 | /* First fill our array */ | 711 | /* First fill our array */ |
712 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { | 712 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { |
713 | struct device_node *isa, *pci; | 713 | struct device_node *isa, *pci; |
714 | struct isa_reg_property *reg; | 714 | struct isa_reg_property *reg; |
715 | unsigned long phys_size, addr_size, io_base; | 715 | unsigned long phys_size, addr_size, io_base; |
716 | u32 *rangesp; | 716 | u32 *rangesp; |
717 | u32 *interrupts, *clk, *spd; | 717 | u32 *interrupts, *clk, *spd; |
718 | char *typep; | 718 | char *typep; |
719 | int index, rlen, rentsize; | 719 | int index, rlen, rentsize; |
720 | 720 | ||
721 | /* Ok, first check if it's under an "isa" parent */ | 721 | /* Ok, first check if it's under an "isa" parent */ |
722 | isa = of_get_parent(np); | 722 | isa = of_get_parent(np); |
723 | if (!isa || strcmp(isa->name, "isa")) { | 723 | if (!isa || strcmp(isa->name, "isa")) { |
724 | DBG("%s: no isa parent found\n", np->full_name); | 724 | DBG("%s: no isa parent found\n", np->full_name); |
725 | continue; | 725 | continue; |
726 | } | 726 | } |
727 | 727 | ||
728 | /* Now look for an "ibm,aix-loc" property that gives us ordering | 728 | /* Now look for an "ibm,aix-loc" property that gives us ordering |
729 | * if any... | 729 | * if any... |
730 | */ | 730 | */ |
731 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); | 731 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); |
732 | 732 | ||
733 | /* Get the ISA port number */ | 733 | /* Get the ISA port number */ |
734 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); | 734 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); |
735 | if (reg == NULL) | 735 | if (reg == NULL) |
736 | goto next_port; | 736 | goto next_port; |
737 | /* We assume the interrupt number isn't translated ... */ | 737 | /* We assume the interrupt number isn't translated ... */ |
738 | interrupts = (u32 *)get_property(np, "interrupts", NULL); | 738 | interrupts = (u32 *)get_property(np, "interrupts", NULL); |
739 | /* get clock freq. if present */ | 739 | /* get clock freq. if present */ |
740 | clk = (u32 *)get_property(np, "clock-frequency", NULL); | 740 | clk = (u32 *)get_property(np, "clock-frequency", NULL); |
741 | /* get default speed if present */ | 741 | /* get default speed if present */ |
742 | spd = (u32 *)get_property(np, "current-speed", NULL); | 742 | spd = (u32 *)get_property(np, "current-speed", NULL); |
743 | /* Default to locate at end of array */ | 743 | /* Default to locate at end of array */ |
744 | index = old_serial_count; /* end of the array by default */ | 744 | index = old_serial_count; /* end of the array by default */ |
745 | 745 | ||
746 | /* If we have a location index, then use it */ | 746 | /* If we have a location index, then use it */ |
747 | if (typep && *typep == 'S') { | 747 | if (typep && *typep == 'S') { |
748 | index = simple_strtol(typep+1, NULL, 0) - 1; | 748 | index = simple_strtol(typep+1, NULL, 0) - 1; |
749 | /* if index is out of range, use end of array instead */ | 749 | /* if index is out of range, use end of array instead */ |
750 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 750 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
751 | index = old_serial_count; | 751 | index = old_serial_count; |
752 | /* if our index is still out of range, that mean that | 752 | /* if our index is still out of range, that mean that |
753 | * array is full, we could scan for a free slot but that | 753 | * array is full, we could scan for a free slot but that |
754 | * make little sense to bother, just skip the port | 754 | * make little sense to bother, just skip the port |
755 | */ | 755 | */ |
756 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 756 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
757 | goto next_port; | 757 | goto next_port; |
758 | if (index >= old_serial_count) | 758 | if (index >= old_serial_count) |
759 | old_serial_count = index + 1; | 759 | old_serial_count = index + 1; |
760 | /* Check if there is a port who already claimed our slot */ | 760 | /* Check if there is a port who already claimed our slot */ |
761 | if (serial_ports[index].iobase != 0) { | 761 | if (serial_ports[index].iobase != 0) { |
762 | /* if we still have some room, move it, else override */ | 762 | /* if we still have some room, move it, else override */ |
763 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { | 763 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { |
764 | DBG("Moved legacy port %d -> %d\n", index, | 764 | DBG("Moved legacy port %d -> %d\n", index, |
765 | old_serial_count); | 765 | old_serial_count); |
766 | serial_ports[old_serial_count++] = | 766 | serial_ports[old_serial_count++] = |
767 | serial_ports[index]; | 767 | serial_ports[index]; |
768 | } else { | 768 | } else { |
769 | DBG("Replacing legacy port %d\n", index); | 769 | DBG("Replacing legacy port %d\n", index); |
770 | } | 770 | } |
771 | } | 771 | } |
772 | } | 772 | } |
773 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 773 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
774 | goto next_port; | 774 | goto next_port; |
775 | if (index >= old_serial_count) | 775 | if (index >= old_serial_count) |
776 | old_serial_count = index + 1; | 776 | old_serial_count = index + 1; |
777 | 777 | ||
778 | /* Now fill the entry */ | 778 | /* Now fill the entry */ |
779 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); | 779 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); |
780 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; | 780 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; |
781 | serial_ports[index].iobase = reg->address; | 781 | serial_ports[index].iobase = reg->address; |
782 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; | 782 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; |
783 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; | 783 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; |
784 | 784 | ||
785 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", | 785 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", |
786 | index, | 786 | index, |
787 | serial_ports[index].iobase, | 787 | serial_ports[index].iobase, |
788 | serial_ports[index].irq, | 788 | serial_ports[index].irq, |
789 | serial_ports[index].uartclk); | 789 | serial_ports[index].uartclk); |
790 | 790 | ||
791 | /* Get phys address of IO reg for port 1 */ | 791 | /* Get phys address of IO reg for port 1 */ |
792 | if (index != 0) | 792 | if (index != 0) |
793 | goto next_port; | 793 | goto next_port; |
794 | 794 | ||
795 | pci = of_get_parent(isa); | 795 | pci = of_get_parent(isa); |
796 | if (!pci) { | 796 | if (!pci) { |
797 | DBG("%s: no pci parent found\n", np->full_name); | 797 | DBG("%s: no pci parent found\n", np->full_name); |
798 | goto next_port; | 798 | goto next_port; |
799 | } | 799 | } |
800 | 800 | ||
801 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); | 801 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); |
802 | if (rangesp == NULL) { | 802 | if (rangesp == NULL) { |
803 | of_node_put(pci); | 803 | of_node_put(pci); |
804 | goto next_port; | 804 | goto next_port; |
805 | } | 805 | } |
806 | rlen /= 4; | 806 | rlen /= 4; |
807 | 807 | ||
808 | /* we need the #size-cells of the PCI bridge node itself */ | 808 | /* we need the #size-cells of the PCI bridge node itself */ |
809 | phys_size = 1; | 809 | phys_size = 1; |
810 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); | 810 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); |
811 | if (sizeprop != NULL) | 811 | if (sizeprop != NULL) |
812 | phys_size = *sizeprop; | 812 | phys_size = *sizeprop; |
813 | /* we need the parent #addr-cells */ | 813 | /* we need the parent #addr-cells */ |
814 | addr_size = prom_n_addr_cells(pci); | 814 | addr_size = prom_n_addr_cells(pci); |
815 | rentsize = 3 + addr_size + phys_size; | 815 | rentsize = 3 + addr_size + phys_size; |
816 | io_base = 0; | 816 | io_base = 0; |
817 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { | 817 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { |
818 | if (((rangesp[0] >> 24) & 0x3) != 1) | 818 | if (((rangesp[0] >> 24) & 0x3) != 1) |
819 | continue; /* not IO space */ | 819 | continue; /* not IO space */ |
820 | io_base = rangesp[3]; | 820 | io_base = rangesp[3]; |
821 | if (addr_size == 2) | 821 | if (addr_size == 2) |
822 | io_base = (io_base << 32) | rangesp[4]; | 822 | io_base = (io_base << 32) | rangesp[4]; |
823 | } | 823 | } |
824 | if (io_base != 0) { | 824 | if (io_base != 0) { |
825 | *physport = io_base + reg->address; | 825 | *physport = io_base + reg->address; |
826 | if (default_speed && spd) | 826 | if (default_speed && spd) |
827 | *default_speed = *spd; | 827 | *default_speed = *spd; |
828 | } | 828 | } |
829 | of_node_put(pci); | 829 | of_node_put(pci); |
830 | next_port: | 830 | next_port: |
831 | of_node_put(isa); | 831 | of_node_put(isa); |
832 | } | 832 | } |
833 | 833 | ||
834 | DBG(" <- generic_find_legacy_serial_port()\n"); | 834 | DBG(" <- generic_find_legacy_serial_port()\n"); |
835 | } | 835 | } |
836 | 836 | ||
837 | static struct platform_device serial_device = { | 837 | static struct platform_device serial_device = { |
838 | .name = "serial8250", | 838 | .name = "serial8250", |
839 | .id = PLAT8250_DEV_PLATFORM, | 839 | .id = PLAT8250_DEV_PLATFORM, |
840 | .dev = { | 840 | .dev = { |
841 | .platform_data = serial_ports, | 841 | .platform_data = serial_ports, |
842 | }, | 842 | }, |
843 | }; | 843 | }; |
844 | 844 | ||
845 | static int __init serial_dev_init(void) | 845 | static int __init serial_dev_init(void) |
846 | { | 846 | { |
847 | return platform_device_register(&serial_device); | 847 | return platform_device_register(&serial_device); |
848 | } | 848 | } |
849 | arch_initcall(serial_dev_init); | 849 | arch_initcall(serial_dev_init); |
850 | 850 | ||
851 | #endif /* CONFIG_PPC_ISERIES */ | 851 | #endif /* CONFIG_PPC_ISERIES */ |
852 | 852 | ||
853 | int check_legacy_ioport(unsigned long base_port) | 853 | int check_legacy_ioport(unsigned long base_port) |
854 | { | 854 | { |
855 | if (ppc_md.check_legacy_ioport == NULL) | 855 | if (ppc_md.check_legacy_ioport == NULL) |
856 | return 0; | 856 | return 0; |
857 | return ppc_md.check_legacy_ioport(base_port); | 857 | return ppc_md.check_legacy_ioport(base_port); |
858 | } | 858 | } |
859 | EXPORT_SYMBOL(check_legacy_ioport); | 859 | EXPORT_SYMBOL(check_legacy_ioport); |
860 | 860 | ||
861 | #ifdef CONFIG_XMON | ||
862 | static int __init early_xmon(char *p) | ||
863 | { | ||
864 | /* ensure xmon is enabled */ | ||
865 | if (p) { | ||
866 | if (strncmp(p, "on", 2) == 0) | ||
867 | xmon_init(1); | ||
868 | if (strncmp(p, "off", 3) == 0) | ||
869 | xmon_init(0); | ||
870 | if (strncmp(p, "early", 5) != 0) | ||
871 | return 0; | ||
872 | } | ||
873 | xmon_init(1); | ||
874 | debugger(NULL); | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | early_param("xmon", early_xmon); | ||
879 | #endif | ||
880 | |||
881 | void cpu_die(void) | 861 | void cpu_die(void) |
882 | { | 862 | { |
883 | if (ppc_md.cpu_die) | 863 | if (ppc_md.cpu_die) |
884 | ppc_md.cpu_die(); | 864 | ppc_md.cpu_die(); |
885 | } | 865 | } |
886 | 866 |
arch/powerpc/xmon/Makefile
1 | # Makefile for xmon | 1 | # Makefile for xmon |
2 | 2 | ||
3 | ifdef CONFIG_PPC64 | 3 | ifdef CONFIG_PPC64 |
4 | EXTRA_CFLAGS += -mno-minimal-toc | 4 | EXTRA_CFLAGS += -mno-minimal-toc |
5 | endif | 5 | endif |
6 | 6 | ||
7 | obj-$(CONFIG_8xx) += start_8xx.o | 7 | obj-$(CONFIG_8xx) += start_8xx.o |
8 | obj-$(CONFIG_6xx) += start_32.o | 8 | obj-$(CONFIG_6xx) += start_32.o |
9 | obj-$(CONFIG_4xx) += start_32.o | 9 | obj-$(CONFIG_4xx) += start_32.o |
10 | obj-$(CONFIG_PPC64) += start_64.o | 10 | obj-$(CONFIG_PPC64) += start_64.o |
11 | obj-y += xmon.o ppc-dis.o ppc-opc.o subr_prf.o setjmp.o | 11 | obj-y += xmon.o ppc-dis.o ppc-opc.o setjmp.o nonstdio.o |
12 | 12 |
arch/powerpc/xmon/nonstdio.c
File was created | 1 | /* | |
2 | * Copyright (C) 1996-2005 Paul Mackerras. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #include <linux/string.h> | ||
10 | #include <asm/time.h> | ||
11 | #include "nonstdio.h" | ||
12 | |||
13 | int xmon_putchar(int c) | ||
14 | { | ||
15 | char ch = c; | ||
16 | |||
17 | if (c == '\n') | ||
18 | xmon_putchar('\r'); | ||
19 | return xmon_write(&ch, 1) == 1? c: -1; | ||
20 | } | ||
21 | |||
22 | static char line[256]; | ||
23 | static char *lineptr; | ||
24 | static int lineleft; | ||
25 | |||
26 | int xmon_expect(const char *str, unsigned long timeout) | ||
27 | { | ||
28 | int c; | ||
29 | unsigned long t0; | ||
30 | |||
31 | /* assume 25MHz default timebase if tb_ticks_per_sec not set yet */ | ||
32 | timeout *= tb_ticks_per_sec? tb_ticks_per_sec: 25000000; | ||
33 | t0 = get_tbl(); | ||
34 | do { | ||
35 | lineptr = line; | ||
36 | for (;;) { | ||
37 | c = xmon_read_poll(); | ||
38 | if (c == -1) { | ||
39 | if (get_tbl() - t0 > timeout) | ||
40 | return 0; | ||
41 | continue; | ||
42 | } | ||
43 | if (c == '\n') | ||
44 | break; | ||
45 | if (c != '\r' && lineptr < &line[sizeof(line) - 1]) | ||
46 | *lineptr++ = c; | ||
47 | } | ||
48 | *lineptr = 0; | ||
49 | } while (strstr(line, str) == NULL); | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | int xmon_getchar(void) | ||
54 | { | ||
55 | int c; | ||
56 | |||
57 | if (lineleft == 0) { | ||
58 | lineptr = line; | ||
59 | for (;;) { | ||
60 | c = xmon_readchar(); | ||
61 | if (c == -1 || c == 4) | ||
62 | break; | ||
63 | if (c == '\r' || c == '\n') { | ||
64 | *lineptr++ = '\n'; | ||
65 | xmon_putchar('\n'); | ||
66 | break; | ||
67 | } | ||
68 | switch (c) { | ||
69 | case 0177: | ||
70 | case '\b': | ||
71 | if (lineptr > line) { | ||
72 | xmon_putchar('\b'); | ||
73 | xmon_putchar(' '); | ||
74 | xmon_putchar('\b'); | ||
75 | --lineptr; | ||
76 | } | ||
77 | break; | ||
78 | case 'U' & 0x1F: | ||
79 | while (lineptr > line) { | ||
80 | xmon_putchar('\b'); | ||
81 | xmon_putchar(' '); | ||
82 | xmon_putchar('\b'); | ||
83 | --lineptr; | ||
84 | } | ||
85 | break; | ||
86 | default: | ||
87 | if (lineptr >= &line[sizeof(line) - 1]) | ||
88 | xmon_putchar('\a'); | ||
89 | else { | ||
90 | xmon_putchar(c); | ||
91 | *lineptr++ = c; | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | lineleft = lineptr - line; | ||
96 | lineptr = line; | ||
97 | } | ||
98 | if (lineleft == 0) | ||
99 | return -1; | ||
100 | --lineleft; | ||
101 | return *lineptr++; | ||
102 | } | ||
103 | |||
104 | char *xmon_gets(char *str, int nb) | ||
105 | { | ||
106 | char *p; | ||
107 | int c; | ||
108 | |||
109 | for (p = str; p < str + nb - 1; ) { | ||
110 | c = xmon_getchar(); | ||
111 | if (c == -1) { | ||
112 | if (p == str) | ||
113 | return NULL; | ||
114 | break; | ||
115 | } | ||
116 | *p++ = c; | ||
117 | if (c == '\n') | ||
118 | break; | ||
119 | } | ||
120 | *p = 0; | ||
121 | return str; | ||
122 | } | ||
123 | |||
124 | void xmon_printf(const char *format, ...) | ||
125 | { | ||
126 | va_list args; | ||
127 | int n; | ||
128 | static char xmon_outbuf[1024]; | ||
129 | |||
130 | va_start(args, format); | ||
131 | n = vsnprintf(xmon_outbuf, sizeof(xmon_outbuf), format, args); | ||
132 | va_end(args); | ||
133 | xmon_write(xmon_outbuf, n); | ||
134 | } | ||
135 |
arch/powerpc/xmon/nonstdio.h
1 | typedef int FILE; | ||
2 | extern FILE *xmon_stdin, *xmon_stdout; | ||
3 | #define EOF (-1) | 1 | #define EOF (-1) |
4 | #define stdin xmon_stdin | 2 | |
5 | #define stdout xmon_stdout | ||
6 | #define printf xmon_printf | 3 | #define printf xmon_printf |
7 | #define fprintf xmon_fprintf | ||
8 | #define fputs xmon_fputs | ||
9 | #define fgets xmon_fgets | ||
10 | #define putchar xmon_putchar | 4 | #define putchar xmon_putchar |
11 | #define getchar xmon_getchar | ||
12 | #define putc xmon_putc | ||
13 | #define getc xmon_getc | ||
14 | #define fopen(n, m) NULL | ||
15 | #define fflush(f) do {} while (0) | ||
16 | #define fclose(f) do {} while (0) | ||
17 | extern char *fgets(char *, int, void *); | ||
18 | extern void xmon_printf(const char *, ...); | ||
19 | extern void xmon_fprintf(void *, const char *, ...); | ||
20 | extern void xmon_sprintf(char *, const char *, ...); | ||
21 | 5 | ||
22 | #define perror(s) printf("%s: no files!\n", (s)) | 6 | extern int xmon_putchar(int c); |
7 | extern int xmon_getchar(void); |
arch/powerpc/xmon/start_32.c
1 | /* | 1 | /* |
2 | * Copyright (C) 1996 Paul Mackerras. | 2 | * Copyright (C) 1996 Paul Mackerras. |
3 | */ | 3 | */ |
4 | #include <linux/config.h> | 4 | #include <linux/config.h> |
5 | #include <linux/string.h> | 5 | #include <linux/string.h> |
6 | #include <asm/machdep.h> | 6 | #include <asm/machdep.h> |
7 | #include <asm/io.h> | 7 | #include <asm/io.h> |
8 | #include <asm/page.h> | 8 | #include <asm/page.h> |
9 | #include <linux/adb.h> | 9 | #include <linux/adb.h> |
10 | #include <linux/pmu.h> | 10 | #include <linux/pmu.h> |
11 | #include <linux/cuda.h> | 11 | #include <linux/cuda.h> |
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/sysrq.h> | ||
15 | #include <linux/bitops.h> | 14 | #include <linux/bitops.h> |
16 | #include <asm/xmon.h> | 15 | #include <asm/xmon.h> |
17 | #include <asm/prom.h> | 16 | #include <asm/prom.h> |
18 | #include <asm/bootx.h> | 17 | #include <asm/bootx.h> |
19 | #include <asm/machdep.h> | 18 | #include <asm/machdep.h> |
20 | #include <asm/errno.h> | 19 | #include <asm/errno.h> |
21 | #include <asm/pmac_feature.h> | 20 | #include <asm/pmac_feature.h> |
22 | #include <asm/processor.h> | 21 | #include <asm/processor.h> |
23 | #include <asm/delay.h> | 22 | #include <asm/delay.h> |
24 | #include <asm/btext.h> | 23 | #include <asm/btext.h> |
24 | #include <asm/time.h> | ||
25 | #include "nonstdio.h" | ||
25 | 26 | ||
26 | static volatile unsigned char __iomem *sccc, *sccd; | 27 | static volatile unsigned char __iomem *sccc, *sccd; |
27 | unsigned int TXRDY, RXRDY, DLAB; | 28 | unsigned int TXRDY, RXRDY, DLAB; |
28 | static int xmon_expect(const char *str, unsigned int timeout); | ||
29 | 29 | ||
30 | static int use_serial; | 30 | static int use_serial; |
31 | static int use_screen; | 31 | static int use_screen; |
32 | static int via_modem; | 32 | static int via_modem; |
33 | static int xmon_use_sccb; | 33 | static int xmon_use_sccb; |
34 | static struct device_node *channel_node; | 34 | static struct device_node *channel_node; |
35 | 35 | ||
36 | #define TB_SPEED 25000000 | ||
37 | |||
38 | static inline unsigned int readtb(void) | ||
39 | { | ||
40 | unsigned int ret; | ||
41 | |||
42 | asm volatile("mftb %0" : "=r" (ret) :); | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | void buf_access(void) | 36 | void buf_access(void) |
47 | { | 37 | { |
48 | if (DLAB) | 38 | if (DLAB) |
49 | sccd[3] &= ~DLAB; /* reset DLAB */ | 39 | sccd[3] &= ~DLAB; /* reset DLAB */ |
50 | } | 40 | } |
51 | 41 | ||
52 | extern int adb_init(void); | 42 | extern int adb_init(void); |
53 | 43 | ||
54 | #ifdef CONFIG_PPC_CHRP | 44 | #ifdef CONFIG_PPC_CHRP |
55 | /* | 45 | /* |
56 | * This looks in the "ranges" property for the primary PCI host bridge | 46 | * This looks in the "ranges" property for the primary PCI host bridge |
57 | * to find the physical address of the start of PCI/ISA I/O space. | 47 | * to find the physical address of the start of PCI/ISA I/O space. |
58 | * It is basically a cut-down version of pci_process_bridge_OF_ranges. | 48 | * It is basically a cut-down version of pci_process_bridge_OF_ranges. |
59 | */ | 49 | */ |
60 | static unsigned long chrp_find_phys_io_base(void) | 50 | static unsigned long chrp_find_phys_io_base(void) |
61 | { | 51 | { |
62 | struct device_node *node; | 52 | struct device_node *node; |
63 | unsigned int *ranges; | 53 | unsigned int *ranges; |
64 | unsigned long base = CHRP_ISA_IO_BASE; | 54 | unsigned long base = CHRP_ISA_IO_BASE; |
65 | int rlen = 0; | 55 | int rlen = 0; |
66 | int np; | 56 | int np; |
67 | 57 | ||
68 | node = find_devices("isa"); | 58 | node = find_devices("isa"); |
69 | if (node != NULL) { | 59 | if (node != NULL) { |
70 | node = node->parent; | 60 | node = node->parent; |
71 | if (node == NULL || node->type == NULL | 61 | if (node == NULL || node->type == NULL |
72 | || strcmp(node->type, "pci") != 0) | 62 | || strcmp(node->type, "pci") != 0) |
73 | node = NULL; | 63 | node = NULL; |
74 | } | 64 | } |
75 | if (node == NULL) | 65 | if (node == NULL) |
76 | node = find_devices("pci"); | 66 | node = find_devices("pci"); |
77 | if (node == NULL) | 67 | if (node == NULL) |
78 | return base; | 68 | return base; |
79 | 69 | ||
80 | ranges = (unsigned int *) get_property(node, "ranges", &rlen); | 70 | ranges = (unsigned int *) get_property(node, "ranges", &rlen); |
81 | np = prom_n_addr_cells(node) + 5; | 71 | np = prom_n_addr_cells(node) + 5; |
82 | while ((rlen -= np * sizeof(unsigned int)) >= 0) { | 72 | while ((rlen -= np * sizeof(unsigned int)) >= 0) { |
83 | if ((ranges[0] >> 24) == 1 && ranges[2] == 0) { | 73 | if ((ranges[0] >> 24) == 1 && ranges[2] == 0) { |
84 | /* I/O space starting at 0, grab the phys base */ | 74 | /* I/O space starting at 0, grab the phys base */ |
85 | base = ranges[np - 3]; | 75 | base = ranges[np - 3]; |
86 | break; | 76 | break; |
87 | } | 77 | } |
88 | ranges += np; | 78 | ranges += np; |
89 | } | 79 | } |
90 | return base; | 80 | return base; |
91 | } | 81 | } |
92 | #endif /* CONFIG_PPC_CHRP */ | 82 | #endif /* CONFIG_PPC_CHRP */ |
93 | 83 | ||
94 | #ifdef CONFIG_MAGIC_SYSRQ | 84 | void xmon_map_scc(void) |
95 | static void sysrq_handle_xmon(int key, struct pt_regs *regs, | ||
96 | struct tty_struct *tty) | ||
97 | { | 85 | { |
98 | xmon(regs); | ||
99 | } | ||
100 | |||
101 | static struct sysrq_key_op sysrq_xmon_op = | ||
102 | { | ||
103 | .handler = sysrq_handle_xmon, | ||
104 | .help_msg = "Xmon", | ||
105 | .action_msg = "Entering xmon", | ||
106 | }; | ||
107 | #endif | ||
108 | |||
109 | void | ||
110 | xmon_map_scc(void) | ||
111 | { | ||
112 | #ifdef CONFIG_PPC_MULTIPLATFORM | 86 | #ifdef CONFIG_PPC_MULTIPLATFORM |
113 | volatile unsigned char __iomem *base; | 87 | volatile unsigned char __iomem *base; |
114 | 88 | ||
115 | if (_machine == _MACH_Pmac) { | 89 | if (_machine == _MACH_Pmac) { |
116 | struct device_node *np; | 90 | struct device_node *np; |
117 | unsigned long addr; | 91 | unsigned long addr; |
118 | #ifdef CONFIG_BOOTX_TEXT | 92 | #ifdef CONFIG_BOOTX_TEXT |
119 | if (!use_screen && !use_serial | 93 | if (!use_screen && !use_serial |
120 | && !machine_is_compatible("iMac")) { | 94 | && !machine_is_compatible("iMac")) { |
121 | /* see if there is a keyboard in the device tree | 95 | /* see if there is a keyboard in the device tree |
122 | with a parent of type "adb" */ | 96 | with a parent of type "adb" */ |
123 | for (np = find_devices("keyboard"); np; np = np->next) | 97 | for (np = find_devices("keyboard"); np; np = np->next) |
124 | if (np->parent && np->parent->type | 98 | if (np->parent && np->parent->type |
125 | && strcmp(np->parent->type, "adb") == 0) | 99 | && strcmp(np->parent->type, "adb") == 0) |
126 | break; | 100 | break; |
127 | 101 | ||
128 | /* needs to be hacked if xmon_printk is to be used | 102 | /* needs to be hacked if xmon_printk is to be used |
129 | from within find_via_pmu() */ | 103 | from within find_via_pmu() */ |
130 | #ifdef CONFIG_ADB_PMU | 104 | #ifdef CONFIG_ADB_PMU |
131 | if (np != NULL && boot_text_mapped && find_via_pmu()) | 105 | if (np != NULL && boot_text_mapped && find_via_pmu()) |
132 | use_screen = 1; | 106 | use_screen = 1; |
133 | #endif | 107 | #endif |
134 | #ifdef CONFIG_ADB_CUDA | 108 | #ifdef CONFIG_ADB_CUDA |
135 | if (np != NULL && boot_text_mapped && find_via_cuda()) | 109 | if (np != NULL && boot_text_mapped && find_via_cuda()) |
136 | use_screen = 1; | 110 | use_screen = 1; |
137 | #endif | 111 | #endif |
138 | } | 112 | } |
139 | if (!use_screen && (np = find_devices("escc")) != NULL) { | 113 | if (!use_screen && (np = find_devices("escc")) != NULL) { |
140 | /* | 114 | /* |
141 | * look for the device node for the serial port | 115 | * look for the device node for the serial port |
142 | * we're using and see if it says it has a modem | 116 | * we're using and see if it says it has a modem |
143 | */ | 117 | */ |
144 | char *name = xmon_use_sccb? "ch-b": "ch-a"; | 118 | char *name = xmon_use_sccb? "ch-b": "ch-a"; |
145 | char *slots; | 119 | char *slots; |
146 | int l; | 120 | int l; |
147 | 121 | ||
148 | np = np->child; | 122 | np = np->child; |
149 | while (np != NULL && strcmp(np->name, name) != 0) | 123 | while (np != NULL && strcmp(np->name, name) != 0) |
150 | np = np->sibling; | 124 | np = np->sibling; |
151 | if (np != NULL) { | 125 | if (np != NULL) { |
152 | /* XXX should parse this properly */ | 126 | /* XXX should parse this properly */ |
153 | channel_node = np; | 127 | channel_node = np; |
154 | slots = get_property(np, "slot-names", &l); | 128 | slots = get_property(np, "slot-names", &l); |
155 | if (slots != NULL && l >= 10 | 129 | if (slots != NULL && l >= 10 |
156 | && strcmp(slots+4, "Modem") == 0) | 130 | && strcmp(slots+4, "Modem") == 0) |
157 | via_modem = 1; | 131 | via_modem = 1; |
158 | } | 132 | } |
159 | } | 133 | } |
160 | btext_drawstring("xmon uses "); | 134 | btext_drawstring("xmon uses "); |
161 | if (use_screen) | 135 | if (use_screen) |
162 | btext_drawstring("screen and keyboard\n"); | 136 | btext_drawstring("screen and keyboard\n"); |
163 | else { | 137 | else { |
164 | if (via_modem) | 138 | if (via_modem) |
165 | btext_drawstring("modem on "); | 139 | btext_drawstring("modem on "); |
166 | btext_drawstring(xmon_use_sccb? "printer": "modem"); | 140 | btext_drawstring(xmon_use_sccb? "printer": "modem"); |
167 | btext_drawstring(" port\n"); | 141 | btext_drawstring(" port\n"); |
168 | } | 142 | } |
169 | 143 | ||
170 | #endif /* CONFIG_BOOTX_TEXT */ | 144 | #endif /* CONFIG_BOOTX_TEXT */ |
171 | 145 | ||
172 | #ifdef CHRP_ESCC | 146 | #ifdef CHRP_ESCC |
173 | addr = 0xc1013020; | 147 | addr = 0xc1013020; |
174 | #else | 148 | #else |
175 | addr = 0xf3013020; | 149 | addr = 0xf3013020; |
176 | #endif | 150 | #endif |
177 | TXRDY = 4; | 151 | TXRDY = 4; |
178 | RXRDY = 1; | 152 | RXRDY = 1; |
179 | 153 | ||
180 | np = find_devices("mac-io"); | 154 | np = find_devices("mac-io"); |
181 | if (np && np->n_addrs) | 155 | if (np && np->n_addrs) |
182 | addr = np->addrs[0].address + 0x13020; | 156 | addr = np->addrs[0].address + 0x13020; |
183 | base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); | 157 | base = (volatile unsigned char *) ioremap(addr & PAGE_MASK, PAGE_SIZE); |
184 | sccc = base + (addr & ~PAGE_MASK); | 158 | sccc = base + (addr & ~PAGE_MASK); |
185 | sccd = sccc + 0x10; | 159 | sccd = sccc + 0x10; |
186 | 160 | ||
187 | } else { | 161 | } else { |
188 | base = (volatile unsigned char *) isa_io_base; | 162 | base = (volatile unsigned char *) isa_io_base; |
189 | 163 | ||
190 | #ifdef CONFIG_PPC_CHRP | 164 | #ifdef CONFIG_PPC_CHRP |
191 | if (_machine == _MACH_chrp) | 165 | if (_machine == _MACH_chrp) |
192 | base = (volatile unsigned char __iomem *) | 166 | base = (volatile unsigned char __iomem *) |
193 | ioremap(chrp_find_phys_io_base(), 0x1000); | 167 | ioremap(chrp_find_phys_io_base(), 0x1000); |
194 | #endif | 168 | #endif |
195 | 169 | ||
196 | sccc = base + 0x3fd; | 170 | sccc = base + 0x3fd; |
197 | sccd = base + 0x3f8; | 171 | sccd = base + 0x3f8; |
198 | if (xmon_use_sccb) { | 172 | if (xmon_use_sccb) { |
199 | sccc -= 0x100; | 173 | sccc -= 0x100; |
200 | sccd -= 0x100; | 174 | sccd -= 0x100; |
201 | } | 175 | } |
202 | TXRDY = 0x20; | 176 | TXRDY = 0x20; |
203 | RXRDY = 1; | 177 | RXRDY = 1; |
204 | DLAB = 0x80; | 178 | DLAB = 0x80; |
205 | } | 179 | } |
206 | #elif defined(CONFIG_GEMINI) | 180 | #elif defined(CONFIG_GEMINI) |
207 | /* should already be mapped by the kernel boot */ | 181 | /* should already be mapped by the kernel boot */ |
208 | sccc = (volatile unsigned char __iomem *) 0xffeffb0d; | 182 | sccc = (volatile unsigned char __iomem *) 0xffeffb0d; |
209 | sccd = (volatile unsigned char __iomem *) 0xffeffb08; | 183 | sccd = (volatile unsigned char __iomem *) 0xffeffb08; |
210 | TXRDY = 0x20; | 184 | TXRDY = 0x20; |
211 | RXRDY = 1; | 185 | RXRDY = 1; |
212 | DLAB = 0x80; | 186 | DLAB = 0x80; |
213 | #elif defined(CONFIG_405GP) | 187 | #elif defined(CONFIG_405GP) |
214 | sccc = (volatile unsigned char __iomem *)0xef600305; | 188 | sccc = (volatile unsigned char __iomem *)0xef600305; |
215 | sccd = (volatile unsigned char __iomem *)0xef600300; | 189 | sccd = (volatile unsigned char __iomem *)0xef600300; |
216 | TXRDY = 0x20; | 190 | TXRDY = 0x20; |
217 | RXRDY = 1; | 191 | RXRDY = 1; |
218 | DLAB = 0x80; | 192 | DLAB = 0x80; |
219 | #endif /* platform */ | 193 | #endif /* platform */ |
220 | |||
221 | register_sysrq_key('x', &sysrq_xmon_op); | ||
222 | } | 194 | } |
223 | 195 | ||
224 | static int scc_initialized = 0; | 196 | static int scc_initialized = 0; |
225 | 197 | ||
226 | void xmon_init_scc(void); | 198 | void xmon_init_scc(void); |
227 | extern void cuda_poll(void); | 199 | extern void cuda_poll(void); |
228 | 200 | ||
229 | static inline void do_poll_adb(void) | 201 | static inline void do_poll_adb(void) |
230 | { | 202 | { |
231 | #ifdef CONFIG_ADB_PMU | 203 | #ifdef CONFIG_ADB_PMU |
232 | if (sys_ctrler == SYS_CTRLER_PMU) | 204 | if (sys_ctrler == SYS_CTRLER_PMU) |
233 | pmu_poll_adb(); | 205 | pmu_poll_adb(); |
234 | #endif /* CONFIG_ADB_PMU */ | 206 | #endif /* CONFIG_ADB_PMU */ |
235 | #ifdef CONFIG_ADB_CUDA | 207 | #ifdef CONFIG_ADB_CUDA |
236 | if (sys_ctrler == SYS_CTRLER_CUDA) | 208 | if (sys_ctrler == SYS_CTRLER_CUDA) |
237 | cuda_poll(); | 209 | cuda_poll(); |
238 | #endif /* CONFIG_ADB_CUDA */ | 210 | #endif /* CONFIG_ADB_CUDA */ |
239 | } | 211 | } |
240 | 212 | ||
241 | int | 213 | int xmon_write(void *ptr, int nb) |
242 | xmon_write(void *handle, void *ptr, int nb) | ||
243 | { | 214 | { |
244 | char *p = ptr; | 215 | char *p = ptr; |
245 | int i, c, ct; | 216 | int i, c, ct; |
246 | 217 | ||
247 | #ifdef CONFIG_SMP | 218 | #ifdef CONFIG_SMP |
248 | static unsigned long xmon_write_lock; | 219 | static unsigned long xmon_write_lock; |
249 | int lock_wait = 1000000; | 220 | int lock_wait = 1000000; |
250 | int locked; | 221 | int locked; |
251 | 222 | ||
252 | while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0) | 223 | while ((locked = test_and_set_bit(0, &xmon_write_lock)) != 0) |
253 | if (--lock_wait == 0) | 224 | if (--lock_wait == 0) |
254 | break; | 225 | break; |
255 | #endif | 226 | #endif |
256 | 227 | ||
257 | #ifdef CONFIG_BOOTX_TEXT | 228 | #ifdef CONFIG_BOOTX_TEXT |
258 | if (use_screen) { | 229 | if (use_screen) { |
259 | /* write it on the screen */ | 230 | /* write it on the screen */ |
260 | for (i = 0; i < nb; ++i) | 231 | for (i = 0; i < nb; ++i) |
261 | btext_drawchar(*p++); | 232 | btext_drawchar(*p++); |
262 | goto out; | 233 | goto out; |
263 | } | 234 | } |
264 | #endif | 235 | #endif |
265 | if (!scc_initialized) | 236 | if (!scc_initialized) |
266 | xmon_init_scc(); | 237 | xmon_init_scc(); |
267 | ct = 0; | 238 | ct = 0; |
268 | for (i = 0; i < nb; ++i) { | 239 | for (i = 0; i < nb; ++i) { |
269 | while ((*sccc & TXRDY) == 0) | 240 | while ((*sccc & TXRDY) == 0) |
270 | do_poll_adb(); | 241 | do_poll_adb(); |
271 | c = p[i]; | 242 | c = p[i]; |
272 | if (c == '\n' && !ct) { | 243 | if (c == '\n' && !ct) { |
273 | c = '\r'; | 244 | c = '\r'; |
274 | ct = 1; | 245 | ct = 1; |
275 | --i; | 246 | --i; |
276 | } else { | 247 | } else { |
277 | ct = 0; | 248 | ct = 0; |
278 | } | 249 | } |
279 | buf_access(); | 250 | buf_access(); |
280 | *sccd = c; | 251 | *sccd = c; |
281 | eieio(); | 252 | eieio(); |
282 | } | 253 | } |
283 | 254 | ||
284 | out: | 255 | out: |
285 | #ifdef CONFIG_SMP | 256 | #ifdef CONFIG_SMP |
286 | if (!locked) | 257 | if (!locked) |
287 | clear_bit(0, &xmon_write_lock); | 258 | clear_bit(0, &xmon_write_lock); |
288 | #endif | 259 | #endif |
289 | return nb; | 260 | return nb; |
290 | } | 261 | } |
291 | 262 | ||
292 | int xmon_wants_key; | 263 | int xmon_wants_key; |
293 | int xmon_adb_keycode; | 264 | int xmon_adb_keycode; |
294 | 265 | ||
295 | #ifdef CONFIG_BOOTX_TEXT | 266 | #ifdef CONFIG_BOOTX_TEXT |
296 | static int xmon_adb_shiftstate; | 267 | static int xmon_adb_shiftstate; |
297 | 268 | ||
298 | static unsigned char xmon_keytab[128] = | 269 | static unsigned char xmon_keytab[128] = |
299 | "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ | 270 | "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ |
300 | "yt123465=97-80]o" /* 0x10 - 0x1f */ | 271 | "yt123465=97-80]o" /* 0x10 - 0x1f */ |
301 | "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ | 272 | "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ |
302 | "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ | 273 | "\t `\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ |
303 | "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ | 274 | "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ |
304 | "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ | 275 | "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ |
305 | 276 | ||
306 | static unsigned char xmon_shift_keytab[128] = | 277 | static unsigned char xmon_shift_keytab[128] = |
307 | "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */ | 278 | "ASDFHGZXCV\000BQWER" /* 0x00 - 0x0f */ |
308 | "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */ | 279 | "YT!@#$^%+(&_*)}O" /* 0x10 - 0x1f */ |
309 | "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */ | 280 | "U{IP\rLJ\"K:|<?NM>" /* 0x20 - 0x2f */ |
310 | "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ | 281 | "\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0" /* 0x30 - 0x3f */ |
311 | "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ | 282 | "\0.\0*\0+\0\0\0\0\0/\r\0-\0" /* 0x40 - 0x4f */ |
312 | "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ | 283 | "\0\0000123456789\0\0\0"; /* 0x50 - 0x5f */ |
313 | 284 | ||
314 | static int | 285 | static int xmon_get_adb_key(void) |
315 | xmon_get_adb_key(void) | ||
316 | { | 286 | { |
317 | int k, t, on; | 287 | int k, t, on; |
318 | 288 | ||
319 | xmon_wants_key = 1; | 289 | xmon_wants_key = 1; |
320 | for (;;) { | 290 | for (;;) { |
321 | xmon_adb_keycode = -1; | 291 | xmon_adb_keycode = -1; |
322 | t = 0; | 292 | t = 0; |
323 | on = 0; | 293 | on = 0; |
324 | do { | 294 | do { |
325 | if (--t < 0) { | 295 | if (--t < 0) { |
326 | on = 1 - on; | 296 | on = 1 - on; |
327 | btext_drawchar(on? 0xdb: 0x20); | 297 | btext_drawchar(on? 0xdb: 0x20); |
328 | btext_drawchar('\b'); | 298 | btext_drawchar('\b'); |
329 | t = 200000; | 299 | t = 200000; |
330 | } | 300 | } |
331 | do_poll_adb(); | 301 | do_poll_adb(); |
332 | } while (xmon_adb_keycode == -1); | 302 | } while (xmon_adb_keycode == -1); |
333 | k = xmon_adb_keycode; | 303 | k = xmon_adb_keycode; |
334 | if (on) | 304 | if (on) |
335 | btext_drawstring(" \b"); | 305 | btext_drawstring(" \b"); |
336 | 306 | ||
337 | /* test for shift keys */ | 307 | /* test for shift keys */ |
338 | if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { | 308 | if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) { |
339 | xmon_adb_shiftstate = (k & 0x80) == 0; | 309 | xmon_adb_shiftstate = (k & 0x80) == 0; |
340 | continue; | 310 | continue; |
341 | } | 311 | } |
342 | if (k >= 0x80) | 312 | if (k >= 0x80) |
343 | continue; /* ignore up transitions */ | 313 | continue; /* ignore up transitions */ |
344 | k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k]; | 314 | k = (xmon_adb_shiftstate? xmon_shift_keytab: xmon_keytab)[k]; |
345 | if (k != 0) | 315 | if (k != 0) |
346 | break; | 316 | break; |
347 | } | 317 | } |
348 | xmon_wants_key = 0; | 318 | xmon_wants_key = 0; |
349 | return k; | 319 | return k; |
350 | } | 320 | } |
351 | #endif /* CONFIG_BOOTX_TEXT */ | 321 | #endif /* CONFIG_BOOTX_TEXT */ |
352 | 322 | ||
353 | int | 323 | int xmon_readchar(void) |
354 | xmon_read(void *handle, void *ptr, int nb) | ||
355 | { | 324 | { |
356 | char *p = ptr; | ||
357 | int i; | ||
358 | |||
359 | #ifdef CONFIG_BOOTX_TEXT | 325 | #ifdef CONFIG_BOOTX_TEXT |
360 | if (use_screen) { | 326 | if (use_screen) |
361 | for (i = 0; i < nb; ++i) | 327 | return xmon_get_adb_key(); |
362 | *p++ = xmon_get_adb_key(); | ||
363 | return i; | ||
364 | } | ||
365 | #endif | 328 | #endif |
366 | if (!scc_initialized) | 329 | if (!scc_initialized) |
367 | xmon_init_scc(); | 330 | xmon_init_scc(); |
368 | for (i = 0; i < nb; ++i) { | ||
369 | while ((*sccc & RXRDY) == 0) | 331 | while ((*sccc & RXRDY) == 0) |
370 | do_poll_adb(); | 332 | do_poll_adb(); |
371 | buf_access(); | 333 | buf_access(); |
372 | *p++ = *sccd; | 334 | return *sccd; |
373 | } | ||
374 | return i; | ||
375 | } | 335 | } |
376 | 336 | ||
377 | int | 337 | int xmon_read_poll(void) |
378 | xmon_read_poll(void) | ||
379 | { | 338 | { |
380 | if ((*sccc & RXRDY) == 0) { | 339 | if ((*sccc & RXRDY) == 0) { |
381 | do_poll_adb(); | 340 | do_poll_adb(); |
382 | return -1; | 341 | return -1; |
383 | } | 342 | } |
384 | buf_access(); | 343 | buf_access(); |
385 | return *sccd; | 344 | return *sccd; |
386 | } | 345 | } |
387 | 346 | ||
388 | static unsigned char scc_inittab[] = { | 347 | static unsigned char scc_inittab[] = { |
389 | 13, 0, /* set baud rate divisor */ | 348 | 13, 0, /* set baud rate divisor */ |
390 | 12, 1, | 349 | 12, 1, |
391 | 14, 1, /* baud rate gen enable, src=rtxc */ | 350 | 14, 1, /* baud rate gen enable, src=rtxc */ |
392 | 11, 0x50, /* clocks = br gen */ | 351 | 11, 0x50, /* clocks = br gen */ |
393 | 5, 0xea, /* tx 8 bits, assert DTR & RTS */ | 352 | 5, 0xea, /* tx 8 bits, assert DTR & RTS */ |
394 | 4, 0x46, /* x16 clock, 1 stop */ | 353 | 4, 0x46, /* x16 clock, 1 stop */ |
395 | 3, 0xc1, /* rx enable, 8 bits */ | 354 | 3, 0xc1, /* rx enable, 8 bits */ |
396 | }; | 355 | }; |
397 | 356 | ||
398 | void | 357 | void xmon_init_scc(void) |
399 | xmon_init_scc(void) | ||
400 | { | 358 | { |
401 | if ( _machine == _MACH_chrp ) | 359 | if ( _machine == _MACH_chrp ) |
402 | { | 360 | { |
403 | sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ | 361 | sccd[3] = 0x83; eieio(); /* LCR = 8N1 + DLAB */ |
404 | sccd[0] = 12; eieio(); /* DLL = 9600 baud */ | 362 | sccd[0] = 12; eieio(); /* DLL = 9600 baud */ |
405 | sccd[1] = 0; eieio(); | 363 | sccd[1] = 0; eieio(); |
406 | sccd[2] = 0; eieio(); /* FCR = 0 */ | 364 | sccd[2] = 0; eieio(); /* FCR = 0 */ |
407 | sccd[3] = 3; eieio(); /* LCR = 8N1 */ | 365 | sccd[3] = 3; eieio(); /* LCR = 8N1 */ |
408 | sccd[1] = 0; eieio(); /* IER = 0 */ | 366 | sccd[1] = 0; eieio(); /* IER = 0 */ |
409 | } | 367 | } |
410 | else if ( _machine == _MACH_Pmac ) | 368 | else if ( _machine == _MACH_Pmac ) |
411 | { | 369 | { |
412 | int i, x; | 370 | int i, x; |
371 | unsigned long timeout; | ||
413 | 372 | ||
414 | if (channel_node != 0) | 373 | if (channel_node != 0) |
415 | pmac_call_feature( | 374 | pmac_call_feature( |
416 | PMAC_FTR_SCC_ENABLE, | 375 | PMAC_FTR_SCC_ENABLE, |
417 | channel_node, | 376 | channel_node, |
418 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); | 377 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); |
419 | printk(KERN_INFO "Serial port locked ON by debugger !\n"); | 378 | printk(KERN_INFO "Serial port locked ON by debugger !\n"); |
420 | if (via_modem && channel_node != 0) { | 379 | if (via_modem && channel_node != 0) { |
421 | unsigned int t0; | 380 | unsigned int t0; |
422 | 381 | ||
423 | pmac_call_feature( | 382 | pmac_call_feature( |
424 | PMAC_FTR_MODEM_ENABLE, | 383 | PMAC_FTR_MODEM_ENABLE, |
425 | channel_node, 0, 1); | 384 | channel_node, 0, 1); |
426 | printk(KERN_INFO "Modem powered up by debugger !\n"); | 385 | printk(KERN_INFO "Modem powered up by debugger !\n"); |
427 | t0 = readtb(); | 386 | t0 = get_tbl(); |
428 | while (readtb() - t0 < 3*TB_SPEED) | 387 | timeout = 3 * tb_ticks_per_sec; |
388 | if (timeout == 0) | ||
389 | /* assume 25MHz if tb_ticks_per_sec not set */ | ||
390 | timeout = 75000000; | ||
391 | while (get_tbl() - t0 < timeout) | ||
429 | eieio(); | 392 | eieio(); |
430 | } | 393 | } |
431 | /* use the B channel if requested */ | 394 | /* use the B channel if requested */ |
432 | if (xmon_use_sccb) { | 395 | if (xmon_use_sccb) { |
433 | sccc = (volatile unsigned char *) | 396 | sccc = (volatile unsigned char *) |
434 | ((unsigned long)sccc & ~0x20); | 397 | ((unsigned long)sccc & ~0x20); |
435 | sccd = sccc + 0x10; | 398 | sccd = sccc + 0x10; |
436 | } | 399 | } |
437 | for (i = 20000; i != 0; --i) { | 400 | for (i = 20000; i != 0; --i) { |
438 | x = *sccc; eieio(); | 401 | x = *sccc; eieio(); |
439 | } | 402 | } |
440 | *sccc = 9; eieio(); /* reset A or B side */ | 403 | *sccc = 9; eieio(); /* reset A or B side */ |
441 | *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio(); | 404 | *sccc = ((unsigned long)sccc & 0x20)? 0x80: 0x40; eieio(); |
442 | for (i = 0; i < sizeof(scc_inittab); ++i) { | 405 | for (i = 0; i < sizeof(scc_inittab); ++i) { |
443 | *sccc = scc_inittab[i]; | 406 | *sccc = scc_inittab[i]; |
444 | eieio(); | 407 | eieio(); |
445 | } | 408 | } |
446 | } | 409 | } |
447 | scc_initialized = 1; | 410 | scc_initialized = 1; |
448 | if (via_modem) { | 411 | if (via_modem) { |
449 | for (;;) { | 412 | for (;;) { |
450 | xmon_write(NULL, "ATE1V1\r", 7); | 413 | xmon_write("ATE1V1\r", 7); |
451 | if (xmon_expect("OK", 5)) { | 414 | if (xmon_expect("OK", 5)) { |
452 | xmon_write(NULL, "ATA\r", 4); | 415 | xmon_write("ATA\r", 4); |
453 | if (xmon_expect("CONNECT", 40)) | 416 | if (xmon_expect("CONNECT", 40)) |
454 | break; | 417 | break; |
455 | } | 418 | } |
456 | xmon_write(NULL, "+++", 3); | 419 | xmon_write("+++", 3); |
457 | xmon_expect("OK", 3); | 420 | xmon_expect("OK", 3); |
458 | } | 421 | } |
459 | } | 422 | } |
460 | } | 423 | } |
461 | 424 | ||
462 | void *xmon_stdin; | 425 | void xmon_enter(void) |
463 | void *xmon_stdout; | ||
464 | void *xmon_stderr; | ||
465 | |||
466 | int xmon_putc(int c, void *f) | ||
467 | { | 426 | { |
468 | char ch = c; | ||
469 | |||
470 | if (c == '\n') | ||
471 | xmon_putc('\r', f); | ||
472 | return xmon_write(f, &ch, 1) == 1? c: -1; | ||
473 | } | ||
474 | |||
475 | int xmon_putchar(int c) | ||
476 | { | ||
477 | return xmon_putc(c, xmon_stdout); | ||
478 | } | ||
479 | |||
480 | int xmon_fputs(char *str, void *f) | ||
481 | { | ||
482 | int n = strlen(str); | ||
483 | |||
484 | return xmon_write(f, str, n) == n? 0: -1; | ||
485 | } | ||
486 | |||
487 | int | ||
488 | xmon_readchar(void) | ||
489 | { | ||
490 | char ch; | ||
491 | |||
492 | for (;;) { | ||
493 | switch (xmon_read(xmon_stdin, &ch, 1)) { | ||
494 | case 1: | ||
495 | return ch; | ||
496 | case -1: | ||
497 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | ||
498 | return -1; | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | |||
503 | static char line[256]; | ||
504 | static char *lineptr; | ||
505 | static int lineleft; | ||
506 | |||
507 | int xmon_expect(const char *str, unsigned int timeout) | ||
508 | { | ||
509 | int c; | ||
510 | unsigned int t0; | ||
511 | |||
512 | timeout *= TB_SPEED; | ||
513 | t0 = readtb(); | ||
514 | do { | ||
515 | lineptr = line; | ||
516 | for (;;) { | ||
517 | c = xmon_read_poll(); | ||
518 | if (c == -1) { | ||
519 | if (readtb() - t0 > timeout) | ||
520 | return 0; | ||
521 | continue; | ||
522 | } | ||
523 | if (c == '\n') | ||
524 | break; | ||
525 | if (c != '\r' && lineptr < &line[sizeof(line) - 1]) | ||
526 | *lineptr++ = c; | ||
527 | } | ||
528 | *lineptr = 0; | ||
529 | } while (strstr(line, str) == NULL); | ||
530 | return 1; | ||
531 | } | ||
532 | |||
533 | int | ||
534 | xmon_getchar(void) | ||
535 | { | ||
536 | int c; | ||
537 | |||
538 | if (lineleft == 0) { | ||
539 | lineptr = line; | ||
540 | for (;;) { | ||
541 | c = xmon_readchar(); | ||
542 | if (c == -1 || c == 4) | ||
543 | break; | ||
544 | if (c == '\r' || c == '\n') { | ||
545 | *lineptr++ = '\n'; | ||
546 | xmon_putchar('\n'); | ||
547 | break; | ||
548 | } | ||
549 | switch (c) { | ||
550 | case 0177: | ||
551 | case '\b': | ||
552 | if (lineptr > line) { | ||
553 | xmon_putchar('\b'); | ||
554 | xmon_putchar(' '); | ||
555 | xmon_putchar('\b'); | ||
556 | --lineptr; | ||
557 | } | ||
558 | break; | ||
559 | case 'U' & 0x1F: | ||
560 | while (lineptr > line) { | ||
561 | xmon_putchar('\b'); | ||
562 | xmon_putchar(' '); | ||
563 | xmon_putchar('\b'); | ||
564 | --lineptr; | ||
565 | } | ||
566 | break; | ||
567 | default: | ||
568 | if (lineptr >= &line[sizeof(line) - 1]) | ||
569 | xmon_putchar('\a'); | ||
570 | else { | ||
571 | xmon_putchar(c); | ||
572 | *lineptr++ = c; | ||
573 | } | ||
574 | } | ||
575 | } | ||
576 | lineleft = lineptr - line; | ||
577 | lineptr = line; | ||
578 | } | ||
579 | if (lineleft == 0) | ||
580 | return -1; | ||
581 | --lineleft; | ||
582 | return *lineptr++; | ||
583 | } | ||
584 | |||
585 | char * | ||
586 | xmon_fgets(char *str, int nb, void *f) | ||
587 | { | ||
588 | char *p; | ||
589 | int c; | ||
590 | |||
591 | for (p = str; p < str + nb - 1; ) { | ||
592 | c = xmon_getchar(); | ||
593 | if (c == -1) { | ||
594 | if (p == str) | ||
595 | return NULL; | ||
596 | break; | ||
597 | } | ||
598 | *p++ = c; | ||
599 | if (c == '\n') | ||
600 | break; | ||
601 | } | ||
602 | *p = 0; | ||
603 | return str; | ||
604 | } | ||
605 | |||
606 | void | ||
607 | xmon_enter(void) | ||
608 | { | ||
609 | #ifdef CONFIG_ADB_PMU | 427 | #ifdef CONFIG_ADB_PMU |
610 | if (_machine == _MACH_Pmac) { | 428 | if (_machine == _MACH_Pmac) { |
611 | pmu_suspend(); | 429 | pmu_suspend(); |
612 | } | 430 | } |
613 | #endif | 431 | #endif |
614 | } | 432 | } |
615 | 433 | ||
616 | void | 434 | void xmon_leave(void) |
617 | xmon_leave(void) | ||
618 | { | 435 | { |
arch/powerpc/xmon/start_64.c
1 | /* | 1 | /* |
2 | * Copyright (C) 1996 Paul Mackerras. | 2 | * Copyright (C) 1996 Paul Mackerras. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License | 5 | * modify it under the terms of the GNU General Public License |
6 | * as published by the Free Software Foundation; either version | 6 | * as published by the Free Software Foundation; either version |
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | */ | 8 | */ |
9 | #include <linux/config.h> | ||
10 | #include <linux/string.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/sysrq.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <asm/machdep.h> | 9 | #include <asm/machdep.h> |
16 | #include <asm/io.h> | ||
17 | #include <asm/page.h> | ||
18 | #include <asm/prom.h> | ||
19 | #include <asm/processor.h> | ||
20 | #include <asm/udbg.h> | 10 | #include <asm/udbg.h> |
21 | #include <asm/system.h> | ||
22 | #include "nonstdio.h" | 11 | #include "nonstdio.h" |
23 | 12 | ||
24 | #ifdef CONFIG_MAGIC_SYSRQ | 13 | void xmon_map_scc(void) |
25 | |||
26 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, | ||
27 | struct tty_struct *tty) | ||
28 | { | 14 | { |
29 | /* ensure xmon is enabled */ | ||
30 | xmon_init(1); | ||
31 | debugger(pt_regs); | ||
32 | } | 15 | } |
33 | 16 | ||
34 | static struct sysrq_key_op sysrq_xmon_op = | 17 | int xmon_write(void *ptr, int nb) |
35 | { | 18 | { |
36 | .handler = sysrq_handle_xmon, | ||
37 | .help_msg = "Xmon", | ||
38 | .action_msg = "Entering xmon", | ||
39 | }; | ||
40 | |||
41 | static int __init setup_xmon_sysrq(void) | ||
42 | { | ||
43 | register_sysrq_key('x', &sysrq_xmon_op); | ||
44 | return 0; | ||
45 | } | ||
46 | __initcall(setup_xmon_sysrq); | ||
47 | #endif /* CONFIG_MAGIC_SYSRQ */ | ||
48 | |||
49 | int | ||
50 | xmon_write(void *handle, void *ptr, int nb) | ||
51 | { | ||
52 | return udbg_write(ptr, nb); | 19 | return udbg_write(ptr, nb); |
53 | } | 20 | } |
54 | 21 | ||
55 | int | 22 | int xmon_readchar(void) |
56 | xmon_read(void *handle, void *ptr, int nb) | ||
57 | { | 23 | { |
58 | return udbg_read(ptr, nb); | 24 | if (udbg_getc) |
25 | return udbg_getc(); | ||
26 | return -1; | ||
59 | } | 27 | } |
60 | 28 | ||
61 | int | 29 | int xmon_read_poll(void) |
62 | xmon_read_poll(void) | ||
63 | { | 30 | { |
64 | if (udbg_getc_poll) | 31 | if (udbg_getc_poll) |
65 | return udbg_getc_poll(); | 32 | return udbg_getc_poll(); |
66 | return -1; | 33 | return -1; |
67 | } | ||
68 | |||
69 | FILE *xmon_stdin; | ||
70 | FILE *xmon_stdout; | ||
71 | |||
72 | int | ||
73 | xmon_putc(int c, void *f) | ||
74 | { | ||
75 | char ch = c; | ||
76 | |||
77 | if (c == '\n') | ||
78 | xmon_putc('\r', f); | ||
79 | return xmon_write(f, &ch, 1) == 1? c: -1; | ||
80 | } | ||
81 | |||
82 | int | ||
83 | xmon_putchar(int c) | ||
84 | { | ||
85 | return xmon_putc(c, xmon_stdout); | ||
86 | } | ||
87 | |||
88 | int | ||
89 | xmon_fputs(char *str, void *f) | ||
90 | { | ||
91 | int n = strlen(str); | ||
92 | |||
93 | return xmon_write(f, str, n) == n? 0: -1; | ||
94 | } | ||
95 | |||
96 | int | ||
97 | xmon_readchar(void) | ||
98 | { | ||
99 | char ch; | ||
100 | |||
101 | for (;;) { | ||
102 | switch (xmon_read(xmon_stdin, &ch, 1)) { | ||
103 | case 1: | ||
104 | return ch; | ||
105 | case -1: | ||
106 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | ||
107 | return -1; | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static char line[256]; | ||
113 | static char *lineptr; | ||
114 | static int lineleft; | ||
115 | |||
116 | int | ||
117 | xmon_getchar(void) | ||
118 | { | ||
119 | int c; | ||
120 | |||
121 | if (lineleft == 0) { | ||
122 | lineptr = line; | ||
123 | for (;;) { | ||
124 | c = xmon_readchar(); | ||
125 | if (c == -1 || c == 4) | ||
126 | break; | ||
127 | if (c == '\r' || c == '\n') { | ||
128 | *lineptr++ = '\n'; | ||
129 | xmon_putchar('\n'); | ||
130 | break; | ||
131 | } | ||
132 | switch (c) { | ||
133 | case 0177: | ||
134 | case '\b': | ||
135 | if (lineptr > line) { | ||
136 | xmon_putchar('\b'); | ||
137 | xmon_putchar(' '); | ||
138 | xmon_putchar('\b'); | ||
139 | --lineptr; | ||
140 | } | ||
141 | break; | ||
142 | case 'U' & 0x1F: | ||
143 | while (lineptr > line) { | ||
144 | xmon_putchar('\b'); | ||
145 | xmon_putchar(' '); | ||
146 | xmon_putchar('\b'); | ||
147 | --lineptr; | ||
148 | } | ||
149 | break; | ||
150 | default: | ||
151 | if (lineptr >= &line[sizeof(line) - 1]) | ||
152 | xmon_putchar('\a'); | ||
153 | else { | ||
154 | xmon_putchar(c); | ||
155 | *lineptr++ = c; | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | lineleft = lineptr - line; | ||
160 | lineptr = line; | ||
161 | } | ||
162 | if (lineleft == 0) | ||
163 | return -1; | ||
164 | --lineleft; | ||
165 | return *lineptr++; | ||
166 | } | ||
167 | |||
168 | char * | ||
169 | xmon_fgets(char *str, int nb, void *f) | ||
170 | { | ||
171 | char *p; | ||
172 | int c; | ||
173 | |||
174 | for (p = str; p < str + nb - 1; ) { | ||
175 | c = xmon_getchar(); | ||
176 | if (c == -1) { | ||
177 | if (p == str) | ||
178 | return NULL; | ||
179 | break; | ||
180 | } | ||
181 | *p++ = c; | ||
182 | if (c == '\n') | ||
183 | break; | ||
184 | } | ||
185 | *p = 0; | ||
186 | return str; |
arch/powerpc/xmon/start_8xx.c
1 | /* | 1 | /* |
2 | * Copyright (C) 1996 Paul Mackerras. | 2 | * Copyright (C) 1996 Paul Mackerras. |
3 | * Copyright (C) 2000 Dan Malek. | 3 | * Copyright (C) 2000 Dan Malek. |
4 | * Quick hack of Paul's code to make XMON work on 8xx processors. Lots | 4 | * Quick hack of Paul's code to make XMON work on 8xx processors. Lots |
5 | * of assumptions, like the SMC1 is used, it has been initialized by the | 5 | * of assumptions, like the SMC1 is used, it has been initialized by the |
6 | * loader at some point, and we can just stuff and suck bytes. | 6 | * loader at some point, and we can just stuff and suck bytes. |
7 | * We rely upon the 8xx uart driver to support us, as the interface | 7 | * We rely upon the 8xx uart driver to support us, as the interface |
8 | * changes between boot up and operational phases of the kernel. | 8 | * changes between boot up and operational phases of the kernel. |
9 | */ | 9 | */ |
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <asm/machdep.h> | 11 | #include <asm/machdep.h> |
12 | #include <asm/io.h> | 12 | #include <asm/io.h> |
13 | #include <asm/page.h> | 13 | #include <asm/page.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <asm/8xx_immap.h> | 15 | #include <asm/8xx_immap.h> |
16 | #include <asm/mpc8xx.h> | 16 | #include <asm/mpc8xx.h> |
17 | #include <asm/commproc.h> | 17 | #include <asm/commproc.h> |
18 | #include "nonstdio.h" | ||
18 | 19 | ||
19 | extern void xmon_printf(const char *fmt, ...); | ||
20 | extern int xmon_8xx_write(char *str, int nb); | 20 | extern int xmon_8xx_write(char *str, int nb); |
21 | extern int xmon_8xx_read_poll(void); | 21 | extern int xmon_8xx_read_poll(void); |
22 | extern int xmon_8xx_read_char(void); | 22 | extern int xmon_8xx_read_char(void); |
23 | void prom_drawhex(uint); | ||
24 | void prom_drawstring(const char *str); | ||
25 | 23 | ||
26 | static int use_screen = 1; /* default */ | 24 | void xmon_map_scc(void) |
27 | |||
28 | #define TB_SPEED 25000000 | ||
29 | |||
30 | static inline unsigned int readtb(void) | ||
31 | { | 25 | { |
32 | unsigned int ret; | ||
33 | |||
34 | asm volatile("mftb %0" : "=r" (ret) :); | ||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | void buf_access(void) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | void | ||
43 | xmon_map_scc(void) | ||
44 | { | ||
45 | |||
46 | cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); | 26 | cpmp = (cpm8xx_t *)&(((immap_t *)IMAP_ADDR)->im_cpm); |
47 | use_screen = 0; | ||
48 | |||
49 | prom_drawstring("xmon uses serial port\n"); | ||
50 | } | 27 | } |
51 | 28 | ||
52 | static int scc_initialized = 0; | ||
53 | |||
54 | void xmon_init_scc(void); | 29 | void xmon_init_scc(void); |
55 | 30 | ||
56 | int | 31 | int xmon_write(void *ptr, int nb) |
57 | xmon_write(void *handle, void *ptr, int nb) | ||
58 | { | 32 | { |
59 | char *p = ptr; | ||
60 | int i, c, ct; | ||
61 | |||
62 | if (!scc_initialized) | ||
63 | xmon_init_scc(); | ||
64 | |||
65 | return(xmon_8xx_write(ptr, nb)); | 33 | return(xmon_8xx_write(ptr, nb)); |
66 | } | 34 | } |
67 | 35 | ||
68 | int xmon_wants_key; | 36 | int xmon_readchar(void) |
69 | |||
70 | int | ||
71 | xmon_read(void *handle, void *ptr, int nb) | ||
72 | { | 37 | { |
73 | char *p = ptr; | 38 | return xmon_8xx_read_char(); |
74 | int i; | ||
75 | |||
76 | if (!scc_initialized) | ||
77 | xmon_init_scc(); | ||
78 | |||
79 | for (i = 0; i < nb; ++i) { | ||
80 | *p++ = xmon_8xx_read_char(); | ||
81 | } | ||
82 | return i; | ||
83 | } | 39 | } |
84 | 40 | ||
85 | int | 41 | int xmon_read_poll(void) |
86 | xmon_read_poll(void) | ||
87 | { | 42 | { |
88 | return(xmon_8xx_read_poll()); | 43 | return(xmon_8xx_read_poll()); |
89 | } | ||
90 | |||
91 | void | ||
92 | xmon_init_scc() | ||
93 | { | ||
94 | scc_initialized = 1; | ||
95 | } | ||
96 | |||
97 | #if 0 | ||
98 | extern int (*prom_entry)(void *); | ||
99 | |||
100 | int | ||
101 | xmon_exit(void) | ||
102 | { | ||
103 | struct prom_args { | ||
104 | char *service; | ||
105 | } args; | ||
106 | |||
107 | for (;;) { | ||
108 | args.service = "exit"; | ||
109 | (*prom_entry)(&args); | ||
110 | } | ||
111 | } | ||
112 | #endif | ||
113 | |||
114 | void *xmon_stdin; | ||
115 | void *xmon_stdout; | ||
116 | void *xmon_stderr; | ||
117 | |||
118 | void | ||
119 | xmon_init(void) | ||
120 | { | ||
121 | } | ||
122 | |||
123 | int | ||
124 | xmon_putc(int c, void *f) | ||
125 | { | ||
126 | char ch = c; | ||
127 | |||
128 | if (c == '\n') | ||
129 | xmon_putc('\r', f); | ||
130 | return xmon_write(f, &ch, 1) == 1? c: -1; | ||
131 | } | ||
132 | |||
133 | int | ||
134 | xmon_putchar(int c) | ||
135 | { | ||
136 | return xmon_putc(c, xmon_stdout); | ||
137 | } | ||
138 | |||
139 | int | ||
140 | xmon_fputs(char *str, void *f) | ||
141 | { | ||
142 | int n = strlen(str); | ||
143 | |||
144 | return xmon_write(f, str, n) == n? 0: -1; | ||
145 | } | ||
146 | |||
147 | int | ||
148 | xmon_readchar(void) | ||
149 | { | ||
150 | char ch; | ||
151 | |||
152 | for (;;) { | ||
153 | switch (xmon_read(xmon_stdin, &ch, 1)) { | ||
154 | case 1: | ||
155 | return ch; | ||
156 | case -1: | ||
157 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | ||
158 | return -1; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static char line[256]; | ||
164 | static char *lineptr; | ||
165 | static int lineleft; | ||
166 | |||
167 | #if 0 | ||
168 | int xmon_expect(const char *str, unsigned int timeout) | ||
169 | { | ||
170 | int c; | ||
171 | unsigned int t0; | ||
172 | |||
173 | timeout *= TB_SPEED; | ||
174 | t0 = readtb(); | ||
175 | do { | ||
176 | lineptr = line; | ||
177 | for (;;) { | ||
178 | c = xmon_read_poll(); | ||
179 | if (c == -1) { | ||
180 | if (readtb() - t0 > timeout) | ||
181 | return 0; | ||
182 | continue; | ||
183 | } | ||
184 | if (c == '\n') | ||
185 | break; | ||
186 | if (c != '\r' && lineptr < &line[sizeof(line) - 1]) | ||
187 | *lineptr++ = c; | ||
188 | } | ||
189 | *lineptr = 0; | ||
190 | } while (strstr(line, str) == NULL); | ||
191 | return 1; | ||
192 | } | ||
193 | #endif | ||
194 | |||
195 | int | ||
196 | xmon_getchar(void) | ||
197 | { | ||
198 | int c; | ||
199 | |||
200 | if (lineleft == 0) { | ||
201 | lineptr = line; | ||
202 | for (;;) { | ||
203 | c = xmon_readchar(); | ||
204 | if (c == -1 || c == 4) | ||
205 | break; | ||
206 | if (c == '\r' || c == '\n') { | ||
207 | *lineptr++ = '\n'; | ||
208 | xmon_putchar('\n'); | ||
209 | break; | ||
210 | } | ||
211 | switch (c) { | ||
212 | case 0177: | ||
213 | case '\b': | ||
214 | if (lineptr > line) { | ||
215 | xmon_putchar('\b'); | ||
216 | xmon_putchar(' '); | ||
217 | xmon_putchar('\b'); | ||
218 | --lineptr; | ||
219 | } | ||
220 | break; | ||
221 | case 'U' & 0x1F: | ||
222 | while (lineptr > line) { | ||
223 | xmon_putchar('\b'); | ||
224 | xmon_putchar(' '); | ||
225 | xmon_putchar('\b'); | ||
226 | --lineptr; | ||
227 | } | ||
228 | break; | ||
229 | default: | ||
230 | if (lineptr >= &line[sizeof(line) - 1]) | ||
231 | xmon_putchar('\a'); | ||
232 | else { | ||
233 | xmon_putchar(c); | ||
234 | *lineptr++ = c; | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | lineleft = lineptr - line; | ||
239 | lineptr = line; | ||
240 | } | ||
241 | if (lineleft == 0) | ||
242 | return -1; | ||
243 | --lineleft; | ||
244 | return *lineptr++; | ||
245 | } | ||
246 | |||
247 | char * | ||
248 | xmon_fgets(char *str, int nb, void *f) | ||
249 | { | ||
250 | char *p; | ||
251 | int c; | ||
252 | |||
253 | for (p = str; p < str + nb - 1; ) { | ||
254 | c = xmon_getchar(); | ||
255 | if (c == -1) { | ||
256 | if (p == str) | ||
257 | return 0; | ||
258 | break; | ||
259 | } | ||
260 | *p++ = c; | ||
261 | if (c == '\n') | ||
262 | break; | ||
263 | } | ||
264 | *p = 0; | ||
265 | return str; | ||
266 | } | ||
267 | |||
268 | void | ||
269 | prom_drawhex(uint val) | ||
270 | { | ||
271 | unsigned char buf[10]; | ||
272 | |||
273 | int i; | ||
274 | for (i = 7; i >= 0; i--) | ||
275 | { | ||
276 | buf[i] = "0123456789abcdef"[val & 0x0f]; | ||
277 | val >>= 4; | ||
278 | } | ||
279 | buf[8] = '\0'; | ||
280 | xmon_fputs(buf, xmon_stdout); | ||
281 | } | ||
282 | |||
283 | void | ||
284 | prom_drawstring(const char *str) | ||
285 | { | ||
286 | xmon_fputs(str, xmon_stdout); | ||
287 | } | 44 | } |
arch/powerpc/xmon/subr_prf.c
1 | /* | File was deleted | |
2 | * Written by Cort Dougan to replace the version originally used | ||
3 | * by Paul Mackerras, which came from NetBSD and thus had copyright | ||
4 | * conflicts with Linux. | ||
5 | * | ||
6 | * This file makes liberal use of the standard linux utility | ||
7 | * routines to reduce the size of the binary. We assume we can | ||
8 | * trust some parts of Linux inside the debugger. | ||
9 | * -- Cort (cort@cs.nmt.edu) | ||
10 | * | ||
11 | * Copyright (C) 1999 Cort Dougan. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version | ||
16 | * 2 of the License, or (at your option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <stdarg.h> | ||
23 | #include "nonstdio.h" | ||
24 | |||
25 | extern int xmon_write(void *, void *, int); | ||
26 | |||
27 | void xmon_vfprintf(void *f, const char *fmt, va_list ap) | ||
28 | { | ||
29 | static char xmon_buf[2048]; | ||
30 | int n; | ||
31 | |||
32 | n = vsprintf(xmon_buf, fmt, ap); | ||
33 | xmon_write(f, xmon_buf, n); | ||
34 | } | ||
35 | |||
36 | void xmon_printf(const char *fmt, ...) | ||
37 | { | ||
38 | va_list ap; | ||
39 | |||
40 | va_start(ap, fmt); | ||
41 | xmon_vfprintf(stdout, fmt, ap); | ||
42 | va_end(ap); | ||
43 | } | ||
44 | EXPORT_SYMBOL(xmon_printf); | ||
45 | |||
46 | void xmon_fprintf(void *f, const char *fmt, ...) | ||
47 | { | ||
48 | va_list ap; | ||
49 | |||
50 | va_start(ap, fmt); | ||
51 | xmon_vfprintf(f, fmt, ap); | ||
52 | va_end(ap); | ||
53 | } | ||
54 | 1 | /* | |
55 | 2 | * Written by Cort Dougan to replace the version originally used |
arch/powerpc/xmon/xmon.c
1 | /* | 1 | /* |
2 | * Routines providing a simple monitor for use on the PowerMac. | 2 | * Routines providing a simple monitor for use on the PowerMac. |
3 | * | 3 | * |
4 | * Copyright (C) 1996 Paul Mackerras. | 4 | * Copyright (C) 1996-2005 Paul Mackerras. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
14 | #include <linux/smp.h> | 14 | #include <linux/smp.h> |
15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
16 | #include <linux/reboot.h> | 16 | #include <linux/reboot.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/kallsyms.h> | 18 | #include <linux/kallsyms.h> |
19 | #include <linux/cpumask.h> | 19 | #include <linux/cpumask.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/sysrq.h> | ||
21 | 22 | ||
22 | #include <asm/ptrace.h> | 23 | #include <asm/ptrace.h> |
23 | #include <asm/string.h> | 24 | #include <asm/string.h> |
24 | #include <asm/prom.h> | 25 | #include <asm/prom.h> |
25 | #include <asm/machdep.h> | 26 | #include <asm/machdep.h> |
26 | #include <asm/xmon.h> | 27 | #include <asm/xmon.h> |
27 | #ifdef CONFIG_PMAC_BACKLIGHT | 28 | #ifdef CONFIG_PMAC_BACKLIGHT |
28 | #include <asm/backlight.h> | 29 | #include <asm/backlight.h> |
29 | #endif | 30 | #endif |
30 | #include <asm/processor.h> | 31 | #include <asm/processor.h> |
31 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
32 | #include <asm/mmu.h> | 33 | #include <asm/mmu.h> |
33 | #include <asm/mmu_context.h> | 34 | #include <asm/mmu_context.h> |
34 | #include <asm/cputable.h> | 35 | #include <asm/cputable.h> |
35 | #include <asm/rtas.h> | 36 | #include <asm/rtas.h> |
36 | #include <asm/sstep.h> | 37 | #include <asm/sstep.h> |
37 | #include <asm/bug.h> | 38 | #include <asm/bug.h> |
38 | 39 | ||
39 | #ifdef CONFIG_PPC64 | 40 | #ifdef CONFIG_PPC64 |
40 | #include <asm/hvcall.h> | 41 | #include <asm/hvcall.h> |
41 | #include <asm/paca.h> | 42 | #include <asm/paca.h> |
42 | #endif | 43 | #endif |
43 | 44 | ||
44 | #include "nonstdio.h" | 45 | #include "nonstdio.h" |
45 | 46 | ||
46 | #define scanhex xmon_scanhex | 47 | #define scanhex xmon_scanhex |
47 | #define skipbl xmon_skipbl | 48 | #define skipbl xmon_skipbl |
48 | 49 | ||
49 | #ifdef CONFIG_SMP | 50 | #ifdef CONFIG_SMP |
50 | cpumask_t cpus_in_xmon = CPU_MASK_NONE; | 51 | cpumask_t cpus_in_xmon = CPU_MASK_NONE; |
51 | static unsigned long xmon_taken = 1; | 52 | static unsigned long xmon_taken = 1; |
52 | static int xmon_owner; | 53 | static int xmon_owner; |
53 | static int xmon_gate; | 54 | static int xmon_gate; |
54 | #endif /* CONFIG_SMP */ | 55 | #endif /* CONFIG_SMP */ |
55 | 56 | ||
56 | static unsigned long in_xmon = 0; | 57 | static unsigned long in_xmon = 0; |
57 | 58 | ||
58 | static unsigned long adrs; | 59 | static unsigned long adrs; |
59 | static int size = 1; | 60 | static int size = 1; |
60 | #define MAX_DUMP (128 * 1024) | 61 | #define MAX_DUMP (128 * 1024) |
61 | static unsigned long ndump = 64; | 62 | static unsigned long ndump = 64; |
62 | static unsigned long nidump = 16; | 63 | static unsigned long nidump = 16; |
63 | static unsigned long ncsum = 4096; | 64 | static unsigned long ncsum = 4096; |
64 | static int termch; | 65 | static int termch; |
65 | static char tmpstr[128]; | 66 | static char tmpstr[128]; |
66 | 67 | ||
67 | #define JMP_BUF_LEN 23 | 68 | #define JMP_BUF_LEN 23 |
68 | static long bus_error_jmp[JMP_BUF_LEN]; | 69 | static long bus_error_jmp[JMP_BUF_LEN]; |
69 | static int catch_memory_errors; | 70 | static int catch_memory_errors; |
70 | static long *xmon_fault_jmp[NR_CPUS]; | 71 | static long *xmon_fault_jmp[NR_CPUS]; |
71 | #define setjmp xmon_setjmp | 72 | #define setjmp xmon_setjmp |
72 | #define longjmp xmon_longjmp | 73 | #define longjmp xmon_longjmp |
73 | 74 | ||
74 | /* Breakpoint stuff */ | 75 | /* Breakpoint stuff */ |
75 | struct bpt { | 76 | struct bpt { |
76 | unsigned long address; | 77 | unsigned long address; |
77 | unsigned int instr[2]; | 78 | unsigned int instr[2]; |
78 | atomic_t ref_count; | 79 | atomic_t ref_count; |
79 | int enabled; | 80 | int enabled; |
80 | unsigned long pad; | 81 | unsigned long pad; |
81 | }; | 82 | }; |
82 | 83 | ||
83 | /* Bits in bpt.enabled */ | 84 | /* Bits in bpt.enabled */ |
84 | #define BP_IABR_TE 1 /* IABR translation enabled */ | 85 | #define BP_IABR_TE 1 /* IABR translation enabled */ |
85 | #define BP_IABR 2 | 86 | #define BP_IABR 2 |
86 | #define BP_TRAP 8 | 87 | #define BP_TRAP 8 |
87 | #define BP_DABR 0x10 | 88 | #define BP_DABR 0x10 |
88 | 89 | ||
89 | #define NBPTS 256 | 90 | #define NBPTS 256 |
90 | static struct bpt bpts[NBPTS]; | 91 | static struct bpt bpts[NBPTS]; |
91 | static struct bpt dabr; | 92 | static struct bpt dabr; |
92 | static struct bpt *iabr; | 93 | static struct bpt *iabr; |
93 | static unsigned bpinstr = 0x7fe00008; /* trap */ | 94 | static unsigned bpinstr = 0x7fe00008; /* trap */ |
94 | 95 | ||
95 | #define BP_NUM(bp) ((bp) - bpts + 1) | 96 | #define BP_NUM(bp) ((bp) - bpts + 1) |
96 | 97 | ||
97 | /* Prototypes */ | 98 | /* Prototypes */ |
98 | static int cmds(struct pt_regs *); | 99 | static int cmds(struct pt_regs *); |
99 | static int mread(unsigned long, void *, int); | 100 | static int mread(unsigned long, void *, int); |
100 | static int mwrite(unsigned long, void *, int); | 101 | static int mwrite(unsigned long, void *, int); |
101 | static int handle_fault(struct pt_regs *); | 102 | static int handle_fault(struct pt_regs *); |
102 | static void byterev(unsigned char *, int); | 103 | static void byterev(unsigned char *, int); |
103 | static void memex(void); | 104 | static void memex(void); |
104 | static int bsesc(void); | 105 | static int bsesc(void); |
105 | static void dump(void); | 106 | static void dump(void); |
106 | static void prdump(unsigned long, long); | 107 | static void prdump(unsigned long, long); |
107 | static int ppc_inst_dump(unsigned long, long, int); | 108 | static int ppc_inst_dump(unsigned long, long, int); |
108 | void print_address(unsigned long); | 109 | void print_address(unsigned long); |
109 | static void backtrace(struct pt_regs *); | 110 | static void backtrace(struct pt_regs *); |
110 | static void excprint(struct pt_regs *); | 111 | static void excprint(struct pt_regs *); |
111 | static void prregs(struct pt_regs *); | 112 | static void prregs(struct pt_regs *); |
112 | static void memops(int); | 113 | static void memops(int); |
113 | static void memlocate(void); | 114 | static void memlocate(void); |
114 | static void memzcan(void); | 115 | static void memzcan(void); |
115 | static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned); | 116 | static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned); |
116 | int skipbl(void); | 117 | int skipbl(void); |
117 | int scanhex(unsigned long *valp); | 118 | int scanhex(unsigned long *valp); |
118 | static void scannl(void); | 119 | static void scannl(void); |
119 | static int hexdigit(int); | 120 | static int hexdigit(int); |
120 | void getstring(char *, int); | 121 | void getstring(char *, int); |
121 | static void flush_input(void); | 122 | static void flush_input(void); |
122 | static int inchar(void); | 123 | static int inchar(void); |
123 | static void take_input(char *); | 124 | static void take_input(char *); |
124 | static unsigned long read_spr(int); | 125 | static unsigned long read_spr(int); |
125 | static void write_spr(int, unsigned long); | 126 | static void write_spr(int, unsigned long); |
126 | static void super_regs(void); | 127 | static void super_regs(void); |
127 | static void remove_bpts(void); | 128 | static void remove_bpts(void); |
128 | static void insert_bpts(void); | 129 | static void insert_bpts(void); |
129 | static void remove_cpu_bpts(void); | 130 | static void remove_cpu_bpts(void); |
130 | static void insert_cpu_bpts(void); | 131 | static void insert_cpu_bpts(void); |
131 | static struct bpt *at_breakpoint(unsigned long pc); | 132 | static struct bpt *at_breakpoint(unsigned long pc); |
132 | static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp); | 133 | static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp); |
133 | static int do_step(struct pt_regs *); | 134 | static int do_step(struct pt_regs *); |
134 | static void bpt_cmds(void); | 135 | static void bpt_cmds(void); |
135 | static void cacheflush(void); | 136 | static void cacheflush(void); |
136 | static int cpu_cmd(void); | 137 | static int cpu_cmd(void); |
137 | static void csum(void); | 138 | static void csum(void); |
138 | static void bootcmds(void); | 139 | static void bootcmds(void); |
139 | static void proccall(void); | 140 | static void proccall(void); |
140 | void dump_segments(void); | 141 | void dump_segments(void); |
141 | static void symbol_lookup(void); | 142 | static void symbol_lookup(void); |
142 | static void xmon_print_symbol(unsigned long address, const char *mid, | 143 | static void xmon_print_symbol(unsigned long address, const char *mid, |
143 | const char *after); | 144 | const char *after); |
144 | static const char *getvecname(unsigned long vec); | 145 | static const char *getvecname(unsigned long vec); |
145 | 146 | ||
146 | extern int print_insn_powerpc(unsigned long, unsigned long, int); | 147 | extern int print_insn_powerpc(unsigned long, unsigned long, int); |
147 | extern void printf(const char *fmt, ...); | ||
148 | extern void xmon_vfprintf(void *f, const char *fmt, va_list ap); | ||
149 | extern int xmon_putc(int c, void *f); | ||
150 | extern int putchar(int ch); | ||
151 | 148 | ||
152 | extern void xmon_enter(void); | 149 | extern void xmon_enter(void); |
153 | extern void xmon_leave(void); | 150 | extern void xmon_leave(void); |
154 | 151 | ||
155 | extern int xmon_read_poll(void); | ||
156 | extern long setjmp(long *); | 152 | extern long setjmp(long *); |
157 | extern void longjmp(long *, long); | 153 | extern void longjmp(long *, long); |
158 | extern void xmon_save_regs(struct pt_regs *); | 154 | extern void xmon_save_regs(struct pt_regs *); |
159 | 155 | ||
160 | #ifdef CONFIG_PPC64 | 156 | #ifdef CONFIG_PPC64 |
161 | #define REG "%.16lx" | 157 | #define REG "%.16lx" |
162 | #define REGS_PER_LINE 4 | 158 | #define REGS_PER_LINE 4 |
163 | #define LAST_VOLATILE 13 | 159 | #define LAST_VOLATILE 13 |
164 | #else | 160 | #else |
165 | #define REG "%.8lx" | 161 | #define REG "%.8lx" |
166 | #define REGS_PER_LINE 8 | 162 | #define REGS_PER_LINE 8 |
167 | #define LAST_VOLATILE 12 | 163 | #define LAST_VOLATILE 12 |
168 | #endif | 164 | #endif |
169 | 165 | ||
170 | #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) | 166 | #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) |
171 | 167 | ||
172 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ | 168 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ |
173 | || ('a' <= (c) && (c) <= 'f') \ | 169 | || ('a' <= (c) && (c) <= 'f') \ |
174 | || ('A' <= (c) && (c) <= 'F')) | 170 | || ('A' <= (c) && (c) <= 'F')) |
175 | #define isalnum(c) (('0' <= (c) && (c) <= '9') \ | 171 | #define isalnum(c) (('0' <= (c) && (c) <= '9') \ |
176 | || ('a' <= (c) && (c) <= 'z') \ | 172 | || ('a' <= (c) && (c) <= 'z') \ |
177 | || ('A' <= (c) && (c) <= 'Z')) | 173 | || ('A' <= (c) && (c) <= 'Z')) |
178 | #define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0) | 174 | #define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0) |
179 | 175 | ||
180 | static char *help_string = "\ | 176 | static char *help_string = "\ |
181 | Commands:\n\ | 177 | Commands:\n\ |
182 | b show breakpoints\n\ | 178 | b show breakpoints\n\ |
183 | bd set data breakpoint\n\ | 179 | bd set data breakpoint\n\ |
184 | bi set instruction breakpoint\n\ | 180 | bi set instruction breakpoint\n\ |
185 | bc clear breakpoint\n" | 181 | bc clear breakpoint\n" |
186 | #ifdef CONFIG_SMP | 182 | #ifdef CONFIG_SMP |
187 | "\ | 183 | "\ |
188 | c print cpus stopped in xmon\n\ | 184 | c print cpus stopped in xmon\n\ |
189 | c# try to switch to cpu number h (in hex)\n" | 185 | c# try to switch to cpu number h (in hex)\n" |
190 | #endif | 186 | #endif |
191 | "\ | 187 | "\ |
192 | C checksum\n\ | 188 | C checksum\n\ |
193 | d dump bytes\n\ | 189 | d dump bytes\n\ |
194 | di dump instructions\n\ | 190 | di dump instructions\n\ |
195 | df dump float values\n\ | 191 | df dump float values\n\ |
196 | dd dump double values\n\ | 192 | dd dump double values\n\ |
197 | e print exception information\n\ | 193 | e print exception information\n\ |
198 | f flush cache\n\ | 194 | f flush cache\n\ |
199 | la lookup symbol+offset of specified address\n\ | 195 | la lookup symbol+offset of specified address\n\ |
200 | ls lookup address of specified symbol\n\ | 196 | ls lookup address of specified symbol\n\ |
201 | m examine/change memory\n\ | 197 | m examine/change memory\n\ |
202 | mm move a block of memory\n\ | 198 | mm move a block of memory\n\ |
203 | ms set a block of memory\n\ | 199 | ms set a block of memory\n\ |
204 | md compare two blocks of memory\n\ | 200 | md compare two blocks of memory\n\ |
205 | ml locate a block of memory\n\ | 201 | ml locate a block of memory\n\ |
206 | mz zero a block of memory\n\ | 202 | mz zero a block of memory\n\ |
207 | mi show information about memory allocation\n\ | 203 | mi show information about memory allocation\n\ |
208 | p call a procedure\n\ | 204 | p call a procedure\n\ |
209 | r print registers\n\ | 205 | r print registers\n\ |
210 | s single step\n\ | 206 | s single step\n\ |
211 | S print special registers\n\ | 207 | S print special registers\n\ |
212 | t print backtrace\n\ | 208 | t print backtrace\n\ |
213 | x exit monitor and recover\n\ | 209 | x exit monitor and recover\n\ |
214 | X exit monitor and dont recover\n" | 210 | X exit monitor and dont recover\n" |
215 | #ifdef CONFIG_PPC64 | 211 | #ifdef CONFIG_PPC64 |
216 | " u dump segment table or SLB\n" | 212 | " u dump segment table or SLB\n" |
217 | #endif | 213 | #endif |
218 | #ifdef CONFIG_PPC_STD_MMU_32 | 214 | #ifdef CONFIG_PPC_STD_MMU_32 |
219 | " u dump segment registers\n" | 215 | " u dump segment registers\n" |
220 | #endif | 216 | #endif |
221 | " ? help\n" | 217 | " ? help\n" |
222 | " zr reboot\n\ | 218 | " zr reboot\n\ |
223 | zh halt\n" | 219 | zh halt\n" |
224 | ; | 220 | ; |
225 | 221 | ||
226 | static struct pt_regs *xmon_regs; | 222 | static struct pt_regs *xmon_regs; |
227 | 223 | ||
228 | static inline void sync(void) | 224 | static inline void sync(void) |
229 | { | 225 | { |
230 | asm volatile("sync; isync"); | 226 | asm volatile("sync; isync"); |
231 | } | 227 | } |
232 | 228 | ||
233 | static inline void store_inst(void *p) | 229 | static inline void store_inst(void *p) |
234 | { | 230 | { |
235 | asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p)); | 231 | asm volatile ("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r" (p)); |
236 | } | 232 | } |
237 | 233 | ||
238 | static inline void cflush(void *p) | 234 | static inline void cflush(void *p) |
239 | { | 235 | { |
240 | asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p)); | 236 | asm volatile ("dcbf 0,%0; icbi 0,%0" : : "r" (p)); |
241 | } | 237 | } |
242 | 238 | ||
243 | static inline void cinval(void *p) | 239 | static inline void cinval(void *p) |
244 | { | 240 | { |
245 | asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); | 241 | asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p)); |
246 | } | 242 | } |
247 | 243 | ||
248 | /* | 244 | /* |
249 | * Disable surveillance (the service processor watchdog function) | 245 | * Disable surveillance (the service processor watchdog function) |
250 | * while we are in xmon. | 246 | * while we are in xmon. |
251 | * XXX we should re-enable it when we leave. :) | 247 | * XXX we should re-enable it when we leave. :) |
252 | */ | 248 | */ |
253 | #define SURVEILLANCE_TOKEN 9000 | 249 | #define SURVEILLANCE_TOKEN 9000 |
254 | 250 | ||
255 | static inline void disable_surveillance(void) | 251 | static inline void disable_surveillance(void) |
256 | { | 252 | { |
257 | #ifdef CONFIG_PPC_PSERIES | 253 | #ifdef CONFIG_PPC_PSERIES |
258 | /* Since this can't be a module, args should end up below 4GB. */ | 254 | /* Since this can't be a module, args should end up below 4GB. */ |
259 | static struct rtas_args args; | 255 | static struct rtas_args args; |
260 | 256 | ||
261 | /* | 257 | /* |
262 | * At this point we have got all the cpus we can into | 258 | * At this point we have got all the cpus we can into |
263 | * xmon, so there is hopefully no other cpu calling RTAS | 259 | * xmon, so there is hopefully no other cpu calling RTAS |
264 | * at the moment, even though we don't take rtas.lock. | 260 | * at the moment, even though we don't take rtas.lock. |
265 | * If we did try to take rtas.lock there would be a | 261 | * If we did try to take rtas.lock there would be a |
266 | * real possibility of deadlock. | 262 | * real possibility of deadlock. |
267 | */ | 263 | */ |
268 | args.token = rtas_token("set-indicator"); | 264 | args.token = rtas_token("set-indicator"); |
269 | if (args.token == RTAS_UNKNOWN_SERVICE) | 265 | if (args.token == RTAS_UNKNOWN_SERVICE) |
270 | return; | 266 | return; |
271 | args.nargs = 3; | 267 | args.nargs = 3; |
272 | args.nret = 1; | 268 | args.nret = 1; |
273 | args.rets = &args.args[3]; | 269 | args.rets = &args.args[3]; |
274 | args.args[0] = SURVEILLANCE_TOKEN; | 270 | args.args[0] = SURVEILLANCE_TOKEN; |
275 | args.args[1] = 0; | 271 | args.args[1] = 0; |
276 | args.args[2] = 0; | 272 | args.args[2] = 0; |
277 | enter_rtas(__pa(&args)); | 273 | enter_rtas(__pa(&args)); |
278 | #endif /* CONFIG_PPC_PSERIES */ | 274 | #endif /* CONFIG_PPC_PSERIES */ |
279 | } | 275 | } |
280 | 276 | ||
281 | #ifdef CONFIG_SMP | 277 | #ifdef CONFIG_SMP |
282 | static int xmon_speaker; | 278 | static int xmon_speaker; |
283 | 279 | ||
284 | static void get_output_lock(void) | 280 | static void get_output_lock(void) |
285 | { | 281 | { |
286 | int me = smp_processor_id() + 0x100; | 282 | int me = smp_processor_id() + 0x100; |
287 | int last_speaker = 0, prev; | 283 | int last_speaker = 0, prev; |
288 | long timeout; | 284 | long timeout; |
289 | 285 | ||
290 | if (xmon_speaker == me) | 286 | if (xmon_speaker == me) |
291 | return; | 287 | return; |
292 | for (;;) { | 288 | for (;;) { |
293 | if (xmon_speaker == 0) { | 289 | if (xmon_speaker == 0) { |
294 | last_speaker = cmpxchg(&xmon_speaker, 0, me); | 290 | last_speaker = cmpxchg(&xmon_speaker, 0, me); |
295 | if (last_speaker == 0) | 291 | if (last_speaker == 0) |
296 | return; | 292 | return; |
297 | } | 293 | } |
298 | timeout = 10000000; | 294 | timeout = 10000000; |
299 | while (xmon_speaker == last_speaker) { | 295 | while (xmon_speaker == last_speaker) { |
300 | if (--timeout > 0) | 296 | if (--timeout > 0) |
301 | continue; | 297 | continue; |
302 | /* hostile takeover */ | 298 | /* hostile takeover */ |
303 | prev = cmpxchg(&xmon_speaker, last_speaker, me); | 299 | prev = cmpxchg(&xmon_speaker, last_speaker, me); |
304 | if (prev == last_speaker) | 300 | if (prev == last_speaker) |
305 | return; | 301 | return; |
306 | break; | 302 | break; |
307 | } | 303 | } |
308 | } | 304 | } |
309 | } | 305 | } |
310 | 306 | ||
311 | static void release_output_lock(void) | 307 | static void release_output_lock(void) |
312 | { | 308 | { |
313 | xmon_speaker = 0; | 309 | xmon_speaker = 0; |
314 | } | 310 | } |
315 | #endif | 311 | #endif |
316 | 312 | ||
317 | int xmon_core(struct pt_regs *regs, int fromipi) | 313 | int xmon_core(struct pt_regs *regs, int fromipi) |
318 | { | 314 | { |
319 | int cmd = 0; | 315 | int cmd = 0; |
320 | unsigned long msr; | 316 | unsigned long msr; |
321 | struct bpt *bp; | 317 | struct bpt *bp; |
322 | long recurse_jmp[JMP_BUF_LEN]; | 318 | long recurse_jmp[JMP_BUF_LEN]; |
323 | unsigned long offset; | 319 | unsigned long offset; |
324 | #ifdef CONFIG_SMP | 320 | #ifdef CONFIG_SMP |
325 | int cpu; | 321 | int cpu; |
326 | int secondary; | 322 | int secondary; |
327 | unsigned long timeout; | 323 | unsigned long timeout; |
328 | #endif | 324 | #endif |
329 | 325 | ||
330 | msr = mfmsr(); | 326 | msr = mfmsr(); |
331 | mtmsr(msr & ~MSR_EE); /* disable interrupts */ | 327 | mtmsr(msr & ~MSR_EE); /* disable interrupts */ |
332 | 328 | ||
333 | bp = in_breakpoint_table(regs->nip, &offset); | 329 | bp = in_breakpoint_table(regs->nip, &offset); |
334 | if (bp != NULL) { | 330 | if (bp != NULL) { |
335 | regs->nip = bp->address + offset; | 331 | regs->nip = bp->address + offset; |
336 | atomic_dec(&bp->ref_count); | 332 | atomic_dec(&bp->ref_count); |
337 | } | 333 | } |
338 | 334 | ||
339 | remove_cpu_bpts(); | 335 | remove_cpu_bpts(); |
340 | 336 | ||
341 | #ifdef CONFIG_SMP | 337 | #ifdef CONFIG_SMP |
342 | cpu = smp_processor_id(); | 338 | cpu = smp_processor_id(); |
343 | if (cpu_isset(cpu, cpus_in_xmon)) { | 339 | if (cpu_isset(cpu, cpus_in_xmon)) { |
344 | get_output_lock(); | 340 | get_output_lock(); |
345 | excprint(regs); | 341 | excprint(regs); |
346 | printf("cpu 0x%x: Exception %lx %s in xmon, " | 342 | printf("cpu 0x%x: Exception %lx %s in xmon, " |
347 | "returning to main loop\n", | 343 | "returning to main loop\n", |
348 | cpu, regs->trap, getvecname(TRAP(regs))); | 344 | cpu, regs->trap, getvecname(TRAP(regs))); |
349 | release_output_lock(); | 345 | release_output_lock(); |
350 | longjmp(xmon_fault_jmp[cpu], 1); | 346 | longjmp(xmon_fault_jmp[cpu], 1); |
351 | } | 347 | } |
352 | 348 | ||
353 | if (setjmp(recurse_jmp) != 0) { | 349 | if (setjmp(recurse_jmp) != 0) { |
354 | if (!in_xmon || !xmon_gate) { | 350 | if (!in_xmon || !xmon_gate) { |
355 | get_output_lock(); | 351 | get_output_lock(); |
356 | printf("xmon: WARNING: bad recursive fault " | 352 | printf("xmon: WARNING: bad recursive fault " |
357 | "on cpu 0x%x\n", cpu); | 353 | "on cpu 0x%x\n", cpu); |
358 | release_output_lock(); | 354 | release_output_lock(); |
359 | goto waiting; | 355 | goto waiting; |
360 | } | 356 | } |
361 | secondary = !(xmon_taken && cpu == xmon_owner); | 357 | secondary = !(xmon_taken && cpu == xmon_owner); |
362 | goto cmdloop; | 358 | goto cmdloop; |
363 | } | 359 | } |
364 | 360 | ||
365 | xmon_fault_jmp[cpu] = recurse_jmp; | 361 | xmon_fault_jmp[cpu] = recurse_jmp; |
366 | cpu_set(cpu, cpus_in_xmon); | 362 | cpu_set(cpu, cpus_in_xmon); |
367 | 363 | ||
368 | bp = NULL; | 364 | bp = NULL; |
369 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) | 365 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) |
370 | bp = at_breakpoint(regs->nip); | 366 | bp = at_breakpoint(regs->nip); |
371 | if (bp || (regs->msr & MSR_RI) == 0) | 367 | if (bp || (regs->msr & MSR_RI) == 0) |
372 | fromipi = 0; | 368 | fromipi = 0; |
373 | 369 | ||
374 | if (!fromipi) { | 370 | if (!fromipi) { |
375 | get_output_lock(); | 371 | get_output_lock(); |
376 | excprint(regs); | 372 | excprint(regs); |
377 | if (bp) { | 373 | if (bp) { |
378 | printf("cpu 0x%x stopped at breakpoint 0x%x (", | 374 | printf("cpu 0x%x stopped at breakpoint 0x%x (", |
379 | cpu, BP_NUM(bp)); | 375 | cpu, BP_NUM(bp)); |
380 | xmon_print_symbol(regs->nip, " ", ")\n"); | 376 | xmon_print_symbol(regs->nip, " ", ")\n"); |
381 | } | 377 | } |
382 | if ((regs->msr & MSR_RI) == 0) | 378 | if ((regs->msr & MSR_RI) == 0) |
383 | printf("WARNING: exception is not recoverable, " | 379 | printf("WARNING: exception is not recoverable, " |
384 | "can't continue\n"); | 380 | "can't continue\n"); |
385 | release_output_lock(); | 381 | release_output_lock(); |
386 | } | 382 | } |
387 | 383 | ||
388 | waiting: | 384 | waiting: |
389 | secondary = 1; | 385 | secondary = 1; |
390 | while (secondary && !xmon_gate) { | 386 | while (secondary && !xmon_gate) { |
391 | if (in_xmon == 0) { | 387 | if (in_xmon == 0) { |
392 | if (fromipi) | 388 | if (fromipi) |
393 | goto leave; | 389 | goto leave; |
394 | secondary = test_and_set_bit(0, &in_xmon); | 390 | secondary = test_and_set_bit(0, &in_xmon); |
395 | } | 391 | } |
396 | barrier(); | 392 | barrier(); |
397 | } | 393 | } |
398 | 394 | ||
399 | if (!secondary && !xmon_gate) { | 395 | if (!secondary && !xmon_gate) { |
400 | /* we are the first cpu to come in */ | 396 | /* we are the first cpu to come in */ |
401 | /* interrupt other cpu(s) */ | 397 | /* interrupt other cpu(s) */ |
402 | int ncpus = num_online_cpus(); | 398 | int ncpus = num_online_cpus(); |
403 | 399 | ||
404 | xmon_owner = cpu; | 400 | xmon_owner = cpu; |
405 | mb(); | 401 | mb(); |
406 | if (ncpus > 1) { | 402 | if (ncpus > 1) { |
407 | smp_send_debugger_break(MSG_ALL_BUT_SELF); | 403 | smp_send_debugger_break(MSG_ALL_BUT_SELF); |
408 | /* wait for other cpus to come in */ | 404 | /* wait for other cpus to come in */ |
409 | for (timeout = 100000000; timeout != 0; --timeout) { | 405 | for (timeout = 100000000; timeout != 0; --timeout) { |
410 | if (cpus_weight(cpus_in_xmon) >= ncpus) | 406 | if (cpus_weight(cpus_in_xmon) >= ncpus) |
411 | break; | 407 | break; |
412 | barrier(); | 408 | barrier(); |
413 | } | 409 | } |
414 | } | 410 | } |
415 | remove_bpts(); | 411 | remove_bpts(); |
416 | disable_surveillance(); | 412 | disable_surveillance(); |
417 | /* for breakpoint or single step, print the current instr. */ | 413 | /* for breakpoint or single step, print the current instr. */ |
418 | if (bp || TRAP(regs) == 0xd00) | 414 | if (bp || TRAP(regs) == 0xd00) |
419 | ppc_inst_dump(regs->nip, 1, 0); | 415 | ppc_inst_dump(regs->nip, 1, 0); |
420 | printf("enter ? for help\n"); | 416 | printf("enter ? for help\n"); |
421 | mb(); | 417 | mb(); |
422 | xmon_gate = 1; | 418 | xmon_gate = 1; |
423 | barrier(); | 419 | barrier(); |
424 | } | 420 | } |
425 | 421 | ||
426 | cmdloop: | 422 | cmdloop: |
427 | while (in_xmon) { | 423 | while (in_xmon) { |
428 | if (secondary) { | 424 | if (secondary) { |
429 | if (cpu == xmon_owner) { | 425 | if (cpu == xmon_owner) { |
430 | if (!test_and_set_bit(0, &xmon_taken)) { | 426 | if (!test_and_set_bit(0, &xmon_taken)) { |
431 | secondary = 0; | 427 | secondary = 0; |
432 | continue; | 428 | continue; |
433 | } | 429 | } |
434 | /* missed it */ | 430 | /* missed it */ |
435 | while (cpu == xmon_owner) | 431 | while (cpu == xmon_owner) |
436 | barrier(); | 432 | barrier(); |
437 | } | 433 | } |
438 | barrier(); | 434 | barrier(); |
439 | } else { | 435 | } else { |
440 | cmd = cmds(regs); | 436 | cmd = cmds(regs); |
441 | if (cmd != 0) { | 437 | if (cmd != 0) { |
442 | /* exiting xmon */ | 438 | /* exiting xmon */ |
443 | insert_bpts(); | 439 | insert_bpts(); |
444 | xmon_gate = 0; | 440 | xmon_gate = 0; |
445 | wmb(); | 441 | wmb(); |
446 | in_xmon = 0; | 442 | in_xmon = 0; |
447 | break; | 443 | break; |
448 | } | 444 | } |
449 | /* have switched to some other cpu */ | 445 | /* have switched to some other cpu */ |
450 | secondary = 1; | 446 | secondary = 1; |
451 | } | 447 | } |
452 | } | 448 | } |
453 | leave: | 449 | leave: |
454 | cpu_clear(cpu, cpus_in_xmon); | 450 | cpu_clear(cpu, cpus_in_xmon); |
455 | xmon_fault_jmp[cpu] = NULL; | 451 | xmon_fault_jmp[cpu] = NULL; |
456 | 452 | ||
457 | #else | 453 | #else |
458 | /* UP is simple... */ | 454 | /* UP is simple... */ |
459 | if (in_xmon) { | 455 | if (in_xmon) { |
460 | printf("Exception %lx %s in xmon, returning to main loop\n", | 456 | printf("Exception %lx %s in xmon, returning to main loop\n", |
461 | regs->trap, getvecname(TRAP(regs))); | 457 | regs->trap, getvecname(TRAP(regs))); |
462 | longjmp(xmon_fault_jmp[0], 1); | 458 | longjmp(xmon_fault_jmp[0], 1); |
463 | } | 459 | } |
464 | if (setjmp(recurse_jmp) == 0) { | 460 | if (setjmp(recurse_jmp) == 0) { |
465 | xmon_fault_jmp[0] = recurse_jmp; | 461 | xmon_fault_jmp[0] = recurse_jmp; |
466 | in_xmon = 1; | 462 | in_xmon = 1; |
467 | 463 | ||
468 | excprint(regs); | 464 | excprint(regs); |
469 | bp = at_breakpoint(regs->nip); | 465 | bp = at_breakpoint(regs->nip); |
470 | if (bp) { | 466 | if (bp) { |
471 | printf("Stopped at breakpoint %x (", BP_NUM(bp)); | 467 | printf("Stopped at breakpoint %x (", BP_NUM(bp)); |
472 | xmon_print_symbol(regs->nip, " ", ")\n"); | 468 | xmon_print_symbol(regs->nip, " ", ")\n"); |
473 | } | 469 | } |
474 | if ((regs->msr & MSR_RI) == 0) | 470 | if ((regs->msr & MSR_RI) == 0) |
475 | printf("WARNING: exception is not recoverable, " | 471 | printf("WARNING: exception is not recoverable, " |
476 | "can't continue\n"); | 472 | "can't continue\n"); |
477 | remove_bpts(); | 473 | remove_bpts(); |
478 | disable_surveillance(); | 474 | disable_surveillance(); |
479 | /* for breakpoint or single step, print the current instr. */ | 475 | /* for breakpoint or single step, print the current instr. */ |
480 | if (bp || TRAP(regs) == 0xd00) | 476 | if (bp || TRAP(regs) == 0xd00) |
481 | ppc_inst_dump(regs->nip, 1, 0); | 477 | ppc_inst_dump(regs->nip, 1, 0); |
482 | printf("enter ? for help\n"); | 478 | printf("enter ? for help\n"); |
483 | } | 479 | } |
484 | 480 | ||
485 | cmd = cmds(regs); | 481 | cmd = cmds(regs); |
486 | 482 | ||
487 | insert_bpts(); | 483 | insert_bpts(); |
488 | in_xmon = 0; | 484 | in_xmon = 0; |
489 | #endif | 485 | #endif |
490 | 486 | ||
491 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { | 487 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { |
492 | bp = at_breakpoint(regs->nip); | 488 | bp = at_breakpoint(regs->nip); |
493 | if (bp != NULL) { | 489 | if (bp != NULL) { |
494 | int stepped = emulate_step(regs, bp->instr[0]); | 490 | int stepped = emulate_step(regs, bp->instr[0]); |
495 | if (stepped == 0) { | 491 | if (stepped == 0) { |
496 | regs->nip = (unsigned long) &bp->instr[0]; | 492 | regs->nip = (unsigned long) &bp->instr[0]; |
497 | atomic_inc(&bp->ref_count); | 493 | atomic_inc(&bp->ref_count); |
498 | } else if (stepped < 0) { | 494 | } else if (stepped < 0) { |
499 | printf("Couldn't single-step %s instruction\n", | 495 | printf("Couldn't single-step %s instruction\n", |
500 | (IS_RFID(bp->instr[0])? "rfid": "mtmsrd")); | 496 | (IS_RFID(bp->instr[0])? "rfid": "mtmsrd")); |
501 | } | 497 | } |
502 | } | 498 | } |
503 | } | 499 | } |
504 | 500 | ||
505 | insert_cpu_bpts(); | 501 | insert_cpu_bpts(); |
506 | 502 | ||
507 | mtmsr(msr); /* restore interrupt enable */ | 503 | mtmsr(msr); /* restore interrupt enable */ |
508 | 504 | ||
509 | return cmd != 'X'; | 505 | return cmd != 'X'; |
510 | } | 506 | } |
511 | 507 | ||
512 | int xmon(struct pt_regs *excp) | 508 | int xmon(struct pt_regs *excp) |
513 | { | 509 | { |
514 | struct pt_regs regs; | 510 | struct pt_regs regs; |
515 | 511 | ||
516 | if (excp == NULL) { | 512 | if (excp == NULL) { |
517 | xmon_save_regs(®s); | 513 | xmon_save_regs(®s); |
518 | excp = ®s; | 514 | excp = ®s; |
519 | } | 515 | } |
520 | return xmon_core(excp, 0); | 516 | return xmon_core(excp, 0); |
521 | } | 517 | } |
522 | EXPORT_SYMBOL(xmon); | 518 | EXPORT_SYMBOL(xmon); |
523 | 519 | ||
524 | irqreturn_t | 520 | irqreturn_t |
525 | xmon_irq(int irq, void *d, struct pt_regs *regs) | 521 | xmon_irq(int irq, void *d, struct pt_regs *regs) |
526 | { | 522 | { |
527 | unsigned long flags; | 523 | unsigned long flags; |
528 | local_irq_save(flags); | 524 | local_irq_save(flags); |
529 | printf("Keyboard interrupt\n"); | 525 | printf("Keyboard interrupt\n"); |
530 | xmon(regs); | 526 | xmon(regs); |
531 | local_irq_restore(flags); | 527 | local_irq_restore(flags); |
532 | return IRQ_HANDLED; | 528 | return IRQ_HANDLED; |
533 | } | 529 | } |
534 | 530 | ||
535 | int xmon_bpt(struct pt_regs *regs) | 531 | int xmon_bpt(struct pt_regs *regs) |
536 | { | 532 | { |
537 | struct bpt *bp; | 533 | struct bpt *bp; |
538 | unsigned long offset; | 534 | unsigned long offset; |
539 | 535 | ||
540 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) | 536 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) |
541 | return 0; | 537 | return 0; |
542 | 538 | ||
543 | /* Are we at the trap at bp->instr[1] for some bp? */ | 539 | /* Are we at the trap at bp->instr[1] for some bp? */ |
544 | bp = in_breakpoint_table(regs->nip, &offset); | 540 | bp = in_breakpoint_table(regs->nip, &offset); |
545 | if (bp != NULL && offset == 4) { | 541 | if (bp != NULL && offset == 4) { |
546 | regs->nip = bp->address + 4; | 542 | regs->nip = bp->address + 4; |
547 | atomic_dec(&bp->ref_count); | 543 | atomic_dec(&bp->ref_count); |
548 | return 1; | 544 | return 1; |
549 | } | 545 | } |
550 | 546 | ||
551 | /* Are we at a breakpoint? */ | 547 | /* Are we at a breakpoint? */ |
552 | bp = at_breakpoint(regs->nip); | 548 | bp = at_breakpoint(regs->nip); |
553 | if (!bp) | 549 | if (!bp) |
554 | return 0; | 550 | return 0; |
555 | 551 | ||
556 | xmon_core(regs, 0); | 552 | xmon_core(regs, 0); |
557 | 553 | ||
558 | return 1; | 554 | return 1; |
559 | } | 555 | } |
560 | 556 | ||
561 | int xmon_sstep(struct pt_regs *regs) | 557 | int xmon_sstep(struct pt_regs *regs) |
562 | { | 558 | { |
563 | if (user_mode(regs)) | 559 | if (user_mode(regs)) |
564 | return 0; | 560 | return 0; |
565 | xmon_core(regs, 0); | 561 | xmon_core(regs, 0); |
566 | return 1; | 562 | return 1; |
567 | } | 563 | } |
568 | 564 | ||
569 | int xmon_dabr_match(struct pt_regs *regs) | 565 | int xmon_dabr_match(struct pt_regs *regs) |
570 | { | 566 | { |
571 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) | 567 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) |
572 | return 0; | 568 | return 0; |
573 | if (dabr.enabled == 0) | 569 | if (dabr.enabled == 0) |
574 | return 0; | 570 | return 0; |
575 | xmon_core(regs, 0); | 571 | xmon_core(regs, 0); |
576 | return 1; | 572 | return 1; |
577 | } | 573 | } |
578 | 574 | ||
579 | int xmon_iabr_match(struct pt_regs *regs) | 575 | int xmon_iabr_match(struct pt_regs *regs) |
580 | { | 576 | { |
581 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) | 577 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) |
582 | return 0; | 578 | return 0; |
583 | if (iabr == 0) | 579 | if (iabr == 0) |
584 | return 0; | 580 | return 0; |
585 | xmon_core(regs, 0); | 581 | xmon_core(regs, 0); |
586 | return 1; | 582 | return 1; |
587 | } | 583 | } |
588 | 584 | ||
589 | int xmon_ipi(struct pt_regs *regs) | 585 | int xmon_ipi(struct pt_regs *regs) |
590 | { | 586 | { |
591 | #ifdef CONFIG_SMP | 587 | #ifdef CONFIG_SMP |
592 | if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon)) | 588 | if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon)) |
593 | xmon_core(regs, 1); | 589 | xmon_core(regs, 1); |
594 | #endif | 590 | #endif |
595 | return 0; | 591 | return 0; |
596 | } | 592 | } |
597 | 593 | ||
598 | int xmon_fault_handler(struct pt_regs *regs) | 594 | int xmon_fault_handler(struct pt_regs *regs) |
599 | { | 595 | { |
600 | struct bpt *bp; | 596 | struct bpt *bp; |
601 | unsigned long offset; | 597 | unsigned long offset; |
602 | 598 | ||
603 | if (in_xmon && catch_memory_errors) | 599 | if (in_xmon && catch_memory_errors) |
604 | handle_fault(regs); /* doesn't return */ | 600 | handle_fault(regs); /* doesn't return */ |
605 | 601 | ||
606 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { | 602 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { |
607 | bp = in_breakpoint_table(regs->nip, &offset); | 603 | bp = in_breakpoint_table(regs->nip, &offset); |
608 | if (bp != NULL) { | 604 | if (bp != NULL) { |
609 | regs->nip = bp->address + offset; | 605 | regs->nip = bp->address + offset; |
610 | atomic_dec(&bp->ref_count); | 606 | atomic_dec(&bp->ref_count); |
611 | } | 607 | } |
612 | } | 608 | } |
613 | 609 | ||
614 | return 0; | 610 | return 0; |
615 | } | 611 | } |
616 | 612 | ||
617 | static struct bpt *at_breakpoint(unsigned long pc) | 613 | static struct bpt *at_breakpoint(unsigned long pc) |
618 | { | 614 | { |
619 | int i; | 615 | int i; |
620 | struct bpt *bp; | 616 | struct bpt *bp; |
621 | 617 | ||
622 | bp = bpts; | 618 | bp = bpts; |
623 | for (i = 0; i < NBPTS; ++i, ++bp) | 619 | for (i = 0; i < NBPTS; ++i, ++bp) |
624 | if (bp->enabled && pc == bp->address) | 620 | if (bp->enabled && pc == bp->address) |
625 | return bp; | 621 | return bp; |
626 | return NULL; | 622 | return NULL; |
627 | } | 623 | } |
628 | 624 | ||
629 | static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp) | 625 | static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp) |
630 | { | 626 | { |
631 | unsigned long off; | 627 | unsigned long off; |
632 | 628 | ||
633 | off = nip - (unsigned long) bpts; | 629 | off = nip - (unsigned long) bpts; |
634 | if (off >= sizeof(bpts)) | 630 | if (off >= sizeof(bpts)) |
635 | return NULL; | 631 | return NULL; |
636 | off %= sizeof(struct bpt); | 632 | off %= sizeof(struct bpt); |
637 | if (off != offsetof(struct bpt, instr[0]) | 633 | if (off != offsetof(struct bpt, instr[0]) |
638 | && off != offsetof(struct bpt, instr[1])) | 634 | && off != offsetof(struct bpt, instr[1])) |
639 | return NULL; | 635 | return NULL; |
640 | *offp = off - offsetof(struct bpt, instr[0]); | 636 | *offp = off - offsetof(struct bpt, instr[0]); |
641 | return (struct bpt *) (nip - off); | 637 | return (struct bpt *) (nip - off); |
642 | } | 638 | } |
643 | 639 | ||
644 | static struct bpt *new_breakpoint(unsigned long a) | 640 | static struct bpt *new_breakpoint(unsigned long a) |
645 | { | 641 | { |
646 | struct bpt *bp; | 642 | struct bpt *bp; |
647 | 643 | ||
648 | a &= ~3UL; | 644 | a &= ~3UL; |
649 | bp = at_breakpoint(a); | 645 | bp = at_breakpoint(a); |
650 | if (bp) | 646 | if (bp) |
651 | return bp; | 647 | return bp; |
652 | 648 | ||
653 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { | 649 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { |
654 | if (!bp->enabled && atomic_read(&bp->ref_count) == 0) { | 650 | if (!bp->enabled && atomic_read(&bp->ref_count) == 0) { |
655 | bp->address = a; | 651 | bp->address = a; |
656 | bp->instr[1] = bpinstr; | 652 | bp->instr[1] = bpinstr; |
657 | store_inst(&bp->instr[1]); | 653 | store_inst(&bp->instr[1]); |
658 | return bp; | 654 | return bp; |
659 | } | 655 | } |
660 | } | 656 | } |
661 | 657 | ||
662 | printf("Sorry, no free breakpoints. Please clear one first.\n"); | 658 | printf("Sorry, no free breakpoints. Please clear one first.\n"); |
663 | return NULL; | 659 | return NULL; |
664 | } | 660 | } |
665 | 661 | ||
666 | static void insert_bpts(void) | 662 | static void insert_bpts(void) |
667 | { | 663 | { |
668 | int i; | 664 | int i; |
669 | struct bpt *bp; | 665 | struct bpt *bp; |
670 | 666 | ||
671 | bp = bpts; | 667 | bp = bpts; |
672 | for (i = 0; i < NBPTS; ++i, ++bp) { | 668 | for (i = 0; i < NBPTS; ++i, ++bp) { |
673 | if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0) | 669 | if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0) |
674 | continue; | 670 | continue; |
675 | if (mread(bp->address, &bp->instr[0], 4) != 4) { | 671 | if (mread(bp->address, &bp->instr[0], 4) != 4) { |
676 | printf("Couldn't read instruction at %lx, " | 672 | printf("Couldn't read instruction at %lx, " |
677 | "disabling breakpoint there\n", bp->address); | 673 | "disabling breakpoint there\n", bp->address); |
678 | bp->enabled = 0; | 674 | bp->enabled = 0; |
679 | continue; | 675 | continue; |
680 | } | 676 | } |
681 | if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) { | 677 | if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) { |
682 | printf("Breakpoint at %lx is on an mtmsrd or rfid " | 678 | printf("Breakpoint at %lx is on an mtmsrd or rfid " |
683 | "instruction, disabling it\n", bp->address); | 679 | "instruction, disabling it\n", bp->address); |
684 | bp->enabled = 0; | 680 | bp->enabled = 0; |
685 | continue; | 681 | continue; |
686 | } | 682 | } |
687 | store_inst(&bp->instr[0]); | 683 | store_inst(&bp->instr[0]); |
688 | if (bp->enabled & BP_IABR) | 684 | if (bp->enabled & BP_IABR) |
689 | continue; | 685 | continue; |
690 | if (mwrite(bp->address, &bpinstr, 4) != 4) { | 686 | if (mwrite(bp->address, &bpinstr, 4) != 4) { |
691 | printf("Couldn't write instruction at %lx, " | 687 | printf("Couldn't write instruction at %lx, " |
692 | "disabling breakpoint there\n", bp->address); | 688 | "disabling breakpoint there\n", bp->address); |
693 | bp->enabled &= ~BP_TRAP; | 689 | bp->enabled &= ~BP_TRAP; |
694 | continue; | 690 | continue; |
695 | } | 691 | } |
696 | store_inst((void *)bp->address); | 692 | store_inst((void *)bp->address); |
697 | } | 693 | } |
698 | } | 694 | } |
699 | 695 | ||
700 | static void insert_cpu_bpts(void) | 696 | static void insert_cpu_bpts(void) |
701 | { | 697 | { |
702 | if (dabr.enabled) | 698 | if (dabr.enabled) |
703 | set_dabr(dabr.address | (dabr.enabled & 7)); | 699 | set_dabr(dabr.address | (dabr.enabled & 7)); |
704 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) | 700 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) |
705 | mtspr(SPRN_IABR, iabr->address | 701 | mtspr(SPRN_IABR, iabr->address |
706 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); | 702 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); |
707 | } | 703 | } |
708 | 704 | ||
709 | static void remove_bpts(void) | 705 | static void remove_bpts(void) |
710 | { | 706 | { |
711 | int i; | 707 | int i; |
712 | struct bpt *bp; | 708 | struct bpt *bp; |
713 | unsigned instr; | 709 | unsigned instr; |
714 | 710 | ||
715 | bp = bpts; | 711 | bp = bpts; |
716 | for (i = 0; i < NBPTS; ++i, ++bp) { | 712 | for (i = 0; i < NBPTS; ++i, ++bp) { |
717 | if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP) | 713 | if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP) |
718 | continue; | 714 | continue; |
719 | if (mread(bp->address, &instr, 4) == 4 | 715 | if (mread(bp->address, &instr, 4) == 4 |
720 | && instr == bpinstr | 716 | && instr == bpinstr |
721 | && mwrite(bp->address, &bp->instr, 4) != 4) | 717 | && mwrite(bp->address, &bp->instr, 4) != 4) |
722 | printf("Couldn't remove breakpoint at %lx\n", | 718 | printf("Couldn't remove breakpoint at %lx\n", |
723 | bp->address); | 719 | bp->address); |
724 | else | 720 | else |
725 | store_inst((void *)bp->address); | 721 | store_inst((void *)bp->address); |
726 | } | 722 | } |
727 | } | 723 | } |
728 | 724 | ||
729 | static void remove_cpu_bpts(void) | 725 | static void remove_cpu_bpts(void) |
730 | { | 726 | { |
731 | set_dabr(0); | 727 | set_dabr(0); |
732 | if (cpu_has_feature(CPU_FTR_IABR)) | 728 | if (cpu_has_feature(CPU_FTR_IABR)) |
733 | mtspr(SPRN_IABR, 0); | 729 | mtspr(SPRN_IABR, 0); |
734 | } | 730 | } |
735 | 731 | ||
736 | /* Command interpreting routine */ | 732 | /* Command interpreting routine */ |
737 | static char *last_cmd; | 733 | static char *last_cmd; |
738 | 734 | ||
739 | static int | 735 | static int |
740 | cmds(struct pt_regs *excp) | 736 | cmds(struct pt_regs *excp) |
741 | { | 737 | { |
742 | int cmd = 0; | 738 | int cmd = 0; |
743 | 739 | ||
744 | last_cmd = NULL; | 740 | last_cmd = NULL; |
745 | xmon_regs = excp; | 741 | xmon_regs = excp; |
746 | for(;;) { | 742 | for(;;) { |
747 | #ifdef CONFIG_SMP | 743 | #ifdef CONFIG_SMP |
748 | printf("%x:", smp_processor_id()); | 744 | printf("%x:", smp_processor_id()); |
749 | #endif /* CONFIG_SMP */ | 745 | #endif /* CONFIG_SMP */ |
750 | printf("mon> "); | 746 | printf("mon> "); |
751 | fflush(stdout); | ||
752 | flush_input(); | 747 | flush_input(); |
753 | termch = 0; | 748 | termch = 0; |
754 | cmd = skipbl(); | 749 | cmd = skipbl(); |
755 | if( cmd == '\n' ) { | 750 | if( cmd == '\n' ) { |
756 | if (last_cmd == NULL) | 751 | if (last_cmd == NULL) |
757 | continue; | 752 | continue; |
758 | take_input(last_cmd); | 753 | take_input(last_cmd); |
759 | last_cmd = NULL; | 754 | last_cmd = NULL; |
760 | cmd = inchar(); | 755 | cmd = inchar(); |
761 | } | 756 | } |
762 | switch (cmd) { | 757 | switch (cmd) { |
763 | case 'm': | 758 | case 'm': |
764 | cmd = inchar(); | 759 | cmd = inchar(); |
765 | switch (cmd) { | 760 | switch (cmd) { |
766 | case 'm': | 761 | case 'm': |
767 | case 's': | 762 | case 's': |
768 | case 'd': | 763 | case 'd': |
769 | memops(cmd); | 764 | memops(cmd); |
770 | break; | 765 | break; |
771 | case 'l': | 766 | case 'l': |
772 | memlocate(); | 767 | memlocate(); |
773 | break; | 768 | break; |
774 | case 'z': | 769 | case 'z': |
775 | memzcan(); | 770 | memzcan(); |
776 | break; | 771 | break; |
777 | case 'i': | 772 | case 'i': |
778 | show_mem(); | 773 | show_mem(); |
779 | break; | 774 | break; |
780 | default: | 775 | default: |
781 | termch = cmd; | 776 | termch = cmd; |
782 | memex(); | 777 | memex(); |
783 | } | 778 | } |
784 | break; | 779 | break; |
785 | case 'd': | 780 | case 'd': |
786 | dump(); | 781 | dump(); |
787 | break; | 782 | break; |
788 | case 'l': | 783 | case 'l': |
789 | symbol_lookup(); | 784 | symbol_lookup(); |
790 | break; | 785 | break; |
791 | case 'r': | 786 | case 'r': |
792 | prregs(excp); /* print regs */ | 787 | prregs(excp); /* print regs */ |
793 | break; | 788 | break; |
794 | case 'e': | 789 | case 'e': |
795 | excprint(excp); | 790 | excprint(excp); |
796 | break; | 791 | break; |
797 | case 'S': | 792 | case 'S': |
798 | super_regs(); | 793 | super_regs(); |
799 | break; | 794 | break; |
800 | case 't': | 795 | case 't': |
801 | backtrace(excp); | 796 | backtrace(excp); |
802 | break; | 797 | break; |
803 | case 'f': | 798 | case 'f': |
804 | cacheflush(); | 799 | cacheflush(); |
805 | break; | 800 | break; |
806 | case 's': | 801 | case 's': |
807 | if (do_step(excp)) | 802 | if (do_step(excp)) |
808 | return cmd; | 803 | return cmd; |
809 | break; | 804 | break; |
810 | case 'x': | 805 | case 'x': |
811 | case 'X': | 806 | case 'X': |
812 | case EOF: | 807 | case EOF: |
813 | return cmd; | 808 | return cmd; |
814 | case '?': | 809 | case '?': |
815 | printf(help_string); | 810 | printf(help_string); |
816 | break; | 811 | break; |
817 | case 'b': | 812 | case 'b': |
818 | bpt_cmds(); | 813 | bpt_cmds(); |
819 | break; | 814 | break; |
820 | case 'C': | 815 | case 'C': |
821 | csum(); | 816 | csum(); |
822 | break; | 817 | break; |
823 | case 'c': | 818 | case 'c': |
824 | if (cpu_cmd()) | 819 | if (cpu_cmd()) |
825 | return 0; | 820 | return 0; |
826 | break; | 821 | break; |
827 | case 'z': | 822 | case 'z': |
828 | bootcmds(); | 823 | bootcmds(); |
829 | break; | 824 | break; |
830 | case 'p': | 825 | case 'p': |
831 | proccall(); | 826 | proccall(); |
832 | break; | 827 | break; |
833 | #ifdef CONFIG_PPC_STD_MMU | 828 | #ifdef CONFIG_PPC_STD_MMU |
834 | case 'u': | 829 | case 'u': |
835 | dump_segments(); | 830 | dump_segments(); |
836 | break; | 831 | break; |
837 | #endif | 832 | #endif |
838 | default: | 833 | default: |
839 | printf("Unrecognized command: "); | 834 | printf("Unrecognized command: "); |
840 | do { | 835 | do { |
841 | if (' ' < cmd && cmd <= '~') | 836 | if (' ' < cmd && cmd <= '~') |
842 | putchar(cmd); | 837 | putchar(cmd); |
843 | else | 838 | else |
844 | printf("\\x%x", cmd); | 839 | printf("\\x%x", cmd); |
845 | cmd = inchar(); | 840 | cmd = inchar(); |
846 | } while (cmd != '\n'); | 841 | } while (cmd != '\n'); |
847 | printf(" (type ? for help)\n"); | 842 | printf(" (type ? for help)\n"); |
848 | break; | 843 | break; |
849 | } | 844 | } |
850 | } | 845 | } |
851 | } | 846 | } |
852 | 847 | ||
853 | /* | 848 | /* |
854 | * Step a single instruction. | 849 | * Step a single instruction. |
855 | * Some instructions we emulate, others we execute with MSR_SE set. | 850 | * Some instructions we emulate, others we execute with MSR_SE set. |
856 | */ | 851 | */ |
857 | static int do_step(struct pt_regs *regs) | 852 | static int do_step(struct pt_regs *regs) |
858 | { | 853 | { |
859 | unsigned int instr; | 854 | unsigned int instr; |
860 | int stepped; | 855 | int stepped; |
861 | 856 | ||
862 | /* check we are in 64-bit kernel mode, translation enabled */ | 857 | /* check we are in 64-bit kernel mode, translation enabled */ |
863 | if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) { | 858 | if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) { |
864 | if (mread(regs->nip, &instr, 4) == 4) { | 859 | if (mread(regs->nip, &instr, 4) == 4) { |
865 | stepped = emulate_step(regs, instr); | 860 | stepped = emulate_step(regs, instr); |
866 | if (stepped < 0) { | 861 | if (stepped < 0) { |
867 | printf("Couldn't single-step %s instruction\n", | 862 | printf("Couldn't single-step %s instruction\n", |
868 | (IS_RFID(instr)? "rfid": "mtmsrd")); | 863 | (IS_RFID(instr)? "rfid": "mtmsrd")); |
869 | return 0; | 864 | return 0; |
870 | } | 865 | } |
871 | if (stepped > 0) { | 866 | if (stepped > 0) { |
872 | regs->trap = 0xd00 | (regs->trap & 1); | 867 | regs->trap = 0xd00 | (regs->trap & 1); |
873 | printf("stepped to "); | 868 | printf("stepped to "); |
874 | xmon_print_symbol(regs->nip, " ", "\n"); | 869 | xmon_print_symbol(regs->nip, " ", "\n"); |
875 | ppc_inst_dump(regs->nip, 1, 0); | 870 | ppc_inst_dump(regs->nip, 1, 0); |
876 | return 0; | 871 | return 0; |
877 | } | 872 | } |
878 | } | 873 | } |
879 | } | 874 | } |
880 | regs->msr |= MSR_SE; | 875 | regs->msr |= MSR_SE; |
881 | return 1; | 876 | return 1; |
882 | } | 877 | } |
883 | 878 | ||
884 | static void bootcmds(void) | 879 | static void bootcmds(void) |
885 | { | 880 | { |
886 | int cmd; | 881 | int cmd; |
887 | 882 | ||
888 | cmd = inchar(); | 883 | cmd = inchar(); |
889 | if (cmd == 'r') | 884 | if (cmd == 'r') |
890 | ppc_md.restart(NULL); | 885 | ppc_md.restart(NULL); |
891 | else if (cmd == 'h') | 886 | else if (cmd == 'h') |
892 | ppc_md.halt(); | 887 | ppc_md.halt(); |
893 | else if (cmd == 'p') | 888 | else if (cmd == 'p') |
894 | ppc_md.power_off(); | 889 | ppc_md.power_off(); |
895 | } | 890 | } |
896 | 891 | ||
897 | static int cpu_cmd(void) | 892 | static int cpu_cmd(void) |
898 | { | 893 | { |
899 | #ifdef CONFIG_SMP | 894 | #ifdef CONFIG_SMP |
900 | unsigned long cpu; | 895 | unsigned long cpu; |
901 | int timeout; | 896 | int timeout; |
902 | int count; | 897 | int count; |
903 | 898 | ||
904 | if (!scanhex(&cpu)) { | 899 | if (!scanhex(&cpu)) { |
905 | /* print cpus waiting or in xmon */ | 900 | /* print cpus waiting or in xmon */ |
906 | printf("cpus stopped:"); | 901 | printf("cpus stopped:"); |
907 | count = 0; | 902 | count = 0; |
908 | for (cpu = 0; cpu < NR_CPUS; ++cpu) { | 903 | for (cpu = 0; cpu < NR_CPUS; ++cpu) { |
909 | if (cpu_isset(cpu, cpus_in_xmon)) { | 904 | if (cpu_isset(cpu, cpus_in_xmon)) { |
910 | if (count == 0) | 905 | if (count == 0) |
911 | printf(" %x", cpu); | 906 | printf(" %x", cpu); |
912 | ++count; | 907 | ++count; |
913 | } else { | 908 | } else { |
914 | if (count > 1) | 909 | if (count > 1) |
915 | printf("-%x", cpu - 1); | 910 | printf("-%x", cpu - 1); |
916 | count = 0; | 911 | count = 0; |
917 | } | 912 | } |
918 | } | 913 | } |
919 | if (count > 1) | 914 | if (count > 1) |
920 | printf("-%x", NR_CPUS - 1); | 915 | printf("-%x", NR_CPUS - 1); |
921 | printf("\n"); | 916 | printf("\n"); |
922 | return 0; | 917 | return 0; |
923 | } | 918 | } |
924 | /* try to switch to cpu specified */ | 919 | /* try to switch to cpu specified */ |
925 | if (!cpu_isset(cpu, cpus_in_xmon)) { | 920 | if (!cpu_isset(cpu, cpus_in_xmon)) { |
926 | printf("cpu 0x%x isn't in xmon\n", cpu); | 921 | printf("cpu 0x%x isn't in xmon\n", cpu); |
927 | return 0; | 922 | return 0; |
928 | } | 923 | } |
929 | xmon_taken = 0; | 924 | xmon_taken = 0; |
930 | mb(); | 925 | mb(); |
931 | xmon_owner = cpu; | 926 | xmon_owner = cpu; |
932 | timeout = 10000000; | 927 | timeout = 10000000; |
933 | while (!xmon_taken) { | 928 | while (!xmon_taken) { |
934 | if (--timeout == 0) { | 929 | if (--timeout == 0) { |
935 | if (test_and_set_bit(0, &xmon_taken)) | 930 | if (test_and_set_bit(0, &xmon_taken)) |
936 | break; | 931 | break; |
937 | /* take control back */ | 932 | /* take control back */ |
938 | mb(); | 933 | mb(); |
939 | xmon_owner = smp_processor_id(); | 934 | xmon_owner = smp_processor_id(); |
940 | printf("cpu %u didn't take control\n", cpu); | 935 | printf("cpu %u didn't take control\n", cpu); |
941 | return 0; | 936 | return 0; |
942 | } | 937 | } |
943 | barrier(); | 938 | barrier(); |
944 | } | 939 | } |
945 | return 1; | 940 | return 1; |
946 | #else | 941 | #else |
947 | return 0; | 942 | return 0; |
948 | #endif /* CONFIG_SMP */ | 943 | #endif /* CONFIG_SMP */ |
949 | } | 944 | } |
950 | 945 | ||
951 | static unsigned short fcstab[256] = { | 946 | static unsigned short fcstab[256] = { |
952 | 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, | 947 | 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, |
953 | 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, | 948 | 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, |
954 | 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, | 949 | 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, |
955 | 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, | 950 | 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, |
956 | 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, | 951 | 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, |
957 | 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, | 952 | 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, |
958 | 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, | 953 | 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, |
959 | 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, | 954 | 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, |
960 | 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, | 955 | 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, |
961 | 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, | 956 | 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, |
962 | 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, | 957 | 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, |
963 | 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, | 958 | 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, |
964 | 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, | 959 | 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, |
965 | 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, | 960 | 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, |
966 | 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, | 961 | 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, |
967 | 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, | 962 | 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, |
968 | 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, | 963 | 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, |
969 | 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, | 964 | 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, |
970 | 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, | 965 | 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, |
971 | 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, | 966 | 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, |
972 | 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, | 967 | 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, |
973 | 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, | 968 | 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, |
974 | 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, | 969 | 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, |
975 | 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, | 970 | 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, |
976 | 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, | 971 | 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, |
977 | 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, | 972 | 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, |
978 | 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, | 973 | 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, |
979 | 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, | 974 | 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, |
980 | 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, | 975 | 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, |
981 | 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, | 976 | 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, |
982 | 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, | 977 | 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, |
983 | 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 | 978 | 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 |
984 | }; | 979 | }; |
985 | 980 | ||
986 | #define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) | 981 | #define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) |
987 | 982 | ||
988 | static void | 983 | static void |
989 | csum(void) | 984 | csum(void) |
990 | { | 985 | { |
991 | unsigned int i; | 986 | unsigned int i; |
992 | unsigned short fcs; | 987 | unsigned short fcs; |
993 | unsigned char v; | 988 | unsigned char v; |
994 | 989 | ||
995 | if (!scanhex(&adrs)) | 990 | if (!scanhex(&adrs)) |
996 | return; | 991 | return; |
997 | if (!scanhex(&ncsum)) | 992 | if (!scanhex(&ncsum)) |
998 | return; | 993 | return; |
999 | fcs = 0xffff; | 994 | fcs = 0xffff; |
1000 | for (i = 0; i < ncsum; ++i) { | 995 | for (i = 0; i < ncsum; ++i) { |
1001 | if (mread(adrs+i, &v, 1) == 0) { | 996 | if (mread(adrs+i, &v, 1) == 0) { |
1002 | printf("csum stopped at %x\n", adrs+i); | 997 | printf("csum stopped at %x\n", adrs+i); |
1003 | break; | 998 | break; |
1004 | } | 999 | } |
1005 | fcs = FCS(fcs, v); | 1000 | fcs = FCS(fcs, v); |
1006 | } | 1001 | } |
1007 | printf("%x\n", fcs); | 1002 | printf("%x\n", fcs); |
1008 | } | 1003 | } |
1009 | 1004 | ||
1010 | /* | 1005 | /* |
1011 | * Check if this is a suitable place to put a breakpoint. | 1006 | * Check if this is a suitable place to put a breakpoint. |
1012 | */ | 1007 | */ |
1013 | static long check_bp_loc(unsigned long addr) | 1008 | static long check_bp_loc(unsigned long addr) |
1014 | { | 1009 | { |
1015 | unsigned int instr; | 1010 | unsigned int instr; |
1016 | 1011 | ||
1017 | addr &= ~3; | 1012 | addr &= ~3; |
1018 | if (addr < KERNELBASE) { | 1013 | if (addr < KERNELBASE) { |
1019 | printf("Breakpoints may only be placed at kernel addresses\n"); | 1014 | printf("Breakpoints may only be placed at kernel addresses\n"); |
1020 | return 0; | 1015 | return 0; |
1021 | } | 1016 | } |
1022 | if (!mread(addr, &instr, sizeof(instr))) { | 1017 | if (!mread(addr, &instr, sizeof(instr))) { |
1023 | printf("Can't read instruction at address %lx\n", addr); | 1018 | printf("Can't read instruction at address %lx\n", addr); |
1024 | return 0; | 1019 | return 0; |
1025 | } | 1020 | } |
1026 | if (IS_MTMSRD(instr) || IS_RFID(instr)) { | 1021 | if (IS_MTMSRD(instr) || IS_RFID(instr)) { |
1027 | printf("Breakpoints may not be placed on mtmsrd or rfid " | 1022 | printf("Breakpoints may not be placed on mtmsrd or rfid " |
1028 | "instructions\n"); | 1023 | "instructions\n"); |
1029 | return 0; | 1024 | return 0; |
1030 | } | 1025 | } |
1031 | return 1; | 1026 | return 1; |
1032 | } | 1027 | } |
1033 | 1028 | ||
1034 | static char *breakpoint_help_string = | 1029 | static char *breakpoint_help_string = |
1035 | "Breakpoint command usage:\n" | 1030 | "Breakpoint command usage:\n" |
1036 | "b show breakpoints\n" | 1031 | "b show breakpoints\n" |
1037 | "b <addr> [cnt] set breakpoint at given instr addr\n" | 1032 | "b <addr> [cnt] set breakpoint at given instr addr\n" |
1038 | "bc clear all breakpoints\n" | 1033 | "bc clear all breakpoints\n" |
1039 | "bc <n/addr> clear breakpoint number n or at addr\n" | 1034 | "bc <n/addr> clear breakpoint number n or at addr\n" |
1040 | "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n" | 1035 | "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n" |
1041 | "bd <addr> [cnt] set hardware data breakpoint\n" | 1036 | "bd <addr> [cnt] set hardware data breakpoint\n" |
1042 | ""; | 1037 | ""; |
1043 | 1038 | ||
1044 | static void | 1039 | static void |
1045 | bpt_cmds(void) | 1040 | bpt_cmds(void) |
1046 | { | 1041 | { |
1047 | int cmd; | 1042 | int cmd; |
1048 | unsigned long a; | 1043 | unsigned long a; |
1049 | int mode, i; | 1044 | int mode, i; |
1050 | struct bpt *bp; | 1045 | struct bpt *bp; |
1051 | const char badaddr[] = "Only kernel addresses are permitted " | 1046 | const char badaddr[] = "Only kernel addresses are permitted " |
1052 | "for breakpoints\n"; | 1047 | "for breakpoints\n"; |
1053 | 1048 | ||
1054 | cmd = inchar(); | 1049 | cmd = inchar(); |
1055 | switch (cmd) { | 1050 | switch (cmd) { |
1056 | #ifndef CONFIG_8xx | 1051 | #ifndef CONFIG_8xx |
1057 | case 'd': /* bd - hardware data breakpoint */ | 1052 | case 'd': /* bd - hardware data breakpoint */ |
1058 | mode = 7; | 1053 | mode = 7; |
1059 | cmd = inchar(); | 1054 | cmd = inchar(); |
1060 | if (cmd == 'r') | 1055 | if (cmd == 'r') |
1061 | mode = 5; | 1056 | mode = 5; |
1062 | else if (cmd == 'w') | 1057 | else if (cmd == 'w') |
1063 | mode = 6; | 1058 | mode = 6; |
1064 | else | 1059 | else |
1065 | termch = cmd; | 1060 | termch = cmd; |
1066 | dabr.address = 0; | 1061 | dabr.address = 0; |
1067 | dabr.enabled = 0; | 1062 | dabr.enabled = 0; |
1068 | if (scanhex(&dabr.address)) { | 1063 | if (scanhex(&dabr.address)) { |
1069 | if (dabr.address < KERNELBASE) { | 1064 | if (dabr.address < KERNELBASE) { |
1070 | printf(badaddr); | 1065 | printf(badaddr); |
1071 | break; | 1066 | break; |
1072 | } | 1067 | } |
1073 | dabr.address &= ~7; | 1068 | dabr.address &= ~7; |
1074 | dabr.enabled = mode | BP_DABR; | 1069 | dabr.enabled = mode | BP_DABR; |
1075 | } | 1070 | } |
1076 | break; | 1071 | break; |
1077 | 1072 | ||
1078 | case 'i': /* bi - hardware instr breakpoint */ | 1073 | case 'i': /* bi - hardware instr breakpoint */ |
1079 | if (!cpu_has_feature(CPU_FTR_IABR)) { | 1074 | if (!cpu_has_feature(CPU_FTR_IABR)) { |
1080 | printf("Hardware instruction breakpoint " | 1075 | printf("Hardware instruction breakpoint " |
1081 | "not supported on this cpu\n"); | 1076 | "not supported on this cpu\n"); |
1082 | break; | 1077 | break; |
1083 | } | 1078 | } |
1084 | if (iabr) { | 1079 | if (iabr) { |
1085 | iabr->enabled &= ~(BP_IABR | BP_IABR_TE); | 1080 | iabr->enabled &= ~(BP_IABR | BP_IABR_TE); |
1086 | iabr = NULL; | 1081 | iabr = NULL; |
1087 | } | 1082 | } |
1088 | if (!scanhex(&a)) | 1083 | if (!scanhex(&a)) |
1089 | break; | 1084 | break; |
1090 | if (!check_bp_loc(a)) | 1085 | if (!check_bp_loc(a)) |
1091 | break; | 1086 | break; |
1092 | bp = new_breakpoint(a); | 1087 | bp = new_breakpoint(a); |
1093 | if (bp != NULL) { | 1088 | if (bp != NULL) { |
1094 | bp->enabled |= BP_IABR | BP_IABR_TE; | 1089 | bp->enabled |= BP_IABR | BP_IABR_TE; |
1095 | iabr = bp; | 1090 | iabr = bp; |
1096 | } | 1091 | } |
1097 | break; | 1092 | break; |
1098 | #endif | 1093 | #endif |
1099 | 1094 | ||
1100 | case 'c': | 1095 | case 'c': |
1101 | if (!scanhex(&a)) { | 1096 | if (!scanhex(&a)) { |
1102 | /* clear all breakpoints */ | 1097 | /* clear all breakpoints */ |
1103 | for (i = 0; i < NBPTS; ++i) | 1098 | for (i = 0; i < NBPTS; ++i) |
1104 | bpts[i].enabled = 0; | 1099 | bpts[i].enabled = 0; |
1105 | iabr = NULL; | 1100 | iabr = NULL; |
1106 | dabr.enabled = 0; | 1101 | dabr.enabled = 0; |
1107 | printf("All breakpoints cleared\n"); | 1102 | printf("All breakpoints cleared\n"); |
1108 | break; | 1103 | break; |
1109 | } | 1104 | } |
1110 | 1105 | ||
1111 | if (a <= NBPTS && a >= 1) { | 1106 | if (a <= NBPTS && a >= 1) { |
1112 | /* assume a breakpoint number */ | 1107 | /* assume a breakpoint number */ |
1113 | bp = &bpts[a-1]; /* bp nums are 1 based */ | 1108 | bp = &bpts[a-1]; /* bp nums are 1 based */ |
1114 | } else { | 1109 | } else { |
1115 | /* assume a breakpoint address */ | 1110 | /* assume a breakpoint address */ |
1116 | bp = at_breakpoint(a); | 1111 | bp = at_breakpoint(a); |
1117 | if (bp == 0) { | 1112 | if (bp == 0) { |
1118 | printf("No breakpoint at %x\n", a); | 1113 | printf("No breakpoint at %x\n", a); |
1119 | break; | 1114 | break; |
1120 | } | 1115 | } |
1121 | } | 1116 | } |
1122 | 1117 | ||
1123 | printf("Cleared breakpoint %x (", BP_NUM(bp)); | 1118 | printf("Cleared breakpoint %x (", BP_NUM(bp)); |
1124 | xmon_print_symbol(bp->address, " ", ")\n"); | 1119 | xmon_print_symbol(bp->address, " ", ")\n"); |
1125 | bp->enabled = 0; | 1120 | bp->enabled = 0; |
1126 | break; | 1121 | break; |
1127 | 1122 | ||
1128 | default: | 1123 | default: |
1129 | termch = cmd; | 1124 | termch = cmd; |
1130 | cmd = skipbl(); | 1125 | cmd = skipbl(); |
1131 | if (cmd == '?') { | 1126 | if (cmd == '?') { |
1132 | printf(breakpoint_help_string); | 1127 | printf(breakpoint_help_string); |
1133 | break; | 1128 | break; |
1134 | } | 1129 | } |
1135 | termch = cmd; | 1130 | termch = cmd; |
1136 | if (!scanhex(&a)) { | 1131 | if (!scanhex(&a)) { |
1137 | /* print all breakpoints */ | 1132 | /* print all breakpoints */ |
1138 | printf(" type address\n"); | 1133 | printf(" type address\n"); |
1139 | if (dabr.enabled) { | 1134 | if (dabr.enabled) { |
1140 | printf(" data "REG" [", dabr.address); | 1135 | printf(" data "REG" [", dabr.address); |
1141 | if (dabr.enabled & 1) | 1136 | if (dabr.enabled & 1) |
1142 | printf("r"); | 1137 | printf("r"); |
1143 | if (dabr.enabled & 2) | 1138 | if (dabr.enabled & 2) |
1144 | printf("w"); | 1139 | printf("w"); |
1145 | printf("]\n"); | 1140 | printf("]\n"); |
1146 | } | 1141 | } |
1147 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { | 1142 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { |
1148 | if (!bp->enabled) | 1143 | if (!bp->enabled) |
1149 | continue; | 1144 | continue; |
1150 | printf("%2x %s ", BP_NUM(bp), | 1145 | printf("%2x %s ", BP_NUM(bp), |
1151 | (bp->enabled & BP_IABR)? "inst": "trap"); | 1146 | (bp->enabled & BP_IABR)? "inst": "trap"); |
1152 | xmon_print_symbol(bp->address, " ", "\n"); | 1147 | xmon_print_symbol(bp->address, " ", "\n"); |
1153 | } | 1148 | } |
1154 | break; | 1149 | break; |
1155 | } | 1150 | } |
1156 | 1151 | ||
1157 | if (!check_bp_loc(a)) | 1152 | if (!check_bp_loc(a)) |
1158 | break; | 1153 | break; |
1159 | bp = new_breakpoint(a); | 1154 | bp = new_breakpoint(a); |
1160 | if (bp != NULL) | 1155 | if (bp != NULL) |
1161 | bp->enabled |= BP_TRAP; | 1156 | bp->enabled |= BP_TRAP; |
1162 | break; | 1157 | break; |
1163 | } | 1158 | } |
1164 | } | 1159 | } |
1165 | 1160 | ||
1166 | /* Very cheap human name for vector lookup. */ | 1161 | /* Very cheap human name for vector lookup. */ |
1167 | static | 1162 | static |
1168 | const char *getvecname(unsigned long vec) | 1163 | const char *getvecname(unsigned long vec) |
1169 | { | 1164 | { |
1170 | char *ret; | 1165 | char *ret; |
1171 | 1166 | ||
1172 | switch (vec) { | 1167 | switch (vec) { |
1173 | case 0x100: ret = "(System Reset)"; break; | 1168 | case 0x100: ret = "(System Reset)"; break; |
1174 | case 0x200: ret = "(Machine Check)"; break; | 1169 | case 0x200: ret = "(Machine Check)"; break; |
1175 | case 0x300: ret = "(Data Access)"; break; | 1170 | case 0x300: ret = "(Data Access)"; break; |
1176 | case 0x380: ret = "(Data SLB Access)"; break; | 1171 | case 0x380: ret = "(Data SLB Access)"; break; |
1177 | case 0x400: ret = "(Instruction Access)"; break; | 1172 | case 0x400: ret = "(Instruction Access)"; break; |
1178 | case 0x480: ret = "(Instruction SLB Access)"; break; | 1173 | case 0x480: ret = "(Instruction SLB Access)"; break; |
1179 | case 0x500: ret = "(Hardware Interrupt)"; break; | 1174 | case 0x500: ret = "(Hardware Interrupt)"; break; |
1180 | case 0x600: ret = "(Alignment)"; break; | 1175 | case 0x600: ret = "(Alignment)"; break; |
1181 | case 0x700: ret = "(Program Check)"; break; | 1176 | case 0x700: ret = "(Program Check)"; break; |
1182 | case 0x800: ret = "(FPU Unavailable)"; break; | 1177 | case 0x800: ret = "(FPU Unavailable)"; break; |
1183 | case 0x900: ret = "(Decrementer)"; break; | 1178 | case 0x900: ret = "(Decrementer)"; break; |
1184 | case 0xc00: ret = "(System Call)"; break; | 1179 | case 0xc00: ret = "(System Call)"; break; |
1185 | case 0xd00: ret = "(Single Step)"; break; | 1180 | case 0xd00: ret = "(Single Step)"; break; |
1186 | case 0xf00: ret = "(Performance Monitor)"; break; | 1181 | case 0xf00: ret = "(Performance Monitor)"; break; |
1187 | case 0xf20: ret = "(Altivec Unavailable)"; break; | 1182 | case 0xf20: ret = "(Altivec Unavailable)"; break; |
1188 | case 0x1300: ret = "(Instruction Breakpoint)"; break; | 1183 | case 0x1300: ret = "(Instruction Breakpoint)"; break; |
1189 | default: ret = ""; | 1184 | default: ret = ""; |
1190 | } | 1185 | } |
1191 | return ret; | 1186 | return ret; |
1192 | } | 1187 | } |
1193 | 1188 | ||
1194 | static void get_function_bounds(unsigned long pc, unsigned long *startp, | 1189 | static void get_function_bounds(unsigned long pc, unsigned long *startp, |
1195 | unsigned long *endp) | 1190 | unsigned long *endp) |
1196 | { | 1191 | { |
1197 | unsigned long size, offset; | 1192 | unsigned long size, offset; |
1198 | const char *name; | 1193 | const char *name; |
1199 | char *modname; | 1194 | char *modname; |
1200 | 1195 | ||
1201 | *startp = *endp = 0; | 1196 | *startp = *endp = 0; |
1202 | if (pc == 0) | 1197 | if (pc == 0) |
1203 | return; | 1198 | return; |
1204 | if (setjmp(bus_error_jmp) == 0) { | 1199 | if (setjmp(bus_error_jmp) == 0) { |
1205 | catch_memory_errors = 1; | 1200 | catch_memory_errors = 1; |
1206 | sync(); | 1201 | sync(); |
1207 | name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr); | 1202 | name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr); |
1208 | if (name != NULL) { | 1203 | if (name != NULL) { |
1209 | *startp = pc - offset; | 1204 | *startp = pc - offset; |
1210 | *endp = pc - offset + size; | 1205 | *endp = pc - offset + size; |
1211 | } | 1206 | } |
1212 | sync(); | 1207 | sync(); |
1213 | } | 1208 | } |
1214 | catch_memory_errors = 0; | 1209 | catch_memory_errors = 0; |
1215 | } | 1210 | } |
1216 | 1211 | ||
1217 | static int xmon_depth_to_print = 64; | 1212 | static int xmon_depth_to_print = 64; |
1218 | 1213 | ||
1219 | #ifdef CONFIG_PPC64 | 1214 | #ifdef CONFIG_PPC64 |
1220 | #define LRSAVE_OFFSET 0x10 | 1215 | #define LRSAVE_OFFSET 0x10 |
1221 | #define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */ | 1216 | #define REG_FRAME_MARKER 0x7265677368657265ul /* "regshere" */ |
1222 | #define MARKER_OFFSET 0x60 | 1217 | #define MARKER_OFFSET 0x60 |
1223 | #define REGS_OFFSET 0x70 | 1218 | #define REGS_OFFSET 0x70 |
1224 | #else | 1219 | #else |
1225 | #define LRSAVE_OFFSET 4 | 1220 | #define LRSAVE_OFFSET 4 |
1226 | #define REG_FRAME_MARKER 0x72656773 | 1221 | #define REG_FRAME_MARKER 0x72656773 |
1227 | #define MARKER_OFFSET 8 | 1222 | #define MARKER_OFFSET 8 |
1228 | #define REGS_OFFSET 16 | 1223 | #define REGS_OFFSET 16 |
1229 | #endif | 1224 | #endif |
1230 | 1225 | ||
1231 | static void xmon_show_stack(unsigned long sp, unsigned long lr, | 1226 | static void xmon_show_stack(unsigned long sp, unsigned long lr, |
1232 | unsigned long pc) | 1227 | unsigned long pc) |
1233 | { | 1228 | { |
1234 | unsigned long ip; | 1229 | unsigned long ip; |
1235 | unsigned long newsp; | 1230 | unsigned long newsp; |
1236 | unsigned long marker; | 1231 | unsigned long marker; |
1237 | int count = 0; | 1232 | int count = 0; |
1238 | struct pt_regs regs; | 1233 | struct pt_regs regs; |
1239 | 1234 | ||
1240 | do { | 1235 | do { |
1241 | if (sp < PAGE_OFFSET) { | 1236 | if (sp < PAGE_OFFSET) { |
1242 | if (sp != 0) | 1237 | if (sp != 0) |
1243 | printf("SP (%lx) is in userspace\n", sp); | 1238 | printf("SP (%lx) is in userspace\n", sp); |
1244 | break; | 1239 | break; |
1245 | } | 1240 | } |
1246 | 1241 | ||
1247 | if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long)) | 1242 | if (!mread(sp + LRSAVE_OFFSET, &ip, sizeof(unsigned long)) |
1248 | || !mread(sp, &newsp, sizeof(unsigned long))) { | 1243 | || !mread(sp, &newsp, sizeof(unsigned long))) { |
1249 | printf("Couldn't read stack frame at %lx\n", sp); | 1244 | printf("Couldn't read stack frame at %lx\n", sp); |
1250 | break; | 1245 | break; |
1251 | } | 1246 | } |
1252 | 1247 | ||
1253 | /* | 1248 | /* |
1254 | * For the first stack frame, try to work out if | 1249 | * For the first stack frame, try to work out if |
1255 | * LR and/or the saved LR value in the bottommost | 1250 | * LR and/or the saved LR value in the bottommost |
1256 | * stack frame are valid. | 1251 | * stack frame are valid. |
1257 | */ | 1252 | */ |
1258 | if ((pc | lr) != 0) { | 1253 | if ((pc | lr) != 0) { |
1259 | unsigned long fnstart, fnend; | 1254 | unsigned long fnstart, fnend; |
1260 | unsigned long nextip; | 1255 | unsigned long nextip; |
1261 | int printip = 1; | 1256 | int printip = 1; |
1262 | 1257 | ||
1263 | get_function_bounds(pc, &fnstart, &fnend); | 1258 | get_function_bounds(pc, &fnstart, &fnend); |
1264 | nextip = 0; | 1259 | nextip = 0; |
1265 | if (newsp > sp) | 1260 | if (newsp > sp) |
1266 | mread(newsp + LRSAVE_OFFSET, &nextip, | 1261 | mread(newsp + LRSAVE_OFFSET, &nextip, |
1267 | sizeof(unsigned long)); | 1262 | sizeof(unsigned long)); |
1268 | if (lr == ip) { | 1263 | if (lr == ip) { |
1269 | if (lr < PAGE_OFFSET | 1264 | if (lr < PAGE_OFFSET |
1270 | || (fnstart <= lr && lr < fnend)) | 1265 | || (fnstart <= lr && lr < fnend)) |
1271 | printip = 0; | 1266 | printip = 0; |
1272 | } else if (lr == nextip) { | 1267 | } else if (lr == nextip) { |
1273 | printip = 0; | 1268 | printip = 0; |
1274 | } else if (lr >= PAGE_OFFSET | 1269 | } else if (lr >= PAGE_OFFSET |
1275 | && !(fnstart <= lr && lr < fnend)) { | 1270 | && !(fnstart <= lr && lr < fnend)) { |
1276 | printf("[link register ] "); | 1271 | printf("[link register ] "); |
1277 | xmon_print_symbol(lr, " ", "\n"); | 1272 | xmon_print_symbol(lr, " ", "\n"); |
1278 | } | 1273 | } |
1279 | if (printip) { | 1274 | if (printip) { |
1280 | printf("["REG"] ", sp); | 1275 | printf("["REG"] ", sp); |
1281 | xmon_print_symbol(ip, " ", " (unreliable)\n"); | 1276 | xmon_print_symbol(ip, " ", " (unreliable)\n"); |
1282 | } | 1277 | } |
1283 | pc = lr = 0; | 1278 | pc = lr = 0; |
1284 | 1279 | ||
1285 | } else { | 1280 | } else { |
1286 | printf("["REG"] ", sp); | 1281 | printf("["REG"] ", sp); |
1287 | xmon_print_symbol(ip, " ", "\n"); | 1282 | xmon_print_symbol(ip, " ", "\n"); |
1288 | } | 1283 | } |
1289 | 1284 | ||
1290 | /* Look for "regshere" marker to see if this is | 1285 | /* Look for "regshere" marker to see if this is |
1291 | an exception frame. */ | 1286 | an exception frame. */ |
1292 | if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long)) | 1287 | if (mread(sp + MARKER_OFFSET, &marker, sizeof(unsigned long)) |
1293 | && marker == REG_FRAME_MARKER) { | 1288 | && marker == REG_FRAME_MARKER) { |
1294 | if (mread(sp + REGS_OFFSET, ®s, sizeof(regs)) | 1289 | if (mread(sp + REGS_OFFSET, ®s, sizeof(regs)) |
1295 | != sizeof(regs)) { | 1290 | != sizeof(regs)) { |
1296 | printf("Couldn't read registers at %lx\n", | 1291 | printf("Couldn't read registers at %lx\n", |
1297 | sp + REGS_OFFSET); | 1292 | sp + REGS_OFFSET); |
1298 | break; | 1293 | break; |
1299 | } | 1294 | } |
1300 | printf("--- Exception: %lx %s at ", regs.trap, | 1295 | printf("--- Exception: %lx %s at ", regs.trap, |
1301 | getvecname(TRAP(®s))); | 1296 | getvecname(TRAP(®s))); |
1302 | pc = regs.nip; | 1297 | pc = regs.nip; |
1303 | lr = regs.link; | 1298 | lr = regs.link; |
1304 | xmon_print_symbol(pc, " ", "\n"); | 1299 | xmon_print_symbol(pc, " ", "\n"); |
1305 | } | 1300 | } |
1306 | 1301 | ||
1307 | if (newsp == 0) | 1302 | if (newsp == 0) |
1308 | break; | 1303 | break; |
1309 | 1304 | ||
1310 | sp = newsp; | 1305 | sp = newsp; |
1311 | } while (count++ < xmon_depth_to_print); | 1306 | } while (count++ < xmon_depth_to_print); |
1312 | } | 1307 | } |
1313 | 1308 | ||
1314 | static void backtrace(struct pt_regs *excp) | 1309 | static void backtrace(struct pt_regs *excp) |
1315 | { | 1310 | { |
1316 | unsigned long sp; | 1311 | unsigned long sp; |
1317 | 1312 | ||
1318 | if (scanhex(&sp)) | 1313 | if (scanhex(&sp)) |
1319 | xmon_show_stack(sp, 0, 0); | 1314 | xmon_show_stack(sp, 0, 0); |
1320 | else | 1315 | else |
1321 | xmon_show_stack(excp->gpr[1], excp->link, excp->nip); | 1316 | xmon_show_stack(excp->gpr[1], excp->link, excp->nip); |
1322 | scannl(); | 1317 | scannl(); |
1323 | } | 1318 | } |
1324 | 1319 | ||
1325 | static void print_bug_trap(struct pt_regs *regs) | 1320 | static void print_bug_trap(struct pt_regs *regs) |
1326 | { | 1321 | { |
1327 | struct bug_entry *bug; | 1322 | struct bug_entry *bug; |
1328 | unsigned long addr; | 1323 | unsigned long addr; |
1329 | 1324 | ||
1330 | if (regs->msr & MSR_PR) | 1325 | if (regs->msr & MSR_PR) |
1331 | return; /* not in kernel */ | 1326 | return; /* not in kernel */ |
1332 | addr = regs->nip; /* address of trap instruction */ | 1327 | addr = regs->nip; /* address of trap instruction */ |
1333 | if (addr < PAGE_OFFSET) | 1328 | if (addr < PAGE_OFFSET) |
1334 | return; | 1329 | return; |
1335 | bug = find_bug(regs->nip); | 1330 | bug = find_bug(regs->nip); |
1336 | if (bug == NULL) | 1331 | if (bug == NULL) |
1337 | return; | 1332 | return; |
1338 | if (bug->line & BUG_WARNING_TRAP) | 1333 | if (bug->line & BUG_WARNING_TRAP) |
1339 | return; | 1334 | return; |
1340 | 1335 | ||
1341 | printf("kernel BUG in %s at %s:%d!\n", | 1336 | printf("kernel BUG in %s at %s:%d!\n", |
1342 | bug->function, bug->file, (unsigned int)bug->line); | 1337 | bug->function, bug->file, (unsigned int)bug->line); |
1343 | } | 1338 | } |
1344 | 1339 | ||
1345 | void excprint(struct pt_regs *fp) | 1340 | void excprint(struct pt_regs *fp) |
1346 | { | 1341 | { |
1347 | unsigned long trap; | 1342 | unsigned long trap; |
1348 | 1343 | ||
1349 | #ifdef CONFIG_SMP | 1344 | #ifdef CONFIG_SMP |
1350 | printf("cpu 0x%x: ", smp_processor_id()); | 1345 | printf("cpu 0x%x: ", smp_processor_id()); |
1351 | #endif /* CONFIG_SMP */ | 1346 | #endif /* CONFIG_SMP */ |
1352 | 1347 | ||
1353 | trap = TRAP(fp); | 1348 | trap = TRAP(fp); |
1354 | printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp); | 1349 | printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp); |
1355 | printf(" pc: "); | 1350 | printf(" pc: "); |
1356 | xmon_print_symbol(fp->nip, ": ", "\n"); | 1351 | xmon_print_symbol(fp->nip, ": ", "\n"); |
1357 | 1352 | ||
1358 | printf(" lr: ", fp->link); | 1353 | printf(" lr: ", fp->link); |
1359 | xmon_print_symbol(fp->link, ": ", "\n"); | 1354 | xmon_print_symbol(fp->link, ": ", "\n"); |
1360 | 1355 | ||
1361 | printf(" sp: %lx\n", fp->gpr[1]); | 1356 | printf(" sp: %lx\n", fp->gpr[1]); |
1362 | printf(" msr: %lx\n", fp->msr); | 1357 | printf(" msr: %lx\n", fp->msr); |
1363 | 1358 | ||
1364 | if (trap == 0x300 || trap == 0x380 || trap == 0x600) { | 1359 | if (trap == 0x300 || trap == 0x380 || trap == 0x600) { |
1365 | printf(" dar: %lx\n", fp->dar); | 1360 | printf(" dar: %lx\n", fp->dar); |
1366 | if (trap != 0x380) | 1361 | if (trap != 0x380) |
1367 | printf(" dsisr: %lx\n", fp->dsisr); | 1362 | printf(" dsisr: %lx\n", fp->dsisr); |
1368 | } | 1363 | } |
1369 | 1364 | ||
1370 | printf(" current = 0x%lx\n", current); | 1365 | printf(" current = 0x%lx\n", current); |
1371 | #ifdef CONFIG_PPC64 | 1366 | #ifdef CONFIG_PPC64 |
1372 | printf(" paca = 0x%lx\n", get_paca()); | 1367 | printf(" paca = 0x%lx\n", get_paca()); |
1373 | #endif | 1368 | #endif |
1374 | if (current) { | 1369 | if (current) { |
1375 | printf(" pid = %ld, comm = %s\n", | 1370 | printf(" pid = %ld, comm = %s\n", |
1376 | current->pid, current->comm); | 1371 | current->pid, current->comm); |
1377 | } | 1372 | } |
1378 | 1373 | ||
1379 | if (trap == 0x700) | 1374 | if (trap == 0x700) |
1380 | print_bug_trap(fp); | 1375 | print_bug_trap(fp); |
1381 | } | 1376 | } |
1382 | 1377 | ||
1383 | void prregs(struct pt_regs *fp) | 1378 | void prregs(struct pt_regs *fp) |
1384 | { | 1379 | { |
1385 | int n, trap; | 1380 | int n, trap; |
1386 | unsigned long base; | 1381 | unsigned long base; |
1387 | struct pt_regs regs; | 1382 | struct pt_regs regs; |
1388 | 1383 | ||
1389 | if (scanhex(&base)) { | 1384 | if (scanhex(&base)) { |
1390 | if (setjmp(bus_error_jmp) == 0) { | 1385 | if (setjmp(bus_error_jmp) == 0) { |
1391 | catch_memory_errors = 1; | 1386 | catch_memory_errors = 1; |
1392 | sync(); | 1387 | sync(); |
1393 | regs = *(struct pt_regs *)base; | 1388 | regs = *(struct pt_regs *)base; |
1394 | sync(); | 1389 | sync(); |
1395 | __delay(200); | 1390 | __delay(200); |
1396 | } else { | 1391 | } else { |
1397 | catch_memory_errors = 0; | 1392 | catch_memory_errors = 0; |
1398 | printf("*** Error reading registers from "REG"\n", | 1393 | printf("*** Error reading registers from "REG"\n", |
1399 | base); | 1394 | base); |
1400 | return; | 1395 | return; |
1401 | } | 1396 | } |
1402 | catch_memory_errors = 0; | 1397 | catch_memory_errors = 0; |
1403 | fp = ®s; | 1398 | fp = ®s; |
1404 | } | 1399 | } |
1405 | 1400 | ||
1406 | #ifdef CONFIG_PPC64 | 1401 | #ifdef CONFIG_PPC64 |
1407 | if (FULL_REGS(fp)) { | 1402 | if (FULL_REGS(fp)) { |
1408 | for (n = 0; n < 16; ++n) | 1403 | for (n = 0; n < 16; ++n) |
1409 | printf("R%.2ld = "REG" R%.2ld = "REG"\n", | 1404 | printf("R%.2ld = "REG" R%.2ld = "REG"\n", |
1410 | n, fp->gpr[n], n+16, fp->gpr[n+16]); | 1405 | n, fp->gpr[n], n+16, fp->gpr[n+16]); |
1411 | } else { | 1406 | } else { |
1412 | for (n = 0; n < 7; ++n) | 1407 | for (n = 0; n < 7; ++n) |
1413 | printf("R%.2ld = "REG" R%.2ld = "REG"\n", | 1408 | printf("R%.2ld = "REG" R%.2ld = "REG"\n", |
1414 | n, fp->gpr[n], n+7, fp->gpr[n+7]); | 1409 | n, fp->gpr[n], n+7, fp->gpr[n+7]); |
1415 | } | 1410 | } |
1416 | #else | 1411 | #else |
1417 | for (n = 0; n < 32; ++n) { | 1412 | for (n = 0; n < 32; ++n) { |
1418 | printf("R%.2d = %.8x%s", n, fp->gpr[n], | 1413 | printf("R%.2d = %.8x%s", n, fp->gpr[n], |
1419 | (n & 3) == 3? "\n": " "); | 1414 | (n & 3) == 3? "\n": " "); |
1420 | if (n == 12 && !FULL_REGS(fp)) { | 1415 | if (n == 12 && !FULL_REGS(fp)) { |
1421 | printf("\n"); | 1416 | printf("\n"); |
1422 | break; | 1417 | break; |
1423 | } | 1418 | } |
1424 | } | 1419 | } |
1425 | #endif | 1420 | #endif |
1426 | printf("pc = "); | 1421 | printf("pc = "); |
1427 | xmon_print_symbol(fp->nip, " ", "\n"); | 1422 | xmon_print_symbol(fp->nip, " ", "\n"); |
1428 | printf("lr = "); | 1423 | printf("lr = "); |
1429 | xmon_print_symbol(fp->link, " ", "\n"); | 1424 | xmon_print_symbol(fp->link, " ", "\n"); |
1430 | printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr); | 1425 | printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr); |
1431 | printf("ctr = "REG" xer = "REG" trap = %4lx\n", | 1426 | printf("ctr = "REG" xer = "REG" trap = %4lx\n", |
1432 | fp->ctr, fp->xer, fp->trap); | 1427 | fp->ctr, fp->xer, fp->trap); |
1433 | trap = TRAP(fp); | 1428 | trap = TRAP(fp); |
1434 | if (trap == 0x300 || trap == 0x380 || trap == 0x600) | 1429 | if (trap == 0x300 || trap == 0x380 || trap == 0x600) |
1435 | printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr); | 1430 | printf("dar = "REG" dsisr = %.8lx\n", fp->dar, fp->dsisr); |
1436 | } | 1431 | } |
1437 | 1432 | ||
1438 | void cacheflush(void) | 1433 | void cacheflush(void) |
1439 | { | 1434 | { |
1440 | int cmd; | 1435 | int cmd; |
1441 | unsigned long nflush; | 1436 | unsigned long nflush; |
1442 | 1437 | ||
1443 | cmd = inchar(); | 1438 | cmd = inchar(); |
1444 | if (cmd != 'i') | 1439 | if (cmd != 'i') |
1445 | termch = cmd; | 1440 | termch = cmd; |
1446 | scanhex((void *)&adrs); | 1441 | scanhex((void *)&adrs); |
1447 | if (termch != '\n') | 1442 | if (termch != '\n') |
1448 | termch = 0; | 1443 | termch = 0; |
1449 | nflush = 1; | 1444 | nflush = 1; |
1450 | scanhex(&nflush); | 1445 | scanhex(&nflush); |
1451 | nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES; | 1446 | nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES; |
1452 | if (setjmp(bus_error_jmp) == 0) { | 1447 | if (setjmp(bus_error_jmp) == 0) { |
1453 | catch_memory_errors = 1; | 1448 | catch_memory_errors = 1; |
1454 | sync(); | 1449 | sync(); |
1455 | 1450 | ||
1456 | if (cmd != 'i') { | 1451 | if (cmd != 'i') { |
1457 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) | 1452 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) |
1458 | cflush((void *) adrs); | 1453 | cflush((void *) adrs); |
1459 | } else { | 1454 | } else { |
1460 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) | 1455 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) |
1461 | cinval((void *) adrs); | 1456 | cinval((void *) adrs); |
1462 | } | 1457 | } |
1463 | sync(); | 1458 | sync(); |
1464 | /* wait a little while to see if we get a machine check */ | 1459 | /* wait a little while to see if we get a machine check */ |
1465 | __delay(200); | 1460 | __delay(200); |
1466 | } | 1461 | } |
1467 | catch_memory_errors = 0; | 1462 | catch_memory_errors = 0; |
1468 | } | 1463 | } |
1469 | 1464 | ||
1470 | unsigned long | 1465 | unsigned long |
1471 | read_spr(int n) | 1466 | read_spr(int n) |
1472 | { | 1467 | { |
1473 | unsigned int instrs[2]; | 1468 | unsigned int instrs[2]; |
1474 | unsigned long (*code)(void); | 1469 | unsigned long (*code)(void); |
1475 | unsigned long opd[3]; | 1470 | unsigned long opd[3]; |
1476 | unsigned long ret = -1UL; | 1471 | unsigned long ret = -1UL; |
1477 | 1472 | ||
1478 | instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); | 1473 | instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); |
1479 | instrs[1] = 0x4e800020; | 1474 | instrs[1] = 0x4e800020; |
1480 | opd[0] = (unsigned long)instrs; | 1475 | opd[0] = (unsigned long)instrs; |
1481 | opd[1] = 0; | 1476 | opd[1] = 0; |
1482 | opd[2] = 0; | 1477 | opd[2] = 0; |
1483 | store_inst(instrs); | 1478 | store_inst(instrs); |
1484 | store_inst(instrs+1); | 1479 | store_inst(instrs+1); |
1485 | code = (unsigned long (*)(void)) opd; | 1480 | code = (unsigned long (*)(void)) opd; |
1486 | 1481 | ||
1487 | if (setjmp(bus_error_jmp) == 0) { | 1482 | if (setjmp(bus_error_jmp) == 0) { |
1488 | catch_memory_errors = 1; | 1483 | catch_memory_errors = 1; |
1489 | sync(); | 1484 | sync(); |
1490 | 1485 | ||
1491 | ret = code(); | 1486 | ret = code(); |
1492 | 1487 | ||
1493 | sync(); | 1488 | sync(); |
1494 | /* wait a little while to see if we get a machine check */ | 1489 | /* wait a little while to see if we get a machine check */ |
1495 | __delay(200); | 1490 | __delay(200); |
1496 | n = size; | 1491 | n = size; |
1497 | } | 1492 | } |
1498 | 1493 | ||
1499 | return ret; | 1494 | return ret; |
1500 | } | 1495 | } |
1501 | 1496 | ||
1502 | void | 1497 | void |
1503 | write_spr(int n, unsigned long val) | 1498 | write_spr(int n, unsigned long val) |
1504 | { | 1499 | { |
1505 | unsigned int instrs[2]; | 1500 | unsigned int instrs[2]; |
1506 | unsigned long (*code)(unsigned long); | 1501 | unsigned long (*code)(unsigned long); |
1507 | unsigned long opd[3]; | 1502 | unsigned long opd[3]; |
1508 | 1503 | ||
1509 | instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); | 1504 | instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); |
1510 | instrs[1] = 0x4e800020; | 1505 | instrs[1] = 0x4e800020; |
1511 | opd[0] = (unsigned long)instrs; | 1506 | opd[0] = (unsigned long)instrs; |
1512 | opd[1] = 0; | 1507 | opd[1] = 0; |
1513 | opd[2] = 0; | 1508 | opd[2] = 0; |
1514 | store_inst(instrs); | 1509 | store_inst(instrs); |
1515 | store_inst(instrs+1); | 1510 | store_inst(instrs+1); |
1516 | code = (unsigned long (*)(unsigned long)) opd; | 1511 | code = (unsigned long (*)(unsigned long)) opd; |
1517 | 1512 | ||
1518 | if (setjmp(bus_error_jmp) == 0) { | 1513 | if (setjmp(bus_error_jmp) == 0) { |
1519 | catch_memory_errors = 1; | 1514 | catch_memory_errors = 1; |
1520 | sync(); | 1515 | sync(); |
1521 | 1516 | ||
1522 | code(val); | 1517 | code(val); |
1523 | 1518 | ||
1524 | sync(); | 1519 | sync(); |
1525 | /* wait a little while to see if we get a machine check */ | 1520 | /* wait a little while to see if we get a machine check */ |
1526 | __delay(200); | 1521 | __delay(200); |
1527 | n = size; | 1522 | n = size; |
1528 | } | 1523 | } |
1529 | } | 1524 | } |
1530 | 1525 | ||
1531 | static unsigned long regno; | 1526 | static unsigned long regno; |
1532 | extern char exc_prolog; | 1527 | extern char exc_prolog; |
1533 | extern char dec_exc; | 1528 | extern char dec_exc; |
1534 | 1529 | ||
1535 | void super_regs(void) | 1530 | void super_regs(void) |
1536 | { | 1531 | { |
1537 | int cmd; | 1532 | int cmd; |
1538 | unsigned long val; | 1533 | unsigned long val; |
1539 | #ifdef CONFIG_PPC_ISERIES | 1534 | #ifdef CONFIG_PPC_ISERIES |
1540 | struct paca_struct *ptrPaca = NULL; | 1535 | struct paca_struct *ptrPaca = NULL; |
1541 | struct lppaca *ptrLpPaca = NULL; | 1536 | struct lppaca *ptrLpPaca = NULL; |
1542 | struct ItLpRegSave *ptrLpRegSave = NULL; | 1537 | struct ItLpRegSave *ptrLpRegSave = NULL; |
1543 | #endif | 1538 | #endif |
1544 | 1539 | ||
1545 | cmd = skipbl(); | 1540 | cmd = skipbl(); |
1546 | if (cmd == '\n') { | 1541 | if (cmd == '\n') { |
1547 | unsigned long sp, toc; | 1542 | unsigned long sp, toc; |
1548 | asm("mr %0,1" : "=r" (sp) :); | 1543 | asm("mr %0,1" : "=r" (sp) :); |
1549 | asm("mr %0,2" : "=r" (toc) :); | 1544 | asm("mr %0,2" : "=r" (toc) :); |
1550 | 1545 | ||
1551 | printf("msr = "REG" sprg0= "REG"\n", | 1546 | printf("msr = "REG" sprg0= "REG"\n", |
1552 | mfmsr(), mfspr(SPRN_SPRG0)); | 1547 | mfmsr(), mfspr(SPRN_SPRG0)); |
1553 | printf("pvr = "REG" sprg1= "REG"\n", | 1548 | printf("pvr = "REG" sprg1= "REG"\n", |
1554 | mfspr(SPRN_PVR), mfspr(SPRN_SPRG1)); | 1549 | mfspr(SPRN_PVR), mfspr(SPRN_SPRG1)); |
1555 | printf("dec = "REG" sprg2= "REG"\n", | 1550 | printf("dec = "REG" sprg2= "REG"\n", |
1556 | mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); | 1551 | mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); |
1557 | printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); | 1552 | printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); |
1558 | printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR)); | 1553 | printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR)); |
1559 | #ifdef CONFIG_PPC_ISERIES | 1554 | #ifdef CONFIG_PPC_ISERIES |
1560 | // Dump out relevant Paca data areas. | 1555 | // Dump out relevant Paca data areas. |
1561 | printf("Paca: \n"); | 1556 | printf("Paca: \n"); |
1562 | ptrPaca = get_paca(); | 1557 | ptrPaca = get_paca(); |
1563 | 1558 | ||
1564 | printf(" Local Processor Control Area (LpPaca): \n"); | 1559 | printf(" Local Processor Control Area (LpPaca): \n"); |
1565 | ptrLpPaca = ptrPaca->lppaca_ptr; | 1560 | ptrLpPaca = ptrPaca->lppaca_ptr; |
1566 | printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", | 1561 | printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", |
1567 | ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); | 1562 | ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); |
1568 | printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", | 1563 | printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", |
1569 | ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); | 1564 | ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); |
1570 | printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5); | 1565 | printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5); |
1571 | 1566 | ||
1572 | printf(" Local Processor Register Save Area (LpRegSave): \n"); | 1567 | printf(" Local Processor Register Save Area (LpRegSave): \n"); |
1573 | ptrLpRegSave = ptrPaca->reg_save_ptr; | 1568 | ptrLpRegSave = ptrPaca->reg_save_ptr; |
1574 | printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n", | 1569 | printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n", |
1575 | ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0); | 1570 | ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0); |
1576 | printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n", | 1571 | printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n", |
1577 | ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3); | 1572 | ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3); |
1578 | printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n", | 1573 | printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n", |
1579 | ptrLpRegSave->xMSR, ptrLpRegSave->xNIA); | 1574 | ptrLpRegSave->xMSR, ptrLpRegSave->xNIA); |
1580 | #endif | 1575 | #endif |
1581 | 1576 | ||
1582 | return; | 1577 | return; |
1583 | } | 1578 | } |
1584 | 1579 | ||
1585 | scanhex(®no); | 1580 | scanhex(®no); |
1586 | switch (cmd) { | 1581 | switch (cmd) { |
1587 | case 'w': | 1582 | case 'w': |
1588 | val = read_spr(regno); | 1583 | val = read_spr(regno); |
1589 | scanhex(&val); | 1584 | scanhex(&val); |
1590 | write_spr(regno, val); | 1585 | write_spr(regno, val); |
1591 | /* fall through */ | 1586 | /* fall through */ |
1592 | case 'r': | 1587 | case 'r': |
1593 | printf("spr %lx = %lx\n", regno, read_spr(regno)); | 1588 | printf("spr %lx = %lx\n", regno, read_spr(regno)); |
1594 | break; | 1589 | break; |
1595 | } | 1590 | } |
1596 | scannl(); | 1591 | scannl(); |
1597 | } | 1592 | } |
1598 | 1593 | ||
1599 | /* | 1594 | /* |
1600 | * Stuff for reading and writing memory safely | 1595 | * Stuff for reading and writing memory safely |
1601 | */ | 1596 | */ |
1602 | int | 1597 | int |
1603 | mread(unsigned long adrs, void *buf, int size) | 1598 | mread(unsigned long adrs, void *buf, int size) |
1604 | { | 1599 | { |
1605 | volatile int n; | 1600 | volatile int n; |
1606 | char *p, *q; | 1601 | char *p, *q; |
1607 | 1602 | ||
1608 | n = 0; | 1603 | n = 0; |
1609 | if (setjmp(bus_error_jmp) == 0) { | 1604 | if (setjmp(bus_error_jmp) == 0) { |
1610 | catch_memory_errors = 1; | 1605 | catch_memory_errors = 1; |
1611 | sync(); | 1606 | sync(); |
1612 | p = (char *)adrs; | 1607 | p = (char *)adrs; |
1613 | q = (char *)buf; | 1608 | q = (char *)buf; |
1614 | switch (size) { | 1609 | switch (size) { |
1615 | case 2: | 1610 | case 2: |
1616 | *(u16 *)q = *(u16 *)p; | 1611 | *(u16 *)q = *(u16 *)p; |
1617 | break; | 1612 | break; |
1618 | case 4: | 1613 | case 4: |
1619 | *(u32 *)q = *(u32 *)p; | 1614 | *(u32 *)q = *(u32 *)p; |
1620 | break; | 1615 | break; |
1621 | case 8: | 1616 | case 8: |
1622 | *(u64 *)q = *(u64 *)p; | 1617 | *(u64 *)q = *(u64 *)p; |
1623 | break; | 1618 | break; |
1624 | default: | 1619 | default: |
1625 | for( ; n < size; ++n) { | 1620 | for( ; n < size; ++n) { |
1626 | *q++ = *p++; | 1621 | *q++ = *p++; |
1627 | sync(); | 1622 | sync(); |
1628 | } | 1623 | } |
1629 | } | 1624 | } |
1630 | sync(); | 1625 | sync(); |
1631 | /* wait a little while to see if we get a machine check */ | 1626 | /* wait a little while to see if we get a machine check */ |
1632 | __delay(200); | 1627 | __delay(200); |
1633 | n = size; | 1628 | n = size; |
1634 | } | 1629 | } |
1635 | catch_memory_errors = 0; | 1630 | catch_memory_errors = 0; |
1636 | return n; | 1631 | return n; |
1637 | } | 1632 | } |
1638 | 1633 | ||
1639 | int | 1634 | int |
1640 | mwrite(unsigned long adrs, void *buf, int size) | 1635 | mwrite(unsigned long adrs, void *buf, int size) |
1641 | { | 1636 | { |
1642 | volatile int n; | 1637 | volatile int n; |
1643 | char *p, *q; | 1638 | char *p, *q; |
1644 | 1639 | ||
1645 | n = 0; | 1640 | n = 0; |
1646 | if (setjmp(bus_error_jmp) == 0) { | 1641 | if (setjmp(bus_error_jmp) == 0) { |
1647 | catch_memory_errors = 1; | 1642 | catch_memory_errors = 1; |
1648 | sync(); | 1643 | sync(); |
1649 | p = (char *) adrs; | 1644 | p = (char *) adrs; |
1650 | q = (char *) buf; | 1645 | q = (char *) buf; |
1651 | switch (size) { | 1646 | switch (size) { |
1652 | case 2: | 1647 | case 2: |
1653 | *(u16 *)p = *(u16 *)q; | 1648 | *(u16 *)p = *(u16 *)q; |
1654 | break; | 1649 | break; |
1655 | case 4: | 1650 | case 4: |
1656 | *(u32 *)p = *(u32 *)q; | 1651 | *(u32 *)p = *(u32 *)q; |
1657 | break; | 1652 | break; |
1658 | case 8: | 1653 | case 8: |
1659 | *(u64 *)p = *(u64 *)q; | 1654 | *(u64 *)p = *(u64 *)q; |
1660 | break; | 1655 | break; |
1661 | default: | 1656 | default: |
1662 | for ( ; n < size; ++n) { | 1657 | for ( ; n < size; ++n) { |
1663 | *p++ = *q++; | 1658 | *p++ = *q++; |
1664 | sync(); | 1659 | sync(); |
1665 | } | 1660 | } |
1666 | } | 1661 | } |
1667 | sync(); | 1662 | sync(); |
1668 | /* wait a little while to see if we get a machine check */ | 1663 | /* wait a little while to see if we get a machine check */ |
1669 | __delay(200); | 1664 | __delay(200); |
1670 | n = size; | 1665 | n = size; |
1671 | } else { | 1666 | } else { |
1672 | printf("*** Error writing address %x\n", adrs + n); | 1667 | printf("*** Error writing address %x\n", adrs + n); |
1673 | } | 1668 | } |
1674 | catch_memory_errors = 0; | 1669 | catch_memory_errors = 0; |
1675 | return n; | 1670 | return n; |
1676 | } | 1671 | } |
1677 | 1672 | ||
1678 | static int fault_type; | 1673 | static int fault_type; |
1679 | static int fault_except; | 1674 | static int fault_except; |
1680 | static char *fault_chars[] = { "--", "**", "##" }; | 1675 | static char *fault_chars[] = { "--", "**", "##" }; |
1681 | 1676 | ||
1682 | static int handle_fault(struct pt_regs *regs) | 1677 | static int handle_fault(struct pt_regs *regs) |
1683 | { | 1678 | { |
1684 | fault_except = TRAP(regs); | 1679 | fault_except = TRAP(regs); |
1685 | switch (TRAP(regs)) { | 1680 | switch (TRAP(regs)) { |
1686 | case 0x200: | 1681 | case 0x200: |
1687 | fault_type = 0; | 1682 | fault_type = 0; |
1688 | break; | 1683 | break; |
1689 | case 0x300: | 1684 | case 0x300: |
1690 | case 0x380: | 1685 | case 0x380: |
1691 | fault_type = 1; | 1686 | fault_type = 1; |
1692 | break; | 1687 | break; |
1693 | default: | 1688 | default: |
1694 | fault_type = 2; | 1689 | fault_type = 2; |
1695 | } | 1690 | } |
1696 | 1691 | ||
1697 | longjmp(bus_error_jmp, 1); | 1692 | longjmp(bus_error_jmp, 1); |
1698 | 1693 | ||
1699 | return 0; | 1694 | return 0; |
1700 | } | 1695 | } |
1701 | 1696 | ||
1702 | #define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) | 1697 | #define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) |
1703 | 1698 | ||
1704 | void | 1699 | void |
1705 | byterev(unsigned char *val, int size) | 1700 | byterev(unsigned char *val, int size) |
1706 | { | 1701 | { |
1707 | int t; | 1702 | int t; |
1708 | 1703 | ||
1709 | switch (size) { | 1704 | switch (size) { |
1710 | case 2: | 1705 | case 2: |
1711 | SWAP(val[0], val[1], t); | 1706 | SWAP(val[0], val[1], t); |
1712 | break; | 1707 | break; |
1713 | case 4: | 1708 | case 4: |
1714 | SWAP(val[0], val[3], t); | 1709 | SWAP(val[0], val[3], t); |
1715 | SWAP(val[1], val[2], t); | 1710 | SWAP(val[1], val[2], t); |
1716 | break; | 1711 | break; |
1717 | case 8: /* is there really any use for this? */ | 1712 | case 8: /* is there really any use for this? */ |
1718 | SWAP(val[0], val[7], t); | 1713 | SWAP(val[0], val[7], t); |
1719 | SWAP(val[1], val[6], t); | 1714 | SWAP(val[1], val[6], t); |
1720 | SWAP(val[2], val[5], t); | 1715 | SWAP(val[2], val[5], t); |
1721 | SWAP(val[3], val[4], t); | 1716 | SWAP(val[3], val[4], t); |
1722 | break; | 1717 | break; |
1723 | } | 1718 | } |
1724 | } | 1719 | } |
1725 | 1720 | ||
1726 | static int brev; | 1721 | static int brev; |
1727 | static int mnoread; | 1722 | static int mnoread; |
1728 | 1723 | ||
1729 | static char *memex_help_string = | 1724 | static char *memex_help_string = |
1730 | "Memory examine command usage:\n" | 1725 | "Memory examine command usage:\n" |
1731 | "m [addr] [flags] examine/change memory\n" | 1726 | "m [addr] [flags] examine/change memory\n" |
1732 | " addr is optional. will start where left off.\n" | 1727 | " addr is optional. will start where left off.\n" |
1733 | " flags may include chars from this set:\n" | 1728 | " flags may include chars from this set:\n" |
1734 | " b modify by bytes (default)\n" | 1729 | " b modify by bytes (default)\n" |
1735 | " w modify by words (2 byte)\n" | 1730 | " w modify by words (2 byte)\n" |
1736 | " l modify by longs (4 byte)\n" | 1731 | " l modify by longs (4 byte)\n" |
1737 | " d modify by doubleword (8 byte)\n" | 1732 | " d modify by doubleword (8 byte)\n" |
1738 | " r toggle reverse byte order mode\n" | 1733 | " r toggle reverse byte order mode\n" |
1739 | " n do not read memory (for i/o spaces)\n" | 1734 | " n do not read memory (for i/o spaces)\n" |
1740 | " . ok to read (default)\n" | 1735 | " . ok to read (default)\n" |
1741 | "NOTE: flags are saved as defaults\n" | 1736 | "NOTE: flags are saved as defaults\n" |
1742 | ""; | 1737 | ""; |
1743 | 1738 | ||
1744 | static char *memex_subcmd_help_string = | 1739 | static char *memex_subcmd_help_string = |
1745 | "Memory examine subcommands:\n" | 1740 | "Memory examine subcommands:\n" |
1746 | " hexval write this val to current location\n" | 1741 | " hexval write this val to current location\n" |
1747 | " 'string' write chars from string to this location\n" | 1742 | " 'string' write chars from string to this location\n" |
1748 | " ' increment address\n" | 1743 | " ' increment address\n" |
1749 | " ^ decrement address\n" | 1744 | " ^ decrement address\n" |
1750 | " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n" | 1745 | " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n" |
1751 | " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n" | 1746 | " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n" |
1752 | " ` clear no-read flag\n" | 1747 | " ` clear no-read flag\n" |
1753 | " ; stay at this addr\n" | 1748 | " ; stay at this addr\n" |
1754 | " v change to byte mode\n" | 1749 | " v change to byte mode\n" |
1755 | " w change to word (2 byte) mode\n" | 1750 | " w change to word (2 byte) mode\n" |
1756 | " l change to long (4 byte) mode\n" | 1751 | " l change to long (4 byte) mode\n" |
1757 | " u change to doubleword (8 byte) mode\n" | 1752 | " u change to doubleword (8 byte) mode\n" |
1758 | " m addr change current addr\n" | 1753 | " m addr change current addr\n" |
1759 | " n toggle no-read flag\n" | 1754 | " n toggle no-read flag\n" |
1760 | " r toggle byte reverse flag\n" | 1755 | " r toggle byte reverse flag\n" |
1761 | " < count back up count bytes\n" | 1756 | " < count back up count bytes\n" |
1762 | " > count skip forward count bytes\n" | 1757 | " > count skip forward count bytes\n" |
1763 | " x exit this mode\n" | 1758 | " x exit this mode\n" |
1764 | ""; | 1759 | ""; |
1765 | 1760 | ||
1766 | void | 1761 | void |
1767 | memex(void) | 1762 | memex(void) |
1768 | { | 1763 | { |
1769 | int cmd, inc, i, nslash; | 1764 | int cmd, inc, i, nslash; |
1770 | unsigned long n; | 1765 | unsigned long n; |
1771 | unsigned char val[16]; | 1766 | unsigned char val[16]; |
1772 | 1767 | ||
1773 | scanhex((void *)&adrs); | 1768 | scanhex((void *)&adrs); |
1774 | cmd = skipbl(); | 1769 | cmd = skipbl(); |
1775 | if (cmd == '?') { | 1770 | if (cmd == '?') { |
1776 | printf(memex_help_string); | 1771 | printf(memex_help_string); |
1777 | return; | 1772 | return; |
1778 | } else { | 1773 | } else { |
1779 | termch = cmd; | 1774 | termch = cmd; |
1780 | } | 1775 | } |
1781 | last_cmd = "m\n"; | 1776 | last_cmd = "m\n"; |
1782 | while ((cmd = skipbl()) != '\n') { | 1777 | while ((cmd = skipbl()) != '\n') { |
1783 | switch( cmd ){ | 1778 | switch( cmd ){ |
1784 | case 'b': size = 1; break; | 1779 | case 'b': size = 1; break; |
1785 | case 'w': size = 2; break; | 1780 | case 'w': size = 2; break; |
1786 | case 'l': size = 4; break; | 1781 | case 'l': size = 4; break; |
1787 | case 'd': size = 8; break; | 1782 | case 'd': size = 8; break; |
1788 | case 'r': brev = !brev; break; | 1783 | case 'r': brev = !brev; break; |
1789 | case 'n': mnoread = 1; break; | 1784 | case 'n': mnoread = 1; break; |
1790 | case '.': mnoread = 0; break; | 1785 | case '.': mnoread = 0; break; |
1791 | } | 1786 | } |
1792 | } | 1787 | } |
1793 | if( size <= 0 ) | 1788 | if( size <= 0 ) |
1794 | size = 1; | 1789 | size = 1; |
1795 | else if( size > 8 ) | 1790 | else if( size > 8 ) |
1796 | size = 8; | 1791 | size = 8; |
1797 | for(;;){ | 1792 | for(;;){ |
1798 | if (!mnoread) | 1793 | if (!mnoread) |
1799 | n = mread(adrs, val, size); | 1794 | n = mread(adrs, val, size); |
1800 | printf("%.16x%c", adrs, brev? 'r': ' '); | 1795 | printf("%.16x%c", adrs, brev? 'r': ' '); |
1801 | if (!mnoread) { | 1796 | if (!mnoread) { |
1802 | if (brev) | 1797 | if (brev) |
1803 | byterev(val, size); | 1798 | byterev(val, size); |
1804 | putchar(' '); | 1799 | putchar(' '); |
1805 | for (i = 0; i < n; ++i) | 1800 | for (i = 0; i < n; ++i) |
1806 | printf("%.2x", val[i]); | 1801 | printf("%.2x", val[i]); |
1807 | for (; i < size; ++i) | 1802 | for (; i < size; ++i) |
1808 | printf("%s", fault_chars[fault_type]); | 1803 | printf("%s", fault_chars[fault_type]); |
1809 | } | 1804 | } |
1810 | putchar(' '); | 1805 | putchar(' '); |
1811 | inc = size; | 1806 | inc = size; |
1812 | nslash = 0; | 1807 | nslash = 0; |
1813 | for(;;){ | 1808 | for(;;){ |
1814 | if( scanhex(&n) ){ | 1809 | if( scanhex(&n) ){ |
1815 | for (i = 0; i < size; ++i) | 1810 | for (i = 0; i < size; ++i) |
1816 | val[i] = n >> (i * 8); | 1811 | val[i] = n >> (i * 8); |
1817 | if (!brev) | 1812 | if (!brev) |
1818 | byterev(val, size); | 1813 | byterev(val, size); |
1819 | mwrite(adrs, val, size); | 1814 | mwrite(adrs, val, size); |
1820 | inc = size; | 1815 | inc = size; |
1821 | } | 1816 | } |
1822 | cmd = skipbl(); | 1817 | cmd = skipbl(); |
1823 | if (cmd == '\n') | 1818 | if (cmd == '\n') |
1824 | break; | 1819 | break; |
1825 | inc = 0; | 1820 | inc = 0; |
1826 | switch (cmd) { | 1821 | switch (cmd) { |
1827 | case '\'': | 1822 | case '\'': |
1828 | for(;;){ | 1823 | for(;;){ |
1829 | n = inchar(); | 1824 | n = inchar(); |
1830 | if( n == '\\' ) | 1825 | if( n == '\\' ) |
1831 | n = bsesc(); | 1826 | n = bsesc(); |
1832 | else if( n == '\'' ) | 1827 | else if( n == '\'' ) |
1833 | break; | 1828 | break; |
1834 | for (i = 0; i < size; ++i) | 1829 | for (i = 0; i < size; ++i) |
1835 | val[i] = n >> (i * 8); | 1830 | val[i] = n >> (i * 8); |
1836 | if (!brev) | 1831 | if (!brev) |
1837 | byterev(val, size); | 1832 | byterev(val, size); |
1838 | mwrite(adrs, val, size); | 1833 | mwrite(adrs, val, size); |
1839 | adrs += size; | 1834 | adrs += size; |
1840 | } | 1835 | } |
1841 | adrs -= size; | 1836 | adrs -= size; |
1842 | inc = size; | 1837 | inc = size; |
1843 | break; | 1838 | break; |
1844 | case ',': | 1839 | case ',': |
1845 | adrs += size; | 1840 | adrs += size; |
1846 | break; | 1841 | break; |
1847 | case '.': | 1842 | case '.': |
1848 | mnoread = 0; | 1843 | mnoread = 0; |
1849 | break; | 1844 | break; |
1850 | case ';': | 1845 | case ';': |
1851 | break; | 1846 | break; |
1852 | case 'x': | 1847 | case 'x': |
1853 | case EOF: | 1848 | case EOF: |
1854 | scannl(); | 1849 | scannl(); |
1855 | return; | 1850 | return; |
1856 | case 'b': | 1851 | case 'b': |
1857 | case 'v': | 1852 | case 'v': |
1858 | size = 1; | 1853 | size = 1; |
1859 | break; | 1854 | break; |
1860 | case 'w': | 1855 | case 'w': |
1861 | size = 2; | 1856 | size = 2; |
1862 | break; | 1857 | break; |
1863 | case 'l': | 1858 | case 'l': |
1864 | size = 4; | 1859 | size = 4; |
1865 | break; | 1860 | break; |
1866 | case 'u': | 1861 | case 'u': |
1867 | size = 8; | 1862 | size = 8; |
1868 | break; | 1863 | break; |
1869 | case '^': | 1864 | case '^': |
1870 | adrs -= size; | 1865 | adrs -= size; |
1871 | break; | 1866 | break; |
1872 | break; | 1867 | break; |
1873 | case '/': | 1868 | case '/': |
1874 | if (nslash > 0) | 1869 | if (nslash > 0) |
1875 | adrs -= 1 << nslash; | 1870 | adrs -= 1 << nslash; |
1876 | else | 1871 | else |
1877 | nslash = 0; | 1872 | nslash = 0; |
1878 | nslash += 4; | 1873 | nslash += 4; |
1879 | adrs += 1 << nslash; | 1874 | adrs += 1 << nslash; |
1880 | break; | 1875 | break; |
1881 | case '\\': | 1876 | case '\\': |
1882 | if (nslash < 0) | 1877 | if (nslash < 0) |
1883 | adrs += 1 << -nslash; | 1878 | adrs += 1 << -nslash; |
1884 | else | 1879 | else |
1885 | nslash = 0; | 1880 | nslash = 0; |
1886 | nslash -= 4; | 1881 | nslash -= 4; |
1887 | adrs -= 1 << -nslash; | 1882 | adrs -= 1 << -nslash; |
1888 | break; | 1883 | break; |
1889 | case 'm': | 1884 | case 'm': |
1890 | scanhex((void *)&adrs); | 1885 | scanhex((void *)&adrs); |
1891 | break; | 1886 | break; |
1892 | case 'n': | 1887 | case 'n': |
1893 | mnoread = 1; | 1888 | mnoread = 1; |
1894 | break; | 1889 | break; |
1895 | case 'r': | 1890 | case 'r': |
1896 | brev = !brev; | 1891 | brev = !brev; |
1897 | break; | 1892 | break; |
1898 | case '<': | 1893 | case '<': |
1899 | n = size; | 1894 | n = size; |
1900 | scanhex(&n); | 1895 | scanhex(&n); |
1901 | adrs -= n; | 1896 | adrs -= n; |
1902 | break; | 1897 | break; |
1903 | case '>': | 1898 | case '>': |
1904 | n = size; | 1899 | n = size; |
1905 | scanhex(&n); | 1900 | scanhex(&n); |
1906 | adrs += n; | 1901 | adrs += n; |
1907 | break; | 1902 | break; |
1908 | case '?': | 1903 | case '?': |
1909 | printf(memex_subcmd_help_string); | 1904 | printf(memex_subcmd_help_string); |
1910 | break; | 1905 | break; |
1911 | } | 1906 | } |
1912 | } | 1907 | } |
1913 | adrs += inc; | 1908 | adrs += inc; |
1914 | } | 1909 | } |
1915 | } | 1910 | } |
1916 | 1911 | ||
1917 | int | 1912 | int |
1918 | bsesc(void) | 1913 | bsesc(void) |
1919 | { | 1914 | { |
1920 | int c; | 1915 | int c; |
1921 | 1916 | ||
1922 | c = inchar(); | 1917 | c = inchar(); |
1923 | switch( c ){ | 1918 | switch( c ){ |
1924 | case 'n': c = '\n'; break; | 1919 | case 'n': c = '\n'; break; |
1925 | case 'r': c = '\r'; break; | 1920 | case 'r': c = '\r'; break; |
1926 | case 'b': c = '\b'; break; | 1921 | case 'b': c = '\b'; break; |
1927 | case 't': c = '\t'; break; | 1922 | case 't': c = '\t'; break; |
1928 | } | 1923 | } |
1929 | return c; | 1924 | return c; |
1930 | } | 1925 | } |
1931 | 1926 | ||
1932 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ | 1927 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ |
1933 | || ('a' <= (c) && (c) <= 'f') \ | 1928 | || ('a' <= (c) && (c) <= 'f') \ |
1934 | || ('A' <= (c) && (c) <= 'F')) | 1929 | || ('A' <= (c) && (c) <= 'F')) |
1935 | void | 1930 | void |
1936 | dump(void) | 1931 | dump(void) |
1937 | { | 1932 | { |
1938 | int c; | 1933 | int c; |
1939 | 1934 | ||
1940 | c = inchar(); | 1935 | c = inchar(); |
1941 | if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') | 1936 | if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') |
1942 | termch = c; | 1937 | termch = c; |
1943 | scanhex((void *)&adrs); | 1938 | scanhex((void *)&adrs); |
1944 | if (termch != '\n') | 1939 | if (termch != '\n') |
1945 | termch = 0; | 1940 | termch = 0; |
1946 | if (c == 'i') { | 1941 | if (c == 'i') { |
1947 | scanhex(&nidump); | 1942 | scanhex(&nidump); |
1948 | if (nidump == 0) | 1943 | if (nidump == 0) |
1949 | nidump = 16; | 1944 | nidump = 16; |
1950 | else if (nidump > MAX_DUMP) | 1945 | else if (nidump > MAX_DUMP) |
1951 | nidump = MAX_DUMP; | 1946 | nidump = MAX_DUMP; |
1952 | adrs += ppc_inst_dump(adrs, nidump, 1); | 1947 | adrs += ppc_inst_dump(adrs, nidump, 1); |
1953 | last_cmd = "di\n"; | 1948 | last_cmd = "di\n"; |
1954 | } else { | 1949 | } else { |
1955 | scanhex(&ndump); | 1950 | scanhex(&ndump); |
1956 | if (ndump == 0) | 1951 | if (ndump == 0) |
1957 | ndump = 64; | 1952 | ndump = 64; |
1958 | else if (ndump > MAX_DUMP) | 1953 | else if (ndump > MAX_DUMP) |
1959 | ndump = MAX_DUMP; | 1954 | ndump = MAX_DUMP; |
1960 | prdump(adrs, ndump); | 1955 | prdump(adrs, ndump); |
1961 | adrs += ndump; | 1956 | adrs += ndump; |
1962 | last_cmd = "d\n"; | 1957 | last_cmd = "d\n"; |
1963 | } | 1958 | } |
1964 | } | 1959 | } |
1965 | 1960 | ||
1966 | void | 1961 | void |
1967 | prdump(unsigned long adrs, long ndump) | 1962 | prdump(unsigned long adrs, long ndump) |
1968 | { | 1963 | { |
1969 | long n, m, c, r, nr; | 1964 | long n, m, c, r, nr; |
1970 | unsigned char temp[16]; | 1965 | unsigned char temp[16]; |
1971 | 1966 | ||
1972 | for (n = ndump; n > 0;) { | 1967 | for (n = ndump; n > 0;) { |
1973 | printf(REG, adrs); | 1968 | printf(REG, adrs); |
1974 | putchar(' '); | 1969 | putchar(' '); |
1975 | r = n < 16? n: 16; | 1970 | r = n < 16? n: 16; |
1976 | nr = mread(adrs, temp, r); | 1971 | nr = mread(adrs, temp, r); |
1977 | adrs += nr; | 1972 | adrs += nr; |
1978 | for (m = 0; m < r; ++m) { | 1973 | for (m = 0; m < r; ++m) { |
1979 | if ((m & 7) == 0 && m > 0) | 1974 | if ((m & 7) == 0 && m > 0) |
1980 | putchar(' '); | 1975 | putchar(' '); |
1981 | if (m < nr) | 1976 | if (m < nr) |
1982 | printf("%.2x", temp[m]); | 1977 | printf("%.2x", temp[m]); |
1983 | else | 1978 | else |
1984 | printf("%s", fault_chars[fault_type]); | 1979 | printf("%s", fault_chars[fault_type]); |
1985 | } | 1980 | } |
1986 | if (m <= 8) | 1981 | if (m <= 8) |
1987 | printf(" "); | 1982 | printf(" "); |
1988 | for (; m < 16; ++m) | 1983 | for (; m < 16; ++m) |
1989 | printf(" "); | 1984 | printf(" "); |
1990 | printf(" |"); | 1985 | printf(" |"); |
1991 | for (m = 0; m < r; ++m) { | 1986 | for (m = 0; m < r; ++m) { |
1992 | if (m < nr) { | 1987 | if (m < nr) { |
1993 | c = temp[m]; | 1988 | c = temp[m]; |
1994 | putchar(' ' <= c && c <= '~'? c: '.'); | 1989 | putchar(' ' <= c && c <= '~'? c: '.'); |
1995 | } else | 1990 | } else |
1996 | putchar(' '); | 1991 | putchar(' '); |
1997 | } | 1992 | } |
1998 | n -= r; | 1993 | n -= r; |
1999 | for (; m < 16; ++m) | 1994 | for (; m < 16; ++m) |
2000 | putchar(' '); | 1995 | putchar(' '); |
2001 | printf("|\n"); | 1996 | printf("|\n"); |
2002 | if (nr < r) | 1997 | if (nr < r) |
2003 | break; | 1998 | break; |
2004 | } | 1999 | } |
2005 | } | 2000 | } |
2006 | 2001 | ||
2007 | int | 2002 | int |
2008 | ppc_inst_dump(unsigned long adr, long count, int praddr) | 2003 | ppc_inst_dump(unsigned long adr, long count, int praddr) |
2009 | { | 2004 | { |
2010 | int nr, dotted; | 2005 | int nr, dotted; |
2011 | unsigned long first_adr; | 2006 | unsigned long first_adr; |
2012 | unsigned long inst, last_inst = 0; | 2007 | unsigned long inst, last_inst = 0; |
2013 | unsigned char val[4]; | 2008 | unsigned char val[4]; |
2014 | 2009 | ||
2015 | dotted = 0; | 2010 | dotted = 0; |
2016 | for (first_adr = adr; count > 0; --count, adr += 4) { | 2011 | for (first_adr = adr; count > 0; --count, adr += 4) { |
2017 | nr = mread(adr, val, 4); | 2012 | nr = mread(adr, val, 4); |
2018 | if (nr == 0) { | 2013 | if (nr == 0) { |
2019 | if (praddr) { | 2014 | if (praddr) { |
2020 | const char *x = fault_chars[fault_type]; | 2015 | const char *x = fault_chars[fault_type]; |
2021 | printf(REG" %s%s%s%s\n", adr, x, x, x, x); | 2016 | printf(REG" %s%s%s%s\n", adr, x, x, x, x); |
2022 | } | 2017 | } |
2023 | break; | 2018 | break; |
2024 | } | 2019 | } |
2025 | inst = GETWORD(val); | 2020 | inst = GETWORD(val); |
2026 | if (adr > first_adr && inst == last_inst) { | 2021 | if (adr > first_adr && inst == last_inst) { |
2027 | if (!dotted) { | 2022 | if (!dotted) { |
2028 | printf(" ...\n"); | 2023 | printf(" ...\n"); |
2029 | dotted = 1; | 2024 | dotted = 1; |
2030 | } | 2025 | } |
2031 | continue; | 2026 | continue; |
2032 | } | 2027 | } |
2033 | dotted = 0; | 2028 | dotted = 0; |
2034 | last_inst = inst; | 2029 | last_inst = inst; |
2035 | if (praddr) | 2030 | if (praddr) |
2036 | printf(REG" %.8x", adr, inst); | 2031 | printf(REG" %.8x", adr, inst); |
2037 | printf("\t"); | 2032 | printf("\t"); |
2038 | print_insn_powerpc(inst, adr, 0); /* always returns 4 */ | 2033 | print_insn_powerpc(inst, adr, 0); /* always returns 4 */ |
2039 | printf("\n"); | 2034 | printf("\n"); |
2040 | } | 2035 | } |
2041 | return adr - first_adr; | 2036 | return adr - first_adr; |
2042 | } | 2037 | } |
2043 | 2038 | ||
2044 | void | 2039 | void |
2045 | print_address(unsigned long addr) | 2040 | print_address(unsigned long addr) |
2046 | { | 2041 | { |
2047 | xmon_print_symbol(addr, "\t# ", ""); | 2042 | xmon_print_symbol(addr, "\t# ", ""); |
2048 | } | 2043 | } |
2049 | 2044 | ||
2050 | 2045 | ||
2051 | /* | 2046 | /* |
2052 | * Memory operations - move, set, print differences | 2047 | * Memory operations - move, set, print differences |
2053 | */ | 2048 | */ |
2054 | static unsigned long mdest; /* destination address */ | 2049 | static unsigned long mdest; /* destination address */ |
2055 | static unsigned long msrc; /* source address */ | 2050 | static unsigned long msrc; /* source address */ |
2056 | static unsigned long mval; /* byte value to set memory to */ | 2051 | static unsigned long mval; /* byte value to set memory to */ |
2057 | static unsigned long mcount; /* # bytes to affect */ | 2052 | static unsigned long mcount; /* # bytes to affect */ |
2058 | static unsigned long mdiffs; /* max # differences to print */ | 2053 | static unsigned long mdiffs; /* max # differences to print */ |
2059 | 2054 | ||
2060 | void | 2055 | void |
2061 | memops(int cmd) | 2056 | memops(int cmd) |
2062 | { | 2057 | { |
2063 | scanhex((void *)&mdest); | 2058 | scanhex((void *)&mdest); |
2064 | if( termch != '\n' ) | 2059 | if( termch != '\n' ) |
2065 | termch = 0; | 2060 | termch = 0; |
2066 | scanhex((void *)(cmd == 's'? &mval: &msrc)); | 2061 | scanhex((void *)(cmd == 's'? &mval: &msrc)); |
2067 | if( termch != '\n' ) | 2062 | if( termch != '\n' ) |
2068 | termch = 0; | 2063 | termch = 0; |
2069 | scanhex((void *)&mcount); | 2064 | scanhex((void *)&mcount); |
2070 | switch( cmd ){ | 2065 | switch( cmd ){ |
2071 | case 'm': | 2066 | case 'm': |
2072 | memmove((void *)mdest, (void *)msrc, mcount); | 2067 | memmove((void *)mdest, (void *)msrc, mcount); |
2073 | break; | 2068 | break; |
2074 | case 's': | 2069 | case 's': |
2075 | memset((void *)mdest, mval, mcount); | 2070 | memset((void *)mdest, mval, mcount); |
2076 | break; | 2071 | break; |
2077 | case 'd': | 2072 | case 'd': |
2078 | if( termch != '\n' ) | 2073 | if( termch != '\n' ) |
2079 | termch = 0; | 2074 | termch = 0; |
2080 | scanhex((void *)&mdiffs); | 2075 | scanhex((void *)&mdiffs); |
2081 | memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs); | 2076 | memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs); |
2082 | break; | 2077 | break; |
2083 | } | 2078 | } |
2084 | } | 2079 | } |
2085 | 2080 | ||
2086 | void | 2081 | void |
2087 | memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr) | 2082 | memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr) |
2088 | { | 2083 | { |
2089 | unsigned n, prt; | 2084 | unsigned n, prt; |
2090 | 2085 | ||
2091 | prt = 0; | 2086 | prt = 0; |
2092 | for( n = nb; n > 0; --n ) | 2087 | for( n = nb; n > 0; --n ) |
2093 | if( *p1++ != *p2++ ) | 2088 | if( *p1++ != *p2++ ) |
2094 | if( ++prt <= maxpr ) | 2089 | if( ++prt <= maxpr ) |
2095 | printf("%.16x %.2x # %.16x %.2x\n", p1 - 1, | 2090 | printf("%.16x %.2x # %.16x %.2x\n", p1 - 1, |
2096 | p1[-1], p2 - 1, p2[-1]); | 2091 | p1[-1], p2 - 1, p2[-1]); |
2097 | if( prt > maxpr ) | 2092 | if( prt > maxpr ) |
2098 | printf("Total of %d differences\n", prt); | 2093 | printf("Total of %d differences\n", prt); |
2099 | } | 2094 | } |
2100 | 2095 | ||
2101 | static unsigned mend; | 2096 | static unsigned mend; |
2102 | static unsigned mask; | 2097 | static unsigned mask; |
2103 | 2098 | ||
2104 | void | 2099 | void |
2105 | memlocate(void) | 2100 | memlocate(void) |
2106 | { | 2101 | { |
2107 | unsigned a, n; | 2102 | unsigned a, n; |
2108 | unsigned char val[4]; | 2103 | unsigned char val[4]; |
2109 | 2104 | ||
2110 | last_cmd = "ml"; | 2105 | last_cmd = "ml"; |
2111 | scanhex((void *)&mdest); | 2106 | scanhex((void *)&mdest); |
2112 | if (termch != '\n') { | 2107 | if (termch != '\n') { |
2113 | termch = 0; | 2108 | termch = 0; |
2114 | scanhex((void *)&mend); | 2109 | scanhex((void *)&mend); |
2115 | if (termch != '\n') { | 2110 | if (termch != '\n') { |
2116 | termch = 0; | 2111 | termch = 0; |
2117 | scanhex((void *)&mval); | 2112 | scanhex((void *)&mval); |
2118 | mask = ~0; | 2113 | mask = ~0; |
2119 | if (termch != '\n') termch = 0; | 2114 | if (termch != '\n') termch = 0; |
2120 | scanhex((void *)&mask); | 2115 | scanhex((void *)&mask); |
2121 | } | 2116 | } |
2122 | } | 2117 | } |
2123 | n = 0; | 2118 | n = 0; |
2124 | for (a = mdest; a < mend; a += 4) { | 2119 | for (a = mdest; a < mend; a += 4) { |
2125 | if (mread(a, val, 4) == 4 | 2120 | if (mread(a, val, 4) == 4 |
2126 | && ((GETWORD(val) ^ mval) & mask) == 0) { | 2121 | && ((GETWORD(val) ^ mval) & mask) == 0) { |
2127 | printf("%.16x: %.16x\n", a, GETWORD(val)); | 2122 | printf("%.16x: %.16x\n", a, GETWORD(val)); |
2128 | if (++n >= 10) | 2123 | if (++n >= 10) |
2129 | break; | 2124 | break; |
2130 | } | 2125 | } |
2131 | } | 2126 | } |
2132 | } | 2127 | } |
2133 | 2128 | ||
2134 | static unsigned long mskip = 0x1000; | 2129 | static unsigned long mskip = 0x1000; |
2135 | static unsigned long mlim = 0xffffffff; | 2130 | static unsigned long mlim = 0xffffffff; |
2136 | 2131 | ||
2137 | void | 2132 | void |
2138 | memzcan(void) | 2133 | memzcan(void) |
2139 | { | 2134 | { |
2140 | unsigned char v; | 2135 | unsigned char v; |
2141 | unsigned a; | 2136 | unsigned a; |
2142 | int ok, ook; | 2137 | int ok, ook; |
2143 | 2138 | ||
2144 | scanhex(&mdest); | 2139 | scanhex(&mdest); |
2145 | if (termch != '\n') termch = 0; | 2140 | if (termch != '\n') termch = 0; |
2146 | scanhex(&mskip); | 2141 | scanhex(&mskip); |
2147 | if (termch != '\n') termch = 0; | 2142 | if (termch != '\n') termch = 0; |
2148 | scanhex(&mlim); | 2143 | scanhex(&mlim); |
2149 | ook = 0; | 2144 | ook = 0; |
2150 | for (a = mdest; a < mlim; a += mskip) { | 2145 | for (a = mdest; a < mlim; a += mskip) { |
2151 | ok = mread(a, &v, 1); | 2146 | ok = mread(a, &v, 1); |
2152 | if (ok && !ook) { | 2147 | if (ok && !ook) { |
2153 | printf("%.8x .. ", a); | 2148 | printf("%.8x .. ", a); |
2154 | fflush(stdout); | ||
2155 | } else if (!ok && ook) | 2149 | } else if (!ok && ook) |
2156 | printf("%.8x\n", a - mskip); | 2150 | printf("%.8x\n", a - mskip); |
2157 | ook = ok; | 2151 | ook = ok; |
2158 | if (a + mskip < a) | 2152 | if (a + mskip < a) |
2159 | break; | 2153 | break; |
2160 | } | 2154 | } |
2161 | if (ook) | 2155 | if (ook) |
2162 | printf("%.8x\n", a - mskip); | 2156 | printf("%.8x\n", a - mskip); |
2163 | } | 2157 | } |
2164 | 2158 | ||
2165 | void proccall(void) | 2159 | void proccall(void) |
2166 | { | 2160 | { |
2167 | unsigned long args[8]; | 2161 | unsigned long args[8]; |
2168 | unsigned long ret; | 2162 | unsigned long ret; |
2169 | int i; | 2163 | int i; |
2170 | typedef unsigned long (*callfunc_t)(unsigned long, unsigned long, | 2164 | typedef unsigned long (*callfunc_t)(unsigned long, unsigned long, |
2171 | unsigned long, unsigned long, unsigned long, | 2165 | unsigned long, unsigned long, unsigned long, |
2172 | unsigned long, unsigned long, unsigned long); | 2166 | unsigned long, unsigned long, unsigned long); |
2173 | callfunc_t func; | 2167 | callfunc_t func; |
2174 | 2168 | ||
2175 | if (!scanhex(&adrs)) | 2169 | if (!scanhex(&adrs)) |
2176 | return; | 2170 | return; |
2177 | if (termch != '\n') | 2171 | if (termch != '\n') |
2178 | termch = 0; | 2172 | termch = 0; |
2179 | for (i = 0; i < 8; ++i) | 2173 | for (i = 0; i < 8; ++i) |
2180 | args[i] = 0; | 2174 | args[i] = 0; |
2181 | for (i = 0; i < 8; ++i) { | 2175 | for (i = 0; i < 8; ++i) { |
2182 | if (!scanhex(&args[i]) || termch == '\n') | 2176 | if (!scanhex(&args[i]) || termch == '\n') |
2183 | break; | 2177 | break; |
2184 | termch = 0; | 2178 | termch = 0; |
2185 | } | 2179 | } |
2186 | func = (callfunc_t) adrs; | 2180 | func = (callfunc_t) adrs; |
2187 | ret = 0; | 2181 | ret = 0; |
2188 | if (setjmp(bus_error_jmp) == 0) { | 2182 | if (setjmp(bus_error_jmp) == 0) { |
2189 | catch_memory_errors = 1; | 2183 | catch_memory_errors = 1; |
2190 | sync(); | 2184 | sync(); |
2191 | ret = func(args[0], args[1], args[2], args[3], | 2185 | ret = func(args[0], args[1], args[2], args[3], |
2192 | args[4], args[5], args[6], args[7]); | 2186 | args[4], args[5], args[6], args[7]); |
2193 | sync(); | 2187 | sync(); |
2194 | printf("return value is %x\n", ret); | 2188 | printf("return value is %x\n", ret); |
2195 | } else { | 2189 | } else { |
2196 | printf("*** %x exception occurred\n", fault_except); | 2190 | printf("*** %x exception occurred\n", fault_except); |
2197 | } | 2191 | } |
2198 | catch_memory_errors = 0; | 2192 | catch_memory_errors = 0; |
2199 | } | 2193 | } |
2200 | 2194 | ||
2201 | /* Input scanning routines */ | 2195 | /* Input scanning routines */ |
2202 | int | 2196 | int |
2203 | skipbl(void) | 2197 | skipbl(void) |
2204 | { | 2198 | { |
2205 | int c; | 2199 | int c; |
2206 | 2200 | ||
2207 | if( termch != 0 ){ | 2201 | if( termch != 0 ){ |
2208 | c = termch; | 2202 | c = termch; |
2209 | termch = 0; | 2203 | termch = 0; |
2210 | } else | 2204 | } else |
2211 | c = inchar(); | 2205 | c = inchar(); |
2212 | while( c == ' ' || c == '\t' ) | 2206 | while( c == ' ' || c == '\t' ) |
2213 | c = inchar(); | 2207 | c = inchar(); |
2214 | return c; | 2208 | return c; |
2215 | } | 2209 | } |
2216 | 2210 | ||
2217 | #define N_PTREGS 44 | 2211 | #define N_PTREGS 44 |
2218 | static char *regnames[N_PTREGS] = { | 2212 | static char *regnames[N_PTREGS] = { |
2219 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | 2213 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
2220 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | 2214 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", |
2221 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | 2215 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", |
2222 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | 2216 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", |
2223 | "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", | 2217 | "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", |
2224 | #ifdef CONFIG_PPC64 | 2218 | #ifdef CONFIG_PPC64 |
2225 | "softe", | 2219 | "softe", |
2226 | #else | 2220 | #else |
2227 | "mq", | 2221 | "mq", |
2228 | #endif | 2222 | #endif |
2229 | "trap", "dar", "dsisr", "res" | 2223 | "trap", "dar", "dsisr", "res" |
2230 | }; | 2224 | }; |
2231 | 2225 | ||
2232 | int | 2226 | int |
2233 | scanhex(unsigned long *vp) | 2227 | scanhex(unsigned long *vp) |
2234 | { | 2228 | { |
2235 | int c, d; | 2229 | int c, d; |
2236 | unsigned long v; | 2230 | unsigned long v; |
2237 | 2231 | ||
2238 | c = skipbl(); | 2232 | c = skipbl(); |
2239 | if (c == '%') { | 2233 | if (c == '%') { |
2240 | /* parse register name */ | 2234 | /* parse register name */ |
2241 | char regname[8]; | 2235 | char regname[8]; |
2242 | int i; | 2236 | int i; |
2243 | 2237 | ||
2244 | for (i = 0; i < sizeof(regname) - 1; ++i) { | 2238 | for (i = 0; i < sizeof(regname) - 1; ++i) { |
2245 | c = inchar(); | 2239 | c = inchar(); |
2246 | if (!isalnum(c)) { | 2240 | if (!isalnum(c)) { |
2247 | termch = c; | 2241 | termch = c; |
2248 | break; | 2242 | break; |
2249 | } | 2243 | } |
2250 | regname[i] = c; | 2244 | regname[i] = c; |
2251 | } | 2245 | } |
2252 | regname[i] = 0; | 2246 | regname[i] = 0; |
2253 | for (i = 0; i < N_PTREGS; ++i) { | 2247 | for (i = 0; i < N_PTREGS; ++i) { |
2254 | if (strcmp(regnames[i], regname) == 0) { | 2248 | if (strcmp(regnames[i], regname) == 0) { |
2255 | if (xmon_regs == NULL) { | 2249 | if (xmon_regs == NULL) { |
2256 | printf("regs not available\n"); | 2250 | printf("regs not available\n"); |
2257 | return 0; | 2251 | return 0; |
2258 | } | 2252 | } |
2259 | *vp = ((unsigned long *)xmon_regs)[i]; | 2253 | *vp = ((unsigned long *)xmon_regs)[i]; |
2260 | return 1; | 2254 | return 1; |
2261 | } | 2255 | } |
2262 | } | 2256 | } |
2263 | printf("invalid register name '%%%s'\n", regname); | 2257 | printf("invalid register name '%%%s'\n", regname); |
2264 | return 0; | 2258 | return 0; |
2265 | } | 2259 | } |
2266 | 2260 | ||
2267 | /* skip leading "0x" if any */ | 2261 | /* skip leading "0x" if any */ |
2268 | 2262 | ||
2269 | if (c == '0') { | 2263 | if (c == '0') { |
2270 | c = inchar(); | 2264 | c = inchar(); |
2271 | if (c == 'x') { | 2265 | if (c == 'x') { |
2272 | c = inchar(); | 2266 | c = inchar(); |
2273 | } else { | 2267 | } else { |
2274 | d = hexdigit(c); | 2268 | d = hexdigit(c); |
2275 | if (d == EOF) { | 2269 | if (d == EOF) { |
2276 | termch = c; | 2270 | termch = c; |
2277 | *vp = 0; | 2271 | *vp = 0; |
2278 | return 1; | 2272 | return 1; |
2279 | } | 2273 | } |
2280 | } | 2274 | } |
2281 | } else if (c == '$') { | 2275 | } else if (c == '$') { |
2282 | int i; | 2276 | int i; |
2283 | for (i=0; i<63; i++) { | 2277 | for (i=0; i<63; i++) { |
2284 | c = inchar(); | 2278 | c = inchar(); |
2285 | if (isspace(c)) { | 2279 | if (isspace(c)) { |
2286 | termch = c; | 2280 | termch = c; |
2287 | break; | 2281 | break; |
2288 | } | 2282 | } |
2289 | tmpstr[i] = c; | 2283 | tmpstr[i] = c; |
2290 | } | 2284 | } |
2291 | tmpstr[i++] = 0; | 2285 | tmpstr[i++] = 0; |
2292 | *vp = 0; | 2286 | *vp = 0; |
2293 | if (setjmp(bus_error_jmp) == 0) { | 2287 | if (setjmp(bus_error_jmp) == 0) { |
2294 | catch_memory_errors = 1; | 2288 | catch_memory_errors = 1; |
2295 | sync(); | 2289 | sync(); |
2296 | *vp = kallsyms_lookup_name(tmpstr); | 2290 | *vp = kallsyms_lookup_name(tmpstr); |
2297 | sync(); | 2291 | sync(); |
2298 | } | 2292 | } |
2299 | catch_memory_errors = 0; | 2293 | catch_memory_errors = 0; |
2300 | if (!(*vp)) { | 2294 | if (!(*vp)) { |
2301 | printf("unknown symbol '%s'\n", tmpstr); | 2295 | printf("unknown symbol '%s'\n", tmpstr); |
2302 | return 0; | 2296 | return 0; |
2303 | } | 2297 | } |
2304 | return 1; | 2298 | return 1; |
2305 | } | 2299 | } |
2306 | 2300 | ||
2307 | d = hexdigit(c); | 2301 | d = hexdigit(c); |
2308 | if (d == EOF) { | 2302 | if (d == EOF) { |
2309 | termch = c; | 2303 | termch = c; |
2310 | return 0; | 2304 | return 0; |
2311 | } | 2305 | } |
2312 | v = 0; | 2306 | v = 0; |
2313 | do { | 2307 | do { |
2314 | v = (v << 4) + d; | 2308 | v = (v << 4) + d; |
2315 | c = inchar(); | 2309 | c = inchar(); |
2316 | d = hexdigit(c); | 2310 | d = hexdigit(c); |
2317 | } while (d != EOF); | 2311 | } while (d != EOF); |
2318 | termch = c; | 2312 | termch = c; |
2319 | *vp = v; | 2313 | *vp = v; |
2320 | return 1; | 2314 | return 1; |
2321 | } | 2315 | } |
2322 | 2316 | ||
2323 | void | 2317 | void |
2324 | scannl(void) | 2318 | scannl(void) |
2325 | { | 2319 | { |
2326 | int c; | 2320 | int c; |
2327 | 2321 | ||
2328 | c = termch; | 2322 | c = termch; |
2329 | termch = 0; | 2323 | termch = 0; |
2330 | while( c != '\n' ) | 2324 | while( c != '\n' ) |
2331 | c = inchar(); | 2325 | c = inchar(); |
2332 | } | 2326 | } |
2333 | 2327 | ||
2334 | int hexdigit(int c) | 2328 | int hexdigit(int c) |
2335 | { | 2329 | { |
2336 | if( '0' <= c && c <= '9' ) | 2330 | if( '0' <= c && c <= '9' ) |
2337 | return c - '0'; | 2331 | return c - '0'; |
2338 | if( 'A' <= c && c <= 'F' ) | 2332 | if( 'A' <= c && c <= 'F' ) |
2339 | return c - ('A' - 10); | 2333 | return c - ('A' - 10); |
2340 | if( 'a' <= c && c <= 'f' ) | 2334 | if( 'a' <= c && c <= 'f' ) |
2341 | return c - ('a' - 10); | 2335 | return c - ('a' - 10); |
2342 | return EOF; | 2336 | return EOF; |
2343 | } | 2337 | } |
2344 | 2338 | ||
2345 | void | 2339 | void |
2346 | getstring(char *s, int size) | 2340 | getstring(char *s, int size) |
2347 | { | 2341 | { |
2348 | int c; | 2342 | int c; |
2349 | 2343 | ||
2350 | c = skipbl(); | 2344 | c = skipbl(); |
2351 | do { | 2345 | do { |
2352 | if( size > 1 ){ | 2346 | if( size > 1 ){ |
2353 | *s++ = c; | 2347 | *s++ = c; |
2354 | --size; | 2348 | --size; |
2355 | } | 2349 | } |
2356 | c = inchar(); | 2350 | c = inchar(); |
2357 | } while( c != ' ' && c != '\t' && c != '\n' ); | 2351 | } while( c != ' ' && c != '\t' && c != '\n' ); |
2358 | termch = c; | 2352 | termch = c; |
2359 | *s = 0; | 2353 | *s = 0; |
2360 | } | 2354 | } |
2361 | 2355 | ||
2362 | static char line[256]; | 2356 | static char line[256]; |
2363 | static char *lineptr; | 2357 | static char *lineptr; |
2364 | 2358 | ||
2365 | void | 2359 | void |
2366 | flush_input(void) | 2360 | flush_input(void) |
2367 | { | 2361 | { |
2368 | lineptr = NULL; | 2362 | lineptr = NULL; |
2369 | } | 2363 | } |
2370 | 2364 | ||
2371 | int | 2365 | int |
2372 | inchar(void) | 2366 | inchar(void) |
2373 | { | 2367 | { |
2374 | if (lineptr == NULL || *lineptr == 0) { | 2368 | if (lineptr == NULL || *lineptr == 0) { |
2375 | if (fgets(line, sizeof(line), stdin) == NULL) { | 2369 | if (xmon_gets(line, sizeof(line)) == NULL) { |
2376 | lineptr = NULL; | 2370 | lineptr = NULL; |
2377 | return EOF; | 2371 | return EOF; |
2378 | } | 2372 | } |
2379 | lineptr = line; | 2373 | lineptr = line; |
2380 | } | 2374 | } |
2381 | return *lineptr++; | 2375 | return *lineptr++; |
2382 | } | 2376 | } |
2383 | 2377 | ||
2384 | void | 2378 | void |
2385 | take_input(char *str) | 2379 | take_input(char *str) |
2386 | { | 2380 | { |
2387 | lineptr = str; | 2381 | lineptr = str; |
2388 | } | 2382 | } |
2389 | 2383 | ||
2390 | 2384 | ||
2391 | static void | 2385 | static void |
2392 | symbol_lookup(void) | 2386 | symbol_lookup(void) |
2393 | { | 2387 | { |
2394 | int type = inchar(); | 2388 | int type = inchar(); |
2395 | unsigned long addr; | 2389 | unsigned long addr; |
2396 | static char tmp[64]; | 2390 | static char tmp[64]; |
2397 | 2391 | ||
2398 | switch (type) { | 2392 | switch (type) { |
2399 | case 'a': | 2393 | case 'a': |
2400 | if (scanhex(&addr)) | 2394 | if (scanhex(&addr)) |
2401 | xmon_print_symbol(addr, ": ", "\n"); | 2395 | xmon_print_symbol(addr, ": ", "\n"); |
2402 | termch = 0; | 2396 | termch = 0; |
2403 | break; | 2397 | break; |
2404 | case 's': | 2398 | case 's': |
2405 | getstring(tmp, 64); | 2399 | getstring(tmp, 64); |
2406 | if (setjmp(bus_error_jmp) == 0) { | 2400 | if (setjmp(bus_error_jmp) == 0) { |
2407 | catch_memory_errors = 1; | 2401 | catch_memory_errors = 1; |
2408 | sync(); | 2402 | sync(); |
2409 | addr = kallsyms_lookup_name(tmp); | 2403 | addr = kallsyms_lookup_name(tmp); |
2410 | if (addr) | 2404 | if (addr) |
2411 | printf("%s: %lx\n", tmp, addr); | 2405 | printf("%s: %lx\n", tmp, addr); |
2412 | else | 2406 | else |
2413 | printf("Symbol '%s' not found.\n", tmp); | 2407 | printf("Symbol '%s' not found.\n", tmp); |
2414 | sync(); | 2408 | sync(); |
2415 | } | 2409 | } |
2416 | catch_memory_errors = 0; | 2410 | catch_memory_errors = 0; |
2417 | termch = 0; | 2411 | termch = 0; |
2418 | break; | 2412 | break; |
2419 | } | 2413 | } |
2420 | } | 2414 | } |
2421 | 2415 | ||
2422 | 2416 | ||
2423 | /* Print an address in numeric and symbolic form (if possible) */ | 2417 | /* Print an address in numeric and symbolic form (if possible) */ |
2424 | static void xmon_print_symbol(unsigned long address, const char *mid, | 2418 | static void xmon_print_symbol(unsigned long address, const char *mid, |
2425 | const char *after) | 2419 | const char *after) |
2426 | { | 2420 | { |
2427 | char *modname; | 2421 | char *modname; |
2428 | const char *name = NULL; | 2422 | const char *name = NULL; |
2429 | unsigned long offset, size; | 2423 | unsigned long offset, size; |
2430 | 2424 | ||
2431 | printf(REG, address); | 2425 | printf(REG, address); |
2432 | if (setjmp(bus_error_jmp) == 0) { | 2426 | if (setjmp(bus_error_jmp) == 0) { |
2433 | catch_memory_errors = 1; | 2427 | catch_memory_errors = 1; |
2434 | sync(); | 2428 | sync(); |
2435 | name = kallsyms_lookup(address, &size, &offset, &modname, | 2429 | name = kallsyms_lookup(address, &size, &offset, &modname, |
2436 | tmpstr); | 2430 | tmpstr); |
2437 | sync(); | 2431 | sync(); |
2438 | /* wait a little while to see if we get a machine check */ | 2432 | /* wait a little while to see if we get a machine check */ |
2439 | __delay(200); | 2433 | __delay(200); |
2440 | } | 2434 | } |
2441 | 2435 | ||
2442 | catch_memory_errors = 0; | 2436 | catch_memory_errors = 0; |
2443 | 2437 | ||
2444 | if (name) { | 2438 | if (name) { |
2445 | printf("%s%s+%#lx/%#lx", mid, name, offset, size); | 2439 | printf("%s%s+%#lx/%#lx", mid, name, offset, size); |
2446 | if (modname) | 2440 | if (modname) |
2447 | printf(" [%s]", modname); | 2441 | printf(" [%s]", modname); |
2448 | } | 2442 | } |
2449 | printf("%s", after); | 2443 | printf("%s", after); |
2450 | } | 2444 | } |
2451 | 2445 | ||
2452 | #ifdef CONFIG_PPC64 | 2446 | #ifdef CONFIG_PPC64 |
2453 | static void dump_slb(void) | 2447 | static void dump_slb(void) |
2454 | { | 2448 | { |
2455 | int i; | 2449 | int i; |
2456 | unsigned long tmp; | 2450 | unsigned long tmp; |
2457 | 2451 | ||
2458 | printf("SLB contents of cpu %x\n", smp_processor_id()); | 2452 | printf("SLB contents of cpu %x\n", smp_processor_id()); |
2459 | 2453 | ||
2460 | for (i = 0; i < SLB_NUM_ENTRIES; i++) { | 2454 | for (i = 0; i < SLB_NUM_ENTRIES; i++) { |
2461 | asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i)); | 2455 | asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i)); |
2462 | printf("%02d %016lx ", i, tmp); | 2456 | printf("%02d %016lx ", i, tmp); |
2463 | 2457 | ||
2464 | asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i)); | 2458 | asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i)); |
2465 | printf("%016lx\n", tmp); | 2459 | printf("%016lx\n", tmp); |
2466 | } | 2460 | } |
2467 | } | 2461 | } |
2468 | 2462 | ||
2469 | static void dump_stab(void) | 2463 | static void dump_stab(void) |
2470 | { | 2464 | { |
2471 | int i; | 2465 | int i; |
2472 | unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; | 2466 | unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; |
2473 | 2467 | ||
2474 | printf("Segment table contents of cpu %x\n", smp_processor_id()); | 2468 | printf("Segment table contents of cpu %x\n", smp_processor_id()); |
2475 | 2469 | ||
2476 | for (i = 0; i < PAGE_SIZE/16; i++) { | 2470 | for (i = 0; i < PAGE_SIZE/16; i++) { |
2477 | unsigned long a, b; | 2471 | unsigned long a, b; |
2478 | 2472 | ||
2479 | a = *tmp++; | 2473 | a = *tmp++; |
2480 | b = *tmp++; | 2474 | b = *tmp++; |
2481 | 2475 | ||
2482 | if (a || b) { | 2476 | if (a || b) { |
2483 | printf("%03d %016lx ", i, a); | 2477 | printf("%03d %016lx ", i, a); |
2484 | printf("%016lx\n", b); | 2478 | printf("%016lx\n", b); |
2485 | } | 2479 | } |
2486 | } | 2480 | } |
2487 | } | 2481 | } |
2488 | 2482 | ||
2489 | void dump_segments(void) | 2483 | void dump_segments(void) |
2490 | { | 2484 | { |
2491 | if (cpu_has_feature(CPU_FTR_SLB)) | 2485 | if (cpu_has_feature(CPU_FTR_SLB)) |
2492 | dump_slb(); | 2486 | dump_slb(); |
2493 | else | 2487 | else |
2494 | dump_stab(); | 2488 | dump_stab(); |
2495 | } | 2489 | } |
2496 | #endif | 2490 | #endif |
2497 | 2491 | ||
2498 | #ifdef CONFIG_PPC_STD_MMU_32 | 2492 | #ifdef CONFIG_PPC_STD_MMU_32 |
2499 | void dump_segments(void) | 2493 | void dump_segments(void) |
2500 | { | 2494 | { |
2501 | int i; | 2495 | int i; |
2502 | 2496 | ||
2503 | printf("sr0-15 ="); | 2497 | printf("sr0-15 ="); |
2504 | for (i = 0; i < 16; ++i) | 2498 | for (i = 0; i < 16; ++i) |
2505 | printf(" %x", mfsrin(i)); | 2499 | printf(" %x", mfsrin(i)); |
2506 | printf("\n"); | 2500 | printf("\n"); |
2507 | } | 2501 | } |
2508 | #endif | 2502 | #endif |
2509 | 2503 | ||
2510 | void xmon_init(int enable) | 2504 | void xmon_init(int enable) |
2511 | { | 2505 | { |
2512 | if (enable) { | 2506 | if (enable) { |
2513 | __debugger = xmon; | 2507 | __debugger = xmon; |
2514 | __debugger_ipi = xmon_ipi; | 2508 | __debugger_ipi = xmon_ipi; |
2515 | __debugger_bpt = xmon_bpt; | 2509 | __debugger_bpt = xmon_bpt; |
2516 | __debugger_sstep = xmon_sstep; | 2510 | __debugger_sstep = xmon_sstep; |
2517 | __debugger_iabr_match = xmon_iabr_match; | 2511 | __debugger_iabr_match = xmon_iabr_match; |
2518 | __debugger_dabr_match = xmon_dabr_match; | 2512 | __debugger_dabr_match = xmon_dabr_match; |
2519 | __debugger_fault_handler = xmon_fault_handler; | 2513 | __debugger_fault_handler = xmon_fault_handler; |
2520 | } else { | 2514 | } else { |
2521 | __debugger = NULL; | 2515 | __debugger = NULL; |
2522 | __debugger_ipi = NULL; | 2516 | __debugger_ipi = NULL; |
2523 | __debugger_bpt = NULL; | 2517 | __debugger_bpt = NULL; |
2524 | __debugger_sstep = NULL; | 2518 | __debugger_sstep = NULL; |
2525 | __debugger_iabr_match = NULL; | 2519 | __debugger_iabr_match = NULL; |
2526 | __debugger_dabr_match = NULL; | 2520 | __debugger_dabr_match = NULL; |
2527 | __debugger_fault_handler = NULL; | 2521 | __debugger_fault_handler = NULL; |
2528 | } | 2522 | } |
2523 | xmon_map_scc(); | ||
2529 | } | 2524 | } |
2525 | |||
2526 | #ifdef CONFIG_MAGIC_SYSRQ | ||
2527 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, | ||
2528 | struct tty_struct *tty) | ||
2529 | { | ||
2530 | /* ensure xmon is enabled */ | ||
2531 | xmon_init(1); | ||
2532 | debugger(pt_regs); | ||
2533 | } | ||
2534 | |||
2535 | static struct sysrq_key_op sysrq_xmon_op = | ||
2536 | { | ||
2537 | .handler = sysrq_handle_xmon, | ||
2538 | .help_msg = "Xmon", | ||
2539 | .action_msg = "Entering xmon", | ||
2540 | }; | ||
2541 | |||
2542 | static int __init setup_xmon_sysrq(void) |
include/asm-powerpc/xmon.h
1 | #ifndef __PPC_XMON_H | 1 | #ifndef __PPC_XMON_H |
2 | #define __PPC_XMON_H | 2 | #define __PPC_XMON_H |
3 | #ifdef __KERNEL__ | 3 | #ifdef __KERNEL__ |
4 | 4 | ||
5 | struct pt_regs; | 5 | struct pt_regs; |
6 | 6 | ||
7 | extern int xmon(struct pt_regs *excp); | 7 | extern int xmon(struct pt_regs *excp); |
8 | extern void xmon_printf(const char *fmt, ...); | 8 | extern void xmon_printf(const char *fmt, ...); |
9 | extern void xmon_init(int); | 9 | extern void xmon_init(int); |
10 | extern void xmon_map_scc(void); | ||
11 | 10 | ||
12 | #endif | 11 | #endif |
13 | #endif | 12 | #endif |
14 | 13 |