aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/9pfs/Kconfig5
-rw-r--r--hw/arm/virt.c9
-rw-r--r--hw/audio/ac97.c11
-rw-r--r--hw/audio/adlib.c5
-rw-r--r--hw/audio/cs4231a.c5
-rw-r--r--hw/audio/es1370.c13
-rw-r--r--hw/audio/gus.c7
-rw-r--r--hw/audio/hda-codec.c17
-rw-r--r--hw/audio/milkymist-ac97.c14
-rw-r--r--hw/audio/pcspk.c3
-rw-r--r--hw/audio/pl041.c1
-rw-r--r--hw/audio/sb16.c3
-rw-r--r--hw/audio/wm8750.c10
-rw-r--r--hw/char/spapr_vty.c30
-rw-r--r--hw/core/loader.c48
-rw-r--r--hw/core/machine.c3
-rw-r--r--hw/core/qdev-properties-system.c57
-rw-r--r--hw/i386/pc.c28
-rw-r--r--hw/i386/pc_piix.c14
-rw-r--r--hw/i386/pc_q35.c13
-rw-r--r--hw/intc/pnv_xive.c9
-rw-r--r--hw/intc/spapr_xive.c6
-rw-r--r--hw/intc/xive.c206
-rw-r--r--hw/ppc/Makefile.objs1
-rw-r--r--hw/ppc/ppc.c13
-rw-r--r--hw/ppc/spapr.c115
-rw-r--r--hw/ppc/spapr_caps.c46
-rw-r--r--hw/ppc/spapr_drc.c7
-rw-r--r--hw/ppc/spapr_hcall.c167
-rw-r--r--hw/ppc/spapr_iommu.c2
-rw-r--r--hw/ppc/spapr_irq.c7
-rw-r--r--hw/ppc/spapr_pci.c29
-rw-r--r--hw/ppc/spapr_rtas.c32
-rw-r--r--hw/ppc/spapr_tpm_proxy.c178
-rw-r--r--hw/ppc/trace-events4
-rw-r--r--hw/s390x/s390-virtio-ccw.c14
-rw-r--r--hw/scsi/lsi53c895a.c41
-rw-r--r--hw/timer/mc146818rtc.c19
-rw-r--r--hw/usb/dev-audio.c1
39 files changed, 999 insertions, 194 deletions
diff --git a/hw/9pfs/Kconfig b/hw/9pfs/Kconfig
index 8c5032c575..3ae5749661 100644
--- a/hw/9pfs/Kconfig
+++ b/hw/9pfs/Kconfig
@@ -1,4 +1,9 @@
+config FSDEV_9P
+ bool
+ depends on VIRTFS
+
config VIRTIO_9P
bool
default y
depends on VIRTFS && VIRTIO
+ select FSDEV_9P
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 02510acb81..0d1629ccb3 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -2050,10 +2050,17 @@ static void machvirt_machine_init(void)
}
type_init(machvirt_machine_init);
+static void virt_machine_4_2_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(4, 2)
+
static void virt_machine_4_1_options(MachineClass *mc)
{
+ virt_machine_4_2_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
}
-DEFINE_VIRT_MACHINE_AS_LATEST(4, 1)
+DEFINE_VIRT_MACHINE(4, 1)
static void virt_machine_4_0_options(MachineClass *mc)
{
diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c
index 115ee51c7c..a136b97f68 100644
--- a/hw/audio/ac97.c
+++ b/hw/audio/ac97.c
@@ -965,7 +965,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
uint32_t temp = r->picb << 1;
uint32_t written = 0;
int to_copy = 0;
- temp = audio_MIN (temp, max);
+ temp = MIN (temp, max);
if (!temp) {
*stop = 1;
@@ -974,7 +974,7 @@ static int write_audio (AC97LinkState *s, AC97BusMasterRegs *r,
while (temp) {
int copied;
- to_copy = audio_MIN (temp, sizeof (tmpbuf));
+ to_copy = MIN (temp, sizeof (tmpbuf));
pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
copied = AUD_write (s->voice_po, tmpbuf, to_copy);
dolog ("write_audio max=%x to_copy=%x copied=%x\n",
@@ -1020,7 +1020,7 @@ static void write_bup (AC97LinkState *s, int elapsed)
}
while (elapsed) {
- int temp = audio_MIN (elapsed, sizeof (s->silence));
+ int temp = MIN (elapsed, sizeof (s->silence));
while (temp) {
int copied = AUD_write (s->voice_po, s->silence, temp);
if (!copied)
@@ -1041,7 +1041,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
int to_copy = 0;
SWVoiceIn *voice = (r - s->bm_regs) == MC_INDEX ? s->voice_mc : s->voice_pi;
- temp = audio_MIN (temp, max);
+ temp = MIN (temp, max);
if (!temp) {
*stop = 1;
@@ -1050,7 +1050,7 @@ static int read_audio (AC97LinkState *s, AC97BusMasterRegs *r,
while (temp) {
int acquired;
- to_copy = audio_MIN (temp, sizeof (tmpbuf));
+ to_copy = MIN (temp, sizeof (tmpbuf));
acquired = AUD_read (voice, tmpbuf, to_copy);
if (!acquired) {
*stop = 1;
@@ -1410,6 +1410,7 @@ static int ac97_init (PCIBus *bus)
}
static Property ac97_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(AC97LinkState, card),
DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
DEFINE_PROP_END_OF_LIST (),
};
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 2f4aacbf43..cb4178d861 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -195,7 +195,7 @@ static void adlib_callback (void *opaque, int free)
return;
}
- to_play = audio_MIN (s->left, samples);
+ to_play = MIN (s->left, samples);
while (to_play) {
written = write_audio (s, to_play);
@@ -210,7 +210,7 @@ static void adlib_callback (void *opaque, int free)
}
}
- samples = audio_MIN (samples, s->samples - s->pos);
+ samples = MIN (samples, s->samples - s->pos);
if (!samples) {
return;
}
@@ -299,6 +299,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
}
static Property adlib_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(AdlibState, card),
DEFINE_PROP_UINT32 ("iobase", AdlibState, port, 0x220),
DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100),
DEFINE_PROP_END_OF_LIST (),
diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c
index d77a4e713e..c7b8067489 100644
--- a/hw/audio/cs4231a.c
+++ b/hw/audio/cs4231a.c
@@ -536,7 +536,7 @@ static int cs_write_audio (CSState *s, int nchan, int dma_pos,
int copied;
size_t to_copy;
- to_copy = audio_MIN (temp, left);
+ to_copy = MIN (temp, left);
if (to_copy > sizeof (tmpbuf)) {
to_copy = sizeof (tmpbuf);
}
@@ -579,7 +579,7 @@ static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
till = (s->dregs[Playback_Lower_Base_Count]
| (s->dregs[Playback_Upper_Base_Count] << 8)) << s->shift;
till -= s->transferred;
- copy = audio_MIN (till, copy);
+ copy = MIN (till, copy);
}
if ((copy <= 0) || (dma_len <= 0)) {
@@ -690,6 +690,7 @@ static int cs4231a_init (ISABus *bus)
}
static Property cs4231a_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(CSState, card),
DEFINE_PROP_UINT32 ("iobase", CSState, port, 0x534),
DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c
index 39deecbbc6..f9e9f2a3b3 100644
--- a/hw/audio/es1370.c
+++ b/hw/audio/es1370.c
@@ -645,7 +645,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
int size = d->frame_cnt & 0xffff;
int left = ((size - cnt + 1) << 2) + d->leftover;
int transferred = 0;
- int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
+ int temp = MIN (max, MIN (left, csc_bytes));
int index = d - &s->chan[0];
addr += (cnt << 2) + d->leftover;
@@ -654,7 +654,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
while (temp) {
int acquired, to_copy;
- to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+ to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
if (!acquired)
break;
@@ -672,7 +672,7 @@ static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
while (temp) {
int copied, to_copy;
- to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
+ to_copy = MIN ((size_t) temp, sizeof (tmpbuf));
pci_dma_read (&s->dev, addr, tmpbuf, to_copy);
copied = AUD_write (voice, tmpbuf, to_copy);
if (!copied)
@@ -887,6 +887,11 @@ static int es1370_init (PCIBus *bus)
return 0;
}
+static Property es1370_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(ES1370State, card),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void es1370_class_init (ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
@@ -903,6 +908,7 @@ static void es1370_class_init (ObjectClass *klass, void *data)
dc->desc = "ENSONIQ AudioPCI ES1370";
dc->vmsd = &vmstate_es1370;
dc->reset = es1370_on_reset;
+ dc->props = es1370_properties;
}
static const TypeInfo es1370_info = {
@@ -923,4 +929,3 @@ static void es1370_register_types (void)
}
type_init (es1370_register_types)
-
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index dbfe7cf634..2b6b7c4e3f 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -119,7 +119,7 @@ static void GUS_callback (void *opaque, int free)
GUSState *s = opaque;
samples = free >> s->shift;
- to_play = audio_MIN (samples, s->left);
+ to_play = MIN (samples, s->left);
while (to_play) {
int written = write_audio (s, to_play);
@@ -134,7 +134,7 @@ static void GUS_callback (void *opaque, int free)
net += written;
}
- samples = audio_MIN (samples, s->samples);
+ samples = MIN (samples, s->samples);
if (samples) {
gus_mixvoices (&s->emu, s->freq, samples, s->mixbuf);
@@ -194,7 +194,7 @@ static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
ldebug ("read DMA %#x %d\n", dma_pos, dma_len);
mode = k->has_autoinitialization(s->isa_dma, s->emu.gusdma);
while (left) {
- int to_copy = audio_MIN ((size_t) left, sizeof (tmpbuf));
+ int to_copy = MIN ((size_t) left, sizeof (tmpbuf));
int copied;
ldebug ("left=%d to_copy=%d pos=%d\n", left, to_copy, pos);
@@ -299,6 +299,7 @@ static int GUS_init (ISABus *bus)
}
static Property gus_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(GUSState, card),
DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
DEFINE_PROP_UINT32 ("iobase", GUSState, port, 0x240),
DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 4fee0673d9..f17e8d8dce 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -235,10 +235,10 @@ static void hda_audio_input_timer(void *opaque)
goto out_timer;
}
- int64_t to_transfer = audio_MIN(wpos - rpos, wanted_rpos - rpos);
+ int64_t to_transfer = MIN(wpos - rpos, wanted_rpos - rpos);
while (to_transfer) {
uint32_t start = (rpos & B_MASK);
- uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer);
+ uint32_t chunk = MIN(B_SIZE - start, to_transfer);
int rc = hda_codec_xfer(
&st->state->hda, st->stream, false, st->buf + start, chunk);
if (!rc) {
@@ -263,13 +263,13 @@ static void hda_audio_input_cb(void *opaque, int avail)
int64_t wpos = st->wpos;
int64_t rpos = st->rpos;
- int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), avail);
+ int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), avail);
hda_timer_sync_adjust(st, -((wpos - rpos) + to_transfer - (B_SIZE >> 1)));
while (to_transfer) {
uint32_t start = (uint32_t) (wpos & B_MASK);
- uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer);
+ uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
uint32_t read = AUD_read(st->voice.in, st->buf + start, chunk);
wpos += read;
to_transfer -= read;
@@ -299,10 +299,10 @@ static void hda_audio_output_timer(void *opaque)
goto out_timer;
}
- int64_t to_transfer = audio_MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos);
+ int64_t to_transfer = MIN(B_SIZE - (wpos - rpos), wanted_wpos - wpos);
while (to_transfer) {
uint32_t start = (wpos & B_MASK);
- uint32_t chunk = audio_MIN(B_SIZE - start, to_transfer);
+ uint32_t chunk = MIN(B_SIZE - start, to_transfer);
int rc = hda_codec_xfer(
&st->state->hda, st->stream, true, st->buf + start, chunk);
if (!rc) {
@@ -327,7 +327,7 @@ static void hda_audio_output_cb(void *opaque, int avail)
int64_t wpos = st->wpos;
int64_t rpos = st->rpos;
- int64_t to_transfer = audio_MIN(wpos - rpos, avail);
+ int64_t to_transfer = MIN(wpos - rpos, avail);
if (wpos - rpos == B_SIZE) {
/* drop buffer, reset timer adjust */
@@ -342,7 +342,7 @@ static void hda_audio_output_cb(void *opaque, int avail)
while (to_transfer) {
uint32_t start = (uint32_t) (rpos & B_MASK);
- uint32_t chunk = (uint32_t) audio_MIN(B_SIZE - start, to_transfer);
+ uint32_t chunk = (uint32_t) MIN(B_SIZE - start, to_transfer);
uint32_t written = AUD_write(st->voice.out, st->buf + start, chunk);
rpos += written;
to_transfer -= written;
@@ -841,6 +841,7 @@ static const VMStateDescription vmstate_hda_audio = {
};
static Property hda_audio_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(HDAAudioState, card),
DEFINE_PROP_UINT32("debug", HDAAudioState, debug, 0),
DEFINE_PROP_BOOL("mixer", HDAAudioState, mixer, true),
DEFINE_PROP_BOOL("use-timer", HDAAudioState, use_timer, true),
diff --git a/hw/audio/milkymist-ac97.c b/hw/audio/milkymist-ac97.c
index 481dde10a1..6d409eff1b 100644
--- a/hw/audio/milkymist-ac97.c
+++ b/hw/audio/milkymist-ac97.c
@@ -185,7 +185,7 @@ static void ac97_in_cb(void *opaque, int avail_b)
MilkymistAC97State *s = opaque;
uint8_t buf[4096];
uint32_t remaining = s->regs[R_U_REMAINING];
- int temp = audio_MIN(remaining, avail_b);
+ int temp = MIN(remaining, avail_b);
uint32_t addr = s->regs[R_U_ADDR];
int transferred = 0;
@@ -199,7 +199,7 @@ static void ac97_in_cb(void *opaque, int avail_b)
while (temp) {
int acquired, to_copy;
- to_copy = audio_MIN(temp, sizeof(buf));
+ to_copy = MIN(temp, sizeof(buf));
acquired = AUD_read(s->voice_in, buf, to_copy);
if (!acquired) {
break;
@@ -228,7 +228,7 @@ static void ac97_out_cb(void *opaque, int free_b)
MilkymistAC97State *s = opaque;
uint8_t buf[4096];
uint32_t remaining = s->regs[R_D_REMAINING];
- int temp = audio_MIN(remaining, free_b);
+ int temp = MIN(remaining, free_b);
uint32_t addr = s->regs[R_D_ADDR];
int transferred = 0;
@@ -242,7 +242,7 @@ static void ac97_out_cb(void *opaque, int free_b)
while (temp) {
int copied, to_copy;
- to_copy = audio_MIN(temp, sizeof(buf));
+ to_copy = MIN(temp, sizeof(buf));
cpu_physical_memory_read(addr, buf, to_copy);
copied = AUD_write(s->voice_out, buf, to_copy);
if (!copied) {
@@ -330,6 +330,11 @@ static const VMStateDescription vmstate_milkymist_ac97 = {
}
};
+static Property milkymist_ac97_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(MilkymistAC97State, card),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -337,6 +342,7 @@ static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
dc->realize = milkymist_ac97_realize;
dc->reset = milkymist_ac97_reset;
dc->vmsd = &vmstate_milkymist_ac97;
+ dc->props = milkymist_ac97_properties;
}
static const TypeInfo milkymist_ac97_info = {
diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c
index 016946d4b2..d773eb80de 100644
--- a/hw/audio/pcspk.c
+++ b/hw/audio/pcspk.c
@@ -103,7 +103,7 @@ static void pcspk_callback(void *opaque, int free)
}
while (free > 0) {
- n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
+ n = MIN(s->samples - s->play_pos, (unsigned int)free);
n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
if (!n)
break;
@@ -209,6 +209,7 @@ static const VMStateDescription vmstate_spk = {
};
static Property pcspk_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(PCSpkState, card),
DEFINE_PROP_UINT32("iobase", PCSpkState, iobase, -1),
DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c
index ca91399078..c30417d46d 100644
--- a/hw/audio/pl041.c
+++ b/hw/audio/pl041.c
@@ -625,6 +625,7 @@ static const VMStateDescription vmstate_pl041 = {
};
static Property pl041_device_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(PL041State, codec.card),
/* Non-compact FIFO depth property */
DEFINE_PROP_UINT32("nc_fifo_depth", PL041State, fifo_depth,
DEFAULT_FIFO_DEPTH),
diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c
index 3ad01f3599..a354f94acb 100644
--- a/hw/audio/sb16.c
+++ b/hw/audio/sb16.c
@@ -1169,7 +1169,7 @@ static int write_audio (SB16State *s, int nchan, int dma_pos,
int copied;
size_t to_copy;
- to_copy = audio_MIN (temp, left);
+ to_copy = MIN (temp, left);
if (to_copy > sizeof (tmpbuf)) {
to_copy = sizeof (tmpbuf);
}
@@ -1422,6 +1422,7 @@ static int SB16_init (ISABus *bus)
}
static Property sb16_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(SB16State, card),
DEFINE_PROP_UINT32 ("version", SB16State, ver, 0x0405), /* 4.5 */
DEFINE_PROP_UINT32 ("iobase", SB16State, port, 0x220),
DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c
index 9f6df5d59c..601ed04aff 100644
--- a/hw/audio/wm8750.c
+++ b/hw/audio/wm8750.c
@@ -70,7 +70,7 @@ static inline void wm8750_in_load(WM8750State *s)
{
if (s->idx_in + s->req_in <= sizeof(s->data_in))
return;
- s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
+ s->idx_in = MAX(0, (int) sizeof(s->data_in) - s->req_in);
AUD_read(*s->in[0], s->data_in + s->idx_in,
sizeof(s->data_in) - s->idx_in);
}
@@ -101,7 +101,7 @@ static void wm8750_audio_out_cb(void *opaque, int free_b)
wm8750_out_flush(s);
} else
s->req_out = free_b - s->idx_out;
-
+
s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
}
@@ -702,6 +702,11 @@ void wm8750_set_bclk_in(void *opaque, int new_hz)
wm8750_clk_update(s, 1);
}
+static Property wm8750_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(WM8750State, card),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void wm8750_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -712,6 +717,7 @@ static void wm8750_class_init(ObjectClass *klass, void *data)
sc->recv = wm8750_rx;
sc->send = wm8750_tx;
dc->vmsd = &vmstate_wm8750;
+ dc->props = wm8750_properties;
}
static const TypeInfo wm8750_info = {
diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c
index 7f860fcce7..087c93e4fa 100644
--- a/hw/char/spapr_vty.c
+++ b/hw/char/spapr_vty.c
@@ -59,25 +59,19 @@ static int vty_getchars(SpaprVioDevice *sdev, uint8_t *buf, int max)
int n = 0;
while ((n < max) && (dev->out != dev->in)) {
- buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
-
- /* PowerVM's vty implementation has a bug where it inserts a
- * \0 after every \r going to the guest. Existing guests have
- * a workaround for this which removes every \0 immediately
- * following a \r, so here we make ourselves bug-for-bug
- * compatible, so that the guest won't drop a real \0-after-\r
- * that happens to occur in a binary stream. */
- if (buf[n - 1] == '\r') {
- if (n < max) {
- buf[n++] = '\0';
- } else {
- /* No room for the extra \0, roll back and try again
- * next time */
- dev->out--;
- n--;
- break;
- }
+ /*
+ * Long ago, PowerVM's vty implementation had a bug where it
+ * inserted a \0 after every \r going to the guest. Existing
+ * guests have a workaround for this which removes every \0
+ * immediately following a \r. To avoid triggering this
+ * workaround, we stop before inserting a \0 if the preceding
+ * character in the output buffer is a \r.
+ */
+ if (n > 0 && (buf[n - 1] == '\r') &&
+ (dev->buf[dev->out % VTERM_BUFSIZE] == '\0')) {
+ break;
}
+ buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
}
qemu_chr_fe_accept_input(&dev->chardev);
diff --git a/hw/core/loader.c b/hw/core/loader.c
index 84e4f3efac..32f7cc7c33 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -58,6 +58,7 @@
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "qemu/cutils.h"
+#include "sysemu/runstate.h"
#include <zlib.h>
@@ -838,6 +839,7 @@ struct Rom {
int isrom;
char *fw_dir;
char *fw_file;
+ GMappedFile *mapped_file;
bool committed;
@@ -848,10 +850,25 @@ struct Rom {
static FWCfgState *fw_cfg;
static QTAILQ_HEAD(, Rom) roms = QTAILQ_HEAD_INITIALIZER(roms);
-/* rom->data must be heap-allocated (do not use with rom_add_elf_program()) */
+/*
+ * rom->data can be heap-allocated or memory-mapped (e.g. when added with
+ * rom_add_elf_program())
+ */
+static void rom_free_data(Rom *rom)
+{
+ if (rom->mapped_file) {
+ g_mapped_file_unref(rom->mapped_file);
+ rom->mapped_file = NULL;
+ } else {
+ g_free(rom->data);
+ }
+
+ rom->data = NULL;
+}
+
static void rom_free(Rom *rom)
{
- g_free(rom->data);
+ rom_free_data(rom);
g_free(rom->path);
g_free(rom->name);
g_free(rom->fw_dir);
@@ -1058,11 +1075,12 @@ MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
/* This function is specific for elf program because we don't need to allocate
* all the rom. We just allocate the first part and the rest is just zeros. This
- * is why romsize and datasize are different. Also, this function seize the
- * memory ownership of "data", so we don't have to allocate and copy the buffer.
+ * is why romsize and datasize are different. Also, this function takes its own
+ * reference to "mapped_file", so we don't have to allocate and copy the buffer.
*/
-int rom_add_elf_program(const char *name, void *data, size_t datasize,
- size_t romsize, hwaddr addr, AddressSpace *as)
+int rom_add_elf_program(const char *name, GMappedFile *mapped_file, void *data,
+ size_t datasize, size_t romsize, hwaddr addr,
+ AddressSpace *as)
{
Rom *rom;
@@ -1073,6 +1091,12 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize,
rom->romsize = romsize;
rom->data = data;
rom->as = as;
+
+ if (mapped_file && data) {
+ g_mapped_file_ref(mapped_file);
+ rom->mapped_file = mapped_file;
+ }
+
rom_insert(rom);
return 0;
}
@@ -1091,6 +1115,15 @@ static void rom_reset(void *unused)
{
Rom *rom;
+ /*
+ * We don't need to fill in the RAM with ROM data because we'll fill
+ * the data in during the next incoming migration in all cases. Note
+ * that some of those RAMs can actually be modified by the guest on ARM
+ * so this is probably the only right thing to do here.
+ */
+ if (runstate_check(RUN_STATE_INMIGRATE))
+ return;
+
QTAILQ_FOREACH(rom, &roms, next) {
if (rom->fw_file) {
continue;
@@ -1107,8 +1140,7 @@ static void rom_reset(void *unused)
}
if (rom->isrom) {
/* rom needs to be written only once */
- g_free(rom->data);
- rom->data = NULL;
+ rom_free_data(rom);
}
/*
* The rom loader is really on the same level as firmware in the guest
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 32d1ca9abc..83cd1bfeec 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -27,6 +27,9 @@
#include "hw/pci/pci.h"
#include "hw/mem/nvdimm.h"
+GlobalProperty hw_compat_4_1[] = {};
+const size_t hw_compat_4_1_len = G_N_ELEMENTS(hw_compat_4_1);
+
GlobalProperty hw_compat_4_0[] = {
{ "VGA", "edid", "false" },
{ "secondary-vga", "edid", "false" },
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index fceab9afd5..70bfd4809b 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
+#include "audio/audio.h"
#include "net/net.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
@@ -353,6 +354,62 @@ const PropertyInfo qdev_prop_netdev = {
};
+/* --- audiodev --- */
+static void get_audiodev(Object *obj, Visitor *v, const char* name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
+ char *p = g_strdup(audio_get_id(card));
+
+ visit_type_str(v, name, &p, errp);
+ g_free(p);
+}
+
+static void set_audiodev(Object *obj, Visitor *v, const char* name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ QEMUSoundCard *card = qdev_get_prop_ptr(dev, prop);
+ AudioState *state;
+ Error *local_err = NULL;
+ int err = 0;
+ char *str;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_str(v, name, &str, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ state = audio_state_by_name(str);
+
+ if (!state) {
+ err = -ENOENT;
+ goto out;
+ }
+ card->state = state;
+
+out:
+ error_set_from_qdev_prop_error(errp, err, dev, prop, str);
+ g_free(str);
+}
+
+const PropertyInfo qdev_prop_audiodev = {
+ .name = "str",
+ .description = "ID of an audiodev to use as a backend",
+ /* release done on shutdown */
+ .get = get_audiodev,
+ .set = set_audiodev,
+};
+
void qdev_prop_set_drive(DeviceState *dev, const char *name,
BlockBackend *value, Error **errp)
{
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 3ab4bcb3ca..697c33606a 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -119,6 +119,9 @@ struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
/* Physical Address of PVH entry point read from kernel ELF NOTE */
static size_t pvh_start_addr;
+GlobalProperty pc_compat_4_1[] = {};
+const size_t pc_compat_4_1_len = G_N_ELEMENTS(pc_compat_4_1);
+
GlobalProperty pc_compat_4_0[] = {};
const size_t pc_compat_4_0_len = G_N_ELEMENTS(pc_compat_4_0);
@@ -1244,17 +1247,21 @@ static void load_linux(PCMachineState *pcms,
/* load initrd */
if (initrd_filename) {
+ GMappedFile *mapped_file;
gsize initrd_size;
gchar *initrd_data;
GError *gerr = NULL;
- if (!g_file_get_contents(initrd_filename, &initrd_data,
- &initrd_size, &gerr)) {
+ mapped_file = g_mapped_file_new(initrd_filename, false, &gerr);
+ if (!mapped_file) {
fprintf(stderr, "qemu: error reading initrd %s: %s\n",
initrd_filename, gerr->message);
exit(1);
}
+ pcms->initrd_mapped_file = mapped_file;
+ initrd_data = g_mapped_file_get_contents(mapped_file);
+ initrd_size = g_mapped_file_get_length(mapped_file);
initrd_max = pcms->below_4g_mem_size - pcmc->acpi_data_size - 1;
if (initrd_size >= initrd_max) {
fprintf(stderr, "qemu: initrd is too large, cannot support."
@@ -1381,6 +1388,7 @@ static void load_linux(PCMachineState *pcms,
/* load initrd */
if (initrd_filename) {
+ GMappedFile *mapped_file;
gsize initrd_size;
gchar *initrd_data;
GError *gerr = NULL;
@@ -1390,12 +1398,16 @@ static void load_linux(PCMachineState *pcms,
exit(1);
}
- if (!g_file_get_contents(initrd_filename, &initrd_data,
- &initrd_size, &gerr)) {
+ mapped_file = g_mapped_file_new(initrd_filename, false, &gerr);
+ if (!mapped_file) {
fprintf(stderr, "qemu: error reading initrd %s: %s\n",
initrd_filename, gerr->message);
exit(1);
}
+ pcms->initrd_mapped_file = mapped_file;
+
+ initrd_data = g_mapped_file_get_contents(mapped_file);
+ initrd_size = g_mapped_file_get_length(mapped_file);
if (initrd_size >= initrd_max) {
fprintf(stderr, "qemu: initrd is too large, cannot support."
"(max: %"PRIu32", need %"PRId64")\n",
@@ -2831,6 +2843,13 @@ static void pc_machine_reset(MachineState *machine)
}
}
+static void pc_machine_wakeup(MachineState *machine)
+{
+ cpu_synchronize_all_states();
+ pc_machine_reset(machine);
+ cpu_synchronize_all_post_reset();
+}
+
static CpuInstanceProperties
pc_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
{
@@ -2943,6 +2962,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_IDE;
mc->max_cpus = 255;
mc->reset = pc_machine_reset;
+ mc->wakeup = pc_machine_wakeup;
hc->pre_plug = pc_machine_device_pre_plug_cb;
hc->plug = pc_machine_device_plug_cb;
hc->unplug_request = pc_machine_device_unplug_request_cb;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 187d846af4..2362675149 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -432,7 +432,7 @@ static void pc_i440fx_machine_options(MachineClass *m)
machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
}
-static void pc_i440fx_4_1_machine_options(MachineClass *m)
+static void pc_i440fx_4_2_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_machine_options(m);
@@ -441,6 +441,18 @@ static void pc_i440fx_4_1_machine_options(MachineClass *m)
pcmc->default_cpu_version = 1;
}
+DEFINE_I440FX_MACHINE(v4_2, "pc-i440fx-4.2", NULL,
+ pc_i440fx_4_2_machine_options);
+
+static void pc_i440fx_4_1_machine_options(MachineClass *m)
+{
+ pc_i440fx_4_2_machine_options(m);
+ m->alias = NULL;
+ m->is_default = 0;
+ compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len);
+ compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len);
+}
+
DEFINE_I440FX_MACHINE(v4_1, "pc-i440fx-4.1", NULL,
pc_i440fx_4_1_machine_options);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index be3464f485..d4e8a1cb9f 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -364,7 +364,7 @@ static void pc_q35_machine_options(MachineClass *m)
m->max_cpus = 288;
}
-static void pc_q35_4_1_machine_options(MachineClass *m)
+static void pc_q35_4_2_machine_options(MachineClass *m)
{
PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_machine_options(m);
@@ -372,6 +372,17 @@ static void pc_q35_4_1_machine_options(MachineClass *m)
pcmc->default_cpu_version = 1;
}
+DEFINE_Q35_MACHINE(v4_2, "pc-q35-4.2", NULL,
+ pc_q35_4_2_machine_options);
+
+static void pc_q35_4_1_machine_options(MachineClass *m)
+{
+ pc_q35_4_2_machine_options(m);
+ m->alias = NULL;
+ compat_props_add(m->compat_props, hw_compat_4_1, hw_compat_4_1_len);
+ compat_props_add(m->compat_props, pc_compat_4_1, pc_compat_4_1_len);
+}
+
DEFINE_Q35_MACHINE(v4_1, "pc-q35-4.1", NULL,
pc_q35_4_1_machine_options);
diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c
index a8caf258fd..ed6e9d71bb 100644
--- a/hw/intc/pnv_xive.c
+++ b/hw/intc/pnv_xive.c
@@ -1595,6 +1595,15 @@ void pnv_xive_pic_print_info(PnvXive *xive, Monitor *mon)
}
xive_end_pic_print_info(&end, i, mon);
}
+
+ monitor_printf(mon, "XIVE[%x] END Escalation %08x .. %08x\n", blk, 0,
+ nr_ends - 1);
+ for (i = 0; i < nr_ends; i++) {
+ if (xive_router_get_end(xrtr, blk, i, &end)) {
+ break;
+ }
+ xive_end_eas_pic_print_info(&end, i, mon);
+ }
}
static void pnv_xive_reset(void *dev)
diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index aad981cb78..c1c97192a7 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -146,7 +146,6 @@ static void spapr_xive_end_pic_print_info(SpaprXive *xive, XiveEND *end,
priority, qindex, qentries, qaddr_base, qgen);
xive_end_queue_pic_print_info(end, 6, mon);
- monitor_printf(mon, "]");
}
void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon)
@@ -537,7 +536,10 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi)
return false;
}
- xive->eat[lisn].w |= cpu_to_be64(EAS_VALID);
+ /*
+ * Set default values when allocating an IRQ number
+ */
+ xive->eat[lisn].w |= cpu_to_be64(EAS_VALID | EAS_MASKED);
if (lsi) {
xive_source_irq_set_lsi(xsrc, lisn);
}
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 7a6e4b763a..b7417210d8 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -337,6 +337,17 @@ static void xive_tm_set_os_pending(XiveTCTX *tctx, hwaddr offset,
xive_tctx_notify(tctx, TM_QW1_OS);
}
+static uint64_t xive_tm_pull_os_ctx(XiveTCTX *tctx, hwaddr offset,
+ unsigned size)
+{
+ uint32_t qw1w2_prev = xive_tctx_word2(&tctx->regs[TM_QW1_OS]);
+ uint32_t qw1w2;
+
+ qw1w2 = xive_set_field32(TM_QW1W2_VO, qw1w2_prev, 0);
+ memcpy(&tctx->regs[TM_QW1_OS + TM_WORD2], &qw1w2, 4);
+ return qw1w2;
+}
+
/*
* Define a mapping of "special" operations depending on the TIMA page
* offset and the size of the operation.
@@ -363,6 +374,8 @@ static const XiveTmOp xive_tm_operations[] = {
/* MMIOs above 2K : special operations with side effects */
{ XIVE_TM_OS_PAGE, TM_SPC_ACK_OS_REG, 2, NULL, xive_tm_ack_os_reg },
{ XIVE_TM_OS_PAGE, TM_SPC_SET_OS_PENDING, 1, xive_tm_set_os_pending, NULL },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 4, NULL, xive_tm_pull_os_ctx },
+ { XIVE_TM_HV_PAGE, TM_SPC_PULL_OS_CTX, 8, NULL, xive_tm_pull_os_ctx },
{ XIVE_TM_HV_PAGE, TM_SPC_ACK_HV_REG, 2, NULL, xive_tm_ack_hv_reg },
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 4, NULL, xive_tm_pull_pool_ctx },
{ XIVE_TM_HV_PAGE, TM_SPC_PULL_POOL_CTX, 8, NULL, xive_tm_pull_pool_ctx },
@@ -406,7 +419,7 @@ void xive_tctx_tm_write(XiveTCTX *tctx, hwaddr offset, uint64_t value,
if (offset & 0x800) {
xto = xive_tm_find_op(offset, size, true);
if (!xto) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA"
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid write access at TIMA "
"@%"HWADDR_PRIx"\n", offset);
} else {
xto->write_handler(tctx, offset, value, size);
@@ -1145,6 +1158,7 @@ void xive_end_queue_pic_print_info(XiveEND *end, uint32_t width, Monitor *mon)
be32_to_cpu(qdata));
qindex = (qindex + 1) & (qentries - 1);
}
+ monitor_printf(mon, "]");
}
void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
@@ -1155,24 +1169,36 @@ void xive_end_pic_print_info(XiveEND *end, uint32_t end_idx, Monitor *mon)
uint32_t qsize = xive_get_field32(END_W0_QSIZE, end->w0);
uint32_t qentries = 1 << (qsize + 10);
- uint32_t nvt = xive_get_field32(END_W6_NVT_INDEX, end->w6);
+ uint32_t nvt_blk = xive_get_field32(END_W6_NVT_BLOCK, end->w6);
+ uint32_t nvt_idx = xive_get_field32(END_W6_NVT_INDEX, end->w6);
uint8_t priority = xive_get_field32(END_W7_F0_PRIORITY, end->w7);
+ uint8_t pq;
if (!xive_end_is_valid(end)) {
return;
}
- monitor_printf(mon, " %08x %c%c%c%c%c prio:%d nvt:%04x eq:@%08"PRIx64
- "% 6d/%5d ^%d", end_idx,
+ pq = xive_get_field32(END_W1_ESn, end->w1);
+
+ monitor_printf(mon, " %08x %c%c %c%c%c%c%c%c%c prio:%d nvt:%02x/%04x",
+ end_idx,
+ pq & XIVE_ESB_VAL_P ? 'P' : '-',
+ pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
xive_end_is_valid(end) ? 'v' : '-',
xive_end_is_enqueue(end) ? 'q' : '-',
xive_end_is_notify(end) ? 'n' : '-',
xive_end_is_backlog(end) ? 'b' : '-',
xive_end_is_escalate(end) ? 'e' : '-',
- priority, nvt, qaddr_base, qindex, qentries, qgen);
+ xive_end_is_uncond_escalation(end) ? 'u' : '-',
+ xive_end_is_silent_escalation(end) ? 's' : '-',
+ priority, nvt_blk, nvt_idx);
- xive_end_queue_pic_print_info(end, 6, mon);
- monitor_printf(mon, "]\n");
+ if (qaddr_base) {
+ monitor_printf(mon, " eq:@%08"PRIx64"% 6d/%5d ^%d",
+ qaddr_base, qindex, qentries, qgen);
+ xive_end_queue_pic_print_info(end, 6, mon);
+ }
+ monitor_printf(mon, "\n");
}
static void xive_end_enqueue(XiveEND *end, uint32_t data)
@@ -1200,6 +1226,29 @@ static void xive_end_enqueue(XiveEND *end, uint32_t data)
end->w1 = xive_set_field32(END_W1_PAGE_OFF, end->w1, qindex);
}
+void xive_end_eas_pic_print_info(XiveEND *end, uint32_t end_idx,
+ Monitor *mon)
+{
+ XiveEAS *eas = (XiveEAS *) &end->w4;
+ uint8_t pq;
+
+ if (!xive_end_is_escalate(end)) {
+ return;
+ }
+
+ pq = xive_get_field32(END_W1_ESe, end->w1);
+
+ monitor_printf(mon, " %08x %c%c %c%c end:%02x/%04x data:%08x\n",
+ end_idx,
+ pq & XIVE_ESB_VAL_P ? 'P' : '-',
+ pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
+ xive_eas_is_valid(eas) ? 'V' : ' ',
+ xive_eas_is_masked(eas) ? 'M' : ' ',
+ (uint8_t) xive_get_field64(EAS_END_BLOCK, eas->w),
+ (uint32_t) xive_get_field64(EAS_END_INDEX, eas->w),
+ (uint32_t) xive_get_field64(EAS_END_DATA, eas->w));
+}
+
/*
* XIVE Router (aka. Virtualization Controller or IVRE)
*/
@@ -1398,46 +1447,43 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format,
*
* The parameters represent what is sent on the PowerBus
*/
-static void xive_presenter_notify(XiveRouter *xrtr, uint8_t format,
+static bool xive_presenter_notify(XiveRouter *xrtr, uint8_t format,
uint8_t nvt_blk, uint32_t nvt_idx,
bool cam_ignore, uint8_t priority,
uint32_t logic_serv)
{
- XiveNVT nvt;
XiveTCTXMatch match = { .tctx = NULL, .ring = 0 };
bool found;
- /* NVT cache lookup */
- if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n",
- nvt_blk, nvt_idx);
- return;
- }
-
- if (!xive_nvt_is_valid(&nvt)) {
- qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n",
- nvt_blk, nvt_idx);
- return;
- }
-
found = xive_presenter_match(xrtr, format, nvt_blk, nvt_idx, cam_ignore,
priority, logic_serv, &match);
if (found) {
ipb_update(&match.tctx->regs[match.ring], priority);
xive_tctx_notify(match.tctx, match.ring);
- return;
}
- /* Record the IPB in the associated NVT structure */
- ipb_update((uint8_t *) &nvt.w4, priority);
- xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
+ return found;
+}
- /*
- * If no matching NVT is dispatched on a HW thread :
- * - update the NVT structure if backlog is activated
- * - escalate (ESe PQ bits and EAS in w4-5) if escalation is
- * activated
- */
+/*
+ * Notification using the END ESe/ESn bit (Event State Buffer for
+ * escalation and notification). Profide futher coalescing in the
+ * Router.
+ */
+static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk,
+ uint32_t end_idx, XiveEND *end,
+ uint32_t end_esmask)
+{
+ uint8_t pq = xive_get_field32(end_esmask, end->w1);
+ bool notify = xive_esb_trigger(&pq);
+
+ if (pq != xive_get_field32(end_esmask, end->w1)) {
+ end->w1 = xive_set_field32(end_esmask, end->w1, pq);
+ xive_router_write_end(xrtr, end_blk, end_idx, end, 1);
+ }
+
+ /* ESe/n[Q]=1 : end of notification */
+ return notify;
}
/*
@@ -1451,6 +1497,10 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
XiveEND end;
uint8_t priority;
uint8_t format;
+ uint8_t nvt_blk;
+ uint32_t nvt_idx;
+ XiveNVT nvt;
+ bool found;
/* END cache lookup */
if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) {
@@ -1472,6 +1522,13 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
}
/*
+ * When the END is silent, we skip the notification part.
+ */
+ if (xive_end_is_silent_escalation(&end)) {
+ goto do_escalation;
+ }
+
+ /*
* The W7 format depends on the F bit in W6. It defines the type
* of the notification :
*
@@ -1492,16 +1549,9 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
* even futher coalescing in the Router
*/
if (!xive_end_is_notify(&end)) {
- uint8_t pq = xive_get_field32(END_W1_ESn, end.w1);
- bool notify = xive_esb_trigger(&pq);
-
- if (pq != xive_get_field32(END_W1_ESn, end.w1)) {
- end.w1 = xive_set_field32(END_W1_ESn, end.w1, pq);
- xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
- }
-
/* ESn[Q]=1 : end of notification */
- if (!notify) {
+ if (!xive_router_end_es_notify(xrtr, end_blk, end_idx,
+ &end, END_W1_ESn)) {
return;
}
}
@@ -1509,14 +1559,82 @@ static void xive_router_end_notify(XiveRouter *xrtr, uint8_t end_blk,
/*
* Follows IVPE notification
*/
- xive_presenter_notify(xrtr, format,
- xive_get_field32(END_W6_NVT_BLOCK, end.w6),
- xive_get_field32(END_W6_NVT_INDEX, end.w6),
+ nvt_blk = xive_get_field32(END_W6_NVT_BLOCK, end.w6);
+ nvt_idx = xive_get_field32(END_W6_NVT_INDEX, end.w6);
+
+ /* NVT cache lookup */
+ if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n",
+ nvt_blk, nvt_idx);
+ return;
+ }
+
+ if (!xive_nvt_is_valid(&nvt)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n",
+ nvt_blk, nvt_idx);
+ return;
+ }
+
+ found = xive_presenter_notify(xrtr, format, nvt_blk, nvt_idx,
xive_get_field32(END_W7_F0_IGNORE, end.w7),
priority,
xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7));
/* TODO: Auto EOI. */
+
+ if (found) {
+ return;
+ }
+
+ /*
+ * If no matching NVT is dispatched on a HW thread :
+ * - specific VP: update the NVT structure if backlog is activated
+ * - logical server : forward request to IVPE (not supported)
+ */
+ if (xive_end_is_backlog(&end)) {
+ if (format == 1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "XIVE: END %x/%x invalid config: F1 & backlog\n",
+ end_blk, end_idx);
+ return;
+ }
+ /* Record the IPB in the associated NVT structure */
+ ipb_update((uint8_t *) &nvt.w4, priority);
+ xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
+
+ /*
+ * On HW, follows a "Broadcast Backlog" to IVPEs
+ */
+ }
+
+do_escalation:
+ /*
+ * If activated, escalate notification using the ESe PQ bits and
+ * the EAS in w4-5
+ */
+ if (!xive_end_is_escalate(&end)) {
+ return;
+ }
+
+ /*
+ * Check the END ESe (Event State Buffer for escalation) for even
+ * futher coalescing in the Router
+ */
+ if (!xive_end_is_uncond_escalation(&end)) {
+ /* ESe[Q]=1 : end of notification */
+ if (!xive_router_end_es_notify(xrtr, end_blk, end_idx,
+ &end, END_W1_ESe)) {
+ return;
+ }
+ }
+
+ /*
+ * The END trigger becomes an Escalation trigger
+ */
+ xive_router_end_notify(xrtr,
+ xive_get_field32(END_W4_ESC_END_BLOCK, end.w4),
+ xive_get_field32(END_W4_ESC_END_INDEX, end.w4),
+ xive_get_field32(END_W5_ESC_END_DATA, end.w5));
}
void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 9da93af905..2c4e1c8de0 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -5,6 +5,7 @@ obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o
obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o spapr_irq.o
+obj-$(CONFIG_PSERIES) += spapr_tpm_proxy.o
obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o
# IBM PowerNV
obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 7963feeab4..52a18eb7d7 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -1011,6 +1011,8 @@ static void timebase_save(PPCTimebase *tb)
* there is no need to update it from KVM here
*/
tb->guest_timebase = ticks + first_ppc_cpu->env.tb_env->tb_offset;
+
+ tb->runstate_paused = runstate_check(RUN_STATE_PAUSED);
}
static void timebase_load(PPCTimebase *tb)
@@ -1054,9 +1056,9 @@ void cpu_ppc_clock_vm_state_change(void *opaque, int running,
}
/*
- * When migrating, read the clock just before migration,
- * so that the guest clock counts during the events
- * between:
+ * When migrating a running guest, read the clock just
+ * before migration, so that the guest clock counts
+ * during the events between:
*
* * vm_stop()
* *
@@ -1071,7 +1073,10 @@ static int timebase_pre_save(void *opaque)
{
PPCTimebase *tb = opaque;
- timebase_save(tb);
+ /* guest_timebase won't be overridden in case of paused guest */
+ if (!tb->runstate_paused) {
+ timebase_save(tb);
+ }
return 0;
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index e09c67eb75..64fc2255cc 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -79,6 +79,7 @@
#include "qemu/cutils.h"
#include "hw/ppc/spapr_cpu_core.h"
#include "hw/mem/memory-device.h"
+#include "hw/ppc/spapr_tpm_proxy.h"
#include <libfdt.h>
@@ -1070,6 +1071,7 @@ static void spapr_dt_rtas(SpaprMachineState *spapr, void *fdt)
add_str(hypertas, "hcall-tce");
add_str(hypertas, "hcall-vio");
add_str(hypertas, "hcall-splpar");
+ add_str(hypertas, "hcall-join");
add_str(hypertas, "hcall-bulk");
add_str(hypertas, "hcall-set-mode");
add_str(hypertas, "hcall-sprg0");
@@ -1753,10 +1755,6 @@ static void spapr_machine_reset(MachineState *machine)
ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
}
- if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
- spapr_irq_msi_reset(spapr);
- }
-
/*
* This is fixing some of the default configuration of the XIVE
* devices. To be called after the reset of the machine devices.
@@ -3081,6 +3079,13 @@ static void spapr_machine_init(MachineState *machine)
qemu_register_boot_set(spapr_boot_set, spapr);
+ /*
+ * Nothing needs to be done to resume a suspended guest because
+ * suspending does not change the machine state, so no need for
+ * a ->wakeup method.
+ */
+ qemu_register_wakeup_support();
+
if (kvm_enabled()) {
/* to stop and start vmclock */
qemu_add_vm_change_state_handler(cpu_ppc_clock_vm_state_change,
@@ -4035,6 +4040,29 @@ static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
}
}
+static void spapr_tpm_proxy_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(dev);
+
+ if (spapr->tpm_proxy != NULL) {
+ error_setg(errp, "Only one TPM proxy can be specified for this machine");
+ return;
+ }
+
+ spapr->tpm_proxy = tpm_proxy;
+}
+
+static void spapr_tpm_proxy_unplug(HotplugHandler *hotplug_dev, DeviceState *dev)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(OBJECT(hotplug_dev));
+
+ object_property_set_bool(OBJECT(dev), false, "realized", NULL);
+ object_unparent(OBJECT(dev));
+ spapr->tpm_proxy = NULL;
+}
+
static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -4044,6 +4072,8 @@ static void spapr_machine_device_plug(HotplugHandler *hotplug_dev,
spapr_core_plug(hotplug_dev, dev, errp);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
spapr_phb_plug(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
+ spapr_tpm_proxy_plug(hotplug_dev, dev, errp);
}
}
@@ -4056,6 +4086,8 @@ static void spapr_machine_device_unplug(HotplugHandler *hotplug_dev,
spapr_core_unplug(hotplug_dev, dev);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
spapr_phb_unplug(hotplug_dev, dev);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
+ spapr_tpm_proxy_unplug(hotplug_dev, dev);
}
}
@@ -4090,6 +4122,8 @@ static void spapr_machine_device_unplug_request(HotplugHandler *hotplug_dev,
return;
}
spapr_phb_unplug_request(hotplug_dev, dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
+ spapr_tpm_proxy_unplug(hotplug_dev, dev);
}
}
@@ -4110,7 +4144,8 @@ static HotplugHandler *spapr_get_hotplug_handler(MachineState *machine,
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) ||
object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_CPU_CORE) ||
- object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE)) {
+ object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_PCI_HOST_BRIDGE) ||
+ object_dynamic_cast(OBJECT(dev), TYPE_SPAPR_TPM_PROXY)) {
return HOTPLUG_HANDLER(machine);
}
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
@@ -4306,6 +4341,53 @@ PowerPCCPU *spapr_find_cpu(int vcpu_id)
return NULL;
}
+static void spapr_cpu_exec_enter(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
+{
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ /* These are only called by TCG, KVM maintains dispatch state */
+
+ spapr_cpu->prod = false;
+ if (spapr_cpu->vpa_addr) {
+ CPUState *cs = CPU(cpu);
+ uint32_t dispatch;
+
+ dispatch = ldl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
+ dispatch++;
+ if ((dispatch & 1) != 0) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "VPA: incorrect dispatch counter value for "
+ "dispatched partition %u, correcting.\n", dispatch);
+ dispatch++;
+ }
+ stl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
+ }
+}
+
+static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu)
+{
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ if (spapr_cpu->vpa_addr) {
+ CPUState *cs = CPU(cpu);
+ uint32_t dispatch;
+
+ dispatch = ldl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
+ dispatch++;
+ if ((dispatch & 1) != 1) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "VPA: incorrect dispatch counter value for "
+ "preempted partition %u, correcting.\n", dispatch);
+ dispatch++;
+ }
+ stl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER, dispatch);
+ }
+}
+
static void spapr_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -4362,6 +4444,8 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
vhc->hpte_set_r = spapr_hpte_set_r;
vhc->get_pate = spapr_get_pate;
vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr;
+ vhc->cpu_exec_enter = spapr_cpu_exec_enter;
+ vhc->cpu_exec_exit = spapr_cpu_exec_exit;
xic->ics_get = spapr_ics_get;
xic->ics_resend = spapr_ics_resend;
xic->icp_get = spapr_icp_get;
@@ -4431,14 +4515,31 @@ static const TypeInfo spapr_machine_info = {
type_init(spapr_machine_register_##suffix)
/*
+ * pseries-4.2
+ */
+static void spapr_machine_4_2_class_options(MachineClass *mc)
+{
+ /* Defaults for the latest behaviour inherited from the base class */
+}
+
+DEFINE_SPAPR_MACHINE(4_2, "4.2", true);
+
+/*
* pseries-4.1
*/
static void spapr_machine_4_1_class_options(MachineClass *mc)
{
- /* Defaults for the latest behaviour inherited from the base class */
+ static GlobalProperty compat[] = {
+ /* Only allow 4kiB and 64kiB IOMMU pagesizes */
+ { TYPE_SPAPR_PCI_HOST_BRIDGE, "pgsz", "0x11000" },
+ };
+
+ spapr_machine_4_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
}
-DEFINE_SPAPR_MACHINE(4_1, "4.1", true);
+DEFINE_SPAPR_MACHINE(4_1, "4.1", false);
/*
* pseries-4.0
diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c
index 7830d66d77..481dfd2a27 100644
--- a/hw/ppc/spapr_caps.c
+++ b/hw/ppc/spapr_caps.c
@@ -195,10 +195,12 @@ static void cap_htm_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
}
if (tcg_enabled()) {
error_setg(errp,
- "No Transactional Memory support in TCG, try cap-htm=off");
+ "No Transactional Memory support in TCG,"
+ " try appending -machine cap-htm=off");
} else if (kvm_enabled() && !kvmppc_has_cap_htm()) {
error_setg(errp,
-"KVM implementation does not support Transactional Memory, try cap-htm=off"
+"KVM implementation does not support Transactional Memory,"
+ " try appending -machine cap-htm=off"
);
}
}
@@ -216,7 +218,8 @@ static void cap_vsx_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
* rid of anything that doesn't do VMX */
g_assert(env->insns_flags & PPC_ALTIVEC);
if (!(env->insns_flags2 & PPC2_VSX)) {
- error_setg(errp, "VSX support not available, try cap-vsx=off");
+ error_setg(errp, "VSX support not available,"
+ " try appending -machine cap-vsx=off");
}
}
@@ -230,7 +233,8 @@ static void cap_dfp_apply(SpaprMachineState *spapr, uint8_t val, Error **errp)
return;
}
if (!(env->insns_flags2 & PPC2_DFP)) {
- error_setg(errp, "DFP support not available, try cap-dfp=off");
+ error_setg(errp, "DFP support not available,"
+ " try appending -machine cap-dfp=off");
}
}
@@ -254,7 +258,8 @@ static void cap_safe_cache_apply(SpaprMachineState *spapr, uint8_t val,
cap_cfpc_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested safe cache capability level not supported by kvm, try cap-cfpc=%s",
+ "Requested safe cache capability level not supported by kvm,"
+ " try appending -machine cap-cfpc=%s",
cap_cfpc_possible.vals[kvm_val]);
}
@@ -282,7 +287,8 @@ static void cap_safe_bounds_check_apply(SpaprMachineState *spapr, uint8_t val,
cap_sbbc_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested safe bounds check capability level not supported by kvm, try cap-sbbc=%s",
+"Requested safe bounds check capability level not supported by kvm,"
+ " try appending -machine cap-sbbc=%s",
cap_sbbc_possible.vals[kvm_val]);
}
@@ -313,7 +319,8 @@ static void cap_safe_indirect_branch_apply(SpaprMachineState *spapr,
cap_ibs_possible.vals[val]);
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested safe indirect branch capability level not supported by kvm, try cap-ibs=%s",
+"Requested safe indirect branch capability level not supported by kvm,"
+ " try appending -machine cap-ibs=%s",
cap_ibs_possible.vals[kvm_val]);
}
@@ -402,11 +409,13 @@ static void cap_nested_kvm_hv_apply(SpaprMachineState *spapr,
if (tcg_enabled()) {
error_setg(errp,
- "No Nested KVM-HV support in tcg, try cap-nested-hv=off");
+ "No Nested KVM-HV support in tcg,"
+ " try appending -machine cap-nested-hv=off");
} else if (kvm_enabled()) {
if (!kvmppc_has_cap_nested_kvm_hv()) {
error_setg(errp,
-"KVM implementation does not support Nested KVM-HV, try cap-nested-hv=off");
+"KVM implementation does not support Nested KVM-HV,"
+ " try appending -machine cap-nested-hv=off");
} else if (kvmppc_set_cap_nested_kvm_hv(val) < 0) {
error_setg(errp,
"Error enabling cap-nested-hv with KVM, try cap-nested-hv=off");
@@ -436,10 +445,12 @@ static void cap_large_decr_apply(SpaprMachineState *spapr,
if (!kvm_nr_bits) {
error_setg(errp,
- "No large decrementer support, try cap-large-decr=off");
+ "No large decrementer support,"
+ " try appending -machine cap-large-decr=off");
} else if (pcc->lrg_decr_bits != kvm_nr_bits) {
error_setg(errp,
-"KVM large decrementer size (%d) differs to model (%d), try -cap-large-decr=off",
+"KVM large decrementer size (%d) differs to model (%d),"
+ " try appending -machine cap-large-decr=off",
kvm_nr_bits, pcc->lrg_decr_bits);
}
}
@@ -455,7 +466,8 @@ static void cap_large_decr_cpu_apply(SpaprMachineState *spapr,
if (kvm_enabled()) {
if (kvmppc_enable_cap_large_decr(cpu, val)) {
error_setg(errp,
- "No large decrementer support, try cap-large-decr=off");
+ "No large decrementer support,"
+ " try appending -machine cap-large-decr=off");
}
}
@@ -475,10 +487,12 @@ static void cap_ccf_assist_apply(SpaprMachineState *spapr, uint8_t val,
if (tcg_enabled() && val) {
/* TODO - for now only allow broken for TCG */
error_setg(errp,
-"Requested count cache flush assist capability level not supported by tcg, try cap-ccf-assist=off");
+"Requested count cache flush assist capability level not supported by tcg,"
+ " try appending -machine cap-ccf-assist=off");
} else if (kvm_enabled() && (val > kvm_val)) {
error_setg(errp,
-"Requested count cache flush assist capability level not supported by kvm, try cap-ccf-assist=off");
+"Requested count cache flush assist capability level not supported by kvm,"
+ " try appending -machine cap-ccf-assist=off");
}
}
@@ -779,7 +793,7 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp)
for (i = 0; i < ARRAY_SIZE(capability_table); i++) {
SpaprCapabilityInfo *cap = &capability_table[i];
- const char *name = g_strdup_printf("cap-%s", cap->name);
+ char *name = g_strdup_printf("cap-%s", cap->name);
char *desc;
object_class_property_add(klass, name, cap->type,
@@ -787,11 +801,13 @@ void spapr_caps_add_properties(SpaprMachineClass *smc, Error **errp)
NULL, cap, &local_err);
if (local_err) {
error_propagate(errp, local_err);
+ g_free(name);
return;
}
desc = g_strdup_printf("%s", cap->description);
object_class_property_set_description(klass, name, desc, &local_err);
+ g_free(name);
g_free(desc);
if (local_err) {
error_propagate(errp, local_err);
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 09255f4951..62f1a42592 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -227,7 +227,7 @@ static uint32_t drc_set_unusable(SpaprDrc *drc)
return RTAS_OUT_SUCCESS;
}
-static const char *spapr_drc_name(SpaprDrc *drc)
+static char *spapr_drc_name(SpaprDrc *drc)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
@@ -828,6 +828,7 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
Object *obj;
SpaprDrc *drc;
SpaprDrcClass *drck;
+ char *drc_name = NULL;
uint32_t drc_index, drc_power_domain;
if (!strstart(prop->type, "link<", NULL)) {
@@ -857,8 +858,10 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask)
g_array_append_val(drc_power_domains, drc_power_domain);
/* ibm,drc-names */
- drc_names = g_string_append(drc_names, spapr_drc_name(drc));
+ drc_name = spapr_drc_name(drc);
+ drc_names = g_string_append(drc_names, drc_name);
drc_names = g_string_insert_len(drc_names, -1, "\0", 1);
+ g_free(drc_name);
/* ibm,drc-types */
drc_types = g_string_append(drc_types, drck->typename);
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 225c60a9fc..e20a946b99 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -875,11 +875,6 @@ unmap_out:
#define FLAGS_DEREGISTER_DTL 0x0000c00000000000ULL
#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
-#define VPA_MIN_SIZE 640
-#define VPA_SIZE_OFFSET 0x4
-#define VPA_SHARED_PROC_OFFSET 0x9
-#define VPA_SHARED_PROC_VAL 0x2
-
static target_ulong register_vpa(PowerPCCPU *cpu, target_ulong vpa)
{
CPUState *cs = CPU(cpu);
@@ -1056,14 +1051,155 @@ static target_ulong h_cede(PowerPCCPU *cpu, SpaprMachineState *spapr,
{
CPUPPCState *env = &cpu->env;
CPUState *cs = CPU(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
env->msr |= (1ULL << MSR_EE);
hreg_compute_hflags(env);
+
+ if (spapr_cpu->prod) {
+ spapr_cpu->prod = false;
+ return H_SUCCESS;
+ }
+
if (!cpu_has_work(cs)) {
cs->halted = 1;
cs->exception_index = EXCP_HLT;
cs->exit_request = 1;
}
+
+ return H_SUCCESS;
+}
+
+/*
+ * Confer to self, aka join. Cede could use the same pattern as well, if
+ * EXCP_HLT can be changed to ECXP_HALTED.
+ */
+static target_ulong h_confer_self(PowerPCCPU *cpu)
+{
+ CPUState *cs = CPU(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ if (spapr_cpu->prod) {
+ spapr_cpu->prod = false;
+ return H_SUCCESS;
+ }
+ cs->halted = 1;
+ cs->exception_index = EXCP_HALTED;
+ cs->exit_request = 1;
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_join(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ CPUPPCState *env = &cpu->env;
+ CPUState *cs;
+ bool last_unjoined = true;
+
+ if (env->msr & (1ULL << MSR_EE)) {
+ return H_BAD_MODE;
+ }
+
+ /*
+ * Must not join the last CPU running. Interestingly, no such restriction
+ * for H_CONFER-to-self, but that is probably not intended to be used
+ * when H_JOIN is available.
+ */
+ CPU_FOREACH(cs) {
+ PowerPCCPU *c = POWERPC_CPU(cs);
+ CPUPPCState *e = &c->env;
+ if (c == cpu) {
+ continue;
+ }
+
+ /* Don't have a way to indicate joined, so use halted && MSR[EE]=0 */
+ if (!cs->halted || (e->msr & (1ULL << MSR_EE))) {
+ last_unjoined = false;
+ break;
+ }
+ }
+ if (last_unjoined) {
+ return H_CONTINUE;
+ }
+
+ return h_confer_self(cpu);
+}
+
+static target_ulong h_confer(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_long target = args[0];
+ uint32_t dispatch = args[1];
+ CPUState *cs = CPU(cpu);
+ SpaprCpuState *spapr_cpu;
+
+ /*
+ * -1 means confer to all other CPUs without dispatch counter check,
+ * otherwise it's a targeted confer.
+ */
+ if (target != -1) {
+ PowerPCCPU *target_cpu = spapr_find_cpu(target);
+ uint32_t target_dispatch;
+
+ if (!target_cpu) {
+ return H_PARAMETER;
+ }
+
+ /*
+ * target == self is a special case, we wait until prodded, without
+ * dispatch counter check.
+ */
+ if (cpu == target_cpu) {
+ return h_confer_self(cpu);
+ }
+
+ spapr_cpu = spapr_cpu_state(target_cpu);
+ if (!spapr_cpu->vpa_addr || ((dispatch & 1) == 0)) {
+ return H_SUCCESS;
+ }
+
+ target_dispatch = ldl_be_phys(cs->as,
+ spapr_cpu->vpa_addr + VPA_DISPATCH_COUNTER);
+ if (target_dispatch != dispatch) {
+ return H_SUCCESS;
+ }
+
+ /*
+ * The targeted confer does not do anything special beyond yielding
+ * the current vCPU, but even this should be better than nothing.
+ * At least for single-threaded tcg, it gives the target a chance to
+ * run before we run again. Multi-threaded tcg does not really do
+ * anything with EXCP_YIELD yet.
+ */
+ }
+
+ cs->exception_index = EXCP_YIELD;
+ cs->exit_request = 1;
+ cpu_loop_exit(cs);
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_prod(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_long target = args[0];
+ PowerPCCPU *tcpu;
+ CPUState *cs;
+ SpaprCpuState *spapr_cpu;
+
+ tcpu = spapr_find_cpu(target);
+ cs = CPU(tcpu);
+ if (!cs) {
+ return H_PARAMETER;
+ }
+
+ spapr_cpu = spapr_cpu_state(tcpu);
+ spapr_cpu->prod = true;
+ cs->halted = 0;
+ qemu_cpu_kick(cs);
+
return H_SUCCESS;
}
@@ -1613,6 +1749,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
ov5_updates = spapr_ovec_new();
spapr->cas_reboot = spapr_ovec_diff(ov5_updates,
ov5_cas_old, spapr->ov5_cas);
+ spapr_ovec_cleanup(ov5_cas_old);
/* Now that processing is finished, set the radix/hash bit for the
* guest if it requested a valid mode; otherwise terminate the boot. */
if (guest_radix) {
@@ -1630,6 +1767,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
}
spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest,
OV1_PPC_3_00);
+ spapr_ovec_cleanup(ov1_guest);
if (!spapr->cas_reboot) {
/* If spapr_machine_reset() did not set up a HPT but one is necessary
* (because the guest isn't going to use radix) then set it up here. */
@@ -1825,6 +1963,7 @@ static target_ulong h_update_dt(PowerPCCPU *cpu, SpaprMachineState *spapr,
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
+static spapr_hcall_fn svm_hypercall_table[(SVM_HCALL_MAX - SVM_HCALL_BASE) / 4 + 1];
void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
{
@@ -1834,6 +1973,11 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
assert((opcode & 0x3) == 0);
slot = &papr_hypercall_table[opcode / 4];
+ } else if (opcode >= SVM_HCALL_BASE && opcode <= SVM_HCALL_MAX) {
+ /* we only have SVM-related hcall numbers assigned in multiples of 4 */
+ assert((opcode & 0x3) == 0);
+
+ slot = &svm_hypercall_table[(opcode - SVM_HCALL_BASE) / 4];
} else {
assert((opcode >= KVMPPC_HCALL_BASE) && (opcode <= KVMPPC_HCALL_MAX));
@@ -1856,6 +2000,13 @@ target_ulong spapr_hypercall(PowerPCCPU *cpu, target_ulong opcode,
if (fn) {
return fn(cpu, spapr, opcode, args);
}
+ } else if ((opcode >= SVM_HCALL_BASE) &&
+ (opcode <= SVM_HCALL_MAX)) {
+ spapr_hcall_fn fn = svm_hypercall_table[(opcode - SVM_HCALL_BASE) / 4];
+
+ if (fn) {
+ return fn(cpu, spapr, opcode, args);
+ }
} else if ((opcode >= KVMPPC_HCALL_BASE) &&
(opcode <= KVMPPC_HCALL_MAX)) {
spapr_hcall_fn fn = kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
@@ -1888,6 +2039,12 @@ static void hypercall_register_types(void)
/* hcall-splpar */
spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
spapr_register_hypercall(H_CEDE, h_cede);
+ spapr_register_hypercall(H_CONFER, h_confer);
+ spapr_register_hypercall(H_PROD, h_prod);
+
+ /* hcall-join */
+ spapr_register_hypercall(H_JOIN, h_join);
+
spapr_register_hypercall(H_SIGNAL_SYS_RESET, h_signal_sys_reset);
/* processor register resource access h-calls */
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index ce85f8ac63..e87b3d50f7 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -136,7 +136,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
ret.addr_mask = ~page_mask;
ret.perm = spapr_tce_iommu_access_flags(tce);
}
- trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
+ trace_spapr_iommu_xlate(tcet->liobn, addr, ret.translated_addr, ret.perm,
ret.addr_mask);
return ret;
diff --git a/hw/ppc/spapr_irq.c b/hw/ppc/spapr_irq.c
index 2f87fe08f3..06fe2432ba 100644
--- a/hw/ppc/spapr_irq.c
+++ b/hw/ppc/spapr_irq.c
@@ -59,11 +59,6 @@ void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num)
bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num);
}
-void spapr_irq_msi_reset(SpaprMachineState *spapr)
-{
- bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr);
-}
-
static void spapr_irq_init_kvm(SpaprMachineState *spapr,
SpaprIrq *irq, Error **errp)
{
@@ -731,6 +726,8 @@ int spapr_irq_post_load(SpaprMachineState *spapr, int version_id)
void spapr_irq_reset(SpaprMachineState *spapr, Error **errp)
{
+ assert(!spapr->irq_map || bitmap_empty(spapr->irq_map, spapr->irq_map_nr));
+
if (spapr->irq->reset) {
spapr->irq->reset(spapr, errp);
}
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index bf31fd854c..deb0b0c80c 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -338,10 +338,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
return;
}
- if (!smc->legacy_irq_allocation) {
- spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
- }
- spapr_irq_free(spapr, msi->first_irq, msi->num);
if (msi_present(pdev)) {
spapr_msi_setmsg(pdev, 0, false, 0, 0);
}
@@ -411,10 +407,6 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, SpaprMachineState *spapr,
/* Release previous MSIs */
if (msi) {
- if (!smc->legacy_irq_allocation) {
- spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
- }
- spapr_irq_free(spapr, msi->first_irq, msi->num);
g_hash_table_remove(phb->msi, &config_addr);
}
@@ -1808,6 +1800,19 @@ static void spapr_phb_unrealize(DeviceState *dev, Error **errp)
memory_region_del_subregion(get_system_memory(), &sphb->mem32window);
}
+static void spapr_phb_destroy_msi(gpointer opaque)
+{
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+ SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
+ spapr_pci_msi *msi = opaque;
+
+ if (!smc->legacy_irq_allocation) {
+ spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
+ }
+ spapr_irq_free(spapr, msi->first_irq, msi->num);
+ g_free(msi);
+}
+
static void spapr_phb_realize(DeviceState *dev, Error **errp)
{
/* We don't use SPAPR_MACHINE() in order to exit gracefully if the user
@@ -2019,7 +2024,8 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
spapr_tce_get_iommu(tcet));
}
- sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free);
+ sphb->msi = g_hash_table_new_full(g_int_hash, g_int_equal, g_free,
+ spapr_phb_destroy_msi);
return;
unrealize:
@@ -2074,6 +2080,8 @@ static void spapr_phb_reset(DeviceState *qdev)
if (spapr_phb_eeh_available(SPAPR_PCI_HOST_BRIDGE(qdev))) {
spapr_phb_vfio_reset(qdev);
}
+
+ g_hash_table_remove_all(sphb->msi);
}
static Property spapr_phb_properties[] = {
@@ -2093,7 +2101,8 @@ static Property spapr_phb_properties[] = {
0x800000000000000ULL),
DEFINE_PROP_BOOL("ddw", SpaprPhbState, ddw_enabled, true),
DEFINE_PROP_UINT64("pgsz", SpaprPhbState, page_size_mask,
- (1ULL << 12) | (1ULL << 16)),
+ (1ULL << 12) | (1ULL << 16)
+ | (1ULL << 21) | (1ULL << 24)),
DEFINE_PROP_UINT32("numa_node", SpaprPhbState, numa_node, -1),
DEFINE_PROP_BOOL("pre-2.8-migration", SpaprPhbState,
pre_2_8_migration, false),
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index d3f9a69a51..526b489297 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -217,6 +217,36 @@ static void rtas_stop_self(PowerPCCPU *cpu, SpaprMachineState *spapr,
qemu_cpu_kick(cs);
}
+static void rtas_ibm_suspend_me(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ CPUState *cs;
+
+ if (nargs != 0 || nret != 1) {
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+ return;
+ }
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *c = POWERPC_CPU(cs);
+ CPUPPCState *e = &c->env;
+ if (c == cpu) {
+ continue;
+ }
+
+ /* See h_join */
+ if (!cs->halted || (e->msr & (1ULL << MSR_EE))) {
+ rtas_st(rets, 0, H_MULTI_THREADS_ACTIVE);
+ return;
+ }
+ }
+
+ qemu_system_suspend_request();
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
+}
+
static inline int sysparm_st(target_ulong addr, target_ulong len,
const void *val, uint16_t vallen)
{
@@ -484,6 +514,8 @@ static void core_rtas_register_types(void)
rtas_query_cpu_stopped_state);
spapr_rtas_register(RTAS_START_CPU, "start-cpu", rtas_start_cpu);
spapr_rtas_register(RTAS_STOP_SELF, "stop-self", rtas_stop_self);
+ spapr_rtas_register(RTAS_IBM_SUSPEND_ME, "ibm,suspend-me",
+ rtas_ibm_suspend_me);
spapr_rtas_register(RTAS_IBM_GET_SYSTEM_PARAMETER,
"ibm,get-system-parameter",
rtas_ibm_get_system_parameter);
diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c
new file mode 100644
index 0000000000..b835d25be6
--- /dev/null
+++ b/hw/ppc/spapr_tpm_proxy.c
@@ -0,0 +1,178 @@
+/*
+ * SPAPR TPM Proxy/Hypercall
+ *
+ * Copyright IBM Corp. 2019
+ *
+ * Authors:
+ * Michael Roth <mdroth@linux.vnet.ibm.com>
+ *
+ * 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-common.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "sysemu/reset.h"
+#include "cpu.h"
+#include "hw/ppc/spapr.h"
+#include "hw/qdev-properties.h"
+#include "trace.h"
+
+#define TPM_SPAPR_BUFSIZE 4096
+
+enum {
+ TPM_COMM_OP_EXECUTE = 1,
+ TPM_COMM_OP_CLOSE_SESSION = 2,
+};
+
+static void spapr_tpm_proxy_reset(void *opaque)
+{
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(opaque);
+
+ if (tpm_proxy->host_fd != -1) {
+ close(tpm_proxy->host_fd);
+ tpm_proxy->host_fd = -1;
+ }
+}
+
+static ssize_t tpm_execute(SpaprTpmProxy *tpm_proxy, target_ulong *args)
+{
+ uint64_t data_in = ppc64_phys_to_real(args[1]);
+ target_ulong data_in_size = args[2];
+ uint64_t data_out = ppc64_phys_to_real(args[3]);
+ target_ulong data_out_size = args[4];
+ uint8_t buf_in[TPM_SPAPR_BUFSIZE];
+ uint8_t buf_out[TPM_SPAPR_BUFSIZE];
+ ssize_t ret;
+
+ trace_spapr_tpm_execute(data_in, data_in_size, data_out, data_out_size);
+
+ if (data_in_size > TPM_SPAPR_BUFSIZE) {
+ error_report("invalid TPM input buffer size: " TARGET_FMT_lu,
+ data_in_size);
+ return H_P3;
+ }
+
+ if (data_out_size < TPM_SPAPR_BUFSIZE) {
+ error_report("invalid TPM output buffer size: " TARGET_FMT_lu,
+ data_out_size);
+ return H_P5;
+ }
+
+ if (tpm_proxy->host_fd == -1) {
+ tpm_proxy->host_fd = open(tpm_proxy->host_path, O_RDWR);
+ if (tpm_proxy->host_fd == -1) {
+ error_report("failed to open TPM device %s: %d",
+ tpm_proxy->host_path, errno);
+ return H_RESOURCE;
+ }
+ }
+
+ cpu_physical_memory_read(data_in, buf_in, data_in_size);
+
+ do {
+ ret = write(tpm_proxy->host_fd, buf_in, data_in_size);
+ if (ret > 0) {
+ data_in_size -= ret;
+ }
+ } while ((ret >= 0 && data_in_size > 0) || (ret == -1 && errno == EINTR));
+
+ if (ret == -1) {
+ error_report("failed to write to TPM device %s: %d",
+ tpm_proxy->host_path, errno);
+ return H_RESOURCE;
+ }
+
+ do {
+ ret = read(tpm_proxy->host_fd, buf_out, data_out_size);
+ } while (ret == 0 || (ret == -1 && errno == EINTR));
+
+ if (ret == -1) {
+ error_report("failed to read from TPM device %s: %d",
+ tpm_proxy->host_path, errno);
+ return H_RESOURCE;
+ }
+
+ cpu_physical_memory_write(data_out, buf_out, ret);
+ args[0] = ret;
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_tpm_comm(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong op = args[0];
+ SpaprTpmProxy *tpm_proxy = spapr->tpm_proxy;
+
+ if (!tpm_proxy) {
+ error_report("TPM proxy not available");
+ return H_FUNCTION;
+ }
+
+ trace_spapr_h_tpm_comm(tpm_proxy->host_path ?: "null", op);
+
+ switch (op) {
+ case TPM_COMM_OP_EXECUTE:
+ return tpm_execute(tpm_proxy, args);
+ case TPM_COMM_OP_CLOSE_SESSION:
+ spapr_tpm_proxy_reset(tpm_proxy);
+ return H_SUCCESS;
+ default:
+ return H_PARAMETER;
+ }
+}
+
+static void spapr_tpm_proxy_realize(DeviceState *d, Error **errp)
+{
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d);
+
+ if (tpm_proxy->host_path == NULL) {
+ error_setg(errp, "must specify 'host-path' option for device");
+ return;
+ }
+
+ tpm_proxy->host_fd = -1;
+ qemu_register_reset(spapr_tpm_proxy_reset, tpm_proxy);
+}
+
+static void spapr_tpm_proxy_unrealize(DeviceState *d, Error **errp)
+{
+ SpaprTpmProxy *tpm_proxy = SPAPR_TPM_PROXY(d);
+
+ qemu_unregister_reset(spapr_tpm_proxy_reset, tpm_proxy);
+}
+
+static Property spapr_tpm_proxy_properties[] = {
+ DEFINE_PROP_STRING("host-path", SpaprTpmProxy, host_path),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_tpm_proxy_class_init(ObjectClass *k, void *data)
+{
+ DeviceClass *dk = DEVICE_CLASS(k);
+
+ dk->realize = spapr_tpm_proxy_realize;
+ dk->unrealize = spapr_tpm_proxy_unrealize;
+ dk->user_creatable = true;
+ dk->props = spapr_tpm_proxy_properties;
+}
+
+static const TypeInfo spapr_tpm_proxy_info = {
+ .name = TYPE_SPAPR_TPM_PROXY,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SpaprTpmProxy),
+ .class_init = spapr_tpm_proxy_class_init,
+};
+
+static void spapr_tpm_proxy_register_types(void)
+{
+ type_register_static(&spapr_tpm_proxy_info);
+ spapr_register_hypercall(SVM_H_TPM_COMM, h_tpm_comm);
+}
+
+type_init(spapr_tpm_proxy_register_types)
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index f76448f532..96dad767a1 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -25,6 +25,10 @@ spapr_update_dt(unsigned cb) "New blob %u bytes"
spapr_update_dt_failed_size(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x"
spapr_update_dt_failed_check(unsigned cbold, unsigned cbnew, unsigned magic) "Old blob %u bytes, new blob %u bytes, magic 0x%x"
+# spapr_hcall_tpm.c
+spapr_h_tpm_comm(const char *device_path, uint64_t operation) "tpm_device_path=%s operation=0x%"PRIu64
+spapr_tpm_execute(uint64_t data_in, uint64_t data_in_sz, uint64_t data_out, uint64_t data_out_sz) "data_in=0x%"PRIx64", data_in_sz=%"PRIu64", data_out=0x%"PRIx64", data_out_sz=%"PRIu64
+
# spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
spapr_iommu_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=0x%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 434d933ec9..8bfb6684cb 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -663,14 +663,26 @@ bool css_migration_enabled(void)
} \
type_init(ccw_machine_register_##suffix)
+static void ccw_machine_4_2_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_4_2_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(4_2, "4.2", true);
+
static void ccw_machine_4_1_instance_options(MachineState *machine)
{
+ ccw_machine_4_2_instance_options(machine);
}
static void ccw_machine_4_1_class_options(MachineClass *mc)
{
+ ccw_machine_4_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
}
-DEFINE_CCW_MACHINE(4_1, "4.1", true);
+DEFINE_CCW_MACHINE(4_1, "4.1", false);
static void ccw_machine_4_0_instance_options(MachineState *machine)
{
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 222a286d44..ec53b14f7f 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -186,6 +186,9 @@ static const char *names[] = {
/* Flag set if this is a tagged command. */
#define LSI_TAG_VALID (1 << 16)
+/* Maximum instructions to process. */
+#define LSI_MAX_INSN 10000
+
typedef struct lsi_request {
SCSIRequest *req;
uint32_t tag;
@@ -1133,7 +1136,21 @@ static void lsi_execute_script(LSIState *s)
s->istat1 |= LSI_ISTAT1_SRUN;
again:
- insn_processed++;
+ if (++insn_processed > LSI_MAX_INSN) {
+ /* Some windows drivers make the device spin waiting for a memory
+ location to change. If we have been executed a lot of code then
+ assume this is the case and force an unexpected device disconnect.
+ This is apparently sufficient to beat the drivers into submission.
+ */
+ if (!(s->sien0 & LSI_SIST0_UDC)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lsi_scsi: inf. loop with UDC masked");
+ }
+ lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
+ lsi_disconnect(s);
+ trace_lsi_execute_script_stop();
+ return;
+ }
insn = read_dword(s, s->dsp);
if (!insn) {
/* If we receive an empty opcode increment the DSP by 4 bytes
@@ -1570,19 +1587,7 @@ again:
}
}
}
- if (insn_processed > 10000 && s->waiting == LSI_NOWAIT) {
- /* Some windows drivers make the device spin waiting for a memory
- location to change. If we have been executed a lot of code then
- assume this is the case and force an unexpected device disconnect.
- This is apparently sufficient to beat the drivers into submission.
- */
- if (!(s->sien0 & LSI_SIST0_UDC)) {
- qemu_log_mask(LOG_GUEST_ERROR,
- "lsi_scsi: inf. loop with UDC masked");
- }
- lsi_script_scsi_interrupt(s, LSI_SIST0_UDC, 0);
- lsi_disconnect(s);
- } else if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) {
+ if (s->istat1 & LSI_ISTAT1_SRUN && s->waiting == LSI_NOWAIT) {
if (s->dcntl & LSI_DCNTL_SSM) {
lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
} else {
@@ -1970,6 +1975,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
case 0x2f: /* DSP[24:31] */
s->dsp &= 0x00ffffff;
s->dsp |= val << 24;
+ /*
+ * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one
+ * instruction. Is this correct?
+ */
if ((s->dmode & LSI_DMODE_MAN) == 0
&& (s->istat1 & LSI_ISTAT1_SRUN) == 0)
lsi_execute_script(s);
@@ -1988,6 +1997,10 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
break;
case 0x3b: /* DCNTL */
s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
+ /*
+ * FIXME: if s->waiting != LSI_NOWAIT, this will only execute one
+ * instruction. Is this correct?
+ */
if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
lsi_execute_script(s);
break;
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 26618842c9..6cb378751b 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -96,7 +96,6 @@ typedef struct RTCState {
uint32_t irq_coalesced;
uint32_t period;
QEMUTimer *coalesced_timer;
- Notifier clock_reset_notifier;
LostTickPolicy lost_tick_policy;
Notifier suspend_notifier;
QLIST_ENTRY(RTCState) link;
@@ -889,20 +888,6 @@ static const VMStateDescription vmstate_rtc = {
}
};
-static void rtc_notify_clock_reset(Notifier *notifier, void *data)
-{
- RTCState *s = container_of(notifier, RTCState, clock_reset_notifier);
- int64_t now = *(int64_t *)data;
-
- rtc_set_date_from_host(ISA_DEVICE(s));
- periodic_timer_update(s, now, 0);
- check_update_timer(s);
-
- if (s->lost_tick_policy == LOST_TICK_POLICY_SLEW) {
- rtc_coalesced_timer_update(s);
- }
-}
-
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
BIOS will read it and start S3 resume at POST Entry */
static void rtc_notify_suspend(Notifier *notifier, void *data)
@@ -988,10 +973,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
s->update_timer = timer_new_ns(rtc_clock, rtc_update_timer, s);
check_update_timer(s);
- s->clock_reset_notifier.notify = rtc_notify_clock_reset;
- qemu_clock_register_reset_notifier(rtc_clock,
- &s->clock_reset_notifier);
-
s->suspend_notifier.notify = rtc_notify_suspend;
qemu_register_suspend_notifier(&s->suspend_notifier);
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index d3ca3bd1ab..ae42e5a2f1 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -667,6 +667,7 @@ static const VMStateDescription vmstate_usb_audio = {
};
static Property usb_audio_properties[] = {
+ DEFINE_AUDIO_PROPERTIES(USBAudioState, card),
DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
32 * USBAUDIO_PACKET_SIZE),