aboutsummaryrefslogtreecommitdiff
path: root/hw/misc/bcm2835_property.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/misc/bcm2835_property.c')
-rw-r--r--hw/misc/bcm2835_property.c149
1 files changed, 122 insertions, 27 deletions
diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c
index bdd9a6b..a21c6a5 100644
--- a/hw/misc/bcm2835_property.c
+++ b/hw/misc/bcm2835_property.c
@@ -13,7 +13,7 @@
#include "hw/irq.h"
#include "hw/misc/bcm2835_mbox_defs.h"
#include "hw/arm/raspberrypi-fw-defs.h"
-#include "sysemu/dma.h"
+#include "system/dma.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
@@ -25,13 +25,7 @@
static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
{
- uint32_t tag;
- uint32_t bufsize;
uint32_t tot_len;
- size_t resplen;
- uint32_t tmp;
- int n;
- uint32_t offset, length, color;
/*
* Copy the current state of the framebuffer config; we will update
@@ -50,10 +44,10 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
/* @(addr + 4) : Buffer response code */
value = s->addr + 8;
while (value + 8 <= s->addr + tot_len) {
- tag = ldl_le_phys(&s->dma_as, value);
- bufsize = ldl_le_phys(&s->dma_as, value + 4);
+ uint32_t tag = ldl_le_phys(&s->dma_as, value);
+ uint32_t bufsize = ldl_le_phys(&s->dma_as, value + 4);
/* @(value + 8) : Request/response indicator */
- resplen = 0;
+ size_t resplen = 0;
switch (tag) {
case RPI_FWREQ_PROPERTY_END:
break;
@@ -97,13 +91,16 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
resplen = 8;
break;
case RPI_FWREQ_SET_POWER_STATE:
- /* Assume that whatever device they asked for exists,
- * and we'll just claim we set it to the desired state
+ {
+ /*
+ * Assume that whatever device they asked for exists,
+ * and we'll just claim we set it to the desired state.
*/
- tmp = ldl_le_phys(&s->dma_as, value + 16);
- stl_le_phys(&s->dma_as, value + 16, (tmp & 1));
+ uint32_t state = ldl_le_phys(&s->dma_as, value + 16);
+ stl_le_phys(&s->dma_as, value + 16, (state & 1));
resplen = 8;
break;
+ }
/* Clocks */
@@ -273,19 +270,25 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
resplen = 16;
break;
case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE:
- offset = ldl_le_phys(&s->dma_as, value + 12);
- length = ldl_le_phys(&s->dma_as, value + 16);
- n = 0;
- while (n < length - offset) {
- color = ldl_le_phys(&s->dma_as, value + 20 + (n << 2));
- stl_le_phys(&s->dma_as,
- s->fbdev->vcram_base + ((offset + n) << 2), color);
- n++;
+ {
+ uint32_t offset = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t length = ldl_le_phys(&s->dma_as, value + 16);
+ int resp;
+
+ if (offset > 255 || length < 1 || length > 256) {
+ resp = 1; /* invalid request */
+ } else {
+ for (uint32_t e = 0; e < length; e++) {
+ uint32_t color = ldl_le_phys(&s->dma_as, value + 20 + (e << 2));
+ stl_le_phys(&s->dma_as,
+ s->fbdev->vcram_base + ((offset + e) << 2), color);
+ }
+ resp = 0;
}
- stl_le_phys(&s->dma_as, value + 12, 0);
+ stl_le_phys(&s->dma_as, value + 12, resp);
resplen = 4;
break;
-
+ }
case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS:
stl_le_phys(&s->dma_as, value + 12, 1);
resplen = 4;
@@ -322,6 +325,96 @@ 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:
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
+
+ resplen = 8 + 4 * number;
+
+ for (uint32_t n = start_num; n < start_num + number &&
+ n < BCM2835_OTP_CUSTOMER_OTP_LEN; n++) {
+ uint32_t otp_row = bcm2835_otp_get_row(s->otp,
+ BCM2835_OTP_CUSTOMER_OTP + n);
+ stl_le_phys(&s->dma_as,
+ value + 20 + ((n - start_num) << 2), otp_row);
+ }
+ break;
+ }
+ case RPI_FWREQ_SET_CUSTOMER_OTP:
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
+
+ resplen = 4;
+
+ /* Magic numbers to permanently lock customer OTP */
+ if (start_num == BCM2835_OTP_LOCK_NUM1 &&
+ number == BCM2835_OTP_LOCK_NUM2) {
+ bcm2835_otp_set_row(s->otp,
+ BCM2835_OTP_ROW_32,
+ BCM2835_OTP_ROW_32_LOCK);
+ break;
+ }
+
+ /* If row 32 has the lock bit, don't allow further writes */
+ if (bcm2835_otp_get_row(s->otp, BCM2835_OTP_ROW_32) &
+ BCM2835_OTP_ROW_32_LOCK) {
+ break;
+ }
+
+ for (uint32_t n = start_num; n < start_num + number &&
+ n < BCM2835_OTP_CUSTOMER_OTP_LEN; n++) {
+ uint32_t otp_row = ldl_le_phys(&s->dma_as,
+ value + 20 + ((n - start_num) << 2));
+ bcm2835_otp_set_row(s->otp,
+ BCM2835_OTP_CUSTOMER_OTP + n, otp_row);
+ }
+ break;
+ }
+
+ /* Device-specific private key */
+ case RPI_FWREQ_GET_PRIVATE_KEY:
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
+
+ resplen = 8 + 4 * number;
+
+ for (uint32_t n = start_num; n < start_num + number &&
+ n < BCM2835_OTP_PRIVATE_KEY_LEN; n++) {
+ uint32_t otp_row = bcm2835_otp_get_row(s->otp,
+ BCM2835_OTP_PRIVATE_KEY + n);
+ stl_le_phys(&s->dma_as,
+ value + 20 + ((n - start_num) << 2), otp_row);
+ }
+ break;
+ }
+ case RPI_FWREQ_SET_PRIVATE_KEY:
+ {
+ uint32_t start_num = ldl_le_phys(&s->dma_as, value + 12);
+ uint32_t number = ldl_le_phys(&s->dma_as, value + 16);
+
+ resplen = 4;
+
+ /* If row 32 has the lock bit, don't allow further writes */
+ if (bcm2835_otp_get_row(s->otp, BCM2835_OTP_ROW_32) &
+ BCM2835_OTP_ROW_32_LOCK) {
+ break;
+ }
+
+ for (uint32_t n = start_num; n < start_num + number &&
+ n < BCM2835_OTP_PRIVATE_KEY_LEN; n++) {
+ uint32_t otp_row = ldl_le_phys(&s->dma_as,
+ value + 20 + ((n - start_num) << 2));
+ bcm2835_otp_set_row(s->otp,
+ BCM2835_OTP_PRIVATE_KEY + n, otp_row);
+ }
+ break;
+ }
default:
qemu_log_mask(LOG_UNIMP,
"bcm2835_property: unhandled tag 0x%08x\n", tag);
@@ -449,19 +542,21 @@ 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);
bcm2835_property_reset(dev);
}
-static Property bcm2835_property_props[] = {
+static const Property bcm2835_property_props[] = {
DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0),
DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line),
- DEFINE_PROP_END_OF_LIST()
};
-static void bcm2835_property_class_init(ObjectClass *klass, void *data)
+static void bcm2835_property_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);