Skip to content

Commit 87bd33e

Browse files
peterdelevoryaslegoater
authored andcommitted
hw: aspeed_gpio: Fix GPIO array indexing
The gpio array is declared as a dense array: qemu_irq gpios[ASPEED_GPIO_NR_PINS]; (AST2500 has 228, AST2400 has 216, AST2600 has 208) However, this array is used like a matrix of GPIO sets (e.g. gpio[NR_SETS][NR_PINS_PER_SET] = gpio[8][32]) size_t offset = set * GPIOS_PER_SET + gpio; qemu_set_irq(s->gpios[offset], !!(new & mask)); This can result in an out-of-bounds access to "s->gpios" because the gpio sets do _not_ have the same length. Some of the groups (e.g. GPIOAB) only have 4 pins. 228 != 8 * 32 == 256. To fix this, I converted the gpio array from dense to sparse, to that match both the hardware layout and this existing indexing code. Fixes: 4b7f956 ("hw/gpio: Add basic Aspeed GPIO model for AST2400 and AST2500") Signed-off-by: Peter Delevoryas <[email protected]> Message-Id: <[email protected]> Signed-off-by: Cédric Le Goater <[email protected]>
1 parent 9fffe14 commit 87bd33e

File tree

2 files changed

+35
-50
lines changed

2 files changed

+35
-50
lines changed

hw/gpio/aspeed_gpio.c

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@
1616
#include "hw/irq.h"
1717
#include "migration/vmstate.h"
1818

19-
#define GPIOS_PER_REG 32
20-
#define GPIOS_PER_SET GPIOS_PER_REG
21-
#define GPIO_PIN_GAP_SIZE 4
2219
#define GPIOS_PER_GROUP 8
23-
#define GPIO_GROUP_SHIFT 3
2420

2521
/* GPIO Source Types */
2622
#define ASPEED_CMD_SRC_MASK 0x01010101
@@ -259,7 +255,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
259255

