blob: 92d17fd8247fd45def4908375a7c07cb34663b55 [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 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andrew Scull18c78fc2018-08-20 12:57:41 +010017#include "hf/cpu.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010018
Andrew Scull04502e42018-09-03 14:54:52 +010019#include <stdalign.h>
20
Andrew Scull18c78fc2018-08-20 12:57:41 +010021#include "hf/api.h"
Andrew Scull877ae4b2019-07-02 12:52:33 +010022#include "hf/check.h"
Andrew Scull18c78fc2018-08-20 12:57:41 +010023#include "hf/dlog.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010024
Andrew Scull19503262018-09-20 14:48:39 +010025#include "vmapi/hf/call.h"
26
Andrew Scull23e93a82018-10-26 14:56:04 +010027#define STACK_SIZE PAGE_SIZE
28
Andrew Sculleed724b2019-09-12 09:57:19 +010029/**
30 * The stacks to be used by the CPUs.
31 *
32 * Align to page boundaries to ensure that cache lines are not shared between a
33 * CPU's stack and data that can be accessed from other CPUs. If this did
34 * happen, there may be coherency problems when the stack is being used before
35 * caching is enabled.
36 */
37alignas(PAGE_SIZE) static char callstacks[MAX_CPUS][STACK_SIZE];
38
39/* NOLINTNEXTLINE(misc-redundant-expression) */
40static_assert((STACK_SIZE % PAGE_SIZE) == 0, "Keep each stack page aligned.");
41static_assert((PAGE_SIZE % STACK_ALIGN) == 0,
42 "Page alignment is too weak for the stack.");
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010043
Jose Marinho20713fa2019-08-07 15:42:07 +010044/**
45 * Internal buffer used to store SPCI messages from a VM Tx. Its usage prevents
46 * TOCTOU issues while Hafnium performs actions on information that would
47 * otherwise be re-writable by the VM.
48 *
49 * Each buffer is owned by a single cpu. The buffer can only be used for
50 * spci_msg_send. The information stored in the buffer is only valid during the
51 * spci_msg_send request is performed.
52 */
Andrew Walbran0ec61592019-12-17 13:29:01 +000053alignas(PAGE_SIZE) static uint8_t cpu_message_buffer[MAX_CPUS][PAGE_SIZE];
Jose Marinho20713fa2019-08-07 15:42:07 +010054
55uint8_t *cpu_get_buffer(cpu_id_t cpu_id)
56{
57 CHECK(cpu_id < MAX_CPUS);
58
59 return cpu_message_buffer[cpu_id];
60}
61
62uint32_t cpu_get_buffer_size(cpu_id_t cpu_id)
63{
64 CHECK(cpu_id < MAX_CPUS);
65
66 return sizeof(cpu_message_buffer[cpu_id]);
67}
68
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010069/* State of all supported CPUs. The stack of the first one is initialized. */
70struct cpu cpus[MAX_CPUS] = {
71 {
72 .is_on = 1,
Andrew Scullf3d45592018-09-20 14:30:22 +010073 .stack_bottom = &callstacks[0][STACK_SIZE],
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010074 },
75};
76
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000077static uint32_t cpu_count = 1;
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010078
Andrew Walbran4d3fa282019-06-26 13:31:15 +010079void cpu_module_init(const cpu_id_t *cpu_ids, size_t count)
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000080{
81 uint32_t i;
82 uint32_t j;
Andrew Walbran4d3fa282019-06-26 13:31:15 +010083 cpu_id_t boot_cpu_id = cpus[0].id;
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000084 bool found_boot_cpu = false;
85
86 cpu_count = count;
87
88 /*
89 * Initialize CPUs with the IDs from the configuration passed in. The
90 * CPUs after the boot CPU are initialized in reverse order. The boot
91 * CPU is initialized when it is found or in place of the last CPU if it
92 * is not found.
93 */
94 j = cpu_count;
95 for (i = 0; i < cpu_count; ++i) {
96 struct cpu *c;
Andrew Walbran4d3fa282019-06-26 13:31:15 +010097 cpu_id_t id = cpu_ids[i];
Andrew Scullbb3ab6c2018-11-26 20:38:49 +000098
99 if (found_boot_cpu || id != boot_cpu_id) {
Andrew Scull48973982019-08-16 17:40:28 +0100100 --j;
101 c = &cpus[j];
102 c->stack_bottom = &callstacks[j][STACK_SIZE];
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000103 } else {
104 found_boot_cpu = true;
105 c = &cpus[0];
Andrew Scull48973982019-08-16 17:40:28 +0100106 CHECK(c->stack_bottom == &callstacks[0][STACK_SIZE]);
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000107 }
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000108
Andrew Scull48973982019-08-16 17:40:28 +0100109 sl_init(&c->lock);
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000110 c->id = id;
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100111 }
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000112
113 if (!found_boot_cpu) {
114 /* Boot CPU was initialized but with wrong ID. */
David Brazdil7d853452019-09-12 10:07:36 +0100115 dlog("Boot CPU's ID not found in config.\n");
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000116 cpus[0].id = boot_cpu_id;
117 }
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100118}
119
120size_t cpu_index(struct cpu *c)
121{
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100122 return c - cpus;
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +0100123}
124
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100125/**
126 * Turns CPU on and returns the previous state.
127 */
Andrew Scull37402872018-10-24 14:23:06 +0100128bool cpu_on(struct cpu *c, ipaddr_t entry, uintreg_t arg)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100129{
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100130 bool prev;
131
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100132 sl_lock(&c->lock);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100133 prev = c->is_on;
134 c->is_on = true;
135 sl_unlock(&c->lock);
136
137 if (!prev) {
Andrew Walbran42347a92019-05-09 13:59:03 +0100138 struct vm *vm = vm_find(HF_PRIMARY_VM_ID);
Andrew Walbrane1310df2019-04-29 17:28:28 +0100139 struct vcpu *vcpu = vm_get_vcpu(vm, cpu_index(c));
Andrew Walbranb58f8992019-04-15 12:29:31 +0100140 struct vcpu_locked vcpu_locked;
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000141
Andrew Walbranb58f8992019-04-15 12:29:31 +0100142 vcpu_locked = vcpu_lock(vcpu);
143 vcpu_on(vcpu_locked, entry, arg);
144 vcpu_unlock(&vcpu_locked);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100145 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100146
147 return prev;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100148}
149
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100150/**
151 * Prepares the CPU for turning itself off.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100152 */
153void cpu_off(struct cpu *c)
154{
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100155 sl_lock(&c->lock);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100156 c->is_on = false;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100157 sl_unlock(&c->lock);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100158}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100159
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100160/**
161 * Searches for a CPU based on its id.
162 */
Andrew Walbran4d3fa282019-06-26 13:31:15 +0100163struct cpu *cpu_find(cpu_id_t id)
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100164{
165 size_t i;
166
Andrew Scullbb3ab6c2018-11-26 20:38:49 +0000167 for (i = 0; i < cpu_count; i++) {
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100168 if (cpus[i].id == id) {
Andrew Scullf3d45592018-09-20 14:30:22 +0100169 return &cpus[i];
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100170 }
171 }
172
173 return NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100174}