diff mbox series

[08/10] arm: allwinner-h3: add Security Identifier device

Message ID 20191202210947.3603-9-nieklinnenbank@gmail.com
State New
Headers show
Series Add Allwinner H3 SoC and Orange Pi PC Machine | expand

Commit Message

Niek Linnenbank Dec. 2, 2019, 9:09 p.m. UTC
The Security Identifier device in Allwinner H3 System on Chip
gives applications a per-board unique identifier. This commit
adds support for the Allwinner H3 Security Identifier using
randomized data as input.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
---
 hw/arm/allwinner-h3.c              |  11 ++
 hw/misc/Makefile.objs              |   1 +
 hw/misc/allwinner-h3-sid.c         | 162 +++++++++++++++++++++++++++++
 hw/misc/trace-events               |   5 +
 include/hw/arm/allwinner-h3.h      |   2 +
 include/hw/misc/allwinner-h3-sid.h |  42 ++++++++
 6 files changed, 223 insertions(+)
 create mode 100644 hw/misc/allwinner-h3-sid.c
 create mode 100644 include/hw/misc/allwinner-h3-sid.h

Comments

Peter Maydell Dec. 6, 2019, 2:27 p.m. UTC | #1
On Mon, 2 Dec 2019 at 21:10, Niek Linnenbank <nieklinnenbank@gmail.com> wrote:
>
> The Security Identifier device in Allwinner H3 System on Chip
> gives applications a per-board unique identifier. This commit
> adds support for the Allwinner H3 Security Identifier using
> randomized data as input.

If this is a fixed value in hardware, I'm not sure that
having the QEMU model pick a random value is the best
choice. If we just set it to a fixed value in QEMU, is
that going to cause problems?

(Generally it's nice for QEMU to be deterministic, so it
behaves the same way every time you run it. Also if it's
always the same we don't need to bother migrating the
ID value.)

thanks
-- PMM
Philippe Mathieu-Daudé Dec. 6, 2019, 4:35 p.m. UTC | #2
On 12/6/19 3:27 PM, Peter Maydell wrote:
> On Mon, 2 Dec 2019 at 21:10, Niek Linnenbank <nieklinnenbank@gmail.com> wrote:
>>
>> The Security Identifier device in Allwinner H3 System on Chip
>> gives applications a per-board unique identifier. This commit
>> adds support for the Allwinner H3 Security Identifier using
>> randomized data as input.
> 
> If this is a fixed value in hardware, I'm not sure that
> having the QEMU model pick a random value is the best
> choice. If we just set it to a fixed value in QEMU, is
> that going to cause problems?
> 
> (Generally it's nice for QEMU to be deterministic, so it
> behaves the same way every time you run it. Also if it's
> always the same we don't need to bother migrating the
> ID value.)

Agreed. Since the identifier is 128-bit, I'd use DEFINE_PROP_UUID() or, 
to be even safer, DEFINE_PROP_UUID_NODEFAULT().
See how the ipmi-bmc-sim device checks its guid field and fails if unset.
Niek Linnenbank Dec. 6, 2019, 8:20 p.m. UTC | #3
Hey Peter, Philippe,

On Fri, Dec 6, 2019 at 5:35 PM Philippe Mathieu-Daudé <philmd@redhat.com>
wrote:

> On 12/6/19 3:27 PM, Peter Maydell wrote:
> > On Mon, 2 Dec 2019 at 21:10, Niek Linnenbank <nieklinnenbank@gmail.com>
> wrote:
> >>
> >> The Security Identifier device in Allwinner H3 System on Chip
> >> gives applications a per-board unique identifier. This commit
> >> adds support for the Allwinner H3 Security Identifier using
> >> randomized data as input.
> >
> > If this is a fixed value in hardware, I'm not sure that
> > having the QEMU model pick a random value is the best
> > choice. If we just set it to a fixed value in QEMU, is
> > that going to cause problems?
> >
> > (Generally it's nice for QEMU to be deterministic, so it
> > behaves the same way every time you run it. Also if it's
> > always the same we don't need to bother migrating the
> > ID value.)
>
> Agreed. Since the identifier is 128-bit, I'd use DEFINE_PROP_UUID() or,
> to be even safer, DEFINE_PROP_UUID_NODEFAULT().
> See how the ipmi-bmc-sim device checks its guid field and fails if unset.
>

Thank you both for clarifying this. OK, I'll update this patch such that
the identifier is fixed,
using the functions Philippe suggested.

The reason I originally chose to make it randomized is that U-Boot mainline
reads out the
SID data in order to create a MAC address for the ethernet device. So when
a user runs multiple
QEMU machines inside a virtualized network, they will get the same MACs if
the SID isnt unique.
However this problem can also be solved very easy with U-Boot itself by
just overriding the ethaddr environment variable.

