MPC8360E安全引擎PKEU与DEU寄存器详解与中断控制实战

AI助手已提取文章相关产品:

1. 项目概述与核心价值

在嵌入式通信处理器,尤其是像MPC8360E这样的PowerQUICC II Pro系列芯片中,硬件安全引擎(Security Engine, SEC)是保障系统通信安全与性能的基石。它不是软件库,而是一个实实在在的、挂在系统总线上的硬件协处理器。今天,我们不谈高层的SSL/TLS协议,也不讲抽象的加密算法,就深入到这个“黑盒子”的内部,掰开揉碎地看看它的两个核心执行单元——公钥引擎(PKEU)和数据加密标准单元(DEU)——到底是怎么通过一堆寄存器被我们“使唤”的,特别是当它们“闹脾气”(出错)或“睡过头”(需要初始化)时,我们如何通过中断控制机制让它乖乖听话。

很多开发者拿到芯片手册,看到动辄几十页的寄存器描述,往往头大,直接套用现成的驱动了事。但当你真正需要调试一个棘手的加密失败问题,或者试图榨干硬件性能时,不理解这些寄存器每一位的含义及其背后的状态机逻辑,就如同盲人摸象。SEC 2.4中的PKEU和DEU,其设计哲学非常典型:通过状态寄存器(如PKEUSR, DEUSR)让你“看见”模块内部,通过中断状态寄存器(如PKEUISR, DEUISR)告诉你“哪里疼”,再通过控制寄存器(如PKEURCR, DEURCR, PKEUICR, DEUICR)让你“动手治疗”。这种“状态监控-错误上报-控制干预”的三段式硬件管理机制,是构建稳定、可靠嵌入式安全系统的关键。

本文将基于MPC8360E的参考手册,带你穿透手册表格,以一线开发者的视角,详解PKEU和DEU的寄存器地图、中断控制流以及模块初始化的每一个细节。我会结合常见的实操场景,比如如何安全地启动一个加密任务、如何诊断一个静默的失败、以及如何区分“模块复位”和“中断复位”,让你不仅能看懂手册,更能用活这些寄存器。

2. 安全引擎SEC 2.4架构与寄存器地图总览

在深入PKEU和DEU之前,我们得先对SEC 2.4这个“大管家”有个整体认识。SEC 2.4是一个高度集成的硬件安全子系统,它内部包含了多个独立的执行单元(Execution Unit, EU),每个EU都是专精于某类密码学算法的硬件加速器。除了本文重点讨论的PKEU(负责RSA、ECC等公钥运算)和DEU(负责DES/3DES对称加密),通常还包括AES单元、哈希单元、随机数生成器等。

这些EU对主机(CPU)来说,表现为一片连续的内存映射I/O(MMIO)空间。主机通过像访问内存一样读写这些特定地址,来配置EU、输入数据、读取状态和获取结果。这种设计将复杂的密码学运算抽象为简单的寄存器读写,极大降低了软件开发的复杂度。每个EU的寄存器地图布局都有相似的逻辑分区,通常包括: 模式/控制寄存器 数据/密钥寄存器 状态寄存器 中断相关寄存器 以及 FIFO接口

注意 :手册中反复强调,当SEC作为“发起者”(Initiator)模式运行时(即通过内置的DMA和描述符链自动处理数据),驱动程序会封装这些寄存器操作,开发者无需直接访问。我们这里探讨的“直接寄存器编程”,主要适用于“从属”(Slave)模式(即CPU直接管理)、深度调试、性能优化或理解底层机制的场景。搞清你的应用场景,才能决定你需要深入到哪一层。

PKEU和DEU的寄存器偏移地址都以 0x3_ 开头,这表明它们位于SEC模块内部统一编址的空间内。例如,PKEU的状态寄存器(PKEUSR)在 0x3_C028 ,而DEU的模式寄存器(DEUMR)在 0x3_2000 。在编写底层驱动时,我们需要先通过芯片的CCSR(控制器配置状态寄存器)找到SEC模块的基地址,然后加上这些偏移量来访问具体的寄存器。

3. PKEU寄存器详解与中断控制机制

