1 // Raw screen writing and debug output code.
3 // Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
7 #include <stdarg.h> // va_list
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
15 #define DEBUG_PORT PORT_SERIAL1
16 #define DEBUG_TIMEOUT 100000
21 if (!CONFIG_DEBUG_SERIAL)
23 // setup for serial logging: 8N1
24 u8 oldparam, newparam = 0x03;
25 oldparam = inb(DEBUG_PORT+SEROFF_LCR);
26 outb(newparam, DEBUG_PORT+SEROFF_LCR);
28 u8 oldier, newier = 0;
29 oldier = inb(DEBUG_PORT+SEROFF_IER);
30 outb(newier, DEBUG_PORT+SEROFF_IER);
32 if (oldparam != newparam || oldier != newier)
33 dprintf(1, "Changing serial settings was %x/%x now %x/%x\n"
34 , oldparam, oldier, newparam, newier);
37 // Write a character to the serial port.
41 if (!CONFIG_DEBUG_SERIAL)
43 int timeout = DEBUG_TIMEOUT;
44 while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x60) != 0x60)
48 outb(c, DEBUG_PORT+SEROFF_DATA);
51 // Make sure all serial port writes have been completely sent.
55 if (!CONFIG_DEBUG_SERIAL)
57 int timeout = DEBUG_TIMEOUT;
58 while ((inb(DEBUG_PORT+SEROFF_LSR) & 0x40) != 0x40)
64 // Show a character on the screen.
69 // printf is only used in 32bit code.
72 memset(&br, 0, sizeof(br));
76 call16_int(0x10, &br);
79 // Output a character.
81 putc(u16 action, char c)
83 if (CONFIG_DEBUG_LEVEL && (CONFIG_SCREEN_AND_DEBUG || !action)) {
84 if (! CONFIG_COREBOOT)
85 // Send character to debug port.
86 outb(c, PORT_BIOS_DEBUG);
87 // Send character to serial port.
94 // Send character to video screen.
103 puts(u16 action, const char *s)
109 // Output a string that is in the CS segment.
111 puts_cs(u16 action, const char *s)
114 char c = GET_GLOBAL(*(u8*)s);
121 // Output an unsigned integer.
123 putuint(u16 action, u32 val)
126 char *d = &buf[sizeof(buf) - 1];
129 *d = (val % 10) + '0';
138 // Output a single digit hex character.
140 putsinglehex(u16 action, u32 val)
145 val = 'a' + val - 10;
149 // Output an integer in hexadecimal.
151 puthex(u16 action, u32 val, int width)
169 default: putsinglehex(action, (val >> 28) & 0xf);
170 case 7: putsinglehex(action, (val >> 24) & 0xf);
171 case 6: putsinglehex(action, (val >> 20) & 0xf);
172 case 5: putsinglehex(action, (val >> 16) & 0xf);
173 case 4: putsinglehex(action, (val >> 12) & 0xf);
174 case 3: putsinglehex(action, (val >> 8) & 0xf);
175 case 2: putsinglehex(action, (val >> 4) & 0xf);
176 case 1: putsinglehex(action, (val >> 0) & 0xf);
183 return ((u8)(c - '0')) < 10;
187 bvprintf(u16 action, const char *fmt, va_list args)
191 char c = GET_GLOBAL(*(u8*)s);
201 c = GET_GLOBAL(*(u8*)n);
204 field_width = field_width * 10 + c - '0';
208 // Ignore long format indicator
210 c = GET_GLOBAL(*(u8*)n);
219 val = va_arg(args, s32);
224 putuint(action, val);
227 val = va_arg(args, s32);
228 putuint(action, val);
231 /* %p always has 0x prepended */
236 val = va_arg(args, s32);
237 puthex(action, val, field_width);
240 val = va_arg(args, int);
244 // Hack to support "%.s" - meaning string on stack.
245 if (GET_GLOBAL(*(u8*)(n+1)) != 's')
248 sarg = va_arg(args, const char *);
252 sarg = va_arg(args, const char *);
253 puts_cs(action, sarg);
261 debug_serial_flush();
265 panic(const char *fmt, ...)
267 if (CONFIG_DEBUG_LEVEL) {
270 bvprintf(0, fmt, args);
274 // XXX - use PANIC PORT.
281 __dprintf(const char *fmt, ...)
285 bvprintf(0, fmt, args);
290 printf(const char *fmt, ...)
294 bvprintf(1, fmt, args);
299 hexdump(const void *d, int len)
303 if (count % 8 == 0) {
305 puthex(0, count*4, 8);
310 puthex(0, *(u32*)d, 8);
316 debug_serial_flush();
320 dump_regs(struct bregs *regs)
323 dprintf(1, " NULL\n");
326 dprintf(1, " a=%08x b=%08x c=%08x d=%08x ds=%04x es=%04x ss=%04x\n"
327 , regs->eax, regs->ebx, regs->ecx, regs->edx
328 , regs->ds, regs->es, GET_SEG(SS));
329 dprintf(1, " si=%08x di=%08x bp=%08x sp=%08x cs=%04x ip=%04x f=%04x\n"
330 , regs->esi, regs->edi, regs->ebp, (u32)®s[1]
331 , regs->code.seg, regs->code.offset, regs->flags);
334 // Report entry to an Interrupt Service Routine (ISR).
336 __debug_isr(const char *fname)
340 debug_serial_flush();
343 // Function called on handler startup.
345 __debug_enter(struct bregs *regs, const char *fname)
347 dprintf(1, "enter %s:\n", fname);
351 // Send debugging output info.
353 __debug_stub(struct bregs *regs, int lineno, const char *fname)
355 dprintf(1, "stub %s:%d:\n", fname, lineno);
359 // Report on a handler returning a failure notification to the caller.
361 __set_fail(struct bregs *regs, int lineno, const char *fname)
363 dprintf(1, "fail %s:%d:\n", fname, lineno);
365 set_fail_silent(regs);
368 // Report on a handler returning a failure code to the caller. Note,
369 // the lineno and return code are encoded in the same parameter as gcc
370 // does a better job of scheduling function calls when there are 3 or
373 __set_code_fail(struct bregs *regs, u32 linecode, const char *fname)
376 u32 lineno = linecode >> 8;
377 dprintf(1, "fail %s:%d(%x):\n", fname, lineno, code);
379 set_code_fail_silent(regs, code);