blob: 81f15aed60da5906cd85c7dbf90eb0b3ec600f1e [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scull18834872018-10-12 11:48:09 +01003 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
Andrew Scull18834872018-10-12 11:48:09 +01007 */
8
Andrew Scull18c78fc2018-08-20 12:57:41 +01009#include "hf/cpu.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010010
Max Shvetsov9c0ebe42020-08-27 12:37:57 +010011#include "hf/arch/cache.h"
12
Andrew Scull18c78fc2018-08-20 12:57:41 +010013#include "hf/api.h"
Andrew Scull877ae4b2019-07-02 12:52:33 +010014#include "hf/check.h"
Andrew Scull18c78fc2018-08-20 12:57:41 +010015#include "hf/dlog.h"
Daniel Boulby7011b5a2024-10-15 18:27:26 +010016#include "hf/list.h"
J-Alves90d30d02025-05-09 16:04:48 +010017#include "hf/types.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010018
Andrew Scull19503262018-09-20 14:48:39 +010019#include "vmapi/hf/call.h"
20
Andrew Sculleed724b2019-09-12 09:57:19 +010021/**
22 * The stacks to be used by the CPUs.
23 *
Kathleen Capella4df55202022-12-01 15:39:26 -050024 * Defined in assembly for aarch64 in "src/arch/aarch64/stacks.S."
25 * Defined for host-based unit tests in "src/cpu_test.cc".
Andrew Sculleed724b2019-09-12 09:57:19 +010026 */
Kathleen Capella4df55202022-12-01 15:39:26 -050027
28extern char callstacks[MAX_CPUS][STACK_SIZE];
Andrew Sculleed724b2019-09-12 09:57:19 +010029
30/* NOLINTNEXTLINE(misc-redundant-expression) */
31static_assert((STACK_SIZE % PAGE_SIZE) == 0, "Keep each stack page aligned.");
32static_assert((PAGE_SIZE % STACK_ALIGN) == 0,
33 "Page alignment is too weak for the stack.");
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010034
Jose Marinho20713fa2019-08-07 15:42:07 +010035/**
Andrew Walbranb5ab43c2020-04-30 11:32:54 +010036 * Internal buffer used to store FF-A messages from a VM Tx. Its usage prevents
Jose Marinho20713fa2019-08-07 15:42:07 +010037 * TOCTOU issues while Hafnium performs actions on information that would
38 * otherwise be re-writable by the VM.
39 *
J-Alves90d30d02025-05-09 16:04:48 +010040 * Each buffer is owned by a single CPU. Can be used when handling FF-A
41 * messages, from and to the SPMC. E.g. FF-A memory sharing, indirect messaging
42 * and partition info get.
Jose Marinho20713fa2019-08-07 15:42:07 +010043 */
J-Alves90d30d02025-05-09 16:04:48 +010044alignas(PAGE_SIZE) static uint8_t cpu_message_buffer[MAX_CPUS][HF_MAILBOX_SIZE];
Jose Marinho20713fa2019-08-07 15:42:07 +010045
Mahesh Bireddy8ca57862020-01-07 13:43:21 +053046uint8_t *cpu_get_buffer(struct cpu *c)
Jose Marinho20713fa2019-08-07 15:42:07 +010047{
Mahesh Bireddy8ca57862020-01-07 13:43:21 +053048 size_t cpu_indx = cpu_index(c);
Jose Marinho20713fa2019-08-07 15:42:07 +010049
Mahesh Bireddy8ca57862020-01-07 13:43:21 +053050 CHECK(cpu_indx < MAX_CPUS);
51
52 return cpu_message_buffer[cpu_indx];
Jose Marinho20713fa2019-08-07 15:42:07 +010053}
54
Mahesh Bireddy8ca57862020-01-07 13:43:21 +053055uint32_t cpu_get_buffer_size(struct cpu *c)
Jose Marinho20713fa2019-08-07 15:42:07 +010056{
Mahesh Bireddy8ca57862020-01-07 13:43:21 +053057 size_t cpu_indx = cpu_index(c);
Jose Marinho20713fa2019-08-07 15:42:07 +010058
Mahesh Bireddy8ca57862020-01-07 13:43:21 +053059 CHECK(cpu_indx < MAX_CPUS);
60
61 return sizeof(cpu_message_buffer[cpu_indx]);
Jose Marinho20713fa2019-08-07 15:42:07 +010062}
63
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010064/* State of all supported CPUs. The stack of the first one is initialized. */
65struct cpu cpus[MAX_CPUS] = {
66 {
67 .is_on = 1,
Andrew Scullf3d45592018-09-20 14:30:22 +010068 .stack_bottom = &callstacks[0][STACK_SIZE],
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010069 },
70};
71
Max Shvetsov9c0ebe42020-08-27 12:37:57 +010072uint32_t cpu_count = 1;
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010073
Andrew Walbran4d3fa282019-06-26 13:31:15 +010074void cpu_module_init(const cpu_id_t *cpu_ids, size_t count)
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000075{
76 uint32_t i;
77 uint32_t j;
Andrew Walbran4d3fa282019-06-26 13:31:15 +010078 cpu_id_t boot_cpu_id = cpus[0].id;
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000079 bool found_boot_cpu = false;
80
81 cpu_count = count;
82
83 /*
84 * Initialize CPUs with the IDs from the configuration passed in. The
85 * CPUs after the boot CPU are initialized in reverse order. The boot
86 * CPU is initialized when it is found or in place of the last CPU if it
87 * is not found.
88 */
89 j = cpu_count;
90 for (i = 0; i < cpu_count; ++i) {
91 struct cpu *c;
Madhukar Pappireddyf658f5e2024-09-25 14:10:18 -050092 struct timer_pending_vcpu_list *timer_list;
Andrew Walbran4d3fa282019-06-26 13:31:15 +010093 cpu_id_t id = cpu_ids[i];
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000094
95 if (found_boot_cpu || id != boot_cpu_id) {
Andrew Scull48973982019-08-16 17:40:28 +010096 --j;
97 c = &cpus[j];
98 c->stack_bottom = &callstacks[j][STACK_SIZE];
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000099 } else {
100 found_boot_cpu = true;
101 c = &cpus[0];
Andrew Scull48973982019-08-16 17:40:28 +0100102 CHECK(c->stack_bottom == &callstacks[0][STACK_SIZE]);
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000103 }
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000104
Andrew Scull48973982019-08-16 17:40:28 +0100105 sl_init(&c->lock);
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000106 c->id = id;
Madhukar Pappireddyf658f5e2024-09-25 14:10:18 -0500107
108 timer_list = &c->pending_timer_vcpus_list;
109
110 /*
111 * Initialize the list of vCPUs with pending arch timer for
112 * each CPU. The root entry fields is configured such that
113 * its `prev` and `next` fields point to itself.
114 */
115 list_init(&(timer_list->root_entry));
Daniel Boulby7011b5a2024-10-15 18:27:26 +0100116
117 /*
118 * Initialize the list of vCPUs with pending IPIs for
119 * each CPU. The root entry fields is configured such that
120 * its `prev` and `next` fields point to itself.
121 */
122 list_init(&c->pending_ipis);
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100123 }
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000124
125 if (!found_boot_cpu) {
126 /* Boot CPU was initialized but with wrong ID. */
Andrew Walbran17eebf92020-02-05 16:35:49 +0000127 dlog_warning("Boot CPU's ID not found in config.\n");
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000128 cpus[0].id = boot_cpu_id;
129 }
Max Shvetsov9c0ebe42020-08-27 12:37:57 +0100130
131 /*
132 * Clean the cache for the cpus array such that secondary cores
133 * hitting the entry point can read the cpus array consistently
134 * with MMU off (hence data cache off).
135 */
Olivier Depreza2846172021-03-23 18:45:41 +0100136 arch_cache_data_clean_range(va_from_ptr(cpus), sizeof(cpus));
Max Shvetsov9c0ebe42020-08-27 12:37:57 +0100137
Olivier Depreza2846172021-03-23 18:45:41 +0100138 arch_cache_data_clean_range(va_from_ptr(&cpu_count), sizeof(cpu_count));
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100139}
140
141size_t cpu_index(struct cpu *c)
142{
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100143 return c - cpus;
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100144}
145
Olivier Deprez7d5e5532020-09-22 15:06:58 +0200146/*
147 * Return cpu with the given index.
148 */
149struct cpu *cpu_find_index(size_t index)
150{
151 return (index < MAX_CPUS) ? &cpus[index] : NULL;
152}
153
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100154/**
155 * Turns CPU on and returns the previous state.
156 */
Olivier Deprez70f8a4a2022-09-26 09:17:56 +0200157bool cpu_on(struct cpu *c)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100158{
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100159 bool prev;
160
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100161 sl_lock(&c->lock);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100162 prev = c->is_on;
163 c->is_on = true;
164 sl_unlock(&c->lock);
165
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100166 return prev;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100167}
168
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100169/**
170 * Prepares the CPU for turning itself off.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100171 */
172void cpu_off(struct cpu *c)
173{
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100174 sl_lock(&c->lock);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100175 c->is_on = false;
Madhukar Pappireddy984e99a2025-02-10 09:55:27 -0600176 c->last_sp_initialized = false;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100177 sl_unlock(&c->lock);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100178}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100179
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100180/**
Fuad Tabbab0ef2a42019-12-19 11:19:25 +0000181 * Searches for a CPU based on its ID.
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100182 */
Andrew Walbran4d3fa282019-06-26 13:31:15 +0100183struct cpu *cpu_find(cpu_id_t id)
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100184{
185 size_t i;
186
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000187 for (i = 0; i < cpu_count; i++) {
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100188 if (cpus[i].id == id) {
Andrew Scullf3d45592018-09-20 14:30:22 +0100189 return &cpus[i];
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100190 }
191 }
192
193 return NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100194}