diff mbox series

hw/arm: Add 'virtm' hardware

Message ID 20200625230740.549114-1-keithp@keithp.com (mailing list archive)
State New, archived
Headers show
Series hw/arm: Add 'virtm' hardware | expand

Commit Message

Denis V. Lunev" via June 25, 2020, 11:07 p.m. UTC
'virtm' is a hardware target that is designed to be used for compiler
and library testing on Cortex-M processors. It supports all cortex-m
processors and includes sufficient memory to run even large test
cases.

Signed-off-by: Keith Packard <keithp@keithp.com>
---
 MAINTAINERS          |   9 +++-
 hw/arm/Makefile.objs |   2 +-
 hw/arm/virtm.c       | 112 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 121 insertions(+), 2 deletions(-)
 create mode 100644 hw/arm/virtm.c

Comments

Peter Maydell June 26, 2020, 8:38 a.m. UTC | #1
On Fri, 26 Jun 2020 at 00:07, Keith Packard <keithp@keithp.com> wrote:
>
> 'virtm' is a hardware target that is designed to be used for compiler
> and library testing on Cortex-M processors. It supports all cortex-m
> processors and includes sufficient memory to run even large test
> cases.
>
> Signed-off-by: Keith Packard <keithp@keithp.com>

So, I'm really dubious about adding more "virtual"
not-real-hardware boards. We have "virt" because we
absolutely have to have it for KVM purposes; but otherwise
"emulate real hardware" gives us a concrete specification
of what we're trying to do and tends to lead us into fewer
messy swamps than making up virtual platforms does.

For instance, this board model claims to handle the M33
but makes no attempt to set up any of the TrustZone
related components like the IDAU, so it isn't really
a useful platform for that CPU. You also enable bitband,
which is maybe plausible for Cortex-M3/M4 but not for the
others. This is the kind of area where having a real
hardware system to check against means we make the
right choices about what does or doesn't need to be
present.

thanks
-- PMM
Denis V. Lunev" via June 26, 2020, 4:40 p.m. UTC | #2
Peter Maydell <peter.maydell@linaro.org> writes:

> So, I'm really dubious about adding more "virtual"
> not-real-hardware boards. We have "virt" because we
> absolutely have to have it for KVM purposes; but otherwise
> "emulate real hardware" gives us a concrete specification
> of what we're trying to do and tends to lead us into fewer
> messy swamps than making up virtual platforms does.

It depends on what you're using qemu for. I'm using it for C library
tests, where I need memory and a processor, plus the ability to make
semihosting calls and that's it.

It seems like it should be possible to construct a virtual platform that
is limited to just these elements without getting too far into the
weeds?

> For instance, this board model claims to handle the M33
> but makes no attempt to set up any of the TrustZone
> related components like the IDAU, so it isn't really
> a useful platform for that CPU.

It's sufficient for my purposes, if adding those things would make it
suitable for more people, that'd be awesome.

> You also enable bitband, which is maybe plausible for Cortex-M3/M4 but
> not for the others.

Thanks for the bug report; bits of this code came from the stellaris
code, including that part. I'll review the code in more detail to make
sure it doesn't expose any features which aren't supposed to be. That
will catch toolchain bugs which attempt to use features not present in
the hardware, which is critical to successful validation.

> This is the kind of area where having a real hardware system to check
> against means we make the right choices about what does or doesn't
> need to be present.

I have tried every single 32-bit ARM emulation provided by qemu and none
of them offer enough memory along with the ability to select an
arbitrary processor. The stellaris code is the closest as it allows
overriding the CPU type, and I've been able to run most of the C library
tests using that. However, both boards supported by that code have a
small fixed memory size, which isn't large enough to run the full test
suite (the math tests require over 1M of ROM and RAM).

Instead of creating another virtual platform, should I be working on the
existing virt code to add cortex-m support?

Ideally, I'd be able to emulate the full set of configurations that the
embedded ARM GCC port does. I'm currently using the 2019-q3 release,
which offers 18 configurations. Before I included 'virtm', I was able to
test only one of them using the mps2-an385 emulator. With virtm, I'm
covering 11 of them.

