xref: /dragonfly/stand/boot/pc32/btx/btxldr/btxldr.S (revision 7d3e9a5b)
1/*
2 * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 *    contributors may be used to endorse or promote products derived
19 *    from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * Copyright (c) 1998 Robert Nordier
35 * All rights reserved.
36 *
37 * Redistribution and use in source and binary forms are freely
38 * permitted provided that the above copyright notice and this
39 * paragraph and the following disclaimer are duplicated in all
40 * such forms.
41 *
42 * This software is provided "AS IS" and without any express or
43 * implied warranties, including, without limitation, the implied
44 * warranties of merchantability and fitness for a particular
45 * purpose.
46 *
47 * $FreeBSD: src/sys/boot/i386/btx/btxldr/Makefile,v 1.17 2004/04/27 19:45:16 ru Exp $
48 * $DragonFly: src/sys/boot/pc32/btx/btxldr/btxldr.S,v 1.3 2004/07/19 23:30:34 dillon Exp $
49 */
50
51/*
52 * Prototype BTX loader program, written in a couple of hours.  The
53 * real thing should probably be more flexible, and in C.
54 */
55
56#include "../../bootasm.h"
57/*
58 * Memory locations.
59 */
60		.set MEM_DATA,start+0x1000	# Data segment
61/*
62 * Segment selectors.
63 */
64		.set SEL_SCODE,0x8		# 4GB code
65		.set SEL_SDATA,0x10		# 4GB data
66		.set SEL_RCODE,0x18		# 64K code
67		.set SEL_RDATA,0x20		# 64K data
68/*
69 * Paging constants.
70 */
71		.set PAG_SIZ,0x1000		# Page size
72		.set PAG_ENT,0x4		# Page entry size
73/*
74 * Screen constants.
75 */
76		.set SCR_MAT,0x7		# Mode/attribute
77		.set SCR_COL,0x50		# Columns per row
78		.set SCR_ROW,0x19		# Rows per screen
79/*
80 * Required by aout gas inadequacy.
81 */
82		.set SIZ_STUB,0x1a		# Size of stub
83/*
84 * We expect to be loaded by boot2 at the origin defined in ./Makefile.
85 * This is typically 0x200000.
86 *
87 * I *THINK* (not sure) that execution begins with us in 'virtual mode',
88 * meaning everything is offset by MEM_BTX_USR.  We will load a gdt to
89 * set the base offsets back to 0.
90 */
91		.globl start
92/*
93 * BTX program loader for ELF clients.
94 */
95start:		cld				# String ops inc
96		movl $m_logo,%esi		# Identify
97		call putstr			#  ourselves
98#if !defined(MEM_BTX_USR_STK)
99		movzwl BDA_MEM,%eax		# Get base memory
100		decl %eax
101		shll $0xa,%eax			# Convert to bytes
102#else
103		movl $MEM_BTX_USR_STK,%eax
104#endif
105		movl %eax,%ebp			# Base of user stack
106#ifdef BTXLDR_VERBOSE
107		movl $m_mem,%esi		# Display
108		call hexout			#  amount of
109		call putstr			#  base memory
110#endif
111
112		/*
113		 * Load a new GDT.  XXX what does this do to running code
114		 * segments?  What if an interrupt occurs?  What if the
115		 * segment registers are reloaded?
116		 */
117		lgdt gdtdesc
118
119		/*
120		 * Relocate caller's arguments.
121		 */
122#ifdef BTXLDR_VERBOSE
123		movl $m_esp,%esi		# Display
124		movl %esp,%eax			#  caller
125		call hexout			#  stack
126		call putstr			#  pointer
127		movl $m_args,%esi		# Format string
128		leal 0x4(%esp,1),%ebx		# First argument
129		movl $0x6,%ecx			# Count
130start.1:	movl (%ebx),%eax		# Get argument and
131		addl $0x4,%ebx			#  bump pointer
132		call hexout			# Display it
133		loop start.1			# Till done
134		call putstr			# End message
135#endif
136		/*
137		 * Arguments: (entry, boothowto, bootdev, 0, 0, 0, bootinfo)
138		 *		0x00,  0x04,      0x08,             0x18
139		 *
140		 * sizeof(bootinfo) == 0x48 (BOOTINFO_SIZE)
141		 * sizeof arguments == 0x18 (MEM_ARG_SIZE)
142		 * total arguments  == 0x60 bytes (USR_ARGOFFSET)
143		 */
144
145		movl $BOOTINFO_SIZE,%ecx 	# Allocate space
146		subl %ecx,%ebp			#  for bootinfo
147		movl 0x18(%esp,1),%esi		# Source: bootinfo
148		cmpl $0x0, %esi			# If the bootinfo pointer
149		je start_null_bi		#  is null, do not copy it
150		movl %ebp,%edi			# Destination
151		rep				# Copy
152		movsb				#  it
153		movl %ebp,0x18(%esp,1)		# Update pointer
154#ifdef BTXLDR_VERBOSE
155		movl $m_rel_bi,%esi		# Display
156		movl %ebp,%eax			#  bootinfo
157		call hexout			#  relocation
158		call putstr			#  message
159#endif
160start_null_bi:	movl $0x18,%ecx 		# Allocate space
161		subl %ecx,%ebp			#  for arguments
162		leal 0x4(%esp,1),%esi		# Source
163		movl %ebp,%edi			# Destination
164		rep				# Copy
165		movsb				#  them
166#ifdef BTXLDR_VERBOSE
167		movl $m_rel_args,%esi		# Display
168		movl %ebp,%eax			#  argument
169		call hexout			#  relocation
170		call putstr			#  message
171#endif
172/*
173 * Set up BTX kernel.
174 */
175		movl $MEM_BTX_ESP,%esp		# Set up new stack
176		movl $MEM_DATA,%ebx		# Data segment
177		movl $m_vers,%esi		# Display BTX
178		call putstr			#  version message
179		movb 0x5(%ebx),%al		# Get major version
180		addb $'0',%al			# Display
181		call putchr			#  it
182		movb $'.',%al			# And a
183		call putchr			#  dot
184		movb 0x6(%ebx),%al		# Get minor
185		xorb %ah,%ah			#  version
186		movb $0xa,%dl			# Divide
187		divb %dl,%al			#  by 10
188		addb $'0',%al			# Display
189		call putchr			#  tens
190		movb %ah,%al			# Get units
191		addb $'0',%al			# Display
192		call putchr			#  units
193		call putstr			# End message
194
195		# Relocate the BTX image from wherever it was loaded (%ebx),
196		# which is typically offset 0x1000 in the load data, to
197		# MEM_BTX_ORG (typically 0x9000).
198		#
199		# MEM_BTX_TBL + ((mappages | 0x3ff) + 1) * 4
200		# mappages is typically 0x0ffn so we get 0x1000*4 = 0x4000
201		# MEM_BTX_TBL is traditionally mapped at 0x5000 so the
202		# whole calculation translated to MEM_BTX_ORG (0x9000).
203#if 0
204		/* XXX what is all of this junk? */
205		movzwl 0x8(%ebx),%edi		# Compute the BTX load address
206		orl $PAG_SIZ/PAG_ENT-1,%edi	# (by skipping the page table)
207		incl %edi
208		shll $0x2,%edi
209		addl $MEM_BTX_TBL,%edi
210#else
211		movl $MEM_BTX_ORG,%edi
212#endif
213		movl %ebx,%esi			# %esi = BTX image source
214		pushl %edi			# Save load address
215		movzwl 0xa(%ebx),%ecx		# Image size (bytes)
216#ifdef BTXLDR_VERBOSE
217		pushl %ecx			# Save image size
218#endif
219		rep				# Relocate BTX
220		movsb
221		movl %esi,%ebx			# Keep place
222#ifdef BTXLDR_VERBOSE
223		movl $m_rel_btx,%esi		# Restore
224		popl %eax			#  parameters
225		call hexout			#  and
226#endif
227		popl %ebp			#  display
228#ifdef BTXLDR_VERBOSE
229		movl %ebp,%eax			#  the
230		call hexout			#  relocation
231		call putstr			#  message
232#endif
233		/*
234		 * ADJUST EBP FOR USER BASE ADDRESS
235		 *
236		 * XXX why not just move MEM_BTX_USR into %ebp ?
237		 */
238		addl $MEM_BTX_USR-MEM_BTX_ORG,%ebp
239#ifdef BTXLDR_VERBOSE
240		movl $m_base,%esi		#  the
241		movl %ebp,%eax			#  user
242		call hexout			#  base
243		call putstr			#  address
244#endif
245/*
246 * Set up ELF-format client program.
247 */
248		cmpl $0x464c457f,(%ebx) 	# ELF magic number?
249		je start.3			# Yes
250		movl $e_fmt,%esi		# Display error
251		call putstr			#  message
252start.2:	jmp start.2			# Hang
253start.3:
254#ifdef BTXLDR_VERBOSE
255		movl $m_elf,%esi		# Display ELF
256		call putstr			#  message
257		movl $m_segs,%esi		# Format string
258#endif
259		movl $0x2,%edi			# Segment count
260		movl 0x1c(%ebx),%edx		# Get e_phoff
261		addl %ebx,%edx			# To pointer
262		movzwl 0x2c(%ebx),%ecx		# Get e_phnum
263start.4:	cmpl $0x1,(%edx)		# Is p_type PT_LOAD?
264		jne start.6			# No
265#ifdef BTXLDR_VERBOSE
266		movl 0x4(%edx),%eax		# Display
267		call hexout			#  p_offset
268		movl 0x8(%edx),%eax		# Display
269		call hexout			#  p_vaddr
270		movl 0x10(%edx),%eax		# Display
271		call hexout			#  p_filesz
272		movl 0x14(%edx),%eax		# Display
273		call hexout			#  p_memsz
274		call putstr			# End message
275#endif
276		pushl %esi			# Save
277		pushl %edi			#  working
278		pushl %ecx			#  registers
279		movl 0x4(%edx),%esi		# Get p_offset
280		addl %ebx,%esi			#  as pointer
281		movl 0x8(%edx),%edi		# Get p_vaddr
282		addl %ebp,%edi			#  as pointer
283		movl 0x10(%edx),%ecx		# Get p_filesz
284		rep				# Set up
285		movsb				#  segment
286		movl 0x14(%edx),%ecx		# Any bytes
287		subl 0x10(%edx),%ecx		#  to zero?
288		jz start.5			# No
289		xorb %al,%al			# Then
290		rep				#  zero
291		stosb				#  them
292start.5:	popl %ecx			# Restore
293		popl %edi			#  working
294		popl %esi			#  registers
295		decl %edi			# Segments to do
296		je start.7			# If none
297start.6:	addl $0x20,%edx 		# To next entry
298		loop start.4			# Till done
299start.7:
300#ifdef BTXLDR_VERBOSE
301		movl $m_done,%esi		# Display done
302		call putstr			#  message
303#endif
304		movl $start.8,%esi		# Real mode stub
305		movl $BOOT0_ORIGIN,%edi		# Destination
306		movl $start.9-start.8,%ecx	# Size
307		rep				# Relocate
308		movsb				#  it
309		ljmp $SEL_RCODE,$BOOT0_ORIGIN	# To 16-bit code
310		.code16
311start.8:	xorw %ax,%ax			# Data
312		movb $SEL_RDATA,%al		#  selector
313		movw %ax,%ss			# Reload SS
314		movw %ax,%ds			# Reset
315		movw %ax,%es			#  other
316		movw %ax,%fs			#  segment
317		movw %ax,%gs			#  limits
318		movl %cr0,%eax			# Switch to
319		decw %ax			#  real
320		movl %eax,%cr0			#  mode
321		ljmp $0,$MEM_BTX_ENTRY		# Jump to BTX entry point
322start.9:
323		.code32
324/*
325 * Output message [ESI] followed by EAX in hex.
326 */
327hexout: 	pushl %eax			# Save
328		call putstr			# Display message
329		popl %eax			# Restore
330		pushl %esi			# Save
331		pushl %edi			# callers
332		movl $buf,%edi			# Buffer
333		pushl %edi			# Save
334		call hex32			# To hex
335		xorb %al,%al			# Terminate
336		stosb				#  string
337		popl %esi			# Restore
338hexout.1:	lodsb				# Get a char
339		cmpb $'0',%al			# Leading zero?
340		je hexout.1			# Yes
341		testb %al,%al			# End of string?
342		jne hexout.2			# No
343		decl %esi			# Undo
344hexout.2:	decl %esi			# Adjust for inc
345		call putstr			# Display hex
346		popl %edi			# Restore
347		popl %esi			# callers
348		ret				# To caller
349/*
350 * Output zero-terminated string [ESI] to the console.
351 */
352putstr.0:	call putchr			# Output char
353putstr: 	lodsb				# Load char
354		testb %al,%al			# End of string?
355		jne putstr.0			# No
356		ret				# To caller
357/*
358 * Output character AL to the console.
359 */
360putchr: 	pusha				# Save
361		xorl %ecx,%ecx			# Zero for loops
362		movb $SCR_MAT,%ah		# Mode/attribute
363		movl $BDA_POS,%ebx		# BDA pointer
364		movw (%ebx),%dx 		# Cursor position
365		movl $0xb8000,%edi		# Regen buffer (color)
366		cmpb %ah,BDA_SCR-BDA_POS(%ebx)	# Mono mode?
367		jne putchr.1			# No
368		xorw %di,%di			# Regen buffer (mono)
369putchr.1:	cmpb $0xa,%al			# New line?
370		je putchr.2			# Yes
371		xchgl %eax,%ecx 		# Save char
372		movb $SCR_COL,%al		# Columns per row
373		mulb %dh			#  * row position
374		addb %dl,%al			#  + column
375		adcb $0x0,%ah			#  position
376		shll %eax			#  * 2
377		xchgl %eax,%ecx 		# Swap char, offset
378		movw %ax,(%edi,%ecx,1)		# Write attr:char
379		incl %edx			# Bump cursor
380		cmpb $SCR_COL,%dl		# Beyond row?
381		jb putchr.3			# No
382putchr.2:	xorb %dl,%dl			# Zero column
383		incb %dh			# Bump row
384putchr.3:	cmpb $SCR_ROW,%dh		# Beyond screen?
385		jb putchr.4			# No
386		leal 2*SCR_COL(%edi),%esi	# New top line
387		movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
388		rep				# Scroll
389		movsl				#  screen
390		movb $' ',%al			# Space
391		movb $SCR_COL,%cl		# Columns to clear
392		rep				# Clear
393		stosw				#  line
394		movb $SCR_ROW-1,%dh		# Bottom line
395putchr.4:	movw %dx,(%ebx) 		# Update position
396		popa				# Restore
397		ret				# To caller
398/*
399 * Convert EAX, AX, or AL to hex, saving the result to [EDI].
400 */
401hex32:		pushl %eax			# Save
402		shrl $0x10,%eax 		# Do upper
403		call hex16			#  16
404		popl %eax			# Restore
405hex16:		call hex16.1			# Do upper 8
406hex16.1:	xchgb %ah,%al			# Save/restore
407hex8:		pushl %eax			# Save
408		shrb $0x4,%al			# Do upper
409		call hex8.1			#  4
410		popl %eax			# Restore
411hex8.1: 	andb $0xf,%al			# Get lower 4
412		cmpb $0xa,%al			# Convert
413		sbbb $0x69,%al			#  to hex
414		das				#  digit
415		orb $0x20,%al			# To lower case
416		stosb				# Save char
417		ret				# (Recursive)
418
419		.data
420		.p2align 4
421/*
422 * Global descriptor table.
423 */
424gdt:		.word 0x0,0x0,0x0,0x0		# Null entry
425		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE
426		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
427		.word 0xffff,0x0,0x9a00,0x0	# SEL_RCODE
428		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
429gdt.1:
430gdtdesc:	.word gdt.1-gdt-1		# Limit
431		.long gdt			# Base
432/*
433 * Messages.
434 */
435m_logo: 	.asciz " \nBTX loader 1.00  "
436m_vers: 	.asciz "BTX version is \0\n"
437e_fmt:		.asciz "Error: Client format not supported\n"
438#ifdef BTXLDR_VERBOSE
439m_mem:		.asciz "Starting in protected mode (base mem=\0)\n"
440m_esp:		.asciz "Arguments passed (esp=\0):\n"
441m_args: 	.asciz"<howto="
442		.asciz" bootdev="
443		.asciz" junk="
444		.asciz" "
445		.asciz" "
446		.asciz" bootinfo=\0>\n"
447m_rel_bi:	.asciz "Relocated bootinfo (size=48) to \0\n"
448m_rel_args:	.asciz "Relocated arguments (size=18) to \0\n"
449m_rel_btx:	.asciz "Relocated kernel (size=\0) to \0\n"
450m_base: 	.asciz "Client base address is \0\n"
451m_elf:		.asciz "Client format is ELF\n"
452m_segs: 	.asciz "text segment: offset="
453		.asciz " vaddr="
454		.asciz " filesz="
455		.asciz " memsz=\0\n"
456		.asciz "data segment: offset="
457		.asciz " vaddr="
458		.asciz " filesz="
459		.asciz " memsz=\0\n"
460m_done: 	.asciz "Loading complete\n"
461#endif
462/*
463 * Uninitialized data area.
464 */
465buf:						# Scratch buffer
466