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