Gentoo on UEFI-based computer

Gentoo Korea Wiki
Alchemist (토론 | 기여)님의 2013년 8월 10일 (토) 12:50 판 (→‎젠투 리눅스 설치에서 부팅까지)
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)
둘러보기로 가기 검색하러 가기

개요

최근, 대부분의 메인보드에는 UEFI(Unified Extensible Firmware Interface)라고 불리는, 기존의 BIOS와는 다른, 펌웨어가 탑재되어 출시된다. UEFI-펌웨어는 직접 OS kernel을 로드할 수 있는 부팅매니저를 포함하고 있다. 따라서, UEFI 기반으로 시스템을 부팅하려고 한다면, 기존의 BIOS 기반으로 제작된 부트로더, 부팅매니저등은 사용할 수 없고, 사용할 필요도 없다. UEFI-펌웨어가 시스템을 부팅하는 구체적인 메커니즘은 다른 페이지를 참고하도록 하고, 여기서는 젠투 리눅스 배포판을 UEFI 기반으로 부팅하기까지 과정을 알아본다. 본 문서는 GRUB이라는 부트로더를 사용할 줄 모르고, UEFI-펌웨어가 탑재된 보드를 사용하는 사람에게 최적(?)의 문서가 될 것이다.

젠투 리눅스 설치에서 부팅까지

아래 설치 과정을 무작정 따라하기 보다, 아웃라인을 잡고 시작하기를 권장한다. 그러면 이 문서에 나온 시나리오를 개인의 취향에 맞게 개선할 수 있을 것이다. 또한 시작에 앞서 overview를 권고함은 이 문서는 진행과정에서 의도적으로 실수를 범하고 있기 때문이다.

먼저 언제나 그렇듯, gentoo livecd와 stage3 tar ball, 최신 portage tar ball을 미러서버에서 다운받고 시작하도록 한다. 시스템 아키텍쳐별로 livecd, stage3이 같은 디렉토리에서 배포되고, portage tar ball은 snapshot이란 디렉토리에서 배포되고 있다.

http://ftp.daum.net/gentoo/releases/

이 문서에서는 Gentoo livecd는 LiveDVD가 아닌 minimal을 사용하였다. 요즘 환경에서 iso를 physical-CD에 굽는 경우는 드물 것이고, 아마도 부팅가능한 USB 플래시 드라이브를 제작하고 싶을 것이다. UNetbootin이라는 툴을 사용하면 iso 이미지를 가지고 간단하게 bootable UFD(USB Flash Drive)를 제작할 수 있다.

http://unetbootin.sourceforge.net/

OSX 환경 사용자는 이 툴을 사용하여 제작된 UFD가 정상적으로 부팅되지 않을 수 있다. 그럴 경우는 다음 처리를 해주어야 한다.

osx ~ $ diskutil list # 주의! USB 디스크 번호 확인

osx ~ $ sudo fdisk -e /dev/rdisk1 # /dev/disk1이 아니다

fdisk: 1> p

1: 0B 1023 254 63 - 1023 254 63 [ 2 - 18555416] Win95 FAT-32

fdisk:*1> f 1

fdisk:*1> p

*1: 0B 1023 254 63 - 1023 254 63 [ 2 - 18555416] Win95 FAT-32

fdisk:*1> w

fdisk: 1> exit

젠투 livecd로 부팅을 하게 되면 dmesg, lspcils* 유틸리티를 비롯하여,

livecd ~ # more /proc/cpuinfo

등을 통해 시스템의 하드웨어 정보를 얻을 수 있다. 시스템 시간(date)을 설치과정에서 고치려면 가장 처음에 고칠 것을 권장한다.

livecd ~ # date MMDDhhmmYYYY

Alt+F2 혹은 Alt+방향키 등으로 여러개의 프레임 버퍼를 띄워두고 작업을 진행 할 수 있다.

콘솔작업보다는 ssh 접속을 통한 터미널작업을 추천한다.

livecd ~ # ifconfig

livecd ~ # # ip 주소가 잡혀있지 않은 경우에는 `net-setup' 스크립트로 네트워크를 설정한다.

livecd ~ # # net-setup eth0 && ifconfig

livecd ~ # # LAN 환경에 dhcp 서버가 있다면 `dhcpcd eth0'을 명령하면 쉽게 ip를 발급받을 수 있다.

