サイトアイコン Boot macOS

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

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

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

macOSが起動するときに、早い段階で禁止マークが出て停止してしまうことがあります。多くの場合、カーネルを読込むメモリが確保できないエラーです。これをslideオプションで解決します。追記:この記事はCloverを前提に書いてあります。OpenCoreに関してはこちらをご覧ください。またコメントいただいたように、CloverにOpenCoreのツールを流用して対応することも可能なようです。症状禁止マークが出て早々に起動停止してしまう場合に、-vオプションで起動すると、"Error Allocating xxxx pages at xxxxxxxx"というようなメ...
slideでカーネル読み込み番地を調整する (Clover編) - Boot macOS

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

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 ユーザに必要なものは以下です。

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

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

BIOS設定

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

テストブート

上記のように、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にする

DevirtualiseMmioのデフォルトはfalseですが、これをtrueにします。これにより、カーネルを読み込む場所のメモリー使用が64から256MB程度節約できて、KASLRの失敗を防止できます。

MMIOはMemory Mapped IOのことです。入出力デバイスのコントロールをメモリーのアドレス線を利用して行うのがMMIOです。上でのべたEFI Shellのmemmapコマンドによると、E0000000番地からFFFFFFFF番地までの512MBにMMIOが割り当てられています。インテルチップセットのマザーボードなら同様のようです。この番地には、メモリーが割り当てられていたとしても、IOへのアクセスになってしまい使えません。

Type Start            End              # Pages          Attributes
MMIO 00000000E0000000-00000000EFFFFFFF 0000000000010000 800000000000100D
MMIO 00000000FE000000-00000000FE010FFF 0000000000000011 8000000000000001
MMIO 00000000FEC00000-00000000FEC00FFF 0000000000000001 800000000000100D
MMIO 00000000FED00000-00000000FED03FFF 0000000000000004 800000000000100D
MMIO 00000000FEE00000-00000000FEE00FFF 0000000000000001 8000000000000001
MMIO 00000000FF000000-00000000FFFFFFFF 0000000000001000 800000000000100D

(以下はフォーラムで教えていただいた図をもとに考えた説明です、間違っていたらすみません)EFIによってOSが起動する際に、通常はMMIOに論理アドレスを与えて(仮想化して)、論理アドレスからMMIOを使用できる状態にするようです。ただMMIOの仮想化を行わなくても(de-virtualiseしても)、物理アドレスにアクセスできるプロセスからはMMIOを使えるのでそれほど問題はないようです。MMIOを仮想化しない場合は、MMIOの部分もメモリーにマップできるので、64MBから256MBの空き領域が稼げるようです。DevirtualiseMmioフラグをtureにすると、カーネルが読み込まれる領域を少しでも多く確保できるので、起動失敗の確率を下げられます。

Kaby Lake以前のCPUでは、デフォルト通りfalseが、Coffee Lake, Comet Lakeなどではtrueにすると良いとされていますが、手元のCoffee Lake-Sではfalseでも動きました。通常はfalseで、起動失敗する場合にはtrueを試すのが良いと思います。

ちなみにどうでも良いことですが、virtualize (仮想化) をvirtualiseと書くのは英国風らしいです。

config.plistにMmioWhitelistを指定する

DevirtualiseMmioをtrueにした場合に、メモリは節約できるものの、Threadripper TRX40 19H などの一部のシステムで起動しなくなることがあるらしいです。そのような場合、DevirtualiseMmioを適用しない領域を指定するのが、これがMmioWhitelistです。これの作り方について説明がありますが省略します。ほとんどのシステムでは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を使いましょうとの方針だと思います。

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

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

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

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

まとめ

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

モバイルバージョンを終了