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