260256
diff = old ^ new;
261257
if (diff) {
262-
for (gpio = 0; gpio < GPIOS_PER_REG; gpio++) {
258+
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
263259
uint32_t mask = 1 << gpio;
264260

265261
/* If the gpio needs to be updated... */
@@ -283,8 +279,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
283279
if (direction & mask) {
284280
/* ...trigger the line-state IRQ */
285281
ptrdiff_t set = aspeed_gpio_set_idx(s, regs);
286-
size_t offset = set * GPIOS_PER_SET + gpio;
287-
qemu_set_irq(s->gpios[offset], !!(new & mask));
282+
qemu_set_irq(s->gpios[set][gpio], !!(new & mask));
288283
} else {
289284
/* ...otherwise if we meet the line's current IRQ policy... */
290285
if (aspeed_evaluate_irq(regs, old & mask, gpio)) {
@@ -297,21 +292,6 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
297292
qemu_set_irq(s->irq, !!(s->pending));
298293
}
299294

300-
static uint32_t aspeed_adjust_pin(AspeedGPIOState *s, uint32_t pin)
301-
{
302-
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
303-
/*
304-
* The 2500 has a 4 pin gap in group AB and the 2400 has a 4 pin
305-
* gap in group Y (and only four pins in AB but this is the last group so
306-
* it doesn't matter).
307-
*/
308-
if (agc->gap && pin >= agc->gap) {
309-
pin += GPIO_PIN_GAP_SIZE;
310-
}
311-
312-
return pin;
313-
}
314-
315295
static bool aspeed_gpio_get_pin_level(AspeedGPIOState *s, uint32_t set_idx,
316296
uint32_t pin)
317297
{
@@ -367,7 +347,7 @@ static uint32_t update_value_control_source(GPIOSets *regs, uint32_t old_value,
367347
uint32_t new_value = 0;
368348

369349
/* for each group in set */
370-
for (i = 0; i < GPIOS_PER_REG; i += GPIOS_PER_GROUP) {
350+
for (i = 0; i < ASPEED_GPIOS_PER_SET; i += GPIOS_PER_GROUP) {
371351
cmd_source = extract32(regs->cmd_source_0, i, 1)
372352
| (extract32(regs->cmd_source_1, i, 1) << 1);
373353

@@ -637,7 +617,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
637617
* bidirectional | 1 | 1 | data
638618
* input only | 1 | 0 | 0
639619
* output only | 0 | 1 | 1
640-
* no pin / gap | 0 | 0 | 0
620+
* no pin | 0 | 0 | 0
641621
*
642622
* which is captured by:
643623
* data = ( data | ~input) & output;
@@ -779,7 +759,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
779759
}
780760

781761
/****************** Setup functions ******************/
782-
static const GPIOSetProperties ast2400_set_props[] = {
762+
static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
783763
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
784764
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
785765
[2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
@@ -789,7 +769,7 @@ static const GPIOSetProperties ast2400_set_props[] = {
789769
[6] = {0x0000000f, 0x0fffff0f, {"Y", "Z", "AA", "AB"} },
790770
};
791771

792-
static const GPIOSetProperties ast2500_set_props[] = {
772+
static const GPIOSetProperties ast2500_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
793773
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
794774
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
795775
[2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
@@ -800,7 +780,7 @@ static const GPIOSetProperties ast2500_set_props[] = {
800780
[7] = {0x000000ff, 0x000000ff, {"AC"} },
801781
};
802782

803-
static GPIOSetProperties ast2600_3_3v_set_props[] = {
783+
static GPIOSetProperties ast2600_3_3v_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
804784
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
805785
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
806786
[2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
@@ -810,7 +790,7 @@ static GPIOSetProperties ast2600_3_3v_set_props[] = {
810790
[6] = {0x0000ffff, 0x0000ffff, {"Y", "Z"} },
811791
};
812792

813-
static GPIOSetProperties ast2600_1_8v_set_props[] = {
793+
static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
814794
[0] = {0xffffffff, 0xffffffff, {"18A", "18B", "18C", "18D"} },
815795
[1] = {0x0000000f, 0x0000000f, {"18E"} },
816796
};
@@ -836,14 +816,20 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp)
836816
AspeedGPIOState *s = ASPEED_GPIO(dev);
837817
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
838818
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
839-
int pin;
840819

841820
/* Interrupt parent line */
842821
sysbus_init_irq(sbd, &s->irq);
843822

844823
/* Individual GPIOs */
845-
for (pin = 0; pin < agc->nr_gpio_pins; pin++) {
846-
sysbus_init_irq(sbd, &s->gpios[pin]);
824+
for (int i = 0; i < ASPEED_GPIO_MAX_NR_SETS; i++) {
825+
const GPIOSetProperties *props = &agc->props[i];
826+
uint32_t skip = ~(props->input | props->output);
827+
for (int j = 0; j < ASPEED_GPIOS_PER_SET; j++) {
828+
if (skip >> j & 1) {
829+
continue;
830+
}
831+
sysbus_init_irq(sbd, &s->gpios[i][j]);
832+
}
847833
}
848834

849835
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
@@ -856,20 +842,22 @@ static void aspeed_gpio_init(Object *obj)
856842
{
857843
AspeedGPIOState *s = ASPEED_GPIO(obj);
858844
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
859-
int pin;
860-
861-
for (pin = 0; pin < agc->nr_gpio_pins; pin++) {
862-
char *name;
863-
int set_idx = pin / GPIOS_PER_SET;
864-
int pin_idx = aspeed_adjust_pin(s, pin) - (set_idx * GPIOS_PER_SET);
865-
int group_idx = pin_idx >> GPIO_GROUP_SHIFT;
866-
const GPIOSetProperties *props = &agc->props[set_idx];
867-
868-
name = g_strdup_printf("gpio%s%d", props->group_label[group_idx],
869-
pin_idx % GPIOS_PER_GROUP);
870-
object_property_add(obj, name, "bool", aspeed_gpio_get_pin,
871-
aspeed_gpio_set_pin, NULL, NULL);
872-
g_free(name);
845+
846+
for (int i = 0; i < ASPEED_GPIO_MAX_NR_SETS; i++) {
847+
const GPIOSetProperties *props = &agc->props[i];
848+
uint32_t skip = ~(props->input | props->output);
849+
for (int j = 0; j < ASPEED_GPIOS_PER_SET; j++) {
850+
if (skip >> j & 1) {
851+
continue;
852+
}
853+
int group_idx = j / GPIOS_PER_GROUP;
854+
int pin_idx = j % GPIOS_PER_GROUP;
855+
const char *group = &props->group_label[group_idx][0];
856+
char *name = g_strdup_printf("gpio%s%d", group, pin_idx);
857+
object_property_add(obj, name, "bool", aspeed_gpio_get_pin,
858+
aspeed_gpio_set_pin, NULL, NULL);
859+
g_free(name);
860+
}
873861
}
874862
}
875863

@@ -926,7 +914,6 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data)
926914
agc->props = ast2400_set_props;
927915
agc->nr_gpio_pins = 216;
928916
agc->nr_gpio_sets = 7;
929-
agc->gap = 196;
930917
agc->reg_table = aspeed_3_3v_gpios;
931918
}
932919

@@ -937,7 +924,6 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
937924
agc->props = ast2500_set_props;
938925
agc->nr_gpio_pins = 228;
939926
agc->nr_gpio_sets = 8;
940-
agc->gap = 220;
941927
agc->reg_table = aspeed_3_3v_gpios;
942928
}
943929

include/hw/gpio/aspeed_gpio.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
OBJECT_DECLARE_TYPE(AspeedGPIOState, AspeedGPIOClass, ASPEED_GPIO)
1818

1919
#define ASPEED_GPIO_MAX_NR_SETS 8
20+
#define ASPEED_GPIOS_PER_SET 32
2021
#define ASPEED_REGS_PER_BANK 14
2122
#define ASPEED_GPIO_MAX_NR_REGS (ASPEED_REGS_PER_BANK * ASPEED_GPIO_MAX_NR_SETS)
22-
#define ASPEED_GPIO_NR_PINS 228
2323
#define ASPEED_GROUPS_PER_SET 4
2424
#define ASPEED_GPIO_NR_DEBOUNCE_REGS 3
2525
#define ASPEED_CHARS_PER_GROUP_LABEL 4
@@ -60,7 +60,6 @@ struct AspeedGPIOClass {
6060
const GPIOSetProperties *props;
6161
uint32_t nr_gpio_pins;
6262
uint32_t nr_gpio_sets;
63-
uint32_t gap;
6463
const AspeedGPIOReg *reg_table;
6564
};
6665

@@ -72,7 +71,7 @@ struct AspeedGPIOState {
7271
MemoryRegion iomem;
7372
int pending;
7473
qemu_irq irq;
75-
qemu_irq gpios[ASPEED_GPIO_NR_PINS];
74+
qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
7675

7776
/* Parallel GPIO Registers */
7877
uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];

0 commit comments

Comments
 (0)