blob: 1d882fa6844ded4a9372ec261c10e3d0289ee453 [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'Connor4cd522e2013-11-29 12:14:34 -050029// Setup debugging port(s).
Kevin O'Connor61d6b062008-06-21 12:15:10 -040030void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050031debug_preinit(void)
Kevin O'Connor61d6b062008-06-21 12:15:10 -040032{
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050033 serial_debug_preinit();
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040034}
35
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040036// Write a character to debug port(s).
37static void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050038debug_putc(struct putcinfo *action, char c)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040039{
40 if (! CONFIG_DEBUG_LEVEL)
41 return;
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050042 qemu_debug_putc(c);
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020043 if (!MODESEGMENT)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050044 coreboot_debug_putc(c);
45 serial_debug_putc(c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040046}
47
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050048// Flush any pending output to debug port(s).
49static void
50debug_flush(void)
51{
52 serial_debug_flush();
53}
54
55// In segmented mode just need a dummy variable (debug_putc is always
Kevin O'Connor52a300f2009-12-26 23:32:57 -050056// used anyway), and in 32bit flat mode need a pointer to the 32bit
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050057// instance of debug_putc().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050058#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040059static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050060#elif MODESEGMENT
61static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -040062#else
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050063static struct putcinfo debuginfo = { debug_putc };
Kevin O'Connorebd426b2009-10-08 08:51:24 -040064#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040065
66
67/****************************************************************
68 * Screen writing
69 ****************************************************************/
70
Kevin O'Connor65e63422008-07-19 14:12:32 -040071// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050072static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040073screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050074{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050075 struct bregs br;
76 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -040077 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050078 br.ah = 0x0e;
79 br.al = c;
80 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050081}
82
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040083// Handle a character from a printf request.
84static void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050085screen_putc(struct putcinfo *action, char c)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040086{
Kevin O'Connor422263d2011-07-05 20:56:07 -040087 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050088 debug_putc(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040089 if (c == '\n')
90 screenc('\r');
91 screenc(c);
92}
93
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050094static struct putcinfo screeninfo = { screen_putc };
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040095
96
97/****************************************************************
98 * Xprintf code
99 ****************************************************************/
100
Kevin O'Connor65e63422008-07-19 14:12:32 -0400101// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500102static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400103putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500104{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500105 if (MODESEGMENT) {
106 // Only debugging output supported in segmented mode.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500107 debug_putc(action, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400108 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400109 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400110
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400111 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
112 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500113}
114
Kevin O'Connor65e63422008-07-19 14:12:32 -0400115// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500116static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400117puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500118{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500119 if (!MODESEGMENT && !s)
120 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500121 for (; *s; s++)
122 putc(action, *s);
123}
124
Kevin O'Connor65e63422008-07-19 14:12:32 -0400125// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500126static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400127puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500128{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400129 char *vs = (char*)s;
130 for (;; vs++) {
131 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500132 if (!c)
133 break;
134 putc(action, c);
135 }
136}
137
Kevin O'Connor65e63422008-07-19 14:12:32 -0400138// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500139static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400140putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500141{
142 char buf[12];
143 char *d = &buf[sizeof(buf) - 1];
144 *d-- = '\0';
145 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500146 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500147 val /= 10;
148 if (!val)
149 break;
150 d--;
151 }
152 puts(action, d);
153}
154
Kevin O'Connor65e63422008-07-19 14:12:32 -0400155// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500156static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400157putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500158{
159 if (val <= 9)
160 val = '0' + val;
161 else
162 val = 'a' + val - 10;
163 putc(action, val);
164}
165
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500166// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500167static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500168puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500169{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400170 switch (width) {
171 default: putsinglehex(action, (val >> 28) & 0xf);
172 case 7: putsinglehex(action, (val >> 24) & 0xf);
173 case 6: putsinglehex(action, (val >> 20) & 0xf);
174 case 5: putsinglehex(action, (val >> 16) & 0xf);
175 case 4: putsinglehex(action, (val >> 12) & 0xf);
176 case 3: putsinglehex(action, (val >> 8) & 0xf);
177 case 2: putsinglehex(action, (val >> 4) & 0xf);
178 case 1: putsinglehex(action, (val >> 0) & 0xf);
179 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500180}
181
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500182// Output an integer in hexadecimal with a minimum width.
183static void
184putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
185{
186 u32 tmp = val;
187 int count = 1;
188 while (tmp >>= 4)
189 count++;
190 width -= count;
191 while (width-- > 0)
192 putc(action, padchar);
193 puthex(action, val, count);
194}
195
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500196static inline int
197isdigit(u8 c)
198{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400199 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500200}
201
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400202static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400203bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500204{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500205 const char *s = fmt;
206 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500207 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500208 if (!c)
209 break;
210 if (c != '%') {
211 putc(action, c);
212 continue;
213 }
214 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400215 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500216 char padchar = ' ';
217 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500218 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500219 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500220 if (!isdigit(c))
221 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400222 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500223 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400224 else
225 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500226 n++;
227 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500228 if (c == 'l') {
229 // Ignore long format indicator
230 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500231 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500232 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500233 if (c == 'l') {
234 is64 = 1;
235 n++;
236 c = GET_GLOBAL(*(u8*)n);
237 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500238 s32 val;
239 const char *sarg;
240 switch (c) {
241 case '%':
242 putc(action, '%');
243 break;
244 case 'd':
245 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500246 if (is64)
247 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500248 if (val < 0) {
249 putc(action, '-');
250 val = -val;
251 }
252 putuint(action, val);
253 break;
254 case 'u':
255 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500256 if (is64)
257 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500258 putuint(action, val);
259 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400260 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500261 val = va_arg(args, s32);
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400262 putc(action, '0');
263 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500264 puthex(action, val, 8);
265 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500266 case 'x':
267 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500268 if (is64) {
269 u32 upper = va_arg(args, s32);
270 if (upper) {
271 putprettyhex(action, upper, field_width - 8, padchar);
272 puthex(action, val, 8);
273 break;
274 }
275 }
276 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500277 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500278 case 'c':
279 val = va_arg(args, int);
280 putc(action, val);
281 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400282 case '.':
283 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500284 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400285 break;
286 n++;
287 sarg = va_arg(args, const char *);
288 puts(action, sarg);
289 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500290 case 's':
291 sarg = va_arg(args, const char *);
292 puts_cs(action, sarg);
293 break;
294 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500295 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500296 n = s;
297 }
298 s = n;
299 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400300}
301
302void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500303panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400304{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400305 if (CONFIG_DEBUG_LEVEL) {
306 va_list args;
307 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400308 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400309 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500310 debug_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400311 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400312
313 // XXX - use PANIC PORT.
314 irq_disable();
315 for (;;)
316 hlt();
317}
318
319void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400320__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400321{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500322 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400323 && *fmt != '\\' && *fmt != '/') {
324 struct thread_info *cur = getCurThread();
325 if (cur != &MainThread) {
326 // Show "thread id" for this debug message.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500327 debug_putc(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500328 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500329 debug_putc(&debuginfo, '|');
330 debug_putc(&debuginfo, ' ');
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400331 }
332 }
333
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400334 va_list args;
335 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400336 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400337 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500338 debug_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400339}
340
341void
342printf(const char *fmt, ...)
343{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500344 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400345 va_list args;
346 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400347 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500348 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400349 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500350 debug_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500351}
352
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400353
354/****************************************************************
355 * snprintf
356 ****************************************************************/
357
358struct snprintfinfo {
359 struct putcinfo info;
360 char *str, *end;
361};
362
363static void
364putc_str(struct putcinfo *info, char c)
365{
366 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
367 if (sinfo->str >= sinfo->end)
368 return;
369 *sinfo->str = c;
370 sinfo->str++;
371}
372
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500373// Build a formatted string. Note, this function returns the actual
374// number of bytes used (not including null) even in the overflow
375// case.
376int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400377snprintf(char *str, size_t size, const char *fmt, ...)
378{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500379 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400380 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500381 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400382 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
383 va_list args;
384 va_start(args, fmt);
385 bvprintf(&sinfo.info, fmt, args);
386 va_end(args);
387 char *end = sinfo.str;
388 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500389 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400390 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500391 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400392}
393
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500394// Build a formatted string - malloc'ing the memory.
395char *
396znprintf(size_t size, const char *fmt, ...)
397{
398 ASSERT32FLAT();
399 if (!size)
400 return NULL;
401 char *str = malloc_tmp(size);
402 if (!str) {
403 warn_noalloc();
404 return NULL;
405 }
406 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
407 va_list args;
408 va_start(args, fmt);
409 bvprintf(&sinfo.info, fmt, args);
410 va_end(args);
411 char *end = sinfo.str;
412 if (end >= sinfo.end)
413 end = sinfo.end - 1;
414 *end = '\0';
415 return str;
416}
417
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400418
419/****************************************************************
420 * Misc helpers
421 ****************************************************************/
422
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500423void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400424hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500425{
426 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400427 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500428 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400429 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500430 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400431 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500432 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400433 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500434 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500435 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500436 count++;
437 len-=4;
438 d+=4;
439 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400440 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500441 debug_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500442}
443
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500444static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400445dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500446{
447 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400448 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500449 return;
450 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400451 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 -0400452 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400453 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400454 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
455 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400456 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500457}
458
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400459// Report entry to an Interrupt Service Routine (ISR).
460void
461__debug_isr(const char *fname)
462{
463 puts_cs(&debuginfo, fname);
464 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500465 debug_flush();
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400466}
467
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500468// Function called on handler startup.
469void
Kevin O'Connor05600342009-01-02 13:10:58 -0500470__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500471{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400472 dprintf(1, "enter %s:\n", fname);
473 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500474}
475
Kevin O'Connor05600342009-01-02 13:10:58 -0500476// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500477void
Kevin O'Connor05600342009-01-02 13:10:58 -0500478__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500479{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400480 dprintf(1, "stub %s:%d:\n", fname, lineno);
481 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500482}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500483
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500484// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500485void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500486__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500487{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500488 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
489 dprintf(1, "invalid %s:%d:\n", fname, lineno);
490 dump_regs(regs);
491 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400492}
493
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500494// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400495void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500496__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
497{
498 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
499 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
500 dump_regs(regs);
501 }
502}
503
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500504// Report a detected internal inconsistency.
505void
506__warn_internalerror(int lineno, const char *fname)
507{
508 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
509 , fname, lineno);
510}
511
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500512// Report on an allocation failure.
513void
514__warn_noalloc(int lineno, const char *fname)
515{
516 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
517 , fname, lineno);
518}
519
520// Report on a timeout exceeded.
521void
522__warn_timeout(int lineno, const char *fname)
523{
524 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
525}
526
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500527// Report a handler reporting an invalid parameter to the caller.
528void
529__set_invalid(struct bregs *regs, int lineno, const char *fname)
530{
531 __warn_invalid(regs, lineno, fname);
532 set_invalid_silent(regs);
533}
534
535// Report a call of an unimplemented function.
536void
537__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
538{
539 __warn_unimplemented(regs, lineno, fname);
540 set_invalid_silent(regs);
541}
542
543// Report a handler reporting an invalid parameter code to the
544// caller. Note, the lineno and return code are encoded in the same
545// parameter as gcc does a better job of scheduling function calls
546// when there are 3 or less parameters.
547void
548__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400549{
Kevin O'Connor05600342009-01-02 13:10:58 -0500550 u8 code = linecode;
551 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500552 __warn_invalid(regs, lineno, fname);
553 set_code_invalid_silent(regs, code);
554}
555
556// Report a call of an unimplemented function.
557void
558__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
559{
560 u8 code = linecode;
561 u32 lineno = linecode >> 8;
562 __warn_unimplemented(regs, lineno, fname);
563 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500564}