基于S3C44B0微处理器的uClinux内核引导剖析

S3C44B0+Uboot1.1.6+uClinux2.6.9 1 Uboot的移植 1.1 Merge代码 1.2 编译工具 1.3 malloc返回0 1.4 tftp error:packet too big 2 uCLinux2.6.9移植 2.1 Patch源码 2.2 创建vendors s3c44b0 2.3 根文件系统 2.4 建立根文件系统时遇到的问题 2.5 中断向量地址 2.6 解压缩内核 2.7 增加串口驱动 2.7.1 增加串口文件 2.7.2 修改配置文件 2.7.3 Console调用过程 3 Uboot启动uClinux 立即下载
基于S3C44B0微处理器的uClinux内核引导剖析
姜江
Blog:http://blog.youkuaiyun.com/jznsmail
摘 要:本文采用三星公司的S3C44B0微处理器,对uClinux操作系统内核的引导过程进行了剖析。
关键字:S3C44B0X;uClinux;嵌入式系统;内核引导
 
1 前言
伴随着微电子的发展,用于嵌入式设备的处理器速度越来越快,功能也越来越强大。三星公司生产的S3C44B0微处理器,采用的是ARM7TDMI内核。该内核因为有着功耗小、成本低等特点,因此非常适合作为移动手持终端的处理器核心。Linux操作系统因为它的开放性,使得它不断的被应用到各个领域。在嵌入式领域同样也出现了各种各样的Linux变体,最常用的是uClinux。也正是因为uClinux操作系统支持不带MMU单元的ARM处理器,因此该系统可以对S3C44B0微处理器有很好的支持。
在嵌入式系统开发中,第一个部分便是系统的引导。而系统的引导过程是通过BootLoader来完成的。BootLoader程序是与硬件紧密相关的一段代码,而且编写的时候比较复杂,它主要的功能是初始化微处理器以及周边的硬件资源,并且引导操作系统的启动。下面我将以S3C44B0微处理器来作为例子,对uClinux操作系统内核的引导过程进行一个剖析。
 
2 BootLoader程序概念
简单的说Boot Lodaer就是在操作系统内核运行之前运行的一段小程序,通过这段小程序,可以初始化硬件设备、建立系统的内存空间映射图,从而将系统的软硬件环境设置成一个适合的状态,以便为最终调用操作系统内核准备好正确的环境。最终,BootLoader把操作系统内核映象加载到RAM中,并将系统控制权传递给它。
 
2.1 典型的BootLoader程序框架
操作系统角度来说,Boot Loader的总目标就是正确的调用内核来执行。
由于Boot Loader的实现依赖于CPU的体系结构,因此大多数Boot Loader都分为Stage1和Stage2两大部分。依赖于CPU体系结构的代码,例如设备初始化代码等,通常都放在Stage1中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而Stage2通常用C语言来实现,这样可以实现更加复杂的功能,而且代码会具有更好的可读性和可移植性。
Boot Loader的Stage1通常包括如下步骤:
1)     硬件设备初始化
2)     为加载Boot Loader的Stage2准备RAM空间
3)     复制Boot Loader的Stage2到RAM空间中
4)     设置好堆栈
5)     跳转到Stage2的C入口点
Boot Loader的Stage2通常包括如下步骤:
1)  始化本阶段要使用的硬件设备
2)  检测系统内存映射(Memory Map)
3)  将Kernel映象和根文件系统映象从FLASH上读取到RAM空间中
4)  为内核设置启动参数
5)  调用内核
 