For your interest, in the U-Boot source you can see this behaviour in the
file
arch/arm/mach-sunxi/cpu_info.c:139 in sunxi_get_sid(), sun8i_efuse_read()
where it reads the SID
and in board/sunxi/board.c:782 in setup_environment() where it uses the SID
to create the MAC address.

Regards,
Niek
diff mbox series

Patch

diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c
index 44aba1de6a..4fc4c8c725 100644
--- a/hw/arm/allwinner-h3.c
+++ b/hw/arm/allwinner-h3.c
@@ -47,6 +47,9 @@  static void aw_h3_init(Object *obj)
 
     sysbus_init_child_obj(obj, "cpucfg", &s->cpucfg, sizeof(s->cpucfg),
                           TYPE_AW_H3_CPUCFG);
+
+    sysbus_init_child_obj(obj, "sid", &s->sid, sizeof(s->sid),
+                          TYPE_AW_H3_SID);
 }
 
 static void aw_h3_realize(DeviceState *dev, Error **errp)
@@ -206,6 +209,14 @@  static void aw_h3_realize(DeviceState *dev, Error **errp)
     }
     sysbus_mmio_map(SYS_BUS_DEVICE(&s->cpucfg), 0, AW_H3_CPUCFG_BASE);
 
+    /* Security Identifier */
+    object_property_set_bool(OBJECT(&s->sid), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->sid), 0, AW_H3_SID_BASE);
+
     /* Universal Serial Bus */
     sysbus_create_simple(TYPE_AW_H3_EHCI, AW_H3_EHCI0_BASE,
                          s->irq[AW_H3_GIC_SPI_EHCI0]);
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index c4ca2ed689..f3620eee4e 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -31,6 +31,7 @@  common-obj-$(CONFIG_IVSHMEM_DEVICE) += ivshmem.o
 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-clk.o
 obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-cpucfg.o
 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-syscon.o
+common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-sid.o
 common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
 common-obj-$(CONFIG_NSERIES) += cbus.o
 common-obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
