自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(95)
  • 收藏
  • 关注

转载 bootloader开发阶段总结以及可能会碰到的问题

<br />到今天,vivi源代码基本分析完毕。对bootloader有了更深层的认识。在此期间,仔细阅读了毛德操、胡希明先生编著的《嵌入式系统--采用公开源代码和StrongARM/XScale处理器》第七章:嵌入式系统的引导和装入。看了看出版时间,才明白牛人詹荣开或许也受惠于此书。他在IBM Development上发表的那篇《嵌入式bootloader技术内幕》一文,后来在sourceforge上的开源项目jtager,在此书中有详尽的描述。(当然,他们可能是独立研究的。)两者结合起来看,对自己的帮助

2011-04-14 10:54:00 5478 1

转载 vivi源代码最为详细分析(三)

step 5:     MTD设备初始化。     关于什么是MTD,为什么要使用MTD,MTD技术的架构是什么,等等,可以参考《Linux MTD源代码分析》(作者:Jim Zeus,2002-04-29)。这份文档的参考价值比较大,猜想作者在当时可能研究了很长时间,毕竟2002年的时候资料还比较缺乏。当然,因为完全分析透彻,方方面面都点透,这份文档还是没有做到。      在分析代码前先介绍一下MTD(Memory Technology Device)相关的技术。在inux系统中,我们通常会用到不同的存

2011-04-13 15:41:00 3925

转载 vivi源代码最为详细分析(二)

现在进入bootloader之vivi分析的第二阶段,这部分使用C语言实现,部分代码采取内嵌汇编的方式。这里需要用到GNU GCC内嵌汇编的知识,这部分基础还没有具备,需要学习。     下面先按照流程进行分析。需要注意的是,此部分内容并非完全按照原版的vivi源代码,而是加入了自己的理解。另外,对非常简单、google出一片而且有分析正确的部分,在这里就简化了,不做详细分析,只是对网上没有分析到位而又影响理解的部分进行深入分析。我想,这部分内容应该是对《s3c2410完全开发》中vivi源代码分析部分的补

2011-04-12 21:14:00 4005

转载 vivi源代码最为详细分析(一)

<br />通过vivi研究bootloader有一段时间了,基本是在与之相关的基础方面做工作,还没有真正深入研究vivi。以后的学习重心就要放到研究vivi源代码上面了。我想,真正细致地弄清楚vivi实现的细节,对C语言水平的提高,对ARM体系结构的认识,对S3C2410的熟悉,对嵌入式bootloader相关技术,都能有很大的好处。学习的进度会慢一些,但是务求深入,并且打好相关的基础。 一、写在前面的话<br />    嵌入式系统软件开发主要包括五个方面:bootloader编写(移植)、驱动程序编写

2011-04-12 17:47:00 7875

转载 CLOCK

一、对clock的基本认识     第七部分是“clock & power management”,总结如下:     1 s3c2410的clock & power management模块包含三个部分:clock control、usb control、power control。现在的关注点是clock control。     2、s3c2410有两个pll(phase locked loop,锁相环,在高频中学过,可以实现倍频,s3c2410的高频就是由此电路产生的)。其中一个是MPLL,M即为m

2011-04-08 17:01:00 1751

转载 MMU

<br /> 这几天一直在看MMU部分,现在有了基本的认识,还不深入,解决了初级问题,并且仿照vivi完成了一个测试实例,对深入理解和验证推论的结果很有帮助。在学习的过程中,体会到几种方法还是比较实用的:     · 从历史的角度去了解技术,梳理清楚发展主线,效率更高。    · 采用软硬件结合的方法分析,理解更为深入。    · 与同一爱好的朋友交流,可以发现认识的盲区,认识更为全面。    · 应该阅读英文的Datasheet,中文翻译往往有错误,有时候是致命的,以前在c8051F020的SPI的设计中

2011-04-08 16:55:00 2890

原创 INTERRUPT CONTROLLER

