Galaxy Note 10+ kvm 도전 실패기 - 2 (LineageOS 설치하기)
이전 포스트 에서 직접 빌드한 Kernel이 필요하다는 걸 확인했다. galaxy note 10+ 의 커널을 바꿀 수 있는 방법은 여러가지가 있지만, 나는 LineageOS를 이용하기로 했다. LineageOS는 안드로이드 기반 커스텀 펌웨어로, 지속적인 업데이트가 이루어지고 있고 무엇보다 설치 및 빌드 가이드가 상세하게 나와있다.
미리 빌드된 LineageOS 설치해보기
직접 커널을 빌드하기 전에, 먼저 미리 빌드된 LineageOS를 설치해보자. 이 과정을 성공해야 추후 직접 빌드한 LineageOS 설치에 실패했을 때, 핸드폰에는 문제가 없음을 확신하고 진행할 수 있을 것이다.
Bootloader Unlock
삼성 스마트폰에 커스텀 펌웨어를 올리고자 한다면 bootloader unlock 작업이 필수적이다. 해당 방법은 LineageOS 가이드에도 설명이 되어 있고, 갤럭시 노트10+ 루팅하기를 참조해도 된다.
LineageOS 펌웨어 받기
https://download.lineageos.org/devices/d2x/builds에서 note10+용 펌웨어를 다운로드 한다. 나는 가장 최신인 lineage-20.0-20240623-nightly-d2x-signed.zip
파일과 recovery.img
를 다운 받았다.
recovery.img 플래시하기
- 휴대폰의 전원을 종료한다.
- 전원이 종료된 상태에서 볼륨 업과 볼륨 다운키를 누른채로 휴대폰 케이블을 컴퓨터와 연결한다.
- 경고문이 뜨는 것을 확인하고 볼륨업키를 짧게 눌러준다. (다운로드 모드 진입)
- 컴퓨터에서 다음 명령어를 수행한다.
1 2
sudo apt install heimdall-flash heimdall flash --RECOVERY recovery.img --no-reboot
RECOVERY upload successful
문구가 뜨는 것을 확인하고 케이블을 제거한다.- 볼륨다운키와 전원키를 길게 눌러 휴대폰을 종료한다.
- 화면이 꺼지자 마자 케이블을 연결하고, 볼륨상키와 전원키를 길게 눌러준다.
- 휴대폰이 리커버리 모드로 진입하고 LineageOS 로고가 나타나게 된다.
LineageOS 펌웨어 설치하기
정상적으로 진행되었다면 LineageOS 리커버리 모드에 진입해 있을 것이다.
- ‘Factory reset’ -> ‘Format data/factory reset’을 수행한다.
- ‘Apply update’ -> ‘Apply from ADB’를 선택한다.
- 다음 명령어로 설치한다.
1
adb -d sideload lineage-20.0-20240623-nightly-d2x-signed.zip
- 설치가 완료되면 ‘Reboot system now’를 선택하자.
LineageOS가 정상적으로 실행된다! wow!
LineageOS 빌드하기
이제 직접 커널을 빌드해서 올릴 차례이다. LineageOS는 모든 소스코드를 공개하고 있고, 여기에는 당연히 커널도 포함되어 있다. Lineage OS 빌드 가이드를 따라 진행해 보도록 하자.
필수 tool 설치
apt를 통해 설치한다.
1
sudo apt install bc bison build-essential ccache curl flex g++-multilib gcc-multilib git git-lfs gnupg gperf imagemagick lib32readline-dev lib32z1-dev libelf-dev liblz4-tool libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev libwxgtk3.0-dev openjdk-11-jdk python3
repo command 설치하기
1
2
curl https://storage.googleapis.com/git-repo-downloads/repo > /usr/bin/repo
chmod a+x /usr/bin/repo
git configure
1
git lfs install
LineageOS 소스코드 받기
1
2
3
4
mkdir -p ~/android/lineage
cd ~/android/lineage
repo init -u https://github.com/LineageOS/android.git -b lineage-20.0 --git-lfs
repo sync
device-specific code 준비하기
proprietary blobs을 추출해야 한다고 한다. LineageOS가 설치된 핸드폰을 연결하고 다음 명령어를 실행한다.
1
2
cd ~/android/lineage/device/samsung/d2x
./extract-files.sh
이어서 빌드 셋업을 한다.
1
2
3
cd ~/android/lineage
source build/envsetup.sh
breakfast d2x
빌드 및 설치하기
1
2
croot
brunch d2x
빌드가 완료되면 ~/android/lineage/out/target/product/d2x
디렉토리에 lineage-20.0-20240628-UNOFFICIAL-d2x.zip
같은 파일이 생성된 것을 확인할 수 있다. “LineageOS 펌웨어 설치하기”의 3번과 같이 adb -d sideload를 통해 설치하면 된다.
KVM config ON 해보기
lineage source code를 뒤져보면 ~/android/lineage/kernel/samsung/exynos9820/
디렉토리에 커널 소스코드가 존재하는 것을 확인할 수 있다. note10+에 수정한 커널을 올릴 수 있는 테스트 환경을 구축한 것이다. 특히 ~/android/lineage/kernel/samsung/exynos9820/arch/arm64/configs/exynos9820-d2x_defconfig
파일이 우리 커널의 default config를 담당하고 있다. 혹시 모르니 KVM 옵션을 다 켜서 테스트 해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CONFIG_HAVE_KVM=y
CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_IRQFD=y
CONFIG_HAVE_KVM_IRQ_ROUTING=y
CONFIG_HAVE_KVM_DIRTY_RING=y
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
CONFIG_NEED_KVM_DIRTY_RING_WITH_BITMAP=y
CONFIG_HAVE_KVM_EVENTFD=y
CONFIG_KVM_MMIO=y
CONFIG_HAVE_KVM_MSI=y
CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT=y
CONFIG_KVM_VFIO=y
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
CONFIG_HAVE_KVM_IRQ_BYPASS=y
CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE=y
CONFIG_KVM_XFER_TO_GUEST_WORK=y
CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y
CONFIG_KVM_ARM_HOST=y
위 옵션들을 defconfig에 추가한 후, LineageOS를 다시 빌드한다.
결과는…?
adb를 통해 LineageOS shell을 켜준다. 참고로 LineageOS는 개발자 옵션에서 “USB debugging”과 함께 “Rooted debugging”을 함께 제공한다. “Rooted debugging”이 켜져 있을 때 adb root
명령어를 사용하면 sudo권한을 가진 채로 adb shell
을 실행할 수 있다. adb shell
을 실행한 뒤 /dev 디렉터리에 kvm이 존재하는지 확인한다.
1
2
d2x:/ # ls -l /dev | grep kvm
d2x:/ #
당연히 아무것도 안 뜬다…
kvm 옵션이 제대로 켜졌는지 확인해 보자.
1
2
3
adb pull /proc/config.gz .
gzip -d config.gz
cat config | grep -i kvm
다행인지 모르겠지만 kvm 옵션들은 정상적으로 켜져 있었다. kvm 옵션은 켜졌지만, kernel이 kvm을 지원하지 않는다고 판단한 듯하다. 아무래도 프로세서가 EL2를 지원하는지 확인하는게 먼저인 듯 하다.. Galaxy Note 10+ kvm 도전기 - 1 (processor 지원 여부 확인하기)에서 확인한 것처럼 kernel module에서 assembly 명령어를 통해 id_aa64pfr0_el1
레지스터 값을 확인해 보아야 한다.
id_aa64pfr0_el1 값 확인하기
1
2
[38836.393229] hypervisor_check: loading out-of-tree module taints kernel.
[38836.393474] id_aa64pfr0_el1: 0x10112222
cortex-a75 공식 매뉴얼에 따르면 id_aa64pfr0_el1
의 EL2 handling, [11:8]
의 값의 의미는 다음과 같다.
EL3 handling, [15:12] EL3 exception handling: 0x2 Instructions can be executed at EL3 in AArch64 or AArch32 state.
EL2 handling, [11:8] EL2 exception handling: 0x2 Instructions can be executed at EL3 in AArch64 or AArch32 state.
EL1 handling, [7:4] EL1 exception handling. The possible values are: 0x2 Instructions can be executed at EL3 in AArch64 or AArch32 state.
EL0 handling, [3:0] EL0 exception handling. The possible values are: 0x2 Instructions can be executed at EL0 in AArch64 or AArch32 state.
매뉴얼에는 EL3라고 되어 있는데, 다른 프로세서 매뉴얼에서는 EL2라고 되어 있는 거 보면 오타인 듯하다.
Kernel module로 빌드하기
Galaxy Note 10+ kvm 도전기 - 1 (processor 지원 여부 확인하기)에서 만든 linux kernel module을 빌드해보자.
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
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/printk.h>
static inline uint64_t read_id_aa64pfr0_el1(void) {
uint64_t value;
asm volatile("mrs %0, id_aa64pfr0_el1" : "=r" (value));
return value;
}
static int __init hypervisor_check_init(void) {
uint64_t id_aa64pfr0_el1 = read_id_aa64pfr0_el1();
printk("id_aa64pfr0_el1: 0x%llx", id_aa64pfr0_el1);
return 0;
}
static void __exit hypervisor_check_exit(void) {
printk("Hypervisor check module exited.");
}
module_init(hypervisor_check_init);
module_exit(hypervisor_check_exit);
MODULE_LICENSE("GPL");
1
2
3
4
5
6
7
make \
ARCH=arm64 \
CROSS_COMPILE=aarch64-linux-gnu- \
-C /path/to/lineage/kernel/samsung/exynos9820 \
O=/path/to/lineage/out/target/product/d2x/obj/KERNEL_OBJ \
M=$(pwd) \
modules
위의 명령어로 빌드하면 O path에 존재하는 kernel config에 맞춰서 빌드된다. 빌드가 성공적으로 완료되면 hypervisor_check.ko 파일을 확인할 수 있다.
모듈 실행
adb로 ko 파일을 핸드폰에 옮겨서 실행해보도록 하자.
1
2
3
4
5
adb root
adb push hypervisor_check.ko /data/local/tmp
adb shell
cd /data/local/tmp
insmod hypervisor_check.ko
dmesg에 다음과 같은 결과가 나왔다.
1
[51122.742131] id_aa64pfr0_el1: 0x10112222
EL2 handling, [11:8] 값이 0x10이다. Galaxy Note 10+의 프로세서는 EL2모드를 지원한다..! 이제 믿음을 가지고 kernel을 수정해서 kvm을 활성화시키는 작업을 해보자.
3편에서 계속…