目次
リダイレクトを再配置します。これにより、mmu が有効になります。 mmu をオンにする操作は、第 1 レベルのページ テーブルのアドレスと権限を satp" >relocate リダイレクトを再配置します。これにより、mmu が有効になります。 mmu をオンにする操作は、第 1 レベルのページ テーブルのアドレスと権限を satp
ホームページ 運用・保守 Linuxの運用と保守 RISC-V Linuxアセンブリ起動プロセス解析

RISC-V Linuxアセンブリ起動プロセス解析

Aug 01, 2023 pm 03:40 PM
linux risc-v

RISC-V Linux のアセンブリ起動部分は比較的単純で、それほど複雑ではありません。ページ テーブルの作成とリダイレクトという 2 つのコア部分があります。ページテーブルの作成はC言語で書かれています、今日はまずアセンブリ部分を解析していきます、まずアセンブリの起動プロセス全体を解析してから、リダイレクトの解析をしていきます。

注: この記事は、linux5.10.111 カーネルに基づいています

アセンブリ起動プロセス

コンパイルが何を行うのか全体的な分析から始めて、一般的なフレームワークを取得しましょう。

パス: arch/riscv/kernel/head.S、入り口は ENTRY(_start_kernel)

RISC-V Linuxアセンブリ起動プロセス解析

ENTRY(_start_kernel) から開始して、起動前の初期化と、ページ テーブルを確立する前の主な作業を実行します。

  • #すべての割り込みを閉じる
    #
    /* 关闭所有中断 */
        csrw CSR_IE, zero
        csrw CSR_IP, zero
    ログイン後にコピー
#グローバル ポインタ gp をロード
  • #
    /* 加载全局指针gp */
    .option push
    .option norelax
        la gp, __global_pointer$
    .option pop
    ログイン後にコピー
FPU を無効にする
  • /* 禁用 FPU 以检测内核空间中浮点的非法使用*/
        li t0, SR_FS
        csrc CSR_STATUS, t0
    ログイン後にコピー
開始するコアを選択してください
  • /* 选择一个核启动 */
        la a3, hart_lottery
        li a2, 1
        amoadd.w a3, a2, (a3)
        bnez a3, .Lsecondary_start
    ログイン後にコピー
クリアbss セグメント
  • /* 清除bss */
        la a3, __bss_start
        la a4, __bss_stop
        ble a4, a3, clear_bss_done
    ログイン後にコピー
ハート ID と dtb アドレスを保存
  • /* 保存hatr id和dtb地址,hart id保存到a0,dtb地址保存到a1 */
        mv s0, a0
        mv s1, a1
        la a2, boot_cpu_hartid
    ログイン後にコピー
sp ポインタを設定
  •     la sp, init_thread_union + THREAD_SIZE
    ログイン後にコピー
上記の作業が完了すると、一時ページ テーブルの作成が開始され、C 関数 setup_vm にジャンプして一時ページ テーブルを作成します
  •     mv a0, s1
        call setup_vm // 跳转到C函数setup_vm,setup_vm会创建临时页表
    ログイン後にコピー
リダイレクト
  • #ifdef CONFIG_MMU
        la a0, early_pg_dir
        call relocate	//重定向,实际就是开启MMU
    #endif
    ログイン後にコピー
例外ベクタ アドレスを設定し、C 環境をリロードします
  •     call setup_trap_vector
    /* 重载C环境 */
        la tp, init_task
        sw zero, TASK_TI_CPU(tp)
        la sp, init_thread_union + THREAD_SIZE
    ログイン後にコピー