The 'virt' emulator should cover the cortex-a7 cases, leaving only four
cases untested (I haven't figured out the right configuration to run
bare metal code on that yet). I can't find any ARM processors which
implement v8-m with DP support, and the only QEMU module with v5te
support appears to be digic, which I haven't experimented with at all.

                Architecture    FPU             QEMU -cpu       Picolibc tests
        ----    -----           ------          ---------       --------------
        arm	v5te		softfp          arm946          
        arm	v5te		hard            arm946          
        thumb	v7		nofp            cortex-a7       
        thumb	v7+fp		softfp          cortex-a7       
        thumb	v7+fp		hard            cortex-a7       
        thumb	v6-m		nofp            cortex-m0       yes
        thumb	v7-m		nofp            cortex-m3       yes
        thumb	v7e-m		nofp            cortex-m4       yes
        thumb	v7e-m+fp	softfp          cortex-m4       yes
        thumb	v7e-m+fp	hard            cortex-m4       yes
        thumb	v7e-m+dp	softfp          cortex-m7       yes
        thumb	v7e-m+dp	hard            cortex-m7       yes
        thumb	v8-m.base	nofp            cortex-m33      yes
        thumb	v8-m.main	nofp            cortex-m33      yes
        thumb	v8-m.main+fp	softfp          cortex-m33      yes
        thumb	v8-m.main+fp	hard            cortex-m33      yes
        thumb	v8-m.main+dp	softfp
        thumb	v8-m.main+dp	hard
Peter Maydell June 26, 2020, 5:31 p.m. UTC | #3
On Fri, 26 Jun 2020 at 17:40, Keith Packard <keithp@keithp.com> wrote:
>
> Peter Maydell <peter.maydell@linaro.org> writes:
>
> > So, I'm really dubious about adding more "virtual"
> > not-real-hardware boards. We have "virt" because we
> > absolutely have to have it for KVM purposes; but otherwise
> > "emulate real hardware" gives us a concrete specification
> > of what we're trying to do and tends to lead us into fewer
> > messy swamps than making up virtual platforms does.
>
> It depends on what you're using qemu for. I'm using it for C library
> tests, where I need memory and a processor, plus the ability to make
> semihosting calls and that's it.

You might find the user-mode qemu-arm sufficient for that
kind of thing. I know some gcc tests run that way. You
get a processor, semihosting, and whatever memory your
ELF file's data segment says you have (plus anything
you care to mmap()).

> > For instance, this board model claims to handle the M33
> > but makes no attempt to set up any of the TrustZone
> > related components like the IDAU, so it isn't really
> > a useful platform for that CPU.
>
> It's sufficient for my purposes, if adding those things would make it
> suitable for more people, that'd be awesome.

Sure, but "machine-that-works-for-keith-packard" isn't really
a very clearly-defined concept :-)

> > This is the kind of area where having a real hardware system to check
> > against means we make the right choices about what does or doesn't
> > need to be present.
>
> I have tried every single 32-bit ARM emulation provided by qemu and none
> of them offer enough memory along with the ability to select an
> arbitrary processor. The stellaris code is the closest as it allows
> overriding the CPU type, and I've been able to run most of the C library
> tests using that. However, both boards supported by that code have a
> small fixed memory size, which isn't large enough to run the full test
> suite (the math tests require over 1M of ROM and RAM).

> Instead of creating another virtual platform, should I be working on the
> existing virt code to add cortex-m support?

I think that trying to weld M-profile into the A-profile virt
board is likely to be more confusing than having a separate board.
But I remain unhappy about defining a virtual board at all
if I can avoid it.

thanks
-- PMM
Max Filippov June 26, 2020, 6:02 p.m. UTC | #4
On Fri, Jun 26, 2020 at 10:32 AM Peter Maydell <peter.maydell@linaro.org> wrote:
> You might find the user-mode qemu-arm sufficient for that
> kind of thing. I know some gcc tests run that way. You
> get a processor, semihosting, and whatever memory your
> ELF file's data segment says you have (plus anything
> you care to mmap()).

