Navigation

    全志在线开发者论坛

    • Register
    • Login
    • Search
    • Categories
    • Tags
    • 在线文档
    • 社区主页

    全志平台 gpio-keys 驱动应用和 stack crash 解决

    其它全志芯片讨论区
    1
    1
    1391
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      dream LV 6 last edited by

      内核配置


      内核版本:Linux version 4.9.56

      make ARCH=arm64 menuconfig
      Device Drivers  --->
      	Input device support  --->     
      		[*]   Keyboards  --->
      			<*>   GPIO Buttons
      

      配置文件


      sys_config.fex
      ;----------------------------------------------------------------------------------
      ;gpio-keys parameters
      ;----------------------------------------------------------------------------------
      [gpio-keys]
      compatible = "gpio-keys";
      
      [gpio-keys/up]
      linux,code = 103
      linux,input-type = 1
      gpios = port:PH11<6><default><default><default>
      
      [gpio-keys/down]
      linux,code = 108
      linux,input-type = 1
      gpios = port:PH08<0><default><default><default>
      
      [gpio-keys/enter]
      linux,code = 28
      linux,input-type = 1
      gpios = port:PH10<6><default><default><default>
      

      内存越界


      日志信息

      [    2.868360] of_get_named_gpiod_flags: parsed 'gpios' property of node '/soc@01c00000/gpio-keys/up[0]' - status (0)
      [    2.868366] of_get_gpio_flags button->gpio:235...
      [    2.868393] of_get_named_gpiod_flags: parsed 'gpios' property of node '/soc@01c00000/gpio-keys/down[0]' - status (0)
      [    2.868396] of_get_gpio_flags button->gpio:232...
      [    2.868417] of_get_named_gpiod_flags: parsed 'gpios' property of node '/soc@01c00000/gpio-keys/enter[0]' - status (0)
      [    2.868420] of_get_gpio_flags button->gpio:234...
      [    2.869024] input: gpio-keys as /devices/platform/soc/gpio-keys/input/input3
      [    2.869369] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffff8008600ce0
      [    2.869369] 
      [    2.869380] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.9.56 #165
      [    2.869383] Hardware name: sun50iw1 (DT)
      [    2.869388] Call trace:
      [    2.869409] [<ffffff800808a7d4>] dump_backtrace+0x0/0x22c
      [    2.869417] [<ffffff800808aa24>] show_stack+0x24/0x30
      [    2.869430] [<ffffff80083c9a64>] dump_stack+0x8c/0xb0
      [    2.869438] [<ffffff80081a5960>] panic+0x14c/0x298
      [    2.869450] [<ffffff80080a19d0>] print_tainted+0x0/0xa8
      [    2.869463] [<ffffff8008600ce0>] gpio_keys_probe+0x6d0/0x804
      [    2.869474] [<ffffff80084b3e9c>] platform_drv_probe+0x60/0xac
      [    2.869481] [<ffffff80084b1a6c>] driver_probe_device+0x1b8/0x3d4
      [    2.869485] SMP: stopping secondary CPUs
      [    2.877351] Kernel Offset: disabled
      [    2.877354] Memory Limit: none
      

      解决补丁

      diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
      old mode 100644
      new mode 100755
      index 9b8079c..04e1580
      --- a/drivers/input/keyboard/gpio_keys.c
      +++ b/drivers/input/keyboard/gpio_keys.c
      @@ -32,6 +32,7 @@
       #include <linux/of_gpio.h>
       #include <linux/of_irq.h>
       #include <linux/spinlock.h>
      +#include <linux/sunxi-gpio.h>
       
       struct gpio_button_data {
              const struct gpio_keys_button *button;
      @@ -664,11 +665,11 @@ static void gpio_keys_close(struct input_dev *input)
       
              i = 0;
              for_each_available_child_of_node(node, pp) {
      -               enum of_gpio_flags flags;
      +               struct gpio_config gpio_flags;
       
                      button = &pdata->buttons[i++];
       
      -               button->gpio = of_get_gpio_flags(pp, 0, &flags);
      +               button->gpio = of_get_gpio_flags(pp, 0, (enum of_gpio_flags *)&gpio_flags);
                      if (button->gpio < 0) {
                              error = button->gpio;
                              if (error != -ENOENT) {
      @@ -679,7 +680,7 @@ static void gpio_keys_close(struct input_dev *input)
                                      return ERR_PTR(error);
                              }
                      } else {
      -                       button->active_low = flags & OF_GPIO_ACTIVE_LOW;
      +                       button->active_low = gpio_flags.data & OF_GPIO_ACTIVE_LOW;
                      }
       
                      button->irq = irq_of_parse_and_map(pp, 0);
      

      原因分析

      1. gpio_keys 驱动使用 of_get_gpio_flags() 获取 dts 里面 gpio 配置信息。
      2. 但是 of_get_gpio_flags() 传入 enum of_gpio_flags 类型来获取配置信息。
      3. of_get_gpio_flags() 的最终实现由具体的 SOC 厂商实现,这里是全志厂商实现。
      4. 实现的函数为:drivers/pinctrl/sunxi/pinctrl-sunxi.c --> sunxi_pinctrl_gpio_of_xlate()。
      5. 在 sunxi_pinctrl_gpio_of_xlate() 却是通过强制转换 struct gpio_config 类型存储 gpio 配置信息。
      6. enum of_gpio_flags 占用 4 字节,而 struct gpio_config 占用 20 字节,出现内存越界操作的问题。
      // include/linux/of_gpio.h
      enum of_gpio_flags {		
      	OF_GPIO_ACTIVE_LOW = 0x1,
      	OF_GPIO_SINGLE_ENDED = 0x2,
      }; // 4Byte
      
      // include/linux/sunxi-gpio.h
      struct gpio_config {
      	u32	gpio;
      	u32	mul_sel;
      	u32	pull;
      	u32	drv_level;
      	u32	data;
      }; // 20Byte
      
      // drivers/pinctrl/sunxi/pinctrl-sunxi.c
      static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
      				const struct of_phandle_args *gpiospec,
      				u32 *flags)
      {
      	struct gpio_config *config;
      	int pin, base;
      
      	base = PINS_PER_BANK * gpiospec->args[0];
      	pin = base + gpiospec->args[1];
      	pin = pin - gc->base;
      	if (pin > gc->ngpio)
      		return -EINVAL;
      
      	if (flags) {
      		// 问题出在这个条件下面的赋值语句
      		// 传进来的是 enum of_gpio_flags,只有 4Byte 
      		// 结果使用的 struct gpio_config,却有 20Byte 
      		config = (struct gpio_config *)flags;
      		config->gpio = base + gpiospec->args[1];
      		config->mul_sel = gpiospec->args[2];
      		config->drv_level = gpiospec->args[3];
      		config->pull = gpiospec->args[4];
      		config->data = gpiospec->args[5];
      	}
      
      	return pin;
      }
      
      1 Reply Last reply Reply Quote Share 0
      • Referenced by  D dream 
      • 1 / 1
      • First post
        Last post

      Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

      行为准则 | 用户协议 | 隐私权政策