diff options
author | Andreas Kling <kling@serenityos.org> | 2020-07-15 17:32:46 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-15 18:47:45 +0200 |
commit | 2da44dba440da4562eac4fd4b8ab828537f64790 (patch) | |
tree | 982d89fe8052e5c0e4a94ae82b6584ed944850ee | |
parent | 0ce4d3e9425f5c6d78dbd3a82a06aa1e2b45377c (diff) | |
download | serenity-2da44dba440da4562eac4fd4b8ab828537f64790.zip |
UserspaceEmulator: Add support for shared buffers (shbuf)
We track these separately from regular mmap() regions, as they have
slightly different behaviors.
-rw-r--r-- | DevTools/UserspaceEmulator/CMakeLists.txt | 1 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/Emulator.cpp | 117 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/Emulator.h | 10 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/SharedBufferRegion.cpp | 112 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/SharedBufferRegion.h | 66 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/SoftMMU.cpp | 10 | ||||
-rw-r--r-- | DevTools/UserspaceEmulator/SoftMMU.h | 7 |
7 files changed, 311 insertions, 12 deletions
diff --git a/DevTools/UserspaceEmulator/CMakeLists.txt b/DevTools/UserspaceEmulator/CMakeLists.txt index d5670137db..ad0e0c4fd1 100644 --- a/DevTools/UserspaceEmulator/CMakeLists.txt +++ b/DevTools/UserspaceEmulator/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES Emulator.cpp MmapRegion.cpp + SharedBufferRegion.cpp SimpleRegion.cpp SoftCPU.cpp SoftMMU.cpp diff --git a/DevTools/UserspaceEmulator/Emulator.cpp b/DevTools/UserspaceEmulator/Emulator.cpp index 399aa1ab35..508a0bdc76 100644 --- a/DevTools/UserspaceEmulator/Emulator.cpp +++ b/DevTools/UserspaceEmulator/Emulator.cpp @@ -26,12 +26,14 @@ #include "Emulator.h" #include "MmapRegion.h" +#include "SharedBufferRegion.h" #include "SimpleRegion.h" #include "SoftCPU.h" #include <AK/LexicalPath.h> #include <AK/LogStream.h> #include <Kernel/API/Syscall.h> #include <fcntl.h> +#include <serenity.h> #include <stdio.h> #include <string.h> #include <sys/mman.h> @@ -194,6 +196,20 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) dbgprintf("Syscall: %s (%x)\n", Syscall::to_string((Syscall::Function)function), function); #endif switch (function) { + case SC_shbuf_create: + return virt$shbuf_create(arg1, arg2); + case SC_shbuf_allow_pid: + return virt$shbuf_allow_pid(arg1, arg2); + case SC_shbuf_allow_all: + return virt$shbuf_allow_all(arg1); + case SC_shbuf_get: + return virt$shbuf_get(arg1, arg2); + case SC_shbuf_release: + return virt$shbuf_release(arg1); + case SC_shbuf_seal: + return virt$shbuf_seal(arg1); + case SC_shbuf_set_volatile: + return virt$shbuf_set_volatile(arg1, arg2); case SC_mmap: return virt$mmap(arg1); case SC_munmap: @@ -260,6 +276,8 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) return virt$recvfrom(arg1); case SC_kill: return virt$kill(arg1, arg2); + case SC_set_mmap_name: + return virt$set_mmap_name(arg1); case SC_exit: virt$exit((int)arg1); return 0; @@ -270,6 +288,69 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) } } +int Emulator::virt$shbuf_create(int size, FlatPtr buffer) +{ + u8* host_data = nullptr; + int shbuf_id = syscall(SC_shbuf_create, size, &host_data); + if (shbuf_id < 0) + return -errno; + FlatPtr address = allocate_vm(size, PAGE_SIZE); + auto region = SharedBufferRegion::create_with_shbuf_id(address, size, shbuf_id, host_data); + m_mmu.add_region(move(region)); + m_mmu.copy_to_vm(buffer, &address, sizeof(address)); + return shbuf_id; +} + +FlatPtr Emulator::virt$shbuf_get(int shbuf_id, FlatPtr size_ptr) +{ + size_t host_size = 0; + void* host_data = (void*)syscall(SC_shbuf_get, shbuf_id, &host_size); + if (host_data == (void*)-1) + return -errno; + FlatPtr address = allocate_vm(host_size, PAGE_SIZE); + auto region = SharedBufferRegion::create_with_shbuf_id(address, host_size, shbuf_id, (u8*)host_data); + m_mmu.add_region(move(region)); + m_mmu.copy_to_vm(size_ptr, &host_size, sizeof(host_size)); + return address; +} + +int Emulator::virt$shbuf_allow_pid(int shbuf_id, pid_t peer_pid) +{ + auto* region = m_mmu.shbuf_region(shbuf_id); + ASSERT(region); + return region->allow_pid(peer_pid); +} + +int Emulator::virt$shbuf_allow_all(int shbuf_id) +{ + auto* region = m_mmu.shbuf_region(shbuf_id); + ASSERT(region); + return region->allow_all(); +} + +int Emulator::virt$shbuf_release(int shbuf_id) +{ + auto* region = m_mmu.shbuf_region(shbuf_id); + ASSERT(region); + auto rc = region->release(); + m_mmu.remove_region(*region); + return rc; +} + +int Emulator::virt$shbuf_seal(int shbuf_id) +{ + auto* region = m_mmu.shbuf_region(shbuf_id); + ASSERT(region); + return region->seal(); +} + +int Emulator::virt$shbuf_set_volatile(int shbuf_id, bool is_volatile) +{ + auto* region = m_mmu.shbuf_region(shbuf_id); + ASSERT(region); + return region->set_volatile(is_volatile); +} + int Emulator::virt$fstat(int fd, FlatPtr statbuf) { struct stat local_statbuf; @@ -337,6 +418,12 @@ int Emulator::virt$kill(pid_t pid, int signal) return syscall(SC_kill, pid, signal); } +int Emulator::virt$set_mmap_name(FlatPtr) +{ + // FIXME: Implement. + return 0; +} + int Emulator::virt$get_process_name(FlatPtr buffer, int size) { if (size < 9) @@ -503,27 +590,33 @@ u32 Emulator::virt$munmap(FlatPtr address, u32 size) return 0; } -u32 Emulator::virt$mmap(u32 params_addr) +FlatPtr Emulator::allocate_vm(size_t size, size_t alignment) { - Syscall::SC_mmap_params params; - mmu().copy_from_vm(¶ms, params_addr, sizeof(params)); - - ASSERT(params.addr == 0); - // FIXME: Write a proper VM allocator - static u32 next_address = 0x30000000; + static FlatPtr next_address = 0x30000000; - u32 final_address = 0; - u32 final_size = round_up_to_power_of_two(params.size, PAGE_SIZE); + FlatPtr final_address; - if (params.alignment) { + if (alignment) { // FIXME: What if alignment is not a power of 2? - final_address = round_up_to_power_of_two(next_address, params.alignment); + final_address = round_up_to_power_of_two(next_address, alignment); } else { final_address = next_address; } - next_address = final_address + final_size; + next_address = final_address + size; + return final_address; +} + +u32 Emulator::virt$mmap(u32 params_addr) +{ + Syscall::SC_mmap_params params; + mmu().copy_from_vm(¶ms, params_addr, sizeof(params)); + + ASSERT(params.addr == 0); + + u32 final_size = round_up_to_power_of_two(params.size, PAGE_SIZE); + u32 final_address = allocate_vm(final_size, params.alignment); if (params.flags & MAP_ANONYMOUS) mmu().add_region(MmapRegion::create_anonymous(final_address, final_size, params.prot)); diff --git a/DevTools/UserspaceEmulator/Emulator.h b/DevTools/UserspaceEmulator/Emulator.h index 907c7fe61a..912005c623 100644 --- a/DevTools/UserspaceEmulator/Emulator.h +++ b/DevTools/UserspaceEmulator/Emulator.h @@ -57,6 +57,13 @@ private: void setup_stack(const Vector<String>& arguments); + int virt$shbuf_create(int size, FlatPtr buffer); + int virt$shbuf_allow_pid(int, pid_t peer_pid); + int virt$shbuf_allow_all(int); + FlatPtr virt$shbuf_get(int shbuf_id, FlatPtr size); + int virt$shbuf_release(int shbuf_id); + int virt$shbuf_seal(int shbuf_id); + int virt$shbuf_set_volatile(int shbuf_id, bool); u32 virt$mmap(u32); u32 virt$munmap(FlatPtr address, u32 size); u32 virt$gettid(); @@ -75,6 +82,7 @@ private: int virt$mkdir(FlatPtr path, size_t path_length, mode_t mode); int virt$unlink(FlatPtr path, size_t path_length); int virt$get_process_name(FlatPtr buffer, int size); + int virt$set_mmap_name(FlatPtr); int virt$dbgputstr(FlatPtr characters, int length); int virt$dbgputch(char); int virt$fchmod(int, mode_t); @@ -92,6 +100,8 @@ private: int virt$connect(int sockfd, FlatPtr address, socklen_t address_size); void virt$exit(int); + FlatPtr allocate_vm(size_t size, size_t alignment); + bool m_shutdown { false }; int m_exit_status { 0 }; }; diff --git a/DevTools/UserspaceEmulator/SharedBufferRegion.cpp b/DevTools/UserspaceEmulator/SharedBufferRegion.cpp new file mode 100644 index 0000000000..b21338fbff --- /dev/null +++ b/DevTools/UserspaceEmulator/SharedBufferRegion.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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 "SharedBufferRegion.h" +#include "Emulator.h" +#include <Kernel/API/Syscall.h> +#include <serenity.h> +#include <sys/mman.h> + +namespace UserspaceEmulator { + +NonnullOwnPtr<SharedBufferRegion> SharedBufferRegion::create_with_shbuf_id(u32 base, u32 size, int shbuf_id, u8* host_data) +{ + return adopt_own(*new SharedBufferRegion(base, size, shbuf_id, host_data)); +} + +SharedBufferRegion::SharedBufferRegion(u32 base, u32 size, int shbuf_id, u8* host_data) + : Region(base, size) + , m_data(host_data) + , m_shbuf_id(shbuf_id) +{ +} + +SharedBufferRegion::~SharedBufferRegion() +{ +} + +u8 SharedBufferRegion::read8(FlatPtr offset) +{ + ASSERT(offset < size()); + return *reinterpret_cast<const u8*>(m_data + offset); +} + +u16 SharedBufferRegion::read16(u32 offset) +{ + ASSERT(offset + 1 < size()); + return *reinterpret_cast<const u16*>(m_data + offset); +} + +u32 SharedBufferRegion::read32(u32 offset) +{ + ASSERT(offset + 3 < size()); + return *reinterpret_cast<const u32*>(m_data + offset); +} + +void SharedBufferRegion::write8(u32 offset, u8 value) +{ + ASSERT(offset < size()); + *reinterpret_cast<u8*>(m_data + offset) = value; +} + +void SharedBufferRegion::write16(u32 offset, u16 value) +{ + ASSERT(offset + 1 < size()); + *reinterpret_cast<u16*>(m_data + offset) = value; +} + +void SharedBufferRegion::write32(u32 offset, u32 value) +{ + ASSERT(offset + 3 < size()); + *reinterpret_cast<u32*>(m_data + offset) = value; +} + +int SharedBufferRegion::allow_all() +{ + return syscall(SC_shbuf_allow_all, m_shbuf_id); +} + +int SharedBufferRegion::allow_pid(pid_t pid) +{ + return syscall(SC_shbuf_allow_pid, m_shbuf_id, pid); +} + +int SharedBufferRegion::seal() +{ + return syscall(SC_shbuf_seal, m_shbuf_id); +} + +int SharedBufferRegion::release() +{ + return syscall(SC_shbuf_release, m_shbuf_id); +} + +int SharedBufferRegion::set_volatile(bool is_volatile) +{ + return syscall(SC_shbuf_set_volatile, m_shbuf_id, is_volatile); +} + +} diff --git a/DevTools/UserspaceEmulator/SharedBufferRegion.h b/DevTools/UserspaceEmulator/SharedBufferRegion.h new file mode 100644 index 0000000000..9d27c6d43d --- /dev/null +++ b/DevTools/UserspaceEmulator/SharedBufferRegion.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> + * 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 "SoftMMU.h" +#include <sys/mman.h> + +namespace UserspaceEmulator { + +class SharedBufferRegion final : public SoftMMU::Region { +public: + static NonnullOwnPtr<SharedBufferRegion> create_with_shbuf_id(u32 base, u32 size, int shbuf_id, u8* shbuf_data); + virtual ~SharedBufferRegion() override; + + virtual u8 read8(u32 offset) override; + virtual u16 read16(u32 offset) override; + virtual u32 read32(u32 offset) override; + + virtual void write8(u32 offset, u8 value) override; + virtual void write16(u32 offset, u16 value) override; + virtual void write32(u32 offset, u32 value) override; + + u8* data() { return m_data; } + + bool is_shared_buffer() const override { return true; } + + int shbuf_id() const { return m_shbuf_id; } + + int allow_all(); + int allow_pid(pid_t); + int seal(); + int release(); + int set_volatile(bool); + +private: + SharedBufferRegion(u32 base, u32 size, int shbuf_id, u8* shbuf_data); + + u8* m_data { nullptr }; + int m_shbuf_id { 0 }; +}; + +} diff --git a/DevTools/UserspaceEmulator/SoftMMU.cpp b/DevTools/UserspaceEmulator/SoftMMU.cpp index b2ef013a05..4015e7ee16 100644 --- a/DevTools/UserspaceEmulator/SoftMMU.cpp +++ b/DevTools/UserspaceEmulator/SoftMMU.cpp @@ -25,6 +25,7 @@ */ #include "SoftMMU.h" +#include "SharedBufferRegion.h" #include <AK/ByteBuffer.h> namespace UserspaceEmulator { @@ -45,11 +46,15 @@ void SoftMMU::add_region(NonnullOwnPtr<Region> region) { ASSERT(!find_region({ 0x20, region->base() })); // FIXME: More sanity checks pls + if (region->is_shared_buffer()) + m_shbuf_regions.set(static_cast<SharedBufferRegion*>(region.ptr())->shbuf_id(), region.ptr()); m_regions.append(move(region)); } void SoftMMU::remove_region(Region& region) { + if (region.is_shared_buffer()) + m_shbuf_regions.remove(static_cast<SharedBufferRegion&>(region).shbuf_id()); m_regions.remove_first_matching([&](auto& entry) { return entry.ptr() == ®ion; }); } @@ -144,4 +149,9 @@ ByteBuffer SoftMMU::copy_buffer_from_vm(const FlatPtr source, size_t size) return buffer; } +SharedBufferRegion* SoftMMU::shbuf_region(int shbuf_id) +{ + return (SharedBufferRegion*)m_shbuf_regions.get(shbuf_id).value_or(nullptr); +} + } diff --git a/DevTools/UserspaceEmulator/SoftMMU.h b/DevTools/UserspaceEmulator/SoftMMU.h index 9d34cf2883..5d154c4b30 100644 --- a/DevTools/UserspaceEmulator/SoftMMU.h +++ b/DevTools/UserspaceEmulator/SoftMMU.h @@ -26,6 +26,7 @@ #pragma once +#include <AK/HashMap.h> #include <AK/NonnullOwnPtrVector.h> #include <AK/OwnPtr.h> #include <AK/Types.h> @@ -33,6 +34,8 @@ namespace UserspaceEmulator { +class SharedBufferRegion; + class SoftMMU { public: class Region { @@ -54,6 +57,7 @@ public: virtual u32 read32(u32 offset) = 0; virtual u8* cacheable_ptr([[maybe_unused]] u32 offset) { return nullptr; } + virtual bool is_shared_buffer() const { return false; } protected: Region(u32 base, u32 size) @@ -86,9 +90,12 @@ public: void copy_from_vm(void* destination, const FlatPtr source, size_t); ByteBuffer copy_buffer_from_vm(const FlatPtr source, size_t); + SharedBufferRegion* shbuf_region(int shbuf_id); + private: OwnPtr<Region> m_tls_region; NonnullOwnPtrVector<Region> m_regions; + HashMap<int, Region*> m_shbuf_regions; }; } |