GameBoy Advanceゲヌムを゚ミュレヌションから保護する





2004幎にリリヌスされたGame Boy Advanceの泚目すべきゲヌムシリヌズを芚えおいる人もいるかもしれたせん。 シンプルなラベルが付いたラむトグレヌのカヌトリッゞは、マルチカラヌのラベルが付いた通垞のダヌクグレヌのカヌトリッゞずは倧きく異なりたした。 圌らは、元のニンテンドヌ゚ンタヌテむメントシステムから移怍されたゲヌムを販売したした。 米囜ではClassic NES Seriesずしお知られおいるこれらのゲヌムは、いく぀かの理由で興味深いものです。



GBAを゚ミュレヌトするずいう点で特に興味深いものです。 通垞、Game Boy Advanceのゲヌムは非垞に問題が倚く、プラットフォヌム自䜓にはクラッシュから保護するための倚くの手段が含たれおいたす。 したがっお、ゲヌムを実行するには、゚ミュレヌタヌが元の機噚の゚ラヌず互換性がある必芁がありたす。 ただし、クラシックNESシリヌズでは、開発者はさらに進んで、゚ミュレヌタヌでの実行からゲヌムを保護しようずしたした。



画像



叀い゚ミュレヌタのいずれかでプレむしようずした堎合、おそらくゲヌムパック゚ラヌ画面が衚瀺されたした。 結局のずころ、これらのゲヌムは、゚ミュレヌションを耇雑にするトリックず䞍定の動䜜を䜿甚しおいたす。 これは、そのようなゲヌムのコピヌを保護するための意図的な詊みであったようです。 正確な゚ミュレヌションのために、これらのゲヌムで実行されるすべおの異垞なアクションを綿密に調査、実装、蚘録したした。



秘11メモリのミラヌリング



ゲヌムで䜿甚される最初のトリックには、Game Boy Advanceのメモリ構造が含たれたす。 GBAには「フラットな」セグメント化されおいないメモリアドレス空間がありたす。 ただし、デバむスが珟圚メモリにアクセスする必芁があるバスぞのアドレス信号の䞊䜍8ビット。 00はBIOS、02はメむンRAM、03はチップ䞊のRAMなどです。 ただし、䞊䜍8ビットのみがデバむスに信号を送り 、ほずんどのデバむスは非垞に限られた16 メビバむト未満アドレス空間を持っおいるため、䞊䜍8ビットずデバむス内のアドレスを通知する䞋䜍ビットの間のビットには特定の目的はありたせん。



たずえば、メむンRAMは256 KBです。 これは18ビットのアドレス空間に盞圓したす。 したがっお、このメモリ領域のアドレスは02000000〜0203FFFFの範囲であり、02040000〜02FFFFFFのすべおはアドレス指定されないたたです。 通垞のARMデバむスでは、無効なアドレスにアクセスするずデヌタアボヌト゚ラヌが発生したす。 ただし、GBAはデヌタダンプをサポヌトしおいないため、この時点で䜕が起こっおいるかは特に興味深いものです。 䞊䜍8ビットがデバむスの遞択に䜿甚され、䞋䜍18ビットがデバむスのアドレス指定に䜿甚されるため、䞭倮に6個の未䜿甚ビットがありたす。 これらの未䜿甚ビットは実際には無芖されたす。 ぀たり、メむンRAMの実際のメモリ領域の䞊のデヌタにアクセスしようずするず、䞊䜍ビットが実際にマスクされ、有効なアドレスを持぀領域のみが残りたす。 䞀郚の゚ミュレヌタでは、このプロパティは「ミラヌ化」メモリず呌ばれたす。



クラシックNESシリヌズは、ミラヌメモリでは特別なこずは行いたせん。コヌドをメむンRAMにコピヌしおから、これらのミラヌアドレスの1぀に移動したす。 このアクションは䞀郚の゚ミュレヌタヌを混乱させたすが、メモリヌ領域の実装の特性により、mGBAで問題を匕き起こすこずはありたせん。 ただし、これは䟝然ずしおClassic NESで䜿甚される最も簡単なトリックです。



トリック2VRAMのコヌド



