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 */ 11/* 12 * Copyright 2016 Toomas Soome <tsoome@me.com> 13 */ 14 15/* 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 */ 38/* 39 * segment selectors 40 */ 41 .set SEL_SCODE,0x8 42 .set SEL_SDATA,0x10 43 .set SEL_RCODE,0x18 44 .set SEL_RDATA,0x20 45 46 .p2align 4 47 .globl relocater 48relocater: 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 56relocater.1: 57 /* set up jump */ 58 lea (relocater.2-relocater)(%esi), %eax 59 movl %eax, (jump_vector-relocater) (%esi) 60 61 /* set up gdt */ 62 lea (gdt-relocater) (%esi), %eax 63 movl %eax, (gdtaddr-relocater) (%esi) 64 65 /* load gdt */ 66 lgdt (gdtdesc - relocater) (%esi) 67 lidt (idt-relocater) (%esi) 68 69 /* update cs */ 70 ljmp *(jump_vector-relocater) (%esi) 71 72 .code32 73relocater.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 87/* 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 96loop.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 109loop.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) 118 119 ljmp *(jump_vector-relocater) (%esi) 120relocater.3: 121 .code16 122 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) 139relocater.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 179relocator_a20_enabled: 180 .word 0 181 test %ax, %ax 182 jnz a20_done 183 184 movw $0xa00, %ax 185 movw %ax, %sp 186 movw %ax, %bp 187 188 /* Disable A20 */ 189 movw $0x2400, %ax 190 int $0x15 191# jnc a20_done 192 193 call a20_check_state 194 testb %al, %al 195 jz a20_done 196 197 inb $0x92 198 andb $(~0x03), %al 199 outb $0x92 200 jmp a20_done 201 202a20_check_state: 203 movw $100, %cx 2041: 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 229a20_done: 230 /* 231 * set up registers 232 */ 233 /* movw imm16, %ax. */ 234 .byte 0xb8 235 .globl relocator_ds 236relocator_ds: .word 0 237 movw %ax, %ds 238 239 /* movw imm16, %ax. */ 240 .byte 0xb8 241 .globl relocator_es 242relocator_es: .word 0 243 movw %ax, %es 244 245 /* movw imm16, %ax. */ 246 .byte 0xb8 247 .globl relocator_fs 248relocator_fs: .word 0 249 movw %ax, %fs 250 251 /* movw imm16, %ax. */ 252 .byte 0xb8 253 .globl relocator_gs 254relocator_gs: .word 0 255 movw %ax, %gs 256 257 /* movw imm16, %ax. */ 258 .byte 0xb8 259 .globl relocator_ss 260relocator_ss: .word 0 261 movw %ax, %ss 262 263 /* movw imm16, %ax. */ 264 .byte 0xb8 265 .globl relocator_sp 266relocator_sp: .word 0 267 movzwl %ax, %esp 268 269 /* movw imm32, %eax. */ 270 .byte 0x66, 0xb8 271 .globl relocator_esi 272relocator_esi: .long 0 273 movl %eax, %esi 274 275 /* movw imm32, %edx. */ 276 .byte 0x66, 0xba 277 .globl relocator_edx 278relocator_edx: .long 0 279 280 /* movw imm32, %ebx. */ 281 .byte 0x66, 0xbb 282 .globl relocator_ebx 283relocator_ebx: .long 0 284 285 /* movw imm32, %eax. */ 286 .byte 0x66, 0xb8 287 .globl relocator_eax 288relocator_eax: .long 0 289 290 /* movw imm32, %ebp. */ 291 .byte 0x66, 0xbd 292 .globl relocator_ebp 293relocator_ebp: .long 0 294 295 sti 296 .byte 0xea /* ljmp */ 297 .globl relocator_ip 298relocator_ip: 299 .word 0 300 .globl relocator_cs 301relocator_cs: 302 .word 0 303 304/* GDT to reset BTX */ 305 .code32 306 .p2align 4 307jump_vector: .long 0 308 .long SEL_SCODE 309 310gdt: .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 320gdt.1: 321 322gdtdesc: .word gdt.1 - gdt - 1 /* limit */ 323gdtaddr: .long 0 /* base */ 324 325idt: .word 0x3ff 326 .long 0 327 328 .globl relocater_data 329 330/* reserve space for 3 entries */ 331relocater_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 342 343 .globl relocater_size 344relocater_size: 345 .long relocater_size-relocater 346