Skip to content

Commit

Permalink
pinctrl: stm32: prevent the use of the secure protected pins
Browse files Browse the repository at this point in the history
The hardware denies any access from the Linux non-secure world to the
secure-protected pins. Hence, prevent any driver to request such a pin.

Mark the secure-protected GPIO lines as invalid (.init_valid_mask) and
prevent the pinmux request / pinconf setting operations.
Identify the secure pins with "NO ACCESS" in the pinconf sysfs.

Signed-off-by: Fabien Dessenne <fabien.dessenne@foss.st.com>
  • Loading branch information
Fabien Dessenne authored and intel-lab-lkp committed May 2, 2022
1 parent 1a43e9b commit 3953474
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 0 deletions.
64 changes: 64 additions & 0 deletions drivers/pinctrl/stm32/pinctrl-stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#define STM32_GPIO_LCKR 0x1c
#define STM32_GPIO_AFRL 0x20
#define STM32_GPIO_AFRH 0x24
#define STM32_GPIO_SECCFGR 0x30

/* custom bitfield to backup pin status */
#define STM32_GPIO_BKP_MODE_SHIFT 0
Expand Down Expand Up @@ -94,6 +95,7 @@ struct stm32_gpio_bank {
u32 bank_ioport_nr;
u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
u8 irq_type[STM32_GPIO_PINS_PER_BANK];
bool secure_control;
};

struct stm32_pinctrl {
Expand Down Expand Up @@ -294,6 +296,33 @@ static int stm32_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
return ret;
}

static int stm32_gpio_init_valid_mask(struct gpio_chip *chip,
unsigned long *valid_mask,
unsigned int ngpios)
{
struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent);
unsigned int i;
u32 sec;

/* All gpio are valid per default */
bitmap_fill(valid_mask, ngpios);

if (bank->secure_control) {
/* Tag secured pins as invalid */
sec = readl_relaxed(bank->base + STM32_GPIO_SECCFGR);

for (i = 0; i < ngpios; i++) {
if (sec & BIT(i)) {
clear_bit(i, valid_mask);
dev_dbg(pctl->dev, "No access to gpio %d - %d\n", bank->bank_nr, i);
}
}
}

return 0;
}

static const struct gpio_chip stm32_gpio_template = {
.request = stm32_gpio_request,
.free = stm32_gpio_free,
Expand All @@ -304,6 +333,7 @@ static const struct gpio_chip stm32_gpio_template = {
.to_irq = stm32_gpio_to_irq,
.get_direction = stm32_gpio_get_direction,
.set_config = gpiochip_generic_config,
.init_valid_mask = stm32_gpio_init_valid_mask,
};

static void stm32_gpio_irq_trigger(struct irq_data *d)
Expand Down Expand Up @@ -848,12 +878,32 @@ static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
return stm32_pmx_set_mode(bank, pin, !input, 0);
}

static int stm32_pmx_request(struct pinctrl_dev *pctldev, unsigned int gpio)
{
struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
struct pinctrl_gpio_range *range;

range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, gpio);
if (!range) {
dev_err(pctl->dev, "No gpio range defined.\n");
return -EINVAL;
}

if (!gpiochip_line_is_valid(range->gc, stm32_gpio_pin(gpio))) {
dev_warn(pctl->dev, "Can't access gpio %d\n", gpio);
return -EACCES;
}

return 0;
}

static const struct pinmux_ops stm32_pmx_ops = {
.get_functions_count = stm32_pmx_get_funcs_cnt,
.get_function_name = stm32_pmx_get_func_name,
.get_function_groups = stm32_pmx_get_func_groups,
.set_mux = stm32_pmx_set_mux,
.gpio_set_direction = stm32_pmx_gpio_set_direction,
.request = stm32_pmx_request,
.strict = true,
};

Expand Down Expand Up @@ -1064,6 +1114,11 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev,
bank = gpiochip_get_data(range->gc);
offset = stm32_gpio_pin(pin);

if (!gpiochip_line_is_valid(range->gc, offset)) {
dev_warn(pctl->dev, "Can't access gpio %d\n", pin);
return -EACCES;
}

switch (param) {
case PIN_CONFIG_DRIVE_PUSH_PULL:
ret = stm32_pconf_set_driving(bank, offset, 0);
Expand Down Expand Up @@ -1166,6 +1221,11 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev,
bank = gpiochip_get_data(range->gc);
offset = stm32_gpio_pin(pin);

if (!gpiochip_line_is_valid(range->gc, offset)) {
seq_puts(s, "NO ACCESS");
return;
}

stm32_pmx_get_mode(bank, offset, &mode, &alt);
bias = stm32_pconf_get_bias(bank, offset);

Expand Down Expand Up @@ -1278,6 +1338,7 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl,
bank->gpio_chip.parent = dev;
bank->bank_nr = bank_nr;
bank->bank_ioport_nr = bank_ioport_nr;
bank->secure_control = pctl->match_data->secure_control;
spin_lock_init(&bank->lock);

/* create irq hierarchical domain */
Expand Down Expand Up @@ -1582,6 +1643,9 @@ static int __maybe_unused stm32_pinctrl_restore_gpio_regs(
if (!range)
return 0;

if (!gpiochip_line_is_valid(range->gc, offset))
return 0;

pin_is_irq = gpiochip_line_is_irq(range->gc, offset);

if (!desc || (!pin_is_irq && !desc->gpio_owner))
Expand Down
1 change: 1 addition & 0 deletions drivers/pinctrl/stm32/pinctrl-stm32.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct stm32_desc_pin {
struct stm32_pinctrl_match_data {
const struct stm32_desc_pin *pins;
const unsigned int npins;
bool secure_control;
};

struct stm32_gpio_bank;
Expand Down
1 change: 1 addition & 0 deletions drivers/pinctrl/stm32/pinctrl-stm32mp135.c
Original file line number Diff line number Diff line change
Expand Up @@ -1649,6 +1649,7 @@ static const struct stm32_desc_pin stm32mp135_pins[] = {
static struct stm32_pinctrl_match_data stm32mp135_match_data = {
.pins = stm32mp135_pins,
.npins = ARRAY_SIZE(stm32mp135_pins),
.secure_control = true,
};

static const struct of_device_id stm32mp135_pctrl_match[] = {
Expand Down

0 comments on commit 3953474

Please sign in to comment.