From 84b7bc5e14bcdaef0721143f8d99b40fde7e7c5e Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 22 May 2020 12:55:23 +0200 Subject: [PATCH] Kernel: Add convenient ways to map whole BIOS and EBDA into memory This patch adds a MappedROM abstraction to the Kernel VM subsystem. It's basically the read-only byte buffer equivalent of a TypedMapping. We use this in the ACPI and MP table parsers to scan for interesting stuff in low memory instead of doing a bunch of address arithmetic. --- Kernel/ACPI/MultiProcessorParser.cpp | 37 ++++++----------- Kernel/ACPI/MultiProcessorParser.h | 2 +- Kernel/ACPI/Parser.cpp | 35 +++++++---------- Kernel/Arch/PC/BIOS.cpp | 59 ++++++++++++++++++++++++++++ Kernel/Arch/PC/BIOS.h | 36 +++++++++++++++++ Kernel/CMakeLists.txt | 1 + Kernel/Forward.h | 1 + Kernel/VM/MappedROM.h | 45 +++++++++++++++++++++ 8 files changed, 169 insertions(+), 47 deletions(-) create mode 100644 Kernel/Arch/PC/BIOS.cpp create mode 100644 Kernel/Arch/PC/BIOS.h create mode 100644 Kernel/VM/MappedROM.h diff --git a/Kernel/ACPI/MultiProcessorParser.cpp b/Kernel/ACPI/MultiProcessorParser.cpp index 450a62236c0..2191d1194d4 100644 --- a/Kernel/ACPI/MultiProcessorParser.cpp +++ b/Kernel/ACPI/MultiProcessorParser.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -115,42 +116,28 @@ void MultiProcessorParser::parse_configuration_table() PhysicalAddress MultiProcessorParser::search_floating_pointer() { - PhysicalAddress mp_floating_pointer; - auto region = MM.allocate_kernel_region(PhysicalAddress(0), PAGE_SIZE, "MultiProcessor Parser Floating Pointer Structure Finding", Region::Access::Read); - u16 ebda_seg = (u16) * ((uint16_t*)((region->vaddr().get() & PAGE_MASK) + 0x40e)); - klog() << "MultiProcessor: Probing EBDA, Segment 0x" << String::format("%x", ebda_seg); - - mp_floating_pointer = search_floating_pointer_in_ebda(ebda_seg); + auto mp_floating_pointer = search_floating_pointer_in_ebda(); if (!mp_floating_pointer.is_null()) return mp_floating_pointer; return search_floating_pointer_in_bios_area(); } -PhysicalAddress MultiProcessorParser::search_floating_pointer_in_ebda(u16 ebda_segment) +PhysicalAddress MultiProcessorParser::search_floating_pointer_in_ebda() { - auto floating_pointer_region = MM.allocate_kernel_region(PhysicalAddress(page_base_of((u32)(ebda_segment << 4))), PAGE_ROUND_UP(1024), "MultiProcessor Parser floating_pointer Finding #1", Region::Access::Read, false, true); - char* p_floating_pointer_str = (char*)(PhysicalAddress(ebda_segment << 4).as_ptr()); - for (char* floating_pointer_str = (char*)floating_pointer_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).as_ptr(); floating_pointer_str < (char*)(floating_pointer_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).get() + 1024); floating_pointer_str += 16) { -#ifdef MULTIPROCESSOR_DEBUG - //dbg() << "MultiProcessor: Looking for floating pointer structure in EBDA @ V0x " << String::format("%x", floating_pointer_str) << ", P0x" << String::format("%x", p_floating_pointer_str); -#endif - if (!strncmp("_MP_", floating_pointer_str, strlen("_MP_"))) - return PhysicalAddress((FlatPtr)p_floating_pointer_str); - p_floating_pointer_str += 16; + klog() << "MultiProcessor: Probing EBDA"; + auto ebda = map_ebda(); + for (auto* floating_pointer_str = ebda.base(); floating_pointer_str < ebda.end(); floating_pointer_str += 16) { + if (!strncmp("_MP_", (const char*)floating_pointer_str, strlen("_MP_"))) + return ebda.paddr_of(floating_pointer_str); } return {}; } PhysicalAddress MultiProcessorParser::search_floating_pointer_in_bios_area() { - auto floating_pointer_region = MM.allocate_kernel_region(PhysicalAddress(page_base_of((u32)0xE0000)), PAGE_ROUND_UP(0xFFFFF - 0xE0000), "MultiProcessor Parser floating_pointer Finding #2", Region::Access::Read, false, true); - char* p_floating_pointer_str = (char*)(PhysicalAddress(0xE0000).as_ptr()); - for (char* floating_pointer_str = (char*)floating_pointer_region->vaddr().offset(offset_in_page((u32)(0xE0000))).as_ptr(); floating_pointer_str < (char*)(floating_pointer_region->vaddr().offset(offset_in_page((u32)(0xE0000))).get() + (0xFFFFF - 0xE0000)); floating_pointer_str += 16) { -#ifdef MULTIPROCESSOR_DEBUG - //dbg() << "MultiProcessor: Looking for floating pointer structure in BIOS area @ V0x " << String::format("%x", floating_pointer_str) << ", P0x" << String::format("%x", p_floating_pointer_str); -#endif - if (!strncmp("_MP_", floating_pointer_str, strlen("_MP_"))) - return PhysicalAddress((FlatPtr)p_floating_pointer_str); - p_floating_pointer_str += 16; + auto bios = map_bios(); + for (auto* floating_pointer_str = bios.base(); floating_pointer_str < bios.end(); floating_pointer_str += 16) { + if (!strncmp("_MP_", (const char*)floating_pointer_str, strlen("_MP_"))) + return bios.paddr_of(floating_pointer_str); } return {}; } diff --git a/Kernel/ACPI/MultiProcessorParser.h b/Kernel/ACPI/MultiProcessorParser.h index 18b2be6ad16..7aca917d0fa 100644 --- a/Kernel/ACPI/MultiProcessorParser.h +++ b/Kernel/ACPI/MultiProcessorParser.h @@ -206,7 +206,7 @@ protected: Vector get_pci_bus_ids() const; PhysicalAddress search_floating_pointer(); - PhysicalAddress search_floating_pointer_in_ebda(u16 ebda_segment); + PhysicalAddress search_floating_pointer_in_ebda(); PhysicalAddress search_floating_pointer_in_bios_area(); PhysicalAddress m_floating_pointer; diff --git a/Kernel/ACPI/Parser.cpp b/Kernel/ACPI/Parser.cpp index 7b7817d7d41..54ece1a94d2 100644 --- a/Kernel/ACPI/Parser.cpp +++ b/Kernel/ACPI/Parser.cpp @@ -27,11 +27,12 @@ #include #include +#include +#include #include +#include #include #include -#include -#include namespace Kernel { namespace ACPI { @@ -321,32 +322,25 @@ Parser::Parser(PhysicalAddress rsdp) locate_static_data(); } -static PhysicalAddress find_rsdp_in_ebda(u16 ebda_segment) +static PhysicalAddress find_rsdp_in_ebda() { - auto rsdp_region = MM.allocate_kernel_region(PhysicalAddress(page_base_of((u32)(ebda_segment << 4))), PAGE_ROUND_UP(1024), "ACPI Static Parser RSDP Finding #1", Region::Access::Read, false, true); - char* p_rsdp_str = (char*)(PhysicalAddress(ebda_segment << 4).as_ptr()); - for (char* rsdp_str = (char*)rsdp_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).as_ptr(); rsdp_str < (char*)(rsdp_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).get() + 1024); rsdp_str += 16) { + auto ebda = map_ebda(); + for (auto* rsdp_str = ebda.base(); rsdp_str < ebda.end(); rsdp_str += 16) { #ifdef ACPI_DEBUG dbg() << "ACPI: Looking for RSDP in EBDA @ V " << (void*)rsdp_str << ", P " << (void*)p_rsdp_str; #endif - if (!strncmp("RSD PTR ", rsdp_str, strlen("RSD PTR "))) - return PhysicalAddress((FlatPtr)p_rsdp_str); - p_rsdp_str += 16; + if (!strncmp("RSD PTR ", (const char*)rsdp_str, strlen("RSD PTR "))) + return ebda.paddr_of(rsdp_str); } return {}; } static PhysicalAddress find_rsdp_in_bios_area() { - auto rsdp_region = MM.allocate_kernel_region(PhysicalAddress(0xE0000), PAGE_ROUND_UP(0xFFFFF - 0xE0000), "ACPI Static Parser RSDP Finding #2", Region::Access::Read, false, true); - char* p_rsdp_str = (char*)(PhysicalAddress(0xE0000).as_ptr()); - for (char* rsdp_str = (char*)rsdp_region->vaddr().offset(offset_in_page((u32)(0xE0000))).as_ptr(); rsdp_str < (char*)(rsdp_region->vaddr().offset(offset_in_page((u32)(0xE0000))).get() + (0xFFFFF - 0xE0000)); rsdp_str += 16) { -#ifdef ACPI_DEBUG - dbg() << "ACPI: Looking for RSDP in BIOS ROM area @ V " << (void*)rsdp_str << ", P " << (void*)p_rsdp_str; -#endif - if (!strncmp("RSD PTR ", rsdp_str, strlen("RSD PTR "))) - return PhysicalAddress((FlatPtr)p_rsdp_str); - p_rsdp_str += 16; + auto bios = map_bios(); + for (auto* rsdp_str = bios.base(); rsdp_str < bios.end(); rsdp_str += 16) { + if (!strncmp("RSD PTR ", (const char*)rsdp_str, strlen("RSD PTR "))) + return bios.paddr_of(rsdp_str); } return {}; } @@ -364,9 +358,8 @@ static bool validate_table(const Structures::SDTHeader& v_header, size_t length) PhysicalAddress StaticParsing::find_rsdp() { - auto ebda_seg_ptr = map_typed(PhysicalAddress(0x40e)); - klog() << "ACPI: Probing EBDA, Segment 0x" << String::format("%x", *ebda_seg_ptr); - auto rsdp = find_rsdp_in_ebda(*ebda_seg_ptr); + klog() << "ACPI: Probing EBDA"; + auto rsdp = find_rsdp_in_ebda(); if (!rsdp.is_null()) return rsdp; return find_rsdp_in_bios_area(); diff --git a/Kernel/Arch/PC/BIOS.cpp b/Kernel/Arch/PC/BIOS.cpp new file mode 100644 index 00000000000..f8cae3855af --- /dev/null +++ b/Kernel/Arch/PC/BIOS.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include + +namespace Kernel { + +MappedROM map_bios() +{ + MappedROM mapping; + mapping.size = 128 * KB; + mapping.paddr = PhysicalAddress(0xe0000); + mapping.region = MM.allocate_kernel_region(mapping.paddr, PAGE_ROUND_UP(mapping.size), {}, Region::Access::Read); + return mapping; +} + +MappedROM map_ebda() +{ + auto ebda_segment_ptr = map_typed(PhysicalAddress(0x40e)); + auto ebda_length_ptr = map_typed(PhysicalAddress(0x413)); + + PhysicalAddress ebda_paddr(*ebda_segment_ptr << 4); + size_t ebda_size = *ebda_length_ptr; + + MappedROM mapping; + mapping.region = MM.allocate_kernel_region(ebda_paddr.page_base(), PAGE_ROUND_UP(ebda_size), {}, Region::Access::Read); + mapping.offset = ebda_paddr.offset_in_page(); + mapping.size = ebda_size; + mapping.paddr = ebda_paddr; + return mapping; +} + +} diff --git a/Kernel/Arch/PC/BIOS.h b/Kernel/Arch/PC/BIOS.h new file mode 100644 index 00000000000..642e221d140 --- /dev/null +++ b/Kernel/Arch/PC/BIOS.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace Kernel { + +MappedROM map_bios(); +MappedROM map_ebda(); + +} diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 7a48086503b..5a8ee7f1035 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -5,6 +5,7 @@ set(KERNEL_SOURCES ACPI/MultiProcessorParser.cpp ACPI/Parser.cpp Arch/i386/CPU.cpp + Arch/PC/BIOS.cpp CMOS.cpp CommandLine.cpp Console.cpp diff --git a/Kernel/Forward.h b/Kernel/Forward.h index 1587051c974..4b89adb116f 100644 --- a/Kernel/Forward.h +++ b/Kernel/Forward.h @@ -44,6 +44,7 @@ class InodeWatcher; class KBuffer; class KResult; class LocalSocket; +class MappedROM; class PageDirectory; class PerformanceEventBuffer; class PhysicalPage; diff --git a/Kernel/VM/MappedROM.h b/Kernel/VM/MappedROM.h new file mode 100644 index 00000000000..5eb37f57ce5 --- /dev/null +++ b/Kernel/VM/MappedROM.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020, Andreas Kling + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace Kernel { + +struct MappedROM { + const u8* base() const { return region->vaddr().offset(offset).as_ptr(); } + const u8* end() const { return base() + size; } + OwnPtr region; + size_t size { 0 }; + size_t offset { 0 }; + PhysicalAddress paddr; + + PhysicalAddress paddr_of(const u8* ptr) const { return paddr.offset(ptr - this->base()); } +}; + +}