blob: ec51f5e2f6ecf012825e9069e43ccde8232f947e [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'Connor7b673002016-02-03 03:03:15 -050013#include "hw/pci.h" // pci_bdf_to_bus
Kevin O'Connor4d8510c2016-02-03 01:28:20 -050014#include "hw/pcidevice.h" // pci_device
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050015#include "hw/serialio.h" // serial_debug_putc
Kevin O'Connor9dea5902013-09-14 20:23:54 -040016#include "malloc.h" // malloc_tmp
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040017#include "output.h" // dprintf
Kevin O'Connor3df600b2013-09-14 19:28:55 -040018#include "stacks.h" // call16_int
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040019#include "string.h" // memset
Kevin O'Connor2d2fa312013-09-14 21:55:26 -040020#include "util.h" // ScreenAndDebug
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050021
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040022struct putcinfo {
23 void (*func)(struct putcinfo *info, char c);
24};
25
26
27/****************************************************************
28 * Debug output
29 ****************************************************************/
30
Kevin O'Connorbb1fcb42014-01-15 13:52:14 -050031void
32debug_banner(void)
33{
34 dprintf(1, "SeaBIOS (version %s)\n", VERSION);
Kevin O'Connorefd70a52015-10-13 15:44:25 -040035 dprintf(1, "BUILD: %s\n", BUILDINFO);
Kevin O'Connorbb1fcb42014-01-15 13:52:14 -050036}
37
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040038// Write a character to debug port(s).
39static void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050040debug_putc(struct putcinfo *action, char c)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040041{
42 if (! CONFIG_DEBUG_LEVEL)
43 return;
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050044 qemu_debug_putc(c);
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020045 if (!MODESEGMENT)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050046 coreboot_debug_putc(c);
47 serial_debug_putc(c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040048}
49
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050050// Flush any pending output to debug port(s).
51static void
52debug_flush(void)
53{
54 serial_debug_flush();
55}
56
57// In segmented mode just need a dummy variable (debug_putc is always
Kevin O'Connor52a300f2009-12-26 23:32:57 -050058// used anyway), and in 32bit flat mode need a pointer to the 32bit
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050059// instance of debug_putc().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050060#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040061static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050062#elif MODESEGMENT
63static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -040064#else
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050065static struct putcinfo debuginfo = { debug_putc };
Kevin O'Connorebd426b2009-10-08 08:51:24 -040066#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040067
68
69/****************************************************************
70 * Screen writing
71 ****************************************************************/
72
Kevin O'Connor65e63422008-07-19 14:12:32 -040073// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050074static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040075screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050076{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050077 struct bregs br;
78 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -040079 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050080 br.ah = 0x0e;
81 br.al = c;
Kevin O'Connorf6b44b82014-04-05 21:45:27 -040082 br.bl = 0x07;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050083 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050084}
85
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040086// Handle a character from a printf request.
87static void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050088screen_putc(struct putcinfo *action, char c)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040089{
Kevin O'Connor422263d2011-07-05 20:56:07 -040090 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050091 debug_putc(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040092 if (c == '\n')
93 screenc('\r');
94 screenc(c);
95}
96
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050097static struct putcinfo screeninfo = { screen_putc };
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040098
99
100/****************************************************************
101 * Xprintf code
102 ****************************************************************/
103
Kevin O'Connor65e63422008-07-19 14:12:32 -0400104// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500105static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400106putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500107{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500108 if (MODESEGMENT) {
109 // Only debugging output supported in segmented mode.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500110 debug_putc(action, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400111 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400112 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400113
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400114 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
115 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500116}
117
Kevin O'Connor65e63422008-07-19 14:12:32 -0400118// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500119static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400120puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500121{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500122 if (!MODESEGMENT && !s)
123 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500124 for (; *s; s++)
125 putc(action, *s);
126}
127
Kevin O'Connor65e63422008-07-19 14:12:32 -0400128// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500129static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400130puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500131{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400132 char *vs = (char*)s;
133 for (;; vs++) {
134 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500135 if (!c)
136 break;
137 putc(action, c);
138 }
139}
140
Kevin O'Connor65e63422008-07-19 14:12:32 -0400141// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500142static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400143putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500144{
145 char buf[12];
146 char *d = &buf[sizeof(buf) - 1];
147 *d-- = '\0';
148 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500149 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500150 val /= 10;
151 if (!val)
152 break;
153 d--;
154 }
155 puts(action, d);
156}
157
Kevin O'Connor65e63422008-07-19 14:12:32 -0400158// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500159static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400160putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500161{
162 if (val <= 9)
163 val = '0' + val;
164 else
165 val = 'a' + val - 10;
166 putc(action, val);
167}
168
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500169// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500170static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500171puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500172{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400173 switch (width) {
174 default: putsinglehex(action, (val >> 28) & 0xf);
175 case 7: putsinglehex(action, (val >> 24) & 0xf);
176 case 6: putsinglehex(action, (val >> 20) & 0xf);
177 case 5: putsinglehex(action, (val >> 16) & 0xf);
178 case 4: putsinglehex(action, (val >> 12) & 0xf);
179 case 3: putsinglehex(action, (val >> 8) & 0xf);
180 case 2: putsinglehex(action, (val >> 4) & 0xf);
181 case 1: putsinglehex(action, (val >> 0) & 0xf);
182 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500183}
184
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500185// Output an integer in hexadecimal with a minimum width.
186static void
187putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
188{
189 u32 tmp = val;
190 int count = 1;
191 while (tmp >>= 4)
192 count++;
193 width -= count;
194 while (width-- > 0)
195 putc(action, padchar);
196 puthex(action, val, count);
197}
198
Kevin O'Connor7b673002016-02-03 03:03:15 -0500199// Output 'struct pci_device' BDF as %02x:%02x.%x
200static void
201put_pci_device(struct putcinfo *action, struct pci_device *pci)
202{
203 puthex(action, pci_bdf_to_bus(pci->bdf), 2);
204 putc(action, ':');
205 puthex(action, pci_bdf_to_dev(pci->bdf), 2);
206 putc(action, '.');
207 puthex(action, pci_bdf_to_fn(pci->bdf), 1);
208}
209
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500210static inline int
211isdigit(u8 c)
212{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400213 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500214}
215
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400216static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400217bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500218{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500219 const char *s = fmt;
220 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500221 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500222 if (!c)
223 break;
224 if (c != '%') {
225 putc(action, c);
226 continue;
227 }
228 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400229 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500230 char padchar = ' ';
231 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500232 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500233 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500234 if (!isdigit(c))
235 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400236 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500237 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400238 else
239 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500240 n++;
241 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500242 if (c == 'l') {
243 // Ignore long format indicator
244 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500245 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500246 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500247 if (c == 'l') {
248 is64 = 1;
249 n++;
250 c = GET_GLOBAL(*(u8*)n);
251 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500252 s32 val;
253 const char *sarg;
254 switch (c) {
255 case '%':
256 putc(action, '%');
257 break;
258 case 'd':
259 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500260 if (is64)
261 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500262 if (val < 0) {
263 putc(action, '-');
264 val = -val;
265 }
266 putuint(action, val);
267 break;
268 case 'u':
269 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500270 if (is64)
271 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500272 putuint(action, val);
273 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400274 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500275 val = va_arg(args, s32);
Kevin O'Connor7b673002016-02-03 03:03:15 -0500276 if (!MODESEGMENT && GET_GLOBAL(*(u8*)(n+1)) == 'P') {
277 // %pP is 'struct pci_device' printer
278 put_pci_device(action, (void*)val);
279 n++;
280 break;
281 }
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400282 putc(action, '0');
283 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500284 puthex(action, val, 8);
285 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500286 case 'x':
287 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500288 if (is64) {
289 u32 upper = va_arg(args, s32);
290 if (upper) {
291 putprettyhex(action, upper, field_width - 8, padchar);
292 puthex(action, val, 8);
293 break;
294 }
295 }
296 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500297 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500298 case 'c':
299 val = va_arg(args, int);
300 putc(action, val);
301 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400302 case '.':
303 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500304 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400305 break;
306 n++;
307 sarg = va_arg(args, const char *);
308 puts(action, sarg);
309 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500310 case 's':
311 sarg = va_arg(args, const char *);
312 puts_cs(action, sarg);
313 break;
314 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500315 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500316 n = s;
317 }
318 s = n;
319 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400320}
321
322void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500323panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400324{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400325 if (CONFIG_DEBUG_LEVEL) {
326 va_list args;
327 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400328 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400329 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500330 debug_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400331 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400332
333 // XXX - use PANIC PORT.
334 irq_disable();
335 for (;;)
336 hlt();
337}
338
339void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400340__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400341{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500342 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400343 && *fmt != '\\' && *fmt != '/') {
344 struct thread_info *cur = getCurThread();
345 if (cur != &MainThread) {
346 // Show "thread id" for this debug message.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500347 debug_putc(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500348 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500349 debug_putc(&debuginfo, '|');
350 debug_putc(&debuginfo, ' ');
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400351 }
352 }
353
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400354 va_list args;
355 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400356 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400357 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500358 debug_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400359}
360
361void
362printf(const char *fmt, ...)
363{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500364 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400365 va_list args;
366 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400367 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500368 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400369 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500370 debug_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500371}
372
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400373
374/****************************************************************
375 * snprintf
376 ****************************************************************/
377
378struct snprintfinfo {
379 struct putcinfo info;
380 char *str, *end;
381};
382
383static void
384putc_str(struct putcinfo *info, char c)
385{
386 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
387 if (sinfo->str >= sinfo->end)
388 return;
389 *sinfo->str = c;
390 sinfo->str++;
391}
392
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500393// Build a formatted string. Note, this function returns the actual
394// number of bytes used (not including null) even in the overflow
395// case.
396int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400397snprintf(char *str, size_t size, const char *fmt, ...)
398{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500399 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400400 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500401 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400402 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
403 va_list args;
404 va_start(args, fmt);
405 bvprintf(&sinfo.info, fmt, args);
406 va_end(args);
407 char *end = sinfo.str;
408 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500409 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400410 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500411 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400412}
413
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500414// Build a formatted string - malloc'ing the memory.
415char *
416znprintf(size_t size, const char *fmt, ...)
417{
418 ASSERT32FLAT();
419 if (!size)
420 return NULL;
421 char *str = malloc_tmp(size);
422 if (!str) {
423 warn_noalloc();
424 return NULL;
425 }
426 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
427 va_list args;
428 va_start(args, fmt);
429 bvprintf(&sinfo.info, fmt, args);
430 va_end(args);
431 char *end = sinfo.str;
432 if (end >= sinfo.end)
433 end = sinfo.end - 1;
434 *end = '\0';
435 return str;
436}
437
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400438
439/****************************************************************
440 * Misc helpers
441 ****************************************************************/
442
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500443void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400444hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500445{
446 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400447 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500448 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400449 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500450 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400451 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500452 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400453 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500454 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500455 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500456 count++;
457 len-=4;
458 d+=4;
459 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400460 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500461 debug_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500462}
463
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500464static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400465dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500466{
467 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400468 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500469 return;
470 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400471 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 -0400472 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400473 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400474 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
475 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400476 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500477}
478
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400479// Report entry to an Interrupt Service Routine (ISR).
480void
481__debug_isr(const char *fname)
482{
483 puts_cs(&debuginfo, fname);
484 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500485 debug_flush();
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400486}
487
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500488// Function called on handler startup.
489void
Kevin O'Connor05600342009-01-02 13:10:58 -0500490__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500491{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400492 dprintf(1, "enter %s:\n", fname);
493 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500494}
495
Kevin O'Connor05600342009-01-02 13:10:58 -0500496// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500497void
Kevin O'Connor05600342009-01-02 13:10:58 -0500498__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500499{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400500 dprintf(1, "stub %s:%d:\n", fname, lineno);
501 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500502}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500503
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500504// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500505void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500506__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500507{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500508 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
509 dprintf(1, "invalid %s:%d:\n", fname, lineno);
510 dump_regs(regs);
511 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400512}
513
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500514// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400515void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500516__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
517{
518 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
519 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
520 dump_regs(regs);
521 }
522}
523
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500524// Report a detected internal inconsistency.
525void
526__warn_internalerror(int lineno, const char *fname)
527{
528 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
529 , fname, lineno);
530}
531
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500532// Report on an allocation failure.
533void
534__warn_noalloc(int lineno, const char *fname)
535{
536 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
537 , fname, lineno);
538}
539
540// Report on a timeout exceeded.
541void
542__warn_timeout(int lineno, const char *fname)
543{
544 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
545}
546
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500547// Report a handler reporting an invalid parameter to the caller.
548void
549__set_invalid(struct bregs *regs, int lineno, const char *fname)
550{
551 __warn_invalid(regs, lineno, fname);
552 set_invalid_silent(regs);
553}
554
555// Report a call of an unimplemented function.
556void
557__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
558{
559 __warn_unimplemented(regs, lineno, fname);
560 set_invalid_silent(regs);
561}
562
563// Report a handler reporting an invalid parameter code to the
564// caller. Note, the lineno and return code are encoded in the same
565// parameter as gcc does a better job of scheduling function calls
566// when there are 3 or less parameters.
567void
568__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400569{
Kevin O'Connor05600342009-01-02 13:10:58 -0500570 u8 code = linecode;
571 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500572 __warn_invalid(regs, lineno, fname);
573 set_code_invalid_silent(regs, code);
574}
575
576// Report a call of an unimplemented function.
577void
578__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
579{
580 u8 code = linecode;
581 u32 lineno = linecode >> 8;
582 __warn_unimplemented(regs, lineno, fname);
583 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500584}