286 lines
9.3 KiB
ArmAsm
286 lines
9.3 KiB
ArmAsm
/*****************************************************************************
|
|
*
|
|
* THIS FILE IS NOW OBSOLETE.
|
|
*
|
|
* The functions of this file are now placed in init.S.
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
|
|
#ifndef PCBIOS
|
|
#error "16bit code is only supported with the PCBIOS"
|
|
#endif
|
|
|
|
#define CODE_SEG 0x08
|
|
#define DATA_SEG 0x10
|
|
|
|
#define EXEC_IN_SITU_MAGIC 0x45524548 /* 'HERE' */
|
|
|
|
.equ CR0_PE, 1
|
|
|
|
#ifdef GAS291
|
|
#define DATA32 data32;
|
|
#define ADDR32 addr32;
|
|
#define LJMPI(x) ljmp x
|
|
#else
|
|
#define DATA32 data32
|
|
#define ADDR32 addr32
|
|
/* newer GAS295 require #define LJMPI(x) ljmp *x */
|
|
#define LJMPI(x) ljmp x
|
|
#endif
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* start16 : move payload to desired area of memory, set up for exit
|
|
* back to prefix, set up for 32-bit code.
|
|
*
|
|
* Enter (from prefix) with es:di = 0x4552:0x4548 if you want to
|
|
* prevent start16 from moving the payload. There are three
|
|
* motivations for moving the payload:
|
|
*
|
|
* 1. It may be in ROM, in which case we need to move it to RAM.
|
|
* 2. Whatever loaded us probably didn't know about our memory usage
|
|
* beyond the end of the image file. We should claim this memory
|
|
* before using it.
|
|
*
|
|
* Unless the prefix instructs us otherwise we will move the payload to:
|
|
*
|
|
* An area of memory claimed from the BIOS via 40:13.
|
|
*
|
|
* We use the main Etherboot stack (within the image target) as our
|
|
* stack; we don't rely on the prefix passing us a stack usable for
|
|
* anything other than the prefix's return address. The (first 512
|
|
* bytes of the) prefix code segment is copied to a safe archive
|
|
* location.
|
|
*
|
|
* When we return to the prefix (from start32), we copy this code back
|
|
* to a new area of memory, restore the prefix's ss:sp and ljmp back
|
|
* to the copy of the prefix. The prefix will see a return from
|
|
* start16 *but* may be executing at a new location. Code following
|
|
* the lcall to start16 must therefore be position-independent and
|
|
* must also be within [cs:0000,cs:01ff]. We make absolutely no
|
|
* guarantees about the stack contents when the prefix regains
|
|
* control.
|
|
*
|
|
* Trashes just about all registers, including all the segment
|
|
* registers.
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
|
|
.text
|
|
.code16
|
|
.arch i386
|
|
.org 0
|
|
.globl _start16
|
|
_start16:
|
|
|
|
/*****************************************************************************
|
|
* Work out where we are going to place our image (image = optional
|
|
* decompressor + runtime). Exit this stage with %ax containing the
|
|
* runtime target address divided by 16 (i.e. a real-mode segment
|
|
* address).
|
|
*****************************************************************************
|
|
*/
|
|
movw %es, %ax
|
|
cmpw $(EXEC_IN_SITU_MAGIC >> 16), %ax
|
|
jne exec_moved
|
|
cmpw $(EXEC_IN_SITU_MAGIC & 0xffff), %di
|
|
jne exec_moved
|
|
exec_in_situ:
|
|
/* Prefix has warned us not to move the payload. Simply
|
|
* calculate where the image is going to end up, so we can
|
|
* work out where to put our stack.
|
|
*/
|
|
movw %cs, %ax
|
|
addw $((payload-_start16)/16), %ax
|
|
jmp 99f
|
|
exec_moved:
|
|
/* Claim an area of base memory from the BIOS and put the
|
|
* payload there. arch_relocated_to() will deal with freeing
|
|
* up this memory once we've relocated to high memory.
|
|
*/
|
|
movw $0x40, %ax
|
|
movw %ax, %es
|
|
movw %es:(0x13), %ax /* FBMS in kb to %ax */
|
|
shlw $6, %ax /* ... in paragraphs */
|
|
subw $__image_size_pgh, %ax /* Subtract space for image */
|
|
shrw $6, %ax /* Round down to nearest kb */
|
|
movw %ax, %es:(0x13) /* ...and claim memory from BIOS */
|
|
shlw $6, %ax
|
|
99:
|
|
/* At this point %ax contains the segment address for the
|
|
* start of the image (image = optional decompressor + runtime).
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
* Set up stack in start32's stack space within the place we're going
|
|
* to copy Etherboot to, reserve space for GDT, copy return address
|
|
* from prefix stack, store prefix stack address
|
|
*****************************************************************************
|
|
*/
|
|
popl %esi /* Return address */
|
|
mov %ss, %bx /* %es:di = prefix stack address */
|
|
mov %bx, %es /* (*after* pop of return address) */
|
|
movw %sp, %di
|
|
movw $__offset_stack_pgh, %bx /* Set up Etherboot stack */
|
|
addw %ax, %bx
|
|
movw %bx, %ss
|
|
movw $__stack_size, %sp
|
|
subw $(_gdt_end - _gdt), %sp /* Reserve space for GDT */
|
|
movw %sp, %bp /* Record GDT location */
|
|
/* Set up i386_rm_in_call_data_t structure on stack. This is
|
|
* the same structure as is set up by rm_in_call.
|
|
*/
|
|
pushl $0 /* Dummy opcode */
|
|
pushl %esi /* Prefix return address */
|
|
pushfw /* Flags */
|
|
pushw %di /* Prefix %sp */
|
|
pushw %gs /* Segment registers */
|
|
pushw %fs
|
|
pushw %es
|
|
pushw %ds
|
|
pushw %es /* Prefix %ss */
|
|
pushw %cs
|
|
/* Stack is now 32-bit aligned */
|
|
|
|
/* %ax still contains image target segment address */
|
|
|
|
/*****************************************************************************
|
|
* Calculate image target and prefix code physical addresses, store on stack
|
|
* for use in copy routine.
|
|
*****************************************************************************
|
|
*/
|
|
movzwl %es:-2(%di), %ebx /* Prefix code segment */
|
|
shll $4, %ebx
|
|
pushl %ebx /* Prefix code physical address */
|
|
movzwl %ax, %edi /* Image target segment */
|
|
shll $4, %edi
|
|
pushl %edi /* Image target physical address */
|
|
|
|
/*****************************************************************************
|
|
* Transition to 32-bit protected mode. Set up all segment
|
|
* descriptors to use flat physical addresses.
|
|
*****************************************************************************
|
|
*/
|
|
/* Copy gdt to area reserved on stack
|
|
*/
|
|
push %cs /* GDT source location -> %ds:%si */
|
|
pop %ds
|
|
mov $(_gdt - _start16), %si
|
|
push %ss /* GDT target location -> %es:%di */
|
|
pop %es
|
|
mov %bp, %di
|
|
mov $(_gdt_end - _gdt), %cx
|
|
cld
|
|
rep movsb /* Copy GDT to stack */
|
|
movl %ss, %eax
|
|
shll $4, %eax
|
|
movzwl %bp, %ebx
|
|
addl %eax, %ebx /* Physical addr of GDT copy -> %ebx */
|
|
movl %ebx, 2(%bp) /* Fill in addr field in GDT */
|
|
|
|
/* Compute the offset I am running at.
|
|
*/
|
|
movl %cs, %ebx
|
|
shll $4, %ebx /* %ebx = offset for start16 symbols */
|
|
|
|
/* Switch to 32bit protected mode.
|
|
*/
|
|
cli /* Disable interrupts */
|
|
lgdt (%bp) /* Load GDT from stack */
|
|
movl %cr0, %eax /* Set protected mode bit */
|
|
orb $CR0_PE, %al
|
|
movl %eax, %cr0
|
|
movl %ss, %eax /* Convert stack pointer to 32bit */
|
|
shll $4, %eax
|
|
movzwl %sp, %esp
|
|
addl %eax, %esp
|
|
movl $DATA_SEG, %eax /* Reload the segment registers */
|
|
movl %eax, %ds
|
|
movl %eax, %es
|
|
movl %eax, %ss
|
|
movl %eax, %fs
|
|
movl %eax, %gs
|
|
/* Flush prefetch queue, and reload %cs:%eip by effectively ljmping
|
|
* to code32_start. Do the jump via pushl and lret because the text
|
|
* may not be writable/
|
|
*/
|
|
pushl $CODE_SEG
|
|
ADDR32 leal (code32_start-_start16)(%ebx), %eax
|
|
pushl %eax
|
|
DATA32 lret /* DATA32 needed, because we're still in 16-bit mode */
|
|
|
|
_gdt:
|
|
gdtarg:
|
|
.word _gdt_end - _gdt - 1 /* limit */
|
|
.long 0 /* addr */
|
|
.word 0
|
|
_pmcs:
|
|
/* 32 bit protected mode code segment */
|
|
.word 0xffff, 0
|
|
.byte 0, 0x9f, 0xcf, 0
|
|
_pmds:
|
|
/* 32 bit protected mode data segment */
|
|
.word 0xffff,0
|
|
.byte 0,0x93,0xcf,0
|
|
_gdt_end:
|
|
|
|
.code32
|
|
code32_start:
|
|
|
|
/*****************************************************************************
|
|
* Copy payload to target location. Do the copy backwards, since if
|
|
* there's overlap with a forward copy then it means start16 is going
|
|
* to get trashed during the copy anyway...
|
|
*****************************************************************************
|
|
*/
|
|
popl %edi /* Image target physical address */
|
|
pushl %edi
|
|
leal (payload-_start16)(%ebx), %esi /* Image source physical addr */
|
|
movl $__payload_size, %ecx /* Payload size (not image size) */
|
|
addl %ecx, %edi /* Start at last byte (length - 1) */
|
|
decl %edi
|
|
addl %ecx, %esi
|
|
decl %esi
|
|
std /* Backward copy of image */
|
|
rep movsb
|
|
cld
|
|
popl %edi /* Restore image target physical address */
|
|
leal __decompressor_uncompressed(%edi), %ebx
|
|
subl $_text, %ebx /* %ebx = offset for runtime symbols */
|
|
|
|
/*****************************************************************************
|
|
* Copy prefix to storage area within Etherboot image.
|
|
*****************************************************************************
|
|
*/
|
|
popl %esi /* Prefix source physical address */
|
|
pushl %edi
|
|
leal _prefix_copy(%ebx), %edi /* Prefix copy phys. addr. */
|
|
leal _eprefix_copy(%ebx), %ecx
|
|
subl %edi, %ecx /* Prefix copy size */
|
|
rep movsb /* Forward copy of prefix */
|
|
popl %edi /* Restore image target physical address */
|
|
|
|
/*****************************************************************************
|
|
* Record base memory used by Etherboot image
|
|
*****************************************************************************
|
|
*/
|
|
movl %edi, _prefix_image_basemem (%ebx)
|
|
|
|
/*****************************************************************************
|
|
* Jump to start of the image (i.e. the decompressor, or start32 if
|
|
* non-compressed).
|
|
*****************************************************************************
|
|
*/
|
|
pushl $0 /* Inform start32 that exit path is 16-bit */
|
|
jmpl *%edi /* Jump to image */
|
|
|
|
.balign 16
|
|
/* Etherboot needs to be 16byte aligned or data that
|
|
* is virtually aligned is no longer physically aligned
|
|
* which is just nasty in general. 16byte alignment
|
|
* should be sufficient though.
|
|
*/
|
|
payload:
|