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