blob: 64ddbe5f4035e50c4fc1f333592f350c4306c888 [file] [log] [blame]
Olivier Deprezbe671112019-10-28 09:07:50 +00001/*
2 * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
3 *
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 Deprez33e44122020-04-16 17:54:27 +020012/*******************************************************************************
Olivier Deprezc7631a52020-03-23 09:53:06 +010013 * spmd_build_spmc_message
14 *
15 * Builds an SPMD to SPMC direct message request.
16 ******************************************************************************/
17static void spmd_build_spmc_message(gp_regs_t *gpregs, unsigned long long message)
18{
19 write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_MSG_SEND_DIRECT_REQ_SMC32);
20 write_ctx_reg(gpregs, CTX_GPREG_X1,
21 (SPMD_DIRECT_MSG_ENDPOINT_ID << FFA_DIRECT_MSG_SOURCE_SHIFT) |
22 spmd_spmc_id_get());
23 write_ctx_reg(gpregs, CTX_GPREG_X2, FFA_PARAM_MBZ);
24 write_ctx_reg(gpregs, CTX_GPREG_X3, message);
25}
26
27/*******************************************************************************
Olivier Deprez33e44122020-04-16 17:54:27 +020028 * spmd_pm_secondary_core_set_ep
29 ******************************************************************************/
Olivier Deprezc7631a52020-03-23 09:53:06 +010030int spmd_pm_secondary_core_set_ep(unsigned long long mpidr,
31 uintptr_t entry_point, unsigned long long context)
Olivier Deprez33e44122020-04-16 17:54:27 +020032{
33 int id = plat_core_pos_by_mpidr(mpidr);
34
35 if ((id < 0) || (id >= PLATFORM_CORE_COUNT)) {
36 ERROR("%s inconsistent MPIDR (%llx)\n", __func__, mpidr);
37 return -EINVAL;
38 }
39
Olivier Deprez33e44122020-04-16 17:54:27 +020040 /*
41 * Check entry_point address is a PA within
42 * load_address <= entry_point < load_address + binary_size
43 */
44 if (!spmd_check_address_in_binary_image(entry_point)) {
45 ERROR("%s entry point is not within image boundaries (%llx)\n",
46 __func__, mpidr);
47 return -EINVAL;
48 }
49
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020050 spmd_spm_core_context_t *ctx = spmd_get_context_by_mpidr(mpidr);
51 spmd_pm_secondary_ep_t *secondary_ep = &ctx->secondary_ep;
52 if (secondary_ep->locked) {
53 ERROR("%s entry locked (%llx)\n", __func__, mpidr);
54 return -EINVAL;
55 }
56
Olivier Deprez33e44122020-04-16 17:54:27 +020057 /* Fill new entry to corresponding secondary core id and lock it */
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020058 secondary_ep->entry_point = entry_point;
59 secondary_ep->context = context;
60 secondary_ep->locked = true;
Olivier Deprez33e44122020-04-16 17:54:27 +020061
62 VERBOSE("%s %d %llx %lx %llx\n",
63 __func__, id, mpidr, entry_point, context);
64
65 return 0;
66}
67
Olivier Deprezbe671112019-10-28 09:07:50 +000068/*******************************************************************************
69 * This CPU has been turned on. Enter SPMC to initialise S-EL1 or S-EL2. As part
70 * of the SPMC initialization path, they will initialize any SPs that they
71 * manage. Entry into SPMC is done after initialising minimal architectural
72 * state that guarantees safe execution.
73 ******************************************************************************/
74static void spmd_cpu_on_finish_handler(u_register_t unused)
75{
Olivier Deprezc7631a52020-03-23 09:53:06 +010076 entry_point_info_t *spmc_ep_info = spmd_spmc_ep_info_get();
Olivier Deprezbe671112019-10-28 09:07:50 +000077 spmd_spm_core_context_t *ctx = spmd_get_context();
Olivier Deprezc7631a52020-03-23 09:53:06 +010078 unsigned int linear_id = plat_my_core_pos();
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020079 uint64_t rc;
Olivier Deprezbe671112019-10-28 09:07:50 +000080
Olivier Deprezc7631a52020-03-23 09:53:06 +010081 assert(ctx != NULL);
Olivier Deprezbe671112019-10-28 09:07:50 +000082 assert(ctx->state != SPMC_STATE_ON);
Olivier Deprezc7631a52020-03-23 09:53:06 +010083 assert(spmc_ep_info != NULL);
84
85 /*
86 * TODO: this might require locking the spmc_ep_info structure,
87 * or provisioning one structure per cpu
88 */
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020089 if (ctx->secondary_ep.entry_point == 0UL) {
Olivier Deprezc7631a52020-03-23 09:53:06 +010090 goto exit;
91 }
92
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020093 spmc_ep_info->pc = ctx->secondary_ep.entry_point;
Olivier Deprezc7631a52020-03-23 09:53:06 +010094 cm_setup_context(&ctx->cpu_ctx, spmc_ep_info);
95 write_ctx_reg(get_gpregs_ctx(&ctx->cpu_ctx), CTX_GPREG_X0,
Olivier Deprez73ef0dc2020-06-19 15:33:41 +020096 ctx->secondary_ep.context);
Olivier Deprezc7631a52020-03-23 09:53:06 +010097
98 /* Mark CPU as initiating ON operation */
99 ctx->state = SPMC_STATE_ON_PENDING;
Olivier Deprezbe671112019-10-28 09:07:50 +0000100
101 rc = spmd_spm_core_sync_entry(ctx);
Olivier Deprez73ef0dc2020-06-19 15:33:41 +0200102 if (rc != 0ULL) {
103 ERROR("%s failed (%llu) on CPU%u\n", __func__, rc,
Olivier Deprezc7631a52020-03-23 09:53:06 +0100104 linear_id);
Olivier Deprezbe671112019-10-28 09:07:50 +0000105 ctx->state = SPMC_STATE_OFF;
106 return;
107 }
108
Olivier Deprezc7631a52020-03-23 09:53:06 +0100109exit:
Olivier Deprezbe671112019-10-28 09:07:50 +0000110 ctx->state = SPMC_STATE_ON;
Olivier Deprezc7631a52020-03-23 09:53:06 +0100111
112 VERBOSE("CPU %u on!\n", linear_id);
113}
114
115/*******************************************************************************
116 * spmd_cpu_off_handler
117 ******************************************************************************/
118static int32_t spmd_cpu_off_handler(u_register_t unused)
119{
120 spmd_spm_core_context_t *ctx = spmd_get_context();
121 unsigned int linear_id = plat_my_core_pos();
Olivier Deprez73ef0dc2020-06-19 15:33:41 +0200122 int64_t rc;
Olivier Deprezc7631a52020-03-23 09:53:06 +0100123
124 assert(ctx != NULL);
125 assert(ctx->state != SPMC_STATE_OFF);
126
Olivier Deprez73ef0dc2020-06-19 15:33:41 +0200127 if (ctx->secondary_ep.entry_point == 0UL) {
Olivier Deprezc7631a52020-03-23 09:53:06 +0100128 goto exit;
129 }
130
131 /* Build an SPMD to SPMC direct message request. */
132 spmd_build_spmc_message(get_gpregs_ctx(&ctx->cpu_ctx), PSCI_CPU_OFF);
133
134 rc = spmd_spm_core_sync_entry(ctx);
Olivier Deprez73ef0dc2020-06-19 15:33:41 +0200135 if (rc != 0ULL) {
136 ERROR("%s failed (%llu) on CPU%u\n", __func__, rc, linear_id);
Olivier Deprezc7631a52020-03-23 09:53:06 +0100137 }
138
139 /* TODO expect FFA_DIRECT_MSG_RESP returned from SPMC */
140
141exit:
142 ctx->state = SPMC_STATE_OFF;
143
144 VERBOSE("CPU %u off!\n", linear_id);
145
146 return 0;
Olivier Deprezbe671112019-10-28 09:07:50 +0000147}
148
149/*******************************************************************************
150 * Structure populated by the SPM Dispatcher to perform any bookkeeping before
151 * PSCI executes a power mgmt. operation.
152 ******************************************************************************/
153const spd_pm_ops_t spmd_pm = {
154 .svc_on_finish = spmd_cpu_on_finish_handler,
Olivier Deprezc7631a52020-03-23 09:53:06 +0100155 .svc_off = spmd_cpu_off_handler
Olivier Deprezbe671112019-10-28 09:07:50 +0000156};