/* Add some unknown blocks at the start of the wmfw */
get_random_bytes(random_data, sizeof(random_data));
cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, 0xf5, 0,
random_data, sizeof(random_data));
cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, 0xc0, 0, random_data, sizeof(random_data));
cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, 0x33, 0, NULL, 0);
/* Add a single payload to be written to DSP memory */
cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
WMFW_ADSP2_YM, 0,
payload_data, payload_size_bytes);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Check that the payload was written to memory */
reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM);
KUNIT_EXPECT_EQ(test,
regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes), 0);
KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);
}
/* Load a wmfw that doesn't have a valid magic marker. */ staticvoid wmfw_err_wrong_magic(struct kunit *test)
{ struct cs_dsp_test *priv = test->priv; struct cs_dsp_test_local *local = priv->local; struct firmware *wmfw;
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Load a wmfw that is too short for a valid header. */ staticvoid wmfw_err_too_short_for_header(struct kunit *test)
{ struct cs_dsp_test *priv = test->priv; struct cs_dsp_test_local *local = priv->local; struct firmware *wmfw;
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Add the block. A block must have at least 4 bytes of payload */
cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, param->block_type, 0,
&dummy_payload, sizeof(dummy_payload));
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
for (i = 0; i < sizeof(payload); i++) {
wmfw->size--;
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
-EOVERFLOW);
}
}
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
header = (struct wmfw_header *)wmfw->data;
region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
/* Sanity check that we're looking at the correct part of the wmfw */
KUNIT_ASSERT_EQ(test, le32_to_cpu(region->offset) >> 24, param->block_type);
KUNIT_ASSERT_EQ(test, le32_to_cpu(region->len), sizeof(payload));
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity check we're pointing at the alg header */
KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data->id), cs_dsp_wmfw_err_test_mock_algs[0].id);
/* Write a string to the alg name that overflows the array */
memset(alg_data->descr, 0, sizeof(alg_data->descr));
memset(alg_data->name, 'A', sizeof(alg_data->name));
memset(alg_data->descr, 'A', sizeof(alg_data->descr) - 1);
/*
* Sanity-check that a strlen would overflow alg_data->name.
* FORTIFY_STRING obstructs testing what strlen() would actually
* return, so instead verify that a strnlen() returns
* sizeof(alg_data->name[]), therefore it doesn't have a NUL.
*/
KUNIT_ASSERT_EQ(test, strnlen(alg_data->name, sizeof(alg_data->name)),
sizeof(alg_data->name));
/*
* The alg name isn't stored, but cs_dsp parses the name field.
* It should load the file successfully and create the control.
* If FORTIFY_STRING is enabled it will detect a buffer overflow
* if cs_dsp string length walks past end of alg name array.
*/
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), 0);
ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
KUNIT_ASSERT_NOT_NULL(test, ctl);
KUNIT_EXPECT_EQ(test, ctl->subname_len, 0);
}
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Set name string length longer than available space */
*(u8 *)&alg_data[1] = 4;
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
-EOVERFLOW);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Set name string length longer than available space */
*(__le16 *)&alg_data[2] = cpu_to_le16(4);
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
-EOVERFLOW);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity check we're pointing at the alg header */
KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data->id), cs_dsp_wmfw_err_test_mock_algs[0].id);
KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data->ncoeff), 1);
coeff = (void *)alg_data->data;
/* Write a string to the coeff name that overflows the array */
memset(coeff->descr, 0, sizeof(coeff->descr));
memset(coeff->name, 'A', sizeof(coeff->name));
memset(coeff->descr, 'A', sizeof(coeff->descr) - 1);
/*
* Sanity-check that a strlen would overflow coeff->name.
* FORTIFY_STRING obstructs testing what strlen() would actually
* return, so instead verify that a strnlen() returns
* sizeof(coeff->name[]), therefore it doesn't have a NUL.
*/
KUNIT_ASSERT_EQ(test, strnlen(coeff->name, sizeof(coeff->name)),
sizeof(coeff->name));
/*
* V1 controls do not have names, but cs_dsp parses the name
* field. It should load the file successfully and create the
* control.
* If FORTIFY_STRING is enabled it will detect a buffer overflow
* if cs_dsp string length walks past end of coeff name array.
*/
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"), 0);
ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
KUNIT_ASSERT_NOT_NULL(test, ctl);
KUNIT_EXPECT_EQ(test, ctl->subname_len, 0);
}
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity check we're pointing at the alg header */
KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
/* Sanity check we're pointing at the coeff block */
coeff = (__force __le32 *)&alg_data[4];
KUNIT_ASSERT_EQ(test, le32_to_cpu(coeff[0]), mock_coeff_template.mem_type << 16);
/* Fullname follows the shortname rounded up to a __le32 boundary */
shortlen = round_up(le32_to_cpu(coeff[2]) & 0xff, sizeof(__le32));
fullname = &coeff[2] + (shortlen / sizeof(*coeff));
/* Fullname increases in blocks of __le32 so increase past the current __le32 */
fullname[0] = cpu_to_le32(round_up(le32_to_cpu(fullname[0]) + 1, sizeof(__le32)));
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
-EOVERFLOW);
/* Sanity-check that the good wmfw loads ok */
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"), 0);
cs_dsp_power_down(priv->dsp);
/* Sanity check we're pointing at the alg header */
KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
/* Sanity check we're pointing at the coeff block */
coeff = (__force __le32 *)&alg_data[4];
KUNIT_ASSERT_EQ(test, le32_to_cpu(coeff[0]), mock_coeff_template.mem_type << 16);
/* Description follows the shortname and fullname rounded up to __le32 boundaries */
namelen = round_up(le32_to_cpu(coeff[2]) & 0xff, sizeof(__le32));
fullname = &coeff[2] + (namelen / sizeof(*coeff));
namelen = round_up(le32_to_cpu(fullname[0]) & 0xff, sizeof(__le32));
description = fullname + (namelen / sizeof(*fullname));
/* Description increases in blocks of __le32 so increase past the current __le32 */
description[0] = cpu_to_le32(round_up(le32_to_cpu(fullname[0]) + 1, sizeof(__le32)));
KUNIT_EXPECT_EQ(test,
cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
-EOVERFLOW);
static void cs_dsp_wmfw_err_test_exit(struct kunit *test)
{
/*
* Testing error conditions can produce a lot of log output
* from cs_dsp error messages, so rate limit the test cases.
*/
usleep_range(200, 500);
}
static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
int wmfw_version)
{
struct cs_dsp_test *priv;
struct cs_dsp_test_local *local;
struct device *test_dev;
int ret;
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
local = kunit_kzalloc(test, sizeof(struct cs_dsp_test_local), GFP_KERNEL);
if (!local)
return -ENOMEM;
dsp->dev = get_device(test_dev);
if (!dsp->dev)
return -ENODEV;
ret = kunit_add_action_or_reset(test, _put_device_wrapper, dsp->dev);
if (ret)
return ret;
dev_set_drvdata(dsp->dev, priv);
/* Allocate regmap */
ret = cs_dsp_mock_regmap_init(priv);
if (ret)
return ret;
/*
* There must always be a XM header with at least 1 algorithm,
* so create a dummy one and pre-populate XM so the wmfw doesn't
* have to contain an XM blob.
*/
local->xm_header = cs_dsp_create_mock_xm_header(priv,
cs_dsp_wmfw_err_test_mock_algs,
ARRAY_SIZE(cs_dsp_wmfw_err_test_mock_algs));
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->xm_header);
cs_dsp_mock_xm_header_write_to_regmap(local->xm_header);
switch (dsp->type) {
case WMFW_ADSP2:
ret = cs_dsp_adsp2_init(dsp);
break;
case WMFW_HALO:
ret = cs_dsp_halo_init(dsp);
break;
default:
KUNIT_FAIL(test, "Untested DSP type %d\n", dsp->type);
return -EINVAL;
}
if (ret)
return ret;
/* Automatically call cs_dsp_remove() when test case ends */
return kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
}
static int cs_dsp_wmfw_err_test_halo_init(struct kunit *test)
{
struct cs_dsp *dsp;
/* Fill in cs_dsp and initialize */
dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
if (!dsp)
return -ENOMEM;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.