preparations for apic regs virtualization feature described in SDM rev044

This commit is contained in:
Stanislav Shwartsman 2012-09-06 15:21:08 +00:00
parent 8aac6ac761
commit f1fd44b2cf
8 changed files with 189 additions and 152 deletions

View File

@ -710,7 +710,7 @@ void bx_dbg_phy_memory_access(unsigned cpu, bx_phy_address phy, unsigned len, un
"I/O BITMAP",
"VMX LDMSR",
"VMX STMSR",
"VMX VTPR",
"VAPIC",
"SMRAM"
};

View File

@ -135,7 +135,8 @@ OBJS64 = \
bmi64.o \
tbm32.o \
tbm64.o \
xop.o
xop.o \
vapic.o
BX_INCLUDES = ../bochs.h ../config.h
@ -820,6 +821,13 @@ vmfunc.o: vmfunc.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debu
instr.h ia_opcodes.h lazy_flags.h icache.h apic.h i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
xmm.h vmx.h svm.h stack.h
vapic.o: vapic.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../gui/gui.h \
../instrument/stubs/instrument.h cpu.h cpuid.h crregs.h descriptor.h \
instr.h ia_opcodes.h lazy_flags.h icache.h apic.h i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
xmm.h vmx.h svm.h stack.h
xsave.o: xsave.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../gui/siminterface.h ../cpudb.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../gui/gui.h \

View File

