main.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /**
  2. * @file main.c
  3. * @author xiaoyez ([email protected])
  4. * @brief 测试kvm的程序
  5. * @version 0.1
  6. * @date 2023-07-13
  7. *
  8. * @copyright Copyright (c) 2023
  9. *
  10. */
  11. /**
  12. * 测试kvm命令的方法:
  13. * 1.在DragonOS的控制台输入 exec bin/test_kvm.elf
  14. *
  15. */
  16. #include <fcntl.h>
  17. #include <stdint.h>
  18. #include <stdio.h>
  19. #include <sys/ioctl.h>
  20. #include <unistd.h>
  21. #define KVM_CREATE_VCPU 0x00
  22. #define KVM_SET_USER_MEMORY_REGION 0x01
  23. #define KVM_RUN 0x00
  24. #define KVM_GET_REGS 0x01
  25. #define KVM_SET_REGS 0x02
  26. struct kvm_userspace_memory_region {
  27. uint32_t slot; // 要在哪个slot上注册内存区间
  28. // flags有两个取值,KVM_MEM_LOG_DIRTY_PAGES和KVM_MEM_READONLY,用来指示kvm针对这段内存应该做的事情。
  29. // KVM_MEM_LOG_DIRTY_PAGES用来开启内存脏页,KVM_MEM_READONLY用来开启内存只读。
  30. uint32_t flags;
  31. uint64_t guest_phys_addr; // 虚机内存区间起始物理地址
  32. uint64_t memory_size; // 虚机内存区间大小
  33. uint64_t userspace_addr; // 虚机内存区间对应的主机虚拟地址
  34. };
  35. struct kvm_regs {
  36. /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
  37. uint64_t rax, rbx, rcx, rdx;
  38. uint64_t rsi, rdi, rsp, rbp;
  39. uint64_t r8, r9, r10, r11;
  40. uint64_t r12, r13, r14, r15;
  41. uint64_t rip, rflags;
  42. };
  43. int guest_code(){
  44. while (1)
  45. {
  46. // printf("guest code\n");
  47. __asm__ __volatile__ (
  48. "mov %rax, 0\n\t"
  49. "mov %rcx, 0\n\t"
  50. "cpuid\n\t"
  51. );
  52. }
  53. return 0;
  54. }
  55. int main()
  56. {
  57. printf("Test kvm running...\n");
  58. printf("Open /dev/kvm\n");
  59. int kvm_fd = open("/dev/kvm", O_RDWR|O_CLOEXEC);
  60. int vmfd = ioctl(kvm_fd, 0x01, 0);
  61. printf("vmfd=%d\n", vmfd);
  62. /*
  63. __asm__ __volatile__ (
  64. "mov %rax, 0\n\t"
  65. "mov %rcx, 0\n\t"
  66. "cpuid\n\t"
  67. );
  68. */
  69. const uint8_t code[] = {
  70. 0xba, 0xf8, 0x03, /* mov $0x3f8, %dx */
  71. 0x00, 0xd8, /* add %bl, %al */
  72. 0x04, '0', /* add $'0', %al */
  73. 0xee, /* out %al, (%dx) */
  74. 0xb0, '\n', /* mov $'\n', %al */
  75. 0xee, /* out %al, (%dx) */
  76. 0xf4, /* hlt */
  77. };
  78. size_t mem_size = 0x4000; // size of user memory you want to assign
  79. printf("code=%p\n", code);
  80. // void *mem = mmap(0, mem_size, 0x7, -1, 0);
  81. // memcpy(mem, code, sizeof(code));
  82. struct kvm_userspace_memory_region region = {
  83. .slot = 0,
  84. .flags = 0,
  85. .guest_phys_addr = 0,
  86. .memory_size = mem_size,
  87. .userspace_addr = (size_t)code
  88. };
  89. ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &region);
  90. int vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);
  91. printf("vcpufd=%d\n", vcpufd);
  92. int user_entry = 0x0;
  93. struct kvm_regs regs = {0};
  94. regs.rip = user_entry;
  95. regs.rsp = 0x3000; // stack address
  96. regs.rflags = 0x2; // in x86 the 0x2 bit should always be set
  97. ioctl(vcpufd, KVM_SET_REGS, &regs); // set registers
  98. ioctl(vcpufd, KVM_RUN, 0);
  99. return 0;
  100. }