blob: 5f6c0fc641f554c2066e3c84c4591dfa205e5cbd [file] [log] [blame]
Patrick Georgi11f00792020-03-04 15:10:45 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Subrata Banik8cfd76d2018-04-18 11:48:58 +05302#include <arch/cpu.h>
Robert Zieba3f01cd12022-04-14 10:36:15 -06003#include <arch/breakpoint.h>
4#include <arch/null_breakpoint.h>
Aaron Durbin4b032e42018-04-20 01:39:30 -06005#include <arch/exception.h>
Robert Zieba3f01cd12022-04-14 10:36:15 -06006#include <arch/registers.h>
Aaron Durbin4b032e42018-04-20 01:39:30 -06007#include <commonlib/helpers.h>
Eric Biederman432aa6a2004-10-30 22:59:35 +00008#include <console/console.h>
Kyösti Mälkkif2f7f032014-04-04 15:05:28 +03009#include <console/streams.h>
Aaron Durbinaae73d72018-04-21 00:10:10 -060010#include <cpu/x86/cr.h>
Subrata Banik8cfd76d2018-04-18 11:48:58 +053011#include <cpu/x86/lapic.h>
Aaron Durbin4b032e42018-04-20 01:39:30 -060012#include <stdint.h>
Eric Biederman432aa6a2004-10-30 22:59:35 +000013#include <string.h>
14
Julius Wernercd49cce2019-03-05 16:53:33 -080015#if CONFIG(GDB_STUB)
Eric Biederman432aa6a2004-10-30 22:59:35 +000016
17/* BUFMAX defines the maximum number of characters in inbound/outbound buffers.
Stefan Reinauer14e22772010-04-27 06:56:47 +000018 * At least NUM_REGBYTES*2 are needed for register packets
Eric Biederman432aa6a2004-10-30 22:59:35 +000019 */
20#define BUFMAX 400
21enum regnames {
22 EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
23 PC /* also known as eip */,
24 PS /* also known as eflags */,
25 CS, SS, DS, ES, FS, GS,
26 NUM_REGS /* Number of registers. */
27};
28
29static uint32_t gdb_stub_registers[NUM_REGS];
30
31#define GDB_SIG0 0 /* Signal 0 */
32#define GDB_SIGHUP 1 /* Hangup */
33#define GDB_SIGINT 2 /* Interrupt */
34#define GDB_SIGQUIT 3 /* Quit */
35#define GDB_SIGILL 4 /* Illegal instruction */
36#define GDB_SIGTRAP 5 /* Trace/breakpoint trap */
37#define GDB_SIGABRT 6 /* Aborted */
38#define GDB_SIGEMT 7 /* Emulation trap */
39#define GDB_SIGFPE 8 /* Arithmetic exception */
40#define GDB_SIGKILL 9 /* Killed */
41#define GDB_SIGBUS 10 /* Bus error */
42#define GDB_SIGSEGV 11 /* Segmentation fault */
43#define GDB_SIGSYS 12 /* Bad system call */
44#define GDB_SIGPIPE 13 /* Broken pipe */
45#define GDB_SIGALRM 14 /* Alarm clock */
46#define GDB_SIGTERM 15 /* Terminated */
47#define GDB_SIGURG 16 /* Urgent I/O condition */
48#define GDB_SIGSTOP 17 /* Stopped (signal) */
49#define GDB_SIGTSTP 18 /* Stopped (user) */
50#define GDB_SIGCONT 19 /* Continued */
51#define GDB_SIGCHLD 20 /* Child status changed */
52#define GDB_SIGTTIN 21 /* Stopped (tty input) */
53#define GDB_SIGTTOU 22 /* Stopped (tty output) */
54#define GDB_SIGIO 23 /* I/O possible */
55#define GDB_SIGXCPU 24 /* CPU time limit exceeded */
56#define GDB_SIGXFSZ 25 /* File size limit exceeded */
57#define GDB_SIGVTALRM 26 /* Virtual timer expired */
58#define GDB_SIGPROF 27 /* Profiling timer expired */
59#define GDB_SIGWINCH 28 /* Window size changed */
60#define GDB_SIGLOST 29 /* Resource lost */
61#define GDB_SIGUSR1 30 /* User defined signal 1 */
62#define GDB_SUGUSR2 31 /* User defined signal 2 */
63#define GDB_SIGPWR 32 /* Power fail/restart */
64#define GDB_SIGPOLL 33 /* Pollable event occurred */
65#define GDB_SIGWIND 34 /* SIGWIND */
66#define GDB_SIGPHONE 35 /* SIGPHONE */
67#define GDB_SIGWAITING 36 /* Process's LWPs are blocked */
68#define GDB_SIGLWP 37 /* Signal LWP */
69#define GDB_SIGDANGER 38 /* Swap space dangerously low */
70#define GDB_SIGGRANT 39 /* Monitor mode granted */
71#define GDB_SIGRETRACT 40 /* Need to relinquish monitor mode */
72#define GDB_SIGMSG 41 /* Monitor mode data available */
73#define GDB_SIGSOUND 42 /* Sound completed */
74#define GDB_SIGSAK 43 /* Secure attention */
75#define GDB_SIGPRIO 44 /* SIGPRIO */
Stefan Reinauer14e22772010-04-27 06:56:47 +000076
Eric Biederman432aa6a2004-10-30 22:59:35 +000077#define GDB_SIG33 45 /* Real-time event 33 */
78#define GDB_SIG34 46 /* Real-time event 34 */
79#define GDB_SIG35 47 /* Real-time event 35 */
80#define GDB_SIG36 48 /* Real-time event 36 */
81#define GDB_SIG37 49 /* Real-time event 37 */
82#define GDB_SIG38 50 /* Real-time event 38 */
83#define GDB_SIG39 51 /* Real-time event 39 */
84#define GDB_SIG40 52 /* Real-time event 40 */
85#define GDB_SIG41 53 /* Real-time event 41 */
86#define GDB_SIG42 54 /* Real-time event 42 */
87#define GDB_SIG43 55 /* Real-time event 43 */
88#define GDB_SIG44 56 /* Real-time event 44 */
89#define GDB_SIG45 57 /* Real-time event 45 */
90#define GDB_SIG46 58 /* Real-time event 46 */
91#define GDB_SIG47 59 /* Real-time event 47 */
92#define GDB_SIG48 60 /* Real-time event 48 */
93#define GDB_SIG49 61 /* Real-time event 49 */
94#define GDB_SIG50 62 /* Real-time event 50 */
95#define GDB_SIG51 63 /* Real-time event 51 */
96#define GDB_SIG52 64 /* Real-time event 52 */
97#define GDB_SIG53 65 /* Real-time event 53 */
98#define GDB_SIG54 66 /* Real-time event 54 */
99#define GDB_SIG55 67 /* Real-time event 55 */
100#define GDB_SIG56 68 /* Real-time event 56 */
101#define GDB_SIG57 69 /* Real-time event 57 */
102#define GDB_SIG58 70 /* Real-time event 58 */
103#define GDB_SIG59 71 /* Real-time event 59 */
104#define GDB_SIG60 72 /* Real-time event 60 */
105#define GDB_SIG61 73 /* Real-time event 61 */
106#define GDB_SIG62 74 /* Real-time event 62 */
107#define GDB_SIG63 75 /* Real-time event 63 */
108#define GDB_SIGCANCEL 76 /* LWP internal signal */
109#define GDB_SIG32 77 /* Real-time event 32 */
110#define GDB_SIG64 78 /* Real-time event 64 */
111#define GDB_SIG65 79 /* Real-time event 65 */
112#define GDB_SIG66 80 /* Real-time event 66 */
113#define GDB_SIG67 81 /* Real-time event 67 */
114#define GDB_SIG68 82 /* Real-time event 68 */
115#define GDB_SIG69 83 /* Real-time event 69 */
116#define GDB_SIG70 84 /* Real-time event 70 */
117#define GDB_SIG71 85 /* Real-time event 71 */
118#define GDB_SIG72 86 /* Real-time event 72 */
119#define GDB_SIG73 87 /* Real-time event 73 */
120#define GDB_SIG74 88 /* Real-time event 74 */
121#define GDB_SIG75 89 /* Real-time event 75 */
122#define GDB_SIG76 90 /* Real-time event 76 */
123#define GDB_SIG77 91 /* Real-time event 77 */
124#define GDB_SIG78 92 /* Real-time event 78 */
125#define GDB_SIG79 93 /* Real-time event 79 */
126#define GDB_SIG80 94 /* Real-time event 80 */
127#define GDB_SIG81 95 /* Real-time event 81 */
128#define GDB_SIG82 96 /* Real-time event 82 */
129#define GDB_SIG83 97 /* Real-time event 83 */
130#define GDB_SIG84 98 /* Real-time event 84 */
131#define GDB_SIG85 99 /* Real-time event 85 */
132#define GDB_SIG86 100 /* Real-time event 86 */
133#define GDB_SIG87 101 /* Real-time event 87 */
134#define GDB_SIG88 102 /* Real-time event 88 */
135#define GDB_SIG89 103 /* Real-time event 89 */
136#define GDB_SIG90 104 /* Real-time event 90 */
137#define GDB_SIG91 105 /* Real-time event 91 */
138#define GDB_SIG92 106 /* Real-time event 92 */
139#define GDB_SIG93 107 /* Real-time event 93 */
140#define GDB_SIG94 108 /* Real-time event 94 */
141#define GDB_SIG95 109 /* Real-time event 95 */
142#define GDB_SIG96 110 /* Real-time event 96 */
143#define GDB_SIG97 111 /* Real-time event 97 */
144#define GDB_SIG98 112 /* Real-time event 98 */
145#define GDB_SIG99 113 /* Real-time event 99 */
146#define GDB_SIG100 114 /* Real-time event 100 */
147#define GDB_SIG101 115 /* Real-time event 101 */
148#define GDB_SIG102 116 /* Real-time event 102 */
149#define GDB_SIG103 117 /* Real-time event 103 */
150#define GDB_SIG104 118 /* Real-time event 104 */
151#define GDB_SIG105 119 /* Real-time event 105 */
152#define GDB_SIG106 120 /* Real-time event 106 */
153#define GDB_SIG107 121 /* Real-time event 107 */
154#define GDB_SIG108 122 /* Real-time event 108 */
155#define GDB_SIG109 123 /* Real-time event 109 */
156#define GDB_SIG110 124 /* Real-time event 110 */
157#define GDB_SIG111 125 /* Real-time event 111 */
158#define GDB_SIG112 126 /* Real-time event 112 */
159#define GDB_SIG113 127 /* Real-time event 113 */
160#define GDB_SIG114 128 /* Real-time event 114 */
161#define GDB_SIG115 129 /* Real-time event 115 */
162#define GDB_SIG116 130 /* Real-time event 116 */
163#define GDB_SIG117 131 /* Real-time event 117 */
164#define GDB_SIG118 132 /* Real-time event 118 */
165#define GDB_SIG119 133 /* Real-time event 119 */
166#define GDB_SIG120 134 /* Real-time event 120 */
167#define GDB_SIG121 135 /* Real-time event 121 */
168#define GDB_SIG122 136 /* Real-time event 122 */
169#define GDB_SIG123 137 /* Real-time event 123 */
170#define GDB_SIG124 138 /* Real-time event 124 */
171#define GDB_SIG125 139 /* Real-time event 125 */
172#define GDB_SIG126 140 /* Real-time event 126 */
173#define GDB_SIG127 141 /* Real-time event 127 */
174#define GDB_SIGINFO 142 /* Information request */
175#define GDB_UNKNOWN 143 /* Unknown signal */
176#define GDB_DEFAULT 144 /* error: default signal */
177/* Mach exceptions */
178#define GDB_EXC_BAD_ACCESS 145 /* Could not access memory */
179#define GDB_EXC_BAD_INSTRCTION 146 /* Illegal instruction/operand */
180#define GDB_EXC_ARITHMETIC 147 /* Arithmetic exception */
181#define GDB_EXC_EMULATION 148 /* Emulation instruction */
182#define GDB_EXC_SOFTWARE 149 /* Software generated exception */
183#define GDB_EXC_BREAKPOINT 150 /* Breakpoint */
184
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700185static unsigned char exception_to_signal[] = {
Eric Biederman432aa6a2004-10-30 22:59:35 +0000186 [0] = GDB_SIGFPE, /* divide by zero */
187 [1] = GDB_SIGTRAP, /* debug exception */
188 [2] = GDB_SIGSEGV, /* NMI Interrupt */
189 [3] = GDB_SIGTRAP, /* Breakpoint */
190 [4] = GDB_SIGSEGV, /* into instruction (overflow) */
191 [5] = GDB_SIGSEGV, /* bound instruction */
192 [6] = GDB_SIGILL, /* Invalid opcode */
193 [7] = GDB_SIGSEGV, /* coprocessor not available */
194 [8] = GDB_SIGSEGV, /* double fault */
195 [9] = GDB_SIGFPE, /* coprocessor segment overrun */
196 [10] = GDB_SIGSEGV, /* Invalid TSS */
197 [11] = GDB_SIGBUS, /* Segment not present */
198 [12] = GDB_SIGBUS, /* stack exception */
199 [13] = GDB_SIGSEGV, /* general protection */
200 [14] = GDB_SIGSEGV, /* page fault */
201 [15] = GDB_UNKNOWN, /* reserved */
202 [16] = GDB_SIGEMT, /* coprocessor error */
203 [17] = GDB_SIGBUS, /* alignment check */
204 [18] = GDB_SIGSEGV, /* machine check */
205 [19] = GDB_SIGFPE, /* simd floating point exception */
206 [20] = GDB_UNKNOWN,
207 [21] = GDB_UNKNOWN,
208 [22] = GDB_UNKNOWN,
209 [23] = GDB_UNKNOWN,
210 [24] = GDB_UNKNOWN,
211 [25] = GDB_UNKNOWN,
212 [26] = GDB_UNKNOWN,
213 [27] = GDB_UNKNOWN,
214 [28] = GDB_UNKNOWN,
215 [29] = GDB_UNKNOWN,
216 [30] = GDB_UNKNOWN,
217 [31] = GDB_UNKNOWN,
218 [32] = GDB_SIGINT, /* User interrupt */
219};
220
221static const char hexchars[] = "0123456789abcdef";
222static char in_buffer[BUFMAX];
223static char out_buffer[BUFMAX];
224
Eric Biederman432aa6a2004-10-30 22:59:35 +0000225static inline void stub_putc(int ch)
226{
Kyösti Mälkkif2f7f032014-04-04 15:05:28 +0300227 gdb_tx_byte(ch);
228}
229
230static inline void stub_flush(void)
231{
232 gdb_tx_flush();
Eric Biederman432aa6a2004-10-30 22:59:35 +0000233}
234
235static inline int stub_getc(void)
236{
Kyösti Mälkkif2f7f032014-04-04 15:05:28 +0300237 return gdb_rx_byte();
Eric Biederman432aa6a2004-10-30 22:59:35 +0000238}
239
240static int hex(char ch)
241{
242 if ((ch >= 'a') && (ch <= 'f'))
243 return (ch - 'a' + 10);
244 if ((ch >= '0') && (ch <= '9'))
245 return (ch - '0');
246 if ((ch >= 'A') && (ch <= 'F'))
247 return (ch - 'A' + 10);
248 return (-1);
249}
250
251/*
252 * While we find hexadecimal digits, build an int.
253 * Fals is returned if nothing is parsed true otherwise.
254 */
255static int parse_ulong(char **ptr, unsigned long *value)
256{
257 int digit;
258 char *start;
259
260 start = *ptr;
261 *value = 0;
262
Lee Leahy024b13d2017-03-16 13:41:11 -0700263 while ((digit = hex(**ptr)) >= 0) {
Eric Biederman432aa6a2004-10-30 22:59:35 +0000264 *value = ((*value) << 4) | digit;
265 (*ptr)++;
266 }
267 return start != *ptr;
268}
269
270/* convert the memory pointed to by mem into hex, placing result in buf */
271/* return a pointer to the last char put in buf (null) */
272static void copy_to_hex(char *buf, void *addr, unsigned long count)
273{
274 unsigned char ch;
275 char *mem = addr;
276
Lee Leahy024b13d2017-03-16 13:41:11 -0700277 while (count--) {
Eric Biederman432aa6a2004-10-30 22:59:35 +0000278 ch = *mem++;
279 *buf++ = hexchars[ch >> 4];
280 *buf++ = hexchars[ch & 0x0f];
281 }
282 *buf = 0;
Eric Biederman432aa6a2004-10-30 22:59:35 +0000283}
284
Eric Biederman432aa6a2004-10-30 22:59:35 +0000285/* convert the hex array pointed to by buf into binary to be placed in mem */
286/* return a pointer to the character AFTER the last byte written */
287static void copy_from_hex(void *addr, char *buf, unsigned long count)
288{
289 unsigned char ch;
290 char *mem = addr;
291
Lee Leahy024b13d2017-03-16 13:41:11 -0700292 while (count--) {
293 ch = hex(*buf++) << 4;
294 ch = ch + hex(*buf++);
Eric Biederman432aa6a2004-10-30 22:59:35 +0000295 *mem++ = ch;
296 }
297}
298
Eric Biederman432aa6a2004-10-30 22:59:35 +0000299/* scan for the sequence $<data>#<checksum> */
300
301static int get_packet(char *buffer)
302{
303 unsigned char checksum;
304 unsigned char xmitcsum;
305 int count;
306 char ch;
307
308 /* Wishlit implement a timeout in get_packet */
309 do {
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700310 /* wait around for the start character, ignore all other
311 * characters
312 */
Lee Leahy0b5678f2017-03-16 16:01:40 -0700313 while ((ch = (stub_getc() & 0x7f)) != '$')
314 ;
Eric Biederman432aa6a2004-10-30 22:59:35 +0000315 checksum = 0;
316 xmitcsum = -1;
317
318 count = 0;
319
320 /* now, read until a # or end of buffer is found */
321 while (count < BUFMAX) {
322 ch = stub_getc() & 0x7f;
323 if (ch == '#')
324 break;
325 checksum = checksum + ch;
326 buffer[count] = ch;
327 count = count + 1;
328 }
329 buffer[count] = 0;
330
331 if (ch == '#') {
332 xmitcsum = hex(stub_getc() & 0x7f) << 4;
333 xmitcsum += hex(stub_getc() & 0x7f);
334
335 if (checksum != xmitcsum) {
336 stub_putc('-'); /* failed checksum */
Kyösti Mälkkif2f7f032014-04-04 15:05:28 +0300337 stub_flush();
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700338 } else {
Eric Biederman432aa6a2004-10-30 22:59:35 +0000339 stub_putc('+'); /* successful transfer */
Kyösti Mälkkif2f7f032014-04-04 15:05:28 +0300340 stub_flush();
Eric Biederman432aa6a2004-10-30 22:59:35 +0000341 }
342 }
Lee Leahy024b13d2017-03-16 13:41:11 -0700343 } while (checksum != xmitcsum);
Eric Biederman432aa6a2004-10-30 22:59:35 +0000344 return 1;
345}
346
347/* send the packet in buffer.*/
348static void put_packet(char *buffer)
349{
350 unsigned char checksum;
351 int count;
352 char ch;
353
354 /* $<packet info>#<checksum>. */
355 do {
356 stub_putc('$');
357 checksum = 0;
358 count = 0;
359
360 while ((ch = buffer[count])) {
361 stub_putc(ch);
362 checksum += ch;
363 count += 1;
364 }
365
366 stub_putc('#');
367 stub_putc(hexchars[checksum >> 4]);
368 stub_putc(hexchars[checksum % 16]);
Kyösti Mälkkif2f7f032014-04-04 15:05:28 +0300369 stub_flush();
Eric Biederman432aa6a2004-10-30 22:59:35 +0000370
371 } while ((stub_getc() & 0x7f) != '+');
372
373}
374#endif /* CONFIG_GDB_STUB */
375
Robert Zieba3f01cd12022-04-14 10:36:15 -0600376#define DEBUG_VECTOR 1
Eric Biederman432aa6a2004-10-30 22:59:35 +0000377
Maciej Pijankaea921852009-10-27 14:29:29 +0000378void x86_exception(struct eregs *info);
379
Eric Biederman432aa6a2004-10-30 22:59:35 +0000380void x86_exception(struct eregs *info)
381{
Julius Wernercd49cce2019-03-05 16:53:33 -0800382#if CONFIG(GDB_STUB)
Eric Biederman432aa6a2004-10-30 22:59:35 +0000383 int signo;
384 memcpy(gdb_stub_registers, info, 8*sizeof(uint32_t));
385 gdb_stub_registers[PC] = info->eip;
386 gdb_stub_registers[CS] = info->cs;
387 gdb_stub_registers[PS] = info->eflags;
388 signo = GDB_UNKNOWN;
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700389 if (info->vector < ARRAY_SIZE(exception_to_signal))
Eric Biederman432aa6a2004-10-30 22:59:35 +0000390 signo = exception_to_signal[info->vector];
Stefan Reinauer14e22772010-04-27 06:56:47 +0000391
Martin Roth2ed0aa22016-01-05 20:58:58 -0700392 /* reply to the host that an exception has occurred */
Eric Biederman432aa6a2004-10-30 22:59:35 +0000393 out_buffer[0] = 'S';
394 out_buffer[1] = hexchars[(signo>>4) & 0xf];
395 out_buffer[2] = hexchars[signo & 0xf];
396 out_buffer[3] = '\0';
397 put_packet(out_buffer);
398
Lee Leahy024b13d2017-03-16 13:41:11 -0700399 while (1) {
Eric Biederman432aa6a2004-10-30 22:59:35 +0000400 unsigned long addr, length;
401 char *ptr;
402 out_buffer[0] = '\0';
403 out_buffer[1] = '\0';
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700404 if (!get_packet(in_buffer))
Eric Biederman432aa6a2004-10-30 22:59:35 +0000405 break;
Lee Leahy024b13d2017-03-16 13:41:11 -0700406 switch (in_buffer[0]) {
Eric Biederman432aa6a2004-10-30 22:59:35 +0000407 case '?': /* last signal */
408 out_buffer[0] = 'S';
409 out_buffer[1] = hexchars[(signo >> 4) & 0xf];
410 out_buffer[2] = hexchars[signo & 0xf];
411 out_buffer[3] = '\0';
412 break;
Elyes HAOUAS777ea892016-07-29 07:40:41 +0200413 case 'g': /* return the value of the CPU registers */
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700414 copy_to_hex(out_buffer, &gdb_stub_registers,
415 sizeof(gdb_stub_registers));
Eric Biederman432aa6a2004-10-30 22:59:35 +0000416 break;
417 case 'G': /* set the value of the CPU registers - return OK */
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700418 copy_from_hex(&gdb_stub_registers, in_buffer + 1,
419 sizeof(gdb_stub_registers));
Eric Biederman432aa6a2004-10-30 22:59:35 +0000420 memcpy(info, gdb_stub_registers, 8*sizeof(uint32_t));
421 info->eip = gdb_stub_registers[PC];
422 info->cs = gdb_stub_registers[CS];
423 info->eflags = gdb_stub_registers[PS];
Lee Leahy024b13d2017-03-16 13:41:11 -0700424 memcpy(out_buffer, "OK", 3);
Eric Biederman432aa6a2004-10-30 22:59:35 +0000425 break;
426 case 'm':
427 /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
428 ptr = &in_buffer[1];
Lee Leahy024b13d2017-03-16 13:41:11 -0700429 if (parse_ulong(&ptr, &addr) &&
Eric Biederman432aa6a2004-10-30 22:59:35 +0000430 (*ptr++ == ',') &&
431 parse_ulong(&ptr, &length)) {
Eric Biedermana9e632c2004-11-18 22:38:08 +0000432 copy_to_hex(out_buffer, (void *)addr, length);
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700433 } else
Eric Biederman432aa6a2004-10-30 22:59:35 +0000434 memcpy(out_buffer, "E01", 4);
Eric Biederman432aa6a2004-10-30 22:59:35 +0000435 break;
436 case 'M':
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700437 /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA
438 * return OK
439 */
Eric Biederman432aa6a2004-10-30 22:59:35 +0000440 ptr = &in_buffer[1];
Lee Leahy024b13d2017-03-16 13:41:11 -0700441 if (parse_ulong(&ptr, &addr) &&
Eric Biederman432aa6a2004-10-30 22:59:35 +0000442 (*(ptr++) == ',') &&
443 parse_ulong(&ptr, &length) &&
444 (*(ptr++) == ':')) {
445 copy_from_hex((void *)addr, ptr, length);
446 memcpy(out_buffer, "OK", 3);
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700447 } else
Eric Biederman432aa6a2004-10-30 22:59:35 +0000448 memcpy(out_buffer, "E02", 4);
Eric Biederman432aa6a2004-10-30 22:59:35 +0000449 break;
450 case 's':
451 case 'c':
Lee Leahy6f80ccc2017-03-16 15:18:22 -0700452 /* cAA..AA Continue at address AA..AA(optional)
453 * sAA..AA Step one instruction from AA..AA(optional)
454 */
Eric Biederman432aa6a2004-10-30 22:59:35 +0000455 ptr = &in_buffer[1];
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700456 if (parse_ulong(&ptr, &addr))
Eric Biederman432aa6a2004-10-30 22:59:35 +0000457 info->eip = addr;
Eric Biederman432aa6a2004-10-30 22:59:35 +0000458
459 /* Clear the trace bit */
460 info->eflags &= ~(1 << 8);
461 /* Set the trace bit if we are single stepping */
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700462 if (in_buffer[0] == 's')
Eric Biederman432aa6a2004-10-30 22:59:35 +0000463 info->eflags |= (1 << 8);
Eric Biederman432aa6a2004-10-30 22:59:35 +0000464 return;
Eric Biederman432aa6a2004-10-30 22:59:35 +0000465 case 'D':
466 memcpy(out_buffer, "OK", 3);
467 break;
468 case 'k': /* kill request? */
469 break;
470 case 'q': /* query */
471 break;
472 case 'z': /* z0AAAA,LLLL remove memory breakpoint */
473 /* z1AAAA,LLLL remove hardware breakpoint */
474 /* z2AAAA,LLLL remove write watchpoint */
475 /* z3AAAA,LLLL remove read watchpoint */
476 /* z4AAAA,LLLL remove access watchpoint */
477 case 'Z': /* Z0AAAA,LLLL insert memory breakpoint */
478 /* Z1AAAA,LLLL insert hardware breakpoint */
479 /* Z2AAAA,LLLL insert write watchpoint */
480 /* Z3AAAA,LLLL insert read watchpoint */
481 /* Z4AAAA,LLLL insert access watchpoint */
482 break;
483 default:
484 break;
485 }
486 put_packet(out_buffer);
487 }
488#else /* !CONFIG_GDB_STUB */
Paul Menzel6663ad92019-06-24 18:44:33 +0200489
Jacob Garberbc674762019-05-14 11:21:41 -0600490 int logical_processor = 0;
Kyösti Mälkki34806cc2021-05-31 15:15:27 +0300491 u32 apic_id = CONFIG(SMP) ? lapicid() : 0;
Subrata Banik8cfd76d2018-04-18 11:48:58 +0530492
Robert Zieba3f01cd12022-04-14 10:36:15 -0600493 if (info->vector == DEBUG_VECTOR) {
494 if (breakpoint_dispatch_handler(info) == 0)
495 return;
496 }
497
Subrata Banik8cfd76d2018-04-18 11:48:58 +0530498#if ENV_RAMSTAGE
499 logical_processor = cpu_index();
500#endif
Paul Menzel6663ad92019-06-24 18:44:33 +0200501 u8 *code;
Patrick Rudolphadcf7822020-08-27 20:50:18 +0200502#if ENV_X86_64
Paul Menzel6663ad92019-06-24 18:44:33 +0200503#define MDUMP_SIZE 0x100
504 printk(BIOS_EMERG,
505 "CPU Index %d - APIC %d Unexpected Exception:\n"
506 "%lld @ %02llx:%016llx - Halting\n"
507 "Code: %lld rflags: %016llx cr2: %016llx\n"
508 "rax: %016llx rbx: %016llx\n"
509 "rcx: %016llx rdx: %016llx\n"
510 "rdi: %016llx rsi: %016llx\n"
511 "rbp: %016llx rsp: %016llx\n"
512 "r08: %016llx r09: %016llx\n"
513 "r10: %016llx r11: %016llx\n"
514 "r12: %016llx r13: %016llx\n"
515 "r14: %016llx r15: %016llx\n",
Kyösti Mälkki34806cc2021-05-31 15:15:27 +0300516 logical_processor, apic_id,
Paul Menzel6663ad92019-06-24 18:44:33 +0200517 info->vector, info->cs, info->rip,
518 info->error_code, info->rflags, read_cr2(),
519 info->rax, info->rbx, info->rcx, info->rdx,
520 info->rdi, info->rsi, info->rbp, info->rsp,
521 info->r8, info->r9, info->r10, info->r11,
522 info->r12, info->r13, info->r14, info->r15);
523 code = (u8 *)((uintptr_t)info->rip - (MDUMP_SIZE >> 2));
524#else
525#define MDUMP_SIZE 0x80
526
Stefan Reinauer14e22772010-04-27 06:56:47 +0000527 printk(BIOS_EMERG,
Subrata Banik8cfd76d2018-04-18 11:48:58 +0530528 "CPU Index %d - APIC %d Unexpected Exception:"
529 "%d @ %02x:%08x - Halting\n"
Aaron Durbinaae73d72018-04-21 00:10:10 -0600530 "Code: %d eflags: %08x cr2: %08x\n"
Myles Watsonc4ddbff2009-02-09 17:52:54 +0000531 "eax: %08x ebx: %08x ecx: %08x edx: %08x\n"
532 "edi: %08x esi: %08x ebp: %08x esp: %08x\n",
Kyösti Mälkki34806cc2021-05-31 15:15:27 +0300533 logical_processor, apic_id,
Eric Biederman432aa6a2004-10-30 22:59:35 +0000534 info->vector, info->cs, info->eip,
Aaron Durbinaae73d72018-04-21 00:10:10 -0600535 info->error_code, info->eflags, read_cr2(),
Eric Biederman432aa6a2004-10-30 22:59:35 +0000536 info->eax, info->ebx, info->ecx, info->edx,
537 info->edi, info->esi, info->ebp, info->esp);
Paul Menzel6663ad92019-06-24 18:44:33 +0200538 code = (u8 *)((uintptr_t)info->eip - (MDUMP_SIZE >> 1));
539#endif
Alexandru Gagniucde415eb2012-08-15 06:45:18 -0500540 /* Align to 8-byte boundary please, and print eight bytes per row.
541 * This is done to make DRAM burst timing/reordering errors more
542 * evident from the looking at the dump */
Lee Leahy024b13d2017-03-16 13:41:11 -0700543 code = (u8 *)((uintptr_t)code & ~0x7);
Alexandru Gagniucde415eb2012-08-15 06:45:18 -0500544 int i;
Lee Leahy9c7c6f72017-03-16 11:24:09 -0700545 for (i = 0; i < MDUMP_SIZE; i++) {
Lee Leahy024b13d2017-03-16 13:41:11 -0700546 if ((i & 0x07) == 0)
Stefan Reinauer96938852015-06-18 01:23:48 -0700547 printk(BIOS_EMERG, "\n%p:\t", code + i);
Alexandru Gagniucde415eb2012-08-15 06:45:18 -0500548 printk(BIOS_EMERG, "%.2x ", code[i]);
549 }
Raul E Rangel5bb926e2020-06-29 11:28:25 -0600550
551 /* Align to 4-byte boundary and up the stack. */
552 u32 *ptr = (u32 *)(ALIGN_DOWN((uintptr_t)info->esp, sizeof(u32)) + MDUMP_SIZE - 4);
553 for (i = 0; i < MDUMP_SIZE / sizeof(u32); ++i, --ptr) {
554 printk(BIOS_EMERG, "\n%p:\t0x%08x", ptr, *ptr);
555 if ((uintptr_t)ptr == info->ebp)
556 printk(BIOS_EMERG, " <-ebp");
557 else if ((uintptr_t)ptr == info->esp)
558 printk(BIOS_EMERG, " <-esp");
559 }
560
561 die("\n");
Eric Biederman432aa6a2004-10-30 22:59:35 +0000562#endif
563}
Aaron Durbin4b032e42018-04-20 01:39:30 -0600564
565#define GATE_P (1 << 15)
566#define GATE_DPL(x) (((x) & 0x3) << 13)
567#define GATE_SIZE_16 (0 << 11)
568#define GATE_SIZE_32 (1 << 11)
569
570#define IGATE_FLAGS (GATE_P | GATE_DPL(0) | GATE_SIZE_32 | (0x6 << 8))
571
572struct intr_gate {
573 uint16_t offset_0;
574 uint16_t segsel;
575 uint16_t flags;
576 uint16_t offset_1;
577#if ENV_X86_64
578 uint32_t offset_2;
579 uint32_t reserved;
580#endif
581} __packed;
582
583/* Even though the vecX symbols are interrupt entry points just treat them
584 like data to more easily get the pointer values in C. Because IDT entries
Jonathan Neuschäfer773cc1b2018-10-10 14:22:48 +0200585 format splits the offset field up, one can't use the linker to resolve
586 parts of a relocation on x86 ABI. An array of pointers is used to gather
Aaron Durbin4b032e42018-04-20 01:39:30 -0600587 the symbols. The IDT is initialized at runtime when exception_init() is
588 called. */
589extern u8 vec0[], vec1[], vec2[], vec3[], vec4[], vec5[], vec6[], vec7[];
590extern u8 vec8[], vec9[], vec10[], vec11[], vec12[], vec13[], vec14[], vec15[];
591extern u8 vec16[], vec17[], vec18[], vec19[];
592
593static const uintptr_t intr_entries[] = {
594 (uintptr_t)vec0, (uintptr_t)vec1, (uintptr_t)vec2, (uintptr_t)vec3,
595 (uintptr_t)vec4, (uintptr_t)vec5, (uintptr_t)vec6, (uintptr_t)vec7,
596 (uintptr_t)vec8, (uintptr_t)vec9, (uintptr_t)vec10, (uintptr_t)vec11,
597 (uintptr_t)vec12, (uintptr_t)vec13, (uintptr_t)vec14, (uintptr_t)vec15,
598 (uintptr_t)vec16, (uintptr_t)vec17, (uintptr_t)vec18, (uintptr_t)vec19,
599};
600
Arthur Heymans9e1ea542019-11-20 22:09:15 +0100601static struct intr_gate idt[ARRAY_SIZE(intr_entries)] __aligned(8);
Aaron Durbin4b032e42018-04-20 01:39:30 -0600602
603static inline uint16_t get_cs(void)
604{
605 uint16_t segment;
606
607 asm volatile (
608 "mov %%cs, %0\n"
609 : "=r" (segment)
610 :
611 : "memory"
612 );
613
614 return segment;
615}
616
617struct lidtarg {
618 uint16_t limit;
619#if ENV_X86_32
620 uint32_t base;
621#else
622 uint64_t base;
623#endif
624} __packed;
625
626/* This global is for src/cpu/x86/lapic/secondary.S usage which is only
627 used during ramstage. */
628struct lidtarg idtarg;
629
630static void load_idt(void *table, size_t sz)
631{
632 struct lidtarg lidtarg = {
633 .limit = sz - 1,
634 .base = (uintptr_t)table,
635 };
636
637 asm volatile (
638 "lidt %0"
639 :
640 : "m" (lidtarg)
641 : "memory"
642 );
643
644 if (ENV_RAMSTAGE)
645 memcpy(&idtarg, &lidtarg, sizeof(idtarg));
646}
647
648asmlinkage void exception_init(void)
649{
650 int i;
651 uint16_t segment;
Aaron Durbin4b032e42018-04-20 01:39:30 -0600652
653 segment = get_cs();
Aaron Durbin4b032e42018-04-20 01:39:30 -0600654
655 /* Initialize IDT. */
656 for (i = 0; i < ARRAY_SIZE(idt); i++) {
Arthur Heymans9e1ea542019-11-20 22:09:15 +0100657 idt[i].offset_0 = intr_entries[i];
658 idt[i].segsel = segment;
659 idt[i].flags = IGATE_FLAGS;
660 idt[i].offset_1 = intr_entries[i] >> 16;
Aaron Durbin4b032e42018-04-20 01:39:30 -0600661#if ENV_X86_64
Arthur Heymans9e1ea542019-11-20 22:09:15 +0100662 idt[i].offset_2 = intr_entries[i] >> 32;
Aaron Durbin4b032e42018-04-20 01:39:30 -0600663#endif
664 }
665
Arthur Heymans9e1ea542019-11-20 22:09:15 +0100666 load_idt(idt, sizeof(idt));
Robert Zieba3f01cd12022-04-14 10:36:15 -0600667
668 null_breakpoint_init();
Aaron Durbin4b032e42018-04-20 01:39:30 -0600669}