Galaxy Note 10+ kvm 도전 실패기 - 1 (processor 지원 여부 확인하기)
개발하다 보면 Arm 기반 프로세서에서도 테스트해 봐야 하는 상황이 종종 생긴다. 여태껏 QEMU Emulation을 통해 x86머신에서 테스트를 진행해 오긴 했지만, 아무래도 kvm을 쓸 수 없다 보니 너무 느리고 답답하다. Mac PC를 쓰면 된다지만, 1년에 한두 번 쓰자고 사기엔 Mac은 너무 비싸다…. 고민하던 중 놀고 있던 Galaxy Note 10+가 눈에 들어왔다. Arm-v8기반 CPU에 12G라는 넉넉한 RAM까지. kvm만 사용할 수 있다면 ubuntu는 물론 window까지도 쉽게 올려서 test 해볼 수 있을 것이다. 난이도가 굉장히 높을 건 알았지만, 반쯤은 재미로 Galaxy Note 10+에서 kvm을 활성화하는 데에 도전해 보았다.
Processor Support
일단 무엇보다도 processor가 하드웨어 가상화 지원해야 한다. 갤럭시 노트10+는 Exynos 9825라는 SoC를 사용하고 있다. Exynos 9825는 ARM Cortex-A75, ARM Cortex-A55 cpu를 사용한다. 둘 다 ARM-v8에 해당하며, ARM-v8은 대부분 하드웨어 가상화를 지원한다고 한다. 하지만 “Galaxy Note 10+ Processor가 하드웨어 가상화를 지원한다”라는 공식 문서 같은 건 찾을 수 없었다. 이에 직접 ARM spec문서를 찾아보았다.
ARM Cortex-A55 spec 페이지에 따르면, ID_AA64MMFR1_EL1 레지스터의 8~11 bit을 읽으면 Virtualization Host Extensions Support를 알 수 있다고 한다.
VH, [11:8]
Indicates whether Virtualization Host Extensions are supported.
0x1 Virtualization Host Extensions supported.
그런데 문제는, 해당 레지스터 Exception Level 1 이상에서만 읽을 수 있다는 것이다.
ARM Exception Level은 프로세서의 실행 권한을 나타낸다. EL0, EL1, EL2, EL3 순으로 권한이 강해진다. EL0는 사용자 모드를 의미하고, EL1은 커널모드를 의미한다. EL2는 hypervisor모드로 가상화를 관리하는 모드이다. kvm을 지원할 수 있는지는 EL2모드를 지원하는지 알아내는 것과도 같다.
따라서 해당 레지스터를 읽기 위해서는 kernel mode에서 실행해야 한다. 간단히 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");
Makefile도 작성한다.
1
obj-m += hypervisor_check.o
arm에서 돌릴 거니까 CROSS_COMPILE까지 야무지게 해줘야 한다.
1
2
3
4
5
make \
ARCH=arm64 \
CROSS_COMPILE=aarch64-linux-gnu- \
...
make 명령어를 적다가 머리를 스치는 생각이 있다. linux kernel은 기본적으로 버전이 불일치하는 모듈을 받아주지 않는다. 심지어 버전이 맞더라도 compiler가 다른 것도 안 받아준다. (clang vs gcc) 나는 note 10+에 어떤 버전의 커널이 깔려있는지도 모르고, 정품 펌웨어가 어떻게 커널을 빌드했는지는 더더욱 알 리가 없다…
결국 핸드폰의 커널부터 전부 갈아엎기로 했다. (본격 배보다 배꼽 시리즈 시작…)
2편에서 계속…