livecd ~ # ping -c3 www.gentoo.org

livecd ~ # /etc/init.d/sshd start && passwd

나는 콘솔에서 모든 것을 끝내버리겠다(?)한다면, CapsLock키를 Ctrl키로 매핑하여 사용하는 것이 도움이 될 것이다.

livecd ~ # emacs /etc/conf.d/keymaps
keymap="emacs"

livecd ~ # /etc/init.d/keymaps restart

위와 같이 설정하면, CapsLock키를 Ctrl키로 사용할 수 있을 것이다. 참고로 C-a/e, C-f/b, M-f/b, C-t, C-p/n등, 다양한 이맥스 키바인딩은 bash, csh와 같은 표준적인 쉘에서 여전히 유효하다.

다음으로 할 작업은 디스크 편집과정이다. 따라서 데이터 유실과 같은 사항은 각별히 유의하여야 한다. 본 문서에서는 시스템 운용에 두 개의 블록 디스크 장치를 사용하여, 하나는 젠투의 root가 설치되고, 나머지 하나는 /home에 마운트 될 것이다. 이 때, UEFI 기반에서 젠투를 부팅하려 한다면, 반드시 ESP(EFI System Partition)가 하나 이상의 디스크에 존재해야 한다. 또 반드시 ESP는 파티션 테이블 상에서 첫번째 파티션이어야 한다.

livecd ~ # parted -l

livecd ~ # parted /dev/sda # gentoo root가 설치될 디스크

(parted) mklabel gpt

(parted) mkpart EFI fat32 0% 210m # help 메세지에는 PART-TYPE으로 3가지 중 하나만 쓰라고 했지만, 이는 partition table의 name 컬럼에 불과하다.

(parted) mkpart primary linux-swap 210m 710m

(parted) mkpart primary xfs 710m 100%

(parted) set 1 boot on # 1st partition을 ESP로 지정. fdisk의 boot flag와는 다르고, gdisk에서의 part-type code `EF00'와 같다.

(parted) print

(parted) select /dev/sdb

(parted) mklabel gpt

(parted) mkpart primary xfs 0% 100%

(parted) print

(parted) quit

livecd ~ # mkfs.vfat -n"efi" -F32 /dev/sda1

livecd ~ # mkswap -L"swap" /dev/sda2 && swapon LABEL=swap

livecd ~ # mkfs.xfs -L"gentoo" -f /dev/sda3

livecd ~ # mkfs.xfs -L"home" -f /dev/sdb1 #

디스크 파티션 테이블 수정과 각 파티션에 파일시스템까지 올렸다. 이제 젠투 root가 설치될 파티션을 마운트하여 stage3, portage tar ball을 풀고, chroot으로 새 젠투 시스템에 진입한다.

livecd ~ # mount LABEL=gentoo /mnt/gentoo && cd /mnt/gentoo

livecd gentoo # time tar /mnt/cdrom/xvjf stage3.tar.bz2 && ls

livecd gentoo # time tar xvjf /mnt/cdrom/portage.tar.bz2 -C./usr/ && ls

livecd gentoo # mount -t proc /proc /mnt/gentoo/proc

livecd gentoo # mount --rbind /sys /mnt/gentoo/sys

livecd gentoo # mount --rbind /dev /mnt/gentoo/dev

livecd gentoo # mount LABEL=home /mnt/gentoo/home

livecd gentoo # cp -L /etc/resolv.conf ./etc/

livecd gentoo # chroot ./ /bin/bash

livecd / # env-update && source /etc/profile

livecd / # export PS1="(chroot) $PS1"

(chroot) livecd / # passwd

다음은 커널 컴파일까지 과정이다. UEFI 기반으로 부팅이 되려면 반드시 알맞은 커널 설정을 해주어야 한다.

(chroot) livecd / # eselect profile list

(chroot) livecd / # eselect profile set <n>

(chroot) livecd / # nano -w /etc/portage/make.conf # make.conf 설정은 개인 취향에 맞게 설정. 본문에서는 다음과 같이 썼다.

CHOST="x86_64-pc-linux-gnu"
CFLAGS="-O2 -march=native -pipe"
CXXFLAGS="${CFLAGS}"
MAKEOPTS="-j5"
LINGUAS="en ko"

