@@ -183,6 +183,78 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags,
183183 return ERR_PTR (ret );
184184}
185185
186+ static void set_dte_nested (struct amd_iommu * iommu , struct iommu_domain * dom ,
187+ struct iommu_dev_data * dev_data , struct dev_table_entry * new )
188+ {
189+ struct protection_domain * parent ;
190+ struct nested_domain * ndom = to_ndomain (dom );
191+ struct iommu_hwpt_amd_guest * gdte = & ndom -> gdte ;
192+ struct pt_iommu_amdv1_hw_info pt_info ;
193+
194+ /*
195+ * The nest parent domain is attached during the call to the
196+ * struct iommu_ops.viommu_init(), which will be stored as part
197+ * of the struct amd_iommu_viommu.parent.
198+ */
199+ if (WARN_ON (!ndom -> viommu || !ndom -> viommu -> parent ))
200+ return ;
201+
202+ parent = ndom -> viommu -> parent ;
203+ amd_iommu_make_clear_dte (dev_data , new );
204+
205+ /* Retrieve the current pagetable info via the IOMMU PT API. */
206+ pt_iommu_amdv1_hw_info (& parent -> amdv1 , & pt_info );
207+
208+ /*
209+ * Use domain ID from nested domain to program DTE.
210+ * See amd_iommu_alloc_domain_nested().
211+ */
212+ amd_iommu_set_dte_v1 (dev_data , parent , ndom -> gdom_info -> hdom_id ,
213+ & pt_info , new );
214+
215+ /* GV is required for nested page table */
216+ new -> data [0 ] |= DTE_FLAG_GV ;
217+
218+ /* Guest PPR */
219+ new -> data [0 ] |= gdte -> dte [0 ] & DTE_FLAG_PPR ;
220+
221+ /* Guest translation stuff */
222+ new -> data [0 ] |= gdte -> dte [0 ] & (DTE_GLX | DTE_FLAG_GIOV );
223+
224+ /* GCR3 table */
225+ new -> data [0 ] |= gdte -> dte [0 ] & DTE_GCR3_14_12 ;
226+ new -> data [1 ] |= gdte -> dte [1 ] & (DTE_GCR3_30_15 | DTE_GCR3_51_31 );
227+
228+ /* Guest paging mode */
229+ new -> data [2 ] |= gdte -> dte [2 ] & DTE_GPT_LEVEL_MASK ;
230+ }
231+
232+ static int nested_attach_device (struct iommu_domain * dom , struct device * dev ,
233+ struct iommu_domain * old )
234+ {
235+ struct dev_table_entry new = {0 };
236+ struct iommu_dev_data * dev_data = dev_iommu_priv_get (dev );
237+ struct amd_iommu * iommu = get_amd_iommu_from_dev_data (dev_data );
238+ int ret = 0 ;
239+
240+ /*
241+ * Needs to make sure PASID is not enabled
242+ * for this attach path.
243+ */
244+ if (WARN_ON (dev_data -> pasid_enabled ))
245+ return - EINVAL ;
246+
247+ mutex_lock (& dev_data -> mutex );
248+
249+ set_dte_nested (iommu , dom , dev_data , & new );
250+
251+ amd_iommu_update_dte (iommu , dev_data , & new );
252+
253+ mutex_unlock (& dev_data -> mutex );
254+
255+ return ret ;
256+ }
257+
186258static void nested_domain_free (struct iommu_domain * dom )
187259{
188260 struct guest_domain_mapping_info * curr ;
@@ -217,5 +289,6 @@ static void nested_domain_free(struct iommu_domain *dom)
217289}
218290
219291static const struct iommu_domain_ops nested_domain_ops = {
292+ .attach_dev = nested_attach_device ,
220293 .free = nested_domain_free ,
221294};
0 commit comments