Skip to content

Commit

Permalink
Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
Browse files Browse the repository at this point in the history
* qemu-kvm/uq/master:
  pc-bios: update kvmvapic.bin
  kvmvapic: Use optionrom helpers
  optionsrom: Reserve space for checksum
  kvmvapic: Simplify mp/up_set_tpr
  kvmvapic: Introduce TPR access optimization for Windows guests
  kvmvapic: Add option ROM
  target-i386: Add infrastructure for reporting TPR MMIO accesses
  Allow to use pause_all_vcpus from VCPU context
  Process pending work while waiting for initial kick-off in TCG mode
  Remove useless casts from cpu iterators
  kvm: Set cpu_single_env only once
  kvm: Synchronize cpu state in kvm_arch_stop_on_emulation_error()
  • Loading branch information
Anthony Liguori committed Mar 1, 2012
2 parents 7c51c1a + 5b6fb06 commit 5918ff6
Show file tree
Hide file tree
Showing 20 changed files with 1,468 additions and 30 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pc-bios/vgabios-pq/status
pc-bios/optionrom/linuxboot.bin
pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw
pc-bios/optionrom/kvmvapic.bin
.stgit-*
cscope.*
tags
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
mpc8544ds.dtb \
multiboot.bin linuxboot.bin \
multiboot.bin linuxboot.bin kvmvapic.bin \
s390-zipl.rom \
spapr-rtas.bin slof.bin \
palcode-clipper
Expand Down
3 changes: 2 additions & 1 deletion Makefile.target
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,8 @@ obj-y += device-hotplug.o

# Hardware support
obj-i386-y += mc146818rtc.o pc.o
obj-i386-y += sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
obj-i386-y += apic_common.o apic.o kvmvapic.o
obj-i386-y += sga.o ioapic_common.o ioapic.o piix_pci.o
obj-i386-y += vmport.o
obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += debugcon.o multiboot.o
Expand Down
3 changes: 2 additions & 1 deletion cpu-all.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,9 @@ DECLARE_TLS(CPUState *,cpu_single_env);
#define CPU_INTERRUPT_TGT_INT_0 0x0100
#define CPU_INTERRUPT_TGT_INT_1 0x0400
#define CPU_INTERRUPT_TGT_INT_2 0x0800
#define CPU_INTERRUPT_TGT_INT_3 0x2000

/* First unused bit: 0x2000. */
/* First unused bit: 0x4000. */

/* The set of all bits that should be masked when single-stepping. */
#define CPU_INTERRUPT_SSTEP_MASK \
Expand Down
26 changes: 22 additions & 4 deletions cpus.c
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,7 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
qemu_mutex_lock(&qemu_global_mutex);
qemu_thread_get_self(env->thread);
env->thread_id = qemu_get_thread_id();
cpu_single_env = env;

r = kvm_init_vcpu(env);
if (r < 0) {
Expand Down Expand Up @@ -760,6 +761,11 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
/* wait for initial kick-off after machine start */
while (first_cpu->stopped) {
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);

/* process any pending work */
for (env = first_cpu; env != NULL; env = env->next_cpu) {
qemu_wait_io_event_common(env);
}
}

while (1) {
Expand Down Expand Up @@ -852,7 +858,7 @@ static int all_vcpus_paused(void)
if (!penv->stopped) {
return 0;
}
penv = (CPUState *)penv->next_cpu;
penv = penv->next_cpu;
}

return 1;
Expand All @@ -866,15 +872,27 @@ void pause_all_vcpus(void)
while (penv) {
penv->stop = 1;
qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
penv = penv->next_cpu;
}

if (!qemu_thread_is_self(&io_thread)) {
cpu_stop_current();
if (!kvm_enabled()) {
while (penv) {
penv->stop = 0;
penv->stopped = 1;
penv = penv->next_cpu;
}
return;
}
}

while (!all_vcpus_paused()) {
qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
penv = first_cpu;
while (penv) {
qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
penv = penv->next_cpu;
}
}
}
Expand All @@ -888,7 +906,7 @@ void resume_all_vcpus(void)
penv->stop = 0;
penv->stopped = 0;
qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
penv = penv->next_cpu;
}
}

Expand Down
126 changes: 115 additions & 11 deletions hw/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
#define MSI_ADDR_DEST_ID_SHIFT 12
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0

#define SYNC_FROM_VAPIC 0x1
#define SYNC_TO_VAPIC 0x2
#define SYNC_ISR_IRR_TO_VAPIC 0x4

static APICCommonState *local_apics[MAX_APICS + 1];

static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
Expand Down Expand Up @@ -78,6 +82,70 @@ static inline int get_bit(uint32_t *tab, int index)
return !!(tab[i] & mask);
}

/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
int i;
for (i = 7; i >= 0; i--) {
if (tab[i] != 0) {
return i * 32 + fls_bit(tab[i]);
}
}
return -1;
}

static void apic_sync_vapic(APICCommonState *s, int sync_type)
{
VAPICState vapic_state;
size_t length;
off_t start;
int vector;

if (!s->vapic_paddr) {
return;
}
if (sync_type & SYNC_FROM_VAPIC) {
cpu_physical_memory_rw(s->vapic_paddr, (void *)&vapic_state,
sizeof(vapic_state), 0);
s->tpr = vapic_state.tpr;
}
if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
start = offsetof(VAPICState, isr);
length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);

