summaryrefslogtreecommitdiffstats
path: root/lib/vsprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r--lib/vsprintf.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 602d2081e713..b235c96167d3 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -794,6 +794,87 @@ char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec,
}
static noinline_for_stack
+char *bitmap_string(char *buf, char *end, unsigned long *bitmap,
+ struct printf_spec spec, const char *fmt)
+{
+ const int CHUNKSZ = 32;
+ int nr_bits = max_t(int, spec.field_width, 0);
+ int i, chunksz;
+ bool first = true;
+
+ /* reused to print numbers */
+ spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 };
+
+ chunksz = nr_bits & (CHUNKSZ - 1);
+ if (chunksz == 0)
+ chunksz = CHUNKSZ;
+
+ i = ALIGN(nr_bits, CHUNKSZ) - CHUNKSZ;
+ for (; i >= 0; i -= CHUNKSZ) {
+ 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 = false;
+
+ spec.field_width = DIV_ROUND_UP(chunksz, 4);
+ buf = number(buf, end, val, spec);
+
+ chunksz = CHUNKSZ;
+ }
+ return buf;
+}
+
+static noinline_for_stack
+char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap,
+ struct printf_spec spec, const char *fmt)
+{
+ int nr_bits = max_t(int, spec.field_width, 0);
+ /* current bit is 'cur', most recently seen range is [rbot, rtop] */
+ int cur, rbot, rtop;
+ bool first = true;
+
+ /* reused to print numbers */
+ spec = (struct printf_spec){ .base = 10 };
+
+ rbot = cur = find_first_bit(bitmap, nr_bits);
+ while (cur < nr_bits) {
+ rtop = cur;
+ cur = find_next_bit(bitmap, nr_bits, cur + 1);
+ if (cur < nr_bits && cur <= rtop + 1)
+ continue;
+
+ if (!first) {
+ if (buf < end)
+ *buf = ',';
+ buf++;
+ }
+ first = false;
+
+ buf = number(buf, end, rbot, spec);
+ if (rbot < rtop) {
+ if (buf < end)
+ *buf = '-';
+ buf++;
+
+ buf = number(buf, end, rtop, spec);
+ }
+
+ rbot = cur;
+ }
+ return buf;
+}
+
+static noinline_for_stack
char *mac_address_string(char *buf, char *end, u8 *addr,
struct printf_spec spec, const char *fmt)
{
@@ -1258,6 +1339,10 @@ int kptr_restrict __read_mostly;
* - 'B' For backtraced symbolic direct pointers with offset
* - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
* - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
+ * - 'b[l]' For a bitmap, the number of bits is determined by the field
+ * width which must be explicitly specified either as part of the
+ * format string '%32b[l]' or through '%*b[l]', [l] selects
+ * range-list format instead of hex format
* - 'M' For a 6-byte MAC address, it prints the address in the
* usual colon-separated hex notation
* - 'm' For a 6-byte MAC address, it prints the hex address without colons
@@ -1354,6 +1439,13 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
return resource_string(buf, end, ptr, spec, fmt);
case 'h':
return hex_string(buf, end, ptr, spec, fmt);
+ case 'b':
+ switch (fmt[1]) {
+ case 'l':
+ return bitmap_list_string(buf, end, ptr, spec, fmt);
+ default:
+ return bitmap_string(buf, end, ptr, spec, fmt);
+ }
case 'M': /* Colon separated: 00:01:02:03:04:05 */
case 'm': /* Contiguous: 000102030405 */
/* [mM]F (FDDI) */
@@ -1689,6 +1781,8 @@ qualifier:
* %pB output the name of a backtrace symbol with its offset
* %pR output the address range in a struct resource with decoded flags
* %pr output the address range in a struct resource with raw flags
+ * %pb output the bitmap with field width as the number of bits
+ * %pbl output the bitmap as range list with field width as the number of bits
* %pM output a 6-byte MAC address with colons
* %pMR output a 6-byte MAC address with colons in reversed order
* %pMF output a 6-byte MAC address with dashes