0%

Patch Submission Records

1

Description

Bug reported by smatch:

1
drivers/atm/he.c:1520 he_start() warn: 'he_dev->membase' from ioremap() not released on lines: 1061,1118,1168,1417,1427,1433,1468.

Solution

1
false positive.

2

Description

Bug reported by smatch:

1
drivers/gpu/drm/tiny/bochs.c:290 bochs_hw_init() warn: 'bochs->mmio' from ioremap() not released on lines: 246,250,254.

Solution

About drivers/gpu/drm/tiny/bochs.c

drivers/gpu/drm/tiny/bochs.c是Linux内核中的一个设备驱动程序,用于支持Bochs/QEMU虚拟机的图形显示器。它实现了Direct Rendering Manager(DRM)子系统中的驱动程序接口,使得Linux操作系统可以与Bochs/QEMU虚拟机的图形显示器进行通信,以在虚拟环境中显示图形界面。

DRM是Direct Rendering Manager的缩写,是Linux内核中的一个子系统。它提供了用于管理图形硬件设备和处理图形渲染的驱动程序接口,并且允许用户空间应用程序直接访问图形硬件资源。

DRM还提供了一些特殊的功能,例如Kernel Mode Setting(KMS),它允许内核控制显卡输出的分辨率、刷新率等参数,从而改善图形显示性能和质量。此外,DRM还支持3D加速、视频解码等高级图形处理技术,使得Linux系统在图形渲染方面具备与Windows和macOS等操作系统相当的能力。

About ioremap & iounmap

在Linux内核中,ioremap()和iounmap()是用于映射物理地址到虚拟地址的函数。

ioremap()函数将一个物理地址映射到内核虚拟地址空间中,并返回这个虚拟地址。这个函数通常用于驱动程序需要访问硬件设备的寄存器或者其他I/O内存时使用。通过使用ioremap(),驱动程序可以获得一个虚拟地址,用于访问I/O内存。

iounmap()函数则是用于撤销ioremap()所创建的虚拟地址映射。当驱动程序不再需要访问I/O内存时,应该调用iounmap()来释放这些虚拟地址空间,以便其他进程或驱动程序可以使用它们。

需要注意的是,因为ioremap()iounmap()都涉及到对内核虚拟地址空间的修改,因此必须在内核模块中使用,并且需要特权权限才能够使用。

lines in function bochs_hw_init

1
2
3
4
5
6
7
8
9
10
	if ((id & 0xfff0) != VBE_DISPI_ID0) {
DRM_ERROR("ID mismatch\n");
246 return -ENODEV;
}
...
if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0)
250 return -ENODEV;
...
if (addr == 0)
254 return -ENODEV;

原文件即有的ioremap, in bochs_hw_init:

1
2
bochs->mmio = ioremap(ioaddr, iosize);
bochs->fb_map = ioremap(addr, size);

原文件即有的iounmap, in bochs_hw_fini:

1
2
3
4
5
6
7
8
9
10
11
12
13
static void bochs_hw_fini(struct drm_device *dev)
{
struct bochs_device *bochs = dev->dev_private;
/* TODO: shot down existing vram mappings */
if (bochs->mmio)
iounmap(bochs->mmio);
if (bochs->ioports)
release_region(VBE_DISPI_IOPORT_INDEX, 2);
if (bochs->fb_map)
iounmap(bochs->fb_map);
pci_release_regions(to_pci_dev(dev->dev));
kfree(bochs->edid);
}

发现bochs_load中,调用bochs_hw_init(dev)得到返回值ret

  1. 如果ret为非0,会直接返回,唯一一处调用bochs_load的在函数bochs_pci_probe,中的判断为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    	ret = bochs_load(dev);
    if (ret)
    goto err_free_dev;
    ...
    err_hw_fini:
    bochs_hw_fini(dev); (X)
    err_free_dev: <---
    drm_dev_put(dev);
    return ret;

    此时不会进入bochs_hw_fini即不会释放。

  2. 如果ret为0(bochs_hw_init初始化成功)则进一步初始化drmm_vram_helper_init,和我们后续的分析无关。

注意在bochs_hw_init中的返回值共有

1
-EBUSY, -ENOMEM, -ENODEV, 0

原文件即有的对bochs_hw_fini的调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-> static int bochs_load(struct drm_device *dev):
ret = bochs_hw_init(dev);
if (ret)
return ret;

ret = drmm_vram_helper_init(dev, bochs->fb_base, bochs->fb_size);
if (ret)
goto err_hw_fini;

ret = bochs_kms_init(bochs);
if (ret)
goto err_hw_fini;
err_hw_fini:
bochs_hw_fini(dev);

-> static int bochs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_hw_fini:
bochs_hw_fini(dev);

-> static void bochs_pci_remove(struct pci_dev *pdev):
bochs_hw_fini(dev);

3