カーネル読み込みメモリ空間を確保する (OpenCore編)

macOSが起動する時、ブートローダがカーネルをメモリに読み込みます。この時、連続した十分な大きさのメモリ領域が確保できないと、起動に失敗して禁止マークが出ます。この状況への対処方法が、OpenCoreではCloverよりも充実しています。

以前の記事では、メモリの使用状況(メモリマップ)を確認して、空き領域を起動オプションのslide値で指定することで、カーネル用メモリを確実に確保する方法を紹介しました。今回はそのOpenCore編です。


以下のOpenCoreのガイドで、この問題への対処方法が詳しく説明されています。以下はこのサイトの抄訳です。

dortania.github.io
Fixing KASLR slide values · GitBook
https://dortania.github.io/OpenCore-Desktop-Guide/extras/kaslr-fix.html

KASLR Slide値を設定する

このページでは、 “Couldn’t allocate runtime area” (ランタイム領域を割り当てられませんでした) というエラーを理解し、修正したいユーザーのために説明します。これは Z390, X99, X299 などで最もよく現れるエラーです。このページはOpenCoreだけでなく、Cloverも対象にします。

KASLRとは何か?

KASLRは、Kernel address space layout randomizationの略で、セキュリティ目的で使用されます。これにより攻撃者がメモリ内の重要なオブジェクトがどこにあるのかを把握するのを難しくします。

HackintoshでKASLRが問題になるのは、マザーボードに連続した十分なサイズのメモリー空間がなく、カーネルが完全に収まらない場合です。そこで、slide=xxx を使って、KASLRをキャンセルしてメモリーアドレスを固定していました。このパラメータを設定すると、macOSに起動ごとに動作するランダムな領域にカーネル読み込む代わりに、動作することがわかっている場所を使用します。

このガイドが必要な人達

カーネルを読み込むメモリ空間が足りなかったり、細分化されたメモリー空間に読み込み場所が移動してしまったユーザーのためのガイドです。その場合、このようなエラーが出ます。

Error allocating 0x1197b pages at 0x0000000017a80000 alloc type 2
Couldn't allocate runtime area

以下のようなエラーが出ることもあります。

Only 244/256 slide values are usable!

または、macOSの実行中にカーネルパニックが発生することもあります。

panic(cpu 6 caller 0xffffff801fc057ba): a freed zone element has been modified in zone kalloc.4096: expected 0x3f00116dbe8a46f6 but found 0x3f00116d00000000

これらのエラーの1番の特徴は、発生にランダム性があることです。大抵は20回も起動を繰り返せば、1回くらいはエラーを出さないで起動します。

問題解決の方法

これを修正するのは非常に簡単で、その手順はCloverユーザでもOpenCoreユーザーでも同じです。Clover ユーザに必要なものは以下です。

  • Clover Shell : shell64.efi などと呼ばれているファイルを、EFI/CLOVER/tools の下に置きます。
  • OcQuirks : Aptioの修正、OsxAptioFixDrvX, AptioMemoryFixなどと混在させないでください。このガイドでは OcQuirks のみサポートします。EFI/CLOVER/drivers/UEFI の中に置きます。
  • OpenRuntime.efi : OcQuirksのパッケージに含まれます。EFI/CLOVER/drivers/UEFI の中に入れます。
  • OcQuirks.plist : (これもOcQuirksに含まれてます) EFI/CLOVER/drivers/UEFI の中に入れます。

一方、OpenCoreユーザに必要なものは以下です。

  • OpenRuntime
  • OpenShell これをconfig.plistのRoot -> Misc -> Toolsで有効にしておきます。

そして、config.plist -> Booter (OpenCore用) かOcQuirks.plist (Clover用) で以下の設定をします。

  • AvoidRuntimeDefrag: YES
    日付、時刻、NVRAM、電源制御などのUEFIランタイムサービスの修正
  • DevirtualiseMmio : YES
    Stolen Memory のサイズを削減し、slide=N値のオプションを拡張し、Z390のメモリ割り当ての問題を修正するのに非常に役立ちます。
  • EnableSafeModeSlide : YES
    slide 値をセーフモードで使用できるようにします。
  • ProtectUefiServices : NO
    UEFI サービスがファームウェアによってオーバーライドされないように保護します。主に VM、300 シリーズ、および Ice Lake や Comet Lake のような新しいシステムに関連します。
  • ProvideCustomSlide : YES
    これにより、カーネルが、読み込みに適してメモリー空間のみを選択し、起動に失敗する可能性のある場所を避けるようになります。読み込み場所のランダム性は維持していますが、ランダムに選択する際に、不適切なメモリ領域を除外するようになります。(訳注:これが従来のslide設定の役割を果たしてくれるようです。ただし、slideを固定するのではなく、使用可能なslide値を自動で探して、その中からランダムに選んでくれているようです。)
  • RebuildAppleMemoryMap : YES
    macOSと互換性のあるメモリマップを生成します。いくつかのラップトップのOEMファームウェアで失敗することがありますので、早期段階でブートに失敗する場合は、これを無効にします。

