2. Linuxカーネルの起動プロセスの分析

最後のブログでは、Linuxカーネルのコード構造とコンパイルプロセスについて説明しましたこのブログでは、カーネルの移植に役立つカーネルの起動プロセスについて主に説明しています。カーネルの起動プロセスを理解するには、カーネルの目的を知っておく必要があります。カーネルを起動する前の複雑で面倒な操作の主な目的は、カーネルを実行させることです。カーネル操作の目的は何ですか?これは、アプリケーションを実行するためのものでなければならないため、カーネルの主な目的は、ルートファイルシステムをマウントしてから、独自のプログラムを実行することです。LinuxカーネルおよびU-ブートするので、複数のCPUフレームワークのサポートやベニヤの様々なそのアーキテクチャ、開発ボード関連の初期化機能がありますカーネルの起動プロセスは、2つの部分に分けることもできます。アーキテクチャ/開発ボードに関連する起動プロセスと、それに続く一般的な起動プロセスです。次の図は、ARMアーキテクチャプロセッサでのLinuxカーネルvmlinuxの起動プロセスです。ここでは、他の形式のカーネル(Image、uImageなど)が特別な操作の後にvmlinuxを取得し、vmlinuxを起動するため、vmlinuxカーネルを使用しています。

一般的に使用されるアセンブリ言語プログラミングの最初の段階、カーネルが、このCPUアーキテクチャと開発ボードをサポートしているかどうかを検出する必要があるので、カーネルは、複数のCPUアーキテクチャと開発ボードの様々なサポートしているためブートローダーの起動の最後に、マシンコードがカーネルに渡されます。テストに合格すると、カーネルをリンクするときに仮想アドレスが使用されるため、ページテーブルを設定し、MMUを有効にする必要があります- > 次のステージのC(start_kernel)環境を呼び出す準備をするため、データセグメントをコピーし、BBSセグメントをクリアし、スタックを設定する必要があります。 、start_kernel関数(つまり、カーネルが使用する仮想アドレス)を呼び出します

最初の段階のコードフローを以下で分析します(arch / arm / kernel / head.S)

上記はarch / $(ARCH)/head.Sの内容で、主にカーネルがCPUアーキテクチャとシングルボードをサポートしているかどうかを検出するために使用されます(シングルボードは、カーネルの起動時にブートローダーによって渡される最初のパラメーターです(R1に保存)。 ))、第1レベルのページテーブルを作成し、MMUを有効にします。以下は詳細な説明です。

①カーネルがこの開発ボードのCPUをサポートしているかどうかを確認するCPUのIDは、コプロセッサCP15のC0から取得できます。

メーカー番号(8ビット)ARMは0x41を使用 製品のサブ番号(4ビット) ARMシステムのバージョン番号(4ビット) 商品マスタ番号(8bit) プロセッサのバージョン番号(4ビット)

