aboutsummaryrefslogtreecommitdiffstats
path: root/lib/packing.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/packing.c')
-rw-r--r--lib/packing.c70
1 files changed, 43 insertions, 27 deletions
diff --git a/lib/packing.c b/lib/packing.c
index 439125286d2b4e..435236a914fe65 100644
--- a/lib/packing.c
+++ b/lib/packing.c
@@ -9,27 +9,6 @@
#include <linux/types.h>
#include <linux/bitrev.h>
-static int get_le_offset(int offset)
-{
- int closest_multiple_of_4;
-
- closest_multiple_of_4 = (offset / 4) * 4;
- offset -= closest_multiple_of_4;
- return closest_multiple_of_4 + (3 - offset);
-}
-
-static int get_reverse_lsw32_offset(int offset, size_t len)
-{
- int closest_multiple_of_4;
- int word_index;
-
- word_index = offset / 4;
- closest_multiple_of_4 = word_index * 4;
- offset -= closest_multiple_of_4;
- word_index = (len / 4) - word_index - 1;
- return word_index * 4 + offset;
-}
-
static void adjust_for_msb_right_quirk(u64 *to_write, int *box_start_bit,
int *box_end_bit, u8 *box_mask)
{
@@ -48,6 +27,48 @@ static void adjust_for_msb_right_quirk(u64 *to_write, int *box_start_bit,
}
/**
+ * calculate_box_addr - Determine physical location of byte in buffer
+ * @box: Index of byte within buffer seen as a logical big-endian big number
+ * @len: Size of buffer in bytes
+ * @quirks: mask of QUIRK_LSW32_IS_FIRST and QUIRK_LITTLE_ENDIAN
+ *
+ * Function interprets the buffer as a @len byte sized big number, and returns
+ * the physical offset of the @box logical octet within it. Internally, it
+ * treats the big number as groups of 4 bytes. If @len is not a multiple of 4,
+ * the last group may be shorter.
+ *
+ * @QUIRK_LSW32_IS_FIRST gives the ordering of groups of 4 octets relative to
+ * each other. If set, the most significant group of 4 octets is last in the
+ * buffer (and may be truncated if @len is not a multiple of 4).
+ *
+ * @QUIRK_LITTLE_ENDIAN gives the ordering of bytes within each group of 4.
+ * If set, the most significant byte is last in the group. If @len takes the
+ * form of 4k+3, the last group will only be able to represent 24 bits, and its
+ * most significant octet is byte 2.
+ *
+ * Return: the physical offset into the buffer corresponding to the logical box.
+ */
+static int calculate_box_addr(int box, size_t len, u8 quirks)
+{
+ size_t offset_of_group, offset_in_group, this_group = box / 4;
+ size_t group_size;
+
+ if (quirks & QUIRK_LSW32_IS_FIRST)
+ offset_of_group = this_group * 4;
+ else
+ offset_of_group = len - ((this_group + 1) * 4);
+
+ group_size = min(4, len - offset_of_group);
+
+ if (quirks & QUIRK_LITTLE_ENDIAN)
+ offset_in_group = box - this_group * 4;
+ else
+ offset_in_group = group_size - (box - this_group * 4) - 1;
+
+ return offset_of_group + offset_in_group;
+}
+
+/**
* packing - Convert numbers (currently u64) between a packed and an unpacked
* format. Unpacked means laid out in memory in the CPU's native
* understanding of integers, while packed means anything else that
@@ -157,12 +178,7 @@ int packing(void *pbuf, u64 *uval, int startbit, int endbit, size_t pbuflen,
* effective addressing inside the pbuf (so it's not
* logical any longer).
*/
- box_addr = pbuflen - box - 1;
- if (quirks & QUIRK_LITTLE_ENDIAN)
- box_addr = get_le_offset(box_addr);
- if (quirks & QUIRK_LSW32_IS_FIRST)
- box_addr = get_reverse_lsw32_offset(box_addr,
- pbuflen);
+ box_addr = calculate_box_addr(box, pbuflen, quirks);
if (op == UNPACK) {
u64 pval;