xref: /aosp_15_r20/external/executorch/backends/arm/runtime/VelaBinStream.cpp (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
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