<br />    1,中断的基本概念<br />     CPU与外设之间传输数据的控制方式通常有3种:查询方式,中断方式和DMA方式。查询方式的优点是硬件开销小不需要额外的硬件支持只是通过软件不断的轮询,使用起来也就比较简单,但在此方式下,CPU要不断地查询外设的状态,当外设未准备好时,CPU就只能循环的等待,不能执行其他程序,这样就浪费了CPU的大量时间,降低了CPU的利用率,为了解决这个矛盾,通常采用中断传送方式,即当CPU进行主程序的操作时,外设的数据已经存入输入端口的数据寄存器或者输出端口的数据

2011-04-08 15:32:00 4272

原创 UART

<br />一、S3C2410内置的UART控制器<br />S3C2410内部具有3个独立的UART控制器,每个控制器都可以工作在Interrupt(中断)模式或DMA(直接内存访问)模式,也就是说UART控制器可以在CPU与UART控制器传送数据的时候产生中断或DMA请求。并且每个UART控制器均具有16字节的FIFO(先入先出寄存器),支持的最高波特率可达到115.2Kbps<br />图5-11是S3C2410内部UART控制器的结构图 <br /><br />  <br />图5-11  <br

2011-04-08 11:19:00 34520 3

原创 NAND FLASH

<br />  当OM1、OM0都是低电平——即开发板插上BOOT SEL跳线时,S3C2410从NAND Flash启动:NAND Flash的开始4k代码会被自动地复制到内部SRAM中。我们需要使用这4k代码来把更多的代码从NAND Flash中读到SDRAM中去。NAND Flash的操作通过NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT和NFECC六个寄存器来完成。在开始下面内容前,请打开S3C2410数据手册和NAND Flash K9F1208U0M的数据手册。 <br />

2011-04-07 20:31:00 3847 1

原创 GPIO

一、什么是GPIO?     首先应该理解什么是GPIO。GPIO,英文全称为General-Purpose IO ports,也就是通用IO口。在嵌入式系统中常常有数量众多,但是结构却比较简单的外部设备/电路,对这些设备/电路有的需要CPU为之提供控制手段,有的则需要被CPU用作输入信号。而且,许多这样的设备/电路只要求一位,即只要有开/关两种状态就够了,比如灯亮与灭。对这些设备/电路的控制,使用传统的串行口或并行口都不合适。所以在微控制器芯片上一般都会提供一个“通用可编程IO接口”,即GPIO。接口至少

2011-04-07 16:35:00 48756 3

原创 SDRAM-MEMORY CONTROLLER

<br />重点分析s3c2410复位后的内存映射,及其应用。一、基本配置    EDUKIT-III采用核心子板加扩展板的设计方式,我学习ARM9,所以采用s3c2410的核心子板。核心子板资源如下:     MCU      : S3C2410A    SDRAM    : 两片HY57V561620CT-H    NOR FLASH: AM29LV160DB-90EC     扩展板资源:     NAND FLASH: K9F5608UOC二、nand flash boot分析     S3C241

2011-04-07 15:16:00 3439

转载 链接过程分析

