@@ -69,6 +69,11 @@ static u64 tdx_get_supported_xfam(const struct tdx_sys_info_td_conf *td_conf)
6969 return val ;
7070}
7171
72+ static int tdx_get_guest_phys_addr_bits (const u32 eax )
73+ {
74+ return (eax & GENMASK (23 , 16 )) >> 16 ;
75+ }
76+
7277static u32 tdx_set_guest_phys_addr_bits (const u32 eax , int addr_bits )
7378{
7479 return (eax & ~GENMASK (23 , 16 )) | (addr_bits & 0xff ) << 16 ;
@@ -350,7 +355,11 @@ static void tdx_reclaim_td_control_pages(struct kvm *kvm)
350355
351356void tdx_vm_destroy (struct kvm * kvm )
352357{
358+ struct kvm_tdx * kvm_tdx = to_kvm_tdx (kvm );
359+
353360 tdx_reclaim_td_control_pages (kvm );
361+
362+ kvm_tdx -> state = TD_STATE_UNINITIALIZED ;
354363}
355364
356365static int tdx_do_tdh_mng_key_config (void * param )
@@ -369,10 +378,10 @@ static int tdx_do_tdh_mng_key_config(void *param)
369378 return 0 ;
370379}
371380
372- static int __tdx_td_init (struct kvm * kvm );
373-
374381int tdx_vm_init (struct kvm * kvm )
375382{
383+ struct kvm_tdx * kvm_tdx = to_kvm_tdx (kvm );
384+
376385 kvm -> arch .has_protected_state = true;
377386 kvm -> arch .has_private_mem = true;
378387
@@ -389,8 +398,9 @@ int tdx_vm_init(struct kvm *kvm)
389398 */
390399 kvm -> max_vcpus = min_t (int , kvm -> max_vcpus , num_present_cpus ());
391400
392- /* Place holder for TDX specific logic. */
393- return __tdx_td_init (kvm );
401+ kvm_tdx -> state = TD_STATE_UNINITIALIZED ;
402+
403+ return 0 ;
394404}
395405
396406static int tdx_get_capabilities (struct kvm_tdx_cmd * cmd )
@@ -441,15 +451,151 @@ static int tdx_get_capabilities(struct kvm_tdx_cmd *cmd)
441451 return ret ;
442452}
443453
444- static int __tdx_td_init (struct kvm * kvm )
454+ /*
455+ * KVM reports guest physical address in CPUID.0x800000008.EAX[23:16], which is
456+ * similar to TDX's GPAW. Use this field as the interface for userspace to
457+ * configure the GPAW and EPT level for TDs.
458+ *
459+ * Only values 48 and 52 are supported. Value 52 means GPAW-52 and EPT level
460+ * 5, Value 48 means GPAW-48 and EPT level 4. For value 48, GPAW-48 is always
461+ * supported. Value 52 is only supported when the platform supports 5 level
462+ * EPT.
463+ */
464+ static int setup_tdparams_eptp_controls (struct kvm_cpuid2 * cpuid ,
465+ struct td_params * td_params )
466+ {
467+ const struct kvm_cpuid_entry2 * entry ;
468+ int guest_pa ;
469+
470+ entry = kvm_find_cpuid_entry2 (cpuid -> entries , cpuid -> nent , 0x80000008 , 0 );
471+ if (!entry )
472+ return - EINVAL ;
473+
474+ guest_pa = tdx_get_guest_phys_addr_bits (entry -> eax );
475+
476+ if (guest_pa != 48 && guest_pa != 52 )
477+ return - EINVAL ;
478+
479+ if (guest_pa == 52 && !cpu_has_vmx_ept_5levels ())
480+ return - EINVAL ;
481+
482+ td_params -> eptp_controls = VMX_EPTP_MT_WB ;
483+ if (guest_pa == 52 ) {
484+ td_params -> eptp_controls |= VMX_EPTP_PWL_5 ;
485+ td_params -> config_flags |= TDX_CONFIG_FLAGS_MAX_GPAW ;
486+ } else {
487+ td_params -> eptp_controls |= VMX_EPTP_PWL_4 ;
488+ }
489+
490+ return 0 ;
491+ }
492+
493+ static int setup_tdparams_cpuids (struct kvm_cpuid2 * cpuid ,
494+ struct td_params * td_params )
495+ {
496+ const struct tdx_sys_info_td_conf * td_conf = & tdx_sysinfo -> td_conf ;
497+ const struct kvm_cpuid_entry2 * entry ;
498+ struct tdx_cpuid_value * value ;
499+ int i , copy_cnt = 0 ;
500+
501+ /*
502+ * td_params.cpuid_values: The number and the order of cpuid_value must
503+ * be same to the one of struct tdsysinfo.{num_cpuid_config, cpuid_configs}
504+ * It's assumed that td_params was zeroed.
505+ */
506+ for (i = 0 ; i < td_conf -> num_cpuid_config ; i ++ ) {
507+ struct kvm_cpuid_entry2 tmp ;
508+
509+ td_init_cpuid_entry2 (& tmp , i );
510+
511+ entry = kvm_find_cpuid_entry2 (cpuid -> entries , cpuid -> nent ,
512+ tmp .function , tmp .index );
513+ if (!entry )
514+ continue ;
515+
516+ copy_cnt ++ ;
517+
518+ value = & td_params -> cpuid_values [i ];
519+ value -> eax = entry -> eax ;
520+ value -> ebx = entry -> ebx ;
521+ value -> ecx = entry -> ecx ;
522+ value -> edx = entry -> edx ;
523+
524+ /*
525+ * TDX module does not accept nonzero bits 16..23 for the
526+ * CPUID[0x80000008].EAX, see setup_tdparams_eptp_controls().
527+ */
528+ if (tmp .function == 0x80000008 )
529+ value -> eax = tdx_set_guest_phys_addr_bits (value -> eax , 0 );
530+ }
531+
532+ /*
533+ * Rely on the TDX module to reject invalid configuration, but it can't
534+ * check of leafs that don't have a proper slot in td_params->cpuid_values
535+ * to stick then. So fail if there were entries that didn't get copied to
536+ * td_params.
537+ */
538+ if (copy_cnt != cpuid -> nent )
539+ return - EINVAL ;
540+
541+ return 0 ;
542+ }
543+
544+ static int setup_tdparams (struct kvm * kvm , struct td_params * td_params ,
545+ struct kvm_tdx_init_vm * init_vm )
546+ {
547+ const struct tdx_sys_info_td_conf * td_conf = & tdx_sysinfo -> td_conf ;
548+ struct kvm_cpuid2 * cpuid = & init_vm -> cpuid ;
549+ int ret ;
550+
551+ if (kvm -> created_vcpus )
552+ return - EBUSY ;
553+
554+ if (init_vm -> attributes & ~tdx_get_supported_attrs (td_conf ))
555+ return - EINVAL ;
556+
557+ if (init_vm -> xfam & ~tdx_get_supported_xfam (td_conf ))
558+ return - EINVAL ;
559+
560+ td_params -> max_vcpus = kvm -> max_vcpus ;
561+ td_params -> attributes = init_vm -> attributes | td_conf -> attributes_fixed1 ;
562+ td_params -> xfam = init_vm -> xfam | td_conf -> xfam_fixed1 ;
563+
564+ td_params -> config_flags = TDX_CONFIG_FLAGS_NO_RBP_MOD ;
565+ td_params -> tsc_frequency = TDX_TSC_KHZ_TO_25MHZ (kvm -> arch .default_tsc_khz );
566+
567+ ret = setup_tdparams_eptp_controls (cpuid , td_params );
568+ if (ret )
569+ return ret ;
570+
571+ ret = setup_tdparams_cpuids (cpuid , td_params );
572+ if (ret )
573+ return ret ;
574+
575+ #define MEMCPY_SAME_SIZE (dst , src ) \
576+ do { \
577+ BUILD_BUG_ON(sizeof(dst) != sizeof(src)); \
578+ memcpy((dst), (src), sizeof(dst)); \
579+ } while (0)
580+
581+ MEMCPY_SAME_SIZE (td_params -> mrconfigid , init_vm -> mrconfigid );
582+ MEMCPY_SAME_SIZE (td_params -> mrowner , init_vm -> mrowner );
583+ MEMCPY_SAME_SIZE (td_params -> mrownerconfig , init_vm -> mrownerconfig );
584+
585+ return 0 ;
586+ }
587+
588+ static int __tdx_td_init (struct kvm * kvm , struct td_params * td_params ,
589+ u64 * seamcall_err )
445590{
446591 struct kvm_tdx * kvm_tdx = to_kvm_tdx (kvm );
447592 cpumask_var_t packages ;
448593 struct page * * tdcs_pages = NULL ;
449594 struct page * tdr_page ;
450595 int ret , i ;
451- u64 err ;
596+ u64 err , rcx ;
452597
598+ * seamcall_err = 0 ;
453599 ret = tdx_guest_keyid_alloc ();
454600 if (ret < 0 )
455601 return ret ;
@@ -561,10 +707,23 @@ static int __tdx_td_init(struct kvm *kvm)
561707 }
562708 }
563709
564- /*
565- * Note, TDH_MNG_INIT cannot be invoked here. TDH_MNG_INIT requires a dedicated
566- * ioctl() to define the configure CPUID values for the TD.
567- */
710+ err = tdh_mng_init (& kvm_tdx -> td , __pa (td_params ), & rcx );
711+ if ((err & TDX_SEAMCALL_STATUS_MASK ) == TDX_OPERAND_INVALID ) {
712+ /*
713+ * Because a user gives operands, don't warn.
714+ * Return a hint to the user because it's sometimes hard for the
715+ * user to figure out which operand is invalid. SEAMCALL status
716+ * code includes which operand caused invalid operand error.
717+ */
718+ * seamcall_err = err ;
719+ ret = - EINVAL ;
720+ goto teardown ;
721+ } else if (WARN_ON_ONCE (err )) {
722+ pr_tdx_error_1 (TDH_MNG_INIT , err , rcx );
723+ ret = - EIO ;
724+ goto teardown ;
725+ }
726+
568727 return 0 ;
569728
570729 /*
@@ -612,6 +771,83 @@ static int __tdx_td_init(struct kvm *kvm)
612771 return ret ;
613772}
614773
774+ static int tdx_td_init (struct kvm * kvm , struct kvm_tdx_cmd * cmd )
775+ {
776+ struct kvm_tdx * kvm_tdx = to_kvm_tdx (kvm );
777+ struct kvm_tdx_init_vm * init_vm ;
778+ struct td_params * td_params = NULL ;
779+ int ret ;
780+
781+ BUILD_BUG_ON (sizeof (* init_vm ) != 256 + sizeof_field (struct kvm_tdx_init_vm , cpuid ));
782+ BUILD_BUG_ON (sizeof (struct td_params ) != 1024 );
783+
784+ if (kvm_tdx -> state != TD_STATE_UNINITIALIZED )
785+ return - EINVAL ;
786+
787+ if (cmd -> flags )
788+ return - EINVAL ;
789+
790+ init_vm = kmalloc (sizeof (* init_vm ) +
791+ sizeof (init_vm -> cpuid .entries [0 ]) * KVM_MAX_CPUID_ENTRIES ,
792+ GFP_KERNEL );
793+ if (!init_vm )
794+ return - ENOMEM ;
795+
796+ if (copy_from_user (init_vm , u64_to_user_ptr (cmd -> data ), sizeof (* init_vm ))) {
797+ ret = - EFAULT ;
798+ goto out ;
799+ }
800+
801+ if (init_vm -> cpuid .nent > KVM_MAX_CPUID_ENTRIES ) {
802+ ret = - E2BIG ;
803+ goto out ;
804+ }
805+
806+ if (copy_from_user (init_vm -> cpuid .entries ,
807+ u64_to_user_ptr (cmd -> data ) + sizeof (* init_vm ),
808+ flex_array_size (init_vm , cpuid .entries , init_vm -> cpuid .nent ))) {
809+ ret = - EFAULT ;
810+ goto out ;
811+ }
812+
813+ if (memchr_inv (init_vm -> reserved , 0 , sizeof (init_vm -> reserved ))) {
814+ ret = - EINVAL ;
815+ goto out ;
816+ }
817+
818+ if (init_vm -> cpuid .padding ) {
819+ ret = - EINVAL ;
820+ goto out ;
821+ }
822+
823+ td_params = kzalloc (sizeof (struct td_params ), GFP_KERNEL );
824+ if (!td_params ) {
825+ ret = - ENOMEM ;
826+ goto out ;
827+ }
828+
829+ ret = setup_tdparams (kvm , td_params , init_vm );
830+ if (ret )
831+ goto out ;
832+
833+ ret = __tdx_td_init (kvm , td_params , & cmd -> hw_error );
834+ if (ret )
835+ goto out ;
836+
837+ kvm_tdx -> tsc_offset = td_tdcs_exec_read64 (kvm_tdx , TD_TDCS_EXEC_TSC_OFFSET );
838+ kvm_tdx -> tsc_multiplier = td_tdcs_exec_read64 (kvm_tdx , TD_TDCS_EXEC_TSC_MULTIPLIER );
839+ kvm_tdx -> attributes = td_params -> attributes ;
840+ kvm_tdx -> xfam = td_params -> xfam ;
841+
842+ kvm_tdx -> state = TD_STATE_INITIALIZED ;
843+ out :
844+ /* kfree() accepts NULL. */
845+ kfree (init_vm );
846+ kfree (td_params );
847+
848+ return ret ;
849+ }
850+
615851int tdx_vm_ioctl (struct kvm * kvm , void __user * argp )
616852{
617853 struct kvm_tdx_cmd tdx_cmd ;
@@ -633,6 +869,9 @@ int tdx_vm_ioctl(struct kvm *kvm, void __user *argp)
633869 case KVM_TDX_CAPABILITIES :
634870 r = tdx_get_capabilities (& tdx_cmd );
635871 break ;
872+ case KVM_TDX_INIT_VM :
873+ r = tdx_td_init (kvm , & tdx_cmd );
874+ break ;
636875 default :
637876 r = - EINVAL ;
638877 goto out ;
0 commit comments