热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

基于MTD的NAND驱动开发、K9F1G082Kpage、Yaffs2FilesSystem

转载:http:hi.baidu.comcui1206item1d4119e376132513585dd886基于MTD的NAND驱动(linux-2.6.22.10内核),目前已

times new roman", times; font-size: 18px;‘>转载:http://hi.baidu.com/cui1206/item/1d4119e376132513585dd886

 

times new roman", times; font-size: 18px;‘>基于MTD的NAND驱动(linux-2.6.22.10内核),目前已可以在该驱动的支持下跑cramfs和jffs2文件系统,另外,该驱动也可以同时支持small
page(每页512 Byte)和big page(每页2048
Byte)两种NAND芯片。在此整理一下与NAND驱动相关的概念,结构体,驱动框架和流程,同时分析一下基于MTD的NAND驱动的部分函数,尤其是其中的nand_scan()函数。(涉及到具体NAND芯片时,若不做说明,将以small
page的NAND芯片为例。) 


MTD
驱动程序是专门针对嵌入式Linux的一种驱动程序,相对于常规块设备驱动程序(比如PC中的IDE硬盘)而言,MTD驱动程序能更好的支持和管理闪存设备,因为它本身就是专为闪存设备而设计的。 

times new roman", times; font-size: 18px;‘>具体地讲,基于MTD的FLASH驱动,承上可以很好地支持cramfs,jffs2和yaffs等文件系统,启下也能对FLASH的擦除,读写,FLASH坏块以及损耗平衡进行很好的管理。所谓损耗平衡,是指对NAND的擦写不能总是集中在某一个或某几个block中,这是由NAND芯片有限的擦写次数的特性决定的。 
times new roman", times; font-size: 18px;‘>总之,在现阶段,要为FLASH设备开发Linux下的驱动程序,那么基于MTD的开发将几乎是省时又省力的唯一选择! 

times new roman", times; font-size: 18px;‘>一、NAND和NOR的区别 

times new roman", times; font-size: 18px;‘>Google “Nand
Flash和Nor Flash的区别”。 


简单点说,主要的区别就是: 

times new roman", times; font-size: 18px;‘>1、
NAND比NOR便宜;NAND的容量比NOR大(指相同成本);NAND的擦写次数是NOR的十倍;NAND的擦除和写入速度比NOR快,读取速度比NOR稍慢; 


times new roman", times; font-size: 18px;‘>2、
NAND和NOR的读都可以以字节为单位,但NAND的写以page为单位,而NOR可以随机写每一个字节。NAND和NOR的擦除都以block为单位,但一般NAND的block比NOR的block小。另外,不管是NAND还是NOR,在写入前,都必须先进行擦除操作,但是NOR在擦除前要先写0; 


times new roman", times; font-size: 18px;‘>3、
NAND不能在片内运行程序,而NOR可以。但目前很多CPU都可以在上电时,以硬件的方式先将NAND的第一个block中的内容(一般是程序代码,且也许不足一个block,如2KB大小)自动copy到ram中,然后再运行,因此只要CPU支持,NAND也可以当成启动设备; 


times new roman", times; font-size: 18px;‘>4、
NAND和NOR都可能发生比特位反转(但NAND反转的几率远大于NOR),因此这两者都必须进行ECC操作;NAND可能会有坏块(出厂时厂家会对坏块做标记),在使用过程中也还有可能会出现新的坏块,因此NAND驱动必须对坏块进行管理。 


times new roman", times; font-size: 18px;‘>二、内核树中基于MTD的NAND驱动代码的布局 

times new roman", times; font-size: 18px;‘>在Linux内核中,

times new roman", times; font-size: 18px;‘>MTD源代码放在linux-2.6.22.10/driver/mtd目录中,该目录中包含chips、devices、maps、nand、onenand和ubi六个子目录。 

times new roman", times; font-size: 18px;‘>其中只有nand和onenand目录中的代码才与NAND驱动相关,不过nand目录中的代码比较通用,而onenand目录中的代码相对于nand中的代码而言则简化了很多,但顾名思义就可以知道,它仅仅适用于只使用一块NAND芯片的系统。因此,除非你能确定你的系统只使用一块NAND芯片,而且将来永远也不会扩展,否则就不要使用onenand中的代码。 

