From 70173dbb9948b13f423aabbd49d7f7cea6b34d1e Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 25 Sep 2014 14:07:27 +0200 Subject: [PATCH 01/13] x86/HVM: fix miscellaneous aspects of x2APIC emulation - generate #GP on invalid APIC base MSR transitions - fail reads from the EOI and self-IPI registers (which are write-only) - handle self-IPI writes and the ICR2 half of ICR writes largely in hvm_x2apic_msr_write() and (for self-IPI only) vlapic_apicv_write() - don't permit MMIO-based access in x2APIC mode - filter writes to read-only registers in hvm_x2apic_msr_write(), allowing conditionals to be dropped from vlapic_reg_write() - don't ignore upper half of MSR-based write to ESR being non-zero - don't ignore other writes to reserved bits - VMX's EXIT_REASON_APIC_WRITE must not result in #GP (this exit being trap-like, this exception would get raised on the wrong RIP) - make hvm_x2apic_msr_read() produce X86EMUL_* return codes just like hvm_x2apic_msr_write() does (benign to the only caller) Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Acked-by: Tim Deegan --- xen/arch/x86/hvm/hvm.c | 3 +- xen/arch/x86/hvm/vlapic.c | 151 +++++++++++++++++++++---------- xen/arch/x86/hvm/vmx/vmx.c | 3 +- xen/include/asm-x86/hvm/vlapic.h | 2 +- 4 files changed, 107 insertions(+), 52 deletions(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 34f28d0fcd..9504ffc4b6 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -4504,7 +4504,8 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content) break; case MSR_IA32_APICBASE: - vlapic_msr_set(vcpu_vlapic(v), msr_content); + if ( !vlapic_msr_set(vcpu_vlapic(v), msr_content) ) + goto gp_fault; break; case MSR_IA32_TSC_DEADLINE: diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 47c4eaa1a1..09804f8b08 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -45,11 +45,11 @@ #define VLAPIC_LVT_NUM 6 #define LVT_MASK \ - APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK + (APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK) #define LINT_MASK \ - LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\ - APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER + (LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY |\ + APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER) static const unsigned int vlapic_lvt_mask[VLAPIC_LVT_NUM] = { @@ -614,7 +614,7 @@ int hvm_x2apic_msr_read(struct vcpu *v, unsigned int msr, uint64_t *msr_content) uint32_t low, high = 0, offset = (msr - MSR_IA32_APICBASE_MSR) << 4; if ( !vlapic_x2apic_mode(vlapic) ) - return 1; + return X86EMUL_UNHANDLEABLE; vlapic_read_aligned(vlapic, offset, &low); switch ( offset ) @@ -627,12 +627,15 @@ int hvm_x2apic_msr_read(struct vcpu *v, unsigned int msr, uint64_t *msr_content) vlapic_read_aligned(vlapic, APIC_ICR2, &high); break; + case APIC_EOI: case APIC_ICR2: - return 1; + case APIC_SELF_IPI: + return X86EMUL_UNHANDLEABLE; } *msr_content = (((uint64_t)high) << 32) | low; - return 0; + + return X86EMUL_OKAY; } static void vlapic_pt_cb(struct vcpu *v, void *data) @@ -656,10 +659,7 @@ static int vlapic_reg_write(struct vcpu *v, switch ( offset ) { case APIC_ID: - if ( !vlapic_x2apic_mode(vlapic) ) - vlapic_set_reg(vlapic, APIC_ID, val); - else - rc = X86EMUL_UNHANDLEABLE; + vlapic_set_reg(vlapic, APIC_ID, val); break; case APIC_TASKPRI: @@ -671,17 +671,11 @@ static int vlapic_reg_write(struct vcpu *v, break; case APIC_LDR: - if ( !vlapic_x2apic_mode(vlapic) ) - vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK); - else - rc = X86EMUL_UNHANDLEABLE; + vlapic_set_reg(vlapic, APIC_LDR, val & APIC_LDR_MASK); break; case APIC_DFR: - if ( !vlapic_x2apic_mode(vlapic) ) - vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF); - else - rc = X86EMUL_UNHANDLEABLE; + vlapic_set_reg(vlapic, APIC_DFR, val | 0x0FFFFFFF); break; case APIC_SPIV: @@ -708,21 +702,6 @@ static int vlapic_reg_write(struct vcpu *v, } break; - case APIC_ESR: - if ( vlapic_x2apic_mode(vlapic) && (val != 0) ) - { - gdprintk(XENLOG_ERR, "Local APIC write ESR with non-zero %lx\n", - val); - rc = X86EMUL_UNHANDLEABLE; - } - break; - - case APIC_SELF_IPI: - rc = vlapic_x2apic_mode(vlapic) - ? vlapic_reg_write(v, APIC_ICR, 0x40000 | (val & 0xff)) - : X86EMUL_UNHANDLEABLE; - break; - case APIC_ICR: val &= ~(1 << 12); /* always clear the pending bit */ vlapic_ipi(vlapic, val, vlapic_get_reg(vlapic, APIC_ICR2)); @@ -730,9 +709,7 @@ static int vlapic_reg_write(struct vcpu *v, break; case APIC_ICR2: - if ( !vlapic_x2apic_mode(vlapic) ) - val &= 0xff000000; - vlapic_set_reg(vlapic, APIC_ICR2, val); + vlapic_set_reg(vlapic, APIC_ICR2, val & 0xff000000); break; case APIC_LVTT: /* LVT Timer Reg */ @@ -877,8 +854,17 @@ static int vlapic_write(struct vcpu *v, unsigned long address, int vlapic_apicv_write(struct vcpu *v, unsigned int offset) { - uint32_t val = vlapic_get_reg(vcpu_vlapic(v), offset); - return vlapic_reg_write(v, offset, val); + struct vlapic *vlapic = vcpu_vlapic(v); + uint32_t val = vlapic_get_reg(vlapic, offset); + + if ( !vlapic_x2apic_mode(vlapic) ) + return vlapic_reg_write(v, offset, val); + + if ( offset != APIC_SELF_IPI ) + return X86EMUL_UNHANDLEABLE; + + return vlapic_reg_write(v, APIC_ICR, + APIC_DEST_SELF | (val & APIC_VECTOR_MASK)); } int hvm_x2apic_msr_write(struct vcpu *v, unsigned int msr, uint64_t msr_content) @@ -891,16 +877,69 @@ int hvm_x2apic_msr_write(struct vcpu *v, unsigned int msr, uint64_t msr_content) switch ( offset ) { - int rc; - - case APIC_ICR: - rc = vlapic_reg_write(v, APIC_ICR2, (uint32_t)(msr_content >> 32)); - if ( rc ) - return rc; + case APIC_TASKPRI: + if ( msr_content & ~APIC_TPRI_MASK ) + return X86EMUL_UNHANDLEABLE; break; - case APIC_ICR2: - return X86EMUL_UNHANDLEABLE; + case APIC_SPIV: + if ( msr_content & ~(APIC_VECTOR_MASK | APIC_SPIV_APIC_ENABLED | + (VLAPIC_VERSION & APIC_LVR_DIRECTED_EOI + ? APIC_SPIV_DIRECTED_EOI : 0)) ) + return X86EMUL_UNHANDLEABLE; + break; + + case APIC_LVTT: + if ( msr_content & ~(LVT_MASK | APIC_TIMER_MODE_MASK) ) + return X86EMUL_UNHANDLEABLE; + break; + + case APIC_LVTTHMR: + case APIC_LVTPC: + case APIC_CMCI: + if ( msr_content & ~(LVT_MASK | APIC_MODE_MASK) ) + return X86EMUL_UNHANDLEABLE; + break; + + case APIC_LVT0: + case APIC_LVT1: + if ( msr_content & ~LINT_MASK ) + return X86EMUL_UNHANDLEABLE; + break; + + case APIC_LVTERR: + if ( msr_content & ~LVT_MASK ) + return X86EMUL_UNHANDLEABLE; + break; + + case APIC_TMICT: + break; + + case APIC_TDCR: + if ( msr_content & ~APIC_TDR_DIV_1 ) + return X86EMUL_UNHANDLEABLE; + break; + + case APIC_ICR: + if ( (uint32_t)msr_content & ~(APIC_VECTOR_MASK | APIC_MODE_MASK | + APIC_DEST_MASK | APIC_INT_ASSERT | + APIC_INT_LEVELTRIG | APIC_SHORT_MASK) ) + return X86EMUL_UNHANDLEABLE; + vlapic_set_reg(vlapic, APIC_ICR2, msr_content >> 32); + break; + + case APIC_SELF_IPI: + if ( msr_content & ~APIC_VECTOR_MASK ) + return X86EMUL_UNHANDLEABLE; + offset = APIC_ICR; + msr_content = APIC_DEST_SELF | (msr_content & APIC_VECTOR_MASK); + break; + + case APIC_EOI: + case APIC_ESR: + if ( msr_content ) + default: + return X86EMUL_UNHANDLEABLE; } return vlapic_reg_write(v, offset, (uint32_t)msr_content); @@ -910,7 +949,10 @@ static int vlapic_range(struct vcpu *v, unsigned long addr) { struct vlapic *vlapic = vcpu_vlapic(v); unsigned long offset = addr - vlapic_base_address(vlapic); - return (!vlapic_hw_disabled(vlapic) && (offset < PAGE_SIZE)); + + return !vlapic_hw_disabled(vlapic) && + !vlapic_x2apic_mode(vlapic) && + (offset < PAGE_SIZE); } const struct hvm_mmio_handler vlapic_mmio_handler = { @@ -919,10 +961,12 @@ const struct hvm_mmio_handler vlapic_mmio_handler = { .write_handler = vlapic_write }; -void vlapic_msr_set(struct vlapic *vlapic, uint64_t value) +bool_t vlapic_msr_set(struct vlapic *vlapic, uint64_t value) { if ( (vlapic->hw.apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE ) { + if ( unlikely(value & MSR_IA32_APICBASE_EXTD) ) + return 0; if ( value & MSR_IA32_APICBASE_ENABLE ) { vlapic_reset(vlapic); @@ -931,10 +975,15 @@ void vlapic_msr_set(struct vlapic *vlapic, uint64_t value) } else { + if ( unlikely(vlapic_x2apic_mode(vlapic)) ) + return 0; vlapic->hw.disabled |= VLAPIC_HW_DISABLED; pt_may_unmask_irq(vlapic_domain(vlapic), NULL); } } + else if ( !(value & MSR_IA32_APICBASE_ENABLE) && + unlikely(value & MSR_IA32_APICBASE_EXTD) ) + return 0; vlapic->hw.apic_base_msr = value; @@ -949,6 +998,8 @@ void vlapic_msr_set(struct vlapic *vlapic, uint64_t value) HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "apic base msr is 0x%016"PRIx64, vlapic->hw.apic_base_msr); + + return 1; } uint64_t vlapic_tdt_msr_get(struct vlapic *vlapic) @@ -1232,6 +1283,10 @@ static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h) if ( hvm_load_entry_zeroextend(LAPIC, h, &s->hw) != 0 ) return -EINVAL; + if ( !(s->hw.apic_base_msr & MSR_IA32_APICBASE_ENABLE) && + unlikely(vlapic_x2apic_mode(s)) ) + return -EINVAL; + vmx_vlapic_msr_changed(v); return 0; diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 923f0082ec..fd0ad59c04 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -3123,8 +3123,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) break; case EXIT_REASON_APIC_WRITE: - if ( vmx_handle_apic_write() ) - hvm_inject_hw_exception(TRAP_gp_fault, 0); + vmx_handle_apic_write(); break; case EXIT_REASON_ACCESS_GDTR_OR_IDTR: diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index 66f0aff4fc..a1ae95ed0c 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -106,7 +106,7 @@ void vlapic_destroy(struct vcpu *v); void vlapic_reset(struct vlapic *vlapic); -void vlapic_msr_set(struct vlapic *vlapic, uint64_t value); +bool_t vlapic_msr_set(struct vlapic *vlapic, uint64_t value); void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t value); uint64_t vlapic_tdt_msr_get(struct vlapic *vlapic); From f9e0cccf7b355896d8fd9f87d66e34f77de61061 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 25 Sep 2014 14:08:20 +0200 Subject: [PATCH 02/13] x86/HVM: fix ID handling of x2APIC emulation - properly change ID when switching into x2APIC mode (instead of mimicking necessary behavior in hvm_x2apic_msr_read()) - correctly (meaningfully) set LDR (so far it ended up being 1 on all vCPU-s) - even if we don't support more than 128 vCPU-s in a HVM guest for now, we should properly handle IDs as 32-bit values (i.e. not ignore the top 24 bits) - with that, properly do cluster ID and bit mask check in vlapic_match_logical_addr() Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Acked-by: Tim Deegan --- xen/arch/x86/hvm/vlapic.c | 85 +++++++++++++++++++++++--------- xen/include/asm-x86/hvm/vlapic.h | 13 +++-- 2 files changed, 72 insertions(+), 26 deletions(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 09804f8b08..19a099a4aa 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -173,18 +173,17 @@ uint32_t vlapic_set_ppr(struct vlapic *vlapic) return ppr; } -static int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda) +static int vlapic_match_logical_addr(struct vlapic *vlapic, uint32_t mda) { int result = 0; - uint32_t logical_id; + uint32_t logical_id = vlapic_get_reg(vlapic, APIC_LDR); if ( vlapic_x2apic_mode(vlapic) ) - { - logical_id = vlapic_get_reg(vlapic, APIC_LDR); - return !!(logical_id & mda); - } + return ((logical_id >> 16) == (mda >> 16)) && + (uint16_t)(logical_id & mda); - logical_id = GET_xAPIC_LOGICAL_ID(vlapic_get_reg(vlapic, APIC_LDR)); + logical_id = GET_xAPIC_LOGICAL_ID(logical_id); + mda = (uint8_t)mda; switch ( vlapic_get_reg(vlapic, APIC_DFR) ) { @@ -208,7 +207,7 @@ static int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda) bool_t vlapic_match_dest( struct vlapic *target, struct vlapic *source, - int short_hand, uint8_t dest, uint8_t dest_mode) + int short_hand, uint32_t dest, uint8_t dest_mode) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest %#x, " "dest_mode %#x, short_hand %#x", @@ -219,7 +218,8 @@ bool_t vlapic_match_dest( case APIC_DEST_NOSHORT: if ( dest_mode ) return vlapic_match_logical_addr(target, dest); - return ((dest == 0xFF) || (dest == VLAPIC_ID(target))); + return (dest == _VLAPIC_ID(target, 0xffffffff)) || + (dest == VLAPIC_ID(target)); case APIC_DEST_SELF: return (target == source); @@ -353,7 +353,7 @@ static void vlapic_accept_irq(struct vcpu *v, uint32_t icr_low) struct vlapic *vlapic_lowest_prio( struct domain *d, struct vlapic *source, - int short_hand, uint8_t dest, uint8_t dest_mode) + int short_hand, uint32_t dest, uint8_t dest_mode) { int old = d->arch.hvm_domain.irq.round_robin_prev_vcpu; uint32_t ppr, target_ppr = UINT_MAX; @@ -438,9 +438,7 @@ void vlapic_ipi( HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr = 0x%08x:%08x", icr_high, icr_low); - dest = (vlapic_x2apic_mode(vlapic) - ? icr_high - : GET_xAPIC_DEST_FIELD(icr_high)); + dest = _VLAPIC_ID(vlapic, icr_high); switch ( icr_low & APIC_MODE_MASK ) { @@ -619,10 +617,6 @@ int hvm_x2apic_msr_read(struct vcpu *v, unsigned int msr, uint64_t *msr_content) vlapic_read_aligned(vlapic, offset, &low); switch ( offset ) { - case APIC_ID: - low = GET_xAPIC_ID(low); - break; - case APIC_ICR: vlapic_read_aligned(vlapic, APIC_ICR2, &high); break; @@ -656,6 +650,8 @@ static int vlapic_reg_write(struct vcpu *v, struct vlapic *vlapic = vcpu_vlapic(v); int rc = X86EMUL_OKAY; + memset(&vlapic->loaded, 0, sizeof(vlapic->loaded)); + switch ( offset ) { case APIC_ID: @@ -961,6 +957,15 @@ const struct hvm_mmio_handler vlapic_mmio_handler = { .write_handler = vlapic_write }; +static void set_x2apic_id(struct vlapic *vlapic) +{ + u32 id = vlapic_vcpu(vlapic)->vcpu_id; + u32 ldr = ((id & ~0xf) << 12) | (1 << (id & 0xf)); + + vlapic_set_reg(vlapic, APIC_ID, id * 2); + vlapic_set_reg(vlapic, APIC_LDR, ldr); +} + bool_t vlapic_msr_set(struct vlapic *vlapic, uint64_t value) { if ( (vlapic->hw.apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE ) @@ -986,13 +991,10 @@ bool_t vlapic_msr_set(struct vlapic *vlapic, uint64_t value) return 0; vlapic->hw.apic_base_msr = value; + memset(&vlapic->loaded, 0, sizeof(vlapic->loaded)); if ( vlapic_x2apic_mode(vlapic) ) - { - u32 id = vlapic_get_reg(vlapic, APIC_ID); - u32 ldr = ((id & ~0xf) << 16) | (1 << (id & 0xf)); - vlapic_set_reg(vlapic, APIC_LDR, ldr); - } + set_x2apic_id(vlapic); vmx_vlapic_msr_changed(vlapic_vcpu(vlapic)); @@ -1264,6 +1266,35 @@ static int lapic_save_regs(struct domain *d, hvm_domain_context_t *h) return rc; } +/* + * Following lapic_load_hidden()/lapic_load_regs() we may need to + * correct ID and LDR when they come from an old, broken hypervisor. + */ +static void lapic_load_fixup(struct vlapic *vlapic) +{ + uint32_t id = vlapic->loaded.id; + + if ( vlapic_x2apic_mode(vlapic) && id && vlapic->loaded.ldr == 1 ) + { + /* + * This is optional: ID != 0 contradicts LDR == 1. It's being added + * to aid in eventual debugging of issues arising from the fixup done + * here, but can be dropped as soon as it is found to conflict with + * other (future) changes. + */ + if ( GET_xAPIC_ID(id) != vlapic_vcpu(vlapic)->vcpu_id * 2 || + id != SET_xAPIC_ID(GET_xAPIC_ID(id)) ) + printk(XENLOG_G_WARNING "%pv: bogus APIC ID %#x loaded\n", + vlapic_vcpu(vlapic), id); + set_x2apic_id(vlapic); + } + else /* Undo an eventual earlier fixup. */ + { + vlapic_set_reg(vlapic, APIC_ID, id); + vlapic_set_reg(vlapic, APIC_LDR, vlapic->loaded.ldr); + } +} + static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h) { uint16_t vcpuid; @@ -1283,6 +1314,10 @@ static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h) if ( hvm_load_entry_zeroextend(LAPIC, h, &s->hw) != 0 ) return -EINVAL; + s->loaded.hw = 1; + if ( s->loaded.regs ) + lapic_load_fixup(s); + if ( !(s->hw.apic_base_msr & MSR_IA32_APICBASE_ENABLE) && unlikely(vlapic_x2apic_mode(s)) ) return -EINVAL; @@ -1311,6 +1346,12 @@ static int lapic_load_regs(struct domain *d, hvm_domain_context_t *h) if ( hvm_load_entry(LAPIC_REGS, h, s->regs) != 0 ) return -EINVAL; + s->loaded.id = vlapic_get_reg(s, APIC_ID); + s->loaded.ldr = vlapic_get_reg(s, APIC_LDR); + s->loaded.regs = 1; + if ( s->loaded.hw ) + lapic_load_fixup(s); + if ( hvm_funcs.process_isr ) hvm_funcs.process_isr(vlapic_find_highest_isr(s), v); diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index a1ae95ed0c..0b00791336 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -30,8 +30,9 @@ #define vlapic_vcpu(x) (container_of((x), struct vcpu, arch.hvm_vcpu.vlapic)) #define vlapic_domain(x) (vlapic_vcpu(x)->domain) -#define VLAPIC_ID(vlapic) \ - (GET_xAPIC_ID(vlapic_get_reg((vlapic), APIC_ID))) +#define _VLAPIC_ID(vlapic, id) (vlapic_x2apic_mode(vlapic) \ + ? (id) : GET_xAPIC_ID(id)) +#define VLAPIC_ID(vlapic) _VLAPIC_ID(vlapic, vlapic_get_reg(vlapic, APIC_ID)) /* * APIC can be disabled in two ways: @@ -70,6 +71,10 @@ struct vlapic { struct hvm_hw_lapic hw; struct hvm_hw_lapic_regs *regs; + struct { + bool_t hw, regs; + uint32_t id, ldr; + } loaded; struct periodic_time pt; s_time_t timer_last_update; struct page_info *regs_page; @@ -124,10 +129,10 @@ int vlapic_apicv_write(struct vcpu *v, unsigned int offset); struct vlapic *vlapic_lowest_prio( struct domain *d, struct vlapic *source, - int short_hand, uint8_t dest, uint8_t dest_mode); + int short_hand, uint32_t dest, uint8_t dest_mode); bool_t vlapic_match_dest( struct vlapic *target, struct vlapic *source, - int short_hand, uint8_t dest, uint8_t dest_mode); + int short_hand, uint32_t dest, uint8_t dest_mode); #endif /* __ASM_X86_HVM_VLAPIC_H__ */ From 5623343d05a0a63c9a77f0254312c79e41795f76 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 25 Sep 2014 14:09:10 +0200 Subject: [PATCH 03/13] x86/vlapic: a few type adjustments Constify a couple of pointer parameters, convert a boolean function return type to bool_t, and clean up a printk() being touched anyway. Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Acked-by: Tim Deegan --- xen/arch/x86/hvm/vlapic.c | 23 ++++++++++++----------- xen/include/asm-x86/hvm/vlapic.h | 13 ++++++++----- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 19a099a4aa..99ae1be00b 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -173,9 +173,10 @@ uint32_t vlapic_set_ppr(struct vlapic *vlapic) return ppr; } -static int vlapic_match_logical_addr(struct vlapic *vlapic, uint32_t mda) +static bool_t vlapic_match_logical_addr(const struct vlapic *vlapic, + uint32_t mda) { - int result = 0; + bool_t result = 0; uint32_t logical_id = vlapic_get_reg(vlapic, APIC_LDR); if ( vlapic_x2apic_mode(vlapic) ) @@ -196,9 +197,9 @@ static int vlapic_match_logical_addr(struct vlapic *vlapic, uint32_t mda) result = 1; break; default: - gdprintk(XENLOG_WARNING, "Bad DFR value for lapic of vcpu %d: %08x\n", - vlapic_vcpu(vlapic)->vcpu_id, - vlapic_get_reg(vlapic, APIC_DFR)); + printk(XENLOG_G_WARNING "%pv: bad LAPIC DFR value %08x\n", + const_vlapic_vcpu(vlapic), + vlapic_get_reg(vlapic, APIC_DFR)); break; } @@ -206,8 +207,8 @@ static int vlapic_match_logical_addr(struct vlapic *vlapic, uint32_t mda) } bool_t vlapic_match_dest( - struct vlapic *target, struct vlapic *source, - int short_hand, uint32_t dest, uint8_t dest_mode) + const struct vlapic *target, const struct vlapic *source, + int short_hand, uint32_t dest, bool_t dest_mode) { HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "target %p, source %p, dest %#x, " "dest_mode %#x, short_hand %#x", @@ -286,7 +287,7 @@ static void vlapic_init_sipi_action(unsigned long _vcpu) uint32_t icr = vcpu_vlapic(origin)->init_sipi.icr; uint32_t dest = vcpu_vlapic(origin)->init_sipi.dest; uint32_t short_hand = icr & APIC_SHORT_MASK; - uint32_t dest_mode = !!(icr & APIC_DEST_MASK); + bool_t dest_mode = !!(icr & APIC_DEST_MASK); struct vcpu *v; if ( icr == 0 ) @@ -352,8 +353,8 @@ static void vlapic_accept_irq(struct vcpu *v, uint32_t icr_low) } struct vlapic *vlapic_lowest_prio( - struct domain *d, struct vlapic *source, - int short_hand, uint32_t dest, uint8_t dest_mode) + struct domain *d, const struct vlapic *source, + int short_hand, uint32_t dest, bool_t dest_mode) { int old = d->arch.hvm_domain.irq.round_robin_prev_vcpu; uint32_t ppr, target_ppr = UINT_MAX; @@ -434,7 +435,7 @@ void vlapic_ipi( { unsigned int dest; unsigned int short_hand = icr_low & APIC_SHORT_MASK; - unsigned int dest_mode = !!(icr_low & APIC_DEST_MASK); + bool_t dest_mode = !!(icr_low & APIC_DEST_MASK); HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "icr = 0x%08x:%08x", icr_high, icr_low); diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index 0b00791336..bf59b9594c 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -28,6 +28,8 @@ #define vcpu_vlapic(x) (&(x)->arch.hvm_vcpu.vlapic) #define vlapic_vcpu(x) (container_of((x), struct vcpu, arch.hvm_vcpu.vlapic)) +#define const_vlapic_vcpu(x) (container_of((x), const struct vcpu, \ + arch.hvm_vcpu.vlapic)) #define vlapic_domain(x) (vlapic_vcpu(x)->domain) #define _VLAPIC_ID(vlapic, id) (vlapic_x2apic_mode(vlapic) \ @@ -88,7 +90,8 @@ struct vlapic { /* vlapic's frequence is 100 MHz */ #define APIC_BUS_CYCLE_NS 10 -static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg) +static inline uint32_t vlapic_get_reg(const struct vlapic *vlapic, + uint32_t reg) { return *((uint32_t *)(&vlapic->regs->data[reg])); } @@ -128,11 +131,11 @@ void vlapic_ipi(struct vlapic *vlapic, uint32_t icr_low, uint32_t icr_high); int vlapic_apicv_write(struct vcpu *v, unsigned int offset); struct vlapic *vlapic_lowest_prio( - struct domain *d, struct vlapic *source, - int short_hand, uint32_t dest, uint8_t dest_mode); + struct domain *d, const struct vlapic *source, + int short_hand, uint32_t dest, bool_t dest_mode); bool_t vlapic_match_dest( - struct vlapic *target, struct vlapic *source, - int short_hand, uint32_t dest, uint8_t dest_mode); + const struct vlapic *target, const struct vlapic *source, + int short_hand, uint32_t dest, bool_t dest_mode); #endif /* __ASM_X86_HVM_VLAPIC_H__ */ From 0a43c50cb0c55d2f770b69d9452c994d9f2cdd84 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Thu, 25 Sep 2014 14:10:01 +0200 Subject: [PATCH 04/13] x86/vlapic: don't silently accept bad vectors Vectors 0-15 are reserved, and a physical LAPIC - upon sending or receiving one - would generate an APIC error instead of doing the requested action. Make our emulation behave similarly. Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper Acked-by: Tim Deegan --- xen/arch/x86/hvm/vlapic.c | 38 +++++++++++++++++++++++++++++++- xen/include/asm-x86/hvm/vlapic.h | 1 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 99ae1be00b..388e656baf 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -123,10 +123,34 @@ static int vlapic_find_highest_irr(struct vlapic *vlapic) return vlapic_find_highest_vector(&vlapic->regs->data[APIC_IRR]); } +static void vlapic_error(struct vlapic *vlapic, unsigned int errmask) +{ + unsigned long flags; + uint32_t esr; + + spin_lock_irqsave(&vlapic->esr_lock, flags); + esr = vlapic_get_reg(vlapic, APIC_ESR); + if ( (esr & errmask) != errmask ) + { + uint32_t lvterr = vlapic_get_reg(vlapic, APIC_LVTERR); + + vlapic_set_reg(vlapic, APIC_ESR, esr | errmask); + if ( !(lvterr & APIC_LVT_MASKED) ) + vlapic_set_irq(vlapic, lvterr & APIC_VECTOR_MASK, 0); + } + spin_unlock_irqrestore(&vlapic->esr_lock, flags); +} + void vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig) { struct vcpu *target = vlapic_vcpu(vlapic); + if ( unlikely(vec < 16) ) + { + vlapic_error(vlapic, APIC_ESR_RECVILL); + return; + } + if ( trig ) vlapic_set_vector(vec, &vlapic->regs->data[APIC_TMR]); @@ -460,7 +484,12 @@ void vlapic_ipi( struct vlapic *target = vlapic_lowest_prio( vlapic_domain(vlapic), vlapic, short_hand, dest, dest_mode); if ( target != NULL ) - vlapic_accept_irq(vlapic_vcpu(target), icr_low); + { + if ( likely((icr_low & APIC_VECTOR_MASK) >= 16) ) + vlapic_accept_irq(vlapic_vcpu(target), icr_low); + else + vlapic_error(vlapic, APIC_ESR_SENDILL); + } break; } @@ -468,6 +497,11 @@ void vlapic_ipi( struct vcpu *v; bool_t batch = is_multicast_dest(vlapic, short_hand, dest, dest_mode); + if ( unlikely((icr_low & APIC_VECTOR_MASK) < 16) ) + { + vlapic_error(vlapic, APIC_ESR_SENDILL); + break; + } if ( batch ) cpu_raise_softirq_batch_begin(); for_each_vcpu ( vlapic_domain(vlapic), v ) @@ -1404,6 +1438,8 @@ int vlapic_init(struct vcpu *v) if ( v->vcpu_id == 0 ) vlapic->hw.apic_base_msr |= MSR_IA32_APICBASE_BSP; + spin_lock_init(&vlapic->esr_lock); + tasklet_init(&vlapic->init_sipi.tasklet, vlapic_init_sipi_action, (unsigned long)v); diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index bf59b9594c..16752b5195 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -77,6 +77,7 @@ struct vlapic { bool_t hw, regs; uint32_t id, ldr; } loaded; + spinlock_t esr_lock; struct periodic_time pt; s_time_t timer_last_update; struct page_info *regs_page; From 201f261e859e06e4c083a83e3eaf35397c22dad4 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:22:12 +0200 Subject: [PATCH 05/13] EFI: move x86 boot/runtime code to common/efi This moves the EFI boot and runtime services code to the common/efi directory. This code is symbolicly linked back into the arch/x86/efi directory where it is built if a build-time check for PE/COFF support in the toolchain passes. In the PE/COFF supporting case, both the EFI executable and the normal Xen image (with stubbed EFI functions) are built. We can't use the normal common build infrastructure since we are building two versions at the same time, with different EFI related code in each. No code changes, just file movement and make updates. The files are symbolicly linked at build time back toe the original arch/x86/efi directory. This is in preparation for adding ARM EFI support where much of these files can be shared. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- .gitignore | 4 ++++ xen/Makefile | 3 +++ xen/{arch/x86 => common}/efi/boot.c | 0 xen/{arch/x86 => common}/efi/compat.c | 0 xen/{arch/x86 => common}/efi/efi.h | 0 xen/{arch/x86 => common}/efi/runtime.c | 0 6 files changed, 7 insertions(+) rename xen/{arch/x86 => common}/efi/boot.c (100%) rename xen/{arch/x86 => common}/efi/compat.c (100%) rename xen/{arch/x86 => common}/efi/efi.h (100%) rename xen/{arch/x86 => common}/efi/runtime.c (100%) diff --git a/.gitignore b/.gitignore index d50ff905df..67ed7cb7b2 100644 --- a/.gitignore +++ b/.gitignore @@ -253,6 +253,10 @@ xen/arch/x86/efi.lds xen/arch/x86/efi/check.efi xen/arch/x86/efi/disabled xen/arch/x86/efi/mkreloc +xen/arch/*/efi/boot.c +xen/arch/*/efi/compat.c +xen/arch/*/efi/efi.h +xen/arch/*/efi/runtime.c xen/ddb/* xen/include/headers.chk xen/include/asm diff --git a/xen/Makefile b/xen/Makefile index 0e58bce91a..04f72e6c93 100644 --- a/xen/Makefile +++ b/xen/Makefile @@ -100,6 +100,9 @@ $(TARGET): delete-unfresh-files $(MAKE) -C tools $(MAKE) -f $(BASEDIR)/Rules.mk include/xen/compile.h [ -e include/asm ] || ln -sf asm-$(TARGET_ARCH) include/asm + [ -e arch/$(TARGET_ARCH)/efi ] && for f in boot.c runtime.c compat.c efi.h;\ + do ln -nsf ../../../common/efi/$$f arch/$(TARGET_ARCH)/efi/; done;\ + /bin/true $(MAKE) -f $(BASEDIR)/Rules.mk -C include $(MAKE) -f $(BASEDIR)/Rules.mk -C arch/$(TARGET_ARCH) asm-offsets.s $(MAKE) -f $(BASEDIR)/Rules.mk include/asm-$(TARGET_ARCH)/asm-offsets.h diff --git a/xen/arch/x86/efi/boot.c b/xen/common/efi/boot.c similarity index 100% rename from xen/arch/x86/efi/boot.c rename to xen/common/efi/boot.c diff --git a/xen/arch/x86/efi/compat.c b/xen/common/efi/compat.c similarity index 100% rename from xen/arch/x86/efi/compat.c rename to xen/common/efi/compat.c diff --git a/xen/arch/x86/efi/efi.h b/xen/common/efi/efi.h similarity index 100% rename from xen/arch/x86/efi/efi.h rename to xen/common/efi/efi.h diff --git a/xen/arch/x86/efi/runtime.c b/xen/common/efi/runtime.c similarity index 100% rename from xen/arch/x86/efi/runtime.c rename to xen/common/efi/runtime.c From 02cf7bdc094b6d497dec391a1caa11605236022c Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:24:52 +0200 Subject: [PATCH 06/13] EFI: move x86 specific functions/variables to arch header Move the global variables and functions that can be moved as-is from the common boot.c file to the x86 implementation header file. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 129 ++++++++++++++++++++++++++++ xen/common/efi/boot.c | 145 ++++---------------------------- xen/include/asm-x86/processor.h | 1 + xen/include/xen/kernel.h | 2 +- 4 files changed, 146 insertions(+), 131 deletions(-) create mode 100644 xen/arch/x86/efi/efi-boot.h diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h new file mode 100644 index 0000000000..bd5f043d71 --- /dev/null +++ b/xen/arch/x86/efi/efi-boot.h @@ -0,0 +1,129 @@ +/* + * Architecture specific implementation for EFI boot code. This file + * is intended to be included by common/efi/boot.c _only_, and + * therefore can define arch specific global variables. + */ +#include +#include +#include +#include + +static struct file __initdata ucode; +static multiboot_info_t __initdata mbi = { + .flags = MBI_MODULES | MBI_LOADERNAME +}; +static module_t __initdata mb_modules[3]; + +static void __init edd_put_string(u8 *dst, size_t n, const char *src) +{ + while ( n-- && *src ) + *dst++ = *src++; + if ( *src ) + PrintErrMesg(L"Internal error populating EDD info", + EFI_BUFFER_TOO_SMALL); + while ( n-- ) + *dst++ = ' '; +} +#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) + +extern const intpte_t __page_tables_start[], __page_tables_end[]; +#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ + (intpte_t *)(v) < __page_tables_end) + +#define PE_BASE_RELOC_ABS 0 +#define PE_BASE_RELOC_HIGHLOW 3 +#define PE_BASE_RELOC_DIR64 10 + +extern const struct pe_base_relocs { + u32 rva; + u32 size; + u16 entries[]; +} __base_relocs_start[], __base_relocs_end[]; + +static void __init efi_arch_relocate_image(unsigned long delta) +{ + const struct pe_base_relocs *base_relocs; + + for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; ) + { + unsigned int i, n; + + n = (base_relocs->size - sizeof(*base_relocs)) / + sizeof(*base_relocs->entries); + for ( i = 0; i < n; ++i ) + { + unsigned long addr = xen_phys_start + base_relocs->rva + + (base_relocs->entries[i] & 0xfff); + + switch ( base_relocs->entries[i] >> 12 ) + { + case PE_BASE_RELOC_ABS: + break; + case PE_BASE_RELOC_HIGHLOW: + if ( delta ) + { + *(u32 *)addr += delta; + if ( in_page_tables(addr) ) + *(u32 *)addr += xen_phys_start; + } + break; + case PE_BASE_RELOC_DIR64: + if ( delta ) + { + *(u64 *)addr += delta; + if ( in_page_tables(addr) ) + *(intpte_t *)addr += xen_phys_start; + } + break; + default: + blexit(L"Unsupported relocation type"); + } + } + base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); + } +} + +extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; +extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; + +static void __init relocate_trampoline(unsigned long phys) +{ + const s32 *trampoline_ptr; + + trampoline_phys = phys; + /* Apply relocations to trampoline. */ + for ( trampoline_ptr = __trampoline_rel_start; + trampoline_ptr < __trampoline_rel_stop; + ++trampoline_ptr ) + *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; + for ( trampoline_ptr = __trampoline_seg_start; + trampoline_ptr < __trampoline_seg_stop; + ++trampoline_ptr ) + *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; +} + +static void __init place_string(u32 *addr, const char *s) +{ + static char *__initdata alloc = start; + + if ( s && *s ) + { + size_t len1 = strlen(s) + 1; + const char *old = (char *)(long)*addr; + size_t len2 = *addr ? strlen(old) + 1 : 0; + + alloc -= len1 + len2; + /* + * Insert new string before already existing one. This is needed + * for options passed on the command line to override options from + * the configuration file. + */ + memcpy(alloc, s, len1); + if ( *addr ) + { + alloc[len1 - 1] = ' '; + memcpy(alloc + len1, old, len2); + } + } + *addr = (long)alloc; +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 6f345929f1..b543d76ddb 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -18,13 +18,9 @@ #include #include #include -#include -#include #define __ASSEMBLY__ /* avoid pulling in ACPI stuff (conflicts with EFI) */ #include #undef __ASSEMBLY__ -#include -#include /* Using SetVirtualAddressMap() is incompatible with kexec: */ #undef USE_SET_VIRTUAL_ADDRESS_MAP @@ -41,9 +37,6 @@ typedef struct { EFI_SHIM_LOCK_VERIFY Verify; } EFI_SHIM_LOCK_PROTOCOL; -extern char start[]; -extern u32 cpuid_ext_features; - union string { CHAR16 *w; char *s; @@ -58,6 +51,13 @@ struct file { }; }; +static CHAR16 *FormatDec(UINT64 Val, CHAR16 *Buffer); +static CHAR16 *FormatHex(UINT64 Val, UINTN Width, CHAR16 *Buffer); +static void DisplayUint(UINT64 Val, INTN Width); +static CHAR16 *wstrcpy(CHAR16 *d, const CHAR16 *s); +static void noreturn blexit(const CHAR16 *str); +static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode); + static EFI_BOOT_SERVICES *__initdata efi_bs; static EFI_HANDLE __initdata efi_ih; @@ -69,19 +69,18 @@ static UINT32 __initdata mdesc_ver; static struct file __initdata cfg; static struct file __initdata kernel; static struct file __initdata ramdisk; -static struct file __initdata ucode; static struct file __initdata xsm; - -static multiboot_info_t __initdata mbi = { - .flags = MBI_MODULES | MBI_LOADERNAME -}; -static module_t __initdata mb_modules[3]; - static CHAR16 __initdata newline[] = L"\r\n"; #define PrintStr(s) StdOut->OutputString(StdOut, s) #define PrintErr(s) StdErr->OutputString(StdErr, s) +/* + * Include architecture specific implementation here, which references the + * static globals defined above. + */ +#include "efi-boot.h" + static CHAR16 *__init FormatDec(UINT64 Val, CHAR16 *Buffer) { if ( Val >= 10 ) @@ -255,32 +254,6 @@ static void __init PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode) blexit(mesg); } -static void __init place_string(u32 *addr, const char *s) -{ - static char *__initdata alloc = start; - - if ( s && *s ) - { - size_t len1 = strlen(s) + 1; - const char *old = (char *)(long)*addr; - size_t len2 = *addr ? strlen(old) + 1 : 0; - - alloc -= len1 + len2; - /* - * Insert new string before already existing one. This is needed - * for options passed on the command line to override options from - * the configuration file. - */ - memcpy(alloc, s, len1); - if ( *addr ) - { - alloc[len1 - 1] = ' '; - memcpy(alloc + len1, old, len2); - } - } - *addr = (long)alloc; -} - static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv, CHAR16 *cmdline, UINTN cmdsize) { @@ -574,18 +547,6 @@ static void __init split_value(char *s) *s = 0; } -static void __init edd_put_string(u8 *dst, size_t n, const char *src) -{ - while ( n-- && *src ) - *dst++ = *src++; - if ( *src ) - PrintErrMesg(L"Internal error populating EDD info", - EFI_BUFFER_TOO_SMALL); - while ( n-- ) - *dst++ = ' '; -} -#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s) - static void __init setup_efi_pci(void) { EFI_STATUS status; @@ -688,82 +649,6 @@ static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz) return max(*pos + *sz, bpp); } -extern const intpte_t __page_tables_start[], __page_tables_end[]; -#define in_page_tables(v) ((intpte_t *)(v) >= __page_tables_start && \ - (intpte_t *)(v) < __page_tables_end) - -#define PE_BASE_RELOC_ABS 0 -#define PE_BASE_RELOC_HIGHLOW 3 -#define PE_BASE_RELOC_DIR64 10 - -extern const struct pe_base_relocs { - u32 rva; - u32 size; - u16 entries[]; -} __base_relocs_start[], __base_relocs_end[]; - -static void __init relocate_image(unsigned long delta) -{ - const struct pe_base_relocs *base_relocs; - - for ( base_relocs = __base_relocs_start; base_relocs < __base_relocs_end; ) - { - unsigned int i, n; - - n = (base_relocs->size - sizeof(*base_relocs)) / - sizeof(*base_relocs->entries); - for ( i = 0; i < n; ++i ) - { - unsigned long addr = xen_phys_start + base_relocs->rva + - (base_relocs->entries[i] & 0xfff); - - switch ( base_relocs->entries[i] >> 12 ) - { - case PE_BASE_RELOC_ABS: - break; - case PE_BASE_RELOC_HIGHLOW: - if ( delta ) - { - *(u32 *)addr += delta; - if ( in_page_tables(addr) ) - *(u32 *)addr += xen_phys_start; - } - break; - case PE_BASE_RELOC_DIR64: - if ( delta ) - { - *(u64 *)addr += delta; - if ( in_page_tables(addr) ) - *(intpte_t *)addr += xen_phys_start; - } - break; - default: - blexit(L"Unsupported relocation type"); - } - } - base_relocs = (const void *)(base_relocs->entries + i + (i & 1)); - } -} - -extern const s32 __trampoline_rel_start[], __trampoline_rel_stop[]; -extern const s32 __trampoline_seg_start[], __trampoline_seg_stop[]; - -static void __init relocate_trampoline(unsigned long phys) -{ - const s32 *trampoline_ptr; - - trampoline_phys = phys; - /* Apply relocations to trampoline. */ - for ( trampoline_ptr = __trampoline_rel_start; - trampoline_ptr < __trampoline_rel_stop; - ++trampoline_ptr ) - *(u32 *)(*trampoline_ptr + (long)trampoline_ptr) += phys; - for ( trampoline_ptr = __trampoline_seg_start; - trampoline_ptr < __trampoline_seg_stop; - ++trampoline_ptr ) - *(u16 *)(*trampoline_ptr + (long)trampoline_ptr) = phys >> 4; -} - void EFIAPI __init noreturn efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { @@ -880,7 +765,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) PrintStr(L"Xen " __stringify(XEN_VERSION) "." __stringify(XEN_SUBVERSION) XEN_EXTRAVERSION " (c/s " XEN_CHANGESET ") EFI loader\r\n"); - relocate_image(0); + efi_arch_relocate_image(0); if ( StdOut->QueryMode(StdOut, StdOut->Mode->Mode, &cols, &rows) == EFI_SUCCESS ) @@ -1461,7 +1346,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_memmap = (void *)efi_memmap + DIRECTMAP_VIRT_START; efi_fw_vendor = (void *)efi_fw_vendor + DIRECTMAP_VIRT_START; - relocate_image(__XEN_VIRT_START - xen_phys_start); + efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start); memcpy((void *)trampoline_phys, trampoline_start, cfg.size); /* Set system registers and transfer control. */ diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index 9e1f210e6e..f98eaf5217 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -199,6 +199,7 @@ extern void set_cpuid_faulting(bool_t enable); extern u64 host_pat; extern bool_t opt_cpu_info; +extern u32 cpuid_ext_features; /* Maximum width of physical addresses supported by the hardware */ extern unsigned int paddr_bits; diff --git a/xen/include/xen/kernel.h b/xen/include/xen/kernel.h index 2c6d448369..548b64da9f 100644 --- a/xen/include/xen/kernel.h +++ b/xen/include/xen/kernel.h @@ -65,7 +65,7 @@ 1; \ }) -extern char _start[], _end[]; +extern char _start[], _end[], start[]; #define is_kernel(p) ({ \ char *__p = (char *)(unsigned long)(p); \ (__p >= _start) && (__p < _end); \ From d9c3e9f9b3a297af6ff3c5c22f36b621012d3ba4 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:26:34 +0200 Subject: [PATCH 07/13] EFI: create arch functions to allocate memory for and process memory map The memory used to store the EFI memory map is allocated in an architecture specific way, and the processing of the memory map itself uses x86 specific data structures. This patch adds architecture specific funtions so each architecture can provide its own implementation. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 71 +++++++++++++++++++++++++++++++++++++ xen/common/efi/boot.c | 62 ++++---------------------------- 2 files changed, 77 insertions(+), 56 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index bd5f043d71..80b8dfe58a 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -127,3 +127,74 @@ static void __init place_string(u32 *addr, const char *s) } *addr = (long)alloc; } + +static void __init efi_arch_process_memory_map(EFI_SYSTEM_TABLE *SystemTable, + void *map, + UINTN map_size, + UINTN desc_size, + UINT32 desc_ver) +{ + struct e820entry *e; + unsigned int i; + + /* Populate E820 table and check trampoline area availability. */ + e = e820map - 1; + for ( i = 0; i < map_size; i += desc_size ) + { + EFI_MEMORY_DESCRIPTOR *desc = map + i; + u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT; + u32 type; + + switch ( desc->Type ) + { + default: + type = E820_RESERVED; + break; + case EfiConventionalMemory: + case EfiBootServicesCode: + case EfiBootServicesData: + if ( !trampoline_phys && desc->PhysicalStart + len <= 0x100000 && + len >= cfg.size && desc->PhysicalStart + len > cfg.addr ) + cfg.addr = (desc->PhysicalStart + len - cfg.size) & PAGE_MASK; + /* fall through */ + case EfiLoaderCode: + case EfiLoaderData: + if ( desc->Attribute & EFI_MEMORY_WB ) + type = E820_RAM; + else + case EfiUnusableMemory: + type = E820_UNUSABLE; + break; + case EfiACPIReclaimMemory: + type = E820_ACPI; + break; + case EfiACPIMemoryNVS: + type = E820_NVS; + break; + } + if ( e820nr && type == e->type && + desc->PhysicalStart == e->addr + e->size ) + e->size += len; + else if ( !len || e820nr >= E820MAX ) + continue; + else + { + ++e; + e->addr = desc->PhysicalStart; + e->size = len; + e->type = type; + ++e820nr; + } + } + +} + +static void *__init efi_arch_allocate_mmap_buffer(UINTN map_size) +{ + place_string(&mbi.mem_upper, NULL); + mbi.mem_upper -= map_size; + mbi.mem_upper &= -__alignof__(EFI_MEMORY_DESCRIPTOR); + if ( mbi.mem_upper < xen_phys_start ) + return NULL; + return (void *)(long)mbi.mem_upper; +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index b543d76ddb..f5ea6a5585 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -668,7 +668,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; EFI_FILE_HANDLE dir_handle; union string section = { NULL }, name; - struct e820entry *e; u64 efer; bool_t base_video = 0; @@ -970,8 +969,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) mbi.boot_loader_name = (long)"EFI"; mbi.mods_addr = (long)mb_modules; - place_string(&mbi.mem_upper, NULL); - /* Collect EDD info. */ BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); @@ -1268,65 +1265,18 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_bs->GetMemoryMap(&efi_memmap_size, NULL, &map_key, &efi_mdesc_size, &mdesc_ver); - mbi.mem_upper -= efi_memmap_size; - mbi.mem_upper &= -__alignof__(EFI_MEMORY_DESCRIPTOR); - if ( mbi.mem_upper < xen_phys_start ) - blexit(L"Out of static memory"); - efi_memmap = (void *)(long)mbi.mem_upper; + efi_memmap = efi_arch_allocate_mmap_buffer(efi_memmap_size); + if ( !efi_memmap ) + blexit(L"Unable to allocate memory for EFI memory map"); + status = efi_bs->GetMemoryMap(&efi_memmap_size, efi_memmap, &map_key, &efi_mdesc_size, &mdesc_ver); if ( EFI_ERROR(status) ) PrintErrMesg(L"Cannot obtain memory map", status); - /* Populate E820 table and check trampoline area availability. */ - e = e820map - 1; - for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size ) - { - EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i; - u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT; - u32 type; + efi_arch_process_memory_map(SystemTable, efi_memmap, efi_memmap_size, + efi_mdesc_size, mdesc_ver); - switch ( desc->Type ) - { - default: - type = E820_RESERVED; - break; - case EfiConventionalMemory: - case EfiBootServicesCode: - case EfiBootServicesData: - if ( !trampoline_phys && desc->PhysicalStart + len <= 0x100000 && - len >= cfg.size && desc->PhysicalStart + len > cfg.addr ) - cfg.addr = (desc->PhysicalStart + len - cfg.size) & PAGE_MASK; - /* fall through */ - case EfiLoaderCode: - case EfiLoaderData: - if ( desc->Attribute & EFI_MEMORY_WB ) - type = E820_RAM; - else - case EfiUnusableMemory: - type = E820_UNUSABLE; - break; - case EfiACPIReclaimMemory: - type = E820_ACPI; - break; - case EfiACPIMemoryNVS: - type = E820_NVS; - break; - } - if ( e820nr && type == e->type && - desc->PhysicalStart == e->addr + e->size ) - e->size += len; - else if ( !len || e820nr >= E820MAX ) - continue; - else - { - ++e; - e->addr = desc->PhysicalStart; - e->size = len; - e->type = type; - ++e820nr; - } - } if ( !trampoline_phys ) { if ( !cfg.addr ) From 236502c1102ac95532683c83ef4defff6c5bda4e Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:27:55 +0200 Subject: [PATCH 08/13] EFI: add architecture functions for pre/post ExitBootServices The UEFI ExitBootServices function is invoked to transition the system to the 'runtime' mode of operation, and is done right before transitioning from the EFI loader code into Xen proper. x86 does some arch specific memory management (trampoline) before exit boot services, and the code that transitions from the EFI application state to Xen is architecture specific. This patch adds two functions, one pre and one post ExitBootServices to allow each architecture to to handle these cases in a customized manner. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 50 +++++++++++++++++++++++++++++++++++++ xen/common/efi/boot.c | 42 ++----------------------------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 80b8dfe58a..254783fd8d 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -198,3 +198,53 @@ static void *__init efi_arch_allocate_mmap_buffer(UINTN map_size) return NULL; return (void *)(long)mbi.mem_upper; } + +static void __init efi_arch_pre_exit_boot(void) +{ + if ( !trampoline_phys ) + { + if ( !cfg.addr ) + blexit(L"No memory for trampoline"); + relocate_trampoline(cfg.addr); + } +} + +static void __init noreturn efi_arch_post_exit_boot(void) +{ + u64 efer; + + efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start); + memcpy((void *)trampoline_phys, trampoline_start, cfg.size); + + /* Set system registers and transfer control. */ + asm volatile("pushq $0\n\tpopfq"); + rdmsrl(MSR_EFER, efer); + efer |= EFER_SCE; + if ( cpuid_ext_features & (1 << (X86_FEATURE_NX & 0x1f)) ) + efer |= EFER_NX; + wrmsrl(MSR_EFER, efer); + write_cr0(X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | + X86_CR0_AM | X86_CR0_PG); + asm volatile ( "mov %[cr4], %%cr4\n\t" + "mov %[cr3], %%cr3\n\t" + "movabs $__start_xen, %[rip]\n\t" + "lgdt gdt_descr(%%rip)\n\t" + "mov stack_start(%%rip), %%rsp\n\t" + "mov %[ds], %%ss\n\t" + "mov %[ds], %%ds\n\t" + "mov %[ds], %%es\n\t" + "mov %[ds], %%fs\n\t" + "mov %[ds], %%gs\n\t" + "movl %[cs], 8(%%rsp)\n\t" + "mov %[rip], (%%rsp)\n\t" + "lretq %[stkoff]-16" + : [rip] "=&r" (efer/* any dead 64-bit variable */) + : [cr3] "r" (idle_pg_table), + [cr4] "r" (mmu_cr4_features), + [cs] "ir" (__HYPERVISOR_CS), + [ds] "r" (__HYPERVISOR_DS), + [stkoff] "i" (STACK_SIZE - sizeof(struct cpu_info)), + "D" (&mbi) + : "memory" ); + for( ; ; ); /* not reached */ +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index f5ea6a5585..11f749ede5 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -668,7 +668,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info; EFI_FILE_HANDLE dir_handle; union string section = { NULL }, name; - u64 efer; bool_t base_video = 0; efi_ih = ImageHandle; @@ -1277,12 +1276,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_arch_process_memory_map(SystemTable, efi_memmap, efi_memmap_size, efi_mdesc_size, mdesc_ver); - if ( !trampoline_phys ) - { - if ( !cfg.addr ) - blexit(L"No memory for trampoline"); - relocate_trampoline(cfg.addr); - } + efi_arch_pre_exit_boot(); status = efi_bs->ExitBootServices(ImageHandle, map_key); if ( EFI_ERROR(status) ) @@ -1296,39 +1290,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_memmap = (void *)efi_memmap + DIRECTMAP_VIRT_START; efi_fw_vendor = (void *)efi_fw_vendor + DIRECTMAP_VIRT_START; - efi_arch_relocate_image(__XEN_VIRT_START - xen_phys_start); - memcpy((void *)trampoline_phys, trampoline_start, cfg.size); - - /* Set system registers and transfer control. */ - asm volatile("pushq $0\n\tpopfq"); - rdmsrl(MSR_EFER, efer); - efer |= EFER_SCE; - if ( cpuid_ext_features & (1 << (X86_FEATURE_NX & 0x1f)) ) - efer |= EFER_NX; - wrmsrl(MSR_EFER, efer); - write_cr0(X86_CR0_PE | X86_CR0_MP | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | - X86_CR0_AM | X86_CR0_PG); - asm volatile ( "mov %[cr4], %%cr4\n\t" - "mov %[cr3], %%cr3\n\t" - "movabs $__start_xen, %[rip]\n\t" - "lgdt gdt_descr(%%rip)\n\t" - "mov stack_start(%%rip), %%rsp\n\t" - "mov %[ds], %%ss\n\t" - "mov %[ds], %%ds\n\t" - "mov %[ds], %%es\n\t" - "mov %[ds], %%fs\n\t" - "mov %[ds], %%gs\n\t" - "movl %[cs], 8(%%rsp)\n\t" - "mov %[rip], (%%rsp)\n\t" - "lretq %[stkoff]-16" - : [rip] "=&r" (efer/* any dead 64-bit variable */) - : [cr3] "r" (idle_pg_table), - [cr4] "r" (mmu_cr4_features), - [cs] "ir" (__HYPERVISOR_CS), - [ds] "r" (__HYPERVISOR_DS), - [stkoff] "i" (STACK_SIZE - sizeof(struct cpu_info)), - "D" (&mbi) - : "memory" ); + efi_arch_post_exit_boot(); for( ; ; ); /* not reached */ } From dbbb27f1eb667363324a239f38a9a6ca1c0f74e8 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:28:27 +0200 Subject: [PATCH 09/13] EFI: add efi_arch_cfg_file_early/late() to handle arch specific cfg file fields Different architectures have some different configuration file fields that need to be handled. In particular, x86 has ucode and ARM has device tree files to be loaded. These arch specific functions is used to allow each architecture to implement these features in arch specific code. Early/late versions are provided, as ARM needs to process the DTB entry first, and x86 wants to process the ucode entry last as it is the smallest allocation. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 20 ++++++++++++++++++++ xen/common/efi/boot.c | 21 ++++++++++----------- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 254783fd8d..61e2198d4b 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -248,3 +248,23 @@ static void __init noreturn efi_arch_post_exit_boot(void) : "memory" ); for( ; ; ); /* not reached */ } + +static void __init efi_arch_cfg_file_early(EFI_FILE_HANDLE dir_handle, char *section) +{ +} + +static void __init efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle, char *section) +{ + union string name; + + name.s = get_value(&cfg, section, "ucode"); + if ( !name.s ) + name.s = get_value(&cfg, "global", "ucode"); + if ( name.s ) + { + microcode_set_module(mbi.mods_count); + split_value(name.s); + read_file(dir_handle, s2w(&name), &ucode); + efi_bs->FreePool(name.w); + } +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 11f749ede5..9681de274b 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -57,6 +57,12 @@ static void DisplayUint(UINT64 Val, INTN Width); static CHAR16 *wstrcpy(CHAR16 *d, const CHAR16 *s); static void noreturn blexit(const CHAR16 *str); static void PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode); +static char *get_value(const struct file *cfg, const char *section, + const char *item); +static void split_value(char *s); +static CHAR16 *s2w(union string *str); +static bool_t read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, + struct file *file); static EFI_BOOT_SERVICES *__initdata efi_bs; static EFI_HANDLE __initdata efi_ih; @@ -846,6 +852,9 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } if ( !name.s ) blexit(L"No Dom0 kernel image specified."); + + efi_arch_cfg_file_early(dir_handle, section.s); + split_value(name.s); read_file(dir_handle, s2w(&name), &kernel); efi_bs->FreePool(name.w); @@ -863,17 +872,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) efi_bs->FreePool(name.w); } - name.s = get_value(&cfg, section.s, "ucode"); - if ( !name.s ) - name.s = get_value(&cfg, "global", "ucode"); - if ( name.s ) - { - microcode_set_module(mbi.mods_count); - split_value(name.s); - read_file(dir_handle, s2w(&name), &ucode); - efi_bs->FreePool(name.w); - } - name.s = get_value(&cfg, section.s, "xsm"); if ( name.s ) { @@ -912,6 +910,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) cols = rows = depth = 0; } } + efi_arch_cfg_file_late(dir_handle, section.s); efi_bs->FreePages(cfg.addr, PFN_UP(cfg.size)); cfg.addr = 0; From fbc3d9a220842d49a6b8d8415d32af4d536af3ff Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:28:48 +0200 Subject: [PATCH 10/13] EFI: add efi_arch_handle_cmdline() for processing commandline Add arch function for processing the Xen commandline and updating internal structures. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 34 ++++++++++++++++++++++++++++++++++ xen/common/efi/boot.c | 37 +++++++++---------------------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 61e2198d4b..07e9fc7484 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -268,3 +268,37 @@ static void __init efi_arch_cfg_file_late(EFI_FILE_HANDLE dir_handle, char *sect efi_bs->FreePool(name.w); } } + +static void __init efi_arch_handle_cmdline(CHAR16 *image_name, + CHAR16 *cmdline_options, + char *cfgfile_options) +{ + union string name; + + if ( cmdline_options ) + { + name.w = cmdline_options; + w2s(&name); + place_string(&mbi.cmdline, name.s); + } + if ( cfgfile_options ) + place_string(&mbi.cmdline, cfgfile_options); + /* Insert image name last, as it gets prefixed to the other options. */ + if ( image_name ) + { + name.w = image_name; + w2s(&name); + } + else + name.s = "xen"; + place_string(&mbi.cmdline, name.s); + + if ( mbi.cmdline ) + mbi.flags |= MBI_CMDLINE; + /* + * These must not be initialized statically, since the value must + * not get relocated when processing base relocations later. + */ + mbi.boot_loader_name = (long)"EFI"; + mbi.mods_addr = (long)mb_modules; +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 9681de274b..9be9c70c06 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -61,6 +61,7 @@ static char *get_value(const struct file *cfg, const char *section, const char *item); static void split_value(char *s); static CHAR16 *s2w(union string *str); +static char *w2s(const union string *str); static bool_t read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, struct file *file); @@ -261,7 +262,8 @@ static void __init PrintErrMesg(const CHAR16 *mesg, EFI_STATUS ErrCode) } static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv, - CHAR16 *cmdline, UINTN cmdsize) + CHAR16 *cmdline, UINTN cmdsize, + CHAR16 **options) { CHAR16 *ptr = (CHAR16 *)(argv + argc + 1), *prev = NULL; bool_t prev_sep = TRUE; @@ -287,10 +289,8 @@ static unsigned int __init get_argv(unsigned int argc, CHAR16 **argv, ++argc; else if ( prev && wstrcmp(prev, L"--") == 0 ) { - union string rest = { .w = cmdline }; - - --argv; - place_string(&mbi.cmdline, w2s(&rest)); + if ( options ) + *options = cmdline; break; } else @@ -666,7 +666,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; unsigned int i, argc; - CHAR16 **argv, *file_name, *cfg_file_name = NULL; + CHAR16 **argv, *file_name, *cfg_file_name = NULL, *options = NULL; UINTN cols, rows, depth, size, map_key, info_size, gop_mode = ~0; EFI_HANDLE *handles = NULL; EFI_SHIM_LOCK_PROTOCOL *shim_lock; @@ -704,14 +704,14 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) dir_handle = get_parent_handle(loaded_image, &file_name); argc = get_argv(0, NULL, loaded_image->LoadOptions, - loaded_image->LoadOptionsSize); + loaded_image->LoadOptionsSize, NULL); if ( argc > 0 && efi_bs->AllocatePool(EfiLoaderData, (argc + 1) * sizeof(*argv) + loaded_image->LoadOptionsSize, (void **)&argv) == EFI_SUCCESS ) get_argv(argc, argv, loaded_image->LoadOptions, - loaded_image->LoadOptionsSize); + loaded_image->LoadOptionsSize, &options); else argc = 0; for ( i = 1; i < argc; ++i ) @@ -881,17 +881,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } name.s = get_value(&cfg, section.s, "options"); - if ( name.s ) - place_string(&mbi.cmdline, name.s); - /* Insert image name last, as it gets prefixed to the other options. */ - if ( argc ) - { - name.w = *argv; - w2s(&name); - } - else - name.s = "xen"; - place_string(&mbi.cmdline, name.s); + efi_arch_handle_cmdline(argc ? *argv : NULL, options, name.s); cols = rows = depth = 0; if ( !base_video ) @@ -958,15 +948,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } } - if ( mbi.cmdline ) - mbi.flags |= MBI_CMDLINE; - /* - * These must not be initialized statically, since the value must - * not get relocated when processing base relocations below. - */ - mbi.boot_loader_name = (long)"EFI"; - mbi.mods_addr = (long)mb_modules; - /* Collect EDD info. */ BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); From b4bfea5532ef3daab1759c2afef64093faa8c6af Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:29:29 +0200 Subject: [PATCH 11/13] EFI: move x86 specific disk probing code Move x86 specific disk (EDD) probing to arch specific file. This code is x86 only and relates to legacy BIOS handling of disk drives. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 152 ++++++++++++++++++++++++++++++++++++ xen/common/efi/boot.c | 144 +--------------------------------- 2 files changed, 153 insertions(+), 143 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 07e9fc7484..786d5cdb5c 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -302,3 +302,155 @@ static void __init efi_arch_handle_cmdline(CHAR16 *image_name, mbi.boot_loader_name = (long)"EFI"; mbi.mods_addr = (long)mb_modules; } + +static void __init efi_arch_edd(void) +{ + static EFI_GUID __initdata bio_guid = BLOCK_IO_PROTOCOL; + static EFI_GUID __initdata devp_guid = DEVICE_PATH_PROTOCOL; + EFI_HANDLE *handles = NULL; + unsigned int i; + UINTN size; + EFI_STATUS status; + + /* Collect EDD info. */ + BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); + BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); + size = 0; + status = efi_bs->LocateHandle(ByProtocol, &bio_guid, NULL, &size, NULL); + if ( status == EFI_BUFFER_TOO_SMALL ) + status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles); + if ( !EFI_ERROR(status) ) + status = efi_bs->LocateHandle(ByProtocol, &bio_guid, NULL, &size, + handles); + if ( EFI_ERROR(status) ) + size = 0; + for ( i = 0; i < size / sizeof(*handles); ++i ) + { + EFI_BLOCK_IO *bio; + EFI_DEV_PATH_PTR devp; + struct edd_info *info = boot_edd_info + boot_edd_info_nr; + struct edd_device_params *params = &info->edd_device_params; + enum { root, acpi, pci, ctrlr } state = root; + + status = efi_bs->HandleProtocol(handles[i], &bio_guid, (void **)&bio); + if ( EFI_ERROR(status) || + bio->Media->RemovableMedia || + bio->Media->LogicalPartition ) + continue; + if ( boot_edd_info_nr < EDD_INFO_MAX ) + { + info->device = 0x80 + boot_edd_info_nr; /* fake */ + info->version = 0x11; + params->length = offsetof(struct edd_device_params, dpte_ptr); + params->number_of_sectors = bio->Media->LastBlock + 1; + params->bytes_per_sector = bio->Media->BlockSize; + params->dpte_ptr = ~0; + } + ++boot_edd_info_nr; + status = efi_bs->HandleProtocol(handles[i], &devp_guid, + (void **)&devp); + if ( EFI_ERROR(status) ) + continue; + for ( ; !IsDevicePathEnd(devp.DevPath); + devp.DevPath = NextDevicePathNode(devp.DevPath) ) + { + switch ( DevicePathType(devp.DevPath) ) + { + const u8 *p; + + case ACPI_DEVICE_PATH: + if ( state != root || boot_edd_info_nr > EDD_INFO_MAX ) + break; + switch ( DevicePathSubType(devp.DevPath) ) + { + case ACPI_DP: + if ( devp.Acpi->HID != EISA_PNP_ID(0xA03) && + devp.Acpi->HID != EISA_PNP_ID(0xA08) ) + break; + params->interface_path.pci.bus = devp.Acpi->UID; + state = acpi; + break; + case EXPANDED_ACPI_DP: + /* XXX */ + break; + } + break; + case HARDWARE_DEVICE_PATH: + if ( state != acpi || + DevicePathSubType(devp.DevPath) != HW_PCI_DP || + boot_edd_info_nr > EDD_INFO_MAX ) + break; + state = pci; + edd_put_string(params->host_bus_type, "PCI"); + params->interface_path.pci.slot = devp.Pci->Device; + params->interface_path.pci.function = devp.Pci->Function; + break; + case MESSAGING_DEVICE_PATH: + if ( state != pci || boot_edd_info_nr > EDD_INFO_MAX ) + break; + state = ctrlr; + switch ( DevicePathSubType(devp.DevPath) ) + { + case MSG_ATAPI_DP: + edd_put_string(params->interface_type, "ATAPI"); + params->interface_path.pci.channel = + devp.Atapi->PrimarySecondary; + params->device_path.atapi.device = devp.Atapi->SlaveMaster; + params->device_path.atapi.lun = devp.Atapi->Lun; + break; + case MSG_SCSI_DP: + edd_put_string(params->interface_type, "SCSI"); + params->device_path.scsi.id = devp.Scsi->Pun; + params->device_path.scsi.lun = devp.Scsi->Lun; + break; + case MSG_FIBRECHANNEL_DP: + edd_put_string(params->interface_type, "FIBRE"); + params->device_path.fibre.wwid = devp.FibreChannel->WWN; + params->device_path.fibre.lun = devp.FibreChannel->Lun; + break; + case MSG_1394_DP: + edd_put_string(params->interface_type, "1394"); + params->device_path.i1394.eui = devp.F1394->Guid; + break; + case MSG_USB_DP: + case MSG_USB_CLASS_DP: + edd_put_string(params->interface_type, "USB"); + break; + case MSG_I2O_DP: + edd_put_string(params->interface_type, "I2O"); + params->device_path.i2o.identity_tag = devp.I2O->Tid; + break; + default: + continue; + } + info->version = 0x30; + params->length = sizeof(struct edd_device_params); + params->key = 0xbedd; + params->device_path_info_length = + sizeof(struct edd_device_params) - + offsetof(struct edd_device_params, key); + for ( p = (const u8 *)¶ms->key; p < ¶ms->checksum; ++p ) + params->checksum -= *p; + break; + case MEDIA_DEVICE_PATH: + if ( DevicePathSubType(devp.DevPath) == MEDIA_HARDDRIVE_DP && + devp.HardDrive->MBRType == MBR_TYPE_PCAT && + boot_mbr_signature_nr < EDD_MBR_SIG_MAX ) + { + struct mbr_signature *sig = boot_mbr_signature + + boot_mbr_signature_nr; + + sig->device = 0x80 + boot_edd_info_nr; /* fake */ + memcpy(&sig->signature, devp.HardDrive->Signature, + sizeof(sig->signature)); + ++boot_mbr_signature_nr; + } + break; + } + } + } + if ( handles ) + efi_bs->FreePool(handles); + if ( boot_edd_info_nr > EDD_INFO_MAX ) + boot_edd_info_nr = EDD_INFO_MAX; +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 9be9c70c06..25922612fe 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -660,8 +660,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) { static EFI_GUID __initdata loaded_image_guid = LOADED_IMAGE_PROTOCOL; static EFI_GUID __initdata gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - static EFI_GUID __initdata bio_guid = BLOCK_IO_PROTOCOL; - static EFI_GUID __initdata devp_guid = DEVICE_PATH_PROTOCOL; static EFI_GUID __initdata shim_lock_guid = SHIM_LOCK_PROTOCOL_GUID; EFI_LOADED_IMAGE *loaded_image; EFI_STATUS status; @@ -948,147 +946,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) } } - /* Collect EDD info. */ - BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE); - BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE); - size = 0; - status = efi_bs->LocateHandle(ByProtocol, &bio_guid, NULL, &size, NULL); - if ( status == EFI_BUFFER_TOO_SMALL ) - status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles); - if ( !EFI_ERROR(status) ) - status = efi_bs->LocateHandle(ByProtocol, &bio_guid, NULL, &size, - handles); - if ( EFI_ERROR(status) ) - size = 0; - for ( i = 0; i < size / sizeof(*handles); ++i ) - { - EFI_BLOCK_IO *bio; - EFI_DEV_PATH_PTR devp; - struct edd_info *info = boot_edd_info + boot_edd_info_nr; - struct edd_device_params *params = &info->edd_device_params; - enum { root, acpi, pci, ctrlr } state = root; - - status = efi_bs->HandleProtocol(handles[i], &bio_guid, (void **)&bio); - if ( EFI_ERROR(status) || - bio->Media->RemovableMedia || - bio->Media->LogicalPartition ) - continue; - if ( boot_edd_info_nr < EDD_INFO_MAX ) - { - info->device = 0x80 + boot_edd_info_nr; /* fake */ - info->version = 0x11; - params->length = offsetof(struct edd_device_params, dpte_ptr); - params->number_of_sectors = bio->Media->LastBlock + 1; - params->bytes_per_sector = bio->Media->BlockSize; - params->dpte_ptr = ~0; - } - ++boot_edd_info_nr; - status = efi_bs->HandleProtocol(handles[i], &devp_guid, - (void **)&devp); - if ( EFI_ERROR(status) ) - continue; - for ( ; !IsDevicePathEnd(devp.DevPath); - devp.DevPath = NextDevicePathNode(devp.DevPath) ) - { - switch ( DevicePathType(devp.DevPath) ) - { - const u8 *p; - - case ACPI_DEVICE_PATH: - if ( state != root || boot_edd_info_nr > EDD_INFO_MAX ) - break; - switch ( DevicePathSubType(devp.DevPath) ) - { - case ACPI_DP: - if ( devp.Acpi->HID != EISA_PNP_ID(0xA03) && - devp.Acpi->HID != EISA_PNP_ID(0xA08) ) - break; - params->interface_path.pci.bus = devp.Acpi->UID; - state = acpi; - break; - case EXPANDED_ACPI_DP: - /* XXX */ - break; - } - break; - case HARDWARE_DEVICE_PATH: - if ( state != acpi || - DevicePathSubType(devp.DevPath) != HW_PCI_DP || - boot_edd_info_nr > EDD_INFO_MAX ) - break; - state = pci; - edd_put_string(params->host_bus_type, "PCI"); - params->interface_path.pci.slot = devp.Pci->Device; - params->interface_path.pci.function = devp.Pci->Function; - break; - case MESSAGING_DEVICE_PATH: - if ( state != pci || boot_edd_info_nr > EDD_INFO_MAX ) - break; - state = ctrlr; - switch ( DevicePathSubType(devp.DevPath) ) - { - case MSG_ATAPI_DP: - edd_put_string(params->interface_type, "ATAPI"); - params->interface_path.pci.channel = - devp.Atapi->PrimarySecondary; - params->device_path.atapi.device = devp.Atapi->SlaveMaster; - params->device_path.atapi.lun = devp.Atapi->Lun; - break; - case MSG_SCSI_DP: - edd_put_string(params->interface_type, "SCSI"); - params->device_path.scsi.id = devp.Scsi->Pun; - params->device_path.scsi.lun = devp.Scsi->Lun; - break; - case MSG_FIBRECHANNEL_DP: - edd_put_string(params->interface_type, "FIBRE"); - params->device_path.fibre.wwid = devp.FibreChannel->WWN; - params->device_path.fibre.lun = devp.FibreChannel->Lun; - break; - case MSG_1394_DP: - edd_put_string(params->interface_type, "1394"); - params->device_path.i1394.eui = devp.F1394->Guid; - break; - case MSG_USB_DP: - case MSG_USB_CLASS_DP: - edd_put_string(params->interface_type, "USB"); - break; - case MSG_I2O_DP: - edd_put_string(params->interface_type, "I2O"); - params->device_path.i2o.identity_tag = devp.I2O->Tid; - break; - default: - continue; - } - info->version = 0x30; - params->length = sizeof(struct edd_device_params); - params->key = 0xbedd; - params->device_path_info_length = - sizeof(struct edd_device_params) - - offsetof(struct edd_device_params, key); - for ( p = (const u8 *)¶ms->key; p < ¶ms->checksum; ++p ) - params->checksum -= *p; - break; - case MEDIA_DEVICE_PATH: - if ( DevicePathSubType(devp.DevPath) == MEDIA_HARDDRIVE_DP && - devp.HardDrive->MBRType == MBR_TYPE_PCAT && - boot_mbr_signature_nr < EDD_MBR_SIG_MAX ) - { - struct mbr_signature *sig = boot_mbr_signature + - boot_mbr_signature_nr; - - sig->device = 0x80 + boot_edd_info_nr; /* fake */ - memcpy(&sig->signature, devp.HardDrive->Signature, - sizeof(sig->signature)); - ++boot_mbr_signature_nr; - } - break; - } - } - } - if ( handles ) - efi_bs->FreePool(handles); - if ( boot_edd_info_nr > EDD_INFO_MAX ) - boot_edd_info_nr = EDD_INFO_MAX; + efi_arch_edd(); /* XXX Collect EDID info. */ From 783d2750f04d741f2fcb3693fdcf3371cd9db60f Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:29:51 +0200 Subject: [PATCH 12/13] EFI: create arch functions for console and video init Add arch functions for text console and graphics initialization, and move VGA specific code to x86 architecture file. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 75 +++++++++++++++++++++++++++++++++++++ xen/common/efi/boot.c | 69 ++-------------------------------- 2 files changed, 78 insertions(+), 66 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 786d5cdb5c..5a1346c206 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -454,3 +454,78 @@ static void __init efi_arch_edd(void) if ( boot_edd_info_nr > EDD_INFO_MAX ) boot_edd_info_nr = EDD_INFO_MAX; } + +static void __init efi_arch_console_init(UINTN cols, UINTN rows) +{ + vga_console_info.video_type = XEN_VGATYPE_TEXT_MODE_3; + vga_console_info.u.text_mode_3.columns = cols; + vga_console_info.u.text_mode_3.rows = rows; + vga_console_info.u.text_mode_3.font_height = 16; +} + +static void __init efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, + UINTN info_size, + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info) +{ + int bpp = 0; + + switch ( mode_info->PixelFormat ) + { + case PixelRedGreenBlueReserved8BitPerColor: + vga_console_info.u.vesa_lfb.red_pos = 0; + vga_console_info.u.vesa_lfb.red_size = 8; + vga_console_info.u.vesa_lfb.green_pos = 8; + vga_console_info.u.vesa_lfb.green_size = 8; + vga_console_info.u.vesa_lfb.blue_pos = 16; + vga_console_info.u.vesa_lfb.blue_size = 8; + vga_console_info.u.vesa_lfb.rsvd_pos = 24; + vga_console_info.u.vesa_lfb.rsvd_size = 8; + bpp = 32; + break; + case PixelBlueGreenRedReserved8BitPerColor: + vga_console_info.u.vesa_lfb.red_pos = 16; + vga_console_info.u.vesa_lfb.red_size = 8; + vga_console_info.u.vesa_lfb.green_pos = 8; + vga_console_info.u.vesa_lfb.green_size = 8; + vga_console_info.u.vesa_lfb.blue_pos = 0; + vga_console_info.u.vesa_lfb.blue_size = 8; + vga_console_info.u.vesa_lfb.rsvd_pos = 24; + vga_console_info.u.vesa_lfb.rsvd_size = 8; + bpp = 32; + break; + case PixelBitMask: + bpp = set_color(mode_info->PixelInformation.RedMask, bpp, + &vga_console_info.u.vesa_lfb.red_pos, + &vga_console_info.u.vesa_lfb.red_size); + bpp = set_color(mode_info->PixelInformation.GreenMask, bpp, + &vga_console_info.u.vesa_lfb.green_pos, + &vga_console_info.u.vesa_lfb.green_size); + bpp = set_color(mode_info->PixelInformation.BlueMask, bpp, + &vga_console_info.u.vesa_lfb.blue_pos, + &vga_console_info.u.vesa_lfb.blue_size); + bpp = set_color(mode_info->PixelInformation.ReservedMask, bpp, + &vga_console_info.u.vesa_lfb.rsvd_pos, + &vga_console_info.u.vesa_lfb.rsvd_size); + if ( bpp > 0 ) + break; + /* fall through */ + default: + PrintErr(L"Current graphics mode is unsupported!\r\n"); + bpp = 0; + break; + } + if ( bpp > 0 ) + { + vga_console_info.video_type = XEN_VGATYPE_EFI_LFB; + vga_console_info.u.vesa_lfb.gbl_caps = 2; /* possibly non-VGA */ + vga_console_info.u.vesa_lfb.width = + mode_info->HorizontalResolution; + vga_console_info.u.vesa_lfb.height = mode_info->VerticalResolution; + vga_console_info.u.vesa_lfb.bits_per_pixel = bpp; + vga_console_info.u.vesa_lfb.bytes_per_line = + (mode_info->PixelsPerScanLine * bpp + 7) >> 3; + vga_console_info.u.vesa_lfb.lfb_base = gop->Mode->FrameBufferBase; + vga_console_info.u.vesa_lfb.lfb_size = + (gop->Mode->FrameBufferSize + 0xffff) >> 16; + } +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index 25922612fe..cbad256cce 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -64,6 +64,7 @@ static CHAR16 *s2w(union string *str); static char *w2s(const union string *str); static bool_t read_file(EFI_FILE_HANDLE dir_handle, CHAR16 *name, struct file *file); +static int set_color(u32 mask, int bpp, u8 *pos, u8 *sz); static EFI_BOOT_SERVICES *__initdata efi_bs; static EFI_HANDLE __initdata efi_ih; @@ -771,12 +772,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) if ( StdOut->QueryMode(StdOut, StdOut->Mode->Mode, &cols, &rows) == EFI_SUCCESS ) - { - vga_console_info.video_type = XEN_VGATYPE_TEXT_MODE_3; - vga_console_info.u.text_mode_3.columns = cols; - vga_console_info.u.text_mode_3.rows = rows; - vga_console_info.u.text_mode_3.font_height = 16; - } + efi_arch_console_init(cols, rows); size = 0; status = efi_bs->LocateHandle(ByProtocol, &gop_guid, NULL, &size, NULL); @@ -1030,7 +1026,6 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) if ( gop ) { - int bpp = 0; /* Set graphics mode. */ if ( gop_mode < gop->Mode->MaxMode && gop_mode != gop->Mode->Mode ) @@ -1039,65 +1034,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) /* Get graphics and frame buffer info. */ status = gop->QueryMode(gop, gop->Mode->Mode, &info_size, &mode_info); if ( !EFI_ERROR(status) ) - switch ( mode_info->PixelFormat ) - { - case PixelRedGreenBlueReserved8BitPerColor: - vga_console_info.u.vesa_lfb.red_pos = 0; - vga_console_info.u.vesa_lfb.red_size = 8; - vga_console_info.u.vesa_lfb.green_pos = 8; - vga_console_info.u.vesa_lfb.green_size = 8; - vga_console_info.u.vesa_lfb.blue_pos = 16; - vga_console_info.u.vesa_lfb.blue_size = 8; - vga_console_info.u.vesa_lfb.rsvd_pos = 24; - vga_console_info.u.vesa_lfb.rsvd_size = 8; - bpp = 32; - break; - case PixelBlueGreenRedReserved8BitPerColor: - vga_console_info.u.vesa_lfb.red_pos = 16; - vga_console_info.u.vesa_lfb.red_size = 8; - vga_console_info.u.vesa_lfb.green_pos = 8; - vga_console_info.u.vesa_lfb.green_size = 8; - vga_console_info.u.vesa_lfb.blue_pos = 0; - vga_console_info.u.vesa_lfb.blue_size = 8; - vga_console_info.u.vesa_lfb.rsvd_pos = 24; - vga_console_info.u.vesa_lfb.rsvd_size = 8; - bpp = 32; - break; - case PixelBitMask: - bpp = set_color(mode_info->PixelInformation.RedMask, bpp, - &vga_console_info.u.vesa_lfb.red_pos, - &vga_console_info.u.vesa_lfb.red_size); - bpp = set_color(mode_info->PixelInformation.GreenMask, bpp, - &vga_console_info.u.vesa_lfb.green_pos, - &vga_console_info.u.vesa_lfb.green_size); - bpp = set_color(mode_info->PixelInformation.BlueMask, bpp, - &vga_console_info.u.vesa_lfb.blue_pos, - &vga_console_info.u.vesa_lfb.blue_size); - bpp = set_color(mode_info->PixelInformation.ReservedMask, bpp, - &vga_console_info.u.vesa_lfb.rsvd_pos, - &vga_console_info.u.vesa_lfb.rsvd_size); - if ( bpp > 0 ) - break; - /* fall through */ - default: - PrintErr(L"Current graphics mode is unsupported!\r\n"); - status = EFI_UNSUPPORTED; - break; - } - if ( !EFI_ERROR(status) ) - { - vga_console_info.video_type = XEN_VGATYPE_EFI_LFB; - vga_console_info.u.vesa_lfb.gbl_caps = 2; /* possibly non-VGA */ - vga_console_info.u.vesa_lfb.width = - mode_info->HorizontalResolution; - vga_console_info.u.vesa_lfb.height = mode_info->VerticalResolution; - vga_console_info.u.vesa_lfb.bits_per_pixel = bpp; - vga_console_info.u.vesa_lfb.bytes_per_line = - (mode_info->PixelsPerScanLine * bpp + 7) >> 3; - vga_console_info.u.vesa_lfb.lfb_base = gop->Mode->FrameBufferBase; - vga_console_info.u.vesa_lfb.lfb_size = - (gop->Mode->FrameBufferSize + 0xffff) >> 16; - } + efi_arch_video_init(gop, info_size, mode_info); } efi_bs->GetMemoryMap(&efi_memmap_size, NULL, &map_key, From 253d54081af32d6dc9ce08e6befa26a768c52521 Mon Sep 17 00:00:00 2001 From: Roy Franz Date: Thu, 25 Sep 2014 14:30:16 +0200 Subject: [PATCH 13/13] EFI: arch specific memory setup This patch adds efi_arch_memory() to allow each architecture a hook to use for do memory setup. x86 uses this for trampoline memory setup and some pagetable setup. Signed-off-by: Roy Franz Acked-by: Jan Beulich --- xen/arch/x86/efi/efi-boot.h | 35 +++++++++++++++++++++++++++++++++++ xen/common/efi/boot.c | 29 +---------------------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 5a1346c206..2f032e0059 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -529,3 +529,38 @@ static void __init efi_arch_video_init(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, (gop->Mode->FrameBufferSize + 0xffff) >> 16; } } + +static void __init efi_arch_memory_setup(void) +{ + unsigned int i; + EFI_STATUS status; + + /* Allocate space for trampoline (in first Mb). */ + cfg.addr = 0x100000; + cfg.size = trampoline_end - trampoline_start; + status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, + PFN_UP(cfg.size), &cfg.addr); + if ( status == EFI_SUCCESS ) + relocate_trampoline(cfg.addr); + else + { + cfg.addr = 0; + PrintStr(L"Trampoline space cannot be allocated; will try fallback.\r\n"); + } + + /* Initialise L2 identity-map and boot-map page table entries (16MB). */ + for ( i = 0; i < 8; ++i ) + { + unsigned int slot = (xen_phys_start >> L2_PAGETABLE_SHIFT) + i; + paddr_t addr = slot << L2_PAGETABLE_SHIFT; + + l2_identmap[slot] = l2e_from_paddr(addr, PAGE_HYPERVISOR|_PAGE_PSE); + slot &= L2_PAGETABLE_ENTRIES - 1; + l2_bootmap[slot] = l2e_from_paddr(addr, __PAGE_HYPERVISOR|_PAGE_PSE); + } + /* Initialise L3 boot-map page directory entries. */ + l3_bootmap[l3_table_offset(xen_phys_start)] = + l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR); + l3_bootmap[l3_table_offset(xen_phys_start + (8 << L2_PAGETABLE_SHIFT) - 1)] = + l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR); +} diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c index cbad256cce..c9b5fdca83 100644 --- a/xen/common/efi/boot.c +++ b/xen/common/efi/boot.c @@ -995,34 +995,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) PrintStr(newline); } - /* Allocate space for trampoline (in first Mb). */ - cfg.addr = 0x100000; - cfg.size = trampoline_end - trampoline_start; - status = efi_bs->AllocatePages(AllocateMaxAddress, EfiLoaderData, - PFN_UP(cfg.size), &cfg.addr); - if ( status == EFI_SUCCESS ) - relocate_trampoline(cfg.addr); - else - { - cfg.addr = 0; - PrintStr(L"Trampoline space cannot be allocated; will try fallback.\r\n"); - } - - /* Initialise L2 identity-map and boot-map page table entries (16MB). */ - for ( i = 0; i < 8; ++i ) - { - unsigned int slot = (xen_phys_start >> L2_PAGETABLE_SHIFT) + i; - paddr_t addr = slot << L2_PAGETABLE_SHIFT; - - l2_identmap[slot] = l2e_from_paddr(addr, PAGE_HYPERVISOR|_PAGE_PSE); - slot &= L2_PAGETABLE_ENTRIES - 1; - l2_bootmap[slot] = l2e_from_paddr(addr, __PAGE_HYPERVISOR|_PAGE_PSE); - } - /* Initialise L3 boot-map page directory entries. */ - l3_bootmap[l3_table_offset(xen_phys_start)] = - l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR); - l3_bootmap[l3_table_offset(xen_phys_start + (8 << L2_PAGETABLE_SHIFT) - 1)] = - l3e_from_paddr((UINTN)l2_bootmap, __PAGE_HYPERVISOR); + efi_arch_memory_setup(); if ( gop ) {