公钥引擎(PKEU)是处理非对称加密算法的核心,比如RSA签名/验证、ECDH密钥交换。它的运算对象是大数(2048位),因此其寄存器设计围绕着大数操作数和运算状态展开。

3.1 PKEU核心控制与状态寄存器

PKEU复位控制寄存器(PKEURCR) 是你与PKEU交互的第一个关键门户。它位于偏移地址 0x3_C020 (根据上下文推断,手册表格未明确给出偏移,但结构类似DEU)。这个寄存器的三个高位控制位决定了PKEU的“重启”级别:

名称 描述 操作影响
63 SR 软件复位 等同于硬件复位引脚。将 所有 PKEU内部寄存器和状态机复位到上电初始值。复位完成后需等待PKEUSR[RD]置位。
62 MI 模块初始化 软复位的一个子集 。它会复位大部分PKEU逻辑(如计算单元、参数内存),但 保持中断控制寄存器(PKEUICR)的内容不变 。适用于需要重新开始计算但不想改变当前中断屏蔽设置的场景。
61 RI 复位中断 最温和的复位 。仅复位中断逻辑,即清除PKEUISR中的错误状态位,并复位DONE和ERROR中断信号。 影响正在进行的计算或参数内存中的数据。

实操心得一:理解三级复位的差异 在实际调试中,这三个位的误用会导致诡异的问题。假设你的PKEU因为一个密钥错误(KSE)而 halt 了。如果你错误地写了SR位,整个PKEU被彻底重置,你之前加载到参数内存A、B、E、N的所有操作数全部丢失,需要全部重新加载,耗时很长。如果你写了MI位,参数内存会被重新初始化(通常清零),但你的中断屏蔽设置(比如你屏蔽了地址错误AE)得以保留。最合适的操作是写RI位:它只清除PKEUISR中的错误标志位,让中断信号线恢复常态,便于CPU重新启动任务或进行错误处理,而不扰动其他状态。 正确的流程通常是:先读PKEUISR诊断错误 -> 根据错误类型决定处理方式(如重新加载参数)-> 最后写RI位清除中断状态 -> 重新触发计算。

PKEU状态寄存器(PKEUSR) 位于 0x3_C028 ,是一个只读窗口,用于窥探PKEU内部的关键信号。

名称 描述
63 RD 复位完成。0表示复位(SR或MI)正在进行中;1表示复位流程已结束,PKEU就绪。 在发起任何计算前,必须确认此位为1。
62 ID 中断完成。反映DONE中断信号线的状态。当一次计算(如模幂运算)成功完成,此位会被硬件置1,并触发中断(如果未被屏蔽)。
61 IE 中断错误。反映ERROR中断信号线的状态。当任何使能的错误发生时,此位置1。
58 HALT 停止标志。 这是一个非常重要的状态位 。当PKEU因一个未被中断控制寄存器屏蔽的错误而停止工作时,此位置1。即使错误在PKEUISR中被屏蔽了,只要错误发生导致引擎停止,HALT位也会置1。因此, 在检查错误时,应同时查询PKEUISR和PKEUSR[HALT]
57 Z 零检测位。反映上次采样时PKEU内部零检测标志的状态。 手册特别警告 ,只有特定指令会修改此位,使用时需极其小心,通常用于某些算法例程的内部判断。

注意 :PKEUSR是只读的。尝试写入它会触发一个地址错误(AE),并在PKEUISR中体现出来。这算是一个硬件上的防误写保护。

3.2 PKEU中断状态与控制寄存器

中断是CPU与PKEU异步通信的核心机制。PKEU通过两条中断线信号给SEC控制器:DONE(完成)和ERROR(错误)。而具体是哪些错误会导致ERROR信号拉高,则由一对寄存器精细控制。

PKEU中断状态寄存器(PKEUISR) 位于 0x3_C030 。它像一个详细的错误日志,记录了自上次清除以来���生的所有 已使能 的错误事件。每一位对应一种特定的错误类型。

