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
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.