Cでメモリを読み書きする方法はすべてわかっています。ポインタを持っており、メモリへの読み書きをしたいときに逆参照します。下位レベルでは、コントロールバスは、コントロールバス上のIO/PORTラインを設定しないことによってメモリからの読み出し要求を処理し、メモリコントローラがメモリを読み書きできるようにします。 しかし、ポート・アドレスではポート・アドレスが使用され、それらに対する読取り/書込みは制御バスがIO/PORTラインを設定することを除いてメモリの読取り/書込みと同じプロセスであるため、メモリ・コントローラは現在のバスを無視しIOコントローラは注意を払う。 x86 ASMでは、INとOUTの命令があります。しかし、Cでこれを行う方法はありますか?私はWindows 7/10(win32)環境にいます。特定のヘッダー(ウィンドウの検索に問題があります)では、_inpやinpなどの関数が存在する可能性がありますが、asmのIN命令とOUT命令と同じことを行う方法はありますか? (EDIT:INとOUTはリング0命令なので、インラインアセンブリーは使用できません)Cで制御バス上にIO/PORTラインを設定する方法
答えて
Cは、どのようにIOを実行するかを含め、どのプラットフォームからも完全に抽象です。
WindowsにはREAD_PORT_XXX
があります。
あなたのいずれかが必要これらの機能を使用することができるようにするために:
- CPL(現行特権レベルが)これはまたリング0として知られて0に等しいです。値3
- の
- IOPL(IO特権レベル)IOマップに設定された適切なビット。
最後の2つは、私が覚えている限り、Windowsではサポートされていません。
最初のものはデバイスドライバでしか実現できません。現代のOSはユーザーモードプログラムに(IOアクセスを含む)カーネル特権を与えません。
あなたは、読み取り/書き込みがIOのオフセット書き込み/読み出しに対応するポートへのアクセスを読み書きするための64KiB Control Device Objectへのアクセスを変換する非常にシンプルなドライバを書くことができます。
唯一必要なものはWDK/DDKです。
幸運にも、私はそのようなドライバソースを手にしています。
私はこれを書いたときに覚えていないので、塩の粒でそれを取る。
#include <ntddk.h>
#include <wdf.h>
#include <Wdmsec.h>
VOID IomemIoEvtIoRead (WDFQUEUE Queue, WDFREQUEST Request, size_t Length);
VOID IomemIoEvtIoWrite (WDFQUEUE Queue, WDFREQUEST Request, size_t Length);
NTSTATUS IoMemIoReadWrite(WDFREQUEST Request, size_t Length, ULONG_PTR* copied);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
WDF_DRIVER_CONFIG config;
NTSTATUS status = STATUS_UNSUCCESSFUL;
WDFDRIVER driver = NULL;
PWDFDEVICE_INIT deviceInit = NULL;
WDFDEVICE device = NULL;
WDF_IO_QUEUE_CONFIG queueConfig;
WDFQUEUE queue = NULL;
UNICODE_STRING acl, deviceName;
WDF_DRIVER_CONFIG_INIT(&config, NULL);
status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config,&driver);
if (!NT_SUCCESS(status))
return STATUS_UNSUCCESSFUL;
///////////////////////////////////////
RtlInitUnicodeString(&acl, L"D:P(A;;GA;;;WD)");
RtlInitUnicodeString(&deviceName, L"\\Device\\iomem_io");
status = STATUS_UNSUCCESSFUL;
deviceInit = WdfControlDeviceInitAllocate(driver, (PCUNICODE_STRING)&acl);
if (deviceInit)
status = WdfDeviceInitAssignName(deviceInit, (PCUNICODE_STRING)&deviceName);
if (NT_SUCCESS(status))
status = WdfDeviceCreate(&deviceInit, WDF_NO_OBJECT_ATTRIBUTES, &device);
if (!NT_SUCCESS(status))
{
WdfDeviceInitFree(deviceInit);
return status;
}
WdfControlFinishInitializing(device);
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchSequential);
queueConfig.EvtIoRead = IomemIoEvtIoRead;
queueConfig.EvtIoWrite = IomemIoEvtIoWrite;
return WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue);
}
VOID IomemIoEvtIoRead (WDFQUEUE Queue, WDFREQUEST Request, size_t Length)
{
ULONG_PTR bytesCopied = 0;
NTSTATUS status = IoMemIoReadWrite(Request, Length, &bytesCopied);
WdfRequestCompleteWithInformation(Request, status, bytesCopied);
}
VOID IomemIoEvtIoWrite (WDFQUEUE Queue, WDFREQUEST Request, size_t Length)
{
ULONG_PTR bytesCopied = 0;
NTSTATUS status = IoMemIoReadWrite(Request, Length, &bytesCopied);
WdfRequestCompleteWithInformation(Request, status, bytesCopied);
}
NTSTATUS IoMemIoReadWrite(WDFREQUEST Request, size_t Length, ULONG_PTR* copied)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
WDF_REQUEST_PARAMETERS params;
size_t io_length;
LONGLONG port;
LONG data;
PVOID buffer;
WDFMEMORY memory;
WDF_REQUEST_PARAMETERS_INIT(¶ms);
WdfRequestGetParameters(Request, ¶ms);
if (params.Type == WdfRequestTypeRead)
{
io_length = params.Parameters.Read.Length;
port = (LONGLONG)params.Parameters.Read.DeviceOffset;
}
else if (params.Type == WdfRequestTypeWrite)
{
io_length = params.Parameters.Write.Length;
port = (LONGLONG)params.Parameters.Write.DeviceOffset;
}
else
return status;
if (io_length > 4 || io_length == 3 || io_length > Length)
return status;
status = WdfRequestRetrieveOutputMemory(Request, &memory);
if (!NT_SUCCESS(status))
return status;
buffer = WdfMemoryGetBuffer(memory, NULL);
if (params.Type == WdfRequestTypeRead)
{
switch (io_length)
{
case 1: data = READ_PORT_UCHAR((PUCHAR)port); break;
case 2: data = READ_PORT_USHORT((PUSHORT)port); break;
case 4: data = READ_PORT_ULONG((PULONG)port); break;
default: return STATUS_UNSUCCESSFUL;
}
RtlCopyMemory(&data, buffer, io_length);
}
else
{
RtlCopyMemory(buffer, &data, io_length);
switch (io_length)
{
case 1: WRITE_PORT_UCHAR((PUCHAR)port, (UCHAR)data); break;
case 2: WRITE_PORT_USHORT((PUSHORT)port, (USHORT)data); break;
case 4: WRITE_PORT_ULONG((PULONG)port, data); break;
default: return STATUS_UNSUCCESSFUL;
}
}
if (copied)
*copied = io_length;
return STATUS_SUCCESS;
}
あなたは(私はあなたに残し操作)あなたは、ファイル\Device\iomem_io
を開くXオフセットに追求し、ポートからの読み取り/書き込みにそれに読み取り/書き込みすることができますをコンパイルし、このドライバをロードした後X。
あなたが回答に与えたバストポロジの説明は、最善のものと古いものです。
最新のバストポロジはより複雑で、特にPCIe以来、レガシーまたはプラットフォーム固有の機能(電源管理など)のみがIOアドレス空間を介してアクセスされます。
他のすべてはメモリマップされたIOです。
最小のカーネルドライバーがない場合:いいえ、できません。
Cには、INおよびOUTアセンブラコマンドに近いメカニズムはありません。以前はメモリマップされたI/Oをサポートしていないマシンでは初期段階では迷惑でしたが、かなり先読みで除外されていることが判明しました。今日のオペレーティングシステムのほとんどは、特権を持っているためオペレーション。
間接的にI/Oポートにアクセスするには、INまたはOUT要求を呼び出して0にするカーネルドライバが必要です。いくつかの例は、「直接I/O」を検索することによって見つけることができます。特定のタイミング要件やセキュリティをサポートする方法がないなど、かなりの数のユーザーにとって、ユーザー空間からのものを使用することは悪い習慣とみなされます。
Windowsコンパイラのいくつかのバージョンでは、直接ポートアクセスをサポートしているWindowsバージョンをターゲットにしていました。_inp()
および_outp()
ユーザプログラムから直接ポートアドレスを許可するライブラリ関数をサポートしていました。カーネルやデバイスドライバのコードではまだまだあります。
まあ、その "nuissance"はいくつかの深刻な背景を持っていました。周辺アドレス用に貴重な64Kバイトのアドレス空間を無駄にすることはありませんでした。また、アドレス範囲をデコードするために外部ロジック(AND/NAND /などのような4つの単純なゲートを持つICを使用することが多い)を単純化しました。 – Olaf
@Olaf私は、別々のI/Oとメモリアドレススペースが迷惑であるとは言いませんでした(あなたが言うように、まれなアドレススペースをI/O用に複製するのがよい理由がありました)。 ) – tofro
まあ、すべてのアーキテクチャがそれらを持っていたわけではない(そして、今日ではそれはx86上の伝統であり、埋め込まれているものでさえも)、それは問題になるだろう標準でそれらをサポートする。同様に、デフォルトで低レベルの機能を提供するようにCに指示します。周辺レジスタにアクセスするには、あまりにも多くの異なるメカニズムがあります(I/Oスペース対メモリマップだけでなく、後者は追加の手段が必要かもしれません)。このような低レベルのアクセスを忘れることはありません**常にアーキテクチャの独立した少数のドライバモジュールでカバーされるべきです。 – Olaf
- 1. C#グラフのライン制御
- 2. c#asp.netのWebページにアクセス制御ヘッダーを設定する方法は?
- 3. 制御されたインターフェイスでリモートデータベースを設定する方法
- 4. odata4jにキャッシュ制御ヘッダーを設定する方法は?
- 5. マイクロサービスのアクセス制御を設定する方法
- 6. シリアルポートのフロー制御ラインをbashスクリプトから設定しますか?
- 7. Windows/C++上でUSB TMCデバイスを制御する最も簡単な方法
- 8. IBなしでビュー上でUIButtonを制御する方法
- 9. MATLAB GUIでビデオを制御するスライダを設定する方法は?
- 10. 制御アプリケーション設定アクセス
- 11. 設定したフォーカスキーボード制御
- 12. プロット上でセルテーブルの配置を制御する方法は?
- 13. iOS上でBluetoothデバイスの音量を制御する方法は?
- 14. C#でアプリケーションのコントロール(?)を制御する方法は?
- 15. linux/C++でマスターボリュームを制御する方法は?
- 16. 別のビューコントローラでオブジェクトを制御する方法は? (Xcode:objective-c)
- 17. Visual C++でマウスの動きを制御する方法は?
- 18. C++では、cinの流れを制御する方法
- 19. レールでのユーザー設定とアクセス制御
- 20. TabActivityのアクティビティ(タブ)からの制御の設定方法
- 21. Cortex M4の補助制御レジスタビットの設定方法
- 22. ホバーでdivを制御する方法:
- 23. QListWidgetでスクロールバーを制御する方法
- 24. Opentracingでサンプリングを制御する方法
- 25. CANバス上のバス調停
- 26. OnResume()でイベントを制御するかどうかを制御する方法は?
- 27. 設定ファイルを使用して変数を制御する方法
- 28. WPF/Silverlightでヘッダー/ラインを設定する方法
- 29. フォーカスビジュアルスタイルをWPFのラインに設定する方法
- 30. Azure Appfabric Serviceバス設定エラー
Uhhh ...インラインasm? – stackptr
@stackptr INとOUTはリング0の優先順位付き命令です。それらを使用できる唯一の場所はWindowsカーネルです。典型的なWindowsアプリケーションは、リング3と4で動作します。 –
私は、現代のOSでは、これらのトラフ自身のデバイスドライバにアクセスできます(通常の想定方法で、あなたのコンテキストを利用したバグを数えずに)。 (私はOSがどのようにミックスのようなものがこれを解決しているのかわからない。ドライバはリング0でもないが、Linux OSやMSウィンドウのものにとどまっている限りドライバはほとんどが0のIIRCである) – Ped7g