Commit b13cfd173f73c3f6f9a307b7b6e64d45fbd756b2
Committed by
Paul Mackerras
1 parent
bef5686229
Exists in
master
and in
4 other branches
[PATCH] ppc64: allow xmon=off
If both CONFIG_XMON and CONFIG_XMON_DEFAULT is enabled in the .config, there is no way to disable xmon again. setup_system calls first xmon_init, later parse_early_param. So a new 'xmon=off' cmdline option will do the right thing. Signed-off-by: Olaf Hering <olh@suse.de> Signed-off-by: Paul Mackerras <paulus@samba.org>
Showing 4 changed files with 26 additions and 14 deletions Inline Diff
arch/ppc64/kernel/setup.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/version.h> | 28 | #include <linux/version.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/bootinfo.h> | 40 | #include <asm/bootinfo.h> |
| 41 | #include <asm/smp.h> | 41 | #include <asm/smp.h> |
| 42 | #include <asm/elf.h> | 42 | #include <asm/elf.h> |
| 43 | #include <asm/machdep.h> | 43 | #include <asm/machdep.h> |
| 44 | #include <asm/paca.h> | 44 | #include <asm/paca.h> |
| 45 | #include <asm/ppcdebug.h> | 45 | #include <asm/ppcdebug.h> |
| 46 | #include <asm/time.h> | 46 | #include <asm/time.h> |
| 47 | #include <asm/cputable.h> | 47 | #include <asm/cputable.h> |
| 48 | #include <asm/sections.h> | 48 | #include <asm/sections.h> |
| 49 | #include <asm/btext.h> | 49 | #include <asm/btext.h> |
| 50 | #include <asm/nvram.h> | 50 | #include <asm/nvram.h> |
| 51 | #include <asm/setup.h> | 51 | #include <asm/setup.h> |
| 52 | #include <asm/system.h> | 52 | #include <asm/system.h> |
| 53 | #include <asm/rtas.h> | 53 | #include <asm/rtas.h> |
| 54 | #include <asm/iommu.h> | 54 | #include <asm/iommu.h> |
| 55 | #include <asm/serial.h> | 55 | #include <asm/serial.h> |
| 56 | #include <asm/cache.h> | 56 | #include <asm/cache.h> |
| 57 | #include <asm/page.h> | 57 | #include <asm/page.h> |
| 58 | #include <asm/mmu.h> | 58 | #include <asm/mmu.h> |
| 59 | #include <asm/lmb.h> | 59 | #include <asm/lmb.h> |
| 60 | #include <asm/iSeries/ItLpNaca.h> | 60 | #include <asm/iSeries/ItLpNaca.h> |
| 61 | 61 | ||
| 62 | #ifdef DEBUG | 62 | #ifdef DEBUG |
| 63 | #define DBG(fmt...) udbg_printf(fmt) | 63 | #define DBG(fmt...) udbg_printf(fmt) |
| 64 | #else | 64 | #else |
| 65 | #define DBG(fmt...) | 65 | #define DBG(fmt...) |
| 66 | #endif | 66 | #endif |
| 67 | 67 | ||
| 68 | /* | 68 | /* |
| 69 | * Here are some early debugging facilities. You can enable one | 69 | * Here are some early debugging facilities. You can enable one |
| 70 | * but your kernel will not boot on anything else if you do so | 70 | * but your kernel will not boot on anything else if you do so |
| 71 | */ | 71 | */ |
| 72 | 72 | ||
| 73 | /* This one is for use on LPAR machines that support an HVC console | 73 | /* This one is for use on LPAR machines that support an HVC console |
| 74 | * on vterm 0 | 74 | * on vterm 0 |
| 75 | */ | 75 | */ |
| 76 | extern void udbg_init_debug_lpar(void); | 76 | extern void udbg_init_debug_lpar(void); |
| 77 | /* This one is for use on Apple G5 machines | 77 | /* This one is for use on Apple G5 machines |
| 78 | */ | 78 | */ |
| 79 | extern void udbg_init_pmac_realmode(void); | 79 | extern void udbg_init_pmac_realmode(void); |
| 80 | /* That's RTAS panel debug */ | 80 | /* That's RTAS panel debug */ |
| 81 | extern void call_rtas_display_status_delay(unsigned char c); | 81 | extern void call_rtas_display_status_delay(unsigned char c); |
| 82 | /* Here's maple real mode debug */ | 82 | /* Here's maple real mode debug */ |
| 83 | extern void udbg_init_maple_realmode(void); | 83 | extern void udbg_init_maple_realmode(void); |
| 84 | 84 | ||
| 85 | #define EARLY_DEBUG_INIT() do {} while(0) | 85 | #define EARLY_DEBUG_INIT() do {} while(0) |
| 86 | 86 | ||
| 87 | #if 0 | 87 | #if 0 |
| 88 | #define EARLY_DEBUG_INIT() udbg_init_debug_lpar() | 88 | #define EARLY_DEBUG_INIT() udbg_init_debug_lpar() |
| 89 | #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() | 89 | #define EARLY_DEBUG_INIT() udbg_init_maple_realmode() |
| 90 | #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() | 90 | #define EARLY_DEBUG_INIT() udbg_init_pmac_realmode() |
| 91 | #define EARLY_DEBUG_INIT() \ | 91 | #define EARLY_DEBUG_INIT() \ |
| 92 | do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0) | 92 | do { ppc_md.udbg_putc = call_rtas_display_status_delay; } while(0) |
| 93 | #endif | 93 | #endif |
| 94 | 94 | ||
| 95 | /* extern void *stab; */ | 95 | /* extern void *stab; */ |
| 96 | extern unsigned long klimit; | 96 | extern unsigned long klimit; |
| 97 | 97 | ||
| 98 | extern void mm_init_ppc64(void); | 98 | extern void mm_init_ppc64(void); |
| 99 | extern void stab_initialize(unsigned long stab); | 99 | extern void stab_initialize(unsigned long stab); |
| 100 | extern void htab_initialize(void); | 100 | extern void htab_initialize(void); |
| 101 | extern void early_init_devtree(void *flat_dt); | 101 | extern void early_init_devtree(void *flat_dt); |
| 102 | extern void unflatten_device_tree(void); | 102 | extern void unflatten_device_tree(void); |
| 103 | 103 | ||
| 104 | extern void smp_release_cpus(void); | 104 | extern void smp_release_cpus(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 | u64 ppc64_debug_switch; | 111 | u64 ppc64_debug_switch; |
| 112 | 112 | ||
| 113 | struct ppc64_caches ppc64_caches; | 113 | struct ppc64_caches ppc64_caches; |
| 114 | EXPORT_SYMBOL_GPL(ppc64_caches); | 114 | EXPORT_SYMBOL_GPL(ppc64_caches); |
| 115 | 115 | ||
| 116 | /* | 116 | /* |
| 117 | * These are used in binfmt_elf.c to put aux entries on the stack | 117 | * These are used in binfmt_elf.c to put aux entries on the stack |
| 118 | * for each elf executable being started. | 118 | * for each elf executable being started. |
| 119 | */ | 119 | */ |
| 120 | int dcache_bsize; | 120 | int dcache_bsize; |
| 121 | int icache_bsize; | 121 | int icache_bsize; |
| 122 | int ucache_bsize; | 122 | int ucache_bsize; |
| 123 | 123 | ||
| 124 | /* The main machine-dep calls structure | 124 | /* The main machine-dep calls structure |
| 125 | */ | 125 | */ |
| 126 | struct machdep_calls ppc_md; | 126 | struct machdep_calls ppc_md; |
| 127 | EXPORT_SYMBOL(ppc_md); | 127 | EXPORT_SYMBOL(ppc_md); |
| 128 | 128 | ||
| 129 | #ifdef CONFIG_MAGIC_SYSRQ | 129 | #ifdef CONFIG_MAGIC_SYSRQ |
| 130 | unsigned long SYSRQ_KEY; | 130 | unsigned long SYSRQ_KEY; |
| 131 | #endif /* CONFIG_MAGIC_SYSRQ */ | 131 | #endif /* CONFIG_MAGIC_SYSRQ */ |
| 132 | 132 | ||
| 133 | 133 | ||
| 134 | static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); | 134 | static int ppc64_panic_event(struct notifier_block *, unsigned long, void *); |
| 135 | static struct notifier_block ppc64_panic_block = { | 135 | static struct notifier_block ppc64_panic_block = { |
| 136 | .notifier_call = ppc64_panic_event, | 136 | .notifier_call = ppc64_panic_event, |
| 137 | .priority = INT_MIN /* may not return; must be done last */ | 137 | .priority = INT_MIN /* may not return; must be done last */ |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | /* | 140 | /* |
| 141 | * Perhaps we can put the pmac screen_info[] here | 141 | * Perhaps we can put the pmac screen_info[] here |
| 142 | * on pmac as well so we don't need the ifdef's. | 142 | * on pmac as well so we don't need the ifdef's. |
| 143 | * Until we get multiple-console support in here | 143 | * Until we get multiple-console support in here |
| 144 | * that is. -- Cort | 144 | * that is. -- Cort |
| 145 | * Maybe tie it to serial consoles, since this is really what | 145 | * Maybe tie it to serial consoles, since this is really what |
| 146 | * these processors use on existing boards. -- Dan | 146 | * these processors use on existing boards. -- Dan |
| 147 | */ | 147 | */ |
| 148 | struct screen_info screen_info = { | 148 | struct screen_info screen_info = { |
| 149 | .orig_x = 0, | 149 | .orig_x = 0, |
| 150 | .orig_y = 25, | 150 | .orig_y = 25, |
| 151 | .orig_video_cols = 80, | 151 | .orig_video_cols = 80, |
| 152 | .orig_video_lines = 25, | 152 | .orig_video_lines = 25, |
| 153 | .orig_video_isVGA = 1, | 153 | .orig_video_isVGA = 1, |
| 154 | .orig_video_points = 16 | 154 | .orig_video_points = 16 |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| 157 | /* | 157 | /* |
| 158 | * Initialize the PPCDBG state. Called before relocation has been enabled. | 158 | * Initialize the PPCDBG state. Called before relocation has been enabled. |
| 159 | */ | 159 | */ |
| 160 | void __init ppcdbg_initialize(void) | 160 | void __init ppcdbg_initialize(void) |
| 161 | { | 161 | { |
| 162 | ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ | 162 | ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */ |
| 163 | /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; | 163 | /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | /* | 166 | /* |
| 167 | * Early boot console based on udbg | 167 | * Early boot console based on udbg |
| 168 | */ | 168 | */ |
| 169 | static struct console udbg_console = { | 169 | static struct console udbg_console = { |
| 170 | .name = "udbg", | 170 | .name = "udbg", |
| 171 | .write = udbg_console_write, | 171 | .write = udbg_console_write, |
| 172 | .flags = CON_PRINTBUFFER, | 172 | .flags = CON_PRINTBUFFER, |
| 173 | .index = -1, | 173 | .index = -1, |
| 174 | }; | 174 | }; |
| 175 | static int early_console_initialized; | 175 | static int early_console_initialized; |
| 176 | 176 | ||
| 177 | void __init disable_early_printk(void) | 177 | void __init disable_early_printk(void) |
| 178 | { | 178 | { |
| 179 | if (!early_console_initialized) | 179 | if (!early_console_initialized) |
| 180 | return; | 180 | return; |
| 181 | unregister_console(&udbg_console); | 181 | unregister_console(&udbg_console); |
| 182 | early_console_initialized = 0; | 182 | early_console_initialized = 0; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) | 185 | #if defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) |
| 186 | 186 | ||
| 187 | static int smt_enabled_cmdline; | 187 | static int smt_enabled_cmdline; |
| 188 | 188 | ||
| 189 | /* Look for ibm,smt-enabled OF option */ | 189 | /* Look for ibm,smt-enabled OF option */ |
| 190 | static void check_smt_enabled(void) | 190 | static void check_smt_enabled(void) |
| 191 | { | 191 | { |
| 192 | struct device_node *dn; | 192 | struct device_node *dn; |
| 193 | char *smt_option; | 193 | char *smt_option; |
| 194 | 194 | ||
| 195 | /* Allow the command line to overrule the OF option */ | 195 | /* Allow the command line to overrule the OF option */ |
| 196 | if (smt_enabled_cmdline) | 196 | if (smt_enabled_cmdline) |
| 197 | return; | 197 | return; |
| 198 | 198 | ||
| 199 | dn = of_find_node_by_path("/options"); | 199 | dn = of_find_node_by_path("/options"); |
| 200 | 200 | ||
| 201 | if (dn) { | 201 | if (dn) { |
| 202 | smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); | 202 | smt_option = (char *)get_property(dn, "ibm,smt-enabled", NULL); |
| 203 | 203 | ||
| 204 | if (smt_option) { | 204 | if (smt_option) { |
| 205 | if (!strcmp(smt_option, "on")) | 205 | if (!strcmp(smt_option, "on")) |
| 206 | smt_enabled_at_boot = 1; | 206 | smt_enabled_at_boot = 1; |
| 207 | else if (!strcmp(smt_option, "off")) | 207 | else if (!strcmp(smt_option, "off")) |
| 208 | smt_enabled_at_boot = 0; | 208 | smt_enabled_at_boot = 0; |
| 209 | } | 209 | } |
| 210 | } | 210 | } |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | /* Look for smt-enabled= cmdline option */ | 213 | /* Look for smt-enabled= cmdline option */ |
| 214 | static int __init early_smt_enabled(char *p) | 214 | static int __init early_smt_enabled(char *p) |
| 215 | { | 215 | { |
| 216 | smt_enabled_cmdline = 1; | 216 | smt_enabled_cmdline = 1; |
| 217 | 217 | ||
| 218 | if (!p) | 218 | if (!p) |
| 219 | return 0; | 219 | return 0; |
| 220 | 220 | ||
| 221 | if (!strcmp(p, "on") || !strcmp(p, "1")) | 221 | if (!strcmp(p, "on") || !strcmp(p, "1")) |
| 222 | smt_enabled_at_boot = 1; | 222 | smt_enabled_at_boot = 1; |
| 223 | else if (!strcmp(p, "off") || !strcmp(p, "0")) | 223 | else if (!strcmp(p, "off") || !strcmp(p, "0")) |
| 224 | smt_enabled_at_boot = 0; | 224 | smt_enabled_at_boot = 0; |
| 225 | 225 | ||
| 226 | return 0; | 226 | return 0; |
| 227 | } | 227 | } |
| 228 | early_param("smt-enabled", early_smt_enabled); | 228 | early_param("smt-enabled", early_smt_enabled); |
| 229 | 229 | ||
| 230 | /** | 230 | /** |
| 231 | * setup_cpu_maps - initialize the following cpu maps: | 231 | * setup_cpu_maps - initialize the following cpu maps: |
| 232 | * cpu_possible_map | 232 | * cpu_possible_map |
| 233 | * cpu_present_map | 233 | * cpu_present_map |
| 234 | * cpu_sibling_map | 234 | * cpu_sibling_map |
| 235 | * | 235 | * |
| 236 | * Having the possible map set up early allows us to restrict allocations | 236 | * Having the possible map set up early allows us to restrict allocations |
| 237 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. | 237 | * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. |
| 238 | * | 238 | * |
| 239 | * We do not initialize the online map here; cpus set their own bits in | 239 | * We do not initialize the online map here; cpus set their own bits in |
| 240 | * cpu_online_map as they come up. | 240 | * cpu_online_map as they come up. |
| 241 | * | 241 | * |
| 242 | * This function is valid only for Open Firmware systems. finish_device_tree | 242 | * This function is valid only for Open Firmware systems. finish_device_tree |
| 243 | * must be called before using this. | 243 | * must be called before using this. |
| 244 | * | 244 | * |
| 245 | * While we're here, we may as well set the "physical" cpu ids in the paca. | 245 | * While we're here, we may as well set the "physical" cpu ids in the paca. |
| 246 | */ | 246 | */ |
| 247 | static void __init setup_cpu_maps(void) | 247 | static void __init setup_cpu_maps(void) |
| 248 | { | 248 | { |
| 249 | struct device_node *dn = NULL; | 249 | struct device_node *dn = NULL; |
| 250 | int cpu = 0; | 250 | int cpu = 0; |
| 251 | int swap_cpuid = 0; | 251 | int swap_cpuid = 0; |
| 252 | 252 | ||
| 253 | check_smt_enabled(); | 253 | check_smt_enabled(); |
| 254 | 254 | ||
| 255 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { | 255 | while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { |
| 256 | u32 *intserv; | 256 | u32 *intserv; |
| 257 | int j, len = sizeof(u32), nthreads; | 257 | int j, len = sizeof(u32), nthreads; |
| 258 | 258 | ||
| 259 | intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", | 259 | intserv = (u32 *)get_property(dn, "ibm,ppc-interrupt-server#s", |
| 260 | &len); | 260 | &len); |
| 261 | if (!intserv) | 261 | if (!intserv) |
| 262 | intserv = (u32 *)get_property(dn, "reg", NULL); | 262 | intserv = (u32 *)get_property(dn, "reg", NULL); |
| 263 | 263 | ||
| 264 | nthreads = len / sizeof(u32); | 264 | nthreads = len / sizeof(u32); |
| 265 | 265 | ||
| 266 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { | 266 | for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { |
| 267 | cpu_set(cpu, cpu_present_map); | 267 | cpu_set(cpu, cpu_present_map); |
| 268 | set_hard_smp_processor_id(cpu, intserv[j]); | 268 | set_hard_smp_processor_id(cpu, intserv[j]); |
| 269 | 269 | ||
| 270 | if (intserv[j] == boot_cpuid_phys) | 270 | if (intserv[j] == boot_cpuid_phys) |
| 271 | swap_cpuid = cpu; | 271 | swap_cpuid = cpu; |
| 272 | cpu_set(cpu, cpu_possible_map); | 272 | cpu_set(cpu, cpu_possible_map); |
| 273 | cpu++; | 273 | cpu++; |
| 274 | } | 274 | } |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that | 277 | /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that |
| 278 | * boot cpu is logical 0. | 278 | * boot cpu is logical 0. |
| 279 | */ | 279 | */ |
| 280 | if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { | 280 | if (boot_cpuid_phys != get_hard_smp_processor_id(0)) { |
| 281 | u32 tmp; | 281 | u32 tmp; |
| 282 | tmp = get_hard_smp_processor_id(0); | 282 | tmp = get_hard_smp_processor_id(0); |
| 283 | set_hard_smp_processor_id(0, boot_cpuid_phys); | 283 | set_hard_smp_processor_id(0, boot_cpuid_phys); |
| 284 | set_hard_smp_processor_id(swap_cpuid, tmp); | 284 | set_hard_smp_processor_id(swap_cpuid, tmp); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | /* | 287 | /* |
| 288 | * On pSeries LPAR, we need to know how many cpus | 288 | * On pSeries LPAR, we need to know how many cpus |
| 289 | * could possibly be added to this partition. | 289 | * could possibly be added to this partition. |
| 290 | */ | 290 | */ |
| 291 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && | 291 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR && |
| 292 | (dn = of_find_node_by_path("/rtas"))) { | 292 | (dn = of_find_node_by_path("/rtas"))) { |
| 293 | int num_addr_cell, num_size_cell, maxcpus; | 293 | int num_addr_cell, num_size_cell, maxcpus; |
| 294 | unsigned int *ireg; | 294 | unsigned int *ireg; |
| 295 | 295 | ||
| 296 | num_addr_cell = prom_n_addr_cells(dn); | 296 | num_addr_cell = prom_n_addr_cells(dn); |
| 297 | num_size_cell = prom_n_size_cells(dn); | 297 | num_size_cell = prom_n_size_cells(dn); |
| 298 | 298 | ||
| 299 | ireg = (unsigned int *) | 299 | ireg = (unsigned int *) |
| 300 | get_property(dn, "ibm,lrdr-capacity", NULL); | 300 | get_property(dn, "ibm,lrdr-capacity", NULL); |
| 301 | 301 | ||
| 302 | if (!ireg) | 302 | if (!ireg) |
| 303 | goto out; | 303 | goto out; |
| 304 | 304 | ||
| 305 | maxcpus = ireg[num_addr_cell + num_size_cell]; | 305 | maxcpus = ireg[num_addr_cell + num_size_cell]; |
| 306 | 306 | ||
| 307 | /* Double maxcpus for processors which have SMT capability */ | 307 | /* Double maxcpus for processors which have SMT capability */ |
| 308 | if (cpu_has_feature(CPU_FTR_SMT)) | 308 | if (cpu_has_feature(CPU_FTR_SMT)) |
| 309 | maxcpus *= 2; | 309 | maxcpus *= 2; |
| 310 | 310 | ||
| 311 | if (maxcpus > NR_CPUS) { | 311 | if (maxcpus > NR_CPUS) { |
| 312 | printk(KERN_WARNING | 312 | printk(KERN_WARNING |
| 313 | "Partition configured for %d cpus, " | 313 | "Partition configured for %d cpus, " |
| 314 | "operating system maximum is %d.\n", | 314 | "operating system maximum is %d.\n", |
| 315 | maxcpus, NR_CPUS); | 315 | maxcpus, NR_CPUS); |
| 316 | maxcpus = NR_CPUS; | 316 | maxcpus = NR_CPUS; |
| 317 | } else | 317 | } else |
| 318 | printk(KERN_INFO "Partition configured for %d cpus.\n", | 318 | printk(KERN_INFO "Partition configured for %d cpus.\n", |
| 319 | maxcpus); | 319 | maxcpus); |
| 320 | 320 | ||
| 321 | for (cpu = 0; cpu < maxcpus; cpu++) | 321 | for (cpu = 0; cpu < maxcpus; cpu++) |
| 322 | cpu_set(cpu, cpu_possible_map); | 322 | cpu_set(cpu, cpu_possible_map); |
| 323 | out: | 323 | out: |
| 324 | of_node_put(dn); | 324 | of_node_put(dn); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | /* | 327 | /* |
| 328 | * Do the sibling map; assume only two threads per processor. | 328 | * Do the sibling map; assume only two threads per processor. |
| 329 | */ | 329 | */ |
| 330 | for_each_cpu(cpu) { | 330 | for_each_cpu(cpu) { |
| 331 | cpu_set(cpu, cpu_sibling_map[cpu]); | 331 | cpu_set(cpu, cpu_sibling_map[cpu]); |
| 332 | if (cpu_has_feature(CPU_FTR_SMT)) | 332 | if (cpu_has_feature(CPU_FTR_SMT)) |
| 333 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); | 333 | cpu_set(cpu ^ 0x1, cpu_sibling_map[cpu]); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | systemcfg->processorCount = num_present_cpus(); | 336 | systemcfg->processorCount = num_present_cpus(); |
| 337 | } | 337 | } |
| 338 | #endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ | 338 | #endif /* defined(CONFIG_PPC_MULTIPLATFORM) && defined(CONFIG_SMP) */ |
| 339 | 339 | ||
| 340 | 340 | ||
| 341 | #ifdef CONFIG_PPC_MULTIPLATFORM | 341 | #ifdef CONFIG_PPC_MULTIPLATFORM |
| 342 | 342 | ||
| 343 | extern struct machdep_calls pSeries_md; | 343 | extern struct machdep_calls pSeries_md; |
| 344 | extern struct machdep_calls pmac_md; | 344 | extern struct machdep_calls pmac_md; |
| 345 | extern struct machdep_calls maple_md; | 345 | extern struct machdep_calls maple_md; |
| 346 | extern struct machdep_calls bpa_md; | 346 | extern struct machdep_calls bpa_md; |
| 347 | 347 | ||
| 348 | /* Ultimately, stuff them in an elf section like initcalls... */ | 348 | /* Ultimately, stuff them in an elf section like initcalls... */ |
| 349 | static struct machdep_calls __initdata *machines[] = { | 349 | static struct machdep_calls __initdata *machines[] = { |
| 350 | #ifdef CONFIG_PPC_PSERIES | 350 | #ifdef CONFIG_PPC_PSERIES |
| 351 | &pSeries_md, | 351 | &pSeries_md, |
| 352 | #endif /* CONFIG_PPC_PSERIES */ | 352 | #endif /* CONFIG_PPC_PSERIES */ |
| 353 | #ifdef CONFIG_PPC_PMAC | 353 | #ifdef CONFIG_PPC_PMAC |
| 354 | &pmac_md, | 354 | &pmac_md, |
| 355 | #endif /* CONFIG_PPC_PMAC */ | 355 | #endif /* CONFIG_PPC_PMAC */ |
| 356 | #ifdef CONFIG_PPC_MAPLE | 356 | #ifdef CONFIG_PPC_MAPLE |
| 357 | &maple_md, | 357 | &maple_md, |
| 358 | #endif /* CONFIG_PPC_MAPLE */ | 358 | #endif /* CONFIG_PPC_MAPLE */ |
| 359 | #ifdef CONFIG_PPC_BPA | 359 | #ifdef CONFIG_PPC_BPA |
| 360 | &bpa_md, | 360 | &bpa_md, |
| 361 | #endif | 361 | #endif |
| 362 | NULL | 362 | NULL |
| 363 | }; | 363 | }; |
| 364 | 364 | ||
| 365 | /* | 365 | /* |
| 366 | * Early initialization entry point. This is called by head.S | 366 | * Early initialization entry point. This is called by head.S |
| 367 | * with MMU translation disabled. We rely on the "feature" of | 367 | * with MMU translation disabled. We rely on the "feature" of |
| 368 | * the CPU that ignores the top 2 bits of the address in real | 368 | * the CPU that ignores the top 2 bits of the address in real |
| 369 | * mode so we can access kernel globals normally provided we | 369 | * mode so we can access kernel globals normally provided we |
| 370 | * only toy with things in the RMO region. From here, we do | 370 | * only toy with things in the RMO region. From here, we do |
| 371 | * some early parsing of the device-tree to setup out LMB | 371 | * some early parsing of the device-tree to setup out LMB |
| 372 | * data structures, and allocate & initialize the hash table | 372 | * data structures, and allocate & initialize the hash table |
| 373 | * and segment tables so we can start running with translation | 373 | * and segment tables so we can start running with translation |
| 374 | * enabled. | 374 | * enabled. |
| 375 | * | 375 | * |
| 376 | * It is this function which will call the probe() callback of | 376 | * It is this function which will call the probe() callback of |
| 377 | * the various platform types and copy the matching one to the | 377 | * the various platform types and copy the matching one to the |
| 378 | * global ppc_md structure. Your platform can eventually do | 378 | * global ppc_md structure. Your platform can eventually do |
| 379 | * some very early initializations from the probe() routine, but | 379 | * some very early initializations from the probe() routine, but |
| 380 | * this is not recommended, be very careful as, for example, the | 380 | * this is not recommended, be very careful as, for example, the |
| 381 | * device-tree is not accessible via normal means at this point. | 381 | * device-tree is not accessible via normal means at this point. |
| 382 | */ | 382 | */ |
| 383 | 383 | ||
| 384 | void __init early_setup(unsigned long dt_ptr) | 384 | void __init early_setup(unsigned long dt_ptr) |
| 385 | { | 385 | { |
| 386 | struct paca_struct *lpaca = get_paca(); | 386 | struct paca_struct *lpaca = get_paca(); |
| 387 | static struct machdep_calls **mach; | 387 | static struct machdep_calls **mach; |
| 388 | 388 | ||
| 389 | /* | 389 | /* |
| 390 | * Enable early debugging if any specified (see top of | 390 | * Enable early debugging if any specified (see top of |
| 391 | * this file) | 391 | * this file) |
| 392 | */ | 392 | */ |
| 393 | EARLY_DEBUG_INIT(); | 393 | EARLY_DEBUG_INIT(); |
| 394 | 394 | ||
| 395 | DBG(" -> early_setup()\n"); | 395 | DBG(" -> early_setup()\n"); |
| 396 | 396 | ||
| 397 | /* | 397 | /* |
| 398 | * Fill the default DBG level (do we want to keep | 398 | * Fill the default DBG level (do we want to keep |
| 399 | * that old mecanism around forever ?) | 399 | * that old mecanism around forever ?) |
| 400 | */ | 400 | */ |
| 401 | ppcdbg_initialize(); | 401 | ppcdbg_initialize(); |
| 402 | 402 | ||
| 403 | /* | 403 | /* |
| 404 | * Do early initializations using the flattened device | 404 | * Do early initializations using the flattened device |
| 405 | * tree, like retreiving the physical memory map or | 405 | * tree, like retreiving the physical memory map or |
| 406 | * calculating/retreiving the hash table size | 406 | * calculating/retreiving the hash table size |
| 407 | */ | 407 | */ |
| 408 | early_init_devtree(__va(dt_ptr)); | 408 | early_init_devtree(__va(dt_ptr)); |
| 409 | 409 | ||
| 410 | /* | 410 | /* |
| 411 | * Iterate all ppc_md structures until we find the proper | 411 | * Iterate all ppc_md structures until we find the proper |
| 412 | * one for the current machine type | 412 | * one for the current machine type |
| 413 | */ | 413 | */ |
| 414 | DBG("Probing machine type for platform %x...\n", | 414 | DBG("Probing machine type for platform %x...\n", |
| 415 | systemcfg->platform); | 415 | systemcfg->platform); |
| 416 | 416 | ||
| 417 | for (mach = machines; *mach; mach++) { | 417 | for (mach = machines; *mach; mach++) { |
| 418 | if ((*mach)->probe(systemcfg->platform)) | 418 | if ((*mach)->probe(systemcfg->platform)) |
| 419 | break; | 419 | break; |
| 420 | } | 420 | } |
| 421 | /* What can we do if we didn't find ? */ | 421 | /* What can we do if we didn't find ? */ |
| 422 | if (*mach == NULL) { | 422 | if (*mach == NULL) { |
| 423 | DBG("No suitable machine found !\n"); | 423 | DBG("No suitable machine found !\n"); |
| 424 | for (;;); | 424 | for (;;); |
| 425 | } | 425 | } |
| 426 | ppc_md = **mach; | 426 | ppc_md = **mach; |
| 427 | 427 | ||
| 428 | /* our udbg callbacks got overriden by the above, let's put them | 428 | /* our udbg callbacks got overriden by the above, let's put them |
| 429 | * back in. Ultimately, I want those things to be split from the | 429 | * back in. Ultimately, I want those things to be split from the |
| 430 | * main ppc_md | 430 | * main ppc_md |
| 431 | */ | 431 | */ |
| 432 | EARLY_DEBUG_INIT(); | 432 | EARLY_DEBUG_INIT(); |
| 433 | 433 | ||
| 434 | DBG("Found, Initializing memory management...\n"); | 434 | DBG("Found, Initializing memory management...\n"); |
| 435 | 435 | ||
| 436 | /* | 436 | /* |
| 437 | * Initialize stab / SLB management | 437 | * Initialize stab / SLB management |
| 438 | */ | 438 | */ |
| 439 | stab_initialize(lpaca->stab_real); | 439 | stab_initialize(lpaca->stab_real); |
| 440 | 440 | ||
| 441 | /* | 441 | /* |
| 442 | * Initialize the MMU Hash table and create the linear mapping | 442 | * Initialize the MMU Hash table and create the linear mapping |
| 443 | * of memory | 443 | * of memory |
| 444 | */ | 444 | */ |
| 445 | htab_initialize(); | 445 | htab_initialize(); |
| 446 | 446 | ||
| 447 | DBG(" <- early_setup()\n"); | 447 | DBG(" <- early_setup()\n"); |
| 448 | } | 448 | } |
| 449 | 449 | ||
| 450 | 450 | ||
| 451 | /* | 451 | /* |
| 452 | * Initialize some remaining members of the ppc64_caches and systemcfg structures | 452 | * Initialize some remaining members of the ppc64_caches and systemcfg structures |
| 453 | * (at least until we get rid of them completely). This is mostly some | 453 | * (at least until we get rid of them completely). This is mostly some |
| 454 | * cache informations about the CPU that will be used by cache flush | 454 | * cache informations about the CPU that will be used by cache flush |
| 455 | * routines and/or provided to userland | 455 | * routines and/or provided to userland |
| 456 | */ | 456 | */ |
| 457 | static void __init initialize_cache_info(void) | 457 | static void __init initialize_cache_info(void) |
| 458 | { | 458 | { |
| 459 | struct device_node *np; | 459 | struct device_node *np; |
| 460 | unsigned long num_cpus = 0; | 460 | unsigned long num_cpus = 0; |
| 461 | 461 | ||
| 462 | DBG(" -> initialize_cache_info()\n"); | 462 | DBG(" -> initialize_cache_info()\n"); |
| 463 | 463 | ||
| 464 | for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { | 464 | for (np = NULL; (np = of_find_node_by_type(np, "cpu"));) { |
| 465 | num_cpus += 1; | 465 | num_cpus += 1; |
| 466 | 466 | ||
| 467 | /* We're assuming *all* of the CPUs have the same | 467 | /* We're assuming *all* of the CPUs have the same |
| 468 | * d-cache and i-cache sizes... -Peter | 468 | * d-cache and i-cache sizes... -Peter |
| 469 | */ | 469 | */ |
| 470 | 470 | ||
| 471 | if ( num_cpus == 1 ) { | 471 | if ( num_cpus == 1 ) { |
| 472 | u32 *sizep, *lsizep; | 472 | u32 *sizep, *lsizep; |
| 473 | u32 size, lsize; | 473 | u32 size, lsize; |
| 474 | const char *dc, *ic; | 474 | const char *dc, *ic; |
| 475 | 475 | ||
| 476 | /* Then read cache informations */ | 476 | /* Then read cache informations */ |
| 477 | if (systemcfg->platform == PLATFORM_POWERMAC) { | 477 | if (systemcfg->platform == PLATFORM_POWERMAC) { |
| 478 | dc = "d-cache-block-size"; | 478 | dc = "d-cache-block-size"; |
| 479 | ic = "i-cache-block-size"; | 479 | ic = "i-cache-block-size"; |
| 480 | } else { | 480 | } else { |
| 481 | dc = "d-cache-line-size"; | 481 | dc = "d-cache-line-size"; |
| 482 | ic = "i-cache-line-size"; | 482 | ic = "i-cache-line-size"; |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | size = 0; | 485 | size = 0; |
| 486 | lsize = cur_cpu_spec->dcache_bsize; | 486 | lsize = cur_cpu_spec->dcache_bsize; |
| 487 | sizep = (u32 *)get_property(np, "d-cache-size", NULL); | 487 | sizep = (u32 *)get_property(np, "d-cache-size", NULL); |
| 488 | if (sizep != NULL) | 488 | if (sizep != NULL) |
| 489 | size = *sizep; | 489 | size = *sizep; |
| 490 | lsizep = (u32 *) get_property(np, dc, NULL); | 490 | lsizep = (u32 *) get_property(np, dc, NULL); |
| 491 | if (lsizep != NULL) | 491 | if (lsizep != NULL) |
| 492 | lsize = *lsizep; | 492 | lsize = *lsizep; |
| 493 | if (sizep == 0 || lsizep == 0) | 493 | if (sizep == 0 || lsizep == 0) |
| 494 | DBG("Argh, can't find dcache properties ! " | 494 | DBG("Argh, can't find dcache properties ! " |
| 495 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 495 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
| 496 | 496 | ||
| 497 | systemcfg->dcache_size = ppc64_caches.dsize = size; | 497 | systemcfg->dcache_size = ppc64_caches.dsize = size; |
| 498 | systemcfg->dcache_line_size = | 498 | systemcfg->dcache_line_size = |
| 499 | ppc64_caches.dline_size = lsize; | 499 | ppc64_caches.dline_size = lsize; |
| 500 | ppc64_caches.log_dline_size = __ilog2(lsize); | 500 | ppc64_caches.log_dline_size = __ilog2(lsize); |
| 501 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; | 501 | ppc64_caches.dlines_per_page = PAGE_SIZE / lsize; |
| 502 | 502 | ||
| 503 | size = 0; | 503 | size = 0; |
| 504 | lsize = cur_cpu_spec->icache_bsize; | 504 | lsize = cur_cpu_spec->icache_bsize; |
| 505 | sizep = (u32 *)get_property(np, "i-cache-size", NULL); | 505 | sizep = (u32 *)get_property(np, "i-cache-size", NULL); |
| 506 | if (sizep != NULL) | 506 | if (sizep != NULL) |
| 507 | size = *sizep; | 507 | size = *sizep; |
| 508 | lsizep = (u32 *)get_property(np, ic, NULL); | 508 | lsizep = (u32 *)get_property(np, ic, NULL); |
| 509 | if (lsizep != NULL) | 509 | if (lsizep != NULL) |
| 510 | lsize = *lsizep; | 510 | lsize = *lsizep; |
| 511 | if (sizep == 0 || lsizep == 0) | 511 | if (sizep == 0 || lsizep == 0) |
| 512 | DBG("Argh, can't find icache properties ! " | 512 | DBG("Argh, can't find icache properties ! " |
| 513 | "sizep: %p, lsizep: %p\n", sizep, lsizep); | 513 | "sizep: %p, lsizep: %p\n", sizep, lsizep); |
| 514 | 514 | ||
| 515 | systemcfg->icache_size = ppc64_caches.isize = size; | 515 | systemcfg->icache_size = ppc64_caches.isize = size; |
| 516 | systemcfg->icache_line_size = | 516 | systemcfg->icache_line_size = |
| 517 | ppc64_caches.iline_size = lsize; | 517 | ppc64_caches.iline_size = lsize; |
| 518 | ppc64_caches.log_iline_size = __ilog2(lsize); | 518 | ppc64_caches.log_iline_size = __ilog2(lsize); |
| 519 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; | 519 | ppc64_caches.ilines_per_page = PAGE_SIZE / lsize; |
| 520 | } | 520 | } |
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | /* Add an eye catcher and the systemcfg layout version number */ | 523 | /* Add an eye catcher and the systemcfg layout version number */ |
| 524 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); | 524 | strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64"); |
| 525 | systemcfg->version.major = SYSTEMCFG_MAJOR; | 525 | systemcfg->version.major = SYSTEMCFG_MAJOR; |
| 526 | systemcfg->version.minor = SYSTEMCFG_MINOR; | 526 | systemcfg->version.minor = SYSTEMCFG_MINOR; |
| 527 | systemcfg->processor = mfspr(SPRN_PVR); | 527 | systemcfg->processor = mfspr(SPRN_PVR); |
| 528 | 528 | ||
| 529 | DBG(" <- initialize_cache_info()\n"); | 529 | DBG(" <- initialize_cache_info()\n"); |
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | static void __init check_for_initrd(void) | 532 | static void __init check_for_initrd(void) |
| 533 | { | 533 | { |
| 534 | #ifdef CONFIG_BLK_DEV_INITRD | 534 | #ifdef CONFIG_BLK_DEV_INITRD |
| 535 | u64 *prop; | 535 | u64 *prop; |
| 536 | 536 | ||
| 537 | DBG(" -> check_for_initrd()\n"); | 537 | DBG(" -> check_for_initrd()\n"); |
| 538 | 538 | ||
| 539 | prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL); | 539 | prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL); |
| 540 | if (prop != NULL) { | 540 | if (prop != NULL) { |
| 541 | initrd_start = (unsigned long)__va(*prop); | 541 | initrd_start = (unsigned long)__va(*prop); |
| 542 | prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL); | 542 | prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL); |
| 543 | if (prop != NULL) { | 543 | if (prop != NULL) { |
| 544 | initrd_end = (unsigned long)__va(*prop); | 544 | initrd_end = (unsigned long)__va(*prop); |
| 545 | initrd_below_start_ok = 1; | 545 | initrd_below_start_ok = 1; |
| 546 | } else | 546 | } else |
| 547 | initrd_start = 0; | 547 | initrd_start = 0; |
| 548 | } | 548 | } |
| 549 | 549 | ||
| 550 | /* If we were passed an initrd, set the ROOT_DEV properly if the values | 550 | /* If we were passed an initrd, set the ROOT_DEV properly if the values |
| 551 | * look sensible. If not, clear initrd reference. | 551 | * look sensible. If not, clear initrd reference. |
| 552 | */ | 552 | */ |
| 553 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && | 553 | if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE && |
| 554 | initrd_end > initrd_start) | 554 | initrd_end > initrd_start) |
| 555 | ROOT_DEV = Root_RAM0; | 555 | ROOT_DEV = Root_RAM0; |
| 556 | else | 556 | else |
| 557 | initrd_start = initrd_end = 0; | 557 | initrd_start = initrd_end = 0; |
| 558 | 558 | ||
| 559 | if (initrd_start) | 559 | if (initrd_start) |
| 560 | printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); | 560 | printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end); |
| 561 | 561 | ||
| 562 | DBG(" <- check_for_initrd()\n"); | 562 | DBG(" <- check_for_initrd()\n"); |
| 563 | #endif /* CONFIG_BLK_DEV_INITRD */ | 563 | #endif /* CONFIG_BLK_DEV_INITRD */ |
| 564 | } | 564 | } |
| 565 | 565 | ||
| 566 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 566 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
| 567 | 567 | ||
| 568 | /* | 568 | /* |
| 569 | * Do some initial setup of the system. The parameters are those which | 569 | * Do some initial setup of the system. The parameters are those which |
| 570 | * were passed in from the bootloader. | 570 | * were passed in from the bootloader. |
| 571 | */ | 571 | */ |
| 572 | void __init setup_system(void) | 572 | void __init setup_system(void) |
| 573 | { | 573 | { |
| 574 | DBG(" -> setup_system()\n"); | 574 | DBG(" -> setup_system()\n"); |
| 575 | 575 | ||
| 576 | #ifdef CONFIG_PPC_ISERIES | 576 | #ifdef CONFIG_PPC_ISERIES |
| 577 | /* pSeries systems are identified in prom.c via OF. */ | 577 | /* pSeries systems are identified in prom.c via OF. */ |
| 578 | if (itLpNaca.xLparInstalled == 1) | 578 | if (itLpNaca.xLparInstalled == 1) |
| 579 | systemcfg->platform = PLATFORM_ISERIES_LPAR; | 579 | systemcfg->platform = PLATFORM_ISERIES_LPAR; |
| 580 | 580 | ||
| 581 | ppc_md.init_early(); | 581 | ppc_md.init_early(); |
| 582 | #else /* CONFIG_PPC_ISERIES */ | 582 | #else /* CONFIG_PPC_ISERIES */ |
| 583 | 583 | ||
| 584 | /* | 584 | /* |
| 585 | * Unflatten the device-tree passed by prom_init or kexec | 585 | * Unflatten the device-tree passed by prom_init or kexec |
| 586 | */ | 586 | */ |
| 587 | unflatten_device_tree(); | 587 | unflatten_device_tree(); |
| 588 | 588 | ||
| 589 | /* | 589 | /* |
| 590 | * Fill the ppc64_caches & systemcfg structures with informations | 590 | * Fill the ppc64_caches & systemcfg structures with informations |
| 591 | * retreived from the device-tree. Need to be called before | 591 | * retreived from the device-tree. Need to be called before |
| 592 | * finish_device_tree() since the later requires some of the | 592 | * finish_device_tree() since the later requires some of the |
| 593 | * informations filled up here to properly parse the interrupt | 593 | * informations filled up here to properly parse the interrupt |
| 594 | * tree. | 594 | * tree. |
| 595 | * It also sets up the cache line sizes which allows to call | 595 | * It also sets up the cache line sizes which allows to call |
| 596 | * routines like flush_icache_range (used by the hash init | 596 | * routines like flush_icache_range (used by the hash init |
| 597 | * later on). | 597 | * later on). |
| 598 | */ | 598 | */ |
| 599 | initialize_cache_info(); | 599 | initialize_cache_info(); |
| 600 | 600 | ||
| 601 | #ifdef CONFIG_PPC_RTAS | 601 | #ifdef CONFIG_PPC_RTAS |
| 602 | /* | 602 | /* |
| 603 | * Initialize RTAS if available | 603 | * Initialize RTAS if available |
| 604 | */ | 604 | */ |
| 605 | rtas_initialize(); | 605 | rtas_initialize(); |
| 606 | #endif /* CONFIG_PPC_RTAS */ | 606 | #endif /* CONFIG_PPC_RTAS */ |
| 607 | 607 | ||
| 608 | /* | 608 | /* |
| 609 | * Check if we have an initrd provided via the device-tree | 609 | * Check if we have an initrd provided via the device-tree |
| 610 | */ | 610 | */ |
| 611 | check_for_initrd(); | 611 | check_for_initrd(); |
| 612 | 612 | ||
| 613 | /* | 613 | /* |
| 614 | * Do some platform specific early initializations, that includes | 614 | * Do some platform specific early initializations, that includes |
| 615 | * setting up the hash table pointers. It also sets up some interrupt-mapping | 615 | * setting up the hash table pointers. It also sets up some interrupt-mapping |
| 616 | * related options that will be used by finish_device_tree() | 616 | * related options that will be used by finish_device_tree() |
| 617 | */ | 617 | */ |
| 618 | ppc_md.init_early(); | 618 | ppc_md.init_early(); |
| 619 | 619 | ||
| 620 | /* | 620 | /* |
| 621 | * "Finish" the device-tree, that is do the actual parsing of | 621 | * "Finish" the device-tree, that is do the actual parsing of |
| 622 | * some of the properties like the interrupt map | 622 | * some of the properties like the interrupt map |
| 623 | */ | 623 | */ |
| 624 | finish_device_tree(); | 624 | finish_device_tree(); |
| 625 | 625 | ||
| 626 | /* | 626 | /* |
| 627 | * Initialize xmon | 627 | * Initialize xmon |
| 628 | */ | 628 | */ |
| 629 | #ifdef CONFIG_XMON_DEFAULT | 629 | #ifdef CONFIG_XMON_DEFAULT |
| 630 | xmon_init(); | 630 | xmon_init(1); |
| 631 | #endif | 631 | #endif |
| 632 | /* | 632 | /* |
| 633 | * Register early console | 633 | * Register early console |
| 634 | */ | 634 | */ |
| 635 | early_console_initialized = 1; | 635 | early_console_initialized = 1; |
| 636 | register_console(&udbg_console); | 636 | register_console(&udbg_console); |
| 637 | 637 | ||
| 638 | /* Save unparsed command line copy for /proc/cmdline */ | 638 | /* Save unparsed command line copy for /proc/cmdline */ |
| 639 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); | 639 | strlcpy(saved_command_line, cmd_line, COMMAND_LINE_SIZE); |
| 640 | 640 | ||
| 641 | parse_early_param(); | 641 | parse_early_param(); |
| 642 | #endif /* !CONFIG_PPC_ISERIES */ | 642 | #endif /* !CONFIG_PPC_ISERIES */ |
| 643 | 643 | ||
| 644 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) | 644 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) |
| 645 | /* | 645 | /* |
| 646 | * iSeries has already initialized the cpu maps at this point. | 646 | * iSeries has already initialized the cpu maps at this point. |
| 647 | */ | 647 | */ |
| 648 | setup_cpu_maps(); | 648 | setup_cpu_maps(); |
| 649 | 649 | ||
| 650 | /* Release secondary cpus out of their spinloops at 0x60 now that | 650 | /* Release secondary cpus out of their spinloops at 0x60 now that |
| 651 | * we can map physical -> logical CPU ids | 651 | * we can map physical -> logical CPU ids |
| 652 | */ | 652 | */ |
| 653 | smp_release_cpus(); | 653 | smp_release_cpus(); |
| 654 | #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ | 654 | #endif /* defined(CONFIG_SMP) && !defined(CONFIG_PPC_ISERIES) */ |
| 655 | 655 | ||
| 656 | printk("Starting Linux PPC64 %s\n", UTS_RELEASE); | 656 | printk("Starting Linux PPC64 %s\n", UTS_RELEASE); |
| 657 | 657 | ||
| 658 | printk("-----------------------------------------------------\n"); | 658 | printk("-----------------------------------------------------\n"); |
| 659 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); | 659 | printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); |
| 660 | printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); | 660 | printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); |
| 661 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); | 661 | printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); |
| 662 | printk("systemcfg = 0x%p\n", systemcfg); | 662 | printk("systemcfg = 0x%p\n", systemcfg); |
| 663 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); | 663 | printk("systemcfg->platform = 0x%x\n", systemcfg->platform); |
| 664 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); | 664 | printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); |
| 665 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); | 665 | printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); |
| 666 | printk("ppc64_caches.dcache_line_size = 0x%x\n", | 666 | printk("ppc64_caches.dcache_line_size = 0x%x\n", |
| 667 | ppc64_caches.dline_size); | 667 | ppc64_caches.dline_size); |
| 668 | printk("ppc64_caches.icache_line_size = 0x%x\n", | 668 | printk("ppc64_caches.icache_line_size = 0x%x\n", |
| 669 | ppc64_caches.iline_size); | 669 | ppc64_caches.iline_size); |
| 670 | printk("htab_address = 0x%p\n", htab_address); | 670 | printk("htab_address = 0x%p\n", htab_address); |
| 671 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); | 671 | printk("htab_hash_mask = 0x%lx\n", htab_hash_mask); |
| 672 | printk("-----------------------------------------------------\n"); | 672 | printk("-----------------------------------------------------\n"); |
| 673 | 673 | ||
| 674 | mm_init_ppc64(); | 674 | mm_init_ppc64(); |
| 675 | 675 | ||
| 676 | DBG(" <- setup_system()\n"); | 676 | DBG(" <- setup_system()\n"); |
| 677 | } | 677 | } |
| 678 | 678 | ||
| 679 | /* also used by kexec */ | 679 | /* also used by kexec */ |
| 680 | void machine_shutdown(void) | 680 | void machine_shutdown(void) |
| 681 | { | 681 | { |
| 682 | if (ppc_md.nvram_sync) | 682 | if (ppc_md.nvram_sync) |
| 683 | ppc_md.nvram_sync(); | 683 | ppc_md.nvram_sync(); |
| 684 | } | 684 | } |
| 685 | 685 | ||
| 686 | void machine_restart(char *cmd) | 686 | void machine_restart(char *cmd) |
| 687 | { | 687 | { |
| 688 | machine_shutdown(); | 688 | machine_shutdown(); |
| 689 | ppc_md.restart(cmd); | 689 | ppc_md.restart(cmd); |
| 690 | #ifdef CONFIG_SMP | 690 | #ifdef CONFIG_SMP |
| 691 | smp_send_stop(); | 691 | smp_send_stop(); |
| 692 | #endif | 692 | #endif |
| 693 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 693 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
| 694 | local_irq_disable(); | 694 | local_irq_disable(); |
| 695 | while (1) ; | 695 | while (1) ; |
| 696 | } | 696 | } |
| 697 | 697 | ||
| 698 | void machine_power_off(void) | 698 | void machine_power_off(void) |
| 699 | { | 699 | { |
| 700 | machine_shutdown(); | 700 | machine_shutdown(); |
| 701 | ppc_md.power_off(); | 701 | ppc_md.power_off(); |
| 702 | #ifdef CONFIG_SMP | 702 | #ifdef CONFIG_SMP |
| 703 | smp_send_stop(); | 703 | smp_send_stop(); |
| 704 | #endif | 704 | #endif |
| 705 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 705 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
| 706 | local_irq_disable(); | 706 | local_irq_disable(); |
| 707 | while (1) ; | 707 | while (1) ; |
| 708 | } | 708 | } |
| 709 | /* Used by the G5 thermal driver */ | 709 | /* Used by the G5 thermal driver */ |
| 710 | EXPORT_SYMBOL_GPL(machine_power_off); | 710 | EXPORT_SYMBOL_GPL(machine_power_off); |
| 711 | 711 | ||
| 712 | void machine_halt(void) | 712 | void machine_halt(void) |
| 713 | { | 713 | { |
| 714 | machine_shutdown(); | 714 | machine_shutdown(); |
| 715 | ppc_md.halt(); | 715 | ppc_md.halt(); |
| 716 | #ifdef CONFIG_SMP | 716 | #ifdef CONFIG_SMP |
| 717 | smp_send_stop(); | 717 | smp_send_stop(); |
| 718 | #endif | 718 | #endif |
| 719 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | 719 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); |
| 720 | local_irq_disable(); | 720 | local_irq_disable(); |
| 721 | while (1) ; | 721 | while (1) ; |
| 722 | } | 722 | } |
| 723 | 723 | ||
| 724 | static int ppc64_panic_event(struct notifier_block *this, | 724 | static int ppc64_panic_event(struct notifier_block *this, |
| 725 | unsigned long event, void *ptr) | 725 | unsigned long event, void *ptr) |
| 726 | { | 726 | { |
| 727 | ppc_md.panic((char *)ptr); /* May not return */ | 727 | ppc_md.panic((char *)ptr); /* May not return */ |
| 728 | return NOTIFY_DONE; | 728 | return NOTIFY_DONE; |
| 729 | } | 729 | } |
| 730 | 730 | ||
| 731 | 731 | ||
| 732 | #ifdef CONFIG_SMP | 732 | #ifdef CONFIG_SMP |
| 733 | DEFINE_PER_CPU(unsigned int, pvr); | 733 | DEFINE_PER_CPU(unsigned int, pvr); |
| 734 | #endif | 734 | #endif |
| 735 | 735 | ||
| 736 | static int show_cpuinfo(struct seq_file *m, void *v) | 736 | static int show_cpuinfo(struct seq_file *m, void *v) |
| 737 | { | 737 | { |
| 738 | unsigned long cpu_id = (unsigned long)v - 1; | 738 | unsigned long cpu_id = (unsigned long)v - 1; |
| 739 | unsigned int pvr; | 739 | unsigned int pvr; |
| 740 | unsigned short maj; | 740 | unsigned short maj; |
| 741 | unsigned short min; | 741 | unsigned short min; |
| 742 | 742 | ||
| 743 | if (cpu_id == NR_CPUS) { | 743 | if (cpu_id == NR_CPUS) { |
| 744 | seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); | 744 | seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); |
| 745 | 745 | ||
| 746 | if (ppc_md.get_cpuinfo != NULL) | 746 | if (ppc_md.get_cpuinfo != NULL) |
| 747 | ppc_md.get_cpuinfo(m); | 747 | ppc_md.get_cpuinfo(m); |
| 748 | 748 | ||
| 749 | return 0; | 749 | return 0; |
| 750 | } | 750 | } |
| 751 | 751 | ||
| 752 | /* We only show online cpus: disable preempt (overzealous, I | 752 | /* We only show online cpus: disable preempt (overzealous, I |
| 753 | * knew) to prevent cpu going down. */ | 753 | * knew) to prevent cpu going down. */ |
| 754 | preempt_disable(); | 754 | preempt_disable(); |
| 755 | if (!cpu_online(cpu_id)) { | 755 | if (!cpu_online(cpu_id)) { |
| 756 | preempt_enable(); | 756 | preempt_enable(); |
| 757 | return 0; | 757 | return 0; |
| 758 | } | 758 | } |
| 759 | 759 | ||
| 760 | #ifdef CONFIG_SMP | 760 | #ifdef CONFIG_SMP |
| 761 | pvr = per_cpu(pvr, cpu_id); | 761 | pvr = per_cpu(pvr, cpu_id); |
| 762 | #else | 762 | #else |
| 763 | pvr = mfspr(SPRN_PVR); | 763 | pvr = mfspr(SPRN_PVR); |
| 764 | #endif | 764 | #endif |
| 765 | maj = (pvr >> 8) & 0xFF; | 765 | maj = (pvr >> 8) & 0xFF; |
| 766 | min = pvr & 0xFF; | 766 | min = pvr & 0xFF; |
| 767 | 767 | ||
| 768 | seq_printf(m, "processor\t: %lu\n", cpu_id); | 768 | seq_printf(m, "processor\t: %lu\n", cpu_id); |
| 769 | seq_printf(m, "cpu\t\t: "); | 769 | seq_printf(m, "cpu\t\t: "); |
| 770 | 770 | ||
| 771 | if (cur_cpu_spec->pvr_mask) | 771 | if (cur_cpu_spec->pvr_mask) |
| 772 | seq_printf(m, "%s", cur_cpu_spec->cpu_name); | 772 | seq_printf(m, "%s", cur_cpu_spec->cpu_name); |
| 773 | else | 773 | else |
| 774 | seq_printf(m, "unknown (%08x)", pvr); | 774 | seq_printf(m, "unknown (%08x)", pvr); |
| 775 | 775 | ||
| 776 | #ifdef CONFIG_ALTIVEC | 776 | #ifdef CONFIG_ALTIVEC |
| 777 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | 777 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) |
| 778 | seq_printf(m, ", altivec supported"); | 778 | seq_printf(m, ", altivec supported"); |
| 779 | #endif /* CONFIG_ALTIVEC */ | 779 | #endif /* CONFIG_ALTIVEC */ |
| 780 | 780 | ||
| 781 | seq_printf(m, "\n"); | 781 | seq_printf(m, "\n"); |
| 782 | 782 | ||
| 783 | /* | 783 | /* |
| 784 | * Assume here that all clock rates are the same in a | 784 | * Assume here that all clock rates are the same in a |
| 785 | * smp system. -- Cort | 785 | * smp system. -- Cort |
| 786 | */ | 786 | */ |
| 787 | seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, | 787 | seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000, |
| 788 | ppc_proc_freq % 1000000); | 788 | ppc_proc_freq % 1000000); |
| 789 | 789 | ||
| 790 | seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); | 790 | seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min); |
| 791 | 791 | ||
| 792 | preempt_enable(); | 792 | preempt_enable(); |
| 793 | return 0; | 793 | return 0; |
| 794 | } | 794 | } |
| 795 | 795 | ||
| 796 | static void *c_start(struct seq_file *m, loff_t *pos) | 796 | static void *c_start(struct seq_file *m, loff_t *pos) |
| 797 | { | 797 | { |
| 798 | return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; | 798 | return *pos <= NR_CPUS ? (void *)((*pos)+1) : NULL; |
| 799 | } | 799 | } |
| 800 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | 800 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) |
| 801 | { | 801 | { |
| 802 | ++*pos; | 802 | ++*pos; |
| 803 | return c_start(m, pos); | 803 | return c_start(m, pos); |
| 804 | } | 804 | } |
| 805 | static void c_stop(struct seq_file *m, void *v) | 805 | static void c_stop(struct seq_file *m, void *v) |
| 806 | { | 806 | { |
| 807 | } | 807 | } |
| 808 | struct seq_operations cpuinfo_op = { | 808 | struct seq_operations cpuinfo_op = { |
| 809 | .start =c_start, | 809 | .start =c_start, |
| 810 | .next = c_next, | 810 | .next = c_next, |
| 811 | .stop = c_stop, | 811 | .stop = c_stop, |
| 812 | .show = show_cpuinfo, | 812 | .show = show_cpuinfo, |
| 813 | }; | 813 | }; |
| 814 | 814 | ||
| 815 | /* | 815 | /* |
| 816 | * These three variables are used to save values passed to us by prom_init() | 816 | * These three variables are used to save values passed to us by prom_init() |
| 817 | * via the device tree. The TCE variables are needed because with a memory_limit | 817 | * via the device tree. The TCE variables are needed because with a memory_limit |
| 818 | * in force we may need to explicitly map the TCE are at the top of RAM. | 818 | * in force we may need to explicitly map the TCE are at the top of RAM. |
| 819 | */ | 819 | */ |
| 820 | unsigned long memory_limit; | 820 | unsigned long memory_limit; |
| 821 | unsigned long tce_alloc_start; | 821 | unsigned long tce_alloc_start; |
| 822 | unsigned long tce_alloc_end; | 822 | unsigned long tce_alloc_end; |
| 823 | 823 | ||
| 824 | #ifdef CONFIG_PPC_ISERIES | 824 | #ifdef CONFIG_PPC_ISERIES |
| 825 | /* | 825 | /* |
| 826 | * On iSeries we just parse the mem=X option from the command line. | 826 | * On iSeries we just parse the mem=X option from the command line. |
| 827 | * On pSeries it's a bit more complicated, see prom_init_mem() | 827 | * On pSeries it's a bit more complicated, see prom_init_mem() |
| 828 | */ | 828 | */ |
| 829 | static int __init early_parsemem(char *p) | 829 | static int __init early_parsemem(char *p) |
| 830 | { | 830 | { |
| 831 | if (!p) | 831 | if (!p) |
| 832 | return 0; | 832 | return 0; |
| 833 | 833 | ||
| 834 | memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); | 834 | memory_limit = ALIGN(memparse(p, &p), PAGE_SIZE); |
| 835 | 835 | ||
| 836 | return 0; | 836 | return 0; |
| 837 | } | 837 | } |
| 838 | early_param("mem", early_parsemem); | 838 | early_param("mem", early_parsemem); |
| 839 | #endif /* CONFIG_PPC_ISERIES */ | 839 | #endif /* CONFIG_PPC_ISERIES */ |
| 840 | 840 | ||
| 841 | #ifdef CONFIG_PPC_MULTIPLATFORM | 841 | #ifdef CONFIG_PPC_MULTIPLATFORM |
| 842 | static int __init set_preferred_console(void) | 842 | static int __init set_preferred_console(void) |
| 843 | { | 843 | { |
| 844 | struct device_node *prom_stdout = NULL; | 844 | struct device_node *prom_stdout = NULL; |
| 845 | char *name; | 845 | char *name; |
| 846 | u32 *spd; | 846 | u32 *spd; |
| 847 | int offset = 0; | 847 | int offset = 0; |
| 848 | 848 | ||
| 849 | DBG(" -> set_preferred_console()\n"); | 849 | DBG(" -> set_preferred_console()\n"); |
| 850 | 850 | ||
| 851 | /* The user has requested a console so this is already set up. */ | 851 | /* The user has requested a console so this is already set up. */ |
| 852 | if (strstr(saved_command_line, "console=")) { | 852 | if (strstr(saved_command_line, "console=")) { |
| 853 | DBG(" console was specified !\n"); | 853 | DBG(" console was specified !\n"); |
| 854 | return -EBUSY; | 854 | return -EBUSY; |
| 855 | } | 855 | } |
| 856 | 856 | ||
| 857 | if (!of_chosen) { | 857 | if (!of_chosen) { |
| 858 | DBG(" of_chosen is NULL !\n"); | 858 | DBG(" of_chosen is NULL !\n"); |
| 859 | return -ENODEV; | 859 | return -ENODEV; |
| 860 | } | 860 | } |
| 861 | /* We are getting a weird phandle from OF ... */ | 861 | /* We are getting a weird phandle from OF ... */ |
| 862 | /* ... So use the full path instead */ | 862 | /* ... So use the full path instead */ |
| 863 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | 863 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); |
| 864 | if (name == NULL) { | 864 | if (name == NULL) { |
| 865 | DBG(" no linux,stdout-path !\n"); | 865 | DBG(" no linux,stdout-path !\n"); |
| 866 | return -ENODEV; | 866 | return -ENODEV; |
| 867 | } | 867 | } |
| 868 | prom_stdout = of_find_node_by_path(name); | 868 | prom_stdout = of_find_node_by_path(name); |
| 869 | if (!prom_stdout) { | 869 | if (!prom_stdout) { |
| 870 | DBG(" can't find stdout package %s !\n", name); | 870 | DBG(" can't find stdout package %s !\n", name); |
| 871 | return -ENODEV; | 871 | return -ENODEV; |
| 872 | } | 872 | } |
| 873 | DBG("stdout is %s\n", prom_stdout->full_name); | 873 | DBG("stdout is %s\n", prom_stdout->full_name); |
| 874 | 874 | ||
| 875 | name = (char *)get_property(prom_stdout, "name", NULL); | 875 | name = (char *)get_property(prom_stdout, "name", NULL); |
| 876 | if (!name) { | 876 | if (!name) { |
| 877 | DBG(" stdout package has no name !\n"); | 877 | DBG(" stdout package has no name !\n"); |
| 878 | goto not_found; | 878 | goto not_found; |
| 879 | } | 879 | } |
| 880 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); | 880 | spd = (u32 *)get_property(prom_stdout, "current-speed", NULL); |
| 881 | 881 | ||
| 882 | if (0) | 882 | if (0) |
| 883 | ; | 883 | ; |
| 884 | #ifdef CONFIG_SERIAL_8250_CONSOLE | 884 | #ifdef CONFIG_SERIAL_8250_CONSOLE |
| 885 | else if (strcmp(name, "serial") == 0) { | 885 | else if (strcmp(name, "serial") == 0) { |
| 886 | int i; | 886 | int i; |
| 887 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); | 887 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i); |
| 888 | if (i > 8) { | 888 | if (i > 8) { |
| 889 | switch (reg[1]) { | 889 | switch (reg[1]) { |
| 890 | case 0x3f8: | 890 | case 0x3f8: |
| 891 | offset = 0; | 891 | offset = 0; |
| 892 | break; | 892 | break; |
| 893 | case 0x2f8: | 893 | case 0x2f8: |
| 894 | offset = 1; | 894 | offset = 1; |
| 895 | break; | 895 | break; |
| 896 | case 0x898: | 896 | case 0x898: |
| 897 | offset = 2; | 897 | offset = 2; |
| 898 | break; | 898 | break; |
| 899 | case 0x890: | 899 | case 0x890: |
| 900 | offset = 3; | 900 | offset = 3; |
| 901 | break; | 901 | break; |
| 902 | default: | 902 | default: |
| 903 | /* We dont recognise the serial port */ | 903 | /* We dont recognise the serial port */ |
| 904 | goto not_found; | 904 | goto not_found; |
| 905 | } | 905 | } |
| 906 | } | 906 | } |
| 907 | } | 907 | } |
| 908 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ | 908 | #endif /* CONFIG_SERIAL_8250_CONSOLE */ |
| 909 | #ifdef CONFIG_PPC_PSERIES | 909 | #ifdef CONFIG_PPC_PSERIES |
| 910 | else if (strcmp(name, "vty") == 0) { | 910 | else if (strcmp(name, "vty") == 0) { |
| 911 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); | 911 | u32 *reg = (u32 *)get_property(prom_stdout, "reg", NULL); |
| 912 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); | 912 | char *compat = (char *)get_property(prom_stdout, "compatible", NULL); |
| 913 | 913 | ||
| 914 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { | 914 | if (reg && compat && (strcmp(compat, "hvterm-protocol") == 0)) { |
| 915 | /* Host Virtual Serial Interface */ | 915 | /* Host Virtual Serial Interface */ |
| 916 | int offset; | 916 | int offset; |
| 917 | switch (reg[0]) { | 917 | switch (reg[0]) { |
| 918 | case 0x30000000: | 918 | case 0x30000000: |
| 919 | offset = 0; | 919 | offset = 0; |
| 920 | break; | 920 | break; |
| 921 | case 0x30000001: | 921 | case 0x30000001: |
| 922 | offset = 1; | 922 | offset = 1; |
| 923 | break; | 923 | break; |
| 924 | default: | 924 | default: |
| 925 | goto not_found; | 925 | goto not_found; |
| 926 | } | 926 | } |
| 927 | of_node_put(prom_stdout); | 927 | of_node_put(prom_stdout); |
| 928 | DBG("Found hvsi console at offset %d\n", offset); | 928 | DBG("Found hvsi console at offset %d\n", offset); |
| 929 | return add_preferred_console("hvsi", offset, NULL); | 929 | return add_preferred_console("hvsi", offset, NULL); |
| 930 | } else { | 930 | } else { |
| 931 | /* pSeries LPAR virtual console */ | 931 | /* pSeries LPAR virtual console */ |
| 932 | of_node_put(prom_stdout); | 932 | of_node_put(prom_stdout); |
| 933 | DBG("Found hvc console\n"); | 933 | DBG("Found hvc console\n"); |
| 934 | return add_preferred_console("hvc", 0, NULL); | 934 | return add_preferred_console("hvc", 0, NULL); |
| 935 | } | 935 | } |
| 936 | } | 936 | } |
| 937 | #endif /* CONFIG_PPC_PSERIES */ | 937 | #endif /* CONFIG_PPC_PSERIES */ |
| 938 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE | 938 | #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE |
| 939 | else if (strcmp(name, "ch-a") == 0) | 939 | else if (strcmp(name, "ch-a") == 0) |
| 940 | offset = 0; | 940 | offset = 0; |
| 941 | else if (strcmp(name, "ch-b") == 0) | 941 | else if (strcmp(name, "ch-b") == 0) |
| 942 | offset = 1; | 942 | offset = 1; |
| 943 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ | 943 | #endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ |
| 944 | else | 944 | else |
| 945 | goto not_found; | 945 | goto not_found; |
| 946 | of_node_put(prom_stdout); | 946 | of_node_put(prom_stdout); |
| 947 | 947 | ||
| 948 | DBG("Found serial console at ttyS%d\n", offset); | 948 | DBG("Found serial console at ttyS%d\n", offset); |
| 949 | 949 | ||
| 950 | if (spd) { | 950 | if (spd) { |
| 951 | static char __initdata opt[16]; | 951 | static char __initdata opt[16]; |
| 952 | sprintf(opt, "%d", *spd); | 952 | sprintf(opt, "%d", *spd); |
| 953 | return add_preferred_console("ttyS", offset, opt); | 953 | return add_preferred_console("ttyS", offset, opt); |
| 954 | } else | 954 | } else |
| 955 | return add_preferred_console("ttyS", offset, NULL); | 955 | return add_preferred_console("ttyS", offset, NULL); |
| 956 | 956 | ||
| 957 | not_found: | 957 | not_found: |
| 958 | DBG("No preferred console found !\n"); | 958 | DBG("No preferred console found !\n"); |
| 959 | of_node_put(prom_stdout); | 959 | of_node_put(prom_stdout); |
| 960 | return -ENODEV; | 960 | return -ENODEV; |
| 961 | } | 961 | } |
| 962 | console_initcall(set_preferred_console); | 962 | console_initcall(set_preferred_console); |
| 963 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 963 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
| 964 | 964 | ||
| 965 | #ifdef CONFIG_IRQSTACKS | 965 | #ifdef CONFIG_IRQSTACKS |
| 966 | static void __init irqstack_early_init(void) | 966 | static void __init irqstack_early_init(void) |
| 967 | { | 967 | { |
| 968 | unsigned int i; | 968 | unsigned int i; |
| 969 | 969 | ||
| 970 | /* | 970 | /* |
| 971 | * interrupt stacks must be under 256MB, we cannot afford to take | 971 | * interrupt stacks must be under 256MB, we cannot afford to take |
| 972 | * SLB misses on them. | 972 | * SLB misses on them. |
| 973 | */ | 973 | */ |
| 974 | for_each_cpu(i) { | 974 | for_each_cpu(i) { |
| 975 | softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, | 975 | softirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, |
| 976 | THREAD_SIZE, 0x10000000)); | 976 | THREAD_SIZE, 0x10000000)); |
| 977 | hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, | 977 | hardirq_ctx[i] = (struct thread_info *)__va(lmb_alloc_base(THREAD_SIZE, |
| 978 | THREAD_SIZE, 0x10000000)); | 978 | THREAD_SIZE, 0x10000000)); |
| 979 | } | 979 | } |
| 980 | } | 980 | } |
| 981 | #else | 981 | #else |
| 982 | #define irqstack_early_init() | 982 | #define irqstack_early_init() |
| 983 | #endif | 983 | #endif |
| 984 | 984 | ||
| 985 | /* | 985 | /* |
| 986 | * Stack space used when we detect a bad kernel stack pointer, and | 986 | * Stack space used when we detect a bad kernel stack pointer, and |
| 987 | * early in SMP boots before relocation is enabled. | 987 | * early in SMP boots before relocation is enabled. |
| 988 | */ | 988 | */ |
| 989 | static void __init emergency_stack_init(void) | 989 | static void __init emergency_stack_init(void) |
| 990 | { | 990 | { |
| 991 | unsigned long limit; | 991 | unsigned long limit; |
| 992 | unsigned int i; | 992 | unsigned int i; |
| 993 | 993 | ||
| 994 | /* | 994 | /* |
| 995 | * Emergency stacks must be under 256MB, we cannot afford to take | 995 | * Emergency stacks must be under 256MB, we cannot afford to take |
| 996 | * SLB misses on them. The ABI also requires them to be 128-byte | 996 | * SLB misses on them. The ABI also requires them to be 128-byte |
| 997 | * aligned. | 997 | * aligned. |
| 998 | * | 998 | * |
| 999 | * Since we use these as temporary stacks during secondary CPU | 999 | * Since we use these as temporary stacks during secondary CPU |
| 1000 | * bringup, we need to get at them in real mode. This means they | 1000 | * bringup, we need to get at them in real mode. This means they |
| 1001 | * must also be within the RMO region. | 1001 | * must also be within the RMO region. |
| 1002 | */ | 1002 | */ |
| 1003 | limit = min(0x10000000UL, lmb.rmo_size); | 1003 | limit = min(0x10000000UL, lmb.rmo_size); |
| 1004 | 1004 | ||
| 1005 | for_each_cpu(i) | 1005 | for_each_cpu(i) |
| 1006 | paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, | 1006 | paca[i].emergency_sp = __va(lmb_alloc_base(PAGE_SIZE, 128, |
| 1007 | limit)) + PAGE_SIZE; | 1007 | limit)) + PAGE_SIZE; |
| 1008 | } | 1008 | } |
| 1009 | 1009 | ||
| 1010 | /* | 1010 | /* |
| 1011 | * Called from setup_arch to initialize the bitmap of available | 1011 | * Called from setup_arch to initialize the bitmap of available |
| 1012 | * syscalls in the systemcfg page | 1012 | * syscalls in the systemcfg page |
| 1013 | */ | 1013 | */ |
| 1014 | void __init setup_syscall_map(void) | 1014 | void __init setup_syscall_map(void) |
| 1015 | { | 1015 | { |
| 1016 | unsigned int i, count64 = 0, count32 = 0; | 1016 | unsigned int i, count64 = 0, count32 = 0; |
| 1017 | extern unsigned long *sys_call_table; | 1017 | extern unsigned long *sys_call_table; |
| 1018 | extern unsigned long *sys_call_table32; | 1018 | extern unsigned long *sys_call_table32; |
| 1019 | extern unsigned long sys_ni_syscall; | 1019 | extern unsigned long sys_ni_syscall; |
| 1020 | 1020 | ||
| 1021 | 1021 | ||
| 1022 | for (i = 0; i < __NR_syscalls; i++) { | 1022 | for (i = 0; i < __NR_syscalls; i++) { |
| 1023 | if (sys_call_table[i] == sys_ni_syscall) | 1023 | if (sys_call_table[i] == sys_ni_syscall) |
| 1024 | continue; | 1024 | continue; |
| 1025 | count64++; | 1025 | count64++; |
| 1026 | systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); | 1026 | systemcfg->syscall_map_64[i >> 5] |= 0x80000000UL >> (i & 0x1f); |
| 1027 | } | 1027 | } |
| 1028 | for (i = 0; i < __NR_syscalls; i++) { | 1028 | for (i = 0; i < __NR_syscalls; i++) { |
| 1029 | if (sys_call_table32[i] == sys_ni_syscall) | 1029 | if (sys_call_table32[i] == sys_ni_syscall) |
| 1030 | continue; | 1030 | continue; |
| 1031 | count32++; | 1031 | count32++; |
| 1032 | systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); | 1032 | systemcfg->syscall_map_32[i >> 5] |= 0x80000000UL >> (i & 0x1f); |
| 1033 | } | 1033 | } |
| 1034 | printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", | 1034 | printk(KERN_INFO "Syscall map setup, %d 32 bits and %d 64 bits syscalls\n", |
| 1035 | count32, count64); | 1035 | count32, count64); |
| 1036 | } | 1036 | } |
| 1037 | 1037 | ||
| 1038 | /* | 1038 | /* |
| 1039 | * Called into from start_kernel, after lock_kernel has been called. | 1039 | * Called into from start_kernel, after lock_kernel has been called. |
| 1040 | * Initializes bootmem, which is unsed to manage page allocation until | 1040 | * Initializes bootmem, which is unsed to manage page allocation until |
| 1041 | * mem_init is called. | 1041 | * mem_init is called. |
| 1042 | */ | 1042 | */ |
| 1043 | void __init setup_arch(char **cmdline_p) | 1043 | void __init setup_arch(char **cmdline_p) |
| 1044 | { | 1044 | { |
| 1045 | extern void do_init_bootmem(void); | 1045 | extern void do_init_bootmem(void); |
| 1046 | 1046 | ||
| 1047 | ppc64_boot_msg(0x12, "Setup Arch"); | 1047 | ppc64_boot_msg(0x12, "Setup Arch"); |
| 1048 | 1048 | ||
| 1049 | *cmdline_p = cmd_line; | 1049 | *cmdline_p = cmd_line; |
| 1050 | 1050 | ||
| 1051 | /* | 1051 | /* |
| 1052 | * Set cache line size based on type of cpu as a default. | 1052 | * Set cache line size based on type of cpu as a default. |
| 1053 | * Systems with OF can look in the properties on the cpu node(s) | 1053 | * Systems with OF can look in the properties on the cpu node(s) |
| 1054 | * for a possibly more accurate value. | 1054 | * for a possibly more accurate value. |
| 1055 | */ | 1055 | */ |
| 1056 | dcache_bsize = ppc64_caches.dline_size; | 1056 | dcache_bsize = ppc64_caches.dline_size; |
| 1057 | icache_bsize = ppc64_caches.iline_size; | 1057 | icache_bsize = ppc64_caches.iline_size; |
| 1058 | 1058 | ||
| 1059 | /* reboot on panic */ | 1059 | /* reboot on panic */ |
| 1060 | panic_timeout = 180; | 1060 | panic_timeout = 180; |
| 1061 | 1061 | ||
| 1062 | if (ppc_md.panic) | 1062 | if (ppc_md.panic) |
| 1063 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); | 1063 | notifier_chain_register(&panic_notifier_list, &ppc64_panic_block); |
| 1064 | 1064 | ||
| 1065 | init_mm.start_code = PAGE_OFFSET; | 1065 | init_mm.start_code = PAGE_OFFSET; |
| 1066 | init_mm.end_code = (unsigned long) _etext; | 1066 | init_mm.end_code = (unsigned long) _etext; |
| 1067 | init_mm.end_data = (unsigned long) _edata; | 1067 | init_mm.end_data = (unsigned long) _edata; |
| 1068 | init_mm.brk = klimit; | 1068 | init_mm.brk = klimit; |
| 1069 | 1069 | ||
| 1070 | irqstack_early_init(); | 1070 | irqstack_early_init(); |
| 1071 | emergency_stack_init(); | 1071 | emergency_stack_init(); |
| 1072 | 1072 | ||
| 1073 | stabs_alloc(); | 1073 | stabs_alloc(); |
| 1074 | 1074 | ||
| 1075 | /* set up the bootmem stuff with available memory */ | 1075 | /* set up the bootmem stuff with available memory */ |
| 1076 | do_init_bootmem(); | 1076 | do_init_bootmem(); |
| 1077 | sparse_init(); | 1077 | sparse_init(); |
| 1078 | 1078 | ||
| 1079 | /* initialize the syscall map in systemcfg */ | 1079 | /* initialize the syscall map in systemcfg */ |
| 1080 | setup_syscall_map(); | 1080 | setup_syscall_map(); |
| 1081 | 1081 | ||
| 1082 | ppc_md.setup_arch(); | 1082 | ppc_md.setup_arch(); |
| 1083 | 1083 | ||
| 1084 | /* Use the default idle loop if the platform hasn't provided one. */ | 1084 | /* Use the default idle loop if the platform hasn't provided one. */ |
| 1085 | if (NULL == ppc_md.idle_loop) { | 1085 | if (NULL == ppc_md.idle_loop) { |
| 1086 | ppc_md.idle_loop = default_idle; | 1086 | ppc_md.idle_loop = default_idle; |
| 1087 | printk(KERN_INFO "Using default idle loop\n"); | 1087 | printk(KERN_INFO "Using default idle loop\n"); |
| 1088 | } | 1088 | } |
| 1089 | 1089 | ||
| 1090 | paging_init(); | 1090 | paging_init(); |
| 1091 | ppc64_boot_msg(0x15, "Setup Done"); | 1091 | ppc64_boot_msg(0x15, "Setup Done"); |
| 1092 | } | 1092 | } |
| 1093 | 1093 | ||
| 1094 | 1094 | ||
| 1095 | /* ToDo: do something useful if ppc_md is not yet setup. */ | 1095 | /* ToDo: do something useful if ppc_md is not yet setup. */ |
| 1096 | #define PPC64_LINUX_FUNCTION 0x0f000000 | 1096 | #define PPC64_LINUX_FUNCTION 0x0f000000 |
| 1097 | #define PPC64_IPL_MESSAGE 0xc0000000 | 1097 | #define PPC64_IPL_MESSAGE 0xc0000000 |
| 1098 | #define PPC64_TERM_MESSAGE 0xb0000000 | 1098 | #define PPC64_TERM_MESSAGE 0xb0000000 |
| 1099 | #define PPC64_ATTN_MESSAGE 0xa0000000 | 1099 | #define PPC64_ATTN_MESSAGE 0xa0000000 |
| 1100 | #define PPC64_DUMP_MESSAGE 0xd0000000 | 1100 | #define PPC64_DUMP_MESSAGE 0xd0000000 |
| 1101 | 1101 | ||
| 1102 | static void ppc64_do_msg(unsigned int src, const char *msg) | 1102 | static void ppc64_do_msg(unsigned int src, const char *msg) |
| 1103 | { | 1103 | { |
| 1104 | if (ppc_md.progress) { | 1104 | if (ppc_md.progress) { |
| 1105 | char buf[128]; | 1105 | char buf[128]; |
| 1106 | 1106 | ||
| 1107 | sprintf(buf, "%08X\n", src); | 1107 | sprintf(buf, "%08X\n", src); |
| 1108 | ppc_md.progress(buf, 0); | 1108 | ppc_md.progress(buf, 0); |
| 1109 | snprintf(buf, 128, "%s", msg); | 1109 | snprintf(buf, 128, "%s", msg); |
| 1110 | ppc_md.progress(buf, 0); | 1110 | ppc_md.progress(buf, 0); |
| 1111 | } | 1111 | } |
| 1112 | } | 1112 | } |
| 1113 | 1113 | ||
| 1114 | /* Print a boot progress message. */ | 1114 | /* Print a boot progress message. */ |
| 1115 | void ppc64_boot_msg(unsigned int src, const char *msg) | 1115 | void ppc64_boot_msg(unsigned int src, const char *msg) |
| 1116 | { | 1116 | { |
| 1117 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); | 1117 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_IPL_MESSAGE|src, msg); |
| 1118 | printk("[boot]%04x %s\n", src, msg); | 1118 | printk("[boot]%04x %s\n", src, msg); |
| 1119 | } | 1119 | } |
| 1120 | 1120 | ||
| 1121 | /* Print a termination message (print only -- does not stop the kernel) */ | 1121 | /* Print a termination message (print only -- does not stop the kernel) */ |
| 1122 | void ppc64_terminate_msg(unsigned int src, const char *msg) | 1122 | void ppc64_terminate_msg(unsigned int src, const char *msg) |
| 1123 | { | 1123 | { |
| 1124 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); | 1124 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); |
| 1125 | printk("[terminate]%04x %s\n", src, msg); | 1125 | printk("[terminate]%04x %s\n", src, msg); |
| 1126 | } | 1126 | } |
| 1127 | 1127 | ||
| 1128 | /* Print something that needs attention (device error, etc) */ | 1128 | /* Print something that needs attention (device error, etc) */ |
| 1129 | void ppc64_attention_msg(unsigned int src, const char *msg) | 1129 | void ppc64_attention_msg(unsigned int src, const char *msg) |
| 1130 | { | 1130 | { |
| 1131 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); | 1131 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_ATTN_MESSAGE|src, msg); |
| 1132 | printk("[attention]%04x %s\n", src, msg); | 1132 | printk("[attention]%04x %s\n", src, msg); |
| 1133 | } | 1133 | } |
| 1134 | 1134 | ||
| 1135 | /* Print a dump progress message. */ | 1135 | /* Print a dump progress message. */ |
| 1136 | void ppc64_dump_msg(unsigned int src, const char *msg) | 1136 | void ppc64_dump_msg(unsigned int src, const char *msg) |
| 1137 | { | 1137 | { |
| 1138 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); | 1138 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_DUMP_MESSAGE|src, msg); |
| 1139 | printk("[dump]%04x %s\n", src, msg); | 1139 | printk("[dump]%04x %s\n", src, msg); |
| 1140 | } | 1140 | } |
| 1141 | 1141 | ||
| 1142 | /* This should only be called on processor 0 during calibrate decr */ | 1142 | /* This should only be called on processor 0 during calibrate decr */ |
| 1143 | void __init setup_default_decr(void) | 1143 | void __init setup_default_decr(void) |
| 1144 | { | 1144 | { |
| 1145 | struct paca_struct *lpaca = get_paca(); | 1145 | struct paca_struct *lpaca = get_paca(); |
| 1146 | 1146 | ||
| 1147 | lpaca->default_decr = tb_ticks_per_jiffy; | 1147 | lpaca->default_decr = tb_ticks_per_jiffy; |
| 1148 | lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; | 1148 | lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; |
| 1149 | } | 1149 | } |
| 1150 | 1150 | ||
| 1151 | #ifndef CONFIG_PPC_ISERIES | 1151 | #ifndef CONFIG_PPC_ISERIES |
| 1152 | /* | 1152 | /* |
| 1153 | * This function can be used by platforms to "find" legacy serial ports. | 1153 | * This function can be used by platforms to "find" legacy serial ports. |
| 1154 | * It works for "serial" nodes under an "isa" node, and will try to | 1154 | * It works for "serial" nodes under an "isa" node, and will try to |
| 1155 | * respect the "ibm,aix-loc" property if any. It works with up to 8 | 1155 | * respect the "ibm,aix-loc" property if any. It works with up to 8 |
| 1156 | * ports. | 1156 | * ports. |
| 1157 | */ | 1157 | */ |
| 1158 | 1158 | ||
| 1159 | #define MAX_LEGACY_SERIAL_PORTS 8 | 1159 | #define MAX_LEGACY_SERIAL_PORTS 8 |
| 1160 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; | 1160 | static struct plat_serial8250_port serial_ports[MAX_LEGACY_SERIAL_PORTS+1]; |
| 1161 | static unsigned int old_serial_count; | 1161 | static unsigned int old_serial_count; |
| 1162 | 1162 | ||
| 1163 | void __init generic_find_legacy_serial_ports(u64 *physport, | 1163 | void __init generic_find_legacy_serial_ports(u64 *physport, |
| 1164 | unsigned int *default_speed) | 1164 | unsigned int *default_speed) |
| 1165 | { | 1165 | { |
| 1166 | struct device_node *np; | 1166 | struct device_node *np; |
| 1167 | u32 *sizeprop; | 1167 | u32 *sizeprop; |
| 1168 | 1168 | ||
| 1169 | struct isa_reg_property { | 1169 | struct isa_reg_property { |
| 1170 | u32 space; | 1170 | u32 space; |
| 1171 | u32 address; | 1171 | u32 address; |
| 1172 | u32 size; | 1172 | u32 size; |
| 1173 | }; | 1173 | }; |
| 1174 | struct pci_reg_property { | 1174 | struct pci_reg_property { |
| 1175 | struct pci_address addr; | 1175 | struct pci_address addr; |
| 1176 | u32 size_hi; | 1176 | u32 size_hi; |
| 1177 | u32 size_lo; | 1177 | u32 size_lo; |
| 1178 | }; | 1178 | }; |
| 1179 | 1179 | ||
| 1180 | DBG(" -> generic_find_legacy_serial_port()\n"); | 1180 | DBG(" -> generic_find_legacy_serial_port()\n"); |
| 1181 | 1181 | ||
| 1182 | *physport = 0; | 1182 | *physport = 0; |
| 1183 | if (default_speed) | 1183 | if (default_speed) |
| 1184 | *default_speed = 0; | 1184 | *default_speed = 0; |
| 1185 | 1185 | ||
| 1186 | np = of_find_node_by_path("/"); | 1186 | np = of_find_node_by_path("/"); |
| 1187 | if (!np) | 1187 | if (!np) |
| 1188 | return; | 1188 | return; |
| 1189 | 1189 | ||
| 1190 | /* First fill our array */ | 1190 | /* First fill our array */ |
| 1191 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { | 1191 | for (np = NULL; (np = of_find_node_by_type(np, "serial"));) { |
| 1192 | struct device_node *isa, *pci; | 1192 | struct device_node *isa, *pci; |
| 1193 | struct isa_reg_property *reg; | 1193 | struct isa_reg_property *reg; |
| 1194 | unsigned long phys_size, addr_size, io_base; | 1194 | unsigned long phys_size, addr_size, io_base; |
| 1195 | u32 *rangesp; | 1195 | u32 *rangesp; |
| 1196 | u32 *interrupts, *clk, *spd; | 1196 | u32 *interrupts, *clk, *spd; |
| 1197 | char *typep; | 1197 | char *typep; |
| 1198 | int index, rlen, rentsize; | 1198 | int index, rlen, rentsize; |
| 1199 | 1199 | ||
| 1200 | /* Ok, first check if it's under an "isa" parent */ | 1200 | /* Ok, first check if it's under an "isa" parent */ |
| 1201 | isa = of_get_parent(np); | 1201 | isa = of_get_parent(np); |
| 1202 | if (!isa || strcmp(isa->name, "isa")) { | 1202 | if (!isa || strcmp(isa->name, "isa")) { |
| 1203 | DBG("%s: no isa parent found\n", np->full_name); | 1203 | DBG("%s: no isa parent found\n", np->full_name); |
| 1204 | continue; | 1204 | continue; |
| 1205 | } | 1205 | } |
| 1206 | 1206 | ||
| 1207 | /* Now look for an "ibm,aix-loc" property that gives us ordering | 1207 | /* Now look for an "ibm,aix-loc" property that gives us ordering |
| 1208 | * if any... | 1208 | * if any... |
| 1209 | */ | 1209 | */ |
| 1210 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); | 1210 | typep = (char *)get_property(np, "ibm,aix-loc", NULL); |
| 1211 | 1211 | ||
| 1212 | /* Get the ISA port number */ | 1212 | /* Get the ISA port number */ |
| 1213 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); | 1213 | reg = (struct isa_reg_property *)get_property(np, "reg", NULL); |
| 1214 | if (reg == NULL) | 1214 | if (reg == NULL) |
| 1215 | goto next_port; | 1215 | goto next_port; |
| 1216 | /* We assume the interrupt number isn't translated ... */ | 1216 | /* We assume the interrupt number isn't translated ... */ |
| 1217 | interrupts = (u32 *)get_property(np, "interrupts", NULL); | 1217 | interrupts = (u32 *)get_property(np, "interrupts", NULL); |
| 1218 | /* get clock freq. if present */ | 1218 | /* get clock freq. if present */ |
| 1219 | clk = (u32 *)get_property(np, "clock-frequency", NULL); | 1219 | clk = (u32 *)get_property(np, "clock-frequency", NULL); |
| 1220 | /* get default speed if present */ | 1220 | /* get default speed if present */ |
| 1221 | spd = (u32 *)get_property(np, "current-speed", NULL); | 1221 | spd = (u32 *)get_property(np, "current-speed", NULL); |
| 1222 | /* Default to locate at end of array */ | 1222 | /* Default to locate at end of array */ |
| 1223 | index = old_serial_count; /* end of the array by default */ | 1223 | index = old_serial_count; /* end of the array by default */ |
| 1224 | 1224 | ||
| 1225 | /* If we have a location index, then use it */ | 1225 | /* If we have a location index, then use it */ |
| 1226 | if (typep && *typep == 'S') { | 1226 | if (typep && *typep == 'S') { |
| 1227 | index = simple_strtol(typep+1, NULL, 0) - 1; | 1227 | index = simple_strtol(typep+1, NULL, 0) - 1; |
| 1228 | /* if index is out of range, use end of array instead */ | 1228 | /* if index is out of range, use end of array instead */ |
| 1229 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 1229 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
| 1230 | index = old_serial_count; | 1230 | index = old_serial_count; |
| 1231 | /* if our index is still out of range, that mean that | 1231 | /* if our index is still out of range, that mean that |
| 1232 | * array is full, we could scan for a free slot but that | 1232 | * array is full, we could scan for a free slot but that |
| 1233 | * make little sense to bother, just skip the port | 1233 | * make little sense to bother, just skip the port |
| 1234 | */ | 1234 | */ |
| 1235 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 1235 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
| 1236 | goto next_port; | 1236 | goto next_port; |
| 1237 | if (index >= old_serial_count) | 1237 | if (index >= old_serial_count) |
| 1238 | old_serial_count = index + 1; | 1238 | old_serial_count = index + 1; |
| 1239 | /* Check if there is a port who already claimed our slot */ | 1239 | /* Check if there is a port who already claimed our slot */ |
| 1240 | if (serial_ports[index].iobase != 0) { | 1240 | if (serial_ports[index].iobase != 0) { |
| 1241 | /* if we still have some room, move it, else override */ | 1241 | /* if we still have some room, move it, else override */ |
| 1242 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { | 1242 | if (old_serial_count < MAX_LEGACY_SERIAL_PORTS) { |
| 1243 | DBG("Moved legacy port %d -> %d\n", index, | 1243 | DBG("Moved legacy port %d -> %d\n", index, |
| 1244 | old_serial_count); | 1244 | old_serial_count); |
| 1245 | serial_ports[old_serial_count++] = | 1245 | serial_ports[old_serial_count++] = |
| 1246 | serial_ports[index]; | 1246 | serial_ports[index]; |
| 1247 | } else { | 1247 | } else { |
| 1248 | DBG("Replacing legacy port %d\n", index); | 1248 | DBG("Replacing legacy port %d\n", index); |
| 1249 | } | 1249 | } |
| 1250 | } | 1250 | } |
| 1251 | } | 1251 | } |
| 1252 | if (index >= MAX_LEGACY_SERIAL_PORTS) | 1252 | if (index >= MAX_LEGACY_SERIAL_PORTS) |
| 1253 | goto next_port; | 1253 | goto next_port; |
| 1254 | if (index >= old_serial_count) | 1254 | if (index >= old_serial_count) |
| 1255 | old_serial_count = index + 1; | 1255 | old_serial_count = index + 1; |
| 1256 | 1256 | ||
| 1257 | /* Now fill the entry */ | 1257 | /* Now fill the entry */ |
| 1258 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); | 1258 | memset(&serial_ports[index], 0, sizeof(struct plat_serial8250_port)); |
| 1259 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; | 1259 | serial_ports[index].uartclk = clk ? *clk : BASE_BAUD * 16; |
| 1260 | serial_ports[index].iobase = reg->address; | 1260 | serial_ports[index].iobase = reg->address; |
| 1261 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; | 1261 | serial_ports[index].irq = interrupts ? interrupts[0] : 0; |
| 1262 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; | 1262 | serial_ports[index].flags = ASYNC_BOOT_AUTOCONF; |
| 1263 | 1263 | ||
| 1264 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", | 1264 | DBG("Added legacy port, index: %d, port: %x, irq: %d, clk: %d\n", |
| 1265 | index, | 1265 | index, |
| 1266 | serial_ports[index].iobase, | 1266 | serial_ports[index].iobase, |
| 1267 | serial_ports[index].irq, | 1267 | serial_ports[index].irq, |
| 1268 | serial_ports[index].uartclk); | 1268 | serial_ports[index].uartclk); |
| 1269 | 1269 | ||
| 1270 | /* Get phys address of IO reg for port 1 */ | 1270 | /* Get phys address of IO reg for port 1 */ |
| 1271 | if (index != 0) | 1271 | if (index != 0) |
| 1272 | goto next_port; | 1272 | goto next_port; |
| 1273 | 1273 | ||
| 1274 | pci = of_get_parent(isa); | 1274 | pci = of_get_parent(isa); |
| 1275 | if (!pci) { | 1275 | if (!pci) { |
| 1276 | DBG("%s: no pci parent found\n", np->full_name); | 1276 | DBG("%s: no pci parent found\n", np->full_name); |
| 1277 | goto next_port; | 1277 | goto next_port; |
| 1278 | } | 1278 | } |
| 1279 | 1279 | ||
| 1280 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); | 1280 | rangesp = (u32 *)get_property(pci, "ranges", &rlen); |
| 1281 | if (rangesp == NULL) { | 1281 | if (rangesp == NULL) { |
| 1282 | of_node_put(pci); | 1282 | of_node_put(pci); |
| 1283 | goto next_port; | 1283 | goto next_port; |
| 1284 | } | 1284 | } |
| 1285 | rlen /= 4; | 1285 | rlen /= 4; |
| 1286 | 1286 | ||
| 1287 | /* we need the #size-cells of the PCI bridge node itself */ | 1287 | /* we need the #size-cells of the PCI bridge node itself */ |
| 1288 | phys_size = 1; | 1288 | phys_size = 1; |
| 1289 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); | 1289 | sizeprop = (u32 *)get_property(pci, "#size-cells", NULL); |
| 1290 | if (sizeprop != NULL) | 1290 | if (sizeprop != NULL) |
| 1291 | phys_size = *sizeprop; | 1291 | phys_size = *sizeprop; |
| 1292 | /* we need the parent #addr-cells */ | 1292 | /* we need the parent #addr-cells */ |
| 1293 | addr_size = prom_n_addr_cells(pci); | 1293 | addr_size = prom_n_addr_cells(pci); |
| 1294 | rentsize = 3 + addr_size + phys_size; | 1294 | rentsize = 3 + addr_size + phys_size; |
| 1295 | io_base = 0; | 1295 | io_base = 0; |
| 1296 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { | 1296 | for (;rlen >= rentsize; rlen -= rentsize,rangesp += rentsize) { |
| 1297 | if (((rangesp[0] >> 24) & 0x3) != 1) | 1297 | if (((rangesp[0] >> 24) & 0x3) != 1) |
| 1298 | continue; /* not IO space */ | 1298 | continue; /* not IO space */ |
| 1299 | io_base = rangesp[3]; | 1299 | io_base = rangesp[3]; |
| 1300 | if (addr_size == 2) | 1300 | if (addr_size == 2) |
| 1301 | io_base = (io_base << 32) | rangesp[4]; | 1301 | io_base = (io_base << 32) | rangesp[4]; |
| 1302 | } | 1302 | } |
| 1303 | if (io_base != 0) { | 1303 | if (io_base != 0) { |
| 1304 | *physport = io_base + reg->address; | 1304 | *physport = io_base + reg->address; |
| 1305 | if (default_speed && spd) | 1305 | if (default_speed && spd) |
| 1306 | *default_speed = *spd; | 1306 | *default_speed = *spd; |
| 1307 | } | 1307 | } |
| 1308 | of_node_put(pci); | 1308 | of_node_put(pci); |
| 1309 | next_port: | 1309 | next_port: |
| 1310 | of_node_put(isa); | 1310 | of_node_put(isa); |
| 1311 | } | 1311 | } |
| 1312 | 1312 | ||
| 1313 | DBG(" <- generic_find_legacy_serial_port()\n"); | 1313 | DBG(" <- generic_find_legacy_serial_port()\n"); |
| 1314 | } | 1314 | } |
| 1315 | 1315 | ||
| 1316 | static struct platform_device serial_device = { | 1316 | static struct platform_device serial_device = { |
| 1317 | .name = "serial8250", | 1317 | .name = "serial8250", |
| 1318 | .id = 0, | 1318 | .id = 0, |
| 1319 | .dev = { | 1319 | .dev = { |
| 1320 | .platform_data = serial_ports, | 1320 | .platform_data = serial_ports, |
| 1321 | }, | 1321 | }, |
| 1322 | }; | 1322 | }; |
| 1323 | 1323 | ||
| 1324 | static int __init serial_dev_init(void) | 1324 | static int __init serial_dev_init(void) |
| 1325 | { | 1325 | { |
| 1326 | return platform_device_register(&serial_device); | 1326 | return platform_device_register(&serial_device); |
| 1327 | } | 1327 | } |
| 1328 | arch_initcall(serial_dev_init); | 1328 | arch_initcall(serial_dev_init); |
| 1329 | 1329 | ||
| 1330 | #endif /* CONFIG_PPC_ISERIES */ | 1330 | #endif /* CONFIG_PPC_ISERIES */ |
| 1331 | 1331 | ||
| 1332 | int check_legacy_ioport(unsigned long base_port) | 1332 | int check_legacy_ioport(unsigned long base_port) |
| 1333 | { | 1333 | { |
| 1334 | if (ppc_md.check_legacy_ioport == NULL) | 1334 | if (ppc_md.check_legacy_ioport == NULL) |
| 1335 | return 0; | 1335 | return 0; |
| 1336 | return ppc_md.check_legacy_ioport(base_port); | 1336 | return ppc_md.check_legacy_ioport(base_port); |
| 1337 | } | 1337 | } |
| 1338 | EXPORT_SYMBOL(check_legacy_ioport); | 1338 | EXPORT_SYMBOL(check_legacy_ioport); |
| 1339 | 1339 | ||
| 1340 | #ifdef CONFIG_XMON | 1340 | #ifdef CONFIG_XMON |
| 1341 | static int __init early_xmon(char *p) | 1341 | static int __init early_xmon(char *p) |
| 1342 | { | 1342 | { |
| 1343 | /* ensure xmon is enabled */ | 1343 | /* ensure xmon is enabled */ |
| 1344 | if (p) { | 1344 | if (p) { |
| 1345 | if (strncmp(p, "on", 2) == 0) | 1345 | if (strncmp(p, "on", 2) == 0) |
| 1346 | xmon_init(); | 1346 | xmon_init(1); |
| 1347 | if (strncmp(p, "off", 3) == 0) | ||
| 1348 | xmon_init(0); | ||
| 1347 | if (strncmp(p, "early", 5) != 0) | 1349 | if (strncmp(p, "early", 5) != 0) |
| 1348 | return 0; | 1350 | return 0; |
| 1349 | } | 1351 | } |
| 1350 | xmon_init(); | 1352 | xmon_init(1); |
| 1351 | debugger(NULL); | 1353 | debugger(NULL); |
| 1352 | 1354 | ||
| 1353 | return 0; | 1355 | return 0; |
| 1354 | } | 1356 | } |
| 1355 | early_param("xmon", early_xmon); | 1357 | early_param("xmon", early_xmon); |
| 1356 | #endif | 1358 | #endif |
| 1357 | 1359 | ||
| 1358 | void cpu_die(void) | 1360 | void cpu_die(void) |
| 1359 | { | 1361 | { |
| 1360 | if (ppc_md.cpu_die) | 1362 | if (ppc_md.cpu_die) |
| 1361 | ppc_md.cpu_die(); | 1363 | ppc_md.cpu_die(); |
| 1362 | } | 1364 | } |
| 1363 | 1365 |
arch/ppc64/xmon/start.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> | 9 | #include <linux/config.h> |
| 10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
| 11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| 13 | #include <linux/sysrq.h> | 13 | #include <linux/sysrq.h> |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <asm/machdep.h> | 15 | #include <asm/machdep.h> |
| 16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
| 17 | #include <asm/page.h> | 17 | #include <asm/page.h> |
| 18 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
| 19 | #include <asm/processor.h> | 19 | #include <asm/processor.h> |
| 20 | #include <asm/udbg.h> | 20 | #include <asm/udbg.h> |
| 21 | #include <asm/system.h> | 21 | #include <asm/system.h> |
| 22 | #include "nonstdio.h" | 22 | #include "nonstdio.h" |
| 23 | 23 | ||
| 24 | #ifdef CONFIG_MAGIC_SYSRQ | 24 | #ifdef CONFIG_MAGIC_SYSRQ |
| 25 | 25 | ||
| 26 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, | 26 | static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs, |
| 27 | struct tty_struct *tty) | 27 | struct tty_struct *tty) |
| 28 | { | 28 | { |
| 29 | /* ensure xmon is enabled */ | 29 | /* ensure xmon is enabled */ |
| 30 | xmon_init(); | 30 | xmon_init(1); |
| 31 | debugger(pt_regs); | 31 | debugger(pt_regs); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | static struct sysrq_key_op sysrq_xmon_op = | 34 | static struct sysrq_key_op sysrq_xmon_op = |
| 35 | { | 35 | { |
| 36 | .handler = sysrq_handle_xmon, | 36 | .handler = sysrq_handle_xmon, |
| 37 | .help_msg = "Xmon", | 37 | .help_msg = "Xmon", |
| 38 | .action_msg = "Entering xmon", | 38 | .action_msg = "Entering xmon", |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | static int __init setup_xmon_sysrq(void) | 41 | static int __init setup_xmon_sysrq(void) |
| 42 | { | 42 | { |
| 43 | register_sysrq_key('x', &sysrq_xmon_op); | 43 | register_sysrq_key('x', &sysrq_xmon_op); |
| 44 | return 0; | 44 | return 0; |
| 45 | } | 45 | } |
| 46 | __initcall(setup_xmon_sysrq); | 46 | __initcall(setup_xmon_sysrq); |
| 47 | #endif /* CONFIG_MAGIC_SYSRQ */ | 47 | #endif /* CONFIG_MAGIC_SYSRQ */ |
| 48 | 48 | ||
| 49 | int | 49 | int |
| 50 | xmon_write(void *handle, void *ptr, int nb) | 50 | xmon_write(void *handle, void *ptr, int nb) |
| 51 | { | 51 | { |
| 52 | return udbg_write(ptr, nb); | 52 | return udbg_write(ptr, nb); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | int | 55 | int |
| 56 | xmon_read(void *handle, void *ptr, int nb) | 56 | xmon_read(void *handle, void *ptr, int nb) |
| 57 | { | 57 | { |
| 58 | return udbg_read(ptr, nb); | 58 | return udbg_read(ptr, nb); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | int | 61 | int |
| 62 | xmon_read_poll(void) | 62 | xmon_read_poll(void) |
| 63 | { | 63 | { |
| 64 | return udbg_getc_poll(); | 64 | return udbg_getc_poll(); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | FILE *xmon_stdin; | 67 | FILE *xmon_stdin; |
| 68 | FILE *xmon_stdout; | 68 | FILE *xmon_stdout; |
| 69 | 69 | ||
| 70 | int | 70 | int |
| 71 | xmon_putc(int c, void *f) | 71 | xmon_putc(int c, void *f) |
| 72 | { | 72 | { |
| 73 | char ch = c; | 73 | char ch = c; |
| 74 | 74 | ||
| 75 | if (c == '\n') | 75 | if (c == '\n') |
| 76 | xmon_putc('\r', f); | 76 | xmon_putc('\r', f); |
| 77 | return xmon_write(f, &ch, 1) == 1? c: -1; | 77 | return xmon_write(f, &ch, 1) == 1? c: -1; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | int | 80 | int |
| 81 | xmon_putchar(int c) | 81 | xmon_putchar(int c) |
| 82 | { | 82 | { |
| 83 | return xmon_putc(c, xmon_stdout); | 83 | return xmon_putc(c, xmon_stdout); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | int | 86 | int |
| 87 | xmon_fputs(char *str, void *f) | 87 | xmon_fputs(char *str, void *f) |
| 88 | { | 88 | { |
| 89 | int n = strlen(str); | 89 | int n = strlen(str); |
| 90 | 90 | ||
| 91 | return xmon_write(f, str, n) == n? 0: -1; | 91 | return xmon_write(f, str, n) == n? 0: -1; |
| 92 | } | 92 | } |
| 93 | 93 | ||
| 94 | int | 94 | int |
| 95 | xmon_readchar(void) | 95 | xmon_readchar(void) |
| 96 | { | 96 | { |
| 97 | char ch; | 97 | char ch; |
| 98 | 98 | ||
| 99 | for (;;) { | 99 | for (;;) { |
| 100 | switch (xmon_read(xmon_stdin, &ch, 1)) { | 100 | switch (xmon_read(xmon_stdin, &ch, 1)) { |
| 101 | case 1: | 101 | case 1: |
| 102 | return ch; | 102 | return ch; |
| 103 | case -1: | 103 | case -1: |
| 104 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); | 104 | xmon_printf("read(stdin) returned -1\r\n", 0, 0); |
| 105 | return -1; | 105 | return -1; |
| 106 | } | 106 | } |
| 107 | } | 107 | } |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static char line[256]; | 110 | static char line[256]; |
| 111 | static char *lineptr; | 111 | static char *lineptr; |
| 112 | static int lineleft; | 112 | static int lineleft; |
| 113 | 113 | ||
| 114 | int | 114 | int |
| 115 | xmon_getchar(void) | 115 | xmon_getchar(void) |
| 116 | { | 116 | { |
| 117 | int c; | 117 | int c; |
| 118 | 118 | ||
| 119 | if (lineleft == 0) { | 119 | if (lineleft == 0) { |
| 120 | lineptr = line; | 120 | lineptr = line; |
| 121 | for (;;) { | 121 | for (;;) { |
| 122 | c = xmon_readchar(); | 122 | c = xmon_readchar(); |
| 123 | if (c == -1 || c == 4) | 123 | if (c == -1 || c == 4) |
| 124 | break; | 124 | break; |
| 125 | if (c == '\r' || c == '\n') { | 125 | if (c == '\r' || c == '\n') { |
| 126 | *lineptr++ = '\n'; | 126 | *lineptr++ = '\n'; |
| 127 | xmon_putchar('\n'); | 127 | xmon_putchar('\n'); |
| 128 | break; | 128 | break; |
| 129 | } | 129 | } |
| 130 | switch (c) { | 130 | switch (c) { |
| 131 | case 0177: | 131 | case 0177: |
| 132 | case '\b': | 132 | case '\b': |
| 133 | if (lineptr > line) { | 133 | if (lineptr > line) { |
| 134 | xmon_putchar('\b'); | 134 | xmon_putchar('\b'); |
| 135 | xmon_putchar(' '); | 135 | xmon_putchar(' '); |
| 136 | xmon_putchar('\b'); | 136 | xmon_putchar('\b'); |
| 137 | --lineptr; | 137 | --lineptr; |
| 138 | } | 138 | } |
| 139 | break; | 139 | break; |
| 140 | case 'U' & 0x1F: | 140 | case 'U' & 0x1F: |
| 141 | while (lineptr > line) { | 141 | while (lineptr > line) { |
| 142 | xmon_putchar('\b'); | 142 | xmon_putchar('\b'); |
| 143 | xmon_putchar(' '); | 143 | xmon_putchar(' '); |
| 144 | xmon_putchar('\b'); | 144 | xmon_putchar('\b'); |
| 145 | --lineptr; | 145 | --lineptr; |
| 146 | } | 146 | } |
| 147 | break; | 147 | break; |
| 148 | default: | 148 | default: |
| 149 | if (lineptr >= &line[sizeof(line) - 1]) | 149 | if (lineptr >= &line[sizeof(line) - 1]) |
| 150 | xmon_putchar('\a'); | 150 | xmon_putchar('\a'); |
| 151 | else { | 151 | else { |
| 152 | xmon_putchar(c); | 152 | xmon_putchar(c); |
| 153 | *lineptr++ = c; | 153 | *lineptr++ = c; |
| 154 | } | 154 | } |
| 155 | } | 155 | } |
| 156 | } | 156 | } |
| 157 | lineleft = lineptr - line; | 157 | lineleft = lineptr - line; |
| 158 | lineptr = line; | 158 | lineptr = line; |
| 159 | } | 159 | } |
| 160 | if (lineleft == 0) | 160 | if (lineleft == 0) |
| 161 | return -1; | 161 | return -1; |
| 162 | --lineleft; | 162 | --lineleft; |
| 163 | return *lineptr++; | 163 | return *lineptr++; |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | char * | 166 | char * |
| 167 | xmon_fgets(char *str, int nb, void *f) | 167 | xmon_fgets(char *str, int nb, void *f) |
| 168 | { | 168 | { |
| 169 | char *p; | 169 | char *p; |
| 170 | int c; | 170 | int c; |
| 171 | 171 | ||
| 172 | for (p = str; p < str + nb - 1; ) { | 172 | for (p = str; p < str + nb - 1; ) { |
| 173 | c = xmon_getchar(); | 173 | c = xmon_getchar(); |
| 174 | if (c == -1) { | 174 | if (c == -1) { |
| 175 | if (p == str) | 175 | if (p == str) |
| 176 | return NULL; | 176 | return NULL; |
| 177 | break; | 177 | break; |
| 178 | } | 178 | } |
| 179 | *p++ = c; | 179 | *p++ = c; |
| 180 | if (c == '\n') | 180 | if (c == '\n') |
| 181 | break; | 181 | break; |
| 182 | } | 182 | } |
| 183 | *p = 0; | 183 | *p = 0; |
| 184 | return str; | 184 | return str; |
| 185 | } | 185 | } |
| 186 | 186 |
arch/ppc64/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 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 | 20 | ||
| 21 | #include <asm/ptrace.h> | 21 | #include <asm/ptrace.h> |
| 22 | #include <asm/string.h> | 22 | #include <asm/string.h> |
| 23 | #include <asm/prom.h> | 23 | #include <asm/prom.h> |
| 24 | #include <asm/machdep.h> | 24 | #include <asm/machdep.h> |
| 25 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
| 26 | #include <asm/pgtable.h> | 26 | #include <asm/pgtable.h> |
| 27 | #include <asm/mmu.h> | 27 | #include <asm/mmu.h> |
| 28 | #include <asm/mmu_context.h> | 28 | #include <asm/mmu_context.h> |
| 29 | #include <asm/paca.h> | 29 | #include <asm/paca.h> |
| 30 | #include <asm/ppcdebug.h> | 30 | #include <asm/ppcdebug.h> |
| 31 | #include <asm/cputable.h> | 31 | #include <asm/cputable.h> |
| 32 | #include <asm/rtas.h> | 32 | #include <asm/rtas.h> |
| 33 | #include <asm/sstep.h> | 33 | #include <asm/sstep.h> |
| 34 | #include <asm/bug.h> | 34 | #include <asm/bug.h> |
| 35 | #include <asm/hvcall.h> | 35 | #include <asm/hvcall.h> |
| 36 | 36 | ||
| 37 | #include "nonstdio.h" | 37 | #include "nonstdio.h" |
| 38 | #include "privinst.h" | 38 | #include "privinst.h" |
| 39 | 39 | ||
| 40 | #define scanhex xmon_scanhex | 40 | #define scanhex xmon_scanhex |
| 41 | #define skipbl xmon_skipbl | 41 | #define skipbl xmon_skipbl |
| 42 | 42 | ||
| 43 | #ifdef CONFIG_SMP | 43 | #ifdef CONFIG_SMP |
| 44 | cpumask_t cpus_in_xmon = CPU_MASK_NONE; | 44 | cpumask_t cpus_in_xmon = CPU_MASK_NONE; |
| 45 | static unsigned long xmon_taken = 1; | 45 | static unsigned long xmon_taken = 1; |
| 46 | static int xmon_owner; | 46 | static int xmon_owner; |
| 47 | static int xmon_gate; | 47 | static int xmon_gate; |
| 48 | #endif /* CONFIG_SMP */ | 48 | #endif /* CONFIG_SMP */ |
| 49 | 49 | ||
| 50 | static unsigned long in_xmon = 0; | 50 | static unsigned long in_xmon = 0; |
| 51 | 51 | ||
| 52 | static unsigned long adrs; | 52 | static unsigned long adrs; |
| 53 | static int size = 1; | 53 | static int size = 1; |
| 54 | #define MAX_DUMP (128 * 1024) | 54 | #define MAX_DUMP (128 * 1024) |
| 55 | static unsigned long ndump = 64; | 55 | static unsigned long ndump = 64; |
| 56 | static unsigned long nidump = 16; | 56 | static unsigned long nidump = 16; |
| 57 | static unsigned long ncsum = 4096; | 57 | static unsigned long ncsum = 4096; |
| 58 | static int termch; | 58 | static int termch; |
| 59 | static char tmpstr[128]; | 59 | static char tmpstr[128]; |
| 60 | 60 | ||
| 61 | #define JMP_BUF_LEN (184/sizeof(long)) | 61 | #define JMP_BUF_LEN (184/sizeof(long)) |
| 62 | static long bus_error_jmp[JMP_BUF_LEN]; | 62 | static long bus_error_jmp[JMP_BUF_LEN]; |
| 63 | static int catch_memory_errors; | 63 | static int catch_memory_errors; |
| 64 | static long *xmon_fault_jmp[NR_CPUS]; | 64 | static long *xmon_fault_jmp[NR_CPUS]; |
| 65 | #define setjmp xmon_setjmp | 65 | #define setjmp xmon_setjmp |
| 66 | #define longjmp xmon_longjmp | 66 | #define longjmp xmon_longjmp |
| 67 | 67 | ||
| 68 | /* Breakpoint stuff */ | 68 | /* Breakpoint stuff */ |
| 69 | struct bpt { | 69 | struct bpt { |
| 70 | unsigned long address; | 70 | unsigned long address; |
| 71 | unsigned int instr[2]; | 71 | unsigned int instr[2]; |
| 72 | atomic_t ref_count; | 72 | atomic_t ref_count; |
| 73 | int enabled; | 73 | int enabled; |
| 74 | unsigned long pad; | 74 | unsigned long pad; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | /* Bits in bpt.enabled */ | 77 | /* Bits in bpt.enabled */ |
| 78 | #define BP_IABR_TE 1 /* IABR translation enabled */ | 78 | #define BP_IABR_TE 1 /* IABR translation enabled */ |
| 79 | #define BP_IABR 2 | 79 | #define BP_IABR 2 |
| 80 | #define BP_TRAP 8 | 80 | #define BP_TRAP 8 |
| 81 | #define BP_DABR 0x10 | 81 | #define BP_DABR 0x10 |
| 82 | 82 | ||
| 83 | #define NBPTS 256 | 83 | #define NBPTS 256 |
| 84 | static struct bpt bpts[NBPTS]; | 84 | static struct bpt bpts[NBPTS]; |
| 85 | static struct bpt dabr; | 85 | static struct bpt dabr; |
| 86 | static struct bpt *iabr; | 86 | static struct bpt *iabr; |
| 87 | static unsigned bpinstr = 0x7fe00008; /* trap */ | 87 | static unsigned bpinstr = 0x7fe00008; /* trap */ |
| 88 | 88 | ||
| 89 | #define BP_NUM(bp) ((bp) - bpts + 1) | 89 | #define BP_NUM(bp) ((bp) - bpts + 1) |
| 90 | 90 | ||
| 91 | /* Prototypes */ | 91 | /* Prototypes */ |
| 92 | static int cmds(struct pt_regs *); | 92 | static int cmds(struct pt_regs *); |
| 93 | static int mread(unsigned long, void *, int); | 93 | static int mread(unsigned long, void *, int); |
| 94 | static int mwrite(unsigned long, void *, int); | 94 | static int mwrite(unsigned long, void *, int); |
| 95 | static int handle_fault(struct pt_regs *); | 95 | static int handle_fault(struct pt_regs *); |
| 96 | static void byterev(unsigned char *, int); | 96 | static void byterev(unsigned char *, int); |
| 97 | static void memex(void); | 97 | static void memex(void); |
| 98 | static int bsesc(void); | 98 | static int bsesc(void); |
| 99 | static void dump(void); | 99 | static void dump(void); |
| 100 | static void prdump(unsigned long, long); | 100 | static void prdump(unsigned long, long); |
| 101 | static int ppc_inst_dump(unsigned long, long, int); | 101 | static int ppc_inst_dump(unsigned long, long, int); |
| 102 | void print_address(unsigned long); | 102 | void print_address(unsigned long); |
| 103 | static void backtrace(struct pt_regs *); | 103 | static void backtrace(struct pt_regs *); |
| 104 | static void excprint(struct pt_regs *); | 104 | static void excprint(struct pt_regs *); |
| 105 | static void prregs(struct pt_regs *); | 105 | static void prregs(struct pt_regs *); |
| 106 | static void memops(int); | 106 | static void memops(int); |
| 107 | static void memlocate(void); | 107 | static void memlocate(void); |
| 108 | static void memzcan(void); | 108 | static void memzcan(void); |
| 109 | static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned); | 109 | static void memdiffs(unsigned char *, unsigned char *, unsigned, unsigned); |
| 110 | int skipbl(void); | 110 | int skipbl(void); |
| 111 | int scanhex(unsigned long *valp); | 111 | int scanhex(unsigned long *valp); |
| 112 | static void scannl(void); | 112 | static void scannl(void); |
| 113 | static int hexdigit(int); | 113 | static int hexdigit(int); |
| 114 | void getstring(char *, int); | 114 | void getstring(char *, int); |
| 115 | static void flush_input(void); | 115 | static void flush_input(void); |
| 116 | static int inchar(void); | 116 | static int inchar(void); |
| 117 | static void take_input(char *); | 117 | static void take_input(char *); |
| 118 | static unsigned long read_spr(int); | 118 | static unsigned long read_spr(int); |
| 119 | static void write_spr(int, unsigned long); | 119 | static void write_spr(int, unsigned long); |
| 120 | static void super_regs(void); | 120 | static void super_regs(void); |
| 121 | static void remove_bpts(void); | 121 | static void remove_bpts(void); |
| 122 | static void insert_bpts(void); | 122 | static void insert_bpts(void); |
| 123 | static void remove_cpu_bpts(void); | 123 | static void remove_cpu_bpts(void); |
| 124 | static void insert_cpu_bpts(void); | 124 | static void insert_cpu_bpts(void); |
| 125 | static struct bpt *at_breakpoint(unsigned long pc); | 125 | static struct bpt *at_breakpoint(unsigned long pc); |
| 126 | static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp); | 126 | static struct bpt *in_breakpoint_table(unsigned long pc, unsigned long *offp); |
| 127 | static int do_step(struct pt_regs *); | 127 | static int do_step(struct pt_regs *); |
| 128 | static void bpt_cmds(void); | 128 | static void bpt_cmds(void); |
| 129 | static void cacheflush(void); | 129 | static void cacheflush(void); |
| 130 | static int cpu_cmd(void); | 130 | static int cpu_cmd(void); |
| 131 | static void csum(void); | 131 | static void csum(void); |
| 132 | static void bootcmds(void); | 132 | static void bootcmds(void); |
| 133 | void dump_segments(void); | 133 | void dump_segments(void); |
| 134 | static void symbol_lookup(void); | 134 | static void symbol_lookup(void); |
| 135 | static void xmon_print_symbol(unsigned long address, const char *mid, | 135 | static void xmon_print_symbol(unsigned long address, const char *mid, |
| 136 | const char *after); | 136 | const char *after); |
| 137 | static const char *getvecname(unsigned long vec); | 137 | static const char *getvecname(unsigned long vec); |
| 138 | 138 | ||
| 139 | static void debug_trace(void); | 139 | static void debug_trace(void); |
| 140 | 140 | ||
| 141 | extern int print_insn_powerpc(unsigned long, unsigned long, int); | 141 | extern int print_insn_powerpc(unsigned long, unsigned long, int); |
| 142 | extern void printf(const char *fmt, ...); | 142 | extern void printf(const char *fmt, ...); |
| 143 | extern void xmon_vfprintf(void *f, const char *fmt, va_list ap); | 143 | extern void xmon_vfprintf(void *f, const char *fmt, va_list ap); |
| 144 | extern int xmon_putc(int c, void *f); | 144 | extern int xmon_putc(int c, void *f); |
| 145 | extern int putchar(int ch); | 145 | extern int putchar(int ch); |
| 146 | extern int xmon_read_poll(void); | 146 | extern int xmon_read_poll(void); |
| 147 | extern int setjmp(long *); | 147 | extern int setjmp(long *); |
| 148 | extern void longjmp(long *, int); | 148 | extern void longjmp(long *, int); |
| 149 | extern unsigned long _ASR; | 149 | extern unsigned long _ASR; |
| 150 | 150 | ||
| 151 | #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) | 151 | #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) |
| 152 | 152 | ||
| 153 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ | 153 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ |
| 154 | || ('a' <= (c) && (c) <= 'f') \ | 154 | || ('a' <= (c) && (c) <= 'f') \ |
| 155 | || ('A' <= (c) && (c) <= 'F')) | 155 | || ('A' <= (c) && (c) <= 'F')) |
| 156 | #define isalnum(c) (('0' <= (c) && (c) <= '9') \ | 156 | #define isalnum(c) (('0' <= (c) && (c) <= '9') \ |
| 157 | || ('a' <= (c) && (c) <= 'z') \ | 157 | || ('a' <= (c) && (c) <= 'z') \ |
| 158 | || ('A' <= (c) && (c) <= 'Z')) | 158 | || ('A' <= (c) && (c) <= 'Z')) |
| 159 | #define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0) | 159 | #define isspace(c) (c == ' ' || c == '\t' || c == 10 || c == 13 || c == 0) |
| 160 | 160 | ||
| 161 | static char *help_string = "\ | 161 | static char *help_string = "\ |
| 162 | Commands:\n\ | 162 | Commands:\n\ |
| 163 | b show breakpoints\n\ | 163 | b show breakpoints\n\ |
| 164 | bd set data breakpoint\n\ | 164 | bd set data breakpoint\n\ |
| 165 | bi set instruction breakpoint\n\ | 165 | bi set instruction breakpoint\n\ |
| 166 | bc clear breakpoint\n" | 166 | bc clear breakpoint\n" |
| 167 | #ifdef CONFIG_SMP | 167 | #ifdef CONFIG_SMP |
| 168 | "\ | 168 | "\ |
| 169 | c print cpus stopped in xmon\n\ | 169 | c print cpus stopped in xmon\n\ |
| 170 | c# try to switch to cpu number h (in hex)\n" | 170 | c# try to switch to cpu number h (in hex)\n" |
| 171 | #endif | 171 | #endif |
| 172 | "\ | 172 | "\ |
| 173 | C checksum\n\ | 173 | C checksum\n\ |
| 174 | d dump bytes\n\ | 174 | d dump bytes\n\ |
| 175 | di dump instructions\n\ | 175 | di dump instructions\n\ |
| 176 | df dump float values\n\ | 176 | df dump float values\n\ |
| 177 | dd dump double values\n\ | 177 | dd dump double values\n\ |
| 178 | e print exception information\n\ | 178 | e print exception information\n\ |
| 179 | f flush cache\n\ | 179 | f flush cache\n\ |
| 180 | la lookup symbol+offset of specified address\n\ | 180 | la lookup symbol+offset of specified address\n\ |
| 181 | ls lookup address of specified symbol\n\ | 181 | ls lookup address of specified symbol\n\ |
| 182 | m examine/change memory\n\ | 182 | m examine/change memory\n\ |
| 183 | mm move a block of memory\n\ | 183 | mm move a block of memory\n\ |
| 184 | ms set a block of memory\n\ | 184 | ms set a block of memory\n\ |
| 185 | md compare two blocks of memory\n\ | 185 | md compare two blocks of memory\n\ |
| 186 | ml locate a block of memory\n\ | 186 | ml locate a block of memory\n\ |
| 187 | mz zero a block of memory\n\ | 187 | mz zero a block of memory\n\ |
| 188 | mi show information about memory allocation\n\ | 188 | mi show information about memory allocation\n\ |
| 189 | p show the task list\n\ | 189 | p show the task list\n\ |
| 190 | r print registers\n\ | 190 | r print registers\n\ |
| 191 | s single step\n\ | 191 | s single step\n\ |
| 192 | S print special registers\n\ | 192 | S print special registers\n\ |
| 193 | t print backtrace\n\ | 193 | t print backtrace\n\ |
| 194 | T Enable/Disable PPCDBG flags\n\ | 194 | T Enable/Disable PPCDBG flags\n\ |
| 195 | x exit monitor and recover\n\ | 195 | x exit monitor and recover\n\ |
| 196 | X exit monitor and dont recover\n\ | 196 | X exit monitor and dont recover\n\ |
| 197 | u dump segment table or SLB\n\ | 197 | u dump segment table or SLB\n\ |
| 198 | ? help\n" | 198 | ? help\n" |
| 199 | "\ | 199 | "\ |
| 200 | zr reboot\n\ | 200 | zr reboot\n\ |
| 201 | zh halt\n" | 201 | zh halt\n" |
| 202 | ; | 202 | ; |
| 203 | 203 | ||
| 204 | static struct pt_regs *xmon_regs; | 204 | static struct pt_regs *xmon_regs; |
| 205 | 205 | ||
| 206 | extern inline void sync(void) | 206 | extern inline void sync(void) |
| 207 | { | 207 | { |
| 208 | asm volatile("sync; isync"); | 208 | asm volatile("sync; isync"); |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | /* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs). | 211 | /* (Ref: 64-bit PowerPC ELF ABI Spplement; Ian Lance Taylor, Zembu Labs). |
| 212 | A PPC stack frame looks like this: | 212 | A PPC stack frame looks like this: |
| 213 | 213 | ||
| 214 | High Address | 214 | High Address |
| 215 | Back Chain | 215 | Back Chain |
| 216 | FP reg save area | 216 | FP reg save area |
| 217 | GP reg save area | 217 | GP reg save area |
| 218 | Local var space | 218 | Local var space |
| 219 | Parameter save area (SP+48) | 219 | Parameter save area (SP+48) |
| 220 | TOC save area (SP+40) | 220 | TOC save area (SP+40) |
| 221 | link editor doubleword (SP+32) | 221 | link editor doubleword (SP+32) |
| 222 | compiler doubleword (SP+24) | 222 | compiler doubleword (SP+24) |
| 223 | LR save (SP+16) | 223 | LR save (SP+16) |
| 224 | CR save (SP+8) | 224 | CR save (SP+8) |
| 225 | Back Chain (SP+0) | 225 | Back Chain (SP+0) |
| 226 | 226 | ||
| 227 | Note that the LR (ret addr) may not be saved in the current frame if | 227 | Note that the LR (ret addr) may not be saved in the current frame if |
| 228 | no functions have been called from the current function. | 228 | no functions have been called from the current function. |
| 229 | */ | 229 | */ |
| 230 | 230 | ||
| 231 | /* | 231 | /* |
| 232 | * Disable surveillance (the service processor watchdog function) | 232 | * Disable surveillance (the service processor watchdog function) |
| 233 | * while we are in xmon. | 233 | * while we are in xmon. |
| 234 | * XXX we should re-enable it when we leave. :) | 234 | * XXX we should re-enable it when we leave. :) |
| 235 | */ | 235 | */ |
| 236 | #define SURVEILLANCE_TOKEN 9000 | 236 | #define SURVEILLANCE_TOKEN 9000 |
| 237 | 237 | ||
| 238 | static inline void disable_surveillance(void) | 238 | static inline void disable_surveillance(void) |
| 239 | { | 239 | { |
| 240 | #ifdef CONFIG_PPC_PSERIES | 240 | #ifdef CONFIG_PPC_PSERIES |
| 241 | /* Since this can't be a module, args should end up below 4GB. */ | 241 | /* Since this can't be a module, args should end up below 4GB. */ |
| 242 | static struct rtas_args args; | 242 | static struct rtas_args args; |
| 243 | 243 | ||
| 244 | /* | 244 | /* |
| 245 | * At this point we have got all the cpus we can into | 245 | * At this point we have got all the cpus we can into |
| 246 | * xmon, so there is hopefully no other cpu calling RTAS | 246 | * xmon, so there is hopefully no other cpu calling RTAS |
| 247 | * at the moment, even though we don't take rtas.lock. | 247 | * at the moment, even though we don't take rtas.lock. |
| 248 | * If we did try to take rtas.lock there would be a | 248 | * If we did try to take rtas.lock there would be a |
| 249 | * real possibility of deadlock. | 249 | * real possibility of deadlock. |
| 250 | */ | 250 | */ |
| 251 | args.token = rtas_token("set-indicator"); | 251 | args.token = rtas_token("set-indicator"); |
| 252 | if (args.token == RTAS_UNKNOWN_SERVICE) | 252 | if (args.token == RTAS_UNKNOWN_SERVICE) |
| 253 | return; | 253 | return; |
| 254 | args.nargs = 3; | 254 | args.nargs = 3; |
| 255 | args.nret = 1; | 255 | args.nret = 1; |
| 256 | args.rets = &args.args[3]; | 256 | args.rets = &args.args[3]; |
| 257 | args.args[0] = SURVEILLANCE_TOKEN; | 257 | args.args[0] = SURVEILLANCE_TOKEN; |
| 258 | args.args[1] = 0; | 258 | args.args[1] = 0; |
| 259 | args.args[2] = 0; | 259 | args.args[2] = 0; |
| 260 | enter_rtas(__pa(&args)); | 260 | enter_rtas(__pa(&args)); |
| 261 | #endif /* CONFIG_PPC_PSERIES */ | 261 | #endif /* CONFIG_PPC_PSERIES */ |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | #ifdef CONFIG_SMP | 264 | #ifdef CONFIG_SMP |
| 265 | static int xmon_speaker; | 265 | static int xmon_speaker; |
| 266 | 266 | ||
| 267 | static void get_output_lock(void) | 267 | static void get_output_lock(void) |
| 268 | { | 268 | { |
| 269 | int me = smp_processor_id() + 0x100; | 269 | int me = smp_processor_id() + 0x100; |
| 270 | int last_speaker = 0, prev; | 270 | int last_speaker = 0, prev; |
| 271 | long timeout; | 271 | long timeout; |
| 272 | 272 | ||
| 273 | if (xmon_speaker == me) | 273 | if (xmon_speaker == me) |
| 274 | return; | 274 | return; |
| 275 | for (;;) { | 275 | for (;;) { |
| 276 | if (xmon_speaker == 0) { | 276 | if (xmon_speaker == 0) { |
| 277 | last_speaker = cmpxchg(&xmon_speaker, 0, me); | 277 | last_speaker = cmpxchg(&xmon_speaker, 0, me); |
| 278 | if (last_speaker == 0) | 278 | if (last_speaker == 0) |
| 279 | return; | 279 | return; |
| 280 | } | 280 | } |
| 281 | timeout = 10000000; | 281 | timeout = 10000000; |
| 282 | while (xmon_speaker == last_speaker) { | 282 | while (xmon_speaker == last_speaker) { |
| 283 | if (--timeout > 0) | 283 | if (--timeout > 0) |
| 284 | continue; | 284 | continue; |
| 285 | /* hostile takeover */ | 285 | /* hostile takeover */ |
| 286 | prev = cmpxchg(&xmon_speaker, last_speaker, me); | 286 | prev = cmpxchg(&xmon_speaker, last_speaker, me); |
| 287 | if (prev == last_speaker) | 287 | if (prev == last_speaker) |
| 288 | return; | 288 | return; |
| 289 | break; | 289 | break; |
| 290 | } | 290 | } |
| 291 | } | 291 | } |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | static void release_output_lock(void) | 294 | static void release_output_lock(void) |
| 295 | { | 295 | { |
| 296 | xmon_speaker = 0; | 296 | xmon_speaker = 0; |
| 297 | } | 297 | } |
| 298 | #endif | 298 | #endif |
| 299 | 299 | ||
| 300 | int xmon_core(struct pt_regs *regs, int fromipi) | 300 | int xmon_core(struct pt_regs *regs, int fromipi) |
| 301 | { | 301 | { |
| 302 | int cmd = 0; | 302 | int cmd = 0; |
| 303 | unsigned long msr; | 303 | unsigned long msr; |
| 304 | struct bpt *bp; | 304 | struct bpt *bp; |
| 305 | long recurse_jmp[JMP_BUF_LEN]; | 305 | long recurse_jmp[JMP_BUF_LEN]; |
| 306 | unsigned long offset; | 306 | unsigned long offset; |
| 307 | #ifdef CONFIG_SMP | 307 | #ifdef CONFIG_SMP |
| 308 | int cpu; | 308 | int cpu; |
| 309 | int secondary; | 309 | int secondary; |
| 310 | unsigned long timeout; | 310 | unsigned long timeout; |
| 311 | #endif | 311 | #endif |
| 312 | 312 | ||
| 313 | msr = get_msr(); | 313 | msr = get_msr(); |
| 314 | set_msrd(msr & ~MSR_EE); /* disable interrupts */ | 314 | set_msrd(msr & ~MSR_EE); /* disable interrupts */ |
| 315 | 315 | ||
| 316 | bp = in_breakpoint_table(regs->nip, &offset); | 316 | bp = in_breakpoint_table(regs->nip, &offset); |
| 317 | if (bp != NULL) { | 317 | if (bp != NULL) { |
| 318 | regs->nip = bp->address + offset; | 318 | regs->nip = bp->address + offset; |
| 319 | atomic_dec(&bp->ref_count); | 319 | atomic_dec(&bp->ref_count); |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | remove_cpu_bpts(); | 322 | remove_cpu_bpts(); |
| 323 | 323 | ||
| 324 | #ifdef CONFIG_SMP | 324 | #ifdef CONFIG_SMP |
| 325 | cpu = smp_processor_id(); | 325 | cpu = smp_processor_id(); |
| 326 | if (cpu_isset(cpu, cpus_in_xmon)) { | 326 | if (cpu_isset(cpu, cpus_in_xmon)) { |
| 327 | get_output_lock(); | 327 | get_output_lock(); |
| 328 | excprint(regs); | 328 | excprint(regs); |
| 329 | printf("cpu 0x%x: Exception %lx %s in xmon, " | 329 | printf("cpu 0x%x: Exception %lx %s in xmon, " |
| 330 | "returning to main loop\n", | 330 | "returning to main loop\n", |
| 331 | cpu, regs->trap, getvecname(TRAP(regs))); | 331 | cpu, regs->trap, getvecname(TRAP(regs))); |
| 332 | release_output_lock(); | 332 | release_output_lock(); |
| 333 | longjmp(xmon_fault_jmp[cpu], 1); | 333 | longjmp(xmon_fault_jmp[cpu], 1); |
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | if (setjmp(recurse_jmp) != 0) { | 336 | if (setjmp(recurse_jmp) != 0) { |
| 337 | if (!in_xmon || !xmon_gate) { | 337 | if (!in_xmon || !xmon_gate) { |
| 338 | get_output_lock(); | 338 | get_output_lock(); |
| 339 | printf("xmon: WARNING: bad recursive fault " | 339 | printf("xmon: WARNING: bad recursive fault " |
| 340 | "on cpu 0x%x\n", cpu); | 340 | "on cpu 0x%x\n", cpu); |
| 341 | release_output_lock(); | 341 | release_output_lock(); |
| 342 | goto waiting; | 342 | goto waiting; |
| 343 | } | 343 | } |
| 344 | secondary = !(xmon_taken && cpu == xmon_owner); | 344 | secondary = !(xmon_taken && cpu == xmon_owner); |
| 345 | goto cmdloop; | 345 | goto cmdloop; |
| 346 | } | 346 | } |
| 347 | 347 | ||
| 348 | xmon_fault_jmp[cpu] = recurse_jmp; | 348 | xmon_fault_jmp[cpu] = recurse_jmp; |
| 349 | cpu_set(cpu, cpus_in_xmon); | 349 | cpu_set(cpu, cpus_in_xmon); |
| 350 | 350 | ||
| 351 | bp = NULL; | 351 | bp = NULL; |
| 352 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) | 352 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) |
| 353 | bp = at_breakpoint(regs->nip); | 353 | bp = at_breakpoint(regs->nip); |
| 354 | if (bp || (regs->msr & MSR_RI) == 0) | 354 | if (bp || (regs->msr & MSR_RI) == 0) |
| 355 | fromipi = 0; | 355 | fromipi = 0; |
| 356 | 356 | ||
| 357 | if (!fromipi) { | 357 | if (!fromipi) { |
| 358 | get_output_lock(); | 358 | get_output_lock(); |
| 359 | excprint(regs); | 359 | excprint(regs); |
| 360 | if (bp) { | 360 | if (bp) { |
| 361 | printf("cpu 0x%x stopped at breakpoint 0x%x (", | 361 | printf("cpu 0x%x stopped at breakpoint 0x%x (", |
| 362 | cpu, BP_NUM(bp)); | 362 | cpu, BP_NUM(bp)); |
| 363 | xmon_print_symbol(regs->nip, " ", ")\n"); | 363 | xmon_print_symbol(regs->nip, " ", ")\n"); |
| 364 | } | 364 | } |
| 365 | if ((regs->msr & MSR_RI) == 0) | 365 | if ((regs->msr & MSR_RI) == 0) |
| 366 | printf("WARNING: exception is not recoverable, " | 366 | printf("WARNING: exception is not recoverable, " |
| 367 | "can't continue\n"); | 367 | "can't continue\n"); |
| 368 | release_output_lock(); | 368 | release_output_lock(); |
| 369 | } | 369 | } |
| 370 | 370 | ||
| 371 | waiting: | 371 | waiting: |
| 372 | secondary = 1; | 372 | secondary = 1; |
| 373 | while (secondary && !xmon_gate) { | 373 | while (secondary && !xmon_gate) { |
| 374 | if (in_xmon == 0) { | 374 | if (in_xmon == 0) { |
| 375 | if (fromipi) | 375 | if (fromipi) |
| 376 | goto leave; | 376 | goto leave; |
| 377 | secondary = test_and_set_bit(0, &in_xmon); | 377 | secondary = test_and_set_bit(0, &in_xmon); |
| 378 | } | 378 | } |
| 379 | barrier(); | 379 | barrier(); |
| 380 | } | 380 | } |
| 381 | 381 | ||
| 382 | if (!secondary && !xmon_gate) { | 382 | if (!secondary && !xmon_gate) { |
| 383 | /* we are the first cpu to come in */ | 383 | /* we are the first cpu to come in */ |
| 384 | /* interrupt other cpu(s) */ | 384 | /* interrupt other cpu(s) */ |
| 385 | int ncpus = num_online_cpus(); | 385 | int ncpus = num_online_cpus(); |
| 386 | 386 | ||
| 387 | xmon_owner = cpu; | 387 | xmon_owner = cpu; |
| 388 | mb(); | 388 | mb(); |
| 389 | if (ncpus > 1) { | 389 | if (ncpus > 1) { |
| 390 | smp_send_debugger_break(MSG_ALL_BUT_SELF); | 390 | smp_send_debugger_break(MSG_ALL_BUT_SELF); |
| 391 | /* wait for other cpus to come in */ | 391 | /* wait for other cpus to come in */ |
| 392 | for (timeout = 100000000; timeout != 0; --timeout) { | 392 | for (timeout = 100000000; timeout != 0; --timeout) { |
| 393 | if (cpus_weight(cpus_in_xmon) >= ncpus) | 393 | if (cpus_weight(cpus_in_xmon) >= ncpus) |
| 394 | break; | 394 | break; |
| 395 | barrier(); | 395 | barrier(); |
| 396 | } | 396 | } |
| 397 | } | 397 | } |
| 398 | remove_bpts(); | 398 | remove_bpts(); |
| 399 | disable_surveillance(); | 399 | disable_surveillance(); |
| 400 | /* for breakpoint or single step, print the current instr. */ | 400 | /* for breakpoint or single step, print the current instr. */ |
| 401 | if (bp || TRAP(regs) == 0xd00) | 401 | if (bp || TRAP(regs) == 0xd00) |
| 402 | ppc_inst_dump(regs->nip, 1, 0); | 402 | ppc_inst_dump(regs->nip, 1, 0); |
| 403 | printf("enter ? for help\n"); | 403 | printf("enter ? for help\n"); |
| 404 | mb(); | 404 | mb(); |
| 405 | xmon_gate = 1; | 405 | xmon_gate = 1; |
| 406 | barrier(); | 406 | barrier(); |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | cmdloop: | 409 | cmdloop: |
| 410 | while (in_xmon) { | 410 | while (in_xmon) { |
| 411 | if (secondary) { | 411 | if (secondary) { |
| 412 | if (cpu == xmon_owner) { | 412 | if (cpu == xmon_owner) { |
| 413 | if (!test_and_set_bit(0, &xmon_taken)) { | 413 | if (!test_and_set_bit(0, &xmon_taken)) { |
| 414 | secondary = 0; | 414 | secondary = 0; |
| 415 | continue; | 415 | continue; |
| 416 | } | 416 | } |
| 417 | /* missed it */ | 417 | /* missed it */ |
| 418 | while (cpu == xmon_owner) | 418 | while (cpu == xmon_owner) |
| 419 | barrier(); | 419 | barrier(); |
| 420 | } | 420 | } |
| 421 | barrier(); | 421 | barrier(); |
| 422 | } else { | 422 | } else { |
| 423 | cmd = cmds(regs); | 423 | cmd = cmds(regs); |
| 424 | if (cmd != 0) { | 424 | if (cmd != 0) { |
| 425 | /* exiting xmon */ | 425 | /* exiting xmon */ |
| 426 | insert_bpts(); | 426 | insert_bpts(); |
| 427 | xmon_gate = 0; | 427 | xmon_gate = 0; |
| 428 | wmb(); | 428 | wmb(); |
| 429 | in_xmon = 0; | 429 | in_xmon = 0; |
| 430 | break; | 430 | break; |
| 431 | } | 431 | } |
| 432 | /* have switched to some other cpu */ | 432 | /* have switched to some other cpu */ |
| 433 | secondary = 1; | 433 | secondary = 1; |
| 434 | } | 434 | } |
| 435 | } | 435 | } |
| 436 | leave: | 436 | leave: |
| 437 | cpu_clear(cpu, cpus_in_xmon); | 437 | cpu_clear(cpu, cpus_in_xmon); |
| 438 | xmon_fault_jmp[cpu] = NULL; | 438 | xmon_fault_jmp[cpu] = NULL; |
| 439 | 439 | ||
| 440 | #else | 440 | #else |
| 441 | /* UP is simple... */ | 441 | /* UP is simple... */ |
| 442 | if (in_xmon) { | 442 | if (in_xmon) { |
| 443 | printf("Exception %lx %s in xmon, returning to main loop\n", | 443 | printf("Exception %lx %s in xmon, returning to main loop\n", |
| 444 | regs->trap, getvecname(TRAP(regs))); | 444 | regs->trap, getvecname(TRAP(regs))); |
| 445 | longjmp(xmon_fault_jmp[0], 1); | 445 | longjmp(xmon_fault_jmp[0], 1); |
| 446 | } | 446 | } |
| 447 | if (setjmp(recurse_jmp) == 0) { | 447 | if (setjmp(recurse_jmp) == 0) { |
| 448 | xmon_fault_jmp[0] = recurse_jmp; | 448 | xmon_fault_jmp[0] = recurse_jmp; |
| 449 | in_xmon = 1; | 449 | in_xmon = 1; |
| 450 | 450 | ||
| 451 | excprint(regs); | 451 | excprint(regs); |
| 452 | bp = at_breakpoint(regs->nip); | 452 | bp = at_breakpoint(regs->nip); |
| 453 | if (bp) { | 453 | if (bp) { |
| 454 | printf("Stopped at breakpoint %x (", BP_NUM(bp)); | 454 | printf("Stopped at breakpoint %x (", BP_NUM(bp)); |
| 455 | xmon_print_symbol(regs->nip, " ", ")\n"); | 455 | xmon_print_symbol(regs->nip, " ", ")\n"); |
| 456 | } | 456 | } |
| 457 | if ((regs->msr & MSR_RI) == 0) | 457 | if ((regs->msr & MSR_RI) == 0) |
| 458 | printf("WARNING: exception is not recoverable, " | 458 | printf("WARNING: exception is not recoverable, " |
| 459 | "can't continue\n"); | 459 | "can't continue\n"); |
| 460 | remove_bpts(); | 460 | remove_bpts(); |
| 461 | disable_surveillance(); | 461 | disable_surveillance(); |
| 462 | /* for breakpoint or single step, print the current instr. */ | 462 | /* for breakpoint or single step, print the current instr. */ |
| 463 | if (bp || TRAP(regs) == 0xd00) | 463 | if (bp || TRAP(regs) == 0xd00) |
| 464 | ppc_inst_dump(regs->nip, 1, 0); | 464 | ppc_inst_dump(regs->nip, 1, 0); |
| 465 | printf("enter ? for help\n"); | 465 | printf("enter ? for help\n"); |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | cmd = cmds(regs); | 468 | cmd = cmds(regs); |
| 469 | 469 | ||
| 470 | insert_bpts(); | 470 | insert_bpts(); |
| 471 | in_xmon = 0; | 471 | in_xmon = 0; |
| 472 | #endif | 472 | #endif |
| 473 | 473 | ||
| 474 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { | 474 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { |
| 475 | bp = at_breakpoint(regs->nip); | 475 | bp = at_breakpoint(regs->nip); |
| 476 | if (bp != NULL) { | 476 | if (bp != NULL) { |
| 477 | int stepped = emulate_step(regs, bp->instr[0]); | 477 | int stepped = emulate_step(regs, bp->instr[0]); |
| 478 | if (stepped == 0) { | 478 | if (stepped == 0) { |
| 479 | regs->nip = (unsigned long) &bp->instr[0]; | 479 | regs->nip = (unsigned long) &bp->instr[0]; |
| 480 | atomic_inc(&bp->ref_count); | 480 | atomic_inc(&bp->ref_count); |
| 481 | } else if (stepped < 0) { | 481 | } else if (stepped < 0) { |
| 482 | printf("Couldn't single-step %s instruction\n", | 482 | printf("Couldn't single-step %s instruction\n", |
| 483 | (IS_RFID(bp->instr[0])? "rfid": "mtmsrd")); | 483 | (IS_RFID(bp->instr[0])? "rfid": "mtmsrd")); |
| 484 | } | 484 | } |
| 485 | } | 485 | } |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | insert_cpu_bpts(); | 488 | insert_cpu_bpts(); |
| 489 | 489 | ||
| 490 | set_msrd(msr); /* restore interrupt enable */ | 490 | set_msrd(msr); /* restore interrupt enable */ |
| 491 | 491 | ||
| 492 | return cmd != 'X'; | 492 | return cmd != 'X'; |
| 493 | } | 493 | } |
| 494 | 494 | ||
| 495 | int xmon(struct pt_regs *excp) | 495 | int xmon(struct pt_regs *excp) |
| 496 | { | 496 | { |
| 497 | struct pt_regs regs; | 497 | struct pt_regs regs; |
| 498 | 498 | ||
| 499 | if (excp == NULL) { | 499 | if (excp == NULL) { |
| 500 | /* Ok, grab regs as they are now. | 500 | /* Ok, grab regs as they are now. |
| 501 | This won't do a particularily good job because the | 501 | This won't do a particularily good job because the |
| 502 | prologue has already been executed. | 502 | prologue has already been executed. |
| 503 | ToDo: We could reach back into the callers save | 503 | ToDo: We could reach back into the callers save |
| 504 | area to do a better job of representing the | 504 | area to do a better job of representing the |
| 505 | caller's state. | 505 | caller's state. |
| 506 | */ | 506 | */ |
| 507 | asm volatile ("std 0,0(%0)\n\ | 507 | asm volatile ("std 0,0(%0)\n\ |
| 508 | std 1,8(%0)\n\ | 508 | std 1,8(%0)\n\ |
| 509 | std 2,16(%0)\n\ | 509 | std 2,16(%0)\n\ |
| 510 | std 3,24(%0)\n\ | 510 | std 3,24(%0)\n\ |
| 511 | std 4,32(%0)\n\ | 511 | std 4,32(%0)\n\ |
| 512 | std 5,40(%0)\n\ | 512 | std 5,40(%0)\n\ |
| 513 | std 6,48(%0)\n\ | 513 | std 6,48(%0)\n\ |
| 514 | std 7,56(%0)\n\ | 514 | std 7,56(%0)\n\ |
| 515 | std 8,64(%0)\n\ | 515 | std 8,64(%0)\n\ |
| 516 | std 9,72(%0)\n\ | 516 | std 9,72(%0)\n\ |
| 517 | std 10,80(%0)\n\ | 517 | std 10,80(%0)\n\ |
| 518 | std 11,88(%0)\n\ | 518 | std 11,88(%0)\n\ |
| 519 | std 12,96(%0)\n\ | 519 | std 12,96(%0)\n\ |
| 520 | std 13,104(%0)\n\ | 520 | std 13,104(%0)\n\ |
| 521 | std 14,112(%0)\n\ | 521 | std 14,112(%0)\n\ |
| 522 | std 15,120(%0)\n\ | 522 | std 15,120(%0)\n\ |
| 523 | std 16,128(%0)\n\ | 523 | std 16,128(%0)\n\ |
| 524 | std 17,136(%0)\n\ | 524 | std 17,136(%0)\n\ |
| 525 | std 18,144(%0)\n\ | 525 | std 18,144(%0)\n\ |
| 526 | std 19,152(%0)\n\ | 526 | std 19,152(%0)\n\ |
| 527 | std 20,160(%0)\n\ | 527 | std 20,160(%0)\n\ |
| 528 | std 21,168(%0)\n\ | 528 | std 21,168(%0)\n\ |
| 529 | std 22,176(%0)\n\ | 529 | std 22,176(%0)\n\ |
| 530 | std 23,184(%0)\n\ | 530 | std 23,184(%0)\n\ |
| 531 | std 24,192(%0)\n\ | 531 | std 24,192(%0)\n\ |
| 532 | std 25,200(%0)\n\ | 532 | std 25,200(%0)\n\ |
| 533 | std 26,208(%0)\n\ | 533 | std 26,208(%0)\n\ |
| 534 | std 27,216(%0)\n\ | 534 | std 27,216(%0)\n\ |
| 535 | std 28,224(%0)\n\ | 535 | std 28,224(%0)\n\ |
| 536 | std 29,232(%0)\n\ | 536 | std 29,232(%0)\n\ |
| 537 | std 30,240(%0)\n\ | 537 | std 30,240(%0)\n\ |
| 538 | std 31,248(%0)" : : "b" (®s)); | 538 | std 31,248(%0)" : : "b" (®s)); |
| 539 | 539 | ||
| 540 | regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2]; | 540 | regs.nip = regs.link = ((unsigned long *)(regs.gpr[1]))[2]; |
| 541 | regs.msr = get_msr(); | 541 | regs.msr = get_msr(); |
| 542 | regs.ctr = get_ctr(); | 542 | regs.ctr = get_ctr(); |
| 543 | regs.xer = get_xer(); | 543 | regs.xer = get_xer(); |
| 544 | regs.ccr = get_cr(); | 544 | regs.ccr = get_cr(); |
| 545 | regs.trap = 0; | 545 | regs.trap = 0; |
| 546 | excp = ®s; | 546 | excp = ®s; |
| 547 | } | 547 | } |
| 548 | return xmon_core(excp, 0); | 548 | return xmon_core(excp, 0); |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | int xmon_bpt(struct pt_regs *regs) | 551 | int xmon_bpt(struct pt_regs *regs) |
| 552 | { | 552 | { |
| 553 | struct bpt *bp; | 553 | struct bpt *bp; |
| 554 | unsigned long offset; | 554 | unsigned long offset; |
| 555 | 555 | ||
| 556 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) | 556 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) |
| 557 | return 0; | 557 | return 0; |
| 558 | 558 | ||
| 559 | /* Are we at the trap at bp->instr[1] for some bp? */ | 559 | /* Are we at the trap at bp->instr[1] for some bp? */ |
| 560 | bp = in_breakpoint_table(regs->nip, &offset); | 560 | bp = in_breakpoint_table(regs->nip, &offset); |
| 561 | if (bp != NULL && offset == 4) { | 561 | if (bp != NULL && offset == 4) { |
| 562 | regs->nip = bp->address + 4; | 562 | regs->nip = bp->address + 4; |
| 563 | atomic_dec(&bp->ref_count); | 563 | atomic_dec(&bp->ref_count); |
| 564 | return 1; | 564 | return 1; |
| 565 | } | 565 | } |
| 566 | 566 | ||
| 567 | /* Are we at a breakpoint? */ | 567 | /* Are we at a breakpoint? */ |
| 568 | bp = at_breakpoint(regs->nip); | 568 | bp = at_breakpoint(regs->nip); |
| 569 | if (!bp) | 569 | if (!bp) |
| 570 | return 0; | 570 | return 0; |
| 571 | 571 | ||
| 572 | xmon_core(regs, 0); | 572 | xmon_core(regs, 0); |
| 573 | 573 | ||
| 574 | return 1; | 574 | return 1; |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | int xmon_sstep(struct pt_regs *regs) | 577 | int xmon_sstep(struct pt_regs *regs) |
| 578 | { | 578 | { |
| 579 | if (user_mode(regs)) | 579 | if (user_mode(regs)) |
| 580 | return 0; | 580 | return 0; |
| 581 | xmon_core(regs, 0); | 581 | xmon_core(regs, 0); |
| 582 | return 1; | 582 | return 1; |
| 583 | } | 583 | } |
| 584 | 584 | ||
| 585 | int xmon_dabr_match(struct pt_regs *regs) | 585 | int xmon_dabr_match(struct pt_regs *regs) |
| 586 | { | 586 | { |
| 587 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) | 587 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) |
| 588 | return 0; | 588 | return 0; |
| 589 | xmon_core(regs, 0); | 589 | xmon_core(regs, 0); |
| 590 | return 1; | 590 | return 1; |
| 591 | } | 591 | } |
| 592 | 592 | ||
| 593 | int xmon_iabr_match(struct pt_regs *regs) | 593 | int xmon_iabr_match(struct pt_regs *regs) |
| 594 | { | 594 | { |
| 595 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) | 595 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF)) |
| 596 | return 0; | 596 | return 0; |
| 597 | if (iabr == 0) | 597 | if (iabr == 0) |
| 598 | return 0; | 598 | return 0; |
| 599 | xmon_core(regs, 0); | 599 | xmon_core(regs, 0); |
| 600 | return 1; | 600 | return 1; |
| 601 | } | 601 | } |
| 602 | 602 | ||
| 603 | int xmon_ipi(struct pt_regs *regs) | 603 | int xmon_ipi(struct pt_regs *regs) |
| 604 | { | 604 | { |
| 605 | #ifdef CONFIG_SMP | 605 | #ifdef CONFIG_SMP |
| 606 | if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon)) | 606 | if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon)) |
| 607 | xmon_core(regs, 1); | 607 | xmon_core(regs, 1); |
| 608 | #endif | 608 | #endif |
| 609 | return 0; | 609 | return 0; |
| 610 | } | 610 | } |
| 611 | 611 | ||
| 612 | int xmon_fault_handler(struct pt_regs *regs) | 612 | int xmon_fault_handler(struct pt_regs *regs) |
| 613 | { | 613 | { |
| 614 | struct bpt *bp; | 614 | struct bpt *bp; |
| 615 | unsigned long offset; | 615 | unsigned long offset; |
| 616 | 616 | ||
| 617 | if (in_xmon && catch_memory_errors) | 617 | if (in_xmon && catch_memory_errors) |
| 618 | handle_fault(regs); /* doesn't return */ | 618 | handle_fault(regs); /* doesn't return */ |
| 619 | 619 | ||
| 620 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { | 620 | if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) { |
| 621 | bp = in_breakpoint_table(regs->nip, &offset); | 621 | bp = in_breakpoint_table(regs->nip, &offset); |
| 622 | if (bp != NULL) { | 622 | if (bp != NULL) { |
| 623 | regs->nip = bp->address + offset; | 623 | regs->nip = bp->address + offset; |
| 624 | atomic_dec(&bp->ref_count); | 624 | atomic_dec(&bp->ref_count); |
| 625 | } | 625 | } |
| 626 | } | 626 | } |
| 627 | 627 | ||
| 628 | return 0; | 628 | return 0; |
| 629 | } | 629 | } |
| 630 | 630 | ||
| 631 | /* On systems with a hypervisor, we can't set the DABR | 631 | /* On systems with a hypervisor, we can't set the DABR |
| 632 | (data address breakpoint register) directly. */ | 632 | (data address breakpoint register) directly. */ |
| 633 | static void set_controlled_dabr(unsigned long val) | 633 | static void set_controlled_dabr(unsigned long val) |
| 634 | { | 634 | { |
| 635 | #ifdef CONFIG_PPC_PSERIES | 635 | #ifdef CONFIG_PPC_PSERIES |
| 636 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { | 636 | if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { |
| 637 | int rc = plpar_hcall_norets(H_SET_DABR, val); | 637 | int rc = plpar_hcall_norets(H_SET_DABR, val); |
| 638 | if (rc != H_Success) | 638 | if (rc != H_Success) |
| 639 | xmon_printf("Warning: setting DABR failed (%d)\n", rc); | 639 | xmon_printf("Warning: setting DABR failed (%d)\n", rc); |
| 640 | } else | 640 | } else |
| 641 | #endif | 641 | #endif |
| 642 | set_dabr(val); | 642 | set_dabr(val); |
| 643 | } | 643 | } |
| 644 | 644 | ||
| 645 | static struct bpt *at_breakpoint(unsigned long pc) | 645 | static struct bpt *at_breakpoint(unsigned long pc) |
| 646 | { | 646 | { |
| 647 | int i; | 647 | int i; |
| 648 | struct bpt *bp; | 648 | struct bpt *bp; |
| 649 | 649 | ||
| 650 | bp = bpts; | 650 | bp = bpts; |
| 651 | for (i = 0; i < NBPTS; ++i, ++bp) | 651 | for (i = 0; i < NBPTS; ++i, ++bp) |
| 652 | if (bp->enabled && pc == bp->address) | 652 | if (bp->enabled && pc == bp->address) |
| 653 | return bp; | 653 | return bp; |
| 654 | return NULL; | 654 | return NULL; |
| 655 | } | 655 | } |
| 656 | 656 | ||
| 657 | static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp) | 657 | static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp) |
| 658 | { | 658 | { |
| 659 | unsigned long off; | 659 | unsigned long off; |
| 660 | 660 | ||
| 661 | off = nip - (unsigned long) bpts; | 661 | off = nip - (unsigned long) bpts; |
| 662 | if (off >= sizeof(bpts)) | 662 | if (off >= sizeof(bpts)) |
| 663 | return NULL; | 663 | return NULL; |
| 664 | off %= sizeof(struct bpt); | 664 | off %= sizeof(struct bpt); |
| 665 | if (off != offsetof(struct bpt, instr[0]) | 665 | if (off != offsetof(struct bpt, instr[0]) |
| 666 | && off != offsetof(struct bpt, instr[1])) | 666 | && off != offsetof(struct bpt, instr[1])) |
| 667 | return NULL; | 667 | return NULL; |
| 668 | *offp = off - offsetof(struct bpt, instr[0]); | 668 | *offp = off - offsetof(struct bpt, instr[0]); |
| 669 | return (struct bpt *) (nip - off); | 669 | return (struct bpt *) (nip - off); |
| 670 | } | 670 | } |
| 671 | 671 | ||
| 672 | static struct bpt *new_breakpoint(unsigned long a) | 672 | static struct bpt *new_breakpoint(unsigned long a) |
| 673 | { | 673 | { |
| 674 | struct bpt *bp; | 674 | struct bpt *bp; |
| 675 | 675 | ||
| 676 | a &= ~3UL; | 676 | a &= ~3UL; |
| 677 | bp = at_breakpoint(a); | 677 | bp = at_breakpoint(a); |
| 678 | if (bp) | 678 | if (bp) |
| 679 | return bp; | 679 | return bp; |
| 680 | 680 | ||
| 681 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { | 681 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { |
| 682 | if (!bp->enabled && atomic_read(&bp->ref_count) == 0) { | 682 | if (!bp->enabled && atomic_read(&bp->ref_count) == 0) { |
| 683 | bp->address = a; | 683 | bp->address = a; |
| 684 | bp->instr[1] = bpinstr; | 684 | bp->instr[1] = bpinstr; |
| 685 | store_inst(&bp->instr[1]); | 685 | store_inst(&bp->instr[1]); |
| 686 | return bp; | 686 | return bp; |
| 687 | } | 687 | } |
| 688 | } | 688 | } |
| 689 | 689 | ||
| 690 | printf("Sorry, no free breakpoints. Please clear one first.\n"); | 690 | printf("Sorry, no free breakpoints. Please clear one first.\n"); |
| 691 | return NULL; | 691 | return NULL; |
| 692 | } | 692 | } |
| 693 | 693 | ||
| 694 | static void insert_bpts(void) | 694 | static void insert_bpts(void) |
| 695 | { | 695 | { |
| 696 | int i; | 696 | int i; |
| 697 | struct bpt *bp; | 697 | struct bpt *bp; |
| 698 | 698 | ||
| 699 | bp = bpts; | 699 | bp = bpts; |
| 700 | for (i = 0; i < NBPTS; ++i, ++bp) { | 700 | for (i = 0; i < NBPTS; ++i, ++bp) { |
| 701 | if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0) | 701 | if ((bp->enabled & (BP_TRAP|BP_IABR)) == 0) |
| 702 | continue; | 702 | continue; |
| 703 | if (mread(bp->address, &bp->instr[0], 4) != 4) { | 703 | if (mread(bp->address, &bp->instr[0], 4) != 4) { |
| 704 | printf("Couldn't read instruction at %lx, " | 704 | printf("Couldn't read instruction at %lx, " |
| 705 | "disabling breakpoint there\n", bp->address); | 705 | "disabling breakpoint there\n", bp->address); |
| 706 | bp->enabled = 0; | 706 | bp->enabled = 0; |
| 707 | continue; | 707 | continue; |
| 708 | } | 708 | } |
| 709 | if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) { | 709 | if (IS_MTMSRD(bp->instr[0]) || IS_RFID(bp->instr[0])) { |
| 710 | printf("Breakpoint at %lx is on an mtmsrd or rfid " | 710 | printf("Breakpoint at %lx is on an mtmsrd or rfid " |
| 711 | "instruction, disabling it\n", bp->address); | 711 | "instruction, disabling it\n", bp->address); |
| 712 | bp->enabled = 0; | 712 | bp->enabled = 0; |
| 713 | continue; | 713 | continue; |
| 714 | } | 714 | } |
| 715 | store_inst(&bp->instr[0]); | 715 | store_inst(&bp->instr[0]); |
| 716 | if (bp->enabled & BP_IABR) | 716 | if (bp->enabled & BP_IABR) |
| 717 | continue; | 717 | continue; |
| 718 | if (mwrite(bp->address, &bpinstr, 4) != 4) { | 718 | if (mwrite(bp->address, &bpinstr, 4) != 4) { |
| 719 | printf("Couldn't write instruction at %lx, " | 719 | printf("Couldn't write instruction at %lx, " |
| 720 | "disabling breakpoint there\n", bp->address); | 720 | "disabling breakpoint there\n", bp->address); |
| 721 | bp->enabled &= ~BP_TRAP; | 721 | bp->enabled &= ~BP_TRAP; |
| 722 | continue; | 722 | continue; |
| 723 | } | 723 | } |
| 724 | store_inst((void *)bp->address); | 724 | store_inst((void *)bp->address); |
| 725 | } | 725 | } |
| 726 | } | 726 | } |
| 727 | 727 | ||
| 728 | static void insert_cpu_bpts(void) | 728 | static void insert_cpu_bpts(void) |
| 729 | { | 729 | { |
| 730 | if (dabr.enabled) | 730 | if (dabr.enabled) |
| 731 | set_controlled_dabr(dabr.address | (dabr.enabled & 7)); | 731 | set_controlled_dabr(dabr.address | (dabr.enabled & 7)); |
| 732 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) | 732 | if (iabr && cpu_has_feature(CPU_FTR_IABR)) |
| 733 | set_iabr(iabr->address | 733 | set_iabr(iabr->address |
| 734 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); | 734 | | (iabr->enabled & (BP_IABR|BP_IABR_TE))); |
| 735 | } | 735 | } |
| 736 | 736 | ||
| 737 | static void remove_bpts(void) | 737 | static void remove_bpts(void) |
| 738 | { | 738 | { |
| 739 | int i; | 739 | int i; |
| 740 | struct bpt *bp; | 740 | struct bpt *bp; |
| 741 | unsigned instr; | 741 | unsigned instr; |
| 742 | 742 | ||
| 743 | bp = bpts; | 743 | bp = bpts; |
| 744 | for (i = 0; i < NBPTS; ++i, ++bp) { | 744 | for (i = 0; i < NBPTS; ++i, ++bp) { |
| 745 | if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP) | 745 | if ((bp->enabled & (BP_TRAP|BP_IABR)) != BP_TRAP) |
| 746 | continue; | 746 | continue; |
| 747 | if (mread(bp->address, &instr, 4) == 4 | 747 | if (mread(bp->address, &instr, 4) == 4 |
| 748 | && instr == bpinstr | 748 | && instr == bpinstr |
| 749 | && mwrite(bp->address, &bp->instr, 4) != 4) | 749 | && mwrite(bp->address, &bp->instr, 4) != 4) |
| 750 | printf("Couldn't remove breakpoint at %lx\n", | 750 | printf("Couldn't remove breakpoint at %lx\n", |
| 751 | bp->address); | 751 | bp->address); |
| 752 | else | 752 | else |
| 753 | store_inst((void *)bp->address); | 753 | store_inst((void *)bp->address); |
| 754 | } | 754 | } |
| 755 | } | 755 | } |
| 756 | 756 | ||
| 757 | static void remove_cpu_bpts(void) | 757 | static void remove_cpu_bpts(void) |
| 758 | { | 758 | { |
| 759 | set_controlled_dabr(0); | 759 | set_controlled_dabr(0); |
| 760 | if (cpu_has_feature(CPU_FTR_IABR)) | 760 | if (cpu_has_feature(CPU_FTR_IABR)) |
| 761 | set_iabr(0); | 761 | set_iabr(0); |
| 762 | } | 762 | } |
| 763 | 763 | ||
| 764 | /* Command interpreting routine */ | 764 | /* Command interpreting routine */ |
| 765 | static char *last_cmd; | 765 | static char *last_cmd; |
| 766 | 766 | ||
| 767 | static int | 767 | static int |
| 768 | cmds(struct pt_regs *excp) | 768 | cmds(struct pt_regs *excp) |
| 769 | { | 769 | { |
| 770 | int cmd = 0; | 770 | int cmd = 0; |
| 771 | 771 | ||
| 772 | last_cmd = NULL; | 772 | last_cmd = NULL; |
| 773 | xmon_regs = excp; | 773 | xmon_regs = excp; |
| 774 | for(;;) { | 774 | for(;;) { |
| 775 | #ifdef CONFIG_SMP | 775 | #ifdef CONFIG_SMP |
| 776 | printf("%x:", smp_processor_id()); | 776 | printf("%x:", smp_processor_id()); |
| 777 | #endif /* CONFIG_SMP */ | 777 | #endif /* CONFIG_SMP */ |
| 778 | printf("mon> "); | 778 | printf("mon> "); |
| 779 | fflush(stdout); | 779 | fflush(stdout); |
| 780 | flush_input(); | 780 | flush_input(); |
| 781 | termch = 0; | 781 | termch = 0; |
| 782 | cmd = skipbl(); | 782 | cmd = skipbl(); |
| 783 | if( cmd == '\n' ) { | 783 | if( cmd == '\n' ) { |
| 784 | if (last_cmd == NULL) | 784 | if (last_cmd == NULL) |
| 785 | continue; | 785 | continue; |
| 786 | take_input(last_cmd); | 786 | take_input(last_cmd); |
| 787 | last_cmd = NULL; | 787 | last_cmd = NULL; |
| 788 | cmd = inchar(); | 788 | cmd = inchar(); |
| 789 | } | 789 | } |
| 790 | switch (cmd) { | 790 | switch (cmd) { |
| 791 | case 'm': | 791 | case 'm': |
| 792 | cmd = inchar(); | 792 | cmd = inchar(); |
| 793 | switch (cmd) { | 793 | switch (cmd) { |
| 794 | case 'm': | 794 | case 'm': |
| 795 | case 's': | 795 | case 's': |
| 796 | case 'd': | 796 | case 'd': |
| 797 | memops(cmd); | 797 | memops(cmd); |
| 798 | break; | 798 | break; |
| 799 | case 'l': | 799 | case 'l': |
| 800 | memlocate(); | 800 | memlocate(); |
| 801 | break; | 801 | break; |
| 802 | case 'z': | 802 | case 'z': |
| 803 | memzcan(); | 803 | memzcan(); |
| 804 | break; | 804 | break; |
| 805 | case 'i': | 805 | case 'i': |
| 806 | show_mem(); | 806 | show_mem(); |
| 807 | break; | 807 | break; |
| 808 | default: | 808 | default: |
| 809 | termch = cmd; | 809 | termch = cmd; |
| 810 | memex(); | 810 | memex(); |
| 811 | } | 811 | } |
| 812 | break; | 812 | break; |
| 813 | case 'd': | 813 | case 'd': |
| 814 | dump(); | 814 | dump(); |
| 815 | break; | 815 | break; |
| 816 | case 'l': | 816 | case 'l': |
| 817 | symbol_lookup(); | 817 | symbol_lookup(); |
| 818 | break; | 818 | break; |
| 819 | case 'r': | 819 | case 'r': |
| 820 | prregs(excp); /* print regs */ | 820 | prregs(excp); /* print regs */ |
| 821 | break; | 821 | break; |
| 822 | case 'e': | 822 | case 'e': |
| 823 | excprint(excp); | 823 | excprint(excp); |
| 824 | break; | 824 | break; |
| 825 | case 'S': | 825 | case 'S': |
| 826 | super_regs(); | 826 | super_regs(); |
| 827 | break; | 827 | break; |
| 828 | case 't': | 828 | case 't': |
| 829 | backtrace(excp); | 829 | backtrace(excp); |
| 830 | break; | 830 | break; |
| 831 | case 'f': | 831 | case 'f': |
| 832 | cacheflush(); | 832 | cacheflush(); |
| 833 | break; | 833 | break; |
| 834 | case 's': | 834 | case 's': |
| 835 | if (do_step(excp)) | 835 | if (do_step(excp)) |
| 836 | return cmd; | 836 | return cmd; |
| 837 | break; | 837 | break; |
| 838 | case 'x': | 838 | case 'x': |
| 839 | case 'X': | 839 | case 'X': |
| 840 | case EOF: | 840 | case EOF: |
| 841 | return cmd; | 841 | return cmd; |
| 842 | case '?': | 842 | case '?': |
| 843 | printf(help_string); | 843 | printf(help_string); |
| 844 | break; | 844 | break; |
| 845 | case 'p': | 845 | case 'p': |
| 846 | show_state(); | 846 | show_state(); |
| 847 | break; | 847 | break; |
| 848 | case 'b': | 848 | case 'b': |
| 849 | bpt_cmds(); | 849 | bpt_cmds(); |
| 850 | break; | 850 | break; |
| 851 | case 'C': | 851 | case 'C': |
| 852 | csum(); | 852 | csum(); |
| 853 | break; | 853 | break; |
| 854 | case 'c': | 854 | case 'c': |
| 855 | if (cpu_cmd()) | 855 | if (cpu_cmd()) |
| 856 | return 0; | 856 | return 0; |
| 857 | break; | 857 | break; |
| 858 | case 'z': | 858 | case 'z': |
| 859 | bootcmds(); | 859 | bootcmds(); |
| 860 | break; | 860 | break; |
| 861 | case 'T': | 861 | case 'T': |
| 862 | debug_trace(); | 862 | debug_trace(); |
| 863 | break; | 863 | break; |
| 864 | case 'u': | 864 | case 'u': |
| 865 | dump_segments(); | 865 | dump_segments(); |
| 866 | break; | 866 | break; |
| 867 | default: | 867 | default: |
| 868 | printf("Unrecognized command: "); | 868 | printf("Unrecognized command: "); |
| 869 | do { | 869 | do { |
| 870 | if (' ' < cmd && cmd <= '~') | 870 | if (' ' < cmd && cmd <= '~') |
| 871 | putchar(cmd); | 871 | putchar(cmd); |
| 872 | else | 872 | else |
| 873 | printf("\\x%x", cmd); | 873 | printf("\\x%x", cmd); |
| 874 | cmd = inchar(); | 874 | cmd = inchar(); |
| 875 | } while (cmd != '\n'); | 875 | } while (cmd != '\n'); |
| 876 | printf(" (type ? for help)\n"); | 876 | printf(" (type ? for help)\n"); |
| 877 | break; | 877 | break; |
| 878 | } | 878 | } |
| 879 | } | 879 | } |
| 880 | } | 880 | } |
| 881 | 881 | ||
| 882 | /* | 882 | /* |
| 883 | * Step a single instruction. | 883 | * Step a single instruction. |
| 884 | * Some instructions we emulate, others we execute with MSR_SE set. | 884 | * Some instructions we emulate, others we execute with MSR_SE set. |
| 885 | */ | 885 | */ |
| 886 | static int do_step(struct pt_regs *regs) | 886 | static int do_step(struct pt_regs *regs) |
| 887 | { | 887 | { |
| 888 | unsigned int instr; | 888 | unsigned int instr; |
| 889 | int stepped; | 889 | int stepped; |
| 890 | 890 | ||
| 891 | /* check we are in 64-bit kernel mode, translation enabled */ | 891 | /* check we are in 64-bit kernel mode, translation enabled */ |
| 892 | if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) { | 892 | if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) { |
| 893 | if (mread(regs->nip, &instr, 4) == 4) { | 893 | if (mread(regs->nip, &instr, 4) == 4) { |
| 894 | stepped = emulate_step(regs, instr); | 894 | stepped = emulate_step(regs, instr); |
| 895 | if (stepped < 0) { | 895 | if (stepped < 0) { |
| 896 | printf("Couldn't single-step %s instruction\n", | 896 | printf("Couldn't single-step %s instruction\n", |
| 897 | (IS_RFID(instr)? "rfid": "mtmsrd")); | 897 | (IS_RFID(instr)? "rfid": "mtmsrd")); |
| 898 | return 0; | 898 | return 0; |
| 899 | } | 899 | } |
| 900 | if (stepped > 0) { | 900 | if (stepped > 0) { |
| 901 | regs->trap = 0xd00 | (regs->trap & 1); | 901 | regs->trap = 0xd00 | (regs->trap & 1); |
| 902 | printf("stepped to "); | 902 | printf("stepped to "); |
| 903 | xmon_print_symbol(regs->nip, " ", "\n"); | 903 | xmon_print_symbol(regs->nip, " ", "\n"); |
| 904 | ppc_inst_dump(regs->nip, 1, 0); | 904 | ppc_inst_dump(regs->nip, 1, 0); |
| 905 | return 0; | 905 | return 0; |
| 906 | } | 906 | } |
| 907 | } | 907 | } |
| 908 | } | 908 | } |
| 909 | regs->msr |= MSR_SE; | 909 | regs->msr |= MSR_SE; |
| 910 | return 1; | 910 | return 1; |
| 911 | } | 911 | } |
| 912 | 912 | ||
| 913 | static void bootcmds(void) | 913 | static void bootcmds(void) |
| 914 | { | 914 | { |
| 915 | int cmd; | 915 | int cmd; |
| 916 | 916 | ||
| 917 | cmd = inchar(); | 917 | cmd = inchar(); |
| 918 | if (cmd == 'r') | 918 | if (cmd == 'r') |
| 919 | ppc_md.restart(NULL); | 919 | ppc_md.restart(NULL); |
| 920 | else if (cmd == 'h') | 920 | else if (cmd == 'h') |
| 921 | ppc_md.halt(); | 921 | ppc_md.halt(); |
| 922 | else if (cmd == 'p') | 922 | else if (cmd == 'p') |
| 923 | ppc_md.power_off(); | 923 | ppc_md.power_off(); |
| 924 | } | 924 | } |
| 925 | 925 | ||
| 926 | static int cpu_cmd(void) | 926 | static int cpu_cmd(void) |
| 927 | { | 927 | { |
| 928 | #ifdef CONFIG_SMP | 928 | #ifdef CONFIG_SMP |
| 929 | unsigned long cpu; | 929 | unsigned long cpu; |
| 930 | int timeout; | 930 | int timeout; |
| 931 | int count; | 931 | int count; |
| 932 | 932 | ||
| 933 | if (!scanhex(&cpu)) { | 933 | if (!scanhex(&cpu)) { |
| 934 | /* print cpus waiting or in xmon */ | 934 | /* print cpus waiting or in xmon */ |
| 935 | printf("cpus stopped:"); | 935 | printf("cpus stopped:"); |
| 936 | count = 0; | 936 | count = 0; |
| 937 | for (cpu = 0; cpu < NR_CPUS; ++cpu) { | 937 | for (cpu = 0; cpu < NR_CPUS; ++cpu) { |
| 938 | if (cpu_isset(cpu, cpus_in_xmon)) { | 938 | if (cpu_isset(cpu, cpus_in_xmon)) { |
| 939 | if (count == 0) | 939 | if (count == 0) |
| 940 | printf(" %x", cpu); | 940 | printf(" %x", cpu); |
| 941 | ++count; | 941 | ++count; |
| 942 | } else { | 942 | } else { |
| 943 | if (count > 1) | 943 | if (count > 1) |
| 944 | printf("-%x", cpu - 1); | 944 | printf("-%x", cpu - 1); |
| 945 | count = 0; | 945 | count = 0; |
| 946 | } | 946 | } |
| 947 | } | 947 | } |
| 948 | if (count > 1) | 948 | if (count > 1) |
| 949 | printf("-%x", NR_CPUS - 1); | 949 | printf("-%x", NR_CPUS - 1); |
| 950 | printf("\n"); | 950 | printf("\n"); |
| 951 | return 0; | 951 | return 0; |
| 952 | } | 952 | } |
| 953 | /* try to switch to cpu specified */ | 953 | /* try to switch to cpu specified */ |
| 954 | if (!cpu_isset(cpu, cpus_in_xmon)) { | 954 | if (!cpu_isset(cpu, cpus_in_xmon)) { |
| 955 | printf("cpu 0x%x isn't in xmon\n", cpu); | 955 | printf("cpu 0x%x isn't in xmon\n", cpu); |
| 956 | return 0; | 956 | return 0; |
| 957 | } | 957 | } |
| 958 | xmon_taken = 0; | 958 | xmon_taken = 0; |
| 959 | mb(); | 959 | mb(); |
| 960 | xmon_owner = cpu; | 960 | xmon_owner = cpu; |
| 961 | timeout = 10000000; | 961 | timeout = 10000000; |
| 962 | while (!xmon_taken) { | 962 | while (!xmon_taken) { |
| 963 | if (--timeout == 0) { | 963 | if (--timeout == 0) { |
| 964 | if (test_and_set_bit(0, &xmon_taken)) | 964 | if (test_and_set_bit(0, &xmon_taken)) |
| 965 | break; | 965 | break; |
| 966 | /* take control back */ | 966 | /* take control back */ |
| 967 | mb(); | 967 | mb(); |
| 968 | xmon_owner = smp_processor_id(); | 968 | xmon_owner = smp_processor_id(); |
| 969 | printf("cpu %u didn't take control\n", cpu); | 969 | printf("cpu %u didn't take control\n", cpu); |
| 970 | return 0; | 970 | return 0; |
| 971 | } | 971 | } |
| 972 | barrier(); | 972 | barrier(); |
| 973 | } | 973 | } |
| 974 | return 1; | 974 | return 1; |
| 975 | #else | 975 | #else |
| 976 | return 0; | 976 | return 0; |
| 977 | #endif /* CONFIG_SMP */ | 977 | #endif /* CONFIG_SMP */ |
| 978 | } | 978 | } |
| 979 | 979 | ||
| 980 | static unsigned short fcstab[256] = { | 980 | static unsigned short fcstab[256] = { |
| 981 | 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, | 981 | 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, |
| 982 | 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, | 982 | 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, |
| 983 | 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, | 983 | 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, |
| 984 | 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, | 984 | 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, |
| 985 | 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, | 985 | 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, |
| 986 | 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, | 986 | 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, |
| 987 | 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, | 987 | 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, |
| 988 | 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, | 988 | 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, |
| 989 | 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, | 989 | 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, |
| 990 | 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, | 990 | 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, |
| 991 | 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, | 991 | 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, |
| 992 | 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, | 992 | 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, |
| 993 | 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, | 993 | 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, |
| 994 | 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, | 994 | 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, |
| 995 | 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, | 995 | 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, |
| 996 | 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, | 996 | 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, |
| 997 | 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, | 997 | 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, |
| 998 | 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, | 998 | 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, |
| 999 | 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, | 999 | 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, |
| 1000 | 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, | 1000 | 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, |
| 1001 | 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, | 1001 | 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, |
| 1002 | 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, | 1002 | 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, |
| 1003 | 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, | 1003 | 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, |
| 1004 | 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, | 1004 | 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, |
| 1005 | 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, | 1005 | 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, |
| 1006 | 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, | 1006 | 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, |
| 1007 | 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, | 1007 | 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, |
| 1008 | 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, | 1008 | 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, |
| 1009 | 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, | 1009 | 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, |
| 1010 | 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, | 1010 | 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, |
| 1011 | 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, | 1011 | 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, |
| 1012 | 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 | 1012 | 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 |
| 1013 | }; | 1013 | }; |
| 1014 | 1014 | ||
| 1015 | #define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) | 1015 | #define FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) |
| 1016 | 1016 | ||
| 1017 | static void | 1017 | static void |
| 1018 | csum(void) | 1018 | csum(void) |
| 1019 | { | 1019 | { |
| 1020 | unsigned int i; | 1020 | unsigned int i; |
| 1021 | unsigned short fcs; | 1021 | unsigned short fcs; |
| 1022 | unsigned char v; | 1022 | unsigned char v; |
| 1023 | 1023 | ||
| 1024 | if (!scanhex(&adrs)) | 1024 | if (!scanhex(&adrs)) |
| 1025 | return; | 1025 | return; |
| 1026 | if (!scanhex(&ncsum)) | 1026 | if (!scanhex(&ncsum)) |
| 1027 | return; | 1027 | return; |
| 1028 | fcs = 0xffff; | 1028 | fcs = 0xffff; |
| 1029 | for (i = 0; i < ncsum; ++i) { | 1029 | for (i = 0; i < ncsum; ++i) { |
| 1030 | if (mread(adrs+i, &v, 1) == 0) { | 1030 | if (mread(adrs+i, &v, 1) == 0) { |
| 1031 | printf("csum stopped at %x\n", adrs+i); | 1031 | printf("csum stopped at %x\n", adrs+i); |
| 1032 | break; | 1032 | break; |
| 1033 | } | 1033 | } |
| 1034 | fcs = FCS(fcs, v); | 1034 | fcs = FCS(fcs, v); |
| 1035 | } | 1035 | } |
| 1036 | printf("%x\n", fcs); | 1036 | printf("%x\n", fcs); |
| 1037 | } | 1037 | } |
| 1038 | 1038 | ||
| 1039 | /* | 1039 | /* |
| 1040 | * Check if this is a suitable place to put a breakpoint. | 1040 | * Check if this is a suitable place to put a breakpoint. |
| 1041 | */ | 1041 | */ |
| 1042 | static long check_bp_loc(unsigned long addr) | 1042 | static long check_bp_loc(unsigned long addr) |
| 1043 | { | 1043 | { |
| 1044 | unsigned int instr; | 1044 | unsigned int instr; |
| 1045 | 1045 | ||
| 1046 | addr &= ~3; | 1046 | addr &= ~3; |
| 1047 | if (addr < KERNELBASE) { | 1047 | if (addr < KERNELBASE) { |
| 1048 | printf("Breakpoints may only be placed at kernel addresses\n"); | 1048 | printf("Breakpoints may only be placed at kernel addresses\n"); |
| 1049 | return 0; | 1049 | return 0; |
| 1050 | } | 1050 | } |
| 1051 | if (!mread(addr, &instr, sizeof(instr))) { | 1051 | if (!mread(addr, &instr, sizeof(instr))) { |
| 1052 | printf("Can't read instruction at address %lx\n", addr); | 1052 | printf("Can't read instruction at address %lx\n", addr); |
| 1053 | return 0; | 1053 | return 0; |
| 1054 | } | 1054 | } |
| 1055 | if (IS_MTMSRD(instr) || IS_RFID(instr)) { | 1055 | if (IS_MTMSRD(instr) || IS_RFID(instr)) { |
| 1056 | printf("Breakpoints may not be placed on mtmsrd or rfid " | 1056 | printf("Breakpoints may not be placed on mtmsrd or rfid " |
| 1057 | "instructions\n"); | 1057 | "instructions\n"); |
| 1058 | return 0; | 1058 | return 0; |
| 1059 | } | 1059 | } |
| 1060 | return 1; | 1060 | return 1; |
| 1061 | } | 1061 | } |
| 1062 | 1062 | ||
| 1063 | static char *breakpoint_help_string = | 1063 | static char *breakpoint_help_string = |
| 1064 | "Breakpoint command usage:\n" | 1064 | "Breakpoint command usage:\n" |
| 1065 | "b show breakpoints\n" | 1065 | "b show breakpoints\n" |
| 1066 | "b <addr> [cnt] set breakpoint at given instr addr\n" | 1066 | "b <addr> [cnt] set breakpoint at given instr addr\n" |
| 1067 | "bc clear all breakpoints\n" | 1067 | "bc clear all breakpoints\n" |
| 1068 | "bc <n/addr> clear breakpoint number n or at addr\n" | 1068 | "bc <n/addr> clear breakpoint number n or at addr\n" |
| 1069 | "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n" | 1069 | "bi <addr> [cnt] set hardware instr breakpoint (POWER3/RS64 only)\n" |
| 1070 | "bd <addr> [cnt] set hardware data breakpoint\n" | 1070 | "bd <addr> [cnt] set hardware data breakpoint\n" |
| 1071 | ""; | 1071 | ""; |
| 1072 | 1072 | ||
| 1073 | static void | 1073 | static void |
| 1074 | bpt_cmds(void) | 1074 | bpt_cmds(void) |
| 1075 | { | 1075 | { |
| 1076 | int cmd; | 1076 | int cmd; |
| 1077 | unsigned long a; | 1077 | unsigned long a; |
| 1078 | int mode, i; | 1078 | int mode, i; |
| 1079 | struct bpt *bp; | 1079 | struct bpt *bp; |
| 1080 | const char badaddr[] = "Only kernel addresses are permitted " | 1080 | const char badaddr[] = "Only kernel addresses are permitted " |
| 1081 | "for breakpoints\n"; | 1081 | "for breakpoints\n"; |
| 1082 | 1082 | ||
| 1083 | cmd = inchar(); | 1083 | cmd = inchar(); |
| 1084 | switch (cmd) { | 1084 | switch (cmd) { |
| 1085 | case 'd': /* bd - hardware data breakpoint */ | 1085 | case 'd': /* bd - hardware data breakpoint */ |
| 1086 | mode = 7; | 1086 | mode = 7; |
| 1087 | cmd = inchar(); | 1087 | cmd = inchar(); |
| 1088 | if (cmd == 'r') | 1088 | if (cmd == 'r') |
| 1089 | mode = 5; | 1089 | mode = 5; |
| 1090 | else if (cmd == 'w') | 1090 | else if (cmd == 'w') |
| 1091 | mode = 6; | 1091 | mode = 6; |
| 1092 | else | 1092 | else |
| 1093 | termch = cmd; | 1093 | termch = cmd; |
| 1094 | dabr.address = 0; | 1094 | dabr.address = 0; |
| 1095 | dabr.enabled = 0; | 1095 | dabr.enabled = 0; |
| 1096 | if (scanhex(&dabr.address)) { | 1096 | if (scanhex(&dabr.address)) { |
| 1097 | if (dabr.address < KERNELBASE) { | 1097 | if (dabr.address < KERNELBASE) { |
| 1098 | printf(badaddr); | 1098 | printf(badaddr); |
| 1099 | break; | 1099 | break; |
| 1100 | } | 1100 | } |
| 1101 | dabr.address &= ~7; | 1101 | dabr.address &= ~7; |
| 1102 | dabr.enabled = mode | BP_DABR; | 1102 | dabr.enabled = mode | BP_DABR; |
| 1103 | } | 1103 | } |
| 1104 | break; | 1104 | break; |
| 1105 | 1105 | ||
| 1106 | case 'i': /* bi - hardware instr breakpoint */ | 1106 | case 'i': /* bi - hardware instr breakpoint */ |
| 1107 | if (!cpu_has_feature(CPU_FTR_IABR)) { | 1107 | if (!cpu_has_feature(CPU_FTR_IABR)) { |
| 1108 | printf("Hardware instruction breakpoint " | 1108 | printf("Hardware instruction breakpoint " |
| 1109 | "not supported on this cpu\n"); | 1109 | "not supported on this cpu\n"); |
| 1110 | break; | 1110 | break; |
| 1111 | } | 1111 | } |
| 1112 | if (iabr) { | 1112 | if (iabr) { |
| 1113 | iabr->enabled &= ~(BP_IABR | BP_IABR_TE); | 1113 | iabr->enabled &= ~(BP_IABR | BP_IABR_TE); |
| 1114 | iabr = NULL; | 1114 | iabr = NULL; |
| 1115 | } | 1115 | } |
| 1116 | if (!scanhex(&a)) | 1116 | if (!scanhex(&a)) |
| 1117 | break; | 1117 | break; |
| 1118 | if (!check_bp_loc(a)) | 1118 | if (!check_bp_loc(a)) |
| 1119 | break; | 1119 | break; |
| 1120 | bp = new_breakpoint(a); | 1120 | bp = new_breakpoint(a); |
| 1121 | if (bp != NULL) { | 1121 | if (bp != NULL) { |
| 1122 | bp->enabled |= BP_IABR | BP_IABR_TE; | 1122 | bp->enabled |= BP_IABR | BP_IABR_TE; |
| 1123 | iabr = bp; | 1123 | iabr = bp; |
| 1124 | } | 1124 | } |
| 1125 | break; | 1125 | break; |
| 1126 | 1126 | ||
| 1127 | case 'c': | 1127 | case 'c': |
| 1128 | if (!scanhex(&a)) { | 1128 | if (!scanhex(&a)) { |
| 1129 | /* clear all breakpoints */ | 1129 | /* clear all breakpoints */ |
| 1130 | for (i = 0; i < NBPTS; ++i) | 1130 | for (i = 0; i < NBPTS; ++i) |
| 1131 | bpts[i].enabled = 0; | 1131 | bpts[i].enabled = 0; |
| 1132 | iabr = NULL; | 1132 | iabr = NULL; |
| 1133 | dabr.enabled = 0; | 1133 | dabr.enabled = 0; |
| 1134 | printf("All breakpoints cleared\n"); | 1134 | printf("All breakpoints cleared\n"); |
| 1135 | break; | 1135 | break; |
| 1136 | } | 1136 | } |
| 1137 | 1137 | ||
| 1138 | if (a <= NBPTS && a >= 1) { | 1138 | if (a <= NBPTS && a >= 1) { |
| 1139 | /* assume a breakpoint number */ | 1139 | /* assume a breakpoint number */ |
| 1140 | bp = &bpts[a-1]; /* bp nums are 1 based */ | 1140 | bp = &bpts[a-1]; /* bp nums are 1 based */ |
| 1141 | } else { | 1141 | } else { |
| 1142 | /* assume a breakpoint address */ | 1142 | /* assume a breakpoint address */ |
| 1143 | bp = at_breakpoint(a); | 1143 | bp = at_breakpoint(a); |
| 1144 | if (bp == 0) { | 1144 | if (bp == 0) { |
| 1145 | printf("No breakpoint at %x\n", a); | 1145 | printf("No breakpoint at %x\n", a); |
| 1146 | break; | 1146 | break; |
| 1147 | } | 1147 | } |
| 1148 | } | 1148 | } |
| 1149 | 1149 | ||
| 1150 | printf("Cleared breakpoint %x (", BP_NUM(bp)); | 1150 | printf("Cleared breakpoint %x (", BP_NUM(bp)); |
| 1151 | xmon_print_symbol(bp->address, " ", ")\n"); | 1151 | xmon_print_symbol(bp->address, " ", ")\n"); |
| 1152 | bp->enabled = 0; | 1152 | bp->enabled = 0; |
| 1153 | break; | 1153 | break; |
| 1154 | 1154 | ||
| 1155 | default: | 1155 | default: |
| 1156 | termch = cmd; | 1156 | termch = cmd; |
| 1157 | cmd = skipbl(); | 1157 | cmd = skipbl(); |
| 1158 | if (cmd == '?') { | 1158 | if (cmd == '?') { |
| 1159 | printf(breakpoint_help_string); | 1159 | printf(breakpoint_help_string); |
| 1160 | break; | 1160 | break; |
| 1161 | } | 1161 | } |
| 1162 | termch = cmd; | 1162 | termch = cmd; |
| 1163 | if (!scanhex(&a)) { | 1163 | if (!scanhex(&a)) { |
| 1164 | /* print all breakpoints */ | 1164 | /* print all breakpoints */ |
| 1165 | printf(" type address\n"); | 1165 | printf(" type address\n"); |
| 1166 | if (dabr.enabled) { | 1166 | if (dabr.enabled) { |
| 1167 | printf(" data %.16lx [", dabr.address); | 1167 | printf(" data %.16lx [", dabr.address); |
| 1168 | if (dabr.enabled & 1) | 1168 | if (dabr.enabled & 1) |
| 1169 | printf("r"); | 1169 | printf("r"); |
| 1170 | if (dabr.enabled & 2) | 1170 | if (dabr.enabled & 2) |
| 1171 | printf("w"); | 1171 | printf("w"); |
| 1172 | printf("]\n"); | 1172 | printf("]\n"); |
| 1173 | } | 1173 | } |
| 1174 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { | 1174 | for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { |
| 1175 | if (!bp->enabled) | 1175 | if (!bp->enabled) |
| 1176 | continue; | 1176 | continue; |
| 1177 | printf("%2x %s ", BP_NUM(bp), | 1177 | printf("%2x %s ", BP_NUM(bp), |
| 1178 | (bp->enabled & BP_IABR)? "inst": "trap"); | 1178 | (bp->enabled & BP_IABR)? "inst": "trap"); |
| 1179 | xmon_print_symbol(bp->address, " ", "\n"); | 1179 | xmon_print_symbol(bp->address, " ", "\n"); |
| 1180 | } | 1180 | } |
| 1181 | break; | 1181 | break; |
| 1182 | } | 1182 | } |
| 1183 | 1183 | ||
| 1184 | if (!check_bp_loc(a)) | 1184 | if (!check_bp_loc(a)) |
| 1185 | break; | 1185 | break; |
| 1186 | bp = new_breakpoint(a); | 1186 | bp = new_breakpoint(a); |
| 1187 | if (bp != NULL) | 1187 | if (bp != NULL) |
| 1188 | bp->enabled |= BP_TRAP; | 1188 | bp->enabled |= BP_TRAP; |
| 1189 | break; | 1189 | break; |
| 1190 | } | 1190 | } |
| 1191 | } | 1191 | } |
| 1192 | 1192 | ||
| 1193 | /* Very cheap human name for vector lookup. */ | 1193 | /* Very cheap human name for vector lookup. */ |
| 1194 | static | 1194 | static |
| 1195 | const char *getvecname(unsigned long vec) | 1195 | const char *getvecname(unsigned long vec) |
| 1196 | { | 1196 | { |
| 1197 | char *ret; | 1197 | char *ret; |
| 1198 | 1198 | ||
| 1199 | switch (vec) { | 1199 | switch (vec) { |
| 1200 | case 0x100: ret = "(System Reset)"; break; | 1200 | case 0x100: ret = "(System Reset)"; break; |
| 1201 | case 0x200: ret = "(Machine Check)"; break; | 1201 | case 0x200: ret = "(Machine Check)"; break; |
| 1202 | case 0x300: ret = "(Data Access)"; break; | 1202 | case 0x300: ret = "(Data Access)"; break; |
| 1203 | case 0x380: ret = "(Data SLB Access)"; break; | 1203 | case 0x380: ret = "(Data SLB Access)"; break; |
| 1204 | case 0x400: ret = "(Instruction Access)"; break; | 1204 | case 0x400: ret = "(Instruction Access)"; break; |
| 1205 | case 0x480: ret = "(Instruction SLB Access)"; break; | 1205 | case 0x480: ret = "(Instruction SLB Access)"; break; |
| 1206 | case 0x500: ret = "(Hardware Interrupt)"; break; | 1206 | case 0x500: ret = "(Hardware Interrupt)"; break; |
| 1207 | case 0x600: ret = "(Alignment)"; break; | 1207 | case 0x600: ret = "(Alignment)"; break; |
| 1208 | case 0x700: ret = "(Program Check)"; break; | 1208 | case 0x700: ret = "(Program Check)"; break; |
| 1209 | case 0x800: ret = "(FPU Unavailable)"; break; | 1209 | case 0x800: ret = "(FPU Unavailable)"; break; |
| 1210 | case 0x900: ret = "(Decrementer)"; break; | 1210 | case 0x900: ret = "(Decrementer)"; break; |
| 1211 | case 0xc00: ret = "(System Call)"; break; | 1211 | case 0xc00: ret = "(System Call)"; break; |
| 1212 | case 0xd00: ret = "(Single Step)"; break; | 1212 | case 0xd00: ret = "(Single Step)"; break; |
| 1213 | case 0xf00: ret = "(Performance Monitor)"; break; | 1213 | case 0xf00: ret = "(Performance Monitor)"; break; |
| 1214 | case 0xf20: ret = "(Altivec Unavailable)"; break; | 1214 | case 0xf20: ret = "(Altivec Unavailable)"; break; |
| 1215 | case 0x1300: ret = "(Instruction Breakpoint)"; break; | 1215 | case 0x1300: ret = "(Instruction Breakpoint)"; break; |
| 1216 | default: ret = ""; | 1216 | default: ret = ""; |
| 1217 | } | 1217 | } |
| 1218 | return ret; | 1218 | return ret; |
| 1219 | } | 1219 | } |
| 1220 | 1220 | ||
| 1221 | static void get_function_bounds(unsigned long pc, unsigned long *startp, | 1221 | static void get_function_bounds(unsigned long pc, unsigned long *startp, |
| 1222 | unsigned long *endp) | 1222 | unsigned long *endp) |
| 1223 | { | 1223 | { |
| 1224 | unsigned long size, offset; | 1224 | unsigned long size, offset; |
| 1225 | const char *name; | 1225 | const char *name; |
| 1226 | char *modname; | 1226 | char *modname; |
| 1227 | 1227 | ||
| 1228 | *startp = *endp = 0; | 1228 | *startp = *endp = 0; |
| 1229 | if (pc == 0) | 1229 | if (pc == 0) |
| 1230 | return; | 1230 | return; |
| 1231 | if (setjmp(bus_error_jmp) == 0) { | 1231 | if (setjmp(bus_error_jmp) == 0) { |
| 1232 | catch_memory_errors = 1; | 1232 | catch_memory_errors = 1; |
| 1233 | sync(); | 1233 | sync(); |
| 1234 | name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr); | 1234 | name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr); |
| 1235 | if (name != NULL) { | 1235 | if (name != NULL) { |
| 1236 | *startp = pc - offset; | 1236 | *startp = pc - offset; |
| 1237 | *endp = pc - offset + size; | 1237 | *endp = pc - offset + size; |
| 1238 | } | 1238 | } |
| 1239 | sync(); | 1239 | sync(); |
| 1240 | } | 1240 | } |
| 1241 | catch_memory_errors = 0; | 1241 | catch_memory_errors = 0; |
| 1242 | } | 1242 | } |
| 1243 | 1243 | ||
| 1244 | static int xmon_depth_to_print = 64; | 1244 | static int xmon_depth_to_print = 64; |
| 1245 | 1245 | ||
| 1246 | static void xmon_show_stack(unsigned long sp, unsigned long lr, | 1246 | static void xmon_show_stack(unsigned long sp, unsigned long lr, |
| 1247 | unsigned long pc) | 1247 | unsigned long pc) |
| 1248 | { | 1248 | { |
| 1249 | unsigned long ip; | 1249 | unsigned long ip; |
| 1250 | unsigned long newsp; | 1250 | unsigned long newsp; |
| 1251 | unsigned long marker; | 1251 | unsigned long marker; |
| 1252 | int count = 0; | 1252 | int count = 0; |
| 1253 | struct pt_regs regs; | 1253 | struct pt_regs regs; |
| 1254 | 1254 | ||
| 1255 | do { | 1255 | do { |
| 1256 | if (sp < PAGE_OFFSET) { | 1256 | if (sp < PAGE_OFFSET) { |
| 1257 | if (sp != 0) | 1257 | if (sp != 0) |
| 1258 | printf("SP (%lx) is in userspace\n", sp); | 1258 | printf("SP (%lx) is in userspace\n", sp); |
| 1259 | break; | 1259 | break; |
| 1260 | } | 1260 | } |
| 1261 | 1261 | ||
| 1262 | if (!mread(sp + 16, &ip, sizeof(unsigned long)) | 1262 | if (!mread(sp + 16, &ip, sizeof(unsigned long)) |
| 1263 | || !mread(sp, &newsp, sizeof(unsigned long))) { | 1263 | || !mread(sp, &newsp, sizeof(unsigned long))) { |
| 1264 | printf("Couldn't read stack frame at %lx\n", sp); | 1264 | printf("Couldn't read stack frame at %lx\n", sp); |
| 1265 | break; | 1265 | break; |
| 1266 | } | 1266 | } |
| 1267 | 1267 | ||
| 1268 | /* | 1268 | /* |
| 1269 | * For the first stack frame, try to work out if | 1269 | * For the first stack frame, try to work out if |
| 1270 | * LR and/or the saved LR value in the bottommost | 1270 | * LR and/or the saved LR value in the bottommost |
| 1271 | * stack frame are valid. | 1271 | * stack frame are valid. |
| 1272 | */ | 1272 | */ |
| 1273 | if ((pc | lr) != 0) { | 1273 | if ((pc | lr) != 0) { |
| 1274 | unsigned long fnstart, fnend; | 1274 | unsigned long fnstart, fnend; |
| 1275 | unsigned long nextip; | 1275 | unsigned long nextip; |
| 1276 | int printip = 1; | 1276 | int printip = 1; |
| 1277 | 1277 | ||
| 1278 | get_function_bounds(pc, &fnstart, &fnend); | 1278 | get_function_bounds(pc, &fnstart, &fnend); |
| 1279 | nextip = 0; | 1279 | nextip = 0; |
| 1280 | if (newsp > sp) | 1280 | if (newsp > sp) |
| 1281 | mread(newsp + 16, &nextip, | 1281 | mread(newsp + 16, &nextip, |
| 1282 | sizeof(unsigned long)); | 1282 | sizeof(unsigned long)); |
| 1283 | if (lr == ip) { | 1283 | if (lr == ip) { |
| 1284 | if (lr < PAGE_OFFSET | 1284 | if (lr < PAGE_OFFSET |
| 1285 | || (fnstart <= lr && lr < fnend)) | 1285 | || (fnstart <= lr && lr < fnend)) |
| 1286 | printip = 0; | 1286 | printip = 0; |
| 1287 | } else if (lr == nextip) { | 1287 | } else if (lr == nextip) { |
| 1288 | printip = 0; | 1288 | printip = 0; |
| 1289 | } else if (lr >= PAGE_OFFSET | 1289 | } else if (lr >= PAGE_OFFSET |
| 1290 | && !(fnstart <= lr && lr < fnend)) { | 1290 | && !(fnstart <= lr && lr < fnend)) { |
| 1291 | printf("[link register ] "); | 1291 | printf("[link register ] "); |
| 1292 | xmon_print_symbol(lr, " ", "\n"); | 1292 | xmon_print_symbol(lr, " ", "\n"); |
| 1293 | } | 1293 | } |
| 1294 | if (printip) { | 1294 | if (printip) { |
| 1295 | printf("[%.16lx] ", sp); | 1295 | printf("[%.16lx] ", sp); |
| 1296 | xmon_print_symbol(ip, " ", " (unreliable)\n"); | 1296 | xmon_print_symbol(ip, " ", " (unreliable)\n"); |
| 1297 | } | 1297 | } |
| 1298 | pc = lr = 0; | 1298 | pc = lr = 0; |
| 1299 | 1299 | ||
| 1300 | } else { | 1300 | } else { |
| 1301 | printf("[%.16lx] ", sp); | 1301 | printf("[%.16lx] ", sp); |
| 1302 | xmon_print_symbol(ip, " ", "\n"); | 1302 | xmon_print_symbol(ip, " ", "\n"); |
| 1303 | } | 1303 | } |
| 1304 | 1304 | ||
| 1305 | /* Look for "regshere" marker to see if this is | 1305 | /* Look for "regshere" marker to see if this is |
| 1306 | an exception frame. */ | 1306 | an exception frame. */ |
| 1307 | if (mread(sp + 0x60, &marker, sizeof(unsigned long)) | 1307 | if (mread(sp + 0x60, &marker, sizeof(unsigned long)) |
| 1308 | && marker == 0x7265677368657265ul) { | 1308 | && marker == 0x7265677368657265ul) { |
| 1309 | if (mread(sp + 0x70, ®s, sizeof(regs)) | 1309 | if (mread(sp + 0x70, ®s, sizeof(regs)) |
| 1310 | != sizeof(regs)) { | 1310 | != sizeof(regs)) { |
| 1311 | printf("Couldn't read registers at %lx\n", | 1311 | printf("Couldn't read registers at %lx\n", |
| 1312 | sp + 0x70); | 1312 | sp + 0x70); |
| 1313 | break; | 1313 | break; |
| 1314 | } | 1314 | } |
| 1315 | printf("--- Exception: %lx %s at ", regs.trap, | 1315 | printf("--- Exception: %lx %s at ", regs.trap, |
| 1316 | getvecname(TRAP(®s))); | 1316 | getvecname(TRAP(®s))); |
| 1317 | pc = regs.nip; | 1317 | pc = regs.nip; |
| 1318 | lr = regs.link; | 1318 | lr = regs.link; |
| 1319 | xmon_print_symbol(pc, " ", "\n"); | 1319 | xmon_print_symbol(pc, " ", "\n"); |
| 1320 | } | 1320 | } |
| 1321 | 1321 | ||
| 1322 | if (newsp == 0) | 1322 | if (newsp == 0) |
| 1323 | break; | 1323 | break; |
| 1324 | 1324 | ||
| 1325 | sp = newsp; | 1325 | sp = newsp; |
| 1326 | } while (count++ < xmon_depth_to_print); | 1326 | } while (count++ < xmon_depth_to_print); |
| 1327 | } | 1327 | } |
| 1328 | 1328 | ||
| 1329 | static void backtrace(struct pt_regs *excp) | 1329 | static void backtrace(struct pt_regs *excp) |
| 1330 | { | 1330 | { |
| 1331 | unsigned long sp; | 1331 | unsigned long sp; |
| 1332 | 1332 | ||
| 1333 | if (scanhex(&sp)) | 1333 | if (scanhex(&sp)) |
| 1334 | xmon_show_stack(sp, 0, 0); | 1334 | xmon_show_stack(sp, 0, 0); |
| 1335 | else | 1335 | else |
| 1336 | xmon_show_stack(excp->gpr[1], excp->link, excp->nip); | 1336 | xmon_show_stack(excp->gpr[1], excp->link, excp->nip); |
| 1337 | scannl(); | 1337 | scannl(); |
| 1338 | } | 1338 | } |
| 1339 | 1339 | ||
| 1340 | static void print_bug_trap(struct pt_regs *regs) | 1340 | static void print_bug_trap(struct pt_regs *regs) |
| 1341 | { | 1341 | { |
| 1342 | struct bug_entry *bug; | 1342 | struct bug_entry *bug; |
| 1343 | unsigned long addr; | 1343 | unsigned long addr; |
| 1344 | 1344 | ||
| 1345 | if (regs->msr & MSR_PR) | 1345 | if (regs->msr & MSR_PR) |
| 1346 | return; /* not in kernel */ | 1346 | return; /* not in kernel */ |
| 1347 | addr = regs->nip; /* address of trap instruction */ | 1347 | addr = regs->nip; /* address of trap instruction */ |
| 1348 | if (addr < PAGE_OFFSET) | 1348 | if (addr < PAGE_OFFSET) |
| 1349 | return; | 1349 | return; |
| 1350 | bug = find_bug(regs->nip); | 1350 | bug = find_bug(regs->nip); |
| 1351 | if (bug == NULL) | 1351 | if (bug == NULL) |
| 1352 | return; | 1352 | return; |
| 1353 | if (bug->line & BUG_WARNING_TRAP) | 1353 | if (bug->line & BUG_WARNING_TRAP) |
| 1354 | return; | 1354 | return; |
| 1355 | 1355 | ||
| 1356 | printf("kernel BUG in %s at %s:%d!\n", | 1356 | printf("kernel BUG in %s at %s:%d!\n", |
| 1357 | bug->function, bug->file, (unsigned int)bug->line); | 1357 | bug->function, bug->file, (unsigned int)bug->line); |
| 1358 | } | 1358 | } |
| 1359 | 1359 | ||
| 1360 | void excprint(struct pt_regs *fp) | 1360 | void excprint(struct pt_regs *fp) |
| 1361 | { | 1361 | { |
| 1362 | unsigned long trap; | 1362 | unsigned long trap; |
| 1363 | 1363 | ||
| 1364 | #ifdef CONFIG_SMP | 1364 | #ifdef CONFIG_SMP |
| 1365 | printf("cpu 0x%x: ", smp_processor_id()); | 1365 | printf("cpu 0x%x: ", smp_processor_id()); |
| 1366 | #endif /* CONFIG_SMP */ | 1366 | #endif /* CONFIG_SMP */ |
| 1367 | 1367 | ||
| 1368 | trap = TRAP(fp); | 1368 | trap = TRAP(fp); |
| 1369 | printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp); | 1369 | printf("Vector: %lx %s at [%lx]\n", fp->trap, getvecname(trap), fp); |
| 1370 | printf(" pc: "); | 1370 | printf(" pc: "); |
| 1371 | xmon_print_symbol(fp->nip, ": ", "\n"); | 1371 | xmon_print_symbol(fp->nip, ": ", "\n"); |
| 1372 | 1372 | ||
| 1373 | printf(" lr: ", fp->link); | 1373 | printf(" lr: ", fp->link); |
| 1374 | xmon_print_symbol(fp->link, ": ", "\n"); | 1374 | xmon_print_symbol(fp->link, ": ", "\n"); |
| 1375 | 1375 | ||
| 1376 | printf(" sp: %lx\n", fp->gpr[1]); | 1376 | printf(" sp: %lx\n", fp->gpr[1]); |
| 1377 | printf(" msr: %lx\n", fp->msr); | 1377 | printf(" msr: %lx\n", fp->msr); |
| 1378 | 1378 | ||
| 1379 | if (trap == 0x300 || trap == 0x380 || trap == 0x600) { | 1379 | if (trap == 0x300 || trap == 0x380 || trap == 0x600) { |
| 1380 | printf(" dar: %lx\n", fp->dar); | 1380 | printf(" dar: %lx\n", fp->dar); |
| 1381 | if (trap != 0x380) | 1381 | if (trap != 0x380) |
| 1382 | printf(" dsisr: %lx\n", fp->dsisr); | 1382 | printf(" dsisr: %lx\n", fp->dsisr); |
| 1383 | } | 1383 | } |
| 1384 | 1384 | ||
| 1385 | printf(" current = 0x%lx\n", current); | 1385 | printf(" current = 0x%lx\n", current); |
| 1386 | printf(" paca = 0x%lx\n", get_paca()); | 1386 | printf(" paca = 0x%lx\n", get_paca()); |
| 1387 | if (current) { | 1387 | if (current) { |
| 1388 | printf(" pid = %ld, comm = %s\n", | 1388 | printf(" pid = %ld, comm = %s\n", |
| 1389 | current->pid, current->comm); | 1389 | current->pid, current->comm); |
| 1390 | } | 1390 | } |
| 1391 | 1391 | ||
| 1392 | if (trap == 0x700) | 1392 | if (trap == 0x700) |
| 1393 | print_bug_trap(fp); | 1393 | print_bug_trap(fp); |
| 1394 | } | 1394 | } |
| 1395 | 1395 | ||
| 1396 | void prregs(struct pt_regs *fp) | 1396 | void prregs(struct pt_regs *fp) |
| 1397 | { | 1397 | { |
| 1398 | int n; | 1398 | int n; |
| 1399 | unsigned long base; | 1399 | unsigned long base; |
| 1400 | struct pt_regs regs; | 1400 | struct pt_regs regs; |
| 1401 | 1401 | ||
| 1402 | if (scanhex(&base)) { | 1402 | if (scanhex(&base)) { |
| 1403 | if (setjmp(bus_error_jmp) == 0) { | 1403 | if (setjmp(bus_error_jmp) == 0) { |
| 1404 | catch_memory_errors = 1; | 1404 | catch_memory_errors = 1; |
| 1405 | sync(); | 1405 | sync(); |
| 1406 | regs = *(struct pt_regs *)base; | 1406 | regs = *(struct pt_regs *)base; |
| 1407 | sync(); | 1407 | sync(); |
| 1408 | __delay(200); | 1408 | __delay(200); |
| 1409 | } else { | 1409 | } else { |
| 1410 | catch_memory_errors = 0; | 1410 | catch_memory_errors = 0; |
| 1411 | printf("*** Error reading registers from %.16lx\n", | 1411 | printf("*** Error reading registers from %.16lx\n", |
| 1412 | base); | 1412 | base); |
| 1413 | return; | 1413 | return; |
| 1414 | } | 1414 | } |
| 1415 | catch_memory_errors = 0; | 1415 | catch_memory_errors = 0; |
| 1416 | fp = ®s; | 1416 | fp = ®s; |
| 1417 | } | 1417 | } |
| 1418 | 1418 | ||
| 1419 | if (FULL_REGS(fp)) { | 1419 | if (FULL_REGS(fp)) { |
| 1420 | for (n = 0; n < 16; ++n) | 1420 | for (n = 0; n < 16; ++n) |
| 1421 | printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", | 1421 | printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", |
| 1422 | n, fp->gpr[n], n+16, fp->gpr[n+16]); | 1422 | n, fp->gpr[n], n+16, fp->gpr[n+16]); |
| 1423 | } else { | 1423 | } else { |
| 1424 | for (n = 0; n < 7; ++n) | 1424 | for (n = 0; n < 7; ++n) |
| 1425 | printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", | 1425 | printf("R%.2ld = %.16lx R%.2ld = %.16lx\n", |
| 1426 | n, fp->gpr[n], n+7, fp->gpr[n+7]); | 1426 | n, fp->gpr[n], n+7, fp->gpr[n+7]); |
| 1427 | } | 1427 | } |
| 1428 | printf("pc = "); | 1428 | printf("pc = "); |
| 1429 | xmon_print_symbol(fp->nip, " ", "\n"); | 1429 | xmon_print_symbol(fp->nip, " ", "\n"); |
| 1430 | printf("lr = "); | 1430 | printf("lr = "); |
| 1431 | xmon_print_symbol(fp->link, " ", "\n"); | 1431 | xmon_print_symbol(fp->link, " ", "\n"); |
| 1432 | printf("msr = %.16lx cr = %.8lx\n", fp->msr, fp->ccr); | 1432 | printf("msr = %.16lx cr = %.8lx\n", fp->msr, fp->ccr); |
| 1433 | printf("ctr = %.16lx xer = %.16lx trap = %8lx\n", | 1433 | printf("ctr = %.16lx xer = %.16lx trap = %8lx\n", |
| 1434 | fp->ctr, fp->xer, fp->trap); | 1434 | fp->ctr, fp->xer, fp->trap); |
| 1435 | } | 1435 | } |
| 1436 | 1436 | ||
| 1437 | void cacheflush(void) | 1437 | void cacheflush(void) |
| 1438 | { | 1438 | { |
| 1439 | int cmd; | 1439 | int cmd; |
| 1440 | unsigned long nflush; | 1440 | unsigned long nflush; |
| 1441 | 1441 | ||
| 1442 | cmd = inchar(); | 1442 | cmd = inchar(); |
| 1443 | if (cmd != 'i') | 1443 | if (cmd != 'i') |
| 1444 | termch = cmd; | 1444 | termch = cmd; |
| 1445 | scanhex((void *)&adrs); | 1445 | scanhex((void *)&adrs); |
| 1446 | if (termch != '\n') | 1446 | if (termch != '\n') |
| 1447 | termch = 0; | 1447 | termch = 0; |
| 1448 | nflush = 1; | 1448 | nflush = 1; |
| 1449 | scanhex(&nflush); | 1449 | scanhex(&nflush); |
| 1450 | nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES; | 1450 | nflush = (nflush + L1_CACHE_BYTES - 1) / L1_CACHE_BYTES; |
| 1451 | if (setjmp(bus_error_jmp) == 0) { | 1451 | if (setjmp(bus_error_jmp) == 0) { |
| 1452 | catch_memory_errors = 1; | 1452 | catch_memory_errors = 1; |
| 1453 | sync(); | 1453 | sync(); |
| 1454 | 1454 | ||
| 1455 | if (cmd != 'i') { | 1455 | if (cmd != 'i') { |
| 1456 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) | 1456 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) |
| 1457 | cflush((void *) adrs); | 1457 | cflush((void *) adrs); |
| 1458 | } else { | 1458 | } else { |
| 1459 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) | 1459 | for (; nflush > 0; --nflush, adrs += L1_CACHE_BYTES) |
| 1460 | cinval((void *) adrs); | 1460 | cinval((void *) adrs); |
| 1461 | } | 1461 | } |
| 1462 | sync(); | 1462 | sync(); |
| 1463 | /* wait a little while to see if we get a machine check */ | 1463 | /* wait a little while to see if we get a machine check */ |
| 1464 | __delay(200); | 1464 | __delay(200); |
| 1465 | } | 1465 | } |
| 1466 | catch_memory_errors = 0; | 1466 | catch_memory_errors = 0; |
| 1467 | } | 1467 | } |
| 1468 | 1468 | ||
| 1469 | unsigned long | 1469 | unsigned long |
| 1470 | read_spr(int n) | 1470 | read_spr(int n) |
| 1471 | { | 1471 | { |
| 1472 | unsigned int instrs[2]; | 1472 | unsigned int instrs[2]; |
| 1473 | unsigned long (*code)(void); | 1473 | unsigned long (*code)(void); |
| 1474 | unsigned long opd[3]; | 1474 | unsigned long opd[3]; |
| 1475 | unsigned long ret = -1UL; | 1475 | unsigned long ret = -1UL; |
| 1476 | 1476 | ||
| 1477 | instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); | 1477 | instrs[0] = 0x7c6002a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); |
| 1478 | instrs[1] = 0x4e800020; | 1478 | instrs[1] = 0x4e800020; |
| 1479 | opd[0] = (unsigned long)instrs; | 1479 | opd[0] = (unsigned long)instrs; |
| 1480 | opd[1] = 0; | 1480 | opd[1] = 0; |
| 1481 | opd[2] = 0; | 1481 | opd[2] = 0; |
| 1482 | store_inst(instrs); | 1482 | store_inst(instrs); |
| 1483 | store_inst(instrs+1); | 1483 | store_inst(instrs+1); |
| 1484 | code = (unsigned long (*)(void)) opd; | 1484 | code = (unsigned long (*)(void)) opd; |
| 1485 | 1485 | ||
| 1486 | if (setjmp(bus_error_jmp) == 0) { | 1486 | if (setjmp(bus_error_jmp) == 0) { |
| 1487 | catch_memory_errors = 1; | 1487 | catch_memory_errors = 1; |
| 1488 | sync(); | 1488 | sync(); |
| 1489 | 1489 | ||
| 1490 | ret = code(); | 1490 | ret = code(); |
| 1491 | 1491 | ||
| 1492 | sync(); | 1492 | sync(); |
| 1493 | /* wait a little while to see if we get a machine check */ | 1493 | /* wait a little while to see if we get a machine check */ |
| 1494 | __delay(200); | 1494 | __delay(200); |
| 1495 | n = size; | 1495 | n = size; |
| 1496 | } | 1496 | } |
| 1497 | 1497 | ||
| 1498 | return ret; | 1498 | return ret; |
| 1499 | } | 1499 | } |
| 1500 | 1500 | ||
| 1501 | void | 1501 | void |
| 1502 | write_spr(int n, unsigned long val) | 1502 | write_spr(int n, unsigned long val) |
| 1503 | { | 1503 | { |
| 1504 | unsigned int instrs[2]; | 1504 | unsigned int instrs[2]; |
| 1505 | unsigned long (*code)(unsigned long); | 1505 | unsigned long (*code)(unsigned long); |
| 1506 | unsigned long opd[3]; | 1506 | unsigned long opd[3]; |
| 1507 | 1507 | ||
| 1508 | instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); | 1508 | instrs[0] = 0x7c6003a6 + ((n & 0x1F) << 16) + ((n & 0x3e0) << 6); |
| 1509 | instrs[1] = 0x4e800020; | 1509 | instrs[1] = 0x4e800020; |
| 1510 | opd[0] = (unsigned long)instrs; | 1510 | opd[0] = (unsigned long)instrs; |
| 1511 | opd[1] = 0; | 1511 | opd[1] = 0; |
| 1512 | opd[2] = 0; | 1512 | opd[2] = 0; |
| 1513 | store_inst(instrs); | 1513 | store_inst(instrs); |
| 1514 | store_inst(instrs+1); | 1514 | store_inst(instrs+1); |
| 1515 | code = (unsigned long (*)(unsigned long)) opd; | 1515 | code = (unsigned long (*)(unsigned long)) opd; |
| 1516 | 1516 | ||
| 1517 | if (setjmp(bus_error_jmp) == 0) { | 1517 | if (setjmp(bus_error_jmp) == 0) { |
| 1518 | catch_memory_errors = 1; | 1518 | catch_memory_errors = 1; |
| 1519 | sync(); | 1519 | sync(); |
| 1520 | 1520 | ||
| 1521 | code(val); | 1521 | code(val); |
| 1522 | 1522 | ||
| 1523 | sync(); | 1523 | sync(); |
| 1524 | /* wait a little while to see if we get a machine check */ | 1524 | /* wait a little while to see if we get a machine check */ |
| 1525 | __delay(200); | 1525 | __delay(200); |
| 1526 | n = size; | 1526 | n = size; |
| 1527 | } | 1527 | } |
| 1528 | } | 1528 | } |
| 1529 | 1529 | ||
| 1530 | static unsigned long regno; | 1530 | static unsigned long regno; |
| 1531 | extern char exc_prolog; | 1531 | extern char exc_prolog; |
| 1532 | extern char dec_exc; | 1532 | extern char dec_exc; |
| 1533 | 1533 | ||
| 1534 | void | 1534 | void |
| 1535 | super_regs(void) | 1535 | super_regs(void) |
| 1536 | { | 1536 | { |
| 1537 | int cmd; | 1537 | int cmd; |
| 1538 | unsigned long val; | 1538 | unsigned long val; |
| 1539 | #ifdef CONFIG_PPC_ISERIES | 1539 | #ifdef CONFIG_PPC_ISERIES |
| 1540 | struct paca_struct *ptrPaca = NULL; | 1540 | struct paca_struct *ptrPaca = NULL; |
| 1541 | struct lppaca *ptrLpPaca = NULL; | 1541 | struct lppaca *ptrLpPaca = NULL; |
| 1542 | struct ItLpRegSave *ptrLpRegSave = NULL; | 1542 | struct ItLpRegSave *ptrLpRegSave = NULL; |
| 1543 | #endif | 1543 | #endif |
| 1544 | 1544 | ||
| 1545 | cmd = skipbl(); | 1545 | cmd = skipbl(); |
| 1546 | if (cmd == '\n') { | 1546 | if (cmd == '\n') { |
| 1547 | unsigned long sp, toc; | 1547 | unsigned long sp, toc; |
| 1548 | asm("mr %0,1" : "=r" (sp) :); | 1548 | asm("mr %0,1" : "=r" (sp) :); |
| 1549 | asm("mr %0,2" : "=r" (toc) :); | 1549 | asm("mr %0,2" : "=r" (toc) :); |
| 1550 | 1550 | ||
| 1551 | printf("msr = %.16lx sprg0= %.16lx\n", get_msr(), get_sprg0()); | 1551 | printf("msr = %.16lx sprg0= %.16lx\n", get_msr(), get_sprg0()); |
| 1552 | printf("pvr = %.16lx sprg1= %.16lx\n", get_pvr(), get_sprg1()); | 1552 | printf("pvr = %.16lx sprg1= %.16lx\n", get_pvr(), get_sprg1()); |
| 1553 | printf("dec = %.16lx sprg2= %.16lx\n", get_dec(), get_sprg2()); | 1553 | printf("dec = %.16lx sprg2= %.16lx\n", get_dec(), get_sprg2()); |
| 1554 | printf("sp = %.16lx sprg3= %.16lx\n", sp, get_sprg3()); | 1554 | printf("sp = %.16lx sprg3= %.16lx\n", sp, get_sprg3()); |
| 1555 | printf("toc = %.16lx dar = %.16lx\n", toc, get_dar()); | 1555 | printf("toc = %.16lx dar = %.16lx\n", toc, get_dar()); |
| 1556 | printf("srr0 = %.16lx srr1 = %.16lx\n", get_srr0(), get_srr1()); | 1556 | printf("srr0 = %.16lx srr1 = %.16lx\n", get_srr0(), get_srr1()); |
| 1557 | #ifdef CONFIG_PPC_ISERIES | 1557 | #ifdef CONFIG_PPC_ISERIES |
| 1558 | // Dump out relevant Paca data areas. | 1558 | // Dump out relevant Paca data areas. |
| 1559 | printf("Paca: \n"); | 1559 | printf("Paca: \n"); |
| 1560 | ptrPaca = get_paca(); | 1560 | ptrPaca = get_paca(); |
| 1561 | 1561 | ||
| 1562 | printf(" Local Processor Control Area (LpPaca): \n"); | 1562 | printf(" Local Processor Control Area (LpPaca): \n"); |
| 1563 | ptrLpPaca = ptrPaca->lppaca_ptr; | 1563 | ptrLpPaca = ptrPaca->lppaca_ptr; |
| 1564 | printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", | 1564 | printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", |
| 1565 | ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); | 1565 | ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); |
| 1566 | printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", | 1566 | printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", |
| 1567 | ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); | 1567 | ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); |
| 1568 | printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5); | 1568 | printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5); |
| 1569 | 1569 | ||
| 1570 | printf(" Local Processor Register Save Area (LpRegSave): \n"); | 1570 | printf(" Local Processor Register Save Area (LpRegSave): \n"); |
| 1571 | ptrLpRegSave = ptrPaca->reg_save_ptr; | 1571 | ptrLpRegSave = ptrPaca->reg_save_ptr; |
| 1572 | printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n", | 1572 | printf(" Saved Sprg0=%.16lx Saved Sprg1=%.16lx \n", |
| 1573 | ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0); | 1573 | ptrLpRegSave->xSPRG0, ptrLpRegSave->xSPRG0); |
| 1574 | printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n", | 1574 | printf(" Saved Sprg2=%.16lx Saved Sprg3=%.16lx \n", |
| 1575 | ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3); | 1575 | ptrLpRegSave->xSPRG2, ptrLpRegSave->xSPRG3); |
| 1576 | printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n", | 1576 | printf(" Saved Msr =%.16lx Saved Nia =%.16lx \n", |
| 1577 | ptrLpRegSave->xMSR, ptrLpRegSave->xNIA); | 1577 | ptrLpRegSave->xMSR, ptrLpRegSave->xNIA); |
| 1578 | #endif | 1578 | #endif |
| 1579 | 1579 | ||
| 1580 | return; | 1580 | return; |
| 1581 | } | 1581 | } |
| 1582 | 1582 | ||
| 1583 | scanhex(®no); | 1583 | scanhex(®no); |
| 1584 | switch (cmd) { | 1584 | switch (cmd) { |
| 1585 | case 'w': | 1585 | case 'w': |
| 1586 | val = read_spr(regno); | 1586 | val = read_spr(regno); |
| 1587 | scanhex(&val); | 1587 | scanhex(&val); |
| 1588 | write_spr(regno, val); | 1588 | write_spr(regno, val); |
| 1589 | /* fall through */ | 1589 | /* fall through */ |
| 1590 | case 'r': | 1590 | case 'r': |
| 1591 | printf("spr %lx = %lx\n", regno, read_spr(regno)); | 1591 | printf("spr %lx = %lx\n", regno, read_spr(regno)); |
| 1592 | break; | 1592 | break; |
| 1593 | case 'm': | 1593 | case 'm': |
| 1594 | val = get_msr(); | 1594 | val = get_msr(); |
| 1595 | scanhex(&val); | 1595 | scanhex(&val); |
| 1596 | set_msrd(val); | 1596 | set_msrd(val); |
| 1597 | break; | 1597 | break; |
| 1598 | } | 1598 | } |
| 1599 | scannl(); | 1599 | scannl(); |
| 1600 | } | 1600 | } |
| 1601 | 1601 | ||
| 1602 | /* | 1602 | /* |
| 1603 | * Stuff for reading and writing memory safely | 1603 | * Stuff for reading and writing memory safely |
| 1604 | */ | 1604 | */ |
| 1605 | int | 1605 | int |
| 1606 | mread(unsigned long adrs, void *buf, int size) | 1606 | mread(unsigned long adrs, void *buf, int size) |
| 1607 | { | 1607 | { |
| 1608 | volatile int n; | 1608 | volatile int n; |
| 1609 | char *p, *q; | 1609 | char *p, *q; |
| 1610 | 1610 | ||
| 1611 | n = 0; | 1611 | n = 0; |
| 1612 | if (setjmp(bus_error_jmp) == 0) { | 1612 | if (setjmp(bus_error_jmp) == 0) { |
| 1613 | catch_memory_errors = 1; | 1613 | catch_memory_errors = 1; |
| 1614 | sync(); | 1614 | sync(); |
| 1615 | p = (char *)adrs; | 1615 | p = (char *)adrs; |
| 1616 | q = (char *)buf; | 1616 | q = (char *)buf; |
| 1617 | switch (size) { | 1617 | switch (size) { |
| 1618 | case 2: | 1618 | case 2: |
| 1619 | *(short *)q = *(short *)p; | 1619 | *(short *)q = *(short *)p; |
| 1620 | break; | 1620 | break; |
| 1621 | case 4: | 1621 | case 4: |
| 1622 | *(int *)q = *(int *)p; | 1622 | *(int *)q = *(int *)p; |
| 1623 | break; | 1623 | break; |
| 1624 | case 8: | 1624 | case 8: |
| 1625 | *(long *)q = *(long *)p; | 1625 | *(long *)q = *(long *)p; |
| 1626 | break; | 1626 | break; |
| 1627 | default: | 1627 | default: |
| 1628 | for( ; n < size; ++n) { | 1628 | for( ; n < size; ++n) { |
| 1629 | *q++ = *p++; | 1629 | *q++ = *p++; |
| 1630 | sync(); | 1630 | sync(); |
| 1631 | } | 1631 | } |
| 1632 | } | 1632 | } |
| 1633 | sync(); | 1633 | sync(); |
| 1634 | /* wait a little while to see if we get a machine check */ | 1634 | /* wait a little while to see if we get a machine check */ |
| 1635 | __delay(200); | 1635 | __delay(200); |
| 1636 | n = size; | 1636 | n = size; |
| 1637 | } | 1637 | } |
| 1638 | catch_memory_errors = 0; | 1638 | catch_memory_errors = 0; |
| 1639 | return n; | 1639 | return n; |
| 1640 | } | 1640 | } |
| 1641 | 1641 | ||
| 1642 | int | 1642 | int |
| 1643 | mwrite(unsigned long adrs, void *buf, int size) | 1643 | mwrite(unsigned long adrs, void *buf, int size) |
| 1644 | { | 1644 | { |
| 1645 | volatile int n; | 1645 | volatile int n; |
| 1646 | char *p, *q; | 1646 | char *p, *q; |
| 1647 | 1647 | ||
| 1648 | n = 0; | 1648 | n = 0; |
| 1649 | if (setjmp(bus_error_jmp) == 0) { | 1649 | if (setjmp(bus_error_jmp) == 0) { |
| 1650 | catch_memory_errors = 1; | 1650 | catch_memory_errors = 1; |
| 1651 | sync(); | 1651 | sync(); |
| 1652 | p = (char *) adrs; | 1652 | p = (char *) adrs; |
| 1653 | q = (char *) buf; | 1653 | q = (char *) buf; |
| 1654 | switch (size) { | 1654 | switch (size) { |
| 1655 | case 2: | 1655 | case 2: |
| 1656 | *(short *)p = *(short *)q; | 1656 | *(short *)p = *(short *)q; |
| 1657 | break; | 1657 | break; |
| 1658 | case 4: | 1658 | case 4: |
| 1659 | *(int *)p = *(int *)q; | 1659 | *(int *)p = *(int *)q; |
| 1660 | break; | 1660 | break; |
| 1661 | case 8: | 1661 | case 8: |
| 1662 | *(long *)p = *(long *)q; | 1662 | *(long *)p = *(long *)q; |
| 1663 | break; | 1663 | break; |
| 1664 | default: | 1664 | default: |
| 1665 | for ( ; n < size; ++n) { | 1665 | for ( ; n < size; ++n) { |
| 1666 | *p++ = *q++; | 1666 | *p++ = *q++; |
| 1667 | sync(); | 1667 | sync(); |
| 1668 | } | 1668 | } |
| 1669 | } | 1669 | } |
| 1670 | sync(); | 1670 | sync(); |
| 1671 | /* wait a little while to see if we get a machine check */ | 1671 | /* wait a little while to see if we get a machine check */ |
| 1672 | __delay(200); | 1672 | __delay(200); |
| 1673 | n = size; | 1673 | n = size; |
| 1674 | } else { | 1674 | } else { |
| 1675 | printf("*** Error writing address %x\n", adrs + n); | 1675 | printf("*** Error writing address %x\n", adrs + n); |
| 1676 | } | 1676 | } |
| 1677 | catch_memory_errors = 0; | 1677 | catch_memory_errors = 0; |
| 1678 | return n; | 1678 | return n; |
| 1679 | } | 1679 | } |
| 1680 | 1680 | ||
| 1681 | static int fault_type; | 1681 | static int fault_type; |
| 1682 | static char *fault_chars[] = { "--", "**", "##" }; | 1682 | static char *fault_chars[] = { "--", "**", "##" }; |
| 1683 | 1683 | ||
| 1684 | static int | 1684 | static int |
| 1685 | handle_fault(struct pt_regs *regs) | 1685 | handle_fault(struct pt_regs *regs) |
| 1686 | { | 1686 | { |
| 1687 | switch (TRAP(regs)) { | 1687 | switch (TRAP(regs)) { |
| 1688 | case 0x200: | 1688 | case 0x200: |
| 1689 | fault_type = 0; | 1689 | fault_type = 0; |
| 1690 | break; | 1690 | break; |
| 1691 | case 0x300: | 1691 | case 0x300: |
| 1692 | case 0x380: | 1692 | case 0x380: |
| 1693 | fault_type = 1; | 1693 | fault_type = 1; |
| 1694 | break; | 1694 | break; |
| 1695 | default: | 1695 | default: |
| 1696 | fault_type = 2; | 1696 | fault_type = 2; |
| 1697 | } | 1697 | } |
| 1698 | 1698 | ||
| 1699 | longjmp(bus_error_jmp, 1); | 1699 | longjmp(bus_error_jmp, 1); |
| 1700 | 1700 | ||
| 1701 | return 0; | 1701 | return 0; |
| 1702 | } | 1702 | } |
| 1703 | 1703 | ||
| 1704 | #define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) | 1704 | #define SWAP(a, b, t) ((t) = (a), (a) = (b), (b) = (t)) |
| 1705 | 1705 | ||
| 1706 | void | 1706 | void |
| 1707 | byterev(unsigned char *val, int size) | 1707 | byterev(unsigned char *val, int size) |
| 1708 | { | 1708 | { |
| 1709 | int t; | 1709 | int t; |
| 1710 | 1710 | ||
| 1711 | switch (size) { | 1711 | switch (size) { |
| 1712 | case 2: | 1712 | case 2: |
| 1713 | SWAP(val[0], val[1], t); | 1713 | SWAP(val[0], val[1], t); |
| 1714 | break; | 1714 | break; |
| 1715 | case 4: | 1715 | case 4: |
| 1716 | SWAP(val[0], val[3], t); | 1716 | SWAP(val[0], val[3], t); |
| 1717 | SWAP(val[1], val[2], t); | 1717 | SWAP(val[1], val[2], t); |
| 1718 | break; | 1718 | break; |
| 1719 | case 8: /* is there really any use for this? */ | 1719 | case 8: /* is there really any use for this? */ |
| 1720 | SWAP(val[0], val[7], t); | 1720 | SWAP(val[0], val[7], t); |
| 1721 | SWAP(val[1], val[6], t); | 1721 | SWAP(val[1], val[6], t); |
| 1722 | SWAP(val[2], val[5], t); | 1722 | SWAP(val[2], val[5], t); |
| 1723 | SWAP(val[3], val[4], t); | 1723 | SWAP(val[3], val[4], t); |
| 1724 | break; | 1724 | break; |
| 1725 | } | 1725 | } |
| 1726 | } | 1726 | } |
| 1727 | 1727 | ||
| 1728 | static int brev; | 1728 | static int brev; |
| 1729 | static int mnoread; | 1729 | static int mnoread; |
| 1730 | 1730 | ||
| 1731 | static char *memex_help_string = | 1731 | static char *memex_help_string = |
| 1732 | "Memory examine command usage:\n" | 1732 | "Memory examine command usage:\n" |
| 1733 | "m [addr] [flags] examine/change memory\n" | 1733 | "m [addr] [flags] examine/change memory\n" |
| 1734 | " addr is optional. will start where left off.\n" | 1734 | " addr is optional. will start where left off.\n" |
| 1735 | " flags may include chars from this set:\n" | 1735 | " flags may include chars from this set:\n" |
| 1736 | " b modify by bytes (default)\n" | 1736 | " b modify by bytes (default)\n" |
| 1737 | " w modify by words (2 byte)\n" | 1737 | " w modify by words (2 byte)\n" |
| 1738 | " l modify by longs (4 byte)\n" | 1738 | " l modify by longs (4 byte)\n" |
| 1739 | " d modify by doubleword (8 byte)\n" | 1739 | " d modify by doubleword (8 byte)\n" |
| 1740 | " r toggle reverse byte order mode\n" | 1740 | " r toggle reverse byte order mode\n" |
| 1741 | " n do not read memory (for i/o spaces)\n" | 1741 | " n do not read memory (for i/o spaces)\n" |
| 1742 | " . ok to read (default)\n" | 1742 | " . ok to read (default)\n" |
| 1743 | "NOTE: flags are saved as defaults\n" | 1743 | "NOTE: flags are saved as defaults\n" |
| 1744 | ""; | 1744 | ""; |
| 1745 | 1745 | ||
| 1746 | static char *memex_subcmd_help_string = | 1746 | static char *memex_subcmd_help_string = |
| 1747 | "Memory examine subcommands:\n" | 1747 | "Memory examine subcommands:\n" |
| 1748 | " hexval write this val to current location\n" | 1748 | " hexval write this val to current location\n" |
| 1749 | " 'string' write chars from string to this location\n" | 1749 | " 'string' write chars from string to this location\n" |
| 1750 | " ' increment address\n" | 1750 | " ' increment address\n" |
| 1751 | " ^ decrement address\n" | 1751 | " ^ decrement address\n" |
| 1752 | " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n" | 1752 | " / increment addr by 0x10. //=0x100, ///=0x1000, etc\n" |
| 1753 | " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n" | 1753 | " \\ decrement addr by 0x10. \\\\=0x100, \\\\\\=0x1000, etc\n" |
| 1754 | " ` clear no-read flag\n" | 1754 | " ` clear no-read flag\n" |
| 1755 | " ; stay at this addr\n" | 1755 | " ; stay at this addr\n" |
| 1756 | " v change to byte mode\n" | 1756 | " v change to byte mode\n" |
| 1757 | " w change to word (2 byte) mode\n" | 1757 | " w change to word (2 byte) mode\n" |
| 1758 | " l change to long (4 byte) mode\n" | 1758 | " l change to long (4 byte) mode\n" |
| 1759 | " u change to doubleword (8 byte) mode\n" | 1759 | " u change to doubleword (8 byte) mode\n" |
| 1760 | " m addr change current addr\n" | 1760 | " m addr change current addr\n" |
| 1761 | " n toggle no-read flag\n" | 1761 | " n toggle no-read flag\n" |
| 1762 | " r toggle byte reverse flag\n" | 1762 | " r toggle byte reverse flag\n" |
| 1763 | " < count back up count bytes\n" | 1763 | " < count back up count bytes\n" |
| 1764 | " > count skip forward count bytes\n" | 1764 | " > count skip forward count bytes\n" |
| 1765 | " x exit this mode\n" | 1765 | " x exit this mode\n" |
| 1766 | ""; | 1766 | ""; |
| 1767 | 1767 | ||
| 1768 | void | 1768 | void |
| 1769 | memex(void) | 1769 | memex(void) |
| 1770 | { | 1770 | { |
| 1771 | int cmd, inc, i, nslash; | 1771 | int cmd, inc, i, nslash; |
| 1772 | unsigned long n; | 1772 | unsigned long n; |
| 1773 | unsigned char val[16]; | 1773 | unsigned char val[16]; |
| 1774 | 1774 | ||
| 1775 | scanhex((void *)&adrs); | 1775 | scanhex((void *)&adrs); |
| 1776 | cmd = skipbl(); | 1776 | cmd = skipbl(); |
| 1777 | if (cmd == '?') { | 1777 | if (cmd == '?') { |
| 1778 | printf(memex_help_string); | 1778 | printf(memex_help_string); |
| 1779 | return; | 1779 | return; |
| 1780 | } else { | 1780 | } else { |
| 1781 | termch = cmd; | 1781 | termch = cmd; |
| 1782 | } | 1782 | } |
| 1783 | last_cmd = "m\n"; | 1783 | last_cmd = "m\n"; |
| 1784 | while ((cmd = skipbl()) != '\n') { | 1784 | while ((cmd = skipbl()) != '\n') { |
| 1785 | switch( cmd ){ | 1785 | switch( cmd ){ |
| 1786 | case 'b': size = 1; break; | 1786 | case 'b': size = 1; break; |
| 1787 | case 'w': size = 2; break; | 1787 | case 'w': size = 2; break; |
| 1788 | case 'l': size = 4; break; | 1788 | case 'l': size = 4; break; |
| 1789 | case 'd': size = 8; break; | 1789 | case 'd': size = 8; break; |
| 1790 | case 'r': brev = !brev; break; | 1790 | case 'r': brev = !brev; break; |
| 1791 | case 'n': mnoread = 1; break; | 1791 | case 'n': mnoread = 1; break; |
| 1792 | case '.': mnoread = 0; break; | 1792 | case '.': mnoread = 0; break; |
| 1793 | } | 1793 | } |
| 1794 | } | 1794 | } |
| 1795 | if( size <= 0 ) | 1795 | if( size <= 0 ) |
| 1796 | size = 1; | 1796 | size = 1; |
| 1797 | else if( size > 8 ) | 1797 | else if( size > 8 ) |
| 1798 | size = 8; | 1798 | size = 8; |
| 1799 | for(;;){ | 1799 | for(;;){ |
| 1800 | if (!mnoread) | 1800 | if (!mnoread) |
| 1801 | n = mread(adrs, val, size); | 1801 | n = mread(adrs, val, size); |
| 1802 | printf("%.16x%c", adrs, brev? 'r': ' '); | 1802 | printf("%.16x%c", adrs, brev? 'r': ' '); |
| 1803 | if (!mnoread) { | 1803 | if (!mnoread) { |
| 1804 | if (brev) | 1804 | if (brev) |
| 1805 | byterev(val, size); | 1805 | byterev(val, size); |
| 1806 | putchar(' '); | 1806 | putchar(' '); |
| 1807 | for (i = 0; i < n; ++i) | 1807 | for (i = 0; i < n; ++i) |
| 1808 | printf("%.2x", val[i]); | 1808 | printf("%.2x", val[i]); |
| 1809 | for (; i < size; ++i) | 1809 | for (; i < size; ++i) |
| 1810 | printf("%s", fault_chars[fault_type]); | 1810 | printf("%s", fault_chars[fault_type]); |
| 1811 | } | 1811 | } |
| 1812 | putchar(' '); | 1812 | putchar(' '); |
| 1813 | inc = size; | 1813 | inc = size; |
| 1814 | nslash = 0; | 1814 | nslash = 0; |
| 1815 | for(;;){ | 1815 | for(;;){ |
| 1816 | if( scanhex(&n) ){ | 1816 | if( scanhex(&n) ){ |
| 1817 | for (i = 0; i < size; ++i) | 1817 | for (i = 0; i < size; ++i) |
| 1818 | val[i] = n >> (i * 8); | 1818 | val[i] = n >> (i * 8); |
| 1819 | if (!brev) | 1819 | if (!brev) |
| 1820 | byterev(val, size); | 1820 | byterev(val, size); |
| 1821 | mwrite(adrs, val, size); | 1821 | mwrite(adrs, val, size); |
| 1822 | inc = size; | 1822 | inc = size; |
| 1823 | } | 1823 | } |
| 1824 | cmd = skipbl(); | 1824 | cmd = skipbl(); |
| 1825 | if (cmd == '\n') | 1825 | if (cmd == '\n') |
| 1826 | break; | 1826 | break; |
| 1827 | inc = 0; | 1827 | inc = 0; |
| 1828 | switch (cmd) { | 1828 | switch (cmd) { |
| 1829 | case '\'': | 1829 | case '\'': |
| 1830 | for(;;){ | 1830 | for(;;){ |
| 1831 | n = inchar(); | 1831 | n = inchar(); |
| 1832 | if( n == '\\' ) | 1832 | if( n == '\\' ) |
| 1833 | n = bsesc(); | 1833 | n = bsesc(); |
| 1834 | else if( n == '\'' ) | 1834 | else if( n == '\'' ) |
| 1835 | break; | 1835 | break; |
| 1836 | for (i = 0; i < size; ++i) | 1836 | for (i = 0; i < size; ++i) |
| 1837 | val[i] = n >> (i * 8); | 1837 | val[i] = n >> (i * 8); |
| 1838 | if (!brev) | 1838 | if (!brev) |
| 1839 | byterev(val, size); | 1839 | byterev(val, size); |
| 1840 | mwrite(adrs, val, size); | 1840 | mwrite(adrs, val, size); |
| 1841 | adrs += size; | 1841 | adrs += size; |
| 1842 | } | 1842 | } |
| 1843 | adrs -= size; | 1843 | adrs -= size; |
| 1844 | inc = size; | 1844 | inc = size; |
| 1845 | break; | 1845 | break; |
| 1846 | case ',': | 1846 | case ',': |
| 1847 | adrs += size; | 1847 | adrs += size; |
| 1848 | break; | 1848 | break; |
| 1849 | case '.': | 1849 | case '.': |
| 1850 | mnoread = 0; | 1850 | mnoread = 0; |
| 1851 | break; | 1851 | break; |
| 1852 | case ';': | 1852 | case ';': |
| 1853 | break; | 1853 | break; |
| 1854 | case 'x': | 1854 | case 'x': |
| 1855 | case EOF: | 1855 | case EOF: |
| 1856 | scannl(); | 1856 | scannl(); |
| 1857 | return; | 1857 | return; |
| 1858 | case 'b': | 1858 | case 'b': |
| 1859 | case 'v': | 1859 | case 'v': |
| 1860 | size = 1; | 1860 | size = 1; |
| 1861 | break; | 1861 | break; |
| 1862 | case 'w': | 1862 | case 'w': |
| 1863 | size = 2; | 1863 | size = 2; |
| 1864 | break; | 1864 | break; |
| 1865 | case 'l': | 1865 | case 'l': |
| 1866 | size = 4; | 1866 | size = 4; |
| 1867 | break; | 1867 | break; |
| 1868 | case 'u': | 1868 | case 'u': |
| 1869 | size = 8; | 1869 | size = 8; |
| 1870 | break; | 1870 | break; |
| 1871 | case '^': | 1871 | case '^': |
| 1872 | adrs -= size; | 1872 | adrs -= size; |
| 1873 | break; | 1873 | break; |
| 1874 | break; | 1874 | break; |
| 1875 | case '/': | 1875 | case '/': |
| 1876 | if (nslash > 0) | 1876 | if (nslash > 0) |
| 1877 | adrs -= 1 << nslash; | 1877 | adrs -= 1 << nslash; |
| 1878 | else | 1878 | else |
| 1879 | nslash = 0; | 1879 | nslash = 0; |
| 1880 | nslash += 4; | 1880 | nslash += 4; |
| 1881 | adrs += 1 << nslash; | 1881 | adrs += 1 << nslash; |
| 1882 | break; | 1882 | break; |
| 1883 | case '\\': | 1883 | case '\\': |
| 1884 | if (nslash < 0) | 1884 | if (nslash < 0) |
| 1885 | adrs += 1 << -nslash; | 1885 | adrs += 1 << -nslash; |
| 1886 | else | 1886 | else |
| 1887 | nslash = 0; | 1887 | nslash = 0; |
| 1888 | nslash -= 4; | 1888 | nslash -= 4; |
| 1889 | adrs -= 1 << -nslash; | 1889 | adrs -= 1 << -nslash; |
| 1890 | break; | 1890 | break; |
| 1891 | case 'm': | 1891 | case 'm': |
| 1892 | scanhex((void *)&adrs); | 1892 | scanhex((void *)&adrs); |
| 1893 | break; | 1893 | break; |
| 1894 | case 'n': | 1894 | case 'n': |
| 1895 | mnoread = 1; | 1895 | mnoread = 1; |
| 1896 | break; | 1896 | break; |
| 1897 | case 'r': | 1897 | case 'r': |
| 1898 | brev = !brev; | 1898 | brev = !brev; |
| 1899 | break; | 1899 | break; |
| 1900 | case '<': | 1900 | case '<': |
| 1901 | n = size; | 1901 | n = size; |
| 1902 | scanhex(&n); | 1902 | scanhex(&n); |
| 1903 | adrs -= n; | 1903 | adrs -= n; |
| 1904 | break; | 1904 | break; |
| 1905 | case '>': | 1905 | case '>': |
| 1906 | n = size; | 1906 | n = size; |
| 1907 | scanhex(&n); | 1907 | scanhex(&n); |
| 1908 | adrs += n; | 1908 | adrs += n; |
| 1909 | break; | 1909 | break; |
| 1910 | case '?': | 1910 | case '?': |
| 1911 | printf(memex_subcmd_help_string); | 1911 | printf(memex_subcmd_help_string); |
| 1912 | break; | 1912 | break; |
| 1913 | } | 1913 | } |
| 1914 | } | 1914 | } |
| 1915 | adrs += inc; | 1915 | adrs += inc; |
| 1916 | } | 1916 | } |
| 1917 | } | 1917 | } |
| 1918 | 1918 | ||
| 1919 | int | 1919 | int |
| 1920 | bsesc(void) | 1920 | bsesc(void) |
| 1921 | { | 1921 | { |
| 1922 | int c; | 1922 | int c; |
| 1923 | 1923 | ||
| 1924 | c = inchar(); | 1924 | c = inchar(); |
| 1925 | switch( c ){ | 1925 | switch( c ){ |
| 1926 | case 'n': c = '\n'; break; | 1926 | case 'n': c = '\n'; break; |
| 1927 | case 'r': c = '\r'; break; | 1927 | case 'r': c = '\r'; break; |
| 1928 | case 'b': c = '\b'; break; | 1928 | case 'b': c = '\b'; break; |
| 1929 | case 't': c = '\t'; break; | 1929 | case 't': c = '\t'; break; |
| 1930 | } | 1930 | } |
| 1931 | return c; | 1931 | return c; |
| 1932 | } | 1932 | } |
| 1933 | 1933 | ||
| 1934 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ | 1934 | #define isxdigit(c) (('0' <= (c) && (c) <= '9') \ |
| 1935 | || ('a' <= (c) && (c) <= 'f') \ | 1935 | || ('a' <= (c) && (c) <= 'f') \ |
| 1936 | || ('A' <= (c) && (c) <= 'F')) | 1936 | || ('A' <= (c) && (c) <= 'F')) |
| 1937 | void | 1937 | void |
| 1938 | dump(void) | 1938 | dump(void) |
| 1939 | { | 1939 | { |
| 1940 | int c; | 1940 | int c; |
| 1941 | 1941 | ||
| 1942 | c = inchar(); | 1942 | c = inchar(); |
| 1943 | if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') | 1943 | if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n') |
| 1944 | termch = c; | 1944 | termch = c; |
| 1945 | scanhex((void *)&adrs); | 1945 | scanhex((void *)&adrs); |
| 1946 | if (termch != '\n') | 1946 | if (termch != '\n') |
| 1947 | termch = 0; | 1947 | termch = 0; |
| 1948 | if (c == 'i') { | 1948 | if (c == 'i') { |
| 1949 | scanhex(&nidump); | 1949 | scanhex(&nidump); |
| 1950 | if (nidump == 0) | 1950 | if (nidump == 0) |
| 1951 | nidump = 16; | 1951 | nidump = 16; |
| 1952 | else if (nidump > MAX_DUMP) | 1952 | else if (nidump > MAX_DUMP) |
| 1953 | nidump = MAX_DUMP; | 1953 | nidump = MAX_DUMP; |
| 1954 | adrs += ppc_inst_dump(adrs, nidump, 1); | 1954 | adrs += ppc_inst_dump(adrs, nidump, 1); |
| 1955 | last_cmd = "di\n"; | 1955 | last_cmd = "di\n"; |
| 1956 | } else { | 1956 | } else { |
| 1957 | scanhex(&ndump); | 1957 | scanhex(&ndump); |
| 1958 | if (ndump == 0) | 1958 | if (ndump == 0) |
| 1959 | ndump = 64; | 1959 | ndump = 64; |
| 1960 | else if (ndump > MAX_DUMP) | 1960 | else if (ndump > MAX_DUMP) |
| 1961 | ndump = MAX_DUMP; | 1961 | ndump = MAX_DUMP; |
| 1962 | prdump(adrs, ndump); | 1962 | prdump(adrs, ndump); |
| 1963 | adrs += ndump; | 1963 | adrs += ndump; |
| 1964 | last_cmd = "d\n"; | 1964 | last_cmd = "d\n"; |
| 1965 | } | 1965 | } |
| 1966 | } | 1966 | } |
| 1967 | 1967 | ||
| 1968 | void | 1968 | void |
| 1969 | prdump(unsigned long adrs, long ndump) | 1969 | prdump(unsigned long adrs, long ndump) |
| 1970 | { | 1970 | { |
| 1971 | long n, m, c, r, nr; | 1971 | long n, m, c, r, nr; |
| 1972 | unsigned char temp[16]; | 1972 | unsigned char temp[16]; |
| 1973 | 1973 | ||
| 1974 | for (n = ndump; n > 0;) { | 1974 | for (n = ndump; n > 0;) { |
| 1975 | printf("%.16lx", adrs); | 1975 | printf("%.16lx", adrs); |
| 1976 | putchar(' '); | 1976 | putchar(' '); |
| 1977 | r = n < 16? n: 16; | 1977 | r = n < 16? n: 16; |
| 1978 | nr = mread(adrs, temp, r); | 1978 | nr = mread(adrs, temp, r); |
| 1979 | adrs += nr; | 1979 | adrs += nr; |
| 1980 | for (m = 0; m < r; ++m) { | 1980 | for (m = 0; m < r; ++m) { |
| 1981 | if ((m & 7) == 0 && m > 0) | 1981 | if ((m & 7) == 0 && m > 0) |
| 1982 | putchar(' '); | 1982 | putchar(' '); |
| 1983 | if (m < nr) | 1983 | if (m < nr) |
| 1984 | printf("%.2x", temp[m]); | 1984 | printf("%.2x", temp[m]); |
| 1985 | else | 1985 | else |
| 1986 | printf("%s", fault_chars[fault_type]); | 1986 | printf("%s", fault_chars[fault_type]); |
| 1987 | } | 1987 | } |
| 1988 | if (m <= 8) | 1988 | if (m <= 8) |
| 1989 | printf(" "); | 1989 | printf(" "); |
| 1990 | for (; m < 16; ++m) | 1990 | for (; m < 16; ++m) |
| 1991 | printf(" "); | 1991 | printf(" "); |
| 1992 | printf(" |"); | 1992 | printf(" |"); |
| 1993 | for (m = 0; m < r; ++m) { | 1993 | for (m = 0; m < r; ++m) { |
| 1994 | if (m < nr) { | 1994 | if (m < nr) { |
| 1995 | c = temp[m]; | 1995 | c = temp[m]; |
| 1996 | putchar(' ' <= c && c <= '~'? c: '.'); | 1996 | putchar(' ' <= c && c <= '~'? c: '.'); |
| 1997 | } else | 1997 | } else |
| 1998 | putchar(' '); | 1998 | putchar(' '); |
| 1999 | } | 1999 | } |
| 2000 | n -= r; | 2000 | n -= r; |
| 2001 | for (; m < 16; ++m) | 2001 | for (; m < 16; ++m) |
| 2002 | putchar(' '); | 2002 | putchar(' '); |
| 2003 | printf("|\n"); | 2003 | printf("|\n"); |
| 2004 | if (nr < r) | 2004 | if (nr < r) |
| 2005 | break; | 2005 | break; |
| 2006 | } | 2006 | } |
| 2007 | } | 2007 | } |
| 2008 | 2008 | ||
| 2009 | int | 2009 | int |
| 2010 | ppc_inst_dump(unsigned long adr, long count, int praddr) | 2010 | ppc_inst_dump(unsigned long adr, long count, int praddr) |
| 2011 | { | 2011 | { |
| 2012 | int nr, dotted; | 2012 | int nr, dotted; |
| 2013 | unsigned long first_adr; | 2013 | unsigned long first_adr; |
| 2014 | unsigned long inst, last_inst = 0; | 2014 | unsigned long inst, last_inst = 0; |
| 2015 | unsigned char val[4]; | 2015 | unsigned char val[4]; |
| 2016 | 2016 | ||
| 2017 | dotted = 0; | 2017 | dotted = 0; |
| 2018 | for (first_adr = adr; count > 0; --count, adr += 4) { | 2018 | for (first_adr = adr; count > 0; --count, adr += 4) { |
| 2019 | nr = mread(adr, val, 4); | 2019 | nr = mread(adr, val, 4); |
| 2020 | if (nr == 0) { | 2020 | if (nr == 0) { |
| 2021 | if (praddr) { | 2021 | if (praddr) { |
| 2022 | const char *x = fault_chars[fault_type]; | 2022 | const char *x = fault_chars[fault_type]; |
| 2023 | printf("%.16lx %s%s%s%s\n", adr, x, x, x, x); | 2023 | printf("%.16lx %s%s%s%s\n", adr, x, x, x, x); |
| 2024 | } | 2024 | } |
| 2025 | break; | 2025 | break; |
| 2026 | } | 2026 | } |
| 2027 | inst = GETWORD(val); | 2027 | inst = GETWORD(val); |
| 2028 | if (adr > first_adr && inst == last_inst) { | 2028 | if (adr > first_adr && inst == last_inst) { |
| 2029 | if (!dotted) { | 2029 | if (!dotted) { |
| 2030 | printf(" ...\n"); | 2030 | printf(" ...\n"); |
| 2031 | dotted = 1; | 2031 | dotted = 1; |
| 2032 | } | 2032 | } |
| 2033 | continue; | 2033 | continue; |
| 2034 | } | 2034 | } |
| 2035 | dotted = 0; | 2035 | dotted = 0; |
| 2036 | last_inst = inst; | 2036 | last_inst = inst; |
| 2037 | if (praddr) | 2037 | if (praddr) |
| 2038 | printf("%.16lx %.8x", adr, inst); | 2038 | printf("%.16lx %.8x", adr, inst); |
| 2039 | printf("\t"); | 2039 | printf("\t"); |
| 2040 | print_insn_powerpc(inst, adr, 0); /* always returns 4 */ | 2040 | print_insn_powerpc(inst, adr, 0); /* always returns 4 */ |
| 2041 | printf("\n"); | 2041 | printf("\n"); |
| 2042 | } | 2042 | } |
| 2043 | return adr - first_adr; | 2043 | return adr - first_adr; |
| 2044 | } | 2044 | } |
| 2045 | 2045 | ||
| 2046 | void | 2046 | void |
| 2047 | print_address(unsigned long addr) | 2047 | print_address(unsigned long addr) |
| 2048 | { | 2048 | { |
| 2049 | xmon_print_symbol(addr, "\t# ", ""); | 2049 | xmon_print_symbol(addr, "\t# ", ""); |
| 2050 | } | 2050 | } |
| 2051 | 2051 | ||
| 2052 | 2052 | ||
| 2053 | /* | 2053 | /* |
| 2054 | * Memory operations - move, set, print differences | 2054 | * Memory operations - move, set, print differences |
| 2055 | */ | 2055 | */ |
| 2056 | static unsigned long mdest; /* destination address */ | 2056 | static unsigned long mdest; /* destination address */ |
| 2057 | static unsigned long msrc; /* source address */ | 2057 | static unsigned long msrc; /* source address */ |
| 2058 | static unsigned long mval; /* byte value to set memory to */ | 2058 | static unsigned long mval; /* byte value to set memory to */ |
| 2059 | static unsigned long mcount; /* # bytes to affect */ | 2059 | static unsigned long mcount; /* # bytes to affect */ |
| 2060 | static unsigned long mdiffs; /* max # differences to print */ | 2060 | static unsigned long mdiffs; /* max # differences to print */ |
| 2061 | 2061 | ||
| 2062 | void | 2062 | void |
| 2063 | memops(int cmd) | 2063 | memops(int cmd) |
| 2064 | { | 2064 | { |
| 2065 | scanhex((void *)&mdest); | 2065 | scanhex((void *)&mdest); |
| 2066 | if( termch != '\n' ) | 2066 | if( termch != '\n' ) |
| 2067 | termch = 0; | 2067 | termch = 0; |
| 2068 | scanhex((void *)(cmd == 's'? &mval: &msrc)); | 2068 | scanhex((void *)(cmd == 's'? &mval: &msrc)); |
| 2069 | if( termch != '\n' ) | 2069 | if( termch != '\n' ) |
| 2070 | termch = 0; | 2070 | termch = 0; |
| 2071 | scanhex((void *)&mcount); | 2071 | scanhex((void *)&mcount); |
| 2072 | switch( cmd ){ | 2072 | switch( cmd ){ |
| 2073 | case 'm': | 2073 | case 'm': |
| 2074 | memmove((void *)mdest, (void *)msrc, mcount); | 2074 | memmove((void *)mdest, (void *)msrc, mcount); |
| 2075 | break; | 2075 | break; |
| 2076 | case 's': | 2076 | case 's': |
| 2077 | memset((void *)mdest, mval, mcount); | 2077 | memset((void *)mdest, mval, mcount); |
| 2078 | break; | 2078 | break; |
| 2079 | case 'd': | 2079 | case 'd': |
| 2080 | if( termch != '\n' ) | 2080 | if( termch != '\n' ) |
| 2081 | termch = 0; | 2081 | termch = 0; |
| 2082 | scanhex((void *)&mdiffs); | 2082 | scanhex((void *)&mdiffs); |
| 2083 | memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs); | 2083 | memdiffs((unsigned char *)mdest, (unsigned char *)msrc, mcount, mdiffs); |
| 2084 | break; | 2084 | break; |
| 2085 | } | 2085 | } |
| 2086 | } | 2086 | } |
| 2087 | 2087 | ||
| 2088 | void | 2088 | void |
| 2089 | memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr) | 2089 | memdiffs(unsigned char *p1, unsigned char *p2, unsigned nb, unsigned maxpr) |
| 2090 | { | 2090 | { |
| 2091 | unsigned n, prt; | 2091 | unsigned n, prt; |
| 2092 | 2092 | ||
| 2093 | prt = 0; | 2093 | prt = 0; |
| 2094 | for( n = nb; n > 0; --n ) | 2094 | for( n = nb; n > 0; --n ) |
| 2095 | if( *p1++ != *p2++ ) | 2095 | if( *p1++ != *p2++ ) |
| 2096 | if( ++prt <= maxpr ) | 2096 | if( ++prt <= maxpr ) |
| 2097 | printf("%.16x %.2x # %.16x %.2x\n", p1 - 1, | 2097 | printf("%.16x %.2x # %.16x %.2x\n", p1 - 1, |
| 2098 | p1[-1], p2 - 1, p2[-1]); | 2098 | p1[-1], p2 - 1, p2[-1]); |
| 2099 | if( prt > maxpr ) | 2099 | if( prt > maxpr ) |
| 2100 | printf("Total of %d differences\n", prt); | 2100 | printf("Total of %d differences\n", prt); |
| 2101 | } | 2101 | } |
| 2102 | 2102 | ||
| 2103 | static unsigned mend; | 2103 | static unsigned mend; |
| 2104 | static unsigned mask; | 2104 | static unsigned mask; |
| 2105 | 2105 | ||
| 2106 | void | 2106 | void |
| 2107 | memlocate(void) | 2107 | memlocate(void) |
| 2108 | { | 2108 | { |
| 2109 | unsigned a, n; | 2109 | unsigned a, n; |
| 2110 | unsigned char val[4]; | 2110 | unsigned char val[4]; |
| 2111 | 2111 | ||
| 2112 | last_cmd = "ml"; | 2112 | last_cmd = "ml"; |
| 2113 | scanhex((void *)&mdest); | 2113 | scanhex((void *)&mdest); |
| 2114 | if (termch != '\n') { | 2114 | if (termch != '\n') { |
| 2115 | termch = 0; | 2115 | termch = 0; |
| 2116 | scanhex((void *)&mend); | 2116 | scanhex((void *)&mend); |
| 2117 | if (termch != '\n') { | 2117 | if (termch != '\n') { |
| 2118 | termch = 0; | 2118 | termch = 0; |
| 2119 | scanhex((void *)&mval); | 2119 | scanhex((void *)&mval); |
| 2120 | mask = ~0; | 2120 | mask = ~0; |
| 2121 | if (termch != '\n') termch = 0; | 2121 | if (termch != '\n') termch = 0; |
| 2122 | scanhex((void *)&mask); | 2122 | scanhex((void *)&mask); |
| 2123 | } | 2123 | } |
| 2124 | } | 2124 | } |
| 2125 | n = 0; | 2125 | n = 0; |
| 2126 | for (a = mdest; a < mend; a += 4) { | 2126 | for (a = mdest; a < mend; a += 4) { |
| 2127 | if (mread(a, val, 4) == 4 | 2127 | if (mread(a, val, 4) == 4 |
| 2128 | && ((GETWORD(val) ^ mval) & mask) == 0) { | 2128 | && ((GETWORD(val) ^ mval) & mask) == 0) { |
| 2129 | printf("%.16x: %.16x\n", a, GETWORD(val)); | 2129 | printf("%.16x: %.16x\n", a, GETWORD(val)); |
| 2130 | if (++n >= 10) | 2130 | if (++n >= 10) |
| 2131 | break; | 2131 | break; |
| 2132 | } | 2132 | } |
| 2133 | } | 2133 | } |
| 2134 | } | 2134 | } |
| 2135 | 2135 | ||
| 2136 | static unsigned long mskip = 0x1000; | 2136 | static unsigned long mskip = 0x1000; |
| 2137 | static unsigned long mlim = 0xffffffff; | 2137 | static unsigned long mlim = 0xffffffff; |
| 2138 | 2138 | ||
| 2139 | void | 2139 | void |
| 2140 | memzcan(void) | 2140 | memzcan(void) |
| 2141 | { | 2141 | { |
| 2142 | unsigned char v; | 2142 | unsigned char v; |
| 2143 | unsigned a; | 2143 | unsigned a; |
| 2144 | int ok, ook; | 2144 | int ok, ook; |
| 2145 | 2145 | ||
| 2146 | scanhex(&mdest); | 2146 | scanhex(&mdest); |
| 2147 | if (termch != '\n') termch = 0; | 2147 | if (termch != '\n') termch = 0; |
| 2148 | scanhex(&mskip); | 2148 | scanhex(&mskip); |
| 2149 | if (termch != '\n') termch = 0; | 2149 | if (termch != '\n') termch = 0; |
| 2150 | scanhex(&mlim); | 2150 | scanhex(&mlim); |
| 2151 | ook = 0; | 2151 | ook = 0; |
| 2152 | for (a = mdest; a < mlim; a += mskip) { | 2152 | for (a = mdest; a < mlim; a += mskip) { |
| 2153 | ok = mread(a, &v, 1); | 2153 | ok = mread(a, &v, 1); |
| 2154 | if (ok && !ook) { | 2154 | if (ok && !ook) { |
| 2155 | printf("%.8x .. ", a); | 2155 | printf("%.8x .. ", a); |
| 2156 | fflush(stdout); | 2156 | fflush(stdout); |
| 2157 | } else if (!ok && ook) | 2157 | } else if (!ok && ook) |
| 2158 | printf("%.8x\n", a - mskip); | 2158 | printf("%.8x\n", a - mskip); |
| 2159 | ook = ok; | 2159 | ook = ok; |
| 2160 | if (a + mskip < a) | 2160 | if (a + mskip < a) |
| 2161 | break; | 2161 | break; |
| 2162 | } | 2162 | } |
| 2163 | if (ook) | 2163 | if (ook) |
| 2164 | printf("%.8x\n", a - mskip); | 2164 | printf("%.8x\n", a - mskip); |
| 2165 | } | 2165 | } |
| 2166 | 2166 | ||
| 2167 | /* Input scanning routines */ | 2167 | /* Input scanning routines */ |
| 2168 | int | 2168 | int |
| 2169 | skipbl(void) | 2169 | skipbl(void) |
| 2170 | { | 2170 | { |
| 2171 | int c; | 2171 | int c; |
| 2172 | 2172 | ||
| 2173 | if( termch != 0 ){ | 2173 | if( termch != 0 ){ |
| 2174 | c = termch; | 2174 | c = termch; |
| 2175 | termch = 0; | 2175 | termch = 0; |
| 2176 | } else | 2176 | } else |
| 2177 | c = inchar(); | 2177 | c = inchar(); |
| 2178 | while( c == ' ' || c == '\t' ) | 2178 | while( c == ' ' || c == '\t' ) |
| 2179 | c = inchar(); | 2179 | c = inchar(); |
| 2180 | return c; | 2180 | return c; |
| 2181 | } | 2181 | } |
| 2182 | 2182 | ||
| 2183 | #define N_PTREGS 44 | 2183 | #define N_PTREGS 44 |
| 2184 | static char *regnames[N_PTREGS] = { | 2184 | static char *regnames[N_PTREGS] = { |
| 2185 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | 2185 | "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
| 2186 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", | 2186 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", |
| 2187 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | 2187 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", |
| 2188 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | 2188 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", |
| 2189 | "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "softe", | 2189 | "pc", "msr", "or3", "ctr", "lr", "xer", "ccr", "softe", |
| 2190 | "trap", "dar", "dsisr", "res" | 2190 | "trap", "dar", "dsisr", "res" |
| 2191 | }; | 2191 | }; |
| 2192 | 2192 | ||
| 2193 | int | 2193 | int |
| 2194 | scanhex(unsigned long *vp) | 2194 | scanhex(unsigned long *vp) |
| 2195 | { | 2195 | { |
| 2196 | int c, d; | 2196 | int c, d; |
| 2197 | unsigned long v; | 2197 | unsigned long v; |
| 2198 | 2198 | ||
| 2199 | c = skipbl(); | 2199 | c = skipbl(); |
| 2200 | if (c == '%') { | 2200 | if (c == '%') { |
| 2201 | /* parse register name */ | 2201 | /* parse register name */ |
| 2202 | char regname[8]; | 2202 | char regname[8]; |
| 2203 | int i; | 2203 | int i; |
| 2204 | 2204 | ||
| 2205 | for (i = 0; i < sizeof(regname) - 1; ++i) { | 2205 | for (i = 0; i < sizeof(regname) - 1; ++i) { |
| 2206 | c = inchar(); | 2206 | c = inchar(); |
| 2207 | if (!isalnum(c)) { | 2207 | if (!isalnum(c)) { |
| 2208 | termch = c; | 2208 | termch = c; |
| 2209 | break; | 2209 | break; |
| 2210 | } | 2210 | } |
| 2211 | regname[i] = c; | 2211 | regname[i] = c; |
| 2212 | } | 2212 | } |
| 2213 | regname[i] = 0; | 2213 | regname[i] = 0; |
| 2214 | for (i = 0; i < N_PTREGS; ++i) { | 2214 | for (i = 0; i < N_PTREGS; ++i) { |
| 2215 | if (strcmp(regnames[i], regname) == 0) { | 2215 | if (strcmp(regnames[i], regname) == 0) { |
| 2216 | if (xmon_regs == NULL) { | 2216 | if (xmon_regs == NULL) { |
| 2217 | printf("regs not available\n"); | 2217 | printf("regs not available\n"); |
| 2218 | return 0; | 2218 | return 0; |
| 2219 | } | 2219 | } |
| 2220 | *vp = ((unsigned long *)xmon_regs)[i]; | 2220 | *vp = ((unsigned long *)xmon_regs)[i]; |
| 2221 | return 1; | 2221 | return 1; |
| 2222 | } | 2222 | } |
| 2223 | } | 2223 | } |
| 2224 | printf("invalid register name '%%%s'\n", regname); | 2224 | printf("invalid register name '%%%s'\n", regname); |
| 2225 | return 0; | 2225 | return 0; |
| 2226 | } | 2226 | } |
| 2227 | 2227 | ||
| 2228 | /* skip leading "0x" if any */ | 2228 | /* skip leading "0x" if any */ |
| 2229 | 2229 | ||
| 2230 | if (c == '0') { | 2230 | if (c == '0') { |
| 2231 | c = inchar(); | 2231 | c = inchar(); |
| 2232 | if (c == 'x') { | 2232 | if (c == 'x') { |
| 2233 | c = inchar(); | 2233 | c = inchar(); |
| 2234 | } else { | 2234 | } else { |
| 2235 | d = hexdigit(c); | 2235 | d = hexdigit(c); |
| 2236 | if (d == EOF) { | 2236 | if (d == EOF) { |
| 2237 | termch = c; | 2237 | termch = c; |
| 2238 | *vp = 0; | 2238 | *vp = 0; |
| 2239 | return 1; | 2239 | return 1; |
| 2240 | } | 2240 | } |
| 2241 | } | 2241 | } |
| 2242 | } else if (c == '$') { | 2242 | } else if (c == '$') { |
| 2243 | int i; | 2243 | int i; |
| 2244 | for (i=0; i<63; i++) { | 2244 | for (i=0; i<63; i++) { |
| 2245 | c = inchar(); | 2245 | c = inchar(); |
| 2246 | if (isspace(c)) { | 2246 | if (isspace(c)) { |
| 2247 | termch = c; | 2247 | termch = c; |
| 2248 | break; | 2248 | break; |
| 2249 | } | 2249 | } |
| 2250 | tmpstr[i] = c; | 2250 | tmpstr[i] = c; |
| 2251 | } | 2251 | } |
| 2252 | tmpstr[i++] = 0; | 2252 | tmpstr[i++] = 0; |
| 2253 | *vp = 0; | 2253 | *vp = 0; |
| 2254 | if (setjmp(bus_error_jmp) == 0) { | 2254 | if (setjmp(bus_error_jmp) == 0) { |
| 2255 | catch_memory_errors = 1; | 2255 | catch_memory_errors = 1; |
| 2256 | sync(); | 2256 | sync(); |
| 2257 | *vp = kallsyms_lookup_name(tmpstr); | 2257 | *vp = kallsyms_lookup_name(tmpstr); |
| 2258 | sync(); | 2258 | sync(); |
| 2259 | } | 2259 | } |
| 2260 | catch_memory_errors = 0; | 2260 | catch_memory_errors = 0; |
| 2261 | if (!(*vp)) { | 2261 | if (!(*vp)) { |
| 2262 | printf("unknown symbol '%s'\n", tmpstr); | 2262 | printf("unknown symbol '%s'\n", tmpstr); |
| 2263 | return 0; | 2263 | return 0; |
| 2264 | } | 2264 | } |
| 2265 | return 1; | 2265 | return 1; |
| 2266 | } | 2266 | } |
| 2267 | 2267 | ||
| 2268 | d = hexdigit(c); | 2268 | d = hexdigit(c); |
| 2269 | if (d == EOF) { | 2269 | if (d == EOF) { |
| 2270 | termch = c; | 2270 | termch = c; |
| 2271 | return 0; | 2271 | return 0; |
| 2272 | } | 2272 | } |
| 2273 | v = 0; | 2273 | v = 0; |
| 2274 | do { | 2274 | do { |
| 2275 | v = (v << 4) + d; | 2275 | v = (v << 4) + d; |
| 2276 | c = inchar(); | 2276 | c = inchar(); |
| 2277 | d = hexdigit(c); | 2277 | d = hexdigit(c); |
| 2278 | } while (d != EOF); | 2278 | } while (d != EOF); |
| 2279 | termch = c; | 2279 | termch = c; |
| 2280 | *vp = v; | 2280 | *vp = v; |
| 2281 | return 1; | 2281 | return 1; |
| 2282 | } | 2282 | } |
| 2283 | 2283 | ||
| 2284 | void | 2284 | void |
| 2285 | scannl(void) | 2285 | scannl(void) |
| 2286 | { | 2286 | { |
| 2287 | int c; | 2287 | int c; |
| 2288 | 2288 | ||
| 2289 | c = termch; | 2289 | c = termch; |
| 2290 | termch = 0; | 2290 | termch = 0; |
| 2291 | while( c != '\n' ) | 2291 | while( c != '\n' ) |
| 2292 | c = inchar(); | 2292 | c = inchar(); |
| 2293 | } | 2293 | } |
| 2294 | 2294 | ||
| 2295 | int | 2295 | int |
| 2296 | hexdigit(int c) | 2296 | hexdigit(int c) |
| 2297 | { | 2297 | { |
| 2298 | if( '0' <= c && c <= '9' ) | 2298 | if( '0' <= c && c <= '9' ) |
| 2299 | return c - '0'; | 2299 | return c - '0'; |
| 2300 | if( 'A' <= c && c <= 'F' ) | 2300 | if( 'A' <= c && c <= 'F' ) |
| 2301 | return c - ('A' - 10); | 2301 | return c - ('A' - 10); |
| 2302 | if( 'a' <= c && c <= 'f' ) | 2302 | if( 'a' <= c && c <= 'f' ) |
| 2303 | return c - ('a' - 10); | 2303 | return c - ('a' - 10); |
| 2304 | return EOF; | 2304 | return EOF; |
| 2305 | } | 2305 | } |
| 2306 | 2306 | ||
| 2307 | void | 2307 | void |
| 2308 | getstring(char *s, int size) | 2308 | getstring(char *s, int size) |
| 2309 | { | 2309 | { |
| 2310 | int c; | 2310 | int c; |
| 2311 | 2311 | ||
| 2312 | c = skipbl(); | 2312 | c = skipbl(); |
| 2313 | do { | 2313 | do { |
| 2314 | if( size > 1 ){ | 2314 | if( size > 1 ){ |
| 2315 | *s++ = c; | 2315 | *s++ = c; |
| 2316 | --size; | 2316 | --size; |
| 2317 | } | 2317 | } |
| 2318 | c = inchar(); | 2318 | c = inchar(); |
| 2319 | } while( c != ' ' && c != '\t' && c != '\n' ); | 2319 | } while( c != ' ' && c != '\t' && c != '\n' ); |
| 2320 | termch = c; | 2320 | termch = c; |
| 2321 | *s = 0; | 2321 | *s = 0; |
| 2322 | } | 2322 | } |
| 2323 | 2323 | ||
| 2324 | static char line[256]; | 2324 | static char line[256]; |
| 2325 | static char *lineptr; | 2325 | static char *lineptr; |
| 2326 | 2326 | ||
| 2327 | void | 2327 | void |
| 2328 | flush_input(void) | 2328 | flush_input(void) |
| 2329 | { | 2329 | { |
| 2330 | lineptr = NULL; | 2330 | lineptr = NULL; |
| 2331 | } | 2331 | } |
| 2332 | 2332 | ||
| 2333 | int | 2333 | int |
| 2334 | inchar(void) | 2334 | inchar(void) |
| 2335 | { | 2335 | { |
| 2336 | if (lineptr == NULL || *lineptr == 0) { | 2336 | if (lineptr == NULL || *lineptr == 0) { |
| 2337 | if (fgets(line, sizeof(line), stdin) == NULL) { | 2337 | if (fgets(line, sizeof(line), stdin) == NULL) { |
| 2338 | lineptr = NULL; | 2338 | lineptr = NULL; |
| 2339 | return EOF; | 2339 | return EOF; |
| 2340 | } | 2340 | } |
| 2341 | lineptr = line; | 2341 | lineptr = line; |
| 2342 | } | 2342 | } |
| 2343 | return *lineptr++; | 2343 | return *lineptr++; |
| 2344 | } | 2344 | } |
| 2345 | 2345 | ||
| 2346 | void | 2346 | void |
| 2347 | take_input(char *str) | 2347 | take_input(char *str) |
| 2348 | { | 2348 | { |
| 2349 | lineptr = str; | 2349 | lineptr = str; |
| 2350 | } | 2350 | } |
| 2351 | 2351 | ||
| 2352 | 2352 | ||
| 2353 | static void | 2353 | static void |
| 2354 | symbol_lookup(void) | 2354 | symbol_lookup(void) |
| 2355 | { | 2355 | { |
| 2356 | int type = inchar(); | 2356 | int type = inchar(); |
| 2357 | unsigned long addr; | 2357 | unsigned long addr; |
| 2358 | static char tmp[64]; | 2358 | static char tmp[64]; |
| 2359 | 2359 | ||
| 2360 | switch (type) { | 2360 | switch (type) { |
| 2361 | case 'a': | 2361 | case 'a': |
| 2362 | if (scanhex(&addr)) | 2362 | if (scanhex(&addr)) |
| 2363 | xmon_print_symbol(addr, ": ", "\n"); | 2363 | xmon_print_symbol(addr, ": ", "\n"); |
| 2364 | termch = 0; | 2364 | termch = 0; |
| 2365 | break; | 2365 | break; |
| 2366 | case 's': | 2366 | case 's': |
| 2367 | getstring(tmp, 64); | 2367 | getstring(tmp, 64); |
| 2368 | if (setjmp(bus_error_jmp) == 0) { | 2368 | if (setjmp(bus_error_jmp) == 0) { |
| 2369 | catch_memory_errors = 1; | 2369 | catch_memory_errors = 1; |
| 2370 | sync(); | 2370 | sync(); |
| 2371 | addr = kallsyms_lookup_name(tmp); | 2371 | addr = kallsyms_lookup_name(tmp); |
| 2372 | if (addr) | 2372 | if (addr) |
| 2373 | printf("%s: %lx\n", tmp, addr); | 2373 | printf("%s: %lx\n", tmp, addr); |
| 2374 | else | 2374 | else |
| 2375 | printf("Symbol '%s' not found.\n", tmp); | 2375 | printf("Symbol '%s' not found.\n", tmp); |
| 2376 | sync(); | 2376 | sync(); |
| 2377 | } | 2377 | } |
| 2378 | catch_memory_errors = 0; | 2378 | catch_memory_errors = 0; |
| 2379 | termch = 0; | 2379 | termch = 0; |
| 2380 | break; | 2380 | break; |
| 2381 | } | 2381 | } |
| 2382 | } | 2382 | } |
| 2383 | 2383 | ||
| 2384 | 2384 | ||
| 2385 | /* Print an address in numeric and symbolic form (if possible) */ | 2385 | /* Print an address in numeric and symbolic form (if possible) */ |
| 2386 | static void xmon_print_symbol(unsigned long address, const char *mid, | 2386 | static void xmon_print_symbol(unsigned long address, const char *mid, |
| 2387 | const char *after) | 2387 | const char *after) |
| 2388 | { | 2388 | { |
| 2389 | char *modname; | 2389 | char *modname; |
| 2390 | const char *name = NULL; | 2390 | const char *name = NULL; |
| 2391 | unsigned long offset, size; | 2391 | unsigned long offset, size; |
| 2392 | 2392 | ||
| 2393 | printf("%.16lx", address); | 2393 | printf("%.16lx", address); |
| 2394 | if (setjmp(bus_error_jmp) == 0) { | 2394 | if (setjmp(bus_error_jmp) == 0) { |
| 2395 | catch_memory_errors = 1; | 2395 | catch_memory_errors = 1; |
| 2396 | sync(); | 2396 | sync(); |
| 2397 | name = kallsyms_lookup(address, &size, &offset, &modname, | 2397 | name = kallsyms_lookup(address, &size, &offset, &modname, |
| 2398 | tmpstr); | 2398 | tmpstr); |
| 2399 | sync(); | 2399 | sync(); |
| 2400 | /* wait a little while to see if we get a machine check */ | 2400 | /* wait a little while to see if we get a machine check */ |
| 2401 | __delay(200); | 2401 | __delay(200); |
| 2402 | } | 2402 | } |
| 2403 | 2403 | ||
| 2404 | catch_memory_errors = 0; | 2404 | catch_memory_errors = 0; |
| 2405 | 2405 | ||
| 2406 | if (name) { | 2406 | if (name) { |
| 2407 | printf("%s%s+%#lx/%#lx", mid, name, offset, size); | 2407 | printf("%s%s+%#lx/%#lx", mid, name, offset, size); |
| 2408 | if (modname) | 2408 | if (modname) |
| 2409 | printf(" [%s]", modname); | 2409 | printf(" [%s]", modname); |
| 2410 | } | 2410 | } |
| 2411 | printf("%s", after); | 2411 | printf("%s", after); |
| 2412 | } | 2412 | } |
| 2413 | 2413 | ||
| 2414 | static void debug_trace(void) | 2414 | static void debug_trace(void) |
| 2415 | { | 2415 | { |
| 2416 | unsigned long val, cmd, on; | 2416 | unsigned long val, cmd, on; |
| 2417 | 2417 | ||
| 2418 | cmd = skipbl(); | 2418 | cmd = skipbl(); |
| 2419 | if (cmd == '\n') { | 2419 | if (cmd == '\n') { |
| 2420 | /* show current state */ | 2420 | /* show current state */ |
| 2421 | unsigned long i; | 2421 | unsigned long i; |
| 2422 | printf("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); | 2422 | printf("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch); |
| 2423 | for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) { | 2423 | for (i = 0; i < PPCDBG_NUM_FLAGS ;i++) { |
| 2424 | on = PPCDBG_BITVAL(i) & ppc64_debug_switch; | 2424 | on = PPCDBG_BITVAL(i) & ppc64_debug_switch; |
| 2425 | printf("%02x %s %12s ", i, on ? "on " : "off", trace_names[i] ? trace_names[i] : ""); | 2425 | printf("%02x %s %12s ", i, on ? "on " : "off", trace_names[i] ? trace_names[i] : ""); |
| 2426 | if (((i+1) % 3) == 0) | 2426 | if (((i+1) % 3) == 0) |
| 2427 | printf("\n"); | 2427 | printf("\n"); |
| 2428 | } | 2428 | } |
| 2429 | printf("\n"); | 2429 | printf("\n"); |
| 2430 | return; | 2430 | return; |
| 2431 | } | 2431 | } |
| 2432 | while (cmd != '\n') { | 2432 | while (cmd != '\n') { |
| 2433 | on = 1; /* default if no sign given */ | 2433 | on = 1; /* default if no sign given */ |
| 2434 | while (cmd == '+' || cmd == '-') { | 2434 | while (cmd == '+' || cmd == '-') { |
| 2435 | on = (cmd == '+'); | 2435 | on = (cmd == '+'); |
| 2436 | cmd = inchar(); | 2436 | cmd = inchar(); |
| 2437 | if (cmd == ' ' || cmd == '\n') { /* Turn on or off based on + or - */ | 2437 | if (cmd == ' ' || cmd == '\n') { /* Turn on or off based on + or - */ |
| 2438 | ppc64_debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE; | 2438 | ppc64_debug_switch = on ? PPCDBG_ALL:PPCDBG_NONE; |
| 2439 | printf("Setting all values to %s...\n", on ? "on" : "off"); | 2439 | printf("Setting all values to %s...\n", on ? "on" : "off"); |
| 2440 | if (cmd == '\n') return; | 2440 | if (cmd == '\n') return; |
| 2441 | else cmd = skipbl(); | 2441 | else cmd = skipbl(); |
| 2442 | } | 2442 | } |
| 2443 | else | 2443 | else |
| 2444 | termch = cmd; | 2444 | termch = cmd; |
| 2445 | } | 2445 | } |
| 2446 | termch = cmd; /* not +/- ... let scanhex see it */ | 2446 | termch = cmd; /* not +/- ... let scanhex see it */ |
| 2447 | scanhex((void *)&val); | 2447 | scanhex((void *)&val); |
| 2448 | if (val >= 64) { | 2448 | if (val >= 64) { |
| 2449 | printf("Value %x out of range:\n", val); | 2449 | printf("Value %x out of range:\n", val); |
| 2450 | return; | 2450 | return; |
| 2451 | } | 2451 | } |
| 2452 | if (on) { | 2452 | if (on) { |
| 2453 | ppc64_debug_switch |= PPCDBG_BITVAL(val); | 2453 | ppc64_debug_switch |= PPCDBG_BITVAL(val); |
| 2454 | printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); | 2454 | printf("enable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); |
| 2455 | } else { | 2455 | } else { |
| 2456 | ppc64_debug_switch &= ~PPCDBG_BITVAL(val); | 2456 | ppc64_debug_switch &= ~PPCDBG_BITVAL(val); |
| 2457 | printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); | 2457 | printf("disable debug %x %s\n", val, trace_names[val] ? trace_names[val] : ""); |
| 2458 | } | 2458 | } |
| 2459 | cmd = skipbl(); | 2459 | cmd = skipbl(); |
| 2460 | } | 2460 | } |
| 2461 | } | 2461 | } |
| 2462 | 2462 | ||
| 2463 | static void dump_slb(void) | 2463 | static void dump_slb(void) |
| 2464 | { | 2464 | { |
| 2465 | int i; | 2465 | int i; |
| 2466 | unsigned long tmp; | 2466 | unsigned long tmp; |
| 2467 | 2467 | ||
| 2468 | printf("SLB contents of cpu %x\n", smp_processor_id()); | 2468 | printf("SLB contents of cpu %x\n", smp_processor_id()); |
| 2469 | 2469 | ||
| 2470 | for (i = 0; i < SLB_NUM_ENTRIES; i++) { | 2470 | for (i = 0; i < SLB_NUM_ENTRIES; i++) { |
| 2471 | asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i)); | 2471 | asm volatile("slbmfee %0,%1" : "=r" (tmp) : "r" (i)); |
| 2472 | printf("%02d %016lx ", i, tmp); | 2472 | printf("%02d %016lx ", i, tmp); |
| 2473 | 2473 | ||
| 2474 | asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i)); | 2474 | asm volatile("slbmfev %0,%1" : "=r" (tmp) : "r" (i)); |
| 2475 | printf("%016lx\n", tmp); | 2475 | printf("%016lx\n", tmp); |
| 2476 | } | 2476 | } |
| 2477 | } | 2477 | } |
| 2478 | 2478 | ||
| 2479 | static void dump_stab(void) | 2479 | static void dump_stab(void) |
| 2480 | { | 2480 | { |
| 2481 | int i; | 2481 | int i; |
| 2482 | unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; | 2482 | unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; |
| 2483 | 2483 | ||
| 2484 | printf("Segment table contents of cpu %x\n", smp_processor_id()); | 2484 | printf("Segment table contents of cpu %x\n", smp_processor_id()); |
| 2485 | 2485 | ||
| 2486 | for (i = 0; i < PAGE_SIZE/16; i++) { | 2486 | for (i = 0; i < PAGE_SIZE/16; i++) { |
| 2487 | unsigned long a, b; | 2487 | unsigned long a, b; |
| 2488 | 2488 | ||
| 2489 | a = *tmp++; | 2489 | a = *tmp++; |
| 2490 | b = *tmp++; | 2490 | b = *tmp++; |
| 2491 | 2491 | ||
| 2492 | if (a || b) { | 2492 | if (a || b) { |
| 2493 | printf("%03d %016lx ", i, a); | 2493 | printf("%03d %016lx ", i, a); |
| 2494 | printf("%016lx\n", b); | 2494 | printf("%016lx\n", b); |
| 2495 | } | 2495 | } |
| 2496 | } | 2496 | } |
| 2497 | } | 2497 | } |
| 2498 | 2498 | ||
| 2499 | void xmon_init(void) | 2499 | void xmon_init(int enable) |
| 2500 | { | 2500 | { |
| 2501 | __debugger = xmon; | 2501 | if (enable) { |
| 2502 | __debugger_ipi = xmon_ipi; | 2502 | __debugger = xmon; |
| 2503 | __debugger_bpt = xmon_bpt; | 2503 | __debugger_ipi = xmon_ipi; |
| 2504 | __debugger_sstep = xmon_sstep; | 2504 | __debugger_bpt = xmon_bpt; |
| 2505 | __debugger_iabr_match = xmon_iabr_match; | 2505 | __debugger_sstep = xmon_sstep; |
| 2506 | __debugger_dabr_match = xmon_dabr_match; | 2506 | __debugger_iabr_match = xmon_iabr_match; |
| 2507 | __debugger_fault_handler = xmon_fault_handler; | 2507 | __debugger_dabr_match = xmon_dabr_match; |
| 2508 | __debugger_fault_handler = xmon_fault_handler; | ||
| 2509 | } else { | ||
| 2510 | __debugger = NULL; | ||
| 2511 | __debugger_ipi = NULL; | ||
| 2512 | __debugger_bpt = NULL; | ||
| 2513 | __debugger_sstep = NULL; | ||
| 2514 | __debugger_iabr_match = NULL; | ||
| 2515 | __debugger_dabr_match = NULL; | ||
| 2516 | __debugger_fault_handler = NULL; | ||
| 2517 | } | ||
| 2508 | } | 2518 | } |
| 2509 | 2519 | ||
| 2510 | void dump_segments(void) | 2520 | void dump_segments(void) |
| 2511 | { | 2521 | { |
| 2512 | if (cpu_has_feature(CPU_FTR_SLB)) | 2522 | if (cpu_has_feature(CPU_FTR_SLB)) |
| 2513 | dump_slb(); | 2523 | dump_slb(); |
| 2514 | else | 2524 | else |
| 2515 | dump_stab(); | 2525 | dump_stab(); |
| 2516 | } | 2526 | } |
| 2517 | 2527 |
include/asm-ppc64/system.h
| 1 | #ifndef __PPC64_SYSTEM_H | 1 | #ifndef __PPC64_SYSTEM_H |
| 2 | #define __PPC64_SYSTEM_H | 2 | #define __PPC64_SYSTEM_H |
| 3 | 3 | ||
| 4 | /* | 4 | /* |
| 5 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
| 6 | * modify it under the terms of the GNU General Public License | 6 | * modify it under the terms of the GNU General Public License |
| 7 | * as published by the Free Software Foundation; either version | 7 | * as published by the Free Software Foundation; either version |
| 8 | * 2 of the License, or (at your option) any later version. | 8 | * 2 of the License, or (at your option) any later version. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/config.h> | 11 | #include <linux/config.h> |
| 12 | #include <linux/compiler.h> | 12 | #include <linux/compiler.h> |
| 13 | #include <asm/page.h> | 13 | #include <asm/page.h> |
| 14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
| 15 | #include <asm/hw_irq.h> | 15 | #include <asm/hw_irq.h> |
| 16 | #include <asm/memory.h> | 16 | #include <asm/memory.h> |
| 17 | 17 | ||
| 18 | /* | 18 | /* |
| 19 | * Memory barrier. | 19 | * Memory barrier. |
| 20 | * The sync instruction guarantees that all memory accesses initiated | 20 | * The sync instruction guarantees that all memory accesses initiated |
| 21 | * by this processor have been performed (with respect to all other | 21 | * by this processor have been performed (with respect to all other |
| 22 | * mechanisms that access memory). The eieio instruction is a barrier | 22 | * mechanisms that access memory). The eieio instruction is a barrier |
| 23 | * providing an ordering (separately) for (a) cacheable stores and (b) | 23 | * providing an ordering (separately) for (a) cacheable stores and (b) |
| 24 | * loads and stores to non-cacheable memory (e.g. I/O devices). | 24 | * loads and stores to non-cacheable memory (e.g. I/O devices). |
| 25 | * | 25 | * |
| 26 | * mb() prevents loads and stores being reordered across this point. | 26 | * mb() prevents loads and stores being reordered across this point. |
| 27 | * rmb() prevents loads being reordered across this point. | 27 | * rmb() prevents loads being reordered across this point. |
| 28 | * wmb() prevents stores being reordered across this point. | 28 | * wmb() prevents stores being reordered across this point. |
| 29 | * read_barrier_depends() prevents data-dependent loads being reordered | 29 | * read_barrier_depends() prevents data-dependent loads being reordered |
| 30 | * across this point (nop on PPC). | 30 | * across this point (nop on PPC). |
| 31 | * | 31 | * |
| 32 | * We have to use the sync instructions for mb(), since lwsync doesn't | 32 | * We have to use the sync instructions for mb(), since lwsync doesn't |
| 33 | * order loads with respect to previous stores. Lwsync is fine for | 33 | * order loads with respect to previous stores. Lwsync is fine for |
| 34 | * rmb(), though. | 34 | * rmb(), though. |
| 35 | * For wmb(), we use sync since wmb is used in drivers to order | 35 | * For wmb(), we use sync since wmb is used in drivers to order |
| 36 | * stores to system memory with respect to writes to the device. | 36 | * stores to system memory with respect to writes to the device. |
| 37 | * However, smp_wmb() can be a lighter-weight eieio barrier on | 37 | * However, smp_wmb() can be a lighter-weight eieio barrier on |
| 38 | * SMP since it is only used to order updates to system memory. | 38 | * SMP since it is only used to order updates to system memory. |
| 39 | */ | 39 | */ |
| 40 | #define mb() __asm__ __volatile__ ("sync" : : : "memory") | 40 | #define mb() __asm__ __volatile__ ("sync" : : : "memory") |
| 41 | #define rmb() __asm__ __volatile__ ("lwsync" : : : "memory") | 41 | #define rmb() __asm__ __volatile__ ("lwsync" : : : "memory") |
| 42 | #define wmb() __asm__ __volatile__ ("sync" : : : "memory") | 42 | #define wmb() __asm__ __volatile__ ("sync" : : : "memory") |
| 43 | #define read_barrier_depends() do { } while(0) | 43 | #define read_barrier_depends() do { } while(0) |
| 44 | 44 | ||
| 45 | #define set_mb(var, value) do { var = value; smp_mb(); } while (0) | 45 | #define set_mb(var, value) do { var = value; smp_mb(); } while (0) |
| 46 | #define set_wmb(var, value) do { var = value; smp_wmb(); } while (0) | 46 | #define set_wmb(var, value) do { var = value; smp_wmb(); } while (0) |
| 47 | 47 | ||
| 48 | #ifdef CONFIG_SMP | 48 | #ifdef CONFIG_SMP |
| 49 | #define smp_mb() mb() | 49 | #define smp_mb() mb() |
| 50 | #define smp_rmb() rmb() | 50 | #define smp_rmb() rmb() |
| 51 | #define smp_wmb() __asm__ __volatile__ ("eieio" : : : "memory") | 51 | #define smp_wmb() __asm__ __volatile__ ("eieio" : : : "memory") |
| 52 | #define smp_read_barrier_depends() read_barrier_depends() | 52 | #define smp_read_barrier_depends() read_barrier_depends() |
| 53 | #else | 53 | #else |
| 54 | #define smp_mb() __asm__ __volatile__("": : :"memory") | 54 | #define smp_mb() __asm__ __volatile__("": : :"memory") |
| 55 | #define smp_rmb() __asm__ __volatile__("": : :"memory") | 55 | #define smp_rmb() __asm__ __volatile__("": : :"memory") |
| 56 | #define smp_wmb() __asm__ __volatile__("": : :"memory") | 56 | #define smp_wmb() __asm__ __volatile__("": : :"memory") |
| 57 | #define smp_read_barrier_depends() do { } while(0) | 57 | #define smp_read_barrier_depends() do { } while(0) |
| 58 | #endif /* CONFIG_SMP */ | 58 | #endif /* CONFIG_SMP */ |
| 59 | 59 | ||
| 60 | #ifdef __KERNEL__ | 60 | #ifdef __KERNEL__ |
| 61 | struct task_struct; | 61 | struct task_struct; |
| 62 | struct pt_regs; | 62 | struct pt_regs; |
| 63 | 63 | ||
| 64 | #ifdef CONFIG_DEBUGGER | 64 | #ifdef CONFIG_DEBUGGER |
| 65 | 65 | ||
| 66 | extern int (*__debugger)(struct pt_regs *regs); | 66 | extern int (*__debugger)(struct pt_regs *regs); |
| 67 | extern int (*__debugger_ipi)(struct pt_regs *regs); | 67 | extern int (*__debugger_ipi)(struct pt_regs *regs); |
| 68 | extern int (*__debugger_bpt)(struct pt_regs *regs); | 68 | extern int (*__debugger_bpt)(struct pt_regs *regs); |
| 69 | extern int (*__debugger_sstep)(struct pt_regs *regs); | 69 | extern int (*__debugger_sstep)(struct pt_regs *regs); |
| 70 | extern int (*__debugger_iabr_match)(struct pt_regs *regs); | 70 | extern int (*__debugger_iabr_match)(struct pt_regs *regs); |
| 71 | extern int (*__debugger_dabr_match)(struct pt_regs *regs); | 71 | extern int (*__debugger_dabr_match)(struct pt_regs *regs); |
| 72 | extern int (*__debugger_fault_handler)(struct pt_regs *regs); | 72 | extern int (*__debugger_fault_handler)(struct pt_regs *regs); |
| 73 | 73 | ||
| 74 | #define DEBUGGER_BOILERPLATE(__NAME) \ | 74 | #define DEBUGGER_BOILERPLATE(__NAME) \ |
| 75 | static inline int __NAME(struct pt_regs *regs) \ | 75 | static inline int __NAME(struct pt_regs *regs) \ |
| 76 | { \ | 76 | { \ |
| 77 | if (unlikely(__ ## __NAME)) \ | 77 | if (unlikely(__ ## __NAME)) \ |
| 78 | return __ ## __NAME(regs); \ | 78 | return __ ## __NAME(regs); \ |
| 79 | return 0; \ | 79 | return 0; \ |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | DEBUGGER_BOILERPLATE(debugger) | 82 | DEBUGGER_BOILERPLATE(debugger) |
| 83 | DEBUGGER_BOILERPLATE(debugger_ipi) | 83 | DEBUGGER_BOILERPLATE(debugger_ipi) |
| 84 | DEBUGGER_BOILERPLATE(debugger_bpt) | 84 | DEBUGGER_BOILERPLATE(debugger_bpt) |
| 85 | DEBUGGER_BOILERPLATE(debugger_sstep) | 85 | DEBUGGER_BOILERPLATE(debugger_sstep) |
| 86 | DEBUGGER_BOILERPLATE(debugger_iabr_match) | 86 | DEBUGGER_BOILERPLATE(debugger_iabr_match) |
| 87 | DEBUGGER_BOILERPLATE(debugger_dabr_match) | 87 | DEBUGGER_BOILERPLATE(debugger_dabr_match) |
| 88 | DEBUGGER_BOILERPLATE(debugger_fault_handler) | 88 | DEBUGGER_BOILERPLATE(debugger_fault_handler) |
| 89 | 89 | ||
| 90 | #ifdef CONFIG_XMON | 90 | #ifdef CONFIG_XMON |
| 91 | extern void xmon_init(void); | 91 | extern void xmon_init(int enable); |
| 92 | #endif | 92 | #endif |
| 93 | 93 | ||
| 94 | #else | 94 | #else |
| 95 | static inline int debugger(struct pt_regs *regs) { return 0; } | 95 | static inline int debugger(struct pt_regs *regs) { return 0; } |
| 96 | static inline int debugger_ipi(struct pt_regs *regs) { return 0; } | 96 | static inline int debugger_ipi(struct pt_regs *regs) { return 0; } |
| 97 | static inline int debugger_bpt(struct pt_regs *regs) { return 0; } | 97 | static inline int debugger_bpt(struct pt_regs *regs) { return 0; } |
| 98 | static inline int debugger_sstep(struct pt_regs *regs) { return 0; } | 98 | static inline int debugger_sstep(struct pt_regs *regs) { return 0; } |
| 99 | static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; } | 99 | static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; } |
| 100 | static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } | 100 | static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; } |
| 101 | static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } | 101 | static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; } |
| 102 | #endif | 102 | #endif |
| 103 | 103 | ||
| 104 | extern int fix_alignment(struct pt_regs *regs); | 104 | extern int fix_alignment(struct pt_regs *regs); |
| 105 | extern void bad_page_fault(struct pt_regs *regs, unsigned long address, | 105 | extern void bad_page_fault(struct pt_regs *regs, unsigned long address, |
| 106 | int sig); | 106 | int sig); |
| 107 | extern void show_regs(struct pt_regs * regs); | 107 | extern void show_regs(struct pt_regs * regs); |
| 108 | extern void low_hash_fault(struct pt_regs *regs, unsigned long address); | 108 | extern void low_hash_fault(struct pt_regs *regs, unsigned long address); |
| 109 | extern int die(const char *str, struct pt_regs *regs, long err); | 109 | extern int die(const char *str, struct pt_regs *regs, long err); |
| 110 | 110 | ||
| 111 | extern int _get_PVR(void); | 111 | extern int _get_PVR(void); |
| 112 | extern void giveup_fpu(struct task_struct *); | 112 | extern void giveup_fpu(struct task_struct *); |
| 113 | extern void disable_kernel_fp(void); | 113 | extern void disable_kernel_fp(void); |
| 114 | extern void flush_fp_to_thread(struct task_struct *); | 114 | extern void flush_fp_to_thread(struct task_struct *); |
| 115 | extern void enable_kernel_fp(void); | 115 | extern void enable_kernel_fp(void); |
| 116 | extern void giveup_altivec(struct task_struct *); | 116 | extern void giveup_altivec(struct task_struct *); |
| 117 | extern void disable_kernel_altivec(void); | 117 | extern void disable_kernel_altivec(void); |
| 118 | extern void enable_kernel_altivec(void); | 118 | extern void enable_kernel_altivec(void); |
| 119 | extern int emulate_altivec(struct pt_regs *); | 119 | extern int emulate_altivec(struct pt_regs *); |
| 120 | extern void cvt_fd(float *from, double *to, unsigned long *fpscr); | 120 | extern void cvt_fd(float *from, double *to, unsigned long *fpscr); |
| 121 | extern void cvt_df(double *from, float *to, unsigned long *fpscr); | 121 | extern void cvt_df(double *from, float *to, unsigned long *fpscr); |
| 122 | 122 | ||
| 123 | #ifdef CONFIG_ALTIVEC | 123 | #ifdef CONFIG_ALTIVEC |
| 124 | extern void flush_altivec_to_thread(struct task_struct *); | 124 | extern void flush_altivec_to_thread(struct task_struct *); |
| 125 | #else | 125 | #else |
| 126 | static inline void flush_altivec_to_thread(struct task_struct *t) | 126 | static inline void flush_altivec_to_thread(struct task_struct *t) |
| 127 | { | 127 | { |
| 128 | } | 128 | } |
| 129 | #endif | 129 | #endif |
| 130 | 130 | ||
| 131 | extern int mem_init_done; /* set on boot once kmalloc can be called */ | 131 | extern int mem_init_done; /* set on boot once kmalloc can be called */ |
| 132 | 132 | ||
| 133 | /* EBCDIC -> ASCII conversion for [0-9A-Z] on iSeries */ | 133 | /* EBCDIC -> ASCII conversion for [0-9A-Z] on iSeries */ |
| 134 | extern unsigned char e2a(unsigned char); | 134 | extern unsigned char e2a(unsigned char); |
| 135 | 135 | ||
| 136 | extern struct task_struct *__switch_to(struct task_struct *, | 136 | extern struct task_struct *__switch_to(struct task_struct *, |
| 137 | struct task_struct *); | 137 | struct task_struct *); |
| 138 | #define switch_to(prev, next, last) ((last) = __switch_to((prev), (next))) | 138 | #define switch_to(prev, next, last) ((last) = __switch_to((prev), (next))) |
| 139 | 139 | ||
| 140 | struct thread_struct; | 140 | struct thread_struct; |
| 141 | extern struct task_struct * _switch(struct thread_struct *prev, | 141 | extern struct task_struct * _switch(struct thread_struct *prev, |
| 142 | struct thread_struct *next); | 142 | struct thread_struct *next); |
| 143 | 143 | ||
| 144 | static inline int __is_processor(unsigned long pv) | 144 | static inline int __is_processor(unsigned long pv) |
| 145 | { | 145 | { |
| 146 | unsigned long pvr; | 146 | unsigned long pvr; |
| 147 | asm("mfspr %0, 0x11F" : "=r" (pvr)); | 147 | asm("mfspr %0, 0x11F" : "=r" (pvr)); |
| 148 | return(PVR_VER(pvr) == pv); | 148 | return(PVR_VER(pvr) == pv); |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | /* | 151 | /* |
| 152 | * Atomic exchange | 152 | * Atomic exchange |
| 153 | * | 153 | * |
| 154 | * Changes the memory location '*ptr' to be val and returns | 154 | * Changes the memory location '*ptr' to be val and returns |
| 155 | * the previous value stored there. | 155 | * the previous value stored there. |
| 156 | * | 156 | * |
| 157 | * Inline asm pulled from arch/ppc/kernel/misc.S so ppc64 | 157 | * Inline asm pulled from arch/ppc/kernel/misc.S so ppc64 |
| 158 | * is more like most of the other architectures. | 158 | * is more like most of the other architectures. |
| 159 | */ | 159 | */ |
| 160 | static __inline__ unsigned long | 160 | static __inline__ unsigned long |
| 161 | __xchg_u32(volatile int *m, unsigned long val) | 161 | __xchg_u32(volatile int *m, unsigned long val) |
| 162 | { | 162 | { |
| 163 | unsigned long dummy; | 163 | unsigned long dummy; |
| 164 | 164 | ||
| 165 | __asm__ __volatile__( | 165 | __asm__ __volatile__( |
| 166 | EIEIO_ON_SMP | 166 | EIEIO_ON_SMP |
| 167 | "1: lwarx %0,0,%3 # __xchg_u32\n\ | 167 | "1: lwarx %0,0,%3 # __xchg_u32\n\ |
| 168 | stwcx. %2,0,%3\n\ | 168 | stwcx. %2,0,%3\n\ |
| 169 | 2: bne- 1b" | 169 | 2: bne- 1b" |
| 170 | ISYNC_ON_SMP | 170 | ISYNC_ON_SMP |
| 171 | : "=&r" (dummy), "=m" (*m) | 171 | : "=&r" (dummy), "=m" (*m) |
| 172 | : "r" (val), "r" (m) | 172 | : "r" (val), "r" (m) |
| 173 | : "cc", "memory"); | 173 | : "cc", "memory"); |
| 174 | 174 | ||
| 175 | return (dummy); | 175 | return (dummy); |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | static __inline__ unsigned long | 178 | static __inline__ unsigned long |
| 179 | __xchg_u64(volatile long *m, unsigned long val) | 179 | __xchg_u64(volatile long *m, unsigned long val) |
| 180 | { | 180 | { |
| 181 | unsigned long dummy; | 181 | unsigned long dummy; |
| 182 | 182 | ||
| 183 | __asm__ __volatile__( | 183 | __asm__ __volatile__( |
| 184 | EIEIO_ON_SMP | 184 | EIEIO_ON_SMP |
| 185 | "1: ldarx %0,0,%3 # __xchg_u64\n\ | 185 | "1: ldarx %0,0,%3 # __xchg_u64\n\ |
| 186 | stdcx. %2,0,%3\n\ | 186 | stdcx. %2,0,%3\n\ |
| 187 | 2: bne- 1b" | 187 | 2: bne- 1b" |
| 188 | ISYNC_ON_SMP | 188 | ISYNC_ON_SMP |
| 189 | : "=&r" (dummy), "=m" (*m) | 189 | : "=&r" (dummy), "=m" (*m) |
| 190 | : "r" (val), "r" (m) | 190 | : "r" (val), "r" (m) |
| 191 | : "cc", "memory"); | 191 | : "cc", "memory"); |
| 192 | 192 | ||
| 193 | return (dummy); | 193 | return (dummy); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | /* | 196 | /* |
| 197 | * This function doesn't exist, so you'll get a linker error | 197 | * This function doesn't exist, so you'll get a linker error |
| 198 | * if something tries to do an invalid xchg(). | 198 | * if something tries to do an invalid xchg(). |
| 199 | */ | 199 | */ |
| 200 | extern void __xchg_called_with_bad_pointer(void); | 200 | extern void __xchg_called_with_bad_pointer(void); |
| 201 | 201 | ||
| 202 | static __inline__ unsigned long | 202 | static __inline__ unsigned long |
| 203 | __xchg(volatile void *ptr, unsigned long x, int size) | 203 | __xchg(volatile void *ptr, unsigned long x, int size) |
| 204 | { | 204 | { |
| 205 | switch (size) { | 205 | switch (size) { |
| 206 | case 4: | 206 | case 4: |
| 207 | return __xchg_u32(ptr, x); | 207 | return __xchg_u32(ptr, x); |
| 208 | case 8: | 208 | case 8: |
| 209 | return __xchg_u64(ptr, x); | 209 | return __xchg_u64(ptr, x); |
| 210 | } | 210 | } |
| 211 | __xchg_called_with_bad_pointer(); | 211 | __xchg_called_with_bad_pointer(); |
| 212 | return x; | 212 | return x; |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | #define xchg(ptr,x) \ | 215 | #define xchg(ptr,x) \ |
| 216 | ({ \ | 216 | ({ \ |
| 217 | __typeof__(*(ptr)) _x_ = (x); \ | 217 | __typeof__(*(ptr)) _x_ = (x); \ |
| 218 | (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \ | 218 | (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \ |
| 219 | }) | 219 | }) |
| 220 | 220 | ||
| 221 | #define tas(ptr) (xchg((ptr),1)) | 221 | #define tas(ptr) (xchg((ptr),1)) |
| 222 | 222 | ||
| 223 | #define __HAVE_ARCH_CMPXCHG 1 | 223 | #define __HAVE_ARCH_CMPXCHG 1 |
| 224 | 224 | ||
| 225 | static __inline__ unsigned long | 225 | static __inline__ unsigned long |
| 226 | __cmpxchg_u32(volatile int *p, int old, int new) | 226 | __cmpxchg_u32(volatile int *p, int old, int new) |
| 227 | { | 227 | { |
| 228 | unsigned int prev; | 228 | unsigned int prev; |
| 229 | 229 | ||
| 230 | __asm__ __volatile__ ( | 230 | __asm__ __volatile__ ( |
| 231 | EIEIO_ON_SMP | 231 | EIEIO_ON_SMP |
| 232 | "1: lwarx %0,0,%2 # __cmpxchg_u32\n\ | 232 | "1: lwarx %0,0,%2 # __cmpxchg_u32\n\ |
| 233 | cmpw 0,%0,%3\n\ | 233 | cmpw 0,%0,%3\n\ |
| 234 | bne- 2f\n\ | 234 | bne- 2f\n\ |
| 235 | stwcx. %4,0,%2\n\ | 235 | stwcx. %4,0,%2\n\ |
| 236 | bne- 1b" | 236 | bne- 1b" |
| 237 | ISYNC_ON_SMP | 237 | ISYNC_ON_SMP |
| 238 | "\n\ | 238 | "\n\ |
| 239 | 2:" | 239 | 2:" |
| 240 | : "=&r" (prev), "=m" (*p) | 240 | : "=&r" (prev), "=m" (*p) |
| 241 | : "r" (p), "r" (old), "r" (new), "m" (*p) | 241 | : "r" (p), "r" (old), "r" (new), "m" (*p) |
| 242 | : "cc", "memory"); | 242 | : "cc", "memory"); |
| 243 | 243 | ||
| 244 | return prev; | 244 | return prev; |
| 245 | } | 245 | } |
| 246 | 246 | ||
| 247 | static __inline__ unsigned long | 247 | static __inline__ unsigned long |
| 248 | __cmpxchg_u64(volatile long *p, unsigned long old, unsigned long new) | 248 | __cmpxchg_u64(volatile long *p, unsigned long old, unsigned long new) |
| 249 | { | 249 | { |
| 250 | unsigned long prev; | 250 | unsigned long prev; |
| 251 | 251 | ||
| 252 | __asm__ __volatile__ ( | 252 | __asm__ __volatile__ ( |
| 253 | EIEIO_ON_SMP | 253 | EIEIO_ON_SMP |
| 254 | "1: ldarx %0,0,%2 # __cmpxchg_u64\n\ | 254 | "1: ldarx %0,0,%2 # __cmpxchg_u64\n\ |
| 255 | cmpd 0,%0,%3\n\ | 255 | cmpd 0,%0,%3\n\ |
| 256 | bne- 2f\n\ | 256 | bne- 2f\n\ |
| 257 | stdcx. %4,0,%2\n\ | 257 | stdcx. %4,0,%2\n\ |
| 258 | bne- 1b" | 258 | bne- 1b" |
| 259 | ISYNC_ON_SMP | 259 | ISYNC_ON_SMP |
| 260 | "\n\ | 260 | "\n\ |
| 261 | 2:" | 261 | 2:" |
| 262 | : "=&r" (prev), "=m" (*p) | 262 | : "=&r" (prev), "=m" (*p) |
| 263 | : "r" (p), "r" (old), "r" (new), "m" (*p) | 263 | : "r" (p), "r" (old), "r" (new), "m" (*p) |
| 264 | : "cc", "memory"); | 264 | : "cc", "memory"); |
| 265 | 265 | ||
| 266 | return prev; | 266 | return prev; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | /* This function doesn't exist, so you'll get a linker error | 269 | /* This function doesn't exist, so you'll get a linker error |
| 270 | if something tries to do an invalid cmpxchg(). */ | 270 | if something tries to do an invalid cmpxchg(). */ |
| 271 | extern void __cmpxchg_called_with_bad_pointer(void); | 271 | extern void __cmpxchg_called_with_bad_pointer(void); |
| 272 | 272 | ||
| 273 | static __inline__ unsigned long | 273 | static __inline__ unsigned long |
| 274 | __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | 274 | __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) |
| 275 | { | 275 | { |
| 276 | switch (size) { | 276 | switch (size) { |
| 277 | case 4: | 277 | case 4: |
| 278 | return __cmpxchg_u32(ptr, old, new); | 278 | return __cmpxchg_u32(ptr, old, new); |
| 279 | case 8: | 279 | case 8: |
| 280 | return __cmpxchg_u64(ptr, old, new); | 280 | return __cmpxchg_u64(ptr, old, new); |
| 281 | } | 281 | } |
| 282 | __cmpxchg_called_with_bad_pointer(); | 282 | __cmpxchg_called_with_bad_pointer(); |
| 283 | return old; | 283 | return old; |
| 284 | } | 284 | } |
| 285 | 285 | ||
| 286 | #define cmpxchg(ptr,o,n) \ | 286 | #define cmpxchg(ptr,o,n) \ |
| 287 | ({ \ | 287 | ({ \ |
| 288 | __typeof__(*(ptr)) _o_ = (o); \ | 288 | __typeof__(*(ptr)) _o_ = (o); \ |
| 289 | __typeof__(*(ptr)) _n_ = (n); \ | 289 | __typeof__(*(ptr)) _n_ = (n); \ |
| 290 | (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ | 290 | (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ |
| 291 | (unsigned long)_n_, sizeof(*(ptr))); \ | 291 | (unsigned long)_n_, sizeof(*(ptr))); \ |
| 292 | }) | 292 | }) |
| 293 | 293 | ||
| 294 | /* | 294 | /* |
| 295 | * We handle most unaligned accesses in hardware. On the other hand | 295 | * We handle most unaligned accesses in hardware. On the other hand |
| 296 | * unaligned DMA can be very expensive on some ppc64 IO chips (it does | 296 | * unaligned DMA can be very expensive on some ppc64 IO chips (it does |
| 297 | * powers of 2 writes until it reaches sufficient alignment). | 297 | * powers of 2 writes until it reaches sufficient alignment). |
| 298 | * | 298 | * |
| 299 | * Based on this we disable the IP header alignment in network drivers. | 299 | * Based on this we disable the IP header alignment in network drivers. |
| 300 | */ | 300 | */ |
| 301 | #define NET_IP_ALIGN 0 | 301 | #define NET_IP_ALIGN 0 |
| 302 | 302 | ||
| 303 | #define arch_align_stack(x) (x) | 303 | #define arch_align_stack(x) (x) |
| 304 | 304 | ||
| 305 | extern unsigned long reloc_offset(void); | 305 | extern unsigned long reloc_offset(void); |
| 306 | 306 | ||
| 307 | #endif /* __KERNEL__ */ | 307 | #endif /* __KERNEL__ */ |
| 308 | #endif | 308 | #endif |
| 309 | 309 |