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