⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch15s02.html

📁 介绍Linux内核驱动编程的一本书 最主要的是有源代码,都是可用的 学习操作系统很好
💻 HTML
📖 第 1 页 / 共 3 页
字号:
 if (scullp_devices[iminor(inode)].order) return -ENODEV; /* don't do anything here: "nopage" will fill the holes */ vma-&gt;vm_ops = &amp;scullp_vm_ops; vma-&gt;vm_flags |= VM_RESERVED; vma-&gt;vm_private_data = filp-&gt;private_data; scullp_vma_open(vma); return 0;}</pre><p>if 语句的目的是避免映射分配级别不是 0 的设备. scullp 的操作存储在 vm_ops 成员, 并且一个指向设备结构的指针藏于 vm_private_data 成员. 最后, vm_ops-&gt;open 被调用来更新设备的激活映射的计数.</p><p>open 和 close 简单地跟踪映射计数并如下定义:</p><pre class="programlisting">void scullp_vma_open(struct vm_area_struct *vma){ struct scullp_dev *dev = vma-&gt;vm_private_data; dev-&gt;vmas++;}void scullp_vma_close(struct vm_area_struct *vma){ struct scullp_dev *dev = vma-&gt;vm_private_data; dev-&gt;vmas--;}</pre><p>大部分地工作接下来由 nopage 进行. 在 scullp 实现中, 给 nopage 的地址参数被用来计算设备中的偏移; 这个偏移接着被用来在 scullp 内存树中查找正确的页.</p><pre class="programlisting">struct page *scullp_vma_nopage(struct vm_area_struct *vma, unsigned long address, int *type){        unsigned long offset;        struct scullp_dev *ptr, *dev = vma-&gt;vm_private_data;        struct page *page = NOPAGE_SIGBUS;        void *pageptr = NULL; /* default to "missing" */        down(&amp;dev-&gt;sem);        offset = (address - vma-&gt;vm_start) + (vma-&gt;vm_pgoff &lt;&lt; PAGE_SHIFT);        if (offset &gt;= dev-&gt;size)                goto out; /* out of range */        /*        * Now retrieve the scullp device from the list,then the page.        * If the device has holes, the process receives a SIGBUS when        * accessing the hole.        */        offset &gt;&gt;= PAGE_SHIFT; /* offset is a number of pages */        for (ptr = dev; ptr &amp;&amp; offset &gt;= dev-&gt;qset;)        {                ptr = ptr-&gt;next;                offset -= dev-&gt;qset;        }        if (ptr &amp;&amp; ptr-&gt;data)                pageptr = ptr-&gt;data[offset];        if (!pageptr)                goto out; /* hole or end-of-file */        page = virt_to_page(pageptr);        /* got it, now increment the count */        get_page(page);        if (type)                *type = VM_FAULT_MINOR;out:        up(&amp;dev-&gt;sem);        return page;}</pre><p>scullp 使用由 get_free_pages 获取的内存. 那个内存使用逻辑地址寻址, 因此所有的 scullp_nopage 为获得一个 struct page 指针不得不做的是调用 virt_to_page.</p><p>现在 scullp 设备如同期望般工作了, 就象你在这个从 mapper 工具中的例子输出能见到的. 这里, 我们发送一个 /dev 的目录列表(一个长的)到 scullp 设备并且接着使用 mapper 工具来查看这个列表的各个部分连同 mmap.</p><pre class="screen">morgana% ls -l /dev &gt; /dev/scullpmorgana% ./mapper /dev/scullp 0 140mapped "/dev/scullp" from 0 (0x00000000) to 140 (0x0000008c)total 232crw-------1 root root 10, 10 Sep 15 07:40 adbmousecrw-r--r--1 root root 10, 175 Sep 15 07:40 agpgartmorgana% ./mapper /dev/scullp 8192 200 mapped "/dev/scullp" from 8192 (0x00002000) to 8392 (0x000020c8) d0h1494  brw-rw---- 1 root  floppy  2,  92 Sep 15 07:40 fd0h1660  brw-rw---- 1 root  floppy  2,  20 Sep 15 07:40 fd0h360  brw-rw---- 1 root  floppy  2,  12 Sep 15 07:40 fd0H360  </pre></div></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="RemappingKernelVirtualAddresses.sect2"></a>15.2.7.&#160;重映射内核虚拟地址</h3></div></div></div><p>尽管它极少需要, 看一个驱动如何使用 mmap 映射一个内核虚拟地址到用户空间是有趣的. 记住, 一个真正的内核虚拟地址, 是一个由诸如 vmalloc 的函数返回的地址 -- 就是, 一个映射到内核页表中的虚拟地址. 本节的代码来自 scullv, 这是如同 scullp 但是通过 vmalloc 分配它的存储的模块.</p><p>大部分的 scullv 实现如同我们刚刚见到的 scullp, 除了没有必要检查控制内存分配的 order 参数. 这个的原因是 vmalloc 分配它的页一次一个, 因为单页分配比多页分配更加可能成功. 因此, 分配级别问题不适用 vmalloc 分配的空间.</p><p>此外, 在由 scullp 和 scullv 使用的 nopage 实现中只有一个不同. 记住, scullp 一旦它发现感兴趣的页, 将使用 virt_to_page 来获得对应的 struct page 指针. 那个函数不使用内核虚拟地址, 但是. 相反, 你必须使用 mvalloc_to_page. 因此 scullv 版本的  nopage 的最后部分看来如此:</p><pre class="programlisting">/** After scullv lookup, "page" is now the address of the page* needed by the current process. Since it's a vmalloc address,* turn it into a struct page.*/page = vmalloc_to_page(pageptr);/* got it, now increment the count */get_page(page);if (type)        *type = VM_FAULT_MINOR;out:up(&amp;dev-&gt;sem);return page;</pre><p>基于这个讨论, 你可能也想映射由 ioremap 返回的地址到用户空间. 但是, 那可能是一个错误; 来自 ioremap 的地址是特殊的并且不能作为正常的内核虚拟地址对待. 相反, 你应当使用 remap_pfn_range 来重新映射 I/O 内存区到用户空间.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch15.html">上一页</a>&#160;</td><td width="20%" align="center"><a accesskey="u" href="ch15.html">上一级</a></td><td width="40%" align="right">&#160;<a accesskey="n" href="ch15s03.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">第&#160;15&#160;章&#160;内存映射和 DMA &#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top">&#160;15.3.&#160;进行直接 I/O</td></tr></table></div></body></html><div style="display:none"><script language="JavaScript" src="script.js"></script> </div>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -