Minor cleanups.
[seabios.git] / src / output.c
1 // Raw screen writing code.
2 //
3 // Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
4 //
5 // This file may be distributed under the terms of the GNU GPLv3 license.
6
7 #include <stdarg.h> // va_list
8
9 #include "farptr.h" // GET_VAR
10 #include "util.h" // printf
11 #include "biosvar.h" // struct bregs
12
13 static void
14 screenc(u8 c)
15 {
16     struct bregs br;
17     memset(&br, 0, sizeof(br));
18     br.ah = 0x0e;
19     br.al = c;
20     call16_int(0x10, &br);
21 }
22
23 // Write a charcter to the framebuffer.
24 static void
25 putc(u16 action, char c)
26 {
27     outb(c, PORT_BIOS_DEBUG);
28     if (action) {
29         if (c == '\n')
30             screenc('\r');
31         screenc(c);
32     }
33 }
34
35 // Write a string to the framebuffer.
36 static void
37 puts(u16 action, const char *s)
38 {
39     for (; *s; s++)
40         putc(action, *s);
41 }
42
43 // Write a string to the framebuffer.
44 static void
45 puts_cs(u16 action, const char *s)
46 {
47     for (;; s++) {
48         char c = GET_VAR(CS, *(u8*)s);
49         if (!c)
50             break;
51         putc(action, c);
52     }
53 }
54
55 // Write an unsigned integer to the screen.
56 static void
57 putuint(u16 action, u32 val)
58 {
59     char buf[12];
60     char *d = &buf[sizeof(buf) - 1];
61     *d-- = '\0';
62     for (;;) {
63         *d = (val % 10) + '0';
64         val /= 10;
65         if (!val)
66             break;
67         d--;
68     }
69     puts(action, d);
70 }
71
72 // Write a single digit hex character to the screen.
73 static inline void
74 putsinglehex(u16 action, u32 val)
75 {
76     if (val <= 9)
77         val = '0' + val;
78     else
79         val = 'a' + val - 10;
80     putc(action, val);
81 }
82
83 // Write an integer in hexadecimal to the screen.
84 static void
85 puthex(u16 action, u32 val)
86 {
87     putsinglehex(action, (val >> 28) & 0xf);
88     putsinglehex(action, (val >> 24) & 0xf);
89     putsinglehex(action, (val >> 20) & 0xf);
90     putsinglehex(action, (val >> 16) & 0xf);
91     putsinglehex(action, (val >> 12) & 0xf);
92     putsinglehex(action, (val >> 8) & 0xf);
93     putsinglehex(action, (val >> 4) & 0xf);
94     putsinglehex(action, (val >> 0) & 0xf);
95 }
96
97 static inline int
98 isdigit(u8 c)
99 {
100     return c - '0' < 10;
101 }
102
103 static void
104 bvprintf(u16 action, const char *fmt, va_list args)
105 {
106     const char *s = fmt;
107     for (;; s++) {
108         char c = GET_VAR(CS, *(u8*)s);
109         if (!c)
110             break;
111         if (c != '%') {
112             putc(action, c);
113             continue;
114         }
115         const char *n = s+1;
116         for (;;) {
117             c = GET_VAR(CS, *(u8*)n);
118             if (!isdigit(c))
119                 break;
120             n++;
121         }
122         if (c == 'l') {
123             // Ignore long format indicator
124             n++;
125             c = GET_VAR(CS, *(u8*)n);
126         }
127         s32 val;
128         const char *sarg;
129         switch (c) {
130         case '%':
131             putc(action, '%');
132             break;
133         case 'd':
134             val = va_arg(args, s32);
135             if (val < 0) {
136                 putc(action, '-');
137                 val = -val;
138             }
139             putuint(action, val);
140             break;
141         case 'u':
142             val = va_arg(args, s32);
143             putuint(action, val);
144             break;
145         case 'p':
146         case 'x':
147             val = va_arg(args, s32);
148             puthex(action, val);
149             break;
150         case 'c':
151             val = va_arg(args, int);
152             putc(action, val);
153             break;
154         case '.':
155             // Hack to support "%.s" - meaning string on stack.
156             if (GET_VAR(CS, *(u8*)(n+1)) != 's')
157                 break;
158             n++;
159             sarg = va_arg(args, const char *);
160             puts(action, sarg);
161             break;
162         case 's':
163             sarg = va_arg(args, const char *);
164             puts_cs(action, sarg);
165             break;
166         default:
167             putc(action, '%');
168             n = s;
169         }
170         s = n;
171     }
172 }
173
174 void
175 BX_PANIC(const char *fmt, ...)
176 {
177     va_list args;
178     va_start(args, fmt);
179     bvprintf(0, fmt, args);
180     va_end(args);
181
182     // XXX - use PANIC PORT.
183     irq_disable();
184     for (;;)
185         hlt();
186 }
187
188 void
189 BX_INFO(const char *fmt, ...)
190 {
191     va_list args;
192     va_start(args, fmt);
193     bvprintf(0, fmt, args);
194     va_end(args);
195 }
196
197 void
198 printf(const char *fmt, ...)
199 {
200     va_list args;
201     va_start(args, fmt);
202     bvprintf(1, fmt, args);
203     va_end(args);
204 }
205
206 static void
207 dump_regs(const char *fname, const char *type, struct bregs *regs)
208 {
209     if (!regs) {
210         BX_INFO("%s %s: NULL\n", type, fname);
211         return;
212     }
213     BX_INFO("%s %s: a=%x b=%x c=%x d=%x si=%x di=%x\n"
214             , type, fname, regs->eax, regs->ebx, regs->ecx, regs->edx
215             , regs->esi, regs->edi);
216     BX_INFO("  ds=%x es=%x ip=%x cs=%x f=%x r=%p\n"
217             , regs->ds, regs->es, regs->ip, regs->cs, regs->flags, regs);
218 }
219
220 void
221 __debug_isr(const char *fname)
222 {
223     puts_cs(0, fname);
224     putc(0, '\n');
225 }
226
227 // Function called on handler startup.
228 void
229 __debug_enter(const char *fname, struct bregs *regs)
230 {
231     // XXX - implement run time suppression test
232     dump_regs(fname, "enter", regs);
233 }
234
235 void
236 __debug_fail(const char *fname, struct bregs *regs)
237 {
238     dump_regs(fname, "fail", regs);
239 }
240
241 void
242 __debug_stub(const char *fname, struct bregs *regs)
243 {
244     dump_regs(fname, "stub", regs);
245 }