vCPU creation we have created VM thru an ioctl call. Now it is time for us to trace path of vCPU creation. In Last chapter you would have notitced the .init() function of QEMU machine. The .init() function will create &initialize the cpu and create a thread to run the VM. creation of cpu is done by kvm_create_vcpu(). kvm_main_loop() function does loop for ever.

machine->init(ram_size, vga_ram_size, boot_devices, ds, kernel_filename, kernel_cmdline, initrd_filename, cpu_model) {

pc_init_pci() {

      pc_init1() {


          for(i = 0; i < smp_cpus; i++) {

               env = pc_new_cpu(i, cpu_model, pci_enabled) {

                     /* cpu_init macro would be pointing to cpu_x86_init. This is initialised
                        different cpu_arch_init() 
                      */ 
                     cpu_init(cpu_model) {

                            kvm_init_new_ap(env->cpu_index, env) {


                                 /* Create a new thread using pthread. main function 
                                     ap_main_loop
                                  */
                                  ap_main_loop();

                                        /* This create vpcu */   
                                        kvm_create_vcpu();


                                        kvm_main_loop_cpu(env); 

Lets study functions kvm_create_vcpu() & kvm_main_loop_cpu() in next sections.

void kvm_create_vcpu() {

    /* allocate memory for run structure */ 
     kvm->run[cpu_num] = mmap(); 

     r = ioctl(kvm->vm_fd, KVM_CREATE_VCPU, slot) {

           vcpu = kvm_arch_vcpu_create(kvm, n) {

                kvm_x86_ops->vcpu_create(kvm, id) {
                       // .vcpu_create = vmx_create_vcpu is in
                       //vmx.c so it will call   vmx_create_vcpu()
                       vmx_create_vcpu() {
                             // we need a bigger discussion on vmx_create_cput ...but 
                             // will do it in "vmx.c chapter"

                       }  


                }

           }

    }

All resource needed for vCPU is allocated in previous step; now it is the time to start running.

void kvm_main_loop_cpu() {

kvm_load_registers() { kvm_arch_load_regs() }

while(1) {

   kvm_cpu_exec() {
             kvm_run {
                    int fd = kvm->vcpu_fd[vcpu];
                    struct kvm_run *run = kvm->run[vcpu];

                    /* Start VM using an ioctl KVM_RUN. this will move control to vmx.c
                    */
                    ioctl(fd, KVM_RUN, 0);
             }                                          

             /* when virtual machine exit. The control comes here. Now it is time for us to 
              * analyse the exit reason 
              */


              switch (run->exit_reason) {
                    case KVM_EXIT_IO:
                          /* handle_io calls kvm->callbacks->inb() etc functions to emulate the 
                           * the behaviour
                           */     
                           r = handle_io(kvm, run, vcpu);


                    case KVM_EXIT_MMIO:
                           r = handle_mmio(kvm, run); {
                           /* this will call specific function for each hardware emulated device;
                            * Eg, for e1000 , it is  e1000_mmio_read &  e1000_mmio_write.
                            * These functions got registered during pci_init() and callbacks- 
                            * thru kvm-callbacks.                                                                               * d->mmio_index =     
                            *       cpu_register_io_memory(e1000_mmio_read,e1000_mmio_write, d);
                            *  we will cover more on peripheral chapter  
                            */  

                   case KVM_EXIT_HLT:
                            r = handle_halt(kvm, vcpu);
                            break;

               }




      }
      /* wait for SIG_IPI signal with a timeout */        
      kvm_main_loop_wait() //end of while loop
 }                        

Lets talk about vm_enter and vm_exit. once QEMU decides that it is time to run a VM, it can setup registers and call a vm_enter. vm_enter is implemented in assembly language and is calling processor specific processor specific instruction to enter VM mode. In this mode, processor can execute VM code directly ; no need of emulation. This is possible only when we execute VM of same arch. for example, if you run a x86 vm on x86 linux os.

results matching ""

    No results matching ""