blob: ed13fca23c6ad62682114659eb1d830a389734c0 [file] [log] [blame]
// 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_