背景
Read the fucking source code!
--By魯迅A picture is worth a thousand words.
--Byゴーリキー
説明:
- カーネルのバージョン:4.14
- ARM64プロセッサ、コンテックス-A53、二核
- ツールを使用してください:Source Insightは3.5、Visioの
1.はじめに
私たちはいくつかの簡単な質問を考えてみましょうか?
- システムがどのように物理メモリを認識しているのですか?
- 実メモリ管理初期化コードが実行される前にカーネルがどのように対処するメモリを割り当てる必要がありますか?
さんが読んで、最初の質問に答えることをしてみましょうdts
学生をドキュメント見ている必要がありますmemory
へのノードのarch/arm64/boot/dts/freescale/fsl-ls208xa.dtsi
例:
memory@80000000 {
device_type = "memory";
reg = <0x00000000 0x80000000 0 0x80000000>;
/* DRAM space - 1, size : 2 GB DRAM */
};
このノードは、開始アドレスとメモリのサイズを記述し、実際には、カーネルは、構文解析dtb
ファイル読む時間memory
システムメモリに登録して検出するように、ノードの内容を。
そして、新たな問題再び?Ubootは意志kernel image
とdtb
メモリにコピーし、そしてだろうdtb物理地址
知らせるkernel
、kernel
物理アドレスから読み取る必要があるdtb
最後のメモリ情報を取得するために、ファイルおよび解決、dtb
アクセスする仮想アドレスにマッピングされる物理アドレスが、今回はpaging_init
まだしていません呼び出して、それはそれを行うにはどのようにして、物理アドレスのマッピングがまだ完了していないと言うことでしょうか?はい、Fixed map
メカニズムが登場しました。
すべての物理メモリは、システムに追加された:2番目の質問への答えmm_init
のシステムが使用する前に、memblock
メモリを管理するためのモジュールを。
アドベンチャーは、それを開きます!
2. early_fixmap_init
簡単に言えば、Fixed map
仮想アドレス期間の領域を指し、並進ステージ内のすべての線形アドレスは、この領域で良好に決定され、これらの仮想アドレスは、必要boot
物理アドレスフェーズにマッピングします。
仮想アドレス空間の写真を見て:
図はfixed: 0xffffffbefe7fd000 - 0xffffffbefec00000
、記載されているFixed map
領域です。
そして、この地域のより詳細なレイアウトは何ですか?見てください、それは明確な計画を構造をしますarch/arm64/include/asm/fixmap.h
enum fixed_address
図からわかるようにアクセスしたい場合は、DTB
物理アドレスが配置され、その後、物理アドレスをにマップする必要があるFixed map
地域、そして仮想アドレスが領域にアクセスします。アクセスIO
スペースが同じ理由で、次のようにと話をします。
そして、見てみましょうearly_fixmap_init
、それの機能のキーコード:
void __init early_fixmap_init(void)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
unsigned long addr = FIXADDR_START; /* (1) */
pgd = pgd_offset_k(addr); /* (2) */
if (CONFIG_PGTABLE_LEVELS > 3 &&
!(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa_symbol(bm_pud))) {
/*
* We only end up here if the kernel mapping and the fixmap
* share the top level pgd entry, which should only happen on
* 16k/4 levels configurations.
*/
BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
pud = pud_offset_kimg(pgd, addr);
} else {
if (pgd_none(*pgd))
__pgd_populate(pgd, __pa_symbol(bm_pud), PUD_TYPE_TABLE); /* (3) */
pud = fixmap_pud(addr);
}
if (pud_none(*pud))
__pud_populate(pud, __pa_symbol(bm_pmd), PMD_TYPE_TABLE); /* (4) */
pmd = fixmap_pmd(addr);
__pmd_populate(pmd, __pa_symbol(bm_pte), PMD_TYPE_TABLE); /* (5) */
......
}
キーポイント:
FIXADDR_START
定義Fixed map
領域の開始アドレスは、配置されているarch/arm64/include/asm/fixmap.h
中で、pgd_offset_k(addr)
入手するにはaddr
PGDグローバル・ページ・テーブルに対応するアドレスをentry
、このPGDグローバル・ページ・テーブルは、swapper_pg_dir
グローバル・ページ・テーブル;bm_pud
物理アドレスは、内容の書かれたPGDグローバル・ページ・テーブルです。bm_pmd
物理アドレスが書かれたPUDのページディレクトリテーブルです。bm_pte
物理アドレスは、内容の書かれたPMDのページテーブル表です。
bm_pud/bm_pmd/bm_pte
ページ・テーブル、ページテーブル記憶レベルの中央に対応する3つのグローバル配列、entry
次のように定義されます:
static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
実際には、early_fixmap_init
再び使用される対応を移入するときだけ充填を行っていないマッピング、特定の物理および仮想アドレスのマッピングのための枠組みを確立し、これはユーザー固有ですpte entry
。ようなfixmap_remap_fdt()
機能は、典型的な充填でpte entry
読み取る前にマッピングの最終段階を完了するために、プロセスdtb
ファイルを。
理解するための絵に、理解して徹底しました:
3. early_ioremap_init
あなたは初期ブートで動作する必要がある場合はIO设备
、その後、ioremap
一緒にプレイするために、実際のメモリ管理との関係が大きすぎ、あまりにも詳細な分析ではありませんので。
簡単に言えば、ioremap
空間7 * 256K
領域に格納されているslot_vir[]
場合、最終的にIO操作の必要性、呼び出す、アレイ__early_ioremap
機能、充填に相当する機能をpte entry
このように仮想アドレスと物理アドレスの最終的なマッピングを完成。
4. memblock
以上の内容について、単に適切にアクセスするためには、伏線されDTB
たファイルを物理アドレス情報を解決します。以下の呼び出し手順への入口から最終追加:
したがって、この章の焦点はしているmemblock
モジュール、これは初期のメモリ割り当てマネージャーです、私は助けるが、中に前に考えることはできませんNuttx
達成するためのメモリプール、および詳細は、すでに明らかではないが、思考の枠組みは似ています。
4.1構造
これは、3つのデータ構造の合計によって記述されています。
struct memblock
これは、すべての物理メモリを維持するために使用されるグローバル変数を定義し;struct memblock_type
メモリ及び記憶保持を含むシステム、メモリの代表的なタイプは、実際に使用されます。struct memblock_region
特定のメモリ領域を記述するために使用され、中に含まれる配列、あなたは128まで保存することができます。struct memblock_type
regions
その上に直接コード:
static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS] __initdata_memblock;
#endif
struct memblock memblock __initdata_memblock = {
.memory.regions = memblock_memory_init_regions,
.memory.cnt = 1, /* empty dummy entry */
.memory.max = INIT_MEMBLOCK_REGIONS,
.memory.name = "memory",
.reserved.regions = memblock_reserved_init_regions,
.reserved.cnt = 1, /* empty dummy entry */
.reserved.max = INIT_MEMBLOCK_REGIONS,
.reserved.name = "reserved",
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
.physmem.regions = memblock_physmem_init_regions,
.physmem.cnt = 1, /* empty dummy entry */
.physmem.max = INIT_PHYSMEM_REGIONS,
.physmem.name = "physmem",
#endif
.bottom_up = false,
.current_limit = MEMBLOCK_ALLOC_ANYWHERE,
};
定義されたmemblock
定義が初期化されているグローバル変数として。初期化時間regions
点アレイのサイズ前記静的グローバル配列であるINIT_MEMBLOCK_REGIONS
、即ち128は、これらのメモリブロックの数を制限し、実際にこの値よりも、配列がされる場合、コードに見ることができます2倍高速の動的拡張。
初期化が終わった後は、一般的には次のようになります。
4.2 memblock_add / memblock_remove
memblock
サブモジュール、基本的なロジックを追加および削除操作のメモリに関連し、そして最終的に呼び出すことによってmemblock_add_range/memblock_remove_range
達成しました。
memblock_add_range
:
図の左側は、パフォーマンスが適切な部分で達成され、機能の実行を示すフローチャートです。図面の右側の部分は、実際の状況は、より多くのがあってもよい典型的なケースであるが、コアロジックが中に挿入されたregion
物理アドレス範囲の重複が表示された場合、次に実行、決意split
最終それを備え、操作を行動操作。flag
region
merge
memblock_remove_range
典型的な場合、以下に示すような機能による効果:
今複数の領域にまたがるオフ領域を、削除する必要がある場合region
、それは最初に呼び出されます、memblock_isolate_range
この作品分割領域であることを、その後、呼び出しmemblock_isolate_range
地域ベースの上でregion
除去操作。
あなたが呼び出すとmemblock_alloc
、IPアドレスを割り当てるための最後の呼び出しを機能をmemblock_add_range
実現するために、このメモリのアプリケーションは、最終的に追加されますreserved
入力し、結局、他の人が使用すべきではない、出て配分されています。
5. arm64_memblock_init
物理メモリがシステムに追加されると、arm64_memblock_init
主な仕事は、いくつかの特別な領域を追加することで、全体の物理メモリを整理しますreserved
メモリに。以下に示すように機能が、完成されています。
- ライトグリーンのボックスが示しているメモリ領域を確保されており、残りの部分は、あなたがメモリの実際の使用に行くことができるということです。
物理メモリの一般的な外観があり、メモリページテーブルマッピングの必要性についてのフォローアップは、の仮想アドレスから物理アドレスへの実際のマッピングを行います。
それは継続されるでしょう。