1// Copyright 2016 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <lib/rodso.h> 8 9#include <inttypes.h> 10#include <vm/vm_address_region.h> 11#include <vm/vm_aspace.h> 12#include <vm/vm_object.h> 13#include <vm/vm_object_paged.h> 14#include <object/handle.h> 15#include <object/vm_address_region_dispatcher.h> 16#include <object/vm_object_dispatcher.h> 17 18RoDso::RoDso(const char* name, const void* image, size_t size, 19 uintptr_t code_start) 20 : name_(name), code_start_(code_start), size_(size) { 21 DEBUG_ASSERT(IS_PAGE_ALIGNED(size)); 22 DEBUG_ASSERT(IS_PAGE_ALIGNED(code_start)); 23 DEBUG_ASSERT(code_start > 0); 24 DEBUG_ASSERT(code_start < size); 25 fbl::RefPtr<Dispatcher> dispatcher; 26 27 // create vmo out of ro data mapped in kernel space 28 fbl::RefPtr<VmObject> vmo; 29 zx_status_t status = VmObjectPaged::CreateFromROData(image, size, &vmo); 30 ASSERT(status == ZX_OK); 31 32 // build and point a dispatcher at it 33 status = VmObjectDispatcher::Create( 34 fbl::move(vmo), 35 &dispatcher, &vmo_rights_); 36 ASSERT(status == ZX_OK); 37 38 status = dispatcher->set_name(name, strlen(name)); 39 ASSERT(status == ZX_OK); 40 vmo_ = DownCastDispatcher<VmObjectDispatcher>(&dispatcher); 41 vmo_rights_ &= ~ZX_RIGHT_WRITE; 42 43 // unmap it from the kernel 44 // NOTE: this means the image can no longer be referenced from original pointer 45 status = VmAspace::kernel_aspace()->arch_aspace().Unmap( 46 reinterpret_cast<vaddr_t>(image), 47 size / PAGE_SIZE, nullptr); 48 ASSERT(status == ZX_OK); 49} 50 51HandleOwner RoDso::vmo_handle() const { 52 return Handle::Make(vmo_, vmo_rights_); 53} 54 55// Map one segment from our VM object. 56zx_status_t RoDso::MapSegment(fbl::RefPtr<VmAddressRegionDispatcher> vmar, 57 bool code, 58 size_t vmar_offset, 59 size_t start_offset, 60 size_t end_offset) const { 61 62 uint32_t flags = ZX_VM_SPECIFIC | ZX_VM_PERM_READ; 63 if (code) 64 flags |= ZX_VM_PERM_EXECUTE; 65 66 size_t len = end_offset - start_offset; 67 68 fbl::RefPtr<VmMapping> mapping; 69 zx_status_t status = vmar->Map(vmar_offset, vmo_->vmo(), 70 start_offset, len, flags, &mapping); 71 72 const char* segment_name = code ? "code" : "rodata"; 73 if (status != ZX_OK) { 74 dprintf(CRITICAL, 75 "userboot: %s %s mapping %#zx @ %#" PRIxPTR 76 " size %#zx failed %d\n", 77 name_, segment_name, start_offset, 78 vmar->vmar()->base() + vmar_offset, len, status); 79 } else { 80 DEBUG_ASSERT(mapping->base() == vmar->vmar()->base() + vmar_offset); 81 dprintf(SPEW, "userboot: %-8s %-6s %#7zx @ [%#" PRIxPTR 82 ",%#" PRIxPTR ")\n", name_, segment_name, start_offset, 83 mapping->base(), mapping->base() + len); 84 } 85 86 return status; 87} 88 89zx_status_t RoDso::Map(fbl::RefPtr<VmAddressRegionDispatcher> vmar, 90 size_t offset) const { 91 zx_status_t status = MapSegment(vmar, false, offset, 0, code_start_); 92 if (status == ZX_OK) 93 status = MapSegment(fbl::move(vmar), true, 94 offset + code_start_, code_start_, size_); 95 return status; 96} 97