[PATCH 4/5] lib: vsprintf: enable '%*pb[l]' format specifier
lukas.funke-oss at weidmueller.com
lukas.funke-oss at weidmueller.com
Mon Dec 11 13:20:50 CET 2023
From: Lukas Funke <lukas.funke at weidmueller.com>
The commit enables vsprintf() to handle the '%*pb[l]' format specifier
in order to print bitmaps and its derivatives such as cpumask and
nodemask [1]. This can be used to derive kernel boot parameters from
bitmaks such as 'isolcpu' or 'nohz_full' [2].
[1] https://www.kernel.org/doc/Documentation/printk-formats.txt
[2] https://www.kernel.org/doc/html/latest/admin-guide/kernel-parameters.html
Signed-off-by: Lukas Funke <lukas.funke at weidmueller.com>
---
lib/vsprintf.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index e14c6ca9f9..abbd80ea9c 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -25,6 +25,7 @@
#include <linux/err.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/bitmap.h>
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
@@ -390,6 +391,71 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
flags & ~SPECIAL);
}
+static char *bitmap_string(char *buf, char *end, const unsigned long *bitmap,
+ int field_width, int precision, int flags)
+{
+ const int CHUNKSIZE = 32;
+ int nr_bits = max_t(int, field_width, 0);
+ int i, chunksz;
+ int first = 1;
+
+ chunksz = nr_bits & (CHUNKSIZE - 1);
+ if (chunksz == 0)
+ chunksz = CHUNKSIZE;
+
+ i = ALIGN(nr_bits, CHUNKSIZE) - CHUNKSIZE;
+ for (; i >= 0; i -= CHUNKSIZE) {
+ u32 chunkmask, val;
+ int word, bit;
+
+ chunkmask = ((1ULL << chunksz) - 1);
+ word = i / BITS_PER_LONG;
+ bit = i % BITS_PER_LONG;
+ val = (bitmap[word] >> bit) & chunkmask;
+
+ if (!first) {
+ if (buf < end)
+ *buf = ',';
+ buf++;
+ }
+ first = 0;
+
+ field_width = DIV_ROUND_UP(chunksz, 4);
+ buf = number(buf, end, val, 16, field_width, precision,
+ (SMALL | ZEROPAD));
+
+ chunksz = CHUNKSIZE;
+ }
+ return buf;
+}
+
+static char *bitmap_list_string(char *buf, char *end, unsigned long *addr,
+ int field_width, int precision, int flags)
+{
+ int nr_bits = max_t(int, field_width, 0);
+ int first = 1;
+ int rbot, rtop;
+
+ for_each_set_bitrange(rbot, rtop, addr, nr_bits) {
+ if (!first) {
+ if (buf < end)
+ *buf = ',';
+ buf++;
+ }
+ first = 0;
+
+ buf = number(buf, end, rbot, 10, 0, -1, 0);
+ if (rtop == rbot + 1)
+ continue;
+
+ if (buf < end)
+ *buf = '-';
+ buf = number(++buf, end, rtop - 1, 10, 0, -1, 0);
+ }
+
+ return buf;
+}
+
#ifdef CONFIG_LIB_UUID
/*
* This works (roughly) the same way as Linux's.
@@ -503,6 +569,15 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
precision, flags);
flags &= ~SPECIAL;
break;
+ case 'b':
+ switch (fmt[1]) {
+ case 'l':
+ return bitmap_list_string(buf, end, ptr, field_width,
+ precision, flags);
+ default:
+ return bitmap_string(buf, end, ptr, field_width,
+ precision, flags);
+ }
#ifdef CONFIG_LIB_UUID
case 'U':
return uuid_string(buf, end, ptr, field_width, precision,
--
2.30.2
More information about the U-Boot
mailing list