Project

General

Profile

Diag

Qualcomm Diag is the qualcomm diagnostics interface built into many Qualcomm based chipsets (or rather their software) for a long time (more than a decade). It is not publicly documented, but there are tools from Qualcomm (QPST, QXDM) as well as proprietary third-party tools and some Free Softare projects that implement parts of it.

The general idea is that there is some physical transport medium between the chipset/modem and an external PC, and the PC can request certain diagnostic information to be sent via that physical transport. Initially, this transport was a dedicated serial port/UART. Later, this became a virtual serial port over USB.

In a single-processor Modem (with only a baseband processor) it is rather simple: Some software on the baseband processor implements the DIAG protocol, and responds to any related requests received on the DIAG port.

In a multi-processor situation (like the MDM9215/MDM9x07 with their Linux-running Cortex-A5), the situation becomes slightly more complex. First of all, not only the external host/PC might want to consume DIAG information, but also code on the Linux processor inside the chip. Furthermore, code in the Linux processor might also want to offer some DIAG information towards the external host/PC.

The Qualcomm Android Linux kernel (usd even on the non-Android devices) implements several related kernel drivers, see Qualcomm_Kernel

In userspace on the Linux inside the modem, there is a (unfortunately again non-free) library called libdiag which offers some convenience API for programs to either consume DIAG or to generate/respond to DIAG received from the host/PC. Luckily the library is not performing much required functionality, so third-party programs like SnoopSnitch have managed to talk directly to the /dev/diag kernel device without needing to use that non-free library.

Acronyms

DCI Diag Consumer Interface

Child Pages

DIAG Services

Name Description
LOG Diagnostic Log Services
MSG Debug Message Service (F3/QSHRINK?)
EVENT Diagnostic Events
PKT Diagnostic Packet Request/Response
DCI_LOG Diag Consumer Interface Logging
DCI_EVENT Diag Consumer Interface Events

Subsystems

Logging

Logging works by so-called log-codes. The Log code identifies the source/category of the logged information. Log codes are 16bit unsigned integers.

Base Code Purpose
0x1000 CDMA 1x
0x4000 WCDMA
0x5000 GSM
0x6000 Location Based Services
0x7000 UMTS
0x8000 TDMA
0xA000 DTV
0xB000 APPS
0xB010 LTE (until 0xB1FF)
0xB400 WIMAX
0xC000 DSP
0xD000 TD-SCDMA (until 0xD1FF)
0xF000 LOG TOOLS

Kernel support

See Qualcomm_Kernel

Library

There is /usr/lib/libdiag.so.1 which is linked by virtually any Qualcomm or Quectel proprietary program running on the Linux in the Modem.

it offers the follwing symbols:

