1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include <io/uart.h>
14 #include <lib/printk.h>
15 #include <common/types.h>
16
17 #define PRINT_BUF_LEN 64
18
19 typedef __builtin_va_list va_list;
20 #define va_start(v, l) __builtin_va_start(v, l)
21 #define va_end(v) __builtin_va_end(v)
22 #define va_arg(v, l) __builtin_va_arg(v, l)
23 #define va_copy(d, s) __builtin_va_copy(d, s)
24
25 graphic_putc_handler graphic_putc = NULL;
set_graphic_putc_handler(graphic_putc_handler f)26 void set_graphic_putc_handler(graphic_putc_handler f)
27 {
28 graphic_putc = f;
29 }
30
simple_outputchar(char ** str,char c)31 static void simple_outputchar(char **str, char c)
32 {
33 if (str) {
34 **str = c;
35 ++(*str);
36 } else {
37 uart_send(c);
38 if (graphic_putc)
39 graphic_putc(c);
40 }
41 }
42
43 enum flags { PAD_ZERO = 1, PAD_RIGHT = 2 };
44
prints(char ** out,const char * string,int width,int flags)45 static int prints(char **out, const char *string, int width, int flags)
46 {
47 int pc = 0, padchar = ' ';
48
49 if (width > 0) {
50 int len = 0;
51 const char *ptr;
52 for (ptr = string; *ptr; ++ptr)
53 ++len;
54 if (len >= width)
55 width = 0;
56 else
57 width -= len;
58 if (flags & PAD_ZERO)
59 padchar = '0';
60 }
61 if (!(flags & PAD_RIGHT)) {
62 for (; width > 0; --width) {
63 simple_outputchar(out, padchar);
64 ++pc;
65 }
66 }
67 for (; *string; ++string) {
68 simple_outputchar(out, *string);
69 ++pc;
70 }
71 for (; width > 0; --width) {
72 simple_outputchar(out, padchar);
73 ++pc;
74 }
75
76 return pc;
77 }
78
simple_outputi(char ** out,long i,int base,int sign,int width,int flags,int letbase)79 static int simple_outputi(char **out, long i, int base, int sign, int width,
80 int flags, int letbase)
81 {
82 char print_buf[PRINT_BUF_LEN];
83 char *s;
84 int t, neg = 0, pc = 0;
85 unsigned long u = i;
86
87 if (i == 0) {
88 print_buf[0] = '0';
89 print_buf[1] = '\0';
90 return prints(out, print_buf, width, flags);
91 }
92
93 if (sign && base == 10 && i < 0) {
94 neg = 1;
95 u = -i;
96 }
97
98 s = print_buf + PRINT_BUF_LEN - 1;
99 *s = '\0';
100
101 while (u) {
102 t = u % base;
103 if (t >= 10)
104 t += letbase - '0' - 10;
105 *--s = t + '0';
106 u /= base;
107 }
108
109 if (neg) {
110 if (width && (flags & PAD_ZERO)) {
111 simple_outputchar(out, '-');
112 ++pc;
113 --width;
114 } else {
115 *--s = '-';
116 }
117 }
118
119 return pc + prints(out, s, width, flags);
120 }
121
simple_vsprintf(char ** out,const char * format,va_list ap)122 static int simple_vsprintf(char **out, const char *format, va_list ap)
123 {
124 int width, flags;
125 int pc = 0;
126 char scr[2];
127 union {
128 char c;
129 char *s;
130 int i;
131 unsigned int u;
132 long li;
133 unsigned long lu;
134 long long lli;
135 unsigned long long llu;
136 short hi;
137 unsigned short hu;
138 signed char hhi;
139 unsigned char hhu;
140 void *p;
141 } u;
142
143 for (; *format != 0; ++format) {
144 if (*format == '%') {
145 ++format;
146 width = flags = 0;
147 if (*format == '\0')
148 break;
149 if (*format == '%')
150 goto out;
151 if (*format == '-') {
152 ++format;
153 flags = PAD_RIGHT;
154 }
155 while (*format == '0') {
156 ++format;
157 flags |= PAD_ZERO;
158 }
159 if (*format == '*') {
160 width = va_arg(ap, int);
161 format++;
162 } else {
163 for (; *format >= '0' && *format <= '9'; ++format) {
164 width *= 10;
165 width += *format - '0';
166 }
167 }
168 switch (*format) {
169 case ('d'):
170 u.i = va_arg(ap, int);
171 pc += simple_outputi(out, u.i, 10, 1, width, flags, 'a');
172 break;
173
174 case ('b'):
175 u.i = va_arg(ap, int);
176 pc += simple_outputi(out, u.i, 2, 1, width, flags, 'a');
177 break;
178
179 case ('u'):
180 u.u = va_arg(ap, unsigned int);
181 pc += simple_outputi(out, u.u, 10, 0, width, flags, 'a');
182 break;
183
184 case ('p'):
185 u.llu = va_arg(ap, unsigned long);
186 pc += simple_outputi(out, u.llu, 16, 0, width, flags, 'a');
187 break;
188
189 case ('x'):
190 u.u = va_arg(ap, unsigned int);
191 pc += simple_outputi(out, u.u, 16, 0, width, flags, 'a');
192 break;
193
194 case ('X'):
195 u.u = va_arg(ap, unsigned int);
196 pc += simple_outputi(out, u.u, 16, 0, width, flags, 'A');
197 break;
198
199 case ('c'):
200 u.c = va_arg(ap, int);
201 scr[0] = u.c;
202 scr[1] = '\0';
203 pc += prints(out, scr, width, flags);
204 break;
205
206 case ('s'):
207 u.s = va_arg(ap, char *);
208 pc += prints(out, u.s ? u.s : "(null)", width, flags);
209 break;
210 case ('l'):
211 ++format;
212 switch (*format) {
213 case ('d'):
214 u.li = va_arg(ap, long);
215 pc += simple_outputi(out, u.li, 10, 1, width, flags, 'a');
216 break;
217
218 case ('u'):
219 u.lu = va_arg(ap, unsigned long);
220 pc += simple_outputi(out, u.lu, 10, 0, width, flags, 'a');
221 break;
222
223 case ('x'):
224 u.lu = va_arg(ap, unsigned long);
225 pc += simple_outputi(out, u.lu, 16, 0, width, flags, 'a');
226 break;
227
228 case ('X'):
229 u.lu = va_arg(ap, unsigned long);
230 pc += simple_outputi(out, u.lu, 16, 0, width, flags, 'A');
231 break;
232
233 case ('l'):
234 ++format;
235 switch (*format) {
236 case ('d'):
237 u.lli = va_arg(ap, long long);
238 pc += simple_outputi(
239 out, u.lli, 10, 1, width, flags, 'a');
240 break;
241
242 case ('u'):
243 u.llu = va_arg(ap, unsigned long long);
244 pc += simple_outputi(
245 out, u.llu, 10, 0, width, flags, 'a');
246 break;
247
248 case ('x'):
249 u.llu = va_arg(ap, unsigned long long);
250 pc += simple_outputi(
251 out, u.llu, 16, 0, width, flags, 'a');
252 break;
253
254 case ('X'):
255 u.llu = va_arg(ap, unsigned long long);
256 pc += simple_outputi(
257 out, u.llu, 16, 0, width, flags, 'A');
258 break;
259
260 default:
261 break;
262 }
263 break;
264 default:
265 break;
266 }
267 break;
268 case ('h'):
269 ++format;
270 switch (*format) {
271 case ('d'):
272 u.hi = va_arg(ap, int);
273 pc += simple_outputi(out, u.hi, 10, 1, width, flags, 'a');
274 break;
275
276 case ('u'):
277 u.hu = va_arg(ap, unsigned int);
278 pc += simple_outputi(out, u.lli, 10, 0, width, flags, 'a');
279 break;
280
281 case ('x'):
282 u.hu = va_arg(ap, unsigned int);
283 pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'a');
284 break;
285
286 case ('X'):
287 u.hu = va_arg(ap, unsigned int);
288 pc += simple_outputi(out, u.lli, 16, 0, width, flags, 'A');
289 break;
290
291 case ('h'):
292 ++format;
293 switch (*format) {
294 case ('d'):
295 u.hhi = va_arg(ap, int);
296 pc += simple_outputi(
297 out, u.hhi, 10, 1, width, flags, 'a');
298 break;
299
300 case ('u'):
301 u.hhu = va_arg(ap, unsigned int);
302 pc += simple_outputi(
303 out, u.lli, 10, 0, width, flags, 'a');
304 break;
305
306 case ('x'):
307 u.hhu = va_arg(ap, unsigned int);
308 pc += simple_outputi(
309 out, u.lli, 16, 0, width, flags, 'a');
310 break;
311
312 case ('X'):
313 u.hhu = va_arg(ap, unsigned int);
314 pc += simple_outputi(
315 out, u.lli, 16, 0, width, flags, 'A');
316 break;
317
318 default:
319 break;
320 }
321 break;
322 default:
323 break;
324 }
325 break;
326 default:
327 break;
328 }
329 } else {
330 out:
331 if (*format == '\n')
332 simple_outputchar(out, '\r');
333 simple_outputchar(out, *format);
334 ++pc;
335 }
336 }
337 if (out)
338 **out = '\0';
339 return pc;
340 }
341
simple_sprintf(char * str,const char * fmt,...)342 int simple_sprintf(char *str, const char *fmt, ...)
343 {
344 va_list va;
345 int count;
346
347 va_start(va, fmt);
348 count = simple_vsprintf(&str, fmt, va);
349 va_end(va);
350
351 return count;
352 }
353
354 #define BUF_SIZE 512
355 extern bool is_tlogger_on(void);
356 extern int append_chcore_log(const char *str, size_t len, bool is_kernel);
357
printk(const char * fmt,...)358 void printk(const char *fmt, ...)
359 {
360 va_list va;
361
362 if (is_tlogger_on()) {
363 char buf[BUF_SIZE];
364 int count;
365 char *ptr = buf;
366
367 va_start(va, fmt);
368 count = simple_vsprintf(&ptr, fmt, va);
369 va_end(va);
370 append_chcore_log(buf, count, true);
371 return;
372 }
373
374 va_start(va, fmt);
375 simple_vsprintf(NULL, fmt, va);
376 va_end(va);
377 }
378