質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

Q&A

解決済

1回答

1976閲覧

[難解]Linuxカーネル kernel_initの処理に関して どのように最初のユーザーモードプロセスが生成されるのか。

kazuyakazuya

総合スコア193

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

x86

x86はIntel 8086 CPU シリーズの命令セットアルキテクチャーです。

0グッド

0クリップ

投稿2020/07/29 13:23

編集2020/07/29 13:32

Linuxにおいて最初のユーザープロセスがどのように生成されるのかを調べています。

カーネル探検(rest_init()からプロセス番号1生成まで)

要約しました。

① kernel_thread(kernel_init,...) ↓ ② kernel_thread(kerneladd,...) ↓ ③ schdule() ↓ ④ kernel_init() //以下の関数はkernel_init内で呼ばれます。 ↓ ⑤ init_post ↓ ⑥ run_init_process() kernel_execve(init_filename,...) //execveシステムコールを呼び出すだけ。

で、前提

forkシステムコール・・・指定したプロセスをコピー・クローンを作成
execveシステムコール・・・このシステムコールを読んだプロセスのメモリ内容を
引数に指定したプログラム(言い方が適切ではないかも)用に"完全に"入れ替える。

また、

③においてスケジューリング関数が呼ばれるまでプロセスの概念はないはずです。
kernel_thread関数が2回呼ばれています。
これにより、以下の2つがスケジューリング関数が呼ばれて
スケジュールされることによりCPU実行権が回ってくるまで待機することになります。
カーネルスレッドとして動くことになる。

・kernel_init
・kernel_add

で、本題

kernel_init内(これはカーネルスレッド)でramfsの/initを実行するために
run_init_process()以下の関数を呼び出していますよね。(詳しくはサイトを参照)

execveシステムコール・・・このシステムコールを読んだプロセスのメモリ内容を 引数に指定したプログラム(言い方が適切ではないかも)用に"完全に"入れ替える。

ならば、カーネルスレッドであるkernel_initのメモリ内容はinit用に完全に入れ替わってしまうことになってしまいますよね?
まぁ、実際にはそうなりませんが なぜそうならないのか?

ここで呼ばれているexecveシステムコールと言うのは普段僕たちが目にしているexecveシステムコールとは別のものではないか?(とりあえず、仕組みとしてそう作ることはできるだろう)
とも考えているのですが実際はどうなっているんでしょうか?

これ知っている人このサイトにいるんですかね・・・
もし知っていたら教えてください!

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

このページに書いてあることが回答になっているっぽいですけどどうですかね。

投稿2020/07/29 14:08

hytNInE

総合スコア133

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuyakazuya

2020/07/29 14:35

あれ、ちょっと誤解があったかも ちょっと考えます。。。
kazuyakazuya

2020/07/29 14:49

すみません 私の理解力が低い上 見落としているものだと思いますがそのリンク先のどのへんでしょうか? 念のため・・・えーと(私の聞きたいのは)、 https://qiita.com/saikoro-steak/items/e8121afdd5f294e14c43#kernel_init run_init_process kernel_execve do_execve_common bprm_mm_init といった関数が記述されていますが・・・ do_execve_common bprm_mm_init 上記の関数というのはカーネルスレッドとして動いているkernel_init関数内で呼ばれている関数ですよね? 上記の関数が呼ばれる前にexecveによりinitがメモリにロードされる。 (execveを呼んだkernel_initの内容のメモリは消える。 do_execve_common bprm_mm_init とかも) なら、execveでinitを実行した後それら関数は呼ばれないことになってしまうのではないか? でも実際そうならないのはなぜか?ということです。
hytNInE

2020/07/29 16:46

