Search code examples
linuxlinux-kernelbitmapbit-manipulation

How to get aribtrary portion of a bitmap in Linux kernel program?


I have this code snippet from a baremetal program(here printf is for baremetal).

  rd_data = *(__GICD + GICD_TYPER);
  printf("--- GICD Page Status (GICD_TYPER)----------------------\n");
  printf("ITLineNumber(=SPIS/32):   %d\n", BIT_FIELD_READER(rd_data, 3, 0)); 
  printf("SecurityExtn:             %d\n", BIT_FIELD_READER(rd_data,10,10));
  printf("MBIS:                     %d\n", BIT_FIELD_READER(rd_data,16,16));
  printf("LPIS:                     %d\n", BIT_FIELD_READER(rd_data,17,17));
  printf("DVIS:                     %d\n", BIT_FIELD_READER(rd_data,18,18));
  printf("IDbits:                   %d\n", BIT_FIELD_READER(rd_data,23,19));
  printf("A3V:                      %d\n", BIT_FIELD_READER(rd_data,24,24));
  printf("No1N:                     %d\n", BIT_FIELD_READER(rd_data,25,25));

The macro BIT_FIELD_READER(rd_data, end_bit, start_bit) looks very convenient.
And now I wish to print the some registers of a peripheral registers in kernel code (using printk), and searched the kernel code if there is something similar(to copy-paste and just replace the macro).
In include/linux/bitmap.h, there is bitmap_get_value8(map, start) but it's only for getting 8 bit value.
And in include/linux/bitfield.h, I found something like #define REG_FIELD_A GENMASK(6, 0) and a = FIELD_GET(REG_FIELD_A, reg);. But this requires defining every field which is cumbsersome and not succinct. Isn't there any macro getting arbitrary bit fields using start and end position(or length) in Linux kernel code?


Solution

  • The BIT_FIELD_READER macro described in the question could be defined using macros defined by #include <linux/bitfield.h> and #include <linux/bits.h> as follows:

    #define BIT_FIELD_READER(_reg, _hi, _lo) FIELD_GET(GENMASK(_hi, _lo), _reg)
    

    A restriction is that the _hi and _lo parameters need to be compile-time constants because the FIELD_GET(_mask, _reg) macro requires the _mask parameter to be a compile-time constant.

    Similar wrappers around the FIELD_PREP(_mask, _val), FIELD_MAX(_mask), and FIELD_FIT(_mask, _val) macros may be useful:

    #define BIT_FIELD_PREP(_val, _hi, _lo) FIELD_PREP(GENMASK(_hi, _lo), _val)
    #define BIT_FIELD_MAX(_hi, _lo) FIELD_MAX(GENMASK(_hi, _lo)
    #define BIT_FIELD_FIT(_val, _hi, _lo) FIELD_FIT(GENMASK(_hi, _lo), _val)
    

    They have the same restriction that the _hi and _lo parameters need to be compile-time constants.