<br />有些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错误信息不能定位到某一行)。或者对语言的一些部分不知道为什么要(或者不要)这样那样设计。了解本文之后,或许会有一些答案。<br />    首先看看我们是如何写一个程序的。如果你在使用某种IDE(Visual Studio,Elicpse,Dev C++等),你可能不会发现程序是如何组织起来的(很多人因此而反对初学者使

2011-03-24 17:00:00 1319

转载 GNU LD

<br />今天把vivi所用到的ld的用法都看懂了,常见的选项含义也清楚了。翻看了一下kernel的链接脚本,发现相当复杂,并且需要对全局有很好的把握,对整个的地址空间分配也必须清楚。这点暂时还做不到,属于后续工作。先把ld的基本用法总结一下,因为《Linkers and Loaders》还没有读完,所以暂时还不能作出总结。不过,对链接和加载已经有了更深入的认识。在读using ld时,很多地方自然就理解了。慢慢来,把这块知识体协理顺。 1、什么是ld?它有什么作用?     ld是GNU binutil

2011-03-24 14:41:00 6157 10

转载 GNU AS

一 GNU AS简介    GNU AS是GNU汇编器,主要用于把汇编代码转换成二进制代码,并存放到一个object文件中。GNU AS工具本身的使用方法比较简单,主要参考文档《Using as--the GNU Assembler》(2.14)。首先看一下1.1 Structure of this Manual。     This manual is intended to describe what you need to know to use gnu as. We cover the syntax

2011-03-24 13:26:00 4580

原创 Trap命令之信号处理

<br />一. trap捕捉到信号之后,可以有三种反应方式: <br />  (1)执行一段程序来处理这一信号<br />  (2)接受信号的默认操作 <br />  (3)忽视这一信号<br /><br />二. trap对上面三种方式提供了三种基本形式:    <br /> <br />      第一种形式的trap命令在shell接收到signal list清单中数值相同的信号时,将执行双引号中的命令串。   <br />  trap 'commands' signal-list   <br />

2011-03-23 13:18:00 2457

原创 Makefile中的wildcard用法

<br />在Makefile规则中,通配符会被自动展开。但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTERN...)。在Makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空。需要注意的是:这种情况下规则中通配符的展开和上一小节匹配通配符的区别。<br />一般我们可以使用“$(wildcard *.c)”来获取工作

2011-03-22 11:33:00 194229 22

原创 关于vivi编译时遇到的几个错误

