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