Ejemplo n.º 1
0
void tfm_thrd_context_switch(struct tfm_state_context_ext *ctxb,
                             struct tfm_thrd_ctx *prev,
                             struct tfm_thrd_ctx *next)
{
    /* Update latest context into the current thread context */
    tfm_memcpy(&prev->state_ctx.ctxb, ctxb, sizeof(*ctxb));
    /* Update background context with next thread's context */
    tfm_memcpy(ctxb, &next->state_ctx.ctxb, sizeof(next->state_ctx.ctxb));
    /* Set current thread indicator with next thread */
    CURR_THRD = next;
}
Ejemplo n.º 2
0
/**
 * \brief SVC handler for \ref psa_write.
 *
 * \param[in] args              Include all input arguments:
 *                              msg_handle, outvec_idx, buffer, num_bytes.
 *
 * \retval void                 Success
 * \retval "Does not return"    The call is invalid, one or more of the
 *                              following are true:
 * \arg                           msg_handle is invalid.
 * \arg                           msg_handle does not refer to a
 *                                \ref PSA_IPC_CALL message.
 * \arg                           outvec_idx is equal to or greater than
 *                                \ref PSA_MAX_IOVEC.
 * \arg                           The memory reference for buffer is invalid.
 * \arg                           The call attempts to write data past the end
 *                                of the client output vector.
 */