最後に C 関数 start_kernel にジャンプし、C 言語部分の初期化が開始され、アセンブリ部分が実行されます
  • tail start_kernel
    ログイン後にコピー
    完全な _start_kernel アセンブリ コード:
  • ENTRY(_start_kernel)
    	/* 关闭所有中断 */
    	csrw CSR_IE, zero
    	csrw CSR_IP, zero
    
    	/* 在源码中,这里有一个M模式处理的宏,这里没有用到,直接跳过*/
    
    	/* 加载全局指针gp */
    .option push
    .option norelax
    	la gp, __global_pointer$
    .option pop
    
    	/* 禁用 FPU 以检测内核空间中浮点的非法使用*/
    	li t0, SR_FS
    	csrc CSR_STATUS, t0
    
    #ifdef CONFIG_SMP
    	li t0, CONFIG_NR_CPUS
    	blt a0, t0, .Lgood_cores
    	tail .Lsecondary_park
    .Lgood_cores:
    #endif
    
    	/* 选择一个核启动 */
    	la a3, hart_lottery
    	li a2, 1
    	amoadd.w a3, a2, (a3)
    	bnez a3, .Lsecondary_start
    
    	/* 清除bss */
    	la a3, __bss_start
    	la a4, __bss_stop
    	ble a4, a3, clear_bss_done
    clear_bss:
    	REG_S zero, (a3)
    	add a3, a3, RISCV_SZPTR
    	blt a3, a4, clear_bss
    clear_bss_done:
    
    	/* 保存hatr id和dtb地址,hart id保存到a0,dtb地址保存到a1 */
    	mv s0, a0
    	mv s1, a1
    	la a2, boot_cpu_hartid
    	REG_S a0, (a2)
    
    	/* 初始化页表,然后重定向到虚拟地址 */
    	la sp, init_thread_union + THREAD_SIZE
    	mv a0, s1
    	call setup_vm // 跳转到C函数setup_vm,setup_vm会创建临时页表
    #ifdef CONFIG_MMU
    	la a0, early_pg_dir
    	call relocate	//重定向,实际就是开启MMU
    #endif /* CONFIG_MMU */
    
    	call setup_trap_vector
    	/* 重载C环境 */
    	la tp, init_task
    	sw zero, TASK_TI_CPU(tp)
    	la sp, init_thread_union + THREAD_SIZE
    
    #ifdef CONFIG_KASAN
    	call kasan_early_init
    #endif
    	/* Start the kernel */
    	call soc_early_init
    	tail start_kernel	//跳转到C函数start_kernel,开始C语言部分初始化
    ログイン後にコピー
アセンブリの非常に重要な部分は、後続のプログラムが実行を継続できるかどうかを決定するページ テーブルの作成です。 setup_vm がページ テーブルを作成した後、relocate リダイレクトの実行が開始されます。このリダイレクトは主に mmu を有効にします。relocate のアセンブリは以下で分析されます。

relocate リダイレクトを再配置します。これにより、mmu が有効になります。 mmu をオンにする操作は、第 1 レベルのページ テーブルのアドレスと権限を satp

レジスタに書き込むことであり、これは mmu をオンにするものとみなされます。

#ifdef CONFIG_MMU
    la a0, early_pg_dir //跳转到relocate前,先把第一级页表early_pg_dir的地址存入a0
    call relocate		//跳转到relocate,开启MMU
#endif
ログイン後にコピー

relocate有两次开启mmu的操作,第一次开启mmu使用的是setup_vm()建立的trampoline_gd_dir页表,这页表保存的是kernel的前2M内存。第二次开启MMU使用的是early_pg_dir页表,这个页表映射了整个kernel内存以及dtb的4M空间。

如果trampoline_pg_dir或者early_pg_dir这两个页表的映射没弄好的话,开启MMU的时候就会失败,所以页表的建立十分关键。页表创建后续再深究,下面分析relocate汇编代码。

  • 计算返回地址

    返回地址就是ra加上虚拟地址和物理地址之间的偏移量,这个是固定偏移量。PAGE_OFFSETkernel入口地址对应的虚拟地址,_start就是kernel入口地址的虚拟地址,PAGE_OFFSET - _start就得到它们之间的偏移,然后再和ra相加,就是返回地址。

/* Relocate return address */
	li a1, PAGE_OFFSET
	la a2, _start
	sub a1, a1, a2
	add ra, ra, a1
ログイン後にコピー
  • 将异常入口1f的虚拟地址写入stvec寄存器

    因为一旦开启MMU,地址都变成了虚拟地址,原来访问的都是物理地址,开启MMU时,地址发生了改变,VA != PA,从而进入异常,所以要先设置异常入口地址,此时的异常入口为1f

/* Point stvec to virtual address of intruction after satp write */
	la a2, 1f
	add a2, a2, a1
	csrw CSR_TVEC, a2
ログイン後にコピー
  • 提前计算切换到early_pg_dir页表要写入satp的值

再进入relocate之前,就已经把early_pg_dir赋值给a0了,所以a0是early_pg_dir。srl是逻辑右移,mmu使用的是sv39,虚拟地址39位,物理地址56位:

RISC-V Linuxアセンブリ起動プロセス解析低12位是偏移量,所以PAGE_SHIFT等于12,将early_pg_dir地址右移12位存到a2。根据satp寄存器定义:

RISC-V Linuxアセンブリ起動プロセス解析

MODE0x8 に等しい場合は、sv39 mmu を使用することを意味し、0x0 はアドレス変換がないことを意味します。つまり、MMU は有効になっていません。ここで、STAP_MODEsv39、つまり 0x8 です。 early_pg_dir アドレスと SATP_MODE の論理和をとった後、satp レジスタに書き込まれた値を取得し、最後にそれを a2 に保存できます。

/* Compute satp for kernel page tables, but don't load it yet */
	srl a2, a0, PAGE_SHIFT
	li a1, SATP_MODE	//sv39 mmu
	or a2, a2, a1
ログイン後にコピー
  • 第一次开启MMU,使用trampoline_pg_dir页表

satp值的计算和上述是一样的。开启MMU之前,通过sfence.vma命令先刷新TLB。此时开启MMU,就会进入下面的标号为1的汇编段

	la a0, trampoline_pg_dir
	srl a0, a0, PAGE_SHIFT
	or a0, a0, a1
	sfence.vma	
	csrw CSR_SATP, a0
ログイン後にコピー

进入异常1f段,重新设置异常入口为.Lsecondary_park,然后切换到early_pg_dir页表,相当于第二次开启MMU。此时,如果之前建立的early_pg_dir页表不对,则会就进入.Lsecondary_park.Lsecondary_park里面是个wfi指令,是个死循环。

完整relocate汇编代码:

relocate:
	/* Relocate return address */
	li a1, PAGE_OFFSET
	la a2, _start
	sub a1, a1, a2
	add ra, ra, a1

	/* Point stvec to virtual address of intruction after satp write */
	la a2, 1f
	add a2, a2, a1
	csrw CSR_TVEC, a2

	/* Compute satp for kernel page tables, but don't load it yet */
	srl a2, a0, PAGE_SHIFT
	li a1, SATP_MODE
	or a2, a2, a1

	/*
	 * Load trampoline page directory, which will cause us to trap to
	 * stvec if VA != PA, or simply fall through if VA == PA.  We need a
	 * full fence here because setup_vm() just wrote these PTEs and we need
	 * to ensure the new translations are in use.
	 */
	la a0, trampoline_pg_dir
	srl a0, a0, PAGE_SHIFT
	or a0, a0, a1
	sfence.vma
	csrw CSR_SATP, a0
.align 2
1:
	/* Set trap vector to spin forever to help debug */
	la a0, .Lsecondary_park
	csrw CSR_TVEC, a0

	/* Reload the global pointer */
.option push
.option norelax
	la gp, __global_pointer$
.option pop

	/*
	 * Switch to kernel page tables.  A full fence is necessary in order to
	 * avoid using the trampoline translations, which are only correct for
	 * the first superpage.  Fetching the fence is guarnteed to work
	 * because that first superpage is translated the same way.
	 */
	csrw CSR_SATP, a2
	sfence.vma

	ret
ログイン後にコピー

总结

以上就是RISC-V Linux的汇编启动流程,虽说RISC-V的指令不复杂,但要理解这个汇编启动的部分,还是需要一点基础和时间。另外,大多数人工作中基本用不上汇编,只有真正用上了理解才会比较深。希望本文能够帮助到有需要的人。

以上がRISC-V Linuxアセンブリ起動プロセス解析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Linuxは実際に何に適していますか? Linuxは実際に何に適していますか? Apr 12, 2025 am 12:20 AM

Linuxは、サーバー、開発環境、埋め込みシステムに適しています。 1.サーバーオペレーティングシステムとして、Linuxは安定して効率的であり、多くの場合、高電流アプリケーションの展開に使用されます。 2。開発環境として、Linuxは効率的なコマンドラインツールとパッケージ管理システムを提供して、開発効率を向上させます。 3.埋め込まれたシステムでは、Linuxは軽量でカスタマイズ可能で、リソースが限られている環境に適しています。

Oracleのインスタンス名を表示する方法 Oracleのインスタンス名を表示する方法 Apr 11, 2025 pm 08:18 PM