times new roman", times; font-size: 18px;‘>因此,若只是开发基于MTD的NAND驱动程序,那么我们需要关注的代码就基本上全在linux-2.6.22.10/drivers/mtd/nand目录中了,而该目录中也不是所有的代码文件都与我们将要开发的NAND驱动有关,除了Makefile和Kconfig之外,其中真正与NAND驱动有关的代码文件只有6个,即: 

times new roman", times; font-size: 18px;‘>1、
nand_base.c: 

定义了NAND驱动中对NAND芯片最基本的操作函数和操作流程,如擦除、读写page、读写oob等。当然这些函数都只是进行一些default的操作,若你的系统在对NAND操作时有一些特殊的动作,则需要在你自己的驱动代码中进行定义,然后Replace这些default的函数。 

times new roman", times; font-size: 18px;‘>2、
nand_bbt.c: 

定义了NAND驱动中与坏块管理有关的函数和结构体。 

times new roman", times; font-size: 18px;‘>3、
nand_ids.c: 

定义了两个全局类型的结构体:struct
nand_flash_dev nand_flash_ids[ ]和struct nand_manufacturers nand_manuf_ids[
]。其中前者定义了一些NAND芯片的类型,后者定义了NAND芯片的几个厂商。NAND芯片的ID至少包含两项内容:厂商ID和厂商为自己的NAND芯片定义的芯片ID。当NAND驱动被加载的时候,它会去读取具体NAND芯片的ID,然后根据读取的内容到上述定义的nand_manuf_ids[
]和nand_flash_ids[
]两个结构体中去查找,以此判断该NAND芯片是那个厂商的产品,以及该NAND芯片的类型。若查找不到,则NAND驱动就会加载失败,因此在开发NAND驱动前必须事先将你的NAND芯片添加到这两个结构体中去(其实这两个结构体中已经定义了市场上绝大多数的NAND芯片,所以除非你的NAND芯片实在比较特殊,否则一般不需要额外添加)。值得一提的是,nand_flash_ids[
]中有三项属性比较重要,即pagesize、chipsize和erasesize,驱动就是依据这三项属性来决定对NAND芯片进行擦除,读写等操作时的大小的。其中pagesize即NAND芯片的页大小,一般为256、512或2048;chipsize即NAND芯片的容量;erasesize即每次擦除操作的大小,通常就是NAND芯片的block大小。 


times new roman", times; font-size: 18px;‘>4、
nand_ecc.c: 

定义了NAND驱动中与softeware
ECC有关的函数和结构体,若你的系统支持hardware ECC,且不需要software
ECC,则该文件也不需理会。 


5、
nandsim.c: 

定义了Nokia开发的模拟NAND设备,默认是Toshiba
NAND 8MiB 1,8V 8-bit(根据ManufactureID),开发普通NAND驱动时不用理会。 


times new roman", times; font-size: 18px;‘>6、
diskonchip.c: 

定义了片上磁盘(DOC)相关的一些函数,开发普通NAND驱动时不用理会。 

times new roman", times; font-size: 18px;‘>除了上述六个文件之外,nand目录中其他文件基本都是特定系统的NAND驱动程序例子,但本人看来真正有参考价值的只有cafe_nand.c和s3c2410.c两个,而其中又尤以cafe_nand.c更为详细,另外,nand目录中也似乎只有cafe_nand.c中的驱动程序在读写NAND芯片时用到了DMA操作。 

times new roman", times; font-size: 18px;‘>综上所述,若要研究基于MTD的NAND驱动,其实所需阅读的代码量也不是很大。 

times new roman", times; font-size: 18px;‘>另外,在动手写NAND驱动之前,也许需要读一下以下文档: 
times new roman", times; font-size: 18px;‘>1、 Linux MTD
源代码分析: 

该文档可以让我们对MTD有一个直观而又相对具体的认识,但它似乎主要是针对NOR
FLASH的,对于实际开发NAND驱动的帮助并不是很大。 

2、
MTD NAND Driver Programming Interface: 

