Skip to content
Snippets Groups Projects
bootasm.S 3.56 KiB
Newer Older
rsc's avatar
 
rsc committed
# Start the first CPU: switch to 32-bit protected mode, jump into C.
# The BIOS loads this code from the first sector of the hard disk into
# memory at physical address 0x7c00 and starts executing in real mode
# with %cs=0 %ip=7c00.
rsc's avatar
 
rsc committed
.set PROT_MODE_CSEG, 0x8         # kernel code segment selector
.set PROT_MODE_DSEG, 0x10        # kernel data segment selector
.set CR0_PE_ON,      0x1         # protected mode enable flag
rsc's avatar
rsc committed

.globl start                      # Entry point
start:
.code16                           # This runs in real mode
  cli                             # Disable interrupts
rtm's avatar
rtm committed

  # 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
rtm's avatar
rtm committed

rsc's avatar
rsc committed
  # Enable A20:
rsc's avatar
rsc committed
  #   For backwards compatibility with the earliest PCs, physical
  #   address line 20 is tied low, so that addresses higher than
  #   1MB wrap around to zero by default.  This code undoes this.
rsc's avatar
 
rsc committed
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.1

  movb    $0xd1,%al               # 0xd1 -> port 0x64
  outb    %al,$0x64
rtm's avatar
rtm committed

rsc's avatar
 
rsc committed
  inb     $0x64,%al               # Wait for not busy
  testb   $0x2,%al
  jnz     seta20.2

  movb    $0xdf,%al               # 0xdf -> port 0x60
  outb    %al,$0x60
rsc's avatar
rsc committed
# 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:
rsc's avatar
rsc committed
  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
rtm's avatar
rtm committed
#### we are in 32-bit protected mode (hence the .code32)
.code32
rsc's avatar
rsc committed
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
rsc's avatar
 
rsc committed
  
  # Set up the stack pointer, growing downward from 0x7c00.
  movl    $start, %esp

  call cmain                      # finish the boot load from C.
                                  # cmain() should not return
spin:
  jmp spin                        # ..but in case it does, spin

rsc's avatar
 
rsc committed
# Bootstrap GDT
.p2align 2                                # force 4 byte alignment
rtm's avatar
rtm committed
gdt:
  SEG_NULLASM                             # null seg
  SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)   # code seg
  SEG_ASM(STA_W, 0x0, 0xffffffff)         # data seg
rsc's avatar
 
rsc committed

rtm's avatar
rtm committed
gdtdesc:
  .word   0x17                            # sizeof(gdt) - 1
  .long   gdt                             # address gdt