xv6/bootasm.S + xv6/bootmain.c

时间:2021-10-14 22:17:22

xv6/bootasm.S

 1 #include "asm.h"
 2 #include "memlayout.h"
 3 #include "mmu.h"
 4 
 5 # Start the first CPU: switch to 32-bit protected mode, jump into C.
 6 # The BIOS loads this code from the first sector of the hard disk into
 7 # memory at physical address 0x7c00 and starts executing in real mode
 8 # with %cs=0 %ip=7c00.
 9 
10 .code16 # Assemble for 16-bit mode
11 .globl start
12 start:
13 cli # BIOS enabled interrupts; disable
14 
15 # Zero data segment registers DS, ES, and SS.
16 xorw %ax,%ax # Set %ax to zero
17 movw %ax,%ds # -> Data Segment
18 movw %ax,%es # -> Extra Segment
19 movw %ax,%ss # -> Stack Segment
20 
21 # Physical address line A20 is tied to zero so that the first PCs
22 # with 2 MB would run software that assumed 1 MB. Undo that.
23 seta20.1:
24 inb $0x64,%al # Wait for not busy
25 testb $0x2,%al
26 jnz seta20.1
27 
28 movb $0xd1,%al # 0xd1 -> port 0x64
29 outb %al,$0x64
30 
31 seta20.2:
32 inb $0x64,%al # Wait for not busy
33 testb $0x2,%al
34 jnz seta20.2
35 
36 movb $0xdf,%al # 0xdf -> port 0x60
37 outb %al,$0x60
38 
39 # Switch from real to protected mode. Use a bootstrap GDT that makes
40 # virtual addresses map directly to physical addresses so that the
41 # effective memory map doesn’t change during the transition.
42 lgdt gdtdesc
43 movl %cr0, %eax
44 orl $CR0_PE, %eax
45 movl %eax, %cr0
46 
47 
48 
49 
50 
51 # Complete transition to 32-bit protected mode by using long jmp
52 # to reload %cs and %eip. The segment descriptors are set up with no
53 # translation, so that the mapping is still the identity mapping.
54 ljmp $(SEG_KCODE<<3), $start32
55 
56 .code32 # Tell assembler to generate 32-bit code now.
57 start32:
58 # Set up the protected-mode data segment registers
59 movw $(SEG_KDATA<<3), %ax # Our data segment selector
60 movw %ax, %ds # -> DS: Data Segment
61 movw %ax, %es # -> ES: Extra Segment
62 movw %ax, %ss # -> SS: Stack Segment
63 movw $0, %ax # Zero segments not ready for use
64 movw %ax, %fs # -> FS
65 movw %ax, %gs # -> GS
66 
67 # Set up the stack pointer and call into C.
68 movl $start, %esp
69 call bootmain
70 
71 # If bootmain returns (it shouldn’t), trigger a Bochs
72 # breakpoint if running under Bochs, then loop.
73 movw $0x8a00, %ax # 0x8a00 -> port 0x8a00
74 movw %ax, %dx
75 outw %ax, %dx
76 movw $0x8ae0, %ax # 0x8ae0 -> port 0x8a00
77 outw %ax, %dx
78 spin:
79 jmp spin
80 
81 # Bootstrap GDT
82 .p2align 2 # force 4 byte alignment
83 gdt:
84 SEG_NULLASM # null seg
85 SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg
86 SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg
87 
88 gdtdesc:
89 .word (gdtdesc - gdt - 1) # sizeof(gdt) - 1
90 .long gdt # address gdt

 

xv6/bootmain.c

 1 // Boot loader.
 2 //
 3 // Part of the boot sector, along with bootasm.S, which calls bootmain().
 4 // bootasm.S has put the processor into protected 32-bit mode.
 5 // bootmain() loads an ELF kernel image from the disk starting at
 6 // sector 1 and then jumps to the kernel entry routine.
 7 
 8 #include "types.h"
 9 #include "elf.h"
10 #include "x86.h"
11 #include "memlayout.h"
12 
13 #define SECTSIZE 512
14 
15 void readseg(uchar*, uint, uint);
16 
17 void
18 bootmain(void)
19 {
20     struct elfhdr *elf;
21     struct proghdr *ph, *eph;
22     void (*entry)(void);
23     uchar* pa;
24 
25     elf = (struct elfhdr*)0x10000; // scratch space
26 
27     // Read 1st page off disk
28     readseg((uchar*)elf, 4096, 0);
29 
30     // Is this an ELF executable?
31     if(elf->magic != ELF_MAGIC)
32         return; // let bootasm.S handle error
33 
34     // Load each program segment (ignores ph flags).
35     ph = (struct proghdr*)((uchar*)elf + elf->phoff);
36     eph = ph + elf->phnum;
37     for(; ph < eph; ph++){
38         pa = (uchar*)ph->paddr;
39         readseg(pa, ph->filesz, ph->off);
40         if(ph->memsz > ph->filesz)
41             stosb(pa + ph->filesz, 0, ph->memsz - ph->filesz);
42     }
43 
44     // Call the entry point from the ELF header.
45     // Does not return!
46     entry = (void(*)(void))(elf->entry);
47     entry();
48 }
49 
50 
51 void
52 waitdisk(void)
53 {
54     // Wait for disk ready.
55     while((inb(0x1F7) & 0xC0) != 0x40)
56         ;
57 }
58 
59 // Read a single sector at offset into dst.
60 void
61 readsect(void *dst, uint offset)
62 {
63     // Issue command.
64     waitdisk();
65     outb(0x1F2, 1); // count = 1
66     outb(0x1F3, offset);
67     outb(0x1F4, offset >> 8);
68     outb(0x1F5, offset >> 16);
69     outb(0x1F6, (offset >> 24) | 0xE0);
70     outb(0x1F7, 0x20); // cmd 0x20 - read sectors
71 
72     // Read data.
73     waitdisk();
74     insl(0x1F0, dst, SECTSIZE/4);
75 }
76 
77 // Read ’count’ bytes at ’offset’ from kernel into physical address ’pa’.
78 // Might copy more than asked.
79 void
80 readseg(uchar* pa, uint count, uint offset)
81 {
82     uchar* epa;
83 
84     epa = pa + count;
85 
86     // Round down to sector boundary.
87     pa -= offset % SECTSIZE;
88 
89     // Translate from bytes to sectors; kernel starts at sector 1.
90     offset = (offset / SECTSIZE) + 1;
91 
92     // If this is too slow, we could read lots of sectors at a time.
93     // We’d write more to memory than asked, but it doesn’t matter --
94     // we load in increasing order.
95     for(; pa < epa; pa += SECTSIZE, offset++)
96         readsect(pa, offset);
97 }