@deroll/cmio 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/LICENSE +202 -0
- package/README.md +122 -0
- package/binding.gyp +53 -0
- package/deps/machine-guest-tools/AUTHORS +7 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/abi.h +589 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/buf.h +82 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/io.h +168 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/keccak.h +131 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/merkle.h +118 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/rollup.h +260 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/include/libcmt/util.h +34 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/abi.c +315 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/buf.c +121 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/io-mock.c +319 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/io.c +164 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/keccak.c +156 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/merkle.c +202 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/rollup.c +455 -0
- package/deps/machine-guest-tools/sys-utils/libcmt/src/util.c +52 -0
- package/lib/index.d.mts +18 -0
- package/lib/index.d.ts +162 -0
- package/lib/index.js +230 -0
- package/lib/index.mjs +19 -0
- package/package.json +70 -0
- package/prebuilds/darwin-arm64/@deroll+cmio.node +0 -0
- package/src/addon.cc +411 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/* Copyright Cartesi and individual authors (see AUTHORS)
|
|
2
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
#include "libcmt/io.h"
|
|
17
|
+
#include "libcmt/util.h"
|
|
18
|
+
|
|
19
|
+
#include <errno.h>
|
|
20
|
+
#include <stdio.h>
|
|
21
|
+
#include <stdlib.h>
|
|
22
|
+
#include <string.h>
|
|
23
|
+
|
|
24
|
+
/** track the number of open "devices". Mimic the kernel driver behavior by limiting it to 1 */
|
|
25
|
+
static int open_count = 0;
|
|
26
|
+
|
|
27
|
+
int cmt_io_init(cmt_io_driver_t *_me) {
|
|
28
|
+
if (!_me) {
|
|
29
|
+
return -EINVAL;
|
|
30
|
+
}
|
|
31
|
+
if (open_count) {
|
|
32
|
+
return -EBUSY;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
open_count++;
|
|
36
|
+
cmt_io_driver_mock_t *me = &_me->mock;
|
|
37
|
+
|
|
38
|
+
size_t tx_length = 2U << 20; // 2MB
|
|
39
|
+
size_t rx_length = 2U << 20; // 2MB
|
|
40
|
+
cmt_buf_init(me->tx, tx_length, malloc(tx_length));
|
|
41
|
+
cmt_buf_init(me->rx, rx_length, malloc(rx_length));
|
|
42
|
+
|
|
43
|
+
if (!me->tx->begin || !me->rx->begin) {
|
|
44
|
+
free(me->tx->begin);
|
|
45
|
+
free(me->rx->begin);
|
|
46
|
+
return -ENOMEM;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
char *inputs = getenv("CMT_INPUTS");
|
|
50
|
+
if (inputs) {
|
|
51
|
+
cmt_buf_init(&me->inputs_left, strlen(inputs), inputs);
|
|
52
|
+
} else {
|
|
53
|
+
cmt_buf_init(&me->inputs_left, 0, "");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// in case the user writes something before loading any input
|
|
57
|
+
strcpy(me->input_filename, "none");
|
|
58
|
+
strcpy(me->input_fileext, ".bin");
|
|
59
|
+
|
|
60
|
+
me->input_seq = 0;
|
|
61
|
+
me->output_seq = 0;
|
|
62
|
+
me->report_seq = 0;
|
|
63
|
+
me->exception_seq = 0;
|
|
64
|
+
me->gio_seq = 0;
|
|
65
|
+
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void cmt_io_fini(cmt_io_driver_t *_me) {
|
|
70
|
+
if (!_me) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (open_count == 0) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
open_count--;
|
|
79
|
+
cmt_io_driver_mock_t *me = &_me->mock;
|
|
80
|
+
|
|
81
|
+
free(me->tx->begin);
|
|
82
|
+
free(me->rx->begin);
|
|
83
|
+
|
|
84
|
+
memset(_me, 0, sizeof(*_me));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
cmt_buf_t cmt_io_get_tx(cmt_io_driver_t *me) {
|
|
88
|
+
cmt_buf_t empty = {NULL, NULL};
|
|
89
|
+
if (!me) {
|
|
90
|
+
return empty;
|
|
91
|
+
}
|
|
92
|
+
return *me->mock.tx;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
cmt_buf_t cmt_io_get_rx(cmt_io_driver_t *me) {
|
|
96
|
+
cmt_buf_t empty = {NULL, NULL};
|
|
97
|
+
if (!me) {
|
|
98
|
+
return empty;
|
|
99
|
+
}
|
|
100
|
+
return *me->mock.rx;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static int load_next_input(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
104
|
+
cmt_buf_t current_input;
|
|
105
|
+
char filepath[128] = {0};
|
|
106
|
+
if (!cmt_buf_split_by_comma(¤t_input, &me->inputs_left)) {
|
|
107
|
+
return -EINVAL;
|
|
108
|
+
}
|
|
109
|
+
// NOLINTNEXTLINE(cert-err34-c,clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
|
110
|
+
if (sscanf((char *) current_input.begin, "%d:%127[^,]", &me->input_type, filepath) != 2) {
|
|
111
|
+
return -EINVAL;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
size_t file_length = 0;
|
|
115
|
+
int rc = cmt_util_read_whole_file(filepath, cmt_buf_length(me->rx), me->rx->begin, &file_length);
|
|
116
|
+
if (rc) {
|
|
117
|
+
if (cmt_util_debug_enabled()) {
|
|
118
|
+
(void) fprintf(stderr, "failed to load \"%s\". %s\n", filepath, strerror(-rc));
|
|
119
|
+
}
|
|
120
|
+
return rc;
|
|
121
|
+
}
|
|
122
|
+
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
|
123
|
+
if (sscanf(filepath, " %127[^.]%15s", me->input_filename, me->input_fileext) != 2) {
|
|
124
|
+
if (cmt_util_debug_enabled()) {
|
|
125
|
+
(void) fprintf(stderr, "failed to parse filename: \"%s\"\n", filepath);
|
|
126
|
+
}
|
|
127
|
+
return -EINVAL;
|
|
128
|
+
}
|
|
129
|
+
rr->reason = me->input_type;
|
|
130
|
+
rr->data = file_length;
|
|
131
|
+
|
|
132
|
+
me->output_seq = 0;
|
|
133
|
+
me->report_seq = 0;
|
|
134
|
+
me->exception_seq = 0;
|
|
135
|
+
|
|
136
|
+
if (cmt_util_debug_enabled()) {
|
|
137
|
+
(void) fprintf(stderr, "processing filename: \"%s\" (%lu), type: %d\n", filepath, file_length, me->input_type);
|
|
138
|
+
}
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static int store_output(cmt_io_driver_mock_t *me, const char *filepath, struct cmt_io_yield *rr) {
|
|
143
|
+
if (rr->data > cmt_buf_length(me->rx)) {
|
|
144
|
+
return -ENOBUFS;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
int rc = cmt_util_write_whole_file(filepath, rr->data, me->tx->begin);
|
|
148
|
+
if (rc) {
|
|
149
|
+
(void) fprintf(stderr, "failed to store \"%s\". %s\n", filepath, strerror(-rc));
|
|
150
|
+
return rc;
|
|
151
|
+
}
|
|
152
|
+
if (cmt_util_debug_enabled()) {
|
|
153
|
+
(void) fprintf(stderr, "wrote filename: \"%s\" (%u)\n", filepath, rr->data);
|
|
154
|
+
}
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static int store_next_output(cmt_io_driver_mock_t *me, char *ns, int *seq, struct cmt_io_yield *rr) {
|
|
159
|
+
char filepath[128 + 32 + 8 + 16];
|
|
160
|
+
// NOLINTNEXTLINE(cert-err33-c, clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
|
161
|
+
snprintf(filepath, sizeof filepath, "%s.%s%d%s", me->input_filename, ns, (*seq)++, me->input_fileext);
|
|
162
|
+
return store_output(me, filepath, rr);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static int mock_progress(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
166
|
+
(void) me;
|
|
167
|
+
if (rr->cmd != HTIF_YIELD_CMD_AUTOMATIC) {
|
|
168
|
+
(void) fprintf(stderr, "Expected cmd to be AUTOMATIC\n");
|
|
169
|
+
return -EINVAL;
|
|
170
|
+
}
|
|
171
|
+
(void) fprintf(stderr, "Progress: %6.2f\n", (double) rr->data / 10);
|
|
172
|
+
return 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static int mock_rx_accepted(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
176
|
+
if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
|
|
177
|
+
(void) fprintf(stderr, "Expected cmd to be MANUAL\n");
|
|
178
|
+
return -EINVAL;
|
|
179
|
+
}
|
|
180
|
+
if (me->input_seq++) { // skip the first
|
|
181
|
+
char filepath[128 + 32 + 8 + 16];
|
|
182
|
+
// NOLINTNEXTLINE(cert-err33-c, clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
|
|
183
|
+
snprintf(filepath, sizeof filepath, "%s.outputs_root_hash%s", me->input_filename, me->input_fileext);
|
|
184
|
+
int rc = store_output(me, filepath, rr);
|
|
185
|
+
if (rc) {
|
|
186
|
+
return rc;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (load_next_input(me, rr)) {
|
|
190
|
+
return -ENODATA;
|
|
191
|
+
}
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
static int mock_rx_rejected(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
196
|
+
if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
|
|
197
|
+
(void) fprintf(stderr, "Expected cmd to be MANUAL\n");
|
|
198
|
+
return -EINVAL;
|
|
199
|
+
}
|
|
200
|
+
(void) fprintf(stderr, "%s:%d no revert for the mock implementation\n", __FILE__, __LINE__);
|
|
201
|
+
if (load_next_input(me, rr)) {
|
|
202
|
+
return -ENOSYS;
|
|
203
|
+
}
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
static int mock_tx_output(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
208
|
+
if (rr->cmd != HTIF_YIELD_CMD_AUTOMATIC) {
|
|
209
|
+
(void) fprintf(stderr, "Expected cmd to be AUTOMATIC\n");
|
|
210
|
+
return -EINVAL;
|
|
211
|
+
}
|
|
212
|
+
return store_next_output(me, "output-", &me->output_seq, rr);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static int mock_tx_report(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
216
|
+
if (rr->cmd != HTIF_YIELD_CMD_AUTOMATIC) {
|
|
217
|
+
(void) fprintf(stderr, "Expected cmd to be AUTOMATIC\n");
|
|
218
|
+
return -EINVAL;
|
|
219
|
+
}
|
|
220
|
+
return store_next_output(me, "report-", &me->report_seq, rr);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
static int mock_tx_exception(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
224
|
+
if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
|
|
225
|
+
(void) fprintf(stderr, "Expected cmd to be MANUAL\n");
|
|
226
|
+
return -EINVAL;
|
|
227
|
+
}
|
|
228
|
+
return store_next_output(me, "exception-", &me->exception_seq, rr);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
static int mock_tx_gio(cmt_io_driver_mock_t *me, struct cmt_io_yield *rr) {
|
|
232
|
+
int rc = 0;
|
|
233
|
+
if (rr->cmd != HTIF_YIELD_CMD_MANUAL) {
|
|
234
|
+
(void) fprintf(stderr, "Expected cmd to be MANUAL\n");
|
|
235
|
+
return -EINVAL;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
rc = store_next_output(me, "gio-", &me->gio_seq, rr);
|
|
239
|
+
if (rc) {
|
|
240
|
+
return rc;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
rc = load_next_input(me, rr);
|
|
244
|
+
if (rc) {
|
|
245
|
+
return rc;
|
|
246
|
+
}
|
|
247
|
+
return 0;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* These behaviours are defined by the cartesi-machine emulator */
|
|
251
|
+
static int cmt_io_yield_inner(cmt_io_driver_t *_me, struct cmt_io_yield *rr) {
|
|
252
|
+
cmt_io_driver_mock_t *me = &_me->mock;
|
|
253
|
+
|
|
254
|
+
if (rr->cmd == HTIF_YIELD_CMD_MANUAL) {
|
|
255
|
+
switch (rr->reason) {
|
|
256
|
+
case HTIF_YIELD_MANUAL_REASON_RX_ACCEPTED:
|
|
257
|
+
return mock_rx_accepted(me, rr);
|
|
258
|
+
case HTIF_YIELD_MANUAL_REASON_RX_REJECTED:
|
|
259
|
+
return mock_rx_rejected(me, rr);
|
|
260
|
+
case HTIF_YIELD_MANUAL_REASON_TX_EXCEPTION:
|
|
261
|
+
return mock_tx_exception(me, rr);
|
|
262
|
+
default:
|
|
263
|
+
return mock_tx_gio(me, rr);
|
|
264
|
+
}
|
|
265
|
+
} else if (rr->cmd == HTIF_YIELD_CMD_AUTOMATIC) {
|
|
266
|
+
switch (rr->reason) {
|
|
267
|
+
case HTIF_YIELD_AUTOMATIC_REASON_PROGRESS:
|
|
268
|
+
return mock_progress(me, rr);
|
|
269
|
+
case HTIF_YIELD_AUTOMATIC_REASON_TX_OUTPUT:
|
|
270
|
+
return mock_tx_output(me, rr);
|
|
271
|
+
case HTIF_YIELD_AUTOMATIC_REASON_TX_REPORT:
|
|
272
|
+
return mock_tx_report(me, rr);
|
|
273
|
+
default:
|
|
274
|
+
return -EINVAL;
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
return -EINVAL;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return 0;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/* emulate io.c:cmt_io_yield behavior (go and check it does if you change it) */
|
|
284
|
+
int cmt_io_yield(cmt_io_driver_t *_me, struct cmt_io_yield *rr) {
|
|
285
|
+
if (!_me) {
|
|
286
|
+
return -EINVAL;
|
|
287
|
+
}
|
|
288
|
+
if (!rr) {
|
|
289
|
+
return -EINVAL;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
bool debug = cmt_util_debug_enabled();
|
|
293
|
+
if (debug) {
|
|
294
|
+
(void) fprintf(stderr,
|
|
295
|
+
"tohost {\n"
|
|
296
|
+
"\t.dev = %d,\n"
|
|
297
|
+
"\t.cmd = %d,\n"
|
|
298
|
+
"\t.reason = %d,\n"
|
|
299
|
+
"\t.data = %d,\n"
|
|
300
|
+
"};\n",
|
|
301
|
+
rr->dev, rr->cmd, rr->reason, rr->data);
|
|
302
|
+
}
|
|
303
|
+
int rc = cmt_io_yield_inner(_me, rr);
|
|
304
|
+
if (rc) {
|
|
305
|
+
return rc;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (debug) {
|
|
309
|
+
(void) fprintf(stderr,
|
|
310
|
+
"fromhost {\n"
|
|
311
|
+
"\t.dev = %d,\n"
|
|
312
|
+
"\t.cmd = %d,\n"
|
|
313
|
+
"\t.reason = %d,\n"
|
|
314
|
+
"\t.data = %d,\n"
|
|
315
|
+
"};\n",
|
|
316
|
+
rr->dev, rr->cmd, rr->reason, rr->data);
|
|
317
|
+
}
|
|
318
|
+
return rc;
|
|
319
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/* Copyright Cartesi and individual authors (see AUTHORS)
|
|
2
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
#include "libcmt/io.h"
|
|
17
|
+
#include "libcmt/util.h"
|
|
18
|
+
|
|
19
|
+
#include <stdbool.h>
|
|
20
|
+
#include <stdio.h>
|
|
21
|
+
#include <stdlib.h>
|
|
22
|
+
#include <string.h>
|
|
23
|
+
|
|
24
|
+
#include <errno.h>
|
|
25
|
+
#include <fcntl.h>
|
|
26
|
+
#include <sys/ioctl.h>
|
|
27
|
+
#include <sys/mman.h>
|
|
28
|
+
#include <unistd.h>
|
|
29
|
+
|
|
30
|
+
#include <linux/cartesi/cmio.h>
|
|
31
|
+
|
|
32
|
+
int cmt_io_init(cmt_io_driver_t *_me) {
|
|
33
|
+
int rc = 0;
|
|
34
|
+
|
|
35
|
+
if (!_me) {
|
|
36
|
+
return -EINVAL;
|
|
37
|
+
}
|
|
38
|
+
cmt_io_driver_ioctl_t *me = &_me->ioctl;
|
|
39
|
+
me->fd = open("/dev/cmio", O_RDWR);
|
|
40
|
+
|
|
41
|
+
if (me->fd < 0) {
|
|
42
|
+
rc = -errno;
|
|
43
|
+
return rc;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
struct cmio_setup setup;
|
|
47
|
+
if (ioctl(me->fd, IOCTL_CMIO_SETUP, &setup)) {
|
|
48
|
+
rc = -errno;
|
|
49
|
+
goto do_close;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void *tx = mmap((void *) setup.tx.data, setup.tx.length, PROT_READ | PROT_WRITE, MAP_SHARED, me->fd, 0);
|
|
53
|
+
if (tx == MAP_FAILED) {
|
|
54
|
+
rc = -errno;
|
|
55
|
+
goto do_close;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void *rx = mmap((void *) setup.rx.data, setup.rx.length, PROT_READ, MAP_SHARED, me->fd, 0);
|
|
59
|
+
if (rx == MAP_FAILED) {
|
|
60
|
+
rc = -errno;
|
|
61
|
+
goto do_unmap;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
cmt_buf_init(me->tx, setup.tx.length, tx);
|
|
65
|
+
cmt_buf_init(me->rx, setup.rx.length, rx);
|
|
66
|
+
return 0;
|
|
67
|
+
|
|
68
|
+
do_unmap:
|
|
69
|
+
munmap(tx, setup.tx.length);
|
|
70
|
+
do_close:
|
|
71
|
+
close(me->fd);
|
|
72
|
+
return rc;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
void cmt_io_fini(cmt_io_driver_t *_me) {
|
|
76
|
+
if (!_me) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
cmt_io_driver_ioctl_t *me = &_me->ioctl;
|
|
80
|
+
|
|
81
|
+
munmap(me->tx->begin, cmt_buf_length(me->tx));
|
|
82
|
+
munmap(me->rx->begin, cmt_buf_length(me->rx));
|
|
83
|
+
close(me->fd);
|
|
84
|
+
|
|
85
|
+
memset(me, 0, sizeof(*me));
|
|
86
|
+
me->fd = -1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
cmt_buf_t cmt_io_get_tx(cmt_io_driver_t *me) {
|
|
90
|
+
const cmt_buf_t empty = {NULL, NULL};
|
|
91
|
+
if (!me) {
|
|
92
|
+
return empty;
|
|
93
|
+
}
|
|
94
|
+
return *me->ioctl.tx;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
cmt_buf_t cmt_io_get_rx(cmt_io_driver_t *me) {
|
|
98
|
+
const cmt_buf_t empty = {NULL, NULL};
|
|
99
|
+
if (!me) {
|
|
100
|
+
return empty;
|
|
101
|
+
}
|
|
102
|
+
return *me->ioctl.rx;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static uint64_t pack(struct cmt_io_yield *rr) {
|
|
106
|
+
// clang-format off
|
|
107
|
+
return ((uint64_t) rr->dev << 56)
|
|
108
|
+
| ((uint64_t) rr->cmd << 56 >> 8)
|
|
109
|
+
| ((uint64_t) rr->reason << 48 >> 16)
|
|
110
|
+
| ((uint64_t) rr->data << 32 >> 32);
|
|
111
|
+
// clang-format on
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static struct cmt_io_yield unpack(uint64_t x) {
|
|
115
|
+
// clang-format off
|
|
116
|
+
struct cmt_io_yield out = {
|
|
117
|
+
x >> 56,
|
|
118
|
+
x << 8 >> 56,
|
|
119
|
+
x << 16 >> 48,
|
|
120
|
+
x << 32 >> 32,
|
|
121
|
+
};
|
|
122
|
+
// clang-format on
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* io-mock.c:cmt_io_yield emulates this behavior (go and check it does if you change it) */
|
|
127
|
+
int cmt_io_yield(cmt_io_driver_t *_me, struct cmt_io_yield *rr) {
|
|
128
|
+
if (!_me) {
|
|
129
|
+
return -EINVAL;
|
|
130
|
+
}
|
|
131
|
+
if (!rr) {
|
|
132
|
+
return -EINVAL;
|
|
133
|
+
}
|
|
134
|
+
cmt_io_driver_ioctl_t *me = &_me->ioctl;
|
|
135
|
+
|
|
136
|
+
bool debug = cmt_util_debug_enabled();
|
|
137
|
+
if (debug) {
|
|
138
|
+
(void) fprintf(stderr,
|
|
139
|
+
"tohost {\n"
|
|
140
|
+
"\t.dev = %d,\n"
|
|
141
|
+
"\t.cmd = %d,\n"
|
|
142
|
+
"\t.reason = %d,\n"
|
|
143
|
+
"\t.data = %d,\n"
|
|
144
|
+
"};\n",
|
|
145
|
+
rr->dev, rr->cmd, rr->reason, rr->data);
|
|
146
|
+
}
|
|
147
|
+
uint64_t req = pack(rr);
|
|
148
|
+
if (ioctl(me->fd, IOCTL_CMIO_YIELD, &req)) {
|
|
149
|
+
return -errno;
|
|
150
|
+
}
|
|
151
|
+
*rr = unpack(req);
|
|
152
|
+
|
|
153
|
+
if (debug) {
|
|
154
|
+
(void) fprintf(stderr,
|
|
155
|
+
"fromhost {\n"
|
|
156
|
+
"\t.dev = %d,\n"
|
|
157
|
+
"\t.cmd = %d,\n"
|
|
158
|
+
"\t.reason = %d,\n"
|
|
159
|
+
"\t.data = %d,\n"
|
|
160
|
+
"};\n",
|
|
161
|
+
rr->dev, rr->cmd, rr->reason, rr->data);
|
|
162
|
+
}
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/* Copyright Cartesi and individual authors (see AUTHORS)
|
|
2
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
#include "libcmt/keccak.h"
|
|
17
|
+
#include "libcmt/abi.h"
|
|
18
|
+
|
|
19
|
+
#include <string.h>
|
|
20
|
+
|
|
21
|
+
// Helper macros for stringification
|
|
22
|
+
#define TO_STRING_HELPER(X) #X
|
|
23
|
+
#define TO_STRING(X) TO_STRING_HELPER(X)
|
|
24
|
+
|
|
25
|
+
// Define loop unrolling depending on the compiler
|
|
26
|
+
#if defined(__clang__)
|
|
27
|
+
#define UNROLL_LOOP(n) _Pragma(TO_STRING(unroll(n)))
|
|
28
|
+
#elif defined(__GNUC__) && !defined(__clang__)
|
|
29
|
+
#define UNROLL_LOOP(n) _Pragma(TO_STRING(GCC unroll(n)))
|
|
30
|
+
#else
|
|
31
|
+
#define UNROLL_LOOP(n)
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
|
|
35
|
+
|
|
36
|
+
/** Initialize a keccak state
|
|
37
|
+
* @note don't port. use @ref cmt_keccak_init */
|
|
38
|
+
// clang-format off
|
|
39
|
+
#define CMT_KECCAK_INIT(STATE) \
|
|
40
|
+
{ \
|
|
41
|
+
.st.q = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, \
|
|
42
|
+
.pt = 0, .rsiz = 200 - 2 * CMT_KECCAK_LENGTH, \
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// clang-format on
|
|
46
|
+
|
|
47
|
+
static void keccakf(uint64_t st[25]) {
|
|
48
|
+
// clang-format off
|
|
49
|
+
const uint64_t keccakf_rndc[24] = {
|
|
50
|
+
0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, 0x000000000000808b,
|
|
51
|
+
0x0000000080000001, 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, 0x0000000000000088,
|
|
52
|
+
0x0000000080008009, 0x000000008000000a, 0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
|
|
53
|
+
0x8000000000008003, 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a,
|
|
54
|
+
0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
|
|
55
|
+
};
|
|
56
|
+
const int keccakf_rotc[24] = { 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
|
57
|
+
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 };
|
|
58
|
+
const int keccakf_piln[24] = { 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
|
59
|
+
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 };
|
|
60
|
+
// clang-format on
|
|
61
|
+
|
|
62
|
+
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
|
63
|
+
for (int i = 0; i < 25; i++) {
|
|
64
|
+
st[i] = __builtin_bswap64((uint64_t *) (st[i]));
|
|
65
|
+
}
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
for (int r = 0; r < 24; r++) {
|
|
69
|
+
uint64_t t = 0;
|
|
70
|
+
uint64_t bc[5];
|
|
71
|
+
|
|
72
|
+
// Theta
|
|
73
|
+
UNROLL_LOOP(5)
|
|
74
|
+
for (int i = 0; i < 5; i++) {
|
|
75
|
+
bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
UNROLL_LOOP(5)
|
|
79
|
+
for (int i = 0; i < 5; i++) {
|
|
80
|
+
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
|
|
81
|
+
for (int j = 0; j < 25; j += 5) {
|
|
82
|
+
st[j + i] ^= t;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Rho Pi
|
|
87
|
+
t = st[1];
|
|
88
|
+
UNROLL_LOOP(24)
|
|
89
|
+
for (int i = 0; i < 24; i++) {
|
|
90
|
+
int j = keccakf_piln[i];
|
|
91
|
+
bc[0] = st[j];
|
|
92
|
+
st[j] = ROTL64(t, keccakf_rotc[i]);
|
|
93
|
+
t = bc[0];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Chi
|
|
97
|
+
UNROLL_LOOP(25)
|
|
98
|
+
for (int j = 0; j < 25; j += 5) {
|
|
99
|
+
for (int i = 0; i < 5; i++) {
|
|
100
|
+
bc[i] = st[j + i];
|
|
101
|
+
}
|
|
102
|
+
for (int i = 0; i < 5; i++) {
|
|
103
|
+
st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Iota
|
|
108
|
+
st[0] ^= keccakf_rndc[r];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
|
|
112
|
+
for (int i = 0; i < 25; i++) {
|
|
113
|
+
st[i] = __builtin_bswap64(st[i]);
|
|
114
|
+
}
|
|
115
|
+
#endif
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
void cmt_keccak_init(cmt_keccak_t *state) {
|
|
119
|
+
*state = (cmt_keccak_t) CMT_KECCAK_INIT(state);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
void cmt_keccak_update(cmt_keccak_t *state, size_t n, const void *data) {
|
|
123
|
+
int j = state->pt;
|
|
124
|
+
for (size_t i = 0; i < n; i++) {
|
|
125
|
+
state->st.b[j++] ^= ((const uint8_t *) data)[i];
|
|
126
|
+
if (j >= state->rsiz) {
|
|
127
|
+
keccakf(state->st.q);
|
|
128
|
+
j = 0;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
state->pt = j;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
void cmt_keccak_final(cmt_keccak_t *state, void *md) {
|
|
135
|
+
state->st.b[state->pt] ^= 0x01;
|
|
136
|
+
state->st.b[state->rsiz - 1] ^= 0x80;
|
|
137
|
+
keccakf(state->st.q);
|
|
138
|
+
|
|
139
|
+
for (int i = 0; i < CMT_KECCAK_LENGTH; i++) {
|
|
140
|
+
((uint8_t *) md)[i] = state->st.b[i];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
uint8_t *cmt_keccak_data(size_t length, const void *data, uint8_t md[CMT_KECCAK_LENGTH]) {
|
|
145
|
+
cmt_keccak_t c[1];
|
|
146
|
+
cmt_keccak_init(c);
|
|
147
|
+
cmt_keccak_update(c, length, data);
|
|
148
|
+
cmt_keccak_final(c, md);
|
|
149
|
+
return md;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
uint32_t cmt_keccak_funsel(const char *decl) {
|
|
153
|
+
uint8_t md[32];
|
|
154
|
+
cmt_keccak_data(strlen(decl), decl, md);
|
|
155
|
+
return CMT_ABI_FUNSEL(md[0], md[1], md[2], md[3]);
|
|
156
|
+
}
|