blob: 37c4942eddd482828694865d021ff61547359d3f [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'Connorf076a3e2008-02-25 22:25:15 -050014
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040015struct putcinfo {
16 void (*func)(struct putcinfo *info, char c);
17};
18
19
20/****************************************************************
21 * Debug output
22 ****************************************************************/
23
Kevin O'Connor5c732402008-06-07 10:43:07 -040024#define DEBUG_TIMEOUT 100000
25
Kevin O'Connor61d6b062008-06-21 12:15:10 -040026void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050027debug_serial_setup(void)
Kevin O'Connor61d6b062008-06-21 12:15:10 -040028{
29 if (!CONFIG_DEBUG_SERIAL)
30 return;
31 // setup for serial logging: 8N1
32 u8 oldparam, newparam = 0x03;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040033 oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
34 outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040035 // Disable irqs
36 u8 oldier, newier = 0;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040037 oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
38 outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040039
40 if (oldparam != newparam || oldier != newier)
41 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
42 , oldparam, oldier, newparam, newier);
43}
44
Kevin O'Connor65e63422008-07-19 14:12:32 -040045// Write a character to the serial port.
Kevin O'Connor5c732402008-06-07 10:43:07 -040046static void
47debug_serial(char c)
48{
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040049 if (!CONFIG_DEBUG_SERIAL)
50 return;
Kevin O'Connor5c732402008-06-07 10:43:07 -040051 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040052 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
Kevin O'Connor5c732402008-06-07 10:43:07 -040053 if (!timeout--)
54 // Ran out of time.
55 return;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040056 outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
Kevin O'Connor5c732402008-06-07 10:43:07 -040057}
58
Kevin O'Connorb9e62d22009-08-02 13:18:27 -040059// Make sure all serial port writes have been completely sent.
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040060static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050061debug_serial_flush(void)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040062{
63 if (!CONFIG_DEBUG_SERIAL)
64 return;
65 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040066 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040067 if (!timeout--)
68 // Ran out of time.
69 return;
70}
71
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040072// Write a character to debug port(s).
73static void
74putc_debug(struct putcinfo *action, char c)
75{
76 if (! CONFIG_DEBUG_LEVEL)
77 return;
Julian Pidancet7123d982012-02-01 16:03:24 +000078 if (CONFIG_DEBUG_IO)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040079 // Send character to debug port.
Julian Pidancet7123d982012-02-01 16:03:24 +000080 outb(c, CONFIG_DEBUG_IO_PORT);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040081 if (c == '\n')
82 debug_serial('\r');
83 debug_serial(c);
84}
85
Kevin O'Connor52a300f2009-12-26 23:32:57 -050086// In segmented mode just need a dummy variable (putc_debug is always
87// used anyway), and in 32bit flat mode need a pointer to the 32bit
88// instance of putc_debug().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050089#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040090static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050091#elif MODESEGMENT
92static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -040093#else
94static struct putcinfo debuginfo = { putc_debug };
95#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040096
97
98/****************************************************************
99 * Screen writing
100 ****************************************************************/
101
Kevin O'Connor65e63422008-07-19 14:12:32 -0400102// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500103static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400104screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500105{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500106 struct bregs br;
107 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -0400108 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500109 br.ah = 0x0e;
110 br.al = c;
111 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500112}
113
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400114// Handle a character from a printf request.
115static void
116putc_screen(struct putcinfo *action, char c)
117{
Kevin O'Connor422263d2011-07-05 20:56:07 -0400118 if (ScreenAndDebug)
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400119 putc_debug(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400120 if (c == '\n')
121 screenc('\r');
122 screenc(c);
123}
124
125static struct putcinfo screeninfo = { putc_screen };
126
127
128/****************************************************************
129 * Xprintf code
130 ****************************************************************/
131
Kevin O'Connor65e63422008-07-19 14:12:32 -0400132// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500133static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400134putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500135{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500136 if (MODESEGMENT) {
137 // Only debugging output supported in segmented mode.
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400138 putc_debug(action, c);
139 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400140 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400141
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400142 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
143 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500144}
145
Kevin O'Connor65e63422008-07-19 14:12:32 -0400146// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500147static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400148puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500149{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500150 if (!MODESEGMENT && !s)
151 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500152 for (; *s; s++)
153 putc(action, *s);
154}
155
Kevin O'Connor65e63422008-07-19 14:12:32 -0400156// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500157static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400158puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500159{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400160 char *vs = (char*)s;
161 for (;; vs++) {
162 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500163 if (!c)
164 break;
165 putc(action, c);
166 }
167}
168
Kevin O'Connor65e63422008-07-19 14:12:32 -0400169// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500170static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400171putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500172{
173 char buf[12];
174 char *d = &buf[sizeof(buf) - 1];
175 *d-- = '\0';
176 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500177 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500178 val /= 10;
179 if (!val)
180 break;
181 d--;
182 }
183 puts(action, d);
184}
185
Kevin O'Connor65e63422008-07-19 14:12:32 -0400186// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500187static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400188putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500189{
190 if (val <= 9)
191 val = '0' + val;
192 else
193 val = 'a' + val - 10;
194 putc(action, val);
195}
196
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500197// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500198static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500199puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500200{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400201 switch (width) {
202 default: putsinglehex(action, (val >> 28) & 0xf);
203 case 7: putsinglehex(action, (val >> 24) & 0xf);
204 case 6: putsinglehex(action, (val >> 20) & 0xf);
205 case 5: putsinglehex(action, (val >> 16) & 0xf);
206 case 4: putsinglehex(action, (val >> 12) & 0xf);
207 case 3: putsinglehex(action, (val >> 8) & 0xf);
208 case 2: putsinglehex(action, (val >> 4) & 0xf);
209 case 1: putsinglehex(action, (val >> 0) & 0xf);
210 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500211}
212
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500213// Output an integer in hexadecimal with a minimum width.
214static void
215putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
216{
217 u32 tmp = val;
218 int count = 1;
219 while (tmp >>= 4)
220 count++;
221 width -= count;
222 while (width-- > 0)
223 putc(action, padchar);
224 puthex(action, val, count);
225}
226
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500227static inline int
228isdigit(u8 c)
229{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400230 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500231}
232
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400233static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400234bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500235{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500236 const char *s = fmt;
237 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500238 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500239 if (!c)
240 break;
241 if (c != '%') {
242 putc(action, c);
243 continue;
244 }
245 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400246 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500247 char padchar = ' ';
248 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500249 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500250 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500251 if (!isdigit(c))
252 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400253 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500254 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400255 else
256 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500257 n++;
258 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500259 if (c == 'l') {
260 // Ignore long format indicator
261 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500262 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500263 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500264 if (c == 'l') {
265 is64 = 1;
266 n++;
267 c = GET_GLOBAL(*(u8*)n);
268 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500269 s32 val;
270 const char *sarg;
271 switch (c) {
272 case '%':
273 putc(action, '%');
274 break;
275 case 'd':
276 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500277 if (is64)
278 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500279 if (val < 0) {
280 putc(action, '-');
281 val = -val;
282 }
283 putuint(action, val);
284 break;
285 case 'u':
286 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500287 if (is64)
288 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500289 putuint(action, val);
290 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400291 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500292 val = va_arg(args, s32);
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400293 putc(action, '0');
294 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500295 puthex(action, val, 8);
296 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500297 case 'x':
298 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500299 if (is64) {
300 u32 upper = va_arg(args, s32);
301 if (upper) {
302 putprettyhex(action, upper, field_width - 8, padchar);
303 puthex(action, val, 8);
304 break;
305 }
306 }
307 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500308 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500309 case 'c':
310 val = va_arg(args, int);
311 putc(action, val);
312 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400313 case '.':
314 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500315 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400316 break;
317 n++;
318 sarg = va_arg(args, const char *);
319 puts(action, sarg);
320 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500321 case 's':
322 sarg = va_arg(args, const char *);
323 puts_cs(action, sarg);
324 break;
325 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500326 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500327 n = s;
328 }
329 s = n;
330 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400331}
332
333void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500334panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400335{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400336 if (CONFIG_DEBUG_LEVEL) {
337 va_list args;
338 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400339 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400340 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400341 debug_serial_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400342 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400343
344 // XXX - use PANIC PORT.
345 irq_disable();
346 for (;;)
347 hlt();
348}
349
350void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400351__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400352{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500353 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400354 && *fmt != '\\' && *fmt != '/') {
355 struct thread_info *cur = getCurThread();
356 if (cur != &MainThread) {
357 // Show "thread id" for this debug message.
358 putc_debug(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500359 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400360 putc_debug(&debuginfo, '|');
361 putc_debug(&debuginfo, ' ');
362 }
363 }
364
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(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400368 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400369 debug_serial_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400370}
371
372void
373printf(const char *fmt, ...)
374{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500375 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400376 va_list args;
377 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400378 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500379 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400380 if (ScreenAndDebug)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400381 debug_serial_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500382}
383
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400384
385/****************************************************************
386 * snprintf
387 ****************************************************************/
388
389struct snprintfinfo {
390 struct putcinfo info;
391 char *str, *end;
392};
393
394static void
395putc_str(struct putcinfo *info, char c)
396{
397 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
398 if (sinfo->str >= sinfo->end)
399 return;
400 *sinfo->str = c;
401 sinfo->str++;
402}
403
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500404// Build a formatted string. Note, this function returns the actual
405// number of bytes used (not including null) even in the overflow
406// case.
407int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400408snprintf(char *str, size_t size, const char *fmt, ...)
409{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500410 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400411 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500412 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400413 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
414 va_list args;
415 va_start(args, fmt);
416 bvprintf(&sinfo.info, fmt, args);
417 va_end(args);
418 char *end = sinfo.str;
419 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500420 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400421 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500422 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400423}
424
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500425// Build a formatted string - malloc'ing the memory.
426char *
427znprintf(size_t size, const char *fmt, ...)
428{
429 ASSERT32FLAT();
430 if (!size)
431 return NULL;
432 char *str = malloc_tmp(size);
433 if (!str) {
434 warn_noalloc();
435 return NULL;
436 }
437 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
438 va_list args;
439 va_start(args, fmt);
440 bvprintf(&sinfo.info, fmt, args);
441 va_end(args);
442 char *end = sinfo.str;
443 if (end >= sinfo.end)
444 end = sinfo.end - 1;
445 *end = '\0';
446 return str;
447}
448
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400449
450/****************************************************************
451 * Misc helpers
452 ****************************************************************/
453
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500454void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400455hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500456{
457 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400458 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500459 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400460 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500461 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400462 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500463 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400464 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500465 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500466 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500467 count++;
468 len-=4;
469 d+=4;
470 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400471 putc(&debuginfo, '\n');
Kevin O'Connor3e832bb2009-05-15 22:22:12 -0400472 debug_serial_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500473}
474
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500475static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400476dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500477{
478 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400479 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500480 return;
481 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400482 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 -0400483 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400484 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400485 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
486 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400487 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500488}
489
Kevin O'Connor05600342009-01-02 13:10:58 -0500490// Report entry to an Interrupt Service Routine (ISR).
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500491void
Kevin O'Connored128492008-03-11 11:14:59 -0400492__debug_isr(const char *fname)
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500493{
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400494 puts_cs(&debuginfo, fname);
495 putc(&debuginfo, '\n');
Kevin O'Connor3e832bb2009-05-15 22:22:12 -0400496 debug_serial_flush();
Kevin O'Connorc65a3802008-03-02 13:58:23 -0500497}
498
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500499// Function called on handler startup.
500void
Kevin O'Connor05600342009-01-02 13:10:58 -0500501__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500502{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400503 dprintf(1, "enter %s:\n", fname);
504 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500505}
506
Kevin O'Connor05600342009-01-02 13:10:58 -0500507// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500508void
Kevin O'Connor05600342009-01-02 13:10:58 -0500509__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500510{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400511 dprintf(1, "stub %s:%d:\n", fname, lineno);
512 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500513}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500514
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500515// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500516void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500517__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500518{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500519 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
520 dprintf(1, "invalid %s:%d:\n", fname, lineno);
521 dump_regs(regs);
522 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400523}
524
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500525// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400526void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500527__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
528{
529 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
530 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
531 dump_regs(regs);
532 }
533}
534
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500535// Report a detected internal inconsistency.
536void
537__warn_internalerror(int lineno, const char *fname)
538{
539 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
540 , fname, lineno);
541}
542
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500543// Report on an allocation failure.
544void
545__warn_noalloc(int lineno, const char *fname)
546{
547 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
548 , fname, lineno);
549}
550
551// Report on a timeout exceeded.
552void
553__warn_timeout(int lineno, const char *fname)
554{
555 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
556}
557
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500558// Report a handler reporting an invalid parameter to the caller.
559void
560__set_invalid(struct bregs *regs, int lineno, const char *fname)
561{
562 __warn_invalid(regs, lineno, fname);
563 set_invalid_silent(regs);
564}
565
566// Report a call of an unimplemented function.
567void
568__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
569{
570 __warn_unimplemented(regs, lineno, fname);
571 set_invalid_silent(regs);
572}
573
574// Report a handler reporting an invalid parameter code to the
575// caller. Note, the lineno and return code are encoded in the same
576// parameter as gcc does a better job of scheduling function calls
577// when there are 3 or less parameters.
578void
579__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400580{
Kevin O'Connor05600342009-01-02 13:10:58 -0500581 u8 code = linecode;
582 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500583 __warn_invalid(regs, lineno, fname);
584 set_code_invalid_silent(regs, code);
585}
586
587// Report a call of an unimplemented function.
588void
589__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
590{
591 u8 code = linecode;
592 u32 lineno = linecode >> 8;
593 __warn_unimplemented(regs, lineno, fname);
594 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500595}