aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2006-12-11 11:22:18 +0000
committerAvi Kivity <avi@qumranet.com>2006-12-11 11:22:18 +0000
commitdd5f8255f4ecf32f3ed3c3fd30977f01ebe8b495 (patch)
treeae1ae6c76c1c9a0c3f0f4758a1d76d9f22e74a67
parent4748026110f3efbc333b9a01160760980bdc7011 (diff)
kvm: kernel release: merge from trunk
Merged revisions 3174,3176-3179,3181-3182,3184-3190,3192-3193,3195,3197-3202,3204-3205,3207-3208,3212-3213,3215-3219,3223-3224,3226-3228,3230-3262,3265-3274,3276-3281,3283-3296,3298-3300,3302-3305,3307-3310,3312-3318,3322-3324,3326-3338,3340-3356,3358,3360-3371,3373-3375,3377-3383,3385-3386,3403-3411,3413-3414,3416-3417,3419,3421,3425,3427-3431,3436-3438,3441,3445,3449,3451-3452,3454-3456,3458-3461,3464-3470,3473-3474,3476,3478,3481-3491,3493-3505,3507-3514,3516,3518-3522,3524-3545,3547-3552,3554-3569,3571-3583,3586,3589-3590,3592-3611,3613,3615-3619,3621-3628,3630-3646,3648-3663,3665-3675,3677-3699,3701-3718,3720-3722,3724-3725,3727-3742,3744-3758,3762-3767,3769-3773,3775-3776,3778-3788,3790,3792-3813,3815-3816,3819-3824,3826,3828-3832,3837-3838,3842,3845,3848-3879,3881-3906,3910,3918,3921,3928,3933,3940,3946,3948-3950,3952,3954-3956,3970-3972,3975,3977,3981,3983,3990-4012,4014-4023,4025-4031,4033-4051,4053-4056 via svnmerge from svn://cleopatra.q/svn/kvm/kvm/trunk ........ r3884 | dor | 2006-11-22 16:40:05 +0200 (Wed, 22 Nov 2006) | 2 lines Move the rpm dir to the above level. Good for linkage with the external repository rpms ........ r3891 | uri | 2006-11-23 11:24:58 +0200 (Thu, 23 Nov 2006) | 2 lines kvm: Makefile: removing one 'clean' target (out of two) ........ r3992 | avi | 2006-11-28 18:02:46 +0200 (Tue, 28 Nov 2006) | 2 lines kvm: web: update for amd ........ r3993 | uri | 2006-11-28 18:58:18 +0200 (Tue, 28 Nov 2006) | 2 lines qemu migration: in preparation for non blocking sockets ........ r3994 | uri | 2006-11-29 12:09:04 +0200 (Wed, 29 Nov 2006) | 10 lines qemu migration: use non-blocking sockets for connection establishment benefits: 1. let the guest run on the src-host 2. do not "lose" console on dst-host 3. later let any side start the migration (enable src being the listener). When the migration start blocking sockets are used. ToDo: keep using non-blocking sockets for the sender. ........ r3995 | dor | 2006-11-29 12:38:04 +0200 (Wed, 29 Nov 2006) | 2 lines Add the amd, intel kernel modules to the installation ........ r3996 | dor | 2006-11-29 12:47:10 +0200 (Wed, 29 Nov 2006) | 2 lines Add removal of platform specific modules. ........ r3998 | uri | 2006-11-29 14:58:10 +0200 (Wed, 29 Nov 2006) | 4 lines qemu: focus on monitor if '-S' option requested Eliminates the need for the first ALT-CTRL-2 ........ r3999 | avi | 2006-11-29 16:22:14 +0200 (Wed, 29 Nov 2006) | 2 lines kvm: web: add bug tracker menu item ........ r4002 | uri | 2006-11-29 18:13:54 +0200 (Wed, 29 Nov 2006) | 2 lines qemu monitor: enable 'migration' subcommand completion ........ r4003 | uri | 2006-11-29 19:15:24 +0200 (Wed, 29 Nov 2006) | 7 lines qemu monitor: enable 'migration' subcommand completion (not done in r4002) r4002 modified migration.c where migration_start_src/dst functions were introduced (to enable later start from the listener), as well as automatic stop/cont before/after the actual migration and migration time measurement. ........ r4004 | uri | 2006-11-29 21:28:22 +0200 (Wed, 29 Nov 2006) | 4 lines qemu migration: comment out automatic-cleanup upon migration completion Causes segmentation fault in main_loop_wait ........ r4009 | dor | 2006-11-30 13:03:00 +0200 (Thu, 30 Nov 2006) | 2 lines Add explanation for windows status + a work around. ........ r4010 | avi | 2006-11-30 14:13:35 +0200 (Thu, 30 Nov 2006) | 6 lines kvm: web: update windows install procedure - minor content changes - proper html for list - correct attribution ........ r4014 | avi | 2006-11-30 16:13:50 +0200 (Thu, 30 Nov 2006) | 4 lines kvm: enable alsa for qemu allows sound on host. ........ r4016 | uri | 2006-12-03 11:19:31 +0200 (Sun, 03 Dec 2006) | 4 lines qemu-kvm load state: removed default values of segments Recommit this part of rev 3880 that was overwritten by a merge. ........ r4020 | avi | 2006-12-04 11:13:20 +0200 (Mon, 04 Dec 2006) | 2 lines kvm: web: recruiting ad ........ r4021 | avi | 2006-12-04 11:14:34 +0200 (Mon, 04 Dec 2006) | 2 lines kvm: web: mark AMD as supported ........ r4028 | uri | 2006-12-05 10:25:56 +0200 (Tue, 05 Dec 2006) | 2 lines qemu migration interface (0000143): basic support for 'migration status' ........ r4029 | uri | 2006-12-05 11:09:40 +0200 (Tue, 05 Dec 2006) | 8 lines qemu: make select-fds-service-loop io-handlers-deletion safe Deletion of an io handler (calling qemu_set_fd_handler(fd, NULL, NULL, NULL)) done from its own read handler, could cause segmentation fault when checking its write handler. Separating read handlers from write handlers solves that problem since the write handlers loop would now skip the deleted ioh. ........ r4030 | uri | 2006-12-05 11:22:01 +0200 (Tue, 05 Dec 2006) | 6 lines qemu migration interface: (0000143) disconnect socket when migration finishes The host on which the guest continues to run closes the connection dst-host on successful migration, src-host on failure. The other host waits for the connection to be closed. ........ r4031 | uri | 2006-12-05 11:57:09 +0200 (Tue, 05 Dec 2006) | 8 lines qemu migration interface (0000143): separate migration start and migration connect Before the source host had to be the one who connects and the destination host had to be the one who listens. Now migration start is independent of connection establishment. The source host must be the one who starts the migration, with 'migration start' command. ........ r4034 | uri | 2006-12-05 12:36:55 +0200 (Tue, 05 Dec 2006) | 2 lines qemu migration interface (0000143): add 'migration set' subcommands to monitor ........ r4035 | uri | 2006-12-05 12:55:56 +0200 (Tue, 05 Dec 2006) | 2 lines qemu monitor: 'migration', 'migration set': show help if no subcommand given ........ r4036 | uri | 2006-12-05 13:28:26 +0200 (Tue, 05 Dec 2006) | 5 lines qemu monitor: added 'const' to functions parameters Those removed by r4035 and more. Noticed by avi. ........ r4037 | uri | 2006-12-05 13:33:13 +0200 (Tue, 05 Dec 2006) | 4 lines qemu migration interface (0000143): basic implementation for 'migration set' Save the values, Show them, (currently) Ignore them. ........ r4038 | yaniv | 2006-12-05 14:34:56 +0200 (Tue, 05 Dec 2006) | 1 line kvm: fix ACPI SCI delivery ........ r4039 | itaish | 2006-12-06 11:11:45 +0200 (Wed, 06 Dec 2006) | 3 lines Hypercall: Create the qemu side of the pci io device for the hypercall. Next plan is to use regular memory page instead of io port for each write. ........ r4046 | avi | 2006-12-10 11:37:03 +0200 (Sun, 10 Dec 2006) | 4 lines kvm: qemu: replace the segment macros by functions From: Anthony Liguori <aliguori@cs.utexas.edu> ........
-rw-r--r--Makefile.target5
-rw-r--r--hw/acpi.c89
-rw-r--r--hw/hypercall.c91
-rw-r--r--hw/pc.c7
-rw-r--r--hw/piix_pci.c4
-rw-r--r--hw/vga.c4
-rwxr-xr-xkvm/configure1
-rw-r--r--kvm/kernel/kvm-kmod.spec6
-rw-r--r--kvm/kvm.spec2
-rw-r--r--migration.c259
-rw-r--r--migration.h3
-rw-r--r--monitor.c30
-rw-r--r--qemu-kvm.c145
-rw-r--r--vl.c6
-rw-r--r--vl.h4
15 files changed, 500 insertions, 156 deletions
diff --git a/Makefile.target b/Makefile.target
index 51fed35f1..296ea63b1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -340,7 +340,10 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
# PCI network cards
-VL_OBJS+= ne2000.o rtl8139.o pcnet.o
+VL_OBJS+= ne2000.o rtl8139.o pcnet.o
+
+# PCI Hypercall
+VL_OBJS+= hypercall.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
diff --git a/hw/acpi.c b/hw/acpi.c
index 6c20a4e93..488404268 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -34,7 +34,8 @@ typedef struct PIIX4PMState {
uint16_t pmen;
uint16_t pmcntrl;
QEMUTimer *tmr_timer;
- int64_t tmr_overflow_time;
+ int64_t pmtmr;
+ int active_timer;
} PIIX4PMState;
#define RTC_EN (1 << 10)
@@ -46,50 +47,71 @@ typedef struct PIIX4PMState {
#define SUS_EN (1 << 13)
+#define SCI_IRQ 9
+
/* Note: only used for ACPI bios init. Could be deleted when ACPI init
is integrated in Bochs BIOS */
static PIIX4PMState *piix4_pm_state;
+extern IOAPICState *ioapic;
+
+
+static void update_pmtmr(PIIX4PMState *s)
+{
+ struct timespec ts;
+ int64_t val;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ val = ts.tv_sec;
+ val *= 1000000000;
+ val += ts.tv_nsec;
+ val *= PM_FREQ;
+ val /= 1000000000;
+
+ if (!(s->pmsts & TMROF_EN)) {
+ if ((val & 0x00800000) != (s->pmtmr & 0x00800000)) {
+ s->pmsts |= TMROF_EN;
+ if (s->pmen & TMROF_EN) {
+ ioapic_set_irq(ioapic, SCI_IRQ, 1);
+ }
+ } else if (!s->active_timer) {
+ uint64_t delta = 0x00800000 - (val & 0x007fffff);
+ delta /= (PM_FREQ / 1000);
+ s->active_timer = 1;
+ qemu_mod_timer(s->tmr_timer, qemu_get_clock(rt_clock) + delta + 1);
+ }
+ }
+ s->pmtmr = val;
+}
+
static uint32_t get_pmtmr(PIIX4PMState *s)
{
- uint32_t d;
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
- return d & 0xffffff;
+ update_pmtmr(s);
+ return s->pmtmr & 0xffffff;
}
static int get_pmsts(PIIX4PMState *s)
{
- int64_t d;
- int pmsts;
- pmsts = s->pmsts;
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
- if (d >= s->tmr_overflow_time)
- s->pmsts |= TMROF_EN;
- return pmsts;
+ return s->pmsts;
}
+
static void pm_update_sci(PIIX4PMState *s)
{
- int sci_level, pmsts;
- int64_t expire_time;
-
- pmsts = get_pmsts(s);
- sci_level = (((pmsts & s->pmen) &
+ int sci_level;
+ sci_level = (((s->pmsts & s->pmen) &
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
- pci_set_irq(&s->dev, 0, sci_level);
- /* schedule a timer interruption if needed */
- if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
- expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
- qemu_mod_timer(s->tmr_timer, expire_time);
- } else {
- qemu_del_timer(s->tmr_timer);
+ if (!sci_level) {
+ ioapic_set_irq(ioapic, SCI_IRQ, 0);
}
}
static void pm_tmr_timer(void *opaque)
{
PIIX4PMState *s = opaque;
- pm_update_sci(s);
+ s->active_timer = 0;
+ update_pmtmr(s);
}
static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
@@ -98,18 +120,9 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
addr &= 0x3f;
switch(addr) {
case 0x00:
- {
- int64_t d;
- int pmsts;
- pmsts = get_pmsts(s);
- if (pmsts & val & TMROF_EN) {
- /* if TMRSTS is reset, then compute the new overflow time */
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
- s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
- }
- s->pmsts &= ~val;
- pm_update_sci(s);
- }
+ s->pmsts &= ~val;
+ update_pmtmr(s);
+ pm_update_sci(s);
break;
case 0x02:
s->pmen = val;
@@ -259,7 +272,7 @@ void piix4_pm_init(PCIBus *bus, int devfn)
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
(serial_hds[1] != NULL ? 0x90 : 0);
- s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
+ s->tmr_timer = qemu_new_timer(rt_clock, pm_tmr_timer, s);
piix4_pm_state = s;
}
@@ -559,7 +572,7 @@ void acpi_bios_init(void)
fadt->dsdt = cpu_to_le32(dsdt_addr);
fadt->model = 1;
fadt->reserved1 = 0;
- fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]);
+ fadt->sci_int = cpu_to_le16(SCI_IRQ);
fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
fadt->acpi_enable = 0xf1;
fadt->acpi_disable = 0xf0;
diff --git a/hw/hypercall.c b/hw/hypercall.c
new file mode 100644
index 000000000..c59a2e7bf
--- /dev/null
+++ b/hw/hypercall.c
@@ -0,0 +1,91 @@
+/*
+ * QEMU-KVM Hypercall emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2006 Qumranet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+typedef struct HypercallState {
+ uint8_t cmd;
+ uint32_t start;
+ uint32_t stop;
+} HypercallState;
+
+static void hp_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ //printf("hp_ioport_write, val=0x%x\n", val);
+}
+
+static uint32_t hp_ioport_read(void *opaque, uint32_t addr)
+{
+ //printf("hp_ioport_read\n");
+ return 0;
+}
+
+/***********************************************************/
+/* PCI Hypercall definitions */
+
+typedef struct PCIHypercallState {
+ PCIDevice dev;
+ HypercallState hp;
+} PCIHypercallState;
+
+static void hp_map(PCIDevice *pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ PCIHypercallState *d = (PCIHypercallState *)pci_dev;
+ HypercallState *s = &d->hp;
+
+ register_ioport_write(addr, 16, 1, hp_ioport_write, s);
+ register_ioport_read(addr, 16, 1, hp_ioport_read, s);
+
+}
+
+void pci_hypercall_init(PCIBus *bus)
+{
+ PCIHypercallState *d;
+
+ uint8_t *pci_conf;
+
+ //printf("pci_hypercall_init\n");
+
+ d = (PCIHypercallState *)pci_register_device(bus,
+ "HPNAME", sizeof(PCIHypercallState),
+ -1,
+ NULL, NULL);
+
+ pci_conf = d->dev.config;
+ pci_conf[0x00] = 0x02; // Qumranet vendor ID 0x5002
+ pci_conf[0x01] = 0x50;
+ pci_conf[0x02] = 0x58; // Qumranet DeviceID 0x2258
+ pci_conf[0x03] = 0x22;
+
+ pci_conf[0x09] = 0x00; // ProgIf
+ pci_conf[0x0a] = 0x00; // SubClass
+ pci_conf[0x0b] = 0x05; // BaseClass
+
+ pci_conf[0x0e] = 0x00; // header_type
+ pci_conf[0x3d] = 0x00; // interrupt pin 0
+
+ pci_register_io_region(&d->dev, 0, 0x100,
+ PCI_ADDRESS_SPACE_IO, hp_map);
+}
diff --git a/hw/pc.c b/hw/pc.c
index 2965b4617..d7ad72887 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -43,7 +43,8 @@ extern int kvm_allowed;
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
-static IOAPICState *ioapic;
+
+IOAPICState *ioapic;
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
{
@@ -852,6 +853,10 @@ static void pc_init1(int ram_size, int vga_ram_size, int boot_device,
}
}
+#define USE_HYPERCALL
+#ifdef USE_HYPERCALL
+ pci_hypercall_init(pci_bus);
+#endif
if (pci_enabled) {
pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
} else {
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 1f7ad94c6..d143d59ae 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -158,8 +158,12 @@ static void piix3_reset(PCIDevice *d)
pci_conf[0x4e] = 0x03;
pci_conf[0x4f] = 0x00;
pci_conf[0x60] = 0x80;
+ pci_conf[0x61] = 0x80;
+ pci_conf[0x62] = 0x80;
+ pci_conf[0x63] = 0x80;
pci_conf[0x69] = 0x02;
pci_conf[0x70] = 0x80;
+ pci_conf[0x71] = 0x80;
pci_conf[0x76] = 0x0c;
pci_conf[0x77] = 0x0c;
pci_conf[0x78] = 0x02;
diff --git a/hw/vga.c b/hw/vga.c
index 41088068d..4c1e57e4b 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1507,16 +1507,20 @@ static void vga_draw_graphic(VGAState *s, int full_update)
update = full_update |
cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
+#ifdef USE_KVM
if (kvm_allowed) {
update |= bitmap_get_dirty(bitmap, (page0 - s->vram_offset) >> TARGET_PAGE_BITS);
update |= bitmap_get_dirty(bitmap, (page1 - s->vram_offset) >> TARGET_PAGE_BITS);
}
+#endif
if ((page1 - page0) > TARGET_PAGE_SIZE) {
/* if wide line, can use another page */
update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
VGA_DIRTY_FLAG);
+#ifdef USE_KVM
if (kvm_allowed)
update |= bitmap_get_dirty(bitmap, (page0 - s->vram_offset) >> TARGET_PAGE_BITS);
+#endif
}
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
diff --git a/kvm/configure b/kvm/configure
index 060df707a..abadafebe 100755
--- a/kvm/configure
+++ b/kvm/configure
@@ -66,6 +66,7 @@ target_cpu() {
--disable-kqemu --extra-cflags="-I $PWD/../user" \
--extra-ldflags="-L $PWD/../user" \
--enable-kvm --kernel-path="$libkvm_kerneldir" \
+ --enable-alsa \
--prefix="$prefix"
)
diff --git a/kvm/kernel/kvm-kmod.spec b/kvm/kernel/kvm-kmod.spec
index 9b9874acf..da2554c44 100644
--- a/kvm/kernel/kvm-kmod.spec
+++ b/kvm/kernel/kvm-kmod.spec
@@ -26,8 +26,8 @@ rm -rf %{buildroot}
%define moddir /lib/modules/%{kverrel}/extra
mkdir -p %{buildroot}/%{moddir}
-cp %{objdir}/%{kmod_name}.ko %{buildroot}/%{moddir}
-chmod u+x %{buildroot}/%{moddir}/%{kmod_name}.ko
+cp %{objdir}/%{kmod_name}.ko %{objdir}/%{kmod_name}-intel.ko %{objdir}/%{kmod_name}-amd.ko %{buildroot}/%{moddir}
+chmod u+x %{buildroot}/%{moddir}/%{kmod_name}*.ko
%post
@@ -41,6 +41,8 @@ depmod %{kverrel}
%files
%{moddir}/%{kmod_name}.ko
+%{moddir}/%{kmod_name}-amd.ko
+%{moddir}/%{kmod_name}-intel.ko
%changelog
diff --git a/kvm/kvm.spec b/kvm/kvm.spec
index bc6745936..17d8af6c6 100644
--- a/kvm/kvm.spec
+++ b/kvm/kvm.spec
@@ -20,7 +20,7 @@ BuildRequires: compat-gcc-32
BuildRequires: compat-gcc-34
%endif
-BuildRequires: SDL-devel zlib-devel
+BuildRequires: SDL-devel zlib-devel alsa-lib-devel
%define _prebuilt %{?prebuilt:1}%{!?prebuilt:0}
diff --git a/migration.c b/migration.c
index 82c9d670b..80ec292d5 100644
--- a/migration.c
+++ b/migration.c
@@ -3,11 +3,20 @@
#include "migration.h"
#define TO_BE_IMPLEMENTED term_printf("%s: TO_BE_IMPLEMENTED\n", __FUNCTION__)
+#define USE_NONBLOCKING_SOCKETS
#ifndef CONFIG_USER_ONLY
/* defined in vl.c */
int parse_host_port(struct sockaddr_in *saddr, const char *str);
+#ifdef USE_NONBLOCKING_SOCKETS
+void socket_set_block(int fd) /* should be in vl.c ? */
+{
+ int val;
+ val = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, val & ~O_NONBLOCK);
+}
+#endif
#define FD_UNUSED -1
@@ -17,29 +26,73 @@ typedef enum {
READER = 2
} migration_role_t;
+typedef enum {
+ MIG_STAT_NONE = 0, /* disconnected */
+ MIG_STAT_CONN = 1, /* connection established */
+ MIG_STAT_START = 2, /* migration started */
+ MIG_STAT_SUCC = 3, /* migration completed successfully */
+ MIG_STAT_FAIL = 4, /* migration failed */
+ MIG_STAT_CANCEL = 5 /* migration canceled */
+} migration_status_t;
+
+typedef struct migration_bandwith_params {
+ int min, max, offline, seconds;
+} migration_bandwith_params_t;
+
typedef struct migration_state {
int fd;
+ migration_status_t status;
#define BUFFSIZE ( 256 * 1024)
unsigned char buff[BUFFSIZE]; /* FIXME: allocate dynamically; use mutli/double buffer */
unsigned buffsize;
unsigned head, tail;
migration_role_t role;
int64_t head_counter, tail_counter;
+ migration_bandwith_params_t bw;
} migration_state_t;
static migration_state_t ms = {
.fd = FD_UNUSED,
+ .status = MIG_STAT_NONE,
.buff = { 0 },
.buffsize = BUFFSIZE,
.head = 0,
.tail = 0,
.head_counter = 0,
- .tail_counter = 0
+ .tail_counter = 0,
+ .bw = {0, 0, 0, 0}
};
static const char *reader_default_addr="localhost:4455";
static const char *writer_default_addr="localhost:4456";
+/* forward declarations */
+static void migration_start_dst(int online);
+
+
+static const char *mig_stat_str(migration_status_t mig_stat)
+{
+ struct {
+ migration_status_t stat;
+ const char *str;
+ } stat_strs[] = {
+ {MIG_STAT_NONE, "disconnected"},
+ {MIG_STAT_CONN, "connected"},
+ {MIG_STAT_START, "migration stared"},
+ {MIG_STAT_SUCC, "migration completed successfully"},
+ {MIG_STAT_FAIL, "migration failed"},
+ {MIG_STAT_CANCEL, "migration canceled"}
+ };
+
+ int i;
+
+ for (i=0 ; i<sizeof(stat_strs)/sizeof(stat_strs[0]) ; i++)
+ if (stat_strs[i].stat == mig_stat)
+ return stat_strs[i].str;
+
+ return "unknown migration_status";
+}
+
/* circular buffer functions */
static int migration_buffer_empty(migration_state_t *pms)
{
@@ -94,7 +147,7 @@ static int parse_host_port_and_message(struct sockaddr_in *saddr,
return 0;
}
-static void migration_cleanup(migration_state_t *pms)
+static void migration_cleanup(migration_state_t *pms, migration_status_t stat)
{
if (pms->fd != FD_UNUSED) {
#ifdef USE_NONBLOCKING_SOCKETS
@@ -102,6 +155,7 @@ static void migration_cleanup(migration_state_t *pms)
#endif
close(pms->fd);
pms->fd = FD_UNUSED;
+ pms->status = stat;
}
}
@@ -110,8 +164,11 @@ static int migration_read_from_socket(void *opaque)
migration_state_t *pms = (migration_state_t *)opaque;
int size, toend;
+ if (pms->status != MIG_STAT_START)
+ return 0;
if (pms->fd == FD_UNUSED) /* not connected */
return 0;
+
while (1) { /* breaking if O.K. */
size = migration_buffer_bytes_empty(pms); /* available size */
toend = migration_buffer_bytes_head_end(pms);
@@ -127,7 +184,7 @@ static int migration_read_from_socket(void *opaque)
if (size == 0) {
/* connection closed */
term_printf("migration_read_from_socket: CONNECTION CLOSED\n");
- migration_cleanup(pms);
+ migration_cleanup(pms, MIG_STAT_FAIL);
/* FIXME: call vm_start on A or B according to migration status ? */
return size;
}
@@ -144,6 +201,8 @@ static int migration_write_into_socket(void *opaque, int len)
migration_state_t *pms = (migration_state_t *)opaque;
int size, toend;
+ if (pms->status != MIG_STAT_START)
+ return 0;
if (pms->fd == FD_UNUSED) /* not connected */
return 0;
while (1) { /* breaking if O.K. */
@@ -164,7 +223,7 @@ static int migration_write_into_socket(void *opaque, int len)
if (size == 0) {
/* connection closed */
term_printf("migration_write_into_socket: CONNECTION CLOSED\n");
- migration_cleanup(pms);
+ migration_cleanup(pms, MIG_STAT_FAIL);
return size;
}
else /* we did write something */
@@ -175,6 +234,11 @@ static int migration_write_into_socket(void *opaque, int len)
return size;
}
+static void migration_start_now(void *opaque)
+{
+ migration_start_dst(0);
+}
+
static void migration_accept(void *opaque)
{
migration_state_t *pms = (migration_state_t *)opaque;
@@ -197,19 +261,18 @@ static void migration_accept(void *opaque)
/* FIXME: Need to be modified if we want to have a control connection
* e.g. cancel/abort
*/
- migration_cleanup(pms); /* clean old fd */
+ migration_cleanup(pms, MIG_STAT_CONN); /* clean old fd */
pms->fd = new_fd;
term_printf("accepted new socket as fd %d\n", pms->fd);
#ifdef USE_NONBLOCKING_SOCKETS
/* start handling I/O */
- qemu_set_fd_handler(pms->fd, migration_read_from_socket, NULL, NULL);
+ qemu_set_fd_handler(pms->fd, migration_start_now, NULL, pms);
#else
term_printf("waiting for migration to start...\n");
- do_migration_start("offline");
+ migration_start_now(pms);
#endif
-
}
@@ -223,8 +286,6 @@ void do_migration_listen(char *arg1, char *arg2)
return;
}
- ms.role = READER;
-
if (parse_host_port_and_message(&local, arg1, reader_default_addr, "migration listen"))
return;
@@ -243,22 +304,24 @@ void do_migration_listen(char *arg1, char *arg2)
setsockopt(ms.fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
if (bind(ms.fd, &local, sizeof local) < 0 ) {
- migration_cleanup(&ms);
+ migration_cleanup(&ms, MIG_STAT_NONE);
term_printf("migration listen: bind() failed (%s)\n", strerror(errno));
return;
}
if (listen(ms.fd, 1) < 0) { /* allow only one connection */
- migration_cleanup(&ms);
+ migration_cleanup(&ms, MIG_STAT_NONE);
term_printf("migration listen: listen() failed (%s)\n", strerror(errno));
return;
}
+ term_printf("migration listen: listening on fd %d\n", ms.fd);
+
#ifdef USE_NONBLOCKING_SOCKETS
/* FIXME: should I allow BLOCKING socket after vm_stop() to get full bandwidth? */
- socket_set_nonblock(fd); /* do not block and delay the guest */
+ socket_set_nonblock(ms.fd); /* do not block and delay the guest */
- qemu_set_fd_handler(fd, migration_accept, NULL, NULL); /* wait for connect() */
+ qemu_set_fd_handler(ms.fd, migration_accept, NULL, &ms); /* wait for connect() */
#else
migration_accept(&ms);
#endif
@@ -379,6 +442,33 @@ static int migration_write_buffer(const char *buff, int len)
return len_req - len;
}
+static void migration_connect_check(void *opaque)
+{
+ migration_state_t *pms = (migration_state_t *)opaque;
+ int err, rc;
+ socklen_t len=sizeof(err);
+
+ rc = getsockopt(pms->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &len);
+ if (rc != 0) {
+ term_printf("migration connect: getsockopt FAILED (%s)\n", strerror(errno));
+ migration_cleanup(pms, MIG_STAT_NONE);
+ return;
+ }
+ if (err == 0) {
+ term_printf("migration connect: connected through fd %d\n", pms->fd);
+ pms->status = MIG_STAT_CONN;
+ }
+ else {
+ term_printf("migration connect: failed to conenct (%s)\n", strerror(err));
+ return;
+ }
+
+#ifdef USE_NONBLOCKING_SOCKETS
+ qemu_set_fd_handler(pms->fd, migration_start_now, NULL, pms);
+#endif
+}
+
+
void do_migration_connect(char *arg1, char *arg2)
{
struct sockaddr_in local, remote;
@@ -402,45 +492,137 @@ void do_migration_connect(char *arg1, char *arg2)
strerror(errno));
return;
}
+
+#ifdef USE_NONBLOCKING_SOCKETS
+ socket_set_nonblock(ms.fd);
+ qemu_set_fd_handler(ms.fd, NULL, migration_connect_check, &ms);
+#endif
- if (connect(ms.fd, (struct sockaddr*)&remote, sizeof remote) < 0) {
- term_printf("migration connect: connect() failed (%s)\n",
- strerror(errno));
- migration_cleanup(&ms);
+ while (connect(ms.fd, (struct sockaddr*)&remote, sizeof remote) < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno != EINPROGRESS) {
+ term_printf("migration connect: connect() failed (%s)\n",
+ strerror(errno));
+ migration_cleanup(&ms, MIG_STAT_NONE);
+ }
return;
}
- term_printf("migration connect: connected through fd %d\n", ms.fd);
+ migration_connect_check(&ms);
}
+static void migration_disconnect(void *opaque)
+{
+ migration_state_t *pms = (migration_state_t*)opaque;
+ migration_cleanup(pms, pms->status);
+}
+
+static void migration_start_common(int online,
+ int (*migrate)(const char*, QEMUFile*),
+ int cont_on_success)
+{
+ int rc;
+ int64_t start_time, end_time;
+ const char *dummy = "online_migration";
+ migration_state_t *pms = &ms;
+
+ if (pms->status != MIG_STAT_CONN) {
+ switch (pms->status) {
+ case MIG_STAT_NONE:
+ case MIG_STAT_FAIL:
+ case MIG_STAT_SUCC:
+ case MIG_STAT_CANCEL:
+ term_printf("migration start: not connected to peer\n");
+ break;
+ case MIG_STAT_START:
+ term_printf("migration start: migration already running\n");
+ break;
+ default:
+ term_printf("migration start: UNKNOWN state %d\n", pms->status);
+ }
+ return;
+ }
+
+#ifdef USE_NONBLOCKING_SOCKETS
+ qemu_set_fd_handler(pms->fd, NULL, NULL, NULL);
+ socket_set_block(pms->fd); /* read as fast as you can */
+#endif
+
+ pms->status = MIG_STAT_START;
+ start_time = qemu_get_clock(rt_clock);
+ term_printf("\nstarting migration (at %" PRIx64 ")\n", start_time);
+ vm_stop(EXCP_INTERRUPT); /* FIXME: use EXCP_MIGRATION ? */
+ rc = migrate(dummy, &qemu_savevm_method_socket);
+ end_time = qemu_get_clock(rt_clock);
+ term_printf("migration %s (at %" PRIx64 " (%" PRIx64 "))\n",
+ (rc)?"failed":"completed", end_time, end_time - start_time);
+ if ((rc==0) && (pms->status == MIG_STAT_START))
+ pms->status = MIG_STAT_SUCC;
+ else
+ if (pms->status == MIG_STAT_START)
+ pms->status = MIG_STAT_FAIL;
+ if (((pms->status == MIG_STAT_SUCC) && cont_on_success) ||
+ ((pms->status != MIG_STAT_SUCC) && !cont_on_success)) {
+ migration_cleanup(pms, pms->status);
+ vm_start();
+ }
+ else
+ qemu_set_fd_handler(pms->fd, migration_disconnect, NULL, pms);
+}
+
+static void migration_start_src(int online)
+{
+ ms.role = WRITER;
+
+ migration_start_common(online, qemu_savevm, 0);
+}
+
+static void migration_start_dst(int online)
+{
+ ms.role = READER;
+
+ migration_start_common(online, qemu_loadvm, 1);
+}
void do_migration_getfd(int fd) { TO_BE_IMPLEMENTED; }
void do_migration_start(char *deadoralive)
{
- int rc = -1;
- const char *dummy = "online_migration";
+ migration_start_src(0);
+}
- switch (ms.role) {
- case WRITER:
- rc = qemu_savevm(dummy, &qemu_savevm_method_socket);
- break;
- case READER:
- rc = qemu_loadvm(dummy, &qemu_savevm_method_socket);
- break;
- default:
- term_printf("ERROR: unexpected role=%d\n", ms.role);
- break;
+void do_migration_cancel(void)
+{
+ migration_cleanup(&ms, MIG_STAT_CANCEL);
+}
+void do_migration_status(void){
+ term_printf("migration status: %s\n", mig_stat_str(ms.status));
+}
+void do_migration_set_rate(int min, int max, int offline)
+{
+ if ((min<0) || (max<0) || (offline<0)) {
+ term_printf("%s: positive values only please\n", __FUNCTION__);
+ return;
}
- term_printf("migration %s\n", (rc)?"failed":"completed");
+ ms.bw.min = min;
+ ms.bw.max = max;
+ ms.bw.offline = offline;
}
-void do_migration_cancel(void)
+void do_migration_set_total_time(int seconds)
+{
+ if (seconds<0){
+ term_printf("%s: positive values only please\n", __FUNCTION__);
+ return;
+ }
+ ms.bw.seconds = seconds;
+}
+void do_migration_show(void)
{
- migration_cleanup(&ms);
+ term_printf("%8s %8s %8s %8s\n%8d %8d %8d %8d\n",
+ "min", "max", "offline", "seconds",
+ ms.bw.min, ms.bw.max, ms.bw.offline, ms.bw.seconds);
}
-void do_migration_status(void){ TO_BE_IMPLEMENTED; }
-void do_migration_set(char *fmt, ...){ TO_BE_IMPLEMENTED; }
-void do_migration_show(void){ TO_BE_IMPLEMENTED; }
@@ -545,7 +727,8 @@ void do_migration_getfd(int fd) { TO_BE_IMPLEMENTED; }
void do_migration_start(char *deadoralive) { TO_BE_IMPLEMENTED; }
void do_migration_cancel(void){ TO_BE_IMPLEMENTED; }
void do_migration_status(void){ TO_BE_IMPLEMENTED; }
-void do_migration_set(char *fmt, ...){ TO_BE_IMPLEMENTED; }
+void do_migration_set_rate(int min, int max, int offline) { TO_BE_IMPLEMENTED; }
+void do_migration_set_total_time(int seconds) { TO_BE_IMPLEMENTED; }
void do_migration_show(void){ TO_BE_IMPLEMENTED; }
#endif /* of CONFIG_USER_ONLY is defined */
diff --git a/migration.h b/migration.h
index c93662d0a..acdc50343 100644
--- a/migration.h
+++ b/migration.h
@@ -8,7 +8,8 @@ void do_migration_getfd(int fd);
void do_migration_start(char *deadoralive);
void do_migration_cancel(void);
void do_migration_status(void);
-void do_migration_set(char *fmt, ...);
+void do_migration_set_rate(int min, int max, int offline);
+void do_migration_set_total_time(int seconds);
void do_migration_show(void);
#endif /* QEMU_MIGRATION_H */
diff --git a/monitor.c b/monitor.c
index 285781081..1bef19ea9 100644
--- a/monitor.c
+++ b/monitor.c
@@ -60,6 +60,7 @@ static CharDriverState *monitor_hd;
static term_cmd_t term_cmds[];
static term_cmd_t info_cmds[];
static term_cmd_t migration_cmds[];
+static term_cmd_t migration_set_cmds[];
static char term_outbuf[1024];
static int term_outbuf_index;
@@ -1159,14 +1160,28 @@ static void do_stop_capture (int n)
static void do_migration(const char *subcmdline)
{
+ if (subcmdline[0] == '\0')
+ subcmdline = "help";
monitor_handle_command(migration_cmds, subcmdline);
}
-static void do_migration_help(char *name)
+static void do_migration_help(const char *name)
{
help_cmd1(migration_cmds, "migration ", name);
}
+static void do_migration_set(const char *subcmdline)
+{
+ if (subcmdline[0] == '\0')
+ subcmdline = "help";
+ monitor_handle_command(migration_set_cmds, subcmdline);
+}
+
+static void do_migration_set_help(const char *name)
+{
+ help_cmd1(migration_set_cmds, "migration set ", name);
+}
+
#ifdef HAS_AUDIO
int wav_start_capture (CaptureState *s, const char *path, int freq,
int bits, int nchannels);
@@ -1325,6 +1340,13 @@ static term_cmd_t migration_cmds[] = {
{ NULL, NULL, },
};
+static term_cmd_t migration_set_cmds[] = {
+ { "rate", "iii", do_migration_set_rate, "min max offline", "bandwidth params" },
+ { "total_time", "i", do_migration_set_total_time, "seconds", "max migration time"},
+ { "help", "s?", do_migration_set_help, "[subcommand]", "show help message"},
+ { NULL, NULL, }
+};
+
/*******************************************************************/
static const char *pch;
@@ -2417,6 +2439,7 @@ void readline_find_completion(const char *cmdline)
bdrv_iterate(block_completion_it, (void *)str);
break;
case 's':
+ case 'A':
/* XXX: more generic ? */
if (!strcmp(cmd->name, "info")) {
completion_index = strlen(str);
@@ -2428,6 +2451,11 @@ void readline_find_completion(const char *cmdline)
for(key = key_defs; key->name != NULL; key++) {
cmd_completion(str, key->name);
}
+ } else if (!strcmp(cmd->name, "migration")) {
+ completion_index = strlen(str);
+ for(cmd = migration_cmds; cmd->name != NULL; cmd++) {
+ cmd_completion(str, cmd->name);
+ }
}
break;
default:
diff --git a/qemu-kvm.c b/qemu-kvm.c
index 74557c8e9..0c7a7f289 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -73,6 +73,55 @@ static int get_msr_entry(struct kvm_msr_entry *entry, CPUState *env)
#define MSR_COUNT 5
#endif
+static void set_v8086_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
+{
+ lhs->selector = rhs->selector;
+ lhs->base = rhs->base;
+ lhs->limit = rhs->limit;
+ lhs->type = 3;
+ lhs->present = 1;
+ lhs->dpl = 3;
+ lhs->db = 0;
+ lhs->s = 1;
+ lhs->l = 0;
+ lhs->g = 0;
+ lhs->avl = 0;
+ lhs->unusable = 0;
+}
+
+static void set_seg(struct kvm_segment *lhs, const SegmentCache *rhs)
+{
+ unsigned flags = rhs->flags;
+ lhs->selector = rhs->selector;
+ lhs->base = rhs->base;
+ lhs->limit = rhs->limit;
+ lhs->type = (flags >> DESC_TYPE_SHIFT) & 15;
+ lhs->present = (flags & DESC_P_MASK) != 0;
+ lhs->dpl = rhs->selector & 3;
+ lhs->db = (flags >> DESC_B_SHIFT) & 1;
+ lhs->s = (flags & DESC_S_MASK) != 0;
+ lhs->l = (flags >> DESC_L_SHIFT) & 1;
+ lhs->g = (flags & DESC_G_MASK) != 0;
+ lhs->avl = (flags & DESC_AVL_MASK) != 0;
+ lhs->unusable = 0;
+}
+
+static void get_seg(SegmentCache *lhs, const struct kvm_segment *rhs)
+{
+ lhs->selector = rhs->selector;
+ lhs->base = rhs->base;
+ lhs->limit = rhs->limit;
+ lhs->flags =
+ (rhs->type << DESC_TYPE_SHIFT)
+ | (rhs->present * DESC_P_MASK)
+ | (rhs->dpl << DESC_DPL_SHIFT)
+ | (rhs->db << DESC_B_SHIFT)
+ | (rhs->s * DESC_S_MASK)
+ | (rhs->l << DESC_L_SHIFT)
+ | (rhs->g * DESC_G_MASK)
+ | (rhs->avl * DESC_AVL_MASK);
+}
+
static void load_regs(CPUState *env)
{
struct kvm_regs regs;
@@ -110,56 +159,20 @@ static void load_regs(CPUState *env)
memcpy(sregs.interrupt_bitmap, env->kvm_interrupt_bitmap, sizeof(sregs.interrupt_bitmap));
-#define set_seg(var, seg, default_s, default_type) \
- do { \
- unsigned flags = env->seg.flags; \
- unsigned valid = flags & ~DESC_P_MASK; \
- sregs.var.selector = env->seg.selector; \
- sregs.var.base = env->seg.base; \
- sregs.var.limit = env->seg.limit; \
- sregs.var.type = valid ? (flags >> DESC_TYPE_SHIFT) & 15 : default_type; \
- sregs.var.present = valid ? (flags & DESC_P_MASK) != 0 : 1; \
- sregs.var.dpl = env->seg.selector & 3; \
- sregs.var.db = valid ? (flags >> DESC_B_SHIFT) & 1 : 0; \
- sregs.var.s = valid ? (flags & DESC_S_MASK) != 0 : default_s; \
- sregs.var.l = valid ? (flags >> DESC_L_SHIFT) & 1 : 0; \
- sregs.var.g = valid ? (flags & DESC_G_MASK) != 0 : 0; \
- sregs.var.avl = (flags & DESC_AVL_MASK) != 0; \
- sregs.var.unusable = 0; \
- } while (0)
-
-
-#define set_v8086_seg(var, seg) \
- do { \
- sregs.var.selector = env->seg.selector; \
- sregs.var.base = env->seg.base; \
- sregs.var.limit = env->seg.limit; \
- sregs.var.type = 3; \
- sregs.var.present = 1; \
- sregs.var.dpl = 3; \
- sregs.var.db = 0; \
- sregs.var.s = 1; \
- sregs.var.l = 0; \
- sregs.var.g = 0; \
- sregs.var.avl = 0; \
- sregs.var.unusable = 0; \
- } while (0)
-
-
if ((env->eflags & VM_MASK)) {
- set_v8086_seg(cs, segs[R_CS]);
- set_v8086_seg(ds, segs[R_DS]);
- set_v8086_seg(es, segs[R_ES]);
- set_v8086_seg(fs, segs[R_FS]);
- set_v8086_seg(gs, segs[R_GS]);
- set_v8086_seg(ss, segs[R_SS]);
+ set_v8086_seg(&sregs.cs, &env->segs[R_CS]);
+ set_v8086_seg(&sregs.ds, &env->segs[R_DS]);
+ set_v8086_seg(&sregs.es, &env->segs[R_ES]);
+ set_v8086_seg(&sregs.fs, &env->segs[R_FS]);
+ set_v8086_seg(&sregs.gs, &env->segs[R_GS]);
+ set_v8086_seg(&sregs.ss, &env->segs[R_SS]);
} else {
- set_seg(cs, segs[R_CS], 1, 11);
- set_seg(ds, segs[R_DS], 1, 3);
- set_seg(es, segs[R_ES], 1, 3);
- set_seg(fs, segs[R_FS], 1, 3);
- set_seg(gs, segs[R_GS], 1, 3);
- set_seg(ss, segs[R_SS], 1, 3);
+ set_seg(&sregs.cs, &env->segs[R_CS]);
+ set_seg(&sregs.ds, &env->segs[R_DS]);
+ set_seg(&sregs.es, &env->segs[R_ES]);
+ set_seg(&sregs.fs, &env->segs[R_FS]);
+ set_seg(&sregs.gs, &env->segs[R_GS]);
+ set_seg(&sregs.ss, &env->segs[R_SS]);
if (env->cr[0] & CR0_PE_MASK) {
/* force ss cpl to cs cpl */
@@ -169,8 +182,8 @@ static void load_regs(CPUState *env)
}
}
- set_seg(tr, tr, 0, 3);
- set_seg(ldt, ldt, 0, 2);
+ set_seg(&sregs.tr, &env->tr);
+ set_seg(&sregs.ldt, &env->ldt);
sregs.idt.limit = env->idt.limit;
sregs.idt.base = env->idt.base;
@@ -241,29 +254,15 @@ static void save_regs(CPUState *env)
memcpy(env->kvm_interrupt_bitmap, sregs.interrupt_bitmap, sizeof(env->kvm_interrupt_bitmap));
-#define get_seg(var, seg) \
- env->seg.selector = sregs.var.selector; \
- env->seg.base = sregs.var.base; \
- env->seg.limit = sregs.var.limit ; \
- env->seg.flags = \
- (sregs.var.type << DESC_TYPE_SHIFT) \
- | (sregs.var.present * DESC_P_MASK) \
- | (sregs.var.dpl << DESC_DPL_SHIFT) \
- | (sregs.var.db << DESC_B_SHIFT) \
- | (sregs.var.s * DESC_S_MASK) \
- | (sregs.var.l << DESC_L_SHIFT) \
- | (sregs.var.g * DESC_G_MASK) \
- | (sregs.var.avl * DESC_AVL_MASK)
-
- get_seg(cs, segs[R_CS]);
- get_seg(ds, segs[R_DS]);
- get_seg(es, segs[R_ES]);
- get_seg(fs, segs[R_FS]);
- get_seg(gs, segs[R_GS]);
- get_seg(ss, segs[R_SS]);
-
- get_seg(tr, tr);
- get_seg(ldt, ldt);
+ get_seg(&env->segs[R_CS], &sregs.cs);
+ get_seg(&env->segs[R_DS], &sregs.ds);
+ get_seg(&env->segs[R_ES], &sregs.es);
+ get_seg(&env->segs[R_FS], &sregs.fs);
+ get_seg(&env->segs[R_GS], &sregs.gs);
+ get_seg(&env->segs[R_SS], &sregs.ss);
+
+ get_seg(&env->tr, &sregs.tr);
+ get_seg(&env->ldt, &sregs.ldt);
env->idt.limit = sregs.idt.limit;
env->idt.base = sregs.idt.base;
diff --git a/vl.c b/vl.c
index 5f8bb1de7..0167158a9 100644
--- a/vl.c
+++ b/vl.c
@@ -5114,6 +5114,9 @@ void main_loop_wait(int timeout)
if (FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
}
+ }
+ for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
+ ioh_next = ioh->next;
if (FD_ISSET(ioh->fd, &wfds)) {
ioh->fd_write(ioh->opaque);
}
@@ -6356,6 +6359,9 @@ int main(int argc, char **argv)
if (start_emulation) {
vm_start();
}
+ else {
+ console_select(1); /* focus on monitor */
+ }
}
main_loop();
quit_timers();
diff --git a/vl.h b/vl.h
index 9f29ac472..3b90138ce 100644
--- a/vl.h
+++ b/vl.h
@@ -1031,6 +1031,10 @@ int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
typedef struct ADBDevice ADBDevice;
+/* hypercall.c */
+
+void pci_hypercall_init(PCIBus *bus);
+
/* buf = NULL means polling */
typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out,
const uint8_t *buf, int len);