sortix-mirror/sortix/kernel.cpp

321 lines
11 KiB
C++
Raw Normal View History

/*******************************************************************************
2011-08-05 12:25:00 +00:00
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011, 2012.
2011-08-05 12:25:00 +00:00
This file is part of Sortix.
Sortix 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 3 of the License, or (at your option) any later
version.
Sortix 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
Sortix. If not, see <http://www.gnu.org/licenses/>.
2011-08-05 12:25:00 +00:00
kernel.cpp
The main kernel initialization routine. Configures hardware and starts an
initial process from the init ramdisk, allowing a full operating system.
2011-08-05 12:25:00 +00:00
*******************************************************************************/
2011-08-05 12:25:00 +00:00
#include "platform.h"
#include <libmaxsi/memory.h>
#include <libmaxsi/string.h>
#include <libmaxsi/format.h>
#include "log.h"
#include "panic.h"
#include "kernelinfo.h"
#include "x86-family/gdt.h"
2011-08-05 12:25:00 +00:00
#include "time.h"
#include "keyboard.h"
#include "multiboot.h"
#include "memorymanagement.h"
#include "thread.h"
Implemented the fork() system call and what it needed to work properly. This commit got completely out of control. Added the fork(), getpid(), getppid(), sleep(), usleep() system calls, and aliases in the Maxsi:: namespace. Fixed a bug where zero-byte allocation would fail. Worked on the DescriptorTable class which now works and can fork. Got rid of some massive print-registers statements and replaced them with the portable InterruptRegisters::LogRegisters() function. Removed the SysExecuteOld function and replaced it with Process::Execute(). Rewrote the boot sequence in kernel.cpp such that it now loads the system idle process 'idle' as PID 0, and the initization process 'init' as PID 1. Rewrote the SIGINT hack. Processes now maintain a family-tree structure and keep track of their threads. PIDs are now allocated using a simple hack. Virtual memory per-process can now be allocated using a simple hack. Processes can now be forked. Fixed the Process::Execute function such that it now resets the stack pointer to where the stack actually is - not just a magic value. Removed the old and ugly Process::_endcodesection hack. Rewrote the scheduler into a much cleaner and faster version. Debug code is now moved to designated functions. The noop kernel-thread has been replaced by a simple user-space infinite-loop program 'idle'. The Thread class has been seperated from the Scheduler except in Scheduler- related code. Thread::{Save,Load}Registers has been improved and has been moved to $(CPU)/thread.cpp. Threads can now be forked. A new CreateThread function creates threads properly and portably. Added a MicrosecondsSinceBoot() function. Fixed a crucial bug in MemoryManagement::Fork(). Added an 'idle' user-space program that is a noop infinite loop, which is used by the scheduler when there is nothing to do. Rewrote the 'init' program such that it now forks off a shell, instead of becoming the shell. Added the $$ (current PID) and $PPID (parent PPID) variables to the shell.
2011-09-21 18:52:29 +00:00
#include "process.h"
2011-08-05 12:25:00 +00:00
#include "scheduler.h"
#include "syscall.h"
#include "pci.h"
#include "uart.h"
#include "terminal.h"
2011-08-05 12:25:00 +00:00
#include "serialterminal.h"
#include "vgaterminal.h"
#include "elf.h"
#include "initrd.h"
#include "vga.h"
#include "sound.h"
2011-11-16 07:37:29 +00:00
#include "io.h"
#include "pipe.h"
#include "filesystem.h"
#include "mount.h"
#include "directory.h"
2011-11-30 22:30:14 +00:00
#include "interrupt.h"
#include "fs/devfs.h"
2011-08-05 12:25:00 +00:00
using namespace Maxsi;
void* RunApplication(void* Parameter);
// Keep the stack size aligned with $CPU/base.s
extern "C" { size_t stack[64*1024] = {0}; }
2011-08-05 12:25:00 +00:00
namespace Sortix
{
void DoBSoD()
{
#ifdef PLATFORM_SERIAL
UART::WriteChar(27);
UART::WriteChar(91);
UART::WriteChar(48 + 4);
UART::WriteChar(48 + 4);
UART::WriteChar(109);
#endif
Log::Print(" ");
Log::Print(" ");
Log::Print("Windows Boot Manager has experienced a problem. ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" Status: 0xc000000f ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" Info: An error occured during transferring execution. ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" ");
Log::Print("You can try to recover the system with the Microsoft Windows System Recovery ");
Log::Print("Tools. (You might need to restart the system manually). ");
Log::Print(" ");
Log::Print("If the problem continues, please contact your system administrator or computer ");
Log::Print("manufacturer. ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" ");
Log::Print(" ");
#ifdef JSSORTIX
JSSortix::Exit();
#else
while ( true ) { }
#endif
}
void DoMaxsiLogo()
{
Log::Print("\e[37;41m\e[2J"); // Make the background color red.
2011-08-12 18:09:40 +00:00
Log::Print(" _ \n");
Log::Print(" / \\ \n");
Log::Print(" /\\ /\\ / \\ \n");
Log::Print(" / \\ / \\ | | \n");
Log::Print(" / \\/ \\ | | \n");
Log::Print(" | O O \\_______________________ / | \n");
Log::Print(" | | \n");
Log::Print(" | \\_______/ / \n");
Log::Print(" \\ / \n");
Log::Print(" ------ --------------- ---/ \n");
Log::Print(" / \\ / \\ \n");
Log::Print(" / \\ / \\ \n");
Log::Print(" / \\ / \\ \n");
Log::Print(" /_____________\\ /____________\\ \n");
Log::Print(" \n");
Log::Print(" BOOTING OPERATING SYSTEM... ");
2011-08-05 12:25:00 +00:00
}
void DoWelcome()
{
#ifdef BSOD
DoBSoD();
#endif
DoMaxsiLogo();
}
extern "C" void KernelInit(unsigned long Magic, multiboot_info_t* BootInfo)
{
#ifdef JSSORTIX
// TODO: Make JSVM multiboot compliant.
multiboot_info_t MBInfo; BootInfo = &MBInfo;
multiboot_memory_map_t MBMMap;
MBMMap.addr = 0x100000;
MBMMap.len = 0xC00000;
MBMMap.type = MULTIBOOT_MEMORY_AVAILABLE;
MBMMap.size = sizeof(MBMMap) - sizeof(MBMMap.size);
BootInfo->flags = MULTIBOOT_INFO_MEM_MAP;
BootInfo->mmap_addr = (multiboot_uint32_t) &MBMMap;
BootInfo->mmap_length = sizeof(MBMMap);
#endif
// Initialize system calls.
Syscall::Init();
2011-08-05 12:25:00 +00:00
// Initialize the default terminal.
Maxsi::Format::Callback logcallback;
void* logpointer;
#if PLATFORM_SERIAL
// Initialize the serial driver.
UART::Init();
SerialTerminal::Init();
logcallback = SerialTerminal::Print;
logpointer = NULL;
#else
VGATerminal::Init();
logcallback = VGATerminal::Print;
logpointer = NULL;
#endif
// Initialize the kernel log.
Log::Init(logcallback, logpointer);
// Display the boot welcome screen.
DoWelcome();
2011-11-30 22:30:14 +00:00
if ( BootInfo == NULL ) { Panic("kernel.cpp: The bootinfo structure was NULL. Are your bootloader multiboot compliant?"); }
2011-08-05 12:25:00 +00:00
addr_t initrd = NULL;
2011-08-05 12:25:00 +00:00
size_t initrdsize = 0;
#ifndef JSSORTIX
2011-11-30 22:30:14 +00:00
uint32_t* modules = (uint32_t*) BootInfo->mods_addr;
2011-08-05 12:25:00 +00:00
for ( uint32_t I = 0; I < BootInfo->mods_count; I++ )
{
initrdsize = modules[2*I+1] - modules[2*I+0];
initrd = (addr_t) modules[2*I+0];
2011-08-05 12:25:00 +00:00
break;
}
2011-11-30 22:30:14 +00:00
if ( !initrd ) { PanicF("No init ramdisk provided"); }
2011-11-30 22:30:14 +00:00
#else
// TODO: UGLY HACK because JSVM doesn't support multiboot yet!
initrd = (addr_t) 0x180000UL;
initrdsize = 0x280000; // 2 MiB 512 KiB
#endif
Memory::RegisterInitRDSize(initrdsize);
2011-11-30 22:30:14 +00:00
// Initialize the paging and virtual memory.
Memory::Init(BootInfo);
2011-08-05 12:25:00 +00:00
// Initialize the GDT and TSS structures.
GDT::Init();
// Initialize the interrupt handler table and enable interrupts.
2011-11-30 22:30:14 +00:00
Interrupt::Init();
2011-08-05 12:25:00 +00:00
// Initialize the kernel heap.
Maxsi::Memory::Init();
// Initialize the list of kernel devices.
DeviceFS::Init();
// Initialize the keyboard.
Keyboard::Init();
2011-08-05 12:25:00 +00:00
// Initialize the terminal.
Terminal::Init();
// Initialize the VGA driver.
VGA::Init();
// Initialize the sound driver.
Sound::Init();
// Initialize the process system.
Process::Init();
2011-08-05 12:25:00 +00:00
// Initialize the thread system.
Thread::Init();
2011-11-16 07:37:29 +00:00
// Initialize the IO system.
IO::Init();
// Initialize the pipe system.
Pipe::Init();
// Initialize the filesystem system.
FileSystem::Init();
// Initialize the directory system.
Directory::Init();
// Initialize the mount system.
Mount::Init();
2011-08-05 12:25:00 +00:00
// Initialize the scheduler.
Scheduler::Init();
// Initialize the kernel information query syscall.
Info::Init();
Implemented the fork() system call and what it needed to work properly. This commit got completely out of control. Added the fork(), getpid(), getppid(), sleep(), usleep() system calls, and aliases in the Maxsi:: namespace. Fixed a bug where zero-byte allocation would fail. Worked on the DescriptorTable class which now works and can fork. Got rid of some massive print-registers statements and replaced them with the portable InterruptRegisters::LogRegisters() function. Removed the SysExecuteOld function and replaced it with Process::Execute(). Rewrote the boot sequence in kernel.cpp such that it now loads the system idle process 'idle' as PID 0, and the initization process 'init' as PID 1. Rewrote the SIGINT hack. Processes now maintain a family-tree structure and keep track of their threads. PIDs are now allocated using a simple hack. Virtual memory per-process can now be allocated using a simple hack. Processes can now be forked. Fixed the Process::Execute function such that it now resets the stack pointer to where the stack actually is - not just a magic value. Removed the old and ugly Process::_endcodesection hack. Rewrote the scheduler into a much cleaner and faster version. Debug code is now moved to designated functions. The noop kernel-thread has been replaced by a simple user-space infinite-loop program 'idle'. The Thread class has been seperated from the Scheduler except in Scheduler- related code. Thread::{Save,Load}Registers has been improved and has been moved to $(CPU)/thread.cpp. Threads can now be forked. A new CreateThread function creates threads properly and portably. Added a MicrosecondsSinceBoot() function. Fixed a crucial bug in MemoryManagement::Fork(). Added an 'idle' user-space program that is a noop infinite loop, which is used by the scheduler when there is nothing to do. Rewrote the 'init' program such that it now forks off a shell, instead of becoming the shell. Added the $$ (current PID) and $PPID (parent PPID) variables to the shell.
2011-09-21 18:52:29 +00:00
// Set up the initial ram disk.
InitRD::Init(initrd, initrdsize);
#ifndef JSSORTIX
// Search for PCI devices and load their drivers.
PCI::Init();
#endif
Implemented the fork() system call and what it needed to work properly. This commit got completely out of control. Added the fork(), getpid(), getppid(), sleep(), usleep() system calls, and aliases in the Maxsi:: namespace. Fixed a bug where zero-byte allocation would fail. Worked on the DescriptorTable class which now works and can fork. Got rid of some massive print-registers statements and replaced them with the portable InterruptRegisters::LogRegisters() function. Removed the SysExecuteOld function and replaced it with Process::Execute(). Rewrote the boot sequence in kernel.cpp such that it now loads the system idle process 'idle' as PID 0, and the initization process 'init' as PID 1. Rewrote the SIGINT hack. Processes now maintain a family-tree structure and keep track of their threads. PIDs are now allocated using a simple hack. Virtual memory per-process can now be allocated using a simple hack. Processes can now be forked. Fixed the Process::Execute function such that it now resets the stack pointer to where the stack actually is - not just a magic value. Removed the old and ugly Process::_endcodesection hack. Rewrote the scheduler into a much cleaner and faster version. Debug code is now moved to designated functions. The noop kernel-thread has been replaced by a simple user-space infinite-loop program 'idle'. The Thread class has been seperated from the Scheduler except in Scheduler- related code. Thread::{Save,Load}Registers has been improved and has been moved to $(CPU)/thread.cpp. Threads can now be forked. A new CreateThread function creates threads properly and portably. Added a MicrosecondsSinceBoot() function. Fixed a crucial bug in MemoryManagement::Fork(). Added an 'idle' user-space program that is a noop infinite loop, which is used by the scheduler when there is nothing to do. Rewrote the 'init' program such that it now forks off a shell, instead of becoming the shell. Added the $$ (current PID) and $PPID (parent PPID) variables to the shell.
2011-09-21 18:52:29 +00:00
// Alright, now the system's drivers are loaded and initialized. It is
// time to load the initial user-space programs and start execution of
// the actual operating system.
byte* program;
size_t programsize;
// Create an address space for the idle process.
addr_t idleaddrspace = Memory::Fork();
if ( !idleaddrspace ) { Panic("could not fork an idle process address space"); }
Implemented the fork() system call and what it needed to work properly. This commit got completely out of control. Added the fork(), getpid(), getppid(), sleep(), usleep() system calls, and aliases in the Maxsi:: namespace. Fixed a bug where zero-byte allocation would fail. Worked on the DescriptorTable class which now works and can fork. Got rid of some massive print-registers statements and replaced them with the portable InterruptRegisters::LogRegisters() function. Removed the SysExecuteOld function and replaced it with Process::Execute(). Rewrote the boot sequence in kernel.cpp such that it now loads the system idle process 'idle' as PID 0, and the initization process 'init' as PID 1. Rewrote the SIGINT hack. Processes now maintain a family-tree structure and keep track of their threads. PIDs are now allocated using a simple hack. Virtual memory per-process can now be allocated using a simple hack. Processes can now be forked. Fixed the Process::Execute function such that it now resets the stack pointer to where the stack actually is - not just a magic value. Removed the old and ugly Process::_endcodesection hack. Rewrote the scheduler into a much cleaner and faster version. Debug code is now moved to designated functions. The noop kernel-thread has been replaced by a simple user-space infinite-loop program 'idle'. The Thread class has been seperated from the Scheduler except in Scheduler- related code. Thread::{Save,Load}Registers has been improved and has been moved to $(CPU)/thread.cpp. Threads can now be forked. A new CreateThread function creates threads properly and portably. Added a MicrosecondsSinceBoot() function. Fixed a crucial bug in MemoryManagement::Fork(). Added an 'idle' user-space program that is a noop infinite loop, which is used by the scheduler when there is nothing to do. Rewrote the 'init' program such that it now forks off a shell, instead of becoming the shell. Added the $$ (current PID) and $PPID (parent PPID) variables to the shell.
2011-09-21 18:52:29 +00:00
// Create an address space for the initial process.
addr_t initaddrspace = Memory::Fork();
if ( !initaddrspace ) { Panic("could not fork an initial process address space"); }
Implemented the fork() system call and what it needed to work properly. This commit got completely out of control. Added the fork(), getpid(), getppid(), sleep(), usleep() system calls, and aliases in the Maxsi:: namespace. Fixed a bug where zero-byte allocation would fail. Worked on the DescriptorTable class which now works and can fork. Got rid of some massive print-registers statements and replaced them with the portable InterruptRegisters::LogRegisters() function. Removed the SysExecuteOld function and replaced it with Process::Execute(). Rewrote the boot sequence in kernel.cpp such that it now loads the system idle process 'idle' as PID 0, and the initization process 'init' as PID 1. Rewrote the SIGINT hack. Processes now maintain a family-tree structure and keep track of their threads. PIDs are now allocated using a simple hack. Virtual memory per-process can now be allocated using a simple hack. Processes can now be forked. Fixed the Process::Execute function such that it now resets the stack pointer to where the stack actually is - not just a magic value. Removed the old and ugly Process::_endcodesection hack. Rewrote the scheduler into a much cleaner and faster version. Debug code is now moved to designated functions. The noop kernel-thread has been replaced by a simple user-space infinite-loop program 'idle'. The Thread class has been seperated from the Scheduler except in Scheduler- related code. Thread::{Save,Load}Registers has been improved and has been moved to $(CPU)/thread.cpp. Threads can now be forked. A new CreateThread function creates threads properly and portably. Added a MicrosecondsSinceBoot() function. Fixed a crucial bug in MemoryManagement::Fork(). Added an 'idle' user-space program that is a noop infinite loop, which is used by the scheduler when there is nothing to do. Rewrote the 'init' program such that it now forks off a shell, instead of becoming the shell. Added the $$ (current PID) and $PPID (parent PPID) variables to the shell.
2011-09-21 18:52:29 +00:00
// Create the system idle process.
Process* idle = new Process;
if ( !idle ) { Panic("could not allocate idle process"); }
idle->addrspace = idleaddrspace;
Memory::SwitchAddressSpace(idleaddrspace);
Scheduler::SetDummyThreadOwner(idle);
program = InitRD::Open("idle", &programsize);
if ( program == NULL ) { PanicF("initrd did not contain 'idle'"); }
addr_t idlestart = ELF::Construct(idle, program, programsize);
if ( !idlestart ) { Panic("could not construct ELF image for idle process"); }
Thread* idlethread = CreateThread(idlestart);
if ( !idlethread ) { Panic("could not create thread for the idle process"); }
Scheduler::SetIdleThread(idlethread);
// Create the initial process.
Process* init = new Process;
if ( !init ) { Panic("could not allocate init process"); }
init->addrspace = initaddrspace;
Memory::SwitchAddressSpace(initaddrspace);
Scheduler::SetDummyThreadOwner(init);
program = InitRD::Open("init", &programsize);
if ( program == NULL ) { PanicF("initrd did not contain 'init'"); }
addr_t initstart = ELF::Construct(init, program, programsize);
if ( !initstart ) { Panic("could not construct ELF image for init process"); }
Thread* initthread = CreateThread(initstart);
if ( !initthread ) { Panic("could not create thread for the init process"); }
Scheduler::SetInitProcess(init);
2011-08-05 12:25:00 +00:00
// Lastly set up the timer driver and we are ready to run the OS.
Time::Init();
// Run the OS.
Scheduler::MainLoop();
}
}