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 <object/resource_dispatcher.h> 8 9#include <fbl/alloc_checker.h> 10#include <inttypes.h> 11#include <kernel/auto_lock.h> 12#include <kernel/range_check.h> 13#include <lib/counters.h> 14#include <pretty/sizes.h> 15#include <string.h> 16#include <trace.h> 17#include <vm/vm.h> 18#include <zircon/rights.h> 19#include <zircon/syscalls/resource.h> 20 21#define LOCAL_TRACE 0 22 23KCOUNTER(root_resource_created, "resource.root.created"); 24KCOUNTER(hypervisor_resource_created, "resource.hypervisor.created"); 25KCOUNTER(vmex_resource_created, "resource.vmex.created"); 26KCOUNTER(mmio_resource_created, "resource.mmio.created"); 27KCOUNTER(irq_resource_created, "resource.irq.created"); 28KCOUNTER(ioport_resource_created, "resource.ioport.created"); 29 30// Storage for static members of ResourceDispatcher 31RegionAllocator ResourceDispatcher::static_rallocs_[ZX_RSRC_KIND_COUNT]; 32ResourceDispatcher::ResourceList ResourceDispatcher::static_resource_list_; 33RegionAllocator::RegionPool::RefPtr ResourceDispatcher::region_pool_; 34const char* kLogTag = "Resources:"; 35 36zx_status_t ResourceDispatcher::Create(fbl::RefPtr<ResourceDispatcher>* dispatcher, 37 zx_rights_t* rights, 38 uint32_t kind, 39 uint64_t base, 40 size_t size, 41 uint32_t flags, 42 const char name[ZX_MAX_NAME_LEN], 43 RegionAllocator rallocs[ZX_RSRC_KIND_COUNT], 44 ResourceList* resource_list) { 45 Guard<fbl::Mutex> guard{ResourcesLock::Get()}; 46 if (kind >= ZX_RSRC_KIND_COUNT || (flags & ZX_RSRC_FLAGS_MASK) != flags) { 47 return ZX_ERR_INVALID_ARGS; 48 } 49 50 // The first thing we need to do for any resource is ensure that it has not 51 // been exclusively reserved. If GetRegion succeeds and we have a region 52 // uptr then in the case of an exclusive resource we'll move it into the 53 // class instance. Otherwise, the resource is shared and we'll release it 54 // back to the allocator since we only used it to verify it existed in the 55 // allocator. 56 // 57 // TODO: Hypervisor resources should be represented in some other capability 58 // object because they represent a binary permission rather than anything 59 // more finely grained. It will work properly here because the base/size of a 60 // hypervisor resource is never checked, but it's a workaround until a 61 // proper capability exists for it. 62 zx_status_t status; 63 RegionAllocator::Region::UPtr region_uptr = nullptr; 64 switch (kind) { 65 case ZX_RSRC_KIND_ROOT: 66 case ZX_RSRC_KIND_HYPERVISOR: 67 case ZX_RSRC_KIND_VMEX: 68 // It does not make sense for an abstract resource type to have a base/size tuple 69 if (base || size) { 70 return ZX_ERR_INVALID_ARGS; 71 } 72 break; 73 default: 74 status = rallocs[kind].GetRegion({.base = base, .size = size}, region_uptr); 75 if (status != ZX_OK) { 76 LTRACEF("%s couldn't pull the resource out of the ralloc %d\n", kLogTag, status); 77 return status; 78 } 79 } 80 81 // If the allocation is exclusive then a check needs to be made to ensure 82 // that no shared allocation already exists and/or overlaps. Shared 83 // resources don't need to do so because grabbing the exclusive region above 84 // (temporarily) ensures they are valid allocations. If this check fails 85 // then the region above will be released back to the pool anyway. 86 if (flags & ZX_RSRC_FLAG_EXCLUSIVE) { 87 auto callback = [&](const ResourceDispatcher& rsrc) { 88 LTRACEF("%s walking resources, found [%u, %#lx, %zu]\n", kLogTag, rsrc.get_kind(), 89 rsrc.get_base(), rsrc.get_size()); 90 if (kind != rsrc.get_kind()) { 91 return ZX_OK; 92 } 93 94 if (Intersects(base, size, rsrc.get_base(), rsrc.get_size())) { 95 LTRACEF("%s [%#lx, %zu] intersects with [%#lx, %zu] found in list!\n", kLogTag, 96 base, size, rsrc.get_base(), rsrc.get_size()); 97 return ZX_ERR_NOT_FOUND; 98 } 99 100 return ZX_OK; 101 }; 102 LTRACEF("%s scanning resource list for [%u, %#lx, %zu]\n", kLogTag, kind, base, size); 103 zx_status_t status = ResourceDispatcher::ForEachResourceLocked(callback, resource_list); 104 if (status != ZX_OK) { 105 return status; 106 } 107 } 108 109 // We've passd the first hurdle, so it's time to construct the dispatcher 110 // itself. The constructor will handle adding itself to the shared list if 111 // necessary. 112 fbl::AllocChecker ac; 113 auto disp = fbl::AdoptRef(new (&ac) ResourceDispatcher(kind, base, size, flags, 114 fbl::move(region_uptr), 115 rallocs, resource_list)); 116 if (!ac.check()) { 117 return ZX_ERR_NO_MEMORY; 118 } 119 120 if (name != nullptr) { 121 disp->set_name(name, ZX_MAX_NAME_LEN); 122 } 123 124 *rights = ZX_DEFAULT_RESOURCE_RIGHTS; 125 *dispatcher = fbl::move(disp); 126 127 LTRACEF("%s [%u, %#lx, %zu] resource created.\n", kLogTag, kind, base, size); 128 return ZX_OK; 129} 130 131ResourceDispatcher::ResourceDispatcher(uint32_t kind, 132 uint64_t base, 133 uint64_t size, 134 uint32_t flags, 135 RegionAllocator::Region::UPtr&& region, 136 RegionAllocator rallocs[ZX_RSRC_KIND_COUNT], 137 ResourceList* resource_list) 138 : kind_(kind), base_(base), size_(size), flags_(flags), 139 resource_list_(resource_list) { 140 if (flags_ & ZX_RSRC_FLAG_EXCLUSIVE) { 141 exclusive_region_ = fbl::move(region); 142 } 143 144 switch (kind_) { 145 case ZX_RSRC_KIND_ROOT: 146 kcounter_add(root_resource_created, 1); 147 break; 148 case ZX_RSRC_KIND_HYPERVISOR: 149 kcounter_add(hypervisor_resource_created, 1); 150 break; 151 case ZX_RSRC_KIND_VMEX: 152 kcounter_add(vmex_resource_created, 1); 153 break; 154 case ZX_RSRC_KIND_MMIO: 155 kcounter_add(mmio_resource_created, 1); 156 break; 157 case ZX_RSRC_KIND_IRQ: 158 kcounter_add(irq_resource_created, 1); 159 break; 160 case ZX_RSRC_KIND_IOPORT: 161 kcounter_add(ioport_resource_created, 1); 162 break; 163 } 164 resource_list_->push_back(this); 165} 166 167ResourceDispatcher::~ResourceDispatcher() { 168 // exclusive allocations will be released when the uptr goes out of scope, 169 // shared need to be removed from |all_shared_list_| 170 Guard<fbl::Mutex> guard{ResourcesLock::Get()}; 171 char name[ZX_MAX_NAME_LEN]; 172 get_name(name); 173 resource_list_->erase(*this); 174} 175 176zx_status_t ResourceDispatcher::InitializeAllocator(uint32_t kind, 177 uint64_t base, 178 size_t size, 179 RegionAllocator rallocs[ZX_RSRC_KIND_COUNT]) { 180 DEBUG_ASSERT(kind < ZX_RSRC_KIND_COUNT); 181 DEBUG_ASSERT(size > 0); 182 183 Guard<fbl::Mutex> guard{ResourcesLock::Get()}; 184 zx_status_t status; 185 186 // This method should only be called for resource kinds with bookkeeping. 187 if (kind >= ZX_RSRC_KIND_COUNT) { 188 return ZX_ERR_INVALID_ARGS; 189 } 190 191 // Create the initial region pool if necessary. Its storage is allocated in this cpp file 192 if (region_pool_ == nullptr) { 193 region_pool_ = RegionAllocator::RegionPool::Create(kMaxRegionPoolSize); 194 } 195 196 // Failure to allocate this early in boot is a critical error 197 DEBUG_ASSERT(region_pool_); 198 199 status = rallocs[kind].SetRegionPool(region_pool_); 200 if (status != ZX_OK) { 201 return status; 202 } 203 204 // Add the initial address space specified by the platform to the region allocator. 205 // This will be used for verifying both shared and exclusive allocations of address 206 // space. 207 status = rallocs[kind].AddRegion({.base = base, .size = size}); 208 LTRACEF("%s added [%#lx, %zu] to kind %u in allocator %p: %d\n", 209 kLogTag, base, size, kind, rallocs, status); 210 return status; 211} 212 213// Size specifiers for the debug output 214constexpr int kTypeLen = 10; 215constexpr int kFlagLen = 6; 216constexpr int kNameLen = ZX_MAX_NAME_LEN - 1; 217constexpr int kNumLen = 16; 218constexpr int kPrettyLen = 8; 219 220// Utility function to format the flags into a user-readable string. 221static constexpr void flags_to_string(uint32_t flags, char str[kFlagLen]) { 222 str[0] = ' '; 223 str[1] = ' '; 224 str[2] = ' '; 225 str[3] = (flags & ZX_RSRC_FLAG_EXCLUSIVE) ? ' ' : 's'; 226 str[4] = (flags & ZX_RSRC_FLAG_EXCLUSIVE) ? 'x' : ' '; 227 str[5] = '\0'; 228} 229 230static void pad_field(int width) { 231 printf("\t%.*s", width, " "); 232} 233 234void ResourceDispatcher::Dump() { 235 uint32_t kind; 236 auto callback = [&](const ResourceDispatcher& r) -> zx_status_t { 237 char name[ZX_MAX_NAME_LEN]; 238 char flag_str[kFlagLen]; 239 char pretty_size[kPrettyLen]; 240 241 // exit early so we can print the list in a grouped format 242 // without adding overhead to the list management. 243 if (r.get_kind() != kind) { 244 return ZX_OK; 245 } 246 247 // A safety check to make sure we don't need to worry about snprintf edge cases 248 r.get_name(name); 249 flags_to_string(r.get_flags(), flag_str); 250 251 // IRQs are allocated one at a time, so range display doesn't make much sense. 252 switch (r.get_kind()) { 253 case ZX_RSRC_KIND_ROOT: 254 printf("%.*s", kTypeLen, "root"); 255 pad_field(kFlagLen); // Root has no flags 256 printf("\t%.*s", kNameLen, name); 257 printf("\n"); 258 break; 259 case ZX_RSRC_KIND_HYPERVISOR: 260 printf("%.*s", kTypeLen, "hypervisor"); 261 printf("\t%.*s", kFlagLen, flag_str); 262 printf("\t%.*s", kNameLen, name); 263 printf("\n"); 264 break; 265 case ZX_RSRC_KIND_IRQ: 266 printf("%.*s", kTypeLen, "irq"); 267 printf("\t%.*s", kFlagLen, flag_str); 268 printf("\t%.*s", kNameLen, name); 269 printf("\t%#.*" PRIxPTR, kNumLen, r.get_base()); 270 printf("\n"); 271 break; 272 case ZX_RSRC_KIND_IOPORT: 273 printf("%.*s", kTypeLen, "io"); 274 printf("\t%.*s", kFlagLen, flag_str); 275 printf("\t%.*s", kNameLen, name); 276 printf("\t%#.*" PRIxPTR, kNumLen, r.get_base()); 277 printf("\t%#.*" PRIxPTR, kNumLen, r.get_base() + r.get_size()); 278 printf("\t%.*s", kPrettyLen, 279 format_size(pretty_size, sizeof(pretty_size), r.get_size())); 280 printf("\n"); 281 break; 282 case ZX_RSRC_KIND_MMIO: 283 printf("%.*s", kTypeLen, "mmio"); 284 printf("\t%.*s", kFlagLen, flag_str); 285 printf("\t%.*s", kNameLen, name); 286 printf("\t%#.*" PRIxPTR, kNumLen, r.get_base()); 287 printf("\t%#.*" PRIxPTR, kNumLen, r.get_base() + r.get_size()); 288 printf("\t%.*s", kPrettyLen, 289 format_size(pretty_size, sizeof(pretty_size), r.get_size())); 290 printf("\n"); 291 break; 292 } 293 294 return ZX_OK; 295 }; 296 297 printf("%10s\t%4s\t%31s\t%16s\t%16s\t%8s\n\n", "type", "flags", "name", "start", "end", "size"); 298 for (kind = 0; kind < ZX_RSRC_KIND_COUNT; kind++) { 299 ResourceDispatcher::ForEachResource(callback); 300 } 301} 302 303#include <lib/console.h> 304 305static int cmd_resources(int argc, const cmd_args* argv, uint32_t flags) { 306 ResourceDispatcher::Dump(); 307 return true; 308} 309 310STATIC_COMMAND_START 311STATIC_COMMAND("resource", "Inspect physical address space resource allocations", &cmd_resources) 312STATIC_COMMAND_END(resources); 313