aboutsummaryrefslogtreecommitdiff
path: root/stand/i386/libi386/relocater_tramp.S
blob: 6db4a7509b2cdbfa54722496008e66cdaade4e09 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/*-
 * Copyright 2015 Toomas Soome <tsoome@me.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */


/*
 * relocate is needed to support loading code which has to be located
 * below 1MB, as both BTX and loader are using low memory area.
 *
 * relocate and start loaded code. Since loaded code may need to be
 * placed to already occupied memory area, this code is moved to safe
 * memory area and then btx __exec will be called with physical pointer
 * to this area. __exec will set pointer to %eax and use call *%eax,
 * so on entry, we have new "base" address in %eax.
 *
 * Relocate will first set up and load new safe GDT to shut down BTX,
 * then loaded code will be relocated to final memory location,
 * then machine will be switched from 32bit protected mode to 16bit
 * protected mode following by switch to real mode with A20 enabled or
 * disabled. Finally the loaded code will be started and it will take
 * over the whole system.
 *
 * For now, the known "safe" memory area for relocate is 0x600,
 * the actual "free" memory is supposed to start from 0x500, leaving
 * first 0x100 bytes in reserve. As relocate code+data is very small,
 * it will leave enough space to set up boot blocks to 0:7c00 or load
 * linux kernel below 1MB space.
 */
/*
 * segment selectors
 */
		.set SEL_SCODE,0x8
		.set SEL_SDATA,0x10
		.set SEL_RCODE,0x18
		.set SEL_RDATA,0x20

		.p2align	4
		.globl relocater
relocater:
		cli
		/*
		 * set up GDT from new location
		 */
		movl	%eax, %esi		/* our base address */
		add	$(relocater.1-relocater), %eax
		jmp	*%eax
relocater.1:
		/* set up jump */
		lea	(relocater.2-relocater)(%esi), %eax
		movl	%eax, (jump_vector-relocater) (%esi)

		/* set up gdt */
		lea	(gdt-relocater) (%esi), %eax
		movl	%eax, (gdtaddr-relocater) (%esi)

		/* load gdt */
		lgdt	(gdtdesc - relocater) (%esi)
		lidt	(idt-relocater) (%esi)

		/* update cs */
		ljmp *(jump_vector-relocater) (%esi)

		.code32
relocater.2:
		xorl	%eax, %eax
		movb	$SEL_SDATA, %al
		movw	%ax, %ss
		movw	%ax, %ds
		movw	%ax, %es
		movw	%ax, %fs
		movw	%ax, %gs
		movl	%cr0, %eax		/* disable paging */
		andl	$~0x80000000,%eax
		movl	%eax, %cr0
		xorl	%ecx, %ecx		/* flush TLB */
		movl	%ecx, %cr3
		cld
/*
 * relocate data loop. load source, dest and size from
 * relocater_data[i], 0 value will stop the loop.
 * registers used for move: %esi, %edi, %ecx.
 * %ebx to keep base
 * %edx for relocater_data offset
 */
		movl	%esi, %ebx		/* base address */
		xorl	%edx, %edx
loop.1:
		movl	(relocater_data-relocater)(%ebx, %edx, 4), %eax
		testl	%eax, %eax
		jz	loop.2
		movl	(relocater_data-relocater)(%ebx, %edx, 4), %esi
		inc	%edx
		movl	(relocater_data-relocater)(%ebx, %edx, 4), %edi
		inc	%edx
		movl	(relocater_data-relocater)(%ebx, %edx, 4), %ecx
		inc	%edx
		rep
		movsb
		jmp	loop.1
loop.2:
		movl	%ebx, %esi		/* restore esi */
		/*
		 * data is relocated, switch to 16bit mode
		 */
		lea	(relocater.3-relocater)(%esi), %eax
		movl	%eax, (jump_vector-relocater) (%esi)
		movl	$SEL_RCODE, %eax
		movl	%eax, (jump_vector-relocater+4) (%esi)

		ljmp *(jump_vector-relocater) (%esi)
relocater.3:
		.code16

		movw	$SEL_RDATA, %ax
		movw	%ax, %ds
		movw	%ax, %es
		movw	%ax, %fs
		movw	%ax, %gs
		movw	%ax, %ss
		lidt	(idt-relocater) (%esi)
		lea	(relocater.4-relocater)(%esi), %eax
		movl	%eax, (jump_vector-relocater) (%esi)
		xorl	%eax, %eax
		movl	%eax, (jump_vector-relocater+4) (%esi)
		/* clear PE */
		movl	%cr0, %eax
		dec	%al
		movl	%eax, %cr0
		ljmp *(jump_vector-relocater) (%esi)
