2

Linux 以外のグラフィックス ドライバーを機能させるには、C ポインターを使用してアクセスする必要がある FLASH メモリにデータを保存しています (この要件は DMA 関連だと思いますが、よくわかりません)。read の呼び出しは機能しますが、FLASH と非 Linux ドライバーの間に中間 RAM バッファーを配置したくありません。

ただし、ポインターを作成して必要なアドレスを格納するだけで、Linux は無効なアクセスに関する例外を発行します。

void *ptr = 0xdeadbeef;
int a = *ptr; // invalid access!

ここで何が欠けていますか?そして、誰かがこの概念を私にとって明確にするための資料を教えてもらえますか?

mmapについて読んでいますが、これが必要かどうかわかりません。

4

3 に答える 3

4

問題は、Linux が仮想アドレス空間でプログラムを実行することです。したがって、コードで直接使用するすべてのアドレス (0xdeadbeef など) は、メモリ管理ユニットによって物理アドレスに変換される仮想アドレスであり、必ずしも仮想アドレスと同じであるとは限りません。これにより、複数の独立したプロセスとページングなどの他のものを簡単に分離できます。

問題は、あなたの場合、物理アドレスが仮想アドレス 0xdeadbeef にマップされていないため、カーネルが実行を中止することです。

すでに見つけた呼び出し mmap は、カーネルに特定のファイルを (特定のオフセットから) プロセスの仮想アドレスに割り当てるように要求します。mmap の戻りアドレスは、まったく異なるアドレスになる可能性があることに注意してください。そのため、取得した仮想アドレスについて何も仮定しないでください。

したがって、メモリデバイスのオフセットが物理アドレスである mmap と /dev/mem の例があります。カーネルがプロセスの仮想アドレスに与えたオフセットからファイルを割り当てることができた後、直接アクセスであるかのようにメモリ領域にアクセスできます。

エリアが不要になったら、そのエリアをマンマップすることを忘れないでください。そうしないと、メモリ リークに似た問題が発生します。

/dev/mem メソッドの問題の 1 つは、プロセスを実行しているユーザーがこのデバイスにアクセスする必要があることです。これにより、セキュリティの問題が発生する可能性があります (たとえば、 Samsung は最近、ハンドヘルド デバイスにそのようなセキュリティ ホールを導入しました)。

より安全な方法は、私が見つけた記事 ( The Userspace I/O HOWTO ) で説明されている方法です。これは、ユーザーのプロセスがアクセスできるメモリ領域を引き続き制御できるためです。

于 2013-01-30T14:10:02.173 に答える
1

別の方法でメモリにアクセスする必要があります。基本的に、/dev/mem を開いて mmap() を使用する必要があります。(あなたが提案したように)。簡単な例:

int openMem(unsigned int address, unsigned int size)
{
int             mmapFD;
int             page_size;
unsigned int    page_start_address;

/* Minimum page size for the mmapped region. */
mask = size - 1;

/* Get the page size. */
page_size = (int) sysconf(_SC_PAGE_SIZE);

/* We have to map shared memory to beginning of memory page so adjust 
 * memory address accordingly. */
page_start_address = address - (address % page_size);

/* Open the file that will be mapped. */

if((mmapFD = open("/dev/mem", (O_RDWR | O_SYNC))) == -1)
{
    printf("Opening shared memory device failed\n");
    return -1;
}

mmap_base_address = mmap(0, size, (PROT_READ|PROT_WRITE), MAP_SHARED, mmapFD, (off_t)page_start_address & ~mask);
if(mmap_base_address == MAP_FAILED)
{
    printf("Mapping memory failed\n");
    return -1;
}
return 0;
}

unsigned int *getAddress(unsigned int address)
{
unsigned int    log_address;

log_address = (int)((off_t)mmap_base_address + ((off_t)address & mask));

return (unsigned int*)log_address;
}

...

result = openMem(address, 0x10000);

if (result < 0)
    return result;

target_address =  getValue(address);

*(unsigned int*)target_address = value;

これにより、「値」が「アドレス」に設定されます。

于 2013-01-30T14:20:49.403 に答える
0

電話する必要がありますioremap-次のようなもの:

void *myaddr = ioremap(0xdeadbeef, size);

size はメモリ領域のサイズです。たとえば、最初の引数にページ整列アドレスを使用することをお勧めします0xdeadb000が、実際のデバイスはとにかく「0xdeadbeef」ではないと思います。

編集: ioremap の呼び出しはドライバーから行う必要があります。

于 2013-01-30T14:11:46.417 に答える