blob: a26fe9f23e260c1d306339a6b1059c5e8b6e77bb [file] [log] [blame] [edit]
/*
* Copyright 2023 Arm Limited and/or its affiliates.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
/*
* Warning: Do not change this without changing arm_backend.py::vela_compile
* as that function emits this format and the two need to align.
*/
#include <executorch/backends/arm/runtime/VelaBinStream.h>
#include <cstring>
#include <executorch/runtime/core/error.h>
namespace executorch {
namespace backends {
namespace arm {
// get next mul of 16 ptr, return n if already aligned
static uintptr_t next_mul_16(uintptr_t n) {
return ((n - 1) | 15) + 1;
}
bool vela_bin_validate(const char* data, int size) {
const char* foot = data + size - sizeof(VelaBinBlock);
// Check 16 byte alignment
bool valid = true;
if ((uintptr_t)data != next_mul_16((uintptr_t)data)) {
ET_LOG(Error, "Vela bin ptr not aligned to 16 bytes: %p", (void*)data);
valid = false;
}
if ((uintptr_t)foot != next_mul_16((uintptr_t)foot)) {
ET_LOG(Error, "End of vela bin not aligned to 16 bytes: %p", (void*)foot);
valid = false;
}
// Check header and footer blocks are the right format
if (strncmp(data, "vela_bin_stream", strlen("vela_bin_stream")) != 0) {
ET_LOG(Error, "Incorrect header in vela_bin_stream");
valid = false;
}
if (strncmp(foot, "vela_end_stream", strlen("vela_end_stream")) != 0) {
ET_LOG(Error, "Incorrect footer in vela_bin_stream");
valid = false;
}
return valid;
}
bool vela_bin_read(const char* data, VelaHandles* handles, int size) {
const char* ptr = data;
while (ptr - data < size) {
VelaBinBlock* b = (VelaBinBlock*)ptr;
ptr += sizeof(VelaBinBlock) + next_mul_16(b->size);
if (!strncmp(b->name, "vela_bin_stream", strlen("vela_bin_stream"))) {
// expect vela_bin_stream first
if ((char*)b != (char*)data)
return false;
} else if (!strncmp(b->name, "cmd_data", strlen("cmd_data"))) {
// This driver magic header confirms a valid command stream in binary
if (strncmp(b->data, "COP1", strlen("COP1")))
return false;
handles->cmd_data = b->data;
handles->cmd_data_size = b->size;
} else if (!strncmp(b->name, "weight_data", strlen("weight_data"))) {
handles->weight_data = b->data;
handles->weight_data_size = b->size;
} else if (!strncmp(b->name, "scratch_data", strlen("scratch_data"))) {
handles->scratch_data = b->data;
handles->scratch_data_size = b->size;
} else if (!strncmp(b->name, "inputs", strlen("inputs"))) {
handles->inputs = (VelaIOs*)b->data;
} else if (!strncmp(b->name, "outputs", strlen("outputs"))) {
handles->outputs = (VelaIOs*)b->data;
} else if (!strncmp(
b->name, "vela_end_stream", strlen("vela_end_stream"))) {
// expect vela_end_stream last
if (ptr - data != size) {
ET_LOG(Error, "Expected vela binary to end with vela_end_stream");
return false;
}
return true;
} else {
// Unrecognised block name
ET_LOG(Error, "Invalid block name or malformed binary");
return false;
}
}
// We've fallen off the end without finding vela_end_stream
return false;
}
} // namespace arm
} // namespace backends
} // namespace executorch