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