Remove the brackets around the -f option which imply that it is
optional. The default value is a NULL pointer.
FastRPC is not specialized to serving files to the DSPs and can do other
things such as logging and profiling, pending discovery. Change the
description of the program accordingly.
Referring to a "FastRPC node" is a bit vague and misses the detail that
the program is expecting a path to a file (a device node). Refer to the
file as a FastRPC device node so the user can intuitively look for what
the program wants.
The letter in the -R option was seemingly chosen arbitrarily. Add the
word which it originated from ("root") to make it memorable.
The INIT_ATTACH and INIT_ATTACH_SNS terms have no meaning in the usage
text. They are terms of jargon originating in the userspace API for the
Linux kernel driver, as abbreviations of FASTRPC_IOCTL_INIT_ATTACH and
FASTRPC_IOCTL_INIT_ATTACH_SNS. It is unclear what the difference is
between the two, and SNS is ambiguous with no clear connection to
sensors (did Qualcomm design some DSP communication protocol around a
Social Networking Service?). Instead of deriving terms used to inform
the driver how to interact with the DSP, use the name of the
PD ("sensorspd") and describe the effective interaction with the DSP.
If the file name for the FastRPC device node is a NULL pointer, then the
error message always prints out a NULL pointer, made redundant by the
word "invalid". An unspecified device node is an error made by the user,
and the usage text should be given to the user instead of an internal
diagnosis of invalid usage.
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
You can build and install this project using meson:
~/sensh/fastrpc $ meson setup build
~/sensh/fastrpc $ ninja -C build
~/sensh/fastrpc # ninja -C build install
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.
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;
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 (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.
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_SCALARS_MAKE() macro or the second argument of the
REMOTE_SCALARS_MAKEX() macro
(defined here).
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 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:
Physical file/dir Android file/dir
/usr/share/qcom/acdb /vendor/etc/acdbdata
/usr/share/qcom/dsp /vendor/dsp
/usr/share/qcom/sensors/config /vendor/etc/sensors/config
/usr/share/qcom/sensors/registry /mnt/vendor/persist/sensors/registry/registry
/usr/share/qcom/sensors/sns_reg.conf /vendor/etc/sensors/sns_reg_config
These files and directories should be populated with files from your device's Android firmware.
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.