自分もそこまで詳しく読んだわけではないので、「ブートローダがRAM上に配置したinitramfsを展開し、rootfsを作成する」「rootfs上のinitを実行する」あたりの項目に期待する答えがあるのかなと思ったしだいです。 改めて、kazuyakazuyaさんが参考にされているページを見てみましたが、処理概要の項目do_execve_commonの説明の最後でinitが実行されるとあります。また、bprm_mm_initもdo_execve_commonの中で呼ばれている関数っぽいです。なので、kernel_execveの処理後にdo_execve_common等が呼ばれるのでなくkernel_execveの中でdo_execveやbprm_mm_initは行われているということなのではないでしょうか。 exec関連のコード(https://github.com/torvalds/linux/blob/master/fs/exec.c)を見てもそうなっているっぽいので、こちらも見てみてください。
kazuyakazuya

2020/07/31 14:38

いくつか分からない点がありますが・・・ まず do_execve_commonまたその下に書かれている関数たちってのは do_execveの中身であり、まだinitは実行されていませんよね。 私は質問でここでのexecveによってメモリ書き換えはされないと書きましたが あれ?やっぱされてるのかな だとしたら kernel_init(カーネルスレッド)の中でexecveが呼ばれ kernel_init(カーネルスレッド)がinit(ユーザータスク)に生まれ変わるって感じでしょうか?
kazuyakazuya

2020/07/31 14:41

リンク先の記述で ここから戻り、kernel_execve()に戻る。call sys_execve以降から再開する。iret命令実行。レジスタ復帰。ここでカーネルプロセスから初めてのユーザプロセスが誕生する という部分があります。 kernel_execve()に戻った先というのはどこを指しているのでしょうか? kernel_execve自体はkernel_initの中で呼ばれています。 kernel_execveが実行されてkernel_initがinitに代わっているなら 戻る先はinitってことでしょうか? (ごめんなさい 文章見にくいかもしれません)
hytNInE

2020/08/01 09:24

>kernel_init(カーネルスレッド)がinit(ユーザータスク)に生まれ変わるって感じでしょうか? 一番最初の回答で示したページに以下のような記述があったので、生まれ変わるということで合っているように思います。 「ブートローダがRAM上に配置したinitramfsを展開し、rootfsを作成する」項目内の図にて ・init実行(自身がinitになる) 「rootfs上のinitを実行する」項目内の記述にて ・kernel_init()から以下のようにtry_to_run_init_process()を呼び出すことで最終的にdo_execve()を呼び出し、自身をinitとして実行します。 >kernel_execve()に戻った先というのはどこを指しているのでしょうか? ちょっとその戻るという表現は自分もよくわかりませんでした。 do_execveから辿った最後の処理であるstart_thread()でレジスタを書き換えているので、この関数から抜ける時にはinitに変わっていてkernel_execveには戻らないように思えるのですが。。。
kazuyakazuya

2020/08/02 02:16

最後に一つ! ここで呼ばれているkernel_execveによってユーザープロセス(init)が作成させますが やはり、ここで呼ばれているexecveシステムコールは 普段使っている奴とは別物なのでしょうか?
hytNInE

2020/08/02 13:04

おそらく同じだと思います。 参考にしているページの処理概要のところにあるkernel_execve()の横にも「execveシステムコールを呼び出すだけ。」とあります。実際コードを見てみてもkernel_execveからsys_execveが呼ばれています。 また、execveシステムコールも結局はsys_execveにたどり着いたと記憶してます。なので同じなのではないでしょうか。 ちなみに、kernel_execveはv3の途中以降見当たらなくなってます。なのでv3.0のコードを見て確認しました。処理の大まかな流れは変わらないと思うので、理解したことが無駄になることはないはずですけど。 自分もざっくりと理解しているだけで、コードを詳細に解読してるわけではないので、ちょっとふわっとした回答になってしまいすいません。なので、しっくりきていない部分もあるかもしれませんが、その辺りを解消するには、たぶん本格的にコードを解読していく必要がある気がします。
kazuyakazuya

2020/08/02 14:47

了解です。付き合ってくれてありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問