打印
[嵌入式linux]

构建linux之最小系统(原创) 献给我的2010

[复制链接]
12541|28
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
51avr|  楼主 | 2010-1-1 15:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 51avr 于 2010-1-1 15:32 编辑

声明:该文件是对我2009年最后两周学习过程的总结,希望能帮助到学习中的人们。该文档按照当前日期的最新版GPL协议发布。欢迎转载,但须注明作者及出处。
作者:Jim Zheng。接触Linux 4年,但是一直处于自学状态,没有机会参与Linux平台的产品开发。很希望能用上Linux平台作实际开发。联系方式:zhengweishang@google.com
日期:2010.1.1

内容提要:
1。最小系统的意义
2。最小系统的要素
3。主机环境介绍
4。软件版本选择
5。构建完成之文件
6。最小系统启动信息
7。详细构建过程
8。下一步工作
1。最小系统的意义
在我的开发经历中,每当要使用新的硬件或软件平台时,我都会从他们的最小系统开始。比如新使用一款单片机,我会首先研究其电源、复位、时钟、JTAG、UART。根据这些可以搭建一个开发的最小硬件系统。我在维护一套3W行的C语言软件时,也曾将起其精简到1千行的最小系统,仅包含消息机制、在屏幕上显示一个小图标、队列服务等,而其他的功能都是一些添加上去的模块。吃透这个最小系统后,增加功能或修正bug就简单很多。最小系统有些像建房子打的地基,对它理解透了,会发现那些眼花缭乱的功能通过添砖加瓦的工作就可以完成了。现今的软硬件系统设计时模块化都做得很好,增减一个功能模块已经是个比较简单的事情。
我想比较深入的学习Linux,于是想到:Linux的最小系统是什么样?
2。最小系统的要素
Linux的发布版本都提供了大量完善的功能和服务,而我想建立的最小系统之仅包含以下要素:
A. 有字符显示。
B。能通过键盘输入字符
C。能执行ls等简单命令
根据以上需求,并分析Linux平台的架构。该最小系统特征如下
A。kernel+rootfs, 不使用initrd.
B. ls等命令放在rootfs中,elf格式。静态编译,不支持动态链接库。
C。 kernel支持elf可执行文件格式
D。 kernel不支持可加载模块功能。必要的驱动直接编译到kernel中。
E。kernel应包含字符的显示驱动、键盘驱动。
F。rootfs放在IDE硬盘上,所以kernel应包含PATA驱动
G。rootfs为EXT3文件系统,kernel应包含EXT2、EXT3文件系统驱动。
3。主机环境介绍
[root@goldway ~]# cat /proc/version
Linux version 2.6.18-1.2798.fc6 (brewbuilder@hs20-bc2-4.build.redhat.com) (gcc version 4.1.1 20061011 (Red Hat 4.1.1-30)) #1 SMP Mon Oct 16 14:37:32 EDT 2006
[root@goldway ~]# cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 15
model           : 2
model name      : Intel(R) Celeron(R) CPU 2.60GHz
stepping        : 9
cpu MHz         : 2625.987
cache size      : 128 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 2
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe up cid xtpr
bogomips        : 5257.90
[root@goldway ~]# lspci
00:00.0 Host bridge: VIA Technologies, Inc. P4M266 Host Bridge
00:01.0 PCI bridge: VIA Technologies, Inc. VT8633 [Apollo Pro266 AGP]
00:10.0 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1 Controller (rev 80)
00:10.1 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1 Controller (rev 80)
00:10.2 USB Controller: VIA Technologies, Inc. VT82xxxxx UHCI USB 1.1 Controller (rev 80)
00:10.3 USB Controller: VIA Technologies, Inc. USB 2.0 (rev 82)
00:11.0 ISA bridge: VIA Technologies, Inc. VT8235 ISA Bridge
00:11.1 IDE interface: VIA Technologies, Inc. VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE (rev 06)
00:11.5 ** audio controller: VIA Technologies, Inc. VT8233/A/8235/8237 AC97 Audio Controller (rev 50)
00:12.0 Ethernet controller: VIA Technologies, Inc. VT6102 [Rhine-II] (rev 74)
01:00.0 VGA compatible controller: nVidia Corporation NV34 [GeForce FX 5200] (rev a1)
[root@goldway ~]# fdisk -l
Disk /dev/hda: 160.0 GB, 160041885696 bytes
255 heads, 63 sectors/track, 19457 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
   Device Boot      Start         End      Blocks   Id  System
