112771Sqtt2@cornell.edu/*
212771Sqtt2@cornell.edu * Copyright (c) 2018, Cornell University
312771Sqtt2@cornell.edu * All rights reserved.
412771Sqtt2@cornell.edu *
512771Sqtt2@cornell.edu * Redistribution and use in source and binary forms, with or
612771Sqtt2@cornell.edu * without modification, are permitted provided that the following
712771Sqtt2@cornell.edu * conditions are met:
812771Sqtt2@cornell.edu *
912771Sqtt2@cornell.edu * Redistributions of source code must retain the above copyright
1012771Sqtt2@cornell.edu * notice, this list of conditions and the following disclaimer.
1112771Sqtt2@cornell.edu *
1212771Sqtt2@cornell.edu * Redistributions in binary form must reproduce the above
1312771Sqtt2@cornell.edu * copyright notice, this list of conditions and the following
1412771Sqtt2@cornell.edu * disclaimer in the documentation and/or other materials provided
1512771Sqtt2@cornell.edu * with the distribution.
1612771Sqtt2@cornell.edu *
1712771Sqtt2@cornell.edu * Neither the name of Cornell University nor the names of its
1812771Sqtt2@cornell.edu * contributors may be used to endorse or promote products derived
1912771Sqtt2@cornell.edu * from this software without specific prior written permission.
2012771Sqtt2@cornell.edu *
2112771Sqtt2@cornell.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
2212771Sqtt2@cornell.edu * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
2312771Sqtt2@cornell.edu * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2412771Sqtt2@cornell.edu * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2512771Sqtt2@cornell.edu * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
2612771Sqtt2@cornell.edu * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2712771Sqtt2@cornell.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2812771Sqtt2@cornell.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
2912771Sqtt2@cornell.edu * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3012771Sqtt2@cornell.edu * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3112771Sqtt2@cornell.edu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
3212771Sqtt2@cornell.edu * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3312771Sqtt2@cornell.edu * POSSIBILITY OF SUCH DAMAGE.
3412771Sqtt2@cornell.edu *
3512771Sqtt2@cornell.edu * Authors: Tuan Ta
3612771Sqtt2@cornell.edu */
3712771Sqtt2@cornell.edu
3812771Sqtt2@cornell.edu//------------------------------------------------------------------------
3912771Sqtt2@cornell.edu// sysclone_d tests basic functionalities of clone system call:
4012771Sqtt2@cornell.edu//    - create a new thread
4112771Sqtt2@cornell.edu//    - assign a new per-thread stack frame to the child thread
4212771Sqtt2@cornell.edu//    - assign a new per-thread TLS to the child thread
4312771Sqtt2@cornell.edu//
4412771Sqtt2@cornell.edu// In addition to testing clone(), sysclone_d partially checks
4512771Sqtt2@cornell.edu// functionalities of futex and exit system calls that are used to
4612771Sqtt2@cornell.edu// facilitate thread exit and synchronization.
4712771Sqtt2@cornell.edu//------------------------------------------------------------------------
4812771Sqtt2@cornell.edu
4912771Sqtt2@cornell.edu#include "riscv_test.h"
5012771Sqtt2@cornell.edu#include "test_macros.h"
5112771Sqtt2@cornell.edu#include "test_macros_mt_ecall.h"
5212771Sqtt2@cornell.edu
5312771Sqtt2@cornell.edu  RVTEST_RV64U
5412771Sqtt2@cornell.edu  RVTEST_CODE_BEGIN
5512771Sqtt2@cornell.edu
5612771Sqtt2@cornell.edu#define MAX_NUM_THREADS 20
5712771Sqtt2@cornell.edu
5812771Sqtt2@cornell.edu//------------------------------------------------------------------------
5912771Sqtt2@cornell.edu// Master thread creates new threads, waits for all threads to complete,
6012771Sqtt2@cornell.edu// deallocates threads and checks result
6112771Sqtt2@cornell.edu//------------------------------------------------------------------------
6212771Sqtt2@cornell.edu  li      a0, MAX_NUM_THREADS
6312771Sqtt2@cornell.edu  call    _create_threads
6412771Sqtt2@cornell.edu
6512771Sqtt2@cornell.edu  la      t6, n_worker_threads
6612771Sqtt2@cornell.edu  ld      a0, (t6)
6712771Sqtt2@cornell.edu  beqz    a0, _fail                   // exit if there's no worker thread
6812771Sqtt2@cornell.edu  call    _join
6912771Sqtt2@cornell.edu
7012771Sqtt2@cornell.edu  la      t6, n_worker_threads
7112771Sqtt2@cornell.edu  ld      a0, (t6)
7212771Sqtt2@cornell.edu  call    _check
7312771Sqtt2@cornell.edu
7412771Sqtt2@cornell.edu  la      t6, n_worker_threads
7512771Sqtt2@cornell.edu  ld      a0, (t6)
7612771Sqtt2@cornell.edu  call    _delete_threads
7712771Sqtt2@cornell.edu
7812771Sqtt2@cornell.edu  li      a0, SUCCESS
7912771Sqtt2@cornell.edu
8012771Sqtt2@cornell.edu  RVTEST_CODE_END
8112771Sqtt2@cornell.edu
8212771Sqtt2@cornell.edu//------------------------------------------------------------------------
8312771Sqtt2@cornell.edu// mt_test function executed by child threads
8412771Sqtt2@cornell.edu//------------------------------------------------------------------------
8512771Sqtt2@cornell.edu_mt_test:
8612771Sqtt2@cornell.edu  // get this thread's TID
8712771Sqtt2@cornell.edu  li      a7, SYSCALL_GETTID
8812771Sqtt2@cornell.edu  ecall
8912771Sqtt2@cornell.edu
9012771Sqtt2@cornell.edu  // store the TID to both stack and TLS of this thread
9112771Sqtt2@cornell.edu  addi    sp, sp, -8
9212771Sqtt2@cornell.edu  sd      a0, (sp)
9312771Sqtt2@cornell.edu  sd      a0, (tp)
9412771Sqtt2@cornell.edu
9512771Sqtt2@cornell.edu  RVTEST_CODE_END
9612771Sqtt2@cornell.edu
9712771Sqtt2@cornell.edu//------------------------------------------------------------------------
9812771Sqtt2@cornell.edu// _check:
9912771Sqtt2@cornell.edu//    The master thread looks into the stack and TLS of each child thread
10012771Sqtt2@cornell.edu//    and check if the child thread's TID was written in both places.
10112771Sqtt2@cornell.edu//
10212771Sqtt2@cornell.edu//    This function assumes the following structure in the calling thread's
10312771Sqtt2@cornell.edu//    stack frame
10412771Sqtt2@cornell.edu//
10512771Sqtt2@cornell.edu//    | child_stack_ptr_0       |  << fp: frame pointer
10612771Sqtt2@cornell.edu//    | child_tls_ptr_0         |
10712771Sqtt2@cornell.edu//    | child_thread_id_0       |
10812771Sqtt2@cornell.edu//    | saved_child_thread_id_0 |
10912771Sqtt2@cornell.edu//    | child_stack_ptr_1       |
11012771Sqtt2@cornell.edu//    | child_tls_ptr_1         |
11112771Sqtt2@cornell.edu//    | child_thread_id_1       |
11212771Sqtt2@cornell.edu//    | saved_child_thread_id_1 |
11312771Sqtt2@cornell.edu//    | ...                     |  << sp: stack pointer
11412771Sqtt2@cornell.edu//
11512771Sqtt2@cornell.edu//    This function takes a number of threads to check in a0
11612771Sqtt2@cornell.edu//------------------------------------------------------------------------
11712771Sqtt2@cornell.edu
11812771Sqtt2@cornell.edu_check:
11912771Sqtt2@cornell.edu  mv      t0, a0          // get the number of threads
12012771Sqtt2@cornell.edu  mv      s0, ra          // save return register
12112771Sqtt2@cornell.edu  mv      s1, sp          // save stack pointer
12212771Sqtt2@cornell.edu1:
12312771Sqtt2@cornell.edu  ld      t1, (sp)        // get child_thread_saved_id
12412771Sqtt2@cornell.edu
12512771Sqtt2@cornell.edu  addi    sp, sp, 8
12612771Sqtt2@cornell.edu  ld      t2, (sp)        // get child_thread_id
12712771Sqtt2@cornell.edu  bnez    t2, _fail       // this child_thread_id should have been cleared
12812771Sqtt2@cornell.edu
12912771Sqtt2@cornell.edu  addi    sp, sp, 8
13012771Sqtt2@cornell.edu  ld      t3, (sp)        // get child_tls_ptr
13112771Sqtt2@cornell.edu  ld      t3, (t3)        // get the first value stored in child's TLS
13212771Sqtt2@cornell.edu  bne     t1, t3, _fail   // child_tid should have been saved in the TLS
13312771Sqtt2@cornell.edu
13412771Sqtt2@cornell.edu  addi    sp, sp, 8
13512771Sqtt2@cornell.edu  ld      t4, (sp)        // get child_stack_ptr
13612771Sqtt2@cornell.edu  li      t5, MEM_SIZE
13712771Sqtt2@cornell.edu  add     t4, t4, t5      // get the high address of child's stack
13812771Sqtt2@cornell.edu  ld      t4, -8(t4)      // get the first value stored in child's stack
13912771Sqtt2@cornell.edu  bne     t1, t4, _fail   // child_tid should have been saved in the stack
14012771Sqtt2@cornell.edu
14112771Sqtt2@cornell.edu  addi    sp, sp, 8
14212771Sqtt2@cornell.edu
14312771Sqtt2@cornell.edu  // decrement the number of threads to wait for
14412771Sqtt2@cornell.edu  addi    t0, t0, -1
14512771Sqtt2@cornell.edu  bnez    t0, 1b
14612771Sqtt2@cornell.edu
14712771Sqtt2@cornell.edu  // finish checking all threads
14812771Sqtt2@cornell.edu  mv      ra, s0                  // restore return register
14912771Sqtt2@cornell.edu  mv      sp, s1                  // restore stack pointer
15012771Sqtt2@cornell.edu  ret
15112771Sqtt2@cornell.edu
15212771Sqtt2@cornell.edu_fail:
15312771Sqtt2@cornell.edu  li        a0, FAILURE
15412771Sqtt2@cornell.edu  RVTEST_CODE_END
15512771Sqtt2@cornell.edu
15612771Sqtt2@cornell.edu  .data
15712771Sqtt2@cornell.edu
15812771Sqtt2@cornell.eduMT_DATA
159