xref: /openbmc/qemu/tests/multiboot/libc.c (revision 77a8257e)
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 void* memcpy(void *dest, const void *src, int n)
26 {
27     char *d = dest;
28     const char *s = src;
29 
30     while (n--) {
31         *d++ = *s++;
32     }
33 
34     return dest;
35 }
36 
37 static void print_char(char c)
38 {
39     outb(0xe9, c);
40 }
41 
42 static void print_str(char *s)
43 {
44     while (*s) {
45         print_char(*s++);
46     }
47 }
48 
49 static void print_num(uint64_t value, int base)
50 {
51     char digits[] = "0123456789abcdef";
52     char buf[32] = { 0 };
53     int i = sizeof(buf) - 2;
54 
55     do {
56         buf[i--] = digits[value % base];
57         value /= base;
58     } while (value);
59 
60     print_str(&buf[i + 1]);
61 }
62 
63 void printf(const char *fmt, ...)
64 {
65     va_list ap;
66     uint64_t val;
67     char *str;
68     int base;
69     int has_long;
70     int alt_form;
71 
72     va_start(ap, fmt);
73 
74     for (; *fmt; fmt++) {
75         if (*fmt != '%') {
76             print_char(*fmt);
77             continue;
78         }
79         fmt++;
80 
81         if (*fmt == '#') {
82             fmt++;
83             alt_form = 1;
84         } else {
85             alt_form = 0;
86         }
87 
88         if (*fmt == 'l') {
89             fmt++;
90             if (*fmt == 'l') {
91                 fmt++;
92                 has_long = 2;
93             } else {
94                 has_long = 1;
95             }
96         } else {
97             has_long = 0;
98         }
99 
100         switch (*fmt) {
101         case 'x':
102         case 'p':
103             base = 16;
104             goto convert_number;
105         case 'd':
106         case 'i':
107         case 'u':
108             base = 10;
109             goto convert_number;
110         case 'o':
111             base = 8;
112             goto convert_number;
113 
114         convert_number:
115             switch (has_long) {
116             case 0:
117                 val = va_arg(ap, unsigned int);
118                 break;
119             case 1:
120                 val = va_arg(ap, unsigned long);
121                 break;
122             case 2:
123                 val = va_arg(ap, unsigned long long);
124                 break;
125             }
126 
127             if (alt_form && base == 16) {
128                 print_str("0x");
129             }
130 
131             print_num(val, base);
132             break;
133 
134         case 's':
135             str = va_arg(ap, char*);
136             print_str(str);
137             break;
138         case '%':
139             print_char(*fmt);
140             break;
141         default:
142             print_char('%');
143             print_char(*fmt);
144             break;
145         }
146     }
147 
148     va_end(ap);
149 }
150 
151 
152