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