上記の関数は、head_common.Sで定義されています。__lookup_processor_type関数の最初の行では、ラベル3の物理アドレスを取得します。R3で(現時点ではMMU関数は有効になっていないため、CPUは物理アドレスを使用します)注:ADR命令によって取得されるアドレスはPCレジスタに基づいています計算されたコードの2行目は、__ proc_info_begin __proc_info_endおよび(これらはリンクスクリプトで使用されるアドレスであり、仮想アドレスです)をr5-r7に保存することです。これは、物理アドレスと仮想アドレスの偏差を計算するためのもので、後者の2つは、__ proc_info_beginと__proc_info_endの物理アドレスを計算するためのものです。ラベル1:内部で行われるのは、__ proc_info_beginから__proc_info_endまでのproc_info_list情報を読み取ることです(proc_info_list構造のプロトタイプは、カーネルでサポートされているCPUを意味するinclude / asm-arm / procinfo.hで定義されています。ARM アーキテクチャーCPUの場合、これらの構造本体は、arch / arm / mmディレクトリで定義されています。これは、proc_arm920.Sなど、arm920アーキテクチャーCPUのproc_info_listの構造およびその他の情報の定義ファイルを表します。異なるproc_info_list構造は、異なる機関のCPUをサポートするために使用され、すべて定義されています.proc_info_initセクションで、これらの構造体はまとめられ(__proc_info_beginは開始アドレスです)、プロセッサから読み取られたCPUID(r9)値と比較され、同じCPUに属しているかどうかが確認されます。一致する場合、ラベルに転送されます。 2:一致しない場合はその場所に戻り、読み続けてから一致します。最後まで一致は成功せず、r5は0に割り当てられて終了しました。注:異なる開発ボードのCPUは異なる場合があります。ARMアーキテクチャのCPUは、arch / arm / mm /ディレクトリで定義されます。これは、proc_arm920.Sファイルで定義されている__arm920_proc_info(proc_info_list構造)などのCPUの関連情報を定義します。そのため、このCPUを使用する場合は、このファイルを含める必要があります。カーネルを構成する場合は、それを構成する必要があります(構成メニューは、システムの[タイプ]-> [ARM920Tプロセッサのサポート]です)

②カーネルがこの開発ボードのマシンIDをサポートしているか確認し、BootLoaderが起動する際にマシンIDが渡される(R1に格納されている)。__look_machine_type関数も__look_processor_typeに類似しており、head_common.Sでも定義されています

カーネルでサポートされる開発ボードごとに、machine_desc構造が定義されます。これは、マシンタイプID、開始I / O物理アドレス、割り込み初期化関数など、開発ボードに関連するいくつかのプロパティと機能を定義します以下のためのアーチ/アーム/マッハXXX /に格納されているARMアーキテクチャボード定義ファイル xxxx.c 、開発ボードに関連するいくつかの情報を含む、machine_descプロトタイプ体で定義されているが含ま/ ASM-アーム/マッハ/ arch.hでは、すべてのmachine_desc構造は.arch.info.initセクションにあります。このセクションの開始アドレスは__arch_info_beginで、終了アドレスは__arch_info_endです。関連する開発ボードを使用するには、カーネルも構成する必要があります。関連するファイルをカーネルに含める必要もあります(arch / arm / math-s3c2410 / mach-smdk2410.cなど)。構成メニューは、システムタイプ-> XXX machine-> xxにあります。で。

        __lookup_machine_type関数は上記の__lookup_processor_type関数に似ており、.arch_info_initセクションの仮想開始アドレスと終了アドレスが取得され、物理アドレスに変換されます。次に、machine_descのマシンIDをセグメントの開始アドレスから読み取り、R1と比較します。一致する場合は、ラベル2にジャンプして戻ります。それらが一致しない場合は、内部の情報を読み続け、一致しない場合は、割り当てR5 = 0が終了します。

③MMUを有効にするページテーブルを作成し、スタックを初期化し、BSSセグメントをクリアし、データセグメントなどをコピーし、start_kernel(head-common.S内)を呼び出してカーネルの第2ステージに入ります。

__enable_mmuを呼び出してMMU関数を有効にした後、関数は最終的にR13の内容を実行します(つまり、上記で保存した__switch_data)。__Switch_dataは、多くの関数を定義するhead_common.Sで定義されています。

上記の関数の最後で、main.cのstart_kernelを呼び出して、2番目のステージに入ります。

カーネル起動の第2段階:

u-bootがカーネルに渡すパラメーターには2つのタイプがあります。1つは事前に存在するアドレスのタグリスト、もう1つはカーネルの呼び出し時にR1レジスターで指定されたマシンIDです。マシンIDは、ブートフェーズ(上記でマシンIDを検出したとき)で使用され、タグリストは最初にsetup_arch関数で処理されます。

set_arch関数の機能:​​プロセッサーに関連するいくつかの設定を行います->開発ボードに関連するいくつかの設定を行います->タグリストを処理します->コマンドラインパラメーターを処理します->ページテーブルpaging_init(&meminfo、mdesc)を再初期化します。

初期化ページテーブルpaging_initの2番目のパラメータは、前のlookup_machine_type関数によって返されたmachine_desc構造で、この構造は、arch / arm / mach-xxx / mach-smdkxxx.c関数で定義されています。s3c2440開発ボードの定義は以下の通りです。この構造はしばしば重要であり、ボードレベルの初期化はここで定義されます

paging_init-> devicemap_init-> mdesc-> map_io()のmap_ioは、この構造体の.map_io関数ポインターのメンバーです次のクロックを変更する必要があります。16934400を12MHzに変更してください。

コンソール初期化関数:

__con_initcall_startと__con_initcall_endの間に定義された各関数を呼び出します。これらの関数は、console_initcall()マクロを使用して指定されます。このマクロは、.con_initcall_initの属性を持つ関数を定義するために使用されます。

一連の初期化の後、start_kernelはrest_init()を呼び出し、rest_init()関数でカーネルスレッドkernel_initが作成されます。主にファイルシステムをマウントしてアプリケーションを実行するには、ルートファイルシステムをprepare_namespace()にマウントします

ファイルシステムをマウントした後、init_post()を実行します。これにより、主に/ dev / consoleデバイスファイルが開き、run_init_process()を呼び出してinitプログラムを実行します。

カーネルは最初のプロセスinitを開始するために実行され、initはさまざまなアプリケーションを分岐します。その後、ユーザー空間でコンテンツの実行を開始できます。

元の記事を35件公開 Like1 Visits 1870

おすすめ

転載: blog.csdn.net/lzj_linux188/article/details/102695522
おすすめ