blob: ecafa878ba5f7da26c3703750b08d837d80c1236 [file] [log] [blame]
Olivier Deprezbe671112019-10-28 09:07:50 +00001/*
Olivier Deprezeae45962021-01-19 15:06:47 +01002 * Copyright (c) 2020-2021, ARM Limited and Contributors. All rights reserved.
Olivier Deprezbe671112019-10-28 09:07:50 +00003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
Olivier Deprez33e44122020-04-16 17:54:27 +02008#include <errno.h>
Olivier Deprezc7631a52020-03-23 09:53:06 +01009#include <lib/el3_runtime/context_mgmt.h>
Olivier Deprezbe671112019-10-28 09:07:50 +000010#include "spmd_private.h"
11
Olivier Deprezeae45962021-01-19 15:06:47 +010012static struct {
13 bool secondary_ep_locked;
14 uintptr_t secondary_ep;
15} g_spmd_pm;
16
Olivier Deprez33e44122020-04-16 17:54:27 +020017/*******************************************************************************
Olivier Deprezc7631a52020-03-23 09:53:06 +010018 * spmd_build_spmc_message
19 *
20 * Builds an SPMD to SPMC direct message request.
21 ******************************************************************************/
22static void spmd_build_spmc_message(gp_regs_t *gpregs, unsigned long long message)
23{
24 write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32);
25 write_ctx_reg(gpregs, CTX_GPREG_X1,
26 (SPMD_DIRECT_MSG_ENDPOINT_ID << FFA_DIRECT_MSG_SOURCE_SHIFT) |
27 spmd_spmc_id_get());
28 write_ctx_reg(gpregs, CTX_GPREG_X2, FFA_PARAM_MBZ);
29 write_ctx_reg(gpregs, CTX_GPREG_X3, message);
30}
31
32/*******************************************************************************
Olivier Deprezeae45962021-01-19 15:06:47 +010033 * spmd_pm_secondary_ep_register
Olivier Deprez33e44122020-04-16 17:54:27 +020034 ******************************************************************************/
Olivier Deprezeae45962021-01-19 15:06:47 +010035int spmd_pm_secondary_ep_register(uintptr_t entry_point)
Olivier Deprez33e44122020-04-16 17:54:27 +020036{
Olivier Deprezeae45962021-01-19 15:06:47 +010037 if (g_spmd_pm.secondary_ep_locked == true) {
38 return FFA_ERROR_INVALID_PARAMETER;
Olivier Deprez33e44122020-04-16 17:54:27 +020039 }
40
Olivier Deprez33e44122020-04-16 17:54:27 +020041 /*
42 * Check entry_point address is a PA within
43 * load_address <= entry_point < load_address + binary_size
44 */
45 if (!spmd_check_address_in_binary_image(entry_point)) {
Olivier Deprezeae45962021-01-19 15:06:47 +010046 ERROR("%s entry point is not within image boundaries\n",
47 __func__);
48 return FFA_ERROR_INVALID_PARAMETER;
Olivier Deprez33e44122020-04-16 17:54:27 +020049 }
50
Olivier Deprezeae45962021-01-19 15:06:47 +010051 g_spmd_pm.secondary_ep = entry_point;
52 g_spmd_pm.secondary_ep_locked = true;
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020053
Olivier Deprezeae45962021-01-19 15:06:47 +010054 VERBOSE("%s %lx\n", __func__, entry_point);
Olivier Deprez33e44122020-04-16 17:54:27 +020055
56 return 0;
57}
58
Olivier Deprezbe671112019-10-28 09:07:50 +000059/*******************************************************************************
60 * This CPU has been turned on. Enter SPMC to initialise S-EL1 or S-EL2. As part
61 * of the SPMC initialization path, they will initialize any SPs that they
62 * manage. Entry into SPMC is done after initialising minimal architectural
63 * state that guarantees safe execution.
64 ******************************************************************************/
65static void spmd_cpu_on_finish_handler(u_register_t unused)
66{
Olivier Deprezc7631a52020-03-23 09:53:06 +010067 entry_point_info_t *spmc_ep_info = spmd_spmc_ep_info_get();
Olivier Deprezbe671112019-10-28 09:07:50 +000068 spmd_spm_core_context_t *ctx = spmd_get_context();
Olivier Deprezc7631a52020-03-23 09:53:06 +010069 unsigned int linear_id = plat_my_core_pos();
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020070 uint64_t rc;
Olivier Deprezbe671112019-10-28 09:07:50 +000071
Olivier Deprezc7631a52020-03-23 09:53:06 +010072 assert(ctx != NULL);
Olivier Deprezbe671112019-10-28 09:07:50 +000073 assert(ctx->state != SPMC_STATE_ON);
Olivier Deprezc7631a52020-03-23 09:53:06 +010074 assert(spmc_ep_info != NULL);
75
76 /*
Olivier Deprezeae45962021-01-19 15:06:47 +010077 * Leave the possibility that the SPMC does not call
78 * FFA_SECONDARY_EP_REGISTER in which case re-use the
79 * primary core address for booting secondary cores.
Olivier Deprezc7631a52020-03-23 09:53:06 +010080 */
Olivier Deprezeae45962021-01-19 15:06:47 +010081 if (g_spmd_pm.secondary_ep_locked == true) {
82 spmc_ep_info->pc = g_spmd_pm.secondary_ep;
Olivier Deprezc7631a52020-03-23 09:53:06 +010083 }
84
Olivier Deprezc7631a52020-03-23 09:53:06 +010085 cm_setup_context(&ctx->cpu_ctx, spmc_ep_info);
Olivier Deprezc7631a52020-03-23 09:53:06 +010086
87 /* Mark CPU as initiating ON operation */
88 ctx->state = SPMC_STATE_ON_PENDING;
Olivier Deprezbe671112019-10-28 09:07:50 +000089
90 rc = spmd_spm_core_sync_entry(ctx);
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020091 if (rc != 0ULL) {
92 ERROR("%s failed (%llu) on CPU%u\n", __func__, rc,
Olivier Deprezc7631a52020-03-23 09:53:06 +010093 linear_id);
Olivier Deprezbe671112019-10-28 09:07:50 +000094 ctx->state = SPMC_STATE_OFF;
95 return;
96 }
97
98 ctx->state = SPMC_STATE_ON;
Olivier Deprezc7631a52020-03-23 09:53:06 +010099
100 VERBOSE("CPU %u on!\n", linear_id);
101}
102
103/*******************************************************************************
104 * spmd_cpu_off_handler
105 ******************************************************************************/
106static int32_t spmd_cpu_off_handler(u_register_t unused)
107{
108 spmd_spm_core_context_t *ctx = spmd_get_context();
109 unsigned int linear_id = plat_my_core_pos();
Olivier Deprez73ef0dc2020-06-19 15:33:41 +0200110 int64_t rc;
Olivier Deprezc7631a52020-03-23 09:53:06 +0100111
112 assert(ctx != NULL);
113 assert(ctx->state != SPMC_STATE_OFF);
114
Olivier Deprezc7631a52020-03-23 09:53:06 +0100115 /* Build an SPMD to SPMC direct message request. */
116 spmd_build_spmc_message(get_gpregs_ctx(&ctx->cpu_ctx), PSCI_CPU_OFF);
117
118 rc = spmd_spm_core_sync_entry(ctx);
Olivier Deprez73ef0dc2020-06-19 15:33:41 +0200119 if (rc != 0ULL) {
120 ERROR("%s failed (%llu) on CPU%u\n", __func__, rc, linear_id);
Olivier Deprezc7631a52020-03-23 09:53:06 +0100121 }
122
Olivier Deprezeae45962021-01-19 15:06:47 +0100123 /* Expect a direct message response from the SPMC. */
124 u_register_t ffa_resp_func = read_ctx_reg(get_gpregs_ctx(&ctx->cpu_ctx),
125 CTX_GPREG_X0);
126 if (ffa_resp_func != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
127 ERROR("%s invalid SPMC response (%lx).\n",
128 __func__, ffa_resp_func);
129 return -EINVAL;
130 }
Olivier Deprezc7631a52020-03-23 09:53:06 +0100131
Olivier Deprezc7631a52020-03-23 09:53:06 +0100132 ctx->state = SPMC_STATE_OFF;
133
134 VERBOSE("CPU %u off!\n", linear_id);
135
136 return 0;
Olivier Deprezbe671112019-10-28 09:07:50 +0000137}
138
139/*******************************************************************************
140 * Structure populated by the SPM Dispatcher to perform any bookkeeping before
141 * PSCI executes a power mgmt. operation.
142 ******************************************************************************/
143const spd_pm_ops_t spmd_pm = {
144 .svc_on_finish = spmd_cpu_on_finish_handler,
Olivier Deprezc7631a52020-03-23 09:53:06 +0100145 .svc_off = spmd_cpu_off_handler
Olivier Deprezbe671112019-10-28 09:07:50 +0000146};