(chroot) livecd / # mount -t tmpfs -o size=2G none /var/tmp/portage

(chroot) livecd / # emerge -av mirrorselect

(chroot) livecd / # mirrorselect -o -i >> /etc/portage/make.conf

(chroot) livecd / # mirrorselect -o -i -r >> /etc/portage/make.conf

(chroot) livecd / # emerge --sync

(chroot) livecd / # emerge genkernel gentoo-sources && cd /usr/src/linux

(chroot) livecd linux # make menuconfig

커널 설정에서 다음 작업은 반드시 해야한다.

Processor type and features  --->
    [*] EFI runtime service support
    [*]   EFI stub support
    [*] Build a relocatable kernel
Device Drivers  --->
    Graphics support --->
        <*> Support for frame buffer devices  --->
            [*]   Enable firmware EDID
            [*]   EFI-based Framebuffer Support
        Console display driver support  --->
            <*> Framebuffer Console support
Firmware Drivers  --->
    <*> EFI Variable Support via sysfs
-*- enabler the block layer --->
    Partition Types  --->
        [*]   EFI GUID Partition support

혹은 /usr/src/linux/.config를 직접 수정한다고 하면 다음 커널옵션이 활성화되어 있는지 확인한다.

CONFIG_EFI=y
CONFIG_EFI_STUB=y
CONFIG_RELOCATABLE=y
CONFIG_FIRMWARE_EDID=y
CONFIG_FB_EFI=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_EFI_VARS=y
CONFIG_EFI_PARTITION=y

또 한가지 주의할 사항은 UEFI는 커널과 분리된 initramfs를 로드할 수 없다. 따라서 initramfs를 쓰려고 한다면, 커널에 built-in 되어 있어야 한다. genkernel을 쓰게되면, 커널설정에 기본으로 initramfs를 쓰는 것으로 되어 있으니 이 부분도 반드시 확인해야 하는 부분이 되겠다.

