mirror of
https://github.com/linux-msm/hexagonrpc.git
synced 2026-10-07 15:29:50 -07:00
Compare commits
81
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2377fd46f0 | ||
|
|
372ca67d7a | ||
|
|
4b1ecd8505 | ||
|
|
53e347f39d | ||
|
|
75150d4860 | ||
|
|
5620db43a7 | ||
|
|
0e9e03b37b | ||
|
|
61bb51bbc9 | ||
|
|
ffbc4da830 | ||
|
|
2415d5f90d | ||
|
|
7aab0f2c42 | ||
|
|
b7eff23db1 | ||
|
|
716e1e27c7 | ||
|
|
54ba43fbc3 | ||
|
|
f6d8a0e686 | ||
|
|
9db873f24f | ||
|
|
3f46980dc9 | ||
|
|
30fa49eb20 | ||
|
|
b7ad1021a2 | ||
|
|
f23297f962 | ||
|
|
c4c469bd8a | ||
|
|
6840e1dcfa | ||
|
|
aaef8a1e28 | ||
|
|
63b1711021 | ||
|
|
39dd3aec6e | ||
|
|
892b9f549e | ||
|
|
b410c74a81 | ||
|
|
24c3eea173 | ||
|
|
8949140fa6 | ||
|
|
154bd2631c | ||
|
|
b4db2118cb | ||
|
|
ecd901bc48 | ||
|
|
a31ec9caf9 | ||
|
|
0156911ba4 | ||
|
|
c82b2da4eb | ||
|
|
cd314096a3 | ||
|
|
1162ccd84c | ||
|
|
a56406c928 | ||
|
|
4054893648 | ||
|
|
d6c458bd17 | ||
|
|
753ebda39b | ||
|
|
1dc590d638 | ||
|
|
f085f578e3 | ||
|
|
0b4c7bffaf | ||
|
|
00b5f80608 | ||
|
|
9ea9bed77b | ||
|
|
23585daf67 | ||
|
|
e0d6c2a7ac | ||
|
|
329f1ae841 | ||
|
|
2358946095 | ||
|
|
06ef0b17a4 | ||
|
|
d87d8ffc47 | ||
|
|
947f52d779 | ||
|
|
4983830139 | ||
|
|
5e04177155 | ||
|
|
ee439dd6cb | ||
|
|
b686df88d7 | ||
|
|
ccaa9728d9 | ||
|
|
f5e05d0e7d | ||
|
|
b6d1f60ae9 | ||
|
|
ac6b6d61d0 | ||
|
|
44d4a818aa | ||
|
|
2b8875d185 | ||
|
|
4fb42aaa79 | ||
|
|
d791bb48a0 | ||
|
|
9d97f21f4a | ||
|
|
1874e7a109 | ||
|
|
aa1cfca7b4 | ||
|
|
4e2d1d46c6 | ||
|
|
3becf15c7a | ||
|
|
3bf791122f | ||
|
|
ea226ef7b9 | ||
|
|
77ff6338be | ||
|
|
1e83c7316e | ||
|
|
3af581489d | ||
|
|
36bff0f541 | ||
|
|
0ed58012fa | ||
|
|
cd8a751732 | ||
|
|
9946564fe9 | ||
|
|
4a5f23e5d9 | ||
|
|
7dfd7d778c |
No files matched your search
@@ -1,65 +0,0 @@
|
||||
#
|
||||
# Build system
|
||||
#
|
||||
# Copyright (C) 2022 Richard Acayan
|
||||
#
|
||||
# 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 <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
QMIC = qmic
|
||||
CC = gcc
|
||||
LIBS = -lprotobuf-c -lqrtr
|
||||
CFLAGS = -Wall -Wextra -Wpedantic -Ibuild -I.
|
||||
PROTOC_C = protoc-c
|
||||
|
||||
build/sensh: build/sensh.o build/qmi_sns_client.o build/sns_client_event_msg.pb-c.o build/sns_client_request_msg.pb-c.o build/sns_proximity_event.pb-c.o build/sns_std_attr_event.pb-c.o build/sns_std_attr_req.pb-c.o build/sns_std_sensor_event.pb-c.o build/sns_std_suid.pb-c.o build/sns_suid_event.pb-c.o build/sns_suid_req.pb-c.o
|
||||
$(CC) -o build/sensh build/sensh.o build/qmi_sns_client.o build/sns_client_event_msg.pb-c.o build/sns_client_request_msg.pb-c.o build/sns_proximity_event.pb-c.o build/sns_std_attr_event.pb-c.o build/sns_std_attr_req.pb-c.o build/sns_std_sensor_event.pb-c.o build/sns_std_suid.pb-c.o build/sns_suid_event.pb-c.o build/sns_suid_req.pb-c.o $(LIBS)
|
||||
|
||||
build/qmi_%.d: build/qmi_%.c
|
||||
$(CC) $(CFLAGS) -MM -MT build/$*.o -o $@ $<
|
||||
|
||||
build/%.pb-c.d: build/%.pb-c.c
|
||||
$(CC) $(CFLAGS) -MM -MT build/$*.o -o $@ $<
|
||||
|
||||
build/%.d: %.c
|
||||
$(CC) $(CFLAGS) -MM -MT build/$*.o -o $@ $<
|
||||
|
||||
build/qmi_%.o: build/qmi_%.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
build/%.pb-c.o: build/%.pb-c.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
build/%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
build/qmi_%.c build/qmi_%.h: qmi/%.qmi
|
||||
cd build && $(QMIC) -k < ../$<
|
||||
|
||||
build/%.pb-c.c build/%.pb-c.h: protobuf/%.proto
|
||||
$(PROTOC_C) --c_out=build -Iprotobuf $<
|
||||
|
||||
include build/sensh.d
|
||||
include build/qmi_sns_client.d
|
||||
include build/sns_client_event_msg.pb-c.d
|
||||
include build/sns_client_request_msg.pb-c.d
|
||||
include build/sns_proximity_event.pb-c.d
|
||||
include build/sns_std_attr_event.pb-c.d
|
||||
include build/sns_std_attr_req.pb-c.d
|
||||
include build/sns_std_sensor_event.pb-c.d
|
||||
include build/sns_std_suid.pb-c.d
|
||||
include build/sns_suid_event.pb-c.d
|
||||
include build/sns_suid_req.pb-c.d
|
||||
@@ -1,65 +1,158 @@
|
||||
This is a proof-of-concept for interacting with the Snapdragon Sensor Core
|
||||
using the reverse-engineered protocol buffers. It was made to try to
|
||||
initialize it, but the Pixel 3a is missing some sensors once the firmware is
|
||||
loaded.
|
||||
This directory contains a FastRPC ioctl wrapper and a reverse tunnel.
|
||||
|
||||
A best effort is made to prefix all log messages with `sensh: ` so it's clear
|
||||
which lines were entered by the user.
|
||||
FastRPC is used to communicate with the Context Hub Runtime Environment, a
|
||||
program on the DSP that manages sensors, and to serve files to remote
|
||||
processors.
|
||||
|
||||
# Requirements
|
||||
# Wrapper function
|
||||
|
||||
- gcc
|
||||
- libqrtr
|
||||
- meson or make
|
||||
- protobuf-c
|
||||
- qmic (https://github.com/andersson/qmic)
|
||||
The wrapper function is designed so that the ioctl arguments do not need to be
|
||||
constructed for each remote method. Instead, it accepts an open file descriptor,
|
||||
handle, method definition, and arguments to the remote method using `va_args`.
|
||||
This makes it relatively easy to add remote methods without the use of the QAIC
|
||||
interface compiler or a free software alternative.
|
||||
|
||||
# Installation
|
||||
## Installation
|
||||
|
||||
This can be compiled using Meson:
|
||||
You can build and install this project using meson:
|
||||
|
||||
$ meson setup build
|
||||
$ ninja -C build
|
||||
~/sensh/fastrpc $ meson setup build
|
||||
~/sensh/fastrpc $ ninja -C build
|
||||
~/sensh/fastrpc # ninja -C build install
|
||||
|
||||
There is also a Makefile to compile this, if you can get it to work:
|
||||
## Usage
|
||||
|
||||
$ mkdir build
|
||||
$ make -k
|
||||
Making already-defined method calls is relatively straightforward, depending on
|
||||
the remote method that you're calling. You just need the function definition, an
|
||||
open file descriptor, the handle, and the arguments for it.
|
||||
|
||||
# Usage
|
||||
uint32_t prev_ctx, prev_result, nested_outbufs_len;
|
||||
uint32_t ctx, nested_handle, nested_sc, nested_inbufs_len;
|
||||
uint32_t nested_inbufs_size;
|
||||
const void *nested_outbufs;
|
||||
void *nested_inbufs;
|
||||
int fd;
|
||||
|
||||
Sensh doesn't automatically track, probe, or look up sensors; that is for a full
|
||||
implementation. Instead, it expects you to look up the sensor and copy the ID
|
||||
with your terminal emulator:
|
||||
ret = fastrpc2(&adsp_listener_next2_def, fd, ADSP_LISTENER_HANDLE,
|
||||
prev_ctx,
|
||||
prev_result,
|
||||
nested_outbufs_len, nested_outbufs,
|
||||
&ctx,
|
||||
&nested_handle,
|
||||
&nested_sc,
|
||||
&nested_inbufs_len,
|
||||
nested_inbufs_size, nested_inbufs);
|
||||
|
||||
lookup accel_cal
|
||||
sensh: accel_cal sensor found: A1392FDF217B7D9EI6648AED8C04DDFB9
|
||||
attr A1392FDF217B7D9EI6648AED8C04DDFB9
|
||||
sensh: name: ASH_CAL
|
||||
sensh: vendor: GOOGLE
|
||||
sensh: type: accel_cal
|
||||
sensh: version: 1
|
||||
sensh: api: sns_cal.proto
|
||||
sensh: rates: 10.000000
|
||||
sensh: stream type: 1
|
||||
sensh: physical sensor: 0
|
||||
sensh: available: 1
|
||||
All inputs are specified before all outputs. Words in the first (called "prim",
|
||||
or primary in QAIC-generated code) input and output buffers go in the form of
|
||||
`uint32_t` arguments. Each buffer is accepted as a `uint32_t` length and a
|
||||
pointer.
|
||||
|
||||
You can send 3 messages: lookup, attr, and watch. The lookup command returns
|
||||
SUIDs for the passed data type. The attr command returns attributes for the
|
||||
sensor. Finally, the watch command tells the sensor core to send events from a
|
||||
sensor whenever the sensor's value changes. The watch command is only valid if
|
||||
the stream type is 1 or 2.
|
||||
### Creating function definitions
|
||||
|
||||
An EOF (normally Ctrl+D) is enough to exit the shell unless the sensor core
|
||||
died.
|
||||
Assuming you already have knowledge about the remote method to call, you must
|
||||
first write a function definition for it. A function definition is a struct with
|
||||
information on its method ID and the arguments it accepts.
|
||||
|
||||
# References
|
||||
First, the method ID is taken from the first argument of the
|
||||
`REMOTE_SCALARS_MAKE()` macro or the second argument of the
|
||||
`REMOTE_SCALARS_MAKEX()` macro
|
||||
(defined [here](https://android.googlesource.com/platform/external/fastrpc/+/d6d6e3bba244e40e6043bd687f4cacf090a767b5/inc/remote.h#80)).
|
||||
|
||||
The following sources were used as reference:
|
||||
Example:
|
||||
|
||||
- [https://android.googlesource.com/platform/system/chre](https://android.googlesource.com/platform/system/chre)
|
||||
- [https://android.googlesource.com/platform/external/fastrpc](https://android.googlesource.com/platform/external/fastrpc)
|
||||
- [https://github.com/calebccff/sensordaemon-re](https://github.com/calebccff/sensordaemon-re)
|
||||
- [https://gitlab.freedesktop.org/mobile-broadband/libqmi/-/merge\_requests/346](https://gitlab.freedesktop.org/mobile-broadband/libqmi/-/merge_requests/346)
|
||||
- [https://git.linaro.org/landing-teams/working/qualcomm/fastrpc.git](https://git.linaro.org/landing-teams/working/qualcomm/fastrpc.git)
|
||||
REMOTE_SCALARS_MAKE(4, 2, 2)
|
||||
|
||||
has the method 4.
|
||||
|
||||
Next, information on how many arguments it takes must be specified. There are
|
||||
four types of arguments:
|
||||
|
||||
- 32-bit input words in the first input buffer, excluding lengths for the input
|
||||
and output buffers
|
||||
- 32-bit output words in the first output buffer
|
||||
- input buffers, excluding the first
|
||||
- output buffers, excluding the first
|
||||
|
||||
To get the size of the first input and output buffers, a dump must be consulted,
|
||||
or the prim argument of generated C files:
|
||||
|
||||
invoking via fastrpc, handle 3, method 4, 2 inbufs, 2 outbufs, 0 inhandles, 0 outhandles
|
||||
fastrpc argument 00000000FFFFFFFF0000000000000000 // 16 bytes, or 4 words
|
||||
fastrpc argument
|
||||
invoking via fastrpc, handle 5, method 4, 1 inbufs, 1 outbufs, 0 inhandles, 0 outhandles
|
||||
fastrpc return 91000000000000000002020029000000 // 16 bytes, or 4 words
|
||||
fastrpc return
|
||||
|
||||
Since there are 2 input buffers excluding the first (these can have a variable
|
||||
size), 2 must be subtracted from the 4 input words. These will be provided by
|
||||
the wrapper as the sizes for the variable-length input and output buffers.
|
||||
|
||||
Counting each of these will give the numbers needed for the function definition.
|
||||
|
||||
A function definition looks like:
|
||||
|
||||
const struct fastrpc_function_def_interp2 adsp_listener_next2_def = {
|
||||
.msg_id = 4,
|
||||
.in_nums = 2,
|
||||
.in_bufs = 1,
|
||||
.out_nums = 4,
|
||||
.out_bufs = 1,
|
||||
};
|
||||
|
||||
or:
|
||||
|
||||
#define DEFINE_REMOTE_PROCEDURE(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, \
|
||||
};
|
||||
|
||||
DEFINE_REMOTE_PROCEDURE(4, adsp_listener_next2, 2, 1, 4, 1)
|
||||
|
||||
# Reverse tunnel
|
||||
|
||||
The reverse tunnel calls the `adsp_listener_next2` remote method to receive
|
||||
method calls for the Application Processor.
|
||||
|
||||
Interfaces are initialized in the `start_reverse_tunnel` function, in hexagonrpcd/rpcd.c.
|
||||
|
||||
## HexagonFS
|
||||
|
||||
The reverse tunnel's `apps_std` interface serves files to the remote processor.
|
||||
These files are searched for in a directory tree, starting at the location
|
||||
defined by the `-R` option, or in `/usr/share/qcom` by default:
|
||||
|
||||
HexagonRPCD file/dir Android file/dir
|
||||
acdb /vendor/etc/acdbdata
|
||||
dsp /vendor/dsp
|
||||
sensors/config /vendor/etc/sensors/config
|
||||
sensors/registry /mnt/vendor/persist/sensors/registry/registry
|
||||
sensors/sns_reg.conf /vendor/etc/sensors/sns_reg_config
|
||||
socinfo /sys/devices/soc0
|
||||
|
||||
These files and directories should be populated with files from your device's
|
||||
Android firmware.
|
||||
|
||||
If you can pass the `-R` option, the convention is to pass `-R
|
||||
/usr/share/qcom/SOC/VENDOR/DEVICE`, where SOC is the SoC name in lowercase,
|
||||
VENDOR is the capitalized name of the device vendor, and DEVICE is the device
|
||||
name (e.g. `-R /usr/share/qcom/sdm845/SHIFT/axolotl` or `-R
|
||||
/usr/share/qcom/sdm845/Thundercomm/db845c`).
|
||||
|
||||
# Future plans
|
||||
|
||||
Reverse tunnels are separated by the process that opens the file descriptor and
|
||||
cannot service requests from other processes that do not share the same file
|
||||
descriptor. There should be some daemon that opens the device and allows clients
|
||||
to send requests.
|
||||
|
||||
FastRPC may be the way to offload work to the DSPs. When a FastRPC function call
|
||||
is made, the `<name>_skel_invoke` function in a shared object named
|
||||
`lib<name>_skel.so` is called on the DSP. Further investigation is needed to
|
||||
make a working build system for this.
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Sensor SUID
|
||||
* FastRPC interface list for building method definitions
|
||||
*
|
||||
* Copyright (C) 2022 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
@@ -19,9 +19,6 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
#define HEXAGONRPC_BUILD_METHOD_DEFINITIONS 1
|
||||
|
||||
message sns_std_suid {
|
||||
required fixed64 suid_low = 1;
|
||||
required fixed64 suid_high = 2;
|
||||
}
|
||||
#include "interfaces/chre_slpi.def"
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Context Hub Runtime Environment interface
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* CHRE client daemon entry point
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <libhexagonrpc/fastrpc.h>
|
||||
#include <libhexagonrpc/interfaces/remotectl.def>
|
||||
#include <libhexagonrpc/session.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct fastrpc_context *ctx;
|
||||
int fd, ret;
|
||||
|
||||
fd = hexagonrpc_fd_from_env();
|
||||
if (fd == -1)
|
||||
return 1;
|
||||
|
||||
ret = remotectl_open(fd, "chre_slpi", &ctx, remotectl_err);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
ret = chre_slpi_start_thread(ctx);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Could not start CHRE\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = chre_slpi_wait_on_thread_exit(ctx);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Could not wait for CHRE thread\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
remotectl_close(ctx, remotectl_err);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
executable('chrecd',
|
||||
'interfaces.c',
|
||||
'main.c',
|
||||
c_args : cflags,
|
||||
include_directories : include,
|
||||
install : true,
|
||||
link_with : libhexagonrpc,
|
||||
install_dir : client_target,
|
||||
)
|
||||
@@ -1,143 +0,0 @@
|
||||
This directory contains a FastRPC ioctl wrapper and a reverse tunnel.
|
||||
|
||||
FastRPC is used to communicate with the Context Hub Runtime Environment, a
|
||||
program on the DSP that manages sensors, and to serve files to remote
|
||||
processors.
|
||||
|
||||
# Wrapper function
|
||||
|
||||
The wrapper function is designed so that the ioctl arguments do not need to be
|
||||
constructed for each remote method. Instead, it accepts an open file descriptor,
|
||||
handle, method definition, and arguments to the remote method using `va_args`.
|
||||
This makes it relatively easy to add remote methods without the use of the QAIC
|
||||
interface compiler or a free software alternative.
|
||||
|
||||
## Installation
|
||||
|
||||
There is currently no build system.
|
||||
|
||||
$ gcc -o libhexagonrpc.so -shared fastrpc.c context.c
|
||||
|
||||
## Usage
|
||||
|
||||
Making already-defined method calls is relatively straightforward, depending on
|
||||
the remote method that you're calling. You just need the function definition, an
|
||||
open file descriptor, the handle, and the arguments for it.
|
||||
|
||||
ret = fastrpc2(&adsp_listener_next2_def, fd, ADSP_LISTENER_HANDLE,
|
||||
prev_ctx,
|
||||
prev_result,
|
||||
nested_outbufs_len, nested_outbufs,
|
||||
ctx,
|
||||
nested_handle,
|
||||
nested_sc,
|
||||
nested_inbufs_len,
|
||||
nested_inbufs_size, nested_inbufs);
|
||||
|
||||
All inputs are specified before all outputs. Words in the first input and output
|
||||
buffers go in the form of `uint32_t` arguments. Each buffer is accepted as a
|
||||
`uint32_t` length and a pointer.
|
||||
|
||||
### Creating function definitions
|
||||
|
||||
Assuming you already have knowledge about the remote method to call, you must
|
||||
first write a function definition for it. A function definition is a struct with
|
||||
information on its method ID and the arguments it accepts.
|
||||
|
||||
First, the method ID is taken from the first argument of the
|
||||
`REMOTE_METHOD_MAKE()` macro or the second argument of the
|
||||
`REMOTE_METHOD_MAKEX()` macro.
|
||||
|
||||
Example:
|
||||
|
||||
REMOTE_SCALARS_MAKE(4, 2, 2)
|
||||
|
||||
has the method 4.
|
||||
|
||||
Next, information on how many arguments it takes must be specified. There are
|
||||
four types of arguments:
|
||||
|
||||
- 32-bit input words in the first input buffer, excluding lengths for the input
|
||||
and output buffers
|
||||
- 32-bit output words in the first output buffer
|
||||
- input buffers, excluding the first
|
||||
- output buffers, excluding the first
|
||||
|
||||
To get the size of the first input and output buffers, a dump must be consulted,
|
||||
or the prim argument of generated C files:
|
||||
|
||||
invoking via fastrpc, handle 3, method 4, 2 inbufs, 2 outbufs, 0 inhandles, 0 outhandles
|
||||
fastrpc argument 00000000FFFFFFFF0000000000000000 // 16 bytes, or 4 words
|
||||
fastrpc argument
|
||||
invoking via fastrpc, handle 5, method 4, 1 inbufs, 1 outbufs, 0 inhandles, 0 outhandles
|
||||
fastrpc return 91000000000000000002020029000000 // 16 bytes, or 4 words
|
||||
fastrpc return
|
||||
|
||||
Since there are 2 input buffers excluding the first (these can have a variable
|
||||
size), 2 must be subtracted from the 4 input words. These will be provided by
|
||||
the wrapper as the sizes for the variable-length input and output buffers.
|
||||
|
||||
Counting each of these will give the numbers needed for the function definition.
|
||||
|
||||
A function definition looks like:
|
||||
|
||||
const struct fastrpc_function_def_interp2 adsp_listener_next2_def = {
|
||||
.msg_id = 4,
|
||||
.in_nums = 2,
|
||||
.in_bufs = 1,
|
||||
.out_nums = 4,
|
||||
.out_bufs = 1,
|
||||
};
|
||||
|
||||
or:
|
||||
|
||||
#define DEFINE_REMOTE_PROCEDURE(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, \
|
||||
};
|
||||
|
||||
DEFINE_REMOTE_PROCEDURE(4, adsp_listener_next2, 2, 1, 4, 1)
|
||||
|
||||
# Reverse tunnel
|
||||
|
||||
The reverse tunnel calls the `adsp_listener_next2` remote method to receive
|
||||
method calls for the Application Processor.
|
||||
|
||||
Interfaces are listed in the `fastrpc_listener_interfaces` variable.
|
||||
|
||||
## HexagonFS
|
||||
|
||||
The reverse tunnel's `apps_std` interface serves files to the remote processor.
|
||||
These files are searched for in:
|
||||
|
||||
Physical file/dir Android file/dir
|
||||
/etc/qcom/sns_reg.conf /vendor/etc/sensors/sns_reg_config
|
||||
/etc/qcom/sensors.d /vendor/etc/sensors/config
|
||||
/var/lib/qcom/sensors /mnt/vendor/persist/sensors/registry
|
||||
/usr/lib/qcom/adsp /vendor/dsp/adsp
|
||||
/usr/lib/qcom/adsp/avs /vendor/etc/acdbdata
|
||||
|
||||
These files and directories should be populated with files from your device's
|
||||
Android firmware.
|
||||
|
||||
# Future plans
|
||||
|
||||
This directory is a bit messy. It should be organized into different
|
||||
subdirectories and have a build system. This should also be renamed to
|
||||
HexagonRPC to avoid a name collision.
|
||||
|
||||
Reverse tunnels are separated by the process that opens the file descriptor and
|
||||
cannot service requests from other processes that do not share the same file
|
||||
descriptor. There should be some daemon that opens the device and allows clients
|
||||
to send requests.
|
||||
|
||||
FastRPC may be the way to offload work to the DSPs. When a FastRPC function call
|
||||
is made, the `<name>_skel_invoke` function in a shared object named
|
||||
`lib<name>_skel.so` is called on the DSP. Further investigation is needed to
|
||||
make a working build system for this.
|
||||
@@ -1,236 +0,0 @@
|
||||
/*
|
||||
* FastRPC Example
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libhexagonrpc/fastrpc.h>
|
||||
#include <misc/fastrpc.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "aee_error.h"
|
||||
#include "interfaces/adsp_default_listener.def"
|
||||
#include "interfaces/chre_slpi.def"
|
||||
#include "interfaces/remotectl.def"
|
||||
#include "listener.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 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);
|
||||
}
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
ret = remotectl_open(fd, "adsp_default_listener", &ctx, remotectl_err);
|
||||
if (ret)
|
||||
return 1;
|
||||
|
||||
ret = adsp_default_listener_register(ctx);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Could not register ADSP default listener\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
remotectl_close(ctx, remotectl_err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void *start_reverse_tunnel(void *data)
|
||||
{
|
||||
int *fd = data;
|
||||
int ret;
|
||||
|
||||
ret = register_fastrpc_listener(*fd);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
run_fastrpc_listener(*fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *start_chre_client(void *data)
|
||||
{
|
||||
struct fastrpc_context *ctx;
|
||||
int *fd = data;
|
||||
int ret;
|
||||
|
||||
ret = remotectl_open(*fd, "chre_slpi", &ctx, remotectl_err);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
ret = chre_slpi_start_thread(ctx);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Could not start CHRE\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = chre_slpi_wait_on_thread_exit(ctx);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Could not wait for CHRE thread\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
remotectl_close(ctx, remotectl_err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
pthread_t chre_thread, listener_thread;
|
||||
char *fastrpc_node = NULL;
|
||||
int fd, ret, opt;
|
||||
bool attach_sns = false;
|
||||
|
||||
while ((opt = getopt(argc, argv, "sf:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
fastrpc_node = optarg;
|
||||
break;
|
||||
case 's':
|
||||
attach_sns = true;
|
||||
break;
|
||||
default:
|
||||
printf("Usage: %s [-s] [-f FastRPC node]\n\n", argv[0]);
|
||||
printf("Qualcomm Hexagon filesystem daemon\n\n");
|
||||
printf("\t-f\tFastRPC node to attach to\n");
|
||||
printf("\t-s\tUse INIT_ATTACH_SNS instead of INIT_ATTACH ioctl\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fastrpc_node) {
|
||||
fprintf(stderr, "Invalid FastRPC node: %s\n", fastrpc_node);
|
||||
return 2;
|
||||
}
|
||||
|
||||
printf("Starting %s (%s) on %s\n", argv[0], attach_sns? "INIT_ATTACH_SNS": "INIT_ATTACH", fastrpc_node);
|
||||
|
||||
fd = open(fastrpc_node, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Could not open FastRPC node (%s): %s\n", fastrpc_node, strerror(errno));
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (attach_sns)
|
||||
ret = ioctl(fd, FASTRPC_IOCTL_INIT_ATTACH_SNS, NULL);
|
||||
else
|
||||
ret = ioctl(fd, FASTRPC_IOCTL_INIT_ATTACH, NULL);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Could not attach to FastRPC node: %s\n", strerror(errno));
|
||||
goto err_close_dev;
|
||||
}
|
||||
|
||||
pthread_create(&listener_thread, NULL, start_reverse_tunnel, &fd);
|
||||
pthread_create(&chre_thread, NULL, start_chre_client, &fd);
|
||||
|
||||
pthread_join(listener_thread, NULL);
|
||||
pthread_join(chre_thread, NULL);
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
|
||||
err_close_dev:
|
||||
close(fd);
|
||||
return 4;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
project('fastrpc', 'c')
|
||||
|
||||
include = include_directories('include')
|
||||
|
||||
subdir('libhexagonrpc')
|
||||
|
||||
subdir('hexagonrpcd')
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* FastRPC memory mapping interface implementation
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <misc/fastrpc.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "aee_error.h"
|
||||
#include "apps_mem.h"
|
||||
#include "interfaces/apps_mem.def"
|
||||
#include "listener.h"
|
||||
|
||||
// See fastrpc.git/src/apps_mem_imp.c
|
||||
#define ADSP_MMAP_HEAP_ADDR 4
|
||||
#define ADSP_MMAP_REMOTE_HEAP_ADDR 8
|
||||
#define ADSP_MMAP_ADD_PAGES 0x1000
|
||||
|
||||
struct apps_mem_ctx {
|
||||
int fd;
|
||||
};
|
||||
|
||||
static uint32_t apps_mem_request_map64(void *data,
|
||||
const struct fastrpc_io_buffer *inbufs,
|
||||
struct fastrpc_io_buffer *outbufs)
|
||||
{
|
||||
struct apps_mem_ctx *ctx = data;
|
||||
const struct {
|
||||
uint32_t heap_id;
|
||||
uint32_t lflags;
|
||||
uint32_t rflags;
|
||||
uint32_t padding;
|
||||
uint64_t vin;
|
||||
uint64_t len;
|
||||
} *first_in = inbufs[0].p;
|
||||
struct {
|
||||
uint64_t vapps;
|
||||
uint64_t vadsp;
|
||||
} *first_out = outbufs[0].p;
|
||||
struct fastrpc_req_mmap mmap;
|
||||
int ret;
|
||||
|
||||
if (!(first_in->rflags & ADSP_MMAP_ADD_PAGES)) {
|
||||
fprintf(stderr, "Unsupported mmap operation: DMA buffer request\n");
|
||||
return AEE_EUNSUPPORTED;
|
||||
}
|
||||
|
||||
mmap.fd = -1;
|
||||
mmap.flags = first_in->rflags;
|
||||
mmap.vaddrin = 0;
|
||||
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]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if HEXAGONRPC_VERBOSE
|
||||
printf("mmap(%d, %x, %x, %lu, %lu) -> %" PRIx64 "\n",
|
||||
first_in->heap_id,
|
||||
first_in->lflags,
|
||||
first_in->rflags,
|
||||
first_in->vin,
|
||||
first_in->len,
|
||||
mmap.vaddrout);
|
||||
#endif
|
||||
|
||||
first_out->vapps = 0;
|
||||
first_out->vadsp = mmap.vaddrout & 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fastrpc_interface *fastrpc_apps_mem_init(int fd)
|
||||
{
|
||||
struct fastrpc_interface *iface;
|
||||
struct apps_mem_ctx *ctx;
|
||||
|
||||
iface = malloc(sizeof(*iface));
|
||||
if (iface == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (ctx == NULL)
|
||||
goto err_free_iface;
|
||||
|
||||
memcpy(iface, &apps_mem_interface, sizeof(*iface));
|
||||
|
||||
ctx->fd = fd;
|
||||
|
||||
iface->data = ctx;
|
||||
|
||||
return iface;
|
||||
|
||||
err_free_iface:
|
||||
free(iface);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fastrpc_apps_mem_deinit(struct fastrpc_interface *iface)
|
||||
{
|
||||
free(iface->data);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static const struct fastrpc_function_impl apps_mem_procs[] = {
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = &apps_mem_request_map64_def, .impl = apps_mem_request_map64, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
{ .def = NULL, .impl = NULL, },
|
||||
};
|
||||
|
||||
const struct fastrpc_interface apps_mem_interface = {
|
||||
.name = "apps_mem",
|
||||
.n_procs = 6,
|
||||
.procs = apps_mem_procs,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* FastRPC operating system interface - context initialization
|
||||
*
|
||||
* Copyright (C) 2024 The Sensor Shell 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef APPS_MEM_H
|
||||
#define APPS_MEM_H
|
||||
|
||||
#include "listener.h"
|
||||
|
||||
struct fastrpc_interface *fastrpc_apps_mem_init();
|
||||
void fastrpc_apps_mem_deinit(struct fastrpc_interface *iface);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Protocol Buffer for Sensor Attribute Requests
|
||||
* FastRPC operating system interface - context initialization
|
||||
*
|
||||
* Copyright (C) 2022 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
@@ -19,8 +19,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
#ifndef APPS_STD_H
|
||||
#define APPS_STD_H
|
||||
|
||||
message sns_std_attr_req {
|
||||
required int32 unkfield_4 = 2;
|
||||
}
|
||||
#include "hexagonfs.h"
|
||||
#include "listener.h"
|
||||
|
||||
struct fastrpc_interface *fastrpc_apps_std_init(struct hexagonfs_dirent *root);
|
||||
void fastrpc_apps_std_deinit(struct fastrpc_interface *iface);
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Virtual read-only filesystem for Hexagon processors
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
@@ -29,111 +29,6 @@
|
||||
|
||||
#include "hexagonfs.h"
|
||||
|
||||
#define HEXAGONFS_MAX_FD 256
|
||||
|
||||
#define DEFINE_VIRT_DIR(dirname, files...) \
|
||||
(struct hexagonfs_dirent) { \
|
||||
.name = dirname, \
|
||||
.ops = &hexagonfs_virt_dir_ops, \
|
||||
.u.dir = (struct hexagonfs_dirent *[]) { files }, \
|
||||
}
|
||||
|
||||
#define DEFINE_MAPPED(dirname, path) \
|
||||
(struct hexagonfs_dirent) { \
|
||||
.name = dirname, \
|
||||
.ops = &hexagonfs_mapped_ops, \
|
||||
.u.phys = path, \
|
||||
}
|
||||
|
||||
#define DEFINE_SYSFILE(dirname, path) \
|
||||
(struct hexagonfs_dirent) { \
|
||||
.name = dirname, \
|
||||
.ops = &hexagonfs_mapped_sysfs_ops, \
|
||||
.u.phys = path, \
|
||||
}
|
||||
|
||||
static struct hexagonfs_dirent root_dir = DEFINE_VIRT_DIR("/",
|
||||
&DEFINE_VIRT_DIR("mnt",
|
||||
&DEFINE_VIRT_DIR("vendor",
|
||||
&DEFINE_VIRT_DIR("persist",
|
||||
&DEFINE_VIRT_DIR("sensors",
|
||||
&DEFINE_VIRT_DIR("registry",
|
||||
&DEFINE_MAPPED("registry",
|
||||
"/var/lib/qcom/sensors"),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
&DEFINE_VIRT_DIR("persist",
|
||||
&DEFINE_VIRT_DIR("sensors",
|
||||
&DEFINE_VIRT_DIR("registry",
|
||||
&DEFINE_MAPPED("registry",
|
||||
"/var/lib/qcom/sensors"),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
&DEFINE_VIRT_DIR("sys",
|
||||
&DEFINE_VIRT_DIR("devices",
|
||||
&DEFINE_VIRT_DIR("soc0",
|
||||
&DEFINE_SYSFILE("hw_platform",
|
||||
"/sys/kernel/debug/qcom_socinfo/hardware_platform"),
|
||||
&(struct hexagonfs_dirent) {
|
||||
.name = "platform_subtype",
|
||||
.ops = &hexagonfs_plat_subtype_name_ops,
|
||||
.u.phys = "/sys/kernel/debug/qcom_socinfo/hardware_platform_subtype",
|
||||
},
|
||||
&DEFINE_SYSFILE("platform_subtype_id",
|
||||
"/sys/kernel/debug/qcom_socinfo/hardware_platform_subtype"),
|
||||
&DEFINE_SYSFILE("platform_version",
|
||||
"/sys/kernel/debug/qcom_socinfo/platform_version"),
|
||||
&DEFINE_SYSFILE("revision",
|
||||
"/sys/devices/soc0/revision"),
|
||||
&DEFINE_SYSFILE("soc_id",
|
||||
"/sys/devices/soc0/soc_id"),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
&DEFINE_VIRT_DIR("usr",
|
||||
&DEFINE_VIRT_DIR("lib",
|
||||
&DEFINE_VIRT_DIR("qcom",
|
||||
&DEFINE_MAPPED("adsp",
|
||||
"/usr/lib/qcom/adsp/"),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
&DEFINE_VIRT_DIR("vendor",
|
||||
&DEFINE_VIRT_DIR("etc",
|
||||
&DEFINE_VIRT_DIR("sensors",
|
||||
&DEFINE_MAPPED("config",
|
||||
"/etc/qcom/sensors.d/"),
|
||||
&DEFINE_MAPPED("sns_reg_config",
|
||||
"/etc/qcom/sns_reg.conf"),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
),
|
||||
NULL,
|
||||
);
|
||||
|
||||
static struct hexagonfs_fd *fds[HEXAGONFS_MAX_FD];
|
||||
|
||||
static char *copy_segment_and_advance(const char *path,
|
||||
bool *trailing_slash,
|
||||
const char **next)
|
||||
@@ -174,8 +69,11 @@ static struct hexagonfs_fd *pop_dir(struct hexagonfs_fd *dir,
|
||||
|
||||
if (dir != root && dir->up != NULL) {
|
||||
up = dir->up;
|
||||
dir->ops->close(dir->data);
|
||||
free(dir);
|
||||
|
||||
if (!dir->is_assigned) {
|
||||
dir->ops->close(dir->data);
|
||||
free(dir);
|
||||
}
|
||||
} else {
|
||||
up = dir;
|
||||
}
|
||||
@@ -183,7 +81,8 @@ static struct hexagonfs_fd *pop_dir(struct hexagonfs_fd *dir,
|
||||
return up;
|
||||
}
|
||||
|
||||
static int allocate_file_number(struct hexagonfs_fd *fd)
|
||||
static int allocate_file_number(struct hexagonfs_fd **fds,
|
||||
struct hexagonfs_fd *fd)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
@@ -212,7 +111,7 @@ static void destroy_file_descriptor(struct hexagonfs_fd *fd)
|
||||
}
|
||||
}
|
||||
|
||||
int hexagonfs_open_root()
|
||||
int hexagonfs_open_root(struct hexagonfs_fd **fds, struct hexagonfs_dirent *root)
|
||||
{
|
||||
struct hexagonfs_fd *fd;
|
||||
int ret;
|
||||
@@ -221,16 +120,15 @@ int hexagonfs_open_root()
|
||||
if (fd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
fd->off = 0;
|
||||
fd->is_assigned = false;
|
||||
fd->up = NULL;
|
||||
fd->ops = root_dir.ops;
|
||||
fd->ops = root->ops;
|
||||
|
||||
ret = root_dir.ops->from_dirent(root_dir.u.ptr, true, &fd->data);
|
||||
ret = root->ops->from_dirent(root->u.ptr, true, &fd->data);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = allocate_file_number(fd);
|
||||
ret = allocate_file_number(fds, fd);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
@@ -241,7 +139,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hexagonfs_openat(int rootfd, int dirfd, const char *name)
|
||||
int hexagonfs_openat(struct hexagonfs_fd **fds, int rootfd, int dirfd, const char *name)
|
||||
{
|
||||
struct hexagonfs_fd *fd;
|
||||
const char *curr = name;
|
||||
@@ -281,7 +179,7 @@ int hexagonfs_openat(int rootfd, int dirfd, const char *name)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = allocate_file_number(fd);
|
||||
ret = allocate_file_number(fds, fd);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
@@ -293,7 +191,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hexagonfs_close(int fileno)
|
||||
int hexagonfs_close(struct hexagonfs_fd **fds, int fileno)
|
||||
{
|
||||
struct hexagonfs_fd *fd;
|
||||
|
||||
@@ -312,7 +210,7 @@ int hexagonfs_close(int fileno)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagonfs_lseek(int fileno, off_t off, int whence)
|
||||
int hexagonfs_lseek(struct hexagonfs_fd **fds, int fileno, off_t off, int whence)
|
||||
{
|
||||
struct hexagonfs_fd *fd;
|
||||
|
||||
@@ -329,7 +227,7 @@ int hexagonfs_lseek(int fileno, off_t off, int whence)
|
||||
return fd->ops->seek(fd, off, whence);
|
||||
}
|
||||
|
||||
ssize_t hexagonfs_read(int fileno, size_t size, void *ptr)
|
||||
ssize_t hexagonfs_read(struct hexagonfs_fd **fds, int fileno, size_t size, void *ptr)
|
||||
{
|
||||
struct hexagonfs_fd *fd;
|
||||
|
||||
@@ -346,7 +244,7 @@ ssize_t hexagonfs_read(int fileno, size_t size, void *ptr)
|
||||
return fd->ops->read(fd, size, ptr);
|
||||
}
|
||||
|
||||
int hexagonfs_readdir(int fileno, size_t ent_size, char *ent)
|
||||
int hexagonfs_readdir(struct hexagonfs_fd **fds, int fileno, size_t ent_size, char *ent)
|
||||
{
|
||||
struct hexagonfs_fd *fd;
|
||||
|
||||
@@ -363,7 +261,7 @@ int hexagonfs_readdir(int fileno, size_t ent_size, char *ent)
|
||||
return fd->ops->readdir(fd, ent_size, ent);
|
||||
}
|
||||
|
||||
int hexagonfs_fstat(int fileno, struct stat *stats)
|
||||
int hexagonfs_fstat(struct hexagonfs_fd **fds, int fileno, struct stat *stats)
|
||||
{
|
||||
struct hexagonfs_fd *fd;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Virtual read-only filesystem for Hexagon processors
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
@@ -27,11 +27,13 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define HEXAGONFS_MAX_FD 256
|
||||
|
||||
struct hexagonfs_fd;
|
||||
|
||||
struct hexagonfs_file_ops {
|
||||
void (*close)(void *fd_data);
|
||||
int (*from_dirent)(void *dirent_data, bool dir, void **fd_data);
|
||||
int (*from_dirent)(const void *dirent_data, bool dir, void **fd_data);
|
||||
int (*openat)(struct hexagonfs_fd *dir,
|
||||
const char *segment,
|
||||
bool expect_dir,
|
||||
@@ -54,7 +56,6 @@ struct hexagonfs_dirent {
|
||||
};
|
||||
|
||||
struct hexagonfs_fd {
|
||||
off_t off;
|
||||
bool is_assigned;
|
||||
struct hexagonfs_fd *up;
|
||||
void *data;
|
||||
@@ -63,17 +64,18 @@ struct hexagonfs_fd {
|
||||
};
|
||||
|
||||
extern struct hexagonfs_file_ops hexagonfs_mapped_ops;
|
||||
extern struct hexagonfs_file_ops hexagonfs_mapped_or_empty_ops;
|
||||
extern struct hexagonfs_file_ops hexagonfs_mapped_sysfs_ops;
|
||||
extern struct hexagonfs_file_ops hexagonfs_plat_subtype_name_ops;
|
||||
extern struct hexagonfs_file_ops hexagonfs_virt_dir_ops;
|
||||
|
||||
int hexagonfs_open_root();
|
||||
int hexagonfs_openat(int rootfd, int dirfd, const char *name);
|
||||
int hexagonfs_close(int fileno);
|
||||
int hexagonfs_open_root(struct hexagonfs_fd **fds, struct hexagonfs_dirent *root);
|
||||
int hexagonfs_openat(struct hexagonfs_fd **fds, int rootfd, int dirfd, const char *name);
|
||||
int hexagonfs_close(struct hexagonfs_fd **fds, int fileno);
|
||||
|
||||
int hexagonfs_fstat(int fileno, struct stat *stats);
|
||||
int hexagonfs_lseek(int fileno, off_t pos, int whence);
|
||||
int hexagonfs_readdir(int fileno, size_t size, char *name);
|
||||
ssize_t hexagonfs_read(int fileno, size_t size, void *ptr);
|
||||
int hexagonfs_fstat(struct hexagonfs_fd **fds, int fileno, struct stat *stats);
|
||||
int hexagonfs_lseek(struct hexagonfs_fd **fds, int fileno, off_t pos, int whence);
|
||||
int hexagonfs_readdir(struct hexagonfs_fd **fds, int fileno, size_t size, char *name);
|
||||
ssize_t hexagonfs_read(struct hexagonfs_fd **fds, int fileno, size_t size, void *ptr);
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* HexagonFS mapped file/directory operations
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
@@ -47,7 +47,7 @@ static void mapped_close(void *fd_data)
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static int mapped_from_dirent(void *dirent_data, bool dir, void **fd_data)
|
||||
static int mapped_from_dirent(const void *dirent_data, bool dir, void **fd_data)
|
||||
{
|
||||
struct mapped_ctx *ctx;
|
||||
const char *name = dirent_data;
|
||||
@@ -110,7 +110,7 @@ static int mapped_openat(struct hexagonfs_fd *dir,
|
||||
|
||||
ctx->dir = NULL;
|
||||
|
||||
fd->off = 0;
|
||||
fd->is_assigned = false;
|
||||
fd->up = dir;
|
||||
fd->ops = &hexagonfs_mapped_ops;
|
||||
fd->data = ctx;
|
||||
@@ -126,7 +126,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t mapped_read(struct hexagonfs_fd *fd, size_t size, void *out)
|
||||
static ssize_t mapped_read(struct hexagonfs_fd *fd, size_t size, void *out)
|
||||
{
|
||||
struct mapped_ctx *ctx = fd->data;
|
||||
ssize_t ret;
|
||||
@@ -138,7 +138,7 @@ ssize_t mapped_read(struct hexagonfs_fd *fd, size_t size, void *out)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mapped_readdir(struct hexagonfs_fd *fd, size_t size, char *out)
|
||||
static int mapped_readdir(struct hexagonfs_fd *fd, size_t size, char *out)
|
||||
{
|
||||
struct mapped_ctx *ctx = fd->data;
|
||||
struct dirent *ent;
|
||||
@@ -216,6 +216,89 @@ static int mapped_stat(struct hexagonfs_fd *fd, struct stat *stats)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mapped_or_empty_close(void *fd_data)
|
||||
{
|
||||
if (fd_data)
|
||||
mapped_close(fd_data);
|
||||
}
|
||||
|
||||
static int mapped_or_empty_from_dirent(const void *dirent_data, bool dir, void **fd_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mapped_from_dirent(dirent_data, dir, fd_data);
|
||||
if (ret)
|
||||
*fd_data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mapped_or_empty_openat(struct hexagonfs_fd *dir,
|
||||
const char *segment,
|
||||
bool expect_dir,
|
||||
struct hexagonfs_fd **out)
|
||||
{
|
||||
if (dir->data)
|
||||
return mapped_openat(dir, segment, expect_dir, out);
|
||||
else
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static ssize_t mapped_or_empty_read(struct hexagonfs_fd *fd,
|
||||
size_t size, void *out)
|
||||
{
|
||||
if (fd->data)
|
||||
return mapped_read(fd, size, out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mapped_or_empty_readdir(struct hexagonfs_fd *fd,
|
||||
size_t size, char *out)
|
||||
{
|
||||
if (fd->data) {
|
||||
return mapped_readdir(fd, size, out);
|
||||
} else {
|
||||
out[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int mapped_or_empty_seek(struct hexagonfs_fd *fd, off_t off, int whence)
|
||||
{
|
||||
if (fd->data)
|
||||
return mapped_seek(fd, off, whence);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mapped_or_empty_stat(struct hexagonfs_fd *fd, struct stat *stats)
|
||||
{
|
||||
if (fd->data) {
|
||||
return mapped_stat(fd, stats);
|
||||
} else {
|
||||
stats->st_size = 0;
|
||||
stats->st_dev = 0;
|
||||
stats->st_rdev = 0;
|
||||
stats->st_ino = 0;
|
||||
stats->st_nlink = 0;
|
||||
|
||||
stats->st_mode = S_IFDIR
|
||||
| S_IRUSR | S_IXUSR
|
||||
| S_IRGRP | S_IXGRP
|
||||
| S_IROTH | S_IXOTH;
|
||||
|
||||
stats->st_atim.tv_sec = 0;
|
||||
stats->st_atim.tv_nsec = 0;
|
||||
stats->st_ctim.tv_sec = 0;
|
||||
stats->st_ctim.tv_nsec = 0;
|
||||
stats->st_mtim.tv_sec = 0;
|
||||
stats->st_mtim.tv_nsec = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the sysfs variant of the stat function.
|
||||
*
|
||||
@@ -249,6 +332,16 @@ struct hexagonfs_file_ops hexagonfs_mapped_ops = {
|
||||
.stat = mapped_stat,
|
||||
};
|
||||
|
||||
struct hexagonfs_file_ops hexagonfs_mapped_or_empty_ops = {
|
||||
.close = mapped_or_empty_close,
|
||||
.from_dirent = mapped_or_empty_from_dirent,
|
||||
.openat = mapped_or_empty_openat,
|
||||
.read = mapped_or_empty_read,
|
||||
.readdir = mapped_or_empty_readdir,
|
||||
.seek = mapped_or_empty_seek,
|
||||
.stat = mapped_or_empty_stat,
|
||||
};
|
||||
|
||||
struct hexagonfs_file_ops hexagonfs_mapped_sysfs_ops = {
|
||||
.close = mapped_close,
|
||||
.from_dirent = mapped_from_dirent,
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* HexagonFS operations for a missing sysfs file
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
@@ -41,7 +41,7 @@ static void plat_subtype_name_close(void *fd_data)
|
||||
free(ctx->name);
|
||||
}
|
||||
|
||||
static int plat_subtype_name_from_dirent(void *dirent_data,
|
||||
static int plat_subtype_name_from_dirent(const void *dirent_data,
|
||||
bool dir,
|
||||
void **fd_data)
|
||||
{
|
||||
@@ -54,7 +54,7 @@ static int plat_subtype_name_from_dirent(void *dirent_data,
|
||||
if (ctx == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->fd = open((const char *) dirent_data, O_RDONLY);
|
||||
ctx->fd = open(dirent_data, O_RDONLY);
|
||||
if (ctx->fd == -1)
|
||||
return -errno;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* HexagonFS virtual directory operations
|
||||
*
|
||||
* Copyright (C) 2023 Richard Acayan
|
||||
* Copyright (C) 2023 The Sensor Shell Contributors
|
||||
*
|
||||
* This file is part of sensh.
|
||||
*
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -30,10 +31,10 @@
|
||||
* This function searches for the relevant path segment in the path directory.
|
||||
* It is not optimized because it is dealing with small directories.
|
||||
*/
|
||||
static struct hexagonfs_dirent *walk_dir(struct hexagonfs_dirent **dir,
|
||||
static const struct hexagonfs_dirent *walk_dir(const struct hexagonfs_dirent *const *dir,
|
||||
const char *segment)
|
||||
{
|
||||
struct hexagonfs_dirent **curr = dir;
|
||||
const struct hexagonfs_dirent *const *curr = dir;
|
||||
|
||||
while (*curr != NULL) {
|
||||
if (!strcmp(segment, (*curr)->name))
|
||||
@@ -45,9 +46,17 @@ static struct hexagonfs_dirent *walk_dir(struct hexagonfs_dirent **dir,
|
||||
return *curr;
|
||||
}
|
||||
|
||||
static int virt_dir_from_dirent(void *dirent_data, bool dir, void **fd_data)
|
||||
static int virt_dir_from_dirent(const void *dirent_data, bool dir, void **fd_data)
|
||||
{
|
||||
*fd_data = dirent_data;
|
||||
const struct hexagonfs_dirent *const **wrapper;
|
||||
|
||||
wrapper = malloc(sizeof(*wrapper));
|
||||
if (wrapper == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
*wrapper = dirent_data;
|
||||
*fd_data = wrapper;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -56,12 +65,12 @@ static int virt_dir_openat(struct hexagonfs_fd *dir,
|
||||
bool expect_dir,
|
||||
struct hexagonfs_fd **out)
|
||||
{
|
||||
const struct hexagonfs_dirent *const **dirlist = dir->data;
|
||||
const struct hexagonfs_dirent *ent;
|
||||
struct hexagonfs_fd *fd;
|
||||
struct hexagonfs_dirent *ent;
|
||||
struct hexagonfs_dirent **dirlist = dir->data;
|
||||
int ret;
|
||||
|
||||
ent = walk_dir(dirlist, segment);
|
||||
ent = walk_dir(*dirlist, segment);
|
||||
if (ent == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
@@ -69,7 +78,7 @@ static int virt_dir_openat(struct hexagonfs_fd *dir,
|
||||
if (fd == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
fd->off = 0;
|
||||
fd->is_assigned = false;
|
||||
fd->up = dir;
|
||||
fd->ops = ent->ops;
|
||||
|
||||
@@ -88,6 +97,7 @@ err:
|
||||
|
||||
static void virt_dir_close(void *fd_data)
|
||||
{
|
||||
free(fd_data);
|
||||
}
|
||||
|
||||
static int virt_dir_stat(struct hexagonfs_fd *fd, struct stat *stats)
|
||||
Loaded 20 of 60 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user