1/* $OpenBSD: srt0.S,v 1.3 2012/10/29 14:18:11 jsing Exp $ */ 2 3/* 4 * Copyright (c) 1997 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29#include <machine/asm.h> 30#include <assym.h> 31 32#define BOOTSTACK 0xfffc 33 34 .globl _C_LABEL(end) 35 .globl _C_LABEL(edata) 36 .globl _C_LABEL(boot) 37 .globl _C_LABEL(_rtt) 38 .globl _C_LABEL(bios_bootdev) 39 .globl _ASM_LABEL(pmm_init) 40 .globl Gdtr 41 42 .text 43 .code16 44 .globl _start 45_start: 46#ifdef DEBUG 47 movl $0xb80a0, %ebx 48 addr32 movl $0x07420742, (%ebx) 49#endif 50 51/* Clobbers %ax, maybe more */ 52#define putc(c) movb $c, %al; call Lchr 53 54 /* 55 * We are loaded by the PXE loader at location 0x7C00. Like 56 * the standard /boot, we are linked to run at 0x40120 (load 57 * address 0x40000), so we relocate to there. 58 * 59 * From 0x7C00 to 0x40000 is 0x38400 (230400) bytes, so we don't 60 * have to worry about an overlapping copy until pxeboot is 61 * over 225 KB. 62 * 63 * PXE loads us with a stack that grows down from 0x80000 (512 KB). 64 * While it is unlikely that this will clash with our code that 65 * we're copying up, we create a temporary stack just below us 66 * before the relocate. We also set the entire %esp register, to 67 * be on the safe side. 68 */ 69#define PXEBOOTADDR 0x7c00 /* Address where we are loaded by PXE */ 70 xorw %ax, %ax 71 movw %ax, %ss /* CPU disables interrupts till... */ 72 movl $PXEBOOTADDR-4, %esp /* after this instruction */ 73 74 pushl %edx /* Preserve the drive number. */ 75 76 movw $(PXEBOOTADDR >> 4), %ax /* Reloc from %ds = 0x7c0. */ 77 movw $(LINKADDR >> 4), %bx /* Reloc to %es = 0x4012. */ 78 79 movl $_C_LABEL(end), %edx 80 subl $_C_LABEL(_start), %edx /* How big are we? */ 81 82 /* 83 * Relocate in blocks that are a maximum of 32KB in size, incrementing 84 * the segment registers after each block. The 'rep; movsb' instruction 85 * uses %cx, which limits us to a maximum block size of 0xfff0, even 86 * though we can address the full 64KB within a single segment. 87 */ 88#define RELOC_BLOCK_SIZE 0x8000 89reloc_loop: 90 movl %edx, %ecx 91 jcxz reloc_done 92 cmpl $RELOC_BLOCK_SIZE, %ecx 93 jbe reloc_notrunc 94 movl $RELOC_BLOCK_SIZE, %ecx 95reloc_notrunc: 96 subl %ecx, %edx 97 98 movw %ax, %ds /* Where we're coming from */ 99 xorw %si, %si 100 101 movw %bx, %es /* Where we're going to */ 102 xorw %di, %di 103 104 cld 105 rep; movsb /* Copy into place */ 106 107 addw $(RELOC_BLOCK_SIZE >> 4), %ax 108 addw $(RELOC_BLOCK_SIZE >> 4), %bx 109 110 jmp reloc_loop 111 112reloc_done: 113 popl %edx 114 jmpl $(LINKADDR >> 4), $(relocated-_start) /* Now relocate */ 115 116relocated: 117 /* 118 * In 16-bit mode, we have segment registers == 0x4012, and 119 * offsets work from here, with offset(_start) == 0. 120 * 121 * In 32-bit mode, we have a flat memory model, where 122 * offset(_start) == 0x40120. This is how we're linked. 123 * 124 * Now transition to protected mode. 125 * 126 * First, initialise the global descriptor table. 127 */ 128 cli 129 push %cs 130 pop %ds 131 addr32 data32 lgdt (Gdtr - LINKADDR) 132 133 movl %cr0, %eax 134 orl $CR0_PE, %eax 135 data32 movl %eax, %cr0 136 data32 ljmp $8, $1f /* Seg sel 0x08 is flat 32-bit code */ 1371: 138 .code32 139 movl $0x10, %eax /* Seg sel 0x10 is flat 32-bit data */ 140 mov %ax, %ds 141 mov %ax, %es 142 mov %ax, %fs 143 mov %ax, %gs 144 mov %ax, %ss 145 movl $BOOTSTACK, %esp 146#ifdef DEBUG 147 movl $0xb8000, %ebx 148 movl $0x07420742, (%ebx) 149#endif 150 151 xorl %edx, %edx 152 movl %edx, _C_LABEL(bios_bootdev) 153 pushl %edx /* boot() takes this as a parameter */ 154 155#ifdef DEBUG 156 movl $0xb80a4, %ebx 157 movl $0x07520752, (%ebx) 158#endif 159 160 /* Zero .bss */ 161 xorl %eax, %eax 162 movl $_C_LABEL(end), %ecx 163 subl $_C_LABEL(edata), %ecx 164 movl $_C_LABEL(edata), %edi 165 cld 166 rep; stosb 167 168 /* Set up an interrupt descriptor table for protected mode. */ 169 call _ASM_LABEL(pmm_init) 170 171 /* Set our program name ("PXEBOOT", not "BOOT"). */ 172 movl $pxe_progname, %eax 173 movl %eax, progname 174 175 /* 176 * Now call "main()". 177 * 178 * We run in flat 32-bit protected mode, with no address mapping. 179 */ 180#ifdef DEBUG 181 movl $0xb8004, %ebx 182 movl $0x07410741, (%ebx) 183#endif 184 call _C_LABEL(boot) 185 186 /* boot() should not return. If it does, reset computer. */ 187 jmp _C_LABEL(_rtt) 188 189ENTRY(debugchar) 190 pushl %ebx 191 movl 8(%esp), %ebx 192 addl %ebx, %ebx 193 addl $0xb8000, %ebx 194 195 xorl %eax, %eax 196 movb 12(%esp), %al 197 198 andl $0xfffffffe, %ebx 199 movb %al, (%ebx) 200 popl %ebx 201 ret 202 203 .code16 204 205/* 206 * Write out value in %ax in hex 207 */ 208hex_word: 209 pushw %ax 210 mov %ah, %al 211 call hex_byte 212 popw %ax 213 /* fall thru */ 214/* 215 * Write out value in %al in hex 216 */ 217hex_byte: 218 pushw %ax 219 shrb $4, %al 220 call hex_nibble 221 popw %ax 222 /* fall thru */ 223 224/* Write out nibble in %al */ 225hex_nibble: 226 and $0x0F, %al 227 add $'0', %al 228 cmpb $'9', %al 229 jbe Lchr 230 addb $'A'-'9'-1, %al 231 /* fall thru to Lchr */ 232/* 233 * Lchr: write the character in %al to console 234 */ 235Lchr: 236 pushw %bx 237 movb $0x0e, %ah 238 xorw %bx, %bx 239 incw %bx /* movw $0x01, %bx */ 240 int $0x10 241 popw %bx 242 ret 243 244pxe_progname: 245 .asciz "PXEBOOT" 246 247 .end 248