名称 描述
57 AE 地址错误。访问了PKEU地址空间中非法的地址(如写入只读寄存器,读取只写寄存器E/N)。
56 ME 模式错误。模式寄存器中写入了非法值(例如,向保留位写1)。
55 DSE 数据大小错误。向数据大小寄存器写入了超出97-2048位范围的值。
54 KSE 密钥大小错误。向密钥大小寄存器写入了非法值(对于PKEU,通常有特定约束)。
53 CE 上下文错误。 这是一个常见的运行时错误 。当PKEU正在运行时(即从写入PKEUEUG开始到ID置位之间),任何对关键配置寄存器(密钥、密钥大小、数据大小、模式寄存器)的修改都会触发此错误。
51 IE 内部错误。PKEU内部处理过程中检测到的错误(如运算溢出)。这是一个“总括”性错误位,任何使能的错误发生它都会置位。
50 INV 反转错误。在执行模逆元计算时,操作数为零。

关键机制 :PKEUISR中的位是“粘性”的。一旦置位,除非通过写PKEUICR对应位或进行模块复位(RI/MI/SR),否则不会自动清除。这保证了CPU有足够时间读取错误信息。

PKEU中断控制寄存器(PKEUICR) 位于 0x3_C038 。它是PKEUISR的“开关面板”。PKEUICR中的每一位与PKEUISR中的错误位一一对应。

名称 描述
57 AE 地址错误使能。0=使能(错误发生时更新PKEUISR并触发ERROR中断);1=禁用(忽略此错误)。
56 ME 模式错误使能。
... ... ... (其他位与PKEUISR对应)

中断控制逻辑详解

  1. 错误发生 :PKEU在运行中检测到一个错误,例如上下文错误(CE)。
  2. 查询屏蔽 :硬件检查PKEUICR中对应位(CE位)的值。
    • 如果PKEUICR[CE] = 1(禁用),则硬件忽略此错误。 PKEUISR[CE]不会置位,ERROR中断信号不会拉高,但PKEUSR[HALT]可能会置1(如果错误导致引擎停止) 。这是手册里一个容易忽略的细节:某些致命错误即使被屏蔽,也可能导致引擎HALT。
    • 如果PKEUICR[CE] = 0(使能),则进入下一步。
  3. 记录与中断 :硬件将PKEUISR[CE]置位。同时,由于有使能的错误发生,PKEUISR[IE](内部错误)也会被置位。然后,PKEU拉高ERROR中断信号线通知SEC控制器。
  4. 引擎行为 对于绝大多数使能的错误,PKEU会停止当前处理(Halt) 。这是一个安全设计,防止在错误状态下继续产生无意义或更危险的结果。
  5. CPU处理 :CPU通过SEC控制器的中断状态寄存器(ISR)感知到ERROR中断,进而查询PKEUISR定位具体错误。处理完毕后,通过写PKEUICR对应位(写1)或写PKEURCR[RI]来清除PKEUISR中的错误标志,为下一次操作做准备。

实操心得二:中断屏蔽策略 在开发初期或调试阶段,建议将所有错误都使能(PKEUICR各位清零),以便捕获所有潜在问题。在生产环境中,为了提高鲁棒性,可能会选择屏蔽一些非致命的、可恢复的错误,或者由上层协议保证不会发生的错误。例如,如果你的软件流程绝对保证不会在计算中修改上下文,那么可以考虑屏蔽CE错误。但 强烈建议始终使能AE、ME、KSE、DSE这类配置性错误 ,因为它们通常意味着软件存在bug。

3.3 PKEU参数内存与启动流程

PKEU有四个2048位的参数内存:A, B, E, N。它们用于存放大数操作数。数据格式是小端字节序:最低有效字节放在最低地址。

  • 内存A/B :通常作为输入操作数和结果存储区。在椭圆曲线运算中,它们还被分割为四个512位内存使用。
  • 内存E 只写 。存储模幂运算的指数或椭圆曲线点乘的乘数k。尝试读取会触发AE错误。
  • 内存N 只写 。存储模数(用于模运算)或不可约多项式(用于F2m域椭圆曲线)。尝试读取会触发AE错误。

PKEU EU-Go寄存器(PKEUEUG) 位于 0x3_C050 ,是一个 只写 的触发器。向这个寄存器执行写操作(写入任何值均可,通常写0),就是向PKEU下达“开始计算”的指令。PKEU会根据当前模式寄存器、参数内存的内容,启动相应的公钥运算流程。

