641 lines
19 KiB
C
641 lines
19 KiB
C
/* Copyright (C) 2004 The SOS Team
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
USA.
|
|
*/
|
|
|
|
#include <sos/errno.h>
|
|
|
|
/* Include definitions of the multiboot standard */
|
|
#include <bootstrap/multiboot.h>
|
|
#include <hwcore/idt.h>
|
|
#include <hwcore/gdt.h>
|
|
#include <hwcore/irq.h>
|
|
#include <hwcore/exception.h>
|
|
#include <hwcore/i8254.h>
|
|
#include <sos/list.h>
|
|
#include <sos/physmem.h>
|
|
#include <hwcore/paging.h>
|
|
#include <hwcore/mm_context.h>
|
|
#include <hwcore/swintr.h>
|
|
#include <sos/kmem_vmm.h>
|
|
#include <sos/kmalloc.h>
|
|
#include <sos/time.h>
|
|
#include <sos/thread.h>
|
|
#include <sos/process.h>
|
|
#include <sos/umem_vmm.h>
|
|
#include <sos/klibc.h>
|
|
#include <sos/assert.h>
|
|
#include <drivers/x86_videomem.h>
|
|
#include <drivers/bochs.h>
|
|
#include <sos/calcload.h>
|
|
#include <sos/umem_vmm.h>
|
|
#include <sos/binfmt_elf32.h>
|
|
#include <drivers/zero.h>
|
|
#include <sos/fs.h>
|
|
#include <drivers/fs_virtfs.h>
|
|
#include <drivers/fs_fat.h>
|
|
#include <drivers/devices.h>
|
|
#include <drivers/mem.h>
|
|
#include <drivers/tty.h>
|
|
#include <drivers/console.h>
|
|
#include <drivers/serial.h>
|
|
#include <sos/blkdev.h>
|
|
#include <sos/fs_pagecache.h>
|
|
#include <drivers/ide.h>
|
|
|
|
/* Helper function to display each bits of a 32bits integer on the
|
|
screen as dark or light carrets */
|
|
void display_bits(unsigned char row, unsigned char col,
|
|
unsigned char attribute,
|
|
sos_ui32_t integer)
|
|
{
|
|
int i;
|
|
/* Scan each bit of the integer, MSb first */
|
|
for (i = 31 ; i >= 0 ; i--)
|
|
{
|
|
/* Test if bit i of 'integer' is set */
|
|
int bit_i = (integer & (1 << i));
|
|
/* Ascii 219 => dark carret, Ascii 177 => light carret */
|
|
unsigned char ascii_code = bit_i?219:177;
|
|
sos_x86_videomem_putchar(row, col++,
|
|
attribute,
|
|
ascii_code);
|
|
}
|
|
}
|
|
|
|
/* Clock IRQ handler */
|
|
static void clk_it(int intid)
|
|
{
|
|
static sos_ui32_t clock_count = 0;
|
|
|
|
display_bits(0, 48,
|
|
SOS_X86_VIDEO_FG_LTGREEN | SOS_X86_VIDEO_BG_BLUE,
|
|
clock_count);
|
|
clock_count++;
|
|
|
|
/* Execute the expired timeout actions (if any) */
|
|
sos_time_do_tick();
|
|
|
|
/* Update scheduler statistics and status */
|
|
sos_sched_do_timer_tick();
|
|
}
|
|
|
|
|
|
/* ======================================================================
|
|
* Page fault exception handling
|
|
*/
|
|
|
|
|
|
/* Page fault exception handler with demand paging for the kernel */
|
|
static void pgflt_ex(int intid, struct sos_cpu_state *ctxt)
|
|
{
|
|
static sos_ui32_t demand_paging_count = 0;
|
|
struct sos_thread * cur_thr = sos_thread_get_current();
|
|
sos_vaddr_t faulting_vaddr = sos_cpu_context_get_EX_faulting_vaddr(ctxt);
|
|
sos_paddr_t ppage_paddr;
|
|
|
|
if (sos_cpu_context_is_in_user_mode(ctxt)
|
|
|| (cur_thr->fixup_uaccess.return_vaddr))
|
|
{
|
|
__label__ unforce_address_space;
|
|
sos_bool_t need_to_prepare_user_space_access;
|
|
sos_ui32_t errcode = sos_cpu_context_get_EX_info(ctxt);
|
|
|
|
/* Do we already try to access an address space ? */
|
|
need_to_prepare_user_space_access
|
|
= (sos_thread_get_current()->squatted_address_space == NULL);
|
|
|
|
if (need_to_prepare_user_space_access)
|
|
/* No: Need to configure the interrupted thread user space */
|
|
sos_thread_prepare_user_space_access(NULL, 0);
|
|
|
|
if (SOS_OK ==
|
|
sos_umem_vmm_try_resolve_page_fault(faulting_vaddr,
|
|
errcode & (1 << 1),
|
|
TRUE))
|
|
goto unforce_address_space;
|
|
|
|
/* If the page fault occured in kernel mode, return to kernel to
|
|
the fixup address */
|
|
if (! sos_cpu_context_is_in_user_mode(ctxt))
|
|
{
|
|
cur_thr->fixup_uaccess.faulted_uaddr = faulting_vaddr;
|
|
sos_cpu_context_set_EX_return_address(ctxt,
|
|
cur_thr->fixup_uaccess.return_vaddr);
|
|
goto unforce_address_space;
|
|
}
|
|
|
|
if (need_to_prepare_user_space_access)
|
|
sos_thread_end_user_space_access();
|
|
|
|
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",
|
|
(void*)sos_thread_get_current(),
|
|
sos_cpu_context_get_PC(ctxt),
|
|
(unsigned)faulting_vaddr,
|
|
(unsigned)sos_cpu_context_get_EX_info(ctxt));
|
|
sos_bochs_printf("Terminating User thread\n");
|
|
sos_thread_exit();
|
|
|
|
unforce_address_space:
|
|
if (need_to_prepare_user_space_access)
|
|
sos_thread_end_user_space_access();
|
|
return;
|
|
}
|
|
|
|
/* Check if address is covered by any VMM range */
|
|
if (! sos_kmem_vmm_is_valid_vaddr(faulting_vaddr))
|
|
{
|
|
/* No: The page fault is out of any kernel virtual region. For
|
|
the moment, we don't handle this. */
|
|
sos_display_fatal_error("Unresolved page Fault at instruction 0x%x on access to address 0x%x (info=%x)!",
|
|
sos_cpu_context_get_PC(ctxt),
|
|
(unsigned)faulting_vaddr,
|
|
(unsigned)sos_cpu_context_get_EX_info(ctxt));
|
|
SOS_ASSERT_FATAL(! "Got page fault (note: demand paging is disabled)");
|
|
}
|
|
|
|
|
|
/*
|
|
* Demand paging in kernel space
|
|
*/
|
|
|
|
/* Update the number of demand paging requests handled */
|
|
demand_paging_count ++;
|
|
display_bits(0, 0,
|
|
SOS_X86_VIDEO_FG_LTRED | SOS_X86_VIDEO_BG_BLUE,
|
|
demand_paging_count);
|
|
|
|
/* Allocate a new page for the virtual address */
|
|
ppage_paddr = sos_physmem_ref_physpage_new(FALSE);
|
|
if (! ppage_paddr)
|
|
SOS_ASSERT_FATAL(! "TODO: implement swap. (Out of mem in demand paging because no swap for kernel yet !)");
|
|
SOS_ASSERT_FATAL(SOS_OK == sos_paging_map(ppage_paddr,
|
|
SOS_PAGE_ALIGN_INF(faulting_vaddr),
|
|
FALSE,
|
|
SOS_VM_MAP_PROT_READ
|
|
| SOS_VM_MAP_PROT_WRITE
|
|
| SOS_VM_MAP_ATOMIC));
|
|
sos_physmem_unref_physpage(ppage_paddr);
|
|
|
|
/* Ok, we can now return to interrupted context */
|
|
}
|
|
|
|
|
|
|
|
/* ======================================================================
|
|
* An operating system MUST always have a ready thread ! Otherwise:
|
|
* what would the CPU have to execute ?!
|
|
*/
|
|
static void idle_thread(void* unused) __attribute__((noreturn));
|
|
static void idle_thread(void* unused)
|
|
{
|
|
sos_ui32_t idle_twiddle = 0;
|
|
|
|
while (1)
|
|
{
|
|
/* Remove this instruction if you get an "Invalid opcode" CPU
|
|
exception (old 80386 CPU) */
|
|
asm("hlt\n");
|
|
|
|
idle_twiddle ++;
|
|
display_bits(0, 0, SOS_X86_VIDEO_FG_GREEN | SOS_X86_VIDEO_BG_BLUE,
|
|
idle_twiddle);
|
|
|
|
/* Lend the CPU to some other thread */
|
|
sos_thread_yield();
|
|
}
|
|
}
|
|
|
|
|
|
/* ======================================================================
|
|
* Kernel thread showing some CPU usage statistics on the console every 1s
|
|
*/
|
|
#define LOAD_DISPLAY_BASELINE 4
|
|
#define LOAD_DISPLAY_STARTROW 34
|
|
static void stat_thread(void * unused) __attribute__((noreturn));
|
|
static void stat_thread(void * unused)
|
|
{
|
|
while (1)
|
|
{
|
|
sos_ui32_t flags;
|
|
sos_ui32_t load1, load5, load15;
|
|
char str1[11], str5[11], str15[11];
|
|
struct sos_time t;
|
|
t.sec = 1;
|
|
t.nanosec = 0;
|
|
|
|
sos_thread_sleep(& t);
|
|
|
|
sos_disable_IRQs(flags);
|
|
|
|
/* The IDLE task is EXcluded in the following computation */
|
|
sos_load_get_sload(&load1, &load5, &load15);
|
|
sos_load_to_string(str1, load1);
|
|
sos_load_to_string(str5, load5);
|
|
sos_load_to_string(str15, load15);
|
|
sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+0, LOAD_DISPLAY_STARTROW,
|
|
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
|
|
"Kernel (- Idle): %s %s %s ",
|
|
str1, str5, str15);
|
|
|
|
sos_load_get_uload(&load1, &load5, &load15);
|
|
sos_load_to_string(str1, load1);
|
|
sos_load_to_string(str5, load5);
|
|
sos_load_to_string(str15, load15);
|
|
sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+1, LOAD_DISPLAY_STARTROW,
|
|
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
|
|
"User: %s %s %s ",
|
|
str1, str5, str15);
|
|
|
|
sos_load_get_uratio(&load1, &load5, &load15);
|
|
sos_load_to_string(str1, load1);
|
|
sos_load_to_string(str5, load5);
|
|
sos_load_to_string(str15, load15);
|
|
sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+2, LOAD_DISPLAY_STARTROW,
|
|
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
|
|
"User CPU %%: %s %s %s ",
|
|
str1, str5, str15);
|
|
|
|
/* The IDLE task is INcluded in the following computation */
|
|
sos_load_get_sratio(&load1, &load5, &load15);
|
|
sos_load_to_string(str1, load1);
|
|
sos_load_to_string(str5, load5);
|
|
sos_load_to_string(str15, load15);
|
|
sos_x86_videomem_printf(LOAD_DISPLAY_BASELINE+3, LOAD_DISPLAY_STARTROW,
|
|
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
|
|
"Kernel CPU %% (+ Idle): %s %s %s ",
|
|
str1, str5, str15);
|
|
sos_restore_IRQs(flags);
|
|
}
|
|
}
|
|
|
|
|
|
/* ======================================================================
|
|
* Start the "init" (userland) process
|
|
*/
|
|
static sos_ret_t
|
|
start_init(struct sos_fs_manager_instance * rootfs)
|
|
{
|
|
sos_ret_t retval;
|
|
struct sos_umem_vmm_as *as_init;
|
|
struct sos_process *proc_init;
|
|
struct sos_thread *new_thr;
|
|
sos_uaddr_t ustack, start_uaddr;
|
|
int fake_args[32]; /* Must be large enough to contain argv/envp for init */
|
|
sos_ret_t ret;
|
|
struct sos_fs_opened_file * init_root, * init_cwd, * unused_of;
|
|
|
|
/* Create the new process */
|
|
proc_init = sos_process_create("init", FALSE);
|
|
if (! proc_init)
|
|
return -SOS_ENOMEM;
|
|
as_init = sos_process_get_address_space(proc_init);
|
|
|
|
|
|
/*
|
|
* Setup the root and CWD directories of the process. The root of
|
|
* this process will correspond to the "global" root of the whole
|
|
* system since all the future processes will duplicate it !
|
|
*/
|
|
retval = sos_fs_new_opened_file(proc_init, rootfs->root,
|
|
SOS_FS_OPEN_READ | SOS_FS_OPEN_WRITE,
|
|
& init_root);
|
|
if (SOS_OK != retval)
|
|
{
|
|
sos_process_unref(proc_init);
|
|
return -SOS_ENOENT;
|
|
}
|
|
|
|
/* Duplicate the root file to set the current working directory of
|
|
the init process */
|
|
retval = sos_fs_duplicate_opened_file(init_root, proc_init,
|
|
& init_cwd);
|
|
if (SOS_OK != retval)
|
|
{
|
|
sos_fs_close(init_root);
|
|
sos_process_unref(proc_init);
|
|
return -SOS_ENOENT;
|
|
}
|
|
|
|
/* Now update the process ! */
|
|
if ( ( SOS_OK != sos_process_chroot(proc_init, init_root, & unused_of) )
|
|
|| ( SOS_OK != sos_process_chdir(proc_init, init_cwd, & unused_of) ) )
|
|
{
|
|
sos_fs_close(init_root);
|
|
sos_fs_close(init_cwd);
|
|
sos_process_chroot(proc_init, NULL, & unused_of);
|
|
sos_process_chdir(proc_init, NULL, & unused_of);
|
|
sos_process_unref(proc_init);
|
|
return -SOS_ENOENT;
|
|
}
|
|
|
|
|
|
/* Map the 'init' program in user space */
|
|
start_uaddr = sos_binfmt_elf32_map(as_init, "init");
|
|
if (0 == start_uaddr)
|
|
{
|
|
sos_process_unref(proc_init);
|
|
return -SOS_ENOENT;
|
|
}
|
|
|
|
/* Allocate the user stack */
|
|
ustack = (SOS_PAGING_UPPER_USER_ADDRESS - SOS_DEFAULT_USER_STACK_SIZE) + 1;
|
|
retval = sos_dev_zero_map(as_init, &ustack, SOS_DEFAULT_USER_STACK_SIZE,
|
|
SOS_VM_MAP_PROT_READ | SOS_VM_MAP_PROT_WRITE,
|
|
/* PRIVATE */ 0);
|
|
if (SOS_OK != retval)
|
|
{
|
|
sos_process_unref(proc_init);
|
|
return -SOS_ENOMEM;
|
|
}
|
|
|
|
/* Compute the address of the stack that will be used to initialize
|
|
the user thread */
|
|
ustack = SOS_ALIGN_INF((ustack + SOS_DEFAULT_USER_STACK_SIZE
|
|
- sizeof(fake_args)), 4);
|
|
|
|
/* Build fake argv/envp arguments for the init process. See
|
|
userland/crt.c for the format. */
|
|
fake_args[0] = 0x1; /* argc */
|
|
fake_args[1] = 4 * sizeof(fake_args[0]); /* offset of argv[0] */
|
|
fake_args[2] = 0x0; /* delimiter between argv and envp */
|
|
fake_args[3] = 0x0; /* end of envp */
|
|
strzcpy ((char *) & fake_args[4], /* argv[0] contents */
|
|
"init", 5);
|
|
|
|
/* Copy the arguments to the user thread stack */
|
|
ret = sos_memcpy_to_specified_userspace (as_init,
|
|
ustack,
|
|
(sos_vaddr_t) fake_args,
|
|
sizeof(fake_args));
|
|
if (sizeof(fake_args) != ret)
|
|
{
|
|
sos_bochs_printf ("sos_memcpy_to_specified_userspace() failed, returned %d\n", ret);
|
|
sos_process_unref(proc_init);
|
|
return ret;
|
|
}
|
|
|
|
/* Now create the user thread */
|
|
new_thr = sos_create_user_thread(NULL,
|
|
proc_init,
|
|
start_uaddr,
|
|
0, 0,
|
|
ustack,
|
|
SOS_SCHED_PRIO_TS_LOWEST);
|
|
if (! new_thr)
|
|
{
|
|
sos_process_unref(proc_init);
|
|
return -SOS_ENOMEM;
|
|
}
|
|
|
|
sos_process_unref(proc_init);
|
|
return SOS_OK;
|
|
}
|
|
|
|
|
|
|
|
/* ======================================================================
|
|
* The C entry point of our operating system
|
|
*/
|
|
void sos_main(unsigned long magic, unsigned long arg)
|
|
__attribute__((noreturn));
|
|
void sos_main(unsigned long magic, unsigned long arg)
|
|
{
|
|
sos_paddr_t sos_kernel_core_base_paddr, sos_kernel_core_top_paddr;
|
|
struct sos_time tick_resolution;
|
|
struct sos_fs_manager_instance * rootfs;
|
|
|
|
/* Size of RAM above 1MB. Might be undefined ! */
|
|
unsigned long int upper_mem = 0;
|
|
|
|
/* Setup bochs and console, and clear the console */
|
|
sos_bochs_subsystem_setup();
|
|
|
|
sos_x86_videomem_setup();
|
|
sos_x86_videomem_cls(SOS_X86_VIDEO_BG_BLUE);
|
|
|
|
/* Greetings from SOS */
|
|
if (magic == MULTIBOOT_BOOTLOADER_MAGIC)
|
|
{
|
|
/* Grub sends us a structure, called multiboot_info_t with a lot of
|
|
precious informations about the system, see the multiboot
|
|
documentation for more information. */
|
|
multiboot_info_t *mbi = (multiboot_info_t *) arg;
|
|
|
|
/* Multiboot says: "The value returned for upper memory is
|
|
maximally the address of the first upper memory hole minus 1
|
|
megabyte.". It also adds: "It is not guaranteed to be this
|
|
value." aka "YMMV" ;) */
|
|
upper_mem = mbi->mem_upper;
|
|
sos_x86_videomem_printf(1, 0,
|
|
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
|
|
"Welcome From GRUB to %s%c RAM is %dMB (upper mem = 0x%x kB)",
|
|
"SOS article 10", ',',
|
|
(unsigned)(upper_mem >> 10) + 1,
|
|
(unsigned)upper_mem);
|
|
}
|
|
else if (magic == 0x42244224)
|
|
{
|
|
/* Loaded with SOS bootsect */
|
|
upper_mem = arg;
|
|
sos_x86_videomem_printf(1, 0,
|
|
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
|
|
"Welcome to %s%c RAM is %dMB (upper mem = 0x%x kB)",
|
|
"SOS article 10", ',',
|
|
(unsigned)(upper_mem >> 10) + 1,
|
|
(unsigned)upper_mem);
|
|
}
|
|
else
|
|
/* Not loaded with grub, not from an enhanced bootsect */
|
|
sos_x86_videomem_printf(1, 0,
|
|
SOS_X86_VIDEO_FG_YELLOW | SOS_X86_VIDEO_BG_BLUE,
|
|
"Welcome to SOS article 10");
|
|
|
|
sos_bochs_putstring("Message in a bochs: This is SOS article 10.\n");
|
|
|
|
/* Setup CPU segmentation and IRQ subsystem */
|
|
sos_gdt_subsystem_setup();
|
|
sos_idt_subsystem_setup();
|
|
|
|
/* Setup SOS IRQs and exceptions subsystem */
|
|
sos_exception_subsystem_setup();
|
|
sos_irq_subsystem_setup();
|
|
|
|
/* Configure the timer so as to raise the IRQ0 at a 100Hz rate */
|
|
sos_i8254_set_frequency(100);
|
|
|
|
/* Setup the kernel time subsystem to get prepared to take the timer
|
|
ticks into account */
|
|
tick_resolution = (struct sos_time) { .sec=0, .nanosec=10000000UL };
|
|
sos_time_subsysem_setup(& tick_resolution);
|
|
|
|
/* We need to know the RAM size */
|
|
if (upper_mem == 0)
|
|
{
|
|
sos_x86_videomem_putstring(20, 0,
|
|
SOS_X86_VIDEO_FG_LTRED
|
|
| SOS_X86_VIDEO_BG_BLUE
|
|
| SOS_X86_VIDEO_FG_BLINKING,
|
|
"I don't know RAM size ! Load me with Grub...");
|
|
/* STOP ! */
|
|
for (;;)
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Some interrupt handlers
|
|
*/
|
|
|
|
/* Binding some HW interrupts and exceptions to software routines */
|
|
sos_irq_set_routine(SOS_IRQ_TIMER,
|
|
clk_it);
|
|
|
|
/*
|
|
* Setup physical memory management
|
|
*/
|
|
|
|
SOS_ASSERT_FATAL(SOS_OK
|
|
== sos_physmem_subsystem_setup((upper_mem<<10) + (1<<20),
|
|
&sos_kernel_core_base_paddr,
|
|
&sos_kernel_core_top_paddr));
|
|
|
|
/*
|
|
* Switch to paged-memory mode
|
|
*/
|
|
|
|
/* Disabling interrupts should seem more correct, but it's not really
|
|
necessary at this stage */
|
|
SOS_ASSERT_FATAL(SOS_OK ==
|
|
sos_paging_subsystem_setup(sos_kernel_core_base_paddr,
|
|
sos_kernel_core_top_paddr));
|
|
|
|
/* Bind the page fault exception */
|
|
sos_exception_set_routine(SOS_EXCEPT_PAGE_FAULT,
|
|
pgflt_ex);
|
|
|
|
/*
|
|
* Setup kernel virtual memory allocator
|
|
*/
|
|
|
|
if (sos_kmem_vmm_subsystem_setup(sos_kernel_core_base_paddr,
|
|
sos_kernel_core_top_paddr,
|
|
bootstrap_stack_bottom,
|
|
bootstrap_stack_bottom
|
|
+ bootstrap_stack_size))
|
|
sos_bochs_printf("Could not setup the Kernel virtual space allocator\n");
|
|
|
|
if (sos_kmalloc_subsystem_setup())
|
|
sos_bochs_printf("Could not setup the Kmalloc subsystem\n");
|
|
|
|
/*
|
|
* Initialize the MMU context subsystem
|
|
*/
|
|
sos_mm_context_subsystem_setup();
|
|
|
|
/*
|
|
* Initialize the CPU context subsystem
|
|
*/
|
|
sos_cpu_context_subsystem_setup();
|
|
|
|
/*
|
|
* Bind the syscall handler to its software interrupt handler
|
|
*/
|
|
sos_swintr_subsystem_setup();
|
|
|
|
|
|
/*
|
|
* Initialize the Kernel thread and scheduler subsystems
|
|
*/
|
|
|
|
/* Initialize kernel thread subsystem */
|
|
sos_thread_subsystem_setup(bootstrap_stack_bottom,
|
|
bootstrap_stack_size);
|
|
|
|
/* Initialize the scheduler */
|
|
sos_sched_subsystem_setup();
|
|
|
|
/* Declare the IDLE thread */
|
|
SOS_ASSERT_FATAL(sos_create_kernel_thread("idle", idle_thread, NULL,
|
|
SOS_SCHED_PRIO_TS_LOWEST) != NULL);
|
|
|
|
/* Prepare the stats subsystem */
|
|
sos_load_subsystem_setup();
|
|
|
|
/* Declare a thread that prints some stats */
|
|
SOS_ASSERT_FATAL(sos_create_kernel_thread("stat_thread", stat_thread,
|
|
NULL,
|
|
SOS_SCHED_PRIO_TS_LOWEST) != NULL);
|
|
|
|
|
|
/*
|
|
* Initialise user address space management subsystem
|
|
*/
|
|
sos_umem_vmm_subsystem_setup();
|
|
sos_dev_zero_subsystem_setup();
|
|
|
|
/* Initialize the page and block cache subsystems */
|
|
sos_fs_pagecache_subsystem_setup();
|
|
sos_blockdev_subsystem_setup();
|
|
sos_dev_mem_chardev_setup();
|
|
|
|
/*
|
|
* Initialize process stuff
|
|
*/
|
|
sos_process_subsystem_setup();
|
|
|
|
|
|
/* Enabling the HW interrupts here, this will make the timer HW
|
|
interrupt call the scheduler */
|
|
asm volatile ("sti\n");
|
|
|
|
|
|
SOS_ASSERT_FATAL(SOS_OK == sos_fs_virtfs_subsystem_setup());
|
|
SOS_ASSERT_FATAL(SOS_OK == sos_fs_fat_subsystem_setup());
|
|
SOS_ASSERT_FATAL(SOS_OK == sos_fs_subsystem_setup(NULL,
|
|
"virtfs",
|
|
NULL,
|
|
& rootfs));
|
|
|
|
|
|
tty_subsystem_setup();
|
|
sos_ttyS0_subsystem_setup();
|
|
sos_console_subsystem_setup();
|
|
|
|
|
|
sos_ide_subsystem_setup();
|
|
|
|
|
|
|
|
/* Start the 'init' process, which in turns launches the other
|
|
programs */
|
|
start_init(rootfs);
|
|
/*
|
|
* We can safely exit from this function now, for there is already
|
|
* an idle Kernel thread ready to make the CPU busy working...
|
|
*
|
|
* However, we must EXPLICITELY call sos_thread_exit() because a
|
|
* simple "return" will return nowhere ! Actually this first thread
|
|
* was initialized by the Grub bootstrap stage, at a time when the
|
|
* word "thread" did not exist. This means that the stack was not
|
|
* setup in order for a return here to call sos_thread_exit()
|
|
* automagically. Hence we must call it manually. This is the ONLY
|
|
* kernel thread where we must do this manually.
|
|
*/
|
|
sos_bochs_printf("Bye from primary thread !\n");
|
|
sos_thread_exit();
|
|
SOS_FATAL_ERROR("No trespassing !");
|
|
}
|