774 lines
27 KiB
C++
774 lines
27 KiB
C++
/*
|
|
* Copyright (C) 2023 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
|
|
#include "chre/core/event_loop_manager.h"
|
|
#include "chre/core/host_comms_manager.h"
|
|
#include "chre/platform/host_link.h"
|
|
#include "chre/platform/log.h"
|
|
#include "chre/platform/shared/host_protocol_chre.h"
|
|
#include "chre/platform/shared/log_buffer_manager.h"
|
|
#include "chre/platform/shared/nanoapp_load_manager.h"
|
|
#include "chre/platform/system_time.h"
|
|
#include "chre/platform/system_timer.h"
|
|
#include "chre/util/flatbuffers/helpers.h"
|
|
#include "chre/util/nested_data_ptr.h"
|
|
|
|
#include "dma_api.h"
|
|
#include "ipi.h"
|
|
#include "ipi_id.h"
|
|
#include "resource_req.h"
|
|
#include "scp_dram_region.h"
|
|
|
|
// Because the LOGx macros are being redirected to logcat through
|
|
// HostLink::sendLogMessageV2 and HostLink::send, calling them from
|
|
// inside HostLink impl could result in endless recursion.
|
|
// So redefine them to just printf function to SCP console.
|
|
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_ERROR
|
|
#undef LOGE
|
|
#define LOGE(fmt, arg...) PRINTF_E("[CHRE]" fmt "\n", ##arg)
|
|
#endif
|
|
|
|
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_WARN
|
|
#undef LOGW
|
|
#define LOGW(fmt, arg...) PRINTF_W("[CHRE]" fmt "\n", ##arg)
|
|
#endif
|
|
|
|
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_INFO
|
|
#undef LOGI
|
|
#define LOGI(fmt, arg...) PRINTF_I("[CHRE]" fmt "\n", ##arg)
|
|
#endif
|
|
|
|
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_DEBUG
|
|
#undef LOGD
|
|
#define LOGD(fmt, arg...) PRINTF_D("[CHRE]" fmt "\n", ##arg)
|
|
#endif
|
|
|
|
#if CHRE_MINIMUM_LOG_LEVEL >= CHRE_LOG_LEVEL_VERBOSE
|
|
#undef LOGV
|
|
#define LOGV(fmt, arg...) PRINTF_D("[CHRE]" fmt "\n", ##arg)
|
|
#endif
|
|
|
|
namespace chre {
|
|
namespace {
|
|
|
|
struct UnloadNanoappCallbackData {
|
|
uint64_t appId;
|
|
uint32_t transactionId;
|
|
uint16_t hostClientId;
|
|
bool allowSystemNanoappUnload;
|
|
};
|
|
|
|
uint32_t gChreIpiRecvData[2];
|
|
uint32_t gChreIpiAckToHost[2]; // SCP reply ack data (AP to SCP)
|
|
int gChreIpiAckFromHost[2]; // SCP get ack data from AP (SCP to AP)
|
|
|
|
void *gChreSubregionRecvAddr;
|
|
size_t gChreSubregionRecvSize;
|
|
void *gChreSubregionSendAddr;
|
|
size_t gChreSubregionSendSize;
|
|
|
|
// TODO(b/263958729): move it to HostLinkBase, and revisit buffer size
|
|
// payload buffers
|
|
#define CHRE_IPI_RECV_BUFFER_SIZE (CHRE_MESSAGE_TO_HOST_MAX_SIZE + 128)
|
|
uint32_t gChreRecvBuffer[CHRE_IPI_RECV_BUFFER_SIZE / sizeof(uint32_t)]
|
|
__attribute__((aligned(CACHE_LINE_SIZE)));
|
|
|
|
#ifdef SCP_CHRE_USE_DMA
|
|
static inline uint32_t align(uint32_t target, uint32_t size) {
|
|
return (target + size - 1) & ~(size - 1);
|
|
}
|
|
#endif
|
|
|
|
#define SCP_CHRE_MAGIC 0x67728269
|
|
struct ScpChreIpiMsg {
|
|
uint32_t magic;
|
|
uint32_t size;
|
|
};
|
|
|
|
struct NanoappListData {
|
|
ChreFlatBufferBuilder *builder;
|
|
DynamicVector<NanoappListEntryOffset> nanoappEntries;
|
|
uint16_t hostClientId;
|
|
};
|
|
|
|
enum class PendingMessageType {
|
|
Shutdown,
|
|
NanoappMessageToHost,
|
|
HubInfoResponse,
|
|
NanoappListResponse,
|
|
LoadNanoappResponse,
|
|
UnloadNanoappResponse,
|
|
DebugDumpData,
|
|
DebugDumpResponse,
|
|
TimeSyncRequest,
|
|
LowPowerMicAccessRequest,
|
|
LowPowerMicAccessRelease,
|
|
EncodedLogMessage,
|
|
SelfTestResponse,
|
|
MetricLog,
|
|
NanConfigurationRequest,
|
|
};
|
|
|
|
struct PendingMessage {
|
|
PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
|
|
type = msgType;
|
|
data.hostClientId = hostClientId;
|
|
}
|
|
|
|
PendingMessage(PendingMessageType msgType,
|
|
const HostMessage *msgToHost = nullptr) {
|
|
type = msgType;
|
|
data.msgToHost = msgToHost;
|
|
}
|
|
|
|
PendingMessage(PendingMessageType msgType, ChreFlatBufferBuilder *builder) {
|
|
type = msgType;
|
|
data.builder = builder;
|
|
}
|
|
|
|
PendingMessageType type;
|
|
union {
|
|
const HostMessage *msgToHost;
|
|
uint16_t hostClientId;
|
|
ChreFlatBufferBuilder *builder;
|
|
} data;
|
|
};
|
|
|
|
constexpr size_t kOutboundQueueSize = 100;
|
|
FixedSizeBlockingQueue<PendingMessage, kOutboundQueueSize> gOutboundQueue;
|
|
|
|
typedef void(MessageBuilderFunction)(ChreFlatBufferBuilder &builder,
|
|
void *cookie);
|
|
|
|
inline HostCommsManager &getHostCommsManager() {
|
|
return EventLoopManagerSingleton::get()->getHostCommsManager();
|
|
}
|
|
|
|
bool generateMessageFromBuilder(ChreFlatBufferBuilder *builder) {
|
|
CHRE_ASSERT(builder != nullptr);
|
|
LOGV("%s: message size %d", __func__, builder->GetSize());
|
|
bool result =
|
|
HostLinkBase::send(builder->GetBufferPointer(), builder->GetSize());
|
|
|
|
// clean up
|
|
builder->~ChreFlatBufferBuilder();
|
|
memoryFree(builder);
|
|
return result;
|
|
}
|
|
|
|
bool generateMessageToHost(const HostMessage *message) {
|
|
LOGV("%s: message size %zu", __func__, message->message.size());
|
|
// TODO(b/263958729): ideally we'd construct our flatbuffer directly in the
|
|
// host-supplied buffer
|
|
constexpr size_t kFixedReserveSize = 80;
|
|
ChreFlatBufferBuilder builder(message->message.size() + kFixedReserveSize);
|
|
HostProtocolChre::encodeNanoappMessage(
|
|
builder, message->appId, message->toHostData.messageType,
|
|
message->toHostData.hostEndpoint, message->message.data(),
|
|
message->message.size(), message->toHostData.appPermissions,
|
|
message->toHostData.messagePermissions, message->toHostData.wokeHost);
|
|
bool result =
|
|
HostLinkBase::send(builder.GetBufferPointer(), builder.GetSize());
|
|
|
|
// clean up
|
|
getHostCommsManager().onMessageToHostComplete(message);
|
|
return result;
|
|
}
|
|
|
|
int generateHubInfoResponse(uint16_t hostClientId) {
|
|
constexpr size_t kInitialBufferSize = 192;
|
|
|
|
constexpr char kHubName[] = "CHRE on Tinysys";
|
|
constexpr char kVendor[] = "Google";
|
|
constexpr char kToolchain[] =
|
|
"Clang " STRINGIFY(__clang_major__) "." STRINGIFY(
|
|
__clang_minor__) "." STRINGIFY(__clang_patchlevel__);
|
|
constexpr uint32_t kLegacyPlatformVersion = 0;
|
|
constexpr uint32_t kLegacyToolchainVersion =
|
|
((__clang_major__ & 0xFF) << 24) | ((__clang_minor__ & 0xFF) << 16) |
|
|
(__clang_patchlevel__ & 0xFFFF);
|
|
constexpr float kPeakMips = 350;
|
|
constexpr float kStoppedPower = 0;
|
|
constexpr float kSleepPower = 1;
|
|
constexpr float kPeakPower = 15;
|
|
|
|
// Note that this may execute prior to EventLoopManager::lateInit() completing
|
|
ChreFlatBufferBuilder builder(kInitialBufferSize);
|
|
HostProtocolChre::encodeHubInfoResponse(
|
|
builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion,
|
|
kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower,
|
|
kPeakPower, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(),
|
|
chreGetVersion(), hostClientId);
|
|
|
|
return HostLinkBase::send(builder.GetBufferPointer(), builder.GetSize());
|
|
}
|
|
|
|
bool dequeueMessage(PendingMessage pendingMsg) {
|
|
LOGV("%s: message type %d", __func__, pendingMsg.type);
|
|
bool result = false;
|
|
switch (pendingMsg.type) {
|
|
case PendingMessageType::NanoappMessageToHost:
|
|
result = generateMessageToHost(pendingMsg.data.msgToHost);
|
|
break;
|
|
|
|
case PendingMessageType::HubInfoResponse:
|
|
result = generateHubInfoResponse(pendingMsg.data.hostClientId);
|
|
break;
|
|
|
|
case PendingMessageType::NanoappListResponse:
|
|
case PendingMessageType::LoadNanoappResponse:
|
|
case PendingMessageType::UnloadNanoappResponse:
|
|
case PendingMessageType::DebugDumpData:
|
|
case PendingMessageType::DebugDumpResponse:
|
|
case PendingMessageType::TimeSyncRequest:
|
|
case PendingMessageType::LowPowerMicAccessRequest:
|
|
case PendingMessageType::LowPowerMicAccessRelease:
|
|
case PendingMessageType::EncodedLogMessage:
|
|
case PendingMessageType::SelfTestResponse:
|
|
case PendingMessageType::MetricLog:
|
|
case PendingMessageType::NanConfigurationRequest:
|
|
result = generateMessageFromBuilder(pendingMsg.data.builder);
|
|
break;
|
|
|
|
default:
|
|
CHRE_ASSERT_LOG(false, "Unexpected pending message type");
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Wrapper function to enqueue a message on the outbound message queue. All
|
|
* outgoing message to the host must be called through this function.
|
|
*
|
|
* @param message The message to send to host.
|
|
*
|
|
* @return true if the message was successfully added to the queue.
|
|
*/
|
|
bool enqueueMessage(PendingMessage pendingMsg) {
|
|
return gOutboundQueue.push(pendingMsg);
|
|
}
|
|
|
|
/**
|
|
* Helper function that takes care of the boilerplate for allocating a
|
|
* ChreFlatBufferBuilder on the heap and adding it to the outbound message
|
|
* queue.
|
|
*
|
|
* @param msgType Identifies the message while in the outbound queue
|
|
* @param initialBufferSize Number of bytes to reserve when first allocating the
|
|
* ChreFlatBufferBuilder
|
|
* @param buildMsgFunc Synchronous callback used to encode the FlatBuffer
|
|
* message. Will not be invoked if allocation fails.
|
|
* @param cookie Opaque pointer that will be passed through to buildMsgFunc
|
|
*
|
|
* @return true if the message was successfully added to the queue
|
|
*/
|
|
bool buildAndEnqueueMessage(PendingMessageType msgType,
|
|
size_t initialBufferSize,
|
|
MessageBuilderFunction *msgBuilder, void *cookie) {
|
|
LOGV("%s: message type %d, size %zu", __func__, msgType, initialBufferSize);
|
|
bool pushed = false;
|
|
|
|
auto builder = MakeUnique<ChreFlatBufferBuilder>(initialBufferSize);
|
|
if (builder.isNull()) {
|
|
LOGE("Couldn't allocate memory for message type %d",
|
|
static_cast<int>(msgType));
|
|
} else {
|
|
msgBuilder(*builder, cookie);
|
|
|
|
// TODO(b/263958729): if this fails, ideally we should block for some
|
|
// timeout until there's space in the queue
|
|
if (!enqueueMessage(PendingMessage(msgType, builder.get()))) {
|
|
LOGE("Couldn't push message type %d to outbound queue",
|
|
static_cast<int>(msgType));
|
|
} else {
|
|
builder.release();
|
|
pushed = true;
|
|
}
|
|
}
|
|
|
|
return pushed;
|
|
}
|
|
|
|
/**
|
|
* FlatBuffer message builder callback used with handleNanoappListRequest()
|
|
*/
|
|
void buildNanoappListResponse(ChreFlatBufferBuilder &builder, void *cookie) {
|
|
LOGV("%s", __func__);
|
|
auto nanoappAdderCallback = [](const Nanoapp *nanoapp, void *data) {
|
|
auto *cbData = static_cast<NanoappListData *>(data);
|
|
HostProtocolChre::addNanoappListEntry(
|
|
*(cbData->builder), cbData->nanoappEntries, nanoapp->getAppId(),
|
|
nanoapp->getAppVersion(), true /*enabled*/, nanoapp->isSystemNanoapp(),
|
|
nanoapp->getAppPermissions(), nanoapp->getRpcServices());
|
|
};
|
|
|
|
// Add a NanoappListEntry to the FlatBuffer for each nanoapp
|
|
auto *cbData = static_cast<NanoappListData *>(cookie);
|
|
cbData->builder = &builder;
|
|
EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
|
|
eventLoop.forEachNanoapp(nanoappAdderCallback, cbData);
|
|
HostProtocolChre::finishNanoappListResponse(builder, cbData->nanoappEntries,
|
|
cbData->hostClientId);
|
|
}
|
|
|
|
void handleUnloadNanoappCallback(uint16_t /*type*/, void *data,
|
|
void * /*extraData*/) {
|
|
auto *cbData = static_cast<UnloadNanoappCallbackData *>(data);
|
|
bool success = false;
|
|
uint16_t instanceId;
|
|
EventLoop &eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
|
|
if (!eventLoop.findNanoappInstanceIdByAppId(cbData->appId, &instanceId)) {
|
|
LOGE("Couldn't unload app ID 0x%016" PRIx64 ": not found", cbData->appId);
|
|
} else {
|
|
success =
|
|
eventLoop.unloadNanoapp(instanceId, cbData->allowSystemNanoappUnload);
|
|
}
|
|
|
|
constexpr size_t kInitialBufferSize = 52;
|
|
auto builder = MakeUnique<ChreFlatBufferBuilder>(kInitialBufferSize);
|
|
HostProtocolChre::encodeUnloadNanoappResponse(*builder, cbData->hostClientId,
|
|
cbData->transactionId, success);
|
|
|
|
if (!enqueueMessage(PendingMessage(PendingMessageType::UnloadNanoappResponse,
|
|
builder.get()))) {
|
|
LOGE("Failed to send unload response to host: %x transactionID: 0x%x",
|
|
cbData->hostClientId, cbData->transactionId);
|
|
} else {
|
|
builder.release();
|
|
}
|
|
|
|
memoryFree(data);
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
void sendDebugDumpResultToHost(uint16_t hostClientId, const char * /*debugStr*/,
|
|
size_t /*debugStrSize*/, bool /*complete*/,
|
|
uint32_t /*dataCount*/) {
|
|
LOGV("%s: host client id %d", __func__, hostClientId);
|
|
// TODO(b/263958729): Implement this.
|
|
}
|
|
|
|
HostLinkBase::HostLinkBase() {
|
|
LOGV("HostLinkBase::%s", __func__);
|
|
initializeIpi();
|
|
}
|
|
|
|
HostLinkBase::~HostLinkBase() {
|
|
LOGV("HostLinkBase::%s", __func__);
|
|
}
|
|
|
|
void HostLinkBase::vChreReceiveTask(void *pvParameters) {
|
|
int i = 0;
|
|
int ret = 0;
|
|
|
|
LOGV("%s", __func__);
|
|
while (true) {
|
|
LOGV("%s calling ipi_recv_reply(), Cnt=%d", __func__, i++);
|
|
ret = ipi_recv_reply(IPI_IN_C_HOST_SCP_CHRE, (void *)&gChreIpiAckToHost[0],
|
|
1);
|
|
if (ret != IPI_ACTION_DONE)
|
|
LOGE("%s ipi_recv_reply() ret = %d", __func__, ret);
|
|
LOGV("%s reply_end", __func__);
|
|
}
|
|
}
|
|
|
|
void HostLinkBase::vChreSendTask(void *pvParameters) {
|
|
while (true) {
|
|
auto msg = gOutboundQueue.pop();
|
|
dequeueMessage(msg);
|
|
}
|
|
}
|
|
|
|
void HostLinkBase::chreIpiHandler(unsigned int id, void *prdata, void *data,
|
|
unsigned int len) {
|
|
/* receive magic and cmd */
|
|
struct ScpChreIpiMsg msg = *(struct ScpChreIpiMsg *)data;
|
|
|
|
// check the magic number and payload size need to be copy(if need) */
|
|
LOGV("%s: msg.magic=0x%x, msg.size=%u", __func__, msg.magic, msg.size);
|
|
if (msg.magic != SCP_CHRE_MAGIC) {
|
|
LOGE("Invalid magic number, skip message");
|
|
gChreIpiAckToHost[0] = IPI_NO_MEMORY;
|
|
gChreIpiAckToHost[1] = 0;
|
|
return;
|
|
}
|
|
|
|
// Mapping the physical address of share memory for SCP
|
|
uint32_t srcAddr =
|
|
ap_to_scp(reinterpret_cast<uint32_t>(gChreSubregionRecvAddr));
|
|
|
|
#ifdef SCP_CHRE_USE_DMA
|
|
// Using SCP DMA HW to copy the data from share memory to SCP side, ex:
|
|
// gChreRecvBuffer gChreRecvBuffer could be a global variables or a SCP heap
|
|
// memory at SRAM/DRAM
|
|
scp_dma_transaction_dram(reinterpret_cast<uint32_t>(&gChreRecvBuffer[0]),
|
|
srcAddr, msg.size, DMA_MEM_ID, NO_RESERVED);
|
|
|
|
// Invalid cache to update the newest data before using
|
|
mrv_dcache_invalid_multi_addr(reinterpret_cast<uint32_t>(&gChreRecvBuffer[0]),
|
|
align(msg.size, CACHE_LINE_SIZE));
|
|
#else
|
|
dvfs_enable_DRAM_resource(CHRE_MEM_ID);
|
|
memcpy(static_cast<void *>(gChreRecvBuffer),
|
|
reinterpret_cast<void *>(srcAddr), msg.size);
|
|
dvfs_disable_DRAM_resource(CHRE_MEM_ID);
|
|
#endif
|
|
|
|
// process the message
|
|
LOGV("chre_rcvbuf: 0x%x 0x%x 0x%x 0x%x", gChreRecvBuffer[0],
|
|
gChreRecvBuffer[1], gChreRecvBuffer[2], gChreRecvBuffer[3]);
|
|
receive(static_cast<HostLinkBase *>(prdata), gChreRecvBuffer, msg.size);
|
|
|
|
// After finishing the job, akc the message to host
|
|
gChreIpiAckToHost[0] = IPI_ACTION_DONE;
|
|
gChreIpiAckToHost[1] = msg.size;
|
|
}
|
|
|
|
void HostLinkBase::initializeIpi(void) {
|
|
LOGV("%s", __func__);
|
|
bool success = false;
|
|
int ret;
|
|
constexpr size_t kBackgroundTaskStackSize = 1024;
|
|
constexpr UBaseType_t kBackgroundTaskPriority = 2;
|
|
|
|
// prepared share memory information and register the callback functions
|
|
if (!(ret = scp_get_reserve_mem_by_id(SCP_CHRE_FROM_MEM_ID,
|
|
&gChreSubregionRecvAddr,
|
|
&gChreSubregionRecvSize))) {
|
|
LOGE("%s: get SCP_CHRE_FROM_MEM_ID memory fail", __func__);
|
|
} else if (!(ret = scp_get_reserve_mem_by_id(SCP_CHRE_TO_MEM_ID,
|
|
&gChreSubregionSendAddr,
|
|
&gChreSubregionSendSize))) {
|
|
LOGE("%s: get SCP_CHRE_TO_MEM_ID memory fail", __func__);
|
|
} else if (pdPASS != xTaskCreate(vChreReceiveTask, "CHRE_RECEIVE",
|
|
kBackgroundTaskStackSize, (void *)0,
|
|
kBackgroundTaskPriority, NULL)) {
|
|
LOGE("%s failed to create ipi receiver task", __func__);
|
|
} else if (pdPASS != xTaskCreate(vChreSendTask, "CHRE_SEND",
|
|
kBackgroundTaskStackSize, (void *)0,
|
|
kBackgroundTaskPriority, NULL)) {
|
|
LOGE("%s failed to create ipi outbound message queue task", __func__);
|
|
} else if (IPI_ACTION_DONE !=
|
|
(ret = ipi_register(IPI_IN_C_HOST_SCP_CHRE, (void *)chreIpiHandler,
|
|
(void *)this, (void *)&gChreIpiRecvData[0]))) {
|
|
LOGE("ipi_register IPI_IN_C_HOST_SCP_CHRE failed, %d", ret);
|
|
} else if (IPI_ACTION_DONE !=
|
|
(ret = ipi_register(IPI_OUT_C_SCP_HOST_CHRE, NULL, (void *)this,
|
|
(void *)&gChreIpiAckFromHost[0]))) {
|
|
LOGE("ipi_register IPI_OUT_C_SCP_HOST_CHRE failed, %d", ret);
|
|
} else {
|
|
success = true;
|
|
}
|
|
|
|
if (!success) {
|
|
FATAL_ERROR("HostLinkBase::initializeIpi() failed");
|
|
}
|
|
}
|
|
|
|
void HostLinkBase::receive(HostLinkBase *instance, void *message,
|
|
int messageLen) {
|
|
LOGV("%s: message len %d", __func__, messageLen);
|
|
|
|
// TODO(b/263958729): A crude way to initially determine daemon's up - set
|
|
// a flag on the first message received. This is temporary until a better
|
|
// way to do this is available.
|
|
instance->setInitialized(true);
|
|
|
|
if (!HostProtocolChre::decodeMessageFromHost(message, messageLen)) {
|
|
LOGE("Failed to decode msg %p of len %u", message, messageLen);
|
|
}
|
|
}
|
|
|
|
bool HostLinkBase::send(uint8_t *data, size_t dataLen) {
|
|
#ifndef HOST_LINK_IPI_SEND_TIMEOUT_MS
|
|
#define HOST_LINK_IPI_SEND_TIMEOUT_MS 100
|
|
#endif
|
|
#ifndef HOST_LINK_IPI_RESPONSE_TIMEOUT_MS
|
|
#define HOST_LINK_IPI_RESPONSE_TIMEOUT_MS 100
|
|
#endif
|
|
LOGV("HostLinkBase::%s: %zu, %p", __func__, dataLen, data);
|
|
struct ScpChreIpiMsg msg;
|
|
msg.magic = SCP_CHRE_MAGIC;
|
|
msg.size = dataLen;
|
|
|
|
// Mapping the physical address of share memory for SCP
|
|
void *dstAddr = reinterpret_cast<void *>(
|
|
ap_to_scp(reinterpret_cast<uint32_t>(gChreSubregionSendAddr)));
|
|
|
|
#ifdef SCP_CHRE_USE_DMA
|
|
// TODO(b/263958729): use DMA for larger payload
|
|
// No need cache operation, because src_dst handled by SCP CPU and dstAddr is
|
|
// non-cacheable
|
|
#else
|
|
dvfs_enable_DRAM_resource(CHRE_MEM_ID);
|
|
memcpy(dstAddr, data, dataLen);
|
|
dvfs_disable_DRAM_resource(CHRE_MEM_ID);
|
|
#endif
|
|
|
|
// NB: len param for ipi_send is in number of 32-bit words
|
|
int ret = ipi_send_compl(
|
|
IPI_OUT_C_SCP_HOST_CHRE, &msg, sizeof(msg) / sizeof(uint32_t),
|
|
HOST_LINK_IPI_SEND_TIMEOUT_MS, HOST_LINK_IPI_RESPONSE_TIMEOUT_MS);
|
|
if (ret) {
|
|
LOGE("chre ipi send fail(%d)", ret);
|
|
} else {
|
|
/* check ack data for make sure IPI wasn't busy */
|
|
LOGV("chre ipi send, check ack data: 0x%x", gChreIpiAckFromHost[0]);
|
|
if (gChreIpiAckFromHost[0] == IPI_ACTION_DONE) {
|
|
LOGV("chre ipi send done, you can send another IPI");
|
|
} else if (gChreIpiAckFromHost[0] == IPI_PIN_BUSY) {
|
|
/* you may have to re-send the IPI, or drop this one */
|
|
LOGV(
|
|
"chre ipi send busy, user thread has not wait the IPI until job "
|
|
"finished");
|
|
} else if (gChreIpiAckFromHost[0] == IPI_NO_MEMORY) {
|
|
LOGV("chre ipi send with wrong size(%zu)", dataLen);
|
|
} else {
|
|
LOGV("chre ipi send unknown case");
|
|
}
|
|
}
|
|
|
|
return ret == IPI_ACTION_DONE;
|
|
}
|
|
|
|
void HostLinkBase::sendTimeSyncRequest() {
|
|
LOGV("%s", __func__);
|
|
// TODO(b/263958729): Implement this.
|
|
}
|
|
|
|
void HostLinkBase::sendLogMessageV2(const uint8_t *logMessage,
|
|
size_t logMessageSize,
|
|
uint32_t numLogsDropped) {
|
|
LOGV("%s: size %zu", __func__, logMessageSize);
|
|
struct LogMessageData {
|
|
const uint8_t *logMsg;
|
|
size_t logMsgSize;
|
|
uint32_t numLogsDropped;
|
|
};
|
|
|
|
LogMessageData logMessageData{logMessage, logMessageSize, numLogsDropped};
|
|
|
|
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
|
|
const auto *data = static_cast<const LogMessageData *>(cookie);
|
|
HostProtocolChre::encodeLogMessagesV2(
|
|
builder, data->logMsg, data->logMsgSize, data->numLogsDropped);
|
|
};
|
|
|
|
constexpr size_t kInitialSize = 128;
|
|
bool result = false;
|
|
if (isInitialized()) {
|
|
result = buildAndEnqueueMessage(
|
|
PendingMessageType::EncodedLogMessage,
|
|
kInitialSize + logMessageSize + sizeof(numLogsDropped), msgBuilder,
|
|
&logMessageData);
|
|
}
|
|
|
|
#ifdef CHRE_USE_BUFFERED_LOGGING
|
|
if (LogBufferManagerSingleton::isInitialized()) {
|
|
LogBufferManagerSingleton::get()->onLogsSentToHost(result);
|
|
}
|
|
#else
|
|
UNUSED_VAR(result);
|
|
#endif
|
|
}
|
|
|
|
bool HostLink::sendMessage(HostMessage const *message) {
|
|
LOGV("HostLink::%s size(%zu)", __func__, message->message.size());
|
|
bool success = false;
|
|
|
|
if (isInitialized()) {
|
|
success = enqueueMessage(
|
|
PendingMessage(PendingMessageType::NanoappMessageToHost, message));
|
|
} else {
|
|
LOGW("Dropping outbound message: host link not initialized yet");
|
|
}
|
|
return success;
|
|
}
|
|
|
|
// TODO(b/263958729): HostMessageHandlers member function implementations are
|
|
// expected to be (mostly) identical for any platform that uses flatbuffers
|
|
// to encode messages - refactor the host link to merge the multiple copies
|
|
// we currently have.
|
|
void HostMessageHandlers::handleNanoappMessage(uint64_t appId,
|
|
uint32_t messageType,
|
|
uint16_t hostEndpoint,
|
|
const void *messageData,
|
|
size_t messageDataLen) {
|
|
LOGV("Parsed nanoapp message from host: app ID 0x%016" PRIx64
|
|
", endpoint "
|
|
"0x%" PRIx16 ", msgType %" PRIu32 ", payload size %zu",
|
|
appId, hostEndpoint, messageType, messageDataLen);
|
|
|
|
// TODO(b/263958729): Implement this.
|
|
getHostCommsManager().sendMessageToNanoappFromHost(
|
|
appId, messageType, hostEndpoint, messageData, messageDataLen);
|
|
}
|
|
|
|
void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
|
|
LOGV("%s: host client id %d", __func__, hostClientId);
|
|
enqueueMessage(
|
|
PendingMessage(PendingMessageType::HubInfoResponse, hostClientId));
|
|
}
|
|
|
|
void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
|
|
auto callback = [](uint16_t /*type*/, void *data, void * /*extraData*/) {
|
|
uint16_t cbHostClientId = NestedDataPtr<uint16_t>(data);
|
|
|
|
NanoappListData cbData = {};
|
|
cbData.hostClientId = cbHostClientId;
|
|
|
|
size_t expectedNanoappCount =
|
|
EventLoopManagerSingleton::get()->getEventLoop().getNanoappCount();
|
|
if (!cbData.nanoappEntries.reserve(expectedNanoappCount)) {
|
|
LOG_OOM();
|
|
} else {
|
|
constexpr size_t kFixedOverhead = 48;
|
|
constexpr size_t kPerNanoappSize = 32;
|
|
size_t initialBufferSize =
|
|
(kFixedOverhead + expectedNanoappCount * kPerNanoappSize);
|
|
|
|
buildAndEnqueueMessage(PendingMessageType::NanoappListResponse,
|
|
initialBufferSize, buildNanoappListResponse,
|
|
&cbData);
|
|
}
|
|
};
|
|
|
|
LOGD("Nanoapp list request from client ID %" PRIu16, hostClientId);
|
|
EventLoopManagerSingleton::get()->deferCallback(
|
|
SystemCallbackType::NanoappListResponse,
|
|
NestedDataPtr<uint16_t>(hostClientId), callback);
|
|
}
|
|
|
|
void HostMessageHandlers::sendFragmentResponse(uint16_t hostClientId,
|
|
uint32_t transactionId,
|
|
uint32_t fragmentId,
|
|
bool success) {
|
|
struct FragmentedLoadInfoResponse {
|
|
uint16_t hostClientId;
|
|
uint32_t transactionId;
|
|
uint32_t fragmentId;
|
|
bool success;
|
|
};
|
|
|
|
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void *cookie) {
|
|
auto *cbData = static_cast<FragmentedLoadInfoResponse *>(cookie);
|
|
HostProtocolChre::encodeLoadNanoappResponse(
|
|
builder, cbData->hostClientId, cbData->transactionId, cbData->success,
|
|
cbData->fragmentId);
|
|
};
|
|
|
|
FragmentedLoadInfoResponse response = {
|
|
.hostClientId = hostClientId,
|
|
.transactionId = transactionId,
|
|
.fragmentId = fragmentId,
|
|
.success = success,
|
|
};
|
|
constexpr size_t kInitialBufferSize = 52;
|
|
buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse,
|
|
kInitialBufferSize, msgBuilder, &response);
|
|
}
|
|
|
|
void HostMessageHandlers::handleLoadNanoappRequest(
|
|
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
|
|
uint32_t appVersion, uint32_t appFlags, uint32_t targetApiVersion,
|
|
const void *buffer, size_t bufferLen, const char *appFileName,
|
|
uint32_t fragmentId, size_t appBinaryLen, bool respondBeforeStart) {
|
|
UNUSED_VAR(appFileName);
|
|
|
|
loadNanoappData(hostClientId, transactionId, appId, appVersion, appFlags,
|
|
targetApiVersion, buffer, bufferLen, fragmentId, appBinaryLen,
|
|
respondBeforeStart);
|
|
}
|
|
|
|
void HostMessageHandlers::handleUnloadNanoappRequest(
|
|
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
|
|
bool allowSystemNanoappUnload) {
|
|
LOGD("Unload nanoapp request from client %" PRIu16 " (txnID %" PRIu32
|
|
") for appId 0x%016" PRIx64 " system %d",
|
|
hostClientId, transactionId, appId, allowSystemNanoappUnload);
|
|
auto *cbData = memoryAlloc<UnloadNanoappCallbackData>();
|
|
if (cbData == nullptr) {
|
|
LOG_OOM();
|
|
} else {
|
|
cbData->appId = appId;
|
|
cbData->transactionId = transactionId;
|
|
cbData->hostClientId = hostClientId;
|
|
cbData->allowSystemNanoappUnload = allowSystemNanoappUnload;
|
|
|
|
EventLoopManagerSingleton::get()->deferCallback(
|
|
SystemCallbackType::HandleUnloadNanoapp, cbData,
|
|
handleUnloadNanoappCallback);
|
|
}
|
|
}
|
|
|
|
void HostLink::flushMessagesSentByNanoapp(uint64_t /* appId */) {
|
|
// Not implemented
|
|
}
|
|
|
|
void HostMessageHandlers::handleTimeSyncMessage(int64_t offset) {
|
|
LOGE("%s unsupported.", __func__);
|
|
}
|
|
|
|
void HostMessageHandlers::handleDebugDumpRequest(uint16_t hostClientId) {
|
|
LOGV("%s: host client id %d", __func__, hostClientId);
|
|
// TODO(b/263958729): Implement this.
|
|
}
|
|
|
|
void HostMessageHandlers::handleSettingChangeMessage(fbs::Setting setting,
|
|
fbs::SettingState state) {
|
|
// TODO(b/267207477): Refactor handleSettingChangeMessage to shared code
|
|
Setting chreSetting;
|
|
bool chreSettingEnabled;
|
|
if (HostProtocolChre::getSettingFromFbs(setting, &chreSetting) &&
|
|
HostProtocolChre::getSettingEnabledFromFbs(state, &chreSettingEnabled)) {
|
|
EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
|
|
chreSetting, chreSettingEnabled);
|
|
}
|
|
}
|
|
|
|
void HostMessageHandlers::handleSelfTestRequest(uint16_t hostClientId) {
|
|
LOGV("%s: host client id %d", __func__, hostClientId);
|
|
// TODO(b/263958729): Implement this.
|
|
}
|
|
|
|
void HostMessageHandlers::handleNanConfigurationUpdate(bool /* enabled */) {
|
|
LOGE("%s NAN unsupported.", __func__);
|
|
}
|
|
|
|
void sendAudioRequest() {
|
|
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void * /*cookie*/) {
|
|
HostProtocolChre::encodeLowPowerMicAccessRequest(builder);
|
|
};
|
|
constexpr size_t kInitialSize = 32;
|
|
buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRequest,
|
|
kInitialSize, msgBuilder, /* cookie= */ nullptr);
|
|
}
|
|
|
|
void sendAudioRelease() {
|
|
auto msgBuilder = [](ChreFlatBufferBuilder &builder, void * /*cookie*/) {
|
|
HostProtocolChre::encodeLowPowerMicAccessRelease(builder);
|
|
};
|
|
constexpr size_t kInitialSize = 32;
|
|
buildAndEnqueueMessage(PendingMessageType::LowPowerMicAccessRelease,
|
|
kInitialSize, msgBuilder, /* cookie= */ nullptr);
|
|
}
|
|
|
|
} // namespace chre
|