Skip to content

Commit 51ff62c

Browse files
authored
Merge pull request #298 from tactcomplabs/fix_stack_thread_allocation
Fix stack and thread local storage allocation
2 parents 1590af2 + b604229 commit 51ff62c

File tree

8 files changed

+90
-33
lines changed

8 files changed

+90
-33
lines changed

include/RevCPU.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,6 @@ class RevCPU : public SST::Component {
235235
// - Handles updating LSQueue & MarkLoadComplete function pointers
236236
void AssignThread( std::unique_ptr<RevThread>&& ThreadToAssign, unsigned ProcID );
237237

238-
// Sets up arguments for a thread with a given ID and feature set.
239-
void SetupArgs( const std::unique_ptr<RevRegFile>& RegFile );
240-
241238
// Checks the status of ALL threads that are currently blocked.
242239
void CheckBlockedThreads();
243240

include/RevRegFile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ inline void BoxNaN( double* dest, const float* value ) {
4545
enum class RevReg : uint16_t {
4646
zero = 0, ra = 1, sp = 2, gp = 3, tp = 4, t0 = 5, t1 = 6, t2 = 7,
4747
s0 = 8, s1 = 9, a0 = 10, a1 = 11, a2 = 12, a3 = 13, a4 = 14, a5 = 15,
48+
fp = 8,
4849
a6 = 16, a7 = 17, s2 = 18, s3 = 19, s4 = 20, s5 = 21, s6 = 22, s7 = 23,
4950
s8 = 24, s9 = 25, s10 = 26, s11 = 27, t3 = 28, t4 = 29, t5 = 30, t6 = 31,
5051
ft0 = 0, ft1 = 1, ft2 = 2, ft3 = 3, ft4 = 4, ft5 = 5, ft6 = 6, ft7 = 7,

src/RevCPU.cc

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -694,10 +694,12 @@ bool RevCPU::clockTick( SST::Cycle_t currentCycle ) {
694694
void RevCPU::InitThread( std::unique_ptr<RevThread>&& ThreadToInit ) {
695695
// Get a pointer to the register state for this thread
696696
std::unique_ptr<RevRegFile> RegState = ThreadToInit->TransferVirtRegState();
697+
697698
// Set the global pointer register and the frame pointer register
698699
auto gp = Loader->GetSymbolAddr( "__global_pointer$" );
699700
RegState->SetX( RevReg::gp, gp );
700-
RegState->SetX( RevReg::s0, gp ); // s0 = x8 = frame pointer register
701+
RegState->SetX( RevReg::fp, gp );
702+
701703
// Set state to Ready
702704
ThreadToInit->SetState( ThreadState::READY );
703705
output.verbose( CALL_INFO, 4, 0, "Initializing Thread %" PRIu32 "\n", ThreadToInit->GetID() );
@@ -754,18 +756,6 @@ void RevCPU::CheckBlockedThreads() {
754756
return;
755757
}
756758

757-
// ----------------------------------
758-
// We need to initialize the x10 register to include the value of
759-
// ARGC. This is >= 1 (the executable name is always included).
760-
// We also need to initialize the ARGV pointer to the value
761-
// of the ARGV base pointer in memory which is currently set to
762-
// the top of stack.
763-
// ----------------------------------
764-
void RevCPU::SetupArgs( const std::unique_ptr<RevRegFile>& RegFile ) {
765-
RegFile->SetX( RevReg::a0, Opts->GetArgv().size() + 1 );
766-
RegFile->SetX( RevReg::a1, Mem->GetStackTop() );
767-
}
768-
769759
// Checks core 'i' to see if it has any available harts to assign work to
770760
// if it does and there is work to assign (ie. ReadyThreads is not empty)
771761
// assign it and enable the processor if not already enabled.
@@ -860,14 +850,35 @@ void RevCPU::HandleThreadStateChangesForProc( uint32_t ProcID ) {
860850
}
861851

862852
void RevCPU::InitMainThread( uint32_t MainThreadID, const uint64_t StartAddr ) {
863-
// @Lee: Is there a better way to get the feature info?
864-
std::unique_ptr<RevRegFile> MainThreadRegState = std::make_unique<RevRegFile>( Procs[0] );
853+
auto MainThreadRegState = std::make_unique<RevRegFile>( Procs[0] );
854+
855+
// The Program Counter gets set to the start address
865856
MainThreadRegState->SetPC( StartAddr );
866-
MainThreadRegState->SetX( RevReg::tp, Mem->GetThreadMemSegs().front()->getTopAddr() );
867-
MainThreadRegState->SetX( RevReg::sp, Mem->GetThreadMemSegs().front()->getTopAddr() - Mem->GetTLSSize() );
868-
MainThreadRegState->SetX( RevReg::gp, Loader->GetSymbolAddr( "__global_pointer$" ) );
869-
MainThreadRegState->SetX( 8, Loader->GetSymbolAddr( "__global_pointer$" ) );
870-
SetupArgs( MainThreadRegState );
857+
858+
// We need to initialize the a0 register to the value of ARGC.
859+
// This is >= 1 (the executable name is always included).
860+
// We also need to initialize the a1 register to the ARGV pointer
861+
// of the ARGV base pointer in memory which is currently set to
862+
// the top of stack.
863+
uint64_t stackTop = Mem->GetStackTop();
864+
MainThreadRegState->SetX( RevReg::a0, Opts->GetArgv().size() + 1 );
865+
MainThreadRegState->SetX( RevReg::a1, stackTop );
866+
867+
// We subtract Mem->GetTLSSize() bytes from the current stack top, and
868+
// round down to a multiple of 16 bytes. We set it as the new top of stack.
869+
stackTop = ( stackTop - Mem->GetTLSSize() ) & ~uint64_t{ 15 };
870+
Mem->SetStackTop( stackTop );
871+
872+
// We set the stack pointer and the thread pointer to the new stack top
873+
// The thread local storage is accessed with a nonnegative offset from tp,
874+
// and the stack grows down with sp being subtracted from before storing.
875+
MainThreadRegState->SetX( RevReg::sp, stackTop );
876+
MainThreadRegState->SetX( RevReg::tp, stackTop );
877+
878+
auto gp = Loader->GetSymbolAddr( "__global_pointer$" );
879+
MainThreadRegState->SetX( RevReg::gp, gp );
880+
MainThreadRegState->SetX( RevReg::fp, gp );
881+
871882
std::unique_ptr<RevThread> MainThread = std::make_unique<RevThread>(
872883
MainThreadID,
873884
_INVALID_TID_, // No Parent Thread ID

src/RevCore.cc

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,25 +1916,30 @@ RevRegFile* RevCore::GetRegFile( unsigned HartID ) const {
19161916
void RevCore::CreateThread( uint32_t NewTID, uint64_t firstPC, void* arg ) {
19171917
// tidAddr is the address we have to write the new thread's id to
19181918
output->verbose( CALL_INFO, 2, 0, "Creating new thread with PC = 0x%" PRIx64 "\n", firstPC );
1919-
uint32_t ParentThreadID = Harts.at( HartToExecID )->GetAssignedThreadID();
1919+
uint32_t ParentThreadID = Harts.at( HartToExecID )->GetAssignedThreadID();
19201920

19211921
// Create the new thread's memory
1922-
std::shared_ptr<MemSegment> NewThreadMem = mem->AddThreadMem();
1922+
std::shared_ptr<MemSegment> NewThreadMem = mem->AddThreadMem();
19231923

19241924
// TODO: Copy TLS into new memory
19251925

19261926
// Create new register file
1927-
std::unique_ptr<RevRegFile> NewThreadRegFile = std::make_unique<RevRegFile>( this );
1927+
auto NewThreadRegFile = std::make_unique<RevRegFile>( this );
19281928

19291929
// Copy the arg to the new threads a0 register
19301930
NewThreadRegFile->SetX( RevReg::a0, reinterpret_cast<uintptr_t>( arg ) );
19311931

1932+
// Set the stack and thread pointer
1933+
// The thread local storage is accessed with a nonnegative offset from tp,
1934+
// and the stack grows down with sp being subtracted from before storing.
1935+
uint64_t sp = ( NewThreadMem->getTopAddr() - mem->GetTLSSize() ) & ~uint64_t{ 15 };
1936+
NewThreadRegFile->SetX( RevReg::tp, sp );
1937+
NewThreadRegFile->SetX( RevReg::sp, sp );
1938+
19321939
// Set the global pointer
1933-
// TODO: Cleanup
1934-
NewThreadRegFile->SetX( RevReg::tp, NewThreadMem->getTopAddr() );
1935-
NewThreadRegFile->SetX( RevReg::sp, NewThreadMem->getTopAddr() - mem->GetTLSSize() );
1936-
NewThreadRegFile->SetX( RevReg::gp, loader->GetSymbolAddr( "__global_pointer$" ) );
1937-
NewThreadRegFile->SetX( RevReg::s0, loader->GetSymbolAddr( "__global_pointer$" ) );
1940+
auto gp = loader->GetSymbolAddr( "__global_pointer$" );
1941+
NewThreadRegFile->SetX( RevReg::gp, gp );
1942+
NewThreadRegFile->SetX( RevReg::fp, gp ); // frame pointer register
19381943
NewThreadRegFile->SetPC( firstPC );
19391944

19401945
// Create a new RevThread Object

src/RevLoader.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,8 +478,8 @@ bool RevLoader::LoadProgramArgs( const std::string& exe, const std::vector<std::
478478
//
479479
// Each string that argv[i] points to starts at an address which is a multiple of XLEN.
480480
//
481-
// Finally, in RevCPU::SetupArgs(), we initialize the a0 register to the value of argc
482-
// and the a1 register to the base pointer to argv.
481+
// Finally, in RevCPU::InitMainThread(), we initialize the a0 register to the value of
482+
// argc and the a1 register to the base pointer to argv.
483483
// -------------- END MEMORY LAYOUT NOTES
484484

485485
// Allocate sizeof(XLEN) bytes for each of the argv[] pointers

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ add_rev_test(ARGC_SHORT argc_short 30 "test_level=2;memh;rv64;loader;" SCRIPT "r
230230
add_rev_test(ARGV argv 30 "test_level=2;memh;rv64;loader;c++" SCRIPT "run_argv.sh")
231231
add_rev_test(ARGV_layout argv_layout 30 "test_level=2;memh;rv32;loader;" SCRIPT "run_argv_layout.sh")
232232
add_rev_test(ARGV_limit argv_limit 75 "test_level=2;memh;rv32;loader;" SCRIPT "run_argv_limit.sh")
233+
add_rev_test(ARGV_stack argv_stack 10 "memh;rv64")
233234
add_rev_test(COPROC_EX coproc_ex 30 "memh;rv64;coproc" SCRIPT "run_coproc_ex.sh")
234235

235236
if(TEST_LEVEL GREATER_EQUAL 2)

test/argv_stack/Makefile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#
2+
# Makefile
3+
#
4+
# makefile: argv_stack
5+
#
6+
# Copyright (C) 2017-2024 Tactical Computing Laboratories, LLC
7+
# All Rights Reserved
8+
9+
#
10+
# See LICENSE in the top level directory for licensing details
11+
#
12+
13+
.PHONY: src
14+
15+
EXAMPLE=argv_stack
16+
CC=${RVCC}
17+
ARCH=rv64imafdc
18+
19+
all: $(EXAMPLE).exe
20+
$(EXAMPLE).exe: $(EXAMPLE).c
21+
$(CC) -march=$(ARCH) -O3 -static -o $(EXAMPLE).exe $(EXAMPLE).c
22+
clean:
23+
rm -Rf $(EXAMPLE).exe
24+
25+
#-- EOF

test/argv_stack/argv_stack.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* argv_stack.c
3+
*
4+
* Copyright (C) 2017-2024 Tactical Computing Laboratories, LLC
5+
* All Rights Reserved
6+
7+
*
8+
* See LICENSE in the top level directory for licensing details
9+
*
10+
*/
11+
12+
int main( int argc, char** argv ) {
13+
char a[1024];
14+
if( a + sizeof( a ) > (char*) argv )
15+
asm( ".word 0" );
16+
return 0;
17+
}

0 commit comments

Comments
 (0)