diff --git a/chrecd/interface/chre_slpi.c b/chrecd/interface/chre_slpi.c new file mode 100644 index 0000000..450a476 --- /dev/null +++ b/chrecd/interface/chre_slpi.c @@ -0,0 +1,39 @@ +/* + * Context Hub Runtime Environment interface - method definitions + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +const struct hrpc_method_def_interp4 chre_slpi_start_thread_def = { + .msg_id = 0, + .n_args = 0, + .args = NULL, + .n_inner_types = 0, + .inner_types = NULL, +}; + +const struct hrpc_method_def_interp4 chre_slpi_wait_on_thread_exit_def = { + .msg_id = 1, + .n_args = 0, + .args = NULL, + .n_inner_types = 0, + .inner_types = NULL, +}; diff --git a/chrecd/interface/chre_slpi.h b/chrecd/interface/chre_slpi.h new file mode 100644 index 0000000..4c33b68 --- /dev/null +++ b/chrecd/interface/chre_slpi.h @@ -0,0 +1,41 @@ +/* + * Context Hub Runtime Environment interface - API + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INTERFACE_CHRE_SLPI_H +#define INTERFACE_CHRE_SLPI_H + +#include +#include + +extern struct hrpc_method_def_interp4 chre_slpi_start_thread_def; +static inline int chre_slpi_start_thread(int fd, uint32_t hdl) +{ + return hexagonrpc(&chre_slpi_start_thread_def, fd, hdl); +} + +extern struct hrpc_method_def_interp4 chre_slpi_wait_on_thread_exit_def; +static inline int chre_slpi_wait_on_thread_exit(int fd, uint32_t hdl) +{ + return hexagonrpc(&chre_slpi_wait_on_thread_exit_def, fd, hdl); +} + + +#endif /* INTERFACE_CHRE_SLPI_H */ diff --git a/chrecd/interfaces/chre_slpi.def b/chrecd/interfaces/chre_slpi.def deleted file mode 100644 index d9aaeff..0000000 --- a/chrecd/interfaces/chre_slpi.def +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Context Hub Runtime Environment interface - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef INTERFACE_CHRE_SLPI_DEF -#define INTERFACE_CHRE_SLPI_DEF - -#include - -HEXAGONRPC_DEFINE_REMOTE_METHOD(0, chre_slpi_start_thread, 0, 0, 0, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(1, chre_slpi_wait_on_thread_exit, 0, 0, 0, 0) - -#endif /* INTERFACE_CHRE_SLPI_DEF */ diff --git a/chrecd/main.c b/chrecd/main.c index 3dadc40..7eed53d 100644 --- a/chrecd/main.c +++ b/chrecd/main.c @@ -20,105 +20,42 @@ */ #include -#include -#include +#include #include #include #include #include -#include "interfaces/chre_slpi.def" - -/* TODO move these to libhexagonrpc since most clients use them */ -static int remotectl_open(int fd, char *name, struct fastrpc_context **ctx, void (*err_cb)(const char *err)) -{ - uint32_t handle; - int32_t dlret; - char err[256]; - int ret; - - ret = fastrpc2(&remotectl_open_def, fd, REMOTECTL_HANDLE, - strlen(name) + 1, name, - &handle, - &dlret, - 256, err); - - if (ret == -1) { - err_cb(strerror(errno)); - return ret; - } - - if (dlret == -5) { - err_cb(err); - return dlret; - } - - *ctx = fastrpc_create_context(fd, handle); - - return ret; -} - -static int remotectl_close(struct fastrpc_context *ctx, void (*err_cb)(const char *err)) -{ - uint32_t dlret; - char err[256]; - int ret; - - ret = fastrpc2(&remotectl_close_def, ctx->fd, REMOTECTL_HANDLE, - ctx->handle, - &dlret, - 256, err); - - if (ret == -1) { - err_cb(strerror(errno)); - return ret; - } - - fastrpc_destroy_context(ctx); - - return ret; -} - -static void remotectl_err(const char *err) -{ - fprintf(stderr, "Could not remotectl: %s\n", err); -} - -static int chre_slpi_start_thread(struct fastrpc_context *ctx) -{ - return fastrpc(&chre_slpi_start_thread_def, ctx); -} - -static int chre_slpi_wait_on_thread_exit(struct fastrpc_context *ctx) -{ - return fastrpc(&chre_slpi_wait_on_thread_exit_def, ctx); -} +#include "interface/chre_slpi.h" int main() { - struct fastrpc_context *ctx; + uint32_t hdl; + char err[256]; int fd, ret; fd = hexagonrpc_fd_from_env(); if (fd == -1) return 1; - ret = remotectl_open(fd, "chre_slpi", &ctx, remotectl_err); - if (ret) + ret = hexagonrpc_open(fd, "chre_slpi", &hdl, 256, err); + if (ret) { + fprintf(stderr, "Could not open CHRE remote interface: %s\n", err); return 1; + } - ret = chre_slpi_start_thread(ctx); + ret = chre_slpi_start_thread(fd, hdl); if (ret) { fprintf(stderr, "Could not start CHRE\n"); goto err; } - ret = chre_slpi_wait_on_thread_exit(ctx); + ret = chre_slpi_wait_on_thread_exit(fd, hdl); if (ret) { fprintf(stderr, "Could not wait for CHRE thread\n"); goto err; } err: - remotectl_close(ctx, remotectl_err); + hexagonrpc_close(fd, hdl); } diff --git a/chrecd/meson.build b/chrecd/meson.build index 983d742..2108a79 100644 --- a/chrecd/meson.build +++ b/chrecd/meson.build @@ -1,5 +1,5 @@ executable('chrecd', - 'interfaces.c', + 'interface/chre_slpi.c', 'main.c', c_args : cflags, include_directories : include, diff --git a/hexagonrpcd/apps_mem.c b/hexagonrpcd/apps_mem.c index f4d0bf9..1477f0b 100644 --- a/hexagonrpcd/apps_mem.c +++ b/hexagonrpcd/apps_mem.c @@ -20,15 +20,15 @@ */ #include +#include #include #include #include #include #include -#include "aee_error.h" #include "apps_mem.h" -#include "interfaces/apps_mem.def" +#include "interface/apps_mem.h" #include "listener.h" // See fastrpc.git/src/apps_mem_imp.c @@ -71,11 +71,9 @@ static uint32_t apps_mem_request_map64(void *data, mmap.size = first_in->len; ret = ioctl(ctx->fd, FASTRPC_IOCTL_MMAP, &mmap); - if (ret == -1) { - perror("Memory map failed"); - return AEE_EFAILED; - } else if (ret) { - fprintf(stderr, "Memory map failed: %s\n", aee_strerror[ret]); + if (ret) { + fprintf(stderr, "Memory map failed: %s\n", + hexagonrpc_strerror(ret)); return ret; } diff --git a/hexagonrpcd/apps_std.c b/hexagonrpcd/apps_std.c index 06519f8..3ae0e8d 100644 --- a/hexagonrpcd/apps_std.c +++ b/hexagonrpcd/apps_std.c @@ -20,15 +20,15 @@ */ #include +#include #include #include #include #include #include -#include "aee_error.h" -#include "interfaces/apps_std.def" #include "hexagonfs.h" +#include "interface/apps_std.h" #include "iobuffer.h" #include "listener.h" diff --git a/chrecd/interfaces.c b/hexagonrpcd/interface/adsp_default_listener.c similarity index 57% rename from chrecd/interfaces.c rename to hexagonrpcd/interface/adsp_default_listener.c index 26b21ba..a632abb 100644 --- a/chrecd/interfaces.c +++ b/hexagonrpcd/interface/adsp_default_listener.c @@ -1,11 +1,11 @@ /* - * FastRPC interface list for building method definitions + * FastRPC reverse tunnel registration interface - method definitions * - * Copyright (C) 2023 The Sensor Shell Contributors + * Copyright (C) 2025 HexagonRPC Contributors * - * This file is part of sensh. + * This file is part of HexagonRPC. * - * Sensh is free software: you can redistribute it and/or modify + * HexagonRPC is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -19,6 +19,13 @@ * along with this program. If not, see . */ -#define HEXAGONRPC_BUILD_METHOD_DEFINITIONS 1 +#include +#include -#include "interfaces/chre_slpi.def" +const struct hrpc_method_def_interp4 adsp_default_listener_register_def = { + .msg_id = 0, + .n_args = 0, + .args = NULL, + .n_inner_types = 0, + .inner_types = NULL, +}; diff --git a/hexagonrpcd/interface/adsp_default_listener.h b/hexagonrpcd/interface/adsp_default_listener.h new file mode 100644 index 0000000..c5cea3a --- /dev/null +++ b/hexagonrpcd/interface/adsp_default_listener.h @@ -0,0 +1,34 @@ +/* + * FastRPC reverse tunnel registration interface - API + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INTERFACE_ADSP_DEFAULT_LISTENER_H +#define INTERFACE_ADSP_DEFAULT_LISTENER_H + +#include +#include + +extern struct hrpc_method_def_interp4 adsp_default_listener_register_def; +static inline int adsp_default_listener_register(int fd, uint32_t hdl) +{ + return hexagonrpc(&adsp_default_listener_register_def, fd, hdl); +} + +#endif /* INTERFACE_ADSP_DEFAULT_LISTENER_H */ diff --git a/hexagonrpcd/interface/adsp_listener.c b/hexagonrpcd/interface/adsp_listener.c new file mode 100644 index 0000000..d2197df --- /dev/null +++ b/hexagonrpcd/interface/adsp_listener.c @@ -0,0 +1,50 @@ +/* + * FastRPC reverse tunnel main interface - method definitions + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +const struct hrpc_method_def_interp4 adsp_listener_init2_def = { + .msg_id = 3, + .n_args = 0, + .args = NULL, + .n_inner_types = 0, + .inner_types = NULL, +}; + +struct hrpc_arg_def_interp4 adsp_listener_next2_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB_SEQ, sizeof(char) }, +}; + +const struct hrpc_method_def_interp4 adsp_listener_next2_def = { + .msg_id = 4, + .n_args = HRPC_ARRAY_SIZE(adsp_listener_next2_args), + .args = adsp_listener_next2_args, + .n_inner_types = 0, + .inner_types = NULL, +}; diff --git a/hexagonrpcd/interface/adsp_listener.h b/hexagonrpcd/interface/adsp_listener.h new file mode 100644 index 0000000..362d775 --- /dev/null +++ b/hexagonrpcd/interface/adsp_listener.h @@ -0,0 +1,54 @@ +/* + * FastRPC reverse tunnel main interface - API + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INTERFACE_ADSP_LISTENER_H +#define INTERFACE_ADSP_LISTENER_H + +#include +#include + +#define ADSP_LISTENER 3 + +extern struct hrpc_method_def_interp4 adsp_listener_init2_def; +static inline int adsp_listener_init2(int fd) +{ + return hexagonrpc(&adsp_listener_init2_def, fd, ADSP_LISTENER); +} + +extern struct hrpc_method_def_interp4 adsp_listener_next2_def; +static inline int adsp_listener_next2(int fd, + uint32_t ret_rctx, + uint32_t ret_res, + uint32_t ret_outbufs_len, const char *ret_outbufs, + uint32_t *rctx, + uint32_t *handle, + uint32_t *sc, + uint32_t *inbufs_len, + uint32_t inbufs_size, char *inbufs) +{ + return hexagonrpc(&adsp_listener_next2_def, fd, ADSP_LISTENER, + ret_rctx, ret_res, + ret_outbufs_len, (const void *) ret_outbufs, + rctx, handle, sc, inbufs_len, + inbufs_size, (void *) inbufs); +} + +#endif /* INTERFACE_ADSP_LISTENER_H */ diff --git a/hexagonrpcd/interface/apps_mem.c b/hexagonrpcd/interface/apps_mem.c new file mode 100644 index 0000000..018043f --- /dev/null +++ b/hexagonrpcd/interface/apps_mem.c @@ -0,0 +1,42 @@ +/* + * FastRPC memory mapping interface - method definitions + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +static struct hrpc_arg_def_interp4 apps_mem_request_map64_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_WORD, sizeof(uint64_t) }, + { HRPC_ARG_WORD, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, +}; + +const struct hrpc_method_def_interp4 apps_mem_request_map64_def = { + .msg_id = 2, + .n_args = HRPC_ARRAY_SIZE(apps_mem_request_map64_args), + .args = apps_mem_request_map64_args, + .n_inner_types = 0, + .inner_types = NULL, +}; diff --git a/libhexagonrpc/interfaces.c b/hexagonrpcd/interface/apps_mem.h similarity index 60% rename from libhexagonrpc/interfaces.c rename to hexagonrpcd/interface/apps_mem.h index b1ce1ab..6e7da96 100644 --- a/libhexagonrpc/interfaces.c +++ b/hexagonrpcd/interface/apps_mem.h @@ -1,11 +1,11 @@ /* - * FastRPC interface list for building common method definitions + * FastRPC memory mapping interface - API * - * Copyright (C) 2023 The Sensor Shell Contributors + * Copyright (C) 2025 HexagonRPC Contributors * - * This file is part of sensh. + * This file is part of HexagonRPC. * - * Sensh is free software: you can redistribute it and/or modify + * HexagonRPC is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. @@ -19,6 +19,11 @@ * along with this program. If not, see . */ -#define HEXAGONRPC_BUILD_METHOD_DEFINITIONS 1 +#ifndef INTERFACE_APPS_MEM_H +#define INTERFACE_APPS_MEM_H -#include +#include + +extern struct hrpc_method_def_interp4 apps_mem_request_map64_def; + +#endif /* INTERFACE_APPS_MEM_H */ diff --git a/hexagonrpcd/interface/apps_std.c b/hexagonrpcd/interface/apps_std.c new file mode 100644 index 0000000..67b3ace --- /dev/null +++ b/hexagonrpcd/interface/apps_std.c @@ -0,0 +1,184 @@ +/* + * FastRPC operating system interface - method definitions + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +static struct hrpc_arg_def_interp4 apps_std_freopen_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB_SEQ, sizeof(char) }, +}; + +const struct hrpc_method_def_interp4 apps_std_freopen_def = { + .msg_id = 1, + .n_args = HRPC_ARRAY_SIZE(apps_std_freopen_args), + .args = apps_std_freopen_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_fflush_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_fflush_def = { + .msg_id = 2, + .n_args = HRPC_ARRAY_SIZE(apps_std_fflush_args), + .args = apps_std_fflush_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_fclose_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_fclose_def = { + .msg_id = 3, + .n_args = HRPC_ARRAY_SIZE(apps_std_fclose_args), + .args = apps_std_fclose_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_fread_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB_SEQ, sizeof(char) }, +}; + +const struct hrpc_method_def_interp4 apps_std_fread_def = { + .msg_id = 4, + .n_args = HRPC_ARRAY_SIZE(apps_std_fread_args), + .args = apps_std_fread_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_fseek_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_WORD, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_fseek_def = { + .msg_id = 9, + .n_args = HRPC_ARRAY_SIZE(apps_std_fseek_args), + .args = apps_std_fseek_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_fopen_with_env_args[] = { + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_fopen_with_env_def = { + .msg_id = 19, + .n_args = HRPC_ARRAY_SIZE(apps_std_fopen_with_env_args), + .args = apps_std_fopen_with_env_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_opendir_args[] = { + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_opendir_def = { + .msg_id = 26, + .n_args = HRPC_ARRAY_SIZE(apps_std_opendir_args), + .args = apps_std_opendir_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_closedir_args[] = { + { HRPC_ARG_WORD, sizeof(uint64_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_closedir_def = { + .msg_id = 27, + .n_args = HRPC_ARRAY_SIZE(apps_std_closedir_args), + .args = apps_std_closedir_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_readdir_args[] = { + { HRPC_ARG_WORD, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(char) * 256 }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_readdir_def = { + .msg_id = 28, + .n_args = HRPC_ARRAY_SIZE(apps_std_readdir_args), + .args = apps_std_readdir_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_mkdir_args[] = { + { HRPC_ARG_BLOB, sizeof(char) }, + { HRPC_ARG_WORD, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_mkdir_def = { + .msg_id = 29, + .n_args = HRPC_ARRAY_SIZE(apps_std_mkdir_args), + .args = apps_std_mkdir_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static struct hrpc_arg_def_interp4 apps_std_stat_args[] = { + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint64_t) }, +}; + +const struct hrpc_method_def_interp4 apps_std_stat_def = { + .msg_id = 31, + .n_args = HRPC_ARRAY_SIZE(apps_std_stat_args), + .args = apps_std_stat_args, + .n_inner_types = 0, + .inner_types = NULL, +}; diff --git a/hexagonrpcd/interface/apps_std.h b/hexagonrpcd/interface/apps_std.h new file mode 100644 index 0000000..b80a1ca --- /dev/null +++ b/hexagonrpcd/interface/apps_std.h @@ -0,0 +1,39 @@ +/* + * FastRPC operating system interface - API + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INTERFACE_APPS_STD_H +#define INTERFACE_APPS_STD_H + +#include + +extern struct hrpc_method_def_interp4 apps_std_freopen_def; +extern struct hrpc_method_def_interp4 apps_std_fflush_def; +extern struct hrpc_method_def_interp4 apps_std_fclose_def; +extern struct hrpc_method_def_interp4 apps_std_fread_def; +extern struct hrpc_method_def_interp4 apps_std_fseek_def; +extern struct hrpc_method_def_interp4 apps_std_fopen_with_env_def; +extern struct hrpc_method_def_interp4 apps_std_opendir_def; +extern struct hrpc_method_def_interp4 apps_std_closedir_def; +extern struct hrpc_method_def_interp4 apps_std_readdir_def; +extern struct hrpc_method_def_interp4 apps_std_mkdir_def; +extern struct hrpc_method_def_interp4 apps_std_stat_def; + +#endif /* INTERFACE_APPS_STD_H */ diff --git a/hexagonrpcd/interfaces.c b/hexagonrpcd/interfaces.c deleted file mode 100644 index 3e64e63..0000000 --- a/hexagonrpcd/interfaces.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * FastRPC interface list for building method definitions - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#define HEXAGONRPC_BUILD_METHOD_DEFINITIONS 1 - -#include "interfaces/adsp_default_listener.def" -#include "interfaces/apps_mem.def" -#include "interfaces/apps_std.def" -#include "interfaces/adsp_listener.def" diff --git a/hexagonrpcd/interfaces/adsp_default_listener.def b/hexagonrpcd/interfaces/adsp_default_listener.def deleted file mode 100644 index 0e56ed5..0000000 --- a/hexagonrpcd/interfaces/adsp_default_listener.def +++ /dev/null @@ -1,29 +0,0 @@ -/* - * FastRPC reverse tunnel registration interface - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef INTERFACE_ADSP_DEFAULT_LISTENER_DEF -#define INTERFACE_ADSP_DEFAULT_LISTENER_DEF - -#include - -HEXAGONRPC_DEFINE_REMOTE_METHOD(0, adsp_default_listener_register, 0, 0, 0, 0) - -#endif /* INTERFACE_ADSP_DEFAULT_LISTENER_DEF */ diff --git a/hexagonrpcd/interfaces/adsp_listener.def b/hexagonrpcd/interfaces/adsp_listener.def deleted file mode 100644 index 4f521c0..0000000 --- a/hexagonrpcd/interfaces/adsp_listener.def +++ /dev/null @@ -1,32 +0,0 @@ -/* - * FastRPC reverse tunnel main interface - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef INTERFACE_ADSP_LISTENER_DEF -#define INTERFACE_ADSP_LISTENER_DEF - -#include - -#define ADSP_LISTENER_HANDLE 3 - -HEXAGONRPC_DEFINE_REMOTE_METHOD(3, adsp_listener_init2, 0, 0, 0, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(4, adsp_listener_next2, 2, 1, 4, 1) - -#endif /* INTERFACE_ADSP_LISTENER_DEF */ diff --git a/hexagonrpcd/interfaces/apps_mem.def b/hexagonrpcd/interfaces/apps_mem.def deleted file mode 100644 index 948b837..0000000 --- a/hexagonrpcd/interfaces/apps_mem.def +++ /dev/null @@ -1,29 +0,0 @@ -/* - * FastRPC operating system interface - * - * Copyright (C) 2024 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef INTERFACE_APPS_MEM_DEF -#define INTERFACE_APPS_MEM_DEF - -#include - -HEXAGONRPC_DEFINE_REMOTE_METHOD(2, apps_mem_request_map64, 8, 0, 4, 0) - -#endif /* INTERFACE_APPS_MEM_DEF */ diff --git a/hexagonrpcd/interfaces/apps_std.def b/hexagonrpcd/interfaces/apps_std.def deleted file mode 100644 index 2fbbdb1..0000000 --- a/hexagonrpcd/interfaces/apps_std.def +++ /dev/null @@ -1,38 +0,0 @@ -/* - * FastRPC operating system interface - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef INTERFACE_APPS_STD_DEF -#define INTERFACE_APPS_STD_DEF - -#include - -HEXAGONRPC_DEFINE_REMOTE_METHOD(1, apps_std_freopen, 1, 0, 1, 1) -HEXAGONRPC_DEFINE_REMOTE_METHOD(2, apps_std_fflush, 8, 0, 0, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(3, apps_std_fclose, 1, 0, 0, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(4, apps_std_fread, 1, 0, 2, 1) -HEXAGONRPC_DEFINE_REMOTE_METHOD(9, apps_std_fseek, 3, 0, 0, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(19, apps_std_fopen_with_env, 0, 4, 1, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(26, apps_std_opendir, 0, 1, 2, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(27, apps_std_closedir, 2, 0, 0, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(28, apps_std_readdir, 2, 0, 66, 0) -HEXAGONRPC_DEFINE_REMOTE_METHOD(31, apps_std_stat, 1, 1, 24, 0) - -#endif /* INTERFACE_APPS_STD_DEF */ diff --git a/hexagonrpcd/iobuffer.c b/hexagonrpcd/iobuffer.c index 6481651..0995f8e 100644 --- a/hexagonrpcd/iobuffer.c +++ b/hexagonrpcd/iobuffer.c @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#include +#include #include #include #include diff --git a/hexagonrpcd/iobuffer.h b/hexagonrpcd/iobuffer.h index 3b32cf6..de4218d 100644 --- a/hexagonrpcd/iobuffer.h +++ b/hexagonrpcd/iobuffer.h @@ -27,7 +27,7 @@ #include struct fastrpc_io_buffer { - uint32_t s; + size_t s; void *p; }; diff --git a/hexagonrpcd/listener.c b/hexagonrpcd/listener.c index 932c54d..33cbf75 100644 --- a/hexagonrpcd/listener.c +++ b/hexagonrpcd/listener.c @@ -20,117 +20,400 @@ */ #include -#include -#include +#include +#include #include +#include #include -#include "aee_error.h" -#include "interfaces/adsp_listener.def" +#include "interface/adsp_listener.h" #include "iobuffer.h" #include "listener.h" -static int adsp_listener_init2(int fd) +static int count_sizes_in_type4(const struct hrpc_inner_type_def_interp4 *type, + const struct fastrpc_io_buffer **curr_inbuf, + const struct fastrpc_io_buffer *inbufs_end, + const void **inst, const void *end) { - return fastrpc2(&adsp_listener_init2_def, fd, ADSP_LISTENER_HANDLE); + size_t size, i; + + for (i = 0; i < type->s; i++) { + switch (type->p[i].t) { + case HRPC_ARG_BLOB: + *inst = (const char *) *inst + type->p[i].d; + if (*inst > end) + return -1; + + break; + case HRPC_ARG_BLOB_SEQ: + if ((const void *) ((const uint32_t *) *inst + 1) > end) + return -1; + + if (*curr_inbuf >= inbufs_end) + return -1; + + size = *(const uint32_t *) *inst; + size *= type->p[i].d; + if ((*curr_inbuf)->s != size) + return -1; + + *inst = (const uint32_t *) *inst + 1; + (*curr_inbuf)++; + break; + default: + return -1; + } + } + + return 0; } -static int adsp_listener_next2(int fd, - uint32_t ret_rctx, - uint32_t ret_res, - uint32_t ret_outbuf_len, void *ret_outbuf, - uint32_t *rctx, - uint32_t *handle, - uint32_t *sc, - uint32_t *inbufs_len, - uint32_t inbufs_size, void *inbufs) +static int count_sizes_out_type4(const struct hrpc_inner_type_def_interp4 *type, + uint8_t *n_outbufs, + const void **inst, const void *end) { - return fastrpc2(&adsp_listener_next2_def, fd, ADSP_LISTENER_HANDLE, - ret_rctx, - ret_res, - ret_outbuf_len, ret_outbuf, - rctx, - handle, - sc, - inbufs_len, - inbufs_size, inbufs); + size_t i; + + for (i = 0; i < type->s; i++) { + switch (type->p[i].t) { + case HRPC_ARG_BLOB: + break; + case HRPC_ARG_BLOB_SEQ: + *inst = (const uint32_t *) *inst + 1; + if (*inst > end) + return -1; + + if (*n_outbufs == 0) + return -1; + (*n_outbufs)--; + break; + default: + return -1; + } + } + + return 0; } -static struct fastrpc_io_buffer *allocate_outbufs(const struct fastrpc_function_def_interp2 *def, - uint32_t *first_inbuf) +static int count_sizes4(const struct hrpc_method_def_interp4 *def, + uint8_t n_inbufs, uint8_t n_outbufs, + const struct fastrpc_io_buffer *inbufs) { - struct fastrpc_io_buffer *out; - size_t out_count; - size_t i, j; - off_t off; - uint32_t *sizes; - - out_count = def->out_bufs + (def->out_nums && 1); - /* - * POSIX allows malloc to return a non-NULL pointer to a zero-size area - * in memory. Since the code below assumes non-zero size if the pointer - * is non-NULL, exit early if we do not need to allocate anything. - */ - if (out_count == 0) - return NULL; - - out = malloc(sizeof(struct fastrpc_io_buffer) * out_count); - if (out == NULL) - return NULL; + const struct hrpc_inner_type_def_interp4 *inner_type; + const void *pos = inbufs[0].p; + const void *end = (const char *) inbufs[0].p + inbufs[0].s; + const struct fastrpc_io_buffer *inbufs_end = &inbufs[n_inbufs]; + const struct fastrpc_io_buffer *curr_inbuf = &inbufs[1]; + size_t size, i, j; + const void *inner_pos; + const void *inner_end; + int ret; - out[0].s = def->out_nums * 4; - if (out[0].s) { - out[0].p = malloc(def->out_nums * 4); - if (out[0].p == NULL) - goto err_free_out; + if (def->msg_id > 30) + pos = (const uint32_t *) pos + 1; + + for (i = 0; i < def->n_args; i++) { + switch (def->args[i].t) { + case HRPC_ARG_WORD: + if (def->args[i].d != 4 && def->args[i].d != 8) + return -1; + + /* fall through */ + case HRPC_ARG_BLOB: + pos = (const char *) pos + def->args[i].d; + if (pos > end) + return -1; + + break; + case HRPC_ARG_TYPE: + inner_type = &def->inner_types[def->args[i].d]; + ret = count_sizes_in_type4(inner_type, + &curr_inbuf, + inbufs_end, + &pos, end); + if (ret) + return -1; + + break; + case HRPC_ARG_BLOB_SEQ: + if ((const void *) ((const uint32_t *) pos + 1) > end) + return -1; + + if (curr_inbuf >= inbufs_end) + return -1; + + size = *(const uint32_t *) pos * def->args[i].d; + if (curr_inbuf->s != size) + return -1; + + pos = (const uint32_t *) pos + 1; + curr_inbuf++; + break; + case HRPC_ARG_TYPE_SEQ: + if ((const void *) ((const uint32_t *) pos + 1) > end) + return -1; + + if (curr_inbuf >= inbufs_end) + return -1; + + size = *(const uint32_t *) pos; + pos = (const uint32_t *) pos + 1; + + inner_type = &def->inner_types[def->args[i].d]; + inner_pos = curr_inbuf->p; + inner_end = (const char *) curr_inbuf->p + curr_inbuf->s; + curr_inbuf++; + for (j = 0; j < size; j++) { + ret = count_sizes_in_type4(inner_type, + &curr_inbuf, + inbufs_end, + &inner_pos, + inner_end); + if (ret) + return -1; + } + + break; + case HRPC_ARG_OUT_BLOB: + break; + case HRPC_ARG_OUT_TYPE: + inner_type = &def->inner_types[def->args[i].d]; + ret = count_sizes_out_type4(inner_type, + &n_outbufs, + &pos, end); + if (ret) + return -1; + + break; + case HRPC_ARG_OUT_BLOB_SEQ: + if ((const void *) ((const uint32_t *) pos + 1) > end) + return -1; + + if (n_outbufs == 0) + return -1; + + pos = (const uint32_t *) pos + 1; + n_outbufs--; + break; + case HRPC_ARG_OUT_TYPE_SEQ: + if ((const void *) ((const uint32_t *) pos + 1) > end) + return -1; + + if (curr_inbuf >= inbufs_end) + return -1; + + size = *(const uint32_t *) pos; + pos = (const uint32_t *) pos + 1; + + inner_type = &def->inner_types[def->args[i].d]; + inner_pos = curr_inbuf->p; + inner_end = (const char *) curr_inbuf->p + curr_inbuf->s; + curr_inbuf++; + for (j = 0; j < size; j++) { + ret = count_sizes_out_type4(inner_type, + &n_outbufs, + &inner_pos, + inner_end); + if (ret) + return -1; + } + + break; + default: + return -1; + } } - off = def->out_nums && 1; - sizes = &first_inbuf[def->in_nums + def->in_bufs]; + return 0; +} - for (i = 0; i < def->out_bufs; i++) { - out[off + i].s = sizes[i]; - out[off + i].p = malloc(sizes[i]); - if (out[off + i].p == NULL) - goto err_free_prev; +static int alloc_outbufs_in_type4(const struct hrpc_inner_type_def_interp4 *type, + const struct fastrpc_io_buffer **curr_inbuf, + const void **inst) +{ + size_t i; + + for (i = 0; i < type->s; i++) { + switch (type->p[i].t) { + case HRPC_ARG_BLOB: + *inst = (const char *) *inst + type->p[i].d; + break; + case HRPC_ARG_BLOB_SEQ: + *inst = (const uint32_t *) *inst + 1; + (*curr_inbuf)++; + break; + default: + return -1; + } } - return out; + return 0; +} -err_free_prev: - for (j = 0; j < i; j++) - free(out[off + j].p); +static int alloc_outbufs_out_type4(const struct hrpc_inner_type_def_interp4 *type, + struct fastrpc_io_buffer **curr_outbuf, + const void **inst_in, size_t *n_inst_out) +{ + size_t size, i; + + for (i = 0; i < type->s; i++) { + switch (type->p[i].t) { + case HRPC_ARG_BLOB: + *n_inst_out += type->p[i].d; + break; + case HRPC_ARG_BLOB_SEQ: + size = type->p[i].d; + size *= *(const uint32_t *) *inst_in; + + (*curr_outbuf)->s = size; + (*curr_outbuf)->p = malloc(size); + if ((*curr_outbuf)->p == NULL) + return -1; + + *inst_in = (const uint32_t *) *inst_in + 1; + (*curr_outbuf)++; + break; + default: + return -1; + } + } -err_free_out: - free(out); - return NULL; + return 0; } -static int check_inbuf_sizes(const struct fastrpc_function_def_interp2 *def, - const struct fastrpc_io_buffer *inbufs) +static struct fastrpc_io_buffer *alloc_outbufs4(const struct hrpc_method_def_interp4 *def, + const struct fastrpc_io_buffer *inbufs, + uint8_t n_outbufs) { - uint8_t i; - const uint32_t *sizes = &((const uint32_t *) inbufs[0].p)[def->in_nums]; - - if (inbufs[0].s != 4U * (def->in_nums - + def->in_bufs - + def->out_bufs)) { - fprintf(stderr, "Invalid number of input numbers: %" PRIu32 " (expected %u)\n", - inbufs[0].s, - 4 * (def->in_nums - + def->in_bufs - + def->out_bufs)); - return -1; + const struct hrpc_inner_type_def_interp4 *inner_type; + const void *prim_in = inbufs[0].p; + struct fastrpc_io_buffer *out, *curr_outbuf, *inner_outbuf; + const struct fastrpc_io_buffer *curr_inbuf = &inbufs[1]; + const void *inner_pos; + size_t i, j, size, prim_out_size = 0; + int ret; + + curr_outbuf = out = calloc(n_outbufs, sizeof(*out)); + if (out == NULL) + return NULL; + + for (i = 0; i < def->n_args; i++) { + if (def->args[i].t == HRPC_ARG_OUT_BLOB + || def->args[i].t == HRPC_ARG_OUT_TYPE) { + curr_outbuf = &out[1]; + break; + } } - for (i = 0; i < def->in_bufs; i++) { - if (inbufs[i + 1].s != sizes[i]) { - fprintf(stderr, "Invalid buffer size\n"); - return -1; + for (i = 0; i < def->n_args; i++) { + switch (def->args[i].t) { + case HRPC_ARG_WORD: + case HRPC_ARG_BLOB: + prim_in = (const char *) prim_in + def->args[i].d; + break; + case HRPC_ARG_TYPE: + inner_type = &def->inner_types[def->args[i].d]; + ret = alloc_outbufs_in_type4(inner_type, + &curr_inbuf, + &prim_in); + if (ret) + return NULL; + + break; + case HRPC_ARG_BLOB_SEQ: + prim_in = (const uint32_t *) prim_in + 1; + curr_inbuf++; + break; + case HRPC_ARG_TYPE_SEQ: + size = *(const uint32_t *) prim_in; + prim_in = (const uint32_t *) prim_in + 1; + + inner_type = &def->inner_types[def->args[i].d]; + inner_pos = curr_inbuf->p; + curr_inbuf++; + for (j = 0; j < size; j++) { + ret = alloc_outbufs_in_type4(inner_type, + &curr_inbuf, + &inner_pos); + if (ret) + return NULL; + } + + break; + case HRPC_ARG_OUT_BLOB: + prim_out_size += def->args[i].d; + break; + case HRPC_ARG_OUT_TYPE: + inner_type = &def->inner_types[def->args[i].d]; + ret = alloc_outbufs_out_type4(inner_type, + &curr_outbuf, + &prim_in, + &prim_out_size); + if (ret) + return NULL; + + break; + case HRPC_ARG_OUT_BLOB_SEQ: + size = *(const uint32_t *) prim_in; + size *= def->args[i].d; + + curr_outbuf->s = size; + curr_outbuf->p = malloc(size); + if (curr_outbuf->p == NULL) + goto err; + + curr_outbuf++; + + prim_in = (const uint32_t *) prim_in + 1; + break; + case HRPC_ARG_OUT_TYPE_SEQ: + size = *(const uint32_t *) prim_in; + prim_in = (const uint32_t *) prim_in + 1; + + inner_type = &def->inner_types[def->args[i].d]; + inner_pos = curr_inbuf->p; + curr_inbuf++; + + inner_outbuf = curr_outbuf; + curr_outbuf++; + + for (j = 0; j < size; j++) { + ret = alloc_outbufs_out_type4(inner_type, + &curr_outbuf, + &inner_pos, + &inner_outbuf->s); + if (ret) + return NULL; + } + + inner_outbuf->p = malloc(inner_outbuf->s); + if (inner_outbuf->p == NULL) + return NULL; + + break; + default: + goto err; } } - return 0; + if (prim_out_size != 0) { + out[0].s = prim_out_size; + out[0].p = malloc(prim_out_size); + if (out[0].p == NULL) + goto err; + } + + return out; + +err: + for (; curr_outbuf >= out; curr_outbuf--) { + if (curr_outbuf->p != NULL) + free(curr_outbuf->p); + } + + free(out); + + return NULL; } static int return_for_next_invoke(int fd, @@ -215,11 +498,20 @@ static int invoke_requested_procedure(size_t n_ifaces, struct fastrpc_io_buffer **returned) { const struct fastrpc_function_impl *impl; - uint8_t in_count; - uint8_t out_count; uint32_t method = REMOTE_SCALARS_METHOD(sc); int ret; + if (method < 31) { + method = REMOTE_SCALARS_METHOD(sc); + } else if (REMOTE_SCALARS_INBUFS(sc) != 0 + && decoded[0].s >= sizeof(uint32_t)) { + method = *(const uint32_t *) decoded[0].p; + } else { + fprintf(stderr, "Expected extended method ID, but got none\n"); + *result = AEE_EBADPARM; + return 1; + } + if (sc & 0xff) { fprintf(stderr, "Handles are not supported, but got %u in, %u out\n", (sc & 0xf0) >> 4, sc & 0xf); @@ -247,26 +539,17 @@ static int invoke_requested_procedure(size_t n_ifaces, return 1; } - in_count = impl->def->in_bufs + ((impl->def->in_nums - || impl->def->in_bufs - || impl->def->out_bufs) && 1); - out_count = impl->def->out_bufs + (impl->def->out_nums && 1); - - if (REMOTE_SCALARS_INBUFS(sc) != in_count - || REMOTE_SCALARS_OUTBUFS(sc) != out_count) { - fprintf(stderr, "Unexpected buffer count: %08x\n", sc); - *result = AEE_EBADPARM; - return 1; - } - - ret = check_inbuf_sizes(impl->def, decoded); + ret = count_sizes4(impl->def, REMOTE_SCALARS_INBUFS(sc), + REMOTE_SCALARS_OUTBUFS(sc), decoded); if (ret) { + fprintf(stderr, "Inconsistent buffer sizes\n"); *result = AEE_EBADPARM; return 1; } - *returned = allocate_outbufs(impl->def, decoded[0].p); - if (*returned == NULL && out_count > 0) { + *returned = alloc_outbufs4(impl->def, decoded, + REMOTE_SCALARS_OUTBUFS(sc)); + if (*returned == NULL && impl->def->n_args > 0) { perror("Could not allocate output buffers"); *result = AEE_ENOMEMORY; return 1; diff --git a/hexagonrpcd/listener.h b/hexagonrpcd/listener.h index 7c2aab3..8938b87 100644 --- a/hexagonrpcd/listener.h +++ b/hexagonrpcd/listener.h @@ -22,14 +22,14 @@ #ifndef LISTENER_H #define LISTENER_H -#include +#include #include #include #include "iobuffer.h" struct fastrpc_function_impl { - const struct fastrpc_function_def_interp2 *def; + const struct hrpc_method_def_interp4 *def; uint32_t (*impl)(void *data, const struct fastrpc_io_buffer *inbufs, struct fastrpc_io_buffer *outbufs); diff --git a/hexagonrpcd/localctl.c b/hexagonrpcd/localctl.c index 3eaef88..f90f99e 100644 --- a/hexagonrpcd/localctl.c +++ b/hexagonrpcd/localctl.c @@ -19,13 +19,13 @@ * along with this program. If not, see . */ -#include +#include +#include #include #include #include #include -#include "aee_error.h" #include "iobuffer.h" #include "listener.h" #include "localctl.h" diff --git a/hexagonrpcd/meson.build b/hexagonrpcd/meson.build index 3d1e9d1..11244ef 100644 --- a/hexagonrpcd/meson.build +++ b/hexagonrpcd/meson.build @@ -1,8 +1,10 @@ executable('hexagonrpcd', - 'aee_error.c', 'apps_mem.c', 'apps_std.c', - 'interfaces.c', + 'interface/adsp_default_listener.c', + 'interface/adsp_listener.c', + 'interface/apps_mem.c', + 'interface/apps_std.c', 'hexagonfs.c', 'hexagonfs_mapped.c', 'hexagonfs_plat_subtype_name.c', diff --git a/hexagonrpcd/rpcd.c b/hexagonrpcd/rpcd.c index cc1f5cf..38d5c00 100644 --- a/hexagonrpcd/rpcd.c +++ b/hexagonrpcd/rpcd.c @@ -21,8 +21,10 @@ #include #include -#include -#include +#include +#include +#include +#include #include #include #include @@ -34,99 +36,34 @@ #include #include -#include "aee_error.h" #include "apps_mem.h" #include "apps_std.h" #include "hexagonfs.h" -#include "interfaces/adsp_default_listener.def" +#include "interface/adsp_default_listener.h" #include "listener.h" #include "localctl.h" #include "rpcd_builder.h" -static int remotectl_open(int fd, char *name, struct fastrpc_context **ctx, void (*err_cb)(const char *err)) -{ - uint32_t handle; - int32_t dlret; - char err[256]; - int ret; - - ret = fastrpc2(&remotectl_open_def, fd, REMOTECTL_HANDLE, - strlen(name) + 1, name, - &handle, - &dlret, - 256, err); - - if (ret == -1) { - err_cb(strerror(errno)); - return ret; - } - - if (dlret == -5) { - err_cb(err); - return dlret; - } else if (dlret) { - err_cb(aee_strerror[dlret]); - return dlret; - } - - *ctx = fastrpc_create_context(fd, handle); - - return ret; -} - -static int remotectl_close(struct fastrpc_context *ctx, void (*err_cb)(const char *err)) -{ - uint32_t dlret; - char err[256]; - int ret; - - ret = fastrpc2(&remotectl_close_def, ctx->fd, REMOTECTL_HANDLE, - ctx->handle, - &dlret, - 256, err); - - if (ret == -1) { - err_cb(strerror(errno)); - return ret; - } - - if (dlret) { - err_cb(aee_strerror[dlret]); - return dlret; - } - - fastrpc_destroy_context(ctx); - - return ret; -} - -static int adsp_default_listener_register(struct fastrpc_context *ctx) -{ - return fastrpc(&adsp_default_listener_register_def, ctx); -} - -static void remotectl_err(const char *err) -{ - fprintf(stderr, "Could not remotectl: %s\n", err); -} - static int register_fastrpc_listener(int fd) { - struct fastrpc_context *ctx; + uint32_t hdl; + char err[256]; int ret; - ret = remotectl_open(fd, "adsp_default_listener", &ctx, remotectl_err); - if (ret) + ret = hexagonrpc_open(fd, "adsp_default_listener", &hdl, 256, err); + if (ret) { + fprintf(stderr, "Could not open remote interface: %s\n", err); return 1; + } - ret = adsp_default_listener_register(ctx); + ret = adsp_default_listener_register(fd, hdl); if (ret) { fprintf(stderr, "Could not register ADSP default listener\n"); goto err; } err: - remotectl_close(ctx, remotectl_err); + hexagonrpc_close(fd, hdl); return ret; } @@ -268,7 +205,7 @@ static void *start_reverse_tunnel(int fd, const char *device_dir, const char *ds * fully populate the ifaces array as long as it receives a pointer to * it. */ - ifaces[REMOTECTL_HANDLE] = fastrpc_localctl_init(n_ifaces, ifaces); + ifaces[REMOTECTL] = fastrpc_localctl_init(n_ifaces, ifaces); // Dynamic interfaces with no hardcoded handle ifaces[1] = fastrpc_apps_std_init(root_dir); @@ -280,7 +217,7 @@ static void *start_reverse_tunnel(int fd, const char *device_dir, const char *ds run_fastrpc_listener(fd, n_ifaces, ifaces); - fastrpc_localctl_deinit(ifaces[REMOTECTL_HANDLE]); + fastrpc_localctl_deinit(ifaces[REMOTECTL]); free(ifaces); diff --git a/hexagonrpcd/aee_error.h b/include/libhexagonrpc/error.h similarity index 93% rename from hexagonrpcd/aee_error.h rename to include/libhexagonrpc/error.h index 911165e..375c3f4 100644 --- a/hexagonrpcd/aee_error.h +++ b/include/libhexagonrpc/error.h @@ -2,6 +2,7 @@ * Imported FastRPC error numbers * * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, The Sensor Shell Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -29,8 +30,8 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef AEE_STRERROR_H -#define AEE_STRERROR_H +#ifndef LIBHEXAGONRPC_ERROR_H +#define LIBHEXAGONRPC_ERROR_H #define AEE_SUCCESS 0 #define AEE_EFAILED 1 @@ -83,6 +84,6 @@ #define AEE_ECPUEXCEPTION 48 #define AEE_EREADONLY 49 -extern const char *aee_strerror[]; +const char *hexagonrpc_strerror(int ret); -#endif +#endif /* LIBHEXAGONRPC_ERROR_H */ diff --git a/include/libhexagonrpc/fastrpc.h b/include/libhexagonrpc/fastrpc.h deleted file mode 100644 index 69f0d17..0000000 --- a/include/libhexagonrpc/fastrpc.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * FastRPC API Replacement - header files - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef FASTRPC_H -#define FASTRPC_H - -#include -#include -#include - -// See fastrpc.git/inc/remote.h -#define REMOTE_SCALARS_MAKEX(nAttr,nMethod,nIn,nOut,noIn,noOut) \ - ((((uint32_t) (nAttr) & 0x7) << 29) | \ - (((uint32_t) (nMethod) & 0x1f) << 24) | \ - (((uint32_t) (nIn) & 0xff) << 16) | \ - (((uint32_t) (nOut) & 0xff) << 8) | \ - (((uint32_t) (noIn) & 0x0f) << 4) | \ - ((uint32_t) (noOut) & 0x0f)) - -#define REMOTE_SCALARS_MAKE(nMethod,nIn,nOut) REMOTE_SCALARS_MAKEX(0,nMethod,nIn,nOut,0,0) - -#define REMOTE_SCALARS_METHOD(sc) (((sc) >> 24) & 0x1f) -#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0xff) -#define REMOTE_SCALARS_OUTBUFS(sc) (((sc) >> 8) & 0xff) - -struct fastrpc_context { - int fd; - uint32_t handle; -}; - -struct fastrpc_function_def_interp2 { - uint32_t msg_id; - uint8_t in_nums; - uint8_t in_bufs; - uint8_t out_nums; - uint8_t out_bufs; -}; - -struct fastrpc_context *fastrpc_create_context(int fd, uint32_t handle); - -static inline void fastrpc_destroy_context(struct fastrpc_context *ctx) -{ - free(ctx); -} - -int vfastrpc2(const struct fastrpc_function_def_interp2 *def, - int fd, uint32_t handle, va_list arg_list); -int vfastrpc(const struct fastrpc_function_def_interp2 *def, - const struct fastrpc_context *ctx, va_list arg_list); -int fastrpc2(const struct fastrpc_function_def_interp2 *def, - int fd, uint32_t handle, ...); -int fastrpc(const struct fastrpc_function_def_interp2 *def, - const struct fastrpc_context *ctx, ...); - -#endif diff --git a/include/libhexagonrpc/handle.h b/include/libhexagonrpc/handle.h new file mode 100644 index 0000000..15a2c4f --- /dev/null +++ b/include/libhexagonrpc/handle.h @@ -0,0 +1,41 @@ +/* + * FastRPC handle utilities + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIBHEXAGONRPC_HANDLE_H +#define LIBHEXAGONRPC_HANDLE_H + +#include +#include + +/* + * Open a remote interface by name and get its handle. + * + * On success, returns 0 and sets the handle. + * On failure, returns -1 and sets the err string. + */ +int hexagonrpc_open(int fd, const char *name, uint32_t *hdl, size_t n_err, char *err); + +/* + * Close a remote interface by its handle. + */ +void hexagonrpc_close(int fd, uint32_t hdl); + +#endif /* LIBHEXAGONRPC_HANDLE_H */ diff --git a/include/libhexagonrpc/hexagonrpc.h b/include/libhexagonrpc/hexagonrpc.h new file mode 100644 index 0000000..3bebda6 --- /dev/null +++ b/include/libhexagonrpc/hexagonrpc.h @@ -0,0 +1,90 @@ +/* + * FastRPC argument marshalling - header files + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef HEXAGONRPC_H +#define HEXAGONRPC_H + +#include +#include +#include +#include + +// See fastrpc.git/inc/remote.h +#define REMOTE_SCALARS_MAKEX(nAttr,nMethod,nIn,nOut,noIn,noOut) \ + ((((uint32_t) (nAttr) & 0x7) << 29) | \ + (((uint32_t) (nMethod) & 0x1f) << 24) | \ + (((uint32_t) (nIn) & 0xff) << 16) | \ + (((uint32_t) (nOut) & 0xff) << 8) | \ + (((uint32_t) (noIn) & 0x0f) << 4) | \ + ((uint32_t) (noOut) & 0x0f)) + +#define REMOTE_SCALARS_MAKE(nMethod,nIn,nOut) REMOTE_SCALARS_MAKEX(0,nMethod,nIn,nOut,0,0) + +#define REMOTE_SCALARS_METHOD(sc) (((sc) >> 24) & 0x1f) +#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0xff) +#define REMOTE_SCALARS_OUTBUFS(sc) (((sc) >> 8) & 0xff) + +#define HRPC_ARRAY_SIZE(p) (sizeof(p) / sizeof(*(p))) + +// Literal uint32_t or uint64_t (top-level use only) +#define HRPC_ARG_WORD 0 +// Pointer to data of size d (usable in inner types) +#define HRPC_ARG_BLOB 1 +// Pointer to inner type, with d indexing the inner_types array (top-level use only) +#define HRPC_ARG_TYPE 2 +// Number of elements and pointer to sequence, element size d (usable in inner types) +#define HRPC_ARG_BLOB_SEQ 3 +// Number of elements and pointer to sequence of inner type, with index d +#define HRPC_ARG_TYPE_SEQ 4 +// Type 5 is reserved for sequence of inner type containing other sequences of inner types + +// Corresponding argument types for output (top-level use only) +#define HRPC_ARG_OUT_BLOB 6 +#define HRPC_ARG_OUT_TYPE 7 +#define HRPC_ARG_OUT_BLOB_SEQ 8 +#define HRPC_ARG_OUT_TYPE_SEQ 9 + +struct hrpc_arg_def_interp4 { + // Type (field t) can be any HRPC_ARG_* macro + uint32_t t; + // Data depends on type + uint32_t d; +}; + +struct hrpc_inner_type_def_interp4 { + size_t s; + const struct hrpc_arg_def_interp4 *p; +}; + +struct hrpc_method_def_interp4 { + uint32_t msg_id; + size_t n_args; + const struct hrpc_arg_def_interp4 *args; + size_t n_inner_types; + const struct hrpc_inner_type_def_interp4 *inner_types; +}; + +int vhexagonrpc(const struct hrpc_method_def_interp4 *def, + int fd, uint32_t handle, va_list list); +int hexagonrpc(const struct hrpc_method_def_interp4 *def, + int fd, uint32_t handle, ...); + +#endif diff --git a/include/libhexagonrpc/interface.h b/include/libhexagonrpc/interface.h deleted file mode 100644 index 0b6700f..0000000 --- a/include/libhexagonrpc/interface.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * FastRPC interface method definition macros - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LIBHEXAGONRPC_INTERFACE_H -#define LIBHEXAGONRPC_INTERFACE_H - -#include - -/* - * We want to declare method definitions as external by default so we only need - * special flags when compiling the interfaces. Otherwise, everything that uses - * the interfaces would need to define a macro. - */ -#if !HEXAGONRPC_BUILD_METHOD_DEFINITIONS - -#define HEXAGONRPC_DEFINE_REMOTE_METHOD(mid, name, \ - innums, inbufs, \ - outnums, outbufs) \ - extern const struct fastrpc_function_def_interp2 name##_def; - -#else /* HEXAGONRPC_BUILD_METHOD_DEFINITIONS */ - -#define HEXAGONRPC_DEFINE_REMOTE_METHOD(mid, name, \ - innums, inbufs, \ - outnums, outbufs) \ - const struct fastrpc_function_def_interp2 name##_def = { \ - .msg_id = mid, \ - .in_nums = innums, \ - .in_bufs = inbufs, \ - .out_nums = outnums, \ - .out_bufs = outbufs, \ - }; - -#endif /* HEXAGONRPC_BUILD_METHOD_DEFINITIONS */ - -#endif /* LIBHEXAGONRPC_INTERFACE_H */ diff --git a/include/libhexagonrpc/interface/remotectl.h b/include/libhexagonrpc/interface/remotectl.h new file mode 100644 index 0000000..67e46d1 --- /dev/null +++ b/include/libhexagonrpc/interface/remotectl.h @@ -0,0 +1,52 @@ +/* + * Remote processor control interface - API + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef INTERFACE_REMOTECTL_H +#define INTERFACE_REMOTECTL_H + +#include +#include + +#define REMOTECTL 0 + +extern struct hrpc_method_def_interp4 remotectl_open_def; +static inline int remotectl_open(int fd, + uint32_t n_str, const char *str, + uint32_t *handle, + uint32_t n_err, char *err, + uint32_t *err_valid_len) +{ + return hexagonrpc(&remotectl_open_def, fd, REMOTECTL, + n_str, (const void *) str, + (void *) handle, n_err, (void *) err, (void *) err_valid_len); +} + +extern struct hrpc_method_def_interp4 remotectl_close_def; +static inline int remotectl_close(int fd, + uint32_t handle, + uint32_t n_err, char *err, + uint32_t *err_valid_len) +{ + return hexagonrpc(&remotectl_close_def, fd, REMOTECTL, + handle, n_err, (void *) err, (void *) err_valid_len); +} + +#endif /* INTERFACE_REMOTECTL_H */ diff --git a/include/libhexagonrpc/interfaces/remotectl.def b/include/libhexagonrpc/interfaces/remotectl.def deleted file mode 100644 index ba23c57..0000000 --- a/include/libhexagonrpc/interfaces/remotectl.def +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Remote processor control interface - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef INTERFACE_REMOTECTL_DEF -#define INTERFACE_REMOTECTL_DEF - -#include - -#define REMOTECTL_HANDLE 0 - -HEXAGONRPC_DEFINE_REMOTE_METHOD(0, remotectl_open, 0, 1, 2, 1) -HEXAGONRPC_DEFINE_REMOTE_METHOD(1, remotectl_close, 1, 0, 1, 1) - -#endif /* INTERFACE_REMOTECTL_DEF */ diff --git a/libhexagonrpc/context.c b/libhexagonrpc/context.c deleted file mode 100644 index c3fa204..0000000 --- a/libhexagonrpc/context.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * FastRPC API Replacement - context-based interface - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -struct fastrpc_context *fastrpc_create_context(int fd, uint32_t handle) -{ - struct fastrpc_context *ctx; - - ctx = malloc(sizeof(*ctx)); - if (ctx == NULL) - return NULL; - - ctx->fd = fd; - ctx->handle = handle; - - return ctx; -} - -int vfastrpc(const struct fastrpc_function_def_interp2 *def, - const struct fastrpc_context *ctx, va_list arg_list) -{ - return vfastrpc2(def, ctx->fd, ctx->handle, arg_list); -} - -int fastrpc(const struct fastrpc_function_def_interp2 *def, - const struct fastrpc_context *ctx, ...) -{ - va_list arg_list; - int ret; - - va_start(arg_list, ctx); - ret = vfastrpc(def, ctx, arg_list); - va_end(arg_list); - - return ret; -} - diff --git a/hexagonrpcd/aee_error.c b/libhexagonrpc/error.c similarity index 89% rename from hexagonrpcd/aee_error.c rename to libhexagonrpc/error.c index f0f2930..7b2cc20 100644 --- a/hexagonrpcd/aee_error.c +++ b/libhexagonrpc/error.c @@ -2,6 +2,7 @@ * Imported FastRPC error messages * * Copyright (c) 2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, The Sensor Shell Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -29,7 +30,10 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -const char *aee_strerror[] = { +#include +#include + +static const char *err_tab[] = { "No error", "General failure", "Insufficient RAM", @@ -81,3 +85,13 @@ const char *aee_strerror[] = { "A CPU exception occurred", "Cannot change read-only object or parameter", }; + +const char *hexagonrpc_strerror(int ret) +{ + if (ret == -1) + return strerror(errno); + else if (ret >= 0 && (unsigned int) ret < sizeof(err_tab) / sizeof(*err_tab)) + return err_tab[ret]; + + return "Unknown error"; +} diff --git a/libhexagonrpc/fastrpc.c b/libhexagonrpc/fastrpc.c deleted file mode 100644 index cee9323..0000000 --- a/libhexagonrpc/fastrpc.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * FastRPC API Replacement - * - * Copyright (C) 2023 The Sensor Shell Contributors - * - * This file is part of sensh. - * - * Sensh is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -static void allocate_first_inbuf(const struct fastrpc_function_def_interp2 *def, - struct fastrpc_invoke_args *arg, - uint32_t **inbuf) -{ - uint32_t *buf; - size_t len; - - len = sizeof(uint32_t) * (def->in_nums + def->in_bufs + def->out_bufs); - - if (len) - buf = malloc(len); - else - buf = NULL; - - *inbuf = buf; - - if (buf != NULL) { - arg->ptr = (__u64) buf; - arg->length = len; - arg->fd = -1; - } -} - -static void allocate_first_outbuf(const struct fastrpc_function_def_interp2 *def, - struct fastrpc_invoke_args *arg, - uint32_t **outbuf) -{ - uint32_t *buf; - size_t len; - - len = sizeof(uint32_t) * def->out_nums; - - if (len) - buf = malloc(len); - else - buf = NULL; - - *outbuf = buf; - - if (buf != NULL) { - arg->ptr = (__u64) buf; - arg->length = len; - arg->fd = -1; - } -} - -/* - * This populates relevant inputs (in general) with information necessary to - * receive output from the remote processor. - * - * First, it allocates a new first output buffer to contain the returned 32-bit - * integers. This output buffer must be freed after use. - * - * With a peek at the output arguments, it populates the fastrpc_invoke_args - * struct to give information about the buffer to the kernel, and adds an entry - * to the first input buffer to tell the remote processor how large the - * function-level output buffer can be. - * - * This is the only part of the argument processing that can be split off into - * a different function because it is operating on a copy of the va_list. - * Calling va_arg() on a va_list after the return of a function that already - * used it causes undefined behavior. - */ -static void prepare_outbufs(const struct fastrpc_function_def_interp2 *def, - struct fastrpc_invoke_args *args, - uint8_t out_count, - uint32_t *inbuf, - uint32_t **outbuf, - va_list peek) -{ - int i; - int off; - int size; - - allocate_first_outbuf(def, args, outbuf); - - off = def->out_nums && 1; - - for (i = 0; i < def->out_nums; i++) - va_arg(peek, uint32_t *); - - for (i = 0; i < def->out_bufs; i++) { - size = va_arg(peek, uint32_t); - - args[off + i].ptr = (__u64) va_arg(peek, void *); - args[off + i].length = size; - args[off + i].fd = -1; - - inbuf[i] = size; - } -} - -/* - * This is the main function to invoke a fastrpc procedure call. The first - * parameter specifies how to populate the ioctl-level buffers. The second and - * third parameters specify where to send the invocation to. The fourth is the - * list of arguments that the procedure call should interact with. - * - * The argument list has, in order: - * - a (uint32_t val) for each input number - * - a (uint32_t len, void *buf) for each input buffer - * - a (uint32_t *val) for each output number - * - a (uint32_t max_size, void *buf) for each output buffer - * - * A good example for this would be the adsp_listener_next2 call: - * - * static inline void adsp_listener_next2(int fd, uint32_t handle, - * uint32_t prev_ctx, - * uint32_t prev_result, - * uint32_t nested_outbufs_len, - * void *nested_outbufs, - * uint32_t *ctx, - * uint32_t *nested_handle, - * uint32_t *nested_sc, - * uint32_t *nested_inbufs_len, - * uint32_t nested_inbufs_size, - * void *nested_inbufs) - * { - * struct fastrpc_function_def_interp2 def = { - * .in_nums = 2, - * .in_bufs = 1, - * .out_nums = 4, - * .out_bufs = 1, - * .mid = 4, - * }; - * return fastrpc(def, fd, handle, - * prev_ctx, - * prev_result, - * nested_outbufs_len, - * nested_outbufs, - * ctx, - * nested_handle, - * nested_sc, - * nested_inbufs_len, - * nested_inbufs_size, - * nested_inbufs); - * } - */ -int vfastrpc2(const struct fastrpc_function_def_interp2 *def, - int fd, uint32_t handle, va_list arg_list) -{ - va_list peek; - struct fastrpc_invoke invoke; - struct fastrpc_invoke_args *args; - uint32_t *inbuf; - uint32_t *outbuf; - uint8_t in_count; - uint8_t out_count; - uint32_t size; - uint8_t i; - int ret; - - /* - * Calculate the amount of needed buffers, accounting for the need for - * the maximum size of the output buffer. - */ - in_count = def->in_bufs + ((def->in_nums - || def->in_bufs - || def->out_bufs) && 1); - out_count = def->out_bufs + (def->out_nums && 1); - - if (in_count || out_count) - args = malloc(sizeof(*args) * (in_count + out_count)); - else - args = NULL; - - allocate_first_inbuf(def, args, &inbuf); - - for (i = 0; i < def->in_nums; i++) - inbuf[i] = va_arg(arg_list, uint32_t); - - for (i = 0; i < def->in_bufs; i++) { - size = va_arg(arg_list, uint32_t); - - args[i + 1].ptr = (__u64) va_arg(arg_list, void *); - args[i + 1].length = size; - args[i + 1].fd = -1; - - inbuf[def->in_nums + i] = size; - } - - va_copy(peek, arg_list); - prepare_outbufs(def, - &args[in_count], - out_count, - &inbuf[def->in_nums + def->in_bufs], - &outbuf, - peek); - va_end(peek); - - invoke.handle = handle; - invoke.sc = REMOTE_SCALARS_MAKE(def->msg_id, in_count, out_count); - invoke.args = (__u64) args; - - ret = ioctl(fd, FASTRPC_IOCTL_INVOKE, (__u64) &invoke); - - for (i = 0; i < def->out_nums; i++) - *va_arg(arg_list, uint32_t *) = outbuf[i]; - - if (in_count || out_count) - free(args); - - if (in_count) - free(inbuf); - - if (out_count) - free(outbuf); - - return ret; -} - -int fastrpc2(const struct fastrpc_function_def_interp2 *def, - int fd, uint32_t handle, ...) -{ - va_list arg_list; - int ret; - - va_start(arg_list, handle); - ret = vfastrpc2(def, fd, handle, arg_list); - va_end(arg_list); - - return ret; -} diff --git a/libhexagonrpc/handle.c b/libhexagonrpc/handle.c new file mode 100644 index 0000000..7268440 --- /dev/null +++ b/libhexagonrpc/handle.c @@ -0,0 +1,57 @@ +/* + * FastRPC remote interface handle management + * + * Copyright (C) 2023 The Sensor Shell Contributors + * + * This file is part of sensh. + * + * Sensh is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include + +int hexagonrpc_open(int fd, const char *name, uint32_t *hdl, size_t n_err, char *err) +{ + uint32_t dlerr; + int ret; + + ret = remotectl_open(fd, strlen(name) + 1, name, hdl, + n_err, err, &dlerr); + if (ret) { + strncpy(err, hexagonrpc_strerror(ret), n_err); + err[n_err - 1] = '\0'; + return -1; + } + + /* + * The error message is already in the buffer because the buffer was + * directly passed as an output buffer. Simply return at this point. + */ + if (dlerr) + return -1; + + return 0; +} + +void hexagonrpc_close(int fd, uint32_t hdl) +{ + uint32_t dlerr; + + remotectl_close(fd, hdl, 0, NULL, &dlerr); +} diff --git a/libhexagonrpc/hexagonrpc.c b/libhexagonrpc/hexagonrpc.c new file mode 100644 index 0000000..b638530 --- /dev/null +++ b/libhexagonrpc/hexagonrpc.c @@ -0,0 +1,831 @@ +/* + * FastRPC argument marshalling + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/* + * Operations to be done for a stage of invoking. + * + * The hexagonrpc function has 5 stages that parse the method definition: + * - count: count the I/O buffers in need of marshalling + * - alloc: populate fastrpc_invoke_args with pointers, allocating when needed + * - encode: marshal va_args into primary input buffer + * - decode: demarshal primary output buffer into va_args buffers + * - free: free any buffers allocated by the alloc stage + * + * These stages interpret the arguments in the exact same way and have a + * similar control structure. To reduce code duplication, each stage can call + * emit_args with their own stage_ops callbacks and state. + */ +struct stage_ops { + void (*emit_prim_in)(size_t size, const void *ptr, void *data); + void (*emit_prim_out)(size_t size, void *ptr, void *data); + void (*emit_inbuf)(size_t size, const void *ptr, void *data); + void (*emit_outbuf)(size_t size, void *ptr, void *data); + + int (*emit_type_seq_in)(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, const void *inst); + int (*emit_type_seq_out)(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, void *inst); +}; + +// Used by count_ops +struct buf_count { + uint8_t n_inbufs; + uint8_t n_outbufs; + uint32_t n_prim_in; + uint32_t n_prim_out; +}; + +// Used by alloc_ops and free_ops +struct curr_buf { + struct fastrpc_invoke_args *inbuf; + struct fastrpc_invoke_args *outbuf; +}; + +// Used by encode_ops and decode_ops +struct curr_pos { + struct fastrpc_invoke_args *buf; + void *prim; +}; + +static const struct stage_ops count_ops; +static const struct stage_ops alloc_ops; +static const struct stage_ops encode_ops; +static const struct stage_ops decode_ops; +static const struct stage_ops free_ops; + +static int emit_inner_type_in(const struct hrpc_inner_type_def_interp4 *type, + const struct stage_ops *ops, void *data, + const void **inst) +{ + uint32_t arg32; + void *ptr; + size_t i, size; + + for (i = 0; i < type->s; i++) { + switch (type->p[i].t) { + case HRPC_ARG_BLOB: + size = type->p[i].d; + ops->emit_prim_in(size, *inst, data); + *inst = (char *) *inst + size; + break; + case HRPC_ARG_BLOB_SEQ: + arg32 = *(const uint32_t *) *inst; + *inst = (uint32_t *) *inst + 1; + ptr = *(void **) *inst; + *inst = (void **) *inst + 1; + + size = (size_t) type->p[i].d * arg32; + + ops->emit_prim_in(sizeof(arg32), &arg32, data); + ops->emit_inbuf(size, ptr, data); + + break; + // Not seen so far in public IDLs + case HRPC_ARG_TYPE_SEQ: + return -1; + default: + return -1; + } + } + + return 0; +} + +static int emit_inner_type_out(const struct hrpc_inner_type_def_interp4 *type, + const struct stage_ops *ops, void *data, + void **inst) +{ + uint32_t arg32; + void *ptr; + size_t i, size; + + for (i = 0; i < type->s; i++) { + switch (type->p[i].t) { + case HRPC_ARG_BLOB: + size = type->p[i].d; + ops->emit_prim_out(size, *inst, data); + *inst = (char *) *inst + size; + break; + case HRPC_ARG_BLOB_SEQ: + arg32 = *(const uint32_t *) *inst; + *inst = (uint32_t *) *inst + 1; + ptr = *(void **) *inst; + *inst = (void **) *inst + 1; + + size = (size_t) type->p[i].d * arg32; + + ops->emit_prim_in(sizeof(arg32), &arg32, data); + ops->emit_outbuf(size, ptr, data); + + break; + // Not seen so far in public IDLs + case HRPC_ARG_TYPE_SEQ: + return -1; + default: + return -1; + } + } + + return 0; +} + +static int emit_args(const struct hrpc_method_def_interp4 *def, + const struct stage_ops *ops, void *data, + va_list list) +{ + const struct hrpc_inner_type_def_interp4 *inner_type; + uint32_t arg32; + uint64_t arg64; + const void *iptr; + void *optr; + size_t i, size; + int ret; + + for (i = 0; i < def->n_args; i++) { + switch (def->args[i].t) { + case HRPC_ARG_WORD: + size = def->args[i].d; + if (size == sizeof(uint32_t)) { + arg32 = va_arg(list, uint32_t); + ops->emit_prim_in(size, &arg32, data); + } else if (size == sizeof(uint64_t)) { + arg64 = va_arg(list, uint64_t); + ops->emit_prim_in(size, &arg64, data); + } else { + return -1; + } + + break; + case HRPC_ARG_BLOB: + size = def->args[i].d; + iptr = va_arg(list, const void *); + ops->emit_prim_in(size, iptr, data); + break; + case HRPC_ARG_TYPE: + iptr = va_arg(list, const void *); + inner_type = &def->inner_types[def->args[i].d]; + ret = emit_inner_type_in(inner_type, + ops, data, &iptr); + if (ret) + return ret; + break; + case HRPC_ARG_BLOB_SEQ: + arg32 = va_arg(list, uint32_t); + iptr = va_arg(list, const void *); + size = (size_t) def->args[i].d * arg32; + + ops->emit_prim_in(sizeof(arg32), &arg32, data); + ops->emit_inbuf(size, iptr, data); + + break; + case HRPC_ARG_TYPE_SEQ: + arg32 = va_arg(list, uint32_t); + iptr = va_arg(list, const void *); + ret = ops->emit_type_seq_in(def, inner_type, + data, arg32, iptr); + if (ret) + return ret; + break; + case HRPC_ARG_OUT_BLOB: + optr = va_arg(list, void *); + ops->emit_prim_out(def->args[i].d, optr, data); + break; + case HRPC_ARG_OUT_TYPE: + optr = va_arg(list, void *); + inner_type = &def->inner_types[def->args[i].d]; + ret = emit_inner_type_out(inner_type, + ops, data, &optr); + if (ret) + return ret; + break; + case HRPC_ARG_OUT_BLOB_SEQ: + arg32 = va_arg(list, uint32_t); + optr = va_arg(list, void *); + size = (size_t) def->args[i].d * arg32; + + ops->emit_prim_in(sizeof(arg32), &arg32, data); + ops->emit_outbuf(size, optr, data); + + break; + case HRPC_ARG_OUT_TYPE_SEQ: + arg32 = va_arg(list, uint32_t); + optr = va_arg(list, void *); + ret = ops->emit_type_seq_out(def, inner_type, + data, arg32, optr); + if (ret) + return ret; + break; + default: + return -1; + } + } + + return 0; +} + +static void emit_nop_in(size_t size, const void *ptr, void *data) +{ +} + +static void emit_nop_out(size_t size, void *ptr, void *data) +{ +} + +static void count_prim_in(size_t size, const void *ptr, void *data) +{ + ((struct buf_count *) data)->n_prim_in += size; +} + +static void count_prim_out(size_t size, void *ptr, void *data) +{ + ((struct buf_count *) data)->n_prim_out += size; +} + +static void count_inbuf(size_t size, const void *ptr, void *data) +{ + ((struct buf_count *) data)->n_inbufs++; +} + +static void count_outbuf(size_t size, void *ptr, void *data) +{ + ((struct buf_count *) data)->n_outbufs++; +} + +static int count_type_seq_in(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, const void *inst) +{ + struct buf_count inner_count = { 0, 0, 0, 0 }; + struct buf_count *count = data; + int ret = 0; + + if (n_inst) { + ret = emit_inner_type_in(type, + &count_ops, &inner_count, + &inst); + count->n_inbufs++; + count->n_inbufs += inner_count.n_inbufs * n_inst; + } + + return ret; +} + +static int count_type_seq_out(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, void *inst) +{ + struct buf_count inner_count = { 0, 0, 0, 0 }; + struct buf_count *count = data; + int ret = 0; + + if (n_inst) { + ret = emit_inner_type_out(type, + &count_ops, &inner_count, + &inst); + count->n_inbufs++; + count->n_outbufs += inner_count.n_outbufs * n_inst; + } + + return ret; +} + +static const struct stage_ops count_ops = { + .emit_prim_in = count_prim_in, + .emit_prim_out = count_prim_out, + .emit_inbuf = count_inbuf, + .emit_outbuf = count_outbuf, + .emit_type_seq_in = count_type_seq_in, + .emit_type_seq_out = count_type_seq_out, +}; + +static void alloc_inbuf(size_t size, const void *ptr, void *data) +{ + struct curr_buf *curr = data; + + curr->inbuf->length = size; + curr->inbuf->ptr = (__u64) ptr; + curr->inbuf++; +} + +static void alloc_outbuf(size_t size, void *ptr, void *data) +{ + struct curr_buf *curr = data; + + curr->outbuf->length = size; + curr->outbuf->ptr = (__u64) ptr; + curr->outbuf++; +} + +static int alloc_type_seq_in(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, const void *inst) +{ + struct buf_count inner_count = { 0, 0, 0, 0 }; + struct curr_buf *curr = data; + int ret = 0; + size_t i; + + if (n_inst) { + ret = emit_inner_type_in(type, + &count_ops, &inner_count, + &inst); + if (ret) + return ret; + + curr->inbuf->length = inner_count.n_prim_in * n_inst; + curr->inbuf->ptr = (__u64) malloc(curr->inbuf->length); + if (curr->inbuf->ptr == 0) + return -1; + } + + curr->inbuf++; + + for (i = 0; i < n_inst; i++) { + ret = emit_inner_type_in(type, &alloc_ops, data, &inst); + if (ret) + return ret; + } + + return ret; +} + +static int alloc_type_seq_out(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, void *inst) +{ + struct buf_count inner_count = { 0, 0, 0, 0 }; + struct curr_buf *curr = data; + int ret = 0; + size_t i; + + if (n_inst) { + ret = emit_inner_type_out(type, + &count_ops, &inner_count, + &inst); + if (ret) + return ret; + + curr->inbuf->length = inner_count.n_prim_in * n_inst; + curr->inbuf->ptr = (__u64) malloc(curr->inbuf->length); + if (curr->inbuf->ptr == 0) + return -1; + + curr->outbuf->length = inner_count.n_prim_out * n_inst; + curr->outbuf->ptr = (__u64) malloc(curr->outbuf->length); + if (curr->outbuf->ptr == 0) + return -1; + } + + curr->inbuf++; + curr->outbuf++; + + for (i = 0; i < n_inst; i++) { + ret = emit_inner_type_out(type, &alloc_ops, data, &inst); + if (ret) + return ret; + } + + return 0; +} + +static const struct stage_ops alloc_ops = { + .emit_prim_in = emit_nop_in, + .emit_prim_out = emit_nop_out, + .emit_inbuf = alloc_inbuf, + .emit_outbuf = alloc_outbuf, + .emit_type_seq_in = alloc_type_seq_in, + .emit_type_seq_out = alloc_type_seq_out, +}; + +static void encode_prim_in(size_t size, const void *ptr, void *data) +{ + struct curr_pos *pos = data; + + memcpy(pos->prim, ptr, size); + pos->prim = (char *) pos->prim + size; +} + +static void encode_inbuf(size_t size, const void *ptr, void *data) +{ + ((struct curr_pos *) data)->buf++; +} + +static int encode_type_seq_in(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, const void *inst) +{ + struct curr_pos inner_pos; + struct curr_pos *pos = data; + int ret; + size_t i; + + inner_pos.buf = pos->buf; + inner_pos.prim = (void *) pos->buf->ptr; + + for (i = 0; i < n_inst; i++) { + ret = emit_inner_type_in(type, &encode_ops, &inner_pos, &inst); + if (ret) + return ret; + } + + pos->buf = inner_pos.buf; + return 0; +} + +static int encode_type_seq_out(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, void *inst) +{ + struct curr_pos inner_pos; + struct curr_pos *pos = data; + int ret; + size_t i; + + inner_pos.buf = pos->buf; + inner_pos.prim = (void *) pos->buf->ptr; + + for (i = 0; i < n_inst; i++) { + ret = emit_inner_type_out(type, &encode_ops, &inner_pos, &inst); + if (ret) + return ret; + } + + pos->buf = inner_pos.buf; + return 0; +} + +static const struct stage_ops encode_ops = { + .emit_prim_in = encode_prim_in, + .emit_prim_out = emit_nop_out, + .emit_inbuf = encode_inbuf, + .emit_outbuf = emit_nop_out, + .emit_type_seq_in = encode_type_seq_in, + .emit_type_seq_out = encode_type_seq_out, +}; + +static void decode_prim_out(size_t size, void *ptr, void *data) +{ + struct curr_pos *pos = data; + + memcpy(ptr, pos->prim, size); + pos->prim = (char *) pos->prim + size; +} + +static void decode_outbuf(size_t size, void *ptr, void *data) +{ + ((struct curr_pos *) data)->buf++; +} + +static int decode_type_seq_in(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, const void *inst) +{ + return 0; +} + +static int decode_type_seq_out(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, void *inst) +{ + struct curr_pos inner_pos; + struct curr_pos *pos = data; + int ret; + size_t i; + + inner_pos.buf = pos->buf; + inner_pos.prim = (void *) pos->buf->ptr; + + for (i = 0; i < n_inst; i++) { + ret = emit_inner_type_out(type, &decode_ops, &inner_pos, &inst); + if (ret) + return ret; + } + + pos->buf = inner_pos.buf; + return 0; +} + +static const struct stage_ops decode_ops = { + .emit_prim_in = emit_nop_in, + .emit_prim_out = decode_prim_out, + .emit_inbuf = emit_nop_in, + .emit_outbuf = decode_outbuf, + .emit_type_seq_in = decode_type_seq_in, + .emit_type_seq_out = decode_type_seq_out, +}; + +static void free_inbuf(size_t size, const void *ptr, void *data) +{ + ((struct curr_buf *) data)->inbuf++; +} + +static void free_outbuf(size_t size, void *ptr, void *data) +{ + ((struct curr_buf *) data)->outbuf++; +} + +static int free_type_seq_in(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, const void *inst) +{ + struct curr_buf *curr = data; + int ret = 0; + size_t i; + + if (n_inst) { + free((void *) curr->inbuf->ptr); + } + + curr->inbuf++; + + for (i = 0; i < n_inst; i++) { + ret = emit_inner_type_in(type, &free_ops, data, &inst); + if (ret) + return ret; + } + + return 0; +} + +static int free_type_seq_out(const struct hrpc_method_def_interp4 *def, + const struct hrpc_inner_type_def_interp4 *type, + void *data, size_t n_inst, void *inst) +{ + struct curr_buf *curr = data; + int ret = 0; + size_t i; + + if (n_inst) { + free((void *) curr->inbuf->ptr); + free((void *) curr->outbuf->ptr); + } + + curr->inbuf++; + curr->outbuf++; + + for (i = 0; i < n_inst; i++) { + ret = emit_inner_type_out(type, &free_ops, data, &inst); + if (ret) + return ret; + } + + return 0; +} + +static const struct stage_ops free_ops = { + .emit_prim_in = emit_nop_in, + .emit_prim_out = emit_nop_out, + .emit_inbuf = free_inbuf, + .emit_outbuf = free_outbuf, + .emit_type_seq_in = free_type_seq_in, + .emit_type_seq_out = free_type_seq_out, +}; + +static int count_args(const struct hrpc_method_def_interp4 *def, + struct buf_count *count, va_list list) +{ + int ret; + + if (def->msg_id > 30) + count->n_prim_in += 4; + + ret = emit_args(def, &count_ops, count, list); + if (ret) + return ret; + + if (count->n_prim_in) + count->n_inbufs++; + if (count->n_prim_out) + count->n_outbufs++; + + return 0; +} + +static void free_args(const struct hrpc_method_def_interp4 *def, + const struct buf_count *count, + struct fastrpc_invoke_args *args, + va_list list); + +static struct fastrpc_invoke_args *alloc_args(const struct hrpc_method_def_interp4 *def, + const struct buf_count *count, + va_list list) +{ + struct curr_buf curr_buf = { NULL, NULL }; + struct fastrpc_invoke_args *args; + size_t i; + int ret = -1; + va_list peek; + + args = malloc(sizeof(*args) * (count->n_inbufs + count->n_outbufs)); + if (args == NULL) + return NULL; + + for (i = 0; i < count->n_inbufs + count->n_outbufs; i++) { + args[i].fd = -1; + args[i].attr = 0; + args[i].ptr = 0; + } + + curr_buf.inbuf = &args[0]; + curr_buf.outbuf = &args[count->n_inbufs]; + + if (count->n_prim_in) { + curr_buf.inbuf->length = count->n_prim_in; + curr_buf.inbuf->ptr = (__u64) malloc(count->n_prim_in); + if (curr_buf.inbuf->ptr == 0) + goto err; + curr_buf.inbuf++; + } + + if (count->n_prim_out) { + curr_buf.outbuf->length = count->n_prim_out; + curr_buf.outbuf->ptr = (__u64) malloc(count->n_prim_out); + if (curr_buf.outbuf->ptr == 0) + goto err; + curr_buf.outbuf++; + } + + va_copy(peek, list); + ret = emit_args(def, &alloc_ops, &curr_buf, peek); + va_end(peek); + if (ret) + goto err; + + return args; + +err: + va_copy(peek, list); + free_args(def, count, args, peek); + va_end(peek); + return NULL; +} + +static int encode_args(const struct hrpc_method_def_interp4 *def, + const struct buf_count *count, + struct fastrpc_invoke_args *args, + va_list list) +{ + struct curr_pos curr_pos; + + curr_pos.buf = &args[0]; + if (count->n_prim_in) { + curr_pos.prim = (void *) args[0].ptr; + curr_pos.buf++; + } else { + curr_pos.prim = NULL; + } + + if (def->msg_id > 30) { + *(uint32_t *) curr_pos.prim = def->msg_id; + curr_pos.prim = (uint32_t *) curr_pos.prim + 1; + } + + return emit_args(def, &encode_ops, &curr_pos, list); +} + +static void decode_args(const struct hrpc_method_def_interp4 *def, + const struct buf_count *count, + struct fastrpc_invoke_args *args, + va_list list) +{ + struct curr_pos curr_pos; + + curr_pos.buf = &args[count->n_inbufs]; + if (count->n_prim_out) { + curr_pos.prim = (void *) args[count->n_inbufs].ptr; + curr_pos.buf++; + } else { + curr_pos.prim = NULL; + } + + emit_args(def, &decode_ops, &curr_pos, list); +} + +static void free_args(const struct hrpc_method_def_interp4 *def, + const struct buf_count *count, + struct fastrpc_invoke_args *args, + va_list list) +{ + struct curr_buf curr_buf = { NULL, NULL }; + + curr_buf.inbuf = &args[0]; + curr_buf.outbuf = &args[count->n_inbufs]; + + if (count->n_prim_in) { + if (curr_buf.inbuf->ptr) + free((void *) curr_buf.inbuf->ptr); + curr_buf.inbuf++; + } + + if (count->n_prim_out) { + if (curr_buf.outbuf->ptr) + free((void *) curr_buf.outbuf->ptr); + curr_buf.outbuf++; + } + + emit_args(def, &free_ops, &curr_buf, list); + + free(args); +} + +/* + * 1. validate def and count prim_in, prim_out sizes + * 2. construct prim_in, sequences with nestings + * 3. point inbufs to sequences, nested sequences + * 4. return prim_out + */ +int vhexagonrpc(const struct hrpc_method_def_interp4 *def, + int fd, uint32_t handle, va_list list) +{ + struct buf_count count = { 0, 0, 0, 0 }; + struct fastrpc_invoke invoke; + struct fastrpc_invoke_args *args; + va_list peek; + int ret; + + va_copy(peek, list); + ret = count_args(def, &count, peek); + va_end(peek); + if (ret) + return ret; + + va_copy(peek, list); + args = alloc_args(def, &count, peek); + va_end(peek); + if (args == NULL) + return -1; + + va_copy(peek, list); + ret = encode_args(def, &count, args, peek); + va_end(peek); + if (ret) + goto err; + + invoke.args = (__u64) args; + invoke.handle = handle; + if (def->msg_id > 30) + invoke.sc = REMOTE_SCALARS_MAKE(31, + count.n_inbufs, count.n_outbufs); + else + invoke.sc = REMOTE_SCALARS_MAKE(def->msg_id, + count.n_inbufs, count.n_outbufs); + + ret = ioctl(fd, FASTRPC_IOCTL_INVOKE, (__u64) &invoke); + if (ret) + goto err; + + va_copy(peek, list); + decode_args(def, &count, args, peek); + va_end(peek); + +err: + va_copy(peek, list); + free_args(def, &count, args, peek); + va_end(peek); + return ret; +} + +int hexagonrpc(const struct hrpc_method_def_interp4 *def, + int fd, uint32_t handle, ...) +{ + va_list list; + int ret; + + va_start(list, handle); + ret = vhexagonrpc(def, fd, handle, list); + va_end(list); + + return ret; +} diff --git a/libhexagonrpc/interface/remotectl.c b/libhexagonrpc/interface/remotectl.c new file mode 100644 index 0000000..d1a170b --- /dev/null +++ b/libhexagonrpc/interface/remotectl.c @@ -0,0 +1,52 @@ +/* + * Remote processor control interface - method definitions + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +struct hrpc_arg_def_interp4 remotectl_open_args[] = { + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 remotectl_open_def = { + .msg_id = 0, + .n_args = HRPC_ARRAY_SIZE(remotectl_open_args), + .args = remotectl_open_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +struct hrpc_arg_def_interp4 remotectl_close_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_OUT_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_OUT_BLOB, sizeof(uint32_t) }, +}; + +const struct hrpc_method_def_interp4 remotectl_close_def = { + .msg_id = 1, + .n_args = HRPC_ARRAY_SIZE(remotectl_close_args), + .args = remotectl_close_args, + .n_inner_types = 0, + .inner_types = NULL, +}; diff --git a/libhexagonrpc/meson.build b/libhexagonrpc/meson.build index 24efb34..6811853 100644 --- a/libhexagonrpc/meson.build +++ b/libhexagonrpc/meson.build @@ -1,7 +1,8 @@ libhexagonrpc = shared_library('hexagonrpc', - 'context.c', - 'fastrpc.c', - 'interfaces.c', + 'error.c', + 'handle.c', + 'hexagonrpc.c', + 'interface/remotectl.c', 'session.c', c_args : cflags, include_directories : include, diff --git a/tests/meson.build b/tests/meson.build index e7303c7..70fd8ee 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -24,5 +24,13 @@ test_hexagonfs = executable('test_hexagonfs', include_directories : include, ) +test_hexagonrpc = executable('test_hexagonrpc', + 'test_hexagonrpc.c', + '../libhexagonrpc/hexagonrpc.c', + c_args : cflags, + include_directories : include, +) + test('iobuffer', test_iobuffer) test('hexagonfs', test_hexagonfs, args : [sample_file]) +test('hexagonrpc', test_hexagonrpc) diff --git a/tests/test_hexagonfs.c b/tests/test_hexagonfs.c index ae9ee7a..38e767d 100644 --- a/tests/test_hexagonfs.c +++ b/tests/test_hexagonfs.c @@ -20,8 +20,8 @@ */ #include -#include #include +#include #include #include diff --git a/tests/test_hexagonrpc.c b/tests/test_hexagonrpc.c new file mode 100644 index 0000000..f168ad8 --- /dev/null +++ b/tests/test_hexagonrpc.c @@ -0,0 +1,177 @@ +/* + * FastRPC reverse tunnel - tests for virtual filesystem + * + * Copyright (C) 2025 HexagonRPC Contributors + * + * This file is part of HexagonRPC. + * + * HexagonRPC is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __GLIBC__ +typedef unsigned long int ioctl_operation; +#else +typedef int ioctl_operation; +#endif + +struct expected_invoke_arg { + size_t len; + const void *ptr; +}; + +static const struct expected_invoke_arg *expected = NULL; +static uint32_t expected_sc = 0; + +static const uint32_t no_args_sc = REMOTE_SCALARS_MAKE(0, 0, 0); + +static const struct hrpc_method_def_interp4 no_args_def = { + .msg_id = 0, + .n_args = 0, + .args = NULL, + .n_inner_types = 0, + .inner_types = NULL, +}; + +static const char scalar_arg_exp0[] = { + 0x67, 0x45, 0x23, 0x01, + 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static const char scalar_arg_exp1[] = { + 'h', 'i', +}; + +static const struct expected_invoke_arg scalar_arg_exp[] = { + { + .len = sizeof(scalar_arg_exp0), + .ptr = scalar_arg_exp0, + }, + { + .len = sizeof(scalar_arg_exp1), + .ptr = scalar_arg_exp1, + }, + { + .len = 0, + .ptr = NULL, + }, +}; + +static const uint32_t scalar_arg_sc = REMOTE_SCALARS_MAKE(0, 3, 0); + +static const struct hrpc_arg_def_interp4 scalar_arg_args[] = { + { HRPC_ARG_WORD, sizeof(uint32_t) }, + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, + { HRPC_ARG_BLOB_SEQ, sizeof(char) }, +}; + +static const struct hrpc_method_def_interp4 scalar_arg_def = { + .msg_id = 0, + .n_args = HRPC_ARRAY_SIZE(scalar_arg_args), + .args = scalar_arg_args, + .n_inner_types = 0, + .inner_types = NULL, +}; + +int ioctl(int fd, ioctl_operation op, ...) +{ + struct fastrpc_invoke *invoke; + struct fastrpc_invoke_args *args; + size_t i, n_inbufs, n_outbufs; + void *data; + va_list list; + + va_start(list, op); + data = va_arg(list, void *); + va_end(list); + + if (op != (ioctl_operation) FASTRPC_IOCTL_INVOKE) { + return syscall(SYS_ioctl, fd, op, data); + } else { + invoke = data; + + if (fd != -1) + return -1; + + if (invoke->handle != 0) + return -1; + + if (invoke->sc != expected_sc) + return -1; + + n_inbufs = REMOTE_SCALARS_INBUFS(invoke->sc); + n_outbufs = REMOTE_SCALARS_OUTBUFS(invoke->sc); + args = (struct fastrpc_invoke_args *) invoke->args; + + for (i = 0; i < n_inbufs; i++) { + if (args[i].fd != -1 || args[i].attr != 0) + return -1; + + if (args[i].length != expected[i].len) + return -1; + + if (memcmp((void *) args[i].ptr, + expected[i].ptr, + args[i].length)) + return -1; + } + + for (i = n_inbufs; i < n_inbufs + n_outbufs; i++) { + if (args[i].fd != -1 || args[i].attr != 0) + return -1; + + if (args[i].length < expected[i].len) + return -1; + + memcpy((void *) args[i].ptr, + expected[i].ptr, + args[i].length); + } + + return 0; + } +} + +int main(void) +{ + int ret, fd = -1; + uint32_t hdl = 0; + + expected_sc = no_args_sc; + expected = NULL; + ret = hexagonrpc(&no_args_def, fd, hdl); + if (ret) + return 1; + + expected_sc = scalar_arg_sc; + expected = scalar_arg_exp; + ret = hexagonrpc(&scalar_arg_def, fd, hdl, + (uint32_t) 0x01234567, + (uint32_t) 2, (const void *) "hi", + (uint32_t) 0, (const void *) NULL); + if (ret) + return 1; + + return 0; +} diff --git a/tests/test_iobuffer.c b/tests/test_iobuffer.c index 99da73f..a252f24 100644 --- a/tests/test_iobuffer.c +++ b/tests/test_iobuffer.c @@ -19,7 +19,8 @@ * along with this program. If not, see . */ -#include +#include +#include #include #include "../hexagonrpcd/iobuffer.h"