I routinely run xtensa gcc testsuite in user-mode qemu, the results
are the same as when I run it on a remote board emulated by
system-mode QEMU. OTOH for the glibc testsuite the results in
user-mode and system-mode emulation used to differ significantly.
Here's my account of differences:
http://wiki.osll.ru/doku.php/etc:users:jcmvbkbc:glibc-xtensa
Most of them are due to unsupported/differently implemented
syscalls.
Denis V. Lunev" via June 26, 2020, 8:12 p.m. UTC | #5
Peter Maydell <peter.maydell@linaro.org> writes:

> You might find the user-mode qemu-arm sufficient for that
> kind of thing. I know some gcc tests run that way. You
> get a processor, semihosting, and whatever memory your
> ELF file's data segment says you have (plus anything
> you care to mmap()).

Thanks for the pointer; I've spent a bit of time checking out whether
that might work, and it looks like I could get some testing done there,
but I couldn't get the chip startup code tested (things like enabling
the FPU, setting up the stack, data and bss segments).

I had always assumed that qemu-arm was designed to run user-mode Linux
applications on top of another Linux system (given that it's called
'arm-linux-user' in the qemu configuration code). That's why I hadn't
even tried using it for this work.

> Sure, but "machine-that-works-for-keith-packard" isn't really
> a very clearly-defined concept :-)

It seems well defined to me at least? An ARM core plus memory. That's
sufficient to run tests with semihosting to validate compilers,
libraries and the like. It would also serve as a model for people
developing new QEMU boards to start from; here's a processor and memory,
now you add peripherals and you've got a complete system.

This is all in service of a pretty easily explained goal -- a free
software C library designed for embedded systems that gets tested on the
target processors.

With QEMU, I'm able to incorporate all of the code necessary right in
the library to execute tests on simulated hardware that starts from the
reset vector. That same code can run on native hardware, allowing
developers to get past the usual embedded development startup hurdle of
creating a linker script, writing NVIC interrupt vector table and
initializing RAM.

I'd like to make the memory parameters configurable so that a developer
could set qemu to match their particular SoC. Then they'd be able to run
their application under QEMU and at least ensure that it gets to main()
before flashing it on the target hardware.

> I think that trying to weld M-profile into the A-profile virt
> board is likely to be more confusing than having a separate board.
> But I remain unhappy about defining a virtual board at all
> if I can avoid it.

Ok, that was my thinking for doing this as a separate board; the
existing virt board seems complex enough without attempting to wedge
something very different into it.

I'll experiment with the arm-linux-user mode of QEMU a bit more to see
how much testing that would enable; it should at least allow testing of
the libc and libm functions, although not the crt0 implementation and
sample linker scripts.

I'd love help in creating a better definition of what the 'virtm' board
should be, and figure out a way to explain it so that you appreciate the
value it brings to the ARM ecosystem.
Denis V. Lunev" via June 26, 2020, 8:14 p.m. UTC | #6
Max Filippov <jcmvbkbc@gmail.com> writes:

> Most of them are due to unsupported/differently implemented
> syscalls.

Yeah, I think that was the basis of my confusion -- qemu-arm is not a
bare metal environment, and my work is focused on enabling application
development in that environment.
Peter Maydell June 26, 2020, 9:40 p.m. UTC | #7
On Fri, 26 Jun 2020 at 21:14, Keith Packard <keithp@keithp.com> wrote:
>
> Max Filippov <jcmvbkbc@gmail.com> writes:
>
> > Most of them are due to unsupported/differently implemented
> > syscalls.
>
> Yeah, I think that was the basis of my confusion -- qemu-arm is not a
> bare metal environment, and my work is focused on enabling application
> development in that environment.

Yes, but for certain cases of bare-metal code that doesn't need to
touch devices or use any privileged-only instructions it may be
a usable environment. (This is more side-effect than intentional:
as you say the primary use case is Linux userspace binaries.)

thanks
-- PMM
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index 1b40446c73..4c7e394dd6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -850,9 +850,16 @@  Virt
 M: Peter Maydell <peter.maydell@linaro.org>
 L: qemu-arm@nongnu.org
 S: Maintained
-F: hw/arm/virt*
+F: hw/arm/virt.c
+F: hw/arm/virt-acpi-build.c
 F: include/hw/arm/virt.h
 
