From 218875eb79b80bfed4cdb2b6193744614abd7caa Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 16 Mar 2015 17:24:42 +0100 Subject: [PATCH] Initialize paging before KernelInit. --- kernel/com.cpp | 37 ++++--- kernel/com.h | 1 - .../include/sortix/kernel/memorymanagement.h | 4 +- kernel/kernel.cpp | 20 ++-- kernel/x64/boot.S | 99 ++++++++++++++----- kernel/x64/memorymanagement.cpp | 83 +--------------- kernel/x86-family/memorymanagement.cpp | 32 ++---- kernel/x86/boot.S | 51 ++++++++++ kernel/x86/memorymanagement.cpp | 67 +------------ 9 files changed, 161 insertions(+), 233 deletions(-) diff --git a/kernel/com.cpp b/kernel/com.cpp index 8323262c..8aed1cc3 100644 --- a/kernel/com.cpp +++ b/kernel/com.cpp @@ -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 com_devices[1 + NUM_COM_PORTS]; void Init(const char* devpath, Ref 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++ ) diff --git a/kernel/com.h b/kernel/com.h index 76b85bf6..db0d2ded 100644 --- a/kernel/com.h +++ b/kernel/com.h @@ -31,7 +31,6 @@ namespace Sortix { namespace COM { -void EarlyInit(); void Init(const char* devpath, Ref slashdev); } // namespace COM diff --git a/kernel/include/sortix/kernel/memorymanagement.h b/kernel/include/sortix/kernel/memorymanagement.h index 912f961d..22da3ccf 100644 --- a/kernel/include/sortix/kernel/memorymanagement.h +++ b/kernel/include/sortix/kernel/memorymanagement.h @@ -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); diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index 0f89ff9b..94ac0310 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -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(); diff --git a/kernel/x64/boot.S b/kernel/x64/boot.S index ff95ee25..6e94f09a 100644 --- a/kernel/x64/boot.S +++ b/kernel/x64/boot.S @@ -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 diff --git a/kernel/x64/memorymanagement.cpp b/kernel/x64/memorymanagement.cpp index 82674e2c..755709de 100644 --- a/kernel/x64/memorymanagement.cpp +++ b/kernel/x64/memorymanagement.cpp @@ -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 diff --git a/kernel/x86-family/memorymanagement.cpp b/kernel/x86-family/memorymanagement.cpp index 7eee7145..9398483b 100644 --- a/kernel/x86-family/memorymanagement.cpp +++ b/kernel/x86-family/memorymanagement.cpp @@ -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(); } diff --git a/kernel/x86/boot.S b/kernel/x86/boot.S index 3ed45951..41094117 100644 --- a/kernel/x86/boot.S +++ b/kernel/x86/boot.S @@ -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 diff --git a/kernel/x86/memorymanagement.cpp b/kernel/x86/memorymanagement.cpp index 3776c7b8..03fae138 100644 --- a/kernel/x86/memorymanagement.cpp +++ b/kernel/x86/memorymanagement.cpp @@ -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