1/* 2 * Copyright 2017, 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(DATA61_BSD) 11 */ 12 13#include <autoconf.h> 14#include <sel4test-driver/gen_config.h> 15 16/* This file contains tests related to multicore. */ 17 18#include <stdio.h> 19#include <sel4/sel4.h> 20 21#include "../helpers.h" 22 23static int counter_func(volatile seL4_Word *counter) 24{ 25 while (1) { 26 (*counter)++; 27 } 28 return 0; 29} 30 31int smp_test_tcb_resume(env_t env) 32{ 33 helper_thread_t t1; 34 volatile seL4_Word counter; 35 ZF_LOGD("smp_test_tcb_resume\n"); 36 create_helper_thread(env, &t1); 37 38 set_helper_priority(env, &t1, 100); 39 start_helper(env, &t1, (helper_fn_t) counter_func, (seL4_Word) &counter, 0, 0, 0); 40 41 seL4_Word old_counter; 42 43 /* Let the counter thread run. */ 44 sel4test_sleep(env, 10 * NS_IN_MS); 45 46 old_counter = counter; 47 48 /* Let it run again on the current core. */ 49 sel4test_sleep(env, 10 * NS_IN_MS); 50 51 /* Now, counter should have moved. */ 52 test_check(counter != old_counter); 53 54 /* Suspend the thread, and move it to new core. */ 55 seL4_TCB_Suspend(get_helper_tcb(&t1)); 56 set_helper_affinity(env, &t1, 1); 57 58 old_counter = counter; 59 60 /* Check if the thread is running. */ 61 sel4test_sleep(env, 10 * NS_IN_MS); 62 63 /* Counter should not have moved. */ 64 test_check(counter == old_counter); 65 old_counter = counter; 66 67 /* Resume the thread and check it does move. */ 68 seL4_TCB_Resume(get_helper_tcb(&t1)); 69 sel4test_sleep(env, 10 * NS_IN_MS); 70 test_check(counter != old_counter); 71 72 /* Suspend the thread. */ 73 seL4_TCB_Suspend(get_helper_tcb(&t1)); 74 75 old_counter = counter; 76 77 /* Check if the thread is running. */ 78 sel4test_sleep(env, 10 * NS_IN_MS); 79 80 /* Counter should not have moved. */ 81 test_check(counter == old_counter); 82 83 /* Done. */ 84 cleanup_helper(env, &t1); 85 86 return sel4test_get_result(); 87} 88DEFINE_TEST(MULTICORE0001, "Test suspending and resuming a thread on different core", smp_test_tcb_resume, 89 config_set(CONFIG_HAVE_TIMER) &&CONFIG_MAX_NUM_NODES > 1) 90 91int smp_test_tcb_move(env_t env) 92{ 93 helper_thread_t t1; 94 volatile seL4_Word counter; 95 ZF_LOGD("smp_test_tcb_move\n"); 96 create_helper_thread(env, &t1); 97 98 set_helper_priority(env, &t1, 100); 99 start_helper(env, &t1, (helper_fn_t) counter_func, (seL4_Word) &counter, 0, 0, 0); 100 101 seL4_Word old_counter; 102 103 old_counter = counter; 104 105 /* Let it run on the current core. */ 106 sleep_busy(env, 10 * NS_IN_MS); 107 108 /* Now, counter should not have moved. */ 109 test_check(counter == old_counter); 110 111 for (int i = 1; i < env->cores; i++) { 112 set_helper_affinity(env, &t1, i); 113 114 old_counter = counter; 115 116 /* Check if the thread is running. */ 117 sleep_busy(env, 10 * NS_IN_MS); 118 119 /* Counter should have moved. */ 120 test_check(counter != old_counter); 121 } 122 123 /* Done. */ 124 cleanup_helper(env, &t1); 125 126 return sel4test_get_result(); 127} 128DEFINE_TEST(MULTICORE0002, "Test thread is runnable on all available cores (0 + other)", smp_test_tcb_move, 129 config_set(CONFIG_HAVE_TIMER) &&CONFIG_MAX_NUM_NODES > 1) 130 131int smp_test_tcb_delete(env_t env) 132{ 133 helper_thread_t t1; 134 volatile seL4_Word counter; 135 ZF_LOGD("smp_test_tcb_delete\n"); 136 create_helper_thread(env, &t1); 137 138 set_helper_priority(env, &t1, 100); 139 start_helper(env, &t1, (helper_fn_t) counter_func, (seL4_Word) &counter, 0, 0, 0); 140 141 seL4_Word old_counter; 142 143 old_counter = counter; 144 145 /* Let it run on the current core. */ 146 sleep_busy(env, 10 * NS_IN_MS); 147 148 /* Now, counter should not have moved. */ 149 test_check(counter == old_counter); 150 151 set_helper_affinity(env, &t1, 1); 152 153 old_counter = counter; 154 155 /* Check if the thread is running. */ 156 sleep_busy(env, 10 * NS_IN_MS); 157 158 /* Counter should have moved. */ 159 test_check(counter != old_counter); 160 161 /* Now delete the helper thread running on another core */ 162 cleanup_helper(env, &t1); 163 164 old_counter = counter; 165 166 /* Check if the thread is running. */ 167 sleep_busy(env, 10 * NS_IN_MS); 168 169 /* Now, counter should not have moved. */ 170 test_check(counter == old_counter); 171 172 /* Done. */ 173 return sel4test_get_result(); 174} 175 176DEFINE_TEST(MULTICORE0005, "Test remote delete thread running on other cores", smp_test_tcb_delete, 177 config_set(CONFIG_HAVE_TIMER) &&CONFIG_MAX_NUM_NODES > 1) 178 179static int 180faulter_func(volatile seL4_Word shared_mem) 181{ 182 volatile seL4_Word *page; 183 184 page = (volatile seL4_Word *)shared_mem; 185 186 /* Accessing to the new page... */ 187 while (1) { 188 *page = 1; 189 } 190 191 return 0; 192} 193 194static int handler_func(seL4_CPtr fault_ep, volatile seL4_Word *pf) 195{ 196 seL4_MessageInfo_t tag; 197 seL4_Word sender_badge = 0; 198 199 /* Waiting for fault from faulter */ 200 tag = api_wait(fault_ep, &sender_badge); 201 *pf = seL4_MessageInfo_get_label(tag); 202 return 0; 203} 204 205static int smp_test_tlb_instance(env_t env, bool inter_as) 206{ 207 int error; 208 volatile seL4_Word tag; 209 volatile seL4_Word shared_mem = 0; 210 ZF_LOGD("smp_test_tlb\n"); 211 212 helper_thread_t handler_thread; 213 helper_thread_t faulter_thread; 214 vspace_t *vspace; 215 seL4_CPtr faulter_vspace, faulter_cspace; 216 seL4_CPtr fault_ep = vka_alloc_endpoint_leaky(&env->vka); 217 create_helper_thread(env, &handler_thread); 218 set_helper_priority(env, &handler_thread, 100); 219 220 seL4_CPtr fault_ep_faulter = fault_ep; 221 if (inter_as) { 222 create_helper_process(env, &faulter_thread); 223 224 /* copy the fault endpoint to the faulter */ 225 cspacepath_t path; 226 vka_cspace_make_path(&env->vka, fault_ep, &path); 227 seL4_CPtr remote_fault_ep = sel4utils_copy_path_to_process(&faulter_thread.process, path); 228 assert(remote_fault_ep != -1); 229 230 if (!config_set(CONFIG_KERNEL_MCS)) { 231 fault_ep_faulter = remote_fault_ep; 232 } 233 234 faulter_cspace = faulter_thread.process.cspace.cptr; 235 faulter_vspace = faulter_thread.process.pd.cptr; 236 vspace = &faulter_thread.process.vspace; 237 } else { 238 create_helper_thread(env, &faulter_thread); 239 faulter_cspace = env->cspace_root; 240 faulter_vspace = env->page_directory; 241 vspace = &env->vspace; 242 } 243 244 error = api_tcb_set_space(get_helper_tcb(&faulter_thread), 245 fault_ep_faulter, 246 faulter_cspace, 247 api_make_guard_skip_word(seL4_WordBits - env->cspace_size_bits), 248 faulter_vspace, seL4_NilData); 249 test_error_eq(error, seL4_NoError); 250 251 /* Move handler to core 1 and faulter to the last available core */ 252 set_helper_affinity(env, &handler_thread, 1); 253 set_helper_affinity(env, &faulter_thread, env->cores - 1); 254 255 /* Map new page to shared address space */ 256 shared_mem = (seL4_Word) vspace_new_pages(vspace, seL4_AllRights, 1, seL4_PageBits); 257 258 start_helper(env, &handler_thread, (helper_fn_t) handler_func, fault_ep, (seL4_Word) &tag, 0, 0); 259 start_helper(env, &faulter_thread, (helper_fn_t) faulter_func, (seL4_Word) shared_mem, 0, 0, 0); 260 261 /* Wait for some access... */ 262 sel4test_sleep(env, 10 * NS_IN_MS); 263 264 /* Unmap the page */ 265 vspace_unmap_pages(vspace, (void *) shared_mem, 1, seL4_PageBits, &env->vka); 266 267 /* Wait for some access... */ 268 sel4test_sleep(env, CONFIG_TIMER_TICK_MS * NS_IN_MS / 10); 269 270 /* We should see page fault */ 271 test_check(tag == seL4_Fault_VMFault); 272 273 /* Done. */ 274 cleanup_helper(env, &faulter_thread); 275 cleanup_helper(env, &handler_thread); 276 return sel4test_get_result(); 277} 278 279int smp_test_tlb(env_t env) 280{ 281 test_result_t result; 282 /* Test unmapping a frame from the same VSpace and different VSpace. */ 283 for (int i = 0; i < 20; i++) { 284 bool inter_as = (i % 2 == 0) ? true : false; 285 result = smp_test_tlb_instance(env, inter_as); 286 if (result != SUCCESS) { 287 return result; 288 } 289 } 290 return result; 291 292} 293DEFINE_TEST(MULTICORE0003, "Test TLB invalidated cross cores", smp_test_tlb, 294 config_set(CONFIG_HAVE_TIMER) &&CONFIG_MAX_NUM_NODES > 1) 295 296static int 297kernel_entry_func(seL4_Word *unused) 298{ 299 while (1) { 300 seL4_Yield(); 301 } 302 return 0; 303} 304 305int smp_test_tcb_clh(env_t env) 306{ 307 helper_thread_t t[env->cores]; 308 ZF_LOGD("smp_test_tcb_move\n"); 309 310 for (int i = 1; i < env->cores; i++) { 311 create_helper_thread(env, &t[i]); 312 313 set_helper_affinity(env, &t[i], i); 314 start_helper(env, &t[i], (helper_fn_t) kernel_entry_func, (seL4_Word) NULL, 0, 0, 0); 315 } 316 317 /* All threads start calling 'seL4_Yield', which results in a queue to be generated in CLH lock. 318 * By the time we are trying to clean up threads, they should be already in CLH queue which 319 * result the delay release of the lock and stalling of the core. 320 * 321 * There is no failing here. 322 * If something is worng with IPI or lock handling we would stuck or possibly crash! */ 323 324 /* We should be able to cleanup all threads */ 325 for (int i = 1; i < env->cores; i++) { 326 cleanup_helper(env, &t[i]); 327 } 328 329 /* Do this again... */ 330 for (int i = 1; i < env->cores; i++) { 331 create_helper_thread(env, &t[i]); 332 333 set_helper_affinity(env, &t[i], i); 334 start_helper(env, &t[i], (helper_fn_t) kernel_entry_func, (seL4_Word) NULL, 0, 0, 0); 335 } 336 337 /* We should be able to cleanup all threads */ 338 for (int i = 1; i < env->cores; i++) { 339 cleanup_helper(env, &t[i]); 340 } 341 342 return sel4test_get_result(); 343} 344DEFINE_TEST(MULTICORE0004, "Test core stalling is behaving properly (flaky)", smp_test_tcb_clh, 345 CONFIG_MAX_NUM_NODES > 1) 346