# KVM in 16 mode ## Foreword 簡單紀錄下 kvm 的使用方法 ## Abstract Steps 1. Open Device - 透過以下 code 來開啟 device : ```c= open("/dev/kvm", O_RDWR | O_CLOEXEC); ``` > O_CLOEXEC 為 atomic 級別的操作,過程中不會被打斷,另外 exec 新的 process 時會隨之關閉 > return 為 kvmfd ,操作該 kvm 需要用到的 file descriptor 2. Create a vm - 透過 ioctl 來跟 device 溝通,這邊要求建立一個 virtual machine: ```c= int vmfd = ioctl(kvmfd, KVM_CREATE_VM, 0); ``` 3. Set memory to guest - guest 為 vm 中運行的電腦,想當然一定要有 memory - 直接在外部用 mmap 要一塊記憶體,而後再透過 ioctl 給 guest 用: ```c= void *mem = (void*)mmap(0, (size_t)mem_len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); ``` > 不確定為啥不用 PROT_EXEC - 檢查跟把 code 送進去就不多寫... - 另外要設定 userspace memory region: ```c= struct kvm_userspace_memory_region region = { .slot = 0, .flags = 0, .guest_phys_addr = 0, .memory_size = mem_sz, .userspace_addr = (size_t)mem }; ``` > slot, flags 具體用途日後再研究... - 最後透過 ioctl 傳給 vm 用就好了 ```c= ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &region); ``` 4. Assign CPU to vm - 直接用 ioctl 給: ```c= int vcpufd = ioctl(kvmfd, KVM_GET_VCPU, 0); ``` 5. set cpu memory - 不確定 cpu 內的 memory 是指啥...不過推測應該是指放 code 的記憶體區域 - 一樣透過 mmap 來要 memory 後用 ioctl 給 vcpu 用: ```c= size_t vcpu_mem_sz = ioctl(kvmfd, KVM_GET_VCPU_MMAP_SIZE, 0); struct kvm_run *run = (struct kvm_run*)mmap(0, vcpu_mem_sz, PROT_READ | PROT_WRITE, MAP_SHARED, vcpufd, 0); ``` 6. Set cpu registers - 有了 cpu 接下來要搞定 registers 是很合理的 - 最基本的 gerneral register: ```c= struct kvm_regs regs; regs.rip = usr_entry; regs.rsp = 0x20000; // for stack regs.rflags = 0x2; // not sure for what ioctl(vcpufd, KVM_SET_REGS, &regs); ``` > 剛剛發現之前做的練習給錯 fd ,這樣居然還能跑....代表設定 register 其實沒啥差嗎? - 還有 special register: ```c= struct sregs sregs; ioctl(vcpufd, KVM_GET_SREGS, &sregs); sregs.cs.base = sregs.cs.selector = 0; ioctl(vcpufd, KVM_SET_SREGS, &sregs); ``` > 這邊應該是直接從系統拿 sregs 的設定,然後改掉 cs.base 和 cs.selector,最後回傳回去 7. Run the VM - 前面設定很多,真正執行的時候只有一行: ```c= ioctl(vcpufd, KVM_RUN, NULL); ``` - 後面就是收尾的部分: ```c= switch(run->exit_reaion) { case KVM_EXIT_HLT: // instruction halt // need output the error message ... case KVM_EXIT_IO: putchar(*(((char*)run) + run->io.data_offset)); // I guess it will print the character break; case KVM_EXIT_FAIL_ENTRY: // print error case KVM_INTERNAL_ERROR: //print error case KVM_EXIT_SHUTDOWN: //just shutdown default: // unhandeled error } ``` ## 結尾 之後再進行 long mode 的部分,還要補一些不熟的地方,今天或明天應該可以開始學習