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 15#ifdef CONFIG_REFOS_RUN_TESTS 16 17#include <assert.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <string.h> 21 22#include <refos/refos.h> 23#include <refos/test.h> 24#include <refos/error.h> 25#include <refos/share.h> 26#include <refos/vmlayout.h> 27#include <refos-io/morecore.h> 28#include <refos-io/stdio.h> 29#include <refos-rpc/name_client.h> 30#include <refos-rpc/name_client_helper.h> 31#include <refos-rpc/proc_client.h> 32#include <refos-rpc/proc_client_helper.h> 33#include <refos-rpc/data_client.h> 34#include <refos-rpc/data_client_helper.h> 35#include <refos-rpc/serv_client.h> 36#include <refos-util/cspace.h> 37#include <refos-util/init.h> 38#include <refos-util/walloc.h> 39 40#include "test_fileserv.h" 41#include "test_anon_ram.h" 42 43/* Debug printing. */ 44#include <refos-util/dprintf.h> 45 46#define MMAP_SIZE 0x100000 // 16MB. 47static char mmapRegion[MMAP_SIZE]; 48 49extern uintptr_t __vsyscall_ptr; 50 51#define BSS_MAGIC 0xBA13DD37 52#define BSS_ARRAY_SIZE 0x20000 53#define TEST_KERNEL_VM_RESERVED_START 0xE0000000 54#define TEST_USERLAND_TEST_APP "/fileserv/test_user" 55 56char bssArray[BSS_ARRAY_SIZE]; 57int bssVar = BSS_MAGIC; 58int bssVar2; 59 60const char* dprintfServerName = "OS_TEST"; 61int dprintfServerColour = 37; 62 63/* ---------------------------------- Memory tests ---------------------------------------- */ 64 65static int 66test_bss(void) 67{ 68 test_start("bss zero"); 69 test_assert(bssVar == BSS_MAGIC); 70 test_assert(bssVar2 == 0); 71 for (int i = 0; i < BSS_ARRAY_SIZE; i++) { 72 test_assert(bssArray[i] == 0); 73 bssArray[i] = (char)((i*7)%250); 74 } 75 test_assert(bssVar == BSS_MAGIC); 76 test_assert(bssVar2 == 0); 77 for (int i = 0; i < BSS_ARRAY_SIZE; i++) { 78 test_assert(bssArray[i] == (char)((i*7)%250)); 79 } 80 return test_success(); 81} 82 83static int 84test_stack(void) 85{ 86 test_start("stack"); 87 const size_t stackAllocSize = 0x2000; 88 char stackArray[stackAllocSize]; 89 for (int i = 0; i < stackAllocSize; i++) { 90 stackArray[i] = (char)(i * 1234); 91 } 92 for (int i = 0; i < stackAllocSize; i++) { 93 test_assert( stackArray[i] == (char)(i * 1234)); 94 } 95 return test_success(); 96} 97 98static int 99test_heap(void) 100{ 101 test_start("heap"); 102 /* Test heap malloc actually works. */ 103 const size_t heapAllocSize = 0x16000; 104 char *heapArray = malloc(heapAllocSize); 105 test_assert(heapArray); 106 for (int i = 0; i < heapAllocSize; i++) { 107 heapArray[i] = (i%2)?'z':'a'; 108 } 109 for (int i = 0; i < heapAllocSize; i++) { 110 test_assert(heapArray[i] == (i%2)?'z':'a'); 111 } 112 free(heapArray); 113 /* Test that free works by continually allocating and free-ing a large block. */ 114 for (int i = 0; i < 10000; i++) { 115 char *heapArray2 = malloc(heapAllocSize); 116 test_assert(heapArray2); 117 heapArray2[4] = 123; 118 test_assert(heapArray2[4] == 123); 119 free(heapArray); 120 } 121 return test_success(); 122} 123 124/* -------------------------------- Process server tests -------------------------------------- */ 125 126static int 127test_process_server_ping(void) 128{ 129 test_start("process server ping"); 130 for (int i = 0; i < 8; i++) { 131 int error = proc_ping(); 132 test_assert(error == ESUCCESS); 133 } 134 return test_success(); 135} 136 137static int 138test_process_server_endpoints(void) 139{ 140 test_start("process server endpoints"); 141 142 seL4_CPtr ep = proc_new_endpoint(); 143 test_assert(ep && ROS_ERRNO() == ESUCCESS); 144 145 seL4_CPtr aep = proc_new_async_endpoint(); 146 test_assert(aep && ROS_ERRNO() == ESUCCESS); 147 148 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1); 149 seL4_SetMR(0, 0x31336); 150 seL4_NBSend(aep, tag); 151 152 seL4_Word badge; 153 seL4_Recv(aep, &badge); 154 155 test_assert(badge == 0); 156 test_assert(seL4_GetMR(0) == 0x31336); 157 158 proc_del_endpoint(ep); 159 proc_del_async_endpoint(aep); 160 161 return test_success(); 162} 163 164static int 165test_process_server_window(void) 166{ 167 test_start("process server memwindows"); 168 seL4_Word testBase = 0x20000000; 169 170 /* Create invalid window in kernel memory. */ 171 seL4_CPtr invalidKernelMemWindow = proc_create_mem_window( 172 TEST_KERNEL_VM_RESERVED_START + 100, 0x1000); 173 test_assert(invalidKernelMemWindow == 0 && ROS_ERRNO() == EINVALIDPARAM); 174 175 /* Create valid test windows. */ 176 int windowBases[] = {0x2000, 0x4000, 0x6000, 0x8000, 0x10000}; 177 seL4_CPtr validWindows[5]; 178 int nWindows = 5; 179 for (int i = 0; i < nWindows; i++) { 180 validWindows[i] = proc_create_mem_window(testBase + windowBases[i], 10); 181 test_assert(validWindows[i] != 0 && ROS_ERRNO() == ESUCCESS); 182 } 183 184 int testWin[] = {0x2000, 1, 0x4001, 20, 0x7000, 10, 0x6002, 50, 0, 0x9FFF}; 185 int expectedResult[] = {EINVALIDWINDOW, EINVALIDWINDOW, ESUCCESS, EINVALIDWINDOW, EINVALIDWINDOW}; 186 int numTestWin = 5; 187 for (int i = 0; i < numTestWin; i++) { 188 seL4_CPtr testWindow = proc_create_mem_window(testBase + testWin[i*2], testWin[i*2+1]); 189 test_assert(ROS_ERRNO() == expectedResult[i]); 190 if (expectedResult[i] == ESUCCESS) { 191 test_assert(testWindow); 192 } 193 if (testWindow) { 194 int error = proc_delete_mem_window(testWindow); 195 test_assert(error == ESUCCESS); 196 } 197 } 198 199 for (int i = 0; i < nWindows; i++) { 200 if (validWindows[i]) { 201 int error = proc_delete_mem_window(validWindows[i]); 202 test_assert(error == ESUCCESS); 203 } 204 } 205 206 return test_success(); 207} 208 209static int 210test_process_server_window_resize(void) 211{ 212 test_start("process server memwindow resize"); 213 seL4_Word testBase = 0x20000000; 214 215 /* Test window resize. */ 216 seL4_CPtr testRWindow = proc_create_mem_window(testBase + 0x1000, 0x2000); 217 test_assert(testRWindow && ROS_ERRNO() == ESUCCESS); 218 219 seL4_CPtr testCheckWindow = proc_create_mem_window(testBase + 0x3000, 0x1000); 220 test_assert(testCheckWindow && ROS_ERRNO() == ESUCCESS); 221 222 /* Resizing the latter window should succeed. */ 223 int error = proc_resize_mem_window(testCheckWindow, 0x2000); 224 test_assert(error == ESUCCESS); 225 /* Increasing the previous window should cause overlap error. */ 226 error = proc_resize_mem_window(testRWindow, 0x2100); 227 test_assert(error == EINVALIDPARAM); 228 /* Zero size not allowed. */ 229 error = proc_resize_mem_window(testRWindow, 0); 230 test_assert(error == EINVALIDPARAM); 231 /* Shrinking window is OK. */ 232 error = proc_resize_mem_window(testRWindow, 0x1900); 233 test_assert(error == ESUCCESS); 234 /* Invalid window. */ 235 error = proc_resize_mem_window(0x0, 0x2100); 236 test_assert(error == EINVALIDWINDOW); 237 238 239 /* Delete the latter window. */ 240 error = proc_delete_mem_window(testCheckWindow); 241 test_assert(error == ESUCCESS); 242 243 /* Increasing the previous window should now succeed, as the latter window causing the overlap 244 is now gone. */ 245 error = proc_resize_mem_window(testRWindow, 0x2100); 246 test_assert(error == ESUCCESS); 247 error = proc_delete_mem_window(testRWindow); 248 test_assert(error == ESUCCESS); 249 250 return test_success(); 251} 252 253static int 254test_process_server_param_buffer(void) 255{ 256 test_start("process server param sharing"); 257 int error; 258 seL4_CPtr ds = data_open(REFOS_PROCSERV_EP, "anon", 259 0x0, 0x0, PROCESS_PARAM_DEFAULTSIZE, &error); 260 test_assert(error == ESUCCESS); 261 test_assert(ds); 262 error = proc_set_parambuffer(ds, PROCESS_PARAM_DEFAULTSIZE); 263 test_assert(error == ESUCCESS); 264 return test_success(); 265} 266 267static int 268test_process_server_nameserv(void) 269{ 270 test_start("process server registration"); 271 int error; 272 nsv_mountpoint_t mp; 273 char *testServerName = "os_test_dummy_server"; 274 char *testServerPath = "/os_test_dummy_server/foo.txt"; 275 276 /* Should not find this server. */ 277 mp = nsv_resolve(testServerPath); 278 test_assert(ROS_ERRNO() == ESERVERNOTFOUND); 279 test_assert(mp.success == false); 280 test_assert(mp.serverAnon == 0); 281 282 /* Make a quick anon cap. */ 283 seL4_CPtr aep = proc_new_async_endpoint(); 284 test_assert(aep && ROS_ERRNO() == ESUCCESS); 285 286 /* We register ourselves now under this server name. */ 287 error = nsv_register(REFOS_NAMESERV_EP, testServerName, aep); 288 test_assert(error == ESUCCESS); 289 290 /* We should find ourself now. */ 291 mp = nsv_resolve(testServerPath); 292 test_assert(ROS_ERRNO() == ESUCCESS); 293 test_assert(mp.success == true); 294 test_assert(mp.serverAnon != 0); 295 test_assert(strcmp(mp.dspaceName, "foo.txt") == 0); 296 test_assert(strcmp(mp.nameservPathPrefix, "/os_test_dummy_server/") == 0); 297 298 /* Test this anon cap we recieved and make sure it is actually the one we passed in. */ 299 seL4_MessageInfo_t tag = seL4_MessageInfo_new(0, 0, 0, 1); 300 seL4_SetMR(0, 0xabbadadd); 301 seL4_NBSend(mp.serverAnon, tag); 302 303 seL4_Word badge; 304 seL4_Recv(aep, &badge); 305 test_assert(badge == 0); 306 test_assert(seL4_GetMR(0) == 0xabbadadd); 307 308 /* Release the resources stored in the valid mountpoint. */ 309 nsv_mountpoint_release(&mp); 310 test_assert(mp.success == false); 311 test_assert(mp.serverAnon == 0); 312 313 /* We now unregister ourselves. */ 314 error = nsv_unregister(REFOS_NAMESERV_EP, testServerName); 315 test_assert(error == ESUCCESS); 316 317 /* We should not be able to find this server again. */ 318 mp = nsv_resolve(testServerPath); 319 test_assert(ROS_ERRNO() == ESERVERNOTFOUND); 320 test_assert(mp.success == false); 321 test_assert(mp.serverAnon == 0); 322 323 proc_del_async_endpoint(aep); 324 return test_success(); 325} 326 327static int 328test_start_userland_test(void) 329{ 330 tprintf("TEST_OS | Starting RefOS userland environment unit tests...\n"); 331 int status = EINVALID; 332 int error; 333 (void) error; 334 335 /* Start the application */ 336 error = proc_new_proc(TEST_USERLAND_TEST_APP, "", true, 70, &status); 337 assert(error == ESUCCESS); 338 assert(status == 0x1234); 339 return 0; 340} 341 342 343static void 344test_process_server(void) 345{ 346 test_process_server_ping(); 347 test_process_server_endpoints(); 348 test_process_server_window(); 349 test_process_server_window_resize(); 350 test_process_server_param_buffer(); 351 test_process_server_nameserv(); 352} 353 354/* -------------------------------- RefOSUtil tests -------------------------------------- */ 355 356static int 357test_rosutil_calloc(void) 358{ 359 test_start("rosutil calloc"); 360 for (int i = 0; i <= 64; i++) { 361 seL4_CPtr c = csalloc(); 362 test_assert(c); 363 csfree(c); 364 } 365 return test_success(); 366} 367 368static int 369test_rosutil_walloc(void) 370{ 371 test_start("rosutil walloc"); 372 for (int i = 0; i < 8; i++) { 373 int npages = i % 2 ? 2 : 3; 374 seL4_CPtr windowCap; 375 seL4_Word vaddr = walloc(npages, &windowCap); 376 test_assert(vaddr && windowCap); 377 walloc_free(vaddr, npages); 378 } 379 return test_success(); 380} 381 382static void 383test_rosutil(void) 384{ 385 test_rosutil_calloc(); 386 test_rosutil_walloc(); 387} 388 389static int 390test_share(void) 391{ 392 test_start("share"); 393 394 char *testBuf = malloc(4096 * 3); 395 char *srcBuf = malloc(4096 * 3); 396 char *sharedBuf = malloc(4096 * 3 + 9); 397 int i; 398 unsigned int bytesRead = 0; 399 unsigned int start = 0; 400 unsigned int end = 0; 401 402 for (i = 0; i < 4096 * 3; i++) { 403 srcBuf[i] = 'a' + (i / 4096); 404 testBuf[i] = 0; 405 } 406 407 for (i = 0; i < 4096 * 3 + 9; i++) { 408 sharedBuf[i] = 0; 409 } 410 411 int ret = refos_share_write(srcBuf, 4096 * 3, sharedBuf, 4096 * 3 + 9, &end); 412 tvprintf("return is %d\n", ret); 413 tvprintf("end is %d\n", end); 414 test_assert(ret == 0 && end == 4096 * 3); 415 416 ret = refos_share_read(testBuf, 4096 * 3, sharedBuf, 4096 * 3 + 9, &start, &bytesRead); 417 tvprintf("return is %d\n", ret); 418 tvprintf("bytesRead is %d\n", bytesRead); 419 test_assert(ret == 0 && bytesRead == 4096 * 3); 420 421 for (i = 0; i < 4096 * 3; i++) { 422 test_assert(testBuf[i] == srcBuf[i]); 423 } 424 425 for (i = 0; i < 4096 * 3; i++) { 426 srcBuf[i] = 0; 427 testBuf[i] = 0; 428 } 429 430 for (i = 0; i < 4096 * 3 + 9; i++) { 431 sharedBuf[i] = 0; 432 } 433 434 for (i = 0; i < 4096; i++) { 435 srcBuf[i] = 'a'; 436 } 437 for (i = 8192; i < 4096 * 3; i++) { 438 srcBuf[i] = 'a'; 439 } 440 441 end = 8192; 442 start = 8192; 443 bytesRead = 0; 444 unsigned int *ptr = (unsigned int*)sharedBuf; 445 ptr[0] = start; 446 ptr[1] = end; 447 448 char *srcBuf2 = malloc(4096 * 2); 449 for (i = 0; i < 4096 * 2; i++) { 450 srcBuf2[i] = 'a'; 451 } 452 453 ret = refos_share_write(srcBuf2, 4096 * 2, sharedBuf, 4096 * 3 + 9, &end); 454 ret = refos_share_read(testBuf, 4096 * 2, sharedBuf, 4096 * 3 + 9, &start, &bytesRead); 455 for (i = 0; i < 4096 * 2; i++) { 456 test_assert(testBuf[i] == srcBuf2[i]); 457 } 458 459 return test_success(); 460 461} 462 463/* ---------------------------------- OS Level tests ---------------------------------------- */ 464 465static void 466test_OS_level(void) 467{ 468 test_bss(); 469 test_stack(); 470 test_heap(); 471 test_process_server(); 472 test_anon_dataspace(); 473 test_file_server(); 474 test_rosutil(); 475 test_share(); 476} 477 478#endif /* CONFIG_REFOS_RUN_TESTS */ 479 480int 481main() 482{ 483#ifdef CONFIG_REFOS_RUN_TESTS 484 /* Future Work 4: 485 Eventually RefOS should be changed so that processes that are started 486 by the process server do not require that the their system call table be 487 explicitly referenced in the code like this. Without expliciting referencing 488 __vsyscall_ptr in main(), the compiler optimizes away __vsyscall_ptr 489 and then processes started by the process server can't find their system call 490 table. Each of the four places in RefOS where this explicit reference is 491 required is affected by a custom linker script (linker.lds), so it is possible 492 that the custom linker script (and then likely other things too) needs to be 493 modified. Also note that the ROS_ERROR() and assert() inside this if statement 494 would not actually be able to execute if __vsyscall_ptr() were ever not set. 495 The purpose of these calls to ROS_ERROR() and assert() is to show future 496 developers that __vsyscall_ptr needs to be defined. 497 */ 498 if (! __vsyscall_ptr) { 499 ROS_ERROR("Test OS server could not find system call table."); 500 assert("!Test OS server could not find system call table."); 501 return 0; 502 } 503 504 refosio_setup_morecore_override(mmapRegion, MMAP_SIZE); 505 refos_initialise_os_minimal(); 506 refos_setup_dataspace_stdio(REFOS_DEFAULT_STDIO_DSPACE); 507 508 tprintf("OS_TESTS | Running RefOS OS-level tests.\n"); 509 test_title = "OS_TESTS"; 510 test_OS_level(); 511 test_print_log(); 512 513 test_start_userland_test(); 514 tprintf("OS_TESTS | Back to Refos OS-level. Running userland second time.\n"); 515 test_start_userland_test(); 516 tprintf("OS_TESTS | Back to Refos OS-level. Quitting.\n"); 517#endif /* CONFIG_REFOS_RUN_TESTS */ 518 519 return 0; 520} 521