376 lines
12 KiB
C
376 lines
12 KiB
C
/// MentOS, The Mentoring Operating system project
|
||
/// @file kernel.c
|
||
/// @brief Kernel main function.
|
||
/// @copyright (c) 2014-2021 This file is distributed under the MIT License.
|
||
/// See LICENSE.md for details.
|
||
|
||
#include "io/proc_modules.h"
|
||
#include "mem/vmem_map.h"
|
||
#include "fs/procfs.h"
|
||
#include "devices/pci.h"
|
||
#include "drivers/ata.h"
|
||
#include "descriptor_tables/idt.h"
|
||
#include "kernel.h"
|
||
#include "mem/zone_allocator.h"
|
||
#include "descriptor_tables/gdt.h"
|
||
#include "system/syscall.h"
|
||
#include "version.h"
|
||
#include "io/video.h"
|
||
#include "hardware/pic8259.h"
|
||
#include "io/debug.h"
|
||
#include "drivers/fdc.h"
|
||
#include "fs/initrd.h"
|
||
#include "fs/ext2.h"
|
||
#include "klib/irqflags.h"
|
||
#include "drivers/keyboard/keyboard.h"
|
||
#include "process/scheduler.h"
|
||
#include "hardware/timer.h"
|
||
#include "fs/vfs.h"
|
||
#include "devices/fpu.h"
|
||
#include "system/printk.h"
|
||
#include "sys/module.h"
|
||
#include "drivers/rtc.h"
|
||
#include "stdio.h"
|
||
#include "assert.h"
|
||
#include "io/vga/vga.h"
|
||
#include "string.h"
|
||
#include "fcntl.h"
|
||
|
||
/// Describe start address of grub multiboot modules.
|
||
char *module_start[MAX_MODULES];
|
||
/// Describe end address of grub multiboot modules.
|
||
char *module_end[MAX_MODULES];
|
||
|
||
// Everything is defined in kernel.ld.
|
||
|
||
/// Points at the multiheader grub info, starting address.
|
||
extern uint32_t _multiboot_header_start;
|
||
/// Points at the multiheader grub info, ending address.
|
||
extern uint32_t _multiboot_header_end;
|
||
/// Points at the kernel code, starting address.
|
||
extern uint32_t _text_start;
|
||
/// Points at the kernel code, ending address.
|
||
extern uint32_t _text_end;
|
||
/// Points at the read-only kernel data, starting address.
|
||
extern uint32_t _rodata_start;
|
||
/// Points at the read-only kernel data, ending address.
|
||
extern uint32_t _rodata_end;
|
||
/// Points at the read-write kernel data initialized, starting address.
|
||
extern uint32_t _data_start;
|
||
/// Points at the read-write kernel data initialized, ending address.
|
||
extern uint32_t _data_end;
|
||
/// Points at the read-write kernel data uninitialized an kernel stack, starting address.
|
||
extern uint32_t _bss_start;
|
||
/// Points at the read-write kernel data uninitialized an kernel stack, ending address.
|
||
extern uint32_t _bss_end;
|
||
/// Points at the top of the kernel stack.
|
||
extern uint32_t stack_top;
|
||
/// Points at the bottom of the kernel stack.
|
||
extern uint32_t stack_bottom;
|
||
/// Points at the end of kernel code/data.
|
||
extern uint32_t end;
|
||
|
||
/// Initial ESP.
|
||
uintptr_t initial_esp = 0;
|
||
/// The boot info.
|
||
boot_info_t boot_info;
|
||
|
||
/// @brief Prints [OK] at the current row and column 60.
|
||
static inline void print_ok()
|
||
{
|
||
video_move_cursor(75, video_get_y());
|
||
video_puts("[" FG_GREEN_BRIGHT "OK" FG_WHITE "]\n");
|
||
}
|
||
|
||
/// @brief Prints [FAIL] at the current row and column 60.
|
||
static inline void print_fail()
|
||
{
|
||
video_move_cursor(75, video_get_y());
|
||
video_puts("[" FG_RED_BRIGHT "FAIL" FG_WHITE "]\n");
|
||
}
|
||
|
||
/// @brief Entry point of the kernel.
|
||
/// @param boot_informations Information concerning the boot.
|
||
/// @return The exit status of the kernel.
|
||
int kmain(boot_info_t *boot_informations)
|
||
{
|
||
pr_notice("Booting...\n");
|
||
// Make a copy for when paging is enabled
|
||
boot_info = *boot_informations;
|
||
// Am I booted by a Multiboot-compliant boot loader?
|
||
if (boot_info.magic != MULTIBOOT_BOOTLOADER_MAGIC) {
|
||
printf("Invalid magic number: 0x%x\n", (unsigned)boot_info.magic);
|
||
return 1;
|
||
}
|
||
// Set the initial esp.
|
||
initial_esp = boot_info.stack_base;
|
||
// Dump the multiboot structure.
|
||
dump_multiboot(boot_info.multiboot_header);
|
||
//==========================================================================
|
||
pr_notice("Initialize the video...\n");
|
||
vga_initialize();
|
||
video_init();
|
||
|
||
//==========================================================================
|
||
printf(OS_NAME " " OS_VERSION);
|
||
printf("\nSite:");
|
||
printf(OS_SITEURL);
|
||
printf("\n\n");
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize modules...\n");
|
||
printf("Initialize modules...");
|
||
if (!init_modules(boot_info.multiboot_header)) {
|
||
print_fail();
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
pr_debug("End of modules: 0x%09p\n", get_address_after_modules());
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize physical memory manager...\n");
|
||
printf("Initialize physical memory manager...");
|
||
if (!pmmngr_init(&boot_info)) {
|
||
print_fail();
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize slab allocator.\n");
|
||
printf("Initialize slab...");
|
||
kmem_cache_init();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
// The Global Descriptor Table (GDT) is a data structure used by Intel
|
||
// x86-family processors starting with the 80286 in order to define the
|
||
// characteristics of the various memory areas used during program execution,
|
||
// including the base address, the size, and access privileges like
|
||
// executability and writability. These memory areas are called segments in
|
||
// Intel terminology.
|
||
pr_notice("Initialize Global Descriptor Table (GDT)...\n");
|
||
printf("Initialize GDT...");
|
||
init_gdt();
|
||
print_ok();
|
||
// The IDT is used to show the processor what Interrupt Service Routine
|
||
// (ISR) to call to handle an exception. IDT entries are also called
|
||
// Interrupt requests whenever a device has completed a request and needs to
|
||
// be serviced.
|
||
// ISRs are used to save the current processor state and set up the
|
||
// appropriate segment registers needed for kernel mode before the kernel’s
|
||
// C-level interrupt handler is called. To handle the right exception, the
|
||
// correct entry in the IDT should be pointed to the correct ISR.
|
||
pr_notice("Initialize Interrupt Service Routine(ISR)...\n");
|
||
printf("Initialize IDT...");
|
||
init_idt();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize system calls...\n");
|
||
printf("Initialize system calls...");
|
||
syscall_init();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize IRQ...\n");
|
||
printf("Initialize IRQ...");
|
||
pic8259_init_irq();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Relocate modules.\n");
|
||
printf("Relocate modules...");
|
||
relocate_modules();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize paging.\n");
|
||
printf("Initialize paging...");
|
||
paging_init(&boot_info);
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize virtual memory mapping.\n");
|
||
printf("Initialize virtual memory mapping...");
|
||
virt_init();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Install the timer.\n");
|
||
printf("Setting up timer...");
|
||
timer_install();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Install RTC.\n");
|
||
printf("Setting up RTC...");
|
||
rtc_initialize();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize the filesystem.\n");
|
||
printf("Initialize the filesystem...");
|
||
vfs_init();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
// Scan for ata devices.
|
||
pr_notice("Initialize ATA devices...\n");
|
||
printf("Initialize ATA devices...\n");
|
||
if (ata_initialize()) {
|
||
pr_emerg("Failed to initialize ATA devices!\n");
|
||
return 1;
|
||
}
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize EXT2 filesystem...\n");
|
||
printf("Initialize EXT2 filesystem...\n");
|
||
if (ext2_initialize()) {
|
||
pr_emerg("Failed to initialize EXT2 filesystem!\n");
|
||
return 1;
|
||
}
|
||
|
||
//==========================================================================
|
||
pr_notice("Mount EXT2 filesystem...\n");
|
||
printf("Mount EXT2 filesystem...\n");
|
||
if (do_mount("ext2", "/", "/dev/hda")) {
|
||
pr_emerg("Failed to mount EXT2 filesystem...\n");
|
||
return 1;
|
||
}
|
||
|
||
//==========================================================================
|
||
#if 0
|
||
pr_notice(" Initialize 'initrd'...\n");
|
||
printf(" Initialize 'initrd'...");
|
||
if (initrd_init_module()) {
|
||
print_fail();
|
||
pr_emerg("Failed to register `initrd`!\n");
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
if (do_mount("initrd", "/", "/dev/ram0")) {
|
||
pr_emerg("Failed to mount root `/`!\n");
|
||
return 1;
|
||
}
|
||
#endif
|
||
|
||
//==========================================================================
|
||
pr_notice(" Initialize 'procfs'...\n");
|
||
printf(" Initialize 'procfs'...");
|
||
if (procfs_module_init()) {
|
||
print_fail();
|
||
pr_emerg("Failed to register `procfs`!\n");
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice(" Mounting 'procfs'...\n");
|
||
printf(" Mounting 'procfs'...");
|
||
if (do_mount("procfs", "/proc", NULL)) {
|
||
pr_emerg("Failed to mount procfs at `/proc`!\n");
|
||
return 1;
|
||
}
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize video procfs file...\n");
|
||
printf("Initialize video procfs file...");
|
||
if (procv_module_init()) {
|
||
print_fail();
|
||
pr_emerg("Failed to initialize `/proc/video`!\n");
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize system procfs file...\n");
|
||
printf("Initialize system procfs file...");
|
||
if (procs_module_init()) {
|
||
print_fail();
|
||
pr_emerg("Failed to initialize proc system entries!\n");
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Setting up keyboard driver...\n");
|
||
printf("Setting up keyboard driver...");
|
||
keyboard_initialize();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
#if 0
|
||
pr_notice("Install the mouse.\n");
|
||
printf(" * Setting up mouse driver...");
|
||
mouse_install(); // Install the mouse.
|
||
print_ok();
|
||
#endif
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize the scheduler.\n");
|
||
printf("Initialize the scheduler...");
|
||
scheduler_initialize();
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Init process management...\n");
|
||
printf("Init process management...");
|
||
if (!init_tasking()) {
|
||
print_fail();
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Creating init process...\n");
|
||
printf("Creating init process...");
|
||
task_struct *init_p = process_create_init("/bin/init");
|
||
if (!init_p) {
|
||
print_fail();
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize floating point unit...\n");
|
||
printf("Initialize floating point unit...");
|
||
if (!fpu_install()) {
|
||
print_fail();
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
//==========================================================================
|
||
pr_notice("Initialize signals...\n");
|
||
printf("Initialize signals...");
|
||
if (!signals_init()) {
|
||
print_fail();
|
||
return 1;
|
||
}
|
||
print_ok();
|
||
|
||
vfs_file_t *file = vfs_open("/home/test.txt", O_CREAT | O_EXCL, 0);
|
||
|
||
while (true) {}
|
||
|
||
// We have completed the booting procedure.
|
||
pr_notice("Booting done, jumping into init process.\n");
|
||
// Print the welcome message.
|
||
printf("\n .: Welcome to MentOS :.\n\n");
|
||
// Switch to the page directory of init.
|
||
paging_switch_directory_va(init_p->mm->pgd);
|
||
// Jump into init process.
|
||
scheduler_enter_user_jmp(
|
||
// Entry point.
|
||
init_p->thread.regs.eip,
|
||
// Stack pointer.
|
||
init_p->thread.regs.useresp);
|
||
// Enable interrupt requests.
|
||
sti();
|
||
for (;;) {}
|
||
// We should not be here.
|
||
pr_emerg("Dear developer, we have to talk...\n");
|
||
return 1;
|
||
}
|