/dev/hda1   *           1        1001     8040501    7  HPFS/NTFS
/dev/hda2            1002       19457   148247820    f  W95 Ext'd (LBA)
/dev/hda5            1002        5001    32129968+   7  HPFS/NTFS
/dev/hda6            5002        9001    32129968+   7  HPFS/NTFS
/dev/hda7            9002       13001    32129968+   c  W95 FAT32 (LBA)
/dev/hda8           13002       17001    32129968+   c  W95 FAT32 (LBA)
/dev/hda9           18213       19457    10000431   83  Linux
/dev/hda10          17002       18081     8675068+  83  Linux
/dev/hda11          18082       18212     1052226   82  Linux swap / Solaris
Partition table entries are not in disk order
[root@goldway ~]# mount
/dev/hda10 on / type ext3 (rw)
proc on /proc type proc (rw)
sysfs on /sys type sysfs (rw)
devpts on /dev/pts type devpts (rw,gid=5,mode=620)
tmpfs on /dev/shm type tmpfs (rw)
/dev/hda7 on /mnt/windows/f type vfat (rw)
/dev/hda8 on /mnt/windows/g type vfat (rw)
none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw)
/dev/hda9 on /mnt/cdrom type ext3 (rw)

请注意以下几点:
A。硬盘是IDE接口,所以这篇文档描述的操作不适合于使用SATA硬盘的朋友。
B。我使用的linux dist是fedora core 6. gcc version 4.1.1
C。/dev/hda10是fc6的/, 即将构建的最小系统的文件将放在/dev/hda9中。

4。软件版本选择
A. 选择busybox-1.15.3构建rootfs.
B. 内核版本选择linux-2.6.26.5 。gcc4.1.1不支持最新版的kernel.
5。构建完成之文件
[root@goldway ~]# ll /mnt/cdrom
总计 728
drwxr-xr-x 2 root root   4096 12-31 19:20 bin
-rw-r--r-- 1 root root 701872 01-01 00:28 bzImage
drwxr-xr-x 2 root root   4096 12-31 19:27 dev
-rw-r--r-- 1 root root   3900 2010-01-01 dmesg.txt
drwxr-xr-x 3 root root   4096 01-01 13:03 etc
drwxr-xr-x 2 root root   4096 01-01 13:07 mnt
drwxr-xr-x 2 root root   4096 12-31 19:25 proc
drwxr-xr-x 2 root root   4096 12-31 19:20 sbin
drwxr-xr-x 2 root root   4096 12-31 19:25 sys
drwxr-xr-x 4 root root   4096 12-31 19:20 usr
以上文件夹打包给大家
[root@goldway cdrom]# tar jcf ../rootfs.tar.bz2 *
[root@goldway cdrom]# ll ..
总计 1508
drwxr-xr-x 10 root root    4096 2010-01-01 cdrom
-rw-r--r--  1 root root 1516709 01-01 13:14 rootfs.tar.bz2
drwxr-xr-x  2 root root    4096 12-11 19:14 usb
drwxr-xr-x  6 root root    4096 11-07 17:38 windows
以下为grub引导设置:
[root@goldway ~]# cat /etc/grub.conf
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You do not have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /, eg.
#          root (hd0,9)
#          kernel /boot/vmlinuz-version ro root=/dev/hda10
#          initrd /boot/initrd-version.img
#boot=/dev/hda
default=2
timeout=5
splashimage=(hd0,9)/boot/grub/splash.xpm.gz
hiddenmenu
title kernel test
        root (hd0,8)
        kernel /bzImage ro root=/dev/hda9
