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 <sos/errno.h>
020 
021 /* Include definitions of the multiboot standard */
022 #include <bootstrap/multiboot.h>
023 #include <hwcore/idt.h>
024 #include <hwcore/gdt.h>
025 #include <hwcore/irq.h>
026 #include <hwcore/exception.h>
027 #include <hwcore/i8254.h>
028 #include <sos/list.h>
029 #include <sos/physmem.h>
030 #include <hwcore/paging.h>
031 #include <hwcore/mm_context.h>
032 #include <hwcore/swintr.h>
033 #include <sos/kmem_vmm.h>
034 #include <sos/kmalloc.h>
035 #include <sos/time.h>
036 #include <sos/thread.h>
037 #include <sos/process.h>
038 #include <sos/umem_vmm.h>
039 #include <sos/klibc.h>
040 #include <sos/assert.h>
041 #include <drivers/x86_videomem.h>
042 #include <drivers/bochs.h>
043 #include <sos/calcload.h>
044 #include <sos/umem_vmm.h>
045 #include <sos/binfmt_elf32.h>
046 #include <drivers/zero.h>
047 #include <sos/fs.h>
048 #include <drivers/fs_virtfs.h>
049 
050 /* Helper function to display each bits of a 32bits integer on the
051    screen as dark or light carrets */
052 void display_bits(unsigned char row, unsigned char col,
053                   unsigned char attribute,
054                   sos_ui32_t integer)
055 {
056   int i;
057   /* Scan each bit of the integer, MSb first */
058   for (i = 31 ; i >= 0 ; i--)
059     {
060       /* Test if bit i of 'integer' is set */
061       int bit_i = (integer & (1 << i));
062       /* Ascii 219 => dark carret, Ascii 177 => light carret */
063       unsigned char ascii_code = bit_i?219:177;
064       sos_x86_videomem_putchar(row, col++,
065                                attribute,
066                                ascii_code);
067     }
068 }
069 
070 /* Clock IRQ handler */
071 static void clk_it(int intid)
072 {
073   static sos_ui32_t clock_count = 0;
074 
075   display_bits(0, 48,
076                SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE,
077                clock_count);
078   clock_count++;
079 
080   /* Execute the expired timeout actions (if any) */
081   sos_time_do_tick();
082 
083   /* Update scheduler statistics and status */
084   sos_sched_do_timer_tick();
085 }
086 
087 
088 /* ======================================================================
089  * Page fault exception handling
090  */
091 
092 
093 /* Page fault exception handler with demand paging for the kernel */
094 static void pgflt_ex(int intid, struct sos_cpu_state *ctxt)
095 {
096   static sos_ui32_t demand_paging_count = 0;
097   struct sos_thread * cur_thr = sos_thread_get_current();
098   sos_vaddr_t faulting_vaddr  = sos_cpu_context_get_EX_faulting_vaddr(ctxt);
099   sos_paddr_t ppage_paddr;
100 
101   if (sos_cpu_context_is_in_user_mode(ctxt)
102       || (cur_thr->fixup_uaccess.return_vaddr))
103     {
104       __label__ unforce_address_space;
105       sos_bool_t need_to_setup_mmu;
106       sos_ui32_t errcode = sos_cpu_context_get_EX_info(ctxt);
107 
108       /* Make sure to always stay in the interrupted thread's MMU
109          configuration */
110       need_to_setup_mmu = (cur_thr->squatted_mm_context
111                            != sos_process_get_mm_context(cur_thr->process));
112       if (need_to_setup_mmu)
113         sos_thread_prepare_user_space_access(NULL, 0);
114 
115       if (SOS_OK ==
116           sos_umem_vmm_try_resolve_page_fault(faulting_vaddr,
117                                               errcode & (1 << 1),
118                                               TRUE))
119         goto unforce_address_space;
120 
121       /* If the page fault occured in kernel mode, return to kernel to
122          the fixup address */
123       if (! sos_cpu_context_is_in_user_mode(ctxt))
124         {
125           cur_thr->fixup_uaccess.faulted_uaddr = faulting_vaddr;
126           sos_cpu_context_set_EX_return_address(ctxt,
127                                                 cur_thr->fixup_uaccess.return_vaddr);
128           goto unforce_address_space;
129         }
130 
131       if (need_to_setup_mmu)
132         sos_thread_end_user_space_access();
133 
134       sos_bochs_printf("Unresolved USER page Fault at instruction 0x%x on access to address 0x%x (info=%x)!\n",
135                        sos_cpu_context_get_PC(ctxt),
136                        (unsigned)faulting_vaddr,
137                        (unsigned)sos_cpu_context_get_EX_info(ctxt));
138       sos_bochs_printf("Terminating User thread\n");
139       sos_thread_exit();
140 
141     unforce_address_space:
142       if (need_to_setup_mmu)
143         sos_thread_end_user_space_access();
144       return;
145     }
146 
147   /* Check if address is covered by any VMM range */
148   if (! sos_kmem_vmm_is_valid_vaddr(faulting_vaddr))
149     {
150       /* No: The page fault is out of any kernel virtual region. For
151          the moment, we don't handle this. */
152       sos_display_fatal_error("Unresolved page Fault at instruction 0x%x on access to address 0x%x (info=%x)!",
153                               sos_cpu_context_get_PC(ctxt),
154                               (unsigned)faulting_vaddr,
155                               (unsigned)sos_cpu_context_get_EX_info(ctxt));
156       SOS_ASSERT_FATAL(! "Got page fault (note: demand paging is disabled)");
157     }
158 
159 
160   /*
161    * Demand paging in kernel space
162    */
163  
164   /* Update the number of demand paging requests handled */
165   demand_paging_count ++;
166   display_bits(0, 0,
167                SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE,
168                demand_paging_count);
169 
170   /* Allocate a new page for the virtual address */
171   ppage_paddr = sos_physmem_ref_physpage_new(FALSE);
172   if (! ppage_paddr)
173     SOS_ASSERT_FATAL(! "TODO: implement swap. (Out of mem in demand paging because no swap for kernel yet !)");
174   SOS_ASSERT_FATAL(SOS_OK == sos_paging_map(ppage_paddr,
175                                             SOS_PAGE_ALIGN_INF(faulting_vaddr),
176                                             FALSE,
177                                             SOS_VM_MAP_PROT_READ
178                                             | SOS_VM_MAP_PROT_WRITE
179                                             | SOS_VM_MAP_ATOMIC));
180   sos_physmem_unref_physpage(ppage_paddr);
181 
182   /* Ok, we can now return to interrupted context */
183 }
184 
185 
186 
187 /* ======================================================================
188  * An operating system MUST always have a ready thread ! Otherwise:
189  * what would the CPU have to execute ?!
190  */
191 static void idle_thread()
192 {
193   sos_ui32_t idle_twiddle = 0;
194 
195   while (1)
196     {
197       /* Remove this instruction if you get an "Invalid opcode" CPU
198          exception (old 80386 CPU) */
199       asm("hlt\n");
200 
201       idle_twiddle ++;
202       display_bits(0, 0, SOS_X86_VIDEO_FG_GREEN | SOS_X86_VIDEO_BG_BLUE,
203                    idle_twiddle);
204       
205       /* Lend the CPU to some other thread */
206       sos_thread_yield();
207     }
208 }
209 
210 
211 /* ======================================================================
212  * Kernel thread showing some CPU usage statistics on the console every 1s
213  */
214 static void stat_thread()
215 {
216   while (1)
217     {
218       sos_ui32_t flags;
219       sos_ui32_t load1, load5, load15;
220       char str1[11], str5[11], str15[11];
221       struct sos_time t;
222       t.sec = 1;
223       t.nanosec = 0;
224 
225       sos_thread_sleep(& t);
226 
227       sos_disable_IRQs(flags);
228 
229       /* The IDLE task is EXcluded in the following computation */
230       sos_load_get_sload(&load1, &load5, &load15);
231       sos_load_to_string(str1, load1);
232       sos_load_to_string(str5, load5);
233       sos_load_to_string(str15, load15);
234       sos_x86_videomem_printf(16, 34,
235                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
236                               "Kernel (- Idle): %s %s %s    ",
237                               str1, str5, str15);
238 
239       sos_load_get_uload(&load1, &load5, &load15);
240       sos_load_to_string(str1, load1);
241       sos_load_to_string(str5, load5);
242       sos_load_to_string(str15, load15);
243       sos_x86_videomem_printf(17, 34,
244                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
245                               "User: %s %s %s        ",
246                               str1, str5, str15);
247 
248       sos_load_get_uratio(&load1, &load5, &load15);
249       sos_load_to_string(str1, load1);
250       sos_load_to_string(str5, load5);
251       sos_load_to_string(str15, load15);
252       sos_x86_videomem_printf(18, 34,
253                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
254                               "User CPU %%: %s %s %s        ",
255                               str1, str5, str15);
256 
257       /* The IDLE task is INcluded in the following computation */
258       sos_load_get_sratio(&load1, &load5, &load15);
259       sos_load_to_string(str1, load1);
260       sos_load_to_string(str5, load5);
261       sos_load_to_string(str15, load15);
262       sos_x86_videomem_printf(19, 34,
263                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
264                               "Kernel CPU %% (+ Idle): %s %s %s    ",
265                               str1, str5, str15);
266       sos_restore_IRQs(flags);
267     }
268 }
269 
270 
271 /* ======================================================================
272  * Start the "init" (userland) process
273  */
274 static sos_ret_t
275 start_init(struct sos_fs_manager_instance * rootfs)
276 {
277   sos_ret_t retval;
278   struct sos_umem_vmm_as *as_init;
279   struct sos_process *proc_init;
280   struct sos_thread *new_thr;
281   sos_uaddr_t ustack, start_uaddr;
282   struct sos_fs_opened_file * init_root, * init_cwd, * unused_of;
283 
284   /* Create the new process */
285   proc_init = sos_process_create("init", FALSE);
286   if (! proc_init)
287     return -SOS_ENOMEM;
288   as_init = sos_process_get_address_space(proc_init);
289 
290 
291   /*
292    * Setup the root and CWD directories of the process. The root of
293    * this process will correspond to the "global" root of the whole
294    * system since all the future processes will duplicate it !
295    */
296   retval = sos_fs_new_opened_file(proc_init, rootfs->root,
297                                   SOS_FS_OPEN_READ | SOS_FS_OPEN_WRITE,
298                                   & init_root);
299   if (SOS_OK != retval)
300     {
301       sos_process_unref(proc_init);
302       return -SOS_ENOENT;
303     }
304 
305   /* Duplicate the root file to set the current working directory of
306      the init process */
307   retval = sos_fs_duplicate_opened_file(init_root, proc_init,
308                                         & init_cwd);
309   if (SOS_OK != retval)
310     {
311       sos_fs_close(init_root);
312       sos_process_unref(proc_init);
313       return -SOS_ENOENT;
314     }
315 
316   /* Now update the process ! */
317   if ( ( SOS_OK != sos_process_chroot(proc_init, init_root, & unused_of) )
318        || ( SOS_OK != sos_process_chdir(proc_init, init_cwd, & unused_of) ) )
319     {
320       sos_fs_close(init_root);
321       sos_fs_close(init_cwd);
322       sos_process_chroot(proc_init, NULL, & unused_of);
323       sos_process_chdir(proc_init, NULL, & unused_of);
324       sos_process_unref(proc_init);
325       return -SOS_ENOENT;
326     }
327 
328   /* Map the 'init' program in user space */
329   start_uaddr = sos_binfmt_elf32_map(as_init, "init");
330   if (0 == start_uaddr)
331     {
332       sos_process_unref(proc_init);
333       return -SOS_ENOENT;
334     }
335 
336   /* Allocate the user stack */
337   ustack = (SOS_PAGING_TOP_USER_ADDRESS - SOS_DEFAULT_USER_STACK_SIZE) + 1;
338   retval = sos_dev_zero_map(as_init, &ustack, SOS_DEFAULT_USER_STACK_SIZE,
339                             SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE,
340                             /* PRIVATE */ 0);
341   if (SOS_OK != retval)
342     {
343       sos_process_unref(proc_init);
344       return -SOS_ENOMEM;
345     }
346 
347   /* Now create the user thread */
348   new_thr = sos_create_user_thread(NULL,
349                                    proc_init,
350                                    start_uaddr,
351                                    0, 0,
352                                    ustack + SOS_DEFAULT_USER_STACK_SIZE - 4,
353                                    SOS_SCHED_PRIO_TS_LOWEST);
354   if (! new_thr)
355     {
356       sos_process_unref(proc_init);
357       return -SOS_ENOMEM;
358     }
359 
360   sos_process_unref(proc_init);
361   return SOS_OK;
362 }
363 
364 
365 /* ======================================================================
366  * The C entry point of our operating system
367  */
368 void sos_main(unsigned long magic, unsigned long arg)
369 {
370   unsigned i;
371   sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr;
372   struct sos_time tick_resolution;
373   struct sos_fs_manager_instance * rootfs;
374 
375   /* Size of RAM above 1MB. Might be undefined ! */
376   unsigned long int upper_mem = 0;
377 
378   /* Setup bochs and console, and clear the console */
379   sos_bochs_setup();
380 
381   sos_x86_videomem_setup();
382   sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE);
383 
384   /* Greetings from SOS */
385   if (magic == MULTIBOOT_BOOTLOADER_MAGIC)
386     {
387       /* Grub sends us a structure, called multiboot_info_t with a lot of
388          precious informations about the system, see the multiboot
389          documentation for more information. */
390       multiboot_info_t *mbi = (multiboot_info_t *) arg;
391 
392       /* Multiboot says: "The value returned for upper memory is
393          maximally the address of the first upper memory hole minus 1
394          megabyte.". It also adds: "It is not guaranteed to be this
395          value." aka "YMMV" ;) */
396       upper_mem = mbi->mem_upper;
397       sos_x86_videomem_printf(1, 0,
398                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
399                               "Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)",
400                               "SOS article 8", ',',
401                               (unsigned)(upper_mem >> 10) + 1,
402                               (unsigned)upper_mem);
403     }
404   else if (magic == 0x42244224)
405     {
406       /* Loaded with SOS bootsect */
407       upper_mem = arg;
408       sos_x86_videomem_printf(1, 0,
409                               SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
410                               "Welcome to %s%c RAM is %dMB (upper mem = 0x%x kB)",
411                               "SOS article 8", ',',
412                               (unsigned)(upper_mem >> 10) + 1,
413                               (unsigned)upper_mem);
414     }
415   else
416     /* Not loaded with grub, not from an enhanced bootsect */
417     sos_x86_videomem_printf(1, 0,
418                             SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
419                             "Welcome to SOS article 8");
420 
421   sos_bochs_putstring("Message in a bochs: This is SOS article 8.\n");
422 
423   /* Setup CPU segmentation and IRQ subsystem */
424   sos_gdt_subsystem_setup();
425   sos_idt_subsystem_setup();
426 
427   /* Setup SOS IRQs and exceptions subsystem */
428   sos_exception_subsystem_setup();
429   sos_irq_subsystem_setup();
430 
431   /* Configure the timer so as to raise the IRQ0 at a 100Hz rate */
432   sos_i8254_set_frequency(100);
433 
434   /* Setup the kernel time subsystem to get prepared to take the timer
435      ticks into account */
436   tick_resolution = (struct sos_time) { .sec=0, .nanosec=10000000UL };
437   sos_time_subsysem_setup(& tick_resolution);
438 
439   /* We need to know the RAM size */
440   if (upper_mem == 0)
441     {
442       sos_x86_videomem_putstring(20, 0,
443                                  SOS_X86_VIDEO_FG_LTRED
444                                    | SOS_X86_VIDEO_BG_BLUE
445                                    | SOS_X86_VIDEO_FG_BLINKING,
446                                  "I don't know RAM size ! Load me with Grub...");
447       /* STOP ! */
448       for (;;)
449         continue;
450     }
451 
452   /*
453    * Some interrupt handlers
454    */
455 
456   /* Binding some HW interrupts and exceptions to software routines */
457   sos_irq_set_routine(SOS_IRQ_TIMER,
458                       clk_it);
459 
460   /*
461    * Setup physical memory management
462    */
463 
464   SOS_ASSERT_FATAL(SOS_OK
465                    == sos_physmem_subsystem_setup((upper_mem<<10) + (1<<20),
466                                                   &sos_kernel_core_base_paddr,
467                                                   &sos_kernel_core_top_paddr));
468   
469   /*
470    * Switch to paged-memory mode
471    */
472 
473   /* Disabling interrupts should seem more correct, but it's not really
474      necessary at this stage */
475   SOS_ASSERT_FATAL(SOS_OK ==
476                    sos_paging_subsystem_setup(sos_kernel_core_base_paddr,
477                                               sos_kernel_core_top_paddr));
478   
479   /* Bind the page fault exception */
480   sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT,
481                             pgflt_ex);
482 
483   /*
484    * Setup kernel virtual memory allocator
485    */
486 
487   if (sos_kmem_vmm_subsystem_setup(sos_kernel_core_base_paddr,
488                                    sos_kernel_core_top_paddr,
489                                    bootstrap_stack_bottom,
490                                    bootstrap_stack_bottom
491                                    + bootstrap_stack_size))
492     sos_bochs_printf("Could not setup the Kernel virtual space allocator\n");
493 
494   if (sos_kmalloc_subsystem_setup())
495     sos_bochs_printf("Could not setup the Kmalloc subsystem\n");
496 
497   /*
498    * Initialize the MMU context subsystem
499    */
500   sos_mm_context_subsystem_setup();
501 
502   /*
503    * Initialize the CPU context subsystem
504    */
505   sos_cpu_context_subsystem_setup();
506 
507   /*
508    * Bind the syscall handler to its software interrupt handler
509    */
510   sos_swintr_subsystem_setup();
511 
512 
513   /*
514    * Initialize the Kernel thread and scheduler subsystems
515    */
516   
517   /* Initialize kernel thread subsystem */
518   sos_thread_subsystem_setup(bootstrap_stack_bottom,
519                              bootstrap_stack_size);
520 
521   /* Initialize the scheduler */
522   sos_sched_subsystem_setup();
523 
524   /* Declare the IDLE thread */
525   SOS_ASSERT_FATAL(sos_create_kernel_thread("idle", idle_thread, NULL,
526                                             SOS_SCHED_PRIO_TS_LOWEST) != NULL);
527 
528   /* Prepare the stats subsystem */
529   sos_load_subsystem_setup();
530 
531   /* Declare a thread that prints some stats */
532   SOS_ASSERT_FATAL(sos_create_kernel_thread("stat_thread", stat_thread,
533                                             NULL,
534                                             SOS_SCHED_PRIO_TS_LOWEST) != NULL);
535 
536 
537   /*
538    * Initialise user address space management subsystem
539    */
540   sos_umem_vmm_subsystem_setup();
541   sos_dev_zero_subsystem_setup();
542 
543   /*
544    * Initialize process stuff
545    */
546   sos_process_subsystem_setup();
547 
548 
549   /* Enabling the HW interrupts here, this will make the timer HW
550      interrupt call the scheduler */
551   asm volatile ("sti\n");
552 
553 
554   SOS_ASSERT_FATAL(SOS_OK == sos_fs_virtfs_subsystem_setup());
555   SOS_ASSERT_FATAL(SOS_OK == sos_fs_subsystem_setup(NULL,
556                                                     "virtfs",
557                                                     NULL,
558                                                     & rootfs));
559 
560 
561   /* Start the 'init' process, which in turns launches the other
562      programs */
563   start_init(rootfs);
564   /*
565    * We can safely exit from this function now, for there is already
566    * an idle Kernel thread ready to make the CPU busy working...
567    *
568    * However, we must EXPLICITELY call sos_thread_exit() because a
569    * simple "return" will return nowhere ! Actually this first thread
570    * was initialized by the Grub bootstrap stage, at a time when the
571    * word "thread" did not exist. This means that the stack was not
572    * setup in order for a return here to call sos_thread_exit()
573    * automagically. Hence we must call it manually. This is the ONLY
574    * kernel thread where we must do this manually.
575    */
576   sos_bochs_printf("Bye from primary thread !\n");
577   sos_thread_exit();
578   SOS_FATAL_ERROR("No trespassing !");
579 }

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