加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

uboot之nand flash相关(3)

发布时间:2020-12-15 17:58:56 所属栏目:百科 来源:网络整理
导读:然后我们分析一下nand flash的读写等函数。 既然是命令那自然要看到U_BOOT_CMD宏,这个宏分析的很多就不分析了。在cmd_nand.c文件中。nand的命令执行函数是do_nand。当然我们没有定义CFG_NAND_LEGACY,要看这个分支。do_nand函数也没有什么好分析的,摘取几个
然后我们分析一下nand flash的读写等函数。
既然是命令那自然要看到U_BOOT_CMD宏,这个宏分析的很多就不分析了。在cmd_nand.c文件中。nand的命令执行函数是do_nand。当然我们没有定义CFG_NAND_LEGACY,要看这个分支。do_nand函数也没有什么好分析的,摘取几个命令的处理分析下。
1。nand bad命令
列出函数调用次序先,
do_nand
nand_block_isbad//include/nand.h
nand_block_isbad//在Nand_base.c中, info->block_isbad函数指针指向
nand_block_checkbad//在Nand_base.c
nand_block_bad() //在Nand_base.c中,nand_chip,this->block_bad函数指针指向,
nand_isbad_bbt //在Nand_bbt.c中
如下。

点击(此处)折叠或打开

  1. nand?=?&nand_info[nand_curr_device];
  2. if?(strcmp(cmd,?"bad")?==?0{
  3. printf("nDevice %d bad blocks:n")for?(off?;?off?<?nand->size+=?nand>erasesize//按块循环
  4. (nand_block_isbad(nand(1)
  5. printf" %08xn";
  6. return 0;
  7. }
这个函数的定义在include/nand.h中,它调用nand_info[]变量中的block_isbad函数指针指向的函数;这个指针在初始化时已经被分配,这里是Nand_base.c文件中的nand_block_isbad函数。这里有个小问题,那有两个都被编译的nand_block_isbad函数的定义,那到底调用的是哪个呢。答案是nand.h中的,因为Nand_base.c中的是被定义成static的函数,只能在本文件中使用。

点击(此处)折叠或打开

  1. static?int?nand_block_isbad?(struct mtd_info?*mtd)
  2. {
  3. *?Check?for?invalid offset?*/
  4. (ofs?>?mtd)
  5. return?-EINVAL;

  6. return nand_block_checkbad?(mtd?1}
这个函数又会调用nand_block_checkbad 函数

点击(此处)折叠或打开

  1. static?int?nand_block_checkbad?int?getchipint?allowbbt{
  2. struct nand_chip?*this?=?mtd>priv;

  3. (!this>bbt/如果nand_chip结构体变量中的bbt(坏块标记表)表指针是空的
  4. return this>block_bad*?Return info from the table?/
  5. return nand_isbad_bbt?}
block_bad函数指针被指向nand_block_bad,分析它,
此函数将从芯片读取坏块标记

点击(此处)折叠或打开

  1. static?int?nand_block_bad{
  2. int?page?res?;
  3. struct nand_chip?;
  4. u16 bad;

  5. page?int>>?this>page_shift&?this>pagemask;?)

  6. (getchip{?/选中芯片
  7. chipnr?>chip_shift*?Grab the lock?and?see?if?the device?is?available?/
  8. nand_get_device?(this?FL_READING*?Select?the NAND device?/
  9. this>select_chip}

  10. >options?&?NAND_BUSWIDTH_16{
  11. this>cmdfunc??this>badblockpos?&?0xFE;
  12. bad?=?cpu_to_le16>read_word&?0x1)
  13. bad?=?1(bad?&?0xFF!=?0xff)
  14. res?}?else?>badblockpos(2>read_byte(3*?Deselect?and?wake up anyone waiting?on?the device?/
  15. nand_release_device}

  16. return res}
(1)从偏移地址获取页号。page_shift是page页位数(就是一页的大小的数值用二进制表示最高位的序号)。将偏移地址右移页位数,则低位就是页的号码,有相当于除页大小。然后在与上pagemask,就是页大小(主要是将高位置0,其实这里与不与感觉都无所谓,高位本来就是0)
(2)主要就是这一句,cmdfunc()函数,发送读取oob区命令。this->badblockpos在nand_scan函数中设置了大页0,小页5。
(3)读出的位是否是0xff,如果不是就是坏块。
...................................
再看下如果有bbt表,nand_block_checkbad函数将调用nand_isbad_bbt。bbt表在初始化时scan_bbt函数已经建立。所以nand bad命令在这个uboot中都是通过查bbt表完成的。

点击(此处)折叠或打开

  1. int?nand_isbad_bbt?;
  2. int?block;
  3. uint8_t resGet?block number?*?2?/
  4. block?(offs?>?>bbt_erase_shift?-?1[block?>?3]?(block?&?0x06&?0x03)

  5. DEBUG?(MTD_DEBUG_LEVEL2"nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02xn"(unsigned?)offs?block?>?1;

  6. switch?)rescase?0x00:?return 0case?0x01:?return 1case?0x02:?return allowbbt???0?:?1}
  7. return 1}
nand bad命令处理暂时分析到这里
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

分析nand read 命令:
nand read命令的调用顺序为:
do_nand //cmd_nand.c
nand_read_opts ///driver/mtd/nand/nand_util.c
nand_read //nand_base.c,meminfo->read指针指向
nand_read_ecc //nand_base.c
sep4020_nand_read_buf//cpu/sep4020/nand_flash.c

这里的代码大多照搬了内核的mtd层代码,而仅仅对于uboot不需要这么复杂,一些操作觉得不合理,有很多无用又费周折的操作。
do_nand函数中read相关部分:

点击(此处)折叠或打开

  1. (strncmp"read"=?0?||?strncmp"write"{
  2. int?read;

  3. (argc?<?4)
  4. goto usage;

  5. addr?(ulong)simple_strtoul(argv[2NULL;

  6. read?=?strncmp*?1?=?read=?write?/
  7. printf"nNAND %s: "??"read"?:?;
  8. (arg_off_size-?3+?3&off&size)
  9. return 1;

  10. s?=?strchr'.(s?NULL?&&
  11. !strcmp(s".jffs2"|?".e"".i"{
  12. (read*?read?/
  13. nand_read_options_t opts;
  14. memset&opts(opts;
  15. opts.buffer?(u_char)?addr/addr是内存地址,nand读出来的数据最终将存入这里
  16. opts.length?=?size/读取的大小
  17. opts.offset?=?off/flash地址
  18. opts.quiet?=?quiet;
  19. ret?=?nand_read_opts/读数据操作,opts将保存必要的信息。
  20. *?write?/
  21. nand_write_options_t opts*?opts.forcejffs2?/
  22. opts.pad?.blockalign?=?nand_write_opts}
  23. &?".yaffs";?
  24. opts.forceyaffs?.noecc?.writeoob?.skipfirstblk?}


  25. ".oob"*?read out-of-band data?/
  26. )
  27. ret?>read_oob
  28. (u_char?else
  29. ret?>write_oob=?nand_read)addr=?nand_write}

  30. printf" %d bytes %s: %sn""written""ERROR"?"OK";

  31. return ret?;
  32. }
nand_read_opts在/driver/mtd/nand/nand_util.c,参照代码中原本的英文注释,代码量大也就不做详细分析了

点击(此处)折叠或打开

  1. *
  2. *?nand_read_opts:?-?read image from NAND flash with support?for?various options
  3. *?@param meminfo NAND device?to?erase
  4. *?@param opts read options?@see struct nand_read_options)
  5. *?@return 0?in?case?of success
  6. /
  7. int?nand_read_opts(nand_info_t?*meminfoconst?nand_read_options_t?*optsint?imglen?=?opts>length;
  8. int?pagelenint?baderaseblockint?blockstart?-1int?percent_complete?;
  9. loff_t offs;
  10. size_t readlen;
  11. ulong mtdoffset?>offset;
  12. u_char?*buffer?>bufferint?result*?make sure device page sizes are valid?(meminfo>oobsize?=?16?&?meminfo>oobblock?=?512=?8?=?256=?64?=?2048{
  13. printf"Unknown flash (not normal NAND)n";
  14. return?}

  15. pagelen?=?meminfo>oobblock
  16. +?>readoob???meminfo:?0*?checkif?length?is?not?larger than device?(imglen?/?pagelen*?meminfo>oobblock>size?-?opts"Image %d bytes,NAND page %d bytes,"
  17. "OOB area %u bytes,device size %u bytesn"?pagelen;
  18. printf"Input block is larger than devicen"}

  19. !opts>quiet)
  20. printf"n"get?data from input?and?write?to?the device?while?(mtdoffset?<?meminfo{

  21. WATCHDOG_RESET?*?new eraseblockfor?bad block.?Stay?in?the
  22. loop?to?be sure?if?the offset changes because of
  23. *?a bad blocknext?block that will be
  24. *?written?is?also checked.?Thus avoiding errors?if
  25. *?the block)?after the skipped blockis?also bad
  26. (number of blocks depending?on?the blockalign
  27. (blockstart?~meminfo+1{
  28. blockstart?=?mtdoffset?;
  29. offs?=?blockstart;
  30. baderaseblock?*?check all the blocks?in?an?erase?block?for
  31. *?bad blocks?do?int?ret?>block_isbad(ret?<?0"Bad block check failedn"{
  32. baderaseblock?"rBad block at 0x%lx "
  33. "in erase block from "
  34. "0x%x will be skippedn"(long)?offs(baderaseblock{
  35. mtdoffset?=?blockstart
  36. +?meminfo}
  37. offs?<?blockstart?*?read page data?to?memory buffer?/
  38. result?>read/读2048字节(不包含oob的一页)
  39. mtdoffset/nand flash地址
  40. meminfo/页大小(2048)&readlen(unsigned char?&data_buf(result?"reading NAND page at offset 0x%lx failedn"<?readlen{
  41. readlen?=?imglen}

  42. memcpy(buffer?readlen;
  43. buffer?=?readlen;
  44. imglen?/上面是读页有效数据(2048),这里读oob数据。
  45. >readoob{?
  46. result?>oobsize&oob_buf"nMTD readoob failure: %dn"?oob_buf;

  47. buffer?{
  48. unsigned long long n?(unsigned long long-imglen*?100int?percent;

  49. do_div(n;
  50. percent?)n*?output progress message only at whole percent
  51. *?steps?to?reduce the number of messages printed
  52. on?(slow)?serial consoles
  53. (percent?=?percent_complete"rReading data from 0x%x "
  54. "-- %3d%% complete.";
  55. percent_complete?=?percent}

  56. mtdoffset?>?0"Could not read entire image due to bad blocksn"*?return happy?/
  57. return 0}
上面meminfo->read指向的函数是,nand_read在nand_base.c文件中。

点击(此处)折叠或打开

  1. static?int?nand_read??size_t?len*?retlen*?buf{
  2. return nand_read_ecc??retlen}
nand_read_ecc函数在nand_base.c中,函数如下

点击(此处)折叠或打开

  1. *
  2. *?nand_read_ecc?-?[MTD Interface]?Read data with ECC
  3. *?@mtd:?MTD device structure
  4. *?@from:?offset?to?read from
  5. *?@:?number of bytes?to?read
  6. *?@retlen:?pointer?to?variable?to?store the number of read bytes
  7. *?@buf:?the databuffer?to?put data
  8. *?@oob_buf:?filesystem supplied oob data buffer
  9. *?@oobsel:?oob selection structure
  10. *?NAND read with ECC
  11. /
  12. static?int?nand_read_ecc?*?oob_buf*oobsel)
  13. {
  14. int?i?colend?sndcmd?;
  15. int?read??ecc_status?;
  16. struct nand_chip?;
  17. u_char?*data_poi*oob_data?=?oob_buf;
  18. u_char ecc_calc[32;
  19. u_char ecc_codeint?eccmode;
  20. unsigned?*oob_configint?datidxint?blockcheck?(1?<<?>phys_erase_shift?-?thisint?eccbytesint?compareecc?int?oobreadlen;


  21. DEBUG?(MTD_DEBUG_LEVEL3"nand_read_ecc: from = 0x%08x,len = %in")?from)?;

  22. Do?not?allow reads past?end?of device?/
  23. (from?+?{
  24. DEBUG?(MTD_DEBUG_LEVEL0"nand_read_ecc: Attempt read beyond end of devicen";
  25. *retlen?;
  26. return?}

  27. /
  28. nand_get_device?FL_READING*?use userspace supplied oobinfoif?zero?(oobsel?)
  29. oobsel?&mtd>oobinfo*?Autoplace of oob data???Use the default placement scheme?(oobsel>useecc?=?MTD_NANDECC_AUTOPLACE=?this>autooob;

  30. eccmode?=?oobsel??this>eccmode?:?NAND_ECC_NONE;
  31. oob_config?>eccpos/
  32. chipnr?;
  33. this*?First we calculate the starting page?/
  34. realpage?;
  35. page?=?realpage?Get?raw starting column?/
  36. col?=?from?end?;
  37. ecc?>eccsize;
  38. eccbytes?>eccbytes(eccmode?=?NAND_ECC_NONE&?NAND_HWECC_SYNDROME)
  39. compareecc?;

  40. oobreadlen?)
  41. oobreadlen?Loop?until?all data read?(read?<?{

  42. int?aligned?!col?len?-?readIf?the read?not?page alignedto?read into data buffer
  43. *?due?to?eccelse?we read into return buffer direct
  44. (aligned)
  45. data_poi?&buf[readelse
  46. data_poi?>data_buf*?Checkif?we have this page?in?the buffer
  47. *?FIXME:?Make it work when we must provide oob data too*?check the usage of data_buf oob field
  48. (realpage?>pagebuf?!oob_buf{
  49. *?aligned read???)
  50. memcpy?(data_poi;
  51. goto readdataif?we must send the read command?(sndcmd{ //板级读命令发送,其实这里主要设置了nandflash的地址。
  52. this?0x00;
  53. sndcmd?get?oob areaif?we have no oob buffer from fs-driver?!oob_buf?|?oobsel=?MTD_NANDECC_AUTOPLACE?|
  54. oobsel=?MTD_NANDECC_AUTOPL_USR)
  55. oob_data?&this[;

  56. eccsteps?>eccsteps;

  57. switch?(eccmodecase?NAND_ECC_NONE*?No ECCin?a page?*?XXX U-BOOT XXX?/
  58. #if?0
  59. static unsigned long lastwhinge?(lastwhinge?/?HZ(jiffies?{
  60. printk?(KERN_WARNING?"Reading data from NAND FLASH without ECC is not recommendedn";
  61. lastwhinge?=?jiffies}
  62. #else
  63. puts;
  64. #endif
  65. this>read_buf;
  66. breakcase?NAND_ECC_SOFT*?Software ECC 3/256:?Read?+?oob data?/
  67. this/读取数据
  68. (i?;?eccsteps=3=?ecc)
  69. this>calculate_ecc&data_poi[datidx&ecc_calc[i;

  70. default:
  71. =eccbytes{
  72. this>enable_hwecc*?HW ecc with syndrome calculation must read the
  73. *?syndrome from flash immidiately after the data?!compareecc*?Some hw ecc generators need?to?know when the
  74. *?syndrome?is?read from flash?&oob_data*?We calc?error?correction directly*?generator?for?an?errorand
  75. *?does the?error?correction?on?the fly?>correct_data&ecc_code"nand_read_ecc: "
  76. "Failed ECC read,page 0x%08x on chip %dn";
  77. ecc_failed}
  78. }
  79. break*?read oobdata?[mtd-?oobreadlen*?Skip ECC checknot?requested?(ECC_NONE?or?HW_ECC with syndromes)
  80. goto readoob*?Pick the ECC bytes out of the oob data?(j?;?j?<?oobsel;?j)
  81. ecc_code[j=?oob_data[oob_config*?correct dataif?neccecary?;?i?<?this;?i{
  82. ecc_status?Get?next?chunk of ecc bytes?/
  83. j?=?eccbytesif?we have a fs supplied oob-buffer*?This?is?the legacy mode.?Used by YAFFS1
  84. *?Should go away some?day
  85. (oob_buf?&?oobsel=?MTD_NANDECC_PLACEint?*p?;
  86. p=?ecc_status(ecc_status?"nand_read_ecc: "?}

  87. readoob-buffer?(oob_buf*?without autoplace.?Legacy mode used by YAFFS1?/
  88. switch>useecccase?MTD_NANDECC_AUTOPLACEcase?MTD_NANDECC_AUTOPL_USR*?Walk through the autoplace chunks?<?mtd>oobavailint?from?>oobfree[0int?num?[1;
  89. memcpy[oob+j[from;
  90. j=?num}
  91. oob?case?MTD_NANDECC_PLACE*?YAFFS1 legacy mode?/
  92. oob_data?>eccsteps?*?sizeof?;
  93. default:
  94. oob_data?}
  95. readdata*?Partial page read!aligned=?col&?read?)
  96. buf=?data_poi=?realpageelse
  97. read?*?Apply delay?or?wait?for?ready/busy pin
  98. Do?this before the AUTOINCR check*?arise?if?a chip which does auto increment
  99. is?marked as NOAUTOINCR by the board driver.
  100. >dev_ready)
  101. udelay?>chip_delayelse
  102. =?)
  103. breakFor?subsequent reads align?to?page boundary.?*?Increment page address?/
  104. realpage;

  105. page?if?we cross a chip boundary?!page{
  106. chipnrif?the chip supports auto page increment
  107. or?if?we have hit a block boundary!NAND_CANAUTOINCR(page?&?blockcheck)
  108. sndcmd?/
  109. nand_release_device*?Return successif?no ECC failures-EBADMSG
  110. *?fs driver will take care of that*?retlen?=?desired?and?result?;
  111. return ecc_failed?-EBADMSG?;
  112. }

this->cmdfunc (mtd,NAND_CMD_READ0,0x00,page)函数指针指向的函数为sep4020_nand_command函数

点击(此处)折叠或打开

  1. static void sep4020_nand_command?(struct mtd_info?*mtd,?unsigned command,?int?column,?intpage_addr)
  2. {
  3. register struct nand_chip?*this?=?mtd->priv;

  4. if(command?==?NAND_CMD_READOOB)?//(1)
  5. {
  6. column?+=?mtd->oobblock;
  7. command?=?NAND_CMD_READ0;
  8. }
  9. //column是坏块在oob中的位置,加上oobblock(就是页大小pagesiz,不知道为什么起这个名字oobblock),这样就是
  10. //地址中的列地址。command命令赋值NAND_CMD_READ0(0),读命令。

  11. this->hwcontrol(mtd,?NAND_CTL_SETCLE);
  12. //命令引脚使能

  13. switch(command)
  14. {
  15. case?NAND_CMD_READ0:
  16. *(volatile unsigned long*)EMI_NAND_COM_RAW?=?0x40003000;
  17. //这个寄存器[7:0]命令的第一个字节00?[15:8]是命令的第二个字节30?.
  18. //最高位是使能位(暂不开启),30位是字节表示1字节还是2字节命令。4=0100
  19. break;
  20. case?NAND_CMD_SEQIN:
  21. *(volatile unsigned long*)EMI_NAND_COM_RAW?=?0x40001080;
  22. //?80,10 写flash
  23. break;
  24. default:
  25. this->write_byte(mtd,command);
  26. break;
  27. }
  28. this->hwcontrol(mtd,NAND_CTL_CLRCLE);
  29. //命令引脚无效
  30. if?(command?==?NAND_CMD_READID)
  31. {
  32. EMI_NAND_COM?|=?0x80000000;?//使能EMI_NAND_COM
  33. this->hwcontrol(mtd,?NAND_READ_ID);?
  34. return;
  35. }

  36. if?(command?==?NAND_CMD_STATUS)
  37. {
  38. EMI_NAND_COM?|=?0x80000000;?//使能EMI_NAND_COM
  39. this->hwcontrol(mtd,?NAND_READ_STATUS);
  40. }

  41. if?(command?==?NAND_CMD_RESET)
  42. {
  43. EMI_NAND_COM?|=?0x80000000;
  44. this->hwcontrol(mtd,?NAND_CTL_CLRALE);
  45. }
  46. /*?Set?ALE?and?clear CLE?to?start address cycle?*/

  47. if?(column?!=?-1?||?page_addr?!=?-1)?{
  48. this->hwcontrol(mtd,?NAND_CTL_SETALE);?//这里这个函数其实没什么用。?
  49. EMI_NAND_ADDR1?=?page_addr<<16;?//page_addr是页号。128M,2Kflash一共就64K页
  50. EMI_NAND_ADDR2?=?page_addr>>16;?//对于一共总数64K的页,这个值等于0
  51. this->hwcontrol(mtd,?NAND_CTL_CLRALE);
  52. }
  53. //

  54. }
分析sep4020_hwcontrol函数。此函数之所以存在,应该是为了和MCU通过引脚直接控制或其他MCU的nand flash的代码结构保持兼容,此处此函数的主要作用是将IO_ADDR_W替换成对应的寄存器地址

点击(此处)折叠或打开

  1. static void sep4020_hwcontrol(struct mtd_info?*mtd,?int?cmd)
  2. {?
  3. struct nand_chip?*this?=?mtd->priv;

  4. switch?(cmd)?{
  5. case?NAND_CTL_SETNCE:?
  6. case?NAND_CTL_CLRNCE:
  7. break;
  8. //对于nCE位的操作都不予理睬

  9. case?NAND_CTL_SETCLE:
  10. this->IO_ADDR_W?=?(void __iomem?*)?EMI_NAND_COM_RAW;
  11. break;
  12. //IO_ADDR_W是nand flash的数据寄存器地址。是_iomem类型变量(这是个空的宏定义,
  13. //但这样可以让人很容易知道这是个寄存器变量。),这里的作用是将EMI_NAND_COM_RAW即nand flash
  14. //内存的地址赋值给IO_ADDR_W,这样后面的操作,在使用IO_ADDR_W时就是使用EMI_NAND_COM_RAW。

  15. case?NAND_CTL_SETALE:
  16. this->IO_ADDR_W?=?(void __iomem?*)?EMI_NAND_ADDR1_RAW;
  17. break;

  18. case?NAND_READ_ID:
  19. this->IO_ADDR_R?=?(void __iomem?*)?EMI_NAND_ID_RAW;
  20. break;

  21. case?NAND_READ_STATUS:
  22. this->IO_ADDR_R?=?(void __iomem?*)?EMI_NAND_STA_RAW;
  23. break;

  24. /*?NAND_CTL_CLRCLE:?*/
  25. /*?NAND_CTL_CLRALE:?*/
  26. default:
  27. this->IO_ADDR_W?=?(void __iomem?*)?EMI_NAND_DATA_RAW;
  28. this->IO_ADDR_R?=?(void __iomem?*)?EMI_NAND_DATA_RAW;
  29. //在一些命令使能和地址使能后,将IO_ADDR_W还原成EMI_NAND_DATA_RAW nand flash数据寄存器地址
  30. break;
  31. }
  32. }
this->read_buf(mtd,data_poi,end);read_buf指向的函数为sep4020_nand_read_buf,

点击(此处)折叠或打开

  1. static void sep4020_nand_read_buf*bufint?/配置DMAC用于nand的传输
  2. DMAC_C0CONTROL?(2112>2<14<13<9<6<3;
  3. DMAC_C0SRCADDR?=?EMI_NAND_DATA_RAW?;
  4. DMAC_C0DESTADD?=?vaddr/vaddr在board_nand_init函数中,使用malloc分配的一块2112大的内存空间
  5. DMAC_C0CONFIGURATION?=?0x31d?;?
  6. EMI_NAND_COM?=?0xc0003000/nand命令控制器,00 30读命令,且最高位使能nand控制器,开始读数据。
  7. while(EMI_NAND_IDLE?&?0x01if=?2048?|?=?2112/如果要读取的长度是1页或包含oob的1页。则从vaddr开始复制len长度的数据
  8. {
  9. memcpy(buf;?
  10. =?64/如果读取的长度是64,则是要只读取oob区域,则从vaddr+2048地址处开始复制。
  11. {?
  12. memcpy+2048}
  13. }
这个函数使能了nand flash控制器,将nandflash中对于的一页数据读出,并将适当的数据复制给了参数传来的buf。

nand read命令大致就是这样一个流程。本来想只是写写uboot关于nand的处理,和这个sep4020 nand控制器的特点。没想到这个版本的uboot就是nand驱动和内核的差不多,代码量太多。可能也是自己不熟悉这块,陆陆续续写了几天,感觉写的效率很低,写的想吐。于是草草结尾。之后看看其他版本的uboot的nand相关,不知道还是不是这样了。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读