2.2 系统内存组织
由于嵌入式设备具有很好的制定性,因此通常硬件环境会变的千差万别。就算是用户使用了相同的处理器芯片,但是也很有可能因为外围设备电路设计的不同,而存在差异。对于BootLoader程序来说,存储设备的与处理器的连接方式,与其息息相关。对于我们采用的S3C44B0微处理器来说,在系统加电之后,指令指针是指向0x00000000的,也就是说系统是从0x00000000开始之行。正是因为这个原因,通常这个地址空间我们会安排给FLASH存储器。这样我们可以将BootLoader启动代码以及我们之后将会要启动的uClinux操作系统映像烧写到Flash里。对于RAM地址空间,S3C44B0芯片将其设定为从0x0C000000到0x0FFFFFFF一共64MB的范围里。我们可以通过设定存储器控制寄存器来重新设定RAM的大小。例如我们试验采用的存储设备安排如下:
0x00000000 – 0x003FFFFF 4MB Flash
0x0C000000 – 0x0C7FFFFF 8MB RAM
通常来说对于系统的引导和操作系统的启动,可以完全都在Flash中进行,但是Flash存储器的速度相对于RAM来说会慢很多,因此出于速度上的考虑,我们通常会将启动代码和uClinux操作系统的内核映像文件拷贝到RAM中之行。
下面我将对典型的BootLoader程序框架进行分析。
 
2.3 Stage1阶段
该阶段的主要工作是完成对系统中断向量的设置,初始化微处理器内部寄存器,初始化堆栈,初始化RAM地址空间,并且将Stage2部分的C代码拷贝到RAM空间的指定地点,然后跳转到C代码入口点继续执行。对于这段代码来说,做的都是一些准备工作,因此为了提高效率,这段代码通常都是使用汇编语言来完成的。下面我将结合具体的代码来分析一下Stage1的启动过程。
1)设置中断向量
设置S3C44B0处理器定义的8种系统中断的中断向量地址。这八种系统中断分别是复位中断、未定义指令中断、软件中断、指令预取异常中断、数据异常中断、地址异常中断、IRQ中断和FIQ中断。这8个中断通常是通过无条件跳转的方式来实现的。具体的代码如下。
__entry :
              b       ResetHandler                /* Reset vector          */
              b       HandlerUndef                /* Undefined instruction */
              b       HandlerSWI                       /* SWI                   */
              b       HandlerPabort                /* Prefetch abort        */
              b       HandlerDabort                     /* Data abort            */
              b       .                                 /* Address exception     */
              b       HandlerIRQ                        /* IRQ                   */
              b            HandlerFIQ                        /* FIQ                   */
 
2)初始化微处理器内部寄存器
这段代码主要是要完成硬件部分的初始化,包括关闭中断响应、初始化微处理器通用端口、设置CPU频率等操作。不过需要注意的是,在进行硬件初始化之前需要将微处理器的运行状态转换到SVC模式下。
MRS              a1,CPSR                          /*; Pickup current CPSR*/
       BIC         a1,a1,#MODE_MASK           /*; Clear the mode bits*/
       ORR              a1,a1,#SUP_MODE                     /*; Set the supervisor mode bits*/
       ORR              a1,a1,#LOCKOUT                /*; Insure IRQ and FIQ intr are locked out*/
       MSR              CPSR_cxsf,a1                     /*; Setup the new CPSR*/
3)初始化系统RAM空间
这个部分的工作主要是为之后启动代码和内核映像的拷贝操作做准备,并且也为之后的C代码的执行初始化堆栈。这部分的工作主要可以分成两个部分来处理。首先,根据系统配置的存储器特性来初始化相关的存储器控制寄存器。在我们使用的S3C44B0处理器中,存储空间被分成了BANK0-BANK7一共8个块,分别由BANKCON0-BANKCON7控制各个块存储器的读写时钟和片选时钟等信号参数。具体代码如下:
ldr   r0,=rBANKCON0
    ldr   r1,=0x700   
    str   r1,[r0]
       
    ldr   r0,=rBANKCON1
       ldr   r1,=0x700     /* 0x7ffc */
       str   r1,[r0]      
             
       ldr   r0,=rBANKCON2
       ldr   r1,=0x700    /* 0x7ffc */
       str   r1,[r0]      
             
       ldr   r0,=rBANKCON3
       ldr r1,=0x7568
       str   r1,[r0]      
      
       ldr   r0,=rBANKCON4
       ldr   r1,=0x700    /* 0x7ffc */
       str   r1,[r0]     
        
       ldr   r0,=rBANKCON5
       ldr   r1,=0x700   /* 0x7ffc */
       str   r1,[r0]
            
       ldr   r0,=rBANKCON6
       ldr   r1,=0x18008
       str   r1,[r0]
                   
       ldr   r0,=rBANKCON7
       ldr   r1,=0x18000
       str   r1,[r0]
                   
       ldr   r0,=rREFRESH
       ldr   r1,=0xac03e1
       str   r1,[r0]      
      
       ldr   r0,=rBANKSIZE
       ldr   r1,=0x16
       str   r1,[r0]      
      
       ldr   r0,=rMRSRB6
       ldr   r1,=0x020
       str   r1,[r0]      
      
       ldr   r0,=rMRSRB7
       ldr   r1,=0x020
       str   r1,[r0] 
