2022-05-13 16:57:02 +02:00
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright ( C ) 2015 Pengutronix , Steffen Trumtrar < kernel @ pengutronix . de >
* Copyright ( C ) 2021 Pengutronix , Ahmad Fatoum < kernel @ pengutronix . de >
*/
# define pr_fmt(fmt) "caam blob_gen: " fmt
2022-11-21 15:12:41 +01:00
# include <linux/bitfield.h>
2022-05-13 16:57:02 +02:00
# include <linux/device.h>
# include <soc/fsl/caam-blob.h>
# include "compat.h"
# include "desc_constr.h"
# include "desc.h"
# include "error.h"
# include "intern.h"
# include "jr.h"
# include "regs.h"
# define CAAM_BLOB_DESC_BYTES_MAX \
/* Command to initialize & stating length of descriptor */ \
( CAAM_CMD_SZ + \
/* Command to append the key-modifier + key-modifier data */ \
CAAM_CMD_SZ + CAAM_BLOB_KEYMOD_LENGTH + \
/* Command to include input key + pointer to the input key */ \
CAAM_CMD_SZ + CAAM_PTR_SZ_MAX + \
/* Command to include output key + pointer to the output key */ \
CAAM_CMD_SZ + CAAM_PTR_SZ_MAX + \
/* Command describing the operation to perform */ \
CAAM_CMD_SZ )
struct caam_blob_priv {
struct device jrdev ;
} ;
struct caam_blob_job_result {
int err ;
struct completion completion ;
} ;
static void caam_blob_job_done ( struct device * dev , u32 * desc , u32 err , void * context )
{
struct caam_blob_job_result * res = context ;
int ecode = 0 ;
dev_dbg ( dev , " %s %d: err 0x%x \n " , __func__ , __LINE__ , err ) ;
if ( err )
ecode = caam_jr_strstatus ( dev , err ) ;
res - > err = ecode ;
/*
* Upon completion , desc points to a buffer containing a CAAM job
* descriptor which encapsulates data into an externally - storable
* blob .
*/
complete ( & res - > completion ) ;
}
int caam_process_blob ( struct caam_blob_priv * priv ,
struct caam_blob_info * info , bool encap )
{
2022-11-21 15:12:41 +01:00
const struct caam_drv_private * ctrlpriv ;
2022-05-13 16:57:02 +02:00
struct caam_blob_job_result testres ;
struct device * jrdev = & priv - > jrdev ;
dma_addr_t dma_in , dma_out ;
int op = OP_PCLID_BLOB ;
size_t output_len ;
u32 * desc ;
2022-11-21 15:12:41 +01:00
u32 moo ;
2022-05-13 16:57:02 +02:00
int ret ;
if ( info - > key_mod_len > CAAM_BLOB_KEYMOD_LENGTH )
return - EINVAL ;
if ( encap ) {
op | = OP_TYPE_ENCAP_PROTOCOL ;
output_len = info - > input_len + CAAM_BLOB_OVERHEAD ;
} else {
op | = OP_TYPE_DECAP_PROTOCOL ;
output_len = info - > input_len - CAAM_BLOB_OVERHEAD ;
}
desc = kzalloc ( CAAM_BLOB_DESC_BYTES_MAX , GFP_KERNEL | GFP_DMA ) ;
if ( ! desc )
return - ENOMEM ;
dma_in = dma_map_single ( jrdev , info - > input , info - > input_len ,
DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( jrdev , dma_in ) ) {
dev_err ( jrdev , " unable to map input DMA buffer \n " ) ;
ret = - ENOMEM ;
goto out_free ;
}
dma_out = dma_map_single ( jrdev , info - > output , output_len ,
DMA_FROM_DEVICE ) ;
if ( dma_mapping_error ( jrdev , dma_out ) ) {
dev_err ( jrdev , " unable to map output DMA buffer \n " ) ;
ret = - ENOMEM ;
goto out_unmap_in ;
}
2022-11-21 15:12:41 +01:00
ctrlpriv = dev_get_drvdata ( jrdev - > parent ) ;
moo = FIELD_GET ( CSTA_MOO , ioread32 ( & ctrlpriv - > ctrl - > perfmon . status ) ) ;
if ( moo ! = CSTA_MOO_SECURE & & moo ! = CSTA_MOO_TRUSTED )
dev_warn ( jrdev ,
" using insecure test key, enable HAB to use unique device key! \n " ) ;
2022-05-13 16:57:02 +02:00
/*
* A data blob is encrypted using a blob key ( BK ) ; a random number .
* The BK is used as an AES - CCM key . The initial block ( B0 ) and the
* initial counter ( Ctr0 ) are generated automatically and stored in
* Class 1 Context DWords 0 + 1 + 2 + 3. The random BK is stored in the
* Class 1 Key Register . Operation Mode is set to AES - CCM .
*/
init_job_desc ( desc , 0 ) ;
append_key_as_imm ( desc , info - > key_mod , info - > key_mod_len ,
info - > key_mod_len , CLASS_2 | KEY_DEST_CLASS_REG ) ;
append_seq_in_ptr_intlen ( desc , dma_in , info - > input_len , 0 ) ;
append_seq_out_ptr_intlen ( desc , dma_out , output_len , 0 ) ;
append_operation ( desc , op ) ;
print_hex_dump_debug ( " data@ " __stringify ( __LINE__ ) " : " ,
DUMP_PREFIX_ADDRESS , 16 , 1 , info - > input ,
info - > input_len , false ) ;
print_hex_dump_debug ( " jobdesc@ " __stringify ( __LINE__ ) " : " ,
DUMP_PREFIX_ADDRESS , 16 , 1 , desc ,
desc_bytes ( desc ) , false ) ;
testres . err = 0 ;
init_completion ( & testres . completion ) ;
ret = caam_jr_enqueue ( jrdev , desc , caam_blob_job_done , & testres ) ;
if ( ret = = - EINPROGRESS ) {
wait_for_completion ( & testres . completion ) ;
ret = testres . err ;
print_hex_dump_debug ( " output@ " __stringify ( __LINE__ ) " : " ,
DUMP_PREFIX_ADDRESS , 16 , 1 , info - > output ,
output_len , false ) ;
}
if ( ret = = 0 )
info - > output_len = output_len ;
dma_unmap_single ( jrdev , dma_out , output_len , DMA_FROM_DEVICE ) ;
out_unmap_in :
dma_unmap_single ( jrdev , dma_in , info - > input_len , DMA_TO_DEVICE ) ;
out_free :
kfree ( desc ) ;
return ret ;
}
EXPORT_SYMBOL ( caam_process_blob ) ;
struct caam_blob_priv * caam_blob_gen_init ( void )
{
struct caam_drv_private * ctrlpriv ;
struct device * jrdev ;
/*
* caam_blob_gen_init ( ) may expectedly fail with - ENODEV , e . g . when
* CAAM driver didn ' t probe or when SoC lacks BLOB support . An
* error would be harsh in this case , so we stick to info level .
*/
jrdev = caam_jr_alloc ( ) ;
if ( IS_ERR ( jrdev ) ) {
pr_info ( " job ring requested, but none currently available \n " ) ;
return ERR_PTR ( - ENODEV ) ;
}
ctrlpriv = dev_get_drvdata ( jrdev - > parent ) ;
if ( ! ctrlpriv - > blob_present ) {
dev_info ( jrdev , " no hardware blob generation support \n " ) ;
caam_jr_free ( jrdev ) ;
return ERR_PTR ( - ENODEV ) ;
}
return container_of ( jrdev , struct caam_blob_priv , jrdev ) ;
}
EXPORT_SYMBOL ( caam_blob_gen_init ) ;
void caam_blob_gen_exit ( struct caam_blob_priv * priv )
{
caam_jr_free ( & priv - > jrdev ) ;
}
EXPORT_SYMBOL ( caam_blob_gen_exit ) ;