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