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