# Stage 2 — loaded by stage1 at 0x7E00, still in 16-bit real mode. Does the # VBE mode setup, A20 line, and real->protected mode switch that used to # live directly in the boot sector, then hands off to stage2main() (C) to # draw a splash and load the actual kernel. Not sector-size-constrained — # only bounded by STAGE2_SECTORS in bootasm.S / the Makefile. #include "../include/asm.h" #include "../include/memlayout.h" #include "../include/mmu.h" .code16 .global stage2start stage2start: # Segments are already zeroed by stage1; %sp is inherited too. movw $bootmsg, %si call print16 # VBE Setup. Mode info block goes at 0x30000, not 0x9000 — stage2 itself # is loaded starting at 0x7E00 and, with the boot-menu/progress-bar code, # is now big enough to reach 0x9000, so writing the VBE block there would # clobber stage2's own tail end. 0x30000 is clear of stage2 (ends well # under 0xA000), the multiboot kernel-search buffer (0x10000-0x14000), # and the kernel's own load address (0x100000). movw $0x3000, %ax movw %ax, %es xorw %di, %di # ES:DI = 3000:0000 = flat 0x30000 movw $0x0143, %cx movw $0x4F01, %ax int $0x10 cmpw $0x004F, %ax jne e820 movw $0x4143, %bx movw $0x4F02, %ax int $0x10 # BIOS E820 memory map — the standard firmware interface every serious # loader (GRUB, Linux's own boot stub, the BSDs) uses to learn the real # RAM layout instead of guessing. Entry count goes to flat 0x30200, # 24-byte entries start at 0x30208 (both inside the 0x3000 segment the # VBE block already claimed; verbose flag sits at +0x100). Capped at 32 # entries so a pathological BIOS can't run us past the buffer. e820: movw $0x3000, %ax movw %ax, %es xorl %ebx, %ebx # continuation cookie, 0 = first call movw $0x208, %di xorl %ebp, %ebp # entry count e820loop: movl $0xE820, %eax movl $0x534D4150, %edx # 'SMAP' movl $24, %ecx int $0x15 jc e820done # carry = end of map (or unsupported BIOS) cmpl $0x534D4150, %eax jne e820done addw $24, %di incl %ebp cmpl $32, %ebp jae e820done testl %ebx, %ebx jnz e820loop e820done: movl %ebp, %es:(0x200) xorw %ax, %ax movw %ax, %es seta20.1: inb $0x64, %al testb $0x2, %al jnz seta20.1 movb $0xd1, %al outb %al, $0x64 seta20.2: inb $0x64, %al testb $0x2, %al jnz seta20.2 movb $0xdf, %al outb %al, $0x60 lgdt gdtdesc movl %cr0, %eax orl $CR0_PE, %eax movl %eax, %cr0 ljmp $(SEG_KCODE<<3), $start32 # Print null-terminated string at DS:SI via BIOS teletype (real mode only). # Clobbers AX, BX, SI. print16: .Lp16loop: lodsb testb %al, %al jz .Lp16done movb $0x0E, %ah movw $0x0007, %bx int $0x10 jmp .Lp16loop .Lp16done: ret bootmsg: .asciz "SchOS booting...\r\n" .code32 start32: movw $(SEG_KDATA<<3), %ax movw %ax, %ds movw %ax, %es movw %ax, %ss xorw %ax, %ax movw %ax, %fs movw %ax, %gs movl $0x7c00, %esp call stage2main spin: jmp spin .p2align 2 gdt: SEG_NULLASM SEG_ASM(STA_X|STA_R, 0x0, 0xffffffff) SEG_ASM(STA_W, 0x0, 0xffffffff) gdtdesc: .word (gdtdesc - gdt - 1) .long gdt