nxp:driver for crypto h/w accelerator caam
NXP has hardware crypto accelerator called CAAM. - Work with Job ring - Jobs are submitted to CAAM in the form of 64 word descriptor. Signed-off-by: Ruchika Gupta <ruchika.gupta@nxp.com> Signed-off-by: Pankaj Gupta <pankaj.gupta@nxp.com> Change-Id: I02bcfce68143b8630e1833a74c4b126972f4323d
This commit is contained in:
parent
066ee1add1
commit
a0edacb8f0
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# Copyright 2020 NXP
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
#
|
||||
|
||||
ifeq (${ADD_CAAM},)
|
||||
|
||||
ADD_CAAM := 1
|
||||
CAAM_DRIVER_PATH := drivers/nxp/crypto/caam
|
||||
|
||||
CAAM_DRIVER_SOURCES += $(wildcard $(CAAM_DRIVER_PATH)/src/*.c)
|
||||
|
||||
PLAT_INCLUDES += -I$(CAAM_DRIVER_PATH)/include
|
||||
|
||||
ifeq (${BL_COMM_CRYPTO_NEEDED},yes)
|
||||
BL_COMMON_SOURCES += ${CAAM_DRIVER_SOURCES}
|
||||
else
|
||||
ifeq (${BL2_CRYPTO_NEEDED},yes)
|
||||
BL2_SOURCES += ${CAAM_DRIVER_SOURCES}
|
||||
endif
|
||||
ifeq (${BL31_CRYPTO_NEEDED},yes)
|
||||
BL31_SOURCES += ${CAAM_DRIVER_SOURCES}
|
||||
endif
|
||||
endif
|
||||
|
||||
endif
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CAAM_H
|
||||
#define CAAM_H
|
||||
|
||||
#include "caam_io.h"
|
||||
#include "sec_jr_driver.h"
|
||||
|
||||
|
||||
/* Job ring 3 is reserved for usage by sec firmware */
|
||||
#define DEFAULT_JR 3
|
||||
|
||||
#if defined(CONFIG_CHASSIS_3_2) || defined(CONFIG_CHASSIS_2)
|
||||
#define CAAM_JR0_OFFSET 0x10000
|
||||
#define CAAM_JR1_OFFSET 0x20000
|
||||
#define CAAM_JR2_OFFSET 0x30000
|
||||
#define CAAM_JR3_OFFSET 0x40000
|
||||
#endif
|
||||
|
||||
enum sig_alg {
|
||||
RSA,
|
||||
ECC
|
||||
};
|
||||
|
||||
/* This function does basic SEC Initialization */
|
||||
int sec_init(uintptr_t nxp_caam_addr);
|
||||
int config_sec_block(void);
|
||||
uintptr_t get_caam_addr(void);
|
||||
|
||||
/* This function is used to submit jobs to JR */
|
||||
int run_descriptor_jr(struct job_descriptor *desc);
|
||||
|
||||
/* This function is used to instatiate the HW RNG is already not instantiated */
|
||||
int hw_rng_instantiate(void);
|
||||
|
||||
/* This function is used to return random bytes of byte_len from HW RNG */
|
||||
int get_rand_bytes_hw(uint8_t *bytes, int byte_len);
|
||||
|
||||
/* This function is used to set the hw unique key from HW CAAM */
|
||||
int get_hw_unq_key_blob_hw(uint8_t *hw_key, int size);
|
||||
|
||||
/* This function is used to fetch random number from
|
||||
* CAAM of length either of 4 bytes or 8 bytes depending
|
||||
* rngWidth value.
|
||||
*/
|
||||
unsigned long long get_random(int rngWidth);
|
||||
|
||||
#endif /* CAAM_H */
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2018-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CAAM_IO_H
|
||||
#define CAAM_IO_H
|
||||
|
||||
#include <endian.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
typedef unsigned long long phys_addr_t;
|
||||
typedef unsigned long long phys_size_t;
|
||||
|
||||
/* Return higher 32 bits of physical address */
|
||||
#define PHYS_ADDR_HI(phys_addr) \
|
||||
(uint32_t)(((uint64_t)phys_addr) >> 32)
|
||||
|
||||
/* Return lower 32 bits of physical address */
|
||||
#define PHYS_ADDR_LO(phys_addr) \
|
||||
(uint32_t)(((uint64_t)phys_addr) & 0xFFFFFFFF)
|
||||
|
||||
#ifdef NXP_SEC_BE
|
||||
#define sec_in32(a) bswap32(mmio_read_32((uintptr_t)(a)))
|
||||
#define sec_out32(a, v) mmio_write_32((uintptr_t)(a), bswap32(v))
|
||||
#define sec_in64(addr) ( \
|
||||
((uint64_t)sec_in32((uintptr_t)(addr)) << 32) | \
|
||||
(sec_in32(((uintptr_t)(addr)) + 4)))
|
||||
#define sec_out64(addr, val) ({ \
|
||||
sec_out32(((uintptr_t)(addr)), (uint32_t)((val) >> 32)); \
|
||||
sec_out32(((uintptr_t)(addr)) + 4, (uint32_t)(val)); })
|
||||
#elif defined(NXP_SEC_LE)
|
||||
#define sec_in32(a) mmio_read_32((uintptr_t)(a))
|
||||
#define sec_out32(a, v) mmio_write_32((uintptr_t)(a), (v))
|
||||
#define sec_in64(addr) ( \
|
||||
((uint64_t)sec_in32((uintptr_t)(addr) + 4) << 32) | \
|
||||
(sec_in32((uintptr_t)(addr))))
|
||||
#define sec_out64(addr, val) ({ \
|
||||
sec_out32(((uintptr_t)(addr)) + 4, (uint32_t)((val) >> 32)); \
|
||||
sec_out32(((uintptr_t)(addr)), (uint32_t)(val)); })
|
||||
#else
|
||||
#error Please define CCSR SEC register endianness
|
||||
#endif
|
||||
|
||||
static inline void *ptov(phys_addr_t *ptr)
|
||||
{
|
||||
return (void *)ptr;
|
||||
}
|
||||
|
||||
static inline phys_addr_t *vtop(void *ptr)
|
||||
{
|
||||
return (phys_addr_t *)ptr;
|
||||
}
|
||||
#endif /* CAAM_IO_H */
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __HASH_H__
|
||||
#define __HASH_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* List of hash algorithms */
|
||||
enum hash_algo {
|
||||
SHA1 = 0,
|
||||
SHA256
|
||||
};
|
||||
|
||||
/* number of bytes in the SHA256-256 digest */
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
/*
|
||||
* number of words in the digest - Digest is kept internally
|
||||
* as 8 32-bit words
|
||||
*/
|
||||
#define _SHA256_DIGEST_LENGTH 8
|
||||
|
||||
/*
|
||||
* block length - A block, treated as a sequence of
|
||||
* 32-bit words
|
||||
*/
|
||||
#define SHA256_BLOCK_LENGTH 16
|
||||
|
||||
/* number of bytes in the block */
|
||||
#define SHA256_DATA_SIZE 64
|
||||
|
||||
#define MAX_SG 12
|
||||
|
||||
struct sg_entry {
|
||||
#if defined(NXP_SEC_LE)
|
||||
uint32_t addr_lo; /* Memory Address - lo */
|
||||
uint32_t addr_hi; /* Memory Address of start of buffer - hi */
|
||||
#else
|
||||
uint32_t addr_hi; /* Memory Address of start of buffer - hi */
|
||||
uint32_t addr_lo; /* Memory Address - lo */
|
||||
#endif
|
||||
|
||||
uint32_t len_flag; /* Length of the data in the frame */
|
||||
#define SG_ENTRY_LENGTH_MASK 0x3FFFFFFF
|
||||
#define SG_ENTRY_EXTENSION_BIT 0x80000000
|
||||
#define SG_ENTRY_FINAL_BIT 0x40000000
|
||||
uint32_t bpid_offset;
|
||||
#define SG_ENTRY_BPID_MASK 0x00FF0000
|
||||
#define SG_ENTRY_BPID_SHIFT 16
|
||||
#define SG_ENTRY_OFFSET_MASK 0x00001FFF
|
||||
#define SG_ENTRY_OFFSET_SHIFT 0
|
||||
};
|
||||
|
||||
/*
|
||||
* SHA256-256 context
|
||||
* contain the following fields
|
||||
* State
|
||||
* count low
|
||||
* count high
|
||||
* block data buffer
|
||||
* index to the buffer
|
||||
*/
|
||||
struct hash_ctx {
|
||||
struct sg_entry sg_tbl[MAX_SG];
|
||||
uint32_t hash_desc[64];
|
||||
uint8_t hash[SHA256_DIGEST_SIZE];
|
||||
uint32_t sg_num;
|
||||
uint32_t len;
|
||||
uint8_t *data;
|
||||
enum hash_algo algo;
|
||||
bool active;
|
||||
};
|
||||
|
||||
int hash_init(enum hash_algo algo, void **ctx);
|
||||
int hash_update(enum hash_algo algo, void *context, void *data_ptr,
|
||||
unsigned int data_len);
|
||||
int hash_final(enum hash_algo algo, void *context, void *hash_ptr,
|
||||
unsigned int hash_len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __JOBDESC_H
|
||||
#define __JOBDESC_H
|
||||
|
||||
#include <rsa.h>
|
||||
|
||||
#define DESC_LEN_MASK 0x7f
|
||||
#define DESC_START_SHIFT 16
|
||||
|
||||
#define KEY_BLOB_SIZE 32
|
||||
#define MAC_SIZE 16
|
||||
|
||||
#define KEY_IDNFR_SZ_BYTES 16
|
||||
#define CLASS_SHIFT 25
|
||||
#define CLASS_2 (0x02 << CLASS_SHIFT)
|
||||
|
||||
#define CMD_SHIFT 27
|
||||
#define CMD_OPERATION (U(0x10) << CMD_SHIFT)
|
||||
|
||||
#define OP_TYPE_SHIFT 24
|
||||
#define OP_TYPE_ENCAP_PROTOCOL (0x07 << OP_TYPE_SHIFT)
|
||||
|
||||
/* Assuming OP_TYPE = OP_TYPE_UNI_PROTOCOL */
|
||||
#define OP_PCLID_SHIFT 16
|
||||
#define OP_PCLID_BLOB (0x0d << OP_PCLID_SHIFT)
|
||||
|
||||
#define BLOB_PROTO_INFO 0x00000002
|
||||
|
||||
uint32_t desc_length(uint32_t *desc);
|
||||
|
||||
int cnstr_rng_jobdesc(uint32_t *desc, uint32_t state_handle,
|
||||
uint32_t *add_inp, uint32_t add_ip_len,
|
||||
uint8_t *out_data, uint32_t len);
|
||||
|
||||
int cnstr_rng_instantiate_jobdesc(uint32_t *desc);
|
||||
|
||||
/* Construct descriptor to generate hw key blob */
|
||||
int cnstr_hw_encap_blob_jobdesc(uint32_t *desc,
|
||||
uint8_t *key_idnfr, uint32_t key_sz,
|
||||
uint32_t key_class, uint8_t *plain_txt,
|
||||
uint32_t in_sz, uint8_t *enc_blob,
|
||||
uint32_t out_sz, uint32_t operation);
|
||||
|
||||
void cnstr_hash_jobdesc(uint32_t *desc, uint8_t *msg, uint32_t msgsz,
|
||||
uint8_t *digest);
|
||||
|
||||
void cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
|
||||
struct pk_in_params *pkin, uint8_t *out,
|
||||
uint32_t out_siz);
|
||||
#endif
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JR_DRIVER_CONFIG_H_
|
||||
#define _JR_DRIVER_CONFIG_H_
|
||||
|
||||
/* Helper defines */
|
||||
|
||||
/* Define used for setting a flag on */
|
||||
#define ON 1
|
||||
/* Define used for setting a flag off */
|
||||
#define OFF 0
|
||||
|
||||
/* SEC is configured to start work in polling mode, */
|
||||
#define SEC_STARTUP_POLLING_MODE 0
|
||||
/*
|
||||
* SEC is configured to start work in interrupt mode,
|
||||
* when configured for NAPI notification style.
|
||||
*/
|
||||
#define SEC_STARTUP_INTERRUPT_MODE 1
|
||||
|
||||
/*
|
||||
* SEC driver will use ONLY interrupts to receive notifications
|
||||
* for processed packets from SEC engine hardware.
|
||||
*/
|
||||
#define SEC_NOTIFICATION_TYPE_IRQ 1
|
||||
/*
|
||||
* SEC driver will use ONLY polling to receive notifications
|
||||
* for processed packets from SEC engine hardware.
|
||||
*/
|
||||
#define SEC_NOTIFICATION_TYPE_POLL 2
|
||||
|
||||
/*
|
||||
* Determines how SEC user space driver will receive notifications
|
||||
* for processed packets from SEC engine.
|
||||
* Valid values are: #SEC_NOTIFICATION_TYPE_POLL, #SEC_NOTIFICATION_TYPE_IRQ
|
||||
*/
|
||||
#define SEC_NOTIFICATION_TYPE SEC_NOTIFICATION_TYPE_POLL
|
||||
|
||||
/* Maximum number of job rings supported by SEC hardware */
|
||||
#define MAX_SEC_JOB_RINGS 1
|
||||
|
||||
/*
|
||||
* Size of cryptographic context that is used directly in communicating
|
||||
* with SEC device.
|
||||
* SEC device works only with physical addresses. This is the maximum size
|
||||
* for a SEC descriptor ( = 64 words).
|
||||
*/
|
||||
|
||||
#define SEC_CRYPTO_DESCRIPTOR_SIZE 256
|
||||
|
||||
/*
|
||||
* Size of job descriptor submitted to SEC device for each packet to be
|
||||
* processed.
|
||||
* Job descriptor contains 3 DMA address pointers:
|
||||
* - to shared descriptor, to input buffer and to output buffer.
|
||||
* The job descriptor contains other SEC specific commands as well:
|
||||
* - HEADER command, SEQ IN PTR command SEQ OUT PTR command and opaque
|
||||
* data, each measuring 4 bytes.
|
||||
* Job descriptor size, depending on physical address representation:
|
||||
* - 32 bit - size is 28 bytes - cacheline-aligned size is 64 bytes
|
||||
* - 36 bit - size is 40 bytes - cacheline-aligned size is 64 bytes
|
||||
* @note: Job descriptor must be cacheline-aligned to ensure efficient memory
|
||||
* access.
|
||||
* @note: If other format is used for job descriptor, then the size must be
|
||||
* revised.
|
||||
*/
|
||||
|
||||
#define SEC_JOB_DESCRIPTOR_SIZE 64
|
||||
|
||||
/*
|
||||
* Size of one entry in the input ring of a job ring.
|
||||
* Input ring contains pointers to job descriptors.
|
||||
* The memory used for an input ring and output ring must be physically
|
||||
* contiguous.
|
||||
*/
|
||||
|
||||
#define SEC_JOB_INPUT_RING_ENTRY_SIZE sizeof(phys_addr_t)
|
||||
|
||||
/*
|
||||
* Size of one entry in the output ring of a job ring.
|
||||
* Output ring entry is a pointer to a job descriptor followed by a 4 byte
|
||||
* status word.
|
||||
* The memory used for an input ring and output ring must be physically
|
||||
* contiguous.
|
||||
* @note If desired to use also the optional SEQ OUT indication in output
|
||||
* ring entries, then 4 more bytes must be added to the size.
|
||||
*/
|
||||
|
||||
#define SEC_JOB_OUTPUT_RING_ENTRY_SIZE (SEC_JOB_INPUT_RING_ENTRY_SIZE + 4)
|
||||
|
||||
/* DMA memory required for an input ring of a job ring. */
|
||||
#define SEC_DMA_MEM_INPUT_RING_SIZE \
|
||||
((SEC_JOB_INPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE))
|
||||
|
||||
/*
|
||||
* DMA memory required for an output ring of a job ring.
|
||||
* Required extra 4 byte for status word per each entry.
|
||||
*/
|
||||
#define SEC_DMA_MEM_OUTPUT_RING_SIZE \
|
||||
((SEC_JOB_OUTPUT_RING_ENTRY_SIZE) * (SEC_JOB_RING_SIZE))
|
||||
|
||||
/* DMA memory required for descriptors of a job ring. */
|
||||
#define SEC_DMA_MEM_DESCRIPTORS \
|
||||
((SEC_CRYPTO_DESCRIPTOR_SIZE)*(SEC_JOB_RING_SIZE))
|
||||
|
||||
/* DMA memory required for a job ring, including both input output rings. */
|
||||
#define SEC_DMA_MEM_JOB_RING_SIZE \
|
||||
((SEC_DMA_MEM_INPUT_RING_SIZE) + \
|
||||
(SEC_DMA_MEM_OUTPUT_RING_SIZE))
|
||||
|
||||
/*
|
||||
* When calling sec_init() UA will provide an area of virtual memory
|
||||
* of size #SEC_DMA_MEMORY_SIZE to be used internally by the driver
|
||||
* to allocate data (like SEC descriptors) that needs to be passed to
|
||||
* SEC device in physical addressing and later on retrieved from SEC device.
|
||||
* At initialization the UA provides specialized ptov/vtop functions/macros to
|
||||
* translate addresses allocated from this memory area.
|
||||
*/
|
||||
#define SEC_DMA_MEMORY_SIZE \
|
||||
((SEC_DMA_MEM_JOB_RING_SIZE) * (MAX_SEC_JOB_RINGS))
|
||||
|
||||
/*
|
||||
* SEC DEVICE related configuration.
|
||||
|
||||
* Enable/Disable logging support at compile time.
|
||||
* Valid values:
|
||||
* ON - enable logging
|
||||
* OFF - disable logging
|
||||
* The messages are logged at stdout.
|
||||
*/
|
||||
|
||||
#define SEC_DRIVER_LOGGING OFF
|
||||
|
||||
/*
|
||||
* Configure logging level at compile time.
|
||||
* Valid values:
|
||||
* SEC_DRIVER_LOG_ERROR - log only errors
|
||||
* SEC_DRIVER_LOG_INFO - log errors and info messages
|
||||
* SEC_DRIVER_LOG_DEBUG - log errors, info and debug messages
|
||||
*/
|
||||
|
||||
#define SEC_DRIVER_LOGGING_LEVEL SEC_DRIVER_LOG_DEBUG
|
||||
|
||||
/*
|
||||
* SEC JOB RING related configuration.
|
||||
|
||||
* Configure the size of the JOB RING.
|
||||
* The maximum size of the ring is hardware limited to 1024.
|
||||
* However the number of packets in flight in a time interval of
|
||||
* 1ms can be calculated
|
||||
* from the traffic rate (Mbps) and packet size.
|
||||
* Here it was considered a packet size of 40 bytes.
|
||||
* @note Round up to nearest power of 2 for optimized update
|
||||
* of producer/consumer indexes of each job ring
|
||||
* \todo Should set to 750, according to the calculation above, but
|
||||
* the JR size must be power of 2, thus the next closest value must
|
||||
* be chosen (i.e. 512 since 1024 is not available)
|
||||
* For firmware choose this to be 16
|
||||
*/
|
||||
|
||||
#define SEC_JOB_RING_SIZE 16
|
||||
|
||||
/*
|
||||
* Interrupt coalescing related configuration.
|
||||
* NOTE: SEC hardware enabled interrupt
|
||||
* coalescing is not supported on SEC version 3.1!
|
||||
* SEC version 4.4 has support for interrupt
|
||||
* coalescing.
|
||||
*/
|
||||
|
||||
#if SEC_NOTIFICATION_TYPE != SEC_NOTIFICATION_TYPE_POLL
|
||||
|
||||
#define SEC_INT_COALESCING_ENABLE ON
|
||||
/*
|
||||
* Interrupt Coalescing Descriptor Count Threshold.
|
||||
* While interrupt coalescing is enabled (ICEN=1), this value determines
|
||||
* how many Descriptors are completed before raising an interrupt.
|
||||
* Valid values for this field are from 0 to 255.
|
||||
* Note that a value of 1 functionally defeats the advantages of interrupt
|
||||
* coalescing since the threshold value is reached each time that a
|
||||
* Job Descriptor is completed. A value of 0 is treated in the same
|
||||
* manner as a value of 1.
|
||||
*
|
||||
*/
|
||||
#define SEC_INTERRUPT_COALESCING_DESCRIPTOR_COUNT_THRESH 10
|
||||
|
||||
/*
|
||||
* Interrupt Coalescing Timer Threshold.
|
||||
* While interrupt coalescing is enabled (ICEN=1), this value determines the
|
||||
* maximum amount of time after processing a Descriptor before raising an
|
||||
* interrupt.
|
||||
* The threshold value is represented in units equal to 64 CAAM interface
|
||||
* clocks. Valid values for this field are from 1 to 65535.
|
||||
* A value of 0 results in behavior identical to that when interrupt
|
||||
* coalescing is disabled.
|
||||
*/
|
||||
#define SEC_INTERRUPT_COALESCING_TIMER_THRESH 100
|
||||
#endif /* SEC_NOTIFICATION_TYPE_POLL */
|
||||
|
||||
#endif /* _JR_DRIVER_CONFIG_H_ */
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RSA_H__
|
||||
#define _RSA_H__
|
||||
|
||||
/* RSA key size defines */
|
||||
#define RSA_4K_KEY_SZ 4096
|
||||
#define RSA_4K_KEY_SZ_BYTES (RSA_4K_KEY_SZ/8)
|
||||
#define RSA_2K_KEY_SZ 2048
|
||||
#define RSA_2K_KEY_SZ_BYTES (RSA_2K_KEY_SZ/8)
|
||||
#define RSA_1K_KEY_SZ 1024
|
||||
#define RSA_1K_KEY_SZ_BYTES (RSA_1K_KEY_SZ/8)
|
||||
|
||||
#define SHA256_BYTES (256/8)
|
||||
|
||||
struct pk_in_params {
|
||||
uint8_t *e;
|
||||
uint32_t e_siz;
|
||||
uint8_t *n;
|
||||
uint32_t n_siz;
|
||||
uint8_t *a;
|
||||
uint32_t a_siz;
|
||||
uint8_t *b;
|
||||
uint32_t b_siz;
|
||||
};
|
||||
|
||||
struct rsa_context {
|
||||
struct pk_in_params pkin;
|
||||
};
|
||||
|
||||
int rsa_verify_signature(void *hash_ptr, unsigned int hash_len,
|
||||
void *sig_ptr, unsigned int sig_len,
|
||||
void *pk_ptr, unsigned int pk_len);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,506 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SEC_HW_SPECIFIC_H_
|
||||
#define _SEC_HW_SPECIFIC_H_
|
||||
|
||||
#include "caam.h"
|
||||
#include "sec_jr_driver.h"
|
||||
|
||||
/* DEFINES AND MACROS */
|
||||
|
||||
/* Used to retry resetting a job ring in SEC hardware. */
|
||||
#define SEC_TIMEOUT 100000
|
||||
|
||||
/*
|
||||
* Offset to the registers of a job ring.
|
||||
*Is different for each job ring.
|
||||
*/
|
||||
#define CHAN_BASE(jr) ((phys_addr_t)(jr)->register_base_addr)
|
||||
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
#define SEC_JOB_RING_IS_FULL(pi, ci, ring_max_size, ring_threshold) \
|
||||
((((pi) + 1 + ((ring_max_size) - (ring_threshold))) & \
|
||||
(ring_max_size - 1)) == ((ci)))
|
||||
|
||||
#define SEC_CIRCULAR_COUNTER(x, max) (((x) + 1) & (max - 1))
|
||||
|
||||
/* Struct representing various job ring registers */
|
||||
struct jobring_regs {
|
||||
#ifdef NXP_SEC_BE
|
||||
unsigned int irba_h;
|
||||
unsigned int irba_l;
|
||||
#else
|
||||
unsigned int irba_l;
|
||||
unsigned int irba_h;
|
||||
#endif
|
||||
unsigned int rsvd1;
|
||||
unsigned int irs;
|
||||
unsigned int rsvd2;
|
||||
unsigned int irsa;
|
||||
unsigned int rsvd3;
|
||||
unsigned int irja;
|
||||
#ifdef NXP_SEC_BE
|
||||
unsigned int orba_h;
|
||||
unsigned int orba_l;
|
||||
#else
|
||||
unsigned int orba_l;
|
||||
unsigned int orba_h;
|
||||
#endif
|
||||
unsigned int rsvd4;
|
||||
unsigned int ors;
|
||||
unsigned int rsvd5;
|
||||
unsigned int orjr;
|
||||
unsigned int rsvd6;
|
||||
unsigned int orsf;
|
||||
unsigned int rsvd7;
|
||||
unsigned int jrsta;
|
||||
unsigned int rsvd8;
|
||||
unsigned int jrint;
|
||||
unsigned int jrcfg0;
|
||||
unsigned int jrcfg1;
|
||||
unsigned int rsvd9;
|
||||
unsigned int irri;
|
||||
unsigned int rsvd10;
|
||||
unsigned int orwi;
|
||||
unsigned int rsvd11;
|
||||
unsigned int jrcr;
|
||||
};
|
||||
|
||||
/* Offsets representing common SEC Registers */
|
||||
#define SEC_REG_MCFGR_OFFSET 0x0004
|
||||
#define SEC_REG_SCFGR_OFFSET 0x000C
|
||||
#define SEC_REG_JR0ICIDR_MS_OFFSET 0x0010
|
||||
#define SEC_REG_JR0ICIDR_LS_OFFSET 0x0014
|
||||
#define SEC_REG_JR1ICIDR_MS_OFFSET 0x0018
|
||||
#define SEC_REG_JR1ICIDR_LS_OFFSET 0x001C
|
||||
#define SEC_REG_JR2ICIDR_MS_OFFSET 0x0020
|
||||
#define SEC_REG_JR2ICIDR_LS_OFFSET 0x0024
|
||||
#define SEC_REG_JR3ICIDR_MS_OFFSET 0x0028
|
||||
#define SEC_REG_JR3ICIDR_LS_OFFSET 0x002C
|
||||
#define SEC_REG_JRSTARTR_OFFSET 0x005C
|
||||
#define SEC_REG_CTPR_MS_OFFSET 0x0FA8
|
||||
|
||||
/* Offsets representing various RNG registers */
|
||||
#define RNG_REG_RTMCTL_OFFSET 0x0600
|
||||
#define RNG_REG_RTSDCTL_OFFSET 0x0610
|
||||
#define RNG_REG_RTFRQMIN_OFFSET 0x0618
|
||||
#define RNG_REG_RTFRQMAX_OFFSET 0x061C
|
||||
#define RNG_REG_RDSTA_OFFSET 0x06C0
|
||||
#define ALG_AAI_SH_SHIFT 4
|
||||
|
||||
/* SEC Registers Bitmasks */
|
||||
#define MCFGR_PS_SHIFT 16
|
||||
#define MCFGR_AWCACHE_SHIFT 8
|
||||
#define MCFGR_AWCACHE_MASK (0xF << MCFGR_AWCACHE_SHIFT)
|
||||
#define MCFGR_ARCACHE_SHIFT 12
|
||||
#define MCFGR_ARCACHE_MASK (0xF << MCFGR_ARCACHE_SHIFT)
|
||||
|
||||
#define SCFGR_RNGSH0 0x00000200
|
||||
#define SCFGR_VIRT_EN 0x00008000
|
||||
|
||||
#define JRICID_MS_LICID 0x80000000
|
||||
#define JRICID_MS_LAMTD 0x00020000
|
||||
#define JRICID_MS_AMTDT 0x00010000
|
||||
#define JRICID_MS_TZ 0x00008000
|
||||
#define JRICID_LS_SDID_MASK 0x00000FFF
|
||||
#define JRICID_LS_NSEQID_MASK 0x0FFF0000
|
||||
#define JRICID_LS_NSEQID_SHIFT 16
|
||||
#define JRICID_LS_SEQID_MASK 0x00000FFF
|
||||
|
||||
#define JRSTARTR_STARTJR0 0x00000001
|
||||
#define JRSTARTR_STARTJR1 0x00000002
|
||||
#define JRSTARTR_STARTJR2 0x00000004
|
||||
#define JRSTARTR_STARTJR3 0x00000008
|
||||
|
||||
#define CTPR_VIRT_EN_POR 0x00000002
|
||||
#define CTPR_VIRT_EN_INC 0x00000001
|
||||
|
||||
/* RNG RDSTA bitmask */
|
||||
#define RNG_STATE0_HANDLE_INSTANTIATED 0x00000001
|
||||
#define RTMCTL_PRGM 0x00010000 /* 1 -> program mode, 0 -> run mode */
|
||||
/* use von Neumann data in both entropy shifter and statistical checker */
|
||||
#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_SC 0
|
||||
/* use raw data in both entropy shifter and statistical checker */
|
||||
#define RTMCTL_SAMP_MODE_RAW_ES_SC 1
|
||||
/* use von Neumann data in entropy shifter, raw data in statistical checker */
|
||||
#define RTMCTL_SAMP_MODE_VON_NEUMANN_ES_RAW_SC 2
|
||||
/* invalid combination */
|
||||
#define RTMCTL_SAMP_MODE_INVALID 3
|
||||
#define RTSDCTL_ENT_DLY_MIN 3200
|
||||
#define RTSDCTL_ENT_DLY_MAX 12800
|
||||
#define RTSDCTL_ENT_DLY_SHIFT 16
|
||||
#define RTSDCTL_ENT_DLY_MASK (U(0xffff) << RTSDCTL_ENT_DLY_SHIFT)
|
||||
#define RTFRQMAX_DISABLE (1 << 20)
|
||||
|
||||
/* Constants for error handling on job ring */
|
||||
#define JR_REG_JRINT_ERR_TYPE_SHIFT 8
|
||||
#define JR_REG_JRINT_ERR_ORWI_SHIFT 16
|
||||
#define JR_REG_JRINIT_JRE_SHIFT 1
|
||||
|
||||
#define JRINT_JRE (1 << JR_REG_JRINIT_JRE_SHIFT)
|
||||
#define JRINT_ERR_WRITE_STATUS (1 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_BAD_INPUT_BASE (3 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_BAD_OUTPUT_BASE (4 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_WRITE_2_IRBA (5 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_WRITE_2_ORBA (6 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_RES_B4_HALT (7 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_REM_TOO_MANY (8 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_ADD_TOO_MANY (9 << JR_REG_JRINT_ERR_TYPE_SHIFT)
|
||||
#define JRINT_ERR_HALT_MASK 0x0C
|
||||
#define JRINT_ERR_HALT_INPROGRESS 0x04
|
||||
#define JRINT_ERR_HALT_COMPLETE 0x08
|
||||
|
||||
#define JR_REG_JRCR_VAL_RESET 0x00000001
|
||||
|
||||
#define JR_REG_JRCFG_LO_ICTT_SHIFT 0x10
|
||||
#define JR_REG_JRCFG_LO_ICDCT_SHIFT 0x08
|
||||
#define JR_REG_JRCFG_LO_ICEN_EN 0x02
|
||||
#define JR_REG_JRCFG_LO_IMSK_EN 0x01
|
||||
|
||||
/* Constants for Descriptor Processing errors */
|
||||
#define SEC_HW_ERR_SSRC_NO_SRC 0x00
|
||||
#define SEC_HW_ERR_SSRC_CCB_ERR 0x02
|
||||
#define SEC_HW_ERR_SSRC_JMP_HALT_U 0x03
|
||||
#define SEC_HW_ERR_SSRC_DECO 0x04
|
||||
#define SEC_HW_ERR_SSRC_JR 0x06
|
||||
#define SEC_HW_ERR_SSRC_JMP_HALT_COND 0x07
|
||||
|
||||
#define SEC_HW_ERR_DECO_HFN_THRESHOLD 0xF1
|
||||
#define SEC_HW_ERR_CCB_ICV_CHECK_FAIL 0x0A
|
||||
|
||||
/* Macros for extracting error codes for the job ring */
|
||||
|
||||
#define JR_REG_JRINT_ERR_TYPE_EXTRACT(value) \
|
||||
((value) & 0x00000F00)
|
||||
|
||||
#define JR_REG_JRINT_ERR_ORWI_EXTRACT(value) \
|
||||
(((value) & 0x3FFF0000) >> \
|
||||
JR_REG_JRINT_ERR_ORWI_SHIFT)
|
||||
|
||||
#define JR_REG_JRINT_JRE_EXTRACT(value) \
|
||||
((value) & JRINT_JRE)
|
||||
|
||||
/* Macros for manipulating JR registers */
|
||||
typedef union {
|
||||
uint64_t m_whole;
|
||||
struct {
|
||||
#ifdef NXP_SEC_BE
|
||||
uint32_t high;
|
||||
uint32_t low;
|
||||
#else
|
||||
uint32_t low;
|
||||
uint32_t high;
|
||||
#endif
|
||||
} m_halves;
|
||||
} ptr_addr_t;
|
||||
|
||||
#if defined(CONFIG_PHYS_64BIT)
|
||||
#define sec_read_addr(a) sec_in64((a))
|
||||
#define sec_write_addr(a, v) sec_out64((a), (v))
|
||||
#else
|
||||
#define sec_read_addr(a) sec_in32((a))
|
||||
#define sec_write_addr(a, v) sec_out32((a), (v))
|
||||
#endif
|
||||
|
||||
#define JR_REG(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET)
|
||||
#define JR_REG_LO(name, jr) (CHAN_BASE(jr) + JR_REG_##name##_OFFSET_LO)
|
||||
|
||||
#define GET_JR_REG(name, jr) (sec_in32(JR_REG(name, (jr))))
|
||||
#define GET_JR_REG_LO(name, jr) (sec_in32(JR_REG_LO(name, (jr))))
|
||||
|
||||
#define SET_JR_REG(name, jr, val) \
|
||||
(sec_out32(JR_REG(name, (jr)), (val)))
|
||||
|
||||
#define SET_JR_REG_LO(name, jr, val) \
|
||||
(sec_out32(JR_REG_LO(name, (jr)), (val)))
|
||||
|
||||
/* STRUCTURES AND OTHER TYPEDEFS */
|
||||
/* Lists the possible states for a job ring. */
|
||||
typedef enum sec_job_ring_state_e {
|
||||
SEC_JOB_RING_STATE_STARTED, /* Job ring is initialized */
|
||||
SEC_JOB_RING_STATE_RESET, /* Job ring reset is in progres */
|
||||
} sec_job_ring_state_t;
|
||||
|
||||
struct sec_job_ring_t {
|
||||
/*
|
||||
* Consumer index for job ring (jobs array).
|
||||
* @note: cidx and pidx are accessed from
|
||||
* different threads.
|
||||
* Place the cidx and pidx inside the structure
|
||||
* so that they lay on different cachelines, to
|
||||
* avoid false sharing between threads when the
|
||||
* threads run on different cores!
|
||||
*/
|
||||
uint32_t cidx;
|
||||
|
||||
/* Producer index for job ring (jobs array) */
|
||||
uint32_t pidx;
|
||||
|
||||
/* Ring of input descriptors. Size of array is power of 2 to allow
|
||||
* fast update of producer/consumer indexes with bitwise operations.
|
||||
*/
|
||||
phys_addr_t *input_ring;
|
||||
|
||||
/* Ring of output descriptors. */
|
||||
struct sec_outring_entry *output_ring;
|
||||
|
||||
/* The file descriptor used for polling for interrupts notifications */
|
||||
uint32_t irq_fd;
|
||||
|
||||
/* Model used by SEC Driver to receive notifications from SEC.
|
||||
* Can be either of the three:
|
||||
* #SEC_NOTIFICATION_TYPE_IRQ or
|
||||
* #SEC_NOTIFICATION_TYPE_POLL
|
||||
*/
|
||||
uint32_t jr_mode;
|
||||
/* Base address for SEC's register memory for this job ring. */
|
||||
void *register_base_addr;
|
||||
/* notifies if coelescing is enabled for the job ring */
|
||||
uint8_t coalescing_en;
|
||||
/* The state of this job ring */
|
||||
sec_job_ring_state_t jr_state;
|
||||
};
|
||||
|
||||
/* Forward structure declaration */
|
||||
typedef struct sec_job_ring_t sec_job_ring_t;
|
||||
|
||||
struct sec_outring_entry {
|
||||
phys_addr_t desc; /* Pointer to completed descriptor */
|
||||
uint32_t status; /* Status for completed descriptor */
|
||||
} __packed;
|
||||
|
||||
/* Lists the states possible for the SEC user space driver. */
|
||||
typedef enum sec_driver_state_e {
|
||||
SEC_DRIVER_STATE_IDLE, /*< Driver not initialized */
|
||||
SEC_DRIVER_STATE_STARTED, /*< Driver initialized and */
|
||||
SEC_DRIVER_STATE_RELEASE, /*< Driver release is in progress */
|
||||
} sec_driver_state_t;
|
||||
|
||||
/* Union describing the possible error codes that */
|
||||
/* can be set in the descriptor status word */
|
||||
|
||||
union hw_error_code {
|
||||
uint32_t error;
|
||||
union {
|
||||
struct {
|
||||
uint32_t ssrc:4;
|
||||
uint32_t ssed_val:28;
|
||||
} __packed value;
|
||||
struct {
|
||||
uint32_t ssrc:4;
|
||||
uint32_t res:28;
|
||||
} __packed no_status_src;
|
||||
struct {
|
||||
uint32_t ssrc:4;
|
||||
uint32_t jmp:1;
|
||||
uint32_t res:11;
|
||||
uint32_t desc_idx:8;
|
||||
uint32_t cha_id:4;
|
||||
uint32_t err_id:4;
|
||||
} __packed ccb_status_src;
|
||||
struct {
|
||||
uint32_t ssrc:4;
|
||||
uint32_t jmp:1;
|
||||
uint32_t res:11;
|
||||
uint32_t desc_idx:8;
|
||||
uint32_t offset:8;
|
||||
} __packed jmp_halt_user_src;
|
||||
struct {
|
||||
uint32_t ssrc:4;
|
||||
uint32_t jmp:1;
|
||||
uint32_t res:11;
|
||||
uint32_t desc_idx:8;
|
||||
uint32_t desc_err:8;
|
||||
} __packed deco_src;
|
||||
struct {
|
||||
uint32_t ssrc:4;
|
||||
uint32_t res:17;
|
||||
uint32_t naddr:3;
|
||||
uint32_t desc_err:8;
|
||||
} __packed jr_src;
|
||||
struct {
|
||||
uint32_t ssrc:4;
|
||||
uint32_t jmp:1;
|
||||
uint32_t res:11;
|
||||
uint32_t desc_idx:8;
|
||||
uint32_t cond:8;
|
||||
} __packed jmp_halt_cond_src;
|
||||
} __packed error_desc;
|
||||
} __packed;
|
||||
|
||||
/* FUNCTION PROTOTYPES */
|
||||
|
||||
/*
|
||||
* @brief Initialize a job ring/channel in SEC device.
|
||||
* Write configuration register/s to properly initialize a job ring.
|
||||
*
|
||||
* @param [in] job_ring The job ring
|
||||
*
|
||||
* @retval 0 for success
|
||||
* @retval other for error
|
||||
*/
|
||||
int hw_reset_job_ring(sec_job_ring_t *job_ring);
|
||||
|
||||
/*
|
||||
* @brief Reset a job ring/channel in SEC device.
|
||||
* Write configuration register/s to reset a job ring.
|
||||
*
|
||||
* @param [in] job_ring The job ring
|
||||
*
|
||||
* @retval 0 for success
|
||||
* @retval -1 in case job ring reset failed
|
||||
*/
|
||||
int hw_shutdown_job_ring(sec_job_ring_t *job_ring);
|
||||
|
||||
/*
|
||||
* @brief Handle a job ring/channel error in SEC device.
|
||||
* Identify the error type and clear error bits if required.
|
||||
*
|
||||
* @param [in] job_ring The job ring
|
||||
* @param [in] sec_error_code error code as first read from SEC engine
|
||||
*/
|
||||
|
||||
void hw_handle_job_ring_error(sec_job_ring_t *job_ring,
|
||||
uint32_t sec_error_code);
|
||||
/*
|
||||
* @brief Handle a job ring error in the device.
|
||||
* Identify the error type and printout a explanatory
|
||||
* messages.
|
||||
*
|
||||
* @param [in] job_ring The job ring
|
||||
*
|
||||
*/
|
||||
|
||||
int hw_job_ring_error(sec_job_ring_t *job_ring);
|
||||
|
||||
/* @brief Set interrupt coalescing parameters on the Job Ring.
|
||||
* @param [in] job_ring The job ring
|
||||
* @param [in] irq_coalesing_timer
|
||||
* Interrupt coalescing timer threshold.
|
||||
* This value determines the maximum
|
||||
* amount of time after processing a descriptor
|
||||
* before raising an interrupt.
|
||||
* @param [in] irq_coalescing_count
|
||||
* Interrupt coalescing count threshold.
|
||||
* This value determines how many descriptors
|
||||
* are completed before raising an interrupt.
|
||||
*/
|
||||
|
||||
int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring,
|
||||
uint16_t irq_coalescing_timer,
|
||||
uint8_t irq_coalescing_count);
|
||||
|
||||
/* @brief Enable interrupt coalescing on a job ring
|
||||
* @param [in] job_ring The job ring
|
||||
*/
|
||||
|
||||
int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring);
|
||||
|
||||
/*
|
||||
* @brief Disable interrupt coalescing on a job ring
|
||||
* @param [in] job_ring The job ring
|
||||
*/
|
||||
|
||||
int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring);
|
||||
|
||||
/*
|
||||
* @brief Poll the HW for already processed jobs in the JR
|
||||
* and notify the available jobs to UA.
|
||||
*
|
||||
* @param [in] job_ring The job ring to poll.
|
||||
* @param [in] limit The maximum number of jobs to notify.
|
||||
* If set to negative value, all available
|
||||
* jobs are notified.
|
||||
*
|
||||
* @retval >=0 for No of jobs notified to UA.
|
||||
* @retval -1 for error
|
||||
*/
|
||||
|
||||
int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit);
|
||||
|
||||
/* @brief Poll the HW for already processed jobs in the JR
|
||||
* and silently discard the available jobs or notify them to UA
|
||||
* with indicated error code.
|
||||
|
||||
* @param [in,out] job_ring The job ring to poll.
|
||||
* @param [in] do_notify Can be #TRUE or #FALSE.
|
||||
* Indicates if descriptors to be discarded
|
||||
* or notified to UA with given error_code.
|
||||
* @param [in] error_code The detailed SEC error code.
|
||||
* @param [out] notified_descs Number of notified descriptors.
|
||||
* Can be NULL if do_notify is #FALSE
|
||||
*/
|
||||
void hw_flush_job_ring(struct sec_job_ring_t *job_ring,
|
||||
uint32_t do_notify,
|
||||
uint32_t error_code, uint32_t *notified_descs);
|
||||
|
||||
/*
|
||||
* @brief Flush job rings of any processed descs.
|
||||
* The processed descs are silently dropped,
|
||||
* WITHOUT being notified to UA.
|
||||
*/
|
||||
void flush_job_rings(void);
|
||||
|
||||
/*
|
||||
* @brief Handle desc that generated error in SEC engine.
|
||||
* Identify the exact type of error and handle the error.
|
||||
* Depending on the error type, the job ring could be reset.
|
||||
* All descs that are submitted for processing on this job ring
|
||||
* are notified to User Application with error status and detailed error code.
|
||||
|
||||
* @param [in] job_ring Job ring
|
||||
* @param [in] sec_error_code Error code read from job ring's Channel
|
||||
* Status Register
|
||||
* @param [out] notified_descs Number of notified descs. Can be NULL if
|
||||
* do_notify is #FALSE
|
||||
* @param [out] do_driver_shutdown If set to #TRUE, then UA is returned code
|
||||
* #SEC_PROCESSING_ERROR
|
||||
* which is indication that UA must call
|
||||
* sec_release() after this.
|
||||
*/
|
||||
void sec_handle_desc_error(struct sec_job_ring_t *job_ring,
|
||||
uint32_t sec_error_code,
|
||||
uint32_t *notified_descs,
|
||||
uint32_t *do_driver_shutdown);
|
||||
|
||||
/*
|
||||
* @brief Release the software and hardware resources tied to a job ring.
|
||||
* @param [in] job_ring The job ring
|
||||
* @retval 0 for success
|
||||
* @retval -1 for error
|
||||
*/
|
||||
int shutdown_job_ring(struct sec_job_ring_t *job_ring);
|
||||
|
||||
/*
|
||||
* @brief Enable irqs on associated job ring.
|
||||
* @param [in] job_ring The job ring
|
||||
* @retval 0 for success
|
||||
* @retval -1 for error
|
||||
*/
|
||||
int jr_enable_irqs(struct sec_job_ring_t *job_ring);
|
||||
|
||||
/*
|
||||
* @brief Disable irqs on associated job ring.
|
||||
* @param [in] job_ring The job ring
|
||||
* @retval 0 for success
|
||||
* @retval -1 for error
|
||||
*/
|
||||
int jr_disable_irqs(struct sec_job_ring_t *job_ring);
|
||||
|
||||
/*
|
||||
* IRJA - Input Ring Jobs Added Register shows
|
||||
* how many new jobs were added to the Input Ring.
|
||||
*/
|
||||
static inline void hw_enqueue_desc_on_job_ring(struct jobring_regs *regs,
|
||||
int num)
|
||||
{
|
||||
sec_out32(®s->irja, num);
|
||||
}
|
||||
|
||||
#endif /* _SEC_HW_SPECIFIC_H_ */
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _JR_DRIVER_H_
|
||||
#define _JR_DRIVER_H_
|
||||
|
||||
#include "jr_driver_config.h"
|
||||
|
||||
/* The maximum size of a SEC descriptor, in WORDs (32 bits). */
|
||||
#define MAX_DESC_SIZE_WORDS 64
|
||||
|
||||
#define CAAM_TIMEOUT 200000 /* ms */
|
||||
|
||||
/* Return codes for JR user space driver APIs */
|
||||
typedef enum sec_return_code_e {
|
||||
SEC_SUCCESS = 0,
|
||||
SEC_INVALID_INPUT_PARAM,
|
||||
SEC_OUT_OF_MEMORY,
|
||||
SEC_DESCRIPTOR_IN_FLIGHT,
|
||||
SEC_LAST_DESCRIPTOR_IN_FLIGHT,
|
||||
SEC_PROCESSING_ERROR,
|
||||
SEC_DESC_PROCESSING_ERROR,
|
||||
SEC_JR_IS_FULL,
|
||||
SEC_DRIVER_RELEASE_IN_PROGRESS,
|
||||
SEC_DRIVER_ALREADY_INITIALIZED,
|
||||
SEC_DRIVER_NOT_INITIALIZED,
|
||||
SEC_JOB_RING_RESET_IN_PROGRESS,
|
||||
SEC_RESET_ENGINE_FAILED,
|
||||
SEC_ENABLE_IRQS_FAILED,
|
||||
SEC_DISABLE_IRQS_FAILED,
|
||||
SEC_RETURN_CODE_MAX_VALUE,
|
||||
} sec_return_code_t;
|
||||
|
||||
/* STRUCTURES AND OTHER TYPEDEFS */
|
||||
|
||||
/*
|
||||
* @brief Function called by JR User Space driver to notify every processed
|
||||
* descriptor.
|
||||
*
|
||||
* Callback provided by the User Application.
|
||||
* Callback is invoked by JR User Space driver for each descriptor processed by
|
||||
* SEC
|
||||
* @param [in] status Status word indicating processing result for
|
||||
* this descriptor.
|
||||
* @param [in] arg Opaque data passed by User Application
|
||||
* It is opaque from JR driver's point of view.
|
||||
* @param [in] job_ring The job ring handle on which the processed
|
||||
* descriptor word was enqueued
|
||||
*/
|
||||
typedef void (*user_callback) (uint32_t *desc, uint32_t status,
|
||||
void *arg, void *job_ring);
|
||||
|
||||
/*
|
||||
* Structure encompassing a job descriptor which is to be processed
|
||||
* by SEC. User should also initialise this structure with the callback
|
||||
* function pointer which will be called by driver after recieving proccessed
|
||||
* descriptor from SEC. User data is also passed in this data structure which
|
||||
* will be sent as an argument to the user callback function.
|
||||
*/
|
||||
struct job_descriptor {
|
||||
uint32_t desc[MAX_DESC_SIZE_WORDS];
|
||||
void *arg;
|
||||
user_callback callback;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Initialize the JR User Space driver.
|
||||
* This function will handle initialization of sec library
|
||||
* along with registering platform specific callbacks,
|
||||
* as well as local data initialization.
|
||||
* Call once during application startup.
|
||||
* @note Global SEC initialization is done in SEC kernel driver.
|
||||
* @note The hardware IDs of the initialized Job Rings are opaque to the UA.
|
||||
* The exact Job Rings used by this library are decided between SEC user
|
||||
* space driver and SEC kernel driver. A static partitioning of Job Rings is
|
||||
* assumed, configured in DTS(device tree specification) file.
|
||||
* @param [in] platform_cb Registering the platform specific
|
||||
* callbacks with driver
|
||||
* @retval ::0 for successful execution
|
||||
* @retval ::-1 failure
|
||||
*/
|
||||
int sec_jr_lib_init(void);
|
||||
|
||||
/*
|
||||
* @brief Initialize the software and hardware resources tied to a job ring.
|
||||
* @param [in] jr_mode; Model to be used by SEC Driver to receive
|
||||
* notifications from SEC. Can be either
|
||||
* SEC_NOTIFICATION_TYPE_IRQ or
|
||||
* SEC_NOTIFICATION_TYPE_POLL
|
||||
* @param [in] irq_coalescing_timer This value determines the maximum
|
||||
* amount of time after processing a
|
||||
* descriptor before raising an interrupt.
|
||||
* @param [in] irq_coalescing_count This value determines how many
|
||||
* descriptors are completed before
|
||||
* raising an interrupt.
|
||||
* @param [in] reg_base_addr The job ring base address register
|
||||
* @param [in] irq_id The job ring interrupt identification number.
|
||||
* @retval job_ring_handle for successful job ring configuration
|
||||
* @retval NULL on error
|
||||
*/
|
||||
void *init_job_ring(uint8_t jr_mode,
|
||||
uint16_t irq_coalescing_timer,
|
||||
uint8_t irq_coalescing_count,
|
||||
void *reg_base_addr, uint32_t irq_id);
|
||||
|
||||
/*
|
||||
* @brief Release the resources used by the JR User Space driver.
|
||||
* Reset and release SEC's job rings indicated by the User Application at
|
||||
* init_job_ring() and free any memory allocated internally.
|
||||
* Call once during application tear down.
|
||||
* @note In case there are any descriptors in-flight (descriptors received by
|
||||
* JR driver for processing and for which no response was yet provided to UA),
|
||||
* the descriptors are discarded without any notifications to User Application.
|
||||
* @retval ::0 is returned for a successful execution
|
||||
* @retval ::-1 is returned if JR driver release is in progress
|
||||
*/
|
||||
int sec_release(void);
|
||||
|
||||
/*
|
||||
* @brief Submit a descriptor for SEC processing.
|
||||
* This function creates a "job" which is meant to instruct SEC HW
|
||||
* to perform the processing on the input buffer. The "job" is enqueued
|
||||
* in the Job Ring associated. The function will return after the "job"
|
||||
* enqueue is finished. The function will not wait for SEC to
|
||||
* start or/and finish the "job" processing.
|
||||
* After the processing is finished the SEC HW writes the processing result
|
||||
* to the provided output buffer.
|
||||
* The Caller must poll JR driver using jr_dequeue()
|
||||
* to receive notifications of the processing completion
|
||||
* status. The notifications are received by caller by means of callback
|
||||
* (see ::user_callback).
|
||||
* @param [in] job_ring_handle The handle of the job ring on which
|
||||
* descriptor is to be enqueued
|
||||
* @param [in] job_descriptor The job descriptor structure of type
|
||||
* struct job_descriptor. This structure
|
||||
* should be filled with job descriptor along
|
||||
* with callback function to be called after
|
||||
* processing of descriptor and some
|
||||
* opaque data passed to be passed to the
|
||||
* callback function
|
||||
*
|
||||
* @retval ::0 is returned for successful execution
|
||||
* @retval ::-1 is returned if there is some enqueue failure
|
||||
*/
|
||||
int enq_jr_desc(void *job_ring_handle, struct job_descriptor *jobdescr);
|
||||
|
||||
/*
|
||||
* @brief Polls for available descriptors processed by SEC on a specific
|
||||
* Job Ring
|
||||
* This function polls the SEC Job Rings and delivers processed descriptors
|
||||
* Each processed descriptor has a user_callback registered.
|
||||
* This user_callback is invoked for each processed descriptor.
|
||||
* The polling is stopped when "limit" descriptors are notified or when
|
||||
* there are no more descriptors to notify.
|
||||
* @note The dequeue_jr() API cannot be called from within a user_callback
|
||||
* function
|
||||
* @param [in] job_ring_handle The Job Ring handle.
|
||||
* @param [in] limit This value represents the maximum number
|
||||
* of processed descriptors that can be
|
||||
* notified API call on this Job Ring.
|
||||
* Note that fewer descriptors may be notified
|
||||
* if enough processed descriptors are not
|
||||
* available.
|
||||
* If limit has a negative value, then all
|
||||
* ready descriptors will be notified.
|
||||
*
|
||||
* @retval :: >=0 is returned where retval is the total
|
||||
* Number of descriptors notified
|
||||
* during this function call.
|
||||
* @retval :: -1 is returned in case of some error
|
||||
*/
|
||||
int dequeue_jr(void *job_ring_handle, int32_t limit);
|
||||
|
||||
#endif /* _JR_DRIVER_H_ */
|
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Copyright 2018-2020 NXP
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
#
|
||||
|
||||
SEC_DRIVERS_PATH := drivers/nxp/crypto/caam
|
||||
|
||||
ifeq (${TRUSTED_BOARD_BOOT},1)
|
||||
AUTH_SOURCES += $(wildcard $(SEC_DRIVERS_PATH)/src/auth/*.c)
|
||||
endif
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include <drivers/auth/crypto_mod.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "jobdesc.h"
|
||||
#include "sec_hw_specific.h"
|
||||
|
||||
/* Since no Allocator is available . Taking a global static ctx.
|
||||
* This would mean that only one active ctx can be there at a time.
|
||||
*/
|
||||
|
||||
static struct hash_ctx glbl_ctx;
|
||||
|
||||
static void hash_done(uint32_t *desc, uint32_t status, void *arg,
|
||||
void *job_ring)
|
||||
{
|
||||
INFO("Hash Desc SUCCESS with status %x\n", status);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : hash_init
|
||||
* Arguments : ctx - SHA context
|
||||
* Return : init,
|
||||
* Description : This function initializes the context for SHA calculation
|
||||
***************************************************************************/
|
||||
int hash_init(enum hash_algo algo, void **ctx)
|
||||
{
|
||||
if (glbl_ctx.active == false) {
|
||||
memset(&glbl_ctx, 0, sizeof(struct hash_ctx));
|
||||
glbl_ctx.active = true;
|
||||
glbl_ctx.algo = algo;
|
||||
*ctx = &glbl_ctx;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : hash_update
|
||||
* Arguments : ctx - SHA context
|
||||
* buffer - Data
|
||||
* length - Length
|
||||
* Return : -1 on error
|
||||
* 0 on SUCCESS
|
||||
* Description : This function creates SG entry of the data provided
|
||||
***************************************************************************/
|
||||
int hash_update(enum hash_algo algo, void *context, void *data_ptr,
|
||||
unsigned int data_len)
|
||||
{
|
||||
struct hash_ctx *ctx = context;
|
||||
/* MAX_SG would be MAX_SG_ENTRIES + key + hdr + sg table */
|
||||
if (ctx->sg_num >= MAX_SG) {
|
||||
ERROR("Reached limit for calling %s\n", __func__);
|
||||
ctx->active = false;
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
|
||||
if (ctx->algo != algo) {
|
||||
ERROR("ctx for algo not correct\n");
|
||||
ctx->active = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
flush_dcache_range((uintptr_t)data_ptr, data_len);
|
||||
dmbsy();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PHYS_64BIT
|
||||
sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi,
|
||||
(uint32_t) ((uintptr_t) data_ptr >> 32));
|
||||
#else
|
||||
sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_hi, 0x0);
|
||||
#endif
|
||||
sec_out32(&ctx->sg_tbl[ctx->sg_num].addr_lo, (uintptr_t) data_ptr);
|
||||
|
||||
sec_out32(&ctx->sg_tbl[ctx->sg_num].len_flag,
|
||||
(data_len & SG_ENTRY_LENGTH_MASK));
|
||||
|
||||
ctx->sg_num++;
|
||||
|
||||
ctx->len += data_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : hash_final
|
||||
* Arguments : ctx - SHA context
|
||||
* Return : SUCCESS or FAILURE
|
||||
* Description : This function sets the final bit and enqueues the decriptor
|
||||
***************************************************************************/
|
||||
int hash_final(enum hash_algo algo, void *context, void *hash_ptr,
|
||||
unsigned int hash_len)
|
||||
{
|
||||
int ret = 0;
|
||||
struct hash_ctx *ctx = context;
|
||||
uint32_t final = 0U;
|
||||
|
||||
struct job_descriptor jobdesc __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
|
||||
jobdesc.arg = NULL;
|
||||
jobdesc.callback = hash_done;
|
||||
|
||||
if (ctx->algo != algo) {
|
||||
ERROR("ctx for algo not correct\n");
|
||||
ctx->active = false;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
final = sec_in32(&ctx->sg_tbl[ctx->sg_num - 1].len_flag) |
|
||||
SG_ENTRY_FINAL_BIT;
|
||||
sec_out32(&ctx->sg_tbl[ctx->sg_num - 1].len_flag, final);
|
||||
|
||||
dsb();
|
||||
|
||||
/* create the hw_rng descriptor */
|
||||
cnstr_hash_jobdesc(jobdesc.desc, (uint8_t *) ctx->sg_tbl,
|
||||
ctx->len, hash_ptr);
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
flush_dcache_range((uintptr_t)ctx->sg_tbl,
|
||||
(sizeof(struct sg_entry) * MAX_SG));
|
||||
inv_dcache_range((uintptr_t)hash_ptr, hash_len);
|
||||
|
||||
dmbsy();
|
||||
#endif
|
||||
|
||||
/* Finally, generate the requested random data bytes */
|
||||
ret = run_descriptor_jr(&jobdesc);
|
||||
if (ret != 0) {
|
||||
ERROR("Error in running descriptor\n");
|
||||
ret = -1;
|
||||
}
|
||||
ctx->active = false;
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include <drivers/auth/crypto_mod.h>
|
||||
|
||||
#include "hash.h"
|
||||
#include "rsa.h"
|
||||
|
||||
#define LIB_NAME "NXP crypto"
|
||||
|
||||
/*
|
||||
* Initialize the library and export the descriptor
|
||||
*/
|
||||
static void init(void)
|
||||
{
|
||||
/* Initialize NXP crypto library`:*/
|
||||
NOTICE("Initializing & configuring SEC block.\n");
|
||||
|
||||
if (config_sec_block() < 0) {
|
||||
ERROR("Init & config failure for caam.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify a signature.
|
||||
*
|
||||
* For IMG_PLAT - data points to a PKCS#1.5 encoded HASH
|
||||
* sig_alg will be RSA or ECC
|
||||
* Parameters are passed using the DER encoding format following the ASN.1
|
||||
* structures detailed above.
|
||||
*/
|
||||
static int verify_signature(void *data_ptr, unsigned int data_len,
|
||||
void *sig_ptr, unsigned int sig_len,
|
||||
void *sign_alg, unsigned int sig_alg_len,
|
||||
void *pk_ptr, unsigned int pk_len)
|
||||
{
|
||||
int ret = CRYPTO_SUCCESS;
|
||||
|
||||
enum sig_alg alg = *(enum sig_alg *)sign_alg;
|
||||
|
||||
switch (alg) {
|
||||
case RSA:
|
||||
NOTICE("Verifying RSA\n");
|
||||
ret = rsa_verify_signature(data_ptr, data_len, sig_ptr, sig_len,
|
||||
pk_ptr, pk_len);
|
||||
break;
|
||||
case ECC:
|
||||
default:
|
||||
ret = CRYPTO_ERR_SIGNATURE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
ERROR("RSA verification Failed\n");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Match a hash
|
||||
*
|
||||
* Digest info is passed as a table of SHA-26 hashes and digest_info_len
|
||||
* is number of entries in the table
|
||||
* This implementation is very specific to the CSF header parser ROTPK
|
||||
* comparison.
|
||||
*/
|
||||
static int verify_hash(void *data_ptr, unsigned int data_len,
|
||||
void *digest_info_ptr, unsigned int digest_info_len)
|
||||
{
|
||||
void *ctx = NULL;
|
||||
int i = 0, ret = 0;
|
||||
enum hash_algo algo = SHA256;
|
||||
uint8_t hash[SHA256_BYTES] __aligned(CACHE_WRITEBACK_GRANULE) = {0};
|
||||
uint32_t digest_size = SHA256_BYTES;
|
||||
uint8_t *hash_tbl = digest_info_ptr;
|
||||
|
||||
NOTICE("Verifying hash\n");
|
||||
ret = hash_init(algo, &ctx);
|
||||
if (ret != 0) {
|
||||
return CRYPTO_ERR_HASH;
|
||||
}
|
||||
|
||||
/* Update hash with that of SRK table */
|
||||
ret = hash_update(algo, ctx, data_ptr, data_len);
|
||||
if (ret != 0) {
|
||||
return CRYPTO_ERR_HASH;
|
||||
}
|
||||
|
||||
/* Copy hash at destination buffer */
|
||||
ret = hash_final(algo, ctx, hash, digest_size);
|
||||
if (ret != 0) {
|
||||
return CRYPTO_ERR_HASH;
|
||||
}
|
||||
|
||||
VERBOSE("%s Calculated hash\n", __func__);
|
||||
for (i = 0; i < SHA256_BYTES/4; i++) {
|
||||
VERBOSE("%x\n", *((uint32_t *)hash + i));
|
||||
}
|
||||
|
||||
for (i = 0; i < digest_info_len; i++) {
|
||||
if (memcmp(hash, (hash_tbl + (i * digest_size)),
|
||||
digest_size) == 0) {
|
||||
return CRYPTO_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return CRYPTO_ERR_HASH;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register crypto library descriptor
|
||||
*/
|
||||
REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash, NULL);
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include <drivers/auth/crypto_mod.h>
|
||||
|
||||
#include "jobdesc.h"
|
||||
#include "rsa.h"
|
||||
#include "sec_hw_specific.h"
|
||||
|
||||
/* This array contains DER value for SHA-256 */
|
||||
static const uint8_t hash_identifier[] = {
|
||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
|
||||
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
|
||||
0x04, 0x20
|
||||
};
|
||||
|
||||
static void rsa_done(uint32_t *desc, uint32_t status, void *arg,
|
||||
void *job_ring)
|
||||
{
|
||||
INFO("RSA Desc SUCCESS with status %x\n", status);
|
||||
}
|
||||
|
||||
static int rsa_public_verif_sec(uint8_t *sign, uint8_t *to,
|
||||
uint8_t *rsa_pub_key, uint32_t klen)
|
||||
{
|
||||
int ret = 0;
|
||||
struct rsa_context ctx __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
struct job_descriptor jobdesc __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
|
||||
jobdesc.arg = NULL;
|
||||
jobdesc.callback = rsa_done;
|
||||
|
||||
memset(&ctx, 0, sizeof(struct rsa_context));
|
||||
|
||||
ctx.pkin.a = sign;
|
||||
ctx.pkin.a_siz = klen;
|
||||
ctx.pkin.n = rsa_pub_key;
|
||||
ctx.pkin.n_siz = klen;
|
||||
ctx.pkin.e = rsa_pub_key + klen;
|
||||
ctx.pkin.e_siz = klen;
|
||||
|
||||
cnstr_jobdesc_pkha_rsaexp(jobdesc.desc, &ctx.pkin, to, klen);
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
flush_dcache_range((uintptr_t)sign, klen);
|
||||
flush_dcache_range((uintptr_t)rsa_pub_key, 2 * klen);
|
||||
flush_dcache_range((uintptr_t)&ctx.pkin, sizeof(ctx.pkin));
|
||||
inv_dcache_range((uintptr_t)to, klen);
|
||||
|
||||
dmbsy();
|
||||
dsbsy();
|
||||
isb();
|
||||
#endif
|
||||
|
||||
/* Finally, generate the requested random data bytes */
|
||||
ret = run_descriptor_jr(&jobdesc);
|
||||
if (ret != 0) {
|
||||
ERROR("Error in running descriptor\n");
|
||||
ret = -1;
|
||||
}
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
inv_dcache_range((uintptr_t)to, klen);
|
||||
dmbsy();
|
||||
dsbsy();
|
||||
isb();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct encoded hash EM' wrt PKCSv1.5. This function calculates the
|
||||
* pointers for padding, DER value and hash. And finally, constructs EM'
|
||||
* which includes hash of complete CSF header and ESBC image. If SG flag
|
||||
* is on, hash of SG table and entries is also included.
|
||||
*/
|
||||
static int construct_img_encoded_hash_second(uint8_t *hash, uint8_t hash_len,
|
||||
uint8_t *encoded_hash_second,
|
||||
unsigned int key_len)
|
||||
{
|
||||
/*
|
||||
* RSA PKCSv1.5 encoding format for encoded message is below
|
||||
* EM = 0x0 || 0x1 || PS || 0x0 || DER || Hash
|
||||
* PS is Padding String
|
||||
* DER is DER value for SHA-256
|
||||
* Hash is SHA-256 hash
|
||||
* *********************************************************
|
||||
* representative points to first byte of EM initially and is
|
||||
* filled with 0x0
|
||||
* representative is incremented by 1 and second byte is filled
|
||||
* with 0x1
|
||||
* padding points to third byte of EM
|
||||
* digest points to full length of EM - 32 bytes
|
||||
* hash_id (DER value) points to 19 bytes before pDigest
|
||||
* separator is one byte which separates padding and DER
|
||||
*/
|
||||
|
||||
unsigned int len;
|
||||
uint8_t *representative;
|
||||
uint8_t *padding, *digest;
|
||||
uint8_t *hash_id, *separator;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (hash_len != SHA256_BYTES) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Key length = Modulus length */
|
||||
len = (key_len / 2U) - 1U;
|
||||
representative = encoded_hash_second;
|
||||
representative[0] = 0U;
|
||||
representative[1] = 1U; /* block type 1 */
|
||||
|
||||
padding = &representative[2];
|
||||
digest = &representative[1] + len - 32;
|
||||
hash_id = digest - sizeof(hash_identifier);
|
||||
separator = hash_id - 1;
|
||||
|
||||
/* fill padding area pointed by padding with 0xff */
|
||||
memset(padding, 0xff, separator - padding);
|
||||
|
||||
/* fill byte pointed by separator */
|
||||
*separator = 0U;
|
||||
|
||||
/* fill SHA-256 DER value pointed by HashId */
|
||||
memcpy(hash_id, hash_identifier, sizeof(hash_identifier));
|
||||
|
||||
/* fill hash pointed by Digest */
|
||||
for (i = 0; i < SHA256_BYTES; i++) {
|
||||
digest[i] = hash[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rsa_verify_signature(void *hash_ptr, unsigned int hash_len,
|
||||
void *sig_ptr, unsigned int sig_len,
|
||||
void *pk_ptr, unsigned int pk_len)
|
||||
{
|
||||
uint8_t img_encoded_hash_second[RSA_4K_KEY_SZ_BYTES];
|
||||
uint8_t encoded_hash[RSA_4K_KEY_SZ_BYTES] __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
int ret = 0;
|
||||
|
||||
ret = construct_img_encoded_hash_second(hash_ptr, hash_len,
|
||||
img_encoded_hash_second,
|
||||
pk_len);
|
||||
if (ret != 0) {
|
||||
ERROR("Encoded Hash Failure\n");
|
||||
return CRYPTO_ERR_SIGNATURE;
|
||||
}
|
||||
|
||||
ret = rsa_public_verif_sec(sig_ptr, encoded_hash, pk_ptr, pk_len / 2);
|
||||
if (ret != 0) {
|
||||
ERROR("RSA signature Failure\n");
|
||||
return CRYPTO_ERR_SIGNATURE;
|
||||
}
|
||||
|
||||
ret = memcmp(img_encoded_hash_second, encoded_hash, sig_len);
|
||||
if (ret != 0) {
|
||||
ERROR("Comparison Failure\n");
|
||||
return CRYPTO_ERR_SIGNATURE;
|
||||
}
|
||||
|
||||
return CRYPTO_SUCCESS;
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include "jobdesc.h"
|
||||
#include "sec_hw_specific.h"
|
||||
|
||||
static uintptr_t g_nxp_caam_addr;
|
||||
static void *job_ring;
|
||||
|
||||
uintptr_t get_caam_addr(void)
|
||||
{
|
||||
if (g_nxp_caam_addr == 0) {
|
||||
ERROR("Sec Init is not done.\n");
|
||||
panic();
|
||||
}
|
||||
return g_nxp_caam_addr;
|
||||
}
|
||||
|
||||
/* This function sets the TZ bit for the Job ring number passed as @num */
|
||||
static void config_tz(int num)
|
||||
{
|
||||
uint32_t jricid;
|
||||
|
||||
/* Setting TZ bit of job ring */
|
||||
switch (num) {
|
||||
case 0:
|
||||
jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET);
|
||||
sec_out32(g_nxp_caam_addr + SEC_REG_JR0ICIDR_MS_OFFSET,
|
||||
jricid | JRICID_MS_TZ);
|
||||
break;
|
||||
case 1:
|
||||
jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET);
|
||||
sec_out32(g_nxp_caam_addr + SEC_REG_JR1ICIDR_MS_OFFSET,
|
||||
jricid | JRICID_MS_TZ);
|
||||
break;
|
||||
case 2:
|
||||
jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET);
|
||||
sec_out32(g_nxp_caam_addr + SEC_REG_JR2ICIDR_MS_OFFSET,
|
||||
jricid | JRICID_MS_TZ);
|
||||
break;
|
||||
case 3:
|
||||
jricid = sec_in32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET);
|
||||
sec_out32(g_nxp_caam_addr + SEC_REG_JR3ICIDR_MS_OFFSET,
|
||||
jricid | JRICID_MS_TZ);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function checks if Virtualization is enabled for JR and
|
||||
* accordingly sets the bot for starting JR<num> in JRSTARTR register
|
||||
*/
|
||||
static inline void start_jr(int num)
|
||||
{
|
||||
uint32_t ctpr = sec_in32((g_nxp_caam_addr + SEC_REG_CTPR_MS_OFFSET));
|
||||
uint32_t tmp = sec_in32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET));
|
||||
uint32_t scfgr = sec_in32((g_nxp_caam_addr + SEC_REG_SCFGR_OFFSET));
|
||||
bool start = false;
|
||||
|
||||
if ((ctpr & CTPR_VIRT_EN_INC) != 0U) {
|
||||
if (((ctpr & CTPR_VIRT_EN_POR) != 0U) ||
|
||||
((scfgr & SCFGR_VIRT_EN) != 0U)) {
|
||||
start = true;
|
||||
}
|
||||
} else {
|
||||
if ((ctpr & CTPR_VIRT_EN_POR) != 0U) {
|
||||
start = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (start == true) {
|
||||
switch (num) {
|
||||
case 0:
|
||||
tmp |= JRSTARTR_STARTJR0;
|
||||
break;
|
||||
case 1:
|
||||
tmp |= JRSTARTR_STARTJR1;
|
||||
break;
|
||||
case 2:
|
||||
tmp |= JRSTARTR_STARTJR2;
|
||||
break;
|
||||
case 3:
|
||||
tmp |= JRSTARTR_STARTJR3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
sec_out32((g_nxp_caam_addr + SEC_REG_JRSTARTR_OFFSET), tmp);
|
||||
}
|
||||
|
||||
/* This functions configures the Job Ring
|
||||
* JR3 is reserved for use by Secure world
|
||||
*/
|
||||
static int configure_jr(int num)
|
||||
{
|
||||
int ret;
|
||||
void *reg_base_addr;
|
||||
|
||||
switch (num) {
|
||||
case 0:
|
||||
reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR0_OFFSET);
|
||||
break;
|
||||
case 1:
|
||||
reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR1_OFFSET);
|
||||
break;
|
||||
case 2:
|
||||
reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR2_OFFSET);
|
||||
break;
|
||||
case 3:
|
||||
reg_base_addr = (void *)(g_nxp_caam_addr + CAAM_JR3_OFFSET);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Initialize the JR library */
|
||||
ret = sec_jr_lib_init();
|
||||
if (ret != 0) {
|
||||
ERROR("Error in sec_jr_lib_init");
|
||||
return -1;
|
||||
}
|
||||
|
||||
start_jr(num);
|
||||
|
||||
/* Do HW configuration of the JR */
|
||||
job_ring = init_job_ring(SEC_NOTIFICATION_TYPE_POLL, 0, 0,
|
||||
reg_base_addr, 0);
|
||||
|
||||
if (job_ring == NULL) {
|
||||
ERROR("Error in init_job_ring");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TBD - Configures and locks the ICID values for various JR */
|
||||
static inline void configure_icid(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* TBD configures the TZ settings of RTIC */
|
||||
static inline void configure_rtic(void)
|
||||
{
|
||||
}
|
||||
|
||||
int sec_init(uintptr_t nxp_caam_addr)
|
||||
{
|
||||
g_nxp_caam_addr = nxp_caam_addr;
|
||||
return config_sec_block();
|
||||
}
|
||||
|
||||
/* This function configure SEC block:
|
||||
* - It does basic parameter setting
|
||||
* - Configures the default Job ring assigned to TZ /secure world
|
||||
* - Instantiates the RNG
|
||||
*/
|
||||
int config_sec_block(void)
|
||||
{
|
||||
int ret = 0;
|
||||
uint32_t mcfgr;
|
||||
|
||||
if (g_nxp_caam_addr == 0) {
|
||||
ERROR("Sec Init is not done.\n");
|
||||
return -1;
|
||||
} else if (job_ring != NULL) {
|
||||
NOTICE("Sec is already initialized and configured.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mcfgr = sec_in32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET);
|
||||
|
||||
/* Modify CAAM Read/Write attributes
|
||||
* AXI Write - Cacheable, WB and WA
|
||||
* AXI Read - Cacheable, RA
|
||||
*/
|
||||
#if defined(CONFIG_ARCH_LS2080A) || defined(CONFIG_ARCH_LS2088A)
|
||||
mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0xb << MCFGR_AWCACHE_SHIFT);
|
||||
mcfgr = (mcfgr & ~MCFGR_ARCACHE_MASK) | (0x6 << MCFGR_ARCACHE_SHIFT);
|
||||
#else
|
||||
mcfgr = (mcfgr & ~MCFGR_AWCACHE_MASK) | (0x2 << MCFGR_AWCACHE_SHIFT);
|
||||
#endif
|
||||
|
||||
/* Set PS bit to 1 */
|
||||
#ifdef CONFIG_PHYS_64BIT
|
||||
mcfgr |= (1 << MCFGR_PS_SHIFT);
|
||||
#endif
|
||||
sec_out32(g_nxp_caam_addr + SEC_REG_MCFGR_OFFSET, mcfgr);
|
||||
|
||||
/* Asssign ICID to all Job rings and lock them for usage */
|
||||
configure_icid();
|
||||
|
||||
/* Configure the RTIC */
|
||||
configure_rtic();
|
||||
|
||||
/* Configure the default JR for usage */
|
||||
ret = configure_jr(DEFAULT_JR);
|
||||
if (ret != 0) {
|
||||
ERROR("\nFSL_JR: configuration failure\n");
|
||||
return -1;
|
||||
}
|
||||
/* Do TZ configuration of default JR for sec firmware */
|
||||
config_tz(DEFAULT_JR);
|
||||
|
||||
#ifdef CONFIG_RNG_INIT
|
||||
/* Instantiate the RNG */
|
||||
ret = hw_rng_instantiate();
|
||||
if (ret != 0) {
|
||||
ERROR("\nRNG Instantiation failure\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This function is used for sumbitting job to the Job Ring
|
||||
* [param] [in] - jobdesc to be submitted
|
||||
* Return - -1 in case of error and 0 in case of SUCCESS
|
||||
*/
|
||||
int run_descriptor_jr(struct job_descriptor *jobdesc)
|
||||
{
|
||||
int i = 0, ret = 0;
|
||||
uint32_t *desc_addr = jobdesc->desc;
|
||||
uint32_t desc_len = desc_length(jobdesc->desc);
|
||||
uint32_t desc_word;
|
||||
|
||||
for (i = 0; i < desc_len; i++) {
|
||||
desc_word = desc_addr[i];
|
||||
VERBOSE("%x\n", desc_word);
|
||||
sec_out32((uint32_t *)&desc_addr[i], desc_word);
|
||||
}
|
||||
dsb();
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
flush_dcache_range((uintptr_t)desc_addr, desc_len * 4);
|
||||
dmbsy();
|
||||
dsbsy();
|
||||
isb();
|
||||
#endif
|
||||
|
||||
ret = enq_jr_desc(job_ring, jobdesc);
|
||||
if (ret == 0) {
|
||||
VERBOSE("JR enqueue done...\n");
|
||||
} else {
|
||||
ERROR("Error in Enqueue\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
VERBOSE("Dequeue in progress");
|
||||
|
||||
ret = dequeue_jr(job_ring, -1);
|
||||
if (ret >= 0) {
|
||||
VERBOSE("Dequeue of %x desc success\n", ret);
|
||||
ret = 0;
|
||||
} else {
|
||||
ERROR("deq_ret %x\n", ret);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* this function returns a random number using HW RNG Algo
|
||||
* In case of failure, random number returned is 0
|
||||
* prngWidth = 0 - 32 bit random number
|
||||
* prngWidth > 0 means 64 bit random number
|
||||
*/
|
||||
unsigned long long get_random(int rngWidth)
|
||||
{
|
||||
unsigned long long result = 0;
|
||||
uint8_t rand_byte[64] __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
uint8_t rand_byte_swp[8];
|
||||
int bytes = 0;
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CAAM_TEST
|
||||
rand_byte[0] = U(0x12);
|
||||
rand_byte[1] = U(0x34);
|
||||
rand_byte[2] = U(0x56);
|
||||
rand_byte[3] = U(0x78);
|
||||
rand_byte[4] = U(0x9a);
|
||||
rand_byte[5] = U(0xbc);
|
||||
rand_byte[6] = U(0xde);
|
||||
rand_byte[7] = U(0xf1);
|
||||
#endif
|
||||
|
||||
if (rngWidth == 0U) {
|
||||
bytes = 4;
|
||||
} else {
|
||||
bytes = 8;
|
||||
}
|
||||
|
||||
memset(rand_byte, 0, 64);
|
||||
|
||||
ret = get_rand_bytes_hw(rand_byte, bytes);
|
||||
|
||||
for (i = 0; i < bytes; i++) {
|
||||
if (ret != 0) {
|
||||
/* Return 0 in case of failure */
|
||||
rand_byte_swp[i] = 0;
|
||||
} else {
|
||||
rand_byte_swp[i] = rand_byte[bytes - i - 1];
|
||||
result = (result << 8) | rand_byte_swp[i];
|
||||
}
|
||||
}
|
||||
|
||||
INFO("result %llx\n", result);
|
||||
|
||||
return result;
|
||||
|
||||
} /* _get_RNG() */
|
||||
|
||||
unsigned int _get_hw_unq_key(uint64_t hw_key_phy_addr, unsigned int size)
|
||||
{
|
||||
int ret = 0;
|
||||
uint8_t *hw_key = (uint8_t *) ptov((phys_addr_t *) hw_key_phy_addr);
|
||||
|
||||
ret = get_hw_unq_key_blob_hw(hw_key, size);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include "jobdesc.h"
|
||||
#include "sec_hw_specific.h"
|
||||
|
||||
|
||||
/* Callback function after Instantiation decsriptor is submitted to SEC
|
||||
*/
|
||||
static void blob_done(uint32_t *desc, uint32_t status, void *arg,
|
||||
void *job_ring)
|
||||
{
|
||||
INFO("Blob Desc SUCCESS with status %x\n", status);
|
||||
}
|
||||
|
||||
/* @brief Submit descriptor to create blob
|
||||
* @retval 0 on success
|
||||
* @retval -1 on error
|
||||
*/
|
||||
int get_hw_unq_key_blob_hw(uint8_t *hw_key, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
|
||||
uint32_t key_sz = KEY_IDNFR_SZ_BYTES;
|
||||
uint8_t key_data[KEY_IDNFR_SZ_BYTES];
|
||||
uint8_t in_data[16];
|
||||
uint8_t out_data[16 + KEY_BLOB_SIZE + MAC_SIZE];
|
||||
struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
struct job_descriptor *jobdesc = &desc;
|
||||
uint32_t in_sz = 16U;
|
||||
|
||||
/* Output blob will have 32 bytes key blob in beginning and
|
||||
* 16 byte HMAC identifier at end of data blob
|
||||
*/
|
||||
uint32_t out_sz = in_sz + KEY_BLOB_SIZE + MAC_SIZE;
|
||||
|
||||
uint32_t operation = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL |
|
||||
OP_PCLID_BLOB | BLOB_PROTO_INFO;
|
||||
|
||||
memset(key_data, 0xff, KEY_IDNFR_SZ_BYTES);
|
||||
memset(in_data, 0x00, in_sz);
|
||||
memset(out_data, 0x00, in_sz);
|
||||
|
||||
jobdesc->arg = NULL;
|
||||
jobdesc->callback = blob_done;
|
||||
|
||||
INFO("\nGenerating Master Key Verification Blob.\n");
|
||||
|
||||
/* Create the hw_rng descriptor */
|
||||
ret = cnstr_hw_encap_blob_jobdesc(jobdesc->desc, key_data, key_sz,
|
||||
CLASS_2, in_data, in_sz, out_data,
|
||||
out_sz, operation);
|
||||
|
||||
/* Finally, generate the blob. */
|
||||
ret = run_descriptor_jr(jobdesc);
|
||||
if (ret != 0) {
|
||||
ERROR("Error in running hw unq key blob descriptor\n");
|
||||
return -1;
|
||||
}
|
||||
/* Copying alternate bytes of the Master Key Verification Blob.
|
||||
*/
|
||||
for (i = 0; i < size; i++) {
|
||||
hw_key[i] = out_data[2 * i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Copyright 2017-2020 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include "jobdesc.h"
|
||||
#include "rsa.h"
|
||||
#include "sec_hw_specific.h"
|
||||
|
||||
|
||||
/* Return Length of desctiptr from first word */
|
||||
uint32_t desc_length(uint32_t *desc)
|
||||
{
|
||||
return desc[0] & DESC_LEN_MASK;
|
||||
}
|
||||
|
||||
/*Update start index in first word of descriptor */
|
||||
void desc_update_start_index(uint32_t *desc, uint32_t index)
|
||||
{
|
||||
desc[0] |= (index << DESC_START_SHIFT);
|
||||
}
|
||||
|
||||
/* Initialize the descriptor */
|
||||
void desc_init(uint32_t *desc)
|
||||
{
|
||||
*desc = 0;
|
||||
}
|
||||
|
||||
/* Add word in the descriptor and increment the length */
|
||||
void desc_add_word(uint32_t *desc, uint32_t word)
|
||||
{
|
||||
uint32_t len = desc_length(desc);
|
||||
|
||||
/* Add Word at Last */
|
||||
uint32_t *last = desc + len;
|
||||
*last = word;
|
||||
|
||||
/* Increase the length */
|
||||
desc[0] += 1;
|
||||
}
|
||||
|
||||
/* Add Pointer to the descriptor */
|
||||
void desc_add_ptr(uint32_t *desc, phys_addr_t *ptr)
|
||||
{
|
||||
uint32_t len = desc_length(desc);
|
||||
|
||||
/* Add Word at Last */
|
||||
phys_addr_t *last = (phys_addr_t *) (desc + len);
|
||||
|
||||
#ifdef CONFIG_PHYS_64BIT
|
||||
ptr_addr_t *ptr_addr = (ptr_addr_t *) last;
|
||||
|
||||
ptr_addr->m_halves.high = PHYS_ADDR_HI(ptr);
|
||||
ptr_addr->m_halves.low = PHYS_ADDR_LO(ptr);
|
||||
#else
|
||||
*last = ptr;
|
||||
#endif
|
||||
|
||||
/* Increase the length */
|
||||
desc[0] += (uint32_t) (sizeof(phys_addr_t) / sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/* Descriptor to generate Random words */
|
||||
int cnstr_rng_jobdesc(uint32_t *desc, uint32_t state_handle,
|
||||
uint32_t *add_inp, uint32_t add_ip_len,
|
||||
uint8_t *out_data, uint32_t len)
|
||||
{
|
||||
phys_addr_t *phys_addr_out = vtop(out_data);
|
||||
|
||||
/* Current descriptor support only 64K length */
|
||||
if (len > U(0xffff))
|
||||
return -1;
|
||||
/* Additional Input not supported by current descriptor */
|
||||
if (add_ip_len > 0U)
|
||||
return -1;
|
||||
|
||||
VERBOSE("Constructing descriptor\n");
|
||||
desc_init(desc);
|
||||
/* Class1 Alg Operation,RNG Optype, Generate */
|
||||
desc_add_word(desc, U(0xb0800000));
|
||||
desc_add_word(desc, U(0x82500000) | (state_handle << ALG_AAI_SH_SHIFT));
|
||||
desc_add_word(desc, U(0x60340000) | len);
|
||||
desc_add_ptr(desc, phys_addr_out);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/* Construct descriptor to instantiate RNG */
|
||||
int cnstr_rng_instantiate_jobdesc(uint32_t *desc)
|
||||
{
|
||||
desc_init(desc);
|
||||
desc_add_word(desc, U(0xb0800000));
|
||||
/* Class1 Alg Operation,RNG Optype, Instantiate */
|
||||
desc_add_word(desc, U(0x82500004));
|
||||
/* Wait for done */
|
||||
desc_add_word(desc, U(0xa2000001));
|
||||
/*Load to clear written */
|
||||
desc_add_word(desc, U(0x10880004));
|
||||
/*Pri Mode Reg clear */
|
||||
desc_add_word(desc, U(0x00000001));
|
||||
/* Generate secure keys */
|
||||
desc_add_word(desc, U(0x82501000));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Construct descriptor to generate hw key blob */
|
||||
int cnstr_hw_encap_blob_jobdesc(uint32_t *desc,
|
||||
uint8_t *key_idnfr, uint32_t key_sz,
|
||||
uint32_t key_class, uint8_t *plain_txt,
|
||||
uint32_t in_sz, uint8_t *enc_blob,
|
||||
uint32_t out_sz, uint32_t operation)
|
||||
{
|
||||
phys_addr_t *phys_key_idnfr, *phys_addr_in, *phys_addr_out;
|
||||
int i = 0;
|
||||
|
||||
phys_key_idnfr = vtop((void *)key_idnfr);
|
||||
phys_addr_in = vtop((void *)plain_txt);
|
||||
phys_addr_out = vtop((void *)enc_blob);
|
||||
|
||||
desc_init(desc);
|
||||
|
||||
desc_add_word(desc, U(0xb0800000));
|
||||
|
||||
/* Key Identifier */
|
||||
desc_add_word(desc, (key_class | key_sz));
|
||||
desc_add_ptr(desc, phys_key_idnfr);
|
||||
|
||||
/* Source Address */
|
||||
desc_add_word(desc, U(0xf0400000));
|
||||
desc_add_ptr(desc, phys_addr_in);
|
||||
|
||||
/* In Size = 0x10 */
|
||||
desc_add_word(desc, in_sz);
|
||||
|
||||
/* Out Address */
|
||||
desc_add_word(desc, U(0xf8400000));
|
||||
desc_add_ptr(desc, phys_addr_out);
|
||||
|
||||
/* Out Size = 0x10 */
|
||||
desc_add_word(desc, out_sz);
|
||||
|
||||
/* Operation */
|
||||
desc_add_word(desc, operation);
|
||||
|
||||
for (i = 0; i < 15; i++)
|
||||
VERBOSE("desc word %x\n", desc[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : inline_cnstr_jobdesc_pkha_rsaexp
|
||||
* Arguments : desc - Pointer to Descriptor
|
||||
* pkin - Pointer to Input Params
|
||||
* out - Pointer to Output
|
||||
* out_siz - Output Size
|
||||
* Return : Void
|
||||
* Description : Creates the descriptor for PKHA RSA
|
||||
***************************************************************************/
|
||||
void cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
|
||||
struct pk_in_params *pkin, uint8_t *out,
|
||||
uint32_t out_siz)
|
||||
{
|
||||
phys_addr_t *ptr_addr_e, *ptr_addr_a, *ptr_addr_n, *ptr_addr_out;
|
||||
|
||||
ptr_addr_e = vtop((void *)(pkin->e));
|
||||
ptr_addr_a = vtop((void *)(pkin->a));
|
||||
ptr_addr_n = vtop((void *)(pkin->n));
|
||||
ptr_addr_out = vtop((void *)(out));
|
||||
|
||||
desc_init(desc);
|
||||
desc_add_word(desc, U(0xb0800000));
|
||||
desc_add_word(desc, U(0x02010000) | pkin->e_siz);
|
||||
desc_add_ptr(desc, ptr_addr_e);
|
||||
desc_add_word(desc, U(0x220c0000) | pkin->a_siz);
|
||||
desc_add_ptr(desc, ptr_addr_a);
|
||||
desc_add_word(desc, U(0x22080000) | pkin->n_siz);
|
||||
desc_add_ptr(desc, ptr_addr_n);
|
||||
desc_add_word(desc, U(0x81800006));
|
||||
desc_add_word(desc, U(0x620d0000) | out_siz);
|
||||
desc_add_ptr(desc, ptr_addr_out);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Function : inline_cnstr_jobdesc_sha256
|
||||
* Arguments : desc - Pointer to Descriptor
|
||||
* msg - Pointer to SG Table
|
||||
* msgsz - Size of SG Table
|
||||
* digest - Pointer to Output Digest
|
||||
* Return : Void
|
||||
* Description : Creates the descriptor for SHA256 HASH calculation
|
||||
***************************************************************************/
|
||||
void cnstr_hash_jobdesc(uint32_t *desc, uint8_t *msg, uint32_t msgsz,
|
||||
uint8_t *digest)
|
||||
{
|
||||
/* SHA 256 , output is of length 32 words */
|
||||
phys_addr_t *ptr_addr_in, *ptr_addr_out;
|
||||
|
||||
ptr_addr_in = (void *)vtop(msg);
|
||||
ptr_addr_out = (void *)vtop(digest);
|
||||
|
||||
desc_init(desc);
|
||||
desc_add_word(desc, U(0xb0800000));
|
||||
|
||||
/* Operation Command
|
||||
* OP_TYPE_CLASS2_ALG | OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HASH |
|
||||
* OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT | OP_ALG_ICV_OFF)
|
||||
*/
|
||||
desc_add_word(desc, U(0x8443000d));
|
||||
|
||||
if (msgsz > U(0xffff)) {
|
||||
desc_add_word(desc, U(0x25540000)); /* FIFO Load */
|
||||
desc_add_ptr(desc, ptr_addr_in); /* Pointer to msg */
|
||||
desc_add_word(desc, msgsz); /* Size */
|
||||
desc_add_word(desc, U(0x54200020)); /* FIFO Store */
|
||||
desc_add_ptr(desc, ptr_addr_out); /* Pointer to Result */
|
||||
} else {
|
||||
desc_add_word(desc, U(0x25140000) | msgsz);
|
||||
desc_add_ptr(desc, ptr_addr_in);
|
||||
desc_add_word(desc, U(0x54200020));
|
||||
desc_add_ptr(desc, ptr_addr_out);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include "jobdesc.h"
|
||||
#include "sec_hw_specific.h"
|
||||
|
||||
|
||||
/* Callback function after Instantiation decsriptor is submitted to SEC */
|
||||
static void rng_done(uint32_t *desc, uint32_t status, void *arg,
|
||||
void *job_ring)
|
||||
{
|
||||
INFO("RNG Desc SUCCESS with status %x\n", status);
|
||||
}
|
||||
|
||||
/* Is the HW RNG instantiated?
|
||||
* Return code:
|
||||
* 0 - Not in the instantiated state
|
||||
* 1 - In the instantiated state
|
||||
* state_handle - 0 for SH0, 1 for SH1
|
||||
*/
|
||||
static int is_hw_rng_instantiated(uint32_t *state_handle)
|
||||
{
|
||||
int ret_code = 0;
|
||||
uint32_t rdsta;
|
||||
|
||||
rdsta = sec_in32(get_caam_addr() + RNG_REG_RDSTA_OFFSET);
|
||||
|
||||
/*Check if either of the two state handles has been instantiated */
|
||||
if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
|
||||
*state_handle = 0;
|
||||
ret_code = 1;
|
||||
} else if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
|
||||
*state_handle = 1;
|
||||
ret_code = 1;
|
||||
}
|
||||
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
/* @brief Kick the TRNG block of the RNG HW Engine
|
||||
* @param [in] ent_delay Entropy delay to be used
|
||||
* By default, the TRNG runs for 200 clocks per sample;
|
||||
* 1200 clocks per sample generates better entropy.
|
||||
* @retval 0 on success
|
||||
* @retval -1 on error
|
||||
*/
|
||||
static void kick_trng(int ent_delay)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
/* put RNG4 into program mode */
|
||||
val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
|
||||
val = val | RTMCTL_PRGM;
|
||||
sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
|
||||
|
||||
/* rtsdctl bits 0-15 contain "Entropy Delay, which defines the
|
||||
* length (in system clocks) of each Entropy sample taken
|
||||
*/
|
||||
val = sec_in32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET);
|
||||
val = (val & ~RTSDCTL_ENT_DLY_MASK) |
|
||||
(ent_delay << RTSDCTL_ENT_DLY_SHIFT);
|
||||
sec_out32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET, val);
|
||||
/* min. freq. count, equal to 1/4 of the entropy sample length */
|
||||
sec_out32(get_caam_addr() + RNG_REG_RTFRQMIN_OFFSET, ent_delay >> 2);
|
||||
/* disable maximum frequency count */
|
||||
sec_out32(get_caam_addr() + RNG_REG_RTFRQMAX_OFFSET, RTFRQMAX_DISABLE);
|
||||
|
||||
/* select raw sampling in both entropy shifter
|
||||
* and statistical checker
|
||||
*/
|
||||
val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
|
||||
val = val | RTMCTL_SAMP_MODE_RAW_ES_SC;
|
||||
sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
|
||||
|
||||
/* put RNG4 into run mode */
|
||||
val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
|
||||
val = val & ~RTMCTL_PRGM;
|
||||
sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
|
||||
}
|
||||
|
||||
/* @brief Submit descriptor to instantiate the RNG
|
||||
* @retval 0 on success
|
||||
* @retval -1 on error
|
||||
*/
|
||||
static int instantiate_rng(void)
|
||||
{
|
||||
int ret = 0;
|
||||
struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
struct job_descriptor *jobdesc = &desc;
|
||||
|
||||
jobdesc->arg = NULL;
|
||||
jobdesc->callback = rng_done;
|
||||
|
||||
/* create the hw_rng descriptor */
|
||||
cnstr_rng_instantiate_jobdesc(jobdesc->desc);
|
||||
|
||||
/* Finally, generate the requested random data bytes */
|
||||
ret = run_descriptor_jr(jobdesc);
|
||||
if (ret != 0) {
|
||||
ERROR("Error in running descriptor\n");
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Generate Random Data using HW RNG
|
||||
* Parameters:
|
||||
* uint8_t* add_input - user specified optional input byte array
|
||||
* uint32_t add_input_len - number of bytes of additional input
|
||||
* uint8_t* out - user specified output byte array
|
||||
* uint32_t out_len - number of bytes to store in output byte array
|
||||
* Return code:
|
||||
* 0 - SUCCESS
|
||||
* -1 - ERROR
|
||||
*/
|
||||
static int
|
||||
hw_rng_generate(uint32_t *add_input, uint32_t add_input_len,
|
||||
uint8_t *out, uint32_t out_len, uint32_t state_handle)
|
||||
{
|
||||
int ret = 0;
|
||||
struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
struct job_descriptor *jobdesc = &desc;
|
||||
|
||||
jobdesc->arg = NULL;
|
||||
jobdesc->callback = rng_done;
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
inv_dcache_range((uintptr_t)out, out_len);
|
||||
dmbsy();
|
||||
#endif
|
||||
|
||||
/* create the hw_rng descriptor */
|
||||
ret = cnstr_rng_jobdesc(jobdesc->desc, state_handle,
|
||||
add_input, add_input_len, out, out_len);
|
||||
if (ret != 0) {
|
||||
ERROR("Descriptor construction failed\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
/* Finally, generate the requested random data bytes */
|
||||
ret = run_descriptor_jr(jobdesc);
|
||||
if (ret != 0) {
|
||||
ERROR("Error in running descriptor\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* this function instantiates the rng
|
||||
*
|
||||
* Return code:
|
||||
* 0 - All is well
|
||||
* <0 - Error occurred somewhere
|
||||
*/
|
||||
int hw_rng_instantiate(void)
|
||||
{
|
||||
int ret = 0;
|
||||
int ent_delay = RTSDCTL_ENT_DLY_MIN;
|
||||
uint32_t state_handle;
|
||||
|
||||
ret = is_hw_rng_instantiated(&state_handle);
|
||||
if (ret != 0) {
|
||||
NOTICE("RNG already instantiated\n");
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
kick_trng(ent_delay);
|
||||
ent_delay += 400;
|
||||
/*if instantiate_rng(...) fails, the loop will rerun
|
||||
*and the kick_trng(...) function will modify the
|
||||
*upper and lower limits of the entropy sampling
|
||||
*interval, leading to a sucessful initialization of
|
||||
*/
|
||||
ret = instantiate_rng();
|
||||
} while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
|
||||
if (ret != 0) {
|
||||
ERROR("RNG: Failed to instantiate RNG\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
NOTICE("RNG: INSTANTIATED\n");
|
||||
|
||||
/* Enable RDB bit so that RNG works faster */
|
||||
// sec_setbits32(&sec->scfgr, SEC_SCFGR_RDBENABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Generate random bytes, and stuff them into the bytes buffer
|
||||
*
|
||||
* If the HW RNG has not already been instantiated,
|
||||
* it will be instantiated before data is generated.
|
||||
*
|
||||
* Parameters:
|
||||
* uint8_t* bytes - byte buffer large enough to hold the requested random date
|
||||
* int byte_len - number of random bytes to generate
|
||||
*
|
||||
* Return code:
|
||||
* 0 - All is well
|
||||
* ~0 - Error occurred somewhere
|
||||
*/
|
||||
int get_rand_bytes_hw(uint8_t *bytes, int byte_len)
|
||||
{
|
||||
int ret_code = 0;
|
||||
uint32_t state_handle;
|
||||
|
||||
/* If this is the first time this routine is called,
|
||||
* then the hash_drbg will not already be instantiated.
|
||||
* Therefore, before generating data, instantiate the hash_drbg
|
||||
*/
|
||||
ret_code = is_hw_rng_instantiated(&state_handle);
|
||||
if (ret_code == 0) {
|
||||
INFO("Instantiating the HW RNG\n");
|
||||
|
||||
/* Instantiate the hw RNG */
|
||||
ret_code = hw_rng_instantiate();
|
||||
if (ret_code != 0) {
|
||||
ERROR("HW RNG Instantiate failed\n");
|
||||
return ret_code;
|
||||
}
|
||||
}
|
||||
/* If HW RNG is still not instantiated, something must have gone wrong,
|
||||
* it must be in the error state, we will not generate any random data
|
||||
*/
|
||||
if (is_hw_rng_instantiated(&state_handle) == 0) {
|
||||
ERROR("HW RNG is in an Error state, and cannot be used\n");
|
||||
return -1;
|
||||
}
|
||||
/* Generate a random 256-bit value, as 32 bytes */
|
||||
ret_code = hw_rng_generate(0, 0, bytes, byte_len, state_handle);
|
||||
if (ret_code != 0) {
|
||||
ERROR("HW RNG Generate failed\n");
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
return ret_code;
|
||||
}
|
|
@ -0,0 +1,635 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include "jobdesc.h"
|
||||
#include "sec_hw_specific.h"
|
||||
|
||||
|
||||
/* Job rings used for communication with SEC HW */
|
||||
extern struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS];
|
||||
|
||||
/* The current state of SEC user space driver */
|
||||
extern volatile sec_driver_state_t g_driver_state;
|
||||
|
||||
/* The number of job rings used by SEC user space driver */
|
||||
extern int g_job_rings_no;
|
||||
|
||||
/* LOCAL FUNCTIONS */
|
||||
static inline void hw_set_input_ring_start_addr(struct jobring_regs *regs,
|
||||
phys_addr_t *start_addr)
|
||||
{
|
||||
#if defined(CONFIG_PHYS_64BIT)
|
||||
sec_out32(®s->irba_h, PHYS_ADDR_HI(start_addr));
|
||||
#else
|
||||
sec_out32(®s->irba_h, 0);
|
||||
#endif
|
||||
sec_out32(®s->irba_l, PHYS_ADDR_LO(start_addr));
|
||||
}
|
||||
|
||||
static inline void hw_set_output_ring_start_addr(struct jobring_regs *regs,
|
||||
phys_addr_t *start_addr)
|
||||
{
|
||||
#if defined(CONFIG_PHYS_64BIT)
|
||||
sec_out32(®s->orba_h, PHYS_ADDR_HI(start_addr));
|
||||
#else
|
||||
sec_out32(®s->orba_h, 0);
|
||||
#endif
|
||||
sec_out32(®s->orba_l, PHYS_ADDR_LO(start_addr));
|
||||
}
|
||||
|
||||
/* ORJR - Output Ring Jobs Removed Register shows how many jobs were
|
||||
* removed from the Output Ring for processing by software. This is done after
|
||||
* the software has processed the entries.
|
||||
*/
|
||||
static inline void hw_remove_entries(sec_job_ring_t *jr, int num)
|
||||
{
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)jr->register_base_addr;
|
||||
|
||||
sec_out32(®s->orjr, num);
|
||||
}
|
||||
|
||||
/* IRSA - Input Ring Slots Available register holds the number of entries in
|
||||
* the Job Ring's input ring. Once a job is enqueued, the value returned is
|
||||
* decremented by the hardware by the number of jobs enqueued.
|
||||
*/
|
||||
static inline int hw_get_available_slots(sec_job_ring_t *jr)
|
||||
{
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)jr->register_base_addr;
|
||||
|
||||
return sec_in32(®s->irsa);
|
||||
}
|
||||
|
||||
/* ORSFR - Output Ring Slots Full register holds the number of jobs which were
|
||||
* processed by the SEC and can be retrieved by the software. Once a job has
|
||||
* been processed by software, the user will call hw_remove_one_entry in order
|
||||
* to notify the SEC that the entry was processed
|
||||
*/
|
||||
static inline int hw_get_no_finished_jobs(sec_job_ring_t *jr)
|
||||
{
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)jr->register_base_addr;
|
||||
|
||||
return sec_in32(®s->orsf);
|
||||
}
|
||||
|
||||
/* @brief Process Jump Halt Condition related errors
|
||||
* @param [in] error_code The error code in the descriptor status word
|
||||
*/
|
||||
static inline void hw_handle_jmp_halt_cond_err(union hw_error_code error_code)
|
||||
{
|
||||
ERROR("JMP %x\n", error_code.error_desc.jmp_halt_cond_src.jmp);
|
||||
ERROR("Descriptor Index: %d\n",
|
||||
error_code.error_desc.jmp_halt_cond_src.desc_idx);
|
||||
ERROR(" Condition %x\n", error_code.error_desc.jmp_halt_cond_src.cond);
|
||||
}
|
||||
|
||||
/* @brief Process DECO related errors
|
||||
* @param [in] error_code The error code in the descriptor status word
|
||||
*/
|
||||
static inline void hw_handle_deco_err(union hw_error_code error_code)
|
||||
{
|
||||
ERROR("JMP %x\n", error_code.error_desc.deco_src.jmp);
|
||||
ERROR("Descriptor Index: 0x%x",
|
||||
error_code.error_desc.deco_src.desc_idx);
|
||||
|
||||
switch (error_code.error_desc.deco_src.desc_err) {
|
||||
case SEC_HW_ERR_DECO_HFN_THRESHOLD:
|
||||
WARN(" Descriptor completed but exceeds the Threshold");
|
||||
break;
|
||||
default:
|
||||
ERROR("Error 0x%04x not implemented",
|
||||
error_code.error_desc.deco_src.desc_err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* @brief Process Jump Halt User Status related errors
|
||||
* @param [in] error_code The error code in the descriptor status word
|
||||
*/
|
||||
static inline void hw_handle_jmp_halt_user_err(union hw_error_code error_code)
|
||||
{
|
||||
WARN(" Not implemented");
|
||||
}
|
||||
|
||||
/* @brief Process CCB related errors
|
||||
* @param [in] error_code The error code in the descriptor status word
|
||||
*/
|
||||
static inline void hw_handle_ccb_err(union hw_error_code hw_error_code)
|
||||
{
|
||||
WARN(" Not implemented");
|
||||
}
|
||||
|
||||
/* @brief Process Job Ring related errors
|
||||
* @param [in] error_code The error code in the descriptor status word
|
||||
*/
|
||||
static inline void hw_handle_jr_err(union hw_error_code hw_error_code)
|
||||
{
|
||||
WARN(" Not implemented");
|
||||
}
|
||||
|
||||
/* GLOBAL FUNCTIONS */
|
||||
|
||||
int hw_reset_job_ring(sec_job_ring_t *job_ring)
|
||||
{
|
||||
int ret = 0;
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
|
||||
/* First reset the job ring in hw */
|
||||
ret = hw_shutdown_job_ring(job_ring);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed resetting job ring in hardware");
|
||||
return ret;
|
||||
}
|
||||
/* In order to have the HW JR in a workable state
|
||||
*after a reset, I need to re-write the input
|
||||
* queue size, input start address, output queue
|
||||
* size and output start address
|
||||
* Write the JR input queue size to the HW register
|
||||
*/
|
||||
sec_out32(®s->irs, SEC_JOB_RING_SIZE);
|
||||
|
||||
/* Write the JR output queue size to the HW register */
|
||||
sec_out32(®s->ors, SEC_JOB_RING_SIZE);
|
||||
|
||||
/* Write the JR input queue start address */
|
||||
hw_set_input_ring_start_addr(regs, vtop(job_ring->input_ring));
|
||||
|
||||
/* Write the JR output queue start address */
|
||||
hw_set_output_ring_start_addr(regs, vtop(job_ring->output_ring));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_shutdown_job_ring(sec_job_ring_t *job_ring)
|
||||
{
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
unsigned int timeout = SEC_TIMEOUT;
|
||||
uint32_t tmp = 0U;
|
||||
|
||||
VERBOSE("Resetting Job ring\n");
|
||||
|
||||
/*
|
||||
* Mask interrupts since we are going to poll
|
||||
* for reset completion status
|
||||
* Also, at POR, interrupts are ENABLED on a JR, thus
|
||||
* this is the point where I can disable them without
|
||||
* changing the code logic too much
|
||||
*/
|
||||
|
||||
jr_disable_irqs(job_ring);
|
||||
|
||||
/* initiate flush (required prior to reset) */
|
||||
sec_out32(®s->jrcr, JR_REG_JRCR_VAL_RESET);
|
||||
|
||||
/* dummy read */
|
||||
tmp = sec_in32(®s->jrcr);
|
||||
|
||||
do {
|
||||
tmp = sec_in32(®s->jrint);
|
||||
} while (((tmp & JRINT_ERR_HALT_MASK) ==
|
||||
JRINT_ERR_HALT_INPROGRESS) && ((--timeout) != 0U));
|
||||
|
||||
if ((tmp & JRINT_ERR_HALT_MASK) != JRINT_ERR_HALT_COMPLETE ||
|
||||
timeout == 0U) {
|
||||
ERROR("Failed to flush hw job ring %x\n %u", tmp, timeout);
|
||||
/* unmask interrupts */
|
||||
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
|
||||
jr_enable_irqs(job_ring);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* Initiate reset */
|
||||
timeout = SEC_TIMEOUT;
|
||||
sec_out32(®s->jrcr, JR_REG_JRCR_VAL_RESET);
|
||||
|
||||
do {
|
||||
tmp = sec_in32(®s->jrcr);
|
||||
} while (((tmp & JR_REG_JRCR_VAL_RESET) != 0U) &&
|
||||
((--timeout) != 0U));
|
||||
|
||||
if (timeout == 0U) {
|
||||
ERROR("Failed to reset hw job ring\n");
|
||||
/* unmask interrupts */
|
||||
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
|
||||
jr_enable_irqs(job_ring);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/* unmask interrupts */
|
||||
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
|
||||
jr_enable_irqs(job_ring);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void hw_handle_job_ring_error(sec_job_ring_t *job_ring, uint32_t error_code)
|
||||
{
|
||||
union hw_error_code hw_err_code;
|
||||
|
||||
hw_err_code.error = error_code;
|
||||
|
||||
switch (hw_err_code.error_desc.value.ssrc) {
|
||||
case SEC_HW_ERR_SSRC_NO_SRC:
|
||||
INFO("No Status Source ");
|
||||
break;
|
||||
case SEC_HW_ERR_SSRC_CCB_ERR:
|
||||
INFO("CCB Status Source");
|
||||
hw_handle_ccb_err(hw_err_code);
|
||||
break;
|
||||
case SEC_HW_ERR_SSRC_JMP_HALT_U:
|
||||
INFO("Jump Halt User Status Source");
|
||||
hw_handle_jmp_halt_user_err(hw_err_code);
|
||||
break;
|
||||
case SEC_HW_ERR_SSRC_DECO:
|
||||
INFO("DECO Status Source");
|
||||
hw_handle_deco_err(hw_err_code);
|
||||
break;
|
||||
case SEC_HW_ERR_SSRC_JR:
|
||||
INFO("Job Ring Status Source");
|
||||
hw_handle_jr_err(hw_err_code);
|
||||
break;
|
||||
case SEC_HW_ERR_SSRC_JMP_HALT_COND:
|
||||
INFO("Jump Halt Condition Codes");
|
||||
hw_handle_jmp_halt_cond_err(hw_err_code);
|
||||
break;
|
||||
default:
|
||||
INFO("Unknown SSRC");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int hw_job_ring_error(sec_job_ring_t *job_ring)
|
||||
{
|
||||
uint32_t jrint_error_code;
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
|
||||
if (JR_REG_JRINT_JRE_EXTRACT(sec_in32(®s->jrint)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
jrint_error_code =
|
||||
JR_REG_JRINT_ERR_TYPE_EXTRACT(sec_in32(®s->jrint));
|
||||
switch (jrint_error_code) {
|
||||
case JRINT_ERR_WRITE_STATUS:
|
||||
ERROR("Error writing status to Output Ring ");
|
||||
break;
|
||||
case JRINT_ERR_BAD_INPUT_BASE:
|
||||
ERROR("Bad Input Ring Base (not on a 4-byte boundary)\n");
|
||||
break;
|
||||
case JRINT_ERR_BAD_OUTPUT_BASE:
|
||||
ERROR("Bad Output Ring Base (not on a 4-byte boundary)\n");
|
||||
break;
|
||||
case JRINT_ERR_WRITE_2_IRBA:
|
||||
ERROR("Invalid write to Input Ring Base Address Register\n");
|
||||
break;
|
||||
case JRINT_ERR_WRITE_2_ORBA:
|
||||
ERROR("Invalid write to Output Ring Base Address Register\n");
|
||||
break;
|
||||
case JRINT_ERR_RES_B4_HALT:
|
||||
ERROR("Job Ring released before Job Ring is halted\n");
|
||||
break;
|
||||
case JRINT_ERR_REM_TOO_MANY:
|
||||
ERROR("Removed too many jobs from job ring\n");
|
||||
break;
|
||||
case JRINT_ERR_ADD_TOO_MANY:
|
||||
ERROR("Added too many jobs on job ring\n");
|
||||
break;
|
||||
default:
|
||||
ERROR("Unknown SEC JR Error :%d\n", jrint_error_code);
|
||||
break;
|
||||
}
|
||||
return jrint_error_code;
|
||||
}
|
||||
|
||||
int hw_job_ring_set_coalescing_param(sec_job_ring_t *job_ring,
|
||||
uint16_t irq_coalescing_timer,
|
||||
uint8_t irq_coalescing_count)
|
||||
{
|
||||
uint32_t reg_val = 0U;
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
|
||||
/* Set descriptor count coalescing */
|
||||
reg_val |= (irq_coalescing_count << JR_REG_JRCFG_LO_ICDCT_SHIFT);
|
||||
|
||||
/* Set coalescing timer value */
|
||||
reg_val |= (irq_coalescing_timer << JR_REG_JRCFG_LO_ICTT_SHIFT);
|
||||
|
||||
/* Update parameters in HW */
|
||||
sec_out32(®s->jrcfg1, reg_val);
|
||||
|
||||
VERBOSE("Set coalescing params on jr\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_job_ring_enable_coalescing(sec_job_ring_t *job_ring)
|
||||
{
|
||||
uint32_t reg_val = 0U;
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
|
||||
/* Get the current value of the register */
|
||||
reg_val = sec_in32(®s->jrcfg1);
|
||||
|
||||
/* Enable coalescing */
|
||||
reg_val |= JR_REG_JRCFG_LO_ICEN_EN;
|
||||
|
||||
/* Write in hw */
|
||||
sec_out32(®s->jrcfg1, reg_val);
|
||||
|
||||
VERBOSE("Enabled coalescing on jr\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hw_job_ring_disable_coalescing(sec_job_ring_t *job_ring)
|
||||
{
|
||||
uint32_t reg_val = 0U;
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
|
||||
/* Get the current value of the register */
|
||||
reg_val = sec_in32(®s->jrcfg1);
|
||||
|
||||
/* Disable coalescing */
|
||||
reg_val &= ~JR_REG_JRCFG_LO_ICEN_EN;
|
||||
|
||||
/* Write in hw */
|
||||
sec_out32(®s->jrcfg1, reg_val);
|
||||
|
||||
VERBOSE("Disabled coalescing on jr");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void hw_flush_job_ring(struct sec_job_ring_t *job_ring,
|
||||
uint32_t do_notify,
|
||||
uint32_t error_code, uint32_t *notified_descs)
|
||||
{
|
||||
int32_t jobs_no_to_discard = 0;
|
||||
int32_t discarded_descs_no = 0;
|
||||
int32_t number_of_jobs_available = 0;
|
||||
|
||||
VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx);
|
||||
VERBOSE("error code %x\n", error_code);
|
||||
VERBOSE("Notify_desc = %d\n", do_notify);
|
||||
|
||||
number_of_jobs_available = hw_get_no_finished_jobs(job_ring);
|
||||
|
||||
/* Discard all jobs */
|
||||
jobs_no_to_discard = number_of_jobs_available;
|
||||
|
||||
VERBOSE("JR pi[%d]i ci[%d]\n", job_ring->pidx, job_ring->cidx);
|
||||
VERBOSE("Discarding desc = %d\n", jobs_no_to_discard);
|
||||
|
||||
while (jobs_no_to_discard > discarded_descs_no) {
|
||||
discarded_descs_no++;
|
||||
/* Now increment the consumer index for the current job ring,
|
||||
* AFTER saving job in temporary location!
|
||||
* Increment the consumer index for the current job ring
|
||||
*/
|
||||
|
||||
job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx,
|
||||
SEC_JOB_RING_SIZE);
|
||||
|
||||
hw_remove_entries(job_ring, 1);
|
||||
}
|
||||
|
||||
if (do_notify == true) {
|
||||
if (notified_descs == NULL) {
|
||||
return;
|
||||
}
|
||||
*notified_descs = discarded_descs_no;
|
||||
}
|
||||
}
|
||||
|
||||
/* return >0 in case of success
|
||||
* -1 in case of error from SEC block
|
||||
* 0 in case job not yet processed by SEC
|
||||
* or Descriptor returned is NULL after dequeue
|
||||
*/
|
||||
int hw_poll_job_ring(struct sec_job_ring_t *job_ring, int32_t limit)
|
||||
{
|
||||
int32_t jobs_no_to_notify = 0;
|
||||
int32_t number_of_jobs_available = 0;
|
||||
int32_t notified_descs_no = 0;
|
||||
uint32_t error_descs_no = 0U;
|
||||
uint32_t sec_error_code = 0U;
|
||||
uint32_t do_driver_shutdown = false;
|
||||
phys_addr_t *fnptr, *arg_addr;
|
||||
user_callback usercall = NULL;
|
||||
uint8_t *current_desc;
|
||||
void *arg;
|
||||
uintptr_t current_desc_addr;
|
||||
phys_addr_t current_desc_loc;
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
inv_dcache_range((uintptr_t)job_ring->register_base_addr, sizeof(struct jobring_regs));
|
||||
dmbsy();
|
||||
#endif
|
||||
|
||||
/* check here if any JR error that cannot be written
|
||||
* in the output status word has occurred
|
||||
*/
|
||||
sec_error_code = hw_job_ring_error(job_ring);
|
||||
if (unlikely(sec_error_code) != 0) {
|
||||
ERROR("Error here itself %x\n", sec_error_code);
|
||||
return -1;
|
||||
}
|
||||
/* Compute the number of notifications that need to be raised to UA
|
||||
* If limit < 0 -> notify all done jobs
|
||||
* If limit > total number of done jobs -> notify all done jobs
|
||||
* If limit = 0 -> error
|
||||
* If limit > 0 && limit < total number of done jobs -> notify a number
|
||||
* of done jobs equal with limit
|
||||
*/
|
||||
|
||||
/*compute the number of jobs available in the job ring based on the
|
||||
* producer and consumer index values.
|
||||
*/
|
||||
|
||||
number_of_jobs_available = hw_get_no_finished_jobs(job_ring);
|
||||
jobs_no_to_notify = (limit < 0 || limit > number_of_jobs_available) ?
|
||||
number_of_jobs_available : limit;
|
||||
VERBOSE("JR - pi %d, ci %d, ", job_ring->pidx, job_ring->cidx);
|
||||
VERBOSE("Jobs submitted %d", number_of_jobs_available);
|
||||
VERBOSE("Jobs to notify %d\n", jobs_no_to_notify);
|
||||
|
||||
while (jobs_no_to_notify > notified_descs_no) {
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
inv_dcache_range(
|
||||
(uintptr_t)(&job_ring->output_ring[job_ring->cidx]),
|
||||
sizeof(struct sec_outring_entry));
|
||||
dmbsy();
|
||||
#endif
|
||||
|
||||
/* Get job status here */
|
||||
sec_error_code =
|
||||
sec_in32(&(job_ring->output_ring[job_ring->cidx].status));
|
||||
|
||||
/* Get completed descriptor
|
||||
*/
|
||||
current_desc_loc = (uintptr_t)
|
||||
&job_ring->output_ring[job_ring->cidx].desc;
|
||||
current_desc_addr = sec_read_addr(current_desc_loc);
|
||||
|
||||
current_desc = ptov((phys_addr_t *) current_desc_addr);
|
||||
if (current_desc == 0) {
|
||||
ERROR("No descriptor returned from SEC");
|
||||
assert(current_desc);
|
||||
return 0;
|
||||
}
|
||||
/* now increment the consumer index for the current job ring,
|
||||
* AFTER saving job in temporary location!
|
||||
*/
|
||||
job_ring->cidx = SEC_CIRCULAR_COUNTER(job_ring->cidx,
|
||||
SEC_JOB_RING_SIZE);
|
||||
|
||||
if (sec_error_code != 0) {
|
||||
ERROR("desc at cidx %d\n ", job_ring->cidx);
|
||||
ERROR("generated error %x\n", sec_error_code);
|
||||
|
||||
sec_handle_desc_error(job_ring,
|
||||
sec_error_code,
|
||||
&error_descs_no,
|
||||
&do_driver_shutdown);
|
||||
hw_remove_entries(job_ring, 1);
|
||||
|
||||
return -1;
|
||||
}
|
||||
/* Signal that the job has been processed & the slot is free */
|
||||
hw_remove_entries(job_ring, 1);
|
||||
notified_descs_no++;
|
||||
|
||||
arg_addr = (phys_addr_t *) (current_desc +
|
||||
(MAX_DESC_SIZE_WORDS * sizeof(uint32_t)));
|
||||
|
||||
fnptr = (phys_addr_t *) (current_desc +
|
||||
(MAX_DESC_SIZE_WORDS * sizeof(uint32_t)
|
||||
+ sizeof(void *)));
|
||||
|
||||
arg = (void *)*(arg_addr);
|
||||
if (*fnptr != 0) {
|
||||
VERBOSE("Callback Function called\n");
|
||||
usercall = (user_callback) *(fnptr);
|
||||
(*usercall) ((uint32_t *) current_desc,
|
||||
sec_error_code, arg, job_ring);
|
||||
}
|
||||
}
|
||||
|
||||
return notified_descs_no;
|
||||
}
|
||||
|
||||
void sec_handle_desc_error(sec_job_ring_t *job_ring,
|
||||
uint32_t sec_error_code,
|
||||
uint32_t *notified_descs,
|
||||
uint32_t *do_driver_shutdown)
|
||||
{
|
||||
/* Analyze the SEC error on this job ring */
|
||||
hw_handle_job_ring_error(job_ring, sec_error_code);
|
||||
}
|
||||
|
||||
void flush_job_rings(void)
|
||||
{
|
||||
struct sec_job_ring_t *job_ring = NULL;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < g_job_rings_no; i++) {
|
||||
job_ring = &g_job_rings[i];
|
||||
/* Producer index is frozen. If consumer index is not equal
|
||||
* with producer index, then we have descs to flush.
|
||||
*/
|
||||
while (job_ring->pidx != job_ring->cidx) {
|
||||
hw_flush_job_ring(job_ring, false, 0, /* no error */
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int shutdown_job_ring(struct sec_job_ring_t *job_ring)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = hw_shutdown_job_ring(job_ring);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed to shutdown hardware job ring\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (job_ring->coalescing_en != 0) {
|
||||
hw_job_ring_disable_coalescing(job_ring);
|
||||
}
|
||||
|
||||
if (job_ring->jr_mode != SEC_NOTIFICATION_TYPE_POLL) {
|
||||
ret = jr_disable_irqs(job_ring);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed to disable irqs for job ring");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jr_enable_irqs(struct sec_job_ring_t *job_ring)
|
||||
{
|
||||
uint32_t reg_val = 0U;
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
|
||||
/* Get the current value of the register */
|
||||
reg_val = sec_in32(®s->jrcfg1);
|
||||
|
||||
/* Enable interrupts by disabling interrupt masking*/
|
||||
reg_val &= ~JR_REG_JRCFG_LO_IMSK_EN;
|
||||
|
||||
/* Update parameters in HW */
|
||||
sec_out32(®s->jrcfg1, reg_val);
|
||||
|
||||
VERBOSE("Enable interrupts on JR\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int jr_disable_irqs(struct sec_job_ring_t *job_ring)
|
||||
{
|
||||
uint32_t reg_val = 0U;
|
||||
struct jobring_regs *regs =
|
||||
(struct jobring_regs *)job_ring->register_base_addr;
|
||||
|
||||
/* Get the current value of the register */
|
||||
reg_val = sec_in32(®s->jrcfg1);
|
||||
|
||||
/* Disable interrupts by enabling interrupt masking*/
|
||||
reg_val |= JR_REG_JRCFG_LO_IMSK_EN;
|
||||
|
||||
/* Update parameters in HW */
|
||||
sec_out32(®s->jrcfg1, reg_val);
|
||||
|
||||
VERBOSE("Disable interrupts on JR\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include "caam.h"
|
||||
#include <common/debug.h>
|
||||
#include "jobdesc.h"
|
||||
#include "nxp_timer.h"
|
||||
#include "sec_hw_specific.h"
|
||||
#include "sec_jr_driver.h"
|
||||
|
||||
|
||||
/* Job rings used for communication with SEC HW */
|
||||
struct sec_job_ring_t g_job_rings[MAX_SEC_JOB_RINGS];
|
||||
|
||||
/* The current state of SEC user space driver */
|
||||
volatile sec_driver_state_t g_driver_state = SEC_DRIVER_STATE_IDLE;
|
||||
|
||||
int g_job_rings_no;
|
||||
|
||||
uint8_t ip_ring[SEC_DMA_MEM_INPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
uint8_t op_ring[SEC_DMA_MEM_OUTPUT_RING_SIZE] __aligned(CACHE_WRITEBACK_GRANULE);
|
||||
|
||||
void *init_job_ring(uint8_t jr_mode,
|
||||
uint16_t irq_coalescing_timer,
|
||||
uint8_t irq_coalescing_count,
|
||||
void *reg_base_addr, uint32_t irq_id)
|
||||
{
|
||||
struct sec_job_ring_t *job_ring = &g_job_rings[g_job_rings_no++];
|
||||
int ret = 0;
|
||||
|
||||
job_ring->register_base_addr = reg_base_addr;
|
||||
job_ring->jr_mode = jr_mode;
|
||||
job_ring->irq_fd = irq_id;
|
||||
|
||||
job_ring->input_ring = vtop(ip_ring);
|
||||
memset(job_ring->input_ring, 0, SEC_DMA_MEM_INPUT_RING_SIZE);
|
||||
|
||||
job_ring->output_ring = (struct sec_outring_entry *)vtop(op_ring);
|
||||
memset(job_ring->output_ring, 0, SEC_DMA_MEM_OUTPUT_RING_SIZE);
|
||||
|
||||
dsb();
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
flush_dcache_range((uintptr_t)(job_ring->input_ring),
|
||||
SEC_DMA_MEM_INPUT_RING_SIZE),
|
||||
flush_dcache_range((uintptr_t)(job_ring->output_ring),
|
||||
SEC_DMA_MEM_OUTPUT_RING_SIZE),
|
||||
|
||||
dmbsy();
|
||||
#endif
|
||||
/* Reset job ring in SEC hw and configure job ring registers */
|
||||
ret = hw_reset_job_ring(job_ring);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed to reset hardware job ring\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (jr_mode == SEC_NOTIFICATION_TYPE_IRQ) {
|
||||
/* Enable IRQ if driver work sin interrupt mode */
|
||||
ERROR("Enabling DONE IRQ generation on job ring\n");
|
||||
ret = jr_enable_irqs(job_ring);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed to enable irqs for job ring\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if ((irq_coalescing_timer != 0) || (irq_coalescing_count != 0)) {
|
||||
hw_job_ring_set_coalescing_param(job_ring,
|
||||
irq_coalescing_timer,
|
||||
irq_coalescing_count);
|
||||
|
||||
hw_job_ring_enable_coalescing(job_ring);
|
||||
job_ring->coalescing_en = 1;
|
||||
}
|
||||
|
||||
job_ring->jr_state = SEC_JOB_RING_STATE_STARTED;
|
||||
|
||||
return job_ring;
|
||||
}
|
||||
|
||||
int sec_release(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Validate driver state */
|
||||
if (g_driver_state == SEC_DRIVER_STATE_RELEASE) {
|
||||
ERROR("Driver release is already in progress");
|
||||
return SEC_DRIVER_RELEASE_IN_PROGRESS;
|
||||
}
|
||||
/* Update driver state */
|
||||
g_driver_state = SEC_DRIVER_STATE_RELEASE;
|
||||
|
||||
/* If any descriptors in flight , poll and wait
|
||||
* until all descriptors are received and silently discarded.
|
||||
*/
|
||||
|
||||
flush_job_rings();
|
||||
|
||||
for (i = 0; i < g_job_rings_no; i++) {
|
||||
shutdown_job_ring(&g_job_rings[i]);
|
||||
}
|
||||
g_job_rings_no = 0;
|
||||
g_driver_state = SEC_DRIVER_STATE_IDLE;
|
||||
|
||||
return SEC_SUCCESS;
|
||||
}
|
||||
|
||||
int sec_jr_lib_init(void)
|
||||
{
|
||||
/* Validate driver state */
|
||||
if (g_driver_state != SEC_DRIVER_STATE_IDLE) {
|
||||
ERROR("Driver already initialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(g_job_rings, 0, sizeof(g_job_rings));
|
||||
g_job_rings_no = 0;
|
||||
|
||||
/* Update driver state */
|
||||
g_driver_state = SEC_DRIVER_STATE_STARTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dequeue_jr(void *job_ring_handle, int32_t limit)
|
||||
{
|
||||
int ret = 0;
|
||||
int notified_descs_no = 0;
|
||||
struct sec_job_ring_t *job_ring = (sec_job_ring_t *) job_ring_handle;
|
||||
uint64_t start_time;
|
||||
|
||||
/* Validate driver state */
|
||||
if (g_driver_state != SEC_DRIVER_STATE_STARTED) {
|
||||
ERROR("Driver release in progress or driver not initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Validate input arguments */
|
||||
if (job_ring == NULL) {
|
||||
ERROR("job_ring_handle is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
if (((limit == 0) || (limit > SEC_JOB_RING_SIZE))) {
|
||||
ERROR("Invalid limit parameter configuration\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
VERBOSE("JR Polling limit[%d]\n", limit);
|
||||
|
||||
/* Poll job ring
|
||||
* If limit < 0 -> poll JR until no more notifications are available.
|
||||
* If limit > 0 -> poll JR until limit is reached.
|
||||
*/
|
||||
|
||||
start_time = get_timer_val(0);
|
||||
|
||||
while (notified_descs_no == 0) {
|
||||
/* Run hw poll job ring */
|
||||
notified_descs_no = hw_poll_job_ring(job_ring, limit);
|
||||
if (notified_descs_no < 0) {
|
||||
ERROR("Error polling SEC engine job ring ");
|
||||
return notified_descs_no;
|
||||
}
|
||||
VERBOSE("Jobs notified[%d]. ", notified_descs_no);
|
||||
|
||||
if (get_timer_val(start_time) >= CAAM_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (job_ring->jr_mode == SEC_NOTIFICATION_TYPE_IRQ) {
|
||||
|
||||
/* Always enable IRQ generation when in pure IRQ mode */
|
||||
ret = jr_enable_irqs(job_ring);
|
||||
if (ret != 0) {
|
||||
ERROR("Failed to enable irqs for job ring");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return notified_descs_no;
|
||||
}
|
||||
|
||||
int enq_jr_desc(void *job_ring_handle, struct job_descriptor *jobdescr)
|
||||
{
|
||||
struct sec_job_ring_t *job_ring;
|
||||
|
||||
job_ring = (struct sec_job_ring_t *)job_ring_handle;
|
||||
|
||||
/* Validate driver state */
|
||||
if (g_driver_state != SEC_DRIVER_STATE_STARTED) {
|
||||
ERROR("Driver release in progress or driver not initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check job ring state */
|
||||
if (job_ring->jr_state != SEC_JOB_RING_STATE_STARTED) {
|
||||
ERROR("Job ring is currently resetting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SEC_JOB_RING_IS_FULL(job_ring->pidx, job_ring->cidx,
|
||||
SEC_JOB_RING_SIZE, SEC_JOB_RING_SIZE)) {
|
||||
ERROR("Job ring is full\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set ptr in input ring to current descriptor */
|
||||
sec_write_addr(&job_ring->input_ring[job_ring->pidx],
|
||||
(phys_addr_t) vtop(jobdescr->desc));
|
||||
|
||||
dsb();
|
||||
|
||||
#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
|
||||
flush_dcache_range((uintptr_t)(&job_ring->input_ring[job_ring->pidx]),
|
||||
sizeof(phys_addr_t));
|
||||
|
||||
inv_dcache_range((uintptr_t)(&job_ring->output_ring[job_ring->cidx]),
|
||||
sizeof(struct sec_outring_entry));
|
||||
dmbsy();
|
||||
#endif
|
||||
/* Notify HW that a new job is enqueued */
|
||||
hw_enqueue_desc_on_job_ring(
|
||||
(struct jobring_regs *)job_ring->register_base_addr, 1);
|
||||
|
||||
/* increment the producer index for the current job ring */
|
||||
job_ring->pidx = SEC_CIRCULAR_COUNTER(job_ring->pidx,
|
||||
SEC_JOB_RING_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue