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