Merge remote-tracking branch 'upstream/master' into main

This commit is contained in:
Andrea Fioraldi 2022-10-17 17:48:40 +02:00
commit 97211a7b7c
87 changed files with 3720 additions and 1104 deletions

View File

@ -77,86 +77,12 @@
do { } while (0)
#endif
#define KVM_MSI_HASHTAB_SIZE 256
struct KVMParkedVcpu {
unsigned long vcpu_id;
int kvm_fd;
QLIST_ENTRY(KVMParkedVcpu) node;
};
enum KVMDirtyRingReaperState {
KVM_DIRTY_RING_REAPER_NONE = 0,
/* The reaper is sleeping */
KVM_DIRTY_RING_REAPER_WAIT,
/* The reaper is reaping for dirty pages */
KVM_DIRTY_RING_REAPER_REAPING,
};
/*
* KVM reaper instance, responsible for collecting the KVM dirty bits
* via the dirty ring.
*/
struct KVMDirtyRingReaper {
/* The reaper thread */
QemuThread reaper_thr;
volatile uint64_t reaper_iteration; /* iteration number of reaper thr */
volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */
};
struct KVMState
{
AccelState parent_obj;
int nr_slots;
int fd;
int vmfd;
int coalesced_mmio;
int coalesced_pio;
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
bool coalesced_flush_in_progress;
int vcpu_events;
int robust_singlestep;
int debugregs;
#ifdef KVM_CAP_SET_GUEST_DEBUG
QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints;
#endif
int max_nested_state_len;
int many_ioeventfds;
int intx_set_mask;
int kvm_shadow_mem;
bool kernel_irqchip_allowed;
bool kernel_irqchip_required;
OnOffAuto kernel_irqchip_split;
bool sync_mmu;
uint64_t manual_dirty_log_protect;
/* The man page (and posix) say ioctl numbers are signed int, but
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
* unsigned, and treating them as signed here can break things */
unsigned irq_set_ioctl;
unsigned int sigmask_len;
GHashTable *gsimap;
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing *irq_routes;
int nr_allocated_irq_routes;
unsigned long *used_gsi_bitmap;
unsigned int gsi_count;
QTAILQ_HEAD(, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE];
#endif
KVMMemoryListener memory_listener;
QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus;
/* For "info mtree -f" to tell if an MR is registered in KVM */
int nr_as;
struct KVMAs {
KVMMemoryListener *ml;
AddressSpace *as;
} *as;
uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */
uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */
struct KVMDirtyRingReaper reaper;
};
KVMState *kvm_state;
bool kvm_kernel_irqchip;
bool kvm_split_irqchip;
@ -3692,6 +3618,8 @@ static void kvm_accel_instance_init(Object *obj)
s->kernel_irqchip_split = ON_OFF_AUTO_AUTO;
/* KVM dirty ring is by default off */
s->kvm_dirty_ring_size = 0;
s->notify_vmexit = NOTIFY_VMEXIT_OPTION_RUN;
s->notify_window = 0;
}
/**
@ -3731,6 +3659,8 @@ static void kvm_accel_class_init(ObjectClass *oc, void *data)
NULL, NULL);
object_class_property_set_description(oc, "dirty-ring-size",
"Size of KVM dirty page ring buffer (default: 0, i.e. use bitmap)");
kvm_arch_accel_class_init(oc);
}
static const TypeInfo kvm_accel_type = {

View File

@ -602,6 +602,42 @@ static int alsa_open(bool in, struct alsa_params_req *req,
return -1;
}
static size_t alsa_buffer_get_free(HWVoiceOut *hw)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *)hw;
snd_pcm_sframes_t avail;
size_t alsa_free, generic_free, generic_in_use;
avail = snd_pcm_avail_update(alsa->handle);
if (avail < 0) {
if (avail == -EPIPE) {
if (!alsa_recover(alsa->handle)) {
avail = snd_pcm_avail_update(alsa->handle);
}
}
if (avail < 0) {
alsa_logerr(avail,
"Could not obtain number of available frames\n");
avail = 0;
}
}
alsa_free = avail * hw->info.bytes_per_frame;
generic_free = audio_generic_buffer_get_free(hw);
generic_in_use = hw->samples * hw->info.bytes_per_frame - generic_free;
if (generic_in_use) {
/*
* This code can only be reached in the unlikely case that
* snd_pcm_avail_update() returned a larger number of frames
* than snd_pcm_writei() could write. Make sure that all
* remaining bytes in the generic buffer can be written.
*/
alsa_free = alsa_free > generic_in_use ? alsa_free - generic_in_use : 0;
}
return alsa_free;
}
static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
@ -916,7 +952,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
.init_out = alsa_init_out,
.fini_out = alsa_fini_out,
.write = alsa_write,
.buffer_get_free = audio_generic_buffer_get_free,
.buffer_get_free = alsa_buffer_get_free,
.run_buffer_out = audio_generic_run_buffer_out,
.enable_out = alsa_enable_out,

View File

@ -986,6 +986,18 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
}
}
/**
* audio_frontend_frames_in() - returns the number of frames the resampling
* code generates from frames_in frames
*
* @sw: audio recording frontend
* @frames_in: number of frames
*/
static size_t audio_frontend_frames_in(SWVoiceIn *sw, size_t frames_in)
{
return (int64_t)frames_in * sw->ratio >> 32;
}
static size_t audio_get_avail (SWVoiceIn *sw)
{
size_t live;
@ -1002,17 +1014,24 @@ static size_t audio_get_avail (SWVoiceIn *sw)
}
ldebug (
"%s: get_avail live %zu ret %" PRId64 "\n",
"%s: get_avail live %zu frontend frames %zu\n",
SW_NAME (sw),
live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame
live, audio_frontend_frames_in(sw, live)
);
return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame;
return live;
}
static size_t audio_sw_bytes_free(SWVoiceOut *sw, size_t free)
/**
* audio_frontend_frames_out() - returns the number of frames needed to
* get frames_out frames after resampling
*
* @sw: audio playback frontend
* @frames_out: number of frames
*/
static size_t audio_frontend_frames_out(SWVoiceOut *sw, size_t frames_out)
{
return (((int64_t)free << 32) / sw->ratio) * sw->info.bytes_per_frame;
return ((int64_t)frames_out << 32) / sw->ratio;
}
static size_t audio_get_free(SWVoiceOut *sw)
@ -1034,8 +1053,8 @@ static size_t audio_get_free(SWVoiceOut *sw)
dead = sw->hw->mix_buf->size - live;
#ifdef DEBUG_OUT
dolog("%s: get_free live %zu dead %zu sw_bytes %zu\n",
SW_NAME(sw), live, dead, audio_sw_bytes_free(sw, dead));
dolog("%s: get_free live %zu dead %zu frontend frames %zu\n",
SW_NAME(sw), live, dead, audio_frontend_frames_out(sw, dead));
#endif
return dead;
@ -1121,8 +1140,12 @@ static void audio_run_out (AudioState *s)
HWVoiceOut *hw = NULL;
SWVoiceOut *sw;
if (!audio_get_pdo_out(s->dev)->mixing_engine) {
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
size_t played, live, prev_rpos;
size_t hw_free = audio_pcm_hw_get_free(hw);
int nb_live;
if (!audio_get_pdo_out(s->dev)->mixing_engine) {
/* there is exactly 1 sw for each hw with no mixeng */
sw = hw->sw_head.lh_first;
@ -1135,16 +1158,16 @@ static void audio_run_out (AudioState *s)
}
if (sw->active) {
sw->callback.fn(sw->callback.opaque, INT_MAX);
sw->callback.fn(sw->callback.opaque,
hw_free * sw->info.bytes_per_frame);
}
}
return;
}
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
size_t played, live, prev_rpos;
size_t hw_free = audio_pcm_hw_get_free(hw);
int nb_live;
if (hw->pcm_ops->run_buffer_out) {
hw->pcm_ops->run_buffer_out(hw);
}
continue;
}
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (sw->active) {
@ -1152,13 +1175,14 @@ static void audio_run_out (AudioState *s)
size_t free;
if (hw_free > sw->total_hw_samples_mixed) {
free = audio_sw_bytes_free(sw,
free = audio_frontend_frames_out(sw,
MIN(sw_free, hw_free - sw->total_hw_samples_mixed));
} else {
free = 0;
}
if (free > 0) {
sw->callback.fn(sw->callback.opaque, free);
sw->callback.fn(sw->callback.opaque,
free * sw->info.bytes_per_frame);
}
}
}
@ -1297,11 +1321,13 @@ static void audio_run_in (AudioState *s)
sw->total_hw_samples_acquired -= min;
if (sw->active) {
size_t sw_avail = audio_get_avail(sw);
size_t avail;
avail = audio_get_avail (sw);
avail = audio_frontend_frames_in(sw, sw_avail);
if (avail > 0) {
sw->callback.fn (sw->callback.opaque, avail);
sw->callback.fn(sw->callback.opaque,
avail * sw->info.bytes_per_frame);
}
}
}
@ -1501,10 +1527,6 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
}
}
if (hw->pcm_ops->run_buffer_out) {
hw->pcm_ops->run_buffer_out(hw);
}
return total;
}
@ -1750,13 +1772,13 @@ static AudioState *audio_init(Audiodev *dev, const char *name)
s->nb_hw_voices_out = audio_get_pdo_out(dev)->voices;
s->nb_hw_voices_in = audio_get_pdo_in(dev)->voices;
if (s->nb_hw_voices_out <= 0) {
if (s->nb_hw_voices_out < 1) {
dolog ("Bogus number of playback voices %d, setting to 1\n",
s->nb_hw_voices_out);
s->nb_hw_voices_out = 1;
}
if (s->nb_hw_voices_in <= 0) {
if (s->nb_hw_voices_in < 0) {
dolog ("Bogus number of capture voices %d, setting to 0\n",
s->nb_hw_voices_in);
s->nb_hw_voices_in = 0;
@ -2251,26 +2273,39 @@ void audio_rate_start(RateCtl *rate)
rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
size_t bytes_avail)
size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info)
{
int64_t now;
int64_t ticks;
int64_t bytes;
int64_t samples;
size_t ret;
int64_t frames;
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ticks = now - rate->start_ticks;
bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
samples = (bytes - rate->bytes_sent) / info->bytes_per_frame;
if (samples < 0 || samples > 65536) {
AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples);
frames = (bytes - rate->bytes_sent) / info->bytes_per_frame;
if (frames < 0 || frames > 65536) {
AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", frames);
audio_rate_start(rate);
samples = 0;
frames = 0;
}
ret = MIN(samples * info->bytes_per_frame, bytes_avail);
rate->bytes_sent += ret;
return ret;
return frames * info->bytes_per_frame;
}
void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used)
{
rate->bytes_sent += bytes_used;
}
size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info,
size_t bytes_avail)
{
size_t bytes;
bytes = audio_rate_peek_bytes(rate, info);
bytes = MIN(bytes, bytes_avail);
audio_rate_add_bytes(rate, bytes);
return bytes;
}

View File

@ -263,7 +263,9 @@ typedef struct RateCtl {
} RateCtl;
void audio_rate_start(RateCtl *rate);
size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info);
void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used);
size_t audio_rate_get_bytes(RateCtl *rate, struct audio_pcm_info *info,
size_t bytes_avail);
static inline size_t audio_ring_dist(size_t dst, size_t src, size_t len)

View File

@ -110,7 +110,11 @@ static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw)
return 0;
}
#ifdef DAC
samples = ((int64_t) sw->HWBUF->size << 32) / sw->ratio;
#else
samples = (int64_t)sw->HWBUF->size * sw->ratio >> 32;
#endif
sw->buf = audio_calloc(__func__, samples, sizeof(struct st_sample));
if (!sw->buf) {

View File

@ -82,7 +82,7 @@ static void *dbus_get_buffer_out(HWVoiceOut *hw, size_t *size)
}
*size = MIN(vo->buf_size - vo->buf_pos, *size);
*size = audio_rate_get_bytes(&hw->info, &vo->rate, *size);
*size = audio_rate_get_bytes(&vo->rate, &hw->info, *size);
return vo->buf + vo->buf_pos;
@ -343,7 +343,7 @@ dbus_read(HWVoiceIn *hw, void *buf, size_t size)
trace_dbus_audio_read(size);
/* size = audio_rate_get_bytes(&hw->info, &vo->rate, size); */
/* size = audio_rate_get_bytes(&vo->rate, &hw->info, size); */
g_hash_table_iter_init(&iter, da->in_listeners);
while (g_hash_table_iter_next(&iter, NULL, (void **)&listener)) {

View File

@ -44,7 +44,7 @@ typedef struct NoVoiceIn {
static size_t no_write(HWVoiceOut *hw, void *buf, size_t len)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
return audio_rate_get_bytes(&hw->info, &no->rate, len);
return audio_rate_get_bytes(&no->rate, &hw->info, len);
}
static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
@ -89,7 +89,7 @@ static void no_fini_in (HWVoiceIn *hw)
static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size);
int64_t bytes = audio_rate_get_bytes(&no->rate, &hw->info, size);
audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame);
return bytes;

View File

