david/ipxe
david
/
ipxe
Archived
1
0
Fork 0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/arch/i386/core/start16.S

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: