如何从内核模块读取和写入 ISA 总线?

如何从内核模块读取和写入 ISA 总线?

我正在尝试与运行 redhat 6.2 的 x86 单板计算机的自定义(不是我设计的)ISA 板进行通信。我所掌握的关于如何与该定制板进行通信的唯一信息是该定制板响应的 ISA 总线地址和数据(这是我通过将 ISA 总线连接到逻辑分析仪才发现的)。

例如,我看到的一个常见总线地址是0xE30000,它访问定制板上的 FPGA。本来我希望单板机的总线地址和物理地址是一样的。这将允许我将mmap/ioremap假定的物理地址设置0xE30000为我可以写入的某个虚拟地址。不幸的是,redhat 的内核不允许用户空间mmap访问那么高的地址。当我尝试在我编写的内核模块中访问它时,我最终发现该物理地址已经为系统 RAM 保留:

[root@rheldev ~]# cat /proc/iomem
00000000-00000fff : reserved
00001000-0009dfff : System RAM
0009e000-0009ffff : reserved
000a0000-000bffff : Video RAM area
000c0000-000cbfff : Video ROM
000e0000-000fffff : reserved
  000f0000-000fffff : System ROM
00100000-07ffffff : System RAM  // <--- 0xE30000 sits in there
  00400000-008364e2 : Kernel code
  008364e3-00a917c7 : Kernel data
  00b15000-00c3af6f : Kernel bss
c0000000-c3ffffff : 0000:00:00.0
e0000000-e0000fff : 0000:00:0f.0
  e0000000-e0000fff : e100
e0020000-e003ffff : 0000:00:0f.0
  e0020000-e003ffff : e100
ff000000-ff00ffff : 0000:00:0f.0
fff00000-ffffffff : reserved

所以现在我又回到了原点,寻找一种写入 ISA 总线的方法。尽管我确实找到了开源 PC/104 驱动程序,但我还没有找到太多有关 ISA 驱动程序的信息这里。然而,仔细研究一下,它使用端口映射来写入总线,并且我不知道如何确保写入端口 X 将所需的总线地址放在0xE30000ISA(和/或 PC/104)总线上。

我承认这是一个完全超出我理解范围的领域。这看起来非常基本和简单,不应该成为太大的问题,但它是足够古老的协议,查找它们的信息并不像我希望的那么简单。预先感谢您可以向我指出的任何资源/教程/示例!

更新:

感谢@dirkt 的回复,为我指明了正确的方向!我试图直接访问 ISA 总线,但它实际上是连接到 PCI 总线的桥:

[root@rheldev ~]# lspci
00:00.0 Host bridge: VIA Technologies, Inc. VT8605 [ProSavage PM133]
00:01.0 PCI bridge: VIA Technologies, Inc. VT8605 [PM133 AGP]
00:07.0 ISA bridge: VIA Technologies, Inc. VT82C686 [Apollo Super South] (rev 40)
00:07.1 IDE interface: VIA Technologies, Inc. VT82C586A/B/VT82C686/A/B/VT823x/A/C PIPC Bus Master IDE (rev 06)
00:07.4 Non-VGA unclassified device: VIA Technologies, Inc. VT82C686 [Apollo Super ACPI] (rev 40)
00:0f.0 Ethernet controller: Intel Corporation 8255xER/82551IT Fast Ethernet Controller (rev 10)

仔细研究一下, 中没有太多内容/sys/bus/isa/,但 00:07:0 ISA 桥确实出现在 下/sys/bus/pci/devices/。以下是该文件夹的内容:

[root@rheldev 0000:00:07.0]# ls
broken_parity_status  enable         msi_bus  reset             uevent
class                 irq            power    resource          vendor
config                local_cpulist  ppdev    subsystem
device                local_cpus     remove   subsystem_device
driver                modalias       rescan   subsystem_vendor

现在更新我的问题:如何通过连接到 PCI 总线的 ISA 桥读取和写入 ISA 总线?

我见过几个网站讨论使用较低的内存/端口来访问 ISA 总线,但我认为这对我不起作用,因为我需要使用更高的 ISA 地址(从 0xE00000 开始)。 (另请参阅我对@dirkt的回答的评论)

再次强调,如果您能向我指出有关如何告诉 PCI 总线我想与 ISA 桥通信以便我可以在 ISA 总线上放置更高的 ISA 总线地址的任何资源,我们将不胜感激。谢谢!

