|
|
1.1 root 1: // Raw screen writing and debug output code.
2: //
3: // Copyright (C) 2008,2009 Kevin O'Connor <[email protected]>
4: //
5: // This file may be distributed under the terms of the GNU LGPLv3 license.
6:
7: #include <stdarg.h> // va_list
8:
9: #include "farptr.h" // GET_VAR
10: #include "util.h" // printf
11: #include "bregs.h" // struct bregs
12: #include "config.h" // CONFIG_*
13: #include "biosvar.h" // GET_GLOBAL
14:
15: struct putcinfo {
16: void (*func)(struct putcinfo *info, char c);
17: };
18:
19:
20: /****************************************************************
21: * Debug output
22: ****************************************************************/
23:
24: #define DEBUG_PORT PORT_SERIAL1
25: #define DEBUG_TIMEOUT 100000
26:
27: void
1.1.1.2 ! root 28: debug_serial_setup(void)
1.1 root 29: {
30: if (!CONFIG_DEBUG_SERIAL)
31: return;
32: // setup for serial logging: 8N1
33: u8 oldparam, newparam = 0x03;
34: oldparam = inb(DEBUG_PORT+SEROFF_LCR);
35: outb(newparam, DEBUG_PORT+SEROFF_LCR);
36: // Disable irqs
37: u8 oldier, newier = 0;
38: oldier = inb(DEBUG_PORT+SEROFF_IER);
39: outb(newier, DEBUG_PORT+SEROFF_IER);
40:
41: if (oldparam != newparam || oldier != newier)
42: dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
43: , oldparam, oldier, newparam, newier);
44: }
45:
46: // Write a character to the serial port.
47: static void
48: debug_serial(char c)
49: {
50: if (!CONFIG_DEBUG_SERIAL)
51: return;
52: int timeout = DEBUG_TIMEOUT;
53: while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x60) != 0x60)
54: if (!timeout--)
55: // Ran out of time.
56: return;
57: outb(c, DEBUG_PORT+SEROFF_DATA);
58: }
59:
60: // Make sure all serial port writes have been completely sent.
61: static void
1.1.1.2 ! root 62: debug_serial_flush(void)
1.1 root 63: {
64: if (!CONFIG_DEBUG_SERIAL)
65: return;
66: int timeout = DEBUG_TIMEOUT;
67: while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x40) != 0x40)
68: if (!timeout--)
69: // Ran out of time.
70: return;
71: }
72:
73: // Write a character to debug port(s).
74: static void
75: putc_debug(struct putcinfo *action, char c)
76: {
77: if (! CONFIG_DEBUG_LEVEL)
78: return;
79: if (! CONFIG_COREBOOT)
80: // Send character to debug port.
81: outb(c, PORT_BIOS_DEBUG);
82: if (c == '\n')
83: debug_serial('\r');
84: debug_serial(c);
85: }
86:
1.1.1.2 ! root 87: // In segmented mode just need a dummy variable (putc_debug is always
! 88: // used anyway), and in 32bit flat mode need a pointer to the 32bit
! 89: // instance of putc_debug().
1.1 root 90: #if MODE16
91: static struct putcinfo debuginfo VAR16;
1.1.1.2 ! root 92: #elif MODESEGMENT
! 93: static struct putcinfo debuginfo VAR32SEG;
1.1 root 94: #else
95: static struct putcinfo debuginfo = { putc_debug };
96: #endif
97:
98:
99: /****************************************************************
100: * Screen writing
101: ****************************************************************/
102:
103: // Show a character on the screen.
104: static void
105: screenc(char c)
106: {
107: struct bregs br;
108: memset(&br, 0, sizeof(br));
109: br.flags = F_IF;
110: br.ah = 0x0e;
111: br.al = c;
112: call16_int(0x10, &br);
113: }
114:
115: // Handle a character from a printf request.
116: static void
117: putc_screen(struct putcinfo *action, char c)
118: {
119: if (CONFIG_SCREEN_AND_DEBUG)
120: putc_debug(&debuginfo, c);
121: if (c == '\n')
122: screenc('\r');
123: screenc(c);
124: }
125:
126: static struct putcinfo screeninfo = { putc_screen };
127:
128:
129: /****************************************************************
130: * Xprintf code
131: ****************************************************************/
132:
133: // Output a character.
134: static void
135: putc(struct putcinfo *action, char c)
136: {
1.1.1.2 ! root 137: if (MODESEGMENT) {
! 138: // Only debugging output supported in segmented mode.
1.1 root 139: putc_debug(action, c);
140: return;
141: }
142:
143: void (*func)(struct putcinfo *info, char c) = GET_GLOBAL(action->func);
144: func(action, c);
145: }
146:
147: // Ouptut a string.
148: static void
149: puts(struct putcinfo *action, const char *s)
150: {
151: for (; *s; s++)
152: putc(action, *s);
153: }
154:
155: // Output a string that is in the CS segment.
156: static void
157: puts_cs(struct putcinfo *action, const char *s)
158: {
159: char *vs = (char*)s;
160: for (;; vs++) {
161: char c = GET_GLOBAL(*vs);
162: if (!c)
163: break;
164: putc(action, c);
165: }
166: }
167:
168: // Output an unsigned integer.
169: static void
170: putuint(struct putcinfo *action, u32 val)
171: {
172: char buf[12];
173: char *d = &buf[sizeof(buf) - 1];
174: *d-- = '\0';
175: for (;;) {
176: *d = (val % 10) + '0';
177: val /= 10;
178: if (!val)
179: break;
180: d--;
181: }
182: puts(action, d);
183: }
184:
185: // Output a single digit hex character.
186: static inline void
187: putsinglehex(struct putcinfo *action, u32 val)
188: {
189: if (val <= 9)
190: val = '0' + val;
191: else
192: val = 'a' + val - 10;
193: putc(action, val);
194: }
195:
196: // Output an integer in hexadecimal.
197: static void
198: puthex(struct putcinfo *action, u32 val, int width)
199: {
200: if (!width) {
201: u32 tmp = val;
202: width = 1;
203: if (tmp > 0xffff) {
204: width += 4;
205: tmp >>= 16;
206: }
207: if (tmp > 0xff) {
208: width += 2;
209: tmp >>= 8;
210: }
211: if (tmp > 0xf)
212: width += 1;
213: }
214:
215: switch (width) {
216: default: putsinglehex(action, (val >> 28) & 0xf);
217: case 7: putsinglehex(action, (val >> 24) & 0xf);
218: case 6: putsinglehex(action, (val >> 20) & 0xf);
219: case 5: putsinglehex(action, (val >> 16) & 0xf);
220: case 4: putsinglehex(action, (val >> 12) & 0xf);
221: case 3: putsinglehex(action, (val >> 8) & 0xf);
222: case 2: putsinglehex(action, (val >> 4) & 0xf);
223: case 1: putsinglehex(action, (val >> 0) & 0xf);
224: }
225: }
226:
227: static inline int
228: isdigit(u8 c)
229: {
230: return ((u8)(c - '0')) < 10;
231: }
232:
233: static void
234: bvprintf(struct putcinfo *action, const char *fmt, va_list args)
235: {
236: const char *s = fmt;
237: for (;; s++) {
238: char c = GET_GLOBAL(*(u8*)s);
239: if (!c)
240: break;
241: if (c != '%') {
242: putc(action, c);
243: continue;
244: }
245: const char *n = s+1;
246: int field_width = 0;
247: for (;;) {
248: c = GET_GLOBAL(*(u8*)n);
249: if (!isdigit(c))
250: break;
251: field_width = field_width * 10 + c - '0';
252: n++;
253: }
254: if (c == 'l') {
255: // Ignore long format indicator
256: n++;
257: c = GET_GLOBAL(*(u8*)n);
258: }
259: s32 val;
260: const char *sarg;
261: switch (c) {
262: case '%':
263: putc(action, '%');
264: break;
265: case 'd':
266: val = va_arg(args, s32);
267: if (val < 0) {
268: putc(action, '-');
269: val = -val;
270: }
271: putuint(action, val);
272: break;
273: case 'u':
274: val = va_arg(args, s32);
275: putuint(action, val);
276: break;
277: case 'p':
278: /* %p always has 0x prepended */
279: putc(action, '0');
280: putc(action, 'x');
281: field_width = 8;
282: case 'x':
283: val = va_arg(args, s32);
284: puthex(action, val, field_width);
285: break;
286: case 'c':
287: val = va_arg(args, int);
288: putc(action, val);
289: break;
290: case '.':
291: // Hack to support "%.s" - meaning string on stack.
292: if (GET_GLOBAL(*(u8*)(n+1)) != 's')
293: break;
294: n++;
295: sarg = va_arg(args, const char *);
296: puts(action, sarg);
297: break;
298: case 's':
299: sarg = va_arg(args, const char *);
300: puts_cs(action, sarg);
301: break;
302: default:
303: putc(action, '%');
304: n = s;
305: }
306: s = n;
307: }
308: }
309:
310: void
311: panic(const char *fmt, ...)
312: {
313: if (CONFIG_DEBUG_LEVEL) {
314: va_list args;
315: va_start(args, fmt);
316: bvprintf(&debuginfo, fmt, args);
317: va_end(args);
318: debug_serial_flush();
319: }
320:
321: // XXX - use PANIC PORT.
322: irq_disable();
323: for (;;)
324: hlt();
325: }
326:
327: void
328: __dprintf(const char *fmt, ...)
329: {
1.1.1.2 ! root 330: if (!MODESEGMENT && CONFIG_THREADS && CONFIG_DEBUG_LEVEL >= DEBUG_thread
1.1 root 331: && *fmt != '\\' && *fmt != '/') {
332: struct thread_info *cur = getCurThread();
333: if (cur != &MainThread) {
334: // Show "thread id" for this debug message.
335: putc_debug(&debuginfo, '|');
336: puthex(&debuginfo, (u32)cur, 8);
337: putc_debug(&debuginfo, '|');
338: putc_debug(&debuginfo, ' ');
339: }
340: }
341:
342: va_list args;
343: va_start(args, fmt);
344: bvprintf(&debuginfo, fmt, args);
345: va_end(args);
346: debug_serial_flush();
347: }
348:
349: void
350: printf(const char *fmt, ...)
351: {
1.1.1.2 ! root 352: ASSERT32FLAT();
1.1 root 353: va_list args;
354: va_start(args, fmt);
355: bvprintf(&screeninfo, fmt, args);
356: va_end(args);
357: if (CONFIG_SCREEN_AND_DEBUG)
358: debug_serial_flush();
359: }
360:
361:
362: /****************************************************************
363: * snprintf
364: ****************************************************************/
365:
366: struct snprintfinfo {
367: struct putcinfo info;
368: char *str, *end;
369: };
370:
371: static void
372: putc_str(struct putcinfo *info, char c)
373: {
374: struct snprintfinfo *sinfo = container_of(info, struct snprintfinfo, info);
375: if (sinfo->str >= sinfo->end)
376: return;
377: *sinfo->str = c;
378: sinfo->str++;
379: }
380:
381: // Build a formatted string. Note, this function returns the actual
382: // number of bytes used (not including null) even in the overflow
383: // case.
384: int
385: snprintf(char *str, size_t size, const char *fmt, ...)
386: {
1.1.1.2 ! root 387: ASSERT32FLAT();
1.1 root 388: if (!size)
389: return 0;
390: struct snprintfinfo sinfo = { { putc_str }, str, str + size };
391: va_list args;
392: va_start(args, fmt);
393: bvprintf(&sinfo.info, fmt, args);
394: va_end(args);
395: char *end = sinfo.str;
396: if (end >= sinfo.end)
397: end = sinfo.end - 1;
398: *end = '\0';
399: return end - str;
400: }
401:
402:
403: /****************************************************************
404: * Misc helpers
405: ****************************************************************/
406:
407: void
408: hexdump(const void *d, int len)
409: {
410: int count=0;
411: while (len > 0) {
412: if (count % 8 == 0) {
413: putc(&debuginfo, '\n');
414: puthex(&debuginfo, count*4, 8);
415: putc(&debuginfo, ':');
416: } else {
417: putc(&debuginfo, ' ');
418: }
419: puthex(&debuginfo, *(u32*)d, 8);
420: count++;
421: len-=4;
422: d+=4;
423: }
424: putc(&debuginfo, '\n');
425: debug_serial_flush();
426: }
427:
428: static void
429: dump_regs(struct bregs *regs)
430: {
431: if (!regs) {
432: dprintf(1, " NULL\n");
433: return;
434: }
435: dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n"
436: , regs->eax, regs->ebx, regs->ecx, regs->edx
437: , regs->ds, regs->es, GET_SEG(SS));
438: dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
439: , regs->esi, regs->edi, regs->ebp, (u32)®s[1]
440: , regs->code.seg, regs->code.offset, regs->flags);
441: }
442:
443: // Report entry to an Interrupt Service Routine (ISR).
444: void
445: __debug_isr(const char *fname)
446: {
447: puts_cs(&debuginfo, fname);
448: putc(&debuginfo, '\n');
449: debug_serial_flush();
450: }
451:
452: // Function called on handler startup.
453: void
454: __debug_enter(struct bregs *regs, const char *fname)
455: {
456: dprintf(1, "enter %s:\n", fname);
457: dump_regs(regs);
458: }
459:
460: // Send debugging output info.
461: void
462: __debug_stub(struct bregs *regs, int lineno, const char *fname)
463: {
464: dprintf(1, "stub %s:%d:\n", fname, lineno);
465: dump_regs(regs);
466: }
467:
468: // Report on an invalid parameter.
469: void
470: __warn_invalid(struct bregs *regs, int lineno, const char *fname)
471: {
472: if (CONFIG_DEBUG_LEVEL >= DEBUG_invalid) {
473: dprintf(1, "invalid %s:%d:\n", fname, lineno);
474: dump_regs(regs);
475: }
476: }
477:
478: // Report on an unimplemented feature.
479: void
480: __warn_unimplemented(struct bregs *regs, int lineno, const char *fname)
481: {
482: if (CONFIG_DEBUG_LEVEL >= DEBUG_unimplemented) {
483: dprintf(1, "unimplemented %s:%d:\n", fname, lineno);
484: dump_regs(regs);
485: }
486: }
487:
488: // Report a handler reporting an invalid parameter to the caller.
489: void
490: __set_invalid(struct bregs *regs, int lineno, const char *fname)
491: {
492: __warn_invalid(regs, lineno, fname);
493: set_invalid_silent(regs);
494: }
495:
496: // Report a call of an unimplemented function.
497: void
498: __set_unimplemented(struct bregs *regs, int lineno, const char *fname)
499: {
500: __warn_unimplemented(regs, lineno, fname);
501: set_invalid_silent(regs);
502: }
503:
504: // Report a handler reporting an invalid parameter code to the
505: // caller. Note, the lineno and return code are encoded in the same
506: // parameter as gcc does a better job of scheduling function calls
507: // when there are 3 or less parameters.
508: void
509: __set_code_invalid(struct bregs *regs, u32 linecode, const char *fname)
510: {
511: u8 code = linecode;
512: u32 lineno = linecode >> 8;
513: __warn_invalid(regs, lineno, fname);
514: set_code_invalid_silent(regs, code);
515: }
516:
517: // Report a call of an unimplemented function.
518: void
519: __set_code_unimplemented(struct bregs *regs, u32 linecode, const char *fname)
520: {
521: u8 code = linecode;
522: u32 lineno = linecode >> 8;
523: __warn_unimplemented(regs, lineno, fname);
524: set_code_invalid_silent(regs, code);
525: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.