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) 2004  The SOS 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 /* Include definitions of the multiboot standard */
021 #include <bootstrap/multiboot.h>
022 #include <hwcore/idt.h>
023 #include <hwcore/gdt.h>
024 #include <hwcore/irq.h>
025 #include <hwcore/exception.h>
026 #include <hwcore/i8254.h>
027 #include <sos/list.h>
028 #include <sos/physmem.h>
029 #include <hwcore/paging.h>
030 #include <sos/kmem_vmm.h>
031 #include <sos/kmalloc.h>
032 #include <sos/klibc.h>
033 #include <sos/assert.h>
034 #include <drivers/x86_videomem.h>
035 #include <drivers/bochs.h>
036 
037 
038 /* Helper function to display each bits of a 32bits integer on the
039    screen as dark or light carrets */
040 void display_bits(unsigned char row, unsigned char col,
041                   unsigned char attribute,
042                   sos_ui32_t integer)
043 {
044   int i;
045   /* Scan each bit of the integer, MSb first */
046   for (i = 31 ; i >= 0 ; i--)
047     {
048       /* Test if bit i of 'integer' is set */
049       int bit_i = (integer & (1 << i));
050       /* Ascii 219 => dark carret, Ascii 177 => light carret */
051       unsigned char ascii_code = bit_i?219:177;
052       sos_x86_videomem_putchar(row, col++,
053                                attribute,
054                                ascii_code);
055     }
056 }
057 
058 
059 /* Clock IRQ handler */
060 static void clk_it(int intid,
061                    const struct sos_cpu_kstate *cpu_kstate)
062 {
063   static sos_ui32_t clock_count = 0;
064 
065   display_bits(0, 48,
066                SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE,
067                clock_count);
068   clock_count++;
069 }
070 
071 
072 /* ======================================================================
073  * Page fault exception handling
074  */
075 
076 /* Helper function to dump a backtrace on bochs and/or the console */
077 static void dump_backtrace(const struct sos_cpu_kstate *cpu_kstate,
078                            sos_vaddr_t stack_bottom,
079                            sos_size_t  stack_size,
080                            sos_bool_t on_console,
081                            sos_bool_t on_bochs)
082 {
083   static void backtracer(sos_vaddr_t PC,
084                          sos_vaddr_t params,
085                          sos_ui32_t depth,
086                          void *custom_arg)
087     {
088       sos_ui32_t invalid = 0xffffffff, *arg1, *arg2, *arg3, *arg4;
089 
090       /* Get the address of the first 3 arguments from the
091          frame. Among these arguments, 0, 1, 2, 3 arguments might be
092          meaningful (depending on how many arguments the function may
093          take). */
094       arg1 = (sos_ui32_t*)params;
095       arg2 = (sos_ui32_t*)(params+4);
096       arg3 = (sos_ui32_t*)(params+8);
097       arg4 = (sos_ui32_t*)(params+12);
098 
099       /* Make sure the addresses of these arguments fit inside the
100          stack boundaries */
101 #define INTERVAL_OK(b,v,u) ( ((b) <= (sos_vaddr_t)(v)) \
102                              && ((sos_vaddr_t)(v) < (u)) )
103       if (!INTERVAL_OK(stack_bottom, arg1, stack_bottom + stack_size))
104         arg1 = &invalid;
105       if (!INTERVAL_OK(stack_bottom, arg2, stack_bottom + stack_size))
106         arg2 = &invalid;
107       if (!INTERVAL_OK(stack_bottom, arg3, stack_bottom + stack_size))
108         arg3 = &invalid;
109       if (!INTERVAL_OK(stack_bottom, arg4, stack_bottom + stack_size))
110         arg4 = &invalid;
111 
112       /* Print the function context for this frame */
113       if (on_bochs)
114         sos_bochs_printf("[%d] PC=0x%x arg1=0x%x arg2=0x%x arg3=0x%x\n",
115                          (unsigned)depth, (unsigned)PC,
116                          (unsigned)*arg1, (unsigned)*arg2,
117                          (unsigned)*arg3);
118 
119       if (on_console)
120         sos_x86_videomem_printf(23-depth, 3,
121                                 SOS_X86_VIDEO_BG_BLUE
122                                   | SOS_X86_VIDEO_FG_LTGREEN,
123                                 "[%d] PC=0x%x arg1=0x%x arg2=0x%x arg3=0x%x arg4=0x%x",
124                                 (unsigned)depth, PC,
125                                 (unsigned)*arg1, (unsigned)*arg2,
126                                 (unsigned)*arg3, (unsigned)*arg4);
127       
128     }
129 
130   sos_backtrace(cpu_kstate, 15, stack_bottom, stack_size, backtracer, NULL);
131 }
132 
133 
134 /* Page fault exception handler with demand paging for the kernel */
135 static void pgflt_ex(int intid, const struct sos_cpu_kstate *ctxt)
136 {
137   static sos_ui32_t demand_paging_count = 0;
138   sos_vaddr_t faulting_vaddr = sos_cpu_kstate_get_EX_faulting_vaddr(ctxt);
139   sos_paddr_t ppage_paddr;
140 
141   /* Check if address is covered by any VMM range */
142   if (! sos_kmem_vmm_is_valid_vaddr(faulting_vaddr))
143     {
144       /* No: The page fault is out of any kernel virtual region. For
145          the moment, we don't handle this. */
146       dump_backtrace(ctxt,
147                      bootstrap_stack_bottom,
148                      bootstrap_stack_size,
149                      TRUE, TRUE);
150       sos_display_fatal_error("Unresolved page Fault on access to address 0x%x (info=%x)!",
151                               (unsigned)faulting_vaddr,
152                               (unsigned)sos_cpu_kstate_get_EX_info(ctxt));
153       SOS_ASSERT_FATAL(! "Got page fault (note: demand paging is disabled)");
154     }
155 
156 
157   /*
158    * Demand paging
159    */
160  
161   /* Update the number of demand paging requests handled */
162   demand_paging_count ++;
163   display_bits(0, 0,
164                SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE,
165                demand_paging_count);
166 
167   /* Allocate a new page for the virtual address */
168   ppage_paddr = sos_physmem_ref_physpage_new(FALSE);
169   if (! ppage_paddr)
170     SOS_ASSERT_FATAL(! "TODO: implement swap. (Out of mem in demand paging because no swap for kernel yet !)");
171   SOS_ASSERT_FATAL(SOS_OK == sos_paging_map(ppage_paddr,
172                                             SOS_PAGE_ALIGN_INF(faulting_vaddr),
173                                             FALSE,
174                                             SOS_VM_MAP_PROT_READ
175                                             | SOS_VM_MAP_PROT_WRITE
176                                             | SOS_VM_MAP_ATOMIC));
177   sos_physmem_unref_physpage(ppage_paddr);
178 
179   /* Ok, we can now return to interrupted context */
180 }
181 
182 
183 
184 /* ======================================================================
185  * Demonstrate the use of the CPU kernet context management API:
186  *  - A coroutine prints "Hlowrd" and switches to the other after each
187  *    letter
188  *  - A coroutine prints "el ol\n" and switches back to the other after
189  *    each letter.
190  * The first to reach the '\n' returns back to main.
191  */
192 struct sos_cpu_kstate *ctxt_hello1;
193 struct sos_cpu_kstate *ctxt_hello2;
194 struct sos_cpu_kstate *ctxt_main;
195 sos_vaddr_t hello1_stack, hello2_stack;
196 
197 static void reclaim_stack(sos_vaddr_t stack_vaddr)
198 {
199   sos_kfree(stack_vaddr);
200 }
201 
202 
203 static void exit_hello12(sos_vaddr_t stack_vaddr)
204 {
205   sos_cpu_kstate_exit_to(ctxt_main,
206                          (sos_cpu_kstate_function_arg1_t*) reclaim_stack,
207                          stack_vaddr);
208 }
209 
210 
211 static void hello1 (char *str)
212 {
213   for ( ; *str != '\n' ; str++)
214     {
215       sos_bochs_printf("hello1: %c\n", *str);
216       sos_cpu_kstate_switch(& ctxt_hello1, ctxt_hello2);
217     }
218 
219   /* You can uncomment this in case you explicitly want to exit
220      now. But returning from the function will do the same */
221   /* sos_cpu_kstate_exit_to(ctxt_main,
222                          (sos_cpu_kstate_function_arg1_t*) reclaim_stack,
223                          hello1_stack); */
224 }
225 
226 
227 static void hello2 (char *str)
228 {
229   for ( ; *str != '\n' ; str++)
230     {
231       sos_bochs_printf("hello2: %c\n", *str);
232       sos_cpu_kstate_switch(& ctxt_hello2, ctxt_hello1);
233     }
234 
235   /* You can uncomment this in case you explicitly want to exit
236      now. But returning from the function will do the same */
237   /* sos_cpu_kstate_exit_to(ctxt_main,
238                          (sos_cpu_kstate_function_arg1_t*) reclaim_stack,
239                          hello2_stack); */
240 }
241 
242 
243 void print_hello_world ()
244 {
245 #define DEMO_STACK_SIZE 1024
246   /* Allocate the stacks */
247   hello1_stack = sos_kmalloc(DEMO_STACK_SIZE, 0);
248   hello2_stack = sos_kmalloc(DEMO_STACK_SIZE, 0);
249 
250   /* Initialize the coroutines' contexts */
251   sos_cpu_kstate_init(&ctxt_hello1,
252                       (sos_cpu_kstate_function_arg1_t*) hello1,
253                       (sos_ui32_t) "Hlowrd",
254                       (sos_vaddr_t) hello1_stack, DEMO_STACK_SIZE,
255                       (sos_cpu_kstate_function_arg1_t*) exit_hello12,
256                       (sos_ui32_t) hello1_stack);
257   sos_cpu_kstate_init(&ctxt_hello2,
258                       (sos_cpu_kstate_function_arg1_t*) hello2,
259                       (sos_ui32_t) "el ol\n",
260                       (sos_vaddr_t) hello2_stack, DEMO_STACK_SIZE,
261                       (sos_cpu_kstate_function_arg1_t*) exit_hello12,
262                       (sos_ui32_t) hello2_stack);
263 
264   /* Go to first coroutine */
265   sos_bochs_printf("Printing Hello World\\n...\n");
266   sos_cpu_kstate_switch(& ctxt_main, ctxt_hello1);
267 
268   /* The first coroutine to reach the '\n' switched back to us */
269   sos_bochs_printf("Back in main !\n");
270 }
271 
272 
273 /* ======================================================================
274  * Generate page faults on an unmapped but allocated kernel virtual
275  * region, which results in a series of physical memory mappings for the
276  * faulted pages.
277  */
278 static void test_demand_paging(int nb_alloc_vpages, int nb_alloc_ppages)
279 {
280   int i;
281   sos_vaddr_t base_vaddr;
282 
283   sos_x86_videomem_printf(10, 0,
284                           SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_LTGREEN,
285                           "Demand paging test (alloc %dMB of VMM, test %dkB RAM)",
286                           nb_alloc_vpages >> 8, nb_alloc_ppages << 2);
287   
288   /* Allocate virtual memory */
289   base_vaddr = sos_kmem_vmm_alloc(nb_alloc_vpages, 0);
290 
291   SOS_ASSERT_FATAL(base_vaddr != (sos_vaddr_t)NULL);
292   sos_x86_videomem_printf(11, 0,
293                           SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
294                           "Allocated virtual region [0x%x, 0x%x[",
295                           base_vaddr,
296                           base_vaddr + nb_alloc_vpages*SOS_PAGE_SIZE);
297 
298   /* Now use part of it in physical memory */
299   for (i = 0 ; (i < nb_alloc_ppages) && (i < nb_alloc_vpages) ; i++)
300     {
301       /* Compute an address inside the range */
302       sos_ui32_t *value, j;
303       sos_vaddr_t vaddr = base_vaddr;
304       vaddr += (nb_alloc_vpages - (i + 1))*SOS_PAGE_SIZE;
305       vaddr += 2345;
306 
307       sos_x86_videomem_printf(12, 0,
308                               SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
309                               "Writing %d at virtual address 0x%x...",
310                               i, vaddr);
311 
312       /* Write at this address */
313       value = (sos_ui32_t*)vaddr;
314       *value = i;
315 
316       /* Yep ! A new page should normally have been allocated for us */
317       sos_x86_videomem_printf(13, 0,
318                               SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
319                               "Value read at address 0x%x = %d",
320                               vaddr, (unsigned)*value);
321     }
322 
323   SOS_ASSERT_FATAL(SOS_OK == sos_kmem_vmm_free(base_vaddr));
324   /* Yep ! A new page should normally have been allocated for us */
325   sos_x86_videomem_printf(14, 0,
326                           SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
327                           "Done (area un-allocated)");
328 }
329 
330 
331 
332 /* ======================================================================
333  * Shows how the backtrace stuff works
334  */
335 
336 /* Recursive function. Print the backtrace from the innermost function */
337 static void test_backtrace(int i, int magic, sos_vaddr_t stack_bottom,
338                            sos_size_t  stack_size)
339 {
340   if (i <= 0)
341     {
342       /* The page fault exception handler will print the backtrace of
343          this function, because address 0x42 is not mapped */
344       *((char*)0x42) = 12;
345 
346       /* More direct variant: */
347       /* dump_backtrace(NULL, stack_bottom, stack_size, TRUE, TRUE); */
348     }
349   else
350     test_backtrace(i-1, magic, stack_bottom, stack_size);
351 }
352 
353 
354 /* ======================================================================
355  * Parsing of Mathematical expressions
356  *
357  * This is a recursive lexer/parser/evaluator for arithmetical
358  * expressions. Supports both binary +/-* and unary +- operators, as
359  * well as parentheses.
360  *
361  * Terminal tokens (Lexer):
362  *  - Number: positive integer number
363  *  - Variable: ascii name (regexp: [a-zA-Z]+)
364  *  - Operator: +*-/
365  *  - Opening/closing parentheses
366  *
367  * Grammar (Parser):
368  *  Expression ::= Term E'
369  *  Expr_lr    ::= + Term Expr_lr | - Term Expr_lr | Nothing
370  *  Term       ::= Factor Term_lr
371  *  Term_lr    ::= * Factor Term_lr | / Factor Term_lr | Nothing
372  *  Factor     ::= - Factor | + Factor | Scalar | ( Expression )
373  *  Scalar     ::= Number | Variable
374  *
375  * Note. This is the left-recursive equivalent of the following basic grammar:
376  *  Expression ::= Expression + Term | Expression - Term
377  *  Term       ::= Term * Factor | Term / Factor
378  *  factor     ::= - Factor | + Factor | Scalar | Variable | ( Expression )
379  *  Scalar     ::= Number | Variable
380  *
381  * The parsing is composed of a 3 stages pipeline:
382  *  - The reader: reads a string 1 character at a time, transferring
383  *    the control back to lexer after each char. This function shows the
384  *    interest in using coroutines, because its state (str) is
385  *    implicitely stored in the stack between each iteration.
386  *  - The lexer: consumes the characters from the reader and identifies
387  *    the terminal tokens, 1 token at a time, transferring control back
388  *    to the parser after each token. This function shows the interest
389  *    in using coroutines, because its state (c and got_what_before) is
390  *    implicitely stored in the stack between each iteration.
391  *  - The parser: consumes the tokens from the lexer and builds the
392  *    syntax tree of the expression. There is no real algorithmic
393  *    interest in defining a coroutine devoted to do this. HOWEVER, we
394  *    do use one for that because this allows us to switch to a much
395  *    deeper stack. Actually, the parser is highly recursive, so that
396  *    the default 16kB stack of the sos_main() function might not be
397  *    enough. Here, we switch to a 64kB stack, which is safer for
398  *    recursive functions. The Parser uses intermediary functions: these
399  *    are defined and implemented as internal nested functions. This is
400  *    just for the sake of clarity, and is absolutely not mandatory for
401  *    the algorithm: one can transfer these functions out of the parser
402  *    function without restriction.
403  *
404  * The evaluator is another recursive function that reuses the
405  * parser's stack to evaluate the parsed expression with the given
406  * values for the variables present in the expression. As for the
407  * parser function, this function defines and uses a nested function,
408  * which can be extracted from the main evaluation function at will.
409  *
410  * All these functions support a kind of "exception" feature: when
411  * something goes wrong, control is transferred DIRECTLY back to the
412  * sos_main() context, without unrolling the recursions. This shows
413  * how exceptions basically work, but one should not consider this as
414  * a reference exceptions implementation. Real exception mechanisms
415  * (such as that in the C++ language) call the destructors to the
416  * objects allocated on the stack during the "stack unwinding" process
417  * upon exception handling, which complicates a lot the mechanism. We
418  * don't have real Objects here (in the OOP sense, full-featured with
419  * destructors), so we don't have to complicate things.
420  *
421  * After this little coroutine demo, one should forget all about such
422  * a low-level manual direct manipulation of stacks. This would
423  * probably mess up the whole kernel to do what we do here (locked
424  * resources such as mutex/semaphore won't be correctly unlocked,
425  * ...). Higher level "kernel thread" primitives will soon be
426  * presented, which provide a higher-level set of APIs to manage CPU
427  * contexts. You'll have to use EXCLUSIVELY those APIs. If you still
428  * need a huge stack to do recursion for example, please don't even
429  * think of changing manually the stack for something bigger ! Simply
430  * rethink your algorithm, making it non-recursive.
431  */
432 
433 
434 /* The stacks involved */
435 static char stack_reader[1024];
436 static char stack_lexer[1024];
437 static char deep_stack[65536]; /* For the parser and the evaluator */
438 
439 /* The CPU states for the various coroutines */
440 static struct sos_cpu_kstate *st_reader, *st_lexer, *st_parser,
441   *st_eval, *st_free, *st_main;
442 
443 
444 /*
445  * Default exit/reclaim functions: return control to the "sos_main()"
446  * context
447  */
448 static void reclaim(int unused)
449 {
450 }
451 static void func_exit(sos_ui32_t unused)
452 {
453   sos_cpu_kstate_exit_to(st_main, (sos_cpu_kstate_function_arg1_t*)reclaim, 0);
454 }
455 
456 
457 /*
458  * The reader coroutine and associated variable. This coroutine could
459  * have been a normal function, except that the current parsed
460  * character would have to be stored somewhere.
461  */
462 static char data_reader_to_lexer;
463 
464 static void func_reader(const char *str)
465 {
466   for ( ; str && (*str != '\0') ; str++)
467     {
468       data_reader_to_lexer = *str;
469       sos_cpu_kstate_switch(& st_reader, st_lexer);
470     }
471 
472   data_reader_to_lexer = '\0';
473   sos_cpu_kstate_switch(& st_reader, st_lexer);
474 }
475 
476 
477 /*
478  * The Lexer coroutine and associated types/variables. This coroutine
479  * could have been a normal function, except that the current parsed
480  * character, token and previous token would have to be stored
481  * somewhere.
482  */
483 #define STR_VAR_MAXLEN 16
484 static struct lex_elem
485 {
486   enum { LEX_IS_NUMBER, LEX_IS_OPER, LEX_IS_VAR,
487          LEX_IS_OPENPAR, LEX_IS_CLOSEPAR, LEX_END } type;
488   union {
489     int  number;
490     char operator;
491     char var[STR_VAR_MAXLEN];
492   };
493 } data_lexer_to_parser;
494 
495 static void func_lexer(sos_ui32_t unused)
496 {
497   char c;
498   enum { GOT_SPACE, GOT_NUM, GOT_OP, GOT_STR,
499          GOT_OPENPAR, GOT_CLOSEPAR } got_what, got_what_before;
500 
501   data_lexer_to_parser.number = 0;
502   got_what_before = GOT_SPACE;
503   do
504     {
505       /* Consume one character from the reader */
506       sos_cpu_kstate_switch(& st_lexer, st_reader);
507       c = data_reader_to_lexer;
508 
509       /* Classify the consumed character */
510       if ( (c >= '0') && (c <= '9') )
511         got_what = GOT_NUM;
512       else if ( (c == '+') || (c == '-') || (c == '*') || (c == '/') )
513         got_what = GOT_OP;
514       else if ( ( (c >= 'a') && (c <= 'z') )
515                 || ( (c >= 'A') && (c <= 'Z') ) )
516         got_what = GOT_STR;
517       else if (c == '(')
518         got_what = GOT_OPENPAR;
519       else if (c == ')')
520         got_what = GOT_CLOSEPAR;
521       else
522         got_what = GOT_SPACE;
523 
524       /* Determine whether the current token is ended */
525       if ( (got_what != got_what_before)
526            || (got_what_before == GOT_OP)
527            || (got_what_before == GOT_OPENPAR)
528            || (got_what_before == GOT_CLOSEPAR) )
529         {
530           /* return control back to the parser if the previous token
531              has been recognized */
532           if ( (got_what_before != GOT_SPACE) )
533             sos_cpu_kstate_switch(& st_lexer, st_parser);
534 
535           data_lexer_to_parser.number = 0;
536         }
537 
538       /* Update the token being currently recognized */
539       if (got_what == GOT_OP)
540         {
541           data_lexer_to_parser.type = LEX_IS_OPER;
542           data_lexer_to_parser.operator = c;
543         }
544       else if (got_what == GOT_NUM)
545         {
546           data_lexer_to_parser.type = LEX_IS_NUMBER;
547           data_lexer_to_parser.number *= 10;
548           data_lexer_to_parser.number += (c - '0');
549         }
550       else if (got_what == GOT_STR)
551         {
552           char to_cat[] = { c, '\0' };
553           data_lexer_to_parser.type = LEX_IS_VAR;
554           strzcat(data_lexer_to_parser.var, to_cat, STR_VAR_MAXLEN);
555         }
556       else if (got_what == GOT_OPENPAR)
557         data_lexer_to_parser.type = LEX_IS_OPENPAR;
558       else if (got_what == GOT_CLOSEPAR)
559         data_lexer_to_parser.type = LEX_IS_CLOSEPAR;
560 
561       got_what_before = got_what;
562     }
563   while (c != '\0');
564 
565   /* Transfer last recognized token to the parser */
566   if ( (got_what_before != GOT_SPACE) )
567     sos_cpu_kstate_switch(& st_lexer, st_parser);
568 
569   /* Signal that no more token are available */
570   data_lexer_to_parser.type = LEX_END;
571   sos_cpu_kstate_switch(& st_lexer, st_parser);
572 
573   /* Exception: parser asks for a token AFTER having received the last
574      one */
575   sos_bochs_printf("Error: end of string already reached !\n");
576   sos_cpu_kstate_switch(& st_lexer, st_main);
577 }
578 
579 
580 /*
581  * The Parser coroutine and associated types/variables
582  */
583 struct syntax_node
584 {
585   enum { YY_IS_BINOP, YY_IS_UNAROP, YY_IS_NUM, YY_IS_VAR } type;
586   union
587   {
588     int  number;
589     char var[STR_VAR_MAXLEN];
590     struct
591     {
592       char op;
593       struct syntax_node *parm_left, *parm_right;
594     } binop;
595     struct
596     {
597       char op;
598       struct syntax_node *parm;
599     } unarop;
600   };
601 };
602 
603 static void func_parser(struct syntax_node ** syntax_tree)
604 {
605   static struct syntax_node *alloc_node_num(int val);
606   static struct syntax_node *alloc_node_var(const char * name);
607   static struct syntax_node *alloc_node_binop(char op,
608                                               struct syntax_node *parm_left,
609                                               struct syntax_node *parm_right);
610   static struct syntax_node *alloc_node_unarop(char op,
611                                                struct syntax_node *parm);
612   static struct syntax_node * get_expr();
613   static struct syntax_node * get_expr_lr(struct syntax_node *n);
614   static struct syntax_node * get_term();
615   static struct syntax_node * get_term_lr(struct syntax_node *n);
616   static struct syntax_node * get_factor();
617   static struct syntax_node * get_scalar();
618 
619   /* Create a new node to store a number */
620   static struct syntax_node *alloc_node_num(int val)
621     {
622       struct syntax_node *n
623         = (struct syntax_node*) sos_kmalloc(sizeof(struct syntax_node), 0);
624       n->type   = YY_IS_NUM;
625       n->number = val;
626       return n;
627     }
628   /* Create a new node to store a variable */
629   static struct syntax_node *alloc_node_var(const char * name)
630     {
631       struct syntax_node *n
632         = (struct syntax_node*) sos_kmalloc(sizeof(struct syntax_node), 0);
633       n->type   = YY_IS_VAR;
634       strzcpy(n->var, name, STR_VAR_MAXLEN);
635       return n;
636     }
637   /* Create a new node to store a binary operator */
638   static struct syntax_node *alloc_node_binop(char op,
639                                               struct syntax_node *parm_left,
640                                               struct syntax_node *parm_right)
641     {
642       struct syntax_node *n
643         = (struct syntax_node*) sos_kmalloc(sizeof(struct syntax_node), 0);
644       n->type             = YY_IS_BINOP;
645       n->binop.op         = op;
646       n->binop.parm_left  = parm_left;
647       n->binop.parm_right = parm_right;
648       return n;
649     }
650   /* Create a new node to store a unary operator */
651   static struct syntax_node *alloc_node_unarop(char op,
652                                                struct syntax_node *parm)
653     {
654       struct syntax_node *n
655         = (struct syntax_node*) sos_kmalloc(sizeof(struct syntax_node), 0);
656       n->type        = YY_IS_UNAROP;
657       n->unarop.op   = op;
658       n->unarop.parm = parm;
659       return n;
660     }
661 
662   /* Raise an exception: transfer control back to main context,
663      without unrolling the whole recursion */
664   static void parser_exception(const char *str)
665     {
666       sos_bochs_printf("Parser exception: %s\n", str);
667       sos_cpu_kstate_switch(& st_parser, st_main);
668     }
669 
670   /* Consume the current terminal "number" token and ask for a new
671      token */
672   static int get_number()
673     {
674       int v;
675       if (data_lexer_to_parser.type != LEX_IS_NUMBER)
676         parser_exception("Expected number");
677       v = data_lexer_to_parser.number;
678       sos_cpu_kstate_switch(& st_parser, st_lexer);
679       return v;
680     }
681   /* Consume the current terminal "variable" token and ask for a new
682      token */
683   static void get_str(char name[STR_VAR_MAXLEN])
684     {
685       if (data_lexer_to_parser.type != LEX_IS_VAR)
686         parser_exception("Expected variable");
687       strzcpy(name, data_lexer_to_parser.var, STR_VAR_MAXLEN);
688       sos_cpu_kstate_switch(& st_parser, st_lexer);
689     }
690   /* Consume the current terminal "operator" token and ask for a new
691      token */
692   static char get_op()
693     {
694       char op;
695       if (data_lexer_to_parser.type != LEX_IS_OPER)
696         parser_exception("Expected operator");
697       op = data_lexer_to_parser.operator;
698       sos_cpu_kstate_switch(& st_parser, st_lexer);
699       return op;
700     }
701   /* Consume the current terminal "parenthese" token and ask for a new
702      token */
703   static void get_par()
704     {
705       if ( (data_lexer_to_parser.type != LEX_IS_OPENPAR)
706            && (data_lexer_to_parser.type != LEX_IS_CLOSEPAR) )
707         parser_exception("Expected parenthese");
708       sos_cpu_kstate_switch(& st_parser, st_lexer);
709     }
710 
711   /* Parse an Expression */
712   static struct syntax_node * get_expr()
713     {
714       struct syntax_node *t = get_term();
715       return get_expr_lr(t);
716     }
717   /* Parse an Expr_lr */
718   static struct syntax_node * get_expr_lr(struct syntax_node *n)
719     {
720       if ( (data_lexer_to_parser.type == LEX_IS_OPER)
721            && ( (data_lexer_to_parser.operator == '+')
722                 || (data_lexer_to_parser.operator == '-') ) )
723         {
724           char op = get_op();
725           struct syntax_node *term = get_term();
726           struct syntax_node *node_op = alloc_node_binop(op, n, term);
727           return get_expr_lr(node_op);
728         }
729       return n;
730     }
731   /* Parse a Term */
732   static struct syntax_node * get_term()
733     {
734       struct syntax_node *f1 = get_factor();
735       return get_term_lr(f1);
736     }
737   /* Parse a Term_lr */
738   static struct syntax_node * get_term_lr(struct syntax_node *n)
739     {
740       if ( (data_lexer_to_parser.type == LEX_IS_OPER)
741            && ( (data_lexer_to_parser.operator == '*')
742                 || (data_lexer_to_parser.operator == '/') ) )
743         {
744           char op = get_op();
745           struct syntax_node *factor = get_factor();
746           struct syntax_node *node_op = alloc_node_binop(op, n, factor);
747           return get_term_lr(node_op);
748         }
749       return n;
750     }
751   /* Parse a Factor */
752   static struct syntax_node * get_factor()
753     {
754       if ( (data_lexer_to_parser.type == LEX_IS_OPER)
755            && ( (data_lexer_to_parser.operator == '-')
756                 || (data_lexer_to_parser.operator == '+') ) )
757         { char op = data_lexer_to_parser.operator;
758         get_op(); return alloc_node_unarop(op, get_factor()); }
759       else if (data_lexer_to_parser.type == LEX_IS_OPENPAR)
760         {
761           struct syntax_node *expr;
762           get_par();
763           expr = get_expr();
764           if (data_lexer_to_parser.type != LEX_IS_CLOSEPAR)
765             parser_exception("Mismatched parentheses");
766           get_par();
767           return expr;
768         }
769   
770       return get_scalar();
771     }
772   /* Parse a Scalar */
773   static struct syntax_node * get_scalar()
774     {
775       if (data_lexer_to_parser.type != LEX_IS_NUMBER)
776         {
777           char var[STR_VAR_MAXLEN];
778           get_str(var);
779           return alloc_node_var(var);
780         }
781       return alloc_node_num(get_number());
782     }
783 
784 
785   /*
786    * Body of the function
787    */
788 
789   /* Get the first token */
790   sos_cpu_kstate_switch(& st_parser, st_lexer);
791 
792   /* Begin the parsing ! */
793   *syntax_tree = get_expr();
794   /* The result is returned in the syntax_tree parameter */
795 }
796 
797 
798 /*
799  * Setup the parser's pipeline
800  */
801 static struct syntax_node * parse_expression(const char *expr)
802 {
803   struct syntax_node *retval = NULL;
804 
805   /* Build the context of the functions in the pipeline */
806   sos_cpu_kstate_init(& st_reader,
807                       (sos_cpu_kstate_function_arg1_t*)func_reader,
808                       (sos_ui32_t)expr,
809                       (sos_vaddr_t)stack_reader, sizeof(stack_reader),
810                       (sos_cpu_kstate_function_arg1_t*)func_exit, 0);
811   sos_cpu_kstate_init(& st_lexer,
812                       (sos_cpu_kstate_function_arg1_t*)func_lexer,
813                       0,
814                       (sos_vaddr_t)stack_lexer, sizeof(stack_lexer),
815                       (sos_cpu_kstate_function_arg1_t*)func_exit, 0);
816   sos_cpu_kstate_init(& st_parser,
817                       (sos_cpu_kstate_function_arg1_t*)func_parser,
818                       (sos_ui32_t) /* syntax tree ! */&retval,
819                       (sos_vaddr_t)deep_stack, sizeof(deep_stack),
820                       (sos_cpu_kstate_function_arg1_t*)func_exit, 0);
821 
822   /* Parse the expression */
823   sos_cpu_kstate_switch(& st_main, st_parser);
824   return retval;
825 }
826 
827 
828 /*
829  * The Evaluator coroutine and associated types/variables
830  */
831 struct func_eval_params
832 {
833   const struct syntax_node *e;
834   const char **var_name;
835   int *var_val;
836   int nb_vars;
837 
838   int result;
839 };
840 
841 static void func_eval(struct func_eval_params *parms)
842 {
843   /* The internal (recursive) nested function to evaluate each node of
844      the syntax tree */
845   static int rec_eval(const struct syntax_node *n,
846                       const char* var_name[], int var_val[], int nb_vars)
847     {
848       switch (n->type)
849         {
850         case YY_IS_NUM:
851           return n->number;
852 
853         case YY_IS_VAR:
854           {
855             int i;
856             for (i = 0 ; i < nb_vars ; i++)
857               if (0 == strcmp(var_name[i], n->var))
858                 return var_val[i];
859 
860             /* Exception: no variable with that name ! */
861             sos_bochs_printf("ERROR: unknown variable %s\n", n->var);
862             sos_cpu_kstate_switch(& st_eval, st_main);
863           }
864 
865         case YY_IS_BINOP:
866           {
867             int left = rec_eval(n->binop.parm_left,
868                                 var_name, var_val, nb_vars);
869             int right = rec_eval(n->binop.parm_right,
870                                  var_name, var_val, nb_vars);
871             switch (n->binop.op)
872               {
873               case '+': return left + right;
874               case '-': return left - right;
875               case '*': return left * right;
876               case '/': return left / right;
877               default:
878                 /* Exception: no such operator (INTERNAL error) ! */
879                 sos_bochs_printf("ERROR: unknown binop %c\n", n->binop.op);
880                 sos_cpu_kstate_switch(& st_eval, st_main);
881               }
882           }
883 
884         case YY_IS_UNAROP:
885           {
886             int arg = rec_eval(n->unarop.parm, var_name, var_val, nb_vars);
887             switch (n->unarop.op)
888               {
889               case '-': return -arg;
890               case '+': return arg;
891               default:
892                 /* Exception: no such operator (INTERNAL error) ! */
893                 sos_bochs_printf("ERROR: unknown unarop %c\n", n->unarop.op);
894                 sos_cpu_kstate_switch(& st_eval, st_main);
895               }
896           }
897         }
898       
899       /* Exception: no such syntax node (INTERNAL error) ! */
900       sos_bochs_printf("ERROR: invalid node type\n");
901       sos_cpu_kstate_switch(& st_eval, st_main);
902       return -1; /* let's make gcc happy */
903     }
904 
905 
906   /*
907    * Function BODY
908    */
909   /* Update p.result returned back to calling function */
910   parms->result
911     = rec_eval(parms->e, parms->var_name, parms->var_val, parms->nb_vars);
912 }
913 
914 /*
915  * Change the stack for something larger in order to call the
916  * recursive function above in a safe way
917  */
918 static int eval_expression(const struct syntax_node *e,
919                            const char* var_name[], int var_val[], int nb_vars)
920 {
921   struct func_eval_params p
922     = (struct func_eval_params){ .e=e,
923                                  .var_name=var_name,
924                                  .var_val=var_val,
925                                  .nb_vars=nb_vars,
926                                  .result = 0 };
927 
928   sos_cpu_kstate_init(& st_eval,
929                       (sos_cpu_kstate_function_arg1_t*)func_eval,
930                       (sos_ui32_t)/* p.result is modified upon success */&p,
931                       (sos_vaddr_t)deep_stack, sizeof(deep_stack),
932                       (sos_cpu_kstate_function_arg1_t*)func_exit, 0);
933 
934   /* Go ! */
935   sos_cpu_kstate_switch(& st_main, st_eval);
936   return p.result;
937 }
938 
939 
940 /*
941  * Function to free the syntax tree
942  */
943 static void func_free(struct syntax_node *n)
944 {
945   switch (n->type)
946     {
947     case YY_IS_NUM:
948     case YY_IS_VAR:
949       break;
950       
951     case YY_IS_BINOP:
952       func_free(n->binop.parm_left);
953       func_free(n->binop.parm_right);
954       break;
955       
956     case YY_IS_UNAROP:
957       func_free(n->unarop.parm);
958       break;
959     }
960   
961   sos_kfree((sos_vaddr_t)n);
962 }
963 
964 /*
965  * Change the stack for something larger in order to call the
966  * recursive function above in a safe way
967  */
968 static void free_syntax_tree(struct syntax_node *tree)
969 {
970   sos_cpu_kstate_init(& st_free,
971                       (sos_cpu_kstate_function_arg1_t*)func_free,
972                       (sos_ui32_t)tree,
973                       (sos_vaddr_t)deep_stack, sizeof(deep_stack),
974                       (sos_cpu_kstate_function_arg1_t*)func_exit, 0);
975 
976   /* Go ! */
977   sos_cpu_kstate_switch(& st_main, st_free);
978 }
979 
980 
981 /* ======================================================================
982  * The C entry point of our operating system
983  */
984 void sos_main(unsigned long magic, unsigned long addr)
985 {
986   unsigned i;
987   sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr;
988   struct syntax_node *syntax_tree;
989 
990   /* Grub sends us a structure, called multiboot_info_t with a lot of
991      precious informations about the system, see the multiboot
992      documentation for more information. */
993   multiboot_info_t *mbi;
994   mbi = (multiboot_info_t *) addr;
995 
996   /* Setup bochs and console, and clear the console */
997   sos_bochs_setup();
998 
999   sos_x86_videomem_setup();
1000   sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE);
1001 
1002   /* Greetings from SOS */
1003   if (magic == MULTIBOOT_BOOTLOADER_MAGIC)
1004     /* Loaded with Grub */
1005     sos_x86_videomem_printf(1, 0,
1006                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
1007                             "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)",
1008                             "SOS", ',',
1009                             (unsigned)(mbi->mem_upper >> 10) + 1,
1010                             (unsigned)mbi->mem_upper);
1011   else
1012     /* Not loaded with grub */
1013     sos_x86_videomem_printf(1, 0,
1014                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
1015                             "Welcome to SOS");
1016 
1017   sos_bochs_putstring("Message in a bochs\n");
1018 
1019   /* Setup CPU segmentation and IRQ subsystem */
1020   sos_gdt_subsystem_setup();
1021   sos_idt_subsystem_setup();
1022 
1023   /* Setup SOS IRQs and exceptions subsystem */
1024   sos_exception_subsystem_setup();
1025   sos_irq_subsystem_setup();
1026 
1027   /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */
1028   sos_i8254_set_frequency(100);
1029 
1030   /* We need a multiboot-compliant boot loader to get the size of the RAM */
1031   if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
1032     {
1033       sos_x86_videomem_putstring(20, 0,
1034                                  SOS_X86_VIDEO_FG_LTRED
1035                                    | SOS_X86_VIDEO_BG_BLUE
1036                                    | SOS_X86_VIDEO_FG_BLINKING,
1037                                  "I'm not loaded with Grub !");
1038       /* STOP ! */
1039       for (;;)
1040         continue;
1041     }
1042 
1043   /*
1044    * Some interrupt handlers
1045    */
1046 
1047   /* Binding some HW interrupts and exceptions to software routines */
1048   sos_irq_set_routine(SOS_IRQ_TIMER,
1049                       clk_it);
1050 
1051   /*
1052    * Setup physical memory management
1053    */
1054 
1055   /* Multiboot says: "The value returned for upper memory is maximally
1056      the address of the first upper memory hole minus 1 megabyte.". It
1057      also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */
1058   sos_physmem_subsystem_setup((mbi->mem_upper<<10) + (1<<20),
1059                               & sos_kernel_core_base_paddr,
1060                               & sos_kernel_core_top_paddr);
1061   
1062   /*
1063    * Switch to paged-memory mode
1064    */
1065 
1066   /* Disabling interrupts should seem more correct, but it's not really
1067      necessary at this stage */
1068   SOS_ASSERT_FATAL(SOS_OK ==
1069                    sos_paging_subsystem_setup(sos_kernel_core_base_paddr,
1070                                               sos_kernel_core_top_paddr));
1071   
1072   /* Bind the page fault exception */
1073   sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT,
1074                             pgflt_ex);
1075 
1076   /*
1077    * Setup kernel virtual memory allocator
1078    */ 
1079 
1080   if (sos_kmem_vmm_subsystem_setup(sos_kernel_core_base_paddr,
1081                                    sos_kernel_core_top_paddr,
1082                                    bootstrap_stack_bottom,
1083                                    bootstrap_stack_bottom
1084                                    + bootstrap_stack_size))
1085     sos_bochs_printf("Could not setup the Kernel virtual space allocator\n");
1086 
1087   if (sos_kmalloc_subsystem_setup())
1088     sos_bochs_printf("Could not setup the Kmalloc subsystem\n");
1089 
1090   /*
1091    * Enabling the HW interrupts here, this will make the timer HW
1092    * interrupt call our clk_it handler
1093    */
1094   asm volatile ("sti\n");
1095 
1096   /*
1097    * Print hello world using coroutines
1098    */
1099   print_hello_world();
1100 
1101 
1102   /*
1103    * Run coroutine tests
1104    */
1105   sos_x86_videomem_printf(4, 0,
1106                           SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_LTGREEN,
1107                           "Coroutine test");
1108   sos_x86_videomem_printf(5, 0,
1109                           SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
1110                           "Parsing...");
1111   syntax_tree = parse_expression(" -  ( (69/ toto)+ ( (( - +-- 1))) + --toto*((toto+ - - y - +2*(y-toto))*y) +2*(y-toto) )/- (( y - toto)*2)");
1112 
1113   if (syntax_tree != NULL)
1114     {
1115       sos_x86_videomem_printf(6, 0,
1116                               SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
1117                               "Evaluating...");
1118       sos_x86_videomem_printf(7, 0,
1119                               SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
1120                               "Result=%d (if 0: check bochs output)",
1121                               eval_expression(syntax_tree,
1122                                               (const char*[]){"toto", "y"},
1123                                               (int[]){3, 4},
1124                                               2));
1125       free_syntax_tree(syntax_tree);
1126       sos_x86_videomem_printf(8, 0,
1127                               SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
1128                               "Done (un-allocated syntax tree)");
1129     }
1130   else
1131     {
1132       sos_x86_videomem_printf(6, 0,
1133                               SOS_X86_VIDEO_BG_BLUE | SOS_X86_VIDEO_FG_YELLOW,
1134                               "Error in parsing (see bochs output)");
1135     }
1136 
1137   /*
1138    * Run some demand-paging tests
1139    */
1140   test_demand_paging(234567, 500);
1141 
1142 
1143   /*
1144    * Create an un-resolved page fault, which will make the page fault
1145    * handler print the backtrace.
1146    */
1147   test_backtrace(6, 0xdeadbeef, bootstrap_stack_bottom, bootstrap_stack_size);
1148 
1149   /*
1150    * System should be halted BEFORE here !
1151    */
1152 
1153 
1154   /* An operatig system never ends */
1155   for (;;)
1156     {
1157       /* Remove this instruction if you get an "Invalid opcode" CPU
1158          exception (old 80386 CPU) */
1159       asm("hlt\n");
1160 
1161       continue;
1162     }
1163 }

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