blob: 74f4a508a430707c8d67ca41be13c8cbdb4bbd84 [file] [log] [blame]
// Copyright 2016 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
#include <lib/rodso.h>
#include <inttypes.h>
#include <vm/vm_address_region.h>
#include <vm/vm_aspace.h>
#include <vm/vm_object.h>
#include <vm/vm_object_paged.h>
#include <object/handle.h>
#include <object/vm_address_region_dispatcher.h>
#include <object/vm_object_dispatcher.h>
RoDso::RoDso(const char* name, const void* image, size_t size,
uintptr_t code_start)
: name_(name), code_start_(code_start), size_(size) {
DEBUG_ASSERT(IS_PAGE_ALIGNED(size));
DEBUG_ASSERT(IS_PAGE_ALIGNED(code_start));
DEBUG_ASSERT(code_start > 0);
DEBUG_ASSERT(code_start < size);
fbl::RefPtr<Dispatcher> dispatcher;
// create vmo out of ro data mapped in kernel space
fbl::RefPtr<VmObject> vmo;
zx_status_t status = VmObjectPaged::CreateFromWiredPages(image, size, true, &vmo);
ASSERT(status == ZX_OK);
// build and point a dispatcher at it
status = VmObjectDispatcher::Create(
ktl::move(vmo),
&dispatcher, &vmo_rights_);
ASSERT(status == ZX_OK);
status = dispatcher->set_name(name, strlen(name));
ASSERT(status == ZX_OK);
vmo_ = DownCastDispatcher<VmObjectDispatcher>(&dispatcher);
vmo_rights_ &= ~ZX_RIGHT_WRITE;
vmo_rights_ |= ZX_RIGHT_EXECUTE;
}
HandleOwner RoDso::vmo_handle() const {
return Handle::Make(vmo_, vmo_rights_);
}
// Map one segment from our VM object.
zx_status_t RoDso::MapSegment(fbl::RefPtr<VmAddressRegionDispatcher> vmar,
bool code,
size_t vmar_offset,
size_t start_offset,
size_t end_offset) const {
uint32_t flags = ZX_VM_SPECIFIC | ZX_VM_PERM_READ;
if (code)
flags |= ZX_VM_PERM_EXECUTE;
size_t len = end_offset - start_offset;
fbl::RefPtr<VmMapping> mapping;
zx_status_t status = vmar->Map(vmar_offset, vmo_->vmo(),
start_offset, len, flags, &mapping);
const char* segment_name = code ? "code" : "rodata";
if (status != ZX_OK) {
dprintf(CRITICAL,
"userboot: %s %s mapping %#zx @ %#" PRIxPTR
" size %#zx failed %d\n",
name_, segment_name, start_offset,
vmar->vmar()->base() + vmar_offset, len, status);
} else {
DEBUG_ASSERT(mapping->base() == vmar->vmar()->base() + vmar_offset);
dprintf(SPEW, "userboot: %-8s %-6s %#7zx @ [%#" PRIxPTR
",%#" PRIxPTR ")\n", name_, segment_name, start_offset,
mapping->base(), mapping->base() + len);
}
return status;
}
zx_status_t RoDso::Map(fbl::RefPtr<VmAddressRegionDispatcher> vmar,
size_t offset) const {
zx_status_t status = MapSegment(vmar, false, offset, 0, code_start_);
if (status == ZX_OK)
status = MapSegment(ktl::move(vmar), true,
offset + code_start_, code_start_, size_);
return status;
}