blob: 994a1d6190c71465c67ea9f629aa907f3d511f6a [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'Connor4cd522e2013-11-29 12:14:34 -05003// Copyright (C) 2008-2013 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'Connor9521e262008-07-04 13:04:29 -040010#include "bregs.h" // struct bregs
11#include "config.h" // CONFIG_*
Kevin O'Connor15157a32008-12-13 11:10:37 -050012#include "biosvar.h" // GET_GLOBAL
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050013#include "hw/serialio.h" // serial_debug_putc
Kevin O'Connor9dea5902013-09-14 20:23:54 -040014#include "malloc.h" // malloc_tmp
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040015#include "output.h" // dprintf
Kevin O'Connor3df600b2013-09-14 19:28:55 -040016#include "stacks.h" // call16_int
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040017#include "string.h" // memset
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040018#include "util.h" // ScreenAndDebug
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050019
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040020struct putcinfo {
21 void (*func)(struct putcinfo *info, char c);
22};
23
24
25/****************************************************************
26 * Debug output
27 ****************************************************************/
28
Kevin O'Connorbb1fcb42014-01-15 13:52:14 -050029void
30debug_banner(void)
31{
32 dprintf(1, "SeaBIOS (version %s)\n", VERSION);
33}
34
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040035// Write a character to debug port(s).
36static void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050037debug_putc(struct putcinfo *action, char c)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040038{
39 if (! CONFIG_DEBUG_LEVEL)
40 return;
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050041 qemu_debug_putc(c);
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020042 if (!MODESEGMENT)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050043 coreboot_debug_putc(c);
44 serial_debug_putc(c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040045}
46
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050047// Flush any pending output to debug port(s).
48static void
49debug_flush(void)
50{
51 serial_debug_flush();
52}
53
54// In segmented mode just need a dummy variable (debug_putc is always
Kevin O'Connor52a300f2009-12-26 23:32:57 -050055// used anyway), and in 32bit flat mode need a pointer to the 32bit
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050056// instance of debug_putc().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050057#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040058static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050059#elif MODESEGMENT
60static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -040061#else
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050062static struct putcinfo debuginfo = { debug_putc };
Kevin O'Connorebd426b2009-10-08 08:51:24 -040063#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040064
65
66/****************************************************************
67 * Screen writing
68 ****************************************************************/
69
Kevin O'Connor65e63422008-07-19 14:12:32 -040070// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050071static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040072screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050073{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050074 struct bregs br;
75 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -040076 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050077 br.ah = 0x0e;
78 br.al = c;
79 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050080}
81
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040082// Handle a character from a printf request.
83static void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050084screen_putc(struct putcinfo *action, char c)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040085{
Kevin O'Connor422263d2011-07-05 20:56:07 -040086 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050087 debug_putc(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040088 if (c == '\n')
89 screenc('\r');
90 screenc(c);
91}
92
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050093static struct putcinfo screeninfo = { screen_putc };
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040094
95
96/****************************************************************
97 * Xprintf code
98 ****************************************************************/
99
Kevin O'Connor65e63422008-07-19 14:12:32 -0400100// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500101static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400102putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500103{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500104 if (MODESEGMENT) {
105 // Only debugging output supported in segmented mode.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500106 debug_putc(action, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400107 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400108 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400109
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400110 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
111 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500112}
113
Kevin O'Connor65e63422008-07-19 14:12:32 -0400114// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500115static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400116puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500117{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500118 if (!MODESEGMENT && !s)
119 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500120 for (; *s; s++)
121 putc(action, *s);
122}
123
Kevin O'Connor65e63422008-07-19 14:12:32 -0400124// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500125static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400126puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500127{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400128 char *vs = (char*)s;
129 for (;; vs++) {
130 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500131 if (!c)
132 break;
133 putc(action, c);
134 }
135}
136
Kevin O'Connor65e63422008-07-19 14:12:32 -0400137// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500138static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400139putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500140{
141 char buf[12];
142 char *d = &buf[sizeof(buf) - 1];
143 *d-- = '\0';
144 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500145 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500146 val /= 10;
147 if (!val)
148 break;
149 d--;
150 }
151 puts(action, d);
152}
153
Kevin O'Connor65e63422008-07-19 14:12:32 -0400154// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500155static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400156putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500157{
158 if (val <= 9)
159 val = '0' + val;
160 else
161 val = 'a' + val - 10;
162 putc(action, val);
163}
164
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500165// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500166static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500167puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500168{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400169 switch (width) {
170 default: putsinglehex(action, (val >> 28) & 0xf);
171 case 7: putsinglehex(action, (val >> 24) & 0xf);
172 case 6: putsinglehex(action, (val >> 20) & 0xf);
173 case 5: putsinglehex(action, (val >> 16) & 0xf);
174 case 4: putsinglehex(action, (val >> 12) & 0xf);
175 case 3: putsinglehex(action, (val >> 8) & 0xf);
176 case 2: putsinglehex(action, (val >> 4) & 0xf);
177 case 1: putsinglehex(action, (val >> 0) & 0xf);
178 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500179}
180
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500181// Output an integer in hexadecimal with a minimum width.
182static void
183putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
184{
185 u32 tmp = val;
186 int count = 1;
187 while (tmp >>= 4)
188 count++;
189 width -= count;
190 while (width-- > 0)
191 putc(action, padchar);
192 puthex(action, val, count);
193}
194
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500195static inline int
196isdigit(u8 c)
197{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400198 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500199}
200
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400201static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400202bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500203{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500204 const char *s = fmt;
205 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500206 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500207 if (!c)
208 break;
209 if (c != '%') {
210 putc(action, c);
211 continue;
212 }
213 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400214 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500215 char padchar = ' ';
216 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500217 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500218 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500219 if (!isdigit(c))
220 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400221 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500222 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400223 else
224 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500225 n++;
226 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500227 if (c == 'l') {
228 // Ignore long format indicator
229 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500230 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500231 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500232 if (c == 'l') {
233 is64 = 1;
234 n++;
235 c = GET_GLOBAL(*(u8*)n);
236 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500237 s32 val;
238 const char *sarg;
239 switch (c) {
240 case '%':
241 putc(action, '%');
242 break;
243 case 'd':
244 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500245 if (is64)
246 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500247 if (val < 0) {
248 putc(action, '-');
249 val = -val;
250 }
251 putuint(action, val);
252 break;
253 case 'u':
254 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500255 if (is64)
256 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500257 putuint(action, val);
258 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400259 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500260 val = va_arg(args, s32);
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400261 putc(action, '0');
262 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500263 puthex(action, val, 8);
264 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500265 case 'x':
266 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500267 if (is64) {
268 u32 upper = va_arg(args, s32);
269 if (upper) {
270 putprettyhex(action, upper, field_width - 8, padchar);
271 puthex(action, val, 8);
272 break;
273 }
274 }
275 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500276 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500277 case 'c':
278 val = va_arg(args, int);
279 putc(action, val);
280 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400281 case '.':
282 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500283 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400284 break;
285 n++;
286 sarg = va_arg(args, const char *);
287 puts(action, sarg);
288 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500289 case 's':
290 sarg = va_arg(args, const char *);
291 puts_cs(action, sarg);
292 break;
293 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500294 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500295 n = s;
296 }
297 s = n;
298 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400299}
300
301void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500302panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400303{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400304 if (CONFIG_DEBUG_LEVEL) {
305 va_list args;
306 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400307 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400308 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500309 debug_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400310 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400311
312 // XXX - use PANIC PORT.
313 irq_disable();
314 for (;;)
315 hlt();
316}
317
318void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400319__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400320{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500321 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400322 && *fmt != '\\' && *fmt != '/') {
323 struct thread_info *cur = getCurThread();
324 if (cur != &MainThread) {
325 // Show "thread id" for this debug message.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500326 debug_putc(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500327 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500328 debug_putc(&debuginfo, '|');
329 debug_putc(&debuginfo, ' ');
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400330 }
331 }
332
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400333 va_list args;
334 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400335 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400336 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500337 debug_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400338}
339
340void
341printf(const char *fmt, ...)
342{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500343 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400344 va_list args;
345 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400346 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500347 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400348 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500349 debug_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500350}
351
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400352
353/****************************************************************
354 * snprintf
355 ****************************************************************/
356
357struct snprintfinfo {
358 struct putcinfo info;
359 char *str, *end;
360};
361
362static void
363putc_str(struct putcinfo *info, char c)
364{
365 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
366 if (sinfo->str >= sinfo->end)
367 return;
368 *sinfo->str = c;
369 sinfo->str++;
370}
371
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500372// Build a formatted string. Note, this function returns the actual
373// number of bytes used (not including null) even in the overflow
374// case.
375int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400376snprintf(char *str, size_t size, const char *fmt, ...)
377{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500378 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400379 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500380 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400381 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
382 va_list args;
383 va_start(args, fmt);
384 bvprintf(&sinfo.info, fmt, args);
385 va_end(args);
386 char *end = sinfo.str;
387 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500388 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400389 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500390 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400391}
392
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500393// Build a formatted string - malloc'ing the memory.
394char *
395znprintf(size_t size, const char *fmt, ...)
396{
397 ASSERT32FLAT();
398 if (!size)
399 return NULL;
400 char *str = malloc_tmp(size);
401 if (!str) {
402 warn_noalloc();
403 return NULL;
404 }
405 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
406 va_list args;
407 va_start(args, fmt);
408 bvprintf(&sinfo.info, fmt, args);
409 va_end(args);
410 char *end = sinfo.str;
411 if (end >= sinfo.end)
412 end = sinfo.end - 1;
413 *end = '\0';
414 return str;
415}
416
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400417
418/****************************************************************
419 * Misc helpers
420 ****************************************************************/
421
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500422void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400423hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500424{
425 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400426 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500427 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400428 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500429 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400430 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500431 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400432 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500433 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500434 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500435 count++;
436 len-=4;
437 d+=4;
438 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400439 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500440 debug_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500441}
442
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500443static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400444dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500445{
446 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400447 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500448 return;
449 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400450 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 -0400451 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400452 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400453 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
454 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400455 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500456}
457
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400458// Report entry to an Interrupt Service Routine (ISR).
459void
460__debug_isr(const char *fname)
461{
462 puts_cs(&debuginfo, fname);
463 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500464 debug_flush();
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400465}
466
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500467// Function called on handler startup.
468void
Kevin O'Connor05600342009-01-02 13:10:58 -0500469__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500470{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400471 dprintf(1, "enter %s:\n", fname);
472 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500473}
474
Kevin O'Connor05600342009-01-02 13:10:58 -0500475// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500476void
Kevin O'Connor05600342009-01-02 13:10:58 -0500477__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500478{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400479 dprintf(1, "stub %s:%d:\n", fname, lineno);
480 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500481}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500482
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500483// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500484void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500485__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500486{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500487 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
488 dprintf(1, "invalid %s:%d:\n", fname, lineno);
489 dump_regs(regs);
490 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400491}
492
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500493// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400494void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500495__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
496{
497 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
498 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
499 dump_regs(regs);
500 }
501}
502
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500503// Report a detected internal inconsistency.
504void
505__warn_internalerror(int lineno, const char *fname)
506{
507 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
508 , fname, lineno);
509}
510
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500511// Report on an allocation failure.
512void
513__warn_noalloc(int lineno, const char *fname)
514{
515 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
516 , fname, lineno);
517}
518
519// Report on a timeout exceeded.
520void
521__warn_timeout(int lineno, const char *fname)
522{
523 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
524}
525
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500526// Report a handler reporting an invalid parameter to the caller.
527void
528__set_invalid(struct bregs *regs, int lineno, const char *fname)
529{
530 __warn_invalid(regs, lineno, fname);
531 set_invalid_silent(regs);
532}
533
534// Report a call of an unimplemented function.
535void
536__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
537{
538 __warn_unimplemented(regs, lineno, fname);
539 set_invalid_silent(regs);
540}
541
542// Report a handler reporting an invalid parameter code to the
543// caller. Note, the lineno and return code are encoded in the same
544// parameter as gcc does a better job of scheduling function calls
545// when there are 3 or less parameters.
546void
547__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400548{
Kevin O'Connor05600342009-01-02 13:10:58 -0500549 u8 code = linecode;
550 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500551 __warn_invalid(regs, lineno, fname);
552 set_code_invalid_silent(regs, code);
553}
554
555// Report a call of an unimplemented function.
556void
557__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
558{
559 u8 code = linecode;
560 u32 lineno = linecode >> 8;
561 __warn_unimplemented(regs, lineno, fname);
562 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500563}