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>
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 @@
#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 @@
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 @@
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';