串口的mmap IO口地址
mmap IO port address for serial port
我正在检查串行端口 (uart) 0x2f8 的 io 端口地址是否可以映射到用户 space。
我想自己在驱动程序中执行此操作,而不是使用任何库来了解需要哪些 api 来实现此目的。但是,我不确定它是否真的可以完成,因为这是特定于 x86 和端口 IO 的。无论如何,我已经在用户 space.
中编写了一个 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 内存时,我期望从 0x2f8(uart 的基数)偏移 0x7(便签本)处的 0x5A。但是我没有看到预期的输出。
我试过的另一种方法是 ioport_map 给出了一个地址 0x102f8,这似乎不是
像虚拟地址但更像物理地址 (BASE + 0x2f8)
所以,我直接用这个地址来获取pfn。但还是一样的结果。
我的用户space程序如下:
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 标签以从平台方面获得一些帮助,以防有人知道其中的区别。
注意:此答案特定于 x86。
I/O 端口通过 IN 和 OUT 指令访问。
应该可以映射驱动程序管理的反弹缓冲区,并使用这些指令写入串行。您可能需要编写同步接口(例如刷新 ioctl)。
与您可以使用基于 MMIO 的设备所做的不同,您将无法粗略地将接触设备的内存直接映射到用户 space,因为该内存不存在。
您可以尝试修改 I/O 端口权限,以便用户 space 可以访问 I/O 端口本身。 ioperm 系统调用(可能还有其他系统调用)管理这个。
我正在检查串行端口 (uart) 0x2f8 的 io 端口地址是否可以映射到用户 space。 我想自己在驱动程序中执行此操作,而不是使用任何库来了解需要哪些 api 来实现此目的。但是,我不确定它是否真的可以完成,因为这是特定于 x86 和端口 IO 的。无论如何,我已经在用户 space.
中编写了一个 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 内存时,我期望从 0x2f8(uart 的基数)偏移 0x7(便签本)处的 0x5A。但是我没有看到预期的输出。
我试过的另一种方法是 ioport_map 给出了一个地址 0x102f8,这似乎不是 像虚拟地址但更像物理地址 (BASE + 0x2f8) 所以,我直接用这个地址来获取pfn。但还是一样的结果。
我的用户space程序如下:
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 标签以从平台方面获得一些帮助,以防有人知道其中的区别。
注意:此答案特定于 x86。
I/O 端口通过 IN 和 OUT 指令访问。
应该可以映射驱动程序管理的反弹缓冲区,并使用这些指令写入串行。您可能需要编写同步接口(例如刷新 ioctl)。
与您可以使用基于 MMIO 的设备所做的不同,您将无法粗略地将接触设备的内存直接映射到用户 space,因为该内存不存在。
您可以尝试修改 I/O 端口权限,以便用户 space 可以访问 I/O 端口本身。 ioperm 系统调用(可能还有其他系统调用)管理这个。