@ -332,68 +332,6 @@ void bx_local_apic_c::write(bx_phy_address addr, void *data, unsigned len)
write_aligned(addr, *((Bit32u*) data));
}
#define BX_LAPIC_ID 0x020
#define BX_LAPIC_VERSION 0x030
#define BX_LAPIC_TPR 0x080
#define BX_LAPIC_ARBITRATION_PRIORITY 0x090
#define BX_LAPIC_PPR 0x0A0
#define BX_LAPIC_EOI 0x0B0
#define BX_LAPIC_RRD 0x0C0
#define BX_LAPIC_LDR 0x0D0
#define BX_LAPIC_DESTINATION_FORMAT 0x0E0
#define BX_LAPIC_SPURIOUS_VECTOR 0x0F0
#define BX_LAPIC_ISR1 0x100
#define BX_LAPIC_ISR2 0x110
#define BX_LAPIC_ISR3 0x120
#define BX_LAPIC_ISR4 0x130
#define BX_LAPIC_ISR5 0x140
#define BX_LAPIC_ISR6 0x150
#define BX_LAPIC_ISR7 0x160
#define BX_LAPIC_ISR8 0x170
#define BX_LAPIC_TMR1 0x180
#define BX_LAPIC_TMR2 0x190
#define BX_LAPIC_TMR3 0x1A0
#define BX_LAPIC_TMR4 0x1B0
#define BX_LAPIC_TMR5 0x1C0
#define BX_LAPIC_TMR6 0x1D0
#define BX_LAPIC_TMR7 0x1E0
#define BX_LAPIC_TMR8 0x1F0
#define BX_LAPIC_IRR1 0x200
#define BX_LAPIC_IRR2 0x210
#define BX_LAPIC_IRR3 0x220
#define BX_LAPIC_IRR4 0x230
#define BX_LAPIC_IRR5 0x240
#define BX_LAPIC_IRR6 0x250
#define BX_LAPIC_IRR7 0x260
#define BX_LAPIC_IRR8 0x270
#define BX_LAPIC_ESR 0x280
#define BX_LAPIC_LVT_CMCI 0x2F0
#define BX_LAPIC_ICR_LO 0x300
#define BX_LAPIC_ICR_HI 0x310
#define BX_LAPIC_LVT_TIMER 0x320
#define BX_LAPIC_LVT_THERMAL 0x330
#define BX_LAPIC_LVT_PERFMON 0x340
#define BX_LAPIC_LVT_LINT0 0x350
#define BX_LAPIC_LVT_LINT1 0x360
#define BX_LAPIC_LVT_ERROR 0x370
#define BX_LAPIC_TIMER_INITIAL_COUNT 0x380
#define BX_LAPIC_TIMER_CURRENT_COUNT 0x390
#define BX_LAPIC_TIMER_DIVIDE_CFG 0x3E0
#define BX_LAPIC_SELF_IPI 0x3F0
// extended AMD
#define BX_LAPIC_EXT_APIC_FEATURE 0x400
#define BX_LAPIC_EXT_APIC_CONTROL 0x410
#define BX_LAPIC_SPECIFIC_EOI 0x420
#define BX_LAPIC_IER1 0x480
#define BX_LAPIC_IER2 0x490
#define BX_LAPIC_IER3 0x4A0
#define BX_LAPIC_IER4 0x4B0
#define BX_LAPIC_IER5 0x4C0
#define BX_LAPIC_IER6 0x4D0
#define BX_LAPIC_IER7 0x4E0
#define BX_LAPIC_IER8 0x4F0
// APIC read: 4 byte read from 16-byte aligned APIC address
Bit32u bx_local_apic_c::read_aligned(bx_phy_address addr)
{

View File

@ -42,6 +42,70 @@
typedef Bit32u apic_dest_t; /* same definition in ioapic.h */
// local apic registers
#define BX_LAPIC_ID 0x020
#define BX_LAPIC_VERSION 0x030
#define BX_LAPIC_TPR 0x080
#define BX_LAPIC_ARBITRATION_PRIORITY 0x090
#define BX_LAPIC_PPR 0x0A0
#define BX_LAPIC_EOI 0x0B0
#define BX_LAPIC_RRD 0x0C0
#define BX_LAPIC_LDR 0x0D0
#define BX_LAPIC_DESTINATION_FORMAT 0x0E0
#define BX_LAPIC_SPURIOUS_VECTOR 0x0F0
#define BX_LAPIC_ISR1 0x100
#define BX_LAPIC_ISR2 0x110
#define BX_LAPIC_ISR3 0x120
#define BX_LAPIC_ISR4 0x130
#define BX_LAPIC_ISR5 0x140
#define BX_LAPIC_ISR6 0x150
#define BX_LAPIC_ISR7 0x160
#define BX_LAPIC_ISR8 0x170
#define BX_LAPIC_TMR1 0x180
#define BX_LAPIC_TMR2 0x190
#define BX_LAPIC_TMR3 0x1A0
#define BX_LAPIC_TMR4 0x1B0
#define BX_LAPIC_TMR5 0x1C0
#define BX_LAPIC_TMR6 0x1D0
#define BX_LAPIC_TMR7 0x1E0
#define BX_LAPIC_TMR8 0x1F0
#define BX_LAPIC_IRR1 0x200
#define BX_LAPIC_IRR2 0x210
#define BX_LAPIC_IRR3 0x220
#define BX_LAPIC_IRR4 0x230
#define BX_LAPIC_IRR5 0x240
#define BX_LAPIC_IRR6 0x250
#define BX_LAPIC_IRR7 0x260
#define BX_LAPIC_IRR8 0x270
#define BX_LAPIC_ESR 0x280
#define BX_LAPIC_LVT_CMCI 0x2F0
#define BX_LAPIC_ICR_LO 0x300
#define BX_LAPIC_ICR_HI 0x310
#define BX_LAPIC_LVT_TIMER 0x320
#define BX_LAPIC_LVT_THERMAL 0x330
#define BX_LAPIC_LVT_PERFMON 0x340
#define BX_LAPIC_LVT_LINT0 0x350
#define BX_LAPIC_LVT_LINT1 0x360
#define BX_LAPIC_LVT_ERROR 0x370
#define BX_LAPIC_TIMER_INITIAL_COUNT 0x380
#define BX_LAPIC_TIMER_CURRENT_COUNT 0x390
#define BX_LAPIC_TIMER_DIVIDE_CFG 0x3E0
#define BX_LAPIC_SELF_IPI 0x3F0
// extended AMD
#define BX_LAPIC_EXT_APIC_FEATURE 0x400
#define BX_LAPIC_EXT_APIC_CONTROL 0x410
#define BX_LAPIC_SPECIFIC_EOI 0x420
#define BX_LAPIC_IER1 0x480
#define BX_LAPIC_IER2 0x490
#define BX_LAPIC_IER3 0x4A0
#define BX_LAPIC_IER4 0x4B0
#define BX_LAPIC_IER5 0x4C0
#define BX_LAPIC_IER6 0x4D0
#define BX_LAPIC_IER7 0x4E0
#define BX_LAPIC_IER8 0x4F0
class BOCHSAPI bx_local_apic_c : public logfunctions
{
bx_phy_address base_addr;

View File

@ -328,7 +328,7 @@ enum {
BX_IO_BITMAP_ACCESS,
BX_VMX_LOAD_MSR_ACCESS,
BX_VMX_STORE_MSR_ACCESS,
BX_VMX_VTPR_ACCESS,
BX_VMX_VAPIC_ACCESS,
BX_SMRAM_ACCESS
};

View File

@ -143,7 +143,7 @@ typedef bx_cpuid_t* (*bx_create_cpuid_method)(BX_CPU_C *cpu);
// cpuid VMX features
#define BX_VMX_TPR_SHADOW (1 << 0) /* TPR shadow */
#define BX_VMX_VIRTUAL_NMI (1 << 1) /* Virtual NMI */
#define BX_VMX_APIC_VIRTUALIZATION (1 << 2) /* APIC Virtualization */
#define BX_VMX_APIC_VIRTUALIZATION (1 << 2) /* APIC Access Virtualization */
#define BX_VMX_WBINVD_VMEXIT (1 << 3) /* WBINVD VMEXIT */
#define BX_VMX_PERF_GLOBAL_CTRL (1 << 4) /* Save/Restore MSR_PERF_GLOBAL_CTRL */
#define BX_VMX_MONITOR_TRAP_FLAG (1 << 5) /* Monitor trap Flag (MTF) */
@ -159,6 +159,8 @@ typedef bx_cpuid_t* (*bx_create_cpuid_method)(BX_CPU_C *cpu);
#define BX_VMX_PAUSE_LOOP_EXITING (1 << 15) /* Pause Loop Exiting */
#define BX_VMX_EPTP_SWITCHING (1 << 16) /* EPTP switching (VM Function 0) */
#define BX_VMX_EPT_ACCESS_DIRTY (1 << 17) /* Extended Page Tables (EPT) A/D Bits */
#define BX_VMX_VIRTUAL_APIC_REGS (1 << 18) /* APIC Registers Virtualization */
#define BX_VMX_VIRTUAL_INTERRUPTS (1 << 19) /* Virtual Interrupt Delivery */
// CPUID defines - STD features CPUID[0x00000001].EDX
// ----------------------------

111
bochs/cpu/vapic.cc Normal file
View File

@ -0,0 +1,111 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2012 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_VMX && BX_SUPPORT_X86_64
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::is_virtual_apic_page(bx_phy_address paddr)
{
if (BX_CPU_THIS_PTR in_vmx_guest) {
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES))
if (PPFOf(paddr) == PPFOf(vm->apic_access_page)) return 1;
}
return 0;
}
Bit32u BX_CPU_C::VMX_Read_VTPR(void)
{
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.virtual_apic_page_addr + BX_LAPIC_TPR;
Bit32u vtpr;
access_read_physical(pAddr, 4, (Bit8u*)(&vtpr));
BX_NOTIFY_PHY_MEMORY_ACCESS(pAddr, 4, BX_READ, BX_VMX_VAPIC_ACCESS, (Bit8u*)(&vtpr));
return vtpr;
}
void BX_CPU_C::VMX_Write_VTPR(Bit8u vtpr)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
bx_phy_address pAddr = vm->virtual_apic_page_addr + BX_LAPIC_TPR;
Bit32u field32 = vtpr;
access_write_physical(pAddr, 4, (Bit8u*)(&field32));
BX_NOTIFY_PHY_MEMORY_ACCESS(pAddr, 4, BX_WRITE, BX_VMX_VAPIC_ACCESS, (Bit8u*)(&field32));
Bit8u tpr_shadow = vtpr >> 4;
if (tpr_shadow < vm->vm_tpr_threshold) {
// commit current instruction to produce trap-like VMexit
BX_CPU_THIS_PTR prev_rip = RIP; // commit new RIP
VMexit(VMX_VMEXIT_TPR_THRESHOLD, 0);
}
}
void BX_CPU_C::VMX_Virtual_Apic_Read(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
// access is not instruction fetch because cpu::prefetch will crash them
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == BX_LAPIC_TPR && len <= 4) {
// VTPR access
Bit32u vtpr = VMX_Read_VTPR();
if (len == 1)
*((Bit8u *) data) = vtpr & 0xff;
else if (len == 2)
*((Bit16u *) data) = vtpr & 0xffff;
else if (len == 4)
*((Bit32u *) data) = vtpr;
else
BX_PANIC(("PANIC: Unsupported Virtual APIC access len = 3 !"));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_READ_INSTRUCTION_EXECUTION;
VMexit(VMX_VMEXIT_APIC_ACCESS, qualification);
}
void BX_CPU_C::VMX_Virtual_Apic_Write(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == BX_LAPIC_TPR && len <= 4) {
// VTPR access
VMX_Write_VTPR(*((Bit8u *) data));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_WRITE_INSTRUCTION_EXECUTION;
VMexit(VMX_VMEXIT_APIC_ACCESS, qualification);
}
#endif // BX_SUPPORT_VMX && BX_SUPPORT_X86_64