diff --git a/hw/misc/allwinner-h3-sid.c b/hw/misc/allwinner-h3-sid.c
new file mode 100644
index 0000000000..e13e0d9887
--- /dev/null
+++ b/hw/misc/allwinner-h3-sid.c
@@ -0,0 +1,162 @@ 
+/*
+ * Allwinner H3 Security ID emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "qemu/guest-random.h"
+#include "qapi/error.h"
+#include "hw/misc/allwinner-h3-sid.h"
+
+/* SID register offsets */
+#define REG_PRCTL         (0x40) /* Control */
+#define REG_RDKEY         (0x60) /* Read Key */
+
+/* SID register flags */
+#define REG_PRCTL_WRITE   (0x2)  /* Unknown write flag */
+#define REG_PRCTL_OP_LOCK (0xAC) /* Lock operation */
+
+static uint64_t allwinner_h3_sid_read(void *opaque, hwaddr offset,
+                                      unsigned size)
+{
+    const AwH3SidState *s = (AwH3SidState *)opaque;
+    uint64_t val = 0;
+
+    switch (offset) {
+    case REG_PRCTL:    /* Control */
+        val = s->control;
+        break;
+    case REG_RDKEY:    /* Read Key */
+        val = s->rdkey;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        return 0;
+    }
+
+    return val;
+}
+
+static void allwinner_h3_sid_write(void *opaque, hwaddr offset,
+                                      uint64_t val, unsigned size)
+{
+    AwH3SidState *s = (AwH3SidState *)opaque;
+
+    switch (offset) {
+    case REG_PRCTL:    /* Control */
+        s->control = val & ~(REG_PRCTL_WRITE);
+        if (!(s->control & REG_PRCTL_OP_LOCK)) {
+            uint32_t id = (s->control >> 16) / sizeof(uint32_t);
+            if (id < AW_H3_SID_NUM_IDS) {
+                s->rdkey = s->identifier[id];
+            }
+        }
+        break;
+    case REG_RDKEY:    /* Read Key */
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write offset 0x%04x\n",
+                      __func__, (uint32_t)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps allwinner_h3_sid_ops = {
+    .read = allwinner_h3_sid_read,
+    .write = allwinner_h3_sid_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+        .unaligned = false
+    }
+};
+
+static void allwinner_h3_sid_reset(DeviceState *dev)
+{
+    AwH3SidState *s = AW_H3_SID(dev);
+    Error *err = NULL;
+
+    /* Set default values for registers */
+    s->control = 0;
+    s->rdkey = 0;
+
+    /* Initialize identifier data */
+    for (int i = 0; i < AW_H3_SID_NUM_IDS; i++) {
+        s->identifier[i] = 0;
+    }
+
+    if (qemu_guest_getrandom(s->identifier, sizeof(s->identifier), &err)) {
+        error_report_err(err);
+    }
+}
+
+static void allwinner_h3_sid_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static void allwinner_h3_sid_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    AwH3SidState *s = AW_H3_SID(obj);
+
+    /* Memory mapping */
+    memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_sid_ops, s,
+                          TYPE_AW_H3_SID, AW_H3_SID_REGS_MEM_SIZE);
+    sysbus_init_mmio(sbd, &s->iomem);
+}
+
+static const VMStateDescription allwinner_h3_sid_vmstate = {
+    .name = TYPE_AW_H3_SID,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(control, AwH3SidState),
+        VMSTATE_UINT32(rdkey, AwH3SidState),
+        VMSTATE_UINT32_ARRAY(identifier, AwH3SidState, AW_H3_SID_NUM_IDS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void allwinner_h3_sid_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = allwinner_h3_sid_reset;
+    dc->realize = allwinner_h3_sid_realize;
+    dc->vmsd = &allwinner_h3_sid_vmstate;
+}
+
+static const TypeInfo allwinner_h3_sid_info = {
+    .name          = TYPE_AW_H3_SID,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_init = allwinner_h3_sid_init,
+    .instance_size = sizeof(AwH3SidState),
+    .class_init    = allwinner_h3_sid_class_init,
+};
+
+static void allwinner_h3_sid_register(void)
+{
+    type_register_static(&allwinner_h3_sid_info);
+}
+
+type_init(allwinner_h3_sid_register)
diff --git a/hw/misc/trace-events b/hw/misc/trace-events
index 1deb1d08c1..5d8a95816a 100644
--- a/hw/misc/trace-events
+++ b/hw/misc/trace-events
@@ -1,5 +1,10 @@ 
 # See docs/devel/tracing.txt for syntax documentation.
 
+# allwinner-h3-cpucfg.c
+allwinner_h3_cpucfg_cpu_reset(uint8_t cpu_id, uint32_t reset_addr) "H3-CPUCFG: cpu_reset: id %u, reset_addr 0x%08x"
+allwinner_h3_cpucfg_read(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+allwinner_h3_cpucfg_write(uint64_t offset, uint64_t data, unsigned size) "H3-CPUCFG: write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
+
 # eccmemctl.c
 ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x"
 ecc_mem_writel_mdr(uint32_t val) "Write memory delay 0x%08x"
diff --git a/include/hw/arm/allwinner-h3.h b/include/hw/arm/allwinner-h3.h
index 374061b550..33602599eb 100644
--- a/include/hw/arm/allwinner-h3.h
+++ b/include/hw/arm/allwinner-h3.h
@@ -29,6 +29,7 @@ 
 #include "hw/misc/allwinner-h3-clk.h"
 #include "hw/misc/allwinner-h3-cpucfg.h"
 #include "hw/misc/allwinner-h3-syscon.h"
+#include "hw/misc/allwinner-h3-sid.h"
 #include "target/arm/cpu.h"
 
 #define AW_H3_SRAM_A1_BASE     (0x00000000)
@@ -115,6 +116,7 @@  typedef struct AwH3State {
     AwH3ClockState ccu;
     AwH3CpuCfgState cpucfg;
     AwH3SysconState syscon;
+    AwH3SidState sid;
     GICState gic;
     MemoryRegion sram_a1;
     MemoryRegion sram_a2;
diff --git a/include/hw/misc/allwinner-h3-sid.h b/include/hw/misc/allwinner-h3-sid.h
new file mode 100644
index 0000000000..359cc86dfc
--- /dev/null
+++ b/include/hw/misc/allwinner-h3-sid.h
@@ -0,0 +1,42 @@ 
+/*
+ * Allwinner H3 Security ID emulation
+ *
+ * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_MISC_ALLWINNER_H3_SID_H
+#define HW_MISC_ALLWINNER_H3_SID_H
+
+#include "hw/sysbus.h"
+
+#define AW_H3_SID_NUM_IDS        (4)
+#define AW_H3_SID_REGS_MEM_SIZE  (1024)
+
+#define TYPE_AW_H3_SID    "allwinner-h3-sid"
+#define AW_H3_SID(obj)    OBJECT_CHECK(AwH3SidState, (obj), TYPE_AW_H3_SID)
+
+typedef struct AwH3SidState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+
+    MemoryRegion iomem;
+    uint32_t control;
+    uint32_t rdkey;
+    uint32_t identifier[AW_H3_SID_NUM_IDS];
+} AwH3SidState;
+
+#endif