test/svc: add test for thread create

This commit is contained in:
Michael Scire 2021-11-08 13:29:00 -08:00
parent 21b7884653
commit 1d39e06f32
3 changed files with 109 additions and 1 deletions

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ams::test::TestThreadCreateRegistersOnFunctionEntry(void *ctx) */
.section .text._ZN3ams4test40TestThreadCreateRegistersOnFunctionEntryEPv, "ax", %progbits
.global _ZN3ams4test40TestThreadCreateRegistersOnFunctionEntryEPv
.type _ZN3ams4test40TestThreadCreateRegistersOnFunctionEntryEPv, %function
_ZN3ams4test40TestThreadCreateRegistersOnFunctionEntryEPv:
/* Save all registers to our context. */
stp x0, x1, [x0, #0x00]
stp x2, x3, [x0, #0x10]
stp x4, x5, [x0, #0x20]
stp x6, x7, [x0, #0x30]
stp x8, x9, [x0, #0x40]
stp x10, x11, [x0, #0x50]
stp x12, x13, [x0, #0x60]
stp x14, x15, [x0, #0x70]
stp x16, x17, [x0, #0x80]
stp x18, x19, [x0, #0x90]
stp x20, x21, [x0, #0xA0]
stp x22, x23, [x0, #0xB0]
stp x24, x25, [x0, #0xC0]
stp x26, x27, [x0, #0xD0]
stp x28, x29, [x0, #0xE0]
mov x1, sp
stp x30, x1, [x0, #0xF0]
/* Exit the thread. */
svc 0xa

View file

@ -0,0 +1,65 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#include "util_common.hpp"
#include "util_scoped_heap.hpp"
namespace ams::test {
void TestThreadCreateRegistersOnFunctionEntry(void *ctx);
DOCTEST_TEST_CASE( "Creating a thread results in fixed register contents." ) {
/* Create heap. */
ScopedHeap heap(os::MemoryPageSize);
/* Create register buffer. */
u64 thread_registers[32];
std::memset(thread_registers, 0xCC, sizeof(thread_registers));
/* Create thread. */
svc::Handle thread_handle;
DOCTEST_CHECK(R_SUCCEEDED(svc::CreateThread(std::addressof(thread_handle), reinterpret_cast<uintptr_t>(&TestThreadCreateRegistersOnFunctionEntry), reinterpret_cast<uintptr_t>(thread_registers), heap.GetAddress() + os::MemoryPageSize, HighestTestPriority, NumCores - 1)));
/* Start thread. */
DOCTEST_CHECK(R_SUCCEEDED(svc::StartThread(thread_handle)));
/* Wait for thread to exit. */
s32 dummy;
DOCTEST_CHECK(R_SUCCEEDED(svc::WaitSynchronization(std::addressof(dummy), std::addressof(thread_handle), 1, -1)));
/* Close thread handle. */
DOCTEST_CHECK(R_SUCCEEDED(svc::CloseHandle(thread_handle)));
/* Check thread initial registers. */
for (size_t i = 0; i < util::size(thread_registers); ++i) {
if (i == 0) {
/* X0 is argument. */
DOCTEST_CHECK(thread_registers[i] == reinterpret_cast<uintptr_t>(thread_registers));
} else if (i == 18) {
/* X18 is an odd cfi value. */
DOCTEST_CHECK(thread_registers[i] != 0);
DOCTEST_CHECK((thread_registers[i] & 0x1) != 0);
} else if (i == 31) {
/* SP is user-provided sp. */
DOCTEST_CHECK(thread_registers[i] == (heap.GetAddress() + os::MemoryPageSize));
} else {
/* All other registers are zero. */
DOCTEST_CHECK(thread_registers[i] == 0);
}
}
}
}

View file

@ -46,7 +46,7 @@ namespace ams::test {
/* Wait long enough that we can be confident preemption will occur, and therefore our interrupt flag will be set. */
{
constexpr auto MinimumTicksToGuaranteeInterruptFlag = ::ams::svc::Tick(PreemptionTimeSpan) + 1;
constexpr auto MinimumTicksToGuaranteeInterruptFlag = ::ams::svc::Tick(PreemptionTimeSpan) + ::ams::svc::Tick(PreemptionTimeSpan) + 2;
auto GetSystemTickForPinnedThread = []() ALWAYS_INLINE_LAMBDA -> ::ams::svc::Tick {
s64 v;