@@ -2616,11 +2616,28 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
qemu_set_irq(cpu->gt_timer_outputs[timeridx], irqstate);
if (istatus) {
- /* Next transition is when count rolls back over to zero */
- nexttick = UINT64_MAX;
+ /*
+ * Next transition is when (count - offset) rolls back over to 0.
+ * If offset > count then this is when count == offset;
+ * if offset <= count then this is when count == offset + 2^64
+ * For the latter case we set nexttick to an "as far in future
+ * as possible" value and let the code below handle it.
+ */
+ if (offset > count) {
+ nexttick = offset;
+ } else {
+ nexttick = UINT64_MAX;
+ }
} else {
- /* Next transition is when we hit cval */
- nexttick = gt->cval + offset;
+ /*
+ * Next transition is when (count - offset) == cval, i.e.
+ * when count == (cval + offset).
+ * If that would overflow, then again we set up the next interrupt
+ * for "as far in the future as possible" for the code below.
+ */
+ if (uadd64_overflow(gt->cval, offset, &nexttick)) {
+ nexttick = UINT64_MAX;
+ }
}
/*
* Note that the desired next expiry time might be beyond the
@@ -45,7 +45,8 @@ TESTS+=memory-sve
# Running
QEMU_BASE_MACHINE=-M virt -cpu max -display none
-QEMU_OPTS+=$(QEMU_BASE_MACHINE) -semihosting-config enable=on,target=native,chardev=output -kernel
+QEMU_BASE_ARGS=-semihosting-config enable=on,target=native,chardev=output
+QEMU_OPTS+=$(QEMU_BASE_MACHINE) $(QEMU_BASE_ARGS) -kernel
# console test is manual only
QEMU_SEMIHOST=-chardev stdio,mux=on,id=stdio0 -semihosting-config enable=on,chardev=stdio0 -mon chardev=stdio0,mode=readline
@@ -55,6 +56,10 @@ run-semiconsole: semiconsole
run-plugin-semiconsole-with-%: semiconsole
$(call skip-test, $<, "MANUAL ONLY")
+# vtimer test needs EL2
+QEMU_EL2_MACHINE=-machine virt,virtualization=on,gic-version=2 -cpu cortex-a57 -smp 4
+run-vtimer: QEMU_OPTS=$(QEMU_EL2_MACHINE) $(QEMU_BASE_ARGS) -kernel
+
# Simple Record/Replay Test
.PHONY: memory-record
run-memory-record: memory-record memory
new file mode 100644
@@ -0,0 +1,48 @@
+/*
+ * Simple Virtual Timer Test
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <inttypes.h>
+#include <minilib.h>
+
+/* grabbed from Linux */
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+#define read_sysreg(r) ({ \
+ uint64_t __val; \
+ asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
+ __val; \
+})
+
+#define write_sysreg(r, v) do { \
+ uint64_t __val = (uint64_t)(v); \
+ asm volatile("msr " __stringify(r) ", %x0" \
+ : : "rZ" (__val)); \
+} while (0)
+
+int main(void)
+{
+ int i;
+
+ ml_printf("VTimer Test\n");
+
+ write_sysreg(cntvoff_el2, 1);
+ write_sysreg(cntv_cval_el0, -1);
+ write_sysreg(cntv_ctl_el0, 1);
+
+ ml_printf("cntvoff_el2=%lx\n", read_sysreg(cntvoff_el2));
+ ml_printf("cntv_cval_el0=%lx\n", read_sysreg(cntv_cval_el0));
+ ml_printf("cntv_ctl_el0=%lx\n", read_sysreg(cntv_ctl_el0));
+
+ /* Now read cval a few times */
+ for (i = 0; i < 10; i++) {
+ ml_printf("%d: cntv_cval_el0=%lx\n", i, read_sysreg(cntv_cval_el0));
+ }
+
+ return 0;
+}