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