标准PKEU操作流程(Slave模式)

  1. 复位与等待 :如果需要,执行复位(SR/MI),并轮询PKEUSR[RD]直到为1。
  2. 配置 :设置模式寄存器(选择算法、曲线参数等)。
  3. 加载数据 :向参数内存A、B、E、N写入相应的操作数(大数)。
  4. 设置大小 :配置密钥大小和数据大小寄存器。
  5. 启动计算 :向PKEUEUG寄存器执行一次写操作。
  6. 等待完成 :轮询PKEUSR[ID]位,或等待DONE中断。同时监控PKEUSR[HALT]和PKEUISR。
  7. 获取结果 :计算完成后,从参数内存B(或指定结果区域)读取结果。
  8. 错误处理 :如果PKEUSR[IE]为1或收到ERROR中断,则读取PKEUISR诊断错误,根据错误类型进行恢复(如重新加载数据、复位中断RI),然后回到步骤2或3。

4. DEU寄存器详解与中断控制机制

数据加密标准单元(DEU)负责DES和3DES对称加密算法,支持ECB和CBC模式。它的寄存器结构与PKEU类似,但增加了更多与数据流、FIFO管理相关的功能。

4.1 DEU核心控制与状态寄存器

DEU模式寄存器(DEUMR) 位于 0x3_2000 ,是配置DEU工作模式的核心。

名称 描述
63 ED 加密/解密。1=加密,0=解密。
62 TS 单DES/三DES。1=三DES,0=单DES。
61 CE 工作模式。1=CBC模式,0=ECB模式。
53-55 BURST SIZE 突发大小。 手册特别强调 ,此字段仅为调试可见,在Slave模式下不应直接写入,它由通道在Initiator模式自动配置。

DEU密钥大小寄存器(DEUKSR) 数据大小寄存器(DEUDSR) 分别位于 0x3_2008 0x3_2010 。它们有严格的合法性检查:

  • DEUKSR :单DES必须为8字节(0x08);三DES可为16字节(2密钥,K1=K3)或24字节(3密钥)。
  • DEUDSR :待处理数据的 总长度 (单位字节)。其低6位(bits 58-63)必须为0,即总长度必须是64位(8字节)的整数倍。DEU 自动填充数据,必须由软件保证。

警告 :在调试模式下直接写这两个寄存器可能触发非法大小错误。务必在操作前,在DEUICR中禁用对应的KSE和DSE错误检测。

DEU状态寄存器(DEUSR) 位于 0x3_2028 ,提供了DEU内部状态的实时快照。

名称 描述
63 RD 复位完成。
62 ID 中断完成(DONE信号)。
61 IE 中断错误(ERROR信号)。
58 HALT 停止标志。含义同PKEU。
48-55 IFL 输入FIFO中当前的双字(dword, 4字节)数量。
40-47 OFL 输出FIFO中当前的双字数量。

IFL和OFL字段是调试数据流问题的利器 。如果加密流程卡住,检查IFL是否为0且OFL无数据,可能意味着数据未正确写入输入FIFO;如果IFL有值但OFL无增长,可能DEU内部处理挂起(HALT)。

4.2 DEU中断状态与控制寄存器

DEU的中断系统比PKEU更复杂,因为它涉及数据流(FIFO)错误。

DEU中断状态寄存器(DEUISR) 位于 0x3_2030 ,错误类型更为丰富。

名称 描述
63 OFO 输出FIFO溢出。输出FIFO已满时仍尝试写入。
62 OFU 输出FIFO下溢。输出FIFO为空时仍尝试读取。
61 IFO 输入FIFO溢出。输入FIFO已满时仍尝试写入。 注意 :Slave模式下,FIFO深度有限(512字节),需注意流量控制。
60 IFU 输入FIFO下溢。输入FIFO为空时仍尝试读取。
59 IFE 输入FIFO错误。DONE中断产生时,输入FIFO非空。
58 OFE 输出FIFO错误。写入DEUDSR时,输出FIFO非空。
57 AE 地址错误。
56 ME 模式错误。
55 DSE 数据大小错误。
54 KSE 密钥大小错误。
53 CE 上下文错误。 运行时修改DEU关键寄存器(密钥、IV、模式、大小寄存器)会触发
52 ERE 早期读错误。 在DEU加密过程中读取了初始化向量(IV)寄存器
51 IE 内部错误。
50 KPE 密钥奇偶校验错误。DES密钥每个字节有1个奇偶校验位,此错误表示写入的密钥不符合奇校验规则。

