summaryrefslogtreecommitdiff
path: root/drivers/mxc/security/mxc_scc_internals.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mxc/security/mxc_scc_internals.h')
-rw-r--r--drivers/mxc/security/mxc_scc_internals.h498
1 files changed, 498 insertions, 0 deletions
diff --git a/drivers/mxc/security/mxc_scc_internals.h b/drivers/mxc/security/mxc_scc_internals.h
new file mode 100644
index 000000000000..fddb0da9a4a5
--- /dev/null
+++ b/drivers/mxc/security/mxc_scc_internals.h
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2004-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#ifndef __MXC_SCC_INTERNALS_H__
+#define __MXC_SCC_INTERNALS_H__
+
+/*!
+ * @file mxc_scc_internals.h
+ *
+ * @brief This is intended to be the file which contains most or all of the code or
+ * changes need to port the driver. It also includes other definitions needed
+ * by the driver.
+ *
+ * This header file should only ever be included by scc_driver.c
+ *
+ * Compile-time flags minimally needed:
+ *
+ * @li Some sort of platform flag.
+ * @li Some start-of-SCC consideration, such as SCC_BASE_ADDR
+ *
+ * Some changes which could be made when porting this driver:
+ * #SCC_SPIN_COUNT
+ *
+ * @ingroup MXCSCC
+ */
+#if 0
+#include <linux/version.h> /* Current version Linux kernel */
+#include <linux/module.h> /* Basic support for loadable modules,
+ printk */
+#include <linux/init.h> /* module_init, module_exit */
+#include <linux/kernel.h> /* General kernel system calls */
+#include <linux/sched.h> /* for interrupt.h */
+#include <linux/spinlock.h>
+#include <linux/interrupt.h> /* IRQ / interrupt definitions */
+#include <linux/io.h> /* ioremap() */
+#endif
+#include <linux/mxc_scc_driver.h>
+
+/* Get handle on certain per-platform symbols */
+#ifdef TAHITI
+#include <asm/arch/mx2.h>
+
+/*
+ * Mark the SCC as always there... as Tahiti is not officially supported by
+ * driver. Porting opportunity.
+ */
+#define SCC_ENABLED() (1)
+
+#elif defined(MXC)
+
+#include <mach/iim.h>
+#include <mach/mxc_scc.h>
+
+#ifdef SCC_FUSE
+
+/*
+ * This macro is used to determine whether the SCC is enabled/available
+ * on the platform. This macro may need to be ported.
+ */
+#define SCC_ENABLED() ((SCC_FUSE & MXC_IIMHWV1_SCC_DISABLE) == 0)
+
+#else
+
+#define SCC_ENABLED() (1)
+
+#endif
+
+#else /* neither TAHITI nor MXC */
+
+#error Do not understand target architecture
+
+#endif /* TAHITI */
+
+/* Temporarily define compile-time flags to make Doxygen happy. */
+#ifdef DOXYGEN_HACK
+/*! @addtogroup scccompileflags */
+/*! @{ */
+
+/*! @def NO_SMN_INTERRUPT
+ * The SMN interrupt is not wired to the CPU at all.
+ */
+#define NO_SMN_INTERRUPT
+
+/*!
+ * Register an interrupt handler for the SMN as well as
+ * the SCM. In some implementations, the SMN is not connected at all (see
+ * #NO_SMN_INTERRUPT), and in others, it is on the same interrupt line as the
+ * SCM. When defining this flag, the SMN interrupt should be on a separate
+ * line from the SCM interrupt.
+ */
+
+#define USE_SMN_INTERRUPT
+
+/*!
+ * Turn on generation of run-time operational, debug, and error messages
+ */
+#define SCC_DEBUG
+
+/*!
+ * Turn on generation of run-time logging of access to the SCM and SMN
+ * registers.
+ */
+#define SCC_REGISTER_DEBUG
+
+/*!
+ * Turn on generation of run-time logging of access to the SCM Red and
+ * Black memories. Will only work if #SCC_REGISTER_DEBUG is also defined.
+ */
+#define SCC_RAM_DEBUG
+
+/*!
+ * If the driver finds the SCC in HEALTH_CHECK state, go ahead and
+ * run a quick ASC to bring it to SECURE state.
+ */
+#define SCC_BRINGUP
+
+/*!
+ * Expected to come from platform header files or compile command line.
+ * This symbol must be the address of the SCC
+ */
+#define SCC_BASE
+
+/*!
+ * This must be the interrupt line number of the SCM interrupt.
+ */
+#define INT_SCM
+
+/*!
+ * if #USE_SMN_INTERRUPT is defined, this must be the interrupt line number of
+ * the SMN interrupt.
+ */
+#define INT_SMN
+
+/*!
+ * Define the number of Stored Keys which the SCC driver will make available.
+ * Value shall be from 0 to 20. Default is zero (0).
+ */
+#define SCC_KEY_SLOTS
+
+/*!
+ * Make sure that this flag is defined if compiling for a Little-Endian
+ * platform. Linux Kernel builds provide this flag.
+ */
+#define __LITTLE_ENDIAN
+
+/*!
+ * Make sure that this flag is defined if compiling for a Big-Endian platform.
+ * Linux Kernel builds provide this flag.
+ */
+#define __BIG_ENDIAN
+
+/*!
+ * Read a 32-bit register value from a 'peripheral'. Standard Linux/Unix
+ * macro.
+ *
+ * @param offset Bus address of register to be read
+ *
+ * @return The value of the register
+ */
+#define readl(offset)
+
+/*!
+ * Write a 32-bit value to a register in a 'peripheral'. Standard Linux/Unix
+ * macro.
+ *
+ * @param value The 32-bit value to store
+ * @param offset Bus address of register to be written
+ *
+ * return (none)
+ */
+#define writel(value,offset)
+
+ /*! @} *//* end group scccompileflags */
+
+#endif /* DOXYGEN_HACK */
+
+/*!
+ * Define the number of Stored Keys which the SCC driver will make available.
+ * Value shall be from 0 to 20. Default is zero (0).
+ */
+#define SCC_KEY_SLOTS 20
+
+#ifndef SCC_KEY_SLOTS
+#define SCC_KEY_SLOTS 0
+
+#else
+
+#if (SCC_KEY_SLOTS < 0) || (SCC_KEY_SLOTS > 20)
+#error Bad value for SCC_KEY_SLOTS
+#endif
+
+/*!
+ * Maximum length of key/secret value which can be stored in SCC.
+ */
+#define SCC_MAX_KEY_SIZE 32
+
+/*!
+ * This is the size, in bytes, of each key slot, and therefore the maximum size
+ * of the wrapped key.
+ */
+#define SCC_KEY_SLOT_SIZE 32
+
+/*!
+ * This is the offset into each RAM of the base of the area which is
+ * not used for Stored Keys.
+ */
+#define SCM_NON_RESERVED_OFFSET (SCC_KEY_SLOTS * SCC_KEY_SLOT_SIZE)
+
+#endif
+
+/* These come for free with Linux, but may need to be set in a port. */
+#ifndef __BIG_ENDIAN
+#ifndef __LITTLE_ENDIAN
+#error One of __LITTLE_ENDIAN or __BIG_ENDIAN must be #defined
+#endif
+#else
+#ifdef __LITTLE_ENDIAN
+#error Exactly one of __LITTLE_ENDIAN or __BIG_ENDIAN must be #defined
+#endif
+#endif
+
+#ifndef SCC_CALLBACK_SIZE
+/*! The number of function pointers which can be stored in #scc_callbacks.
+ * Defaults to 4, can be overridden with compile-line argument.
+ */
+#define SCC_CALLBACK_SIZE 4
+#endif
+
+/*! Initial CRC value for CCITT-CRC calculation. */
+#define CRC_CCITT_START 0xFFFF
+
+#ifdef TAHITI
+
+/*!
+ * The SCC_BASE has to be SMN_BASE_ADDR on TAHITI, as the banks of
+ * registers are swapped in place.
+ */
+#define SCC_BASE SMN_BASE_ADDR
+
+/*! The interrupt number for the SCC (SCM only!) on Tahiti */
+#define INT_SCC_SCM 62
+
+/*! Tahiti does not have the SMN interrupt wired to the CPU. */
+#define NO_SMN_INTERRUPT
+
+#endif /* TAHITI */
+
+/*! Number of times to spin between polling of SCC while waiting for cipher
+ * or zeroizing function to complete. See also #SCC_CIPHER_MAX_POLL_COUNT. */
+#define SCC_SPIN_COUNT 1000
+
+/*! Number of times to polling SCC while waiting for cipher
+ * or zeroizing function to complete. See also #SCC_SPIN_COUNT. */
+#define SCC_CIPHER_MAX_POLL_COUNT 100
+
+/*!
+ * @def SCC_READ_REGISTER
+ * Read a 32-bit value from an SCC register. Macro which depends upon
+ * #scc_base. Linux readl()/writel() macros operate on 32-bit quantities, as
+ * do SCC register reads/writes.
+ *
+ * @param offset Register offset within SCC.
+ *
+ * @return The value from the SCC's register.
+ */
+#ifndef SCC_REGISTER_DEBUG
+#define SCC_READ_REGISTER(offset) __raw_readl(scc_base+(offset))
+#else
+#define SCC_READ_REGISTER(offset) dbg_scc_read_register(offset)
+#endif
+
+/*!
+ * Write a 32-bit value to an SCC register. Macro depends upon #scc_base.
+ * Linux readl()/writel() macros operate on 32-bit quantities, as do SCC
+ * register reads/writes.
+ *
+ * @param offset Register offset within SCC.
+ * @param value 32-bit value to store into the register
+ *
+ * @return (void)
+ */
+#ifndef SCC_REGISTER_DEBUG
+#define SCC_WRITE_REGISTER(offset,value) (void)__raw_writel(value, scc_base+(offset))
+#else
+#define SCC_WRITE_REGISTER(offset,value) dbg_scc_write_register(offset, value)
+#endif
+
+/*!
+ * Calculates the byte offset into a word
+ * @param bp The byte (char*) pointer
+ * @return The offset (0, 1, 2, or 3)
+ */
+#define SCC_BYTE_OFFSET(bp) ((uint32_t)(bp) % sizeof(uint32_t))
+
+/*!
+ * Converts (by rounding down) a byte pointer into a word pointer
+ * @param bp The byte (char*) pointer
+ * @return The word (uint32_t) as though it were an aligned (uint32_t*)
+ */
+#define SCC_WORD_PTR(bp) (((uint32_t)(bp)) & ~(sizeof(uint32_t)-1))
+
+/*!
+ * Determine number of bytes in an SCC block
+ *
+ * @return Bytes / block
+ */
+#define SCC_BLOCK_SIZE_BYTES() scc_configuration.block_size_bytes
+
+/*!
+ * Maximum number of additional bytes which may be added in CRC+padding mode.
+ */
+#define PADDING_BUFFER_MAX_BYTES (CRC_SIZE_BYTES + sizeof(scc_block_padding))
+
+/*!
+ * Shorthand (clearer, anyway) for number of bytes in a CRC.
+ */
+#define CRC_SIZE_BYTES (sizeof(crc_t))
+
+/*!
+ * The polynomial used in CCITT-CRC calculation
+ */
+#define CRC_POLYNOMIAL 0x1021
+
+/*!
+ * Calculate CRC on one byte of data
+ *
+ * @param[in,out] running_crc A value of type crc_t where CRC is kept. This
+ * must be an rvalue and an lvalue.
+ * @param[in] byte_value The byte (uint8_t, char) to be put in the CRC
+ *
+ * @return none
+ */
+#define CALC_CRC(byte_value,running_crc) { \
+ uint8_t data; \
+ data = (0xff&(byte_value)) ^ (running_crc >> 8); \
+ running_crc = scc_crc_lookup_table[data] ^ (running_crc << 8); \
+}
+
+/*! Value of 'beginning of padding' marker in driver-provided padding */
+#define SCC_DRIVER_PAD_CHAR 0x80
+
+/*! Name of the driver. Used (on Linux, anyway) when registering interrupts */
+#define SCC_DRIVER_NAME "scc"
+
+/* Port -- these symbols are defined in Linux 2.6 and later. They are defined
+ * here for backwards compatibility because this started life as a 2.4
+ * driver, and as a guide to portation to other platforms.
+ */
+
+#if !defined(LINUX_VERSION_CODE) || LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+#define irqreturn_t void /* Return type of an interrupt handler */
+
+#define IRQ_HANDLED /* Would be '1' for handled -- as in return IRQ_HANDLED; */
+
+#define IRQ_NONE /* would be '0' for not handled -- as in return IRQ_NONE; */
+
+#define IRQ_RETVAL(x) /* Return x==0 (not handled) or non-zero (handled) */
+
+#endif /* LINUX earlier than 2.5 */
+
+/* These are nice to have around */
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/*! Provide a typedef for the CRC which can be used in encrypt/decrypt */
+typedef uint16_t crc_t;
+
+/*! Gives high-level view of state of the SCC */
+enum scc_status {
+ SCC_STATUS_INITIAL, /*!< State of driver before ever checking */
+ SCC_STATUS_CHECKING, /*!< Transient state while driver loading */
+ SCC_STATUS_UNIMPLEMENTED, /*!< SCC is non-existent or unuseable */
+ SCC_STATUS_OK, /*!< SCC is in Secure or Default state */
+ SCC_STATUS_FAILED /*!< In Failed state */
+};
+
+/*!
+ * Information about a key slot.
+ */
+struct scc_key_slot {
+ uint64_t owner_id; /*!< Access control value. */
+ uint32_t length; /*!< Length of value in slot. */
+ uint32_t offset; /*!< Offset of value from start of each RAM. */
+ uint32_t status; /*!< 0 = unassigned, 1 = assigned. */
+};
+
+/* Forward-declare a number routines which are not part of user api */
+static int scc_init(void);
+static void scc_cleanup(void);
+
+/* Forward defines of internal functions */
+OS_DEV_ISR(scc_irq);
+/*! Perform callbacks registered by #scc_monitor_security_failure().
+ *
+ * Make sure callbacks only happen once... Since there may be some reason why
+ * the interrupt isn't generated, this routine could be called from base(task)
+ * level.
+ *
+ * One at a time, go through #scc_callbacks[] and call any non-null pointers.
+ */
+static void scc_perform_callbacks(void);
+static uint32_t copy_to_scc(const uint8_t * from, uint32_t to,
+ unsigned long count_bytes, uint16_t * crc);
+static uint32_t copy_from_scc(const uint32_t from, uint8_t * to,
+ unsigned long count_bytes, uint16_t * crc);
+static scc_return_t scc_strip_padding(uint8_t * from,
+ unsigned *count_bytes_stripped);
+static uint32_t scc_update_state(void);
+static void scc_init_ccitt_crc(void);
+static uint32_t scc_grab_config_values(void);
+static int setup_interrupt_handling(void);
+/*!
+ * Perform an encryption on the input. If @c verify_crc is true, a CRC must be
+ * calculated on the plaintext, and appended, with padding, before computing
+ * the ciphertext.
+ *
+ * @param[in] count_in_bytes Count of bytes of plaintext
+ * @param[in] data_in Pointer to the plaintext
+ * @param[in] scm_control Bit values for the SCM_CONTROL register
+ * @param[in,out] data_out Pointer for storing ciphertext
+ * @param[in] add_crc Flag for computing CRC - 0 no, else yes
+ * @param[in,out] count_out_bytes Number of bytes available at @c data_out
+ */
+static scc_return_t scc_encrypt(uint32_t count_in_bytes,
+ const uint8_t * data_in,
+ uint32_t scm_control, uint8_t * data_out,
+ int add_crc, unsigned long *count_out_bytes);
+
+/*!
+ * Perform a decryption on the input. If @c verify_crc is true, the last block
+ * (maybe the two last blocks) is special - it should contain a CRC and
+ * padding. These must be stripped and verified.
+ *
+ * @param[in] count_in_bytes Count of bytes of ciphertext
+ * @param[in] data_in Pointer to the ciphertext
+ * @param[in] scm_control Bit values for the SCM_CONTROL register
+ * @param[in,out] data_out Pointer for storing plaintext
+ * @param[in] verify_crc Flag for running CRC - 0 no, else yes
+ * @param[in,out] count_out_bytes Number of bytes available at @c data_out
+
+ */
+static scc_return_t scc_decrypt(uint32_t count_in_bytes,
+ const uint8_t * data_in,
+ uint32_t scm_control, uint8_t * data_out,
+ int verify_crc, unsigned long *count_out_bytes);
+
+static void scc_wait_completion(void);
+static int is_cipher_done(void);
+static scc_return_t check_register_accessible(uint32_t offset,
+ uint32_t smn_status,
+ uint32_t scm_status);
+static scc_return_t check_register_offset(uint32_t offset);
+
+#ifdef SCC_REGISTER_DEBUG
+static uint32_t dbg_scc_read_register(uint32_t offset);
+static void dbg_scc_write_register(uint32_t offset, uint32_t value);
+#endif
+
+/* For Linux kernel, export the API functions to other kernel modules */
+EXPORT_SYMBOL(scc_get_configuration);
+EXPORT_SYMBOL(scc_zeroize_memories);
+EXPORT_SYMBOL(scc_crypt);
+EXPORT_SYMBOL(scc_set_sw_alarm);
+EXPORT_SYMBOL(scc_monitor_security_failure);
+EXPORT_SYMBOL(scc_stop_monitoring_security_failure);
+EXPORT_SYMBOL(scc_read_register);
+EXPORT_SYMBOL(scc_write_register);
+EXPORT_SYMBOL(scc_alloc_slot);
+EXPORT_SYMBOL(scc_dealloc_slot);
+EXPORT_SYMBOL(scc_load_slot);
+EXPORT_SYMBOL(scc_encrypt_slot);
+EXPORT_SYMBOL(scc_decrypt_slot);
+EXPORT_SYMBOL(scc_get_slot_info);
+
+/* Tell Linux where to invoke driver at boot/module load time */
+module_init(scc_init);
+/* Tell Linux where to invoke driver on module unload */
+module_exit(scc_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Device Driver for SCC (SMN/SCM)");
+
+#endif /* __MXC_SCC_INTERNALS_H__ */