aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Vanek <vanekt@fbl.cz>2023-05-13 06:39:48 +0200
committerTomas Vanek <vanekt@fbl.cz>2023-05-24 05:27:02 +0000
commit5c46a5de49f5dd14227b9444a5815eaaadd7ceb4 (patch)
treee4f71f2e6dbe9e9ae72c44c8f7deba929f251b97
parentb41b368255d53d9561851900eeeba38b12720a82 (diff)
downloadriscv-openocd-5c46a5de49f5dd14227b9444a5815eaaadd7ceb4.zip
riscv-openocd-5c46a5de49f5dd14227b9444a5815eaaadd7ceb4.tar.gz
riscv-openocd-5c46a5de49f5dd14227b9444a5815eaaadd7ceb4.tar.bz2
jtag/drivers/bcm2835gpio: add peripheral_mem_dev config command
The bcm2835gpio driver preferred /dev/gpiomem for access to memory mapped GPIO control and used /dev/mem as a fallback only if it couldn't open /dev/gpiomem. /dev/mem usually requires elevated rights or specific capabilities of the opening process, so the fallback failed anyway. Although /dev/gpiomem is the strongly preferred option with respect to security, there could be also use cases which require /dev/mem even if /dev/gpiomem is available (e.g. changing the GPIO pad settings is necessary or testing/debugging OpenOCD). It was difficult to handle such cases because they required to block globally the system device /dev/gpiomem (remove, rename or chmod). Drop the fallback feature and select the memory device by 'bcm2835gpio peripheral_mem_dev' configuration command. Use /dev/gpiomem as a default. Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Change-Id: I60e427bda795d7a13d55d61443590dd31d694832 Reviewed-on: https://review.openocd.org/c/openocd/+/7350 Tested-by: jenkins Reviewed-by: Jonathan Bell <jonathan@raspberrypi.com>
-rw-r--r--doc/openocd.texi23
-rw-r--r--src/jtag/drivers/bcm2835gpio.c45
2 files changed, 55 insertions, 13 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index f27e17c..d0bc3f9 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -3292,10 +3292,6 @@ configuration on exit.
GPIO numbers >= 32 can't be used for performance reasons. GPIO configuration is
handled by the generic command @ref{adapter gpio, @command{adapter gpio}}.
-/dev/gpiomem is preferred for GPIO mapping with fallback to /dev/mem.
-If /dev/mem is used GPIO 0-27 pads are set to the limited
-slew rate and drive strength is reduced to 4 mA (2 mA on RPi 4).
-
See @file{interface/raspberrypi-native.cfg} for a sample config and
@file{interface/raspberrypi-gpio-connector.cfg} for pinout.
@@ -3304,8 +3300,25 @@ Set SPEED_COEFF and SPEED_OFFSET for delay calculations. If unspecified,
speed_coeff defaults to 113714, and speed_offset defaults to 28.
@end deffn
+@deffn {Config Command} {bcm2835gpio peripheral_mem_dev} @var{device}
+Set the device path for access to the memory mapped GPIO control registers.
+Uses @file{/dev/gpiomem} by default, this is also the preferred option with
+respect to system security.
+If overridden to @file{/dev/mem}:
+@itemize @minus
+@item OpenOCD needs @code{cap_sys_rawio} or run as root to open @file{/dev/mem}.
+Please be aware of security issues imposed by running OpenOCD with
+elevated user rights and by @file{/dev/mem} itself.
+@item correct @command{peripheral_base} must be configured.
+@item GPIO 0-27 pads are set to the limited slew rate
+and drive strength is reduced to 4 mA (2 mA on RPi 4).
+@end itemize
+
+@end deffn
+
@deffn {Config Command} {bcm2835gpio peripheral_base} @var{base}
-Set the peripheral base register address to access GPIOs. For the RPi1, use
+Set the peripheral base register address to access GPIOs.
+Ignored if @file{/dev/gpiomem} is used. For the RPi1, use
0x20000000. For RPi2 and RPi3, use 0x3F000000. For RPi4, use 0xFE000000. A full
list can be found in the
@uref{https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md, official guide}.
diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c
index c723860..39e4af3 100644
--- a/src/jtag/drivers/bcm2835gpio.c
+++ b/src/jtag/drivers/bcm2835gpio.c
@@ -19,6 +19,7 @@
#include <sys/mman.h>
+static char *bcm2835_peri_mem_dev;
static off_t bcm2835_peri_base = 0x20000000;
#define BCM2835_GPIO_BASE (bcm2835_peri_base + 0x200000) /* GPIO controller */
@@ -57,6 +58,14 @@ static struct initial_gpio_state {
} initial_gpio_state[ADAPTER_GPIO_IDX_NUM];
static uint32_t initial_drive_strength_etc;
+static inline const char *bcm2835_get_mem_dev(void)
+{
+ if (bcm2835_peri_mem_dev)
+ return bcm2835_peri_mem_dev;
+
+ return "/dev/gpiomem";
+}
+
static inline void bcm2835_gpio_synchronize(void)
{
/* Ensure that previous writes to GPIO registers are flushed out of
@@ -300,6 +309,18 @@ COMMAND_HANDLER(bcm2835gpio_handle_speed_coeffs)
return ERROR_OK;
}
+COMMAND_HANDLER(bcm2835gpio_handle_peripheral_mem_dev)
+{
+ if (CMD_ARGC == 1) {
+ free(bcm2835_peri_mem_dev);
+ bcm2835_peri_mem_dev = strdup(CMD_ARGV[0]);
+ }
+
+ command_print(CMD, "BCM2835 GPIO: peripheral_mem_dev = %s",
+ bcm2835_get_mem_dev());
+ return ERROR_OK;
+}
+
COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base)
{
uint64_t tmp_base;
@@ -323,6 +344,13 @@ static const struct command_registration bcm2835gpio_subcommand_handlers[] = {
.usage = "[SPEED_COEFF SPEED_OFFSET]",
},
{
+ .name = "peripheral_mem_dev",
+ .handler = &bcm2835gpio_handle_peripheral_mem_dev,
+ .mode = COMMAND_CONFIG,
+ .help = "device to map memory mapped GPIOs from.",
+ .usage = "[device]",
+ },
+ {
.name = "peripheral_base",
.handler = &bcm2835gpio_handle_peripheral_base,
.mode = COMMAND_CONFIG,
@@ -413,16 +441,16 @@ static int bcm2835gpio_init(void)
return ERROR_JTAG_INIT_FAILED;
}
- bool pad_mapping_possible = false;
+ bool is_gpiomem = strcmp(bcm2835_get_mem_dev(), "/dev/gpiomem") == 0;
+ bool pad_mapping_possible = !is_gpiomem;
- dev_mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
- if (dev_mem_fd < 0) {
- LOG_DEBUG("Cannot open /dev/gpiomem, fallback to /dev/mem");
- dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
- pad_mapping_possible = true;
- }
+ dev_mem_fd = open(bcm2835_get_mem_dev(), O_RDWR | O_SYNC);
if (dev_mem_fd < 0) {
- LOG_ERROR("open: %s", strerror(errno));
+ LOG_ERROR("open %s: %s", bcm2835_get_mem_dev(), strerror(errno));
+ /* TODO: add /dev/mem specific doc and refer to it
+ * if (!is_gpiomem && (errno == EACCES || errno == EPERM))
+ * LOG_INFO("Consult the user's guide chapter 4.? how to set permissions and capabilities");
+ */
return ERROR_JTAG_INIT_FAILED;
}
@@ -532,6 +560,7 @@ static int bcm2835gpio_quit(void)
pads_base[BCM2835_PADS_GPIO_0_27_OFFSET] = 0x5A000000 | initial_drive_strength_etc;
}
bcm2835gpio_munmap();
+ free(bcm2835_peri_mem_dev);
return ERROR_OK;
}