[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC][PATCH v1 3/4] qtest: add basic rtc test module
From: |
Michael Roth |
Subject: |
[Qemu-devel] [RFC][PATCH v1 3/4] qtest: add basic rtc test module |
Date: |
Fri, 4 Feb 2011 07:49:51 -0600 |
This test module initializes a basic system with an ISA bus, a PIC
(currently not used in the test), and an RTC. Currently only drift
testing is performed at various frequencies. This is currently more
of a proof of concept than a rigorous test, and will be improved
over time.
Signed-off-by: Michael Roth <address@hidden>
---
qtest/qtest-rtc.c | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 170 insertions(+), 0 deletions(-)
create mode 100644 qtest/qtest-rtc.c
diff --git a/qtest/qtest-rtc.c b/qtest/qtest-rtc.c
new file mode 100644
index 0000000..a494fd5
--- /dev/null
+++ b/qtest/qtest-rtc.c
@@ -0,0 +1,170 @@
+#include <stdio.h>
+#include "qtest/qtest.h"
+#include "sysemu.h"
+#include "hw/pc.h"
+#include "hw/isa.h"
+#include "hw/irq.h"
+#include "hw/mc146818rtc.h"
+
+#define RAM_SIZE_B 128 * 1024 * 1024
+#define DEBUG_QT
+#ifdef DEBUG_QT
+#define TRACE(msg, ...) do { \
+ fprintf(stderr, "%s:%s():L%d: " msg "\n", \
+ __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+} while(0)
+#else
+#define TRACE(msg, ...) \
+ do { } while (0)
+#endif
+
+static enum {
+ HANDLER_MODE_NORMAL = 0,
+ HANDLER_MODE_DRIFT_TEST_INIT,
+ HANDLER_MODE_DRIFT_TEST_STARTED,
+ HANDLER_MODE_ONESHOT_TEST_INIT,
+ HANDLER_MODE_ONESHOT_TEST_STARTED,
+} handler_mode = HANDLER_MODE_NORMAL;
+
+static uint32_t irq_count, irq_count_max;
+static struct timeval ts1, ts2;
+
+static void cmos_write(int addr, unsigned int val)
+{
+ cpu_outb(0x70, addr - 0x70);
+ cpu_outb(0x71, val);
+}
+
+static unsigned int cmos_read(int addr)
+{
+ cpu_outb(0x70, addr - 0x70);
+ return cpu_inb(0x71);
+}
+
+static void rtc_irq_handler(void *opaque, int n, int level)
+{
+ int rtc_reg_c = 0;
+ if (level) {
+ switch (handler_mode) {
+ case HANDLER_MODE_DRIFT_TEST_INIT:
+ irq_count = 0;
+ gettimeofday(&ts1, NULL);
+ handler_mode = HANDLER_MODE_DRIFT_TEST_STARTED;
+ break;
+ case HANDLER_MODE_DRIFT_TEST_STARTED:
+ if (++irq_count == irq_count_max) {
+ gettimeofday(&ts2, NULL);
+ handler_mode = HANDLER_MODE_NORMAL;
+ }
+ break;
+ default:
+ break;
+ }
+ /* reset irq line */
+ rtc_reg_c = cmos_read(0x7C);
+ }
+ //TRACE("irq: %d, level: %d, 0x7c: %d", n, level, rtc_reg_c);
+}
+
+#define DRIFT_RATIO_MAX .05
+
+static void test_drift(void)
+{
+ uint32_t hz, start, stop, duration_ms, exp_duration_ms;
+ float drift_ratio;
+
+ handler_mode = HANDLER_MODE_NORMAL;
+ /* enable timer interrupts */
+ cmos_write(0x7B, cmos_read(0x7B) | 0x40);
+
+ /* set frequency to 2hz (32*1024khz >> (div - 1)), div is bottom 4 bits */
+ cmos_write(0x7A, (cmos_read(0x7A) & 0xF0) | 0x0F);
+ hz = 2;
+ irq_count_max = hz*5;
+ handler_mode = HANDLER_MODE_DRIFT_TEST_INIT;
+ while (handler_mode != HANDLER_MODE_NORMAL) {
+ sleep(1);
+ }
+ start = ts1.tv_sec * 1000 * 1000 + ts1.tv_usec;
+ stop = ts2.tv_sec * 1000 * 1000 + ts2.tv_usec;
+ duration_ms = (stop - start) / 1000;
+ exp_duration_ms = irq_count_max / 2 * 1000;
+ drift_ratio = fabs(1.0 - (float)duration_ms/exp_duration_ms);
+ TRACE("hz: %u, duration_ms: %u, exp_duration: %u, drift ratio: %f",
+ hz, duration_ms, exp_duration_ms, drift_ratio);
+ assert(drift_ratio <= .05);
+
+ /* set frequency to 1024hz */
+ cmos_write(0x7A, (cmos_read(0x7A) & 0xF0) | 0x06);
+ hz = 1024;
+ irq_count_max = hz * 5;
+ handler_mode = HANDLER_MODE_DRIFT_TEST_INIT;
+ while (handler_mode != HANDLER_MODE_NORMAL) {
+ sleep(1);
+ }
+ start = ts1.tv_sec * 1000 * 1000 + ts1.tv_usec;
+ stop = ts2.tv_sec * 1000 * 1000 + ts2.tv_usec;
+ duration_ms = (stop - start) / 1000;
+ exp_duration_ms = irq_count_max / hz * 1000;
+ drift_ratio = fabs(1.0 - (float)duration_ms/exp_duration_ms);
+ TRACE("hz: %u, duration_ms: %u, exp_duration: %u, drift ratio: %f",
+ hz, duration_ms, exp_duration_ms, drift_ratio);
+ assert(drift_ratio <= .05);
+}
+
+static void qtest_rtc_init(void)
+{
+ ram_addr_t below_4g_mem_size, above_4g_mem_size;
+ IsaIrqState *isa_irq_state;
+ ISADevice *rtc_state;
+ qemu_irq *rtc_irq, *cpu_irq, *isa_irq, *i8259;
+
+ /* allocate ram */
+ pc_memory_init(RAM_SIZE_B, NULL, NULL, NULL,
+ &below_4g_mem_size, &above_4g_mem_size);
+ /*
+ pc_cmos_init(below_4g_mem_size, above_4g_mem_size, NULL,
+ NULL, NULL, NULL, NULL);
+ */
+
+ /* set up the isa bus. we'll use an intercept handler for the rtc
+ * interrupts, but set the PIC up in case we want to use it later
+ */
+ cpu_irq = pc_allocate_cpu_irq();
+ i8259 = i8259_init(cpu_irq[0]);
+ isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+ isa_irq_state->i8259 = i8259;
+ isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+ isa_bus_new(NULL);
+ isa_bus_irqs(isa_irq);
+
+ /* set up rtc */
+ rtc_irq = qemu_allocate_irqs(rtc_irq_handler, NULL, 1);
+ rtc_state = rtc_init(2000, rtc_irq[0]);
+}
+
+static void qtest_rtc_cleanup(void)
+{
+}
+
+static void *qtest_rtc_start(void *thread_args)
+{
+ test_drift();
+ //g_assert(false);
+ qemu_system_shutdown_request();
+ return NULL;
+}
+
+static QTestModule qtest_module = {
+ .name = "rtc",
+ .init = qtest_rtc_init,
+ .cleanup = qtest_rtc_cleanup,
+ .start = qtest_rtc_start,
+};
+
+static void qtest_module_register(void)
+{
+ qtest_register(&qtest_module);
+}
+
+qtest_init_registry(qtest_module_register)
--
1.7.0.4