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