阿里安全 谢君
本技术分析文章通过对高通的4/5G移动基带系统进行深入逆向工程提示其内部消息通信机制以及核心架构设计逻辑,本文的研究基于高通的4G基带MDM9707以及5G基带模块sdx55的固件之上分析完成,高通基带系统现在都是基于高通主流的hexagon DSP指令架构来实现,该架构非常适合应用于音视频编解码,计算机视觉等,软件无线电等应用中的浮点和向量计算,在高通骁龙处理器的子系统中大量使用,大多应用于手机,汽车,可穿戴设备以及移动通信设备中,Hexagon DSP相关信息可以从这里 获取,运行在Hexagon DSP芯片上的操作系统QuRT是由高通设计的实时操作系统,高通基带系统所有的上层业务将会运行在该操作系统之上,阅读该技术分析文章之前,假定你已经对操作系统的原理有所了解,例如CPU调度,IPC(进程间通信),以及基本的数据队列enqueue/dequeue的操作。
一个系统里面运行着不同的任务,不同任务在不同的运行状态在处理相应的业务逻辑时可能需要与其它任务交换数据或者同步信息,这里面就需要操作系统的底层IPC机制来完成了,3GPP组织定义了不同移动通信技术从物理层/链路层/逻辑处理层等各种标准,例如(5GNR/4GLTE/3G WCDMA/TD-SCDMA/CDMA2000/2G /GSM等通信技术),这些技术标准在基带系统里面实现会被划分成不同的任务来维护不同的状态,处理不同的消息信令,以及维护不同通信技术的切换等操作,比如现在的大部分智能手机基带系统基本上都支持2/3/4G通信相关的技术,这些基带系统根据移动运营商支持的移动通信技术和国家区域支持的标准的不同会使用相应的移动通信技术,比如中国在3G时代中国移动使用的TD-SCDMA,而中国联通使用的是WCDMA技术,为了保证移动设备的一些基本功能的可用性(语音通信和sms短信息),比如某些地方部署了4G基站,你可以在那里使用4G LTE的(Voice-over-IP/SMS-over-IP)通信技术,在一些偏远的地区可能只部署了2G基站,这时基带系统根据环境切换到GSM的协议栈,这些功能的维护与切换从基带系统层面来讲都需要系统消息机制来配合完成。
高通基带系统的消息机制建立在运行的实时操作系统QuRT之上,之前我有一篇文章 有简单介绍过底层IPC机制,今天我将详细介绍上层业务逻辑相关的消息传递机制与数据结构。我们把运行在基带系统上的业务逻辑实体的最小单位定义为线程(thread),根据线程生命周期的不同分为以下两大类:
消息通信底层API封装简介:
而根据任务线程的业务功能的不同划分成以下几大类:
我在这里 记录了高通MDM9607基带系统一次实时运行的任务快照列表。
基于以上的设计理念,高通设计一套灵活的消息通信系统,一直到现在5GNR的基带系统也在用,接下来我将详细介绍该消息系统的架构,相关的算法和数据结构。
为了区分不同任务所接受到的消息以及任务所能处理相应消息的原语操作权限,通过接受到的消息来区分消息来源以及接受到相应消息后的相应的处理动作,高通的消息系统引入了任务消息接受体(msgr_client)和UMID(Unique Message ID)的机制,任务消息接受体由相应的任务创建生成,并通过初始注册可接受消息UMID来设置任务相应原语操作的权限,每个任务可以创建一个或者多个msgr_client,每一个UMID消息也可以注册给多个msgr_client,每一个UMID消息标示着一次相应的原语操作,在MDM9607里面定义的UMID数量多达1万多个,而在最新高通的5G基带里面可使用的UMID高达2万多,每个UMID背后都对应着相应的原语操作,UMID的值与相应的命名规则如下。
注:if type_id>9 ,type_id=type_id-6 offset bit 8~15 8bits type_id list
举个例子UMID 0x40D120E 对应的描述原语是LTE_RRC_IRAT_FROM_LTE_TO_G_RESEL_REQI,拆分结果如下:
注:这种UMID值的解析方法在某些定义里面并不适用,比如LTE_ML1_DLM_TST_SKIP_RACH_REQ的值为6,就没法用上面的方法解析,有些值并不严格遵循这种解析算法,可能是由于历史原因,定义UMID值的规则不一样。
基带系统把任务标示为多个不同的技术大类,来标示和模块化相应的子功能,以MDM9607为例:
下图是MDM9607 LTE的部分子模块ID的对应关系
关键消息发送API:
我们已经了解到UMID所对应原语操作的含义,如果需要执行相应的原语操作,只需要向注册过UMID的模块发送umid消息即可,接下来我们需要了解umid消息是如何路由到相应模块(tech_mod_id)的消息接收器(msgr_client)的,下面会详细介绍相应的算法和数据结构,我整理了几张表来描述。
为了更方便的理解上述的数据结构的关系与操作算法,画了一张简单的图来加深该消息系统的理解。 通过以上算法和数据结构,可以很方便的完成UMID与tech_mod_id的消息路由的注册,消息发送等操作。
需要说明的一点就是一个tech_mod_id可能会关联多个msgr_client,所以msgr_client_id就成了消息传递的唯一标识,通过msgr_client_id得到全局的msgr_client_desc的结构定义,该结构体里面包含接受消息的任务utcb和接受消息的signal id,这里通过tech_mod_id 0xf19对应的MM(Mobility Management)任务进行举例。
我在一个实时运行的MDM9607系统上面,描绘出所有UMID和tech_mod_id之间的消息路由情况,由于实在太大, 可以在https://github.com/vessial/baseband/blob/master/umid_pro.svg 进行查看。
高通基带系统里面的消息状态机,是实现3GPP定义功能最重要的组成部分,消息状态机在移动通信系统里面扮演着非常重要的角色,也是多模移动通信系统的核心,3GPP在定义的多个移动通信技术的分层协议栈时,不同的通信技术模式之间切换,会通过状态机来维护相应的分层逻辑的状态和可操作功能,接下来将重要介绍高通基带系统使用的状态机数据结构以及相关算法,本文将研究主要流4G LTE和5G NR系统上使用的第二代状态机消息系统,老的第一代状态机系统不在这里介绍了。
我从MDM9607固件里面提取的详细的状态机信息可以在https://github.com/vessial/baseband/blob/master/lte_sm.log 进行查看。
3GPP定义的L3层的RRC(Radio Resource Control)的状态机是最为复杂的,高通在实现4G LTE的RRC时使用了大量的状态机进行功能管理。 MDM9607 4G LTE RRC状态机类型如下: state name: LTE_RRC_CSG_ASF_SM state name: LTE_RRC_DT_SM // state name: LTE_RRC_IRAT_TO_G_MGR_SM state name: LTE_RRC_LLC_SM state name: LTE_RRC_CAPABILITIES_SM state name: LTE_RRC_IRAT_FROM_1X_MGR_SM state name: LTE_RRC_SEC_SM //sim认证和密钥协商管理相关的状态机 state name: LTE_RRC_CRP_SM state name: LTE_RRC_IRAT_FROM_DO_MGR_SM //负责从CDMA-EVDO切换到LTE的管理状态机 state name: LTE_RRC_IRAT_FROM_TDS_MGR_SM //负责从TDSCDMA切换到LTE的状态机 state name: LTE_RRC_PAGING_SM //寻呼管理的状态机 state name: LTE_RRC_CONFIG_SM state name: LTE_RRC_MISC_SM state name: LTE_RRC_MEAS_SM state name: LTE_RRC_CEP_SM state name: LTE_RRC_IRAT_TO_1X_MGR_SM state name: LTE_RRC_IRAT_FROM_W_MGR_SM state name: LTE_RRC_MDT_SM state name: LTE_RRC_IRAT_TO_DO_MGR_SM state name: LTE_RRC_CONTROLLER_SM //关键的LTE的控制状态机,控制服务的停止和开启 state name: LTE_RRC_IRAT_TO_TDS_MGR_SM state name: LTE_RRC_IRAT_TO_W_MGR_SM //从LTE切换到WCDMA的管理状态机 state name: LTE_RRC_EMP_SM state name: LTE_RRC_MH_SM state name: LTE_RRC_UEINFO_SM //UE信息管理的状态机 state name: LTE_RRC_SIB_SM //系统信息块的管理状态机 state name: LTE_RRC_PLMN_SEARCH_SM //搜索网络使用的状态机 state name: LTE_RRC_IRAT_FROM_G_MGR_SM //从GSM切换到LTE的状态机 state name: LTE_RRC_CSP_SM //cell search plmn状态机 state name: LTE_RRC_ESMGR_SM // EMBMS管理状态机 state name: LTE_RRC_CRE_SM
我们拿LTE_RRC_PAGING_SM状态机定义作例子与之对应的数据结构作解析
下图为MDM9607 4G LTE_RRC的状态机图谱
为了更直观的理解消息状态机的操作过程,我这里提供了一个例子来展示消息传递过程以及状态机的处理过程,这个过程是在基带处理IDLE状态下,没有接入任何移动通信网络,到基带一次接入4G LTE网络到SIM认证的过程,这里只提供RRC的状态机的处理过程。
DL_DCCH的Information Transfer字段里面包含了来自MME发送过来的认证请求数据(LTE NAS EMM信令消息id 0x52),包含有nas key set id, 16个字节的认证随机数据auth_param rand,以及16个字节的auth param AUTN数据,SIM卡通过收到的这两个关键信息进行认证, 并计算生成Auth_resp发送给MME进行比较完成本地端和服务器端的认证,本地端计算如下。
本地端收到的rand(16bytes)+AUTN(16bytes) K为sim卡和MME都持有的sim卡的唯一隐私数据,sim卡端只有sim卡芯片可以读取。
SIM卡端密钥派生认证过程,f1/2/3/4/5为sim卡的计算功能函数
AK=f5(K,rand)
IK=f4(K,rand)
CK=f3(K,rand)
RES=f2(K,rand) //计算给MME进行认证SIM卡的数据
SQN=AUTN^AK (6bytes) AMF=AUTN[6:8]
MAC=f1(K,SQN,rand,AMF)
SIM卡端认证MME端过程
sim_autn=SQN^AK(6bytes)+AMF(2bytes)+MAC(8bytes)
比较MME发过来的AUTN和sim_autn ,相等则认为MME合法。
基带把sim卡计算得到的RES通过LTE NAS EMM 信令消息号0x53包裹到UL_DCCH的InformationTransfer字段里面发给基站进而到MME进行认证。
MME认证SIM卡的过程就比较简单了。 MME端计算XRES=f2(K,rand),然后比较收到的RES,相等表示MME认证SIM卡成功,至此认证完成。 由于上述操作涉及EMM和RRC之间的交互过程比较复杂,这里只是简单提一下,EMM的状态机会在下一篇文章里面单独详细介绍。
由于从全球公开的信息渠道中并不能获取高通基带系统的深入信息,所以花费1年多的时间通过对底层操作系统和上层3GPP实现的业务系统进行深度逆向工程,这篇文章只是系统性的介绍了高通4/5G基带系统的消息机制和消息状态机,我认为这是一个关键的架构设计,梳理清楚其消息架构对于理解3GPP实现的消息原语操作以及对移动通信技术的多模分层设计有非常大的帮助,该消息系统架构设计具有非常好的扩展性,可以很灵活的增加新的功能到该消息框架中去,可以很好的减少系统测试成本,有很多设计理念值得学习和借鉴,由于现今高通5G基带所支持的UMID操作数高达2万多个,所以这里的展示的例子只是揭示了状态机功能操作的冰山一角,后续会持续研究对于状态机安全漏洞的挖掘研究,实现高效的5G安全测试体系,通过对基带系统的深刻认知,可以更好的对基站系统和核心网系统进行安全评估。
/
/
信号发送
int
rex_send_sigs(utcb
*
dst_task_obj,unsigned
int
signal_id);
/
/
第一个参数为向目标任务发送消息的结构定义,第二个参数为要发送的信号
id
int
rex_wait_sigs(unsigned
int
recv_sigs_masks);
/
/
第一个参数为可以允许接受信号
id
的掩码,每个任务最多可以设置可接受信号
id
个数为
32
个,每个任务可以接受多个信号
id
时,通过信号
id
的或操作来得到该任务可以接受信号的掩码,返回值为接受到的信号
id
/
/
如果是带数据的信号发送,封装底层API,类似如下
int
send_sigs_with_dat(utcb
*
dst_task_obj,unsigned
int
signal_id,data_queue
*
send_data_queue);
int
recv_sigs_with_dat(unsigned
int
recv_sigs_masks,data_queue
*
recv_data_queue);
/
/
信号发送
int
rex_send_sigs(utcb
*
dst_task_obj,unsigned
int
signal_id);
/
/
第一个参数为向目标任务发送消息的结构定义,第二个参数为要发送的信号
id
int
rex_wait_sigs(unsigned
int
recv_sigs_masks);
/
/
第一个参数为可以允许接受信号
id
的掩码,每个任务最多可以设置可接受信号
id
个数为
32
个,每个任务可以接受多个信号
id
时,通过信号
id
的或操作来得到该任务可以接受信号的掩码,返回值为接受到的信号
id
/
/
如果是带数据的信号发送,封装底层API,类似如下
int
send_sigs_with_dat(utcb
*
dst_task_obj,unsigned
int
signal_id,data_queue
*
send_data_queue);
int
recv_sigs_with_dat(unsigned
int
recv_sigs_masks,data_queue
*
recv_data_queue);
Name
offset and length
Comment
tech_id
24~31 8bits
eg, LTE->0x04, IMS->0x15, MDM9607 0x1b, SDX55 0x20
mod_id
16~23 8bits
eg, 0xd -> RRC 0xf -> MAC 0x11-> RLC DL
type_id
8~15 8bits
type <= 0x09) || (type >= 0x11 && type <= 0x17,totally 0x11 type_ids
op_type_id
4~8 4bits
Op entity ,eg IRAT_FROM_LTE_TO_G
op_id
0~3 4bits
Opcode seq, eg abort/search/startup/deinit/init/cfg etc
Type_name
value
Comment
CMD
1
Command primitive
REQ
2
request
RSP
3
response
IND
4
indication
DLM
7
downlink message
CNF
8
confirm
TMR
9
timer
REQI
0x12
request Internal
RSPI
0x13
Response internal
INDI
0x14
indication internal
CNFI
0x15
confirm internal
TMRI
0x16
timer internal
name
value
LTE
0x04
RRC
0x0d
REQI
0x12
RESEL
0x0
IRAT_FROM_LTE_TO_G
0x0e
tech_id
Tech_name
0
MCS(Modem Common Service)
2
MM_CM(0x201) UI(0x20a) (Unnumbered Information) MM_DOM(0x202),MM_MMOC(0x251)
4
LTE
5
FTM
6
rfa_tech (0x600 rf_fwrsp,0x603 rfgsm, 0x604 rf_1x ,0x601 0x605 rf_hdr ,0x606 rfgsm_ftm,0x607 rf_lte,0x608 rf_lte_ftm,0x60b rf_qmi, 0x60c rf_meas,0x40f/0x1a04 rf_lte ,0x120f rf_tdscdma)
7
cdma
8
hdr
9
gsm
0x0a
location(gps/gnss)
0x0b
wcdma
0x0c
ds(data service)
0x0d
1x(csfb)
0x0f
nas(0xf19 mm, 0xf1c esm)
0x10
gstk(Generic SIM Application Toolkit)
0x12
tdscdma
0x13
wms
0x15
ims
0x16
qmi
0x17
ecall 0x1701 ecall_app ,0x1702 ecall_ivs
0x18
policyman
0x1a
rflm
tech_id+mod_id
name
0x401
ML1 MGR
0x407
LL1_SRCH
0x408
LL1_DL
0x409
LL1_UL
0x40a
LL1_SYS
0x40b
LL1_Async
0x40d
RRC
0x40f
MAC
0x411
RLC DL
0x412
RLC UL
0x413
PDCP DL
0x414
PDCP UL
0x41b
ML1_GM
0x41e
SW.app
0x420
ML1_GM_SCHDLR
0x427
TLB(Test Loop )
0x42b
ML1_GM_Sleep
0x434
ML1_AFC
0x43b
PDCP offload
0x43e
ML1 offload
0x43f
ML1 Co-existence
0x441
ML1 GM MSMGR
0x442
PDCPCOMP
0x445
ML1 SM FSCAN
msgr_send(umsg
*
buf,uint32 buf_size);
struct umsg{
struct msgr_hdr_struct_type{
uint32 dest_umid;
/
/
offset
0
,要发送的UMID号
uint16 src_tech_mod_id;
/
/
offset
4
,发送源tech_mod_id的标识
uint8 num_attach;
/
/
offset
7
uint8 tail_flag ;
/
/
offset
8
,头部结尾标志
0x7f
uint8 inst_id;
/
/
offset
9
,
}
uint8 send_dsm_flag;
/
/
offset
0x10
,置
1
表示发送数据通过dsm结构承载的标志
dsm
*
dsm_obj;
/
/
offset
0x14
, 发送数据dsm结构指针
}
msgrq_wait(void
*
msgr_client_ptr,void
*
msg_recv_buf,uint32 msg_recv_buf_size,uint32
*
msg_recvd_size_ptr);
/
/
接受消息的函数
msgr_register(uint16 mod_id,void
*
msgr_client_ptr,void
*
mailbox_obj,uint32 umid);
/
/
msgr_client注册umid的消息路由
msgr_send(umsg
*
buf,uint32 buf_size);
struct umsg{
struct msgr_hdr_struct_type{
uint32 dest_umid;
/
/
offset
0
,要发送的UMID号
uint16 src_tech_mod_id;
/
/
offset
4
,发送源tech_mod_id的标识
uint8 num_attach;
/
/
offset
7
uint8 tail_flag ;
/
/
offset
8
,头部结尾标志
0x7f
uint8 inst_id;
/
/
offset
9
,
}
uint8 send_dsm_flag;
/
/
offset
0x10
,置
1
表示发送数据通过dsm结构承载的标志
dsm
*
dsm_obj;
/
/
offset
0x14
, 发送数据dsm结构指针
}
msgrq_wait(void
*
msgr_client_ptr,void
*
msg_recv_buf,uint32 msg_recv_buf_size,uint32
*
msg_recvd_size_ptr);
/
/
接受消息的函数
msgr_register(uint16 mod_id,void
*
msgr_client_ptr,void
*
mailbox_obj,uint32 umid);
/
/
msgr_client注册umid的消息路由
map_name
map_size
key
value
value_size
Memory Attribution
techs_map
techs * 8
tech_id
module_counts, modules_map
8 bytes
Read Only
modules_map
module_counts 0x11 2
(mod_id 0x11+type_id) 2
types_map_id
2 bytes
Read Only
types_map
types_map_ids * 0x20
types_map_id * 0x20 +(op_type_id&0x1e)
tech_mod_type_seq
2 bytes
Read/Write
umids_map
umid_seq_id * 0x8
8 * (tech_mod_type_seq+op_id)
umid, next_umid_seq_id,msgr_client_id
8 bytes
Read/Write
msgr_clients_map
0x34*total_msgr_client_counts
msgr_client_seq_id
msgr_client_desc
0x34
Read/Write
struct msgr_client_desc{
/
/
全局msgr_client结构描述
uint32 umids_registered;
uint16 msgr_client_reg_type;
/
/
1
-
>msgrq_sig
type
,
2
-
> rexq_sig
uint16 tech_mod_id;
/
/
union
*
msg_sig_p{
/
/
offset
0x10
struct msgrq_sig
*
msgq_p;
/
/
msgr reg
type
1
,
4G
及以后使用的mailbox消息传递系统
struct rexq_sig
*
rexq_p;
/
/
msgr reg
type
2
,兼容
2G
/
3G
时代使用的Rex IPC消息传递系统
}
struct msgrq
*
msgrq_p;
/
/
offset
0x14
,
if
reg
type
1
struct msgr_client_obj
*
msgr_client_obj_ptr;
/
/
offset
0x30
}
struct msgr_client_obj{
/
/
msgr_client结构体
unsigned
int
msgr_client_reg_type;
/
/
1
-
> msgrq aka mailbox,
2
-
>rex_q,接受消息的方式
unsigned
int
register_umid_counts;
/
/
offset
8
,消息接受器注册的umid的总数
unsigned
int
total_reged_recv_signal_counts;
/
/
offset
0x0c
,注册的接受消息的signal的个数
union sig_recv_obj{
msgrq_sig
*
msgrq_signal_obj;
/
/
offset
0x10
msgrq_sig
type
,
4
/
5G
未来的主流类型
rexq_sig
*
rex_signal_obj;
/
/
offset
0x10
rexq_sig
type
,这个主要是为了兼容之前
2
/
3G
的系统的数据结构
}
unsigned
int
task_recv_signal_set_mask;
/
/
offset
0x14
,注册的接受消息的signal号的掩码
uint32 err_counts;
/
/
offset
0x18
unsigned
int
recvd_signal_id;
/
/
offset
0x1c
,当前接受到的signal
id
,msgr_client_reg_type为
1
struct msgrq
*
recvd_msgrq_ptr;
/
/
offset
0x20
,当前接受消息承载的msgrq对象,msgr_client_reg_type为
1
struct msgrq
*
msgrq_first_entry;
/
/
offset
0x24
,接受msgrq消息链表结构指针,msgr_client_reg_type为
1
unsigned
int
total_msgrq_counts;
/
/
offset
0x28
, 可以接受msgrq消息的总数,通过可以task_recv_signal_set_mask来确定,msgr_client_reg_type为
1
}
struct msgrq_sig{
uint32 sig_ready_flag;
/
/
must be
1
struct sig_def{
uint32 signal_id_for_recv;
/
/
offset
8
uint32 signal_reged_wait_mask;
/
/
offset
0xc
void
*
kernel_msg_queue;
unsigned
int
attribute;
};
}
struct rexq_sig{
/
/
size
0x1c
, 兼容
2
/
3G
系统的数据结构
utcb
*
msgr_client_utcb_ptr;
/
/
offset
0
任务接受消息使用的utcb标识
uint32 msgr_client_signal_id;
/
/
offset
4
接受消息使用的signal
id
msg_queue
*
msgr_out_msg_q;
/
/
offset
0x8
msg_queue
*
rex_msg_in_q;
/
/
offset
0xc
uint16 msg_data_q_used_size;
/
/
offset
0x10
uint16 rexq_id;
/
/
offset
0x12
uint16 msg_data_q_size;
/
/
offset
0x14
}
struct msg_data_q{
struct msg_data_q
*
prev_q;
struct msg_data_q
*
next_q;
char data[msg_data_q_size
-
8
];
}
struct msg_queue{
struct msg_data_q
*
headp;
struct msg_data_q
*
tailp;
uint32 total_q_counts;
}
struct msgrq{
void
*
msg_recv_buf_header;
/
/
offset
0
void
*
msg_recv_end_buf;
/
/
offset
4
char msgrq_name[
16
];
/
/
offset
0x10
int
msgrq_recvd_seq;
/
/
ofset
0x18
unsigned
int
reged_recv_signal_id_mask;
/
/
offset
0x1c
,可供接受消息signal的掩码
void
*
msgr_buf_remain_ptr;
/
/
offset
0x20
,可供接受消息的剩余空间起始地址
void
*
msgr_recv_buf;
/
/
offset
0x24
,当前接受到消息的buf地址
uint32 msgr_buf_remain_size;
/
/
offset
0x28
unsigned
int
total_msg_recv_buf_size;
/
/
offset
0x30
int8 is_buf_in_use;
/
/
offset
0x70
,
0
-
>
in
use,
1
-
>
not
in
use
uint32 recvd_msg_blocks;
/
/
offset
0x58
,收到的消息次数总和
struct msgrq
*
next_msgrq;
/
/
offset
0x74
}
struct msgr_client_desc{
/
/
全局msgr_client结构描述
uint32 umids_registered;
uint16 msgr_client_reg_type;
/
/
1
-
>msgrq_sig
type
,
2
-
> rexq_sig
uint16 tech_mod_id;
/
/
union
*
msg_sig_p{
/
/
offset
0x10
struct msgrq_sig
*
msgq_p;
/
/
msgr reg
type
1
,
4G
及以后使用的mailbox消息传递系统
struct rexq_sig
*
rexq_p;
/
/
msgr reg
type
2
,兼容
2G
/
3G
时代使用的Rex IPC消息传递系统
}
struct msgrq
*
msgrq_p;
/
/
offset
0x14
,
if
reg
type
1
struct msgr_client_obj
*
msgr_client_obj_ptr;
/
/
offset
0x30
}
struct msgr_client_obj{
/
/
msgr_client结构体
unsigned
int
msgr_client_reg_type;
/
/
1
-
> msgrq aka mailbox,
2
-
>rex_q,接受消息的方式
unsigned
int
register_umid_counts;
/
/
offset
8
,消息接受器注册的umid的总数
unsigned
int
total_reged_recv_signal_counts;
/
/
offset
0x0c
,注册的接受消息的signal的个数
union sig_recv_obj{
msgrq_sig
*
msgrq_signal_obj;
/
/
offset
0x10
msgrq_sig
type
,
4
/
5G
未来的主流类型
rexq_sig
*
rex_signal_obj;
/
/
offset
0x10
rexq_sig
type
,这个主要是为了兼容之前
2
/
3G
的系统的数据结构
}
unsigned
int
task_recv_signal_set_mask;
/
/
offset
0x14
,注册的接受消息的signal号的掩码
uint32 err_counts;
/
/
offset
0x18
unsigned
int
recvd_signal_id;
/
/
offset
0x1c
,当前接受到的signal
id
,msgr_client_reg_type为
1
struct msgrq
*
recvd_msgrq_ptr;
/
/
offset
0x20
,当前接受消息承载的msgrq对象,msgr_client_reg_type为
1
struct msgrq
*
msgrq_first_entry;
/
/
offset
0x24
,接受msgrq消息链表结构指针,msgr_client_reg_type为
1
unsigned
int
total_msgrq_counts;
/
/
offset
0x28
, 可以接受msgrq消息的总数,通过可以task_recv_signal_set_mask来确定,msgr_client_reg_type为
1
}
struct msgrq_sig{
uint32 sig_ready_flag;
/
/
must be
1
struct sig_def{
uint32 signal_id_for_recv;
/
/
offset
8
uint32 signal_reged_wait_mask;
/
/
offset
0xc
void
*
kernel_msg_queue;
unsigned
int
attribute;
};
}
struct rexq_sig{
/
/
size
0x1c
, 兼容
2
/
3G
系统的数据结构
utcb
*
msgr_client_utcb_ptr;
/
/
offset
0
任务接受消息使用的utcb标识
uint32 msgr_client_signal_id;
/
/
offset
4
接受消息使用的signal
id
msg_queue
*
msgr_out_msg_q;
/
/
offset
0x8
msg_queue
*
rex_msg_in_q;
/
/
offset
0xc
uint16 msg_data_q_used_size;
/
/
offset
0x10
uint16 rexq_id;
/
/
offset
0x12
uint16 msg_data_q_size;
/
/
offset
0x14
}
struct msg_data_q{
struct msg_data_q
*
prev_q;
struct msg_data_q
*
next_q;
char data[msg_data_q_size
-
8
];
}
struct msg_queue{
struct msg_data_q
*
headp;
struct msg_data_q
*
tailp;
uint32 total_q_counts;
}
struct msgrq{
void
*
msg_recv_buf_header;
/
/
offset
0
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-9-8 18:17
被kanxue编辑
,原因: