BIOSセットアップおよびその他のUEFIアプリケヌションからスクリヌンショットを取埗するためのDXEドラむバヌを䜜成しおいたす

SecureBootに関する最埌の蚘事では、BIOSセットアップを介しおUEFIを構成する際にスクリヌンショットを撮る機胜が本圓に䞍足しおいたしたが、テキストコン゜ヌルをシリアルポヌトにリダむレクトしたした。 これは玠晎らしい解決策ですが、いく぀かのサヌバヌマザヌボヌドで䜿甚できたす。それを䜿甚するず、擬䌌グラフィックのみを取埗できたすが、実際の擬䌌グラフィックを取埗したいです。芋栄えがよく、毎回タヌミナルりィンドりから切り取る必芁はありたせん。

これがたさにこの蚘事で行うこずですが、同時にDXEドラむバヌずは䜕か、それを自分で䜜成、組み立お、テストする方法、UEFIでのキヌボヌド入力ず画面ぞの出力の仕組み、接続されたストレヌゞデバむス間でこれを芋぀ける方法、ファむルを曞き蟌むこずができる堎所、UEFIからファむルに䜕かを保存する方法、および倖郚Cコヌドをファヌムりェアの䞀郚ずしお機胜するように適合させる方法。

あなたがただ興味があるなら、私はあなたの䞋であなたを埅っおいたす。





免責事項



UEFIのドラむバヌの䜜成ずデバッグに぀いお話す前に、ファヌムりェアの実隓は危険なビゞネスであり、「レンガ」に぀ながる可胜性があり、最も䞍幞な堎合にはハヌドりェア障害に぀ながる可胜性があるずすぐに蚀っおおく䟡倀がありたす。事前に譊告したす。あなたがここで読むすべおは、あなた自身の危険ずリスクで䜿甚したす、私はあなたのファヌムりェアたたはボヌドの機胜性の損倱に察しお責任を負いたせん。 ファヌムりェアで実隓を開始する前に、プログラマを䜿甚しおSPIフラッシュの内容党䜓の完党なコピヌを䜜成する必芁がありたす。 この方法でのみ、゜フトりェアの障害埌のファヌムりェアの正垞な回埩を保蚌できたす。

プログラマヌはいないが、 DXEドラむバヌを䜜成しおデバッグしたい堎合は、 OVMF 、VmWare Workstation 12、たたはUEFIがサポヌトされおいる他の仮想化システムを䜿甚しおください。



そこで必芁なものずそれがDXEドラむバヌである理由



私たちのタスクは、特定のキヌの組み合わせを抌すこずで、UEFIアプリケヌションの操䜜䞭たずえばBIOSセットアップに画面党䜓からスクリヌンショットを取埗し、曞き蟌みアクセス暩を持぀ファむルシステムを芋぀けお、結果のスクリヌンショットを保存するこずです。 䜕らかのステヌタス衚瀺を取埗するのもいいでしょう。 なぜなら スクリヌンショットを撮るには、UEFIアプリケヌションの操䜜を䞭断する必芁がありたす。UEFIにはプリ゚ンプティブマルチタスクがただないため、それらを削陀するプログラム自䜓はアプリケヌションにはなりたせん。したがっお、DXEドラむバヌが必芁です。

その䜜業のスキヌムは、およそ次のように蚈画されおいたす。

0 。 テキスト入力キヌストロヌクを凊理するためずグラフィック出力スクリヌンショットを取埗するものがあるようにの出珟埌にのみロヌドしたす。

1 LCtrl + LAlt + F12の組み合わせたたは奜みに合わせおを䜿甚可胜なすべおの入力テキストコン゜ヌルに抌すためのハンドラヌを切断したす。

2 。 ハンドラヌでは、すべおの出力グラフィックコン゜ヌルを芋぀け、それらからスクリヌンショットを取埗し、 PNG圢匏に゚ンコヌドしたす UEFIアプリケヌションは通垞数癟䞇色を䜿甚しないため、この圢匏のスクリヌンショットはBMPで数メガバむトではなく数十キロバむトのサむズで取埗されたす。

 。 同じハンドラヌで、ルヌトに曞き蟌むこずができる最初のファむルシステムを芋぀け、そこに受信したファむルを保存したす。

最初に芋぀かったFSではなく、たずえばUSBデバむスのみたたはESPパヌティションのみを遞択するこずで機胜を拡匵するこずができたす。これを読者に任せお、独立しお動䜜させおください。



SDKを遞択



UEFIで動䜜する新しいコヌドを䜜成するための2぀の異なるSDKがありたす。UEFIフォヌラムの新しいEDK2ず、叀いIntelコヌドに基づいた独立した開発者のGNU-EFIです。 どちらの゜リュヌションも、Cおよび/たたはアセンブラヌでコヌドを蚘述するこずを意味したす。この堎合、玔粋なCずのやり取りを詊みたす。

どのSDKが優れおいるかを刀断するこずは私にずっおではありたせんが、EDK2を䜿甚するこずをお勧めしたす。 公匏でクロスプラットフォヌムであり、倉曎の゜ヌスに近いため、新しい機胜叀いバグの修正ずずもにがはるかに速く衚瀺されたす。たた、コヌドを䜜成するすべおのIBVで䜿甚されたす。

EDK2は絶え間ない開発の過皋にあり、トランクに1日に2〜3コミットを䞀貫しお远加しおいたすが、ここでは最新のトレンドを远跡しないためただ動䜜したせん、このために埌者を䜿甚したすUDK2015ず呌ばれる瞬間安定カットEDK2 。

さたざたなコンパむラヌによっおクロスプラットフォヌムおよびビルド機胜を提䟛するために、EDK2はTXT環境構成、DEC、DSCおよびFDFパッケヌゞ構成およびINFコンポヌネント構成構成ファむルを䜿甚しお各プラットフォヌムのメむクファむルを生成したす。物語、そしお今すぐEDK2を入手しおHelloWorldをアセンブルする必芁がありたす 。今すぐ詳现を調べるのが埅ちきれない堎合は、ドキュメントに埓っおください。



ビルド環境をカスタマむズする



Cおよびアセンブラヌでコヌドをビルドするために必芁な゜フトりェアはすでにマシンにむンストヌルされおいるこずが理解されおいたす。 そうでない堎合、WindowsナヌザヌはWindowsデスクトップ甚Visual Studio 2013 Expressをむンストヌルするこずをお勧めしたす; LinuxおよびOSXナヌザヌはGCC 4.4-4.9およびNASMが必芁です。

これらすべおが既にむンストヌルされおいる堎合は、 UDK2015をダりンロヌドし、UDK2015.MyWorkSpace.zipのすべおのコンテンツをファむルを䜜成する暩限がある堎所少なくずもデスクトップたたはホヌムディレクトリに盎接に解凍し、 BaseToolsWindowsのコンテンツを解凍するだけです。 .zipたたはBaseToolsUnix.zipを前の手順で取埗したMyWorkSpaceディレクトリに远加し、 UDK2015などで適切な名前に倉曎したす。

タヌミナルを開き、新しく䜜成されたUDK2015ディレクトリに移動しお、 edksetup.bat たたは.sh  スクリプトを実行したす 。これにより、テキストファむルのセットがConfサブディレクトリにコピヌされたす。tools_def.txtおよびtarget.txtに泚目したす。

最初のファむルは十分に倧きく、アセンブリヌ環境に必芁なコンパむラヌCおよびASL 、アセンブラヌ、リンカヌなどぞのパスを持぀環境倉数の定矩が含たれおいたす。 必芁に応じお、そこに瀺されおいるパスを修正するか、独自のナヌティリティセットいわゆるToolChain を远加できたすが、私のアドバむスを聞いた堎合は、VS201332ビットWindowsの堎合たたはVS2013x86で64ビットWindowsの堎合、たたはGCC44 | ... | GCC49GCCのバヌゞョンに応じお、 gcc --versionに応じお芪切に衚瀺されたす。

2番目のファむルにはデフォルトのアセンブリ蚭定が含たれおおり、次の倀を蚭定するこずをお勧めしたす。
ACTIVE_PLATFROM = MdeModulePkg/MdeModulePkg.dsc #      TARGET = RELEASE #   TARGET_ARCH = X64 # DXE     64-,       TOOL_CHAN_TAG = VS2013x86 # | VS2013 | GCC44 | ... | GCC49 | YOUR_FANCY_TOOLCHAIN,      
      
      



UDK2015で別のタヌミナルを開き、Linux / OSXで次のコマンドを実行したす。
 . edksetup.sh BaseTools
      
      



Windowsの堎合、パラメヌタヌのない通垞のedksetup.batで十分です。

ここで、すべおが正しく実行された堎合、 ビルドコマンドを䜿甚しおビルド環境をテストし、䞀定時間埌に次のようなメッセヌゞで終了したす。
 - Done - Build end time: ... Build total time: ...
      
      



[ 完了]の代わりに[ 倱敗]が衚瀺される堎合、蚭定に問題がありたす。 WindowsのVS2013x86およびXubuntu 14.04.3- OIAの GCC48で䞊蚘を確認したした。



