1/* 2 * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * Copyright (c) 1998 Robert Nordier 35 * All rights reserved. 36 * 37 * Redistribution and use in source and binary forms are freely 38 * permitted provided that the above copyright notice and this 39 * paragraph and the following disclaimer are duplicated in all 40 * such forms. 41 * 42 * This software is provided "AS IS" and without any express or 43 * implied warranties, including, without limitation, the implied 44 * warranties of merchantability and fitness for a particular 45 * purpose. 46 * 47 * $FreeBSD: src/sys/boot/i386/btx/btxldr/Makefile,v 1.17 2004/04/27 19:45:16 ru Exp $ 48 * $DragonFly: src/sys/boot/pc32/btx/btxldr/btxldr.S,v 1.3 2004/07/19 23:30:34 dillon Exp $ 49 */ 50 51/* 52 * Prototype BTX loader program, written in a couple of hours. The 53 * real thing should probably be more flexible, and in C. 54 */ 55 56#include "../../bootasm.h" 57/* 58 * Memory locations. 59 */ 60 .set MEM_DATA,start+0x1000 # Data segment 61/* 62 * Segment selectors. 63 */ 64 .set SEL_SCODE,0x8 # 4GB code 65 .set SEL_SDATA,0x10 # 4GB data 66 .set SEL_RCODE,0x18 # 64K code 67 .set SEL_RDATA,0x20 # 64K data 68/* 69 * Paging constants. 70 */ 71 .set PAG_SIZ,0x1000 # Page size 72 .set PAG_ENT,0x4 # Page entry size 73/* 74 * Screen constants. 75 */ 76 .set SCR_MAT,0x7 # Mode/attribute 77 .set SCR_COL,0x50 # Columns per row 78 .set SCR_ROW,0x19 # Rows per screen 79/* 80 * Required by aout gas inadequacy. 81 */ 82 .set SIZ_STUB,0x1a # Size of stub 83/* 84 * We expect to be loaded by boot2 at the origin defined in ./Makefile. 85 * This is typically 0x200000. 86 * 87 * I *THINK* (not sure) that execution begins with us in 'virtual mode', 88 * meaning everything is offset by MEM_BTX_USR. We will load a gdt to 89 * set the base offsets back to 0. 90 */ 91 .globl start 92/* 93 * BTX program loader for ELF clients. 94 */ 95start: cld # String ops inc 96 movl $m_logo,%esi # Identify 97 call putstr # ourselves 98#if !defined(MEM_BTX_USR_STK) 99 movzwl BDA_MEM,%eax # Get base memory 100 decl %eax 101 shll $0xa,%eax # Convert to bytes 102#else 103 movl $MEM_BTX_USR_STK,%eax 104#endif 105 movl %eax,%ebp # Base of user stack 106#ifdef BTXLDR_VERBOSE 107 movl $m_mem,%esi # Display 108 call hexout # amount of 109 call putstr # base memory 110#endif 111 112 /* 113 * Load a new GDT. XXX what does this do to running code 114 * segments? What if an interrupt occurs? What if the 115 * segment registers are reloaded? 116 */ 117 lgdt gdtdesc 118 119 /* 120 * Relocate caller's arguments. 121 */ 122#ifdef BTXLDR_VERBOSE 123 movl $m_esp,%esi # Display 124 movl %esp,%eax # caller 125 call hexout # stack 126 call putstr # pointer 127 movl $m_args,%esi # Format string 128 leal 0x4(%esp,1),%ebx # First argument 129 movl $0x6,%ecx # Count 130start.1: movl (%ebx),%eax # Get argument and 131 addl $0x4,%ebx # bump pointer 132 call hexout # Display it 133 loop start.1 # Till done 134 call putstr # End message 135#endif 136 /* 137 * Arguments: (entry, boothowto, bootdev, 0, 0, 0, bootinfo) 138 * 0x00, 0x04, 0x08, 0x18 139 * 140 * sizeof(bootinfo) == 0x48 (BOOTINFO_SIZE) 141 * sizeof arguments == 0x18 (MEM_ARG_SIZE) 142 * total arguments == 0x60 bytes (USR_ARGOFFSET) 143 */ 144 145 movl $BOOTINFO_SIZE,%ecx # Allocate space 146 subl %ecx,%ebp # for bootinfo 147 movl 0x18(%esp,1),%esi # Source: bootinfo 148 cmpl $0x0, %esi # If the bootinfo pointer 149 je start_null_bi # is null, do not copy it 150 movl %ebp,%edi # Destination 151 rep # Copy 152 movsb # it 153 movl %ebp,0x18(%esp,1) # Update pointer 154#ifdef BTXLDR_VERBOSE 155 movl $m_rel_bi,%esi # Display 156 movl %ebp,%eax # bootinfo 157 call hexout # relocation 158 call putstr # message 159#endif 160start_null_bi: movl $0x18,%ecx # Allocate space 161 subl %ecx,%ebp # for arguments 162 leal 0x4(%esp,1),%esi # Source 163 movl %ebp,%edi # Destination 164 rep # Copy 165 movsb # them 166#ifdef BTXLDR_VERBOSE 167 movl $m_rel_args,%esi # Display 168 movl %ebp,%eax # argument 169 call hexout # relocation 170 call putstr # message 171#endif 172/* 173 * Set up BTX kernel. 174 */ 175 movl $MEM_BTX_ESP,%esp # Set up new stack 176 movl $MEM_DATA,%ebx # Data segment 177 movl $m_vers,%esi # Display BTX 178 call putstr # version message 179 movb 0x5(%ebx),%al # Get major version 180 addb $'0',%al # Display 181 call putchr # it 182 movb $'.',%al # And a 183 call putchr # dot 184 movb 0x6(%ebx),%al # Get minor 185 xorb %ah,%ah # version 186 movb $0xa,%dl # Divide 187 divb %dl,%al # by 10 188 addb $'0',%al # Display 189 call putchr # tens 190 movb %ah,%al # Get units 191 addb $'0',%al # Display 192 call putchr # units 193 call putstr # End message 194 195 # Relocate the BTX image from wherever it was loaded (%ebx), 196 # which is typically offset 0x1000 in the load data, to 197 # MEM_BTX_ORG (typically 0x9000). 198 # 199 # MEM_BTX_TBL + ((mappages | 0x3ff) + 1) * 4 200 # mappages is typically 0x0ffn so we get 0x1000*4 = 0x4000 201 # MEM_BTX_TBL is traditionally mapped at 0x5000 so the 202 # whole calculation translated to MEM_BTX_ORG (0x9000). 203#if 0 204 /* XXX what is all of this junk? */ 205 movzwl 0x8(%ebx),%edi # Compute the BTX load address 206 orl $PAG_SIZ/PAG_ENT-1,%edi # (by skipping the page table) 207 incl %edi 208 shll $0x2,%edi 209 addl $MEM_BTX_TBL,%edi 210#else 211 movl $MEM_BTX_ORG,%edi 212#endif 213 movl %ebx,%esi # %esi = BTX image source 214 pushl %edi # Save load address 215 movzwl 0xa(%ebx),%ecx # Image size (bytes) 216#ifdef BTXLDR_VERBOSE 217 pushl %ecx # Save image size 218#endif 219 rep # Relocate BTX 220 movsb 221 movl %esi,%ebx # Keep place 222#ifdef BTXLDR_VERBOSE 223 movl $m_rel_btx,%esi # Restore 224 popl %eax # parameters 225 call hexout # and 226#endif 227 popl %ebp # display 228#ifdef BTXLDR_VERBOSE 229 movl %ebp,%eax # the 230 call hexout # relocation 231 call putstr # message 232#endif 233 /* 234 * ADJUST EBP FOR USER BASE ADDRESS 235 * 236 * XXX why not just move MEM_BTX_USR into %ebp ? 237 */ 238 addl $MEM_BTX_USR-MEM_BTX_ORG,%ebp 239#ifdef BTXLDR_VERBOSE 240 movl $m_base,%esi # the 241 movl %ebp,%eax # user 242 call hexout # base 243 call putstr # address 244#endif 245/* 246 * Set up ELF-format client program. 247 */ 248 cmpl $0x464c457f,(%ebx) # ELF magic number? 249 je start.3 # Yes 250 movl $e_fmt,%esi # Display error 251 call putstr # message 252start.2: jmp start.2 # Hang 253start.3: 254#ifdef BTXLDR_VERBOSE 255 movl $m_elf,%esi # Display ELF 256 call putstr # message 257 movl $m_segs,%esi # Format string 258#endif 259 movl $0x2,%edi # Segment count 260 movl 0x1c(%ebx),%edx # Get e_phoff 261 addl %ebx,%edx # To pointer 262 movzwl 0x2c(%ebx),%ecx # Get e_phnum 263start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? 264 jne start.6 # No 265#ifdef BTXLDR_VERBOSE 266 movl 0x4(%edx),%eax # Display 267 call hexout # p_offset 268 movl 0x8(%edx),%eax # Display 269 call hexout # p_vaddr 270 movl 0x10(%edx),%eax # Display 271 call hexout # p_filesz 272 movl 0x14(%edx),%eax # Display 273 call hexout # p_memsz 274 call putstr # End message 275#endif 276 pushl %esi # Save 277 pushl %edi # working 278 pushl %ecx # registers 279 movl 0x4(%edx),%esi # Get p_offset 280 addl %ebx,%esi # as pointer 281 movl 0x8(%edx),%edi # Get p_vaddr 282 addl %ebp,%edi # as pointer 283 movl 0x10(%edx),%ecx # Get p_filesz 284 rep # Set up 285 movsb # segment 286 movl 0x14(%edx),%ecx # Any bytes 287 subl 0x10(%edx),%ecx # to zero? 288 jz start.5 # No 289 xorb %al,%al # Then 290 rep # zero 291 stosb # them 292start.5: popl %ecx # Restore 293 popl %edi # working 294 popl %esi # registers 295 decl %edi # Segments to do 296 je start.7 # If none 297start.6: addl $0x20,%edx # To next entry 298 loop start.4 # Till done 299start.7: 300#ifdef BTXLDR_VERBOSE 301 movl $m_done,%esi # Display done 302 call putstr # message 303#endif 304 movl $start.8,%esi # Real mode stub 305 movl $BOOT0_ORIGIN,%edi # Destination 306 movl $start.9-start.8,%ecx # Size 307 rep # Relocate 308 movsb # it 309 ljmp $SEL_RCODE,$BOOT0_ORIGIN # To 16-bit code 310 .code16 311start.8: xorw %ax,%ax # Data 312 movb $SEL_RDATA,%al # selector 313 movw %ax,%ss # Reload SS 314 movw %ax,%ds # Reset 315 movw %ax,%es # other 316 movw %ax,%fs # segment 317 movw %ax,%gs # limits 318 movl %cr0,%eax # Switch to 319 decw %ax # real 320 movl %eax,%cr0 # mode 321 ljmp $0,$MEM_BTX_ENTRY # Jump to BTX entry point 322start.9: 323 .code32 324/* 325 * Output message [ESI] followed by EAX in hex. 326 */ 327hexout: pushl %eax # Save 328 call putstr # Display message 329 popl %eax # Restore 330 pushl %esi # Save 331 pushl %edi # callers 332 movl $buf,%edi # Buffer 333 pushl %edi # Save 334 call hex32 # To hex 335 xorb %al,%al # Terminate 336 stosb # string 337 popl %esi # Restore 338hexout.1: lodsb # Get a char 339 cmpb $'0',%al # Leading zero? 340 je hexout.1 # Yes 341 testb %al,%al # End of string? 342 jne hexout.2 # No 343 decl %esi # Undo 344hexout.2: decl %esi # Adjust for inc 345 call putstr # Display hex 346 popl %edi # Restore 347 popl %esi # callers 348 ret # To caller 349/* 350 * Output zero-terminated string [ESI] to the console. 351 */ 352putstr.0: call putchr # Output char 353putstr: lodsb # Load char 354 testb %al,%al # End of string? 355 jne putstr.0 # No 356 ret # To caller 357/* 358 * Output character AL to the console. 359 */ 360putchr: pusha # Save 361 xorl %ecx,%ecx # Zero for loops 362 movb $SCR_MAT,%ah # Mode/attribute 363 movl $BDA_POS,%ebx # BDA pointer 364 movw (%ebx),%dx # Cursor position 365 movl $0xb8000,%edi # Regen buffer (color) 366 cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? 367 jne putchr.1 # No 368 xorw %di,%di # Regen buffer (mono) 369putchr.1: cmpb $0xa,%al # New line? 370 je putchr.2 # Yes 371 xchgl %eax,%ecx # Save char 372 movb $SCR_COL,%al # Columns per row 373 mulb %dh # * row position 374 addb %dl,%al # + column 375 adcb $0x0,%ah # position 376 shll %eax # * 2 377 xchgl %eax,%ecx # Swap char, offset 378 movw %ax,(%edi,%ecx,1) # Write attr:char 379 incl %edx # Bump cursor 380 cmpb $SCR_COL,%dl # Beyond row? 381 jb putchr.3 # No 382putchr.2: xorb %dl,%dl # Zero column 383 incb %dh # Bump row 384putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? 385 jb putchr.4 # No 386 leal 2*SCR_COL(%edi),%esi # New top line 387 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move 388 rep # Scroll 389 movsl # screen 390 movb $' ',%al # Space 391 movb $SCR_COL,%cl # Columns to clear 392 rep # Clear 393 stosw # line 394 movb $SCR_ROW-1,%dh # Bottom line 395putchr.4: movw %dx,(%ebx) # Update position 396 popa # Restore 397 ret # To caller 398/* 399 * Convert EAX, AX, or AL to hex, saving the result to [EDI]. 400 */ 401hex32: pushl %eax # Save 402 shrl $0x10,%eax # Do upper 403 call hex16 # 16 404 popl %eax # Restore 405hex16: call hex16.1 # Do upper 8 406hex16.1: xchgb %ah,%al # Save/restore 407hex8: pushl %eax # Save 408 shrb $0x4,%al # Do upper 409 call hex8.1 # 4 410 popl %eax # Restore 411hex8.1: andb $0xf,%al # Get lower 4 412 cmpb $0xa,%al # Convert 413 sbbb $0x69,%al # to hex 414 das # digit 415 orb $0x20,%al # To lower case 416 stosb # Save char 417 ret # (Recursive) 418 419 .data 420 .p2align 4 421/* 422 * Global descriptor table. 423 */ 424gdt: .word 0x0,0x0,0x0,0x0 # Null entry 425 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE 426 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA 427 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE 428 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA 429gdt.1: 430gdtdesc: .word gdt.1-gdt-1 # Limit 431 .long gdt # Base 432/* 433 * Messages. 434 */ 435m_logo: .asciz " \nBTX loader 1.00 " 436m_vers: .asciz "BTX version is \0\n" 437e_fmt: .asciz "Error: Client format not supported\n" 438#ifdef BTXLDR_VERBOSE 439m_mem: .asciz "Starting in protected mode (base mem=\0)\n" 440m_esp: .asciz "Arguments passed (esp=\0):\n" 441m_args: .asciz"<howto=" 442 .asciz" bootdev=" 443 .asciz" junk=" 444 .asciz" " 445 .asciz" " 446 .asciz" bootinfo=\0>\n" 447m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" 448m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" 449m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" 450m_base: .asciz "Client base address is \0\n" 451m_elf: .asciz "Client format is ELF\n" 452m_segs: .asciz "text segment: offset=" 453 .asciz " vaddr=" 454 .asciz " filesz=" 455 .asciz " memsz=\0\n" 456 .asciz "data segment: offset=" 457 .asciz " vaddr=" 458 .asciz " filesz=" 459 .asciz " memsz=\0\n" 460m_done: .asciz "Loading complete\n" 461#endif 462/* 463 * Uninitialized data area. 464 */ 465buf: # Scratch buffer 466