티스토리 뷰
Host 환경 구축
ubuntu 배포판 설치 (edgy 버전 Ubuntu 6.10)
- ubuntu linux edgy 버전 CD로 부팅해서 설치
- 설치중 파티션 나눔 :
hda #1 크기 : 39.0 GB 용도 : EXT3 저널링 파일 시스템 마운트 위치 : / hda #2 크기 : 15.0 GB 용도 : EXT3 저널링 파일 시스템 마운트 위치 : /mnt/fs hda #3 크기 : 2.0 GB 용도 : 스왑 마운트 위치 : 스왑
- 설치 완료 후 배포판 업데이트
$ sudo apt-get update #꾸러미 목록을 새로 가져온다 $ sudo apt-get dist-upgrade #배포판 업그레이드 $ sudo apt-get upgrade #업데이트
- Ubuntu 소프트웨어 소스를 universe, multiverse 모두 가능하도록 수정
$ vi sudo /etc/apt/sources.list
- 임시로 네트워크 설정하는 법
$ sudo ifconfig eth0 210.107.224.139 netmask 255.255.255.0 up #고정ip 설정 $ sudo route add default gw 210.107.224.1 #Gateway 설정
- 네트워크 설정
$ sudo vi /etc/network/interfaces #고정ip 설정 auto eth0 iface eth0 inet static address 210.107.224.139 netmask 255.255.255.0 gateway 210.107.224.1 $ sudo vi /etc/resolv.conf #DNS 설정 search sejong.ac.kr nameserver 210.107.239.131 210.107.239.132 $ sudo /etc/init.d/networking restart #네트워크 재시작
- ssh 설치
$ sudo apt-get install ssh
- vim 설치 #vim은 vi의 기능을 확장한 프로그램이다.
$ sudo apt-get install vim
- gcc compiler 설치
$ sudo apt-get install build-essential
Busybox 빌드 (Host환경)
- 임의의 공간에 압축풀기
$ tar xvfj busybox-1.4.2.tar.bz2
- 환경설정 (default)
$ make defconfig #디폴트로 환경설정을 해준다.
- 환경설정 (사용자 설정)
$ make menuconfig #그래픽화면으로 환경설정 가능. HOSTCC scripts/kconfig/lxdialog/checklist.o In file included from scripts/kconfig/lxdialog/checklist.c:24: scripts/kconfig/lxdialog/dialog.h:31:20: error: curses.h: No such file or directory In file included from scripts/kconfig/lxdialog/checklist.c:24: scripts/kconfig/lxdialog/dialog.h:128: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘use_colors’ #에러메세지 (위의 메세지를 보면 "curses.h" 라는 헤더파일이 없어서 함수선언이 안되었음을 알 수 있다.) $ apt-cache search ncurses dev #ncurses의 dev패키지를 찾음. $ sudo apt-get install libncurses5-dev #Developer's libraries and docs for ncurses 인스톨 $ make menuconfig #이제 환경설정이 ui화면으로 잘나온다.
- busybox 빌드
$ make #busybox를 빌드 (busybox-1.4.2 버전) LINK busybox_unstripped /home/clauson/Desktop/busybox-1.4.2/scripts/trylink: 5: function: not found /home/clauson/Desktop/busybox-1.4.2/scripts/trylink: 11: Syntax error: "}" unexpected #에러메세지 (1.4.2버전은 Ubuntu 6.10 에서 빌드가 안된다.)
- 최신버전으로 다시 빌드 [23 March, 2007 -- busybox 1.5.0 (unstable)] #unstable 버전이지만 Ubuntu 6.10 에서 빌드가 되었다.
$ tar xvfj busybox-1.5.0.tar.bz2 $ make defconfig $ make
- busybox 시험 사용예시 "./busybox [appletname] [options]"
$ ./busybox ls -l $ ./busybox cat LICENSE $ ./busybox ash #busybox shell을 사용할 수 있다.
Target 환경 구축
busybox 인스톨
- 이젠 target에서 쓸 수 있도로 busybox를 static하게 빌드해보자 (지금까진 library쓰도록 빌드했다.)
$ make defconfig #defconfig로 설정하면 전부 select하기 때문에 편의상 했다. $ make memuconfig #여기서 busybox를 static하게 빌드하도록 설정할 수 있다. Busybox Configuration -> Build Options -> Build BusyBox as a static binary (no shared libs)란에 체크 $ make
- 빌드한 busybox를 target에 install해보자.
$ sudo make PREFIX=/mnt/fs install #이렇게 하면 빌드한 busybox가 /mnt/fs에 복사되고 디렉터리를 만들고 파일을 링크한다. $ cd /mnt/fs $ ls home #아무것도 복사안됐다. 모르겠다.
- install을 하면 ./_install이라는 폴더에 인스톨을 해놓고 사용자가 지정한 공간으로 옮기는 과정이기때문에 그냥 수동으로 복사했다.
$ sudo cp -a ./_install/* /mnt/fs $ cd /mnt/fs $ ls bin home linuxrc lost+found sbin usr #모두 복사가 되었다.
- 이것으로 static하게 빌드한 busybox를 target 환경에 인스톨하는 것을 마쳤다.
Target으로 부팅하기 위한 준비
- Boot process에 대한 이해
http://kldp.org/HOWTO/html/Bootdisk-HOWTO/x100.html#AEN103
1. 롬(정확히는 BIOS)내의 코드를 실행시키는 것으로 부팅을 시작. 2. 이 코드는 부트 드라이브(첫번째 드라이브 /dev/fd0)의 섹터 0, 실린더 0 부분을 읽어들인다. 3. BIOS 는 읽어들인 이 섹터의 내용을 실행. 4. 그 섹터에는 GRUB 등과 같은 부트로더(boot loader)의 코드가 들어있다. 5. 부트로더는 커널을 찾아 메모리에 로드한 후 실행시키는 방식으로 부트를 시작. 6. 일단 커널이 완전히 로드되면, 커널은 기본적인 디바이스들과 그 내부 데이터 구조를 초기화시킨다. 7. 초기화가 완료되면 커널 이미지내의 특정한 위치에 있는 램디스크 워드라는 것을 읽는다. 8. 이 워드는 루트 파일시스템을 어디에서 어떻게 찾아야 하는지를 나타내고 있다. 9. 루트 파일시스템이란 단순히 "/" 에 마운트되는 파일시스템을 말한다. 10. 루트 파일시스템을 로드하는데 성공하면, 루트 파일시스템에 있는 init 프로세스(/sbin/init)를 찾아 실행을 시도한다. 11. init 는 그 설정파일인 /etc/inittab 에서 sysinit 라인을 찾아 그에 해당하는 이름의 스크립트를 실행시킨다. 12. sysinit 스크립트의 실행이 끝나면 다시 init 프로세스로 조종권이 돌아온다.
- Boot process에 대한 이해를 바탕으로 target으로 부팅하기 위해 해야할 일
루트 파일 시스템의 디렉터리를 생성
$ sudo mkdir boot dev etc lib mnt opt proc root tmp var $ ls bin dev home linuxrc mnt proc sbin usr boot etc lib lost+found opt root tmp var
커널 컴파일
- 참고 문헌
http://kldp.org/KoreanDoc/Kernel_Compile-KLDP
- 커널 다운로드
- 커널 버전
The latest stable version of the Linux kernel is: 2.6.20.6 2007-04-06 20:06 UTC F V VI C Changelog F를 선택하면 full버전을 다운로드 받을 수 있다. 커널 버전중에 2는 주 버전이고 6은 짝수번호일때는 안정버전 홀수일때는 개발버전이다.
- 필요한 패키지
커널 컴파일도 menuconfig를 쓰는데 busybox 빌드할 때 처럼 ncurses 라이브러리를 설치했는지 확인해야 한다.
- 다운로드한 커널 압축 풀기
$ tar xvfj linux-2.6.20.6.tar.bz2
- 커널 설정
http://wiki.kldp.org/wiki.php/LinuxdocSgml/2.4Kernel_Compile-KLDP
$ make menuconfig
- 커널 컴파일
$ time make bzImage #압축된 커널 이미지를 만든다. I를 대문자로 써야한다, time은 빌드하는 시간을 재준다. LD vmlinux SYSMAP System.map SYSMAP .tmp_System.map MODPOST vmlinux AS arch/i386/boot/bootsect.o LD arch/i386/boot/bootsect AS arch/i386/boot/setup.o LD arch/i386/boot/setup AS arch/i386/boot/compressed/head.o CC arch/i386/boot/compressed/misc.o OBJCOPY arch/i386/boot/compressed/vmlinux.bin GZIP arch/i386/boot/compressed/vmlinux.bin.gz LD arch/i386/boot/compressed/piggy.o LD arch/i386/boot/compressed/vmlinux OBJCOPY arch/i386/boot/vmlinux.bin HOSTCC arch/i386/boot/tools/build BUILD arch/i386/boot/bzImage Root device is (3, 1) Boot sector 512 bytes. Setup is 4634 bytes. System is 2845 kB Kernel: arch/i386/boot/bzImage is ready (#1) real 10m13.676s user 8m48.065s sys 0m41.143s
- 커널 컴파일이 완료되면 /usr/src/linux/arch/i386/boot/디렉토리 아래 bzImage를 찾을 수 있다.
- 커널 설치
sudo cp ./arch/i386/boot/bzImage /mnt/fs/boot/vmlinuz-2.6.20.6 #커널 이미지를 타겟의 /boot에 복사 sudo cp ./System.map /mnt/fs/boot sudo cp ./.config /mnt/fs/boot/ #make menuconfig로 만들었던 커널의 설정 파일을 타겟의 /boot에 복사
- 부트로더(GRUB) 변경해서 커널 적용
http://www.ibm.com/developerworks/kr/library/l-bootload.html
$ sudo gedit /boot/grub/menu.lst title EmbeddedlinuxSystem, kernel 2.6.20.6 root (hd0,1) kernel /boot/vmlinuz-2.6.20.6 root=/dev/hda2
- 부팅
$ sudo reboot 부팅도중에 ESC키를 눌러서 GRUB에 들어가서 새로 컴파일한 커널을 선택한다.
- 커널 패닉
- 커널 다시 빌드하기
$ make menulist #설정 다시 변경하기 $ make bzImage $ gedit cp.sh #아까 한 커널 설치 과정(파일 3개를 복사했었다.)을 쉘스크립트로 짬. #!/bin/bash sudo cp -a ./arch/i386/boot/bzImage /mnt/fs/boot/vmlinuz-2.6.20.6 sudo cp -a ./System.map /mnt/fs/boot sudo cp -a ./.config /mnt/fs/boot/ $ chmod +x cp.sh #만든 쉘스크립트를 실행파일로 바꿔줌. $ more cp.sh #쉘스크립트 내용 확인 #!/bin/bash sudo cp -a ./arch/i386/boot/bzImage /mnt/fs/boot/vmlinuz-2.6.20.6 sudo cp -a ./System.map /mnt/fs/boot sudo cp -a ./.config /mnt/fs/boot/ $ ./cp.sh #스크립트 실행, 복사가 되고 커널이 설치 되었다.
init 프로세스(/sbin/init) 생성
init프로세스는 busybox를 빌드하고 target으로 인스톨했을때 /sbin/init으로 이미 생성되었다.(busybox는 init을 지원한다.)
실수로 /boot를 지우다
- 커널을 컴파일한 후 /mnt/boot 아래의 파일을 모두 지우고 다시 구성하려다 루트에 /boot를 지우고 말았다.
- 루트에 /boot 는 커널과 /boot/grub 에 GRUB 관련 파일들이 있다.
- 커널은 백업해 놓은 것이 있어서 복구했고 /boot/grub/menu.lst 는 다시 편집해서 만들었다.
- 그런데 /boot/grub 밑에 stage1 stage2 등의 파일을 복구하지 않아서 부팅시 GRUB에서 커널을 못찾는 상황이 발생했다.
시스템 복구
- rescue img 다운로드
http://www.sysresccd.org/Download
- rescue img를 cd로 굽기
- 구운 시디로 부팅
- 쉘이 뜨면 복구할 하드디스크의 파티션을 마운트
$ mount /dev/hda1 /mnt/hda1 #mount 장치 마운트할위치 $ cp /boot/grub/* /mnt/hda1/boot/grub #grub 디렉터리의 stage1 stage2등의 파일 복사
- 다시 부팅하면 GRUB에서 커널을 인식하고 잘 부팅된다.
USB Memory에 Embedded Linux System 구축하기
사용한 USB Memory : 삼성전자 Classic & Simple SUM-1GTB
- 양산된 USB Memory는 기본적으로 fat32 파일시스템이고 파티션은 만들어져 있지 않은 상태이다.
- 일반적으로 모든 작업은 언마운트 상태에서 진행한다. 언마운트시 USB전원까지 차단할 수 있으므로 주의
USB Memory 언마운트
- USB Memory를 꽂으면 자동으로 /media/usbdisk에 마운트 되는데 이를 해지하자.
$ sudo umount /media/usbdisk $ mount #언마운트 되었는지 확인 /dev/hda1 on / type ext3 (rw,errors=remount-ro) proc on /proc type proc (rw,noexec,nosuid,nodev) /sys on /sys type sysfs (rw,noexec,nosuid,nodev) varrun on /var/run type tmpfs (rw,noexec,nosuid,nodev,mode=0755) varlock on /var/lock type tmpfs (rw,noexec,nosuid,nodev,mode=1777) procbususb on /proc/bus/usb type usbfs (rw) udev on /dev type tmpfs (rw,mode=0755) devshm on /dev/shm type tmpfs (rw) devpts on /dev/pts type devpts (rw,gid=5,mode=620) lrm on /lib/modules/2.6.17-11-generic/volatile type tmpfs (rw) /dev/hda2 on /mnt/fs type ext3 (rw) binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw)
USB Memory를 초기화
- dd는 디스크를 통채로 카피하는 명령인데 0으로 된 zero라는 device를 sda device에 복사함으로써 디스크를 완전 삭제하는 것은 물론 MBR까지도 삭제하는 효과를 준다.
$ sudo dd if=/dev/zero of=/dev/sda dd: writing to `/dev/sda': No space left on device 1982465+0 records in 1982464+0 records out 1015021568 bytes (1.0 GB) copied, 392.869 seconds, 2.6 MB/s
USB Memory에 MBR을 설치
- 먼저 MBR을 설치하기 위한 패키지를 설치하고 USB Memory에 MBR을 설치한다.
$ sudo apt-get install mbr #mbr패키지 설치 $ sudo install-mbr /dev/sda #USB Memory에 MBR 설치 install-mbr:/dev/sda: No boot signature found. Use --force to override. #에러메시지 $ sudo install-mbr --force /dev/sda #force라는 옵션을 줘서 강제로 설치
USB Memory에 파티션 생성
- 일반적으로 양산된 Usb Memory는 파티션없는 상태에서 그냥 사용이 가능하지만 파티션이 없으면 GRUB이 설치되지 않으므로 fdisk명령으로 파티션을 만들어줘야 한다.
$ sudo fdisk /dev/sda Command (m for help): m Command action a toggle a bootable flag b edit bsd disklabel c toggle the dos compatibility flag d delete a partition l list known partition types m print this menu n add a new partition o create a new empty DOS partition table p print the partition table q quit without saving changes s create a new empty Sun disklabel t change a partition's system id u change display/entry units v verify the partition table w write table to disk and exit x extra functionality (experts only) Command (m for help): p #파티션 현황(파티션이 없는 것을 알 수 있다.) Disk /dev/sda: 1015 MB, 1015021568 bytes 32 heads, 61 sectors/track, 1015 cylinders Units = cylinders of 1952 * 512 = 999424 bytes Device Boot Start End Blocks Id System Command (m for help): n #새로운 파티션 만듦 Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-1015, default 1): 1 Last cylinder or +size or +sizeM or +sizeK (1-1015, default 1015): 1015 Command (m for help): p #파티션 현황(sda1으로 파티션이 만들어졌다.) Disk /dev/sda: 1015 MB, 1015021568 bytes 32 heads, 61 sectors/track, 1015 cylinders Units = cylinders of 1952 * 512 = 999424 bytes Device Boot Start End Blocks Id System /dev/sda1 1 1015 990609+ 83 Linux Command (m for help): w #변경사항 적용 및 종료 The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks.
USB Memory의 sda1파티션을 ext3 파일 시스템으로 포맷
mke2fs 1.39 (29-May-2006) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 123904 inodes, 247652 blocks 12382 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=255852544 8 block groups 32768 blocks per group, 32768 fragments per group 15488 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Writing inode tables: done Creating journal (4096 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 37 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override.
- ext3로 포맷되었는지 확인
$ sudo mkdir /mnt/usb #마운트 할 디렉터리 생성 $ sudo mount /dev/sda1 /mnt/usb #생성한 디렉터리로 마운트(마운트를 해야 파일시스템을 확인할 수 있다.) $ df -T Filesystem Type 1K-blocks Used Available Use% Mounted on /dev/hda1 ext3 40313964 4019300 34246780 11% / varrun tmpfs 257932 80 257852 1% /var/run varlock tmpfs 257932 0 257932 0% /var/lock procbususb usbfs 10240 116 10124 2% /proc/bus/usb udev tmpfs 10240 116 10124 2% /dev devshm tmpfs 257932 0 257932 0% /dev/shm lrm tmpfs 257932 17580 240352 7% /lib/modules/2.6.17-11-generic/volatile /dev/hda2 ext3 15646868 325208 14526848 3% /mnt/fs /dev/sda1 ext3 975016 17632 907856 2% /mnt/usb #ext3로 포맷되었음을 알 수 있다.
USB Memory에 Target에 만들어놓은 루트 파일시스템 복사
- 여기서 주의할 점은 lost+found 폴더는 옮기지 말아야 한다는 것이다. 이 폴더는 파티션에서 고유하게 만들어지는 것이므로 덮어쓰게 되면 에러가 나서 종료되거나 느려지는 등의 문제가 생긴다.
- lost+found 폴더를 제외하고 파일 복사를 하기 위해 쉘 스크립트를 이용하자.
$ sudo vi cp.sh $ ls cp.sh $ sudo chmod +x cp.sh $ more cp.sh #!/bin/bash sudo cp -a /mnt/fs/bin /mnt/fs/boot /mnt/fs/dev /mnt/fs/etc /mnt/fs/home /mnt/fs /lib /mnt/fs/linuxrc /mnt/fs/mnt /mnt/fs/opt /mnt/fs/proc /mnt/fs/root /mnt/fs/s bin /mnt/fs/tmp /mnt/fs/usr /mnt/fs/var /mnt/usb/ $ sudo ./cp.sh $ ls bin dev home linuxrc mnt proc sbin usr boot etc lib lost+found opt root tmp var
USB Memory의 MBR에 GRUB 인스톨
- USB Memory가 마운트 되어있지 않는 다면 반드시 마운트를 해야 한다. 왜냐하면 grub를 인스톨 할 때 명령어 중에 USB Memory의 루트디렉터리를 설정해 주는 부분이 있는데 그 명령으로 grub의 필수 파일들을 루트디렉터리의 /boot/grub에 복사하기 때문이다.
$ sudo mount /dev/sda1 /mnt/usb #마운트 $ sudo grub-install --root-directory=/mnt/usb /dev/sda #루트디렉터리 란에는 마운트된 경로 지정 Probing devices to guess BIOS drives. This may take a long time. Installation finished. No error reported. This is the contents of the device map /media/usbdisk/boot/grub/device.map. Check if this is correct or not. If any of the lines is incorrect, fix it and re-run the script `grub-install'. (fd0) /dev/fd0 (hd0) /dev/hda (hd1) /dev/sda #GRUB에서의 sda는 (hd1)으로 표기함을 알 수 있다. #그렇지만 나중에 menu.lst를 수정할때 USB Memory로 부팅할 때는 디바이스 순서가 바뀌기 때문에hd0으로 써줘야 한다.
menu.lst 작성
- 부팅하고 GRUB를 읽어들이고 나서 menu.lst 에 기록되어 있는 방법으로 부팅한다.
$ sudo gedit menu.lst $ more menu.lst default 1 timeout 5 title EmbeddedlinuxSystem, kernel 2.6.20.6 root (hd0,0) kernel /boot/vmlinuz-2.6.20.6 root=/dev/hda1
커널 패닉
- USB Memory로 부팅할 때 커널 패닉이 일어났다. USB Memory를 인식하도록 커널을 다시 빌드해야 한다.
커널 다시 빌드
USB Memory에 맞는 커널 빌드
- USB Memory를 인식하려면 SCSI와 USB 부분을 추가 해주어야 한다.
$ make menuconfig Device Drivers ---> SCSI device support ---> (Although SCSI will be enabled automatically when selecting USB Mass Storage, we need to enable disk support.) --- SCSI support type (disk, tape, CD-ROM) <*> SCSI disk support (Then move back a level and go into USB support) USB support ---> (This is the root hub and is required for USB support. If you'd like to compile this as a module, it will be called usbcore.) <*> Support for Host-side USB (Enable this option to see your USB devices in /proc/bus/usb. This is recommended.) [*] USB device filesystem (Select at least one of the HCDs. If you are unsure, picking all is fine.) --- USB Host Controller Drivers <*> EHCI HCD (USB 2.0) support < > OHCI HCD support <*> UHCI HCD (most Intel and VIA) support (Moving a little further down, we come to CDC and mass storage.) < > USB Modem (CDC ACM) support <*> USB Printer support <*> USB Mass Storage support (Then the HID bits. You have to select HID input support if you have a USB keyboard, mouse, joystick or any other USB input device) --- USB Input Devices <*> USB Human Interface Device (full HID) support [*] HID input layer support (If you have a USB Network Card like the RTL8150, you'll need this) USB Network Adapters ---> <*> USB RTL8150 based ethernet device support (EXPERIMENTAL) (If you have a serial to USB converter like the Prolific 2303, you'll need this) USB Serial Converter support ---> <*> USB Serial Converter support <*> USB Prolific 2303 Single Port Serial Driver (NEW)
http://www.gentoo.org/doc/en/usb-guide.xml
USB Memory가 작동하는지 실험
- Host 환경(/mnt/fs)의 커널(위에서 컴파일한)에서 USB장치를 인식하는지 실험해본다.
- Target의 파일시스템(/mnt/fs/boot)에 커널을 복사하고 그 파일시스템으로 부팅한 뒤 USB Memory를 꽂아 본다.
- Target의 파일시스템의 /mnt/fs/dev에 sda1파일이 없으면 복사한다.
- USB Memory가 인식이 되면 마운트 한다.
$ cd mnt $ mkdir usb #만약 디렉터리가 생성되지 않으면 GRUB MENU에서 커널부분 끝에 rw라고 적어준다. $ mount -t ext3 /dev/sda1 /mnt/usb #일반적인 방법으로 -t ext3부분을 빼면 마운트 되지 않는다.
자료출처 : http://physics.sejong.ac.kr/parallel/cgi-bin/moin.cgi/EmbeddedLinuxProject
'Application > Linux' 카테고리의 다른 글
VIM 개행문자 Unix <-> DOS <-> MacOS 변경 (0) | 2012.03.06 |
---|---|
cpp파일로 컴파일할 때 주의점 (0) | 2012.01.01 |
우분투에서 USB를 포맷하는 방법 (3) | 2011.12.31 |
Ubunut add-apt-repository 가 없을때 (0) | 2011.12.25 |
리눅스에서 NTFS 퀵포맷하기 (0) | 2011.10.20 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- USB Lecture
- Network Inspector
- Mabinogi
- Life News
- Reverse Engineering
- 야마꼬툰
- cartoon
- 막장로그
- wallpaper
- C#
- 나비효과
- Embedded System
- 3D Engine
- Assembly
- win32
- Military
- console
- diary
- 짤방 및 아이콘
- Linux
- WDB
- Information Processor
- Tech News
- humor
- 프리랜서로 살아남는 법
- Web Programming
- medical
- BadCode
- Battle
- network
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
글 보관함