MMU分析

mips结构的tlb(MMU)分析 一,基于mips架构的mmu(TLB)的分析 首先说一下和tlb有关的几个重要的寄存器: EntryHi:CP0寄存器号    10       包含了输入的关键字VPN2和记住当前活动的ASID EntryLo0-1:CP0寄存器号 2-3       包含了输出用到的关键字,以及标志位 PageMask:CP0寄存器号   5       配置映射页的大小 Index:CP 阅读详情
一、MMU是什么?
 
    MMU,英文名称为Memory Manage Unit, 中文可以为“内存管理单元”,或者“存储器管理单元”。MMU是硬件设备,它与virtual memory是紧密联系在一起的。
 
    看一下s3c2410 datasheet Appendix 1中关于ARM920T的介绍(因为s3c2410采用的是ARM920T的处理器)。对ARM9系列处理器有如下几种:
 

    --ARM9TDMI(ARM9TDMI Core)
    --ARM940T(ARM9TDMI core plus cache and protection unit)
    --ARM920T(ARM9TDMI core plus cache and MMU)

 
    可见ARM920T具备了MMU功能部件。而且还有cache。它采用了一种变形的Harvard架构,拥有16KB的Instruction cache和16KB的Data cache,MMU和cache有密切的联系,后面会谈到。
 
    总之,由于s3c2410这款SoC采用了ARM920T的处理器(处理器内核为ARM9TDMI,关于这些命名的区分在前面已经讨论过了),所以拥有了MMU和cache。有了这个硬件基础,软件上才可能使用这个功能。那么,现在的问题是,s3c2410拥有MMU,那么MMU到底有什么用呢?还是从历史发展的角度看一下。
 