@ -72,11 +72,6 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
ilast = *ibuf++;
rate->ipos++;
/* if ipos overflow, there is a infinite loop */
if (rate->ipos == 0xffffffff) {
rate->ipos = 1;
rate->opos = rate->opos & 0xffffffff;
}
/* See if we finished the input buffer yet */
if (ibuf >= iend) {
goto the_end;
@ -85,6 +80,12 @@ void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
icur = *ibuf;
/* wrap ipos and opos around long before they overflow */
if (rate->ipos >= 0x10001) {
rate->ipos = 1;
rate->opos &= 0xffffffff;
}
/* interpolate */
#ifdef FLOAT_MIXENG
#ifdef RECIPROCAL

View File

@ -120,6 +120,13 @@ static void line_out_fini (HWVoiceOut *hw)
spice_server_remove_interface (&out->sin.base);
}
static size_t line_out_get_free(HWVoiceOut *hw)
{
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
return audio_rate_peek_bytes(&out->rate, &hw->info);
}
static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
{
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
@ -133,8 +140,6 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
*size = MIN((out->fsize - out->fpos) << 2, *size);
}
*size = audio_rate_get_bytes(&hw->info, &out->rate, *size);
return out->frame + out->fpos;
}
@ -142,6 +147,8 @@ static size_t line_out_put_buffer(HWVoiceOut *hw, void *buf, size_t size)
{
SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw);
audio_rate_add_bytes(&out->rate, size);
if (buf) {
assert(buf == out->frame + out->fpos && out->fpos <= out->fsize);
out->fpos += size >> 2;
@ -232,10 +239,13 @@ static void line_in_fini (HWVoiceIn *hw)
static size_t line_in_read(HWVoiceIn *hw, void *buf, size_t len)
{
SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw);
uint64_t to_read = audio_rate_get_bytes(&hw->info, &in->rate, len) >> 2;
uint64_t to_read = audio_rate_get_bytes(&in->rate, &hw->info, len) >> 2;
size_t ready = spice_server_record_get_samples(&in->sin, buf, to_read);
/* XXX: do we need this? */
/*
* If the client didn't send new frames, it most likely disconnected.
* Generate silence in this case to avoid a stalled audio stream.
*/
if (ready == 0) {
memset(buf, 0, to_read << 2);
ready = to_read;
@ -282,6 +292,7 @@ static struct audio_pcm_ops audio_callbacks = {
.init_out = line_out_init,
.fini_out = line_out_fini,
.write = audio_generic_write,
.buffer_get_free = line_out_get_free,
.get_buffer_out = line_out_get_buffer,
.put_buffer_out = line_out_put_buffer,
.enable_out = line_out_enable,

View File

@ -42,7 +42,7 @@ typedef struct WAVVoiceOut {
static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len);
int64_t bytes = audio_rate_get_bytes(&wav->rate, &hw->info, len);
assert(bytes % hw->info.bytes_per_frame == 0);
if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) {

File diff suppressed because it is too large Load Diff

View File

@ -113,13 +113,22 @@
# Virtualization, as specified in the AMD64 Architecture
# Programmer's Manual. QEMU command line options related to
# this feature are documented in
# "docs/amd-memory-encryption.txt".
# "docs/system/i386/amd-memory-encryption.rst".
#
# @amd-sev-es: The firmware supports running under AMD Secure Encrypted
# Virtualization - Encrypted State, as specified in the AMD64
# Architecture Programmer's Manual. QEMU command line options
# related to this feature are documented in
# "docs/amd-memory-encryption.txt".
# "docs/system/i386/amd-memory-encryption.rst".
#
# @amd-sev-snp: The firmware supports running under AMD Secure Encrypted
# Virtualization - Secure Nested Paging, as specified in the
# AMD64 Architecture Programmer's Manual. QEMU command line
# options related to this feature are documented in
# "docs/system/i386/amd-memory-encryption.rst".
#
# @intel-tdx: The firmware supports running under Intel Trust Domain
# Extensions (TDX).
#
# @enrolled-keys: The variable store (NVRAM) template associated with
# the firmware binary has the UEFI Secure Boot
@ -185,9 +194,11 @@
# Since: 3.0
##
{ 'enum' : 'FirmwareFeature',
'data' : [ 'acpi-s3', 'acpi-s4', 'amd-sev', 'amd-sev-es', 'enrolled-keys',
'requires-smm', 'secure-boot', 'verbose-dynamic',
'verbose-static' ] }
'data' : [ 'acpi-s3', 'acpi-s4',
'amd-sev', 'amd-sev-es', 'amd-sev-snp',
'intel-tdx',
'enrolled-keys', 'requires-smm', 'secure-boot',
'verbose-dynamic', 'verbose-static' ] }
##
# @FirmwareFlashFile:

View File

@ -22,16 +22,14 @@ maintained as part of the virtio specification.
1af4:1004 SCSI host bus adapter device (legacy)
1af4:1005 entropy generator device (legacy)
1af4:1009 9p filesystem device (legacy)
1af4:1012 vsock device (bug compatibility)
1af4:1041 network device (modern)
1af4:1042 block device (modern)
1af4:1043 console device (modern)
1af4:1044 entropy generator device (modern)
1af4:1045 balloon device (modern)
1af4:1048 SCSI host bus adapter device (modern)
1af4:1049 9p filesystem device (modern)
1af4:1050 virtio gpu device (modern)
1af4:1052 virtio input device (modern)
1af4:1040 Start of ID range for modern virtio devices. The PCI device
to ID is calculated from the virtio device ID by adding the
1af4:10ef 0x1040 offset. The virtio IDs are defined in the virtio
specification. The Linux kernel has a header file with
defines for all virtio IDs (linux/virtio_ids.h), qemu has a
copy in include/standard-headers/.
1af4:10f0 Available for experimental usage without registration. Must get
to official ID when the code leaves the test lab (i.e. when seeking

View File

@ -822,55 +822,6 @@ static void do_cpu_reset(void *opaque)
}
}
/**
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
* by key.
* @fw_cfg: The firmware config instance to store the data in.
* @size_key: The firmware config key to store the size of the loaded
* data under, with fw_cfg_add_i32().
* @data_key: The firmware config key to store the loaded data under,
* with fw_cfg_add_bytes().
* @image_name: The name of the image file to load. If it is NULL, the
* function returns without doing anything.
* @try_decompress: Whether the image should be decompressed (gunzipped) before
* adding it to fw_cfg. If decompression fails, the image is
* loaded as-is.
*
* In case of failure, the function prints an error message to stderr and the
* process exits with status 1.
*/
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
uint16_t data_key, const char *image_name,
bool try_decompress)
{
size_t size = -1;
uint8_t *data;
if (image_name == NULL) {
return;
}
if (try_decompress) {
size = load_image_gzipped_buffer(image_name,
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
}
if (size == (size_t)-1) {
gchar *contents;
gsize length;
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
error_report("failed to load \"%s\"", image_name);
exit(1);
}
size = length;
data = (uint8_t *)contents;
}
fw_cfg_add_i32(fw_cfg, size_key, size);
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
static int do_arm_linux_init(Object *obj, void *opaque)
{
if (object_dynamic_cast(obj, TYPE_ARM_LINUX_BOOT_IF)) {

View File

@ -834,7 +834,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
word alignment, so we keep them for the next line */
/* XXX: keep alignment to speed up transfer */
end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
copy_count = s->cirrus_srcptr_end - end_ptr;
copy_count = MIN(s->cirrus_srcptr_end - end_ptr, CIRRUS_BLTBUFSIZE);
memmove(s->cirrus_bltbuf, end_ptr, copy_count);
s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;

View File

@ -180,8 +180,18 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
if (addr_between(addr, plic->priority_base, plic->num_sources << 2)) {
uint32_t irq = ((addr - plic->priority_base) >> 2) + 1;
plic->source_priority[irq] = value & 7;
sifive_plic_update(plic);
if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
/*
* if "num_priorities + 1" is power-of-2, make each register bit of
* interrupt priority WARL (Write-Any-Read-Legal). Just filter
* out the access to unsupported priority bits.
*/
plic->source_priority[irq] = value % (plic->num_priorities + 1);
sifive_plic_update(plic);
} else if (value <= plic->num_priorities) {
plic->source_priority[irq] = value;
sifive_plic_update(plic);
}
} else if (addr_between(addr, plic->pending_base,
plic->num_sources >> 3)) {
qemu_log_mask(LOG_GUEST_ERROR,
@ -205,7 +215,16 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value,
uint32_t contextid = (addr & (plic->context_stride - 1));
if (contextid == 0) {
if (value <= plic->num_priorities) {
if (((plic->num_priorities + 1) & plic->num_priorities) == 0) {
/*
* if "num_priorities + 1" is power-of-2, each register bit of
* interrupt priority is WARL (Write-Any-Read-Legal). Just
* filter out the access to unsupported priority bits.
*/
plic->target_priority[addrid] = value %
(plic->num_priorities + 1);
sifive_plic_update(plic);
} else if (value <= plic->num_priorities) {
plic->target_priority[addrid] = value;
sifive_plic_update(plic);
}

View File

@ -598,39 +598,6 @@ static void reset_load_elf(void *opaque)
}
}
/* Load an image file into an fw_cfg entry identified by key. */
static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
uint16_t data_key, const char *image_name,
bool try_decompress)
{
size_t size = -1;
uint8_t *data;
if (image_name == NULL) {
return;
}
if (try_decompress) {
size = load_image_gzipped_buffer(image_name,
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
}
if (size == (size_t)-1) {
gchar *contents;
gsize length;
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
error_report("failed to load \"%s\"", image_name);
exit(1);
}
size = length;
data = (uint8_t *)contents;
}
fw_cfg_add_i32(fw_cfg, size_key, size);
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
{
/*

View File

@ -41,6 +41,7 @@
#include "qapi/error.h"
#include "hw/acpi/aml-build.h"
#include "hw/pci/pci_bus.h"
#include "hw/loader.h"
#define FW_CFG_FILE_SLOTS_DFLT 0x20
@ -1221,6 +1222,37 @@ FWCfgState *fw_cfg_find(void)
return FW_CFG(object_resolve_path_type("", TYPE_FW_CFG, NULL));
}
void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
uint16_t data_key, const char *image_name,
bool try_decompress)
{
size_t size = -1;
uint8_t *data;
if (image_name == NULL) {
return;
}
if (try_decompress) {
size = load_image_gzipped_buffer(image_name,
LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
}
if (size == (size_t)-1) {
gchar *contents;
gsize length;
if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
error_report("failed to load \"%s\"", image_name);
exit(1);
}
size = length;
data = (uint8_t *)contents;
}
fw_cfg_add_i32(fw_cfg, size_key, size);
fw_cfg_add_bytes(fw_cfg, data_key, data, size);
}
static void fw_cfg_class_init(ObjectClass *klass, void *data)
{

View File

@ -111,8 +111,8 @@ char *riscv_find_firmware(const char *firmware_filename)
if (filename == NULL) {
if (!qtest_enabled()) {
/*
* We only ship plain binary bios images in the QEMU source.
* With Spike machine that uses ELF images as the default bios,
* We only ship OpenSBI binary bios images in the QEMU source.
* For machines that use images other than the default bios,
* running QEMU test will complain hence let's suppress the error
* report for QEMU testing.
*/
@ -338,3 +338,32 @@ void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr)
riscv_cpu->env.fdt_addr = fdt_addr;
}
}
void riscv_setup_firmware_boot(MachineState *machine)
{
if (machine->kernel_filename) {
FWCfgState *fw_cfg;
fw_cfg = fw_cfg_find();
assert(fw_cfg);
/*
* Expose the kernel, the command line, and the initrd in fw_cfg.
* We don't process them here at all, it's all left to the
* firmware.
*/
load_image_to_fw_cfg(fw_cfg,
FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
machine->kernel_filename,
true);
load_image_to_fw_cfg(fw_cfg,
FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
machine->initrd_filename, false);
if (machine->kernel_cmdline) {
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
strlen(machine->kernel_cmdline) + 1);
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
machine->kernel_cmdline);
}
}
}

View File

