blob: 32dbb935afc8a3322caf971708702f4456f99f2a [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "utils.h"
#include <lib/zx/channel.h>
#include <string.h>
#include <zircon/assert.h>
#include <zircon/device/intel-hda.h>
#include <zircon/process.h>
#include <utility>
#include <ddk/binding.h>
#include <ddk/driver.h>
#include <dispatcher-pool/dispatcher-channel.h>
#include <dispatcher-pool/dispatcher-execution-domain.h>
#include <fbl/algorithm.h>
#include <fbl/alloc_checker.h>
#include <intel-hda/utils/intel-hda-registers.h>
#include "debug-logging.h"
namespace audio {
namespace intel_hda {
fbl::RefPtr<fzl::VmarManager> CreateDriverVmars() {
// Create a compact VMAR to map all of our registers into.
//
// TODO(johngro): See ZX-1822 for details.
//
// Sizing right now is a bit of a guessing game. A compact VMAR is not
// going to perfectly tightly pack everything; it will still insert random
// gaps in an attempt to get some minimum level of ASLR. For now, I'm using
// hardcoded guidance from teisenbe@ about how to size for the worst case.
// If/when there is a better way of doing this, I need to come back and
// switch to that.
//
// Formula being used here should be...
// 2 * (total_region_size + (512k * (total_allocations - 1)))
constexpr size_t MAX_SIZE_PER_CONTROLLER = sizeof(hda_all_registers_t) + MAPPED_CORB_RIRB_SIZE +
(MAX_STREAMS_PER_CONTROLLER * MAPPED_BDL_SIZE) +
sizeof(adsp_registers_t) + MAPPED_BDL_SIZE;
// One alloc for the main registers, one for code loader BDL.
constexpr size_t MAX_ALLOCS_PER_DSP = 2;
// One alloc for the main registers, one for the CORB/RIRB, two for DSP,
// and one for each possible stream BDL.
constexpr size_t MAX_ALLOCS_PER_CONTROLLER = 2 + MAX_ALLOCS_PER_DSP + MAX_STREAMS_PER_CONTROLLER;
constexpr size_t VMAR_SIZE =
2 * (MAX_SIZE_PER_CONTROLLER + ((MAX_ALLOCS_PER_CONTROLLER - 1) * (512u << 10)));
GLOBAL_LOG(DEBUG, "Allocating 0x%zx byte VMAR for registers.\n", VMAR_SIZE);
return fzl::VmarManager::Create(VMAR_SIZE);
}
zx_status_t CreateAndActivateChannel(const fbl::RefPtr<dispatcher::ExecutionDomain>& domain,
dispatcher::Channel::ProcessHandler phandler,
dispatcher::Channel::ChannelClosedHandler chandler,
fbl::RefPtr<dispatcher::Channel>* local_endpoint_out,
zx::channel* remote_endpoint_out) {
if (remote_endpoint_out == nullptr) {
return ZX_ERR_INVALID_ARGS;
}
auto channel = dispatcher::Channel::Create();
if (channel == nullptr) {
return ZX_ERR_NO_MEMORY;
}
zx_status_t res =
channel->Activate(remote_endpoint_out, domain, std::move(phandler), std::move(chandler));
if ((res == ZX_OK) && (local_endpoint_out != nullptr)) {
*local_endpoint_out = std::move(channel);
}
return res;
}
} // namespace intel_hda
} // namespace audio