+Virt M
+M: Keith Packard <keithp@keithp.com>
+L: qemu-arm@nongnu.org
+S: Maintained
+F: hw/arm/virtm.c
+
 Xilinx Zynq
 M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 M: Alistair Francis <alistair@alistair23.me>
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 534a6a119e..54be15b40a 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -1,6 +1,6 @@ 
 obj-y += boot.o
 obj-$(CONFIG_PLATFORM_BUS) += sysbus-fdt.o
-obj-$(CONFIG_ARM_VIRT) += virt.o
+obj-$(CONFIG_ARM_VIRT) += virt.o virtm.o
 obj-$(CONFIG_ACPI) += virt-acpi-build.o
 obj-$(CONFIG_DIGIC) += digic_boards.o
 obj-$(CONFIG_EXYNOS4) += exynos4_boards.o
diff --git a/hw/arm/virtm.c b/hw/arm/virtm.c
new file mode 100644
index 0000000000..beda3644f5
--- /dev/null
+++ b/hw/arm/virtm.c
@@ -0,0 +1,112 @@ 
+/*
+ * Virtual ARM Cortex M
+ *
+ * Copyright © 2020, Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/arm/boot.h"
+#include "hw/boards.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/armv7m.h"
+#include "hw/misc/unimp.h"
+#include "cpu.h"
+
+#define NUM_IRQ_LINES 32
+#define ROM_BASE  0x00000000
+#define ROM_SIZE  0x20000000
+#define RAM_BASE    0x20000000
+#define RAM_SIZE    0x20000000
+
+static const char *valid_cpus[] = {
+    ARM_CPU_TYPE_NAME("cortex-m0"),
+    ARM_CPU_TYPE_NAME("cortex-m3"),
+    ARM_CPU_TYPE_NAME("cortex-m33"),
+    ARM_CPU_TYPE_NAME("cortex-m4"),
+    ARM_CPU_TYPE_NAME("cortex-m7"),
+};
+
+static bool cpu_type_valid(const char *cpu)
+{
+    int i;
+
+    return true;
+    for (i = 0; i < ARRAY_SIZE(valid_cpus); i++) {
+        if (strcmp(cpu, valid_cpus[i]) == 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+static void machvirtm_init(MachineState *ms)
+{
+    DeviceState *nvic;
+
+    if (!cpu_type_valid(ms->cpu_type)) {
+        error_report("virtm: CPU type %s not supported", ms->cpu_type);
+        exit(1);
+    }
+
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *rom = g_new(MemoryRegion, 1);
+    MemoryRegion *system_memory = get_system_memory();
+
+    /* Flash programming is done via the SCU, so pretend it is ROM.  */
+    memory_region_init_rom(rom, NULL, "virtm.rom", ROM_SIZE,
+                           &error_fatal);
+    memory_region_add_subregion(system_memory, ROM_BASE, rom);
+
+    memory_region_init_ram(ram, NULL, "virtm.ram", RAM_SIZE,
+                           &error_fatal);
+    memory_region_add_subregion(system_memory, RAM_BASE, ram);
+
+    nvic = qdev_new(TYPE_ARMV7M);
+    qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES);
+    qdev_prop_set_string(nvic, "cpu-type", ms->cpu_type);
+    qdev_prop_set_bit(nvic, "enable-bitband", true);
+    object_property_set_link(OBJECT(nvic), OBJECT(get_system_memory()),
+                                     "memory", &error_abort);
+    /* This will exit with an error if the user passed us a bad cpu_type */
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal);
+
+    armv7m_load_kernel(ARM_CPU(first_cpu), ms->kernel_filename, ROM_SIZE);
+}
+
+static void virtm_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->desc = "Virtual Cortex-M";
+    mc->init = machvirtm_init;
+    mc->ignore_memory_transaction_failures = true;
+    mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-m3");
+}
+
+static const TypeInfo virtm_type = {
+    .name = MACHINE_TYPE_NAME("virtm"),
+    .parent = TYPE_MACHINE,
+    .class_init = virtm_class_init,
+};
+
+static void virtm_machine_init(void)
+{
+    type_register_static(&virtm_type);
+}
+
+type_init(virtm_machine_init)