1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <dispatcher-pool/dispatcher-channel.h> 6#include <dispatcher-pool/dispatcher-execution-domain.h> 7#include <ddk/binding.h> 8#include <ddk/driver.h> 9#include <intel-hda/utils/intel-hda-registers.h> 10#include <fbl/algorithm.h> 11#include <fbl/alloc_checker.h> 12#include <string.h> 13#include <zircon/assert.h> 14#include <zircon/device/intel-hda.h> 15#include <zircon/process.h> 16#include <lib/zx/channel.h> 17 18#include "debug-logging.h" 19#include "utils.h" 20 21namespace audio { 22namespace intel_hda { 23 24fbl::RefPtr<fzl::VmarManager> DriverVmars::registers_; 25 26zx_status_t DriverVmars::Initialize() { 27 if (registers_ != nullptr) { 28 return ZX_ERR_BAD_STATE; 29 } 30 31 // Create a compact VMAR to map all of our registers into. 32 // 33 // TODO(johngro): See ZX-1822 for details. 34 // 35 // Sizing right now is a bit of a guessing game. A compact VMAR is not 36 // going to perfectly tightly pack everything; it will still insert random 37 // gaps in an attempt to get some minimum level of ASLR. For now, I'm using 38 // hardcoded guidance from teisenbe@ about how to size for the worst case. 39 // If/when there is a better way of doing this, I need to come back and 40 // switch to that. 41 // 42 // Formula being used here should be... 43 // 2 * (total_region_size + (512k * (total_allocations - 1))) 44 constexpr size_t MAX_SIZE_PER_CONTROLLER = 45 sizeof(hda_all_registers_t) + 46 MAPPED_CORB_RIRB_SIZE + 47 (MAX_STREAMS_PER_CONTROLLER * MAPPED_BDL_SIZE) + 48 sizeof(adsp_registers_t) + 49 MAPPED_BDL_SIZE; 50 51 // One alloc for the main registers, one for code loader BDL. 52 constexpr size_t MAX_ALLOCS_PER_DSP = 2; 53 // One alloc for the main registers, one for the CORB/RIRB, two for DSP, 54 // and one for each possible stream BDL. 55 constexpr size_t MAX_ALLOCS_PER_CONTROLLER = 2 + MAX_ALLOCS_PER_DSP + 56 MAX_STREAMS_PER_CONTROLLER; 57 constexpr size_t MAX_CONTROLLERS = 4; 58 constexpr size_t VMAR_SIZE = 2 * 59 ((MAX_CONTROLLERS * MAX_SIZE_PER_CONTROLLER) + 60 (((MAX_CONTROLLERS * MAX_ALLOCS_PER_CONTROLLER) - 1) * (512u << 10))); 61 62 GLOBAL_LOG(TRACE, "Allocating 0x%zx byte VMAR for registers.\n", VMAR_SIZE); 63 registers_ = fzl::VmarManager::Create(VMAR_SIZE); 64 if (registers_ == nullptr) { 65 return ZX_ERR_NO_MEMORY; 66 } 67 68 return ZX_OK; 69} 70 71void DriverVmars::Shutdown() { 72 registers_.reset(); 73} 74 75zx_status_t HandleDeviceIoctl(uint32_t op, 76 void* out_buf, 77 size_t out_len, 78 size_t* out_actual, 79 const fbl::RefPtr<dispatcher::ExecutionDomain>& domain, 80 dispatcher::Channel::ProcessHandler phandler, 81 dispatcher::Channel::ChannelClosedHandler chandler) { 82 if (op != IHDA_IOCTL_GET_CHANNEL) { 83 return ZX_ERR_NOT_SUPPORTED; 84 } 85 86 if ((out_buf == nullptr) || 87 (out_actual == nullptr) || 88 (out_len != sizeof(zx_handle_t))) { 89 return ZX_ERR_INVALID_ARGS; 90 } 91 92 zx::channel remote_endpoint_out; 93 zx_status_t res = CreateAndActivateChannel(domain, 94 fbl::move(phandler), 95 fbl::move(chandler), 96 nullptr, 97 &remote_endpoint_out); 98 if (res == ZX_OK) { 99 *(reinterpret_cast<zx_handle_t*>(out_buf)) = remote_endpoint_out.release(); 100 *out_actual = sizeof(zx_handle_t); 101 } 102 103 return res; 104} 105 106zx_status_t CreateAndActivateChannel(const fbl::RefPtr<dispatcher::ExecutionDomain>& domain, 107 dispatcher::Channel::ProcessHandler phandler, 108 dispatcher::Channel::ChannelClosedHandler chandler, 109 fbl::RefPtr<dispatcher::Channel>* local_endpoint_out, 110 zx::channel* remote_endpoint_out) { 111 if (remote_endpoint_out == nullptr) { 112 return ZX_ERR_INVALID_ARGS; 113 } 114 115 auto channel = dispatcher::Channel::Create(); 116 if (channel == nullptr) { 117 return ZX_ERR_NO_MEMORY; 118 } 119 120 zx_status_t res = channel->Activate(remote_endpoint_out, 121 domain, 122 fbl::move(phandler), 123 fbl::move(chandler)); 124 if ((res == ZX_OK) && (local_endpoint_out != nullptr)) { 125 *local_endpoint_out = fbl::move(channel); 126 } 127 128 return res; 129} 130 131} // namespace intel_hda 132} // namespace audio 133