aboutsummaryrefslogtreecommitdiff
path: root/stand/i386/libi386/relocater_tramp.S
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
committerWarner Losh <imp@FreeBSD.org>2017-11-14 23:02:19 +0000
commitca987d4641cdcd7f27e153db17c5bf064934faf5 (patch)
tree6c3860e3ba8949be9528d644fbb7fa88d8bbbb79 /stand/i386/libi386/relocater_tramp.S
parent6eac7115560381ce5c9e2939ab3fce82bb9b6a95 (diff)
downloadsrc-ca987d4641cdcd7f27e153db17c5bf064934faf5.tar.gz
src-ca987d4641cdcd7f27e153db17c5bf064934faf5.zip
Move sys/boot to stand. Fix all references to new location
Sponsored by: Netflix
Notes
Notes: svn path=/head/; revision=325834
Diffstat (limited to 'stand/i386/libi386/relocater_tramp.S')
-rw-r--r--stand/i386/libi386/relocater_tramp.S358
1 files changed, 358 insertions, 0 deletions
diff --git a/stand/i386/libi386/relocater_tramp.S b/stand/i386/libi386/relocater_tramp.S
new file mode 100644
index 000000000000..6db4a7509b2c
--- /dev/null
+++ b/stand/i386/libi386/relocater_tramp.S
@@ -0,0 +1,358 @@
+/*-
+ * Copyright 2015 Toomas Soome <tsoome@me.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+
+/*
+ * relocate is needed to support loading code which has to be located
+ * below 1MB, as both BTX and loader are using low memory area.
+ *
+ * relocate and start loaded code. Since loaded code may need to be
+ * placed to already occupied memory area, this code is moved to safe
+ * memory area and then btx __exec will be called with physical pointer
+ * to this area. __exec will set pointer to %eax and use call *%eax,
+ * so on entry, we have new "base" address in %eax.
+ *
+ * Relocate will first set up and load new safe GDT to shut down BTX,
+ * then loaded code will be relocated to final memory location,
+ * then machine will be switched from 32bit protected mode to 16bit
+ * protected mode following by switch to real mode with A20 enabled or
+ * disabled. Finally the loaded code will be started and it will take
+ * over the whole system.
+ *
+ * For now, the known "safe" memory area for relocate is 0x600,
+ * the actual "free" memory is supposed to start from 0x500, leaving
+ * first 0x100 bytes in reserve. As relocate code+data is very small,
+ * it will leave enough space to set up boot blocks to 0:7c00 or load
+ * linux kernel below 1MB space.
+ */
+/*
+ * segment selectors
+ */
+ .set SEL_SCODE,0x8
+ .set SEL_SDATA,0x10
+ .set SEL_RCODE,0x18
+ .set SEL_RDATA,0x20
+
+ .p2align 4
+ .globl relocater
+relocater:
+ cli
+ /*
+ * set up GDT from new location
+ */
+ movl %eax, %esi /* our base address */
+ add $(relocater.1-relocater), %eax
+ jmp *%eax
+relocater.1:
+ /* set up jump */
+ lea (relocater.2-relocater)(%esi), %eax
+ movl %eax, (jump_vector-relocater) (%esi)
+
+ /* set up gdt */
+ lea (gdt-relocater) (%esi), %eax
+ movl %eax, (gdtaddr-relocater) (%esi)
+
+ /* load gdt */
+ lgdt (gdtdesc - relocater) (%esi)
+ lidt (idt-relocater) (%esi)
+
+ /* update cs */
+ ljmp *(jump_vector-relocater) (%esi)
+
+ .code32
+relocater.2:
+ xorl %eax, %eax
+ movb $SEL_SDATA, %al
+ movw %ax, %ss
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movl %cr0, %eax /* disable paging */
+ andl $~0x80000000,%eax
+ movl %eax, %cr0
+ xorl %ecx, %ecx /* flush TLB */
+ movl %ecx, %cr3
+ cld
+/*
+ * relocate data loop. load source, dest and size from
+ * relocater_data[i], 0 value will stop the loop.
+ * registers used for move: %esi, %edi, %ecx.
+ * %ebx to keep base
+ * %edx for relocater_data offset
+ */
+ movl %esi, %ebx /* base address */
+ xorl %edx, %edx
+loop.1:
+ movl (relocater_data-relocater)(%ebx, %edx, 4), %eax
+ testl %eax, %eax
+ jz loop.2
+ movl (relocater_data-relocater)(%ebx, %edx, 4), %esi
+ inc %edx
+ movl (relocater_data-relocater)(%ebx, %edx, 4), %edi
+ inc %edx
+ movl (relocater_data-relocater)(%ebx, %edx, 4), %ecx
+ inc %edx
+ rep
+ movsb
+ jmp loop.1
+loop.2:
+ movl %ebx, %esi /* restore esi */
+ /*
+ * data is relocated, switch to 16bit mode
+ */
+ lea (relocater.3-relocater)(%esi), %eax
+ movl %eax, (jump_vector-relocater) (%esi)
+ movl $SEL_RCODE, %eax
+ movl %eax, (jump_vector-relocater+4) (%esi)
+
+ ljmp *(jump_vector-relocater) (%esi)
+relocater.3:
+ .code16
+
+ movw $SEL_RDATA, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+ lidt (idt-relocater) (%esi)
+ lea (relocater.4-relocater)(%esi), %eax
+ movl %eax, (jump_vector-relocater) (%esi)
+ xorl %eax, %eax
+ movl %eax, (jump_vector-relocater+4) (%esi)
+ /* clear PE */
+ movl %cr0, %eax
+ dec %al
+ movl %eax, %cr0
+ ljmp *(jump_vector-relocater) (%esi)
+relocater.4:
+ xorw %ax, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+ /*
+ * set real mode irq offsets
+ */
+ movw $0x7008,%bx
+ in $0x21,%al # Save master
+ push %ax # IMR
+ in $0xa1,%al # Save slave
+ push %ax # IMR
+ movb $0x11,%al # ICW1 to
+ outb %al,$0x20 # master,
+ outb %al,$0xa0 # slave
+ movb %bl,%al # ICW2 to
+ outb %al,$0x21 # master
+ movb %bh,%al # ICW2 to
+ outb %al,$0xa1 # slave
+ movb $0x4,%al # ICW3 to
+ outb %al,$0x21 # master
+ movb $0x2,%al # ICW3 to
+ outb %al,$0xa1 # slave
+ movb $0x1,%al # ICW4 to
+ outb %al,$0x21 # master,
+ outb %al,$0xa1 # slave
+ pop %ax # Restore slave
+ outb %al,$0xa1 # IMR
+ pop %ax # Restore master
+ outb %al,$0x21 # IMR
+ # done
+ /*
+ * Should A20 be left enabled?
+ */
+ /* movw imm16, %ax */
+ .byte 0xb8
+ .globl relocator_a20_enabled
+relocator_a20_enabled:
+ .word 0
+ test %ax, %ax
+ jnz a20_done
+
+ movw $0xa00, %ax
+ movw %ax, %sp
+ movw %ax, %bp
+
+ /* Disable A20 */
+ movw $0x2400, %ax
+ int $0x15
+# jnc a20_done
+
+ call a20_check_state
+ testb %al, %al
+ jz a20_done
+
+ inb $0x92
+ andb $(~0x03), %al
+ outb $0x92
+ jmp a20_done
+
+a20_check_state:
+ movw $100, %cx
+1:
+ xorw %ax, %ax
+ movw %ax, %ds
+ decw %ax
+ movw %ax, %es
+ xorw %ax, %ax
+ movw $0x8000, %ax
+ movw %ax, %si
+ addw $0x10, %ax
+ movw %ax, %di
+ movb %ds:(%si), %dl
+ movb %es:(%di), %al
+ movb %al, %dh
+ decb %dh
+ movb %dh, %ds:(%si)
+ outb %al, $0x80
+ outb %al, $0x80
+ movb %es:(%di), %dh
+ subb %dh, %al
+ xorb $1, %al
+ movb %dl, %ds:(%si)
+ testb %al, %al
+ jz a20_done
+ loop 1b
+ ret
+a20_done:
+ /*
+ * set up registers
+ */
+ /* movw imm16, %ax. */
+ .byte 0xb8
+ .globl relocator_ds
+relocator_ds: .word 0
+ movw %ax, %ds
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+ .globl relocator_es
+relocator_es: .word 0
+ movw %ax, %es
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+ .globl relocator_fs
+relocator_fs: .word 0
+ movw %ax, %fs
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+ .globl relocator_gs
+relocator_gs: .word 0
+ movw %ax, %gs
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+ .globl relocator_ss
+relocator_ss: .word 0
+ movw %ax, %ss
+
+ /* movw imm16, %ax. */
+ .byte 0xb8
+ .globl relocator_sp
+relocator_sp: .word 0
+ movzwl %ax, %esp
+
+ /* movw imm32, %eax. */
+ .byte 0x66, 0xb8
+ .globl relocator_esi
+relocator_esi: .long 0
+ movl %eax, %esi
+
+ /* movw imm32, %edx. */
+ .byte 0x66, 0xba
+ .globl relocator_edx
+relocator_edx: .long 0
+
+ /* movw imm32, %ebx. */
+ .byte 0x66, 0xbb
+ .globl relocator_ebx
+relocator_ebx: .long 0
+
+ /* movw imm32, %eax. */
+ .byte 0x66, 0xb8
+ .globl relocator_eax
+relocator_eax: .long 0
+
+ /* movw imm32, %ebp. */
+ .byte 0x66, 0xbd
+ .globl relocator_ebp
+relocator_ebp: .long 0
+
+ sti
+ .byte 0xea /* ljmp */
+ .globl relocator_ip
+relocator_ip:
+ .word 0
+ .globl relocator_cs
+relocator_cs:
+ .word 0
+
+/* GDT to reset BTX */
+ .code32
+ .p2align 4
+jump_vector: .long 0
+ .long SEL_SCODE
+
+gdt: .word 0x0, 0x0 /* null entry */
+ .byte 0x0, 0x0, 0x0, 0x0
+ .word 0xffff, 0x0 /* SEL_SCODE */
+ .byte 0x0, 0x9a, 0xcf, 0x0
+ .word 0xffff, 0x0 /* SEL_SDATA */
+ .byte 0x0, 0x92, 0xcf, 0x0
+ .word 0xffff, 0x0 /* SEL_RCODE */
+ .byte 0x0, 0x9a, 0x0f, 0x0
+ .word 0xffff, 0x0 /* SEL_RDATA */
+ .byte 0x0, 0x92, 0x0f, 0x0
+gdt.1:
+
+gdtdesc: .word gdt.1 - gdt - 1 /* limit */
+gdtaddr: .long 0 /* base */
+
+idt: .word 0x3ff
+ .long 0
+
+ .globl relocater_data
+relocater_data:
+ .long 0 /* src */
+ .long 0 /* dest */
+ .long 0 /* size */
+ .long 0 /* src */
+ .long 0 /* dest */
+ .long 0 /* size */
+ .long 0 /* src */
+ .long 0 /* dest */
+ .long 0 /* size */
+ .long 0
+
+ .globl relocater_size
+relocater_size:
+ .long relocater_size-relocater