【分析笔记】全志平台 gpio_wdt 驱动应用和 stack crash 解决
使用说明
第一次遇到看门狗芯片是通过切换电平信号来喂狗,如 SGM706 芯片,之前也比较少会用到看门狗芯片。原本打算参考 sunxi-wdt.c 的框架,利用定时器自己写一个,无意中发现内核已经有 gpio_wdt.c 驱动程序,其原理也是通过内核定时器实现喂狗。因其使用了 of_get_gpio_flags() 接口获取 GPIO 信息,和 gpio-keys.c 驱动一样,该接口存在内存越界的问题,需要略作修改才能使用。
内核配置
内核版本:Linux 4.9
make ARCH=arm64 menuconfig
Device Drivers --->
[*] Watchdog Timer Support --->
<*> LED Support for GPIO connected LEDs
<*> Watchdog device controlled through GPIO-line
配置文件
sys_config.fex
全志平台便捷方式配置,也可以使用通用的 dts 配置方式
;----------------------------------------------------------------------------------
;gpio-wdt parameters
;compatible: 匹配平台驱动
;hw_algo: 清除看门狗计数方式:切换方式(toggle)或脉冲方式(level)
;hw_margin_ms: 看门狗电路会触发复位的最长时间(毫秒),不能小于 2 或者大于 65535
;always-running: 如果看门狗不能关闭,使能后驱动默认会自动喂狗,在应用层调用 STOP 接口不会执行关闭
;gpios: 连接看门狗芯片 WDI 的引脚
;----------------------------------------------------------------------------------
[wdt-gpio]
compatible = "linux,wdt-gpio"
hw_algo = "level"
hw_margin_ms = 1600
always-running = "true"
gpios = port:PL12<1><default><default><default>
配置选项说明:linux-4.9\Documentation\devicetree\bindings\watchdog\gpio_wdt.txt
* GPIO-controlled Watchdog
Required Properties:
- compatible: Should contain "linux,wdt-gpio".
- gpios: From common gpio binding; gpio connection to WDT reset pin.
- hw_algo: The algorithm used by the driver. Should be one of the
following values:
- toggle: Either a high-to-low or a low-to-high transition clears
the WDT counter. The watchdog timer is disabled when GPIO is
left floating or connected to a three-state buffer.
- level: Low or high level starts counting WDT timeout,
the opposite level disables the WDT. Active level is determined
by the GPIO flags.
- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
Optional Properties:
- always-running: If the watchdog timer cannot be disabled, add this flag to
have the driver keep toggling the signal without a client. It will only cease
to toggle the signal when the device is open and the timeout elapsed.
Example:
watchdog: watchdog {
/* ADM706 */
compatible = "linux,wdt-gpio";
gpios = <&gpio3 9 GPIO_ACTIVE_LOW>;
hw_algo = "toggle";
hw_margin_ms = <1600>;
};
内存越界
日志信息
[ 3.727333] sunxi-wdt 1c20ca0.watchdog: Watchdog enabled (timeout=16 sec, nowayout=0)
[ 3.736874] of_get_named_gpiod_flags: parsed 'gpios' property of node '/soc@01c00000/wdt-gpio[0]' - status (0)
[ 3.748392] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffff8008655044
[ 3.748392]
[ 3.760564] CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.9.56 #179
[ 3.767382] Hardware name: sun50iw1 (DT)
[ 3.771771] Call trace:
[ 3.774522] [<ffffff800808a7d4>] dump_backtrace+0x0/0x22c
[ 3.780566] [<ffffff800808aa24>] show_stack+0x24/0x30
[ 3.786226] [<ffffff80083c9a64>] dump_stack+0x8c/0xb0
[ 3.791880] [<ffffff80081a5960>] panic+0x14c/0x298
[ 3.797247] [<ffffff80080a19d0>] print_tainted+0x0/0xa8
[ 3.803099] [<ffffff8008655044>] gpio_wdt_probe+0x230/0x258
[ 3.809338] [<ffffff80084b3e9c>] platform_drv_probe+0x60/0xac
[ 3.815770] [<ffffff80084b1a6c>] driver_probe_device+0x1b8/0x3d4
[ 3.822493] [<ffffff80084b1d1c>] __driver_attach+0x94/0x108
[ 3.828729] [<ffffff80084af68c>] bus_for_each_dev+0x88/0xc8
[ 3.834964] [<ffffff80084b1374>] driver_attach+0x30/0x3c
[ 3.840908] [<ffffff80084b0d24>] bus_add_driver+0xf8/0x24c
[ 3.847046] [<ffffff80084b2a74>] driver_register+0x9c/0xe8
[ 3.853186] [<ffffff80084b3de0>] __platform_driver_register+0x5c/0x68
[ 3.860400] [<ffffff8008d48a20>] gpio_wdt_driver_init+0x18/0x20
[ 3.867026] [<ffffff8008083a2c>] do_one_initcall+0xb0/0x14c
[ 3.873267] [<ffffff8008d10d64>] kernel_init_freeable+0x14c/0x1e8
[ 3.880093] [<ffffff8008970724>] kernel_init+0x18/0x104
[ 3.885941] [<ffffff8008083050>] ret_from_fork+0x10/0x40
[ 3.891884] SMP: stopping secondary CPUs
[ 3.896276] Kernel Offset: disabled
[ 3.900178] Memory Limit: none
[ 3.909173] Rebooting in 5 seconds..
解决补丁
--- linux-4.9\drivers\watchdog\gpio_wdt.c 2022-09-13 17:51:57.000000000 +0800
+++ linux-4.9\drivers\watchdog\gpio_wdt.c 2022-09-13 17:51:37.000000000 +0800
@@ -12,12 +12,13 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
+#include <linux/sunxi-gpio.h>
#define SOFT_TIMEOUT_MIN 1
#define SOFT_TIMEOUT_DEF 60
#define SOFT_TIMEOUT_MAX 0xffff
enum {
@@ -138,29 +139,29 @@
.set_timeout = gpio_wdt_set_timeout,
};
static int gpio_wdt_probe(struct platform_device *pdev)
{
struct gpio_wdt_priv *priv;
- enum of_gpio_flags flags;
+ struct gpio_config gpio_flags;
unsigned int hw_margin;
unsigned long f = 0;
const char *algo;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
- priv->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
+ priv->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, (enum of_gpio_flags *)&gpio_flags);
if (!gpio_is_valid(priv->gpio))
return priv->gpio;
- priv->active_low = flags & OF_GPIO_ACTIVE_LOW;
+ priv->active_low = gpio_flags.data & OF_GPIO_ACTIVE_LOW;
ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo);
if (ret)
return ret;
if (!strcmp(algo, "toggle")) {
priv->hw_algo = HW_ALGO_TOGGLE;
原因分析
- gpio_wdt 驱动使用 of_get_gpio_flags() 获取 dts 里面 gpio 配置信息。
- 但是 of_get_gpio_flags() 传入 enum of_gpio_flags 类型来获取配置信息。
- of_get_gpio_flags() 的最终实现由具体的 SOC 厂商实现,这里是全志厂商实现。
- 实现的函数为:drivers/pinctrl/sunxi/pinctrl-sunxi.c --> sunxi_pinctrl_gpio_of_xlate()。
- 在 sunxi_pinctrl_gpio_of_xlate() 却是通过强制转换 struct gpio_config 类型存储 gpio 配置信息。
- 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;
}
【分析笔记】全志平台 gpio_wdt 驱动应用和 stack crash 解决的更多相关文章
- Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)
Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要 ...
- 在全志平台调试博通的wifi驱动(类似ap6212)【转】
转自:http://blog.csdn.net/fenzhi1988/article/details/44809779 调试驱动之前,首先先看看驱动代码,了解代码大致工作流程,再根据硬件配置驱动,比如 ...
- uboot的GPIO驱动分析--基于全志的A10芯片【转】
本文转载自:http://blog.csdn.net/lw2011cg/article/details/68954707 uboot的GPIO驱动分析--基于全志的A10芯片 转载至:http://b ...
- u-boot启动流程分析(1)_平台相关部分
转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的“board—>machine—>arch—> ...
- 字符设备驱动、平台设备驱动、设备驱动模型、sysfs的比较和关联
转载自:http://www.kancloud.cn/yueqian_scut/emlinux/106829 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动.设备驱动模型和sy ...
- zeromq源码分析笔记之线程间收发命令(2)
在zeromq源码分析笔记之架构说到了zmq的整体架构,可以看到线程间通信包括两类,一类是用于收发命令,告知对象该调用什么方法去做什么事情,命令的结构由command_t结构体确定:另一类是socke ...
- Spark大型项目实战:电商用户行为分析大数据平台
本项目主要讲解了一套应用于互联网电商企业中,使用Java.Spark等技术开发的大数据统计分析平台,对电商网站的各种用户行为(访问行为.页面跳转行为.购物行为.广告点击行为等)进行复杂的分析.用统计分 ...
- 微软连续12年成为Gartner分析和BI平台魔力象限的领导者
小悦还沉浸在新春开工大吉的工作中,微软Power BI就又迎来了一个好消息!据Gartner刚新鲜出炉的< 2019年Gartner的分析和商业智能平台魔力象限报告>,微软迄今已连续12 ...
- [kernel]字符设备驱动、平台设备驱动、设备驱动模型、sysfs几者之间的比较和关联
转自:http://www.2cto.com/kf/201510/444943.html Linux驱动开发经验总结,绝对干货! 学习Linux设备驱动开发的过程中自然会遇到字符设备驱动.平台设备驱动 ...
- Linux Platform devices 平台设备驱动
设备总线驱动模型:http://blog.csdn.net/lizuobin2/article/details/51570196 本文主要参考:http://www.wowotech.net/devi ...
随机推荐
- Python 包(package)
在比较大型的项目中常常需要编写.用到大量的模块,此时我们可以使用包(Package)来管理这些模块. (一)什么是包? Python包,就是里面装了一个__init__.py文件的文件夹. __ini ...
- Bugku login1
打开是个普普通通的登录界面,盲猜是注入题,先看看源码吧,没找到什么有用的信息,那就先注册试试 注册admin就已经存在,可能待会就爆破admin的密码也可能,因为没有验证嘛 试试注册其他的 登录发现他 ...
- python基础语法/简单数据类型/常量与变量
今日内容概要 PEP-8规范/python基础语法 变量与常量定义 基本数据类型(整形int,字符串str,浮点型float,字典dict,列表list) 到此我们前期的配置已经可以满足我们正常编写代 ...
- 【大数据课程】高途课程实践-Day03:Scala实现商品实时销售统计
〇.概述 1.实现内容 使用Scala编写代码,通过Flink的Source.Sink以及时间语义实现实时销量展示 2.过程 (1)导包并下载依赖 (2)创建数据源数据表并写⼊数据 (3)在Mysql ...
- 【Java SE进阶】Day13 Stream流、方法引用
〇.总结 Stream流的方法:forEach.filter.map.count.limit.skip.concat(结合之前的Collectors接口) 方法引用:Lambda的其他类方法体相同,如 ...
- k8s篇-k8s集群架构及组件详解【史上最详细】
O kubernetes简介 k8s是什么 k8s是一个可移植的.可扩展的开源平台,用于管理容器化的工作负载和服务,可以促进声明式配置和自动化. k8s能做什么 1)服务发现和负载均衡 Kuberne ...
- 直接快速下载NLTK数据
直接快速下载NLTK数据 直接下载NLTK的数据速度很慢,这里提供NLTK数据集,直接下载即可.或者选择下列百度云下载: 链接:https://pan.baidu.com/s/17ZgkoQeMosW ...
- Redis Zset实现统计模块
1. 背景 公司有一个配置中心系统,使用MySQL存储了大量的配置,但现在不清楚哪些配置正在线上使用,哪些已经废弃了,所以需要实现一个统计模块,实现以下两个功能: 查看总体配置的数量以及活跃的数量 查 ...
- IOS移动端 -webkit-overflow-scrollin属性造成的问题
-webkit-overflow-scrolling带来的相关问题. -webkit-overflow-scrolling 属性控制元素在移动设备上是否使用滚动回弹效果. 其具有两个属性: auto: ...
- 一个简单的工具开发:从学生端更新程序部署工具说起,浅谈qt中自定义控件制作和调用、TCP协议下文件的收发 、以及可执行文件的打包
一个简单的工具开发:从学生端更新程序部署工具说起,浅谈qt中ui的使用和TCP协议下文件的收发.以及可执行文件的打包 写在前面,Qt Designer是一个非常操蛋的页面编辑器,它非常的...怎么说呢 ...