View File

@ -650,92 +650,6 @@ void BX_CPU_C::VMexit_DR_Access(unsigned read, unsigned dr, unsigned reg)
}
}
#if BX_SUPPORT_X86_64
Bit32u BX_CPU_C::VMX_Read_VTPR(void)
{
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.virtual_apic_page_addr + 0x80;
Bit32u vtpr;
access_read_physical(pAddr, 4, (Bit8u*)(&vtpr));
BX_NOTIFY_PHY_MEMORY_ACCESS(pAddr, 4, BX_READ, BX_VMX_VTPR_ACCESS, (Bit8u*)(&vtpr));
return vtpr;
}
void BX_CPU_C::VMX_Write_VTPR(Bit8u vtpr)
{
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
bx_phy_address pAddr = vm->virtual_apic_page_addr + 0x80;
Bit32u field32 = vtpr;
access_write_physical(pAddr, 4, (Bit8u*)(&field32));
BX_NOTIFY_PHY_MEMORY_ACCESS(pAddr, 4, BX_WRITE, BX_VMX_VTPR_ACCESS, (Bit8u*)(&field32));
Bit8u tpr_shadow = vtpr >> 4;
if (tpr_shadow < vm->vm_tpr_threshold) {
// commit current instruction to produce trap-like VMexit
BX_CPU_THIS_PTR prev_rip = RIP; // commit new RIP
VMexit(VMX_VMEXIT_TPR_THRESHOLD, 0);
}
}
// apic virtualization
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::is_virtual_apic_page(bx_phy_address paddr)
{
if (BX_CPU_THIS_PTR in_vmx_guest) {
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES))
if (PPFOf(paddr) == PPFOf(vm->apic_access_page)) return 1;
}
return 0;
}
// apic virtualization
void BX_CPU_C::VMX_Virtual_Apic_Read(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
// access is not instruction fetch because cpu::prefetch will crash them
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
// VTPR access
Bit32u vtpr = VMX_Read_VTPR();
if (len == 1)
*((Bit8u *) data) = vtpr & 0xff;
else if (len == 2)
*((Bit16u *) data) = vtpr & 0xffff;
else if (len == 4)
*((Bit32u *) data) = vtpr;
else
BX_PANIC(("PANIC: Unsupported Virtual APIC access len = 3 !"));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_READ_INSTRUCTION_EXECUTION;
VMexit(VMX_VMEXIT_APIC_ACCESS, qualification);
}
// apic virtualization
void BX_CPU_C::VMX_Virtual_Apic_Write(bx_phy_address paddr, unsigned len, void *data)
{
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
Bit32u offset = PAGE_OFFSET(paddr);
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
// VTPR access
VMX_Write_VTPR(*((Bit8u *) data));
return;
}
Bit32u qualification = offset |
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_WRITE_INSTRUCTION_EXECUTION;
VMexit(VMX_VMEXIT_APIC_ACCESS, qualification);
}
#endif
#if BX_SUPPORT_VMX >= 2
Bit16u BX_CPU_C::VMX_Get_Current_VPID(void)
{