]> rtime.felk.cvut.cz Git - jailhouse.git/blob - hypervisor/arch/arm/setup.c
arm: psci: support multiple affinity levels in MPIDR
[jailhouse.git] / hypervisor / arch / arm / setup.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2013
5  *
6  * Authors:
7  *  Jan Kiszka <jan.kiszka@siemens.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include <asm/control.h>
14 #include <asm/irqchip.h>
15 #include <asm/percpu.h>
16 #include <asm/setup.h>
17 #include <asm/sysregs.h>
18 #include <jailhouse/control.h>
19 #include <jailhouse/paging.h>
20 #include <jailhouse/processor.h>
21 #include <jailhouse/string.h>
22
23 unsigned int cache_line_size;
24
25 static int arch_check_features(void)
26 {
27         u32 pfr1;
28         u32 ctr;
29
30         arm_read_sysreg(ID_PFR1_EL1, pfr1);
31
32         if (!PFR1_VIRT(pfr1))
33                 return -ENODEV;
34
35         arm_read_sysreg(CTR_EL0, ctr);
36         /* Extract the minimal cache line size */
37         cache_line_size = 4 << (ctr >> 16 & 0xf);
38
39         return 0;
40 }
41
42 int arch_init_early(void)
43 {
44         int err = 0;
45
46         if ((err = arch_check_features()) != 0)
47                 return err;
48
49         return arch_mmu_cell_init(&root_cell);
50 }
51
52 int arch_cpu_init(struct per_cpu *cpu_data)
53 {
54         int err = 0;
55         unsigned long hcr = HCR_VM_BIT | HCR_IMO_BIT | HCR_FMO_BIT
56                           | HCR_TSC_BIT | HCR_TAC_BIT;
57
58         cpu_data->psci_mbox.entry = 0;
59         cpu_data->virt_id = cpu_data->cpu_id;
60         cpu_data->mpidr = phys_processor_id();
61
62         /*
63          * Copy the registers to restore from the linux stack here, because we
64          * won't be able to access it later
65          */
66         memcpy(&cpu_data->linux_reg, (void *)cpu_data->linux_sp, NUM_ENTRY_REGS
67                         * sizeof(unsigned long));
68
69         err = switch_exception_level(cpu_data);
70         if (err)
71                 return err;
72
73         /*
74          * Save pointer in the thread local storage
75          * Must be done early in order to handle aborts and errors in the setup
76          * code.
77          */
78         arm_write_sysreg(TPIDR_EL2, cpu_data);
79
80         /* Setup guest traps */
81         arm_write_sysreg(HCR, hcr);
82
83         err = arch_mmu_cpu_cell_init(cpu_data);
84         if (err)
85                 return err;
86
87         err = irqchip_init();
88         if (err)
89                 return err;
90
91         err = irqchip_cpu_init(cpu_data);
92
93         return err;
94 }
95
96 int arch_init_late(void)
97 {
98         int err;
99
100         /* Setup the SPI bitmap */
101         err = irqchip_cell_init(&root_cell);
102         if (err)
103                 return err;
104
105         /* Platform-specific SMP operations */
106         register_smp_ops(&root_cell);
107
108         err = root_cell.arch.smp->init(&root_cell);
109         if (err)
110                 return err;
111
112         return map_root_memory_regions();
113 }
114
115 void __attribute__((noreturn)) arch_cpu_activate_vmm(struct per_cpu *cpu_data)
116 {
117         /* Return to the kernel */
118         cpu_prepare_return_el1(cpu_data, 0);
119
120         asm volatile(
121                 /* Reset the hypervisor stack */
122                 "mov    sp, %0\n\t"
123                 /*
124                  * We don't care about clobbering the other registers from now
125                  * on. Must be in sync with arch_entry.
126                  */
127                 "ldm    %1, {r0 - r12}\n\t"
128                 /*
129                  * After this, the kernel won't be able to access the hypervisor
130                  * code.
131                  */
132                 "eret\n\t"
133                 :
134                 : "r" (cpu_data->stack + sizeof(cpu_data->stack)),
135                   "r" (cpu_data->linux_reg));
136
137         __builtin_unreachable();
138 }
139
140 void arch_shutdown_self(struct per_cpu *cpu_data)
141 {
142         irqchip_cpu_shutdown(cpu_data);
143
144         /* Free the guest */
145         arm_write_sysreg(HCR, 0);
146         arm_write_sysreg(TPIDR_EL2, 0);
147         arm_write_sysreg(VTCR_EL2, 0);
148
149         /* Remove stage-2 mappings */
150         arch_cpu_tlb_flush(cpu_data);
151
152         /* TLB flush needs the cell's VMID */
153         isb();
154         arm_write_sysreg(VTTBR_EL2, 0);
155
156         /* Return to EL1 */
157         arch_shutdown_mmu(cpu_data);
158 }
159
160 void arch_cpu_restore(struct per_cpu *cpu_data, int return_code)
161 {
162         struct registers *ctx = guest_regs(cpu_data);
163
164         /*
165          * If we haven't reached switch_exception_level yet, there is nothing to
166          * clean up.
167          */
168         if (!is_el2())
169                 return;
170
171         /*
172          * Otherwise, attempt do disable the MMU and return to EL1 using the
173          * arch_shutdown path. cpu_return will fill the banked registers and the
174          * guest regs structure (stored at the beginning of the stack) to
175          * prepare the ERET.
176          */
177         cpu_prepare_return_el1(cpu_data, return_code);
178
179         memcpy(&ctx->usr, &cpu_data->linux_reg,
180                NUM_ENTRY_REGS * sizeof(unsigned long));
181
182         arch_shutdown_self(cpu_data);
183 }