diff mbox series

[3/3] hw/misc: Implement mailbox properties for customer OTP and device specific private keys

Message ID 20240510141010.656561-4-rayhan.faizel@gmail.com
State New
Headers show
Series Initial support for One-Time Programmable Memory (OTP) in BCM2835 | expand

Commit Message

Rayhan Faizel May 10, 2024, 2:10 p.m. UTC
Four mailbox properties are implemented as follows:
1. Customer OTP: GET_CUSTOMER_OTP and SET_CUSTOMER_OTP
2. Device-specific private key: GET_PRIVATE_KEY and
SET_PRIVATE_KEY.

The customer OTP is located in the rows 36-43. The device-specific private key
is located in the rows 56-63.

The customer OTP can be locked with the magic numbers 0xffffffff 0xaffe0000
when running the SET_CUSTOMER_OTP mailbox command.

P.S I am not sure if the magic lock combo applies to the private key as well.

Signed-off-by: Rayhan Faizel <rayhan.faizel@gmail.com>
---
 hw/arm/bcm2835_peripherals.c         |  2 +
 hw/misc/bcm2835_property.c           | 71 ++++++++++++++++++++++++++++
 include/hw/arm/raspberrypi-fw-defs.h |  2 +
 include/hw/misc/bcm2835_property.h   |  2 +
 4 files changed, 77 insertions(+)

Comments

Philippe Mathieu-Daudé May 13, 2024, 1:51 p.m. UTC | #1
On 10/5/24 16:10, Rayhan Faizel wrote:
> Four mailbox properties are implemented as follows:
> 1. Customer OTP: GET_CUSTOMER_OTP and SET_CUSTOMER_OTP
> 2. Device-specific private key: GET_PRIVATE_KEY and
> SET_PRIVATE_KEY.
> 
> The customer OTP is located in the rows 36-43. The device-specific private key
> is located in the rows 56-63.

Better to define these instead of using magic values in the code,
i.e.:

   #define OTP_PRIVATE_KEY_OFFSET 56
   #define OTP_PRIVATE_KEY_LENGTH 8

> The customer OTP can be locked with the magic numbers 0xffffffff 0xaffe0000
> when running the SET_CUSTOMER_OTP mailbox command.
> 
> P.S I am not sure if the magic lock combo applies to the private key as well.
> 
> Signed-off-by: Rayhan Faizel <rayhan.faizel@gmail.com>
> ---
>   hw/arm/bcm2835_peripherals.c         |  2 +
>   hw/misc/bcm2835_property.c           | 71 ++++++++++++++++++++++++++++
>   include/hw/arm/raspberrypi-fw-defs.h |  2 +
>   include/hw/misc/bcm2835_property.h   |  2 +
>   4 files changed, 77 insertions(+)


> +        /* Device-specific private key */
> +
> +        case RPI_FWREQ_GET_PRIVATE_KEY:
> +            start_num = ldl_le_phys(&s->dma_as, value + 12);
> +            number = ldl_le_phys(&s->dma_as, value + 16);
> +
> +            resplen = 8 + 4 * number;
> +
> +            for (n = start_num; n < start_num + number && n < 8; n++) {
> +                stl_le_phys(&s->dma_as,
> +                            value + 20 + ((n - start_num) << 2),
> +                            bcm2835_otp_read_row(s->otp, 56 + n));
> +            }
> +            break;
> +        case RPI_FWREQ_SET_PRIVATE_KEY:
> +            start_num = ldl_le_phys(&s->dma_as, value + 12);
> +            number = ldl_le_phys(&s->dma_as, value + 16);
> +
> +            resplen = 4;
> +
> +            for (n = start_num; n < start_num + number && n < 8; n++) {
> +                otp_row = ldl_le_phys(&s->dma_as,
> +                                      value + 20 + ((n - start_num) << 2));
> +                bcm2835_otp_write_row(s->otp, 56 + n, otp_row);
> +            }
> +            break;
diff mbox series

Patch

diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c
index 7d735bb56c..ac153a96b9 100644
--- a/hw/arm/bcm2835_peripherals.c
+++ b/hw/arm/bcm2835_peripherals.c
@@ -132,6 +132,8 @@  static void raspi_peripherals_base_init(Object *obj)
                                    OBJECT(&s->fb));
     object_property_add_const_link(OBJECT(&s->property), "dma-mr",
                                    OBJECT(&s->gpu_bus_mr));
+    object_property_add_const_link(OBJECT(&s->property), "otp",
+                                   OBJECT(&s->otp));
 
     /* Extended Mass Media Controller */
     object_initialize_child(obj, "sdhci", &s->sdhci, TYPE_SYSBUS_SDHCI);
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index bdd9a6bbce..bbd9c40af2 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -32,6 +32,7 @@  static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
     uint32_t tmp;
     int n;
     uint32_t offset, length, color;
