@@ -239,25 +239,6 @@ void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot)
239
239
vm_paddr_t paddr = vm_phy_page_alloc (vm ,
240
240
KVM_GUEST_PAGE_TABLE_MIN_PADDR , pgd_memslot );
241
241
vm -> pgd = paddr ;
242
-
243
- /* Set pointer to pgd tables in all the VCPUs that
244
- * have already been created. Future VCPUs will have
245
- * the value set as each one is created.
246
- */
247
- for (struct vcpu * vcpu = vm -> vcpu_head ; vcpu ;
248
- vcpu = vcpu -> next ) {
249
- struct kvm_sregs sregs ;
250
-
251
- /* Obtain the current system register settings */
252
- vcpu_sregs_get (vm , vcpu -> id , & sregs );
253
-
254
- /* Set and store the pointer to the start of the
255
- * pgd tables.
256
- */
257
- sregs .cr3 = vm -> pgd ;
258
- vcpu_sregs_set (vm , vcpu -> id , & sregs );
259
- }
260
-
261
242
vm -> pgd_created = true;
262
243
}
263
244
}
@@ -460,9 +441,32 @@ static void kvm_seg_set_unusable(struct kvm_segment *segp)
460
441
segp -> unusable = true;
461
442
}
462
443
444
+ static void kvm_seg_fill_gdt_64bit (struct kvm_vm * vm , struct kvm_segment * segp )
445
+ {
446
+ void * gdt = addr_gva2hva (vm , vm -> gdt );
447
+ struct desc64 * desc = gdt + (segp -> selector >> 3 ) * 8 ;
448
+
449
+ desc -> limit0 = segp -> limit & 0xFFFF ;
450
+ desc -> base0 = segp -> base & 0xFFFF ;
451
+ desc -> base1 = segp -> base >> 16 ;
452
+ desc -> s = segp -> s ;
453
+ desc -> type = segp -> type ;
454
+ desc -> dpl = segp -> dpl ;
455
+ desc -> p = segp -> present ;
456
+ desc -> limit1 = segp -> limit >> 16 ;
457
+ desc -> l = segp -> l ;
458
+ desc -> db = segp -> db ;
459
+ desc -> g = segp -> g ;
460
+ desc -> base2 = segp -> base >> 24 ;
461
+ if (!segp -> s )
462
+ desc -> base3 = segp -> base >> 32 ;
463
+ }
464
+
465
+
463
466
/* Set Long Mode Flat Kernel Code Segment
464
467
*
465
468
* Input Args:
469
+ * vm - VM whose GDT is being filled, or NULL to only write segp
466
470
* selector - selector value
467
471
*
468
472
* Output Args:
@@ -473,7 +477,7 @@ static void kvm_seg_set_unusable(struct kvm_segment *segp)
473
477
* Sets up the KVM segment pointed to by segp, to be a code segment
474
478
* with the selector value given by selector.
475
479
*/
476
- static void kvm_seg_set_kernel_code_64bit (uint16_t selector ,
480
+ static void kvm_seg_set_kernel_code_64bit (struct kvm_vm * vm , uint16_t selector ,
477
481
struct kvm_segment * segp )
478
482
{
479
483
memset (segp , 0 , sizeof (* segp ));
@@ -486,11 +490,14 @@ static void kvm_seg_set_kernel_code_64bit(uint16_t selector,
486
490
segp -> g = true;
487
491
segp -> l = true;
488
492
segp -> present = 1 ;
493
+ if (vm )
494
+ kvm_seg_fill_gdt_64bit (vm , segp );
489
495
}
490
496
491
497
/* Set Long Mode Flat Kernel Data Segment
492
498
*
493
499
* Input Args:
500
+ * vm - VM whose GDT is being filled, or NULL to only write segp
494
501
* selector - selector value
495
502
*
496
503
* Output Args:
@@ -501,7 +508,7 @@ static void kvm_seg_set_kernel_code_64bit(uint16_t selector,
501
508
* Sets up the KVM segment pointed to by segp, to be a data segment
502
509
* with the selector value given by selector.
503
510
*/
504
- static void kvm_seg_set_kernel_data_64bit (uint16_t selector ,
511
+ static void kvm_seg_set_kernel_data_64bit (struct kvm_vm * vm , uint16_t selector ,
505
512
struct kvm_segment * segp )
506
513
{
507
514
memset (segp , 0 , sizeof (* segp ));
@@ -513,6 +520,8 @@ static void kvm_seg_set_kernel_data_64bit(uint16_t selector,
513
520
*/
514
521
segp -> g = true;
515
522
segp -> present = true;
523
+ if (vm )
524
+ kvm_seg_fill_gdt_64bit (vm , segp );
516
525
}
517
526
518
527
/* Address Guest Virtual to Guest Physical
@@ -575,44 +584,64 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva)
575
584
"gva: 0x%lx" , gva );
576
585
}
577
586
578
- void vcpu_setup (struct kvm_vm * vm , int vcpuid )
587
+ static void kvm_setup_gdt (struct kvm_vm * vm , struct kvm_dtable * dt , int gdt_memslot ,
588
+ int pgd_memslot )
589
+ {
590
+ if (!vm -> gdt )
591
+ vm -> gdt = vm_vaddr_alloc (vm , getpagesize (),
592
+ KVM_UTIL_MIN_VADDR , gdt_memslot , pgd_memslot );
593
+
594
+ dt -> base = vm -> gdt ;
595
+ dt -> limit = getpagesize ();
596
+ }
597
+
598
+ static void kvm_setup_tss_64bit (struct kvm_vm * vm , struct kvm_segment * segp ,
599
+ int selector , int gdt_memslot ,
600
+ int pgd_memslot )
601
+ {
602
+ if (!vm -> tss )
603
+ vm -> tss = vm_vaddr_alloc (vm , getpagesize (),
604
+ KVM_UTIL_MIN_VADDR , gdt_memslot , pgd_memslot );
605
+
606
+ memset (segp , 0 , sizeof (* segp ));
607
+ segp -> base = vm -> tss ;
608
+ segp -> limit = 0x67 ;
609
+ segp -> selector = selector ;
610
+ segp -> type = 0xb ;
611
+ segp -> present = 1 ;
612
+ kvm_seg_fill_gdt_64bit (vm , segp );
613
+ }
614
+
615
+ void vcpu_setup (struct kvm_vm * vm , int vcpuid , int pgd_memslot , int gdt_memslot )
579
616
{
580
617
struct kvm_sregs sregs ;
581
618
582
619
/* Set mode specific system register values. */
583
620
vcpu_sregs_get (vm , vcpuid , & sregs );
584
621
622
+ sregs .idt .limit = 0 ;
623
+
624
+ kvm_setup_gdt (vm , & sregs .gdt , gdt_memslot , pgd_memslot );
625
+
585
626
switch (vm -> mode ) {
586
627
case VM_MODE_FLAT48PG :
587
628
sregs .cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG ;
588
629
sregs .cr4 |= X86_CR4_PAE ;
589
630
sregs .efer |= (EFER_LME | EFER_LMA | EFER_NX );
590
631
591
632
kvm_seg_set_unusable (& sregs .ldt );
592
- kvm_seg_set_kernel_code_64bit (0x8 , & sregs .cs );
593
- kvm_seg_set_kernel_data_64bit (0x10 , & sregs .ds );
594
- kvm_seg_set_kernel_data_64bit (0x10 , & sregs .es );
633
+ kvm_seg_set_kernel_code_64bit (vm , 0x8 , & sregs .cs );
634
+ kvm_seg_set_kernel_data_64bit (vm , 0x10 , & sregs .ds );
635
+ kvm_seg_set_kernel_data_64bit (vm , 0x10 , & sregs .es );
636
+ kvm_setup_tss_64bit (vm , & sregs .tr , 0x18 , gdt_memslot , pgd_memslot );
595
637
break ;
596
638
597
639
default :
598
640
TEST_ASSERT (false, "Unknown guest mode, mode: 0x%x" , vm -> mode );
599
641
}
600
- vcpu_sregs_set (vm , vcpuid , & sregs );
601
-
602
- /* If virtual translation table have been setup, set system register
603
- * to point to the tables. It's okay if they haven't been setup yet,
604
- * in that the code that sets up the virtual translation tables, will
605
- * go back through any VCPUs that have already been created and set
606
- * their values.
607
- */
608
- if (vm -> pgd_created ) {
609
- struct kvm_sregs sregs ;
610
642
611
- vcpu_sregs_get (vm , vcpuid , & sregs );
612
-
613
- sregs .cr3 = vm -> pgd ;
614
- vcpu_sregs_set (vm , vcpuid , & sregs );
615
- }
643
+ sregs .cr3 = vm -> pgd ;
644
+ vcpu_sregs_set (vm , vcpuid , & sregs );
616
645
}
617
646
/* Adds a vCPU with reasonable defaults (i.e., a stack)
618
647
*
@@ -629,7 +658,7 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code)
629
658
DEFAULT_GUEST_STACK_VADDR_MIN , 0 , 0 );
630
659
631
660
/* Create VCPU */
632
- vm_vcpu_add (vm , vcpuid );
661
+ vm_vcpu_add (vm , vcpuid , 0 , 0 );
633
662
634
663
/* Setup guest general purpose registers */
635
664
vcpu_regs_get (vm , vcpuid , & regs );
0 commit comments