title Fedora Core (2.6.18-1.2798.fc6)
        root (hd0,9)
        kernel /boot/vmlinuz-2.6.18-1.2798.fc6 ro root=LABEL=/1 rhgb quiet
        initrd /boot/initrd-2.6.18-1.2798.fc6.img
title Other
        rootnoverify (hd0,0)
        chainloader +1

相关帖子

沙发
51avr|  楼主 | 2010-1-1 15:33 | 只看该作者
6。最小系统启动信息
Linux version 2.6.26.5 (root@goldway) (gcc version 4.1.1 20061011 (Red Hat 4.1.1-30)) #12 Fri Jan 1 00:28:28 CST 2010
BIOS-provided physical RAM map:
BIOS-e820: 0000000000000000 - 000000000009fc00 (usable)
BIOS-e820: 000000000009fc00 - 00000000000a0000 (reserved)
BIOS-e820: 00000000000f0000 - 0000000000100000 (reserved)
BIOS-e820: 0000000000100000 - 000000000fff0000 (usable)
BIOS-e820: 000000000fff0000 - 000000000fff3000 (ACPI NVS)
BIOS-e820: 000000000fff3000 - 0000000010000000 (ACPI data)
BIOS-e820: 00000000fec00000 - 0000000100000000 (reserved)
0MB HIGHMEM available.
255MB LOWMEM available.
Entering add_active_range(0, 0, 65520) 0 entries of 256 used
Zone PFN ranges:
  DMA             0 ->     4096
  Normal       4096 ->    65520
  HighMem     65520 ->    65520
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
    0:        0 ->    65520
On node 0 totalpages: 65520
  DMA zone: 32 pages used for memmap
  DMA zone: 0 pages reserved
  DMA zone: 4064 pages, LIFO batch:0
  Normal zone: 480 pages used for memmap
  Normal zone: 60944 pages, LIFO batch:15
  HighMem zone: 0 pages used for memmap
  Movable zone: 0 pages used for memmap
DMI 2.3 present.
Allocating PCI resources starting at 20000000 (gap: 10000000:eec00000)
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 65008
Kernel command line: ro root=/dev/hda9
Enabling fast FPU save and restore... done.
Enabling unmasked SIMD FPU exception support... done.
Initializing CPU#0
PID hash table entries: 1024 (order: 10, 4096 bytes)
Detected 2625.912 MHz processor.
Console: colour VGA+ 80x25
console [tty0] enabled
Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
Memory: 257764k/262080k available (912k kernel code, 3808k reserved, 300k data, 100k init, 0k highmem)
virtual kernel memory layout:
    fixmap  : 0xfffee000 - 0xfffff000   (  68 kB)
    pkmap   : 0xff800000 - 0xffc00000   (4096 kB)
    vmalloc : 0xd0800000 - 0xff7fe000   ( 751 MB)
    lowmem  : 0xc0000000 - 0xcfff0000   ( 255 MB)
      .init : 0xc0232000 - 0xc024b000   ( 100 kB)
      .data : 0xc01e4097 - 0xc022f42c   ( 300 kB)
      .text : 0xc0100000 - 0xc01e4097   ( 912 kB)
