xref: /freebsd/stand/i386/libi386/relocater_tramp.S (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1*ca987d46SWarner Losh/*-
2*ca987d46SWarner Losh * Copyright 2015 Toomas Soome <tsoome@me.com>
3*ca987d46SWarner Losh * All rights reserved.
4*ca987d46SWarner Losh *
5*ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without
6*ca987d46SWarner Losh * modification, are permitted provided that the following conditions
7*ca987d46SWarner Losh * are met:
8*ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright
9*ca987d46SWarner Losh *    notice, this list of conditions and the following disclaimer.
10*ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright
11*ca987d46SWarner Losh *    notice, this list of conditions and the following disclaimer in the
12*ca987d46SWarner Losh *    documentation and/or other materials provided with the distribution.
13*ca987d46SWarner Losh *
14*ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*ca987d46SWarner Losh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*ca987d46SWarner Losh * SUCH DAMAGE.
25*ca987d46SWarner Losh */
26*ca987d46SWarner Losh
27*ca987d46SWarner Losh
28*ca987d46SWarner Losh/*
29*ca987d46SWarner Losh * relocate is needed to support loading code which has to be located
30*ca987d46SWarner Losh * below 1MB, as both BTX and loader are using low memory area.
31*ca987d46SWarner Losh *
32*ca987d46SWarner Losh * relocate and start loaded code. Since loaded code may need to be
33*ca987d46SWarner Losh * placed to already occupied memory area, this code is moved to safe
34*ca987d46SWarner Losh * memory area and then btx __exec will be called with physical pointer
35*ca987d46SWarner Losh * to this area. __exec will set pointer to %eax and use call *%eax,
36*ca987d46SWarner Losh * so on entry, we have new "base" address in %eax.
37*ca987d46SWarner Losh *
38*ca987d46SWarner Losh * Relocate will first set up and load new safe GDT to shut down BTX,
39*ca987d46SWarner Losh * then loaded code will be relocated to final memory location,
40*ca987d46SWarner Losh * then machine will be switched from 32bit protected mode to 16bit
41*ca987d46SWarner Losh * protected mode following by switch to real mode with A20 enabled or
42*ca987d46SWarner Losh * disabled. Finally the loaded code will be started and it will take
43*ca987d46SWarner Losh * over the whole system.
44*ca987d46SWarner Losh *
45*ca987d46SWarner Losh * For now, the known "safe" memory area for relocate is 0x600,
46*ca987d46SWarner Losh * the actual "free" memory is supposed to start from 0x500, leaving
47*ca987d46SWarner Losh * first 0x100 bytes in reserve. As relocate code+data is very small,
48*ca987d46SWarner Losh * it will leave enough space to set up boot blocks to 0:7c00 or load
49*ca987d46SWarner Losh * linux kernel below 1MB space.
50*ca987d46SWarner Losh */
51*ca987d46SWarner Losh/*
52*ca987d46SWarner Losh * segment selectors
53*ca987d46SWarner Losh */
54*ca987d46SWarner Losh		.set SEL_SCODE,0x8
55*ca987d46SWarner Losh		.set SEL_SDATA,0x10
56*ca987d46SWarner Losh		.set SEL_RCODE,0x18
57*ca987d46SWarner Losh		.set SEL_RDATA,0x20
58*ca987d46SWarner Losh
59*ca987d46SWarner Losh		.p2align	4
60*ca987d46SWarner Losh		.globl relocater
61*ca987d46SWarner Loshrelocater:
62*ca987d46SWarner Losh		cli
63*ca987d46SWarner Losh		/*
64*ca987d46SWarner Losh		 * set up GDT from new location
65*ca987d46SWarner Losh		 */
66*ca987d46SWarner Losh		movl	%eax, %esi		/* our base address */
67*ca987d46SWarner Losh		add	$(relocater.1-relocater), %eax
68*ca987d46SWarner Losh		jmp	*%eax
69*ca987d46SWarner Loshrelocater.1:
70*ca987d46SWarner Losh		/* set up jump */
71*ca987d46SWarner Losh		lea	(relocater.2-relocater)(%esi), %eax
72*ca987d46SWarner Losh		movl	%eax, (jump_vector-relocater) (%esi)
73*ca987d46SWarner Losh
74*ca987d46SWarner Losh		/* set up gdt */
75*ca987d46SWarner Losh		lea	(gdt-relocater) (%esi), %eax
76*ca987d46SWarner Losh		movl	%eax, (gdtaddr-relocater) (%esi)
77*ca987d46SWarner Losh
78*ca987d46SWarner Losh		/* load gdt */
79*ca987d46SWarner Losh		lgdt	(gdtdesc - relocater) (%esi)
80*ca987d46SWarner Losh		lidt	(idt-relocater) (%esi)
81*ca987d46SWarner Losh
82*ca987d46SWarner Losh		/* update cs */
83*ca987d46SWarner Losh		ljmp *(jump_vector-relocater) (%esi)
84*ca987d46SWarner Losh
85*ca987d46SWarner Losh		.code32
86*ca987d46SWarner Loshrelocater.2:
87*ca987d46SWarner Losh		xorl	%eax, %eax
88*ca987d46SWarner Losh		movb	$SEL_SDATA, %al
89*ca987d46SWarner Losh		movw	%ax, %ss
90*ca987d46SWarner Losh		movw	%ax, %ds
91*ca987d46SWarner Losh		movw	%ax, %es
92*ca987d46SWarner Losh		movw	%ax, %fs
93*ca987d46SWarner Losh		movw	%ax, %gs
94*ca987d46SWarner Losh		movl	%cr0, %eax		/* disable paging */
95*ca987d46SWarner Losh		andl	$~0x80000000,%eax
96*ca987d46SWarner Losh		movl	%eax, %cr0
97*ca987d46SWarner Losh		xorl	%ecx, %ecx		/* flush TLB */
98*ca987d46SWarner Losh		movl	%ecx, %cr3
99*ca987d46SWarner Losh		cld
100*ca987d46SWarner Losh/*
101*ca987d46SWarner Losh * relocate data loop. load source, dest and size from
102*ca987d46SWarner Losh * relocater_data[i], 0 value will stop the loop.
103*ca987d46SWarner Losh * registers used for move: %esi, %edi, %ecx.
104*ca987d46SWarner Losh * %ebx to keep base
105*ca987d46SWarner Losh * %edx for relocater_data offset
106*ca987d46SWarner Losh */
107*ca987d46SWarner Losh		movl	%esi, %ebx		/* base address */
108*ca987d46SWarner Losh		xorl	%edx, %edx
109*ca987d46SWarner Loshloop.1:
110*ca987d46SWarner Losh		movl	(relocater_data-relocater)(%ebx, %edx, 4), %eax
111*ca987d46SWarner Losh		testl	%eax, %eax
112*ca987d46SWarner Losh		jz	loop.2
113*ca987d46SWarner Losh		movl	(relocater_data-relocater)(%ebx, %edx, 4), %esi
114*ca987d46SWarner Losh		inc	%edx
115*ca987d46SWarner Losh		movl	(relocater_data-relocater)(%ebx, %edx, 4), %edi
116*ca987d46SWarner Losh		inc	%edx
117*ca987d46SWarner Losh		movl	(relocater_data-relocater)(%ebx, %edx, 4), %ecx
118*ca987d46SWarner Losh		inc	%edx
119*ca987d46SWarner Losh		rep
120*ca987d46SWarner Losh		movsb
121*ca987d46SWarner Losh		jmp	loop.1
122*ca987d46SWarner Loshloop.2:
123*ca987d46SWarner Losh		movl	%ebx, %esi		/* restore esi */
124*ca987d46SWarner Losh		/*
125*ca987d46SWarner Losh		 * data is relocated, switch to 16bit mode
126*ca987d46SWarner Losh		 */
127*ca987d46SWarner Losh		lea	(relocater.3-relocater)(%esi), %eax
128*ca987d46SWarner Losh		movl	%eax, (jump_vector-relocater) (%esi)
129*ca987d46SWarner Losh		movl	$SEL_RCODE, %eax
130*ca987d46SWarner Losh		movl	%eax, (jump_vector-relocater+4) (%esi)
131*ca987d46SWarner Losh
132*ca987d46SWarner Losh		ljmp *(jump_vector-relocater) (%esi)
133*ca987d46SWarner Loshrelocater.3:
134*ca987d46SWarner Losh		.code16
135*ca987d46SWarner Losh
136*ca987d46SWarner Losh		movw	$SEL_RDATA, %ax
137*ca987d46SWarner Losh		movw	%ax, %ds
138*ca987d46SWarner Losh		movw	%ax, %es
139*ca987d46SWarner Losh		movw	%ax, %fs
140*ca987d46SWarner Losh		movw	%ax, %gs
141*ca987d46SWarner Losh		movw	%ax, %ss
142*ca987d46SWarner Losh		lidt	(idt-relocater) (%esi)
143*ca987d46SWarner Losh		lea	(relocater.4-relocater)(%esi), %eax
144*ca987d46SWarner Losh		movl	%eax, (jump_vector-relocater) (%esi)
145*ca987d46SWarner Losh		xorl	%eax, %eax
146*ca987d46SWarner Losh		movl	%eax, (jump_vector-relocater+4) (%esi)
147*ca987d46SWarner Losh		/* clear PE */
148*ca987d46SWarner Losh		movl	%cr0, %eax
149*ca987d46SWarner Losh		dec	%al
150*ca987d46SWarner Losh		movl	%eax, %cr0
151*ca987d46SWarner Losh		ljmp *(jump_vector-relocater) (%esi)
152*ca987d46SWarner Loshrelocater.4:
153*ca987d46SWarner Losh		xorw	%ax, %ax
154*ca987d46SWarner Losh		movw	%ax, %ds
155*ca987d46SWarner Losh		movw	%ax, %es
156*ca987d46SWarner Losh		movw	%ax, %fs
157*ca987d46SWarner Losh		movw	%ax, %gs
158*ca987d46SWarner Losh		movw	%ax, %ss
159*ca987d46SWarner Losh		/*
160*ca987d46SWarner Losh		 * set real mode irq offsets
161*ca987d46SWarner Losh		 */
162*ca987d46SWarner Losh		movw	$0x7008,%bx
163*ca987d46SWarner Losh		in $0x21,%al			# Save master
164*ca987d46SWarner Losh		push %ax			#  IMR
165*ca987d46SWarner Losh		in $0xa1,%al			# Save slave
166*ca987d46SWarner Losh		push %ax			#  IMR
167*ca987d46SWarner Losh		movb $0x11,%al			# ICW1 to
168*ca987d46SWarner Losh		outb %al,$0x20			#  master,
169*ca987d46SWarner Losh		outb %al,$0xa0			#  slave
170*ca987d46SWarner Losh		movb %bl,%al			# ICW2 to
171*ca987d46SWarner Losh		outb %al,$0x21			#  master
172*ca987d46SWarner Losh		movb %bh,%al			# ICW2 to
173*ca987d46SWarner Losh		outb %al,$0xa1			#  slave
174*ca987d46SWarner Losh		movb $0x4,%al			# ICW3 to
175*ca987d46SWarner Losh		outb %al,$0x21			#  master
176*ca987d46SWarner Losh		movb $0x2,%al			# ICW3 to
177*ca987d46SWarner Losh		outb %al,$0xa1			#  slave
178*ca987d46SWarner Losh		movb $0x1,%al			# ICW4 to
179*ca987d46SWarner Losh		outb %al,$0x21			#  master,
180*ca987d46SWarner Losh		outb %al,$0xa1			#  slave
181*ca987d46SWarner Losh		pop %ax				# Restore slave
182*ca987d46SWarner Losh		outb %al,$0xa1			#  IMR
183*ca987d46SWarner Losh		pop %ax				# Restore master
184*ca987d46SWarner Losh		outb %al,$0x21			#  IMR
185*ca987d46SWarner Losh						# done
186*ca987d46SWarner Losh		/*
187*ca987d46SWarner Losh		 * Should A20 be left enabled?
188*ca987d46SWarner Losh		 */
189*ca987d46SWarner Losh		/* movw imm16, %ax */
190*ca987d46SWarner Losh		.byte	0xb8
191*ca987d46SWarner Losh		.globl	relocator_a20_enabled
192*ca987d46SWarner Loshrelocator_a20_enabled:
193*ca987d46SWarner Losh		.word	0
194*ca987d46SWarner Losh		test	%ax, %ax
195*ca987d46SWarner Losh		jnz	a20_done
196*ca987d46SWarner Losh
197*ca987d46SWarner Losh		movw	$0xa00, %ax
198*ca987d46SWarner Losh		movw	%ax, %sp
199*ca987d46SWarner Losh		movw	%ax, %bp
200*ca987d46SWarner Losh
201*ca987d46SWarner Losh		/* Disable A20 */
202*ca987d46SWarner Losh		movw	$0x2400, %ax
203*ca987d46SWarner Losh		int	$0x15
204*ca987d46SWarner Losh#		jnc	a20_done
205*ca987d46SWarner Losh
206*ca987d46SWarner Losh		call	a20_check_state
207*ca987d46SWarner Losh		testb	%al, %al
208*ca987d46SWarner Losh		jz	a20_done
209*ca987d46SWarner Losh
210*ca987d46SWarner Losh		inb	$0x92
211*ca987d46SWarner Losh		andb	$(~0x03), %al
212*ca987d46SWarner Losh		outb	$0x92
213*ca987d46SWarner Losh		jmp	a20_done
214*ca987d46SWarner Losh
215*ca987d46SWarner Losha20_check_state:
216*ca987d46SWarner Losh		movw	$100, %cx
217*ca987d46SWarner Losh1:
218*ca987d46SWarner Losh		xorw	%ax, %ax
219*ca987d46SWarner Losh		movw	%ax, %ds
220*ca987d46SWarner Losh		decw	%ax
221*ca987d46SWarner Losh		movw	%ax, %es
222*ca987d46SWarner Losh		xorw	%ax, %ax
223*ca987d46SWarner Losh		movw	$0x8000, %ax
224*ca987d46SWarner Losh		movw	%ax, %si
225*ca987d46SWarner Losh		addw	$0x10, %ax
226*ca987d46SWarner Losh		movw	%ax, %di
227*ca987d46SWarner Losh		movb	%ds:(%si), %dl
228*ca987d46SWarner Losh		movb	%es:(%di), %al
229*ca987d46SWarner Losh		movb	%al, %dh
230*ca987d46SWarner Losh		decb	%dh
231*ca987d46SWarner Losh		movb	%dh, %ds:(%si)
232*ca987d46SWarner Losh		outb	%al, $0x80
233*ca987d46SWarner Losh		outb	%al, $0x80
234*ca987d46SWarner Losh		movb	%es:(%di), %dh
235*ca987d46SWarner Losh		subb	%dh, %al
236*ca987d46SWarner Losh		xorb	$1, %al
237*ca987d46SWarner Losh		movb	%dl, %ds:(%si)
238*ca987d46SWarner Losh		testb	%al, %al
239*ca987d46SWarner Losh		jz	a20_done
240*ca987d46SWarner Losh		loop	1b
241*ca987d46SWarner Losh		ret
242*ca987d46SWarner Losha20_done:
243*ca987d46SWarner Losh		/*
244*ca987d46SWarner Losh		 * set up registers
245*ca987d46SWarner Losh		 */
246*ca987d46SWarner Losh		/* movw imm16, %ax. */
247*ca987d46SWarner Losh		.byte	0xb8
248*ca987d46SWarner Losh		.globl	relocator_ds
249*ca987d46SWarner Loshrelocator_ds:	.word	0
250*ca987d46SWarner Losh		movw	%ax, %ds
251*ca987d46SWarner Losh
252*ca987d46SWarner Losh		/* movw imm16, %ax. */
253*ca987d46SWarner Losh		.byte	0xb8
254*ca987d46SWarner Losh		.globl	relocator_es
255*ca987d46SWarner Loshrelocator_es:	.word	0
256*ca987d46SWarner Losh		movw	%ax, %es
257*ca987d46SWarner Losh
258*ca987d46SWarner Losh		/* movw imm16, %ax. */
259*ca987d46SWarner Losh		.byte	0xb8
260*ca987d46SWarner Losh		.globl	relocator_fs
261*ca987d46SWarner Loshrelocator_fs:	.word	0
262*ca987d46SWarner Losh		movw	%ax, %fs
263*ca987d46SWarner Losh
264*ca987d46SWarner Losh		/* movw imm16, %ax. */
265*ca987d46SWarner Losh		.byte	0xb8
266*ca987d46SWarner Losh		.globl	relocator_gs
267*ca987d46SWarner Loshrelocator_gs:	.word	0
268*ca987d46SWarner Losh		movw	%ax, %gs
269*ca987d46SWarner Losh
270*ca987d46SWarner Losh		/* movw imm16, %ax. */
271*ca987d46SWarner Losh		.byte	0xb8
272*ca987d46SWarner Losh		.globl	relocator_ss
273*ca987d46SWarner Loshrelocator_ss:	.word	0
274*ca987d46SWarner Losh		movw	%ax, %ss
275*ca987d46SWarner Losh
276*ca987d46SWarner Losh		/* movw imm16, %ax. */
277*ca987d46SWarner Losh		.byte	0xb8
278*ca987d46SWarner Losh		.globl	relocator_sp
279*ca987d46SWarner Loshrelocator_sp:	.word	0
280*ca987d46SWarner Losh		movzwl	%ax, %esp
281*ca987d46SWarner Losh
282*ca987d46SWarner Losh		/* movw imm32, %eax. */
283*ca987d46SWarner Losh		.byte	0x66, 0xb8
284*ca987d46SWarner Losh		.globl	relocator_esi
285*ca987d46SWarner Loshrelocator_esi:	.long	0
286*ca987d46SWarner Losh		movl	%eax, %esi
287*ca987d46SWarner Losh
288*ca987d46SWarner Losh		/* movw imm32, %edx. */
289*ca987d46SWarner Losh		.byte	0x66, 0xba
290*ca987d46SWarner Losh		.globl	relocator_edx
291*ca987d46SWarner Loshrelocator_edx:	.long	0
292*ca987d46SWarner Losh
293*ca987d46SWarner Losh		/* movw imm32, %ebx. */
294*ca987d46SWarner Losh		.byte	0x66, 0xbb
295*ca987d46SWarner Losh		.globl	relocator_ebx
296*ca987d46SWarner Loshrelocator_ebx:	.long	0
297*ca987d46SWarner Losh
298*ca987d46SWarner Losh		/* movw imm32, %eax. */
299*ca987d46SWarner Losh		.byte	0x66, 0xb8
300*ca987d46SWarner Losh		.globl	relocator_eax
301*ca987d46SWarner Loshrelocator_eax:	.long	0
302*ca987d46SWarner Losh
303*ca987d46SWarner Losh		/* movw imm32, %ebp. */
304*ca987d46SWarner Losh		.byte	0x66, 0xbd
305*ca987d46SWarner Losh		.globl	relocator_ebp
306*ca987d46SWarner Loshrelocator_ebp:	.long	0
307*ca987d46SWarner Losh
308*ca987d46SWarner Losh		sti
309*ca987d46SWarner Losh		.byte 0xea			 /* ljmp */
310*ca987d46SWarner Losh		.globl relocator_ip
311*ca987d46SWarner Loshrelocator_ip:
312*ca987d46SWarner Losh		.word 0
313*ca987d46SWarner Losh		.globl relocator_cs
314*ca987d46SWarner Loshrelocator_cs:
315*ca987d46SWarner Losh		.word 0
316*ca987d46SWarner Losh
317*ca987d46SWarner Losh/* GDT to reset BTX */
318*ca987d46SWarner Losh		.code32
319*ca987d46SWarner Losh		.p2align	4
320*ca987d46SWarner Loshjump_vector:	.long	0
321*ca987d46SWarner Losh		.long	SEL_SCODE
322*ca987d46SWarner Losh
323*ca987d46SWarner Loshgdt:		.word 0x0, 0x0			/* null entry */
324*ca987d46SWarner Losh		.byte 0x0, 0x0, 0x0, 0x0
325*ca987d46SWarner Losh		.word 0xffff, 0x0		/* SEL_SCODE */
326*ca987d46SWarner Losh		.byte 0x0, 0x9a, 0xcf, 0x0
327*ca987d46SWarner Losh		.word 0xffff, 0x0		/* SEL_SDATA */
328*ca987d46SWarner Losh		.byte 0x0, 0x92, 0xcf, 0x0
329*ca987d46SWarner Losh		.word 0xffff, 0x0		/* SEL_RCODE */
330*ca987d46SWarner Losh		.byte 0x0, 0x9a, 0x0f, 0x0
331*ca987d46SWarner Losh		.word 0xffff, 0x0		/* SEL_RDATA */
332*ca987d46SWarner Losh		.byte 0x0, 0x92, 0x0f, 0x0
333*ca987d46SWarner Loshgdt.1:
334*ca987d46SWarner Losh
335*ca987d46SWarner Loshgdtdesc:	.word gdt.1 - gdt - 1		/* limit */
336*ca987d46SWarner Loshgdtaddr:	.long 0				/* base */
337*ca987d46SWarner Losh
338*ca987d46SWarner Loshidt:		.word 0x3ff
339*ca987d46SWarner Losh		.long 0
340*ca987d46SWarner Losh
341*ca987d46SWarner Losh		.globl relocater_data
342*ca987d46SWarner Loshrelocater_data:
343*ca987d46SWarner Losh		.long 0			/* src */
344*ca987d46SWarner Losh		.long 0			/* dest */
345*ca987d46SWarner Losh		.long 0			/* size */
346*ca987d46SWarner Losh		.long 0			/* src */
347*ca987d46SWarner Losh		.long 0			/* dest */
348*ca987d46SWarner Losh		.long 0			/* size */
349*ca987d46SWarner Losh		.long 0			/* src */
350*ca987d46SWarner Losh		.long 0			/* dest */
351*ca987d46SWarner Losh		.long 0			/* size */
352*ca987d46SWarner Losh		.long 0
353*ca987d46SWarner Losh
354*ca987d46SWarner Losh		.globl relocater_size
355*ca987d46SWarner Loshrelocater_size:
356*ca987d46SWarner Losh		.long relocater_size-relocater
357