第11章メモリとI / Oアクセス
各プロセスのユーザースペースは完全に独立しており、互いに独立しており、各ユーザープロセスには異なるページテーブルがあります。カーネル空間はカーネルによって
マップされ、プロセスによって変更されることはなく、修正されます。カーネル空間の仮想アドレスから物理アドレスへのマッピングは、すべてのプロセスで共有されます
。カーネルの仮想空間は、他のプログラムから独立してい
ます
。11.3メモリアクセス11.3.1
ユーザー空間メモリの動的アプリケーションメモリの動的アプリケーションの機能ユーザースペースにはmalloc()があり、さまざまなオペレーティングシステムでこの関数を使用することは一貫しており
、malloc()によって要求されるメモリの解放関数はfree()です。Linuxの場合、Cライブラリのmalloc()関数は通常
、brk()とmmap()の2つのシステムコールを介してカーネルからのメモリに適用されます。
ユーザースペースCライブラリのmallocアルゴリズムには実際には二次管理機能があるため、すべてのアプリケーションとメモリの解放に必ずしも
カーネルへのシステムコールが伴うわけではありません。たとえば、リスト11.2のアプリケーションは、カーネルからメモリを取得した直後に
free()を呼び出すことができます。free()は以前にmallopt(M_TRIM_THRESHOLD、-1)および
mallopt(M_MMAP_MAX、0)を呼び出すため、このfree()は呼び出しません。メモリはカーネルに返されますが、Cライブラリの割り当てアルゴリズムにのみ返されます(
メモリは引き続きこのプロセスに属します)。したがって、後続のすべての動的メモリアプリケーションとリリースはユーザーモードで実行されます。
コードリスト11.2ユーザースペースメモリアプリケーションとmallot
#include <malloc.h>
#include <sys/mman.h>
#define SOMESIZE (100*1024*1024) // 100MB
int main(int argc, char *argv[])
{
unsigned char *buffer;
int i;
if (mlockall(MCL_CURRENT | MCL_FUTURE))
mallopt(M_TRIM_THRESHOLD, -1);
mallopt(M_MMAP_MAX, 0);
buffer = malloc(SOMESIZE);
if (!buffer)
exit(-1);
/*
* Touch each page in this piece of memory to get it
* mapped into RAM
*/
for (i = 0; i < SOMESIZE; i += page_size)
buffer[i] = 0;
free(buffer);
/* <do your RT-thing> */
return 0;
}
さらに、Linuxカーネルは常にデマンドページングを使用するため、malloc()が返されると、正常に
返されますが、カーネルは実際にはプロセスメモリを提供しません。この時点で、要求されたメモリを読み取ると、コンテンツはすべて0です。このページの
マッピングは読み取り専用です。特定のページが書き込まれた場合にのみ、カーネルは実際にページフォールト後にこのページをプロセスに渡します。
11.4デバイスのI / OポートとI / Oメモリアクセス
デバイスは通常、デバイスを制御し、デバイスの読み取りと書き込みを行い、デバイスのステータスを取得するための一連のレジスタ、つまり制御レジスタ、データレジスタ、およびステータス
レジスタ。これらのレジスタは、I / Oスペースに配置することも、メモリスペースに配置することもできます。I / Oスペースにある場合、通常はI / O
ポートと呼ばれ、メモリスペースにある場合、対応するメモリスペースはI / Oメモリと呼ばれます。
11.4.1 Linux I / OポートおよびI / Oメモリアクセスインターフェイス
1.I / Oポート
Linuxデバイスドライバでは、Linuxカーネルによって提供される機能を使用して、I / Oスペースにあるポートにアクセスする必要があります。これらの機能には次のものがあります。次の
種類。
1)バイトポート(8ビット幅)の読み取りと書き込み。
unsigned inb(unsigned port);
void outb(unsigned char byte、unsigned port);
2)ワードポート(16ビット幅)の読み取りと書き込み。
unsigned inw(unsigned port);
void outw(unsigned short word、unsigned port);
3)ロングワードポート(32ビット幅)の読み取りと書き込み。
unsigned
inl (unsigned port); void outl(unsigned longword、unsigned port);
4)バイト文字列の読み取りと書き込み。
void insb(unsigned port、void * addr、unsigned long count);
void outsb(unsigned port、void * addr、unsigned long count);
5)insb()ポートポートからカウントバイトを読み取り、読み取り結果はに書き込まれます。 addrが指すメモリ; outsb()
は、addrが指すメモリ内のcountバイトをportで始まるポートに継続的に書き込みます。
6)単語の文字列を読み書きします。
void insw(unsigned port、void * addr、unsigned long count);
void outsw(unsigned port、void * addr、unsigned long count);
7)長い単語の文字列を読み書きします。
void insl(unsigned port、void * addr、unsigned long count);
void outsl(unsigned port、void * addr、unsigned long count);
上記の関数のI / Oポート番号ポートのタイプは、特定のハードウェアプラットフォームに大きく依存します、したがって、ここには符号なしのみが書き込まれます。
2.
I / OメモリカーネルのI / Oメモリ(通常、チップ内のI2C、SPI、USB、その他のコントローラのレジスタ、または外部メモリバス上のデバイス)にアクセスする前に、ioremap()を使用する必要があります。デバイスを設定する機能物理アドレスは仮想アドレスにマッピングされます。ioremap()の
プロトタイプは次のとおりです
。void* ioremap(unsigned long offset、unsigned long size);
ioremap()はvmalloc()に似ており、新しいページテーブルを作成する必要がありますが、実行されません。 vmalloc()
割り当て動作で実行されるメモリ。ioremap()は、特定の物理アドレス範囲にアクセスするために使用できる特別な仮想アドレスを返します。この仮想
アドレスは、vmallocマッピング領域にあります。ioremap()によって取得された仮想アドレスは、iounmap()関数によって解放される必要があり、そのプロトタイプは次のとおりです。
void iounmap(void * addr);
11.4.4デバイスアドレスのユーザースペース
へのマッピング1.メモリマッピングとVMA
ユーザースペースは不可能であり、デバイスに直接アクセスしないでください。ただし、mmap()
関数はデバイスドライバーに実装できるため、ユーザースペースを作成できます。直接アクセスデバイスの物理アドレス。ユーザースペースのメモリセグメントをデバイスメモリに関連付けます。ユーザーがユーザースペースのこのアドレス範囲に
アクセスすると、実際にはデバイスへのアクセスに変換されます。
この機能は、ディスプレイアダプタなどのデバイスにとって非常に意味があります。ユーザースペースがメモリマップを介してビデオメモリに直接アクセスできる場合
、画面フレームの各ピクセルは、ユーザースペースからカーネルスペースにコピーするプロセスを必要としなくなります。
mmap()は、PAGE_SIZEの単位でマップする必要があります。実際、メモリはページの単位でのみマップできます
。PAGE_SIZEの整数倍ではないアドレス範囲をマップする場合は、最初にページの位置合わせを実行して、 PAGE_SIZEの倍数でのマッピング。
file_operationsファイルの操作構造から、ドライバーのmmap()関数のプロトタイプは次のようになっていることがわかります。int
(* mmap)(struct file *、struct vm_area_struct *);
ドライバーのmmap()関数は次のようになります。ユーザーシステムでmmap()を実行する呼び出されると最終的に呼び出されます
。mmap ()システム呼び出しのプロトタイプは、以下に示すように、file_operationsのmmap()のプロトタイプとは大きく異なります
。caddr_tmmap(caddr_t addr、size_t len、int prot、int flags、int fd、off_t offset);
ユーザーがmmap()を呼び出すと、カーネルは次の処理を実行します。
1)プロセスの仮想空間でVMAの一部を見つけます。2)このVMAをマッピングします。
3)デバイスドライバーまたはファイルシステムのfile_operationsがmmap()操作を定義している場合は、それを呼び出します。
4)このVMAをプロセスのVMAリンクリストに挿入します。
file_operationsのmmap()関数の最初のパラメーターは、ステップ1)で見つかったVMAです。
mmap()システムコールによってマップされたメモリは、munmap()によってマップ解除できます。この関数のプロトタイプは次のとおりです
。intmunmap(caddr_t addr、size_t len);
ほとんどのデバイスドライバは、デバイスメモリをユーザースペースにマッピングする機能を提供する必要はありません。シリアルポートなどのストリーム指向の
デバイスの場合、この種のマッピングを実装することは無意味だからです。ディスプレイ、ビデオ、その他のデバイスの場合、マッピングを確立すると、ユーザースペースとカーネルスペース間の
メモリコピーを減らすことができます。
11.5 I / Oメモリの静的マッピング
周辺I / Oメモリの物理アドレスから仮想アドレスへの静的マッピングを確立します
map_descmap_desc構造
体structmap_desc { unsigned long virtual; / *仮想アドレス* / unsigned long pfn; / * __phys_to_pfn(phy_addr)* / unsigned long length; / *サイズ* / unsignedintタイプ; / *タイプ* / };
静的構造体map_desc ixdp2x01_io_desc _ _initData = { .virtual = IXDP2X01_VIRT_CPLD_BASE、 .pfn = _ _phys_to_pfn(IXDP2X01_PHYS_CPLD_BASE)、 .LENGTH = IXDP2X01_CPLD_REGION_SIZE、 .TYPE = MT_DEVICE }。static void _ _init ixdp2x01_map_io(void){ ixp2000_map_io(); iotable_init(&ixdp2x01_io_desc、1); //建立页写射}
11.6 DMA
DMAは、CPUの関与なしに、周辺機器とシステムメモリ間の双方向データ転送を可能にするハードウェアメカニズムです。DMA
を使用すると、システムCPUが実際のI / Oデータ送信プロセスを排除できるため、システムのスループットが大幅に向上します。
DMAモードでのデータ送信は、DMAコントローラー(DMAC)によって制御されます。送信中、CPUは他のタスクを同時に実行できます。
DMAが終了すると、DMACはデータ転送が割り込みによって終了したことをCPUに通知し、CPUは
後処理のために対応する割り込みサービスルーチンを実行します。
第12章Linuxデバイスドライバーのソフトウェアアーキテクチャの考え方