2
0
mirror of https://github.com/xcat2/xNBA.git synced 2026-04-24 21:51:28 +00:00
Conflicts:
	src/config/general.h
This commit is contained in:
Jarrod Johnson
2013-04-09 16:51:14 -04:00
552 changed files with 25918 additions and 5553 deletions

View File

@@ -179,7 +179,12 @@ if ( $embedded_script != "" ) {
// Make the requested image. $status is set to 0 on success
$make_target = "bin/${nic}.${fmt_extension}";
$make_cmd = "make -C '$build_dir' '$make_target' $emb_script_cmd 2>&1";
$gitversion = exec('git describe --always --abbrev=1 --match "" 2>/dev/null');
if ($gitversion) {
$gitversion = "GITVERSION=$gitversion";
}
$make_cmd = "make -C '$build_dir' '$make_target' $gitversion $emb_script_cmd 2>&1";
exec ( $make_cmd, $maketxt, $status );
@@ -239,7 +244,7 @@ if ( $status == 0 ) {
// Delete build directory as soon as it is not needed
rm_build_dir ();
$output_filename = "ipxe-${version}-${nic}.${fmt_extension}";
$output_filename = preg_replace('/[^a-z0-9\+\.\-]/i', '', "ipxe-${version}-${nic}.${fmt_extension}");
// Try to force IE to handle downloading right.
Header ( "Cache-control: private");

View File

@@ -109,6 +109,16 @@ $flag_table = array (
"cfgsec" => "console"
),
"LOG_LEVEL"
=> array (
"flag" => "LOG_LEVEL",
"type" => "choice",
"options" => array("LOG_NONE","LOG_EMERG","LOG_ALERT","LOG_CRIT","LOG_ERR",
"LOG_WARNING","LOG_NOTICE","LOG_INFO","LOG_DEBUG","LOG_ALL"),
"value" => "LOG_NONE",
"cfgsec" => "console"
),
// End Console Options
// Begin Network Protocol Options:

File diff suppressed because it is too large Load Diff

View File

@@ -143,7 +143,25 @@ everything :
bin-i386-efi/ipxe.efirom \
bin-x86_64-efi/ipxe.efi bin-x86_64-efi/ipxe.efidrv \
bin-x86_64-efi/ipxe.efirom \
bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux
bin-i386-linux/tap.linux bin-x86_64-linux/tap.linux \
bin-i386-linux/tests.linux bin-x86_64-linux/tests.linux
###############################################################################
#
# VMware build target: all ROMs used with VMware
#
vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
@$(ECHO) '==========================================================='
@$(ECHO)
@$(ECHO) 'Available ROMs:'
@$(ECHO) ' bin/8086100f.mrom -- intel/e1000'
@$(ECHO) ' bin/808610d3.mrom -- intel/e1000e'
@$(ECHO) ' bin/10222000.rom -- vlance/pcnet32'
@$(ECHO) ' bin/15ad07b0.rom -- vmxnet3'
@$(ECHO)
@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
@$(ECHO)
@$(ECHO) '==========================================================='
###############################################################################
#
@@ -165,13 +183,12 @@ VERSION_PATCH = 3
EXTRAVERSION = -$(shell date +%y%m%d)
MM_VERSION = $(VERSION_MAJOR).$(VERSION_MINOR)
VERSION = $(MM_VERSION).$(VERSION_PATCH)$(EXTRAVERSION)
CFLAGS += -DVERSION_MAJOR=$(VERSION_MAJOR) \
-DVERSION_MINOR=$(VERSION_MINOR) \
-DVERSION_PATCH=$(VERSION_PATCH) \
-DVERSION=\"$(VERSION)\"
IDENT = '$(@F) $(VERSION) (GPL) ipxe.org'
GITVERSION := $(shell git describe --always --abbrev=1 --match "" 2>/dev/null)
ifneq ($(GITVERSION),)
VERSION += ($(GITVERSION))
endif
version :
@$(ECHO) $(VERSION)
@$(ECHO) "$(VERSION)"
###############################################################################
#

View File

@@ -162,9 +162,12 @@ endif
# output of "size". Inhibit this.
#
ifeq ($(CCTYPE),gcc)
CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -x c -c /dev/null \
CFI_TEST = $(CC) -fno-dwarf2-cfi-asm -fno-exceptions -fno-unwind-tables \
-fno-asynchronous-unwind-tables -x c -c /dev/null \
-o /dev/null >/dev/null 2>&1
CFI_FLAGS := $(shell $(CFI_TEST) && $(ECHO) '-fno-dwarf2-cfi-asm')
CFI_FLAGS := $(shell $(CFI_TEST) && \
$(ECHO) '-fno-dwarf2-cfi-asm -fno-exceptions ' \
'-fno-unwind-tables -fno-asynchronous-unwind-tables')
WORKAROUND_CFLAGS += $(CFI_FLAGS)
endif
@@ -608,36 +611,39 @@ CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"")
# (Single-element) list of client private keys
#
KEY_LIST := $(BIN)/.private_key.list
ifeq ($(wildcard $(KEY_LIST)),)
KEY_OLD := <invalid>
ifdef KEY
PRIVKEY := $(KEY) # Maintain backwards compatibility
endif
PRIVKEY_LIST := $(BIN)/.private_key.list
ifeq ($(wildcard $(PRIVKEY_LIST)),)
PRIVKEY_OLD := <invalid>
else
KEY_OLD := $(shell cat $(KEY_LIST))
PRIVKEY_OLD := $(shell cat $(PRIVKEY_LIST))
endif
ifneq ($(KEY_OLD),$(KEY))
$(shell $(ECHO) "$(KEY)" > $(KEY_LIST))
ifneq ($(PRIVKEY_OLD),$(PRIVKEY))
$(shell $(ECHO) "$(PRIVKEY)" > $(PRIVKEY_LIST))
endif
$(KEY_LIST) :
$(PRIVKEY_LIST) :
VERYCLEANUP += $(KEY_LIST)
VERYCLEANUP += $(PRIVKEY_LIST)
# Embedded client private key
#
KEY_INC := $(BIN)/.private_key.der
PRIVKEY_INC := $(BIN)/.private_key.der
ifdef KEY
$(KEY_INC) : $(KEY) $(KEY_LIST)
ifdef PRIVKEY
$(PRIVKEY_INC) : $(PRIVKEY) $(PRIVKEY_LIST)
$(Q)$(OPENSSL) rsa -in $< -outform DER -out $@
clientcert_DEPS += $(KEY_INC)
clientcert_DEPS += $(PRIVKEY_INC)
endif
CLEANUP += $(KEY_INC)
CLEANUP += $(PRIVKEY_INC)
clientcert_DEPS += $(KEY_LIST)
clientcert_DEPS += $(PRIVKEY_LIST)
CFLAGS_clientcert += $(if $(KEY),-DPRIVATE_KEY="\"$(KEY_INC)\"")
CFLAGS_clientcert += $(if $(PRIVKEY),-DPRIVATE_KEY="\"$(PRIVKEY_INC)\"")
# These files use .incbin inline assembly to include a binary file.
# Unfortunately ccache does not detect this dependency and caches
@@ -647,6 +653,17 @@ $(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC)
$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC)
# Version number
#
CFLAGS_version += -DVERSION_MAJOR=$(VERSION_MAJOR) \
-DVERSION_MINOR=$(VERSION_MINOR) \
-DVERSION_PATCH=$(VERSION_PATCH) \
-DVERSION="\"$(VERSION)\""
# Make sure the version number gets updated on every git checkout
ifneq ($(GITVERSION),)
$(BIN)/version.o : ../.git/index
endif
# We automatically generate rules for any file mentioned in AUTO_SRCS
# using the following set of templates. It would be cleaner to use
# $(eval ...), but this function exists only in GNU make >= 3.80.
@@ -660,7 +677,7 @@ $(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC)
define deps_template
@$(ECHO) " [DEPS] $(1)"
@$(MKDIR) -p $(BIN)/deps/$(dir $(1))
@$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
$(Q)$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \
-Wno-error -M $(1) -MG -MP | \
sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d
endef

View File