Oracleでインスタンス名を表示するには3つの方法があります。「sqlplus」と「v $ instanceからselect instance_name;」を使用します。」コマンドラインのコマンド。 「show instance_name;」を使用しますSQL*Plusのコマンド。オペレーティングシステムのタスクマネージャー、Oracle Enterprise Manager、またはオペレーティングシステムを介して、環境変数(LinuxのOracle_Sid)を確認してください。

LinuxでDockerを使用:包括的なガイド LinuxでDockerを使用:包括的なガイド Apr 12, 2025 am 12:07 AM

LinuxでDockerを使用すると、開発と展開の効率が向上する可能性があります。 1。Dockerのインストール:スクリプトを使用して、ubuntuにDockerをインストールします。 2.インストールの確認:sudodockerrunhello-worldを実行します。 3。基本的な使用法:NginxコンテナDockerrun-Namemy-Nginx-P8080を作成します:80-Dnginx。 4。高度な使用法:カスタム画像を作成し、DockerFileを使用してビルドして実行します。 5。最適化とベストプラクティス:マルチステージビルドとドッケルコンポスを使用して、DockerFilesを作成するためのベストプラクティスに従ってください。

Apacheを始める方法 Apacheを始める方法 Apr 13, 2025 pm 01:06 PM

Apacheを開始する手順は次のとおりです。Apache(コマンド:sudo apt-get install apache2または公式Webサイトからダウンロード)をインストールします(linux:linux:sudo systemctl start apache2; windows:apache2.4 "serviceを右クリックして「開始」を右クリック) (オプション、Linux:Sudo SystemCtl

Apache80ポートが占有されている場合はどうすればよいですか Apache80ポートが占有されている場合はどうすればよいですか Apr 13, 2025 pm 01:24 PM

Apache 80ポートが占有されている場合、ソリューションは次のとおりです。ポートを占有するプロセスを見つけて閉じます。ファイアウォールの設定を確認して、Apacheがブロックされていないことを確認してください。上記の方法が機能しない場合は、Apacheを再構成して別のポートを使用してください。 Apacheサービスを再起動します。

DebianのNginx SSLパフォーマンスを監視する方法 DebianのNginx SSLパフォーマンスを監視する方法 Apr 12, 2025 pm 10:18 PM

この記事では、Debianシステム上のNginxサーバーのSSLパフォーマンスを効果的に監視する方法について説明します。 Nginxexporterを使用して、NginxステータスデータをPrometheusにエクスポートし、Grafanaを介して視覚的に表示します。ステップ1:NGINXの構成最初に、NGINX構成ファイルのSTUB_STATUSモジュールを有効にして、NGINXのステータス情報を取得する必要があります。 NGINX構成ファイルに次のスニペットを追加します(通常は/etc/nginx/nginx.confにあるか、そのインクルードファイルにあります):location/nginx_status {stub_status

Oracleの監視を開始する方法 Oracleの監視を開始する方法 Apr 12, 2025 am 06:00 AM

Oracleリスナーを開始する手順は次のとおりです。Windowsのリスナーステータス(LSNRCTLステータスコマンドを使用)を確認し、LinuxとUNIXのOracle Services Managerで「TNSリスナー」サービスを開始し、LSNRCTL Startコマンドを使用してリスナーを起動してLSNRCTLステータスコマンドを実行してリスナーを確認します。

Debianシステムでリサイクルビンをセットアップする方法 Debianシステムでリサイクルビンをセットアップする方法 Apr 12, 2025 pm 10:51 PM

この記事では、デビアンシステムでリサイクルビンを構成する2つの方法を紹介します:グラフィカルインターフェイスとコマンドライン。方法1:Nautilusグラフィカルインターフェイスを使用して、ファイルマネージャーを開きます。デスクトップまたはアプリケーションメニューでNautilusファイルマネージャー(通常は「ファイル」と呼ばれる)を見つけて起動します。リサイクルビンを見つけてください:左ナビゲーションバーのリサイクルビンフォルダーを探してください。見つからない場合は、「他の場所」または「コンピューター」をクリックして検索してみてください。リサイクルビンプロパティの構成:「リサイクルビン」を右クリックし、「プロパティ」を選択します。プロパティウィンドウで、次の設定を調整できます。最大サイズ:リサイクルビンで使用可能なディスクスペースを制限します。保持時間:リサイクルビンでファイルが自動的に削除される前に保存を設定します

See all articles