二、从历史发展的角度看MMU的作用
 
    这一部分可结合蔡于清的讲解【网址: http://www.another-prj.com/viewthread.php?tid=28&extra=page%3D1】来看,下面的大部分内容转载此处,针对自己的理解做了一些扩充性说明。只是需要注意的是,在蔡于清此部分的讲解中,有几处小的错误,完成此部分的讲解后可以进行更正。
 
    MMU功能部件是与虚拟内存技术(virtual memory)紧密联系在一起的。
 
    第一阶段:最初,计算机内存很小,而且非常昂贵,大多数都是以KB为单位的。相应的,当时程序规模很小,不复杂,所以内存还是能够满足需求的。在看《Linkers and Loaders》的时候,也是从这个阶段讲解,不过此书的核心视角是从Linkers和Loaders的发展来看的。也就是,计算机刚刚出现时,还是比较简陋的,各种复杂的技术是伴随着人们需求的提高而出现的。把握住这一点,就可以从需求的角度入手探讨技术,可以分析它如何满足了这样的需求。通过这种分析,理解上就比较简单一些了。
 
    第二阶段:程序规模扩大,考虑到成本问题,出现了overlay技术,也就是内存覆盖策略。基本的原理就是把程序分割成许多称为“覆盖块”的片断。覆盖块0首先加载运行,结束时调用另一个覆盖块。覆盖块的调度是由OS来完成的,但是事先需要分割,这部分工作是程序员借助Linkers来完成的。但是毕竟枯燥,由此带来的开销也比较大。于是进入第三个阶段。
 
    第三阶段:出现virtual memory。 虚拟存储器的基本思想是程序,数据,堆栈的总的大小可以超过物理存储器的大小,操作系统把当前使用的部分保留在内存中,而把其他未被使用的部分保存在磁盘上。比如对一个16MB的程序和一个内存只有4MB的机器,OS通过选择,可以决定各个时刻将哪4M的内容保留在内存中,并在需要时在内存和磁盘间交换程序片段,这样就可以把这个16M的程序运行在一个只具有4M内存机器上了。而这个16M的程序在运行前不必由程序员进行分割。

    伴随着这种技术的出现,“virtual address,即VA”和“physical address, 即PA”也就出现了。一般来说,CPU看到的地址是VA,VA是有地址线来决定的。比如,s3c2410是32位的SoC,那么它的寻址空间为2^32=4GB,那么VA空间也就是4GB。但是在嵌入式系统中,物理存储器是不会有这么大的。现在这块s3c2410的实际内存SDRAM也就64MB,远远小于4GB。也就是说,VA是4GB,PA是64MB,PA的地址空间是VA地址空间的子集。既然PA没有VA那么大,而且CPU只能看到VA,那么CPU如何找到PA呢?这也正是MMU的基本作用之一,就是提供VA到PA的转换机制,除了硬件的支持外,软件上实际就是维护一张表,表中的内容是VA到PA的转换法则。由于有了MMU,那么就可以实现利用VA找到实际物理内存区域。
 
    现在讨论为什么要实现VA到PA的映射。就ARM而言,系统上电后,CPU的PC指向0x00000000或者0xffff0000,这是由CPU的设计者决定的。在这个位置,一般安排非易失性存储器地址空间,比如rom,flash等。但是flash等响应速度慢,这就称为提高系统性能的一个瓶颈。而sdram则具有很高的响应速度,为了提高系统运行速度,可以把flash中的应用程序下载到sdram中执行,也就是一个简单的loader的功能实现。这样就出现一个问题,ARM响应exception时,程序指针指向固定的VA,比如,假设发生了IRQ中断,那么PC执行0x00000018(如果是高端启动,则指向0xffff0018处。)但是此处仍然为非易失性存储器,也就是说,程序的一部分仍然在flash或者rom中执行。这时可以利用MMU,把sdram的地址映射到0x00000000起始的一片连续地址空间,而把原来flash映射到其他不相冲突的存储空间位置。例如,flash的地址范围0x00000000-0x00ffffff,sdram的地址范围0x30000000-0x31ffffff。那么可以把sdram映射到0x00000000-0x1fffffff(此处地址空间未被占用)。映射完成后,如果处理器异常,假设依然为IRQ中断,pc指向0x00000018,但是pc实际上是从物理地址0x30000018处读取指令。通过mmu的映射,可以实现系统运行的加速。这个地方也可以说明bootloader中常见的中断向量表的设置,为什么有些使用b,有些使用ldr了。【b的跳转空间只能是+-32M,而ldr可以大的多了。】
 
    在实际的应用过程中,还可能会把两片不连续的物理地址空间分配给sdram,而在os中,习惯上把sdram的空间连续起来,方便实现动态内存管理。通过mmu可以实现不连续的物理地址空间映射为虚拟地址空间。
 
    另外一个需求就是,实现不同的运行级别,那么一些关键的代码可以设定不被普通应用程序访问。这也是通过mmu控制访问权限来实现的。
 
    综上三个阶段所述,可见MMU的作用主要就是两个:
 
    · 实现VA到PA的映射(可以因此实现方便的动态内存管理)
    · 实现不同的访问权限。
 
三、结合s3c2410来分析MMU的几处硬件特点
 
    首先看看ARM920T的框图:
    可以验证前面的几个概念:
 
    ·位于中心的ARM9TDMI Processor Core发出的地址有两种,IVA和DVA,都是VA。其中I代表Instruction, D代表Data。也就是说,CPU核心看到的都是32bits的VA。
    ·Dcache、Icache、Dmmu、Immu看到的都是对应的MVA(modified virtual address),这个是比较复杂的地方,下面专门拿出这个来讲解。
    ·MMU处理后的输出地址都是对应的PA,通过AMBA Bus Interface连接到ASB总线上面。
 
    这样,从硬件上对地址的概念就比较清晰了。也可以很明显的看出MMU的功能:将VA转换成PA。但是现在存在的一个问题是,MVA是什么,为什么要用到MVA?
 
    可以看CP15协处理器的register 13。这个寄存器是进程识别寄存器,主要的操作如下:
 

Reading from CP15 register 13 returns the value of the process identifier. Writing CP15 register 13 updates the process identifier to the value in bits [31:25]. Bits [24:0] should be zero.

 
    寄存器的字格式为:
 
    很清晰,ProcID为7bits,剩下的25bits should be zero,也就是可以实现2^25=32M的地址对齐。从这个道理上讲,每个进程拥有32M的MVA地址空间,而最多支持的进程数为2^7=128个。这样,128*32M=4GB,正是全部的虚拟地址空间。但是,英文的datasheet上却并非如此,写的记录数字为64个进程,同样每个进程32M,怎么可能达到4GB?参看下图:
 
 
    我觉得上图中的63应该改为127。因为这个63处不可能对应4GB,而应该对应2GB。判断此处属于datasheet的错误。
 
    还有,这个procID是何时,有谁写入的?有谁来维护?根据推断,在bootloader阶段,只需要一个进程就可以了,所以,procID一直都是复位后默认的0,不需要改变。但是后面有了OS后,要想实现多进程,那么就需要对此维护了。所以procID的维护者是系统软件OS。在创建一个新进程的时候,要把进程号写入procID。
 
    另外,关于MVA部分的转换公式,实际上还是有疑问的。
 

