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