blob: 7ccfd10743a2f28835df1e15d65ceb3ad95d62ac [file] [log] [blame]
David Brazdil3ad6e542019-09-13 17:17:09 +01001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
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.
David Brazdil3ad6e542019-09-13 17:17:09 +01007 */
8
9#include "hf/arch/vm/power_mgmt.h"
10
11#include "hf/arch/mm.h"
12
J-Alves491ff302023-06-21 10:58:05 +010013#include "hf/mm.h"
David Brazdil3ad6e542019-09-13 17:17:09 +010014#include "hf/spinlock.h"
15
Andrew Walbran1e7c7742019-12-13 17:10:02 +000016#include "test/hftest.h"
David Brazdil3ad6e542019-09-13 17:17:09 +010017
18struct cpu_start_state {
19 void (*entry)(uintptr_t arg);
20 uintreg_t arg;
21 struct spinlock lock;
22};
23
J-Alves491ff302023-06-21 10:58:05 +010024/*
25 * Stack for secondary execution contexts.
26 * Used in tests for MP partitions where multicore functionality is tested.
27 */
28alignas(PAGE_SIZE) uint8_t secondary_ec_stack[MAX_CPUS - 1][PAGE_SIZE];
29
David Brazdil3ad6e542019-09-13 17:17:09 +010030static noreturn void cpu_entry(uintptr_t arg)
31{
Daniel Boulby11d6c812021-10-04 16:54:56 +010032 /*
33 * The function prototype must match the entry function so we permit the
34 * int to pointer conversion.
35 */
36 // NOLINTNEXTLINE(performance-no-int-to-ptr)
David Brazdil3ad6e542019-09-13 17:17:09 +010037 struct cpu_start_state *s = (struct cpu_start_state *)arg;
38 struct cpu_start_state s_copy;
39
40 /*
41 * Initialize memory and enable caching. Must be the first thing we do.
42 */
43 hftest_mm_vcpu_init();
44
45 /* Make a copy of the cpu_start_state struct. */
46 s_copy = *s;
47
48 /* Inform cpu_start() that the state struct memory can now be freed. */
49 sl_unlock(&s->lock);
50
51 /* Call the given entry function with the given argument. */
52 s_copy.entry(s_copy.arg);
53
54 /* If the entry function returns, turn off the CPU. */
55 arch_cpu_stop();
56}
57
Kathleen Capella462ad8d2024-03-27 16:28:56 -040058bool hftest_cpu_start(uintptr_t id, void (*entry)(uintptr_t arg), uintptr_t arg)
David Brazdil3ad6e542019-09-13 17:17:09 +010059{
60 struct cpu_start_state s;
61 struct arch_cpu_start_state s_arch;
Kathleen Capella462ad8d2024-03-27 16:28:56 -040062 size_t stack_size = sizeof(secondary_ec_stack[0]);
David Brazdil3ad6e542019-09-13 17:17:09 +010063
64 /*
65 * Config for arch_cpu_start() which will start a new CPU and
66 * immediately jump to cpu_entry(). This function must guarantee that
67 * the state struct is not be freed until cpu_entry() is called.
68 */
Kathleen Capella462ad8d2024-03-27 16:28:56 -040069 s_arch.initial_sp = (uintptr_t)secondary_ec_stack + stack_size;
David Brazdil3ad6e542019-09-13 17:17:09 +010070 s_arch.entry = cpu_entry;
71 s_arch.arg = (uintptr_t)&s;
72
73 /*
Andrew Scullc059fbe2019-09-12 12:58:40 +010074 * Flush the `cpu_start_state` struct because the new CPU will be
David Brazdil3ad6e542019-09-13 17:17:09 +010075 * started without caching enabled and will need the data early on.
Andrew Scullc059fbe2019-09-12 12:58:40 +010076 * Write back is all that is really needed so flushing will definitely
77 * get the job done.
David Brazdil3ad6e542019-09-13 17:17:09 +010078 */
Andrew Scullc059fbe2019-09-12 12:58:40 +010079 arch_mm_flush_dcache(&s_arch, sizeof(s_arch));
David Brazdil3ad6e542019-09-13 17:17:09 +010080
81 if ((s_arch.initial_sp % STACK_ALIGN) != 0) {
82 HFTEST_FAIL(true,
83 "Stack pointer of new vCPU not properly aligned.");
84 }
85
86 /*
87 * Config for cpu_entry(). Its job is to initialize memory and call the
88 * provided entry point with the provided argument.
89 */
90 s.entry = entry;
91 s.arg = arg;
92 sl_init(&s.lock);
93
94 /*
95 * Lock the cpu_start_state struct which will be unlocked once
96 * cpu_entry() does not need its content anymore. This simultaneously
97 * protects the arch_cpu_start_state struct which must not be freed
98 * before cpu_entry() is called.
99 */
100 sl_lock(&s.lock);
101
102 /* Try to start the given CPU. */
103 if (!arch_cpu_start(id, &s_arch)) {
Karl Meakine8937d92024-03-19 16:04:25 +0000104 HFTEST_LOG("Couldn't start cpu %lu", id);
David Brazdil3ad6e542019-09-13 17:17:09 +0100105 return false;
106 }
107
108 /*
109 * Wait until cpu_entry() unlocks the cpu_start_state lock before
110 * freeing stack memory.
111 */
112 sl_lock(&s.lock);
113 return true;
114}