Addresses issued by the ARM9TDMI core in the range 0 to 32MB are translated by CP15 register 13, the ProcID register. Address A becomes A + (ProcID x 32MB). It is this translated address that is seen by both the Caches and MMU. Addresses above 32MB undergo no translation.

 
    写成伪代码,可以参考《s3c2410完全开发》。
 

if VA < 32M then
        MVA = VA | (ProcID << 25)
else
        MVA = VA

 
    thisway.diy说利用PID来生成MVA的目的是为了减少切换进程时的代价:如果两个进程占用的VA有重叠,不进行上述处理的话,当进行进程切换时必须进行VA到PA的重新映射,这就需要重新建立页表,使无效cache和TLB等等,代价很大。但是如果进行上述处理的话,进程切换就省事多了:假设两个进程1、2运行时的VA都是0-32M,则它们的MVA分别是(0x02000000-0x03ffffff)、(0x04000000-0x05ffffff),前面看到的MMU、cache使用MVA而不是使用VA,这样就不必进行重建页表等工作了。
 
    但是这里带来的一个问题是,如果进程运行时的VA小于32M,那么根据PID的不同,可以达到4GB空间的任意部分,也就是,虽然可以避免运行VA小于32M时的不同进程的“撞车”,但是同时带来的是VA小于32M可能与VA大于32M的进程产生了“撞车”。这样不是更为普遍吗?现在从原理上还不能理解。翻看《ARM Architecture Reference Manual》,发现对于ARM核,如果采用MVA,那么进程切换实际上对应着Fast context switch extension,不知道原理是什么。对于研究bootloader来说,现在不设计到多进程,整个系统就是一个独立的单进程,PID就是默认的0x0。这个问题可能要后推了。
 
四、提出几个问题
 
    1、在vivi中为什么使用了MMU?是否可以不用?
 
    这个问题已经解决。实际上,在nand flash启动的情况下,vivi中可以不使用MMU。因为一是中断向量表是放在sram里,响应速度比sdram还要快。另外,在bootloader阶段,只有一个进程,不存在多进程的内存空间重叠的问题。也因为一个进程,所以单纯的PA就满足需求,没有必要用VA。开始时,也不需要区分访问权限。大量的工作,比如进程切换、权限访问等等,都是在EOS中处理的。所以,这种情况下,可以不使用MMU。我把vivi中关于MMU的部分去除,编译下载,可以正常引导内核启动,没有问题。
 
    那么,vivi为什么要开启MMU呢?原因也是比较简单的,就是追求系统运行的高效。因为s3c2410的Icache不受MMU的影响,而Dcache和write buffer则必须开启了MMU功能之后,才能使用。而使用Dcache和write buffer后,对系统运行速度的提高是非常明显的,后面还将通过实验来验证这一点。也就是说,在nand flash启动时,vivi使用了MMU,主要是为了获得Dcache和write buffer的使用权,借此提高系统运行的性能。
 
    2、使用了MMU,那么软硬件是如何分工协作的?
 
    这个基本搞清楚了,但是还有一个遗留问题。针对于s3c2410,可以分为如下几个阶段:
 
    · 第一阶段  软件准备
 
    MMU在软件上的实现过程,实际上就是一个查表映射的过程。建立页表(translation table)是MMU功能的重要的一步。页表就是内存的一块区域,由一个个固定格式的entry组成。其中每个entry对应一个VA到PA的转换,每一项的长度是一个word,还可以完成访问权限和缓冲特性的限定。在软件上,就是要把这个表填好。重映射就是修改相应的entry,改变了原来的映射规则,很简单。
 
    这步工作是要软件提前准备的。需要注意的是,明确如何找到这个页表。对于表的查找,需要知道表的基地址和偏移地址,在cp15的register 2用于保存页表的基地址,这样就可以查找到相应的PA了。
 
    · 第二阶段 硬件完成VA-MVA
 
    硬件根据ARM9TDMI发出的VA和CP15的register 13来自动生成MVA。
 
    · 第三个阶段
 
    硬件自动实现cache查询,如果没有,则根据cp15的register 2和MVA找到translation table中的entry,实现相应的PA转换,读取内存,然后根据cache算法更新cache。也就是说,这个阶段也是硬件实现的。不过软件上对cache要进行相应的管理,这个地方的算法相对还是比较复杂的。
 
    综上,对单进程而言,软件操作上就是维护translation table,并且处理好cache相关操作。
 