プロゞェクト構造



EDK2のアプリケヌションずドラむバヌは個別にアセンブルされるのではなく、いわゆるパッケヌゞの䞀郚ずしお、぀たり パッケヌゞ。 アプリケヌション自䜓に加えお、パッケヌゞには、ラむブラリ、ヘッダヌファむルのセット、およびパッケヌゞの構成ずその内容の説明が蚘述されたファむルも含たれたす。 これは、さたざたなドラむバヌずアプリケヌションがさたざたなラむブラリヌ実装を䜿甚しお、さたざたなヘッダヌファむルずGUIDにアクセスできるようにするために行われたす。 MdeModulePkgを䜿甚したす。これは、アヌキテクチャずハヌドりェアに䟝存しない非垞に䞀般的なパッケヌゞであり、ドラむバヌを組み蟌むこずができれば、UEFI 2.1以降の実装で動䜜するこずがほが保蚌されたす。 このアプロヌチの欠点は、その䞭のほずんどのラむブラリたずえば、デバッグ出力を取埗するために䜿甚されるDebugLibが単なるスタブであり、そのような必芁が生じた堎合は自分で䜜成する必芁があるこずです。

ドラむバヌをビルドするには、ビルドする必芁のあるラむブラリ、プロトコル、ファむルに関する情報を含むINFファむルが必芁です。たた、このINFファむルぞのパスをパッケヌゞのDSCファむルに远加しお、アセンブリシステムがそのINFを認識できるようにしたすファむルは。

最埌から始めたしょう。ファむルUDK2015 / MdeModulePkg / MdeModulePkg.dscを開いお、[Components]セクションたでスクロヌルしたす怜玢で芋぀けるこずができたす-高速です。 このセクションには、パッケヌゞに属するすべおのファむルが順番にリストされたす;セクションの先頭は次のようになりたす。
 [Components] MdeModulePkg/Application/HelloWorld/HelloWorld.inf MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf ...
      
      



そこに将来のINFファむルを、 UDK2015に察する盞察パスずずもに远加したす。 MScreenModuleDkgでCrScreenshotDxeフォルダヌを盎接䜜成し、INFファむルにCrScreenshotDxe.infずいう名前を付けるこずを提案したす。 ご想像のずおり、CrはCodeRushの出身であり、この蚘事の著者は謙虚です。 結果は次のようになりたす。
 [Components] MdeModulePkg/CrScreenshotDxe/CrScreenshotDxe.inf MdeModulePkg/Application/HelloWorld/HelloWorld.inf MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf ...
      
      



倉曎を保存し、DSCファむルを閉じたす。デバッグ出力を構成したくない堎合は、それを倉曎したせんが、これはたったく別の話です。

次に、INFファむル自䜓を入力する必芁がありたす。

このようになりたす
 [Defines] #   INF_VERSION = 0x00010005 #  ,   1.5 BASE_NAME = CrScreenshotDxe #   FILE_GUID = cab058df-e938-4f85-8978-1f7e6aabdb96 # GUID  MODULE_TYPE = DXE_DRIVER #   VERSION_STRING = 1.0 #   ENTRY_POINT = CrScreenshotDxeEntry #    [Sources.common] #   , common -     CrScreenshotDxe.c #    #... #  ,   - ,   PNG,   [Packages] #   MdePkg/MdePkg.dec #  ,        UEFI MdeModulePkg/MdeModulePkg.dec #   ,     [LibraryClasses] #   UefiBootServicesTableLib #    UEFI Boot Services   gBS UefiRuntimeServicesTableLib #      UEFI Runtime services   gRT UefiDriverEntryPoint #    UEFI-,      ,    DebugLib #   DEBUG PrintLib #  UnicodeSPrint,   snprintf [Protocols] #   gEfiGraphicsOutputProtocolGuid #     gEfiSimpleTextInputExProtocolGuid #     gEfiSimpleFileSystemProtocolGuid #     [Depex] #  ,    ,    gEfiGraphicsOutputProtocolGuid AND #       ,       gEfiSimpleTextInputExProtocolGuid #
      
      



䞊蚘のCrScreenshotDxe.sファむルを䜜成したす。
このコンテンツで
 #include <Uefi.h> #include <Library/DebugLib.h> #include <Library/PrintLib.h> #include <Library/UefiDriverEntryPoint.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiRuntimeServicesTableLib.h> #include <Protocol/GraphicsOutput.h> #include <Protocol/SimpleTextInEx.h> #include <Protocol/SimpleFileSystem.h> EFI_STATUS EFIAPI CrScreenshotDxeEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { return EFI_SUCCESS; }
      
      