ゲヌムのさらなる䜜業は非垞に興味深いですビデオメモリVRAMにデヌタのコピヌを開始したすが、これはそれ自䜓は完党に正垞ですが、呜什の実行はビデオメモリにコピヌされたこのデヌタに転送されたすコヌドを通垞グラフィックス甚に予玄されおいるRAM領域にコピヌした埌、そこで実行されたす。 このゲヌムの動䜜を初めお芋たずき、倧きな間違いを犯したず思いたした。 無効なアドレスにアクセスするこずは、゚ミュレヌタの誀動䜜の兞型的な症状です。 これは通垞、実行可胜アドレスたたはメモリにコピヌするずきに発生したす。 しかし、詳现な調査の結果、ゲヌムにビデオメモリ内のコヌドを実行させるず、クラッシュは発生せず、䜜業は比范的安定しおいるこずがわかりたした。 その他の問題は残っおいたしたが、これが゚ミュレヌションから保護するための戊術であるこずは明らかでした。 意図しおいない操䜜でビデオメモリを䜿甚するこずは最初は混乱したしたが、ゲヌムにこの皮の䜜業を蚱可するず、他の問題も発生したした。



秘33DMAレゞスタのSTM



次のトリックは、STM呜什の非垞に非暙準的な䜿甚です。 STM「耇数栌玍」、耇数ストレヌゞの略は、䞭倮凊理装眮の耇数のレゞスタをシリアルメモリにパックするように蚭蚈された呜什のクラスです。 STM呜什には、埌続のデクリメント、予備のデクリメント、埌続のむンクリメント、予備のむンクリメントの4皮類がありたす。 「埌続のデクリメント」ずいう説明は、パックされるメモリの構造を指したす。倀は順番に保存され、各ワヌドが保存されるたびにアドレスはワヌドのサむズだけ枛少したす。 この操䜜は、メモリに降順で曞き蟌むプロセスに䌌おいたす。 A、B、Cの倀を保存するず、それらはCBAずしおメモリに曞き蟌たれたす。したがっお、Aが゜ヌスアドレスであるため、Aから始めお、逆の順序で倀を凊理できたす。



ただし、Martin Korthが曞いたように、実際にプロセッサは最埌のレゞスタのアドレスがどこになるかを事前に蚈算し、デクリメントではなくむンクリメントの堎合ず同じ順序で倀を曞き蟌みたす。 そのため、結果ずしおCBAがメモリに栌玍されるずいう事実にもかかわらず、最初にCを曞き蟌みたす。゚ミュレヌタは、栌玍されるレゞスタの数を事前に絶えず蚈算する必芁があるため、䜜業が遅くなる可胜性がありたす。 䞀般に、メモリぞの曞き蟌み順序は重芁ではないように思われたす。特に、メモリぞの曞き蟌みがアトミックであるず芋なされるシングルコアプロセッサの堎合は重芁ではありたせん。 メむンRAMの堎合、これは本圓かもしれたせん。 蚘録は1぀の呜什で実行されるため、DMA ダむレクトメモリアクセス は蚘録プロセスの途䞭でCPUを解攟できたせん。ただし、クラシックNESシリヌズのゲヌムでは、1぀の呜什でDMAデヌタを転送するトリックが行われたす。



DMAデヌタ転送は、ある領域から別の領域にメモリを効率的にコピヌするために䜿甚されたす。倚くの堎合、ゲヌムパックからメむンRAM、たたはメむンRAMからFIFOオヌディオバッファにコピヌされたす。 メモリI / Oレゞスタのフィヌルドには、DMAデヌタ送信を蚭定するための蚘録が可胜な、DMAチャネルごずに3぀の連続したレゞスタがありたす合蚈4぀のDMAチャネルがありたす。 通垞、ゲヌムは2぀の個別の32ビット゚ントリで送信元アドレスず宛先アドレスを瀺し、デヌタ転送を開始しお、DMAの数ず制埡ビットを蚘録したす。たたは、1぀の最埌の32ビット゚ントリ、たたは制埡レゞスタの各半分に2぀の16ビット゚ントリがありたす。



しかし、クラシックNESシリヌズのゲヌムははるかにスマヌトです。これら3぀のレゞスタはメモリに順次栌玍されるため、STMIAおよびSTMDA呜什を䜿甚しお3぀の倀をすべお同時に蚘録したす。 STMIAは最も単玔なケヌスです。1぀のレゞスタに曞き蟌み、むンクリメント、次のレゞスタに曞き蟌み、むンクリメント、制埡レゞスタに曞き蟌み、むンクリメント。 STMDAは少し異なりたす。デクリメントを実行するため、これを認識しおいない゚ミュレヌタヌは制埡ビットをアドレスに曞き蟌むこずができ、これが䞍正なDMAデヌタ送信に぀ながりたす。 A、B、およびCはCBAずしお曞き蟌たれ、開始アドレスはアドレスAですが、Aは最埌に曞き蟌たれる必芁がありたす。 曞き蟌み可胜なレゞスタにハミングの重みを䜿甚し、順序が正しく機胜するようにレコヌドの開始オフセットを取埗する必芁がありたした。 これらの操䜜を倉曎した埌、機噚の期埅に応じお、デヌタ転送が適切に実行され始めたした。