@@ -54,6 +54,8 @@ CFLAGS += -m32
ASFLAGS += --32
ifeq ($(HOST_OS),FreeBSD)
LDFLAGS += -m elf_i386_fbsd
else ifeq ($(HOST_OS),OpenBSD)
LDFLAGS += -m elf_i386_obsd
else
LDFLAGS += -m elf_i386
endif

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -1,73 +0,0 @@
#include <stdint.h>
#include <string.h>
#include <cpu.h>
/** @file
*
* CPU identification
*
*/
/**
* Test to see if CPU flag is changeable
*
* @v flag Flag to test
* @ret can_change Flag is changeable
*/
static inline int flag_is_changeable ( unsigned int flag ) {
uint32_t f1, f2;
__asm__ ( "pushfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"movl %0,%1\n\t"
"xorl %2,%0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"popfl\n\t"
: "=&r" ( f1 ), "=&r" ( f2 )
: "ir" ( flag ) );
return ( ( ( f1 ^ f2 ) & flag ) != 0 );
}
/**
* Get CPU information
*
* @v cpu CPU information structure to fill in
*/
void get_cpuinfo ( struct cpuinfo_x86 *cpu ) {
unsigned int cpuid_level;
unsigned int cpuid_extlevel;
unsigned int discard_1, discard_2, discard_3;
memset ( cpu, 0, sizeof ( *cpu ) );
/* Check for CPUID instruction */
if ( ! flag_is_changeable ( X86_EFLAGS_ID ) ) {
DBG ( "CPUID not supported\n" );
return;
}
/* Get features, if present */
cpuid ( 0x00000000, &cpuid_level, &discard_1,
&discard_2, &discard_3 );
if ( cpuid_level >= 0x00000001 ) {
cpuid ( 0x00000001, &discard_1, &discard_2,
&discard_3, &cpu->features );
} else {
DBG ( "CPUID cannot return capabilities\n" );
}
/* Get 64-bit features, if present */
cpuid ( 0x80000000, &cpuid_extlevel, &discard_1,
&discard_2, &discard_3 );
if ( ( cpuid_extlevel & 0xffff0000 ) == 0x80000000 ) {
if ( cpuid_extlevel >= 0x80000001 ) {
cpuid ( 0x80000001, &discard_1, &discard_2,
&discard_3, &cpu->amd_features );
}
}
}

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -33,8 +33,10 @@ extern char _etextdata[];
/**
* Relocate iPXE
*
* @v ix86 x86 register dump from prefix
* @ret ix86 x86 registers to return to prefix
* @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
@@ -59,7 +61,7 @@ __asmcall void relocate ( struct i386_all_regs *ix86 ) {
/* Determine maximum usable address */
max = MAX_ADDR;
if ( ix86->regs.ebp && ( ix86->regs.ebp < max ) ) {
if ( ix86->regs.ebp < max ) {
max = ix86->regs.ebp;
DBG ( "Limiting relocation to [0,%lx)\n", max );
}

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -70,6 +71,9 @@ struct undi_nic {
/** Delay between retries of PXENV_UNDI_INITIALIZE */
#define UNDI_INITIALIZE_RETRY_DELAY_MS 200
/** Alignment of received frame payload */
#define UNDI_RX_ALIGN 16
static void undinet_close ( struct net_device *netdev );
/** Address of UNDI entry point */
@@ -299,6 +303,7 @@ static void undinet_poll ( struct net_device *netdev ) {
struct s_PXENV_UNDI_ISR undi_isr;
struct io_buffer *iobuf = NULL;
size_t len;
size_t reserve_len;
size_t frag_len;
size_t max_frag_len;
int rc;
@@ -340,6 +345,8 @@ static void undinet_poll ( struct net_device *netdev ) {
/* Packet fragment received */
len = undi_isr.FrameLength;
frag_len = undi_isr.BufferLength;
reserve_len = ( -undi_isr.FrameHeaderLength &
( UNDI_RX_ALIGN - 1 ) );
if ( ( len == 0 ) || ( len < frag_len ) ) {
/* Don't laugh. VMWare does it. */
DBGC ( undinic, "UNDINIC %p reported insane "
@@ -348,15 +355,17 @@ static void undinet_poll ( struct net_device *netdev ) {
netdev_rx_err ( netdev, NULL, -EINVAL );
break;
}
if ( ! iobuf )
iobuf = alloc_iob ( len );
if ( ! iobuf ) {
DBGC ( undinic, "UNDINIC %p could not "
"allocate %zd bytes for RX buffer\n",
undinic, len );
/* Fragment will be dropped */
netdev_rx_err ( netdev, NULL, -ENOMEM );
goto done;
iobuf = alloc_iob ( reserve_len + len );
if ( ! iobuf ) {
DBGC ( undinic, "UNDINIC %p could not "
"allocate %zd bytes for RX "
"buffer\n", undinic, len );
/* Fragment will be dropped */
netdev_rx_err ( netdev, NULL, -ENOMEM );
goto done;
}
iob_reserve ( iobuf, reserve_len );
}
max_frag_len = iob_tailroom ( iobuf );
if ( frag_len > max_frag_len ) {
@@ -516,6 +525,53 @@ static struct net_device_operations undinet_operations = {
.irq = undinet_irq,
};
/** A device with broken support for generating interrupts */
struct undinet_irq_broken {
/** PCI vendor ID */
uint16_t pci_vendor;
/** PCI device ID */
uint16_t pci_device;
};
/**
* List of devices with broken support for generating interrupts
*
* Some PXE stacks are known to claim that IRQs are supported, but
* then never generate interrupts. No satisfactory solution has been
* found to this problem; the workaround is to add the PCI vendor and
* device IDs to this list. This is something of a hack, since it
* will generate false positives for identical devices with a working
* PXE stack (e.g. those that have been reflashed with iPXE), but it's
* an improvement on the current situation.
*/
static const struct undinet_irq_broken undinet_irq_broken_list[] = {
/* HP XX70x laptops */
{ .pci_vendor = 0x8086, .pci_device = 0x1502 },
{ .pci_vendor = 0x8086, .pci_device = 0x1503 },
};
/**
* Check for devices with broken support for generating interrupts
*
* @v undi UNDI device
* @ret irq_is_broken Interrupt support is broken; no interrupts are generated
*/
static int undinet_irq_is_broken ( struct undi_device *undi ) {
const struct undinet_irq_broken *broken;
unsigned int i;
for ( i = 0 ; i < ( sizeof ( undinet_irq_broken_list ) /
sizeof ( undinet_irq_broken_list[0] ) ) ; i++ ) {
broken = &undinet_irq_broken_list[i];
if ( ( undi->dev.desc.bus_type == BUS_TYPE_PCI ) &&
( undi->dev.desc.vendor == broken->pci_vendor ) &&
( undi->dev.desc.device == broken->pci_device ) ) {
return 1;
}
}
return 0;
}
/**
* Probe UNDI device
*
@@ -632,6 +688,11 @@ int undinet_probe ( struct undi_device *undi ) {
undinic );
undinic->hacks |= UNDI_HACK_EB54;
}
if ( undinet_irq_is_broken ( undi ) ) {
DBGC ( undinic, "UNDINIC %p forcing polling mode due to "
"broken interrupts\n", undinic );
undinic->irq_supported = 0;
}
/* Register network device */
if ( ( rc = register_netdev ( netdev ) ) != 0 )

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER )

View File

@@ -12,7 +12,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -12,7 +12,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -189,6 +190,8 @@ static void hide_etherboot ( void ) {
* possible.
*/
static void unhide_etherboot ( int flags __unused ) {
struct memory_map memmap;
int rc;
/* If we have more than one hooked interrupt at this point, it
* means that some other vector is still hooked, in which case
@@ -202,15 +205,23 @@ static void unhide_etherboot ( int flags __unused ) {
return;
}
/* Try to unhook INT 15. If it fails, then just leave it
* hooked; it takes care of protecting itself. :)
*/
unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
&int15_vector );
/* Try to unhook INT 15 */
if ( ( rc = unhook_bios_interrupt ( 0x15, ( unsigned int ) int15,
&int15_vector ) ) != 0 ) {
DBG ( "Cannot unhook INT15: %s\n", strerror ( rc ) );
/* Leave it hooked; there's nothing else we can do,
* and it should be intrinsically safe (though
* wasteful of RAM).
*/
}
/* Unhook fake E820 map, if used */
if ( FAKE_E820 )
unfake_e820();
/* Dump memory map after unhiding */
DBG ( "Unhidden iPXE from system memory map\n" );
get_memmap ( &memmap );
}
/** Hide Etherboot startup function */

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -62,6 +63,10 @@ struct e820_entry {
static struct e820_entry __bss16 ( e820buf );
#define e820buf __use_data16 ( e820buf )
/** We are running during POST; inhibit INT 15,e820 and INT 15,e801 */
uint8_t __bss16 ( memmap_post );
#define memmap_post __use_data16 ( memmap_post )
/**
* Get size of extended memory via INT 15,e801
*
@@ -73,6 +78,12 @@ static unsigned int extmemsize_e801 ( void ) {
unsigned int flags;
unsigned int extmem;
/* Inhibit INT 15,e801 during POST */
if ( memmap_post ) {
DBG ( "INT 15,e801 not available during POST\n" );
return 0;
}
__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
"int $0x15\n\t"
"pushfw\n\t"
@@ -163,6 +174,12 @@ static int meme820 ( struct memory_map *memmap ) {
unsigned int flags;
unsigned int discard_D;
/* Inhibit INT 15,e820 during POST */
if ( memmap_post ) {
DBG ( "INT 15,e820 not available during POST\n" );
return -ENOTTY;
}
/* Clear the E820 buffer. Do this once before starting,
* rather than on each call; some BIOSes rely on the contents
* being preserved between calls.

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include <ipxe/netdevice.h>

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -79,9 +80,22 @@ int call_bootsector ( unsigned int segment, unsigned int offset,
"movw %%ss, %%ax\n\t"
"movw %%ax, %%cs:saved_ss\n\t"
"movw %%sp, %%cs:saved_sp\n\t"
/* Jump to boot sector */
/* Prepare jump to boot sector */
"pushw %%bx\n\t"
"pushw %%di\n\t"
/* Clear all registers */
"xorl %%eax, %%eax\n\t"
"xorl %%ebx, %%ebx\n\t"
"xorl %%ecx, %%ecx\n\t"
/* %edx contains drive number */
"xorl %%esi, %%esi\n\t"
"xorl %%edi, %%edi\n\t"
"xorl %%ebp, %%ebp\n\t"
"movw %%ax, %%ds\n\t"
"movw %%ax, %%es\n\t"
"movw %%ax, %%fs\n\t"
"movw %%ax, %%gs\n\t"
/* Jump to boot sector */
"sti\n\t"
"lret\n\t"
/* Preserved variables */

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -32,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <assert.h>
#include <realmode.h>
#include <bzimage.h>
#include <initrd.h>
#include <ipxe/uaccess.h>
#include <ipxe/image.h>
#include <ipxe/segment.h>
@@ -214,7 +216,8 @@ static void bzimage_update_header ( struct image *image,
} else {
bzimg->cmdline_magic.magic = BZI_CMDLINE_MAGIC;
bzimg->cmdline_magic.offset = bzimg->rm_cmdline;
bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
if ( bzimg->version >= 0x0200 )
bzimg->bzhdr.setup_move_size = bzimg->rm_memsz;
}
/* Set video mode */
@@ -302,11 +305,10 @@ static int bzimage_parse_cmdline ( struct image *image,
* @v image bzImage image
* @v bzimg bzImage context
* @v cmdline Kernel command line
* @ret rc Return status code
*/
static int bzimage_set_cmdline ( struct image *image,
struct bzimage_context *bzimg,
const char *cmdline ) {
static void bzimage_set_cmdline ( struct image *image,
struct bzimage_context *bzimg,
const char *cmdline ) {
size_t cmdline_len;
/* Copy command line down to real-mode portion */
@@ -316,8 +318,32 @@ static int bzimage_set_cmdline ( struct image *image,
copy_to_user ( bzimg->rm_kernel, bzimg->rm_cmdline,
cmdline, cmdline_len );
DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
}
return 0;
/**
* Parse standalone image command line for cpio parameters
*
* @v image bzImage file
* @v cpio CPIO header
* @v cmdline Command line
*/
static void bzimage_parse_cpio_cmdline ( struct image *image,
struct cpio_header *cpio,
const char *cmdline ) {
char *arg;
char *end;
unsigned int mode;
/* Look for "mode=" */
if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
arg += 5;
mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
if ( *end && ( *end != ' ' ) ) {
DBGC ( image, "bzImage %p strange \"mode=\""
"terminator '%c'\n", image, *end );
}
cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
}
}
/**
@@ -326,14 +352,17 @@ static int bzimage_set_cmdline ( struct image *image,
* @v image bzImage image
* @v initrd initrd image
* @v address Address at which to load, or UNULL
* @ret len Length of loaded image, rounded up to 4 bytes
* @ret len Length of loaded image, rounded up to INITRD_ALIGN
*/
static size_t bzimage_load_initrd ( struct image *image,
struct image *initrd,
userptr_t address ) {
char *filename = initrd->cmdline;
char *cmdline;
struct cpio_header cpio;
size_t offset = 0;
size_t name_len;
size_t pad_len;
/* Do not include kernel image itself as an initrd */
if ( initrd == image )
@@ -341,24 +370,28 @@ static size_t bzimage_load_initrd ( struct image *image,
/* Create cpio header before non-prebuilt images */
if ( filename && filename[0] ) {
size_t name_len = ( strlen ( filename ) + 1 );
DBGC ( image, "bzImage %p inserting initrd %p as %s\n",
image, initrd, filename );
cmdline = strchr ( filename, ' ' );
name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
: strlen ( filename ) ) + 1 /* NUL */ );
memset ( &cpio, '0', sizeof ( cpio ) );
memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
cpio_set_field ( cpio.c_mode, 0100644 );
cpio_set_field ( cpio.c_nlink, 1 );
cpio_set_field ( cpio.c_filesize, initrd->len );
cpio_set_field ( cpio.c_namesize, name_len );
if ( cmdline ) {
bzimage_parse_cpio_cmdline ( image, &cpio,
( cmdline + 1 /* ' ' */ ));
}
if ( address ) {
copy_to_user ( address, offset, &cpio,
sizeof ( cpio ) );
}
offset += sizeof ( cpio );
if ( address ) {
memset_user ( address, offset, 0, name_len );
copy_to_user ( address, offset, filename,
name_len );
( name_len - 1 /* NUL (or space) */ ) );
}
offset += name_len;
offset = ( ( offset + 0x03 ) & ~0x03 );
@@ -366,17 +399,82 @@ static size_t bzimage_load_initrd ( struct image *image,
/* Copy in initrd image body */
if ( address )
memcpy_user ( address, offset, initrd->data, 0, initrd->len );
offset += initrd->len;
memmove_user ( address, offset, initrd->data, 0, initrd->len );
if ( address ) {
DBGC ( image, "bzImage %p has initrd %p at [%lx,%lx)\n",
image, initrd, user_to_phys ( address, 0 ),
user_to_phys ( address, offset ) );
DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
"%s%s\n", image, initrd, user_to_phys ( address, 0 ),
user_to_phys ( address, offset ),
user_to_phys ( address, ( offset + initrd->len ) ),
( filename ? " " : "" ), ( filename ? filename : "" ) );
DBGC2_MD5A ( image, user_to_phys ( address, offset ),
user_to_virt ( address, offset ), initrd->len );
}
offset += initrd->len;
/* Round up to multiple of INITRD_ALIGN and zero-pad */
pad_len = ( ( -offset ) & ( INITRD_ALIGN - 1 ) );
if ( address )
memset_user ( address, offset, 0, pad_len );
offset += pad_len;
return offset;
}
/**
* Check that initrds can be loaded
*
* @v image bzImage image
* @v bzimg bzImage context
* @ret rc Return status code
*/
static int bzimage_check_initrds ( struct image *image,
struct bzimage_context *bzimg ) {
struct image *initrd;
userptr_t bottom;
size_t len = 0;
int rc;
/* Calculate total loaded length of initrds */
for_each_image ( initrd ) {
/* Skip kernel */
if ( initrd == image )
continue;
/* Calculate length */
len += bzimage_load_initrd ( image, initrd, UNULL );
DBGC ( image, "bzImage %p initrd %p from [%#08lx,%#08lx)%s%s\n",
image, initrd, user_to_phys ( initrd->data, 0 ),
user_to_phys ( initrd->data, initrd->len ),
( initrd->cmdline ? " " : "" ),
( initrd->cmdline ? initrd->cmdline : "" ) );
DBGC2_MD5A ( image, user_to_phys ( initrd->data, 0 ),
user_to_virt ( initrd->data, 0 ), initrd->len );
}
/* Round up to 4-byte boundary */
offset = ( ( offset + 0x03 ) & ~0x03 );
return offset;
/* Calculate lowest usable address */
bottom = userptr_add ( bzimg->pm_kernel, bzimg->pm_sz );
/* Check that total length fits within space available for
* reshuffling. This is a conservative check, since CPIO
* headers are not present during reshuffling, but this
* doesn't hurt and keeps the code simple.
*/
if ( ( rc = initrd_reshuffle_check ( len, bottom ) ) != 0 ) {
DBGC ( image, "bzImage %p failed reshuffle check: %s\n",
image, strerror ( rc ) );
return rc;
}
/* Check that total length fits within kernel's memory limit */
if ( user_to_phys ( bottom, len ) > bzimg->mem_limit ) {
DBGC ( image, "bzImage %p not enough space for initrds\n",
image );
return -ENOBUFS;
}
return 0;
}
/**
@@ -384,62 +482,63 @@ static size_t bzimage_load_initrd ( struct image *image,
*
* @v image bzImage image
* @v bzimg bzImage context
* @ret rc Return status code
*/
static int bzimage_load_initrds ( struct image *image,
struct bzimage_context *bzimg ) {
static void bzimage_load_initrds ( struct image *image,
struct bzimage_context *bzimg ) {
struct image *initrd;
size_t total_len = 0;
physaddr_t address;
int rc;
struct image *highest = NULL;
struct image *other;
userptr_t top;
userptr_t dest;
size_t len;
/* Add up length of all initrd images */
for_each_image ( initrd )
total_len += bzimage_load_initrd ( image, initrd, UNULL );
/* Reshuffle initrds into desired order */
initrd_reshuffle ( userptr_add ( bzimg->pm_kernel, bzimg->pm_sz ) );
/* Give up if no initrd images found */
if ( ! total_len )
return 0;
/* Find a suitable start address. Try 1MB boundaries,
* starting from the downloaded kernel image itself and
* working downwards until we hit an available region.
*/
for ( address = ( user_to_phys ( image->data, 0 ) & ~0xfffff ) ; ;
address -= 0x100000 ) {
/* Check that we're not going to overwrite the
* kernel itself. This check isn't totally
* accurate, but errs on the side of caution.
*/
if ( address <= ( BZI_LOAD_HIGH_ADDR + image->len ) ) {
DBGC ( image, "bzImage %p could not find a location "
"for initrd\n", image );
return -ENOBUFS;
}
/* Check that we are within the kernel's range */
if ( ( address + total_len - 1 ) > bzimg->mem_limit )
continue;
/* Prepare and verify segment */
if ( ( rc = prep_segment ( phys_to_user ( address ), 0,
total_len ) ) != 0 )
continue;
/* Use this address */
break;
}
/* Record initrd location */
bzimg->ramdisk_image = address;
bzimg->ramdisk_size = total_len;
/* Construct initrd */
DBGC ( image, "bzImage %p constructing initrd at [%lx,%lx)\n",
image, address, ( address + total_len ) );
/* Find highest initrd */
for_each_image ( initrd ) {
address += bzimage_load_initrd ( image, initrd,
phys_to_user ( address ) );
if ( ( highest == NULL ) ||
( userptr_sub ( initrd->data, highest->data ) > 0 ) ) {
highest = initrd;
}
}
return 0;
/* Do nothing if there are no initrds */
if ( ! highest )
return;
/* Find highest usable address */
top = userptr_add ( highest->data,
( ( highest->len + INITRD_ALIGN - 1 ) &
~( INITRD_ALIGN - 1 ) ) );
if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
top = phys_to_user ( bzimg->mem_limit );
DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
image, user_to_phys ( top, 0 ) );
/* Load initrds in order */
for_each_image ( initrd ) {
/* Calculate cumulative length of following
* initrds (including padding).
*/
len = 0;
for_each_image ( other ) {
if ( other == initrd )
len = 0;
len += bzimage_load_initrd ( image, other, UNULL );
}
/* Load initrd at this address */
dest = userptr_add ( top, -len );
bzimage_load_initrd ( image, initrd, dest );
/* Record initrd location */
if ( ! bzimg->ramdisk_image ) {
bzimg->ramdisk_image = user_to_phys ( dest, 0 );
bzimg->ramdisk_size = len;
}
}
}
/**
@@ -472,33 +571,37 @@ static int bzimage_exec ( struct image *image ) {
return rc;
}
/* Parse command line for bootloader parameters */
if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
return rc;
/* Check that initrds can be loaded */
if ( ( rc = bzimage_check_initrds ( image, &bzimg ) ) != 0 )
return rc;
/* Remove kernel from image list (without invalidating image pointer) */
unregister_image ( image_get ( image ) );
/* Load segments */
memcpy_user ( bzimg.rm_kernel, 0, image->data,
0, bzimg.rm_filesz );
memcpy_user ( bzimg.pm_kernel, 0, image->data,
bzimg.rm_filesz, bzimg.pm_sz );
/* Update and write out header */
bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
/* Parse command line for bootloader parameters */
if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
return rc;
/* Store command line */
if ( ( rc = bzimage_set_cmdline ( image, &bzimg, cmdline ) ) != 0 )
return rc;
bzimage_set_cmdline ( image, &bzimg, cmdline );
/* Prepare for exiting. Must do this before loading initrds,
* since loading the initrds will corrupt the external heap.
*/
shutdown_boot();
/* Load any initrds */
if ( ( rc = bzimage_load_initrds ( image, &bzimg ) ) != 0 )
return rc;
bzimage_load_initrds ( image, &bzimg );
/* Update kernel header */
bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
/* Prepare for exiting */
shutdown_boot();
DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
"(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ),
bzimg.rm_kernel_seg, bzimg.rm_heap );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
@@ -228,7 +229,7 @@ static int comboot_identify ( struct image *image ) {
++ext;
if ( strcasecmp( ext, "com" ) && strcasecmp( ext, "cbt" ) ) {
if ( strcasecmp( ext, "cbt" ) ) {
DBGC ( image, "COMBOOT %p: unrecognized extension %s\n",
image, ext );
return -ENOEXEC;

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -0,0 +1,300 @@
/*
* Copyright (C) 2012 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 (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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <errno.h>
#include <initrd.h>
#include <ipxe/image.h>
#include <ipxe/uaccess.h>
#include <ipxe/init.h>
#include <ipxe/memblock.h>
/** @file
*
* Initial ramdisk (initrd) reshuffling
*
*/
/** Maximum address available for initrd */
userptr_t initrd_top;
/** Minimum address available for initrd */
userptr_t initrd_bottom;
/**
* Squash initrds as high as possible in memory
*
* @v top Highest possible address
* @ret used Lowest address used by initrds
*/
static userptr_t initrd_squash_high ( userptr_t top ) {
userptr_t current = top;
struct image *initrd;
struct image *highest;
size_t len;
/* Squash up any initrds already within or below the region */
while ( 1 ) {
/* Find the highest image not yet in its final position */
highest = NULL;
for_each_image ( initrd ) {
if ( ( userptr_sub ( initrd->data, current ) < 0 ) &&
( ( highest == NULL ) ||
( userptr_sub ( initrd->data,
highest->data ) > 0 ) ) ) {
highest = initrd;
}
}
if ( ! highest )
break;
/* Move this image to its final position */
len = ( ( highest->len + INITRD_ALIGN - 1 ) &
~( INITRD_ALIGN - 1 ) );
current = userptr_sub ( current, len );
DBGC ( &images, "INITRD squashing %s [%#08lx,%#08lx)->"
"[%#08lx,%#08lx)\n", highest->name,
user_to_phys ( highest->data, 0 ),
user_to_phys ( highest->data, highest->len ),
user_to_phys ( current, 0 ),
user_to_phys ( current, highest->len ) );
memmove_user ( current, 0, highest->data, 0, highest->len );
highest->data = current;
}
/* Copy any remaining initrds (e.g. embedded images) to the region */
for_each_image ( initrd ) {
if ( userptr_sub ( initrd->data, top ) >= 0 ) {
len = ( ( initrd->len + INITRD_ALIGN - 1 ) &
~( INITRD_ALIGN - 1 ) );
current = userptr_sub ( current, len );
DBGC ( &images, "INITRD copying %s [%#08lx,%#08lx)->"
"[%#08lx,%#08lx)\n", initrd->name,
user_to_phys ( initrd->data, 0 ),
user_to_phys ( initrd->data, initrd->len ),
user_to_phys ( current, 0 ),
user_to_phys ( current, initrd->len ) );
memcpy_user ( current, 0, initrd->data, 0,
initrd->len );
initrd->data = current;
}
}
return current;
}
/**
* Swap position of two adjacent initrds
*
* @v low Lower initrd
* @v high Higher initrd
* @v free Free space
* @v free_len Length of free space
*/
static void initrd_swap ( struct image *low, struct image *high,
userptr_t free, size_t free_len ) {
size_t len = 0;
size_t frag_len;
size_t new_len;
DBGC ( &images, "INITRD swapping %s [%#08lx,%#08lx)<->[%#08lx,%#08lx) "
"%s\n", low->name, user_to_phys ( low->data, 0 ),
user_to_phys ( low->data, low->len ),
user_to_phys ( high->data, 0 ),
user_to_phys ( high->data, high->len ), high->name );
/* Round down length of free space */
free_len &= ~( INITRD_ALIGN - 1 );
assert ( free_len > 0 );
/* Swap image data */
while ( len < high->len ) {
/* Calculate maximum fragment length */
frag_len = ( high->len - len );
if ( frag_len > free_len )
frag_len = free_len;
new_len = ( ( len + frag_len + INITRD_ALIGN - 1 ) &
~( INITRD_ALIGN - 1 ) );
/* Swap fragments */
memcpy_user ( free, 0, high->data, len, frag_len );
memmove_user ( low->data, new_len, low->data, len, low->len );
memcpy_user ( low->data, len, free, 0, frag_len );
len = new_len;
}
/* Adjust data pointers */
high->data = low->data;
low->data = userptr_add ( low->data, len );
}
/**
* Swap position of any two adjacent initrds not currently in the correct order
*
* @v free Free space
* @v free_len Length of free space
* @ret swapped A pair of initrds was swapped
*/
static int initrd_swap_any ( userptr_t free, size_t free_len ) {
struct image *low;
struct image *high;
size_t padded_len;
userptr_t adjacent;
/* Find any pair of initrds that can be swapped */
for_each_image ( low ) {
/* Calculate location of adjacent image (if any) */
padded_len = ( ( low->len + INITRD_ALIGN - 1 ) &
~( INITRD_ALIGN - 1 ) );
adjacent = userptr_add ( low->data, padded_len );
/* Search for adjacent image */
for_each_image ( high ) {
/* If we have found the adjacent image, swap and exit */
if ( high->data == adjacent ) {
initrd_swap ( low, high, free, free_len );
return 1;
}
/* Stop search if all remaining potential
* adjacent images are already in the correct
* order.
*/
if ( high == low )
break;
}
}
/* Nothing swapped */
return 0;
}
/**
* Dump initrd locations (for debug)
*
*/
static void initrd_dump ( void ) {
struct image *initrd;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return;
/* Dump initrd locations */
for_each_image ( initrd ) {
DBGC ( &images, "INITRD %s at [%#08lx,%#08lx)\n",
initrd->name, user_to_phys ( initrd->data, 0 ),
user_to_phys ( initrd->data, initrd->len ) );
DBGC2_MD5A ( &images, user_to_phys ( initrd->data, 0 ),
user_to_virt ( initrd->data, 0 ), initrd->len );
}
}
/**
* Reshuffle initrds into desired order at top of memory
*
* @v bottom Lowest address available for initrds
*
* After this function returns, the initrds have been rearranged in
* memory and the external heap structures will have been corrupted.
* Reshuffling must therefore take place immediately prior to jumping
* to the loaded OS kernel; no further execution within iPXE is
* permitted.
*/
void initrd_reshuffle ( userptr_t bottom ) {
userptr_t top;
userptr_t used;
userptr_t free;
size_t free_len;
/* Calculate limits of available space for initrds */
top = initrd_top;
if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
bottom = initrd_bottom;
/* Debug */
DBGC ( &images, "INITRD region [%#08lx,%#08lx)\n",
user_to_phys ( bottom, 0 ), user_to_phys ( top, 0 ) );
initrd_dump();
/* Squash initrds as high as possible in memory */
used = initrd_squash_high ( top );
/* Calculate available free space */
free = bottom;
free_len = userptr_sub ( used, free );
/* Bubble-sort initrds into desired order */
while ( initrd_swap_any ( free, free_len ) ) {}
/* Debug */
initrd_dump();
}
/**
* Check that there is enough space to reshuffle initrds
*
* @v len Total length of initrds (including padding)
* @v bottom Lowest address available for initrds
* @ret rc Return status code
*/
int initrd_reshuffle_check ( size_t len, userptr_t bottom ) {
userptr_t top;
size_t available;
/* Calculate limits of available space for initrds */
top = initrd_top;
if ( userptr_sub ( initrd_bottom, bottom ) > 0 )
bottom = initrd_bottom;
available = userptr_sub ( top, bottom );
/* Allow for a sensible minimum amount of free space */
len += INITRD_MIN_FREE_LEN;
/* Check for available space */
return ( ( len < available ) ? 0 : -ENOBUFS );
}
/**
* initrd startup function
*
*/
static void initrd_startup ( void ) {
size_t len;
/* Record largest memory block available. Do this after any
* allocations made during driver startup (e.g. large host
* memory blocks for Infiniband devices, which may still be in
* use at the time of rearranging if a SAN device is hooked)
* but before any allocations for downloaded images (which we
* can safely reuse when rearranging).
*/
len = largest_memblock ( &initrd_bottom );
initrd_top = userptr_add ( initrd_bottom, len );
}
/** initrd startup function */
struct startup_fn startup_initrd __startup_fn ( STARTUP_LATE ) = {
.startup = initrd_startup,
};

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -38,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/init.h>
#include <ipxe/features.h>
#include <ipxe/uri.h>
#include <ipxe/version.h>
FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
@@ -246,7 +248,7 @@ static struct multiboot_info __bss16 ( mbinfo );
#define mbinfo __use_data16 ( mbinfo )
/** The multiboot bootloader name */
static char __data16_array ( mb_bootloader_name, [] ) = "iPXE " VERSION;
static char __bss16_array ( mb_bootloader_name, [32] );
#define mb_bootloader_name __use_data16 ( mb_bootloader_name )
/** The multiboot memory map */
@@ -419,6 +421,8 @@ static int multiboot_exec ( struct image *image ) {
mbinfo.cmdline = multiboot_add_cmdline ( image );
mbinfo.mods_addr = virt_to_phys ( mbmodules );
mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
snprintf ( mb_bootloader_name, sizeof ( mb_bootloader_name ),
"iPXE %s", product_version );
mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
if ( ( rc = multiboot_add_modules ( image, max, &mbinfo, mbmodules,
( sizeof ( mbmodules ) /

View File

@@ -10,6 +10,7 @@
#include <ipxe/fakedhcp.h>
#include <ipxe/image.h>
#include <ipxe/features.h>
#include <ipxe/version.h>
/** @file
*
@@ -94,12 +95,6 @@ struct ebinfo {
uint16_t flags; /* Bit flags */
};
/** Info passed to NBI image */
static struct ebinfo loaderinfo = {
VERSION_MAJOR, VERSION_MINOR,
0
};
/**
* Prepare a segment for an NBI image
*
@@ -281,6 +276,10 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
* @ret rc Return status code, if image returns
*/
static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
struct ebinfo loaderinfo = {
product_major_version, product_minor_version,
0
};
int discard_D, discard_S, discard_b;
int rc;

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -35,6 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
/** PXE command line */
const char *pxe_cmdline;
/**
* Execute PXE image
*
@@ -62,16 +66,29 @@ static int pxe_exec ( struct image *image ) {
image );
return -ENODEV;
}
netdev_get ( netdev );
/* Activate PXE */
pxe_activate ( netdev );
/* Set PXE command line */
pxe_cmdline = image->cmdline;
/* Start PXE NBP */
rc = pxe_start_nbp();
/* Clear PXE command line */
pxe_cmdline = NULL;
/* Deactivate PXE */
pxe_deactivate();
/* Try to reopen network device. Ignore errors, since the NBP
* may have called PXENV_STOP_UNDI.
*/
netdev_open ( netdev );
netdev_put ( netdev );
return rc;
}

136
src/arch/i386/image/sdi.c Normal file
View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2012 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 (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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <realmode.h>
#include <sdi.h>
#include <ipxe/image.h>
#include <ipxe/features.h>
/** @file
*
* System Deployment Image (SDI)
*
* Based on the MSDN article "RAM boot using SDI in Windows XP
* Embedded with Service Pack 1", available at the time of writing
* from:
*
* http://msdn.microsoft.com/en-us/library/ms838543.aspx
*/
FEATURE ( FEATURE_IMAGE, "SDI", DHCP_EB_FEATURE_SDI, 1 );
/**
* Parse SDI image header
*
* @v image SDI file
* @v sdi SDI header to fill in
* @ret rc Return status code
*/
static int sdi_parse_header ( struct image *image, struct sdi_header *sdi ) {
/* Sanity check */
if ( image->len < sizeof ( *sdi ) ) {
DBGC ( image, "SDI %p too short for SDI header\n", image );
return -ENOEXEC;
}
/* Read in header */
copy_from_user ( sdi, image->data, 0, sizeof ( *sdi ) );
/* Check signature */
if ( sdi->magic != SDI_MAGIC ) {
DBGC ( image, "SDI %p is not an SDI image\n", image );
return -ENOEXEC;
}
return 0;
}
/**
* Execute SDI image
*
* @v image SDI file
* @ret rc Return status code
*/
static int sdi_exec ( struct image *image ) {
struct sdi_header sdi;
uint32_t sdiptr;
int rc;
/* Parse image header */
if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
return rc;
/* Check that image is bootable */
if ( sdi.boot_size == 0 ) {
DBGC ( image, "SDI %p is not bootable\n", image );
return -ENOTTY;
}
DBGC ( image, "SDI %p image at %08lx+%08zx\n",
image, user_to_phys ( image->data, 0 ), image->len );
DBGC ( image, "SDI %p boot code at %08lx+%llx\n", image,
user_to_phys ( image->data, sdi.boot_offset ), sdi.boot_size );
/* Copy boot code */
memcpy_user ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), 0,
image->data, sdi.boot_offset, sdi.boot_size );
/* Jump to boot code */
sdiptr = ( user_to_phys ( image->data, 0 ) | SDI_WTF );
__asm__ __volatile__ ( REAL_CODE ( "ljmp %0, %1\n\t" )
: : "i" ( SDI_BOOT_SEG ),
"i" ( SDI_BOOT_OFF ),
"d" ( sdiptr ) );
/* There is no way for the image to return, since we provide
* no return address.
*/
assert ( 0 );
return -ECANCELED; /* -EIMPOSSIBLE */
}
/**
* Probe SDI image
*
* @v image SDI file
* @ret rc Return status code
*/
static int sdi_probe ( struct image *image ) {
struct sdi_header sdi;
int rc;
/* Parse image */
if ( ( rc = sdi_parse_header ( image, &sdi ) ) != 0 )
return rc;
return 0;
}
/** SDI image type */
struct image_type sdi_image_type __image_type ( PROBE_NORMAL ) = {
.name = "SDI",
.probe = sdi_probe,
.exec = sdi_exec,
};

View File

@@ -6,6 +6,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define BDA_SEG 0x0040
#define BDA_EQUIPMENT_WORD 0x0010
#define BDA_FBMS 0x0013
#define BDA_REBOOT 0x0072
#define BDA_REBOOT_WARM 0x1234
#define BDA_NUM_DRIVES 0x0075
#endif /* BIOS_H */

View File

@@ -53,8 +53,8 @@ __bswap_variable_64 ( uint64_t x ) {
static inline __attribute__ (( always_inline )) void
__bswap_64s ( uint64_t *x ) {
struct {
uint32_t low;
uint32_t high;
uint32_t __attribute__ (( may_alias )) low;
uint32_t __attribute__ (( may_alias )) high;
} __attribute__ (( may_alias )) *dwords = ( ( void * ) x );
uint32_t discard;

View File

@@ -1,86 +0,0 @@
#ifndef I386_BITS_CPU_H
#define I386_BITS_CPU_H
/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
#define X86_FEATURE_FPU 0 /* Onboard FPU */
#define X86_FEATURE_VME 1 /* Virtual Mode Extensions */
#define X86_FEATURE_DE 2 /* Debugging Extensions */
#define X86_FEATURE_PSE 3 /* Page Size Extensions */
#define X86_FEATURE_TSC 4 /* Time Stamp Counter */
#define X86_FEATURE_MSR 5 /* Model-Specific Registers, RDMSR, WRMSR */
#define X86_FEATURE_PAE 6 /* Physical Address Extensions */
#define X86_FEATURE_MCE 7 /* Machine Check Architecture */
#define X86_FEATURE_CX8 8 /* CMPXCHG8 instruction */
#define X86_FEATURE_APIC 9 /* Onboard APIC */
#define X86_FEATURE_SEP 11 /* SYSENTER/SYSEXIT */
#define X86_FEATURE_MTRR 12 /* Memory Type Range Registers */
#define X86_FEATURE_PGE 13 /* Page Global Enable */
#define X86_FEATURE_MCA 14 /* Machine Check Architecture */
#define X86_FEATURE_CMOV 15 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
#define X86_FEATURE_PAT 16 /* Page Attribute Table */
#define X86_FEATURE_PSE36 17 /* 36-bit PSEs */
#define X86_FEATURE_PN 18 /* Processor serial number */
#define X86_FEATURE_CLFLSH 19 /* Supports the CLFLUSH instruction */
#define X86_FEATURE_DTES 21 /* Debug Trace Store */
#define X86_FEATURE_ACPI 22 /* ACPI via MSR */
#define X86_FEATURE_MMX 23 /* Multimedia Extensions */
#define X86_FEATURE_FXSR 24 /* FXSAVE and FXRSTOR instructions (fast save and restore */
/* of FPU context), and CR4.OSFXSR available */
#define X86_FEATURE_XMM 25 /* Streaming SIMD Extensions */
#define X86_FEATURE_XMM2 26 /* Streaming SIMD Extensions-2 */
#define X86_FEATURE_SELFSNOOP 27 /* CPU self snoop */
#define X86_FEATURE_HT 28 /* Hyper-Threading */
#define X86_FEATURE_ACC 29 /* Automatic clock control */
#define X86_FEATURE_IA64 30 /* IA-64 processor */
/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
/* Don't duplicate feature flags which are redundant with Intel! */
#define X86_FEATURE_SYSCALL 11 /* SYSCALL/SYSRET */
#define X86_FEATURE_MMXEXT 22 /* AMD MMX extensions */
#define X86_FEATURE_LM 29 /* Long Mode (x86-64) */
#define X86_FEATURE_3DNOWEXT 30 /* AMD 3DNow! extensions */
#define X86_FEATURE_3DNOW 31 /* 3DNow! */
/** x86 CPU information */
struct cpuinfo_x86 {
/** CPU features */
unsigned int features;
/** 64-bit CPU features */
unsigned int amd_features;
};
/*
* EFLAGS bits
*/
#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
/*
* Generic CPUID function
*/
static inline __attribute__ (( always_inline )) void
cpuid ( int op, unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx ) {
__asm__ ( "cpuid" :
"=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
: "0" ( op ) );
}
extern void get_cpuinfo ( struct cpuinfo_x86 *cpu );
#endif /* I386_BITS_CPU_H */

View File

@@ -0,0 +1,14 @@
#ifndef _BITS_REBOOT_H
#define _BITS_REBOOT_H
/** @file
*
* i386-specific reboot API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/bios_reboot.h>
#endif /* _BITS_REBOOT_H */

View File

@@ -0,0 +1,29 @@
#ifndef _INITRD_H
#define _INITRD_H
/** @file
*
* Initial ramdisk (initrd) reshuffling
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/uaccess.h>
/** Minimum alignment for initrds
*
* Chosen to maximise memcpy() speeds
*/
#define INITRD_ALIGN 4
/** Minimum free space required to reshuffle initrds
*
* Chosen to avoid absurdly long reshuffling times
*/
#define INITRD_MIN_FREE_LEN ( 512 * 1024 )
extern void initrd_reshuffle ( userptr_t bottom );
extern int initrd_reshuffle_check ( size_t len, userptr_t bottom );
#endif /* _INITRD_H */

View File

@@ -291,122 +291,6 @@ struct master_boot_record {
/** MBR magic signature */
#define INT13_MBR_MAGIC 0xaa55
/** ISO9660 block size */
#define ISO9660_BLKSIZE 2048
/** An ISO9660 Primary Volume Descriptor (fixed portion) */
struct iso9660_primary_descriptor_fixed {
/** Descriptor type */
uint8_t type;
/** Identifier ("CD001") */
uint8_t id[5];
} __attribute__ (( packed ));
/** An ISO9660 Primary Volume Descriptor */
struct iso9660_primary_descriptor {
/** Fixed portion */
struct iso9660_primary_descriptor_fixed fixed;
} __attribute__ (( packed ));
/** ISO9660 Primary Volume Descriptor type */
#define ISO9660_TYPE_PRIMARY 0x01
/** ISO9660 identifier */
#define ISO9660_ID "CD001"
/** ISO9660 Primary Volume Descriptor block address */
#define ISO9660_PRIMARY_LBA 16
/** An El Torito Boot Record Volume Descriptor (fixed portion) */
struct eltorito_descriptor_fixed {
/** Descriptor type */
uint8_t type;
/** Identifier ("CD001") */
uint8_t id[5];
/** Version, must be 1 */
uint8_t version;
/** Boot system indicator; must be "EL TORITO SPECIFICATION" */
uint8_t system_id[32];
} __attribute__ (( packed ));
/** An El Torito Boot Record Volume Descriptor */
struct eltorito_descriptor {
/** Fixed portion */
struct eltorito_descriptor_fixed fixed;
/** Unused */
uint8_t unused[32];
/** Boot catalog sector */
uint32_t sector;
} __attribute__ (( packed ));
/** ISO9660 Boot Volume Descriptor type */
#define ISO9660_TYPE_BOOT 0x00
/** El Torito Boot Record Volume Descriptor block address */
#define ELTORITO_LBA 17
/** An El Torito Boot Catalog Validation Entry */
struct eltorito_validation_entry {
/** Header ID; must be 1 */
uint8_t header_id;
/** Platform ID
*
* 0 = 80x86
* 1 = PowerPC
* 2 = Mac
*/
uint8_t platform_id;
/** Reserved */
uint16_t reserved;
/** ID string */
uint8_t id_string[24];
/** Checksum word */
uint16_t checksum;
/** Signature; must be 0xaa55 */
uint16_t signature;
} __attribute__ (( packed ));
/** El Torito platform IDs */
enum eltorito_platform_id {
ELTORITO_PLATFORM_X86 = 0x00,
ELTORITO_PLATFORM_POWERPC = 0x01,
ELTORITO_PLATFORM_MAC = 0x02,
};
/** A bootable entry in the El Torito Boot Catalog */
struct eltorito_boot_entry {
/** Boot indicator
*
* Must be @c ELTORITO_BOOTABLE for a bootable ISO image
*/
uint8_t indicator;
/** Media type
*
*/
uint8_t media_type;
/** Load segment */
uint16_t load_segment;
/** System type */
uint8_t filesystem;
/** Unused */
uint8_t reserved_a;
/** Sector count */
uint16_t length;
/** Starting sector */
uint32_t start;
/** Unused */
uint8_t reserved_b[20];
} __attribute__ (( packed ));
/** Boot indicator for a bootable ISO image */
#define ELTORITO_BOOTABLE 0x88
/** El Torito media types */
enum eltorito_media_type {
/** No emulation */
ELTORITO_NO_EMULATION = 0,
};
/** A floppy disk geometry */
struct int13_fdd_geometry {
/** Number of tracks */

View File

@@ -0,0 +1,18 @@
#ifndef _IPXE_BIOS_REBOOT_H
#define _IPXE_BIOS_REBOOT_H
/** @file
*
* Standard PC-BIOS reboot mechanism
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#ifdef REBOOT_PCBIOS
#define REBOOT_PREFIX_pcbios
#else
#define REBOOT_PREFIX_pcbios __pcbios_
#endif
#endif /* _IPXE_BIOS_REBOOT_H */

View File

@@ -68,6 +68,12 @@ UACCESS_INLINE ( librm, userptr_add ) ( userptr_t userptr, off_t offset ) {
return trivial_userptr_add ( userptr, offset );
}
static inline __always_inline off_t
UACCESS_INLINE ( librm, userptr_sub ) ( userptr_t userptr,
userptr_t subtrahend ) {
return trivial_userptr_sub ( userptr, subtrahend );
}
static inline __always_inline void
UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off,
userptr_t src, off_t src_off,

View File

@@ -188,6 +188,7 @@ struct pcir_header {
( ( 'P' << 0 ) + ( 'C' << 8 ) + ( 'I' << 16 ) + ( 'R' << 24 ) )
extern struct net_device *pxe_netdev;
extern const char *pxe_cmdline;
extern void pxe_set_netdev ( struct net_device *netdev );
extern PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE

View File

@@ -14,7 +14,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* As an alternative, at your option, you may use this file under the
* following terms, known as the "MIT license":
@@ -1690,6 +1691,27 @@ typedef struct s_PXENV_FILE_EXIT_HOOK PXENV_FILE_EXIT_HOOK_t;
/** @} */ /* pxenv_file_exit_hook */
/** @defgroup pxenv_file_cmdline PXENV_FILE_CMDLINE
*
* FILE CMDLINE
*
* @{
*/
/** PXE API function code for pxenv_file_cmdline() */
#define PXENV_FILE_CMDLINE 0x00e8
/** Parameter block for pxenv_file_cmdline() */
struct s_PXENV_FILE_CMDLINE {
PXENV_STATUS_t Status; /**< PXE status code */
UINT16_t BufferSize; /**< Data buffer size */
SEGOFF16_t Buffer; /**< Data buffer */
} __attribute__ (( packed ));
typedef struct s_PXENV_FILE_CMDLINE PXENV_FILE_CMDLINE_t;
/** @} */ /* pxe_file_cmdline */
/** @} */ /* pxe_file_api */
/** @defgroup pxe_loader_api PXE Loader API

View File

@@ -0,0 +1,39 @@
#ifndef _SDI_H
#define _SDI_H
/** @file
*
* System Deployment Image (SDI)
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** SDI image header */
struct sdi_header {
/** Signature */
uint32_t magic;
/** Version (as an ASCII string) */
uint32_t version;
/** Reserved */
uint8_t reserved[8];
/** Boot code offset */
uint64_t boot_offset;
/** Boot code size */
uint64_t boot_size;
} __attribute__ (( packed ));
/** SDI image signature */
#define SDI_MAGIC \
( ( '$' << 0 ) | ( 'S' << 8 ) | ( 'D' << 16 ) | ( 'I' << 24 ) )
/** SDI boot segment */
#define SDI_BOOT_SEG 0x0000
/** SDI boot offset */
#define SDI_BOOT_OFF 0x7c00
/** Constant to binary-OR with physical address of SDI image */
#define SDI_WTF 0x41
#endif /* _SDI_H */

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2010 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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Standard PC-BIOS reboot mechanism
*
*/
#include <ipxe/reboot.h>
#include <realmode.h>
#include <bios.h>
/**
* Reboot system
*
* @v warm Perform a warm reboot
*/
static void bios_reboot ( int warm ) {
uint16_t flag;
/* Configure BIOS for cold/warm reboot */
flag = ( warm ? BDA_REBOOT_WARM : 0 );
put_real ( flag, BDA_SEG, BDA_REBOOT );
/* Jump to system reset vector */
__asm__ __volatile__ ( REAL_CODE ( "ljmp $0xf000, $0xfff0" ) : : );
}
PROVIDE_REBOOT ( pcbios, reboot, bios_reboot );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -76,6 +77,8 @@ static int bios_find_smbios ( struct smbios *smbios ) {
smbios->address = phys_to_user ( u.entry.smbios_address );
smbios->len = u.entry.smbios_len;
smbios->count = u.entry.smbios_count;
smbios->version =
SMBIOS_VERSION ( u.entry.major, u.entry.minor );
return 0;
}

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -37,6 +38,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/sanboot.h>
#include <ipxe/device.h>
#include <ipxe/pci.h>
#include <ipxe/iso9660.h>
#include <ipxe/eltorito.h>
#include <realmode.h>
#include <bios.h>
#include <biosint.h>
@@ -626,7 +629,7 @@ static const struct int13_fdd_geometry int13_fdd_geometries[] = {
static int int13_guess_geometry_fdd ( struct int13_drive *int13,
unsigned int *heads,
unsigned int *sectors ) {
unsigned int blocks = int13_blksize ( int13 );
unsigned int blocks = int13_capacity ( int13 );
const struct int13_fdd_geometry *geometry;
unsigned int cylinders;
unsigned int i;

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -30,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/uaccess.h>
#include <ipxe/hidemem.h>
#include <ipxe/io.h>
#include <ipxe/memblock.h>
#include <ipxe/umalloc.h>
/** Alignment of external allocated memory */
@@ -58,53 +60,14 @@ static size_t heap_size;
/**
* Initialise external heap
*
* @ret rc Return status code
*/
static int init_eheap ( void ) {
struct memory_map memmap;
unsigned int i;
DBG ( "Allocating external heap\n" );
get_memmap ( &memmap );
heap_size = 0;
for ( i = 0 ; i < memmap.count ; i++ ) {
struct memory_region *region = &memmap.regions[i];
unsigned long r_start, r_end;
unsigned long r_size;
DBG ( "Considering [%llx,%llx)\n", region->start, region->end);
/* Truncate block to 4GB */
if ( region->start > UINT_MAX ) {
DBG ( "...starts after 4GB\n" );
continue;
}
r_start = region->start;
if ( region->end > UINT_MAX ) {
DBG ( "...end truncated to 4GB\n" );
r_end = 0; /* =4GB, given the wraparound */
} else {
r_end = region->end;
}
/* Use largest block */
r_size = ( r_end - r_start );
if ( r_size > heap_size ) {
DBG ( "...new best block found\n" );
top = bottom = phys_to_user ( r_end );
heap_size = r_size;
}
}
if ( ! heap_size ) {
DBG ( "No external heap available\n" );
return -ENOMEM;
}
static void init_eheap ( void ) {
userptr_t base;
heap_size = largest_memblock ( &base );
bottom = top = userptr_add ( base, heap_size );
DBG ( "External heap grows downwards from %lx (size %zx)\n",
user_to_phys ( top, 0 ), heap_size );
return 0;
}
/**
@@ -143,13 +106,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) {
struct external_memory extmem;
userptr_t new = ptr;
size_t align;
int rc;
/* Initialise external memory allocator if necessary */
if ( bottom == top ) {
if ( ( rc = init_eheap() ) != 0 )
return UNULL;
}
/* (Re)initialise external memory allocator if necessary */
if ( bottom == top )
init_eheap();
/* Get block properties into extmem */
if ( ptr && ( ptr != UNOWHERE ) ) {

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/

View File

@@ -19,7 +19,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -29,7 +29,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -232,6 +233,42 @@ static PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) {
return PXENV_EXIT_SUCCESS;
}
/**
* FILE CMDLINE
*
* @v file_cmdline Pointer to a struct s_PXENV_FILE_CMDLINE
* @v s_PXENV_FILE_CMDLINE::Buffer Buffer to contain command line
* @v s_PXENV_FILE_CMDLINE::BufferSize Size of buffer
* @ret #PXENV_EXIT_SUCCESS Command was executed successfully
* @ret #PXENV_EXIT_FAILURE Command was not executed successfully
* @ret s_PXENV_FILE_EXEC::Status PXE status code
* @ret s_PXENV_FILE_EXEC::BufferSize Length of command line (including NUL)
*
*/
static PXENV_EXIT_t
pxenv_file_cmdline ( struct s_PXENV_FILE_CMDLINE *file_cmdline ) {
userptr_t buffer;
size_t max_len;
size_t len;
DBG ( "PXENV_FILE_CMDLINE to %04x:%04x+%04x \"%s\"\n",
file_cmdline->Buffer.segment, file_cmdline->Buffer.offset,
file_cmdline->BufferSize, pxe_cmdline );
buffer = real_to_user ( file_cmdline->Buffer.segment,
file_cmdline->Buffer.offset );
len = file_cmdline->BufferSize;
max_len = ( pxe_cmdline ?
( strlen ( pxe_cmdline ) + 1 /* NUL */ ) : 0 );
if ( len > max_len )
len = max_len;
copy_to_user ( buffer, 0, pxe_cmdline, len );
file_cmdline->BufferSize = max_len;
file_cmdline->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
}
/**
* FILE API CHECK
*
@@ -298,6 +335,8 @@ struct pxe_api_call pxe_file_api[] __pxe_api_call = {
struct s_PXENV_GET_FILE_SIZE ),
PXE_API_CALL ( PXENV_FILE_EXEC, pxenv_file_exec,
struct s_PXENV_FILE_EXEC ),
PXE_API_CALL ( PXENV_FILE_CMDLINE, pxenv_file_cmdline,
struct s_PXENV_FILE_CMDLINE ),
PXE_API_CALL ( PXENV_FILE_API_CHECK, pxenv_file_api_check,
struct s_PXENV_FILE_API_CHECK ),
};

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -20,7 +20,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -19,7 +19,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -70,6 +71,17 @@ static void pxe_tftp_close ( struct pxe_tftp_connection *pxe_tftp, int rc ) {
pxe_tftp->rc = rc;
}
/**
* Check flow control window
*
* @v pxe_tftp PXE TFTP connection
* @ret len Length of window
*/
static size_t pxe_tftp_xfer_window ( struct pxe_tftp_connection *pxe_tftp ) {
return pxe_tftp->blksize;
}
/**
* Receive new data
*
@@ -127,6 +139,8 @@ static int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection *pxe_tftp,
static struct interface_operation pxe_tftp_xfer_ops[] = {
INTF_OP ( xfer_deliver, struct pxe_tftp_connection *,
pxe_tftp_xfer_deliver ),
INTF_OP ( xfer_window, struct pxe_tftp_connection *,
pxe_tftp_xfer_window ),
INTF_OP ( intf_close, struct pxe_tftp_connection *, pxe_tftp_close ),
};
@@ -166,19 +180,19 @@ static int pxe_tftp_open ( uint32_t ipaddress, unsigned int port,
/* Reset PXE TFTP connection structure */
memset ( &pxe_tftp, 0, sizeof ( pxe_tftp ) );
intf_init ( &pxe_tftp.xfer, &pxe_tftp_xfer_desc, NULL );
if ( blksize < TFTP_DEFAULT_BLKSIZE )
blksize = TFTP_DEFAULT_BLKSIZE;
pxe_tftp.blksize = blksize;
pxe_tftp.rc = -EINPROGRESS;
/* Construct URI string */
address.s_addr = ipaddress;
if ( ! port )
port = htons ( TFTP_PORT );
if ( blksize < TFTP_DEFAULT_BLKSIZE )
blksize = TFTP_DEFAULT_BLKSIZE;
snprintf ( uri_string, sizeof ( uri_string ),
"tftp%s://%s:%d%s%s?blksize=%zd",
sizeonly ? "size" : "",
inet_ntoa ( address ), ntohs ( port ),
( ( filename[0] == '/' ) ? "" : "/" ), filename, blksize );
snprintf ( uri_string, sizeof ( uri_string ), "tftp%s://%s:%d%s%s",
sizeonly ? "size" : "", inet_ntoa ( address ),
ntohs ( port ), ( ( filename[0] == '/' ) ? "" : "/" ),
filename );
DBG ( " %s", uri_string );
/* Open PXE TFTP connection */

View File

@@ -28,7 +28,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -19,7 +19,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -357,7 +358,8 @@ pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT *undi_transmit ) {
}
/* Allocate and fill I/O buffer */
iobuf = alloc_iob ( MAX_LL_HEADER_LEN + len );
iobuf = alloc_iob ( MAX_LL_HEADER_LEN +
( ( len > IOB_ZLEN ) ? len : IOB_ZLEN ) );
if ( ! iobuf ) {
DBGC2 ( &pxe_netdev, " could not allocate iobuf\n" );
undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER )

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/**
@@ -38,12 +39,13 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/serial.h>
#include <ipxe/init.h>
#include <ipxe/image.h>
#include <ipxe/version.h>
#include <usr/imgmgmt.h>
#include "config/console.h"
#include "config/serial.h"
/** The "SYSLINUX" version string */
static char __data16_array ( syslinux_version, [] ) = "\r\niPXE " VERSION;
static char __bss16_array ( syslinux_version, [32] );
#define syslinux_version __use_data16 ( syslinux_version )
/** The "SYSLINUX" copyright string */
@@ -325,6 +327,10 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
/* SYSLINUX derivative ID */
ix86->regs.dl = BZI_LOADER_TYPE_IPXE;
/* SYSLINUX version */
snprintf ( syslinux_version, sizeof ( syslinux_version ),
"\r\niPXE %s", product_version );
/* SYSLINUX version and copyright strings */
ix86->segs.es = rm_ds;
ix86->regs.si = ( ( unsigned ) __from_data16 ( syslinux_version ) );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -90,7 +91,7 @@ static int guestinfo_fetch_type ( struct settings *settings,
/* Allocate temporary block to hold GuestInfo value */
info = zalloc ( info_len + 1 /* NUL */ );
if ( ! info ) {
DBGC ( settings, "GuestInfo %p could not allocate %zd bytes\n",
DBGC ( settings, "GuestInfo %p could not allocate %d bytes\n",
settings, info_len );
ret = -ENOMEM;
goto err_alloc;

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
@@ -113,7 +114,7 @@ _exe_start:
call alloc_basemem
xorl %esi, %esi
movl $EXE_DECOMPRESS_ADDRESS, %edi
xorl %ebp, %ebp
orl $0xffffffff, %ebp /* Allow arbitrary relocation */
call install_prealloc
/* Set up real-mode stack */

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
@@ -544,8 +545,7 @@ alloc_basemem:
* Free space allocated with alloc_basemem.
*
* Parameters:
* %ax : .text16 segment address
* %bx : .data16 segment address
* none (.text16 segment address is implicit in %cs)
* Returns:
* %ax : 0 if successfully freed
* Corrupts:
@@ -558,14 +558,14 @@ alloc_basemem:
free_basemem:
/* Preserve registers */
pushw %fs
pushw %ax
/* Check FBMS counter */
pushw %ax
movw %cs, %ax
shrw $6, %ax
pushw $0x40
popw %fs
cmpw %ax, %fs:0x13
popw %ax
jne 1f
/* Check hooked interrupt count */
@@ -573,6 +573,7 @@ free_basemem:
jne 1f
/* OK to free memory */
movw %cs, %ax
addw $_text16_memsz_pgh, %ax
addw $_data16_memsz_pgh, %ax
shrw $6, %ax
@@ -580,6 +581,7 @@ free_basemem:
xorw %ax, %ax
1: /* Restore registers and return */
popw %ax
popw %fs
ret
.size free_basemem, . - free_basemem
@@ -620,7 +622,7 @@ install:
/* Image destination = default */
xorl %edi, %edi
/* Allow arbitrary relocation */
xorl %ebp, %ebp
orl $0xffffffff, %ebp
/* Install text and data segments */
call install_prealloc
/* Restore registers and return */
@@ -640,7 +642,9 @@ install:
* %bx : .data16 segment address
* %esi : Image source physical address (or zero for %cs:0000)
* %edi : Decompression temporary area physical address (or zero for default)
* %ebp : Maximum end address for relocation (or zero for no maximum)
* %ebp : Maximum end address for relocation
* - 0xffffffff for no maximum
* - 0x00000000 to inhibit use of INT 15,e820 and INT 15,e801
* Corrupts:
* none
****************************************************************************
@@ -663,18 +667,22 @@ install_prealloc:
/* Save decompression temporary area physical address */
pushl %edi
/* Install .text16.early */
/* Install .text16.early and calculate %ecx as offset to next block */
progress " .text16.early\n"
pushl %esi
xorl %esi, %esi
movw %cs, %si
shll $4, %esi
pushl %esi /* Save original %cs:0000 */
addl $_text16_early_lma, %esi
movzwl %ax, %edi
shll $4, %edi
movl $_text16_early_filesz, %ecx
movl $_text16_early_memsz, %edx
call install_block /* .text16.early */
popl %ecx /* Calculate offset to next block */
subl %esi, %ecx
negl %ecx
popl %esi
#ifndef KEEP_IT_REAL
@@ -729,7 +737,7 @@ payload_death_message:
jnz 1f
movw %cs, %si
shll $4, %esi
1: addl payload_lma, %esi
1: addl %ecx, %esi
/* Install .text16.late and .data16 */
progress " .text16.late\n"
@@ -790,6 +798,13 @@ payload_death_message:
movw %ax, (init_librm_vector+2)
lcall *init_librm_vector
/* Inhibit INT 15,e820 and INT 15,e801 if applicable */
testl %ebp, %ebp
jnz 1f
incb memmap_post
decl %ebp
1:
/* Call relocate() to determine target address for relocation.
* relocate() will return with %esi, %edi and %ecx set up
* ready for the copy to the new location.
@@ -850,17 +865,6 @@ close_payload_vector:
.word 0
.size close_payload_vector, . - close_payload_vector
/* Payload address */
.section ".prefix.lib", "awx", @progbits
payload_lma:
.long 0
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "ADHL"
.long payload_lma
.long 1
.long 0
.previous
/* Dummy routines to open and close payload */
.section ".text16.early.data", "aw", @progbits
.weak open_payload
@@ -878,8 +882,7 @@ close_payload:
* Uninstall all text and data segments.
*
* Parameters:
* %ax : .text16 segment address
* %bx : .data16 segment address
* none (.text16 segment address is implicit in %cs)
* Returns:
* none
* Corrupts:
@@ -914,6 +917,10 @@ uninstall:
.ascii "PAYL"
.long 0
.long 0
.long _payload_align
.ascii "COPY"
.long _pprefix_lma
.long _pprefix_filesz
.long _max_align
.ascii PACK_OR_COPY
.long _text16_late_lma
@@ -927,3 +934,6 @@ uninstall:
.long _textdata_lma
.long _textdata_filesz
.long _max_align
.weak _payload_align
.equ _payload_align, 1

View File

@@ -231,9 +231,12 @@ run_ipxe:
movzwl %sp, %edx
no_cmd_line:
/* Retrieve initrd pointer and size */
movl %ds:ramdisk_image, %ebp
movl %ds:ramdisk_size, %ecx
/* Calculate maximum relocation address */
movl ramdisk_image, %ebp
testl %ebp, %ebp
jnz 1f
orl $0xffffffff, %ebp /* Allow arbitrary relocation if no initrd */
1:
/* Install iPXE */
call alloc_basemem
@@ -251,6 +254,10 @@ no_cmd_line:
lret
.section ".text16", "awx", @progbits
1:
/* Retrieve initrd pointer and size */
movl ramdisk_image, %ebp
movl ramdisk_size, %ecx
/* Set up %ds for access to .data16 */
movw %bx, %ds

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
@@ -30,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
#define PCI_BAR_EXPROM 0x30
#define ROMPREFIX_EXCLUDE_PAYLOAD 1
#define ROMPREFIX_MORE_IMAGES 1
#define _rom_start _mrom_start
#include "romprefix.S"
@@ -46,8 +48,10 @@ FILE_LICENCE ( GPL2_OR_LATER )
* Parameters:
* %ds:0000 : Prefix
* %esi : Buffer for copy of image source (or zero if no buffer available)
* %ecx : Expected offset within buffer of first payload block
* Returns:
* %esi : Valid image source address (buffered or unbuffered)
* %ecx : Actual offset within buffer of first payload block
* CF set on error
*/
.section ".text16.early", "awx", @progbits
@@ -56,23 +60,25 @@ open_payload:
/* Preserve registers */
pushl %eax
pushw %bx
pushl %ecx
pushl %edx
pushl %edi
pushw %bp
pushw %es
pushw %ds
/* Retrieve bus:dev.fn and image source length from .prefix */
/* Retrieve bus:dev.fn from .prefix */
movw init_pci_busdevfn, %bx
movl image_source_len_dword, %ecx
/* Set up %ds for access to .text16.early */
pushw %cs
popw %ds
/* Store bus:dev.fn and image source length to .text16.early */
/* Set up %es for access to flat address space */
xorw %ax, %ax
movw %ax, %es
/* Store bus:dev.fn to .text16.early */
movw %bx, payload_pci_busdevfn
movl %ecx, rom_bar_copy_len_dword
/* Get expansion ROM BAR current value */
movw $PCI_BAR_EXPROM, %di
@@ -149,6 +155,18 @@ find_mem_bar:
movw $PCI_BAR_EXPROM, %di
call pci_write_config_dword
/* Locate our ROM image */
1: addr32 es cmpw $0xaa55, (%eax)
stc
jne 99f
addr32 es cmpl $_build_id, build_id(%eax)
je 2f
addr32 es movzbl 2(%eax), %ecx
shll $9, %ecx
addl %ecx, %eax
jmp 1b
2:
/* Copy payload to buffer, or set buffer address to BAR address */
testl %esi, %esi
jz 1f
@@ -159,27 +177,32 @@ find_mem_bar:
* properly support flat real mode, it will die horribly.)
*/
pushl %esi
pushw %es
movl %esi, %edi
movl %eax, %esi
movl rom_bar_copy_len_dword, %ecx
xorw %ax, %ax
movw %ax, %es
addr32 es movzbl 2(%esi), %ecx
shll $7, %ecx
addr32 es movzbl 2(%esi,%ecx,4), %edx
shll $7, %edx
addl %edx, %ecx
addr32 es rep movsl
popw %es
popl %esi
jmp 2f
1: /* We have no buffer; set %esi to the BAR address */
movl %eax, %esi
2:
/* Locate first payload block (after the dummy ROM header) */
addr32 es movzbl 2(%esi), %ecx
shll $9, %ecx
addl $_pprefix_skip, %ecx
clc
/* Restore registers and return */
99: popw %ds
popw %es
popw %bp
popl %edi
popl %edx
popl %ecx
popw %bx
popl %eax
lret
@@ -200,11 +223,6 @@ rom_bar_size:
.long 0
.size rom_bar_size, . - rom_bar_size
.section ".text16.early.data", "aw", @progbits
rom_bar_copy_len_dword:
.long 0
.size rom_bar_copy_len_dword, . - rom_bar_copy_len_dword
.section ".text16.early.data", "aw", @progbits
stolen_bar_register:
.word 0
@@ -419,16 +437,68 @@ pci_set_mem_access:
ret
.size pci_set_mem_access, . - pci_set_mem_access
/* Image source area length (in dwords)
/* Payload prefix
*
* We include a dummy ROM header to cover the "hidden" portion of the
* overall ROM image.
*/
.section ".prefix", "ax", @progbits
image_source_len_dword:
.long 0
.size image_source_len_dword, . - image_source_len_dword
.globl _payload_align
.equ _payload_align, 512
.section ".pprefix", "ax", @progbits
.org 0x00
mromheader:
.word 0xaa55 /* BIOS extension signature */
mromheader_size: .byte 0 /* Size in 512-byte blocks */
.org 0x18
.word mpciheader
.org 0x1a
.word 0
.size mromheader, . - mromheader
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "ADDL"
.long image_source_len_dword
.long 4
.ascii "APPB"
.long mromheader_size
.long 512
.long 0
.previous
mpciheader:
.ascii "PCIR" /* Signature */
.word pci_vendor_id /* Vendor identification */
.word pci_device_id /* Device identification */
.word 0x0000 /* Device list pointer */
.word mpciheader_len /* PCI data structure length */
.byte 0x03 /* PCI data structure revision */
.byte 0x02, 0x00, 0x00 /* Class code */
mpciheader_image_length:
.word 0 /* Image length */
.word 0x0001 /* Revision level */
.byte 0xff /* Code type */
.byte 0x80 /* Last image indicator */
mpciheader_runtime_length:
.word 0 /* Maximum run-time image length */
.word 0x0000 /* Configuration utility code header */
.word 0x0000 /* DMTF CLP entry point */
.equ mpciheader_len, . - mpciheader
.size mpciheader, . - mpciheader
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "APPW"
.long mpciheader_image_length
.long 512
.long 0
.ascii "APPW"
.long mpciheader_runtime_length
.long 512
.long 0
.previous
/* Fix up additional image source size
*
*/
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "ADPW"
.long extra_size
.long 512
.long 0
.previous

View File

@@ -54,6 +54,10 @@ _nbi_start:
/* Install iPXE */
call install
/* Set up real-mode stack */
movw %bx, %ss
movw $_estack16, %sp
/* Jump to .text16 segment */
pushw %ax
pushw $1f

View File

@@ -5,6 +5,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
#define PXENV_UNDI_GET_IFACE_INFO 0x0013
#define PXENV_STOP_UNDI 0x0015
#define PXENV_UNLOAD_STACK 0x0070
#define PXENV_FILE_CMDLINE 0x00e8
#define PXE_HACK_EB54 0x0001
@@ -19,6 +20,8 @@ FILE_LICENCE ( GPL2_OR_LATER )
#define EB_MAGIC_1 ( 'E' + ( 't' << 8 ) + ( 'h' << 16 ) + ( 'e' << 24 ) )
#define EB_MAGIC_2 ( 'r' + ( 'b' << 8 ) + ( 'o' << 16 ) + ( 'o' << 24 ) )
#define PREFIX_STACK_SIZE 2048
/*****************************************************************************
* Entry point: set operating context, print welcome message
*****************************************************************************
@@ -46,10 +49,11 @@ _pxe_start:
movw %ax, %ds
movw $0x40, %ax /* BIOS data segment access */
movw %ax, %fs
/* Set up stack just below 0x7c00 */
xorw %ax, %ax
/* Set up temporary stack immediately after the iPXE image */
movw %cs, %ax
addw image_size_pgh, %ax
movw %ax, %ss
movl $0x7c00, %esp
movl $PREFIX_STACK_SIZE, %esp
/* Clear direction flag, for the sake of sanity */
cld
/* Print welcome message */
@@ -60,6 +64,18 @@ _pxe_start:
10: .asciz "PXE->EB:"
.previous
/* Image size (for stack placement calculation) */
.section ".prefix.data", "aw", @progbits
image_size_pgh:
.word 0
.previous
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "ADDW"
.long image_size_pgh
.long 16
.long 0
.previous
/*****************************************************************************
* Find us a usable !PXE or PXENV+ entry point
*****************************************************************************
@@ -366,6 +382,35 @@ get_iface_type:
99: movb $0x0a, %al
call print_character
/*****************************************************************************
* Check for a command line
*****************************************************************************
*/
get_cmdline:
/* Issue PXENV_FILE_CMDLINE */
xorl %esi, %esi
movw %ss, %si
movw %si, ( pxe_parameter_structure + 0x06 )
movw $PREFIX_STACK_SIZE, ( pxe_parameter_structure + 0x04 )
movw $0xffff, ( pxe_parameter_structure + 0x02 )
movw $PXENV_FILE_CMDLINE, %bx
call pxe_call
jc 99f /* Suppress errors; this is an iPXE extension API call */
/* Check for non-NULL command line */
movw ( pxe_parameter_structure + 0x02 ), %ax
testw %ax, %ax
jz 99f
/* Record command line */
shll $4, %esi
addl $PREFIX_STACK_SIZE, %esi
movl %esi, pxe_cmdline
99:
.section ".prefix.data", "aw", @progbits
pxe_cmdline:
.long 0
.previous
/*****************************************************************************
* Leave NIC in a safe state
*****************************************************************************
@@ -713,6 +758,9 @@ run_ipxe:
movw pxe_ss, %di
movl pxe_esp, %ebp
/* Retrieve PXE command line, if any */
movl pxe_cmdline, %esi
/* Jump to .text16 segment with %ds pointing to .data16 */
movw %bx, %ds
pushw %ax
@@ -723,6 +771,9 @@ run_ipxe:
/* Update the exit hook */
movw %cs, ( pxe_exit_hook + 2 )
/* Store command-line pointer */
movl %esi, cmdline_phys
/* Run main program */
pushl $main
pushw %cs

View File

@@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER )
( PMM_HANDLE_BASE | 0x00001000 )
#define PMM_HANDLE_BASE_DECOMPRESS_TO \
( PMM_HANDLE_BASE | 0x00002000 )
#define PCI_FUNC_MASK 0x07
/* ROM banner timeout. Based on the configurable BANNER_TIMEOUT in
* config.h, but converted to a number of (18Hz) timer ticks, and
@@ -39,6 +40,14 @@ FILE_LICENCE ( GPL2_OR_LATER )
#else
#define ZINFO_TYPE_ADxB "ADDB"
#define ZINFO_TYPE_ADxW "ADDW"
#endif
/* Allow ROM to be marked as containing multiple images
*/
#if ROMPREFIX_MORE_IMAGES
#define INDICATOR 0x00
#else
#define INDICATOR 0x80
#endif
.text
@@ -55,6 +64,8 @@ romheader_size: .byte 0 /* Size in 512-byte blocks */
jmp init /* Initialisation vector */
checksum:
.byte 0
.org 0x10
.word ipxeheader
.org 0x16
.word undiheader
.org 0x18
@@ -70,9 +81,6 @@ checksum:
.long 0
.previous
build_id:
.long _build_id /* Randomly-generated build ID */
pciheader:
.ascii "PCIR" /* Signature */
.word pci_vendor_id /* Vendor identification */
@@ -85,7 +93,7 @@ pciheader_image_length:
.word 0 /* Image length */
.word 0x0001 /* Revision level */
.byte 0x00 /* Code type */
.byte 0x80 /* Last image indicator */
.byte INDICATOR /* Last image indicator */
pciheader_runtime_length:
.word 0 /* Maximum run-time image length */
.word 0x0000 /* Configuration utility code header */
@@ -167,6 +175,25 @@ undiheader:
.equ undiheader_len, . - undiheader
.size undiheader, . - undiheader
ipxeheader:
.ascii "iPXE" /* Signature */
.byte ipxeheader_len /* Length of structure */
.byte 0 /* Checksum */
shrunk_rom_size:
.byte 0 /* Shrunk size (in 512-byte blocks) */
.byte 0 /* Reserved */
build_id:
.long _build_id /* Randomly-generated build ID */
.equ ipxeheader_len, . - ipxeheader
.size ipxeheader, . - ipxeheader
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "ADHB"
.long shrunk_rom_size
.long 512
.long 0
.previous
/* Initialisation (called once during POST)
*
* Determine whether or not this is a PnP system via a signature
@@ -326,14 +353,19 @@ pmm_scan:
call print_message
/* We have PMM and so a 1kB stack: preserve whole registers */
pushal
/* Allocate image source PMM block */
movzwl image_source_size, %ecx
/* Allocate image source PMM block. Round up the size to the
* nearest 4kB (8 512-byte sectors) to work around AMI BIOS bugs.
*/
movzbl romheader_size, %ecx
addw extra_size, %cx
addw $0x0007, %cx /* Round up to multiple of 8 512-byte sectors */
andw $0xfff8, %cx
shll $5, %ecx
movl $PMM_HANDLE_BASE_IMAGE_SOURCE, %ebx
movw $get_pmm_image_source, %bp
call get_pmm
movl %esi, image_source
jc 1f
jz 1f
/* Copy ROM to image source PMM block */
pushw %es
xorw %ax, %ax
@@ -341,8 +373,8 @@ pmm_scan:
movl %esi, %edi
xorl %esi, %esi
movzbl romheader_size, %ecx
shll $9, %ecx
addr32 rep movsb /* PMM presence implies flat real mode */
shll $7, %ecx
addr32 rep movsl /* PMM presence implies flat real mode */
popw %es
/* Shrink ROM */
movb shrunk_rom_size, %al
@@ -391,6 +423,9 @@ no_pmm:
xorw %di, %di
cs rep movsb
/* Skip prompt if this is not the first PCI function */
testb $PCI_FUNC_MASK, init_pci_busdevfn
jnz no_shell
/* Prompt for POST-time shell */
movw $init_message_prompt, %si
xorw %di, %di
@@ -409,15 +444,19 @@ no_pmm:
movw $init_message_done, %si
call print_message
popf
jnz 2f
jnz no_shell
/* Ctrl-B was pressed: invoke iPXE. The keypress will be
* picked up by the initial shell prompt, and we will drop
* into a shell.
*/
movl $0xa0000, %ebp /* Inhibit relocation during POST */
xorl %ebp, %ebp /* Inhibit use of INT 15,e820 and INT 15,e801 */
pushw %cs
call exec
2:
no_shell:
movb $( '\n' ), %al
xorw %di, %di
call print_character
/* Restore registers */
popw %gs
popw %fs
@@ -439,7 +478,7 @@ no_pmm:
* %es:0000 : PMM structure
* Returns:
* %ebx : PMM handle
* %esi : allocated block address, or zero (with CF set) if allocation failed
* %esi : allocated block address, or zero (with ZF set) if allocation failed
*/
get_pmm:
/* Preserve registers */
@@ -455,7 +494,10 @@ get_pmm_find:
pushw %dx
pushw %ax
popl %esi
testl %esi, %esi
/* Treat 0xffffffff (not supported) as 0x00000000 (not found) */
incl %esi
jz get_pmm_allocate
decl %esi
jz get_pmm_allocate
/* Block found - check acceptability */
call *%bp
@@ -475,19 +517,20 @@ get_pmm_allocate:
pushw %ax
popl %esi
movw $( '+' ), %di /* Indicate allocation attempt */
testl %esi, %esi
jnz get_pmm_done
stc
get_pmm_done:
/* Print block address */
pushfw
movw %di, %ax
xorw %di, %di
call print_character
movl %esi, %eax
call print_hex_dword
popfw
/* Restore registers and return */
/* Treat 0xffffffff (not supported) as 0x00000000 (allocation
* failed), and set ZF to indicate a zero result.
*/
incl %esi
jz 1f
decl %esi
1: /* Restore registers and return */
popw %di
popl %eax
ret
@@ -560,7 +603,7 @@ init_message_done:
*
*/
init_pci_busdevfn:
.word 0xffff
.word 0
.size init_pci_busdevfn, . - init_pci_busdevfn
/* Image source area
@@ -573,31 +616,12 @@ image_source:
.long 0
.size image_source, . - image_source
/* Image source size (in 512-byte sectors)
/* Additional image source size (in 512-byte sectors)
*
*/
image_source_size:
extra_size:
.word 0
.size image_source_size, . - image_source_size
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "ADDW"
.long image_source_size
.long 512
.long 0
.previous
/* Shrunk ROM size (in 512-byte sectors)
*
*/
shrunk_rom_size:
.byte 0
.size shrunk_rom_size, . - shrunk_rom_size
.section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
.ascii "ADHB"
.long shrunk_rom_size
.long 512
.long 0
.previous
.size extra_size, . - extra_size
/* Temporary decompression area
*
@@ -614,7 +638,7 @@ decompress_to:
* Called by the PnP BIOS when it wants to boot us.
*/
bev_entry:
xorl %ebp, %ebp /* Allow relocation */
orl $0xffffffff, %ebp /* Allow arbitrary relocation */
pushw %cs
call exec
lret
@@ -649,7 +673,7 @@ int19_entry:
/* Leave keypress in buffer and start iPXE. The keypress will
* cause the usual initial Ctrl-B prompt to be skipped.
*/
xorl %ebp, %ebp /* Allow relocation */
orl $0xffffffff, %ebp /* Allow arbitrary relocation */
pushw %cs
call exec
1: /* Try to call original INT 19 vector */

View File

@@ -31,7 +31,7 @@ undiloader:
movw %es:14(%di), %ax
movl image_source, %esi
movl decompress_to, %edi
xorl %ebp, %ebp /* Allow relocation */
orl $0xffffffff, %ebp /* Allow arbitrary relocation */
call install_prealloc
popw %di
/* Call UNDI loader C code */

View File

@@ -1,4 +1,4 @@
/* -*- sh -*- */
/* -*- ld-script -*- */
/*
* Linker script for i386 images
@@ -121,6 +121,23 @@ SECTIONS {
_textdata_filesz = ABSOLUTE ( _mtextdata ) - ABSOLUTE ( _textdata );
_textdata_memsz = ABSOLUTE ( _etextdata ) - ABSOLUTE ( _textdata );
/*
* Payload prefix
*
* If present, this will be placed between .text16.early and .text16.late.
*
*/
.pprefix 0x0 : AT ( _pprefix_lma ) {
_pprefix = .;
KEEP(*(.pprefix))
KEEP(*(.pprefix.*))
_mpprefix = .;
} .bss.pprefix (NOLOAD) : AT ( _end_lma ) {
_epprefix = .;
}
_pprefix_filesz = ABSOLUTE ( _mpprefix ) - ABSOLUTE ( _pprefix );
_pprefix_memsz = ABSOLUTE ( _epprefix ) - ABSOLUTE ( _pprefix );
/*
* Compressor information block
*
@@ -187,8 +204,14 @@ SECTIONS {
_text16_early_lma = .;
. += _text16_early_filesz;
. = ALIGN ( _max_align );
. = ALIGN ( _payload_align );
_pprefix_lma = .;
. += _pprefix_filesz;
. = ALIGN ( _max_align );
_payload_lma = .;
_pprefix_skip = ABSOLUTE ( _payload_lma ) - ABSOLUTE ( _pprefix_lma );
_text16_late_lma = .;
. += _text16_late_filesz;

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/

View File

@@ -7,6 +7,7 @@ INCDIRS += arch/x86/include
SRCDIRS += arch/x86/core
SRCDIRS += arch/x86/interface/efi
SRCDIRS += arch/x86/prefix
SRCDIRS += arch/x86/hci/commands
# breaks building some of the linux-related objects
CFLAGS += -Ulinux

155
src/arch/x86/core/cpuid.c Normal file
View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2012 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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <ipxe/cpuid.h>
/** @file
*
* x86 CPU feature detection
*
*/
/**
* Check whether or not CPUID instruction is supported
*
* @ret is_supported CPUID instruction is supported
*/
static int cpuid_is_supported ( void ) {
unsigned long original;
unsigned long inverted;
__asm__ ( "pushf\n\t"
"pushf\n\t"
"pop %0\n\t"
"mov %0,%1\n\t"
"xor %2,%1\n\t"
"push %1\n\t"
"popf\n\t"
"pushf\n\t"
"pop %1\n\t"
"popf\n\t"
: "=&r" ( original ), "=&r" ( inverted )
: "ir" ( CPUID_FLAG ) );
return ( ( original ^ inverted ) & CPUID_FLAG );
}
/**
* Issue CPUID instruction
*
* @v operation CPUID operation
* @v eax Output via %eax
* @v ebx Output via %ebx
* @v ecx Output via %ecx
* @v edx Output via %edx
*/
static inline __attribute__ (( always_inline )) void
cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
uint32_t *edx ) {
__asm__ ( "cpuid"
: "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
: "0" ( operation ) );
}
/**
* Get Intel-defined x86 CPU features
*
* @v features x86 CPU features to fill in
*/
static void x86_intel_features ( struct x86_features *features ) {
uint32_t max_level;
uint32_t discard_a;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
/* Check that features are available via CPUID */
cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c,
&discard_d );
if ( max_level < CPUID_FEATURES ) {
DBGC ( features, "CPUID has no Intel-defined features (max "
"level %08x)\n", max_level );
return;
}
/* Get features */
cpuid ( CPUID_FEATURES, &discard_a, &discard_b,
&features->intel.ecx, &features->intel.edx );
DBGC ( features, "CPUID Intel features: %%ecx=%08x, %%edx=%08x\n",
features->intel.ecx, features->intel.edx );
}
/**
* Get AMD-defined x86 CPU features
*
* @v features x86 CPU features to fill in
*/
static void x86_amd_features ( struct x86_features *features ) {
uint32_t max_level;
uint32_t discard_a;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
/* Check that features are available via CPUID */
cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c,
&discard_d );
if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) {
DBGC ( features, "CPUID has no extended functions\n" );
return;
}
if ( max_level < CPUID_AMD_FEATURES ) {
DBGC ( features, "CPUID has no AMD-defined features (max "
"level %08x)\n", max_level );
return;
}
/* Get features */
cpuid ( CPUID_AMD_FEATURES, &discard_a, &discard_b,
&features->amd.ecx, &features->amd.edx );
DBGC ( features, "CPUID AMD features: %%ecx=%08x, %%edx=%08x\n",
features->amd.ecx, features->amd.edx );
}
/**
* Get x86 CPU features
*
* @v features x86 CPU features to fill in
*/
void x86_features ( struct x86_features *features ) {
/* Clear all features */
memset ( features, 0, sizeof ( *features ) );
/* Check that CPUID instruction is available */
if ( ! cpuid_is_supported() ) {
DBGC ( features, "CPUID instruction is not supported\n" );
return;
}
/* Get Intel-defined features */
x86_intel_features ( features );
/* Get AMD-defined features */
x86_amd_features ( features );
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (C) 2012 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 (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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Debug port console
*
* The debug port is supported by bochs (via the "port_e9_hack"
* configuration file directive) and by qemu (via the "-debugcon"
* command-line option).
*/
#include <stdint.h>
#include <ipxe/io.h>
#include <ipxe/console.h>
#include <ipxe/init.h>
#include <config/console.h>
/** Debug port */
#define DEBUG_PORT 0xe9
/** Debug port installation check magic value */
#define DEBUG_PORT_CHECK 0xe9
/* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_DEBUGCON ) && CONSOLE_EXPLICIT ( CONSOLE_DEBUGCON ) )
#undef CONSOLE_DEBUGCON
#define CONSOLE_DEBUGCON ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI )
#endif
/**
* Print a character to debug port console
*
* @v character Character to be printed
*/
static void debugcon_putchar ( int character ) {
/* Write character to debug port */
outb ( character, DEBUG_PORT );
}
/** Debug port console driver */
struct console_driver debugcon_console __console_driver = {
.putchar = debugcon_putchar,
.usage = CONSOLE_DEBUGCON,
};
/**
* Initialise debug port console
*
*/
static void debugcon_init ( void ) {
uint8_t check;
/* Check if console is present */
check = inb ( DEBUG_PORT );
if ( check != DEBUG_PORT_CHECK ) {
DBG ( "Debug port not present; disabling console\n" );
debugcon_console.disabled = 1;
}
}
/**
* Debug port console initialisation function
*/
struct init_fn debugcon_init_fn __init_fn ( INIT_EARLY ) = {
.initialise = debugcon_init,
};

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -35,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
* This routine uses MMX instructions.
*/
static uint64_t x86_readq ( volatile uint64_t *io_addr ) {
static __unused uint64_t i386_readq ( volatile uint64_t *io_addr ) {
uint64_t data;
__asm__ __volatile__ ( "pushl %%edx\n\t"
"pushl %%eax\n\t"
@@ -56,7 +57,7 @@ static uint64_t x86_readq ( volatile uint64_t *io_addr ) {
*
* This routine uses MMX instructions.
*/
static void x86_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
static __unused void i386_writeq ( uint64_t data, volatile uint64_t *io_addr ) {
__asm__ __volatile__ ( "pushl %%edx\n\t"
"pushl %%eax\n\t"
"movq (%%esp), %%mm0\n\t"
@@ -75,11 +76,9 @@ PROVIDE_IOAPI_INLINE ( x86, io_to_bus );
PROVIDE_IOAPI_INLINE ( x86, readb );
PROVIDE_IOAPI_INLINE ( x86, readw );
PROVIDE_IOAPI_INLINE ( x86, readl );
PROVIDE_IOAPI ( x86, readq, x86_readq );
PROVIDE_IOAPI_INLINE ( x86, writeb );
PROVIDE_IOAPI_INLINE ( x86, writew );
PROVIDE_IOAPI_INLINE ( x86, writel );
PROVIDE_IOAPI ( x86, writeq, x86_writeq );
PROVIDE_IOAPI_INLINE ( x86, inb );
PROVIDE_IOAPI_INLINE ( x86, inw );
PROVIDE_IOAPI_INLINE ( x86, inl );
@@ -94,3 +93,10 @@ PROVIDE_IOAPI_INLINE ( x86, outsw );
PROVIDE_IOAPI_INLINE ( x86, outsl );
PROVIDE_IOAPI_INLINE ( x86, iodelay );
PROVIDE_IOAPI_INLINE ( x86, mb );
#ifdef __x86_64__
PROVIDE_IOAPI_INLINE ( x86, readq );
PROVIDE_IOAPI_INLINE ( x86, writeq );
#else
PROVIDE_IOAPI ( x86, readq, i386_readq );
PROVIDE_IOAPI ( x86, writeq, i386_writeq );
#endif

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
/** @file
@@ -34,7 +35,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
* @v len Length
* @ret dest Destination address
*/
void * __memcpy ( void *dest, const void *src, size_t len ) {
void * __attribute__ (( noinline )) __memcpy ( void *dest, const void *src,
size_t len ) {
void *edi = dest;
const void *esi = src;
int discard_ecx;
@@ -43,21 +45,146 @@ void * __memcpy ( void *dest, const void *src, size_t len ) {
* moves. Using movsl rather than movsb speeds these up by
* around 32%.
*/
if ( len >> 2 ) {
__asm__ __volatile__ ( "rep movsl"
: "=&D" ( edi ), "=&S" ( esi ),
"=&c" ( discard_ecx )
: "0" ( edi ), "1" ( esi ),
"2" ( len >> 2 )
: "memory" );
}
if ( len & 0x02 ) {
__asm__ __volatile__ ( "movsw" : "=&D" ( edi ), "=&S" ( esi )
: "0" ( edi ), "1" ( esi ) : "memory" );
}
if ( len & 0x01 ) {
__asm__ __volatile__ ( "movsb" : "=&D" ( edi ), "=&S" ( esi )
: "0" ( edi ), "1" ( esi ) : "memory" );
}
__asm__ __volatile__ ( "rep movsl"
: "=&D" ( edi ), "=&S" ( esi ),
"=&c" ( discard_ecx )
: "0" ( edi ), "1" ( esi ), "2" ( len >> 2 )
: "memory" );
__asm__ __volatile__ ( "rep movsb"
: "=&D" ( edi ), "=&S" ( esi ),
"=&c" ( discard_ecx )
: "0" ( edi ), "1" ( esi ), "2" ( len & 3 )
: "memory" );
return dest;
}
/**
* Copy memory area backwards
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void * __attribute__ (( noinline )) __memcpy_reverse ( void *dest,
const void *src,
size_t len ) {
void *edi = ( dest + len - 1 );
const void *esi = ( src + len - 1 );
int discard_ecx;
/* Assume memmove() is not performance-critical, and perform a
* bytewise copy for simplicity.
*/
__asm__ __volatile__ ( "std\n\t"
"rep movsb\n\t"
"cld\n\t"
: "=&D" ( edi ), "=&S" ( esi ),
"=&c" ( discard_ecx )
: "0" ( edi ), "1" ( esi ),
"2" ( len )
: "memory" );
return dest;
}
/**
* Copy (possibly overlapping) memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void * __memmove ( void *dest, const void *src, size_t len ) {
if ( dest <= src ) {
return __memcpy ( dest, src, len );
} else {
return __memcpy_reverse ( dest, src, len );
}
}
/**
* Swap memory areas
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void * memswap ( void *dest, void *src, size_t len ) {
size_t discard_c;
int discard;
__asm__ __volatile__ ( "\n1:\n\t"
"dec %2\n\t"
"js 2f\n\t"
"movb (%0,%2), %b3\n\t"
"xchgb (%1,%2), %b3\n\t"
"movb %b3, (%0,%2)\n\t"
"jmp 1b\n\t"
"2:\n\t"
: "=r" ( src ), "=r" ( dest ),
"=&c" ( discard_c ), "=&q" ( discard )
: "0" ( src ), "1" ( dest ), "2" ( len )
: "memory" );
return dest;
}
/**
* Calculate length of string
*
* @v string String
* @ret len Length (excluding NUL)
*/
size_t strlen ( const char *string ) {
const char *discard_D;
size_t len_plus_one;
__asm__ __volatile__ ( "repne scasb\n\t"
"not %1\n\t"
: "=&D" ( discard_D ), "=&c" ( len_plus_one )
: "0" ( string ), "1" ( -1UL ), "a" ( 0 ) );
return ( len_plus_one - 1 );
}
/**
* Compare strings (up to a specified length)
*
* @v str1 First string
* @v str2 Second string
* @v len Maximum length
* @ret diff Difference
*/
int strncmp ( const char *str1, const char *str2, size_t len ) {
const void *discard_S;
const void *discard_D;
size_t discard_c;
int diff;
__asm__ __volatile__ ( "\n1:\n\t"
"dec %2\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %b3, %b3\n\t"
"jnz 1b\n\t"
/* Equal */
"\n2:\n\t"
"xor %3, %3\n\t"
"jmp 4f\n\t"
/* Not equal; CF indicates difference */
"\n3:\n\t"
"sbb %3, %3\n\t"
"orb $1, %b3\n\t"
"\n4:\n\t"
: "=&S" ( discard_S ), "=&D" ( discard_D ),
"=&c" ( discard_c ), "=&a" ( diff )
: "0" ( str1 ), "1" ( str2 ), "2" ( len ) );
return diff;
}

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2012 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 (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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* TCP/IP checksum
*
*/
#include <limits.h>
#include <ipxe/tcpip.h>
extern char x86_tcpip_loop_end[];
/**
* Calculate continued TCP/IP checkum
*
* @v partial Checksum of already-summed data, in network byte order
* @v data Data buffer
* @v len Length of data buffer
* @ret cksum Updated checksum, in network byte order
*/
uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
const void *data, size_t len ) {
unsigned long sum = ( ( ~partial ) & 0xffff );
unsigned long initial_word_count;
unsigned long loop_count;
unsigned long loop_partial_count;
unsigned long final_word_count;
unsigned long final_byte;
unsigned long discard_S;
unsigned long discard_c;
unsigned long discard_a;
unsigned long discard_r1;
unsigned long discard_r2;
/* Calculate number of initial 16-bit words required to bring
* the main loop into alignment. (We don't care about the
* speed for data aligned to less than 16 bits, since this
* situation won't occur in practice.)
*/
if ( len >= sizeof ( sum ) ) {
initial_word_count = ( ( -( ( intptr_t ) data ) &
( sizeof ( sum ) - 1 ) ) >> 1 );
} else {
initial_word_count = 0;
}
len -= ( initial_word_count * 2 );
/* Calculate number of iterations of the main loop. This loop
* processes native machine words (32-bit or 64-bit), and is
* unrolled 16 times. We calculate an overall iteration
* count, and a starting point for the first iteration.
*/
loop_count = ( len / ( sizeof ( sum ) * 16 ) );
loop_partial_count =
( ( len % ( sizeof ( sum ) * 16 ) ) / sizeof ( sum ) );
/* Calculate number of 16-bit words remaining after the main
* loop completes.
*/
final_word_count = ( ( len % sizeof ( sum ) ) / 2 );
/* Calculate whether or not a final byte remains at the end */
final_byte = ( len & 1 );
/* Calculate the checksum */
__asm__ ( /* Calculate position at which to jump into the
* unrolled loop.
*/
"imul $( -x86_tcpip_loop_step_size ), %4\n\t"
"add %5, %4\n\t"
/* Clear carry flag before starting checksumming */
"clc\n\t"
/* Checksum initial words */
"jmp 2f\n\t"
"\n1:\n\t"
"lodsw\n\t"
"adcw %w2, %w0\n\t"
"\n2:\n\t"
"loop 1b\n\t"
/* Main "lods;adc" loop, unrolled x16 */
"mov %12, %3\n\t"
"jmp *%4\n\t"
"\nx86_tcpip_loop_start:\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"lods%z2\n\tadc %2, %0\n\t"
"\nx86_tcpip_loop_end:\n\t"
"loop x86_tcpip_loop_start\n\t"
".equ x86_tcpip_loop_step_size, "
" ( ( x86_tcpip_loop_end - x86_tcpip_loop_start ) >> 4 )\n\t"
/* Checksum remaining whole words */
"mov %13, %3\n\t"
"jmp 2f\n\t"
"\n1:\n\t"
"lodsw\n\t"
"adcw %w2, %w0\n\t"
"\n2:\n\t"
"loop 1b\n\t"
/* Checksum final byte if applicable */
"mov %14, %3\n\t"
"loop 1f\n\t"
"adcb (%1), %b0\n\t"
"adcb $0, %h0\n\t"
"\n1:\n\t"
/* Fold down to a uint16_t */
"push %0\n\t"
"popw %w0\n\t"
"popw %w2\n\t"
"adcw %w2, %w0\n\t"
#if ULONG_MAX > 0xffffffffUL /* 64-bit only */
"popw %w2\n\t"
"adcw %w2, %w0\n\t"
"popw %w2\n\t"
"adcw %w2, %w0\n\t"
#endif /* 64-bit only */
/* Consume CF */
"adcw $0, %w0\n\t"
"adcw $0, %w0\n\t"
: "=&Q" ( sum ), "=&S" ( discard_S ), "=&a" ( discard_a ),
"=&c" ( discard_c ), "=&r" ( discard_r1 ),
"=&r" ( discard_r2 )
: "0" ( sum ), "1" ( data ), "2" ( 0 ),
"3" ( initial_word_count + 1 ), "4" ( loop_partial_count ),
"5" ( x86_tcpip_loop_end ), "g" ( loop_count + 1 ),
"g" ( final_word_count + 1 ), "g" ( final_byte ) );
return ( ~sum & 0xffff );
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2012 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.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/cpuid.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
/** @file
*
* x86 CPU feature detection command
*
*/
/** "cpuid" options */
struct cpuid_options {
/** Check AMD-defined features (%eax=0x80000001) */
int amd;
/** Check features defined via %ecx */
int ecx;
};
/** "cpuid" option list */
static struct option_descriptor cpuid_opts[] = {
OPTION_DESC ( "ext", 'e', no_argument,
struct cpuid_options, amd, parse_flag ),
/* "--amd" retained for backwards compatibility */
OPTION_DESC ( "amd", 'a', no_argument,
struct cpuid_options, amd, parse_flag ),
OPTION_DESC ( "ecx", 'c', no_argument,
struct cpuid_options, ecx, parse_flag ),
};
/** "cpuid" command descriptor */
static struct command_descriptor cpuid_cmd =
COMMAND_DESC ( struct cpuid_options, cpuid_opts, 1, 1,
"[--ext] [--ecx] <bit>" );
/**
* The "cpuid" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int cpuid_exec ( int argc, char **argv ) {
struct cpuid_options opts;
struct x86_features features;
struct x86_feature_registers *feature_regs;
uint32_t feature_reg;
unsigned int bit;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &cpuid_cmd, &opts ) ) != 0 )
return rc;
/* Parse bit number */
if ( ( rc = parse_integer ( argv[optind], &bit ) ) != 0 )
return rc;
/* Get CPU features */
x86_features ( &features );
/* Extract relevant feature register */
feature_regs = ( opts.amd ? &features.amd : &features.intel );
feature_reg = ( opts.ecx ? feature_regs->ecx : feature_regs->edx );
/* Check presence of specified feature */
return ( ( feature_reg & ( 1 << bit ) ) ? 0 : -ENOENT );
}
/** x86 CPU feature detection command */
struct command cpuid_command __command = {
.name = "cpuid",
.exec = cpuid_exec,
};

View File

@@ -31,6 +31,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_com32 ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00080000 )
#define ERRFILE_comboot_resolv ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00090000 )
#define ERRFILE_comboot_call ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000a0000 )
#define ERRFILE_sdi ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000b0000 )
#define ERRFILE_initrd ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x000c0000 )
#define ERRFILE_undi ( ERRFILE_ARCH | ERRFILE_NET | 0x00000000 )
#define ERRFILE_undiload ( ERRFILE_ARCH | ERRFILE_NET | 0x00010000 )
@@ -38,8 +40,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_undionly ( ERRFILE_ARCH | ERRFILE_NET | 0x00030000 )
#define ERRFILE_undirom ( ERRFILE_ARCH | ERRFILE_NET | 0x00040000 )
#define ERRFILE_timer_rdtsc ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_timer_bios ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
#define ERRFILE_timer_rdtsc ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
#define ERRFILE_timer_bios ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
#define ERRFILE_cpuid_cmd ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00000000 )
/** @} */

View File

@@ -3,7 +3,7 @@
/** @file
*
* i386-specific I/O API implementations
* x86-specific I/O API implementations
*
*/

View File

@@ -1,44 +1,46 @@
#ifndef ETHERBOOT_BITS_STRING_H
#define ETHERBOOT_BITS_STRING_H
/*
* Taken from Linux /usr/include/asm/string.h
* All except memcpy, memmove, memset and memcmp removed.
*
* Non-standard memswap() function added because it saves quite a bit
* of code (mbrown@fensystems.co.uk).
*/
#ifndef X86_BITS_STRING_H
#define X86_BITS_STRING_H
/*
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
* see especially strtok,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
*
* NO Copyright (C) 1991, 1992 Linus Torvalds,
* consider these trivial functions to be PD.
* 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.
*/
FILE_LICENCE ( PUBLIC_DOMAIN );
FILE_LICENCE ( GPL2_OR_LATER );
/** @file
*
* Optimised string operations
*
*/
#define __HAVE_ARCH_MEMCPY
extern void * __memcpy ( void *dest, const void *src, size_t len );
extern void * __memcpy_reverse ( void *dest, const void *src, size_t len );
#if 0
static inline __attribute__ (( always_inline )) void *
__memcpy ( void *dest, const void *src, size_t len ) {
int d0, d1, d2;
__asm__ __volatile__ ( "rep ; movsb"
: "=&c" ( d0 ), "=&S" ( d1 ), "=&D" ( d2 )
: "0" ( len ), "1" ( src ), "2" ( dest )
: "memory" );
return dest;
}
#endif
/**
* Copy memory area (where length is a compile-time constant)
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
static inline __attribute__ (( always_inline )) void *
__constant_memcpy ( void *dest, const void *src, size_t len ) {
union {
@@ -150,103 +152,81 @@ __constant_memcpy ( void *dest, const void *src, size_t len ) {
return dest;
}
#define memcpy( dest, src, len ) \
( __builtin_constant_p ( (len) ) ? \
__constant_memcpy ( (dest), (src), (len) ) : \
__memcpy ( (dest), (src), (len) ) )
/**
* Copy memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
static inline __attribute__ (( always_inline )) void *
memcpy ( void *dest, const void *src, size_t len ) {
if ( __builtin_constant_p ( len ) ) {
return __constant_memcpy ( dest, src, len );
} else {
return __memcpy ( dest, src, len );
}
}
#define __HAVE_ARCH_MEMMOVE
static inline void * memmove(void * dest,const void * src, size_t n)
{
int d0, d1, d2;
if (dest<src)
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),"1" (src),"2" (dest)
: "memory");
else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),
"1" (n-1+(const char *)src),
"2" (n-1+(char *)dest)
:"memory");
return dest;
extern void * __memmove ( void *dest, const void *src, size_t len );
/**
* Copy (possibly overlapping) memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
static inline __attribute__ (( always_inline )) void *
memmove ( void *dest, const void *src, size_t len ) {
ssize_t offset = ( dest - src );
if ( __builtin_constant_p ( offset ) ) {
if ( offset <= 0 ) {
return memcpy ( dest, src, len );
} else {
return __memcpy_reverse ( dest, src, len );
}
} else {
return __memmove ( dest, src, len );
}
}
#define __HAVE_ARCH_MEMSET
static inline void * memset(void *s, int c,size_t count)
{
int d0, d1;
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"stosb"
: "=&c" (d0), "=&D" (d1)
:"a" (c),"1" (s),"0" (count)
:"memory");
return s;
/**
* Fill memory region
*
* @v dest Destination address
* @v fill Fill pattern
* @v len Length
* @ret dest Destination address
*/
static inline void * memset ( void *dest, int fill, size_t len ) {
void *discard_D;
size_t discard_c;
__asm__ __volatile__ ( "rep stosb"
: "=&D" ( discard_D ), "=&c" ( discard_c )
: "0" ( dest ), "1" ( len ), "a" ( fill )
: "memory" );
return dest;
}
#define __HAVE_ARCH_MEMSWAP
static inline void * memswap(void *dest, void *src, size_t n)
{
long d0, d1, d2, d3;
__asm__ __volatile__(
"\n1:\t"
"movb (%2),%%al\n\t"
"xchgb (%1),%%al\n\t"
"inc %1\n\t"
"stosb\n\t"
"loop 1b"
: "=&c" (d0), "=&S" (d1), "=&D" (d2), "=&a" (d3)
: "0" (n), "1" (src), "2" (dest)
: "memory" );
return dest;
}
extern void * memswap ( void *dest, void *src, size_t len );
#define __HAVE_ARCH_STRNCMP
static inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res;
int d0, d1, d2;
__asm__ __volatile__(
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
:"1" (cs),"2" (ct),"3" (count));
return __res;
}
extern int strncmp ( const char *str1, const char *str2, size_t len );
#define __HAVE_ARCH_STRLEN
static inline size_t strlen(const char * s)
{
int d0;
register int __res;
__asm__ __volatile__(
"repne\n\t"
"scasb\n\t"
"notl %0\n\t"
"decl %0"
:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
return __res;
}
#endif /* ETHERBOOT_BITS_STRING_H */
extern size_t strlen ( const char *string );
#endif /* X86_BITS_STRING_H */

View File

@@ -0,0 +1,17 @@
#ifndef _BITS_TCPIP_H
#define _BITS_TCPIP_H
/** @file
*
* Transport-network layer interface
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
extern uint16_t x86_tcpip_continue_chksum ( uint16_t partial,
const void *data, size_t len );
#define tcpip_continue_chksum x86_tcpip_continue_chksum
#endif /* _BITS_TCPIP_H */

View File

@@ -0,0 +1,53 @@
#ifndef _IPXE_CPUID_H
#define _IPXE_CPUID_H
/** @file
*
* x86 CPU feature detection
*
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
/** An x86 CPU feature register set */
struct x86_feature_registers {
/** Features returned via %ecx */
uint32_t ecx;
/** Features returned via %edx */
uint32_t edx;
};
/** x86 CPU features */
struct x86_features {
/** Intel-defined features (%eax=0x00000001) */
struct x86_feature_registers intel;
/** AMD-defined features (%eax=0x80000001) */
struct x86_feature_registers amd;
};
/** CPUID support flag */
#define CPUID_FLAG 0x00200000UL
/** Get vendor ID and largest standard function */
#define CPUID_VENDOR_ID 0x00000000UL
/** Get standard features */
#define CPUID_FEATURES 0x00000001UL
/** Get largest extended function */
#define CPUID_AMD_MAX_FN 0x80000000UL
/** Extended function existence check */
#define CPUID_AMD_CHECK 0x80000000UL
/** Extended function existence check mask */
#define CPUID_AMD_CHECK_MASK 0xffff0000UL
/** Get extended features */
#define CPUID_AMD_FEATURES 0x80000001UL
extern void x86_features ( struct x86_features *features );
#endif /* _IPXE_CPUID_H */

View File

@@ -5,14 +5,14 @@
*
* iPXE I/O API for x86
*
* i386 uses direct pointer dereferences for accesses to memory-mapped
* x86 uses direct pointer dereferences for accesses to memory-mapped
* I/O space, and the inX/outX instructions for accesses to
* port-mapped I/O space.
*
* 64-bit atomic accesses (readq() and writeq()) use MMX instructions,
* and will crash original Pentium and earlier CPUs. Fortunately, no
* hardware that requires atomic 64-bit accesses will physically fit
* into a machine with such an old CPU anyway.
* 64-bit atomic accesses (readq() and writeq()) use MMX instructions
* under i386, and will crash original Pentium and earlier CPUs.
* Fortunately, no hardware that requires atomic 64-bit accesses will
* physically fit into a machine with such an old CPU anyway.
*/
FILE_LICENCE ( GPL2_OR_LATER );
@@ -59,7 +59,7 @@ IOAPI_INLINE ( x86, io_to_bus ) ( volatile const void *io_addr ) {
}
/*
* MMIO reads and writes up to 32 bits
* MMIO reads and writes up to native word size
*
*/
@@ -71,6 +71,9 @@ IOAPI_INLINE ( x86, _api_func ) ( volatile _type *io_addr ) { \
X86_READX ( readb, uint8_t );
X86_READX ( readw, uint16_t );
X86_READX ( readl, uint32_t );
#ifdef __x86_64__
X86_READX ( readq, uint64_t );
#endif
#define X86_WRITEX( _api_func, _type ) \
static inline __always_inline void \
@@ -81,6 +84,9 @@ IOAPI_INLINE ( x86, _api_func ) ( _type data, \
X86_WRITEX ( writeb, uint8_t );
X86_WRITEX ( writew, uint16_t );
X86_WRITEX ( writel, uint32_t );
#ifdef __x86_64__
X86_WRITEX ( writeq, uint64_t );
#endif
/*
* PIO reads and writes up to 32 bits

View File

@@ -13,7 +13,8 @@
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );

Some files were not shown because too many files have changed in this diff Show More