1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6 
7 #include <arch/ops.h>
8 #include <fbl/atomic.h>
9 #include <hypervisor/cpu.h>
10 #include <kernel/cpu.h>
11 #include <kernel/mp.h>
12 #include <kernel/thread.h>
13 
14 namespace {
15 
16 struct percpu_state {
17     fbl::atomic<cpu_mask_t> cpu_mask;
18     hypervisor::percpu_task_t task;
19     void* context;
20 
percpu_state__anon974e60840111::percpu_state21     percpu_state(hypervisor::percpu_task_t _task, void* _context)
22         : cpu_mask(0), task(_task), context(_context) {}
23 };
24 
25 } // namespace
26 
27 namespace hypervisor {
28 
percpu_task(void * arg)29 static void percpu_task(void* arg) {
30     auto state = static_cast<percpu_state*>(arg);
31     cpu_num_t cpu_num = arch_curr_cpu_num();
32     zx_status_t status = state->task(state->context, cpu_num);
33     if (status == ZX_OK)
34         state->cpu_mask.fetch_or(cpu_num_to_mask(cpu_num));
35 }
36 
percpu_exec(percpu_task_t task,void * context)37 cpu_mask_t percpu_exec(percpu_task_t task, void* context) {
38     percpu_state state(task, context);
39     mp_sync_exec(MP_IPI_TARGET_ALL, 0, percpu_task, &state);
40     return state.cpu_mask.load();
41 }
42 
cpu_of(uint16_t vpid)43 cpu_num_t cpu_of(uint16_t vpid) {
44     return (vpid - 1) % arch_max_num_cpus();
45 }
46 
pin_thread(uint16_t vpid)47 thread_t* pin_thread(uint16_t vpid) {
48     thread_t* thread = get_current_thread();
49     thread_set_cpu_affinity(thread, cpu_num_to_mask(cpu_of(vpid)));
50     return thread;
51 }
52 
check_pinned_cpu_invariant(uint16_t vpid,const thread_t * thread)53 bool check_pinned_cpu_invariant(uint16_t vpid, const thread_t* thread) {
54     cpu_num_t cpu = cpu_of(vpid);
55     return thread == get_current_thread() &&
56            thread->cpu_affinity & cpu_num_to_mask(cpu) &&
57            arch_curr_cpu_num() == cpu;
58 }
59 
60 } // namespace hypervisor
61