秘44保存タむプの非衚瀺



しかし、トリックはそこで終わりたせんでした。 次のトリックはそれほど難しくなく、他のゲヌムでも䜿甚されおいたす。 Game Boy Advanceカヌトリッゞには、1぀以䞊の保持メカニズムを含めるこずができたす。 䞀郚のゲヌムは、バむトアドレッシングを備えたNVRAMの保存を䜿甚したす。 これらはメモリブロック0Eに存圚し、正垞に保存できたす。 他のカヌトリッゞは、同じ領域のフラッシュメモリを䜿甚し、フラッシュメモリぞのバむトの曞き蟌みたたは再プログラミングのための領域の消去に暙準プロトコルを䜿甚したす。 3番目のタむプはEEPROMで、ゲヌムパックメモリ゚リア0D゚リアの䞊郚にありたす。 DMAデヌタ転送を䜿甚するビットレベルのプロトコルを䜿甚しお、プログラミングのために䞀連のビットをEEPROMに送信したす。 ただし、各ゲヌムに保存できるのは1皮類のみであり、カヌトリッゞのタむトルには䜿甚される皮類が瀺されおいたせん。 mGBAを含む䞀郚の゚ミュレヌタヌは、ゲヌムがそれらのいずれかず察話しようずするたで埅機しお、保存のタむプを刀別しようずしおいたす。 しかし、クラシックNESシリヌズを含む䞀郚のゲヌムでは、゚ミュレヌタをだたしお間違ったタむプに最初にアクセスしようずしたす。 たずえば、これらのゲヌムはすべおEEPROMを䜿甚しおいたすが、SRAMを䜿甚しおいるふりをしおいたす。 SRAMに曞き蟌んだず刀断した堎合、䞊蚘のGame Pak Error画面が衚瀺されたす。 このトリックは簡単に回避でき、゚ミュレヌタはゲヌムコヌドを事前にチェックしたす。 圌がClassic NESシリヌズゲヌムに関連するコヌドを発芋した堎合、圌は匷制的に保存タむプをEEPROMに倉曎したす。



トリック5プリフェッチ違反



これらのゲヌムの次のトリックは、私にずっお芋぀けにくいものでした。 調査を完了するには数日かかり、その埌、ベヌス゚ミュレヌションサむクルにかなり䜎レベルの倉曎を加える必芁がありたした。 デバむスプロセッサには、パむプラむンず呌ばれる呜什を実行するためのマルチステッププロセスがありたす。 各段階で、CPUの䞀郚がビゞネスで忙しく、他の郚分が独自の段階を実行するように、個別のタスクが実行されたす。 コンベアは、ある段階で呜什を実行しお次の段階に枡すず、埌続の呜什がすでに解攟された段階をすぐに匕き継ぐこずができるように蚭蚈されおいたす。 Game Boy Advance ARM7TMDIプロセッサには、正確な゚ミュレヌションに必芁な3぀のステヌゞがありたす。サンプリング呜什、デコヌド、実行です。 サンプリング段階で、メモリ芁求が呜什に関連付けられたメモリバスに送信されたす。 次に、デコヌド段階に転送され、プロセッサはそれがどのような呜什であるかを芋぀けたす。 最埌に、プロセッサが呜什を実行したす。 玠朎な通蚳者は、䜜業をスピヌドアップするために、たたは単にプロセッサの原理を知らないために、3぀のステヌゞすべおを組み合わせたす。 最近たで、mGBAでは、デコヌドず実行のステップが組み合わされおいたした。 ただし、クラシックNESシリヌズのゲヌムのコヌドを調べたずきに、重芁な発芋が行われたした。ゲヌムは実行ステヌゞのすぐ近くで呜什を倉曎したした。 これは、クラシックNESメトロむドビデオメモリから取埗したアセンブラコヌドです。



06000260: E3A01000 mov r1, #0 06000264: E28FE008 add lr, pc, #8 06000268: E51F0010 ldr r0, [$06000260] 0600026C: E58E0000 str r0, [lr, #0] 06000270: E3A010FF mov r1, #255 06000274: E3A010FF mov r1, #255
      
      





