From: Vladimir Oltean <olteanv@gmail.com>
To: Uladzislau Koshchanka <koshchanka@gmail.com>
Cc: Dan Carpenter <error27@gmail.com>,
netdev@vger.kernel.org, kernel-janitors@vger.kernel.org
Subject: Re: [PATCH net] lib: packing: fix shift wrapping in bit_reverse()
Date: Fri, 9 Dec 2022 16:30:24 +0200 [thread overview]
Message-ID: <20221209143024.ad4cckonv4c3yhxd@skbuf> (raw)
In-Reply-To: <CAHktU2C00J7wY5uDbbScxwb0fD2kwUH+-=hgS5o_Timemh0Auw@mail.gmail.com>
Hi Uladzislau,
On Fri, Dec 09, 2022 at 11:21:21AM +0300, Uladzislau Koshchanka wrote:
> On Wed, 7 Dec 2022 at 14:30, Dan Carpenter <error27@gmail.com> wrote:
> >
> > The bit_reverse() function is clearly supposed to be able to handle
> > 64 bit values, but the types for "(1 << i)" and "bit << (width - i - 1)"
> > are not enough to handle more than 32 bits.
>
> It seems from the surrounding code that this function is only called
> for width of up to a byte (but correct me if I'm wrong).
This observation is quite true. I was quite lazy to look and remember
whether this is the case, but the comment says it quite clearly:
/* Bit indices into the currently accessed 8-bit box */
int box_start_bit, box_end_bit, box_addr;
> There are fast implementations of bit-reverse in include/linux/bitrev.h.
> It's better to just remove this function entirely and call bitrev8,
> which is just a precalc-table lookup. While at it, also sort includes.
The problem I see with bitrev8 is that the byte_rev_table[] can
seemingly be built as a module (the BITREVERSE Kconfig knob is tristate,
and btw your patch doesn't make PACKING select BITREVERSE). But PACKING
is bool. IIRC, I got comments during review that it's not worth making
packing a module, but I may remember wrong.
> @@ -49,7 +37,7 @@ static void adjust_for_msb_right_quirk(u64
> *to_write, int *box_start_bit,
> int new_box_start_bit, new_box_end_bit;
>
> *to_write >>= *box_end_bit;
> - *to_write = bit_reverse(*to_write, box_bit_width);
> + *to_write = bitrev8(*to_write) >> (8 - box_bit_width);
> *to_write <<= *box_end_bit;
>
> new_box_end_bit = box_bit_width - *box_start_bit - 1;
Anyway, the patch works in principle. I know this because I wrote the
following patch to check:
From 17099a86291713d2bcf8137473daea5f390a2ef4 Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <vladimir.oltean@nxp.com>
Date: Fri, 9 Dec 2022 16:23:35 +0200
Subject: [PATCH] lib: packing: add boot-time selftests
In case people want to make changes to the packing() implementation but
they aren't sure it's going to keep working, provide 16 boot-time calls
to packing() which exercise all combinations of quirks plus PACK |
UNPACK.
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
---
lib/Kconfig | 9 +++
lib/packing.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 195 insertions(+)
diff --git a/lib/Kconfig b/lib/Kconfig
index 9bbf8a4b2108..54b8deaf44fc 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -39,6 +39,15 @@ config PACKING
When in doubt, say N.
+config PACKING_SELFTESTS
+ bool "Selftests for packing library"
+ depends on PACKING
+ help
+ Boot-time selftests to make sure that the packing and unpacking
+ functions work properly.
+
+ When in doubt, say N.
+
config BITREVERSE
tristate
diff --git a/lib/packing.c b/lib/packing.c
index 9a72f4bbf0e2..aff70853b0c4 100644
--- a/lib/packing.c
+++ b/lib/packing.c
@@ -210,5 +210,191 @@ int packing(void *pbuf, u64 *uval, int startbit, int endbit, size_t pbuflen,
}
EXPORT_SYMBOL(packing);
+#if IS_ENABLED(CONFIG_PACKING_SELFTESTS)
+
+#define PBUF_LEN 16
+
+/* These selftests pack and unpack a magic 64-bit value (0xcafedeadbeefcafe) at
+ * a fixed logical offset (32) within an otherwise zero array of 128 bits
+ * (16 bytes). They test all possible bit layouts of the 128 bit buffer.
+ */
+static bool test_pack(u8 expected_pbuf[PBUF_LEN], u8 quirks)
+{
+ u64 uval = 0xcafedeadbeefcafe;
+ u8 pbuf[PBUF_LEN];
+ int err, i;
+
+ memset(pbuf, 0, PBUF_LEN);
+ err = packing(pbuf, &uval, 95, 32, PBUF_LEN, PACK, quirks);
+ if (err) {
+ pr_err("packing() returned %pe\n", ERR_PTR(err));
+ return false;
+ }
+
+ for (i = 0; i < PBUF_LEN; i++) {
+ if (pbuf[i] != expected_pbuf[i]) {
+ print_hex_dump(KERN_ERR, "pbuf: ", DUMP_PREFIX_NONE,
+ 16, 1, pbuf, PBUF_LEN, false);
+ print_hex_dump(KERN_ERR, "expected: ", DUMP_PREFIX_NONE,
+ 16, 1, expected_pbuf, PBUF_LEN, false);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool test_unpack(u8 pbuf[PBUF_LEN], u8 quirks)
+{
+ u64 uval, expected_uval = 0xcafedeadbeefcafe;
+ int err;
+
+ err = packing(pbuf, &uval, 95, 32, PBUF_LEN, UNPACK, quirks);
+ if (err) {
+ pr_err("packing() returned %pe\n", ERR_PTR(err));
+ return false;
+ }
+
+ if (uval != expected_uval) {
+ pr_err("uval: 0x%llx expected 0x%llx\n", uval, expected_uval);
+ return false;
+ }
+
+ return true;
+}
+
+static void test_no_quirks(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0xca, 0xfe, 0xde, 0xad,
+ 0xbe, 0xef, 0xca, 0xfe, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, 0);
+ pr_info("packing with no quirks: %s\n", ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, 0);
+ pr_info("unpacking with no quirks: %s\n", ret ? "OK" : "FAIL");
+}
+
+static void test_msb_right(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0x53, 0x7f, 0x7b, 0xb5,
+ 0x7d, 0xf7, 0x53, 0x7f, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("packing with QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("unpacking with QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+}
+
+static void test_le(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0xad, 0xde, 0xfe, 0xca,
+ 0xfe, 0xca, 0xef, 0xbe, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, QUIRK_LITTLE_ENDIAN);
+ pr_info("packing with QUIRK_LITTLE_ENDIAN: %s\n", ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, QUIRK_LITTLE_ENDIAN);
+ pr_info("unpacking with QUIRK_LITTLE_ENDIAN: %s\n",
+ ret ? "OK" : "FAIL");
+}
+
+static void test_le_msb_right(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0xb5, 0x7b, 0x7f, 0x53,
+ 0x7f, 0x53, 0xf7, 0x7d, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, QUIRK_LITTLE_ENDIAN | QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("packing with QUIRK_LITTLE_ENDIAN | QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, QUIRK_LITTLE_ENDIAN | QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("unpacking with QUIRK_LITTLE_ENDIAN | QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+}
+
+static void test_lsw32_first(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0xbe, 0xef, 0xca, 0xfe,
+ 0xca, 0xfe, 0xde, 0xad, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, QUIRK_LSW32_IS_FIRST);
+ pr_info("packing with QUIRK_LSW32_IS_FIRST: %s\n", ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, QUIRK_LSW32_IS_FIRST);
+ pr_info("unpacking with QUIRK_LSW32_IS_FIRST: %s\n", ret ? "OK" : "FAIL");
+}
+
+static void test_lsw32_first_msb_right(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0x7d, 0xf7, 0x53, 0x7f,
+ 0x53, 0x7f, 0x7b, 0xb5, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, QUIRK_LSW32_IS_FIRST | QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("packing with QUIRK_LSW32_IS_FIRST | QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, QUIRK_LSW32_IS_FIRST | QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("unpacking with QUIRK_LSW32_IS_FIRST | QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+}
+
+static void test_lsw32_first_le(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0xfe, 0xca, 0xef, 0xbe,
+ 0xad, 0xde, 0xfe, 0xca, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN);
+ pr_info("packing with QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN: %s\n",
+ ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN);
+ pr_info("unpacking with QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN: %s\n",
+ ret ? "OK" : "FAIL");
+}
+
+static void test_lsw32_first_le_msb_right(void)
+{
+ u8 pbuf[PBUF_LEN] = {0x00, 0x00, 0x00, 0x00, 0x7f, 0x53, 0xf7, 0x7d,
+ 0xb5, 0x7b, 0x7f, 0x53, 0x00, 0x00, 0x00, 0x00};
+ bool ret;
+
+ ret = test_pack(pbuf, QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN |
+ QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("packing with QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN | QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+
+ ret = test_unpack(pbuf, QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN |
+ QUIRK_MSB_ON_THE_RIGHT);
+ pr_info("unpacking with QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN | QUIRK_MSB_ON_THE_RIGHT: %s\n",
+ ret ? "OK" : "FAIL");
+}
+
+static int __init packing_init(void)
+{
+ test_no_quirks();
+ test_msb_right();
+ test_le();
+ test_le_msb_right();
+ test_lsw32_first();
+ test_lsw32_first_msb_right();
+ test_lsw32_first_le();
+ test_lsw32_first_le_msb_right();
+
+ return 0;
+}
+module_init(packing_init);
+#endif
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Generic bitfield packing and unpacking");
--
2.34.1
I've been meaning to do this for a while, but I'm not sure what is the
best way to integrate such a thing. Does anyone have any idea?
next prev parent reply other threads:[~2022-12-09 14:30 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-07 11:23 [PATCH net] lib: packing: fix shift wrapping in bit_reverse() Dan Carpenter
2022-12-07 12:19 ` Vladimir Oltean
2022-12-07 12:21 ` Dan Carpenter
2022-12-07 12:22 ` Vladimir Oltean
2022-12-07 12:51 ` Dan Carpenter
2022-12-07 13:06 ` Vladimir Oltean
2022-12-07 13:02 ` Vladimir Oltean
2022-12-07 19:41 ` David Laight
2022-12-08 16:58 ` Vladimir Oltean
2022-12-09 8:21 ` Uladzislau Koshchanka
2022-12-09 14:30 ` Vladimir Oltean [this message]
2022-12-09 21:01 ` Uladzislau Koshchanka
2022-12-09 22:06 ` Vladimir Oltean
2022-12-09 22:07 ` Vladimir Oltean
2022-12-10 0:44 ` [PATCH] lib: packing: replace bit_reverse() with bitrev8() Uladzislau Koshchanka
2022-12-12 23:04 ` Vladimir Oltean
2022-12-12 23:30 ` patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221209143024.ad4cckonv4c3yhxd@skbuf \
--to=olteanv@gmail.com \
--cc=error27@gmail.com \
--cc=kernel-janitors@vger.kernel.org \
--cc=koshchanka@gmail.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox