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