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