6.828: Operating System Engineering (10)

箇条書き再掲。

  • At what point does the processor start executing 32-bit code? What exactly causes the switch from 16- to 32-bit mode?
  • What is the last instruction of the boot loader executed, and what is the first instruction of the kernel it just loaded?
  • Where is the first instruction of the kernel?
  • How does the boot loader decide how many sectors it must read in order to fetch the entire kernel from disk? Where does it find this information?

とりあえず 0x7c00 で止まっているので色々試してみます。

事前確認

とりあえず protect mode になるのは boot/boot.S の以下なあたりかと。

  # Switch from real to protected mode, using a bootstrap GDT
  # and segment translation that makes virtual addresses 
  # identical to their physical addresses, so that the 
  # effective memory map does not change during the switch.
  lgdt    gdtdesc
  movl    %cr0, %eax
  orl     $CR0_PE_ON, %eax
  movl    %eax, %cr0
  
  # Jump to next instruction, but in 32-bit code segment.
  # Switches processor into 32-bit mode.
  ljmp    $PROT_MODE_CSEG, $protcseg

コメントにも記述されてますね。Linux 0.01 でこのあたり云々した記憶がなんとなく残ってるのですが

  • ES、ES、SS 設定して
  • A20 enable にして
  • gdt を load して
  • cr0 をセットして
  • longjmp しとるな

なナニを全部なんとかしてるみたいですね。デバッガで全部確認必要。
あるいは last instruction of the boot loader executed については main.c の以下になるのかな。

	// call the entry point from the ELF header
	// note: does not return!
	((void (*)(void)) (ELFHDR->e_entry & 0xFFFFFF))();

ELF なナニを起動する方法が若干忘却の彼方ですねorz
三番目の質問は kern/kernel.ld 見れば分かるのかどうか。


SECTIONS
{
	/* Load the kernel at this address: "." means the current address */
	. = 0xF0100000;

	.text : {
		*(.text .stub .text.* .gnu.linkonce.t.*)
	}

んーと、kern/entry.S の以下なのかどうか。

.globl		_start
_start:
	movw	$0x1234,0x472			# warm boot

最後のソレが不明。将棋が終わったら gdb 再開します。

確認事項

まだ終わらんのでいくつか情報を整理しておく。

  • protect mode になる瞬間に gdb 上で変化が確認できるのかどうか
  • ELF なソレを呼び出すとき、gdb 上でどう見えるのか楽しみ
  • そして Kernel 起動した瞬間の挙動も楽しみですね

どうなるか。そして将棋はどうなるのか。と思ったらようやく後手勝ちの表示。
それでは gdb 再開します。

再開

ええと、微妙に命令の詳細が異なってます。boot.asm 見ながら si してるんですが、なんとなく合ってはいるかな的ナニ。

  lgdt    gdtdesc
    7c1e:	0f 01 16             	lgdtl  (%esi)
    7c21:	64                   	fs
    7c22:	7c 0f                	jl     7c33 <protcseg+0x1>
  movl    %cr0, %eax
    7c24:	20 c0                	and    %al,%al
  orl     $CR0_PE_ON, %eax
    7c26:	66 83 c8 01          	or     $0x1,%ax
  movl    %eax, %cr0
    7c2a:	0f 22 c0             	mov    %eax,%cr0

微妙。

[   0:7c1e] => 0x7c1e:  lgdtw  0x7c64
0x00007c1e in ?? ()
(gdb) si
[   0:7c23] => 0x7c23:  mov    %cr0,%eax
0x00007c23 in ?? ()

0x7c23 って何だ (わら
si したら 0x7c26 に移行。

[   0:7c26] => 0x7c26:  or     $0x1,%eax
0x00007c26 in ?? ()
(gdb) si
[   0:7c2a] => 0x7c2a:  mov    %eax,%cr0
0x00007c2a in ?? ()

そろそろ protect mode に change するはず。

(gdb) si
[   0:7c2d] => 0x7c2d:  ljmp   $0x8,$0x7c32
0x00007c2d in ?? ()
(gdb) si
The target architecture is assumed to be i386
=> 0x7c32:      mov    $0x10,%ax
0x00007c32 in ?? ()

これって boot loader で見たよね。そりゃ良いのですが、どこに飛ぶのだったか。
あ、まだ protect mode に移行しただけなんだった。boot.asm 的には以下?

00007c32 <protcseg>:

  .code32                     # Assemble for 32-bit mode
protcseg:
  # Set up the protected-mode data segment registers
  movw    $PROT_MODE_DSEG, %ax    # Our data segment selector
    7c32:	66 b8 10 00          	mov    $0x10,%ax

てーことはもう少ししたら bootmain にアレするのかな。

The target architecture is assumed to be i386
=> 0x7c32:      mov    $0x10,%ax
0x00007c32 in ?? ()
(gdb) si
=> 0x7c36:      mov    %eax,%ds
0x00007c36 in ?? ()
(gdb) si
=> 0x7c38:      mov    %eax,%es
0x00007c38 in ?? ()
(gdb) si
=> 0x7c3a:      mov    %eax,%fs
0x00007c3a in ?? ()
(gdb) si
=> 0x7c3c:      mov    %eax,%gs
0x00007c3c in ?? ()
(gdb) si
=> 0x7c3e:      mov    %eax,%ss
0x00007c3e in ?? ()
(gdb) si
=> 0x7c40:      mov    $0x7c00,%esp
0x00007c40 in ?? ()
(gdb) si
=> 0x7c45:      call   0x7d22
0x00007c45 in ?? ()

ここが call bootmain してる箇所なはず。すすめてみた gdb な出力が以下?

=> 0x7c45:      call   0x7d22
0x00007c45 in ?? ()
(gdb) si
=> 0x7d22:      push   %ebp
0x00007d22 in ?? ()
(gdb) si
=> 0x7d23:      mov    %esp,%ebp
0x00007d23 in ?? ()
(gdb) si
=> 0x7d25:      push   %esi
0x00007d25 in ?? ()
(gdb) si
=> 0x7d26:      push   %ebx
0x00007d26 in ?? ()
(gdb) si
=> 0x7d27:      push   $0x0
0x00007d27 in ?? ()
(gdb) si
=> 0x7d29:      push   $0x1000
0x00007d29 in ?? ()
(gdb) si
=> 0x7d2e:      push   $0x10000
0x00007d2e in ?? ()
(gdb) si
=> 0x7d33:      call   0x7ce3
0x00007d33 in ?? ()

あら? なんか違うカンジ。そして entry.S のソレがいつまで経っても出てきませんな。とゆーことは三番目の質問はダウト回答?
もっかい机上で確認してリトライしてみます。とりあえずエントリ投入。

なるほど

kernel なソレを読み込んでるのかな。ええと、kernel.ld の以下の記述に基いて

SECTIONS
{
	/* Load the kernel at this address: "." means the current address */
	. = 0xF0100000;

	.text : {
		*(.text .stub .text.* .gnu.linkonce.t.*)
	}

breakpoint をナニしてみました。

(gdb) b *0xF0100000
Breakpoint 2 at 0xf0100000
(gdb) 

なんとなくダウトな気がしますが continue してみます。

(gdb) c
Continuing.

ダメみたいorz
いったん全部チャラにしてリトライしてみるか。