Saturday, March 17, 2012

Lab1-Part B: Boot loader & Bootstrap

[Preface] A Hope That My Crude Remarks May Draw Forth By Abler People
Boot loader: 1st stage, don't need to depend on kernel
Bootstrap: 2nd stage, related about kernel image not part of the kernel code, do kernel uncompressing ...etc

  • Something needed to know
    • Addressing methodology and its adv/disadv in real-mode/16-bit protected mode/32-bit protected mode
  • Trace boot loader:
  1. .globl start : 為0x7c00
  2. 16bit ASM section is on
  3. cli ; cld;
  4. Set %ds,%es,%ss to 0
  5. %cs is 0 set by BIOS  CS:IP = 0000:7c00
  6. Enable A20
  7. lgdt gdtdesc //load global descriptor table
  8. set %cr0 to Enable Protected mode
  9. 16 bit ASM is off
  10.  ljmp   $0xb866,$0x87c32
    • CS is replaced as #8 slot at gdt table (PROT_MODE_CSEG)and  plus 0xb866 base.
    • immed is 0x87c32
  11.  set %ds,%es,%fs,%gs,%ss as #10 at gdt table(PROT_MODE_DSEG)
  12.  set esp as 0x7c00 to form stack base address ; stack address: [ss:esp]
  13. call bootmain(void)
  14. call readseg((uint32_t) ELFHDR, SECTSIZE*8, 0); read in ELF headers
  15. call readseg to read in every program header.
  16. jump to kernel.
    • ((void (*)(void)) (ELFHDR->e_entry))();
  17. #
  • Trace readseg
    1. end_pa = pa + memsize
    2.  round down it-physical address for loading program into ram by pa&= 0x(FFFFFE00)  // ~(SECTSIZE-1)
    3. Translate offset into Sector number
      • Note: The offset must start from #1, #0 is the boot sec  
    4. Read enough data by pa and sector number  
      • Because paging is not enable, just direct map into memory. by $PROT_MODE_DSEG, %ax
    5. #
  • Trace readsect
    • do IDE HardDisk read in data.
  • Reply for its questions
    1. At what point does the processor start executing 32-bit code? What exactly causes the switch from 16- to 32-bit mode?
      • before long jump, and set cr0's 1st bit to 1
    2. What is the last instruction of the boot loader executed, and what is the first instruction of the kernel it just loaded?
      1. Last instruction in boot loader
        • In "C": ((void (*)(void)) (ELFHDR->e_entry))();
        • In "GAS": call   *0x10018  to jmp at kernel's entry point 0x10000c
          • 0x10018 is the byte address of at ELFHDR's  #24 byte.
      2. First Instruction in Kernel
        • movw    $0x1234,0x472   //warm boot
    3. Where is the first instruction of the kernel?
      • At kern/entry.S  . .globl entry
      • 0x10000c
    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?
      1. 由ELF info 穿針引線。
        • #man elf
        • readelf -l obj/kern/kernel
        • From its ELF header 
          • get Program header's start offset: e_phoff
          • get how many are the program headers: e_phnum
      2. 由program header 
        • readelf -l  obj/kern/kernel
      • From program headers to do readseg
        • ph->p_pa : the address for prgram segment loaded into ram
          • On systems for which physical addressing is relevant, this member is  reserved for  the  segment's  physical  address.  Under BSD this member is not used and must be zero.
        • ph->p_memsz: 
          • This  member holds the number of bytes in the memory image of the segment.  It may be zero.
        • ph->p_offset
          •  This member holds the offset from the beginning of the file at which the first byte of the segment resides.
  • Discussion
    • Calling conventions gcc at  i386
      • Saved by Caller
        • eax : contain return value
        • ecx: possibly trashed
        • edx: possibly trashed
      • Saved by Callee
        • ebp
        • ebx
        • esi
        • edi
        • must be saved before call
      • Sample
        1. In bootmain, why did it need following instructions?
          • push   %ebp  #x86 gcc calling convention
          • mov    %esp,%ebp  #x86 gcc calling convention
          • push   %edi
          • push   %ebx
        2. In readseg, ...
          • push   %ebp  #x86 gcc calling convention
          • mov    %esp,%ebp  #x86 gcc calling convention
          • push   %edi
  • After Lesson:
  1. Drivers. How did it execute IDE device I/O
    • Ans: Not Yet.
  2. How to decide program headers?
      •   LOAD //PT_LOAD
      •   LOAD //PT_LOAD
      •   GNU_STACK .//PT_GNU_SACK
    • Ans: By session's default orgnization.
  3. In program header, 
    1. Why is memsz and filesz? Loading it totally is not better?
    2. Why is GNU_Stack's Memsize  zero?
    • Program Headers:
    •   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
    •   LOAD           0x001000 0xf0100000 0x00100000 0x075b9 0x075b9 R E 0x1000
    •   LOAD           0x009000 0xf0108000 0x00108000 0x0a300 0x0a960 RW  0x1000
    •   GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
  4. ljmp: how did it decide to do TSS  related stuff
    • Guess: by segment descriptor's field.

    • Just Read The C Programming Language K&R chap5.
    • Address Arithmetic. The Byte added to l-value is by its type.
      • c = (int *) ((char *) c + 1); //added by 1
      • b = (int *) a + 1;//added by 4

    • Something needed to know
      • Change boo/Makefrag的-Ttext : 0x7c000 for link address
      • VMA: Link address. Expected address for it to rum.
      • LMA: Load address. Expected address for it to load into memory.
      • objdump -h:Display the contents of the section headers -See VMA/LMA.
      • objdump -f: Display the contents of the section headers -See entry_point for execution start address
    • objdump -f obj/boot/boot.out
      •  start address 0x00007c00
    • objdump -h obj/boot/boot.out
      • VMA:0x00007c00
      • LMA:0x00007c00
    • Modify boot/Makefrag -Ttext to 0x8C00
      • Error happaned at  ljmp    $PROT_MODE_CSEG, $protcseg @ boot/boot.S
      • .Ttext .text/.org tell assembler its start address 0x8C00 , but BIOS load it into 0x7C00 that .gdt related data follow 0x7C00, at 0x7c64.  When executing ljmp error happened instruction, it will use 0x8c64 by .Ttext claimed, but in reality it is loaded at 0x7C64 by BIOS.
    • After Lesson:
      • Modify -Ttext0x7900. How and Why did it change VMA/LAM not just only entry(.start)?  
        • Ans: Not Yet.
      • How did CPU's chip view reject to execute ljmp instruction if gdt field was something wrong?
        • Ans: Not Yet.

    • Something needed to know
      • Set 1st break point at 0x7c00
        • examine 0x100000
      • Set 2nd breakpoint at 0x10000c
        • examine  0x100000
      • Addresses for obj/kern/kernel
        • VMA:0xf0100000
        • LMA: 0x00100000
        • Entry: 0x10000c
    •  Result
      • BIOS enter Bootloader
        • x/8h 0x100000:       0x0000  0x0000  0x0000  0x0000  0x0000  0x0000  0x0000  0x0000
      • Bootloader enter OS Kernel
        • x/8h 0x100000:       0xb002  0x1bad  0x0000  0x0000  0x4ffe  0xe452  0xc766  0x7205
        • x8h 0x10000c:       0xc766  0x7205  0x0004  0x3400  0xb812  0x0000  0x0011  0x220f
    • Discussion: Why are they different?
      • By LMA's value
      • bootloader load kernel by claim form program header of kernel's elf info.
        • readelf -l obj/kern/kernel
          • Elf file type is EXEC (Executable file)
            Entry point 0x10000c

    No comments:

    Post a Comment