ia64/xen-unstable

view xen/arch/ia64/vmx/vmx_phy_mode.c @ 18094:7da7b53b2139

[IA64] kexec: Only map PAL when making EFI, PAL or SAL calls

Move PAL code from the Xen identity mapped region to the
EFI identity mapped region, which overlaps with guest virtual space.

Make sure that PAL memory is only pinned into the TLB when making
EFI, PAL or SAL calls.

This seems to be nice as it provides a symmetrical approach to
mapping an unmapping pal code.

However it would be just as safe, and arguably simpler just to map
the PAL code (once?) when the EFI RR is active - for instance very
early on in boot, or when calling XEN_EFI_RR_ENTER. In other words,
unpining is XEN_EFI_RR_LEAVE shouldn't be neccessary, as the EFI RR
should protect the memory from unwanted accesses by guests (or
the hypevisor for that matter).

This patch is mostly the work of Yamahata-san.

Cc: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Simon Horman <horms@verge.net.au>
author Isaku Yamahata <yamahata@valinux.co.jp>
date Tue Jul 22 12:15:02 2008 +0900 (2008-07-22)
parents ef290f39ae6b
children 6607624285b2
line source
1 /* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
2 /*
3 * vmx_phy_mode.c: emulating domain physical mode.
4 * Copyright (c) 2005, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 *
19 * Arun Sharma (arun.sharma@intel.com)
20 * Kun Tian (Kevin Tian) (kevin.tian@intel.com)
21 * Xuefei Xu (Anthony Xu) (anthony.xu@intel.com)
22 */
25 #include <asm/processor.h>
26 #include <asm/gcc_intrin.h>
27 #include <asm/vmx_phy_mode.h>
28 #include <asm/pgtable.h>
29 #include <asm/vmmu.h>
30 #include <asm/debugger.h>
32 #define MODE_IND(psr) \
33 (((psr).it << 2) + ((psr).dt << 1) + (psr).rt)
35 #define SW_BAD 0 /* Bad mode transitition */
36 #define SW_2P_DT 1 /* Physical emulation is activated */
37 #define SW_2P_D 2 /* Physical emulation is activated (only for data) */
38 #define SW_2V 3 /* Exit physical mode emulation */
39 #define SW_SELF 4 /* No mode transition */
40 #define SW_NOP 5 /* Mode transition, but without action required */
42 /*
43 * Special notes:
44 * - Index by it/dt/rt sequence
45 * - Only existing mode transitions are allowed in this table
46 * - If gva happens to be rr0 and rr4, only allowed case is identity
47 * mapping (gva=gpa), or panic! (How?)
48 */
49 static const unsigned char mm_switch_table[8][8] = {
50 /* 2004/09/12(Kevin): Allow switch to self */
51 /*
52 * (it,dt,rt): (0,0,0) -> (1,1,1)
53 * This kind of transition usually occurs in the very early
54 * stage of Linux boot up procedure. Another case is in efi
55 * and pal calls. (see "arch/ia64/kernel/head.S")
56 *
57 * (it,dt,rt): (0,0,0) -> (0,1,1)
58 * This kind of transition is found when OSYa exits efi boot
59 * service. Due to gva = gpa in this case (Same region),
60 * data access can be satisfied though itlb entry for physical
61 * emulation is hit.
62 *
63 * (it,dt,rt): (0,0,0) -> (1,0,1)
64 */
65 {SW_SELF,0, 0, SW_NOP, 0, SW_2P_D, 0, SW_2V},
66 {0, 0, 0, 0, 0, 0, 0, 0},
67 {0, 0, 0, 0, 0, 0, 0, 0},
68 /*
69 * (it,dt,rt): (0,1,1) -> (1,1,1)
70 * This kind of transition is found in OSYa.
71 *
72 * (it,dt,rt): (0,1,1) -> (0,0,0)
73 * This kind of transition is found in OSYa
74 */
75 {SW_NOP, 0, 0, SW_SELF,0, 0, 0, SW_2V},
76 /* (1,0,0)->(1,1,1) */
77 {0, 0, 0, 0, 0, 0, 0, SW_2V},
78 /*
79 * (it,dt,rt): (1,0,1) -> (1,1,1)
80 * This kind of transition usually occurs when Linux returns
81 * from the low level TLB miss handlers.
82 * (see "arch/ia64/kernel/ivt.S")
83 *
84 * (it,dt,rt): (1,0,1) -> (0,0,0)
85 */
86 {SW_2P_DT, 0, 0, 0, 0, SW_SELF,0, SW_2V},
87 {0, 0, 0, 0, 0, 0, 0, 0},
88 /*
89 * (it,dt,rt): (1,1,1) -> (1,0,1)
90 * This kind of transition usually occurs in Linux low level
91 * TLB miss handler. (see "arch/ia64/kernel/ivt.S")
92 *
93 * (it,dt,rt): (1,1,1) -> (0,0,0)
94 * This kind of transition usually occurs in pal and efi calls,
95 * which requires running in physical mode.
96 * (see "arch/ia64/kernel/head.S")
97 *
98 * (it,dt,rt): (1,1,1)->(1,0,0)
99 */
100 {SW_2P_DT, 0, 0, 0, SW_2P_D, SW_2P_D, 0, SW_SELF},
101 };
103 void
104 physical_mode_init(VCPU *vcpu)
105 {
106 vcpu->arch.arch_vmx.mmu_mode = VMX_MMU_PHY_DT;
107 }
109 void
110 physical_tlb_miss(VCPU *vcpu, u64 vadr, int type)
111 {
112 u64 pte;
114 pte = (vadr & _PAGE_PPN_MASK) | PHY_PAGE_WB;
115 thash_vhpt_insert(vcpu, pte, (PAGE_SHIFT << 2), vadr, type);
116 }
118 void
119 vmx_init_all_rr(VCPU *vcpu)
120 {
121 // enable vhpt in guest physical mode
122 vcpu->arch.metaphysical_rid_dt |= 1;
124 VMX(vcpu, vrr[VRN0]) = 0x38;
125 vcpu->arch.metaphysical_saved_rr0 = vrrtomrr(vcpu, 0x38);
126 VMX(vcpu, vrr[VRN1]) = 0x38;
127 VMX(vcpu, vrr[VRN2]) = 0x38;
128 VMX(vcpu, vrr[VRN3]) = 0x38;
129 VMX(vcpu, vrr[VRN4]) = 0x38;
130 vcpu->arch.metaphysical_saved_rr4 = vrrtomrr(vcpu, 0x38);
131 VMX(vcpu, vrr[VRN5]) = 0x38;
132 VMX(vcpu, vrr[VRN6]) = 0x38;
133 VMX(vcpu, vrr[VRN7]) = 0x738;
134 }
136 void
137 vmx_load_all_rr(VCPU *vcpu)
138 {
139 unsigned long rr0, rr4;
141 switch (vcpu->arch.arch_vmx.mmu_mode) {
142 case VMX_MMU_VIRTUAL:
143 rr0 = vcpu->arch.metaphysical_saved_rr0;
144 rr4 = vcpu->arch.metaphysical_saved_rr4;
145 break;
146 case VMX_MMU_PHY_DT:
147 rr0 = vcpu->arch.metaphysical_rid_dt;
148 rr4 = vcpu->arch.metaphysical_rid_dt;
149 break;
150 case VMX_MMU_PHY_D:
151 rr0 = vcpu->arch.metaphysical_rid_d;
152 rr4 = vcpu->arch.metaphysical_rid_d;
153 break;
154 default:
155 panic_domain(NULL, "bad mmu mode value");
156 }
158 ia64_set_rr((VRN0 << VRN_SHIFT), rr0);
159 ia64_dv_serialize_data();
160 ia64_set_rr((VRN4 << VRN_SHIFT), rr4);
161 ia64_dv_serialize_data();
162 ia64_set_rr((VRN1 << VRN_SHIFT), vrrtomrr(vcpu, VMX(vcpu, vrr[VRN1])));
163 ia64_dv_serialize_data();
164 ia64_set_rr((VRN2 << VRN_SHIFT), vrrtomrr(vcpu, VMX(vcpu, vrr[VRN2])));
165 ia64_dv_serialize_data();
166 ia64_set_rr((VRN3 << VRN_SHIFT), vrrtomrr(vcpu, VMX(vcpu, vrr[VRN3])));
167 ia64_dv_serialize_data();
168 ia64_set_rr((VRN5 << VRN_SHIFT), vrrtomrr(vcpu, VMX(vcpu, vrr[VRN5])));
169 ia64_dv_serialize_data();
170 ia64_set_rr((VRN6 << VRN_SHIFT), vrrtomrr(vcpu, VMX(vcpu, vrr[VRN6])));
171 ia64_dv_serialize_data();
172 vmx_switch_rr7(vrrtomrr(vcpu,VMX(vcpu, vrr[VRN7])),
173 (void *)vcpu->arch.vhpt.hash,
174 vcpu->arch.privregs);
175 ia64_set_pta(VMX(vcpu, mpta));
176 vmx_ia64_set_dcr(vcpu);
178 ia64_srlz_d();
179 }
181 void
182 switch_to_physical_rid(VCPU *vcpu)
183 {
184 u64 psr;
185 u64 rr;
187 switch (vcpu->arch.arch_vmx.mmu_mode) {
188 case VMX_MMU_PHY_DT:
189 rr = vcpu->arch.metaphysical_rid_dt;
190 break;
191 case VMX_MMU_PHY_D:
192 rr = vcpu->arch.metaphysical_rid_d;
193 break;
194 default:
195 panic_domain(NULL, "bad mmu mode value");
196 }
198 psr = ia64_clear_ic();
199 ia64_set_rr(VRN0<<VRN_SHIFT, rr);
200 ia64_dv_serialize_data();
201 ia64_set_rr(VRN4<<VRN_SHIFT, rr);
202 ia64_srlz_d();
204 ia64_set_psr(psr);
205 ia64_srlz_i();
206 return;
207 }
209 void
210 switch_to_virtual_rid(VCPU *vcpu)
211 {
212 u64 psr;
214 psr = ia64_clear_ic();
215 ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_saved_rr0);
216 ia64_dv_serialize_data();
217 ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_saved_rr4);
218 ia64_srlz_d();
219 ia64_set_psr(psr);
220 ia64_srlz_i();
221 return;
222 }
224 static int mm_switch_action(IA64_PSR opsr, IA64_PSR npsr)
225 {
226 return mm_switch_table[MODE_IND(opsr)][MODE_IND(npsr)];
227 }
229 /* In fast path, psr.ic = 0, psr.i = 0, psr.bn = 0
230 * so that no tlb miss is allowed.
231 */
232 void
233 switch_mm_mode_fast(VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr)
234 {
235 int act;
236 act = mm_switch_action(old_psr, new_psr);
237 switch (act) {
238 case SW_2P_DT:
239 vcpu->arch.arch_vmx.mmu_mode = VMX_MMU_PHY_DT;
240 switch_to_physical_rid(vcpu);
241 break;
242 case SW_2P_D:
243 vcpu->arch.arch_vmx.mmu_mode = VMX_MMU_PHY_D;
244 switch_to_physical_rid(vcpu);
245 break;
246 case SW_2V:
247 vcpu->arch.arch_vmx.mmu_mode = VMX_MMU_VIRTUAL;
248 switch_to_virtual_rid(vcpu);
249 break;
250 default:
251 break;
252 }
253 return;
254 }
256 void
257 switch_mm_mode(VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr)
258 {
259 int act;
260 act = mm_switch_action(old_psr, new_psr);
261 perfc_incra(vmx_switch_mm_mode, act);
262 switch (act) {
263 case SW_2P_DT:
264 vcpu->arch.arch_vmx.mmu_mode = VMX_MMU_PHY_DT;
265 switch_to_physical_rid(vcpu);
266 break;
267 case SW_2P_D:
268 // printk("V -> P_D mode transition: (0x%lx -> 0x%lx)\n",
269 // old_psr.val, new_psr.val);
270 vcpu->arch.arch_vmx.mmu_mode = VMX_MMU_PHY_D;
271 switch_to_physical_rid(vcpu);
272 break;
273 case SW_2V:
274 // printk("P -> V mode transition: (0x%lx -> 0x%lx)\n",
275 // old_psr.val, new_psr.val);
276 vcpu->arch.arch_vmx.mmu_mode = VMX_MMU_VIRTUAL;
277 switch_to_virtual_rid(vcpu);
278 break;
279 case SW_SELF:
280 printk("Switch to self-0x%lx!!! MM mode doesn't change...\n",
281 old_psr.val);
282 break;
283 case SW_NOP:
284 // printk("No action required for mode transition: (0x%lx -> 0x%lx)\n",
285 // old_psr.val, new_psr.val);
286 break;
287 default:
288 /* Sanity check */
289 panic_domain(vcpu_regs(vcpu),
290 "Unexpected virtual <--> physical mode transition, "
291 "old:%lx, new:%lx\n", old_psr.val, new_psr.val);
292 break;
293 }
294 return;
295 }
297 void
298 check_mm_mode_switch (VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr)
299 {
300 if (old_psr.dt != new_psr.dt ||
301 old_psr.it != new_psr.it ||
302 old_psr.rt != new_psr.rt) {
303 switch_mm_mode(vcpu, old_psr, new_psr);
304 debugger_event(XEN_IA64_DEBUG_ON_MMU);
305 }
306 }
309 /*
310 * In physical mode, insert tc/tr for region 0 and 4 uses
311 * RID[0] and RID[4] which is for physical mode emulation.
312 * However what those inserted tc/tr wants is rid for
313 * virtual mode. So original virtual rid needs to be restored
314 * before insert.
315 *
316 * Operations which required such switch include:
317 * - insertions (itc.*, itr.*)
318 * - purges (ptc.* and ptr.*)
319 * - tpa
320 * - tak
321 * - thash?, ttag?
322 * All above needs actual virtual rid for destination entry.
323 */
325 void
326 prepare_if_physical_mode(VCPU *vcpu)
327 {
328 if (!is_virtual_mode(vcpu))
329 switch_to_virtual_rid(vcpu);
330 return;
331 }
333 /* Recover always follows prepare */
334 void
335 recover_if_physical_mode(VCPU *vcpu)
336 {
337 if (!is_virtual_mode(vcpu))
338 switch_to_physical_rid(vcpu);
339 return;
340 }