五、实验
 
    实验内容比较简单,综合了前面的串口实验,灯循环点亮实验,中断实验,nand flash实验,另外,加入了MMU功能。利用MMU功能的开启,观察灯循环点亮实验,如果开启了Dcache和write buffer,灯闪的速度明显快的多,几乎看不出间隔,而把其关闭,则还能够看出间隔。这还是在12MHz的前提下,还没有把PLL功能开启。如果把PLL功能开启,还需要进行相应的调整。
 
    源代码如下,完全仿照vivi的架构,另外,mmu部分基本是采用vivi的源代码,具体的分析留待vivi源代码分析时解决。其实,如果开启了mmu,cache和write buffer是否能够合理有效的使用还是一个问题。如果使用不当,带来的问题可能会比较奇怪,而且难以解决。在这个过程中,需要对照现有的较好的代码进行分析,总结规律,然后应用到自己的设计中去。
 
linux内核 kvm_mmu_page_fault 分析 此函数用于处理客户机(Guest)的页错误(Page Fault),是KVM内存管理单元(MMU)的核心逻辑之一。主要任务包括处理直接物理映射、MMIO访问、嵌套虚拟化错误和指令模拟。此函数是KVM处理客户机页错误的核心逻辑,涵盖从错误分类(MMIO、嵌套错误)到指令模拟的全流程,通过条件分支和硬件特性优化性能。 阅读详情

相关推荐

linux系统中详细分析MMU的具体实现

先来看一张图。

嵌入式技术开发 835

vivi开发笔记(十七):vivi与Linux kernel的参数传递情景分析(下)

原文地址:vivi开发笔记(十七):vivi与Linux kernel的参数传递情景分析(下) 作者:fglswh 下面进入Linux kernel部分,分析与bootloader参数传递对应的部分。       移植Linux需要很大的工作量,其中之一就是HAL层的编写。在具体实现上,HAL层以arch目录的形式存在。显然,该层需要与bootloader 有一定的约

hello world 711

别再让会议变‘回音壁’:手把手教你调优WebRTC的AEC3回声消除(附实战代码)

本文深入解析WebRTC的AEC3回声消除技术,提供从参数调优到声学环境适配的实战指南。通过诊断回声特征、解剖核心参数(如filter.length_blocks和delay_estimate_smoothing)以及应对特殊场景(如密闭空间与开放办公区),帮助开发者有效解决视频会议中的回声问题,提升语音通信质量。附有实战代码和调试工具,适合需要优化实时通信体验的开发者。

weixin_29220405的博客 172

内存管理单元——MMU

一、基本概念介绍 MMU是Memory Management Unit的缩写,中文名是内存管理单元,有时称作分页内存管理单元(英语:paged memory management unit,缩写为PMMU)。它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件。它的功能包括虚拟地址到物理地址的转换(即虚拟内存管理)、内存保护、中央处理器高速缓存的控制,在较为简单的计算机体系结构中,负责总线的仲裁以及存储体切换(bank switching,尤其是在8位的系统上)。 内存管理单元(MMU)的一个重要

weixin_43834468的博客 4593

使用 DeepSeek 配合 即梦AI 生成视频的详细教程

访问即梦AI官网,选择“AI作图”功能,将DeepSeek生成的提示词逐条粘贴至输入框,选择适配的模型(如“通用XL Pro”)和参数(如画幅比例、风格强度)1113。“我要制作一个关于普洱茶文化的宣传视频,请设计一个30秒的脚本,包含时间轴、画面描述、文案和分镜提示词,以表格形式输出。:云南古茶树群,清晨薄雾,金色晨光,露珠特写,国风山水画质感,16:9画幅,使用Nikon D850参数模拟513。:结合DeepSeek生成的知识点脚本与即梦AI的插画风格,制作科普动画211。

