1 /*
2 * Copyright 2023 Arm Limited and/or its affiliates.
3 *
4 * This source code is licensed under the BSD-style license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8 /*
9 * Warning: Do not change this without changing arm_backend.py::vela_compile
10 * as that function emits this format and the two need to align.
11 */
12
13 #include <executorch/backends/arm/runtime/VelaBinStream.h>
14
15 #include <cstring>
16
17 #include <executorch/runtime/core/error.h>
18
19 namespace executorch {
20 namespace backends {
21 namespace arm {
22
23 // get next mul of 16 ptr, return n if already aligned
next_mul_16(uintptr_t n)24 static uintptr_t next_mul_16(uintptr_t n) {
25 return ((n - 1) | 15) + 1;
26 }
27
vela_bin_validate(const char * data,int size)28 bool vela_bin_validate(const char* data, int size) {
29 const char* foot = data + size - sizeof(VelaBinBlock);
30
31 // Check 16 byte alignment
32 bool valid = true;
33 if ((uintptr_t)data != next_mul_16((uintptr_t)data)) {
34 ET_LOG(Error, "Vela bin ptr not aligned to 16 bytes: %p", (void*)data);
35 valid = false;
36 }
37 if ((uintptr_t)foot != next_mul_16((uintptr_t)foot)) {
38 ET_LOG(Error, "End of vela bin not aligned to 16 bytes: %p", (void*)foot);
39 valid = false;
40 }
41 // Check header and footer blocks are the right format
42 if (strncmp(data, "vela_bin_stream", strlen("vela_bin_stream")) != 0) {
43 ET_LOG(Error, "Incorrect header in vela_bin_stream");
44 valid = false;
45 }
46 if (strncmp(foot, "vela_end_stream", strlen("vela_end_stream")) != 0) {
47 ET_LOG(Error, "Incorrect footer in vela_bin_stream");
48 valid = false;
49 }
50
51 return valid;
52 }
53
vela_bin_read(const char * data,VelaHandles * handles,int size)54 bool vela_bin_read(const char* data, VelaHandles* handles, int size) {
55 const char* ptr = data;
56
57 while (ptr - data < size) {
58 VelaBinBlock* b = (VelaBinBlock*)ptr;
59 ptr += sizeof(VelaBinBlock) + next_mul_16(b->size);
60
61 if (!strncmp(b->name, "vela_bin_stream", strlen("vela_bin_stream"))) {
62 // expect vela_bin_stream first
63 if ((char*)b != (char*)data)
64 return false;
65 } else if (!strncmp(b->name, "cmd_data", strlen("cmd_data"))) {
66 // This driver magic header confirms a valid command stream in binary
67 if (strncmp(b->data, "COP1", strlen("COP1")))
68 return false;
69 handles->cmd_data = b->data;
70 handles->cmd_data_size = b->size;
71 } else if (!strncmp(b->name, "weight_data", strlen("weight_data"))) {
72 handles->weight_data = b->data;
73 handles->weight_data_size = b->size;
74 } else if (!strncmp(b->name, "scratch_data", strlen("scratch_data"))) {
75 handles->scratch_data = b->data;
76 handles->scratch_data_size = b->size;
77 } else if (!strncmp(b->name, "inputs", strlen("inputs"))) {
78 handles->inputs = (VelaIOs*)b->data;
79 } else if (!strncmp(b->name, "outputs", strlen("outputs"))) {
80 handles->outputs = (VelaIOs*)b->data;
81 } else if (!strncmp(
82 b->name, "vela_end_stream", strlen("vela_end_stream"))) {
83 // expect vela_end_stream last
84 if (ptr - data != size) {
85 ET_LOG(Error, "Expected vela binary to end with vela_end_stream");
86 return false;
87 }
88 return true;
89 } else {
90 // Unrecognised block name
91 ET_LOG(Error, "Invalid block name or malformed binary");
92 return false;
93 }
94 }
95
96 // We've fallen off the end without finding vela_end_stream
97 return false;
98 }
99
100 } // namespace arm
101 } // namespace backends
102 } // namespace executorch
103