http://www.aoc.nrao.edu/~tjuerges/ALMA/Kernel/mtdnand/ 
times new roman", times; font-size: 18px;‘>该文档中关于ECC的说明很有帮助。 
times new roman", times; font-size: 18px;‘>3、
MTD的官方网站: 

http://www.linux-mtd.infradead.org/

times new roman", times; font-size: 18px;‘>MTD是memory
technology
Device的缩写。MTD支持类似于内存的存储器,它是底层硬件和上层软件之间的桥梁。对底层来说,它无论对nor型或是nandflash都有很好的驱动支持,对上层来说,它抽象出文件系统所需要的接口函数。同时由于flash自身的特别之处(既有类似块设备的特点,又有类似字符设备的特点),MTD可以把flash同时为块设备和字符设备。有了MTD,编写flash的驱动变得十分轻松,因为上层的架构都已经做好,我们只用看看flash的datasheet,写最底层的控制时序即可。 

times new roman", times; font-size: 18px;‘>以下内容为翻译自mtd官方网站http://www.linux-mtd.infradead.org/archive/index.html
times new roman", times; font-size: 18px;‘>mtd致力于为存储器,尤其是flash,设计一个通用的linux下的子系统。
times new roman", times; font-size: 18px;‘>设计这个系统的目标在于,通过这个系统所提供的硬件驱动和上层系统之间的接口,我们可以方便的为新的硬件编写驱动。
times new roman", times; font-size: 18px;‘>对于底层的硬件驱动来说,它们所以提供是读,写,擦除的流程。而文件的存储形式是和他们无关的(如FTL,FFS2等等),用恰当的形式存储用户的数据那时上层系统关注的事情。
times new roman", times; font-size: 18px;‘>MTD的用户模块
times new roman", times; font-size: 18px;‘>MTD为用户提供五种可以直接在用户空间使用的模块
times new roman", times; font-size: 18px;‘>字符设备
times new roman", times; font-size: 18px;‘>块设备
times new roman", times; font-size: 18px;‘>flash转换层
times new roman", times; font-size: 18px;‘>nandflash转换层
times new roman", times; font-size: 18px;‘>JFFS2文件系统

times new roman", times; font-size: 18px;‘>三、NAND相关原理 

times new roman", times; font-size: 18px;‘>在我们开始NAND驱动编写之前,至少应该知道:数据在NAND中是怎样存储的,以及以怎样的方式从NAND中读写数据时。 

times new roman", times; font-size: 18px;‘>1、
NAND的存储结构和操作方式 


这方面的资料可以从任意一种NAND的datasheet中得到,因为基本上每一种NAND的datasheet都会介绍NAND的组成结构和操作命令,而且事实上,大多数的NAND
datasheet都大同小异,所不同的大概只是该NAND芯片的容量大小和读写速度等基本特性。 


这里以每页512字节的NAND
FLASH为例简单说明一下:每一块NAND芯片由n个block组成->每一个block由m个page组成->每一个page由256字节大小的column1(也称1st
half page)、256字节大小的column2(也称2nd half page)和16字节大小的oob(out-of-band,也称spare
area)组成。至于m和n的大小可以查看特定NAND的datasheet。相应的,若给定NAND中的一个字节的地址,我们可以根据这个地址算出block地址(即第几个block)、page地址(即该block中的第几个page)和column地址(即1st
half page,或2nd half page,或oob中的第几个字节)。 


在擦除NAND时,必须每次至少擦除1个block;在写NAND时,必须每次写1个page(有些NAND也支持写不足一个page大小的数据);在读NAND时,分为三种情况(对应三种不同的NAND命令),即读column1、读column2和读oob,那么为什么要分这三种情况呢?假如知道NAND怎样根据给定的地址确定它的存储单元,那么自然也就能明白原因了,其实也并不复杂,主要是因为给定地址中的A8并不在NAND的视野范围之内(也许表达并不准确)。 

times new roman", times; font-size: 18px;‘>事实上,在写基于MTD的NAND驱动时,我们并不需要实现精确到读写某一个byte地址的函数(除了读oob之外),这是因为:

