blob: 4c6a18b419b400c30fddb70d6454a626371b6866 [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
2 * Copyright 2018 Google LLC
3 *
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/arch/cpu.h"
22
23#include "hf/api.h"
24#include "hf/dlog.h"
25#include "hf/std.h"
26#include "hf/vm.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010027
Andrew Scull19503262018-09-20 14:48:39 +010028#include "vmapi/hf/call.h"
29
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010030/* The stack to be used by the CPUs. */
Andrew Scull37402872018-10-24 14:23:06 +010031alignas(2 * sizeof(uintreg_t)) static char callstacks[MAX_CPUS][STACK_SIZE];
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010032
33/* State of all supported CPUs. The stack of the first one is initialized. */
34struct cpu cpus[MAX_CPUS] = {
35 {
36 .is_on = 1,
Andrew Scullf3d45592018-09-20 14:30:22 +010037 .stack_bottom = &callstacks[0][STACK_SIZE],
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010038 },
39};
40
41void cpu_module_init(void)
42{
43 size_t i;
44
45 /* Initialize all CPUs. */
46 for (i = 0; i < MAX_CPUS; i++) {
Andrew Scullf3d45592018-09-20 14:30:22 +010047 struct cpu *c = &cpus[i];
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010048 cpu_init(c);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010049 c->id = i; /* TODO: Initialize ID based on fdt. */
Andrew Scullf3d45592018-09-20 14:30:22 +010050 c->stack_bottom = &callstacks[i][STACK_SIZE];
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010051 }
52}
53
54size_t cpu_index(struct cpu *c)
55{
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010056 return c - cpus;
Wedson Almeida Filho3fcbcff2018-07-10 23:53:39 +010057}
58
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010059void cpu_init(struct cpu *c)
60{
61 /* TODO: Assumes that c is zeroed out already. */
62 sl_init(&c->lock);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010063 c->irq_disable_count = 1;
64}
65
66void cpu_irq_enable(struct cpu *c)
67{
68 c->irq_disable_count--;
Andrew Scull7364a8e2018-07-19 15:39:29 +010069 if (!c->irq_disable_count) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010070 arch_irq_enable();
Andrew Scull7364a8e2018-07-19 15:39:29 +010071 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010072}
73
74void cpu_irq_disable(struct cpu *c)
75{
Andrew Scull7364a8e2018-07-19 15:39:29 +010076 if (!c->irq_disable_count) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010077 arch_irq_disable();
Andrew Scull7364a8e2018-07-19 15:39:29 +010078 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010079 c->irq_disable_count++;
80}
81
Wedson Almeida Filho87009642018-07-02 10:20:07 +010082/**
83 * Turns CPU on and returns the previous state.
84 */
Andrew Scull37402872018-10-24 14:23:06 +010085bool cpu_on(struct cpu *c, ipaddr_t entry, uintreg_t arg)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010086{
Wedson Almeida Filho87009642018-07-02 10:20:07 +010087 bool prev;
88
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010089 sl_lock(&c->lock);
Wedson Almeida Filho87009642018-07-02 10:20:07 +010090 prev = c->is_on;
91 c->is_on = true;
92 sl_unlock(&c->lock);
93
94 if (!prev) {
Wedson Almeida Filho1f81b752018-10-24 15:15:49 +010095 struct vm *vm = vm_get(HF_PRIMARY_VM_ID);
96 struct vcpu *vcpu = &vm->vcpus[cpu_index(c)];
97 arch_regs_init(&vcpu->regs, true, vm->id, vm->ptable.table,
98 entry, arg);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +010099 vcpu_on(vcpu);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100100 }
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100101
102 return prev;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100103}
104
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100105/**
106 * Prepares the CPU for turning itself off.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100107 */
108void cpu_off(struct cpu *c)
109{
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100110 sl_lock(&c->lock);
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100111 c->is_on = false;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100112 sl_unlock(&c->lock);
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100113}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100114
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100115/**
116 * Searches for a CPU based on its id.
117 */
118struct cpu *cpu_find(size_t id)
119{
120 size_t i;
121
122 for (i = 0; i < MAX_CPUS; i++) {
123 if (cpus[i].id == id) {
Andrew Scullf3d45592018-09-20 14:30:22 +0100124 return &cpus[i];
Wedson Almeida Filho03e767a2018-07-30 15:32:03 +0100125 }
126 }
127
128 return NULL;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100129}
130
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100131void vcpu_init(struct vcpu *vcpu, struct vm *vm)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100132{
133 memset(vcpu, 0, sizeof(*vcpu));
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100134 sl_init(&vcpu->lock);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100135 vcpu->vm = vm;
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100136 vcpu->state = vcpu_state_off;
Andrew Sculle53c1752018-10-15 13:15:01 +0100137 arch_regs_set_vcpu_index(&vcpu->regs, vcpu - vm->vcpus);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100138}
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100139
140void vcpu_on(struct vcpu *vcpu)
141{
142 sl_lock(&vcpu->lock);
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100143 vcpu->state = vcpu_state_ready;
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100144 sl_unlock(&vcpu->lock);
145}
146
147void vcpu_off(struct vcpu *vcpu)
148{
149 sl_lock(&vcpu->lock);
Wedson Almeida Filho2f94ec12018-07-26 16:00:48 +0100150 vcpu->state = vcpu_state_off;
Wedson Almeida Filho87009642018-07-02 10:20:07 +0100151 sl_unlock(&vcpu->lock);
152}