Reduce stack usage for ISRs; minor fixes.
[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" // bprintf
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
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 void
107 bprintf(u16 action, const char *fmt, ...)
108 {
109     va_list args;
110     va_start(args, fmt);
111     const char *s = fmt;
112     for (;; s++) {
113         char c = GET_VAR(CS, (u8)*s);
114         if (!c)
115             break;
116         if (c != '%') {
117             putc(action, c);
118             continue;
119         }
120         const char *n = s+1;
121         for (;;) {
122             c = GET_VAR(CS, (u8)*n);
123             if (!isdigit(c))
124                 break;
125             n++;
126         }
127         if (c == 'l') {
128             // Ignore long format indicator
129             n++;
130             c = GET_VAR(CS, (u8)*n);
131         }
132         s32 val;
133         const char *sarg;
134         switch (c) {
135         case '%':
136             putc(action, '%');
137             break;
138         case 'd':
139             val = va_arg(args, s32);
140             if (val < 0) {
141                 putc(action, '-');
142                 val = -val;
143             }
144             putuint(action, val);
145             break;
146         case 'u':
147             val = va_arg(args, s32);
148             putuint(action, val);
149             break;
150         case 'x':
151             val = va_arg(args, s32);
152             puthex(action, val);
153             break;
154         case 'c':
155             val = va_arg(args, int);
156             putc(action, val);
157             break;
158         case 's':
159             sarg = va_arg(args, const char *);
160             puts_cs(action, sarg);
161             break;
162         default:
163             putc(action, '%');
164             n = s;
165         }
166         s = n;
167     }
168     va_end(args);
169 }
170
171 static void
172 dump_regs(const char *fname, const char *type, struct bregs *regs)
173 {
174     if (!regs) {
175         bprintf(0, "%s %s: NULL\n", type, fname);
176         return;
177     }
178     bprintf(0, "%s %s: a=%x b=%x c=%x d=%x si=%x di=%x\n"
179             , type, fname, regs->eax, regs->ebx, regs->ecx, regs->edx
180             , regs->esi, regs->edi);
181     bprintf(0, "  ds=%x es=%x bp=%x sp=%x ip=%x cs=%x f=%x\n"
182             , regs->ds, regs->es, regs->ebp, regs->esp
183             , regs->ip, regs->cs, regs->flags);
184 }
185
186 void
187 __debug_isr(const char *fname)
188 {
189     puts_cs(0, fname);
190     putc(0, '\n');
191 }
192
193 // Function called on handler startup.
194 void
195 __debug_enter(const char *fname, struct bregs *regs)
196 {
197     // XXX - implement run time suppression test
198     dump_regs(fname, "enter", regs);
199 }
200
201 void
202 __debug_fail(const char *fname, struct bregs *regs)
203 {
204     dump_regs(fname, "fail", regs);
205 }
206
207 void
208 __debug_stub(const char *fname, struct bregs *regs)
209 {
210     dump_regs(fname, "stub", regs);
211 }