1*ca987d46SWarner Losh/*- 2*ca987d46SWarner Losh * Copyright 2015 Toomas Soome <tsoome@me.com> 3*ca987d46SWarner Losh * All rights reserved. 4*ca987d46SWarner Losh * 5*ca987d46SWarner Losh * Redistribution and use in source and binary forms, with or without 6*ca987d46SWarner Losh * modification, are permitted provided that the following conditions 7*ca987d46SWarner Losh * are met: 8*ca987d46SWarner Losh * 1. Redistributions of source code must retain the above copyright 9*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer. 10*ca987d46SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 11*ca987d46SWarner Losh * notice, this list of conditions and the following disclaimer in the 12*ca987d46SWarner Losh * documentation and/or other materials provided with the distribution. 13*ca987d46SWarner Losh * 14*ca987d46SWarner Losh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*ca987d46SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*ca987d46SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*ca987d46SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*ca987d46SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*ca987d46SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*ca987d46SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*ca987d46SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*ca987d46SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*ca987d46SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*ca987d46SWarner Losh * SUCH DAMAGE. 25*ca987d46SWarner Losh */ 26*ca987d46SWarner Losh 27*ca987d46SWarner Losh 28*ca987d46SWarner Losh/* 29*ca987d46SWarner Losh * relocate is needed to support loading code which has to be located 30*ca987d46SWarner Losh * below 1MB, as both BTX and loader are using low memory area. 31*ca987d46SWarner Losh * 32*ca987d46SWarner Losh * relocate and start loaded code. Since loaded code may need to be 33*ca987d46SWarner Losh * placed to already occupied memory area, this code is moved to safe 34*ca987d46SWarner Losh * memory area and then btx __exec will be called with physical pointer 35*ca987d46SWarner Losh * to this area. __exec will set pointer to %eax and use call *%eax, 36*ca987d46SWarner Losh * so on entry, we have new "base" address in %eax. 37*ca987d46SWarner Losh * 38*ca987d46SWarner Losh * Relocate will first set up and load new safe GDT to shut down BTX, 39*ca987d46SWarner Losh * then loaded code will be relocated to final memory location, 40*ca987d46SWarner Losh * then machine will be switched from 32bit protected mode to 16bit 41*ca987d46SWarner Losh * protected mode following by switch to real mode with A20 enabled or 42*ca987d46SWarner Losh * disabled. Finally the loaded code will be started and it will take 43*ca987d46SWarner Losh * over the whole system. 44*ca987d46SWarner Losh * 45*ca987d46SWarner Losh * For now, the known "safe" memory area for relocate is 0x600, 46*ca987d46SWarner Losh * the actual "free" memory is supposed to start from 0x500, leaving 47*ca987d46SWarner Losh * first 0x100 bytes in reserve. As relocate code+data is very small, 48*ca987d46SWarner Losh * it will leave enough space to set up boot blocks to 0:7c00 or load 49*ca987d46SWarner Losh * linux kernel below 1MB space. 50*ca987d46SWarner Losh */ 51*ca987d46SWarner Losh/* 52*ca987d46SWarner Losh * segment selectors 53*ca987d46SWarner Losh */ 54*ca987d46SWarner Losh .set SEL_SCODE,0x8 55*ca987d46SWarner Losh .set SEL_SDATA,0x10 56*ca987d46SWarner Losh .set SEL_RCODE,0x18 57*ca987d46SWarner Losh .set SEL_RDATA,0x20 58*ca987d46SWarner Losh 59*ca987d46SWarner Losh .p2align 4 60*ca987d46SWarner Losh .globl relocater 61*ca987d46SWarner Loshrelocater: 62*ca987d46SWarner Losh cli 63*ca987d46SWarner Losh /* 64*ca987d46SWarner Losh * set up GDT from new location 65*ca987d46SWarner Losh */ 66*ca987d46SWarner Losh movl %eax, %esi /* our base address */ 67*ca987d46SWarner Losh add $(relocater.1-relocater), %eax 68*ca987d46SWarner Losh jmp *%eax 69*ca987d46SWarner Loshrelocater.1: 70*ca987d46SWarner Losh /* set up jump */ 71*ca987d46SWarner Losh lea (relocater.2-relocater)(%esi), %eax 72*ca987d46SWarner Losh movl %eax, (jump_vector-relocater) (%esi) 73*ca987d46SWarner Losh 74*ca987d46SWarner Losh /* set up gdt */ 75*ca987d46SWarner Losh lea (gdt-relocater) (%esi), %eax 76*ca987d46SWarner Losh movl %eax, (gdtaddr-relocater) (%esi) 77*ca987d46SWarner Losh 78*ca987d46SWarner Losh /* load gdt */ 79*ca987d46SWarner Losh lgdt (gdtdesc - relocater) (%esi) 80*ca987d46SWarner Losh lidt (idt-relocater) (%esi) 81*ca987d46SWarner Losh 82*ca987d46SWarner Losh /* update cs */ 83*ca987d46SWarner Losh ljmp *(jump_vector-relocater) (%esi) 84*ca987d46SWarner Losh 85*ca987d46SWarner Losh .code32 86*ca987d46SWarner Loshrelocater.2: 87*ca987d46SWarner Losh xorl %eax, %eax 88*ca987d46SWarner Losh movb $SEL_SDATA, %al 89*ca987d46SWarner Losh movw %ax, %ss 90*ca987d46SWarner Losh movw %ax, %ds 91*ca987d46SWarner Losh movw %ax, %es 92*ca987d46SWarner Losh movw %ax, %fs 93*ca987d46SWarner Losh movw %ax, %gs 94*ca987d46SWarner Losh movl %cr0, %eax /* disable paging */ 95*ca987d46SWarner Losh andl $~0x80000000,%eax 96*ca987d46SWarner Losh movl %eax, %cr0 97*ca987d46SWarner Losh xorl %ecx, %ecx /* flush TLB */ 98*ca987d46SWarner Losh movl %ecx, %cr3 99*ca987d46SWarner Losh cld 100*ca987d46SWarner Losh/* 101*ca987d46SWarner Losh * relocate data loop. load source, dest and size from 102*ca987d46SWarner Losh * relocater_data[i], 0 value will stop the loop. 103*ca987d46SWarner Losh * registers used for move: %esi, %edi, %ecx. 104*ca987d46SWarner Losh * %ebx to keep base 105*ca987d46SWarner Losh * %edx for relocater_data offset 106*ca987d46SWarner Losh */ 107*ca987d46SWarner Losh movl %esi, %ebx /* base address */ 108*ca987d46SWarner Losh xorl %edx, %edx 109*ca987d46SWarner Loshloop.1: 110*ca987d46SWarner Losh movl (relocater_data-relocater)(%ebx, %edx, 4), %eax 111*ca987d46SWarner Losh testl %eax, %eax 112*ca987d46SWarner Losh jz loop.2 113*ca987d46SWarner Losh movl (relocater_data-relocater)(%ebx, %edx, 4), %esi 114*ca987d46SWarner Losh inc %edx 115*ca987d46SWarner Losh movl (relocater_data-relocater)(%ebx, %edx, 4), %edi 116*ca987d46SWarner Losh inc %edx 117*ca987d46SWarner Losh movl (relocater_data-relocater)(%ebx, %edx, 4), %ecx 118*ca987d46SWarner Losh inc %edx 119*ca987d46SWarner Losh rep 120*ca987d46SWarner Losh movsb 121*ca987d46SWarner Losh jmp loop.1 122*ca987d46SWarner Loshloop.2: 123*ca987d46SWarner Losh movl %ebx, %esi /* restore esi */ 124*ca987d46SWarner Losh /* 125*ca987d46SWarner Losh * data is relocated, switch to 16bit mode 126*ca987d46SWarner Losh */ 127*ca987d46SWarner Losh lea (relocater.3-relocater)(%esi), %eax 128*ca987d46SWarner Losh movl %eax, (jump_vector-relocater) (%esi) 129*ca987d46SWarner Losh movl $SEL_RCODE, %eax 130*ca987d46SWarner Losh movl %eax, (jump_vector-relocater+4) (%esi) 131*ca987d46SWarner Losh 132*ca987d46SWarner Losh ljmp *(jump_vector-relocater) (%esi) 133*ca987d46SWarner Loshrelocater.3: 134*ca987d46SWarner Losh .code16 135*ca987d46SWarner Losh 136*ca987d46SWarner Losh movw $SEL_RDATA, %ax 137*ca987d46SWarner Losh movw %ax, %ds 138*ca987d46SWarner Losh movw %ax, %es 139*ca987d46SWarner Losh movw %ax, %fs 140*ca987d46SWarner Losh movw %ax, %gs 141*ca987d46SWarner Losh movw %ax, %ss 142*ca987d46SWarner Losh lidt (idt-relocater) (%esi) 143*ca987d46SWarner Losh lea (relocater.4-relocater)(%esi), %eax 144*ca987d46SWarner Losh movl %eax, (jump_vector-relocater) (%esi) 145*ca987d46SWarner Losh xorl %eax, %eax 146*ca987d46SWarner Losh movl %eax, (jump_vector-relocater+4) (%esi) 147*ca987d46SWarner Losh /* clear PE */ 148*ca987d46SWarner Losh movl %cr0, %eax 149*ca987d46SWarner Losh dec %al 150*ca987d46SWarner Losh movl %eax, %cr0 151*ca987d46SWarner Losh ljmp *(jump_vector-relocater) (%esi) 152*ca987d46SWarner Loshrelocater.4: 153*ca987d46SWarner Losh xorw %ax, %ax 154*ca987d46SWarner Losh movw %ax, %ds 155*ca987d46SWarner Losh movw %ax, %es 156*ca987d46SWarner Losh movw %ax, %fs 157*ca987d46SWarner Losh movw %ax, %gs 158*ca987d46SWarner Losh movw %ax, %ss 159*ca987d46SWarner Losh /* 160*ca987d46SWarner Losh * set real mode irq offsets 161*ca987d46SWarner Losh */ 162*ca987d46SWarner Losh movw $0x7008,%bx 163*ca987d46SWarner Losh in $0x21,%al # Save master 164*ca987d46SWarner Losh push %ax # IMR 165*ca987d46SWarner Losh in $0xa1,%al # Save slave 166*ca987d46SWarner Losh push %ax # IMR 167*ca987d46SWarner Losh movb $0x11,%al # ICW1 to 168*ca987d46SWarner Losh outb %al,$0x20 # master, 169*ca987d46SWarner Losh outb %al,$0xa0 # slave 170*ca987d46SWarner Losh movb %bl,%al # ICW2 to 171*ca987d46SWarner Losh outb %al,$0x21 # master 172*ca987d46SWarner Losh movb %bh,%al # ICW2 to 173*ca987d46SWarner Losh outb %al,$0xa1 # slave 174*ca987d46SWarner Losh movb $0x4,%al # ICW3 to 175*ca987d46SWarner Losh outb %al,$0x21 # master 176*ca987d46SWarner Losh movb $0x2,%al # ICW3 to 177*ca987d46SWarner Losh outb %al,$0xa1 # slave 178*ca987d46SWarner Losh movb $0x1,%al # ICW4 to 179*ca987d46SWarner Losh outb %al,$0x21 # master, 180*ca987d46SWarner Losh outb %al,$0xa1 # slave 181*ca987d46SWarner Losh pop %ax # Restore slave 182*ca987d46SWarner Losh outb %al,$0xa1 # IMR 183*ca987d46SWarner Losh pop %ax # Restore master 184*ca987d46SWarner Losh outb %al,$0x21 # IMR 185*ca987d46SWarner Losh # done 186*ca987d46SWarner Losh /* 187*ca987d46SWarner Losh * Should A20 be left enabled? 188*ca987d46SWarner Losh */ 189*ca987d46SWarner Losh /* movw imm16, %ax */ 190*ca987d46SWarner Losh .byte 0xb8 191*ca987d46SWarner Losh .globl relocator_a20_enabled 192*ca987d46SWarner Loshrelocator_a20_enabled: 193*ca987d46SWarner Losh .word 0 194*ca987d46SWarner Losh test %ax, %ax 195*ca987d46SWarner Losh jnz a20_done 196*ca987d46SWarner Losh 197*ca987d46SWarner Losh movw $0xa00, %ax 198*ca987d46SWarner Losh movw %ax, %sp 199*ca987d46SWarner Losh movw %ax, %bp 200*ca987d46SWarner Losh 201*ca987d46SWarner Losh /* Disable A20 */ 202*ca987d46SWarner Losh movw $0x2400, %ax 203*ca987d46SWarner Losh int $0x15 204*ca987d46SWarner Losh# jnc a20_done 205*ca987d46SWarner Losh 206*ca987d46SWarner Losh call a20_check_state 207*ca987d46SWarner Losh testb %al, %al 208*ca987d46SWarner Losh jz a20_done 209*ca987d46SWarner Losh 210*ca987d46SWarner Losh inb $0x92 211*ca987d46SWarner Losh andb $(~0x03), %al 212*ca987d46SWarner Losh outb $0x92 213*ca987d46SWarner Losh jmp a20_done 214*ca987d46SWarner Losh 215*ca987d46SWarner Losha20_check_state: 216*ca987d46SWarner Losh movw $100, %cx 217*ca987d46SWarner Losh1: 218*ca987d46SWarner Losh xorw %ax, %ax 219*ca987d46SWarner Losh movw %ax, %ds 220*ca987d46SWarner Losh decw %ax 221*ca987d46SWarner Losh movw %ax, %es 222*ca987d46SWarner Losh xorw %ax, %ax 223*ca987d46SWarner Losh movw $0x8000, %ax 224*ca987d46SWarner Losh movw %ax, %si 225*ca987d46SWarner Losh addw $0x10, %ax 226*ca987d46SWarner Losh movw %ax, %di 227*ca987d46SWarner Losh movb %ds:(%si), %dl 228*ca987d46SWarner Losh movb %es:(%di), %al 229*ca987d46SWarner Losh movb %al, %dh 230*ca987d46SWarner Losh decb %dh 231*ca987d46SWarner Losh movb %dh, %ds:(%si) 232*ca987d46SWarner Losh outb %al, $0x80 233*ca987d46SWarner Losh outb %al, $0x80 234*ca987d46SWarner Losh movb %es:(%di), %dh 235*ca987d46SWarner Losh subb %dh, %al 236*ca987d46SWarner Losh xorb $1, %al 237*ca987d46SWarner Losh movb %dl, %ds:(%si) 238*ca987d46SWarner Losh testb %al, %al 239*ca987d46SWarner Losh jz a20_done 240*ca987d46SWarner Losh loop 1b 241*ca987d46SWarner Losh ret 242*ca987d46SWarner Losha20_done: 243*ca987d46SWarner Losh /* 244*ca987d46SWarner Losh * set up registers 245*ca987d46SWarner Losh */ 246*ca987d46SWarner Losh /* movw imm16, %ax. */ 247*ca987d46SWarner Losh .byte 0xb8 248*ca987d46SWarner Losh .globl relocator_ds 249*ca987d46SWarner Loshrelocator_ds: .word 0 250*ca987d46SWarner Losh movw %ax, %ds 251*ca987d46SWarner Losh 252*ca987d46SWarner Losh /* movw imm16, %ax. */ 253*ca987d46SWarner Losh .byte 0xb8 254*ca987d46SWarner Losh .globl relocator_es 255*ca987d46SWarner Loshrelocator_es: .word 0 256*ca987d46SWarner Losh movw %ax, %es 257*ca987d46SWarner Losh 258*ca987d46SWarner Losh /* movw imm16, %ax. */ 259*ca987d46SWarner Losh .byte 0xb8 260*ca987d46SWarner Losh .globl relocator_fs 261*ca987d46SWarner Loshrelocator_fs: .word 0 262*ca987d46SWarner Losh movw %ax, %fs 263*ca987d46SWarner Losh 264*ca987d46SWarner Losh /* movw imm16, %ax. */ 265*ca987d46SWarner Losh .byte 0xb8 266*ca987d46SWarner Losh .globl relocator_gs 267*ca987d46SWarner Loshrelocator_gs: .word 0 268*ca987d46SWarner Losh movw %ax, %gs 269*ca987d46SWarner Losh 270*ca987d46SWarner Losh /* movw imm16, %ax. */ 271*ca987d46SWarner Losh .byte 0xb8 272*ca987d46SWarner Losh .globl relocator_ss 273*ca987d46SWarner Loshrelocator_ss: .word 0 274*ca987d46SWarner Losh movw %ax, %ss 275*ca987d46SWarner Losh 276*ca987d46SWarner Losh /* movw imm16, %ax. */ 277*ca987d46SWarner Losh .byte 0xb8 278*ca987d46SWarner Losh .globl relocator_sp 279*ca987d46SWarner Loshrelocator_sp: .word 0 280*ca987d46SWarner Losh movzwl %ax, %esp 281*ca987d46SWarner Losh 282*ca987d46SWarner Losh /* movw imm32, %eax. */ 283*ca987d46SWarner Losh .byte 0x66, 0xb8 284*ca987d46SWarner Losh .globl relocator_esi 285*ca987d46SWarner Loshrelocator_esi: .long 0 286*ca987d46SWarner Losh movl %eax, %esi 287*ca987d46SWarner Losh 288*ca987d46SWarner Losh /* movw imm32, %edx. */ 289*ca987d46SWarner Losh .byte 0x66, 0xba 290*ca987d46SWarner Losh .globl relocator_edx 291*ca987d46SWarner Loshrelocator_edx: .long 0 292*ca987d46SWarner Losh 293*ca987d46SWarner Losh /* movw imm32, %ebx. */ 294*ca987d46SWarner Losh .byte 0x66, 0xbb 295*ca987d46SWarner Losh .globl relocator_ebx 296*ca987d46SWarner Loshrelocator_ebx: .long 0 297*ca987d46SWarner Losh 298*ca987d46SWarner Losh /* movw imm32, %eax. */ 299*ca987d46SWarner Losh .byte 0x66, 0xb8 300*ca987d46SWarner Losh .globl relocator_eax 301*ca987d46SWarner Loshrelocator_eax: .long 0 302*ca987d46SWarner Losh 303*ca987d46SWarner Losh /* movw imm32, %ebp. */ 304*ca987d46SWarner Losh .byte 0x66, 0xbd 305*ca987d46SWarner Losh .globl relocator_ebp 306*ca987d46SWarner Loshrelocator_ebp: .long 0 307*ca987d46SWarner Losh 308*ca987d46SWarner Losh sti 309*ca987d46SWarner Losh .byte 0xea /* ljmp */ 310*ca987d46SWarner Losh .globl relocator_ip 311*ca987d46SWarner Loshrelocator_ip: 312*ca987d46SWarner Losh .word 0 313*ca987d46SWarner Losh .globl relocator_cs 314*ca987d46SWarner Loshrelocator_cs: 315*ca987d46SWarner Losh .word 0 316*ca987d46SWarner Losh 317*ca987d46SWarner Losh/* GDT to reset BTX */ 318*ca987d46SWarner Losh .code32 319*ca987d46SWarner Losh .p2align 4 320*ca987d46SWarner Loshjump_vector: .long 0 321*ca987d46SWarner Losh .long SEL_SCODE 322*ca987d46SWarner Losh 323*ca987d46SWarner Loshgdt: .word 0x0, 0x0 /* null entry */ 324*ca987d46SWarner Losh .byte 0x0, 0x0, 0x0, 0x0 325*ca987d46SWarner Losh .word 0xffff, 0x0 /* SEL_SCODE */ 326*ca987d46SWarner Losh .byte 0x0, 0x9a, 0xcf, 0x0 327*ca987d46SWarner Losh .word 0xffff, 0x0 /* SEL_SDATA */ 328*ca987d46SWarner Losh .byte 0x0, 0x92, 0xcf, 0x0 329*ca987d46SWarner Losh .word 0xffff, 0x0 /* SEL_RCODE */ 330*ca987d46SWarner Losh .byte 0x0, 0x9a, 0x0f, 0x0 331*ca987d46SWarner Losh .word 0xffff, 0x0 /* SEL_RDATA */ 332*ca987d46SWarner Losh .byte 0x0, 0x92, 0x0f, 0x0 333*ca987d46SWarner Loshgdt.1: 334*ca987d46SWarner Losh 335*ca987d46SWarner Loshgdtdesc: .word gdt.1 - gdt - 1 /* limit */ 336*ca987d46SWarner Loshgdtaddr: .long 0 /* base */ 337*ca987d46SWarner Losh 338*ca987d46SWarner Loshidt: .word 0x3ff 339*ca987d46SWarner Losh .long 0 340*ca987d46SWarner Losh 341*ca987d46SWarner Losh .globl relocater_data 342*ca987d46SWarner Loshrelocater_data: 343*ca987d46SWarner Losh .long 0 /* src */ 344*ca987d46SWarner Losh .long 0 /* dest */ 345*ca987d46SWarner Losh .long 0 /* size */ 346*ca987d46SWarner Losh .long 0 /* src */ 347*ca987d46SWarner Losh .long 0 /* dest */ 348*ca987d46SWarner Losh .long 0 /* size */ 349*ca987d46SWarner Losh .long 0 /* src */ 350*ca987d46SWarner Losh .long 0 /* dest */ 351*ca987d46SWarner Losh .long 0 /* size */ 352*ca987d46SWarner Losh .long 0 353*ca987d46SWarner Losh 354*ca987d46SWarner Losh .globl relocater_size 355*ca987d46SWarner Loshrelocater_size: 356*ca987d46SWarner Losh .long relocater_size-relocater 357