<br />1,arm-linux-gcc: installation problem, cannot exec `cpp0': No such file or directory<br />这种错误比较常见,一般涉及到交叉编译器都有可能碰到这种问题,提示是安装有问题,不能执行相应的命令,这主要是和你交叉编译器的安装路径有关,也就是你解压缩后交叉编译器的存放目录,之前直接将压缩包下载后直接放在/root/kevin下,然后解压缩后直接就放在了当前路径,然后设置PATH,这样的放置目录时不行的,一般要将交叉编

2011-03-22 10:37:00 2066

转载 vivi与Linux kernel的参数传递情景分析(下)

<br />下面进入Linux kernel部分,分析与bootloader参数传递对应的部分。     移植Linux需要很大的工作量,其中之一就是HAL层的编写。在具体实现上,HAL层以arch目录的形式存在。显然,该层需要与bootloader有一定的约定,否则就不能很好的支持。其实,这个地方应该思考一个问题,就是说,boot loader可以做到Linux kernel里面,但是这样带来的问题就是可移植性和灵活性都大为降低。而且,bootloader的功能并非操作系统的核心范畴,Linux的核心应该

2011-03-19 16:17:00 1364

原创 uboot环境变量与内核MTD分区关系

<br />uboot 与系统内核中MTD分区的关系:<br />分区只是内核的概念,就是说A~B地址放内核,C~D地址放文件系统,(也就是规定哪个地址区间放内核或者文件系统)等等。<br />1:在内核MTD中可以定义分区A~B,C~D。。。。。。并予以绝对的地址赋值给每个分区。我们可以来看看在内核中是怎样来对MTD进行分区的:arch/arm/plat-s3c24xx/common-smdk.c<br />static struct mtd_partition smdk_default_nand_par

2011-03-19 15:17:00 9762 3

转载 vivi与Linux kernel的参数传递情景分析(上)

<br />在上一部分提到过了,vivi作为bootloader,向内核传递启动参数是其本职工作之一。要把这个情景分析清楚,不仅仅需要分析vivi的参数机制,而且要分析Linux kernel的接收机制。因为这是一个简单的通信过程,比起本科所学习的TCP/IP来简单的多,但是因为简单,所以在协议上并不规范,理解上反而不如TCP/IP协议。下面就分为两个方面对此情景分析。 一、综述内核参数传递机制     现在内核参数传递机制有两种:一种是基于struct param_struct,这种已经比较老了。缺点是该

2011-03-18 15:32:00 2668

原创 asmlinkage宏

<br />asmlinkage是个宏,使用它是为了保持传递参数在stack中。因为从汇编语言到C语言代码参数的传递是通过stack的,它也可能从stack中得到一些不需要的参数。Asmlinkage将要解析那些参数。看一下/usr/include/asm/linkage.h里面的定义:<br />#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))<br />__attribute__是关键字,是gcc的C语言扩展,regparm(0)

2011-03-18 09:30:00 961

转载 arm-linux-gcc/ld/objcopy/objdump参数总结

arm-linux-gccarm-linux-gcc -Wall -O2 -c -o $@ $< -o 只激活预处理,编译,和汇编,也就是他只把程序做成obj文件也就是.o的目标文件 -Wall 指定产生全部的警告信息 -O2 编译器对程序提供的编译优化选项,在编译的时候使用该选项,可以使生成的执行文件的执行效率提高,O后面还可以附带其他的数值,表示提供不同的优化策略。 -c表示只要求编译器进行编译,而不要进行链接,生成以源文件的文件名命名但把其后缀由 .c 或 .cc 变成 .o 的目标文件 -S 只激活

2011-03-15 19:59:00 3564 1

转载 各种烧写文件格式简介

一、ELFExecutable and linking format(ELF)文件是x86 Linux系统下的一种常用目标文件(object file)格式,有三种主要类型:(1)适于连接的可重定位文件(relocatable file),可与其它目标文件一起创建可执行文件和共享目标文件。 (2)适于执行的可执行文件(executable file),用于提供程序的进程映像,加载到内存执行。 (3)共享目标文件(shared object file),连接器可将它与其它可重定位文件和共享目标文件连接成其它的

2011-03-15 19:27:00 1681

转载 vivi移植开发

<br />今天把vivi编译了一下,顺便解决了几个问题。算是初步工作吧,下一步打算读vivi的源代码,然后改造一下,最后争取自己完成一个小的bootloader。 准备工作(这些都是基于EDUKIT-III教学平台,虽然开发工具上有些不同,但是原理和流程上是相同的。相信理解了嵌入式系统开发流程之后,对这些就会有很清晰的认识): 1)下载Nand_Prog.ide.bin到nor flash。这步工作是为烧写nand flash做准备的。为什么不利用仿真器直接烧写nand flash呢?理解了JTAG的原理

2011-03-15 17:13:00 2294

原创 GPBCON控制器控制LED显示

<br />GPBCON是用来设置输入输出属性的,也就是说,你不是要控制LED吗?现在你知道了LED的引脚有GPB0,GPB1,而GPBCON又是控制这些引脚的属性,那么现在我们要控制它闪烁就要设置这些引脚的属性为输出。那么如何设置呢?我们的引脚是GPB0,GPB1,而GPBCON是两位控制一个引脚,所以应该是0101(这里手册上说的很清楚),GPBCON寄存器的低22位都是用来控制引脚的属性,其中每两位控制一个引脚,如[1:0]来控制GPB0也就是第0个引脚,[21:20]来控制GPB10也就是第11个引

2011-03-15 15:35:00 4160

转载 通过共享内存进行进程间通信

<br />共享内存的工作方式<br />顾名思义,共享内存让一段内存可供多个进程访问。用特殊的系统调用(即对 UNIX 内核的请求)分配和释放内存并设置权限;通过一般的读写操作读写内存段中的数据。 <br />共享内存并不是从某一进程拥有的内存中划分出来的;进程的内存总是私有的。共享内存是从系统的空闲内存池中分配的,希望访问它的每个进程连接它。这个连接过程称为映射,它给共享内存段分配每个进程的地址空间中的本地地址。<br /> 假设在同一系统上有两个进程 A 和 B 正在运行(见 图 1),它们可以通过共

2011-03-11 14:12:00 6467

转载 Linux2.6 内核的 Initrd 机制解析

<br />1.什么是 Initrd<br />initrd 的英文含义是 boot loader initialized RAM disk,就是由 boot loader 初始化的内存盘。在 linux内核启动前, boot loader 会将存储介质中的 initrd 文件加载到内存,内核启动时会在访问真正的根文件系统前先访问该内存中的 initrd 文件系统。在 boot loader 配置了 initrd 的情况下,内核启动被分成了两个阶段,第一阶段先执行 initrd 文件系统中的"某个文件",完

2011-03-11 11:12:00 839

转载 devfs、sysfs、udev

<br />一、devfs<br />linux下有专门的文件系统用来对设备进行管理,devfs和sysfs就是其中两种。在2.6内核以前一直使用的是devfs,devfs挂载于/dev目录下,提供了一种类似于文件的方法来管理位于/dev目录下的所有设备,我们知道/dev目录下的每一个文件都对应的是一个设备,至于当前该设备存在与否先且不论,而且这些特殊文件是位于根文件系统上的,在制作文件系统的时候我们就已经建立了这些设备文件,因此通过操作这些特殊文件,可以实现与内核进行交互。但是devfs文件系统有一些缺点

2011-03-11 10:18:00 972

转载 MTD问题解决

***求教使用MTD的问题*** <br /><br />1。我把bootloader和zImage放到了一个2M的NOR Flash上,现在想把自己做的根文件系统fs.jffs2放入另一块8M的NAND Flash上供kernel启动时使用。请问如果我想对NAND FLASH分区,是不是只需对/drivers/mtd/maps下对应的nand_flash.c文件中的"static struct mtd_partition"结构进行改动就可以了? <br />2。文件系统/dev下面的mtd0,mtd1..

2011-03-10 19:35:00 5030

转载 内核启动无法挂载根文件系统的问题

<br />这类问题很常见,先总体介绍一下解决思路。<br />能出现让人激动的的控制台,那么系统移植已经接近完成;但是不少人在最后一步出现问题。<br />要点如下:<br />1. 在正确的位置烧写正确格式的文件系统映象:<br />2. 内核支持这种文件系统格式<br />3. 文件系统的内容要完备<br /> <br />上面说得简单,一个个介绍。<br /> <br />1. 在正确的位置烧写正确的文件系统映象:<br /> <br />(a). 正确的位置<br />嵌入式开发中,常通过boot

2011-03-10 19:33:00 2079

转载 u-boot环境变量的设置与使用

<br />  看到这个标题,可能觉得这个并没有什么的,其实不然,编好了u-boot了,但是如何来使用确不是那么简单的,想当初我将uboot制作出来后以为全部都搞定了,屁颠屁颠的烧到板子上后可系统就是起不来,为什么了,折腾了很久以后才发现是u-boot的环境变量设置错误,在后来的工作中,我发现一些有一定经验的人在这方面也是模模糊糊的扯不清,所以这里要讨论一下。<br /> <br />    u-boot的环境变量是使用u-boot的关键,它可以由你自己定义的,但是其中有一些也是大家经常使用,约定熟成的,有

2011-03-10 17:15:00 2257

原创 initrd

<br />什么是初始 RAM 磁盘?<br />初始 RAM 磁盘(initrd)是在实际根文件系统可用之前挂载到系统中的一个初始根文件系统。initrd 与内核绑定在一起,并作为内核引导过程的一部分进行加载。内核然后会将这个 initrd 文件作为其两阶段引导过程的一部分来加载模块,这样才能稍后使用真正的文件系统,并挂载实际的根文件系统。<br />initrd 中包含了实现这个目标所需要的目录和可执行程序的最小集合,例如将内核模块加载到内核中所使用的 insmod 工具。<br />在桌面或服务器 L

2011-03-10 16:44:00 1536

原创 ramdisk

1、Ram Disk介绍1.1   什么是Ram DiskRam Disk 就是将内存中的一块区域作为物理磁盘来使用的一种技术。对于用户来说,可以把RAM disk与通常的硬盘分区(如/dev/hda1)同等对待来使用。 1.2    Ramdisk与硬盘分区的不同RAM disk不适合作为长期保存文件的介质,掉电后Ramdisk的内容会随内存内容的消失而消失。RAM disk的其中一个优势是它的读写速度高,内存盘的存取速度要远快于目前的物理硬盘,可以被用作需要高速读写的文件。注意:在2.6版本后,Ramd

2011-03-10 15:27:00 3906

转载 Linux系统中/dev/mtd与/dev/mtdblock的区别

<br />MTD(memory technology device内存技术设备)是用于访问memory设备(ROM、flash)的Linux的子系统。MTD的主要目的是为了使新的memory设备的驱动更加简单,为此它在硬件和上层之间提供了一个抽象的接口。MTD的所有源代码在/drivers/mtd子目录下。我将CFI接口的MTD设备分为四层(从设备节点直到底层硬件驱动),这四层从上到下依次是:设备节点、MTD设备层、MTD原始设备层和硬件驱动层。<br />MTD字符驱动程序允许直接访问flash器件,通

2011-03-09 19:41:00 4829

原创 mknod

<br />mknod - make block or character special files<br />mknod [OPTION]... NAME TYPE [MAJOR MINOR]<br />    option 有用的就是 -m 了<br />    name   自定义<br />    type   有 b 和 c 还有 p<br />    主设备号<br />    次设备号<br /><br />主设备号是由linux/major.h定义的,如下定义了一个DOC设备: <br /

2011-03-09 17:00:00 9987 1

原创 struct file_operations

<br />    linux驱动程序中最重要的涉及3个重要的内核数据结构,分别为file_operations,file和inode。<br />    在linux中inode结构用于表示文件,而file结构则表示打开的文件的描述,因为对于单个文件而言可能会有许多个表示打开的文件的描述符,因而就可能会的对应有多个file结构,但是都指向单个inode结构。<br />    在系统内部,I/O设备的存取操作通过特定的的入口来进行,而这组特定的入口由驱动程序来提供的。通常这组设备驱动的接口是由结构体fil

2011-03-09 16:32:00 1179

原创 主设备号和次设备号

<br />     Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。<br />     一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称

2011-03-09 15:04:00 32752 6

原创 MMU工作原理

<br />一、MMU的产生<br />      许多年以前,当人们还在使用DOS或是更古老的操作系统的时候,计算机的内存还非常小,一般都是以K为单位进行计算,相应的,当时的程序规模也不大,所以内存容量虽然小,但还是可以容纳当时的程序。但随着图形界面的兴起还用用户需求的不断增大,应用程序的规模也随之膨胀起来,终于一个难题出现在程序员的面前,那就是应用程序太大以至于内存容纳不下该程序,通常解决的办法是把程序分割成许多称为覆盖块(overlay)的片段。覆盖块0首先运行,结束时他将调用另一个覆盖块。虽然覆盖块

2011-03-08 15:47:00 7588 1

原创 Linux下使用Shell命令控制任务Jobs执行

<br />下列命令可以用来操纵进程任务:<br /><br />ps 列出系统中正在运行的进程;<br />kill 发送信号给一个或多个进程(经常用来杀死一个进程);<br />jobs 列出当前shell环境中已启动的任务状态,若未指定jobsid,则显示所有活动的任务状态信息;如果报告了一个任务的终止(即任务的状态被标记为Terminated),shell 从当前的shell环境已知的列表中删除任务的进程标识;<br />bg 将进程搬到后台运行(Background);<br />fg 将进程搬到

2011-03-08 11:14:00 9093

转载 C语言中函数参数的入栈顺序

<br />对技术执着的人,比如说我,往往对一些问题,不仅想做到“知其然”,还想做到“知其所以然”。C语言可谓博大精深,即使我已经有多年的开发经验,可还是有许多问题不知其所以然。某天某地某人问我,C语言中函数参数的入栈顺序如何?从右至左,我随口回答。为什么是从右至左呢?我终究没有给出合理的解释。于是,只好做了个作业,于是有了这篇小博文。<br />#include <stdio.h><br />void foo(int x, int y, int z)<br />{<br />        printf(

2011-03-08 10:06:00 2407 1

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除