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