@ -1267,7 +1267,30 @@ static void virt_machine_done(Notifier *notifier, void *data)
RISCV64_BIOS_BIN, start_addr, NULL);
}
if (machine->kernel_filename) {
/*
* Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device
* tree cannot be altered and we get FDT_ERR_NOSPACE.
*/
s->fw_cfg = create_fw_cfg(machine);
rom_set_fw(s->fw_cfg);
if (drive_get(IF_PFLASH, 0, 1)) {
/*
* S-mode FW like EDK2 will be kept in second plash (unit 1).
* When both kernel, initrd and pflash options are provided in the
* command line, the kernel and initrd will be copied to the fw_cfg
* table and opensbi will jump to the flash address which is the
* entry point of S-mode FW. It is the job of the S-mode FW to load
* the kernel and initrd using fw_cfg table.
*
* If only pflash is given but not -kernel, then it is the job of
* of the S-mode firmware to locate and load the kernel.
* In either case, the next_addr for opensbi will be the flash address.
*/
riscv_setup_firmware_boot(machine);
kernel_entry = virt_memmap[VIRT_FLASH].base +
virt_memmap[VIRT_FLASH].size / 2;
} else if (machine->kernel_filename) {
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0],
firmware_end_addr);
@ -1300,13 +1323,6 @@ static void virt_machine_done(Notifier *notifier, void *data)
start_addr = virt_memmap[VIRT_FLASH].base;
}
/*
* Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device
* tree cannot be altered and we get FDT_ERR_NOSPACE.
*/
s->fw_cfg = create_fw_cfg(machine);
rom_set_fw(s->fw_cfg);
/* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base,
machine->ram_size, machine->fdt);

View File

@ -2544,6 +2544,7 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
AioContext *ctx;
int ret;
uint32_t blocksize = 2048;
if (!dev->conf.blk) {
/* Anonymous BlockBackend for an empty drive. As we put it into
@ -2553,9 +2554,13 @@ static void scsi_cd_realize(SCSIDevice *dev, Error **errp)
assert(ret == 0);
}
if (dev->conf.physical_block_size != 0) {
blocksize = dev->conf.physical_block_size;
}
ctx = blk_get_aio_context(dev->conf.blk);
aio_context_acquire(ctx);
s->qdev.blocksize = 2048;
s->qdev.blocksize = blocksize;
s->qdev.type = TYPE_ROM;
s->features |= 1 << SCSI_DISK_F_REMOVABLE;
if (!s->product) {

View File

@ -108,18 +108,22 @@ static inline uint8_t div4_round_up(uint8_t dividend)
static void ibex_spi_rxfifo_reset(IbexSPIHostState *s)
{
uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
/* Empty the RX FIFO and assert RXEMPTY */
fifo8_reset(&s->rx_fifo);
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXFULL_MASK;
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_RXEMPTY_MASK;
data = FIELD_DP32(data, STATUS, RXFULL, 0);
data = FIELD_DP32(data, STATUS, RXEMPTY, 1);
s->regs[IBEX_SPI_HOST_STATUS] = data;
}
static void ibex_spi_txfifo_reset(IbexSPIHostState *s)
{
uint32_t data = s->regs[IBEX_SPI_HOST_STATUS];
/* Empty the TX FIFO and assert TXEMPTY */
fifo8_reset(&s->tx_fifo);
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXFULL_MASK;
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_TXEMPTY_MASK;
data = FIELD_DP32(data, STATUS, TXFULL, 0);
data = FIELD_DP32(data, STATUS, TXEMPTY, 1);
s->regs[IBEX_SPI_HOST_STATUS] = data;
}
static void ibex_spi_host_reset(DeviceState *dev)
@ -162,37 +166,38 @@ static void ibex_spi_host_reset(DeviceState *dev)
*/
static void ibex_spi_host_irq(IbexSPIHostState *s)
{
bool error_en = s->regs[IBEX_SPI_HOST_INTR_ENABLE]
& R_INTR_ENABLE_ERROR_MASK;
bool event_en = s->regs[IBEX_SPI_HOST_INTR_ENABLE]
& R_INTR_ENABLE_SPI_EVENT_MASK;
bool err_pending = s->regs[IBEX_SPI_HOST_INTR_STATE]
& R_INTR_STATE_ERROR_MASK;
bool status_pending = s->regs[IBEX_SPI_HOST_INTR_STATE]
& R_INTR_STATE_SPI_EVENT_MASK;
uint32_t intr_test_reg = s->regs[IBEX_SPI_HOST_INTR_TEST];
uint32_t intr_en_reg = s->regs[IBEX_SPI_HOST_INTR_ENABLE];
uint32_t intr_state_reg = s->regs[IBEX_SPI_HOST_INTR_STATE];
uint32_t err_en_reg = s->regs[IBEX_SPI_HOST_ERROR_ENABLE];
uint32_t event_en_reg = s->regs[IBEX_SPI_HOST_EVENT_ENABLE];
uint32_t err_status_reg = s->regs[IBEX_SPI_HOST_ERROR_STATUS];
uint32_t status_reg = s->regs[IBEX_SPI_HOST_STATUS];
bool error_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, ERROR);
bool event_en = FIELD_EX32(intr_en_reg, INTR_ENABLE, SPI_EVENT);
bool err_pending = FIELD_EX32(intr_state_reg, INTR_STATE, ERROR);
bool status_pending = FIELD_EX32(intr_state_reg, INTR_STATE, SPI_EVENT);
int err_irq = 0, event_irq = 0;
/* Error IRQ enabled and Error IRQ Cleared */
if (error_en && !err_pending) {
/* Event enabled, Interrupt Test Error */
if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_ERROR_MASK) {
if (FIELD_EX32(intr_test_reg, INTR_TEST, ERROR)) {
err_irq = 1;
} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
& R_ERROR_ENABLE_CMDBUSY_MASK) &&
s->regs[IBEX_SPI_HOST_ERROR_STATUS]
& R_ERROR_STATUS_CMDBUSY_MASK) {
} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CMDBUSY) &&
FIELD_EX32(err_status_reg, ERROR_STATUS, CMDBUSY)) {
/* Wrote to COMMAND when not READY */
err_irq = 1;
} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
& R_ERROR_ENABLE_CMDINVAL_MASK) &&
s->regs[IBEX_SPI_HOST_ERROR_STATUS]
& R_ERROR_STATUS_CMDINVAL_MASK) {
} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CMDINVAL) &&
FIELD_EX32(err_status_reg, ERROR_STATUS, CMDINVAL)) {
/* Invalid command segment */
err_irq = 1;
} else if ((s->regs[IBEX_SPI_HOST_ERROR_ENABLE]
& R_ERROR_ENABLE_CSIDINVAL_MASK) &&
s->regs[IBEX_SPI_HOST_ERROR_STATUS]
& R_ERROR_STATUS_CSIDINVAL_MASK) {
} else if (FIELD_EX32(err_en_reg, ERROR_ENABLE, CSIDINVAL) &&
FIELD_EX32(err_status_reg, ERROR_STATUS, CSIDINVAL)) {
/* Invalid value for CSID */
err_irq = 1;
}
@ -204,22 +209,19 @@ static void ibex_spi_host_irq(IbexSPIHostState *s)
/* Event IRQ Enabled and Event IRQ Cleared */
if (event_en && !status_pending) {
if (s->regs[IBEX_SPI_HOST_INTR_TEST] & R_INTR_TEST_SPI_EVENT_MASK) {
if (FIELD_EX32(intr_test_reg, INTR_STATE, SPI_EVENT)) {
/* Event enabled, Interrupt Test Event */
event_irq = 1;
} else if ((s->regs[IBEX_SPI_HOST_EVENT_ENABLE]
& R_EVENT_ENABLE_READY_MASK) &&
(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_READY_MASK)) {
} else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, READY) &&
FIELD_EX32(status_reg, STATUS, READY)) {
/* SPI Host ready for next command */
event_irq = 1;
} else if ((s->regs[IBEX_SPI_HOST_EVENT_ENABLE]
& R_EVENT_ENABLE_TXEMPTY_MASK) &&
(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_TXEMPTY_MASK)) {
} else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, TXEMPTY) &&
FIELD_EX32(status_reg, STATUS, TXEMPTY)) {
/* SPI TXEMPTY, TXFIFO drained */
event_irq = 1;
} else if ((s->regs[IBEX_SPI_HOST_EVENT_ENABLE]
& R_EVENT_ENABLE_RXFULL_MASK) &&
(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_RXFULL_MASK)) {
} else if (FIELD_EX32(event_en_reg, EVENT_ENABLE, RXFULL) &&
FIELD_EX32(status_reg, STATUS, RXFULL)) {
/* SPI RXFULL, RXFIFO full */
event_irq = 1;
}
@ -232,10 +234,11 @@ static void ibex_spi_host_irq(IbexSPIHostState *s)
static void ibex_spi_host_transfer(IbexSPIHostState *s)
{
uint32_t rx, tx;
uint32_t rx, tx, data;
/* Get num of one byte transfers */
uint8_t segment_len = ((s->regs[IBEX_SPI_HOST_COMMAND] & R_COMMAND_LEN_MASK)
>> R_COMMAND_LEN_SHIFT);
uint8_t segment_len = FIELD_EX32(s->regs[IBEX_SPI_HOST_COMMAND],
COMMAND, LEN);
while (segment_len > 0) {
if (fifo8_is_empty(&s->tx_fifo)) {
/* Assert Stall */
@ -262,22 +265,21 @@ static void ibex_spi_host_transfer(IbexSPIHostState *s)
--segment_len;
}
data = s->regs[IBEX_SPI_HOST_STATUS];
/* Assert Ready */
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_READY_MASK;
data = FIELD_DP32(data, STATUS, READY, 1);
/* Set RXQD */
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXQD_MASK;
s->regs[IBEX_SPI_HOST_STATUS] |= (R_STATUS_RXQD_MASK
& div4_round_up(segment_len));
data = FIELD_DP32(data, STATUS, RXQD, div4_round_up(segment_len));
/* Set TXQD */
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXQD_MASK;
s->regs[IBEX_SPI_HOST_STATUS] |= (fifo8_num_used(&s->tx_fifo) / 4)
& R_STATUS_TXQD_MASK;
data = FIELD_DP32(data, STATUS, TXQD, fifo8_num_used(&s->tx_fifo) / 4);
/* Clear TXFULL */
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXFULL_MASK;
/* Assert TXEMPTY and drop remaining bytes that exceed segment_len */
ibex_spi_txfifo_reset(s);
data = FIELD_DP32(data, STATUS, TXFULL, 0);
/* Reset RXEMPTY */
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_RXEMPTY_MASK;
data = FIELD_DP32(data, STATUS, RXEMPTY, 0);
/* Update register status */
s->regs[IBEX_SPI_HOST_STATUS] = data;
/* Drop remaining bytes that exceed segment_len */
ibex_spi_txfifo_reset(s);
ibex_spi_host_irq(s);
}
@ -340,7 +342,7 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
{
IbexSPIHostState *s = opaque;
uint32_t val32 = val64;
uint32_t shift_mask = 0xff;
uint32_t shift_mask = 0xff, status = 0, data = 0;
uint8_t txqd_len;
trace_ibex_spi_host_write(addr, size, val64);
@ -350,7 +352,17 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
switch (addr) {
/* Skipping any R/O registers */
case IBEX_SPI_HOST_INTR_STATE...IBEX_SPI_HOST_INTR_ENABLE:
case IBEX_SPI_HOST_INTR_STATE:
/* rw1c status register */
if (FIELD_EX32(val32, INTR_STATE, ERROR)) {
data = FIELD_DP32(data, INTR_STATE, ERROR, 0);
}
if (FIELD_EX32(val32, INTR_STATE, SPI_EVENT)) {
data = FIELD_DP32(data, INTR_STATE, SPI_EVENT, 0);
}
s->regs[addr] = data;
break;
case IBEX_SPI_HOST_INTR_ENABLE:
s->regs[addr] = val32;
break;
case IBEX_SPI_HOST_INTR_TEST:
@ -397,22 +409,24 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
s->regs[addr] = val32;
/* STALL, IP not enabled */
if (!(s->regs[IBEX_SPI_HOST_CONTROL] & R_CONTROL_SPIEN_MASK)) {
if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_CONTROL],
CONTROL, SPIEN))) {
return;
}
/* SPI not ready, IRQ Error */
if (!(s->regs[IBEX_SPI_HOST_STATUS] & R_STATUS_READY_MASK)) {
if (!(FIELD_EX32(s->regs[IBEX_SPI_HOST_STATUS],
STATUS, READY))) {
s->regs[IBEX_SPI_HOST_ERROR_STATUS] |= R_ERROR_STATUS_CMDBUSY_MASK;
ibex_spi_host_irq(s);
return;
}
/* Assert Not Ready */
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_READY_MASK;
if (((val32 & R_COMMAND_DIRECTION_MASK) >> R_COMMAND_DIRECTION_SHIFT)
!= BIDIRECTIONAL_TRANSFER) {
qemu_log_mask(LOG_UNIMP,
if (FIELD_EX32(val32, COMMAND, DIRECTION) != BIDIRECTIONAL_TRANSFER) {
qemu_log_mask(LOG_UNIMP,
"%s: Rx Only/Tx Only are not supported\n", __func__);
}
@ -452,8 +466,8 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
return;
}
/* Byte ordering is set by the IP */
if ((s->regs[IBEX_SPI_HOST_STATUS] &
R_STATUS_BYTEORDER_MASK) == 0) {
status = s->regs[IBEX_SPI_HOST_STATUS];
if (FIELD_EX32(status, STATUS, BYTEORDER) == 0) {
/* LE: LSB transmitted first (default for ibex processor) */
shift_mask = 0xff << (i * 8);
} else {
@ -464,18 +478,18 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
fifo8_push(&s->tx_fifo, (val32 & shift_mask) >> (i * 8));
}
status = s->regs[IBEX_SPI_HOST_STATUS];
/* Reset TXEMPTY */
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXEMPTY_MASK;
status = FIELD_DP32(status, STATUS, TXEMPTY, 0);
/* Update TXQD */
txqd_len = (s->regs[IBEX_SPI_HOST_STATUS] &
R_STATUS_TXQD_MASK) >> R_STATUS_TXQD_SHIFT;
txqd_len = FIELD_EX32(status, STATUS, TXQD);
/* Partial bytes (size < 4) are padded, in words. */
txqd_len += 1;
s->regs[IBEX_SPI_HOST_STATUS] &= ~R_STATUS_TXQD_MASK;
s->regs[IBEX_SPI_HOST_STATUS] |= txqd_len;
status = FIELD_DP32(status, STATUS, TXQD, txqd_len);
/* Assert Ready */
s->regs[IBEX_SPI_HOST_STATUS] |= R_STATUS_READY_MASK;
status = FIELD_DP32(status, STATUS, READY, 1);
/* Update register status */
s->regs[IBEX_SPI_HOST_STATUS] = status;
break;
case IBEX_SPI_HOST_ERROR_ENABLE:
s->regs[addr] = val32;
@ -491,7 +505,27 @@ static void ibex_spi_host_write(void *opaque, hwaddr addr,
* When an error occurs, the corresponding bit must be cleared
* here before issuing any further commands
*/
s->regs[addr] = val32;
status = s->regs[addr];
/* rw1c status register */
if (FIELD_EX32(val32, ERROR_STATUS, CMDBUSY)) {
status = FIELD_DP32(status, ERROR_STATUS, CMDBUSY, 0);
}
if (FIELD_EX32(val32, ERROR_STATUS, OVERFLOW)) {
status = FIELD_DP32(status, ERROR_STATUS, OVERFLOW, 0);
}
if (FIELD_EX32(val32, ERROR_STATUS, UNDERFLOW)) {
status = FIELD_DP32(status, ERROR_STATUS, UNDERFLOW, 0);
}
if (FIELD_EX32(val32, ERROR_STATUS, CMDINVAL)) {
status = FIELD_DP32(status, ERROR_STATUS, CMDINVAL, 0);
}
if (FIELD_EX32(val32, ERROR_STATUS, CSIDINVAL)) {
status = FIELD_DP32(status, ERROR_STATUS, CSIDINVAL, 0);
}
if (FIELD_EX32(val32, ERROR_STATUS, ACCESSINVAL)) {
status = FIELD_DP32(status, ERROR_STATUS, ACCESSINVAL, 0);
}
s->regs[addr] = status;
break;
case IBEX_SPI_HOST_EVENT_ENABLE:
/* Controls which classes of SPI events raise an interrupt. */

View File

@ -74,8 +74,6 @@ static void virtio_iommu_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_iommu_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
device_class_set_props(dc, virtio_iommu_pci_properties);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_IOMMU;
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS;
dc->hotpluggable = false;
@ -90,7 +88,7 @@ static void virtio_iommu_pci_instance_init(Object *obj)
}
static const VirtioPCIDeviceTypeInfo virtio_iommu_pci_info = {
.generic_name = TYPE_VIRTIO_IOMMU_PCI,
.generic_name = TYPE_VIRTIO_IOMMU_PCI,
.instance_size = sizeof(VirtIOIOMMUPCI),
.instance_init = virtio_iommu_pci_instance_init,
.class_init = virtio_iommu_pci_class_init,

View File

@ -104,8 +104,6 @@ static void virtio_mem_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_mem_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_MEM;
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS;

View File

@ -1688,7 +1688,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
pci_set_word(config + PCI_VENDOR_ID,
PCI_VENDOR_ID_REDHAT_QUMRANET);
pci_set_word(config + PCI_DEVICE_ID,
0x1040 + virtio_bus_get_vdev_id(bus));
PCI_DEVICE_ID_VIRTIO_10_BASE + virtio_bus_get_vdev_id(bus));
pci_config_set_revision(config, 1);
}
config[PCI_INTERRUPT_PIN] = 1;

View File

@ -90,8 +90,6 @@ static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_pmem_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_PMEM;
pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
pcidev_k->class_id = PCI_CLASS_OTHERS;

View File

@ -364,4 +364,25 @@ bool fw_cfg_dma_enabled(void *opaque);
*/
const char *fw_cfg_arch_key_name(uint16_t key);
/**
* load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
* by key.
* @fw_cfg: The firmware config instance to store the data in.
* @size_key: The firmware config key to store the size of the loaded
* data under, with fw_cfg_add_i32().
* @data_key: The firmware config key to store the loaded data under,
* with fw_cfg_add_bytes().
* @image_name: The name of the image file to load. If it is NULL, the
* function returns without doing anything.
* @try_decompress: Whether the image should be decompressed (gunzipped) before
* adding it to fw_cfg. If decompression fails, the image is
* loaded as-is.
*
* In case of failure, the function prints an error message to stderr and the
* process exits with status 1.
*/
void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
uint16_t data_key, const char *image_name,
bool try_decompress);
#endif

View File

@ -76,6 +76,7 @@ extern bool pci_available;
#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
#define PCI_SUBDEVICE_ID_QEMU 0x1100
/* legacy virtio-pci devices */
#define PCI_DEVICE_ID_VIRTIO_NET 0x1000
#define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001
#define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002
@ -84,9 +85,15 @@ extern bool pci_available;
#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
#define PCI_DEVICE_ID_VIRTIO_9P 0x1009
#define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012
#define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013
#define PCI_DEVICE_ID_VIRTIO_IOMMU 0x1014
#define PCI_DEVICE_ID_VIRTIO_MEM 0x1015
/*
* modern virtio-pci devices get their id assigned automatically,
* there is no need to add #defines here. It gets calculated as
*
* PCI_DEVICE_ID = PCI_DEVICE_ID_VIRTIO_10_BASE +
* virtio_bus_get_vdev_id(bus)
*/
#define PCI_DEVICE_ID_VIRTIO_10_BASE 0x1040
#define PCI_VENDOR_ID_REDHAT 0x1b36
#define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001

View File

@ -57,5 +57,6 @@ void riscv_rom_copy_firmware_info(MachineState *machine, hwaddr rom_base,
uint32_t reset_vec_size,
uint64_t kernel_entry);
void riscv_setup_direct_kernel(hwaddr kernel_addr, hwaddr fdt_addr);
void riscv_setup_firmware_boot(MachineState *machine);
#endif /* RISCV_BOOT_H */

View File

@ -40,7 +40,7 @@
OBJECT_CHECK(IbexSPIHostState, (obj), TYPE_IBEX_SPI_HOST)
/* SPI Registers */
#define IBEX_SPI_HOST_INTR_STATE (0x00 / 4) /* rw */
#define IBEX_SPI_HOST_INTR_STATE (0x00 / 4) /* rw1c */
#define IBEX_SPI_HOST_INTR_ENABLE (0x04 / 4) /* rw */
#define IBEX_SPI_HOST_INTR_TEST (0x08 / 4) /* wo */
#define IBEX_SPI_HOST_ALERT_TEST (0x0c / 4) /* wo */
@ -54,7 +54,7 @@
#define IBEX_SPI_HOST_TXDATA (0x28 / 4)
#define IBEX_SPI_HOST_ERROR_ENABLE (0x2c / 4) /* rw */
#define IBEX_SPI_HOST_ERROR_STATUS (0x30 / 4) /* rw */
#define IBEX_SPI_HOST_ERROR_STATUS (0x30 / 4) /* rw1c */
#define IBEX_SPI_HOST_EVENT_ENABLE (0x34 / 4) /* rw */
/* FIFO Len in Bytes */

View File

@ -41,7 +41,10 @@ struct QIOChannelCommand {
QIOChannel parent;
int writefd;
int readfd;
pid_t pid;
GPid pid;
#ifdef WIN32
bool blocking;
#endif
};

View File

@ -349,6 +349,8 @@ bool kvm_device_supported(int vmfd, uint64_t type);
extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
void kvm_arch_accel_class_init(ObjectClass *oc);
void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run);
MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run);

View File

@ -10,6 +10,7 @@
#define QEMU_KVM_INT_H
#include "exec/memory.h"
#include "qapi/qapi-types-common.h"
#include "qemu/accel.h"
#include "sysemu/kvm.h"
@ -36,6 +37,81 @@ typedef struct KVMMemoryListener {
int as_id;
} KVMMemoryListener;
#define KVM_MSI_HASHTAB_SIZE 256
enum KVMDirtyRingReaperState {
KVM_DIRTY_RING_REAPER_NONE = 0,
/* The reaper is sleeping */
KVM_DIRTY_RING_REAPER_WAIT,
/* The reaper is reaping for dirty pages */
KVM_DIRTY_RING_REAPER_REAPING,
};
/*
* KVM reaper instance, responsible for collecting the KVM dirty bits
* via the dirty ring.
*/
struct KVMDirtyRingReaper {
/* The reaper thread */
QemuThread reaper_thr;
volatile uint64_t reaper_iteration; /* iteration number of reaper thr */
volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */
};
struct KVMState
{
AccelState parent_obj;
int nr_slots;
int fd;
int vmfd;
int coalesced_mmio;
int coalesced_pio;
struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
bool coalesced_flush_in_progress;
int vcpu_events;
int robust_singlestep;
int debugregs;
#ifdef KVM_CAP_SET_GUEST_DEBUG
QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints;
#endif
int max_nested_state_len;
int many_ioeventfds;
int intx_set_mask;
int kvm_shadow_mem;
bool kernel_irqchip_allowed;
bool kernel_irqchip_required;
OnOffAuto kernel_irqchip_split;
bool sync_mmu;
uint64_t manual_dirty_log_protect;
/* The man page (and posix) say ioctl numbers are signed int, but
* they're not. Linux, glibc and *BSD all treat ioctl numbers as
* unsigned, and treating them as signed here can break things */
unsigned irq_set_ioctl;
unsigned int sigmask_len;
GHashTable *gsimap;
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing *irq_routes;
int nr_allocated_irq_routes;
unsigned long *used_gsi_bitmap;
unsigned int gsi_count;
QTAILQ_HEAD(, KVMMSIRoute) msi_hashtab[KVM_MSI_HASHTAB_SIZE];
#endif
KVMMemoryListener memory_listener;
QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus;
/* For "info mtree -f" to tell if an MR is registered in KVM */
int nr_as;
struct KVMAs {
KVMMemoryListener *ml;
AddressSpace *as;
} *as;
uint64_t kvm_dirty_ring_bytes; /* Size of the per-vcpu dirty ring */
uint32_t kvm_dirty_ring_size; /* Number of dirty GFNs per ring */
struct KVMDirtyRingReaper reaper;
NotifyVmexitOption notify_vmexit;
uint32_t notify_window;
};
void kvm_memory_listener_register(KVMState *s, KVMMemoryListener *kml,
AddressSpace *as, int as_id, const char *name);

View File

