blob: b5d7ae096c0ffe5d53889709adb33482ef2f7826 [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'Connor3df600b2013-09-14 19:28:55 -040015#include "stacks.h" // call16_int
Kevin O'Connorfa9c66a2013-09-14 19:10:40 -040016#include "string.h" // memset
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050017
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040018struct putcinfo {
19 void (*func)(struct putcinfo *info, char c);
20};
21
22
23/****************************************************************
24 * Debug output
25 ****************************************************************/
26
Kevin O'Connor5c732402008-06-07 10:43:07 -040027#define DEBUG_TIMEOUT 100000
28
Kevin O'Connor89a2f962013-02-18 23:36:03 -050029u16 DebugOutputPort VARFSEG = 0x402;
Ian Campbell54f3b252012-06-28 11:08:32 +010030
Kevin O'Connor61d6b062008-06-21 12:15:10 -040031void
Kevin O'Connord83c87b2013-01-21 01:14:12 -050032debug_serial_preinit(void)
Kevin O'Connor61d6b062008-06-21 12:15:10 -040033{
34 if (!CONFIG_DEBUG_SERIAL)
35 return;
36 // setup for serial logging: 8N1
37 u8 oldparam, newparam = 0x03;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040038 oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
39 outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040040 // Disable irqs
41 u8 oldier, newier = 0;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040042 oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
43 outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040044
45 if (oldparam != newparam || oldier != newier)
46 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
47 , oldparam, oldier, newparam, newier);
48}
49
Kevin O'Connor65e63422008-07-19 14:12:32 -040050// Write a character to the serial port.
Kevin O'Connor5c732402008-06-07 10:43:07 -040051static void
52debug_serial(char c)
53{
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040054 if (!CONFIG_DEBUG_SERIAL)
55 return;
Kevin O'Connor5c732402008-06-07 10:43:07 -040056 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040057 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
Kevin O'Connor5c732402008-06-07 10:43:07 -040058 if (!timeout--)
59 // Ran out of time.
60 return;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040061 outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
Kevin O'Connor5c732402008-06-07 10:43:07 -040062}
63
Kevin O'Connorb9e62d22009-08-02 13:18:27 -040064// Make sure all serial port writes have been completely sent.
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040065static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050066debug_serial_flush(void)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040067{
68 if (!CONFIG_DEBUG_SERIAL)
69 return;
70 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040071 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040072 if (!timeout--)
73 // Ran out of time.
74 return;
75}
76
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040077// Write a character to debug port(s).
78static void
79putc_debug(struct putcinfo *action, char c)
80{
81 if (! CONFIG_DEBUG_LEVEL)
82 return;
Gerd Hoffmann2ca73ed2013-06-05 09:37:24 +020083 if (CONFIG_DEBUG_IO && runningOnQEMU())
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040084 // Send character to debug port.
Ian Campbell54f3b252012-06-28 11:08:32 +010085 outb(c, GET_GLOBAL(DebugOutputPort));
Gerd Hoffmannebf03f72013-06-24 11:24:57 +020086 if (!MODESEGMENT)
87 debug_cbmem(c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040088 if (c == '\n')
89 debug_serial('\r');
90 debug_serial(c);
91}
92
Kevin O'Connor52a300f2009-12-26 23:32:57 -050093// In segmented mode just need a dummy variable (putc_debug is always
94// used anyway), and in 32bit flat mode need a pointer to the 32bit
95// instance of putc_debug().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050096#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040097static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050098#elif MODESEGMENT
99static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -0400100#else
101static struct putcinfo debuginfo = { putc_debug };
102#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400103
104
105/****************************************************************
106 * Screen writing
107 ****************************************************************/
108
Kevin O'Connor65e63422008-07-19 14:12:32 -0400109// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500110static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400111screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500112{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500113 struct bregs br;
114 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -0400115 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500116 br.ah = 0x0e;
117 br.al = c;
118 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500119}
120
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400121// Handle a character from a printf request.
122static void
123putc_screen(struct putcinfo *action, char c)
124{
Kevin O'Connor422263d2011-07-05 20:56:07 -0400125 if (ScreenAndDebug)
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400126 putc_debug(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400127 if (c == '\n')
128 screenc('\r');
129 screenc(c);
130}
131
132static struct putcinfo screeninfo = { putc_screen };
133
134
135/****************************************************************
136 * Xprintf code
137 ****************************************************************/
138
Kevin O'Connor65e63422008-07-19 14:12:32 -0400139// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500140static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400141putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500142{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500143 if (MODESEGMENT) {
144 // Only debugging output supported in segmented mode.
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400145 putc_debug(action, c);
146 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400147 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400148
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400149 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
150 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500151}
152
Kevin O'Connor65e63422008-07-19 14:12:32 -0400153// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500154static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400155puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500156{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500157 if (!MODESEGMENT && !s)
158 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500159 for (; *s; s++)
160 putc(action, *s);
161}
162
Kevin O'Connor65e63422008-07-19 14:12:32 -0400163// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500164static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400165puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500166{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400167 char *vs = (char*)s;
168 for (;; vs++) {
169 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500170 if (!c)
171 break;
172 putc(action, c);
173 }
174}
175
Kevin O'Connor65e63422008-07-19 14:12:32 -0400176// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500177static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400178putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500179{
180 char buf[12];
181 char *d = &buf[sizeof(buf) - 1];
182 *d-- = '\0';
183 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500184 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500185 val /= 10;
186 if (!val)
187 break;
188 d--;
189 }
190 puts(action, d);
191}
192
Kevin O'Connor65e63422008-07-19 14:12:32 -0400193// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500194static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400195putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500196{
197 if (val <= 9)
198 val = '0' + val;
199 else
200 val = 'a' + val - 10;
201 putc(action, val);
202}
203
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500204// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500205static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500206puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500207{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400208 switch (width) {
209 default: putsinglehex(action, (val >> 28) & 0xf);
210 case 7: putsinglehex(action, (val >> 24) & 0xf);
211 case 6: putsinglehex(action, (val >> 20) & 0xf);
212 case 5: putsinglehex(action, (val >> 16) & 0xf);
213 case 4: putsinglehex(action, (val >> 12) & 0xf);
214 case 3: putsinglehex(action, (val >> 8) & 0xf);
215 case 2: putsinglehex(action, (val >> 4) & 0xf);
216 case 1: putsinglehex(action, (val >> 0) & 0xf);
217 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500218}
219
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500220// Output an integer in hexadecimal with a minimum width.
221static void
222putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
223{
224 u32 tmp = val;
225 int count = 1;
226 while (tmp >>= 4)
227 count++;
228 width -= count;
229 while (width-- > 0)
230 putc(action, padchar);
231 puthex(action, val, count);
232}
233
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500234static inline int
235isdigit(u8 c)
236{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400237 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500238}
239
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400240static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400241bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500242{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500243 const char *s = fmt;
244 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500245 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500246 if (!c)
247 break;
248 if (c != '%') {
249 putc(action, c);
250 continue;
251 }
252 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400253 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500254 char padchar = ' ';
255 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500256 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500257 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500258 if (!isdigit(c))
259 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400260 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500261 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400262 else
263 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500264 n++;
265 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500266 if (c == 'l') {
267 // Ignore long format indicator
268 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500269 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500270 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500271 if (c == 'l') {
272 is64 = 1;
273 n++;
274 c = GET_GLOBAL(*(u8*)n);
275 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500276 s32 val;
277 const char *sarg;
278 switch (c) {
279 case '%':
280 putc(action, '%');
281 break;
282 case 'd':
283 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500284 if (is64)
285 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500286 if (val < 0) {
287 putc(action, '-');
288 val = -val;
289 }
290 putuint(action, val);
291 break;
292 case 'u':
293 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500294 if (is64)
295 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500296 putuint(action, val);
297 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400298 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500299 val = va_arg(args, s32);
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400300 putc(action, '0');
301 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500302 puthex(action, val, 8);
303 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500304 case 'x':
305 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500306 if (is64) {
307 u32 upper = va_arg(args, s32);
308 if (upper) {
309 putprettyhex(action, upper, field_width - 8, padchar);
310 puthex(action, val, 8);
311 break;
312 }
313 }
314 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500315 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500316 case 'c':
317 val = va_arg(args, int);
318 putc(action, val);
319 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400320 case '.':
321 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500322 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400323 break;
324 n++;
325 sarg = va_arg(args, const char *);
326 puts(action, sarg);
327 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500328 case 's':
329 sarg = va_arg(args, const char *);
330 puts_cs(action, sarg);
331 break;
332 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500333 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500334 n = s;
335 }
336 s = n;
337 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400338}
339
340void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500341panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400342{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400343 if (CONFIG_DEBUG_LEVEL) {
344 va_list args;
345 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400346 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400347 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400348 debug_serial_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400349 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400350
351 // XXX - use PANIC PORT.
352 irq_disable();
353 for (;;)
354 hlt();
355}
356
357void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400358__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400359{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500360 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400361 && *fmt != '\\' && *fmt != '/') {
362 struct thread_info *cur = getCurThread();
363 if (cur != &MainThread) {
364 // Show "thread id" for this debug message.
365 putc_debug(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500366 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400367 putc_debug(&debuginfo, '|');
368 putc_debug(&debuginfo, ' ');
369 }
370 }
371
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400372 va_list args;
373 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400374 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400375 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400376 debug_serial_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400377}
378
379void
380printf(const char *fmt, ...)
381{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500382 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400383 va_list args;
384 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400385 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500386 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400387 if (ScreenAndDebug)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400388 debug_serial_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500389}
390
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400391
392/****************************************************************
393 * snprintf
394 ****************************************************************/
395
396struct snprintfinfo {
397 struct putcinfo info;
398 char *str, *end;
399};
400
401static void
402putc_str(struct putcinfo *info, char c)
403{
404 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
405 if (sinfo->str >= sinfo->end)
406 return;
407 *sinfo->str = c;
408 sinfo->str++;
409}
410
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500411// Build a formatted string. Note, this function returns the actual
412// number of bytes used (not including null) even in the overflow
413// case.
414int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400415snprintf(char *str, size_t size, const char *fmt, ...)
416{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500417 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400418 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500419 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400420 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
421 va_list args;
422 va_start(args, fmt);
423 bvprintf(&sinfo.info, fmt, args);
424 va_end(args);
425 char *end = sinfo.str;
426 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500427 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400428 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500429 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400430}
431
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500432// Build a formatted string - malloc'ing the memory.
433char *
434znprintf(size_t size, const char *fmt, ...)
435{
436 ASSERT32FLAT();
437 if (!size)
438 return NULL;
439 char *str = malloc_tmp(size);
440 if (!str) {
441 warn_noalloc();
442 return NULL;
443 }
444 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
445 va_list args;
446 va_start(args, fmt);
447 bvprintf(&sinfo.info, fmt, args);
448 va_end(args);
449 char *end = sinfo.str;
450 if (end >= sinfo.end)
451 end = sinfo.end - 1;
452 *end = '\0';
453 return str;
454}
455
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400456
457/****************************************************************
458 * Misc helpers
459 ****************************************************************/
460
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500461void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400462hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500463{
464 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400465 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500466 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400467 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500468 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400469 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500470 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400471 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500472 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500473 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500474 count++;
475 len-=4;
476 d+=4;
477 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400478 putc(&debuginfo, '\n');
Kevin O'Connor3e832bb2009-05-15 22:22:12 -0400479 debug_serial_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500480}
481
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500482static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400483dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500484{
485 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400486 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500487 return;
488 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400489 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 -0400490 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400491 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400492 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
493 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400494 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500495}
496
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400497// Report entry to an Interrupt Service Routine (ISR).
498void
499__debug_isr(const char *fname)
500{
501 puts_cs(&debuginfo, fname);
502 putc(&debuginfo, '\n');
503 debug_serial_flush();
504}
505
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500506// Function called on handler startup.
507void
Kevin O'Connor05600342009-01-02 13:10:58 -0500508__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500509{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400510 dprintf(1, "enter %s:\n", fname);
511 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500512}
513
Kevin O'Connor05600342009-01-02 13:10:58 -0500514// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500515void
Kevin O'Connor05600342009-01-02 13:10:58 -0500516__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500517{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400518 dprintf(1, "stub %s:%d:\n", fname, lineno);
519 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500520}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500521
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500522// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500523void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500524__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500525{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500526 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
527 dprintf(1, "invalid %s:%d:\n", fname, lineno);
528 dump_regs(regs);
529 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400530}
531
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500532// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400533void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500534__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
535{
536 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
537 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
538 dump_regs(regs);
539 }
540}
541
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500542// Report a detected internal inconsistency.
543void
544__warn_internalerror(int lineno, const char *fname)
545{
546 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
547 , fname, lineno);
548}
549
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500550// Report on an allocation failure.
551void
552__warn_noalloc(int lineno, const char *fname)
553{
554 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
555 , fname, lineno);
556}
557
558// Report on a timeout exceeded.
559void
560__warn_timeout(int lineno, const char *fname)
561{
562 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
563}
564
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500565// Report a handler reporting an invalid parameter to the caller.
566void
567__set_invalid(struct bregs *regs, int lineno, const char *fname)
568{
569 __warn_invalid(regs, lineno, fname);
570 set_invalid_silent(regs);
571}
572
573// Report a call of an unimplemented function.
574void
575__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
576{
577 __warn_unimplemented(regs, lineno, fname);
578 set_invalid_silent(regs);
579}
580
581// Report a handler reporting an invalid parameter code to the
582// caller. Note, the lineno and return code are encoded in the same
583// parameter as gcc does a better job of scheduling function calls
584// when there are 3 or less parameters.
585void
586__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400587{
Kevin O'Connor05600342009-01-02 13:10:58 -0500588 u8 code = linecode;
589 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500590 __warn_invalid(regs, lineno, fname);
591 set_code_invalid_silent(regs, code);
592}
593
594// Report a call of an unimplemented function.
595void
596__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
597{
598 u8 code = linecode;
599 u32 lineno = linecode >> 8;
600 __warn_unimplemented(regs, lineno, fname);
601 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500602}