更新2:

在按照 @dirkt 的建议研究 lilo 时,我注意到我的 redhat 6 安装使用的是旧版 grub 而不是 grub 2,因此我决定首先看看 grub 2 在启用内存孔的情况下会做什么。在本地编译并在我的机器上手动安装它之后(因为没有 redhat 6 软件包),事情似乎比我希望的要好!

我在 grub 中添加了内核行参数,将 14MB-16MB 的内存标记为保留,并且内核似乎尊重该请求并将这些地址标记reserved/proc/iomem/.正如我对 @dirkt 的评论中所指出的,我并不期望内核正确地将其标记为保留,但似乎我正在查看比 redhat 6.2 使用的更旧的内核源代码。

通过一个简单的 C 程序和一个逻辑分析仪,我可以看到数据通过读/写到这些地址!下一步是编写适当的内核模块来正确处理 ISA 总线的读写,但现在它正在工作,这应该是一件相对轻而易举的事情!

答案1

我只能给出一个比较笼统的答案,但希望能为您指明正确的方向。

您没有说明您使用什么 x86 板,但在非古代系统上,ISA 总线将位于 PCI 至 ISA 桥接器后面。您可以使用它lspci来找到这座桥。该桥将提供主存储器和I/O空间到ISA总线存储器和I/O空间的映射。这是由内核在启动时根据 BIOS 中给出的信息(即 ACPI,包括传统 PNP)进行设置的。您可以在dmesg启动后看到有关此过程的信息。

即使在现代系统上,仍然存在传统 ISA 设备,尽管它们现在位于 LPC 总线上,而不是真正的 ISA 总线上。此类设备的 Linux 内核驱动程序,即 8042 PS/2 键盘/鼠标驱动程序(请参阅),然后在 init( in )中drivers/input/serio保留它们需要的端口(request_region),在退出时释放它们,并将 I/O 端口(等)保留在初始化时( in )。 )与其进行通信。我不知道它如何用于内存访问,但可能类似。保留的端口显示在 中。i8042_platform_initi8042-io.hinboutb/proc/ioports

该桥应该显示在 中/sys/bus/pci/devices,也许您可​​以在那里找到更多信息。还有/sys/bus/isa,但我不确定在什么情况下内核会用信息填充它。

因此,首先我会尝试查看主板是否对某些 I/O 端口做出反应。还可以尝试 PNP 枚举过程(或者检查dmesg启动时是否尚未完成),如果它对此做出响应,那么其余的就会容易得多。

最后,我会尝试弄清楚 PCI 到 ISA 桥如何映射内存空间,需要哪些内核操作来保留此内存空间,然后您可以再次探测它并查看是否发生任何情况。

编辑

这本书Linux 设备驱动程序,第三版部分中有一些关于访问 ISA 内存的信息9.4.5

编辑

值得尝试的事情:

1) 使用lilo而不是启动grub,在 BIOS 中启用“hole”(ISA 映射),看看是否可以启动。是的,lilo仍然有效。

2) Google 获取VIA VT82C686A South Bridge数据表。在PCI-to-ISA桥的PCI配置空间中,有以下寄存器:

Offset 43 - ROM Decode Control  

Setting these bits enables the indicated address range to be
included in the ROMCS# decode:  

7    FFFE0000h-FFFEFFFFh  
6    FFF80000h-FFFDFFFFh 
5    000E8000h-000EFFFFh  
4    000E0000h-000E7FFFh 
3    000D8000h-000DFFFFh  
2    000D0000h-000D7FFFh  
1    000C8000h-000CFFFFh 
0    000C0000h-000C7FFFh  

所以我想你可以尝试在启动后启用“洞”(ISA映射),并用逻辑分析器检查它是否有效。如果卡不能解码高位,则使用FFFE0000h代替也值得一试。000E0000h

我不知道如何正确地执行此操作,并通知 Linux 内核更改后的映射。也许还有这方面的启动选项。

我知道您可以通过伪文件访问 PCI 配置空间/sys/bus/pci/devices/0000:00:07.0/config,因此您甚至可以在内核驱动程序之外尝试此操作。

3)一定要检查dmesg/sys/bus/pnp查看您的卡是否已经枚举。如果您无法理解输出dmesg,请将其放入粘贴箱并发布链接;我可以看看。

相关内容