@ -26,12 +26,11 @@
#include "qemu/sockets.h"
#include "trace.h"
#ifndef WIN32
/**
* qio_channel_command_new_pid:
* @writefd: the FD connected to the command's stdin
* @readfd: the FD connected to the command's stdout
* @pid: the PID of the running child command
* @pid: the PID/HANDLE of the running child command
* @errp: pointer to a NULL-initialized error object
*
* Create a channel for performing I/O with the
@ -50,7 +49,7 @@
static QIOChannelCommand *
qio_channel_command_new_pid(int writefd,
int readfd,
pid_t pid)
GPid pid)
{
QIOChannelCommand *ioc;
@ -60,7 +59,13 @@ qio_channel_command_new_pid(int writefd,
ioc->writefd = writefd;
ioc->pid = pid;
trace_qio_channel_command_new_pid(ioc, writefd, readfd, pid);
trace_qio_channel_command_new_pid(ioc, writefd, readfd,
#ifdef WIN32
GetProcessId(pid)
#else
pid
#endif
);
return ioc;
}
@ -69,108 +74,26 @@ qio_channel_command_new_spawn(const char *const argv[],
int flags,
Error **errp)
{
pid_t pid = -1;
int stdinfd[2] = { -1, -1 };
int stdoutfd[2] = { -1, -1 };
int devnull = -1;
bool stdinnull = false, stdoutnull = false;
QIOChannelCommand *ioc;
g_autoptr(GError) err = NULL;
GPid pid = 0;
GSpawnFlags gflags = G_SPAWN_CLOEXEC_PIPES | G_SPAWN_DO_NOT_REAP_CHILD;
int stdinfd = -1, stdoutfd = -1;
flags = flags & O_ACCMODE;
gflags |= flags == O_WRONLY ? G_SPAWN_STDOUT_TO_DEV_NULL : 0;
if (flags == O_RDONLY) {
stdinnull = true;
}
if (flags == O_WRONLY) {
stdoutnull = true;
if (!g_spawn_async_with_pipes(NULL, (char **)argv, NULL, gflags, NULL, NULL,
&pid,
flags == O_RDONLY ? NULL : &stdinfd,
flags == O_WRONLY ? NULL : &stdoutfd,
NULL, &err)) {
error_setg(errp, "%s", err->message);
return NULL;
}
if (stdinnull || stdoutnull) {
devnull = open("/dev/null", O_RDWR);
if (devnull < 0) {
error_setg_errno(errp, errno,
"Unable to open /dev/null");
goto error;
}
}
if ((!stdinnull && !g_unix_open_pipe(stdinfd, FD_CLOEXEC, NULL)) ||
(!stdoutnull && !g_unix_open_pipe(stdoutfd, FD_CLOEXEC, NULL))) {
error_setg_errno(errp, errno,
"Unable to open pipe");
goto error;
}
pid = qemu_fork(errp);
if (pid < 0) {
goto error;
}
if (pid == 0) { /* child */
dup2(stdinnull ? devnull : stdinfd[0], STDIN_FILENO);
dup2(stdoutnull ? devnull : stdoutfd[1], STDOUT_FILENO);
/* Leave stderr connected to qemu's stderr */
if (!stdinnull) {
close(stdinfd[0]);
close(stdinfd[1]);
}
if (!stdoutnull) {
close(stdoutfd[0]);
close(stdoutfd[1]);
}
if (devnull != -1) {
close(devnull);
}
execv(argv[0], (char * const *)argv);
_exit(1);
}
if (!stdinnull) {
close(stdinfd[0]);
}
if (!stdoutnull) {
close(stdoutfd[1]);
}
ioc = qio_channel_command_new_pid(stdinnull ? devnull : stdinfd[1],
stdoutnull ? devnull : stdoutfd[0],
pid);
trace_qio_channel_command_new_spawn(ioc, argv[0], flags);
return ioc;
error:
if (devnull != -1) {
close(devnull);
}
if (stdinfd[0] != -1) {
close(stdinfd[0]);
}
if (stdinfd[1] != -1) {
close(stdinfd[1]);
}
if (stdoutfd[0] != -1) {
close(stdoutfd[0]);
}
if (stdoutfd[1] != -1) {
close(stdoutfd[1]);
}
return NULL;
return qio_channel_command_new_pid(stdinfd, stdoutfd, pid);
}
#else /* WIN32 */
QIOChannelCommand *
qio_channel_command_new_spawn(const char *const argv[],
int flags,
Error **errp)
{
error_setg_errno(errp, ENOSYS,
"Command spawn not supported on this platform");
return NULL;
}
#endif /* WIN32 */
#ifndef WIN32
static int qio_channel_command_abort(QIOChannelCommand *ioc,
Error **errp)
@ -213,6 +136,23 @@ static int qio_channel_command_abort(QIOChannelCommand *ioc,
return 0;
}
#else
static int qio_channel_command_abort(QIOChannelCommand *ioc,
Error **errp)
{
DWORD ret;
TerminateProcess(ioc->pid, 0);
ret = WaitForSingleObject(ioc->pid, 1000);
if (ret != WAIT_OBJECT_0) {
error_setg(errp,
"Process %llu refused to die",
(unsigned long long)GetProcessId(ioc->pid));
return -1;
}
return 0;
}
#endif /* ! WIN32 */
@ -221,7 +161,7 @@ static void qio_channel_command_init(Object *obj)
QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj);
ioc->readfd = -1;
ioc->writefd = -1;
ioc->pid = -1;
ioc->pid = 0;
}
static void qio_channel_command_finalize(Object *obj)
@ -236,12 +176,27 @@ static void qio_channel_command_finalize(Object *obj)
}
ioc->writefd = ioc->readfd = -1;
if (ioc->pid > 0) {
#ifndef WIN32
qio_channel_command_abort(ioc, NULL);
#endif
g_spawn_close_pid(ioc->pid);
}
}
#ifdef WIN32
static bool win32_fd_poll(int fd, gushort events)
{
GPollFD pfd = { .fd = _get_osfhandle(fd), .events = events };
int res;
do {
res = g_poll(&pfd, 1, 0);
} while (res < 0 && errno == EINTR);
if (res == 0) {
return false;
}
return true;
}
#endif
static ssize_t qio_channel_command_readv(QIOChannel *ioc,
const struct iovec *iov,
@ -253,6 +208,12 @@ static ssize_t qio_channel_command_readv(QIOChannel *ioc,
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
ssize_t ret;
#ifdef WIN32
if (!cioc->blocking && !win32_fd_poll(cioc->readfd, G_IO_IN)) {
return QIO_CHANNEL_ERR_BLOCK;
}
#endif
retry:
ret = readv(cioc->readfd, iov, niov);
if (ret < 0) {
@ -282,6 +243,12 @@ static ssize_t qio_channel_command_writev(QIOChannel *ioc,
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
ssize_t ret;
#ifdef WIN32
if (!cioc->blocking && !win32_fd_poll(cioc->writefd, G_IO_OUT)) {
return QIO_CHANNEL_ERR_BLOCK;
}
#endif
retry:
ret = writev(cioc->writefd, iov, niov);
if (ret <= 0) {
@ -302,14 +269,14 @@ static int qio_channel_command_set_blocking(QIOChannel *ioc,
bool enabled,
Error **errp)
{
#ifdef WIN32
/* command spawn is not supported on win32 */
g_assert_not_reached();
#else
QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
if (!g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL) ||
!g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL)) {
#ifdef WIN32
cioc->blocking = enabled;
#else
if ((cioc->writefd >= 0 && !g_unix_set_fd_nonblocking(cioc->writefd, !enabled, NULL)) ||
(cioc->readfd >= 0 && !g_unix_set_fd_nonblocking(cioc->readfd, !enabled, NULL))) {
error_setg_errno(errp, errno, "Failed to set FD nonblocking");
return -1;
}
@ -350,6 +317,8 @@ static int qio_channel_command_close(QIOChannel *ioc,
(unsigned long long)cioc->pid);
return -1;
}
#else
WaitForSingleObject(cioc->pid, INFINITE);
#endif
if (rv < 0) {

View File

@ -24,6 +24,10 @@
/* from the Linux kernel - /arch/x86/include/uapi/asm/sigcontext.h */
#define TARGET_FP_XSTATE_MAGIC1 0x46505853U /* FPXS */
#define TARGET_FP_XSTATE_MAGIC2 0x46505845U /* FPXE */
#define TARGET_FP_XSTATE_MAGIC2_SIZE 4
struct target_fpreg {
uint16_t significand[4];
uint16_t exponent;
@ -39,6 +43,35 @@ struct target_xmmreg {
uint32_t element[4];
};
struct target_fpx_sw_bytes {
uint32_t magic1;
uint32_t extended_size;
uint64_t xfeatures;
uint32_t xstate_size;
uint32_t reserved[7];
};
QEMU_BUILD_BUG_ON(sizeof(struct target_fpx_sw_bytes) != 12*4);
struct target_fpstate_fxsave {
/* FXSAVE format */
uint16_t cw;
uint16_t sw;
uint16_t twd;
uint16_t fop;
uint64_t rip;
uint64_t rdp;
uint32_t mxcsr;
uint32_t mxcsr_mask;
uint32_t st_space[32];
uint32_t xmm_space[64];
uint32_t hw_reserved[12];
struct target_fpx_sw_bytes sw_reserved;
uint8_t xfeatures[];
};
#define TARGET_FXSAVE_SIZE sizeof(struct target_fpstate_fxsave)
QEMU_BUILD_BUG_ON(TARGET_FXSAVE_SIZE != 512);
QEMU_BUILD_BUG_ON(offsetof(struct target_fpstate_fxsave, sw_reserved) != 464);
struct target_fpstate_32 {
/* Regular FPU environment */
uint32_t cw;
@ -51,35 +84,21 @@ struct target_fpstate_32 {
struct target_fpreg st[8];
uint16_t status;
uint16_t magic; /* 0xffff = regular FPU data only */
/* FXSR FPU environment */
uint32_t _fxsr_env[6]; /* FXSR FPU env is ignored */
uint32_t mxcsr;
uint32_t reserved;
struct target_fpxreg fxsr_st[8]; /* FXSR FPU reg data is ignored */
struct target_xmmreg xmm[8];
uint32_t padding[56];
struct target_fpstate_fxsave fxsave;
};
struct target_fpstate_64 {
/* FXSAVE format */
uint16_t cw;
uint16_t sw;
uint16_t twd;
uint16_t fop;
uint64_t rip;
uint64_t rdp;
uint32_t mxcsr;
uint32_t mxcsr_mask;
uint32_t st_space[32];
uint32_t xmm_space[64];
uint32_t reserved[24];
};
/*
* For simplicity, setup_frame aligns struct target_fpstate_32 to
* 16 bytes, so ensure that the FXSAVE area is also aligned.
*/
QEMU_BUILD_BUG_ON(offsetof(struct target_fpstate_32, fxsave) & 15);
#ifndef TARGET_X86_64
# define target_fpstate target_fpstate_32
# define TARGET_FPSTATE_FXSAVE_OFFSET offsetof(struct target_fpstate_32, fxsave)
#else
# define target_fpstate target_fpstate_64
# define target_fpstate target_fpstate_fxsave
# define TARGET_FPSTATE_FXSAVE_OFFSET 0
#endif
struct target_sigcontext_32 {
@ -163,10 +182,25 @@ struct sigframe {
abi_ulong pretcode;
int sig;
struct target_sigcontext sc;
struct target_fpstate fpstate;
/*
* The actual fpstate is placed after retcode[] below, to make
* room for the variable-sized xsave data. The older unused fpstate
* has to be kept to avoid changing the offset of extramask[], which
* is part of the ABI.
*/
struct target_fpstate fpstate_unused;
abi_ulong extramask[TARGET_NSIG_WORDS-1];
char retcode[8];
/*
* This field will be 16-byte aligned in memory. Applying QEMU_ALIGNED
* to it ensures that the base of the frame has an appropriate alignment
* too.
*/
struct target_fpstate fpstate QEMU_ALIGNED(8);
};
#define TARGET_SIGFRAME_FXSAVE_OFFSET ( \
offsetof(struct sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
struct rt_sigframe {
abi_ulong pretcode;
@ -175,26 +209,62 @@ struct rt_sigframe {
abi_ulong puc;
struct target_siginfo info;
struct target_ucontext uc;
struct target_fpstate fpstate;
char retcode[8];
struct target_fpstate fpstate QEMU_ALIGNED(8);
};
#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
#else
struct rt_sigframe {
abi_ulong pretcode;
struct target_ucontext uc;
struct target_siginfo info;
struct target_fpstate fpstate;
struct target_fpstate fpstate QEMU_ALIGNED(16);
};
#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
#endif
/*
* Set up a signal frame.
*/
/* XXX: save x87 state */
static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
abi_ulong fxsave_addr)
{
if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
/* fxsave_addr must be 16 byte aligned for fxsave */
assert(!(fxsave_addr & 0xf));
cpu_x86_fxsave(env, fxsave_addr);
__put_user(0, &fxsave->sw_reserved.magic1);
} else {
uint32_t xstate_size = xsave_area_size(env->xcr0, false);
uint32_t xfeatures_size = xstate_size - TARGET_FXSAVE_SIZE;
/*
* extended_size is the offset from fpstate_addr to right after the end
* of the extended save states. On 32-bit that includes the legacy
* FSAVE area.
*/
uint32_t extended_size = TARGET_FPSTATE_FXSAVE_OFFSET
+ xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE;
/* fxsave_addr must be 64 byte aligned for xsave */
assert(!(fxsave_addr & 0x3f));
/* Zero the header, XSAVE *adds* features to an existing save state. */
memset(fxsave->xfeatures, 0, 64);
cpu_x86_xsave(env, fxsave_addr);
__put_user(TARGET_FP_XSTATE_MAGIC1, &fxsave->sw_reserved.magic1);
__put_user(extended_size, &fxsave->sw_reserved.extended_size);
__put_user(env->xcr0, &fxsave->sw_reserved.xfeatures);
__put_user(xstate_size, &fxsave->sw_reserved.xstate_size);
__put_user(TARGET_FP_XSTATE_MAGIC2, (uint32_t *) &fxsave->xfeatures[xfeatures_size]);
}
}
static void setup_sigcontext(struct target_sigcontext *sc,
struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
abi_ulong fpstate_addr)
@ -226,13 +296,14 @@ static void setup_sigcontext(struct target_sigcontext *sc,
cpu_x86_fsave(env, fpstate_addr, 1);
fpstate->status = fpstate->sw;
magic = 0xffff;
if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
magic = 0xffff;
} else {
xsave_sigcontext(env, &fpstate->fxsave,
fpstate_addr + TARGET_FPSTATE_FXSAVE_OFFSET);
magic = 0;
}
__put_user(magic, &fpstate->magic);
__put_user(fpstate_addr, &sc->fpstate);
/* non-iBCS2 extensions.. */
__put_user(mask, &sc->oldmask);
__put_user(env->cr[2], &sc->cr2);
#else
__put_user(env->regs[R_EDI], &sc->rdi);
__put_user(env->regs[R_ESI], &sc->rsi);
@ -262,15 +333,14 @@ static void setup_sigcontext(struct target_sigcontext *sc,
__put_user((uint16_t)0, &sc->fs);
__put_user(env->segs[R_SS].selector, &sc->ss);
xsave_sigcontext(env, fpstate, fpstate_addr);
#endif
__put_user(fpstate_addr, &sc->fpstate);
/* non-iBCS2 extensions.. */
__put_user(mask, &sc->oldmask);
__put_user(env->cr[2], &sc->cr2);
/* fpstate_addr must be 16 byte aligned for fxsave */
assert(!(fpstate_addr & 0xf));
cpu_x86_fxsave(env, fpstate_addr);
__put_user(fpstate_addr, &sc->fpstate);
#endif
}
/*
@ -278,7 +348,7 @@ static void setup_sigcontext(struct target_sigcontext *sc,
*/
static inline abi_ulong
get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset)
{
unsigned long esp;
@ -302,11 +372,15 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t frame_size)
#endif
}
#ifndef TARGET_X86_64
return (esp - frame_size) & -8ul;
#else
return ((esp - frame_size) & (~15ul)) - 8;
#endif
if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
return (esp - (fxsave_offset + TARGET_FXSAVE_SIZE)) & -8ul;
} else if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
return ((esp - TARGET_FXSAVE_SIZE) & -16ul) - fxsave_offset;
} else {
size_t xstate_size =
xsave_area_size(env->xcr0, false) + TARGET_FP_XSTATE_MAGIC2_SIZE;
return ((esp - xstate_size) & -64ul) - fxsave_offset;
}
}
#ifndef TARGET_X86_64
@ -334,7 +408,7 @@ void setup_frame(int sig, struct target_sigaction *ka,
struct sigframe *frame;
int i;
frame_addr = get_sigframe(ka, env, sizeof(*frame));
frame_addr = get_sigframe(ka, env, TARGET_SIGFRAME_FXSAVE_OFFSET);
trace_user_setup_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
@ -390,7 +464,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
struct rt_sigframe *frame;
int i;
frame_addr = get_sigframe(ka, env, sizeof(*frame));
frame_addr = get_sigframe(ka, env, TARGET_RT_SIGFRAME_FXSAVE_OFFSET);
trace_user_setup_rt_frame(env, frame_addr);
if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
@ -409,7 +483,11 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
}
/* Create the ucontext. */
__put_user(0, &frame->uc.tuc_flags);
if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
__put_user(1, &frame->uc.tuc_flags);
} else {
__put_user(0, &frame->uc.tuc_flags);
}
__put_user(0, &frame->uc.tuc_link);
target_save_altstack(&frame->uc.tuc_stack, env);
setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
@ -463,10 +541,37 @@ give_sigsegv:
force_sigsegv(sig);
}
static int xrstor_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
abi_ulong fxsave_addr)
{
if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
uint32_t extended_size = tswapl(fxsave->sw_reserved.extended_size);
uint32_t xstate_size = tswapl(fxsave->sw_reserved.xstate_size);
uint32_t xfeatures_size = xstate_size - TARGET_FXSAVE_SIZE;
/* Linux checks MAGIC2 using xstate_size, not extended_size. */
if (tswapl(fxsave->sw_reserved.magic1) == TARGET_FP_XSTATE_MAGIC1 &&
extended_size >= TARGET_FPSTATE_FXSAVE_OFFSET + xstate_size + TARGET_FP_XSTATE_MAGIC2_SIZE) {
if (!access_ok(env_cpu(env), VERIFY_READ, fxsave_addr,
extended_size - TARGET_FPSTATE_FXSAVE_OFFSET)) {
return 1;
}
if (tswapl(*(uint32_t *) &fxsave->xfeatures[xfeatures_size]) == TARGET_FP_XSTATE_MAGIC2) {
cpu_x86_xrstor(env, fxsave_addr);
return 0;
}
}
/* fall through to fxrstor */
}
cpu_x86_fxrstor(env, fxsave_addr);
return 0;
}
static int
restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
{
unsigned int err = 0;
int err = 1;
abi_ulong fpstate_addr;
unsigned int tmpflags;
@ -517,20 +622,28 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc)
fpstate_addr = tswapl(sc->fpstate);
if (fpstate_addr != 0) {
if (!access_ok(env_cpu(env), VERIFY_READ, fpstate_addr,
sizeof(struct target_fpstate))) {
goto badframe;
struct target_fpstate *fpstate;
if (!lock_user_struct(VERIFY_READ, fpstate, fpstate_addr,
sizeof(struct target_fpstate))) {
return err;
}
#ifndef TARGET_X86_64
cpu_x86_frstor(env, fpstate_addr, 1);
if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
cpu_x86_frstor(env, fpstate_addr, 1);
err = 0;
} else {
err = xrstor_sigcontext(env, &fpstate->fxsave,
fpstate_addr + TARGET_FPSTATE_FXSAVE_OFFSET);
}
#else
cpu_x86_fxrstor(env, fpstate_addr);
err = xrstor_sigcontext(env, fpstate, fpstate_addr);
#endif
unlock_user_struct(fpstate, fpstate_addr, 0);
} else {
err = 0;
}
return err;
badframe:
return 1;
}
/* Note: there is no sigreturn on x86_64, there is only rt_sigreturn */

View File

@ -643,3 +643,20 @@
{ 'struct': 'MemoryFailureFlags',
'data': { 'action-required': 'bool',
'recursive': 'bool'} }
##
# @NotifyVmexitOption:
#
# An enumeration of the options specified when enabling notify VM exit
#
# @run: enable the feature, do nothing and continue if the notify VM exit happens.
#
# @internal-error: enable the feature, raise a internal error if the notify
# VM exit happens.
#
# @disable: disable the feature.
#
# Since: 7.2
##
{ 'enum': 'NotifyVmexitOption',
'data': [ 'run', 'internal-error', 'disable' ] }

