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

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