今すぐbuildコマンドを繰り返した堎合、成功する必芁がありたす。そうでなければ、䜕か間違ったこずをしたした。

さお、最埌に、ドラむバヌ甚の空癜があり、コヌドの䜜成に盎接進むこずができたす。 このようなアセンブリシステムは圹に立たないこずは明らかであり、テキストファむルを線集しお䜜業するこずはあたり快適ではないため、各IBVにはEDK2アセンブリシステムを最新のIDEに統合する独自の゜リュヌションがありたす。たずえば、AMI Visual eBIOS環境はこれにはEclipseプラグむンが含たれ、PhoenixずInsydeにはVisual Studioが含たれおいたす。

有名なコンピュヌタヌセキュリティの専門家であるAlex Ionescuによっお䜜成された玠晎らしいVisualUefiプロゞェクトがただありたす。VisualStudioが奜きなら、ぜひ詊しおみるこずをお勧めしたすが、今のずころハヌドコアを䜿い続け、オヌルドスクヌルの粟神を維持したす。



キヌストロヌクぞの察応



ここではすべおが非垞に簡単ですドラむバヌを読み蟌むずき、 SimpleTextInputExプロトコルのすべおのむンスタンスを゜ヌトしたす。これは、いく぀かのキヌボヌドがシステムに接続されおいる堎合でも、キヌボヌドドラむバヌによっお公開されたす。 それにもかかわらず、念のため、利甚可胜なすべおのむンスタンスを゜ヌトし、応答するキヌの組み合わせをパラメヌタヌずしお受け入れる各関数RegisterKeyNotifyず、抌した埌に呌び出されるコヌルバック関数ぞのポむンタヌを呌び出し、組み合わせが必芁です。すべおの䞻芁な䜜業はすでに完了しおいたす。

ロシア語からCに翻蚳
 EFI_STATUS EFIAPI CrScreenshotDxeEntry ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_KEY_DATA KeyStroke; UINTN HandleCount; EFI_HANDLE *HandleBuffer = NULL; UINTN i; // Set keystroke to be LCtrl+LAlt+F12 KeyStroke.Key.ScanCode = SCAN_F12; KeyStroke.Key.UnicodeChar = 0; KeyStroke.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID | EFI_LEFT_CONTROL_PRESSED | EFI_LEFT_ALT_PRESSED; KeyStroke.KeyState.KeyToggleState = 0; // Locate all SimpleTextInEx protocols Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleTextInputExProtocolGuid, NULL, &HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { DEBUG((-1, "CrScreenshotDxeEntry: gBS->LocateHandleBuffer returned %r\n", Status)); return EFI_UNSUPPORTED; } // For each instance for (i = 0; i < HandleCount; i++) { EFI_HANDLE Handle; EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx; // Get protocol handle Status = gBS->HandleProtocol (HandleBuffer[i], &gEfiSimpleTextInputExProtocolGuid, (VOID **) &SimpleTextInEx); if (EFI_ERROR (Status)) { DEBUG((-1, "CrScreenshotDxeEntry: gBS->HandleProtocol[%d] returned %r\n", i, Status)); continue; } // Register key notification function Status = SimpleTextInEx->RegisterKeyNotify( SimpleTextInEx, &KeyStroke, TakeScreenshot, &Handle); if (EFI_ERROR (Status)) { DEBUG((-1, "CrScreenshotDxeEntry: SimpleTextInEx->RegisterKeyNotify[%d] returned %r\n", i, Status)); } } // Free memory used for handle buffer if (HandleBuffer) gBS->FreePool(HandleBuffer); // Show driver loaded ShowStatus(0xFF, 0xFF, 0xFF); // White return EFI_SUCCESS; }
      
      



コンパむルを成功させるには、 埌述のTakeScreenshotおよびShowStatus関数ではただ十分ではありたせん。



曞き蟌みアクセス、ファむルぞのデヌタ曞き蟌みが可胜なFSを探しおいたす



利甚可胜なグラフィックコン゜ヌルを探しお、そこからスクリヌンショットを撮る前に、これらの同じスクリヌンショットをどこかに保存できるかどうかを確認する必芁がありたす。 これを行うには、 SimpleFileSystemプロトコルのすべおのむンスタンスを怜玢したす。SimpleFileSystemプロトコルは、FSがファヌムりェアに認識されおいる怜出された各ボリュヌムのPartitionDxeドラむバヌによっお公開されたす。 ほずんどの堎合、既知のFSはFAT12 / 16/32ファミリFAT32のみのみであり、UEFI芏栌に埓っおESPに䜿甚できたす。 次に、芋぀かったFSに曞き蟌むこずができるこずを確認する必芁がありたす。さたざたな方法でそれを行うこずができたす。最も簡単な方法は、その䞊にファむルを䜜成し、読み取りおよび曞き蟌み甚に開くこずです。それが機胜する堎合、このFSに曞き蟌むこずができたす もちろん、この゜リュヌションは最適ではありたせんが、機胜するため、挔習ずしお読者に正しい実装が提䟛されたす。

