我正在检查串行端口(uart) 0x2f8的io-port地址是否可以映射到用户空间。我希望自己在驱动程序中做到这一点,而不是使用任何库来知道需要哪些api来实现这一点。但是,考虑到这是特定于x86和端口IO的,我不确定它是否真的可以做到。不管怎样,我已经在用户空间中编写了一个mmap函数和调用者。
Setting up the mapping is as below:res = request_region(base_addr, 8 ,"custom_serial_device");
void __iomem * mem_base_addr = ioport_map(base_addr, 8);
iowrite8(0x01, (u8 *)my_dev->mem_base_addr + 3); /*Few more configs and works fine */
/* After this I am able to make the uart function in software loopback mode */现在我决定在这个地址上尝试mmap:
static int my_dev_mmap(struct file *filep, struct vm_area_struct *vma) {
SERIAL_DEV *my_dev = (SERIAL_DEV*)filep->private_data;
unsigned long pfn;
size_t sz = vma->vm_end - vma->vm_start;
unsigned long phys_addr;
if (vma->vm_end - vma->vm_start != PAGE_SIZE) {
return -EINVAL;
}
if (PAGE_SIZE > (1 << 16))
return -ENOSYS;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_flags |= VM_IO;
/*ioport_map gives virtual address so I am using below to get physical addr */
phys_addr = virt_to_phys(my_dev->mem_base_addr);
pfn = phys_addr >> PAGE_SHIFT;
printk("GNA: mmap called: vm-start: 0x%lx vm-end: 0x%lx mem_base: 0x%lx phys: 0x%lx pfn: %lu\n",
vma->vm_start, vma->vm_end, (unsigned long)my_dev->mem_base_addr, phys_addr, pfn);
if (remap_pfn_range(vma, vma->vm_start, pfn, sz, vma->vm_page_prot)) {
printk("GNA: mmap failed\n");
return -EAGAIN;
}
return 0;
}我得到的打印结果如下:
Dec 19 11:05:00 realtek-dpdk kernel: [ 4624.894086] GNA: mmap called:
vm-start: 0x7fa150f4d000 --> Kernel allocates this range which is in user space
vm-end: 0x7fa150f4e000
mem_base: 0x102f8
phys: 0x6587800102f8 --> Virt_to_phys gave this which seems wrong
pfn: 27254063120当我打印mmap'd内存时,我期望0x5A位于从0x2f8 (uart的基址)到0x7 (高速暂存)的偏移量。然而,我没有看到预期的输出。
我尝试的另一种方法是,ioport_map给出了一个地址0x102f8,它看起来不像是一个虚拟地址,但更像是一个物理地址(基址+ 0x2f8),所以,我直接使用这个地址来获取pfn。但结果仍然是一样的。
我的用户空间程序如下:
address = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, configfd, 0);在此之后,我尝试找到在高速暂存存储器中偏移量0x7处写入的值。
for (int i = 0 ; i < 10; i++) {
printf("Value: 0x%x 0x%x\n", address[i], address[0x2f8 + i]);
}那么,有没有可能mmap()一个ioport。如果是,请告诉我正确的步骤。
PS:虽然这是x86,但我添加了embedded-linux标签,以便从平台端获得一些帮助,以防有人知道其中的区别。
发布于 2020-12-20 19:39:33
注意:此答案与x86相关。
I/O端口通过IN和OUT指令访问。
应该可以映射一个由驱动程序管理的反弹缓冲区,并使用这些指令将其写出到串行。您可能需要为同步编写一个接口(例如,flush ioctl)。
与基于MMIO的设备不同,您不能粗略地将接触设备的内存直接映射到用户空间,因为该内存并不存在。
您可以尝试篡改I/O端口权限,以便用户空间可以访问I/O端口本身。ioperm syscall (可能还有其他)管理这一点。
https://stackoverflow.com/questions/65367469
复制相似问题