Compare commits
70 Commits
v8.0.4
...
opensuse-5
Author | SHA1 | Date | |
---|---|---|---|
|
23d8d383d8 | ||
|
8ff872c114 | ||
|
13a41fa935 | ||
|
70c18d0a82 | ||
|
f7e30ef8f3 | ||
|
6847c72027 | ||
|
b9163e86c4 | ||
|
77259efaab | ||
|
dac1f64f31 | ||
|
4b7a9dc430 | ||
|
089350378c | ||
|
d86e4bcc8b | ||
|
da51c128b3 | ||
|
7b9e9c5fec | ||
|
59a49f5f5d | ||
|
b5e1011e0b | ||
|
42a210567d | ||
|
86930f4f72 | ||
|
9d19d8c859 | ||
|
07c3713d1f | ||
|
b7b6e5b2c6 | ||
|
1220ebe1bc | ||
|
04fd2a7937 | ||
|
a3a6927bfb | ||
|
b64c5ed35c | ||
|
099b4d279b | ||
|
24277a231c | ||
|
3b18a6202e | ||
|
11982619f7 | ||
42d60ec13f | |||
1d75f7c32f | |||
|
f85c9f74a2 | ||
|
d9151bbc5b | ||
|
bf571985ab | ||
|
eba7da0e36 | ||
|
229d458f99 | ||
|
381ff55ba3 | ||
|
bad1338a33 | ||
|
6da0aa8802 | ||
|
bd7618c685 | ||
|
b630481553 | ||
|
8e43d6e41d | ||
|
3168739f0e | ||
|
5ce821c0f1 | ||
|
25e0a4e36f | ||
|
8acaf926b4 | ||
|
9a2fb6cce8 | ||
|
5247caee35 | ||
|
7fac5bfd72 | ||
|
9cf4f0dfff | ||
|
7c1c89c71e | ||
|
70dad9e0e5 | ||
|
a1c9693ce8 | ||
|
fbc4cfa54d | ||
|
ee9cd5822e | ||
|
2df4739ae3 | ||
|
acad7ff7b0 | ||
|
5d6346459e | ||
|
b57ff722be | ||
|
d38d57d345 | ||
|
f2a05e7ce2 | ||
|
d993207e99 | ||
|
99f3637a06 | ||
|
5d1dd43e97 | ||
|
5f160c6939 | ||
|
7c902d9d02 | ||
|
d33a1765fc | ||
|
7aa5e46fa1 | ||
|
3c133f4c02 | ||
|
8e0e13bc39 |
@@ -396,6 +396,8 @@ F: target/s390x/machine.c
|
||||
F: target/s390x/sigp.c
|
||||
F: target/s390x/cpu_features*.[ch]
|
||||
F: target/s390x/cpu_models.[ch]
|
||||
F: hw/s390x/pv.c
|
||||
F: include/hw/s390x/pv.h
|
||||
F: hw/intc/s390_flic.c
|
||||
F: hw/intc/s390_flic_kvm.c
|
||||
F: include/hw/s390x/s390_flic.h
|
||||
|
4
Makefile
4
Makefile
@@ -619,7 +619,7 @@ fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal
|
||||
|
||||
scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(authz-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
|
||||
ifdef CONFIG_MPATH
|
||||
scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmultipath -lmpathpersist
|
||||
scsi/qemu-pr-helper$(EXESUF): LIBS += -ludev -lmpathpersist -lmultipath
|
||||
endif
|
||||
|
||||
qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
|
||||
@@ -974,6 +974,7 @@ ifneq ($(DESCS),)
|
||||
"$(DESTDIR)$(qemu_datadir)/firmware/$$x"; \
|
||||
done
|
||||
endif
|
||||
ifneq ($(or $(CONFIG_GTK),$(CONFIG_SDL)),)
|
||||
for s in $(ICON_SIZES); do \
|
||||
mkdir -p "$(DESTDIR)$(qemu_icondir)/hicolor/$${s}/apps"; \
|
||||
$(INSTALL_DATA) $(SRC_PATH)/ui/icons/qemu_$${s}.png \
|
||||
@@ -988,6 +989,7 @@ endif
|
||||
mkdir -p "$(DESTDIR)$(qemu_desktopdir)"
|
||||
$(INSTALL_DATA) $(SRC_PATH)/ui/qemu.desktop \
|
||||
"$(DESTDIR)$(qemu_desktopdir)/qemu.desktop"
|
||||
endif
|
||||
ifdef CONFIG_GTK
|
||||
$(MAKE) -C po $@
|
||||
endif
|
||||
|
@@ -39,6 +39,10 @@ endif
|
||||
PROGS=$(QEMU_PROG) $(QEMU_PROGW)
|
||||
STPFILES=
|
||||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
PROGS+=$(QEMU_PROG)-binfmt
|
||||
endif
|
||||
|
||||
config-target.h: config-target.h-timestamp
|
||||
config-target.h-timestamp: config-target.mak
|
||||
|
||||
@@ -134,6 +138,8 @@ QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) \
|
||||
obj-y += linux-user/
|
||||
obj-y += gdbstub.o thunk.o
|
||||
|
||||
obj-binfmt-y += linux-user/
|
||||
|
||||
endif #CONFIG_LINUX_USER
|
||||
|
||||
#########################################################
|
||||
@@ -176,7 +182,11 @@ generated-files-y += config-devices.h
|
||||
|
||||
endif # CONFIG_SOFTMMU
|
||||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
dummy := $(call unnest-vars,,obj-y obj-binfmt-y)
|
||||
else
|
||||
dummy := $(call unnest-vars,,obj-y)
|
||||
endif
|
||||
all-obj-y := $(obj-y)
|
||||
|
||||
include $(SRC_PATH)/Makefile.objs
|
||||
@@ -211,6 +221,9 @@ ifdef CONFIG_DARWIN
|
||||
$(call quiet-command,SetFile -a C $@,"SETFILE","$(TARGET_DIR)$@")
|
||||
endif
|
||||
|
||||
$(QEMU_PROG)-binfmt: $(obj-binfmt-y)
|
||||
$(call LINK,$^)
|
||||
|
||||
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
|
||||
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES),"GEN","$(TARGET_DIR)$@")
|
||||
|
||||
|
@@ -649,7 +649,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
|
||||
total += isamp;
|
||||
}
|
||||
|
||||
if (!hw->pcm_ops->volume_in) {
|
||||
if (hw->pcm_ops && !hw->pcm_ops->volume_in) {
|
||||
mixeng_volume (sw->buf, ret, &sw->vol);
|
||||
}
|
||||
|
||||
@@ -736,7 +736,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
||||
if (swlim) {
|
||||
sw->conv (sw->buf, buf, swlim);
|
||||
|
||||
if (!sw->hw->pcm_ops->volume_out) {
|
||||
if (sw->hw->pcm_ops && !sw->hw->pcm_ops->volume_out) {
|
||||
mixeng_volume (sw->buf, swlim, &sw->vol);
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#define HW_POISON_H /* avoid poison since we patch against rules it "enforces" */
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define HW_POISON_H /* avoid poison since we patch against rules it "enforces" */
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
@@ -191,6 +192,17 @@ static void mux_chr_accept_input(Chardev *chr)
|
||||
be->chr_read(be->opaque,
|
||||
&d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
|
||||
}
|
||||
|
||||
#if defined(TARGET_S390X)
|
||||
/*
|
||||
* We're still not able to sync producer and consumer, so let's wait a bit
|
||||
* and try again by then.
|
||||
*/
|
||||
if (d->prod[m] != d->cons[m]) {
|
||||
qemu_mod_timer(d->accept_timer, qemu_get_clock_ns(vm_clock)
|
||||
+ (int64_t)100000);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int mux_chr_can_read(void *opaque)
|
||||
@@ -325,6 +337,10 @@ static void qemu_chr_open_mux(Chardev *chr,
|
||||
}
|
||||
|
||||
d->focus = -1;
|
||||
#if defined(TARGET_S390X)
|
||||
d->accept_timer = qemu_new_timer_ns(vm_clock,
|
||||
(QEMUTimerCB *)mux_chr_accept_input, chr);
|
||||
#endif
|
||||
/* only default to opened state if we've realized the initial
|
||||
* set of muxes
|
||||
*/
|
||||
|
@@ -22,6 +22,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define HW_POISON_H /* avoid poison since we patch against rules it "enforces" */
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
6
configure
vendored
6
configure
vendored
@@ -3961,7 +3961,7 @@ int main(void) {
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "-ludev -lmultipath -lmpathpersist" ; then
|
||||
if compile_prog "" "-ludev -lmpathpersist -lmultipath" ; then
|
||||
mpathpersist=yes
|
||||
mpathpersist_new_api=yes
|
||||
else
|
||||
@@ -6495,7 +6495,7 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \
|
||||
fi
|
||||
|
||||
# Only build s390-ccw bios if we're on s390x and the compiler has -march=z900
|
||||
if test "$cpu" = "s390x" ; then
|
||||
if test "$cpu" = "s390x" && test "$softmmu" = yes ; then
|
||||
write_c_skeleton
|
||||
if compile_prog "-march=z900" ""; then
|
||||
roms="$roms s390-ccw"
|
||||
@@ -6939,7 +6939,7 @@ fi
|
||||
if test "$modules" = "yes"; then
|
||||
# $shacmd can generate a hash started with digit, which the compiler doesn't
|
||||
# like as an symbol. So prefix it with an underscore
|
||||
echo "CONFIG_STAMP=_$( (echo $qemu_version; echo $pkgversion; cat $0) | $shacmd - | cut -f1 -d\ )" >> $config_host_mak
|
||||
echo "CONFIG_STAMP=_$( (echo $qemu_version; cat $0) | $shacmd - | cut -f1 -d\ )" >> $config_host_mak
|
||||
echo "CONFIG_MODULES=y" >> $config_host_mak
|
||||
fi
|
||||
if test "$module_upgrades" = "yes"; then
|
||||
|
@@ -7,6 +7,7 @@
|
||||
<body>
|
||||
<h1>QEMU @@VERSION@@ Documentation</h1>
|
||||
<ul>
|
||||
<li><a href="/usr/share/doc/packages/qemu-kvm/kvm-supported.html">SUSE Support Statements</a></li>
|
||||
<li><a href="system/index.html">System Emulation User's Guide</a></li>
|
||||
<li><a href="user/index.html">User Mode Emulation User's Guide</a></li>
|
||||
<li><a href="tools/index.html">Tools Guide</a></li>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
Specify tracing options.
|
||||
|
||||
.. option:: [enable=]PATTERN
|
||||
.. option:: -trace [enable=]PATTERN
|
||||
|
||||
Immediately enable events matching *PATTERN*
|
||||
(either event name or a globbing pattern). This option is only
|
||||
@@ -11,7 +11,7 @@ Specify tracing options.
|
||||
|
||||
Use :option:`-trace help` to print a list of names of trace points.
|
||||
|
||||
.. option:: events=FILE
|
||||
.. option:: -trace events=FILE
|
||||
|
||||
Immediately enable events listed in *FILE*.
|
||||
The file must contain one event name (as listed in the ``trace-events-all``
|
||||
@@ -19,7 +19,7 @@ Specify tracing options.
|
||||
available if QEMU has been compiled with the ``simple``, ``log`` or
|
||||
``ftrace`` tracing backend.
|
||||
|
||||
.. option:: file=FILE
|
||||
.. option:: -trace file=FILE
|
||||
|
||||
Log output traces to *FILE*.
|
||||
This option is only available if QEMU has been compiled with
|
||||
|
3
exec.c
3
exec.c
@@ -2297,11 +2297,13 @@ RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef TARGET_PPC
|
||||
if (kvm_enabled() && !kvm_has_sync_mmu()) {
|
||||
error_setg(errp,
|
||||
"host lacks kvm mmu notifiers, -mem-path unsupported");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (phys_mem_alloc != qemu_anon_ram_alloc) {
|
||||
/*
|
||||
@@ -3538,6 +3540,7 @@ void *address_space_map(AddressSpace *as,
|
||||
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
if (atomic_xchg(&bounce.in_use, true)) {
|
||||
*plen = 0;
|
||||
return NULL;
|
||||
}
|
||||
/* Avoid unbounded allocations */
|
||||
|
@@ -274,7 +274,7 @@ static bool piix4_vmstate_need_smbus(void *opaque, int version_id)
|
||||
static const VMStateDescription vmstate_acpi = {
|
||||
.name = "piix4_pm",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.minimum_version_id = 2, /* qemu-kvm */
|
||||
.post_load = vmstate_acpi_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
|
||||
|
@@ -643,6 +643,9 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
||||
int csc_bytes = (csc + 1) << d->shift;
|
||||
int cnt = d->frame_cnt >> 16;
|
||||
int size = d->frame_cnt & 0xffff;
|
||||
if (size < cnt) {
|
||||
return;
|
||||
}
|
||||
int left = ((size - cnt + 1) << 2) + d->leftover;
|
||||
int transferred = 0;
|
||||
int temp = MIN (max, MIN (left, csc_bytes));
|
||||
@@ -651,7 +654,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
||||
addr += (cnt << 2) + d->leftover;
|
||||
|
||||
if (index == ADC_CHANNEL) {
|
||||
while (temp) {
|
||||
while (temp > 0) {
|
||||
int acquired, to_copy;
|
||||
|
||||
to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
|
||||
@@ -669,7 +672,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
|
||||
else {
|
||||
SWVoiceOut *voice = s->dac_voice[index];
|
||||
|
||||
while (temp) {
|
||||
while (temp > 0) {
|
||||
int copied, to_copy;
|
||||
|
||||
to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
|
||||
|
@@ -275,6 +275,9 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
|
||||
|
||||
xen_block_set_size(blockdev);
|
||||
|
||||
if (!monitor_add_blk(conf->blk, blockdev->drive->id, errp)) {
|
||||
return;
|
||||
}
|
||||
blockdev->dataplane =
|
||||
xen_block_dataplane_create(xendev, blk, conf->logical_block_size,
|
||||
blockdev->props.iothread);
|
||||
@@ -744,6 +747,8 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
|
||||
const char *mode = qdict_get_try_str(opts, "mode");
|
||||
const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
|
||||
const char *discard_enable = qdict_get_try_str(opts, "discard-enable");
|
||||
const char *suse_diskcache_disable_flush = qdict_get_try_str(opts,
|
||||
"suse-diskcache-disable-flush");
|
||||
char *driver = NULL;
|
||||
char *filename = NULL;
|
||||
XenBlockDrive *drive = NULL;
|
||||
@@ -813,6 +818,16 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
|
||||
}
|
||||
}
|
||||
|
||||
if (suse_diskcache_disable_flush) {
|
||||
unsigned long value;
|
||||
if (!qemu_strtoul(suse_diskcache_disable_flush, NULL, 2, &value) && !!value) {
|
||||
QDict *cache_qdict = qdict_new();
|
||||
|
||||
qdict_put_bool(cache_qdict, "no-flush", true);
|
||||
qdict_put_obj(file_layer, "cache", QOBJECT(cache_qdict));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It is necessary to turn file locking off as an emulated device
|
||||
* may have already opened the same image file.
|
||||
|
@@ -285,8 +285,11 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
|
||||
if (idx <= s->vga.vram_size - size) {
|
||||
val = ldn_le_p(s->vga.vram_ptr + idx, size);
|
||||
}
|
||||
} else {
|
||||
} else if (s->regs.mm_index > MM_DATA + 3) {
|
||||
val = ati_mm_read(s, s->regs.mm_index + addr - MM_DATA, size);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ati_mm_read: mm_index too small: %u\n", s->regs.mm_index);
|
||||
}
|
||||
break;
|
||||
case BIOS_0_SCRATCH ... BUS_CNTL - 1:
|
||||
@@ -520,8 +523,11 @@ static void ati_mm_write(void *opaque, hwaddr addr,
|
||||
if (idx <= s->vga.vram_size - size) {
|
||||
stn_le_p(s->vga.vram_ptr + idx, size, data);
|
||||
}
|
||||
} else {
|
||||
} else if (s->regs.mm_index > MM_DATA + 3) {
|
||||
ati_mm_write(s, s->regs.mm_index + addr - MM_DATA, data, size);
|
||||
} else {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"ati_mm_write: mm_index too small: %u\n", s->regs.mm_index);
|
||||
}
|
||||
break;
|
||||
case BIOS_0_SCRATCH ... BUS_CNTL - 1:
|
||||
|
@@ -290,8 +290,8 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
|
||||
const char dist_prefix[] = "exynos4210-gic-alias_dist";
|
||||
char cpu_alias_name[sizeof(cpu_prefix) + 3];
|
||||
char dist_alias_name[sizeof(cpu_prefix) + 3];
|
||||
char cpu_alias_name[sizeof(cpu_prefix) + 7];
|
||||
char dist_alias_name[sizeof(cpu_prefix) + 8];
|
||||
SysBusDevice *gicbusdev;
|
||||
uint32_t n = s->num_cpu;
|
||||
uint32_t i;
|
||||
|
@@ -134,6 +134,7 @@ static void openrisc_sim_init(MachineState *machine)
|
||||
int n;
|
||||
unsigned int smp_cpus = machine->smp.cpus;
|
||||
|
||||
assert(smp_cpus >= 1 && smp_cpus <= 2);
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
cpu = OPENRISC_CPU(cpu_create(machine->cpu_type));
|
||||
if (cpu == NULL) {
|
||||
|
@@ -643,11 +643,6 @@ static SpaprCapabilities default_caps_with_cpu(SpaprMachineState *spapr,
|
||||
|
||||
caps = smc->default_caps;
|
||||
|
||||
if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_3_00,
|
||||
0, spapr->max_compat_pvr)) {
|
||||
caps.caps[SPAPR_CAP_LARGE_DECREMENTER] = SPAPR_CAP_OFF;
|
||||
}
|
||||
|
||||
if (!ppc_type_check_compat(cputype, CPU_POWERPC_LOGICAL_2_07,
|
||||
0, spapr->max_compat_pvr)) {
|
||||
caps.caps[SPAPR_CAP_HTM] = SPAPR_CAP_OFF;
|
||||
|
@@ -31,6 +31,7 @@ obj-y += tod-qemu.o
|
||||
obj-$(CONFIG_KVM) += tod-kvm.o
|
||||
obj-$(CONFIG_KVM) += s390-skeys-kvm.o
|
||||
obj-$(CONFIG_KVM) += s390-stattrib-kvm.o
|
||||
obj-$(CONFIG_KVM) += pv.o
|
||||
obj-y += s390-ccw.o
|
||||
obj-y += ap-device.o
|
||||
obj-y += ap-bridge.o
|
||||
|
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
* bootloader support
|
||||
*
|
||||
* Copyright IBM, Corp. 2012
|
||||
* Copyright IBM, Corp. 2012, 2020
|
||||
*
|
||||
* Authors:
|
||||
* Christian Borntraeger <borntraeger@de.ibm.com>
|
||||
* Janosch Frank <frankja@linux.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
|
||||
* option) any later version. See the COPYING file in the top-level directory.
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "hw/s390x/vfio-ccw.h"
|
||||
#include "hw/s390x/css.h"
|
||||
#include "hw/s390x/ebcdic.h"
|
||||
#include "hw/s390x/pv.h"
|
||||
#include "ipl.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/config-file.h"
|
||||
@@ -566,12 +568,31 @@ void s390_ipl_update_diag308(IplParameterBlock *iplb)
|
||||
{
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
|
||||
ipl->iplb = *iplb;
|
||||
ipl->iplb_valid = true;
|
||||
/*
|
||||
* The IPLB set and retrieved by subcodes 8/9 is completely
|
||||
* separate from the one managed via subcodes 5/6.
|
||||
*/
|
||||
if (iplb->pbt == S390_IPL_TYPE_PV) {
|
||||
ipl->iplb_pv = *iplb;
|
||||
ipl->iplb_valid_pv = true;
|
||||
} else {
|
||||
ipl->iplb = *iplb;
|
||||
ipl->iplb_valid = true;
|
||||
}
|
||||
ipl->netboot = is_virtio_net_device(iplb);
|
||||
update_machine_ipl_properties(iplb);
|
||||
}
|
||||
|
||||
IplParameterBlock *s390_ipl_get_iplb_pv(void)
|
||||
{
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
|
||||
if (!ipl->iplb_valid_pv) {
|
||||
return NULL;
|
||||
}
|
||||
return &ipl->iplb_pv;
|
||||
}
|
||||
|
||||
IplParameterBlock *s390_ipl_get_iplb(void)
|
||||
{
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
@@ -660,6 +681,38 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu)
|
||||
cpu_physical_memory_unmap(addr, len, 1, len);
|
||||
}
|
||||
|
||||
int s390_ipl_prepare_pv_header(void)
|
||||
{
|
||||
IplParameterBlock *ipib = s390_ipl_get_iplb_pv();
|
||||
IPLBlockPV *ipib_pv = &ipib->pv;
|
||||
void *hdr = g_malloc(ipib_pv->pv_header_len);
|
||||
int rc;
|
||||
|
||||
cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr,
|
||||
ipib_pv->pv_header_len);
|
||||
rc = s390_pv_set_sec_parms((uintptr_t)hdr,
|
||||
ipib_pv->pv_header_len);
|
||||
g_free(hdr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int s390_ipl_pv_unpack(void)
|
||||
{
|
||||
IplParameterBlock *ipib = s390_ipl_get_iplb_pv();
|
||||
IPLBlockPV *ipib_pv = &ipib->pv;
|
||||
int i, rc = 0;
|
||||
|
||||
for (i = 0; i < ipib_pv->num_comp; i++) {
|
||||
rc = s390_pv_unpack(ipib_pv->components[i].addr,
|
||||
TARGET_PAGE_ALIGN(ipib_pv->components[i].size),
|
||||
ipib_pv->components[i].tweak_pref);
|
||||
if (rc) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void s390_ipl_prepare_cpu(S390CPU *cpu)
|
||||
{
|
||||
S390IPLState *ipl = get_ipl_device();
|
||||
|
103
hw/s390x/ipl.h
103
hw/s390x/ipl.h
@@ -1,8 +1,9 @@
|
||||
/*
|
||||
* s390 IPL device
|
||||
*
|
||||
* Copyright 2015 IBM Corp.
|
||||
* Copyright 2015, 2020 IBM Corp.
|
||||
* Author(s): Zhang Fan <bjfanzh@cn.ibm.com>
|
||||
* Janosch Frank <frankja@linux.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
@@ -13,8 +14,27 @@
|
||||
#define HW_S390_IPL_H
|
||||
|
||||
#include "cpu.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/qdev-core.h"
|
||||
|
||||
struct IPLBlockPVComp {
|
||||
uint64_t tweak_pref;
|
||||
uint64_t addr;
|
||||
uint64_t size;
|
||||
} QEMU_PACKED;
|
||||
typedef struct IPLBlockPVComp IPLBlockPVComp;
|
||||
|
||||
struct IPLBlockPV {
|
||||
uint8_t reserved18[87]; /* 0x18 */
|
||||
uint8_t version; /* 0x6f */
|
||||
uint32_t reserved70; /* 0x70 */
|
||||
uint32_t num_comp; /* 0x74 */
|
||||
uint64_t pv_header_addr; /* 0x78 */
|
||||
uint64_t pv_header_len; /* 0x80 */
|
||||
struct IPLBlockPVComp components[];
|
||||
} QEMU_PACKED;
|
||||
typedef struct IPLBlockPV IPLBlockPV;
|
||||
|
||||
struct IplBlockCcw {
|
||||
uint8_t reserved0[85];
|
||||
uint8_t ssid;
|
||||
@@ -71,6 +91,7 @@ union IplParameterBlock {
|
||||
union {
|
||||
IplBlockCcw ccw;
|
||||
IplBlockFcp fcp;
|
||||
IPLBlockPV pv;
|
||||
IplBlockQemuScsi scsi;
|
||||
};
|
||||
} QEMU_PACKED;
|
||||
@@ -85,8 +106,11 @@ typedef union IplParameterBlock IplParameterBlock;
|
||||
|
||||
int s390_ipl_set_loadparm(uint8_t *loadparm);
|
||||
void s390_ipl_update_diag308(IplParameterBlock *iplb);
|
||||
int s390_ipl_prepare_pv_header(void);
|
||||
int s390_ipl_pv_unpack(void);
|
||||
void s390_ipl_prepare_cpu(S390CPU *cpu);
|
||||
IplParameterBlock *s390_ipl_get_iplb(void);
|
||||
IplParameterBlock *s390_ipl_get_iplb_pv(void);
|
||||
|
||||
enum s390_reset {
|
||||
/* default is a reset not triggered by a CPU e.g. issued by QMP */
|
||||
@@ -94,6 +118,7 @@ enum s390_reset {
|
||||
S390_RESET_REIPL,
|
||||
S390_RESET_MODIFIED_CLEAR,
|
||||
S390_RESET_LOAD_NORMAL,
|
||||
S390_RESET_PV,
|
||||
};
|
||||
void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type);
|
||||
void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type);
|
||||
@@ -133,6 +158,7 @@ struct S390IPLState {
|
||||
/*< private >*/
|
||||
DeviceState parent_obj;
|
||||
IplParameterBlock iplb;
|
||||
IplParameterBlock iplb_pv;
|
||||
QemuIplParameters qipl;
|
||||
uint64_t start_addr;
|
||||
uint64_t compat_start_addr;
|
||||
@@ -140,6 +166,7 @@ struct S390IPLState {
|
||||
uint64_t compat_bios_start_addr;
|
||||
bool enforce_bios;
|
||||
bool iplb_valid;
|
||||
bool iplb_valid_pv;
|
||||
bool netboot;
|
||||
/* reset related properties don't have to be migrated or reset */
|
||||
enum s390_reset reset_type;
|
||||
@@ -159,11 +186,29 @@ struct S390IPLState {
|
||||
typedef struct S390IPLState S390IPLState;
|
||||
QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
|
||||
|
||||
#define DIAG_308_RC_OK 0x0001
|
||||
#define DIAG_308_RC_NO_CONF 0x0102
|
||||
#define DIAG_308_RC_INVALID 0x0402
|
||||
#define DIAG_308_RC_NO_PV_CONF 0x0902
|
||||
#define DIAG_308_RC_INVAL_FOR_PV 0x0a02
|
||||
|
||||
#define DIAG308_RESET_MOD_CLR 0
|
||||
#define DIAG308_RESET_LOAD_NORM 1
|
||||
#define DIAG308_LOAD_CLEAR 3
|
||||
#define DIAG308_LOAD_NORMAL_DUMP 4
|
||||
#define DIAG308_SET 5
|
||||
#define DIAG308_STORE 6
|
||||
#define DIAG308_PV_SET 8
|
||||
#define DIAG308_PV_STORE 9
|
||||
#define DIAG308_PV_START 10
|
||||
|
||||
#define S390_IPL_TYPE_FCP 0x00
|
||||
#define S390_IPL_TYPE_CCW 0x02
|
||||
#define S390_IPL_TYPE_PV 0x05
|
||||
#define S390_IPL_TYPE_QEMU_SCSI 0xff
|
||||
|
||||
#define S390_IPLB_HEADER_LEN 8
|
||||
#define S390_IPLB_MIN_PV_LEN 148
|
||||
#define S390_IPLB_MIN_CCW_LEN 200
|
||||
#define S390_IPLB_MIN_FCP_LEN 384
|
||||
#define S390_IPLB_MIN_QEMU_SCSI_LEN 200
|
||||
@@ -173,6 +218,62 @@ static inline bool iplb_valid_len(IplParameterBlock *iplb)
|
||||
return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock);
|
||||
}
|
||||
|
||||
static inline bool ipl_valid_pv_components(IplParameterBlock *iplb)
|
||||
{
|
||||
IPLBlockPV *ipib_pv = &iplb->pv;
|
||||
int i;
|
||||
|
||||
if (ipib_pv->num_comp == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < ipib_pv->num_comp; i++) {
|
||||
/* Addr must be 4k aligned */
|
||||
if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Tweak prefix is monotonically increasing with each component */
|
||||
if (i < ipib_pv->num_comp - 1 &&
|
||||
ipib_pv->components[i].tweak_pref >=
|
||||
ipib_pv->components[i + 1].tweak_pref) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool ipl_valid_pv_header(IplParameterBlock *iplb)
|
||||
{
|
||||
IPLBlockPV *ipib_pv = &iplb->pv;
|
||||
|
||||
if (ipib_pv->pv_header_len > 2 * TARGET_PAGE_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!address_space_access_valid(&address_space_memory,
|
||||
ipib_pv->pv_header_addr,
|
||||
ipib_pv->pv_header_len,
|
||||
false,
|
||||
MEMTXATTRS_UNSPECIFIED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool iplb_valid_pv(IplParameterBlock *iplb)
|
||||
{
|
||||
if (iplb->pbt != S390_IPL_TYPE_PV ||
|
||||
be32_to_cpu(iplb->len) < S390_IPLB_MIN_PV_LEN) {
|
||||
return false;
|
||||
}
|
||||
if (!ipl_valid_pv_header(iplb)) {
|
||||
return false;
|
||||
}
|
||||
return ipl_valid_pv_components(iplb);
|
||||
}
|
||||
|
||||
static inline bool iplb_valid(IplParameterBlock *iplb)
|
||||
{
|
||||
switch (iplb->pbt) {
|
||||
|
109
hw/s390x/pv.c
Normal file
109
hw/s390x/pv.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Protected Virtualization functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
* Author(s):
|
||||
* Janosch Frank <frankja@linux.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/s390x/ipl.h"
|
||||
#include "hw/s390x/pv.h"
|
||||
|
||||
static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data)
|
||||
{
|
||||
struct kvm_pv_cmd pv_cmd = {
|
||||
.cmd = cmd,
|
||||
.data = (uint64_t)data,
|
||||
};
|
||||
int rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd);
|
||||
|
||||
if (rc) {
|
||||
error_report("KVM PV command %d (%s) failed: header rc %x rrc %x "
|
||||
"IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc,
|
||||
rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* This macro lets us pass the command as a string to the function so
|
||||
* we can print it on an error.
|
||||
*/
|
||||
#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data);
|
||||
#define s390_pv_cmd_exit(cmd, data) \
|
||||
{ \
|
||||
int rc; \
|
||||
\
|
||||
rc = __s390_pv_cmd(cmd, #cmd, data);\
|
||||
if (rc) { \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
int s390_pv_vm_enable(void)
|
||||
{
|
||||
return s390_pv_cmd(KVM_PV_ENABLE, NULL);
|
||||
}
|
||||
|
||||
void s390_pv_vm_disable(void)
|
||||
{
|
||||
s390_pv_cmd_exit(KVM_PV_DISABLE, NULL);
|
||||
}
|
||||
|
||||
int s390_pv_set_sec_parms(uint64_t origin, uint64_t length)
|
||||
{
|
||||
struct kvm_s390_pv_sec_parm args = {
|
||||
.origin = origin,
|
||||
.length = length,
|
||||
};
|
||||
|
||||
return s390_pv_cmd(KVM_PV_VM_SET_SEC_PARMS, &args);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called for each component in the SE type IPL parameter block 0.
|
||||
*/
|
||||
int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak)
|
||||
{
|
||||
struct kvm_s390_pv_unp args = {
|
||||
.addr = addr,
|
||||
.size = size,
|
||||
.tweak = tweak,
|
||||
};
|
||||
|
||||
return s390_pv_cmd(KVM_PV_VM_UNPACK, &args);
|
||||
}
|
||||
|
||||
void s390_pv_perf_clear_reset(void)
|
||||
{
|
||||
s390_pv_cmd_exit(KVM_PV_VM_PREP_RESET, NULL);
|
||||
}
|
||||
|
||||
int s390_pv_verify(void)
|
||||
{
|
||||
return s390_pv_cmd(KVM_PV_VM_VERIFY, NULL);
|
||||
}
|
||||
|
||||
void s390_pv_unshare(void)
|
||||
{
|
||||
s390_pv_cmd_exit(KVM_PV_VM_UNSHARE_ALL, NULL);
|
||||
}
|
||||
|
||||
void s390_pv_inject_reset_error(CPUState *cs)
|
||||
{
|
||||
int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4;
|
||||
CPUS390XState *env = &S390_CPU(cs)->env;
|
||||
|
||||
/* Report that we are unable to enter protected mode */
|
||||
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
|
||||
}
|
@@ -1,9 +1,10 @@
|
||||
/*
|
||||
* virtio ccw machine
|
||||
*
|
||||
* Copyright 2012 IBM Corp.
|
||||
* Copyright 2012, 2020 IBM Corp.
|
||||
* Copyright (c) 2009 Alexander Graf <agraf@suse.de>
|
||||
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
* Janosch Frank <frankja@linux.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
@@ -42,6 +43,11 @@
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/s390x/tod.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/balloon.h"
|
||||
#include "hw/s390x/pv.h"
|
||||
#include "migration/blocker.h"
|
||||
|
||||
static Error *pv_mig_blocker;
|
||||
|
||||
S390CPU *s390_cpu_addr2state(uint16_t cpu_addr)
|
||||
{
|
||||
@@ -317,10 +323,94 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
|
||||
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
|
||||
}
|
||||
|
||||
static void s390_machine_unprotect(S390CcwMachineState *ms)
|
||||
{
|
||||
s390_pv_vm_disable();
|
||||
ms->pv = false;
|
||||
migrate_del_blocker(pv_mig_blocker);
|
||||
error_free_or_abort(&pv_mig_blocker);
|
||||
qemu_balloon_inhibit(false);
|
||||
}
|
||||
|
||||
static int s390_machine_protect(S390CcwMachineState *ms)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Ballooning on protected VMs needs support in the guest for
|
||||
* sharing and unsharing balloon pages. Block ballooning for
|
||||
* now, until we have a solution to make at least Linux guests
|
||||
* either support it or fail gracefully.
|
||||
*/
|
||||
qemu_balloon_inhibit(true);
|
||||
error_setg(&pv_mig_blocker,
|
||||
"protected VMs are currently not migrateable.");
|
||||
rc = migrate_add_blocker(pv_mig_blocker, &local_err);
|
||||
if (rc) {
|
||||
qemu_balloon_inhibit(false);
|
||||
error_report_err(local_err);
|
||||
error_free_or_abort(&pv_mig_blocker);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Create SE VM */
|
||||
rc = s390_pv_vm_enable();
|
||||
if (rc) {
|
||||
qemu_balloon_inhibit(false);
|
||||
error_report_err(local_err);
|
||||
migrate_del_blocker(pv_mig_blocker);
|
||||
error_free_or_abort(&pv_mig_blocker);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ms->pv = true;
|
||||
|
||||
/* Set SE header and unpack */
|
||||
rc = s390_ipl_prepare_pv_header();
|
||||
if (rc) {
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Decrypt image */
|
||||
rc = s390_ipl_pv_unpack();
|
||||
if (rc) {
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* Verify integrity */
|
||||
rc = s390_pv_verify();
|
||||
if (rc) {
|
||||
goto out_err;
|
||||
}
|
||||
return rc;
|
||||
|
||||
out_err:
|
||||
s390_machine_unprotect(ms);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void s390_pv_prepare_reset(S390CcwMachineState *ms)
|
||||
{
|
||||
CPUState *cs;
|
||||
|
||||
if (!s390_is_pv()) {
|
||||
return;
|
||||
}
|
||||
/* Unsharing requires all cpus to be stopped */
|
||||
CPU_FOREACH(cs) {
|
||||
s390_cpu_set_state(S390_CPU_STATE_STOPPED, S390_CPU(cs));
|
||||
}
|
||||
s390_pv_unshare();
|
||||
s390_pv_perf_clear_reset();
|
||||
}
|
||||
|
||||
static void s390_machine_reset(MachineState *machine)
|
||||
{
|
||||
S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
|
||||
enum s390_reset reset_type;
|
||||
CPUState *cs, *t;
|
||||
S390CPU *cpu;
|
||||
|
||||
/* get the reset parameters, reset them once done */
|
||||
s390_ipl_get_reset_request(&cs, &reset_type);
|
||||
@@ -328,9 +418,15 @@ static void s390_machine_reset(MachineState *machine)
|
||||
/* all CPUs are paused and synchronized at this point */
|
||||
s390_cmma_reset();
|
||||
|
||||
cpu = S390_CPU(cs);
|
||||
|
||||
switch (reset_type) {
|
||||
case S390_RESET_EXTERNAL:
|
||||
case S390_RESET_REIPL:
|
||||
if (s390_is_pv()) {
|
||||
s390_machine_unprotect(ms);
|
||||
}
|
||||
|
||||
qemu_devices_reset();
|
||||
s390_crypto_reset();
|
||||
|
||||
@@ -338,22 +434,56 @@ static void s390_machine_reset(MachineState *machine)
|
||||
run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL);
|
||||
break;
|
||||
case S390_RESET_MODIFIED_CLEAR:
|
||||
/*
|
||||
* Susbsystem reset needs to be done before we unshare memory
|
||||
* and lose access to VIRTIO structures in guest memory.
|
||||
*/
|
||||
subsystem_reset();
|
||||
s390_crypto_reset();
|
||||
s390_pv_prepare_reset(ms);
|
||||
CPU_FOREACH(t) {
|
||||
run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
|
||||
}
|
||||
subsystem_reset();
|
||||
s390_crypto_reset();
|
||||
run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
|
||||
break;
|
||||
case S390_RESET_LOAD_NORMAL:
|
||||
/*
|
||||
* Susbsystem reset needs to be done before we unshare memory
|
||||
* and lose access to VIRTIO structures in guest memory.
|
||||
*/
|
||||
subsystem_reset();
|
||||
s390_pv_prepare_reset(ms);
|
||||
CPU_FOREACH(t) {
|
||||
if (t == cs) {
|
||||
continue;
|
||||
}
|
||||
run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL);
|
||||
}
|
||||
subsystem_reset();
|
||||
run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL);
|
||||
run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
|
||||
break;
|
||||
case S390_RESET_PV: /* Subcode 10 */
|
||||
subsystem_reset();
|
||||
s390_crypto_reset();
|
||||
|
||||
CPU_FOREACH(t) {
|
||||
if (t == cs) {
|
||||
continue;
|
||||
}
|
||||
run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL);
|
||||
}
|
||||
run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL);
|
||||
|
||||
if (s390_machine_protect(ms)) {
|
||||
s390_pv_inject_reset_error(cs);
|
||||
/*
|
||||
* Continue after the diag308 so the guest knows something
|
||||
* went wrong.
|
||||
*/
|
||||
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
|
||||
return;
|
||||
}
|
||||
|
||||
run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL);
|
||||
break;
|
||||
default:
|
||||
|
@@ -33,6 +33,22 @@ static inline SCLPDevice *get_sclp_device(void)
|
||||
return sclp;
|
||||
}
|
||||
|
||||
static inline bool sclp_command_code_valid(uint32_t code)
|
||||
{
|
||||
switch (code & SCLP_CMD_CODE_MASK) {
|
||||
case SCLP_CMDW_READ_SCP_INFO:
|
||||
case SCLP_CMDW_READ_SCP_INFO_FORCED:
|
||||
case SCLP_CMDW_READ_CPU_INFO:
|
||||
case SCLP_CMDW_CONFIGURE_IOA:
|
||||
case SCLP_CMDW_DECONFIGURE_IOA:
|
||||
case SCLP_CMD_READ_EVENT_DATA:
|
||||
case SCLP_CMD_WRITE_EVENT_DATA:
|
||||
case SCLP_CMD_WRITE_EVENT_MASK:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count)
|
||||
{
|
||||
MachineState *ms = MACHINE(qdev_get_machine());
|
||||
@@ -193,6 +209,34 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We only need the address to have something valid for the
|
||||
* service_interrupt call.
|
||||
*/
|
||||
#define SCLP_PV_DUMMY_ADDR 0x4000
|
||||
int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
|
||||
uint32_t code)
|
||||
{
|
||||
SCLPDevice *sclp = get_sclp_device();
|
||||
SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
|
||||
SCCB work_sccb;
|
||||
hwaddr sccb_len = sizeof(SCCB);
|
||||
|
||||
s390_cpu_pv_mem_read(env_archcpu(env), 0, &work_sccb, sccb_len);
|
||||
|
||||
if (!sclp_command_code_valid(code)) {
|
||||
work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
|
||||
goto out_write;
|
||||
}
|
||||
|
||||
sclp_c->execute(sclp, &work_sccb, code);
|
||||
out_write:
|
||||
s390_cpu_pv_mem_write(env_archcpu(env), 0, &work_sccb,
|
||||
be16_to_cpu(work_sccb.h.length));
|
||||
sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
|
||||
{
|
||||
SCLPDevice *sclp = get_sclp_device();
|
||||
@@ -225,17 +269,7 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
|
||||
return -PGM_SPECIFICATION;
|
||||
}
|
||||
|
||||
switch (code & SCLP_CMD_CODE_MASK) {
|
||||
case SCLP_CMDW_READ_SCP_INFO:
|
||||
case SCLP_CMDW_READ_SCP_INFO_FORCED:
|
||||
case SCLP_CMDW_READ_CPU_INFO:
|
||||
case SCLP_CMDW_CONFIGURE_IOA:
|
||||
case SCLP_CMDW_DECONFIGURE_IOA:
|
||||
case SCLP_CMD_READ_EVENT_DATA:
|
||||
case SCLP_CMD_WRITE_EVENT_DATA:
|
||||
case SCLP_CMD_WRITE_EVENT_MASK:
|
||||
break;
|
||||
default:
|
||||
if (!sclp_command_code_valid(code)) {
|
||||
work_sccb.h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
|
||||
goto out_write;
|
||||
}
|
||||
|
@@ -112,7 +112,7 @@ typedef struct MegasasState {
|
||||
uint64_t reply_queue_pa;
|
||||
void *reply_queue;
|
||||
int reply_queue_len;
|
||||
int reply_queue_head;
|
||||
uint16_t reply_queue_head;
|
||||
int reply_queue_tail;
|
||||
uint64_t consumer_pa;
|
||||
uint64_t producer_pa;
|
||||
@@ -445,7 +445,7 @@ static MegasasCmd *megasas_lookup_frame(MegasasState *s,
|
||||
|
||||
index = s->reply_queue_head;
|
||||
|
||||
while (num < s->fw_cmds) {
|
||||
while (num < s->fw_cmds && index < MEGASAS_MAX_FRAMES) {
|
||||
if (s->frames[index].pa && s->frames[index].pa == frame) {
|
||||
cmd = &s->frames[index];
|
||||
break;
|
||||
|
@@ -963,6 +963,7 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
struct smbios_structure_header *header;
|
||||
int size;
|
||||
struct smbios_table *table; /* legacy mode only */
|
||||
uint8_t *dbl_nulls, *orig_end;
|
||||
|
||||
qemu_opts_validate(opts, qemu_smbios_file_opts, &err);
|
||||
if (err) {
|
||||
@@ -977,11 +978,21 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: standard double '\0' terminator expected, per smbios spec.
|
||||
* (except in legacy mode, where the second '\0' is implicit and
|
||||
* will be inserted by the BIOS).
|
||||
* NOTE: standard double '\0' terminator expected, per smbios spec,
|
||||
* unless the data is formatted for legacy mode, which is used by
|
||||
* pc-i440fx-2.0 and earlier machine types. Legacy mode structures
|
||||
* without strings have no '\0' terminators, and those with strings
|
||||
* also don't have an additional '\0' terminator at the end of the
|
||||
* final string '\0' terminator. The BIOS will add the '\0' terminators
|
||||
* to comply with the smbios spec.
|
||||
* For greater compatibility, regardless of the machine type used,
|
||||
* either format is accepted.
|
||||
*/
|
||||
smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
|
||||
smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size + 2);
|
||||
orig_end = smbios_tables + smbios_tables_len + size;
|
||||
/* add extra null bytes to end in case of legacy file data */
|
||||
*orig_end = '\0';
|
||||
*(orig_end + 1) = '\0';
|
||||
header = (struct smbios_structure_header *)(smbios_tables +
|
||||
smbios_tables_len);
|
||||
|
||||
@@ -996,6 +1007,19 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
header->type);
|
||||
return;
|
||||
}
|
||||
for (dbl_nulls = smbios_tables + smbios_tables_len + header->length;
|
||||
dbl_nulls + 2 <= orig_end; dbl_nulls++) {
|
||||
if (*dbl_nulls == '\0' && *(dbl_nulls + 1) == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dbl_nulls + 2 < orig_end) {
|
||||
error_setg(errp, "SMBIOS file data malformed");
|
||||
return;
|
||||
}
|
||||
/* increase size by how many extra nulls were actually needed */
|
||||
size += dbl_nulls + 2 - orig_end;
|
||||
smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
|
||||
set_bit(header->type, have_binfile_bitmap);
|
||||
|
||||
if (header->type == 4) {
|
||||
@@ -1016,6 +1040,17 @@ void smbios_entry_add(QemuOpts *opts, Error **errp)
|
||||
* delete the one we don't need from smbios_set_defaults(),
|
||||
* once we know which machine version has been requested.
|
||||
*/
|
||||
if (dbl_nulls + 2 == orig_end) {
|
||||
/* chop off nulls to get legacy format */
|
||||
if (header->length + 2 == size) {
|
||||
size -= 2;
|
||||
} else {
|
||||
size -= 1;
|
||||
}
|
||||
} else {
|
||||
/* undo conversion from legacy format to per-spec format */
|
||||
size -= dbl_nulls + 2 - orig_end;
|
||||
}
|
||||
if (!smbios_entries) {
|
||||
smbios_entries_len = sizeof(uint16_t);
|
||||
smbios_entries = g_malloc0(smbios_entries_len);
|
||||
|
@@ -224,6 +224,12 @@ static int pit_dispatch_post_load(void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_qemu_kvm(void *opaque, int version_id)
|
||||
{
|
||||
/* HACK: We ignore incoming migration from upstream qemu */
|
||||
return version_id < 3;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pit_common = {
|
||||
.name = "i8254",
|
||||
.version_id = 3,
|
||||
@@ -231,6 +237,7 @@ static const VMStateDescription vmstate_pit_common = {
|
||||
.pre_save = pit_dispatch_pre_save,
|
||||
.post_load = pit_dispatch_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UNUSED_TEST(is_qemu_kvm, 4),
|
||||
VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3),
|
||||
VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2,
|
||||
vmstate_pit_channel, PITChannelState),
|
||||
|
@@ -1722,9 +1722,22 @@ static void usb_mtp_write_metadata(MTPState *s, uint64_t dlen)
|
||||
assert(!s->write_pending);
|
||||
assert(p != NULL);
|
||||
|
||||
/*
|
||||
* We are about to access a packed struct. We are confident that the pointer
|
||||
* address won't be unaligned, so we ignore GCC warnings.
|
||||
*/
|
||||
#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && QEMU_GNUC_PREREQ(9, 0)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
#endif
|
||||
|
||||
filename = utf16_to_str(MIN(dataset->length, filename_chars),
|
||||
dataset->filename);
|
||||
|
||||
#if defined(CONFIG_PRAGMA_DIAGNOSTIC_AVAILABLE) && QEMU_GNUC_PREREQ(9, 0)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
if (strchr(filename, '/')) {
|
||||
usb_mtp_queue_result(s, RES_PARAMETER_NOT_SUPPORTED, d->trans,
|
||||
0, 0, 0, 0);
|
||||
|
@@ -3340,6 +3340,7 @@ static void usb_xhci_init(XHCIState *xhci)
|
||||
usb_bus_new(&xhci->bus, sizeof(xhci->bus), &xhci_bus_ops, dev);
|
||||
|
||||
for (i = 0; i < usbports; i++) {
|
||||
g_assert(i < MAX(MAXPORTS_2, MAXPORTS_3));
|
||||
speedmask = 0;
|
||||
if (i < xhci->numports_2) {
|
||||
if (xhci_get_flag(xhci, XHCI_FLAG_SS_FIRST)) {
|
||||
|
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "config-devices.h"
|
||||
#include "exec/memop.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
@@ -34,6 +34,9 @@ typedef struct MuxChardev {
|
||||
Chardev parent;
|
||||
CharBackend *backends[MAX_MUX];
|
||||
CharBackend chr;
|
||||
#if defined(TARGET_S390X)
|
||||
QEMUTimer *accept_timer;
|
||||
#endif
|
||||
int focus;
|
||||
int mux_cnt;
|
||||
int term_got_escape;
|
||||
|
@@ -2303,7 +2303,8 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, hwaddr len,
|
||||
/* address_space_map: map a physical memory region into a host virtual address
|
||||
*
|
||||
* May map a subset of the requested range, given by and returned in @plen.
|
||||
* May return %NULL if resources needed to perform the mapping are exhausted.
|
||||
* May return %NULL and set *@plen to zero(0), if resources needed to perform
|
||||
* the mapping are exhausted.
|
||||
* Use only for reads OR writes - not for read-modify-write operations.
|
||||
* Use cpu_register_map_client() to know when retrying the map operation is
|
||||
* likely to succeed.
|
||||
|
58
include/hw/s390x/pv.h
Normal file
58
include/hw/s390x/pv.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Protected Virtualization header
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
* Author(s):
|
||||
* Janosch Frank <frankja@linux.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
||||
* your option) any later version. See the COPYING file in the top-level
|
||||
* directory.
|
||||
*/
|
||||
#ifndef HW_S390_PV_H
|
||||
#define HW_S390_PV_H
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
#include "cpu.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
|
||||
static inline bool s390_is_pv(void)
|
||||
{
|
||||
static S390CcwMachineState *ccw;
|
||||
Object *obj;
|
||||
|
||||
if (ccw) {
|
||||
return ccw->pv;
|
||||
}
|
||||
|
||||
/* we have to bail out for the "none" machine */
|
||||
obj = object_dynamic_cast(qdev_get_machine(),
|
||||
TYPE_S390_CCW_MACHINE);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
ccw = S390_CCW_MACHINE(obj);
|
||||
return ccw->pv;
|
||||
}
|
||||
|
||||
int s390_pv_vm_enable(void);
|
||||
void s390_pv_vm_disable(void);
|
||||
int s390_pv_set_sec_parms(uint64_t origin, uint64_t length);
|
||||
int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak);
|
||||
void s390_pv_perf_clear_reset(void);
|
||||
int s390_pv_verify(void);
|
||||
void s390_pv_unshare(void);
|
||||
void s390_pv_inject_reset_error(CPUState *cs);
|
||||
#else /* CONFIG_KVM */
|
||||
static inline bool s390_is_pv(void) { return false; }
|
||||
static inline int s390_pv_vm_enable(void) { return 0; }
|
||||
static inline void s390_pv_vm_disable(void) {}
|
||||
static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; }
|
||||
static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; }
|
||||
static inline void s390_pv_perf_clear_reset(void) {}
|
||||
static inline int s390_pv_verify(void) { return 0; }
|
||||
static inline void s390_pv_unshare(void) {}
|
||||
static inline void s390_pv_inject_reset_error(CPUState *cs) {};
|
||||
#endif /* CONFIG_KVM */
|
||||
|
||||
#endif /* HW_S390_PV_H */
|
@@ -28,6 +28,7 @@ typedef struct S390CcwMachineState {
|
||||
/*< public >*/
|
||||
bool aes_key_wrap;
|
||||
bool dea_key_wrap;
|
||||
bool pv;
|
||||
uint8_t loadparm[8];
|
||||
} S390CcwMachineState;
|
||||
|
||||
|
@@ -217,5 +217,7 @@ void s390_sclp_init(void);
|
||||
void sclp_service_interrupt(uint32_t sccb);
|
||||
void raise_irq_cpu_hotplug(void);
|
||||
int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code);
|
||||
int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
|
||||
uint32_t code);
|
||||
|
||||
#endif
|
||||
|
@@ -474,12 +474,17 @@ struct kvm_s390_mem_op {
|
||||
__u32 size; /* amount of bytes */
|
||||
__u32 op; /* type of operation */
|
||||
__u64 buf; /* buffer in userspace */
|
||||
__u8 ar; /* the access register number */
|
||||
__u8 reserved[31]; /* should be set to 0 */
|
||||
union {
|
||||
__u8 ar; /* the access register number */
|
||||
__u32 sida_offset; /* offset into the sida */
|
||||
__u8 reserved[32]; /* should be set to 0 */
|
||||
};
|
||||
};
|
||||
/* types for kvm_s390_mem_op->op */
|
||||
#define KVM_S390_MEMOP_LOGICAL_READ 0
|
||||
#define KVM_S390_MEMOP_LOGICAL_WRITE 1
|
||||
#define KVM_S390_MEMOP_SIDA_READ 2
|
||||
#define KVM_S390_MEMOP_SIDA_WRITE 3
|
||||
/* flags for kvm_s390_mem_op->flags */
|
||||
#define KVM_S390_MEMOP_F_CHECK_ONLY (1ULL << 0)
|
||||
#define KVM_S390_MEMOP_F_INJECT_EXCEPTION (1ULL << 1)
|
||||
@@ -1010,6 +1015,7 @@ struct kvm_ppc_resize_hpt {
|
||||
#define KVM_CAP_ARM_NISV_TO_USER 177
|
||||
#define KVM_CAP_ARM_INJECT_EXT_DABT 178
|
||||
#define KVM_CAP_S390_VCPU_RESETS 179
|
||||
#define KVM_CAP_S390_PROTECTED 180
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
@@ -1478,6 +1484,41 @@ struct kvm_enc_region {
|
||||
#define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3)
|
||||
#define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4)
|
||||
|
||||
struct kvm_s390_pv_sec_parm {
|
||||
__u64 origin;
|
||||
__u64 length;
|
||||
};
|
||||
|
||||
struct kvm_s390_pv_unp {
|
||||
__u64 addr;
|
||||
__u64 size;
|
||||
__u64 tweak;
|
||||
};
|
||||
|
||||
enum pv_cmd_id {
|
||||
KVM_PV_ENABLE,
|
||||
KVM_PV_DISABLE,
|
||||
KVM_PV_VM_SET_SEC_PARMS,
|
||||
KVM_PV_VM_UNPACK,
|
||||
KVM_PV_VM_VERIFY,
|
||||
KVM_PV_VM_PREP_RESET,
|
||||
KVM_PV_VM_UNSHARE_ALL,
|
||||
KVM_PV_VCPU_CREATE,
|
||||
KVM_PV_VCPU_DESTROY,
|
||||
};
|
||||
|
||||
struct kvm_pv_cmd {
|
||||
__u32 cmd; /* Command to be executed */
|
||||
__u16 rc; /* Ultravisor return code */
|
||||
__u16 rrc; /* Ultravisor return reason code */
|
||||
__u64 data; /* Data or address */
|
||||
__u32 flags; /* flags for future extensions. Must be 0 for now */
|
||||
__u32 reserved[3];
|
||||
};
|
||||
|
||||
/* Available with KVM_CAP_S390_PROTECTED */
|
||||
#define KVM_S390_PV_COMMAND _IOWR(KVMIO, 0xc5, struct kvm_pv_cmd)
|
||||
|
||||
/* Secure Encrypted Virtualization command */
|
||||
enum sev_cmd_id {
|
||||
/* Guest initialization commands */
|
||||
|
@@ -23,3 +23,4 @@ obj-$(TARGET_SPARC) += sparc/
|
||||
obj-$(TARGET_SPARC64) += $(TARGET_ABI_DIR)/
|
||||
obj-$(TARGET_X86_64) += x86_64/
|
||||
obj-$(TARGET_XTENSA) += xtensa/
|
||||
obj-binfmt-y = binfmt.o
|
||||
|
68
linux-user/binfmt.c
Normal file
68
linux-user/binfmt.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define ARCH_NAME "x86_64"
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
char *binfmt;
|
||||
char **new_argv;
|
||||
|
||||
/*
|
||||
* Check if our file name ends with -binfmt
|
||||
*/
|
||||
binfmt = argv[0] + strlen(argv[0]) - strlen("-binfmt");
|
||||
if (strcmp(binfmt, "-binfmt")) {
|
||||
fprintf(stderr, "%s: Invalid executable name\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "%s: Please use me through binfmt with P flag\n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
binfmt[0] = '\0';
|
||||
/* Now argv[0] is the real qemu binary name */
|
||||
|
||||
#ifdef ARCH_NAME
|
||||
{
|
||||
char *hostbin;
|
||||
char *guestarch;
|
||||
int r;
|
||||
|
||||
guestarch = strrchr(argv[0], '-') ;
|
||||
if (!guestarch) {
|
||||
goto skip;
|
||||
}
|
||||
guestarch++;
|
||||
r = asprintf(&hostbin, "/emul/" ARCH_NAME "-for-%s/%s", guestarch, argv[1]);
|
||||
if ((r > 0) && !access(hostbin, X_OK)) {
|
||||
/*
|
||||
* We found a host binary replacement for the non-host binary. Let's
|
||||
* use that instead!
|
||||
*/
|
||||
return execve(hostbin, &argv[2], envp);
|
||||
}
|
||||
}
|
||||
skip:
|
||||
#endif
|
||||
|
||||
new_argv = (char **)malloc((argc + 2) * sizeof(*new_argv));
|
||||
if (argc > 3) {
|
||||
memcpy(&new_argv[4], &argv[3], (argc - 3) * sizeof(*new_argv));
|
||||
}
|
||||
new_argv[0] = argv[0];
|
||||
new_argv[1] = (char *)"-0";
|
||||
new_argv[2] = argv[2];
|
||||
new_argv[3] = argv[1];
|
||||
new_argv[argc + 1] = NULL;
|
||||
|
||||
return execve(new_argv[0], new_argv, envp);
|
||||
}
|
@@ -207,10 +207,10 @@ abi_long memcpy_to_target(abi_ulong dest, const void *src,
|
||||
void target_set_brk(abi_ulong new_brk);
|
||||
abi_long do_brk(abi_ulong new_brk);
|
||||
void syscall_init(void);
|
||||
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
abi_long arg2, abi_long arg3, abi_long arg4,
|
||||
abi_long arg5, abi_long arg6, abi_long arg7,
|
||||
abi_long arg8);
|
||||
abi_long do_syscall(void *cpu_env, int num, abi_ulong arg1,
|
||||
abi_ulong arg2, abi_ulong arg3, abi_ulong arg4,
|
||||
abi_ulong arg5, abi_ulong arg6, abi_ulong arg7,
|
||||
abi_ulong arg8);
|
||||
extern __thread CPUState *thread_cpu;
|
||||
void cpu_loop(CPUArchState *env);
|
||||
const char *target_strerror(int err);
|
||||
|
@@ -632,6 +632,10 @@ static void QEMU_NORETURN dump_core_and_abort(int target_sig)
|
||||
trace_user_force_sig(env, target_sig, host_sig);
|
||||
gdb_signalled(env, target_sig);
|
||||
|
||||
if (target_sig == 6) {
|
||||
goto no_core;
|
||||
}
|
||||
|
||||
/* dump core if supported by target binary format */
|
||||
if (core_dump_signal(target_sig) && (ts->bprm->core_dump != NULL)) {
|
||||
stop_all_tasks();
|
||||
@@ -649,6 +653,8 @@ static void QEMU_NORETURN dump_core_and_abort(int target_sig)
|
||||
target_sig, strsignal(host_sig), "core dumped" );
|
||||
}
|
||||
|
||||
no_core:
|
||||
|
||||
/* The proper exit code for dying from an uncaught signal is
|
||||
* -<signal>. The kernel doesn't allow exit() or _exit() to pass
|
||||
* a negative value. To get the proper exit code we need to
|
||||
|
@@ -5301,8 +5301,21 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
|
||||
ie = ioctl_entries;
|
||||
for(;;) {
|
||||
if (ie->target_cmd == 0) {
|
||||
int i;
|
||||
qemu_log_mask(
|
||||
LOG_UNIMP, "Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
|
||||
LOG_UNIMP, "Unsupported ioctl: cmd=0x%04lx (%x)\n", (unsigned long)cmd,
|
||||
(unsigned int)(cmd & (TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT))
|
||||
>> TARGET_IOC_SIZESHIFT);
|
||||
for (i = 0; ioctl_entries[i].target_cmd; i++) {
|
||||
if ((ioctl_entries[i].target_cmd & ~(TARGET_IOC_SIZEMASK
|
||||
<< TARGET_IOC_SIZESHIFT)) == (cmd & ~(TARGET_IOC_SIZEMASK <<
|
||||
TARGET_IOC_SIZESHIFT)))
|
||||
qemu_log_mask(
|
||||
LOG_UNIMP, "%p\t->\t%s (%x)\n", (void *)(unsigned long)
|
||||
ioctl_entries[i].host_cmd, ioctl_entries[i].name,
|
||||
(ioctl_entries[i].target_cmd & (TARGET_IOC_SIZEMASK
|
||||
<< TARGET_IOC_SIZESHIFT)) >> TARGET_IOC_SIZESHIFT);
|
||||
}
|
||||
return -TARGET_ENOSYS;
|
||||
}
|
||||
if (ie->target_cmd == cmd)
|
||||
@@ -5333,6 +5346,13 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
|
||||
arg_type++;
|
||||
target_size = thunk_type_size(arg_type, 0);
|
||||
switch(ie->access) {
|
||||
/*
|
||||
* FIXME: actually the direction given in the ioctl should be
|
||||
* correct so we can assume the communication is uni-directional.
|
||||
* The alsa developers did not like this concept though and
|
||||
* declared ioctls IOC_R and IOC_W even though they were IOC_RW.
|
||||
*/
|
||||
/*
|
||||
case IOC_R:
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
|
||||
if (!is_error(ret)) {
|
||||
@@ -5351,6 +5371,7 @@ static abi_long do_ioctl(int fd, int cmd, abi_long arg)
|
||||
unlock_user(argptr, arg, 0);
|
||||
ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
case IOC_RW:
|
||||
argptr = lock_user(VERIFY_READ, arg, target_size, 1);
|
||||
@@ -7323,6 +7344,27 @@ static int open_self_stat(void *cpu_env, int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(TARGET_ARM)
|
||||
static int open_cpuinfo(void *cpu_env, int fd)
|
||||
{
|
||||
dprintf(fd,
|
||||
"Processor : ARMv7 Processor rev 5 (v7l)\n"
|
||||
"BogoMIPS : 799.53\n"
|
||||
"Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3\n"
|
||||
"CPU implementer : 0x41\n"
|
||||
"CPU architecture: 7\n"
|
||||
"CPU variant : 0x2\n"
|
||||
"CPU part : 0xc08\n"
|
||||
"CPU revision : 5\n"
|
||||
"\n"
|
||||
"Hardware : Genesi Efika MX (Smarttop)\n"
|
||||
"Revision : 51030\n"
|
||||
"Serial : 0000000000000000\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int open_self_auxv(void *cpu_env, int fd)
|
||||
{
|
||||
CPUState *cpu = env_cpu((CPUArchState *)cpu_env);
|
||||
@@ -7465,6 +7507,9 @@ static int do_openat(void *cpu_env, int dirfd, const char *pathname, int flags,
|
||||
#if defined(TARGET_SPARC)
|
||||
{ "/proc/cpuinfo", open_cpuinfo, is_proc },
|
||||
#endif
|
||||
#if defined(TARGET_ARM)
|
||||
{ "cpuinfo", open_cpuinfo, is_proc_myself },
|
||||
#endif
|
||||
#if defined(TARGET_M68K)
|
||||
{ "/proc/hardware", open_hardware, is_proc },
|
||||
#endif
|
||||
@@ -7605,10 +7650,10 @@ static int host_to_target_cpu_mask(const unsigned long *host_mask,
|
||||
* of syscall results, can be performed.
|
||||
* All errnos that do_syscall() returns must be -TARGET_<errcode>.
|
||||
*/
|
||||
static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
abi_long arg2, abi_long arg3, abi_long arg4,
|
||||
abi_long arg5, abi_long arg6, abi_long arg7,
|
||||
abi_long arg8)
|
||||
static abi_long do_syscall1(void *cpu_env, int num, abi_ulong arg1,
|
||||
abi_ulong arg2, abi_ulong arg3, abi_ulong arg4,
|
||||
abi_ulong arg5, abi_ulong arg6, abi_ulong arg7,
|
||||
abi_ulong arg8)
|
||||
{
|
||||
CPUState *cpu = env_cpu(cpu_env);
|
||||
abi_long ret;
|
||||
@@ -7960,8 +8005,13 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
return ret;
|
||||
#endif
|
||||
#ifdef TARGET_NR_lseek
|
||||
case TARGET_NR_lseek:
|
||||
return get_errno(lseek(arg1, arg2, arg3));
|
||||
case TARGET_NR_lseek: {
|
||||
off_t off = arg2;
|
||||
if (arg3 != SEEK_SET) {
|
||||
off = (abi_long)arg2;
|
||||
}
|
||||
return get_errno(lseek(arg1, off, arg3));
|
||||
}
|
||||
#endif
|
||||
#if defined(TARGET_NR_getxpid) && defined(TARGET_ALPHA)
|
||||
/* Alpha specific */
|
||||
@@ -8837,6 +8887,9 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
if (copy_from_user_timeval(&tv, arg1)) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
|
||||
ret = get_errno(gettimeofday(&tv, &tz));
|
||||
if (!is_error(ret)) {
|
||||
@@ -9999,7 +10052,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
{
|
||||
struct timespec ts, *pts;
|
||||
|
||||
if (arg3 >= 0) {
|
||||
if ((abi_long)arg3 >= 0) {
|
||||
/* Convert ms to secs, ns */
|
||||
ts.tv_sec = arg3 / 1000;
|
||||
ts.tv_nsec = (arg3 % 1000) * 1000000LL;
|
||||
@@ -10375,7 +10428,7 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
*/
|
||||
ret = -TARGET_EINVAL;
|
||||
if (cpu_isar_feature(aa64_sve, env_archcpu(cpu_env))
|
||||
&& arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
|
||||
&& arg2 <= 512 * 16 && !(arg2 & 15)) {
|
||||
CPUARMState *env = cpu_env;
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
uint32_t vq, old_vq;
|
||||
@@ -12408,10 +12461,10 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
|
||||
return ret;
|
||||
}
|
||||
|
||||
abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
abi_long arg2, abi_long arg3, abi_long arg4,
|
||||
abi_long arg5, abi_long arg6, abi_long arg7,
|
||||
abi_long arg8)
|
||||
abi_long do_syscall(void *cpu_env, int num, abi_ulong arg1,
|
||||
abi_ulong arg2, abi_ulong arg3, abi_ulong arg4,
|
||||
abi_ulong arg5, abi_ulong arg6, abi_ulong arg7,
|
||||
abi_ulong arg8)
|
||||
{
|
||||
CPUState *cpu = env_cpu(cpu_env);
|
||||
abi_long ret;
|
||||
|
@@ -2782,7 +2782,7 @@ void qmp_xen_save_devices_state(const char *filename, bool has_live, bool live,
|
||||
* So call bdrv_inactivate_all (release locks) here to let the other
|
||||
* side of the migration take controle of the images.
|
||||
*/
|
||||
if (live && !saved_vm_running) {
|
||||
if (!saved_vm_running) {
|
||||
ret = bdrv_inactivate_all();
|
||||
if (ret) {
|
||||
error_setg(errp, "%s: bdrv_inactivate_all() failed (%d)",
|
||||
|
23
nbd/server.c
23
nbd/server.c
@@ -217,7 +217,7 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
||||
|
||||
msg = g_strdup_vprintf(fmt, va);
|
||||
len = strlen(msg);
|
||||
assert(len < 4096);
|
||||
assert(len < NBD_MAX_STRING_SIZE);
|
||||
trace_nbd_negotiate_send_rep_err(msg);
|
||||
ret = nbd_negotiate_send_rep_len(client, type, len, errp);
|
||||
if (ret < 0) {
|
||||
@@ -231,6 +231,19 @@ nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a malloc'd copy of @name suitable for use in an error reply.
|
||||
*/
|
||||
static char *
|
||||
nbd_sanitize_name(const char *name)
|
||||
{
|
||||
if (strnlen(name, 80) < 80) {
|
||||
return g_strdup(name);
|
||||
}
|
||||
/* XXX Should we also try to sanitize any control characters? */
|
||||
return g_strdup_printf("%.80s...", name);
|
||||
}
|
||||
|
||||
/* Send an error reply.
|
||||
* Return -errno on error, 0 on success. */
|
||||
static int GCC_FMT_ATTR(4, 5)
|
||||
@@ -595,9 +608,11 @@ static int nbd_negotiate_handle_info(NBDClient *client, Error **errp)
|
||||
|
||||
exp = nbd_export_find(name);
|
||||
if (!exp) {
|
||||
g_autofree char *sane_name = nbd_sanitize_name(name);
|
||||
|
||||
return nbd_negotiate_send_rep_err(client, NBD_REP_ERR_UNKNOWN,
|
||||
errp, "export '%s' not present",
|
||||
name);
|
||||
sane_name);
|
||||
}
|
||||
|
||||
/* Don't bother sending NBD_INFO_NAME unless client requested it */
|
||||
@@ -995,8 +1010,10 @@ static int nbd_negotiate_meta_queries(NBDClient *client,
|
||||
|
||||
meta->exp = nbd_export_find(export_name);
|
||||
if (meta->exp == NULL) {
|
||||
g_autofree char *sane_name = nbd_sanitize_name(export_name);
|
||||
|
||||
return nbd_opt_drop(client, NBD_REP_ERR_UNKNOWN, errp,
|
||||
"export '%s' not present", export_name);
|
||||
"export '%s' not present", sane_name);
|
||||
}
|
||||
|
||||
ret = nbd_opt_read(client, &nb_queries, sizeof(nb_queries), errp);
|
||||
|
@@ -53,6 +53,7 @@ libc.a: $(LIBCOBJS)
|
||||
LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \
|
||||
dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o pxelinux.o
|
||||
LIBNETCFLAGS := $(QEMU_CFLAGS) $(CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC)
|
||||
LIBNETCFLAGS += -Wno-address-of-packed-member
|
||||
|
||||
%.o : $(SLOF_DIR)/lib/libnet/%.c
|
||||
$(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@")
|
||||
|
@@ -123,7 +123,12 @@ static int parse_acl_file(const char *filename, ACLList *acl_list)
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "deny") == 0) {
|
||||
acl_rule = g_malloc(sizeof(*acl_rule));
|
||||
acl_rule = calloc(1, sizeof(*acl_rule));
|
||||
if (!acl_rule) {
|
||||
fclose(f);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(arg, "all") == 0) {
|
||||
acl_rule->type = ACL_DENY_ALL;
|
||||
} else {
|
||||
@@ -132,7 +137,12 @@ static int parse_acl_file(const char *filename, ACLList *acl_list)
|
||||
}
|
||||
QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
|
||||
} else if (strcmp(cmd, "allow") == 0) {
|
||||
acl_rule = g_malloc(sizeof(*acl_rule));
|
||||
acl_rule = calloc(1, sizeof(*acl_rule));
|
||||
if (!acl_rule) {
|
||||
fclose(f);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(arg, "all") == 0) {
|
||||
acl_rule->type = ACL_ALLOW_ALL;
|
||||
} else {
|
||||
@@ -433,6 +443,18 @@ int main(int argc, char **argv)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_LIBCAP
|
||||
/*
|
||||
* avoid sending the fd as root user if running suid to not fool
|
||||
* peer credentials to daemons that dont expect that
|
||||
*/
|
||||
if (setuid(getuid()) < 0) {
|
||||
fprintf(stderr, "Failed to drop privileges.\n");
|
||||
ret = EXIT_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* write fd to the domain socket */
|
||||
if (send_fd(unixfd, fd) == -1) {
|
||||
fprintf(stderr, "failed to write fd to unix socket: %s\n",
|
||||
@@ -454,7 +476,7 @@ cleanup:
|
||||
}
|
||||
while ((acl_rule = QSIMPLEQ_FIRST(&acl_list)) != NULL) {
|
||||
QSIMPLEQ_REMOVE_HEAD(&acl_list, entry);
|
||||
g_free(acl_rule);
|
||||
free(acl_rule);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@@ -51,6 +51,12 @@ SEABIOS_EXTRAVERSION="-prebuilt.qemu.org"
|
||||
#
|
||||
EDK2_EFIROM = edk2/BaseTools/Source/C/bin/EfiRom
|
||||
|
||||
# NB: Certain SUSE qemu subpackages use date information, but we want
|
||||
# reproducible builds, so we use a pre-determined timestamp, rather
|
||||
# than the current timestamp to acheive consistent results build to
|
||||
# build.
|
||||
PACKAGING_TIMESTAMP = $(shell date -r ../VERSION +%s)
|
||||
|
||||
default help:
|
||||
@echo "nothing is build by default"
|
||||
@echo "available build targets:"
|
||||
@@ -101,7 +107,7 @@ build-seabios-config-%: config.%
|
||||
|
||||
.PHONY: sgabios skiboot
|
||||
sgabios:
|
||||
$(MAKE) -C sgabios
|
||||
$(MAKE) -C sgabios PACKAGING_TIMESTAMP=$(PACKAGING_TIMESTAMP)
|
||||
cp sgabios/sgabios.bin ../pc-bios
|
||||
|
||||
|
||||
@@ -121,11 +127,13 @@ efi-rom-%: build-pxe-roms build-efi-roms edk2-basetools
|
||||
|
||||
build-pxe-roms:
|
||||
$(MAKE) -C ipxe/src CONFIG=qemu \
|
||||
PACKAGING_TIMESTAMP=$(PACKAGING_TIMESTAMP) \
|
||||
CROSS_COMPILE=$(x86_64_cross_prefix) \
|
||||
$(patsubst %,bin/%.rom,$(pxerom_targets))
|
||||
|
||||
build-efi-roms: build-pxe-roms
|
||||
$(MAKE) -C ipxe/src CONFIG=qemu \
|
||||
PACKAGING_TIMESTAMP=$(PACKAGING_TIMESTAMP) \
|
||||
CROSS_COMPILE=$(x86_64_cross_prefix) \
|
||||
$(patsubst %,bin-i386-efi/%.efidrv,$(pxerom_targets)) \
|
||||
$(patsubst %,bin-x86_64-efi/%.efidrv,$(pxerom_targets))
|
||||
@@ -148,7 +156,9 @@ edk2-basetools:
|
||||
EXTRA_LDFLAGS='$(EDK2_BASETOOLS_LDFLAGS)'
|
||||
|
||||
slof:
|
||||
$(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) qemu
|
||||
$(MAKE) -C SLOF CROSS=$(powerpc64_cross_prefix) \
|
||||
PACKAGING_TIMESTAMP=$(PACKAGING_TIMESTAMP) \
|
||||
qemu
|
||||
cp SLOF/boot_rom.bin ../pc-bios/slof.bin
|
||||
|
||||
u-boot.e500:
|
||||
@@ -195,7 +205,7 @@ opensbi64-sifive_u:
|
||||
cp opensbi/build/platform/sifive/fu540/firmware/fw_jump.bin ../pc-bios/opensbi-riscv64-sifive_u-fw_jump.bin
|
||||
|
||||
bios-microvm:
|
||||
$(MAKE) -C qboot
|
||||
$(MAKE) -C qboot CROSS_COMPILE=$(x86_64_cross_prefix) CC=gcc
|
||||
cp qboot/bios.bin ../pc-bios/bios-microvm.bin
|
||||
|
||||
clean:
|
||||
|
@@ -116,7 +116,15 @@ qemu_edk2_get_cross_prefix()
|
||||
# force soft-float cross-compiler on Debian
|
||||
printf 'arm-linux-gnueabi-'
|
||||
else
|
||||
printf '%s-linux-gnu-\n' "$gcc_arch"
|
||||
if [ "$emulation_target" == arm ]; then
|
||||
printf '%s-suse-linux-gnueabi-\n' "$gcc_arch"
|
||||
else
|
||||
if [ "$gcc_arch" == i686 ]; then
|
||||
printf '%s-suse-linux-\n' "i586"
|
||||
else
|
||||
printf '%s-suse-linux-\n' "$gcc_arch"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Migration Stream Analyzer
|
||||
#
|
||||
|
@@ -266,7 +266,7 @@ qemu_generate_register() {
|
||||
flags="${flags}F"
|
||||
fi
|
||||
|
||||
echo ":qemu-$cpu:M::$magic:$mask:$qemu:$flags"
|
||||
echo ":qemu-$cpu:M::$magic:$mask:$qemu:P$flags"
|
||||
}
|
||||
|
||||
qemu_register_interpreter() {
|
||||
@@ -305,9 +305,9 @@ qemu_set_binfmts() {
|
||||
continue
|
||||
fi
|
||||
|
||||
qemu="$QEMU_PATH/qemu-$cpu"
|
||||
qemu="$QEMU_PATH/qemu-$cpu-binfmt"
|
||||
if [ "$cpu" = "i486" ] ; then
|
||||
qemu="$QEMU_PATH/qemu-i386"
|
||||
qemu="$QEMU_PATH/qemu-i386-binfmt"
|
||||
fi
|
||||
|
||||
qemu="$qemu$QEMU_SUFFIX"
|
||||
@@ -323,7 +323,7 @@ BINFMT_SET=qemu_register_interpreter
|
||||
SYSTEMDDIR="/etc/binfmt.d"
|
||||
DEBIANDIR="/usr/share/binfmts"
|
||||
|
||||
QEMU_PATH=/usr/local/bin
|
||||
QEMU_PATH=/usr/bin
|
||||
CREDENTIAL=no
|
||||
PERSISTENT=no
|
||||
QEMU_SUFFIX=""
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Compares vmstate information stored in JSON format, obtained from
|
||||
# the -dump-vmstate QEMU command.
|
||||
|
12
softmmu/vl.c
12
softmmu/vl.c
@@ -34,6 +34,7 @@
|
||||
#include "qemu/uuid.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include <sys/resource.h>
|
||||
#include "sysemu/seccomp.h"
|
||||
#include "sysemu/tcg.h"
|
||||
|
||||
@@ -2851,6 +2852,7 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||
BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
|
||||
QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list);
|
||||
int mem_prealloc = 0; /* force preallocation of physical target memory */
|
||||
struct rlimit rlimit_as;
|
||||
|
||||
os_set_line_buffering();
|
||||
|
||||
@@ -2862,6 +2864,16 @@ void qemu_init(int argc, char **argv, char **envp)
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
|
||||
/*
|
||||
* Try to raise the soft address space limit.
|
||||
* Default on SLES 11 SP2 is 80% of physical+swap memory.
|
||||
*/
|
||||
getrlimit(RLIMIT_AS, &rlimit_as);
|
||||
if (rlimit_as.rlim_cur < rlimit_as.rlim_max) {
|
||||
rlimit_as.rlim_cur = rlimit_as.rlim_max;
|
||||
setrlimit(RLIMIT_AS, &rlimit_as);
|
||||
}
|
||||
|
||||
atexit(qemu_run_exit_notifiers);
|
||||
qemu_init_exec_dir(argv[0]);
|
||||
|
||||
|
@@ -1942,7 +1942,7 @@ uint64_t cpu_get_tsc(CPUX86State *env);
|
||||
/* XXX: This value should match the one returned by CPUID
|
||||
* and in exec.c */
|
||||
# if defined(TARGET_X86_64)
|
||||
# define TCG_PHYS_ADDR_BITS 40
|
||||
# define TCG_PHYS_ADDR_BITS 42
|
||||
# else
|
||||
# define TCG_PHYS_ADDR_BITS 36
|
||||
# endif
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
#include "hw/s390x/pv.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@@ -76,16 +77,24 @@ static bool s390_cpu_has_work(CPUState *cs)
|
||||
static void s390_cpu_load_normal(CPUState *s)
|
||||
{
|
||||
S390CPU *cpu = S390_CPU(s);
|
||||
uint64_t spsw = ldq_phys(s->as, 0);
|
||||
|
||||
cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
|
||||
/*
|
||||
* Invert short psw indication, so SIE will report a specification
|
||||
* exception if it was not set.
|
||||
*/
|
||||
cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
|
||||
cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
|
||||
uint64_t spsw;
|
||||
|
||||
if (!s390_is_pv()) {
|
||||
spsw = ldq_phys(s->as, 0);
|
||||
cpu->env.psw.mask = spsw & PSW_MASK_SHORT_CTRL;
|
||||
/*
|
||||
* Invert short psw indication, so SIE will report a specification
|
||||
* exception if it was not set.
|
||||
*/
|
||||
cpu->env.psw.mask ^= PSW_MASK_SHORTPSW;
|
||||
cpu->env.psw.addr = spsw & PSW_MASK_SHORT_ADDR;
|
||||
} else {
|
||||
/*
|
||||
* Firmware requires us to set the load state before we set
|
||||
* the cpu to operating on protected guests.
|
||||
*/
|
||||
s390_cpu_set_state(S390_CPU_STATE_LOAD, cpu);
|
||||
}
|
||||
s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu);
|
||||
}
|
||||
#endif
|
||||
|
@@ -823,7 +823,12 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf,
|
||||
#define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len) \
|
||||
s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true)
|
||||
void s390_cpu_virt_mem_handle_exc(S390CPU *cpu, uintptr_t ra);
|
||||
|
||||
int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
|
||||
int len, bool is_write);
|
||||
#define s390_cpu_pv_mem_read(cpu, offset, dest, len) \
|
||||
s390_cpu_pv_mem_rw(cpu, offset, dest, len, false)
|
||||
#define s390_cpu_pv_mem_write(cpu, offset, dest, len) \
|
||||
s390_cpu_pv_mem_rw(cpu, offset, dest, len, true)
|
||||
|
||||
/* sigp.c */
|
||||
int s390_cpu_restart(S390CPU *cpu);
|
||||
|
@@ -107,6 +107,7 @@ DEF_FEAT(DEFLATE_BASE, "deflate-base", STFL, 151, "Deflate-conversion facility (
|
||||
DEF_FEAT(VECTOR_PACKED_DECIMAL_ENH, "vxpdeh", STFL, 152, "Vector-Packed-Decimal-Enhancement Facility")
|
||||
DEF_FEAT(MSA_EXT_9, "msa9-base", STFL, 155, "Message-security-assist-extension-9 facility (excluding subfunctions)")
|
||||
DEF_FEAT(ETOKEN, "etoken", STFL, 156, "Etoken facility")
|
||||
DEF_FEAT(UNPACK, "unpack", STFL, 161, "Unpack facility")
|
||||
|
||||
/* Features exposed via SCLP SCCB Byte 80 - 98 (bit numbers relative to byte-80) */
|
||||
DEF_FEAT(SIE_GSLS, "gsls", SCLP_CONF_CHAR, 40, "SIE: Guest-storage-limit-suppression facility")
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "sysemu/cpus.h"
|
||||
#include "hw/s390x/ipl.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
#include "hw/s390x/pv.h"
|
||||
#include "kvm_s390x.h"
|
||||
|
||||
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
|
||||
{
|
||||
@@ -49,20 +51,13 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
|
||||
return diag288_class->handle_timer(diag288, func, timeout);
|
||||
}
|
||||
|
||||
#define DIAG_308_RC_OK 0x0001
|
||||
#define DIAG_308_RC_NO_CONF 0x0102
|
||||
#define DIAG_308_RC_INVALID 0x0402
|
||||
|
||||
#define DIAG308_RESET_MOD_CLR 0
|
||||
#define DIAG308_RESET_LOAD_NORM 1
|
||||
#define DIAG308_LOAD_CLEAR 3
|
||||
#define DIAG308_LOAD_NORMAL_DUMP 4
|
||||
#define DIAG308_SET 5
|
||||
#define DIAG308_STORE 6
|
||||
|
||||
static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
|
||||
uintptr_t ra, bool write)
|
||||
{
|
||||
/* Handled by the Ultravisor */
|
||||
if (s390_is_pv()) {
|
||||
return 0;
|
||||
}
|
||||
if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
return -1;
|
||||
@@ -78,7 +73,9 @@ static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
|
||||
|
||||
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
|
||||
{
|
||||
bool valid;
|
||||
CPUState *cs = env_cpu(env);
|
||||
S390CPU *cpu = S390_CPU(cs);
|
||||
uint64_t addr = env->regs[r1];
|
||||
uint64_t subcode = env->regs[r3];
|
||||
IplParameterBlock *iplb;
|
||||
@@ -93,6 +90,11 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (subcode) {
|
||||
case DIAG308_RESET_MOD_CLR:
|
||||
s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR);
|
||||
@@ -105,19 +107,30 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
|
||||
s390_ipl_reset_request(cs, S390_RESET_REIPL);
|
||||
break;
|
||||
case DIAG308_SET:
|
||||
case DIAG308_PV_SET:
|
||||
if (diag308_parm_check(env, r1, addr, ra, false)) {
|
||||
return;
|
||||
}
|
||||
iplb = g_new0(IplParameterBlock, 1);
|
||||
cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
|
||||
if (!s390_is_pv()) {
|
||||
cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
|
||||
} else {
|
||||
s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len));
|
||||
}
|
||||
|
||||
if (!iplb_valid_len(iplb)) {
|
||||
env->regs[r1 + 1] = DIAG_308_RC_INVALID;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
|
||||
if (!s390_is_pv()) {
|
||||
cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
|
||||
} else {
|
||||
s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len));
|
||||
}
|
||||
|
||||
if (!iplb_valid(iplb)) {
|
||||
valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
|
||||
if (!valid) {
|
||||
env->regs[r1 + 1] = DIAG_308_RC_INVALID;
|
||||
goto out;
|
||||
}
|
||||
@@ -128,17 +141,43 @@ out:
|
||||
g_free(iplb);
|
||||
return;
|
||||
case DIAG308_STORE:
|
||||
case DIAG308_PV_STORE:
|
||||
if (diag308_parm_check(env, r1, addr, ra, true)) {
|
||||
return;
|
||||
}
|
||||
iplb = s390_ipl_get_iplb();
|
||||
if (iplb) {
|
||||
cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
|
||||
env->regs[r1 + 1] = DIAG_308_RC_OK;
|
||||
if (subcode == DIAG308_PV_STORE) {
|
||||
iplb = s390_ipl_get_iplb_pv();
|
||||
} else {
|
||||
env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
|
||||
iplb = s390_ipl_get_iplb();
|
||||
}
|
||||
if (!iplb) {
|
||||
env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s390_is_pv()) {
|
||||
cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
|
||||
} else {
|
||||
s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len));
|
||||
}
|
||||
env->regs[r1 + 1] = DIAG_308_RC_OK;
|
||||
return;
|
||||
case DIAG308_PV_START:
|
||||
iplb = s390_ipl_get_iplb_pv();
|
||||
if (!iplb) {
|
||||
env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_s390_get_hpage_1m()) {
|
||||
error_report("Protected VMs can currently not be backed with "
|
||||
"huge pages");
|
||||
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
|
||||
return;
|
||||
}
|
||||
|
||||
s390_ipl_reset_request(cs, S390_RESET_PV);
|
||||
break;
|
||||
default:
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
break;
|
||||
|
@@ -562,6 +562,7 @@ static uint16_t full_GEN15_GA1[] = {
|
||||
S390_FEAT_GROUP_MSA_EXT_9,
|
||||
S390_FEAT_GROUP_MSA_EXT_9_PCKMO,
|
||||
S390_FEAT_ETOKEN,
|
||||
S390_FEAT_UNPACK,
|
||||
};
|
||||
|
||||
/* Default features (in order of release)
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/qemu-print.h"
|
||||
#include "hw/s390x/ioinst.h"
|
||||
#include "hw/s390x/pv.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
@@ -246,6 +247,11 @@ int s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
|
||||
hwaddr len = sizeof(*sa);
|
||||
int i;
|
||||
|
||||
/* For PVMs storing will occur when this cpu enters SIE again */
|
||||
if (s390_is_pv()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sa = cpu_physical_memory_map(addr, &len, true);
|
||||
if (!sa) {
|
||||
return -EFAULT;
|
||||
|
@@ -16,6 +16,25 @@
|
||||
#include "hw/s390x/ioinst.h"
|
||||
#include "trace.h"
|
||||
#include "hw/s390x/s390-pci-bus.h"
|
||||
#include "hw/s390x/pv.h"
|
||||
|
||||
/* All I/O instructions but chsc use the s format */
|
||||
static uint64_t get_address_from_regs(CPUS390XState *env, uint32_t ipb,
|
||||
uint8_t *ar)
|
||||
{
|
||||
/*
|
||||
* Addresses for protected guests are all offsets into the
|
||||
* satellite block which holds the IO control structures. Those
|
||||
* control structures are always starting at offset 0 and are
|
||||
* always aligned and accessible. So we can return 0 here which
|
||||
* will pass the following address checks.
|
||||
*/
|
||||
if (s390_is_pv()) {
|
||||
*ar = 0;
|
||||
return 0;
|
||||
}
|
||||
return decode_basedisp_s(env, ipb, ar);
|
||||
}
|
||||
|
||||
int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
|
||||
int *schid)
|
||||
@@ -114,12 +133,14 @@ void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
|
||||
CPUS390XState *env = &cpu->env;
|
||||
uint8_t ar;
|
||||
|
||||
addr = decode_basedisp_s(env, ipb, &ar);
|
||||
addr = get_address_from_regs(env, ipb, &ar);
|
||||
if (addr & 3) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
return;
|
||||
}
|
||||
if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_read(cpu, addr, &schib, sizeof(schib));
|
||||
} else if (s390_cpu_virt_mem_read(cpu, addr, ar, &schib, sizeof(schib))) {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
return;
|
||||
}
|
||||
@@ -171,12 +192,14 @@ void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
|
||||
CPUS390XState *env = &cpu->env;
|
||||
uint8_t ar;
|
||||
|
||||
addr = decode_basedisp_s(env, ipb, &ar);
|
||||
addr = get_address_from_regs(env, ipb, &ar);
|
||||
if (addr & 3) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
return;
|
||||
}
|
||||
if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_read(cpu, addr, &orig_orb, sizeof(orb));
|
||||
} else if (s390_cpu_virt_mem_read(cpu, addr, ar, &orig_orb, sizeof(orb))) {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
return;
|
||||
}
|
||||
@@ -203,7 +226,7 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
|
||||
CPUS390XState *env = &cpu->env;
|
||||
uint8_t ar;
|
||||
|
||||
addr = decode_basedisp_s(env, ipb, &ar);
|
||||
addr = get_address_from_regs(env, ipb, &ar);
|
||||
if (addr & 3) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
return;
|
||||
@@ -212,14 +235,19 @@ void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
|
||||
cc = css_do_stcrw(&crw);
|
||||
/* 0 - crw stored, 1 - zeroes stored */
|
||||
|
||||
if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_write(cpu, addr, &crw, sizeof(crw));
|
||||
setcc(cpu, cc);
|
||||
} else {
|
||||
if (cc == 0) {
|
||||
/* Write failed: requeue CRW since STCRW is suppressing */
|
||||
css_undo_stcrw(&crw);
|
||||
if (s390_cpu_virt_mem_write(cpu, addr, ar, &crw, sizeof(crw)) == 0) {
|
||||
setcc(cpu, cc);
|
||||
} else {
|
||||
if (cc == 0) {
|
||||
/* Write failed: requeue CRW since STCRW is suppressing */
|
||||
css_undo_stcrw(&crw);
|
||||
}
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
}
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,13 +262,20 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
|
||||
CPUS390XState *env = &cpu->env;
|
||||
uint8_t ar;
|
||||
|
||||
addr = decode_basedisp_s(env, ipb, &ar);
|
||||
addr = get_address_from_regs(env, ipb, &ar);
|
||||
if (addr & 3) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioinst_disassemble_sch_ident(reg1, &m, &cssid, &ssid, &schid)) {
|
||||
/*
|
||||
* The Ultravisor checks schid bit 16 to be one and bits 0-12
|
||||
* to be 0 and injects a operand exception itself.
|
||||
*
|
||||
* Hence we should never end up here.
|
||||
*/
|
||||
g_assert(!s390_is_pv());
|
||||
/*
|
||||
* As operand exceptions have a lower priority than access exceptions,
|
||||
* we check whether the memory area is writeable (injecting the
|
||||
@@ -273,14 +308,17 @@ void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb,
|
||||
}
|
||||
}
|
||||
if (cc != 3) {
|
||||
if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
|
||||
sizeof(schib)) != 0) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_write(cpu, addr, &schib, sizeof(schib));
|
||||
} else if (s390_cpu_virt_mem_write(cpu, addr, ar, &schib,
|
||||
sizeof(schib)) != 0) {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Access exceptions have a higher priority than cc3 */
|
||||
if (s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
|
||||
if (!s390_is_pv() &&
|
||||
s390_cpu_virt_mem_check_write(cpu, addr, ar, sizeof(schib)) != 0) {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
return;
|
||||
}
|
||||
@@ -303,7 +341,7 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
|
||||
return -EIO;
|
||||
}
|
||||
trace_ioinst_sch_id("tsch", cssid, ssid, schid);
|
||||
addr = decode_basedisp_s(env, ipb, &ar);
|
||||
addr = get_address_from_regs(env, ipb, &ar);
|
||||
if (addr & 3) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
return -EIO;
|
||||
@@ -317,7 +355,9 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
|
||||
}
|
||||
/* 0 - status pending, 1 - not status pending, 3 - not operational */
|
||||
if (cc != 3) {
|
||||
if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_write(cpu, addr, &irb, irb_len);
|
||||
} else if (s390_cpu_virt_mem_write(cpu, addr, ar, &irb, irb_len) != 0) {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
return -EFAULT;
|
||||
}
|
||||
@@ -325,7 +365,8 @@ int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb, uintptr_t ra)
|
||||
} else {
|
||||
irb_len = sizeof(irb) - sizeof(irb.emw);
|
||||
/* Access exceptions have a higher priority than cc3 */
|
||||
if (s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
|
||||
if (!s390_is_pv() &&
|
||||
s390_cpu_virt_mem_check_write(cpu, addr, ar, irb_len) != 0) {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
return -EFAULT;
|
||||
}
|
||||
@@ -601,7 +642,7 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
|
||||
{
|
||||
ChscReq *req;
|
||||
ChscResp *res;
|
||||
uint64_t addr;
|
||||
uint64_t addr = 0;
|
||||
int reg;
|
||||
uint16_t len;
|
||||
uint16_t command;
|
||||
@@ -610,7 +651,9 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
|
||||
|
||||
trace_ioinst("chsc");
|
||||
reg = (ipb >> 20) & 0x00f;
|
||||
addr = env->regs[reg];
|
||||
if (!s390_is_pv()) {
|
||||
addr = env->regs[reg];
|
||||
}
|
||||
/* Page boundary? */
|
||||
if (addr & 0xfff) {
|
||||
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
|
||||
@@ -621,7 +664,9 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
|
||||
* present CHSC sub-handlers ... if we ever need more, we should take
|
||||
* care of req->len here first.
|
||||
*/
|
||||
if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_read(cpu, addr, buf, sizeof(ChscReq));
|
||||
} else if (s390_cpu_virt_mem_read(cpu, addr, reg, buf, sizeof(ChscReq))) {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
return;
|
||||
}
|
||||
@@ -654,11 +699,16 @@ void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb, uintptr_t ra)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
|
||||
be16_to_cpu(res->len))) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_write(cpu, addr + len, res, be16_to_cpu(res->len));
|
||||
setcc(cpu, 0); /* Command execution complete */
|
||||
} else {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
if (!s390_cpu_virt_mem_write(cpu, addr + len, reg, res,
|
||||
be16_to_cpu(res->len))) {
|
||||
setcc(cpu, 0); /* Command execution complete */
|
||||
} else {
|
||||
s390_cpu_virt_mem_handle_exc(cpu, ra);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,11 @@ int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_s390_get_hpage_1m(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_s390_get_ri(void)
|
||||
{
|
||||
return 0;
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include "exec/memattrs.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
#include "hw/s390x/s390-virtio-hcall.h"
|
||||
#include "hw/s390x/pv.h"
|
||||
|
||||
#ifndef DEBUG_KVM
|
||||
#define DEBUG_KVM 0
|
||||
@@ -115,6 +116,8 @@
|
||||
#define ICPT_CPU_STOP 0x28
|
||||
#define ICPT_OPEREXC 0x2c
|
||||
#define ICPT_IO 0x40
|
||||
#define ICPT_PV_INSTR 0x68
|
||||
#define ICPT_PV_INSTR_NOTIFICATION 0x6c
|
||||
|
||||
#define NR_LOCAL_IRQS 32
|
||||
/*
|
||||
@@ -152,6 +155,7 @@ static int cap_ri;
|
||||
static int cap_gs;
|
||||
static int cap_hpage_1m;
|
||||
static int cap_vcpu_resets;
|
||||
static int cap_protected;
|
||||
|
||||
static int active_cmma;
|
||||
|
||||
@@ -321,6 +325,11 @@ void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
|
||||
cap_hpage_1m = 1;
|
||||
}
|
||||
|
||||
int kvm_s390_get_hpage_1m(void)
|
||||
{
|
||||
return cap_hpage_1m;
|
||||
}
|
||||
|
||||
static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
@@ -344,6 +353,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
||||
cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
|
||||
cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
|
||||
cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
|
||||
cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
|
||||
|
||||
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|
||||
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
|
||||
@@ -844,6 +854,30 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf,
|
||||
int len, bool is_write)
|
||||
{
|
||||
struct kvm_s390_mem_op mem_op = {
|
||||
.sida_offset = offset,
|
||||
.size = len,
|
||||
.op = is_write ? KVM_S390_MEMOP_SIDA_WRITE
|
||||
: KVM_S390_MEMOP_SIDA_READ,
|
||||
.buf = (uint64_t)hostbuf,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (!cap_mem_op || !cap_protected) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
|
||||
if (ret < 0) {
|
||||
error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
|
||||
abort();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy layout for s390:
|
||||
* Older S390 KVM requires the topmost vma of the RAM to be
|
||||
@@ -1199,12 +1233,27 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
|
||||
sccb = env->regs[ipbh0 & 0xf];
|
||||
code = env->regs[(ipbh0 & 0xf0) >> 4];
|
||||
|
||||
r = sclp_service_call(env, sccb, code);
|
||||
if (r < 0) {
|
||||
kvm_s390_program_interrupt(cpu, -r);
|
||||
return;
|
||||
switch (run->s390_sieic.icptcode) {
|
||||
case ICPT_PV_INSTR_NOTIFICATION:
|
||||
g_assert(s390_is_pv());
|
||||
/* The notification intercepts are currently handled by KVM */
|
||||
error_report("unexpected SCLP PV notification");
|
||||
exit(1);
|
||||
break;
|
||||
case ICPT_PV_INSTR:
|
||||
g_assert(s390_is_pv());
|
||||
sclp_service_call_protected(env, sccb, code);
|
||||
/* Setting the CC is done by the Ultravisor. */
|
||||
break;
|
||||
case ICPT_INSTRUCTION:
|
||||
g_assert(!s390_is_pv());
|
||||
r = sclp_service_call(env, sccb, code);
|
||||
if (r < 0) {
|
||||
kvm_s390_program_interrupt(cpu, -r);
|
||||
return;
|
||||
}
|
||||
setcc(cpu, r);
|
||||
}
|
||||
setcc(cpu, r);
|
||||
}
|
||||
|
||||
static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
|
||||
@@ -1693,6 +1742,8 @@ static int handle_intercept(S390CPU *cpu)
|
||||
(long)cs->kvm_run->psw_addr);
|
||||
switch (icpt_code) {
|
||||
case ICPT_INSTRUCTION:
|
||||
case ICPT_PV_INSTR:
|
||||
case ICPT_PV_INSTR_NOTIFICATION:
|
||||
r = handle_instruction(cpu, run);
|
||||
break;
|
||||
case ICPT_PROGRAM:
|
||||
@@ -1773,7 +1824,9 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
|
||||
SysIB_322 sysib;
|
||||
int del, i;
|
||||
|
||||
if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
|
||||
} else if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
|
||||
return;
|
||||
}
|
||||
/* Shift the stack of Extended Names to prepare for our own data */
|
||||
@@ -1826,7 +1879,11 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
|
||||
/* Insert UUID */
|
||||
memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
|
||||
|
||||
s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
|
||||
if (s390_is_pv()) {
|
||||
s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib));
|
||||
} else {
|
||||
s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_stsi(S390CPU *cpu)
|
||||
@@ -2368,6 +2425,14 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
|
||||
clear_bit(S390_FEAT_BPB, model->features);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have support for protected virtualization, indicate
|
||||
* the protected virtualization IPL unpack facility.
|
||||
*/
|
||||
if (cap_protected) {
|
||||
set_bit(S390_FEAT_UNPACK, model->features);
|
||||
}
|
||||
|
||||
/* We emulate a zPCI bus and AEN, therefore we don't need HW support */
|
||||
set_bit(S390_FEAT_ZPCI, model->features);
|
||||
set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);
|
||||
|
@@ -19,10 +19,13 @@ void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
|
||||
void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code);
|
||||
int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
|
||||
int len, bool is_write);
|
||||
int kvm_s390_mem_op_pv(S390CPU *cpu, vaddr addr, void *hostbuf, int len,
|
||||
bool is_write);
|
||||
void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code);
|
||||
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
|
||||
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu);
|
||||
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu);
|
||||
int kvm_s390_get_hpage_1m(void);
|
||||
int kvm_s390_get_ri(void);
|
||||
int kvm_s390_get_gs(void);
|
||||
int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
|
||||
|
@@ -474,6 +474,20 @@ static int translate_pages(S390CPU *cpu, vaddr addr, int nr_pages,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s390_cpu_pv_mem_rw(S390CPU *cpu, unsigned int offset, void *hostbuf,
|
||||
int len, bool is_write)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (kvm_enabled()) {
|
||||
ret = kvm_s390_mem_op_pv(cpu, offset, hostbuf, len, is_write);
|
||||
} else {
|
||||
/* Protected Virtualization is a KVM/Hardware only feature */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* s390_cpu_virt_mem_rw:
|
||||
* @laddr: the logical start address
|
||||
|
@@ -64,7 +64,8 @@ echo
|
||||
_launch_qemu -drive id=testdisk,file="$TEST_IMG",backing.file.filename="$TEST_IMG.base"
|
||||
_send_qemu_cmd $QEMU_HANDLE "commit testdisk" "(qemu)"
|
||||
_send_qemu_cmd $QEMU_HANDLE '' '(qemu)'
|
||||
_cleanup_qemu
|
||||
_send_qemu_cmd $QEMU_HANDLE 'quit' ''
|
||||
wait=1 _cleanup_qemu
|
||||
_img_info | _filter_img_info
|
||||
|
||||
# Make sure that if there was a backing file that was just overridden on the
|
||||
@@ -73,7 +74,8 @@ _make_test_img -F raw -b "$TEST_IMG.orig" 64M
|
||||
_launch_qemu -drive id=testdisk,file="$TEST_IMG",backing.file.filename="$TEST_IMG.base",backing.driver=$IMGFMT
|
||||
_send_qemu_cmd $QEMU_HANDLE "commit testdisk" "(qemu)"
|
||||
_send_qemu_cmd $QEMU_HANDLE '' '(qemu)'
|
||||
_cleanup_qemu
|
||||
_send_qemu_cmd $QEMU_HANDLE 'quit' ''
|
||||
wait=1 _cleanup_qemu
|
||||
_img_info | _filter_img_info
|
||||
|
||||
echo
|
||||
|
@@ -11,6 +11,7 @@ virtual size: 64 MiB (67108864 bytes)
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) commit testdisk
|
||||
(qemu)
|
||||
(qemu) quit
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64 MiB (67108864 bytes)
|
||||
@@ -18,6 +19,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t
|
||||
QEMU X.Y.Z monitor - type 'help' for more information
|
||||
(qemu) commit testdisk
|
||||
(qemu)
|
||||
(qemu) quit
|
||||
image: TEST_DIR/t.IMGFMT
|
||||
file format: IMGFMT
|
||||
virtual size: 64 MiB (67108864 bytes)
|
||||
|
@@ -58,6 +58,10 @@ _send_qemu_cmd $QEMU_HANDLE \
|
||||
$QEMU_IO_PROG -f raw -c quit \
|
||||
"nbd+unix:///no_such_export?socket=$SOCK_DIR/nbd" 2>&1 \
|
||||
| _filter_qemu_io | _filter_nbd
|
||||
# Likewise, with longest possible name permitted in NBD protocol
|
||||
$QEMU_IO_PROG -f raw -c quit \
|
||||
"nbd+unix:///$(printf %4096d 1 | tr ' ' a)?socket=$SOCK_DIR/nbd" 2>&1 \
|
||||
| _filter_qemu_io | _filter_nbd | sed 's/aaaa*aa/aa--aa/'
|
||||
|
||||
_send_qemu_cmd $QEMU_HANDLE \
|
||||
"{ 'execute': 'quit' }" \
|
||||
|
@@ -5,6 +5,8 @@ QA output created by 143
|
||||
{"return": {}}
|
||||
qemu-io: can't open device nbd+unix:///no_such_export?socket=SOCK_DIR/nbd: Requested export not available
|
||||
server reported: export 'no_such_export' not present
|
||||
qemu-io: can't open device nbd+unix:///aa--aa1?socket=SOCK_DIR/nbd: Requested export not available
|
||||
server reported: export 'aa--aa...' not present
|
||||
{ 'execute': 'quit' }
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
|
||||
|
@@ -202,7 +202,8 @@ _send_qemu_cmd $QEMU_HANDLE \
|
||||
'return'
|
||||
_run_cmd $QEMU_IMG commit -b "${TEST_IMG}.b" "${TEST_IMG}.c"
|
||||
|
||||
_cleanup_qemu
|
||||
_send_qemu_cmd $QEMU_HANDLE "{ 'execute': 'quit' }" ''
|
||||
wait=1 _cleanup_qemu
|
||||
|
||||
_launch_qemu
|
||||
|
||||
@@ -254,7 +255,8 @@ _send_qemu_cmd $QEMU_HANDLE \
|
||||
|
||||
_run_cmd $QEMU_IO "${TEST_IMG}" -c 'write 0 512'
|
||||
|
||||
_cleanup_qemu
|
||||
_send_qemu_cmd $QEMU_HANDLE "{ 'execute': 'quit' }" ''
|
||||
wait=1 _cleanup_qemu
|
||||
|
||||
echo
|
||||
echo "== Detecting -U and force-share conflicts =="
|
||||
|
@@ -421,6 +421,8 @@ Is another process using the image [TEST_DIR/t.qcow2]?
|
||||
_qemu_img_wrapper commit -b TEST_DIR/t.qcow2.b TEST_DIR/t.qcow2.c
|
||||
{ 'execute': 'qmp_capabilities' }
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
|
||||
{"return": {}}
|
||||
Adding drive
|
||||
{ 'execute': 'human-monitor-command', 'arguments': { 'command-line': 'drive_add 0 if=none,id=d0,file=TEST_DIR/t.IMGFMT' } }
|
||||
{"return": "OKrn"}
|
||||
@@ -454,6 +456,8 @@ Closing the other
|
||||
{"return": ""}
|
||||
|
||||
_qemu_io_wrapper TEST_DIR/t.qcow2 -c write 0 512
|
||||
{"return": {}}
|
||||
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
|
||||
|
||||
== Detecting -U and force-share conflicts ==
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
QA output created by 162
|
||||
|
||||
=== NBD ===
|
||||
qemu-img: Could not open 'json:{"driver": "nbd", "host": -1}': address resolution failed for -1:10809: Name or service not known
|
||||
qemu-img: Could not open 'json:{"driver": "nbd", "host": 42}': Failed to connect socket: Network is unreachable
|
||||
image: nbd://localhost:PORT
|
||||
image: nbd+unix://?socket=42
|
||||
|
||||
|
@@ -24,6 +24,7 @@ PATH=".:$PATH"
|
||||
HOSTOS=$(uname -s)
|
||||
arch=$(uname -m)
|
||||
[[ "$arch" =~ "ppc64" ]] && qemu_arch=ppc64 || qemu_arch="$arch"
|
||||
[[ "$arch" = "i686" ]] && qemu_arch=i386
|
||||
|
||||
# make sure we have a standard umask
|
||||
umask 022
|
||||
|
@@ -76,7 +76,7 @@ _timed_wait_for()
|
||||
timeout=yes
|
||||
|
||||
QEMU_STATUS[$h]=0
|
||||
while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]}
|
||||
while IFS= read -t $((${QEMU_COMM_TIMEOUT}*3)) resp <&${QEMU_OUT[$h]}
|
||||
do
|
||||
if [ -z "${silent}" ] && [ -z "${mismatch_only}" ]; then
|
||||
echo "${resp}" | _filter_testdir | _filter_qemu \
|
||||
|
@@ -182,7 +182,7 @@
|
||||
158 rw auto quick
|
||||
159 rw auto quick
|
||||
160 rw quick
|
||||
161 rw auto quick
|
||||
#DISABLE FOR NOW 161 rw auto quick
|
||||
162 quick
|
||||
163 rw
|
||||
165 rw quick
|
||||
|
@@ -1,3 +1,4 @@
|
||||
#define HW_POISON_H /* avoid poison since we patch against rules it "enforces" */
|
||||
#include "qemu/osdep.h"
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
|
@@ -1777,6 +1777,7 @@ struct fuse_cmdline_opts {
|
||||
int syslog;
|
||||
int log_level;
|
||||
unsigned int max_idle_threads;
|
||||
unsigned long rlimit_nofile;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -23,6 +23,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define FUSE_HELPER_OPT(t, p) \
|
||||
@@ -53,6 +55,7 @@ static const struct fuse_opt fuse_helper_opts[] = {
|
||||
FUSE_HELPER_OPT("subtype=", nodefault_subtype),
|
||||
FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
|
||||
FUSE_HELPER_OPT("--rlimit-nofile=%lu", rlimit_nofile),
|
||||
FUSE_HELPER_OPT("--syslog", syslog),
|
||||
FUSE_HELPER_OPT_VALUE("log_level=debug", log_level, FUSE_LOG_DEBUG),
|
||||
FUSE_HELPER_OPT_VALUE("log_level=info", log_level, FUSE_LOG_INFO),
|
||||
@@ -171,6 +174,10 @@ void fuse_cmdline_help(void)
|
||||
" default: no_writeback\n"
|
||||
" -o xattr|no_xattr enable/disable xattr\n"
|
||||
" default: no_xattr\n"
|
||||
" --rlimit-nofile=<num> set maximum number of file descriptors\n"
|
||||
" (0 leaves rlimit unchanged)\n"
|
||||
" default: min(1000000, fs.file-max - 16384)\n"
|
||||
" if the current rlimit is lower\n"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -191,11 +198,51 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long get_default_rlimit_nofile(void)
|
||||
{
|
||||
g_autofree gchar *file_max_str = NULL;
|
||||
const rlim_t reserved_fds = 16384; /* leave at least this many fds free */
|
||||
rlim_t max_fds = 1000000; /* our default RLIMIT_NOFILE target */
|
||||
rlim_t file_max;
|
||||
struct rlimit rlim;
|
||||
|
||||
/*
|
||||
* Reduce max_fds below the system-wide maximum, if necessary. This
|
||||
* ensures there are fds available for other processes so we don't
|
||||
* cause resource exhaustion.
|
||||
*/
|
||||
if (!g_file_get_contents("/proc/sys/fs/file-max", &file_max_str,
|
||||
NULL, NULL)) {
|
||||
fuse_log(FUSE_LOG_ERR, "can't read /proc/sys/fs/file-max\n");
|
||||
exit(1);
|
||||
}
|
||||
file_max = g_ascii_strtoull(file_max_str, NULL, 10);
|
||||
if (file_max < 2 * reserved_fds) {
|
||||
fuse_log(FUSE_LOG_ERR,
|
||||
"The fs.file-max sysctl is too low (%lu) to allow a "
|
||||
"reasonable number of open files.\n",
|
||||
(unsigned long)file_max);
|
||||
exit(1);
|
||||
}
|
||||
max_fds = MIN(file_max - reserved_fds, max_fds);
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (rlim.rlim_cur >= max_fds) {
|
||||
return 0; /* we have more fds available than required! */
|
||||
}
|
||||
return max_fds;
|
||||
}
|
||||
|
||||
int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts)
|
||||
{
|
||||
memset(opts, 0, sizeof(struct fuse_cmdline_opts));
|
||||
|
||||
opts->max_idle_threads = 10;
|
||||
opts->rlimit_nofile = get_default_rlimit_nofile();
|
||||
opts->foreground = 1;
|
||||
|
||||
if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) ==
|
||||
|
@@ -2707,24 +2707,18 @@ static void setup_sandbox(struct lo_data *lo, struct fuse_session *se,
|
||||
setup_seccomp(enable_syslog);
|
||||
}
|
||||
|
||||
/* Raise the maximum number of open file descriptors */
|
||||
static void setup_nofile_rlimit(void)
|
||||
/* Set the maximum number of open file descriptors */
|
||||
static void setup_nofile_rlimit(unsigned long rlimit_nofile)
|
||||
{
|
||||
const rlim_t max_fds = 1000000;
|
||||
struct rlimit rlim;
|
||||
struct rlimit rlim = {
|
||||
.rlim_cur = rlimit_nofile,
|
||||
.rlim_max = rlimit_nofile,
|
||||
};
|
||||
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
fuse_log(FUSE_LOG_ERR, "getrlimit(RLIMIT_NOFILE): %m\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (rlim.rlim_cur >= max_fds) {
|
||||
if (rlimit_nofile == 0) {
|
||||
return; /* nothing to do */
|
||||
}
|
||||
|
||||
rlim.rlim_cur = max_fds;
|
||||
rlim.rlim_max = max_fds;
|
||||
|
||||
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
|
||||
/* Ignore SELinux denials */
|
||||
if (errno == EPERM) {
|
||||
@@ -2977,7 +2971,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
fuse_daemonize(opts.foreground);
|
||||
|
||||
setup_nofile_rlimit();
|
||||
setup_nofile_rlimit(opts.rlimit_nofile);
|
||||
|
||||
/* Must be before sandbox since it wants /proc */
|
||||
setup_capng();
|
||||
|
@@ -307,7 +307,12 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
|
||||
qemu_mutex_init(&pool->lock);
|
||||
qemu_cond_init(&pool->worker_stopped);
|
||||
qemu_sem_init(&pool->sem, 0);
|
||||
pool->max_threads = 64;
|
||||
if (sizeof(pool) == 4) {
|
||||
/* 32bit systems run out of virtual memory quickly */
|
||||
pool->max_threads = 4;
|
||||
} else {
|
||||
pool->max_threads = 64;
|
||||
}
|
||||
pool->new_thread_bh = aio_bh_new(ctx, spawn_thread_bh_fn, pool);
|
||||
|
||||
QLIST_INIT(&pool->head);
|
||||
|
Reference in New Issue
Block a user