Huint _arch_setup_thread( Huint th, hthread_thread_t *thread, hthread_start_t start, void *arg ) { void *stack; ppc405_context_t *context; context_entry_t * ppc405_context_table = (context_entry_t *) _vhwti_context_table_ptr_field(); Huint target_bootstrap_thread = (Huint)_vhwti_bootstrap_field(); // Create a new context for the thread (return an error if we couldn't) //context = (ppc405_context_t*)malloc( sizeof(ppc405_context_t) ); //if( context == NULL ) return ENOMEM; context = &ppc405_context_table[ (Huint)th ]; // Store the pointer to the context into the thread's context pointer thread->context = context; // On the PPC405 the stack works from the bottom up. Thus, here we move the // stack pointer to the end of the stack. When doing this it is important for // us to reserve a frame on the stack for the compiler to use. stack = thread->stack; stack += thread->stacksize; stack -= HTHREAD_STACK_RESERVE; // The first four bytes of the context point to the memory that stores the // contents of the registers during a context switch (required by context switcher) context->address = (Huint)(&context->regs); // At the end of a context switch a branch to link register is performed. // In order to start the correct function we must place the function's address // in the link register so that the context switcher will branch to it. // // The hthread's system requires that all threads be bootstrapped by a function // called "_bootstrap_thread". Thus, this code places the address of the // bootstrap function into the link register. //context->regs[PPC405_LR] = (Huint)_bootstrap_thread; context->regs[PPC405_LR] = (Huint)target_bootstrap_thread; // FIXME - weird, but we need to use the heterogeneous version of bootstrap so that the destination processor can understand it // By default, when a thread is started, interrupts are enabled. This is done by // setting the enable interrupts bit in the machine state register on the PPC405 context->regs[PPC405_MSR] = MSR_CE | MSR_EE | MSR_ME ; // | MSR_PR; // Setup MSR bits to forward all data TLB entries to TS = 1 // Setup MSR bits to forward all instruction TLB entries to TS = 0 context->regs[PPC405_MSR] = context->regs[PPC405_MSR] | MSR_DR ; // If the thread has a stack then store it into the PPC's stack pointer register // If the thread we are setting up has a stack then we need to store the pointer // to the stack in the PPC405's GPR1 register. if( thread->stacksize > 0 ) context->regs[PPC405_GPR1] = (Huint)stack; // The function which bootstraps threads requires two arguments. The first argument // if the address of the function to bootstrap. The second argument is the // argument that is given to the function being bootstrapped. In order to pass // these two arguments to the bootstrap function we must storethen into // GPR3 and GPR4. context->regs[PPC405_GPR3] = (Huint)start; context->regs[PPC405_GPR4] = (Huint)arg; // At this point the function was completed successfully. return SUCCESS; }
Huint _setup_thread( Huint tid, hthread_attr_t *attr, hthread_start_t start, void *arg ) { Huint base; void *stack; hthread_stack_t * global_stack_ptr = (hthread_stack_t *)_vhwti_stack_ptr_field(); hthread_thread_t * global_context_ptr =(hthread_thread_t *) _vhwti_context_ptr_field(); context_entry_t * global_context_table_ptr = (context_entry_t *) _vhwti_context_table_ptr_field(); hthread_thread_t * threads = (hthread_thread_t *)global_context_ptr; // Make sure that the thread id is valid if( tid < 0 || tid >= MAX_THREADS) { DEBUG_PRINTF( "SETUP: (ERR=INVALID TID) (TID=%d)\n", tid ); return EINVAL; } // By default use the stack given to us stack = attr->stack_addr; // If the thread has not allocated its own stack then we need to allocate one if( stack == NULL && attr->hardware != Htrue ) { // Make sure that the stack space requested is reasonable if( attr->stack_size <= HTHREAD_STACK_MIN ) { DEBUG_PRINTF( "SETUP: (ERR=INVALID STACK SIZE) (SIZE=%d)\n", attr->stack_size ); return EINVAL; } // Allocate the stack space for the thread //stack = (void*)malloc( attr->stack_size ); // Allocate in statically allocated region stored in global stack pointer stack = (void*)&global_stack_ptr[tid]; #ifdef HTHREADS_SMP // If multiple CPU's, might need to attemp malloc more than once // because of plb issues? while( stack == NULL ) { //stack = (void*)malloc( attr->stack_size ); // Allocate in statically allocated region stored in global stack pointer stack = (void*)&global_stack_ptr[tid]; } #endif // Check that the stack allocation was successful if( stack == NULL ) { DEBUG_PRINTF( "SETUP: (ERR=NO STACK MEMORY)\n" ); return ENOMEM; } } // Store the allocated stack into the threads stack pointer threads[ tid ].stack = stack; // Store the size of the allocated stack into the thread's context threads[ tid ].stacksize = attr->stack_size; // Setup the thread to be a new thread threads[ tid ].newthread = Htrue; // Initialize retval to be NULL threads[ tid ].retval = NULL; // Initialize execution time to 0 threads[ tid ].execution_time = 0; // Determine if the new thread is a hardware thread if( attr->hardware != Htrue ) { // The thread is not a hardware thread so store that information threads[ tid ].hardware = 0x00000000; // Have the architecture perform its setup. return _arch_setup_thread(tid, &threads[tid], start, arg); //return SUCCESS; } else { // Commented out by Jason, as this upsets thread creation times by a large factor //DEBUG_PRINTF( "SETUP: (STA=HARDWARE)\n" ); // Subtracting the offset to the command register we can get the base // address for all of the thread's other registers. base = attr->hardware_addr - HT_HWTI_COMMAND_OFFSET; // Reset the hardware thread interface to prepare for its use _hwti_reset( base ); // Tell the hardware thread what its thread id is _hwti_setid( base, tid ); // Tell the hardware thread what its thread argument is _hwti_setarg( base, (Huint)arg ); // Tell the hardware thread what its function pointer is (added by Jason for MicroBlaze-based HW threads) _hwti_set_fcn_ptr( base, (Huint)start ); // Tell the hardware thread where the global thread stack array and global thread context array are located (added by Jason for MicroBlaze-base d HW threads) _hwti_set_global_context_ptr( base, (Huint)global_context_ptr ); _hwti_set_global_stack_ptr( base, (Huint)global_stack_ptr ); _hwti_set_global_context_table_ptr( base, (Huint)global_context_table_ptr); _hwti_set_bootstrap_ptr(base, (Huint)_bootstrap_thread); // The thread is a hardware thread so store that information threads[ tid ].hardware = attr->hardware_addr; // Return a success indication return SUCCESS; } }