summaryrefslogtreecommitdiff
path: root/security/tf_driver/tf_comm_tz.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/tf_driver/tf_comm_tz.c')
-rw-r--r--security/tf_driver/tf_comm_tz.c911
1 files changed, 0 insertions, 911 deletions
diff --git a/security/tf_driver/tf_comm_tz.c b/security/tf_driver/tf_comm_tz.c
deleted file mode 100644
index 0f36209add7a..000000000000
--- a/security/tf_driver/tf_comm_tz.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/**
- * Copyright (c) 2011 Trusted Logic S.A.
- * All Rights Reserved.
- *
- * Copyright (C) 2011-2012 NVIDIA Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <asm/div64.h>
-#include <asm/system.h>
-#include <linux/version.h>
-#include <asm/cputype.h>
-#include <linux/interrupt.h>
-#include <linux/page-flags.h>
-#include <linux/pagemap.h>
-#include <linux/vmalloc.h>
-#include <linux/jiffies.h>
-
-#include <trace/events/nvsecurity.h>
-
-#include "tf_defs.h"
-#include "tf_comm.h"
-#include "tf_protocol.h"
-#include "tf_util.h"
-#include "tf_conn.h"
-
-/*
- * Structure common to all SMC operations
- */
-struct tf_generic_smc {
- u32 reg0;
- u32 reg1;
- u32 reg2;
- u32 reg3;
- u32 reg4;
-};
-
-/*----------------------------------------------------------------------------
- * SMC operations
- *----------------------------------------------------------------------------*/
-
-static inline void tf_smc_generic_call(
- struct tf_generic_smc *generic_smc)
-{
-#ifdef CONFIG_SMP
- long ret;
- cpumask_t saved_cpu_mask;
- cpumask_t local_cpu_mask = CPU_MASK_NONE;
-
- cpu_set(0, local_cpu_mask);
- cpumask_copy(&saved_cpu_mask, tsk_cpus_allowed(current));
- ret = sched_setaffinity(0, &local_cpu_mask);
- if (ret != 0)
- dprintk(KERN_ERR "sched_setaffinity #1 -> 0x%lX", ret);
-#endif
-
- trace_smc_generic_call(NVSEC_SMC_START);
-
- __asm__ volatile(
- "mov r0, %2\n"
- "mov r1, %3\n"
- "mov r2, %4\n"
- "mov r3, %5\n"
- "mov r4, %6\n"
- ".word 0xe1600070 @ SMC 0\n"
- "mov %0, r0\n"
- "mov %1, r1\n"
- : "=r" (generic_smc->reg0), "=r" (generic_smc->reg1)
- : "r" (generic_smc->reg0), "r" (generic_smc->reg1),
- "r" (generic_smc->reg2), "r" (generic_smc->reg3),
- "r" (generic_smc->reg4)
- : "r0", "r1", "r2", "r3", "r4");
-
- trace_smc_generic_call(NVSEC_SMC_DONE);
-
-#ifdef CONFIG_SMP
- ret = sched_setaffinity(0, &saved_cpu_mask);
- if (ret != 0)
- dprintk(KERN_ERR "sched_setaffinity #2 -> 0x%lX", ret);
-#endif
-}
-
-/*
- * Calls the get protocol version SMC.
- * Fills the parameter pProtocolVersion with the version number returned by the
- * SMC
- */
-static inline void tf_smc_get_protocol_version(u32 *protocol_version)
-{
- struct tf_generic_smc generic_smc;
-
- generic_smc.reg0 = TF_SMC_GET_PROTOCOL_VERSION;
- generic_smc.reg1 = 0;
- generic_smc.reg2 = 0;
- generic_smc.reg3 = 0;
- generic_smc.reg4 = 0;
-
- tf_smc_generic_call(&generic_smc);
- *protocol_version = generic_smc.reg1;
-}
-
-
-/*
- * Calls the init SMC with the specified parameters.
- * Returns zero upon successful completion, or an appropriate error code upon
- * failure.
- */
-static inline int tf_smc_init(u32 shared_page_descriptor)
-{
- struct tf_generic_smc generic_smc;
-
- generic_smc.reg0 = TF_SMC_INIT;
- /* Descriptor for the layer 1 shared buffer */
- generic_smc.reg1 = shared_page_descriptor;
- generic_smc.reg2 = 0;
- generic_smc.reg3 = 0;
- generic_smc.reg4 = 0;
-
- tf_smc_generic_call(&generic_smc);
- if (generic_smc.reg0 != S_SUCCESS)
- printk(KERN_ERR "tf_smc_init:"
- " r0=0x%08X upon return (expected 0x%08X)!\n",
- generic_smc.reg0,
- S_SUCCESS);
-
- return generic_smc.reg0;
-}
-
-
-/*
- * Calls the reset irq SMC.
- */
-static inline void tf_smc_reset_irq(void)
-{
- struct tf_generic_smc generic_smc;
-
- generic_smc.reg0 = TF_SMC_RESET_IRQ;
- generic_smc.reg1 = 0;
- generic_smc.reg2 = 0;
- generic_smc.reg3 = 0;
- generic_smc.reg4 = 0;
-
- tf_smc_generic_call(&generic_smc);
-}
-
-
-/*
- * Calls the WAKE_UP SMC.
- * Returns zero upon successful completion, or an appropriate error code upon
- * failure.
- */
-static inline int tf_smc_wake_up(u32 l1_shared_buffer_descriptor,
- u32 shared_mem_start_offset,
- u32 shared_mem_size)
-{
- struct tf_generic_smc generic_smc;
-
- generic_smc.reg0 = TF_SMC_WAKE_UP;
- generic_smc.reg1 = shared_mem_start_offset;
- /* long form command */
- generic_smc.reg2 = shared_mem_size | 0x80000000;
- generic_smc.reg3 = l1_shared_buffer_descriptor;
- generic_smc.reg4 = 0;
-
- tf_smc_generic_call(&generic_smc);
-
- if (generic_smc.reg0 != S_SUCCESS)
- printk(KERN_ERR "tf_smc_wake_up:"
- " r0=0x%08X upon return (expected 0x%08X)!\n",
- generic_smc.reg0,
- S_SUCCESS);
-
- return generic_smc.reg0;
-}
-
-/*
- * Calls the N-Yield SMC.
- */
-static inline void tf_smc_nyield(void)
-{
- struct tf_generic_smc generic_smc;
-
- generic_smc.reg0 = TF_SMC_N_YIELD;
- generic_smc.reg1 = 0;
- generic_smc.reg2 = 0;
- generic_smc.reg3 = 0;
- generic_smc.reg4 = 0;
-
- tf_smc_generic_call(&generic_smc);
-}
-
-#ifdef CONFIG_SECURE_TRACES
-static void tf_print_secure_traces(struct tf_comm *comm)
-{
- spin_lock(&(comm->lock));
- if (comm->l1_buffer->traces_status != 0) {
- if (comm->l1_buffer->traces_status > 1)
- pr_info("TF : traces lost...\n");
- pr_info("TF : %s", comm->l1_buffer->traces_buffer);
- comm->l1_buffer->traces_status = 0;
- }
- spin_unlock(&(comm->lock));
-}
-#endif
-
-/* Yields the Secure World */
-int tf_schedule_secure_world(struct tf_comm *comm)
-{
- tf_set_current_time(comm);
-
- /* yield to the Secure World */
- tf_smc_nyield();
-
-#ifdef CONFIG_SECURE_TRACES
- tf_print_secure_traces(comm);
-#endif
-
- return 0;
-}
-
-/*
- * Returns the L2 descriptor for the specified user page.
- */
-
-#define L2_INIT_DESCRIPTOR_BASE (0x00000003)
-#define L2_INIT_DESCRIPTOR_V13_12_SHIFT (4)
-
-static u32 tf_get_l2init_descriptor(u32 vaddr)
-{
- struct page *page;
- u32 paddr;
- u32 descriptor;
-
- descriptor = L2_INIT_DESCRIPTOR_BASE;
-
- /* get physical address and add to descriptor */
- page = virt_to_page(vaddr);
- paddr = page_to_phys(page);
- descriptor |= (paddr & L2_DESCRIPTOR_ADDR_MASK);
-
- /* Add virtual address v[13:12] bits to descriptor */
- descriptor |= (DESCRIPTOR_V13_12_GET(vaddr)
- << L2_INIT_DESCRIPTOR_V13_12_SHIFT);
-
- descriptor |= tf_get_l2_descriptor_common(vaddr, &init_mm);
-
-
- return descriptor;
-}
-
-
-/*----------------------------------------------------------------------------
- * Power management
- *----------------------------------------------------------------------------*/
-
-/*
- * Free the memory used by the W3B buffer for the specified comm.
- * This function does nothing if no W3B buffer is allocated for the device.
- */
-static inline void tf_free_w3b(struct tf_comm *comm)
-{
- tf_cleanup_shared_memory(
- &(comm->w3b_cpt_alloc_context),
- &(comm->w3b_shmem_desc),
- 0);
-
- tf_release_coarse_page_table_allocator(&(comm->w3b_cpt_alloc_context));
-
- internal_vfree((void *)comm->w3b);
- comm->w3b = 0;
- comm->w3b_shmem_size = 0;
- clear_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags));
-}
-
-
-/*
- * Allocates the W3B buffer for the specified comm.
- * Returns zero upon successful completion, or an appropriate error code upon
- * failure.
- */
-static inline int tf_allocate_w3b(struct tf_comm *comm)
-{
- int error;
- u32 flags;
- u32 config_flag_s;
- u32 *w3b_descriptors;
- u32 w3b_descriptor_count;
- u32 w3b_current_size;
-
- config_flag_s = tf_read_reg32(&comm->l1_buffer->config_flag_s);
-
-retry:
- if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags))) == 0) {
- /*
- * Initialize the shared memory for the W3B
- */
- tf_init_coarse_page_table_allocator(
- &comm->w3b_cpt_alloc_context);
- } else {
- /*
- * The W3B is allocated but do we have to reallocate a bigger
- * one?
- */
- /* Check H bit */
- if ((config_flag_s & (1<<4)) != 0) {
- /* The size of the W3B may change after SMC_INIT */
- /* Read the current value */
- w3b_current_size = tf_read_reg32(
- &comm->l1_buffer->w3b_size_current_s);
- if (comm->w3b_shmem_size > w3b_current_size)
- return 0;
-
- tf_free_w3b(comm);
- goto retry;
- } else {
- return 0;
- }
- }
-
- /* check H bit */
- if ((config_flag_s & (1<<4)) != 0)
- /* The size of the W3B may change after SMC_INIT */
- /* Read the current value */
- comm->w3b_shmem_size = tf_read_reg32(
- &comm->l1_buffer->w3b_size_current_s);
- else
- comm->w3b_shmem_size = tf_read_reg32(
- &comm->l1_buffer->w3b_size_max_s);
-
- comm->w3b = (u32) internal_vmalloc(comm->w3b_shmem_size);
- if (comm->w3b == 0) {
- printk(KERN_ERR "tf_allocate_w3b():"
- " Out of memory for W3B buffer (%u bytes)!\n",
- (unsigned int)(comm->w3b_shmem_size));
- error = -ENOMEM;
- goto error;
- }
-
- /* initialize the w3b_shmem_desc structure */
- comm->w3b_shmem_desc.type = TF_SHMEM_TYPE_PM_HIBERNATE;
- INIT_LIST_HEAD(&(comm->w3b_shmem_desc.list));
-
- flags = (TF_SHMEM_TYPE_READ | TF_SHMEM_TYPE_WRITE);
-
- /* directly point to the L1 shared buffer W3B descriptors */
- w3b_descriptors = comm->l1_buffer->w3b_descriptors;
-
- /*
- * tf_fill_descriptor_table uses the following parameter as an
- * IN/OUT
- */
-
- error = tf_fill_descriptor_table(
- &(comm->w3b_cpt_alloc_context),
- &(comm->w3b_shmem_desc),
- comm->w3b,
- NULL,
- w3b_descriptors,
- comm->w3b_shmem_size,
- &(comm->w3b_shmem_offset),
- false,
- flags,
- &w3b_descriptor_count);
- if (error != 0) {
- printk(KERN_ERR "tf_allocate_w3b():"
- " tf_fill_descriptor_table failed with "
- "error code 0x%08x!\n",
- error);
- goto error;
- }
-
- set_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags));
-
- /* successful completion */
- return 0;
-
-error:
- tf_free_w3b(comm);
-
- return error;
-}
-
-/*
- * Perform a Secure World shutdown operation.
- * The routine does not return if the operation succeeds.
- * the routine returns an appropriate error code if
- * the operation fails.
- */
-int tf_pm_shutdown(struct tf_comm *comm)
-{
-#ifdef CONFIG_TFN
- /* this function is useless for the TEGRA product */
- return 0;
-#else
- int error;
- union tf_command command;
- union tf_answer answer;
-
- dprintk(KERN_INFO "tf_pm_shutdown()\n");
-
- memset(&command, 0, sizeof(command));
-
- command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT;
- command.header.message_size =
- (sizeof(struct tf_command_management) -
- sizeof(struct tf_command_header))/sizeof(u32);
-
- command.management.command = TF_MANAGEMENT_SHUTDOWN;
-
- error = tf_send_receive(
- comm,
- &command,
- &answer,
- NULL,
- false);
-
- if (error != 0) {
- dprintk(KERN_ERR "tf_pm_shutdown(): "
- "tf_send_receive failed (error %d)!\n",
- error);
- return error;
- }
-
-#ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT
- if (answer.header.error_code != 0)
- dprintk(KERN_ERR "tf_driver: shutdown failed.\n");
- else
- dprintk(KERN_INFO "tf_driver: shutdown succeeded.\n");
-#endif
-
- return answer.header.error_code;
-#endif
-}
-
-
-/*
- * Perform a Secure World hibernate operation.
- * The routine does not return if the operation succeeds.
- * the routine returns an appropriate error code if
- * the operation fails.
- */
-int tf_pm_hibernate(struct tf_comm *comm)
-{
-#ifdef CONFIG_TFN
- /* this function is useless for the TEGRA product */
- return 0;
-#else
- int error;
- union tf_command command;
- union tf_answer answer;
- u32 first_command;
- u32 first_free_command;
-
- dprintk(KERN_INFO "tf_pm_hibernate()\n");
-
- error = tf_allocate_w3b(comm);
- if (error != 0) {
- dprintk(KERN_ERR "tf_pm_hibernate(): "
- "tf_allocate_w3b failed (error %d)!\n",
- error);
- return error;
- }
-
- /*
- * As the polling thread is already hibernating, we
- * should send the message and receive the answer ourself
- */
-
- /* build the "prepare to hibernate" message */
- command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT;
- command.management.command = TF_MANAGEMENT_HIBERNATE;
- /* Long Form Command */
- command.management.shared_mem_descriptors[0] = 0;
- command.management.shared_mem_descriptors[1] = 0;
- command.management.w3b_size =
- comm->w3b_shmem_size | 0x80000000;
- command.management.w3b_start_offset =
- comm->w3b_shmem_offset;
- command.header.operation_id = (u32) &answer;
-
- tf_dump_command(&command);
-
- /* find a slot to send the message in */
-
- /* AFY: why not use the function tf_send_receive?? We are
- * duplicating a lot of subtle code here. And it's not going to be
- * tested because power management is currently not supported by the
- * secure world. */
- for (;;) {
- int queue_words_count, command_size;
-
- spin_lock(&(comm->lock));
-
- first_command = tf_read_reg32(
- &comm->l1_buffer->first_command);
- first_free_command = tf_read_reg32(
- &comm->l1_buffer->first_free_command);
-
- queue_words_count = first_free_command - first_command;
- command_size = command.header.message_size
- + sizeof(struct tf_command_header);
- if ((queue_words_count + command_size) <
- TF_N_MESSAGE_QUEUE_CAPACITY) {
- /* Command queue is not full */
- memcpy(&comm->l1_buffer->command_queue[
- first_free_command %
- TF_N_MESSAGE_QUEUE_CAPACITY],
- &command,
- command_size * sizeof(u32));
-
- tf_write_reg32(&comm->l1_buffer->first_free_command,
- first_free_command + command_size);
-
- spin_unlock(&(comm->lock));
- break;
- }
-
- spin_unlock(&(comm->lock));
- (void)tf_schedule_secure_world(comm);
- }
-
- /* now wait for the answer, dispatching other answers */
- while (1) {
- u32 first_answer;
- u32 first_free_answer;
-
- /* check all the answers */
- first_free_answer = tf_read_reg32(
- &comm->l1_buffer->first_free_answer);
- first_answer = tf_read_reg32(
- &comm->l1_buffer->first_answer);
-
- if (first_answer != first_free_answer) {
- int bFoundAnswer = 0;
-
- do {
- /* answer queue not empty */
- union tf_answer tmp_answer;
- struct tf_answer_header header;
- /* size of the command in words of 32bit */
- int command_size;
-
- /* get the message_size */
- memcpy(&header,
- &comm->l1_buffer->answer_queue[
- first_answer %
- TF_S_ANSWER_QUEUE_CAPACITY],
- sizeof(struct tf_answer_header));
- command_size = header.message_size +
- sizeof(struct tf_answer_header);
-
- /*
- * NOTE: message_size is the number of words
- * following the first word
- */
- memcpy(&tmp_answer,
- &comm->l1_buffer->answer_queue[
- first_answer %
- TF_S_ANSWER_QUEUE_CAPACITY],
- command_size * sizeof(u32));
-
- tf_dump_answer(&tmp_answer);
-
- if (tmp_answer.header.operation_id ==
- (u32) &answer) {
- /*
- * this is the answer to the "prepare to
- * hibernate" message
- */
- memcpy(&answer,
- &tmp_answer,
- command_size * sizeof(u32));
-
- bFoundAnswer = 1;
- tf_write_reg32(
- &comm->l1_buffer->first_answer,
- first_answer + command_size);
- break;
- } else {
- /*
- * this is a standard message answer,
- * dispatch it
- */
- struct tf_answer_struct
- *answerStructure;
-
- answerStructure =
- (struct tf_answer_struct *)
- tmp_answer.header.operation_id;
-
- memcpy(answerStructure->answer,
- &tmp_answer,
- command_size * sizeof(u32));
-
- answerStructure->answer_copied = true;
- }
-
- tf_write_reg32(
- &comm->l1_buffer->first_answer,
- first_answer + command_size);
- } while (first_answer != first_free_answer);
-
- if (bFoundAnswer)
- break;
- }
-
- /*
- * since the Secure World is at least running the "prepare to
- * hibernate" message, its timeout must be immediate So there is
- * no need to check its timeout and schedule() the current
- * thread
- */
- (void)tf_schedule_secure_world(comm);
- } /* while (1) */
-
- printk(KERN_INFO "tf_driver: hibernate.\n");
- return 0;
-#endif
-}
-
-
-/*
- * Perform a Secure World resume operation.
- * The routine returns once the Secure World is active again
- * or if an error occurs during the "resume" process
- */
-int tf_pm_resume(struct tf_comm *comm)
-{
-#ifdef CONFIG_TFN
- /* this function is useless for the TEGRA product */
- return 0;
-#else
- int error;
- u32 status;
-
- dprintk(KERN_INFO "tf_pm_resume()\n");
-
- error = tf_smc_wake_up(
- tf_get_l2init_descriptor((u32)comm->l1_buffer),
- comm->w3b_shmem_offset,
- comm->w3b_shmem_size);
-
- if (error != 0) {
- dprintk(KERN_ERR "tf_pm_resume(): "
- "tf_smc_wake_up failed (error %d)!\n",
- error);
- return error;
- }
-
- status = ((tf_read_reg32(&(comm->l1_buffer->status_s))
- & TF_STATUS_POWER_STATE_MASK)
- >> TF_STATUS_POWER_STATE_SHIFT);
-
- while ((status != TF_POWER_MODE_ACTIVE)
- && (status != TF_POWER_MODE_PANIC)) {
- tf_smc_nyield();
-
- status = ((tf_read_reg32(&(comm->l1_buffer->status_s))
- & TF_STATUS_POWER_STATE_MASK)
- >> TF_STATUS_POWER_STATE_SHIFT);
-
- /*
- * As this may last quite a while, call the kernel scheduler to
- * hand over CPU for other operations
- */
- schedule();
- }
-
- switch (status) {
- case TF_POWER_MODE_ACTIVE:
- break;
-
- case TF_POWER_MODE_PANIC:
- dprintk(KERN_ERR "tf_pm_resume(): "
- "Secure World POWER_MODE_PANIC!\n");
- return -EINVAL;
-
- default:
- dprintk(KERN_ERR "tf_pm_resume(): "
- "unexpected Secure World POWER_MODE (%d)!\n", status);
- return -EINVAL;
- }
-
- dprintk(KERN_INFO "tf_pm_resume() succeeded\n");
- return 0;
-#endif
-}
-
-/*----------------------------------------------------------------------------
- * Communication initialization and termination
- *----------------------------------------------------------------------------*/
-
-/*
- * Handles the software interrupts issued by the Secure World.
- */
-static irqreturn_t tf_soft_int_handler(int irq, void *dev_id)
-{
- struct tf_comm *comm = (struct tf_comm *) dev_id;
-
- if (comm->l1_buffer == NULL)
- return IRQ_NONE;
-
- if ((tf_read_reg32(&comm->l1_buffer->status_s) &
- TF_STATUS_P_MASK) == 0)
- /* interrupt not issued by the Trusted Foundations Software */
- return IRQ_NONE;
-
- tf_smc_reset_irq();
-
- /* signal N_SM_EVENT */
- wake_up(&comm->wait_queue);
-
- return IRQ_HANDLED;
-}
-
-/*
- * Initializes the communication with the Secure World.
- * The L1 shared buffer is allocated and the Secure World
- * is yielded for the first time.
- * returns successfuly once the communication with
- * the Secure World is up and running
- *
- * Returns 0 upon success or appropriate error code
- * upon failure
- */
-int tf_init(struct tf_comm *comm)
-{
- int error;
- struct page *buffer_page;
- u32 protocol_version;
-
- dprintk(KERN_INFO "tf_init()\n");
-
- spin_lock_init(&(comm->lock));
- comm->flags = 0;
- comm->l1_buffer = NULL;
- init_waitqueue_head(&(comm->wait_queue));
-
- /*
- * Check the Secure World protocol version is the expected one.
- */
- tf_smc_get_protocol_version(&protocol_version);
-
- if ((GET_PROTOCOL_MAJOR_VERSION(protocol_version))
- != TF_S_PROTOCOL_MAJOR_VERSION) {
- printk(KERN_ERR "tf_init():"
- " Unsupported Secure World Major Version "
- "(0x%02X, expected 0x%02X)!\n",
- GET_PROTOCOL_MAJOR_VERSION(protocol_version),
- TF_S_PROTOCOL_MAJOR_VERSION);
- error = -EIO;
- goto error;
- }
-
- /*
- * Register the software interrupt handler if required to.
- */
- if (comm->soft_int_irq != -1) {
- dprintk(KERN_INFO "tf_init(): "
- "Registering software interrupt handler (IRQ %d)\n",
- comm->soft_int_irq);
-
- error = request_irq(comm->soft_int_irq,
- tf_soft_int_handler,
- IRQF_SHARED,
- TF_DEVICE_BASE_NAME,
- comm);
- if (error != 0) {
- dprintk(KERN_ERR "tf_init(): "
- "request_irq failed for irq %d (error %d)\n",
- comm->soft_int_irq, error);
- goto error;
- }
- set_bit(TF_COMM_FLAG_IRQ_REQUESTED, &(comm->flags));
- }
-
- /*
- * Allocate and initialize the L1 shared buffer.
- */
- comm->l1_buffer = (void *) internal_get_zeroed_page(GFP_KERNEL);
- if (comm->l1_buffer == NULL) {
- printk(KERN_ERR "tf_init():"
- " get_zeroed_page failed for L1 shared buffer!\n");
- error = -ENOMEM;
- goto error;
- }
-
- /*
- * Ensure the page storing the L1 shared buffer is mapped.
- */
- buffer_page = virt_to_page(comm->l1_buffer);
- trylock_page(buffer_page);
-
- dprintk(KERN_INFO "tf_init(): "
- "L1 shared buffer allocated at virtual:%p, "
- "physical:%p (page:%p)\n",
- comm->l1_buffer,
- (void *)virt_to_phys(comm->l1_buffer),
- buffer_page);
-
- set_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags));
-
- /*
- * Init SMC
- */
- error = tf_smc_init(
- tf_get_l2init_descriptor((u32)comm->l1_buffer));
- if (error != S_SUCCESS) {
- dprintk(KERN_ERR "tf_init(): "
- "tf_smc_init failed (error 0x%08X)!\n",
- error);
- goto error;
- }
-
- /*
- * check whether the interrupts are actually enabled
- * If not, remove irq handler
- */
- if ((tf_read_reg32(&comm->l1_buffer->config_flag_s) &
- TF_CONFIG_FLAG_S) == 0) {
- if (test_and_clear_bit(TF_COMM_FLAG_IRQ_REQUESTED,
- &(comm->flags)) != 0) {
- dprintk(KERN_INFO "tf_init(): "
- "Interrupts not used, unregistering "
- "softint (IRQ %d)\n",
- comm->soft_int_irq);
-
- free_irq(comm->soft_int_irq, comm);
- }
- } else {
- if (test_bit(TF_COMM_FLAG_IRQ_REQUESTED,
- &(comm->flags)) == 0) {
- /*
- * Interrupts are enabled in the Secure World, but not
- * handled by driver
- */
- dprintk(KERN_ERR "tf_init(): "
- "soft_interrupt argument not provided\n");
- error = -EINVAL;
- goto error;
- }
- }
-
- /*
- * Successful completion.
- */
-
- /* yield for the first time */
- (void)tf_schedule_secure_world(comm);
-
- dprintk(KERN_INFO "tf_init(): Success\n");
- return S_SUCCESS;
-
-error:
- /*
- * Error handling.
- */
- dprintk(KERN_INFO "tf_init(): Failure (error %d)\n",
- error);
- tf_terminate(comm);
- return error;
-}
-
-
-/*
- * Attempt to terminate the communication with the Secure World.
- * The L1 shared buffer is freed.
- * Calling this routine terminates definitaly the communication
- * with the Secure World : there is no way to inform the Secure World of a new
- * L1 shared buffer to be used once it has been initialized.
- */
-void tf_terminate(struct tf_comm *comm)
-{
- dprintk(KERN_INFO "tf_terminate()\n");
-
- set_bit(TF_COMM_FLAG_TERMINATING, &(comm->flags));
-
- if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED,
- &(comm->flags))) != 0) {
- dprintk(KERN_INFO "tf_terminate(): "
- "Freeing the W3B buffer...\n");
- tf_free_w3b(comm);
- }
-
- if ((test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED,
- &(comm->flags))) != 0) {
- __clear_page_locked(virt_to_page(comm->l1_buffer));
- internal_free_page((unsigned long) comm->l1_buffer);
- }
-
- if ((test_bit(TF_COMM_FLAG_IRQ_REQUESTED,
- &(comm->flags))) != 0) {
- dprintk(KERN_INFO "tf_terminate(): "
- "Unregistering softint (IRQ %d)\n",
- comm->soft_int_irq);
- free_irq(comm->soft_int_irq, comm);
- }
-}