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