source: trunk/packages/xen-3.1/xen-3.1/xen/arch/ia64/vmx/vmx_process.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 14.3 KB
Line 
1/* -*-  Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
2/*
3 * vmx_process.c: handling VMX architecture-related VM exits
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 *  Xiaoyan Feng (Fleming Feng)  <fleming.feng@intel.com>
20 *  Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com)
21 */
22
23#include <xen/config.h>
24#include <xen/lib.h>
25#include <xen/errno.h>
26#include <xen/sched.h>
27#include <xen/smp.h>
28#include <asm/ptrace.h>
29#include <xen/delay.h>
30
31#include <linux/efi.h>  /* FOR EFI_UNIMPLEMENTED */
32#include <asm/sal.h>    /* FOR struct ia64_sal_retval */
33
34#include <asm/system.h>
35#include <asm/io.h>
36#include <asm/processor.h>
37#include <asm/desc.h>
38#include <asm/vlsapic.h>
39#include <xen/irq.h>
40#include <xen/event.h>
41#include <asm/regionreg.h>
42#include <asm/privop.h>
43#include <asm/ia64_int.h>
44#include <asm/debugger.h>
45//#include <asm/hpsim_ssc.h>
46#include <asm/dom_fw.h>
47#include <asm/vmx_vcpu.h>
48#include <asm/kregs.h>
49#include <asm/vmx.h>
50#include <asm/vmmu.h>
51#include <asm/vmx_mm_def.h>
52#include <asm/vmx_phy_mode.h>
53#include <xen/mm.h>
54#include <asm/vmx_pal.h>
55/* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */
56#define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034
57
58
59extern void die_if_kernel(char *str, struct pt_regs *regs, long err);
60extern void rnat_consumption (VCPU *vcpu);
61extern void alt_itlb (VCPU *vcpu, u64 vadr);
62extern void itlb_fault (VCPU *vcpu, u64 vadr);
63extern void ivhpt_fault (VCPU *vcpu, u64 vadr);
64extern unsigned long handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr);
65
66#define DOMN_PAL_REQUEST    0x110000
67#define DOMN_SAL_REQUEST    0x110001
68
69static u64 vec2off[68] = {0x0,0x400,0x800,0xc00,0x1000,0x1400,0x1800,
70    0x1c00,0x2000,0x2400,0x2800,0x2c00,0x3000,0x3400,0x3800,0x3c00,0x4000,
71    0x4400,0x4800,0x4c00,0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,
72    0x5700,0x5800,0x5900,0x5a00,0x5b00,0x5c00,0x5d00,0x5e00,0x5f00,0x6000,
73    0x6100,0x6200,0x6300,0x6400,0x6500,0x6600,0x6700,0x6800,0x6900,0x6a00,
74    0x6b00,0x6c00,0x6d00,0x6e00,0x6f00,0x7000,0x7100,0x7200,0x7300,0x7400,
75    0x7500,0x7600,0x7700,0x7800,0x7900,0x7a00,0x7b00,0x7c00,0x7d00,0x7e00,
76    0x7f00
77};
78
79
80
81void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim,
82                              u64 vec, REGS *regs)
83{
84    u64 status, vector;
85    VCPU *vcpu = current;
86    u64 vpsr = VCPU(vcpu, vpsr);
87   
88    vector = vec2off[vec];
89    if(!(vpsr&IA64_PSR_IC)&&(vector!=IA64_DATA_NESTED_TLB_VECTOR)){
90        panic_domain(regs, "Guest nested fault vector=%lx!\n", vector);
91    }
92
93    switch (vec) {
94
95    case 22:    // IA64_INST_ACCESS_RIGHTS_VECTOR
96        if (vhpt_access_rights_fixup(vcpu, ifa, 0))
97            return;
98        break;
99
100    case 25:    // IA64_DISABLED_FPREG_VECTOR
101
102        if (FP_PSR(vcpu) & IA64_PSR_DFH) {
103            FP_PSR(vcpu) = IA64_PSR_MFH;
104            if (__ia64_per_cpu_var(fp_owner) != vcpu)
105                __ia64_load_fpu(vcpu->arch._thread.fph);
106        }
107        if (!(VCPU(vcpu, vpsr) & IA64_PSR_DFH)) {
108            regs->cr_ipsr &= ~IA64_PSR_DFH;
109            return;
110        }
111
112        break;       
113       
114    case 32:    // IA64_FP_FAULT_VECTOR
115        // handle fpswa emulation
116        // fp fault
117        status = handle_fpu_swa(1, regs, isr);
118        if (!status) {
119            vcpu_increment_iip(vcpu);
120            return;
121        } else if (IA64_RETRY == status)
122            return;
123        break;
124
125    case 33:    // IA64_FP_TRAP_VECTOR
126        //fp trap
127        status = handle_fpu_swa(0, regs, isr);
128        if (!status)
129            return;
130        else if (IA64_RETRY == status) {
131            vcpu_decrement_iip(vcpu);
132            return;
133        }
134        break;
135   
136    } 
137    VCPU(vcpu,isr)=isr;
138    VCPU(vcpu,iipa) = regs->cr_iip;
139    if (vector == IA64_BREAK_VECTOR || vector == IA64_SPECULATION_VECTOR)
140        VCPU(vcpu,iim) = iim;
141    else {
142        set_ifa_itir_iha(vcpu,ifa,1,1,1);
143    }
144    inject_guest_interruption(vcpu, vector);
145}
146
147
148IA64FAULT
149vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim)
150{
151    struct domain *d = current->domain;
152    struct vcpu *v = current;
153
154    perfc_incr(vmx_ia64_handle_break);
155#ifdef CRASH_DEBUG
156    if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs) &&
157        IS_VMM_ADDRESS(regs->cr_iip)) {
158        if (iim == 0)
159            show_registers(regs);
160        debugger_trap_fatal(0 /* don't care */, regs);
161    } else
162#endif
163    {
164        if (iim == 0) 
165            vmx_die_if_kernel("Break 0 in Hypervisor.", regs, iim);
166
167        if (!user_mode(regs)) {
168            /* Allow hypercalls only when cpl = 0.  */
169            if (iim == d->arch.breakimm) {
170                ia64_hypercall(regs);
171                vcpu_increment_iip(v);
172                return IA64_NO_FAULT;
173            }
174            else if(iim == DOMN_PAL_REQUEST){
175                pal_emul(v);
176                vcpu_increment_iip(v);
177                return IA64_NO_FAULT;
178            }else if(iim == DOMN_SAL_REQUEST){
179                sal_emul(v);
180                vcpu_increment_iip(v);
181                return IA64_NO_FAULT;
182            }
183        }
184        vmx_reflect_interruption(ifa,isr,iim,11,regs);
185    }
186    return IA64_NO_FAULT;
187}
188
189
190void save_banked_regs_to_vpd(VCPU *v, REGS *regs)
191{
192    unsigned long i=0UL, * src,* dst, *sunat, *dunat;
193    IA64_PSR vpsr;
194    src=&regs->r16;
195    sunat=&regs->eml_unat;
196    vpsr.val = VCPU(v, vpsr);
197    if(vpsr.bn){
198        dst = &VCPU(v, vgr[0]);
199        dunat =&VCPU(v, vnat);
200        __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;; \
201                            dep %2 = %0, %2, 0, 16;; \
202                            st8 [%3] = %2;;"
203       ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory");
204
205    }else{
206        dst = &VCPU(v, vbgr[0]);
207//        dunat =&VCPU(v, vbnat);
208//        __asm__ __volatile__ (";;extr.u %0 = %1,%4,16;;
209//                            dep %2 = %0, %2, 16, 16;;
210//                            st8 [%3] = %2;;"
211//       ::"r"(i),"r"(*sunat),"r"(*dunat),"r"(dunat),"i"(IA64_PT_REGS_R16_SLOT):"memory");
212
213    }
214    for(i=0; i<16; i++)
215        *dst++ = *src++;
216}
217
218
219// ONLY gets called from ia64_leave_kernel
220// ONLY call with interrupts disabled?? (else might miss one?)
221// NEVER successful if already reflecting a trap/fault because psr.i==0
222void leave_hypervisor_tail(void)
223{
224    struct domain *d = current->domain;
225    struct vcpu *v = current;
226
227    // FIXME: Will this work properly if doing an RFI???
228    if (!is_idle_domain(d) ) {  // always comes from guest
229//        struct pt_regs *user_regs = vcpu_regs(current);
230        local_irq_enable();
231        do_softirq();
232        local_irq_disable();
233
234        if (v->vcpu_id == 0) {
235            unsigned long callback_irq =
236                d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
237
238            if ( v->arch.arch_vmx.pal_init_pending ) {
239                /*inject INIT interruption to guest pal*/
240                v->arch.arch_vmx.pal_init_pending = 0;
241                deliver_pal_init(v);
242                return;
243            }
244
245            /*
246             * val[63:56] == 1: val[55:0] is a delivery PCI INTx line:
247             *                  Domain = val[47:32], Bus  = val[31:16],
248             *                  DevFn  = val[15: 8], IntX = val[ 1: 0]
249             * val[63:56] == 0: val[55:0] is a delivery as GSI
250             */
251            if (callback_irq != 0 && local_events_need_delivery()) {
252                /* change level for para-device callback irq */
253                /* use level irq to send discrete event */
254                if ((uint8_t)(callback_irq >> 56) == 1) {
255                    /* case of using PCI INTx line as callback irq */
256                    int pdev = (callback_irq >> 11) & 0x1f;
257                    int pintx = callback_irq & 3;
258                    viosapic_set_pci_irq(d, pdev, pintx, 1);
259                    viosapic_set_pci_irq(d, pdev, pintx, 0);
260                } else {
261                    /* case of using GSI as callback irq */
262                    viosapic_set_irq(d, callback_irq, 1);
263                    viosapic_set_irq(d, callback_irq, 0);
264                }
265            }
266        }
267
268        rmb();
269        if (xchg(&v->arch.irq_new_pending, 0)) {
270            v->arch.irq_new_condition = 0;
271            vmx_check_pending_irq(v);
272            return;
273        }
274
275        if (v->arch.irq_new_condition) {
276            v->arch.irq_new_condition = 0;
277            vhpi_detection(v);
278        }
279    }
280}
281
282extern ia64_rr vmx_vcpu_rr(VCPU *vcpu, u64 vadr);
283
284static int vmx_handle_lds(REGS* regs)
285{
286    regs->cr_ipsr |=IA64_PSR_ED;
287    return IA64_FAULT;
288}
289
290/* We came here because the H/W VHPT walker failed to find an entry */
291IA64FAULT
292vmx_hpw_miss(u64 vadr , u64 vec, REGS* regs)
293{
294    IA64_PSR vpsr;
295    int type;
296    u64 vhpt_adr, gppa, pteval, rr, itir;
297    ISR misr;
298    PTA vpta;
299    thash_data_t *data;
300    VCPU *v = current;
301
302    vpsr.val = VCPU(v, vpsr);
303    misr.val = VMX(v,cr_isr);
304   
305    if (vec == 1)
306        type = ISIDE_TLB;
307    else if (vec == 2)
308        type = DSIDE_TLB;
309    else
310        panic_domain(regs, "wrong vec:%lx\n", vec);
311
312    if(is_physical_mode(v)&&(!(vadr<<1>>62))){
313        if(vec==2){
314            if (v->domain != dom0
315                && __gpfn_is_io(v->domain, (vadr << 1) >> (PAGE_SHIFT + 1))) {
316                emulate_io_inst(v,((vadr<<1)>>1),4);   //  UC
317                return IA64_FAULT;
318            }
319        }
320        physical_tlb_miss(v, vadr, type);
321        return IA64_FAULT;
322    }
323
324    if((data=vtlb_lookup(v, vadr,type))!=0){
325        if (v->domain != dom0 && type == DSIDE_TLB) {
326            gppa = (vadr & ((1UL << data->ps) - 1)) +
327                   (data->ppn >> (data->ps - 12) << data->ps);
328            if (__gpfn_is_io(v->domain, gppa >> PAGE_SHIFT)) {
329                if (data->pl >= ((regs->cr_ipsr >> IA64_PSR_CPL0_BIT) & 3))
330                    emulate_io_inst(v, gppa, data->ma);
331                else {
332                    vcpu_set_isr(v, misr.val);
333                    data_access_rights(v, vadr);
334                }
335                return IA64_FAULT;
336            }
337        }
338        thash_vhpt_insert(v, data->page_flags, data->itir, vadr, type);
339
340    }else if(type == DSIDE_TLB){
341   
342        if (misr.sp)
343            return vmx_handle_lds(regs);
344
345        if(!vhpt_enabled(v, vadr, misr.rs?RSE_REF:DATA_REF)){
346            if(vpsr.ic){
347                vcpu_set_isr(v, misr.val);
348                alt_dtlb(v, vadr);
349                return IA64_FAULT;
350            } else{
351                nested_dtlb(v);
352                return IA64_FAULT;
353            }
354        }
355
356        vmx_vcpu_get_pta(v, &vpta.val);
357        if (vpta.vf) {
358            /* Long format is not yet supported.  */
359            if (vpsr.ic) {
360                vcpu_set_isr(v, misr.val);
361                dtlb_fault(v, vadr);
362                return IA64_FAULT;
363            } else {
364                nested_dtlb(v);
365                return IA64_FAULT;
366            }
367        }
368
369        /* avoid recursively walking (short format) VHPT */
370        if ((((vadr ^ vpta.val) << 3) >> (vpta.size + 3)) == 0) {
371            if (vpsr.ic) {
372                vcpu_set_isr(v, misr.val);
373                dtlb_fault(v, vadr);
374                return IA64_FAULT;
375            } else {
376                nested_dtlb(v);
377                return IA64_FAULT;
378            }
379        }
380           
381        vmx_vcpu_thash(v, vadr, &vhpt_adr);
382        if (!guest_vhpt_lookup(vhpt_adr, &pteval)) {
383            /* VHPT successfully read.  */
384            if (!(pteval & _PAGE_P)) {
385                if (vpsr.ic) {
386                    vcpu_set_isr(v, misr.val);
387                    dtlb_fault(v, vadr);
388                    return IA64_FAULT;
389                } else {
390                    nested_dtlb(v);
391                    return IA64_FAULT;
392                }
393            } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) {
394                vcpu_get_rr(v, vadr, &rr);
395                itir = rr & (RR_RID_MASK | RR_PS_MASK);
396                thash_purge_and_insert(v, pteval, itir, vadr, DSIDE_TLB);
397                return IA64_NO_FAULT;
398            } else if (vpsr.ic) {
399                vcpu_set_isr(v, misr.val);
400                dtlb_fault(v, vadr);
401                return IA64_FAULT;
402            }else{
403                nested_dtlb(v);
404                return IA64_FAULT;
405            }
406        } else {
407            /* Can't read VHPT.  */
408            if (vpsr.ic) {
409                vcpu_set_isr(v, misr.val);
410                dvhpt_fault(v, vadr);
411                return IA64_FAULT;
412            } else {
413                nested_dtlb(v);
414                return IA64_FAULT;
415            }
416        }
417    }else if(type == ISIDE_TLB){
418   
419        if (!vpsr.ic)
420            misr.ni = 1;
421        if (!vhpt_enabled(v, vadr, INST_REF)) {
422            vcpu_set_isr(v, misr.val);
423            alt_itlb(v, vadr);
424            return IA64_FAULT;
425        }
426
427        vmx_vcpu_get_pta(v, &vpta.val);
428        if (vpta.vf) {
429            /* Long format is not yet supported.  */
430            vcpu_set_isr(v, misr.val);
431            itlb_fault(v, vadr);
432            return IA64_FAULT;
433        }
434
435
436        vmx_vcpu_thash(v, vadr, &vhpt_adr);
437        if (!guest_vhpt_lookup(vhpt_adr, &pteval)) {
438            /* VHPT successfully read.  */
439            if (pteval & _PAGE_P) {
440                if ((pteval & _PAGE_MA_MASK) == _PAGE_MA_ST) {
441                    vcpu_set_isr(v, misr.val);
442                    itlb_fault(v, vadr);
443                    return IA64_FAULT;
444                }
445                vcpu_get_rr(v, vadr, &rr);
446                itir = rr & (RR_RID_MASK | RR_PS_MASK);
447                thash_purge_and_insert(v, pteval, itir, vadr, ISIDE_TLB);
448                return IA64_NO_FAULT;
449            } else {
450                vcpu_set_isr(v, misr.val);
451                inst_page_not_present(v, vadr);
452                return IA64_FAULT;
453            }
454        } else {
455            vcpu_set_isr(v, misr.val);
456            ivhpt_fault(v, vadr);
457            return IA64_FAULT;
458        }
459    }
460    return IA64_NO_FAULT;
461}
Note: See TracBrowser for help on using the repository browser.