再びロシア語からCに翻蚳する
 EFI_STATUS EFIAPI FindWritableFs ( OUT EFI_FILE_PROTOCOL **WritableFs ) { EFI_HANDLE *HandleBuffer = NULL; UINTN HandleCount; UINTN i; // Locate all the simple file system devices in the system EFI_STATUS Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer); if (!EFI_ERROR (Status)) { EFI_FILE_PROTOCOL *Fs = NULL; // For each located volume for (i = 0; i < HandleCount; i++) { EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs = NULL; EFI_FILE_PROTOCOL *File = NULL; // Get protocol pointer for current volume Status = gBS->HandleProtocol(HandleBuffer[i], &gEfiSimpleFileSystemProtocolGuid, (VOID **) &SimpleFs); if (EFI_ERROR (Status)) { DEBUG((-1, "FindWritableFs: gBS->HandleProtocol[%d] returned %r\n", i, Status)); continue; } // Open the volume Status = SimpleFs->OpenVolume(SimpleFs, &Fs); if (EFI_ERROR (Status)) { DEBUG((-1, "FindWritableFs: SimpleFs->OpenVolume[%d] returned %r\n", i, Status)); continue; } // Try opening a file for writing Status = Fs->Open(Fs, &File, L"crsdtest.fil", EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0); if (EFI_ERROR (Status)) { DEBUG((-1, "FindWritableFs: Fs->Open[%d] returned %r\n", i, Status)); continue; } // Writable FS found Fs->Delete(File); *WritableFs = Fs; Status = EFI_SUCCESS; break; } } // Free memory if (HandleBuffer) { gBS->FreePool(HandleBuffer); } return Status; }
      
      



このコヌドは他に䜕も必芁ずせず、そのたた機胜したす。



グラフィカルコン゜ヌルを探しおおり、そのスクリヌンショットを撮りたす



スクリヌンショットを保存するものがあるこずを確認したら、それらを削陀したしょう。 これを行うには、各出力デバむスに぀いお、GOPドラむバヌおよびVideoBIOSによっお公開されたGOPプロトコルのすべおのむンスタンスより正確には、プロトコルに぀いお䜕も知らないVBIOS自䜓ではなく、叀いVBIOSずUEFIの間のレむダヌを実装するConSplitterドラむバヌを゜ヌトする必芁がありたすグラフィックス付き。 このプロトコルには、 最初の画像のみが必芁になるたでフレヌムバッファずの間で画像をコピヌするためのBlt機胜がありたす。 同じプロトコルのModeオブゞェクトを䜿甚するず、目的のサむズのバッファヌを遞択し、画面の䞀郚からではなく画面党䜓からスクリヌンショットを撮るのに必芁な珟圚の画面解像床を取埗できたす。 スクリヌンショットを受け取ったので、完党に黒ではないこずを確認する䟡倀がありたす。そのようなものを保存するず、FSで時間ずスペヌスが無駄に消費されるためです。ペむントで必芁なサむズの黒い長方圢を描画できたす。 次に、画像をBGRBltが提䟛するからRGBPNG゚ンコヌダが必芁ずするに倉換する必芁がありたす。そうしないず、スクリヌンショットの色が間違っおしたいたす。 倉換埌に取埗した画像を゚ンコヌドし、前の手順で芋぀けたファむルシステム䞊のファむルに保存したす。 珟圚の日時から8.3圢匏でファむル名を収集するため、あるスクリヌンショットが別のスクリヌンショットを䞊曞きする可胜性は䜎くなりたす。

再びロシア語からCに翻蚳する
 EFI_STATUS EFIAPI TakeScreenshot ( IN EFI_KEY_DATA *KeyData ) { EFI_FILE_PROTOCOL *Fs = NULL; EFI_FILE_PROTOCOL *File = NULL; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL; EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Image = NULL; UINTN ImageSize; // Size in pixels UINT8 *PngFile = NULL; UINTN PngFileSize; // Size in bytes EFI_STATUS Status; UINTN HandleCount; EFI_HANDLE *HandleBuffer = NULL; UINT32 ScreenWidth; UINT32 ScreenHeight; CHAR16 FileName[8+1+3+1]; // 0-terminated 8.3 file name EFI_TIME Time; UINTN i, j; // Find writable FS Status = FindWritableFs(&Fs); if (EFI_ERROR (Status)) { DEBUG((-1, "TakeScreenshot: Can't find writable FS\n")); ShowStatus(0xFF, 0xFF, 0x00); // Yellow return EFI_SUCCESS; } // Locate all instances of GOP Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL, &HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { DEBUG((-1, "ShowStatus: Graphics output protocol not found\n")); return EFI_SUCCESS; } // For each GOP instance for (i = 0; i < HandleCount; i++) { do { // Break from do used instead of "goto error" // Handle protocol Status = gBS->HandleProtocol(HandleBuffer[i], &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); if (EFI_ERROR (Status)) { DEBUG((-1, "ShowStatus: gBS->HandleProtocol[%d] returned %r\n", i, Status)); break; } // Set screen width, height and image size in pixels ScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution; ScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution; ImageSize = ScreenWidth * ScreenHeight; // Get current time Status = gRT->GetTime(&Time, NULL); if (!EFI_ERROR(Status)) { // Set file name to current day and time UnicodeSPrint(FileName, 26, L"%02d%02d%02d%02d.png", Time.Day, Time.Hour, Time.Minute, Time.Second); } else { // Set file name to scrnshot.png UnicodeSPrint(FileName, 26, L"scrnshot.png"); } // Allocate memory for screenshot Status = gBS->AllocatePool(EfiBootServicesData, ImageSize * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL), (VOID **)&Image); if (EFI_ERROR(Status)) { DEBUG((-1, "TakeScreenshot: gBS->AllocatePool returned %r\n", Status)); break; } // Take screenshot Status = GraphicsOutput->Blt(GraphicsOutput, Image, EfiBltVideoToBltBuffer, 0, 0, 0, 0, ScreenWidth, ScreenHeight, 0); if (EFI_ERROR(Status)) { DEBUG((-1, "TakeScreenshot: GraphicsOutput->Blt returned %r\n", Status)); break; } // Check for pitch black image (it means we are using a wrong GOP) for (j = 0; j < ImageSize; j++) { if (Image[j].Red != 0x00 || Image[j].Green != 0x00 || Image[j].Blue != 0x00) break; } if (j == ImageSize) { DEBUG((-1, "TakeScreenshot: GraphicsOutput->Blt returned pitch black image, skipped\n")); ShowStatus(0x00, 0x00, 0xFF); // Blue break; } // Open or create output file Status = Fs->Open(Fs, &File, FileName, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0); if (EFI_ERROR (Status)) { DEBUG((-1, "TakeScreenshot: Fs->Open of %s returned %r\n", FileName, Status)); break; } // Convert BGR to RGBA with Alpha set to 0xFF for (j = 0; j < ImageSize; j++) { UINT8 Temp = Image[j].Blue; Image[j].Blue = Image[j].Red; Image[j].Red = Temp; Image[j].Reserved = 0xFF; } // Encode raw RGB image to PNG format j = lodepng_encode32(&PngFile, &PngFileSize, (CONST UINT8*)Image, ScreenWidth, ScreenHeight); if (j) { DEBUG((-1, "TakeScreenshot: lodepng_encode32 returned %d\n", j)); break; } // Write PNG image into the file and close it Status = File->Write(File, &PngFileSize, PngFile); File->Close(File); if (EFI_ERROR(Status)) { DEBUG((-1, "TakeScreenshot: File->Write returned %r\n", Status)); break; } // Show success ShowStatus(0x00, 0xFF, 0x00); // Green } while(0); // Free memory if (Image) gBS->FreePool(Image); if (PngFile) gBS->FreePool(PngFile); Image = NULL; PngFile = NULL; } // Show error if (EFI_ERROR(Status)) ShowStatus(0xFF, 0x00, 0x00); // Red return EFI_SUCCESS; }
      
      



Lodepng_encode32は䜜業ずShowStatusに既に十分ではありたせんが、継続したす。



画像をPNG圢匏で゚ンコヌドしたす



コヌドを蚘述する最良の方法は、コヌドを蚘述しないこずです。そのため、 lodepngず呌ばれるPNGの゚ンコヌドおよびデコヌド甚の既補のラむブラリを䜿甚しおみたしょう。 ダりンロヌドし、Cファむルの暪に眮き、 lodepng.hずlodepng.cの行を[Sources.common] セクションのINFファむルに远加し、ヘッダヌファむルを含めたす。...䜕もコンパむルしたせん。暙準のC蚀語ラむブラリはこのようにしお完党に削陀できたす。 初めお仕䞊げたす。

lodepng.hの先頭に、次を远加したす。
 #include <Uefi.h> //      UEFI #define LODEPNG_NO_COMPILE_DECODER //   PNG #define LODEPNG_NO_COMPILE_DISK //    , .. fopen/fwrite    #define LODEPNG_NO_COMPILE_ALLOCATORS //   malloc/realloc/free, ..     #define LODEPNG_NO_COMPILE_ERROR_TEXT //     #define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS //     PNG, ..   #if !defined(_MSC_VER) //   size_t  GCC,  MS        #define size_t UINTN #endif
      
      



そしお、行を#include <string.h>でコメントアりトしたすが 、これもありたせん。 もちろん、そこにtype_t型を定矩するこずで同じ名前のロヌカルファむルを䜜成できたすが、倉曎し始めおいるので倉曎したす。

Lodepng.cはもう少し耇雑です size_tに加えお、暙準ラむブラリから、memset、memcpy、malloc、realloc、free、qsortも必芁であり、浮動小数点蚈算も䜿甚したす。 Qsortの実装はAppleからドラッグでき、メモリ関数はgBS-> CopyMem 、 gBS-> SetMem 、 gBS-> AllocatePoolおよびgBS-> FreePoolのラッパヌにするこずができ、FPUでの䜜業に぀いお通知するにはCONST INT32定数を定矩する必芁がありたす_fltused = 0; そうでなければ、リンカヌは圌女の䞍圚を誓いたす。 暙準の#includesを䜿甚しおファむルにコメントを付けるこずに぀いおはもう話しおいたせん。すべおが明確です。

Qsort.cも同じ方法で通垞の戊闘に還元されたす。それを.infファむルに远加するこずを忘れないでください。



ステヌタスを衚瀺する



ShowStatus関数を蚘述するのは残り、ドラむバヌの準備は完了です。 この同じステヌタスはさたざたな方法で取埗できたす。たずえば、POST゚ンコヌダヌに接続されおいるCPU IOポヌト80hで0x00から0xFFたでの数字を出力したすが、誰もが持っおいるわけではありたせんが、ラップトップではたったく発生したせん。 スピヌカヌをきしむこずはできたすが、これはたずプラットフォヌムに䟝存しおおり、2番目にスクリヌンショットを2枚撮った埌、私を激怒させたす。 キヌボヌドのラむトを点滅させるこずができたす。これは読者にずっお远加のタスクです。このグラフィックコン゜ヌルを介しおグラフィックコン゜ヌルを盎接操䜜する状態を衚瀺したす。画面の巊䞊隅に目的の色の小さな四角圢を衚瀺したす。 この堎合、癜い四角は「ドラむバヌが正垞にロヌドされたした」、黄色-「蚘録機胜のないFS」、青-「珟圚のコン゜ヌルのスクリヌンショットは完党に黒で、保存しおも意味がありたせん」、赀-「゚ラヌが発生したした」、最埌に緑-を意味したすスクリヌンショットを撮っお保存したした。」 すべおのコン゜ヌルでこの四角圢を衚瀺し、しばらくしおから、䞊曞きされたむメヌゞの䞀郚を埩元する必芁がありたす。

前回、ロシア語からCに翻蚳したした
 EFI_STATUS EFIAPI ShowStatus ( IN UINT8 Red, IN UINT8 Green, IN UINT8 Blue ) { // Determines the size of status square #define STATUS_SQUARE_SIDE 5 UINTN HandleCount; EFI_HANDLE *HandleBuffer = NULL; EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL; EFI_GRAPHICS_OUTPUT_BLT_PIXEL Square[STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE]; EFI_GRAPHICS_OUTPUT_BLT_PIXEL Backup[STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE]; UINTN i; // Locate all instances of GOP EFI_STATUS Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL, &HandleCount, &HandleBuffer); if (EFI_ERROR (Status)) { DEBUG((-1, "ShowStatus: Graphics output protocol not found\n")); return EFI_UNSUPPORTED; } // Set square color for (i = 0 ; i < STATUS_SQUARE_SIDE * STATUS_SQUARE_SIDE; i++) { Square[i].Blue = Blue; Square[i].Green = Green; Square[i].Red = Red; Square[i].Reserved = 0x00; } // For each GOP instance for (i = 0; i < HandleCount; i ++) { // Handle protocol Status = gBS->HandleProtocol(HandleBuffer[i], &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); if (EFI_ERROR (Status)) { DEBUG((-1, "ShowStatus: gBS->HandleProtocol[%d] returned %r\n", i, Status)); continue; } // Backup current image GraphicsOutput->Blt(GraphicsOutput, Backup, EfiBltVideoToBltBuffer, 0, 0, 0, 0, STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0); // Draw the status square GraphicsOutput->Blt(GraphicsOutput, Square, EfiBltBufferToVideo, 0, 0, 0, 0, STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0); // Wait 500ms gBS->Stall(500*1000); // Restore the backup GraphicsOutput->Blt(GraphicsOutput, Backup, EfiBltBufferToVideo, 0, 0, 0, 0, STATUS_SQUARE_SIDE, STATUS_SQUARE_SIDE, 0); } return EFI_SUCCESS; }
      
      



これですべおが準備が敎い、正垞に実行されたすが、準備が敎うたで芋たり、GitHubから既補のドラむバヌをダりンロヌドしお自分のドラむバヌず比范したり、いく぀かの倉曎を説明するのを忘れおいたした。



UEFIシェルで結果をテストする



UDK2015 / Build / MdeModulePkg / RELEASE / X64 / MdeModulePkg / CrScreenshotDxe / CrScreenshotDxe / OUTPUTからアセンブルされたドラむバヌを取埗したす。そこから必芁なファむルは2぀だけです。CrScreenshotDxe.efiドラむバヌ自䜓ず、 CrScreenspexDeの䟝存関係セクションです。

最初に、UEFIシェルからドラむバヌの動䜜をテストしたす。 UEFIシェルを䜿甚しおファむルCrScreenshotDxe.efiをUSBスティックにコピヌし、ブヌトしお、 fs0でフラッシュドラむブのルヌトに移動したすシステムに接続されおいるディスクの数に応じお数が倉わる堎合がありたす 。load CrScreenshotDxe.efiコマンドを実行したす 。 成功メッセヌゞが衚瀺され、画面の䞊郚隅に癜い四角が点滅しおいる堎合は、ドラむバヌが皌働䞭であるこずを意味したす。 私にずっおはこのように芋えたす

UEFIシェル


このスクリヌンショットは、埌続のすべおのスクリヌンショットず同様に、ドラむバヌが撮圱したものであるため、コヌナヌの四角は衚瀺されたせん。

次に、 LCtrl + LAlt + F12を倧胆に抌しお、ステヌタスを確認したす。 AMIシステムでは、グラフィックコン゜ヌルが1぀しかないため、緑色の四角圢が点滅し、1回の組み合わせで1぀のスクリヌンショットを取埗したす。 PhoenixずInsydeを䜿甚しおいるシステムでは、2぀のグラフィックコン゜ヌルがあり、そのうちの1぀は空であるため、最初に青い正方圢、次に緑の正方圢が衚瀺されたすが、スクリヌンショットも1぀しかありたせん。 UEFIシェルからのテスト結果は同じように芋えたす。解像床は800x600ではなく、1366x768です。

さお、すべおがシェルから機胜し、次のようにUEFIアプリケヌションからスクリヌンショットを取埗できたす。

RU.efi




倉曎されたファヌムりェアで結果をテストする



残念ながら、BIOSセットアップのスクリヌンショットはこの方法では削陀できたせん-ドラむバヌの読み蟌みが遅すぎたす。 2぀の解決策がありたす。1぀目は、 UEFIToolを䜿甚しおファヌムりェアのDXEボリュヌムの䟝存関係セクションず共にドラむバヌを远加するこずです。2぀目は、PCIeデバむスのOptionROMに远加するこずです。その埌、ファヌムりェアの倉曎は䞍芁です。埌で必芁な鉄片を入手したら、2番目の方法を実装しようずしたすが、最初の方法には問題はありたせん。USBフラッシュドラむブを挿入、瞫補、開始、スティックし、BIOSセットアップに移動し、LCtrl + LAlt + F12を抌したす- 出来䞊がり、青ず緑の正方圢が衚瀺され、すべおが機胜したす。結果は次のようになりたす。

パスワヌド入力フォヌム


情報タブ


メむンタブ


セキュリティタブ


ブヌトタブ


終了タブ


これは成功です、玳士。



おわりに



ドラむバヌが䜜成され、コヌドがGitHubに投皿され、OptionROMでアむデアを確認するために残り、トピックは閉じられおいるず蚀えたす。

ここで䜕が起こっおいるのかただ理解できない堎合は、コヌドにバグを芋぀けたしたか、たたは蚘事、著者、UEFIの極悪さ、たたはレガシヌBIOSでどれだけ良かったのかを議論したいだけです。コメントを歓迎したす。

読者の皆さんの泚意、良いDXEドラむバヌに感謝したす。



All Articles