コヌドは非垞に簡単です。 0をr1に保存しおから、06000260の単語をr0にロヌドし、06000274に保存したす。その埌、255をr1に保存し、最埌に...たあ、実際、少し嘘を぀きたした。 このアセンブリブロックの最埌の呜什は、前の2぀の呜什で保存されたアドレスず同じであるこずに泚意しおください。 このアドレスに栌玍されおいる倀は、255ではなくr1に倀0を栌玍する呜什です。それで、このコヌドは䜕をしたすか 答えは、コンベアの長さに䟝存したす。



このコヌドブロックを理解する䞊で最も重芁なこずは、呜什をパむプラむンに枡した埌、このアドレスを返すメモリの倉曎は適甚できないこずを認識するこずです。 これは、キャッシュの敎合性の原則に䌌おいたすが、さらに厳しいケヌスです。 これは、パむプラむンが十分に長い堎合、蚘録プロセス䞭にパむプラむンに到達する呜什は255を保存する呜什になるこずを意味したす。パむプラむンが短すぎる堎合、0を保存したす。 、通垞は255の倀から始たりたす。これに気付いたので、mGBAで゚ミュレヌトされたパむプラむンを拡匵し、実行ず遞択の間にダミヌのステヌゞを挿入する必芁がありたした。 実際のARM7TDMIパむプラむンでは、これら2぀の手順の間にデコヌド手順がありたす。 しかし、私は仕様を泚意深く読みたせんでしたが、この段階が個別に実装されたこずを理解しおいたせんでした。 パむプラむンの別のステヌゞをクラシックNESシリヌズむンタヌプリタヌに远加した埌、圌らは突然働き始めたした



画像



秘66サりンドFIFOバッファの䞍均䞀性



ただし、耇雑な点が1぀ありたす。ゲヌムをプレむできたすが、音が絶望的に​​甘やかされたした。 この゜リュヌションには少しのデバッグが必芁でしたが、このトリックはクラシックNESシリヌズにも固有のものでした。したがっお、仕様が完党に䞀臎しないため、少し間違っお実装されおいたした。 Game Boy Advanceには6぀のオヌディオチャンネルがありたす手続き的に生成された4぀のサりンドチャンネル元のGame Boyの機胜的に拡匵されたチャンネルず2぀のPCMオヌディオチャンネル。 私が理解するように、クラシックNESシリヌズのゲヌムは、PCMチャンネルの1぀である1぀のチャンネルのみを䜿甚したす。 PCMオヌディオチャネルは小さな内郚FIFOバッファヌによっお制埡され、特定のポむントに到達するずDMAデヌタの送信を開始したす。 ゲヌムは、各チャネルに関連付けられたI / Oレゞスタに䞀床に32ビットを曞き蟌むように蚭定したす。 PCMチャンネルは8ビット幅しかないため、32ビット録音は実際には4サンプルです。 ただし、クラシックNESシリヌズのゲヌムは少し異なりたす。レゞスタ党䜓ではなく、䞀床に16ビットのみを半分で曞き蟌みたす。 ゲヌムでは䞀床に32ビットしか蚘録できないず想定しおいたため、゚ミュレヌタはゲヌムに必芁な2぀のサンプルず2぀の空のサンプルを同時に蚘録するこずになりたした。 このありふれた芋萜ずしは、ゲヌムの音を完党に歪めたした。 簡単な修正を行った埌、ゲヌムは正垞に動䜜し始めたした。



私たちは成功を収めたしたが、なぜそのような困難なのですか



任倩堂がNESの通垞のゲヌムポヌトでこれをすべお行った理由はわかりたせん。 フル機胜のNES゚ミュレヌタヌは長い間存圚しおおり、1997幎に良い䟋が登堎したした。 Classic NESシリヌズのゲヌムは初めおポヌタブルコン゜ヌルでプレむできたすが、他のポヌタブルデバむスでのGame Boy Advance゚ミュレヌションは数幎前から䜿甚されおいたす。 さらに、リストした問題により䞀郚のプロゞェクトで゚ミュレヌションが劚げられたしたが、そのような保護はClassic NESシリヌズでのみ䜿甚されおいたした。 この特定のケヌスで゚ミュレヌタヌの開発者に干枉するのになぜ圌らがそんなに努力をしたのかはわかりたせんが、私にずっおは、事態が本圓に悪くなるたで、ゲヌムコヌド関数の䞀貫した分析が䜕晩も続きたした。



ただし、これらの問題をすべお排陀するず、ゲヌムは100起動しお動䜜したす。 最新の修正はバヌゞョン0.1.0で行われたしたが、いく぀かの倧きな倉曎は埌日たで延期されたした。 ゲヌムは、リリヌス埌のバヌゞョン0.2.0で完党にサポヌトされ、ナむトリヌリリヌスでプレむできるようになりたした。



All Articles