From: Matthew Ogilvie <mmogilvi_qemu@miniinfo.net>
To: qemu-devel@nongnu.org
Cc: "Maciej W. Rozycki" <macro@linux-mips.org>,
Jan Kiszka <jan.kiszka@web.de>,
Matthew Ogilvie <mmogilvi_qemu@miniinfo.net>,
Gleb Natapov <gleb@redhat.com>
Subject: [Qemu-devel] [PATCH v8 05/10] fix i8254 output logic to match the spec
Date: Sun, 16 Dec 2012 16:56:24 -0700 [thread overview]
Message-ID: <1355702189-6994-6-git-send-email-mmogilvi_qemu@miniinfo.net> (raw)
In-Reply-To: <1355702189-6994-1-git-send-email-mmogilvi_qemu@miniinfo.net>
This patch fixes i8254 output line (IRQ0) logic to match the spec.
Basically, IRQ0 line should normally be high, and only occasionally
go low to cause an edge. This is an important prerequisite to
fixing the i8259 interrupt controller to cancel an unhandled interrupt
when the IRQ line goes low.
More details:
* Fix high-vs-low counting logic to match the timing diagrams
and descriptions in Intel's documentation.
* Improve reading back the count in mode 3.
* Handle GATE input properly with respect to the OUT line, and add
a FIXME comment for "GATE-paused" counting and reading
back the counter. GATE is hard wired high for channel 0 (IRQ0), but
it can be software controlled on channel 2 (PC speaker).
See http://bochs.sourceforge.net/techspec/intel-82c54-timer.pdf.gz
or search the net for 23124406.pdf.
Risks:
There is a risk that migrating between versions of qemu
with and without this patch will lose or gain a single timer
interrupt during the migration process. The only case where
this is likely to be serious is probably losing a single-shot (mode 4)
interrupt, but if my understanding of how things work is good, then
that should only be possible if a whole slew of conditions are
all met:
1. The guest is configured to run in a "tickless" mode (like
modern Linux).
2. The guest is for some reason still using the i8254 rather
than something more modern like an HPET. (The combination
of 1 and 2 should be rare.)
3. The migration is going from a fixed version back to the
old version. (Not sure how common this is, but it should
be rarer than migrating from old to new.)
4. There are not going to be any "timely" events/interrupts
(keyboard, network, process sleeps, etc) that cause the guest
to reset the PIT mode 4 one-shot counter "soon enough".
This combination should be rare enough that more complicated
solutions are not worth the effort.
Signed-off-by: Matthew Ogilvie <mmogilvi_qemu@miniinfo.net>
---
hw/i8254.c | 24 ++++++++++++++++++++++--
hw/i8254_common.c | 18 ++++++------------
2 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/hw/i8254.c b/hw/i8254.c
index bea5f92..edb5b7a 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -39,6 +39,15 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
static int pit_get_count(PITChannelState *s)
{
+ /* FIXME: Add some way to represent a paused timer and return
+ * the paused-at counter value, to better model:
+ * - gate-triggered modes (1 and 5),
+ * - gate-pausable modes,
+ * - [maybe] the "wait until next CLK pulse to load counter" logic,
+ * - [maybe/not clear] half-loaded counter logic for mode 0, and
+ * the "null count" status bit,
+ * - etc.
+ */
uint64_t d;
int counter;
@@ -52,8 +61,7 @@ static int pit_get_count(PITChannelState *s)
counter = (s->count - d) & 0xffff;
break;
case 3:
- /* XXX: may be incorrect for odd counts */
- counter = s->count - ((2 * d) % s->count);
+ counter = (s->count - ((2 * d) % s->count)) & 0xfffe;
break;
default:
counter = s->count - (d % s->count);
@@ -98,6 +106,18 @@ static inline void pit_load_count(PITChannelState *s, int val)
if (val == 0)
val = 0x10000;
s->count_load_time = qemu_get_clock_ns(vm_clock);
+
+ /* In gate-triggered one-shot modes, indirectly model some pit_get_out()
+ * cases by setting the load time way back until gate-triggered.
+ * (Generally only affects reading status from channel 2 speaker,
+ * due to hard-wired gates on other channels.)
+ *
+ * FIXME: This might be redesigned if a paused timer state is added
+ * for pic_get_count().
+ */
+ if (s->mode == 1 || s->mode == 5)
+ s->count_load_time -= muldiv64(val+2, get_ticks_per_sec(), PIT_FREQ);
+
s->count = val;
pit_irq_timer_update(s, s->count_load_time);
}
diff --git a/hw/i8254_common.c b/hw/i8254_common.c
index a03d7cd..dc13c99 100644
--- a/hw/i8254_common.c
+++ b/hw/i8254_common.c
@@ -50,24 +50,18 @@ int pit_get_out(PITChannelState *s, int64_t current_time)
switch (s->mode) {
default:
case 0:
- out = (d >= s->count);
- break;
case 1:
- out = (d < s->count);
+ out = (d >= s->count);
break;
case 2:
- if ((d % s->count) == 0 && d != 0) {
- out = 1;
- } else {
- out = 0;
- }
+ out = (d % s->count) != (s->count - 1) || s->gate == 0;
break;
case 3:
- out = (d % s->count) < ((s->count + 1) >> 1);
+ out = (d % s->count) < ((s->count + 1) >> 1) || s->gate == 0;
break;
case 4:
case 5:
- out = (d == s->count);
+ out = (d != s->count);
break;
}
return out;
@@ -93,10 +87,10 @@ int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time)
break;
case 2:
base = (d / s->count) * s->count;
- if ((d - base) == 0 && d != 0) {
+ if ((d - base) == s->count-1) {
next_time = base + s->count;
} else {
- next_time = base + s->count + 1;
+ next_time = base + s->count - 1;
}
break;
case 3:
--
1.7.10.2.484.gcd07cc5
next prev parent reply other threads:[~2012-12-16 23:56 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-12-16 23:56 [Qemu-devel] [PATCH v8 00/10] i8254, i8259 and running Microport UNIX (ca 1987) Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 01/10] fix some debug printf format strings Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 02/10] vl: fix -hdachs/-hda argument order parsing issues Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 03/10] qemu-options.hx: mention retrace= VGA option Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 04/10] vga: add some optional CGA compatibility hacks Matthew Ogilvie
2012-12-16 23:56 ` Matthew Ogilvie [this message]
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 06/10] i8259: fix so that dropping IRQ level always clears the interrupt request Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 07/10] i8259: refactor pic_set_irq level logic Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 08/10] qtest: fix qemu_irq_intercept_out() Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 09/10] qtest: add set_irq_{in, out} infrastructure for testing interrupt controllers Matthew Ogilvie
2012-12-16 23:56 ` [Qemu-devel] [PATCH v8 10/10] add test/pic-test.c Matthew Ogilvie
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1355702189-6994-6-git-send-email-mmogilvi_qemu@miniinfo.net \
--to=mmogilvi_qemu@miniinfo.net \
--cc=gleb@redhat.com \
--cc=jan.kiszka@web.de \
--cc=macro@linux-mips.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).