359 lines
8.3 KiB
ArmAsm
359 lines
8.3 KiB
ArmAsm
|
/*-
|
||
|
* 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
|