DEU中断控制寄存器(DEUICR) 位于 0x3_2038 ,其每一位与DEUISR对应,用于屏蔽特定错误。其工作原理与PKEUICR完全相同。

4.3 DEU数据流、FIFO与操作流程

DEU通过一对输入/输出FIFO与外界交换数据。这对FIFO在地址空间上是“多地址映射”的,但所有写入地址都指向输入FIFO的尾端,所有读取地址都指向输出FIFO的首端。这简化了编程模型。

关键寄存器

  • DEU IV寄存器 :用于CBC模式的初始化向量。 在加密过程中读取它会触发ERE错误
  • DEU Key寄存器(K1-K3) :只写寄存器,用于加载密钥。读取会触发AE错误。加载顺序对于3DES很重要。
  • DEU EU-Go寄存器(DEUEUG) :位于 0x3_2050 只写 。它的作用与PKEUEUG略有不同。在Slave模式下,当最后一个数据块写入输入FIFO后,必须向DEUEUG写一次,以告知DEU可以开始处理最后一个块并最终产生DONE中断。它是一个“最终块处理触发器”。

标准DEU操作流程(Slave模式,以CBC加密为例)

  1. 初始化 :复位DEU,等待DEUSR[RD]为1。在DEUICR中配置所需的中断屏蔽(如先屏蔽KSE/DSE用于配置)。
  2. 写密钥 :根据单DES/3DES模式,向DEUK1(及DEUK2、DEUK3)写入密钥。
  3. 写IV :向DEUIV寄存器写入初始化向量(CBC模式)。
  4. 配置模式 :向DEUMR写入模式(如 CBC + 3DES + 加密)。
  5. 配置大小 :向DEUKSR写入正确的密钥长度,向DEUDSR写入总数据长度(必须是8的倍数)。
  6. 写入数据 :将明文数据按64位(8字节)为单位,连续写入DEU的FIFO地址空间(实际上是输入FIFO)。需要软件控制写入速度,避免IFO(输入FIFO溢出)。
  7. 触发最终处理 :当最后一个数据块写入后,向DEUEUG寄存器执行一次写操作。
  8. 读取结果 :从DEU的FIFO地址空间(实际上是输出FIFO)连续读取密文数据。同样需控制读取速度,避免OFU(输出FIFO下溢)。
  9. 等待完成与错误处理 :轮询DEUSR[ID]或等待DONE中断。随时监控DEUSR[HALT]和DEUISR。完成后,可读取DEUIV获取新的IV(用于下一个CBC块)。

5. 模块初始化、错误排查与实战技巧

理解了寄存器,最终是为了用好它。下面结合常见问题,分享一些实战中的技巧和避坑指南。

5.1 模块初始化流程详解

模块初始化不仅仅是上电复位。在任务执行间隙、发生不可恢复错误后,都需要一个可靠的初始化流程。

  1. 确定初始化级别

    • 完全复位(SR) :当需要彻底清理现场,从头开始时使用。这会重置所有寄存器,包括中断控制寄存器。操作:写PKEURCR[SR]或DEURCR[SR]为1。然后轮询PKEUSR[RD]或DEUSR[RD]直到为1。
    • 模块初始化(MI) :当需要重新开始计算,但希望保留当前的中断屏蔽配置时使用。操作:写MI位为1。同样等待RD位置1。
    • 中断复位(RI) :仅用于清除当前的中断状态,以便重新启动因错误而停止的任务。 不会 清除配置和数据。操作:写RI位为1。
  2. 初始化后配置顺序 :这是一个容易出错的点。推荐的稳健配置顺序是: a. 屏蔽可能由配置本身触发的错误 :在写配置寄存器前,先在中断控制寄存器(PKEUICR/DEUICR)中临时屏蔽KSE、DSE、ME等错误。例如,设置DEUICR[KSE]=1, DEUICR[DSE]=1, DEUICR[ME]=1。 b. 写入配置寄存器 :依次设置模式寄存器、密钥大小、数据大小等。 c. 恢复错误屏蔽 :将中断控制寄存器中之前屏蔽的位恢复为期望的生产环境状态(通常为使能,即0)。 d. 加载密钥和IV (对于DEU)。 e. 加载操作数 (对于PKEU)或 开始传输数据 (对于DEU)。

