packing.rst 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. ================================================
  2. Generic bitfield packing and unpacking functions
  3. ================================================
  4. Problem statement
  5. -----------------
  6. When working with hardware, one has to choose between several approaches of
  7. interfacing with it.
  8. One can memory-map a pointer to a carefully crafted struct over the hardware
  9. device's memory region, and access its fields as struct members (potentially
  10. declared as bitfields). But writing code this way would make it less portable,
  11. due to potential endianness mismatches between the CPU and the hardware device.
  12. Additionally, one has to pay close attention when translating register
  13. definitions from the hardware documentation into bit field indices for the
  14. structs. Also, some hardware (typically networking equipment) tends to group
  15. its register fields in ways that violate any reasonable word boundaries
  16. (sometimes even 64 bit ones). This creates the inconvenience of having to
  17. define "high" and "low" portions of register fields within the struct.
  18. A more robust alternative to struct field definitions would be to extract the
  19. required fields by shifting the appropriate number of bits. But this would
  20. still not protect from endianness mismatches, except if all memory accesses
  21. were performed byte-by-byte. Also the code can easily get cluttered, and the
  22. high-level idea might get lost among the many bit shifts required.
  23. Many drivers take the bit-shifting approach and then attempt to reduce the
  24. clutter with tailored macros, but more often than not these macros take
  25. shortcuts that still prevent the code from being truly portable.
  26. The solution
  27. ------------
  28. This API deals with 2 basic operations:
  29. - Packing a CPU-usable number into a memory buffer (with hardware
  30. constraints/quirks)
  31. - Unpacking a memory buffer (which has hardware constraints/quirks)
  32. into a CPU-usable number.
  33. The API offers an abstraction over said hardware constraints and quirks,
  34. over CPU endianness and therefore between possible mismatches between
  35. the two.
  36. The basic unit of these API functions is the u64. From the CPU's
  37. perspective, bit 63 always means bit offset 7 of byte 7, albeit only
  38. logically. The question is: where do we lay this bit out in memory?
  39. The following examples cover the memory layout of a packed u64 field.
  40. The byte offsets in the packed buffer are always implicitly 0, 1, ... 7.
  41. What the examples show is where the logical bytes and bits sit.
  42. 1. Normally (no quirks), we would do it like this:
  43. ::
  44. 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
  45. 7 6 5 4
  46. 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  47. 3 2 1 0
  48. That is, the MSByte (7) of the CPU-usable u64 sits at memory offset 0, and the
  49. LSByte (0) of the u64 sits at memory offset 7.
  50. This corresponds to what most folks would regard to as "big endian", where
  51. bit i corresponds to the number 2^i. This is also referred to in the code
  52. comments as "logical" notation.
  53. 2. If QUIRK_MSB_ON_THE_RIGHT is set, we do it like this:
  54. ::
  55. 56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39
  56. 7 6 5 4
  57. 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7
  58. 3 2 1 0
  59. That is, QUIRK_MSB_ON_THE_RIGHT does not affect byte positioning, but
  60. inverts bit offsets inside a byte.
  61. 3. If QUIRK_LITTLE_ENDIAN is set, we do it like this:
  62. ::
  63. 39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56
  64. 4 5 6 7
  65. 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
  66. 0 1 2 3
  67. Therefore, QUIRK_LITTLE_ENDIAN means that inside the memory region, every
  68. byte from each 4-byte word is placed at its mirrored position compared to
  69. the boundary of that word.
  70. 4. If QUIRK_MSB_ON_THE_RIGHT and QUIRK_LITTLE_ENDIAN are both set, we do it
  71. like this:
  72. ::
  73. 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  74. 4 5 6 7
  75. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
  76. 0 1 2 3
  77. 5. If just QUIRK_LSW32_IS_FIRST is set, we do it like this:
  78. ::
  79. 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  80. 3 2 1 0
  81. 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
  82. 7 6 5 4
  83. In this case the 8 byte memory region is interpreted as follows: first
  84. 4 bytes correspond to the least significant 4-byte word, next 4 bytes to
  85. the more significant 4-byte word.
  86. 6. If QUIRK_LSW32_IS_FIRST and QUIRK_MSB_ON_THE_RIGHT are set, we do it like
  87. this:
  88. ::
  89. 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7
  90. 3 2 1 0
  91. 56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39
  92. 7 6 5 4
  93. 7. If QUIRK_LSW32_IS_FIRST and QUIRK_LITTLE_ENDIAN are set, it looks like
  94. this:
  95. ::
  96. 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
  97. 0 1 2 3
  98. 39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56
  99. 4 5 6 7
  100. 8. If QUIRK_LSW32_IS_FIRST, QUIRK_LITTLE_ENDIAN and QUIRK_MSB_ON_THE_RIGHT
  101. are set, it looks like this:
  102. ::
  103. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
  104. 0 1 2 3
  105. 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
  106. 4 5 6 7
  107. We always think of our offsets as if there were no quirk, and we translate
  108. them afterwards, before accessing the memory region.
  109. Intended use
  110. ------------
  111. Drivers that opt to use this API first need to identify which of the above 3
  112. quirk combinations (for a total of 8) match what the hardware documentation
  113. describes. Then they should wrap the packing() function, creating a new
  114. xxx_packing() that calls it using the proper QUIRK_* one-hot bits set.
  115. The packing() function returns an int-encoded error code, which protects the
  116. programmer against incorrect API use. The errors are not expected to occur
  117. during runtime, therefore it is reasonable for xxx_packing() to return void
  118. and simply swallow those errors. Optionally it can dump stack or print the
  119. error description.