[PATCH 4/5] lib: vsprintf: enable '%*pb[l]' format specifier

Heinrich Schuchardt xypron.glpk at gmx.de
Mon Dec 11 17:27:50 CET 2023


On 11.12.23 13:20, lukas.funke-oss at weidmueller.com wrote:
> 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>

Please, add a change for doc/develop/printf.rst to the patch describing
the new format.

Best regards

Heinrich

> ---
>
>   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,



More information about the U-Boot mailing list