Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* debug-stub.c: debug-mode stub |
| 2 | * |
| 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. |
| 4 | * Written by David Howells (dhowells@redhat.com) |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version |
| 9 | * 2 of the License, or (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | #include <linux/string.h> |
| 13 | #include <linux/kernel.h> |
| 14 | #include <linux/signal.h> |
| 15 | #include <linux/sched.h> |
| 16 | #include <linux/init.h> |
| 17 | #include <linux/serial_reg.h> |
| 18 | |
| 19 | #include <asm/system.h> |
| 20 | #include <asm/serial-regs.h> |
| 21 | #include <asm/timer-regs.h> |
| 22 | #include <asm/irc-regs.h> |
| 23 | #include <asm/gdb-stub.h> |
| 24 | #include "gdb-io.h" |
| 25 | |
| 26 | /* CPU board CON5 */ |
| 27 | #define __UART0(X) (*(volatile uint8_t *)(UART0_BASE + (UART_##X))) |
| 28 | |
| 29 | #define LSR_WAIT_FOR0(STATE) \ |
| 30 | do { \ |
| 31 | } while (!(__UART0(LSR) & UART_LSR_##STATE)) |
| 32 | |
| 33 | #define FLOWCTL_QUERY0(LINE) ({ __UART0(MSR) & UART_MSR_##LINE; }) |
| 34 | #define FLOWCTL_CLEAR0(LINE) do { __UART0(MCR) &= ~UART_MCR_##LINE; } while (0) |
| 35 | #define FLOWCTL_SET0(LINE) do { __UART0(MCR) |= UART_MCR_##LINE; } while (0) |
| 36 | |
| 37 | #define FLOWCTL_WAIT_FOR0(LINE) \ |
| 38 | do { \ |
| 39 | gdbstub_do_rx(); \ |
| 40 | } while(!FLOWCTL_QUERY(LINE)) |
| 41 | |
David Howells | 84e8cd6 | 2006-07-10 04:44:55 -0700 | [diff] [blame] | 42 | struct frv_debug_status __debug_status; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 43 | |
David Howells | 84e8cd6 | 2006-07-10 04:44:55 -0700 | [diff] [blame] | 44 | static void __init debug_stub_init(void); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 45 | |
| 46 | /*****************************************************************************/ |
| 47 | /* |
| 48 | * debug mode handler stub |
| 49 | * - we come here with the CPU in debug mode and with exceptions disabled |
| 50 | * - handle debugging services for userspace |
| 51 | */ |
| 52 | asmlinkage void debug_stub(void) |
| 53 | { |
| 54 | unsigned long hsr0; |
| 55 | int type = 0; |
| 56 | |
| 57 | static u8 inited = 0; |
| 58 | if (!inited) { |
| 59 | debug_stub_init(); |
| 60 | type = -1; |
| 61 | inited = 1; |
| 62 | } |
| 63 | |
| 64 | hsr0 = __get_HSR(0); |
| 65 | if (hsr0 & HSR0_ETMD) |
| 66 | __set_HSR(0, hsr0 & ~HSR0_ETMD); |
| 67 | |
| 68 | /* disable single stepping */ |
David Howells | 84e8cd6 | 2006-07-10 04:44:55 -0700 | [diff] [blame] | 69 | __debug_status.dcr &= ~DCR_SE; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 70 | |
| 71 | /* kernel mode can propose an exception be handled in debug mode by jumping to a special |
| 72 | * location */ |
| 73 | if (__debug_frame->pc == (unsigned long) __break_hijack_kernel_event_breaks_here) { |
| 74 | /* replace the debug frame with the kernel frame and discard |
| 75 | * the top kernel context */ |
| 76 | *__debug_frame = *__frame; |
| 77 | __frame = __debug_frame->next_frame; |
David Howells | 84e8cd6 | 2006-07-10 04:44:55 -0700 | [diff] [blame] | 78 | __debug_status.brr = (__debug_frame->tbr & TBR_TT) << 12; |
| 79 | __debug_status.brr |= BRR_EB; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | } |
| 81 | |
| 82 | if (__debug_frame->pc == (unsigned long) __debug_bug_trap + 4) { |
| 83 | __debug_frame->pc = __debug_frame->lr; |
| 84 | type = __debug_frame->gr8; |
| 85 | } |
| 86 | |
| 87 | #ifdef CONFIG_GDBSTUB |
| 88 | gdbstub(type); |
| 89 | #endif |
| 90 | |
| 91 | if (hsr0 & HSR0_ETMD) |
| 92 | __set_HSR(0, __get_HSR(0) | HSR0_ETMD); |
| 93 | |
| 94 | } /* end debug_stub() */ |
| 95 | |
| 96 | /*****************************************************************************/ |
| 97 | /* |
| 98 | * debug stub initialisation |
| 99 | */ |
| 100 | static void __init debug_stub_init(void) |
| 101 | { |
| 102 | __set_IRR(6, 0xff000000); /* map ERRs to NMI */ |
| 103 | __set_IITMR(1, 0x20000000); /* ERR0/1, UART0/1 IRQ detect levels */ |
| 104 | |
| 105 | asm volatile(" movgs gr0,ibar0 \n" |
| 106 | " movgs gr0,ibar1 \n" |
| 107 | " movgs gr0,ibar2 \n" |
| 108 | " movgs gr0,ibar3 \n" |
| 109 | " movgs gr0,dbar0 \n" |
| 110 | " movgs gr0,dbmr00 \n" |
| 111 | " movgs gr0,dbmr01 \n" |
| 112 | " movgs gr0,dbdr00 \n" |
| 113 | " movgs gr0,dbdr01 \n" |
| 114 | " movgs gr0,dbar1 \n" |
| 115 | " movgs gr0,dbmr10 \n" |
| 116 | " movgs gr0,dbmr11 \n" |
| 117 | " movgs gr0,dbdr10 \n" |
| 118 | " movgs gr0,dbdr11 \n" |
| 119 | ); |
| 120 | |
| 121 | /* deal with debugging stub initialisation and initial pause */ |
| 122 | if (__debug_frame->pc == (unsigned long) __debug_stub_init_break) |
| 123 | __debug_frame->pc = (unsigned long) start_kernel; |
| 124 | |
| 125 | /* enable the debug events we want to trap */ |
David Howells | 84e8cd6 | 2006-07-10 04:44:55 -0700 | [diff] [blame] | 126 | __debug_status.dcr = DCR_EBE; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | |
| 128 | #ifdef CONFIG_GDBSTUB |
| 129 | gdbstub_init(); |
| 130 | #endif |
| 131 | |
| 132 | __clr_MASK_all(); |
| 133 | __clr_MASK(15); |
| 134 | __clr_RC(15); |
| 135 | |
| 136 | } /* end debug_stub_init() */ |
| 137 | |
| 138 | /*****************************************************************************/ |
| 139 | /* |
| 140 | * kernel "exit" trap for gdb stub |
| 141 | */ |
| 142 | void debug_stub_exit(int status) |
| 143 | { |
| 144 | |
| 145 | #ifdef CONFIG_GDBSTUB |
| 146 | gdbstub_exit(status); |
| 147 | #endif |
| 148 | |
| 149 | } /* end debug_stub_exit() */ |
| 150 | |
| 151 | /*****************************************************************************/ |
| 152 | /* |
| 153 | * send string to serial port |
| 154 | */ |
| 155 | void debug_to_serial(const char *p, int n) |
| 156 | { |
| 157 | char ch; |
| 158 | |
| 159 | for (; n > 0; n--) { |
| 160 | ch = *p++; |
| 161 | FLOWCTL_SET0(DTR); |
| 162 | LSR_WAIT_FOR0(THRE); |
| 163 | // FLOWCTL_WAIT_FOR(CTS); |
| 164 | |
| 165 | if (ch == 0x0a) { |
| 166 | __UART0(TX) = 0x0d; |
| 167 | mb(); |
| 168 | LSR_WAIT_FOR0(THRE); |
| 169 | // FLOWCTL_WAIT_FOR(CTS); |
| 170 | } |
| 171 | __UART0(TX) = ch; |
| 172 | mb(); |
| 173 | |
| 174 | FLOWCTL_CLEAR0(DTR); |
| 175 | } |
| 176 | |
| 177 | } /* end debug_to_serial() */ |
| 178 | |
| 179 | /*****************************************************************************/ |
| 180 | /* |
| 181 | * send string to serial port |
| 182 | */ |
| 183 | void debug_to_serial2(const char *fmt, ...) |
| 184 | { |
| 185 | va_list va; |
| 186 | char buf[64]; |
| 187 | int n; |
| 188 | |
| 189 | va_start(va, fmt); |
| 190 | n = vsprintf(buf, fmt, va); |
| 191 | va_end(va); |
| 192 | |
| 193 | debug_to_serial(buf, n); |
| 194 | |
| 195 | } /* end debug_to_serial2() */ |
| 196 | |
| 197 | /*****************************************************************************/ |
| 198 | /* |
| 199 | * set up the ttyS0 serial port baud rate timers |
| 200 | */ |
| 201 | void __init console_set_baud(unsigned baud) |
| 202 | { |
| 203 | unsigned value, high, low; |
| 204 | u8 lcr; |
| 205 | |
| 206 | /* work out the divisor to give us the nearest higher baud rate */ |
| 207 | value = __serial_clock_speed_HZ / 16 / baud; |
| 208 | |
| 209 | /* determine the baud rate range */ |
| 210 | high = __serial_clock_speed_HZ / 16 / value; |
| 211 | low = __serial_clock_speed_HZ / 16 / (value + 1); |
| 212 | |
| 213 | /* pick the nearest bound */ |
| 214 | if (low + (high - low) / 2 > baud) |
| 215 | value++; |
| 216 | |
| 217 | lcr = __UART0(LCR); |
| 218 | __UART0(LCR) |= UART_LCR_DLAB; |
| 219 | mb(); |
| 220 | __UART0(DLL) = value & 0xff; |
| 221 | __UART0(DLM) = (value >> 8) & 0xff; |
| 222 | mb(); |
| 223 | __UART0(LCR) = lcr; |
| 224 | mb(); |
| 225 | |
| 226 | } /* end console_set_baud() */ |
| 227 | |
| 228 | /*****************************************************************************/ |
| 229 | /* |
| 230 | * |
| 231 | */ |
| 232 | int __init console_get_baud(void) |
| 233 | { |
| 234 | unsigned value; |
| 235 | u8 lcr; |
| 236 | |
| 237 | lcr = __UART0(LCR); |
| 238 | __UART0(LCR) |= UART_LCR_DLAB; |
| 239 | mb(); |
| 240 | value = __UART0(DLM) << 8; |
| 241 | value |= __UART0(DLL); |
| 242 | __UART0(LCR) = lcr; |
| 243 | mb(); |
| 244 | |
| 245 | return value; |
| 246 | } /* end console_get_baud() */ |
| 247 | |
| 248 | /*****************************************************************************/ |
| 249 | /* |
| 250 | * display BUG() info |
| 251 | */ |
| 252 | #ifndef CONFIG_NO_KERNEL_MSG |
| 253 | void __debug_bug_printk(const char *file, unsigned line) |
| 254 | { |
| 255 | printk("kernel BUG at %s:%d!\n", file, line); |
| 256 | |
| 257 | } /* end __debug_bug_printk() */ |
| 258 | #endif |