diff options
author | rtm <rtm> | 2006-06-12 15:22:12 +0000 |
---|---|---|
committer | rtm <rtm> | 2006-06-12 15:22:12 +0000 |
commit | 55e95b16db458b7f9abeca96e541acbdf8d7f85b (patch) | |
tree | 92a1fcb6f1cdede7ab83b37acabf76e1bc1b10f4 /bootasm.S | |
download | xv6-labs-55e95b16db458b7f9abeca96e541acbdf8d7f85b.tar.gz xv6-labs-55e95b16db458b7f9abeca96e541acbdf8d7f85b.tar.bz2 xv6-labs-55e95b16db458b7f9abeca96e541acbdf8d7f85b.zip |
import
Diffstat (limited to 'bootasm.S')
-rw-r--r-- | bootasm.S | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/bootasm.S b/bootasm.S new file mode 100644 index 0000000..00cbdc9 --- /dev/null +++ b/bootasm.S @@ -0,0 +1,109 @@ +#define SEG_NULL \ + .word 0, 0; \ + .byte 0, 0, 0, 0 +#define SEG(type,base,lim) \ + .word (((lim) >> 12) & 0xffff), ((base) & 0xffff); \ + .byte (((base) >> 16) & 0xff), (0x90 | (type)), \ + (0xC0 | (((lim) >> 28) & 0xf)), (((base) >> 24) & 0xff) + +#define STA_X 0x8 // Executable segment +#define STA_E 0x4 // Expand down (non-executable segments) +#define STA_C 0x4 // Conforming code segment (executable only) +#define STA_W 0x2 // Writeable (non-executable segments) +#define STA_R 0x2 // Readable (executable segments) +#define STA_A 0x1 // Accessed + +.set PROT_MODE_CSEG,0x8 # code segment selector +.set PROT_MODE_DSEG,0x10 # data segment selector +.set CR0_PE_ON,0x1 # protected mode enable flag + +################################################################################### +# ENTRY POINT +# This code should be stored in the first sector of the hard disk. +# After the BIOS initializes the hardware on startup or system reset, +# it loads this code at physical address 0x7c00 - 0x7d00 (512 bytes). +# Then the BIOS jumps to the beginning of it, address 0x7c00, +# while running in 16-bit real-mode (8086 compatibility mode). +# The Code Segment register (CS) is initially zero on entry. +# +# This code switches into 32-bit protected mode so that all of +# memory can accessed, then calls into C. +################################################################################### + +.globl start # Entry point +start: .code16 # This runs in real mode + cli # Disable interrupts + cld # String operations increment + + # Set up the important data segment registers (DS, ES, SS). + xorw %ax,%ax # Segment number zero + movw %ax,%ds # -> Data Segment + movw %ax,%es # -> Extra Segment + movw %ax,%ss # -> Stack Segment + + # Set up the stack pointer, growing downward from 0x7c00. + movw $start,%sp # Stack Pointer + +#### Enable A20: +#### For fascinating historical reasons (related to the fact that +#### the earliest 8086-based PCs could only address 1MB of physical memory +#### and subsequent 80286-based PCs wanted to retain maximum compatibility), +#### physical address line 20 is tied to low when the machine boots. +#### Obviously this a bit of a drag for us, especially when trying to +#### address memory above 1MB. This code undoes this. + +seta20.1: inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.1 # Yes + movb $0xd1,%al # Command: Write + outb %al,$0x64 # output port +seta20.2: inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.2 # Yes + movb $0xdf,%al # Enable + outb %al,$0x60 # A20 + +#### Switch from real to protected mode +#### The descriptors in our GDT allow all physical memory to be accessed. +#### Furthermore, the descriptors have base addresses of 0, so that the +#### segment translation is a NOP, ie. virtual addresses are identical to +#### their physical addresses. With this setup, immediately after +#### enabling protected mode it will still appear to this code +#### that it is running directly on physical memory with no translation. +#### This initial NOP-translation setup is required by the processor +#### to ensure that the transition to protected mode occurs smoothly. + +real_to_prot: cli # Mandatory since we dont set up an IDT + lgdt gdtdesc # load GDT -- mandatory in protected mode + movl %cr0, %eax # turn on protected mode + orl $CR0_PE_ON, %eax # + movl %eax, %cr0 # + ### CPU magic: jump to relocation, flush prefetch queue, and reload %cs + ### Has the effect of just jmp to the next instruction, but simultaneous + ### loads CS with $PROT_MODE_CSEG. + ljmp $PROT_MODE_CSEG, $protcseg + +#### we are in 32-bit protected mode (hence the .code32) +.code32 +protcseg: + # Set up the protected-mode data segment registers + movw $PROT_MODE_DSEG, %ax # Our data segment selector + movw %ax, %ds # -> DS: Data Segment + movw %ax, %es # -> ES: Extra Segment + movw %ax, %fs # -> FS + movw %ax, %gs # -> GS + movw %ax, %ss # -> SS: Stack Segment + + call cmain # finish the boot load from C. + # cmain() should not return +spin: jmp spin # ..but in case it does, spin + +.p2align 2 # force 4 byte alignment +gdt: + SEG_NULL # null seg + SEG(STA_X|STA_R, 0x0, 0xffffffff) # code seg + SEG(STA_W, 0x0, 0xffffffff) # data seg + +gdtdesc: + .word 0x17 # sizeof(gdt) - 1 + .long gdt # address gdt |