sortix-mirror/sortix/kernel.cpp

289 lines
8.9 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 <sortix/kernel/platform.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/refcount.h>
#include <sortix/kernel/textbuffer.h>
#include <sortix/kernel/pci.h>
2011-08-05 12:25:00 +00:00
#include <libmaxsi/memory.h>
#include <libmaxsi/string.h>
#include <libmaxsi/format.h>
#include <sortix/kernel/log.h>
#include <sortix/kernel/panic.h>
#include <sortix/kernel/video.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 <sortix/kernel/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 "ata.h"
#include "com.h"
2011-08-05 12:25:00 +00:00
#include "uart.h"
#include "vgatextbuffer.h"
#include "terminal.h"
2011-08-05 12:25:00 +00:00
#include "serialterminal.h"
#include "textterminal.h"
#include "elf.h"
#include "initrd.h"
#include "vga.h"
#include "bga.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;
// Keep the stack size aligned with $CPU/base.s
extern "C" { size_t stack[64*1024 / sizeof(size_t)] = {0}; }
2011-08-05 12:25:00 +00:00
namespace Sortix {
2011-08-05 12:25:00 +00:00
void DoMaxsiLogo()
{
Log::Print("\e[37;41m\e[2J"); // Make the background color red.
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");
}
2011-08-05 12:25:00 +00:00
void DoWelcome()
{
DoMaxsiLogo();
Log::Print(" BOOTING OPERATING SYSTEM... ");
}
2011-08-05 12:25:00 +00:00
static size_t PrintToTextTerminal(void* user, const char* str, size_t len)
{
return ((TextTerminal*) user)->Print(str, len);
}
static size_t TextTermWidth(void* user)
{
return ((TextTerminal*) user)->Width();
}
static size_t TextTermHeight(void* user)
{
return ((TextTerminal*) user)->Height();
}
extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
{
// Initialize system calls.
Syscall::Init();
2011-08-05 12:25:00 +00:00
// Detect and initialize any serial COM ports in the system.
COM::EarlyInit();
2011-08-05 12:25:00 +00:00
// Setup a text buffer handle for use by the text terminal.
uint16_t* const VGAFB = (uint16_t*) 0xB8000;
const size_t VGA_WIDTH = 80;
const size_t VGA_HEIGHT = 25;
static uint16_t vga_attr_buffer[VGA_WIDTH*VGA_HEIGHT];
VGATextBuffer textbuf(VGAFB, vga_attr_buffer, VGA_WIDTH, VGA_HEIGHT);
TextBufferHandle textbufhandle(NULL, false, &textbuf, false);
// Setup a text terminal instance.
TextTerminal textterm(&textbufhandle);
2011-08-05 12:25:00 +00:00
// Register the text terminal as the kernel log and initialize it.
Log::Init(PrintToTextTerminal, TextTermWidth, TextTermHeight, &textterm);
2011-08-05 12:25:00 +00:00
// Display the boot welcome screen.
DoWelcome();
if ( !bootinfo )
{
Panic("The bootinfo structure was NULL. Are your bootloader "
"multiboot compliant?");
}
2011-08-05 12:25:00 +00:00
addr_t initrd = NULL;
size_t initrdsize = 0;
2011-11-30 22:30:14 +00:00
uint32_t* modules = (uint32_t*) bootinfo->mods_addr;
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];
break;
}
2011-11-30 22:30:14 +00:00
if ( !initrd ) { PanicF("No init ramdisk provided"); }
Memory::RegisterInitRDSize(initrdsize);
2011-11-30 22:30:14 +00:00
// Initialize paging and virtual memory.
Memory::Init(bootinfo);
2011-08-05 12:25:00 +00:00
// Initialize the GDT and TSS structures.
GDT::Init();
2011-08-05 12:25:00 +00:00
// Initialize the interrupt handler table and enable interrupts.
Interrupt::Init();
// Initialize the kernel heap.
Maxsi::Memory::Init();
2011-08-05 12:25:00 +00:00
// Initialize the list of kernel devices.
DeviceFS::Init();
// Initialize the COM ports.
COM::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();
// Initialize the IO system.
IO::Init();
2011-11-16 07:37:29 +00:00
// Initialize the pipe system.
Pipe::Init();
2011-11-16 07:37:29 +00:00
// Initialize the filesystem system.
FileSystem::Init();
// Initialize the directory system.
Directory::Init();
// Initialize the mount system.
Mount::Init();
// Initialize the scheduler.
Scheduler::Init();
2011-08-05 12:25:00 +00:00
// Initialize the kernel information query syscall.
Info::Init();
// Set up the initial ram disk.
InitRD::Init(initrd, initrdsize);
// Initialize the Video Driver framework.
Video::Init(&textbufhandle);
// Search for PCI devices and load their drivers.
PCI::Init();
// Initialize ATA devices.
ATA::Init();
// Initialize the BGA driver.
BGA::Init();
// 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.
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
uint32_t inode;
byte* program;
size_t programsize;
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 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);
inode = InitRD::Traverse(InitRD::Root(), "idle");
if ( inode == NULL ) { PanicF("initrd did not contain 'idle'"); }
program = InitRD::Open(inode, &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);
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 initial process.
Process* init = new Process;
if ( !init ) { Panic("could not allocate init process"); }
init->addrspace = initaddrspace;
Memory::SwitchAddressSpace(initaddrspace);
Scheduler::SetDummyThreadOwner(init);
inode = InitRD::Traverse(InitRD::Root(), "init");
if ( inode == NULL ) { PanicF("initrd did not contain 'init'"); }
program = InitRD::Open(inode, &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();
2011-08-05 12:25:00 +00:00
// Run the OS.
Scheduler::MainLoop();
2011-08-05 12:25:00 +00:00
}
} // namespace Sortix