static void tfm_svcall_psa_write(uint32_t *args)
{
    psa_handle_t msg_handle;
    uint32_t outvec_idx;
    void *buffer = NULL;
    size_t num_bytes;
    struct tfm_msg_body_t *msg = NULL;

    TFM_ASSERT(args != NULL);
    msg_handle = (psa_handle_t)args[0];
    outvec_idx = args[1];
    buffer = (void *)args[2];
    num_bytes = (size_t)args[3];

    /* It is a fatal error if message handle is invalid */
    msg = tfm_spm_get_msg_from_handle(msg_handle);
    if (!msg) {
        tfm_panic();
    }

    /*
     * It is a fatal error if message handle does not refer to a PSA_IPC_CALL
     * message
     */
    if (msg->msg.type != PSA_IPC_CALL) {
        tfm_panic();
    }

    /*
     * It is a fatal error if outvec_idx is equal to or greater than
     * PSA_MAX_IOVEC
     */
    if (outvec_idx >= PSA_MAX_IOVEC) {
        tfm_panic();
    }

    /*
     * It is a fatal error if the call attempts to write data past the end of
     * the client output vector
     */
    if (num_bytes > msg->msg.out_size[outvec_idx] -
        msg->outvec[outvec_idx].len) {
        tfm_panic();
    }

    /*
     * Copy the service buffer to client outvecs. It is a fatal error
     * if the memory reference for buffer is invalid or not readable.
     */
    if (tfm_memory_check(buffer, num_bytes, false,
        TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
        tfm_panic();
    }

    tfm_memcpy(msg->outvec[outvec_idx].base + msg->outvec[outvec_idx].len,
               buffer, num_bytes);

    /* Update the write number */
    msg->outvec[outvec_idx].len += num_bytes;
}
Ejemplo n.º 3
0
/**
 * \brief SVC handler for \ref psa_get.
 *
 * \param[in] args              Include all input arguments: signal, msg.
 *
 * \retval PSA_SUCCESS          Success, *msg will contain the delivered
 *                              message.
 * \retval PSA_ERR_NOMSG        Message could not be delivered.
 * \retval "Does not return"    The call is invalid because one or more of the
 *                              following are true:
 * \arg                           signal has more than a single bit set.
 * \arg                           signal does not correspond to a RoT Service.
 * \arg                           The RoT Service signal is not currently
 *                                asserted.
 * \arg                           The msg pointer provided is not a valid memory
 *                                reference.
 */
static psa_status_t tfm_svcall_psa_get(uint32_t *args)
{
    psa_signal_t signal;
    psa_msg_t *msg = NULL;
    struct tfm_spm_service_t *service = NULL;
    struct tfm_msg_body_t *tmp_msg = NULL;
    struct tfm_spm_ipc_partition_t *partition = NULL;

    TFM_ASSERT(args != NULL);
    signal = (psa_signal_t)args[0];
    msg = (psa_msg_t *)args[1];

    /*
     * Only one message could be retrieved every time for psa_get(). It is a
     * fatal error if the input signal has more than a signal bit set.
     */
    if (tfm_bitcount(signal) != 1) {
        tfm_panic();
    }

    /*
     * Write the message to the service buffer. It is a fatal error if the
     * input msg pointer is not a valid memory reference or not read-write.
     */
    if (tfm_memory_check((void *)msg, sizeof(psa_msg_t),
        false, TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
        tfm_panic();
    }

    partition = tfm_spm_get_running_partition();
    if (!partition) {
        tfm_panic();
    }

    /*
     * It is a fatal error if the caller call psa_get() when no message has
     * been set. The caller must call this function after a RoT Service signal
     * is returned by psa_wait().
     */
    if (partition->signals == 0) {
        tfm_panic();
    }

    /*
     * It is a fatal error if the RoT Service signal is not currently asserted.
     */
    if ((partition->signals & signal) == 0) {
        tfm_panic();
    }

    /*
     * Get Rot service by signal from partition. It is a fatal error if geting
     * failed which mean the input signal is not correspond to a RoT service.
     */
    service = tfm_spm_get_service_by_signal(partition, signal);
    if (!service) {
        tfm_panic();
    }

    tmp_msg = tfm_msg_dequeue(&service->msg_queue);
    if (!tmp_msg) {
        return PSA_ERR_NOMSG;
    }

    tfm_memcpy(msg, &tmp_msg->msg, sizeof(psa_msg_t));

    /*
     * There may be mutiple messages for this RoT Service signal, do not clear
     * its mask until no remaining message.
     */
    if (tfm_msg_queue_is_empty(&service->msg_queue)) {
        partition->signals &= ~signal;
    }

    return PSA_SUCCESS;
}
Ejemplo n.º 4
0
/**
 * \brief SVC handler for \ref psa_read.
 *
 * \param[in] args              Include all input arguments:
 *                              msg_handle, invec_idx, buffer, num_bytes.
 *
 * \retval >0                   Number of bytes copied.
 * \retval 0                    There was no remaining data in this input
 *                              vector.
 * \retval "Does not return"    The call is invalid, one or more of the
 *                              following are true:
 * \arg                           msg_handle is invalid.
 * \arg                           msg_handle does not refer to a
 *                                \ref PSA_IPC_CALL message.
 * \arg                           invec_idx is equal to or greater than
 *                                \ref PSA_MAX_IOVEC.
 * \arg                           the memory reference for buffer is invalid or
 *                                not writable.
 */
static size_t tfm_svcall_psa_read(uint32_t *args)
{
    psa_handle_t msg_handle;
    uint32_t invec_idx;
    void *buffer = NULL;
    size_t num_bytes;
    size_t bytes;
    struct tfm_msg_body_t *msg = NULL;

    TFM_ASSERT(args != NULL);
    msg_handle = (psa_handle_t)args[0];
    invec_idx = args[1];
    buffer = (void *)args[2];
    num_bytes = (size_t)args[3];

    /* It is a fatal error if message handle is invalid */
    msg = tfm_spm_get_msg_from_handle(msg_handle);
    if (!msg) {
        tfm_panic();
    }

    /*
     * It is a fatal error if message handle does not refer to a PSA_IPC_CALL
     * message
     */
    if (msg->msg.type != PSA_IPC_CALL) {
        tfm_panic();
    }

    /*
     * It is a fatal error if invec_idx is equal to or greater than
     * PSA_MAX_IOVEC
     */
    if (invec_idx >= PSA_MAX_IOVEC) {
        tfm_panic();
    }

    /* There was no remaining data in this input vector */
    if (msg->msg.in_size[invec_idx] == 0) {
        return 0;
    }

    /*
     * Copy the client data to the service buffer. It is a fatal error
     * if the memory reference for buffer is invalid or not read-write.
     */
    if (tfm_memory_check(buffer, num_bytes, false,
        TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
        tfm_panic();
    }

    bytes = num_bytes > msg->msg.in_size[invec_idx] ?
                        msg->msg.in_size[invec_idx] : num_bytes;

    tfm_memcpy(buffer, msg->invec[invec_idx].base, bytes);

    /* There maybe some remaining data */
    msg->invec[invec_idx].base += bytes;
    msg->msg.in_size[invec_idx] -= bytes;

    return bytes;
}
Ejemplo n.º 5
0
psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller, uint32_t lr)
{
    psa_handle_t handle;
    psa_invec *inptr, invecs[PSA_MAX_IOVEC];
    psa_outvec *outptr, outvecs[PSA_MAX_IOVEC];
    size_t in_num, out_num;
    struct tfm_spm_service_t *service;
    struct tfm_msg_body_t *msg;
    int i;

    TFM_ASSERT(args != NULL);
    handle = (psa_handle_t)args[0];
    if (!ns_caller) {
        inptr = (psa_invec *)args[1];
        in_num = (size_t)args[2];
        outptr = (psa_outvec *)args[3];
        /*
         * 5th parameter is pushed at stack top before SVC, then PE hardware
         * stacks the execution context. The size of the context depends on
         * various settings:
         * - if FP is not used, 5th parameter is at 8th position counting
         *   from SP;
         * - if FP is used and FPCCR_S.TS is 0, 5th parameter is at 26th
         *   position counting from SP;
         * - if FP is used and FPCCR_S.TS is 1, 5th parameter is at 42th
         *   position counting from SP.
         */
         if (lr & EXC_RETURN_FPU_FRAME_BASIC) {
            out_num = (size_t)args[8];
#if defined (__FPU_USED) && (__FPU_USED == 1U)
         } else if (FPU->FPCCR & FPU_FPCCR_TS_Msk) {
            out_num = (size_t)args[42];
#endif
         } else {
            out_num = (size_t)args[26];
         }
    } else {
        /*
         * FixMe: From non-secure caller, vec and len are composed into a new
         * struct parameter. Need to extract them.
         */
        /*
         * Read parameters from the arguments. It is a fatal error if the
         * memory reference for buffer is invalid or not readable.
         */
        if (tfm_memory_check((void *)args[1], sizeof(uint32_t),
            ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
            tfm_panic();
        }
        if (tfm_memory_check((void *)args[2], sizeof(uint32_t),
            ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
            tfm_panic();
        }

        inptr = (psa_invec *)((psa_invec *)args[1])->base;
        in_num = ((psa_invec *)args[1])->len;
        outptr = (psa_outvec *)((psa_invec *)args[2])->base;
        out_num = ((psa_invec *)args[2])->len;
    }

    /* It is a fatal error if in_len + out_len > PSA_MAX_IOVEC. */
    if (in_num + out_num > PSA_MAX_IOVEC) {
        tfm_panic();
    }

    /* It is a fatal error if an invalid handle was passed. */
    service = tfm_spm_get_service_by_handle(handle);
    if (!service) {
        /* FixMe: Need to implement one mechanism to resolve this failure. */
        tfm_panic();
    }

    /*
     * Read client invecs from the wrap input vector. It is a fatal error
     * if the memory reference for the wrap input vector is invalid or not
     * readable.
     */
    if (tfm_memory_check((void *)inptr, in_num * sizeof(psa_invec),
        ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
        tfm_panic();
    }
    /*
     * Read client outvecs from the wrap output vector and will update the
     * actual length later. It is a fatal error if the memory reference for
     * the wrap output vector is invalid or not read-write.
     */
    if (tfm_memory_check((void *)outptr, out_num * sizeof(psa_outvec),
        ns_caller, TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
        tfm_panic();
    }

    tfm_memset(invecs, 0, sizeof(invecs));
    tfm_memset(outvecs, 0, sizeof(outvecs));

    /* Copy the address out to avoid TOCTOU attacks. */
    tfm_memcpy(invecs, inptr, in_num * sizeof(psa_invec));
    tfm_memcpy(outvecs, outptr, out_num * sizeof(psa_outvec));

    /*
     * For client input vector, it is a fatal error if the provided payload
     * memory reference was invalid or not readable.
     */
    for (i = 0; i < in_num; i++) {
        if (tfm_memory_check((void *)invecs[i].base, invecs[i].len,
            ns_caller, TFM_MEMORY_ACCESS_RO) != IPC_SUCCESS) {
            tfm_panic();
        }
    }
    /*
     * For client output vector, it is a fatal error if the provided payload
     * memory reference was invalid or not read-write.
     */
    for (i = 0; i < out_num; i++) {
        if (tfm_memory_check(outvecs[i].base, outvecs[i].len,
            ns_caller, TFM_MEMORY_ACCESS_RW) != IPC_SUCCESS) {
            tfm_panic();
        }
    }

    /*
     * FixMe: Need to check if the message is unrecognized by the RoT
     * Service or incorrectly formatted.
     */
    msg = tfm_spm_create_msg(service, handle, PSA_IPC_CALL, ns_caller, invecs,
                             in_num, outvecs, out_num, outptr);
    if (!msg) {
        /* FixMe: Need to implement one mechanism to resolve this failure. */
        tfm_panic();
    }

    /*
     * Send message and wake up the SP who is waiting on message queue,
     * and scheduler triggered
     */
    if (tfm_spm_send_event(service, msg) != IPC_SUCCESS) {
        /* FixMe: Need to refine failure process here. */
        tfm_panic();
    }
    return PSA_SUCCESS;
}