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 <hwcore/mm_context.h>
030 #include <hwcore/swintr.h>
031 #include <sos/kmem_vmm.h>
032 #include <sos/kmalloc.h>
033 #include <sos/time.h>
034 #include <sos/thread.h>
035 #include <sos/process.h>
036 #include <sos/klibc.h>
037 #include <sos/assert.h>
038 #include <drivers/x86_videomem.h>
039 #include <drivers/bochs.h>
040 #include <sos/calcload.h>
041 
042 
043 /* Helper function to display each bits of a 32bits integer on the
044    screen as dark or light carrets */
045 void display_bits(unsigned char row, unsigned char col,
046                   unsigned char attribute,
047                   sos_ui32_t integer)
048 {
049   int i;
050   /* Scan each bit of the integer, MSb first */
051   for (i = 31 ; i >= 0 ; i--)
052     {
053       /* Test if bit i of 'integer' is set */
054       int bit_i = (integer & (1 << i));
055       /* Ascii 219 => dark carret, Ascii 177 => light carret */
056       unsigned char ascii_code = bit_i?219:177;
057       sos_x86_videomem_putchar(row, col++,
058                                attribute,
059                                ascii_code);
060     }
061 }
062 
063 
064 /* Clock IRQ handler */
065 static void clk_it(int intid)
066 {
067   static sos_ui32_t clock_count = 0;
068 
069   display_bits(0, 48,
070                SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE,
071                clock_count);
072   clock_count++;
073 
074   /* Execute the expired timeout actions (if any) */
075   sos_time_do_tick();
076 
077   /* Update scheduler statistics and status */
078   sos_sched_do_timer_tick();
079 }
080 
081 
082 /* ======================================================================
083  * Page fault exception handling
084  */
085 
086 
087 /* Page fault exception handler with demand paging for the kernel */
088 static void pgflt_ex(int intid, struct sos_cpu_state *ctxt)
089 {
090   static sos_ui32_t demand_paging_count = 0;
091   sos_vaddr_t faulting_vaddr  = sos_cpu_context_get_EX_faulting_vaddr(ctxt);
092   sos_paddr_t ppage_paddr;
093 
094   if (sos_cpu_context_is_in_user_mode(ctxt))
095     {
096       /* User-mode page faults are considered unresolved for the
097          moment */
098       sos_bochs_printf("Unresolved USER page Fault at instruction 0x%x on access to address 0x%x (info=%x)!\n",
099                        sos_cpu_context_get_PC(ctxt),
100                        (unsigned)faulting_vaddr,
101                        (unsigned)sos_cpu_context_get_EX_info(ctxt));
102       sos_bochs_printf("Terminating User thread\n");
103       sos_thread_exit();
104     }
105 
106   /* Check if address is covered by any VMM range */
107   if (! sos_kmem_vmm_is_valid_vaddr(faulting_vaddr))
108     {
109       /* No: The page fault is out of any kernel virtual region. For
110          the moment, we don't handle this. */
111       sos_display_fatal_error("Unresolved page Fault at instruction 0x%x on access to address 0x%x (info=%x)!",
112                               sos_cpu_context_get_PC(ctxt),
113                               (unsigned)faulting_vaddr,
114                               (unsigned)sos_cpu_context_get_EX_info(ctxt));
115       SOS_ASSERT_FATAL(! "Got page fault (note: demand paging is disabled)");
116     }
117 
118 
119   /*
120    * Demand paging in kernel space
121    */
122  
123   /* Update the number of demand paging requests handled */
124   demand_paging_count ++;
125   display_bits(0, 0,
126                SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE,
127                demand_paging_count);
128 
129   /* Allocate a new page for the virtual address */
130   ppage_paddr = sos_physmem_ref_physpage_new(FALSE);
131   if (! ppage_paddr)
132     SOS_ASSERT_FATAL(! "TODO: implement swap. (Out of mem in demand paging because no swap for kernel yet !)");
133   SOS_ASSERT_FATAL(SOS_OK == sos_paging_map(ppage_paddr,
134                                             SOS_PAGE_ALIGN_INF(faulting_vaddr),
135                                             FALSE,
136                                             SOS_VM_MAP_PROT_READ
137                                             | SOS_VM_MAP_PROT_WRITE
138                                             | SOS_VM_MAP_ATOMIC));
139   sos_physmem_unref_physpage(ppage_paddr);
140 
141   /* Ok, we can now return to interrupted context */
142 }
143 
144 
145 /* ======================================================================
146  * Demonstrate the use of SOS kernel threads
147  *  - Kernel Threads are created with various priorities and their
148  *    state is printed on both the console and the bochs' 0xe9 port
149  *  - For tests regarding threads' synchronization, see mouse_sim.c
150  */
151 
152 struct thr_arg
153 {
154   char character;
155   int  color;
156 
157   int col;
158   int row;
159 };
160 
161 
162 static void demo_thread(void *arg)
163 {
164   struct thr_arg *thr_arg = (struct thr_arg*)arg;
165   int progress = 0;
166 
167   sos_bochs_printf("start %c", thr_arg->character);
168   while (1)
169     {
170       progress ++;
171       display_bits(thr_arg->row, thr_arg->col+1, thr_arg->color, progress);
172 
173       sos_bochs_putchar(thr_arg->character);
174 
175       /* Yield the CPU to another thread sometimes... */
176       if ((random() % 100) == 0)
177         {
178           sos_bochs_printf("yield(%c)\n", thr_arg->character);
179           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'Y');
180           SOS_ASSERT_FATAL(SOS_OK == sos_thread_yield());
181           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'R');
182         }
183 
184       /* Go to sleep some other times... */
185       else if ((random() % 200) == 0)
186         {
187           struct sos_time t = (struct sos_time){ .sec=0, .nanosec=50000000 };
188           sos_bochs_printf("sleep1(%c)\n", thr_arg->character);
189           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 's');
190           SOS_ASSERT_FATAL(SOS_OK == sos_thread_sleep(& t));
191           SOS_ASSERT_FATAL(sos_time_is_zero(& t));
192           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'R');
193         }
194 
195       /* Go to sleep for a longer time some other times... */
196       else if ((random() % 300) == 0)
197         {
198           struct sos_time t = (struct sos_time){ .sec=0, .nanosec=300000000 };
199           sos_bochs_printf("sleep2(%c)\n", thr_arg->character);
200           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'S');
201           SOS_ASSERT_FATAL(SOS_OK == sos_thread_sleep(& t));
202           SOS_ASSERT_FATAL(sos_time_is_zero(& t));
203           sos_x86_videomem_putchar(thr_arg->row, thr_arg->col, 0x1e, 'R');
204         }
205 
206       /* Infinite loop otherwise */
207     }
208 }
209 
210 
211 static void test_thread()
212 {
213   /* "static" variables because we want them to remain even when the
214      function returns */
215   static struct thr_arg arg_b, arg_c, arg_d, arg_e, arg_R, arg_S;
216   sos_ui32_t flags;
217 
218   sos_disable_IRQs(flags);
219 
220   arg_b = (struct thr_arg) { .character='b', .col=0, .row=21, .color=0x14 };
221   sos_create_kernel_thread("YO[b]", demo_thread, (void*)&arg_b, SOS_SCHED_PRIO_TS_LOWEST);
222 
223   arg_c = (struct thr_arg) { .character='c', .col=46, .row=21, .color=0x14 };
224   sos_create_kernel_thread("YO[c]", demo_thread, (void*)&arg_c, SOS_SCHED_PRIO_TS_LOWEST);
225 
226   arg_d = (struct thr_arg) { .character='d', .col=0, .row=20, .color=0x14 };
227   sos_create_kernel_thread("YO[d]", demo_thread, (void*)&arg_d, SOS_SCHED_PRIO_TS_LOWEST-1);
228 
229   arg_e = (struct thr_arg) { .character='e', .col=0, .row=19, .color=0x14 };
230   sos_create_kernel_thread("YO[e]", demo_thread, (void*)&arg_e, SOS_SCHED_PRIO_TS_LOWEST-2);
231 
232   arg_R = (struct thr_arg) { .character='R', .col=0, .row=17, .color=0x1c };
233   sos_create_kernel_thread("YO[R]", demo_thread, (void*)&arg_R, SOS_SCHED_PRIO_RT_LOWEST);
234 
235   arg_S = (struct thr_arg) { .character='S', .col=0, .row=16, .color=0x1c };
236   sos_create_kernel_thread("YO[S]", demo_thread, (void*)&arg_S, SOS_SCHED_PRIO_RT_LOWEST-1);
237 
238   sos_restore_IRQs(flags);
239 }
240 
241 
242 /* ======================================================================
243  * An operating system MUST always have a ready thread ! Otherwise:
244  * what would the CPU have to execute ?!
245  */
246 static void idle_thread()
247 {
248   sos_ui32_t idle_twiddle = 0;
249 
250   while (1)
251     {
252       /* Remove this instruction if you get an "Invalid opcode" CPU
253          exception (old 80386 CPU) */
254       asm("hlt\n");
255 
256       idle_twiddle ++;
257       display_bits(0, 0, SOS_X86_VIDEO_FG_GREEN | SOS_X86_VIDEO_BG_BLUE,
258                    idle_twiddle);
259       
260       /* Lend the CPU to some other thread */
261       sos_thread_yield();
262     }
263 }
264 
265 
266 /* ======================================================================
267  * Kernel thread showing some CPU usage statistics on the console every 1s
268  */
269 static void stat_thread()
270 {
271   while (1)
272     {
273       sos_ui32_t flags;
274       sos_ui32_t load1, load5, load15;
275       char str1[11], str5[11], str15[11];
276       struct sos_time t;
277       t.sec = 1;
278       t.nanosec = 0;
279 
280       sos_thread_sleep(& t);
281 
282       sos_disable_IRQs(flags);
283 
284       /* The IDLE task is EXcluded in the following computation */
285       sos_load_get_sload(&load1, &load5, &load15);
286       sos_load_to_string(str1, load1);
287       sos_load_to_string(str5, load5);
288       sos_load_to_string(str15, load15);
289       sos_x86_videomem_printf(16, 34,
290                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
291                               "Kernel (- Idle): %s %s %s    ",
292                               str1, str5, str15);
293 
294       sos_load_get_uload(&load1, &load5, &load15);
295       sos_load_to_string(str1, load1);
296       sos_load_to_string(str5, load5);
297       sos_load_to_string(str15, load15);
298       sos_x86_videomem_printf(17, 34,
299                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
300                               "User: %s %s %s        ",
301                               str1, str5, str15);
302 
303       sos_load_get_uratio(&load1, &load5, &load15);
304       sos_load_to_string(str1, load1);
305       sos_load_to_string(str5, load5);
306       sos_load_to_string(str15, load15);
307       sos_x86_videomem_printf(18, 34,
308                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
309                               "User CPU %%: %s %s %s        ",
310                               str1, str5, str15);
311 
312       /* The IDLE task is INcluded in the following computation */
313       sos_load_get_sratio(&load1, &load5, &load15);
314       sos_load_to_string(str1, load1);
315       sos_load_to_string(str5, load5);
316       sos_load_to_string(str15, load15);
317       sos_x86_videomem_printf(19, 34,
318                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
319                               "Kernel CPU %% (+ Idle): %s %s %s    ",
320                               str1, str5, str15);
321       sos_restore_IRQs(flags);
322     }
323 }
324 
325 
326 /* ======================================================================
327  * The C entry point of our operating system
328  */
329 void sos_main(unsigned long magic, unsigned long addr)
330 {
331   unsigned i;
332   sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr;
333   struct sos_time tick_resolution;
334 
335   /* Grub sends us a structure, called multiboot_info_t with a lot of
336      precious informations about the system, see the multiboot
337      documentation for more information. */
338   multiboot_info_t *mbi;
339   mbi = (multiboot_info_t *) addr;
340 
341   /* Setup bochs and console, and clear the console */
342   sos_bochs_setup();
343 
344   sos_x86_videomem_setup();
345   sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE);
346 
347   /* Greetings from SOS */
348   if (magic == MULTIBOOT_BOOTLOADER_MAGIC)
349     /* Loaded with Grub */
350     sos_x86_videomem_printf(1, 0,
351                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
352                             "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)",
353                             "SOS article 7", ',',
354                             (unsigned)(mbi->mem_upper >> 10) + 1,
355                             (unsigned)mbi->mem_upper);
356   else
357     /* Not loaded with grub */
358     sos_x86_videomem_printf(1, 0,
359                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
360                             "Welcome to SOS article 7");
361 
362   sos_bochs_putstring("Message in a bochs: This is SOS article 7.\n");
363 
364   /* Setup CPU segmentation and IRQ subsystem */
365   sos_gdt_subsystem_setup();
366   sos_idt_subsystem_setup();
367 
368   /* Setup SOS IRQs and exceptions subsystem */
369   sos_exception_subsystem_setup();
370   sos_irq_subsystem_setup();
371 
372   /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */
373   sos_i8254_set_frequency(100);
374 
375   /* Setup the kernel time subsystem to get prepared to take the timer
376      ticks into account */
377   tick_resolution = (struct sos_time) { .sec=0, .nanosec=10000000UL };
378   sos_time_subsysem_setup(& tick_resolution);
379 
380   /* We need a multiboot-compliant boot loader to get the size of the RAM */
381   if (magic != MULTIBOOT_BOOTLOADER_MAGIC)
382     {
383       sos_x86_videomem_putstring(20, 0,
384                                  SOS_X86_VIDEO_FG_LTRED
385                                    | SOS_X86_VIDEO_BG_BLUE
386                                    | SOS_X86_VIDEO_FG_BLINKING,
387                                  "I'm not loaded with Grub !");
388       /* STOP ! */
389       for (;;)
390         continue;
391     }
392 
393   /*
394    * Some interrupt handlers
395    */
396 
397   /* Binding some HW interrupts and exceptions to software routines */
398   sos_irq_set_routine(SOS_IRQ_TIMER,
399                       clk_it);
400 
401   /*
402    * Setup physical memory management
403    */
404 
405   /* Multiboot says: "The value returned for upper memory is maximally
406      the address of the first upper memory hole minus 1 megabyte.". It
407      also adds: "It is not guaranteed to be this value." aka "YMMV" ;) */
408   sos_physmem_subsystem_setup((mbi->mem_upper<<10) + (1<<20),
409                               & sos_kernel_core_base_paddr,
410                               & sos_kernel_core_top_paddr);
411   
412   /*
413    * Switch to paged-memory mode
414    */
415 
416   /* Disabling interrupts should seem more correct, but it's not really
417      necessary at this stage */
418   SOS_ASSERT_FATAL(SOS_OK ==
419                    sos_paging_subsystem_setup(sos_kernel_core_base_paddr,
420                                               sos_kernel_core_top_paddr));
421   
422   /* Bind the page fault exception */
423   sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT,
424                             pgflt_ex);
425 
426   /*
427    * Setup kernel virtual memory allocator
428    */
429 
430   if (sos_kmem_vmm_subsystem_setup(sos_kernel_core_base_paddr,
431                                    sos_kernel_core_top_paddr,
432                                    bootstrap_stack_bottom,
433                                    bootstrap_stack_bottom
434                                    + bootstrap_stack_size))
435     sos_bochs_printf("Could not setup the Kernel virtual space allocator\n");
436 
437   if (sos_kmalloc_subsystem_setup())
438     sos_bochs_printf("Could not setup the Kmalloc subsystem\n");
439 
440   /*
441    * Initialize the MMU context subsystem
442    */
443   sos_mm_context_subsystem_setup();
444 
445   /*
446    * Initialize the CPU context subsystem
447    */
448   sos_cpu_context_subsystem_setup();
449 
450   /*
451    * Bind the syscall handler to its software interrupt handler
452    */
453   sos_swintr_subsystem_setup();
454 
455 
456   /*
457    * Initialize the Kernel thread and scheduler subsystems
458    */
459   
460   /* Initialize kernel thread subsystem */
461   sos_thread_subsystem_setup(bootstrap_stack_bottom,
462                              bootstrap_stack_size);
463 
464   /* Initialize the scheduler */
465   sos_sched_subsystem_setup();
466 
467   /* Declare the IDLE thread */
468   SOS_ASSERT_FATAL(sos_create_kernel_thread("idle", idle_thread, NULL,
469                                             SOS_SCHED_PRIO_TS_LOWEST) != NULL);
470 
471   /* Prepare the stats subsystem */
472   sos_load_subsystem_setup();
473 
474   /* Declare a thread that prints some stats */
475   SOS_ASSERT_FATAL(sos_create_kernel_thread("stat_thread", stat_thread,
476                                             NULL,
477                                             SOS_SCHED_PRIO_TS_LOWEST) != NULL);
478 
479 
480   /*
481    * Initialize process stuff
482    */
483   sos_process_subsystem_setup();
484 
485 
486   /* Enabling the HW interrupts here, this will make the timer HW
487      interrupt call the scheduler */
488   asm volatile ("sti\n");
489 
490   /* Run some tests involving USER processes and threads */
491   extern void test_art7();
492   test_art7();
493 
494   /* Now run some Kernel threads just for fun ! */
495   extern void MouseSim();
496   MouseSim();
497   test_thread();
498 
499   /*
500    * We can safely exit from this function now, for there is already
501    * an idle Kernel thread ready to make the CPU busy working...
502    *
503    * However, we must EXPLICITELY call sos_thread_exit() because a
504    * simple "return" will return nowhere ! Actually this first thread
505    * was initialized by the Grub bootstrap stage, at a time when the
506    * word "thread" did not exist. This means that the stack was not
507    * setup in order for a return here to call sos_thread_exit()
508    * automagically. Hence we must call it manually. This is the ONLY
509    * kernel thread where we must do this manually.
510    */
511   sos_bochs_printf("Bye from primary thread !\n");
512   sos_thread_exit();
513   SOS_FATAL_ERROR("No trespassing !");
514 }

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