Diag¶
- Table of contents
- 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() |
/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.
Updated by fixeria almost 5 years ago · 16 revisions