BIOS設定

BIOSを以下のように設定します。

  • BIOSを更新する (初期のBIOSにはメモリマップの問題があることが知られているので、非常に重要です, 特にZ390で重要です。)
  • CMOSを工場出荷時設定にリセットする
  • とても必要とされる以下のBIOS設定をします。
    Above4GDecoding : 有効にします。デバイスが4GB以上のメモリ領域を使用できるようになり、macOSカーネルが収まるメモリー空間が増えます。
    Boot Options -> Windows8.1/10 mode : これにより古いレガシーなゴミのようなコードがロードされなくなります。誤解されがちですが、other OSというもう一つの選択肢は、古いバージョンのWindowsを起動するための選択肢であり、LinuxやmacOSのための選択肢ではありません。(訳注:ASUSのZ490マザーボードにCatalinaを入れたマシンでは、other OSにしないと起動しませんでした。)
  • BIOS内の不要なデバイスをできるだけ多く無効にします。これにより、、起動時のマップの細分化がが減少するので、起動失敗の可能性が減ります。
    CSM : 無効にします。有効化してしまうと、レガシーサポートのため、不要なゴミの束が追加され、またUEFIシェルが起動できなくなります。
    Intel SGX : 無効にします。SGXとはSoftware Guard Extensionsの略です。有効にしても、多くのメモリ空間を占有するだけで、macOSでは何もしません。
    Parallel Port と Serial Port:無効にします。macOSではParallel portは認識しませんし、Serialを必要とする人はいないです。
    iGPU : やむを得ない場合は、これを無効にすることで、メモリを大幅に解放できます。
    Thunderbolt : 無効にします。ほとんどのマザーボードはTBを搭載していませんし、搭載していても使用しないなら、無効にすることでメモリ空間を確保できます。
    LED ligiting : 無効にします。もう光らせなくても良いでしょう。
    Legacy USB : 無効にします。これもレガシーなガラクタです。

テストブート

上記のように、EFI、config.plist、BIOSの設定を調整したら、これで起動を試してください。これでめでたく解決したら、この先の作業は不要です。まだ問題が発生する場合は、次のステップで、もっとディープな作業、つまりslide値の計算をしましょう。

slide値を探す

ブートマネージャでEFIシェルを開き、memmapを実行します。すべてのページとそのサイズのリストが以下のように表示されます。ここからが楽しみの始まりです。

Type      Start            End              # Pages          Attributes
RT_Data	  0000000000000000 0000000000000FFF 0000000000000001 800000000000000F
Available 0000000000001000 0000000000057FFF 0000000000000057 000000000000000F
Reserved  0000000000058000 0000000000058FFF 0000000000000001 000000000000000F
Available 0000000000059000 000000000008FFFF 0000000000000037 000000000000000F
RT_Code   0000000000090000 0000000000090FFF 0000000000000001 800000000000000F
Available 0000000000091000 000000000009DFFF 000000000000000D 000000000000000F
Reserved  000000000009E000 000000000009FFFF 0000000000000002 000000000000000F
Available 0000000000100000 000000005B635FFF 000000000005B536 000000000000000F
BS_Data   000000005B636000 000000005B675FFF 0000000000000040 000000000000000F
Available 000000005B676000 000000006AF77FFF 000000000000F902 000000000000000F
LoaderCode000000006AF78000 000000006B155FFF 00000000000001DE 000000000000000F
BS_Data   000000006B156000 000000006B523FFF 00000000000003CE 000000000000000F
ACPI_NVS  000000006B524000 000000006B524FFF 0000000000000001 000000000000000F
BS_Data   000000006B526000 000000006B625FFF 0000000000000100 000000000000000F
Available 000000006B626000 000000006B634FFF 000000000000000F 000000000000000F

