xref: /openbmc/qemu/tests/multiboot/libc.c (revision 1b111dc1)
1 /*
2  * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #include "libc.h"
24 
25 static void print_char(char c)
26 {
27     outb(0xe9, c);
28 }
29 
30 static void print_str(char *s)
31 {
32     while (*s) {
33         print_char(*s++);
34     }
35 }
36 
37 static void print_num(uint64_t value, int base)
38 {
39     char digits[] = "0123456789abcdef";
40     char buf[32] = { 0 };
41     int i = sizeof(buf) - 2;
42 
43     do {
44         buf[i--] = digits[value % base];
45         value /= base;
46     } while (value);
47 
48     print_str(&buf[i + 1]);
49 }
50 
51 void printf(const char *fmt, ...)
52 {
53     va_list ap;
54     uint64_t val;
55     char *str;
56     int base;
57     int has_long;
58     int alt_form;
59 
60     va_start(ap, fmt);
61 
62     for (; *fmt; fmt++) {
63         if (*fmt != '%') {
64             print_char(*fmt);
65             continue;
66         }
67         fmt++;
68 
69         if (*fmt == '#') {
70             fmt++;
71             alt_form = 1;
72         } else {
73             alt_form = 0;
74         }
75 
76         if (*fmt == 'l') {
77             fmt++;
78             if (*fmt == 'l') {
79                 fmt++;
80                 has_long = 2;
81             } else {
82                 has_long = 1;
83             }
84         } else {
85             has_long = 0;
86         }
87 
88         switch (*fmt) {
89         case 'x':
90         case 'p':
91             base = 16;
92             goto convert_number;
93         case 'd':
94         case 'i':
95         case 'u':
96             base = 10;
97             goto convert_number;
98         case 'o':
99             base = 8;
100             goto convert_number;
101 
102         convert_number:
103             switch (has_long) {
104             case 0:
105                 val = va_arg(ap, unsigned int);
106                 break;
107             case 1:
108                 val = va_arg(ap, unsigned long);
109                 break;
110             case 2:
111                 val = va_arg(ap, unsigned long long);
112                 break;
113             }
114 
115             if (alt_form && base == 16) {
116                 print_str("0x");
117             }
118 
119             print_num(val, base);
120             break;
121 
122         case 's':
123             str = va_arg(ap, char*);
124             print_str(str);
125             break;
126         case '%':
127             print_char(*fmt);
128             break;
129         default:
130             print_char('%');
131             print_char(*fmt);
132             break;
133         }
134     }
135 
136     va_end(ap);
137 }
138 
139 
140