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