View File

@ -1199,13 +1199,16 @@
# interfaces (e.g. VGA and virtual console character devices)
# by default.
# Since 7.1
# @show-menubar: Display the main window menubar. Defaults to "on".
# Since 8.0
#
# Since: 2.12
##
{ 'struct' : 'DisplayGTK',
'data' : { '*grab-on-hover' : 'bool',
'*zoom-to-fit' : 'bool',
'*show-tabs' : 'bool' } }
'*show-tabs' : 'bool',
'*show-menubar' : 'bool' } }
##
# @DisplayEGLHeadless:

View File

@ -92,6 +92,10 @@ int main(int argc, char *argv[])
fprintf(stderr, "not a number: %s\n", optarg);
exit(1);
}
if (dpi == 0) {
fprintf(stderr, "cannot be zero: %s\n", optarg);
exit(1);
}
break;
case 'v':
info.vendor = optarg;

View File

@ -191,6 +191,7 @@ DEF("accel", HAS_ARG, QEMU_OPTION_accel,
" split-wx=on|off (enable TCG split w^x mapping)\n"
" tb-size=n (TCG translation block cache size)\n"
" dirty-ring-size=n (KVM dirty ring GFN count, default 0)\n"
" notify-vmexit=run|internal-error|disable,notify-window=n (enable notify VM exit and set notify window, x86 only)\n"
" thread=single|multi (enable multi-threaded TCG)\n", QEMU_ARCH_ALL)
SRST
``-accel name[,prop=value[,...]]``
@ -242,6 +243,16 @@ SRST
is disabled (dirty-ring-size=0). When enabled, KVM will instead
record dirty pages in a bitmap.
``notify-vmexit=run|internal-error|disable,notify-window=n``
Enables or disables notify VM exit support on x86 host and specify
the corresponding notify window to trigger the VM exit if enabled.
``run`` option enables the feature. It does nothing and continue
if the exit happens. ``internal-error`` option enables the feature.
It raises a internal error. ``disable`` option doesn't enable the feature.
This feature can mitigate the CPU stuck issue due to event windows don't
open up for a specified of time (i.e. notify-window).
Default: notify-vmexit=run,notify-window=0.
ERST
DEF("smp", HAS_ARG, QEMU_OPTION_smp,
@ -1969,6 +1980,7 @@ DEF("display", HAS_ARG, QEMU_OPTION_display,
#if defined(CONFIG_GTK)
"-display gtk[,full-screen=on|off][,gl=on|off][,grab-on-hover=on|off]\n"
" [,show-tabs=on|off][,show-cursor=on|off][,window-close=on|off]\n"
" [,show-menubar=on|off]\n"
#endif
#if defined(CONFIG_VNC)
"-display vnc=<display>[,<optargs>]\n"
@ -2061,6 +2073,8 @@ SRST
``window-close=on|off`` : Allow to quit qemu with window close button
``show-menubar=on|off`` : Display the main window menubar, defaults to "on"
``curses[,charset=<encoding>]``
Display video output via curses. For graphics device models
which support a text mode, QEMU can display this output using a

View File

@ -1058,3 +1058,7 @@ bool kvm_arch_cpu_check_are_resettable(void)
{
return true;
}
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}

View File

@ -25,4 +25,8 @@
#define TARGET_PAGE_BITS 12
#define NB_MMU_MODES 3
#ifndef CONFIG_USER_ONLY
# define TARGET_TB_PCREL 1
#endif
#endif

View File

@ -1467,7 +1467,7 @@ ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = {
},
};
static uint32_t xsave_area_size(uint64_t mask, bool compacted)
uint32_t xsave_area_size(uint64_t mask, bool compacted)
{
uint64_t ret = x86_ext_save_areas[0].size;
const ExtSaveArea *esa;
@ -6017,6 +6017,7 @@ static void x86_cpu_reset(DeviceState *dev)
env->exception_has_payload = false;
env->exception_payload = 0;
env->nmi_injected = false;
env->triple_fault_pending = false;
#if !defined(CONFIG_USER_ONLY)
/* We hard-wire the BSP to the first CPU. */
apic_designate_bsp(cpu->apic_state, s->cpu_index == 0);

View File

@ -1739,6 +1739,7 @@ typedef struct CPUArchState {
uint8_t has_error_code;
uint8_t exception_has_payload;
uint64_t exception_payload;
uint8_t triple_fault_pending;
uint32_t ins_len;
uint32_t sipi_vector;
bool tsc_valid;
@ -2070,6 +2071,8 @@ void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32);
void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32);
void cpu_x86_fxsave(CPUX86State *s, target_ulong ptr);
void cpu_x86_fxrstor(CPUX86State *s, target_ulong ptr);
void cpu_x86_xsave(CPUX86State *s, target_ulong ptr);
void cpu_x86_xrstor(CPUX86State *s, target_ulong ptr);
/* cpu.c */
void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
@ -2326,6 +2329,7 @@ bool cpu_is_bsp(X86CPU *cpu);
void x86_cpu_xrstor_all_areas(X86CPU *cpu, const void *buf, uint32_t buflen);
void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen);
uint32_t xsave_area_size(uint64_t mask, bool compacted);
void x86_update_hflags(CPUX86State* env);
static inline bool hyperv_feat_enabled(X86CPU *cpu, int feat)

View File

@ -37,7 +37,7 @@ DEF_HELPER_2(lldt, void, env, int)
DEF_HELPER_2(ltr, void, env, int)
DEF_HELPER_3(load_seg, void, env, int, int)
DEF_HELPER_4(ljmp_protected, void, env, int, tl, tl)
DEF_HELPER_5(lcall_real, void, env, int, tl, int, int)
DEF_HELPER_5(lcall_real, void, env, i32, i32, int, i32)
DEF_HELPER_5(lcall_protected, void, env, int, tl, int, tl)
DEF_HELPER_2(iret_real, void, env, int)
DEF_HELPER_3(iret_protected, void, env, int, int)

View File

@ -15,6 +15,7 @@
#include "qemu/osdep.h"
#include "qapi/qapi-events-run-state.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include <sys/ioctl.h>
#include <sys/utsname.h>
#include <sys/syscall.h>
@ -132,6 +133,7 @@ static int has_xcrs;
static int has_pit_state2;
static int has_sregs2;
static int has_exception_payload;
static int has_triple_fault_event;
static bool has_msr_mcg_ext_ctl;
@ -139,6 +141,8 @@ static struct kvm_cpuid2 *cpuid_cache;
static struct kvm_cpuid2 *hv_cpuid_cache;
static struct kvm_msr_list *kvm_feature_msrs;
static KVMMSRHandlers msr_handlers[KVM_MSR_FILTER_MAX_RANGES];
#define BUS_LOCK_SLICE_TIME 1000000000ULL /* ns */
static RateLimit bus_lock_ratelimit_ctrl;
static int kvm_get_one_msr(X86CPU *cpu, int index, uint64_t *value);
@ -2397,6 +2401,17 @@ static int kvm_get_supported_msrs(KVMState *s)
return ret;
}
static bool kvm_rdmsr_core_thread_count(X86CPU *cpu, uint32_t msr,
uint64_t *val)
{
CPUState *cs = CPU(cpu);
*val = cs->nr_threads * cs->nr_cores; /* thread count, bits 15..0 */
*val |= ((uint32_t)cs->nr_cores << 16); /* core count, bits 31..16 */
return true;
}
static Notifier smram_machine_done;
static KVMMemoryListener smram_listener;
static AddressSpace smram_address_space;
@ -2479,6 +2494,16 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
}
has_triple_fault_event = kvm_check_extension(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT);
if (has_triple_fault_event) {
ret = kvm_vm_enable_cap(s, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 0, true);
if (ret < 0) {
error_report("kvm: Failed to enable triple fault event cap: %s",
strerror(-ret));
return ret;
}
}
ret = kvm_get_supported_msrs(s);
if (ret < 0) {
return ret;
@ -2584,6 +2609,40 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
}
}
if (s->notify_vmexit != NOTIFY_VMEXIT_OPTION_DISABLE &&
kvm_check_extension(s, KVM_CAP_X86_NOTIFY_VMEXIT)) {
uint64_t notify_window_flags =
((uint64_t)s->notify_window << 32) |
KVM_X86_NOTIFY_VMEXIT_ENABLED |
KVM_X86_NOTIFY_VMEXIT_USER;
ret = kvm_vm_enable_cap(s, KVM_CAP_X86_NOTIFY_VMEXIT, 0,
notify_window_flags);
if (ret < 0) {
error_report("kvm: Failed to enable notify vmexit cap: %s",
strerror(-ret));
return ret;
}
}
if (kvm_vm_check_extension(s, KVM_CAP_X86_USER_SPACE_MSR)) {
bool r;
ret = kvm_vm_enable_cap(s, KVM_CAP_X86_USER_SPACE_MSR, 0,
KVM_MSR_EXIT_REASON_FILTER);
if (ret) {
error_report("Could not enable user space MSRs: %s",
strerror(-ret));
exit(1);
}
r = kvm_filter_msr(s, MSR_CORE_THREAD_COUNT,
kvm_rdmsr_core_thread_count, NULL);
if (!r) {
error_report("Could not install MSR_CORE_THREAD_COUNT handler: %s",
strerror(-ret));
exit(1);
}
}
return 0;
}
@ -4295,6 +4354,11 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level)
}
}
if (has_triple_fault_event) {
events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT;
events.triple_fault.pending = env->triple_fault_pending;
}
return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events);
}
@ -4364,6 +4428,10 @@ static int kvm_get_vcpu_events(X86CPU *cpu)
}
}
if (events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT) {
env->triple_fault_pending = events.triple_fault.pending;
}
env->sipi_vector = events.sipi_vector;
return 0;
@ -5073,6 +5141,108 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
}
}
static bool kvm_install_msr_filters(KVMState *s)
{
uint64_t zero = 0;
struct kvm_msr_filter filter = {
.flags = KVM_MSR_FILTER_DEFAULT_ALLOW,
};
int r, i, j = 0;
for (i = 0; i < KVM_MSR_FILTER_MAX_RANGES; i++) {
KVMMSRHandlers *handler = &msr_handlers[i];
if (handler->msr) {
struct kvm_msr_filter_range *range = &filter.ranges[j++];
*range = (struct kvm_msr_filter_range) {
.flags = 0,
.nmsrs = 1,
.base = handler->msr,
.bitmap = (__u8 *)&zero,
};
if (handler->rdmsr) {
range->flags |= KVM_MSR_FILTER_READ;
}
if (handler->wrmsr) {
range->flags |= KVM_MSR_FILTER_WRITE;
}
}
}
r = kvm_vm_ioctl(s, KVM_X86_SET_MSR_FILTER, &filter);
if (r) {
return false;
}
return true;
}
bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
QEMUWRMSRHandler *wrmsr)
{
int i;
for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
if (!msr_handlers[i].msr) {
msr_handlers[i] = (KVMMSRHandlers) {
.msr = msr,
.rdmsr = rdmsr,
.wrmsr = wrmsr,
};
if (!kvm_install_msr_filters(s)) {
msr_handlers[i] = (KVMMSRHandlers) { };
return false;
}
return true;
}
}
return false;
}
static int kvm_handle_rdmsr(X86CPU *cpu, struct kvm_run *run)
{
int i;
bool r;
for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
KVMMSRHandlers *handler = &msr_handlers[i];
if (run->msr.index == handler->msr) {
if (handler->rdmsr) {
r = handler->rdmsr(cpu, handler->msr,
(uint64_t *)&run->msr.data);
run->msr.error = r ? 0 : 1;
return 0;
}
}
}
assert(false);
}
static int kvm_handle_wrmsr(X86CPU *cpu, struct kvm_run *run)
{
int i;
bool r;
for (i = 0; i < ARRAY_SIZE(msr_handlers); i++) {
KVMMSRHandlers *handler = &msr_handlers[i];
if (run->msr.index == handler->msr) {
if (handler->wrmsr) {
r = handler->wrmsr(cpu, handler->msr, run->msr.data);
run->msr.error = r ? 0 : 1;
return 0;
}
}
}
assert(false);
}
static bool has_sgx_provisioning;
static bool __kvm_enable_sgx_provisioning(KVMState *s)
@ -5117,6 +5287,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
X86CPU *cpu = X86_CPU(cs);
uint64_t code;
int ret;
bool ctx_invalid;
char str[256];
KVMState *state;
switch (run->exit_reason) {
case KVM_EXIT_HLT:
@ -5172,6 +5345,31 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
/* already handled in kvm_arch_post_run */
ret = 0;
break;
case KVM_EXIT_NOTIFY:
ctx_invalid = !!(run->notify.flags & KVM_NOTIFY_CONTEXT_INVALID);
state = KVM_STATE(current_accel());
sprintf(str, "Encounter a notify exit with %svalid context in"
" guest. There can be possible misbehaves in guest."
" Please have a look.", ctx_invalid ? "in" : "");
if (ctx_invalid ||
state->notify_vmexit == NOTIFY_VMEXIT_OPTION_INTERNAL_ERROR) {
warn_report("KVM internal error: %s", str);
ret = -1;
} else {
warn_report_once("KVM: %s", str);
ret = 0;
}
break;
case KVM_EXIT_X86_RDMSR:
/* We only enable MSR filtering, any other exit is bogus */
assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER);
ret = kvm_handle_rdmsr(cpu, run);
break;
case KVM_EXIT_X86_WRMSR:
/* We only enable MSR filtering, any other exit is bogus */
assert(run->msr.reason == KVM_MSR_EXIT_REASON_FILTER);
ret = kvm_handle_wrmsr(cpu, run);
break;
default:
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
ret = -1;
@ -5448,3 +5646,71 @@ void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask)
mask &= ~BIT_ULL(bit);
}
}
static int kvm_arch_get_notify_vmexit(Object *obj, Error **errp)
{
KVMState *s = KVM_STATE(obj);
return s->notify_vmexit;
}
static void kvm_arch_set_notify_vmexit(Object *obj, int value, Error **errp)
{
KVMState *s = KVM_STATE(obj);
if (s->fd != -1) {
error_setg(errp, "Cannot set properties after the accelerator has been initialized");
return;
}
s->notify_vmexit = value;
}
static void kvm_arch_get_notify_window(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
KVMState *s = KVM_STATE(obj);
uint32_t value = s->notify_window;
visit_type_uint32(v, name, &value, errp);
}
static void kvm_arch_set_notify_window(Object *obj, Visitor *v,
const char *name, void *opaque,
Error **errp)
{
KVMState *s = KVM_STATE(obj);
Error *error = NULL;
uint32_t value;
if (s->fd != -1) {
error_setg(errp, "Cannot set properties after the accelerator has been initialized");
return;
}
visit_type_uint32(v, name, &value, &error);
if (error) {
error_propagate(errp, error);
return;
}
s->notify_window = value;
}
void kvm_arch_accel_class_init(ObjectClass *oc)
{
object_class_property_add_enum(oc, "notify-vmexit", "NotifyVMexitOption",
&NotifyVmexitOption_lookup,
kvm_arch_get_notify_vmexit,
kvm_arch_set_notify_vmexit);
object_class_property_set_description(oc, "notify-vmexit",
"Enable notify VM exit");
object_class_property_add(oc, "notify-window", "uint32",
kvm_arch_get_notify_window,
kvm_arch_set_notify_window,
NULL, NULL);
object_class_property_set_description(oc, "notify-window",
"Clock cycles without an event window "
"after which a notification VM exit occurs");
}

View File

@ -54,4 +54,15 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address);
bool kvm_enable_sgx_provisioning(KVMState *s);
void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask);
typedef bool QEMURDMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t *val);
typedef bool QEMUWRMSRHandler(X86CPU *cpu, uint32_t msr, uint64_t val);
typedef struct kvm_msr_handlers {
uint32_t msr;
QEMURDMSRHandler *rdmsr;
QEMUWRMSRHandler *wrmsr;
} KVMMSRHandlers;
bool kvm_filter_msr(KVMState *s, uint32_t msr, QEMURDMSRHandler *rdmsr,
QEMUWRMSRHandler *wrmsr);
#endif

View File

@ -1562,6 +1562,25 @@ static const VMStateDescription vmstate_arch_lbr = {
}
};
static bool triple_fault_needed(void *opaque)
{
X86CPU *cpu = opaque;
CPUX86State *env = &cpu->env;
return env->triple_fault_pending;
}
static const VMStateDescription vmstate_triple_fault = {
.name = "cpu/triple_fault",
.version_id = 1,
.minimum_version_id = 1,
.needed = triple_fault_needed,
.fields = (VMStateField[]) {
VMSTATE_UINT8(env.triple_fault_pending, X86CPU),
VMSTATE_END_OF_LIST()
}
};
const VMStateDescription vmstate_x86_cpu = {
.name = "cpu",
.version_id = 12,
@ -1706,6 +1725,7 @@ const VMStateDescription vmstate_x86_cpu = {
&vmstate_amx_xtile,
#endif
&vmstate_arch_lbr,
&vmstate_triple_fault,
NULL
}
};

View File

