exception.c

Go to the documentation of this file.
00001 #include <console/console.h>
00002 #include <string.h>
00003 
00004 #if CONFIG_GDB_STUB == 1
00005 
00006 /* BUFMAX defines the maximum number of characters in inbound/outbound buffers.
00007  * At least NUM_REGBYTES*2 are needed for register packets 
00008  */
00009 #define BUFMAX 400
00010 enum regnames {
00011         EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
00012         PC /* also known as eip */,
00013         PS /* also known as eflags */,
00014         CS, SS, DS, ES, FS, GS,
00015         NUM_REGS /* Number of registers. */
00016 };
00017 
00018 static uint32_t gdb_stub_registers[NUM_REGS];
00019 
00020 #define GDB_SIG0         0     /* Signal 0 */
00021 #define GDB_SIGHUP       1     /* Hangup */
00022 #define GDB_SIGINT       2     /* Interrupt */
00023 #define GDB_SIGQUIT      3     /* Quit */
00024 #define GDB_SIGILL       4     /* Illegal instruction */
00025 #define GDB_SIGTRAP      5     /* Trace/breakpoint trap */
00026 #define GDB_SIGABRT      6     /* Aborted */
00027 #define GDB_SIGEMT       7     /* Emulation trap */
00028 #define GDB_SIGFPE       8     /* Arithmetic exception */
00029 #define GDB_SIGKILL      9     /* Killed */
00030 #define GDB_SIGBUS       10    /* Bus error */
00031 #define GDB_SIGSEGV      11    /* Segmentation fault */
00032 #define GDB_SIGSYS       12    /* Bad system call */
00033 #define GDB_SIGPIPE      13    /* Broken pipe */
00034 #define GDB_SIGALRM      14    /* Alarm clock */
00035 #define GDB_SIGTERM      15    /* Terminated */
00036 #define GDB_SIGURG       16    /* Urgent I/O condition */
00037 #define GDB_SIGSTOP      17    /* Stopped (signal) */
00038 #define GDB_SIGTSTP      18    /* Stopped (user) */
00039 #define GDB_SIGCONT      19    /* Continued */
00040 #define GDB_SIGCHLD      20    /* Child status changed */
00041 #define GDB_SIGTTIN      21    /* Stopped (tty input) */
00042 #define GDB_SIGTTOU      22    /* Stopped (tty output) */
00043 #define GDB_SIGIO        23    /* I/O possible */
00044 #define GDB_SIGXCPU      24    /* CPU time limit exceeded */
00045 #define GDB_SIGXFSZ      25    /* File size limit exceeded */
00046 #define GDB_SIGVTALRM    26    /* Virtual timer expired */
00047 #define GDB_SIGPROF      27    /* Profiling timer expired */
00048 #define GDB_SIGWINCH     28    /* Window size changed */
00049 #define GDB_SIGLOST      29    /* Resource lost */
00050 #define GDB_SIGUSR1      30    /* User defined signal 1 */
00051 #define GDB_SUGUSR2      31    /* User defined signal 2 */
00052 #define GDB_SIGPWR       32    /* Power fail/restart */
00053 #define GDB_SIGPOLL      33    /* Pollable event occurred */
00054 #define GDB_SIGWIND      34    /* SIGWIND */
00055 #define GDB_SIGPHONE     35    /* SIGPHONE */
00056 #define GDB_SIGWAITING   36    /* Process's LWPs are blocked */
00057 #define GDB_SIGLWP       37    /* Signal LWP */
00058 #define GDB_SIGDANGER    38    /* Swap space dangerously low */
00059 #define GDB_SIGGRANT     39    /* Monitor mode granted */
00060 #define GDB_SIGRETRACT   40    /* Need to relinquish monitor mode */
00061 #define GDB_SIGMSG       41    /* Monitor mode data available */
00062 #define GDB_SIGSOUND     42    /* Sound completed */
00063 #define GDB_SIGSAK       43    /* Secure attention */
00064 #define GDB_SIGPRIO      44    /* SIGPRIO */
00065                         
00066 #define GDB_SIG33        45    /* Real-time event 33 */
00067 #define GDB_SIG34        46    /* Real-time event 34 */
00068 #define GDB_SIG35        47    /* Real-time event 35 */
00069 #define GDB_SIG36        48    /* Real-time event 36 */
00070 #define GDB_SIG37        49    /* Real-time event 37 */
00071 #define GDB_SIG38        50    /* Real-time event 38 */
00072 #define GDB_SIG39        51    /* Real-time event 39 */
00073 #define GDB_SIG40        52    /* Real-time event 40 */
00074 #define GDB_SIG41        53    /* Real-time event 41 */
00075 #define GDB_SIG42        54    /* Real-time event 42 */
00076 #define GDB_SIG43        55    /* Real-time event 43 */
00077 #define GDB_SIG44        56    /* Real-time event 44 */
00078 #define GDB_SIG45        57    /* Real-time event 45 */
00079 #define GDB_SIG46        58    /* Real-time event 46 */
00080 #define GDB_SIG47        59    /* Real-time event 47 */
00081 #define GDB_SIG48        60    /* Real-time event 48 */
00082 #define GDB_SIG49        61    /* Real-time event 49 */
00083 #define GDB_SIG50        62    /* Real-time event 50 */
00084 #define GDB_SIG51        63    /* Real-time event 51 */
00085 #define GDB_SIG52        64    /* Real-time event 52 */
00086 #define GDB_SIG53        65    /* Real-time event 53 */
00087 #define GDB_SIG54        66    /* Real-time event 54 */
00088 #define GDB_SIG55        67    /* Real-time event 55 */
00089 #define GDB_SIG56        68    /* Real-time event 56 */
00090 #define GDB_SIG57        69    /* Real-time event 57 */
00091 #define GDB_SIG58        70    /* Real-time event 58 */
00092 #define GDB_SIG59        71    /* Real-time event 59 */
00093 #define GDB_SIG60        72    /* Real-time event 60 */
00094 #define GDB_SIG61        73    /* Real-time event 61 */
00095 #define GDB_SIG62        74    /* Real-time event 62 */
00096 #define GDB_SIG63        75    /* Real-time event 63 */
00097 #define GDB_SIGCANCEL    76    /* LWP internal signal */
00098 #define GDB_SIG32        77    /* Real-time event 32 */
00099 #define GDB_SIG64        78    /* Real-time event 64 */
00100 #define GDB_SIG65        79    /* Real-time event 65 */
00101 #define GDB_SIG66        80    /* Real-time event 66 */
00102 #define GDB_SIG67        81    /* Real-time event 67 */
00103 #define GDB_SIG68        82    /* Real-time event 68 */
00104 #define GDB_SIG69        83    /* Real-time event 69 */
00105 #define GDB_SIG70        84    /* Real-time event 70 */
00106 #define GDB_SIG71        85    /* Real-time event 71 */
00107 #define GDB_SIG72        86    /* Real-time event 72 */
00108 #define GDB_SIG73        87    /* Real-time event 73 */
00109 #define GDB_SIG74        88    /* Real-time event 74 */
00110 #define GDB_SIG75        89    /* Real-time event 75 */
00111 #define GDB_SIG76        90    /* Real-time event 76 */
00112 #define GDB_SIG77        91    /* Real-time event 77 */
00113 #define GDB_SIG78        92    /* Real-time event 78 */
00114 #define GDB_SIG79        93    /* Real-time event 79 */
00115 #define GDB_SIG80        94    /* Real-time event 80 */
00116 #define GDB_SIG81        95    /* Real-time event 81 */
00117 #define GDB_SIG82        96    /* Real-time event 82 */
00118 #define GDB_SIG83        97    /* Real-time event 83 */
00119 #define GDB_SIG84        98    /* Real-time event 84 */
00120 #define GDB_SIG85        99    /* Real-time event 85 */
00121 #define GDB_SIG86       100    /* Real-time event 86 */
00122 #define GDB_SIG87       101    /* Real-time event 87 */
00123 #define GDB_SIG88       102    /* Real-time event 88 */
00124 #define GDB_SIG89       103    /* Real-time event 89 */
00125 #define GDB_SIG90       104    /* Real-time event 90 */
00126 #define GDB_SIG91       105    /* Real-time event 91 */
00127 #define GDB_SIG92       106    /* Real-time event 92 */
00128 #define GDB_SIG93       107    /* Real-time event 93 */
00129 #define GDB_SIG94       108    /* Real-time event 94 */
00130 #define GDB_SIG95       109    /* Real-time event 95 */
00131 #define GDB_SIG96       110    /* Real-time event 96 */
00132 #define GDB_SIG97       111    /* Real-time event 97 */
00133 #define GDB_SIG98       112    /* Real-time event 98 */
00134 #define GDB_SIG99       113    /* Real-time event 99 */
00135 #define GDB_SIG100      114    /* Real-time event 100 */
00136 #define GDB_SIG101      115    /* Real-time event 101 */
00137 #define GDB_SIG102      116    /* Real-time event 102 */
00138 #define GDB_SIG103      117    /* Real-time event 103 */
00139 #define GDB_SIG104      118    /* Real-time event 104 */
00140 #define GDB_SIG105      119    /* Real-time event 105 */
00141 #define GDB_SIG106      120    /* Real-time event 106 */
00142 #define GDB_SIG107      121    /* Real-time event 107 */
00143 #define GDB_SIG108      122    /* Real-time event 108 */
00144 #define GDB_SIG109      123    /* Real-time event 109 */
00145 #define GDB_SIG110      124    /* Real-time event 110 */
00146 #define GDB_SIG111      125    /* Real-time event 111 */
00147 #define GDB_SIG112      126    /* Real-time event 112 */
00148 #define GDB_SIG113      127    /* Real-time event 113 */
00149 #define GDB_SIG114      128    /* Real-time event 114 */
00150 #define GDB_SIG115      129    /* Real-time event 115 */
00151 #define GDB_SIG116      130    /* Real-time event 116 */
00152 #define GDB_SIG117      131    /* Real-time event 117 */
00153 #define GDB_SIG118      132    /* Real-time event 118 */
00154 #define GDB_SIG119      133    /* Real-time event 119 */
00155 #define GDB_SIG120      134    /* Real-time event 120 */
00156 #define GDB_SIG121      135    /* Real-time event 121 */
00157 #define GDB_SIG122      136    /* Real-time event 122 */
00158 #define GDB_SIG123      137    /* Real-time event 123 */
00159 #define GDB_SIG124      138    /* Real-time event 124 */
00160 #define GDB_SIG125      139    /* Real-time event 125 */
00161 #define GDB_SIG126      140    /* Real-time event 126 */
00162 #define GDB_SIG127      141    /* Real-time event 127 */
00163 #define GDB_SIGINFO     142    /* Information request */
00164 #define GDB_UNKNOWN     143    /* Unknown signal */
00165 #define GDB_DEFAULT     144    /* error: default signal */
00166 /* Mach exceptions */
00167 #define GDB_EXC_BAD_ACCESS     145 /* Could not access memory */
00168 #define GDB_EXC_BAD_INSTRCTION 146 /* Illegal instruction/operand */
00169 #define GDB_EXC_ARITHMETIC     147 /* Arithmetic exception */
00170 #define GDB_EXC_EMULATION      148 /* Emulation instruction */
00171 #define GDB_EXC_SOFTWARE       149 /* Software generated exception */
00172 #define GDB_EXC_BREAKPOINT     150 /* Breakpoint */
00173 
00174 
00175 
00176 static unsigned char exception_to_signal[] =
00177 {
00178         [0]  = GDB_SIGFPE,  /* divide by zero */
00179         [1]  = GDB_SIGTRAP, /* debug exception */
00180         [2]  = GDB_SIGSEGV, /* NMI Interrupt */
00181         [3]  = GDB_SIGTRAP, /* Breakpoint */
00182         [4]  = GDB_SIGSEGV, /* into instruction (overflow) */
00183         [5]  = GDB_SIGSEGV, /* bound instruction */
00184         [6]  = GDB_SIGILL,  /* Invalid opcode */
00185         [7]  = GDB_SIGSEGV, /* coprocessor not available */
00186         [8]  = GDB_SIGSEGV, /* double fault */
00187         [9]  = GDB_SIGFPE,  /* coprocessor segment overrun */
00188         [10] = GDB_SIGSEGV, /* Invalid TSS */
00189         [11] = GDB_SIGBUS,  /* Segment not present */
00190         [12] = GDB_SIGBUS,  /* stack exception */
00191         [13] = GDB_SIGSEGV, /* general protection */
00192         [14] = GDB_SIGSEGV, /* page fault */
00193         [15] = GDB_UNKNOWN, /* reserved */
00194         [16] = GDB_SIGEMT,  /* coprocessor error */
00195         [17] = GDB_SIGBUS,  /* alignment check */
00196         [18] = GDB_SIGSEGV, /* machine check */
00197         [19] = GDB_SIGFPE,  /* simd floating point exception */
00198         [20] = GDB_UNKNOWN,
00199         [21] = GDB_UNKNOWN,
00200         [22] = GDB_UNKNOWN,
00201         [23] = GDB_UNKNOWN,
00202         [24] = GDB_UNKNOWN,
00203         [25] = GDB_UNKNOWN,
00204         [26] = GDB_UNKNOWN,
00205         [27] = GDB_UNKNOWN,
00206         [28] = GDB_UNKNOWN,
00207         [29] = GDB_UNKNOWN,
00208         [30] = GDB_UNKNOWN,
00209         [31] = GDB_UNKNOWN,
00210         [32] = GDB_SIGINT,  /* User interrupt */
00211 };
00212 
00213 static const char hexchars[] = "0123456789abcdef";
00214 static char in_buffer[BUFMAX];
00215 static char out_buffer[BUFMAX];
00216 
00217 
00218 static inline void stub_putc(int ch)
00219 {
00220         console_tx_byte(ch);
00221 }
00222 
00223 static inline int stub_getc(void)
00224 {
00225         return console_rx_byte();
00226 }
00227 
00228 static int hex(char ch)
00229 {
00230         if ((ch >= 'a') && (ch <= 'f'))
00231                 return (ch - 'a' + 10);
00232         if ((ch >= '0') && (ch <= '9'))
00233                 return (ch - '0');
00234         if ((ch >= 'A') && (ch <= 'F'))
00235                 return (ch - 'A' + 10);
00236         return (-1);
00237 }
00238 
00239 /*
00240  * While we find hexadecimal digits, build an int.
00241  * Fals is returned if nothing is parsed true otherwise.
00242  */
00243 static int parse_ulong(char **ptr, unsigned long *value)
00244 {
00245         int digit;
00246         char *start;
00247 
00248         start = *ptr;
00249         *value = 0;
00250 
00251         while((digit = hex(**ptr)) >= 0) {
00252                 *value = ((*value) << 4) | digit;
00253                 (*ptr)++;
00254         }
00255         return start != *ptr;
00256 }
00257 
00258 /* convert the memory pointed to by mem into hex, placing result in buf */
00259 /* return a pointer to the last char put in buf (null) */
00260 static void copy_to_hex(char *buf, void *addr, unsigned long count)
00261 {
00262         unsigned char ch;
00263         char *mem = addr;
00264 
00265         while(count--) {
00266                 ch = *mem++;
00267                 *buf++ = hexchars[ch >> 4];
00268                 *buf++ = hexchars[ch & 0x0f];
00269         }
00270         *buf = 0;
00271         return;
00272 }
00273 
00274 
00275 /* convert the hex array pointed to by buf into binary to be placed in mem */
00276 /* return a pointer to the character AFTER the last byte written */
00277 static void copy_from_hex(void *addr, char *buf, unsigned long count)
00278 {
00279         unsigned char ch;
00280         char *mem = addr;
00281 
00282         while(count--) {
00283                 ch = hex (*buf++) << 4;
00284                 ch = ch + hex (*buf++);
00285                 *mem++ = ch;
00286         }
00287 }
00288 
00289 
00290 /* scan for the sequence $<data>#<checksum>     */
00291 
00292 static int get_packet(char *buffer)
00293 {
00294         unsigned char checksum;
00295         unsigned char xmitcsum;
00296         int count;
00297         char ch;
00298 
00299         /* Wishlit implement a timeout in get_packet */
00300         do {
00301                 /* wait around for the start character, ignore all other characters */
00302                 while ((ch = (stub_getc() & 0x7f)) != '$');
00303                 checksum = 0;
00304                 xmitcsum = -1;
00305 
00306                 count = 0;
00307 
00308                 /* now, read until a # or end of buffer is found */
00309                 while (count < BUFMAX) {
00310                         ch = stub_getc() & 0x7f;
00311                         if (ch == '#')
00312                                 break;
00313                         checksum = checksum + ch;
00314                         buffer[count] = ch;
00315                         count = count + 1;
00316                 }
00317                 buffer[count] = 0;
00318 
00319                 if (ch == '#') {
00320                         xmitcsum = hex(stub_getc() & 0x7f) << 4;
00321                         xmitcsum += hex(stub_getc() & 0x7f);
00322 
00323                         if (checksum != xmitcsum) {
00324                                 stub_putc('-'); /* failed checksum */
00325                         }
00326                         else {
00327                                 stub_putc('+'); /* successful transfer */
00328                         }
00329                 }
00330         } while(checksum != xmitcsum);
00331         return 1;
00332 }
00333 
00334 /* send the packet in buffer.*/
00335 static void put_packet(char *buffer)
00336 {
00337         unsigned char checksum;
00338         int count;
00339         char ch;
00340 
00341         /*  $<packet info>#<checksum>. */
00342         do {
00343                 stub_putc('$');
00344                 checksum = 0;
00345                 count = 0;
00346 
00347                 while ((ch = buffer[count])) {
00348                         stub_putc(ch);
00349                         checksum += ch;
00350                         count += 1;
00351                 }
00352 
00353                 stub_putc('#');
00354                 stub_putc(hexchars[checksum >> 4]);
00355                 stub_putc(hexchars[checksum % 16]);
00356 
00357         } while ((stub_getc() & 0x7f) != '+');
00358 
00359 }
00360 #endif /* CONFIG_GDB_STUB */
00361 
00362 struct eregs {
00363         uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
00364         uint32_t vector;
00365         uint32_t error_code;
00366         uint32_t eip;
00367         uint32_t cs;
00368         uint32_t eflags;
00369 };
00370 
00371 void x86_exception(struct eregs *info)
00372 {
00373 #if CONFIG_GDB_STUB == 1
00374         int signo;
00375         memcpy(gdb_stub_registers, info, 8*sizeof(uint32_t));
00376         gdb_stub_registers[PC] = info->eip;
00377         gdb_stub_registers[CS] = info->cs;
00378         gdb_stub_registers[PS] = info->eflags;
00379         signo = GDB_UNKNOWN;
00380         if (info->vector < ARRAY_SIZE(exception_to_signal)) {
00381                 signo = exception_to_signal[info->vector];
00382         }
00383         
00384         /* reply to the host that an exception has occured */
00385         out_buffer[0] = 'S';
00386         out_buffer[1] = hexchars[(signo>>4) & 0xf];
00387         out_buffer[2] = hexchars[signo & 0xf];
00388         out_buffer[3] = '\0';
00389         put_packet(out_buffer);
00390 
00391         while(1) {
00392                 unsigned long addr, length;
00393                 char *ptr;
00394                 out_buffer[0] = '\0';
00395                 out_buffer[1] = '\0';
00396                 if (!get_packet(in_buffer)) {
00397                         break;
00398                 }
00399                 switch(in_buffer[0]) {
00400                 case '?': /* last signal */
00401                         out_buffer[0] = 'S';
00402                         out_buffer[1] = hexchars[(signo >> 4) & 0xf];
00403                         out_buffer[2] = hexchars[signo & 0xf];
00404                         out_buffer[3] = '\0';
00405                         break;
00406                 case 'g': /* return the value of the cpu registers */
00407                         copy_to_hex(out_buffer, &gdb_stub_registers, sizeof(gdb_stub_registers));
00408                         break;
00409                 case 'G': /* set the value of the CPU registers - return OK */
00410                         copy_from_hex(&gdb_stub_registers, in_buffer + 1, sizeof(gdb_stub_registers));
00411                         memcpy(info, gdb_stub_registers, 8*sizeof(uint32_t));
00412                         info->eip    = gdb_stub_registers[PC];
00413                         info->cs     = gdb_stub_registers[CS];
00414                         info->eflags = gdb_stub_registers[PS];
00415                         memcpy(out_buffer, "OK",3);
00416                         break;
00417                 case 'm':
00418                         /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
00419                         ptr = &in_buffer[1];
00420                         if (    parse_ulong(&ptr, &addr) && 
00421                                 (*ptr++ == ',') &&
00422                                 parse_ulong(&ptr, &length)) {
00423                                 copy_to_hex(out_buffer, (void *)addr, length);
00424                         } else {
00425                                 memcpy(out_buffer, "E01", 4);
00426                         }
00427                         break;
00428                 case 'M':
00429                         /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
00430                         ptr = &in_buffer[1];
00431                         if (    parse_ulong(&ptr, &addr) && 
00432                                 (*(ptr++) == ',') &&
00433                                 parse_ulong(&ptr, &length) &&
00434                                 (*(ptr++) == ':')) {
00435                                 copy_from_hex((void *)addr, ptr, length);
00436                                 memcpy(out_buffer, "OK", 3);
00437                         }
00438                         else {
00439                                 memcpy(out_buffer, "E02", 4);
00440                         }
00441                         break;
00442                 case 's':
00443                 case 'c':
00444                         /* cAA..AA    Continue at address AA..AA(optional) */
00445                         /* sAA..AA    Step one instruction from AA..AA(optional) */
00446                         ptr = &in_buffer[1];
00447                         if (parse_ulong(&ptr, &addr)) {
00448                                 info->eip = addr;
00449                         }
00450 
00451                         /* Clear the trace bit */
00452                         info->eflags &= ~(1 << 8);
00453                         /* Set the trace bit if we are single stepping */
00454                         if (in_buffer[0] == 's') {
00455                                 info->eflags |= (1 << 8);
00456                         }
00457                         return;
00458                         break;
00459                 case 'D':
00460                         memcpy(out_buffer, "OK", 3);
00461                         break;
00462                 case 'k':  /* kill request? */
00463                         break;
00464                 case 'q':  /* query */
00465                         break;
00466                 case 'z':  /* z0AAAA,LLLL remove memory breakpoint */
00467                            /* z1AAAA,LLLL remove hardware breakpoint */
00468                            /* z2AAAA,LLLL remove write watchpoint */
00469                            /* z3AAAA,LLLL remove read watchpoint */
00470                            /* z4AAAA,LLLL remove access watchpoint */
00471                 case 'Z':  /* Z0AAAA,LLLL insert memory breakpoint */
00472                            /* Z1AAAA,LLLL insert hardware breakpoint */
00473                            /* Z2AAAA,LLLL insert write watchpoint */
00474                            /* Z3AAAA,LLLL insert read watchpoint */
00475                            /* Z4AAAA,LLLL insert access watchpoint */
00476                         break;
00477                 default:
00478                         break;
00479                 }
00480                 put_packet(out_buffer);
00481         }
00482 #else /* !CONFIG_GDB_STUB */
00483         printk_emerg(
00484                 "Unexpected Exception: %d @ %02x:%08lx - Halting\n"
00485                 "Code: %d eflags: %08lx\n"
00486                 "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n"
00487                 "edi: %08lx esi: %08lx ebp: %08lx esp: %08lx\n",
00488                 info->vector, info->cs, info->eip,
00489                 info->error_code, info->eflags,
00490                 info->eax, info->ebx, info->ecx, info->edx,
00491                 info->edi, info->esi, info->ebp, info->esp);
00492         die("");
00493 #endif
00494 }

Generated on Mon Dec 29 10:54:06 2008 for coreboot by  doxygen 1.5.5