6.828: Operating System Engineering (13)

さ、続きに着手。
てか、以下に

  1. At what point does the processor start executing 32-bit code? What exactly causes the switch from 16- to 32-bit mode?
  2. What is the last instruction of the boot loader executed, and what is the first instruction of the kernel it just loaded?
  3. Where is the first instruction of the kernel?
  4. 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?

答えておいて云々って言いつつ完全スルーだな。二番目以降を以下に。

二番目

以下が kernel を kickoff するソレで

	// call the entry point from the ELF header
	// note: does not return!
	((void (*)(void)) (ELFHDR->e_entry & 0xFFFFFF))();
    7d7a:	a1 18 00 01 00       	mov    0x10018,%eax
    7d7f:	25 ff ff ff 00       	and    $0xffffff,%eax
    7d84:	ff d0                	call   *%eax

kickoff されたナニとしていっちゃん最初に実行されるのが以下のはず。

.globl		_start
_start:
	movw	$0x1234,0x472			# warm boot
f0100000:	02 b0 ad 1b 03 00    	add    0x31bad(%eax),%dh
f0100006:	00 00                	add    %al,(%eax)
f0100008:	fb                   	sti    
f0100009:	4f                   	dec    %edi
f010000a:	52                   	push   %edx
f010000b:	e4 66                	in     $0x66,%al

f010000c <_start>:
f010000c:	66 c7 05 72 04 00 00 	movw   $0x1234,0x472
f0100013:	34 12 

	# Establish our own GDT in place of the boot loader's temporary GDT.
	lgdt	RELOC(mygdtdesc)		# load descriptor table
f0100015:	0f 01 15 18 00 11 00 	lgdtl  0x110018

次は、ってちょっと微妙かも。もっかい確認。
ええと

  • What is the last instruction of the boot loader executed

	// call the entry point from the ELF header
	// note: does not return!
	((void (*)(void)) (ELFHDR->e_entry & 0xFFFFFF))();
    7d7a:	a1 18 00 01 00       	mov    0x10018,%eax
    7d7f:	25 ff ff ff 00       	and    $0xffffff,%eax
    7d84:	ff d0                	call   *%eax

で良いよね。
で、and what is the first instruction of the kernel it just loaded? は

(gdb) b *0x7d84
Breakpoint 2 at 0x7d84
(gdb) c
Continuing.
The target architecture is assumed to be i386
=> 0x7d84:      call   *%eax

Breakpoint 2, 0x00007d84 in ?? ()
(gdb) si
=> 0x10000c:    movw   $0x1234,0x472
0x0010000c in ?? ()
(gdb) 

なので、where is the first instruction of the kernel? って聞かれると 0x001000c 番地ですが何か、ということになるのかな。
あと最後の問いですが

  • 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?

これ、ここで使ってるソレ的には inc/elf.h の以下の

struct Elf {
	uint32_t e_magic;	// must equal ELF_MAGIC
	uint8_t e_elf[12];
	uint16_t e_type;
	uint16_t e_machine;
	uint32_t e_version;
	uint32_t e_entry;
	uint32_t e_phoff;
	uint32_t e_shoff;
	uint32_t e_flags;
	uint16_t e_ehsize;
	uint16_t e_phentsize;
	uint16_t e_phnum;
	uint16_t e_shentsize;
	uint16_t e_shnum;
	uint16_t e_shstrndx;
};

e_phoff 属性が始点 (先頭アソレス + e_phoff 属性) で e_phnum を加算したアドレスが終点になる模様。これ、main.c および inc/elf.h が材料ですね。
次は exercize 6 です。

Exercise 6

change the link address in boot/Makefrag to something wrong, run make clean, recompile the lab with make, and trace into the boot loader again to see what happens.

どうなるのやら。

Program received signal SIGTRAP, Trace/breakpoint trap.
[   0:7c2d] => 0x7c2d:  ljmp   $0x8,$0x7d32
0x00007c2d in ?? ()

こうなった。ちなみに boot/Makefrag は以下。

$(OBJDIR)/boot/boot: $(BOOT_OBJS)
	@echo + ld boot/boot
	$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7D00 -o $@.out $^
	$(V)$(OBJDUMP) -S $@.out >$@.asm
	$(V)$(OBJCOPY) -S -O binary $@.out $@
	$(V)perl boot/sign.pl $(OBJDIR)/boot/boot

0x7C00 を 0x7D00 にナニ。以前のエントリ的には以下だった模様

(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 ?? ()

超微妙。今日のアレ位微妙。32 って何だろ。明日 part.3 読みます。もうヤケクソ。