From mboxrd@z Thu Jan 1 00:00:00 1970 From: Fabrice Gautier To: 'Nick Garnett' , ecos-discuss@sourceware.cygnus.com Subject: RE: [ECOS] Multi thread Debugging Date: Thu, 31 Aug 2000 18:54:00 -0000 Message-id: <8AE4B526B977D411841F00A0CC334020052C3C@cuz-exchange.sdesigns.net> X-SW-Source: 2000-08/msg00396.html 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