blob: 13c638c38921b0fad81853faf48450b17d00a436 [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 Deprezbe671112019-10-28 09:07:50 +00009#include "spmd_private.h"
10
Olivier Deprez33e44122020-04-16 17:54:27 +020011struct spmd_pm_secondary_ep_t {
12 uintptr_t entry_point;
13 uintptr_t context;
14 bool locked;
15};
16
17static struct spmd_pm_secondary_ep_t spmd_pm_secondary_ep[PLATFORM_CORE_COUNT];
18
19/*******************************************************************************
20 * spmd_pm_secondary_core_set_ep
21 ******************************************************************************/
22int32_t spmd_pm_secondary_core_set_ep(uint64_t mpidr, uintptr_t entry_point,
23 uint64_t context)
24{
25 int id = plat_core_pos_by_mpidr(mpidr);
26
27 if ((id < 0) || (id >= PLATFORM_CORE_COUNT)) {
28 ERROR("%s inconsistent MPIDR (%llx)\n", __func__, mpidr);
29 return -EINVAL;
30 }
31
32 if (spmd_pm_secondary_ep[id].locked) {
33 ERROR("%s entry locked (%llx)\n", __func__, mpidr);
34 return -EINVAL;
35 }
36
37 /*
38 * Check entry_point address is a PA within
39 * load_address <= entry_point < load_address + binary_size
40 */
41 if (!spmd_check_address_in_binary_image(entry_point)) {
42 ERROR("%s entry point is not within image boundaries (%llx)\n",
43 __func__, mpidr);
44 return -EINVAL;
45 }
46
47 /* Fill new entry to corresponding secondary core id and lock it */
48 spmd_pm_secondary_ep[id].entry_point = entry_point;
49 spmd_pm_secondary_ep[id].context = context;
50 spmd_pm_secondary_ep[id].locked = true;
51
52 VERBOSE("%s %d %llx %lx %llx\n",
53 __func__, id, mpidr, entry_point, context);
54
55 return 0;
56}
57
Olivier Deprezbe671112019-10-28 09:07:50 +000058/*******************************************************************************
59 * This CPU has been turned on. Enter SPMC to initialise S-EL1 or S-EL2. As part
60 * of the SPMC initialization path, they will initialize any SPs that they
61 * manage. Entry into SPMC is done after initialising minimal architectural
62 * state that guarantees safe execution.
63 ******************************************************************************/
64static void spmd_cpu_on_finish_handler(u_register_t unused)
65{
66 unsigned int linear_id = plat_my_core_pos();
67 spmd_spm_core_context_t *ctx = spmd_get_context();
68 int rc;
69
70 assert(ctx->state != SPMC_STATE_ON);
71
72 rc = spmd_spm_core_sync_entry(ctx);
73 if (rc != 0) {
74 ERROR("SPMC initialisation failed (%d) on CPU%u\n", rc,
75 linear_id);
76 ctx->state = SPMC_STATE_OFF;
77 return;
78 }
79
80 ctx->state = SPMC_STATE_ON;
81}
82
83/*******************************************************************************
84 * Structure populated by the SPM Dispatcher to perform any bookkeeping before
85 * PSCI executes a power mgmt. operation.
86 ******************************************************************************/
87const spd_pm_ops_t spmd_pm = {
88 .svc_on_finish = spmd_cpu_on_finish_handler,
89};