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