weixin_48995695的博客 3万+

vrep小车避障算法_V-REP 多车道巡线与避障

任务概要在给定的赛道中,实现多车道的避障和视觉巡线。避障算法没有限定,可使用人工势场、RRT等路径规划算法。车体大小、赛道信息以及参考资料在此处下载。完成情况已学习并能初步使用 V-REP Python Remote API 接口,实现 Python 与 V-REP 的功能交互。已实现基于视觉传感器的多车道巡线功能。已实现基于视觉传感器的多车道避障功能。V-REP Python Remote AP...

weixin_39692037的博客 1834

[嵌入式系统-42]:内存管理MMU与TLB-1-内存管理全方位概览

内存管理是指在计算机系统中有效地管理和利用内存资源的过程。在计算机系统中,内存是一种临时存储设备,用于存放运行中的程序和数据。内存管理的主要任务包括内存分配、内存释放、内存保护和内存优化等方面,旨在确保系统能够高效地利用内存资源,以支持程序的正常运行和系统的稳定性。内存分配:将系统中的可用内存分配给不同的程序或进程使用。内存分配通常通过操作系统的内存分配器来实现,根据程序的需求分配合适大小的内存块。内存释放:当程序不再需要某块内存时,需要将其释放回系统,以便其他程序可以继续使用。

文火冰糖(王文兵)的博客 1266

新版MQL语言程序设计:用vscode编写编译调试mt4和mt5程序

使用VScode搭建MT4与MT5开发环境,实现编辑编译调试统一。

超哥量化的博客 6872

【操作系统】第五章:虚拟内存(Part3:虚存管理的实现硬件MMU)

MMU-虚存管理硬件1. 什么是MMU2. MMU的产生3. MMU 作用4. MMU 工作过程5. MMU 的 TLB 1. 什么是MMU MMU是 Memory Management Unit 的缩写,即内存管理单元。 针对各种CPU, MMU是个可选的配件. MMU负责的是虚拟地址与物理地址的转换. 提供硬件机制的内存访问授权.(现代 CPU 的应用中,基本上都选择了使用 MMU) 现代的多用户多进程操作系统, 需要MMU, 才能达到每个用户进程都拥有自己的独立的地址空间的目标. 使用MMU, OS划

Chahot的博客 772

onnxruntime-gpu版本选择与CUDA环境配置实战指南

本文是onnxruntime-gpu版本选择与CUDA环境配置的实战指南。针对AI模型部署中常见的GPU无法调用问题,核心在于确保onnxruntime-gpu版本与系统CUDA Toolkit版本严格匹配。文章详细讲解了如何精准确定CUDA版本、查找官方对应关系、执行正确安装命令,并通过完整测试脚本验证GPU是否成功启用,最后提供了常见问题排查与生产环境调优建议。

weixin_29164091的博客 522

编程实践:寒武纪-LLM&VLM模型量化&部署

本文介绍了在MLU370-S4平台上对大模型(LLM/VLM)进行量化的两种方法:SmoothQuant和WeightOnly。以Qwen2-VL-2B模型为例,详细说明了两种量化方式的命令行参数配置,包括必须设置的per_channel选项和量化参数调整建议。量化完成后,提供了模型部署的具体命令示例,包含设备分配、端口设置、并行度等关键参数。文章强调在MLU370芯片上需要手动设置block_size,并指出两种量化方式只能二选一使用。配套资料已上传至百度网盘供参考。

微风❤水墨 507

vivi开发笔记(三):Makefile详解

原文地址:vivi开发笔记(三):Makefile详解 作者:piaoxiang 文章说明:calmarrow(lqm)原创 文章引自:http://piaoxiang.cublog.cn       在Linux下面,要分析一个项目,首先应该读Makefile。前面有了一定的Makefile基础,现在虽然还不能写复杂的Ma

wangjilebeishang的专栏 802

DTI-ALPS 指标计算(附代码),评估脑类淋巴系统功能

DTI-ALPS 指标计算(附代码),评估脑类淋巴系统功能

xxx 1051

