File Index
Files and directories
Sign in
FILE

cs_dsp_test_wmfw_error.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/cirrus/test/cs_dsp_test_wmfw_error.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2//
   3// KUnit tests for cs_dsp.
   4//
   5// Copyright (C) 2024 Cirrus Logic, Inc. and
   6//                    Cirrus Logic International Semiconductor Ltd.
   7//
   8
   9#include <kunit/device.h>
  10#include <kunit/resource.h>
  11#include <kunit/test.h>
  12#include <linux/build_bug.h>
  13#include <linux/firmware/cirrus/cs_dsp.h>
  14#include <linux/firmware/cirrus/cs_dsp_test_utils.h>
  15#include <linux/firmware/cirrus/wmfw.h>
  16#include <linux/random.h>
  17#include <linux/regmap.h>
  18#include <linux/string.h>
  19#include <linux/vmalloc.h>
  20
  21#include "../cs_dsp.h"
  22
  23KUNIT_DEFINE_ACTION_WRAPPER(_put_device_wrapper, put_device, struct device *);
  24KUNIT_DEFINE_ACTION_WRAPPER(_cs_dsp_remove_wrapper, cs_dsp_remove, struct cs_dsp *);
  25
  26struct cs_dsp_test_local {
  27	struct cs_dsp_mock_xm_header *xm_header;
  28	struct cs_dsp_mock_wmfw_builder *wmfw_builder;
  29	int wmfw_version;
  30};
  31
  32struct cs_dsp_wmfw_test_param {
  33	int block_type;
  34};
  35
  36static const struct cs_dsp_mock_alg_def cs_dsp_wmfw_err_test_mock_algs[] = {
  37	{
  38		.id = 0xfafa,
  39		.ver = 0x100000,
  40		.xm_size_words = 164,
  41		.ym_size_words = 164,
  42		.zm_size_words = 164,
  43	},
  44};
  45
  46static const struct cs_dsp_mock_coeff_def mock_coeff_template = {
  47	.shortname = "Dummy Coeff",
  48	.type = WMFW_CTL_TYPE_BYTES,
  49	.mem_type = WMFW_ADSP2_YM,
  50	.flags = WMFW_CTL_FLAG_VOLATILE,
  51	.length_bytes = 4,
  52};
  53
  54/* Load a wmfw containing unknown blocks. They should be skipped. */
  55static void wmfw_load_with_unknown_blocks(struct kunit *test)
  56{
  57	struct cs_dsp_test *priv = test->priv;
  58	struct cs_dsp_test_local *local = priv->local;
  59	struct firmware *wmfw;
  60	unsigned int reg_addr;
  61	u8 *payload_data, *readback;
  62	u8 random_data[8];
  63	const unsigned int payload_size_bytes = 64;
  64
  65	/* Add dummy XM header payload to wmfw */
  66	cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
  67					WMFW_ADSP2_XM, 0,
  68					local->xm_header->blob_data,
  69					local->xm_header->blob_size_bytes);
  70
  71	payload_data = kunit_kmalloc(test, payload_size_bytes, GFP_KERNEL);
  72	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, payload_data);
  73	get_random_bytes(payload_data, payload_size_bytes);
  74
  75	readback = kunit_kzalloc(test, payload_size_bytes, GFP_KERNEL);
  76	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, readback);
  77
  78	/* Add some unknown blocks at the start of the wmfw */
  79	get_random_bytes(random_data, sizeof(random_data));
  80	cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, 0xf5, 0,
  81				       random_data, sizeof(random_data));
  82	cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, 0xc0, 0, random_data,
  83				       sizeof(random_data));
  84	cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, 0x33, 0, NULL, 0);
  85
  86	/* Add a single payload to be written to DSP memory */
  87	cs_dsp_mock_wmfw_add_data_block(local->wmfw_builder,
  88					WMFW_ADSP2_YM, 0,
  89					payload_data, payload_size_bytes);
  90
  91	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
  92
  93	/* Sanity-check that the good wmfw loads ok */
  94	KUNIT_EXPECT_EQ(test,
  95			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
  96			0);
  97	cs_dsp_power_down(priv->dsp);
  98
  99	KUNIT_EXPECT_EQ(test,
 100			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 101			0);
 102
 103	/* Check that the payload was written to memory */
 104	reg_addr = cs_dsp_mock_base_addr_for_mem(priv, WMFW_ADSP2_YM);
 105	KUNIT_EXPECT_EQ(test,
 106			regmap_raw_read(priv->dsp->regmap, reg_addr, readback, payload_size_bytes),
 107			0);
 108	KUNIT_EXPECT_MEMEQ(test, readback, payload_data, payload_size_bytes);
 109}
 110
 111/* Load a wmfw that doesn't have a valid magic marker. */
 112static void wmfw_err_wrong_magic(struct kunit *test)
 113{
 114	struct cs_dsp_test *priv = test->priv;
 115	struct cs_dsp_test_local *local = priv->local;
 116	struct firmware *wmfw;
 117
 118	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 119
 120	/* Sanity-check that the good wmfw loads ok */
 121	KUNIT_EXPECT_EQ(test,
 122			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 123			0);
 124	cs_dsp_power_down(priv->dsp);
 125
 126	memcpy((void *)wmfw->data, "WMDR", 4);
 127	KUNIT_EXPECT_LT(test,
 128			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 129			0);
 130
 131	memcpy((void *)wmfw->data, "xMFW", 4);
 132	KUNIT_EXPECT_LT(test,
 133			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 134			0);
 135
 136	memcpy((void *)wmfw->data, "WxFW", 4);
 137	KUNIT_EXPECT_LT(test,
 138			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 139			0);
 140
 141	memcpy((void *)wmfw->data, "WMxW", 4);
 142	KUNIT_EXPECT_LT(test,
 143			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 144			0);
 145
 146	memcpy((void *)wmfw->data, "WMFx", 4);
 147	KUNIT_EXPECT_LT(test,
 148			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 149			0);
 150
 151	memset((void *)wmfw->data, 0, 4);
 152	KUNIT_EXPECT_LT(test,
 153			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 154			0);
 155}
 156
 157/* Load a wmfw that is too short for a valid header. */
 158static void wmfw_err_too_short_for_header(struct kunit *test)
 159{
 160	struct cs_dsp_test *priv = test->priv;
 161	struct cs_dsp_test_local *local = priv->local;
 162	struct firmware *wmfw;
 163
 164	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 165
 166	/* Sanity-check that the good wmfw loads ok */
 167	KUNIT_EXPECT_EQ(test,
 168			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 169			0);
 170	cs_dsp_power_down(priv->dsp);
 171
 172	do {
 173		wmfw->size--;
 174
 175		KUNIT_EXPECT_EQ(test,
 176				cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 177				-EOVERFLOW);
 178	} while (wmfw->size > 0);
 179}
 180
 181/* Header length field isn't a valid header length. */
 182static void wmfw_err_bad_header_length(struct kunit *test)
 183{
 184	struct cs_dsp_test *priv = test->priv;
 185	struct cs_dsp_test_local *local = priv->local;
 186	struct firmware *wmfw;
 187	struct wmfw_header *header;
 188	unsigned int real_len, len;
 189
 190	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 191
 192	/* Sanity-check that the good wmfw loads ok */
 193	KUNIT_EXPECT_EQ(test,
 194			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 195			0);
 196	cs_dsp_power_down(priv->dsp);
 197
 198	header = (struct wmfw_header *)wmfw->data;
 199	real_len = le32_to_cpu(header->len);
 200
 201	for (len = 0; len < real_len; len++) {
 202		header->len = cpu_to_le32(len);
 203		KUNIT_EXPECT_EQ(test,
 204				cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 205				-EOVERFLOW);
 206	}
 207
 208	for (len = real_len + 1; len < real_len + 7; len++) {
 209		header->len = cpu_to_le32(len);
 210		KUNIT_EXPECT_EQ(test,
 211				cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 212				-EOVERFLOW);
 213	}
 214
 215	header->len = cpu_to_le32(0xffffffff);
 216	KUNIT_EXPECT_EQ(test,
 217			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 218			-EOVERFLOW);
 219
 220	header->len = cpu_to_le32(0x80000000);
 221	KUNIT_EXPECT_EQ(test,
 222			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 223			-EOVERFLOW);
 224
 225	header->len = cpu_to_le32(0x7fffffff);
 226	KUNIT_EXPECT_EQ(test,
 227			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 228			-EOVERFLOW);
 229}
 230
 231/* Wrong core type in header. */
 232static void wmfw_err_bad_core_type(struct kunit *test)
 233{
 234	struct cs_dsp_test *priv = test->priv;
 235	struct cs_dsp_test_local *local = priv->local;
 236	struct firmware *wmfw;
 237	struct wmfw_header *header;
 238
 239	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 240
 241	/* Sanity-check that the good wmfw loads ok */
 242	KUNIT_EXPECT_EQ(test,
 243			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 244			0);
 245	cs_dsp_power_down(priv->dsp);
 246
 247	header = (struct wmfw_header *)wmfw->data;
 248
 249	header->core = 0;
 250	KUNIT_EXPECT_LT(test,
 251			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 252			0);
 253
 254	header->core = 1;
 255	KUNIT_EXPECT_LT(test,
 256			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 257			0);
 258
 259	header->core = priv->dsp->type + 1;
 260	KUNIT_EXPECT_LT(test,
 261			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 262			0);
 263
 264	header->core = 0xff;
 265	KUNIT_EXPECT_LT(test,
 266			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 267			0);
 268}
 269
 270/* File too short to contain a full block header */
 271static void wmfw_too_short_for_block_header(struct kunit *test)
 272{
 273	const struct cs_dsp_wmfw_test_param *param = test->param_value;
 274	struct cs_dsp_test *priv = test->priv;
 275	struct cs_dsp_test_local *local = priv->local;
 276	struct firmware *wmfw;
 277	unsigned int header_length;
 278	u32 dummy_payload = 0;
 279
 280	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 281	header_length = wmfw->size;
 282	kunit_kfree(test, wmfw);
 283
 284	/* Add the block. A block must have at least 4 bytes of payload */
 285	cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, param->block_type, 0,
 286				       &dummy_payload, sizeof(dummy_payload));
 287
 288	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 289	KUNIT_ASSERT_GT(test, wmfw->size, header_length);
 290
 291	/* Sanity-check that the good wmfw loads ok */
 292	KUNIT_EXPECT_EQ(test,
 293			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 294			0);
 295	cs_dsp_power_down(priv->dsp);
 296
 297	for (wmfw->size--; wmfw->size > header_length; wmfw->size--) {
 298		KUNIT_EXPECT_EQ(test,
 299				cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 300				-EOVERFLOW);
 301	}
 302}
 303
 304/* File too short to contain the block payload */
 305static void wmfw_too_short_for_block_payload(struct kunit *test)
 306{
 307	const struct cs_dsp_wmfw_test_param *param = test->param_value;
 308	struct cs_dsp_test *priv = test->priv;
 309	struct cs_dsp_test_local *local = priv->local;
 310	struct firmware *wmfw;
 311	static const u8 payload[256] = { };
 312	int i;
 313
 314	cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, param->block_type, 0,
 315				       payload, sizeof(payload));
 316
 317	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 318
 319	/* Sanity-check that the good wmfw loads ok */
 320	KUNIT_EXPECT_EQ(test,
 321			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 322			0);
 323	cs_dsp_power_down(priv->dsp);
 324
 325	for (i = 0; i < sizeof(payload); i++) {
 326		wmfw->size--;
 327		KUNIT_EXPECT_EQ(test,
 328				cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 329				-EOVERFLOW);
 330	}
 331}
 332
 333/* Block payload length is a garbage value */
 334static void wmfw_block_payload_len_garbage(struct kunit *test)
 335{
 336	const struct cs_dsp_wmfw_test_param *param = test->param_value;
 337	struct cs_dsp_test *priv = test->priv;
 338	struct cs_dsp_test_local *local = priv->local;
 339	struct firmware *wmfw;
 340	struct wmfw_header *header;
 341	struct wmfw_region *region;
 342	u32 payload = 0;
 343
 344
 345	cs_dsp_mock_wmfw_add_raw_block(local->wmfw_builder, param->block_type, 0,
 346				       &payload, sizeof(payload));
 347
 348	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 349
 350	/* Sanity-check that the good wmfw loads ok */
 351	KUNIT_EXPECT_EQ(test,
 352			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 353			0);
 354	cs_dsp_power_down(priv->dsp);
 355
 356	header = (struct wmfw_header *)wmfw->data;
 357	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 358
 359	/* Sanity check that we're looking at the correct part of the wmfw */
 360	KUNIT_ASSERT_EQ(test, le32_to_cpu(region->offset) >> 24, param->block_type);
 361	KUNIT_ASSERT_EQ(test, le32_to_cpu(region->len), sizeof(payload));
 362
 363	region->len = cpu_to_le32(0x8000);
 364	KUNIT_EXPECT_EQ(test,
 365			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 366			-EOVERFLOW);
 367
 368	region->len = cpu_to_le32(0xffff);
 369	KUNIT_EXPECT_EQ(test,
 370			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 371			-EOVERFLOW);
 372
 373	region->len = cpu_to_le32(0x7fffffff);
 374	KUNIT_EXPECT_EQ(test,
 375			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 376			-EOVERFLOW);
 377
 378	region->len = cpu_to_le32(0x80000000);
 379	KUNIT_EXPECT_EQ(test,
 380			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 381			-EOVERFLOW);
 382
 383	region->len = cpu_to_le32(0xffffffff);
 384	KUNIT_EXPECT_EQ(test,
 385			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 386			-EOVERFLOW);
 387}
 388
 389/* File too short to contain an algorithm header */
 390static void wmfw_too_short_for_alg_header(struct kunit *test)
 391{
 392	struct cs_dsp_test *priv = test->priv;
 393	struct cs_dsp_test_local *local = priv->local;
 394	struct firmware *wmfw;
 395	unsigned int header_length;
 396
 397	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 398	header_length = wmfw->size;
 399	kunit_kfree(test, wmfw);
 400
 401	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 402					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 403					      NULL, NULL);
 404	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 405
 406	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 407	KUNIT_ASSERT_GT(test, wmfw->size, header_length);
 408
 409	/* Sanity-check that the good wmfw loads ok */
 410	KUNIT_EXPECT_EQ(test,
 411			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 412			0);
 413	cs_dsp_power_down(priv->dsp);
 414
 415	for (wmfw->size--; wmfw->size > header_length; wmfw->size--) {
 416		KUNIT_EXPECT_EQ(test,
 417				cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 418				-EOVERFLOW);
 419	}
 420}
 421
 422/* V1 algorithm name does not have NUL terminator */
 423static void wmfw_v1_alg_name_unterminated(struct kunit *test)
 424{
 425	struct cs_dsp_test *priv = test->priv;
 426	struct cs_dsp_test_local *local = priv->local;
 427	struct firmware *wmfw;
 428	struct wmfw_header *header;
 429	struct wmfw_region *region;
 430	struct wmfw_adsp_alg_data *alg_data;
 431	struct cs_dsp_coeff_ctl *ctl;
 432
 433	/* Create alg info block with a coefficient */
 434	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 435					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 436					      "abc", "de");
 437	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 438	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 439
 440	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 441
 442	header = (struct wmfw_header *)wmfw->data;
 443	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 444	alg_data = (struct wmfw_adsp_alg_data *)region->data;
 445
 446	/* Sanity check we're pointing at the alg header */
 447	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data->id), cs_dsp_wmfw_err_test_mock_algs[0].id);
 448
 449	/* Write a string to the alg name that overflows the array */
 450	memset(alg_data->descr, 0, sizeof(alg_data->descr));
 451	memset(alg_data->name, 'A', sizeof(alg_data->name));
 452	memset(alg_data->descr, 'A', sizeof(alg_data->descr) - 1);
 453
 454	/*
 455	 * Sanity-check that a strlen would overflow alg_data->name.
 456	 * FORTIFY_STRING obstructs testing what strlen() would actually
 457	 * return, so instead verify that a strnlen() returns
 458	 * sizeof(alg_data->name[]), therefore it doesn't have a NUL.
 459	 */
 460	KUNIT_ASSERT_EQ(test, strnlen(alg_data->name, sizeof(alg_data->name)),
 461			sizeof(alg_data->name));
 462
 463	/*
 464	 * The alg name isn't stored, but cs_dsp parses the name field.
 465	 * It should load the file successfully and create the control.
 466	 * If FORTIFY_STRING is enabled it will detect a buffer overflow
 467	 * if cs_dsp string length walks past end of alg name array.
 468	 */
 469	KUNIT_EXPECT_EQ(test,
 470			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 471			0);
 472	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
 473	KUNIT_ASSERT_NOT_NULL(test, ctl);
 474	KUNIT_EXPECT_EQ(test, ctl->subname_len, 0);
 475}
 476
 477/* V2+ algorithm name exceeds length of containing block */
 478static void wmfw_v2_alg_name_exceeds_block(struct kunit *test)
 479{
 480	struct cs_dsp_test *priv = test->priv;
 481	struct cs_dsp_test_local *local = priv->local;
 482	struct firmware *wmfw;
 483	struct wmfw_header *header;
 484	struct wmfw_region *region;
 485	__le32 *alg_data;
 486
 487	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 488					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 489					      "abc", NULL);
 490	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 491
 492	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 493
 494	/* Sanity-check that the good wmfw loads ok */
 495	KUNIT_EXPECT_EQ(test,
 496			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 497			0);
 498	cs_dsp_power_down(priv->dsp);
 499
 500	header = (struct wmfw_header *)wmfw->data;
 501	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 502	alg_data = (__force __le32 *)region->data;
 503
 504	/*
 505	 * Sanity check we're pointing at the alg header of
 506	 *   [     alg_id       ][name_len]abc
 507	 */
 508	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
 509	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[1]), 3 | ('a' << 8) | ('b' << 16) | ('c' << 24));
 510	KUNIT_ASSERT_EQ(test, *(u8 *)&alg_data[1], 3);
 511
 512	/* Set name string length longer than available space */
 513	*(u8 *)&alg_data[1] = 4;
 514	KUNIT_EXPECT_EQ(test,
 515			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 516			-EOVERFLOW);
 517
 518	*(u8 *)&alg_data[1] = 7;
 519	KUNIT_EXPECT_EQ(test,
 520			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 521			-EOVERFLOW);
 522
 523	*(u8 *)&alg_data[1] = 0x80;
 524	KUNIT_EXPECT_EQ(test,
 525			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 526			-EOVERFLOW);
 527
 528	*(u8 *)&alg_data[1] = 0xff;
 529	KUNIT_EXPECT_EQ(test,
 530			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 531			-EOVERFLOW);
 532}
 533
 534/* V2+ algorithm description exceeds length of containing block */
 535static void wmfw_v2_alg_description_exceeds_block(struct kunit *test)
 536{
 537	struct cs_dsp_test *priv = test->priv;
 538	struct cs_dsp_test_local *local = priv->local;
 539	struct firmware *wmfw;
 540	struct wmfw_header *header;
 541	struct wmfw_region *region;
 542	__le32 *alg_data;
 543
 544	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 545					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 546					      "abc", "de");
 547	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 548
 549	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 550
 551	/* Sanity-check that the good wmfw loads ok */
 552	KUNIT_EXPECT_EQ(test,
 553			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 554			0);
 555	cs_dsp_power_down(priv->dsp);
 556
 557	header = (struct wmfw_header *)wmfw->data;
 558	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 559	alg_data = (__force __le32 *)region->data;
 560
 561	/*
 562	 * Sanity check we're pointing at the alg header of
 563	 *   [     alg_id       ][name_len]abc[desc_len]de
 564	 */
 565	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
 566	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[2]), 2 | ('d' << 16) | ('e' << 24));
 567	KUNIT_ASSERT_EQ(test, le16_to_cpu(*(__le16 *)&alg_data[2]), 2);
 568
 569	/* Set name string length longer than available space */
 570	*(__le16 *)&alg_data[2] = cpu_to_le16(4);
 571	KUNIT_EXPECT_EQ(test,
 572			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 573			-EOVERFLOW);
 574
 575	*(__le16 *)&alg_data[2] = cpu_to_le16(7);
 576	KUNIT_EXPECT_EQ(test,
 577			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 578			-EOVERFLOW);
 579
 580	*(__le16 *)&alg_data[2] = cpu_to_le16(0x80);
 581	KUNIT_EXPECT_EQ(test,
 582			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 583			-EOVERFLOW);
 584
 585	*(__le16 *)&alg_data[2] = cpu_to_le16(0xff);
 586	KUNIT_EXPECT_EQ(test,
 587			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 588			-EOVERFLOW);
 589
 590	*(__le16 *)&alg_data[2] = cpu_to_le16(0x8000);
 591	KUNIT_EXPECT_EQ(test,
 592			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 593			-EOVERFLOW);
 594
 595	*(__le16 *)&alg_data[2] = cpu_to_le16(0xffff);
 596	KUNIT_EXPECT_EQ(test,
 597			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 598			-EOVERFLOW);
 599}
 600
 601/* V1 coefficient count exceeds length of containing block */
 602static void wmfw_v1_coeff_count_exceeds_block(struct kunit *test)
 603{
 604	struct cs_dsp_test *priv = test->priv;
 605	struct cs_dsp_test_local *local = priv->local;
 606	struct firmware *wmfw;
 607	struct wmfw_header *header;
 608	struct wmfw_region *region;
 609	struct wmfw_adsp_alg_data *alg_data;
 610
 611	/* Create alg info block with a coefficient */
 612	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 613					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 614					      "abc", "de");
 615	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 616	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 617
 618	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 619
 620	/* Sanity-check that the good wmfw loads ok */
 621	KUNIT_EXPECT_EQ(test,
 622			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 623			0);
 624	cs_dsp_power_down(priv->dsp);
 625
 626	header = (struct wmfw_header *)wmfw->data;
 627	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 628	alg_data = (struct wmfw_adsp_alg_data *)region->data;
 629
 630	/* Sanity check we're pointing at the alg header */
 631	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data->id), cs_dsp_wmfw_err_test_mock_algs[0].id);
 632
 633	/* Add one to the coefficient count */
 634	alg_data->ncoeff = cpu_to_le32(le32_to_cpu(alg_data->ncoeff) + 1);
 635	KUNIT_EXPECT_EQ(test,
 636			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 637			-EOVERFLOW);
 638
 639	/* Make the coefficient count garbage */
 640	alg_data->ncoeff = cpu_to_le32(0xffffffff);
 641	KUNIT_EXPECT_EQ(test,
 642			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 643			-EOVERFLOW);
 644
 645	alg_data->ncoeff = cpu_to_le32(0x7fffffff);
 646	KUNIT_EXPECT_EQ(test,
 647			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 648			-EOVERFLOW);
 649
 650	alg_data->ncoeff = cpu_to_le32(0x80000000);
 651	KUNIT_EXPECT_EQ(test,
 652			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 653			-EOVERFLOW);
 654}
 655
 656/* V2+ coefficient count exceeds length of containing block */
 657static void wmfw_v2_coeff_count_exceeds_block(struct kunit *test)
 658{
 659	struct cs_dsp_test *priv = test->priv;
 660	struct cs_dsp_test_local *local = priv->local;
 661	struct firmware *wmfw;
 662	struct wmfw_header *header;
 663	struct wmfw_region *region;
 664	__le32 *alg_data, *ncoeff;
 665
 666	/* Create alg info block with a coefficient */
 667	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 668					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 669					      "abc", "de");
 670	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 671	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 672
 673	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 674
 675	/* Sanity-check that the good wmfw loads ok */
 676	KUNIT_EXPECT_EQ(test,
 677			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 678			0);
 679	cs_dsp_power_down(priv->dsp);
 680
 681	header = (struct wmfw_header *)wmfw->data;
 682	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 683	alg_data = (__force __le32 *)region->data;
 684
 685	/* Sanity check we're pointing at the alg header */
 686	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
 687
 688	ncoeff = (__force __le32 *)&alg_data[3];
 689	KUNIT_ASSERT_EQ(test, le32_to_cpu(*ncoeff), 1);
 690
 691	/* Add one to the coefficient count */
 692	*ncoeff = cpu_to_le32(2);
 693	KUNIT_EXPECT_EQ(test,
 694			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 695			-EOVERFLOW);
 696
 697	/* Make the coefficient count garbage */
 698	*ncoeff = cpu_to_le32(0xffffffff);
 699	KUNIT_EXPECT_EQ(test,
 700			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 701			-EOVERFLOW);
 702
 703	*ncoeff = cpu_to_le32(0x7fffffff);
 704	KUNIT_EXPECT_EQ(test,
 705			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 706			-EOVERFLOW);
 707
 708	*ncoeff = cpu_to_le32(0x80000000);
 709	KUNIT_EXPECT_EQ(test,
 710			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 711			-EOVERFLOW);
 712}
 713
 714/* V2+ coefficient block size exceeds length of containing block */
 715static void wmfw_v2_coeff_block_size_exceeds_block(struct kunit *test)
 716{
 717	struct cs_dsp_test *priv = test->priv;
 718	struct cs_dsp_test_local *local = priv->local;
 719	struct firmware *wmfw;
 720	struct wmfw_header *header;
 721	struct wmfw_region *region;
 722	__le32 *alg_data, *coeff;
 723
 724	/* Create alg info block with a coefficient */
 725	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 726					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 727					      "abc", "de");
 728	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 729	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 730
 731	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 732
 733	/* Sanity-check that the good wmfw loads ok */
 734	KUNIT_EXPECT_EQ(test,
 735			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 736			0);
 737	cs_dsp_power_down(priv->dsp);
 738
 739	header = (struct wmfw_header *)wmfw->data;
 740	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 741	alg_data = (__force __le32 *)region->data;
 742
 743	/* Sanity check we're pointing at the alg header */
 744	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
 745
 746	/* Sanity check we're pointing at the coeff block */
 747	coeff = (__force __le32 *)&alg_data[4];
 748	KUNIT_ASSERT_EQ(test, le32_to_cpu(coeff[0]), mock_coeff_template.mem_type << 16);
 749
 750	/* Add one to the block size */
 751	coeff[1] = cpu_to_le32(le32_to_cpu(coeff[1]) + 1);
 752	KUNIT_EXPECT_EQ(test,
 753			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 754			-EOVERFLOW);
 755
 756	/* Make the block size garbage */
 757	coeff[1] = cpu_to_le32(0xffffffff);
 758	KUNIT_EXPECT_EQ(test,
 759			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 760			-EOVERFLOW);
 761
 762	coeff[1] = cpu_to_le32(0x7fffffff);
 763	KUNIT_EXPECT_EQ(test,
 764			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 765			-EOVERFLOW);
 766
 767	coeff[1] = cpu_to_le32(0x80000000);
 768	KUNIT_EXPECT_EQ(test,
 769			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 770			-EOVERFLOW);
 771}
 772
 773/* V1 coeff name does not have NUL terminator */
 774static void wmfw_v1_coeff_name_unterminated(struct kunit *test)
 775{
 776	struct cs_dsp_test *priv = test->priv;
 777	struct cs_dsp_test_local *local = priv->local;
 778	struct firmware *wmfw;
 779	struct wmfw_header *header;
 780	struct wmfw_region *region;
 781	struct wmfw_adsp_alg_data *alg_data;
 782	struct wmfw_adsp_coeff_data *coeff;
 783	struct cs_dsp_coeff_ctl *ctl;
 784
 785	/* Create alg info block with a coefficient */
 786	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 787					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 788					      "abc", "de");
 789	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 790	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 791
 792	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 793
 794	header = (struct wmfw_header *)wmfw->data;
 795	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 796	alg_data = (struct wmfw_adsp_alg_data *)region->data;
 797
 798	/* Sanity check we're pointing at the alg header */
 799	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data->id), cs_dsp_wmfw_err_test_mock_algs[0].id);
 800	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data->ncoeff), 1);
 801
 802	coeff = (void *)alg_data->data;
 803
 804	/* Write a string to the coeff name that overflows the array */
 805	memset(coeff->descr, 0, sizeof(coeff->descr));
 806	memset(coeff->name, 'A', sizeof(coeff->name));
 807	memset(coeff->descr, 'A', sizeof(coeff->descr) - 1);
 808
 809	/*
 810	 * Sanity-check that a strlen would overflow coeff->name.
 811	 * FORTIFY_STRING obstructs testing what strlen() would actually
 812	 * return, so instead verify that a strnlen() returns
 813	 * sizeof(coeff->name[]), therefore it doesn't have a NUL.
 814	 */
 815	KUNIT_ASSERT_EQ(test, strnlen(coeff->name, sizeof(coeff->name)),
 816			sizeof(coeff->name));
 817
 818	/*
 819	 * V1 controls do not have names, but cs_dsp parses the name
 820	 * field. It should load the file successfully and create the
 821	 * control.
 822	 * If FORTIFY_STRING is enabled it will detect a buffer overflow
 823	 * if cs_dsp string length walks past end of coeff name array.
 824	 */
 825	KUNIT_EXPECT_EQ(test,
 826			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 827			0);
 828	ctl = list_first_entry_or_null(&priv->dsp->ctl_list, struct cs_dsp_coeff_ctl, list);
 829	KUNIT_ASSERT_NOT_NULL(test, ctl);
 830	KUNIT_EXPECT_EQ(test, ctl->subname_len, 0);
 831}
 832
 833/* V2+ coefficient shortname exceeds length of coeff block */
 834static void wmfw_v2_coeff_shortname_exceeds_block(struct kunit *test)
 835{
 836	struct cs_dsp_test *priv = test->priv;
 837	struct cs_dsp_test_local *local = priv->local;
 838	struct firmware *wmfw;
 839	struct wmfw_header *header;
 840	struct wmfw_region *region;
 841	__le32 *alg_data, *coeff;
 842
 843	/* Create alg info block with a coefficient */
 844	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 845					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 846					      "abc", "de");
 847	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 848	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 849
 850	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 851
 852	/* Sanity-check that the good wmfw loads ok */
 853	KUNIT_EXPECT_EQ(test,
 854			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 855			0);
 856	cs_dsp_power_down(priv->dsp);
 857
 858	header = (struct wmfw_header *)wmfw->data;
 859	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 860	alg_data = (__force __le32 *)region->data;
 861
 862	/* Sanity check we're pointing at the alg header */
 863	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
 864
 865	/* Sanity check we're pointing at the coeff block */
 866	coeff = (__force __le32 *)&alg_data[4];
 867	KUNIT_ASSERT_EQ(test, le32_to_cpu(coeff[0]), mock_coeff_template.mem_type << 16);
 868
 869	/* Add one to the shortname length */
 870	coeff[2] = cpu_to_le32(le32_to_cpu(coeff[2]) + 1);
 871	KUNIT_EXPECT_EQ(test,
 872			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 873			-EOVERFLOW);
 874
 875	/* Maximum shortname length */
 876	coeff[2] = cpu_to_le32(255);
 877	KUNIT_EXPECT_EQ(test,
 878			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 879			-EOVERFLOW);
 880}
 881
 882/* V2+ coefficient fullname exceeds length of coeff block */
 883static void wmfw_v2_coeff_fullname_exceeds_block(struct kunit *test)
 884{
 885	struct cs_dsp_test *priv = test->priv;
 886	struct cs_dsp_test_local *local = priv->local;
 887	struct firmware *wmfw;
 888	struct wmfw_header *header;
 889	struct wmfw_region *region;
 890	__le32 *alg_data, *coeff, *fullname;
 891	size_t shortlen;
 892
 893	/* Create alg info block with a coefficient */
 894	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 895					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 896					      "abc", "de");
 897	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 898	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 899
 900	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 901
 902	/* Sanity-check that the good wmfw loads ok */
 903	KUNIT_EXPECT_EQ(test,
 904			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 905			0);
 906	cs_dsp_power_down(priv->dsp);
 907
 908	header = (struct wmfw_header *)wmfw->data;
 909	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 910	alg_data = (__force __le32 *)region->data;
 911
 912	/* Sanity check we're pointing at the alg header */
 913	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
 914
 915	/* Sanity check we're pointing at the coeff block */
 916	coeff = (__force __le32 *)&alg_data[4];
 917	KUNIT_ASSERT_EQ(test, le32_to_cpu(coeff[0]), mock_coeff_template.mem_type << 16);
 918
 919	/* Fullname follows the shortname rounded up to a __le32 boundary */
 920	shortlen = round_up(le32_to_cpu(coeff[2]) & 0xff, sizeof(__le32));
 921	fullname = &coeff[2] + (shortlen / sizeof(*coeff));
 922
 923	/* Fullname increases in blocks of __le32 so increase past the current __le32 */
 924	fullname[0] = cpu_to_le32(round_up(le32_to_cpu(fullname[0]) + 1, sizeof(__le32)));
 925	KUNIT_EXPECT_EQ(test,
 926			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 927			-EOVERFLOW);
 928
 929	/* Maximum fullname length */
 930	fullname[0] = cpu_to_le32(255);
 931	KUNIT_EXPECT_EQ(test,
 932			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 933			-EOVERFLOW);
 934}
 935
 936/* V2+ coefficient description exceeds length of coeff block */
 937static void wmfw_v2_coeff_description_exceeds_block(struct kunit *test)
 938{
 939	struct cs_dsp_test *priv = test->priv;
 940	struct cs_dsp_test_local *local = priv->local;
 941	struct firmware *wmfw;
 942	struct wmfw_header *header;
 943	struct wmfw_region *region;
 944	__le32 *alg_data, *coeff, *fullname, *description;
 945	size_t namelen;
 946
 947	/* Create alg info block with a coefficient */
 948	cs_dsp_mock_wmfw_start_alg_info_block(local->wmfw_builder,
 949					      cs_dsp_wmfw_err_test_mock_algs[0].id,
 950					      "abc", "de");
 951	cs_dsp_mock_wmfw_add_coeff_desc(local->wmfw_builder, &mock_coeff_template);
 952	cs_dsp_mock_wmfw_end_alg_info_block(local->wmfw_builder);
 953
 954	wmfw = cs_dsp_mock_wmfw_get_firmware(local->wmfw_builder);
 955
 956	/* Sanity-check that the good wmfw loads ok */
 957	KUNIT_EXPECT_EQ(test,
 958			cs_dsp_power_up(priv->dsp, wmfw, "wmfw", NULL, NULL, "misc"),
 959			0);
 960	cs_dsp_power_down(priv->dsp);
 961
 962	header = (struct wmfw_header *)wmfw->data;
 963	region = (struct wmfw_region *)&wmfw->data[le32_to_cpu(header->len)];
 964	alg_data = (__force __le32 *)region->data;
 965
 966	/* Sanity check we're pointing at the alg header */
 967	KUNIT_ASSERT_EQ(test, le32_to_cpu(alg_data[0]), cs_dsp_wmfw_err_test_mock_algs[0].id);
 968
 969	/* Sanity check we're pointing at the coeff block */
 970	coeff = (__force __le32 *)&alg_data[4];
 971	KUNIT_ASSERT_EQ(test, le32_to_cpu(coeff[0]), mock_coeff_template.mem_type << 16);
 972
 973	/* Description follows the shortname and fullname rounded up to __le32 boundaries */
 974	namelen = round_up(le32_to_cpu(coeff[2]) & 0xff, sizeof(__le32));
 975	fullname = &coeff[2] + (namelen / sizeof(*coeff));
 976	namelen = round_up(le32_to_cpu(fullname[0]) & 0xff, sizeof(__le32));
 977	description = fullname + (namelen / sizeof(*fullname));
 978
 979	/* Description increases in blocks of __le32 so increase past the current __le32 */
 980	description[0] = cpu_to_le32(round_up(le32_to_cpu(fullname[0]) + 1, sizeof(__le32)));
 981	KUNIT_EXPECT_EQ(test,
 982			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 983			-EOVERFLOW);
 984
 985	/* Maximum description length */
 986	fullname[0] = cpu_to_le32(0xffff);
 987	KUNIT_EXPECT_EQ(test,
 988			cs_dsp_power_up(priv->dsp, wmfw, "mock_wmfw", NULL, NULL, "misc"),
 989			-EOVERFLOW);
 990}
 991
 992static void cs_dsp_wmfw_err_test_exit(struct kunit *test)
 993{
 994	cs_dsp_suppress_err_messages = false;
 995	cs_dsp_suppress_warn_messages = false;
 996	cs_dsp_suppress_info_messages = false;
 997}
 998
 999static int cs_dsp_wmfw_err_test_common_init(struct kunit *test, struct cs_dsp *dsp,
1000					    int wmfw_version)
1001{
1002	struct cs_dsp_test *priv;
1003	struct cs_dsp_test_local *local;
1004	struct device *test_dev;
1005	int ret;
1006
1007	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
1008	if (!priv)
1009		return -ENOMEM;
1010
1011	local = kunit_kzalloc(test, sizeof(struct cs_dsp_test_local), GFP_KERNEL);
1012	if (!local)
1013		return -ENOMEM;
1014
1015	priv->test = test;
1016	priv->dsp = dsp;
1017	test->priv = priv;
1018	priv->local = local;
1019	local->wmfw_version = wmfw_version;
1020
1021	/* Create dummy struct device */
1022	test_dev = kunit_device_register(test, "cs_dsp_test_drv");
1023	if (IS_ERR(test_dev))
1024		return PTR_ERR(test_dev);
1025
1026	dsp->dev = get_device(test_dev);
1027	if (!dsp->dev)
1028		return -ENODEV;
1029
1030	ret = kunit_add_action_or_reset(test, _put_device_wrapper, dsp->dev);
1031	if (ret)
1032		return ret;
1033
1034	dev_set_drvdata(dsp->dev, priv);
1035
1036	/* Allocate regmap */
1037	ret = cs_dsp_mock_regmap_init(priv);
1038	if (ret)
1039		return ret;
1040
1041	/*
1042	 * There must always be a XM header with at least 1 algorithm,
1043	 * so create a dummy one and pre-populate XM so the wmfw doesn't
1044	 * have to contain an XM blob.
1045	 */
1046	local->xm_header = cs_dsp_create_mock_xm_header(priv,
1047							cs_dsp_wmfw_err_test_mock_algs,
1048							ARRAY_SIZE(cs_dsp_wmfw_err_test_mock_algs));
1049	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->xm_header);
1050	cs_dsp_mock_xm_header_write_to_regmap(local->xm_header);
1051
1052	local->wmfw_builder = cs_dsp_mock_wmfw_init(priv, local->wmfw_version);
1053	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, local->wmfw_builder);
1054
1055	/* Init cs_dsp */
1056	dsp->client_ops = kunit_kzalloc(test, sizeof(*dsp->client_ops), GFP_KERNEL);
1057	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dsp->client_ops);
1058
1059	switch (dsp->type) {
1060	case WMFW_ADSP2:
1061		ret = cs_dsp_adsp2_init(dsp);
1062		break;
1063	case WMFW_HALO:
1064		ret = cs_dsp_halo_init(dsp);
1065		break;
1066	default:
1067		KUNIT_FAIL(test, "Untested DSP type %d\n", dsp->type);
1068		return -EINVAL;
1069	}
1070
1071	if (ret)
1072		return ret;
1073
1074	/* Automatically call cs_dsp_remove() when test case ends */
1075	ret = kunit_add_action_or_reset(priv->test, _cs_dsp_remove_wrapper, dsp);
1076	if (ret)
1077		return ret;
1078
1079	/*
1080	 * Testing error conditions can produce a lot of log output
1081	 * from cs_dsp error messages, so suppress messages.
1082	 */
1083	cs_dsp_suppress_err_messages = true;
1084	cs_dsp_suppress_warn_messages = true;
1085	cs_dsp_suppress_info_messages = true;
1086
1087	return 0;
1088}
1089
1090static int cs_dsp_wmfw_err_test_halo_init(struct kunit *test)
1091{
1092	struct cs_dsp *dsp;
1093
1094	/* Fill in cs_dsp and initialize */
1095	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
1096	if (!dsp)
1097		return -ENOMEM;
1098
1099	dsp->num = 1;
1100	dsp->type = WMFW_HALO;
1101	dsp->mem = cs_dsp_mock_halo_dsp1_regions;
1102	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_halo_dsp1_region_sizes);
1103	dsp->base = cs_dsp_mock_halo_core_base;
1104	dsp->base_sysinfo = cs_dsp_mock_halo_sysinfo_base;
1105
1106	return cs_dsp_wmfw_err_test_common_init(test, dsp, 3);
1107}
1108
1109static int cs_dsp_wmfw_err_test_adsp2_32bit_init(struct kunit *test, int wmfw_ver)
1110{
1111	struct cs_dsp *dsp;
1112
1113	/* Fill in cs_dsp and initialize */
1114	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
1115	if (!dsp)
1116		return -ENOMEM;
1117
1118	dsp->num = 1;
1119	dsp->type = WMFW_ADSP2;
1120	dsp->rev = 1;
1121	dsp->mem = cs_dsp_mock_adsp2_32bit_dsp1_regions;
1122	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_32bit_dsp1_region_sizes);
1123	dsp->base = cs_dsp_mock_adsp2_32bit_sysbase;
1124
1125	return cs_dsp_wmfw_err_test_common_init(test, dsp, wmfw_ver);
1126}
1127
1128static int cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0_init(struct kunit *test)
1129{
1130	return cs_dsp_wmfw_err_test_adsp2_32bit_init(test, 0);
1131}
1132
1133static int cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1_init(struct kunit *test)
1134{
1135	return cs_dsp_wmfw_err_test_adsp2_32bit_init(test, 1);
1136}
1137
1138static int cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2_init(struct kunit *test)
1139{
1140	return cs_dsp_wmfw_err_test_adsp2_32bit_init(test, 2);
1141}
1142
1143static int cs_dsp_wmfw_err_test_adsp2_16bit_init(struct kunit *test, int wmfw_ver)
1144{
1145	struct cs_dsp *dsp;
1146
1147	/* Fill in cs_dsp and initialize */
1148	dsp = kunit_kzalloc(test, sizeof(*dsp), GFP_KERNEL);
1149	if (!dsp)
1150		return -ENOMEM;
1151
1152	dsp->num = 1;
1153	dsp->type = WMFW_ADSP2;
1154	dsp->rev = 0;
1155	dsp->mem = cs_dsp_mock_adsp2_16bit_dsp1_regions;
1156	dsp->num_mems = cs_dsp_mock_count_regions(cs_dsp_mock_adsp2_16bit_dsp1_region_sizes);
1157	dsp->base = cs_dsp_mock_adsp2_16bit_sysbase;
1158
1159	return cs_dsp_wmfw_err_test_common_init(test, dsp, wmfw_ver);
1160}
1161
1162static int cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0_init(struct kunit *test)
1163{
1164	return cs_dsp_wmfw_err_test_adsp2_16bit_init(test, 0);
1165}
1166
1167static int cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1_init(struct kunit *test)
1168{
1169	return cs_dsp_wmfw_err_test_adsp2_16bit_init(test, 1);
1170}
1171
1172static int cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2_init(struct kunit *test)
1173{
1174	return cs_dsp_wmfw_err_test_adsp2_16bit_init(test, 2);
1175}
1176
1177static void cs_dsp_wmfw_err_block_types_desc(const struct cs_dsp_wmfw_test_param *param,
1178					     char *desc)
1179{
1180	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "block_type:%#x", param->block_type);
1181}
1182
1183static const struct cs_dsp_wmfw_test_param wmfw_valid_block_types_adsp2_cases[] = {
1184	{ .block_type = WMFW_INFO_TEXT },
1185	{ .block_type = WMFW_ADSP2_PM },
1186	{ .block_type = WMFW_ADSP2_YM },
1187};
1188
1189KUNIT_ARRAY_PARAM(wmfw_valid_block_types_adsp2,
1190		  wmfw_valid_block_types_adsp2_cases,
1191		  cs_dsp_wmfw_err_block_types_desc);
1192
1193static const struct cs_dsp_wmfw_test_param wmfw_valid_block_types_halo_cases[] = {
1194	{ .block_type = WMFW_INFO_TEXT },
1195	{ .block_type = WMFW_HALO_PM_PACKED },
1196	{ .block_type = WMFW_ADSP2_YM },
1197};
1198
1199KUNIT_ARRAY_PARAM(wmfw_valid_block_types_halo,
1200		  wmfw_valid_block_types_halo_cases,
1201		  cs_dsp_wmfw_err_block_types_desc);
1202
1203static const struct cs_dsp_wmfw_test_param wmfw_invalid_block_types_cases[] = {
1204	{ .block_type = 0x33 },
1205	{ .block_type = 0xf5 },
1206	{ .block_type = 0xc0 },
1207};
1208
1209KUNIT_ARRAY_PARAM(wmfw_invalid_block_types,
1210		  wmfw_invalid_block_types_cases,
1211		  cs_dsp_wmfw_err_block_types_desc);
1212
1213static struct kunit_case cs_dsp_wmfw_err_test_cases_v0[] = {
1214	KUNIT_CASE(wmfw_load_with_unknown_blocks),
1215	KUNIT_CASE(wmfw_err_wrong_magic),
1216	KUNIT_CASE(wmfw_err_too_short_for_header),
1217	KUNIT_CASE(wmfw_err_bad_header_length),
1218	KUNIT_CASE(wmfw_err_bad_core_type),
1219
1220	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_valid_block_types_adsp2_gen_params),
1221	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1222	KUNIT_CASE_PARAM(wmfw_too_short_for_block_payload, wmfw_valid_block_types_adsp2_gen_params),
1223	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1224	KUNIT_CASE_PARAM(wmfw_block_payload_len_garbage, wmfw_valid_block_types_adsp2_gen_params),
1225	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1226
1227	{ } /* terminator */
1228};
1229
1230static struct kunit_case cs_dsp_wmfw_err_test_cases_v1[] = {
1231	KUNIT_CASE(wmfw_load_with_unknown_blocks),
1232	KUNIT_CASE(wmfw_err_wrong_magic),
1233	KUNIT_CASE(wmfw_err_too_short_for_header),
1234	KUNIT_CASE(wmfw_err_bad_header_length),
1235	KUNIT_CASE(wmfw_err_bad_core_type),
1236
1237	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_valid_block_types_adsp2_gen_params),
1238	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1239	KUNIT_CASE_PARAM(wmfw_too_short_for_block_payload, wmfw_valid_block_types_adsp2_gen_params),
1240	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1241	KUNIT_CASE_PARAM(wmfw_block_payload_len_garbage, wmfw_valid_block_types_adsp2_gen_params),
1242	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1243
1244	KUNIT_CASE(wmfw_too_short_for_alg_header),
1245	KUNIT_CASE(wmfw_v1_alg_name_unterminated),
1246	KUNIT_CASE(wmfw_v1_coeff_count_exceeds_block),
1247	KUNIT_CASE(wmfw_v1_coeff_name_unterminated),
1248
1249	{ } /* terminator */
1250};
1251
1252static struct kunit_case cs_dsp_wmfw_err_test_cases_v2[] = {
1253	KUNIT_CASE(wmfw_load_with_unknown_blocks),
1254	KUNIT_CASE(wmfw_err_wrong_magic),
1255	KUNIT_CASE(wmfw_err_too_short_for_header),
1256	KUNIT_CASE(wmfw_err_bad_header_length),
1257	KUNIT_CASE(wmfw_err_bad_core_type),
1258
1259	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_valid_block_types_adsp2_gen_params),
1260	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1261	KUNIT_CASE_PARAM(wmfw_too_short_for_block_payload, wmfw_valid_block_types_adsp2_gen_params),
1262	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1263	KUNIT_CASE_PARAM(wmfw_block_payload_len_garbage, wmfw_valid_block_types_adsp2_gen_params),
1264	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1265
1266	KUNIT_CASE(wmfw_too_short_for_alg_header),
1267	KUNIT_CASE(wmfw_v2_alg_name_exceeds_block),
1268	KUNIT_CASE(wmfw_v2_alg_description_exceeds_block),
1269	KUNIT_CASE(wmfw_v2_coeff_count_exceeds_block),
1270	KUNIT_CASE(wmfw_v2_coeff_block_size_exceeds_block),
1271	KUNIT_CASE(wmfw_v2_coeff_shortname_exceeds_block),
1272	KUNIT_CASE(wmfw_v2_coeff_fullname_exceeds_block),
1273	KUNIT_CASE(wmfw_v2_coeff_description_exceeds_block),
1274
1275	{ } /* terminator */
1276};
1277
1278static struct kunit_case cs_dsp_wmfw_err_test_cases_v3[] = {
1279	KUNIT_CASE(wmfw_load_with_unknown_blocks),
1280	KUNIT_CASE(wmfw_err_wrong_magic),
1281	KUNIT_CASE(wmfw_err_too_short_for_header),
1282	KUNIT_CASE(wmfw_err_bad_header_length),
1283	KUNIT_CASE(wmfw_err_bad_core_type),
1284
1285	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_valid_block_types_halo_gen_params),
1286	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1287	KUNIT_CASE_PARAM(wmfw_too_short_for_block_payload, wmfw_valid_block_types_halo_gen_params),
1288	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1289	KUNIT_CASE_PARAM(wmfw_block_payload_len_garbage, wmfw_valid_block_types_halo_gen_params),
1290	KUNIT_CASE_PARAM(wmfw_too_short_for_block_header, wmfw_invalid_block_types_gen_params),
1291
1292	KUNIT_CASE(wmfw_too_short_for_alg_header),
1293	KUNIT_CASE(wmfw_v2_alg_name_exceeds_block),
1294	KUNIT_CASE(wmfw_v2_alg_description_exceeds_block),
1295	KUNIT_CASE(wmfw_v2_coeff_count_exceeds_block),
1296	KUNIT_CASE(wmfw_v2_coeff_block_size_exceeds_block),
1297	KUNIT_CASE(wmfw_v2_coeff_shortname_exceeds_block),
1298	KUNIT_CASE(wmfw_v2_coeff_fullname_exceeds_block),
1299	KUNIT_CASE(wmfw_v2_coeff_description_exceeds_block),
1300
1301	{ } /* terminator */
1302};
1303
1304static struct kunit_suite cs_dsp_wmfw_err_test_halo = {
1305	.name = "cs_dsp_wmfwV3_err_halo",
1306	.init = cs_dsp_wmfw_err_test_halo_init,
1307	.exit = cs_dsp_wmfw_err_test_exit,
1308	.test_cases = cs_dsp_wmfw_err_test_cases_v3,
1309};
1310
1311static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0 = {
1312	.name = "cs_dsp_wmfwV0_err_adsp2_32bit",
1313	.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0_init,
1314	.exit = cs_dsp_wmfw_err_test_exit,
1315	.test_cases = cs_dsp_wmfw_err_test_cases_v0,
1316};
1317
1318static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1 = {
1319	.name = "cs_dsp_wmfwV1_err_adsp2_32bit",
1320	.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1_init,
1321	.exit = cs_dsp_wmfw_err_test_exit,
1322	.test_cases = cs_dsp_wmfw_err_test_cases_v1,
1323};
1324
1325static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2 = {
1326	.name = "cs_dsp_wmfwV2_err_adsp2_32bit",
1327	.init = cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2_init,
1328	.exit = cs_dsp_wmfw_err_test_exit,
1329	.test_cases = cs_dsp_wmfw_err_test_cases_v2,
1330};
1331
1332static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0 = {
1333	.name = "cs_dsp_wmfwV0_err_adsp2_16bit",
1334	.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0_init,
1335	.exit = cs_dsp_wmfw_err_test_exit,
1336	.test_cases = cs_dsp_wmfw_err_test_cases_v0,
1337};
1338
1339static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1 = {
1340	.name = "cs_dsp_wmfwV1_err_adsp2_16bit",
1341	.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1_init,
1342	.exit = cs_dsp_wmfw_err_test_exit,
1343	.test_cases = cs_dsp_wmfw_err_test_cases_v1,
1344};
1345
1346static struct kunit_suite cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2 = {
1347	.name = "cs_dsp_wmfwV2_err_adsp2_16bit",
1348	.init = cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2_init,
1349	.exit = cs_dsp_wmfw_err_test_exit,
1350	.test_cases = cs_dsp_wmfw_err_test_cases_v2,
1351};
1352
1353kunit_test_suites(&cs_dsp_wmfw_err_test_halo,
1354		  &cs_dsp_wmfw_err_test_adsp2_32bit_wmfw0,
1355		  &cs_dsp_wmfw_err_test_adsp2_32bit_wmfw1,
1356		  &cs_dsp_wmfw_err_test_adsp2_32bit_wmfw2,
1357		  &cs_dsp_wmfw_err_test_adsp2_16bit_wmfw0,
1358		  &cs_dsp_wmfw_err_test_adsp2_16bit_wmfw1,
1359		  &cs_dsp_wmfw_err_test_adsp2_16bit_wmfw2);
~/ Read-only file preview.