[PATCH v3 07/11] lib: vsprintf: enable '%pbl' format specifier

lukas.funke-oss at weidmueller.com lukas.funke-oss at weidmueller.com
Wed Jan 10 10:10:33 CET 2024


From: Lukas Funke <lukas.funke at weidmueller.com>

The commit enables vsprintf() to handle the '%pbl' 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>
---

Changes in v3:
- Remove bitmap_string() conversion function since the same function
  can be achieved using other format specifier

 lib/vsprintf.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 27ea9c907a..e1779d75f8 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -24,6 +24,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')
@@ -389,6 +390,33 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
 		      flags & ~SPECIAL);
 }
 
+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.
@@ -502,6 +530,20 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 					       precision, flags);
 		flags &= ~SPECIAL;
 		break;
+	case 'b':
+		switch (fmt[1]) {
+		case 'l':
+			/* if the field width is not a multiple of the underlying
+			 * datatype (ulong), we get incorrect results from the bit twiddle
+			 * macros. Thus, round up to a multiple of field width of ulong
+			 */
+			field_width = field_width % BITS_PER_LONG ?
+				ALIGN(field_width, BITS_PER_LONG) : field_width;
+			return bitmap_list_string(buf, end, ptr, field_width,
+							precision, flags);
+		default:
+			return ERR_PTR(-EINVAL);
+		}
 #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