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 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
017 */
018 
019 /* Include definitions of the multiboot standard */
020 #include <bootstrap/multiboot.h>
021 #include <hwcore/idt.h>
022 #include <hwcore/gdt.h>
023 #include <hwcore/irq.h>
024 #include <hwcore/exception.h>
025 #include <hwcore/i8254.h>
026 #include <sos/list.h>
027 #include <sos/physmem.h>
028 #include <hwcore/paging.h>
029 #include <sos/kmem_vmm.h>
030 #include <sos/kmalloc.h>
031 #include <sos/time.h>
032 #include <sos/thread.h>
033 #include <sos/klibc.h>
034 #include <sos/assert.h>
035 #include <drivers/x86_videomem.h>
036 #include <drivers/bochs.h>
037 
038 
039 /* Helper function to display each bits of a 32bits integer on the
040    screen as dark or light carrets */
041 void display_bits(unsigned char row, unsigned char col,
042                   unsigned char attribute,
043                   sos_ui32_t integer)
044 {
045   int i;
046   /* Scan each bit of the integer, MSb first */
047   for (i = 31 ; i >= 0 ; i--)
048     {
049       /* Test if bit i of 'integer' is set */
050       int bit_i = (integer & (1 << i));
051       /* Ascii 219 => dark carret, Ascii 177 => light carret */
052       unsigned char ascii_code = bit_i?219:177;
053       sos_x86_videomem_putchar(row, col++,
054                                attribute,
055                                ascii_code);
056     }
057 }
058 
059 
060 /* Clock IRQ handler */
061 static void clk_it(int intid)
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   /* Execute the expired timeout actions (if any) */
071   sos_time_do_tick();
072 }
073 
074 
075 /* ======================================================================
076  * Page fault exception handling
077  */
078 
079 /* Helper function to dump a backtrace on bochs and/or the console */
080 static void dump_backtrace(const struct sos_cpu_state *cpu_state,
081                            sos_vaddr_t stack_bottom,
082                            sos_size_t  stack_size,
083                            sos_bool_t on_console,
084                            sos_bool_t on_bochs)
085 {
086   static void backtracer(sos_vaddr_t PC,
087                          sos_vaddr_t params,
088                          sos_ui32_t depth,
089                          void *custom_arg)
090     {
091       sos_ui32_t invalid = 0xffffffff, *arg1, *arg2, *arg3, *arg4;
092 
093       /* Get the address of the first 3 arguments from the
094          frame. Among these arguments, 0, 1, 2, 3 arguments might be
095          meaningful (depending on how many arguments the function may
096          take). */
097       arg1 = (sos_ui32_t*)params;
098       arg2 = (sos_ui32_t*)(params+4);
099       arg3 = (sos_ui32_t*)(params+8);
100       arg4 = (sos_ui32_t*)(params+12);
101 
102       /* Make sure the addresses of these arguments fit inside the
103          stack boundaries */
104 #define INTERVAL_OK(b,v,u) ( ((b) <= (sos_vaddr_t)(v)) \
105                              && ((sos_vaddr_t)(v) < (u)) )
106       if (!INTERVAL_OK(stack_bottom, arg1, stack_bottom + stack_size))
107         arg1 = &invalid;
108       if (!INTERVAL_OK(stack_bottom, arg2, stack_bottom + stack_size))
109         arg2 = &invalid;
110       if (!INTERVAL_OK(stack_bottom, arg3, stack_bottom + stack_size))
111         arg3 = &invalid;
112       if (!INTERVAL_OK(stack_bottom, arg4, stack_bottom + stack_size))
113         arg4 = &invalid;
114 
115       /* Print the function context for this frame */
116       if (on_bochs)
117         sos_bochs_printf("[%d] PC=0x%x arg1=0x%x arg2=0x%x arg3=0x%x\n",
118                          (unsigned)depth, (unsigned)PC,
119                          (unsigned)*arg1, (unsigned)*arg2,
120                          (unsigned)*arg3);
121 
122       if (on_console)
123         sos_x86_videomem_printf(23-depth, 3,
124                                 SOS_X86_VIDEO_BG_BLUE
125                                   | SOS_X86_VIDEO_FG_LTGREEN,
126                                 "[%d] PC=0x%x arg1=0x%x arg2=0x%x arg3=0x%x arg4=0x%x",
127                                 (unsigned)depth, PC,
128                                 (unsigned)*arg1, (unsigned)*arg2,
129                                 (unsigned)*arg3, (unsigned)*arg4);
130       
131     }
132 
133   sos_backtrace(cpu_state, 15, stack_bottom, stack_size, backtracer, NULL);
134 }
135 
136 
137 /* Page fault exception handler with demand paging for the kernel */
138 static void pgflt_ex(int intid, const struct sos_cpu_state *ctxt)
139 {
140   static sos_ui32_t demand_paging_count = 0;
141   sos_vaddr_t faulting_vaddr = sos_cpu_context_get_EX_faulting_vaddr(ctxt);
142   sos_paddr_t ppage_paddr;
143 
144   /* Check if address is covered by any VMM range */
145   if (! sos_kmem_vmm_is_valid_vaddr(faulting_vaddr))
146     {
147       /* No: The page fault is out of any kernel virtual region. For
148          the moment, we don't handle this. */
149       dump_backtrace(ctxt,
150                      bootstrap_stack_bottom,
151                      bootstrap_stack_size,
152                      TRUE, TRUE);
153       sos_display_fatal_error("Unresolved page Fault at instruction 0x%x on access to address 0x%x (info=%x)!",
154                               sos_cpu_context_get_PC(ctxt),
155                               (unsigned)faulting_vaddr,
156                               (unsigned)sos_cpu_context_get_EX_info(ctxt));
157       SOS_ASSERT_FATAL(! "Got page fault (note: demand paging is disabled)");
158     }
159 
160 
161   /*
162    * Demand paging
163    */
164  
165   /* Update the number of demand paging requests handled */
166   demand_paging_count ++;
167   display_bits(0, 0,
168                SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE,
169                demand_paging_count);
170 
171   /* Allocate a new page for the virtual address */
172   ppage_paddr = sos_physmem_ref_physpage_new(FALSE);
173   if (! ppage_paddr)
174     SOS_ASSERT_FATAL(! "TODO: implement swap. (Out of mem in demand paging because no swap for kernel yet !)");
175   SOS_ASSERT_FATAL(SOS_OK == sos_paging_map(ppage_paddr,
176                                             SOS_PAGE_ALIGN_INF(faulting_vaddr),
177                                             FALSE,
178                                             SOS_VM_MAP_PROT_READ
179                                             | SOS_VM_MAP_PROT_WRITE
180                                             | SOS_VM_MAP_ATOMIC));
181   sos_physmem_unref_physpage(ppage_paddr);
182 
183   /* Ok, we can now return to interrupted context */
184 }
185 
186 
187 /* ======================================================================
188  * Demonstrate the use of SOS kernel threads
189  *  - Kernel Threads are created with various priorities and their
190  *    state is printed on both the console and the bochs' 0xe9 port
191  *  - For tests regarding threads' synchronization, see mouse_sim.c
192  */
193 
194 struct thr_arg
195 {
196   char character;
197   int  color;
198 
199   int col;
200   int row;
201 };
202 
203 
204 static void demo_thread(void *arg)
205 {
206   struct thr_arg *thr_arg = (struct thr_arg*)arg;
207   int progress = 0;
208 
209   sos_bochs_printf("start %c", thr_arg->character);
210   while (1)
211     {
212       progress ++;
213       display_bits(thr_arg->row, thr_arg->col+1, thr_arg->color, progress);
214 
215       sos_bochs_putchar(thr_arg->character);
216 
217       /* Yield the CPU to another thread sometimes... */
218       if ((random() % 100) == 0)
219         {
220           sos_bochs_printf("yield(%c)\n", thr_arg->character);
221           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'Y');
222           SOS_ASSERT_FATAL(SOS_OK == sos_thread_yield());
223           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'R');
224         }
225 
226       /* Go to sleep some other times... */
227       else if ((random() % 200) == 0)
228         {
229           struct sos_time t = (struct sos_time){ .sec=0, .nanosec=50000000 };
230           sos_bochs_printf("sleep1(%c)\n", thr_arg->character);
231           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 's');
232           SOS_ASSERT_FATAL(SOS_OK == sos_thread_sleep(& t));
233           SOS_ASSERT_FATAL(sos_time_is_zero(& t));
234           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'R');
235         }
236 
237       /* Go to sleep for a longer time some other times... */
238       else if ((random() % 300) == 0)
239         {
240           struct sos_time t = (struct sos_time){ .sec=0, .nanosec=300000000 };
241           sos_bochs_printf("sleep2(%c)\n", thr_arg->character);
242           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'S');
243           SOS_ASSERT_FATAL(SOS_OK == sos_thread_sleep(& t));
244           SOS_ASSERT_FATAL(sos_time_is_zero(& t));
245           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'R');
246         }
247 
248       /* Infinite loop otherwise */
249     }
250 }
251 
252 
253 static void test_thread()
254 {
255   /* "static" variables because we want them to remain even when the
256      function returns */
257   static struct thr_arg arg_b, arg_c, arg_d, arg_e, arg_R, arg_S;
258   sos_ui32_t flags;
259 
260   sos_disable_IRQs(flags);
261 
262   arg_b = (struct thr_arg) { .character='b', .col=0, .row=21, .color=0x14 };
263   sos_create_kernel_thread("YO[b]", demo_thread, (void*)&arg_b);
264 
265   arg_c = (struct thr_arg) { .character='c', .col=46, .row=21, .color=0x14 };
266   sos_create_kernel_thread("YO[c]", demo_thread, (void*)&arg_c);
267 
268   arg_d = (struct thr_arg) { .character='d', .col=0, .row=20, .color=0x14 };
269   sos_create_kernel_thread("YO[d]", demo_thread, (void*)&arg_d);
270 
271   arg_e = (struct thr_arg) { .character='e', .col=0, .row=19, .color=0x14 };
272   sos_create_kernel_thread("YO[e]", demo_thread, (void*)&arg_e);
273 
274   arg_R = (struct thr_arg) { .character='R', .col=0, .row=17, .color=0x1c };
275   sos_create_kernel_thread("YO[R]", demo_thread, (void*)&arg_R);
276 
277   arg_S = (struct thr_arg) { .character='S', .col=0, .row=16, .color=0x1c };
278   sos_create_kernel_thread("YO[S]", demo_thread, (void*)&arg_S);
279 
280   sos_restore_IRQs(flags);
281 }
282 
283 
284 /* ======================================================================
285  * An operating system MUST always have a ready thread ! Otherwise:
286  * what would the CPU have to execute ?!
287  */
288 static void idle_thread()
289 {
290   sos_ui32_t idle_twiddle = 0;
291 
292   while (1)
293     {
294       /* Remove this instruction if you get an "Invalid opcode" CPU
295          exception (old 80386 CPU) */
296       asm("hlt\n");
297 
298       idle_twiddle ++;
299       display_bits(0, 0, SOS_X86_VIDEO_FG_GREEN | SOS_X86_VIDEO_BG_BLUE,
300                    idle_twiddle);
301       
302       /* Lend the CPU to some other thread */
303       sos_thread_yield();
304     }
305 }
306 
307 
308 /* ======================================================================
309  * The C entry point of our operating system
310  */
311 void sos_main(unsigned long magic, unsigned long addr)
312 {
313   unsigned i;
314   sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr;
315   struct sos_time tick_resolution;
316 
317   /* Grub sends us a structure, called multiboot_info_t with a lot of
318      precious informations about the system, see the multiboot
319      documentation for more information. */
320   multiboot_info_t *mbi;
321   mbi = (multiboot_info_t *) addr;
322 
323   /* Setup bochs and console, and clear the console */
324   sos_bochs_setup();
325 
326   sos_x86_videomem_setup();
327   sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE);
328 
329   /* Greetings from SOS */
330   if (magic == MULTIBOOT_BOOTLOADER_MAGIC)
331     /* Loaded with Grub */
332     sos_x86_videomem_printf(1, 0,
333                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
334                             "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)",
335                             "SOS article 6.5", ',',
336                             (unsigned)(mbi->mem_upper >> 10) + 1,
337                             (unsigned)mbi->mem_upper);
338   else
339     /* Not loaded with grub */
340     sos_x86_videomem_printf(1, 0,
341                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
342                             "Welcome to SOS article 6.5");
343 
344   sos_bochs_putstring("Message in a bochs: This is SOS article 6.5.\n");
345 
346   /* Setup CPU segmentation and IRQ subsystem */
347   sos_gdt_subsystem_setup();
348   sos_idt_subsystem_setup();
349 
350   /* Setup SOS IRQs and exceptions subsystem */
351   sos_exception_subsystem_setup();
352   sos_irq_subsystem_setup();
353 
354   /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */
355   sos_i8254_set_frequency(100);
356 
357   /* Setup the kernel time subsystem to get prepared to take the timer
358      ticks into account */
359   tick_resolution = (struct sos_time) { .sec=0, .nanosec=10000000UL };
360   sos_time_subsysem_setup(& tick_resolution);
361 
362   /* We need a multiboot-compliant boot loader to get the size of the RAM */
363   if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
364     {
365       sos_x86_videomem_putstring(20, 0,
366                                  SOS_X86_VIDEO_FG_LTRED
367                                    | SOS_X86_VIDEO_BG_BLUE
368                                    | SOS_X86_VIDEO_FG_BLINKING,
369                                  "I'm not loaded with Grub !");
370       /* STOP ! */
371       for (;;)
372         continue;
373     }
374 
375   /*
376    * Some interrupt handlers
377    */
378 
379   /* Binding some HW interrupts and exceptions to software routines */
380   sos_irq_set_routine(SOS_IRQ_TIMER,
381                       clk_it);
382 
383   /*
384    * Setup physical memory management
385    */
386 
387   /* Multiboot says: "The value returned for upper memory is maximally
388      the address of the first upper memory hole minus 1 megabyte.". It
389      also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */
390   sos_physmem_subsystem_setup((mbi->mem_upper<<10) + (1<<20),
391                               & sos_kernel_core_base_paddr,
392                               & sos_kernel_core_top_paddr);
393   
394   /*
395    * Switch to paged-memory mode
396    */
397 
398   /* Disabling interrupts should seem more correct, but it's not really
399      necessary at this stage */
400   SOS_ASSERT_FATAL(SOS_OK ==
401                    sos_paging_subsystem_setup(sos_kernel_core_base_paddr,
402                                               sos_kernel_core_top_paddr));
403   
404   /* Bind the page fault exception */
405   sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT,
406                             pgflt_ex);
407 
408   /*
409    * Setup kernel virtual memory allocator
410    */
411 
412   if (sos_kmem_vmm_subsystem_setup(sos_kernel_core_base_paddr,
413                                    sos_kernel_core_top_paddr,
414                                    bootstrap_stack_bottom,
415                                    bootstrap_stack_bottom
416                                    + bootstrap_stack_size))
417     sos_bochs_printf("Could not setup the Kernel virtual space allocator\n");
418 
419   if (sos_kmalloc_subsystem_setup())
420     sos_bochs_printf("Could not setup the Kmalloc subsystem\n");
421 
422   /*
423    * Initialize the Kernel thread and scheduler subsystems
424    */
425   
426   /* Initialize kernel thread subsystem */
427   sos_thread_subsystem_setup(bootstrap_stack_bottom,
428                              bootstrap_stack_size);
429 
430   /* Initialize the scheduler */
431   sos_sched_subsystem_setup();
432 
433   /* Declare the IDLE thread */
434   SOS_ASSERT_FATAL(sos_create_kernel_thread("idle", idle_thread, NULL) != NULL);
435 
436   /* Enabling the HW interrupts here, this will make the timer HW
437      interrupt call the scheduler */
438   asm volatile ("sti\n");
439 
440 
441   /* Now run some Kernel threads just for fun ! */
442   extern void MouseSim();
443   MouseSim();
444   test_thread();
445 
446   /*
447    * We can safely exit from this function now, for there is already
448    * an idle Kernel thread ready to make the CPU busy working...
449    *
450    * However, we must EXPLICITELY call sos_thread_exit() because a
451    * simple "return" will return nowhere ! Actually this first thread
452    * was initialized by the Grub bootstrap stage, at a time when the
453    * word "thread" did not exist. This means that the stack was not
454    * setup in order for a return here to call sos_thread_exit()
455    * automagically. Hence we must call it manually. This is the ONLY
456    * kernel thread where we must do this manually.
457    */
458   sos_bochs_printf("Bye from primary thread !\n");
459   sos_thread_exit();
460   SOS_FATAL_ERROR("No trespassing !");
461 }

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