初始化RAM空间的第二个部分就是初始化连接脚本文件中指定的需要清0的地址空间,将该断地址空间的内容清0。该部分地址空间主要是用来存放C语言代码中的全局变量等内容的。实现代码如下:
LDR              a1,=Image_ZI_Base       /* Pickup the start of the BSS area */    
              MOV             a3,#0                                  /* Clear value in a3 */                    
              LDR              a2,=Image_ZI_Limit      /* Pickup the end of the BSS area */      
              CMP              a1,a2                                                          
              BEQ        move_data                                                      
clear_loop :                                                                 
              STR        a3,[a1],#4                            /* Clear a word, a1 += 4 */               
              CMP              a1,a2                                   /* end of ZI ? */                        
              BNE        clear_loop
 
4)为Stage2的C语言代码的执行准备必要的堆栈
因为在Stage2阶段一般都是采用C语言代码来完成的,因此必须在使用C语言代码之前先建立起必要的堆栈信息。通常为了避免堆栈数据被执行代码破坏,通常都是放在RAM的高端地址,并且使得堆栈指针的增长方向是向下增长的。
5)将初始化代码拷贝到RAM中,并且跳转到RAM中执行。因为在我们采用的S3C44B0微处理器里对于FLASH和RAM地址空间是使用的统一编址的,因此我们可以直接使用一个简单循环来完成拷贝。
           ldr          r3, =0x10000         /* 64K Bytes */
              ldr        r2, =0xc700000
              ldr          r1, =0                         
next :            
              ldr          r0,[r1],#4
              str          r0,[r2],#4
              cmp        r1,r3
              bne         next
 
6)跳转到C代码执行(即Stage2阶段)
这个过程是直接给指令指针赋值于跳转的C代码的入口地址,在我们的试验中该入口地址是Main。
LDR              pc,=Main   
 