Checking if this processor honours the WP bit even in supervisor mode...Ok.
CPA: page pool initialized 1 of 1 pages preallocated
SLUB: Genslabs=12, HWalign=128, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
Calibrating delay using timer specific routine.. 5257.16 BogoMIPS (lpj=10514322)
Mount-cache hash table entries: 512
CPU: Trace cache: 12K uops, L1 D cache: 8K
CPU: L2 cache: 128K
CPU: Intel(R) Celeron(R) CPU 2.60GHz stepping 09
Checking 'hlt' instruction... OK.
Freeing SMP alternatives: 0k freed
Setting up standard PCI resources
io scheduler noop registered (default)
Uniform Multi-Platform E-IDE driver
ide: Assuming 50MHz system bus speed for PIO modes; override with idebus=xx
ide_generic: please use "probe_mask=0x3f" module parameter for probing all legacy ISA IDE ports
Probing IDE interface ide0...
hda: ST3160215A, ATA DISK drive
Probing IDE interface ide1...
ide0 at 0x1f0-0x1f7,0x3f6 on irq 14
ide1 at 0x170-0x177,0x376 on irq 15
hda: max request size: 512KiB
hda: 312581808 sectors (160041 MB) w/2048KiB Cache, CHS=19457/255/63
hda: cache flushes supported
hda: hda1 hda2 < hda5 hda6 hda7 hda8 hda9 hda10 hda11 >
serio: i8042 KBD port at 0x60,0x64 irq 1
serio: i8042 AUX port at 0x60,0x64 irq 12
mice: PS/2 mouse device common for all mice
Using IPI Shortcut mode
input: AT Translated Set 2 keyboard as /devices/platform/i8042/serio0/input/input0
kjournald starting.  Commit interval 5 seconds
EXT3-fs: mounted filesystem with ordered data mode.
VFS: Mounted root (ext3 filesystem) readonly.
Freeing unused kernel memory: 100k freed
EXT3-fs warning: maximal mount count reached, running e2fsck is recommended
EXT3 FS on hda9, internal journal

7。详细构建过程
A. 构建rootfs.
[root@goldway ~]# pwd
/root
[root@goldway ~]# tar zxf download/busybox-1.15.3.tar.gz
[root@goldway ~]# cd busybox-1.15.3/
[root@goldway busybox-1.15.3]# make distclean
[root@goldway busybox-1.15.3]# make menuconfig
注意:
        A. 选中Build BusyBox as a static binary (no shared libs)
        B. 取消usleep。默认选择usleep,但是编译有问题。这里直接去掉该项命令。
        C. 其他都使用默认选项.
退出时保存设置。
[root@goldway busybox-1.15.3]# make
[root@goldway busybox-1.15.3]# make install
[root@goldway busybox-1.15.3]# cd _install/
[root@goldway _install]# ll
总计 12
drwxr-xr-x 2 root root 4096 01-01 13:31 bin
lrwxrwxrwx 1 root root   11 01-01 13:31 linuxrc -> bin/busybox
drwxr-xr-x 2 root root 4096 01-01 13:31 sbin
drwxr-xr-x 4 root root 4096 01-01 13:31 usr

[root@goldway _install]# file bin/busybox
bin/busybox: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.9, statically linked, for GNU/Linux 2.6.9, stripped

[root@goldway _install]# rm -f linuxrc
[root@goldway _install]# cp -a ../examples/bootfloppy/etc .
修改etc中的部分内容,修改后如下
[root@goldway _install]# tree etc
etc
|-- fstab
|-- init.d
|   `-- rcS
|-- inittab
`-- profile

1 directory, 4 files
[root@goldway _install]# cat etc/inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
tty2::askfirst:-/bin/sh                                        ------要创建/dev/tty2
::ctrlaltdel:/bin/umount -a -r

[root@goldway _install]# cat etc/init.d/rcS
#! /bin/sh

/bin/mount -a
/bin/mount -o remount,rw /                                ------增加該行,使/可读写.

创建必要的文件夹及文件:
[root@goldway _install]# mkdir sys proc mnt dev
[root@goldway _install]# ls
bin  dev  etc  mnt  proc  sbin  sys  usr
[root@goldway _install]# cp -a /dev/{console,tty,tty2} dev/
[root@goldway _install]# ls dev
console  tty  tty2

