Example #1
0
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;
}
Example #2
0
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;
    }
}