@ -2502,18 +2502,6 @@ void helper_frstor(CPUX86State *env, target_ulong ptr, int data32)
do_frstor(env, ptr, data32, GETPC());
}
#if defined(CONFIG_USER_ONLY)
void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
{
do_fsave(env, ptr, data32, 0);
}
void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
{
do_frstor(env, ptr, data32, 0);
}
#endif
#define XO(X) offsetof(X86XSaveArea, X)
static void do_xsave_fpu(CPUX86State *env, target_ulong ptr, uintptr_t ra)
@ -2787,21 +2775,8 @@ void helper_fxrstor(CPUX86State *env, target_ulong ptr)
do_fxrstor(env, ptr, GETPC());
}
#if defined(CONFIG_USER_ONLY)
void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr)
static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr_t ra)
{
do_fxsave(env, ptr, 0);
}
void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr)
{
do_fxrstor(env, ptr, 0);
}
#endif
void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
{
uintptr_t ra = GETPC();
uint64_t xstate_bv, xcomp_bv, reserve0;
rfbm &= env->xcr0;
@ -2894,6 +2869,43 @@ void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
#undef XO
void helper_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm)
{
do_xrstor(env, ptr, rfbm, GETPC());
}
#if defined(CONFIG_USER_ONLY)
void cpu_x86_fsave(CPUX86State *env, target_ulong ptr, int data32)
{
do_fsave(env, ptr, data32, 0);
}
void cpu_x86_frstor(CPUX86State *env, target_ulong ptr, int data32)
{
do_frstor(env, ptr, data32, 0);
}
void cpu_x86_fxsave(CPUX86State *env, target_ulong ptr)
{
do_fxsave(env, ptr, 0);
}
void cpu_x86_fxrstor(CPUX86State *env, target_ulong ptr)
{
do_fxrstor(env, ptr, 0);
}
void cpu_x86_xsave(CPUX86State *env, target_ulong ptr)
{
do_xsave(env, ptr, -1, get_xinuse(env), -1, 0);
}
void cpu_x86_xrstor(CPUX86State *env, target_ulong ptr)
{
do_xrstor(env, ptr, -1, 0);
}
#endif
uint64_t helper_xgetbv(CPUX86State *env, uint32_t ecx)
{
/* The OS must have enabled XSAVE. */

View File

@ -1504,14 +1504,12 @@ void helper_ljmp_protected(CPUX86State *env, int new_cs, target_ulong new_eip,
}
/* real mode call */
void helper_lcall_real(CPUX86State *env, int new_cs, target_ulong new_eip1,
int shift, int next_eip)
void helper_lcall_real(CPUX86State *env, uint32_t new_cs, uint32_t new_eip,
int shift, uint32_t next_eip)
{
int new_eip;
uint32_t esp, esp_mask;
target_ulong ssp;
new_eip = new_eip1;
esp = env->regs[R_ESP];
esp_mask = get_sp_mask(env->segs[R_SS].flags);
ssp = env->segs[R_SS].base;

View File

@ -450,6 +450,11 @@ void helper_rdmsr(CPUX86State *env)
case MSR_IA32_UCODE_REV:
val = x86_cpu->ucode_rev;
break;
case MSR_CORE_THREAD_COUNT: {
CPUState *cs = CPU(x86_cpu);
val = (cs->nr_threads * cs->nr_cores) | (cs->nr_cores << 16);
break;
}
default:
if ((uint32_t)env->regs[R_ECX] >= MSR_MC0_CTL
&& (uint32_t)env->regs[R_ECX] < MSR_MC0_CTL +

View File

@ -49,9 +49,11 @@ static void x86_cpu_exec_exit(CPUState *cs)
static void x86_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
X86CPU *cpu = X86_CPU(cs);
cpu->env.eip = tb_pc(tb) - tb->cs_base;
/* The instruction pointer is always up to date with TARGET_TB_PCREL. */
if (!TARGET_TB_PCREL) {
CPUX86State *env = cs->env_ptr;
env->eip = tb_pc(tb) - tb->cs_base;
}
}
#ifndef CONFIG_USER_ONLY

File diff suppressed because it is too large Load Diff

View File

@ -1294,3 +1294,7 @@ bool kvm_arch_cpu_check_are_resettable(void)
{
return true;
}
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}

View File

@ -2966,3 +2966,7 @@ bool kvm_arch_cpu_check_are_resettable(void)
{
return true;
}
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}

View File

@ -532,3 +532,7 @@ bool kvm_arch_cpu_check_are_resettable(void)
{
return true;
}
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}

View File

@ -628,6 +628,18 @@ bool pmp_is_range_in_tlb(CPURISCVState *env, hwaddr tlb_sa,
}
if (*tlb_size != 0) {
/*
* At this point we have a tlb_size that is the smallest possible size
* That fits within a TARGET_PAGE_SIZE and the PMP region.
*
* If the size is less then TARGET_PAGE_SIZE we drop the size to 1.
* This means the result isn't cached in the TLB and is only used for
* a single translation.
*/
if (*tlb_size < TARGET_PAGE_SIZE) {
*tlb_size = 1;
}
return true;
}

View File

@ -2581,3 +2581,7 @@ int kvm_s390_get_zpci_op(void)
{
return cap_zpci_op;
}
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}

View File

@ -381,6 +381,8 @@ class BootLinuxConsole(LinuxKernelTest):
:avocado: tags=u-boot
:avocado: tags=accel:tcg
"""
self.require_netdev('user')
uboot_url = ('https://raw.githubusercontent.com/'
'Subbaraya-Sundeep/qemu-test-binaries/'
'fe371d32e50ca682391e1e70ab98c2942aeffb01/u-boot')
@ -779,6 +781,8 @@ class BootLinuxConsole(LinuxKernelTest):
:avocado: tags=machine:orangepi-pc
:avocado: tags=device:sd
"""
self.require_netdev('user')
deb_url = ('https://apt.armbian.com/pool/main/l/'
'linux-5.10.16-sunxi/linux-image-current-sunxi_21.02.2_armhf.deb')
deb_hash = '9fa84beda245cabf0b4fa84cf6eaa7738ead1da0'

View File

@ -93,6 +93,8 @@ class AST2x00Machine(QemuSystemTest):
self.do_test_arm_aspeed(image_path)
def do_test_arm_aspeed_buidroot_start(self, image, cpu_id):
self.require_netdev('user')
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
'-net', 'nic', '-net', 'user')
@ -193,6 +195,7 @@ class AST2x00MachineSDK(QemuSystemTest):
vm=vm)
def do_test_arm_aspeed_sdk_start(self, image, cpu_id):
self.require_netdev('user')
self.vm.set_console()
self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw',
'-net', 'nic', '-net', 'user')

View File

