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 ]

Diff markup

Differences between /hwcore/cpu_context.c (Article 7) and /hwcore/cpu_context.c (Article 8)


001 /* Copyright (C) 2005  David Decotigny            001 /* Copyright (C) 2005  David Decotigny
002    Copyright (C) 2000-2004, The KOS team          002    Copyright (C) 2000-2004, The KOS team
003                                                   003 
004    This program is free software; you can redi    004    This program is free software; you can redistribute it and/or
005    modify it under the terms of the GNU Genera    005    modify it under the terms of the GNU General Public License
006    as published by the Free Software Foundatio    006    as published by the Free Software Foundation; either version 2
007    of the License, or (at your option) any lat    007    of the License, or (at your option) any later version.
008                                                   008    
009    This program is distributed in the hope tha    009    This program is distributed in the hope that it will be useful,
010    but WITHOUT ANY WARRANTY; without even the     010    but WITHOUT ANY WARRANTY; without even the implied warranty of
011    MERCHANTABILITY or FITNESS FOR A PARTICULAR    011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012    GNU General Public License for more details    012    GNU General Public License for more details.
013                                                   013    
014    You should have received a copy of the GNU     014    You should have received a copy of the GNU General Public License
015    along with this program; if not, write to t    015    along with this program; if not, write to the Free Software
016    Foundation, Inc., 59 Temple Place - Suite 3    016    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
017    USA.                                           017    USA. 
018 */                                                018 */
019                                                   019 
020                                                   020 
021 #include <sos/assert.h>                           021 #include <sos/assert.h>
022 #include <sos/klibc.h>                            022 #include <sos/klibc.h>
023 #include <drivers/bochs.h>                        023 #include <drivers/bochs.h>
024 #include <drivers/x86_videomem.h>                 024 #include <drivers/x86_videomem.h>
025 #include <hwcore/segment.h>                       025 #include <hwcore/segment.h>
026 #include <hwcore/gdt.h>                           026 #include <hwcore/gdt.h>
027 #include <sos/uaccess.h>                          027 #include <sos/uaccess.h>
028                                                   028 
029 #include "cpu_context.h"                          029 #include "cpu_context.h"
030                                                   030 
031                                                   031 
032 /**                                               032 /**
033  * Here is the definition of a CPU context for    033  * Here is the definition of a CPU context for IA32 processors. This
034  * is a SOS convention, not a specification gi    034  * is a SOS convention, not a specification given by the IA32
035  * spec. However there is a strong constraint     035  * spec. However there is a strong constraint related to the x86
036  * interrupt handling specification: the top o    036  * interrupt handling specification: the top of the stack MUST be
037  * compatible with the 'iret' instruction, ie     037  * compatible with the 'iret' instruction, ie there must be the
038  * err_code (might be 0), eip, cs and eflags o    038  * err_code (might be 0), eip, cs and eflags of the destination
039  * context in that order (see Intel x86 specs     039  * context in that order (see Intel x86 specs vol 3, figure 5-4).
040  *                                                040  *
041  * @note IMPORTANT: This definition MUST be co    041  * @note IMPORTANT: This definition MUST be consistent with the way
042  * the registers are stored on the stack in       042  * the registers are stored on the stack in
043  * irq_wrappers.S/exception_wrappers.S !!! Hen    043  * irq_wrappers.S/exception_wrappers.S !!! Hence the constraint above.
044  */                                               044  */
045 struct sos_cpu_state {                            045 struct sos_cpu_state {
046   /* (Lower addresses) */                         046   /* (Lower addresses) */
047                                                   047 
048   /* These are SOS convention */                  048   /* These are SOS convention */
049   sos_ui16_t  gs;                                 049   sos_ui16_t  gs;
050   sos_ui16_t  fs;                                 050   sos_ui16_t  fs;
051   sos_ui16_t  es;                                 051   sos_ui16_t  es;
052   sos_ui16_t  ds;                                 052   sos_ui16_t  ds;
053   sos_ui16_t  cpl0_ss; /* This is ALWAYS the S    053   sos_ui16_t  cpl0_ss; /* This is ALWAYS the Stack Segment of the
054                           Kernel context (CPL0    054                           Kernel context (CPL0) of the interrupted
055                           thread, even for a u    055                           thread, even for a user thread */
056   sos_ui16_t  alignment_padding; /* unused */     056   sos_ui16_t  alignment_padding; /* unused */
057   sos_ui32_t  eax;                                057   sos_ui32_t  eax;
058   sos_ui32_t  ebx;                                058   sos_ui32_t  ebx;
059   sos_ui32_t  ecx;                                059   sos_ui32_t  ecx;
060   sos_ui32_t  edx;                                060   sos_ui32_t  edx;
061   sos_ui32_t  esi;                                061   sos_ui32_t  esi;
062   sos_ui32_t  edi;                                062   sos_ui32_t  edi;
063   sos_ui32_t  ebp;                                063   sos_ui32_t  ebp;
064                                                   064 
065   /* MUST NEVER CHANGE (dependent on the IA32     065   /* MUST NEVER CHANGE (dependent on the IA32 iret instruction) */
066   sos_ui32_t  error_code;                         066   sos_ui32_t  error_code;
067   sos_vaddr_t eip;                                067   sos_vaddr_t eip;
068   sos_ui32_t  cs; /* 32bits according to the s    068   sos_ui32_t  cs; /* 32bits according to the specs ! However, the CS
069                      register is really 16bits    069                      register is really 16bits long */
070   sos_ui32_t  eflags;                             070   sos_ui32_t  eflags;
071                                                   071 
072   /* (Higher addresses) */                        072   /* (Higher addresses) */
073 } __attribute__((packed));                        073 } __attribute__((packed));
074                                                   074 
075                                                   075 
076 /**                                               076 /**
077  * The CS value pushed on the stack by the CPU    077  * The CS value pushed on the stack by the CPU upon interrupt, and
078  * needed by the iret instruction, is 32bits l    078  * needed by the iret instruction, is 32bits long while the real CPU
079  * CS register is 16bits only: this macro simp    079  * CS register is 16bits only: this macro simply retrieves the CPU
080  * "CS" register value from the CS value pushe    080  * "CS" register value from the CS value pushed on the stack by the
081  * CPU upon interrupt.                            081  * CPU upon interrupt.
082  *                                                082  *
083  * The remaining 16bits pushed by the CPU shou    083  * The remaining 16bits pushed by the CPU should be considered
084  * "reserved" and architecture dependent. IMHO    084  * "reserved" and architecture dependent. IMHO, the specs don't say
085  * anything about them. Considering that some     085  * anything about them. Considering that some architectures generate
086  * non-zero values for these 16bits (at least     086  * non-zero values for these 16bits (at least Cyrix), we'd better
087  * ignore them.                                   087  * ignore them.
088  */                                               088  */
089 #define GET_CPU_CS_REGISTER_VALUE(pushed_ui32_    089 #define GET_CPU_CS_REGISTER_VALUE(pushed_ui32_cs_value) \
090   ( (pushed_ui32_cs_value) & 0xffff )             090   ( (pushed_ui32_cs_value) & 0xffff )
091                                                   091 
092                                                   092 
093 /**                                               093 /**
094  * Structure of an interrupted Kernel thread's    094  * Structure of an interrupted Kernel thread's context
095  */                                               095  */
096 struct sos_cpu_kstate                             096 struct sos_cpu_kstate
097 {                                                 097 {
098   struct sos_cpu_state regs;                      098   struct sos_cpu_state regs;
099 } __attribute__((packed));                        099 } __attribute__((packed));
100                                                   100 
101                                                   101 
102 /**                                               102 /**
103  * Structure of an interrupted User thread's c    103  * Structure of an interrupted User thread's context. This is almost
104  * the same as a kernel context, except that 2    104  * the same as a kernel context, except that 2 additional values are
105  * pushed on the stack before the eflags/cs/ei    105  * pushed on the stack before the eflags/cs/eip of the interrupted
106  * context: the stack configuration of the int    106  * context: the stack configuration of the interrupted user context.
107  *                                                107  *
108  * @see Section 6.4.1 of Intel x86 vol 1          108  * @see Section 6.4.1 of Intel x86 vol 1
109  */                                               109  */
110 struct sos_cpu_ustate                             110 struct sos_cpu_ustate
111 {                                                 111 {
112   struct sos_cpu_state regs;                      112   struct sos_cpu_state regs;
113   struct                                          113   struct
114   {                                               114   {
115     sos_ui32_t cpl3_esp;                          115     sos_ui32_t cpl3_esp;
116     sos_ui16_t cpl3_ss;                           116     sos_ui16_t cpl3_ss;
117   };                                              117   };
118 } __attribute__((packed));                        118 } __attribute__((packed));
119                                                   119 
120                                                   120 
121 /*                                                121 /*
122  * Structure of a Task State Segment on the x8    122  * Structure of a Task State Segment on the x86 Architecture.
123  *                                                123  *
124  * @see Intel x86 spec vol 3, figure 6-2          124  * @see Intel x86 spec vol 3, figure 6-2
125  *                                                125  *
126  * @note Such a data structure should not cros    126  * @note Such a data structure should not cross any page boundary (see
127  * end of section 6.2.1 of Intel spec vol 3).     127  * end of section 6.2.1 of Intel spec vol 3). This is the reason why
128  * we tell gcc to align it on a 128B boundary     128  * we tell gcc to align it on a 128B boundary (its size is 104B, which
129  * is <= 128).                                    129  * is <= 128).
130  */                                               130  */
131 struct x86_tss {                                  131 struct x86_tss {
132                                                   132 
133   /**                                             133   /**
134    * Intel provides a way for a task to switch    134    * Intel provides a way for a task to switch to another in an
135    * automatic way (call gates). In this case,    135    * automatic way (call gates). In this case, the back_link field
136    * stores the source TSS of the context swit    136    * stores the source TSS of the context switch. This allows to
137    * easily implement coroutines, task backtra    137    * easily implement coroutines, task backtracking, ... In SOS we
138    * don't use TSS for the context switch purp    138    * don't use TSS for the context switch purpouse, so we always
139    * ignore this field.                           139    * ignore this field.
140    * (+0)                                         140    * (+0)
141    */                                             141    */
142   sos_ui16_t back_link;                           142   sos_ui16_t back_link;
143                                                   143 
144   sos_ui16_t reserved1;                           144   sos_ui16_t reserved1;
145                                                   145 
146   /* CPL0 saved context. (+4) */                  146   /* CPL0 saved context. (+4) */
147   sos_vaddr_t esp0;                               147   sos_vaddr_t esp0;
148   sos_ui16_t ss0;                                 148   sos_ui16_t ss0;
149                                                   149 
150   sos_ui16_t reserved2;                           150   sos_ui16_t reserved2;
151                                                   151 
152   /* CPL1 saved context. (+12) */                 152   /* CPL1 saved context. (+12) */
153   sos_vaddr_t esp1;                               153   sos_vaddr_t esp1;
154   sos_ui16_t ss1;                                 154   sos_ui16_t ss1;
155                                                   155 
156   sos_ui16_t reserved3;                           156   sos_ui16_t reserved3;
157                                                   157 
158   /* CPL2 saved context. (+20) */                 158   /* CPL2 saved context. (+20) */
159   sos_vaddr_t esp2;                               159   sos_vaddr_t esp2;
160   sos_ui16_t ss2;                                 160   sos_ui16_t ss2;
161                                                   161 
162   sos_ui16_t reserved4;                           162   sos_ui16_t reserved4;
163                                                   163 
164   /* Interrupted context's saved registers. (+    164   /* Interrupted context's saved registers. (+28) */
165   sos_vaddr_t cr3;                                165   sos_vaddr_t cr3;
166   sos_vaddr_t eip;                                166   sos_vaddr_t eip;
167   sos_ui32_t eflags;                              167   sos_ui32_t eflags;
168   sos_ui32_t eax;                                 168   sos_ui32_t eax;
169   sos_ui32_t ecx;                                 169   sos_ui32_t ecx;
170   sos_ui32_t edx;                                 170   sos_ui32_t edx;
171   sos_ui32_t ebx;                                 171   sos_ui32_t ebx;
172   sos_ui32_t esp;                                 172   sos_ui32_t esp;
173   sos_ui32_t ebp;                                 173   sos_ui32_t ebp;
174   sos_ui32_t esi;                                 174   sos_ui32_t esi;
175   sos_ui32_t edi;                                 175   sos_ui32_t edi;
176                                                   176 
177   /* +72 */                                       177   /* +72 */
178   sos_ui16_t es;                                  178   sos_ui16_t es;
179   sos_ui16_t reserved5;                           179   sos_ui16_t reserved5;
180                                                   180 
181   /* +76 */                                       181   /* +76 */
182   sos_ui16_t cs;                                  182   sos_ui16_t cs;
183   sos_ui16_t reserved6;                           183   sos_ui16_t reserved6;
184                                                   184 
185   /* +80 */                                       185   /* +80 */
186   sos_ui16_t ss;                                  186   sos_ui16_t ss;
187   sos_ui16_t reserved7;                           187   sos_ui16_t reserved7;
188                                                   188 
189   /* +84 */                                       189   /* +84 */
190   sos_ui16_t ds;                                  190   sos_ui16_t ds;
191   sos_ui16_t reserved8;                           191   sos_ui16_t reserved8;
192                                                   192 
193   /* +88 */                                       193   /* +88 */
194   sos_ui16_t fs;                                  194   sos_ui16_t fs;
195   sos_ui16_t reserved9;                           195   sos_ui16_t reserved9;
196                                                   196 
197   /* +92 */                                       197   /* +92 */
198   sos_ui16_t gs;                                  198   sos_ui16_t gs;
199   sos_ui16_t reserved10;                          199   sos_ui16_t reserved10;
200                                                   200 
201   /* +96 */                                       201   /* +96 */
202   sos_ui16_t ldtr;                                202   sos_ui16_t ldtr;
203   sos_ui16_t reserved11;                          203   sos_ui16_t reserved11;
204                                                   204 
205   /* +100 */                                      205   /* +100 */
206   sos_ui16_t debug_trap_flag :1;                  206   sos_ui16_t debug_trap_flag :1;
207   sos_ui16_t reserved12      :15;                 207   sos_ui16_t reserved12      :15;
208   sos_ui16_t iomap_base_addr;                     208   sos_ui16_t iomap_base_addr;
209                                                   209 
210   /* 104 */                                       210   /* 104 */
211 } __attribute__((packed, aligned(128)));          211 } __attribute__((packed, aligned(128)));
212                                                   212 
213                                                   213 
214 static struct x86_tss kernel_tss;                 214 static struct x86_tss kernel_tss;
215                                                   215 
216                                                   216 
217 sos_ret_t sos_cpu_context_subsystem_setup()       217 sos_ret_t sos_cpu_context_subsystem_setup()
218 {                                                 218 {
219   /* Reset the kernel TSS */                      219   /* Reset the kernel TSS */
220   memset(&kernel_tss, 0x0, sizeof(kernel_tss))    220   memset(&kernel_tss, 0x0, sizeof(kernel_tss));
221                                                   221 
222   /**                                             222   /**
223    * Now setup the kernel TSS.                    223    * Now setup the kernel TSS.
224    *                                              224    *
225    * Considering the privilege change method w    225    * Considering the privilege change method we choose (cpl3 -> cpl0
226    * through a software interrupt), we don't n    226    * through a software interrupt), we don't need to initialize a
227    * full-fledged TSS. See section 6.4.1 of In    227    * full-fledged TSS. See section 6.4.1 of Intel x86 vol 1. Actually,
228    * only a correct value for the kernel esp a    228    * only a correct value for the kernel esp and ss are required (aka
229    * "ss0" and "esp0" fields). Since the esp0     229    * "ss0" and "esp0" fields). Since the esp0 will have to be updated
230    * at privilege change time, we don't have t    230    * at privilege change time, we don't have to set it up now.
231    */                                             231    */
232   kernel_tss.ss0 = SOS_BUILD_SEGMENT_REG_VALUE    232   kernel_tss.ss0 = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA);
233                                                   233 
234   /* Register this TSS into the gdt */            234   /* Register this TSS into the gdt */
235   sos_gdt_register_kernel_tss((sos_vaddr_t) &k    235   sos_gdt_register_kernel_tss((sos_vaddr_t) &kernel_tss);
236                                                   236 
237   return SOS_OK;                                  237   return SOS_OK;
238 }                                                 238 }
239                                                   239 
240                                                   240 
241 /**                                               241 /**
242  * THE main operation of a kernel thread. This    242  * THE main operation of a kernel thread. This routine calls the
243  * kernel thread function start_func and calls    243  * kernel thread function start_func and calls exit_func when
244  * start_func returns.                            244  * start_func returns.
245  */                                               245  */
246 static void core_routine (sos_cpu_kstate_funct    246 static void core_routine (sos_cpu_kstate_function_arg1_t *start_func,
247                           sos_ui32_t start_arg    247                           sos_ui32_t start_arg,
248                           sos_cpu_kstate_funct    248                           sos_cpu_kstate_function_arg1_t *exit_func,
249                           sos_ui32_t exit_arg)    249                           sos_ui32_t exit_arg)
250      __attribute__((noreturn));                   250      __attribute__((noreturn));
251                                                   251 
252 static void core_routine (sos_cpu_kstate_funct    252 static void core_routine (sos_cpu_kstate_function_arg1_t *start_func,
253                           sos_ui32_t start_arg    253                           sos_ui32_t start_arg,
254                           sos_cpu_kstate_funct    254                           sos_cpu_kstate_function_arg1_t *exit_func,
255                           sos_ui32_t exit_arg)    255                           sos_ui32_t exit_arg)
256 {                                                 256 {
257   start_func(start_arg);                          257   start_func(start_arg);
258   exit_func(exit_arg);                            258   exit_func(exit_arg);
259                                                   259 
260   SOS_ASSERT_FATAL(! "The exit function of the    260   SOS_ASSERT_FATAL(! "The exit function of the thread should NOT return !");
261   for(;;);                                        261   for(;;);
262 }                                                 262 }
263                                                   263 
264                                                   264 
265 sos_ret_t sos_cpu_kstate_init(struct sos_cpu_s    265 sos_ret_t sos_cpu_kstate_init(struct sos_cpu_state **ctxt,
266                               sos_cpu_kstate_f    266                               sos_cpu_kstate_function_arg1_t *start_func,
267                               sos_ui32_t  star    267                               sos_ui32_t  start_arg,
268                               sos_vaddr_t stac    268                               sos_vaddr_t stack_bottom,
269                               sos_size_t  stac    269                               sos_size_t  stack_size,
270                               sos_cpu_kstate_f    270                               sos_cpu_kstate_function_arg1_t *exit_func,
271                               sos_ui32_t  exit    271                               sos_ui32_t  exit_arg)
272 {                                                 272 {
273   /* We are initializing a Kernel thread's con    273   /* We are initializing a Kernel thread's context */
274   struct sos_cpu_kstate *kctxt;                   274   struct sos_cpu_kstate *kctxt;
275                                                   275 
276   /* This is a critical internal function, so     276   /* This is a critical internal function, so that it is assumed that
277      the caller knows what he does: we legitim    277      the caller knows what he does: we legitimally assume that values
278      for ctxt, start_func, stack_* and exit_fu    278      for ctxt, start_func, stack_* and exit_func are allways VALID ! */
279                                                   279 
280   /* Setup the stack.                             280   /* Setup the stack.
281    *                                              281    *
282    * On x86, the stack goes downward. Each fra    282    * On x86, the stack goes downward. Each frame is configured this
283    * way (higher addresses first):                283    * way (higher addresses first):
284    *                                              284    *
285    *  - (optional unused space. As of gcc 3.3,    285    *  - (optional unused space. As of gcc 3.3, this space is 24 bytes)
286    *  - arg n                                     286    *  - arg n
287    *  - arg n-1                                   287    *  - arg n-1
288    *  - ...                                       288    *  - ...
289    *  - arg 1                                     289    *  - arg 1
290    *  - return instruction address: The addres    290    *  - return instruction address: The address the function returns to
291    *    once finished                             291    *    once finished
292    *  - local variables                           292    *  - local variables
293    *                                              293    *
294    * The remaining of the code should be read     294    * The remaining of the code should be read from the end upward to
295    * understand how the processor will handle     295    * understand how the processor will handle it.
296    */                                             296    */
297                                                   297 
298   sos_vaddr_t tmp_vaddr = stack_bottom + stack    298   sos_vaddr_t tmp_vaddr = stack_bottom + stack_size;
299   sos_ui32_t *stack = (sos_ui32_t*)tmp_vaddr;     299   sos_ui32_t *stack = (sos_ui32_t*)tmp_vaddr;
300                                                   300 
301   /* If needed, poison the stack */               301   /* If needed, poison the stack */
302 #ifdef SOS_CPU_STATE_DETECT_UNINIT_KERNEL_VARS    302 #ifdef SOS_CPU_STATE_DETECT_UNINIT_KERNEL_VARS
303   memset((void*)stack_bottom, SOS_CPU_STATE_ST    303   memset((void*)stack_bottom, SOS_CPU_STATE_STACK_POISON, stack_size);
304 #elif defined(SOS_CPU_STATE_DETECT_KERNEL_STAC    304 #elif defined(SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW)
305   sos_cpu_state_prepare_detect_kernel_stack_ov    305   sos_cpu_state_prepare_detect_kernel_stack_overflow(stack_bottom, stack_size);
306 #endif                                            306 #endif
307                                                   307 
308   /* Simulate a call to the core_routine() fun    308   /* Simulate a call to the core_routine() function: prepare its
309      arguments */                                 309      arguments */
310   *(--stack) = exit_arg;                          310   *(--stack) = exit_arg;
311   *(--stack) = (sos_ui32_t)exit_func;             311   *(--stack) = (sos_ui32_t)exit_func;
312   *(--stack) = start_arg;                         312   *(--stack) = start_arg;
313   *(--stack) = (sos_ui32_t)start_func;            313   *(--stack) = (sos_ui32_t)start_func;
314   *(--stack) = 0; /* Return address of core_ro    314   *(--stack) = 0; /* Return address of core_routine => force page fault */
315                                                   315 
316   /*                                              316   /*
317    * Setup the initial context structure, so t    317    * Setup the initial context structure, so that the CPU will execute
318    * the function core_routine() once this new    318    * the function core_routine() once this new context has been
319    * restored on CPU                              319    * restored on CPU
320    */                                             320    */
321                                                   321 
322   /* Compute the base address of the structure    322   /* Compute the base address of the structure, which must be located
323      below the previous elements */               323      below the previous elements */
324   tmp_vaddr  = ((sos_vaddr_t)stack) - sizeof(s    324   tmp_vaddr  = ((sos_vaddr_t)stack) - sizeof(struct sos_cpu_kstate);
325   kctxt = (struct sos_cpu_kstate*)tmp_vaddr;      325   kctxt = (struct sos_cpu_kstate*)tmp_vaddr;
326                                                   326 
327   /* Initialize the CPU context structure */      327   /* Initialize the CPU context structure */
328   memset(kctxt, 0x0, sizeof(struct sos_cpu_kst    328   memset(kctxt, 0x0, sizeof(struct sos_cpu_kstate));
329                                                   329 
330   /* Tell the CPU context structure that the f    330   /* Tell the CPU context structure that the first instruction to
331      execute will be that of the core_routine(    331      execute will be that of the core_routine() function */
332   kctxt->regs.eip = (sos_ui32_t)core_routine;     332   kctxt->regs.eip = (sos_ui32_t)core_routine;
333                                                   333 
334   /* Setup the segment registers */               334   /* Setup the segment registers */
335   kctxt->regs.cs                                  335   kctxt->regs.cs
336     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SO    336     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE); /* Code */
337   kctxt->regs.ds                                  337   kctxt->regs.ds
338     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SO    338     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA); /* Data */
339   kctxt->regs.es                                  339   kctxt->regs.es
340     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SO    340     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA); /* Data */
341   kctxt->regs.cpl0_ss                             341   kctxt->regs.cpl0_ss
342     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SO    342     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA); /* Stack */
343   /* fs and gs unused for the moment. */          343   /* fs and gs unused for the moment. */
344                                                   344 
345   /* The newly created context is initially in    345   /* The newly created context is initially interruptible */
346   kctxt->regs.eflags = (1 << 9); /* set IF bit    346   kctxt->regs.eflags = (1 << 9); /* set IF bit */
347                                                   347 
348   /* Finally, update the generic kernel/user t    348   /* Finally, update the generic kernel/user thread context */
349   *ctxt = (struct sos_cpu_state*) kctxt;          349   *ctxt = (struct sos_cpu_state*) kctxt;
350                                                   350 
351   return SOS_OK;                                  351   return SOS_OK;
352 }                                                 352 }
353                                                   353 
354                                                   354 
355 sos_ret_t sos_cpu_ustate_init(struct sos_cpu_s !! 355 /**
356                               sos_uaddr_t  use !! 356  * Helper function to create a new user thread context.  When
357                               sos_ui32_t   use !! 357  * model_uctxt is NON NULL, the new user context is the copy of
358                               sos_ui32_t   use !! 358  * model_uctxt, otherwise the SP/PC registers are initialized to the
359                               sos_uaddr_t  use !! 359  * user_initial_SP/PC arguments
360                               sos_vaddr_t  ker !! 360  */
361                               sos_size_t   ker !! 361 static sos_ret_t cpu_ustate_init(struct sos_cpu_state **ctxt,
                                                   >> 362                                  const struct sos_cpu_state *model_uctxt,
                                                   >> 363                                  sos_uaddr_t  user_start_PC,
                                                   >> 364                                  sos_ui32_t   user_start_arg1,
                                                   >> 365                                  sos_ui32_t   user_start_arg2,
                                                   >> 366                                  sos_uaddr_t  user_initial_SP,
                                                   >> 367                                  sos_vaddr_t  kernel_stack_bottom,
                                                   >> 368                                  sos_size_t   kernel_stack_size)
362 {                                                 369 {
363   /* We are initializing a User thread's conte    370   /* We are initializing a User thread's context */
364   struct sos_cpu_ustate *uctxt;                   371   struct sos_cpu_ustate *uctxt;
365                                                   372 
366   /* This is a critical internal function, so     373   /* This is a critical internal function, so that it is assumed that
367      the caller knows what he does: we legitim    374      the caller knows what he does: we legitimally assume that values
368      for ctxt, etc. are allways VALID ! */        375      for ctxt, etc. are allways VALID ! */
369                                                   376 
370   /* Compute the address of the CPU state to r    377   /* Compute the address of the CPU state to restore on CPU when
371      switching to this new user thread */         378      switching to this new user thread */
372   sos_vaddr_t uctxt_vaddr = kernel_stack_botto    379   sos_vaddr_t uctxt_vaddr = kernel_stack_bottom
373                              + kernel_stack_si    380                              + kernel_stack_size
374                              - sizeof(struct s    381                              - sizeof(struct sos_cpu_ustate);
375   uctxt = (struct sos_cpu_ustate*)uctxt_vaddr;    382   uctxt = (struct sos_cpu_ustate*)uctxt_vaddr;
376                                                   383 
                                                   >> 384   if (model_uctxt && !sos_cpu_context_is_in_user_mode(model_uctxt))
                                                   >> 385     return -SOS_EINVAL;
                                                   >> 386 
377   /* If needed, poison the kernel stack */        387   /* If needed, poison the kernel stack */
378 #ifdef SOS_CPU_STATE_DETECT_UNINIT_KERNEL_VARS    388 #ifdef SOS_CPU_STATE_DETECT_UNINIT_KERNEL_VARS
379   memset((void*)kernel_stack_bottom,              389   memset((void*)kernel_stack_bottom,
380          SOS_CPU_STATE_STACK_POISON,              390          SOS_CPU_STATE_STACK_POISON,
381          kernel_stack_size);                      391          kernel_stack_size);
382 #elif defined(SOS_CPU_STATE_DETECT_KERNEL_STAC    392 #elif defined(SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW)
383   sos_cpu_state_prepare_detect_kernel_stack_ov    393   sos_cpu_state_prepare_detect_kernel_stack_overflow(kernel_stack_bottom,
384                                                   394                                                      kernel_stack_size);
385 #endif                                            395 #endif
386                                                   396 
387   /*                                              397   /*
388    * Setup the initial context structure, so t    398    * Setup the initial context structure, so that the CPU will restore
389    * the initial registers' value for the user    399    * the initial registers' value for the user thread. The
390    * user thread argument is passed in the EAX    400    * user thread argument is passed in the EAX register.
391    */                                             401    */
392                                                   402 
393   memset(uctxt, 0x0, sizeof(struct sos_cpu_ust !! 403   /* Initialize the CPU context structure */
394                                                !! 404   if (! model_uctxt)
395   /* Tell the CPU context structure that the f !! 405     {
396      execute will be located at user_start_PC  !! 406       memset(uctxt, 0x0, sizeof(struct sos_cpu_ustate));
397   uctxt->regs.eip = (sos_ui32_t)user_start_PC; !! 407 
398                                                !! 408       /* Tell the CPU context structure that the first instruction to
399   /* Tell the CPU where will be the user stack !! 409          execute will be located at user_start_PC (in user space) */
400   uctxt->cpl3_esp = user_initial_SP;           !! 410       uctxt->regs.eip = (sos_ui32_t)user_start_PC;
                                                   >> 411       
                                                   >> 412       /* Tell the CPU where will be the user stack */
                                                   >> 413       uctxt->cpl3_esp = user_initial_SP;
                                                   >> 414     }
                                                   >> 415   else
                                                   >> 416     memcpy(uctxt, model_uctxt, sizeof(struct sos_cpu_ustate));
401                                                   417 
402   /* The parameter to the start function is no    418   /* The parameter to the start function is not passed by the stack to
403      avoid a possible page fault */               419      avoid a possible page fault */
404   uctxt->regs.eax = user_start_arg1;              420   uctxt->regs.eax = user_start_arg1;
405   uctxt->regs.ebx = user_start_arg2;           !! 421 
                                                   >> 422   /* Optional additional argument for non-duplicated threads */
                                                   >> 423   if (! model_uctxt)
                                                   >> 424     uctxt->regs.ebx = user_start_arg2;
406                                                   425 
407   /* Setup the segment registers */               426   /* Setup the segment registers */
408   uctxt->regs.cs                                  427   uctxt->regs.cs
409     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SO    428     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SOS_SEG_UCODE); /* Code */
410   uctxt->regs.ds                                  429   uctxt->regs.ds
411     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SO    430     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SOS_SEG_UDATA); /* Data */
412   uctxt->regs.es                                  431   uctxt->regs.es
413     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SO    432     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SOS_SEG_UDATA); /* Data */
414   uctxt->cpl3_ss                                  433   uctxt->cpl3_ss
415     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SO    434     = SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SOS_SEG_UDATA); /* User Stack */
416                                                   435 
417   /* We need also to update the segment for th    436   /* We need also to update the segment for the kernel stack
418      segment. It will be used when this contex    437      segment. It will be used when this context will be restored on
419      CPU: initially it will be executing in ke    438      CPU: initially it will be executing in kernel mode and will
420      switch immediatly to user mode */            439      switch immediatly to user mode */
421   uctxt->regs.cpl0_ss                             440   uctxt->regs.cpl0_ss
422     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SO    441     = SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KDATA); /* Kernel Stack */
423                                                   442 
424   /* fs and gs unused for the moment. */          443   /* fs and gs unused for the moment. */
425                                                   444 
426   /* The newly created context is initially in    445   /* The newly created context is initially interruptible */
427   uctxt->regs.eflags = (1 << 9); /* set IF bit    446   uctxt->regs.eflags = (1 << 9); /* set IF bit */
428                                                   447 
429   /* Finally, update the generic kernel/user t    448   /* Finally, update the generic kernel/user thread context */
430   *ctxt = (struct sos_cpu_state*) uctxt;          449   *ctxt = (struct sos_cpu_state*) uctxt;
431                                                   450 
432   return SOS_OK;                                  451   return SOS_OK;
                                                   >> 452 }
                                                   >> 453 
                                                   >> 454 
                                                   >> 455 sos_ret_t sos_cpu_ustate_init(struct sos_cpu_state **ctxt,
                                                   >> 456                               sos_uaddr_t  user_start_PC,
                                                   >> 457                               sos_ui32_t   user_start_arg1,
                                                   >> 458                               sos_ui32_t   user_start_arg2,
                                                   >> 459                               sos_uaddr_t  user_initial_SP,
                                                   >> 460                               sos_vaddr_t  kernel_stack_bottom,
                                                   >> 461                               sos_size_t   kernel_stack_size)
                                                   >> 462 {
                                                   >> 463   return cpu_ustate_init(ctxt, NULL,
                                                   >> 464                          user_start_PC,
                                                   >> 465                          user_start_arg1, user_start_arg2,
                                                   >> 466                          user_initial_SP,
                                                   >> 467                          kernel_stack_bottom, kernel_stack_size);
                                                   >> 468 }
                                                   >> 469 
                                                   >> 470 
                                                   >> 471 sos_ret_t sos_cpu_ustate_duplicate(struct sos_cpu_state **ctxt,
                                                   >> 472                                    const struct sos_cpu_state *model_uctxt,
                                                   >> 473                                    sos_ui32_t   user_retval,
                                                   >> 474                                    sos_vaddr_t  kernel_stack_bottom,
                                                   >> 475                                    sos_size_t   kernel_stack_size)
                                                   >> 476 {
                                                   >> 477   return cpu_ustate_init(ctxt, model_uctxt,
                                                   >> 478                          /* ignored */0,
                                                   >> 479                          user_retval, /* ignored */0,
                                                   >> 480                          /* ignored */0,
                                                   >> 481                          kernel_stack_bottom, kernel_stack_size);
433 }                                                 482 }
434                                                   483 
435                                                   484 
436 sos_ret_t                                         485 sos_ret_t
437 sos_cpu_context_is_in_user_mode(const struct s    486 sos_cpu_context_is_in_user_mode(const struct sos_cpu_state *ctxt)
438 {                                                 487 {
439   /* An interrupted user thread has its CS reg    488   /* An interrupted user thread has its CS register set to that of the
440      User code segment */                         489      User code segment */
441   switch (GET_CPU_CS_REGISTER_VALUE(ctxt->cs))    490   switch (GET_CPU_CS_REGISTER_VALUE(ctxt->cs))
442     {                                             491     {
443     case SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE,    492     case SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SOS_SEG_UCODE):
444       return TRUE;                                493       return TRUE;
445       break;                                      494       break;
446                                                   495 
447     case SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE,    496     case SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE):
448       return FALSE;                               497       return FALSE;
449       break;                                      498       break;
450                                                   499 
451     default:                                      500     default:
452       SOS_FATAL_ERROR("Invalid saved context C    501       SOS_FATAL_ERROR("Invalid saved context Code segment register: 0x%x (k=%x, u=%x) !",
453                       (unsigned) GET_CPU_CS_RE    502                       (unsigned) GET_CPU_CS_REGISTER_VALUE(ctxt->cs),
454                       SOS_BUILD_SEGMENT_REG_VA    503                       SOS_BUILD_SEGMENT_REG_VALUE(0, FALSE, SOS_SEG_KCODE),
455                       SOS_BUILD_SEGMENT_REG_VA    504                       SOS_BUILD_SEGMENT_REG_VALUE(3, FALSE, SOS_SEG_UCODE));
456       break;                                      505       break;
457     }                                             506     }
458                                                   507 
459   /* Should never get here */                     508   /* Should never get here */
460   return -SOS_EFATAL;                             509   return -SOS_EFATAL;
461 }                                                 510 }
462                                                   511 
463                                                   512 
464 #if defined(SOS_CPU_STATE_DETECT_KERNEL_STACK_    513 #if defined(SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW)
465 void                                              514 void
466 sos_cpu_state_prepare_detect_kernel_stack_over    515 sos_cpu_state_prepare_detect_kernel_stack_overflow(const struct sos_cpu_state *ctxt,
467                                                   516                                                    sos_vaddr_t stack_bottom,
468                                                   517                                                    sos_size_t stack_size)
469 {                                                 518 {
470   sos_size_t poison_size = SOS_CPU_STATE_DETEC    519   sos_size_t poison_size = SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW;
471   if (poison_size > stack_size)                   520   if (poison_size > stack_size)
472     poison_size = stack_size;                     521     poison_size = stack_size;
473                                                   522 
474   memset((void*)stack_bottom, SOS_CPU_STATE_ST    523   memset((void*)stack_bottom, SOS_CPU_STATE_STACK_POISON, poison_size);
475 }                                                 524 }
476                                                   525 
477                                                   526 
478 void                                              527 void
479 sos_cpu_state_detect_kernel_stack_overflow(con    528 sos_cpu_state_detect_kernel_stack_overflow(const struct sos_cpu_state *ctxt,
480                                            sos    529                                            sos_vaddr_t stack_bottom,
481                                            sos    530                                            sos_size_t stack_size)
482 {                                                 531 {
483   unsigned char *c;                               532   unsigned char *c;
484   int i;                                          533   int i;
485                                                   534 
486   /* On SOS, "ctxt" corresponds to the address    535   /* On SOS, "ctxt" corresponds to the address of the esp register of
487      the saved context in Kernel mode (always,    536      the saved context in Kernel mode (always, even for the interrupted
488      context of a user thread). Here we make s    537      context of a user thread). Here we make sure that this stack
489      pointer is within the allowed stack area     538      pointer is within the allowed stack area */
490   SOS_ASSERT_FATAL(((sos_vaddr_t)ctxt) >= stac    539   SOS_ASSERT_FATAL(((sos_vaddr_t)ctxt) >= stack_bottom);
491   SOS_ASSERT_FATAL(((sos_vaddr_t)ctxt) + sizeo    540   SOS_ASSERT_FATAL(((sos_vaddr_t)ctxt) + sizeof(struct sos_cpu_kstate)
492                    <= stack_bottom + stack_siz    541                    <= stack_bottom + stack_size);
493                                                   542 
494   /* Check that the bottom of the stack has no    543   /* Check that the bottom of the stack has not been altered */
495   for (c = (unsigned char*) stack_bottom, i =     544   for (c = (unsigned char*) stack_bottom, i = 0 ;
496        (i < SOS_CPU_STATE_DETECT_KERNEL_STACK_    545        (i < SOS_CPU_STATE_DETECT_KERNEL_STACK_OVERFLOW) && (i < stack_size) ;
497        c++, i++)                                  546        c++, i++)
498     {                                             547     {
499       SOS_ASSERT_FATAL(SOS_CPU_STATE_STACK_POI    548       SOS_ASSERT_FATAL(SOS_CPU_STATE_STACK_POISON == *c);
500     }                                             549     }
501 }                                                 550 }
502 #endif                                            551 #endif
503                                                   552 
504                                                   553 
505 /* ===========================================    554 /* =======================================================================
506  * Public Accessor functions                      555  * Public Accessor functions
507  */                                               556  */
508                                                   557 
509                                                   558 
510 sos_vaddr_t sos_cpu_context_get_PC(const struc    559 sos_vaddr_t sos_cpu_context_get_PC(const struct sos_cpu_state *ctxt)
511 {                                                 560 {
512   SOS_ASSERT_FATAL(NULL != ctxt);                 561   SOS_ASSERT_FATAL(NULL != ctxt);
513                                                   562 
514   /* This is the PC of the interrupted context    563   /* This is the PC of the interrupted context (ie kernel or user
515      context). */                                 564      context). */
516   return ctxt->eip;                               565   return ctxt->eip;
517 }                                                 566 }
518                                                   567 
519                                                   568 
520 sos_vaddr_t sos_cpu_context_get_SP(const struc    569 sos_vaddr_t sos_cpu_context_get_SP(const struct sos_cpu_state *ctxt)
521 {                                                 570 {
522   SOS_ASSERT_FATAL(NULL != ctxt);                 571   SOS_ASSERT_FATAL(NULL != ctxt);
523                                                   572 
524   /* 'ctxt' corresponds to the SP of the inter    573   /* 'ctxt' corresponds to the SP of the interrupted context, in Kernel
525      mode. We have to test whether the origina    574      mode. We have to test whether the original interrupted context
526      was that of a kernel or user thread */       575      was that of a kernel or user thread */
527   if (TRUE == sos_cpu_context_is_in_user_mode(    576   if (TRUE == sos_cpu_context_is_in_user_mode(ctxt))
528     {                                             577     {
529       struct sos_cpu_ustate * uctxt = (struct     578       struct sos_cpu_ustate * uctxt = (struct sos_cpu_ustate*)ctxt;
530       return uctxt->cpl3_esp;                     579       return uctxt->cpl3_esp;
531     }                                             580     }
532                                                   581 
533   /* On SOS, "ctxt" corresponds to the address    582   /* On SOS, "ctxt" corresponds to the address of the esp register of
534      the saved context in Kernel mode (always,    583      the saved context in Kernel mode (always, even for the interrupted
535      context of a user thread). */                584      context of a user thread). */
536   return (sos_vaddr_t)ctxt;                       585   return (sos_vaddr_t)ctxt;
537 }                                                 586 }
538                                                   587 
539                                                   588 
540 sos_ret_t                                         589 sos_ret_t
541 sos_cpu_context_set_EX_return_address(struct s    590 sos_cpu_context_set_EX_return_address(struct sos_cpu_state *ctxt,
542                                       sos_vadd    591                                       sos_vaddr_t ret_vaddr)
543 {                                                 592 {
544   ctxt->eip = ret_vaddr;                          593   ctxt->eip = ret_vaddr;
545   return SOS_OK;                                  594   return SOS_OK;
546 }                                                 595 }
547                                                   596 
548                                                   597 
549 void sos_cpu_context_dump(const struct sos_cpu    598 void sos_cpu_context_dump(const struct sos_cpu_state *ctxt)
550 {                                                 599 {
551   char buf[128];                                  600   char buf[128];
552                                                   601 
553   snprintf(buf, sizeof(buf),                      602   snprintf(buf, sizeof(buf),
554            "CPU: eip=%x esp0=%x eflags=%x cs=%    603            "CPU: eip=%x esp0=%x eflags=%x cs=%x ds=%x ss0=%x err=%x",
555            (unsigned)ctxt->eip, (unsigned)ctxt    604            (unsigned)ctxt->eip, (unsigned)ctxt, (unsigned)ctxt->eflags,
556            (unsigned)GET_CPU_CS_REGISTER_VALUE    605            (unsigned)GET_CPU_CS_REGISTER_VALUE(ctxt->cs), (unsigned)ctxt->ds,
557            (unsigned)ctxt->cpl0_ss,               606            (unsigned)ctxt->cpl0_ss,
558            (unsigned)ctxt->error_code);           607            (unsigned)ctxt->error_code);
559   if (TRUE == sos_cpu_context_is_in_user_mode(    608   if (TRUE == sos_cpu_context_is_in_user_mode(ctxt))
560     {                                             609     {
561       struct sos_cpu_ustate * uctxt = (struct     610       struct sos_cpu_ustate * uctxt = (struct sos_cpu_ustate*)ctxt;
562       snprintf(buf, sizeof(buf),                  611       snprintf(buf, sizeof(buf),
563                "%s esp3=%x ss3=%x",               612                "%s esp3=%x ss3=%x",
564                buf, (unsigned)uctxt->cpl3_esp,    613                buf, (unsigned)uctxt->cpl3_esp, (unsigned)uctxt->cpl3_ss);
565     }                                             614     }
566   else                                            615   else
567     snprintf(buf, sizeof(buf), "%s [KERNEL MOD    616     snprintf(buf, sizeof(buf), "%s [KERNEL MODE]", buf);
568                                                   617 
569   sos_bochs_putstring(buf); sos_bochs_putstrin    618   sos_bochs_putstring(buf); sos_bochs_putstring("\n");
570   sos_x86_videomem_putstring(23, 0,               619   sos_x86_videomem_putstring(23, 0,
571                              SOS_X86_VIDEO_FG_    620                              SOS_X86_VIDEO_FG_BLACK | SOS_X86_VIDEO_BG_LTGRAY,
572                              buf);                621                              buf);
573 }                                                 622 }
574                                                   623 
575                                                   624 
576 /* ===========================================    625 /* =======================================================================
577  * Public Accessor functions TO BE USED ONLY B    626  * Public Accessor functions TO BE USED ONLY BY Exception handlers
578  */                                               627  */
579                                                   628 
580                                                   629 
581 sos_ui32_t sos_cpu_context_get_EX_info(const s    630 sos_ui32_t sos_cpu_context_get_EX_info(const struct sos_cpu_state *ctxt)
582 {                                                 631 {
583   SOS_ASSERT_FATAL(NULL != ctxt);                 632   SOS_ASSERT_FATAL(NULL != ctxt);
584   return ctxt->error_code;                        633   return ctxt->error_code;
585 }                                                 634 }
586                                                   635 
587                                                   636 
588 sos_vaddr_t                                       637 sos_vaddr_t
589 sos_cpu_context_get_EX_faulting_vaddr(const st    638 sos_cpu_context_get_EX_faulting_vaddr(const struct sos_cpu_state *ctxt)
590 {                                                 639 {
591   sos_ui32_t cr2;                                 640   sos_ui32_t cr2;
592                                                   641 
593   /*                                              642   /*
594    * See Intel Vol 3 (section 5.14): the addre    643    * See Intel Vol 3 (section 5.14): the address of the faulting
595    * virtual address of a page fault is stored    644    * virtual address of a page fault is stored in the cr2
596    * register.                                    645    * register.
597    *                                              646    *
598    * Actually, we do not store the cr2 registe    647    * Actually, we do not store the cr2 register in a saved
599    * kernel thread's context. So we retrieve t    648    * kernel thread's context. So we retrieve the cr2's value directly
600    * from the processor. The value we retrieve    649    * from the processor. The value we retrieve in an exception handler
601    * is actually the correct one because an ex    650    * is actually the correct one because an exception is synchronous
602    * with the code causing the fault, and cann    651    * with the code causing the fault, and cannot be interrupted since
603    * the IDT entries in SOS are "interrupt gat    652    * the IDT entries in SOS are "interrupt gates" (ie IRQ are
604    * disabled).                                   653    * disabled).
605    */                                             654    */
606   asm volatile ("movl %%cr2, %0"                  655   asm volatile ("movl %%cr2, %0"
607                 :"=r"(cr2)                        656                 :"=r"(cr2)
608                 : );                              657                 : );
609                                                   658 
610   return cr2;                                     659   return cr2;
611 }                                                 660 }
612                                                   661 
613                                                   662 
614 /* ===========================================    663 /* =======================================================================
615  * Public Accessor functions TO BE USED ONLY B    664  * Public Accessor functions TO BE USED ONLY BY the SYSCALL handler
616  */                                               665  */
617                                                   666 
618                                                   667 
619 /*                                                668 /*
620  * By convention, the USER SOS programs always    669  * By convention, the USER SOS programs always pass 4 arguments to the
621  * kernel syscall handler: in eax/../edx. For     670  * kernel syscall handler: in eax/../edx. For less arguments, the
622  * unused registers are filled with 0s. For mo    671  * unused registers are filled with 0s. For more arguments, the 4th
623  * syscall parameter gives the address of the     672  * syscall parameter gives the address of the array containing the
624  * remaining arguments. In any case, eax corre    673  * remaining arguments. In any case, eax corresponds to the syscall
625  * IDentifier.                                    674  * IDentifier.
626  */                                               675  */
627                                                   676 
628                                                   677 
629 inline                                            678 inline
630 sos_ret_t sos_syscall_get3args(const struct so    679 sos_ret_t sos_syscall_get3args(const struct sos_cpu_state *user_ctxt,
631                                /* out */unsign    680                                /* out */unsigned int *arg1,
632                                /* out */unsign    681                                /* out */unsigned int *arg2,
633                                /* out */unsign    682                                /* out */unsigned int *arg3)
634 {                                                 683 {
635   *arg1 = user_ctxt->ebx;                         684   *arg1 = user_ctxt->ebx;
636   *arg2 = user_ctxt->ecx;                         685   *arg2 = user_ctxt->ecx;
637   *arg3 = user_ctxt->edx;                         686   *arg3 = user_ctxt->edx; 
638   return SOS_OK;                                  687   return SOS_OK;
639 }                                                 688 }
640                                                   689 
641                                                   690 
642 sos_ret_t sos_syscall_get1arg(const struct sos    691 sos_ret_t sos_syscall_get1arg(const struct sos_cpu_state *user_ctxt,
643                               /* out */unsigne    692                               /* out */unsigned int *arg1)
644 {                                                 693 {
645   unsigned int unused;                            694   unsigned int unused;
646   return sos_syscall_get3args(user_ctxt, arg1,    695   return sos_syscall_get3args(user_ctxt, arg1, & unused, & unused);
647 }                                                 696 }
648                                                   697 
649                                                   698 
650 sos_ret_t sos_syscall_get2args(const struct so    699 sos_ret_t sos_syscall_get2args(const struct sos_cpu_state *user_ctxt,
651                                /* out */unsign    700                                /* out */unsigned int *arg1,
652                                /* out */unsign    701                                /* out */unsigned int *arg2)
653 {                                                 702 {
654   unsigned int unused;                            703   unsigned int unused;
655   return sos_syscall_get3args(user_ctxt, arg1,    704   return sos_syscall_get3args(user_ctxt, arg1, arg2, & unused);
656 }                                                 705 }
657                                                   706 
658                                                   707 
659 /*                                                708 /*
660  * sos_syscall_get3args() is defined in cpu_co    709  * sos_syscall_get3args() is defined in cpu_context.c because it needs
661  * to know the structure of a struct spu_state    710  * to know the structure of a struct spu_state
662  */                                               711  */
663                                                   712 
664 sos_ret_t sos_syscall_get4args(const struct so    713 sos_ret_t sos_syscall_get4args(const struct sos_cpu_state *user_ctxt,
665                                /* out */unsign    714                                /* out */unsigned int *arg1,
666                                /* out */unsign    715                                /* out */unsigned int *arg2,
667                                /* out */unsign    716                                /* out */unsigned int *arg3,
668                                /* out */unsign    717                                /* out */unsigned int *arg4)
669 {                                                 718 {
670   sos_uaddr_t  uaddr_other_args;                  719   sos_uaddr_t  uaddr_other_args;
671   unsigned int other_args[2];                     720   unsigned int other_args[2];
672   sos_ret_t    retval;                            721   sos_ret_t    retval;
673                                                   722 
674   /* Retrieve the 3 arguments. The last one is    723   /* Retrieve the 3 arguments. The last one is an array containing the
675      remaining arguments */                       724      remaining arguments */
676   retval = sos_syscall_get3args(user_ctxt, arg    725   retval = sos_syscall_get3args(user_ctxt, arg1, arg2,
677                                 (unsigned int     726                                 (unsigned int *)& uaddr_other_args);
678   if (SOS_OK != retval)                           727   if (SOS_OK != retval)
679     return retval;                                728     return retval;
680                                                   729   
681   /* Copy the array containing the remaining a    730   /* Copy the array containing the remaining arguments from user
682      space */                                     731      space */
683   retval = sos_memcpy_from_user((sos_vaddr_t)o    732   retval = sos_memcpy_from_user((sos_vaddr_t)other_args,
684                                 (sos_uaddr_t)u    733                                 (sos_uaddr_t)uaddr_other_args,
685                                 sizeof(other_a    734                                 sizeof(other_args));
686   if (sizeof(other_args) != retval)               735   if (sizeof(other_args) != retval)
687     return -SOS_EFAULT;                           736     return -SOS_EFAULT;
688                                                   737 
689   *arg3 = other_args[0];                          738   *arg3 = other_args[0];
690   *arg4 = other_args[1];                          739   *arg4 = other_args[1];
691   return SOS_OK;                                  740   return SOS_OK;
692 }                                                 741 }
693                                                   742 
694                                                   743 
695 sos_ret_t sos_syscall_get5args(const struct so    744 sos_ret_t sos_syscall_get5args(const struct sos_cpu_state *user_ctxt,
696                                /* out */unsign    745                                /* out */unsigned int *arg1,
697                                /* out */unsign    746                                /* out */unsigned int *arg2,
698                                /* out */unsign    747                                /* out */unsigned int *arg3,
699                                /* out */unsign    748                                /* out */unsigned int *arg4,
700                                /* out */unsign    749                                /* out */unsigned int *arg5)
701 {                                                 750 {
702   sos_uaddr_t  uaddr_other_args;                  751   sos_uaddr_t  uaddr_other_args;
703   unsigned int other_args[3];                     752   unsigned int other_args[3];
704   sos_ret_t    retval;                            753   sos_ret_t    retval;
705                                                   754 
706   /* Retrieve the 3 arguments. The last one is    755   /* Retrieve the 3 arguments. The last one is an array containing the
707      remaining arguments */                       756      remaining arguments */
708   retval = sos_syscall_get3args(user_ctxt, arg    757   retval = sos_syscall_get3args(user_ctxt, arg1, arg2,
709                                 (unsigned int     758                                 (unsigned int *)& uaddr_other_args);
710   if (SOS_OK != retval)                           759   if (SOS_OK != retval)
711     return retval;                                760     return retval;
712                                                   761   
713   /* Copy the array containing the remaining a    762   /* Copy the array containing the remaining arguments from user
714      space */                                     763      space */
715   retval = sos_memcpy_from_user((sos_vaddr_t)o    764   retval = sos_memcpy_from_user((sos_vaddr_t)other_args,
716                                 (sos_uaddr_t)u    765                                 (sos_uaddr_t)uaddr_other_args,
717                                 sizeof(other_a    766                                 sizeof(other_args));
718   if (sizeof(other_args) != retval)               767   if (sizeof(other_args) != retval)
719     return -SOS_EFAULT;                           768     return -SOS_EFAULT;
720                                                   769 
721   *arg3 = other_args[0];                          770   *arg3 = other_args[0];
722   *arg4 = other_args[1];                          771   *arg4 = other_args[1];
723   *arg5 = other_args[2];                          772   *arg5 = other_args[2];
724   return SOS_OK;                                  773   return SOS_OK;
725 }                                                 774 }
726                                                   775 
727                                                   776 
728 sos_ret_t sos_syscall_get6args(const struct so    777 sos_ret_t sos_syscall_get6args(const struct sos_cpu_state *user_ctxt,
729                                /* out */unsign    778                                /* out */unsigned int *arg1,
730                                /* out */unsign    779                                /* out */unsigned int *arg2,
731                                /* out */unsign    780                                /* out */unsigned int *arg3,
732                                /* out */unsign    781                                /* out */unsigned int *arg4,
733                                /* out */unsign    782                                /* out */unsigned int *arg5,
734                                /* out */unsign    783                                /* out */unsigned int *arg6)
735 {                                                 784 {
736   sos_uaddr_t  uaddr_other_args;                  785   sos_uaddr_t  uaddr_other_args;
737   unsigned int other_args[4];                     786   unsigned int other_args[4];
738   sos_ret_t    retval;                            787   sos_ret_t    retval;
739                                                   788 
740   /* Retrieve the 3 arguments. The last one is    789   /* Retrieve the 3 arguments. The last one is an array containing the
741      remaining arguments */                       790      remaining arguments */
742   retval = sos_syscall_get3args(user_ctxt, arg    791   retval = sos_syscall_get3args(user_ctxt, arg1, arg2,
743                                 (unsigned int     792                                 (unsigned int *)& uaddr_other_args);
744   if (SOS_OK != retval)                           793   if (SOS_OK != retval)
745     return retval;                                794     return retval;
746                                                   795   
747   /* Copy the array containing the remaining a    796   /* Copy the array containing the remaining arguments from user
748      space */                                     797      space */
749   retval = sos_memcpy_from_user((sos_vaddr_t)o    798   retval = sos_memcpy_from_user((sos_vaddr_t)other_args,
750                                 (sos_uaddr_t)u    799                                 (sos_uaddr_t)uaddr_other_args,
751                                 sizeof(other_a    800                                 sizeof(other_args));
752   if (sizeof(other_args) != retval)               801   if (sizeof(other_args) != retval)
753     return -SOS_EFAULT;                           802     return -SOS_EFAULT;
754                                                   803 
755   *arg3 = other_args[0];                          804   *arg3 = other_args[0];
756   *arg4 = other_args[1];                          805   *arg4 = other_args[1];
757   *arg5 = other_args[2];                          806   *arg5 = other_args[2];
758   *arg6 = other_args[3];                          807   *arg6 = other_args[3];
759   return SOS_OK;                                  808   return SOS_OK;
760 }                                                 809 }
761                                                   810 
762                                                   811 
763 sos_ret_t sos_syscall_get7args(const struct so    812 sos_ret_t sos_syscall_get7args(const struct sos_cpu_state *user_ctxt,
764                                /* out */unsign    813                                /* out */unsigned int *arg1,
765                                /* out */unsign    814                                /* out */unsigned int *arg2,
766                                /* out */unsign    815                                /* out */unsigned int *arg3,
767                                /* out */unsign    816                                /* out */unsigned int *arg4,
768                                /* out */unsign    817                                /* out */unsigned int *arg5,
769                                /* out */unsign    818                                /* out */unsigned int *arg6,
770                                /* out */unsign    819                                /* out */unsigned int *arg7)
771 {                                                 820 {
772   sos_uaddr_t  uaddr_other_args;                  821   sos_uaddr_t  uaddr_other_args;
773   unsigned int other_args[5];                     822   unsigned int other_args[5];
774   sos_ret_t    retval;                            823   sos_ret_t    retval;
775                                                   824 
776   /* Retrieve the 3 arguments. The last one is    825   /* Retrieve the 3 arguments. The last one is an array containing the
777      remaining arguments */                       826      remaining arguments */
778   retval = sos_syscall_get3args(user_ctxt, arg    827   retval = sos_syscall_get3args(user_ctxt, arg1, arg2,
779                                 (unsigned int     828                                 (unsigned int *)& uaddr_other_args);
780   if (SOS_OK != retval)                           829   if (SOS_OK != retval)
781     return retval;                                830     return retval;
782                                                   831   
783   /* Copy the array containing the remaining a    832   /* Copy the array containing the remaining arguments from user
784      space */                                     833      space */
785   retval = sos_memcpy_from_user((sos_vaddr_t)o    834   retval = sos_memcpy_from_user((sos_vaddr_t)other_args,
786                                 (sos_uaddr_t)u    835                                 (sos_uaddr_t)uaddr_other_args,
787                                 sizeof(other_a    836                                 sizeof(other_args));
788   if (sizeof(other_args) != retval)               837   if (sizeof(other_args) != retval)
789     return -SOS_EFAULT;                           838     return -SOS_EFAULT;
790                                                   839 
791   *arg3 = other_args[0];                          840   *arg3 = other_args[0];
792   *arg4 = other_args[1];                          841   *arg4 = other_args[1];
793   *arg5 = other_args[2];                          842   *arg5 = other_args[2];
794   *arg6 = other_args[3];                          843   *arg6 = other_args[3];
795   *arg7 = other_args[4];                          844   *arg7 = other_args[4];
796   return SOS_OK;                                  845   return SOS_OK;
797 }                                                 846 }
798                                                   847 
799                                                   848 
800 sos_ret_t sos_syscall_get8args(const struct so    849 sos_ret_t sos_syscall_get8args(const struct sos_cpu_state *user_ctxt,
801                                /* out */unsign    850                                /* out */unsigned int *arg1,
802                                /* out */unsign    851                                /* out */unsigned int *arg2,
803                                /* out */unsign    852                                /* out */unsigned int *arg3,
804                                /* out */unsign    853                                /* out */unsigned int *arg4,
805                                /* out */unsign    854                                /* out */unsigned int *arg5,
806                                /* out */unsign    855                                /* out */unsigned int *arg6,
807                                /* out */unsign    856                                /* out */unsigned int *arg7,
808                                /* out */unsign    857                                /* out */unsigned int *arg8)
809 {                                                 858 {
810   sos_uaddr_t  uaddr_other_args;                  859   sos_uaddr_t  uaddr_other_args;
811   unsigned int other_args[6];                     860   unsigned int other_args[6];
812   sos_ret_t    retval;                            861   sos_ret_t    retval;
813                                                   862 
814   /* Retrieve the 3 arguments. The last one is    863   /* Retrieve the 3 arguments. The last one is an array containing the
815      remaining arguments */                       864      remaining arguments */
816   retval = sos_syscall_get3args(user_ctxt, arg    865   retval = sos_syscall_get3args(user_ctxt, arg1, arg2,
817                                 (unsigned int     866                                 (unsigned int *)& uaddr_other_args);
818   if (SOS_OK != retval)                           867   if (SOS_OK != retval)
819     return retval;                                868     return retval;
820                                                   869   
821   /* Copy the array containing the remaining a    870   /* Copy the array containing the remaining arguments from user
822      space */                                     871      space */
823   retval = sos_memcpy_from_user((sos_vaddr_t)o    872   retval = sos_memcpy_from_user((sos_vaddr_t)other_args,
824                                 (sos_uaddr_t)u    873                                 (sos_uaddr_t)uaddr_other_args,
825                                 sizeof(other_a    874                                 sizeof(other_args));
826   if (sizeof(other_args) != retval)               875   if (sizeof(other_args) != retval)
827     return -SOS_EFAULT;                           876     return -SOS_EFAULT;
828                                                   877 
829   *arg3 = other_args[0];                          878   *arg3 = other_args[0];
830   *arg4 = other_args[1];                          879   *arg4 = other_args[1];
831   *arg5 = other_args[2];                          880   *arg5 = other_args[2];
832   *arg6 = other_args[3];                          881   *arg6 = other_args[3];
833   *arg7 = other_args[4];                          882   *arg7 = other_args[4];
834   *arg8 = other_args[5];                          883   *arg8 = other_args[5];
835   return SOS_OK;                                  884   return SOS_OK;
836 }                                                 885 }
837                                                   886 
838                                                   887 
839 /* ===========================================    888 /* =======================================================================
840  * Backtrace facility. To be used for DEBUGgin    889  * Backtrace facility. To be used for DEBUGging purpose ONLY.
841  */                                               890  */
842                                                   891 
843                                                   892 
844 sos_ui32_t sos_backtrace(const struct sos_cpu_    893 sos_ui32_t sos_backtrace(const struct sos_cpu_state *cpu_state,
845                          sos_ui32_t max_depth,    894                          sos_ui32_t max_depth,
846                          sos_vaddr_t stack_bot    895                          sos_vaddr_t stack_bottom,
847                          sos_size_t stack_size    896                          sos_size_t stack_size,
848                          sos_backtrace_callbac    897                          sos_backtrace_callback_t * backtracer,
849                          void *custom_arg)        898                          void *custom_arg)
850 {                                                 899 {
851   int depth;                                      900   int depth;
852   sos_vaddr_t callee_PC, caller_frame;            901   sos_vaddr_t callee_PC, caller_frame;
853                                                   902 
854   /* Cannot backtrace an interrupted user thre    903   /* Cannot backtrace an interrupted user thread ! */
855   if ((NULL != cpu_state)                         904   if ((NULL != cpu_state)
856       &&                                          905       &&
857       (TRUE == sos_cpu_context_is_in_user_mode    906       (TRUE == sos_cpu_context_is_in_user_mode(cpu_state)))
858     {                                             907     {
859       return 0;                                   908       return 0;
860     }                                             909     }
861                                                   910   
862   /*                                              911   /*
863    * Layout of a frame on the x86 (compiler=gc    912    * Layout of a frame on the x86 (compiler=gcc):
864    *                                              913    *
865    * funcA calls funcB calls funcC                914    * funcA calls funcB calls funcC
866    *                                              915    *
867    *         ....                                 916    *         ....
868    *         funcB Argument 2                     917    *         funcB Argument 2
869    *         funcB Argument 1                     918    *         funcB Argument 1
870    *         funcA Return eip                     919    *         funcA Return eip
871    * frameB: funcA ebp (ie previous stack fram    920    * frameB: funcA ebp (ie previous stack frame)
872    *         ....                                 921    *         ....
873    *         (funcB local variables)              922    *         (funcB local variables)
874    *         ....                                 923    *         ....
875    *         funcC Argument 2                     924    *         funcC Argument 2
876    *         funcC Argument 1                     925    *         funcC Argument 1
877    *         funcB Return eip                     926    *         funcB Return eip
878    * frameC: funcB ebp (ie previous stack fram    927    * frameC: funcB ebp (ie previous stack frame == A0) <---- a frame address
879    *         ....                                 928    *         ....
880    *         (funcC local variables)              929    *         (funcC local variables)
881    *         ....                                 930    *         ....
882    *                                              931    *
883    * The presence of "ebp" on the stack depend    932    * The presence of "ebp" on the stack depends on 2 things:
884    *   + the compiler is gcc                      933    *   + the compiler is gcc
885    *   + the source is compiled WITHOUT the -f    934    *   + the source is compiled WITHOUT the -fomit-frame-pointer option
886    * In the absence of "ebp", chances are high    935    * In the absence of "ebp", chances are high that the value pushed
887    * at that address is outside the stack boun    936    * at that address is outside the stack boundaries, meaning that the
888    * function will return -SOS_ENOSUP.            937    * function will return -SOS_ENOSUP.
889    */                                             938    */
890                                                   939 
891   if (cpu_state)                                  940   if (cpu_state)
892     {                                             941     {
893       callee_PC    = cpu_state->eip;              942       callee_PC    = cpu_state->eip;
894       caller_frame = cpu_state->ebp;              943       caller_frame = cpu_state->ebp;
895     }                                             944     }
896   else                                            945   else
897     {                                             946     {
898       /* Skip the sos_backtrace() frame */        947       /* Skip the sos_backtrace() frame */
899       callee_PC    = (sos_vaddr_t)__builtin_re    948       callee_PC    = (sos_vaddr_t)__builtin_return_address(0);
900       caller_frame = (sos_vaddr_t)__builtin_fr    949       caller_frame = (sos_vaddr_t)__builtin_frame_address(1);
901     }                                             950     }
902                                                   951 
903   for(depth=0 ; depth < max_depth ; depth ++)     952   for(depth=0 ; depth < max_depth ; depth ++)
904     {                                             953     {
905       /* Call the callback */                     954       /* Call the callback */
906       backtracer(callee_PC, caller_frame + 8,     955       backtracer(callee_PC, caller_frame + 8, depth, custom_arg);
907                                                   956 
908       /* If the frame address is funky, don't     957       /* If the frame address is funky, don't go further */
909       if ( (caller_frame < stack_bottom)          958       if ( (caller_frame < stack_bottom)
910            || (caller_frame + 4 >= stack_botto    959            || (caller_frame + 4 >= stack_bottom + stack_size) )
911         return depth;                             960         return depth;
912                                                   961 
913       /* Go to caller frame */                    962       /* Go to caller frame */
914       callee_PC    = *((sos_vaddr_t*) (caller_    963       callee_PC    = *((sos_vaddr_t*) (caller_frame + 4));
915       caller_frame = *((sos_vaddr_t*) caller_f    964       caller_frame = *((sos_vaddr_t*) caller_frame);
916     }                                             965     }
917                                                   966   
918   return depth;                                   967   return depth;
919 }                                                 968 }
920                                                   969 
921                                                   970 
922 /* *******************************************    971 /* *************************************************************
923  * Function to manage the TSS.  This function     972  * Function to manage the TSS.  This function is not really "public":
924  * it is reserved to the assembler routines de    973  * it is reserved to the assembler routines defined in
925  * cpu_context_switch.S                           974  * cpu_context_switch.S
926  *                                                975  *
927  * Update the kernel stack address so that the    976  * Update the kernel stack address so that the IRQ, syscalls and
928  * exception return in a correct stack locatio    977  * exception return in a correct stack location when coming back into
929  * kernel mode.                                   978  * kernel mode.
930  */                                               979  */
931 void                                              980 void
932 sos_cpu_context_update_kernel_tss(struct sos_c    981 sos_cpu_context_update_kernel_tss(struct sos_cpu_state *next_ctxt)
933 {                                                 982 {
934   /* next_ctxt corresponds to an interrupted u    983   /* next_ctxt corresponds to an interrupted user thread ? */
935   if (sos_cpu_context_is_in_user_mode(next_ctx    984   if (sos_cpu_context_is_in_user_mode(next_ctxt))
936     {                                             985     {
937       /*                                          986       /*
938        * Yes: "next_ctxt" is an interrupted us    987        * Yes: "next_ctxt" is an interrupted user thread => we are
939        * going to switch to user mode ! Setup     988        * going to switch to user mode ! Setup the stack address so
940        * that the user thread "next_ctxt" can     989        * that the user thread "next_ctxt" can come back to the correct
941        * stack location when returning in kern    990        * stack location when returning in kernel mode.
942        *                                          991        *
943        * This stack location corresponds to th    992        * This stack location corresponds to the SP of the next user
944        * thread once its context has been tran    993        * thread once its context has been transferred on the CPU, ie
945        * once the CPU has executed all the pop    994        * once the CPU has executed all the pop/iret instruction of the
946        * context switch with privilege change.    995        * context switch with privilege change.
947        */                                         996        */
948       kernel_tss.esp0 = ((sos_vaddr_t)next_ctx    997       kernel_tss.esp0 = ((sos_vaddr_t)next_ctxt)
949                         + sizeof(struct sos_cp    998                         + sizeof(struct sos_cpu_ustate);
950       /* Note: no need to protect this agains     999       /* Note: no need to protect this agains IRQ because IRQs are not
951          allowed to update it by themselves, a    1000          allowed to update it by themselves, and they are not allowed
952          to block */                              1001          to block */
953     }                                             1002     }
954   else                                            1003   else
955     {                                             1004     {
956       /* No: No need to update kernel TSS when    1005       /* No: No need to update kernel TSS when we stay in kernel
957          mode */                                  1006          mode */
958     }                                             1007     }
959 }                                                 1008 }
                                                      

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