From acdd1424bc8c76e739d11555b2ef258872ddf32f Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Wed, 20 Jan 2021 18:34:16 +0200 Subject: [PATCH] Kernel: Implement a simple Scatter/Gather List This allows converting a single virtual buffer into its non-physically contiguous parts, this is especially useful for DMA-based devices that support scatter/gather-like functionality, as it eliminates the need to clone outgoing buffers into one physically contiguous buffer. --- Kernel/CMakeLists.txt | 1 + Kernel/VM/MemoryManager.h | 1 + Kernel/VM/ScatterGatherList.cpp | 67 +++++++++++++++++++++++++++++++++ Kernel/VM/ScatterGatherList.h | 55 +++++++++++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 Kernel/VM/ScatterGatherList.cpp create mode 100644 Kernel/VM/ScatterGatherList.h diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 052badfc597..40481e25ee1 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -236,6 +236,7 @@ set(KERNEL_SOURCES VM/Range.cpp VM/RangeAllocator.cpp VM/Region.cpp + VM/ScatterGatherList.cpp VM/SharedInodeVMObject.cpp VM/Space.cpp VM/VMObject.cpp diff --git a/Kernel/VM/MemoryManager.h b/Kernel/VM/MemoryManager.h index 5e5ff9b48b4..f419a9b8500 100644 --- a/Kernel/VM/MemoryManager.h +++ b/Kernel/VM/MemoryManager.h @@ -124,6 +124,7 @@ class MemoryManager { friend class PhysicalRegion; friend class AnonymousVMObject; friend class Region; + friend class ScatterGatherList; friend class VMObject; public: diff --git a/Kernel/VM/ScatterGatherList.cpp b/Kernel/VM/ScatterGatherList.cpp new file mode 100644 index 00000000000..c3771f74383 --- /dev/null +++ b/Kernel/VM/ScatterGatherList.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * 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 + +namespace Kernel { + +ScatterGatherList ScatterGatherList::create_from_buffer(const u8* buffer, size_t size) +{ + VERIFY(buffer && size); + ScatterGatherList new_list; + auto* region = MM.find_region_from_vaddr(VirtualAddress(buffer)); + VERIFY(region); + while (size > 0) { + size_t offset_in_page = (VirtualAddress(buffer) - region->vaddr()).get() % PAGE_SIZE; + size_t size_in_page = min(PAGE_SIZE - offset_in_page, size); + VERIFY(offset_in_page + size_in_page - 1 <= PAGE_SIZE); + new_list.add_entry(region->physical_page(region->page_index_from_address(VirtualAddress(buffer)))->paddr().get(), offset_in_page, size_in_page); + size -= size_in_page; + buffer += size_in_page; + } + return new_list; +} + +ScatterGatherList ScatterGatherList::create_from_physical(PhysicalAddress paddr, size_t size) +{ + VERIFY(!paddr.is_null() && size); + ScatterGatherList new_list; + new_list.add_entry(paddr.page_base().get(), paddr.offset_in_page(), size); + return new_list; +} + +void ScatterGatherList::add_entry(FlatPtr addr, size_t offset, size_t size) +{ + m_entries.append({ addr, offset, size }); +} + +void ScatterGatherList::for_each_entry(Function callback) const +{ + for (auto& entry : m_entries) + callback(entry.page_base + entry.offset, entry.length); +} + +} diff --git a/Kernel/VM/ScatterGatherList.h b/Kernel/VM/ScatterGatherList.h new file mode 100644 index 00000000000..3b33f92a17d --- /dev/null +++ b/Kernel/VM/ScatterGatherList.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021, the SerenityOS developers. + * 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 +#include + +namespace Kernel { + +class ScatterGatherList { + struct ScatterGatherEntry { + FlatPtr page_base; + size_t offset; + size_t length; + }; + +public: + static ScatterGatherList create_from_buffer(const u8* buffer, size_t); + static ScatterGatherList create_from_physical(PhysicalAddress, size_t); + + void add_entry(FlatPtr, size_t offset, size_t size); + [[nodiscard]] size_t length() const { return m_entries.size(); } + + void for_each_entry(Function callback) const; + +private: + Vector m_entries; +}; + +}