| // Copyright 2018 The Fuchsia Authors |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #ifndef ZIRCON_KERNEL_LIB_UNITTEST_INCLUDE_LIB_UNITTEST_USER_MEMORY_H_ |
| #define ZIRCON_KERNEL_LIB_UNITTEST_INCLUDE_LIB_UNITTEST_USER_MEMORY_H_ |
| |
| #include <lib/user_copy/user_ptr.h> |
| |
| #include <ktl/move.h> |
| #include <ktl/unique_ptr.h> |
| #include <vm/pmm.h> |
| #include <vm/scanner.h> |
| #include <vm/vm.h> |
| #include <vm/vm_address_region.h> |
| #include <vm/vm_aspace.h> |
| #include <vm/vm_object_paged.h> |
| |
| namespace testing { |
| |
| // UserMemory facilitates testing code that requires user memory. |
| // |
| // Example: |
| // unique_ptr<UserMemory> mem = UserMemory::Create(sizeof(thing)); |
| // auto mem_out = make_user_out_ptr(mem->out()); |
| // mem_out.copy_array_to_user(&thing, sizeof(thing)); |
| // |
| class UserMemory { |
| public: |
| static ktl::unique_ptr<UserMemory> Create(size_t size); |
| static ktl::unique_ptr<UserMemory> Create(fbl::RefPtr<VmObject> vmo); |
| virtual ~UserMemory(); |
| |
| vaddr_t base() const { return mapping_->base(); } |
| |
| const fbl::RefPtr<VmObject>& vmo() const { return vmo_; } |
| |
| const fbl::RefPtr<VmAspace>& aspace() const { return mapping_->aspace(); } |
| |
| template <typename T> |
| void put(const T& value, size_t i = 0) { |
| zx_status_t status = user_out<T>().element_offset(i).copy_to_user(value); |
| ASSERT(status == ZX_OK); |
| } |
| |
| template <typename T> |
| T get(size_t i = 0) { |
| T value; |
| zx_status_t status = user_in<T>().element_offset(i).copy_from_user(&value); |
| ASSERT(status == ZX_OK); |
| return value; |
| } |
| |
| template <typename T> |
| user_out_ptr<T> user_out() { |
| return make_user_out_ptr(reinterpret_cast<T*>(base())); |
| } |
| |
| template <typename T> |
| user_in_ptr<const T> user_in() { |
| return make_user_in_ptr(reinterpret_cast<const T*>(base())); |
| } |
| |
| // Ensures the mapping is committed and mapped such that usages will cause no faults. |
| zx_status_t CommitAndMap(size_t size, uint64_t offset = 0) { |
| return mapping_->MapRange(offset, size, true); |
| } |
| |
| // Read or write to the underlying VMO directly, bypassing the mapping. |
| zx_status_t VmoRead(void* ptr, uint64_t offset, uint64_t len) { |
| ASSERT(vmo_); |
| return vmo_->Read(ptr, offset, len); |
| } |
| zx_status_t VmoWrite(const void* ptr, uint64_t offset, uint64_t len) { |
| ASSERT(vmo_); |
| return vmo_->Write(ptr, offset, len); |
| } |
| |
| private: |
| UserMemory(fbl::RefPtr<VmMapping> mapping, fbl::RefPtr<VmObject> vmo) |
| : mapping_(ktl::move(mapping)), vmo_(ktl::move(vmo)) {} |
| |
| fbl::RefPtr<VmMapping> mapping_; |
| fbl::RefPtr<VmObject> vmo_; |
| |
| // User memory here is going to be touched directly by the kernel and will not have the option to |
| // fault in memory that should get reclaimed by the scanner. Therefore as long as we are using any |
| // UserMemory we should disable the scanner. |
| AutoVmScannerDisable scanner_disable_; |
| }; |
| |
| } // namespace testing |
| |
| #endif // ZIRCON_KERNEL_LIB_UNITTEST_INCLUDE_LIB_UNITTEST_USER_MEMORY_H_ |