General setup  --->
    [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
    (/boot/initramfs.cpio) Initramfs source file(s)

위의 설정 중 두번째 줄의 /boot/initramfs.cpio는 커널에 built-in 될 initramfs 소스파일이다. 이 소스파일은 반드시 압축되지 않은 CPIO 파일이어야 한다. /boot/initramfs.cpio 다음과 같이 만든다.

(chroot) livecd linux # genkernel initramfs

(chroot) livecd linux # xzcat /boot/initramfs-genkernel* > /boot/initramfs.cpio

(chroot) livecd linux # file /boot/initramfs.cpio

/boot/initramfs.cpio: ASCII cpio archive (SVR4 with no CRC)

(chroot) livecd linux # rm /boot/initramfs-genkernel*

/boot/initramfs.cpio가 만들어지고 나면, 이제 커널을 빌드하고, 빌드된 커널을 UEFI-펌웨어에 내장된 부팅매니저가 로드할 수 있는 위치(ESP)에 설치한다.

(chroot) livecd linux # genkernel kernel

(chroot) livecd linux # mount LABEL=efi /boot

(chroot) livecd linux # mkdir -p /boot/efi/gentoo

(chroot) livecd linux # cp arch/x86/boot/bzImage /boot/efi/gentoo/gentoox64.efi

이제 efibootmgr라는 유틸리티로 [젠투 시스템의 UEFI 기반 부팅]을 설정을 해야하는데 한가지 문제가 있다. 본 문서에서 livecd는 BIOS 기반으로 부팅되었고, 따라서 현재 livecd의 커널은 위에서 언급된 CONFIG_EFI_VARS라고 하는, 즉 EFI 변수를 알고 있지 않다.

(chroot) livecd linux # emerge -av efibootmgr

(chroot) livecd linux # efibootmgr # efivars를 불러 올 수 없다는 메세지를 출력할 것이다.

어떻게든 UEFI 기반으로 젠투 시스템을 부팅하여 efibootmgr가 efivars를 불러 올 수 있기만 하면 된다. 운이 좋게도 이 문제를 해결해 줄 수 있는 EFI-shell 바이너리가 있다.

https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2/ShellBinPkg/UefiShell/X64/Shell.efi

위 링크에서 EFI-shell 바이너리를 다운 받고, 적당히 아무 FAT32로 포맷된 UFD의 최상위 위치에 넣고, UEFI-펌웨어에서 EFI-shell를 실행한다. 메인보드마다 UEFI-펌웨어가 달라서 EFI-shell로 실행하는 방법이 다를 것이다. 본 문서를 작성한 사람의 보드에서는 FAT32 미디어의 최상위 위치에 Shellx64.efi라는 파일만 EFI-shell로 인정(?)한다. 좀 더 우월한(?) 보드는 UEFI-펌웨어에서 [EFI-shell 실행하기]란 메뉴를 선택하면 EFI-shell의 위치를 선택할 수 있는 인터페이스를 제공하기도 한다.

먼저 EFI-shell를 실행하기 전, chroot 환경을 빠져나가야 하는데, 다음을 마무리한다.

(chroot) livecd linux # nano -w /etc/fstab

LABEL=efi       /boot             vfat      noauto,noatime  1 2
LABEL=swap      none              swap      sw              0 0
LABEL=gentoo    /                 xfs       defaults        0 1
LABEL=home      /home             xfs       auto            0 0
tmpfs           /var/tmp/portage  tmpfs     size=2G         0 0

(chroot) livecd linux # emerge syslog-ng vixie-cron xfsprogs dhcpcd

(chroot) livecd linux # rc-update add syslog-ng default

(chroot) livecd linux # rc-update add sshd default

(chroot) livecd linux # exit

livecd gentoo # umount -l /mnt/gentoo/{proc,sys,dev,home,boot}

livecd gentoo # umount -l /mnt/gentoo

livecd gentoo # reboot

UEFI-펌웨어로 진입하여 EFI-shell를 실행하고 나면, fs0:는 EFI-shell 바이너리가 저장된 볼륨이고, 아마도 위에서 빌드한, EFI-stub를 지원하는 커널이 위치한(/dev/sda1) 볼륨은 fs1:일 것이다. EFI-shell에서 커널을 로드하여 UEFI 기반으로 젠투 시스템을 부팅해본다.

2.0 Shell> fs1:

fs1:> \efi\gentoo\gentoox64.efi

커널 로드가 완료되면 커널은 어떤 파티션을 루트로 쓸 것인지 물어본다. 이것은 grub 부트로더가 커널에 전달했던 real_root=명령부분과 같다. 본 문서는 /dev/sda3에 설치하였다.

드디어 처음으로 젠투 시스템을 UEFI에 기반해서 부팅하였다. livecd 환경에서 사용할 수 없었던 efibootmgr 유틸리티는 이제 사용할 수 있다.

gentoo ~ # efibootmgr # -v 옵션을 써보면 efibootmgr의 가능성을 확인할 수 있다.

gentoo ~ # efibootmgr -c -g -d /dev/sda -p1 -L"UEFI:Gentoo" -l"\efi\gentoo\gentoox64.efi"

위 두번째 명령줄이 UEFI 기반으로 젠투 시스템을 별도의 부트로더 없이 바로 부팅할 수 있게 해준다. efibootmgr는 UEFI-펌웨어에서 지정하는 boot-order를 OS에서 직접 편집할 수 있는 유틸리티이다.

이것으로 젠투 리눅스를 UEFI에 기반해서 안전하게 부팅할 수 있게 되었다.

한가지 귀찮은 문제가 남았다고 한다면, UEFI를 기반해서 젠투를 부팅할 때, 매번 커널은 어떤 파티션을 루트로 쓸 지 물어보는 것이 있다. 이는 커널옵션(CONFIG_CMDLINE)에 어떤 파티션을 루트로 쓸 지 미리 써두는 것으로 해결할 수 있다.

gentoo ~ # blkid # /dev/sda3의 UUID를 적어둔다.

...

/dev/sda3: LABEL="gentoo" UUID="467c4aa9-963d-4467-8cd0-d58caaacaff4" TYPE="xfs"

...

gentoo ~ # genkernel --menuconfig bzImage

Processor type and features  --->
    [*] Built-in kernel command line
    (root=UUID=467c4aa9-963d-4467-8cd0-d58caaacaff4)

gentoo ~ # cp /usr/src/linux/arch/x86/boot/bzImage /boot/efi/gentoo/gentoox64.efi