1128710Sru/*
2128710Sru * Copyright (c) 1998 Robert Nordier
3128710Sru * All rights reserved.
4128710Sru *
5128710Sru * Redistribution and use in source and binary forms are freely
6128710Sru * permitted provided that the above copyright notice and this
7128710Sru * paragraph and the following disclaimer are duplicated in all
8128710Sru * such forms.
9128710Sru *
10128710Sru * This software is provided "AS IS" and without any express or
11128710Sru * implied warranties, including, without limitation, the implied
12128710Sru * warranties of merchantability and fitness for a particular
13128710Sru * purpose.
14128710Sru *
15128710Sru * $FreeBSD$
16128710Sru */
1743561Skato
18243448Snyan#include <bootargs.h>
19243448Snyan
20128710Sru/*
21128710Sru * Prototype BTX loader program, written in a couple of hours.  The
22128710Sru * real thing should probably be more flexible, and in C.
23128710Sru */
2443561Skato
25128710Sru/*
26128710Sru * Memory locations.
27128710Sru */
2843561Skato		.set MEM_STUB,0x600		# Real mode stub
2943561Skato		.set MEM_ESP,0x1000		# New stack pointer
3043561Skato		.set MEM_TBL,0x5000		# BTX page tables
3143561Skato		.set MEM_ENTRY,0x9010		# BTX entry point
3258871Skato		.set MEM_DATA,start+0x1000	# Data segment
33128710Sru/*
34128710Sru * Segment selectors.
35128710Sru */
3643561Skato		.set SEL_SCODE,0x8		# 4GB code
3743561Skato		.set SEL_SDATA,0x10		# 4GB data
3843561Skato		.set SEL_RCODE,0x18		# 64K code
3943561Skato		.set SEL_RDATA,0x20		# 64K data
40128710Sru/*
41128710Sru * Paging constants.
42128710Sru */
4343561Skato		.set PAG_SIZ,0x1000		# Page size
4443561Skato		.set PAG_ENT,0x4		# Page entry size
45128710Sru/*
46128710Sru * Screen constants.
47128710Sru */
4843561Skato		.set SCR_MAT,0xe1		# Mode/attribute
4943561Skato		.set SCR_COL,0x50		# Columns per row
5043561Skato		.set SCR_ROW,0x19		# Rows per screen
51128710Sru/*
52128710Sru * BIOS Data Area locations.
53128710Sru */
5443561Skato		.set BDA_MEM,0xa1501		# Free memory
5543561Skato		.set BDA_POS,0xa153e		# Cursor position
56128710Sru/*
57128710Sru * Required by aout gas inadequacy.
58128710Sru */
5943561Skato		.set SIZ_STUB,0x1a		# Size of stub
60128710Sru/*
61128710Sru * We expect to be loaded by boot2 at the origin defined in ./Makefile.
62128710Sru */
6343561Skato		.globl start
64128710Sru/*
65128710Sru * BTX program loader for ELF clients.
66128710Sru */
6743561Skatostart:		cld				# String ops inc
6843561Skato		cli
6943561Skatogdcwait.1:	inb $0x60,%al
7043561Skato		testb $0x04,%al
7143561Skato		jz gdcwait.1
7243561Skato		movb $0xe0,%al
7343561Skato		outb %al,$0x62
7443561Skato		nop
7543561Skatogdcwait.2:	inb $0x60,%al
7643561Skato		testb $0x01,%al
7743561Skato		jz gdcwait.2
7843561Skato		inb $0x62,%al
7943561Skato		movb %al,%dl
8043561Skato		inb $0x62,%al
8143561Skato		movb %al,%dh
8243561Skato		inb $0x62,%al
8343561Skato		inb $0x62,%al
8443561Skato		inb $0x62,%al
8543561Skato		shlw $1,%dx
8643561Skato		movl $BDA_POS,%ebx
8743561Skato		movw %dx,(%ebx)
8843561Skato		movl $m_logo,%esi		# Identify
8943561Skato		call putstr			#  ourselves
9043561Skato		movzwl BDA_MEM,%eax		# Get base memory
9143561Skato		andl $0x7,%eax
9243561Skato		incl %eax
9343561Skato		shll $0x11,%eax			#  in bytes
9443561Skato		movl %eax,%ebp			# Base of user stack
95125780Snyan#ifdef BTXLDR_VERBOSE
9643561Skato		movl $m_mem,%esi		# Display
9758871Skato		call hexout			#  amount of
9858871Skato		call putstr			#  base memory
99125780Snyan#endif
10043561Skato		lgdt gdtdesc			# Load new GDT
101128710Sru/*
102128710Sru * Relocate caller's arguments.
103128710Sru */
104125780Snyan#ifdef BTXLDR_VERBOSE
10543561Skato		movl $m_esp,%esi		# Display
10658871Skato		movl %esp,%eax			#  caller
10758871Skato		call hexout			#  stack
10858871Skato		call putstr			#  pointer
10943561Skato		movl $m_args,%esi		# Format string
110237763Savg		leal 0x4(%esp),%ebx		# First argument
11143561Skato		movl $0x6,%ecx			# Count
11243561Skatostart.1:	movl (%ebx),%eax		# Get argument and
11343561Skato		addl $0x4,%ebx			#  bump pointer
11458871Skato		call hexout			# Display it
11543561Skato		loop start.1			# Till done
11658871Skato		call putstr			# End message
117125780Snyan#endif
118237763Savg		movl BA_BOOTINFO+4(%esp),%esi	# Source: bootinfo
11958871Skato		cmpl $0x0, %esi			# If the bootinfo pointer
12058871Skato		je start_null_bi		#  is null, don't copy it
121237763Savg		movl BI_SIZE(%esi),%ecx 	# Allocate space
122237763Savg		subl %ecx,%ebp			#  for bootinfo
12343561Skato		movl %ebp,%edi			# Destination
12443561Skato		rep				# Copy
12543561Skato		movsb				#  it
126237763Savg		movl %ebp,BA_BOOTINFO+4(%esp)	# Update pointer
127237763Savg		movl %edi,%ebp			# Restore base pointer
128125780Snyan#ifdef BTXLDR_VERBOSE
12943561Skato		movl $m_rel_bi,%esi		# Display
13043561Skato		movl %ebp,%eax			#  bootinfo
13158871Skato		call hexout			#  relocation
13258871Skato		call putstr			#  message
133125780Snyan#endif
134237763Savgstart_null_bi:	movl $BOOTARGS_SIZE,%ecx 	# Fixed size of arguments
135237763Savg		testl $KARGS_FLAGS_EXTARG, BA_BOOTFLAGS+4(%esp) # Check for extra data
136237763Savg		jz start_fixed			# Skip if the flag is not set
137237763Savg		addl BOOTARGS_SIZE+4(%esp),%ecx	# Add size of variable args
138237763Savgstart_fixed:	subl $ARGOFF,%ebp		# Place args at fixed offset
139237763Savg		leal 0x4(%esp),%esi		# Source
14043561Skato		movl %ebp,%edi			# Destination
14143561Skato		rep				# Copy
14243561Skato		movsb				#  them
143125780Snyan#ifdef BTXLDR_VERBOSE
14443561Skato		movl $m_rel_args,%esi		# Display
14543561Skato		movl %ebp,%eax			#  argument
14658871Skato		call hexout			#  relocation
14758871Skato		call putstr			#  message
148125780Snyan#endif
149128710Sru/*
150128710Sru * Set up BTX kernel.
151128710Sru */
15243561Skato		movl $MEM_ESP,%esp		# Set up new stack
15343561Skato		movl $MEM_DATA,%ebx		# Data segment
15443561Skato		movl $m_vers,%esi		# Display BTX
15543561Skato		call putstr			#  version message
15643561Skato		movb 0x5(%ebx),%al		# Get major version
15743561Skato		addb $'0',%al			# Display
15843561Skato		call putchr			#  it
15943561Skato		movb $'.',%al			# And a
16043561Skato		call putchr			#  dot
16143561Skato		movb 0x6(%ebx),%al		# Get minor
16243561Skato		xorb %ah,%ah			#  version
16343561Skato		movb $0xa,%dl			# Divide
16443561Skato		divb %dl,%al			#  by 10
16543561Skato		addb $'0',%al			# Display
16643561Skato		call putchr			#  tens
16743561Skato		movb %ah,%al			# Get units
16843561Skato		addb $'0',%al			# Display
16943561Skato		call putchr			#  units
17043561Skato		call putstr			# End message
17143561Skato		movl %ebx,%esi			# BTX image
17243561Skato		movzwl 0x8(%ebx),%edi		# Compute
17343561Skato		orl $PAG_SIZ/PAG_ENT-1,%edi	#  the
17443561Skato		incl %edi			#  BTX
17543561Skato		shll $0x2,%edi			#  load
17643561Skato		addl $MEM_TBL,%edi		#  address
17758871Skato		pushl %edi			# Save load address
17843561Skato		movzwl 0xa(%ebx),%ecx		# Image size
179125780Snyan#ifdef BTXLDR_VERBOSE
18058871Skato		pushl %ecx			# Save image size
181125780Snyan#endif
18243561Skato		rep				# Relocate
18343561Skato		movsb				#  BTX
18443561Skato		movl %esi,%ebx			# Keep place
185125780Snyan#ifdef BTXLDR_VERBOSE
18643561Skato		movl $m_rel_btx,%esi		# Restore
18743561Skato		popl %eax			#  parameters
18858871Skato		call hexout			#  and
189125780Snyan#endif
19043561Skato		popl %ebp			#  display
191125780Snyan#ifdef BTXLDR_VERBOSE
19243561Skato		movl %ebp,%eax			#  the
19358871Skato		call hexout			#  relocation
19458871Skato		call putstr			#  message
195125780Snyan#endif
19643561Skato		addl $PAG_SIZ,%ebp		# Display
197125780Snyan#ifdef BTXLDR_VERBOSE
19843561Skato		movl $m_base,%esi		#  the
19943561Skato		movl %ebp,%eax			#  user
20058871Skato		call hexout			#  base
20158871Skato		call putstr			#  address
202125780Snyan#endif
203128710Sru/*
204128710Sru * Set up ELF-format client program.
205128710Sru */
20643561Skato		cmpl $0x464c457f,(%ebx) 	# ELF magic number?
20743561Skato		je start.3			# Yes
20843561Skato		movl $e_fmt,%esi		# Display error
20943561Skato		call putstr			#  message
21043561Skatostart.2:	jmp start.2			# Hang
21158871Skatostart.3:
212125780Snyan#ifdef BTXLDR_VERBOSE
21358871Skato		movl $m_elf,%esi		# Display ELF
21458871Skato		call putstr			#  message
21543561Skato		movl $m_segs,%esi		# Format string
216125780Snyan#endif
21743561Skato		movl $0x2,%edi			# Segment count
21843561Skato		movl 0x1c(%ebx),%edx		# Get e_phoff
21943561Skato		addl %ebx,%edx			# To pointer
22043561Skato		movzwl 0x2c(%ebx),%ecx		# Get e_phnum
22143561Skatostart.4:	cmpl $0x1,(%edx)		# Is p_type PT_LOAD?
22243561Skato		jne start.6			# No
223125780Snyan#ifdef BTXLDR_VERBOSE
22443561Skato		movl 0x4(%edx),%eax		# Display
22558871Skato		call hexout			#  p_offset
22643561Skato		movl 0x8(%edx),%eax		# Display
22758871Skato		call hexout			#  p_vaddr
22843561Skato		movl 0x10(%edx),%eax		# Display
22958871Skato		call hexout			#  p_filesz
23043561Skato		movl 0x14(%edx),%eax		# Display
23158871Skato		call hexout			#  p_memsz
23258871Skato		call putstr			# End message
233125780Snyan#endif
23443561Skato		pushl %esi			# Save
23543561Skato		pushl %edi			#  working
23643561Skato		pushl %ecx			#  registers
23743561Skato		movl 0x4(%edx),%esi		# Get p_offset
23843561Skato		addl %ebx,%esi			#  as pointer
23943561Skato		movl 0x8(%edx),%edi		# Get p_vaddr
24043561Skato		addl %ebp,%edi			#  as pointer
24143561Skato		movl 0x10(%edx),%ecx		# Get p_filesz
24243561Skato		rep				# Set up
24343561Skato		movsb				#  segment
24443561Skato		movl 0x14(%edx),%ecx		# Any bytes
24543561Skato		subl 0x10(%edx),%ecx		#  to zero?
24643561Skato		jz start.5			# No
24743561Skato		xorb %al,%al			# Then
24843561Skato		rep				#  zero
24943561Skato		stosb				#  them
25043561Skatostart.5:	popl %ecx			# Restore
25143561Skato		popl %edi			#  working
25243561Skato		popl %esi			#  registers
25343561Skato		decl %edi			# Segments to do
25443561Skato		je start.7			# If none
25543561Skatostart.6:	addl $0x20,%edx 		# To next entry
25643561Skato		loop start.4			# Till done
25758871Skatostart.7:
258125780Snyan#ifdef BTXLDR_VERBOSE
25958871Skato		movl $m_done,%esi		# Display done
26058871Skato		call putstr			#  message
261125780Snyan#endif
26243561Skato		movl $start.8,%esi		# Real mode stub
26343561Skato		movl $MEM_STUB,%edi		# Destination
26461064Snyan		movl $start.9-start.8,%ecx	# Size
26543561Skato		rep				# Relocate
26643561Skato		movsb				#  it
26743561Skato		ljmp $SEL_RCODE,$MEM_STUB	# To 16-bit code
26861064Snyan		.code16
26961064Snyanstart.8:	xorw %ax,%ax			# Data
27043561Skato		movb $SEL_RDATA,%al		#  selector
27161064Snyan		movw %ax,%ss			# Reload SS
27261064Snyan		movw %ax,%ds			# Reset
27361064Snyan		movw %ax,%es			#  other
27461064Snyan		movw %ax,%fs			#  segment
27561064Snyan		movw %ax,%gs			#  limits
27643561Skato		movl %cr0,%eax			# Switch to
27761064Snyan		decw %ax			#  real
27843561Skato		movl %eax,%cr0			#  mode
27961064Snyan		ljmp $0,$MEM_ENTRY		# Jump to BTX entry point
28043561Skatostart.9:
28161064Snyan		.code32
282128710Sru/*
283128710Sru * Output message [ESI] followed by EAX in hex.
284128710Sru */
28543561Skatohexout: 	pushl %eax			# Save
28643561Skato		call putstr			# Display message
28743561Skato		popl %eax			# Restore
28843561Skato		pushl %esi			# Save
28943561Skato		pushl %edi			#  caller's
29043561Skato		movl $buf,%edi			# Buffer
29143561Skato		pushl %edi			# Save
29243561Skato		call hex32			# To hex
29343561Skato		xorb %al,%al			# Terminate
29443561Skato		stosb				#  string
29543561Skato		popl %esi			# Restore
29643561Skatohexout.1:	lodsb				# Get a char
29743561Skato		cmpb $'0',%al			# Leading zero?
29843561Skato		je hexout.1			# Yes
29943561Skato		testb %al,%al			# End of string?
30043561Skato		jne hexout.2			# No
30143561Skato		decl %esi			# Undo
30243561Skatohexout.2:	decl %esi			# Adjust for inc
30343561Skato		call putstr			# Display hex
30443561Skato		popl %edi			# Restore
30543561Skato		popl %esi			#  caller's
30643561Skato		ret				# To caller
307128710Sru/*
308128710Sru * Output zero-terminated string [ESI] to the console.
309128710Sru */
31043561Skatoputstr.0:	call putchr			# Output char
31143561Skatoputstr: 	lodsb				# Load char
31243561Skato		testb %al,%al			# End of string?
31343561Skato		jne putstr.0			# No
31443561Skato		ret				# To caller
315128710Sru/*
316128710Sru * Output character AL to the console.
317128710Sru */
31843561Skatoputchr: 	pusha				# Save
31943561Skato		xorl %ecx,%ecx			# Zero for loops
32043561Skato		movb $SCR_MAT,%ah		# Mode/attribute
32143561Skato		movl $BDA_POS,%ebx		# BDA pointer
32243561Skato		movw (%ebx),%dx 		# Cursor position
32343561Skato		movl $0xa0000,%edi		# Regen buffer (color)
32443561Skatoputchr.1:	cmpb $0xa,%al			# New line?
32543561Skato		je putchr.2			# Yes
32643561Skato		movw %dx,%cx
32743561Skato		movb %al,(%edi,%ecx,1)		# Write char
32843561Skato		addl $0x2000,%ecx
32943561Skato		movb %ah,(%edi,%ecx,1)		# Write attr
33043561Skato		addw $0x2,%dx
33143561Skato		jmp putchr.3
33243561Skatoputchr.2:	movw %dx,%ax
33343561Skato		movb $SCR_COL*2,%dl
33443561Skato		div %dl
33543561Skato		incb %al
33643561Skato		mul %dl
33743561Skato		movw %ax,%dx
33843561Skatoputchr.3:	cmpw $SCR_COL*SCR_ROW*2,%dx
33943561Skato		jb putchr.4			# No
34043561Skato		leal 2*SCR_COL(%edi),%esi	# New top line
34143561Skato		movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
34243561Skato		rep				# Scroll
34343561Skato		movsl				#  screen
34443561Skato		movb $' ',%al			# Space
34543561Skato		xorb %ah,%ah
34643561Skato		movb $SCR_COL,%cl		# Columns to clear
34743561Skato		rep				# Clear
34843561Skato		stosw				#  line
34943561Skato		movw $(SCR_ROW-1)*SCR_COL*2,%dx
35043561Skatoputchr.4:	movw %dx,(%ebx) 		# Update position
35143561Skato		shrw $1,%dx
35243561Skatogdcwait.3:	inb $0x60,%al
35343561Skato		testb $0x04,%al
35443561Skato		jz gdcwait.3
35543561Skato		movb $0x49,%al
35643561Skato		outb %al,$0x62
35743561Skato		movb %dl,%al
35843561Skato		outb %al,$0x60
35943561Skato		movb %dh,%al
36043561Skato		outb %al,$0x60
36143561Skato		popa				# Restore
36243561Skato		ret				# To caller
363128710Sru/*
364128710Sru * Convert EAX, AX, or AL to hex, saving the result to [EDI].
365128710Sru */
36643561Skatohex32:		pushl %eax			# Save
36743561Skato		shrl $0x10,%eax 		# Do upper
36843561Skato		call hex16			#  16
36943561Skato		popl %eax			# Restore
37043561Skatohex16:		call hex16.1			# Do upper 8
37143561Skatohex16.1:	xchgb %ah,%al			# Save/restore
37243561Skatohex8:		pushl %eax			# Save
37343561Skato		shrb $0x4,%al			# Do upper
37443561Skato		call hex8.1			#  4
37543561Skato		popl %eax			# Restore
37643561Skatohex8.1: 	andb $0xf,%al			# Get lower 4
37743561Skato		cmpb $0xa,%al			# Convert
37843561Skato		sbbb $0x69,%al			#  to hex
37943561Skato		das				#  digit
38043561Skato		orb $0x20,%al			# To lower case
38143561Skato		stosb				# Save char
38243561Skato		ret				# (Recursive)
38343561Skato
38443561Skato		.data
38543561Skato		.p2align 4
386128710Sru/*
387128710Sru * Global descriptor table.
388128710Sru */
38943561Skatogdt:		.word 0x0,0x0,0x0,0x0		# Null entry
39043561Skato		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE
39143561Skato		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
39243561Skato		.word 0xffff,0x0,0x9a00,0x0	# SEL_RCODE
39343561Skato		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
39443561Skatogdt.1:
39543561Skatogdtdesc:	.word gdt.1-gdt-1		# Limit
39643561Skato		.long gdt			# Base
397128710Sru/*
398128710Sru * Messages.
399128710Sru */
40052148Sbrianm_logo: 	.asciz " \nBTX loader 1.00  "
40143561Skatom_vers: 	.asciz "BTX version is \0\n"
40243561Skatoe_fmt:		.asciz "Error: Client format not supported\n"
403125780Snyan#ifdef BTXLDR_VERBOSE
40443561Skatom_mem:		.asciz "Starting in protected mode (base mem=\0)\n"
40543561Skatom_esp:		.asciz "Arguments passed (esp=\0):\n"
40643561Skatom_args: 	.asciz"<howto="
40743561Skato		.asciz" bootdev="
40843561Skato		.asciz" junk="
40943561Skato		.asciz" "
41043561Skato		.asciz" "
41143561Skato		.asciz" bootinfo=\0>\n"
41243561Skatom_rel_bi:	.asciz "Relocated bootinfo (size=48) to \0\n"
41343561Skatom_rel_args:	.asciz "Relocated arguments (size=18) to \0\n"
41443561Skatom_rel_btx:	.asciz "Relocated kernel (size=\0) to \0\n"
41543561Skatom_base: 	.asciz "Client base address is \0\n"
41643561Skatom_elf:		.asciz "Client format is ELF\n"
41743561Skatom_segs: 	.asciz "text segment: offset="
41843561Skato		.asciz " vaddr="
41943561Skato		.asciz " filesz="
42043561Skato		.asciz " memsz=\0\n"
42143561Skato		.asciz "data segment: offset="
42243561Skato		.asciz " vaddr="
42343561Skato		.asciz " filesz="
42443561Skato		.asciz " memsz=\0\n"
42543561Skatom_done: 	.asciz "Loading complete\n"
426125780Snyan#endif
427128710Sru/*
428128710Sru * Uninitialized data area.
429128710Sru */
43043561Skatobuf:						# Scratch buffer
431