summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2022-08-05 09:03:43 +0200
committerHelge Deller <deller@gmx.de>2022-08-05 10:43:48 +0200
commit05ab9d3921cd267bdc61f4517e954e05620c98e1 (patch)
tree030bcb079038f55f3209c16b90d2f1b2396299ed
parentdc64a651f6bd83ca22b6c7a90ac486cb853f0356 (diff)
downloadpalo-05ab9d3921cd267bdc61f4517e954e05620c98e1.tar.gz
ipl: Avoid usage of __umoddi3 and __udivdi3 when printing numbers
At palo boot time we don't have an exception handler installed yet. So we must avoid using __umoddi3 and __udivdi3 (which use floating point instructions). This is a trivial work-around to simply output all integer values which are bigger than 32-bit as hex-values only. For hex-printing we can use bitshifts which don't need to be emulated. Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r--ipl/vsprintf.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/ipl/vsprintf.c b/ipl/vsprintf.c
index 4a7a060..052511a 100644
--- a/ipl/vsprintf.c
+++ b/ipl/vsprintf.c
@@ -36,10 +36,17 @@ static int skip_atoi(const char **s)
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
-#define do_div(n,base) ({ \
+/* inline on "unsigned long", not "long long" to avoid using __umoddi3 and __udivdi3 */
+#define do_div_long(n,base) ({ \
int __res; \
-__res = ((unsigned long long) n) % (unsigned) base; \
-n = ((unsigned long long) n) / (unsigned) base; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+#define do_div_hex(n) ({ \
+unsigned long __res; \
+__res = ((unsigned long) n) & 0x0f; \
+n >>= 4; \
__res; })
static char * number(char * str, unsigned long long num, int base, int size, int precision
@@ -79,8 +86,12 @@ static char * number(char * str, unsigned long long num, int base, int size, int
i = 0;
if (num == 0)
tmp[i++]='0';
- else while (num != 0)
- tmp[i++] = digits[do_div(num,base)];
+ else while (num != 0) {
+ if (base == 16)
+ tmp[i++] = digits[do_div_hex(num)];
+ else
+ tmp[i++] = digits[do_div_long(num,base)];
+ }
if (i > precision)
precision = i;
size -= precision;
@@ -277,6 +288,14 @@ again:
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
+ /* workaround to output all integers > 32bit as hex. Avoids millicode routines */
+ if (num >> 32) {
+ if (base != 16) { // append hex symbol "0x"
+ *str++ = '0';
+ *str++ = 'x';
+ }
+ base = 16;
+ }
str = number(str, num, base, field_width, precision, flags);
}
*str = '\0';