blob: 8b63d9abcf392ba5e3273ff09337ef7a69dc3df5 [file] [log] [blame]
Kevin O'Connor65e63422008-07-19 14:12:32 -04001// Raw screen writing and debug output code.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05002//
Kevin O'Connor43562762009-10-12 09:48:12 -04003// Copyright (C) 2008,2009 Kevin O'Connor <kevin@koconnor.net>
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05004//
Kevin O'Connorb1b7c2a2009-01-15 20:52:58 -05005// This file may be distributed under the terms of the GNU LGPLv3 license.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05006
7#include <stdarg.h> // va_list
8
9#include "farptr.h" // GET_VAR
Kevin O'Connor567e4e32008-04-05 11:37:51 -040010#include "util.h" // printf
Kevin O'Connor9521e262008-07-04 13:04:29 -040011#include "bregs.h" // struct bregs
12#include "config.h" // CONFIG_*
Kevin O'Connor15157a32008-12-13 11:10:37 -050013#include "biosvar.h" // GET_GLOBAL
Kevin O'Connorccee6e82013-09-02 21:25:21 -040014#include "fw/paravirt.h" // PlatformRunningOn
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050015
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040016struct putcinfo {
17 void (*func)(struct putcinfo *info, char c);
18};
19
20
21/****************************************************************
22 * Debug output
23 ****************************************************************/
24
Kevin O'Connor5c732402008-06-07 10:43:07 -040025#define DEBUG_TIMEOUT 100000
26
Kevin O'Connor89a2f962013-02-18 23:36:03 -050027u16 DebugOutputPort VARFSEG = 0x402;
Ian Campbell54f3b252012-06-28 11:08:32 +010028
Kevin O'Connor61d6b062008-06-21 12:15:10 -040029void
Kevin O'Connord83c87b2013-01-21 01:14:12 -050030debug_serial_preinit(void)
Kevin O'Connor61d6b062008-06-21 12:15:10 -040031{
32 if (!CONFIG_DEBUG_SERIAL)
33 return;
34 // setup for serial logging: 8N1
35 u8 oldparam, newparam = 0x03;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040036 oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
37 outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040038 // Disable irqs
39 u8 oldier, newier = 0;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040040 oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
41 outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040042
43 if (oldparam != newparam || oldier != newier)
44 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
45 , oldparam, oldier, newparam, newier);
46}
47
Kevin O'Connor65e63422008-07-19 14:12:32 -040048// Write a character to the serial port.
Kevin O'Connor5c732402008-06-07 10:43:07 -040049static void
50debug_serial(char c)
51{
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040052 if (!CONFIG_DEBUG_SERIAL)
53 return;
Kevin O'Connor5c732402008-06-07 10:43:07 -040054 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040055 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
Kevin O'Connor5c732402008-06-07 10:43:07 -040056 if (!timeout--)
57 // Ran out of time.
58 return;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040059 outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
Kevin O'Connor5c732402008-06-07 10:43:07 -040060}
61
Kevin O'Connorb9e62d22009-08-02 13:18:27 -040062// Make sure all serial port writes have been completely sent.
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040063static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050064debug_serial_flush(void)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040065{
66 if (!CONFIG_DEBUG_SERIAL)
67 return;
68 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040069 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040070 if (!timeout--)
71 // Ran out of time.
72 return;
73}
74
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040075// Write a character to debug port(s).
76static void
77putc_debug(struct putcinfo *action, char c)
78{
79 if (! CONFIG_DEBUG_LEVEL)
80 return;
Gerd Hoffmann2ca73ed2013-06-05 09:37:24 +020081 if (CONFIG_DEBUG_IO && runningOnQEMU())
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040082 // Send character to debug port.
Ian Campbell54f3b252012-06-28 11:08:32 +010083 outb(c, GET_GLOBAL(DebugOutputPort));
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020084 if (!MODESEGMENT)
85 debug_cbmem(c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040086 if (c == '\n')
87 debug_serial('\r');
88 debug_serial(c);
89}
90
Kevin O'Connor52a300f2009-12-26 23:32:57 -050091// In segmented mode just need a dummy variable (putc_debug is always
92// used anyway), and in 32bit flat mode need a pointer to the 32bit
93// instance of putc_debug().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050094#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040095static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050096#elif MODESEGMENT
97static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -040098#else
99static struct putcinfo debuginfo = { putc_debug };
100#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400101
102
103/****************************************************************
104 * Screen writing
105 ****************************************************************/
106
Kevin O'Connor65e63422008-07-19 14:12:32 -0400107// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500108static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400109screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500110{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500111 struct bregs br;
112 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -0400113 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500114 br.ah = 0x0e;
115 br.al = c;
116 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500117}
118
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400119// Handle a character from a printf request.
120static void
121putc_screen(struct putcinfo *action, char c)
122{
Kevin O'Connor422263d2011-07-05 20:56:07 -0400123 if (ScreenAndDebug)
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400124 putc_debug(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400125 if (c == '\n')
126 screenc('\r');
127 screenc(c);
128}
129
130static struct putcinfo screeninfo = { putc_screen };
131
132
133/****************************************************************
134 * Xprintf code
135 ****************************************************************/
136
Kevin O'Connor65e63422008-07-19 14:12:32 -0400137// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500138static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400139putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500140{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500141 if (MODESEGMENT) {
142 // Only debugging output supported in segmented mode.
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400143 putc_debug(action, c);
144 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400145 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400146
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400147 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
148 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500149}
150
Kevin O'Connor65e63422008-07-19 14:12:32 -0400151// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500152static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400153puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500154{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500155 if (!MODESEGMENT && !s)
156 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500157 for (; *s; s++)
158 putc(action, *s);
159}
160
Kevin O'Connor65e63422008-07-19 14:12:32 -0400161// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500162static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400163puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500164{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400165 char *vs = (char*)s;
166 for (;; vs++) {
167 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500168 if (!c)
169 break;
170 putc(action, c);
171 }
172}
173
Kevin O'Connor65e63422008-07-19 14:12:32 -0400174// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500175static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400176putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500177{
178 char buf[12];
179 char *d = &buf[sizeof(buf) - 1];
180 *d-- = '\0';
181 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500182 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500183 val /= 10;
184 if (!val)
185 break;
186 d--;
187 }
188 puts(action, d);
189}
190
Kevin O'Connor65e63422008-07-19 14:12:32 -0400191// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500192static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400193putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500194{
195 if (val <= 9)
196 val = '0' + val;
197 else
198 val = 'a' + val - 10;
199 putc(action, val);
200}
201
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500202// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500203static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500204puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500205{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400206 switch (width) {
207 default: putsinglehex(action, (val >> 28) & 0xf);
208 case 7: putsinglehex(action, (val >> 24) & 0xf);
209 case 6: putsinglehex(action, (val >> 20) & 0xf);
210 case 5: putsinglehex(action, (val >> 16) & 0xf);
211 case 4: putsinglehex(action, (val >> 12) & 0xf);
212 case 3: putsinglehex(action, (val >> 8) & 0xf);
213 case 2: putsinglehex(action, (val >> 4) & 0xf);
214 case 1: putsinglehex(action, (val >> 0) & 0xf);
215 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500216}
217
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500218// Output an integer in hexadecimal with a minimum width.
219static void
220putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
221{
222 u32 tmp = val;
223 int count = 1;
224 while (tmp >>= 4)
225 count++;
226 width -= count;
227 while (width-- > 0)
228 putc(action, padchar);
229 puthex(action, val, count);
230}
231
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500232static inline int
233isdigit(u8 c)
234{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400235 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500236}
237
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400238static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400239bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500240{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500241 const char *s = fmt;
242 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500243 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500244 if (!c)
245 break;
246 if (c != '%') {
247 putc(action, c);
248 continue;
249 }
250 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400251 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500252 char padchar = ' ';
253 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500254 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500255 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500256 if (!isdigit(c))
257 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400258 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500259 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400260 else
261 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500262 n++;
263 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500264 if (c == 'l') {
265 // Ignore long format indicator
266 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500267 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500268 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500269 if (c == 'l') {
270 is64 = 1;
271 n++;
272 c = GET_GLOBAL(*(u8*)n);
273 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500274 s32 val;
275 const char *sarg;
276 switch (c) {
277 case '%':
278 putc(action, '%');
279 break;
280 case 'd':
281 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500282 if (is64)
283 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500284 if (val < 0) {
285 putc(action, '-');
286 val = -val;
287 }
288 putuint(action, val);
289 break;
290 case 'u':
291 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500292 if (is64)
293 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500294 putuint(action, val);
295 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400296 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500297 val = va_arg(args, s32);
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400298 putc(action, '0');
299 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500300 puthex(action, val, 8);
301 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500302 case 'x':
303 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500304 if (is64) {
305 u32 upper = va_arg(args, s32);
306 if (upper) {
307 putprettyhex(action, upper, field_width - 8, padchar);
308 puthex(action, val, 8);
309 break;
310 }
311 }
312 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500313 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500314 case 'c':
315 val = va_arg(args, int);
316 putc(action, val);
317 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400318 case '.':
319 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500320 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400321 break;
322 n++;
323 sarg = va_arg(args, const char *);
324 puts(action, sarg);
325 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500326 case 's':
327 sarg = va_arg(args, const char *);
328 puts_cs(action, sarg);
329 break;
330 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500331 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500332 n = s;
333 }
334 s = n;
335 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400336}
337
338void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500339panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400340{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400341 if (CONFIG_DEBUG_LEVEL) {
342 va_list args;
343 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400344 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400345 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400346 debug_serial_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400347 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400348
349 // XXX - use PANIC PORT.
350 irq_disable();
351 for (;;)
352 hlt();
353}
354
355void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400356__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400357{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500358 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400359 && *fmt != '\\' && *fmt != '/') {
360 struct thread_info *cur = getCurThread();
361 if (cur != &MainThread) {
362 // Show "thread id" for this debug message.
363 putc_debug(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500364 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400365 putc_debug(&debuginfo, '|');
366 putc_debug(&debuginfo, ' ');
367 }
368 }
369
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400370 va_list args;
371 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400372 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400373 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400374 debug_serial_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400375}
376
377void
378printf(const char *fmt, ...)
379{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500380 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400381 va_list args;
382 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400383 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500384 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400385 if (ScreenAndDebug)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400386 debug_serial_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500387}
388
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400389
390/****************************************************************
391 * snprintf
392 ****************************************************************/
393
394struct snprintfinfo {
395 struct putcinfo info;
396 char *str, *end;
397};
398
399static void
400putc_str(struct putcinfo *info, char c)
401{
402 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
403 if (sinfo->str >= sinfo->end)
404 return;
405 *sinfo->str = c;
406 sinfo->str++;
407}
408
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500409// Build a formatted string. Note, this function returns the actual
410// number of bytes used (not including null) even in the overflow
411// case.
412int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400413snprintf(char *str, size_t size, const char *fmt, ...)
414{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500415 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400416 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500417 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400418 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
419 va_list args;
420 va_start(args, fmt);
421 bvprintf(&sinfo.info, fmt, args);
422 va_end(args);
423 char *end = sinfo.str;
424 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500425 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400426 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500427 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400428}
429
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500430// Build a formatted string - malloc'ing the memory.
431char *
432znprintf(size_t size, const char *fmt, ...)
433{
434 ASSERT32FLAT();
435 if (!size)
436 return NULL;
437 char *str = malloc_tmp(size);
438 if (!str) {
439 warn_noalloc();
440 return NULL;
441 }
442 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
443 va_list args;
444 va_start(args, fmt);
445 bvprintf(&sinfo.info, fmt, args);
446 va_end(args);
447 char *end = sinfo.str;
448 if (end >= sinfo.end)
449 end = sinfo.end - 1;
450 *end = '\0';
451 return str;
452}
453
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400454
455/****************************************************************
456 * Misc helpers
457 ****************************************************************/
458
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500459void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400460hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500461{
462 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400463 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500464 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400465 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500466 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400467 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500468 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400469 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500470 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500471 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500472 count++;
473 len-=4;
474 d+=4;
475 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400476 putc(&debuginfo, '\n');
Kevin O'Connor3e832bb2009-05-15 22:22:12 -0400477 debug_serial_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500478}
479
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500480static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400481dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500482{
483 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400484 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500485 return;
486 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400487 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 -0400488 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400489 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400490 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
491 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400492 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500493}
494
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400495// Report entry to an Interrupt Service Routine (ISR).
496void
497__debug_isr(const char *fname)
498{
499 puts_cs(&debuginfo, fname);
500 putc(&debuginfo, '\n');
501 debug_serial_flush();
502}
503
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500504// Function called on handler startup.
505void
Kevin O'Connor05600342009-01-02 13:10:58 -0500506__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500507{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400508 dprintf(1, "enter %s:\n", fname);
509 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500510}
511
Kevin O'Connor05600342009-01-02 13:10:58 -0500512// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500513void
Kevin O'Connor05600342009-01-02 13:10:58 -0500514__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500515{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400516 dprintf(1, "stub %s:%d:\n", fname, lineno);
517 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500518}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500519
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500520// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500521void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500522__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500523{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500524 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
525 dprintf(1, "invalid %s:%d:\n", fname, lineno);
526 dump_regs(regs);
527 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400528}
529
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500530// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400531void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500532__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
533{
534 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
535 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
536 dump_regs(regs);
537 }
538}
539
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500540// Report a detected internal inconsistency.
541void
542__warn_internalerror(int lineno, const char *fname)
543{
544 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
545 , fname, lineno);
546}
547
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500548// Report on an allocation failure.
549void
550__warn_noalloc(int lineno, const char *fname)
551{
552 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
553 , fname, lineno);
554}
555
556// Report on a timeout exceeded.
557void
558__warn_timeout(int lineno, const char *fname)
559{
560 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
561}
562
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500563// Report a handler reporting an invalid parameter to the caller.
564void
565__set_invalid(struct bregs *regs, int lineno, const char *fname)
566{
567 __warn_invalid(regs, lineno, fname);
568 set_invalid_silent(regs);
569}
570
571// Report a call of an unimplemented function.
572void
573__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
574{
575 __warn_unimplemented(regs, lineno, fname);
576 set_invalid_silent(regs);
577}
578
579// Report a handler reporting an invalid parameter code to the
580// caller. Note, the lineno and return code are encoded in the same
581// parameter as gcc does a better job of scheduling function calls
582// when there are 3 or less parameters.
583void
584__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400585{
Kevin O'Connor05600342009-01-02 13:10:58 -0500586 u8 code = linecode;
587 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500588 __warn_invalid(regs, lineno, fname);
589 set_code_invalid_silent(regs, code);
590}
591
592// Report a call of an unimplemented function.
593void
594__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
595{
596 u8 code = linecode;
597 u32 lineno = linecode >> 8;
598 __warn_unimplemented(regs, lineno, fname);
599 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500600}