# 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, ®ion);
```
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, ®s);
```
> 剛剛發現之前做的練習給錯 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 的部分,還要補一些不熟的地方,今天或明天應該可以開始學習