1/* 2 * Copyright 2016, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(D61_BSD) 11 */ 12 13#include <autoconf.h> 14#ifdef CONFIG_REFOS_RUN_TESTS 15 16#include <stdlib.h> 17#include <string.h> 18#include "test_memserv.h" 19#include "../state.h" 20#include "../system/memserv/window.h" 21#include "../system/memserv/dataspace.h" 22#include "../system/memserv/ringbuffer.h" 23#include <refos/test.h> 24 25/* -------------------------------------- Window module test ------------------------------------ */ 26 27int 28test_window_list(void) 29{ 30 test_start("windows"); 31 struct w_list wlist; 32 w_init(&wlist); 33 int nWindowTest = W_MAX_WINDOWS / 2; 34 35 /* Spam allocate all the windows. */ 36 for (int i = 1; i < nWindowTest; i++) { 37 reservation_t tempr; 38 struct w_window* w = w_create_window(&wlist, 1024, -1, 0, NULL, tempr, true); 39 test_assert(w); 40 test_assert(w->wID == i); 41 test_assert(w->magic == W_MAGIC); 42 test_assert(w->size == 1024); 43 test_assert(w->clientOwnerPID == -1); 44 test_assert(w->mode == W_MODE_EMPTY); 45 struct w_window* w_ = w_get_window(&wlist, w->wID); 46 test_assert(w_ && w_->wID == i); 47 test_assert(w_ == w); 48 } 49 50 /* Free every second window. */ 51 for (int i = 1; i < nWindowTest; i+=2) { 52 int err = w_delete_window(&wlist, i); 53 test_assert(err == ESUCCESS); 54 } 55 56 /* Make sure every second window is no longer get-able. */ 57 for (int i = 1; i < nWindowTest; i++) { 58 struct w_window* w_ = w_get_window(&wlist, i); 59 if (i % 2) { 60 test_assert(w_ == NULL); 61 } else { 62 test_assert(w_ != NULL); 63 test_assert(w_->magic == W_MAGIC); 64 test_assert(w_->wID == i); 65 } 66 } 67 68 w_deinit(&wlist); 69 return test_success(); 70} 71 72 73int 74test_window_associations(void) 75{ 76 test_start("window associations"); 77 78 struct w_associated_windowlist aw; 79 w_associate_init(&aw); 80 81 w_associate(&aw, 4, 400, 10); 82 w_associate(&aw, 2, 200, 10); 83 w_associate(&aw, 3, 300, 10); 84 w_associate(&aw, 1, 100, 10); 85 w_associate(&aw, 5, 500, 10); 86 87#if REFOS_TEST_VERBOSE_PRINT 88 tvprintf("------- Unsorted window list \n"); 89 w_associate_print(&aw); 90 91 tvprintf("------- Sorted window list \n"); 92 w_associate_find(&aw, (vaddr_t) 0); 93 w_associate_print(&aw); 94#endif 95 96 /* Associate some windows, and test window conflict checking with icky window 97 boundary vaddr cases. */ 98 int testVaddr[] = {400, 401, 300, 301, 90, 110, 105, 500, 510, 505, 499, 200, 201}; 99 int expectedWinID[] = {4, 4, 3, 3, W_INVALID_WINID, W_INVALID_WINID, 1, 5, W_INVALID_WINID, 100 5, W_INVALID_WINID, 2, 2}; 101 int numTestVaddr = 13; 102 int foundWinID; 103 struct w_associated_window *foundWin = NULL; 104 for (int i = 0; i < numTestVaddr; i++) { 105 foundWin = w_associate_find(&aw, testVaddr[i]); 106 foundWinID = foundWin == NULL ? W_INVALID_WINID : foundWin->winID; 107 tvprintf("------- winID for vaddr %d: %d\n", testVaddr[i], foundWinID); 108 test_assert(foundWinID == expectedWinID[i]); 109 } 110 111 /* Test w_associate_check with icky window boundary vaddr cases. */ 112 int testWin[] = {100, 1, 201, 20, 210, 10, 490, 50, 0, 499}; 113 bool expectedCheckResult[] = {false, false, true, false, false}; 114 int numTestWin = 5; 115 for (int i = 0; i < numTestWin; i++) { 116 bool check = w_associate_check(&aw, testWin[i*2], testWin[i*2+1]); 117 tvprintf("------- check for window [%d -> %d], %d\n", testWin[i*2], 118 testWin[i*2] + testWin[i*2+1], check); 119 test_assert(check == expectedCheckResult[i]); 120 } 121 122 /* Test w_associate_find_range with icky window boundary cases. */ 123 int testRange[] = {100, 1, 201, 20, 210, 10, 490, 50, 0, 499, 500, 10, 305, 5}; 124 int expectedFindRangeResult[] = {1, W_INVALID_WINID, W_INVALID_WINID, W_INVALID_WINID, W_INVALID_WINID, 125 5, 3}; 126 int numTestRange = 7; 127 for (int i = 0; i < numTestRange; i++) { 128 foundWin = w_associate_find_range(&aw, testRange[i*2], testRange[i*2+1]); 129 foundWinID = foundWin == NULL ? W_INVALID_WINID : foundWin->winID; 130 tvprintf("------- check range for window [%d -> %d], %d (expected to be %d)\n", 131 testRange[i*2], testRange[i*2] + testRange[i*2+1], 132 foundWinID, expectedFindRangeResult[i]); 133 test_assert(foundWinID == expectedFindRangeResult[i]); 134 } 135 136 /* Test that clearing window association list actually clears. */ 137 w_associate_clear(&aw); 138 for (int i = 0; i < numTestWin; i++) { 139 bool check = w_associate_check(&aw, testWin[i*2], testWin[i*2+1]); 140 test_assert(check == true); 141 } 142 143 return test_success(); 144} 145 146/* --------------------------------- RAM dataspace module test ---------------------------------- */ 147 148int 149test_ram_dspace_list(void) 150{ 151 test_start("ram dataspace list"); 152 153 struct ram_dspace_list rlist; 154 ram_dspace_init(&rlist); 155 156 /* Create a bunch of RAM dataspaces to test with. */ 157 const int rsz[] = {3, 1, REFOS_PAGE_SIZE, REFOS_PAGE_SIZE + 1, 158 REFOS_PAGE_SIZE + 2, REFOS_PAGE_SIZE * 12 + 1}; 159 const int nrsz = 6; 160 struct ram_dspace *testDSpace[nrsz]; 161 162 tvprintf("Creating dataspaces...\n"); 163 for (int i = 0; i < nrsz; i++) { 164 tvprintf(" Creating dataspace %d (size %d)...\n", i, rsz[i]); 165 testDSpace[i] = ram_dspace_create(&rlist, rsz[i]); 166 test_assert(testDSpace[i] != NULL); 167 test_assert(testDSpace[i]->magic == RAM_DATASPACE_MAGIC); 168 test_assert(testDSpace[i]->ID == 1 + i); 169 test_assert(testDSpace[i]->ref == 1); 170 } 171 172 /* Test that getting ID works. */ 173 tvprintf("Testing dataspace get...\n"); 174 for (int i = 0; i < nrsz; i++) { 175 struct ram_dspace * d = ram_dspace_get(&rlist, testDSpace[i]->ID); 176 test_assert(d); 177 test_assert(d->magic == RAM_DATASPACE_MAGIC); 178 test_assert(d->ID == testDSpace[i]->ID); 179 } 180 181 /* Delete some dataspaces and make sure get doesn't work on them any more. */ 182 tvprintf("Deleting dataspaces...\n"); 183 ram_dspace_ref(&rlist, 6); 184 test_assert(testDSpace[5]->ref == 2); 185 ram_dspace_unref(&rlist, 6); 186 test_assert(testDSpace[5]->ref == 1); 187 ram_dspace_unref(&rlist, 6); 188 ram_dspace_unref(&rlist, 5); 189 for (int i = 0; i < 4; i++) { 190 tvprintf(" Testing that dspace ID %d get still works...\n", testDSpace[i]->ID); 191 struct ram_dspace * d = ram_dspace_get(&rlist, testDSpace[i]->ID); 192 test_assert(d); 193 test_assert(d->magic == RAM_DATASPACE_MAGIC); 194 test_assert(d->ID == testDSpace[i]->ID); 195 test_assert(d->ID == i + 1); 196 } 197 for (int i = 4; i < 6; i++) { 198 tvprintf(" Testing that dspace ID %d get returns NULL...\n", i + 1); 199 struct ram_dspace * d = ram_dspace_get(&rlist, i + 1); 200 test_assert(!d); 201 } 202 203 /* Create new dataspaces again, which should reuse the just freed IDs. */ 204 tvprintf("Reallocating dataspaces...\n"); 205 for (int i = 4; i < 6; i++) { 206 testDSpace[i] = ram_dspace_create(&rlist, rsz[i]); 207 test_assert(testDSpace[i] != NULL); 208 test_assert(testDSpace[i]->magic == RAM_DATASPACE_MAGIC); 209 test_assert(testDSpace[i]->ID == 1 + i); 210 } 211 212 /* Create new dataspace should assign new ID. */ 213 tvprintf("Testing new dataspace creation to assign new ID...\n"); 214 struct ram_dspace *testDS_ = ram_dspace_create(&rlist, REFOS_PAGE_SIZE); 215 test_assert(testDS_ && testDS_->magic == RAM_DATASPACE_MAGIC); 216 test_assert(testDS_->ID == 7); 217 218 /* Test get-size and resize. */ 219 test_assert(ram_dspace_get_size(testDS_) == REFOS_PAGE_SIZE); 220 int error = ram_dspace_expand(testDS_, REFOS_PAGE_SIZE * 34); 221 test_assert(error == ESUCCESS); 222 test_assert(ram_dspace_get_size(testDS_) == REFOS_PAGE_SIZE * 34); 223 224 ram_dspace_deinit(&rlist); 225 return test_success(); 226} 227 228/* Internal declarations. */ 229int ram_dspace_read_page(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset); 230int ram_dspace_write_page(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset); 231 232/*! \brief Runs a single instance of the test_ram_dspace_read_write test. 233 Internal helper function. 234*/ 235static int 236test_ram_dspace_read_write_instance_helper(int testBufSize, int writeSize, int writeOffset, 237 int readSize, int readOffset, char usePage, int srcOffset, int ansOffset, int ansSize) 238{ 239 struct ram_dspace_list rlist; 240 ram_dspace_init(&rlist); 241 242 /* Function pointer prototypes for read/write function, so we can easily switch between using 243 ram_dspace_write_page / ram_dspace_write and ram_dspace_read_page / ram_dspace_read tests. 244 */ 245 int (*dsRead)(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset) = NULL; 246 int (*dsWrite)(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset) = NULL; 247 248 int i, error; 249 250 /* Assign the function pointers based on the type of read/write call we want to test. */ 251 if (usePage) { 252 dsRead = &ram_dspace_read_page; 253 dsWrite = &ram_dspace_write_page; 254 } else { 255 dsRead = &ram_dspace_read; 256 dsWrite = &ram_dspace_write; 257 } 258 259 /* Allocate some test buffers. */ 260 char *srcBuf = kmalloc(testBufSize); 261 test_assert(srcBuf != NULL); 262 263 char *testBufA = kmalloc(testBufSize); 264 test_assert(testBufA != NULL); 265 266 char *testBufB = kmalloc(testBufSize); 267 test_assert(testBufB != NULL); 268 269 /* Initialise test buffers. */ 270 for (i = 0; i < testBufSize; i++) { 271 srcBuf[i] = (rand() & 0xFF); 272 testBufA[i] = 0; 273 testBufB[i] = 0; 274 } 275 276 /* Create a test RAM dataspace to play with. */ 277 struct ram_dspace *testDSpace = ram_dspace_create(&rlist, testBufSize); 278 test_assert(testDSpace != NULL); 279 test_assert(testDSpace->magic == RAM_DATASPACE_MAGIC); 280 281 error = dsWrite(srcBuf + srcOffset, writeSize, testDSpace, writeOffset); 282 test_assert(!error); 283 error = dsRead(testBufB, readSize, testDSpace, readOffset); 284 test_assert(!error); 285 286 memcpy(testBufA, srcBuf + ansOffset, ansSize); 287 for (i = 0; i < ansSize; i++) { 288 test_assert(testBufA[i] == testBufB[i]); 289 } 290 291 /* Clean up. */ 292 kfree(testBufA); 293 kfree(testBufB); 294 kfree(srcBuf); 295 296 ram_dspace_deinit(&rlist); 297 return ESUCCESS; 298} 299 300int 301test_ram_dspace_read_write(void) 302{ 303 test_start("ram dataspace read/write"); 304 int error = 0; 305 306 /* Test read/write with aligned page. */ 307 error = test_ram_dspace_read_write_instance_helper ( 308 REFOS_PAGE_SIZE, REFOS_PAGE_SIZE, 0, REFOS_PAGE_SIZE, 0, 309 true, 0, 0, REFOS_PAGE_SIZE 310 ); 311 test_assert(error == ESUCCESS); 312 313 error = test_ram_dspace_read_write_instance_helper ( 314 REFOS_PAGE_SIZE, REFOS_PAGE_SIZE, 0, REFOS_PAGE_SIZE, 0, 315 false, 0, 0, REFOS_PAGE_SIZE 316 ); 317 test_assert(error == ESUCCESS); 318 319 /* Test read/write with some offsets. */ 320 error = test_ram_dspace_read_write_instance_helper ( 321 REFOS_PAGE_SIZE, REFOS_PAGE_SIZE / 2, REFOS_PAGE_SIZE / 4, 322 REFOS_PAGE_SIZE / 8, REFOS_PAGE_SIZE / 2, false, 0, REFOS_PAGE_SIZE / 4, 323 REFOS_PAGE_SIZE / 8 324 ); 325 test_assert(error == ESUCCESS); 326 327 error = test_ram_dspace_read_write_instance_helper ( 328 REFOS_PAGE_SIZE, REFOS_PAGE_SIZE / 2, REFOS_PAGE_SIZE / 4, 329 REFOS_PAGE_SIZE / 8, REFOS_PAGE_SIZE / 2, true, 0, REFOS_PAGE_SIZE / 4, 330 REFOS_PAGE_SIZE / 8 331 ); 332 test_assert(error == ESUCCESS); 333 334 /* Test read/write with offsets on big dataspace. */ 335 error = test_ram_dspace_read_write_instance_helper ( 336 REFOS_PAGE_SIZE * 3, REFOS_PAGE_SIZE * 2, REFOS_PAGE_SIZE / 2, 578, 337 REFOS_PAGE_SIZE + 200, false, 0, (REFOS_PAGE_SIZE / 2) + 200, 578 338 ); 339 test_assert(error == ESUCCESS); 340 341 error = test_ram_dspace_read_write_instance_helper ( 342 REFOS_PAGE_SIZE * 3, REFOS_PAGE_SIZE * 2, REFOS_PAGE_SIZE / 2, 343 REFOS_PAGE_SIZE, REFOS_PAGE_SIZE * 2, false, 0, REFOS_PAGE_SIZE + (REFOS_PAGE_SIZE / 2), 344 REFOS_PAGE_SIZE / 2 345 ); 346 test_assert(error == ESUCCESS); 347 348 return test_success(); 349} 350 351int 352test_ram_dspace_content_init(void) 353{ 354 test_start("ram dataspace content init"); 355 struct ram_dspace_list rlist; 356 ram_dspace_init(&rlist); 357 358 /* Create a dummy EP. */ 359 const int npages = 9; 360 cspacepath_t dummyEP = procserv_mint_badge(20500); 361 cspacepath_t dummyWaiter = procserv_mint_badge(20501); 362 test_assert(dummyEP.capPtr); 363 test_assert(dummyWaiter.capPtr); 364 365 /* Create a test RAM dataspace to play with. */ 366 struct ram_dspace *dspace = ram_dspace_create(&rlist, npages * REFOS_PAGE_SIZE); 367 test_assert(dspace != NULL); 368 test_assert(dspace->magic == RAM_DATASPACE_MAGIC); 369 370 int error = ram_dspace_need_content_init(dspace, 0x1000); 371 test_assert(error == -EINVALID); 372 373 /* Enable content init mode, with dummy EP. */ 374 error = ram_dspace_content_init(dspace, dummyEP, 0x54); 375 test_assert(error == ESUCCESS); 376 377 /* Test content-init bit. */ 378 error = ram_dspace_need_content_init(dspace, npages * REFOS_PAGE_SIZE + 0x35); 379 test_assert(error == -EINVALIDPARAM); 380 for (int i = 0; i < npages; i++) { 381 int val = ram_dspace_need_content_init(dspace, i * REFOS_PAGE_SIZE); 382 test_assert(val == true); 383 ram_dspace_set_content_init_provided(dspace,i * REFOS_PAGE_SIZE); 384 val = ram_dspace_need_content_init(dspace, i * REFOS_PAGE_SIZE); 385 test_assert(val == false); 386 } 387 388 /* Test waiter. */ 389 error = ram_dspace_add_content_init_waiter(dspace, 0x2000, dummyWaiter); 390 test_assert(error == ESUCCESS); 391 392 ram_dspace_unref(&rlist, dspace->ID); 393 ram_dspace_deinit(&rlist); 394 return test_success(); 395} 396 397 398/* ------------------------------- Ring buffer module test ------------------------------- */ 399 400int 401test_ringbuffer(void) 402{ 403 test_start("ring buffer"); 404 405 struct ram_dspace_list rlist; 406 ram_dspace_init(&rlist); 407 408 /* Create a RAM dataspace to attach to a ringbuffer. */ 409 struct ram_dspace *ds = ram_dspace_create(&rlist, 410 (REFOS_PAGE_SIZE * 3) + RINGBUFFER_METADATA_SIZE + 1); 411 char *buf = kmalloc(REFOS_PAGE_SIZE * 3); 412 char *outbuf = kmalloc(REFOS_PAGE_SIZE * 3); 413 test_assert(ds && buf && outbuf); 414 test_assert(ds->magic == RAM_DATASPACE_MAGIC); 415 416 /* Initialise ring buffer content. */ 417 for (int i = 0; i < REFOS_PAGE_SIZE * 3; i++) { 418 outbuf[i] = 0; 419 } 420 for (int i = 0; i < REFOS_PAGE_SIZE * 3; i++) { 421 buf[i] = 'a' + (i / REFOS_PAGE_SIZE); 422 } 423 424 /* Create a write ringbuffer and make sure it has reffed the dataspace. */ 425 struct rb_buffer *rb = rb_create(ds, RB_WRITEONLY); 426 test_assert(rb && rb->magic == RINGBUFFER_MAGIC); 427 test_assert(rb->dataspace->ID = ds->ID); 428 test_assert(rb->dataspace->ref == 2); 429 430 /* Test rb_write icky wrapping case works. */ 431 rb->localEnd = 4096; 432 rb->localStart = 8193; 433 ram_dspace_write(((char*) &rb->localEnd), sizeof(rb->localEnd), rb->dataspace, 434 sizeof(uint32_t)); 435 ram_dspace_write(((char*) &rb->localStart), sizeof(rb->localStart), rb->dataspace, 0); 436 rb_write(rb, buf + REFOS_PAGE_SIZE, REFOS_PAGE_SIZE); 437 438 ram_dspace_read_page(outbuf, REFOS_PAGE_SIZE - (sizeof(seL4_Word) * 2), 439 rb->dataspace, (sizeof(seL4_Word) * 2)); 440 ram_dspace_read_page(outbuf + REFOS_PAGE_SIZE - (sizeof(seL4_Word) * 2), 441 REFOS_PAGE_SIZE, rb->dataspace, REFOS_PAGE_SIZE); 442 ram_dspace_read_page(outbuf + (REFOS_PAGE_SIZE * 2) - (sizeof(seL4_Word) * 2), 443 REFOS_PAGE_SIZE, rb->dataspace, REFOS_PAGE_SIZE * 2); 444 ram_dspace_read_page(outbuf + (REFOS_PAGE_SIZE * 3) - (sizeof(seL4_Word) * 2), 445 (sizeof(seL4_Word) * 2), rb->dataspace, 446 REFOS_PAGE_SIZE * 3 - (sizeof(seL4_Word) * 2)); 447 448 for (int i = 0; i < REFOS_PAGE_SIZE; i++) { 449 test_assert(buf[i] != outbuf[i]); 450 } 451 for (int i = REFOS_PAGE_SIZE; i < REFOS_PAGE_SIZE * 2; i++) { 452 test_assert(buf[i] == outbuf[i]); 453 } 454 for (int i = REFOS_PAGE_SIZE * 2; i < REFOS_PAGE_SIZE * 3; i++) { 455 test_assert(buf[i] != outbuf[i]); 456 } 457 458 /* Create another write ringbuffer and make sure it has reffed the dataspace. */ 459 struct rb_buffer *rbw = rb_create(ds, RB_WRITEONLY); 460 test_assert(rbw && rbw->magic == RINGBUFFER_MAGIC); 461 test_assert(rbw->dataspace->ID = ds->ID); 462 test_assert(rbw->dataspace->ref == 3); 463 for (int i = 0; i < REFOS_PAGE_SIZE * 3; i++) { 464 buf[i] = '0' + (i / REFOS_PAGE_SIZE); 465 outbuf[i] = 133; 466 } 467 size_t bytesRead = 42; 468 469 /* Create read ringbuffer and make sure it has reffed the dataspace. */ 470 struct rb_buffer *rbr = rb_create(ds, RB_READONLY); 471 test_assert(rbr && rbr->magic == RINGBUFFER_MAGIC); 472 test_assert(rbr->dataspace->ID = ds->ID); 473 test_assert(rbr->dataspace->ref == 4); 474 475 /* Test rb_read icky wrapping case works, after rb_write. */ 476 rbw->localStart = rbw->localEnd = 1337; 477 rb_write(rbw, buf, REFOS_PAGE_SIZE * 3); 478 479 rbr->localStart = rbr->localEnd = 1337; 480 rb_read(rbr, outbuf, REFOS_PAGE_SIZE * 3, &bytesRead); 481 482 test_assert(bytesRead == REFOS_PAGE_SIZE * 3); 483 484 for (int i = 0; i < REFOS_PAGE_SIZE * 3; i++) { 485 test_assert(buf[i] == outbuf[i]); 486 } 487 488 /* Test ring buffer deletion. */ 489 rb_delete(rb); 490 test_assert(ds->ref == 3); 491 test_assert(ds->magic == RAM_DATASPACE_MAGIC); 492 493 rb_delete(rbw); 494 test_assert(ds->ref == 2); 495 test_assert(ds->magic == RAM_DATASPACE_MAGIC); 496 497 rb_delete(rbr); 498 test_assert(ds->ref == 1); 499 test_assert(ds->magic == RAM_DATASPACE_MAGIC); 500 501 kfree(buf); 502 kfree(outbuf); 503 504 ram_dspace_deinit(&rlist); 505 return test_success(); 506} 507 508 509#endif /* CONFIG_REFOS_RUN_TESTS */ 510