btxldr.S revision 128716
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 128716 2004-04-28 14:31:44Z ru $
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/*
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
72#ifdef BTXLDR_VERBOSE
73		movl $m_mem,%esi		// Display
74		call hexout			//  amount of
75		call putstr			//  base memory
76#endif
77		lgdt gdtdesc			// Load new GDT
78/*
79 * Relocate caller's arguments.
80 */
81#ifdef 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#endif
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
104#ifdef BTXLDR_VERBOSE
105		movl $m_rel_bi,%esi		// Display
106		movl %ebp,%eax			//  bootinfo
107		call hexout			//  relocation
108		call putstr			//  message
109#endif
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
116#ifdef BTXLDR_VERBOSE
117		movl $m_rel_args,%esi		// Display
118		movl %ebp,%eax			//  argument
119		call hexout			//  relocation
120		call putstr			//  message
121#endif
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
152#ifdef BTXLDR_VERBOSE
153		pushl %ecx			// Save image size
154#endif
155		rep				// Relocate
156		movsb				//  BTX
157		movl %esi,%ebx			// Keep place
158#ifdef BTXLDR_VERBOSE
159		movl $m_rel_btx,%esi		// Restore
160		popl %eax			//  parameters
161		call hexout			//  and
162#endif
163		popl %ebp			//  display
164#ifdef BTXLDR_VERBOSE
165		movl %ebp,%eax			//  the
166		call hexout			//  relocation
167		call putstr			//  message
168#endif
169		addl $PAG_SIZ,%ebp		// Display
170#ifdef BTXLDR_VERBOSE
171		movl $m_base,%esi		//  the
172		movl %ebp,%eax			//  user
173		call hexout			//  base
174		call putstr			//  address
175#endif
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:
185#ifdef BTXLDR_VERBOSE
186		movl $m_elf,%esi		// Display ELF
187		call putstr			//  message
188		movl $m_segs,%esi		// Format string
189#endif
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
196#ifdef 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#endif
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:
231#ifdef BTXLDR_VERBOSE
232		movl $m_done,%esi		// Display done
233		call putstr			//  message
234#endif
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"
369#ifdef 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#endif
393/*
394 * Uninitialized data area.
395 */
396buf:						// Scratch buffer
397