Browse Source
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: I02bcfce68143b8630e1833a74c4b126972f4323dpull/1942/head
Pankaj Gupta
4 years ago
19 changed files with 3459 additions and 0 deletions
@ -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