blob: 3c335cbb28e2383c6c94474437626c804b405904 [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'Connor29ba89e2018-12-17 10:23:49 -050077 if (!MODESEGMENT && GET_IVT(0x10).segoff == FUNC16(entry_10).segoff)
78 // No need to thunk to 16bit mode if vgabios is not present
79 return;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050080 struct bregs br;
81 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -040082 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050083 br.ah = 0x0e;
84 br.al = c;
Kevin O'Connorf6b44b82014-04-05 21:45:27 -040085 br.bl = 0x07;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -050086 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050087}
88
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040089// Handle a character from a printf request.
90static void
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050091screen_putc(struct putcinfo *action, char c)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040092{
Kevin O'Connor422263d2011-07-05 20:56:07 -040093 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -050094 debug_putc(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040095 if (c == '\n')
96 screenc('\r');
97 screenc(c);
98}
99
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500100static struct putcinfo screeninfo = { screen_putc };
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400101
102
103/****************************************************************
104 * Xprintf code
105 ****************************************************************/
106
Kevin O'Connor65e63422008-07-19 14:12:32 -0400107// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500108static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400109putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500110{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500111 if (MODESEGMENT) {
112 // Only debugging output supported in segmented mode.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500113 debug_putc(action, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400114 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400115 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400116
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400117 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
118 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500119}
120
Kevin O'Connor65e63422008-07-19 14:12:32 -0400121// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500122static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400123puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500124{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500125 if (!MODESEGMENT && !s)
126 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500127 for (; *s; s++)
128 putc(action, *s);
129}
130
Kevin O'Connor65e63422008-07-19 14:12:32 -0400131// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500132static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400133puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500134{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400135 char *vs = (char*)s;
136 for (;; vs++) {
137 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500138 if (!c)
139 break;
140 putc(action, c);
141 }
142}
143
Kevin O'Connor65e63422008-07-19 14:12:32 -0400144// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500145static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400146putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500147{
148 char buf[12];
149 char *d = &buf[sizeof(buf) - 1];
150 *d-- = '\0';
151 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500152 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500153 val /= 10;
154 if (!val)
155 break;
156 d--;
157 }
158 puts(action, d);
159}
160
Kevin O'Connor65e63422008-07-19 14:12:32 -0400161// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500162static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400163putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500164{
165 if (val <= 9)
166 val = '0' + val;
167 else
168 val = 'a' + val - 10;
169 putc(action, val);
170}
171
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500172// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500173static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500174puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500175{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400176 switch (width) {
177 default: putsinglehex(action, (val >> 28) & 0xf);
178 case 7: putsinglehex(action, (val >> 24) & 0xf);
179 case 6: putsinglehex(action, (val >> 20) & 0xf);
180 case 5: putsinglehex(action, (val >> 16) & 0xf);
181 case 4: putsinglehex(action, (val >> 12) & 0xf);
182 case 3: putsinglehex(action, (val >> 8) & 0xf);
183 case 2: putsinglehex(action, (val >> 4) & 0xf);
184 case 1: putsinglehex(action, (val >> 0) & 0xf);
185 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500186}
187
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500188// Output an integer in hexadecimal with a minimum width.
189static void
190putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
191{
192 u32 tmp = val;
193 int count = 1;
194 while (tmp >>= 4)
195 count++;
196 width -= count;
197 while (width-- > 0)
198 putc(action, padchar);
199 puthex(action, val, count);
200}
201
Kevin O'Connor7b673002016-02-03 03:03:15 -0500202// Output 'struct pci_device' BDF as %02x:%02x.%x
203static void
204put_pci_device(struct putcinfo *action, struct pci_device *pci)
205{
206 puthex(action, pci_bdf_to_bus(pci->bdf), 2);
207 putc(action, ':');
208 puthex(action, pci_bdf_to_dev(pci->bdf), 2);
209 putc(action, '.');
210 puthex(action, pci_bdf_to_fn(pci->bdf), 1);
211}
212
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500213static inline int
214isdigit(u8 c)
215{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400216 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500217}
218
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400219static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400220bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500221{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500222 const char *s = fmt;
223 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500224 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500225 if (!c)
226 break;
227 if (c != '%') {
228 putc(action, c);
229 continue;
230 }
231 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400232 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500233 char padchar = ' ';
234 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500235 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500236 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500237 if (!isdigit(c))
238 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400239 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500240 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400241 else
242 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500243 n++;
244 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500245 if (c == 'l') {
246 // Ignore long format indicator
247 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500248 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500249 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500250 if (c == 'l') {
251 is64 = 1;
252 n++;
253 c = GET_GLOBAL(*(u8*)n);
254 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500255 s32 val;
256 const char *sarg;
257 switch (c) {
258 case '%':
259 putc(action, '%');
260 break;
261 case 'd':
262 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500263 if (is64)
264 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500265 if (val < 0) {
266 putc(action, '-');
267 val = -val;
268 }
269 putuint(action, val);
270 break;
271 case 'u':
272 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500273 if (is64)
274 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500275 putuint(action, val);
276 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400277 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500278 val = va_arg(args, s32);
Kevin O'Connor7b673002016-02-03 03:03:15 -0500279 if (!MODESEGMENT && GET_GLOBAL(*(u8*)(n+1)) == 'P') {
280 // %pP is 'struct pci_device' printer
281 put_pci_device(action, (void*)val);
282 n++;
283 break;
284 }
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400285 putc(action, '0');
286 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500287 puthex(action, val, 8);
288 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500289 case 'x':
290 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500291 if (is64) {
292 u32 upper = va_arg(args, s32);
293 if (upper) {
294 putprettyhex(action, upper, field_width - 8, padchar);
295 puthex(action, val, 8);
296 break;
297 }
298 }
299 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500300 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500301 case 'c':
302 val = va_arg(args, int);
303 putc(action, val);
304 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400305 case '.':
306 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500307 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400308 break;
309 n++;
310 sarg = va_arg(args, const char *);
311 puts(action, sarg);
312 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500313 case 's':
314 sarg = va_arg(args, const char *);
315 puts_cs(action, sarg);
316 break;
317 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500318 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500319 n = s;
320 }
321 s = n;
322 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400323}
324
325void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500326panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400327{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400328 if (CONFIG_DEBUG_LEVEL) {
329 va_list args;
330 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400331 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400332 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500333 debug_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400334 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400335
336 // XXX - use PANIC PORT.
337 irq_disable();
338 for (;;)
339 hlt();
340}
341
342void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400343__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400344{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500345 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400346 && *fmt != '\\' && *fmt != '/') {
347 struct thread_info *cur = getCurThread();
348 if (cur != &MainThread) {
349 // Show "thread id" for this debug message.
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500350 debug_putc(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500351 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500352 debug_putc(&debuginfo, '|');
353 debug_putc(&debuginfo, ' ');
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400354 }
355 }
356
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400357 va_list args;
358 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400359 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400360 va_end(args);
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500361 debug_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400362}
363
364void
365printf(const char *fmt, ...)
366{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500367 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400368 va_list args;
369 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400370 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500371 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400372 if (ScreenAndDebug)
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500373 debug_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500374}
375
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400376
377/****************************************************************
378 * snprintf
379 ****************************************************************/
380
381struct snprintfinfo {
382 struct putcinfo info;
383 char *str, *end;
384};
385
386static void
387putc_str(struct putcinfo *info, char c)
388{
389 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
390 if (sinfo->str >= sinfo->end)
391 return;
392 *sinfo->str = c;
393 sinfo->str++;
394}
395
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500396// Build a formatted string. Note, this function returns the actual
397// number of bytes used (not including null) even in the overflow
398// case.
399int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400400snprintf(char *str, size_t size, const char *fmt, ...)
401{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500402 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400403 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500404 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400405 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)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500412 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400413 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500414 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400415}
416
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500417// Build a formatted string - malloc'ing the memory.
418char *
419znprintf(size_t size, const char *fmt, ...)
420{
421 ASSERT32FLAT();
422 if (!size)
423 return NULL;
424 char *str = malloc_tmp(size);
425 if (!str) {
426 warn_noalloc();
427 return NULL;
428 }
429 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
430 va_list args;
431 va_start(args, fmt);
432 bvprintf(&sinfo.info, fmt, args);
433 va_end(args);
434 char *end = sinfo.str;
435 if (end >= sinfo.end)
436 end = sinfo.end - 1;
437 *end = '\0';
438 return str;
439}
440
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400441
442/****************************************************************
443 * Misc helpers
444 ****************************************************************/
445
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500446void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400447hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500448{
449 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400450 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500451 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400452 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500453 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400454 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500455 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400456 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500457 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500458 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500459 count++;
460 len-=4;
461 d+=4;
462 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400463 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500464 debug_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500465}
466
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500467static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400468dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500469{
470 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400471 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500472 return;
473 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400474 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 -0400475 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400476 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400477 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
478 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400479 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500480}
481
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400482// Report entry to an Interrupt Service Routine (ISR).
483void
484__debug_isr(const char *fname)
485{
486 puts_cs(&debuginfo, fname);
487 putc(&debuginfo, '\n');
Kevin O'Connor4cd522e2013-11-29 12:14:34 -0500488 debug_flush();
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400489}
490
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500491// Function called on handler startup.
492void
Kevin O'Connor05600342009-01-02 13:10:58 -0500493__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500494{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400495 dprintf(1, "enter %s:\n", fname);
496 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500497}
498
Kevin O'Connor05600342009-01-02 13:10:58 -0500499// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500500void
Kevin O'Connor05600342009-01-02 13:10:58 -0500501__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500502{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400503 dprintf(1, "stub %s:%d:\n", fname, lineno);
504 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500505}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500506
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500507// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500508void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500509__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500510{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500511 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
512 dprintf(1, "invalid %s:%d:\n", fname, lineno);
513 dump_regs(regs);
514 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400515}
516
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500517// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400518void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500519__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
520{
521 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
522 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
523 dump_regs(regs);
524 }
525}
526
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500527// Report a detected internal inconsistency.
528void
529__warn_internalerror(int lineno, const char *fname)
530{
531 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
532 , fname, lineno);
533}
534
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500535// Report on an allocation failure.
536void
537__warn_noalloc(int lineno, const char *fname)
538{
539 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
540 , fname, lineno);
541}
542
543// Report on a timeout exceeded.
544void
545__warn_timeout(int lineno, const char *fname)
546{
547 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
548}
549
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500550// Report a handler reporting an invalid parameter to the caller.
551void
552__set_invalid(struct bregs *regs, int lineno, const char *fname)
553{
554 __warn_invalid(regs, lineno, fname);
555 set_invalid_silent(regs);
556}
557
558// Report a call of an unimplemented function.
559void
560__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
561{
562 __warn_unimplemented(regs, lineno, fname);
563 set_invalid_silent(regs);
564}
565
566// Report a handler reporting an invalid parameter code to the
567// caller. Note, the lineno and return code are encoded in the same
568// parameter as gcc does a better job of scheduling function calls
569// when there are 3 or less parameters.
570void
571__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400572{
Kevin O'Connor05600342009-01-02 13:10:58 -0500573 u8 code = linecode;
574 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500575 __warn_invalid(regs, lineno, fname);
576 set_code_invalid_silent(regs, code);
577}
578
579// Report a call of an unimplemented function.
580void
581__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
582{
583 u8 code = linecode;
584 u32 lineno = linecode >> 8;
585 __warn_unimplemented(regs, lineno, fname);
586 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500587}