---
# System prepended metadata

title: KVM in 16 mode

---

# 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 的部分，還要補一些不熟的地方，今天或明天應該可以開始學習