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#include <bootargs.h> 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 testl $OPT_SET(RBX_MUTE), 4(%esp) # Check first argument 71 setnz muted # for RBX_MUTE, set flag 72 movl $m_logo,%esi # Identify 73 call putstr # ourselves 74 movzwl BDA_MEM,%eax # Get base memory 75 shll $0xa,%eax # in bytes 76 movl %eax,%ebp # Base of user stack 77#ifdef BTXLDR_VERBOSE 78 movl $m_mem,%esi # Display 79 call hexout # amount of 80 call putstr # base memory 81#endif 82 lgdt gdtdesc # Load new GDT 83/* 84 * Relocate caller's arguments. 85 */ 86#ifdef BTXLDR_VERBOSE 87 movl $m_esp,%esi # Display 88 movl %esp,%eax # caller 89 call hexout # stack 90 call putstr # pointer 91 movl $m_args,%esi # Format string 92 leal 0x4(%esp),%ebx # First argument 93 movl $0x6,%ecx # Count 94start.1: movl (%ebx),%eax # Get argument and 95 addl $0x4,%ebx # bump pointer 96 call hexout # Display it 97 loop start.1 # Till done 98 call putstr # End message 99#endif 100 movl BA_BOOTINFO+4(%esp),%esi # Source: bootinfo 101 cmpl $0x0, %esi # If the bootinfo pointer 102 je start_null_bi # is null, don't copy it 103 movl BI_SIZE(%esi),%ecx # Allocate space 104 subl %ecx,%ebp # for bootinfo 105 movl %ebp,%edi # Destination 106 rep # Copy 107 movsb # it 108 movl %ebp,BA_BOOTINFO+4(%esp) # Update pointer 109 movl %edi,%ebp # Restore base pointer 110#ifdef BTXLDR_VERBOSE 111 movl $m_rel_bi,%esi # Display 112 movl %ebp,%eax # bootinfo 113 call hexout # relocation 114 call putstr # message 115#endif 116start_null_bi: movl $BOOTARGS_SIZE,%ecx # Fixed size of arguments 117 testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data 118 jz start_fixed # Skip if the flag is not set 119 addl BOOTARGS_SIZE+4(%esp),%ecx # Add size of variable args 120start_fixed: subl $ARGOFF,%ebp # Place args at fixed offset 121 leal 0x4(%esp),%esi # Source 122 movl %ebp,%edi # Destination 123 rep # Copy 124 movsb # them 125#ifdef BTXLDR_VERBOSE 126 movl $m_rel_args,%esi # Display 127 movl %ebp,%eax # argument 128 call hexout # relocation 129 call putstr # message 130#endif 131/* 132 * Set up BTX kernel. 133 */ 134 movl $MEM_ESP,%esp # Set up new stack 135 movl $MEM_DATA,%ebx # Data segment 136 movl $m_vers,%esi # Display BTX 137 call putstr # version message 138 movb 0x5(%ebx),%al # Get major version 139 addb $'0',%al # Display 140 call putchr # it 141 movb $'.',%al # And a 142 call putchr # dot 143 movb 0x6(%ebx),%al # Get minor 144 xorb %ah,%ah # version 145 movb $0xa,%dl # Divide 146 divb %dl,%al # by 10 147 addb $'0',%al # Display 148 call putchr # tens 149 movb %ah,%al # Get units 150 addb $'0',%al # Display 151 call putchr # units 152 call putstr # End message 153 movl %ebx,%esi # BTX image 154 movzwl 0x8(%ebx),%edi # Compute 155 orl $PAG_SIZ/PAG_ENT-1,%edi # the 156 incl %edi # BTX 157 shll $0x2,%edi # load 158 addl $MEM_TBL,%edi # address 159 pushl %edi # Save load address 160 movzwl 0xa(%ebx),%ecx # Image size 161#ifdef BTXLDR_VERBOSE 162 pushl %ecx # Save image size 163#endif 164 rep # Relocate 165 movsb # BTX 166 movl %esi,%ebx # Keep place 167#ifdef BTXLDR_VERBOSE 168 movl $m_rel_btx,%esi # Restore 169 popl %eax # parameters 170 call hexout # and 171#endif 172 popl %ebp # display 173#ifdef BTXLDR_VERBOSE 174 movl %ebp,%eax # the 175 call hexout # relocation 176 call putstr # message 177#endif 178 addl $PAG_SIZ,%ebp # Display 179#ifdef BTXLDR_VERBOSE 180 movl $m_base,%esi # the 181 movl %ebp,%eax # user 182 call hexout # base 183 call putstr # address 184#endif 185/* 186 * Set up ELF-format client program. 187 */ 188 cmpl $0x464c457f,(%ebx) # ELF magic number? 189 je start.3 # Yes 190 movl $e_fmt,%esi # Display error 191 call putstr # message 192start.2: jmp start.2 # Hang 193start.3: 194#ifdef BTXLDR_VERBOSE 195 movl $m_elf,%esi # Display ELF 196 call putstr # message 197 movl $m_segs,%esi # Format string 198#endif 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 %ecx # working registers 217 movl 0x4(%edx),%esi # Get p_offset 218 addl %ebx,%esi # as pointer 219 movl 0x8(%edx),%edi # Get p_vaddr 220 addl %ebp,%edi # as pointer 221 movl 0x10(%edx),%ecx # Get p_filesz 222 rep # Set up 223 movsb # segment 224 movl 0x14(%edx),%ecx # Any bytes 225 subl 0x10(%edx),%ecx # to zero? 226 jz start.5 # No 227 xorb %al,%al # Then 228 rep # zero 229 stosb # them 230start.5: popl %ecx # Restore 231 popl %esi # registers 232start.6: addl $0x20,%edx # To next entry 233 loop start.4 # Till done 234#ifdef BTXLDR_VERBOSE 235 movl $m_done,%esi # Display done 236 call putstr # message 237#endif 238 movl $start.8,%esi # Real mode stub 239 movl $MEM_STUB,%edi # Destination 240 movl $start.9-start.8,%ecx # Size 241 rep # Relocate 242 movsb # it 243 ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code 244 .code16 245start.8: xorw %ax,%ax # Data 246 movb $SEL_RDATA,%al # selector 247 movw %ax,%ss # Reload SS 248 movw %ax,%ds # Reset 249 movw %ax,%es # other 250 movw %ax,%fs # segment 251 movw %ax,%gs # limits 252 movl %cr0,%eax # Switch to 253 decw %ax # real 254 movl %eax,%cr0 # mode 255 ljmp $0,$MEM_ENTRY # Jump to BTX entry point 256start.9: 257 .code32 258/* 259 * Output message [ESI] followed by EAX in hex. 260 */ 261hexout: pushl %eax # Save 262 call putstr # Display message 263 popl %eax # Restore 264 pushl %esi # Save 265 pushl %edi # caller's 266 movl $buf,%edi # Buffer 267 pushl %edi # Save 268 call hex32 # To hex 269 xorb %al,%al # Terminate 270 stosb # string 271 popl %esi # Restore 272hexout.1: lodsb # Get a char 273 cmpb $'0',%al # Leading zero? 274 je hexout.1 # Yes 275 testb %al,%al # End of string? 276 jne hexout.2 # No 277 decl %esi # Undo 278hexout.2: decl %esi # Adjust for inc 279 call putstr # Display hex 280 popl %edi # Restore 281 popl %esi # caller's 282 ret # To caller 283/* 284 * Output zero-terminated string [ESI] to the console. 285 */ 286putstr.0: call putchr # Output char 287putstr: lodsb # Load char 288 testb %al,%al # End of string? 289 jne putstr.0 # No 290 ret # To caller 291/* 292 * Output character AL to the console. 293 */ 294putchr: testb $1,muted # Check muted 295 jnz putchr.5 # do a nop 296 pusha # Save 297 xorl %ecx,%ecx # Zero for loops 298 movb $SCR_MAT,%ah # Mode/attribute 299 movl $BDA_POS,%ebx # BDA pointer 300 movw (%ebx),%dx # Cursor position 301 movl $0xb8000,%edi # Regen buffer (color) 302 cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? 303 jne putchr.1 # No 304 xorw %di,%di # Regen buffer (mono) 305putchr.1: cmpb $0xa,%al # New line? 306 je putchr.2 # Yes 307 xchgl %eax,%ecx # Save char 308 movb $SCR_COL,%al # Columns per row 309 mulb %dh # * row position 310 addb %dl,%al # + column 311 adcb $0x0,%ah # position 312 shll %eax # * 2 313 xchgl %eax,%ecx # Swap char, offset 314 movw %ax,(%edi,%ecx,1) # Write attr:char 315 incl %edx # Bump cursor 316 cmpb $SCR_COL,%dl # Beyond row? 317 jb putchr.3 # No 318putchr.2: xorb %dl,%dl # Zero column 319 incb %dh # Bump row 320putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? 321 jb putchr.4 # No 322 leal 2*SCR_COL(%edi),%esi # New top line 323 movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move 324 rep # Scroll 325 movsl # screen 326 movb $' ',%al # Space 327 movb $SCR_COL,%cl # Columns to clear 328 rep # Clear 329 stosw # line 330 movb $SCR_ROW-1,%dh # Bottom line 331putchr.4: movw %dx,(%ebx) # Update position 332 popa # Restore 333putchr.5: ret # To caller 334/* 335 * Convert EAX, AX, or AL to hex, saving the result to [EDI]. 336 */ 337hex32: pushl %eax # Save 338 shrl $0x10,%eax # Do upper 339 call hex16 # 16 340 popl %eax # Restore 341hex16: call hex16.1 # Do upper 8 342hex16.1: xchgb %ah,%al # Save/restore 343hex8: pushl %eax # Save 344 shrb $0x4,%al # Do upper 345 call hex8.1 # 4 346 popl %eax # Restore 347hex8.1: andb $0xf,%al # Get lower 4 348 cmpb $0xa,%al # Convert 349 sbbb $0x69,%al # to hex 350 das # digit 351 orb $0x20,%al # To lower case 352 stosb # Save char 353 ret # (Recursive) 354 355 .data 356 .p2align 4 357/* 358 * Global descriptor table. 359 */ 360gdt: .word 0x0,0x0,0x0,0x0 # Null entry 361 .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE 362 .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA 363 .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE 364 .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA 365gdt.1: 366gdtdesc: .word gdt.1-gdt-1 # Limit 367 .long gdt # Base 368/* 369 * Messages. 370 */ 371m_logo: .asciz " \nBTX loader 1.00 " 372m_vers: .asciz "BTX version is \0\n" 373e_fmt: .asciz "Error: Client format not supported\n" 374#ifdef BTXLDR_VERBOSE 375m_mem: .asciz "Starting in protected mode (base mem=\0)\n" 376m_esp: .asciz "Arguments passed (esp=\0):\n" 377m_args: .asciz "<howto=" 378 .asciz " bootdev=" 379 .asciz " junk=" 380 .asciz " " 381 .asciz " " 382 .asciz " bootinfo=\0>\n" 383m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" 384m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" 385m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" 386m_base: .asciz "Client base address is \0\n" 387m_elf: .asciz "Client format is ELF\n" 388m_segs: .asciz "text segment: offset=" 389 .asciz " vaddr=" 390 .asciz " filesz=" 391 .asciz " memsz=\0\n" 392 .asciz "data segment: offset=" 393 .asciz " vaddr=" 394 .asciz " filesz=" 395 .asciz " memsz=\0\n" 396m_done: .asciz "Loading complete\n" 397#endif 398 399/* 400 * Flags 401 */ 402muted: .byte 0x0 403 404/* 405 * Uninitialized data area. 406 */ 407buf: # Scratch buffer 408