Rename and move gpiobus_alloc_ivars() and gpiobus_free_ivars() so they can

be used on non FDT systems.

This prevents access to uninitialized memory on drivers that try to access
pin flags on non FDT systems.
This commit is contained in:
Luiz Otavio O Souza 2015-02-28 20:02:41 +00:00
parent 4fc4286fbc
commit 5019630122
3 changed files with 47 additions and 48 deletions

View File

@ -195,6 +195,39 @@ gpiobus_init_softc(device_t dev)
return (0);
}
int
gpiobus_alloc_ivars(struct gpiobus_ivar *devi)
{
/* Allocate pins and flags memory. */
devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF,
M_NOWAIT | M_ZERO);
if (devi->pins == NULL)
return (ENOMEM);
devi->flags = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF,
M_NOWAIT | M_ZERO);
if (devi->flags == NULL) {
free(devi->pins, M_DEVBUF);
return (ENOMEM);
}
return (0);
}
void
gpiobus_free_ivars(struct gpiobus_ivar *devi)
{
if (devi->flags) {
free(devi->flags, M_DEVBUF);
devi->flags = NULL;
}
if (devi->pins) {
free(devi->pins, M_DEVBUF);
devi->pins = NULL;
}
}
static int
gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
{
@ -206,29 +239,23 @@ gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
if (mask & (1 << i))
npins++;
}
if (npins == 0) {
device_printf(child, "empty pin mask\n");
return (EINVAL);
}
devi->npins = npins;
devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF,
M_NOWAIT | M_ZERO);
if (!devi->pins)
return (ENOMEM);
if (gpiobus_alloc_ivars(devi) != 0) {
device_printf(child, "cannot allocate device ivars\n");
return (EINVAL);
}
npins = 0;
for (i = 0; i < 32; i++) {
if ((mask & (1 << i)) == 0)
continue;
if (i >= sc->sc_npins) {
device_printf(child,
"invalid pin %d, max: %d\n", i, sc->sc_npins - 1);
free(devi->pins, M_DEVBUF);
gpiobus_free_ivars(devi);
return (EINVAL);
}
@ -239,7 +266,7 @@ gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
if (sc->sc_pins_mapped[i]) {
device_printf(child,
"warning: pin %d is already mapped\n", i);
free(devi->pins, M_DEVBUF);
gpiobus_free_ivars(devi);
return (EINVAL);
}
sc->sc_pins_mapped[i] = 1;
@ -299,10 +326,7 @@ gpiobus_detach(device_t dev)
for (i = 0; i < ndevs; i++) {
device_delete_child(dev, devlist[i]);
devi = GPIOBUS_IVAR(devlist[i]);
if (devi->pins) {
free(devi->pins, M_DEVBUF);
devi->pins = NULL;
}
gpiobus_free_ivars(devi);
}
free(devlist, M_TEMP);

View File

@ -100,6 +100,8 @@ int gpio_check_flags(uint32_t, uint32_t);
device_t gpiobus_attach_bus(device_t);
int gpiobus_detach_bus(device_t);
int gpiobus_init_softc(device_t);
int gpiobus_alloc_ivars(struct gpiobus_ivar *);
void gpiobus_free_ivars(struct gpiobus_ivar *);
extern driver_t gpiobus_driver;

View File

@ -69,33 +69,6 @@ ofw_gpiobus_add_fdt_child(device_t bus, phandle_t child)
return (childdev);
}
static int
ofw_gpiobus_alloc_ivars(struct gpiobus_ivar *dinfo)
{
/* Allocate pins and flags memory. */
dinfo->pins = malloc(sizeof(uint32_t) * dinfo->npins, M_DEVBUF,
M_NOWAIT | M_ZERO);
if (dinfo->pins == NULL)
return (ENOMEM);
dinfo->flags = malloc(sizeof(uint32_t) * dinfo->npins, M_DEVBUF,
M_NOWAIT | M_ZERO);
if (dinfo->flags == NULL) {
free(dinfo->pins, M_DEVBUF);
return (ENOMEM);
}
return (0);
}
static void
ofw_gpiobus_free_ivars(struct gpiobus_ivar *dinfo)
{
free(dinfo->flags, M_DEVBUF);
free(dinfo->pins, M_DEVBUF);
}
static int
ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
phandle_t child)
@ -152,7 +125,7 @@ ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
}
/* Allocate the child resources. */
if (ofw_gpiobus_alloc_ivars(dinfo) != 0) {
if (gpiobus_alloc_ivars(dinfo) != 0) {
free(gpios, M_DEVBUF);
return (ENOMEM);
}
@ -172,7 +145,7 @@ ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
/* Read gpio-cells property for this GPIO controller. */
if (OF_getencprop(gpio, "#gpio-cells", &cells,
sizeof(cells)) < 0) {
ofw_gpiobus_free_ivars(dinfo);
gpiobus_free_ivars(dinfo);
free(gpios, M_DEVBUF);
return (EINVAL);
}
@ -180,7 +153,7 @@ ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
/* Get the GPIO pin number and flags. */
if (gpio_map_gpios(sc->sc_dev, child, gpio, cells,
&gpios[i + 1], &dinfo->pins[j], &dinfo->flags[j]) != 0) {
ofw_gpiobus_free_ivars(dinfo);
gpiobus_free_ivars(dinfo);
free(gpios, M_DEVBUF);
return (EINVAL);
}
@ -190,7 +163,7 @@ ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
device_printf(sc->sc_busdev,
"invalid pin %d, max: %d\n",
dinfo->pins[j], sc->sc_npins - 1);
ofw_gpiobus_free_ivars(dinfo);
gpiobus_free_ivars(dinfo);
free(gpios, M_DEVBUF);
return (EINVAL);
}
@ -202,7 +175,7 @@ ofw_gpiobus_parse_gpios(struct gpiobus_softc *sc, struct gpiobus_ivar *dinfo,
device_printf(sc->sc_busdev,
"warning: pin %d is already mapped\n",
dinfo->pins[j]);
ofw_gpiobus_free_ivars(dinfo);
gpiobus_free_ivars(dinfo);
free(gpios, M_DEVBUF);
return (EINVAL);
}