SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2000-2004, The KOS team
002    Copyright (C) 1999  Free Software Foundation, Inc.
003 
004    This program is free software; you can redistribute it and/or
005    modify it under the terms of the GNU General Public License
006    as published by the Free Software Foundation; either version 2
007    of the License, or (at your option) any later version.
008    
009    This program is distributed in the hope that it will be useful,
010    but WITHOUT ANY WARRANTY; without even the implied warranty of
011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012    GNU General Public License for more details.
013    
014    You should have received a copy of the GNU General Public License
015    along with this program; if not, write to the Free Software
016    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
017    USA. 
018 */
019 
020 
021 #include <sos/assert.h>
022 #include <sos/klibc.h>
023 #include <drivers/bochs.h>
024 #include <drivers/x86_videomem.h>
025 #include <hwcore/segment.h>
026 
027 #include "cpu_context.h"
028 
029 
030 /**
031  * Here is the definition of a CPU context for IA32 processors. This
032  * is a SOS convention, not a specification given by the IA32
033  * spec. However there is a strong constraint related to the x86
034  * interrupt handling specification: the top of the stack MUST be
035  * compatible with the 'iret' instruction, ie there must be the
036  * err_code (might be 0), eip, cs and eflags of the destination
037  * context in that order (see Intel x86 specs vol 3, figure 5-4).
038  *
039  * @note IMPORTANT: This definition MUST be consistent with the way
040  * the registers are stored on the stack in
041  * irq_wrappers.S/exception_wrappers.S !!! Hence the constraint above.
042  */
043 struct sos_cpu_kstate {
044   /* (Lower addresses) */
045 
046   /* These are SOS convention */
047   sos_ui16_t  gs;
048   sos_ui16_t  fs;
049   sos_ui16_t  es;
050   sos_ui16_t  ds;
051   sos_ui16_t  ss;
052   sos_ui16_t  alignment_padding; /* unused */
053   sos_ui32_t  eax;
054   sos_ui32_t  ebx;
055   sos_ui32_t  ecx;
056   sos_ui32_t  edx;
057   sos_ui32_t  esi;
058   sos_ui32_t  edi;
059   sos_ui32_t  ebp;
060 
061   /* MUST NEVER CHANGE (dependent on the IA32 iret instruction) */
062   sos_ui32_t  error_code;
063   sos_vaddr_t eip;
064   sos_ui32_t  cs;
065   sos_ui32_t  eflags;
066 
067   /* (Higher addresses) */
068 } __attribute__((packed));
069 
070 
071 static void core_routine (sos_cpu_kstate_function_arg1_t *start_func,
072                           sos_ui32_t start_arg,
073                           sos_cpu_kstate_function_arg1_t *exit_func,
074                           sos_ui32_t exit_arg)
075      __attribute__((noreturn));
076 
077 static void core_routine (sos_cpu_kstate_function_arg1_t *start_func,
078                           sos_ui32_t start_arg,
079                           sos_cpu_kstate_function_arg1_t *exit_func,
080                           sos_ui32_t exit_arg)
081 {
082   start_func(start_arg);
083   exit_func(exit_arg);
084 
085   SOS_ASSERT_FATAL(! "The exit function of the thread should NOT return !");
086   for(;;);
087 }
088 
089 
090 sos_ret_t sos_cpu_kstate_init(struct sos_cpu_kstate **ctxt,
091                               sos_cpu_kstate_function_arg1_t *start_func,
092                               sos_ui32_t  start_arg,
093                               sos_vaddr_t stack_bottom,
094                               sos_size_t  stack_size,
095                               sos_cpu_kstate_function_arg1_t *exit_func,
096                               sos_ui32_t  exit_arg)
097 {
098   /* This is a critical internal function, so that it is assumed that
099      the caller knows what he does: we legitimally assume that values
100      for ctxt, start_func, stack_* and exit_func are allways VALID ! */
101 
102   /* Setup the stack.
103    *
104    * On x86, the stack goes downward. Each frame is configured this
105    * way (higher addresses first):
106    *
107    *  - (optional unused space. As of gcc 3.3, this space is 24 bytes)
108    *  - arg n
109    *  - arg n-1
110    *  - ...
111    *  - arg 1
112    *  - return instruction address: The address the function returns to
113    *    once finished
114    *  - local variables
115    *
116    * The remaining of the code should be read from the end upward to
117    * understand how the processor will handle it.
118    */
119 
120   sos_vaddr_t tmp_vaddr = stack_bottom + stack_size;
121   sos_ui32_t *stack = (sos_ui32_t*)tmp_vaddr;
122 
123   /* If needed, poison the stack */
124 #ifdef SOS_CPU_KSTATE_DETECT_UNINIT_VARS
125   memset((void*)stack_bottom, SOS_CPU_KSTATE_STACK_POISON, stack_size);
126 #elif defined(SOS_CPU_KSTATE_DETECT_STACK_OVERFLOW)
127   sos_cpu_kstate_prepare_detect_stack_overflow(stack_bottom, stack_size);
128 #endif
129 
130   /* Simulate a call to the core_routine() function: prepare its
131      arguments */
132   *(--stack) = exit_arg;
133   *(--stack) = (sos_ui32_t)exit_func;
134   *(--stack) = start_arg;
135   *(--stack) = (sos_ui32_t)start_func;
136   *(--stack) = 0; /* Return address of core_routine => force page fault */
137 
138   /*
139    * Setup the initial context structure, so that the CPU will execute
140    * the function core_routine() once this new context has been
141    * restored on CPU
142    */
143 
144   /* Compute the base address of the structure, which must be located
145      below the previous elements */
146   tmp_vaddr  = ((sos_vaddr_t)stack) - sizeof(struct sos_cpu_kstate);
147   *ctxt = (struct sos_cpu_kstate*)tmp_vaddr;
148 
149   /* Initialize the CPU context structure */
150   memset(*ctxt, 0x0, sizeof(struct sos_cpu_kstate));
151 
152   /* Tell the CPU context structure that the first instruction to
153      execute will be that of the core_routine() function */
154   (*ctxt)->eip = (sos_ui32_t)core_routine;
155 
156   /* Setup the segment registers */
157   (*ctxt)->cs  = SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KCODE); /* Code */
158   (*ctxt)->ds  = SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA); /* Data */
159   (*ctxt)->es  = SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA); /* Data */
160   (*ctxt)->ss  = SOS_BUILD_SEGMENT_REG_VALUE(0, 0, SOS_SEG_KDATA); /* Stack */
161   /* fs and gs unused for the moment. */
162 
163   /* The newly created context is initially interruptible */
164   (*ctxt)->eflags = (1 << 9); /* set IF bit */
165 
166   return SOS_OK;
167 }
168 
169 
170 #if defined(SOS_CPU_KSTATE_DETECT_STACK_OVERFLOW)
171 void
172 sos_cpu_kstate_prepare_detect_stack_overflow(const struct sos_cpu_kstate *ctxt,
173                                              sos_vaddr_t stack_bottom,
174                                              sos_size_t stack_size)
175 {
176   sos_size_t poison_size = SOS_CPU_KSTATE_DETECT_STACK_OVERFLOW;
177   if (poison_size > stack_size)
178     poison_size = stack_size;
179 
180   memset((void*)stack_bottom, SOS_CPU_KSTATE_STACK_POISON, poison_size);
181 }
182 
183 
184 void
185 sos_cpu_kstate_detect_stack_overflow(const struct sos_cpu_kstate *ctxt,
186                                      sos_vaddr_t stack_bottom,
187                                      sos_size_t stack_size)
188 {
189   unsigned char *c;
190   int i;
191 
192   SOS_ASSERT_FATAL(((sos_vaddr_t)ctxt) >= stack_bottom);
193   SOS_ASSERT_FATAL(((sos_vaddr_t)ctxt) + sizeof(struct sos_cpu_kstate)
194                    <= stack_bottom + stack_size);
195   for (c = (unsigned char*) stack_bottom, i = 0 ;
196        (i < SOS_CPU_KSTATE_DETECT_STACK_OVERFLOW) && (i < stack_size) ;
197        c++, i++)
198     {
199       SOS_ASSERT_FATAL(SOS_CPU_KSTATE_STACK_POISON == *c);
200     }
201 }
202 #endif
203 
204 
205 sos_vaddr_t sos_cpu_kstate_get_PC(const struct sos_cpu_kstate *ctxt)
206 {
207   SOS_ASSERT_FATAL(NULL != ctxt);
208   return ctxt->eip;
209 }
210 
211 
212 sos_vaddr_t sos_cpu_kstate_get_SP(const struct sos_cpu_kstate *ctxt)
213 {
214   SOS_ASSERT_FATAL(NULL != ctxt);
215   return (sos_vaddr_t)ctxt;
216 }
217 
218 
219 void sos_cpu_kstate_dump(const struct sos_cpu_kstate *ctxt)
220 {
221   char buf[128];
222   snprintf(buf, sizeof(buf),
223            "CPU: eip=%x esp=%x eflags=%x cs=%x ds=%x ss=%x err=%x",
224            (unsigned)ctxt->eip, (unsigned)ctxt, (unsigned)ctxt->eflags,
225            (unsigned)ctxt->cs, (unsigned)ctxt->ds, (unsigned)ctxt->ss,
226            (unsigned)ctxt->error_code);
227   sos_bochs_putstring(buf); sos_bochs_putstring("\n");
228   sos_x86_videomem_putstring(23, 0,
229                           SOS_X86_VIDEO_FG_BLACK | SOS_X86_VIDEO_BG_LTGRAY,
230                           buf);
231 }
232 
233 
234 sos_ui32_t sos_cpu_kstate_get_EX_info(const struct sos_cpu_kstate *ctxt)
235 {
236   SOS_ASSERT_FATAL(NULL != ctxt);
237   return ctxt->error_code;
238 }
239 
240 
241 sos_vaddr_t
242 sos_cpu_kstate_get_EX_faulting_vaddr(const struct sos_cpu_kstate *ctxt)
243 {
244   sos_ui32_t cr2;
245 
246   /* See Intel Vol 3 (section 5.14): the address of the faulting
247      virtual address of a page fault is stored in the cr2 register */
248   asm volatile ("movl %%cr2, %0"
249                 :"=r"(cr2)
250                 : );
251 
252   return cr2;
253 }
254 
255 
256 sos_ui32_t sos_backtrace(const struct sos_cpu_kstate *cpu_kstate,
257                          sos_ui32_t max_depth,
258                          sos_vaddr_t stack_bottom,
259                          sos_size_t stack_size,
260                          sos_backtrace_callback_t * backtracer,
261                          void *custom_arg)
262 {
263   int depth;
264   sos_vaddr_t callee_PC, caller_frame;
265 
266   /*
267    * Layout of a frame on the x86 (compiler=gcc):
268    *
269    * funcA calls funcB calls funcC
270    *
271    *         ....
272    *         funcB Argument 2
273    *         funcB Argument 1
274    *         funcA Return eip
275    * frameB: funcA ebp (ie previous stack frame)
276    *         ....
277    *         (funcB local variables)
278    *         ....
279    *         funcC Argument 2
280    *         funcC Argument 1
281    *         funcB Return eip
282    * frameC: funcB ebp (ie previous stack frame == A0) <---- a frame address
283    *         ....
284    *         (funcC local variables)
285    *         ....
286    *
287    * The presence of "ebp" on the stack depends on 2 things:
288    *   + the compiler is gcc
289    *   + the source is compiled WITHOUT the -fomit-frame-pointer option
290    * In the absence of "ebp", chances are high that the value pushed
291    * at that address is outside the stack boundaries, meaning that the
292    * function will return -SOS_ENOSUP.
293    */
294 
295   if (cpu_kstate)
296     {
297       callee_PC    = cpu_kstate->eip;
298       caller_frame = cpu_kstate->ebp;
299     }
300   else
301     {
302       /* Skip the sos_backtrace() frame */
303       callee_PC    = (sos_vaddr_t)__builtin_return_address(0);
304       caller_frame = (sos_vaddr_t)__builtin_frame_address(1);
305     }
306 
307   for(depth=0 ; depth < max_depth ; depth ++)
308     {
309       /* Call the callback */
310       backtracer(callee_PC, caller_frame + 8, depth, custom_arg);
311 
312       /* If the frame address is funky, don't go further */
313       if ( (caller_frame < stack_bottom)
314            || (caller_frame + 4 >= stack_bottom + stack_size) )
315         return depth;
316 
317       /* Go to caller frame */
318       callee_PC    = *((sos_vaddr_t*) (caller_frame + 4));
319       caller_frame = *((sos_vaddr_t*) caller_frame);
320     }
321   
322   return depth;
323 }

source navigation ] diff markup ] identifier search ] general search ]