正点原子IMX6ULL 编写虚拟串口 卸载驱动阶段 报错及解决过程

现象

  • 开发平台: IMX6ULL正点原子开发板
  • 学习韦东山 串口驱动相关代码
  • 使用自己/老师提供的代码,在卸载模块的时候出现内核崩溃。崩溃内容如下
/home/constant_z/c_code/UART_CODE/02_virtual_uart/virtual_uart.c virtual_uart_init 950
virtual_uart_probe 100ask
/lib/modules/4.1.15 # rmmod virtual_uart.ko
/home/constant_z/c_code/UART_CODE/02_virtual_uart/virtual_uart.c virtual_uart_exit 965
virtual_uart_remove 100ask
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = 887c8000
[00000000] *pgd=886f1831, *pte=00000000, *ppte=00000000
Internal error: Oops: 80000007 [#1] PREEMPT SMP ARM
Modules linked in: virtual_uart(O-)
CPU: 0 PID: 84 Comm: rmmod Tainted: G           O    4.1.15 #1
Hardware name: Freescale i.MX6 Ultralite (Device Tree)
task: 886aaac0 ti: 887d0000 task.ti: 887d0000
PC is at 0x0
LR is at uart_remove_one_port+0x130/0x150
pc : [<00000000>]    lr : [<8031b204>]    psr: 200d0013
sp : 887d1ef8  ip : 00000000  fp : 00000000
r10: 00000000  r9 : 887d0000  r8 : 8000f604
r7 : 886d109c  r6 : 00000000  r5 : 886d1000  r4 : 886bee10
r3 : 00000000  r2 : 00000000  r1 : 600d0013  r0 : 886bee10
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c5387d  Table: 887c806a  DAC: 00000015
Process rmmod (pid: 84, stack limit = 0x887d0210)
Stack: (0x887d1ef8 to 0x887d2000)
1ee0:                                                       7f000a74 7f0008d8
1f00: 88107644 00000081 8000f604 7f000118 88107610 8034a2a4 88107610 7f0008d8
1f20: 88107644 803486f0 88107610 7f0008d8 88107644 80348e80 7f0008d8 7ec75930
1f40: 5f6c6175 80348450 7f0008a0 7f000494 7f00091c 80093bfc 00001000 74726976
1f60: 5f6c6175 74726175 7ec75900 00000001 887d0000 00000000 76fb8568 800d61a0
1f80: 00100871 00000000 ffffffff 88596108 76fb8568 00027d38 76e515e4 00028a89
1fa0: 74726976 8000f480 00028a89 74726976 7ec75930 00000880 00000000 7ec75bc8
1fc0: 00028a89 74726976 5f6c6175 00000081 00000002 00000000 76fb8000 00000000
1fe0: 7ec75928 7ec75918 000289d1 76e8aad2 800d0030 7ec75930 8bf59811 8bf59c11
[<8031b204>] (uart_remove_one_port) from [<7f000118>] (virtual_uart_remove+0x28/0x38 [virtual_uart])
[<7f000118>] (virtual_uart_remove [virtual_uart]) from [<8034a2a4>] (platform_drv_remove+0x18/0x30)
[<8034a2a4>] (platform_drv_remove) from [<803486f0>] (__device_release_driver+0x70/0xe4)
[<803486f0>] (__device_release_driver) from [<80348e80>] (driver_detach+0xac/0xb0)
[<80348e80>] (driver_detach) from [<80348450>] (bus_remove_driver+0x4c/0xa0)
[<80348450>] (bus_remove_driver) from [<7f000494>] (virtual_uart_exit+0x30/0x40 [virtual_uart])
[<7f000494>] (virtual_uart_exit [virtual_uart]) from [<80093bfc>] (SyS_delete_module+0x174/0x1b8)
[<80093bfc>] (SyS_delete_module) from [<8000f480>] (ret_fast_syscall+0x0/0x3c)
Code: bad PC value
---[ end trace 7250232a078a0492 ]---
Segmentation fault
  • 内核版本
    学习正点原子驱动时的LINUX内核版本是 4.1.15

  • 排查流程:

    1. 通过打印信息发现,初步定位在uart_remove_one_port这个函数中出现问题。
    2. 根据nxp的流程,及它的imx.c,它没有定义全局静态变量uart_port,而是动态申请份分配
      • 于使我使用nxp一样的构造方法,定义私有数据变量结构体,在结构体里面定义uart_port
        不要在私有数据里面定义指针变量,否则,使用devm_kzalloc会报错。
    3. 我做了个基本的测试驱动程序,叫test_base_uart.c,用来一步一步搭建串口驱动
      • 4.1 发现只要填充uart_port结构体后,卸载驱动就会出现错误。
      • 于使我进入内核源码里面,在下面添加内核中添加如下打印信息
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
{
	struct uart_state *state = drv->state + uport->line;
	struct tty_port *port = &state->port;
	struct tty_struct *tty;
	int ret = 0;

	printk("-----1\n");
	BUG_ON(in_interrupt());

	if (state->uart_port != uport)
		dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
			state->uart_port, uport);

	mutex_lock(&port_mutex);

	/*
	 * Mark the port "dead" - this prevents any opens from
	 * succeeding while we shut down the port.
	 */
	mutex_lock(&port->mutex);
	if (!state->uart_port) {
		mutex_unlock(&port->mutex);
		ret = -EINVAL;
		goto out;
	}
	uport->flags |= UPF_DEAD;
	mutex_unlock(&port->mutex);

	printk("-----2\n");
	/*
	 * Remove the devices from the tty layer
	 */
	tty_unregister_device(drv->tty_driver, uport->line);

	printk("-----3\n");
	tty = tty_port_tty_get(port);
	if (tty) {
		tty_vhangup(port->tty);
		tty_kref_put(tty);
	}
	printk("-----4\n");
	/*
	 * If the port is used as a console, unregister it
	 */
	if (uart_console(uport))
		unregister_console(uport->cons);
	printk("-----5\n");
	/*
	 * Free the port IO and memory resources, if any.
	 */
	if (uport->type != PORT_UNKNOWN)
		uport->ops->release_port(uport);
	printk("-----6\n");
	kfree(uport->tty_groups);

	/*
	 * Indicate that there isn't a port here anymore.
	 */
	uport->type = PORT_UNKNOWN;

	state->uart_port = NULL;
out:
	mutex_unlock(&port_mutex);

	return ret;
}

printk均是后续添加进入内核的,重新复现错误,输出如下打印信息

在这里插入图片描述

那问题就简单了,即

if (uport->type != PORT_UNKNOWN)
		uport->ops->release_port(uport);
	printk("-----6\n");

出现问题,结合我们驱动程序中

 virt_uart_port->type = PORT_8250;//必须设置,不然会报错

当初,韦老师视频中随意设置了一项,所以会进入uart_port的我们提供的release_port这个函数,但我们并没有这个函数,所以释放的时候就会指向空指针,而且NXP的原版驱动中imx.c也没有提供对应的项,算是一个bug吧。我们仿照别人有的驱动代码,填充这个操作函数

static void virtual_uart_release_port(struct uart_port *port){
    return;
}

再次加载运行,问题就解决了。

在这里插入图片描述

最后,别忘了复原内核的代码。推荐使用git命令管理自己的内核版本

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值