(訳注:このあと、slide値を決める手順が書かれています。どういうわけか、一番高い番地のAvailableを第一候補として〜15ページしかないのに〜、slideが255を超えるので諦めて、順当に0x100000番地からの領域、すなわちslide=0を選択しています。ということで少し遠回りしている感じもしますし、また、こちらで解説した内容と同じなので省略します。またRedditの/r/hackintoshのdiscordにもツールらしきものがあるらしく、その説明もありますが、これも省略します。)

DevirtualiseMmioを使う

訳注:この先はあまり理解できませんでした。推測を交えて内容をまとめると、次のようなことだと思います。

  • config.plistでDevirtualiseMmioをtrueにする(デフォルトはfalse)。これにより、カーネルを読み込む場所のメモリー使用が64から256MB程度節約できて、KASLRの失敗を防止できます。MMIOは多分、Memory Mapped IOのことかなと思います。このオプションは、MMIOを仮想化しないようにするという指定だと思います。MMIOの仮想化というのがどういうものなのか知らないので、どなたか教えていただければと思います。おそらくは、IO番地を実番地から仮想番地にして、プログラムがIO番地にアクセスする状況にOS(カーネル?ブートローダ?)が介入できるようにすることかなと思います。これにより、いろいろなプログラムがIOにアクセスする状況を、OSが交通整理する仕組みかと想像してます。仮想化するためにオーバーヘッドが生じて、メモリー空間を圧迫するので、それを止めるとメモリーが空くのだと思います。
  • config.plistにMmioWhitelistを指定する。これはDevirtualiseMmioをtrueにすることに関連して、Threadripper TRX40 19H などの一部のシステムでは、DevirtualiseMmioを適用しない(?)領域を指定する必要があるらしいです。これがMnioWhitelistです。これの作り方について説明がありますが省略します。ほとんどのシステムではMnioWhitelistは不要とのことです。

ここまでが抄訳です。


結局どうしたら良いのか

OpenCoreでどう対応すべきかについてまとめます。上記のガイドでは、slide値を求める方法は書いてありますが、ブートオプションなどで設定する方法にまでは書かれていませんでした。当然のことで省略されたのかもしれないですし、slideを使うことをあまり推奨していないのかもしれません。

OpenCoreのReference Manual (0.5.8) の最初の方(15ページ)には、最初にすべきことの一つに、「slideを使うな」と書いてあります。config.plistの設定からも、NVRAMのboot argumentからも削除しておくようにとのことです。そして、「No slide values are usable! Use custom slide!」というエラーが出てから検討してくださいとあります。slideは、KASLRを回避する上、SIPを緩める必要があるので、セキュリティに影響を与えるという考えなのかもしれません。まずはslideを使わなくても済む方法を試みて、それでもダメな場合だけにslideを使いましょうとの方針だと思います。

ということで、このガイドのステップをまとめると、以下になります。まずはマザーボードの設定です。

  • BIOSを更新する
  • Above 4G Decodingを有効にする
  • CSMを無効にする
  • Boot Options -> Windows8.1/10 mode にする(訳注:前述のようにother OSを選択しないと起動しないことがあります)
  • Parallel Port と Serial Portを無効にします

可能ならば以下も設定します。

  • Intel SGX : 使用していないなら無効にします。
  • Thunderbolt : 使用していないなら無効にします。
  • LED ligiting : 無効にします。
  • Legacy USB : 無効にします。

そしてconfig.plistで以下のように設定します。

  • AvoidRuntimeDefrag: true
  • DevirtualiseMmio : true
  • EnableSafeModeSlide : true
  • ProtectUefiServices : false
  • ProvideCustomSlide : true
  • RebuildAppleMemoryMap : true

設定は、環境に合わせて必要なものを選択して、正常に起動するまで少しずつ足して行くのが良いと思います。

まとめ

KASLRに関係した理由でmacOSが起動しないことへの対処法を紹介しました。基本的には、メモリー空間を確保する処置をして、KASLRの選択範囲を狭めることで対応しています。BIOS設定とOpenCoreの機能で大体の場合に対応できて、slideによるカーネル読み込み番地固定は最終手段のようです。

3件のコメント

  1. いつも参考にさせていただいてます。
    なんとかヴァニラな状態で起動するマシンができたのですが、CPUを9100Fから9400に交換しようとしたら起動しなくなりまして、、、
    何かお知恵をいただければ幸いです。

  2. まだまだHackintoshビギナーですが、9100F→9400であれば、大きな違いはiGPUの有無なので、そこに関わりそうなところだと、BIOSの設定、Lilu、WhateverGreenを最新Verにするとかでチェックしてみてはいかがでしょう?

返信を残す

メールアドレスが公開されることはありません。