mirror of
https://github.com/ipxe/ipxe
synced 2026-01-05 03:10:58 +03:00
[bios] Add bin-x86_64-pcbios build platform
Move most arch/i386 files to arch/x86, and adjust the contents of the Makefiles and the include/bits/*.h headers to reflect the new locations. This patch makes no substantive code changes, as can be seen using a rename-aware diff (e.g. "git show -M5"). This patch does not make the pcbios platform functional for x86_64; it merely allows it to compile without errors. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
37
src/arch/x86/core/basemem_packet.c
Normal file
37
src/arch/x86/core/basemem_packet.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Packet buffer in base memory. Used by various components which
|
||||
* need to pass packets to and from external real-mode code.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <basemem_packet.h>
|
||||
|
||||
#undef basemem_packet
|
||||
char __bss16_array ( basemem_packet, [BASEMEM_PACKET_LEN] );
|
||||
178
src/arch/x86/core/cachedhcp.c
Normal file
178
src/arch/x86/core/cachedhcp.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ipxe/dhcppkt.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <realmode.h>
|
||||
#include <pxe_api.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Cached DHCP packet
|
||||
*
|
||||
*/
|
||||
|
||||
/** Cached DHCPACK physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( cached_dhcpack_phys );
|
||||
#define cached_dhcpack_phys __use_data16 ( cached_dhcpack_phys )
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cached_dhcpack_phys
|
||||
|
||||
/** Cached DHCPACK */
|
||||
static struct dhcp_packet *cached_dhcpack;
|
||||
|
||||
/**
|
||||
* Cached DHCPACK startup function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_init ( void ) {
|
||||
struct dhcp_packet *dhcppkt;
|
||||
struct dhcp_packet *tmp;
|
||||
struct dhcphdr *dhcphdr;
|
||||
size_t max_len;
|
||||
size_t len;
|
||||
|
||||
/* Do nothing if no cached DHCPACK is present */
|
||||
if ( ! cached_dhcpack_phys ) {
|
||||
DBGC ( colour, "CACHEDHCP found no cached DHCPACK\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
/* No reliable way to determine length before parsing packet;
|
||||
* start by assuming maximum length permitted by PXE.
|
||||
*/
|
||||
max_len = sizeof ( BOOTPLAYER_t );
|
||||
|
||||
/* Allocate and populate DHCP packet */
|
||||
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
|
||||
if ( ! dhcppkt ) {
|
||||
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
|
||||
return;
|
||||
}
|
||||
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
|
||||
copy_from_user ( dhcphdr, phys_to_user ( cached_dhcpack_phys ), 0,
|
||||
max_len );
|
||||
dhcppkt_init ( dhcppkt, dhcphdr, max_len );
|
||||
|
||||
/* Shrink packet to required length. If reallocation fails,
|
||||
* just continue to use the original packet and waste the
|
||||
* unused space.
|
||||
*/
|
||||
len = dhcppkt_len ( dhcppkt );
|
||||
assert ( len <= max_len );
|
||||
tmp = realloc ( dhcppkt, ( sizeof ( *dhcppkt ) + len ) );
|
||||
if ( tmp )
|
||||
dhcppkt = tmp;
|
||||
|
||||
/* Reinitialise packet at new address */
|
||||
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
|
||||
dhcppkt_init ( dhcppkt, dhcphdr, len );
|
||||
|
||||
/* Store as cached DHCPACK, and mark original copy as consumed */
|
||||
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %08x+%zx\n",
|
||||
cached_dhcpack_phys, len );
|
||||
cached_dhcpack = dhcppkt;
|
||||
cached_dhcpack_phys = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cached DHCPACK startup function
|
||||
*
|
||||
*/
|
||||
static void cachedhcp_startup ( void ) {
|
||||
|
||||
/* If cached DHCP packet was not claimed by any network device
|
||||
* during startup, then free it.
|
||||
*/
|
||||
if ( cached_dhcpack ) {
|
||||
DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
|
||||
dhcppkt_put ( cached_dhcpack );
|
||||
cached_dhcpack = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/** Cached DHCPACK initialisation function */
|
||||
struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = cachedhcp_init,
|
||||
};
|
||||
|
||||
/** Cached DHCPACK startup function */
|
||||
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
.startup = cachedhcp_startup,
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply cached DHCPACK to network device, if applicable
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cachedhcp_probe ( struct net_device *netdev ) {
|
||||
struct ll_protocol *ll_protocol = netdev->ll_protocol;
|
||||
int rc;
|
||||
|
||||
/* Do nothing unless we have a cached DHCPACK */
|
||||
if ( ! cached_dhcpack )
|
||||
return 0;
|
||||
|
||||
/* Do nothing unless cached DHCPACK's MAC address matches this
|
||||
* network device.
|
||||
*/
|
||||
if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
|
||||
ll_protocol->ll_addr_len ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
|
||||
netdev->name );
|
||||
return 0;
|
||||
}
|
||||
DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
|
||||
|
||||
/* Register as DHCP settings for this network device */
|
||||
if ( ( rc = register_settings ( &cached_dhcpack->settings,
|
||||
netdev_settings ( netdev ),
|
||||
DHCP_SETTINGS_NAME ) ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Claim cached DHCPACK */
|
||||
dhcppkt_put ( cached_dhcpack );
|
||||
cached_dhcpack = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Cached DHCP packet network device driver */
|
||||
struct net_driver cachedhcp_driver __net_driver = {
|
||||
.name = "cachedhcp",
|
||||
.probe = cachedhcp_probe,
|
||||
};
|
||||
23
src/arch/x86/core/dumpregs.c
Normal file
23
src/arch/x86/core/dumpregs.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <stdio.h>
|
||||
#include <realmode.h>
|
||||
|
||||
void __asmcall _dump_regs ( struct i386_all_regs *ix86 ) {
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TEXT16_CODE ( ".globl dump_regs\n\t"
|
||||
"\ndump_regs:\n\t"
|
||||
"pushl $_dump_regs\n\t"
|
||||
"pushw %%cs\n\t"
|
||||
"call prot_call\n\t"
|
||||
"addr32 leal 4(%%esp), %%esp\n\t"
|
||||
"ret\n\t" ) : : );
|
||||
|
||||
printf ( "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
|
||||
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
|
||||
"CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n",
|
||||
ix86->regs.eax, ix86->regs.ebx, ix86->regs.ecx,
|
||||
ix86->regs.edx, ix86->regs.esi, ix86->regs.edi,
|
||||
ix86->regs.ebp, ix86->regs.esp,
|
||||
ix86->segs.cs, ix86->segs.ss, ix86->segs.ds,
|
||||
ix86->segs.es, ix86->segs.fs, ix86->segs.gs );
|
||||
}
|
||||
42
src/arch/x86/core/patch_cf.S
Normal file
42
src/arch/x86/core/patch_cf.S
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2009 H. Peter Anvin <hpa@zytor.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.text
|
||||
.arch i386
|
||||
.code16
|
||||
|
||||
/****************************************************************************
|
||||
* Set/clear CF on the stack as appropriate, assumes stack is as it should
|
||||
* be immediately before IRET
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".text16", "ax", @progbits
|
||||
.globl patch_cf
|
||||
patch_cf:
|
||||
pushw %bp
|
||||
movw %sp, %bp
|
||||
setc 8(%bp) /* Set/reset CF; clears PF, AF, ZF, SF */
|
||||
popw %bp
|
||||
ret
|
||||
.size patch_cf, . - patch_cf
|
||||
48
src/arch/x86/core/pci_autoboot.c
Normal file
48
src/arch/x86/core/pci_autoboot.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat Inc.
|
||||
* Alex Williamson <alex.williamson@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/device.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <realmode.h>
|
||||
#include <usr/autoboot.h>
|
||||
|
||||
uint16_t __bss16 ( autoboot_busdevfn );
|
||||
#define autoboot_busdevfn __use_data16 ( autoboot_busdevfn )
|
||||
|
||||
/**
|
||||
* Initialise PCI autoboot device
|
||||
*/
|
||||
static void pci_autoboot_init ( void ) {
|
||||
|
||||
if ( autoboot_busdevfn )
|
||||
set_autoboot_busloc ( BUS_TYPE_PCI, autoboot_busdevfn );
|
||||
}
|
||||
|
||||
/** PCI autoboot device initialisation function */
|
||||
struct init_fn pci_autoboot_init_fn __init_fn ( INIT_NORMAL ) = {
|
||||
.initialise = pci_autoboot_init,
|
||||
};
|
||||
94
src/arch/x86/core/rdtsc_timer.c
Normal file
94
src/arch/x86/core/rdtsc_timer.c
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RDTSC timer
|
||||
*
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/pit8254.h>
|
||||
|
||||
/**
|
||||
* Number of TSC ticks per microsecond
|
||||
*
|
||||
* This is calibrated on the first use of the timer.
|
||||
*/
|
||||
static unsigned long rdtsc_ticks_per_usec;
|
||||
|
||||
/**
|
||||
* Delay for a fixed number of microseconds
|
||||
*
|
||||
* @v usecs Number of microseconds for which to delay
|
||||
*/
|
||||
static void rdtsc_udelay ( unsigned long usecs ) {
|
||||
unsigned long start;
|
||||
unsigned long elapsed;
|
||||
|
||||
/* Sanity guard, since we may divide by this */
|
||||
if ( ! usecs )
|
||||
usecs = 1;
|
||||
|
||||
start = currticks();
|
||||
if ( rdtsc_ticks_per_usec ) {
|
||||
/* Already calibrated; busy-wait until done */
|
||||
do {
|
||||
elapsed = ( currticks() - start );
|
||||
} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
|
||||
} else {
|
||||
/* Not yet calibrated; use 8254 PIT and calibrate
|
||||
* based on result.
|
||||
*/
|
||||
pit8254_udelay ( usecs );
|
||||
elapsed = ( currticks() - start );
|
||||
rdtsc_ticks_per_usec = ( elapsed / usecs );
|
||||
DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
|
||||
"(%ld MHz)\n", elapsed, usecs,
|
||||
( rdtsc_ticks_per_usec << TSC_SHIFT ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks per second
|
||||
*
|
||||
* @ret ticks_per_sec Number of ticks per second
|
||||
*/
|
||||
static unsigned long rdtsc_ticks_per_sec ( void ) {
|
||||
|
||||
/* Calibrate timer, if not already done */
|
||||
if ( ! rdtsc_ticks_per_usec )
|
||||
udelay ( 1 );
|
||||
|
||||
/* Sanity check */
|
||||
assert ( rdtsc_ticks_per_usec != 0 );
|
||||
|
||||
return ( rdtsc_ticks_per_usec * 1000 * 1000 );
|
||||
}
|
||||
|
||||
PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
|
||||
PROVIDE_TIMER_INLINE ( rdtsc, currticks );
|
||||
PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
|
||||
138
src/arch/x86/core/relocate.c
Normal file
138
src/arch/x86/core/relocate.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <ipxe/io.h>
|
||||
#include <registers.h>
|
||||
|
||||
/*
|
||||
* Originally by Eric Biederman
|
||||
*
|
||||
* Heavily modified by Michael Brown
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/*
|
||||
* The linker passes in the symbol _max_align, which is the alignment
|
||||
* that we must preserve, in bytes.
|
||||
*
|
||||
*/
|
||||
extern char _max_align[];
|
||||
#define max_align ( ( size_t ) _max_align )
|
||||
|
||||
/* Linker symbols */
|
||||
extern char _textdata[];
|
||||
extern char _etextdata[];
|
||||
|
||||
/* within 1MB of 4GB is too close.
|
||||
* MAX_ADDR is the maximum address we can easily do DMA to.
|
||||
*
|
||||
* Not sure where this constraint comes from, but kept it from Eric's
|
||||
* old code - mcb30
|
||||
*/
|
||||
#define MAX_ADDR (0xfff00000UL)
|
||||
|
||||
/**
|
||||
* Relocate iPXE
|
||||
*
|
||||
* @v ebp Maximum address to use for relocation
|
||||
* @ret esi Current physical address
|
||||
* @ret edi New physical address
|
||||
* @ret ecx Length to copy
|
||||
*
|
||||
* This finds a suitable location for iPXE near the top of 32-bit
|
||||
* address space, and returns the physical address of the new location
|
||||
* to the prefix in %edi.
|
||||
*/
|
||||
__asmcall void relocate ( struct i386_all_regs *ix86 ) {
|
||||
struct memory_map memmap;
|
||||
uint32_t start, end, size, padded_size, max;
|
||||
uint32_t new_start, new_end;
|
||||
unsigned i;
|
||||
|
||||
/* Get memory map and current location */
|
||||
get_memmap ( &memmap );
|
||||
start = virt_to_phys ( _textdata );
|
||||
end = virt_to_phys ( _etextdata );
|
||||
size = ( end - start );
|
||||
padded_size = ( size + max_align - 1 );
|
||||
|
||||
DBG ( "Relocate: currently at [%x,%x)\n"
|
||||
"...need %x bytes for %zd-byte alignment\n",
|
||||
start, end, padded_size, max_align );
|
||||
|
||||
/* Determine maximum usable address */
|
||||
max = MAX_ADDR;
|
||||
if ( ix86->regs.ebp < max ) {
|
||||
max = ix86->regs.ebp;
|
||||
DBG ( "Limiting relocation to [0,%x)\n", max );
|
||||
}
|
||||
|
||||
/* Walk through the memory map and find the highest address
|
||||
* below 4GB that iPXE will fit into.
|
||||
*/
|
||||
new_end = end;
|
||||
for ( i = 0 ; i < memmap.count ; i++ ) {
|
||||
struct memory_region *region = &memmap.regions[i];
|
||||
uint32_t r_start, r_end;
|
||||
|
||||
DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
|
||||
|
||||
/* Truncate block to maximum address. This will be
|
||||
* less than 4GB, which means that we can get away
|
||||
* with using just 32-bit arithmetic after this stage.
|
||||
*/
|
||||
if ( region->start > max ) {
|
||||
DBG ( "...starts after max=%x\n", max );
|
||||
continue;
|
||||
}
|
||||
r_start = region->start;
|
||||
if ( region->end > max ) {
|
||||
DBG ( "...end truncated to max=%x\n", max );
|
||||
r_end = max;
|
||||
} else {
|
||||
r_end = region->end;
|
||||
}
|
||||
DBG ( "...usable portion is [%x,%x)\n", r_start, r_end );
|
||||
|
||||
/* If we have rounded down r_end below r_ start, skip
|
||||
* this block.
|
||||
*/
|
||||
if ( r_end < r_start ) {
|
||||
DBG ( "...truncated to negative size\n" );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check that there is enough space to fit in iPXE */
|
||||
if ( ( r_end - r_start ) < size ) {
|
||||
DBG ( "...too small (need %x bytes)\n", size );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If the start address of the iPXE we would
|
||||
* place in this block is higher than the end address
|
||||
* of the current highest block, use this block.
|
||||
*
|
||||
* Note that this avoids overlaps with the current
|
||||
* iPXE, as well as choosing the highest of all viable
|
||||
* blocks.
|
||||
*/
|
||||
if ( ( r_end - size ) > new_end ) {
|
||||
new_end = r_end;
|
||||
DBG ( "...new best block found.\n" );
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate new location of iPXE, and align it to the
|
||||
* required alignemnt.
|
||||
*/
|
||||
new_start = new_end - padded_size;
|
||||
new_start += ( start - new_start ) & ( max_align - 1 );
|
||||
new_end = new_start + size;
|
||||
|
||||
DBG ( "Relocating from [%x,%x) to [%x,%x)\n",
|
||||
start, end, new_start, new_end );
|
||||
|
||||
/* Let prefix know what to copy */
|
||||
ix86->regs.esi = start;
|
||||
ix86->regs.edi = new_start;
|
||||
ix86->regs.ecx = size;
|
||||
}
|
||||
269
src/arch/x86/core/runtime.c
Normal file
269
src/arch/x86/core/runtime.c
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Command line and initrd passed to iPXE at runtime
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/script.h>
|
||||
#include <ipxe/umalloc.h>
|
||||
#include <realmode.h>
|
||||
|
||||
/** Command line physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( cmdline_phys );
|
||||
#define cmdline_phys __use_data16 ( cmdline_phys )
|
||||
|
||||
/** initrd physical address
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( initrd_phys );
|
||||
#define initrd_phys __use_data16 ( initrd_phys )
|
||||
|
||||
/** initrd length
|
||||
*
|
||||
* This can be set by the prefix.
|
||||
*/
|
||||
uint32_t __bss16 ( initrd_len );
|
||||
#define initrd_len __use_data16 ( initrd_len )
|
||||
|
||||
/** Internal copy of the command line */
|
||||
static char *cmdline_copy;
|
||||
|
||||
/** Free command line image */
|
||||
static void cmdline_image_free ( struct refcnt *refcnt ) {
|
||||
struct image *image = container_of ( refcnt, struct image, refcnt );
|
||||
|
||||
DBGC ( image, "RUNTIME freeing command line\n" );
|
||||
free ( cmdline_copy );
|
||||
}
|
||||
|
||||
/** Embedded script representing the command line */
|
||||
static struct image cmdline_image = {
|
||||
.refcnt = REF_INIT ( cmdline_image_free ),
|
||||
.name = "<CMDLINE>",
|
||||
.type = &script_image_type,
|
||||
};
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cmdline_image
|
||||
|
||||
/**
|
||||
* Strip unwanted cruft from command line
|
||||
*
|
||||
* @v cmdline Command line
|
||||
* @v cruft Initial substring of cruft to strip
|
||||
*/
|
||||
static void cmdline_strip ( char *cmdline, const char *cruft ) {
|
||||
char *strip;
|
||||
char *strip_end;
|
||||
|
||||
/* Find unwanted cruft, if present */
|
||||
if ( ! ( strip = strstr ( cmdline, cruft ) ) )
|
||||
return;
|
||||
|
||||
/* Strip unwanted cruft */
|
||||
strip_end = strchr ( strip, ' ' );
|
||||
if ( strip_end ) {
|
||||
*strip_end = '\0';
|
||||
DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
|
||||
strcpy ( strip, ( strip_end + 1 ) );
|
||||
} else {
|
||||
DBGC ( colour, "RUNTIME stripping \"%s\"\n", strip );
|
||||
*strip = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise command line
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cmdline_init ( void ) {
|
||||
userptr_t cmdline_user;
|
||||
char *cmdline;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if no command line was specified */
|
||||
if ( ! cmdline_phys ) {
|
||||
DBGC ( colour, "RUNTIME found no command line\n" );
|
||||
return 0;
|
||||
}
|
||||
cmdline_user = phys_to_user ( cmdline_phys );
|
||||
len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ );
|
||||
|
||||
/* Allocate and copy command line */
|
||||
cmdline_copy = malloc ( len );
|
||||
if ( ! cmdline_copy ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate %zd bytes for "
|
||||
"command line\n", len );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_cmdline_copy;
|
||||
}
|
||||
cmdline = cmdline_copy;
|
||||
copy_from_user ( cmdline, cmdline_user, 0, len );
|
||||
DBGC ( colour, "RUNTIME found command line \"%s\" at %08x\n",
|
||||
cmdline, cmdline_phys );
|
||||
|
||||
/* Mark command line as consumed */
|
||||
cmdline_phys = 0;
|
||||
|
||||
/* Strip unwanted cruft from the command line */
|
||||
cmdline_strip ( cmdline, "BOOT_IMAGE=" );
|
||||
cmdline_strip ( cmdline, "initrd=" );
|
||||
while ( isspace ( *cmdline ) )
|
||||
cmdline++;
|
||||
DBGC ( colour, "RUNTIME using command line \"%s\"\n", cmdline );
|
||||
|
||||
/* Prepare and register image */
|
||||
cmdline_image.data = virt_to_user ( cmdline );
|
||||
cmdline_image.len = strlen ( cmdline );
|
||||
if ( cmdline_image.len ) {
|
||||
if ( ( rc = register_image ( &cmdline_image ) ) != 0 ) {
|
||||
DBGC ( colour, "RUNTIME could not register command "
|
||||
"line: %s\n", strerror ( rc ) );
|
||||
goto err_register_image;
|
||||
}
|
||||
}
|
||||
|
||||
/* Drop our reference to the image */
|
||||
image_put ( &cmdline_image );
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_image:
|
||||
image_put ( &cmdline_image );
|
||||
err_alloc_cmdline_copy:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise initrd
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int initrd_init ( void ) {
|
||||
struct image *image;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if no initrd was specified */
|
||||
if ( ! initrd_phys ) {
|
||||
DBGC ( colour, "RUNTIME found no initrd\n" );
|
||||
return 0;
|
||||
}
|
||||
if ( ! initrd_len ) {
|
||||
DBGC ( colour, "RUNTIME found empty initrd\n" );
|
||||
return 0;
|
||||
}
|
||||
DBGC ( colour, "RUNTIME found initrd at [%x,%x)\n",
|
||||
initrd_phys, ( initrd_phys + initrd_len ) );
|
||||
|
||||
/* Allocate image */
|
||||
image = alloc_image ( NULL );
|
||||
if ( ! image ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate image for "
|
||||
"initrd\n" );
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_image;
|
||||
}
|
||||
if ( ( rc = image_set_name ( image, "<INITRD>" ) ) != 0 ) {
|
||||
DBGC ( colour, "RUNTIME could not set image name: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_set_name;
|
||||
}
|
||||
|
||||
/* Allocate and copy initrd content */
|
||||
image->data = umalloc ( initrd_len );
|
||||
if ( ! image->data ) {
|
||||
DBGC ( colour, "RUNTIME could not allocate %d bytes for "
|
||||
"initrd\n", initrd_len );
|
||||
rc = -ENOMEM;
|
||||
goto err_umalloc;
|
||||
}
|
||||
image->len = initrd_len;
|
||||
memcpy_user ( image->data, 0, phys_to_user ( initrd_phys ), 0,
|
||||
initrd_len );
|
||||
|
||||
/* Mark initrd as consumed */
|
||||
initrd_phys = 0;
|
||||
|
||||
/* Register image */
|
||||
if ( ( rc = register_image ( image ) ) != 0 ) {
|
||||
DBGC ( colour, "RUNTIME could not register initrd: %s\n",
|
||||
strerror ( rc ) );
|
||||
goto err_register_image;
|
||||
}
|
||||
|
||||
/* Drop our reference to the image */
|
||||
image_put ( image );
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_image:
|
||||
err_umalloc:
|
||||
err_set_name:
|
||||
image_put ( image );
|
||||
err_alloc_image:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise command line and initrd
|
||||
*
|
||||
*/
|
||||
static void runtime_init ( void ) {
|
||||
int rc;
|
||||
|
||||
/* Initialise command line */
|
||||
if ( ( rc = cmdline_init() ) != 0 ) {
|
||||
/* No way to report failure */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialise initrd */
|
||||
if ( ( rc = initrd_init() ) != 0 ) {
|
||||
/* No way to report failure */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Command line and initrd initialisation function */
|
||||
struct startup_fn runtime_startup_fn __startup_fn ( STARTUP_NORMAL ) = {
|
||||
.startup = runtime_init,
|
||||
};
|
||||
15
src/arch/x86/core/stack.S
Normal file
15
src/arch/x86/core/stack.S
Normal file
@@ -0,0 +1,15 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack
|
||||
_stack:
|
||||
.space 4096
|
||||
.globl _estack
|
||||
_estack:
|
||||
15
src/arch/x86/core/stack16.S
Normal file
15
src/arch/x86/core/stack16.S
Normal file
@@ -0,0 +1,15 @@
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
.arch i386
|
||||
|
||||
/****************************************************************************
|
||||
* Internal stack
|
||||
****************************************************************************
|
||||
*/
|
||||
.section ".stack16", "aw", @nobits
|
||||
.align 8
|
||||
.globl _stack16
|
||||
_stack16:
|
||||
.space 4096
|
||||
.globl _estack16
|
||||
_estack16:
|
||||
113
src/arch/x86/core/video_subr.c
Normal file
113
src/arch/x86/core/video_subr.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
*
|
||||
* modified from linuxbios code
|
||||
* by Cai Qiang <rimy2000@hotmail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stddef.h"
|
||||
#include "string.h"
|
||||
#include <ipxe/io.h>
|
||||
#include <ipxe/console.h>
|
||||
#include <ipxe/init.h>
|
||||
#include "vga.h"
|
||||
#include <config/console.h>
|
||||
|
||||
/* Set default console usage if applicable */
|
||||
#if ! ( defined ( CONSOLE_DIRECT_VGA ) && \
|
||||
CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) )
|
||||
#undef CONSOLE_DIRECT_VGA
|
||||
#define CONSOLE_DIRECT_VGA ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
|
||||
#endif
|
||||
|
||||
struct console_driver vga_console __console_driver;
|
||||
|
||||
static char *vidmem; /* The video buffer */
|
||||
static int video_line, video_col;
|
||||
|
||||
#define VIDBUFFER 0xB8000
|
||||
|
||||
static void memsetw(void *s, int c, unsigned int n)
|
||||
{
|
||||
unsigned int i;
|
||||
u16 *ss = (u16 *) s;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ss[i] = ( u16 ) c;
|
||||
}
|
||||
}
|
||||
|
||||
static void video_init(void)
|
||||
{
|
||||
static int inited=0;
|
||||
|
||||
vidmem = (char *)phys_to_virt(VIDBUFFER);
|
||||
|
||||
if (!inited) {
|
||||
video_line = 0;
|
||||
video_col = 0;
|
||||
|
||||
memsetw(vidmem, VGA_ATTR_CLR_WHT, 2*1024); //
|
||||
|
||||
inited=1;
|
||||
}
|
||||
}
|
||||
|
||||
static void video_scroll(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
memcpy(vidmem, vidmem + COLS * 2, (LINES - 1) * COLS * 2);
|
||||
for (i = (LINES - 1) * COLS * 2; i < LINES * COLS * 2; i += 2)
|
||||
vidmem[i] = ' ';
|
||||
}
|
||||
|
||||
static void vga_putc(int byte)
|
||||
{
|
||||
if (byte == '\n') {
|
||||
video_line++;
|
||||
video_col = 0;
|
||||
|
||||
} else if (byte == '\r') {
|
||||
video_col = 0;
|
||||
|
||||
} else if (byte == '\b') {
|
||||
video_col--;
|
||||
|
||||
} else if (byte == '\t') {
|
||||
video_col += 4;
|
||||
|
||||
} else if (byte == '\a') {
|
||||
//beep
|
||||
//beep(500);
|
||||
|
||||
} else {
|
||||
vidmem[((video_col + (video_line *COLS)) * 2)] = byte;
|
||||
vidmem[((video_col + (video_line *COLS)) * 2) +1] = VGA_ATTR_CLR_WHT;
|
||||
video_col++;
|
||||
}
|
||||
if (video_col < 0) {
|
||||
video_col = 0;
|
||||
}
|
||||
if (video_col >= COLS) {
|
||||
video_line++;
|
||||
video_col = 0;
|
||||
}
|
||||
if (video_line >= LINES) {
|
||||
video_scroll();
|
||||
video_line--;
|
||||
}
|
||||
// move the cursor
|
||||
write_crtc((video_col + (video_line *COLS)) >> 8, CRTC_CURSOR_HI);
|
||||
write_crtc((video_col + (video_line *COLS)) & 0x0ff, CRTC_CURSOR_LO);
|
||||
}
|
||||
|
||||
struct console_driver vga_console __console_driver = {
|
||||
.putchar = vga_putc,
|
||||
.disabled = CONSOLE_DISABLED,
|
||||
.usage = CONSOLE_DIRECT_VGA,
|
||||
};
|
||||
|
||||
struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = {
|
||||
.initialise = video_init,
|
||||
};
|
||||
145
src/arch/x86/core/virtaddr.S
Normal file
145
src/arch/x86/core/virtaddr.S
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Functions to support the virtual addressing method of relocation
|
||||
* that Etherboot uses.
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
|
||||
|
||||
#include "librm.h"
|
||||
|
||||
.arch i386
|
||||
.text
|
||||
.code32
|
||||
|
||||
/****************************************************************************
|
||||
* _virt_to_phys (virtual addressing)
|
||||
*
|
||||
* Switch from virtual to flat physical addresses. %esp is adjusted
|
||||
* to a physical value. Segment registers are set to flat physical
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _virt_to_phys
|
||||
_virt_to_phys:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Change return address to a physical address */
|
||||
movl virt_offset, %ebp
|
||||
addl %ebp, 12(%esp)
|
||||
|
||||
/* Switch to physical code segment */
|
||||
cli
|
||||
pushl $PHYSICAL_CS
|
||||
leal 1f(%ebp), %eax
|
||||
pushl %eax
|
||||
lret
|
||||
1:
|
||||
/* Reload other segment registers and adjust %esp */
|
||||
movl $PHYSICAL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
movl %eax, %ss
|
||||
addl %ebp, %esp
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* _phys_to_virt (flat physical addressing)
|
||||
*
|
||||
* Switch from flat physical to virtual addresses. %esp is adjusted
|
||||
* to a virtual value. Segment registers are set to virtual
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _phys_to_virt
|
||||
_phys_to_virt:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Switch to virtual code segment */
|
||||
cli
|
||||
ljmp $VIRTUAL_CS, $1f
|
||||
1:
|
||||
/* Reload data segment registers */
|
||||
movl $VIRTUAL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
|
||||
/* Reload stack segment and adjust %esp */
|
||||
movl virt_offset, %ebp
|
||||
movl %eax, %ss
|
||||
subl %ebp, %esp
|
||||
|
||||
/* Change the return address to a virtual address */
|
||||
subl %ebp, 12(%esp)
|
||||
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
|
||||
/****************************************************************************
|
||||
* _intr_to_virt (virtual code segment, virtual or physical stack segment)
|
||||
*
|
||||
* Switch from virtual code segment with either a virtual or physical
|
||||
* stack segment to using virtual addressing. %esp is adjusted if
|
||||
* necessary to a virtual value. Segment registers are set to virtual
|
||||
* selectors. All other registers are preserved. Flags are
|
||||
* preserved.
|
||||
*
|
||||
* Parameters: none
|
||||
* Returns: none
|
||||
****************************************************************************
|
||||
*/
|
||||
.globl _intr_to_virt
|
||||
_intr_to_virt:
|
||||
/* Preserve registers and flags */
|
||||
pushfl
|
||||
pushl %eax
|
||||
pushl %ebp
|
||||
|
||||
/* Check whether stack segment is physical or virtual */
|
||||
movl %ss, %eax
|
||||
cmpw $VIRTUAL_DS, %ax
|
||||
movl $VIRTUAL_DS, %eax
|
||||
|
||||
/* Reload data segment registers */
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
|
||||
/* Reload stack segment and adjust %esp if necessary */
|
||||
je 1f
|
||||
movl virt_offset, %ebp
|
||||
movl %eax, %ss
|
||||
subl %ebp, %esp
|
||||
1:
|
||||
/* Restore registers and flags, and return */
|
||||
popl %ebp
|
||||
popl %eax
|
||||
popfl
|
||||
ret
|
||||
Reference in New Issue
Block a user