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 irq;
|
||||||
qemu_irq out[8];
|
qemu_irq out[8];
|
||||||
const unsigned char *id;
|
const unsigned char *id;
|
||||||
|
uint32_t rsvd_start; /* reserved area: [rsvd_start, 0xfcc] */
|
||||||
} PL061State;
|
} PL061State;
|
||||||
|
|
||||||
static const VMStateDescription vmstate_pl061 = {
|
static const VMStateDescription vmstate_pl061 = {
|
||||||
|
@ -152,12 +153,15 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
||||||
{
|
{
|
||||||
PL061State *s = (PL061State *)opaque;
|
PL061State *s = (PL061State *)opaque;
|
||||||
|
|
||||||
if (offset >= 0xfd0 && offset < 0x1000) {
|
|
||||||
return s->id[(offset - 0xfd0) >> 2];
|
|
||||||
}
|
|
||||||
if (offset < 0x400) {
|
if (offset < 0x400) {
|
||||||
return s->data & (offset >> 2);
|
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) {
|
switch (offset) {
|
||||||
case 0x400: /* Direction */
|
case 0x400: /* Direction */
|
||||||
return s->dir;
|
return s->dir;
|
||||||
|
@ -198,10 +202,12 @@ static uint64_t pl061_read(void *opaque, hwaddr offset,
|
||||||
case 0x528: /* Analog mode select */
|
case 0x528: /* Analog mode select */
|
||||||
return s->amsel;
|
return s->amsel;
|
||||||
default:
|
default:
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
break;
|
||||||
"pl061_read: Bad offset %x\n", (int)offset);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
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,
|
static void pl061_write(void *opaque, hwaddr offset,
|
||||||
|
@ -216,6 +222,9 @@ static void pl061_write(void *opaque, hwaddr offset,
|
||||||
pl061_update(s);
|
pl061_update(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (offset >= s->rsvd_start) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
switch (offset) {
|
switch (offset) {
|
||||||
case 0x400: /* Direction */
|
case 0x400: /* Direction */
|
||||||
s->dir = value & 0xff;
|
s->dir = value & 0xff;
|
||||||
|
@ -274,10 +283,13 @@ static void pl061_write(void *opaque, hwaddr offset,
|
||||||
s->amsel = value & 0xff;
|
s->amsel = value & 0xff;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
goto err_out;
|
||||||
"pl061_write: Bad offset %x\n", (int)offset);
|
|
||||||
}
|
}
|
||||||
pl061_update(s);
|
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)
|
static void pl061_reset(DeviceState *dev)
|
||||||
|
@ -347,6 +359,7 @@ static void pl061_luminary_init(Object *obj)
|
||||||
PL061State *s = PL061(obj);
|
PL061State *s = PL061(obj);
|
||||||
|
|
||||||
s->id = pl061_id_luminary;
|
s->id = pl061_id_luminary;
|
||||||
|
s->rsvd_start = 0x52c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl061_init(Object *obj)
|
static void pl061_init(Object *obj)
|
||||||
|
@ -354,6 +367,7 @@ static void pl061_init(Object *obj)
|
||||||
PL061State *s = PL061(obj);
|
PL061State *s = PL061(obj);
|
||||||
|
|
||||||
s->id = pl061_id;
|
s->id = pl061_id;
|
||||||
|
s->rsvd_start = 0x424;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl061_class_init(ObjectClass *klass, void *data)
|
static void pl061_class_init(ObjectClass *klass, void *data)
|
||||||
|
|
Loading…
Reference in New Issue