前回の記事では、RISC-V Linux のエントリ アドレスが 2M にアライメントされている必要があると述べましたが、今日は 2M アライメントの問題を解決する方法について説明します。メモリの一部を最適化します。
注: この記事は linux5.10.111 カーネルに基づいています
各チップが工場から出荷された時点で、そのブートROMのアドレスはチップ内に固定されていると仮定します。ブートROMは0x0、つまり上記のとおりです。電源を入れると、プログラムはアドレス0x0から実行を開始します。
RISC-V Linux を起動する前に、最初に opensbi を実行する必要があるため、opensbi をアドレス 0x0
处,这样芯片上电后,就会从0x0
地址处执行opensbi。在opensbi运行完后,会跳转到opensbi运行地址偏移2M的位置去执行下一级boot(这里下一级boot是kernel),即跳转到0x200000
地址处运行kernel,因此应该把kernel放到内存的0x200000
に配置する必要があります。
メモリ分布図は次のとおりです:
カーネルの場合、起動時に独自のカーネルからアドレスをロードします (つまり、0x200000
) は、ページ テーブル マッピングの確立を開始します。ページ テーブル マッピングが物理メモリに対して確立された場合にのみ、後でこれらのメモリにアクセスできるようになります。カーネルはアドレスの前に 2M メモリをロードします (つまり、0x0 - 0x200000
) はカーネルによって無視され、この 2M メモリに対してページ テーブルは確立されません。つまり、カーネルはこの 2M メモリにアクセスできません。 0x200000
)开始建立页表映射,只有对物理内存建立了页表映射,后面才能访问这些内存。而kernel加载地址前面的2M内存(即0x0 - 0x200000
)将被kernel忽略,不会对这2M内存建立页表,即kernel无法访问这2M内存。
在QEMU上RISC-V Linux的启动信息:
但opensbi实际不需要使用2M这么大的范围,默认是512KB
,opensbi的pmp会保护这512KB
内存,不让其他程序访问。
因此在Kernel和opensbi之间会存在1.5M
512KB
、opensbi の pmp はこれを保護します512KB
メモリ。他のプログラムによるアクセスは許可されません。
1.5M
メモリ ギャップ、およびメモリギャップのこの部分はプログラムによって使用されないため、メモリの無駄が発生します。では、メモリの以前の部分をカーネルに使用させるにはどうすればよいでしょうか。
最適化計画
この 2M メモリを最適化するには 2 つの計画があります: 🎜🎜🎜オプション 1🎜: opensbi をメモリの最後に置き、カーネル エントリ アドレスは 2M アラインメントを維持します。 🎜🎜🎜オプション 2🎜: Opensbi は引き続きメモリの先頭に配置されます。カーネル ソース コードを変更し、2M アライメント制限を解除することで、カーネル アドレスを前方に移動できます。 🎜
opensbi をメモリの最後に置きますが、カーネル エントリ アドレスは 2M アラインメントを維持します。
つまり、カーネルはメモリの前に配置され、opensbi は後ろに配置されます。
たとえば、カーネルはメモリの 0x0
地址处,opensbi放到内存的0x10000000
地址处。这样kernel前面就不会有预留内存,只不过这样需要修改bootrom的地址,将地址从0x0
修改为0x0x10000000
。这种方案只适合芯片还没出厂前,因为用户无法修改bootrom的地址,芯片出厂后,bootrom地址是固定的,假设bootrom地址为0x0
,那么芯片上电后,就会从0x0
开始运行程序,所以opensbi必须放到0x0
アドレスに配置されるため、カーネルは2Mオフセット。
RISC-V Linux のカーネル ソース コードを変更して、2M アライメント制限を解除することもできます。必要なのは setup_vm ()
関数を使用して、 元の第 2 レベルのページ テーブルを第 3 レベルのページ テーブルに変更します。これにより、カーネル エントリ アドレスを 4K に揃えるだけで済み、カーネルを前方に移動するため、フロントメモリが使用されます。 setup_vm()
函数中,将原来的二级页表改为三级页表,这样kernel入口地址只需要4K对齐,因此就能将kernel往前挪,从而利用前面的内存。
路径:arch/riscv/mm/init.c
コードを変更します
元の 2M アライメント チェックをコメントします:
カーネルの最初の 2M ページ テーブル マッピングを第 2 レベルのページ テーブルから第 3 レベルのページ テーブルに変更します。 :
//新增一个PTE pte_t trampoline_pte[PTRS_PER_PTE] __page_aligned_bss; create_pgd_mapping(trampoline_pg_dir,PAGE_OFFSET, (uintptr_t)trampoline_pmd,PGDIR_SIZE,PAGE_TABLE); create_pmd_mapping(trampoline_pmd,PAGE_OFFSET, (uintptr_t)trampoline_pte,PMD_SIZE,PAGE_TABLE); end_va = PAGE_OFFSET + PMD_SIZE; for (va = PAGE_OFFSET; va < end_va; va += PAGE_SIZE) { create_pte_mapping(trampoline_pte,PAGE_OFFSET, load_pa + (va - PAGE_OFFSET), PAGE_SIZE,PAGE_KERNEL_EXEC); }
カーネル全体のページテーブルマッピングが第 2 レベルのページテーブルから第 3 レベルのページテーブルに変更されます: カーネルサイズが 4M+
以上が実践的な戦闘 | RISC-V Linux エントリ アドレス 2M 予約メモリの最適化の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。