btxldr.S revision 239064
18156Sphk/* 28156Sphk * Copyright (c) 1998 Robert Nordier 38156Sphk * All rights reserved. 48156Sphk * 58156Sphk * Redistribution and use in source and binary forms are freely 68156Sphk * permitted provided that the above copyright notice and this 78156Sphk * paragraph and the following disclaimer are duplicated in all 88156Sphk * such forms. 98477Sphk * 108156Sphk * This software is provided "AS IS" and without any express or 118156Sphk * implied warranties, including, without limitation, the implied 128153Sphk * warranties of merchantability and fitness for a particular 138158Sphk * purpose. 148158Sphk * 158158Sphk * $FreeBSD: head/sys/boot/pc98/btx/btxldr/btxldr.S 239064 2012-08-05 14:11:07Z nyan $ 168303Sphk */ 178303Sphk 188303Sphk#include <bootargs.h> 198303Sphk 208303Sphk/* 218303Sphk * Prototype BTX loader program, written in a couple of hours. The 228303Sphk * real thing should probably be more flexible, and in C. 238303Sphk */ 248303Sphk 258156Sphk/* 268241Sjkh * Memory locations. 278153Sphk */ 288153Sphk .set MEM_STUB,0x600 # Real mode stub 298153Sphk .set MEM_ESP,0x1000 # New stack pointer 308153Sphk .set MEM_TBL,0x5000 # BTX page tables 318156Sphk .set MEM_ENTRY,0x9010 # BTX entry point 328153Sphk .set MEM_DATA,start+0x1000 # Data segment 338153Sphk/* 348153Sphk * Segment selectors. 358153Sphk */ 368153Sphk .set SEL_SCODE,0x8 # 4GB code 378153Sphk .set SEL_SDATA,0x10 # 4GB data 388158Sphk .set SEL_RCODE,0x18 # 64K code 398158Sphk .set SEL_RDATA,0x20 # 64K data 408158Sphk/* 418153Sphk * Paging constants. 428153Sphk */ 438153Sphk .set PAG_SIZ,0x1000 # Page size 448153Sphk .set PAG_ENT,0x4 # Page entry size 458153Sphk/* 468153Sphk * Screen constants. 478346Sphk */ 488153Sphk .set SCR_MAT,0xe1 # Mode/attribute 498153Sphk .set SCR_COL,0x50 # Columns per row 508153Sphk .set SCR_ROW,0x19 # Rows per screen 518250Sphk/* 528250Sphk * BIOS Data Area locations. 538250Sphk */ 548250Sphk .set BDA_MEM,0xa1501 # Free memory 558153Sphk .set BDA_POS,0xa153e # Cursor position 568153Sphk/* 578153Sphk * Required by aout gas inadequacy. 588156Sphk */ 598264Sphk .set SIZ_STUB,0x1a # Size of stub 608264Sphk/* 618264Sphk * We expect to be loaded by boot2 at the origin defined in ./Makefile. 628156Sphk */ 638156Sphk .globl start 648156Sphk/* 658156Sphk * BTX program loader for ELF clients. 668156Sphk */ 678156Sphkstart: cld # String ops inc 688156Sphk cli 698264Sphkgdcwait.1: inb $0x60,%al 708233Sphk testb $0x04,%al 718233Sphk jz gdcwait.1 728264Sphk movb $0xe0,%al 738264Sphk outb %al,$0x62 748250Sphk nop 758250Sphkgdcwait.2: inb $0x60,%al 768250Sphk testb $0x01,%al 778250Sphk jz gdcwait.2 788250Sphk inb $0x62,%al 798250Sphk movb %al,%dl 808250Sphk inb $0x62,%al 818250Sphk movb %al,%dh 828250Sphk inb $0x62,%al 838153Sphk inb $0x62,%al 848153Sphk inb $0x62,%al 858156Sphk shlw $1,%dx 868156Sphk movl $BDA_POS,%ebx 878156Sphk movw %dx,(%ebx) 888156Sphk movl $m_logo,%esi # Identify 898153Sphk call putstr # ourselves 908156Sphk movzwl BDA_MEM,%eax # Get base memory 918156Sphk andl $0x7,%eax 928156Sphk incl %eax 938156Sphk shll $0x11,%eax # in bytes 948153Sphk movl %eax,%ebp # Base of user stack 958156Sphk#ifdef BTXLDR_VERBOSE 968156Sphk movl $m_mem,%esi # Display 978156Sphk call hexout # amount of 988156Sphk call putstr # base memory 998153Sphk#endif 1008156Sphk lgdt gdtdesc # Load new GDT 1018156Sphk/* 1028156Sphk * Relocate caller's arguments. 1038156Sphk */ 1048153Sphk#ifdef BTXLDR_VERBOSE 1058156Sphk movl $m_esp,%esi # Display 1068156Sphk movl %esp,%eax # caller 1078156Sphk call hexout # stack 1088156Sphk call putstr # pointer 1098156Sphk movl $m_args,%esi # Format string 1108153Sphk leal 0x4(%esp),%ebx # First argument 1118156Sphk movl $0x6,%ecx # Count 1128156Sphkstart.1: movl (%ebx),%eax # Get argument and 1138156Sphk addl $0x4,%ebx # bump pointer 1148156Sphk call hexout # Display it 1158156Sphk loop start.1 # Till done 1168156Sphk call putstr # End message 1178156Sphk#endif 1188156Sphk movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo 1198156Sphk cmpl $0x0, %esi # If the bootinfo pointer 1208156Sphk je start_null_bi # is null, don't copy it 1218156Sphk movl BI_SIZE(%esi),%ecx # Allocate space 1228156Sphk subl %ecx,%ebp # for bootinfo 1238156Sphk movl %ebp,%edi # Destination 1248156Sphk rep # Copy 1258156Sphk movsb # it 1268156Sphk movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer 1278156Sphk movl %edi,%ebp # Restore base pointer 1288156Sphk#ifdef BTXLDR_VERBOSE 1298156Sphk movl $m_rel_bi,%esi # Display 1308156Sphk movl %ebp,%eax # bootinfo 1318156Sphk call hexout # relocation 1328156Sphk call putstr # message 1338156Sphk#endif 1348156Sphkstart_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments 1358157Sphk testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data 1368157Sphk jz start_fixed # Skip if the flag is not set 1378157Sphk addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args 1388157Sphkstart_fixed: subl $ARGOFF,%ebp # Place args at fixed offset 1398157Sphk leal 0x4(%esp),%esi # Source 1408156Sphk movl %ebp,%edi # Destination 1418156Sphk rep # Copy 1428156Sphk movsb # them 1438156Sphk#ifdef BTXLDR_VERBOSE 1448156Sphk movl $m_rel_args,%esi # Display 1458158Sphk movl %ebp,%eax # argument 1468158Sphk call hexout # relocation 1478158Sphk call putstr # message 1488158Sphk#endif 1498158Sphk/* 1508158Sphk * Set up BTX kernel. 1518158Sphk */ 1528158Sphk movl $MEM_ESP,%esp # Set up new stack 1538158Sphk movl $MEM_DATA,%ebx # Data segment 1548158Sphk movl $m_vers,%esi # Display BTX 1558158Sphk call putstr # version message 1568158Sphk movb 0x5(%ebx),%al # Get major version 1578158Sphk addb $'0',%al # Display 1588158Sphk call putchr # it 1598158Sphk movb $'.',%al # And a 1608158Sphk call putchr # dot 1618158Sphk movb 0x6(%ebx),%al # Get minor 1628158Sphk xorb %ah,%ah # version 1638160Sphk movb $0xa,%dl # Divide 1648160Sphk divb %dl,%al # by 10 1658160Sphk addb $'0',%al # Display 1668160Sphk call putchr # tens 1678160Sphk movb %ah,%al # Get units 1688178Sphk addb $'0',%al # Display 1698178Sphk call putchr # units 1708178Sphk call putstr # End message 1718178Sphk movl %ebx,%esi # BTX image 1728178Sphk movzwl 0x8(%ebx),%edi # Compute 1738178Sphk orl $PAG_SIZ/PAG_ENT-1,%edi # the 1748178Sphk incl %edi # BTX 1758178Sphk shll $0x2,%edi # load 1768178Sphk addl $MEM_TBL,%edi # address 1778178Sphk pushl %edi # Save load address 1788178Sphk movzwl 0xa(%ebx),%ecx # Image size 1798178Sphk#ifdef BTXLDR_VERBOSE 1808178Sphk pushl %ecx # Save image size 1818178Sphk#endif 1828178Sphk rep # Relocate 1838178Sphk movsb # BTX 1848178Sphk movl %esi,%ebx # Keep place 1858178Sphk#ifdef BTXLDR_VERBOSE 1868178Sphk movl $m_rel_btx,%esi # Restore 1878178Sphk popl %eax # parameters 1888178Sphk call hexout # and 1898178Sphk#endif 1908178Sphk popl %ebp # display 1918178Sphk#ifdef BTXLDR_VERBOSE 1928178Sphk movl %ebp,%eax # the 1938178Sphk call hexout # relocation 1948178Sphk call putstr # message 1958178Sphk#endif 1968178Sphk addl $PAG_SIZ,%ebp # Display 1978178Sphk#ifdef BTXLDR_VERBOSE 1988178Sphk movl $m_base,%esi # the 1998178Sphk movl %ebp,%eax # user 2008178Sphk call hexout # base 2018178Sphk call putstr # address 2028404Sphk#endif 2038404Sphk/* 2048404Sphk * Set up ELF-format client program. 2058404Sphk */ 2068404Sphk cmpl $0x464c457f,(%ebx) # ELF magic number? 2078404Sphk je start.3 # Yes 2088404Sphk movl $e_fmt,%esi # Display error 2098477Sphk call putstr # message 2108477Sphkstart.2: jmp start.2 # Hang 2118477Sphkstart.3: 2128477Sphk#ifdef BTXLDR_VERBOSE 2138156Sphk movl $m_elf,%esi # Display ELF 2148156Sphk call putstr # message 2158156Sphk movl $m_segs,%esi # Format string 2168156Sphk#endif 2178153Sphk movl $0x2,%edi # Segment count 2188153Sphk movl 0x1c(%ebx),%edx # Get e_phoff 2198153Sphk addl %ebx,%edx # To pointer 2208346Sphk movzwl 0x2c(%ebx),%ecx # Get e_phnum 2218153Sphkstart.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? 2228153Sphk jne start.6 # No 2238178Sphk#ifdef BTXLDR_VERBOSE 2248153Sphk movl 0x4(%edx),%eax # Display 2258153Sphk call hexout # p_offset 2268153Sphk movl 0x8(%edx),%eax # Display 2278158Sphk call hexout # p_vaddr 2288183Sphk movl 0x10(%edx),%eax # Display 2298153Sphk call hexout # p_filesz 2308153Sphk movl 0x14(%edx),%eax # Display 2318158Sphk call hexout # p_memsz 2328158Sphk call putstr # End message 2338158Sphk#endif 2348158Sphk pushl %esi # Save 2358158Sphk pushl %edi # working 2368158Sphk pushl %ecx # registers 2378158Sphk movl 0x4(%edx),%esi # Get p_offset 2388158Sphk addl %ebx,%esi # as pointer 2398158Sphk movl 0x8(%edx),%edi # Get p_vaddr 2408158Sphk addl %ebp,%edi # as pointer 2418158Sphk movl 0x10(%edx),%ecx # Get p_filesz 2428158Sphk rep # Set up 2438158Sphk movsb # segment 2448158Sphk movl 0x14(%edx),%ecx # Any bytes 2458158Sphk subl 0x10(%edx),%ecx # to zero? 2468158Sphk jz start.5 # No 2478158Sphk xorb %al,%al # Then 2488160Sphk rep # zero 2498178Sphk stosb # them 2508264Sphkstart.5: popl %ecx # Restore 2518158Sphk popl %edi # working 2528158Sphk popl %esi # registers 2538158Sphk decl %edi # Segments to do 2548158Sphk je start.7 # If none 2558158Sphkstart.6: addl $0x20,%edx # To next entry 2568158Sphk loop start.4 # Till done 2578158Sphkstart.7: 2588158Sphk#ifdef BTXLDR_VERBOSE 2598158Sphk movl $m_done,%esi # Display done 2608158Sphk call putstr # message 2618158Sphk#endif 2628303Sphk movl $start.8,%esi # Real mode stub 2638158Sphk movl $MEM_STUB,%edi # Destination 2648158Sphk movl $start.9-start.8,%ecx # Size 2658158Sphk rep # Relocate 2668158Sphk movsb # it 2678158Sphk ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code 2688158Sphk .code16 2698158Sphkstart.8: xorw %ax,%ax # Data 2708158Sphk movb $SEL_RDATA,%al # selector 2718158Sphk movw %ax,%ss # Reload SS 2728158Sphk movw %ax,%ds # Reset 2738158Sphk movw %ax,%es # other 2748158Sphk movw %ax,%fs # segment 2758158Sphk movw %ax,%gs # limits 2768158Sphk movl %cr0,%eax # Switch to 2778158Sphk decw %ax # real 2788158Sphk movl %eax,%cr0 # mode 2798158Sphk ljmp $0,$MEM_ENTRY # Jump to BTX entry point 2808158Sphkstart.9: 2818158Sphk .code32 2828158Sphk/* 2838158Sphk * Output message [ESI] followed by EAX in hex. 2848158Sphk */ 2858158Sphkhexout: pushl %eax # Save 2868158Sphk call putstr # Display message 2878158Sphk popl %eax # Restore 2888158Sphk pushl %esi # Save 2898158Sphk pushl %edi # caller's 2908303Sphk movl $buf,%edi # Buffer 2918158Sphk pushl %edi # Save 2928158Sphk call hex32 # To hex 2938158Sphk xorb %al,%al # Terminate 2948158Sphk stosb # string 2958158Sphk popl %esi # Restore 2968158Sphkhexout.1: lodsb # Get a char 2978158Sphk cmpb $'0',%al # Leading zero? 2988158Sphk je hexout.1 # Yes 2998158Sphk testb %al,%al # End of string? 3008158Sphk jne hexout.2 # No 3018158Sphk decl %esi # Undo 3028158Sphkhexout.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