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

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