linux MMU分析+s5pv210 ubot的mmu分析

由于csdn系统bug,写个笔记也要等人工审核(你有那么多审核员么)?所以MMU的原理请参考

laotang365的专栏 1307

基于图像形态学处理的交通灯检测识别matlab仿真

图像形态学处理是基于数学形态学的理论,利用结构元素(如矩形、圆形等)对图像进行处理,通过将结构元素与图像进行特定的逻辑运算,来提取图像中的目标特征、去除噪声、改善图像质量等。在交通灯检测识别中,主要利用交通灯的颜色、形状等特征,通过形态学操作突出这些特征,抑制背景和噪声干扰,从而实现对交通灯的准确检测和识别。图像采集与预处理采集:通过安装在车辆或道路上的摄像头获取交通场景图像。灰度化:将彩色图像转换为灰度图像,减少数据量,便于后续处理。

平时工作较为繁忙,私信消息一般晚上回复,谢谢大家~~ 160

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

u-boot mmu映射分析

参考:https://www.cnblogs.com/yangjiguang/p/7647801.html 一、映射过程详解 关于页表:ARMv6的MMU进行地址映射时涉及到两种页表,一级页表(first level page table)和二级页表(coarse page table)。 关于映射方式:映射方式有两种,段映射和页映射。段映射只用到一级页表,页映射用到一级页表和二级页表...

coolperl的博客 1981

android 蓝牙通讯demo

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

OpenRisc-40-or1200的MMU模块分析

引言 MMU(memory management unit),无论对于computer architecture designer还是OS designer,都是至关重要的部分,设计和使用的好坏,对性能影响比较大。 MMU,我觉得是硬件和软件配合最密切的部分之一,对于RISC CPU而言,更是这样。 前面,我们对or1200的整体memory hierarchy做了简单分析,了解了cache

Rill的专栏 5635

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

kvm.mmu_audit参数分析

<br />在kvm的参数中增加了如下参数,看看这个是什么功能<br /> <br /> kvm.mmu_audit= [KVM] This is a R/W parameter which allows audit<br />   KVM MMU at runtime.<br />   Default is 0 (off)<br /> <br /> <br />分析对应打开操作:<br />ret = register_trace_kvm_mmu_audit(kvm_mmu_audit, NULL);<b

jemmy858585的专栏 957

2440MMU_Init.c 简要分析

北京蓝海微芯S3C2410开发板启动源码中MMU初始化部分分析 void MMU_Init(MMU_Table table[]) { //========================== IMPORTANT NOTE ========================= //The current stack and code area can't be re-mapped in thi

bingxx11的专栏 3227

《转》 MMU代码分析(作者:wogoyixikexie@gliet)

<br />MMU代码分析(作者:wogoyixikexie@gliet)<br />    ——以前我一直误以为MMU在OAL才开的,在bootloader是不开的,真是大错特错。这个也不怪我,因为有很多书都说在bootloader阶段是不开的。现在看看代码真是感慨万千。<br />————————————————————————<br />    这两天,重新看了MMU和cache,对它有了一点了解,现在再把疑问放到论坛上来,希望大家帮忙(前几天参与押宝,现在分数还没有回来,没有分发帖了,以后有分再补回

newstime的专栏 1798

S3C2410 MMU_Init函数简要分析

转自:http://blog.youkuaiyun.com/tin39/article/details/5112867 北京蓝海微芯S3C2410开发板启动源码中MMU初始化部分试分析 void MMU_Init(MMU_Table table[]) {  //========================== IMPORTANT NOTE =========================

春风得意,马蹄仍急;少年豪情,一笑难回。 872

MMU代码分析(作者:wogoyixikexie@gliet)

MMU代码分析(作者:wogoyixikexie@gliet)    ——以前我一直误以为MMU在OAL才开的,在bootloader是不开的,真是大错特错。这个也不怪我,因为有很多书都说在bootloader阶段是不开的。现在看看代码真是感慨万千。————————————————————————    这两天,重新看了MMU和cache,对它有了一点了解,现在再把疑问放到论坛上来,希

gooogleman#foxmail.com 5553
上一篇: 我的一次创业经历--分享给希望创业的大学生们
下一篇: 关于wince注册表
menuconfig
博客等级 码龄19年 713粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值