@@ -112,9 +112,7 @@ enum qcom_scm_qseecom_tz_cmd_info {
112112 QSEECOM_TZ_CMD_INFO_VERSION = 3 ,
113113};
114114
115- enum qcom_scm_rsctable_resp_type {
116- RSCTABLE_BUFFER_NOT_SUFFICIENT = 20 ,
117- };
115+ #define RSCTABLE_BUFFER_NOT_SUFFICIENT 20
118116
119117#define QSEECOM_MAX_APP_NAME_SIZE 64
120118#define SHMBRIDGE_RESULT_NOTSUPP 4
@@ -564,8 +562,8 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
564562}
565563
566564/**
567- * devm_qcom_scm_pas_context_init () - Initialize peripheral authentication service
568- * context for a given peripheral
565+ * devm_qcom_scm_pas_context_alloc () - Allocate peripheral authentication service
566+ * context for a given peripheral
569567 *
570568 * PAS context is device-resource managed, so the caller does not need
571569 * to worry about freeing the context memory.
@@ -575,12 +573,12 @@ static void qcom_scm_set_download_mode(u32 dload_mode)
575573 * @mem_phys: Subsystem reserve memory start address
576574 * @mem_size: Subsystem reserve memory size
577575 *
578- * Upon successful, returns the PAS context or ERR_PTR() of the error otherwise .
576+ * Returns: The new PAS context, or ERR_PTR() on failure .
579577 */
580- struct qcom_scm_pas_context * devm_qcom_scm_pas_context_init (struct device * dev ,
581- u32 pas_id ,
582- phys_addr_t mem_phys ,
583- size_t mem_size )
578+ struct qcom_scm_pas_context * devm_qcom_scm_pas_context_alloc (struct device * dev ,
579+ u32 pas_id ,
580+ phys_addr_t mem_phys ,
581+ size_t mem_size )
584582{
585583 struct qcom_scm_pas_context * ctx ;
586584
@@ -595,7 +593,7 @@ struct qcom_scm_pas_context *devm_qcom_scm_pas_context_init(struct device *dev,
595593
596594 return ctx ;
597595}
598- EXPORT_SYMBOL_GPL (devm_qcom_scm_pas_context_init );
596+ EXPORT_SYMBOL_GPL (devm_qcom_scm_pas_context_alloc );
599597
600598static int __qcom_scm_pas_init_image (u32 pas_id , dma_addr_t mdata_phys ,
601599 struct qcom_scm_res * res )
@@ -677,7 +675,7 @@ int qcom_scm_pas_init_image(u32 pas_id, const void *metadata, size_t size,
677675 void * mdata_buf ;
678676 int ret ;
679677
680- if (ctx && ctx -> has_iommu )
678+ if (ctx && ctx -> use_tzmem )
681679 return qcom_scm_pas_prep_and_init_image (ctx , metadata , size );
682680
683681 /*
@@ -721,7 +719,7 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_context *ctx)
721719 if (!ctx -> ptr )
722720 return ;
723721
724- if (ctx -> has_iommu )
722+ if (ctx -> use_tzmem )
725723 qcom_tzmem_free (ctx -> ptr );
726724 else
727725 dma_free_coherent (__scm -> dev , ctx -> size , ctx -> ptr , ctx -> phys );
@@ -771,8 +769,9 @@ int qcom_scm_pas_mem_setup(u32 pas_id, phys_addr_t addr, phys_addr_t size)
771769}
772770EXPORT_SYMBOL_GPL (qcom_scm_pas_mem_setup );
773771
774- static int __qcom_scm_pas_get_rsc_table (u32 pas_id , void * input_rt , size_t input_rt_size ,
775- void * * output_rt , size_t * output_rt_size )
772+ static void * __qcom_scm_pas_get_rsc_table (u32 pas_id , void * input_rt_tzm ,
773+ size_t input_rt_size ,
774+ size_t * output_rt_size )
776775{
777776 struct qcom_scm_desc desc = {
778777 .svc = QCOM_SCM_SVC_PIL ,
@@ -782,80 +781,44 @@ static int __qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt, size_t input
782781 .args [0 ] = pas_id ,
783782 .owner = ARM_SMCCC_OWNER_SIP ,
784783 };
785- void * input_rt_buf , * output_rt_buf ;
786- struct resource_table * rsc ;
787784 struct qcom_scm_res res ;
785+ void * output_rt_tzm ;
788786 int ret ;
789787
790- ret = qcom_scm_clk_enable ();
791- if (ret )
792- return ret ;
793-
794- ret = qcom_scm_bw_enable ();
795- if (ret )
796- goto disable_clk ;
797-
798- /*
799- * TrustZone can not accept buffer as NULL value as argument Hence,
800- * we need to pass a input buffer indicating that subsystem firmware
801- * does not have resource table by filling resource table structure.
802- */
803- if (!input_rt )
804- input_rt_size = sizeof (* rsc );
805-
806- input_rt_buf = qcom_tzmem_alloc (__scm -> mempool , input_rt_size , GFP_KERNEL );
807- if (!input_rt_buf ) {
808- ret = - ENOMEM ;
809- goto disable_scm_bw ;
810- }
811-
812- if (!input_rt ) {
813- rsc = input_rt_buf ;
814- rsc -> num = 0 ;
815- } else {
816- memcpy (input_rt_buf , input_rt , input_rt_size );
817- }
818-
819- output_rt_buf = qcom_tzmem_alloc (__scm -> mempool , * output_rt_size , GFP_KERNEL );
820- if (!output_rt_buf ) {
821- ret = - ENOMEM ;
822- goto free_input_rt_buf ;
823- }
788+ output_rt_tzm = qcom_tzmem_alloc (__scm -> mempool , * output_rt_size , GFP_KERNEL );
789+ if (!output_rt_tzm )
790+ return ERR_PTR (- ENOMEM );
824791
825- desc .args [1 ] = qcom_tzmem_to_phys (input_rt_buf );
792+ desc .args [1 ] = qcom_tzmem_to_phys (input_rt_tzm );
826793 desc .args [2 ] = input_rt_size ;
827- desc .args [3 ] = qcom_tzmem_to_phys (output_rt_buf );
794+ desc .args [3 ] = qcom_tzmem_to_phys (output_rt_tzm );
828795 desc .args [4 ] = * output_rt_size ;
829796
830797 /*
831798 * Whether SMC fail or pass, res.result[2] will hold actual resource table
832799 * size.
833800 *
834- * if passed 'output_rt_size' buffer size is not sufficient to hold the
801+ * If passed 'output_rt_size' buffer size is not sufficient to hold the
835802 * resource table TrustZone sends, response code in res.result[1] as
836- * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call with
837- * output_rt buffer with res.result[2] size.
803+ * RSCTABLE_BUFFER_NOT_SUFFICIENT so that caller can retry this SMC call
804+ * with output_rt_tzm buffer with res.result[2] size however, It should not
805+ * be of unresonable size.
838806 */
839807 ret = qcom_scm_call (__scm -> dev , & desc , & res );
840- * output_rt_size = res .result [2 ];
841- if (!ret )
842- memcpy (* output_rt , output_rt_buf , * output_rt_size );
808+ if (!ret && res .result [2 ] > SZ_1G ) {
809+ ret = - E2BIG ;
810+ goto free_output_rt ;
811+ }
843812
813+ * output_rt_size = res .result [2 ];
844814 if (ret && res .result [1 ] == RSCTABLE_BUFFER_NOT_SUFFICIENT )
845- ret = - EAGAIN ;
846-
847- qcom_tzmem_free (output_rt_buf );
848-
849- free_input_rt_buf :
850- qcom_tzmem_free (input_rt_buf );
815+ ret = - EOVERFLOW ;
851816
852- disable_scm_bw :
853- qcom_scm_bw_disable ();
854-
855- disable_clk :
856- qcom_scm_clk_disable ();
817+ free_output_rt :
818+ if (ret )
819+ qcom_tzmem_free (output_rt_tzm );
857820
858- return ret ? : res . result [ 0 ] ;
821+ return ret ? ERR_PTR ( ret ) : output_rt_tzm ;
859822}
860823
861824/**
@@ -877,7 +840,7 @@ static int __qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt, size_t input
877840 * If the remote processor firmware binary does contain static resources, they
878841 * should be passed in input_rt. These will be forwarded to TrustZone for
879842 * authentication. TrustZone will then append the dynamic resources and return
880- * the complete resource table in output_rt .
843+ * the complete resource table in output_rt_tzm .
881844 *
882845 * If the remote processor firmware binary does not include a resource table,
883846 * the caller of this function should set input_rt as NULL and input_rt_size
@@ -890,37 +853,87 @@ static int __qcom_scm_pas_get_rsc_table(u32 pas_id, void *input_rt, size_t input
890853 * @pas_id: peripheral authentication service id
891854 * @input_rt: resource table buffer which is present in firmware binary
892855 * @input_rt_size: size of the resource table present in firmware binary
893- * @output_rt: buffer to which the both static and dynamic resources will
894- * be returned.
895856 * @output_rt_size: TrustZone expects caller should pass worst case size for
896- * the output_rt.
897- *
898- * Return: 0 on success and nonzero on failure.
857+ * the output_rt_tzm.
899858 *
900- * Upon successful return, output_rt will have the resource table and output_rt_size
901- * will have actual resource table size,
859+ * Return:
860+ * On success, returns a pointer to the allocated buffer containing the final
861+ * resource table and output_rt_size will have actual resource table size from
862+ * TrustZone. The caller is responsible for freeing the buffer. On failure,
863+ * returns ERR_PTR(-errno).
902864 */
903- int qcom_scm_pas_get_rsc_table (struct qcom_scm_pas_context * ctx , void * input_rt ,
904- size_t input_rt_size , void * * output_rt ,
905- size_t * output_rt_size )
906- {
907- unsigned int retry_num = 5 ;
865+ struct resource_table * qcom_scm_pas_get_rsc_table (struct qcom_scm_pas_context * ctx ,
866+ void * input_rt ,
867+ size_t input_rt_size ,
868+ size_t * output_rt_size )
869+ {
870+ struct resource_table empty_rsc = {};
871+ size_t size = SZ_16K ;
872+ void * output_rt_tzm ;
873+ void * input_rt_tzm ;
874+ void * tbl_ptr ;
908875 int ret ;
909876
910- do {
911- * output_rt = kzalloc (* output_rt_size , GFP_KERNEL );
912- if (!* output_rt )
913- return - ENOMEM ;
877+ ret = qcom_scm_clk_enable ();
878+ if (ret )
879+ return ERR_PTR (ret );
914880
915- ret = __qcom_scm_pas_get_rsc_table (ctx -> pas_id , input_rt ,
916- input_rt_size , output_rt ,
917- output_rt_size );
918- if (ret )
919- kfree (* output_rt );
881+ ret = qcom_scm_bw_enable ();
882+ if (ret )
883+ goto disable_clk ;
884+
885+ /*
886+ * TrustZone can not accept buffer as NULL value as argument hence,
887+ * we need to pass a input buffer indicating that subsystem firmware
888+ * does not have resource table by filling resource table structure.
889+ */
890+ if (!input_rt ) {
891+ input_rt = & empty_rsc ;
892+ input_rt_size = sizeof (empty_rsc );
893+ }
894+
895+ input_rt_tzm = qcom_tzmem_alloc (__scm -> mempool , input_rt_size , GFP_KERNEL );
896+ if (!input_rt_tzm ) {
897+ ret = - ENOMEM ;
898+ goto disable_scm_bw ;
899+ }
920900
921- } while (ret == - EAGAIN && -- retry_num );
901+ memcpy (input_rt_tzm , input_rt , input_rt_size );
902+
903+ output_rt_tzm = __qcom_scm_pas_get_rsc_table (ctx -> pas_id , input_rt_tzm ,
904+ input_rt_size , & size );
905+ if (PTR_ERR (output_rt_tzm ) == - EOVERFLOW )
906+ /* Try again with the size requested by the TZ */
907+ output_rt_tzm = __qcom_scm_pas_get_rsc_table (ctx -> pas_id ,
908+ input_rt_tzm ,
909+ input_rt_size ,
910+ & size );
911+ if (IS_ERR (output_rt_tzm )) {
912+ ret = PTR_ERR (output_rt_tzm );
913+ goto free_input_rt ;
914+ }
922915
923- return ret ;
916+ tbl_ptr = kzalloc (size , GFP_KERNEL );
917+ if (!tbl_ptr ) {
918+ qcom_tzmem_free (output_rt_tzm );
919+ ret = - ENOMEM ;
920+ goto free_input_rt ;
921+ }
922+
923+ memcpy (tbl_ptr , output_rt_tzm , size );
924+ * output_rt_size = size ;
925+ qcom_tzmem_free (output_rt_tzm );
926+
927+ free_input_rt :
928+ qcom_tzmem_free (input_rt_tzm );
929+
930+ disable_scm_bw :
931+ qcom_scm_bw_disable ();
932+
933+ disable_clk :
934+ qcom_scm_clk_disable ();
935+
936+ return ret ? ERR_PTR (ret ) : tbl_ptr ;
924937}
925938EXPORT_SYMBOL_GPL (qcom_scm_pas_get_rsc_table );
926939
@@ -985,22 +998,21 @@ int qcom_scm_pas_prepare_and_auth_reset(struct qcom_scm_pas_context *ctx)
985998 u64 handle ;
986999 int ret ;
9871000
988- if (!ctx -> has_iommu )
989- return qcom_scm_pas_auth_and_reset (ctx -> pas_id );
990-
9911001 /*
9921002 * When Linux running @ EL1, Gunyah hypervisor running @ EL2 traps the
9931003 * auth_and_reset call and create an shmbridge on the remote subsystem
9941004 * memory region and then invokes a call to TrustZone to authenticate.
1005+ */
1006+ if (!ctx -> use_tzmem )
1007+ return qcom_scm_pas_auth_and_reset (ctx -> pas_id );
1008+
1009+ /*
9951010 * When Linux runs @ EL2 Linux must create the shmbridge itself and then
9961011 * subsequently call TrustZone for authenticate and reset.
9971012 */
9981013 ret = qcom_tzmem_shm_bridge_create (ctx -> mem_phys , ctx -> mem_size , & handle );
999- if (ret ) {
1000- dev_err (__scm -> dev , "Failed to create shmbridge for PAS ID (%u): %d\n" ,
1001- ctx -> pas_id , ret );
1014+ if (ret )
10021015 return ret ;
1003- }
10041016
10051017 ret = qcom_scm_pas_auth_and_reset (ctx -> pas_id );
10061018 qcom_tzmem_shm_bridge_delete (handle );
0 commit comments