blob: 4c9f95b042695e156aab13e0d0101f6ce6be5fd8 [file] [log] [blame]
Kevin O'Connor65e63422008-07-19 14:12:32 -04001// Raw screen writing and debug output code.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05002//
Kevin O'Connor43562762009-10-12 09:48:12 -04003// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05004//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05005// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05006
7#include <stdarg.h> // va_list
8
9#include "farptr.h" // GET_VAR
Kevin O'Connor567e4e32008-04-05 11:37:51 -040010#include "util.h" // printf
Kevin O'Connor9521e262008-07-04 13:04:29 -040011#include "bregs.h" // struct bregs
12#include "config.h" // CONFIG_*
Kevin O'Connor15157a32008-12-13 11:10:37 -050013#include "biosvar.h" // GET_GLOBAL
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050014
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040015struct putcinfo {
16 void (*func)(struct putcinfo *info, char c);
17};
18
19
20/****************************************************************
21 * Debug output
22 ****************************************************************/
23
Kevin O'Connorc151b3b2009-05-12 22:59:41 -040024#define DEBUG_PORT PORT_SERIAL1
Kevin O'Connor5c732402008-06-07 10:43:07 -040025#define DEBUG_TIMEOUT 100000
26
Kevin O'Connor61d6b062008-06-21 12:15:10 -040027void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050028debug_serial_setup(void)
Kevin O'Connor61d6b062008-06-21 12:15:10 -040029{
30 if (!CONFIG_DEBUG_SERIAL)
31 return;
32 // setup for serial logging: 8N1
33 u8 oldparam, newparam = 0x03;
Kevin O'Connorc151b3b2009-05-12 22:59:41 -040034 oldparam = inb(DEBUG_PORT+SEROFF_LCR);
35 outb(newparam, DEBUG_PORT+SEROFF_LCR);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040036 // Disable irqs
37 u8 oldier, newier = 0;
Kevin O'Connorc151b3b2009-05-12 22:59:41 -040038 oldier = inb(DEBUG_PORT+SEROFF_IER);
39 outb(newier, DEBUG_PORT+SEROFF_IER);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040040
41 if (oldparam != newparam || oldier != newier)
42 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
43 , oldparam, oldier, newparam, newier);
44}
45
Kevin O'Connor65e63422008-07-19 14:12:32 -040046// Write a character to the serial port.
Kevin O'Connor5c732402008-06-07 10:43:07 -040047static void
48debug_serial(char c)
49{
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040050 if (!CONFIG_DEBUG_SERIAL)
51 return;
Kevin O'Connor5c732402008-06-07 10:43:07 -040052 int timeout = DEBUG_TIMEOUT;
Kevin O'Connorc151b3b2009-05-12 22:59:41 -040053 while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x60) != 0x60)
Kevin O'Connor5c732402008-06-07 10:43:07 -040054 if (!timeout--)
55 // Ran out of time.
56 return;
Kevin O'Connorc151b3b2009-05-12 22:59:41 -040057 outb(c, DEBUG_PORT+SEROFF_DATA);
Kevin O'Connor5c732402008-06-07 10:43:07 -040058}
59
Kevin O'Connorb9e62d22009-08-02 13:18:27 -040060// Make sure all serial port writes have been completely sent.
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040061static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050062debug_serial_flush(void)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040063{
64 if (!CONFIG_DEBUG_SERIAL)
65 return;
66 int timeout = DEBUG_TIMEOUT;
67 while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x40) != 0x40)
68 if (!timeout--)
69 // Ran out of time.
70 return;
71}
72
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040073// Write a character to debug port(s).
74static void
75putc_debug(struct putcinfo *action, char c)
76{
77 if (! CONFIG_DEBUG_LEVEL)
78 return;
79 if (! CONFIG_COREBOOT)
80 // Send character to debug port.
81 outb(c, PORT_BIOS_DEBUG);
82 if (c == '\n')
83 debug_serial('\r');
84 debug_serial(c);
85}
86
Kevin O'Connor52a300f2009-12-26 23:32:57 -050087// In segmented mode just need a dummy variable (putc_debug is always
88// used anyway), and in 32bit flat mode need a pointer to the 32bit
89// instance of putc_debug().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050090#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040091static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050092#elif MODESEGMENT
93static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -040094#else
95static struct putcinfo debuginfo = { putc_debug };
96#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040097
98
99/****************************************************************
100 * Screen writing
101 ****************************************************************/
102
Kevin O'Connor65e63422008-07-19 14:12:32 -0400103// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500104static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400105screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500106{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500107 struct bregs br;
108 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -0400109 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500110 br.ah = 0x0e;
111 br.al = c;
112 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500113}
114
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400115// Handle a character from a printf request.
116static void
117putc_screen(struct putcinfo *action, char c)
118{
119 if (CONFIG_SCREEN_AND_DEBUG)
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400120 putc_debug(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400121 if (c == '\n')
122 screenc('\r');
123 screenc(c);
124}
125
126static struct putcinfo screeninfo = { putc_screen };
127
128
129/****************************************************************
130 * Xprintf code
131 ****************************************************************/
132
Kevin O'Connor65e63422008-07-19 14:12:32 -0400133// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500134static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400135putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500136{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500137 if (MODESEGMENT) {
138 // Only debugging output supported in segmented mode.
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400139 putc_debug(action, c);
140 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400141 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400142
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400143 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
144 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500145}
146
Kevin O'Connor65e63422008-07-19 14:12:32 -0400147// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500148static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400149puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500150{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500151 if (!MODESEGMENT && !s)
152 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500153 for (; *s; s++)
154 putc(action, *s);
155}
156
Kevin O'Connor65e63422008-07-19 14:12:32 -0400157// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500158static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400159puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500160{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400161 char *vs = (char*)s;
162 for (;; vs++) {
163 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500164 if (!c)
165 break;
166 putc(action, c);
167 }
168}
169
Kevin O'Connor65e63422008-07-19 14:12:32 -0400170// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500171static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400172putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500173{
174 char buf[12];
175 char *d = &buf[sizeof(buf) - 1];
176 *d-- = '\0';
177 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500178 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500179 val /= 10;
180 if (!val)
181 break;
182 d--;
183 }
184 puts(action, d);
185}
186
Kevin O'Connor65e63422008-07-19 14:12:32 -0400187// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500188static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400189putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500190{
191 if (val <= 9)
192 val = '0' + val;
193 else
194 val = 'a' + val - 10;
195 putc(action, val);
196}
197
Kevin O'Connor65e63422008-07-19 14:12:32 -0400198// Output an integer in hexadecimal.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500199static void
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400200puthex(struct putcinfo *action, u32 val, int width, int spacepad)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500201{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400202 if (!width) {
203 u32 tmp = val;
204 width = 1;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400205 while (tmp >>= 4)
206 width++;
207 } else if (spacepad) {
208 u32 tmp = val;
209 u32 count = 1;
210 while (tmp >>= 4)
211 count++;
212 if (width > count) {
213 count = width - count;
214 width -= count;
215 while (count--)
216 putc(action, ' ');
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400217 }
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400218 }
219
220 switch (width) {
221 default: putsinglehex(action, (val >> 28) & 0xf);
222 case 7: putsinglehex(action, (val >> 24) & 0xf);
223 case 6: putsinglehex(action, (val >> 20) & 0xf);
224 case 5: putsinglehex(action, (val >> 16) & 0xf);
225 case 4: putsinglehex(action, (val >> 12) & 0xf);
226 case 3: putsinglehex(action, (val >> 8) & 0xf);
227 case 2: putsinglehex(action, (val >> 4) & 0xf);
228 case 1: putsinglehex(action, (val >> 0) & 0xf);
229 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500230}
231
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500232static inline int
233isdigit(u8 c)
234{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400235 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500236}
237
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400238static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400239bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500240{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500241 const char *s = fmt;
242 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500243 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500244 if (!c)
245 break;
246 if (c != '%') {
247 putc(action, c);
248 continue;
249 }
250 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400251 int field_width = 0;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400252 int spacepad = 1;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500253 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500254 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500255 if (!isdigit(c))
256 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400257 if (!field_width && (c == '0'))
258 spacepad = 0;
259 else
260 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500261 n++;
262 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500263 if (c == 'l') {
264 // Ignore long format indicator
265 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500266 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500267 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500268 s32 val;
269 const char *sarg;
270 switch (c) {
271 case '%':
272 putc(action, '%');
273 break;
274 case 'd':
275 val = va_arg(args, s32);
276 if (val < 0) {
277 putc(action, '-');
278 val = -val;
279 }
280 putuint(action, val);
281 break;
282 case 'u':
283 val = va_arg(args, s32);
284 putuint(action, val);
285 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400286 case 'p':
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400287 /* %p always has 0x prepended */
288 putc(action, '0');
289 putc(action, 'x');
290 field_width = 8;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400291 spacepad = 0;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500292 case 'x':
293 val = va_arg(args, s32);
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400294 puthex(action, val, field_width, spacepad);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500295 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500296 case 'c':
297 val = va_arg(args, int);
298 putc(action, val);
299 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400300 case '.':
301 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500302 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400303 break;
304 n++;
305 sarg = va_arg(args, const char *);
306 puts(action, sarg);
307 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500308 case 's':
309 sarg = va_arg(args, const char *);
310 puts_cs(action, sarg);
311 break;
312 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500313 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500314 n = s;
315 }
316 s = n;
317 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400318}
319
320void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500321panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400322{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400323 if (CONFIG_DEBUG_LEVEL) {
324 va_list args;
325 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400326 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400327 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400328 debug_serial_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400329 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400330
331 // XXX - use PANIC PORT.
332 irq_disable();
333 for (;;)
334 hlt();
335}
336
337void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400338__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400339{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500340 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400341 && *fmt != '\\' && *fmt != '/') {
342 struct thread_info *cur = getCurThread();
343 if (cur != &MainThread) {
344 // Show "thread id" for this debug message.
345 putc_debug(&debuginfo, '|');
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400346 puthex(&debuginfo, (u32)cur, 8, 0);
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400347 putc_debug(&debuginfo, '|');
348 putc_debug(&debuginfo, ' ');
349 }
350 }
351
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400352 va_list args;
353 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400354 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400355 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400356 debug_serial_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400357}
358
359void
360printf(const char *fmt, ...)
361{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500362 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400363 va_list args;
364 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400365 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500366 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400367 if (CONFIG_SCREEN_AND_DEBUG)
368 debug_serial_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500369}
370
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400371
372/****************************************************************
373 * snprintf
374 ****************************************************************/
375
376struct snprintfinfo {
377 struct putcinfo info;
378 char *str, *end;
379};
380
381static void
382putc_str(struct putcinfo *info, char c)
383{
384 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
385 if (sinfo->str >= sinfo->end)
386 return;
387 *sinfo->str = c;
388 sinfo->str++;
389}
390
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500391// Build a formatted string. Note, this function returns the actual
392// number of bytes used (not including null) even in the overflow
393// case.
394int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400395snprintf(char *str, size_t size, const char *fmt, ...)
396{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500397 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400398 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500399 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400400 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
401 va_list args;
402 va_start(args, fmt);
403 bvprintf(&sinfo.info, fmt, args);
404 va_end(args);
405 char *end = sinfo.str;
406 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500407 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400408 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500409 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400410}
411
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500412// Build a formatted string - malloc'ing the memory.
413char *
414znprintf(size_t size, const char *fmt, ...)
415{
416 ASSERT32FLAT();
417 if (!size)
418 return NULL;
419 char *str = malloc_tmp(size);
420 if (!str) {
421 warn_noalloc();
422 return NULL;
423 }
424 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
425 va_list args;
426 va_start(args, fmt);
427 bvprintf(&sinfo.info, fmt, args);
428 va_end(args);
429 char *end = sinfo.str;
430 if (end >= sinfo.end)
431 end = sinfo.end - 1;
432 *end = '\0';
433 return str;
434}
435
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400436
437/****************************************************************
438 * Misc helpers
439 ****************************************************************/
440
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500441void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400442hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500443{
444 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400445 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500446 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400447 putc(&debuginfo, '\n');
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400448 puthex(&debuginfo, count*4, 8, 0);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400449 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500450 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400451 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500452 }
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400453 puthex(&debuginfo, *(u32*)d, 8, 0);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500454 count++;
455 len-=4;
456 d+=4;
457 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400458 putc(&debuginfo, '\n');
Kevin O'Connor3e832bb2009-05-15 22:22:12 -0400459 debug_serial_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500460}
461
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500462static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400463dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500464{
465 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400466 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500467 return;
468 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400469 dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n"
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400470 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400471 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400472 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
473 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400474 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500475}
476
Kevin O'Connor05600342009-01-02 13:10:58 -0500477// Report entry to an Interrupt Service Routine (ISR).
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500478void
Kevin O'Connored128492008-03-11 11:14:59 -0400479__debug_isr(const char *fname)
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500480{
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400481 puts_cs(&debuginfo, fname);
482 putc(&debuginfo, '\n');
Kevin O'Connor3e832bb2009-05-15 22:22:12 -0400483 debug_serial_flush();
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500484}
485
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500486// Function called on handler startup.
487void
Kevin O'Connor05600342009-01-02 13:10:58 -0500488__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500489{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400490 dprintf(1, "enter %s:\n", fname);
491 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500492}
493
Kevin O'Connor05600342009-01-02 13:10:58 -0500494// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500495void
Kevin O'Connor05600342009-01-02 13:10:58 -0500496__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500497{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400498 dprintf(1, "stub %s:%d:\n", fname, lineno);
499 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500500}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500501
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500502// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500503void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500504__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500505{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500506 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
507 dprintf(1, "invalid %s:%d:\n", fname, lineno);
508 dump_regs(regs);
509 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400510}
511
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500512// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400513void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500514__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
515{
516 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
517 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
518 dump_regs(regs);
519 }
520}
521
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500522// Report a detected internal inconsistency.
523void
524__warn_internalerror(int lineno, const char *fname)
525{
526 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
527 , fname, lineno);
528}
529
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500530// Report on an allocation failure.
531void
532__warn_noalloc(int lineno, const char *fname)
533{
534 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
535 , fname, lineno);
536}
537
538// Report on a timeout exceeded.
539void
540__warn_timeout(int lineno, const char *fname)
541{
542 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
543}
544
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500545// Report a handler reporting an invalid parameter to the caller.
546void
547__set_invalid(struct bregs *regs, int lineno, const char *fname)
548{
549 __warn_invalid(regs, lineno, fname);
550 set_invalid_silent(regs);
551}
552
553// Report a call of an unimplemented function.
554void
555__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
556{
557 __warn_unimplemented(regs, lineno, fname);
558 set_invalid_silent(regs);
559}
560
561// Report a handler reporting an invalid parameter code to the
562// caller. Note, the lineno and return code are encoded in the same
563// parameter as gcc does a better job of scheduling function calls
564// when there are 3 or less parameters.
565void
566__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400567{
Kevin O'Connor05600342009-01-02 13:10:58 -0500568 u8 code = linecode;
569 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500570 __warn_invalid(regs, lineno, fname);
571 set_code_invalid_silent(regs, code);
572}
573
574// Report a call of an unimplemented function.
575void
576__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
577{
578 u8 code = linecode;
579 u32 lineno = linecode >> 8;
580 __warn_unimplemented(regs, lineno, fname);
581 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500582}