├── scratchlab.jpg ├── module ├── mkdev.sh ├── guest.h ├── Makefile ├── hrbs.py ├── peach.h ├── vmexit_handler.S └── peach_intel.c ├── Makefile ├── guest ├── guest.S └── Makefile ├── README.md └── main.c /scratchlab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pandengyang/peach/HEAD/scratchlab.jpg -------------------------------------------------------------------------------- /module/mkdev.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -f /dev/peach 4 | mknod /dev/peach c 511 0 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | peach: main.c module/peach.h 2 | gcc -o peach main.c -I./module 3 | 4 | .PHONY: clean 5 | 6 | clean: 7 | rm -rf peach 8 | -------------------------------------------------------------------------------- /module/guest.h: -------------------------------------------------------------------------------- 1 | unsigned char guest_bin[] = { 2 | 0xb8, 0x00, 0x00, 0x0f, 0xa2, 0x2d, 0x20, 0x20, 0x81, 0xeb, 0x20, 0x20, 3 | 0x81, 0xe9, 0x20, 0x20, 0xf4 4 | }; 5 | unsigned int guest_bin_len = 17; 6 | -------------------------------------------------------------------------------- /guest/guest.S: -------------------------------------------------------------------------------- 1 | .code16gcc 2 | .text 3 | .globl _start 4 | .type _start, @function 5 | 6 | _start: 7 | mov $0x0000, %ax 8 | cpuid 9 | sub $0x2020, %ax 10 | sub $0x2020, %bx 11 | sub $0x2020, %cx 12 | 13 | hlt 14 | -------------------------------------------------------------------------------- /module/Makefile: -------------------------------------------------------------------------------- 1 | PWD := $(shell pwd) 2 | 3 | obj-m += peach.o 4 | peach-objs := peach_intel.o vmexit_handler.o 5 | 6 | all: 7 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 8 | 9 | clean: 10 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 11 | -------------------------------------------------------------------------------- /guest/Makefile: -------------------------------------------------------------------------------- 1 | guest.bin: guest.S 2 | gcc -nostdinc -c guest.S -o guest.o 3 | ld -Ttext=0x00 -nostdlib -static guest.o -o guest.elf 4 | objcopy -O binary guest.elf guest.bin 5 | xxd -i guest.bin > ../module/guest.h 6 | 7 | .PHONY: clean 8 | 9 | clean: 10 | rm -rf guest.o guest.elf guest.bin 11 | -------------------------------------------------------------------------------- /module/hrbs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | '''human readable bits''' 4 | 5 | import sys 6 | 7 | if len(sys.argv) != 2: 8 | print("hrbs hex\n") 9 | print(" eg: hrbs 0x01\n") 10 | 11 | exit(-1) 12 | 13 | bits = format(int(sys.argv[1], 16), '064b') 14 | 15 | for i in range(64, 0, -1): 16 | print("{0}\t{1}".format(i - 1, bits[64 - i])) 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 关于 2 | 3 | 桃花源(英文名为 peach)是一个迷你虚拟机,用于学习 Intel 硬件虚拟化技术。学习该项目可使读者对 CPU 虚拟化、内存虚拟化技术有个感性、直观的认识,为学习 KVM 打下坚实的基础。peach 实现了如下功能: 4 | 5 | * 使用 Intel VT-x 技术实现 CPU 虚拟化 6 | * 使用 EPT 技术实现内存虚拟化 7 | * 支持虚拟 x86 实模式运行环境 8 | * 支持虚拟 CPUID 指令 9 | * 支持虚拟 HLT 指令,Guest 利用 HLT 指令关机 10 | 11 | 关于 peach 的详细讲解,请阅读微信公众号 ScratchLab 文章《自己动手写虚拟机(一)》: 12 | 13 | ![微信搜一搜 ScratchLab](scratchlab.jpg) 14 | -------------------------------------------------------------------------------- /module/peach.h: -------------------------------------------------------------------------------- 1 | #ifndef __PEACH_H__ 2 | #define __PEACH_H__ 3 | 4 | #include 5 | 6 | #ifdef USERSPACE 7 | #include 8 | #define u64 uint64_t 9 | #define u32 uint32_t 10 | #define u8 uint8_t 11 | #else 12 | #include 13 | #endif 14 | 15 | #define PEACH_COUNT 1 16 | 17 | #define PEACH_MAJOR 511 18 | #define PEACH_MINOR 0 19 | 20 | #define PEACH_MAGIC 'M' 21 | #define PEACH_PROBE _IOR(PEACH_MAGIC, 0, u64) 22 | #define PEACH_RUN _IO(PEACH_MAGIC, 1) 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /module/vmexit_handler.S: -------------------------------------------------------------------------------- 1 | .code64 2 | .globl _vmexit_handler 3 | .type _vmexit_handler, @function 4 | 5 | _vmexit_handler: 6 | pushq %r15 7 | pushq %r14 8 | pushq %r13 9 | pushq %r12 10 | pushq %r11 11 | pushq %r10 12 | pushq %r9 13 | pushq %r8 14 | pushq %rdi 15 | pushq %rsi 16 | pushq %rbp 17 | pushq %rbx 18 | pushq %rdx 19 | pushq %rcx 20 | pushq %rax 21 | 22 | movq %rsp, %rdi 23 | callq handle_vmexit 24 | 25 | popq %rax 26 | popq %rcx 27 | popq %rdx 28 | popq %rbx 29 | popq %rbp 30 | popq %rsi 31 | popq %rdi 32 | popq %r8 33 | popq %r9 34 | popq %r10 35 | popq %r11 36 | popq %r12 37 | popq %r13 38 | popq %r14 39 | popq %r15 40 | 41 | vmresume 42 | 43 | ret 44 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define USERSPACE 1 10 | #include "peach.h" 11 | 12 | static int peach_fd; 13 | 14 | int main(int argc, char **argv) 15 | { 16 | int ret; 17 | 18 | cpu_set_t mask; 19 | 20 | CPU_ZERO(&mask); 21 | CPU_SET(1, &mask); 22 | if (-1 == sched_setaffinity(0, sizeof mask, &mask)) { 23 | printf("failed to set affinity\n"); 24 | 25 | goto err0; 26 | } 27 | 28 | if ((peach_fd = open("/dev/peach", O_RDWR)) < 0) { 29 | printf("failed to open Peach device\n"); 30 | 31 | goto err0; 32 | } 33 | 34 | if ((ret = ioctl(peach_fd, PEACH_PROBE)) < 0) { 35 | printf("failed to exec ioctl PEACH_PROBE\n"); 36 | 37 | goto err1; 38 | } 39 | 40 | if ((ret = ioctl(peach_fd, PEACH_RUN)) < 0) { 41 | printf("failed to exec ioctl PEACH_RUN\n"); 42 | 43 | goto err1; 44 | } 45 | 46 | printf("guest exits\n"); 47 | 48 | err1: 49 | close(peach_fd); 50 | 51 | err0: 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /module/peach_intel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "peach.h" 11 | #include "guest.h" 12 | 13 | MODULE_LICENSE("GPL"); 14 | MODULE_AUTHOR("ScratchLab"); 15 | 16 | static dev_t peach_dev; 17 | static struct cdev peach_cdev; 18 | 19 | static long peach_ioctl(struct file *file, 20 | unsigned int cmd, 21 | unsigned long data); 22 | static struct file_operations peach_fops = { 23 | .owner = THIS_MODULE, 24 | .unlocked_ioctl = peach_ioctl, 25 | }; 26 | 27 | struct vmcs_hdr { 28 | u32 revision_id:31; 29 | u32 shadow:1; 30 | }; 31 | 32 | #define VMX_SIZE_MAX 4096 33 | struct vmcs { 34 | struct vmcs_hdr hdr; 35 | u32 abort; 36 | char data[VMX_SIZE_MAX - 8]; 37 | }; 38 | 39 | static struct vmcs *vmxon; 40 | static struct vmcs *vmcs; 41 | 42 | static u8 *stack; 43 | 44 | #define GUEST_MEMORY_SIZE (0x1000 * 16) 45 | static u8 *guest_memory; 46 | 47 | #define EPT_MEMORY_SIZE (0x1000 * 4) 48 | static unsigned char *ept_memory; 49 | 50 | static void init_ept(u64 *ept_pointer, u64 guest_memory_pa); 51 | static void init_ept_pointer(u64 *p, u64 pa); 52 | static void init_pml4e(u64 *entry, u64 pa); 53 | static void init_pdpte(u64 *entry, u64 pa); 54 | static void init_pde(u64 *entry, u64 pa); 55 | static void init_pte(u64 *entry, u64 pa); 56 | 57 | void _vmexit_handler(void); 58 | 59 | struct guest_regs { 60 | u64 rax; 61 | u64 rcx; 62 | u64 rdx; 63 | u64 rbx; 64 | u64 rbp; 65 | u64 rsp; 66 | u64 rsi; 67 | u64 rdi; 68 | u64 r8; 69 | u64 r9; 70 | u64 r10; 71 | u64 r11; 72 | u64 r12; 73 | u64 r13; 74 | u64 r14; 75 | u64 r15; 76 | }; 77 | static void dump_guest_regs(struct guest_regs *regs); 78 | 79 | static u64 shutdown_rsp; 80 | static u64 shutdown_rbp; 81 | 82 | static int peach_init(void) 83 | { 84 | printk("PEACH INIT\n"); 85 | 86 | peach_dev = MKDEV(PEACH_MAJOR, PEACH_MINOR); 87 | if (0 < register_chrdev_region(peach_dev, PEACH_COUNT, "peach")) { 88 | printk("register_chrdev_region error\n"); 89 | 90 | goto err0; 91 | } 92 | 93 | cdev_init(&peach_cdev, &peach_fops); 94 | peach_cdev.owner = THIS_MODULE; 95 | 96 | if (0 < cdev_add(&peach_cdev, peach_dev, 1)) { 97 | printk("cdev_add error\n"); 98 | 99 | goto err1; 100 | } 101 | 102 | return 0; 103 | 104 | err1: 105 | unregister_chrdev_region(peach_dev, 1); 106 | 107 | err0: 108 | 109 | return -1; 110 | } 111 | 112 | static void peach_exit(void) 113 | { 114 | printk("PEACH EXIT\n"); 115 | 116 | cdev_del(&peach_cdev); 117 | unregister_chrdev_region(peach_dev, 1); 118 | 119 | return; 120 | } 121 | 122 | static long peach_ioctl(struct file *file, 123 | unsigned int cmd, 124 | unsigned long arg) 125 | { 126 | int i; 127 | 128 | u8 ret1; 129 | 130 | u32 edx, eax, ecx; 131 | u64 rdx; 132 | 133 | u64 vmcs_pa; 134 | u64 vmxon_pa; 135 | 136 | u8 xdtr[10]; 137 | u64 vmcs_field; 138 | u64 vmcs_field_value; 139 | 140 | u64 host_tr_selector; 141 | u64 host_gdt_base; 142 | u64 host_tr_desc; 143 | 144 | u64 ept_pointer; 145 | u64 guest_memory_pa; 146 | 147 | switch (cmd) { 148 | case PEACH_PROBE: 149 | printk("PEACH PROBE\n"); 150 | 151 | ecx = 0x480; 152 | asm volatile ( 153 | "rdmsr\n\t" 154 | : "=a" (eax), "=d" (edx) 155 | : "c" (ecx) 156 | ); 157 | printk("IA32_VMX_BASIC = 0x%08x%08x\n", edx, eax); 158 | 159 | ecx = 0x486; 160 | asm volatile ( 161 | "rdmsr\n\t" 162 | : "=a" (eax), "=d" (edx) 163 | : "c" (ecx) 164 | ); 165 | printk("IA32_VMX_CR0_FIXED0 = 0x%08x%08x\n", edx, eax); 166 | 167 | ecx = 0x487; 168 | asm volatile ( 169 | "rdmsr\n\t" 170 | : "=a" (eax), "=d" (edx) 171 | : "c" (ecx) 172 | ); 173 | printk("IA32_VMX_CR0_FIXED1 = 0x%08x%08x\n", edx, eax); 174 | 175 | ecx = 0x488; 176 | asm volatile ( 177 | "rdmsr\n\t" 178 | : "=a" (eax), "=d" (edx) 179 | : "c" (ecx) 180 | ); 181 | printk("IA32_VMX_CR4_FIXED0 = 0x%08x%08x\n", edx, eax); 182 | 183 | ecx = 0x489; 184 | asm volatile ( 185 | "rdmsr\n\t" 186 | : "=a" (eax), "=d" (edx) 187 | : "c" (ecx) 188 | ); 189 | printk("IA32_VMX_CR4_FIXED1 = 0x%08x%08x\n", edx, eax); 190 | 191 | ecx = 0x48D; 192 | asm volatile ( 193 | "rdmsr\n\t" 194 | : "=a" (eax), "=d" (edx) 195 | : "c" (ecx) 196 | ); 197 | printk("IA32_VMX_TRUE_PINBASED_CTLS = 0x%08x%08x\n", edx, eax); 198 | 199 | ecx = 0x48E; 200 | asm volatile ( 201 | "rdmsr\n\t" 202 | : "=a" (eax), "=d" (edx) 203 | : "c" (ecx) 204 | ); 205 | printk("IA32_VMX_TRUE_PROCBASED_CTLS = 0x%08x%08x\n", edx, eax); 206 | 207 | ecx = 0x48B; 208 | asm volatile ( 209 | "rdmsr\n\t" 210 | : "=a" (eax), "=d" (edx) 211 | : "c" (ecx) 212 | ); 213 | printk("IA32_VMX_PROCBASED_CTLS2 = 0x%08x%08x\n", edx, eax); 214 | 215 | ecx = 0x48F; 216 | asm volatile ( 217 | "rdmsr\n\t" 218 | : "=a" (eax), "=d" (edx) 219 | : "c" (ecx) 220 | ); 221 | printk("IA32_VMX_TRUE_EXIT_CTLS = 0x%08x%08x\n", edx, eax); 222 | 223 | ecx = 0x490; 224 | asm volatile ( 225 | "rdmsr\n\t" 226 | : "=a" (eax), "=d" (edx) 227 | : "c" (ecx) 228 | ); 229 | printk("IA32_VMX_TRUE_ENTRY_CTLS = 0x%08x%08x\n", edx, eax); 230 | 231 | ecx = 0x48C; 232 | asm volatile ( 233 | "rdmsr\n\t" 234 | : "=a" (eax), "=d" (edx) 235 | : "c" (ecx) 236 | ); 237 | 238 | ecx = 0x48C; 239 | asm volatile ( 240 | "rdmsr\n\t" 241 | : "=a" (eax), "=d" (edx) 242 | : "c" (ecx) 243 | ); 244 | printk("IA32_VMX_EPT_VPID_CAP = 0x%08x%08x\n", edx, eax); 245 | 246 | break; 247 | 248 | case PEACH_RUN: 249 | printk("PEACH RUN\n"); 250 | 251 | guest_memory = (u8 *) kmalloc(GUEST_MEMORY_SIZE, 252 | GFP_KERNEL); 253 | guest_memory_pa = __pa(guest_memory); 254 | 255 | for (i = 0; i < guest_bin_len; i++) { 256 | guest_memory[i] = guest_bin[i]; 257 | } 258 | 259 | init_ept(&ept_pointer, guest_memory_pa); 260 | 261 | vmxon = (struct vmcs *) kmalloc(4096, GFP_KERNEL); 262 | memset(vmxon, 0, 4096); 263 | vmxon->hdr.revision_id = 0x00000001; 264 | vmxon->hdr.shadow = 0x00000000; 265 | vmxon_pa = __pa(vmxon); 266 | 267 | vmcs = (struct vmcs *) kmalloc(4096, GFP_KERNEL); 268 | memset(vmcs, 0, 4096); 269 | vmcs->hdr.revision_id = 0x00000001; 270 | vmcs->hdr.shadow = 0x00000000; 271 | vmcs_pa = __pa(vmcs); 272 | 273 | asm volatile ( 274 | "movq %cr4, %rax\n\t" 275 | "bts $13, %rax\n\t" 276 | "movq %rax, %cr4" 277 | ); 278 | 279 | asm volatile ( 280 | "vmxon %[pa]; setna %[ret]" 281 | : [ret] "=rm" (ret1) 282 | : [pa] "m" (vmxon_pa) 283 | : "cc", "memory" 284 | ); 285 | printk("vmxon = %d\n", ret1); 286 | 287 | asm volatile ( 288 | "vmclear %[pa]; setna %[ret]" 289 | : [ret] "=rm" (ret1) 290 | : [pa] "m" (vmcs_pa) 291 | : "cc", "memory" 292 | ); 293 | printk("vmclear = %d\n", ret1); 294 | 295 | asm volatile ( 296 | "vmptrld %[pa]; setna %[ret]" 297 | : [ret] "=rm" (ret1) 298 | : [pa] "m" (vmcs_pa) 299 | : "cc", "memory" 300 | ); 301 | printk("vmptrld = %d\n", ret1); 302 | 303 | vmcs_field = 0x00000802; 304 | vmcs_field_value = 0x0000; 305 | asm volatile ( 306 | "vmwrite %1, %0\n\t" 307 | : 308 | : "r" (vmcs_field), "r" (vmcs_field_value) 309 | ); 310 | printk("Guest CS selctor = 0x%llx\n", vmcs_field_value); 311 | 312 | vmcs_field = 0x0000080E; 313 | vmcs_field_value = 0x0000; 314 | asm volatile ( 315 | "vmwrite %1, %0\n\t" 316 | : 317 | : "r" (vmcs_field), "r" (vmcs_field_value) 318 | ); 319 | printk("Guest TR selctor = 0x%llx\n", vmcs_field_value); 320 | 321 | vmcs_field = 0x00002800; 322 | vmcs_field_value = 0xFFFFFFFFFFFFFFFF; 323 | asm volatile ( 324 | "vmwrite %1, %0\n\t" 325 | : 326 | : "r" (vmcs_field), "r" (vmcs_field_value) 327 | ); 328 | printk("VMCS link pointer = 0x%llx\n", vmcs_field_value); 329 | 330 | vmcs_field = 0x00004802; 331 | vmcs_field_value = 0x0000FFFF; 332 | asm volatile ( 333 | "vmwrite %1, %0\n\t" 334 | : 335 | : "r" (vmcs_field), "r" (vmcs_field_value) 336 | ); 337 | printk("Guest CS limit = 0x%llx\n", vmcs_field_value); 338 | 339 | vmcs_field = 0x0000480E; 340 | vmcs_field_value = 0x0000000FF; 341 | asm volatile ( 342 | "vmwrite %1, %0\n\t" 343 | : 344 | : "r" (vmcs_field), "r" (vmcs_field_value) 345 | ); 346 | printk("Guest TR limit = 0x%llx\n", vmcs_field_value); 347 | 348 | vmcs_field = 0x00004814; 349 | vmcs_field_value = 0x00010000; 350 | asm volatile ( 351 | "vmwrite %1, %0\n\t" 352 | : 353 | : "r" (vmcs_field), "r" (vmcs_field_value) 354 | ); 355 | printk("Guest ES access rights = 0x%llx\n", vmcs_field_value); 356 | 357 | vmcs_field = 0x00004816; 358 | vmcs_field_value = 0x0000009B; 359 | asm volatile ( 360 | "vmwrite %1, %0\n\t" 361 | : 362 | : "r" (vmcs_field), "r" (vmcs_field_value) 363 | ); 364 | printk("Guest CS access rights = 0x%llx\n", vmcs_field_value); 365 | 366 | vmcs_field = 0x00004818; 367 | vmcs_field_value = 0x00010000; 368 | asm volatile ( 369 | "vmwrite %1, %0\n\t" 370 | : 371 | : "r" (vmcs_field), "r" (vmcs_field_value) 372 | ); 373 | printk("Guest SS access rights = 0x%llx\n", vmcs_field_value); 374 | 375 | vmcs_field = 0x0000481A; 376 | vmcs_field_value = 0x00010000; 377 | asm volatile ( 378 | "vmwrite %1, %0\n\t" 379 | : 380 | : "r" (vmcs_field), "r" (vmcs_field_value) 381 | ); 382 | printk("Guest DS access rights = 0x%llx\n", vmcs_field_value); 383 | 384 | vmcs_field = 0x0000481C; 385 | vmcs_field_value = 0x00010000; 386 | asm volatile ( 387 | "vmwrite %1, %0\n\t" 388 | : 389 | : "r" (vmcs_field), "r" (vmcs_field_value) 390 | ); 391 | printk("Guest FS access rights = 0x%llx\n", vmcs_field_value); 392 | 393 | vmcs_field = 0x0000481E; 394 | vmcs_field_value = 0x00010000; 395 | asm volatile ( 396 | "vmwrite %1, %0\n\t" 397 | : 398 | : "r" (vmcs_field), "r" (vmcs_field_value) 399 | ); 400 | printk("Guest GS access rights = 0x%llx\n", vmcs_field_value); 401 | 402 | vmcs_field = 0x00004820; 403 | vmcs_field_value = 0x00010000; 404 | asm volatile ( 405 | "vmwrite %1, %0\n\t" 406 | : 407 | : "r" (vmcs_field), "r" (vmcs_field_value) 408 | ); 409 | printk("Guest LDTR access rights = 0x%llx\n", vmcs_field_value); 410 | 411 | vmcs_field = 0x00004822; 412 | vmcs_field_value = 0x0000008B; 413 | asm volatile ( 414 | "vmwrite %1, %0\n\t" 415 | : 416 | : "r" (vmcs_field), "r" (vmcs_field_value) 417 | ); 418 | printk("Guest TR access rights = 0x%llx\n", vmcs_field_value); 419 | 420 | vmcs_field = 0x00006800; 421 | vmcs_field_value = 0x00000020; 422 | asm volatile ( 423 | "vmwrite %1, %0\n\t" 424 | : 425 | : "r" (vmcs_field), "r" (vmcs_field_value) 426 | ); 427 | printk("Guest CR0 = 0x%llx\n", vmcs_field_value); 428 | 429 | vmcs_field = 0x00006804; 430 | vmcs_field_value = 0x0000000000002000; 431 | asm volatile ( 432 | "vmwrite %1, %0\n\t" 433 | : 434 | : "r" (vmcs_field), "r" (vmcs_field_value) 435 | ); 436 | printk("Guest CR4 = 0x%llx\n", vmcs_field_value); 437 | 438 | vmcs_field = 0x00006808; 439 | vmcs_field_value = 0x0000000000000000; 440 | asm volatile ( 441 | "vmwrite %1, %0\n\t" 442 | : 443 | : "r" (vmcs_field), "r" (vmcs_field_value) 444 | ); 445 | printk("Guest CS base = 0x%llx\n", vmcs_field_value); 446 | 447 | vmcs_field = 0x00006814; 448 | vmcs_field_value = 0x0000000000008000; 449 | asm volatile ( 450 | "vmwrite %1, %0\n\t" 451 | : 452 | : "r" (vmcs_field), "r" (vmcs_field_value) 453 | ); 454 | printk("Guest TR base = 0x%llx\n", vmcs_field_value); 455 | 456 | vmcs_field = 0x0000681E; 457 | vmcs_field_value = 0x0000000000000000; 458 | asm volatile ( 459 | "vmwrite %1, %0\n\t" 460 | : 461 | : "r" (vmcs_field), "r" (vmcs_field_value) 462 | ); 463 | printk("Guest RIP = 0x%llx\n", vmcs_field_value); 464 | 465 | vmcs_field = 0x00006820; 466 | vmcs_field_value = 0x0000000000000002; 467 | asm volatile ( 468 | "vmwrite %1, %0\n\t" 469 | : 470 | : "r" (vmcs_field), "r" (vmcs_field_value) 471 | ); 472 | printk("Guest RFLAGS = 0x%llx\n", vmcs_field_value); 473 | 474 | vmcs_field = 0x00000C00; 475 | asm volatile ( 476 | "movq %%es, %0\n\t" 477 | : "=a" (vmcs_field_value) 478 | : 479 | ); 480 | vmcs_field_value &= 0xF8; 481 | asm volatile ( 482 | "vmwrite %1, %0\n\t" 483 | : 484 | : "r" (vmcs_field), "r" (vmcs_field_value) 485 | ); 486 | printk("Host ES selctor = 0x%llx\n", vmcs_field_value); 487 | 488 | vmcs_field = 0x00000C02; 489 | asm volatile ( 490 | "movq %%cs, %0\n\t" 491 | : "=a" (vmcs_field_value) 492 | : 493 | ); 494 | vmcs_field_value &= 0xF8; 495 | asm volatile ( 496 | "vmwrite %1, %0\n\t" 497 | : 498 | : "r" (vmcs_field), "r" (vmcs_field_value) 499 | ); 500 | printk("Host CS selctor = 0x%llx\n", vmcs_field_value); 501 | 502 | vmcs_field = 0x00000C04; 503 | asm volatile ( 504 | "movq %%ss, %0\n\t" 505 | : "=a" (vmcs_field_value) 506 | : 507 | ); 508 | vmcs_field_value &= 0xF8; 509 | asm volatile ( 510 | "vmwrite %1, %0\n\t" 511 | : 512 | : "r" (vmcs_field), "r" (vmcs_field_value) 513 | ); 514 | printk("Host SS selctor = 0x%llx\n", vmcs_field_value); 515 | 516 | vmcs_field = 0x00000C06; 517 | asm volatile ( 518 | "movq %%ds, %0\n\t" 519 | : "=a" (vmcs_field_value) 520 | : 521 | ); 522 | vmcs_field_value &= 0xF8; 523 | asm volatile ( 524 | "vmwrite %1, %0\n\t" 525 | : 526 | : "r" (vmcs_field), "r" (vmcs_field_value) 527 | ); 528 | printk("Host DS selctor = 0x%llx\n", vmcs_field_value); 529 | 530 | vmcs_field = 0x00000C08; 531 | asm volatile ( 532 | "movq %%fs, %0\n\t" 533 | : "=a" (vmcs_field_value) 534 | : 535 | ); 536 | vmcs_field_value &= 0xF8; 537 | asm volatile ( 538 | "vmwrite %1, %0\n\t" 539 | : 540 | : "r" (vmcs_field), "r" (vmcs_field_value) 541 | ); 542 | printk("Host FS selctor = 0x%llx\n", vmcs_field_value); 543 | 544 | vmcs_field = 0x00000C0A; 545 | asm volatile ( 546 | "movq %%gs, %0\n\t" 547 | : "=a" (vmcs_field_value) 548 | : 549 | ); 550 | vmcs_field_value &= 0xF8; 551 | asm volatile ( 552 | "vmwrite %1, %0\n\t" 553 | : 554 | : "r" (vmcs_field), "r" (vmcs_field_value) 555 | ); 556 | printk("Host GS selctor = 0x%llx\n", vmcs_field_value); 557 | 558 | vmcs_field = 0x00000C0C; 559 | asm volatile ( 560 | "str %0\n\t" 561 | : "=a" (vmcs_field_value) 562 | : 563 | ); 564 | vmcs_field_value &= 0xF8; 565 | asm volatile ( 566 | "vmwrite %1, %0\n\t" 567 | : 568 | : "r" (vmcs_field), "r" (vmcs_field_value) 569 | ); 570 | printk("Host TR selctor = 0x%llx\n", vmcs_field_value); 571 | 572 | vmcs_field = 0x00002C00; 573 | ecx = 0x277; 574 | asm volatile ( 575 | "rdmsr\n\t" 576 | : "=a" (eax), "=d" (edx) 577 | : "c" (ecx) 578 | ); 579 | rdx = edx; 580 | vmcs_field_value = rdx << 32 | eax; 581 | asm volatile ( 582 | "vmwrite %1, %0\n\t" 583 | : 584 | : "r" (vmcs_field), "r" (vmcs_field_value) 585 | ); 586 | printk("Host IA32_PAT = 0x%llx\n", vmcs_field_value); 587 | 588 | vmcs_field = 0x00002C02; 589 | ecx = 0xC0000080; 590 | asm volatile ( 591 | "rdmsr\n\t" 592 | : "=a" (eax), "=d" (edx) 593 | : "c" (ecx) 594 | ); 595 | rdx = edx; 596 | vmcs_field_value = rdx << 32 | eax; 597 | asm volatile ( 598 | "vmwrite %1, %0\n\t" 599 | : 600 | : "r" (vmcs_field), "r" (vmcs_field_value) 601 | ); 602 | printk("Host IA32_EFER = 0x%llx\n", vmcs_field_value); 603 | 604 | vmcs_field = 0x00002C04; 605 | ecx = 0x38F; 606 | asm volatile ( 607 | "rdmsr\n\t" 608 | : "=a" (eax), "=d" (edx) 609 | : "c" (ecx) 610 | ); 611 | rdx = edx; 612 | vmcs_field_value = rdx << 32 | eax; 613 | asm volatile ( 614 | "vmwrite %1, %0\n\t" 615 | : 616 | : "r" (vmcs_field), "r" (vmcs_field_value) 617 | ); 618 | printk("Host IA32_PERF_GLOBAL_CTRL = 0x%llx\n", vmcs_field_value); 619 | 620 | vmcs_field = 0x00004C00; 621 | ecx = 0x174; 622 | asm volatile ( 623 | "rdmsr\n\t" 624 | : "=a" (eax), "=d" (edx) 625 | : "c" (ecx) 626 | ); 627 | rdx = edx; 628 | vmcs_field_value = rdx << 32 | eax; 629 | asm volatile ( 630 | "vmwrite %1, %0\n\t" 631 | : 632 | : "r" (vmcs_field), "r" (vmcs_field_value) 633 | ); 634 | printk("Host IA32_SYSENTER_CS = 0x%llx\n", vmcs_field_value); 635 | 636 | vmcs_field = 0x00006C00; 637 | asm volatile ( 638 | "movq %%cr0, %0\n\t" 639 | : "=a" (vmcs_field_value) 640 | : 641 | ); 642 | asm volatile ( 643 | "vmwrite %1, %0\n\t" 644 | : 645 | : "r" (vmcs_field), "r" (vmcs_field_value) 646 | ); 647 | printk("Host CR0 = 0x%llx\n", vmcs_field_value); 648 | 649 | vmcs_field = 0x00006C02; 650 | asm volatile ( 651 | "movq %%cr3, %0\n\t" 652 | : "=a" (vmcs_field_value) 653 | : 654 | ); 655 | asm volatile ( 656 | "vmwrite %1, %0\n\t" 657 | : 658 | : "r" (vmcs_field), "r" (vmcs_field_value) 659 | ); 660 | printk("Host CR3 = 0x%llx\n", vmcs_field_value); 661 | 662 | vmcs_field = 0x00006C04; 663 | asm volatile ( 664 | "movq %%cr4, %0\n\t" 665 | : "=a" (vmcs_field_value) 666 | : 667 | ); 668 | asm volatile ( 669 | "vmwrite %1, %0\n\t" 670 | : 671 | : "r" (vmcs_field), "r" (vmcs_field_value) 672 | ); 673 | printk("Host CR4 = 0x%llx\n", vmcs_field_value); 674 | 675 | vmcs_field = 0x00006C06; 676 | ecx = 0xC0000100; 677 | asm volatile ( 678 | "rdmsr\n\t" 679 | : "=a" (eax), "=d" (edx) 680 | : "c" (ecx) 681 | ); 682 | rdx = edx; 683 | vmcs_field_value = rdx << 32 | eax; 684 | asm volatile ( 685 | "vmwrite %1, %0\n\t" 686 | : 687 | : "r" (vmcs_field), "r" (vmcs_field_value) 688 | ); 689 | printk("Host FS base = 0x%llx\n", vmcs_field_value); 690 | 691 | vmcs_field = 0x00006C08; 692 | ecx = 0xC0000101; 693 | asm volatile ( 694 | "rdmsr\n\t" 695 | : "=a" (eax), "=d" (edx) 696 | : "c" (ecx) 697 | ); 698 | rdx = edx; 699 | vmcs_field_value = rdx << 32 | eax; 700 | asm volatile ( 701 | "vmwrite %1, %0\n\t" 702 | : 703 | : "r" (vmcs_field), "r" (vmcs_field_value) 704 | ); 705 | printk("Host GS base = 0x%llx\n", vmcs_field_value); 706 | 707 | asm volatile ( 708 | "str %0\n\t" 709 | : "=a" (host_tr_selector) 710 | : 711 | ); 712 | host_tr_selector &= 0xF8; 713 | 714 | asm volatile ( 715 | "sgdt %0\n\t" 716 | : "=m" (xdtr) 717 | : 718 | ); 719 | host_gdt_base = *((u64 *) (xdtr + 2)); 720 | 721 | host_tr_desc = *((u64 *) (host_gdt_base + host_tr_selector)); 722 | vmcs_field_value = ((host_tr_desc & 0x000000FFFFFF0000) >> 16) | ((host_tr_desc & 0xFF00000000000000) >> 32); 723 | 724 | host_tr_desc = *((u64 *) (host_gdt_base + host_tr_selector + 8)); 725 | host_tr_desc <<= 32; 726 | vmcs_field_value |= host_tr_desc; 727 | 728 | vmcs_field = 0x00006C0A; 729 | asm volatile ( 730 | "vmwrite %1, %0\n\t" 731 | : 732 | : "r" (vmcs_field), "r" (vmcs_field_value) 733 | ); 734 | printk("Host TR base = 0x%llx\n", vmcs_field_value); 735 | 736 | vmcs_field = 0x00006C0C; 737 | asm volatile ( 738 | "sgdt %0\n\t" 739 | : "=m" (xdtr) 740 | : 741 | ); 742 | vmcs_field_value = *((u64 *) (xdtr + 2)); 743 | asm volatile ( 744 | "vmwrite %1, %0\n\t" 745 | : 746 | : "r" (vmcs_field), "r" (vmcs_field_value) 747 | ); 748 | printk("Host GDTR base = 0x%llx\n", vmcs_field_value); 749 | 750 | vmcs_field = 0x00006C0E; 751 | asm volatile ( 752 | "sidt %0\n\t" 753 | : "=m" (xdtr) 754 | : 755 | ); 756 | vmcs_field_value = *((u64 *) (xdtr + 2)); 757 | asm volatile ( 758 | "vmwrite %1, %0\n\t" 759 | : 760 | : "r" (vmcs_field), "r" (vmcs_field_value) 761 | ); 762 | printk("Host IDTR base = 0x%llx\n", vmcs_field_value); 763 | 764 | vmcs_field = 0x00006C10; 765 | ecx = 0x175; 766 | asm volatile ( 767 | "rdmsr\n\t" 768 | : "=a" (eax), "=d" (edx) 769 | : "c" (ecx) 770 | ); 771 | rdx = edx; 772 | vmcs_field_value = rdx << 32 | eax; 773 | asm volatile ( 774 | "vmwrite %1, %0\n\t" 775 | : 776 | : "r" (vmcs_field), "r" (vmcs_field_value) 777 | ); 778 | printk("Host IA32_SYSENTER_ESP = 0x%llx\n", vmcs_field_value); 779 | 780 | vmcs_field = 0x00006C12; 781 | ecx = 0x176; 782 | asm volatile ( 783 | "rdmsr\n\t" 784 | : "=a" (eax), "=d" (edx) 785 | : "c" (ecx) 786 | ); 787 | rdx = edx; 788 | vmcs_field_value = rdx << 32 | eax; 789 | asm volatile ( 790 | "vmwrite %1, %0\n\t" 791 | : 792 | : "r" (vmcs_field), "r" (vmcs_field_value) 793 | ); 794 | printk("Host IA32_SYSENTER_EIP = 0x%llx\n", vmcs_field_value); 795 | 796 | stack = (u8 *) kmalloc(0x8000, GFP_KERNEL); 797 | vmcs_field = 0x00006C14; 798 | vmcs_field_value = (u64) stack + 0x8000; 799 | asm volatile ( 800 | "vmwrite %1, %0\n\t" 801 | : 802 | : "r" (vmcs_field), "r" (vmcs_field_value) 803 | ); 804 | printk("Host RSP = 0x%llx\n", vmcs_field_value); 805 | 806 | vmcs_field = 0x00006C16; 807 | vmcs_field_value = (u64) _vmexit_handler; 808 | asm volatile ( 809 | "vmwrite %1, %0\n\t" 810 | : 811 | : "r" (vmcs_field), "r" (vmcs_field_value) 812 | ); 813 | printk("Host RIP = 0x%llx\n", vmcs_field_value); 814 | 815 | vmcs_field = 0x00000000; 816 | vmcs_field_value = 0x0001; 817 | asm volatile ( 818 | "vmwrite %1, %0\n\t" 819 | : 820 | : "r" (vmcs_field), "r" (vmcs_field_value) 821 | ); 822 | printk("VPID = 0x%llx\n", vmcs_field_value); 823 | 824 | vmcs_field = 0x0000201A; 825 | vmcs_field_value = ept_pointer; 826 | asm volatile ( 827 | "vmwrite %1, %0\n\t" 828 | : 829 | : "r" (vmcs_field), "r" (vmcs_field_value) 830 | ); 831 | printk("EPT_POINTER = 0x%llx\n", vmcs_field_value); 832 | 833 | vmcs_field = 0x00004000; 834 | vmcs_field_value = 0x00000016; 835 | asm volatile ( 836 | "vmwrite %1, %0\n\t" 837 | : 838 | : "r" (vmcs_field), "r" (vmcs_field_value) 839 | ); 840 | printk("Pin-based VM-execution controls = 0x%llx\n", vmcs_field_value); 841 | 842 | vmcs_field = 0x00004002; 843 | vmcs_field_value = 0x840061F2; 844 | asm volatile ( 845 | "vmwrite %1, %0\n\t" 846 | : 847 | : "r" (vmcs_field), "r" (vmcs_field_value) 848 | ); 849 | printk("Primary Processor-based VM-execution controls = 0x%llx\n", vmcs_field_value); 850 | 851 | vmcs_field = 0x0000401E; 852 | vmcs_field_value = 0x000000A2; 853 | asm volatile ( 854 | "vmwrite %1, %0\n\t" 855 | : 856 | : "r" (vmcs_field), "r" (vmcs_field_value) 857 | ); 858 | printk("Secondary Processor-based VM-execution controls = 0x%llx\n", vmcs_field_value); 859 | 860 | vmcs_field = 0x00004012; 861 | vmcs_field_value = 0x000011fb; 862 | asm volatile ( 863 | "vmwrite %1, %0\n\t" 864 | : 865 | : "r" (vmcs_field), "r" (vmcs_field_value) 866 | ); 867 | printk("VM-entry controls = 0x%llx\n", vmcs_field_value); 868 | 869 | vmcs_field = 0x0000400C; 870 | vmcs_field_value = 0x00036ffb; 871 | asm volatile ( 872 | "vmwrite %1, %0\n\t" 873 | : 874 | : "r" (vmcs_field), "r" (vmcs_field_value) 875 | ); 876 | printk("VM-exit controls = 0x%llx\n", vmcs_field_value); 877 | 878 | asm volatile ( 879 | "movq %%rsp, %0\n\t" 880 | "movq %%rbp, %1\n\t" 881 | : "=a" (shutdown_rsp), "=b" (shutdown_rbp) 882 | : 883 | ); 884 | 885 | asm volatile ( 886 | "vmlaunch; setna %[ret]" 887 | : [ret] "=rm" (ret1) 888 | : 889 | : "cc", "memory" 890 | ); 891 | printk("vmlaunch = %d\n", ret1); 892 | 893 | vmcs_field = 0x00004402; 894 | asm volatile ( 895 | "vmread %1, %0\n\t" 896 | : "=r" (vmcs_field_value) 897 | : "r" (vmcs_field) 898 | ); 899 | printk("EXIT_REASON = 0x%llx\n", vmcs_field_value); 900 | 901 | asm volatile ("shutdown:"); 902 | printk("********** guest shutdown **********\n"); 903 | 904 | asm volatile ("vmxoff"); 905 | 906 | asm volatile ( 907 | "movq %cr4, %rax\n\t" 908 | "btr $13, %rax\n\t" 909 | "movq %rax, %cr4" 910 | ); 911 | 912 | break; 913 | } 914 | 915 | return 0; 916 | } 917 | 918 | void handle_vmexit(struct guest_regs *regs) 919 | { 920 | u64 vmcs_field; 921 | u64 vmcs_field_value; 922 | u64 guest_rip; 923 | 924 | dump_guest_regs(regs); 925 | 926 | vmcs_field = 0x00004402; 927 | asm volatile ( 928 | "vmread %1, %0\n\t" 929 | : "=r" (vmcs_field_value) 930 | : "r" (vmcs_field) 931 | ); 932 | printk("EXIT_REASON = 0x%llx\n", vmcs_field_value); 933 | 934 | switch (vmcs_field_value) { 935 | case 0x0C: 936 | asm volatile ( 937 | "movq %0, %%rsp\n\t" 938 | "movq %1, %%rbp\n\t" 939 | "jmp shutdown\n\t" 940 | : 941 | : "a" (shutdown_rsp), "b" (shutdown_rbp) 942 | ); 943 | 944 | break; 945 | 946 | case 0x0A: 947 | regs->rax = 0x6368; 948 | regs->rbx = 0x6561; 949 | regs->rcx = 0x70; 950 | 951 | break; 952 | 953 | default: 954 | break; 955 | } 956 | 957 | vmcs_field = 0x0000681E; 958 | asm volatile ( 959 | "vmread %1, %0\n\t" 960 | : "=r" (vmcs_field_value) 961 | : "r" (vmcs_field) 962 | ); 963 | printk("Guest RIP = 0x%llx\n", vmcs_field_value); 964 | 965 | guest_rip = vmcs_field_value; 966 | 967 | vmcs_field = 0x0000440C; 968 | asm volatile ( 969 | "vmread %1, %0\n\t" 970 | : "=r" (vmcs_field_value) 971 | : "r" (vmcs_field) 972 | ); 973 | printk("VM-exit instruction length = 0x%llx\n", vmcs_field_value); 974 | 975 | vmcs_field = 0x0000681E; 976 | vmcs_field_value = guest_rip + vmcs_field_value; 977 | asm volatile ( 978 | "vmwrite %1, %0\n\t" 979 | : 980 | : "r" (vmcs_field), "r" (vmcs_field_value) 981 | ); 982 | printk("Guest RIP = 0x%llx\n", vmcs_field_value); 983 | 984 | return; 985 | } 986 | 987 | static void init_ept(u64 *ept_pointer, u64 guest_memory_pa) 988 | { 989 | int i; 990 | 991 | u64 ept_va; 992 | u64 ept_pa; 993 | 994 | u64 *entry; 995 | 996 | ept_memory = (u8 *) kmalloc(EPT_MEMORY_SIZE, GFP_KERNEL); 997 | memset(ept_memory, 0, EPT_MEMORY_SIZE); 998 | 999 | ept_va = (u64) ept_memory; 1000 | ept_pa = __pa(ept_memory); 1001 | 1002 | init_ept_pointer(ept_pointer, ept_pa); 1003 | 1004 | entry = (u64 *) ept_va; 1005 | init_pml4e(entry, ept_pa + 0x1000); 1006 | printk("pml4e = 0x%llx\n", *entry); 1007 | 1008 | entry = (u64 *) (ept_va + 0x1000); 1009 | init_pdpte(entry, ept_pa + 0x2000); 1010 | printk("pdpte = 0x%llx\n", *entry); 1011 | 1012 | entry = (u64 *) (ept_va + 0x2000); 1013 | init_pde(entry, ept_pa + 0x3000); 1014 | printk("pdte = 0x%llx\n", *entry); 1015 | 1016 | for (i = 0; i < 16; i++) { 1017 | entry = (u64 *) (ept_va + 0x3000 + i * 8); 1018 | init_pte(entry, guest_memory_pa + i * 0x1000); 1019 | printk("pte = 0x%llx\n", *entry); 1020 | } 1021 | 1022 | return; 1023 | } 1024 | 1025 | static void init_ept_pointer(u64 *p, u64 pa) 1026 | { 1027 | *p = pa | 1 << 6 | 3 << 3 | 6; 1028 | 1029 | return; 1030 | } 1031 | 1032 | static void init_pml4e(u64 *entry, u64 pa) 1033 | { 1034 | *entry = pa | 1 << 2 | 1 << 1 | 1; 1035 | 1036 | return; 1037 | } 1038 | 1039 | static void init_pdpte(u64 *entry, u64 pa) 1040 | { 1041 | *entry = pa | 1 << 2 | 1 << 1 | 1; 1042 | 1043 | return; 1044 | } 1045 | 1046 | static void init_pde(u64 *entry, u64 pa) 1047 | { 1048 | *entry = pa | 1 << 2 | 1 << 1 | 1; 1049 | 1050 | return; 1051 | } 1052 | 1053 | static void init_pte(u64 *entry, u64 pa) 1054 | { 1055 | *entry = pa | 6 << 3 | 1 << 2 | 1 << 1 | 1; 1056 | 1057 | return; 1058 | } 1059 | 1060 | static void dump_guest_regs(struct guest_regs *regs) 1061 | { 1062 | printk("********** guest regs **********\n"); 1063 | printk("* rax = 0x%llx\n", regs->rax); 1064 | printk("* rcx = 0x%llx\n", regs->rcx); 1065 | printk("* rdx = 0x%llx\n", regs->rdx); 1066 | printk("* rbx = 0x%llx\n", regs->rbx); 1067 | printk("* rbp = 0x%llx\n", regs->rbp); 1068 | printk("* rsi = 0x%llx\n", regs->rsi); 1069 | printk("* rdi = 0x%llx\n", regs->rdi); 1070 | printk("* r8 = 0x%llx\n", regs->r8); 1071 | printk("* r9 = 0x%llx\n", regs->r9); 1072 | printk("* r10 = 0x%llx\n", regs->r10); 1073 | printk("* r11 = 0x%llx\n", regs->r11); 1074 | printk("* r12 = 0x%llx\n", regs->r12); 1075 | printk("* r13 = 0x%llx\n", regs->r13); 1076 | printk("* r14 = 0x%llx\n", regs->r14); 1077 | printk("* r15 = 0x%llx\n", regs->r15); 1078 | printk("********************************\n"); 1079 | } 1080 | 1081 | module_init(peach_init); 1082 | module_exit(peach_exit); 1083 | --------------------------------------------------------------------------------