btxldr.S revision 302408
11573Srgrimes/* 21573Srgrimes * Copyright (c) 1998 Robert Nordier 31573Srgrimes * All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms are freely 61573Srgrimes * permitted provided that the above copyright notice and this 71573Srgrimes * paragraph and the following disclaimer are duplicated in all 81573Srgrimes * such forms. 91573Srgrimes * 101573Srgrimes * This software is provided "AS IS" and without any express or 111573Srgrimes * implied warranties, including, without limitation, the implied 121573Srgrimes * warranties of merchantability and fitness for a particular 131573Srgrimes * purpose. 141573Srgrimes * 151573Srgrimes * $FreeBSD: stable/11/sys/boot/i386/btx/btxldr/btxldr.S 235154 2012-05-09 08:04:29Z avg $ 161573Srgrimes */ 171573Srgrimes 181573Srgrimes#include <bootargs.h> 191573Srgrimes 201573Srgrimes#define RBX_MUTE 0x10 /* -m */ 211573Srgrimes#define OPT_SET(opt) (1 << (opt)) 221573Srgrimes 231573Srgrimes/* 241573Srgrimes * Prototype BTX loader program, written in a couple of hours. The 251573Srgrimes * real thing should probably be more flexible, and in C. 261573Srgrimes */ 271573Srgrimes 281573Srgrimes/* 291573Srgrimes * Memory locations. 301573Srgrimes */ 311573Srgrimes .set MEM_STUB,0x600 # Real mode stub 3253859Swes .set MEM_ESP,0x1000 # New stack pointer 3353859Swes .set MEM_TBL,0x5000 # BTX page tables 341573Srgrimes .set MEM_ENTRY,0x9010 # BTX entry point 351573Srgrimes .set MEM_DATA,start+0x1000 # Data segment 361573Srgrimes/* 371573Srgrimes * Segment selectors. 381573Srgrimes */ 391573Srgrimes .set SEL_SCODE,0x8 # 4GB code 401573Srgrimes .set SEL_SDATA,0x10 # 4GB data 411573Srgrimes .set SEL_RCODE,0x18 # 64K code 421573Srgrimes .set SEL_RDATA,0x20 # 64K data 431573Srgrimes/* 441573Srgrimes * Paging constants. 451573Srgrimes */ 461573Srgrimes .set PAG_SIZ,0x1000 # Page size 471573Srgrimes .set PAG_ENT,0x4 # Page entry size 481573Srgrimes/* 491573Srgrimes * Screen constants. 501573Srgrimes */ 511573Srgrimes .set SCR_MAT,0x7 # Mode/attribute 5223320Sache .set SCR_COL,0x50 # Columns per row 531573Srgrimes .set SCR_ROW,0x19 # Rows per screen 541573Srgrimes/* 5533666Sjb * BIOS Data Area locations. 5633666Sjb */ 5733666Sjb .set BDA_MEM,0x413 # Free memory 5823320Sache .set BDA_SCR,0x449 # Video mode 5933666Sjb .set BDA_POS,0x450 # Cursor position 601573Srgrimes/* 611573Srgrimes * Required by aout gas inadequacy. 621573Srgrimes */ 631573Srgrimes .set SIZ_STUB,0x1a # Size of stub 641573Srgrimes/* 6553859Swes * We expect to be loaded by boot2 at the origin defined in ./Makefile. 6653859Swes */ 6753859Swes .globl start 6853859Swes/* 6953859Swes * BTX program loader for ELF clients. 7053859Swes */ 7153859Swesstart: cld # String ops inc 7253859Swes testl $OPT_SET(RBX_MUTE), 4(%esp) # Check first argument 7353859Swes setnz muted # for RBX_MUTE, set flag 7453859Swes movl $m_logo,%esi # Identify 7553859Swes call putstr # ourselves 7653859Swes movzwl BDA_MEM,%eax # Get base memory 7753859Swes shll $0xa,%eax # in bytes 7853859Swes movl %eax,%ebp # Base of user stack 7953859Swes#ifdef BTXLDR_VERBOSE 8053859Swes movl $m_mem,%esi # Display 81 call hexout # amount of 82 call putstr # base memory 83#endif 84 lgdt gdtdesc # Load new GDT 85/* 86 * Relocate caller's arguments. 87 */ 88#ifdef BTXLDR_VERBOSE 89 movl $m_esp,%esi # Display 90 movl %esp,%eax # caller 91 call hexout # stack 92 call putstr # pointer 93 movl $m_args,%esi # Format string 94 leal 0x4(%esp),%ebx # First argument 95 movl $0x6,%ecx # Count 96start.1: movl (%ebx),%eax # Get argument and 97 addl $0x4,%ebx # bump pointer 98 call hexout # Display it 99 loop start.1 # Till done 100 call putstr # End message 101#endif 102 movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo 103 cmpl $0x0, %esi # If the bootinfo pointer 104 je start_null_bi # is null, don't copy it 105 movl BI_SIZE(%esi),%ecx # Allocate space 106 subl %ecx,%ebp # for bootinfo 107 movl %ebp,%edi # Destination 108 rep # Copy 109 movsb # it 110 movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer 111 movl %edi,%ebp # Restore base pointer 112#ifdef BTXLDR_VERBOSE 113 movl $m_rel_bi,%esi # Display 114 movl %ebp,%eax # bootinfo 115 call hexout # relocation 116 call putstr # message 117#endif 118start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments 119 testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data 120 jz start_fixed # Skip if the flag is not set 121 addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args 122start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset 123 leal 0x4(%esp),%esi # Source 124 movl %ebp,%edi # Destination 125 rep # Copy 126 movsb # them 127#ifdef BTXLDR_VERBOSE 128 movl $m_rel_args,%esi # Display 129 movl %ebp,%eax # argument 130 call hexout # relocation 131 call putstr # message 132#endif 133/* 134 * Set up BTX kernel. 135 */ 136 movl $MEM_ESP,%esp # Set up new stack 137 movl $MEM_DATA,%ebx # Data segment 138 movl $m_vers,%esi # Display BTX 139 call putstr # version message 140 movb 0x5(%ebx),%al # Get major version 141 addb $'0',%al # Display 142 call putchr # it 143 movb $'.',%al # And a 144 call putchr # dot 145 movb 0x6(%ebx),%al # Get minor 146 xorb %ah,%ah # version 147 movb $0xa,%dl # Divide 148 divb %dl,%al # by 10 149 addb $'0',%al # Display 150 call putchr # tens 151 movb %ah,%al # Get units 152 addb $'0',%al # Display 153 call putchr # units 154 call putstr # End message 155 movl %ebx,%esi # BTX image 156 movzwl 0x8(%ebx),%edi # Compute 157 orl $PAG_SIZ/PAG_ENT-1,%edi # the 158 incl %edi # BTX 159 shll $0x2,%edi # load 160 addl $MEM_TBL,%edi # address 161 pushl %edi # Save load address 162 movzwl 0xa(%ebx),%ecx # Image size 163#ifdef BTXLDR_VERBOSE 164 pushl %ecx # Save image size 165#endif 166 rep # Relocate 167 movsb # BTX 168 movl %esi,%ebx # Keep place 169#ifdef BTXLDR_VERBOSE 170 movl $m_rel_btx,%esi # Restore 171 popl %eax # parameters 172 call hexout # and 173#endif 174 popl %ebp # display 175#ifdef BTXLDR_VERBOSE 176 movl %ebp,%eax # the 177 call hexout # relocation 178 call putstr # message 179#endif 180 addl $PAG_SIZ,%ebp # Display 181#ifdef BTXLDR_VERBOSE 182 movl $m_base,%esi # the 183 movl %ebp,%eax # user 184 call hexout # base 185 call putstr # address 186#endif 187/* 188 * Set up ELF-format client program. 189 */ 190 cmpl $0x464c457f,(%ebx) # ELF magic number? 191 je start.3 # Yes 192 movl $e_fmt,%esi # Display error 193 call putstr # message 194start.2: jmp start.2 # Hang 195start.3: 196#ifdef BTXLDR_VERBOSE 197 movl $m_elf,%esi # Display ELF 198 call putstr # message 199 movl $m_segs,%esi # Format string 200#endif 201 movl $0x2,%edi # Segment count 202 movl 0x1c(%ebx),%edx # Get e_phoff 203 addl %ebx,%edx # To pointer 204 movzwl 0x2c(%ebx),%ecx # Get e_phnum 205start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? 206 jne start.6 # No 207#ifdef BTXLDR_VERBOSE 208 movl 0x4(%edx),%eax # Display 209 call hexout # p_offset 210 movl 0x8(%edx),%eax # Display 211 call hexout # p_vaddr 212 movl 0x10(%edx),%eax # Display 213 call hexout # p_filesz 214 movl 0x14(%edx),%eax # Display 215 call hexout # p_memsz 216 call putstr # End message 217#endif 218 pushl %esi # Save 219 pushl %edi # working 220 pushl %ecx # registers 221 movl 0x4(%edx),%esi # Get p_offset 222 addl %ebx,%esi # as pointer 223 movl 0x8(%edx),%edi # Get p_vaddr 224 addl %ebp,%edi # as pointer 225 movl 0x10(%edx),%ecx # Get p_filesz 226 rep # Set up 227 movsb # segment 228 movl 0x14(%edx),%ecx # Any bytes 229 subl 0x10(%edx),%ecx # to zero? 230 jz start.5 # No 231 xorb %al,%al # Then 232 rep # zero 233 stosb # them 234start.5: popl %ecx # Restore 235 popl %edi # working 236 popl %esi # registers 237 decl %edi # Segments to do 238 je start.7 # If none 239start.6: addl $0x20,%edx # To next entry 240 loop start.4 # Till done 241start.7: 242#ifdef BTXLDR_VERBOSE 243 movl $m_done,%esi # Display done 244 call putstr # message 245#endif 246 movl $start.8,%esi # Real mode stub 247 movl $MEM_STUB,%edi # Destination 248 movl $start.9-start.8,%ecx # Size 249 rep # Relocate 250 movsb # it 251 ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code 252 .code16 253start.8: xorw %ax,%ax # Data 254 movb $SEL_RDATA,%al # selector 255 movw %ax,%ss # Reload SS 256 movw %ax,%ds # Reset 257 movw %ax,%es # other 258 movw %ax,%fs # segment 259 movw %ax,%gs # limits 260 movl %cr0,%eax # Switch to 261 decw %ax # real 262 movl %eax,%cr0 # mode 263 ljmp $0,$MEM_ENTRY # Jump to BTX entry point 264start.9: 265 .code32 266/* 267 * Output message [ESI] followed by EAX in hex. 268 */ 269hexout: pushl %eax # Save 270 call putstr # Display message 271 popl %eax # Restore 272 pushl %esi # Save 273 pushl %edi # caller's 274 movl $buf,%edi # Buffer 275 pushl %edi # Save 276 call hex32 # To hex 277 xorb %al,%al # Terminate 278 stosb # string 279 popl %esi # Restore 280hexout.1: lodsb # Get a char 281 cmpb $'0',%al # Leading zero? 282 je hexout.1 # Yes 283 testb %al,%al # End of string? 284 jne hexout.2 # No 285 decl %esi # Undo 286hexout.2: decl %esi # Adjust for inc 287 call putstr # Display hex 288 popl %edi # Restore 289 popl %esi # caller's 290 ret # To caller 291/* 292 * Output zero-terminated string [ESI] to the console. 293 */ 294putstr.0: call putchr # Output char 295putstr: lodsb # Load char 296 testb %al,%al # End of string? 297 jne putstr.0 # No 298 ret # To caller 299/* 300 * Output character AL to the console. 301 */ 302putchr: testb $1,muted # Check muted 303 jnz putchr.5 # do a nop 304 pusha # Save 305 xorl %ecx,%ecx # Zero for loops 306 movb $SCR_MAT,%ah # Mode/attribute 307 movl $BDA_POS,%ebx # BDA pointer 308 movw (%ebx),%dx # Cursor position 309 movl $0xb8000,%edi # Regen buffer (color) 310 cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? 311 jne putchr.1 # No 312 xorw %di,%di # Regen buffer (mono) 313putchr.1: cmpb $0xa,%al # New line? 314 je putchr.2 # Yes 315 xchgl %eax,%ecx # Save char 316 movb $SCR_COL,%al # Columns per row 317 mulb %dh # * row position 318 addb %dl,%al # + column 319 adcb $0x0,%ah # position 320 shll %eax # * 2 321 xchgl %eax,%ecx # Swap char, offset 322 movw %ax,(%edi,%ecx,1) # Write attr:char 323 incl %edx # Bump cursor 324 cmpb $SCR_COL,%dl # Beyond row? 325 jb putchr.3 # No 326putchr.2: xorb %dl,%dl # Zero column 327 incb %dh # Bump row 328putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? 329 jb putchr.4 # No 330 leal 2*SCR_COL(%edi),%esi # New top line 331 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move 332 rep # Scroll 333 movsl # screen 334 movb $' ',%al # Space 335 movb $SCR_COL,%cl # Columns to clear 336 rep # Clear 337 stosw # line 338 movb $SCR_ROW-1,%dh # Bottom line 339putchr.4: movw %dx,(%ebx) # Update position 340 popa # Restore 341putchr.5: ret # To caller 342/* 343 * Convert EAX, AX, or AL to hex, saving the result to [EDI]. 344 */ 345hex32: pushl %eax # Save 346 shrl $0x10,%eax # Do upper 347 call hex16 # 16 348 popl %eax # Restore 349hex16: call hex16.1 # Do upper 8 350hex16.1: xchgb %ah,%al # Save/restore 351hex8: pushl %eax # Save 352 shrb $0x4,%al # Do upper 353 call hex8.1 # 4 354 popl %eax # Restore 355hex8.1: andb $0xf,%al # Get lower 4 356 cmpb $0xa,%al # Convert 357 sbbb $0x69,%al # to hex 358 das # digit 359 orb $0x20,%al # To lower case 360 stosb # Save char 361 ret # (Recursive) 362 363 .data 364 .p2align 4 365/* 366 * Global descriptor table. 367 */ 368gdt: .word 0x0,0x0,0x0,0x0 # Null entry 369 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE 370 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA 371 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE 372 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA 373gdt.1: 374gdtdesc: .word gdt.1-gdt-1 # Limit 375 .long gdt # Base 376/* 377 * Messages. 378 */ 379m_logo: .asciz " \nBTX loader 1.00 " 380m_vers: .asciz "BTX version is \0\n" 381e_fmt: .asciz "Error: Client format not supported\n" 382#ifdef BTXLDR_VERBOSE 383m_mem: .asciz "Starting in protected mode (base mem=\0)\n" 384m_esp: .asciz "Arguments passed (esp=\0):\n" 385m_args: .asciz"<howto=" 386 .asciz" bootdev=" 387 .asciz" junk=" 388 .asciz" " 389 .asciz" " 390 .asciz" bootinfo=\0>\n" 391m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" 392m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" 393m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" 394m_base: .asciz "Client base address is \0\n" 395m_elf: .asciz "Client format is ELF\n" 396m_segs: .asciz "text segment: offset=" 397 .asciz " vaddr=" 398 .asciz " filesz=" 399 .asciz " memsz=\0\n" 400 .asciz "data segment: offset=" 401 .asciz " vaddr=" 402 .asciz " filesz=" 403 .asciz " memsz=\0\n" 404m_done: .asciz "Loading complete\n" 405#endif 406 407/* 408 * Flags 409 */ 410muted: .byte 0x0 411 412/* 413 * Uninitialized data area. 414 */ 415buf: # Scratch buffer 416