From 0d0ab18b451c4a8e6787218cca618e8697fb5846 Mon Sep 17 00:00:00 2001 From: Baptiste Wicht Date: Mon, 16 Dec 2013 21:31:23 +0100 Subject: [PATCH] Reimplement e820 support --- kernel/include/e820.hpp | 56 ++++++++++++++++++++++++++ kernel/include/types.hpp | 7 +++- kernel/src/boot/boot_16.cpp | 51 +++++++++++++++++++++++- kernel/src/e820.cpp | 78 +++++++++++++++++++++++++++++++++++++ kernel/src/kernel.cpp | 3 ++ 5 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 kernel/include/e820.hpp create mode 100644 kernel/src/e820.cpp diff --git a/kernel/include/e820.hpp b/kernel/include/e820.hpp new file mode 100644 index 00000000..aca8cdaa --- /dev/null +++ b/kernel/include/e820.hpp @@ -0,0 +1,56 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +/* + * The implementation of the memory detection is made in boot_16.cpp + * The finalization of the memory detection is made in e820.cpp once in long + * mode. + */ + +#ifndef CODE_16 +#include "types.hpp" +#endif + +#ifndef E820_HPP +#define E820_HPP + +namespace e820 { + +constexpr const uint32_t MAX_E820_ENTRIES = 25; + +struct bios_e820_entry { + uint32_t base_low; + uint32_t base_high; + uint32_t length_low; + uint32_t length_high; + uint16_t type; + uint16_t acpi; +// uint32_t damn_padding; +} __attribute__((packed)); + +extern int16_t bios_e820_entry_count; +extern bios_e820_entry bios_e820_entries[MAX_E820_ENTRIES]; + +struct mmapentry { + uint64_t base; + uint64_t size; + uint64_t type; +}; + +//Must be called by the kernel to transform e820 entries into mmap entries +void finalize_memory_detection(); + +bool mmap_failed(); +uint64_t mmap_entry_count(); +const mmapentry& mmap_entry(uint64_t i); +const char* str_e820_type(uint64_t type); + +size_t available_memory(); + +} //end of namespace e820 + +#endif \ No newline at end of file diff --git a/kernel/include/types.hpp b/kernel/include/types.hpp index ede658f0..fb3b37de 100644 --- a/kernel/include/types.hpp +++ b/kernel/include/types.hpp @@ -14,11 +14,14 @@ typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__))); typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__))); typedef unsigned int uint64_t __attribute__ ((__mode__ (__DI__))); +typedef unsigned int int16_t __attribute__ ((__mode__ (__HI__))); + typedef uint64_t uintptr_t; typedef uint64_t size_t; -static_assert(sizeof(uint8_t) == 1, "uint32_t must be 1 byte long"); -static_assert(sizeof(uint16_t) == 2, "uint32_t must be 2 bytes long"); +static_assert(sizeof(uint8_t) == 1, "uint8_t must be 1 byte long"); +static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes long"); +static_assert(sizeof(int16_t) == 2, "int16_t must be 2 bytes long"); static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes long"); static_assert(sizeof(uint64_t) == 8, "uint64_t must be 8 bytes long"); static_assert(sizeof(size_t) == 8, "size_t must be 8 bytes long"); diff --git a/kernel/src/boot/boot_16.cpp b/kernel/src/boot/boot_16.cpp index a97b343b..d7ca6c9a 100644 --- a/kernel/src/boot/boot_16.cpp +++ b/kernel/src/boot/boot_16.cpp @@ -12,14 +12,27 @@ namespace { typedef unsigned int uint8_t __attribute__((__mode__(__QI__))); typedef unsigned int uint16_t __attribute__ ((__mode__ (__HI__))); +typedef int int16_t __attribute__ ((__mode__ (__HI__))); typedef unsigned int uint32_t __attribute__ ((__mode__ (__SI__))); typedef unsigned int uint64_t __attribute__ ((__mode__ (__DI__))); static_assert(sizeof(uint8_t) == 1, "uint8_t must be 1 byte long"); static_assert(sizeof(uint16_t) == 2, "uint16_t must be 2 bytes long"); +static_assert(sizeof(int16_t) == 2, "int16_t must be 2 bytes long"); static_assert(sizeof(uint32_t) == 4, "uint32_t must be 4 bytes long"); static_assert(sizeof(uint64_t) == 8, "uint64_t must be 8 bytes long"); +//Just here to be able to compile e820.hpp, should not be +//used in boot_16.cpp +typedef uint64_t size_t; + +} //end of anonymous namespace + +#define CODE_16 +#include "e820.hpp" //Just for the address of the e820 map + +namespace { + struct gdt_ptr { uint16_t length; uint32_t pointer; @@ -43,6 +56,41 @@ void reset_segments(){ set_ds(0); } +int detect_memory_e820(){ + auto* smap = &e820::bios_e820_entries[0]; + + uint16_t entries = 0; + + uint32_t contID = 0; + int signature; + int bytes; + + do { + asm volatile ("int 0x15" + : "=a"(signature), "=c"(bytes), "=b"(contID) + : "a"(0xE820), "b"(contID), "c"(24), "d"(0x534D4150), "D"(smap)); + + if (signature != 0x534D4150){ + return -1; + } + + if (bytes > 20 && (smap->acpi & 0x0001) == 0){ + // ignore this entry + } else { + smap++; + entries++; + } + } while (contID != 0 && entries < e820::MAX_E820_ENTRIES); + + return entries; +} + +void detect_memory(){ + //TODO If e820 fails, try other solutions to get memory map + + e820::bios_e820_entry_count = detect_memory_e820(); +} + void disable_interrupts(){ __asm__ __volatile__ ("cli"); } @@ -181,7 +229,8 @@ void __attribute__ ((noreturn)) rm_main(){ //Make sure segments are clean reset_segments(); - //TODO Detect memory + //Analyze memory + detect_memory(); //Disable interrupts disable_interrupts(); diff --git a/kernel/src/e820.cpp b/kernel/src/e820.cpp new file mode 100644 index 00000000..2113e2ba --- /dev/null +++ b/kernel/src/e820.cpp @@ -0,0 +1,78 @@ +//======================================================================= +// Copyright Baptiste Wicht 2013. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#include "e820.hpp" + +e820::bios_e820_entry e820::bios_e820_entries[e820::MAX_E820_ENTRIES]; +int16_t e820::bios_e820_entry_count = 0; + +namespace { + +e820::mmapentry e820_mmap[e820::MAX_E820_ENTRIES]; +size_t _available_memory; + +} //end of namespace anonymous + +void e820::finalize_memory_detection(){ + if(!mmap_failed()){ + for(uint64_t i = 0; i < bios_e820_entry_count; ++i){ + auto& bios_entry = bios_e820_entries[i]; + auto& os_entry = e820_mmap[i]; + + uint64_t base = bios_entry.base_low + (static_cast(bios_entry.base_high) << 32); + uint64_t length = bios_entry.length_low + (static_cast(bios_entry.length_high) << 32); + + os_entry.base = base; + os_entry.size = length; + os_entry.type = bios_entry.type; + + if(os_entry.base == 0 && os_entry.type == 1){ + os_entry.type = 7; + } + + if(os_entry.type == 1){ + _available_memory += os_entry.size; + } + } + } +} + +uint64_t e820::mmap_entry_count(){ + return bios_e820_entry_count; +} + +bool e820::mmap_failed(){ + return bios_e820_entry_count <= 0; +} + +const e820::mmapentry& e820::mmap_entry(uint64_t i){ + return e820_mmap[i]; +} + +const char* e820::str_e820_type(uint64_t type){ + switch(type){ + case 1: + return "Free"; + case 2: + return "Reserved"; + case 3: + case 4: + return "ACPI"; + case 5: + return "Unusable"; + case 6: + return "Disabled"; + case 7: + return "Kernel"; + default: + return "Unknown"; + } +} + +size_t e820::available_memory(){ + return _available_memory; +} diff --git a/kernel/src/kernel.cpp b/kernel/src/kernel.cpp index d3f9117d..9bebcc16 100644 --- a/kernel/src/kernel.cpp +++ b/kernel/src/kernel.cpp @@ -14,6 +14,7 @@ #include "acpi.hpp" #include "interrupts.hpp" #include "arch.hpp" +#include "e820.hpp" extern "C" { @@ -22,6 +23,8 @@ void _init(); void kernel_main(){ arch::enable_sse(); + e820::finalize_memory_detection(); + interrupt::install_idt(); interrupt::install_isrs(); interrupt::remap_irqs();