📄 ch15.html
字号:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>第 15 章 内存映射和 DMA -Linux设备驱动第三版(中文版)-开发频道-华星在线</title>
<meta name="description" content="驱动开发-开发频道-华星在线" />
<meta name="keywords" content="Linux设备驱动,中文版,第三版,ldd,linux device driver,驱动开发,电子版,程序设计,软件开发,开发频道" />
<meta name="author" content="华星在线 www.21cstar.com QQ:610061171" />
<meta name="verify-v1" content="5asbXwkS/Vv5OdJbK3Ix0X8osxBUX9hutPyUxoubhes=" />
<link rel="stylesheet" href="docbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.69.0">
<link rel="start" href="index.html" title="Linux 设备驱动 Edition 3">
<link rel="up" href="index.html" title="Linux 设备驱动 Edition 3">
<link rel="prev" href="ch14s09.html" title="14.9. 快速参考">
<link rel="next" href="ch15s02.html" title="15.2. mmap 设备操作">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">第 15 章 内存映射和 DMA </th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="ch14s09.html">上一页</a> </td>
<th width="60%" align="center"> </th>
<td width="20%" align="right"> <a accesskey="n" href="ch15s02.html">下一页</a>
</td>
</tr>
</table>
<hr>
</div>
<div class="chapter" lang="zh-cn">
<div class="titlepage"><div><div><h2 class="title">
<a name="MemoryMappingandDMA.chap"></a>第 15 章 内存映射和 DMA </h2></div></div></div>
<div class="toc">
<p><b>目录</b></p>
<dl>
<dt><span class="sect1"><a href="ch15.html#MemoryManagementinLinux.sect1">15.1. Linux 中的内存管理</a></span></dt>
<dd><dl>
<dt><span class="sect2"><a href="ch15.html#AddressTypes.sect2">15.1.1. 地址类型</a></span></dt>
<dt><span class="sect2"><a href="ch15.html#PhsicalAddressesandPages.sect2">15.1.2. 物理地址和页</a></span></dt>
<dt><span class="sect2"><a href="ch15.html#HighandLowMemory.sect2">15.1.3. 高和低内存</a></span></dt>
<dt><span class="sect2"><a href="ch15.html#TheMemoryMapandStructPage.sect2">15.1.4. 内存映射和 struct page</a></span></dt>
<dt><span class="sect2"><a href="ch15.html#PageTables.sect2">15.1.5. 页表</a></span></dt>
<dt><span class="sect2"><a href="ch15.html#VirtualMemoryAreas.sect2">15.1.6. 虚拟内存区</a></span></dt>
<dt><span class="sect2"><a href="ch15.html#TheProcessMemoryMap.sect2">15.1.7. 进程内存映射</a></span></dt>
</dl></dd>
<dt><span class="sect1"><a href="ch15s02.html">15.2. mmap 设备操作</a></span></dt>
<dd><dl>
<dt><span class="sect2"><a href="ch15s02.html#Usingremap_pfn_range.sect2">15.2.1. 使用 remap_pfn_range</a></span></dt>
<dt><span class="sect2"><a href="ch15s02.html#ASimpleImplementation.sect2">15.2.2. 一个简单的实现</a></span></dt>
<dt><span class="sect2"><a href="ch15s02.html#AddingVMAOperations.sect2">15.2.3. 添加 VMA 的操作</a></span></dt>
<dt><span class="sect2"><a href="ch15s02.html#MappingMemorywithnopage.sect2">15.2.4. 使用 nopage 映射内存</a></span></dt>
<dt><span class="sect2"><a href="ch15s02.html#RemappingSpecificIORegions.sect2">15.2.5. 重新映射特定 I/O 区</a></span></dt>
<dt><span class="sect2"><a href="ch15s02.html#RemappingRAM.sect2">15.2.6. 重新映射 RAM</a></span></dt>
<dt><span class="sect2"><a href="ch15s02.html#RemappingKernelVirtualAddresses.sect2">15.2.7. 重映射内核虚拟地址</a></span></dt>
</dl></dd>
<dt><span class="sect1"><a href="ch15s03.html">15.3. 进行直接 I/O</a></span></dt>
<dd><dl><dt><span class="sect2"><a href="ch15s03.html#AsynchronousIO.sect2">15.3.1. 异步 I/O</a></span></dt></dl></dd>
<dt><span class="sect1"><a href="ch15s04.html">15.4. 直接内存存取</a></span></dt>
<dd><dl>
<dt><span class="sect2"><a href="ch15s04.html#OverviewofDMADataTransfer.sect2">15.4.1. 一个 DMA 数据传输的概况</a></span></dt>
<dt><span class="sect2"><a href="ch15s04.html#AllocationgtheDMABuffer.sect2">15.4.2. 分配 DMA 缓冲</a></span></dt>
<dt><span class="sect2"><a href="ch15s04.html#BusAddresses.sect2">15.4.3. 总线地址</a></span></dt>
<dt><span class="sect2"><a href="ch15s04.html#TheGenericDMALayer.sect2">15.4.4. 通用 DMA 层</a></span></dt>
<dt><span class="sect2"><a href="ch15s04.html#DMAforISADevices.sect2">15.4.5. ISA 设备的 DMA</a></span></dt>
</dl></dd>
<dt><span class="sect1"><a href="ch15s05.html">15.5. 快速参考</a></span></dt>
<dd><dl>
<dt><span class="sect2"><a href="ch15s05.html#IntroductoryMaterial.sect2">15.5.1. 介绍性材料</a></span></dt>
<dt><span class="sect2"><a href="ch15s05.html#Implementingmmap.sect2">15.5.2. 实现 mmap</a></span></dt>
<dt><span class="sect2"><a href="ch15s05.html#ImplementingDirectIO.sect2">15.5.3. 实现直接 I/O</a></span></dt>
<dt><span class="sect2"><a href="ch15s05.html#DirectMemoryAccess.sect2">15.5.4. 直接内存存取</a></span></dt>
</dl></dd>
</dl>
</div>
<p>本章研究 Linux 内存管理的部分, 重点在对于设备驱动作者有用的技术. 许多类型的驱动编程需要一些对于虚拟内存子系统如何工作的理解; 我们在本章涉及到的材料来自手头, 而不是象我们曾进入更加复杂和性能关键的子系统一样. 虚拟内存子系统也是 Linux 内核核心的非常有趣的部分, 并且因而, 值得一见.</p>
<p>本章的材料分为 3 个部分:</p>
<div class="itemizedlist"><ul type="disc">
<li><p>第一部分涉及 mmap 系统调用的实现, 它允许设备内存直接映射到一个用户进程地址空间. 不是所有的设备需要 mmap 支持, 但是, 对一些, 映射设备内存可产生可观的性能提高.</p></li>
<li><p>我们接着看从其他的方向跨过边界, 用对直接存取用户空间的讨论. 相对少驱动需要这个能力; 在大部分情况下, 内核做这种映射而驱动甚至不知道它. 但是了解如何映射用户空间内存到内核(使用 get_user_pages)会有用.</p></li>
<li><p>最后一节涵盖直接内存存取( DMA ) I/O 操作, 它提供给外设对系统内存的直接存取.</p></li>
</ul></div>
<p>当然, 所有这些技术需要一个对 Linux 内存管理如何工作的理解, 因此我们从对这个子系统的总览开始.</p>
<div class="sect1" lang="zh-cn">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="MemoryManagementinLinux.sect1"></a>15.1. Linux 中的内存管理</h2></div></div></div>
<p>不是描述操作系统的内存管理理论, 本节试图指出 Linux 实现的主要特点. 尽管你不必是一位 Linux 虚拟内存专家来实现 mmap, 一个对事情如何工作的基本了解是有用的. 下面是一个相当长的对内核使用来管理内存的数据结构的描述. 一旦必要的背景已被覆盖, 我们就进入使用这个结构.</p>
<div class="sect2" lang="zh-cn">
<div class="titlepage"><div><div><h3 class="title">
<a name="AddressTypes.sect2"></a>15.1.1. 地址类型</h3></div></div></div>
<p>Linux 是, 当然, 一个虚拟内存系统, 意味着用户程序见到的地址不直接对应于硬件使用的物理地址. 虚拟内存引入了一个间接层, 它允许了许多好事情. 有了虚拟内存, 系统重运行的程序可以分配远多于物理上可用的内存; 确实, 即便一个单个进程可拥有一个虚拟地址空间大于系统的物理内存. 虚拟内存也允许程序对进程的地址空间运用多种技巧, 包括映射成员的内存到设备内存.</p>
<p>至此, 我们已经讨论了虚拟和物理地址, 但是许多细节被掩盖过去了. Linux 系统处理几种类型的地址, 每个有它自己的含义. 不幸的是, 内核代码不是一直非常清楚确切地在每个情况下在使用什么类型地地址, 因此程序员必须小心.</p>
<p>下面是一个 Linux 中使用的地址类型列表. 图 <a href="ch15.html#ldd3-15-1.fig" title="图 15.1. Linux 中使用的地址类型">Linux 中使用的地址类型</a>显示了这个地址类型如何关联到物理内存.</p>
<div class="figure">
<a name="ldd3-15-1.fig"></a><p class="title"><b>图 15.1. Linux 中使用的地址类型</b></p>
<div><img src="images/ldd3-15-1.png" alt="Linux 中使用的地址类型"></div>
</div>
<div class="variablelist"><dl>
<dt><span class="term"><span>User virtual addresses </span></span></dt>
<dd><p>这是被用户程序见到的常规地址. 用户地址在长度上是 32 位或者 64 位, 依赖底层的硬件结构, 并且每个进程有它自己的虚拟地址空间.</p></dd>
<dt><span class="term"><span>Physical addresses </span></span></dt>
<dd><p>在处理器和系统内存之间使用的地址. 物理地址是 32- 或者 64-位的量; 甚至 32-位系统在某些情况下可使用更大的物理地址.</p></dd>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -