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