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>
This commit is contained in:
parent
1fce1ba985
commit
09aa3bf382
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user