From: "Alex Bennée" <alex.bennee@linaro.org>
To: Andrew Jones <drjones@redhat.com>
Cc: pbonzini@redhat.com, marc.zyngier@arm.com,
christoffer.dall@linaro.org, kvm@vger.kernel.org
Subject: Re: [kvm-unit-tests PATCH v2 3/3] arm/debugtest: test access to the debug registers for guest
Date: Mon, 22 May 2017 19:41:13 +0100 [thread overview]
Message-ID: <87o9uk3fau.fsf@linaro.org> (raw)
In-Reply-To: <20170522172233.rwn73z6m3wmkbfcd@kamzik.brq.redhat.com>
Andrew Jones <drjones@redhat.com> writes:
> On Thu, May 18, 2017 at 05:02:08PM +0100, Alex Bennée wrote:
>> Currently this is a fairly simple test that reads the debug register
>> state and attempts to write/read-back the watchpoint and breakpoint
>> registers.
>>
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>> arm/Makefile.common | 1 +
>> arm/debugtest.c | 671 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 672 insertions(+)
>> create mode 100644 arm/debugtest.c
>>
>> diff --git a/arm/Makefile.common b/arm/Makefile.common
>> index 74c7394..1d7dec1 100644
>> --- a/arm/Makefile.common
>> +++ b/arm/Makefile.common
>> @@ -15,6 +15,7 @@ tests-common += $(TEST_DIR)/pci-test.flat
>> tests-common += $(TEST_DIR)/pmu.flat
>> tests-common += $(TEST_DIR)/gic.flat
>> tests-common += $(TEST_DIR)/psci.flat
>> +tests-common += $(TEST_DIR)/debugtest.flat
>>
>> tests-all = $(tests-common) $(tests)
>> all: $(tests-all)
>> diff --git a/arm/debugtest.c b/arm/debugtest.c
>> new file mode 100644
>> index 0000000..4400bf3
>> --- /dev/null
>> +++ b/arm/debugtest.c
>> @@ -0,0 +1,671 @@
>> +/*
>> + * Test guest access to debug registers.
>> + *
>> + * Copyright (C) 2015, Linaro Ltd, Alex Bennée <alex.bennee@linaro.org>
>> + *
>> + * This work is licensed under the terms of the GNU LGPL, version 2.
>> + */
>> +
>> +#include <libcflat.h>
>> +#include <asm/psci.h>
>> +#include <asm/smp.h>
>> +#include <asm/cpumask.h>
>> +#include <asm/barrier.h>
>> +#include "asm/sysreg.h"
>> +#include "asm/processor.h"
>
> nit: mixing <> and ""
>
>> +
>> +
>> +
>
> nit: excessive blank lines
>
>> +#if defined(__arm__)
>> +
>> +#define ID_DFR0 __ACCESS_CP15(c0, 0, c1, 2)
>> +
>> +/* __ACCESS_CP14(CRn, Op1, CRm, Op2) */
>> +#define DBGDIDR __ACCESS_CP14(c0, 0, c0, 0)
>> +#define DBGDSCR __ACCESS_CP14(c0, 0, c2, 2)
>> +
>> +#define DBGBCR0 __ACCESS_CP14(c0, 0, c0, 5)
>> +#define DBGBCR1 __ACCESS_CP14(c0, 0, c1, 5)
>> +#define DBGBCR2 __ACCESS_CP14(c0, 0, c2, 5)
>> +#define DBGBCR3 __ACCESS_CP14(c0, 0, c3, 5)
>> +#define DBGBCR4 __ACCESS_CP14(c0, 0, c4, 5)
>> +#define DBGBCR5 __ACCESS_CP14(c0, 0, c5, 5)
>> +#define DBGBCR6 __ACCESS_CP14(c0, 0, c6, 5)
>> +#define DBGBCR7 __ACCESS_CP14(c0, 0, c7, 5)
>> +#define DBGBCR8 __ACCESS_CP14(c0, 0, c8, 5)
>> +#define DBGBCR9 __ACCESS_CP14(c0, 0, c9, 5)
>> +#define DBGBCR10 __ACCESS_CP14(c0, 0, c10, 5)
>> +#define DBGBCR11 __ACCESS_CP14(c0, 0, c11, 5)
>> +#define DBGBCR12 __ACCESS_CP14(c0, 0, c12, 5)
>> +#define DBGBCR13 __ACCESS_CP14(c0, 0, c13, 5)
>> +#define DBGBCR14 __ACCESS_CP14(c0, 0, c14, 5)
>> +#define DBGBCR15 __ACCESS_CP14(c0, 0, c15, 5)
>> +#define DBGBVR0 __ACCESS_CP14(c0, 0, c0, 4)
>> +#define DBGBVR1 __ACCESS_CP14(c0, 0, c1, 4)
>> +#define DBGBVR2 __ACCESS_CP14(c0, 0, c2, 4)
>> +#define DBGBVR3 __ACCESS_CP14(c0, 0, c3, 4)
>> +#define DBGBVR4 __ACCESS_CP14(c0, 0, c4, 4)
>> +#define DBGBVR5 __ACCESS_CP14(c0, 0, c5, 4)
>> +#define DBGBVR6 __ACCESS_CP14(c0, 0, c6, 4)
>> +#define DBGBVR7 __ACCESS_CP14(c0, 0, c7, 4)
>> +#define DBGBVR8 __ACCESS_CP14(c0, 0, c8, 4)
>> +#define DBGBVR9 __ACCESS_CP14(c0, 0, c9, 4)
>> +#define DBGBVR10 __ACCESS_CP14(c0, 0, c10, 4)
>> +#define DBGBVR11 __ACCESS_CP14(c0, 0, c11, 4)
>> +#define DBGBVR12 __ACCESS_CP14(c0, 0, c12, 4)
>> +#define DBGBVR13 __ACCESS_CP14(c0, 0, c13, 4)
>> +#define DBGBVR14 __ACCESS_CP14(c0, 0, c14, 4)
>> +#define DBGBVR15 __ACCESS_CP14(c0, 0, c15, 4)
>> +#define DBGWCR0 __ACCESS_CP14(c0, 0, c0, 7)
>> +#define DBGWCR1 __ACCESS_CP14(c0, 0, c1, 7)
>> +#define DBGWCR2 __ACCESS_CP14(c0, 0, c2, 7)
>> +#define DBGWCR3 __ACCESS_CP14(c0, 0, c3, 7)
>> +#define DBGWCR4 __ACCESS_CP14(c0, 0, c4, 7)
>> +#define DBGWCR5 __ACCESS_CP14(c0, 0, c5, 7)
>> +#define DBGWCR6 __ACCESS_CP14(c0, 0, c6, 7)
>> +#define DBGWCR7 __ACCESS_CP14(c0, 0, c7, 7)
>> +#define DBGWCR8 __ACCESS_CP14(c0, 0, c8, 7)
>> +#define DBGWCR9 __ACCESS_CP14(c0, 0, c9, 7)
>> +#define DBGWCR10 __ACCESS_CP14(c0, 0, c10, 7)
>> +#define DBGWCR11 __ACCESS_CP14(c0, 0, c11, 7)
>> +#define DBGWCR12 __ACCESS_CP14(c0, 0, c12, 7)
>> +#define DBGWCR13 __ACCESS_CP14(c0, 0, c13, 7)
>> +#define DBGWCR14 __ACCESS_CP14(c0, 0, c14, 7)
>> +#define DBGWCR15 __ACCESS_CP14(c0, 0, c15, 7)
>> +#define DBGWVR0 __ACCESS_CP14(c0, 0, c0, 6)
>> +#define DBGWVR1 __ACCESS_CP14(c0, 0, c1, 6)
>> +#define DBGWVR2 __ACCESS_CP14(c0, 0, c2, 6)
>> +#define DBGWVR3 __ACCESS_CP14(c0, 0, c3, 6)
>> +#define DBGWVR4 __ACCESS_CP14(c0, 0, c4, 6)
>> +#define DBGWVR5 __ACCESS_CP14(c0, 0, c5, 6)
>> +#define DBGWVR6 __ACCESS_CP14(c0, 0, c6, 6)
>> +#define DBGWVR7 __ACCESS_CP14(c0, 0, c7, 6)
>> +#define DBGWVR8 __ACCESS_CP14(c0, 0, c8, 6)
>> +#define DBGWVR9 __ACCESS_CP14(c0, 0, c9, 6)
>> +#define DBGWVR10 __ACCESS_CP14(c0, 0, c10, 6)
>> +#define DBGWVR11 __ACCESS_CP14(c0, 0, c11, 6)
>> +#define DBGWVR12 __ACCESS_CP14(c0, 0, c12, 6)
>> +#define DBGWVR13 __ACCESS_CP14(c0, 0, c13, 6)
>> +#define DBGWVR14 __ACCESS_CP14(c0, 0, c14, 6)
>> +#define DBGWVR15 __ACCESS_CP14(c0, 0, c15, 6)
>> +
>> +#define read_debug_bcr(reg) read_sysreg(DBGBCR ## reg)
>> +#define read_debug_bvr(reg) read_sysreg(DBGBVR ## reg)
>> +#define read_debug_wcr(reg) read_sysreg(DBGWCR ## reg)
>> +#define read_debug_wvr(reg) read_sysreg(DBGWVR ## reg)
>> +
>> +#define write_debug_bcr(val, reg) write_sysreg(val, DBGBCR ## reg)
>> +#define write_debug_bvr(val, reg) write_sysreg(val, DBGBVR ## reg)
>> +#define write_debug_wcr(val, reg) write_sysreg(val, DBGWCR ## reg)
>> +#define write_debug_wvr(val, reg) write_sysreg(val, DBGWVR ## reg)
>> +
>> +#define PRIxDBGADDR PRIx32
>> +
>> +struct dbgregs {
>> + uint32_t dbgbcr;
>> + uint32_t dbgbvr;
>> + uint32_t dbgwcr;
>> + uint32_t dbgwvr;
>> +};
>> +
>> +#elif defined(__aarch64__)
>> +
>> +#define read_debug_bcr(reg) read_sysreg(dbgbcr ## reg ## _el1)
>> +#define read_debug_bvr(reg) read_sysreg(dbgbvr ## reg ## _el1)
>> +#define read_debug_wcr(reg) read_sysreg(dbgwcr ## reg ## _el1)
>> +#define read_debug_wvr(reg) read_sysreg(dbgwvr ## reg ## _el1)
>> +
>> +#define write_debug_bcr(val, reg) write_sysreg(val, dbgbcr ## reg ## _el1)
>> +#define write_debug_bvr(val, reg) write_sysreg(val, dbgbvr ## reg ## _el1)
>> +#define write_debug_wcr(val, reg) write_sysreg(val, dbgwcr ## reg ## _el1)
>> +#define write_debug_wvr(val, reg) write_sysreg(val, dbgwvr ## reg ## _el1)
>> +
>> +#define PRIxDBGADDR PRIx64
>> +
>> +struct dbgregs {
>> + uint32_t dbgbcr;
>> + uint64_t dbgbvr;
>> + uint32_t dbgwcr;
>> + uint64_t dbgwvr;
>> +};
>> +
>> +#endif
>> +
>> +#define MIN(a, b) ((a) < (b) ? (a) : (b))
>
> MIN() is already defined in libcflat.h
>
>> +
>> +static cpumask_t smp_test_complete;
>> +static int nbp, nwp;
>> +
>> +static void read_dbgb(int n, struct dbgregs *array)
>> +{
>> + switch (n-1) {
>> + case 15:
>> + array[15].dbgbcr = read_debug_bcr(15);
>> + array[15].dbgbvr = read_debug_bvr(15);
>> + case 14:
>> + array[14].dbgbcr = read_debug_bcr(14);
>> + array[14].dbgbvr = read_debug_bvr(14);
>> + case 13:
>> + array[13].dbgbcr = read_debug_bcr(13);
>> + array[13].dbgbvr = read_debug_bvr(13);
>> + case 12:
>> + array[12].dbgbcr = read_debug_bcr(12);
>> + array[12].dbgbvr = read_debug_bvr(12);
>> + case 11:
>> + array[11].dbgbcr = read_debug_bcr(11);
>> + array[11].dbgbvr = read_debug_bvr(11);
>> + case 10:
>> + array[10].dbgbcr = read_debug_bcr(10);
>> + array[10].dbgbvr = read_debug_bvr(10);
>> + case 9:
>> + array[9].dbgbcr = read_debug_bcr(9);
>> + array[9].dbgbvr = read_debug_bvr(9);
>> + case 8:
>> + array[8].dbgbcr = read_debug_bcr(8);
>> + array[8].dbgbvr = read_debug_bvr(8);
>> + case 7:
>> + array[7].dbgbcr = read_debug_bcr(7);
>> + array[7].dbgbvr = read_debug_bvr(7);
>> + case 6:
>> + array[6].dbgbcr = read_debug_bcr(6);
>> + array[6].dbgbvr = read_debug_bvr(6);
>> + case 5:
>> + array[5].dbgbcr = read_debug_bcr(5);
>> + array[5].dbgbvr = read_debug_bvr(5);
>> + case 4:
>> + array[4].dbgbcr = read_debug_bcr(4);
>> + array[4].dbgbvr = read_debug_bvr(4);
>> + case 3:
>> + array[3].dbgbcr = read_debug_bcr(3);
>> + array[3].dbgbvr = read_debug_bvr(3);
>> + case 2:
>> + array[2].dbgbcr = read_debug_bcr(2);
>> + array[2].dbgbvr = read_debug_bvr(2);
>> + case 1:
>> + array[1].dbgbcr = read_debug_bcr(1);
>> + array[1].dbgbvr = read_debug_bvr(1);
>> + case 0:
>> + array[0].dbgbcr = read_debug_bcr(0);
>> + array[0].dbgbvr = read_debug_bvr(0);
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static void write_dbgb(int n, struct dbgregs *array)
>> +{
>> + switch (n-1) {
>> + case 15:
>> + write_debug_bcr(array[15].dbgbcr, 15);
>> + write_debug_bvr(array[15].dbgbvr, 15);
>> + case 14:
>> + write_debug_bcr(array[14].dbgbcr, 14);
>> + write_debug_bvr(array[14].dbgbvr, 14);
>> + case 13:
>> + write_debug_bcr(array[13].dbgbcr, 13);
>> + write_debug_bvr(array[13].dbgbvr, 13);
>> + case 12:
>> + write_debug_bcr(array[12].dbgbcr, 12);
>> + write_debug_bvr(array[12].dbgbvr, 12);
>> + case 11:
>> + write_debug_bcr(array[11].dbgbcr, 11);
>> + write_debug_bvr(array[11].dbgbvr, 11);
>> + case 10:
>> + write_debug_bcr(array[10].dbgbcr, 10);
>> + write_debug_bvr(array[10].dbgbvr, 10);
>> + case 9:
>> + write_debug_bcr(array[9].dbgbcr, 9);
>> + write_debug_bvr(array[9].dbgbvr, 9);
>> + case 8:
>> + write_debug_bcr(array[8].dbgbcr, 8);
>> + write_debug_bvr(array[8].dbgbvr, 8);
>> + case 7:
>> + write_debug_bcr(array[7].dbgbcr, 7);
>> + write_debug_bvr(array[7].dbgbvr, 7);
>> + case 6:
>> + write_debug_bcr(array[6].dbgbcr, 6);
>> + write_debug_bvr(array[6].dbgbvr, 6);
>> + case 5:
>> + write_debug_bcr(array[5].dbgbcr, 5);
>> + write_debug_bvr(array[5].dbgbvr, 5);
>> + case 4:
>> + write_debug_bcr(array[4].dbgbcr, 4);
>> + write_debug_bvr(array[4].dbgbvr, 4);
>> + case 3:
>> + write_debug_bcr(array[3].dbgbcr, 3);
>> + write_debug_bvr(array[3].dbgbvr, 3);
>> + case 2:
>> + write_debug_bcr(array[2].dbgbcr, 2);
>> + write_debug_bvr(array[2].dbgbvr, 2);
>> + case 1:
>> + write_debug_bcr(array[1].dbgbcr, 1);
>> + write_debug_bvr(array[1].dbgbvr, 1);
>> + case 0:
>> + write_debug_bcr(array[0].dbgbcr, 0);
>> + write_debug_bvr(array[0].dbgbvr, 0);
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static void read_dbgw(int n, struct dbgregs *array)
>> +{
>> + switch (n-1) {
>> + case 15:
>> + array[15].dbgwcr = read_debug_wcr(15);
>> + array[15].dbgwvr = read_debug_wvr(15);
>> + case 14:
>> + array[14].dbgwcr = read_debug_wcr(14);
>> + array[14].dbgwvr = read_debug_wvr(14);
>> + case 13:
>> + array[13].dbgwcr = read_debug_wcr(13);
>> + array[13].dbgwvr = read_debug_wvr(13);
>> + case 12:
>> + array[12].dbgwcr = read_debug_wcr(12);
>> + array[12].dbgwvr = read_debug_wvr(12);
>> + case 11:
>> + array[11].dbgwcr = read_debug_wcr(11);
>> + array[11].dbgwvr = read_debug_wvr(11);
>> + case 10:
>> + array[10].dbgwcr = read_debug_wcr(10);
>> + array[10].dbgwvr = read_debug_wvr(10);
>> + case 9:
>> + array[9].dbgwcr = read_debug_wcr(9);
>> + array[9].dbgwvr = read_debug_wvr(9);
>> + case 8:
>> + array[8].dbgwcr = read_debug_wcr(8);
>> + array[8].dbgwvr = read_debug_wvr(8);
>> + case 7:
>> + array[7].dbgwcr = read_debug_wcr(7);
>> + array[7].dbgwvr = read_debug_wvr(7);
>> + case 6:
>> + array[6].dbgwcr = read_debug_wcr(6);
>> + array[6].dbgwvr = read_debug_wvr(6);
>> + case 5:
>> + array[5].dbgwcr = read_debug_wcr(5);
>> + array[5].dbgwvr = read_debug_wvr(5);
>> + case 4:
>> + array[4].dbgwcr = read_debug_wcr(4);
>> + array[4].dbgwvr = read_debug_wvr(4);
>> + case 3:
>> + array[3].dbgwcr = read_debug_wcr(3);
>> + array[3].dbgwvr = read_debug_wvr(3);
>> + case 2:
>> + array[2].dbgwcr = read_debug_wcr(2);
>> + array[2].dbgwvr = read_debug_wvr(2);
>> + case 1:
>> + array[1].dbgwcr = read_debug_wcr(1);
>> + array[1].dbgwvr = read_debug_wvr(1);
>> + case 0:
>> + array[0].dbgwcr = read_debug_wcr(0);
>> + array[0].dbgwvr = read_debug_wvr(0);
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static void write_dbgw(int n, struct dbgregs *array)
>> +{
>> + switch (n-1) {
>> + case 15:
>> + write_debug_wcr(array[15].dbgwcr, 15);
>> + write_debug_wvr(array[15].dbgwvr, 15);
>> + case 14:
>> + write_debug_wcr(array[14].dbgwcr, 14);
>> + write_debug_wvr(array[14].dbgwvr, 14);
>> + case 13:
>> + write_debug_wcr(array[13].dbgwcr, 13);
>> + write_debug_wvr(array[13].dbgwvr, 13);
>> + case 12:
>> + write_debug_wcr(array[12].dbgwcr, 12);
>> + write_debug_wvr(array[12].dbgwvr, 12);
>> + case 11:
>> + write_debug_wcr(array[11].dbgwcr, 11);
>> + write_debug_wvr(array[11].dbgwvr, 11);
>> + case 10:
>> + write_debug_wcr(array[10].dbgwcr, 10);
>> + write_debug_wvr(array[10].dbgwvr, 10);
>> + case 9:
>> + write_debug_wcr(array[9].dbgwcr, 9);
>> + write_debug_wvr(array[9].dbgwvr, 9);
>> + case 8:
>> + write_debug_wcr(array[8].dbgwcr, 8);
>> + write_debug_wvr(array[8].dbgwvr, 8);
>> + case 7:
>> + write_debug_wcr(array[7].dbgwcr, 7);
>> + write_debug_wvr(array[7].dbgwvr, 7);
>> + case 6:
>> + write_debug_wcr(array[6].dbgwcr, 6);
>> + write_debug_wvr(array[6].dbgwvr, 6);
>> + case 5:
>> + write_debug_wcr(array[5].dbgwcr, 5);
>> + write_debug_wvr(array[5].dbgwvr, 5);
>> + case 4:
>> + write_debug_wcr(array[4].dbgwcr, 4);
>> + write_debug_wvr(array[4].dbgwvr, 4);
>> + case 3:
>> + write_debug_wcr(array[3].dbgwcr, 3);
>> + write_debug_wvr(array[3].dbgwvr, 3);
>> + case 2:
>> + write_debug_wcr(array[2].dbgwcr, 2);
>> + write_debug_wvr(array[2].dbgwvr, 2);
>> + case 1:
>> + write_debug_wcr(array[1].dbgwcr, 1);
>> + write_debug_wvr(array[1].dbgwvr, 1);
>> + case 0:
>> + write_debug_wcr(array[0].dbgwcr, 0);
>> + write_debug_wvr(array[0].dbgwvr, 0);
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>
> Any reason not to implement the above functions with
> loops? E.g.
>
> while (--n >= 0) {
> write_debug_wcr(array[n].dbgwcr, n);
> write_debug_wvr(array[n].dbgwvr, n);
> }
Well we are using macro pasting here so we need to instantiate all
possible asm fragments.
>
>> +
>> +static void dump_regs(int cpu, struct dbgregs *array)
>> +{
>> + int i;
>> +
>> + for (i = 0; i < nbp; i++)
>> + printf("CPU%d: B%d 0x%08x:0x%" PRIxDBGADDR "\n", cpu, i,
>> + array[i].dbgbcr, array[i].dbgbvr);
>> + for (i = 0; i < nwp; i++)
>> + printf("CPU%d: W%d 0x%08x:0x%" PRIxDBGADDR "\n", cpu, i,
>> + array[i].dbgwcr, array[i].dbgwvr);
>> +}
>> +
>> +static int compare_regs(struct dbgregs *initial, struct dbgregs *current)
>> +{
>> + int i, errors = 0;
>> +
>> + for (i = 0; i < nbp; i++) {
>> + if (initial[i].dbgbcr != current[i].dbgbcr) {
>> + printf("ERROR DBGBCR%d: %" PRIx32 "!=%" PRIx32 "\n",
>> + i, initial[i].dbgbcr, current[i].dbgbcr);
>> + errors++;
>> + }
>> + if (initial[i].dbgbvr != current[i].dbgbvr) {
>> + printf("ERROR DBGBVR%d: %" PRIxDBGADDR "!=%" PRIxDBGADDR "\n",
>> + i, initial[i].dbgbvr, current[i].dbgbvr);
>> + errors++;
>> + }
>> + }
>> +
>> + for (i = 0; i < nwp; i++) {
>> + if (initial[i].dbgwcr != current[i].dbgwcr) {
>> + printf("ERROR DBGWCR%d: %" PRIx32 "!=%" PRIx32 "\n",
>> + i, initial[i].dbgwcr, current[i].dbgwcr);
>> + errors++;
>> + }
>> + if (initial[i].dbgwvr != current[i].dbgwvr) {
>> + printf("ERROR DBWVR%d: %" PRIxDBGADDR "!=%" PRIxDBGADDR "\n",
>> + i, initial[i].dbgwvr, current[i].dbgwvr);
>> + errors++;
>> + }
>> + }
>
> Shouldn't these error messages also output the CPU?
>
>> +
>> + return errors;
>> +}
>> +
>> +static void test_debug_regs(void)
>> +{
>> + int errors = 0;
>> + int cpu = smp_processor_id();
>> + int i;
>> + struct dbgregs initial[16], current[16];
>> +
>> + printf("CPU%d online\n", cpu);
>> +
>> + printf("Reading Initial Values\n");
>> + read_dbgb(nbp, &initial[0]);
>> + read_dbgw(nwp, &initial[0]);
>> + dump_regs(cpu, &initial[0]);
>> +
>> + printf("Setting simple BPs and WPs\n");
>> + for (i = 0; i < nbp; i++) {
>> + initial[i].dbgbcr = (0x3 << 1) | (0xf << 5) ; /* E=0 */
>> + initial[i].dbgbvr = ~0x3;
>> + }
>> + for (i = 0; i < nwp; i++) {
>> + initial[i].dbgwcr = (0x3 << 1) | (0x3 << 3); /* E=0 */
>> + initial[i].dbgwvr = ~0x7;
>> + }
>> + write_dbgb(nbp, &initial[0]);
>> + write_dbgw(nwp, &initial[0]);
>> +
>> + printf("Reading values back\n");
>
> The above informational printfs will print for each cpu and in whatever
> order the cpus are run, potentially giving strangely ordered output. Do
> we really need them?
>
>> + read_dbgb(nbp, ¤t[0]);
>> + read_dbgw(nwp, ¤t[0]);
>> +
>> + errors += compare_regs(&initial[0], ¤t[0]);
>> +
>> + report("CPU%d: Done - Errors: %d\n", errors == 0, cpu, errors);
>> +
>> + if (errors)
>> + dump_regs(cpu, ¤t[0]);
>> +
>> + cpumask_set_cpu(cpu, &smp_test_complete);
>> + if (cpu != 0)
>> + halt();
>> +}
>> +
>> +static char *split_var(char *s, long *val)
>> +{
>> + char *p;
>> +
>> + p = strchr(s, '=');
>> + if (!p)
>> + return NULL;
>> +
>> + *val = atol(p+1);
>> + *p = '\0';
>> +
>> + return s;
>> +}
>
> We have parse_keyval() in lib/util.c. It isn't an awesome design,
> but it's similar to this old split_var() does. I think Radim has
> plans to improve on it, at which time we'll fix this test up too.
> In short, let's use parse_keyval here for now and not add this
> function.
>
>> +
>> +#if defined(__arm__)
>> +static void read_debug_feature_regs(void)
>> +{
>> + uint32_t id_dfr0 = read_sysreg(ID_DFR0);
>> + uint32_t dbgdidr = read_sysreg(DBGDIDR);
>> + uint32_t dbgdscr = read_sysreg(DBGDSCR);
>> + char *pmu, *dm_m, *mmt_m, *cpt_m, *mmd_m, *cpsd_m, *cpd_m;
>> +
>> + printf("ID_DFR0: 0x%" PRIx32 "\n", id_dfr0);
>> +
>> + /* PMU support */
>> + switch ((id_dfr0 >> 24) & 0xf) {
>> + case 0:
>> + pmu = "No PMUv2";
>> + break;
>> + case 1:
>> + pmu = "PMUv1";
>> + break;
>> + case 2:
>> + pmu = "PMUv2";
>> + break;
>> + case 3:
>> + pmu = "No PMU Extensions";
>> + break;
>> + default:
>> + pmu = "Invalid";
>> + break;
>> + }
>> + printf(" PMU: %s\n", pmu);
>> +
>> + /* M-profile debug model */
>> + switch ((id_dfr0 >> 20) & 0xf) {
>> + case 0:
>> + dm_m = "Not supported";
>> + break;
>> + case 1:
>> + dm_m = "M-profile debug with memory mapped access";
>> + break;
>> + default:
>> + dm_m = "Invalid";
>> + break;
>> + }
>> + printf(" M-profile debug: %s\n", dm_m);
>> +
>> + /* Memory mapped trace model */
>> + switch ((id_dfr0 >> 16) & 0xf) {
>> + case 0:
>> + mmt_m = "Not supported";
>> + break;
>> + case 1:
>> + mmt_m = "Supported with memory mapped access";
>> + break;
>> + default:
>> + mmt_m = "Invalid";
>> + break;
>> + }
>> + printf(" Trace Model: %s\n", mmt_m);
>> +
>> + /* Co-processor trace model */
>> + switch ((id_dfr0 >> 12) & 0xf) {
>> + case 0:
>> + cpt_m = "Not supported";
>> + break;
>> + case 1:
>> + cpt_m = "Supported with CP14access";
>> + break;
>> + default:
>> + cpt_m = "Invalid";
>> + break;
>> + }
>> + printf(" Trace Model: %s\n", cpt_m);
>> +
>> + /* Memory mapped debug model, A and R profiles */
>> + switch ((id_dfr0 >> 8) & 0xf) {
>> + case 0:
>> + mmd_m = "Not supported or pre-ARMv6";
>> + break;
>> + case 4:
>> + mmd_m = "Supported v7 Debug Architecture";
>> + break;
>> + case 5:
>> + mmd_m = "Supported v7.1 Debug Architecture";
>> + break;
>> + default:
>> + mmd_m = "Invalid";
>> + break;
>> + }
>> + printf(" Debug Model: %s\n", mmd_m);
>> +
>> + /* Co-processor secure debug model */
>> + switch ((id_dfr0 >> 4) & 0xf) {
>> + case 0:
>> + cpsd_m = "Not supported";
>> + break;
>> + case 2:
>> + cpsd_m = "Supported v6 Debug Architecture";
>> + break;
>> + case 3:
>> + cpsd_m = "Supported v6.1 Debug Architecture";
>> + break;
>> + case 4:
>> + cpsd_m = "Supported v7 Debug Architecture";
>> + break;
>> + case 5:
>> + cpsd_m = "Supported v7.1 Debug Architecture";
>> + break;
>> + default:
>> + cpsd_m = "Invalid";
>> + break;
>> + }
>> + printf(" Co-processor Secure Debug Model: %s\n", cpsd_m);
>> +
>> + /* Co-processor debug model */
>> + switch ((id_dfr0 >> 0) & 0xf) {
>> + case 0:
>> + cpd_m = "Not supported";
>> + break;
>> + case 2:
>> + cpd_m = "Supported v6 Debug Architecture";
>> + break;
>> + case 3:
>> + cpd_m = "Supported v6.1 Debug Architecture";
>> + break;
>> + case 4:
>> + cpd_m = "Supported v7 Debug Architecture";
>> + break;
>> + case 5:
>> + cpd_m = "Supported v7.1 Debug Architecture";
>> + break;
>> + default:
>> + cpd_m = "Invalid";
>> + break;
>> + }
>> + printf(" Co-processor Debug Model: %s\n", cpd_m);
>> +
>> + /* DBGIDR, num registers */
>> + nwp = (dbgdidr >> 28) + 1;
>> + /* BRPs == 0 is reserved, else it is BRPs + 1 */
>> + nbp = ((dbgdidr >> 24) & 0xf);
>> + if (nbp > 0)
>> + nbp += 1;
>> +
>> + printf("DBGDIDR: 0x%" PRIx32 " nwp:%d nbp:%d\n", dbgdidr, nwp, nbp);
>> +
> nit: extra blank line
>> + printf("DBGDSCR: 0x%" PRIx32 "\n", dbgdscr);
>
> You might want to consider report_info() instead of printfs here.
>
>> +
>> +}
>> +#elif defined(__aarch64__)
>> +static void read_debug_feature_regs(void)
>> +{
>> + uint64_t id = read_sysreg(id_aa64dfr0_el1);
>> +
>> + /* Check the number of break/watch points */
>> + nbp = ((id >> 12) & 0xf);
>> + if (nbp > 0)
>> + nbp -= 1;
>> +
>> + nwp = ((id >> 20) & 0xf);
>> + if (nwp > 0)
>> + nwp -= 1;
>> +
>> + printf("ID_AA64_DFR0_EL1: 0x%" PRIx64 " nwp:%d nbp:%d\n", id, nwp, nbp);
>
> report_info()?
>
>> +}
>> +#endif
>> +
>> +int main(int argc, char **argv)
>> +{
>> + int cpu, i;
>> +
>> + read_debug_feature_regs();
>> +
>> + for (i = 0; i < argc; ++i) {
>
> should start at i = 1, argv[0] is program name
>
>> + char *var;
>> + long val;
>> +
>> + var = split_var(argv[i], &val);
>> +
>> + if (var) {
>> + int tmp;
>> +
>> + if (strcmp(var, "nbp") == 0) {
>> + tmp = MIN(nbp, val);
>> + nbp = tmp;
>> + }
>> + if (strcmp(var, "nwp") == 0) {
>> + tmp = MIN(nwp, val);
>> + nwp = tmp;
>> + }
>> + }
>> + }
>
> Should probably report_info() the values of nbp and nwp
> here as they're variable and have the MIN() thing and all
> modifying them.
>
>> +
>> + for_each_present_cpu(cpu) {
>> + if (cpu == 0)
>> + continue;
>> + smp_boot_secondary(cpu, test_debug_regs);
>> + }
>> +
>> + test_debug_regs();
>> +
>> + while (!cpumask_full(&smp_test_complete))
>> + cpu_relax();
>> +
>> + return report_summary();
>> +}
>> --
>> 2.13.0
>>
>
> Thanks,
> drew
--
Alex Bennée
next prev parent reply other threads:[~2017-05-22 18:41 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-05-18 16:02 [kvm-unit-tests PATCH v2 0/3] ARM debug register test Alex Bennée
2017-05-18 16:02 ` [kvm-unit-tests PATCH v2 1/3] sysregs: add __ACCESS_CP14 macro Alex Bennée
2017-05-22 17:27 ` Andrew Jones
2017-05-18 16:02 ` [kvm-unit-tests PATCH v2 2/3] arm/run: ensure we use processor=host for kvm Alex Bennée
2017-05-18 16:03 ` Paolo Bonzini
2017-05-19 6:29 ` Christoffer Dall
2017-05-19 8:11 ` Paolo Bonzini
2017-05-22 17:25 ` Andrew Jones
2017-05-18 16:02 ` [kvm-unit-tests PATCH v2 3/3] arm/debugtest: test access to the debug registers for guest Alex Bennée
2017-05-22 16:56 ` Radim Krčmář
2017-05-22 18:40 ` Alex Bennée
2017-05-22 17:22 ` Andrew Jones
2017-05-22 18:41 ` Alex Bennée [this message]
2017-05-23 9:41 ` Andrew Jones
2017-05-23 9:50 ` Andrew Jones
2017-05-25 15:32 ` [kvm-unit-tests PATCH v2 0/3] ARM debug register test Paolo Bonzini
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=87o9uk3fau.fsf@linaro.org \
--to=alex.bennee@linaro.org \
--cc=christoffer.dall@linaro.org \
--cc=drjones@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=marc.zyngier@arm.com \
--cc=pbonzini@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.