powerpc/mm: Avoid calling arch_enter/leave_lazy_mmu() in set_ptes
[platform/kernel/linux-starfive.git] / tools / testing / selftests / kvm / lib / guest_sprintf.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include "test_util.h"
3 #include "kvm_util.h"
4 #include "ucall_common.h"
5
6 #define APPEND_BUFFER_SAFE(str, end, v) \
7 do {                                    \
8         GUEST_ASSERT(str < end);        \
9         *str++ = (v);                   \
10 } while (0)
11
12 static int isdigit(int ch)
13 {
14         return (ch >= '0') && (ch <= '9');
15 }
16
17 static int skip_atoi(const char **s)
18 {
19         int i = 0;
20
21         while (isdigit(**s))
22                 i = i * 10 + *((*s)++) - '0';
23         return i;
24 }
25
26 #define ZEROPAD 1               /* pad with zero */
27 #define SIGN    2               /* unsigned/signed long */
28 #define PLUS    4               /* show plus */
29 #define SPACE   8               /* space if plus */
30 #define LEFT    16              /* left justified */
31 #define SMALL   32              /* Must be 32 == 0x20 */
32 #define SPECIAL 64              /* 0x */
33
34 #define __do_div(n, base)                               \
35 ({                                                      \
36         int __res;                                      \
37                                                         \
38         __res = ((uint64_t) n) % (uint32_t) base;       \
39         n = ((uint64_t) n) / (uint32_t) base;           \
40         __res;                                          \
41 })
42
43 static char *number(char *str, const char *end, long num, int base, int size,
44                     int precision, int type)
45 {
46         /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
47         static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
48
49         char tmp[66];
50         char c, sign, locase;
51         int i;
52
53         /*
54          * locase = 0 or 0x20. ORing digits or letters with 'locase'
55          * produces same digits or (maybe lowercased) letters
56          */
57         locase = (type & SMALL);
58         if (type & LEFT)
59                 type &= ~ZEROPAD;
60         if (base < 2 || base > 16)
61                 return NULL;
62         c = (type & ZEROPAD) ? '0' : ' ';
63         sign = 0;
64         if (type & SIGN) {
65                 if (num < 0) {
66                         sign = '-';
67                         num = -num;
68                         size--;
69                 } else if (type & PLUS) {
70                         sign = '+';
71                         size--;
72                 } else if (type & SPACE) {
73                         sign = ' ';
74                         size--;
75                 }
76         }
77         if (type & SPECIAL) {
78                 if (base == 16)
79                         size -= 2;
80                 else if (base == 8)
81                         size--;
82         }
83         i = 0;
84         if (num == 0)
85                 tmp[i++] = '0';
86         else
87                 while (num != 0)
88                         tmp[i++] = (digits[__do_div(num, base)] | locase);
89         if (i > precision)
90                 precision = i;
91         size -= precision;
92         if (!(type & (ZEROPAD + LEFT)))
93                 while (size-- > 0)
94                         APPEND_BUFFER_SAFE(str, end, ' ');
95         if (sign)
96                 APPEND_BUFFER_SAFE(str, end, sign);
97         if (type & SPECIAL) {
98                 if (base == 8)
99                         APPEND_BUFFER_SAFE(str, end, '0');
100                 else if (base == 16) {
101                         APPEND_BUFFER_SAFE(str, end, '0');
102                         APPEND_BUFFER_SAFE(str, end, 'x');
103                 }
104         }
105         if (!(type & LEFT))
106                 while (size-- > 0)
107                         APPEND_BUFFER_SAFE(str, end, c);
108         while (i < precision--)
109                 APPEND_BUFFER_SAFE(str, end, '0');
110         while (i-- > 0)
111                 APPEND_BUFFER_SAFE(str, end, tmp[i]);
112         while (size-- > 0)
113                 APPEND_BUFFER_SAFE(str, end, ' ');
114
115         return str;
116 }
117
118 int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args)
119 {
120         char *str, *end;
121         const char *s;
122         uint64_t num;
123         int i, base;
124         int len;
125
126         int flags;              /* flags to number() */
127
128         int field_width;        /* width of output field */
129         int precision;          /*
130                                  * min. # of digits for integers; max
131                                  * number of chars for from string
132                                  */
133         int qualifier;          /* 'h', 'l', or 'L' for integer fields */
134
135         end = buf + n;
136         GUEST_ASSERT(buf < end);
137         GUEST_ASSERT(n > 0);
138
139         for (str = buf; *fmt; ++fmt) {
140                 if (*fmt != '%') {
141                         APPEND_BUFFER_SAFE(str, end, *fmt);
142                         continue;
143                 }
144
145                 /* process flags */
146                 flags = 0;
147 repeat:
148                 ++fmt;          /* this also skips first '%' */
149                 switch (*fmt) {
150                 case '-':
151                         flags |= LEFT;
152                         goto repeat;
153                 case '+':
154                         flags |= PLUS;
155                         goto repeat;
156                 case ' ':
157                         flags |= SPACE;
158                         goto repeat;
159                 case '#':
160                         flags |= SPECIAL;
161                         goto repeat;
162                 case '0':
163                         flags |= ZEROPAD;
164                         goto repeat;
165                 }
166
167                 /* get field width */
168                 field_width = -1;
169                 if (isdigit(*fmt))
170                         field_width = skip_atoi(&fmt);
171                 else if (*fmt == '*') {
172                         ++fmt;
173                         /* it's the next argument */
174                         field_width = va_arg(args, int);
175                         if (field_width < 0) {
176                                 field_width = -field_width;
177                                 flags |= LEFT;
178                         }
179                 }
180
181                 /* get the precision */
182                 precision = -1;
183                 if (*fmt == '.') {
184                         ++fmt;
185                         if (isdigit(*fmt))
186                                 precision = skip_atoi(&fmt);
187                         else if (*fmt == '*') {
188                                 ++fmt;
189                                 /* it's the next argument */
190                                 precision = va_arg(args, int);
191                         }
192                         if (precision < 0)
193                                 precision = 0;
194                 }
195
196                 /* get the conversion qualifier */
197                 qualifier = -1;
198                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
199                         qualifier = *fmt;
200                         ++fmt;
201                 }
202
203                 /* default base */
204                 base = 10;
205
206                 switch (*fmt) {
207                 case 'c':
208                         if (!(flags & LEFT))
209                                 while (--field_width > 0)
210                                         APPEND_BUFFER_SAFE(str, end, ' ');
211                         APPEND_BUFFER_SAFE(str, end,
212                                             (uint8_t)va_arg(args, int));
213                         while (--field_width > 0)
214                                 APPEND_BUFFER_SAFE(str, end, ' ');
215                         continue;
216
217                 case 's':
218                         s = va_arg(args, char *);
219                         len = strnlen(s, precision);
220
221                         if (!(flags & LEFT))
222                                 while (len < field_width--)
223                                         APPEND_BUFFER_SAFE(str, end, ' ');
224                         for (i = 0; i < len; ++i)
225                                 APPEND_BUFFER_SAFE(str, end, *s++);
226                         while (len < field_width--)
227                                 APPEND_BUFFER_SAFE(str, end, ' ');
228                         continue;
229
230                 case 'p':
231                         if (field_width == -1) {
232                                 field_width = 2 * sizeof(void *);
233                                 flags |= SPECIAL | SMALL | ZEROPAD;
234                         }
235                         str = number(str, end,
236                                      (uint64_t)va_arg(args, void *), 16,
237                                      field_width, precision, flags);
238                         continue;
239
240                 case 'n':
241                         if (qualifier == 'l') {
242                                 long *ip = va_arg(args, long *);
243                                 *ip = (str - buf);
244                         } else {
245                                 int *ip = va_arg(args, int *);
246                                 *ip = (str - buf);
247                         }
248                         continue;
249
250                 case '%':
251                         APPEND_BUFFER_SAFE(str, end, '%');
252                         continue;
253
254                 /* integer number formats - set up the flags and "break" */
255                 case 'o':
256                         base = 8;
257                         break;
258
259                 case 'x':
260                         flags |= SMALL;
261                 case 'X':
262                         base = 16;
263                         break;
264
265                 case 'd':
266                 case 'i':
267                         flags |= SIGN;
268                 case 'u':
269                         break;
270
271                 default:
272                         APPEND_BUFFER_SAFE(str, end, '%');
273                         if (*fmt)
274                                 APPEND_BUFFER_SAFE(str, end, *fmt);
275                         else
276                                 --fmt;
277                         continue;
278                 }
279                 if (qualifier == 'l')
280                         num = va_arg(args, uint64_t);
281                 else if (qualifier == 'h') {
282                         num = (uint16_t)va_arg(args, int);
283                         if (flags & SIGN)
284                                 num = (int16_t)num;
285                 } else if (flags & SIGN)
286                         num = va_arg(args, int);
287                 else
288                         num = va_arg(args, uint32_t);
289                 str = number(str, end, num, base, field_width, precision, flags);
290         }
291
292         GUEST_ASSERT(str < end);
293         *str = '\0';
294         return str - buf;
295 }
296
297 int guest_snprintf(char *buf, int n, const char *fmt, ...)
298 {
299         va_list va;
300         int len;
301
302         va_start(va, fmt);
303         len = guest_vsnprintf(buf, n, fmt, va);
304         va_end(va);
305
306         return len;
307 }