2.4 Stage2阶段
该阶段的代码主要使用C语言来实现的。该阶段的工作主要是建立开发板与宿主机之间的通信,加载uClinux内核映像文件和配置内核启动参数,并且启动内核。
嵌入式设备与宿主机的通讯方式有多种,最常用的是使用串口方式进行数据交换。本试验采用的S3C44B0微处理器提供了两个UART口,因此我们可以任选其中一个来初始化并且使用它来与宿主机交互。对于串口的初始化主要是波特率、奇偶校验、停止位、数据位等内容。
对于串口的波特率和波特因子的计算采用如下公式
Iubrd =((int(mclk/16 / baud + 0.5) – 1)
mclk是频率、baud为波特率
 
2.4.1 检测内存
       该部分的功能主要是检测系统在进行硬件初始化的时候是否发生了内存映射错误,即是否物理地址是否被映射到不存在的地址空间。通常是使用读写方式来检测的,即以内存页为单位,在每个页头进行读写操作,比较读写结果。因为S3C44B0处理器并不支持内存映射,因此我们在Stage2过程中并没有包含该部分功能函数。
 
2.4.2 加载uClinux内核映像
该过程其实只是一个从Flash的指定位置(该位置是uClinux烧写的起始地址)拷贝到RAM中指定的地址空间里。在拷贝之前必须要为uClinux的全局变量结构,即启动参数、内核页表、RAM的页目录等信息预留一定的空间。如果我们将FLASH和RAM看成连在一起的线性地址,则系统的空间分配会如下图:

......
Boot
初始化代码
uClinux
未用
中断向量表
初始化映像代码
启动参数
内核映像
未用
堆栈

 
2.4.3 配置内核启动参数
       我们采用的uClinux是2.4.x内核版本,该版本的内核支持参数启动过程。在嵌入式系统中,启动参数的传入主要是依靠bootloader程序向标记列表(tagged list)的相关域中填写相应的值来完成的。
 
2.5 uClinux内核引导
       当我们初始化完毕uClinux的启动参数之后,控制权就可以交给uClinux内核了,uClinux系统调用内核解压函数(decompress_kernel)来对上一个阶段拷贝的uClinux内核在RAM空间里进行解压(当然如果系统内核在建立的时候没有配置成压缩格式,则解压过程略去)。在解压完毕后,跳转到内核调用函数(call_kernel),该函数实际上执行的是start_kernel(),这个函数包含了有关处理器初始化、中断初始化、进程初始化等操作。最后,将控制权完全的交与uClinux操作系统来执行。
       伪处理过程如下:
       IF(启动参数正确)
              CALL decmporess_kernel()
              CALL call_kernel()
       ELSE
              启动失败
       decompress_kernel()
       {
              解压内核映像
}
call_kernel()
{
       ...
       start_kernel()
       ....
}
 
3 总结
       本文是对S3C44B0的启动过程进行了一次分析,启动部分的代码可以说是嵌入式设备开发比较重要的部分。而且该部分的处理工作往往又比较麻烦,因此在这里我只是想起到抛砖引玉的作用。因为成文时间比较仓促,难免有错误,请大家批评指正。
  
uclinux学习心得,总结了s3c44b0学习得大部分细节 此文档是我今年上半年学习s3c44b0时的所有总结,裸机程序编写 uclinux移植 内核编译 驱动开发 应用程序编写 QT环境编译等等 是我半年的心血 我个人强力推荐 立即下载

相关推荐

ARM7-S3C44B0-CPU板使用说明书

ARM7-S3C44B0-CPU板使用说明书

基于S3C44B0微处理器的uClinux内核引导剖析(转)

基于S3C44B0微处理器的uClinux内核引导剖析基于S3C44B0微处理器的uClinux内核引导剖析姜江E-mail:jznsmail@tom.comBlog:http://blog.youkuaiyun.com/jznsmail摘...

cuankuangzhong6373的博客 419

uclinux-44b0 补丁文件

基于44b0开发板的uclinux补丁文件。 基本适用于公板44B0开发板

如何将uclinux移植到44b0开发板

<br /><br />    从接触到成功,经过了一个礼拜了,查过看过的资料很多,但好多的都是不全面的,而且有些还把些重要的步骤省略了,使我走了很多的弯路,不过最可耻的是,有 些书籍上的资料程序是乱抄来的,真是害人不浅呀,我觉得既然觉得要把东西贡献出来就应该些的更全面些,好让初学的兄弟们能少走些弯路,也别影响到他们的信 心了。我决定把自己的经验写出来是因为我也是忙忙百度中过来的人。我将写下自己所知道的东西,尽量来让大家成功完成自己的事。 <br />  好了,现在我就开始说uclinux的移

dasheng_604的专栏 881

uclinux在44b0上的移植(学习uclinux的好资料)

uclinux在44b0上的移植(学习uclinux的好资料)

基于ARM7TDMI内核的S3C44B0异常处理分析

介绍了ARM7TDMI的7种工作模式及各种工作模式下处理器的基本功能、适用的条件以及在嵌入式系统设计中的重要性。详细分析了复位、快速中断和普通中断的编程要点以及在嵌入式程序设计中的作用,并结合S3C44B0示例程序分析了CPU对异常处理的方法。

uclinux在44B0上的移植

uclinux终于在armsys-c上运行起来了boot用的是立宇泰bootloader 1.3.1uclinux用的是立宇泰的uclinux_armsys_20051111,这个版本已打过补丁,不用任何修改,直接按照编译步骤,把config_main,(把用户自定义内核、自定义用户配置选上),conifg_kernel,config_user, load上,然后按照编译步骤,即可产生

HP Studio 2290

S3C44B0系列中文手册 S3C44B0系列中文手册 S3C44B0系列中文手册

S3C44B0系列中文手册 S3C44B0系列中文手册 S3C44B0系列中文手册

S3C44B0 调试笔记—uClinux

导读:   上班时间很少有机会搞这些东西,基本上都是下班在家里搞,不过在公司写写文挡还是可以的。调试uClinux也是断断续续进行的。以前根本没接触过 linux,搞起来可真是头都要大了。虽说到最后调通比前面耗时少很多,主要原因是网上很多参考资料。但个人感觉这部分难度要更大一些。   接着前面的说吧,编译出一个uClinux的内核出来,就必须在linux环境下,windows下是编译不了的

yingfox的专栏 1901

华为云CodeHub代码托管

什么是代码托管 代码托管(CodeHub)是面向软件开发者的基于Git的在线代码托管服务,是具备安全管控、成员/权限管理、分支保护/合并、在线编辑、统计服务等功能的云端代码仓库,旨在解决软件开发者在跨地域协同、多分支并发、代码版本管理、安全性等方面的问题。 代码托管具有以下特性 · 在线代码阅读、修改、提交,随时随地开发,不受地域限制。 · 在线分支管理,包含分支新建、切换、合并,实现多分支并行开发,效率高。 master分支:最为稳定,功能比较完整,随时可发布的代码。 develop分支:用于平时开

LUJINYUANA的博客 1万+

LaTeX伪代码字体大小调整全攻略:从algorithm到algorithm2e的实战技巧

本文详细介绍了在LaTeX中调整伪代码字体大小的全面技巧,涵盖algorithm、algorithmicx和algorithm2e等主流算法包的使用方法。从基础命令到高级配置,帮助用户解决学术论文和技术文档中的伪代码排版问题,提升算法展示的专业性和可读性。特别针对不同期刊格式要求,提供了实用的字体调整方案。

weixin_29297127的博客 437

【STM32】 ADC 完全指南:从模拟信号采样量化到五大架构原理

本文系统介绍ADC核心概念与五大主流架构。模拟信号具时间与幅值连续性,需经采样(满足奈奎斯特准则防混叠)、量化(引入±1/2LSB误差,SNR≈6.02N+1.76dB)、编码三步转为数字信号。重点解析Flash(并行高速但受限于比较器数量)、SAR(逐次逼近,低功耗适合MCU如STM32)、双积分(高精度抗工频,用于万用表)、流水线(高速吞吐)及Σ-Δ(高分辨率,靠过采样与噪声整形)五类架构原理、优缺点与应用场景。强调分辨率≠精度,选型本质是速度、精度、功耗与面积的权衡。

专注后端与底层技术,分享实战干货与学习笔记,梦想进入字节跳动,步履不停,热爱不止。 484

AWR1642+DCA1000EVM 不使用mmWave Studio软件采集原始ADC数据 Timeout问题汇总

DCA1000 EVM Timeout问题汇总

Jesy_Hsu的博客 1476

嵌入式:2.STM32底层基础(存储、寄存器、时钟、总线、GPIO、寄存器点灯)

存储系统用来存放程序、数据、设备状态,核心三大作用:存放程序代码、保存运行时数据(全局、局部、栈、堆)、数据持久化(比如W25Q64 Flash,可以搭配文件系统)。

2401_86731574的博客 348

STM32 cubeMX配置串口重定向

这篇文章主要讲解什么是串口重定向,为什么要串口串口重定向。使用printf函数和上位机通信是非常的方便的。希望大家都能够掌握。

m0_49476241的博客 4572

2024年11月架构设计师案例分析真题回顾,附参考答案、解析及所涉知识点(二)

软考高级系统架构设计师考试包含三个科目:信息系统综合知识、案例分析和系统架构设计论文。考试形式为机考。本文主要回顾2024年下半年(2024-11-10)系统架构设计师考试上午第二科案例分析的题目,同时附带参考解答、解析和所涉知识点。

一几文的编程学习笔记。 1660

基于STM32的智能浇花系统

本文设计基于STM32F103C8T6的智能浇花系统,集成DHT11、YL-69、MQ-135、GL5528四类传感器,实现温湿度、土壤湿度、CO₂浓度与光照的实时监测。系统支持自动、手动、远程三模式联动控制,通过ESP8266-01S以MQTT协议上云,配合手机APP实现数据可视化与远程指令下发。硬件采用多通道ADC采样、继电器驱动与OLED显示,软件实现精准时序控制与双向通信。测试表明系统稳定可靠,完整覆盖“感知—控制—云联”IoT全链路,具备高扩展性与工程实践价值。

weixin_45732499的博客 171

液滴碰撞壁面的过程背景论文——bouncing反弹,spreading扩展,splashing飞溅。铺展过程介绍。还存在很多未解之谜。

【1993-德国-Phenomena of liquid drop impact on solid and liquid surfaces】液滴碰撞壁面的过程背景——bouncing反弹,spreading扩展,splashing飞溅。还存在很多未解之谜。还存在很多未解之谜。不同液滴形状碰撞过程。

qq_15963745的博客 199

35ms 抗量子握手:ESP32-S3 跑通 ML-KEM-768

ML-KEM(Module-Lattice-based Key Encapsulation Mechanism)基于格密码,是 NIST 2024 年正式发布的 FIPS 203 标准。选 768 参数级(而不是更低的 512)是因为它被广泛视为"长期安全"档位——CATAPULT 等行业联盟也推荐 IoT 长寿命设备直接上 768。密钥交换的抗量子性。现有 IoT 设备大量使用 ECDH,量子计算机(Shor 算法)一旦可用,ECDH 直接失效。

嵌入式单片机实验室 220

第十届MathorCup高校数学建模挑战赛-B题:养老服务床位需求预测与运营模式研究

当养老床位数增加时存在的商机,提出了相应的养老服务床位的运营商业模式。就业的可能性,建立多目标规划模型,尽可能同时满足三方面的要求。务床位的需求、制定合理的养老服务床位发展规划,是构建和谐社会、幸福社会。问题一的床位需求与市场类型的分类结果,查找关于国内养老院的相关数据,探。求,又能持续发展养老事业,同时还能促进社会就业的养老服务床位运营的商业。养老服务床位数的增加能够带来的就业方面因素的影响,并对这些因素进行一个。你们的模型及其结论为科学依据,对政府管理部门针对养老床位规划提出合理的。

getusushu的博客 1139

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

网口ps端--基础知识--调试(1)--deepseek

你现在卡住,是因为这每一层(硬件、驱动、lwIP 协议、IP 地址)中,只要有一层不对,网口就不通。物理层:看灯。灯亮说明线没问题,PHY 没死。MAC 驱动层:看串口打印。有没有打印出Link Speed?如果卡在自协商,说明你的 PHY 驱动还没配好。lwIP 协议层:如果底层通了,IP 也配对了,你调用udp_recv注册了回调函数,当电脑发来 UDP 包时,lwIP 会自动把数据包拆开,送到你的回调函数里。你之前一直在改,就是一直在死磕第 1 层和第 2 层。

AlibabaApple的博客 99

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

S021D-基于STM32单片机自动追光系统(舵机)【Proteus仿真+Keil程序+原理图】

设计以STM32单片机、四路GL5516光敏电阻、两路SG90舵机、OLED、按键搭建双轴追光云台系统。支持手动/自动模式切换,按键可调节追光灵敏度并保存至FLASH;自动模式依靠四路光敏采集光照差值计算方位,驱动舵机跟踪光源,OLED实时显示云台角度与工作状态。

51单片机实物制作DIY设计 185

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: 透过汇编另眼看世界之DLL导出函数调用
下一篇: Sun将Solaris机器上运行Linux促开源发展
stylehack
博客等级 码龄19年 0粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值