times new roman", times; font-size: 18px;‘>基于MTD的NAND驱动在读写NAND时,可以分两种情况,

times new roman", times; font-size: 18px;‘>即:(1)不进行ECC检测时,一次读写一整个page中的MAIN部分(也就是那真实存储数据的512字节);(2)进行ECC检测时(不管是hardware
ECC还是software
ECC),一次读写一整个page(包括16字节的oob部分)。所以部分NAND所支持的写不足一个page大小数据的功能,对MTD来说是用不着的。 


times new roman", times; font-size: 18px;‘>那么,如果只需要读写不足一个page大小的数据怎么办?这是MTD更上层的部分需要处理的事。也就是说,对于NAND驱动来说,它只会读写整整一个page的数据! 

times new roman", times; font-size: 18px;‘>最后值得一提的是,NAND驱动有可能只去读oob部分,这是因为除了ECC信息之外,坏块信息也存储在oob之中,NAND驱动需要读取oob中描述坏块的那个字节(通常是每个block的第一个page的oob中的第六个字节)来判断该block是不是一个坏块。所以,我们只有在读oob时,才需要实现精确到读某一个byte地址的函数。 

times new roman", times; font-size: 18px;‘>由此,我们也可以额外知道一件事,那就是NAND驱动中用到的column地址只在读oob时才有用,而在其他情况下,column地址都为0。 

times new roman", times; font-size: 18px;‘>2、
ECC相关的结构体 

struct
nand_ecclayout { 

          
uint32_t eccbytes; 

          
uint32_t eccpos[64]; 

          
uint32_t oobavail; 

          
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]; 

times new roman", times; font-size: 18px;‘>}; 
times new roman", times; font-size: 18px;‘>这是用来定义ECC在oob中布局的一个结构体。 

times new roman", times; font-size: 18px;‘>前面已经提及过,oob中主要存储两种信息:坏块信息和ECC数据。对与small
page的NAND芯片来说,其中坏块信息占据1个字节(一般固定在第六个字节),ECC数据占据三个字节。所以sturct
nand_ecclayout这个结构体,也就是用来告诉那些与ECC操作无关的函数,Nand芯片的oob部分中,哪些字节是用来存储ECC的(即不可用作它用的),哪些字节是空闲的,即可用的。 


times new roman", times; font-size: 18px;‘>其实之所以有这个结构体,主要是因为硬件ECC的缘故。以写数据为例,在使用硬件ECC的情况下,那三个字节的ECC数据是由硬件计算得到,并且写到NAND芯片的oob中去的,同时也是由硬件决定写到oob的哪三个字节中去。这些都是由硬件做的,而NAND驱动并不知道,所以就需要用这个结构体来告诉驱动了。 

times new roman", times; font-size: 18px;‘>所以,在写NAND驱动时,就有可能需要对这个结构体进行赋值。这里说“有可能”,是因为MTD对这个结构体有一个默认的赋值,假如这个赋值所定义的ECC位置与你的硬件一致的话,那就不必在你的驱动中手动赋值了。其实对大多数硬件(这里所说的硬件,不是指NAND芯片,而是NAND控制器)来说,是不必手动赋值的,但也有许多例外。 

times new roman", times; font-size: 18px;‘>值得一提的是,这个结构体不仅仅用来定义ECC布局,也可以用来将你的驱动在oob中需要额外用到的字节位置保护起来。 

times new roman", times; font-size: 18px;‘>现在对struct
nand_ecclayout 这个结构体进行一下说明。 


uint32_t
eccbytes:ECC的字节数,对于512B-per-page的NAND来说,eccbytes =
3,如果你需要额外用到oob中的数据,那么也可以大于3.

T>:ECC数据在oob中的位置,这里之所以是个64字节的数组,是因为对于2048-per-page的NAND来说,它的oob有64个字节。而对于512B-per-page的NAND来说,可以而且只可以定义它的前16个字节。 
times new roman", times; font-size: 18px;‘>uint32_t
oobavail:oob中可用的字节数,这个值不用赋值,MTD会根据其它三个变量自动计算得到。 

struct
nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES]:显示定义空闲的oob字节。

times new roman", times; font-size: 18px;‘>k9f1208

