btxldr.S revision 237763
1/* 2 * Copyright (c) 1998 Robert Nordier 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are freely 6 * permitted provided that the above copyright notice and this 7 * paragraph and the following disclaimer are duplicated in all 8 * such forms. 9 * 10 * This software is provided "AS IS" and without any express or 11 * implied warranties, including, without limitation, the implied 12 * warranties of merchantability and fitness for a particular 13 * purpose. 14 * 15 * $FreeBSD: stable/9/sys/boot/pc98/btx/btxldr/btxldr.S 237763 2012-06-29 10:12:18Z avg $ 16 */ 17 18/* 19 * Prototype BTX loader program, written in a couple of hours. The 20 * real thing should probably be more flexible, and in C. 21 */ 22 23#include <bootargs.h> 24 25/* 26 * Memory locations. 27 */ 28 .set MEM_STUB,0x600 # Real mode stub 29 .set MEM_ESP,0x1000 # New stack pointer 30 .set MEM_TBL,0x5000 # BTX page tables 31 .set MEM_ENTRY,0x9010 # BTX entry point 32 .set MEM_DATA,start+0x1000 # Data segment 33/* 34 * Segment selectors. 35 */ 36 .set SEL_SCODE,0x8 # 4GB code 37 .set SEL_SDATA,0x10 # 4GB data 38 .set SEL_RCODE,0x18 # 64K code 39 .set SEL_RDATA,0x20 # 64K data 40/* 41 * Paging constants. 42 */ 43 .set PAG_SIZ,0x1000 # Page size 44 .set PAG_ENT,0x4 # Page entry size 45/* 46 * Screen constants. 47 */ 48 .set SCR_MAT,0xe1 # Mode/attribute 49 .set SCR_COL,0x50 # Columns per row 50 .set SCR_ROW,0x19 # Rows per screen 51/* 52 * BIOS Data Area locations. 53 */ 54 .set BDA_MEM,0xa1501 # Free memory 55 .set BDA_POS,0xa153e # Cursor position 56/* 57 * Required by aout gas inadequacy. 58 */ 59 .set SIZ_STUB,0x1a # Size of stub 60/* 61 * We expect to be loaded by boot2 at the origin defined in ./Makefile. 62 */ 63 .globl start 64/* 65 * BTX program loader for ELF clients. 66 */ 67start: cld # String ops inc 68 cli 69gdcwait.1: inb $0x60,%al 70 testb $0x04,%al 71 jz gdcwait.1 72 movb $0xe0,%al 73 outb %al,$0x62 74 nop 75gdcwait.2: inb $0x60,%al 76 testb $0x01,%al 77 jz gdcwait.2 78 inb $0x62,%al 79 movb %al,%dl 80 inb $0x62,%al 81 movb %al,%dh 82 inb $0x62,%al 83 inb $0x62,%al 84 inb $0x62,%al 85 shlw $1,%dx 86 movl $BDA_POS,%ebx 87 movw %dx,(%ebx) 88 movl $m_logo,%esi # Identify 89 call putstr # ourselves 90 movzwl BDA_MEM,%eax # Get base memory 91 andl $0x7,%eax 92 incl %eax 93 shll $0x11,%eax # in bytes 94 movl %eax,%ebp # Base of user stack 95#ifdef BTXLDR_VERBOSE 96 movl $m_mem,%esi # Display 97 call hexout # amount of 98 call putstr # base memory 99#endif 100 lgdt gdtdesc # Load new GDT 101/* 102 * Relocate caller's arguments. 103 */ 104#ifdef BTXLDR_VERBOSE 105 movl $m_esp,%esi # Display 106 movl %esp,%eax # caller 107 call hexout # stack 108 call putstr # pointer 109 movl $m_args,%esi # Format string 110 leal 0x4(%esp),%ebx # First argument 111 movl $0x6,%ecx # Count 112start.1: movl (%ebx),%eax # Get argument and 113 addl $0x4,%ebx # bump pointer 114 call hexout # Display it 115 loop start.1 # Till done 116 call putstr # End message 117#endif 118 movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo 119 cmpl $0x0, %esi # If the bootinfo pointer 120 je start_null_bi # is null, don't copy it 121 movl BI_SIZE(%esi),%ecx # Allocate space 122 subl %ecx,%ebp # for bootinfo 123 movl %ebp,%edi # Destination 124 rep # Copy 125 movsb # it 126 movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer 127 movl %edi,%ebp # Restore base pointer 128#ifdef BTXLDR_VERBOSE 129 movl $m_rel_bi,%esi # Display 130 movl %ebp,%eax # bootinfo 131 call hexout # relocation 132 call putstr # message 133#endif 134start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments 135 testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data 136 jz start_fixed # Skip if the flag is not set 137 addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args 138start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset 139 leal 0x4(%esp),%esi # Source 140 movl %ebp,%edi # Destination 141 rep # Copy 142 movsb # them 143#ifdef BTXLDR_VERBOSE 144 movl $m_rel_args,%esi # Display 145 movl %ebp,%eax # argument 146 call hexout # relocation 147 call putstr # message 148#endif 149/* 150 * Set up BTX kernel. 151 */ 152 movl $MEM_ESP,%esp # Set up new stack 153 movl $MEM_DATA,%ebx # Data segment 154 movl $m_vers,%esi # Display BTX 155 call putstr # version message 156 movb 0x5(%ebx),%al # Get major version 157 addb $'0',%al # Display 158 call putchr # it 159 movb $'.',%al # And a 160 call putchr # dot 161 movb 0x6(%ebx),%al # Get minor 162 xorb %ah,%ah # version 163 movb $0xa,%dl # Divide 164 divb %dl,%al # by 10 165 addb $'0',%al # Display 166 call putchr # tens 167 movb %ah,%al # Get units 168 addb $'0',%al # Display 169 call putchr # units 170 call putstr # End message 171 movl %ebx,%esi # BTX image 172 movzwl 0x8(%ebx),%edi # Compute 173 orl $PAG_SIZ/PAG_ENT-1,%edi # the 174 incl %edi # BTX 175 shll $0x2,%edi # load 176 addl $MEM_TBL,%edi # address 177 pushl %edi # Save load address 178 movzwl 0xa(%ebx),%ecx # Image size 179#ifdef BTXLDR_VERBOSE 180 pushl %ecx # Save image size 181#endif 182 rep # Relocate 183 movsb # BTX 184 movl %esi,%ebx # Keep place 185#ifdef BTXLDR_VERBOSE 186 movl $m_rel_btx,%esi # Restore 187 popl %eax # parameters 188 call hexout # and 189#endif 190 popl %ebp # display 191#ifdef BTXLDR_VERBOSE 192 movl %ebp,%eax # the 193 call hexout # relocation 194 call putstr # message 195#endif 196 addl $PAG_SIZ,%ebp # Display 197#ifdef BTXLDR_VERBOSE 198 movl $m_base,%esi # the 199 movl %ebp,%eax # user 200 call hexout # base 201 call putstr # address 202#endif 203/* 204 * Set up ELF-format client program. 205 */ 206 cmpl $0x464c457f,(%ebx) # ELF magic number? 207 je start.3 # Yes 208 movl $e_fmt,%esi # Display error 209 call putstr # message 210start.2: jmp start.2 # Hang 211start.3: 212#ifdef BTXLDR_VERBOSE 213 movl $m_elf,%esi # Display ELF 214 call putstr # message 215 movl $m_segs,%esi # Format string 216#endif 217 movl $0x2,%edi # Segment count 218 movl 0x1c(%ebx),%edx # Get e_phoff 219 addl %ebx,%edx # To pointer 220 movzwl 0x2c(%ebx),%ecx # Get e_phnum 221start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? 222 jne start.6 # No 223#ifdef BTXLDR_VERBOSE 224 movl 0x4(%edx),%eax # Display 225 call hexout # p_offset 226 movl 0x8(%edx),%eax # Display 227 call hexout # p_vaddr 228 movl 0x10(%edx),%eax # Display 229 call hexout # p_filesz 230 movl 0x14(%edx),%eax # Display 231 call hexout # p_memsz 232 call putstr # End message 233#endif 234 pushl %esi # Save 235 pushl %edi # working 236 pushl %ecx # registers 237 movl 0x4(%edx),%esi # Get p_offset 238 addl %ebx,%esi # as pointer 239 movl 0x8(%edx),%edi # Get p_vaddr 240 addl %ebp,%edi # as pointer 241 movl 0x10(%edx),%ecx # Get p_filesz 242 rep # Set up 243 movsb # segment 244 movl 0x14(%edx),%ecx # Any bytes 245 subl 0x10(%edx),%ecx # to zero? 246 jz start.5 # No 247 xorb %al,%al # Then 248 rep # zero 249 stosb # them 250start.5: popl %ecx # Restore 251 popl %edi # working 252 popl %esi # registers 253 decl %edi # Segments to do 254 je start.7 # If none 255start.6: addl $0x20,%edx # To next entry 256 loop start.4 # Till done 257start.7: 258#ifdef BTXLDR_VERBOSE 259 movl $m_done,%esi # Display done 260 call putstr # message 261#endif 262 movl $start.8,%esi # Real mode stub 263 movl $MEM_STUB,%edi # Destination 264 movl $start.9-start.8,%ecx # Size 265 rep # Relocate 266 movsb # it 267 ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code 268 .code16 269start.8: xorw %ax,%ax # Data 270 movb $SEL_RDATA,%al # selector 271 movw %ax,%ss # Reload SS 272 movw %ax,%ds # Reset 273 movw %ax,%es # other 274 movw %ax,%fs # segment 275 movw %ax,%gs # limits 276 movl %cr0,%eax # Switch to 277 decw %ax # real 278 movl %eax,%cr0 # mode 279 ljmp $0,$MEM_ENTRY # Jump to BTX entry point 280start.9: 281 .code32 282/* 283 * Output message [ESI] followed by EAX in hex. 284 */ 285hexout: pushl %eax # Save 286 call putstr # Display message 287 popl %eax # Restore 288 pushl %esi # Save 289 pushl %edi # caller's 290 movl $buf,%edi # Buffer 291 pushl %edi # Save 292 call hex32 # To hex 293 xorb %al,%al # Terminate 294 stosb # string 295 popl %esi # Restore 296hexout.1: lodsb # Get a char 297 cmpb $'0',%al # Leading zero? 298 je hexout.1 # Yes 299 testb %al,%al # End of string? 300 jne hexout.2 # No 301 decl %esi # Undo 302hexout.2: decl %esi # Adjust for inc 303 call putstr # Display hex 304 popl %edi # Restore 305 popl %esi # caller's 306 ret # To caller 307/* 308 * Output zero-terminated string [ESI] to the console. 309 */ 310putstr.0: call putchr # Output char 311putstr: lodsb # Load char 312 testb %al,%al # End of string? 313 jne putstr.0 # No 314 ret # To caller 315/* 316 * Output character AL to the console. 317 */ 318putchr: pusha # Save 319 xorl %ecx,%ecx # Zero for loops 320 movb $SCR_MAT,%ah # Mode/attribute 321 movl $BDA_POS,%ebx # BDA pointer 322 movw (%ebx),%dx # Cursor position 323 movl $0xa0000,%edi # Regen buffer (color) 324putchr.1: cmpb $0xa,%al # New line? 325 je putchr.2 # Yes 326 movw %dx,%cx 327 movb %al,(%edi,%ecx,1) # Write char 328 addl $0x2000,%ecx 329 movb %ah,(%edi,%ecx,1) # Write attr 330 addw $0x2,%dx 331 jmp putchr.3 332putchr.2: movw %dx,%ax 333 movb $SCR_COL*2,%dl 334 div %dl 335 incb %al 336 mul %dl 337 movw %ax,%dx 338putchr.3: cmpw $SCR_COL*SCR_ROW*2,%dx 339 jb putchr.4 # No 340 leal 2*SCR_COL(%edi),%esi # New top line 341 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move 342 rep # Scroll 343 movsl # screen 344 movb $' ',%al # Space 345 xorb %ah,%ah 346 movb $SCR_COL,%cl # Columns to clear 347 rep # Clear 348 stosw # line 349 movw $(SCR_ROW-1)*SCR_COL*2,%dx 350putchr.4: movw %dx,(%ebx) # Update position 351 shrw $1,%dx 352gdcwait.3: inb $0x60,%al 353 testb $0x04,%al 354 jz gdcwait.3 355 movb $0x49,%al 356 outb %al,$0x62 357 movb %dl,%al 358 outb %al,$0x60 359 movb %dh,%al 360 outb %al,$0x60 361 popa # Restore 362 ret # To caller 363/* 364 * Convert EAX, AX, or AL to hex, saving the result to [EDI]. 365 */ 366hex32: pushl %eax # Save 367 shrl $0x10,%eax # Do upper 368 call hex16 # 16 369 popl %eax # Restore 370hex16: call hex16.1 # Do upper 8 371hex16.1: xchgb %ah,%al # Save/restore 372hex8: pushl %eax # Save 373 shrb $0x4,%al # Do upper 374 call hex8.1 # 4 375 popl %eax # Restore 376hex8.1: andb $0xf,%al # Get lower 4 377 cmpb $0xa,%al # Convert 378 sbbb $0x69,%al # to hex 379 das # digit 380 orb $0x20,%al # To lower case 381 stosb # Save char 382 ret # (Recursive) 383 384 .data 385 .p2align 4 386/* 387 * Global descriptor table. 388 */ 389gdt: .word 0x0,0x0,0x0,0x0 # Null entry 390 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE 391 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA 392 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE 393 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA 394gdt.1: 395gdtdesc: .word gdt.1-gdt-1 # Limit 396 .long gdt # Base 397/* 398 * Messages. 399 */ 400m_logo: .asciz " \nBTX loader 1.00 " 401m_vers: .asciz "BTX version is \0\n" 402e_fmt: .asciz "Error: Client format not supported\n" 403#ifdef BTXLDR_VERBOSE 404m_mem: .asciz "Starting in protected mode (base mem=\0)\n" 405m_esp: .asciz "Arguments passed (esp=\0):\n" 406m_args: .asciz"<howto=" 407 .asciz" bootdev=" 408 .asciz" junk=" 409 .asciz" " 410 .asciz" " 411 .asciz" bootinfo=\0>\n" 412m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" 413m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" 414m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" 415m_base: .asciz "Client base address is \0\n" 416m_elf: .asciz "Client format is ELF\n" 417m_segs: .asciz "text segment: offset=" 418 .asciz " vaddr=" 419 .asciz " filesz=" 420 .asciz " memsz=\0\n" 421 .asciz "data segment: offset=" 422 .asciz " vaddr=" 423 .asciz " filesz=" 424 .asciz " memsz=\0\n" 425m_done: .asciz "Loading complete\n" 426#endif 427/* 428 * Uninitialized data area. 429 */ 430buf: # Scratch buffer 431