B. 内核编译
[root@goldway _install] cd
[root@goldway ~]# tar jxf download/linux-2.6.26.5.tar.bz2
[root@goldway ~]# cd linux-2.6.26.5/
[root@goldway linux-2.6.26.5]# make mrproper
[root@goldway linux-2.6.26.5]# make allnoconfig
[root@goldway linux-2.6.26.5]# make menuconfig
注意以下选项的选择:
        A。选中Executable file formats/Emulations   ---> Kernel support for ELF binaries      -----加载运行rootfs中的程序.
        B。选中Device Drivers --> ATA/ATAPI/MFM/RLL support --> Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
          -->Include IDE/ATA-2 DISK support   该项必选否则VFS错误:kernel panic. unkown block ....
          -->legacy /proc/ide/ support    --- 此项可不选
          -->generic/default IDE chipset support.  ---- 这里选择通用驱动. 也可选择与自己芯片组相同的驱动。
        C。File systems --> Second extended fs support
                    --> Ext3 journalling file system support

退出保存设置
[root@goldway linux-2.6.26.5]# make bzImage          ---------编译内核
[root@goldway linux-2.6.26.5]# cp arch/x86/boot/bzImage ../busybox-1.15.3/_install/
[root@goldway linux-2.6.26.5]# cd
[root@goldway ~]# mount /dev/hda9 /mnt/cdrom
[root@goldway ~]# rm -rf /mnt/cdrom/*       -----清确定自己要做什么.
[root@goldway ~]# cp -a busybox-1.15.3/_install/* /mnt/cdrom/

引导设置参见第5节.
若无意外,重新启动后,即可启动我们制作出来的linux最小系统。

8。下一步工作
最小系统的功能有限,计划增加下面功能:
A。支持VFAT文件系统支持,以mount FAT32文件系统。
B。支持USB。
C。从USB启动?
D。支持网络功能。
E。X window ?
...

to be continued...

使用特权

评论回复
板凳
51avr|  楼主 | 2010-1-1 15:41 | 只看该作者
rootfs.tar.bzip2 (1.44 MB)

使用特权

评论回复
地板
51avr|  楼主 | 2010-1-21 14:40 | 只看该作者
我建了一个QQ群,有兴趣的朋友可以加入。

嵌入式 linux(96833641)
学习linux操作系统,嵌入式系统开发。

使用特权

评论回复
5
51avr|  楼主 | 2010-1-27 08:52 | 只看该作者
声明:该文件是对我学习过程的总结,希望能帮助到学习中的人们。该文档按照当前日期的最新版GPL协议发布。欢迎转载,但须注明作者及出处。
作者:Jim Zheng。接触Linux 4年,但是一直处于自学状态,没有机会参与Linux平台的产品开发。很希望能用上Linux平台作实际开发。联系方式:zhengweishang@google.com
日期:2010.1.26

构建linux之最小系统 SMDK2410篇 (1)简介

简介:
在做完pc平台的linux最小系统后,继续制作基于s3c2410的嵌入式平台的linux最小系统。完成有一段时间了,今天做个总结,希望对自己和大家有些帮助。

pc平台的linux系统由以下部分组成:BIOS+GRUB+kernel+rootfs+app
BIOS是固化在主板上的程序,上电后首先执行。在完成一系列的初始化及配置后,它会把放在硬盘上固定地址的一段代码拷贝到内存中执行(假设BIOS设置为从硬盘启动),这段代码即是通常所指的bootloader, GRUB是bootloader的一种,在pc平台上广泛使用。GRUB很小,它的主要功能是识别文件系统并从中读取kernel到内存当中,配置恰当的参数,跳转到kernel。kernel实现了非常丰富的功能(操作系统的功能),包括驱动硬盘,识别文件系统,操作文件,驱动键盘显示器等。kernel得到控制权以后,整个系统由他完全控制。它会mount rootfs, 启动放置在rootfs中的app: init。而init会初始化用户空间环境,并启动人机接口--shell或桌面环境。
pc平台的最小硬件系统包括:CPU+RAM+硬盘+键盘+显示器+BIOS(主板).电源和时钟也是必须的