secotr
size = 512byte,block_pre_sector =32sector, block size = 512*32 =16K,
device=4096block=64M

times new roman", times; font-size: 18px;‘>k9f1g08

secotr
size = 2k, block_pre_sector =64sector, block size = 2*64 =128K,
device=1024block=128M

times new roman", times; font-size: 18px;‘>以上是我以前对NANDFLASH的结构认识,其中忽略了非常重要的一块,就是NAND用来保存其它信息的一块区域,这些信息包括块好坏的标记,块的逻辑地址,还有页内数据的ECC校验和等。。。。

times new roman", times; font-size: 18px;‘>这部分数据通过结构SectorInfo保存

typedef
struct _SectorInfo

{
times new roman", times; font-size: 18px;‘>   
DWORD
dwReserved1;             
// Reserved - used by FAL

   
BYTE
bOEMReserved;            
// For use by OEM

   
BYTE
bBadBlock;            
// Indicates if block is BAD

   
WORD
wReserved2;              
// Reserved - used by FAL

times new roman", times; font-size: 18px;‘>}SectorInfo,
*PSectorInfo;

times new roman", times; font-size: 18px;‘>在读写NAND时通过

BOOL
FMD_ReadSector (SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo
pSectorInfoBuff, DWORD dwNumSectors);

BOOL
FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo
pSectorInfoBuff, DWORD dwNumSectors);

times new roman", times; font-size: 18px;‘>pSectorInfoBuff参数读取相应sector状态,如果pSectorInfoBuff参数为NULL则读写sector数据。pSectorBuff为NULL则读写sector状态。

times new roman", times; font-size: 18px;‘>地址循环的差别
times new roman", times; font-size: 18px;‘>读数据时。列地址的低16位为0,页内偏移量为0,
times new roman", times; font-size: 18px;‘>         
NF_ADDR(0); // Column (A[7:0]) = 0

  
  NF_ADDR(0); // A[11:8]

       
NF_ADDR((blockPage)&0xff); // A[19:12]

       
NF_ADDR((blockPage>>8)&0xff); // A[27:20]

times new roman", times; font-size: 18px;‘>读状态时,列地址低16位为2048,页内偏移量为2048
times new roman", times; font-size: 18px;‘>  NF_ADDR((2048+0)&0xff);   
// 2060 = 0x080c

  NF_ADDR(((2048+0)>>8)&0xff);
times new roman", times; font-size: 18px;‘>      
NF_ADDR((blockPage)&0xff); // A[19:12]

      
NF_ADDR((blockPage>>8)&0xff); // A[27:20]

times new roman", times; font-size: 18px;‘>读状态时,列地址低16位为2048,页内偏移量为2048
times new roman", times; font-size: 18px;‘>  NF_ADDR((2048+0)&0xff);   
// 2060 = 0x080c

  NF_ADDR(((2048+0)>>8)&0xff);
times new roman", times; font-size: 18px;‘>      
NF_ADDR((blockPage)&0xff); // A[19:12]

      
NF_ADDR((blockPage>>8)&0xff); // A[27:20]

times new roman", times; font-size: 18px;‘>由于NAND设备存储数据有一定错误率,需要ECC校验保证数据的正确性。传统的文件系统一般直接和硬件驱动程序接口,但对于NAND设备,还需要增加一层FTL(flash
translation layer)来完成像块逻辑地址到物理地址转换,坏块标注,ECC校验这样的工作。

TARGETLIBS=
$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\FAL.LIB      
\


NAND驱动
FMD_Init,初始化完全后,就会通过FMD_GetInfo来获得NAND的一些基本信息。

之后
FAL会调用FMD_ReadSector建立物理页到逻辑页的映射表。最后根据注册表的配置,还会决定是否重新格式化NAND,是否自动MOUNT挂载NAND的分区到存储管理器。

times new roman", times; font-size: 18px;‘>[HKEY_LOCAL_MACHINE\System\StorageManager\Profiles\FlashDrv]
times new roman", times; font-size: 18px;‘>"DefaultFileSystem"="FATFS"
times new roman", times; font-size: 18px;‘>"PartitionDriver"="mspart.dll"
times new roman", times; font-size: 18px;‘>"AutoMount"=dword:1
times new roman", times; font-size: 18px;‘>"AutoPart"=dword:1
times new roman", times; font-size: 18px;‘>"AutoFormat"=dword:1

