// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2024, Vladimir Oltean <olteanv@gmail.com>
* Copyright (c) 2024, Intel Corporation.
*/
#include <kunit/test.h>
#include <linux/packing.h>
struct packing_test_case {
const char *desc;
const u8 *pbuf;
size_t pbuf_size;
u64 uval;
size_t start_bit;
size_t end_bit;
u8 quirks;
};
#define NO_QUIRKS 0
/**
* PBUF - Initialize .pbuf and .pbuf_size
* @array: elements of constant physical buffer
*
* Initializes the .pbuf and .pbuf_size fields of a struct packing_test_case
* with a constant array of the specified elements.
*/
#define PBUF(array...) \
.pbuf = (const u8[]){ array }, \
.pbuf_size = sizeof ((const u8 []){ array })
static const struct packing_test_case cases[] = {
/* These tests 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.
*/
{
.desc = "no quirks, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xca, 0 xfe, 0 xde, 0 xad,
0 xbe, 0 xef, 0 xca, 0 xfe, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = NO_QUIRKS,
},
{
.desc = "lsw32 first, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xbe, 0 xef, 0 xca, 0 xfe,
0 xca, 0 xfe, 0 xde, 0 xad, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LSW32_IS_FIRST,
},
{
.desc = "little endian words, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xad, 0 xde, 0 xfe, 0 xca,
0 xfe, 0 xca, 0 xef, 0 xbe, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LITTLE_ENDIAN,
},
{
.desc = "lsw32 first + little endian words, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xfe, 0 xca, 0 xef, 0 xbe,
0 xad, 0 xde, 0 xfe, 0 xca, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "msb right, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x53, 0 x7f, 0 x7b, 0 xb5,
0 x7d, 0 xf7, 0 x53, 0 x7f, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT,
},
{
.desc = "msb right + lsw32 first, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x7d, 0 xf7, 0 x53, 0 x7f,
0 x53, 0 x7f, 0 x7b, 0 xb5, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LSW32_IS_FIRST,
},
{
.desc = "msb right + little endian words, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xb5, 0 x7b, 0 x7f, 0 x53,
0 x7f, 0 x53, 0 xf7, 0 x7d, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "msb right + lsw32 first + little endian words, 16 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x7f, 0 x53, 0 xf7, 0 x7d,
0 xb5, 0 x7b, 0 x7f, 0 x53, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
/* These tests pack and unpack a magic 64-bit value
* (0xcafedeadbeefcafe) at a fixed logical offset (32) within an
* otherwise zero array of varying size from 18 bytes to 24 bytes.
*/
{
.desc = "no quirks, 18 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 xca, 0 xfe,
0 xde, 0 xad, 0 xbe, 0 xef, 0 xca, 0 xfe, 0 x00, 0 x00,
0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = NO_QUIRKS,
},
{
.desc = "no quirks, 19 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 xca,
0 xfe, 0 xde, 0 xad, 0 xbe, 0 xef, 0 xca, 0 xfe, 0 x00,
0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = NO_QUIRKS,
},
{
.desc = "no quirks, 20 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00,
0 xca, 0 xfe, 0 xde, 0 xad, 0 xbe, 0 xef, 0 xca, 0 xfe,
0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = NO_QUIRKS,
},
{
.desc = "no quirks, 22 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00, 0 xca, 0 xfe, 0 xde, 0 xad, 0 xbe, 0 xef,
0 xca, 0 xfe, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = NO_QUIRKS,
},
{
.desc = "no quirks, 24 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00, 0 x00, 0 x00, 0 xca, 0 xfe, 0 xde, 0 xad,
0 xbe, 0 xef, 0 xca, 0 xfe, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = NO_QUIRKS,
},
{
.desc = "lsw32 first + little endian words, 18 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xfe, 0 xca, 0 xef, 0 xbe,
0 xad, 0 xde, 0 xfe, 0 xca, 0 x00, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "lsw32 first + little endian words, 19 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xfe, 0 xca, 0 xef, 0 xbe,
0 xad, 0 xde, 0 xfe, 0 xca, 0 x00, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "lsw32 first + little endian words, 20 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xfe, 0 xca, 0 xef, 0 xbe,
0 xad, 0 xde, 0 xfe, 0 xca, 0 x00, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "lsw32 first + little endian words, 22 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xfe, 0 xca, 0 xef, 0 xbe,
0 xad, 0 xde, 0 xfe, 0 xca, 0 x00, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "lsw32 first + little endian words, 24 bytes" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xfe, 0 xca, 0 xef, 0 xbe,
0 xad, 0 xde, 0 xfe, 0 xca, 0 x00, 0 x00, 0 x00, 0 x00,
0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xcafedeadbeefcafe,
.start_bit = 95 ,
.end_bit = 32 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
/* These tests pack and unpack a magic 64-bit value
* (0x1122334455667788) at an odd starting bit (43) within an
* otherwise zero array of 128 bits (16 bytes). They test all possible
* bit layouts of the 128 bit buffer.
*/
{
.desc = "no quirks, 16 bytes, non-aligned" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x89, 0 x11, 0 x9a, 0 x22, 0 xab,
0 x33, 0 xbc, 0 x40, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = NO_QUIRKS,
},
{
.desc = "lsw32 first, 16 bytes, non-aligned" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x33, 0 xbc, 0 x40, 0 x00,
0 x11, 0 x9a, 0 x22, 0 xab, 0 x00, 0 x00, 0 x00, 0 x89),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_LSW32_IS_FIRST,
},
{
.desc = "little endian words, 16 bytes, non-aligned" ,
PBUF(0 x89, 0 x00, 0 x00, 0 x00, 0 xab, 0 x22, 0 x9a, 0 x11,
0 x00, 0 x40, 0 xbc, 0 x33, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_LITTLE_ENDIAN,
},
{
.desc = "lsw32 first + little endian words, 16 bytes, non-aligned" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x40, 0 xbc, 0 x33,
0 xab, 0 x22, 0 x9a, 0 x11, 0 x89, 0 x00, 0 x00, 0 x00),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "msb right, 16 bytes, non-aligned" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x91, 0 x88, 0 x59, 0 x44, 0 xd5,
0 xcc, 0 x3d, 0 x02, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT,
},
{
.desc = "msb right + lsw32 first, 16 bytes, non-aligned" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xcc, 0 x3d, 0 x02, 0 x00,
0 x88, 0 x59, 0 x44, 0 xd5, 0 x00, 0 x00, 0 x00, 0 x91),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LSW32_IS_FIRST,
},
{
.desc = "msb right + little endian words, 16 bytes, non-aligned" ,
PBUF(0 x91, 0 x00, 0 x00, 0 x00, 0 xd5, 0 x44, 0 x59, 0 x88,
0 x00, 0 x02, 0 x3d, 0 xcc, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "msb right + lsw32 first + little endian words, 16 bytes, non-aligned" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x02, 0 x3d, 0 xcc,
0 xd5, 0 x44, 0 x59, 0 x88, 0 x91, 0 x00, 0 x00, 0 x00),
.uval = 0 x1122334455667788,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
/* These tests pack and unpack a u64 with all bits set
* (0xffffffffffffffff) at an odd starting bit (43) within an
* otherwise zero array of 128 bits (16 bytes). They test all possible
* bit layouts of the 128 bit buffer.
*/
{
.desc = "no quirks, 16 bytes, non-aligned, 0xff" ,
PBUF(0 x00, 0 x00, 0 x07, 0 xff, 0 xff, 0 xff, 0 xff, 0 xff,
0 xff, 0 xff, 0 xf8, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = NO_QUIRKS,
},
{
.desc = "lsw32 first, 16 bytes, non-aligned, 0xff" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xff, 0 xff, 0 xf8, 0 x00,
0 xff, 0 xff, 0 xff, 0 xff, 0 x00, 0 x00, 0 x07, 0 xff),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_LSW32_IS_FIRST,
},
{
.desc = "little endian words, 16 bytes, non-aligned, 0xff" ,
PBUF(0 xff, 0 x07, 0 x00, 0 x00, 0 xff, 0 xff, 0 xff, 0 xff,
0 x00, 0 xf8, 0 xff, 0 xff, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_LITTLE_ENDIAN,
},
{
.desc = "lsw32 first + little endian words, 16 bytes, non-aligned, 0xff" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 xf8, 0 xff, 0 xff,
0 xff, 0 xff, 0 xff, 0 xff, 0 xff, 0 x07, 0 x00, 0 x00),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "msb right, 16 bytes, non-aligned, 0xff" ,
PBUF(0 x00, 0 x00, 0 xe0, 0 xff, 0 xff, 0 xff, 0 xff, 0 xff,
0 xff, 0 xff, 0 x1f, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT,
},
{
.desc = "msb right + lsw32 first, 16 bytes, non-aligned, 0xff" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 xff, 0 xff, 0 x1f, 0 x00,
0 xff, 0 xff, 0 xff, 0 xff, 0 x00, 0 x00, 0 xe0, 0 xff),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LSW32_IS_FIRST,
},
{
.desc = "msb right + little endian words, 16 bytes, non-aligned, 0xff" ,
PBUF(0 xff, 0 xe0, 0 x00, 0 x00, 0 xff, 0 xff, 0 xff, 0 xff,
0 x00, 0 x1f, 0 xff, 0 xff, 0 x00, 0 x00, 0 x00, 0 x00),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LITTLE_ENDIAN,
},
{
.desc = "msb right + lsw32 first + little endian words, 16 bytes, non-aligned, 0xff" ,
PBUF(0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x1f, 0 xff, 0 xff,
0 xff, 0 xff, 0 xff, 0 xff, 0 xff, 0 xe0, 0 x00, 0 x00),
.uval = 0 xffffffffffffffff,
.start_bit = 106 ,
.end_bit = 43 ,
.quirks = QUIRK_MSB_ON_THE_RIGHT | QUIRK_LSW32_IS_FIRST | QUIRK_LITTLE_ENDIAN,
},
};
KUNIT_ARRAY_PARAM_DESC(packing, cases, desc);
static void packing_test_pack(struct kunit *test)
{
const struct packing_test_case *params = test->param_value;
u8 *pbuf;
int err;
pbuf = kunit_kzalloc(test, params->pbuf_size, GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, pbuf);
err = pack (pbuf, params->uval, params->start_bit, params->end_bit,
params->pbuf_size, params->quirks);
KUNIT_EXPECT_EQ_MSG(test, err, 0 , "pack() returned %pe\n" , ERR_PTR(err));
KUNIT_EXPECT_MEMEQ(test, pbuf, params->pbuf, params->pbuf_size);
}
static void packing_test_unpack(struct kunit *test)
{
const struct packing_test_case *params = test->param_value;
u64 uval;
int err;
err = unpack(params->pbuf, &uval, params->start_bit, params->end_bit,
params->pbuf_size, params->quirks);
KUNIT_EXPECT_EQ_MSG(test, err, 0 , "unpack() returned %pe\n" , ERR_PTR(err));
KUNIT_EXPECT_EQ(test, uval, params->uval);
}
#define PACKED_BUF_SIZE 8
typedef struct __packed { u8 buf[PACKED_BUF_SIZE]; } packed_buf_t;
struct test_data {
u32 field3;
u16 field2;
u16 field4;
u16 field6;
u8 field1;
u8 field5;
};
static const struct packed_field_u8 test_fields[] = {
PACKED_FIELD(63 , 61 , struct test_data, field1),
PACKED_FIELD(60 , 52 , struct test_data, field2),
PACKED_FIELD(51 , 28 , struct test_data, field3),
PACKED_FIELD(27 , 14 , struct test_data, field4),
PACKED_FIELD(13 , 9 , struct test_data, field5),
PACKED_FIELD(8 , 0 , struct test_data, field6),
};
static void packing_test_pack_fields(struct kunit *test)
{
const struct test_data data = {
.field1 = 0 x2,
.field2 = 0 x100,
.field3 = 0 xF00050,
.field4 = 0 x7D3,
.field5 = 0 x9,
.field6 = 0 x10B,
};
packed_buf_t expect = {
.buf = { 0 x50, 0 x0F, 0 x00, 0 x05, 0 x01, 0 xF4, 0 xD3, 0 x0B },
};
packed_buf_t buf = {};
pack_fields(&buf, sizeof (buf), &data, test_fields, 0 );
KUNIT_EXPECT_MEMEQ(test, &expect, &buf, sizeof (buf));
}
static void packing_test_unpack_fields(struct kunit *test)
{
const packed_buf_t buf = {
.buf = { 0 x17, 0 x28, 0 x10, 0 x19, 0 x3D, 0 xA9, 0 x07, 0 x9C },
};
struct test_data data = {};
unpack_fields(&buf, sizeof (buf), &data, test_fields, 0 );
KUNIT_EXPECT_EQ(test, 0 , data.field1);
KUNIT_EXPECT_EQ(test, 0 x172, data.field2);
KUNIT_EXPECT_EQ(test, 0 x810193, data.field3);
KUNIT_EXPECT_EQ(test, 0 x36A4, data.field4);
KUNIT_EXPECT_EQ(test, 0 x3, data.field5);
KUNIT_EXPECT_EQ(test, 0 x19C, data.field6);
}
static struct kunit_case packing_test_cases[] = {
KUNIT_CASE_PARAM(packing_test_pack, packing_gen_params),
KUNIT_CASE_PARAM(packing_test_unpack, packing_gen_params),
KUNIT_CASE(packing_test_pack_fields),
KUNIT_CASE(packing_test_unpack_fields),
{},
};
static struct kunit_suite packing_test_suite = {
.name = "packing" ,
.test_cases = packing_test_cases,
};
kunit_test_suite(packing_test_suite);
MODULE_LICENSE("GPL" );
MODULE_DESCRIPTION("KUnit tests for packing library" );
Messung V0.5 in Prozent C=95 H=92 G=93