xref: /xv6-public/bootasm.S (revision 7b644318)
121a88fd4Skaashoek#include "asm.h"
255e95b16Srtm
35d1f4b8aSrsc# Start the first CPU: switch to 32-bit protected mode, jump into C.
45d1f4b8aSrsc# The BIOS loads this code from the first sector of the hard disk into
55d1f4b8aSrsc# memory at physical address 0x7c00 and starts executing in real mode
65d1f4b8aSrsc# with %cs=0 %ip=7c00.
755e95b16Srtm
8e97519a6Srsc#define SEG_KCODE 1  // kernel code
9e97519a6Srsc#define SEG_KDATA 2  // kernel data+stack
10e97519a6Srsc
11e97519a6Srsc#define CR0_PE    1  // protected mode enable bit
1255e95b16Srtm
13b7f653dcSrsc.code16                       # Assemble for 16-bit mode
142bc72bddSrsc.globl start
15a650c606Srscstart:
1655e95b16Srtm  cli                         # Disable interrupts
1755e95b16Srtm
1855e95b16Srtm  # Set up the important data segment registers (DS, ES, SS).
1955e95b16Srtm  xorw    %ax,%ax             # Segment number zero
2055e95b16Srtm  movw    %ax,%ds             # -> Data Segment
2155e95b16Srtm  movw    %ax,%es             # -> Extra Segment
2255e95b16Srtm  movw    %ax,%ss             # -> Stack Segment
2355e95b16Srtm
240cfc7290Srsc  # Enable A20:
2515868c4bSrsc  #   For backwards compatibility with the earliest PCs, physical
2615868c4bSrsc  #   address line 20 is tied low, so that addresses higher than
2715868c4bSrsc  #   1MB wrap around to zero by default.  This code undoes this.
28a650c606Srscseta20.1:
295d1f4b8aSrsc  inb     $0x64,%al               # Wait for not busy
305d1f4b8aSrsc  testb   $0x2,%al
315d1f4b8aSrsc  jnz     seta20.1
325d1f4b8aSrsc
335d1f4b8aSrsc  movb    $0xd1,%al               # 0xd1 -> port 0x64
345d1f4b8aSrsc  outb    %al,$0x64
35a650c606Srsc
36a650c606Srscseta20.2:
375d1f4b8aSrsc  inb     $0x64,%al               # Wait for not busy
385d1f4b8aSrsc  testb   $0x2,%al
395d1f4b8aSrsc  jnz     seta20.2
405d1f4b8aSrsc
415d1f4b8aSrsc  movb    $0xdf,%al               # 0xdf -> port 0x60
425d1f4b8aSrsc  outb    %al,$0x60
4355e95b16Srtm
442bc72bddSrsc//PAGEBREAK!
452bc72bddSrsc  # Switch from real to protected mode, using a bootstrap GDT
462bc72bddSrsc  # and segment translation that makes virtual addresses
47411ee741Srtm  # identical to physical addresses, so that the
482bc72bddSrsc  # effective memory map does not change during the switch.
492bc72bddSrsc  lgdt    gdtdesc
502bc72bddSrsc  movl    %cr0, %eax
51b7f653dcSrsc  orl     $CR0_PE, %eax
522bc72bddSrsc  movl    %eax, %cr0
532bc72bddSrsc
542bc72bddSrsc  # Jump to next instruction, but in 32-bit code segment.
552bc72bddSrsc  # Switches processor into 32-bit mode.
56e97519a6Srsc  ljmp    $(SEG_KCODE<<3), $start32
5755e95b16Srtm
582bc72bddSrsc.code32                       # Assemble for 32-bit mode
59b7f653dcSrscstart32:
6055e95b16Srtm  # Set up the protected-mode data segment registers
61e97519a6Srsc  movw    $(SEG_KDATA<<3), %ax    # Our data segment selector
6255e95b16Srtm  movw    %ax, %ds                # -> DS: Data Segment
6355e95b16Srtm  movw    %ax, %es                # -> ES: Extra Segment
64e97519a6Srsc  movw    %ax, %ss                # -> SS: Stack Segment
65*7b644318Srsc  movw    $0, %ax                 # Zero segments not ready for use
6655e95b16Srtm  movw    %ax, %fs                # -> FS
6755e95b16Srtm  movw    %ax, %gs                # -> GS
685d1f4b8aSrsc
692bc72bddSrsc  # Set up the stack pointer and call into C.
705d1f4b8aSrsc  movl    $start, %esp
71c35c064eSrsc  call    bootmain
725d1f4b8aSrsc
73b7f653dcSrsc  # If bootmain returns (it shouldn't), trigger a Bochs
74b7f653dcSrsc  # breakpoint if running under Bochs, then loop.
75b7f653dcSrsc  movw    $0x8a00, %ax            # 0x8a00 -> port 0x8a00
76b7f653dcSrsc  movw    %ax, %dx
77b7f653dcSrsc  outw    %ax, %dx
78b7f653dcSrsc  movw    $0x8e00, %ax            # 0x8e00 -> port 0x8a00
79b7f653dcSrsc  outw    %ax, %dx
80a650c606Srscspin:
812bc72bddSrsc  jmp     spin
82a650c606Srsc
835d1f4b8aSrsc# Bootstrap GDT
8455e95b16Srtm.p2align 2                                # force 4 byte alignment
8555e95b16Srtmgdt:
867abf49d2Skaashoek  SEG_NULLASM                             # null seg
877abf49d2Skaashoek  SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff)   # code seg
887abf49d2Skaashoek  SEG_ASM(STA_W, 0x0, 0xffffffff)         # data seg
89e97519a6Srsc  SEG_ASM(STA_W, 0x100, 0xffffffff)       # per-cpu data seg; 0x100 is okay for now
905d1f4b8aSrsc
9155e95b16Srtmgdtdesc:
92e97519a6Srsc  .word   0x1f                            # sizeof(gdt) - 1
9355e95b16Srtm  .long   gdt                             # address gdt
94