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