This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
RE: Multi thread Debugging
- To: 'Nick Garnett' <nickg at cygnus dot co dot uk>, ecos-discuss at sourceware dot cygnus dot com
- Subject: RE: [ECOS] Multi thread Debugging
- From: Fabrice Gautier <Fabrice_Gautier at sdesigns dot com>
- Date: Thu, 31 Aug 2000 18:53:33 -0700
Hi,
> -----Original Message-----
> From: Nick Garnett [mailto:nickg@cygnus.co.uk]
> Sent: Thursday, August 31, 2000 4:08 AM
> To: ecos-discuss@sourceware.cygnus.com
> Subject: Re: [ECOS] Multi thread Debugging
>
> All your observations are correct. The main problem is that thread
> saved contexts and interrupt saved contexts are different. In all
> other HALs they are the same. I suspect that the simplest fix for now
> is to change the format of the HAL_SavedRegisters structure to echo
> that pushed by "pusha" and replace the "movl"s in context.S with
> "pusha" and "popa".
I'm testing some changes like this. It seems to work with the HAL context.c
test, but with a more complicated program I've some strange crash I didn't
have before.
The program ends with an exception (SIGSEGV, SIGILL or SIGTRAP) and it seems
this is during a thread switch.
I suspect that in some cases the changes I've made may be unsafe. I'm not
sure if the switch context function have to be re-entrant it is safe to
assume that a context switch can't be interrupted by another context switch?
One main difference between my new version and the current version is that
the next context ptr is not saved as a part of the SavedRegisters structure.
So this pointer is pushed on the stack (as a parameter for
hal_thread_load_context) AFTER the current thread stack pointer has been
saved. So if another context switch occurs at this time I suppose the saved
context will be corrupted.
I post here the modifications I've made:
First the HAL_SavedRegisters structure:
=======================================
typedef struct
{
cyg_uint32 edi;
cyg_uint32 esi;
cyg_uint32 ebp;
cyg_uint32 esp;
cyg_uint32 ebx;
cyg_uint32 edx;
cyg_uint32 ecx;
cyg_uint32 eax;
cyg_uint32 vector; // if saved on interrupt contains intr vector
cyg_uint32 eip;
cyg_uint32 arg1; // cs (when intr) or parameter
cyg_uint32 arg2; // eflags (when intr) or parameter
} HAL_SavedRegisters;
*******************************************************
Then the context init routine:
==============================
//--------------------------------------------------------------------------
---
// Context Initialization
// Initialize the context of a thread.
// Arguments:
// _sp_ name of variable containing current sp, will be written with new sp
// _thread_ thread object address, passed as argument to entry point
// _entry_ entry point address.
// _id_ bit pattern used in initializing registers, for debugging.
#define HAL_THREAD_INIT_CONTEXT( _sparg_, _thread_, _entry_, _id_ ) \
CYG_MACRO_START \
register CYG_WORD* _sp_ = ((CYG_WORD*)((_sparg_) &~15)); \
register HAL_SavedRegisters *_regs_; \
\
/* The 'ret' executed at the end of hal_thread_load_context will */ \
/* use the last entry on the stack as a return pointer (_entry_). */ \
/* Cyg_HardwareThread::thread_entry expects one argument at stack */ \
/* offset 4 (_thread_). The (0xDEADBEEF) entry is the return addr */ \
/* for thread_entry (which is never used). */ \
*(--_sp_) = (CYG_WORD)(0); \
*(--_sp_) = (CYG_WORD)(0); \
*(--_sp_) = (CYG_WORD)(0); \
*(--_sp_) = (CYG_WORD)(0); \
\
_regs_ = (HAL_SavedRegisters *) \
((unsigned long)_sp_ - sizeof(HAL_SavedRegisters)); \
_regs_->arg2 = (CYG_WORD)(_thread_); \
_regs_->arg1 = (CYG_WORD)(0); \
_regs_->eip = (CYG_WORD)(_entry_); \
_regs_->vector = (CYG_WORD)(_id_); \
_sp_-=4; \
_regs_->esp = (CYG_WORD) _sp_; \
_regs_->ebp = (CYG_WORD)(_id_); \
_regs_->esi = (CYG_WORD)(_id_); \
_regs_->edi = (CYG_WORD)(_id_); \
_regs_->eax = (CYG_WORD)(_id_); \
_regs_->ebx = (CYG_WORD)(_id_); \
_regs_->ecx = (CYG_WORD)(_id_); \
_regs_->edx = (CYG_WORD)(_id_); \
(_sparg_) = (CYG_ADDRESS) _regs_; \
CYG_MACRO_END
*******************************************************
And the switch routine:
=======================
#---------------------------------------------------------------------------
---
# hal_thread_switch_context
# Switch thread contexts
# : 0(%esp) : return address
# : 4(%esp) : address of sp of next thread to execute
# : 8(%esp) : address of sp save location of current thread
#
# %eax, %ecx, and %edx are ours to abuse.
FUNC_START(hal_thread_switch_context)
# movl 4(%esp),%eax # next context ptr
# movl 8(%esp),%edx # this context ptr
popl %ebx # save return eip
popl %eax # get next context ptr
popl %edx # get this context ptr
# Save context
pushfl # save eflags
pushw %cs # save cs
pushw 0 # and pad to 32 bits
pushl %ebx # save eip
pushl $0xdeaddead # push vector
pusha # push general registers
# Save next context ptr in this context. Necessary because
# hal_thread_load_context expects to find the ptr on the stack,
# not in a register as on PPC.
# Store the context ptr
movl %esp,(%edx)
#push next context ptr as an argument to load context
pushl %eax
pushl $0xdeadbeef # load_context return pointer, never used
# Now fall through to hal_thread_load_context
#---------------------------------------------------------------------------
---
# hal_thread_load_context
# Load thread context
# : 4(%esp) (!= i386reg_next_context(%esp)) = address of sp of thread to
execute
# Note that this function is also the second half of
hal_thread_switch_context
# and is simply dropped into from it.
#
# %eax, %ecx, and %edx are ours to abuse.
FUNC_START(hal_thread_load_context)
#ifdef CYGHWR_HAL_I386_FPU
movl %cr0, %eax
orl $0x8, %eax
movl %eax, %cr0
#endif
movl 4(%esp),%eax # get new context ptr
movl (%eax),%esp
popal # unstack general registers
popl %ebx # unstack vector (should be 0xdeaddead)
ret