Windows system >> Windowsの知識 >  >> Linuxシステムチュートリアル >> Linuxチュートリアル >> arm + linuxの起動プロセスは、コンパイルされたリンクからカーネル

arm + linuxの起動プロセスは、コンパイルされたリンクからカーネル

  
またはvmlinuxを生成するプロセスに入ります - 最初のものは、
kernel \\ arch \\ arm \\ kernel \\ head-armvです。 .o、そして我々はまた、最初にそれを分析する
ldsリンクファイルkernel \\ arch \\ arm \\ vmlinux.ldsを見ました。//エントリポイントはstextがhead-armv.sにあるべきです
セクション
{
。= 0xC0008000; //ベースアドレスは、カーネルの先頭にある仮想アドレスです。
.init:{/*初期化コードとデータ* /
_stext =。;
__init_begin =。;
*(。text.init)
__proc_info_begin =。;
*(。proc.info)
__proc_info_end =。;
__arch_info_begin =。;
*(。arch.info)
__arch_info_end =。;
__tagtable_begin =。;
*(。taglist)
__tagtable_end =。;
*(。data.init)
。= ALIGN(16);
__setup_start =。;
*(。setup.init)
__setup_end =。;
__initcall_start =。;
*(。initcall.init)
__ initcall_end =。;
。= ALIGN(4096);
__init_end =。;
}
仮想アドレスと物理アドレスについて:MMUを使用した後、システムは仮想アドレスを使用します。実際の物理アドレスを指すMMUを介したアドレス、ここでは0xC0008000の実際の物理アドレスは0x30008000です。具体的なMMUの紹介リファレンス「ARMアーキテクチャとプログラミング」。
head-armv.sというプログラムのエントリを探します。.section" .text.init"、#alloc、#execinstr
.type stextと#function
ENTRY(stext)
Mov r12、r0
mov r0、#F_BIT |  I_BIT |  MODE_SVC @ svcモードを確認してください
msr cpsr_c、r0 @およびすべてのirqが無効になっています
bl __lookup_processor_type
teq r10、#0 @無効なプロセッサですか?
moveq r0、# 'p' @ yes、error ' P '
beq __error
bl __lookup_architecture_type
teq r7、#0 @アーキテクチャが無効ですか?
moveq r0、#' a '@ yes、エラー' a '
beq __error
bl __create_page_tables
adr lr、__ret @ return address
add pc、r10、#12 @ initialise processor
最後の文がどこでジャンプしたかを見てみましょう。
__lookup_processor_typeにあるr10の値に従ってください。
__lookup_processor_type:
adr r5、2f //r5ラベル2のアドレスベースアドレスは0x30008000です。
ldmia r5、{r7、r9、r10} //r7 = __ proc_info_end r9 = __ proc_info_begin < Br> sub r5、r5、r10 //r10ラベル2のリンクアドレスは0xc0008000です。
追加アドレスr7、r7、r5 @
追加アドレスr10、r9、r5 //r10はベースアドレスに変換されます。 0x30008000 __proc_info_begin
2:.long __proc_info_end
.long __proc_info_begin
.long 2b
このr10には__proc_info_beginのアドレスが格納されています。まだMMUを開いていないので、ベースアドレスを0x30008000に変更する必要があります__proc_info_beginが見つかります。
このラベルは上記のvmlinux.ldsにあり、.proc.infoセクションはリンクされています。 、
このセクションはkernel \\ arch \\ arm \\ mm \\ proc-arm920.sの最後にあります。
.section" .proc.info"、#alloc、#execinstr
.type __arm920_proc_info、# Object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.long 0x00000c1e @ mm _flam

b __arm920_setup
わかりましたので、pc、r10、#12 jumpを追加してください。このアドレスにはジャンプステートメントが含まれているだけなので、移動してください。bステートメントは相対アドレスを使用するため、アドレスを変更する必要はありません。__arm920_setupにジャンプします。前のステートメントはadr lrです。 、__ret、__arm920_setupの戻りアドレスを__retに設定すると、
__arm920_setupの実行後にhead-armv.sに戻る__retラベルは引き続き実行されます。
__ret:ldr lr、__switch_data
mcr P15、0、r0、c1、c0 //ここでMMUが開かれていることに注意してください。
r0、r0
mov r0、r0
mov pc、 //__mmap_switchedにジャンプ、ここでは仮想アドレスが使用されています
//この命令ldr lr、__switch_dataがロードされた__mmap_switched addressは、仮想アドレスahです。_ _switch_data:.long __mmap_switched
from _ _ _mmap_switchを実行するためには、C言語コードに変換する必要があります。

SYMBOL_NAME(start_kernel)//kernel \\ init \\ main.c内このプログラムは特に複雑なものではありません。理解して、私はコメントに一つずつ行くことはできません。
ここにフローチャートがあります

C言語で理解するのは難しくありません。
lock_kernel();
printk(linux_banner);
setup_arch(& command_line);
printk("カーネルコマンドライン:%s \\ n"、saved_command_line);
parse_options(command_line);
trap_init();
init_IRQ();
sched_init();
softirq_init();
time_init();
start_kernelが最後に関数を呼び出すのを見るために各関数を追いかける初期化作業の束です。 > static void rest_init(void)


ログインkernel_thread(ini​​t、NULL、CLONE_FS)  CLONE_FILES |  CLONE_SIGNAL);
unlock_kernel();
current-> need_resched = 1;
cpu_idle();
}
kernel_threadを使用してinitプロセスを作成し、main.cを実行します。 init関数
lock_kernel();
do_basic_setup();
do_initcalls関数はdo_basic_setupで呼び出されます。
さまざまなドライバはdo_initcalls(void)で実行されます。
static void __init do_initcalls (void)
{
initcall_t * call;
call =&__ initcall_start;
do {
(* call)();
call ++;
} while(call) <& __ initcall_end);
flush_scheduled_tasks();
} __initcall_startはvmlinux.ldsにも割り当てられているので、kernel \\ include \\ linuxで.initcall.iniセクションを探す必要があります。 \\ init.hで見つけることができます。
#define __init_call __attribute__((未使用、__ section__(" .initcall.init"))))
typedef int(* initcall_t)(void);
#define __initcall( Fn)\\
static initcall_t __initcall _ ## fn __init_call = fn
注意深く調べた結果、これが.initcall.initセクションの初期化関数のアドレスであることがわかります。初期化関数
MODULEを定義しない場合は、#define module_init(x)__initcall(x);
ドライバをカーネルにコンパイルする場合は、非常に簡単です。
init's last
if (execute_command)
execve(execute_command、argv_init、envp_init);
execute_commandは、ppcbootによって渡されるコマンドライン引数に関連しています。つまり、init = /linuxrcは、ルートディレクトリでlinuxrcスクリプトを実行します。このスクリプトはbusybox
を実行し、busyboxは/etc/init.d/rcSスクリプトを再度実行します。このスクリプトは再び実行されます/usr/etc/rc.local
Copyright © Windowsの知識 All Rights Reserved