+    uint32_t start_num, number, otp_row;
 
     /*
      * Copy the current state of the framebuffer config; we will update
@@ -322,6 +323,73 @@  static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
                         0);
             resplen = VCHI_BUSADDR_SIZE;
             break;
+
+        /* Customer OTP */
+
+        case RPI_FWREQ_GET_CUSTOMER_OTP:
+            start_num = ldl_le_phys(&s->dma_as, value + 12);
+            number = ldl_le_phys(&s->dma_as, value + 16);
+
+            resplen = 8 + 4 * number;
+
+            for (n = start_num; n < start_num + number && n < 8; n++) {
+                stl_le_phys(&s->dma_as,
+                            value + 20 + ((n - start_num) << 2),
+                            bcm2835_otp_read_row(s->otp, 36 + n));
+            }
+            break;
+        case RPI_FWREQ_SET_CUSTOMER_OTP:
+            start_num = ldl_le_phys(&s->dma_as, value + 12);
+            number = ldl_le_phys(&s->dma_as, value + 16);
+
+            resplen = 4;
+
+            /* Magic numbers to permanently lock customer OTP */
+            if (start_num == 0xffffffff &&
+                number == 0xaffe0000) {
+                /* Row 30 Bit 30 indicates disabled OTP programming */
+                bcm2835_otp_write_row(s->otp, 30, 1 << 30);
+                break;
+            }
+
+            /* If customer OTP is locked, don't allow further writes */
+            if (bcm2835_otp_read_row(s->otp, 30) & (1 << 30)) {
+                break;
+            }
+
+            for (n = start_num; n < start_num + number && n < 8; n++) {
+                otp_row = ldl_le_phys(&s->dma_as,
+                                      value + 20 + ((n - start_num) << 2));
+                bcm2835_otp_write_row(s->otp, 36 + n, otp_row);
+            }
+            break;
+
+        /* Device-specific private key */
+
+        case RPI_FWREQ_GET_PRIVATE_KEY:
+            start_num = ldl_le_phys(&s->dma_as, value + 12);
+            number = ldl_le_phys(&s->dma_as, value + 16);
+
+            resplen = 8 + 4 * number;
+
+            for (n = start_num; n < start_num + number && n < 8; n++) {
+                stl_le_phys(&s->dma_as,
+                            value + 20 + ((n - start_num) << 2),
+                            bcm2835_otp_read_row(s->otp, 56 + n));
+            }
+            break;
+        case RPI_FWREQ_SET_PRIVATE_KEY:
+            start_num = ldl_le_phys(&s->dma_as, value + 12);
+            number = ldl_le_phys(&s->dma_as, value + 16);
+
+            resplen = 4;
+
+            for (n = start_num; n < start_num + number && n < 8; n++) {
+                otp_row = ldl_le_phys(&s->dma_as,
+                                      value + 20 + ((n - start_num) << 2));
+                bcm2835_otp_write_row(s->otp, 56 + n, otp_row);
+            }
+            break;
         default:
             qemu_log_mask(LOG_UNIMP,
                           "bcm2835_property: unhandled tag 0x%08x\n", tag);
@@ -449,6 +517,9 @@  static void bcm2835_property_realize(DeviceState *dev, Error **errp)
     s->dma_mr = MEMORY_REGION(obj);
     address_space_init(&s->dma_as, s->dma_mr, TYPE_BCM2835_PROPERTY "-memory");
 
+    obj = object_property_get_link(OBJECT(dev), "otp", &error_abort);
+    s->otp = BCM2835_OTP(obj);
+
     /* TODO: connect to MAC address of USB NIC device, once we emulate it */
     qemu_macaddr_default_if_unset(&s->macaddr);
 
diff --git a/include/hw/arm/raspberrypi-fw-defs.h b/include/hw/arm/raspberrypi-fw-defs.h
index 8b404e0533..60b8e5b451 100644
--- a/include/hw/arm/raspberrypi-fw-defs.h
+++ b/include/hw/arm/raspberrypi-fw-defs.h
@@ -56,6 +56,7 @@  enum rpi_firmware_property_tag {
     RPI_FWREQ_GET_THROTTLED =                          0x00030046,
     RPI_FWREQ_GET_CLOCK_MEASURED =                     0x00030047,
     RPI_FWREQ_NOTIFY_REBOOT =                          0x00030048,
+    RPI_FWREQ_GET_PRIVATE_KEY =                        0x00030081,
     RPI_FWREQ_SET_CLOCK_STATE =                        0x00038001,
     RPI_FWREQ_SET_CLOCK_RATE =                         0x00038002,
     RPI_FWREQ_SET_VOLTAGE =                            0x00038003,
@@ -73,6 +74,7 @@  enum rpi_firmware_property_tag {
     RPI_FWREQ_SET_PERIPH_REG =                         0x00038045,
     RPI_FWREQ_GET_POE_HAT_VAL =                        0x00030049,
     RPI_FWREQ_SET_POE_HAT_VAL =                        0x00038049,
+    RPI_FWREQ_SET_PRIVATE_KEY =                        0x00038081,
     RPI_FWREQ_SET_POE_HAT_VAL_OLD =                    0x00030050,
     RPI_FWREQ_NOTIFY_XHCI_RESET =                      0x00030058,
     RPI_FWREQ_GET_REBOOT_FLAGS =                       0x00030064,
diff --git a/include/hw/misc/bcm2835_property.h b/include/hw/misc/bcm2835_property.h
index ba8896610c..2f93fd0c75 100644
--- a/include/hw/misc/bcm2835_property.h
+++ b/include/hw/misc/bcm2835_property.h
@@ -11,6 +11,7 @@ 
 #include "hw/sysbus.h"
 #include "net/net.h"
 #include "hw/display/bcm2835_fb.h"
+#include "hw/nvram/bcm2835_otp.h"
 #include "qom/object.h"
 
 #define TYPE_BCM2835_PROPERTY "bcm2835-property"
@@ -26,6 +27,7 @@  struct BCM2835PropertyState {
     MemoryRegion iomem;
     qemu_irq mbox_irq;
     BCM2835FBState *fbdev;
+    BCM2835OTPState *otp;
 
     MACAddr macaddr;
     uint32_t board_rev;