类比pc平台的linux系统的组成,基于s3c2410的嵌入式系统的linux系统组成如下:bootloader + kernel + rootfs + app。可以发现两种平台的系统组成相似,区别在于嵌入式平台没有BIOS,嵌入式平台的bootloader会实现pc平台的BIOS所完成的部分功能。pc平台的驱动驱动应该会调用BIOS的服务程序,而嵌入式系统的驱动完全在kernel或module中实现。
嵌入式平台的最小硬件系统包括:CPU+RAM+NANDFLASH+UART。其中NAND FLASH相当于硬盘;UART相当于键盘和显示器,实现交互功能。
因为s3c2410内部集成了SDRAM控制器和NANDFLASH控制器,硬件部分只要按照数据手册规范设计就不会有问题。
以下假设配置SDRAM 64M,NAND FLASH 64M, 系统上电从NAND FLASH启动。这样一个系统可称为smdk2410系统。

值得一提的是文件存储介质不一样,使用的文件系统也不一样。硬盘上多使用EXT2/EXT3,而NANDFLASH上面多使用romfs,cramfs,jffs2,yaffs2等。另外硬盘上的分区表可以被内核中的模块识别,而嵌入式系统中可能不使用分区表,在常见的系统中,分区表直接硬编码到内核源码当中。很期待新的kernel能增强对不同文件系统的分区表的识别功能!

根据以上信息, 我计划总结以下内容:
a. 开发环境的建立
b. bootloader: vivi功能分析
c. kernel编译
d. rootfs制作:cramfs
e. 可读写的nand flash文件系统:jffs2
f. 内核虚拟文件系统:proc, sysfs, ramfs, tmpfs..
g. 其他...

使用特权

评论回复
6
lhj200304| | 2010-1-28 16:19 | 只看该作者
mark  有空了拜读

使用特权

评论回复
7
barryyan| | 2010-2-2 19:08 | 只看该作者
没来得及看完,有空再看。

使用特权

评论回复
8
yinchunhua| | 2010-4-16 12:27 | 只看该作者
正在学习

使用特权

评论回复
9
kuangnan| | 2010-4-22 11:13 | 只看该作者
想搞操作系统  但没找到入口

使用特权

评论回复
10
大众牌BF| | 2010-5-5 16:58 | 只看该作者
牛~~进群啦~

使用特权

评论回复
11
lonerwolf| | 2010-5-6 12:28 | 只看该作者
MARK

使用特权

评论回复
12
yyxl| | 2010-12-17 08:22 | 只看该作者
学习学习。。。。。。。。。。。。。

使用特权

评论回复
13
你IT了吗| | 2010-12-23 23:14 | 只看该作者
Mark~~~~

使用特权

评论回复
14
sinanjj| | 2011-1-10 23:27 | 只看该作者
顶上来

使用特权

评论回复
15
51avr|  楼主 | 2011-1-23 14:09 | 只看该作者
一年多没有更新,实在很遗憾。如今的工作量比以前大很多,有心无力,请各位xdjm谅解。

部门现在需要招聘人手,工作内容是android平台的驱动开发,欢迎有较扎实C语言基础的人才过来看看。有linux基础更好,有linux驱动开发经验更好,有手机平台驱动开发经验更好。这里能接触到大量新奇技术,这里有很多学习培训机会,这里有很多施展拳脚的舞台。

有意者请将简历发邮件给我: zhengzhimin@huawei.com, 我们将尽快安排面试。

使用特权

评论回复
16
lala1008| | 2011-1-26 08:22 | 只看该作者
没看懂  哎

使用特权

评论回复
17
一朝成名| | 2011-1-26 10:58 | 只看该作者
是海思吗

使用特权

评论回复
18
wurg| | 2011-1-29 11:14 | 只看该作者
好东东

使用特权

评论回复
19
who_ma| | 2011-1-29 14:05 | 只看该作者
收藏一下,仔细研读

使用特权

评论回复
20
liuzhenya| | 2011-8-11 16:19 | 只看该作者
你的PC的境像是怎么装上去的,也有找算自己玩一下这个啊。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

73

帖子

2

粉丝