From 5d1bea72fec10d7d908a8eff045c89b5ca423dc1 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Thu, 7 Jul 2005 10:12:52 -0700 Subject: [PATCH 01/12] Dummy file to test hg push --- xen/arch/ia64/hyperprivop.S | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/arch/ia64/hyperprivop.S b/xen/arch/ia64/hyperprivop.S index 9fff713278..34a2cf76e2 100644 --- a/xen/arch/ia64/hyperprivop.S +++ b/xen/arch/ia64/hyperprivop.S @@ -1324,3 +1324,4 @@ ENTRY(hyper_itc_i) br.spnt.many dispatch_break_fault ;; END(hyper_itc_i) +// ignore me From 34e779ab911f2bf675d89fd90fbe6b75d2270899 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Sat, 9 Jul 2005 07:25:29 -0700 Subject: [PATCH 02/12] Somehow this file got zeroed out?!? Replacing it --- xen/include/public/acm.h | 157 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/xen/include/public/acm.h b/xen/include/public/acm.h index e69de29bb2..fb70c43d21 100644 --- a/xen/include/public/acm.h +++ b/xen/include/public/acm.h @@ -0,0 +1,157 @@ +/**************************************************************** + * acm.h + * + * Copyright (C) 2005 IBM Corporation + * + * Author: + * Reiner Sailer + * + * Contributors: + * Stefan Berger + * added network byte order support for binary policies + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * sHype general access control module header file. + * here are all definitions that are shared between + * xen-core, guest-kernels, and applications. + * + * todo: move from static policy choice to compile option. + */ + +#ifndef _XEN_PUBLIC_ACM_H +#define _XEN_PUBLIC_ACM_H + +#include "xen.h" +#include "sched_ctl.h" + +/* if ACM_DEBUG defined, all hooks should + * print a short trace message (comment it out + * when not in testing mode ) + */ +/* #define ACM_DEBUG */ + +#ifdef ACM_DEBUG +# define printkd(fmt, args...) printk(fmt,## args) +#else +# define printkd(fmt, args...) +#endif + +/* default ssid reference value if not supplied */ +#define ACM_DEFAULT_SSID 0x0 +#define ACM_DEFAULT_LOCAL_SSID 0x0 + +/* Internal ACM ERROR types */ +#define ACM_OK 0 +#define ACM_UNDEF -1 +#define ACM_INIT_SSID_ERROR -2 +#define ACM_INIT_SOID_ERROR -3 +#define ACM_ERROR -4 + +/* External ACCESS DECISIONS */ +#define ACM_ACCESS_PERMITTED 0 +#define ACM_ACCESS_DENIED -111 +#define ACM_NULL_POINTER_ERROR -200 + +#define ACM_MAX_POLICY 3 + +#define ACM_NULL_POLICY 0 +#define ACM_CHINESE_WALL_POLICY 1 +#define ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY 2 +#define ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY 3 + +/* policy: */ +#define ACM_POLICY_NAME(X) \ + (X == ACM_NULL_POLICY) ? "NULL policy" : \ + (X == ACM_CHINESE_WALL_POLICY) ? "CHINESE WALL policy" : \ + (X == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "SIMPLE TYPE ENFORCEMENT policy" : \ + (X == ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY) ? "CHINESE WALL AND SIMPLE TYPE ENFORCEMENT policy" : \ + "UNDEFINED policy" + +/* defines a ssid reference used by xen */ +typedef u32 ssidref_t; + +/* -------security policy relevant type definitions-------- */ + +/* type identifier; compares to "equal" or "not equal" */ +typedef u16 domaintype_t; + +/* CHINESE WALL POLICY DATA STRUCTURES + * + * current accumulated conflict type set: + * When a domain is started and has a type that is in + * a conflict set, the conflicting types are incremented in + * the aggregate set. When a domain is destroyed, the + * conflicting types to its type are decremented. + * If a domain has multiple types, this procedure works over + * all those types. + * + * conflict_aggregate_set[i] holds the number of + * running domains that have a conflict with type i. + * + * running_types[i] holds the number of running domains + * that include type i in their ssidref-referenced type set + * + * conflict_sets[i][j] is "0" if type j has no conflict + * with type i and is "1" otherwise. + */ +/* high-16 = version, low-16 = check magic */ +#define ACM_MAGIC 0x0001debc + +/* each offset in bytes from start of the struct they + * the are part of */ +/* each buffer consists of all policy information for + * the respective policy given in the policy code + */ +struct acm_policy_buffer { + u32 magic; + u32 policyversion; + u32 len; + u16 primary_policy_code; + u16 primary_buffer_offset; + u16 secondary_policy_code; + u16 secondary_buffer_offset; +}; + +struct acm_chwall_policy_buffer { + u16 policy_code; + u16 chwall_max_types; + u16 chwall_max_ssidrefs; + u16 chwall_max_conflictsets; + u16 chwall_ssid_offset; + u16 chwall_conflict_sets_offset; + u16 chwall_running_types_offset; + u16 chwall_conflict_aggregate_offset; +}; + +struct acm_ste_policy_buffer { + u16 policy_code; + u16 ste_max_types; + u16 ste_max_ssidrefs; + u16 ste_ssid_offset; +}; + +struct acm_stats_buffer { + u32 magic; + u32 policyversion; + u32 len; + u16 primary_policy_code; + u16 primary_stats_offset; + u16 secondary_policy_code; + u16 secondary_stats_offset; +}; + +struct acm_ste_stats_buffer { + u32 ec_eval_count; + u32 gt_eval_count; + u32 ec_denied_count; + u32 gt_denied_count; + u32 ec_cachehit_count; + u32 gt_cachehit_count; +}; + + +#endif From 2f17e74db159f51483cc770523fb79dddbcb6106 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Sat, 9 Jul 2005 07:36:13 -0700 Subject: [PATCH 03/12] Cleanup virtual translation code Add some additional statistics Signed-off by: Matt Chapman Signed-off by: Dan Magenheimer --- xen/arch/ia64/hypercall.c | 18 ++-- xen/arch/ia64/privop.c | 32 ++++++ xen/arch/ia64/process.c | 181 ++++++-------------------------- xen/arch/ia64/vcpu.c | 137 +++++++++++++++++++----- xen/include/asm-ia64/ia64_int.h | 15 ++- xen/include/asm-ia64/vcpu.h | 2 +- 6 files changed, 195 insertions(+), 190 deletions(-) diff --git a/xen/arch/ia64/hypercall.c b/xen/arch/ia64/hypercall.c index 8107e166e2..d7288088cf 100644 --- a/xen/arch/ia64/hypercall.c +++ b/xen/arch/ia64/hypercall.c @@ -19,12 +19,16 @@ extern unsigned long translate_domain_mpaddr(unsigned long); extern struct ia64_sal_retval pal_emulator_static(UINT64); extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); +unsigned long idle_when_pending = 0; +unsigned long pal_halt_light_count = 0; + int ia64_hypercall (struct pt_regs *regs) { struct vcpu *v = (struct domain *) current; struct ia64_sal_retval x; unsigned long *tv, *tc; + int pi; switch (regs->r2) { case FW_HYPERCALL_PAL_CALL: @@ -40,19 +44,21 @@ ia64_hypercall (struct pt_regs *regs) #endif x = pal_emulator_static(regs->r28); if (regs->r28 == PAL_HALT_LIGHT) { -#if 1 #define SPURIOUS_VECTOR 15 - if (vcpu_check_pending_interrupts(v)!=SPURIOUS_VECTOR) { -// int pi = vcpu_check_pending_interrupts(v); + pi = vcpu_check_pending_interrupts(v); + if (pi != SPURIOUS_VECTOR) { + idle_when_pending++; + pi = vcpu_pend_unspecified_interrupt(v); //printf("idle w/int#%d pending!\n",pi); //this shouldn't happen, but it apparently does quite a bit! so don't //allow it to happen... i.e. if a domain has an interrupt pending and //it tries to halt itself because it thinks it is idle, just return here //as deliver_pending_interrupt is called on the way out and will deliver it } - else -#endif - do_sched_op(SCHEDOP_yield); + else { + pal_halt_light_count++; + do_sched_op(SCHEDOP_yield); + } //break; } regs->r8 = x.status; regs->r9 = x.v0; diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c index 3ab81421f6..a48a9edb9b 100644 --- a/xen/arch/ia64/privop.c +++ b/xen/arch/ia64/privop.c @@ -1033,6 +1033,36 @@ void zero_privop_addrs(void) } #endif +extern unsigned long dtlb_translate_count; +extern unsigned long tr_translate_count; +extern unsigned long phys_translate_count; +extern unsigned long vhpt_translate_count; +extern unsigned long lazy_cover_count; +extern unsigned long idle_when_pending; +extern unsigned long pal_halt_light_count; + +int dump_misc_stats(char *buf) +{ + char *s = buf; + s += sprintf(s,"Virtual TR translations: %d\n",tr_translate_count); + s += sprintf(s,"Virtual VHPT translations: %d\n",vhpt_translate_count); + s += sprintf(s,"Virtual DTLB translations: %d\n",dtlb_translate_count); + s += sprintf(s,"Physical translations: %d\n",phys_translate_count); + s += sprintf(s,"Idle when pending: %d\n",idle_when_pending); + s += sprintf(s,"PAL_HALT_LIGHT (no pending): %d\n",pal_halt_light_count); + s += sprintf(s,"Lazy covers: %d\n",lazy_cover_count); + return s - buf; +} + +void zero_misc_stats(void) +{ + dtlb_translate_count = 0; + tr_translate_count = 0; + phys_translate_count = 0; + vhpt_translate_count = 0; + lazy_cover_count = 0; +} + int dump_hyperprivop_counts(char *buf) { int i; @@ -1072,6 +1102,7 @@ int dump_privop_counts_to_user(char __user *ubuf, int len) #ifdef PRIVOP_ADDR_COUNT n += dump_privop_addrs(buf + n); #endif + n += dump_misc_stats(buf + n); if (len < TMPBUFLEN) return -1; if (__copy_to_user(ubuf,buf,n)) return -1; return n; @@ -1086,6 +1117,7 @@ int zero_privop_counts_to_user(char __user *ubuf, int len) #ifdef PRIVOP_ADDR_COUNT zero_privop_addrs(); #endif + zero_misc_stats(); zero_reflect_counts(); if (len < TMPBUFLEN) return -1; if (__copy_to_user(ubuf,buf,n)) return -1; diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c index 802a46b4ea..f8aafe1b40 100644 --- a/xen/arch/ia64/process.c +++ b/xen/arch/ia64/process.c @@ -76,8 +76,6 @@ void schedule_tail(struct vcpu *next) #endif // CONFIG_VTI } -extern TR_ENTRY *match_tr(struct vcpu *v, unsigned long ifa); - void tdpfoo(void) { } // given a domain virtual address, pte and pagesize, extract the metaphysical @@ -260,140 +258,29 @@ printf("*#*#*#* about to deliver early timer to domain %d!!!\n",v->domain->domai ++pending_false_positive; } } +unsigned long lazy_cover_count = 0; int handle_lazy_cover(struct vcpu *v, unsigned long isr, struct pt_regs *regs) { if (!PSCB(v,interrupt_collection_enabled)) { - if (isr & IA64_ISR_IR) { -// printf("Handling lazy cover\n"); - PSCB(v,ifs) = regs->cr_ifs; - PSCB(v,incomplete_regframe) = 1; - regs->cr_ifs = 0; - return(1); // retry same instruction with cr.ifs off - } + PSCB(v,ifs) = regs->cr_ifs; + PSCB(v,incomplete_regframe) = 1; + regs->cr_ifs = 0; + lazy_cover_count++; + return(1); // retry same instruction with cr.ifs off } return(0); } -#define IS_XEN_ADDRESS(d,a) ((a >= d->xen_vastart) && (a <= d->xen_vaend)) - -void xen_handle_domain_access(unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir) -{ - struct domain *d = (struct domain *) current->domain; - struct domain *ed = (struct vcpu *) current; - TR_ENTRY *trp; - unsigned long psr = regs->cr_ipsr, mask, flags; - unsigned long iip = regs->cr_iip; - // FIXME should validate address here - unsigned long pteval, mpaddr, ps; - unsigned long lookup_domain_mpa(struct domain *,unsigned long); - unsigned long match_dtlb(struct vcpu *,unsigned long, unsigned long *, unsigned long *); - IA64FAULT fault; - -// NEED TO HANDLE THREE CASES: -// 1) domain is in metaphysical mode -// 2) domain address is in TR -// 3) domain address is not in TR (reflect data miss) - - // got here trying to read a privop bundle - //if (d->metaphysical_mode) { - if (PSCB(current,metaphysical_mode) && !(address>>61)) { //FIXME - if (d == dom0) { - if (address < dom0_start || address >= dom0_start + dom0_size) { - printk("xen_handle_domain_access: out-of-bounds" - "dom0 mpaddr %p! continuing...\n",mpaddr); - tdpfoo(); - } - } - pteval = lookup_domain_mpa(d,address); - //FIXME: check return value? - // would be nice to have a counter here - vcpu_itc_no_srlz(ed,2,address,pteval,-1UL,PAGE_SHIFT); - return; - } -if (address < 0x4000) printf("WARNING: page_fault @%p, iip=%p\n",address,iip); - - if (trp = match_tr(current,address)) { - // FIXME address had better be pre-validated on insert - pteval = translate_domain_pte(trp->page_flags,address,trp->itir); - vcpu_itc_no_srlz(current,6,address,pteval,-1UL,(trp->itir>>2)&0x3f); - return; - } - // if we are fortunate enough to have it in the 1-entry TLB... - if (pteval = match_dtlb(ed,address,&ps,NULL)) { - vcpu_itc_no_srlz(ed,6,address,pteval,-1UL,ps); - return; - } - if (ia64_done_with_exception(regs)) { -//if (!(uacnt++ & 0x3ff)) printk("*** xen_handle_domain_access: successfully handled cnt=%d iip=%p, addr=%p...\n",uacnt,iip,address); - return; - } - else { - // should never happen. If it does, region 0 addr may - // indicate a bad xen pointer - printk("*** xen_handle_domain_access: exception table" - " lookup failed, iip=%p, addr=%p, spinning...\n", - iip,address); - panic_domain(regs,"*** xen_handle_domain_access: exception table" - " lookup failed, iip=%p, addr=%p, spinning...\n", - iip,address); - } -} - void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs, unsigned long itir) { - struct domain *d = (struct domain *) current->domain; - TR_ENTRY *trp; - unsigned long psr = regs->cr_ipsr, mask, flags; unsigned long iip = regs->cr_iip; // FIXME should validate address here - unsigned long iha, pteval, mpaddr; - unsigned long lookup_domain_mpa(struct domain *,unsigned long); + unsigned long pteval; unsigned long is_data = !((isr >> IA64_ISR_X_BIT) & 1UL); - unsigned long vector; IA64FAULT fault; - - //The right way is put in VHPT and take another miss! - - // weak attempt to avoid doing both I/D tlb insert to avoid - // problems for privop bundle fetch, doesn't work, deal with later - if (IS_XEN_ADDRESS(d,iip) && !IS_XEN_ADDRESS(d,address)) { - xen_handle_domain_access(address, isr, regs, itir); - - return; - } - - // FIXME: no need to pass itir in to this routine as we need to - // compute the virtual itir anyway (based on domain's RR.ps) - // AND ACTUALLY reflect_interruption doesn't use it anyway! - itir = vcpu_get_itir_on_fault(current,address); - - if (PSCB(current,metaphysical_mode) && (is_data || !(address>>61))) { //FIXME - // FIXME should validate mpaddr here - if (d == dom0) { - if (address < dom0_start || address >= dom0_start + dom0_size) { - printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, iip=%p! continuing...\n",address,iip); - printk("ia64_do_page_fault: out-of-bounds dom0 mpaddr %p, old iip=%p!\n",address,current->vcpu_info->arch.iip); - tdpfoo(); - } - } - pteval = lookup_domain_mpa(d,address); - // FIXME, must be inlined or potential for nested fault here! - vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,PAGE_SHIFT); - return; - } - if (trp = match_tr(current,address)) { - // FIXME address had better be pre-validated on insert - pteval = translate_domain_pte(trp->page_flags,address,trp->itir); - vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,(trp->itir>>2)&0x3f); - return; - } - - if (handle_lazy_cover(current, isr, regs)) return; -if (!(address>>61)) { -panic_domain(0,"ia64_do_page_fault: @%p???, iip=%p, b0=%p, itc=%p (spinning...)\n",address,iip,regs->b0,ia64_get_itc()); -} + if ((isr & IA64_ISR_IR) && handle_lazy_cover(current, isr, regs)) return; if ((isr & IA64_ISR_SP) || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH)) { @@ -406,37 +293,29 @@ panic_domain(0,"ia64_do_page_fault: @%p???, iip=%p, b0=%p, itc=%p (spinning...)\ return; } - if (vcpu_get_rr_ve(current, address) && (PSCB(current,pta) & IA64_PTA_VE)) + fault = vcpu_translate(current,address,is_data,&pteval,&itir); + if (fault == IA64_NO_FAULT) { - if (PSCB(current,pta) & IA64_PTA_VF) - { - /* long format VHPT - not implemented */ - vector = is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR; - } - else - { - /* short format VHPT */ - vcpu_thash(current, address, &iha); - if (__copy_from_user(&pteval, iha, sizeof(pteval)) == 0) - { - /* - * Optimisation: this VHPT walker aborts on not-present pages - * instead of inserting a not-present translation, this allows - * vectoring directly to the miss handler. - \ */ - if (pteval & _PAGE_P) - { - pteval = translate_domain_pte(pteval,address,itir); - vcpu_itc_no_srlz(current,is_data?6:1,address,pteval,-1UL,(itir>>2)&0x3f); - return; - } - else vector = is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR; - } - else vector = IA64_VHPT_TRANS_VECTOR; - } + pteval = translate_domain_pte(pteval,address,itir); + vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,(itir>>2)&0x3f); + return; } - else vector = is_data ? IA64_ALT_DATA_TLB_VECTOR : IA64_ALT_INST_TLB_VECTOR; - reflect_interruption(address, isr, itir, regs, vector); + else if (IS_VMM_ADDRESS(iip)) + { + if (!ia64_done_with_exception(regs)) { + // should never happen. If it does, region 0 addr may + // indicate a bad xen pointer + printk("*** xen_handle_domain_access: exception table" + " lookup failed, iip=%p, addr=%p, spinning...\n", + iip,address); + panic_domain(regs,"*** xen_handle_domain_access: exception table" + " lookup failed, iip=%p, addr=%p, spinning...\n", + iip,address); + } + return; + } + + reflect_interruption(address, isr, 0, regs, fault); } void @@ -865,6 +744,6 @@ printf("*** Handled privop masquerading as NaT fault\n"); while(vector); return; } - if (check_lazy_cover && handle_lazy_cover(v, isr, regs)) return; + if (check_lazy_cover && (isr & IA64_ISR_IR) && handle_lazy_cover(v, isr, regs)) return; reflect_interruption(ifa,isr,itir,regs,vector); } diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index 45ae1bc656..57f721150c 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -53,9 +53,16 @@ extern void privop_count_addr(unsigned long addr, int inst); #define PRIVOP_COUNT_ADDR(x,y) do {} while (0) #endif +unsigned long dtlb_translate_count = 0; +unsigned long tr_translate_count = 0; +unsigned long phys_translate_count = 0; + unsigned long vcpu_verbose = 0; #define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0) +extern TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa); +extern TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa); + /************************************************************************** VCPU general register access routines **************************************************************************/ @@ -224,6 +231,9 @@ IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) //else printf("but nothing pending\n"); } #endif + if (enabling_interrupts && + vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + PSCB(vcpu,pending_interruption) = 1; return IA64_NO_FAULT; } @@ -267,6 +277,9 @@ IA64FAULT vcpu_set_psr_l(VCPU *vcpu, UINT64 val) return IA64_EXTINT_VECTOR; } #endif + if (enabling_interrupts && + vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + PSCB(vcpu,pending_interruption) = 1; return IA64_NO_FAULT; } @@ -532,6 +545,11 @@ IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val) VCPU interrupt control register access routines **************************************************************************/ +void vcpu_pend_unspecified_interrupt(VCPU *vcpu) +{ + PSCB(vcpu,pending_interruption) = 1; +} + void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) { if (vector & ~0xff) { @@ -1241,28 +1259,101 @@ IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr) return (IA64_ILLOP_FAULT); } +#define itir_ps(itir) ((itir >> 2) & 0x3f) +#define itir_mask(itir) (~((1UL << itir_ps(itir)) - 1)) + +unsigned long vhpt_translate_count = 0; + +IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir) +{ + unsigned long pta, pta_mask, iha, pte, ps; + TR_ENTRY *trp; + ia64_rr rr; + + if (!(address >> 61)) { + if (!PSCB(vcpu,metaphysical_mode)) + panic_domain(0,"vcpu_translate: bad address %p\n", address); + + *pteval = (address & _PAGE_PPN_MASK) | __DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX; + *itir = PAGE_SHIFT << 2; + phys_translate_count++; + return IA64_NO_FAULT; + } + + /* check translation registers */ + if ((trp = match_tr(vcpu,address))) { + tr_translate_count++; + *pteval = trp->page_flags; + *itir = trp->itir; + return IA64_NO_FAULT; + } + + /* check 1-entry TLB */ + if ((trp = match_dtlb(vcpu,address))) { + dtlb_translate_count++; + *pteval = trp->page_flags; + *itir = trp->itir; + return IA64_NO_FAULT; + } + + /* check guest VHPT */ + pta = PSCB(vcpu,pta); + rr.rrval = PSCB(vcpu,rrs)[address>>61]; + if (rr.ve && (pta & IA64_PTA_VE)) + { + if (pta & IA64_PTA_VF) + { + /* long format VHPT - not implemented */ + return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + } + else + { + /* short format VHPT */ + + /* avoid recursively walking VHPT */ + pta_mask = (itir_mask(pta) << 3) >> 3; + if (((address ^ pta) & pta_mask) == 0) + return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + + vcpu_thash(vcpu, address, &iha); + if (__copy_from_user(&pte, (void *)iha, sizeof(pte)) != 0) + return IA64_VHPT_TRANS_VECTOR; + + /* + * Optimisation: this VHPT walker aborts on not-present pages + * instead of inserting a not-present translation, this allows + * vectoring directly to the miss handler. + \ */ + if (pte & _PAGE_P) + { + *pteval = pte; + *itir = vcpu_get_itir_on_fault(vcpu,address); + vhpt_translate_count++; + return IA64_NO_FAULT; + } + return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + } + } + return (is_data ? IA64_ALT_DATA_TLB_VECTOR : IA64_ALT_INST_TLB_VECTOR); +} + IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) { - extern TR_ENTRY *match_tr(VCPU *,UINT64); - unsigned long match_dtlb(VCPU *, unsigned long, unsigned long *, unsigned long *); - TR_ENTRY *trp; - UINT64 mask, pteval, mp_pte, ps; + UINT64 pteval, itir, mask; + IA64FAULT fault; -extern unsigned long privop_trace; - if (pteval = match_dtlb(vcpu, vadr, &ps, &mp_pte) && (mp_pte != -1UL)) { - mask = (1L << ps) - 1; - *padr = ((mp_pte & _PAGE_PPN_MASK) & ~mask) | (vadr & mask); - verbose("vcpu_tpa: addr=%p @%p, successful, padr=%p\n",vadr,PSCB(vcpu,iip),*padr); + fault = vcpu_translate(vcpu, vadr, 1, &pteval, &itir); + if (fault == IA64_NO_FAULT) + { + mask = itir_mask(itir); + *padr = (pteval & _PAGE_PPN_MASK & mask) | (vadr & ~mask); return (IA64_NO_FAULT); } - if (trp=match_tr(current,vadr)) { - mask = (1L << trp->ps) - 1; - *padr = ((trp->ppn << 12) & ~mask) | (vadr & mask); - verbose("vcpu_tpa: addr=%p @%p, successful, padr=%p\n",vadr,PSCB(vcpu,iip),*padr); - return (IA64_NO_FAULT); + else + { + PSCB(vcpu,tmp[0]) = vadr; // save ifa in vcpu structure, then specify IA64_FORCED_IFA + return (fault | IA64_FORCED_IFA); } - verbose("vcpu_tpa addr=%p, @%p, forcing data miss\n",vadr,PSCB(vcpu,iip)); - return vcpu_force_data_miss(vcpu, vadr); } IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) @@ -1614,15 +1705,12 @@ void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 // NOTE: returns a physical pte, NOT a "metaphysical" pte, so do not check // the physical address contained for correctness -unsigned long match_dtlb(VCPU *vcpu, unsigned long ifa, unsigned long *ps, unsigned long *mp_pte) +TR_ENTRY *match_dtlb(VCPU *vcpu, unsigned long ifa) { TR_ENTRY *trp; - if (trp = vcpu_match_tr_entry(vcpu,&vcpu->arch.dtlb,ifa,1)) { - if (ps) *ps = trp->ps; - if (mp_pte) *mp_pte = vcpu->arch.dtlb_pte; - return (trp->page_flags); - } + if (trp = vcpu_match_tr_entry(vcpu,&vcpu->arch.dtlb,ifa,1)) + return (&vcpu->arch.dtlb); return 0UL; } @@ -1679,11 +1767,12 @@ IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr) // TODO: Only allowed for current vcpu UINT64 mpaddr, ps; IA64FAULT fault; - unsigned long match_dtlb(VCPU *, unsigned long, unsigned long *, unsigned long *); + TR_ENTRY *trp; unsigned long lookup_domain_mpa(struct domain *,unsigned long); unsigned long pteval, dom_imva; - if (pteval = match_dtlb(vcpu, vadr, NULL, NULL)) { + if ((trp = match_dtlb(vcpu,vadr))) { + pteval = trp->page_flags; dom_imva = __va(pteval & _PFN_MASK); ia64_fc(dom_imva); return IA64_NO_FAULT; diff --git a/xen/include/asm-ia64/ia64_int.h b/xen/include/asm-ia64/ia64_int.h index 2e4f61b6b1..c560dca005 100644 --- a/xen/include/asm-ia64/ia64_int.h +++ b/xen/include/asm-ia64/ia64_int.h @@ -3,11 +3,11 @@ //#include "ia64.h" -#define IA64_VHPT_TRANS_VECTOR 0x0000 /* UNUSED */ +#define IA64_VHPT_TRANS_VECTOR 0x0000 #define IA64_INST_TLB_VECTOR 0x0400 #define IA64_DATA_TLB_VECTOR 0x0800 -#define IA64_ALT_INST_TLB_VECTOR 0x0c00 /* UNUSED */ -#define IA64_ALT_DATA_TLB_VECTOR 0x1000 /* UNUSED */ +#define IA64_ALT_INST_TLB_VECTOR 0x0c00 +#define IA64_ALT_DATA_TLB_VECTOR 0x1000 #define IA64_DATA_NESTED_TLB_VECTOR 0x1400 #define IA64_INST_KEY_MISS_VECTOR 0x1800 #define IA64_DATA_KEY_MISS_VECTOR 0x1c00 @@ -33,12 +33,11 @@ #define IA64_TAKEN_BRANCH_TRAP_VECTOR 0x5f00 #define IA64_SINGLE_STEP_TRAP_VECTOR 0x6000 -#define IA64_NO_FAULT 0x0000 -#define IA64_RFI_IN_PROGRESS 0x0001 -#define IA64_RETRY 0x0002 +#define IA64_NO_FAULT 0x0001 +#define IA64_RFI_IN_PROGRESS 0x0002 +#define IA64_RETRY 0x0003 #ifdef CONFIG_VTI -#define IA64_FAULT 0x0001 -#define IA64_INJ_FAULT 0x0005 +#define IA64_FAULT 0x0002 #endif //CONFIG_VTI #define IA64_FORCED_IFA 0x0004 #define IA64_ILLOP_FAULT (IA64_GENEX_VECTOR | 0x00) diff --git a/xen/include/asm-ia64/vcpu.h b/xen/include/asm-ia64/vcpu.h index f4ca7de36f..b5f97323b6 100644 --- a/xen/include/asm-ia64/vcpu.h +++ b/xen/include/asm-ia64/vcpu.h @@ -135,6 +135,7 @@ extern IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 addr_range); extern IA64FAULT vcpu_ptc_ga(VCPU *vcpu, UINT64 vadr, UINT64 addr_range); extern IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr, UINT64 addr_range); extern IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr, UINT64 addr_range); +extern IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir); extern IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr); /* misc */ extern IA64FAULT vcpu_rfi(VCPU *vcpu); @@ -150,5 +151,4 @@ extern void vcpu_itc_no_srlz(VCPU *vcpu, UINT64, UINT64, UINT64, UINT64, UINT64) extern UINT64 vcpu_get_tmp(VCPU *, UINT64); extern void vcpu_set_tmp(VCPU *, UINT64, UINT64); - #endif From ef04737cbf5b1482d95d7ceb6a2e31c1d41376e2 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Sat, 9 Jul 2005 07:37:13 -0700 Subject: [PATCH 04/12] Add fast path for thash hyperprivop Add fast path for ptc.ga hyperprivop Add fast path for iaccess/daccess reflect --- xen/arch/ia64/asm-offsets.c | 5 + xen/arch/ia64/hyperprivop.S | 249 ++++++++++++++++++++++++++++++++---- xen/arch/ia64/ivt.S | 23 +++- 3 files changed, 247 insertions(+), 30 deletions(-) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index b374c4809b..9c2326a6a0 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -46,6 +46,8 @@ void foo(void) DEFINE(XSI_PSR_IC, (SHAREDINFO_ADDR+offsetof(vcpu_info_t, arch.interrupt_collection_enabled))); DEFINE(XSI_PSR_I_OFS, offsetof(vcpu_info_t, arch.interrupt_delivery_enabled)); DEFINE(XSI_IIP_OFS, offsetof(vcpu_info_t, arch.iip)); + DEFINE(XSI_IFA_OFS, offsetof(vcpu_info_t, arch.ifa)); + DEFINE(XSI_ITIR_OFS, offsetof(vcpu_info_t, arch.itir)); DEFINE(XSI_IPSR, (SHAREDINFO_ADDR+offsetof(vcpu_info_t, arch.ipsr))); DEFINE(XSI_IPSR_OFS, offsetof(vcpu_info_t, arch.ipsr)); DEFINE(XSI_IFS_OFS, offsetof(vcpu_info_t, arch.ifs)); @@ -61,6 +63,7 @@ void foo(void) DEFINE(XSI_PEND_OFS, offsetof(vcpu_info_t, arch.pending_interruption)); DEFINE(XSI_RR0_OFS, offsetof(vcpu_info_t, arch.rrs[0])); DEFINE(XSI_TPR_OFS, offsetof(vcpu_info_t, arch.tpr)); + DEFINE(XSI_PTA_OFS, offsetof (vcpu_info_t, arch.pta)); DEFINE(XSI_ITV_OFS, offsetof(vcpu_info_t, arch.itv)); //DEFINE(IA64_TASK_BLOCKED_OFFSET,offsetof (struct task_struct, blocked)); //DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); @@ -85,6 +88,8 @@ void foo(void) DEFINE(IA64_VCPU_ENDING_RID_OFFSET, offsetof (struct vcpu, arch.ending_rid)); DEFINE(IA64_VCPU_DOMAIN_ITM_OFFSET, offsetof (struct vcpu, arch.domain_itm)); DEFINE(IA64_VCPU_DOMAIN_ITM_LAST_OFFSET, offsetof (struct vcpu, arch.domain_itm_last)); + DEFINE(IA64_VCPU_ITLB_OFFSET, offsetof (struct vcpu, arch.itlb)); + DEFINE(IA64_VCPU_DTLB_OFFSET, offsetof (struct vcpu, arch.dtlb)); BLANK(); DEFINE(IA64_CPUINFO_ITM_NEXT_OFFSET, offsetof (struct cpuinfo_ia64, itm_next)); diff --git a/xen/arch/ia64/hyperprivop.S b/xen/arch/ia64/hyperprivop.S index 34a2cf76e2..98a4b439bf 100644 --- a/xen/arch/ia64/hyperprivop.S +++ b/xen/arch/ia64/hyperprivop.S @@ -125,6 +125,10 @@ GLOBAL_ENTRY(fast_hyperprivop) cmp.eq p7,p6=XEN_HYPER_ITC_I,r17 (p7) br.sptk.many hyper_itc_i;; + // HYPERPRIVOP_THASH? + cmp.eq p7,p6=XEN_HYPER_THASH,r17 +(p7) br.sptk.many hyper_thash;; + // if not one of the above, give up for now and do it the slow way br.sptk.many dispatch_break_fault ;; @@ -440,7 +444,6 @@ fast_tick_reflect_done: END(fast_tick_reflect) // reflect domain breaks directly to domain -// FIXME: DOES NOT WORK YET // r16 == cr.isr // r17 == cr.iim // r18 == XSI_PSR_IC @@ -471,15 +474,30 @@ GLOBAL_ENTRY(fast_break_reflect) cmp.eq p7,p0=r22,r17; (p7) br.spnt.few dispatch_break_fault ;; #endif -#ifdef FAST_REFLECT_CNT - movl r20=fast_reflect_count+((0x2c00>>8)*8);; - ld8 r21=[r20];; - adds r21=1,r21;; - st8 [r20]=r21;; -#endif + movl r20=0x2c00; // save iim in shared_info adds r21=XSI_IIM_OFS-XSI_PSR_IC_OFS,r18 ;; st8 [r21]=r17;; + // fall through + + +// reflect to domain ivt+r20 +// sets up isr,iip,ipsr,ifs (FIXME: do iipa too) +// r16 == cr.isr +// r18 == XSI_PSR_IC +// r20 == offset into ivt +// r29 == iip +// r30 == ipsr +// r31 == pr +ENTRY(fast_reflect) +#ifdef FAST_REFLECT_CNT + movl r22=fast_reflect_count; + shr r23=r20,5;; + add r22=r22,r23;; + ld8 r21=[r22];; + adds r21=1,r21;; + st8 [r22]=r21;; +#endif // save iip in shared_info (DON'T POINT TO NEXT INSTRUCTION!) adds r21=XSI_IIP_OFS-XSI_PSR_IC_OFS,r18 ;; st8 [r21]=r29;; @@ -504,9 +522,9 @@ GLOBAL_ENTRY(fast_break_reflect) or r30=r30,r28;; and r30=r30,r27;; // also set shared_mem ipsr.i and ipsr.ic appropriately - ld8 r20=[r18];; - extr.u r22=r20,32,32 - cmp4.eq p6,p7=r20,r0;; + ld8 r24=[r18];; + extr.u r22=r24,32,32 + cmp4.eq p6,p7=r24,r0;; (p6) dep r30=0,r30,IA64_PSR_IC_BIT,1 (p7) dep r30=-1,r30,IA64_PSR_IC_BIT,1 ;; cmp4.eq p6,p7=r22,r0;; @@ -520,13 +538,13 @@ GLOBAL_ENTRY(fast_break_reflect) // cover and set shared_mem precover_ifs to cr.ifs // set shared_mem ifs and incomplete_regframe to 0 cover ;; - mov r20=cr.ifs;; + mov r24=cr.ifs;; adds r21=XSI_INCOMPL_REG_OFS-XSI_PSR_IC_OFS,r18 ;; st4 [r21]=r0 ;; adds r21=XSI_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; st8 [r21]=r0 ;; adds r21=XSI_PRECOVER_IFS_OFS-XSI_PSR_IC_OFS,r18 ;; - st8 [r21]=r20 ;; + st8 [r21]=r24 ;; // vpsr.i = vpsr.ic = 0 on delivery of interruption st8 [r18]=r0;; // FIXME: need to save iipa and isr to be arch-compliant @@ -534,22 +552,30 @@ GLOBAL_ENTRY(fast_break_reflect) mov r22=IA64_KR(CURRENT);; adds r22=IA64_VCPU_IVA_OFFSET,r22;; ld8 r23=[r22];; - movl r24=0x2c00;; - add r24=r24,r23;; - mov cr.iip=r24;; + add r20=r20,r23;; + mov cr.iip=r20;; // OK, now all set to go except for switch to virtual bank0 mov r30=r2; mov r29=r3;; adds r2=XSI_BANK1_OFS-XSI_PSR_IC_OFS,r18; adds r3=(XSI_BANK1_OFS+8)-XSI_PSR_IC_OFS,r18;; bsw.1;; - st8 [r2]=r16,16; st8 [r3]=r17,16 ;; - st8 [r2]=r18,16; st8 [r3]=r19,16 ;; - st8 [r2]=r20,16; st8 [r3]=r21,16 ;; - st8 [r2]=r22,16; st8 [r3]=r23,16 ;; - st8 [r2]=r24,16; st8 [r3]=r25,16 ;; - st8 [r2]=r26,16; st8 [r3]=r27,16 ;; - st8 [r2]=r28,16; st8 [r3]=r29,16 ;; - st8 [r2]=r30,16; st8 [r3]=r31,16 ;; + // FIXME: need to handle ar.unat! + .mem.offset 0,0; st8.spill [r2]=r16,16; + .mem.offset 8,0; st8.spill [r3]=r17,16 ;; + .mem.offset 0,0; st8.spill [r2]=r18,16; + .mem.offset 8,0; st8.spill [r3]=r19,16 ;; + .mem.offset 0,0; st8.spill [r2]=r20,16; + .mem.offset 8,0; st8.spill [r3]=r21,16 ;; + .mem.offset 0,0; st8.spill [r2]=r22,16; + .mem.offset 8,0; st8.spill [r3]=r23,16 ;; + .mem.offset 0,0; st8.spill [r2]=r24,16; + .mem.offset 8,0; st8.spill [r3]=r25,16 ;; + .mem.offset 0,0; st8.spill [r2]=r26,16; + .mem.offset 8,0; st8.spill [r3]=r27,16 ;; + .mem.offset 0,0; st8.spill [r2]=r28,16; + .mem.offset 8,0; st8.spill [r3]=r29,16 ;; + .mem.offset 0,0; st8.spill [r2]=r30,16; + .mem.offset 8,0; st8.spill [r3]=r31,16 ;; movl r31=XSI_IPSR;; bsw.0 ;; mov r2=r30; mov r3=r29;; @@ -559,6 +585,41 @@ GLOBAL_ENTRY(fast_break_reflect) rfi ;; +// reflect access faults (0x2400,0x2800,0x5300) directly to domain +// r16 == isr +// r17 == ifa +// r19 == reflect number (only pass-thru to dispatch_reflection) +// r20 == offset into ivt +// r31 == pr +GLOBAL_ENTRY(fast_access_reflect) + mov r30=cr.ipsr;; + mov r29=cr.iip;; + extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; + cmp.ne p7,p0=r21,r0 +(p7) br.spnt.few dispatch_reflection ;; + extr.u r21=r30,IA64_PSR_PP_BIT,1 ;; + cmp.ne p7,p0=r21,r0 +(p7) br.spnt.few dispatch_reflection ;; + extr.u r21=r30,IA64_PSR_CPL0_BIT,2 ;; + cmp.eq p7,p0=r21,r0 +(p7) br.spnt.few dispatch_reflection ;; + movl r18=XSI_PSR_IC;; + ld8 r21=[r18];; + cmp.eq p7,p0=r0,r21 +(p7) br.spnt.few dispatch_reflection ;; + // set shared_mem ifa, FIXME: should we validate it? + mov r17=cr.ifa;; + adds r21=XSI_IFA_OFS-XSI_PSR_IC_OFS,r18 ;; + st8 [r21]=r17 ;; + // get rr[ifa] and save to itir in shared memory (extra bits ignored) + shr.u r22=r17,61 + adds r23=XSI_ITIR_OFS-XSI_PSR_IC_OFS,r18 + adds r21=XSI_RR0_OFS-XSI_PSR_IC_OFS,r18 ;; + shladd r22=r22,3,r21;; + ld8 r22=[r22];; + st8 [r23]=r22;; + br.cond.sptk.many fast_reflect;; + // ensure that, if giving up, registers at entry to fast_hyperprivop unchanged ENTRY(hyper_rfi) @@ -1312,8 +1373,146 @@ ENTRY(hyper_set_rr) ;; END(hyper_set_rr) +// this routine was derived from optimized assembly output from +// vcpu_thash so it is dense and difficult to read but it works +// On entry: +// r18 == XSI_PSR_IC +// r31 == pr +GLOBAL_ENTRY(hyper_thash) +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_THASH);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + shr.u r20 = r8, 61 + addl r25 = 1, r0 + movl r17 = 0xe000000000000000 + ;; + and r21 = r17, r8 // VHPT_Addr1 + ;; + shladd r28 = r20, 3, r18 + adds r19 = XSI_PTA_OFS-XSI_PSR_IC_OFS, r18 + ;; + adds r27 = XSI_RR0_OFS-XSI_PSR_IC_OFS, r28 + addl r28 = 32767, r0 + ld8 r24 = [r19] // pta + ;; + ld8 r23 = [r27] // rrs[vadr>>61] + extr.u r26 = r24, 2, 6 + ;; + extr.u r22 = r23, 2, 6 + shl r30 = r25, r26 + ;; + shr.u r19 = r8, r22 + shr.u r29 = r24, 15 + ;; + adds r17 = -1, r30 + ;; + shladd r27 = r19, 3, r0 + extr.u r26 = r17, 15, 46 + ;; + andcm r24 = r29, r26 + and r19 = r28, r27 + shr.u r25 = r27, 15 + ;; + and r23 = r26, r25 + ;; + or r22 = r24, r23 + ;; + dep.z r20 = r22, 15, 46 + ;; + or r16 = r20, r21 + ;; + or r8 = r19, r16 + // done, update iip/ipsr to next instruction + mov r24=cr.ipsr + mov r25=cr.iip;; + extr.u r26=r24,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r25=16,r25 +(p7) adds r26=1,r26 + ;; + dep r24=r26,r24,41,2 + ;; + mov cr.ipsr=r24 + mov cr.iip=r25 + mov pr=r31,-1 ;; + rfi + ;; +END(hyper_thash) + ENTRY(hyper_ptc_ga) - br.spnt.many dispatch_break_fault ;; +#ifdef CONFIG_SMP +FIXME: ptc.ga instruction requires spinlock for SMP +#endif + // FIXME: validate not flushing Xen addresses +#ifdef FAST_HYPERPRIVOP_CNT + movl r20=fast_hyperpriv_cnt+(8*XEN_HYPER_PTC_GA);; + ld8 r21=[r20];; + adds r21=1,r21;; + st8 [r20]=r21;; +#endif + mov r28=r8 + extr.u r19=r9,2,6 // addr_range=1<<((r9&0xfc)>>2) + mov r20=1 + shr.u r24=r8,61 + addl r27=56,r0 // PAGE_SHIFT<<2 (for ptc.ga) + movl r26=0x8000000000000000 // INVALID_TI_TAG + mov r30=ar.lc + ;; + shl r19=r20,r19 + cmp.eq p7,p0=7,r24 +(p7) br.spnt.many dispatch_break_fault ;; // slow way for rr7 + ;; + cmp.le p7,p0=r19,r0 // skip flush if size<=0 +(p7) br.cond.dpnt 2f ;; + extr.u r24=r19,0,PAGE_SHIFT + shr.u r23=r19,PAGE_SHIFT ;; // repeat loop for n pages + cmp.ne p7,p0=r24,r0 ;; +(p7) adds r23=1,r23 ;; // n_pagesti_tag = 1 + st8 [r25]=r24 + ptc.ga r28,r27 ;; + srlz.i ;; + add r28=r29,r28 + br.cloop.sptk.few 1b + ;; +2: + mov ar.lc=r30 ;; + mov r29=cr.ipsr + mov r30=cr.iip;; + mov r27=IA64_KR(CURRENT);; + adds r25=IA64_VCPU_DTLB_OFFSET,r27 + adds r26=IA64_VCPU_ITLB_OFFSET,r27;; + ld8 r24=[r25] + ld8 r27=[r26] ;; + and r24=-2,r24 + and r27=-2,r27 ;; + st8 [r25]=r24 // set 1-entry i/dtlb as not present + st8 [r26]=r27 ;; + // increment to point to next instruction + extr.u r26=r29,41,2 ;; + cmp.eq p6,p7=2,r26 ;; +(p6) mov r26=0 +(p6) adds r30=16,r30 +(p7) adds r26=1,r26 + ;; + dep r29=r26,r29,41,2 + ;; + mov cr.ipsr=r29 + mov cr.iip=r30 + mov pr=r31,-1 ;; + rfi + ;; END(hyper_ptc_ga) ENTRY(hyper_itc_d) @@ -1323,5 +1522,3 @@ END(hyper_itc_d) ENTRY(hyper_itc_i) br.spnt.many dispatch_break_fault ;; END(hyper_itc_i) - -// ignore me diff --git a/xen/arch/ia64/ivt.S b/xen/arch/ia64/ivt.S index 37ae794366..6530783e67 100644 --- a/xen/arch/ia64/ivt.S +++ b/xen/arch/ia64/ivt.S @@ -666,7 +666,12 @@ END(dirty_bit) // 0x2400 Entry 9 (size 64 bundles) Instruction Access-bit (27) ENTRY(iaccess_bit) #ifdef XEN - REFLECT(9) + mov r31=pr; + mov r16=cr.isr + mov r17=cr.ifa + mov r19=9 + movl r20=0x2400 + br.sptk.many fast_access_reflect;; #endif DBG_FAULT(9) // Like Entry 8, except for instruction access @@ -734,7 +739,12 @@ END(iaccess_bit) // 0x2800 Entry 10 (size 64 bundles) Data Access-bit (15,55) ENTRY(daccess_bit) #ifdef XEN - REFLECT(10) + mov r31=pr; + mov r16=cr.isr + mov r17=cr.ifa + mov r19=10 + movl r20=0x2800 + br.sptk.many fast_access_reflect;; #endif DBG_FAULT(10) // Like Entry 8, except for data access @@ -1395,7 +1405,12 @@ END(iaccess_rights) // 0x5300 Entry 23 (size 16 bundles) Data Access Rights (14,53) ENTRY(daccess_rights) #ifdef XEN - REFLECT(23) + mov r31=pr; + mov r16=cr.isr + mov r17=cr.ifa + mov r19=23 + movl r20=0x5300 + br.sptk.many fast_access_reflect;; #endif DBG_FAULT(23) mov r16=cr.ifa @@ -1821,7 +1836,7 @@ END(ia32_interrupt) #ifdef XEN .org ia64_ivt+0x8000 -ENTRY(dispatch_reflection) +GLOBAL_ENTRY(dispatch_reflection) /* * Input: * psr.ic: off From a608bc4566fd9f5fe5cb74e2143e062350cffdfe Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Sat, 9 Jul 2005 07:58:56 -0700 Subject: [PATCH 05/12] Intel's pre-bk->hg transition patches Signed-off-by Eddie Dong Signed-off-by Anthony Xu Signed-off-by Kevin Tian --- xen/arch/ia64/Makefile | 2 +- xen/arch/ia64/asm-offsets.c | 1 + xen/arch/ia64/domain.c | 127 ++++++- xen/arch/ia64/mm.c | 17 +- xen/arch/ia64/mmio.c | 544 +++++++++++++++++----------- xen/arch/ia64/pal_emul.c | 283 +++++++++++++++ xen/arch/ia64/vlsapic.c | 223 ++++++++---- xen/arch/ia64/vmx_entry.S | 2 +- xen/arch/ia64/vmx_hypercall.c | 24 +- xen/arch/ia64/vmx_init.c | 23 +- xen/arch/ia64/vmx_ivt.S | 54 ++- xen/arch/ia64/vmx_minstate.h | 6 +- xen/arch/ia64/vmx_phy_mode.c | 101 ++++-- xen/arch/ia64/vmx_process.c | 57 ++- xen/arch/ia64/vmx_support.c | 159 ++++++++ xen/arch/ia64/vmx_vcpu.c | 39 +- xen/arch/ia64/vmx_virt.c | 15 +- xen/arch/ia64/vtlb.c | 9 +- xen/arch/ia64/xensetup.c | 1 - xen/include/asm-ia64/config.h | 1 + xen/include/asm-ia64/domain.h | 4 +- xen/include/asm-ia64/privop.h | 18 + xen/include/asm-ia64/vmx.h | 2 + xen/include/asm-ia64/vmx_phy_mode.h | 1 + xen/include/asm-ia64/vmx_vcpu.h | 22 +- xen/include/asm-ia64/vmx_vpd.h | 8 +- xen/include/asm-ia64/xenprocessor.h | 10 + xen/include/asm-ia64/xensystem.h | 2 + xen/include/public/arch-ia64.h | 10 + 29 files changed, 1371 insertions(+), 394 deletions(-) create mode 100644 xen/arch/ia64/pal_emul.c create mode 100644 xen/arch/ia64/vmx_support.c diff --git a/xen/arch/ia64/Makefile b/xen/arch/ia64/Makefile index d2be0994ab..5e497818cc 100644 --- a/xen/arch/ia64/Makefile +++ b/xen/arch/ia64/Makefile @@ -15,7 +15,7 @@ OBJS = xensetup.o setup.o time.o irq.o ia64_ksyms.o process.o smp.o \ ifeq ($(CONFIG_VTI),y) OBJS += vmx_init.o vmx_virt.o vmx_vcpu.o vmx_process.o vmx_vsa.o vmx_ivt.o \ vmx_phy_mode.o vmx_utility.o vmx_interrupt.o vmx_entry.o vmmu.o \ - vtlb.o mmio.o vlsapic.o vmx_hypercall.o mm.o + vtlb.o mmio.o vlsapic.o vmx_hypercall.o mm.o vmx_support.o pal_emul.o endif # perfmon.o # unwind.o needed for kernel unwinding (rare) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index 9c2326a6a0..43589b6586 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -224,6 +224,7 @@ void foo(void) #ifdef CONFIG_VTI DEFINE(IA64_VPD_BASE_OFFSET, offsetof (struct vcpu, arch.arch_vmx.vpd)); + DEFINE(IA64_VLSAPIC_INSVC_BASE_OFFSET, offsetof (struct vcpu, arch.arch_vmx.in_service[0])); DEFINE(IA64_VPD_CR_VPTA_OFFSET, offsetof (cr_t, pta)); DEFINE(XXX_THASH_SIZE, sizeof (thash_data_t)); diff --git a/xen/arch/ia64/domain.c b/xen/arch/ia64/domain.c index c6ead10510..5929f17d11 100644 --- a/xen/arch/ia64/domain.c +++ b/xen/arch/ia64/domain.c @@ -37,10 +37,13 @@ #include /* for IA64_THREAD_INFO_SIZE */ #include /* for function declarations */ +#include #ifdef CONFIG_VTI #include #include +#include #include +#include #endif // CONFIG_VTI #define CONFIG_DOMAIN0_CONTIGUOUS @@ -203,18 +206,20 @@ void arch_do_createdomain(struct vcpu *v) * after up. */ d->shared_info = (void *)alloc_xenheap_page(); - - /* FIXME: Because full virtual cpu info is placed in this area, - * it's unlikely to put it into one shareinfo page. Later - * need split vcpu context from vcpu_info and conforms to - * normal xen convention. + /* Now assume all vcpu info and event indicators can be + * held in one shared page. Definitely later we need to + * consider more about it */ - v->vcpu_info = (void *)alloc_xenheap_page(); - if (!v->vcpu_info) { - printk("ERROR/HALTING: CAN'T ALLOC PAGE\n"); - while (1); + + memset(d->shared_info, 0, PAGE_SIZE); + v->vcpu_info = &d->shared_info->vcpu_data[v->vcpu_id]; + /* Mask all events, and specific port will be unmasked + * when customer subscribes to it. + */ + if(v == d->vcpu[0]) { + memset(&d->shared_info->evtchn_mask[0], 0xff, + sizeof(d->shared_info->evtchn_mask)); } - memset(v->vcpu_info, 0, PAGE_SIZE); /* Allocate per-domain vTLB and vhpt */ v->arch.vtlb = init_domain_tlb(v); @@ -291,6 +296,7 @@ void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c) c->shared = v->domain->shared_info->arch; } +#ifndef CONFIG_VTI int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) { struct pt_regs *regs = (struct pt_regs *) ((unsigned long) v + IA64_STK_OFFSET) - 1; @@ -312,6 +318,79 @@ int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) v->domain->shared_info->arch = c->shared; return 0; } +#else // CONFIG_VTI +int arch_set_info_guest( + struct vcpu *v, struct vcpu_guest_context *c) +{ + struct domain *d = v->domain; + int i, rc, ret; + unsigned long progress = 0; + + if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) + return 0; + + /* Lazy FP not implemented yet */ + clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags); + if ( c->flags & VGCF_FPU_VALID ) + set_bit(_VCPUF_fpu_initialised, &v->vcpu_flags); + + /* Sync d/i cache conservatively, after domain N is loaded */ + ret = ia64_pal_cache_flush(3, 0, &progress, NULL); + if (ret != PAL_STATUS_SUCCESS) + panic("PAL CACHE FLUSH failed for dom[%d].\n", + v->domain->domain_id); + DPRINTK("Sync i/d cache for dom%d image SUCC\n", + v->domain->domain_id); + + /* Physical mode emulation initialization, including + * emulation ID allcation and related memory request + */ + physical_mode_init(v); + + /* FIXME: only support PMT table continuously by far */ + d->arch.pmt = __va(c->pt_base); + d->arch.max_pfn = c->pt_max_pfn; + v->arch.arch_vmx.vmx_platform.shared_page_va = __va(c->share_io_pg); + memset((char *)__va(c->share_io_pg),0,PAGE_SIZE); + + if (c->flags & VGCF_VMX_GUEST) { + if (!vmx_enabled) + panic("No VMX hardware feature for vmx domain.\n"); + + vmx_final_setup_domain(d); + + /* One more step to enable interrupt assist */ + set_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags); + } + + vlsapic_reset(v); + vtm_init(v); + + /* Only open one port for I/O and interrupt emulation */ + if (v == d->vcpu[0]) { + memset(&d->shared_info->evtchn_mask[0], 0xff, + sizeof(d->shared_info->evtchn_mask)); + clear_bit(IOPACKET_PORT, &d->shared_info->evtchn_mask[0]); + } + /* Setup domain context. Actually IA-64 is a bit different with + * x86, with almost all system resources better managed by HV + * directly. CP only needs to provide start IP of guest, which + * ideally is the load address of guest Firmware. + */ + new_thread(v, c->guest_iip, 0, 0); + + + d->xen_vastart = 0xf000000000000000; + d->xen_vaend = 0xf300000000000000; + d->arch.breakimm = 0x1000 + d->domain_id; + v->arch._thread.on_ustack = 0; + + /* Don't redo final setup */ + set_bit(_VCPUF_initialised, &v->vcpu_flags); + + return 0; +} +#endif // CONFIG_VTI void arch_do_boot_vcpu(struct vcpu *v) { @@ -361,7 +440,10 @@ void new_thread(struct vcpu *v, init_all_rr(v); if (VMX_DOMAIN(v)) { - VMX_VPD(v,vgr[12]) = dom_fw_setup(d,saved_command_line,256L); + if (d == dom0) { + VMX_VPD(v,vgr[12]) = dom_fw_setup(d,saved_command_line,256L); + printk("new_thread, done with dom_fw_setup\n"); + } /* Virtual processor context setup */ VMX_VPD(v, vpsr) = IA64_PSR_BN; VPD_CR(v, dcr) = 0; @@ -556,6 +638,7 @@ tryagain: } // FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE +#ifndef CONFIG_VTI unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) { unsigned long pte = lookup_domain_mpa(d,mpaddr); @@ -566,6 +649,14 @@ unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) imva |= mpaddr & ~PAGE_MASK; return(imva); } +#else // CONFIG_VTI +unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) +{ + unsigned long imva = __gpa_to_mpa(d, mpaddr); + + return __va(imva); +} +#endif // CONFIG_VTI // remove following line if not privifying in memory //#define HAVE_PRIVIFY_MEMORY @@ -812,6 +903,17 @@ void build_shared_info(struct domain *d) /* ... */ } +/* + * Domain 0 has direct access to all devices absolutely. However + * the major point of this stub here, is to allow alloc_dom_mem + * handled with order > 0 request. Dom0 requires that bit set to + * allocate memory for other domains. + */ +void physdev_init_dom0(struct domain *d) +{ + set_bit(_DOMF_physdev_access, &d->domain_flags); +} + extern unsigned long running_on_sim; unsigned int vmx_dom0 = 0; int construct_dom0(struct domain *d, @@ -963,6 +1065,7 @@ int construct_dom0(struct domain *d, set_bit(_DOMF_constructed, &d->domain_flags); new_thread(v, pkern_entry, 0, 0); + physdev_init_dom0(d); // FIXME: Hack for keyboard input #ifdef CLONE_DOMAIN0 if (d == dom0) @@ -978,6 +1081,8 @@ if (d == dom0) return 0; } + + #else //CONFIG_VTI int construct_dom0(struct domain *d, diff --git a/xen/arch/ia64/mm.c b/xen/arch/ia64/mm.c index 755596f89e..deeccbbe67 100644 --- a/xen/arch/ia64/mm.c +++ b/xen/arch/ia64/mm.c @@ -95,7 +95,7 @@ #include #include #include - +#include /* uregs->ptr is virtual address uregs->val is pte value @@ -109,8 +109,9 @@ int do_mmu_update(mmu_update_t *ureqs,u64 count,u64 *pdone,u64 foreigndom) mmu_update_t req; ia64_rr rr; thash_cb_t *hcb; - thash_data_t entry={0}; + thash_data_t entry={0},*ovl; vcpu = current; + search_section_t sections; hcb = vmx_vcpu_get_vtlb(vcpu); for ( i = 0; i < count; i++ ) { @@ -124,8 +125,18 @@ int do_mmu_update(mmu_update_t *ureqs,u64 count,u64 *pdone,u64 foreigndom) entry.cl = DSIDE_TLB; rr = vmx_vcpu_rr(vcpu, req.ptr); entry.ps = rr.ps; + entry.key = redistribute_rid(rr.rid); entry.rid = rr.rid; - vtlb_insert(hcb, &entry, req.ptr); + entry.vadr = PAGEALIGN(req.ptr,entry.ps); + sections.tr = 1; + sections.tc = 0; + ovl = thash_find_overlap(hcb, &entry, sections); + if (ovl) { + // generate MCA. + panic("Tlb conflict!!"); + return; + } + thash_purge_and_insert(hcb, &entry); }else if(cmd == MMU_MACHPHYS_UPDATE){ mfn = req.ptr >>PAGE_SHIFT; gpfn = req.val; diff --git a/xen/arch/ia64/mmio.c b/xen/arch/ia64/mmio.c index 2fb5c34251..6a3f4873c6 100644 --- a/xen/arch/ia64/mmio.c +++ b/xen/arch/ia64/mmio.c @@ -27,7 +27,13 @@ #include #include #include +#include +#include +#include +#include +#include +/* struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) { int i; @@ -37,215 +43,14 @@ struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) } return NULL; } - - -extern void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma); -static inline void mmio_write(VCPU *vcpu, void *src, u64 dest_pa, size_t s, int ma) -{ - struct virutal_platform_def *v_plat; - struct mmio_list *mio; - - v_plat = vmx_vcpu_get_plat(vcpu); - mio = lookup_mmio(dest_pa, v_plat->mmio); - if ( mio == NULL ) - panic ("Wrong address for MMIO\n"); - - switch (mio->iot) { - case PIB_MMIO: - pib_write(vcpu, src, dest_pa - v_plat->pib_base, s, ma); - break; - case VGA_BUFF: - case CHIPSET_IO: - case LOW_MMIO: - case LEGACY_IO: - case IO_SAPIC: - default: - break; - } - return; -} - -static inline void mmio_read(VCPU *vcpu, u64 src_pa, void *dest, size_t s, int ma) -{ - struct virutal_platform_def *v_plat; - struct mmio_list *mio; - - v_plat = vmx_vcpu_get_plat(vcpu); - mio = lookup_mmio(src_pa, v_plat->mmio); - if ( mio == NULL ) - panic ("Wrong address for MMIO\n"); - - switch (mio->iot) { - case PIB_MMIO: - pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma); - break; - case VGA_BUFF: - case CHIPSET_IO: - case LOW_MMIO: - case LEGACY_IO: - case IO_SAPIC: - default: - break; - } - return; -} - -/* - * Read or write data in guest virtual address mode. - */ - -void -memwrite_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s) -{ - uint64_t pa; - - if (!vtlb->nomap) - panic("Normal memory write shouldn't go to this point!"); - pa = PPN_2_PA(vtlb->ppn); - pa += POFFSET((u64)dest, vtlb->ps); - mmio_write (vcpu, src, pa, s, vtlb->ma); -} - - -void -memwrite_p(VCPU *vcpu, void *src, void *dest, size_t s) -{ - uint64_t pa = (uint64_t)dest; - int ma; - - if ( pa & (1UL <<63) ) { - // UC - ma = 4; - pa <<=1; - pa >>=1; - } - else { - // WBL - ma = 0; // using WB for WBL - } - mmio_write (vcpu, src, pa, s, ma); -} - -void -memread_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s) -{ - uint64_t pa; - - if (!vtlb->nomap) - panic("Normal memory write shouldn't go to this point!"); - pa = PPN_2_PA(vtlb->ppn); - pa += POFFSET((u64)src, vtlb->ps); - - mmio_read(vcpu, pa, dest, s, vtlb->ma); -} - -void -memread_p(VCPU *vcpu, void *src, void *dest, size_t s) -{ - uint64_t pa = (uint64_t)src; - int ma; - - if ( pa & (1UL <<63) ) { - // UC - ma = 4; - pa <<=1; - pa >>=1; - } - else { - // WBL - ma = 0; // using WB for WBL - } - mmio_read(vcpu, pa, dest, s, ma); -} +*/ #define PIB_LOW_HALF(ofst) !(ofst&(1<<20)) #define PIB_OFST_INTA 0x1E0000 #define PIB_OFST_XTP 0x1E0008 - -/* - * Deliver IPI message. (Only U-VP is supported now) - * offset: address offset to IPI space. - * value: deliver value. - */ -static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector) +static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) { -#ifdef IPI_DEBUG - printf ("deliver_ipi %lx %lx\n",dm,vector); -#endif - switch ( dm ) { - case 0: // INT - vmx_vcpu_pend_interrupt (vcpu, vector); - break; - case 2: // PMI - // TODO -- inject guest PMI - panic ("Inject guest PMI!\n"); - break; - case 4: // NMI - vmx_vcpu_pend_interrupt (vcpu, 2); - break; - case 5: // INIT - // TODO -- inject guest INIT - panic ("Inject guest INIT!\n"); - break; - case 7: // ExtINT - vmx_vcpu_pend_interrupt (vcpu, 0); - break; - - case 1: - case 3: - case 6: - default: - panic ("Deliver reserved IPI!\n"); - break; - } -} - -/* - * TODO: Use hash table for the lookup. - */ -static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid) -{ - int i; - VCPU *vcpu; - LID lid; - - for (i=0; ivcpu[i]; - lid.val = VPD_CR(vcpu, lid); - if ( lid.id == id && lid.eid == eid ) { - return vcpu; - } - } - return NULL; -} - -/* - * execute write IPI op. - */ -static int write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value) -{ - VCPU *target_cpu; - - target_cpu = lid_2_vcpu(vcpu->domain, - ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid); - if ( target_cpu == NULL ) panic("Unknown IPI cpu\n"); - if ( target_cpu == vcpu ) { - // IPI to self - deliver_ipi (vcpu, ((ipi_d_t)value).dm, - ((ipi_d_t)value).vector); - return 1; - } - else { - // TODO: send Host IPI to inject guest SMP IPI interruption - panic ("No SM-VP supported!\n"); - return 0; - } -} - -void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) -{ - switch (pib_off) { case PIB_OFST_INTA: panic("Undefined write on PIB INTA\n"); @@ -276,7 +81,7 @@ void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) } } -void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) +static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) { switch (pib_off) { case PIB_OFST_INTA: @@ -323,3 +128,334 @@ void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) } } +static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + unsigned long addr; + + vio = (vcpu_iodata_t *) v->arch.arch_vmx.vmx_platform.shared_page_va; + if (vio == 0) { + panic("bad shared page: %lx", (unsigned long)vio); + } + p = &vio->vp_ioreq; + p->addr = pa; + p->size = 1<count = 1; + p->dir = dir; + if(dir==IOREQ_WRITE) //write; + p->u.data = *val; + p->pdata_valid = 0; + p->port_mm = 1; + p->df = 0; + + set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + p->state = STATE_IOREQ_READY; + evtchn_send(IOPACKET_PORT); + vmx_wait_io(); + if(dir){ //read + *val=p->u.data; + } + return; +} +#define TO_LEGACY_IO(pa) (((pa)>>12<<2)|((pa)&0x3)) + +static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) +{ + struct vcpu *v = current; + vcpu_iodata_t *vio; + ioreq_t *p; + unsigned long addr; + + vio = (vcpu_iodata_t *) v->arch.arch_vmx.vmx_platform.shared_page_va; + if (vio == 0) { + panic("bad shared page: %lx"); + } + p = &vio->vp_ioreq; + p->addr = TO_LEGACY_IO(pa&0x3ffffffUL); + p->size = 1<count = 1; + p->dir = dir; + if(dir==IOREQ_WRITE) //write; + p->u.data = *val; + p->pdata_valid = 0; + p->port_mm = 0; + p->df = 0; + + set_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + p->state = STATE_IOREQ_READY; + evtchn_send(IOPACKET_PORT); + vmx_wait_io(); + if(dir){ //read + *val=p->u.data; + } + return; +} + +static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int dir) +{ + struct virutal_platform_def *v_plat; + //mmio_type_t iot; + unsigned long iot; + iot=__gpfn_is_io(vcpu->domain, src_pa>>PAGE_SHIFT); + v_plat = vmx_vcpu_get_plat(vcpu); + + switch (iot) { + case GPFN_PIB: + if(!dir) + pib_write(vcpu, src_pa - v_plat->pib_base, dest, s, ma); + else + pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma); + break; + case GPFN_GFW: + break; + case GPFN_FRAME_BUFFER: + case GPFN_LOW_MMIO: + low_mmio_access(vcpu, src_pa, dest, s, dir); + break; + case GPFN_LEGACY_IO: + legacy_io_access(vcpu, src_pa, dest, s, dir); + break; + case GPFN_IOSAPIC: + default: + panic("Bad I/O access\n"); + break; + } + return; +} + +/* + * Read or write data in guest virtual address mode. + */ +/* +void +memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa; + + if (!vtlb->nomap) + panic("Normal memory write shouldn't go to this point!"); + pa = PPN_2_PA(vtlb->ppn); + pa += POFFSET((u64)dest, vtlb->ps); + mmio_write (vcpu, src, pa, s, vtlb->ma); +} + + +void +memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa = (uint64_t)dest; + int ma; + + if ( pa & (1UL <<63) ) { + // UC + ma = 4; + pa <<=1; + pa >>=1; + } + else { + // WBL + ma = 0; // using WB for WBL + } + mmio_write (vcpu, src, pa, s, ma); +} + +void +memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa; + + if (!vtlb->nomap) + panic("Normal memory write shouldn't go to this point!"); + pa = PPN_2_PA(vtlb->ppn); + pa += POFFSET((u64)src, vtlb->ps); + + mmio_read(vcpu, pa, dest, s, vtlb->ma); +} + +void +memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) +{ + uint64_t pa = (uint64_t)src; + int ma; + + if ( pa & (1UL <<63) ) { + // UC + ma = 4; + pa <<=1; + pa >>=1; + } + else { + // WBL + ma = 0; // using WB for WBL + } + mmio_read(vcpu, pa, dest, s, ma); +} +*/ + + +/* + * Deliver IPI message. (Only U-VP is supported now) + * offset: address offset to IPI space. + * value: deliver value. + */ +static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector) +{ +#ifdef IPI_DEBUG + printf ("deliver_ipi %lx %lx\n",dm,vector); +#endif + switch ( dm ) { + case 0: // INT + vmx_vcpu_pend_interrupt (vcpu, vector); + break; + case 2: // PMI + // TODO -- inject guest PMI + panic ("Inject guest PMI!\n"); + break; + case 4: // NMI + vmx_vcpu_pend_interrupt (vcpu, 2); + break; + case 5: // INIT + // TODO -- inject guest INIT + panic ("Inject guest INIT!\n"); + break; + case 7: // ExtINT + vmx_vcpu_pend_interrupt (vcpu, 0); + break; + case 1: + case 3: + case 6: + default: + panic ("Deliver reserved IPI!\n"); + break; + } +} + +/* + * TODO: Use hash table for the lookup. + */ +static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid) +{ + int i; + VCPU *vcpu; + LID lid; + for (i=0; ivcpu[i]; + lid.val = VPD_CR(vcpu, lid); + if ( lid.id == id && lid.eid == eid ) { + return vcpu; + } + } + return NULL; +} + +/* + * execute write IPI op. + */ +static int write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value) +{ + VCPU *target_cpu; + + target_cpu = lid_2_vcpu(vcpu->domain, + ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid); + if ( target_cpu == NULL ) panic("Unknown IPI cpu\n"); + if ( target_cpu == vcpu ) { + // IPI to self + deliver_ipi (vcpu, ((ipi_d_t)value).dm, + ((ipi_d_t)value).vector); + return 1; + } + else { + // TODO: send Host IPI to inject guest SMP IPI interruption + panic ("No SM-VP supported!\n"); + return 0; + } +} + + +/* + dir 1: read 0:write + inst_type 0:integer 1:floating point + */ +extern IA64_BUNDLE __vmx_get_domain_bundle(u64 iip); + + +void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) +{ + REGS *regs; + IA64_BUNDLE bundle; + int slot, dir, inst_type=0; + size_t size; + u64 data, value, slot1a, slot1b; + INST64 inst; + regs=vcpu_regs(vcpu); + bundle = __vmx_get_domain_bundle(regs->cr_iip); + slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; + if (!slot) inst.inst = bundle.slot0; + else if (slot == 1){ + slot1a=bundle.slot1a; + slot1b=bundle.slot1b; + inst.inst =slot1a + (slot1b<<18); + } + else if (slot == 2) inst.inst = bundle.slot2; + + if(inst.M1.major==4&&inst.M1.m==0&&inst.M1.x==0){ + inst_type=0; //fp + size=(inst.M1.x6&0x3); + if((inst.M1.x6>>2)>0xb){ // write + vmx_vcpu_get_gr(vcpu,inst.M4.r2,&data); + dir=IOREQ_WRITE; //write + }else if((inst.M1.x6>>2)<0xb){ // read + vmx_vcpu_get_gr(vcpu,inst.M1.r1,&value); + dir=IOREQ_READ; + }else{ + printf("This memory access instruction can't be emulated one : %lx\n",inst.inst); + while(1); + } + }else if(inst.M6.major==6&&inst.M6.m==0&&inst.M6.x==0&&inst.M6.x6==3){ + inst_type=1; //fp + dir=IOREQ_READ; + size=3; //ldfd + }else{ + printf("This memory access instruction can't be emulated two: %lx\n ",inst.inst); + while(1); + } + + if(dir==IOREQ_WRITE){ + mmio_access(vcpu, padr, &data, size, ma, dir); + }else{ + mmio_access(vcpu, padr, &data, size, ma, dir); + if(size==0) + data = (value & 0xffffffffffffff00U) | (data & 0xffU); + else if(size==1) + data = (value & 0xffffffffffff0000U) | (data & 0xffffU); + else if(size==2) + data = (value & 0xffffffff00000000U) | (data & 0xffffffffU); + + if(inst_type==0){ //gp + vmx_vcpu_set_gr(vcpu,inst.M1.r1,data,0); + }else{ + panic("Don't support ldfd now !"); +/* switch(inst.M6.f1){ + + case 6: + regs->f6=(struct ia64_fpreg)data; + case 7: + regs->f7=(struct ia64_fpreg)data; + case 8: + regs->f8=(struct ia64_fpreg)data; + case 9: + regs->f9=(struct ia64_fpreg)data; + case 10: + regs->f10=(struct ia64_fpreg)data; + case 11: + regs->f11=(struct ia64_fpreg)data; + default : + ia64_ldfs(inst.M6.f1,&data); + } +*/ + } + } + vmx_vcpu_increment_iip(vcpu); +} diff --git a/xen/arch/ia64/pal_emul.c b/xen/arch/ia64/pal_emul.c new file mode 100644 index 0000000000..f859f17bb0 --- /dev/null +++ b/xen/arch/ia64/pal_emul.c @@ -0,0 +1,283 @@ +/* PAL/SAL call delegation + * + * Copyright (c) 2004 Li Susie + * Copyright (c) 2005 Yu Ke + */ + +#include + +static void +get_pal_parameters (VCPU *vcpu, UINT64 *gr29, + UINT64 *gr30, UINT64 *gr31) { + + vmx_vcpu_get_gr(vcpu,29,gr29); + vmx_vcpu_get_gr(vcpu,30,gr30); + vmx_vcpu_get_gr(vcpu,31,gr31); +} + +static void +set_pal_result (VCPU *vcpu,struct ia64_pal_retval result) { + + vmx_vcpu_set_gr(vcpu,8, result.status,0); + vmx_vcpu_set_gr(vcpu,9, result.v0,0); + vmx_vcpu_set_gr(vcpu,10, result.v1,0); + vmx_vcpu_set_gr(vcpu,11, result.v2,0); +} + + +static struct ia64_pal_retval +pal_cache_flush (VCPU *vcpu) { + UINT64 gr28,gr29, gr30, gr31; + struct ia64_pal_retval result; + + get_pal_parameters (vcpu, &gr29, &gr30, &gr31); + vmx_vcpu_get_gr(vcpu,28,&gr28); + + /* Always call Host Pal in int=1 */ + gr30 = gr30 &(~(0x2UL)); + + /* call Host PAL cache flush */ + result=ia64_pal_call_static(gr28 ,gr29, gr30,gr31,1); // Clear psr.ic when call PAL_CACHE_FLUSH + + /* If host PAL call is interrupted, then loop to complete it */ +// while (result.status == 1) { +// ia64_pal_call_static(gr28 ,gr29, gr30, +// result.v1,1LL); +// } + while (result.status != 0) { + panic("PAL_CACHE_FLUSH ERROR, status %d", result.status); + } + + return result; +} + +static struct ia64_pal_retval +pal_vm_tr_read (VCPU *vcpu ) { +#warning pal_vm_tr_read: to be implemented + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + + +static struct ia64_pal_retval +pal_prefetch_visibility (VCPU *vcpu) { + /* Due to current MM virtualization algorithm, + * We do not allow guest to change mapping attribute. + * Thus we will not support PAL_PREFETCH_VISIBILITY + */ + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_platform_addr(VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= 0; //success + + return result; +} + +static struct ia64_pal_retval +pal_halt (VCPU *vcpu) { +#warning pal_halt: to be implemented + //bugbug: to be implement. + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + + +static struct ia64_pal_retval +pal_halt_light (VCPU *vcpu) { +#if 0 + // GVMM will go back to HVMM and ask HVMM to call yield(). + vmmdata.p_ctlblk->status = VM_OK; + vmmdata.p_ctlblk->ctlcode = ExitVM_YIELD; + + vmm_transition((UINT64)&vmmdata.p_gsa->guest, + (UINT64)&vmmdata.p_gsa->host, + (UINT64) vmmdata.p_tramp,0,0); + + + result.status = 0; + result.pal_result[0]=0; + result.pal_result[1]=0; + result.pal_result[2]=0; + + return result; +#endif + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_cache_read (VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_cache_write (VCPU *vcpu) { + struct ia64_pal_retval result; + + result.status= -1; //unimplemented + + return result; +} + +static struct ia64_pal_retval +pal_bus_get_features(VCPU *vcpu){ + +} + +static struct ia64_pal_retval +pal_cache_summary(VCPU *vcpu){ + +} + +static struct ia64_pal_retval +pal_cache_init(VCPU *vcpu){ + struct ia64_pal_retval result; + result.status=0; + return result; +} + +static struct ia64_pal_retval +pal_cache_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_cache_prot_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_cache_shared_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_mem_attrib(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_debug_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_fixed_addr(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_freq_base(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_freq_ratios(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_halt_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_logical_to_physica(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_perf_mon_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_proc_get_features(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_ptce_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_register_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_rse_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_test_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_summary(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_info(VCPU *vcpu){ +} + +static struct ia64_pal_retval +pal_vm_page_size(VCPU *vcpu){ +} + +void +pal_emul( VCPU *vcpu) { + UINT64 gr28; + struct ia64_pal_retval result; + + + vmx_vcpu_get_gr(vcpu,28,&gr28); //bank1 + + switch (gr28) { + case PAL_CACHE_FLUSH: + result = pal_cache_flush (vcpu); + break; + + case PAL_PREFETCH_VISIBILITY: + result = pal_prefetch_visibility (vcpu); + break; + + case PAL_VM_TR_READ: + result = pal_vm_tr_read (vcpu); + break; + + case PAL_HALT: + result = pal_halt (vcpu); + break; + + case PAL_HALT_LIGHT: + result = pal_halt_light (vcpu); + break; + + case PAL_CACHE_READ: + result = pal_cache_read (vcpu); + break; + + case PAL_CACHE_WRITE: + result = pal_cache_write (vcpu); + break; + + case PAL_PLATFORM_ADDR: + result = pal_platform_addr (vcpu); + break; + + default: + panic("pal_emul(): guest call unsupported pal" ); + } + set_pal_result (vcpu, result); +} + + diff --git a/xen/arch/ia64/vlsapic.c b/xen/arch/ia64/vlsapic.c index c25c91d1fa..29a3ef3a93 100644 --- a/xen/arch/ia64/vlsapic.c +++ b/xen/arch/ia64/vlsapic.c @@ -133,7 +133,7 @@ uint64_t vtm_get_itc(VCPU *vcpu) // FIXME: should use local_irq_disable & local_irq_enable ?? local_irq_save(spsr); guest_itc = now_itc(vtm); - update_last_itc(vtm, guest_itc); +// update_last_itc(vtm, guest_itc); local_irq_restore(spsr); return guest_itc; @@ -174,12 +174,12 @@ void vtm_set_itv(VCPU *vcpu) /* Interrupt must be disabled at this point */ extern u64 tick_to_ns(u64 tick); -#define TIMER_SLOP (50*1000) /* ns */ /* copy from ac_timer.c */ +#define TIMER_SLOP (50*1000) /* ns */ /* copy from ac_timer.c */ void vtm_interruption_update(VCPU *vcpu, vtime_t* vtm) { uint64_t cur_itc,vitm,vitv; uint64_t expires; - long diff_now, diff_last; + long diff_now, diff_last; uint64_t spsr; vitv = VPD_CR(vcpu, itv); @@ -237,21 +237,30 @@ void vtm_domain_in(VCPU *vcpu) #define NMI_VECTOR 2 #define ExtINT_VECTOR 0 - +#define NULL_VECTOR -1 #define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.arch_vmx.in_service[i]) -/* - * LID-CR64: Keep in vpd. - * IVR-CR65: (RO) see guest_read_ivr(). - * TPR-CR66: Keep in vpd, acceleration enabled. - * EOI-CR67: see guest_write_eoi(). - * IRR0-3 - CR68-71: (RO) Keep in vpd irq_pending[] - * can move to vpd for optimization. - * ITV: in time virtualization. - * PMV: Keep in vpd initialized as 0x10000. - * CMCV: Keep in vpd initialized as 0x10000. - * LRR0-1: Keep in vpd, initialized as 0x10000. - * - */ +static void update_vhpi(VCPU *vcpu, int vec) +{ + u64 vhpi; + if ( vec == NULL_VECTOR ) { + vhpi = 0; + } + else if ( vec == NMI_VECTOR ) { // NMI + vhpi = 32; + } else if (vec == ExtINT_VECTOR) { //ExtINT + vhpi = 16; + } + else { + vhpi = vec / 16; + } + + VMX_VPD(vcpu,vhpi) = vhpi; + // TODO: Add support for XENO + if ( VMX_VPD(vcpu,vac).a_int ) { + ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT, + (uint64_t) &(vcpu->arch.arch_vmx.vpd), 0, 0,0,0,0,0); + } +} void vlsapic_reset(VCPU *vcpu) { @@ -268,9 +277,11 @@ void vlsapic_reset(VCPU *vcpu) VPD_CR(vcpu, cmcv) = 0x10000; VPD_CR(vcpu, lrr0) = 0x10000; // default reset value? VPD_CR(vcpu, lrr1) = 0x10000; // default reset value? + update_vhpi(vcpu, NULL_VECTOR); for ( i=0; i<4; i++) { VLSAPIC_INSVC(vcpu,i) = 0; } + DPRINTK("VLSAPIC inservice base=%lp\n", &VLSAPIC_INSVC(vcpu,0) ); } /* @@ -281,7 +292,7 @@ void vlsapic_reset(VCPU *vcpu) */ static __inline__ int highest_bits(uint64_t *dat) { - uint64_t bits, bitnum=-1; + uint64_t bits, bitnum; int i; /* loop for all 256 bits */ @@ -292,12 +303,12 @@ static __inline__ int highest_bits(uint64_t *dat) return i*64+bitnum; } } - return -1; + return NULL_VECTOR; } /* * Return 0-255 for pending irq. - * -1 when no pending. + * NULL_VECTOR: when no pending. */ static int highest_pending_irq(VCPU *vcpu) { @@ -320,7 +331,7 @@ static int highest_inservice_irq(VCPU *vcpu) static int is_higher_irq(int pending, int inservice) { return ( (pending >> 4) > (inservice>>4) || - ((pending != -1) && (inservice == -1)) ); + ((pending != NULL_VECTOR) && (inservice == NULL_VECTOR)) ); } static int is_higher_class(int pending, int mic) @@ -333,40 +344,96 @@ static int is_invalid_irq(int vec) return (vec == 1 || ((vec <= 14 && vec >= 3))); } +#define IRQ_NO_MASKED 0 +#define IRQ_MASKED_BY_VTPR 1 +#define IRQ_MASKED_BY_INSVC 2 // masked by inservice IRQ + /* See Table 5-8 in SDM vol2 for the definition */ static int -irq_masked(VCPU *vcpu, int h_pending, int h_inservice) +_xirq_masked(VCPU *vcpu, int h_pending, int h_inservice) { - uint64_t vtpr; + tpr_t vtpr; + uint64_t mmi; - vtpr = VPD_CR(vcpu, tpr); + vtpr.val = VPD_CR(vcpu, tpr); - if ( h_pending == NMI_VECTOR && h_inservice != NMI_VECTOR ) + if ( h_inservice == NMI_VECTOR ) { + return IRQ_MASKED_BY_INSVC; + } + if ( h_pending == NMI_VECTOR ) { // Non Maskable Interrupt - return 0; + return IRQ_NO_MASKED; + } + if ( h_inservice == ExtINT_VECTOR ) { + return IRQ_MASKED_BY_INSVC; + } + mmi = vtpr.mmi; + if ( h_pending == ExtINT_VECTOR ) { + if ( mmi ) { + // mask all external IRQ + return IRQ_MASKED_BY_VTPR; + } + else { + return IRQ_NO_MASKED; + } + } - if ( h_pending == ExtINT_VECTOR && h_inservice >= 16) - return (vtpr>>16)&1; // vtpr.mmi - - if ( !(vtpr&(1UL<<16)) && - is_higher_irq(h_pending, h_inservice) && - is_higher_class(h_pending, (vtpr>>4)&0xf) ) - return 0; - - return 1; + if ( is_higher_irq(h_pending, h_inservice) ) { + if ( !mmi && is_higher_class(h_pending, vtpr.mic) ) { + return IRQ_NO_MASKED; + } + else { + return IRQ_MASKED_BY_VTPR; + } + } + else { + return IRQ_MASKED_BY_INSVC; + } } +static int irq_masked(VCPU *vcpu, int h_pending, int h_inservice) +{ + int mask; + + mask = _xirq_masked(vcpu, h_pending, h_inservice); + return mask; +} + + +/* + * May come from virtualization fault or + * nested host interrupt. + */ void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) { uint64_t spsr; if (vector & ~0xff) { - printf("vmx_vcpu_pend_interrupt: bad vector\n"); + DPRINTK("vmx_vcpu_pend_interrupt: bad vector\n"); return; } local_irq_save(spsr); VPD_CR(vcpu,irr[vector>>6]) |= 1UL<<(vector&63); local_irq_restore(spsr); + vcpu->arch.irq_new_pending = 1; +} + +/* + * Add batch of pending interrupt. + * The interrupt source is contained in pend_irr[0-3] with + * each bits stand for one interrupt. + */ +void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, UINT64 *pend_irr) +{ + uint64_t spsr; + int i; + + local_irq_save(spsr); + for (i=0 ; i<4; i++ ) { + VPD_CR(vcpu,irr[i]) |= pend_irr[i]; + } + local_irq_restore(spsr); + vcpu->arch.irq_new_pending = 1; } /* @@ -383,7 +450,7 @@ void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) */ int vmx_check_pending_irq(VCPU *vcpu) { - uint64_t spsr; + uint64_t spsr, mask; int h_pending, h_inservice; int injected=0; uint64_t isr; @@ -391,22 +458,25 @@ int vmx_check_pending_irq(VCPU *vcpu) local_irq_save(spsr); h_pending = highest_pending_irq(vcpu); - if ( h_pending == -1 ) goto chk_irq_exit; + if ( h_pending == NULL_VECTOR ) goto chk_irq_exit; h_inservice = highest_inservice_irq(vcpu); vpsr.val = vmx_vcpu_get_psr(vcpu); - if ( vpsr.i && - !irq_masked(vcpu, h_pending, h_inservice) ) { - //inject_guest_irq(v); + mask = irq_masked(vcpu, h_pending, h_inservice); + if ( vpsr.i && IRQ_NO_MASKED == mask ) { isr = vpsr.val & IA64_PSR_RI; if ( !vpsr.ic ) panic("Interrupt when IC=0\n"); vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ injected = 1; } - else if ( VMX_VPD(vcpu,vac).a_int && - is_higher_irq(h_pending,h_inservice) ) { - vmx_inject_vhpi(vcpu,h_pending); + else if ( mask == IRQ_MASKED_BY_INSVC ) { + // cann't inject VHPI +// DPRINTK("IRQ masked by higher inservice\n"); + } + else { + // masked by vpsr.i or vtpr. + update_vhpi(vcpu,h_pending); } chk_irq_exit: @@ -414,17 +484,21 @@ chk_irq_exit: return injected; } +/* + * Only coming from virtualization fault. + */ void guest_write_eoi(VCPU *vcpu) { int vec; uint64_t spsr; vec = highest_inservice_irq(vcpu); - if ( vec < 0 ) panic("Wrong vector to EOI\n"); + if ( vec == NULL_VECTOR ) panic("Wrong vector to EOI\n"); local_irq_save(spsr); VLSAPIC_INSVC(vcpu,vec>>6) &= ~(1UL <<(vec&63)); local_irq_restore(spsr); VPD_CR(vcpu, eoi)=0; // overwrite the data + vmx_check_pending_irq(vcpu); } uint64_t guest_read_vivr(VCPU *vcpu) @@ -435,37 +509,54 @@ uint64_t guest_read_vivr(VCPU *vcpu) local_irq_save(spsr); vec = highest_pending_irq(vcpu); h_inservice = highest_inservice_irq(vcpu); - if ( vec < 0 || irq_masked(vcpu, vec, h_inservice) ) { + if ( vec == NULL_VECTOR || + irq_masked(vcpu, vec, h_inservice) != IRQ_NO_MASKED ) { local_irq_restore(spsr); return IA64_SPURIOUS_INT_VECTOR; } VLSAPIC_INSVC(vcpu,vec>>6) |= (1UL <<(vec&63)); VPD_CR(vcpu, irr[vec>>6]) &= ~(1UL <<(vec&63)); - - h_inservice = highest_inservice_irq(vcpu); - next = highest_pending_irq(vcpu); - if ( VMX_VPD(vcpu,vac).a_int && - (is_higher_irq(next, h_inservice) || (next == -1)) ) - vmx_inject_vhpi(vcpu, next); + update_vhpi(vcpu, NULL_VECTOR); // clear VHPI till EOI or IRR write local_irq_restore(spsr); return (uint64_t)vec; } -void vmx_inject_vhpi(VCPU *vcpu, u8 vec) +static void generate_exirq(VCPU *vcpu) { - VMX_VPD(vcpu,vhpi) = vec / 16; - - - // non-maskable - if ( vec == NMI_VECTOR ) // NMI - VMX_VPD(vcpu,vhpi) = 32; - else if (vec == ExtINT_VECTOR) //ExtINT - VMX_VPD(vcpu,vhpi) = 16; - else if (vec == -1) - VMX_VPD(vcpu,vhpi) = 0; /* Nothing pending */ - - ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT, - (uint64_t) &(vcpu->arch.arch_vmx.vpd), 0, 0,0,0,0,0); + IA64_PSR vpsr; + uint64_t isr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + update_vhpi(vcpu, NULL_VECTOR); + isr = vpsr.val & IA64_PSR_RI; + if ( !vpsr.ic ) + panic("Interrupt when IC=0\n"); + vmx_reflect_interruption(0,isr,0, 12 ); // EXT IRQ } +vhpi_detection(VCPU *vcpu) +{ + uint64_t threshold,vhpi; + tpr_t vtpr; + IA64_PSR vpsr; + + vpsr.val = vmx_vcpu_get_psr(vcpu); + vtpr.val = VPD_CR(vcpu, tpr); + + threshold = ((!vpsr.i) << 5) | (vtpr.mmi << 4) | vtpr.mic; + vhpi = VMX_VPD(vcpu,vhpi); + if ( vhpi > threshold ) { + // interrupt actived + generate_exirq (vcpu); + } +} + +vmx_vexirq(VCPU *vcpu) +{ + static uint64_t vexirq_count=0; + + vexirq_count ++; + printk("Virtual ex-irq %ld\n", vexirq_count); + generate_exirq (vcpu); +} diff --git a/xen/arch/ia64/vmx_entry.S b/xen/arch/ia64/vmx_entry.S index 682a69df8a..261fc591f4 100644 --- a/xen/arch/ia64/vmx_entry.S +++ b/xen/arch/ia64/vmx_entry.S @@ -217,7 +217,7 @@ GLOBAL_ENTRY(ia64_leave_hypervisor) alloc loc0=ar.pfs,0,1,1,0 adds out0=16,r12 ;; - br.call.sptk.many b0=vmx_deliver_pending_interrupt + br.call.sptk.many b0=leave_hypervisor_tail mov ar.pfs=loc0 adds r8=IA64_VPD_BASE_OFFSET,r13 ;; diff --git a/xen/arch/ia64/vmx_hypercall.c b/xen/arch/ia64/vmx_hypercall.c index 5e0d8917eb..fc5f1f8c46 100644 --- a/xen/arch/ia64/vmx_hypercall.c +++ b/xen/arch/ia64/vmx_hypercall.c @@ -141,21 +141,27 @@ void hyper_lock_page(void) static int do_set_shared_page(VCPU *vcpu, u64 gpa) { u64 shared_info, o_info; + struct domain *d = vcpu->domain; + struct vcpu *v; if(vcpu->domain!=dom0) return -EPERM; shared_info = __gpa_to_mpa(vcpu->domain, gpa); o_info = (u64)vcpu->domain->shared_info; - vcpu->domain->shared_info= (shared_info_t *)__va(shared_info); + d->shared_info= (shared_info_t *)__va(shared_info); /* Copy existing shared info into new page */ - if (!o_info) { - memcpy((void*)vcpu->domain->shared_info, (void*)o_info, PAGE_SIZE); - /* If original page belongs to xen heap, then relinguish back - * to xen heap. Or else, leave to domain itself to decide. - */ - if (likely(IS_XEN_HEAP_FRAME(virt_to_page(o_info)))) - free_xenheap_page(o_info); - } + if (o_info) { + memcpy((void*)d->shared_info, (void*)o_info, PAGE_SIZE); + for_each_vcpu(d, v) { + v->vcpu_info = &d->shared_info->vcpu_data[v->vcpu_id]; + } + /* If original page belongs to xen heap, then relinguish back + * to xen heap. Or else, leave to domain itself to decide. + */ + if (likely(IS_XEN_HEAP_FRAME(virt_to_page(o_info)))) + free_xenheap_page(o_info); + } else + memset(d->shared_info, 0, PAGE_SIZE); return 0; } diff --git a/xen/arch/ia64/vmx_init.c b/xen/arch/ia64/vmx_init.c index f89659ba0c..d313b1b4d9 100644 --- a/xen/arch/ia64/vmx_init.c +++ b/xen/arch/ia64/vmx_init.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -225,6 +226,17 @@ vmx_save_state(struct vcpu *v) vmx_purge_double_mapping(dom_rr7, KERNEL_START, (u64)v->arch.vtlb->ts->vhpt->hash); + /* Need to save KR when domain switch, though HV itself doesn;t + * use them. + */ + v->arch.arch_vmx.vkr[0] = ia64_get_kr(0); + v->arch.arch_vmx.vkr[1] = ia64_get_kr(1); + v->arch.arch_vmx.vkr[2] = ia64_get_kr(2); + v->arch.arch_vmx.vkr[3] = ia64_get_kr(3); + v->arch.arch_vmx.vkr[4] = ia64_get_kr(4); + v->arch.arch_vmx.vkr[5] = ia64_get_kr(5); + v->arch.arch_vmx.vkr[6] = ia64_get_kr(6); + v->arch.arch_vmx.vkr[7] = ia64_get_kr(7); } /* Even guest is in physical mode, we still need such double mapping */ @@ -234,6 +246,7 @@ vmx_load_state(struct vcpu *v) u64 status, psr; u64 old_rr0, dom_rr7, rr0_xen_start, rr0_vhpt; u64 pte_xen, pte_vhpt; + int i; status = ia64_pal_vp_restore(v->arch.arch_vmx.vpd, 0); if (status != PAL_STATUS_SUCCESS) @@ -246,6 +259,14 @@ vmx_load_state(struct vcpu *v) (u64)v->arch.vtlb->ts->vhpt->hash, pte_xen, pte_vhpt); + ia64_set_kr(0, v->arch.arch_vmx.vkr[0]); + ia64_set_kr(1, v->arch.arch_vmx.vkr[1]); + ia64_set_kr(2, v->arch.arch_vmx.vkr[2]); + ia64_set_kr(3, v->arch.arch_vmx.vkr[3]); + ia64_set_kr(4, v->arch.arch_vmx.vkr[4]); + ia64_set_kr(5, v->arch.arch_vmx.vkr[5]); + ia64_set_kr(6, v->arch.arch_vmx.vkr[6]); + ia64_set_kr(7, v->arch.arch_vmx.vkr[7]); /* Guest vTLB is not required to be switched explicitly, since * anchored in vcpu */ } @@ -290,7 +311,7 @@ vmx_final_setup_domain(struct domain *d) vmx_create_vp(v); /* Set this ed to be vmx */ - v->arch.arch_vmx.flags = 1; + set_bit(ARCH_VMX_VMCS_LOADED, &v->arch.arch_vmx.flags); /* Other vmx specific initialization work */ } diff --git a/xen/arch/ia64/vmx_ivt.S b/xen/arch/ia64/vmx_ivt.S index 407dc4cd86..90d2398a67 100644 --- a/xen/arch/ia64/vmx_ivt.S +++ b/xen/arch/ia64/vmx_ivt.S @@ -347,11 +347,16 @@ ENTRY(vmx_break_fault) mov r31=pr mov r19=11 mov r30=cr.iim - mov r29=0x1100 + movl r29=0x1100 ;; - cmp4.eq p6,p7=r29,r30 + cmp.eq p6,p7=r30,r0 + (p6) br.sptk vmx_fault_11 + ;; + cmp.eq p6,p7=r29,r30 (p6) br.dptk.few vmx_hypercall_dispatch (p7) br.sptk.many vmx_dispatch_break_fault + ;; + VMX_FAULT(11); END(vmx_break_fault) .org vmx_ia64_ivt+0x3000 @@ -363,6 +368,8 @@ ENTRY(vmx_interrupt) mov r29=cr.ipsr ;; tbit.z p6,p7=r29,IA64_PSR_VM_BIT + tbit.z p0,p15=r29,IA64_PSR_I_BIT + ;; (p7) br.sptk vmx_dispatch_interrupt ;; mov r27=ar.rsc /* M */ @@ -447,7 +454,7 @@ ENTRY(vmx_interrupt) ;; srlz.i ;; - ssm psr.i + (p15) ssm psr.i adds r3=8,r2 // set up second base pointer for SAVE_REST srlz.i // ensure everybody knows psr.ic is back on ;; @@ -508,9 +515,12 @@ END(vmx_interrupt) .org vmx_ia64_ivt+0x3400 ///////////////////////////////////////////////////////////////////////////////////////// // 0x3400 Entry 13 (size 64 bundles) Reserved +ENTRY(vmx_virtual_exirq) VMX_DBG_FAULT(13) - VMX_FAULT(13) - + mov r31=pr + mov r19=13 + br.sptk vmx_dispatch_vexirq +END(vmx_virtual_exirq) .org vmx_ia64_ivt+0x3800 ///////////////////////////////////////////////////////////////////////////////////////// @@ -876,7 +886,7 @@ ENTRY(vmx_dispatch_reflection) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -887,8 +897,6 @@ ENTRY(vmx_dispatch_reflection) END(vmx_dispatch_reflection) ENTRY(vmx_dispatch_virtualization_fault) - cmp.eq pEml,pNonEml=r0,r0 /* force pEml =1, save r4 ~ r7 */ - ;; VMX_SAVE_MIN_WITH_COVER_R19 ;; alloc r14=ar.pfs,0,0,3,0 // now it's safe (must be first in insn group!) @@ -899,7 +907,7 @@ ENTRY(vmx_dispatch_virtualization_fault) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -910,6 +918,24 @@ ENTRY(vmx_dispatch_virtualization_fault) END(vmx_dispatch_virtualization_fault) +ENTRY(vmx_dispatch_vexirq) + VMX_SAVE_MIN_WITH_COVER_R19 + alloc r14=ar.pfs,0,0,1,0 + mov out0=r13 + + ssm psr.ic + ;; + srlz.i // guarantee that interruption collection is on + ;; + (p15) ssm psr.i // restore psr.i + adds r3=16,r2 // set up second base pointer + ;; + VMX_SAVE_REST + movl r14=ia64_leave_hypervisor + ;; + mov rp=r14 + br.call.sptk.many b6=vmx_vexirq +END(vmx_dispatch_vexirq) ENTRY(vmx_dispatch_tlb_miss) VMX_SAVE_MIN_WITH_COVER_R19 @@ -922,7 +948,7 @@ ENTRY(vmx_dispatch_tlb_miss) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -947,7 +973,7 @@ ENTRY(vmx_dispatch_break_fault) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15)ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -965,7 +991,7 @@ ENTRY(vmx_hypercall_dispatch) ;; srlz.i // guarantee that interruption collection is on ;; - ssm psr.i // restore psr.i + (p15) ssm psr.i // restore psr.i adds r3=16,r2 // set up second base pointer ;; VMX_SAVE_REST @@ -987,8 +1013,6 @@ END(vmx_hypercall_dispatch) ENTRY(vmx_dispatch_interrupt) - cmp.ne pEml,pNonEml=r0,r0 /* force pNonEml =1, don't save r4 ~ r7 */ - ;; VMX_SAVE_MIN_WITH_COVER_R19 // uses r31; defines r2 and r3 ;; alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group @@ -999,7 +1023,7 @@ ENTRY(vmx_dispatch_interrupt) ;; srlz.i ;; - ssm psr.i + (p15) ssm psr.i adds r3=16,r2 // set up second base pointer for SAVE_REST ;; VMX_SAVE_REST diff --git a/xen/arch/ia64/vmx_minstate.h b/xen/arch/ia64/vmx_minstate.h index 76f8e7f065..0356fdbf8d 100644 --- a/xen/arch/ia64/vmx_minstate.h +++ b/xen/arch/ia64/vmx_minstate.h @@ -148,10 +148,14 @@ mov r20=r1; /* A */ \ mov r26=ar.unat; /* M */ \ mov r29=cr.ipsr; /* M */ \ + mov r18=cr.isr; \ COVER; /* B;; (or nothing) */ \ ;; \ - tbit.z p6,p7=r29,IA64_PSR_VM_BIT; \ + tbit.z p6,p0=r29,IA64_PSR_VM_BIT; \ + tbit.nz.or p6,p0 = r18,39; \ + ;; \ (p6) br.sptk.few vmx_panic; \ + tbit.z p0,p15=r29,IA64_PSR_I_BIT; \ mov r1=r16; \ /* mov r21=r16; */ \ /* switch from user to kernel RBS: */ \ diff --git a/xen/arch/ia64/vmx_phy_mode.c b/xen/arch/ia64/vmx_phy_mode.c index def87baf9e..16c1a457b5 100644 --- a/xen/arch/ia64/vmx_phy_mode.c +++ b/xen/arch/ia64/vmx_phy_mode.c @@ -119,30 +119,67 @@ physical_mode_init(VCPU *vcpu) vcpu->arch.old_rsc = 0; vcpu->arch.mode_flags = GUEST_IN_PHY; - psr = ia64_clear_ic(); - - ia64_set_rr((VRN0<domain->arch.emul_phy_rr0.rrval); - ia64_srlz_d(); - ia64_set_rr((VRN4<domain->arch.emul_phy_rr4.rrval); - ia64_srlz_d(); -#if 0 - /* FIXME: temp workaround to support guest physical mode */ -ia64_itr(0x1, IA64_TEMP_PHYSICAL, dom0_start, - pte_val(pfn_pte((dom0_start >> PAGE_SHIFT), PAGE_KERNEL)), - 28); -ia64_itr(0x2, IA64_TEMP_PHYSICAL, dom0_start, - pte_val(pfn_pte((dom0_start >> PAGE_SHIFT), PAGE_KERNEL)), - 28); -ia64_srlz_i(); -#endif - ia64_set_psr(psr); - ia64_srlz_i(); return; } extern u64 get_mfn(domid_t domid, u64 gpfn, u64 pages); +#if 0 +void +physical_itlb_miss_domn(VCPU *vcpu, u64 vadr) +{ + u64 psr; + IA64_PSR vpsr; + u64 mppn,gppn,mpp1,gpp1; + struct domain *d; + static u64 test=0; + d=vcpu->domain; + if(test) + panic("domn physical itlb miss happen\n"); + else + test=1; + vpsr.val=vmx_vcpu_get_psr(vcpu); + gppn=(vadr<<1)>>13; + mppn = get_mfn(DOMID_SELF,gppn,1); + mppn=(mppn<<12)|(vpsr.cpl<<7); + gpp1=0; + mpp1 = get_mfn(DOMID_SELF,gpp1,1); + mpp1=(mpp1<<12)|(vpsr.cpl<<7); +// if(vadr>>63) +// mppn |= PHY_PAGE_UC; +// else +// mppn |= PHY_PAGE_WB; + mpp1 |= PHY_PAGE_WB; + psr=ia64_clear_ic(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL, vadr&(~0xfff), (mppn|PHY_PAGE_WB), 24); + ia64_stop(); + ia64_srlz_i(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL+1, vadr&(~0x8000000000000fffUL), (mppn|PHY_PAGE_WB), 24); + ia64_stop(); + ia64_srlz_i(); + ia64_itr(0x1, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); + ia64_srlz_i(); + ia64_itr(0x2, IA64_TEMP_PHYSICAL+2, gpp1&(~0xfff), mpp1, 28); + ia64_stop(); + ia64_srlz_i(); + ia64_set_psr(psr); + ia64_srlz_i(); + return; +} +#endif + void physical_itlb_miss(VCPU *vcpu, u64 vadr) +{ + physical_itlb_miss_dom0(vcpu, vadr); +} + + +void +physical_itlb_miss_dom0(VCPU *vcpu, u64 vadr) { u64 psr; IA64_PSR vpsr; @@ -150,7 +187,11 @@ physical_itlb_miss(VCPU *vcpu, u64 vadr) vpsr.val=vmx_vcpu_get_psr(vcpu); gppn=(vadr<<1)>>13; mppn = get_mfn(DOMID_SELF,gppn,1); - mppn=(mppn<<12)|(vpsr.cpl<<7)|PHY_PAGE_WB; + mppn=(mppn<<12)|(vpsr.cpl<<7); +// if(vadr>>63) +// mppn |= PHY_PAGE_UC; +// else + mppn |= PHY_PAGE_WB; psr=ia64_clear_ic(); ia64_itc(1,vadr&(~0xfff),mppn,EMUL_PHY_PAGE_SHIFT); @@ -159,12 +200,15 @@ physical_itlb_miss(VCPU *vcpu, u64 vadr) return; } + void physical_dtlb_miss(VCPU *vcpu, u64 vadr) { u64 psr; IA64_PSR vpsr; u64 mppn,gppn; +// if(vcpu->domain!=dom0) +// panic("dom n physical dtlb miss happen\n"); vpsr.val=vmx_vcpu_get_psr(vcpu); gppn=(vadr<<1)>>13; mppn = get_mfn(DOMID_SELF,gppn,1); @@ -209,6 +253,8 @@ vmx_load_all_rr(VCPU *vcpu) * mode in same region */ if (is_physical_mode(vcpu)) { + if (vcpu->arch.mode_flags & GUEST_PHY_EMUL) + panic("Unexpected domain switch in phy emul\n"); ia64_set_rr((VRN0 << VRN_SHIFT), vcpu->domain->arch.emul_phy_rr0.rrval); ia64_set_rr((VRN4 << VRN_SHIFT), @@ -262,15 +308,10 @@ switch_to_virtual_rid(VCPU *vcpu) psr=ia64_clear_ic(); mrr=vmx_vcpu_rr(vcpu,VRN0<arch.mode_flags |= GUEST_PHY_EMUL; switch_to_virtual_rid(vcpu); + } return; } @@ -386,8 +429,10 @@ prepare_if_physical_mode(VCPU *vcpu) void recover_if_physical_mode(VCPU *vcpu) { - if (is_physical_mode(vcpu)) + if (is_physical_mode(vcpu)) { + vcpu->arch.mode_flags &= ~GUEST_PHY_EMUL; switch_to_physical_rid(vcpu); + } return; } diff --git a/xen/arch/ia64/vmx_process.c b/xen/arch/ia64/vmx_process.c index 8ab671cdb8..0456d9d001 100644 --- a/xen/arch/ia64/vmx_process.c +++ b/xen/arch/ia64/vmx_process.c @@ -45,7 +45,9 @@ #include #include #include +#include #include +#include /* reset all PSR field to 0, except up,mfl,mfh,pk,dt,rt,mc,it */ #define INITIAL_PSR_VALUE_AT_INTERRUPTION 0x0000001808028034 @@ -53,7 +55,7 @@ extern struct ia64_sal_retval pal_emulator_static(UINT64); extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); extern void rnat_consumption (VCPU *vcpu); - +#define DOMN_PAL_REQUEST 0x110000 IA64FAULT vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) { @@ -148,7 +150,10 @@ vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long is regs->r2); #endif vmx_vcpu_increment_iip(current); - } else + }else if(iim == DOMN_PAL_REQUEST){ + pal_emul(current); + vmx_vcpu_increment_iip(current); + } else vmx_reflect_interruption(ifa,isr,iim,11); } @@ -187,26 +192,43 @@ void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim, // ONLY gets called from ia64_leave_kernel // ONLY call with interrupts disabled?? (else might miss one?) // NEVER successful if already reflecting a trap/fault because psr.i==0 -void vmx_deliver_pending_interrupt(struct pt_regs *regs) +void leave_hypervisor_tail(struct pt_regs *regs) { struct domain *d = current->domain; struct vcpu *v = current; // FIXME: Will this work properly if doing an RFI??? if (!is_idle_task(d) ) { // always comes from guest - //vcpu_poke_timer(v); - //if (vcpu_deliverable_interrupts(v)) { - // unsigned long isr = regs->cr_ipsr & IA64_PSR_RI; - // foodpi(); - // reflect_interruption(0,isr,0,regs,IA64_EXTINT_VECTOR); - //} extern void vmx_dorfirfi(void); struct pt_regs *user_regs = vcpu_regs(current); + if (local_softirq_pending()) + do_softirq(); + local_irq_disable(); + if (user_regs != regs) printk("WARNING: checking pending interrupt in nested interrupt!!!\n"); - if (regs->cr_iip == *(unsigned long *)vmx_dorfirfi) - return; - vmx_check_pending_irq(v); + + /* VMX Domain N has other interrupt source, saying DM */ + if (test_bit(ARCH_VMX_INTR_ASSIST, &v->arch.arch_vmx.flags)) + vmx_intr_assist(v); + + /* FIXME: Check event pending indicator, and set + * pending bit if necessary to inject back to guest. + * Should be careful about window between this check + * and above assist, since IOPACKET_PORT shouldn't be + * injected into vmx domain. + * + * Now hardcode the vector as 0x10 temporarily + */ + if (event_pending(v)&&(!((v->arch.arch_vmx.in_service[0])&(1UL<<0x10)))) { + VPD_CR(v, irr[0]) |= 1UL << 0x10; + v->arch.irq_new_pending = 1; + } + + if ( v->arch.irq_new_pending ) { + v->arch.irq_new_pending = 0; + vmx_check_pending_irq(v); + } } } @@ -244,7 +266,11 @@ void vmx_hpw_miss(VCPU *vcpu, u64 vec, u64 vadr) return; } if((vec==2)&&(!vpsr.dt)){ - physical_dtlb_miss(vcpu, vadr); + if(vcpu->domain!=dom0&&__gpfn_is_io(vcpu->domain,(vadr<<1)>>(PAGE_SHIFT+1))){ + emulate_io_inst(vcpu,((vadr<<1)>>1),4); // UC + }else{ + physical_dtlb_miss(vcpu, vadr); + } return; } vrr = vmx_vcpu_rr(vcpu,vadr); @@ -255,6 +281,11 @@ void vmx_hpw_miss(VCPU *vcpu, u64 vec, u64 vadr) // prepare_if_physical_mode(vcpu); if(data=vtlb_lookup_ex(vtlb, vrr.rid, vadr,type)){ + if(vcpu->domain!=dom0&&type==DSIDE_TLB && __gpfn_is_io(vcpu->domain, data->ppn>>(PAGE_SHIFT-12))){ + vadr=(vadr&((1UL<ps)-1))+(data->ppn>>(data->ps-12)<ps); + emulate_io_inst(vcpu, vadr, data->ma); + return IA64_FAULT; + } if ( data->ps != vrr.ps ) { machine_tlb_insert(vcpu, data); } diff --git a/xen/arch/ia64/vmx_support.c b/xen/arch/ia64/vmx_support.c new file mode 100644 index 0000000000..ed92bad2b0 --- /dev/null +++ b/xen/arch/ia64/vmx_support.c @@ -0,0 +1,159 @@ + +/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* + * vmx_support.c: vmx specific support interface. + * Copyright (c) 2005, Intel Corporation. + * Kun Tian (Kevin Tian) (Kevin.tian@intel.com) + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ +#include +#include +#include +#include +#include + +/* + * I/O emulation should be atomic from domain point of view. However, + * when emulation code is waiting for I/O completion by do_block, + * other events like DM interrupt, VBD, etc. may come and unblock + * current exection flow. So we have to prepare for re-block if unblocked + * by non I/O completion event. + */ +void vmx_wait_io(void) +{ + struct vcpu *v = current; + struct domain *d = v->domain; + extern void do_block(); + + do { + if (!test_bit(IOPACKET_PORT, + &d->shared_info->evtchn_pending[0])) + do_block(); + + /* Unblocked when some event is coming. Clear pending indication + * immediately if deciding to go for io assist + */ + if (test_and_clear_bit(IOPACKET_PORT, + &d->shared_info->evtchn_pending[0])) { + clear_bit(IOPACKET_PORT>>5, &v->vcpu_info->evtchn_pending_sel); + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + vmx_io_assist(v); + } + + + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { + /* + * Latest event is not I/O completion, so clear corresponding + * selector and pending indication, to allow real event coming + */ + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + + /* Here atually one window is leaved before selector is cleared. + * However this window only delay the indication to coming event, + * nothing losed. Next loop will check I/O channel to fix this + * window. + */ + clear_bit(IOPACKET_PORT>>5, &v->vcpu_info->evtchn_pending_sel); + } + else + break; + } while (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)); +} + +/* + * Only place to call vmx_io_assist is mmio/legacy_io emulation. + * Since I/O emulation is synchronous, it shouldn't be called in + * other places. This is not like x86, since IA-64 implements a + * per-vp stack without continuation. + */ +void vmx_io_assist(struct vcpu *v) +{ + vcpu_iodata_t *vio; + ioreq_t *p; + + /* + * This shared page contains I/O request between emulation code + * and device model. + */ + vio = (vcpu_iodata_t *)v->arch.arch_vmx.vmx_platform.shared_page_va; + if (!vio) + panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); + + p = &vio->vp_ioreq; + + if (p->state == STATE_IORESP_HOOK) + panic("Not supported: No hook available for DM request\n"); + + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) { + if (p->state != STATE_IORESP_READY) { + /* Can't do_block here, for the same reason as other places to + * use vmx_wait_io. Simple return is safe since vmx_wait_io will + * try to block again + */ + return; + } else + p->state = STATE_INVALID; + + clear_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags); + } else + return; /* Spurous event? */ +} + +/* + * VMX domainN has two types of interrupt source: lsapic model within + * HV, and device model within domain 0 (service OS). There're another + * pending array in share page, manipulated by device model directly. + * To conform to VT-i spec, we have to sync pending bits in shared page + * into VPD. This has to be done before checking pending interrupt at + * resume to guest. For domain 0, all the interrupt sources come from + * HV, which then doesn't require this assist. + */ +void vmx_intr_assist(struct vcpu *v) +{ + vcpu_iodata_t *vio; + struct domain *d = v->domain; + extern void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, + unsigned long *pend_irr); + + /* I/O emulation is atomic, so it's impossible to see execution flow + * out of vmx_wait_io, when guest is still waiting for response. + */ + if (test_bit(ARCH_VMX_IO_WAIT, &v->arch.arch_vmx.flags)) + panic("!!!Bad resume to guest before I/O emulation is done.\n"); + + /* Clear indicator specific to interrupt delivered from DM */ + if (test_and_clear_bit(IOPACKET_PORT, + &d->shared_info->evtchn_pending[0])) { + if (!d->shared_info->evtchn_pending[IOPACKET_PORT >> 5]) + clear_bit(IOPACKET_PORT>>5, &v->vcpu_info->evtchn_pending_sel); + + if (!v->vcpu_info->evtchn_pending_sel) + clear_bit(0, &v->vcpu_info->evtchn_upcall_pending); + } + + /* Even without event pending, we still need to sync pending bits + * between DM and vlsapic. The reason is that interrupt delivery + * shares same event channel as I/O emulation, with corresponding + * indicator possibly cleared when vmx_wait_io(). + */ + vio = (vcpu_iodata_t *)v->arch.arch_vmx.vmx_platform.shared_page_va; + if (!vio) + panic("Corruption: bad shared page: %lx\n", (unsigned long)vio); + + vmx_vcpu_pend_batch_interrupt(v, &vio->vp_intr[0]); + memset(&vio->vp_intr[0], 0, sizeof(vio->vp_intr)); + return; +} diff --git a/xen/arch/ia64/vmx_vcpu.c b/xen/arch/ia64/vmx_vcpu.c index 05c211d428..1e4046389c 100644 --- a/xen/arch/ia64/vmx_vcpu.c +++ b/xen/arch/ia64/vmx_vcpu.c @@ -23,8 +23,6 @@ * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) */ - - #include #include #include @@ -71,8 +69,8 @@ //unsigned long last_guest_rsm = 0x0; struct guest_psr_bundle{ - unsigned long ip; - unsigned long psr; + unsigned long ip; + unsigned long psr; }; struct guest_psr_bundle guest_psr_buf[100]; @@ -107,20 +105,24 @@ vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value) IA64_PSR_SS | IA64_PSR_ED | IA64_PSR_IA )); + if ( !old_psr.i && (value & IA64_PSR_I) ) { + // vpsr.i 0->1 + vcpu->arch.irq_new_condition = 1; + } new_psr.val=vmx_vcpu_get_psr(vcpu); { - struct xen_regs *regs = vcpu_regs(vcpu); - guest_psr_buf[guest_psr_index].ip = regs->cr_iip; - guest_psr_buf[guest_psr_index].psr = new_psr.val; - if (++guest_psr_index >= 100) - guest_psr_index = 0; + struct xen_regs *regs = vcpu_regs(vcpu); + guest_psr_buf[guest_psr_index].ip = regs->cr_iip; + guest_psr_buf[guest_psr_index].psr = new_psr.val; + if (++guest_psr_index >= 100) + guest_psr_index = 0; } #if 0 if (old_psr.i != new_psr.i) { - if (old_psr.i) - last_guest_rsm = vcpu_regs(vcpu)->cr_iip; - else - last_guest_rsm = 0; + if (old_psr.i) + last_guest_rsm = vcpu_regs(vcpu)->cr_iip; + else + last_guest_rsm = 0; } #endif @@ -270,8 +272,8 @@ check_entry(u64 va, u64 ps, char *str) { va &= ~ (PSIZE(ps)-1); if ( va == 0x2000000002908000UL || - va == 0x600000000000C000UL ) { - stop(); + va == 0x600000000000C000UL ) { + stop(); } if (tlb_debug) printf("%s at %lx %lx\n", str, va, 1UL<arch.irq_new_condition = 1; + return IA64_NO_FAULT; +} diff --git a/xen/arch/ia64/vmx_virt.c b/xen/arch/ia64/vmx_virt.c index 29b1164196..7e8f658bac 100644 --- a/xen/arch/ia64/vmx_virt.c +++ b/xen/arch/ia64/vmx_virt.c @@ -1276,7 +1276,13 @@ IA64FAULT vmx_emul_mov_from_cr(VCPU *vcpu, INST64 inst) } - +static void post_emulation_action(VCPU *vcpu) +{ + if ( vcpu->arch.irq_new_condition ) { + vcpu->arch.irq_new_condition = 0; + vhpi_detection(vcpu); + } +} //#define BYPASS_VMAL_OPCODE extern IA64_SLOT_TYPE slot_types[0x20][3]; @@ -1336,7 +1342,7 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { slot = ((struct ia64_psr *)&(regs->cr_ipsr))->ri; if (!slot) inst.inst = bundle.slot0; else if (slot == 1) - inst.inst = bundle.slot1a + (bundle.slot1b<<23); + inst.inst = bundle.slot1a + (bundle.slot1b<<18); else if (slot == 2) inst.inst = bundle.slot2; else printf("priv_handle_op: illegal slot: %d\n", slot); slot_type = slot_types[bundle.template][slot]; @@ -1478,9 +1484,11 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { status=IA64_FAULT; break; default: - printf("unknown cause %d:\n", cause); + printf("unknown cause %d, iip: %lx, ipsr: %lx\n", cause,regs->cr_iip,regs->cr_ipsr); + while(1); /* For unknown cause, let hardware to re-execute */ status=IA64_RETRY; + break; // panic("unknown cause in virtualization intercept"); }; @@ -1494,6 +1502,7 @@ if ( (cause == 0xff && opcode == 0x1e000000000) || cause == 0 ) { } recover_if_physical_mode(vcpu); + post_emulation_action (vcpu); //TODO set_irq_check(v); return; diff --git a/xen/arch/ia64/vtlb.c b/xen/arch/ia64/vtlb.c index 86565531bf..89453b93bb 100644 --- a/xen/arch/ia64/vtlb.c +++ b/xen/arch/ia64/vtlb.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #define MAX_CCH_LENGTH 40 @@ -401,6 +401,8 @@ static void vhpt_insert(thash_cb_t *hcb, thash_data_t *entry, u64 va) panic("Can't convert to machine VHPT entry\n"); } hash_table->next = cch; + if(hash_table->tag==hash_table->next->tag) + while(1); } return /*hash_table*/; } @@ -466,10 +468,11 @@ int cch_depth=0; static thash_data_t *thash_rem_cch(thash_cb_t *hcb, thash_data_t *cch) { thash_data_t *next; - + if ( ++cch_depth > MAX_CCH_LENGTH ) { printf ("cch length > MAX_CCH_LENGTH, exceed the expected length\n"); - } + while(1); + } if ( cch -> next ) { next = thash_rem_cch(hcb, cch->next); } diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c index d95eebfc9f..b4cc8f52c9 100644 --- a/xen/arch/ia64/xensetup.c +++ b/xen/arch/ia64/xensetup.c @@ -30,7 +30,6 @@ struct vcpu *idle_task[NR_CPUS] = { &idle0_vcpu }; #ifdef CLONE_DOMAIN0 struct domain *clones[CLONE_DOMAIN0]; #endif -extern struct domain *dom0; extern unsigned long domain0_ready; int find_max_pfn (unsigned long, unsigned long, void *); diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index e64246d418..71bf6ea2e3 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -49,6 +49,7 @@ typedef unsigned long physaddr_t; extern unsigned long xenheap_phys_end; extern unsigned long xen_pstart; extern unsigned long xenheap_size; +extern struct domain *dom0; extern unsigned long dom0_start; extern unsigned long dom0_size; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 717a7fcf23..0b270a7372 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -42,8 +42,6 @@ struct arch_domain { * max_pages in domain struct, which indicates maximum memory size */ unsigned long max_pfn; - unsigned int section_nr; - mm_section_t *sections; /* Describe memory hole except for Dom0 */ #endif //CONFIG_VTI u64 xen_vastart; u64 xen_vaend; @@ -88,6 +86,8 @@ struct arch_vcpu { void (*schedule_tail) (struct vcpu *); struct trap_bounce trap_bounce; thash_cb_t *vtlb; + char irq_new_pending; + char irq_new_condition; // vpsr.i/vtpr change, check for pending VHPI //for phycial emulation unsigned long old_rsc; int mode_flags; diff --git a/xen/include/asm-ia64/privop.h b/xen/include/asm-ia64/privop.h index 4cad79ee3a..a8cf870d4b 100644 --- a/xen/include/asm-ia64/privop.h +++ b/xen/include/asm-ia64/privop.h @@ -138,6 +138,19 @@ typedef union U_INST64_M47 { IA64_INST inst; struct { unsigned long qp:6, un14:14, r3:7, x6:6, x3:3, un1:1, major:4; }; } INST64_M47; +typedef union U_INST64_M1{ + IA64_INST inst; + struct { unsigned long qp:6, r1:7, un7:7, r3:7, x:1, hint:2, x6:6, m:1, major:4; }; +} INST64_M1; +typedef union U_INST64_M4 { + IA64_INST inst; + struct { unsigned long qp:6, un7:7, r2:7, r3:7, x:1, hint:2, x6:6, m:1, major:4; }; +} INST64_M4; +typedef union U_INST64_M6 { + IA64_INST inst; + struct { unsigned long qp:6, f1:7, un7:7, r3:7, x:1, hint:2, x6:6, m:1, major:4; }; +} INST64_M6; + #endif // CONFIG_VTI typedef union U_INST64 { @@ -151,6 +164,11 @@ typedef union U_INST64 { INST64_I26 I26; // mov register to ar (I unit) INST64_I27 I27; // mov immediate to ar (I unit) INST64_I28 I28; // mov from ar (I unit) +#ifdef CONFIG_VTI + INST64_M1 M1; // ld integer + INST64_M4 M4; // st integer + INST64_M6 M6; // ldfd floating pointer +#endif // CONFIG_VTI INST64_M28 M28; // purge translation cache entry INST64_M29 M29; // mov register to ar (M unit) INST64_M30 M30; // mov immediate to ar (M unit) diff --git a/xen/include/asm-ia64/vmx.h b/xen/include/asm-ia64/vmx.h index 3610bd5cd6..2f5fadd99a 100644 --- a/xen/include/asm-ia64/vmx.h +++ b/xen/include/asm-ia64/vmx.h @@ -35,4 +35,6 @@ extern vmx_insert_double_mapping(u64,u64,u64,u64,u64); extern void vmx_purge_double_mapping(u64, u64, u64); extern void vmx_change_double_mapping(struct vcpu *v, u64 oldrr7, u64 newrr7); +extern void vmx_wait_io(void); +extern void vmx_io_assist(struct vcpu *v); #endif /* _ASM_IA64_VT_H */ diff --git a/xen/include/asm-ia64/vmx_phy_mode.h b/xen/include/asm-ia64/vmx_phy_mode.h index 20c669e69c..039d302ea2 100644 --- a/xen/include/asm-ia64/vmx_phy_mode.h +++ b/xen/include/asm-ia64/vmx_phy_mode.h @@ -83,6 +83,7 @@ #define IA64_RSC_MODE 0x0000000000000003 #define XEN_RR7_RID (0xf00010) #define GUEST_IN_PHY 0x1 +#define GUEST_PHY_EMUL 0x2 extern int valid_mm_mode[]; extern int mm_switch_table[][8]; extern void physical_mode_init(VCPU *); diff --git a/xen/include/asm-ia64/vmx_vcpu.h b/xen/include/asm-ia64/vmx_vcpu.h index dc4e0977b7..a47ceab280 100644 --- a/xen/include/asm-ia64/vmx_vcpu.h +++ b/xen/include/asm-ia64/vmx_vcpu.h @@ -53,7 +53,7 @@ #define VMM_RR_SHIFT 20 #define VMM_RR_MASK ((1UL<domain->domain_id) << VMM_RR_SHIFT) extern u64 indirect_reg_igfld_MASK ( int type, int index, u64 value); extern u64 cr_igfld_mask (int index, u64 value); @@ -69,7 +69,7 @@ extern void vmx_vcpu_set_psr_sync_mpsr(VCPU * vcpu, UINT64 value); extern IA64FAULT vmx_vcpu_cover(VCPU *vcpu); extern thash_cb_t *vmx_vcpu_get_vtlb(VCPU *vcpu); extern thash_cb_t *vmx_vcpu_get_vhpt(VCPU *vcpu); -ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr); +extern ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr); extern IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val); extern IA64FAULT vmx_vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval); extern IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval); @@ -112,10 +112,10 @@ extern uint64_t guest_read_vivr(VCPU *vcpu); extern void vmx_inject_vhpi(VCPU *vcpu, u8 vec); extern void vmx_vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector); extern struct virutal_platform_def *vmx_vcpu_get_plat(VCPU *vcpu); -extern void memread_p(VCPU *vcpu, void *src, void *dest, size_t s); -extern void memread_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s); -extern void memwrite_v(VCPU *vcpu, thash_data_t *vtlb, void *src, void *dest, size_t s); -extern void memwrite_p(VCPU *vcpu, void *src, void *dest, size_t s); +extern void memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s); +extern void memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s); +extern void memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s); +extern void memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s); /************************************************************************** @@ -401,14 +401,8 @@ vmx_vcpu_set_lid(VCPU *vcpu, u64 val) VPD_CR(vcpu,lid)=val; return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_tpr(VCPU *vcpu, u64 val) -{ - VPD_CR(vcpu,tpr)=val; - //TODO - return IA64_NO_FAULT; -} +extern IA64FAULT vmx_vcpu_set_tpr(VCPU *vcpu, u64 val); + static inline IA64FAULT vmx_vcpu_set_eoi(VCPU *vcpu, u64 val) diff --git a/xen/include/asm-ia64/vmx_vpd.h b/xen/include/asm-ia64/vmx_vpd.h index be29ed1d47..1a18f03661 100644 --- a/xen/include/asm-ia64/vmx_vpd.h +++ b/xen/include/asm-ia64/vmx_vpd.h @@ -19,8 +19,8 @@ * Kun Tian (Kevin Tian) (kevin.tian@intel.com) */ -#ifndef _VPD_H_ -#define _VPD_H_ +#ifndef _ASM_IA64_VMX_VPD_H_ +#define _ASM_IA64_VMX_VPD_H_ #ifndef __ASSEMBLY__ @@ -123,6 +123,7 @@ struct arch_vmx_struct { vpd_t *vpd; vtime_t vtm; unsigned long vrr[8]; + unsigned long vkr[8]; unsigned long mrr5; unsigned long mrr6; unsigned long mrr7; @@ -145,6 +146,7 @@ struct arch_vmx_struct { #define ARCH_VMX_VMCS_LAUNCH 1 /* Needs VMCS launch */ #define ARCH_VMX_VMCS_RESUME 2 /* Needs VMCS resume */ #define ARCH_VMX_IO_WAIT 3 /* Waiting for I/O completion */ +#define ARCH_VMX_INTR_ASSIST 4 /* Need DM's assist to issue intr */ #define VMX_DEBUG 1 @@ -191,4 +193,4 @@ extern unsigned int opt_vmx_debug_level; #define VPD_VMM_VAIL_START_OFFSET 31744 -#endif /* _VPD_H_ */ +#endif /* _ASM_IA64_VMX_VPD_H_ */ diff --git a/xen/include/asm-ia64/xenprocessor.h b/xen/include/asm-ia64/xenprocessor.h index abc13dacee..da9a1d6c7b 100644 --- a/xen/include/asm-ia64/xenprocessor.h +++ b/xen/include/asm-ia64/xenprocessor.h @@ -166,6 +166,16 @@ typedef union{ }; } ipi_d_t; +typedef union { + __u64 val; + struct { + __u64 ig0 : 4; + __u64 mic : 4; + __u64 rsv : 8; + __u64 mmi : 1; + __u64 ig1 : 47; + }; +} tpr_t; #define IA64_ISR_CODE_MASK0 0xf #define IA64_UNIMPL_DADDR_FAULT 0x30 diff --git a/xen/include/asm-ia64/xensystem.h b/xen/include/asm-ia64/xensystem.h index 6fadb60ebe..0de4365b47 100644 --- a/xen/include/asm-ia64/xensystem.h +++ b/xen/include/asm-ia64/xensystem.h @@ -33,6 +33,8 @@ #ifdef CONFIG_VTI extern struct task_struct *vmx_ia64_switch_to (void *next_task); #define __switch_to(prev,next,last) do { \ + ia64_save_fpu(prev->arch._thread.fph); \ + ia64_load_fpu(next->arch._thread.fph); \ if (VMX_DOMAIN(prev)) \ vmx_save_state(prev); \ else { \ diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index e9b6767c76..34e9f1c0ae 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -181,6 +181,16 @@ typedef struct { } arch_shared_info_t; // DON'T PACK typedef struct vcpu_guest_context { +#define VGCF_FPU_VALID (1<<0) +#define VGCF_VMX_GUEST (1<<1) +#define VGCF_IN_KERNEL (1<<2) + unsigned long flags; /* VGCF_* flags */ + unsigned long pt_base; /* PMT table base */ + unsigned long pt_max_pfn; /* Max pfn including holes */ + unsigned long share_io_pg; /* Shared page for I/O emulation */ + unsigned long vm_assist; /* VMASST_TYPE_* bitmap, now none on IPF */ + unsigned long guest_iip; /* Guest entry point */ + struct pt_regs regs; arch_vcpu_info_t vcpu; arch_shared_info_t shared; From bd3c0147e469e8015edba14293d16bed30c817dc Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Sun, 10 Jul 2005 08:53:17 -0700 Subject: [PATCH 06/12] Fix zeroing of some counters and add a couple more --- xen/arch/ia64/hypercall.c | 7 ++++--- xen/arch/ia64/privop.c | 5 +++++ xen/arch/ia64/xenmisc.c | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/xen/arch/ia64/hypercall.c b/xen/arch/ia64/hypercall.c index d7288088cf..84b05e850c 100644 --- a/xen/arch/ia64/hypercall.c +++ b/xen/arch/ia64/hypercall.c @@ -34,7 +34,7 @@ ia64_hypercall (struct pt_regs *regs) case FW_HYPERCALL_PAL_CALL: //printf("*** PAL hypercall: index=%d\n",regs->r28); //FIXME: This should call a C routine -#if 1 +#if 0 // This is very conservative, but avoids a possible // (and deadly) freeze in paravirtualized domains due // to a yet-to-be-found bug where pending_interruption @@ -47,8 +47,9 @@ ia64_hypercall (struct pt_regs *regs) #define SPURIOUS_VECTOR 15 pi = vcpu_check_pending_interrupts(v); if (pi != SPURIOUS_VECTOR) { - idle_when_pending++; - pi = vcpu_pend_unspecified_interrupt(v); + if (!v->vcpu_info->arch.pending_interruption) + idle_when_pending++; + vcpu_pend_unspecified_interrupt(v); //printf("idle w/int#%d pending!\n",pi); //this shouldn't happen, but it apparently does quite a bit! so don't //allow it to happen... i.e. if a domain has an interrupt pending and diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c index a48a9edb9b..f648144e4b 100644 --- a/xen/arch/ia64/privop.c +++ b/xen/arch/ia64/privop.c @@ -1040,6 +1040,7 @@ extern unsigned long vhpt_translate_count; extern unsigned long lazy_cover_count; extern unsigned long idle_when_pending; extern unsigned long pal_halt_light_count; +extern unsigned long context_switch_count; int dump_misc_stats(char *buf) { @@ -1050,6 +1051,7 @@ int dump_misc_stats(char *buf) s += sprintf(s,"Physical translations: %d\n",phys_translate_count); s += sprintf(s,"Idle when pending: %d\n",idle_when_pending); s += sprintf(s,"PAL_HALT_LIGHT (no pending): %d\n",pal_halt_light_count); + s += sprintf(s,"context switches: %d\n",context_switch_count); s += sprintf(s,"Lazy covers: %d\n",lazy_cover_count); return s - buf; } @@ -1061,6 +1063,9 @@ void zero_misc_stats(void) phys_translate_count = 0; vhpt_translate_count = 0; lazy_cover_count = 0; + pal_halt_light_count = 0; + idle_when_pending = 0; + context_switch_count = 0; } int dump_hyperprivop_counts(char *buf) diff --git a/xen/arch/ia64/xenmisc.c b/xen/arch/ia64/xenmisc.c index da9c034e96..f734f852dd 100644 --- a/xen/arch/ia64/xenmisc.c +++ b/xen/arch/ia64/xenmisc.c @@ -257,6 +257,8 @@ void *module_text_address(unsigned long addr) { return NULL; } void cs10foo(void) {} void cs01foo(void) {} +unsigned long context_switch_count = 0; + // context_switch void context_switch(struct vcpu *prev, struct vcpu *next) { @@ -276,6 +278,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next) /* Housekeeping for prev domain */ #endif // CONFIG_VTI + context_switch_count++; switch_to(prev,next,prev); #ifdef CONFIG_VTI /* Post-setup for new domain */ From 811e95f41b068f2d32335c0bdfbbbf3ae488ab71 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Mon, 11 Jul 2005 08:20:39 -0700 Subject: [PATCH 07/12] Fixes so xen+xenlinux boots on ski --- xen/arch/ia64/hyperprivop.S | 11 +++++++---- xen/arch/ia64/vhpt.c | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/xen/arch/ia64/hyperprivop.S b/xen/arch/ia64/hyperprivop.S index 98a4b439bf..581044b135 100644 --- a/xen/arch/ia64/hyperprivop.S +++ b/xen/arch/ia64/hyperprivop.S @@ -288,9 +288,10 @@ GLOBAL_ENTRY(fast_tick_reflect) cmp.ne p6,p0=r28,r30 (p6) br.cond.spnt.few rp;; movl r20=(PERCPU_ADDR)+IA64_CPUINFO_ITM_NEXT_OFFSET;; - ld8 r21=[r20];; + ld8 r26=[r20];; mov r27=ar.itc;; - cmp.ltu p6,p0=r21,r27 + adds r27=200,r27 // safety margin + cmp.ltu p6,p0=r26,r27 (p6) br.cond.spnt.few rp;; mov r17=cr.ipsr;; // slow path if: ipsr.be==1, ipsr.pp==1 @@ -300,14 +301,16 @@ GLOBAL_ENTRY(fast_tick_reflect) extr.u r21=r17,IA64_PSR_PP_BIT,1 ;; cmp.ne p6,p0=r21,r0 (p6) br.cond.spnt.few rp;; + // definitely have a domain tick + mov cr.eoi=r0;; + mov rp=r29;; + mov cr.itm=r26;; // ensure next tick #ifdef FAST_REFLECT_CNT movl r20=fast_reflect_count+((0x3000>>8)*8);; ld8 r21=[r20];; adds r21=1,r21;; st8 [r20]=r21;; #endif - mov cr.eoi=r0;; - mov rp=r29;; // vcpu_pend_timer(current) movl r18=XSI_PSR_IC;; adds r20=XSI_ITV_OFS-XSI_PSR_IC_OFS,r18 ;; diff --git a/xen/arch/ia64/vhpt.c b/xen/arch/ia64/vhpt.c index 86495a8fe8..0eca1abdf3 100644 --- a/xen/arch/ia64/vhpt.c +++ b/xen/arch/ia64/vhpt.c @@ -90,9 +90,10 @@ void vhpt_map(void) void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte, unsigned long logps) { unsigned long mask = (1L << logps) - 1; + extern long running_on_sim; int i; - if (logps-PAGE_SHIFT > 10) { + if (logps-PAGE_SHIFT > 10 && !running_on_sim) { // if this happens, we may want to revisit this algorithm printf("vhpt_multiple_insert:logps-PAGE_SHIFT>10,spinning..\n"); while(1); From 0598f74f0d9c2fea3c0d903e4e0cb89d7f094f2d Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 12 Jul 2005 08:13:06 -0700 Subject: [PATCH 08/12] Better pal/sal support Fix bug with pgd allocation (used pgd_quick) Add some more debug info for tracking down vcpu_translate bad addr Signed-off by: Dan Magenheimer --- xen/arch/ia64/asm-offsets.c | 2 +- xen/arch/ia64/dom_fw.c | 101 +++++++++++++++++++++++++++++++++--- xen/arch/ia64/hypercall.c | 15 ++++-- xen/arch/ia64/ivt.S | 6 +-- xen/arch/ia64/vcpu.c | 18 ++++++- 5 files changed, 126 insertions(+), 16 deletions(-) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index 43589b6586..916ccc0fa6 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -93,7 +93,7 @@ void foo(void) BLANK(); DEFINE(IA64_CPUINFO_ITM_NEXT_OFFSET, offsetof (struct cpuinfo_ia64, itm_next)); - DEFINE(IA64_CPUINFO_PGD_QUICK_OFFSET, offsetof (struct cpuinfo_ia64, pgd_quick)); + DEFINE(IA64_CPUINFO_KSOFTIRQD_OFFSET, offsetof (struct cpuinfo_ia64, ksoftirqd)); //DEFINE(IA64_SIGHAND_SIGLOCK_OFFSET,offsetof (struct sighand_struct, siglock)); diff --git a/xen/arch/ia64/dom_fw.c b/xen/arch/ia64/dom_fw.c index b57a727a50..a090006648 100644 --- a/xen/arch/ia64/dom_fw.c +++ b/xen/arch/ia64/dom_fw.c @@ -154,7 +154,7 @@ offtime (unsigned long t, efi_time_t *tp) return 1; } -extern void pal_emulator_static (void); +extern struct ia64_pal_retval pal_emulator_static (unsigned long); /* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */ @@ -220,17 +220,14 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, */ status = 0; if (index == SAL_FREQ_BASE) { - switch (in1) { + if (!running_on_sim) + status = ia64_sal_freq_base(in1,&r9,&r10); + else switch (in1) { case SAL_FREQ_BASE_PLATFORM: r9 = 200000000; break; case SAL_FREQ_BASE_INTERVAL_TIMER: - /* - * Is this supposed to be the cr.itc frequency - * or something platform specific? The SAL - * doc ain't exactly clear on this... - */ r9 = 700000000; break; @@ -285,6 +282,96 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, return ((struct sal_ret_values) {status, r9, r10, r11}); } +struct ia64_pal_retval +xen_pal_emulator(unsigned long index, unsigned long in1, + unsigned long in2, unsigned long in3) +{ + long r9 = 0; + long r10 = 0; + long r11 = 0; + long status = -1; + + if (running_on_sim) return pal_emulator_static(index); + if (index >= PAL_COPY_PAL) { + printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %d!!!!\n", + index); + } + else switch (index) { + case PAL_MEM_ATTRIB: + status = ia64_pal_mem_attrib(&r9); + break; + case PAL_FREQ_BASE: + status = ia64_pal_freq_base(&r9); + break; + case PAL_PROC_GET_FEATURES: + status = ia64_pal_proc_get_features(&r9,&r10,&r11); + break; + case PAL_BUS_GET_FEATURES: + status = ia64_pal_bus_get_features(&r9,&r10,&r11); + break; + case PAL_FREQ_RATIOS: + status = ia64_pal_freq_ratios(&r9,&r10,&r11); + break; + case PAL_PTCE_INFO: + status = ia64_get_ptce(&r9); + break; + case PAL_VERSION: + status = ia64_pal_version(&r9,&r10); + break; + case PAL_VM_PAGE_SIZE: + status = ia64_pal_vm_page_size(&r9,&r10); + break; + case PAL_DEBUG_INFO: + status = ia64_pal_debug_info(&r9,&r10); + break; + case PAL_CACHE_SUMMARY: + status = ia64_pal_cache_summary(&r9,&r10); + break; + case PAL_VM_SUMMARY: + status = ia64_pal_vm_summary(&r9,&r10); + break; + case PAL_RSE_INFO: + status = ia64_pal_rse_info(&r9,&r10); + break; + case PAL_VM_INFO: + status = ia64_pal_vm_info(in1,in2,&r9,&r10); + break; + case PAL_REGISTER_INFO: + status = ia64_pal_register_info(in1,&r9,&r10); + break; + case PAL_CACHE_FLUSH: + return pal_emulator_static(index); /* FIXME */ + break; + case PAL_PERF_MON_INFO: + { + unsigned long pm_buffer[16]; + status = ia64_pal_perf_mon_info(pm_buffer,&r9); + if (status != 0) break; + if (copy_to_user((void __user *)in1,pm_buffer,128)) + printk("xen_pal_emulator: PAL_PERF_MON_INFO " + "can't copy to user!!!!\n"); + } + break; + case PAL_CACHE_INFO: + { + pal_cache_config_info_t ci; + status = ia64_pal_cache_config_info(in1,in2,&ci); + if (status != 0) break; + r9 = ci.pcci_info_1.pcci1_data; + r10 = ci.pcci_info_2.pcci2_data; + } + break; + case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */ + break; + case PAL_HALT_INFO: /* inappropriate info for guest? */ + break; + default: + printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %d!!!!\n", + index); + break; + } + return ((struct ia64_pal_retval) {status, r9, r10, r11}); +} #define NFUNCPTRS 20 diff --git a/xen/arch/ia64/hypercall.c b/xen/arch/ia64/hypercall.c index 84b05e850c..aecd0be174 100644 --- a/xen/arch/ia64/hypercall.c +++ b/xen/arch/ia64/hypercall.c @@ -16,7 +16,7 @@ #include extern unsigned long translate_domain_mpaddr(unsigned long); -extern struct ia64_sal_retval pal_emulator_static(UINT64); +extern struct ia64_pal_retval xen_pal_emulator(UINT64,UINT64,UINT64,UINT64); extern struct ia64_sal_retval sal_emulator(UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64,UINT64); unsigned long idle_when_pending = 0; @@ -27,6 +27,7 @@ ia64_hypercall (struct pt_regs *regs) { struct vcpu *v = (struct domain *) current; struct ia64_sal_retval x; + struct ia64_pal_retval y; unsigned long *tv, *tc; int pi; @@ -42,7 +43,6 @@ ia64_hypercall (struct pt_regs *regs) // in the idle loop, this should resolve it v->vcpu_info->arch.pending_interruption = 1; #endif - x = pal_emulator_static(regs->r28); if (regs->r28 == PAL_HALT_LIGHT) { #define SPURIOUS_VECTOR 15 pi = vcpu_check_pending_interrupts(v); @@ -62,8 +62,15 @@ ia64_hypercall (struct pt_regs *regs) } //break; } - regs->r8 = x.status; regs->r9 = x.v0; - regs->r10 = x.v1; regs->r11 = x.v2; + else if (regs->r28 >= PAL_COPY_PAL) { /* FIXME */ + printf("stacked PAL hypercalls not supported\n"); + regs->r8 = -1; + break; + } + else y = xen_pal_emulator(regs->r28,regs->r29, + regs->r30,regs->r31); + regs->r8 = y.status; regs->r9 = y.v0; + regs->r10 = y.v1; regs->r11 = y.v2; break; case FW_HYPERCALL_SAL_CALL: x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33), diff --git a/xen/arch/ia64/ivt.S b/xen/arch/ia64/ivt.S index 6530783e67..1ac5593068 100644 --- a/xen/arch/ia64/ivt.S +++ b/xen/arch/ia64/ivt.S @@ -931,10 +931,10 @@ ENTRY(interrupt) ;; #ifdef XEN mov r30=cr.ivr // pass cr.ivr as first arg - // FIXME: this is a hack... use cpuinfo.pgd_quick because its + // FIXME: this is a hack... use cpuinfo.ksoftirqd because its // not used anywhere else and we need a place to stash ivr and // there's no registers available unused by SAVE_MIN/REST - movl r29=(PERCPU_ADDR)+IA64_CPUINFO_PGD_QUICK_OFFSET;; + movl r29=(PERCPU_ADDR)+IA64_CPUINFO_KSOFTIRQD_OFFSET;; st8 [r29]=r30;; movl r28=slow_interrupt;; mov r29=rp;; @@ -954,7 +954,7 @@ slow_interrupt: ;; alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group #ifdef XEN - movl out0=(PERCPU_ADDR)+IA64_CPUINFO_PGD_QUICK_OFFSET;; + movl out0=(PERCPU_ADDR)+IA64_CPUINFO_KSOFTIRQD_OFFSET;; ld8 out0=[out0];; #else mov out0=cr.ivr // pass cr.ivr as first arg diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index 57f721150c..985422b112 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -1263,6 +1263,7 @@ IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr) #define itir_mask(itir) (~((1UL << itir_ps(itir)) - 1)) unsigned long vhpt_translate_count = 0; +int in_vcpu_tpa = 0; IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir) { @@ -1271,8 +1272,20 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt ia64_rr rr; if (!(address >> 61)) { - if (!PSCB(vcpu,metaphysical_mode)) + if (!PSCB(vcpu,metaphysical_mode)) { + REGS *regs = vcpu_regs(vcpu); + unsigned long viip = PSCB(vcpu,iip); + unsigned long vipsr = PSCB(vcpu,ipsr); + unsigned long iip = regs->cr_iip; + unsigned long ipsr = regs->cr_ipsr; +#if 0 + printk("vcpu_translate: bad address %p, viip=%p, vipsr=%p, iip=%p, ipsr=%p\n", address, viip, vipsr, iip, ipsr); + if (in_vcpu_tpa) printk("vcpu_translate called from vcpu_tpa\n"); + while(1); panic_domain(0,"vcpu_translate: bad address %p\n", address); +#endif + printk("vcpu_translate: bad address %p, viip=%p, vipsr=%p, iip=%p, ipsr=%p continuing\n", address, viip, vipsr, iip, ipsr); + } *pteval = (address & _PAGE_PPN_MASK) | __DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX; *itir = PAGE_SHIFT << 2; @@ -1291,6 +1304,7 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt /* check 1-entry TLB */ if ((trp = match_dtlb(vcpu,address))) { dtlb_translate_count++; +if (!in_vcpu_tpa) printf("vcpu_translate: found in vdtlb\n"); *pteval = trp->page_flags; *itir = trp->itir; return IA64_NO_FAULT; @@ -1342,7 +1356,9 @@ IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) UINT64 pteval, itir, mask; IA64FAULT fault; +in_vcpu_tpa=1; fault = vcpu_translate(vcpu, vadr, 1, &pteval, &itir); +in_vcpu_tpa=0; if (fault == IA64_NO_FAULT) { mask = itir_mask(itir); From 109baf1c8e4faa3a212d74485c91a5b3fc25fa73 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Wed, 13 Jul 2005 06:43:49 -0700 Subject: [PATCH 09/12] Add easy way to turn off all fast paths to rule them out when debugging --- xen/arch/ia64/dom_fw.c | 4 +++- xen/arch/ia64/hyperprivop.S | 23 +++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/xen/arch/ia64/dom_fw.c b/xen/arch/ia64/dom_fw.c index a090006648..751f39c64f 100644 --- a/xen/arch/ia64/dom_fw.c +++ b/xen/arch/ia64/dom_fw.c @@ -347,9 +347,11 @@ xen_pal_emulator(unsigned long index, unsigned long in1, unsigned long pm_buffer[16]; status = ia64_pal_perf_mon_info(pm_buffer,&r9); if (status != 0) break; - if (copy_to_user((void __user *)in1,pm_buffer,128)) + if (copy_to_user((void __user *)in1,pm_buffer,128)) { printk("xen_pal_emulator: PAL_PERF_MON_INFO " "can't copy to user!!!!\n"); + status = -1; + } } break; case PAL_CACHE_INFO: diff --git a/xen/arch/ia64/hyperprivop.S b/xen/arch/ia64/hyperprivop.S index 581044b135..4f2af0032a 100644 --- a/xen/arch/ia64/hyperprivop.S +++ b/xen/arch/ia64/hyperprivop.S @@ -14,8 +14,15 @@ #include #include +#if 1 // change to 0 to turn off all fast paths +#define FAST_HYPERPRIVOPS #define FAST_HYPERPRIVOP_CNT #define FAST_REFLECT_CNT +#define FAST_TICK +#define FAST_BREAK +#define FAST_ACCESS_REFLECT +#undef RFI_TO_INTERRUPT // not working yet +#endif // FIXME: This is defined in include/asm-ia64/hw_irq.h but this // doesn't appear to be include'able from assembly? @@ -45,6 +52,9 @@ // r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) // r31 == pr GLOBAL_ENTRY(fast_hyperprivop) +#ifndef FAST_HYPERPRIVOPS // see beginning of file + br.sptk.many dispatch_break_fault ;; +#endif // HYPERPRIVOP_SSM_I? // assumes domain interrupts pending, so just do it cmp.eq p7,p6=XEN_HYPER_SSM_I,r17 @@ -280,8 +290,7 @@ ENTRY(hyper_ssm_i) // r30 == cr.ivr // r29 == rp GLOBAL_ENTRY(fast_tick_reflect) -#define FAST_TICK -#ifndef FAST_TICK +#ifndef FAST_TICK // see beginning of file br.cond.sptk.many rp;; #endif mov r28=IA64_TIMER_VECTOR;; @@ -290,7 +299,7 @@ GLOBAL_ENTRY(fast_tick_reflect) movl r20=(PERCPU_ADDR)+IA64_CPUINFO_ITM_NEXT_OFFSET;; ld8 r26=[r20];; mov r27=ar.itc;; - adds r27=200,r27 // safety margin + adds r27=200,r27;; // safety margin cmp.ltu p6,p0=r26,r27 (p6) br.cond.spnt.few rp;; mov r17=cr.ipsr;; @@ -453,8 +462,7 @@ END(fast_tick_reflect) // r19 == vpsr.ic (low 32 bits) | vpsr.i (high 32 bits) // r31 == pr GLOBAL_ENTRY(fast_break_reflect) -#define FAST_BREAK -#ifndef FAST_BREAK +#ifndef FAST_BREAK // see beginning of file br.sptk.many dispatch_break_fault ;; #endif mov r30=cr.ipsr;; @@ -595,6 +603,9 @@ ENTRY(fast_reflect) // r20 == offset into ivt // r31 == pr GLOBAL_ENTRY(fast_access_reflect) +#ifndef FAST_ACCESS_REFLECT // see beginning of file + br.spnt.few dispatch_reflection ;; +#endif mov r30=cr.ipsr;; mov r29=cr.iip;; extr.u r21=r30,IA64_PSR_BE_BIT,1 ;; @@ -670,7 +681,7 @@ ENTRY(hyper_rfi) cmp.ltu p0,p7=r22,r23 ;; // if !(iip=high) (p7) br.spnt.few dispatch_break_fault ;; -#ifndef RFI_TO_INTERRUPT +#ifndef RFI_TO_INTERRUPT // see beginning of file cmp.ne p6,p0=r30,r0 (p6) br.cond.spnt.few dispatch_break_fault ;; #endif From e4cc50f7a43b8e9c86e99568fc9a06e360e1e9d8 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Wed, 13 Jul 2005 13:12:00 -0700 Subject: [PATCH 10/12] Fix PAL_PTCE_INFO and cpuid (pfmon now works) --- xen/arch/ia64/dom_fw.c | 27 ++++++++++++++++++++++++--- xen/arch/ia64/vcpu.c | 12 ++++++++---- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/xen/arch/ia64/dom_fw.c b/xen/arch/ia64/dom_fw.c index 751f39c64f..160d5be4cc 100644 --- a/xen/arch/ia64/dom_fw.c +++ b/xen/arch/ia64/dom_fw.c @@ -313,7 +313,14 @@ xen_pal_emulator(unsigned long index, unsigned long in1, status = ia64_pal_freq_ratios(&r9,&r10,&r11); break; case PAL_PTCE_INFO: - status = ia64_get_ptce(&r9); + { + ia64_ptce_info_t ptce; + status = ia64_get_ptce(&ptce); + if (status != 0) break; + r9 = ptce.base; + r10 = (ptce.count[0]<<32)|(ptce.count[1]&0xffffffffL); + r11 = (ptce.stride[0]<<32)|(ptce.stride[1]&0xffffffffL); + } break; case PAL_VERSION: status = ia64_pal_version(&r9,&r10); @@ -340,18 +347,30 @@ xen_pal_emulator(unsigned long index, unsigned long in1, status = ia64_pal_register_info(in1,&r9,&r10); break; case PAL_CACHE_FLUSH: - return pal_emulator_static(index); /* FIXME */ + /* FIXME */ + printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n"); + BUG(); break; case PAL_PERF_MON_INFO: { unsigned long pm_buffer[16]; + int i; status = ia64_pal_perf_mon_info(pm_buffer,&r9); - if (status != 0) break; + if (status != 0) { + while(1) + printk("PAL_PERF_MON_INFO fails ret=%d\n",status); + break; + } if (copy_to_user((void __user *)in1,pm_buffer,128)) { + while(1) printk("xen_pal_emulator: PAL_PERF_MON_INFO " "can't copy to user!!!!\n"); status = -1; + break; } + printk("PAL_PERF_MON_INFO succeeds! r9=%lx\n",r9); + for (i=0; i<16;i++) + printk("pm_buffer[i]=%lx\n",pm_buffer[i]); } break; case PAL_CACHE_INFO: @@ -364,8 +383,10 @@ xen_pal_emulator(unsigned long index, unsigned long in1, } break; case PAL_VM_TR_READ: /* FIXME: vcpu_get_tr?? */ + printk("PAL_VM_TR_READ NOT IMPLEMENTED, IGNORED!\n"); break; case PAL_HALT_INFO: /* inappropriate info for guest? */ + printk("PAL_HALT_INFO NOT IMPLEMENTED, IGNORED!\n"); break; default: printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %d!!!!\n", diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index 985422b112..c850c5fd65 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -1499,20 +1499,24 @@ IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval) // if reg > 3 switch(reg) { case 0: - case 1: memcpy(pval,"Xen/ia64",8); break; + case 1: + *pval = 0; + break; case 2: *pval = 0; break; case 3: - *pval = 0; //FIXME: See vol1, 3.1.11 + *pval = ia64_get_cpuid(3); break; case 4: - *pval = 1; //FIXME: See vol1, 3.1.11 + *pval = ia64_get_cpuid(4); break; default: - *pval = 0; //FIXME: See vol1, 3.1.11 + if (reg > (ia64_get_cpuid(3) & 0xff)) + return IA64_RSVDREG_FAULT; + *pval = ia64_get_cpuid(reg); break; } return (IA64_NO_FAULT); From 9b63984dd1ef9262c81688756df65a9392151e2e Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Wed, 13 Jul 2005 13:18:04 -0700 Subject: [PATCH 11/12] Oops remove debug output from last changeset --- xen/arch/ia64/dom_fw.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/xen/arch/ia64/dom_fw.c b/xen/arch/ia64/dom_fw.c index 160d5be4cc..bf92f30494 100644 --- a/xen/arch/ia64/dom_fw.c +++ b/xen/arch/ia64/dom_fw.c @@ -368,9 +368,6 @@ xen_pal_emulator(unsigned long index, unsigned long in1, status = -1; break; } - printk("PAL_PERF_MON_INFO succeeds! r9=%lx\n",r9); - for (i=0; i<16;i++) - printk("pm_buffer[i]=%lx\n",pm_buffer[i]); } break; case PAL_CACHE_INFO: From 9996d95f75e58cb7747cfaf9f2a7cdd89392100b Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Thu, 14 Jul 2005 10:46:11 -0700 Subject: [PATCH 12/12] Fix for new ns16550 serial code in xen-unstable.hg --- xen/arch/ia64/xensetup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c index b4cc8f52c9..58a696a458 100644 --- a/xen/arch/ia64/xensetup.c +++ b/xen/arch/ia64/xensetup.c @@ -14,7 +14,7 @@ //#include #include //#include -//#include +#include #include #include #include