blob: 79c3adac9e5187e10c5d7b5c34e3611475f850cc [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'Connor89a2f962013-02-18 23:36:03 -050026u16 DebugOutputPort VARFSEG = 0x402;
Ian Campbell54f3b252012-06-28 11:08:32 +010027
Kevin O'Connor61d6b062008-06-21 12:15:10 -040028void
Kevin O'Connord83c87b2013-01-21 01:14:12 -050029debug_serial_preinit(void)
Kevin O'Connor61d6b062008-06-21 12:15:10 -040030{
31 if (!CONFIG_DEBUG_SERIAL)
32 return;
33 // setup for serial logging: 8N1
34 u8 oldparam, newparam = 0x03;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040035 oldparam = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
36 outb(newparam, CONFIG_DEBUG_SERIAL_PORT+SEROFF_LCR);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040037 // Disable irqs
38 u8 oldier, newier = 0;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040039 oldier = inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
40 outb(newier, CONFIG_DEBUG_SERIAL_PORT+SEROFF_IER);
Kevin O'Connor61d6b062008-06-21 12:15:10 -040041
42 if (oldparam != newparam || oldier != newier)
43 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
44 , oldparam, oldier, newparam, newier);
45}
46
Kevin O'Connor65e63422008-07-19 14:12:32 -040047// Write a character to the serial port.
Kevin O'Connor5c732402008-06-07 10:43:07 -040048static void
49debug_serial(char c)
50{
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040051 if (!CONFIG_DEBUG_SERIAL)
52 return;
Kevin O'Connor5c732402008-06-07 10:43:07 -040053 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040054 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x20) != 0x20)
Kevin O'Connor5c732402008-06-07 10:43:07 -040055 if (!timeout--)
56 // Ran out of time.
57 return;
Kevin O'Connord12e8a22011-05-10 23:36:11 -040058 outb(c, CONFIG_DEBUG_SERIAL_PORT+SEROFF_DATA);
Kevin O'Connor5c732402008-06-07 10:43:07 -040059}
60
Kevin O'Connorb9e62d22009-08-02 13:18:27 -040061// Make sure all serial port writes have been completely sent.
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040062static void
Kevin O'Connor1ca05b02010-01-03 17:43:37 -050063debug_serial_flush(void)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040064{
65 if (!CONFIG_DEBUG_SERIAL)
66 return;
67 int timeout = DEBUG_TIMEOUT;
Kevin O'Connor50440532011-07-09 18:42:34 -040068 while ((inb(CONFIG_DEBUG_SERIAL_PORT+SEROFF_LSR) & 0x60) != 0x60)
Kevin O'Connor3e832bb2009-05-15 22:22:12 -040069 if (!timeout--)
70 // Ran out of time.
71 return;
72}
73
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040074// Write a character to debug port(s).
75static void
76putc_debug(struct putcinfo *action, char c)
77{
78 if (! CONFIG_DEBUG_LEVEL)
79 return;
Julian Pidancet7123d982012-02-01 16:03:24 +000080 if (CONFIG_DEBUG_IO)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040081 // Send character to debug port.
Ian Campbell54f3b252012-06-28 11:08:32 +010082 outb(c, GET_GLOBAL(DebugOutputPort));
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040083 if (c == '\n')
84 debug_serial('\r');
85 debug_serial(c);
86}
87
Kevin O'Connor52a300f2009-12-26 23:32:57 -050088// In segmented mode just need a dummy variable (putc_debug is always
89// used anyway), and in 32bit flat mode need a pointer to the 32bit
90// instance of putc_debug().
Kevin O'Connor871e0a02009-12-30 12:14:53 -050091#if MODE16
Kevin O'Connor43562762009-10-12 09:48:12 -040092static struct putcinfo debuginfo VAR16;
Kevin O'Connor871e0a02009-12-30 12:14:53 -050093#elif MODESEGMENT
94static struct putcinfo debuginfo VAR32SEG;
Kevin O'Connorebd426b2009-10-08 08:51:24 -040095#else
96static struct putcinfo debuginfo = { putc_debug };
97#endif
Kevin O'Connor9ed6b622009-10-07 21:41:08 -040098
99
100/****************************************************************
101 * Screen writing
102 ****************************************************************/
103
Kevin O'Connor65e63422008-07-19 14:12:32 -0400104// Show a character on the screen.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500105static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400106screenc(char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500107{
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500108 struct bregs br;
109 memset(&br, 0, sizeof(br));
Kevin O'Connorf8e800d2009-09-24 21:01:16 -0400110 br.flags = F_IF;
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500111 br.ah = 0x0e;
112 br.al = c;
113 call16_int(0x10, &br);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500114}
115
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400116// Handle a character from a printf request.
117static void
118putc_screen(struct putcinfo *action, char c)
119{
Kevin O'Connor422263d2011-07-05 20:56:07 -0400120 if (ScreenAndDebug)
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400121 putc_debug(&debuginfo, c);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400122 if (c == '\n')
123 screenc('\r');
124 screenc(c);
125}
126
127static struct putcinfo screeninfo = { putc_screen };
128
129
130/****************************************************************
131 * Xprintf code
132 ****************************************************************/
133
Kevin O'Connor65e63422008-07-19 14:12:32 -0400134// Output a character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500135static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400136putc(struct putcinfo *action, char c)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500137{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500138 if (MODESEGMENT) {
139 // Only debugging output supported in segmented mode.
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400140 putc_debug(action, c);
141 return;
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400142 }
Kevin O'Connor1812e202008-05-07 21:29:50 -0400143
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400144 void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
145 func(action, c);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500146}
147
Kevin O'Connor65e63422008-07-19 14:12:32 -0400148// Ouptut a string.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500149static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400150puts(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500151{
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500152 if (!MODESEGMENT && !s)
153 s = "(NULL)";
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500154 for (; *s; s++)
155 putc(action, *s);
156}
157
Kevin O'Connor65e63422008-07-19 14:12:32 -0400158// Output a string that is in the CS segment.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500159static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400160puts_cs(struct putcinfo *action, const char *s)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500161{
Kevin O'Connor462cb502009-10-07 20:59:45 -0400162 char *vs = (char*)s;
163 for (;; vs++) {
164 char c = GET_GLOBAL(*vs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500165 if (!c)
166 break;
167 putc(action, c);
168 }
169}
170
Kevin O'Connor65e63422008-07-19 14:12:32 -0400171// Output an unsigned integer.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500172static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400173putuint(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500174{
175 char buf[12];
176 char *d = &buf[sizeof(buf) - 1];
177 *d-- = '\0';
178 for (;;) {
Kevin O'Connor4b60c002008-02-25 22:29:55 -0500179 *d = (val % 10) + '0';
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500180 val /= 10;
181 if (!val)
182 break;
183 d--;
184 }
185 puts(action, d);
186}
187
Kevin O'Connor65e63422008-07-19 14:12:32 -0400188// Output a single digit hex character.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500189static inline void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400190putsinglehex(struct putcinfo *action, u32 val)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500191{
192 if (val <= 9)
193 val = '0' + val;
194 else
195 val = 'a' + val - 10;
196 putc(action, val);
197}
198
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500199// Output an integer in hexadecimal with a specified width.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500200static void
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500201puthex(struct putcinfo *action, u32 val, int width)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500202{
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400203 switch (width) {
204 default: putsinglehex(action, (val >> 28) & 0xf);
205 case 7: putsinglehex(action, (val >> 24) & 0xf);
206 case 6: putsinglehex(action, (val >> 20) & 0xf);
207 case 5: putsinglehex(action, (val >> 16) & 0xf);
208 case 4: putsinglehex(action, (val >> 12) & 0xf);
209 case 3: putsinglehex(action, (val >> 8) & 0xf);
210 case 2: putsinglehex(action, (val >> 4) & 0xf);
211 case 1: putsinglehex(action, (val >> 0) & 0xf);
212 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500213}
214
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500215// Output an integer in hexadecimal with a minimum width.
216static void
217putprettyhex(struct putcinfo *action, u32 val, int width, char padchar)
218{
219 u32 tmp = val;
220 int count = 1;
221 while (tmp >>= 4)
222 count++;
223 width -= count;
224 while (width-- > 0)
225 putc(action, padchar);
226 puthex(action, val, count);
227}
228
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500229static inline int
230isdigit(u8 c)
231{
Kevin O'Connord6e4b4c2008-08-29 21:20:32 -0400232 return ((u8)(c - '0')) < 10;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500233}
234
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400235static void
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400236bvprintf(struct putcinfo *action, const char *fmt, va_list args)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500237{
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500238 const char *s = fmt;
239 for (;; s++) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500240 char c = GET_GLOBAL(*(u8*)s);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500241 if (!c)
242 break;
243 if (c != '%') {
244 putc(action, c);
245 continue;
246 }
247 const char *n = s+1;
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400248 int field_width = 0;
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500249 char padchar = ' ';
250 u8 is64 = 0;
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500251 for (;;) {
Kevin O'Connor15157a32008-12-13 11:10:37 -0500252 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500253 if (!isdigit(c))
254 break;
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400255 if (!field_width && (c == '0'))
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500256 padchar = '0';
Kevin O'Connor1d7d8932010-06-19 12:05:57 -0400257 else
258 field_width = field_width * 10 + c - '0';
Kevin O'Connor7d0f08a2008-03-04 22:27:55 -0500259 n++;
260 }
Kevin O'Connora9096f42008-03-08 15:40:43 -0500261 if (c == 'l') {
262 // Ignore long format indicator
263 n++;
Kevin O'Connor15157a32008-12-13 11:10:37 -0500264 c = GET_GLOBAL(*(u8*)n);
Kevin O'Connora9096f42008-03-08 15:40:43 -0500265 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500266 if (c == 'l') {
267 is64 = 1;
268 n++;
269 c = GET_GLOBAL(*(u8*)n);
270 }
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500271 s32 val;
272 const char *sarg;
273 switch (c) {
274 case '%':
275 putc(action, '%');
276 break;
277 case 'd':
278 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500279 if (is64)
280 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500281 if (val < 0) {
282 putc(action, '-');
283 val = -val;
284 }
285 putuint(action, val);
286 break;
287 case 'u':
288 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500289 if (is64)
290 va_arg(args, s32);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500291 putuint(action, val);
292 break;
Kevin O'Connorf06f03a2008-03-29 12:44:32 -0400293 case 'p':
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500294 val = va_arg(args, s32);
Kevin O'Connor91b53a72009-05-05 22:52:09 -0400295 putc(action, '0');
296 putc(action, 'x');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500297 puthex(action, val, 8);
298 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500299 case 'x':
300 val = va_arg(args, s32);
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500301 if (is64) {
302 u32 upper = va_arg(args, s32);
303 if (upper) {
304 putprettyhex(action, upper, field_width - 8, padchar);
305 puthex(action, val, 8);
306 break;
307 }
308 }
309 putprettyhex(action, val, field_width, padchar);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500310 break;
Kevin O'Connor12dade52008-03-01 13:35:17 -0500311 case 'c':
312 val = va_arg(args, int);
313 putc(action, val);
314 break;
Kevin O'Connore0113c92008-04-05 15:51:12 -0400315 case '.':
316 // Hack to support "%.s" - meaning string on stack.
Kevin O'Connor15157a32008-12-13 11:10:37 -0500317 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
Kevin O'Connore0113c92008-04-05 15:51:12 -0400318 break;
319 n++;
320 sarg = va_arg(args, const char *);
321 puts(action, sarg);
322 break;
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500323 case 's':
324 sarg = va_arg(args, const char *);
325 puts_cs(action, sarg);
326 break;
327 default:
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500328 putc(action, '%');
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500329 n = s;
330 }
331 s = n;
332 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400333}
334
335void
Kevin O'Connore07e18e2009-02-08 17:07:29 -0500336panic(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400337{
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400338 if (CONFIG_DEBUG_LEVEL) {
339 va_list args;
340 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400341 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400342 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400343 debug_serial_flush();
Kevin O'Connor79cb1192008-07-21 23:29:33 -0400344 }
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400345
346 // XXX - use PANIC PORT.
347 irq_disable();
348 for (;;)
349 hlt();
350}
351
352void
Kevin O'Connorac8df8c2008-05-24 23:46:33 -0400353__dprintf(const char *fmt, ...)
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400354{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500355 if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400356 && *fmt != '\\' && *fmt != '/') {
357 struct thread_info *cur = getCurThread();
358 if (cur != &MainThread) {
359 // Show "thread id" for this debug message.
360 putc_debug(&debuginfo, '|');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500361 puthex(&debuginfo, (u32)cur, 8);
Kevin O'Connorc604f2f2009-10-24 19:56:11 -0400362 putc_debug(&debuginfo, '|');
363 putc_debug(&debuginfo, ' ');
364 }
365 }
366
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400367 va_list args;
368 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400369 bvprintf(&debuginfo, fmt, args);
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400370 va_end(args);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400371 debug_serial_flush();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400372}
373
374void
375printf(const char *fmt, ...)
376{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500377 ASSERT32FLAT();
Kevin O'Connor567e4e32008-04-05 11:37:51 -0400378 va_list args;
379 va_start(args, fmt);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400380 bvprintf(&screeninfo, fmt, args);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500381 va_end(args);
Kevin O'Connor422263d2011-07-05 20:56:07 -0400382 if (ScreenAndDebug)
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400383 debug_serial_flush();
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500384}
385
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400386
387/****************************************************************
388 * snprintf
389 ****************************************************************/
390
391struct snprintfinfo {
392 struct putcinfo info;
393 char *str, *end;
394};
395
396static void
397putc_str(struct putcinfo *info, char c)
398{
399 struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
400 if (sinfo->str >= sinfo->end)
401 return;
402 *sinfo->str = c;
403 sinfo->str++;
404}
405
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500406// Build a formatted string. Note, this function returns the actual
407// number of bytes used (not including null) even in the overflow
408// case.
409int
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400410snprintf(char *str, size_t size, const char *fmt, ...)
411{
Kevin O'Connor52a300f2009-12-26 23:32:57 -0500412 ASSERT32FLAT();
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400413 if (!size)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500414 return 0;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400415 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
416 va_list args;
417 va_start(args, fmt);
418 bvprintf(&sinfo.info, fmt, args);
419 va_end(args);
420 char *end = sinfo.str;
421 if (end >= sinfo.end)
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500422 end = sinfo.end - 1;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400423 *end = '\0';
Kevin O'Connor2be312c2009-11-24 09:37:53 -0500424 return end - str;
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400425}
426
Kevin O'Connorca2bc1c2010-12-29 21:41:19 -0500427// Build a formatted string - malloc'ing the memory.
428char *
429znprintf(size_t size, const char *fmt, ...)
430{
431 ASSERT32FLAT();
432 if (!size)
433 return NULL;
434 char *str = malloc_tmp(size);
435 if (!str) {
436 warn_noalloc();
437 return NULL;
438 }
439 struct snprintfinfo sinfo = { { putc_str }, str, str + size };
440 va_list args;
441 va_start(args, fmt);
442 bvprintf(&sinfo.info, fmt, args);
443 va_end(args);
444 char *end = sinfo.str;
445 if (end >= sinfo.end)
446 end = sinfo.end - 1;
447 *end = '\0';
448 return str;
449}
450
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400451
452/****************************************************************
453 * Misc helpers
454 ****************************************************************/
455
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500456void
Kevin O'Connor114592f2009-09-28 21:32:08 -0400457hexdump(const void *d, int len)
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500458{
459 int count=0;
Kevin O'Connor114592f2009-09-28 21:32:08 -0400460 while (len > 0) {
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500461 if (count % 8 == 0) {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400462 putc(&debuginfo, '\n');
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500463 puthex(&debuginfo, count*4, 8);
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400464 putc(&debuginfo, ':');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500465 } else {
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400466 putc(&debuginfo, ' ');
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500467 }
Kevin O'Connorc04090d2012-03-05 10:14:07 -0500468 puthex(&debuginfo, *(u32*)d, 8);
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500469 count++;
470 len-=4;
471 d+=4;
472 }
Kevin O'Connor9ed6b622009-10-07 21:41:08 -0400473 putc(&debuginfo, '\n');
Kevin O'Connor3e832bb2009-05-15 22:22:12 -0400474 debug_serial_flush();
Kevin O'Connor1eba4292009-02-17 23:14:25 -0500475}
476
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500477static void
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400478dump_regs(struct bregs *regs)
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500479{
480 if (!regs) {
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400481 dprintf(1, " NULL\n");
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500482 return;
483 }
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400484 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 -0400485 , regs->eax, regs->ebx, regs->ecx, regs->edx
Kevin O'Connor7da210c2009-05-16 23:57:08 -0400486 , regs->ds, regs->es, GET_SEG(SS));
Kevin O'Connorf513c912009-05-27 22:27:10 -0400487 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
488 , regs->esi, regs->edi, regs->ebp, (u32)&regs[1]
Kevin O'Connor9f985422009-09-09 11:34:39 -0400489 , regs->code.seg, regs->code.offset, regs->flags);
Kevin O'Connor38fcbfe2008-02-25 22:30:47 -0500490}
491
Kevin O'Connor1297e5d2012-06-02 20:30:58 -0400492// Report entry to an Interrupt Service Routine (ISR).
493void
494__debug_isr(const char *fname)
495{
496 puts_cs(&debuginfo, fname);
497 putc(&debuginfo, '\n');
498 debug_serial_flush();
499}
500
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500501// Function called on handler startup.
502void
Kevin O'Connor05600342009-01-02 13:10:58 -0500503__debug_enter(struct bregs *regs, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500504{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400505 dprintf(1, "enter %s:\n", fname);
506 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500507}
508
Kevin O'Connor05600342009-01-02 13:10:58 -0500509// Send debugging output info.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500510void
Kevin O'Connor05600342009-01-02 13:10:58 -0500511__debug_stub(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500512{
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400513 dprintf(1, "stub %s:%d:\n", fname, lineno);
514 dump_regs(regs);
Kevin O'Connorf076a3e2008-02-25 22:25:15 -0500515}
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500516
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500517// Report on an invalid parameter.
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500518void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500519__warn_invalid(struct bregs *regs, int lineno, const char *fname)
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500520{
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500521 if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
522 dprintf(1, "invalid %s:%d:\n", fname, lineno);
523 dump_regs(regs);
524 }
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400525}
526
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500527// Report on an unimplemented feature.
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400528void
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500529__warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
530{
531 if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
532 dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
533 dump_regs(regs);
534 }
535}
536
Kevin O'Connor7fb8ba82010-02-26 08:45:00 -0500537// Report a detected internal inconsistency.
538void
539__warn_internalerror(int lineno, const char *fname)
540{
541 dprintf(1, "WARNING - internal error detected at %s:%d!\n"
542 , fname, lineno);
543}
544
Kevin O'Connorcfdc13f2010-02-14 13:07:54 -0500545// Report on an allocation failure.
546void
547__warn_noalloc(int lineno, const char *fname)
548{
549 dprintf(1, "WARNING - Unable to allocate resource at %s:%d!\n"
550 , fname, lineno);
551}
552
553// Report on a timeout exceeded.
554void
555__warn_timeout(int lineno, const char *fname)
556{
557 dprintf(1, "WARNING - Timeout at %s:%d!\n", fname, lineno);
558}
559
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500560// Report a handler reporting an invalid parameter to the caller.
561void
562__set_invalid(struct bregs *regs, int lineno, const char *fname)
563{
564 __warn_invalid(regs, lineno, fname);
565 set_invalid_silent(regs);
566}
567
568// Report a call of an unimplemented function.
569void
570__set_unimplemented(struct bregs *regs, int lineno, const char *fname)
571{
572 __warn_unimplemented(regs, lineno, fname);
573 set_invalid_silent(regs);
574}
575
576// Report a handler reporting an invalid parameter code to the
577// caller. Note, the lineno and return code are encoded in the same
578// parameter as gcc does a better job of scheduling function calls
579// when there are 3 or less parameters.
580void
581__set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
Kevin O'Connora68aeaf2008-07-07 21:37:10 -0400582{
Kevin O'Connor05600342009-01-02 13:10:58 -0500583 u8 code = linecode;
584 u32 lineno = linecode >> 8;
Kevin O'Connordfefeb52009-12-13 13:04:17 -0500585 __warn_invalid(regs, lineno, fname);
586 set_code_invalid_silent(regs, code);
587}
588
589// Report a call of an unimplemented function.
590void
591__set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
592{
593 u8 code = linecode;
594 u32 lineno = linecode >> 8;
595 __warn_unimplemented(regs, lineno, fname);
596 set_code_invalid_silent(regs, code);
Kevin O'Connor4ce6a492008-02-29 00:21:27 -0500597}