diff options
author | Wei Huang <wei@redhat.com> | 2016-02-18 11:56:20 -0500 |
---|---|---|
committer | Timothy Pearson <tpearson@raptorengineering.com> | 2019-11-29 19:46:49 -0600 |
commit | 4ce077d351b87c86dbb4eacb4ad632903c3a5df8 (patch) | |
tree | 1516239213774cfdbb9dc8b15a47d065f9e2daa2 /hw/gpio | |
parent | 9b3f9cf86d27e6dfff92196c793112f33727aa7b (diff) | |
download | hqemu-4ce077d351b87c86dbb4eacb4ad632903c3a5df8.zip hqemu-4ce077d351b87c86dbb4eacb4ad632903c3a5df8.tar.gz |
ARM: PL061: Checking register r/w accesses to reserved area
pl061.c emulates two GPIO devices, ARM PL061 and TI Stellaris, which
share the same read/write functions (pl061_read and pl061_write).
However PL061 and Stellaris have different GPIO register definitions
and pl061_read()/pl061_write() doesn't check it. This patch enforces
checking on offset, preventing R/W into the reserved memory area.
Signed-off-by: Wei Huang <wei@redhat.com>
Message-id: 1455814580-17699-1-git-send-email-wei@redhat.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/gpio')
-rw-r--r-- | hw/gpio/pl061.c | 30 |
1 files changed, 22 insertions, 8 deletions
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 5ece8b0..29dc7fc 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -60,6 +60,7 @@ typedef struct PL061State { qemu_irq irq; qemu_irq out[8]; const unsigned char *id; + uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */ } PL061State; static const VMStateDescription vmstate_pl061 = { @@ -152,12 +153,15 @@ static uint64_t pl061_read(void *opaque, hwaddr offset, { PL061State *s = (PL061State *)opaque; - if (offset >= 0xfd0 && offset < 0x1000) { - return s->id[(offset - 0xfd0) >> 2]; - } if (offset < 0x400) { return s->data & (offset >> 2); } + if (offset >= s->rsvd_start && offset <= 0xfcc) { + goto err_out; + } + if (offset >= 0xfd0 && offset < 0x1000) { + return s->id[(offset - 0xfd0) >> 2]; + } switch (offset) { case 0x400: /* Direction */ return s->dir; @@ -198,10 +202,12 @@ static uint64_t pl061_read(void *opaque, hwaddr offset, case 0x528: /* Analog mode select */ return s->amsel; default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl061_read: Bad offset %x\n", (int)offset); - return 0; + break; } +err_out: + qemu_log_mask(LOG_GUEST_ERROR, + "pl061_read: Bad offset %x\n", (int)offset); + return 0; } static void pl061_write(void *opaque, hwaddr offset, @@ -216,6 +222,9 @@ static void pl061_write(void *opaque, hwaddr offset, pl061_update(s); return; } + if (offset >= s->rsvd_start) { + goto err_out; + } switch (offset) { case 0x400: /* Direction */ s->dir = value & 0xff; @@ -274,10 +283,13 @@ static void pl061_write(void *opaque, hwaddr offset, s->amsel = value & 0xff; break; default: - qemu_log_mask(LOG_GUEST_ERROR, - "pl061_write: Bad offset %x\n", (int)offset); + goto err_out; } pl061_update(s); + return; +err_out: + qemu_log_mask(LOG_GUEST_ERROR, + "pl061_write: Bad offset %x\n", (int)offset); } static void pl061_reset(DeviceState *dev) @@ -347,6 +359,7 @@ static void pl061_luminary_init(Object *obj) PL061State *s = PL061(obj); s->id = pl061_id_luminary; + s->rsvd_start = 0x52c; } static void pl061_init(Object *obj) @@ -354,6 +367,7 @@ static void pl061_init(Object *obj) PL061State *s = PL061(obj); s->id = pl061_id; + s->rsvd_start = 0x424; } static void pl061_class_init(ObjectClass *klass, void *data) |