/* $NetBSD: start_pxe.S,v 1.1 2003/10/09 09:42:25 dsl Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * PXE startup * parts from sys/arch/i386/stand/lib/crt/bootsect/start_bootsect.S * * See PXE SPEC 4.4.5 (pdf page 88) */ #include .text ENTRY(start) .code16 # start is loaded at 0x0:0x7c00 but we want 0x7c0:0x0 # ljmp to the next instruction to adjust %cs ljmp $0x7c0, $start1 # Our stack XXX probably not! .space 1024 start1: # set up %ds xorl %eax, %eax mov %cs, %ax mov %ax, %ds # set up %ss and %esp mov %ax, %ss movl $0xfffc, %esp /* stack at top of 64k segment */ movl %eax, _C_LABEL(ourseg) shll $4, %eax /* fix up GDT entries for bootstrap */ #define FIXUP(gdt_index) \ movw %ax, gdt+gdt_index+2; \ movb %bl, gdt+gdt_index+4 shldl $16, %eax, %ebx FIXUP(bootcodeseg) FIXUP(bootrealseg) FIXUP(bootdataseg) /* fix up GDT pointer */ addl $gdt, %eax movl %eax, gdtarg+2 /* change to protected mode */ calll _C_LABEL(real_to_prot) .code32 /* clear bss */ xorl %eax, %eax movl $_C_LABEL(edata), %edi movl $_C_LABEL(end), %ecx subl %edi, %ecx cld rep stosb /* ...and call main()! */ call _C_LABEL(main) .globl _C_LABEL(exit) _C_LABEL(exit): call _C_LABEL(prot_to_real) .code16 movw $efail, %si call message #ifdef notyet /* sleep for 3s = 0x2dc6c0 us */ movb $0x86, %ah mov $0x002d, %cx mov $0xc6c0, %dx int $0x15 /* call ROM BASIC */ int $0x18 #else cli hlt #endif efail: .asciz "Boot fail\r\n" ENTRY(ourseg) .long 0 /************************************************************************** GLOBAL DESCRIPTOR TABLE **************************************************************************/ #ifdef __ELF__ .align 16 #else .align 4 #endif gdt: .word 0, 0 .byte 0, 0x00, 0x00, 0 #ifdef SUPPORT_LINUX /* additional dummy */ .word 0, 0 .byte 0, 0x00, 0x00, 0 #endif /* kernel code segment */ .globl flatcodeseg flatcodeseg = . - gdt .word 0xffff, 0 .byte 0, 0x9f, 0xcf, 0 /* kernel data segment */ .globl flatdataseg flatdataseg = . - gdt .word 0xffff, 0 .byte 0, 0x93, 0xcf, 0 /* boot code segment, base will be patched */ bootcodeseg = . - gdt .word 0xffff, 0 .byte 0, 0x9e, 0x4f, 0 /* boot data segment, base will be patched */ bootdataseg = . - gdt .word 0xffff, 0 .byte 0, 0x92, 0x4f, 0 /* 16 bit real mode, base will be patched */ bootrealseg = . - gdt .word 0xffff, 0 .byte 0, 0x9e, 0x00, 0 /* limits (etc) for data segment in real mode */ bootrealdata = . - gdt .word 0xffff, 0 .byte 0, 0x92, 0x00, 0 gdtlen = . - gdt #ifdef __ELF__ .align 16 #else .align 4 #endif gdtarg: .word gdtlen-1 /* limit */ .long 0 /* addr, will be inserted */ CR0_PE = 0x1 /* * real_to_prot() * transfer from real mode to protected mode. */ ENTRY(real_to_prot) .code16 # guarantee that interrupt is disabled when in prot mode cli pushl %eax push %cs /* ensure %ds is correct */ pop %ds # load the gdtr lgdt gdtarg # set the PE bit of CR0 movl %cr0, %eax orl $CR0_PE, %eax movl %eax, %cr0 # make intrasegment jump to flush the processor pipeline and # reload CS register ljmp $bootcodeseg, $xprot xprot: .code32 # we are in USE32 mode now # set up the protected mode segment registers : DS, SS, ES mov $bootdataseg, %ax mov %ax, %ds mov %ax, %ss mov %ax, %es popl %eax ret /* * prot_to_real() * transfer from protected mode to real mode */ ENTRY(prot_to_real) .code32 pushl %eax # set up a dummy stack frame for the second seg change. # Adjust the intersegment jump instruction following # the clearing of protected mode bit. # This is self-modifying code, but we need a writable # code segment, and an intersegment return does not give us that. movl _C_LABEL(ourseg), %eax movw %ax, xreal-2 /* * Load the segment registers while still in protected mode. * Otherwise the control bits don't get changed. * The correct values are loaded later. */ movw $bootrealdata, %ax movw %ax, %ds movw %ax, %es movw %ax, %ss # Change to use16 mode. ljmp $bootrealseg, $x16 x16: .code16 # clear the PE bit of CR0 movl %cr0, %eax andl $~CR0_PE, %eax movl %eax, %cr0 ljmp $0, $xreal /* segment overwritten above */ xreal: .code16 # we are in real mode now # set up the real mode segment registers : DS, SS, ES mov %cs, %ax mov %ax, %ds mov %ax, %ss mov %ax, %es sti popl %eax retl /* * pbzero(dst, cnt) * where dst is a physical address and cnt is the length */ ENTRY(pbzero) .code32 pushl %ebp movl %esp, %ebp pushl %es pushl %edi cld # set %es to point at the flat segment movl $flatdataseg, %eax mov %ax, %es movl 8(%ebp), %edi # destination movl 12(%ebp), %ecx # count xorl %eax, %eax # value rep stosb popl %edi popl %es popl %ebp ret /* * vpbcopy(src, dst, cnt) * where src is a virtual address and dst is a physical address */ ENTRY(vpbcopy) .code32 pushl %ebp movl %esp, %ebp pushl %es pushl %esi pushl %edi cld # set %es to point at the flat segment movl $flatdataseg, %eax mov %ax, %es movl 8(%ebp), %esi # source movl 12(%ebp), %edi # destination movl 16(%ebp), %ecx # count rep movsb popl %edi popl %esi popl %es popl %ebp ret /* * pvbcopy(src, dst, cnt) * where src is a physical address and dst is a virtual address */ ENTRY(pvbcopy) .code32 pushl %ebp movl %esp, %ebp pushl %ds pushl %esi pushl %edi cld # set %ds to point at the flat segment movl $flatdataseg, %eax mov %ax, %ds movl 8(%ebp), %esi # source movl 12(%ebp), %edi # destination movl 16(%ebp), %ecx # count rep movsb popl %edi popl %esi popl %ds popl %ebp ret ENTRY(vtophys) movl _C_LABEL(ourseg), %eax shll $4, %eax addl 4(%esp), %eax ret /* * message: write the error message in %ds:%esi to the console */ message: .code16 /* * BIOS call "INT 10H Function 0Eh" to write character to console * Call with %ah = 0x0e * %al = character * %bh = page * %bl = foreground color */ pushl %eax pushl %ebx pushl %edx nextb: cld lodsb # load a byte into %al testb %al, %al jz done movb $0x0e, %ah movw $0x0001, %bx int $0x10 jmp nextb done: popl %edx popl %ebx popl %eax ret