@ -23,6 +23,7 @@ class BambooMachine(QemuSystemTest):
:avocado: tags=accel:tcg
"""
self.require_accelerator("tcg")
self.require_netdev('user')
tar_url = ('http://landley.net/aboriginal/downloads/binaries/'
'system-image-powerpc-440fp.tar.gz')
tar_hash = '53e5f16414b195b82d2c70272f81c2eedb39bad9'

View File

@ -65,7 +65,6 @@ class Engine(object):
return records
def _cpu_timing(self, pid):
records = []
now = time.time()
jiffies_per_sec = os.sysconf(os.sysconf_names['SC_CLK_TCK'])

View File

@ -725,7 +725,7 @@ static char *test_acpi_create_args(test_data *data, const char *params,
}
} else {
args = g_strdup_printf("-machine %s %s -accel tcg "
"-net none -display none %s "
"-net none %s "
"-drive id=hd0,if=none,file=%s,format=raw "
"-device %s,drive=hd0 ",
data->machine, data->tcg_only ? "" : "-accel kvm",

View File

@ -15,17 +15,6 @@
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qstring.h"
static void device_del(QTestState *qtest, const char *id)
{
QDict *resp;
resp = qtest_qmp(qtest,
"{'execute': 'device_del', 'arguments': { 'id': %s } }", id);
g_assert(qdict_haskey(resp, "return"));
qobject_unref(resp);
}
static void system_reset(QTestState *qtest)
{
QDict *resp;
@ -68,7 +57,7 @@ static void process_device_remove(QTestState *qtest, const char *id)
* be processed. However during system reset, the removal will be
* handled, removing the device.
*/
device_del(qtest, id);
qtest_qmp_device_del_send(qtest, id);
system_reset(qtest);
wait_device_deleted_event(qtest, id);
}
@ -90,6 +79,19 @@ static void test_pci_unplug_request(void)
qtest_quit(qtest);
}
static void test_q35_pci_unplug_request(void)
{
QTestState *qtest = qtest_initf("-machine q35 "
"-device pcie-root-port,id=p1 "
"-device pcie-pci-bridge,bus=p1,id=b1 "
"-device virtio-mouse-pci,bus=b1,id=dev0");
process_device_remove(qtest, "dev0");
qtest_quit(qtest);
}
static void test_pci_unplug_json_request(void)
{
const char *arch = qtest_get_arch();
@ -108,11 +110,32 @@ static void test_pci_unplug_json_request(void)
qtest_quit(qtest);
}
static void test_q35_pci_unplug_json_request(void)
{
const char *port = "-device '{\"driver\": \"pcie-root-port\", "
"\"id\": \"p1\"}'";
const char *bridge = "-device '{\"driver\": \"pcie-pci-bridge\", "
"\"id\": \"b1\", "
"\"bus\": \"p1\"}'";
const char *device = "-device '{\"driver\": \"virtio-mouse-pci\", "
"\"bus\": \"b1\", "
"\"id\": \"dev0\"}'";
QTestState *qtest = qtest_initf("-machine q35 %s %s %s",
port, bridge, device);
process_device_remove(qtest, "dev0");
qtest_quit(qtest);
}
static void test_ccw_unplug(void)
{
QTestState *qtest = qtest_initf("-device virtio-balloon-ccw,id=dev0");
device_del(qtest, "dev0");
qtest_qmp_device_del_send(qtest, "dev0");
wait_device_deleted_event(qtest, "dev0");
qtest_quit(qtest);
@ -187,5 +210,12 @@ int main(int argc, char **argv)
test_spapr_phb_unplug_request);
}
if (!strcmp(arch, "x86_64") && qtest_has_machine("q35")) {
qtest_add_func("/device-plug/q35-pci-unplug-request",
test_q35_pci_unplug_request);
qtest_add_func("/device-plug/q35-pci-unplug-json-request",
test_q35_pci_unplug_json_request);
}
return g_test_run();
}

View File

@ -123,12 +123,10 @@ static const char *qvirtio_get_dev_type(void)
static void device_add(QTestState *qts)
{
QDict *response;
char driver[32];
snprintf(driver, sizeof(driver), "virtio-blk-%s",
qvirtio_get_dev_type());
response = qtest_qmp(qts, "{'execute': 'device_add',"
g_autofree char *driver = g_strdup_printf("virtio-blk-%s",
qvirtio_get_dev_type());
QDict *response =
qtest_qmp(qts, "{'execute': 'device_add',"
" 'arguments': {"
" 'driver': %s,"
" 'drive': 'drive0',"
@ -143,11 +141,7 @@ static void device_del(QTestState *qts, bool and_reset)
{
QDict *response;
response = qtest_qmp(qts, "{'execute': 'device_del',"
" 'arguments': { 'id': 'dev0' } }");
g_assert(response);
g_assert(qdict_haskey(response, "return"));
qobject_unref(response);
qtest_qmp_device_del_send(qts, "dev0");
if (and_reset) {
response = qtest_qmp(qts, "{'execute': 'system_reset' }");
@ -258,6 +252,27 @@ static void test_cli_device_del(void)
qtest_quit(qts);
}
static void test_cli_device_del_q35(void)
{
QTestState *qts;
/*
* -drive/-device and device_del. Start with a drive used by a
* device that unplugs after reset.
*/
qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,"
"file.read-zeroes=on,format=raw "
"-machine q35 -device pcie-root-port,id=p1 "
"-device pcie-pci-bridge,bus=p1,id=b1 "
"-device virtio-blk-%s,drive=drive0,bus=b1,id=dev0",
qvirtio_get_dev_type());
device_del(qts, true);
g_assert(!has_drive(qts));
qtest_quit(qts);
}
static void test_empty_device_del(void)
{
QTestState *qts;
@ -294,6 +309,43 @@ static void test_device_add_and_del(void)
qtest_quit(qts);
}
static void device_add_q35(QTestState *qts)
{
g_autofree char *driver = g_strdup_printf("virtio-blk-%s",
qvirtio_get_dev_type());
QDict *response =
qtest_qmp(qts, "{'execute': 'device_add',"
" 'arguments': {"
" 'driver': %s,"
" 'drive': 'drive0',"
" 'id': 'dev0',"
" 'bus': 'b1'"
"}}", driver);
g_assert(response);
g_assert(qdict_haskey(response, "return"));
qobject_unref(response);
}
static void test_device_add_and_del_q35(void)
{
QTestState *qts;
/*
* -drive/device_add and device_del. Start with a drive used by a
* device that unplugs after reset.
*/
qts = qtest_initf("-machine q35 -device pcie-root-port,id=p1 "
"-device pcie-pci-bridge,bus=p1,id=b1 "
"-drive if=none,id=drive0,file=null-co://,"
"file.read-zeroes=on,format=raw");
device_add_q35(qts);
device_del(qts, true);
g_assert(!has_drive(qts));
qtest_quit(qts);
}
static void test_drive_add_device_add_and_del(void)
{
QTestState *qts;
@ -318,6 +370,25 @@ static void test_drive_add_device_add_and_del(void)
qtest_quit(qts);
}
static void test_drive_add_device_add_and_del_q35(void)
{
QTestState *qts;
qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 "
"-device pcie-pci-bridge,bus=p1,id=b1");
/*
* drive_add/device_add and device_del. The drive is used by a
* device that unplugs after reset.
*/
drive_add_with_media(qts);
device_add_q35(qts);
device_del(qts, true);
g_assert(!has_drive(qts));
qtest_quit(qts);
}
static void test_blockdev_add_device_add_and_del(void)
{
QTestState *qts;
@ -331,7 +402,7 @@ static void test_blockdev_add_device_add_and_del(void)
qts = qtest_init(machine_addition);
/*
* blockdev_add/device_add and device_del. The it drive is used by a
* blockdev_add/device_add and device_del. The drive is used by a
* device that unplugs after reset, but it doesn't go away.
*/
blockdev_add_with_media(qts);
@ -342,6 +413,25 @@ static void test_blockdev_add_device_add_and_del(void)
qtest_quit(qts);
}
static void test_blockdev_add_device_add_and_del_q35(void)
{
QTestState *qts;
qts = qtest_init("-machine q35 -device pcie-root-port,id=p1 "
"-device pcie-pci-bridge,bus=p1,id=b1");
/*
* blockdev_add/device_add and device_del. The drive is used by a
* device that unplugs after reset, but it doesn't go away.
*/
blockdev_add_with_media(qts);
device_add_q35(qts);
device_del(qts, true);
g_assert(has_blockdev(qts));
qtest_quit(qts);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@ -363,6 +453,17 @@ int main(int argc, char **argv)
test_empty_device_del);
qtest_add_func("/device_del/blockdev",
test_blockdev_add_device_add_and_del);
if (qtest_has_machine("q35")) {
qtest_add_func("/device_del/drive/cli_device_q35",
test_cli_device_del_q35);
qtest_add_func("/device_del/drive/device_add_q35",
test_device_add_and_del_q35);
qtest_add_func("/device_del/drive/drive_add_device_add_q35",
test_drive_add_device_add_and_del_q35);
qtest_add_func("/device_del/blockdev_q35",
test_blockdev_add_device_add_and_del_q35);
}
}
return g_test_run();

View File

@ -21,7 +21,7 @@ static void test_lsi_do_msgout_cancel_req(void)
return;
}
s = qtest_init("-M q35 -m 2G -display none -nodefaults "
s = qtest_init("-M q35 -m 2G -nodefaults "
"-device lsi53c895a,id=scsi "
"-device scsi-hd,drive=disk0 "
"-drive file=null-co://,id=disk0,if=none,format=raw");

View File

@ -40,7 +40,7 @@ static void test_lp1878263_megasas_zero_iov_cnt(void)
*/
static void test_gitlab_issue521_megasas_sgl_ovf(void)
{
QTestState *s = qtest_init("-display none -m 32M -machine q35 "
QTestState *s = qtest_init("-m 32M -machine q35 "
"-nodefaults -device megasas "
"-device scsi-cd,drive=null0 "
"-blockdev "

View File

@ -15,7 +15,7 @@
*/
static void test_fuzz_sb16_0x1c(void)
{
QTestState *s = qtest_init("-M q35 -display none "
QTestState *s = qtest_init("-M q35 "
"-device sb16,audiodev=snd0 "
"-audiodev none,id=snd0");
qtest_outw(s, 0x22c, 0x41);
@ -27,7 +27,7 @@ static void test_fuzz_sb16_0x1c(void)
static void test_fuzz_sb16_0x91(void)
{
QTestState *s = qtest_init("-M pc -display none "
QTestState *s = qtest_init("-M pc "
"-device sb16,audiodev=none "
"-audiodev id=none,driver=none");
qtest_outw(s, 0x22c, 0xf141);
@ -43,7 +43,7 @@ static void test_fuzz_sb16_0x91(void)
*/
static void test_fuzz_sb16_0xd4(void)
{
QTestState *s = qtest_init("-M pc -display none "
QTestState *s = qtest_init("-M pc "
"-device sb16,audiodev=none "
"-audiodev id=none,driver=none");
qtest_outb(s, 0x22c, 0x41);

View File

@ -18,7 +18,7 @@ static void oss_fuzz_29225(void)
{
QTestState *s;
s = qtest_init(" -display none -m 512m -nodefaults -nographic"
s = qtest_init(" -m 512m -nodefaults -nographic"
" -device sdhci-pci,sd-spec-version=3"
" -device sd-card,drive=d0"
" -drive if=none,index=0,file=null-co://,format=raw,id=d0");
@ -61,7 +61,7 @@ static void oss_fuzz_36217(void)
{
QTestState *s;
s = qtest_init(" -display none -m 32 -nodefaults -nographic"
s = qtest_init(" -m 32 -nodefaults -nographic"
" -device sdhci-pci,sd-spec-version=3 "
"-device sd-card,drive=d0 "
"-drive if=none,index=0,file=null-co://,format=raw,id=d0");
@ -95,7 +95,7 @@ static void oss_fuzz_36391(void)
{
QTestState *s;
s = qtest_init(" -display none -m 512M -nodefaults -nographic"
s = qtest_init(" -m 512M -nodefaults -nographic"
" -device sdhci-pci,sd-spec-version=3"
" -device sd-card,drive=drv"
" -drive if=none,index=0,file=null-co://,format=raw,id=drv");

View File

@ -19,7 +19,7 @@ static void test_mmio_oob_from_memory_region_cache(void)
{
QTestState *s;
s = qtest_init("-M pc-q35-5.2 -display none -m 512M "
s = qtest_init("-M pc-q35-5.2 -m 512M "
"-device virtio-scsi,num_queues=8,addr=03.0 ");
qtest_outl(s, 0xcf8, 0x80001811);

View File

@ -14,7 +14,7 @@
*/
static void test_fuzz_xlnx_dp_0x3ac(void)
{
QTestState *s = qtest_init("-M xlnx-zcu102 -display none ");
QTestState *s = qtest_init("-M xlnx-zcu102 ");
qtest_readl(s, 0xfd4a03ac);
qtest_quit(s);
}

View File

@ -691,7 +691,8 @@ static void add_virtio_disk(TestArgs *args,
args->n_virtio_disks++;
}
static void test_override(TestArgs *args, CHSResult expected[])
static void test_override(TestArgs *args, const char *arch,
CHSResult expected[])
{
QTestState *qts;
char *joined_args;
@ -700,7 +701,7 @@ static void test_override(TestArgs *args, CHSResult expected[])
joined_args = g_strjoinv(" ", args->argv);
qts = qtest_initf("-machine pc %s", joined_args);
qts = qtest_initf("-machine %s %s", arch, joined_args);
fw_cfg = pc_fw_cfg_init(qts);
read_bootdevices(fw_cfg, expected);
@ -737,7 +738,28 @@ static void test_override_ide(void)
add_ide_disk(args, 1, 0, 1, 9000, 120, 30);
add_ide_disk(args, 2, 1, 0, 0, 1, 1);
add_ide_disk(args, 3, 1, 1, 1, 0, 0);
test_override(args, expected);
test_override(args, "pc", expected);
}
static void test_override_sata(void)
{
TestArgs *args = create_args();
CHSResult expected[] = {
{"/pci@i0cf8/pci8086,2922@1f,2/drive@0/disk@0", {10000, 120, 30} },
{"/pci@i0cf8/pci8086,2922@1f,2/drive@1/disk@0", {9000, 120, 30} },
{"/pci@i0cf8/pci8086,2922@1f,2/drive@2/disk@0", {0, 1, 1} },
{"/pci@i0cf8/pci8086,2922@1f,2/drive@3/disk@0", {1, 0, 0} },
{NULL, {0, 0, 0} }
};
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
add_ide_disk(args, 0, 0, 0, 10000, 120, 30);
add_ide_disk(args, 1, 1, 0, 9000, 120, 30);
add_ide_disk(args, 2, 2, 0, 0, 1, 1);
add_ide_disk(args, 3, 3, 0, 1, 0, 0);
test_override(args, "q35", expected);
}
static void test_override_scsi(void)
@ -759,7 +781,43 @@ static void test_override_scsi(void)
add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0);
add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0);
test_override(args, expected);
test_override(args, "pc", expected);
}
static void setup_pci_bridge(TestArgs *args, const char *id, const char *rootid)
{
char *root, *br;
root = g_strdup_printf("-device pcie-root-port,id=%s", rootid);
br = g_strdup_printf("-device pcie-pci-bridge,bus=%s,id=%s", rootid, id);
args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, root);
args->argc = append_arg(args->argc, args->argv, ARGV_SIZE, br);
}
static void test_override_scsi_q35(void)
{
TestArgs *args = create_args();
CHSResult expected[] = {
{ "/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@0,0",
{10000, 120, 30}
},
{"/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@1,0", {9000, 120, 30} },
{"/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@2,0", {1, 0, 0} },
{"/pci@i0cf8/pci-bridge@1/scsi@3/channel@0/disk@3,0", {0, 1, 0} },
{NULL, {0, 0, 0} }
};
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
setup_pci_bridge(args, "pcie.0", "br");
add_scsi_controller(args, "lsi53c895a", "br", 3);
add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
add_scsi_disk(args, 2, 0, 0, 2, 0, 1, 0, 0);
add_scsi_disk(args, 3, 0, 0, 3, 0, 0, 1, 0);
test_override(args, "q35", expected);
}
static void test_override_scsi_2_controllers(void)
@ -782,7 +840,7 @@ static void test_override_scsi_2_controllers(void)
add_scsi_disk(args, 1, 0, 0, 1, 0, 9000, 120, 30);
add_scsi_disk(args, 2, 1, 0, 0, 1, 1, 0, 0);
add_scsi_disk(args, 3, 1, 0, 1, 2, 0, 1, 0);
test_override(args, expected);
test_override(args, "pc", expected);
}
static void test_override_virtio_blk(void)
@ -797,7 +855,23 @@ static void test_override_virtio_blk(void)
add_drive_with_mbr(args, empty_mbr, 1);
add_virtio_disk(args, 0, "pci.0", 3, 10000, 120, 30);
add_virtio_disk(args, 1, "pci.0", 4, 9000, 120, 30);
test_override(args, expected);
test_override(args, "pc", expected);
}
static void test_override_virtio_blk_q35(void)
{
TestArgs *args = create_args();
CHSResult expected[] = {
{"/pci@i0cf8/pci-bridge@1/scsi@3/disk@0,0", {10000, 120, 30} },
{"/pci@i0cf8/pci-bridge@1/scsi@4/disk@0,0", {9000, 120, 30} },
{NULL, {0, 0, 0} }
};
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
setup_pci_bridge(args, "pcie.0", "br");
add_virtio_disk(args, 0, "br", 3, 10000, 120, 30);
add_virtio_disk(args, 1, "br", 4, 9000, 120, 30);
test_override(args, "q35", expected);
}
static void test_override_zero_chs(void)
@ -808,16 +882,65 @@ static void test_override_zero_chs(void)
};
add_drive_with_mbr(args, empty_mbr, 1);
add_ide_disk(args, 0, 1, 1, 0, 0, 0);
test_override(args, expected);
test_override(args, "pc", expected);
}
static void test_override_scsi_hot_unplug(void)
static void test_override_zero_chs_q35(void)
{
TestArgs *args = create_args();
CHSResult expected[] = {
{NULL, {0, 0, 0} }
};
add_drive_with_mbr(args, empty_mbr, 1);
add_ide_disk(args, 0, 0, 0, 0, 0, 0);
test_override(args, "q35", expected);
}
static void test_override_hot_unplug(TestArgs *args, const char *devid,
CHSResult expected[], CHSResult expected2[])
{
QTestState *qts;
char *joined_args;
QFWCFG *fw_cfg;
QDict *response;
int i;
joined_args = g_strjoinv(" ", args->argv);
qts = qtest_initf("%s", joined_args);
fw_cfg = pc_fw_cfg_init(qts);
read_bootdevices(fw_cfg, expected);
/* unplug device an restart */
qtest_qmp_device_del_send(qts, devid);
response = qtest_qmp(qts,
"{ 'execute': 'system_reset', 'arguments': { }}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
qobject_unref(response);
qtest_qmp_eventwait(qts, "RESET");
read_bootdevices(fw_cfg, expected2);
g_free(joined_args);
qtest_quit(qts);
g_free(fw_cfg);
for (i = 0; i < args->n_drives; i++) {
unlink(args->drives[i]);
g_free(args->drives[i]);
}
g_free(args->drives);
g_strfreev(args->argv);
g_free(args);
}
static void test_override_scsi_hot_unplug(void)
{
TestArgs *args = create_args();
CHSResult expected[] = {
{"/pci@i0cf8/scsi@2/channel@0/disk@0,0", {10000, 120, 30} },
@ -834,51 +957,50 @@ static void test_override_scsi_hot_unplug(void)
add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20);
joined_args = g_strjoinv(" ", args->argv);
args->argc = append_arg(args->argc, args->argv, ARGV_SIZE,
g_strdup("-machine pc"));
qts = qtest_initf("-machine pc %s", joined_args);
fw_cfg = pc_fw_cfg_init(qts);
test_override_hot_unplug(args, "scsi-disk0", expected, expected2);
}
read_bootdevices(fw_cfg, expected);
static void test_override_scsi_hot_unplug_q35(void)
{
TestArgs *args = create_args();
CHSResult expected[] = {
{
"/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/channel@0/disk@0,0",
{10000, 120, 30}
},
{
"/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/channel@0/disk@1,0",
{20, 20, 20}
},
{NULL, {0, 0, 0} }
};
CHSResult expected2[] = {
{
"/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/channel@0/disk@1,0",
{20, 20, 20}
},
{NULL, {0, 0, 0} }
};
/* unplug device an restart */
response = qtest_qmp(qts,
"{ 'execute': 'device_del',"
" 'arguments': {'id': 'scsi-disk0' }}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
qobject_unref(response);
response = qtest_qmp(qts,
"{ 'execute': 'system_reset', 'arguments': { }}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
qobject_unref(response);
args->argc = append_arg(args->argc, args->argv, ARGV_SIZE,
g_strdup("-device pcie-root-port,id=p0 "
"-device pcie-pci-bridge,bus=p0,id=b1 "
"-machine q35"));
qtest_qmp_eventwait(qts, "RESET");
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
add_scsi_controller(args, "virtio-scsi-pci", "b1", 2);
add_scsi_disk(args, 0, 0, 0, 0, 0, 10000, 120, 30);
add_scsi_disk(args, 1, 0, 0, 1, 0, 20, 20, 20);
read_bootdevices(fw_cfg, expected2);
g_free(joined_args);
qtest_quit(qts);
g_free(fw_cfg);
for (i = 0; i < args->n_drives; i++) {
unlink(args->drives[i]);
g_free(args->drives[i]);
}
g_free(args->drives);
g_strfreev(args->argv);
g_free(args);
test_override_hot_unplug(args, "scsi-disk0", expected, expected2);
}
static void test_override_virtio_hot_unplug(void)
{
QTestState *qts;
char *joined_args;
QFWCFG *fw_cfg;
QDict *response;
int i;
TestArgs *args = create_args();
CHSResult expected[] = {
{"/pci@i0cf8/scsi@2/disk@0,0", {10000, 120, 30} },
@ -894,42 +1016,45 @@ static void test_override_virtio_hot_unplug(void)
add_virtio_disk(args, 0, "pci.0", 2, 10000, 120, 30);
add_virtio_disk(args, 1, "pci.0", 3, 20, 20, 20);
joined_args = g_strjoinv(" ", args->argv);
args->argc = append_arg(args->argc, args->argv, ARGV_SIZE,
g_strdup("-machine pc"));
qts = qtest_initf("-machine pc %s", joined_args);
fw_cfg = pc_fw_cfg_init(qts);
test_override_hot_unplug(args, "virtio-disk0", expected, expected2);
}
read_bootdevices(fw_cfg, expected);
static void test_override_virtio_hot_unplug_q35(void)
{
TestArgs *args = create_args();
CHSResult expected[] = {
{
"/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@2/disk@0,0",
{10000, 120, 30}
},
{
"/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@3/disk@0,0",
{20, 20, 20}
},
{NULL, {0, 0, 0} }
};
CHSResult expected2[] = {
{
"/pci@i0cf8/pci-bridge@1/pci-bridge@0/scsi@3/disk@0,0",
{20, 20, 20}
},
{NULL, {0, 0, 0} }
};
/* unplug device an restart */
response = qtest_qmp(qts,
"{ 'execute': 'device_del',"
" 'arguments': {'id': 'virtio-disk0' }}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
qobject_unref(response);
response = qtest_qmp(qts,
"{ 'execute': 'system_reset', 'arguments': { }}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
qobject_unref(response);
args->argc = append_arg(args->argc, args->argv, ARGV_SIZE,
g_strdup("-device pcie-root-port,id=p0 "
"-device pcie-pci-bridge,bus=p0,id=b1 "
"-machine q35"));
qtest_qmp_eventwait(qts, "RESET");
add_drive_with_mbr(args, empty_mbr, 1);
add_drive_with_mbr(args, empty_mbr, 1);
add_virtio_disk(args, 0, "b1", 2, 10000, 120, 30);
add_virtio_disk(args, 1, "b1", 3, 20, 20, 20);
read_bootdevices(fw_cfg, expected2);
g_free(joined_args);
qtest_quit(qts);
g_free(fw_cfg);
for (i = 0; i < args->n_drives; i++) {
unlink(args->drives[i]);
g_free(args->drives[i]);
}
g_free(args->drives);
g_strfreev(args->argv);
g_free(args);
test_override_hot_unplug(args, "virtio-disk0", expected, expected2);
}
int main(int argc, char **argv)
@ -974,6 +1099,22 @@ int main(int argc, char **argv)
test_override_scsi_hot_unplug);
qtest_add_func("hd-geo/override/virtio_hot_unplug",
test_override_virtio_hot_unplug);
if (qtest_has_machine("q35")) {
qtest_add_func("hd-geo/override/sata", test_override_sata);
qtest_add_func("hd-geo/override/virtio_blk_q35",
test_override_virtio_blk_q35);
qtest_add_func("hd-geo/override/zero_chs_q35",
test_override_zero_chs_q35);
if (qtest_has_device("lsi53c895a")) {
qtest_add_func("hd-geo/override/scsi_q35",
test_override_scsi_q35);
}
qtest_add_func("hd-geo/override/scsi_hot_unplug_q35",
test_override_scsi_hot_unplug_q35);
qtest_add_func("hd-geo/override/virtio_hot_unplug_q35",
test_override_virtio_hot_unplug_q35);
}
} else {
g_test_message("QTEST_QEMU_IMG not set or qemu-img missing; "
"skipping hd-geo/override/* tests");

View File

@ -378,6 +378,20 @@ static void test_ivshmem_server(void)
close(thread.pipe[0]);
}
static void test_ivshmem_hotplug_q35(void)
{
QTestState *qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1 "
"-device pcie-root-port,id=p1 "
"-device pcie-pci-bridge,bus=p1,id=b1 "
"-machine q35");
qtest_qmp_device_add(qts, "ivshmem-plain", "iv1",
"{'memdev': 'mb1', 'bus': 'b1'}");
qtest_qmp_device_del_send(qts, "iv1");
qtest_quit(qts);
}
#define PCI_SLOT_HP 0x06
static void test_ivshmem_hotplug(void)
@ -469,6 +483,7 @@ int main(int argc, char **argv)
{
int ret, fd;
gchar dir[] = "/tmp/ivshmem-test.XXXXXX";
const char *arch = qtest_get_arch();
g_test_init(&argc, &argv, NULL);
@ -494,6 +509,9 @@ int main(int argc, char **argv)
qtest_add_func("/ivshmem/pair", test_ivshmem_pair);
qtest_add_func("/ivshmem/server", test_ivshmem_server);
}
if (!strcmp(arch, "x86_64") && qtest_has_machine("q35")) {
qtest_add_func("/ivshmem/hotplug-q35", test_ivshmem_hotplug_q35);
}
out:
ret = g_test_run();

View File

@ -179,13 +179,7 @@ void qpci_free_pc(QPCIBus *bus)
void qpci_unplug_acpi_device_test(QTestState *qts, const char *id, uint8_t slot)
{
QDict *response;
response = qtest_qmp(qts, "{'execute': 'device_del',"
" 'arguments': {'id': %s}}", id);
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
qobject_unref(response);
qtest_qmp_device_del_send(qts, id);
qtest_outl(qts, ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot);

View File

@ -66,7 +66,7 @@ struct QTestState
};
static GHookList abrt_hooks;
static struct sigaction sigact_old;
static void (*sighandler_old)(int);
static int qtest_query_target_endianness(QTestState *s);
@ -179,20 +179,12 @@ static void sigabrt_handler(int signo)
static void setup_sigabrt_handler(void)
{
struct sigaction sigact;
/* Catch SIGABRT to clean up on g_assert() failure */
sigact = (struct sigaction){
.sa_handler = sigabrt_handler,
.sa_flags = SA_RESETHAND,
};
sigemptyset(&sigact.sa_mask);
sigaction(SIGABRT, &sigact, &sigact_old);
sighandler_old = signal(SIGABRT, sigabrt_handler);
}
static void cleanup_sigabrt_handler(void)
{
sigaction(SIGABRT, &sigact_old, NULL);
signal(SIGABRT, sighandler_old);
}
static bool hook_list_is_empty(GHookList *hook_list)
@ -1371,15 +1363,19 @@ void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd)
*
* {"return": {}}
*/
void qtest_qmp_device_del_send(QTestState *qts, const char *id)
{
QDict *rsp = qtest_qmp(qts, "{'execute': 'device_del', "
"'arguments': {'id': %s}}", id);
g_assert(rsp);
g_assert(qdict_haskey(rsp, "return"));
g_assert(!qdict_haskey(rsp, "error"));
qobject_unref(rsp);
}
void qtest_qmp_device_del(QTestState *qts, const char *id)
{
QDict *rsp;
rsp = qtest_qmp(qts, "{'execute': 'device_del', 'arguments': {'id': %s}}",
id);
g_assert(qdict_haskey(rsp, "return"));
qobject_unref(rsp);
qtest_qmp_device_del_send(qts, id);
qtest_qmp_eventwait(qts, "DEVICE_DELETED");
}

View File

@ -761,12 +761,22 @@ void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id,
void qtest_qmp_add_client(QTestState *qts, const char *protocol, int fd);
#endif /* _WIN32 */
/**
* qtest_qmp_device_del_send:
* @qts: QTestState instance to operate on
* @id: Identification string
*
* Generic hot-unplugging test via the device_del QMP command.
*/
void qtest_qmp_device_del_send(QTestState *qts, const char *id);
/**
* qtest_qmp_device_del:
* @qts: QTestState instance to operate on
* @id: Identification string
*
* Generic hot-unplugging test via the device_del QMP command.
* Waiting for command completion event.
*/
void qtest_qmp_device_del(QTestState *qts, const char *id);

View File

@ -306,8 +306,14 @@ qtests = {
'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'),
}
gvnc = dependency('gvnc-1.0', required: false)
if gvnc.found()
qtests += {'vnc-display-test': [gvnc]}
qtests_generic += [ 'vnc-display-test' ]
endif
if dbus_display
qtests += {'dbus-display-test': [dbus_display1, gio]}
qtests += {'dbus-display-test': [dbus_display1, gio]}
endif
qtest_executables = {}

View File

@ -102,7 +102,7 @@ static bool ufd_version_check(void)
#endif
static const char *tmpfs;
static char *tmpfs;
/* The boot file modifies memory area in [start_address, end_address)
* repeatedly. It outputs a 'B' at a fixed rate while it's still running.
@ -2451,10 +2451,10 @@ static bool kvm_dirty_ring_supported(void)
int main(int argc, char **argv)
{
char template[] = "/tmp/migration-test-XXXXXX";
const bool has_kvm = qtest_has_accel("kvm");
const bool has_uffd = ufd_version_check();
const char *arch = qtest_get_arch();
g_autoptr(GError) err = NULL;
int ret;
g_test_init(&argc, &argv, NULL);
@ -2479,9 +2479,10 @@ int main(int argc, char **argv)
return g_test_run();
}
tmpfs = g_mkdtemp(template);
tmpfs = g_dir_make_tmp("migration-test-XXXXXX", &err);
if (!tmpfs) {
g_test_message("g_mkdtemp on path (%s): %s", template, strerror(errno));
g_test_message("g_dir_make_tmp on path (%s): %s", tmpfs,
err->message);
}
g_assert(tmpfs);
@ -2612,6 +2613,7 @@ int main(int argc, char **argv)
g_test_message("unable to rmdir: path (%s): %s",
tmpfs, strerror(errno));
}
g_free(tmpfs);
return ret;
}

View File

@ -0,0 +1,103 @@
/*
* VNC display tests
*
* Copyright (c) 2022 Red Hat, Inc.
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/sockets.h"
#include "libqtest.h"
#include <gio/gio.h>
#include <gvnc.h>
typedef struct Test {
QTestState *qts;
VncConnection *conn;
GMainLoop *loop;
} Test;
static void on_vnc_error(VncConnection* self,
const char* msg)
{
g_error("vnc-error: %s", msg);
}
static void on_vnc_auth_failure(VncConnection *self,
const char *msg)
{
g_error("vnc-auth-failure: %s", msg);
}
static bool
test_setup(Test *test)
{
#ifdef WIN32
g_test_skip("Not supported on Windows yet");
return false;
#else
int pair[2];
test->qts = qtest_init("-vnc none -name vnc-test");
g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0);
qtest_qmp_add_client(test->qts, "vnc", pair[1]);
test->conn = vnc_connection_new();
g_signal_connect(test->conn, "vnc-error",
G_CALLBACK(on_vnc_error), NULL);
g_signal_connect(test->conn, "vnc-auth-failure",
G_CALLBACK(on_vnc_auth_failure), NULL);
vnc_connection_set_auth_type(test->conn, VNC_CONNECTION_AUTH_NONE);
vnc_connection_open_fd(test->conn, pair[0]);
test->loop = g_main_loop_new(NULL, FALSE);
return true;
#endif
}
static void
test_vnc_basic_on_vnc_initialized(VncConnection *self,
Test *test)
{
const char *name = vnc_connection_get_name(test->conn);
g_assert_cmpstr(name, ==, "QEMU (vnc-test)");
g_main_loop_quit(test->loop);
}
static void
test_vnc_basic(void)
{
Test test;
if (!test_setup(&test)) {
return;
}
g_signal_connect(test.conn, "vnc-initialized",
G_CALLBACK(test_vnc_basic_on_vnc_initialized), &test);
g_main_loop_run(test.loop);
qtest_quit(test.qts);
g_object_unref(test.conn);
g_main_loop_unref(test.loop);
}
int
main(int argc, char **argv)
{
if (getenv("GTK_VNC_DEBUG")) {
vnc_util_set_debug(true);
}
g_test_init(&argc, &argv, NULL);
qtest_add_func("/vnc-display/basic", test_vnc_basic);
return g_test_run();
}

View File

@ -25,7 +25,6 @@
struct QIOChannelTest {
QIOChannel *src;
QIOChannel *dst;
bool blocking;
size_t len;
size_t niov;
char *input;
@ -42,8 +41,6 @@ static gpointer test_io_thread_writer(gpointer opaque)
{
QIOChannelTest *data = opaque;
qio_channel_set_blocking(data->src, data->blocking, NULL);
qio_channel_writev_all(data->src,
data->inputv,
data->niov,
@ -58,8 +55,6 @@ static gpointer test_io_thread_reader(gpointer opaque)
{
QIOChannelTest *data = opaque;
qio_channel_set_blocking(data->dst, data->blocking, NULL);
qio_channel_readv_all(data->dst,
data->outputv,
data->niov,
@ -113,7 +108,9 @@ void qio_channel_test_run_threads(QIOChannelTest *test,
test->src = src;
test->dst = dst;
test->blocking = blocking;
qio_channel_set_blocking(test->dst, blocking, NULL);
qio_channel_set_blocking(test->src, blocking, NULL);
reader = g_thread_new("reader",
test_io_thread_reader,

View File

@ -79,7 +79,7 @@ static void test_image_locking_basic(void)
g_autofree char *img_path = NULL;
uint64_t perm, shared_perm;
int fd = g_file_open_tmp("qtest.XXXXXX", &img_path, NULL);
int fd = g_file_open_tmp("qemu-tst-img-lock.XXXXXX", &img_path, NULL);
assert(fd >= 0);
perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
@ -120,7 +120,7 @@ static void test_set_perm_abort(void)
g_autofree char *img_path = NULL;
uint64_t perm, shared_perm;
int r;
int fd = g_file_open_tmp("qtest.XXXXXX", &img_path, NULL);
int fd = g_file_open_tmp("qemu-tst-img-lock.XXXXXX", &img_path, NULL);
assert(fd >= 0);
perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
@ -140,6 +140,8 @@ static void test_set_perm_abort(void)
check_locked_bytes(fd, perm, ~shared_perm);
blk_unref(blk1);
blk_unref(blk2);
close(fd);
unlink(img_path);
}
int main(int argc, char **argv)

View File

@ -24,29 +24,30 @@
#include "qapi/error.h"
#include "qemu/module.h"
#ifndef WIN32
#define TEST_FIFO "test-io-channel-command.fifo"
#define SOCAT_SRC "PIPE:" TEST_FIFO ",wronly"
#define SOCAT_DST "PIPE:" TEST_FIFO ",rdonly"
static char *socat = NULL;
static void test_io_channel_command_fifo(bool async)
{
#define TEST_FIFO "tests/test-io-channel-command.fifo"
QIOChannel *src, *dst;
QIOChannelTest *test;
const char *srcfifo = "PIPE:" TEST_FIFO ",wronly";
const char *dstfifo = "PIPE:" TEST_FIFO ",rdonly";
const char *srcargv[] = {
"/bin/socat", "-", srcfifo, NULL,
socat, "-", SOCAT_SRC, NULL,
};
const char *dstargv[] = {
"/bin/socat", dstfifo, "-", NULL,
socat, SOCAT_DST, "-", NULL,
};
unlink(TEST_FIFO);
if (access("/bin/socat", X_OK) < 0) {
g_test_skip("socat is missing");
if (!socat) {
g_test_skip("socat is not found in PATH");
return;
}
if (mkfifo(TEST_FIFO, 0600) < 0) {
abort();
}
unlink(TEST_FIFO);
src = QIO_CHANNEL(qio_channel_command_new_spawn(srcargv,
O_WRONLY,
&error_abort));
@ -81,11 +82,12 @@ static void test_io_channel_command_echo(bool async)
QIOChannel *ioc;
QIOChannelTest *test;
const char *socatargv[] = {
"/bin/socat", "-", "-", NULL,
socat, "-", "-", NULL,
};
if (access("/bin/socat", X_OK) < 0) {
return; /* Pretend success if socat is not present */
if (!socat) {
g_test_skip("socat is not found in PATH");
return;
}
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(socatargv,
@ -108,7 +110,6 @@ static void test_io_channel_command_echo_sync(void)
{
test_io_channel_command_echo(false);
}
#endif
int main(int argc, char **argv)
{
@ -116,7 +117,8 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
#ifndef WIN32
socat = g_find_program_in_path("socat");
g_test_add_func("/io/channel/command/fifo/sync",
test_io_channel_command_fifo_sync);
g_test_add_func("/io/channel/command/fifo/async",
@ -125,7 +127,6 @@ int main(int argc, char **argv)
test_io_channel_command_echo_sync);
g_test_add_func("/io/channel/command/echo/async",
test_io_channel_command_echo_async);
#endif
return g_test_run();
}

View File

@ -195,6 +195,9 @@ void gd_egl_switch(DisplayChangeListener *dcl,
if (resized) {
gd_update_windowsize(vc);
}
eglMakeCurrent(qemu_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
QEMUGLContext gd_egl_create_context(DisplayGLCtx *dgc,

View File

@ -681,9 +681,13 @@ static void gd_mouse_mode_change(Notifier *notify, void *data)
s = container_of(notify, GtkDisplayState, mouse_mode_notifier);
/* release the grab at switching to absolute mode */
if (qemu_input_is_absolute() && gd_is_grab_active(s)) {
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
FALSE);
if (qemu_input_is_absolute() && s->ptr_owner) {
if (!s->ptr_owner->window) {
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->grab_item),
FALSE);
} else {
gd_ungrab_pointer(s);
}
}
for (i = 0; i < s->nb_vcs; i++) {
VirtualConsole *vc = &s->vc[i];
@ -2167,7 +2171,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
return group;
}
static GtkWidget *gd_create_menu_view(GtkDisplayState *s)
static GtkWidget *gd_create_menu_view(GtkDisplayState *s, DisplayOptions *opts)
{
GSList *group = NULL;
GtkWidget *view_menu;
@ -2265,7 +2269,8 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s)
s->show_menubar_item = gtk_check_menu_item_new_with_mnemonic(
_("Show Menubar"));
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->show_menubar_item),
TRUE);
!opts->u.gtk.has_show_menubar ||
opts->u.gtk.show_menubar);
gtk_accel_group_connect(s->accel_group, GDK_KEY_m, HOTKEY_MODIFIERS, 0,
g_cclosure_new_swap(G_CALLBACK(gd_accel_show_menubar), s, NULL));
gtk_accel_label_set_accel(
@ -2276,13 +2281,13 @@ static GtkWidget *gd_create_menu_view(GtkDisplayState *s)
return view_menu;
}
static void gd_create_menus(GtkDisplayState *s)
static void gd_create_menus(GtkDisplayState *s, DisplayOptions *opts)
{
GtkSettings *settings;
s->accel_group = gtk_accel_group_new();
s->machine_menu = gd_create_menu_machine(s);
s->view_menu = gd_create_menu_view(s);
s->view_menu = gd_create_menu_view(s, opts);
s->machine_menu_item = gtk_menu_item_new_with_mnemonic(_("_Machine"));
gtk_menu_item_set_submenu(GTK_MENU_ITEM(s->machine_menu_item),
@ -2359,7 +2364,7 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
gtk_window_set_icon_name(GTK_WINDOW(s->window), "qemu");
gd_create_menus(s);
gd_create_menus(s, opts);
gd_connect_signals(s);
@ -2374,6 +2379,10 @@ static void gtk_display_init(DisplayState *ds, DisplayOptions *opts)
gtk_container_add(GTK_CONTAINER(s->window), s->vbox);
gtk_widget_show_all(s->window);
if (opts->u.gtk.has_show_menubar &&
!opts->u.gtk.show_menubar) {
gtk_widget_hide(s->menu_bar);
}
vc = gd_vc_find_current(s);
gtk_widget_set_sensitive(s->view_menu, vc != NULL);

View File

@ -2442,8 +2442,8 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
if (len == 1) {
return 8;
}
uint32_t dlen = abs(read_s32(data, 4));
if (len == 8) {
uint32_t dlen = abs(read_s32(data, 4));
if (dlen > (1 << 20)) {
error_report("vnc: client_cut_text msg payload has %u bytes"
" which exceeds our limit of 1MB.", dlen);
@ -2456,8 +2456,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
}
if (read_s32(data, 4) < 0) {
vnc_client_cut_text_ext(vs, abs(read_s32(data, 4)),
read_u32(data, 8), data + 12);
if (dlen < 4) {
error_report("vnc: malformed payload (header less than 4 bytes)"
" in extended clipboard pseudo-encoding.");
vnc_client_error(vs);
break;
}
vnc_client_cut_text_ext(vs, dlen, read_u32(data, 8), data + 12);
break;
}
vnc_client_cut_text(vs, read_u32(data, 4), data + 8);

View File

@ -111,12 +111,17 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
/*XXX Note: windows has WSASend() and WSARecv() */
unsigned i = 0;
ssize_t ret = 0;
ssize_t off = 0;
while (i < iov_cnt) {
ssize_t r = do_send
? send(sockfd, iov[i].iov_base, iov[i].iov_len, 0)
: recv(sockfd, iov[i].iov_base, iov[i].iov_len, 0);
? send(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0)
: recv(sockfd, iov[i].iov_base + off, iov[i].iov_len - off, 0);
if (r > 0) {
ret += r;
off += r;
if (off < iov[i].iov_len) {
continue;
}
} else if (!r) {
break;
} else if (errno == EINTR) {
@ -129,6 +134,7 @@ do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
}
break;
}
off = 0;
i++;
}
return ret;

View File

@ -538,18 +538,22 @@ int socket_init(void)
#ifndef CONFIG_IOVEC
/* helper function for iov_send_recv() */
static ssize_t
readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
{
unsigned i = 0;
ssize_t ret = 0;
ssize_t off = 0;
while (i < iov_cnt) {
ssize_t r = do_write
? write(fd, iov[i].iov_base, iov[i].iov_len)
: read(fd, iov[i].iov_base, iov[i].iov_len);
? write(fd, iov[i].iov_base + off, iov[i].iov_len - off)
: read(fd, iov[i].iov_base + off, iov[i].iov_len - off);
if (r > 0) {
ret += r;
off += r;
if (off < iov[i].iov_len) {
continue;
}
} else if (!r) {
break;
} else if (errno == EINTR) {
@ -562,6 +566,7 @@ readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
}
break;
}
off = 0;
i++;
}
return ret;

View File

@ -19,12 +19,39 @@
static bool name_threads;
typedef HRESULT (WINAPI *pSetThreadDescription) (HANDLE hThread,
PCWSTR lpThreadDescription);
static pSetThreadDescription SetThreadDescriptionFunc;
static HMODULE kernel32_module;
static bool load_set_thread_description(void)
{
static gsize _init_once = 0;
if (g_once_init_enter(&_init_once)) {
kernel32_module = LoadLibrary("kernel32.dll");
if (kernel32_module) {
SetThreadDescriptionFunc =
(pSetThreadDescription)GetProcAddress(kernel32_module,
"SetThreadDescription");
if (!SetThreadDescriptionFunc) {
FreeLibrary(kernel32_module);
}
}
g_once_init_leave(&_init_once, 1);
}
return !!SetThreadDescriptionFunc;
}
void qemu_thread_naming(bool enable)
{
/* But note we don't actually name them on Windows yet */
name_threads = enable;
fprintf(stderr, "qemu: thread naming not supported on this host\n");
if (enable && !load_set_thread_description()) {
fprintf(stderr, "qemu: thread naming not supported on this host\n");
name_threads = false;
}
}
static void error_exit(int err, const char *msg)
@ -400,6 +427,25 @@ void *qemu_thread_join(QemuThread *thread)
return ret;
}
static bool set_thread_description(HANDLE h, const char *name)
{
HRESULT hr;
g_autofree wchar_t *namew = NULL;
if (!load_set_thread_description()) {
return false;
}
namew = g_utf8_to_utf16(name, -1, NULL, NULL, NULL);
if (!namew) {
return false;
}
hr = SetThreadDescriptionFunc(h, namew);
return SUCCEEDED(hr);
}
void qemu_thread_create(QemuThread *thread, const char *name,
void *(*start_routine)(void *),
void *arg, int mode)
@ -423,7 +469,11 @@ void qemu_thread_create(QemuThread *thread, const char *name,
if (!hThread) {
error_exit(GetLastError(), __func__);
}
if (name_threads && name && !set_thread_description(hThread, name)) {
fprintf(stderr, "qemu: failed to set thread description: %s\n", name);
}
CloseHandle(hThread);
thread->data = data;
}