if (sync_type & SYNC_TO_VAPIC) {
assert(qemu_cpu_is_self(s->cpu_env));

vapic_state.tpr = s->tpr;
vapic_state.enabled = 1;
start = 0;
length = sizeof(VAPICState);
}

vector = get_highest_priority_int(s->isr);
if (vector < 0) {
vector = 0;
}
vapic_state.isr = vector & 0xf0;

vapic_state.zero = 0;

vector = get_highest_priority_int(s->irr);
if (vector < 0) {
vector = 0;
}
vapic_state.irr = vector & 0xff;

cpu_physical_memory_write_rom(s->vapic_paddr + start,
((void *)&vapic_state) + start, length);
}
}

static void apic_vapic_base_update(APICCommonState *s)
{
apic_sync_vapic(s, SYNC_TO_VAPIC);
}

static void apic_local_deliver(APICCommonState *s, int vector)
{
uint32_t lvt = s->lvt[vector];
Expand Down Expand Up @@ -239,20 +307,17 @@ static void apic_set_base(APICCommonState *s, uint64_t val)

static void apic_set_tpr(APICCommonState *s, uint8_t val)
{
s->tpr = (val & 0x0f) << 4;
apic_update_irq(s);
/* Updates from cr8 are ignored while the VAPIC is active */
if (!s->vapic_paddr) {
s->tpr = val << 4;
apic_update_irq(s);
}
}

/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
static uint8_t apic_get_tpr(APICCommonState *s)
{
int i;
for(i = 7; i >= 0; i--) {
if (tab[i] != 0) {
return i * 32 + fls_bit(tab[i]);
}
}
return -1;
apic_sync_vapic(s, SYNC_FROM_VAPIC);
return s->tpr >> 4;
}

static int apic_get_ppr(APICCommonState *s)
Expand Down Expand Up @@ -312,6 +377,14 @@ static void apic_update_irq(APICCommonState *s)
}
}

void apic_poll_irq(DeviceState *d)
{
APICCommonState *s = APIC_COMMON(d);

apic_sync_vapic(s, SYNC_FROM_VAPIC);
apic_update_irq(s);
}

static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
{
apic_report_irq_delivered(!get_bit(s->irr, vector_num));
Expand All @@ -321,6 +394,16 @@ static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
set_bit(s->tmr, vector_num);
else
reset_bit(s->tmr, vector_num);
if (s->vapic_paddr) {
apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
/*
* The vcpu thread needs to see the new IRR before we pull its current
* TPR value. That way, if we miss a lowering of the TRP, the guest
* has the chance to notice the new IRR and poll for IRQs on its own.
*/
smp_wmb();
apic_sync_vapic(s, SYNC_FROM_VAPIC);
}
apic_update_irq(s);
}

Expand All @@ -334,6 +417,7 @@ static void apic_eoi(APICCommonState *s)
if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && get_bit(s->tmr, isrv)) {
ioapic_eoi_broadcast(isrv);
}
apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
apic_update_irq(s);
}

Expand Down Expand Up @@ -471,15 +555,19 @@ int apic_get_interrupt(DeviceState *d)
if (!(s->spurious_vec & APIC_SV_ENABLE))
return -1;

apic_sync_vapic(s, SYNC_FROM_VAPIC);
intno = apic_irq_pending(s);

if (intno == 0) {
apic_sync_vapic(s, SYNC_TO_VAPIC);
return -1;
} else if (intno < 0) {
apic_sync_vapic(s, SYNC_TO_VAPIC);
return s->spurious_vec & 0xff;
}
reset_bit(s->irr, intno);
set_bit(s->isr, intno);
apic_sync_vapic(s, SYNC_TO_VAPIC);
apic_update_irq(s);
return intno;
}
Expand Down Expand Up @@ -576,6 +664,10 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
break;
case 0x08:
apic_sync_vapic(s, SYNC_FROM_VAPIC);
if (apic_report_tpr_access) {
cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_READ);
}
val = s->tpr;
break;
case 0x09:
Expand Down Expand Up @@ -675,7 +767,11 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
case 0x03:
break;
case 0x08:
if (apic_report_tpr_access) {
cpu_report_tpr_access(s->cpu_env, TPR_ACCESS_WRITE);
}
s->tpr = val;
apic_sync_vapic(s, SYNC_TO_VAPIC);
apic_update_irq(s);
break;
case 0x09:
Expand Down Expand Up @@ -737,6 +833,11 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
}

static void apic_pre_save(APICCommonState *s)
{
apic_sync_vapic(s, SYNC_FROM_VAPIC);
}

static void apic_post_load(APICCommonState *s)
{
if (s->timer_expiry != -1) {
Expand Down Expand Up @@ -770,7 +871,10 @@ static void apic_class_init(ObjectClass *klass, void *data)
k->init = apic_init;
k->set_base = apic_set_base;
k->set_tpr = apic_set_tpr;
k->get_tpr = apic_get_tpr;
k->vapic_base_update = apic_vapic_base_update;
k->external_nmi = apic_external_nmi;
k->pre_save = apic_pre_save;
k->post_load = apic_post_load;
}

Expand Down
2 changes: 2 additions & 0 deletions hw/apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ void cpu_set_apic_tpr(DeviceState *s, uint8_t val);
uint8_t cpu_get_apic_tpr(DeviceState *s);
void apic_init_reset(DeviceState *s);
void apic_sipi(DeviceState *s);
void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
TPRAccess access);

/* pc.c */
int cpu_is_bsp(CPUState *env);
Expand Down
Loading

0 comments on commit 5918ff6

Please sign in to comment.