这个顺序可以避免在配置过程中,因为写入一个中间非法值(例如先写模式寄存器但还没写密钥大小)而立即触发错误中断。

5.2 常见错误排查与诊断流程

当系统没有按预期工作(例如,没有产生DONE中断,或触发了ERROR中断),可以遵循以下诊断树:

  1. 检查状态寄存器(PKEUSR/DEUSR)

    • RD位是否为1? 如果不是,模块还在复位中,等待。
    • HALT位是否为1? 如果是,说明引擎已因错误停止。这是第一个需要检查的标志。
    • ID位是否为1? 如果是,说明操作已完成,可能中断被屏蔽或CPU未捕获。
    • IE位是否为1? 如果是,说明有使能的错误发生。
  2. 查询中断状态寄存器(PKEUISR/DEUISR)

    • 如果HALT或IE为1,详细阅读PKEUISR/DEUISR。每一位都指示了具体的错误原因。这是最重要的诊断信息。
  3. 根据错误码分析

    • CE(上下文错误) :最常见。检查是否在引擎运行期间(从写EU-Go到ID置位之间)意外修改了密钥、IV、模式或大小寄存器。这可能是多线程/中断环境下的并发访问问题。
    • KSE/DSE(大小错误) :检查写入DEUKSR/DEUDSR或PKEU对应寄存器的值是否在合法范围内。确认单位是字节还是位。
    • AE(地址错误) :检查代码中的寄存器地址偏移量是否正确。是否尝试读取了只写寄存器(如PKEU的E/N内存,DEU的密钥寄存器)?
    • FIFO错误(IFO, OFO, IFU, OFU, IFE, OFE) :检查Slave模式下的数据流控制。是否在FIFO满时继续写?是否在FIFO空时继续读?DONE中断产生后输入FIFO是否已排空?
    • ERE(早期读错误) :是否在DEU加密过程中读取了DEUIV寄存器?
    • KPE(密钥奇偶校验错误) :检查DES密钥的奇偶校验位。很多软件生成的随机密钥不符合DES奇校验要求,需要手动调整。
  4. 检查中断控制寄存器(PKEUICR/DEUICR)

    • 确认你关心的错误是否被意外屏蔽了。如果错误被屏蔽,它不会在PKEUISR/DEUISR中置位,也不会拉高ERROR中断,但引擎仍可能HALT。
  5. 检查中断控制器

    • 确认SEC模块级别的中断在芯片的中断控制器(如MPC8360E的全局中断控制器)中是否已正确使能和配置。CPU可能收到了中断,但被更上层屏蔽。

5.3 高级调试技巧与性能考量

  • 使用HALT位作为“看门狗” :在你的任务调度循环中,定期(或在超时后)检查PKEUSR/DEUSR的HALT位。即使所有错误中断都被屏蔽,HALT位也能告诉你引擎是否已静默失败。这是一种防御性编程。
  • 理解“粘性”错误位 :PKEUISR/DEUISR的错误位不会自动清除。必须在处理完错误后,通过写中断控制寄存器对应位或写RI位来清除它们。否则,旧的错误标志会一直存在,干扰后续的错误判断。
  • Slave模式下的FIFO管理 :DEU的FIFO深度有限。在编写数据搬移循环时,最好通过查询DEUSR[IFL]和[OFL]来判断FIFO容量,实现简单的流控,避免溢出/下溢错误。对于大数据量,考虑使用DMA。
  • 从Slave模式迁移到Initiator模式 :对于持续的数据流加密(如网络数据包),强烈建议使用SEC的Initiator模式(描述符链)。该模式下,CPU只需设置好描述符(包含密钥、IV、数据地址、长度、模式等),SEC内部的DMA和调度器会自动处理所有EU的配置、数据搬运、中断管理,极大减轻CPU负担,并提高效率。此时,本文讨论的大部分寄存器操作都由硬件自动完成。

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值