Add samsung specific changes
This commit is contained in:
361
Documentation/arm/msm/msm_ipc_logging.txt
Normal file
361
Documentation/arm/msm/msm_ipc_logging.txt
Normal file
@@ -0,0 +1,361 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
This module will be used to log the events by any module/driver which
|
||||
enables Inter Processor Communication (IPC). Some of the IPC drivers such
|
||||
as Message Routers, Multiplexers etc. which act as a passive pipe need
|
||||
some mechanism to log their events. Since all such IPC drivers handle a
|
||||
large amount of traffic/events, using kernel logs renders kernel logs
|
||||
unusable by other drivers and also degrades the performance of IPC
|
||||
drivers. This new module will help in logging such high frequency IPC
|
||||
driver events while keeping the standard kernel logging mechanism
|
||||
intact.
|
||||
|
||||
Hardware description
|
||||
====================
|
||||
|
||||
This module does not drive any hardware resource and will only use the
|
||||
kernel memory-space to log the events.
|
||||
|
||||
Software description
|
||||
====================
|
||||
|
||||
Design Goals
|
||||
------------
|
||||
This module is designed to
|
||||
* support logging for drivers handling large amount of
|
||||
traffic/events
|
||||
* define & differentiate events/logs from different drivers
|
||||
* support both id-based and stream-based logging
|
||||
* support extracting the logs from both live target & memory dump
|
||||
|
||||
IPC Log Context
|
||||
----------------
|
||||
|
||||
This module will support logging by multiple drivers. To differentiate
|
||||
between the multiple drivers that are using this logging mechanism, each
|
||||
driver will be assigned a unique context by this module. Associated with
|
||||
each context is the logging space, dynamically allocated from the kernel
|
||||
memory-space, specific to that context so that the events logged using that
|
||||
context will not interfere with other contexts.
|
||||
|
||||
Event Logging
|
||||
--------------
|
||||
|
||||
Every event will be logged as a <Type: Size: Value> combination. Type
|
||||
field identifies the type of the event that is logged. Size field represents
|
||||
the size of the log information. Value field represents the actual
|
||||
information being logged. This approach will support both id-based logging
|
||||
and stream-based logging. This approach will also support logging sub-events
|
||||
of an event. This module will provide helper routines to encode/decode the
|
||||
logs to/from this format.
|
||||
|
||||
Encode Context
|
||||
---------------
|
||||
|
||||
Encode context is a temporary storage space that will be used by the client
|
||||
drivers to log the events in <Type: Size: Value> format. The client drivers
|
||||
will perform an encode start operation to initialize the encode context
|
||||
data structure. Then the client drivers will log their events into the
|
||||
encode context. Upon completion of event logging, the client drivers will
|
||||
perform an encode end operation to finalize the encode context data
|
||||
structure to be logged. Then this updated encode context data structure
|
||||
will be written into the client driver's IPC Log Context. The maximum
|
||||
event log size will be defined as 256 bytes.
|
||||
|
||||
Log Space
|
||||
----------
|
||||
|
||||
Each context (Figure 1) has an associated log space, which is dynamically
|
||||
allocated from the kernel memory-space. The log space is organized as a list of
|
||||
1 or more kernel memory pages. Each page (Figure 2) contains header information
|
||||
which is used to differentiate the log kernel page from the other kernel pages.
|
||||
|
||||
|
||||
0 ---------------------------------
|
||||
| magic_no = 0x25874452 |
|
||||
---------------------------------
|
||||
| nmagic_no = 0x52784425 |
|
||||
---------------------------------
|
||||
| version |
|
||||
---------------------------------
|
||||
| user_version |
|
||||
---------------------------------
|
||||
| log_id |
|
||||
---------------------------------
|
||||
| header_size |
|
||||
---------------------------------
|
||||
| |
|
||||
| |
|
||||
| name [20 chars] |
|
||||
| |
|
||||
| |
|
||||
---------------------------------
|
||||
| run-time data structures |
|
||||
---------------------------------
|
||||
Figure 1 - Log Context Structure
|
||||
|
||||
|
||||
31 0
|
||||
0 ---------------------------------
|
||||
| magic_no = 0x52784425 |
|
||||
---------------------------------
|
||||
| nmagic_no = 0xAD87BBDA |
|
||||
---------------------------------
|
||||
|1| page_num |
|
||||
---------------------------------
|
||||
| read_offset | write_offset |
|
||||
---------------------------------
|
||||
| log_id |
|
||||
---------------------------------
|
||||
| start_time low word |
|
||||
| start_time high word |
|
||||
---------------------------------
|
||||
| end_time low word |
|
||||
| end_time high word |
|
||||
---------------------------------
|
||||
| context offset |
|
||||
---------------------------------
|
||||
| run-time data structures |
|
||||
. . . . .
|
||||
---------------------------------
|
||||
| |
|
||||
| Log Data |
|
||||
. . .
|
||||
. . .
|
||||
| |
|
||||
--------------------------------- PAGE_SIZE - 1
|
||||
Figure 2 - Log Page Structure
|
||||
|
||||
In addition to extracting logs at runtime through DebugFS, IPC Logging has been
|
||||
designed to allow extraction of logs from a memory dump. The magic numbers,
|
||||
timestamps, and context offset are all added to support the memory-dump
|
||||
extraction use case.
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
Alternate solutions discussed include using kernel & SMEM logs which are
|
||||
limited in size and hence using them render them unusable by other drivers.
|
||||
Also kernel logging into serial console is slowing down the performance of
|
||||
the drivers by multiple times and sometimes lead to APPs watchdog bite.
|
||||
|
||||
Power Management
|
||||
================
|
||||
|
||||
Not-Applicable
|
||||
|
||||
SMP/multi-core
|
||||
==============
|
||||
|
||||
This module uses spinlocks & mutexes to handle multi-core safety.
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
Not-Applicable
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
This logging mechanism, based on experimental data, is not expected to
|
||||
cause a significant performance degradation. Under worst case, it can
|
||||
cause 1 - 2 percent degradation in the throughput of the IPC Drivers.
|
||||
|
||||
Interface
|
||||
=========
|
||||
|
||||
Exported Data Structures
|
||||
------------------------
|
||||
struct encode_context {
|
||||
struct tsv_header hdr;
|
||||
char buff[MAX_MSG_SIZE];
|
||||
int offset;
|
||||
};
|
||||
|
||||
struct decode_context {
|
||||
int output_format;
|
||||
char *buff;
|
||||
int size;
|
||||
};
|
||||
|
||||
Kernel-Space Interface APIs
|
||||
----------------------------
|
||||
/*
|
||||
* ipc_log_context_create: Create a ipc log context
|
||||
*
|
||||
* @max_num_pages: Number of pages of logging space required (max. 10)
|
||||
* @mod_name : Name of the directory entry under DEBUGFS
|
||||
* @user_version : Version number of user-defined message formats
|
||||
*
|
||||
* returns reference to context on success, NULL on failure
|
||||
*/
|
||||
void *ipc_log_context_create(int max_num_pages, const char *mod_name,
|
||||
uint16_t user_version);
|
||||
|
||||
/*
|
||||
* msg_encode_start: Start encoding a log message
|
||||
*
|
||||
* @ectxt: Temporary storage to hold the encoded message
|
||||
* @type: Root event type defined by the module which is logging
|
||||
*/
|
||||
void msg_encode_start(struct encode_context *ectxt, uint32_t type);
|
||||
|
||||
/*
|
||||
* msg_encode_end: Complete the message encode process
|
||||
*
|
||||
* @ectxt: Temporary storage which holds the encoded message
|
||||
*/
|
||||
void msg_encode_end(struct encode_context *ectxt);
|
||||
|
||||
/*
|
||||
* tsv_timestamp_write: Writes the current timestamp count
|
||||
*
|
||||
* @ectxt: Context initialized by calling msg_encode_start()
|
||||
*
|
||||
* Returns 0 on success, -ve error code on failure
|
||||
*/
|
||||
int tsv_timestamp_write(struct encode_context *ectxt);
|
||||
|
||||
/*
|
||||
* tsv_pointer_write: Writes a data pointer
|
||||
*
|
||||
* @ectxt: Context initialized by calling msg_encode_start()
|
||||
* @pointer: Pointer value to write
|
||||
*
|
||||
* Returns 0 on success, -ve error code on failure
|
||||
*/
|
||||
int tsv_pointer_write(struct encode_context *ectxt, void *pointer);
|
||||
|
||||
/*
|
||||
* tsv_int32_write: Writes a 32-bit integer value
|
||||
*
|
||||
* @ectxt: Context initialized by calling msg_encode_start()
|
||||
* @n: Integer to write
|
||||
*
|
||||
* Returns 0 on success, -ve error code on failure
|
||||
*/
|
||||
int tsv_int32_write(struct encode_context *ectxt, int32_t n);
|
||||
|
||||
/*
|
||||
* tsv_byte_array_write: Writes a byte array
|
||||
*
|
||||
* @ectxt: Context initialized by calling msg_encode_start()
|
||||
* @data: Location of data
|
||||
* @data_size: Size of data to be written
|
||||
*
|
||||
* Returns 0 on success, -ve error code on failure
|
||||
*/
|
||||
int tsv_byte_array_write(struct encode_context *ectxt,
|
||||
void *data, int data_size);
|
||||
|
||||
/*
|
||||
* ipc_log_write: Write the encoded message into the log space
|
||||
*
|
||||
* @ctxt: IPC log context where the message has to be logged into
|
||||
* @ectxt: Temporary storage containing the encoded message
|
||||
*/
|
||||
void ipc_log_write(unsigned long ctxt, struct encode_context *ectxt);
|
||||
|
||||
/*
|
||||
* ipc_log_string: Helper function to log a string
|
||||
*
|
||||
* @dlctxt: IPC Log Context created using ipc_log_context_create()
|
||||
* @fmt: Data specified using format specifiers
|
||||
*/
|
||||
int ipc_log_string(unsigned long dlctxt, const char *fmt, ...);
|
||||
|
||||
/*
|
||||
* tsv_timestamp_read: Reads a timestamp
|
||||
*
|
||||
* @ectxt: Context retrieved by reading from log space
|
||||
* @dctxt: Temporary storage to hold the decoded message
|
||||
* @format: Output format while dumping through DEBUGFS
|
||||
*/
|
||||
void tsv_timestamp_read(struct encode_context *ectxt,
|
||||
struct decode_context *dctxt, const char *format);
|
||||
|
||||
/*
|
||||
* tsv_pointer_read: Reads a data pointer
|
||||
*
|
||||
* @ectxt: Context retrieved by reading from log space
|
||||
* @dctxt: Temporary storage to hold the decoded message
|
||||
* @format: Output format while dumping through DEBUGFS
|
||||
*/
|
||||
void tsv_pointer_read(struct encode_context *ectxt,
|
||||
struct decode_context *dctxt, const char *format);
|
||||
|
||||
/*
|
||||
* tsv_int32_read: Reads a 32-bit integer value
|
||||
*
|
||||
* @ectxt: Context retrieved by reading from log space
|
||||
* @dctxt: Temporary storage to hold the decoded message
|
||||
* @format: Output format while dumping through DEBUGFS
|
||||
*/
|
||||
void tsv_int32_read(struct encode_context *ectxt,
|
||||
struct decode_context *dctxt, const char *format);
|
||||
|
||||
/*
|
||||
* tsv_byte_array_read: Reads a byte array/string
|
||||
*
|
||||
* @ectxt: Context retrieved by reading from log space
|
||||
* @dctxt: Temporary storage to hold the decoded message
|
||||
* @format: Output format while dumping through DEBUGFS
|
||||
*/
|
||||
void tsv_byte_array_read(struct encode_context *ectxt,
|
||||
struct decode_context *dctxt, const char *format);
|
||||
|
||||
/*
|
||||
* add_deserialization_func: Register a deserialization function to
|
||||
* to unpack the subevents of a main event
|
||||
*
|
||||
* @ctxt: IPC log context to which the deserialization function has
|
||||
* to be registered
|
||||
* @type: Main/Root event, defined by the module which is logging, to
|
||||
* which this deserialization function has to be registered.
|
||||
* @dfune: Deserialization function to be registered
|
||||
*
|
||||
* return 0 on success, -ve value on FAILURE
|
||||
*/
|
||||
int add_deserialization_func(unsigned long ctxt, int type,
|
||||
void (*dfunc)(struct encode_context *,
|
||||
struct decode_context *));
|
||||
|
||||
Driver parameters
|
||||
=================
|
||||
|
||||
Not-Applicable
|
||||
|
||||
Config options
|
||||
==============
|
||||
|
||||
Not-Applicable
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
This module will partially depend on CONFIG_DEBUGFS, in order to dump the
|
||||
logs through debugfs. If CONFIG_DEBUGFS is disabled, the above mentioned
|
||||
helper functions will perform no operation and return appropriate error
|
||||
code if the return value is non void. Under such circumstances the logs can
|
||||
only be extracted through the memory dump.
|
||||
|
||||
User space utilities
|
||||
====================
|
||||
|
||||
DEBUGFS
|
||||
|
||||
Other
|
||||
=====
|
||||
|
||||
Not-Applicable
|
||||
|
||||
Known issues
|
||||
============
|
||||
|
||||
None
|
||||
|
||||
To do
|
||||
=====
|
||||
|
||||
None
|
468
Documentation/arm/msm/remote_debug_drv.txt
Normal file
468
Documentation/arm/msm/remote_debug_drv.txt
Normal file
@@ -0,0 +1,468 @@
|
||||
Introduction
|
||||
============
|
||||
|
||||
The goal of this debug feature is to provide a reliable, responsive,
|
||||
accurate and secure debug capability to developers interested in
|
||||
debugging MSM subsystem processor images without the use of a hardware
|
||||
debugger.
|
||||
|
||||
The Debug Agent along with the Remote Debug Driver implements a shared
|
||||
memory based transport mechanism that allows for a debugger (ex. GDB)
|
||||
running on a host PC to communicate with a remote stub running on
|
||||
peripheral subsystems such as the ADSP, MODEM etc.
|
||||
|
||||
The diagram below depicts end to end the components involved to
|
||||
support remote debugging:
|
||||
|
||||
|
||||
: :
|
||||
: HOST (PC) : MSM
|
||||
: ,--------, : ,-------,
|
||||
: | | : | Debug | ,--------,
|
||||
: |Debugger|<--:-->| Agent | | Remote |
|
||||
: | | : | App | +----->| Debug |
|
||||
: `--------` : |-------| ,--------, | | Stub |
|
||||
: : | Remote| | |<---+ `--------`
|
||||
: : | Debug |<-->|--------|
|
||||
: : | Driver| | |<---+ ,--------,
|
||||
: : `-------` `--------` | | Remote |
|
||||
: : LA Shared +----->| Debug |
|
||||
: : Memory | Stub |
|
||||
: : `--------`
|
||||
: : Peripheral Subsystems
|
||||
: : (ADSP, MODEM, ...)
|
||||
|
||||
|
||||
Debugger: Debugger application running on the host PC that
|
||||
communicates with the remote stub.
|
||||
Examples: GDB, LLDB
|
||||
|
||||
Debug Agent: Software that runs on the Linux Android platform
|
||||
that provides connectivity from the MSM to the
|
||||
host PC. This involves two portions:
|
||||
1) User mode Debug Agent application that discovers
|
||||
processes running on the subsystems and creates
|
||||
TCP/IP sockets for the host to connect to. In addition
|
||||
to this, it creates an info port that
|
||||
users can connect to discover the various
|
||||
processes and their corresponding debug ports.
|
||||
|
||||
Remote Debug A character based driver that the Debug
|
||||
Driver: Agent uses to transport the payload received from the
|
||||
host to the debug stub running on the subsystem
|
||||
processor over shared memory and vice versa.
|
||||
|
||||
Shared Memory: Shared memory from the SMEM pool that is accessible
|
||||
from the Applications Processor (AP) and the
|
||||
subsystem processors.
|
||||
|
||||
Remote Debug Privileged code that runs in the kernels of the
|
||||
Stub: subsystem processors that receives debug commands
|
||||
from the debugger running on the host and
|
||||
acts on these commands. These commands include reading
|
||||
and writing to registers and memory belonging to the
|
||||
subsystem's address space, setting breakpoints,
|
||||
single stepping etc.
|
||||
|
||||
Hardware description
|
||||
====================
|
||||
|
||||
The Remote Debug Driver interfaces with the Remote Debug stubs
|
||||
running on the subsystem processors and does not drive or
|
||||
manage any hardware resources.
|
||||
|
||||
Software description
|
||||
====================
|
||||
|
||||
The debugger and the remote stubs use Remote Serial Protocol (RSP)
|
||||
to communicate with each other. This is widely used protocol by both
|
||||
software and hardware debuggers. RSP is an ASCII based protocol
|
||||
and used when it is not possible to run GDB server on the target under
|
||||
debug.
|
||||
|
||||
The Debug Agent application along with the Remote Debug Driver
|
||||
is responsible for establishing a bi-directional connection from
|
||||
the debugger application running on the host to the remote debug
|
||||
stub running on a subsystem. The Debug Agent establishes connectivity
|
||||
to the host PC via TCP/IP sockets.
|
||||
|
||||
This feature uses ADB port forwarding to establish connectivity
|
||||
between the debugger running on the host and the target under debug.
|
||||
|
||||
Please note the Debug Agent does not expose HLOS memory to the
|
||||
remote subsystem processors.
|
||||
|
||||
Design
|
||||
======
|
||||
|
||||
Here is the overall flow:
|
||||
|
||||
1) When the Debug Agent application starts up, it opens up a shared memory
|
||||
based transport channel to the various subsystem processor images.
|
||||
|
||||
2) The Debug Agent application sends messages across to the remote stubs
|
||||
to discover the various processes that are running on the subsystem and
|
||||
creates debug sockets for each of them.
|
||||
|
||||
3) Whenever a process running on a subsystem exits, the Debug Agent
|
||||
is notified by the stub so that the debug port and other resources
|
||||
can be reclaimed.
|
||||
|
||||
4) The Debug Agent uses the services of the Remote Debug Driver to
|
||||
transport payload from the host debugger to the remote stub and vice versa.
|
||||
|
||||
5) Communication between the Remote Debug Driver and the Remote Debug stub
|
||||
running on the subsystem processor is done over shared memory (see figure).
|
||||
SMEM services are used to allocate the shared memory that will
|
||||
be readable and writeable by the AP and the subsystem image under debug.
|
||||
|
||||
A separate SMEM allocation takes place for each subsystem processor
|
||||
involved in remote debugging. The remote stub running on each of the
|
||||
subsystems allocates a SMEM buffer using a unique identifier so that both
|
||||
the AP and subsystem get the same physical block of memory. It should be
|
||||
noted that subsystem images can be restarted at any time.
|
||||
However, when a subsystem comes back up, its stub uses the same unique
|
||||
SMEM identifier to allocate the SMEM block. This would not result in a
|
||||
new allocation rather the same block of memory in the first bootup instance
|
||||
is provided back to the stub running on the subsystem.
|
||||
|
||||
An 8KB chunk of shared memory is allocated and used for communication
|
||||
per subsystem. For multi-process capable subsystems, 16KB chunk of shared
|
||||
memory is allocated to allow for simultaneous debugging of more than one
|
||||
process running on a single subsystem.
|
||||
|
||||
The shared memory is used as a circular ring buffer in each direction.
|
||||
Thus we have a bi-directional shared memory channel between the AP
|
||||
and a subsystem. We call this SMQ. Each memory channel contains a header,
|
||||
data and a control mechanism that is used to synchronize read and write
|
||||
of data between the AP and the remote subsystem.
|
||||
|
||||
Overall SMQ memory view:
|
||||
:
|
||||
: +------------------------------------------------+
|
||||
: | SMEM buffer |
|
||||
: |-----------------------+------------------------|
|
||||
: |Producer: LA | Producer: Remote |
|
||||
: |Consumer: Remote | subsystem |
|
||||
: | subsystem | Consumer: LA |
|
||||
: | | |
|
||||
: | Producer| Consumer|
|
||||
: +-----------------------+------------------------+
|
||||
: | |
|
||||
: | |
|
||||
: | +--------------------------------------+
|
||||
: | |
|
||||
: | |
|
||||
: v v
|
||||
: +--------------------------------------------------------------+
|
||||
: | Header | Data | Control |
|
||||
: +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
|
||||
: | | b | b | b | | S |n |n | | S |n |n | |
|
||||
: | Producer | l | l | l | | M |o |o | | M |o |o | |
|
||||
: | Ver | o | o | o | | Q |d |d | | Q |d |d | |
|
||||
: |-----------| c | c | c | ... | |e |e | ... | |e |e | ... |
|
||||
: | | k | k | k | | O | | | | I | | | |
|
||||
: | Consumer | | | | | u |0 |1 | | n |0 |1 | |
|
||||
: | Ver | 0 | 1 | 2 | | t | | | | | | | |
|
||||
: +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
|
||||
: | |
|
||||
: + |
|
||||
: |
|
||||
: +------------------------+
|
||||
: |
|
||||
: v
|
||||
: +----+----+----+----+
|
||||
: | SMQ Nodes |
|
||||
: |----|----|----|----|
|
||||
: Node # | 0 | 1 | 2 | ...|
|
||||
: |----|----|----|----|
|
||||
: Starting Block Index # | 0 | 3 | 8 | ...|
|
||||
: |----|----|----|----|
|
||||
: # of blocks | 3 | 5 | 1 | ...|
|
||||
: +----+----+----+----+
|
||||
:
|
||||
|
||||
Header: Contains version numbers for software compatibility to ensure
|
||||
that both producers and consumers on the AP and subsystems know how to
|
||||
read from and write to the queue.
|
||||
Both the producer and consumer versions are 1.
|
||||
: +---------+-------------------+
|
||||
: | Size | Field |
|
||||
: +---------+-------------------+
|
||||
: | 1 byte | Producer Version |
|
||||
: +---------+-------------------+
|
||||
: | 1 byte | Consumer Version |
|
||||
: +---------+-------------------+
|
||||
|
||||
|
||||
Data: The data portion contains multiple blocks [0..N] of a fixed size.
|
||||
The block size SM_BLOCKSIZE is fixed to 128 bytes for header version #1.
|
||||
Payload sent from the debug agent app is split (if necessary) and placed
|
||||
in these blocks. The first data block is placed at the next 8 byte aligned
|
||||
address after the header.
|
||||
|
||||
The number of blocks for a given SMEM allocation is derived as follows:
|
||||
Number of Blocks = ((Total Size - Alignment - Size of Header
|
||||
- Size of SMQIn - Size of SMQOut)/(SM_BLOCKSIZE))
|
||||
|
||||
The producer maintains a private block map of each of these blocks to
|
||||
determine which of these blocks in the queue is available and which are free.
|
||||
|
||||
Control:
|
||||
The control portion contains a list of nodes [0..N] where N is number
|
||||
of available data blocks. Each node identifies the data
|
||||
block indexes that contain a particular debug message to be transferred,
|
||||
and the number of blocks it took to hold the contents of the message.
|
||||
|
||||
Each node has the following structure:
|
||||
: +---------+-------------------+
|
||||
: | Size | Field |
|
||||
: +---------+-------------------+
|
||||
: | 2 bytes |Staring Block Index|
|
||||
: +---------+-------------------+
|
||||
: | 2 bytes |Number of Blocks |
|
||||
: +---------+-------------------+
|
||||
|
||||
The producer and the consumer update different parts of the control channel
|
||||
(SMQOut / SMQIn) respectively. Each of these control data structures contains
|
||||
information about the last node that was written / read, and the actual nodes
|
||||
that were written/read.
|
||||
|
||||
SMQOut Structure (R/W by producer, R by consumer):
|
||||
: +---------+-------------------+
|
||||
: | Size | Field |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Magic Init Number |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Reset |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Last Sent Index |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Index Free Read |
|
||||
: +---------+-------------------+
|
||||
|
||||
SMQIn Structure (R/W by consumer, R by producer):
|
||||
: +---------+-------------------+
|
||||
: | Size | Field |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Magic Init Number |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Reset ACK |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Last Read Index |
|
||||
: +---------+-------------------+
|
||||
: | 4 bytes | Index Free Write |
|
||||
: +---------+-------------------+
|
||||
|
||||
Magic Init Number:
|
||||
Both SMQ Out and SMQ In initialize this field with a predefined magic
|
||||
number so as to make sure that both the consumer and producer blocks
|
||||
have fully initialized and have valid data in the shared memory control area.
|
||||
Producer Magic #: 0xFF00FF01
|
||||
Consumer Magic #: 0xFF00FF02
|
||||
|
||||
SMQ Out's Last Sent Index and Index Free Read:
|
||||
Only a producer can write to these indexes and they are updated whenever
|
||||
there is new payload to be inserted into the SMQ in order to be sent to a
|
||||
consumer.
|
||||
|
||||
The number of blocks required for the SMQ allocation is determined as:
|
||||
(payload size + SM_BLOCKSIZE - 1) / SM_BLOCKSIZE
|
||||
|
||||
The private block map is searched for a large enough continuous set of blocks
|
||||
and the user data is copied into the data blocks.
|
||||
|
||||
The starting index of the free block(s) is updated in the SMQOut's Last Sent
|
||||
Index. This update keeps track of which index was last written to and the
|
||||
producer uses it to determine where the next allocation could be done.
|
||||
|
||||
Every allocation, a producer updates the Index Free Read from its
|
||||
collaborating consumer's Index Free Write field (if they are unequal).
|
||||
This index value indicates that the consumer has read all blocks associated
|
||||
with allocation on the SMQ and that the producer can reuse these blocks for
|
||||
subsquent allocations since this is a circular queue.
|
||||
|
||||
At cold boot and restart, these indexes are initialized to zero and all
|
||||
blocks are marked as available for allocation.
|
||||
|
||||
SMQ In's Last Read Index and Index Free Write:
|
||||
These indexes are written to only by a consumer and are updated whenever
|
||||
there is new payload to be read from the SMQ. The Last Read Index keeps
|
||||
track of which index was last read by the consumer and using this, it
|
||||
determines where the next read should be done.
|
||||
After completing a read, Last Read Index is incremented to the
|
||||
next block index. A consumer updates Index Free Write to the starting
|
||||
index of an allocation whenever it has completed processing the blocks.
|
||||
This is an optimization that can be used to prevent an additional copy
|
||||
of data from the queue into a client's data buffer and the data in the queue
|
||||
itself can be used.
|
||||
Once Index Free Write is updated, the collaborating producer (on the next
|
||||
data allocation) reads the updated Index Free Write value and it then
|
||||
updates its corresponding SMQ Out's Index Free Read and marks the blocks
|
||||
associated with that index as available for allocation. At cold boot and
|
||||
restart, these indexes are initialized to zero.
|
||||
|
||||
SMQ Out Reset# and SMQ In Reset ACK #:
|
||||
Since subsystems can restart at anytime, the data blocks and control channel
|
||||
can be in an inconsistent state when a producer or consumer comes up.
|
||||
We use Reset and Reset ACK to manage this. At cold boot, the producer
|
||||
initializes the Reset# to a known number ex. 1. Every other reset that the
|
||||
producer undergoes, the Reset#1 is simply incremented by 1. All the producer
|
||||
indexes are reset.
|
||||
When the producer notifies the consumer of data availability, the consumer
|
||||
reads the producers Reset # and copies that into its SMQ In Reset ACK#
|
||||
field when they differ. When that occurs, the consumer resets its
|
||||
indexes to 0.
|
||||
|
||||
6) Asynchronous notifications between a producer and consumer are
|
||||
done using the SMP2P service which is interrupt based.
|
||||
|
||||
Power Management
|
||||
================
|
||||
|
||||
None
|
||||
|
||||
SMP/multi-core
|
||||
==============
|
||||
|
||||
The driver uses completion to wake up the Debug Agent client threads.
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
From the perspective of the subsystem, the AP is untrusted. The remote
|
||||
stubs consult the secure debug fuses to determine whether or not the
|
||||
remote debugging will be enabled at the subsystem.
|
||||
|
||||
If the hardware debug fuses indicate that debugging is disabled, the
|
||||
remote stubs will not be functional on the subsystem. Writes to the
|
||||
queue will only be done if the driver sees that the remote stub has been
|
||||
initialized on the subsystem.
|
||||
|
||||
Therefore even if any untrusted software running on the AP requests
|
||||
the services of the Remote Debug Driver and inject RSP messages
|
||||
into the shared memory buffer, these RSP messages will be discarded and
|
||||
an appropriate error code will be sent up to the invoking application.
|
||||
|
||||
Performance
|
||||
===========
|
||||
|
||||
During operation, the Remote Debug Driver copies RSP messages
|
||||
asynchronously sent from the host debugger to the remote stub and vice
|
||||
versa. The debug messages are ASCII based and relatively short
|
||||
(<25 bytes) and may once in a while go up to a maximum 700 bytes
|
||||
depending on the command the user requested. Thus we do not
|
||||
anticipate any major performance impact. Moreover, in a typical
|
||||
functional debug scenario performance should not be a concern.
|
||||
|
||||
Interface
|
||||
=========
|
||||
|
||||
The Remote Debug Driver is a character based device that manages
|
||||
a piece of shared memory that is used as a bi-directional
|
||||
single producer/consumer circular queue using a next fit allocator.
|
||||
Every subsystem, has its own shared memory buffer that is managed
|
||||
like a separate device.
|
||||
|
||||
The driver distinguishes each subsystem processor's buffer by
|
||||
registering a node with a different minor number.
|
||||
|
||||
For each subsystem that is supported, the driver exposes a user space
|
||||
interface through the following node:
|
||||
- /dev/rdbg-<subsystem>
|
||||
Ex. /dev/rdbg-adsp (for the ADSP subsystem)
|
||||
|
||||
The standard open(), close(), read() and write() API set is
|
||||
implemented.
|
||||
|
||||
The open() syscall will fail if a subsystem is not present or supported
|
||||
by the driver or a shared memory buffer cannot be allocated for the
|
||||
AP - subsystem communication. It will also fail if the subsytem has
|
||||
not initialized the queue on its side. Here are the error codes returned
|
||||
in case a call to open() fails:
|
||||
ENODEV - memory was not yet allocated for the device
|
||||
EEXIST - device is already opened
|
||||
ENOMEM - SMEM allocation failed
|
||||
ECOMM - Subsytem queue is not yet setup
|
||||
ENOMEM - Failure to initialize SMQ
|
||||
|
||||
read() is a blocking call that will return with the number of bytes written
|
||||
by the subsystem whenever the subsystem sends it some payload. Here are the
|
||||
error codes returned in case a call to read() fails:
|
||||
EINVAL - Invalid input
|
||||
ENODEV - Device has not been opened yet
|
||||
ERESTARTSYS - call to wait_for_completion_interruptible is interrupted
|
||||
ENODATA - call to smq_receive failed
|
||||
|
||||
write() attempts to send user mode payload out to the subsystem. It can fail
|
||||
if the SMQ is full. The number of bytes written is returned back to the user.
|
||||
Here are the error codes returned in case a call to write() fails:
|
||||
EINVAL - Invalid input
|
||||
ECOMM - SMQ send failed
|
||||
|
||||
In the close() syscall, the control information state of the SMQ is
|
||||
initialized to zero thereby preventing any further communication between
|
||||
the AP and the subsystem. Here is the error code returned in case
|
||||
a call to close() fails:
|
||||
ENODEV - device wasn't opened/initialized
|
||||
|
||||
The Remote Debug driver uses SMP2P for bi-directional AP to subsystem
|
||||
notification. Notifications are sent to indicate that there are new
|
||||
debug messages available for processing. Each subsystem that is
|
||||
supported will need to add a device tree entry per the usage
|
||||
specification of SMP2P driver.
|
||||
|
||||
In case the remote stub becomes non operational or the security configuration
|
||||
on the subsystem does not permit debugging, any messages put in the SMQ will
|
||||
not be responded to. It is the responsibility of the Debug Agent app and the
|
||||
host debugger application such as GDB to timeout and notify the user of the
|
||||
non availability of remote debugging.
|
||||
|
||||
Driver parameters
|
||||
=================
|
||||
|
||||
None
|
||||
|
||||
Config options
|
||||
==============
|
||||
|
||||
The driver is configured with a device tree entry to map an SMP2P entry
|
||||
to the device. The SMP2P entry name used is "rdbg". Please see
|
||||
kernel\Documentation\arm\msm\msm_smp2p.txt for information about the
|
||||
device tree entry required to configure SMP2P.
|
||||
|
||||
The driver uses the SMEM allocation type SMEM_LC_DEBUGGER to allocate memory
|
||||
for the queue that is used to share data with the subsystems.
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
The Debug Agent driver requires services of SMEM to
|
||||
allocate shared memory buffers.
|
||||
|
||||
SMP2P is used as a bi-directional notification
|
||||
mechanism between the AP and a subsystem processor.
|
||||
|
||||
User space utilities
|
||||
====================
|
||||
|
||||
This driver is meant to be used in conjunction with the user mode
|
||||
Remote Debug Agent application.
|
||||
|
||||
Other
|
||||
=====
|
||||
|
||||
None
|
||||
|
||||
Known issues
|
||||
============
|
||||
For targets with an external subsystem, we cannot use
|
||||
shared memory for communication and would have to use the prevailing
|
||||
transport mechanisms that exists between the AP and the external subsystem.
|
||||
|
||||
This driver cannot be leveraged for such targets.
|
||||
|
||||
To do
|
||||
=====
|
||||
|
||||
None
|
Reference in New Issue
Block a user