log_submit
pools
diag_vote_md_real_time
DiagSvc_Free
diag_dci_get_real_time_status_proc
diagpkt_subsys_get_delayed_rsp_id
diagpkt_subsys_alloc_v2
diag_read_mask_file_list
diagpkt_subsys_get_cmd_code
Diag_LSM_Event_DeInit
diag_wakelock_init
mask_file2
cleanup_mask
diag_register_dci_client
mask_file
msg_send_var
diagpkt_subsys_alloc_v2_delay
log_to_memory
diagpkt_alloc
db_thread_initialized
_init
stop_cond
diag_hdlc_toggle
diag_wakelock_acquire
parser_state
num_bytes_read
log_update_dci_mask
send_mask_modem
qsr4_db_file_fd
qsr4_db_write_buf_pool
event_update_mask
mask_sync_initialize
file_name_curr
msg_sprintf
mask_file_mdm2
event_report_payload
DiagSvc_Malloc_Init
diag_release_dci_client
update_sync_mask
diag_send_socket_data
diag_register_dci_stream_proc
DiagSvc_Malloc
buffer_init
msg_mask_tbl_size
curr_write_idx
diag_logger_flush
pool0_buffers
log_set_length
hdlc_disabled
fd_qsr4_xml
qsr4_xml_file_name
diagpkt_LSM_process_request
diag_get_real_time_status
Diag_LSM_Pkt_DeInit
flush_buffer
diag_callback_send_data
dci_cumulative_event_mask
dci_transaction_id
diag_get_health_stats_proc
stop_mutex
diag_get_health_stats
log_free
mask_file_mdm
diagpkt_subsys_reset_delayed_rsp_id
diag_logger_init
dummy_handler
diag_send_data
diag_kill_qshrink4_threads
ts_get_lohi
diagpkt_subsys_set_rsp_cnt
diag_notify_parser_thread
diag_disable_all_logs
diagpkt_commit
proc_type
diag_log_stream_config
log_status
msg_send
WriteToDisk
Diag_LSM_Log_DeInit
fd_dev
diag_dci_get_real_time_status
qsr4_db_cmd_req_buf
diagpkt_subsys_alloc
get_sync_mask
diag_get_dci_support_list_proc
diag_get_real_time_status_proc
qsr4_read_db_mutex
dir_name
diag_set_socket_fd
diag_switch_logging_proc
diagpkt_get_cmd_code
diagpkt_subsys_get_status
in_read
Diag_LSM_Event_Init
diag_dci_error_type
diag_disable_all_events
pid_file
qsr4_db_parser_thread_hdl
num_dci_proc
in_wait_for_peripheral_status
write_in_progress
Diag_LSM_Pkt_Init
max_file_size
ts_get
diag_get_event_status
log_set_timestamp
curr_read
diag_register_dci_signal_data
diagpkt_shorten
curr_read_idx
pool1_buffers
lookup_pkt_rsp_transaction
diag_disable_console
max_file_num
diag_send_dci_async_req
log_get_length
diagpkt_set_cmd_code
diagpkt_subsys_set_status
diag_peripheral_buffering_drain_immediate
event_mask
log_commit
min_file_size
gdwClientID
msg_send_ts
read_thread_hdl
valid_token
add_guid_to_qshrink4_header
msg_mask
file_list_size
log_shorten
diagpkt_free
fd_socket
flush_log
create_diag_qshrink4_db_parser_thread
diag_read_mask_file
diag_deregister_dci_signal_data
num_dci_clients_event
proc_name
diag_lsm_dci_deinit
diag_wakelock_release
read_buffer
diagpkt_subsys_get_id
peripheral_name
Diag_LSM_Init
diag_configure_peripheral_buffering_tx_mode
curr_write
diag_callback_send_data_hdlc
qsr_msg_send_1
qsr_msg_send_2
db_write_thread_hdl
Diag_LSM_Msg_Init
qsr_msg_send_3
token_list
diag_has_remote_device
diag_register_remote_callback
in_write
file_list
process_incoming_data
delete_log
log_to_device
logging_mode
log_set_code
diagpkt_delay_commit
flush_in_progress
diag_send_to_output
diag_get_max_channels
Diag_LSM_Log_Init
file_name_del
uart_logging_proc
DiagSvc_Malloc_Exit
output_dir
diag_event_stream_config
Diag_LSM_DeInit
diagpkt_tbl_reg
diag_dci_vote_real_time
kill_thread
count_written_bytes_1
qsr_msg_send
event_report
diag_fd
event_update_dci_mask
diag_get_dci_support_list
log_update_mask
parse_data_for_qsr4_db_file_op_rsp
file_list_index
rename_file_names
diag_register_callback
diag_lsm_dci_init
diag_vote_md_real_time_proc
msg_send_1
msg_send_2
msg_send_3
diag_is_wakelock_init
disk_write_hdl
diag_register_socket_cb
msg_update_mask
diag_set_peripheral_mask
log_alloc
dci_client_tbl
do_mask_sync
write_qshrink_header
fd_uart
qsr_msg_send_var
periph_info
diag_logger_exit
send_empty_mask
gnDiag_LSM_Event_Initialized
diagpkt_err_rsp
diag_logger_write
diag_get_log_status
qsr4_read_db_cond
rename_dir_name
diag_wakelock_destroy
diag_register_dci_stream
log_get_code
msg_mask_tbl
Diag_LSM_Msg_DeInit
to_integer
_fini
diag_get_peripheral_name_from_mask
count_written_bytes
diag_switch_logging
fd_md

Initialization

Function Purpose
Diag_LSM_Init() Registering with Diag which gives the client a handle to the Diag. Called once per process

Logging Service API

This is about sending log messages via the Diag interface.

Function Purpose
log_alloc(u16 code, len) Allocate a buffer + fill header
log_shorten(ptr, len) Shorten the length of a previously allocated buffer
log_commit(ptr) Send the log to diag
log_free(ptr) Free a buffer previously allocated with log_alloc()
log_submit(ptr) Convenience wrapper around log_alloc()/memcpy()/log_commit()
On the EC25, it seems only the following Linux programs use the avove API to generate logs via Diag:
  • /usr/bin/cnss_diag
  • /usr/bin/ftmdaemon
  • /usr/bin/mbimd
  • /usr/bin/test_diag

Diag Consumer Interface

This seems to be about implementing a program that consumes Diag events. You can register to certain events/masks and then receive the related information in call-backs.

Function Description
diag_lsm_dci_init() Initialize DCI subsystem of libdiag
diag_register_dci_client() Register a DCI client, issues DIAG_IOCTL_DCI_REG to /dev/diag
diag_get_dci_support_list() Get list of peripherals supported, issues DIAG_IOCTL_DCI_SUPPORT to /dev/diag
diag_register_dci_stream() Register call-backs for events and logs, writes to /dev/diag
diag_event_stream_config() Set up event streaming to the client, writes to /dev/diag
diag_log_stream_config() Specify array of requested log codes, writes to /dev/diag
diag_get_health_stats() Get statistics about missed/succeeded logs and events, issues DIAG_IOCTL_DCI_HEALTH_STATS to /dev/diag
diag_register_dci_signal_data() Request OS signal when DCI data is received

How to configure/enable logging

An external DIAG receiver (e.g. on the host PC) can configure which particular log messages he wants to receive and which not.

For the Linux programs using the libdiag.so logging service API, this means that every time an external DIAG log receiver updates the DIAG mask, that mask is passed into every program using libdiag, so they can update their log masks. This is done by reading on the /dev/diag device and calling into process_diag_payload() which in turn calls log_update_mask() pr msg_update_mask() which updates the log_mask array.

When a given log line is created, exactly that log_mask or read_mask array is consulted to check if the given subsystem is enabled or not.