Initialize paging before KernelInit.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-03-16 17:24:42 +01:00
parent a422c394b8
commit 218875eb79
9 changed files with 161 additions and 233 deletions

View File

@ -44,6 +44,8 @@
#include "com.h"
extern "C" unsigned char nullpage[4096];
namespace Sortix {
namespace COM {
@ -101,12 +103,6 @@ static const unsigned int UART_16750 = 5;
static const size_t NUM_COM_PORTS = 4;
// The IO base ports of each COM port.
static uint16_t com_ports[1 + NUM_COM_PORTS];
// The results of running HardwareProbe on each COM port.
static unsigned int hw_version[1 + NUM_COM_PORTS];
// Uses various characteristics of the UART chips to determine the hardware.
static unsigned int HardwareProbe(uint16_t port)
{
@ -145,20 +141,6 @@ static inline bool CanWriteByte(uint16_t port)
return inport8(port + LSR) & LSR_THRE;
}
void EarlyInit()
{
// We can fetch COM port information from the BIOS Data Area.
const uint16_t* bioscom_ports = (const uint16_t*) 0x0400UL;
for ( size_t i = 1; i <= NUM_COM_PORTS; i++ )
{
if ( !(com_ports[i] = bioscom_ports[i-1]) )
continue;
hw_version[i] = HardwareProbe(com_ports[i]);
outport8(com_ports[i] + IER, 0x0);
}
}
class DevCOMPort : public AbstractInode
{
public:
@ -282,6 +264,21 @@ static Ref<DevCOMPort> com_devices[1 + NUM_COM_PORTS];
void Init(const char* devpath, Ref<Descriptor> slashdev)
{
uint16_t com_ports[1 + NUM_COM_PORTS];
unsigned int hw_version[1 + NUM_COM_PORTS];
const uint16_t* bioscom_ports = (const uint16_t*) (nullpage + 0x400);
for ( size_t i = 1; i <= NUM_COM_PORTS; i++ )
{
if ( !(com_ports[i] = bioscom_ports[i-1]) )
continue;
hw_version[i] = HardwareProbe(com_ports[i]);
outport8(com_ports[i] + IER, 0x0);
}
(void) hw_version;
ioctx_t ctx; SetupKernelIOCtx(&ctx);
for ( size_t i = 1; i <= NUM_COM_PORTS; i++ )

View File

@ -31,7 +31,6 @@
namespace Sortix {
namespace COM {
void EarlyInit();
void Init(const char* devpath, Ref<Descriptor> slashdev);
} // namespace COM

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014, 2015.
This file is part of Sortix.
@ -91,7 +91,7 @@ void Flush();
addr_t Fork();
addr_t GetAddressSpace();
addr_t SwitchAddressSpace(addr_t addrspace);
void DestroyAddressSpace(addr_t fallback = 0);
void DestroyAddressSpace(addr_t fallback);
bool Map(addr_t physical, addr_t mapto, int prot);
addr_t Unmap(addr_t mapto);
addr_t Physical(addr_t mapto);

View File

@ -189,9 +189,6 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
// TODO: Call global constructors using the _init function.
// Detect and initialize any serial COM ports in the system.
COM::EarlyInit();
// Setup a text buffer handle for use by the text terminal.
uint16_t* const VGAFB = (uint16_t*) 0xB8000;
const size_t VGA_WIDTH = 80;
@ -256,9 +253,8 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
"Use a 32-bit OS 3) Use another version of qemu.");
#endif
if ( !bootinfo )
Panic("The bootinfo structure was NULL. Is your bootloader multiboot "
"compliant?");
// Detect available physical memory.
Memory::Init(bootinfo);
initrd = 0;
initrdsize = 0;
@ -271,13 +267,8 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
break;
}
if ( !initrd ) { PanicF("No init ramdisk provided"); }
// Initialize paging and virtual memory.
Memory::Init(bootinfo);
// Initialize the interrupt handler table and enable interrupts.
Interrupt::Init();
if ( !initrd )
Panic("No init ramdisk provided");
// Load the kernel symbols if provided by the bootloader.
do if ( bootinfo->flags & MULTIBOOT_INFO_ELF_SHDR )
@ -387,6 +378,9 @@ extern "C" void KernelInit(unsigned long magic, multiboot_info_t* bootinfo)
SetKernelSymbolTable(symbols, elf_symbol_count-1);
} while ( false );
// Initialize the interrupt handler table and enable interrupts.
Interrupt::Init();
// Initialize the interrupt worker (before scheduling is enabled).
Interrupt::InitWorker();

View File

@ -32,6 +32,40 @@
.long 0x00000003 # Flags.
.long -(0x1BADB002 + 0x00000003) # Checksum
.section .bss, "aw", @nobits
.align 4096
bootpml4:
.skip 4096
bootpml3:
.skip 4096
bootpml2:
.skip 4096
bootpml1_a:
.skip 4096
bootpml1_b:
.skip 4096
fracpml3:
.skip 4096
fracpml2:
.skip 4096
fracpml1:
.skip 4096
forkpml2:
.skip 4096
forkpml1:
.skip 4096
physpml3:
.skip 4096
physpml2:
.skip 4096
physpml1:
.skip 4096
physpml0:
.skip 4096
nullpage: .global nullpage
.skip 4096
.section .text
.global _start
.global __start
.type _start, @function
@ -61,42 +95,53 @@ __start:
pushl $0
pushl %ebx # Multiboot information structure pointer.
# Clear the first $0xE000 bytes following 0x21000.
movl $0x21000, %edi
movl $bootpml4, %edi
movl %edi, %cr3
xorl %eax, %eax
movl $0xE000, %ecx
rep stosl
movl %cr3, %edi
# Set the initial page tables.
# Note that we OR with 0x7 here to allow user-space access, except in the
# first 2 MiB. We also do this with 0x200 to allow forking the page.
# Page-Map Level 4.
movl $(bootpml3 + 0x207), bootpml4 + 0 * 8
# Page-Map Level 4
movl $0x22207, (%edi)
addl $0x1000, %edi
# Page Directory Pointer Table.
movl $(bootpml2 + 0x207), bootpml3 + 0 * 8
# Page-Directory Pointer Table
movl $0x23207, (%edi)
addl $0x1000, %edi
# Page-Directory (no user-space access here)
movl $0x24003, (%edi) # (First 2 MiB)
movl $0x25003, 8(%edi) # (Second 2 MiB)
addl $0x1000, %edi
# Page-Table
# Memory map the first 4 MiB.
movl $0x3, %ebx
movl $1024, %ecx
# Page Directory (no user-space access here).
movl $(bootpml1_a + 0x003), bootpml2 + 0 * 8
movl $(bootpml1_b + 0x003), bootpml2 + 1 * 8
# Page Table (identity map the first 4 MiB, except NULL).
movl $(bootpml1_a + 8), %edi
movl $0x1003, %esi
movl $1023, %ecx
1:
movl %ebx, (%edi)
addl $0x1000, %ebx
movl %esi, (%edi)
addl $0x1000, %esi
addl $8, %edi
loop 1b
# Map the null page.
movl $nullpage, %edi
shrl $12, %edi
movl $0x0003, bootpml1_a(, %edi, 8)
# Fractal mapping.
movl $(bootpml4 + 0x003), bootpml4 + 511 * 8
movl $(fracpml3 + 0x203), bootpml4 + 510 * 8
movl $(bootpml4 + 0x003), fracpml3 + 511 * 8
movl $(fracpml2 + 0x203), fracpml3 + 510 * 8
movl $(bootpml4 + 0x003), fracpml2 + 511 * 8
movl $(fracpml1 + 0x203), fracpml2 + 510 * 8
movl $(bootpml4 + 0x003), fracpml1 + 511 * 8
# Predefined room for forking address spaces.
movl $(forkpml2 + 0x203), fracpml3 + 0 * 8
movl $(forkpml1 + 0x203), forkpml2 + 0 * 8
# Physical page allocator.
movl $(physpml3 + 0x003), bootpml4 + 509 * 8
movl $(physpml2 + 0x003), physpml3 + 0 * 8
movl $(physpml1 + 0x003), physpml2 + 0 * 8
movl $(physpml0 + 0x003), physpml1 + 0 * 8
# Enable PAE.
movl %cr4, %eax
orl $0x20, %eax

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014, 2015.
This file is part of Sortix.
@ -31,83 +31,9 @@
#include "multiboot.h"
#include "x86-family/memorymanagement.h"
namespace Sortix {
namespace Page {
extern size_t stackused;
extern size_t stacklength;
void ExtendStack();
} // namespace Page
} // namespace Sortix
namespace Sortix {
namespace Memory {
void InitCPU()
{
// The x64 boot code already set up virtual memory and identity
// mapped the first 2 MiB. This code finishes the job such that
// virtual memory is fully usable and manageable.
// boot.s already initialized everything from 0x21000UL to 0x2F000UL to
// zeroes. Since these structures are already used, doing it here would
// destroying the existing data.
PML* const BOOTPML4 = (PML* const) 0x21000UL;
PML* const BOOTPML3 = (PML* const) 0x26000UL;
PML* const BOOTPML2 = (PML* const) 0x27000UL;
PML* const BOOTPML1 = (PML* const) 0x28000UL;
// First order of business is to map the virtual memory structures
// to the pre-defined locations in the virtual address space.
addr_t flags = PML_PRESENT | PML_WRITABLE;
// Fractal map the PML1s.
BOOTPML4->entry[511] = (addr_t) BOOTPML4 | flags;
// Fractal map the PML2s.
BOOTPML4->entry[510] = (addr_t) BOOTPML3 | flags | PML_FORK;
BOOTPML3->entry[511] = (addr_t) BOOTPML4 | flags;
// Fractal map the PML3s.
BOOTPML3->entry[510] = (addr_t) BOOTPML2 | flags | PML_FORK;
BOOTPML2->entry[511] = (addr_t) BOOTPML4 | flags;
// Fractal map the PML4s.
BOOTPML2->entry[510] = (addr_t) BOOTPML1 | flags | PML_FORK;
BOOTPML1->entry[511] = (addr_t) BOOTPML4 | flags;
// Add some predefined room for forking address spaces.
PML* const FORKPML2 = (PML* const) 0x29000UL;
PML* const FORKPML1 = (PML* const) 0x2A000UL;
BOOTPML3->entry[0] = (addr_t) FORKPML2 | flags | PML_FORK;
FORKPML2->entry[0] = (addr_t) FORKPML1 | flags | PML_FORK;
// The virtual memory structures are now available on the predefined
// locations. This means the virtual memory code is bootstrapped. Of
// course, we still have no physical page allocator, so that's the
// next step.
PML* const PHYSPML3 = (PML* const) 0x2B000UL;
PML* const PHYSPML2 = (PML* const) 0x2C000UL;
PML* const PHYSPML1 = (PML* const) 0x2D000UL;
PML* const PHYSPML0 = (PML* const) 0x2E000UL;
BOOTPML4->entry[509] = (addr_t) PHYSPML3 | flags;
PHYSPML3->entry[0] = (addr_t) PHYSPML2 | flags;
PHYSPML2->entry[0] = (addr_t) PHYSPML1 | flags;
PHYSPML1->entry[0] = (addr_t) PHYSPML0 | flags;
Page::stackused = 0;
Page::stacklength = 4096UL / sizeof(addr_t);
// The physical memory allocator should now be ready for use. Next
// up, the calling function will fill up the physical allocator with
// plenty of nice physical pages. (see Page::InitPushRegion)
}
// Please note that even if this function exists, you should still clean
// up the address space of a process _before_ calling
// DestroyAddressSpace. This is just a hack because it currently is
@ -156,13 +82,6 @@ void DestroyAddressSpace(addr_t fallback)
// TODO: Page::Put calls may internally Page::Get and then reusing pages we are not done with just yet
RecursiveFreeUserspacePages(TOPPMLLEVEL, 0);
// Switch to the address space from when the world was originally
// created. It should contain the kernel, the whole kernel, and
// nothing but the kernel.
PML* const BOOTPML4 = (PML* const) 0x21000UL;
if ( !fallback )
fallback = (addr_t) BOOTPML4;
SwitchAddressSpace(fallback);
// Ok, now we got marked everything left behind as unused, we can

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014, 2015.
This file is part of Sortix.
@ -49,13 +49,13 @@ namespace Sortix {
namespace Page {
void InitPushRegion(addr_t position, size_t length);
size_t pagesnotonstack;
size_t stackused;
size_t stackreserved;
size_t stacklength;
size_t totalmem;
size_t pagesnotonstack = 0;
size_t stackused = 0;
size_t stackreserved = 0;
size_t stacklength = 4096 / sizeof(addr_t);
size_t totalmem = 0;
size_t page_usage_counts[PAGE_USAGE_NUM_KINDS];
kthread_mutex_t pagelock;
kthread_mutex_t pagelock = KTHREAD_MUTEX_INITIALIZER;
} // namespace Page
} // namespace Sortix
@ -63,7 +63,6 @@ kthread_mutex_t pagelock;
namespace Sortix {
namespace Memory {
void InitCPU();
void AllocateKernelPMLs();
int SysMemStat(size_t* memused, size_t* memtotal);
addr_t PAT2PMLFlags[PAT_NUM];
@ -80,12 +79,7 @@ void InitCPU(multiboot_info_t* bootinfo)
MAXKERNELEND);
}
Page::stackreserved = 0;
Page::pagesnotonstack = 0;
Page::totalmem = 0;
Page::pagelock = KTHREAD_MUTEX_INITIALIZER;
if ( !( bootinfo->flags & MULTIBOOT_INFO_MEM_MAP ) )
if ( !(bootinfo->flags & MULTIBOOT_INFO_MEM_MAP) )
Panic("memorymanagement.cpp: The memory map flag was't set in "
"the multiboot structure. Are your bootloader multiboot "
"specification compliant?");
@ -98,9 +92,8 @@ void InitCPU(multiboot_info_t* bootinfo)
for ( addr_t i = 0; i < PAT_NUM; i++ )
PAT2PMLFlags[i] = EncodePATAsPMLFlag(i);
}
// Otherwise, reroute all requests to the backwards compatible
// scheme. TODO: Not all early 32-bit x86 CPUs supports these
// values, so we need yet another fallback.
// Otherwise, reroute all requests to the backwards compatible scheme.
// TODO: Not all early 32-bit x86 CPUs supports these values.
else
{
PAT2PMLFlags[PAT_UC] = PML_WRTHROUGH | PML_NOCACHE;
@ -113,9 +106,6 @@ void InitCPU(multiboot_info_t* bootinfo)
PAT2PMLFlags[PAT_UCM] = PML_NOCACHE;
}
// Initialize CPU-specific things.
InitCPU();
typedef const multiboot_memory_map_t* mmap_t;
// Loop over every detected memory region.
@ -203,8 +193,6 @@ void InitCPU(multiboot_info_t* bootinfo)
Log::PrintF("%zu bytes of RAM aren't used due to technical "
"restrictions.\n", (size_t) (Page::pagesnotonstack * 0x1000UL));
Memory::Unmap(0x0); // Remove NULL.
// Finish allocating the top level PMLs for the kernels use.
AllocateKernelPMLs();
}

View File

@ -32,6 +32,22 @@
.long 0x00000003 # Flags.
.long -(0x1BADB002 + 0x00000003) # Checksum.
.section .bss, "aw", @nobits
.align 4096
bootpml2:
.skip 4096
bootpml1:
.skip 4096
fracpml1:
.skip 4096
physpml1:
.skip 4096
physpml0:
.skip 4096
nullpage: .global nullpage
.skip 4096
.section .text
.global _start
.global __start
.type _start, @function
@ -52,6 +68,41 @@ __start:
shrl $8, %ecx
movb %cl, gdt + 0x28 + 7
movl $bootpml2, %edi
movl %edi, %cr3
# Page Directory.
movl $(bootpml1 + 0x003), bootpml2 + 0 * 4
# Page Table (identity map the first 4 MiB, except NULL).
movl $(bootpml1 + 4), %edi
movl $0x1003, %esi
movl $1023, %ecx
1:
movl %esi, (%edi)
addl $0x1000, %esi
addl $4, %edi
loop 1b
# Map the null page.
movl $nullpage, %edi
shrl $12, %edi
movl $0x0003, bootpml1(, %edi, 4)
# Fractal mapping.
movl $(bootpml2 + 0x003), bootpml2 + 1023 * 4
movl $(fracpml1 + 0x203), bootpml2 + 1022 * 4
movl $(bootpml2 + 0x003), fracpml1 + 1023 * 4
# Physical page allocator.
movl $(physpml1 + 0x003), bootpml2 + 1021 * 4
movl $(physpml0 + 0x003), physpml1 + 0 * 4
# Enable paging.
movl %cr0, %edi
orl $0x80000000, %edi
movl %edi, %cr0
# Load the Global Descriptor Table pointer register.
subl $6, %esp
movw gdt_size_minus_one, %cx

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014, 2015.
This file is part of Sortix.
@ -45,64 +45,6 @@ void ExtendStack();
namespace Sortix {
namespace Memory {
void InitCPU()
{
PML* const BOOTPML2 = (PML* const) 0x11000UL;
PML* const BOOTPML1 = (PML* const) 0x12000UL;
//PML* const FORKPML1 = (PML* const) 0x13000UL;
PML* const IDENPML1 = (PML* const) 0x14000UL;
// Initialize the memory structures with zeroes.
memset((PML* const) 0x11000UL, 0, 0x6000UL);
// Identity map the first 4 MiB.
addr_t flags = PML_PRESENT | PML_WRITABLE;
BOOTPML2->entry[0] = ((addr_t) IDENPML1) | flags;
for ( size_t i = 0; i < ENTRIES; i++ )
IDENPML1->entry[i] = (i * 4096UL) | flags;
// Next order of business is to map the virtual memory structures
// to the pre-defined locations in the virtual address space.
// Fractal map the PML1s.
BOOTPML2->entry[1023] = (addr_t) BOOTPML2 | flags;
// Fractal map the PML2s.
BOOTPML2->entry[1022] = (addr_t) BOOTPML1 | flags | PML_FORK;
BOOTPML1->entry[1023] = (addr_t) BOOTPML2 | flags;
// Add some predefined room for forking address spaces.
BOOTPML1->entry[0] = 0; // (addr_t) FORKPML1 | flags | PML_FORK;
// The virtual memory structures are now available on the predefined
// locations. This means the virtual memory code is bootstrapped. Of
// course, we still have no physical page allocator, so that's the
// next step.
PML* const PHYSPML1 = (PML* const) 0x15000UL;
PML* const PHYSPML0 = (PML* const) 0x16000UL;
BOOTPML2->entry[1021] = (addr_t) PHYSPML1 | flags;
PHYSPML1->entry[0] = (addr_t) PHYSPML0 | flags;
// Alright, enable virtual memory!
SwitchAddressSpace((addr_t) BOOTPML2);
size_t cr0;
asm volatile("mov %%cr0, %0": "=r"(cr0));
cr0 |= 0x80000000UL; /* Enable paging! */
asm volatile("mov %0, %%cr0":: "r"(cr0));
Page::stackused = 0;
Page::stacklength = 4096UL / sizeof(addr_t);
// The physical memory allocator should now be ready for use. Next
// up, the calling function will fill up the physical allocator with
// plenty of nice physical pages. (see Page::InitPushRegion)
}
// Please note that even if this function exists, you should still clean
// up the address space of a process _before_ calling
// DestroyAddressSpace. This is just a hack because it currently is
@ -147,13 +89,6 @@ void DestroyAddressSpace(addr_t fallback)
// TODO: Page::Put calls may internally Page::Get and then reusing pages we are not done with just yet
RecursiveFreeUserspacePages(TOPPMLLEVEL, 0);
// Switch to the address space from when the world was originally
// created. It should contain the kernel, the whole kernel, and
// nothing but the kernel.
PML* const BOOTPML2 = (PML* const) 0x11000UL;
if ( !fallback )
fallback = (addr_t) BOOTPML2;
SwitchAddressSpace(fallback);
// Ok, now we got marked everything left behind as unused, we can