首页 > 代码库 > xv6/bootasm.S + xv6/bootmain.c

xv6/bootasm.S + xv6/bootmain.c

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 mode11 .globl start12 start:13 cli # BIOS enabled interrupts; disable14 15 # Zero data segment registers DS, ES, and SS.16 xorw %ax,%ax # Set %ax to zero17 movw %ax,%ds # -> Data Segment18 movw %ax,%es # -> Extra Segment19 movw %ax,%ss # -> Stack Segment20 21 # Physical address line A20 is tied to zero so that the first PCs22 # with 2 MB would run software that assumed 1 MB. Undo that.23 seta20.1:24 inb $0x64,%al # Wait for not busy25 testb $0x2,%al26 jnz seta20.127 28 movb $0xd1,%al # 0xd1 -> port 0x6429 outb %al,$0x6430 31 seta20.2:32 inb $0x64,%al # Wait for not busy33 testb $0x2,%al34 jnz seta20.235 36 movb $0xdf,%al # 0xdf -> port 0x6037 outb %al,$0x6038 39 # Switch from real to protected mode. Use a bootstrap GDT that makes40 # virtual addresses map directly to physical addresses so that the41 # effective memory map doesn’t change during the transition.42 lgdt gdtdesc43 movl %cr0, %eax44 orl $CR0_PE, %eax45 movl %eax, %cr046 47 48 49 50 51 # Complete transition to 32-bit protected mode by using long jmp52 # to reload %cs and %eip. The segment descriptors are set up with no53 # translation, so that the mapping is still the identity mapping.54 ljmp $(SEG_KCODE<<3), $start3255 56 .code32 # Tell assembler to generate 32-bit code now.57 start32:58 # Set up the protected-mode data segment registers59 movw $(SEG_KDATA<<3), %ax # Our data segment selector60 movw %ax, %ds # -> DS: Data Segment61 movw %ax, %es # -> ES: Extra Segment62 movw %ax, %ss # -> SS: Stack Segment63 movw $0, %ax # Zero segments not ready for use64 movw %ax, %fs # -> FS65 movw %ax, %gs # -> GS66 67 # Set up the stack pointer and call into C.68 movl $start, %esp69 call bootmain70 71 # If bootmain returns (it shouldn’t), trigger a Bochs72 # breakpoint if running under Bochs, then loop.73 movw $0x8a00, %ax # 0x8a00 -> port 0x8a0074 movw %ax, %dx75 outw %ax, %dx76 movw $0x8ae0, %ax # 0x8ae0 -> port 0x8a0077 outw %ax, %dx78 spin:79 jmp spin80 81 # Bootstrap GDT82 .p2align 2 # force 4 byte alignment83 gdt:84 SEG_NULLASM # null seg85 SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) # code seg86 SEG_ASM(STA_W, 0x0, 0xffffffff) # data seg87 88 gdtdesc:89 .word (gdtdesc - gdt - 1) # sizeof(gdt) - 190 .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 51214 15 void readseg(uchar*, uint, uint);16 17 void18 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 space26 27     // Read 1st page off disk28     readseg((uchar*)elf, 4096, 0);29 30     // Is this an ELF executable?31     if(elf->magic != ELF_MAGIC)32         return; // let bootasm.S handle error33 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 void52 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 void61 readsect(void *dst, uint offset)62 {63     // Issue command.64     waitdisk();65     outb(0x1F2, 1); // count = 166     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 sectors71 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 void80 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 }

 

xv6/bootasm.S + xv6/bootmain.c