times new roman", times; font-size: 18px;‘>*********************************************************************************************************************

times new roman", times; font-size: 18px;‘> 

times new roman", times; font-size: 18px;‘>Yaffs2文件系统移植的一些参考资料:

times new roman", times; font-size: 18px;‘>在结构上YAFFS和YAFFS2有一定的不同,具体结构可以去看一看这篇文档http://www.aleph1.co.uk/node/38

http://jnds.yo2.cn/articles/%E5%9C%A8nand-flash%E4%B8%8A%E5%BB%BA%E7%AB%8Byaffs2%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%EF%BC%88%E4%B8%80%EF%BC%89.html

http://blog.ednchina.com/frenkie/180697/message.aspx


推荐阅读
  • 本文回顾了作者在求职阿里和腾讯实习生过程中,从最初的迷茫到最后成功获得Offer的心路历程。文中不仅分享了个人的面试经历,还提供了宝贵的面试准备建议和技巧。 ... [详细]
  • 深入解析Unity3D游戏开发中的音频播放技术
    在游戏开发中,音频播放是提升玩家沉浸感的关键因素之一。本文将探讨如何在Unity3D中高效地管理和播放不同类型的游戏音频,包括背景音乐和效果音效,并介绍实现这些功能的具体步骤。 ... [详细]
  • 吴石访谈:腾讯安全科恩实验室如何引领物联网安全研究
    腾讯安全科恩实验室曾两次成功破解特斯拉自动驾驶系统,并远程控制汽车,展示了其在汽车安全领域的强大实力。近日,该实验室负责人吴石接受了InfoQ的专访,详细介绍了团队未来的重点方向——物联网安全。 ... [详细]
  • 探讨如何在映射文件中处理重复的属性字段,以避免数据操作时出现错误。 ... [详细]
  • 在测试软件或进行系统维护时,有时会遇到电脑蓝屏的情况,即便使用了沙盒环境也无法完全避免。本文将详细介绍常见的蓝屏错误代码及其解决方案,帮助用户快速定位并解决问题。 ... [详细]
  • 网络流24题——试题库问题
    题目描述:假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 软件测试行业深度解析:迈向高薪的必经之路
    本文深入探讨了软件测试行业的发展现状及未来趋势,旨在帮助有志于在该领域取得高薪的技术人员明确职业方向和发展路径。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 春季职场跃迁指南:如何高效利用金三银四跳槽季
    随着每年的‘金三银四’跳槽高峰期的到来,许多职场人士都开始考虑是否应该寻找新的职业机会。本文将探讨如何制定有效的职业规划、撰写吸引人的简历以及掌握面试技巧,助您在这关键时期成功实现职场跃迁。 ... [详细]
  • Python3爬虫入门:pyspider的基本使用[python爬虫入门]
    Python学习网有大量免费的Python入门教程,欢迎大家来学习。本文主要通过爬取去哪儿网的旅游攻略来给大家介绍pyspid ... [详细]
  • JavaScript 页面卸载事件详解 (onunload)
    当用户从页面离开时(如关闭页面或刷新页面),会触发 onunload 事件,此时可以执行预设的脚本。需要注意的是,不同的浏览器对 onunload 事件的支持程度可能有所不同。 ... [详细]
  • MITM(中间人攻击)原理及防范初探(二)
    上一篇文章MITM(中间人攻击)原理及防范初探(一)给大家介绍了利用ettercap进行arp欺骗及劫持明文口令,后来我发现好友rootoorotor的文章介绍比我写的更透彻,所以基础利用大家可以参看 ... [详细]
  • Android 中的布局方式之线性布局
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文详细介绍了如何利用Xshell配合Xftp实现文件传输,以及如何使用Pure-FTPd构建FTP服务,并探讨了VSFTP与MySQL结合存储虚拟用户的方法。 ... [详细]
author-avatar
敏儿儿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有