relocater.4:
		xorw	%ax, %ax
		movw	%ax, %ds
		movw	%ax, %es
		movw	%ax, %fs
		movw	%ax, %gs
		movw	%ax, %ss
		/*
		 * set real mode irq offsets
		 */
		movw	$0x7008,%bx
		in $0x21,%al			# Save master
		push %ax			#  IMR
		in $0xa1,%al			# Save slave
		push %ax			#  IMR
		movb $0x11,%al			# ICW1 to
		outb %al,$0x20			#  master,
		outb %al,$0xa0			#  slave
		movb %bl,%al			# ICW2 to
		outb %al,$0x21			#  master
		movb %bh,%al			# ICW2 to
		outb %al,$0xa1			#  slave
		movb $0x4,%al			# ICW3 to
		outb %al,$0x21			#  master
		movb $0x2,%al			# ICW3 to
		outb %al,$0xa1			#  slave
		movb $0x1,%al			# ICW4 to
		outb %al,$0x21			#  master,
		outb %al,$0xa1			#  slave
		pop %ax				# Restore slave
		outb %al,$0xa1			#  IMR
		pop %ax				# Restore master
		outb %al,$0x21			#  IMR
						# done
		/*
		 * Should A20 be left enabled?
		 */
		/* movw imm16, %ax */
		.byte	0xb8
		.globl	relocator_a20_enabled
relocator_a20_enabled:
		.word	0
		test	%ax, %ax
		jnz	a20_done

		movw	$0xa00, %ax
		movw	%ax, %sp
		movw	%ax, %bp

		/* Disable A20 */
		movw	$0x2400, %ax
		int	$0x15
#		jnc	a20_done

		call	a20_check_state
		testb	%al, %al
		jz	a20_done

		inb	$0x92
		andb	$(~0x03), %al
		outb	$0x92
		jmp	a20_done

a20_check_state:
		movw	$100, %cx
1:
		xorw	%ax, %ax
		movw	%ax, %ds
		decw	%ax
		movw	%ax, %es
		xorw	%ax, %ax
		movw	$0x8000, %ax
		movw	%ax, %si
		addw	$0x10, %ax
		movw	%ax, %di
		movb	%ds:(%si), %dl
		movb	%es:(%di), %al
		movb	%al, %dh
		decb	%dh
		movb	%dh, %ds:(%si)
		outb	%al, $0x80
		outb	%al, $0x80
		movb	%es:(%di), %dh
		subb	%dh, %al
		xorb	$1, %al
		movb	%dl, %ds:(%si)
		testb	%al, %al
		jz	a20_done
		loop	1b
		ret
a20_done:
		/*
		 * set up registers
		 */
		/* movw imm16, %ax. */
		.byte	0xb8
		.globl	relocator_ds
relocator_ds:	.word	0
		movw	%ax, %ds

		/* movw imm16, %ax. */
		.byte	0xb8
		.globl	relocator_es
relocator_es:	.word	0
		movw	%ax, %es

		/* movw imm16, %ax. */
		.byte	0xb8
		.globl	relocator_fs
relocator_fs:	.word	0
		movw	%ax, %fs

		/* movw imm16, %ax. */
		.byte	0xb8
		.globl	relocator_gs
relocator_gs:	.word	0
		movw	%ax, %gs

		/* movw imm16, %ax. */
		.byte	0xb8
		.globl	relocator_ss
relocator_ss:	.word	0
		movw	%ax, %ss

		/* movw imm16, %ax. */
		.byte	0xb8
		.globl	relocator_sp
relocator_sp:	.word	0
		movzwl	%ax, %esp

		/* movw imm32, %eax. */
		.byte	0x66, 0xb8
		.globl	relocator_esi
relocator_esi:	.long	0
		movl	%eax, %esi

		/* movw imm32, %edx. */
		.byte	0x66, 0xba
		.globl	relocator_edx
relocator_edx:	.long	0

		/* movw imm32, %ebx. */
		.byte	0x66, 0xbb
		.globl	relocator_ebx
relocator_ebx:	.long	0

		/* movw imm32, %eax. */
		.byte	0x66, 0xb8
		.globl	relocator_eax
relocator_eax:	.long	0

		/* movw imm32, %ebp. */
		.byte	0x66, 0xbd
		.globl	relocator_ebp
relocator_ebp:	.long	0

		sti
		.byte 0xea			 /* ljmp */
		.globl relocator_ip
relocator_ip:
		.word 0
		.globl relocator_cs
relocator_cs:
		.word 0

/* GDT to reset BTX */
		.code32
		.p2align	4
jump_vector:	.long	0
		.long	SEL_SCODE

gdt:		.word 0x0, 0x0			/* null entry */
		.byte 0x0, 0x0, 0x0, 0x0
		.word 0xffff, 0x0		/* SEL_SCODE */
		.byte 0x0, 0x9a, 0xcf, 0x0
		.word 0xffff, 0x0		/* SEL_SDATA */
		.byte 0x0, 0x92, 0xcf, 0x0
		.word 0xffff, 0x0		/* SEL_RCODE */
		.byte 0x0, 0x9a, 0x0f, 0x0
		.word 0xffff, 0x0		/* SEL_RDATA */
		.byte 0x0, 0x92, 0x0f, 0x0
gdt.1:

gdtdesc:	.word gdt.1 - gdt - 1		/* limit */
gdtaddr:	.long 0				/* base */

idt:		.word 0x3ff
		.long 0

		.globl relocater_data
relocater_data:
		.long 0			/* src */
		.long 0			/* dest */
		.long 0			/* size */
		.long 0			/* src */
		.long 0			/* dest */
		.long 0			/* size */
		.long 0			/* src */
		.long 0			/* dest */
		.long 0			/* size */
		.long 0

		.globl relocater_size
relocater_size:
		.long relocater_size-relocater