Update the vendored iPXE to the latest code.

This commit is contained in:
David Anderson 2017-02-22 15:13:53 -08:00
parent 735c025438
commit 33769d2ec3
144 changed files with 4828 additions and 842 deletions

View File

@ -1 +1 @@
2afd66eb55996500499eb3bcc39c66ff042679c8
30f96c9f41f2596493c6ca18060bebaaaf44415b

File diff suppressed because one or more lines are too long

View File

@ -53,6 +53,7 @@ EINFO := ./util/einfo
GENKEYMAP := ./util/genkeymap.pl
DOXYGEN := doxygen
LCAB := lcab
QEMUIMG := qemu-img
###############################################################################
#

View File

@ -1,12 +0,0 @@
#ifndef _BITS_TIMER_H
#define _BITS_TIMER_H
/** @file
*
* ARM-specific timer API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#endif /* _BITS_TIMER_H */

View File

@ -120,6 +120,11 @@ NON_AUTO_MEDIA += usb
$(QM)$(ECHO) " [FINISH] $@"
$(Q)cat $^ > $@
NON_AUTO_MEDIA += vhd
%vhd: %usb
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(QEMUIMG) convert -f raw -O vpc $< $@
# Padded floppy image (e.g. for iLO)
NON_AUTO_MEDIA += pdsk
%pdsk : %dsk

View File

@ -24,6 +24,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <ipxe/cpuid.h>
/** @file
@ -32,15 +33,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
/** Colour for debug messages */
#define colour 0x861d
/**
* Check whether or not CPUID instruction is supported
*
* @ret is_supported CPUID instruction is supported
* @ret rc Return status code
*/
int cpuid_is_supported ( void ) {
static int cpuid_instruction_supported ( void ) {
unsigned long original;
unsigned long inverted;
/* Check for instruction existence via flag modifiability */
__asm__ ( "pushf\n\t"
"pushf\n\t"
"pop %0\n\t"
@ -53,7 +58,54 @@ int cpuid_is_supported ( void ) {
"popf\n\t"
: "=&r" ( original ), "=&r" ( inverted )
: "ir" ( CPUID_FLAG ) );
return ( ( original ^ inverted ) & CPUID_FLAG );
if ( ! ( ( original ^ inverted ) & CPUID_FLAG ) ) {
DBGC ( colour, "CPUID instruction is not supported\n" );
return -ENOTSUP;
}
return 0;
}
/**
* Check whether or not CPUID function is supported
*
* @v function CPUID function
* @ret rc Return status code
*/
int cpuid_supported ( uint32_t function ) {
uint32_t max_function;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
int rc;
/* Check that CPUID instruction is available */
if ( ( rc = cpuid_instruction_supported() ) != 0 )
return rc;
/* Find highest supported function number within this family */
cpuid ( ( function & CPUID_EXTENDED ), &max_function, &discard_b,
&discard_c, &discard_d );
/* Fail if maximum function number is meaningless (e.g. if we
* are attempting to call an extended function on a CPU which
* does not support them).
*/
if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
( function & CPUID_AMD_CHECK_MASK ) ) {
DBGC ( colour, "CPUID invalid maximum function %#08x\n",
max_function );
return -EINVAL;
}
/* Fail if this function is not supported */
if ( function > max_function ) {
DBGC ( colour, "CPUID function %#08x not supported\n",
function );
return -ENOTTY;
}
return 0;
}
/**
@ -62,18 +114,13 @@ int cpuid_is_supported ( void ) {
* @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;
int rc;
/* 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 );
if ( ( rc = cpuid_supported ( CPUID_FEATURES ) ) != 0 ) {
DBGC ( features, "CPUID has no Intel-defined features\n" );
return;
}
@ -91,22 +138,13 @@ static void x86_intel_features ( struct x86_features *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;
int rc;
/* 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 );
if ( ( rc = cpuid_supported ( CPUID_AMD_FEATURES ) ) != 0 ) {
DBGC ( features, "CPUID has no AMD-defined features\n" );
return;
}
@ -127,12 +165,6 @@ 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 );

View File

@ -149,48 +149,25 @@ static int cpuid_settings_fetch ( struct settings *settings,
struct setting *setting,
void *data, size_t len ) {
uint32_t function;
uint32_t max_function;
uint32_t num_functions;
uint32_t registers;
uint32_t num_registers;
uint32_t buf[4];
uint32_t output;
uint32_t discard_b;
uint32_t discard_c;
uint32_t discard_d;
size_t frag_len;
size_t result_len = 0;
/* Fail unless CPUID is supported */
if ( ! cpuid_is_supported() ) {
DBGC ( settings, "CPUID not supported\n" );
return -ENOTSUP;
}
/* Find highest supported function number within this set */
function = CPUID_FUNCTION ( setting->tag );
cpuid ( function & CPUID_EXTENDED, &max_function, &discard_b,
&discard_c, &discard_d );
/* Fail if maximum function number is meaningless (e.g. if we
* are attempting to call an extended function on a CPU which
* does not support them).
*/
if ( ( max_function & CPUID_AMD_CHECK_MASK ) !=
( function & CPUID_AMD_CHECK_MASK ) ) {
DBGC ( settings, "CPUID invalid maximum function\n" );
return -ENOTSUP;
}
int rc;
/* Call each function in turn */
function = CPUID_FUNCTION ( setting->tag );
num_functions = CPUID_NUM_FUNCTIONS ( setting->tag );
for ( ; num_functions-- ; function++ ) {
/* Fail if this function is not supported */
if ( function > max_function ) {
DBGC ( settings, "CPUID function %#08x not supported\n",
function );
return -ENOTSUP;
if ( ( rc = cpuid_supported ( function ) ) != 0 ) {
DBGC ( settings, "CPUID function %#08x not supported: "
"%s\n", function, strerror ( rc ) );
return rc;
}
/* Issue CPUID */

View File

@ -108,3 +108,42 @@ void * linux_mremap ( void *old_address, __kernel_size_t old_size,
int linux_munmap ( void *addr, __kernel_size_t length ) {
return linux_syscall ( __NR_munmap, addr, length );
}
int linux_socket ( int domain, int type_, int protocol ) {
#ifdef __NR_socket
return linux_syscall ( __NR_socket, domain, type_, protocol );
#else
#ifndef SOCKOP_socket
# define SOCKOP_socket 1
#endif
unsigned long sc_args[] = { domain, type_, protocol };
return linux_syscall ( __NR_socketcall, SOCKOP_socket, sc_args );
#endif
}
int linux_bind ( int fd, const struct sockaddr *addr, socklen_t addrlen ) {
#ifdef __NR_bind
return linux_syscall ( __NR_bind, fd, addr, addrlen );
#else
#ifndef SOCKOP_bind
# define SOCKOP_bind 2
#endif
unsigned long sc_args[] = { fd, (unsigned long)addr, addrlen };
return linux_syscall ( __NR_socketcall, SOCKOP_bind, sc_args );
#endif
}
ssize_t linux_sendto ( int fd, const void *buf, size_t len, int flags,
const struct sockaddr *daddr, socklen_t addrlen ) {
#ifdef __NR_sendto
return linux_syscall ( __NR_sendto, fd, buf, len, flags,
daddr, addrlen );
#else
#ifndef SOCKOP_sendto
# define SOCKOP_sendto 11
#endif
unsigned long sc_args[] = { fd, (unsigned long)buf, len,
flags, (unsigned long)daddr, addrlen };
return linux_syscall ( __NR_socketcall, SOCKOP_sendto, sc_args );
#endif
}

View File

@ -29,16 +29,70 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <ipxe/timer.h>
#include <ipxe/cpuid.h>
#include <ipxe/pit8254.h>
/**
* Number of TSC ticks per microsecond
/** Number of microseconds to use for TSC calibration */
#define TSC_CALIBRATE_US 1024
/** TSC increment per microsecond */
static unsigned long tsc_per_us;
/** Minimum resolution for scaled TSC timer */
#define TSC_SCALED_HZ 32
/** TSC scale (expressed as a bit shift)
*
* This is calibrated on the first use of the timer.
* We use this to avoid the need for 64-bit divsion on 32-bit systems.
*/
static unsigned long rdtsc_ticks_per_usec;
static unsigned int tsc_scale;
/** Number of timer ticks per scaled TSC increment */
static unsigned long ticks_per_scaled_tsc;
/** Colour for debug messages */
#define colour &tsc_per_us
/**
* Get raw TSC value
*
* @ret tsc Raw TSC value
*/
static inline __always_inline unsigned long rdtsc_raw ( void ) {
unsigned long raw;
__asm__ __volatile__ ( "rdtsc\n\t" : "=a" ( raw ) : : "edx" );
return raw;
}
/**
* Get TSC value, shifted to avoid rollover within a realistic timescale
*
* @ret tsc Scaled TSC value
*/
static inline __always_inline unsigned long rdtsc_scaled ( void ) {
unsigned long scaled;
__asm__ __volatile__ ( "rdtsc\n\t"
"shrdl %b1, %%edx, %%eax\n\t"
: "=a" ( scaled ) : "c" ( tsc_scale ) : "edx" );
return scaled;
}
/**
* Get current system time in ticks
*
* @ret ticks Current time, in ticks
*/
static unsigned long rdtsc_currticks ( void ) {
unsigned long scaled;
scaled = rdtsc_scaled();
return ( scaled * ticks_per_scaled_tsc );
}
/**
* Delay for a fixed number of microseconds
@ -48,47 +102,76 @@ static unsigned long rdtsc_ticks_per_usec;
static void rdtsc_udelay ( unsigned long usecs ) {
unsigned long start;
unsigned long elapsed;
unsigned long threshold;
/* Sanity guard, since we may divide by this */
if ( ! usecs )
usecs = 1;
start = currticks();
if ( rdtsc_ticks_per_usec ) {
/* Already calibrated; busy-wait until done */
do {
elapsed = ( currticks() - start );
} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
} else {
/* Not yet calibrated; use 8254 PIT and calibrate
* based on result.
*/
pit8254_udelay ( usecs );
elapsed = ( currticks() - start );
rdtsc_ticks_per_usec = ( elapsed / usecs );
DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
"(%ld MHz)\n", elapsed, usecs,
( rdtsc_ticks_per_usec << TSC_SHIFT ) );
}
start = rdtsc_raw();
threshold = ( usecs * tsc_per_us );
do {
elapsed = ( rdtsc_raw() - start );
} while ( elapsed < threshold );
}
/**
* Get number of ticks per second
* Probe RDTSC timer
*
* @ret ticks_per_sec Number of ticks per second
* @ret rc Return status code
*/
static unsigned long rdtsc_ticks_per_sec ( void ) {
static int rdtsc_probe ( void ) {
unsigned long before;
unsigned long after;
unsigned long elapsed;
uint32_t apm;
uint32_t discard_a;
uint32_t discard_b;
uint32_t discard_c;
int rc;
/* Calibrate timer, if not already done */
if ( ! rdtsc_ticks_per_usec )
udelay ( 1 );
/* Check that TSC is invariant */
if ( ( rc = cpuid_supported ( CPUID_APM ) ) != 0 ) {
DBGC ( colour, "RDTSC cannot determine APM features: %s\n",
strerror ( rc ) );
return rc;
}
cpuid ( CPUID_APM, &discard_a, &discard_b, &discard_c, &apm );
if ( ! ( apm & CPUID_APM_EDX_TSC_INVARIANT ) ) {
DBGC ( colour, "RDTSC has non-invariant TSC (%#08x)\n",
apm );
return -ENOTTY;
}
/* Sanity check */
assert ( rdtsc_ticks_per_usec != 0 );
/* Calibrate udelay() timer via 8254 PIT */
before = rdtsc_raw();
pit8254_udelay ( TSC_CALIBRATE_US );
after = rdtsc_raw();
elapsed = ( after - before );
tsc_per_us = ( elapsed / TSC_CALIBRATE_US );
if ( ! tsc_per_us ) {
DBGC ( colour, "RDTSC has zero TSC per microsecond\n" );
return -EIO;
}
return ( rdtsc_ticks_per_usec * 1000 * 1000 );
/* Calibrate currticks() scaling factor */
tsc_scale = 31;
ticks_per_scaled_tsc = ( ( 1UL << tsc_scale ) /
( tsc_per_us * ( 1000000 / TICKS_PER_SEC ) ) );
while ( ticks_per_scaled_tsc > ( TICKS_PER_SEC / TSC_SCALED_HZ ) ) {
tsc_scale--;
ticks_per_scaled_tsc >>= 1;
}
DBGC ( colour, "RDTSC has %ld tsc per us, %ld ticks per 2^%d tsc\n",
tsc_per_us, ticks_per_scaled_tsc, tsc_scale );
if ( ! ticks_per_scaled_tsc ) {
DBGC ( colour, "RDTSC has zero ticks per TSC\n" );
return -EIO;
}
return 0;
}
PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
PROVIDE_TIMER_INLINE ( rdtsc, currticks );
PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
/** RDTSC timer */
struct timer rdtsc_timer __timer ( TIMER_PREFERRED ) = {
.name = "rdtsc",
.probe = rdtsc_probe,
.currticks = rdtsc_currticks,
.udelay = rdtsc_udelay,
};

View File

@ -39,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <pic8259.h>
#include <ipxe/malloc.h>
#include <ipxe/device.h>
#include <ipxe/timer.h>
#include <ipxe/cpuid.h>
#include <ipxe/msr.h>
#include <ipxe/hyperv.h>
@ -51,6 +52,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#define HV_MESSAGE_MAX_WAIT_MS 1000
/** Hyper-V timer frequency (fixed 10Mhz) */
#define HV_TIMER_HZ 10000000
/** Hyper-V timer scale factor (used to avoid 64-bit division) */
#define HV_TIMER_SHIFT 18
/**
* Convert a Hyper-V status code to an iPXE status code
*
@ -145,22 +152,19 @@ static void hv_free_message ( struct hv_hypervisor *hv ) {
/**
* Check whether or not we are running in Hyper-V
*
* @v hv Hyper-V hypervisor
* @ret rc Return status code
*/
static int hv_check_hv ( struct hv_hypervisor *hv ) {
static int hv_check_hv ( void ) {
struct x86_features features;
uint32_t interface_id;
uint32_t discard_ebx;
uint32_t discard_ecx;
uint32_t discard_edx;
uint32_t available;
uint32_t permissions;
/* Check for presence of a hypervisor (not necessarily Hyper-V) */
x86_features ( &features );
if ( ! ( features.intel.ecx & CPUID_FEATURES_INTEL_ECX_HYPERVISOR ) ) {
DBGC ( hv, "HV %p not running in a hypervisor\n", hv );
DBGC ( HV_INTERFACE_ID, "HV not running in a hypervisor\n" );
return -ENODEV;
}
@ -168,11 +172,26 @@ static int hv_check_hv ( struct hv_hypervisor *hv ) {
cpuid ( HV_CPUID_INTERFACE_ID, &interface_id, &discard_ebx,
&discard_ecx, &discard_edx );
if ( interface_id != HV_INTERFACE_ID ) {
DBGC ( hv, "HV %p not running in Hyper-V (interface ID "
"%#08x)\n", hv, interface_id );
DBGC ( HV_INTERFACE_ID, "HV not running in Hyper-V (interface "
"ID %#08x)\n", interface_id );
return -ENODEV;
}
return 0;
}
/**
* Check required features
*
* @v hv Hyper-V hypervisor
* @ret rc Return status code
*/
static int hv_check_features ( struct hv_hypervisor *hv ) {
uint32_t available;
uint32_t permissions;
uint32_t discard_ecx;
uint32_t discard_edx;
/* Check that required features and privileges are available */
cpuid ( HV_CPUID_FEATURES, &available, &permissions, &discard_ecx,
&discard_edx );
@ -509,6 +528,10 @@ static int hv_probe ( struct root_device *rootdev ) {
struct hv_hypervisor *hv;
int rc;
/* Check we are running in Hyper-V */
if ( ( rc = hv_check_hv() ) != 0 )
goto err_check_hv;
/* Allocate and initialise structure */
hv = zalloc ( sizeof ( *hv ) );
if ( ! hv ) {
@ -516,9 +539,9 @@ static int hv_probe ( struct root_device *rootdev ) {
goto err_alloc;
}
/* Check we are running in Hyper-V */
if ( ( rc = hv_check_hv ( hv ) ) != 0 )
goto err_check_hv;
/* Check features */
if ( ( rc = hv_check_features ( hv ) ) != 0 )
goto err_check_features;
/* Allocate pages */
if ( ( rc = hv_alloc_pages ( hv, &hv->hypercall, &hv->synic.message,
@ -555,9 +578,10 @@ static int hv_probe ( struct root_device *rootdev ) {
hv_free_pages ( hv, hv->hypercall, hv->synic.message, hv->synic.event,
NULL );
err_alloc_pages:
err_check_hv:
err_check_features:
free ( hv );
err_alloc:
err_check_hv:
return rc;
}
@ -590,6 +614,73 @@ struct root_device hv_root_device __root_device = {
.driver = &hv_root_driver,
};
/**
* Probe timer
*
* @ret rc Return status code
*/
static int hv_timer_probe ( void ) {
uint32_t available;
uint32_t discard_ebx;
uint32_t discard_ecx;
uint32_t discard_edx;
int rc;
/* Check we are running in Hyper-V */
if ( ( rc = hv_check_hv() ) != 0 )
return rc;
/* Check for available reference counter */
cpuid ( HV_CPUID_FEATURES, &available, &discard_ebx, &discard_ecx,
&discard_edx );
if ( ! ( available & HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR ) ) {
DBGC ( HV_INTERFACE_ID, "HV has no time reference counter\n" );
return -ENODEV;
}
return 0;
}
/**
* Get current system time in ticks
*
* @ret ticks Current time, in ticks
*/
static unsigned long hv_currticks ( void ) {
/* Calculate time using a combination of bit shifts and
* multiplication (to avoid a 64-bit division).
*/
return ( ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT ) >> HV_TIMER_SHIFT ) *
( TICKS_PER_SEC / ( HV_TIMER_HZ >> HV_TIMER_SHIFT ) ) );
}
/**
* Delay for a fixed number of microseconds
*
* @v usecs Number of microseconds for which to delay
*/
static void hv_udelay ( unsigned long usecs ) {
uint32_t start;
uint32_t elapsed;
uint32_t threshold;
/* Spin until specified number of 10MHz ticks have elapsed */
start = rdmsr ( HV_X64_MSR_TIME_REF_COUNT );
threshold = ( usecs * ( HV_TIMER_HZ / 1000000 ) );
do {
elapsed = ( rdmsr ( HV_X64_MSR_TIME_REF_COUNT ) - start );
} while ( elapsed < threshold );
}
/** Hyper-V timer */
struct timer hv_timer __timer ( TIMER_PREFERRED ) = {
.name = "Hyper-V",
.probe = hv_timer_probe,
.currticks = hv_currticks,
.udelay = hv_udelay,
};
/* Drag in objects via hv_root_device */
REQUIRING_SYMBOL ( hv_root_device );

View File

@ -21,6 +21,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Get hypervisor features */
#define HV_CPUID_FEATURES 0x40000003UL
/** Time reference counter MSR is available */
#define HV_FEATURES_AVAIL_TIME_REF_COUNT_MSR 0x00000002UL
/** SynIC MSRs are available */
#define HV_FEATURES_AVAIL_SYNIC_MSR 0x00000004UL
@ -39,6 +42,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Hypercall page MSR */
#define HV_X64_MSR_HYPERCALL 0x40000001UL
/** Time reference MSR */
#define HV_X64_MSR_TIME_REF_COUNT 0x40000020UL
/** SynIC control MSR */
#define HV_X64_MSR_SCONTROL 0x40000080UL

View File

@ -94,23 +94,14 @@ static int undipci_probe ( struct pci_device *pci ) {
}
}
/* Add to device hierarchy */
snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
"UNDI-%s", pci->dev.name );
memcpy ( &undi->dev.desc, &pci->dev.desc, sizeof ( undi->dev.desc ) );
undi->dev.parent = &pci->dev;
INIT_LIST_HEAD ( &undi->dev.children );
list_add ( &undi->dev.siblings, &pci->dev.children );
/* Create network device */
if ( ( rc = undinet_probe ( undi ) ) != 0 )
if ( ( rc = undinet_probe ( undi, &pci->dev ) ) != 0 )
goto err_undinet_probe;
return 0;
err_undinet_probe:
undi_unload ( undi );
list_del ( &undi->dev.siblings );
err_find_rom:
err_load_pci:
free ( undi );
@ -128,7 +119,6 @@ static void undipci_remove ( struct pci_device *pci ) {
undinet_remove ( undi );
undi_unload ( undi );
list_del ( &undi->dev.siblings );
free ( undi );
pci_set_drvdata ( pci, NULL );
}

View File

@ -72,7 +72,8 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
/* Only one UNDI instance may be loaded at any given time */
if ( undi_loader_entry.segment ) {
DBG ( "UNDI %p cannot load multiple instances\n", undi );
return -EBUSY;
rc = -EBUSY;
goto err_multiple;
}
/* Set up START_UNDI parameters */
@ -90,10 +91,15 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
undi_loader.UNDI_CS = fbms_seg;
fbms_seg -= ( ( undirom->data_size + 0x0f ) >> 4 );
undi_loader.UNDI_DS = fbms_seg;
undi->fbms = ( fbms_seg >> 6 );
set_fbms ( undi->fbms );
DBGC ( undi, "UNDI %p allocated [%d,%d) kB of base memory\n",
undi, undi->fbms, undi->restore_fbms );
/* Debug info */
DBGC ( undi, "UNDI %p loading UNDI ROM %p to CS %04x DS %04x for ",
undi, undirom, undi_loader.UNDI_CS, undi_loader.UNDI_DS );
DBGC ( undi, "UNDI %p loading ROM %p to CS %04x:%04zx DS %04x:%04zx "
"for ", undi, undirom, undi_loader.UNDI_CS, undirom->code_size,
undi_loader.UNDI_DS, undirom->data_size );
if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
unsigned int bus = ( undi->pci_busdevfn >> 8 );
unsigned int devfn = ( undi->pci_busdevfn & 0xff );
@ -116,15 +122,11 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
: "=a" ( exit )
: "a" ( __from_data16 ( &undi_loader ) )
: "ebx", "ecx", "edx", "esi", "edi" );
if ( exit != PXENV_EXIT_SUCCESS ) {
/* Clear entry point */
memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
rc = -EUNDILOAD ( undi_loader.Status );
DBGC ( undi, "UNDI %p loader failed: %s\n",
undi, strerror ( rc ) );
return rc;
goto err_loader;
}
/* Populate PXE device structure */
@ -138,13 +140,13 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
undi->pxenv.offset, undi->ppxe.segment, undi->ppxe.offset,
undi->entry.segment, undi->entry.offset );
/* Update free base memory counter */
undi->fbms = ( fbms_seg >> 6 );
set_fbms ( undi->fbms );
DBGC ( undi, "UNDI %p using [%d,%d) kB of base memory\n",
undi, undi->fbms, undi->restore_fbms );
return 0;
err_loader:
set_fbms ( undi->restore_fbms );
memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
err_multiple:
return rc;
}
/**

View File

@ -598,19 +598,19 @@ static const struct undinet_irq_broken undinet_irq_broken_list[] = {
/**
* Check for devices with broken support for generating interrupts
*
* @v undi UNDI device
* @v desc Device description
* @ret irq_is_broken Interrupt support is broken; no interrupts are generated
*/
static int undinet_irq_is_broken ( struct undi_device *undi ) {
static int undinet_irq_is_broken ( struct device_description *desc ) {
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 ) ) {
if ( ( desc->bus_type == BUS_TYPE_PCI ) &&
( desc->vendor == broken->pci_vendor ) &&
( desc->device == broken->pci_device ) ) {
return 1;
}
}
@ -621,9 +621,10 @@ static int undinet_irq_is_broken ( struct undi_device *undi ) {
* Probe UNDI device
*
* @v undi UNDI device
* @v dev Underlying generic device
* @ret rc Return status code
*/
int undinet_probe ( struct undi_device *undi ) {
int undinet_probe ( struct undi_device *undi, struct device *dev ) {
struct net_device *netdev;
struct undi_nic *undinic;
struct s_PXENV_START_UNDI start_undi;
@ -644,7 +645,7 @@ int undinet_probe ( struct undi_device *undi ) {
netdev_init ( netdev, &undinet_operations );
undinic = netdev->priv;
undi_set_drvdata ( undi, netdev );
netdev->dev = &undi->dev;
netdev->dev = dev;
memset ( undinic, 0, sizeof ( *undinic ) );
undinet_entry = undi->entry;
DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
@ -733,7 +734,7 @@ int undinet_probe ( struct undi_device *undi ) {
undinic );
undinic->hacks |= UNDI_HACK_EB54;
}
if ( undinet_irq_is_broken ( undi ) ) {
if ( undinet_irq_is_broken ( &dev->desc ) ) {
DBGC ( undinic, "UNDINIC %p forcing polling mode due to "
"broken interrupts\n", undinic );
undinic->irq_supported = 0;

View File

@ -50,6 +50,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* addition to the UNDI driver, build e.g. "bin/undi.dsk".
*/
/** UNDI root bus device */
static struct device undibus_dev;
/**
* Probe UNDI root bus
*
@ -60,6 +63,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
static int undibus_probe ( struct root_device *rootdev ) {
struct undi_device *undi = &preloaded_undi;
struct device *dev = &undibus_dev;
int rc;
/* Check for a valie preloaded UNDI device */
@ -69,34 +73,32 @@ static int undibus_probe ( struct root_device *rootdev ) {
}
/* Add to device hierarchy */
undi->dev.driver_name = "undionly";
dev->driver_name = "undionly";
if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
undi->dev.desc.bus_type = BUS_TYPE_PCI;
undi->dev.desc.location = undi->pci_busdevfn;
undi->dev.desc.vendor = undi->pci_vendor;
undi->dev.desc.device = undi->pci_device;
snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
"UNDI-PCI%02x:%02x.%x",
PCI_BUS ( undi->pci_busdevfn ),
dev->desc.bus_type = BUS_TYPE_PCI;
dev->desc.location = undi->pci_busdevfn;
dev->desc.vendor = undi->pci_vendor;
dev->desc.device = undi->pci_device;
snprintf ( dev->name, sizeof ( dev->name ),
"0000:%02x:%02x.%x", PCI_BUS ( undi->pci_busdevfn ),
PCI_SLOT ( undi->pci_busdevfn ),
PCI_FUNC ( undi->pci_busdevfn ) );
} else if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
undi->dev.desc.bus_type = BUS_TYPE_ISAPNP;
snprintf ( undi->dev.name, sizeof ( undi->dev.name ),
"UNDI-ISAPNP" );
dev->desc.bus_type = BUS_TYPE_ISAPNP;
snprintf ( dev->name, sizeof ( dev->name ), "ISAPNP" );
}
undi->dev.parent = &rootdev->dev;
list_add ( &undi->dev.siblings, &rootdev->dev.children);
INIT_LIST_HEAD ( &undi->dev.children );
dev->parent = &rootdev->dev;
list_add ( &dev->siblings, &rootdev->dev.children);
INIT_LIST_HEAD ( &dev->children );
/* Create network device */
if ( ( rc = undinet_probe ( undi ) ) != 0 )
if ( ( rc = undinet_probe ( undi, dev ) ) != 0 )
goto err;
return 0;
err:
list_del ( &undi->dev.siblings );
list_del ( &dev->siblings );
return rc;
}
@ -107,9 +109,10 @@ static int undibus_probe ( struct root_device *rootdev ) {
*/
static void undibus_remove ( struct root_device *rootdev __unused ) {
struct undi_device *undi = &preloaded_undi;
struct device *dev = &undibus_dev;
undinet_remove ( undi );
list_del ( &undi->dev.siblings );
list_del ( &dev->siblings );
}
/** UNDI bus root device driver */

View File

@ -168,7 +168,7 @@ static int undirom_probe ( unsigned int rom_segment ) {
/* Add to UNDI ROM list and return */
DBGC ( undirom, "UNDIROM %p registered\n", undirom );
list_add ( &undirom->list, &undiroms );
list_add_tail ( &undirom->list, &undiroms );
return 0;
err:

View File

@ -522,10 +522,12 @@ static void bzimage_load_initrds ( struct image *image,
/* Find highest usable address */
top = userptr_add ( highest->data, bzimage_align ( highest->len ) );
if ( user_to_phys ( top, 0 ) > bzimg->mem_limit )
top = phys_to_user ( bzimg->mem_limit );
if ( user_to_phys ( top, -1 ) > bzimg->mem_limit ) {
top = phys_to_user ( ( bzimg->mem_limit + 1 ) &
~( INITRD_ALIGN - 1 ) );
}
DBGC ( image, "bzImage %p loading initrds from %#08lx downwards\n",
image, user_to_phys ( top, 0 ) );
image, user_to_phys ( top, -1 ) );
/* Load initrds in order */
for_each_image ( initrd ) {

View File

@ -7,6 +7,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define BDA_EBDA 0x000e
#define BDA_EQUIPMENT_WORD 0x0010
#define BDA_FBMS 0x0013
#define BDA_TICKS 0x006c
#define BDA_MIDNIGHT 0x0070
#define BDA_REBOOT 0x0072
#define BDA_REBOOT_WARM 0x1234
#define BDA_NUM_DRIVES 0x0075

View File

@ -25,6 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_gdbmach ( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 )
#define ERRFILE_rtc_entropy ( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
#define ERRFILE_acpipwr ( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
#define ERRFILE_cpuid ( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
#define ERRFILE_rdtsc_timer ( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
#define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
#define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

View File

@ -1,15 +0,0 @@
#ifndef _BITS_TIMER_H
#define _BITS_TIMER_H
/** @file
*
* x86-specific timer API implementations
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/bios_timer.h>
#include <ipxe/rdtsc_timer.h>
#endif /* _BITS_TIMER_H */

View File

@ -1,44 +0,0 @@
#ifndef _IPXE_BIOS_TIMER_H
#define _IPXE_BIOS_TIMER_H
/** @file
*
* BIOS timer
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_PCBIOS
#define TIMER_PREFIX_pcbios
#else
#define TIMER_PREFIX_pcbios __pcbios_
#endif
#include <ipxe/pit8254.h>
/**
* Delay for a fixed number of microseconds
*
* @v usecs Number of microseconds for which to delay
*/
static inline __always_inline void
TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
/* BIOS timer is not high-resolution enough for udelay(), so
* we use the 8254 Programmable Interval Timer.
*/
pit8254_udelay ( usecs );
}
/**
* Get number of ticks per second
*
* @ret ticks_per_sec Number of ticks per second
*/
static inline __always_inline unsigned long
TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
/* BIOS timer ticks over at 18.2 ticks per second */
return 18;
}
#endif /* _IPXE_BIOS_TIMER_H */

View File

@ -57,25 +57,31 @@ struct x86_features {
/** Get CPU model */
#define CPUID_MODEL 0x80000002UL
/** Get APM information */
#define CPUID_APM 0x80000007UL
/** Invariant TSC */
#define CPUID_APM_EDX_TSC_INVARIANT 0x00000100UL
/**
* Issue CPUID instruction
*
* @v operation CPUID operation
* @v function CPUID function
* @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,
cpuid ( uint32_t function, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
uint32_t *edx ) {
__asm__ ( "cpuid"
: "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
: "0" ( operation ) );
: "0" ( function ) );
}
extern int cpuid_is_supported ( void );
extern int cpuid_supported ( uint32_t function );
extern void x86_features ( struct x86_features *features );
#endif /* _IPXE_CPUID_H */

View File

@ -1,39 +0,0 @@
#ifndef _IPXE_RDTSC_TIMER_H
#define _IPXE_RDTSC_TIMER_H
/** @file
*
* RDTSC timer
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef TIMER_RDTSC
#define TIMER_PREFIX_rdtsc
#else
#define TIMER_PREFIX_rdtsc __rdtsc_
#endif
/**
* RDTSC values can easily overflow an unsigned long. We discard the
* low-order bits in order to obtain sensibly-scaled values.
*/
#define TSC_SHIFT 8
/**
* Get current system time in ticks
*
* @ret ticks Current time, in ticks
*/
static inline __always_inline unsigned long
TIMER_INLINE ( rdtsc, currticks ) ( void ) {
unsigned long ticks;
__asm__ __volatile__ ( "rdtsc\n\t"
"shrdl %1, %%edx, %%eax\n\t"
: "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
return ticks;
}
#endif /* _IPXE_RDTSC_TIMER_H */

View File

@ -37,8 +37,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/* Register command values */
#define OCW3_ID 0x08
#define OCW3_READ_IRR 0x03
#define OCW3_READ_ISR 0x02
#define OCW3_READ_IRR 0x02
#define OCW3_READ_ISR 0x03
#define ICR_EOI_NON_SPECIFIC 0x20
#define ICR_EOI_NOP 0x40
#define ICR_EOI_SPECIFIC 0x60

View File

@ -53,8 +53,6 @@ struct undi_device {
*/
UINT16_t flags;
/** Generic device */
struct device dev;
/** Driver-private data
*
* Use undi_set_drvdata() and undi_get_drvdata() to access this

View File

@ -10,8 +10,9 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
struct undi_device;
struct device;
extern int undinet_probe ( struct undi_device *undi );
extern int undinet_probe ( struct undi_device *undi, struct device *dev );
extern void undinet_remove ( struct undi_device *undi );
#endif /* _UNDINET_H */

View File

@ -32,6 +32,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/timer.h>
#include <realmode.h>
#include <bios.h>
#include <ipxe/pit8254.h>
/** Number of ticks per day
*
* This seems to be the normative value, as used by e.g. SeaBIOS to
* decide when to set the midnight rollover flag.
*/
#define BIOS_TICKS_PER_DAY 0x1800b0
/** Number of ticks per BIOS tick */
#define TICKS_PER_BIOS_TICK \
( ( TICKS_PER_SEC * 60 * 60 * 24 ) / BIOS_TICKS_PER_DAY )
/**
* Get current system time in ticks
@ -43,7 +55,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* of calling timeofday BIOS interrupt.
*/
static unsigned long bios_currticks ( void ) {
static int days = 0;
static uint32_t offset;
uint32_t ticks;
uint8_t midnight;
@ -53,18 +65,25 @@ static unsigned long bios_currticks ( void ) {
"nop\n\t"
"cli\n\t" );
get_real ( ticks, BDA_SEG, 0x006c );
get_real ( midnight, BDA_SEG, 0x0070 );
/* Read current BIOS time of day */
get_real ( ticks, BDA_SEG, BDA_TICKS );
get_real ( midnight, BDA_SEG, BDA_MIDNIGHT );
/* Handle midnight rollover */
if ( midnight ) {
midnight = 0;
put_real ( midnight, BDA_SEG, 0x0070 );
days += 0x1800b0;
put_real ( midnight, BDA_SEG, BDA_MIDNIGHT );
offset += BIOS_TICKS_PER_DAY;
}
ticks += offset;
return ( days + ticks );
/* Convert to timer ticks */
return ( ticks * TICKS_PER_BIOS_TICK );
}
PROVIDE_TIMER_INLINE ( pcbios, udelay );
PROVIDE_TIMER ( pcbios, currticks, bios_currticks );
PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec );
/** BIOS timer */
struct timer bios_timer __timer ( TIMER_NORMAL ) = {
.name = "bios",
.currticks = bios_currticks,
.udelay = pit8254_udelay,
};

View File

@ -561,6 +561,8 @@ static int int13_guess_geometry_hdd ( struct int13_drive *int13, void *scratch,
struct master_boot_record *mbr = scratch;
struct partition_table_entry *partition;
unsigned int i;
unsigned int end_head;
unsigned int end_sector;
int rc;
/* Default guess is xx/255/63 */
@ -586,10 +588,12 @@ static int int13_guess_geometry_hdd ( struct int13_drive *int13, void *scratch,
*/
for ( i = 0 ; i < 4 ; i++ ) {
partition = &mbr->partitions[i];
if ( ! partition->type )
end_head = PART_HEAD ( partition->chs_end );
end_sector = PART_SECTOR ( partition->chs_end );
if ( ! ( partition->type && end_head && end_sector ) )
continue;
*heads = ( PART_HEAD ( partition->chs_end ) + 1 );
*sectors = PART_SECTOR ( partition->chs_end );
*heads = ( end_head + 1 );
*sectors = end_sector;
DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based "
"on partition %d\n",
int13->drive, *heads, *sectors, ( i + 1 ) );
@ -1747,7 +1751,7 @@ static void int13_unhook ( unsigned int drive ) {
* @ret rc Return status code
*/
static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
uint8_t status;
uint16_t status;
int discard_b, discard_c, discard_d;
uint16_t magic;
@ -1771,7 +1775,7 @@ static int int13_load_mbr ( unsigned int drive, struct segoff *address ) {
: "a" ( 0x0201 ), "b" ( *address ),
"c" ( 1 ), "d" ( drive ) );
if ( status ) {
DBG ( "INT13 drive %02x could not read MBR (status %02x)\n",
DBG ( "INT13 drive %02x could not read MBR (status %04x)\n",
drive, status );
return -EIO;
}
@ -1814,7 +1818,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
struct eltorito_validation_entry valid;
struct eltorito_boot_entry boot;
} __attribute__ (( packed )) catalog;
uint8_t status;
uint16_t status;
/* Use INT 13, 4d to read the boot catalog */
__asm__ __volatile__ ( REAL_CODE ( "stc\n\t"
@ -1829,7 +1833,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
"S" ( __from_data16 ( &eltorito_cmd ) ) );
if ( status ) {
DBG ( "INT13 drive %02x could not read El Torito boot catalog "
"(status %02x)\n", drive, status );
"(status %04x)\n", drive, status );
return -EIO;
}
copy_from_user ( &catalog, phys_to_user ( eltorito_cmd.buffer ), 0,
@ -1876,7 +1880,7 @@ static int int13_load_eltorito ( unsigned int drive, struct segoff *address ) {
"S" ( __from_data16 ( &eltorito_address ) ) );
if ( status ) {
DBG ( "INT13 drive %02x could not read El Torito boot image "
"(status %02x)\n", drive, status );
"(status %04x)\n", drive, status );
return -EIO;
}

View File

@ -36,10 +36,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/* Allow for DBG()-style messages within libprefix */
#ifdef NDEBUG
.macro progress message
.macro progress message, regs:vararg
.endm
#else
.macro progress message
.macro dumpreg reg, others:vararg
pushl %eax
movl \reg, %eax
pushw %di
xorw %di, %di
call print_space
call print_hex_dword
popw %di
popl %eax
.ifnb \others
dumpreg \others
.endif
.endm
.macro progress message, regs:vararg
pushfl
pushw %ds
pushw %si
@ -51,6 +65,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
call print_message
popw %di
popw %si
.ifnb \regs
dumpreg \regs
.endif
pushw %di
pushw %ax
xorw %di, %di
movb $( '\n' ), %al
call print_character
popw %ax
popw %di
popw %ds
popfl
.section ".prefix.data", "aw", @progbits
@ -659,7 +683,7 @@ hooked_bios_interrupts:
.code16
.globl install
install:
progress "install:\n"
progress "\ninstall:"
/* Preserve registers */
pushl %esi
pushl %edi
@ -702,7 +726,7 @@ install:
.code16
.globl install_prealloc
install_prealloc:
progress "install_prealloc:\n"
progress "\ninstall_prealloc:", %eax, %ebx, %esi, %edi, %ebp
/* Save registers on external stack */
pushal
pushw %ds
@ -726,7 +750,6 @@ install_prealloc:
pushl %edi
/* Install .text16.early and calculate %ecx as offset to next block */
progress " .text16.early\n"
pushl %esi
xorl %esi, %esi
movw %cs, %si
@ -737,6 +760,7 @@ install_prealloc:
shll $4, %edi
movl $_text16_early_filesz, %ecx
movl $_text16_early_memsz, %edx
progress " .text16.early ", %esi, %edi, %ecx, %edx
call install_block /* .text16.early */
jc install_block_death
popl %ecx /* Calculate offset to next block */
@ -750,7 +774,7 @@ install_prealloc:
* already have 4GB segment limits as a result of calling
* install_block.)
*/
progress " access_highmem\n"
progress " access_highmem"
pushw %cs
pushw $1f
pushw %ax
@ -762,7 +786,7 @@ install_prealloc:
#endif
/* Open payload (which may not yet be in memory) */
progress " open_payload\n"
progress " open_payload ", %esi, %ecx
pushw %cs
pushw $1f
pushw %ax
@ -779,16 +803,16 @@ install_prealloc:
1: addl %ecx, %esi
/* Install .text16.late and .data16 */
progress " .text16.late\n"
movl $_text16_late_filesz, %ecx
movl $_text16_late_memsz, %edx
progress " .text16.late ", %esi, %edi, %ecx, %edx
call install_block /* .text16.late */
jc install_block_death
progress " .data16\n"
movzwl %bx, %edi
shll $4, %edi
movl $_data16_filesz, %ecx
movl $_data16_filesz, %edx /* do not zero our temporary stack */
progress " .data16 ", %esi, %edi, %ecx, %edx
call install_block /* .data16 */
jc install_block_death
@ -825,10 +849,10 @@ install_prealloc:
* prior to reading the E820 memory map and relocating
* properly.
*/
progress " .textdata\n"
pushl %edi
movl $_textdata_filesz, %ecx
movl $_textdata_memsz, %edx
progress " .textdata ", %esi, %edi, %ecx, %edx
call install_block
jc install_block_death
popl %edi
@ -850,7 +874,7 @@ install_prealloc:
#ifndef KEEP_IT_REAL
/* Initialise librm at current location */
progress " init_librm\n"
progress " init_librm ", %eax, %ebx, %edi
movw %ax, (init_librm_vector+2)
lcall *init_librm_vector
@ -873,7 +897,6 @@ install_prealloc:
* relocate() will return with %esi, %edi and %ecx set up
* ready for the copy to the new location.
*/
progress " relocate\n"
virtcall relocate
/* Jump back to .prefix segment */
@ -882,7 +905,7 @@ install_prealloc:
.section ".prefix.install_prealloc", "awx", @progbits
1:
/* Copy code to new location */
progress " copy\n"
progress " copy ", %esi, %edi, %ecx
pushl %edi
pushw %bx
movw $copy_bytes, %bx
@ -891,7 +914,7 @@ install_prealloc:
popl %edi
/* Initialise librm at new location */
progress " init_librm\n"
progress " init_librm ", %eax, %ebx, %edi
lcall *init_librm_vector
#else /* KEEP_IT_REAL */
@ -903,7 +926,7 @@ install_prealloc:
#endif /* KEEP_IT_REAL */
/* Close access to payload */
progress " close_payload\n"
progress " close_payload"
movw %ax, (close_payload_vector+2)
lcall *close_payload_vector

View File

@ -456,6 +456,24 @@ pci_set_mem_access:
ret
.size pci_set_mem_access, . - pci_set_mem_access
/* Update image source address for UNDI loader
*
* Parameters:
* %esi : Image source address
* Returns:
* %esi : Image source address
*/
.section ".prefix", "ax", @progbits
.globl undiloader_source
undiloader_source:
/* Always use expansion ROM BAR directly when installing via
* the UNDI loader entry point, since the PMM-allocated block
* may collide with whatever is calling the UNDI loader entry
* point.
*/
xorl %esi, %esi
ret
/* Payload prefix
*
* We include a dummy ROM header to cover the "hidden" portion of the

View File

@ -35,7 +35,8 @@ undiloader:
movw %es:12(%di), %bx
movw %es:14(%di), %ax
movl image_source, %esi
movl decompress_to, %edi
call undiloader_source
xorl %edi, %edi
orl $0xffffffff, %ebp /* Allow arbitrary relocation */
call install_prealloc
popw %di
@ -57,3 +58,16 @@ undiloader:
popl %edi
popl %esi
lret
/* Update image source address for UNDI loader
*
* Parameters:
* %esi : Image source address
* Returns:
* %esi : Image source address
*/
.section ".prefix", "ax", @progbits
.globl undiloader_source
.weak undiloader_source
undiloader_source:
ret

View File

@ -7,6 +7,9 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
/* Drag in general configuration */
#include <config/general.h>
/* Drag in local definitions */
#include "librm.h"
@ -207,7 +210,9 @@ VC_TMP_CR3: .space 4
VC_TMP_CR4: .space 4
VC_TMP_EMER: .space 8
.endif
#ifdef TIVOLI_VMM_WORKAROUND
VC_TMP_FXSAVE: .space 512
#endif
VC_TMP_END:
.previous
@ -1000,11 +1005,12 @@ virt_call:
/* Claim ownership of temporary static buffer */
cli
/* Preserve FPU, MMX and SSE state in temporary static buffer */
movw %cs:rm_ds, %ds
fxsave ( rm_tmpbuf + VC_TMP_FXSAVE )
#ifdef TIVOLI_VMM_WORKAROUND
/* Preserve FPU, MMX and SSE state in temporary static buffer */
fxsave ( rm_tmpbuf + VC_TMP_FXSAVE )
#endif
/* Preserve GDT and IDT in temporary static buffer */
sidt ( rm_tmpbuf + VC_TMP_IDT )
sgdt ( rm_tmpbuf + VC_TMP_GDT )
@ -1070,9 +1076,11 @@ vc_rmode:
movl $MSR_EFER, %ecx
wrmsr
.endif
#ifdef TIVOLI_VMM_WORKAROUND
/* Restore FPU, MMX and SSE state from temporary static buffer */
fxrstor ( rm_tmpbuf + VC_TMP_FXSAVE )
#endif
/* Restore registers and flags and return */
popl %eax /* skip %cs and %ss */
popw %ds

View File

@ -1,6 +1,7 @@
#!ipxe
echo Amazon EC2 - iPXE boot via user-data
echo CPU: ${cpuvendor} ${cpumodel}
ifstat ||
dhcp ||
route ||

View File

@ -0,0 +1,8 @@
#!ipxe
echo Google Compute Engine - iPXE boot via metadata
echo CPU: ${cpuvendor} ${cpumodel}
ifstat ||
dhcp ||
route ||
chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot

View File

@ -0,0 +1,4 @@
/* Allow retrieval of metadata (such as an iPXE boot script) from
* Google Compute Engine metadata server.
*/
#define HTTP_HACK_GCE

View File

@ -0,0 +1,4 @@
/* It can often be useful to know the CPU on which a cloud instance is
* running (e.g. to isolate problems with Azure AMD instances).
*/
#define CPUID_SETTINGS

View File

@ -275,6 +275,9 @@ REQUIRE_OBJECT ( profstat_cmd );
#ifdef NTP_CMD
REQUIRE_OBJECT ( ntp_cmd );
#endif
#ifdef CERT_CMD
REQUIRE_OBJECT ( cert_cmd );
#endif
/*
* Drag in miscellaneous objects

View File

@ -43,3 +43,6 @@ REQUIRE_OBJECT ( httpdigest );
#ifdef HTTP_ENC_PEERDIST
REQUIRE_OBJECT ( peerdist );
#endif
#ifdef HTTP_HACK_GCE
REQUIRE_OBJECT ( httpgce );
#endif

View File

@ -0,0 +1,48 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <config/timer.h>
/** @file
*
* Timer configuration options
*
*/
PROVIDE_REQUIRING_SYMBOL();
/*
* Drag in timers
*/
#ifdef TIMER_PCBIOS
REQUIRE_OBJECT ( bios_timer );
#endif
#ifdef TIMER_RDTSC
REQUIRE_OBJECT ( rdtsc_timer );
#endif
#ifdef TIMER_EFI
REQUIRE_OBJECT ( efi_timer );
#endif
#ifdef TIMER_LINUX
REQUIRE_OBJECT ( linux_timer );
#endif

View File

@ -16,7 +16,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define TIMER_EFI
#define UMALLOC_EFI
#define SMBIOS_EFI
#define SANBOOT_NULL
#define SANBOOT_EFI
#define BOFM_EFI
#define ENTROPY_EFI
#define TIME_EFI
@ -27,6 +27,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define IMAGE_EFI /* EFI image support */
#define IMAGE_SCRIPT /* iPXE script image support */
#define SANBOOT_PROTO_ISCSI /* iSCSI protocol */
#define SANBOOT_PROTO_AOE /* AoE protocol */
#define SANBOOT_PROTO_IB_SRP /* Infiniband SCSI RDMA protocol */
#define SANBOOT_PROTO_FCP /* Fibre Channel protocol */
#define USB_HCD_XHCI /* xHCI USB host controller */
#define USB_HCD_EHCI /* EHCI USB host controller */
#define USB_HCD_UHCI /* UHCI USB host controller */

View File

@ -78,6 +78,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define HTTP_AUTH_BASIC /* Basic authentication */
#define HTTP_AUTH_DIGEST /* Digest authentication */
//#define HTTP_ENC_PEERDIST /* PeerDist content encoding */
//#define HTTP_HACK_GCE /* Google Compute Engine hacks */
/*
* 802.11 cryptosystems and handshaking protocols
@ -150,6 +151,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
//#define IPSTAT_CMD /* IP statistics commands */
//#define PROFSTAT_CMD /* Profiling commands */
//#define NTP_CMD /* NTP commands */
//#define CERT_CMD /* Certificate management commands */
/*
* ROM-specific options
@ -189,6 +191,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#undef GDBUDP /* Remote GDB debugging over UDP
* (both may be set) */
//#define EFI_DOWNGRADE_UX /* Downgrade UEFI user experience */
#define TIVOLI_VMM_WORKAROUND /* Work around the Tivoli VMM's garbling of SSE
* registers when iPXE traps to it due to
* privileged instructions */
#include <config/named.h>
#include NAMED_CONFIG(general.h)

View File

@ -8,3 +8,8 @@
/* Work around missing EFI_PXE_BASE_CODE_PROTOCOL */
#define EFI_DOWNGRADE_UX
/* The Tivoli VMM workaround causes a KVM emulation failure on hosts
* without unrestricted_guest support
*/
#undef TIVOLI_VMM_WORKAROUND

View File

@ -79,9 +79,6 @@ struct interface null_intf = INTF_INIT ( null_intf_desc );
* The reference to the existing destination interface is dropped, a
* reference to the new destination interface is obtained, and the
* interface is updated to point to the new destination interface.
*
* Note that there is no "unplug" call; instead you must plug the
* interface into a null interface.
*/
void intf_plug ( struct interface *intf, struct interface *dest ) {
DBGC ( INTF_COL ( intf ),
@ -113,7 +110,10 @@ void intf_plug_plug ( struct interface *a, struct interface *b ) {
* @v intf Object interface
*/
void intf_unplug ( struct interface *intf ) {
intf_plug ( intf, &null_intf );
DBGC ( INTF_COL ( intf ), "INTF " INTF_INTF_FMT " unplug\n",
INTF_INTF_DBG ( intf, intf->dest ) );
intf_put ( intf->dest );
intf->dest = &null_intf;
}
/**
@ -271,6 +271,7 @@ void intf_close ( struct interface *intf, int rc ) {
* unplugs the interface.
*/
void intf_shutdown ( struct interface *intf, int rc ) {
struct interface tmp;
DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " shutting down (%s)\n",
INTF_DBG ( intf ), strerror ( rc ) );
@ -278,11 +279,50 @@ void intf_shutdown ( struct interface *intf, int rc ) {
/* Block further operations */
intf_nullify ( intf );
/* Notify destination of close */
intf_close ( intf, rc );
/* Transfer destination to temporary interface */
tmp.dest = intf->dest;
intf->dest = &null_intf;
/* Unplug interface */
intf_unplug ( intf );
/* Notify destination of close via temporary interface */
intf_close ( &tmp, rc );
/* Unplug temporary interface */
intf_unplug ( &tmp );
}
/**
* Shut down multiple object interfaces
*
* @v intfs Object interfaces
* @v rc Reason for close
*/
void intfs_vshutdown ( va_list intfs, int rc ) {
struct interface *intf;
va_list tmp;
/* Nullify all interfaces to avoid potential loops */
va_copy ( tmp, intfs );
while ( ( intf = va_arg ( tmp, struct interface * ) ) )
intf_nullify ( intf );
va_end ( tmp );
/* Shut down all interfaces */
while ( ( intf = va_arg ( intfs, struct interface * ) ) )
intf_shutdown ( intf, rc );
}
/**
* Shut down multiple object interfaces
*
* @v rc Reason for close
* @v ... Object interfaces
*/
void intfs_shutdown ( int rc, ... ) {
va_list intfs;
va_start ( intfs, rc );
intfs_vshutdown ( intfs, rc );
va_end ( intfs );
}
/**
@ -295,7 +335,6 @@ void intf_shutdown ( struct interface *intf, int rc ) {
* blocked during shutdown.
*/
void intf_restart ( struct interface *intf, int rc ) {
struct interface_descriptor *desc = intf->desc;
/* Shut down the interface */
intf_shutdown ( intf, rc );
@ -309,7 +348,41 @@ void intf_restart ( struct interface *intf, int rc ) {
* infinite loop as the intf_close() operations on each side
* of the link call each other recursively.
*/
intf->desc = desc;
intf_reinit ( intf );
}
/**
* Shut down and restart multiple object interfaces
*
* @v intfs Object interfaces
* @v rc Reason for close
*/
void intfs_vrestart ( va_list intfs, int rc ) {
struct interface *intf;
va_list tmp;
/* Shut down all interfaces */
va_copy ( tmp, intfs );
intfs_vshutdown ( tmp, rc );
va_end ( tmp );
/* Reinitialise all interfaces */
while ( ( intf = va_arg ( intfs, struct interface * ) ) )
intf_reinit ( intf );
}
/**
* Shut down and restart multiple object interfaces
*
* @v rc Reason for close
* @v ... Object interfaces
*/
void intfs_restart ( int rc, ... ) {
va_list intfs;
va_start ( intfs, rc );
intfs_vrestart ( intfs, rc );
va_end ( intfs );
}
/**

View File

@ -117,7 +117,7 @@ int parse_timeout ( char *text, unsigned long *value ) {
return rc;
/* Convert to a number of timer ticks */
*value = ( ( value_ms * TICKS_PER_SEC ) / 1000 );
*value = ( value_ms * TICKS_PER_MS );
return 0;
}

View File

@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <byteswap.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
#include <ipxe/in.h>
#include <ipxe/ip.h>
#include <ipxe/ipv6.h>
@ -2552,6 +2553,38 @@ struct builtin_setting version_builtin_setting __builtin_setting = {
.fetch = version_fetch,
};
/**
* Fetch current time setting
*
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int unixtime_fetch ( void *data, size_t len ) {
uint32_t content;
/* Return current time */
content = htonl ( time(NULL) );
if ( len > sizeof ( content ) )
len = sizeof ( content );
memcpy ( data, &content, len );
return sizeof ( content );
}
/** Current time setting */
const struct setting unixtime_setting __setting ( SETTING_MISC, unixtime ) = {
.name = "unixtime",
.description = "Seconds since the Epoch",
.type = &setting_type_uint32,
.scope = &builtin_scope,
};
/** Current time built-in setting */
struct builtin_setting unixtime_builtin_setting __builtin_setting = {
.setting = &unixtime_setting,
.fetch = unixtime_fetch,
};
/**
* Fetch built-in setting
*

View File

@ -23,11 +23,52 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <unistd.h>
#include <string.h>
#include <ipxe/process.h>
#include <ipxe/console.h>
#include <ipxe/keys.h>
#include <ipxe/nap.h>
#include <ipxe/init.h>
#include <ipxe/timer.h>
/** Current timer */
static struct timer *timer;
/**
* Get current system time in ticks
*
* @ret ticks Current time, in ticks
*/
unsigned long currticks ( void ) {
/* Guard against use during early initialisation */
if ( ! timer ) {
DBGC ( &timer, "TIMER currticks() called before initialisation "
"from %p\n", __builtin_return_address ( 0 ) );
return 0;
}
/* Use selected timer */
return timer->currticks();
}
/**
* Delay for a fixed number of microseconds
*
* @v usecs Number of microseconds for which to delay
*/
void udelay ( unsigned long usecs ) {
/* Guard against use during early initialisation */
if ( ! timer ) {
DBGC ( &timer, "TIMER udelay() called before initialisation "
"from %p\n", __builtin_return_address ( 0 ) );
return;
}
/* Use selected timer */
timer->udelay ( usecs );
}
/**
* Delay for a fixed number of milliseconds
@ -35,6 +76,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @v msecs Number of milliseconds for which to delay
*/
void mdelay ( unsigned long msecs ) {
/* Guard against use during early initialisation */
if ( ! timer ) {
DBGC ( &timer, "TIMER mdelay() called before initialisation "
"from %p\n", __builtin_return_address ( 0 ) );
return;
}
/* Delay for specified number of milliseconds */
while ( msecs-- )
udelay ( 1000 );
}
@ -61,3 +111,35 @@ unsigned int sleep ( unsigned int secs ) {
return 0;
}
/**
* Find a working timer
*
*/
static void timer_probe ( void ) {
int rc;
/* Use first working timer */
for_each_table_entry ( timer, TIMERS ) {
if ( ( timer->probe == NULL ) ||
( ( rc = timer->probe() ) == 0 ) ) {
DBGC ( &timer, "TIMER using %s\n", timer->name );
return;
}
DBGC ( &timer, "TIMER could not initialise %s: %s\n",
timer->name, strerror ( rc ) );
}
/* This is a fatal error */
DBGC ( &timer, "TIMER found no working timers!\n" );
while ( 1 ) {}
}
/** Timer initialisation function */
struct init_fn timer_init_fn __init_fn ( INIT_EARLY ) = {
.initialise = timer_probe,
};
/* Drag in timer configuration */
REQUIRING_SYMBOL ( timer_init_fn );
REQUIRE_OBJECT ( config_timer );

View File

@ -40,7 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* @v uuid UUID
* @ret string UUID in canonical form
*/
char * uuid_ntoa ( const union uuid *uuid ) {
const char * uuid_ntoa ( const union uuid *uuid ) {
static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */
sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",

View File

@ -145,6 +145,24 @@ void certstore_add ( struct x509_certificate *cert ) {
x509_name ( cert ) );
}
/**
* Remove certificate from store
*
* @v cert X.509 certificate
*/
void certstore_del ( struct x509_certificate *cert ) {
/* Ignore attempts to remove permanent certificates */
if ( cert->flags & X509_FL_PERMANENT )
return;
/* Remove certificate from store */
DBGC ( &certstore, "CERTSTORE removed certificate %s\n",
x509_name ( cert ) );
list_del ( &cert->store.list );
x509_put ( cert );
}
/**
* Discard a stored certificate
*
@ -157,14 +175,22 @@ static unsigned int certstore_discard ( void ) {
* only reference is held by the store itself.
*/
list_for_each_entry_reverse ( cert, &certstore.links, store.list ) {
if ( cert->refcnt.count == 0 ) {
DBGC ( &certstore, "CERTSTORE discarded certificate "
"%s\n", x509_name ( cert ) );
list_del ( &cert->store.list );
x509_put ( cert );
return 1;
}
/* Skip certificates for which another reference is held */
if ( cert->refcnt.count > 0 )
continue;
/* Skip certificates that were added at build time or
* added explicitly at run time.
*/
if ( cert->flags & ( X509_FL_PERMANENT | X509_FL_EXPLICIT ) )
continue;
/* Discard certificate */
certstore_del ( cert );
return 1;
}
return 0;
}
@ -214,6 +240,7 @@ static void certstore_init ( void ) {
* permanent reference to it.
*/
certstore_add ( cert );
cert->flags |= X509_FL_PERMANENT;
DBGC ( &certstore, "CERTSTORE permanent certificate %d is %s\n",
i, x509_name ( cert ) );
}

View File

@ -282,7 +282,7 @@ int ocsp_check ( struct x509_certificate *cert,
/* Sanity checks */
assert ( cert != NULL );
assert ( issuer != NULL );
assert ( issuer->valid );
assert ( x509_is_valid ( issuer ) );
/* Allocate and initialise check */
*ocsp = zalloc ( sizeof ( **ocsp ) );

View File

@ -39,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/certstore.h>
#include <ipxe/socket.h>
#include <ipxe/in.h>
#include <ipxe/image.h>
#include <ipxe/x509.h>
#include <config/crypto.h>
@ -121,10 +122,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
__einfo_uniqify ( EINFO_EACCES, 0x0b, "No usable certificates" )
/**
* Get X.509 certificate name (for debugging)
* Get X.509 certificate display name
*
* @v cert X.509 certificate
* @ret name Name (for debugging)
* @ret name Display name
*/
const char * x509_name ( struct x509_certificate *cert ) {
struct asn1_cursor *common_name = &cert->subject.common_name;
@ -1319,7 +1320,7 @@ int x509_validate ( struct x509_certificate *cert,
root = &root_certificates;
/* Return success if certificate has already been validated */
if ( cert->valid )
if ( x509_is_valid ( cert ) )
return 0;
/* Fail if certificate is invalid at specified time */
@ -1328,7 +1329,7 @@ int x509_validate ( struct x509_certificate *cert,
/* Succeed if certificate is a trusted root certificate */
if ( x509_check_root ( cert, root ) == 0 ) {
cert->valid = 1;
cert->flags |= X509_FL_VALIDATED;
cert->path_remaining = ( cert->extensions.basic.path_len + 1 );
return 0;
}
@ -1341,7 +1342,7 @@ int x509_validate ( struct x509_certificate *cert,
}
/* Fail unless issuer has already been validated */
if ( ! issuer->valid ) {
if ( ! x509_is_valid ( issuer ) ) {
DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) );
DBGC ( cert, "issuer %p \"%s\" has not yet been validated\n",
issuer, x509_name ( issuer ) );
@ -1375,7 +1376,7 @@ int x509_validate ( struct x509_certificate *cert,
cert->path_remaining = max_path_remaining;
/* Mark certificate as valid */
cert->valid = 1;
cert->flags |= X509_FL_VALIDATED;
DBGC ( cert, "X509 %p \"%s\" successfully validated using ",
cert, x509_name ( cert ) );
@ -1766,6 +1767,47 @@ int x509_validate_chain ( struct x509_chain *chain, time_t time,
return -EACCES_USELESS;
}
/**
* Extract X.509 certificate object from image
*
* @v image Image
* @v offset Offset within image
* @ret cert X.509 certificate
* @ret next Offset to next image, or negative error
*
* On success, the caller holds a reference to the X.509 certificate,
* and is responsible for ultimately calling x509_put().
*/
int image_x509 ( struct image *image, size_t offset,
struct x509_certificate **cert ) {
struct asn1_cursor *cursor;
int next;
int rc;
/* Get ASN.1 object */
next = image_asn1 ( image, offset, &cursor );
if ( next < 0 ) {
rc = next;
goto err_asn1;
}
/* Parse certificate */
if ( ( rc = x509_certificate ( cursor->data, cursor->len,
cert ) ) != 0 )
goto err_certificate;
/* Free ASN.1 object */
free ( cursor );
return next;
x509_put ( *cert );
err_certificate:
free ( cursor );
err_asn1:
return rc;
}
/* Drag in objects via x509_validate() */
REQUIRING_SYMBOL ( x509_validate );

View File

@ -21,11 +21,37 @@
#include "ipxe/virtio-pci.h"
#include "ipxe/virtio-ring.h"
static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num)
{
size_t queue_size = PAGE_MASK + vring_size(num);
size_t vdata_size = num * sizeof(void *);
vq->queue = zalloc(queue_size + vdata_size);
if (!vq->queue) {
return -ENOMEM;
}
/* vdata immediately follows the ring */
vq->vdata = (void **)(vq->queue + queue_size);
return 0;
}
void vp_free_vq(struct vring_virtqueue *vq)
{
if (vq->queue) {
free(vq->queue);
vq->queue = NULL;
vq->vdata = NULL;
}
}
int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq)
{
struct vring * vr = &vq->vring;
u16 num;
int rc;
/* select the queue */
@ -39,11 +65,6 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
return -1;
}
if (num > MAX_QUEUE_NUM) {
DBG("VIRTIO-PCI ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
return -1;
}
/* check if the queue is already active */
if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
@ -54,8 +75,12 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
vq->queue_index = queue_index;
/* initialize the queue */
vring_init(vr, num, (unsigned char*)&vq->queue);
rc = vp_alloc_vq(vq, num);
if (rc) {
DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n");
return rc;
}
vring_init(vr, num, vq->queue);
/* activate the queue
*
@ -354,18 +379,29 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
return -ENOENT;
if (size & (size - 1)) {
DBG("VIRTIO-PCI %p: bad queue size %d", vdev, size);
DBG("VIRTIO-PCI %p: bad queue size %d\n", vdev, size);
return -EINVAL;
}
if (size > MAX_QUEUE_NUM) {
/* iPXE networking tends to be not perf critical so there's no
* need to accept large queue sizes.
*/
size = MAX_QUEUE_NUM;
}
vq = &vqs[i];
vq->queue_index = i;
/* get offset of notification word for this vq */
off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off));
vq->vring.num = size;
vring_init(&vq->vring, size, (unsigned char *)vq->queue);
err = vp_alloc_vq(vq, size);
if (err) {
DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev);
return err;
}
vring_init(&vq->vring, size, vq->queue);
/* activate the queue */
vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size));
@ -385,7 +421,7 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
off * notify_offset_multiplier, 2,
&vq->notification);
if (err) {
goto err_map_notify;
return err;
}
}
@ -399,11 +435,4 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
vpm_iowrite16(vdev, &vdev->common, 1, COMMON_OFFSET(queue_enable));
}
return 0;
err_map_notify:
/* Undo the virtio_pci_map_capability calls. */
while (i-- > 0) {
virtio_pci_unmap_capability(&vqs[i].notification);
}
return err;
}

View File

@ -22,7 +22,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/pci.h>
#include <ipxe/malloc.h>
#include <ipxe/umalloc.h>
@ -31,10 +30,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/vlan.h>
#include <ipxe/io.h>
#include "flexboot_nodnic.h"
#include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig.h"
#include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig_defaults.h"
#include "mlx_utils/include/public/mlx_pci_gw.h"
#include "mlx_utils/mlx_lib/mlx_vmac/mlx_vmac.h"
#include "mlx_utils/include/public/mlx_types.h"
#include "mlx_utils/include/public/mlx_utils.h"
#include "mlx_utils/include/public/mlx_bail.h"
@ -43,6 +38,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include "mlx_utils/include/public/mlx_pci.h"
#include "mlx_nodnic/include/mlx_device.h"
#include "mlx_nodnic/include/mlx_port.h"
#include <byteswap.h>
#include <usr/ifmgmt.h>
#include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig.h"
#include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig_defaults.h"
#include "mlx_utils/include/public/mlx_pci_gw.h"
#include "mlx_utils/mlx_lib/mlx_vmac/mlx_vmac.h"
/***************************************************************************
*
@ -52,10 +53,27 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
static int flexboot_nodnic_arm_cq ( struct flexboot_nodnic_port *port ) {
#ifndef DEVICE_CX3
mlx_uint32 val = ( port->eth_cq->next_idx & 0xffff );
if ( nodnic_port_set ( & port->port_priv, nodnic_port_option_arm_cq, val ) ) {
MLX_DEBUG_ERROR( port->port_priv.device, "Failed to arm the CQ\n" );
return MLX_FAILED;
mlx_uint32 val32 = 0;
union arm_cq_uar cq_uar;
#define ARM_CQ_UAR_CQ_CI_MASK 0xffffff
#define ARM_CQ_UAR_CMDSN_MASK 3
#define ARM_CQ_UAR_CMDSN_OFFSET 28
#define ARM_CQ_UAR_CQ_CI_OFFSET 0x20
if ( port->port_priv.device->device_cap.support_bar_cq_ctrl ) {
cq_uar.dword[0] = cpu_to_be32((port->eth_cq->next_idx & ARM_CQ_UAR_CQ_CI_MASK) |
((port->cmdsn++ & ARM_CQ_UAR_CMDSN_MASK) << ARM_CQ_UAR_CMDSN_OFFSET));
cq_uar.dword[1] = cpu_to_be32(port->eth_cq->cqn);
wmb();
writeq(cq_uar.qword, port->port_priv.device->uar.virt + ARM_CQ_UAR_CQ_CI_OFFSET);
port->port_priv.arm_cq_doorbell_record->dword[0] = cq_uar.dword[1];
port->port_priv.arm_cq_doorbell_record->dword[1] = cq_uar.dword[0];
} else {
val32 = ( port->eth_cq->next_idx & 0xffffff );
if ( nodnic_port_set ( & port->port_priv, nodnic_port_option_arm_cq, val32 ) ) {
MLX_DEBUG_ERROR( port->port_priv.device, "Failed to arm the CQ\n" );
return MLX_FAILED;
}
}
#else
mlx_utils *utils = port->port_priv.device->utils;
@ -77,7 +95,7 @@ static int flexboot_nodnic_arm_cq ( struct flexboot_nodnic_port *port ) {
data = ( ( ( port->eth_cq->next_idx & 0xffff ) << 16 ) | 0x0080 );
/* Write the new index and update FW that new data was submitted */
mlx_pci_mem_write ( utils, MlxPciWidthUint32, 0,
( mlx_uint64 ) & ( ptr->armcq_cq_ci_dword ), 1, &data );
( mlx_uintn ) & ( ptr->armcq_cq_ci_dword ), 1, &data );
}
#endif
return 0;
@ -96,6 +114,7 @@ static int flexboot_nodnic_create_cq ( struct ib_device *ibdev ,
struct flexboot_nodnic_port *port = &flexboot_nodnic->port[ibdev->port - 1];
struct flexboot_nodnic_completion_queue *flexboot_nodnic_cq;
mlx_status status = MLX_SUCCESS;
mlx_uint32 cqn;
flexboot_nodnic_cq = (struct flexboot_nodnic_completion_queue *)
zalloc(sizeof(*flexboot_nodnic_cq));
@ -114,10 +133,18 @@ static int flexboot_nodnic_create_cq ( struct ib_device *ibdev ,
flexboot_nodnic->callbacks->cqe_set_owner(
flexboot_nodnic_cq->nodnic_completion_queue->cq_virt,
cq->num_cqes);
if ( flexboot_nodnic->device_priv.device_cap.support_bar_cq_ctrl ) {
status = nodnic_port_query(&port->port_priv,
nodnic_port_option_cq_n_index,
(mlx_uint32 *)&cqn );
MLX_FATAL_CHECK_STATUS(status, read_cqn_err,
"failed to query cqn");
cq->cqn = cqn;
}
ib_cq_set_drvdata ( cq, flexboot_nodnic_cq );
return status;
read_cqn_err:
create_err:
free(flexboot_nodnic_cq);
qp_alloc_err:
@ -450,6 +477,9 @@ static int flexboot_nodnic_post_send ( struct ib_device *ibdev,
status = port->port_priv.send_doorbell ( &port->port_priv,
&send_ring->nodnic_ring, ( mlx_uint16 ) wq->next_idx );
if ( flexboot_nodnic->callbacks->tx_uar_send_doorbell_fn ) {
flexboot_nodnic->callbacks->tx_uar_send_doorbell_fn ( ibdev, wqbb );
}
if ( status != 0 ) {
DBGC ( flexboot_nodnic, "flexboot_nodnic %p ring send doorbell failed\n", flexboot_nodnic );
}
@ -1293,12 +1323,14 @@ int flexboot_nodnic_is_supported ( struct pci_device *pci ) {
mlx_pci_gw_teardown( &utils );
pci_gw_init_err:
mlx_utils_teardown(&utils);
utils_init_err:
DBG ( "%s: NODNIC is %s supported (status = %d)\n",
__FUNCTION__, ( is_supported ? "": "not" ), status );
return is_supported;
}
void flexboot_nodnic_copy_mac ( uint8_t mac_addr[], uint32_t low_byte,
uint16_t high_byte ) {
union mac_addr {
@ -1329,13 +1361,14 @@ static mlx_status flexboot_nodnic_get_factory_mac (
status = mlx_vmac_query_virt_mac ( flexboot_nodnic_priv->device_priv.utils,
&virt_mac );
if ( ! status ) {
DBGC ( flexboot_nodnic_priv, "NODNIC %p Failed to set the virtual MAC\n",
flexboot_nodnic_priv );
DBGC ( flexboot_nodnic_priv, "NODNIC %p Failed to set the virtual MAC\n"
,flexboot_nodnic_priv );
}
return status;
}
/**
* Set port masking
*
@ -1361,6 +1394,79 @@ static int flexboot_nodnic_set_port_masking ( struct flexboot_nodnic *flexboot_n
return 0;
}
int init_mlx_utils ( mlx_utils **utils, struct pci_device *pci ) {
int rc = 0;
*utils = ( mlx_utils * ) zalloc ( sizeof ( mlx_utils ) );
if ( *utils == NULL ) {
DBGC ( utils, "%s: Failed to allocate utils\n", __FUNCTION__ );
rc = -1;
goto err_utils_alloc;
}
if ( mlx_utils_init ( *utils, pci ) ) {
DBGC ( utils, "%s: mlx_utils_init failed\n", __FUNCTION__ );
rc = -1;
goto err_utils_init;
}
if ( mlx_pci_gw_init ( *utils ) ){
DBGC ( utils, "%s: mlx_pci_gw_init failed\n", __FUNCTION__ );
rc = -1;
goto err_cmd_init;
}
return 0;
mlx_pci_gw_teardown ( *utils );
err_cmd_init:
mlx_utils_teardown ( *utils );
err_utils_init:
free ( *utils );
err_utils_alloc:
*utils = NULL;
return rc;
}
void free_mlx_utils ( mlx_utils **utils ) {
mlx_pci_gw_teardown ( *utils );
mlx_utils_teardown ( *utils );
free ( *utils );
*utils = NULL;
}
/**
* Initialise Nodnic PCI parameters
*
* @v hermon Nodnic device
*/
static int flexboot_nodnic_alloc_uar ( struct flexboot_nodnic *flexboot_nodnic ) {
mlx_status status = MLX_SUCCESS;
struct pci_device *pci = flexboot_nodnic->pci;
nodnic_uar *uar = &flexboot_nodnic->port[0].port_priv.device->uar;
if ( ! flexboot_nodnic->device_priv.utils ) {
uar->virt = NULL;
DBGC ( flexboot_nodnic, "%s: mlx_utils is not initialized \n", __FUNCTION__ );
return -EINVAL;
}
if ( ! flexboot_nodnic->device_priv.device_cap.support_uar_tx_db ) {
DBGC ( flexboot_nodnic, "%s: tx db using uar is not supported \n", __FUNCTION__ );
return -ENOTSUP;
}
/* read uar offset then allocate */
if ( ( status = nodnic_port_set_send_uar_offset ( &flexboot_nodnic->port[0].port_priv ) ) ) {
DBGC ( flexboot_nodnic, "%s: nodnic_port_set_send_uar_offset failed,"
"status = %d\n", __FUNCTION__, status );
return -EINVAL;
}
uar->phys = ( pci_bar_start ( pci, FLEXBOOT_NODNIC_HCA_BAR ) + (mlx_uint32)uar->offset );
uar->virt = ( void * )( ioremap ( uar->phys, FLEXBOOT_NODNIC_PAGE_SIZE ) );
return status;
}
int flexboot_nodnic_probe ( struct pci_device *pci,
struct flexboot_nodnic_callbacks *callbacks,
void *drv_priv __unused ) {
@ -1388,21 +1494,10 @@ int flexboot_nodnic_probe ( struct pci_device *pci,
pci_set_drvdata ( pci, flexboot_nodnic_priv );
device_priv = &flexboot_nodnic_priv->device_priv;
device_priv->utils = (mlx_utils *)zalloc( sizeof ( mlx_utils ) );
if ( device_priv->utils == NULL ) {
DBGC ( flexboot_nodnic_priv, "%s: Failed to allocate utils\n", __FUNCTION__ );
status = MLX_OUT_OF_RESOURCES;
goto utils_err_alloc;
}
status = mlx_utils_init( device_priv->utils, pci );
MLX_FATAL_CHECK_STATUS(status, utils_init_err,
"mlx_utils_init failed");
/* nodnic init*/
status = mlx_pci_gw_init( device_priv->utils );
MLX_FATAL_CHECK_STATUS(status, cmd_init_err,
"mlx_pci_gw_init failed");
/* init mlx utils */
status = init_mlx_utils ( & device_priv->utils, pci );
MLX_FATAL_CHECK_STATUS(status, err_utils_init,
"init_mlx_utils failed");
/* init device */
status = nodnic_device_init( device_priv );
@ -1426,6 +1521,11 @@ int flexboot_nodnic_probe ( struct pci_device *pci,
MLX_FATAL_CHECK_STATUS(status, err_thin_init_ports,
"flexboot_nodnic_thin_init_ports failed");
if ( ( status = flexboot_nodnic_alloc_uar ( flexboot_nodnic_priv ) ) ) {
DBGC(flexboot_nodnic_priv, "%s: flexboot_nodnic_pci_init failed"
" ( status = %d )\n",__FUNCTION__, status );
}
/* device reg */
status = flexboot_nodnic_set_ports_type( flexboot_nodnic_priv );
MLX_CHECK_STATUS( flexboot_nodnic_priv, status, err_set_ports_types,
@ -1456,11 +1556,8 @@ err_set_masking:
get_cap_err:
nodnic_device_teardown ( device_priv );
device_init_err:
mlx_pci_gw_teardown ( device_priv->utils );
cmd_init_err:
utils_init_err:
free ( device_priv->utils );
utils_err_alloc:
free_mlx_utils ( & device_priv->utils );
err_utils_init:
free ( flexboot_nodnic_priv );
device_err_alloc:
return status;
@ -1473,7 +1570,6 @@ void flexboot_nodnic_remove ( struct pci_device *pci )
flexboot_nodnic_ports_unregister_dev ( flexboot_nodnic_priv );
nodnic_device_teardown( device_priv );
mlx_pci_gw_teardown( device_priv->utils );
free( device_priv->utils );
free_mlx_utils ( & device_priv->utils );
free( flexboot_nodnic_priv );
}

View File

@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/io.h>
#include <ipxe/infiniband.h>
#include <ipxe/netdevice.h>
#include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig.h"
/*
* If defined, use interrupts in NODNIC driver
@ -37,6 +38,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define FLEXBOOT_NODNIC_PORT_BASE 1
#define FLEXBOOT_NODNIC_OPCODE_SEND 0xa
#define FLEXBOOT_NODNIC_HCA_BAR PCI_BASE_ADDRESS_0 //BAR 0
#define FLEXBOOT_NODNIC_PAGE_SHIFT 12
#define FLEXBOOT_NODNIC_PAGE_SIZE (1 << FLEXBOOT_NODNIC_PAGE_SHIFT)
#define FLEXBOOT_NODNIC_PAGE_MASK (FLEXBOOT_NODNIC_PAGE_SIZE - 1)
/* Port protocol */
enum flexboot_nodnic_protocol {
@ -60,6 +65,7 @@ struct flexboot_nodnic_port {
struct ib_completion_queue *eth_cq;
/** Ethernet queue pair */
struct ib_queue_pair *eth_qp;
mlx_uint8 cmdsn;
};
@ -136,6 +142,21 @@ struct cqe_data{
mlx_uint32 byte_cnt;
};
union arm_cq_uar {
struct {
//big endian
mlx_uint32 reserved0 :2;
mlx_uint32 cmdn :2;
mlx_uint32 reserved1 :3;
mlx_uint32 cmd :1;
mlx_uint32 cq_ci :24;
mlx_uint32 reserved2 :8;
mlx_uint32 cq_n :24;
};
mlx_uint32 dword[2];
mlx_uint64 qword;
};
struct flexboot_nodnic_callbacks {
mlx_status ( * fill_completion ) ( void *cqe, struct cqe_data *cqe_data );
mlx_status ( * cqe_set_owner ) ( void *cq, unsigned int num_cqes );
@ -149,6 +170,10 @@ struct flexboot_nodnic_callbacks {
unsigned long wqe_idx
);
void ( * irq ) ( struct net_device *netdev, int enable );
mlx_status ( * tx_uar_send_doorbell_fn ) (
struct ib_device *ibdev,
struct nodnic_send_wqbb *wqbb
);
};
int flexboot_nodnic_probe ( struct pci_device *pci,
@ -159,5 +184,6 @@ void flexboot_nodnic_eth_irq ( struct net_device *netdev, int enable );
int flexboot_nodnic_is_supported ( struct pci_device *pci );
void flexboot_nodnic_copy_mac ( uint8_t mac_addr[], uint32_t low_byte,
uint16_t high_byte );
int init_mlx_utils ( mlx_utils **utils, struct pci_device *pci );
void free_mlx_utils ( mlx_utils **utils );
#endif /* SRC_DRIVERS_INFINIBAND_FLEXBOOT_NODNIC_FLEXBOOT_NODNIC_H_ */

View File

@ -21,31 +21,32 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <errno.h>
#include <strings.h>
#include <byteswap.h>
#include <ipxe/malloc.h>
#include <ipxe/umalloc.h>
#include <ipxe/infiniband.h>
#include <ipxe/ib_smc.h>
#include <ipxe/iobuf.h>
#include <ipxe/netdevice.h>
#include "flexboot_nodnic.h"
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <usr/ifmgmt.h>
#include <ipxe/in.h>
#include <byteswap.h>
#include "mlx_utils/include/public/mlx_pci_gw.h"
#include <config/general.h>
#include <ipxe/ipoib.h>
#include "flexboot_nodnic.h"
#include "mlx_nodnic/include/mlx_port.h"
#include "nodnic_shomron_prm.h"
#include "golan.h"
#include "mlx_utils/include/public/mlx_bail.h"
#include "mlx_utils/mlx_lib/mlx_link_speed/mlx_link_speed.h"
#include "mlx_utils/mlx_lib/mlx_nvconfig/mlx_nvconfig.h"
#include "mlx_utils/include/public/mlx_pci_gw.h"
#include "mlx_nodnic/include/mlx_port.h"
#define DEVICE_IS_CIB( device ) ( device == 0x1011 )
/******************************************************************************/
/************* Very simple memory management for umalloced pages **************/
/******* Temporary solution until full memory management is implemented *******/
/******************************************************************************/
#define GOLAN_PAGES 20
struct golan_page {
struct list_head list;
userptr_t addr;
@ -61,8 +62,7 @@ static void golan_free_pages ( struct list_head *head ) {
}
static int golan_init_pages ( struct list_head *head ) {
struct golan_page *new_entry;
int rc, i;
int rc = 0;
if ( !head ) {
rc = -EINVAL;
@ -70,26 +70,8 @@ static int golan_init_pages ( struct list_head *head ) {
}
INIT_LIST_HEAD ( head );
return rc;
for ( i = 0; i < GOLAN_PAGES; i++ ) {
new_entry = zalloc ( sizeof ( *new_entry ) );
if ( new_entry == NULL ) {
rc = -ENOMEM;
goto err_golan_init_pages_alloc_page;
}
new_entry->addr = umalloc ( GOLAN_PAGE_SIZE );
if ( new_entry->addr == UNULL ) {
free ( new_entry );
rc = -ENOMEM;
goto err_golan_init_pages_alloc_page;
}
list_add ( &new_entry->list, head );
}
return 0;
err_golan_init_pages_alloc_page:
golan_free_pages ( head );
err_golan_init_pages_bad_param:
return rc;
}
@ -98,16 +80,42 @@ static userptr_t golan_get_page ( struct list_head *head ) {
struct golan_page *page;
userptr_t addr;
if ( list_empty ( head ) )
return UNULL;
page = list_first_entry ( head, struct golan_page, list );
list_del ( &page->list );
addr = page->addr;
free ( page );
if ( list_empty ( head ) ) {
addr = umalloc ( GOLAN_PAGE_SIZE );
if ( addr == UNULL ) {
goto err_golan_iget_page_alloc_page;
}
} else {
page = list_first_entry ( head, struct golan_page, list );
list_del ( &page->list );
addr = page->addr;
free ( page );
}
err_golan_iget_page_alloc_page:
return addr;
}
static int golan_return_page ( struct list_head *head,
userptr_t addr ) {
struct golan_page *new_entry;
int rc = 0;
if ( ! head ) {
rc = -EINVAL;
goto err_golan_return_page_bad_param;
}
new_entry = zalloc ( sizeof ( *new_entry ) );
if ( new_entry == NULL ) {
rc = -ENOMEM;
goto err_golan_return_page_alloc_page;
}
new_entry->addr = addr;
list_add_tail( &new_entry->list, head );
err_golan_return_page_alloc_page:
err_golan_return_page_bad_param:
return rc;
}
/******************************************************************************/
const char *golan_qp_state_as_string[] = {
@ -450,8 +458,8 @@ err_query_hca_cap:
static inline int golan_take_pages ( struct golan *golan, uint32_t pages, __be16 func_id ) {
uint32_t out_num_entries = 0;
int size_ibox = sizeof(struct golan_manage_pages_inbox);
int size_obox = sizeof(struct golan_manage_pages_outbox);
int size_ibox = 0;
int size_obox = 0;
int rc = 0;
DBGC(golan, "%s\n", __FUNCTION__);
@ -463,8 +471,8 @@ static inline int golan_take_pages ( struct golan *golan, uint32_t pages, __be16
struct golan_manage_pages_inbox *in;
struct golan_manage_pages_outbox_data *out;
size_ibox += (pas_num * GOLAN_PAS_SIZE);
size_obox += (pas_num * GOLAN_PAS_SIZE);
size_ibox = sizeof(struct golan_manage_pages_inbox) + (pas_num * GOLAN_PAS_SIZE);
size_obox = sizeof(struct golan_manage_pages_outbox) + (pas_num * GOLAN_PAS_SIZE);
cmd = write_cmd(golan, MEM_CMD_IDX, GOLAN_CMD_OP_MANAGE_PAGES, GOLAN_PAGES_TAKE,
MEM_MBOX, MEM_MBOX,
@ -480,7 +488,7 @@ static inline int golan_take_pages ( struct golan *golan, uint32_t pages, __be16
out = (struct golan_manage_pages_outbox_data *)GET_OUTBOX(golan, MEM_MBOX);
out_num_entries = be32_to_cpu(((struct golan_manage_pages_outbox *)(cmd->out))->num_entries);
for (i = 0; i < out_num_entries; ++i) {
ufree(BE64_BUS_2_USR(out->pas[i]));
golan_return_page ( &golan->pages, ( BE64_BUS_2_USR( out->pas[i] ) ) );
}
} else {
if ( rc == -EBUSY ) {
@ -503,8 +511,8 @@ static inline int golan_take_pages ( struct golan *golan, uint32_t pages, __be16
static inline int golan_provide_pages ( struct golan *golan , uint32_t pages, __be16 func_id ) {
struct mbox *mailbox;
int size_ibox = sizeof(struct golan_manage_pages_inbox);
int size_obox = sizeof(struct golan_manage_pages_outbox);
int size_ibox = 0;
int size_obox = 0;
int rc = 0;
DBGC(golan, "%s\n", __FUNCTION__);
@ -517,8 +525,8 @@ static inline int golan_provide_pages ( struct golan *golan , uint32_t pages, __
userptr_t addr = 0;
mailbox = GET_INBOX(golan, MEM_MBOX);
size_ibox += (pas_num * GOLAN_PAS_SIZE);
size_obox += (pas_num * GOLAN_PAS_SIZE);
size_ibox = sizeof(struct golan_manage_pages_inbox) + (pas_num * GOLAN_PAS_SIZE);
size_obox = sizeof(struct golan_manage_pages_outbox) + (pas_num * GOLAN_PAS_SIZE);
cmd = write_cmd(golan, MEM_CMD_IDX, GOLAN_CMD_OP_MANAGE_PAGES, GOLAN_PAGES_GIVE,
MEM_MBOX, MEM_MBOX,
@ -531,7 +539,7 @@ static inline int golan_provide_pages ( struct golan *golan , uint32_t pages, __
in->num_entries = cpu_to_be32(pas_num);
for ( i = 0 , j = MANAGE_PAGES_PSA_OFFSET; i < pas_num; ++i ,++j ) {
if (!(addr = umalloc(GOLAN_PAGE_SIZE))) {
if ( ! ( addr = golan_get_page ( & golan->pages ) ) ) {
rc = -ENOMEM;
DBGC (golan ,"Couldnt allocated page \n");
goto malloc_dma_failed;
@ -555,7 +563,7 @@ static inline int golan_provide_pages ( struct golan *golan , uint32_t pages, __
get_cmd( golan , MEM_CMD_IDX )->status_own,
be32_to_cpu(CMD_SYND(golan, MEM_CMD_IDX)), pas_num);
}
ufree ( addr );
golan_return_page ( &golan->pages ,addr );
goto err_send_command;
}
}
@ -834,7 +842,7 @@ static int golan_create_eq(struct golan *golan)
return 0;
err_create_eq_cmd:
ufree(virt_to_user(golan->eq.eqes));
golan_return_page ( & golan->pages, virt_to_user ( eq->eqes ) );
err_create_eq_eqe_alloc:
DBGC (golan ,"%s [%d] out\n", __FUNCTION__, rc);
return rc;
@ -859,7 +867,7 @@ static void golan_destory_eq(struct golan *golan)
rc = send_command_and_wait(golan, DEF_CMD_IDX, NO_MBOX, NO_MBOX, __FUNCTION__);
GOLAN_PRINT_RC_AND_CMD_STATUS;
ufree(virt_to_user(golan->eq.eqes));
golan_return_page ( &golan->pages, virt_to_user ( golan->eq.eqes ) );
golan->eq.eqn = 0;
DBGC( golan, "%s Event queue (0x%x) was destroyed\n", __FUNCTION__, eqn);
@ -1063,7 +1071,7 @@ static int golan_create_cq(struct ib_device *ibdev,
return 0;
err_create_cq_cmd:
ufree(virt_to_user(golan_cq->cqes));
golan_return_page ( & golan->pages, virt_to_user ( golan_cq->cqes ) );
err_create_cq_cqe_alloc:
free_dma(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE);
err_create_cq_db_alloc:
@ -1100,7 +1108,7 @@ static void golan_destroy_cq(struct ib_device *ibdev,
cq->cqn = 0;
ib_cq_set_drvdata(cq, NULL);
ufree(virt_to_user(golan_cq->cqes));
golan_return_page ( & golan->pages, virt_to_user ( golan_cq->cqes ) );
free_dma(golan_cq->doorbell_record, GOLAN_CQ_DB_RECORD_SIZE);
free(golan_cq);
@ -1272,7 +1280,7 @@ static int golan_create_qp_aux(struct ib_device *ibdev,
err_create_qp_cmd:
free_dma(golan_qp->doorbell_record, sizeof(struct golan_qp_db));
err_create_qp_db_alloc:
ufree((userptr_t)golan_qp->wqes);
golan_return_page ( & golan->pages, ( userptr_t ) golan_qp->wqes );
err_create_qp_wqe_alloc:
err_create_qp_sq_size:
err_create_qp_sq_wqe_size:
@ -1326,7 +1334,7 @@ static int golan_modify_qp_rst_to_init(struct ib_device *ibdev,
in->ctx.pri_path.port = ibdev->port;
in->ctx.flags |= cpu_to_be32(GOLAN_QP_PM_MIGRATED << GOLAN_QP_CTX_PM_STATE_BIT);
in->ctx.pri_path.pkey_index = 0; /* default index */
in->ctx.pri_path.pkey_index = 0;
/* QK is 0 */
/* QP cntr set 0 */
return rc;
@ -1480,7 +1488,7 @@ static void golan_destroy_qp(struct ib_device *ibdev,
ib_qp_set_drvdata(qp, NULL);
free_dma(golan_qp->doorbell_record, sizeof(struct golan_qp_db));
ufree((userptr_t)golan_qp->wqes);
golan_return_page ( & golan->pages, ( userptr_t ) golan_qp->wqes );
free(golan_qp);
DBGC( golan ,"%s QP 0x%lx was destroyed\n", __FUNCTION__, qpn);
@ -1694,8 +1702,8 @@ err_query_vport_gid_cmd:
static int golan_query_vport_pkey ( struct ib_device *ibdev ) {
struct golan *golan = ib_get_drvdata ( ibdev );
struct golan_cmd_layout *cmd;
struct golan_query_hca_vport_pkey_inbox *in;
//struct golan_query_hca_vport_pkey_data *pkey_table;
struct golan_query_hca_vport_pkey_inbox *in;
int pkey_table_size_in_entries = (1 << (7 + golan->caps.pkey_table_size));
int rc;
@ -2244,26 +2252,24 @@ static inline void golan_bring_down(struct golan *golan)
}
static int golan_set_link_speed ( struct golan *golan ){
mlx_utils utils;
mlx_status status;
int i = 0;
int utils_inited = 0;
memset ( &utils, 0, sizeof ( utils ) );
status = mlx_utils_init ( &utils, golan->pci );
MLX_CHECK_STATUS ( golan->pci, status, utils_init_err, "mlx_utils_init failed" );
status = mlx_pci_gw_init ( &utils );
MLX_CHECK_STATUS ( golan->pci, status, pci_gw_init_err, "mlx_pci_gw_init failed" );
if ( ! golan->utils ) {
utils_inited = 1;
status = init_mlx_utils ( & golan->utils, golan->pci );
MLX_CHECK_STATUS ( golan->pci, status, utils_init_err, "mlx_utils_init failed" );
}
for ( i = 0; i < golan->caps.num_ports; ++i ) {
status = mlx_set_link_speed( &utils, i + 1, LINK_SPEED_IB, LINK_SPEED_SDR );
status = mlx_set_link_speed ( golan->utils, i + 1, LINK_SPEED_IB, LINK_SPEED_SDR );
MLX_CHECK_STATUS ( golan->pci, status, set_link_speed_err, "mlx_set_link_speed failed" );
}
set_link_speed_err:
mlx_pci_gw_teardown( &utils );
pci_gw_init_err:
if ( utils_inited )
free_mlx_utils ( & golan->utils );
utils_init_err:
return status;
}
@ -2344,7 +2350,16 @@ out:
*
* @v ibdev Infiniband device
*/
static void golan_ib_close ( struct ib_device *ibdev __unused ) {}
static void golan_ib_close ( struct ib_device *ibdev ) {
struct golan *golan = NULL;
DBG ( "%s start\n", __FUNCTION__ );
if ( ! ibdev )
return;
golan = ib_get_drvdata ( ibdev );
golan_bring_down ( golan );
DBG ( "%s end\n", __FUNCTION__ );
}
/**
* Initialise Infiniband link
@ -2353,11 +2368,13 @@ static void golan_ib_close ( struct ib_device *ibdev __unused ) {}
* @ret rc Return status code
*/
static int golan_ib_open ( struct ib_device *ibdev ) {
struct golan *golan = NULL;
DBG ( "%s start\n", __FUNCTION__ );
if ( ! ibdev )
return -EINVAL;
golan = ib_get_drvdata ( ibdev );
golan_bring_up ( golan );
golan_ib_update ( ibdev );
DBG ( "%s end\n", __FUNCTION__ );
@ -2417,6 +2434,12 @@ static int golan_probe_normal ( struct pci_device *pci ) {
goto err_golan_bringup;
}
if ( ! DEVICE_IS_CIB ( pci->device ) ) {
if ( init_mlx_utils ( & golan->utils, pci ) ) {
rc = -1;
goto err_utils_init;
}
}
/* Allocate Infiniband devices */
for (i = 0; i < golan->caps.num_ports; ++i) {
ibdev = alloc_ibdev( 0 );
@ -2435,10 +2458,13 @@ static int golan_probe_normal ( struct pci_device *pci ) {
/* Register devices */
for ( i = 0; i < golan->caps.num_ports; ++i ) {
port = &golan->ports[i];
if ((rc = golan_register_ibdev ( port ) ) != 0 )
if ((rc = golan_register_ibdev ( port ) ) != 0 ) {
goto err_golan_probe_register_ibdev;
}
}
golan_bring_down ( golan );
return 0;
i = golan->caps.num_ports;
@ -2450,7 +2476,10 @@ err_golan_probe_register_ibdev:
err_golan_probe_alloc_ibdev:
for ( i-- ; ( signed int ) i >= 0 ; i-- )
ibdev_put ( golan->ports[i].ibdev );
if ( ! DEVICE_IS_CIB ( pci->device ) ) {
free_mlx_utils ( & golan->utils );
}
err_utils_init:
golan_bring_down ( golan );
err_golan_bringup:
err_fw_ver_cmdif:
@ -2476,13 +2505,13 @@ static void golan_remove_normal ( struct pci_device *pci ) {
}
for ( i = ( golan->caps.num_ports - 1 ) ; i >= 0 ; i-- ) {
netdev_nullify ( golan->ports[i].netdev );
netdev_put ( golan->ports[i].netdev );
}
for ( i = ( golan->caps.num_ports - 1 ) ; i >= 0 ; i-- ) {
ibdev_put ( golan->ports[i].ibdev );
}
golan_bring_down(golan);
if ( ! DEVICE_IS_CIB ( pci->device ) ) {
free_mlx_utils ( & golan->utils );
}
iounmap( golan->iseg );
golan_free_pages( &golan->pages );
free(golan);
@ -2491,6 +2520,26 @@ static void golan_remove_normal ( struct pci_device *pci ) {
/***************************************************************************
* NODNIC operations
**************************************************************************/
static mlx_status shomron_tx_uar_send_db ( struct ib_device *ibdev,
struct nodnic_send_wqbb *wqbb ) {
mlx_status status = MLX_SUCCESS;
struct flexboot_nodnic *flexboot_nodnic = ib_get_drvdata ( ibdev );
struct shomron_nodnic_eth_send_wqe *eth_wqe =
( struct shomron_nodnic_eth_send_wqe * )wqbb;
struct shomronprm_wqe_segment_ctrl_send *ctrl;
if ( ! ibdev || ! eth_wqe || ! flexboot_nodnic->device_priv.uar.virt ) {
DBG("%s: Invalid parameters\n",__FUNCTION__);
status = MLX_FAILED;
goto err;
}
wmb();
ctrl = & eth_wqe->ctrl;
writeq(*((__be64 *)ctrl), flexboot_nodnic->device_priv.uar.virt + 0x800);
err:
return status;
}
static mlx_status shomron_fill_eth_send_wqe ( struct ib_device *ibdev,
struct ib_queue_pair *qp, struct ib_address_vector *av __unused,
struct io_buffer *iobuf, struct nodnic_send_wqbb *wqbb,
@ -2599,12 +2648,13 @@ struct flexboot_nodnic_callbacks shomron_nodnic_callbacks = {
.fill_completion = shomron_fill_completion,
.cqe_set_owner = shomron_cqe_set_owner,
.irq = flexboot_nodnic_eth_irq,
.tx_uar_send_doorbell_fn = shomron_tx_uar_send_db,
};
static int shomron_nodnic_supported = 0;
static int shomron_nodnic_is_supported ( struct pci_device *pci ) {
if ( pci->device == 0x1011 )
if ( DEVICE_IS_CIB ( pci->device ) )
return 0;
return flexboot_nodnic_is_supported ( pci );
@ -2624,15 +2674,9 @@ static int golan_probe ( struct pci_device *pci ) {
shomron_nodnic_supported = shomron_nodnic_is_supported ( pci );
if ( shomron_nodnic_supported ) {
DBG ( "%s: Using NODNIC driver\n", __FUNCTION__ );
rc = flexboot_nodnic_probe ( pci, &shomron_nodnic_callbacks, NULL );
if ( rc == 0 ) {
DBG ( "%s: Using NODNIC driver\n", __FUNCTION__ );
goto probe_done;
}
shomron_nodnic_supported = 0;
}
if ( ! shomron_nodnic_supported ) {
} else {
DBG ( "%s: Using normal driver\n", __FUNCTION__ );
rc = golan_probe_normal ( pci );
}
@ -2662,6 +2706,8 @@ static struct pci_device_id golan_nics[] = {
PCI_ROM ( 0x15b3, 0x1011, "ConnectIB", "ConnectIB HCA driver: DevID 4113", 0 ),
PCI_ROM ( 0x15b3, 0x1013, "ConnectX-4", "ConnectX-4 HCA driver, DevID 4115", 0 ),
PCI_ROM ( 0x15b3, 0x1015, "ConnectX-4Lx", "ConnectX-4Lx HCA driver, DevID 4117", 0 ),
PCI_ROM ( 0x15b3, 0x1017, "ConnectX-5", "ConnectX-5 HCA driver, DevID 4119", 0 ),
PCI_ROM ( 0x15b3, 0x1019, "ConnectX-5EX", "ConnectX-5EX HCA driver, DevID 4121", 0 ),
};
struct pci_driver golan_driver __pci_driver = {

View File

@ -22,14 +22,15 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <byteswap.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <ipxe/io.h>
#include <ipxe/pci.h>
#include <ipxe/pcibackup.h>
#include <byteswap.h>
#include <errno.h>
#include <ipxe/io.h>
#include <stdio.h>
#include <unistd.h>
#include "CIB_PRM.h"
#include "mlx_utils/include/public/mlx_utils.h"
#define GOLAN_PCI_CONFIG_BAR_SIZE 0x100000//HERMON_PCI_CONFIG_BAR_SIZE //TODO: What is the BAR size?
@ -319,6 +320,7 @@ struct golan {
uint32_t pdn;
u32 mkey;
u32 flags;
mlx_utils *utils;
struct golan_port ports[GOLAN_MAX_PORTS];
};

View File

@ -36,6 +36,8 @@ typedef struct _nodnic_device_capabilites nodnic_device_capabilites;
typedef struct _nodnic_qp nodnic_qp;
typedef struct _nodnic_cq nodnic_cq;
typedef struct _nodnic_eq nodnic_eq;
typedef struct _nodnic_qp_db nodnic_qp_db;
typedef struct _nodnic_arm_cq_db nodnic_arm_cq_db;
/* NODNIC Port states
* Bit 0 - port open/close
@ -73,6 +75,12 @@ typedef enum {
struct nodnic_send_wqbb {
mlx_uint8 force_align[NODNIC_WQBB_SIZE];
};
struct nodnic_doorbell {
mlx_physical_address doorbell_physical;
mlx_void *map;
nodnic_qp_db *qp_doorbell_record;
};
struct nodnic_ring {
mlx_uint32 offset;
/** Work queue entries */
@ -91,7 +99,8 @@ struct nodnic_ring {
mlx_uint32 num_wqes;
mlx_uint32 qpn;
mlx_uint32 next_idx;
mlx_uint32 ring_pi;
struct nodnic_doorbell recv_doorbell;
struct nodnic_doorbell send_doorbell;
};
struct nodnic_send_ring{
@ -117,6 +126,7 @@ struct _nodnic_cq{
mlx_void *map;
/** cq */
mlx_size cq_size;
struct nodnic_doorbell arm_cq_doorbell;
};
struct _nodnic_eq{
@ -136,6 +146,10 @@ struct _nodnic_device_capabilites{
#ifdef DEVICE_CX3
mlx_uint8 crspace_doorbells;
#endif
mlx_uint8 support_rx_pi_dma;
mlx_uint8 support_uar_tx_db;
mlx_uint8 support_bar_cq_ctrl;
mlx_uint8 log_uar_page_size;
};
#ifdef DEVICE_CX3
@ -151,6 +165,13 @@ struct _nodnic_port_data_flow_gw {
} __attribute__ ((packed));
#endif
typedef struct _nodnic_uar_priv{
mlx_uint8 inited;
mlx_uint64 offset;
void *virt;
unsigned long phys;
} nodnic_uar;
struct _nodnic_device_priv{
mlx_boolean is_initiailzied;
mlx_utils *utils;
@ -169,6 +190,7 @@ struct _nodnic_device_priv{
#ifdef DEVICE_CX3
mlx_void *crspace_clear_int;
#endif
nodnic_uar uar;
};
struct _nodnic_port_priv{
@ -181,6 +203,7 @@ struct _nodnic_port_priv{
mlx_uint8 port_num;
nodnic_eq eq;
mlx_mac_address mac_filters[5];
nodnic_arm_cq_db *arm_cq_doorbell_record;
mlx_status (*send_doorbell)(
IN nodnic_port_priv *port_priv,
IN struct nodnic_ring *ring,
@ -197,5 +220,12 @@ struct _nodnic_port_priv{
#endif
};
struct _nodnic_qp_db {
mlx_uint32 recv_db;
mlx_uint32 send_db;
} __attribute ( ( packed ) );
struct _nodnic_arm_cq_db {
mlx_uint32 dword[2];
} __attribute ( ( packed ) );
#endif /* STUB_NODNIC_NODNICDATASTRUCTURES_H_ */

View File

@ -47,6 +47,9 @@ typedef enum {
#ifdef DEVICE_CX3
nodnic_port_option_crspace_en,
#endif
nodnic_port_option_send_ring0_uar_index,
nodnic_port_option_send_ring1_uar_index,
nodnic_port_option_cq_n_index,
}nodnic_port_option;
struct nodnic_port_data_entry{
@ -226,4 +229,14 @@ nodnic_port_read_port_management_change_event(
IN nodnic_port_priv *port_priv,
OUT mlx_boolean *change_event
);
mlx_status
nodnic_port_set_send_uar_offset(
IN nodnic_port_priv *port_priv
);
mlx_status
nodnic_port_update_tx_db_func(
IN nodnic_device_priv *device_priv,
IN nodnic_port_priv *port_priv
);
#endif /* STUB_NODNIC_PORT_H_ */

View File

@ -169,11 +169,17 @@ nodnic_device_clear_int (
mlx_status status = MLX_SUCCESS;
mlx_uint32 disable = 1;
#ifndef DEVICE_CX3
status = nodnic_cmd_write(device_priv, NODNIC_NIC_DISABLE_INT_OFFSET, disable);
#define NODNIC_CLEAR_INT_BAR_OFFSET 0x100C
if ( device_priv->device_cap.support_bar_cq_ctrl ) {
status = mlx_pci_mem_write ( device_priv->utils, MlxPciWidthUint32, 0,
( mlx_uint64 ) ( NODNIC_CLEAR_INT_BAR_OFFSET ), 1, &disable );
} else {
status = nodnic_cmd_write(device_priv, NODNIC_NIC_DISABLE_INT_OFFSET, disable);
}
MLX_CHECK_STATUS(device_priv, status, clear_int_done, "failed writing to disable_bit");
#else
mlx_utils *utils = device_priv->utils;
mlx_uint64 clear_int = (mlx_uint64)(device_priv->crspace_clear_int);
mlx_uint64 clear_int = (mlx_uintn)(device_priv->crspace_clear_int);
mlx_uint32 swapped = 0;
if (device_priv->device_cap.crspace_doorbells == 0) {
@ -303,6 +309,30 @@ nodnic_device_get_cap(
status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x14, (mlx_uint32*)&guid_l);
MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic guid_l");
device_priv->device_guid = guid_l | (guid_h << 32);
#define NODNIC_DEVICE_SUPPORT_RX_PI_DMA_OFFSET 31
#define NODNIC_DEVICE_SUPPORT_RX_PI_DMA_MASK 0x1
#define NODNIC_DEVICE_SUPPORT_UAR_TRX_DB_OFFSET 29
#define NODNIC_DEVICE_SUPPORT_UAR_TRX_DB_MASK 0x1
#define NODNIC_DEVICE_SUPPORT_BAR_CQ_CONTROL_OFFSET 27
#define NODNIC_DEVICE_SUPPORT_BAR_CQ_CONTROL_MASK 0x1
status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x1c, &buffer);
MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic support_rx_pi_dma");
if ( sizeof ( mlx_uintn ) == sizeof ( mlx_uint32 ) ) {
device_cap->support_rx_pi_dma = FALSE;
device_cap->support_uar_tx_db = FALSE;
device_cap->support_bar_cq_ctrl = FALSE;
} else {
device_cap->support_rx_pi_dma = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_RX_PI_DMA_OFFSET);
device_cap->support_uar_tx_db = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_UAR_TRX_DB_OFFSET);
device_cap->support_bar_cq_ctrl = CHECK_BIT(buffer, NODNIC_DEVICE_SUPPORT_BAR_CQ_CONTROL_OFFSET);
}
#define NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_OFFSET 0
#define NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_MASK 0xFF
status = nodnic_cmd_read(device_priv, device_priv->device_offset + 0x20, &buffer);
MLX_FATAL_CHECK_STATUS(status, read_err, "failed to read nodnic log_uar_page_size");
device_cap->log_uar_page_size = ( buffer >> NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_OFFSET) & NODNIC_DEVICE_LOG_UAR_PAGE_SIZE_MASK;
read_err:
parm_err:
return status;

View File

@ -55,11 +55,18 @@ struct nodnic_port_data_entry nodnic_port_data_table[] = {
PortDataEntry(nodnic_port_option_cq_addr_high, 0x68, 0, 0xFFFFFFFF),
PortDataEntry(nodnic_port_option_port_management_change_event, 0x0, 30, 0x1),
PortDataEntry(nodnic_port_option_port_promisc_en, 0x4, 29, 0x1),
#ifndef DEVICE_CX3
PortDataEntry(nodnic_port_option_arm_cq, 0x78, 8, 0xffffff),
#else
PortDataEntry(nodnic_port_option_arm_cq, 0x78, 8, 0xffff),
#endif
PortDataEntry(nodnic_port_option_port_promisc_multicast_en, 0x4, 28, 0x1),
#ifdef DEVICE_CX3
PortDataEntry(nodnic_port_option_crspace_en, 0x4, 27, 0x1),
#endif
PortDataEntry(nodnic_port_option_send_ring0_uar_index, 0x108, 0, 0xFFFFFFFF),
PortDataEntry(nodnic_port_option_send_ring1_uar_index, 0x10c, 0, 0xFFFFFFFF),
PortDataEntry(nodnic_port_option_cq_n_index, 0x118, 0, 0xFFFFFF),
};
#define MAX_QP_DATA_ENTRIES 5
@ -186,6 +193,30 @@ invalid_parm:
return status;
}
mlx_status
nodnic_port_set_send_uar_offset(
IN nodnic_port_priv *port_priv
)
{
mlx_status status = MLX_SUCCESS;
mlx_uint32 out = 0;
if ( ! port_priv->device->device_cap.support_uar_tx_db ) {
MLX_DEBUG_INFO1 ( port_priv, "nodnic_port_set_send_uar_offset: tx db using uar is not supported \n");
status = MLX_UNSUPPORTED;
goto uar_not_supported;
}
status = nodnic_port_query(port_priv,
nodnic_port_option_send_ring0_uar_index, &out);
MLX_CHECK_STATUS(port_priv->device, status, query_err,
"nodnic_port_query failed");
port_priv->device->uar.offset = out << port_priv->device->device_cap.log_uar_page_size;
uar_not_supported:
query_err:
return status;
}
mlx_status
nodnic_port_read_reset_needed(
IN nodnic_port_priv *port_priv,
@ -220,6 +251,111 @@ query_err:
return status;
}
static
mlx_status
nodnic_port_allocate_dbr_dma (
IN nodnic_port_priv *port_priv,
IN struct nodnic_doorbell *nodnic_db,
IN mlx_uint32 dbr_addr_low_ofst,
IN mlx_uint32 dbr_addr_high_ofst,
IN void **dbr_addr,
IN mlx_size size,
IN void **map
)
{
mlx_status status = MLX_SUCCESS;
mlx_uint64 address = 0;
nodnic_device_priv *device_priv = NULL;
if( port_priv == NULL || nodnic_db == NULL ){
status = MLX_INVALID_PARAMETER;
goto invalid_parm;
}
device_priv = port_priv->device;
status = mlx_memory_alloc_dma(device_priv->utils,
size,
NODNIC_MEMORY_ALIGN,
(void **)dbr_addr
);
MLX_FATAL_CHECK_STATUS(status, alloc_db_record_err,
"doorbell record dma allocation error");
status = mlx_memory_map_dma(device_priv->utils,
(void *)(*dbr_addr),
size,
&nodnic_db->doorbell_physical,
map//nodnic_ring->map
);
MLX_FATAL_CHECK_STATUS(status, map_db_record_err,
"doorbell record map dma error");
address = (mlx_uint64)nodnic_db->doorbell_physical;
status = nodnic_cmd_write(device_priv,
dbr_addr_low_ofst,
(mlx_uint32)address);
MLX_FATAL_CHECK_STATUS(status, set_err,
"failed to set doorbell addr low");
address = address >> 32;
status = nodnic_cmd_write(device_priv,
dbr_addr_high_ofst,
(mlx_uint32)address);
MLX_FATAL_CHECK_STATUS(status, set_err,
"failed to set doorbell addr high");
return status;
set_err:
mlx_memory_ummap_dma(device_priv->utils, *map);
map_db_record_err:
mlx_memory_free_dma(device_priv->utils, size,
(void **)dbr_addr);
alloc_db_record_err:
invalid_parm:
return status;
}
static
mlx_status
nodnic_port_cq_dbr_dma_init(
IN nodnic_port_priv *port_priv,
OUT nodnic_cq **cq
)
{
mlx_status status = MLX_SUCCESS;
nodnic_device_priv *device_priv = NULL;
if( port_priv == NULL ){
status = MLX_INVALID_PARAMETER;
goto invalid_parm;
}
device_priv = port_priv->device;
if ( ! device_priv->device_cap.support_bar_cq_ctrl ) {
status = MLX_UNSUPPORTED;
goto uar_arm_cq_db_unsupported;
}
#define NODNIC_PORT_ARM_CQ_DBR_ADDR_LOW_OFFSET 0x114
#define NODNIC_PORT_ARM_CQ_DBR_ADDR_HIGH_OFFSET 0x110
status = nodnic_port_allocate_dbr_dma ( port_priv,&(*cq)->arm_cq_doorbell,
port_priv->port_offset + NODNIC_PORT_ARM_CQ_DBR_ADDR_LOW_OFFSET,
port_priv->port_offset + NODNIC_PORT_ARM_CQ_DBR_ADDR_HIGH_OFFSET,
(void **)&port_priv->arm_cq_doorbell_record ,
sizeof(nodnic_arm_cq_db),
(void **)&((*cq)->arm_cq_doorbell.map));
MLX_FATAL_CHECK_STATUS(status, alloc_dbr_dma_err,
"failed to allocate doorbell record dma");
return status;
alloc_dbr_dma_err:
uar_arm_cq_db_unsupported:
invalid_parm:
return status;
}
mlx_status
nodnic_port_create_cq(
IN nodnic_port_priv *port_priv,
@ -257,17 +393,24 @@ nodnic_port_create_cq(
MLX_FATAL_CHECK_STATUS(status, cq_map_err,
"cq map error");
status = nodnic_port_cq_dbr_dma_init(port_priv,cq);
/* update cq address */
#define NODIC_CQ_ADDR_HIGH 0x68
#define NODIC_CQ_ADDR_LOW 0x6c
address = (mlx_uint64)(*cq)->cq_physical;
nodnic_port_set(port_priv, nodnic_port_option_cq_addr_low,
(mlx_uint32)(address >> 12));
status = nodnic_port_set(port_priv, nodnic_port_option_cq_addr_low,
(mlx_uint32)(address) >> 12);
MLX_FATAL_CHECK_STATUS(status, dma_set_addr_low_err,
"cq set addr low error");
address = address >> 32;
nodnic_port_set(port_priv, nodnic_port_option_cq_addr_high,
status = nodnic_port_set(port_priv, nodnic_port_option_cq_addr_high,
(mlx_uint32)address);
MLX_FATAL_CHECK_STATUS(status, dma_set_addr_high_err,
"cq set addr high error");
return status;
dma_set_addr_high_err:
dma_set_addr_low_err:
mlx_memory_ummap_dma(device_priv->utils, (*cq)->map);
cq_map_err:
mlx_memory_free_dma(device_priv->utils, (*cq)->cq_size,
@ -294,6 +437,21 @@ nodnic_port_destroy_cq(
}
device_priv = port_priv->device;
if ( device_priv->device_cap.support_bar_cq_ctrl ){
status = mlx_memory_ummap_dma(device_priv->utils,
cq->arm_cq_doorbell.map);
if( status != MLX_SUCCESS){
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
}
status = mlx_memory_free_dma(device_priv->utils,
sizeof(nodnic_arm_cq_db),
(void **)&(port_priv->arm_cq_doorbell_record));
if( status != MLX_SUCCESS){
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
}
}
mlx_memory_ummap_dma(device_priv->utils, cq->map);
mlx_memory_free_dma(device_priv->utils, cq->cq_size,
@ -303,6 +461,126 @@ nodnic_port_destroy_cq(
invalid_parm:
return status;
}
static
mlx_status
nodnic_port_allocate_ring_db_dma (
IN nodnic_port_priv *port_priv,
IN struct nodnic_ring *nodnic_ring,
IN struct nodnic_doorbell *nodnic_db
)
{
mlx_status status = MLX_SUCCESS;
if( port_priv == NULL || nodnic_ring == NULL || nodnic_db == NULL ){
status = MLX_INVALID_PARAMETER;
goto invalid_parm;
}
#define NODNIC_RING_DBR_ADDR_LOW_OFFSET 0x1C
#define NODNIC_RING_DBR_ADDR_HIGH_OFFSET 0x18
status = nodnic_port_allocate_dbr_dma ( port_priv,nodnic_db,
nodnic_ring->offset + NODNIC_RING_DBR_ADDR_LOW_OFFSET,
nodnic_ring->offset + NODNIC_RING_DBR_ADDR_HIGH_OFFSET,
(void **)&nodnic_db->qp_doorbell_record,
sizeof(nodnic_qp_db),
(void **)&nodnic_ring->map );
MLX_FATAL_CHECK_STATUS(status, alloc_dbr_dma_err,
"failed to allocate doorbell record dma");
return status;
alloc_dbr_dma_err:
invalid_parm:
return status;
}
static
mlx_status
nodnic_port_rx_pi_dma_alloc(
IN nodnic_port_priv *port_priv,
OUT nodnic_qp **qp
)
{
mlx_status status = MLX_SUCCESS;
nodnic_device_priv *device_priv = NULL;
if( port_priv == NULL || qp == NULL){
status = MLX_INVALID_PARAMETER;
goto invalid_parm;
}
device_priv = port_priv->device;
if ( ! device_priv->device_cap.support_rx_pi_dma ) {
goto rx_pi_dma_unsupported;
}
if ( device_priv->device_cap.support_rx_pi_dma ) {
status = nodnic_port_allocate_ring_db_dma(port_priv,
&(*qp)->receive.nodnic_ring,&(*qp)->receive.nodnic_ring.recv_doorbell);
MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
"rx doorbell dma allocation error");
}
return status;
dma_alloc_err:
rx_pi_dma_unsupported:
invalid_parm:
return status;
}
static
mlx_status
nodnic_port_send_db_dma(
IN nodnic_port_priv *port_priv,
IN struct nodnic_ring *ring,
IN mlx_uint16 index
)
{
mlx_uint32 swapped = 0;
mlx_uint32 index32 = index;
mlx_memory_cpu_to_be32(port_priv->device->utils, index32, &swapped);
ring->send_doorbell.qp_doorbell_record->send_db = swapped;
return MLX_SUCCESS;
}
static
mlx_status
nodnic_port_tx_dbr_dma_init(
IN nodnic_port_priv *port_priv,
OUT nodnic_qp **qp
)
{
mlx_status status = MLX_SUCCESS;
nodnic_device_priv *device_priv = NULL;
if( port_priv == NULL || qp == NULL){
status = MLX_INVALID_PARAMETER;
goto invalid_parm;
}
device_priv = port_priv->device;
if ( ! device_priv->device_cap.support_uar_tx_db || ! device_priv->uar.offset ) {
status = MLX_UNSUPPORTED;
goto uar_tx_db_unsupported;
}
status = nodnic_port_allocate_ring_db_dma(port_priv,
&(*qp)->send.nodnic_ring,&(*qp)->send.nodnic_ring.send_doorbell);
MLX_FATAL_CHECK_STATUS(status, dma_alloc_err,
"tx doorbell dma allocation error");
port_priv->send_doorbell = nodnic_port_send_db_dma;
return status;
dma_alloc_err:
uar_tx_db_unsupported:
invalid_parm:
return status;
}
mlx_status
nodnic_port_create_qp(
IN nodnic_port_priv *port_priv,
@ -376,6 +654,13 @@ nodnic_port_create_qp(
MLX_FATAL_CHECK_STATUS(status, receive_map_err,
"receive wq map error");
status = nodnic_port_rx_pi_dma_alloc(port_priv,qp);
MLX_FATAL_CHECK_STATUS(status, rx_pi_dma_alloc_err,
"receive db dma error");
status = nodnic_port_tx_dbr_dma_init(port_priv,qp);
(*qp)->send.nodnic_ring.wq_size = send_wq_size;
(*qp)->send.nodnic_ring.num_wqes = send_wqe_num;
(*qp)->receive.nodnic_ring.wq_size = receive_wq_size;
@ -420,6 +705,7 @@ nodnic_port_create_qp(
write_recv_addr_err:
write_send_addr_err:
mlx_memory_ummap_dma(device_priv->utils, (*qp)->receive.nodnic_ring.map);
rx_pi_dma_alloc_err:
receive_map_err:
mlx_memory_ummap_dma(device_priv->utils, (*qp)->send.nodnic_ring.map);
send_map_err:
@ -457,6 +743,36 @@ nodnic_port_destroy_qp(
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
}
if ( device_priv->device_cap.support_rx_pi_dma ){
status = mlx_memory_ummap_dma(device_priv->utils,
qp->receive.nodnic_ring.recv_doorbell.map);
if( status != MLX_SUCCESS){
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
}
status = mlx_memory_free_dma(device_priv->utils,
sizeof(nodnic_qp_db),
(void **)&(qp->receive.nodnic_ring.recv_doorbell.qp_doorbell_record));
if( status != MLX_SUCCESS){
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
}
}
if ( device_priv->device_cap.support_uar_tx_db || ! device_priv->uar.offset){
status = mlx_memory_ummap_dma(device_priv->utils,
qp->send.nodnic_ring.send_doorbell.map);
if( status != MLX_SUCCESS){
MLX_DEBUG_ERROR(device_priv, "mlx_memory_ummap_dma failed (Status = %d)\n", status);
}
status = mlx_memory_free_dma(device_priv->utils,
sizeof(nodnic_qp_db),
(void **)&(qp->send.nodnic_ring.send_doorbell.qp_doorbell_record));
if( status != MLX_SUCCESS){
MLX_DEBUG_ERROR(device_priv, "mlx_memory_free_dma failed (Status = %d)\n", status);
}
}
status = mlx_memory_free_dma(device_priv->utils,
qp->receive.nodnic_ring.wq_size,
(void **)&(qp->receive.wqe_virt));
@ -520,7 +836,7 @@ nodnic_port_send_db_connectx3(
nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
mlx_uint32 index32 = index;
mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
(mlx_uint64)&(ptr->send_doorbell), 1, &index32);
(mlx_uintn)&(ptr->send_doorbell), 1, &index32);
return MLX_SUCCESS;
}
@ -535,10 +851,24 @@ nodnic_port_recv_db_connectx3(
nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
mlx_uint32 index32 = index;
mlx_pci_mem_write(port_priv->device->utils, MlxPciWidthUint32, 0,
(mlx_uint64)&(ptr->recv_doorbell), 1, &index32);
(mlx_uintn)&(ptr->recv_doorbell), 1, &index32);
return MLX_SUCCESS;
}
#endif
static
mlx_status
nodnic_port_recv_db_dma(
IN nodnic_port_priv *port_priv __attribute__((unused)),
IN struct nodnic_ring *ring,
IN mlx_uint16 index
)
{
mlx_uint32 swapped = 0;
mlx_uint32 index32 = index;
mlx_memory_cpu_to_be32(port_priv->device->utils, index32, &swapped);
ring->recv_doorbell.qp_doorbell_record->recv_db = swapped;
return MLX_SUCCESS;
}
mlx_status
nodnic_port_update_ring_doorbell(
@ -678,11 +1008,10 @@ nodnic_port_add_mac_filter(
goto bad_param;
}
memset(&zero_mac, 0, sizeof(zero_mac));
device = port_priv->device;
utils = device->utils;
mlx_memory_set(utils, &zero_mac, 0, sizeof(zero_mac));
/* check if mac already exists */
for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
@ -759,11 +1088,10 @@ nodnic_port_remove_mac_filter(
goto bad_param;
}
memset(&zero_mac, 0, sizeof(zero_mac));
device = port_priv->device;
utils = device->utils;
mlx_memory_set(utils, &zero_mac, 0, sizeof(zero_mac));
/* serch for mac filter */
for( ; index < NODNIC_MAX_MAC_FILTERS ; index ++) {
mlx_memory_cmp(utils, &port_priv->mac_filters[index], &mac,
@ -832,7 +1160,7 @@ nodnic_port_set_dma_connectx3(
nodnic_port_data_flow_gw *ptr = port_priv->data_flow_gw;
mlx_uint32 data = (value ? 0xffffffff : 0x0);
mlx_pci_mem_write(utils, MlxPciWidthUint32, 0,
(mlx_uint64)&(ptr->dma_en), 1, &data);
(mlx_uintn)&(ptr->dma_en), 1, &data);
return MLX_SUCCESS;
}
#endif
@ -1029,6 +1357,10 @@ nodnic_port_thin_init(
port_priv->set_dma = nodnic_port_set_dma_connectx3;
}
#endif
if ( device_priv->device_cap.support_rx_pi_dma ) {
port_priv->recv_doorbell = nodnic_port_recv_db_dma;
}
/* clear reset_needed */
nodnic_port_read_reset_needed(port_priv, &reset_needed);

View File

@ -30,6 +30,11 @@ mlx_pci_init_priv(
IN mlx_utils *utils
);
mlx_status
mlx_pci_teardown_priv(
IN mlx_utils *utils
);
mlx_status
mlx_pci_read_priv(
IN mlx_utils *utils,

View File

@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include "../../../mlx_utils_flexboot/include/mlx_logging_priv.h"
#define MLX_PRINT(...) MLX_PRINT_PRIVATE(__VA_ARGS__)
#define MLX_DEBUG_FATAL_ERROR(...) MLX_DEBUG_FATAL_ERROR_PRIVATE(__VA_ARGS__)
#define MLX_DEBUG_ERROR(...) MLX_DEBUG_ERROR_PRIVATE(__VA_ARGS__)
#define MLX_DEBUG_WARN(...) MLX_DEBUG_WARN_PRIVATE(__VA_ARGS__)

View File

@ -36,6 +36,11 @@ mlx_pci_init(
IN mlx_utils *utils
);
mlx_status
mlx_pci_teardown(
IN mlx_utils *utils
);
mlx_status
mlx_pci_read(
IN mlx_utils *utils,

View File

@ -124,6 +124,11 @@ struct mlx_link_speed {
/* -------------- */
mlx_uint32 ib_proto_oper :16;
mlx_uint32 ib_link_width_oper :16;
/* -------------- */
mlx_uint32 reserved7 :32;
/* -------------- */
mlx_uint32 eth_proto_lp_advertise :32;
mlx_uint32 reserved[3];
};
mlx_status

View File

@ -42,6 +42,7 @@ struct nvconfig_tlv_mapping nvconfig_tlv_mapping[] = {
TlvMappingEntry(0x2020, 0x2020, NVRAM_TLV_CLASS_PHYSICAL_PORT, FALSE),
TlvMappingEntry(0x2021, 0x221, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2023, 0x223, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2006, 0x206, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2100, 0x230, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2101, 0x231, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2102, 0x232, NVRAM_TLV_CLASS_HOST, FALSE),
@ -53,6 +54,7 @@ struct nvconfig_tlv_mapping nvconfig_tlv_mapping[] = {
TlvMappingEntry(0x2108, 0x238, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2109, 0x239, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x210A, 0x23A, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2022, 0x222, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2200, 0x240, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2201, 0x241, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2202, 0x242, NVRAM_TLV_CLASS_HOST, FALSE),
@ -60,6 +62,11 @@ struct nvconfig_tlv_mapping nvconfig_tlv_mapping[] = {
TlvMappingEntry(0x2204, 0x244, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2205, 0x245, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2207, 0x247, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2002, 0x202, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x2004, 0x204, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x110, 0x110, NVRAM_TLV_CLASS_HOST, FALSE),
TlvMappingEntry(0x192, 0x192, NVRAM_TLV_CLASS_GLOBAL, FALSE),
TlvMappingEntry(0x101, 0x101, NVRAM_TLV_CLASS_GLOBAL, TRUE),
TlvMappingEntry(0, 0, 0, 0),
};

View File

@ -107,6 +107,22 @@ struct nvconfig_nvda {
mlx_uint8 data[NVCONFIG_MAX_TLV_SIZE];
};
struct nv_conf_cap {
/** WOL En/Dis **/
mlx_uint8 wol_en;
/** VPI En/Dis **/
mlx_uint8 vpi_en;
};
struct mlx_nvconfig_virt_net_addr {
mlx_uint32 reserved1 :29;
mlx_uint32 erase_on_powerup:1;
mlx_uint32 reserverd2 :1;
mlx_uint32 virtual_mac_en :1;
mlx_uint32 virtual_mac_high;
mlx_uint32 virtual_mac_low;
};
mlx_status
nvconfig_query_capability(

View File

@ -86,13 +86,13 @@ nvconfig_get_boot_ext_default_conf(
"TLV not found. Using hard-coded defaults ");
port_conf_def->linkup_timeout = nic_boot_ext_conf->linkup_timeout;
port_conf_def->ip_ver = nic_boot_ext_conf->ip_ver;
port_conf_def->undi_network_wait_to = nic_boot_ext_conf->undi_network_wait_to;
return MLX_SUCCESS;
nvdata_access_err:
port_conf_def->linkup_timeout = DEFAULT_BOOT_LINK_UP_TO;
port_conf_def->ip_ver = DEFAULT_BOOT_IP_VER;
port_conf_def->undi_network_wait_to = DEFAULT_BOOT_UNDI_NETWORK_WAIT_TO;
return status;
}
@ -185,8 +185,12 @@ nvconfig_get_iscsi_gen_default_conf(
port_conf_def->iscsi_chap_auth_en = iscsi_gen->chap_auth_en;
port_conf_def->iscsi_lun_busy_retry_count = iscsi_gen->lun_busy_retry_count;
port_conf_def->iscsi_link_up_delay_time = iscsi_gen->link_up_delay_time;
port_conf_def->iscsi_drive_num = iscsi_gen->drive_num;
return MLX_SUCCESS;
nvdata_access_err:
port_conf_def->iscsi_drive_num = DEFAULT_ISCSI_DRIVE_NUM;
return status;
}
@ -327,6 +331,27 @@ nvdata_access_err:
return status;
}
static
mlx_status
nvconfig_get_rom_cap_default_conf( IN void *data,
IN int status, OUT void *def_struct) {
union mlx_nvconfig_rom_cap_conf *rom_cap_conf =
(union mlx_nvconfig_rom_cap_conf *) data;
struct mlx_nvconfig_conf_defaults *conf_def =
(struct mlx_nvconfig_conf_defaults *) def_struct;
MLX_CHECK_STATUS(NULL, status, nvdata_access_err,
"TLV not found. Using hard-coded defaults ");
conf_def->boot_ip_ver_en = rom_cap_conf->boot_ip_ver_en;
return MLX_SUCCESS;
nvdata_access_err:
rom_cap_conf->boot_ip_ver_en = DEFAULT_BOOT_IP_VERSION_EN;
return status;
}
static struct tlv_default tlv_port_defaults[] = {
TlvDefaultEntry(BOOT_SETTINGS_TYPE, union mlx_nvconfig_nic_boot_conf, &nvconfig_get_boot_default_conf),
TlvDefaultEntry(BOOT_SETTINGS_EXT_TYPE, union mlx_nvconfig_nic_boot_ext_conf, &nvconfig_get_boot_ext_default_conf),
@ -343,6 +368,7 @@ static struct tlv_default tlv_general_defaults[] = {
TlvDefaultEntry(GLOPAL_PCI_CAPS_TYPE, union mlx_nvconfig_virt_caps, &nvconfig_get_nv_virt_caps_default_conf),
TlvDefaultEntry(GLOPAL_PCI_SETTINGS_TYPE, union mlx_nvconfig_virt_conf, &nvconfig_get_nv_virt_default_conf),
TlvDefaultEntry(OCSD_OCBB_TYPE, union mlx_nvconfig_ocsd_ocbb_conf, &nvconfig_get_ocsd_ocbb_default_conf),
TlvDefaultEntry(NV_ROM_CAP_TYPE, union mlx_nvconfig_rom_cap_conf, &nvconfig_get_rom_cap_default_conf),
};
static

View File

@ -32,9 +32,12 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define DEFAULT_BOOT_VLAN 1
#define DEFAULT_ISCSI_DHCP_PARAM_EN 1
#define DEFAULT_ISCSI_IPV4_DHCP_EN 1
#define DEFAULT_ISCSI_DRIVE_NUM 0x80
#define DEFAULT_OCSD_OCBB_EN 1
#define DEFAULT_BOOT_IP_VER 0
#define DEFAULT_BOOT_LINK_UP_TO 0
#define DEFAULT_BOOT_UNDI_NETWORK_WAIT_TO 30
#define DEFAULT_BOOT_IP_VERSION_EN 1
struct mlx_nvconfig_port_conf_defaults {
mlx_uint8 pptx;
@ -56,11 +59,13 @@ struct mlx_nvconfig_port_conf_defaults {
mlx_boolean iscsi_ipv4_dhcp_en;
mlx_uint8 iscsi_lun_busy_retry_count;
mlx_uint8 iscsi_link_up_delay_time;
mlx_uint8 iscsi_drive_num;
mlx_uint8 client_identifier;
mlx_uint8 mac_admin_bit;
mlx_uint8 default_link_type;
mlx_uint8 linkup_timeout;
mlx_uint8 ip_ver;
mlx_uint8 undi_network_wait_to;
};
struct mlx_nvconfig_conf_defaults {
@ -71,6 +76,7 @@ struct mlx_nvconfig_conf_defaults {
mlx_uint8 uar_bar_size;
mlx_uint8 flexboot_menu_to;
mlx_boolean ocsd_ocbb_en;
mlx_boolean boot_ip_ver_en;
};
mlx_status

View File

@ -33,12 +33,15 @@ enum {
OCSD_OCBB_TYPE = 0x2011,
FLOW_CONTROL_TYPE = 0x2020,
BOOT_SETTINGS_TYPE = 0x2021,
NV_ROM_FLEXBOOT_DEBUG = 0x2004,
ISCSI_GENERAL_SETTINGS_TYPE = 0x2100,
IB_BOOT_SETTING_TYPE = 0x2022,
IB_DHCP_SETTINGS_TYPE = 0x2023,
GLOPAL_PCI_SETTINGS_TYPE = 0x80,
GLOPAL_PCI_CAPS_TYPE = 0x81,
GLOBAL_ROM_INI_TYPE = 0x100,
NV_VIRT_NET_ADDR = 0x110,
// Types for iSCSI strings
DHCP_VEND_ID = 0x2101,
@ -59,6 +62,8 @@ enum {
FIRST_TGT_ISCSI_NAME = 0x2204,
FIRST_TGT_CHAP_ID = 0x2205,
FIRST_TGT_CHAP_PWD = 0x2207,
NV_ROM_DEBUG_LEVEL = 0x2002,
NV_ROM_CAP_TYPE = 0x101,
};
union mlx_nvconfig_nic_boot_conf {
@ -78,7 +83,9 @@ union mlx_nvconfig_nic_boot_ext_conf {
struct {
mlx_uint32 linkup_timeout : 8;
mlx_uint32 ip_ver : 2;
mlx_uint32 reserved0 : 22;
mlx_uint32 reserved0 : 6;
mlx_uint32 undi_network_wait_to : 8;
mlx_uint32 reserved1 : 8;
};
mlx_uint32 dword;
};
@ -194,7 +201,8 @@ union mlx_nvconfig_iscsi_general {
/*-------------------*/
mlx_uint32 lun_busy_retry_count:8;
mlx_uint32 link_up_delay_time :8;
mlx_uint32 reserved4 :16;
mlx_uint32 drive_num :8;
mlx_uint32 reserved4 :8;
};
mlx_uint32 dword[3];
};
@ -226,34 +234,98 @@ union mlx_nvconfig_vpi_link_conf {
};
struct mlx_nvcofnig_romini {
mlx_uint32 reserved0 :1;
mlx_uint32 reserved0 :1;
mlx_uint32 shared_memory_en :1;
mlx_uint32 hii_vpi_en :1;
mlx_uint32 tech_enum :1;
mlx_uint32 reserved1 :4;
mlx_uint32 hii_vpi_en :1;
mlx_uint32 tech_enum :1;
mlx_uint32 reserved1 :4;
mlx_uint32 static_component_name_string :1;
mlx_uint32 hii_iscsi_configuration :1;
mlx_uint32 hii_ibm_aim :1;
mlx_uint32 hii_ibm_aim :1;
mlx_uint32 hii_platform_setup :1;
mlx_uint32 hii_bdf_decimal :1;
mlx_uint32 hii_read_only :1;
mlx_uint32 reserved2 :10;
mlx_uint32 reserved2 :10;
mlx_uint32 mac_enum :1;
mlx_uint32 port_enum :1;
mlx_uint32 port_enum :1;
mlx_uint32 flash_en :1;
mlx_uint32 fmp_en :1;
mlx_uint32 bofm_en :1;
mlx_uint32 platform_to_driver_en :1;
mlx_uint32 platform_to_driver_en:1;
mlx_uint32 hii_en :1;
mlx_uint32 undi_en :1;
/* -------------- */
mlx_uint64 dhcp_user_class;
/* -------------- */
mlx_uint32 reserved3 :22;
mlx_uint32 reserved3 :10;
mlx_uint32 ucm_single_port :1;
mlx_uint32 tivoli_wa_en :1;
mlx_uint32 dhcp_pxe_discovery_control_dis :1;
mlx_uint32 hii_flexaddr_override:1;
mlx_uint32 hii_flexaddr_setting :1;
mlx_uint32 guided_ops :1;
mlx_uint32 hii_type :4;
mlx_uint32 hii_mriname2 :1;
mlx_uint32 hii_aim_ucm_ver2 :1;
mlx_uint32 uri_boot_retry_delay :4;
mlx_uint32 uri_boot_retry :4;
mlx_uint32 option_rom_debug :1;
mlx_uint32 promiscuous_vlan :1;
} __attribute__ ((packed));
union mlx_nvconfig_debug_conf {
struct {
mlx_uint32 dbg_log_en :1;
mlx_uint32 reserved1 :31;
/***************************************************/
mlx_uint32 stp_dbg_lvl :2;
mlx_uint32 romprefix_dbg_lvl :2;
mlx_uint32 dhcp_dbg_lvl :2;
mlx_uint32 dhcpv6_dbg_lvl :2;
mlx_uint32 arp_dbg_lvl :2;
mlx_uint32 neighbor_dbg_lvl :2;
mlx_uint32 ndp_dbg_lvl :2;
mlx_uint32 uri_dbg_lvl :2;
mlx_uint32 driver_dbg_lvl :2;
mlx_uint32 nodnic_dbg_lvl :2;
mlx_uint32 nodnic_cmd_dbg_lvl :2;
mlx_uint32 nodnic_device_dbg_lvl :2;
mlx_uint32 nodnic_port_dbg_lvl :2;
mlx_uint32 netdevice_dbg_lvl :2;
mlx_uint32 tftp_dbg_lvl :2;
mlx_uint32 udp_dbg_lvl :2;
/***************************************************/
mlx_uint32 tcp_dbg_lvl :2;
mlx_uint32 tcpip_dbg_lvl :2;
mlx_uint32 ipv4_dbg_lvl :2;
mlx_uint32 ipv6_dbg_lvl :2;
mlx_uint32 drv_set_dbg_lvl :2;
mlx_uint32 stat_update_dbg_lvl :2;
mlx_uint32 pxe_undi_dbg_lvl :2;
mlx_uint32 reserved2 :18;
};
mlx_uint32 dword[3];
};
union mlx_nvconfig_flexboot_debug {
struct {
mlx_uint32 reserved0 :29;
mlx_uint32 panic_behavior :2;
mlx_uint32 boot_to_shell :1;
};
mlx_uint32 dword;
};
union mlx_nvconfig_rom_cap_conf {
struct {
mlx_uint32 reserved0 :28;
mlx_uint32 uefi_logs_en :1;
mlx_uint32 flexboot_debug_en :1;
mlx_uint32 boot_debug_log_en :1;
mlx_uint32 boot_ip_ver_en :1;
};
mlx_uint32 dword;
};
#endif /* MLX_NVCONFIG_PRM_H_ */

View File

@ -316,7 +316,7 @@ mlx_icmd_send_command(
)
{
mlx_status status = MLX_SUCCESS;
mlx_uint32 icmd_status = MLX_FAILED;
mlx_uint32 icmd_status = 0;
if (utils == NULL || data == NULL) {
status = MLX_INVALID_PARAMETER;

View File

@ -20,6 +20,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <stddef.h>
#include "../../include/private/mlx_pci_priv.h"
#include "../../include/public/mlx_pci.h"
@ -38,6 +39,21 @@ bail:
return status;
}
mlx_status
mlx_pci_teardown(
IN mlx_utils *utils
)
{
mlx_status status = MLX_SUCCESS;
if( utils == NULL){
status = MLX_INVALID_PARAMETER;
goto bail;
}
status = mlx_pci_teardown_priv(utils);
bail:
return status;
}
mlx_status
mlx_pci_read(
IN mlx_utils *utils,

View File

@ -20,10 +20,10 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <stddef.h>
#include "../../include/private/mlx_utils_priv.h"
#include "../../include/public/mlx_pci.h"
#include "../../include/public/mlx_utils.h"
mlx_status
mlx_utils_init(
IN mlx_utils *utils,
@ -44,11 +44,12 @@ bail:
mlx_status
mlx_utils_teardown(
IN mlx_utils *utils __attribute__ ((unused))
IN mlx_utils *utils
)
{
mlx_status status = MLX_SUCCESS;
mlx_utils_free_lock(utils);
mlx_pci_teardown(utils);
return status;
}

View File

@ -12,8 +12,8 @@
#include <compiler.h>
#define MLX_DEBUG_FATAL_ERROR_PRIVATE(...) do { \
DBG("%s: ",__func__); \
DBG(__VA_ARGS__); \
printf("%s: ",__func__); \
printf(__VA_ARGS__); \
} while ( 0 )
#define MLX_DEBUG_ERROR_PRIVATE(id, ...) do { \
@ -56,6 +56,7 @@
DBG2(__VA_ARGS__); \
} while ( 0 )
#define MLX_PRINT_PRIVATE(...) printf(__VA_ARGS__)
#endif /* STUB_MLXUTILS_INCLUDE_PRIVATE_FLEXBOOT_DEBUG_H_ */

View File

@ -33,7 +33,7 @@ typedef uint8_t mlx_uint8;
typedef uint16_t mlx_uint16;
typedef uint32_t mlx_uint32;
typedef uint64_t mlx_uint64;
typedef uint32_t mlx_uintn;
typedef unsigned long mlx_uintn;
typedef int8_t mlx_int8;
typedef int16_t mlx_int16;;

View File

@ -6,6 +6,7 @@
*/
#include <ipxe/pci.h>
#include "../../mlx_utils/include/private/mlx_pci_priv.h"
@ -120,6 +121,18 @@ mlx_pci_init_priv(
return status;
}
mlx_status
mlx_pci_teardown_priv(
IN mlx_utils *utils __attribute__ ((unused))
)
{
mlx_status status = MLX_SUCCESS;
#ifdef DEVICE_CX3
iounmap( utils->config );
#endif
return status;
}
mlx_status
mlx_pci_read_priv(
IN mlx_utils *utils,

View File

@ -0,0 +1,325 @@
/*
* Copyright (C) 2016 David Decotigny <ddecotig@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <linux_api.h>
#include <ipxe/list.h>
#include <ipxe/linux.h>
#include <ipxe/malloc.h>
#include <ipxe/device.h>
#include <ipxe/netdevice.h>
#include <ipxe/iobuf.h>
#include <ipxe/ethernet.h>
#include <ipxe/settings.h>
#include <ipxe/socket.h>
/* This hack prevents pre-2.6.32 headers from redefining struct sockaddr */
#define __GLIBC__ 2
#include <linux/socket.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#undef __GLIBC__
#include <byteswap.h>
/* linux-specifc syscall params */
#define LINUX_AF_PACKET 17
#define LINUX_SOCK_RAW 3
#define LINUX_SIOCGIFINDEX 0x8933
#define LINUX_SIOCGIFHWADDR 0x8927
#define RX_BUF_SIZE 1536
/** @file
*
* The AF_PACKET driver.
*
* Bind to an existing linux network interface.
*/
struct af_packet_nic {
/** Linux network interface name */
char * ifname;
/** Packet socket descriptor */
int fd;
/** ifindex */
int ifindex;
};
/** Open the linux interface */
static int af_packet_nic_open ( struct net_device * netdev )
{
struct af_packet_nic * nic = netdev->priv;
struct sockaddr_ll socket_address;
struct ifreq if_data;
int ret;
nic->fd = linux_socket(LINUX_AF_PACKET, LINUX_SOCK_RAW,
htons(ETH_P_ALL));
if (nic->fd < 0) {
DBGC(nic, "af_packet %p socket(AF_PACKET) = %d (%s)\n",
nic, nic->fd, linux_strerror(linux_errno));
return nic->fd;
}
/* resolve ifindex of ifname */
memset(&if_data, 0, sizeof(if_data));
strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name));
ret = linux_ioctl(nic->fd, LINUX_SIOCGIFINDEX, &if_data);
if (ret < 0) {
DBGC(nic, "af_packet %p ioctl(SIOCGIFINDEX) = %d (%s)\n",
nic, ret, linux_strerror(linux_errno));
linux_close(nic->fd);
return ret;
}
nic->ifindex = if_data.ifr_ifindex;
/* bind to interface */
memset(&socket_address, 0, sizeof(socket_address));
socket_address.sll_family = LINUX_AF_PACKET;
socket_address.sll_ifindex = nic->ifindex;
socket_address.sll_protocol = htons(ETH_P_ALL);
ret = linux_bind(nic->fd, (void *) &socket_address,
sizeof(socket_address));
if (ret == -1) {
DBGC(nic, "af_packet %p bind() = %d (%s)\n",
nic, ret, linux_strerror(linux_errno));
linux_close(nic->fd);
return ret;
}
/* Set nonblocking mode to make af_packet_nic_poll() easier */
ret = linux_fcntl(nic->fd, F_SETFL, O_NONBLOCK);
if (ret != 0) {
DBGC(nic, "af_packet %p fcntl(%d, ...) = %d (%s)\n",
nic, nic->fd, ret, linux_strerror(linux_errno));
linux_close(nic->fd);
return ret;
}
return 0;
}
/** Close the packet socket */
static void af_packet_nic_close ( struct net_device *netdev )
{
struct af_packet_nic * nic = netdev->priv;
linux_close(nic->fd);
}
/**
* Transmit an ethernet packet.
*
* The packet can be written to the socket and marked as complete immediately.
*/
static int af_packet_nic_transmit ( struct net_device *netdev,
struct io_buffer *iobuf )
{
struct af_packet_nic * nic = netdev->priv;
struct sockaddr_ll socket_address;
const struct ethhdr * eh;
int rc;
memset(&socket_address, 0, sizeof(socket_address));
socket_address.sll_family = LINUX_AF_PACKET;
socket_address.sll_ifindex = nic->ifindex;
socket_address.sll_halen = ETH_ALEN;
eh = iobuf->data;
memcpy(socket_address.sll_addr, eh->h_dest, ETH_ALEN);
rc = linux_sendto(nic->fd, iobuf->data, iobuf->tail - iobuf->data,
0, (struct sockaddr *)&socket_address,
sizeof(socket_address));
DBGC2(nic, "af_packet %p wrote %d bytes\n", nic, rc);
netdev_tx_complete(netdev, iobuf);
return 0;
}
/** Poll for new packets */
static void af_packet_nic_poll ( struct net_device *netdev )
{
struct af_packet_nic * nic = netdev->priv;
struct pollfd pfd;
struct io_buffer * iobuf;
int r;
pfd.fd = nic->fd;
pfd.events = POLLIN;
if (linux_poll(&pfd, 1, 0) == -1) {
DBGC(nic, "af_packet %p poll failed (%s)\n",
nic, linux_strerror(linux_errno));
return;
}
if ((pfd.revents & POLLIN) == 0)
return;
/* At this point we know there is at least one new packet to be read */
iobuf = alloc_iob(RX_BUF_SIZE);
if (! iobuf)
goto allocfail;
while ((r = linux_read(nic->fd, iobuf->data, RX_BUF_SIZE)) > 0) {
DBGC2(nic, "af_packet %p read %d bytes\n", nic, r);
iob_put(iobuf, r);
netdev_rx(netdev, iobuf);
iobuf = alloc_iob(RX_BUF_SIZE);
if (! iobuf)
goto allocfail;
}
free_iob(iobuf);
return;
allocfail:
DBGC(nic, "af_packet %p alloc_iob failed\n", nic);
}
/**
* Set irq.
*
* Not used on linux, provide a dummy implementation.
*/
static void af_packet_nic_irq ( struct net_device *netdev, int enable )
{
struct af_packet_nic *nic = netdev->priv;
DBGC(nic, "af_packet %p irq enable = %d\n", nic, enable);
}
static int af_packet_update_properties ( struct net_device *netdev )
{
struct af_packet_nic *nic = netdev->priv;
struct ifreq if_data;
int ret;
/* retrieve default MAC address */
int fd = linux_socket(LINUX_AF_PACKET, LINUX_SOCK_RAW, 0);
if (fd < 0) {
DBGC(nic, "af_packet %p cannot create raw socket (%s)\n",
nic, linux_strerror(linux_errno));
return fd;
}
/* retrieve host's MAC address */
memset(&if_data, 0, sizeof(if_data));
strncpy(if_data.ifr_name, nic->ifname, sizeof(if_data.ifr_name));
ret = linux_ioctl(fd, LINUX_SIOCGIFHWADDR, &if_data);
if (ret < 0) {
DBGC(nic, "af_packet %p cannot get mac addr (%s)\n",
nic, linux_strerror(linux_errno));
linux_close(fd);
return ret;
}
linux_close(fd);
/* struct sockaddr = { u16 family, u8 pad[14] (equiv. sa_data) }; */
memcpy(netdev->ll_addr, if_data.ifr_hwaddr.pad, ETH_ALEN);
return 0;
}
/** AF_PACKET operations */
static struct net_device_operations af_packet_nic_operations = {
.open = af_packet_nic_open,
.close = af_packet_nic_close,
.transmit = af_packet_nic_transmit,
.poll = af_packet_nic_poll,
.irq = af_packet_nic_irq,
};
/** Handle a device request for the af_packet driver */
static int af_packet_nic_probe ( struct linux_device *device,
struct linux_device_request *request )
{
struct linux_setting *if_setting;
struct net_device *netdev;
struct af_packet_nic *nic;
int rc;
netdev = alloc_etherdev(sizeof(*nic));
if (! netdev)
return -ENOMEM;
netdev_init(netdev, &af_packet_nic_operations);
nic = netdev->priv;
linux_set_drvdata(device, netdev);
netdev->dev = &device->dev;
memset(nic, 0, sizeof(*nic));
/* Look for the mandatory if setting */
if_setting = linux_find_setting("if", &request->settings);
/* No if setting */
if (! if_setting) {
printf("af_packet missing a mandatory if setting\n");
rc = -EINVAL;
goto err_settings;
}
nic->ifname = if_setting->value;
snprintf ( device->dev.name, sizeof ( device->dev.name ), "%s",
nic->ifname );
device->dev.desc.bus_type = BUS_TYPE_TAP;
af_packet_update_properties(netdev);
if_setting->applied = 1;
/* Apply rest of the settings */
linux_apply_settings(&request->settings, &netdev->settings.settings);
/* Register network device */
if ((rc = register_netdev(netdev)) != 0)
goto err_register;
netdev_link_up(netdev);
return 0;
err_settings:
unregister_netdev(netdev);
err_register:
netdev_nullify(netdev);
netdev_put(netdev);
return rc;
}
/** Remove the device */
static void af_packet_nic_remove ( struct linux_device *device )
{
struct net_device *netdev = linux_get_drvdata(device);
unregister_netdev(netdev);
netdev_nullify(netdev);
netdev_put(netdev);
}
/** AF_PACKET linux_driver */
struct linux_driver af_packet_nic_driver __linux_driver = {
.name = "af_packet",
.probe = af_packet_nic_probe,
.remove = af_packet_nic_remove,
.can_probe = 1,
};

View File

@ -1381,7 +1381,7 @@ ath5k_poll(struct net80211_device *dev)
unsigned int counter = 1000;
if (currticks() - sc->last_calib_ticks >
ATH5K_CALIB_INTERVAL * ticks_per_sec()) {
ATH5K_CALIB_INTERVAL * TICKS_PER_SEC) {
ath5k_calibrate(sc);
sc->last_calib_ticks = currticks();
}

View File

@ -1176,7 +1176,7 @@ nv_mgmt_get_version ( struct forcedeth_private *priv )
ioaddr + NvRegTransmitterControl );
start = currticks();
while ( currticks() > start + 5 * ticks_per_sec() ) {
while ( currticks() > start + 5 * TICKS_PER_SEC ) {
data_ready2 = readl ( ioaddr + NvRegTransmitterControl );
if ( ( data_ready & NVREG_XMITCTL_DATA_READY ) !=
( data_ready2 & NVREG_XMITCTL_DATA_READY ) ) {

View File

@ -1069,7 +1069,7 @@ static struct pci_device_id intel_nics[] = {
PCI_ROM ( 0x8086, 0x15a1, "i218v-2", "I218-V", 0 ),
PCI_ROM ( 0x8086, 0x15a2, "i218lm-3", "I218-LM", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15a3, "i218v-3", "I218-V", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15b7, "i219lm-2", "I219-LM (2)", 0 ),
PCI_ROM ( 0x8086, 0x15b7, "i219lm-2", "I219-LM (2)", INTEL_NO_PHY_RST ),
PCI_ROM ( 0x8086, 0x15b8, "i219v-2", "I219-V (2)", 0 ),
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),

View File

@ -1146,10 +1146,17 @@ static int txnic_lmac_probe ( struct txnic_lmac *lmac ) {
* @v lmac Logical MAC
*/
static void txnic_lmac_remove ( struct txnic_lmac *lmac ) {
uint64_t config;
/* Sanity check */
assert ( lmac->vnic != NULL );
/* Disable packet receive and transmit */
config = readq ( lmac->regs + BGX_CMR_CONFIG );
config &= ~( BGX_CMR_CONFIG_DATA_PKT_TX_EN |
BGX_CMR_CONFIG_DATA_PKT_RX_EN );
writeq ( config, ( lmac->regs + BGX_CMR_CONFIG ) );
/* Unregister network device */
unregister_netdev ( lmac->vnic->netdev );
@ -1338,9 +1345,6 @@ static void txnic_pf_remove ( struct pci_device *pci ) {
/* Remove from list of physical functions */
list_del ( &pf->list );
/* Disable physical function */
writeq ( 0, ( pf->regs + TXNIC_PF_CFG ) );
/* Unmap registers */
iounmap ( pf->regs );

View File

@ -77,13 +77,8 @@ enum {
QUEUE_NB
};
enum {
/** Max number of pending rx packets */
NUM_RX_BUF = 8,
/** Max Ethernet frame length, including FCS and VLAN tag */
RX_BUF_SIZE = 1522,
};
/** Max number of pending rx packets */
#define NUM_RX_BUF 8
struct virtnet_nic {
/** Base pio register address */
@ -104,8 +99,8 @@ struct virtnet_nic {
/** Pending rx packet count */
unsigned int rx_num_iobufs;
/** Virtio net packet header, we only need one */
struct virtio_net_hdr_modern empty_header;
/** Virtio net dummy packet headers */
struct virtio_net_hdr_modern empty_header[QUEUE_NB];
};
/** Add an iobuf to a virtqueue
@ -120,19 +115,24 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
int vq_idx, struct io_buffer *iobuf ) {
struct virtnet_nic *virtnet = netdev->priv;
struct vring_virtqueue *vq = &virtnet->virtqueue[vq_idx];
struct virtio_net_hdr_modern *header = &virtnet->empty_header[vq_idx];
unsigned int out = ( vq_idx == TX_INDEX ) ? 2 : 0;
unsigned int in = ( vq_idx == TX_INDEX ) ? 0 : 2;
size_t header_len = virtnet->virtio_version
? sizeof ( virtnet->empty_header )
: sizeof ( virtnet->empty_header.legacy );
size_t header_len = ( virtnet->virtio_version ?
sizeof ( *header ) : sizeof ( header->legacy ) );
struct vring_list list[] = {
{
/* Share a single zeroed virtio net header between all
* rx and tx packets. This works because this driver
* packets in a ring. This works because this driver
* does not use any advanced features so none of the
* header fields get used.
*
* Some host implementations (notably Google Compute
* Platform) are known to unconditionally write back
* to header->flags for received packets. Work around
* this by using separate RX and TX headers.
*/
.addr = ( char* ) &virtnet->empty_header,
.addr = ( char* ) header,
.length = header_len,
},
{
@ -155,12 +155,13 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
*/
static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) {
struct virtnet_nic *virtnet = netdev->priv;
size_t len = ( netdev->max_pkt_len + 4 /* VLAN */ );
while ( virtnet->rx_num_iobufs < NUM_RX_BUF ) {
struct io_buffer *iobuf;
/* Try to allocate a buffer, stop for now if out of memory */
iobuf = alloc_iob ( RX_BUF_SIZE );
iobuf = alloc_iob ( len );
if ( ! iobuf )
break;
@ -168,13 +169,30 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) {
list_add ( &iobuf->list, &virtnet->rx_iobufs );
/* Mark packet length until we know the actual size */
iob_put ( iobuf, RX_BUF_SIZE );
iob_put ( iobuf, len );
virtnet_enqueue_iob ( netdev, RX_INDEX, iobuf );
virtnet->rx_num_iobufs++;
}
}
/** Helper to free all virtqueue memory
*
* @v netdev Network device
*/
static void virtnet_free_virtqueues ( struct net_device *netdev ) {
struct virtnet_nic *virtnet = netdev->priv;
int i;
for ( i = 0; i < QUEUE_NB; i++ ) {
virtio_pci_unmap_capability ( &virtnet->virtqueue[i].notification );
vp_free_vq ( &virtnet->virtqueue[i] );
}
free ( virtnet->virtqueue );
virtnet->virtqueue = NULL;
}
/** Open network device, legacy virtio 0.9.5
*
* @v netdev Network device
@ -200,8 +218,7 @@ static int virtnet_open_legacy ( struct net_device *netdev ) {
if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) {
DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n",
virtnet, i );
free ( virtnet->virtqueue );
virtnet->virtqueue = NULL;
virtnet_free_virtqueues ( netdev );
return -ENOENT;
}
}
@ -216,7 +233,8 @@ static int virtnet_open_legacy ( struct net_device *netdev ) {
/* Driver is ready */
features = vp_get_features ( ioaddr );
vp_set_features ( ioaddr, features & ( 1 << VIRTIO_NET_F_MAC ) );
vp_set_features ( ioaddr, features & ( ( 1 << VIRTIO_NET_F_MAC ) |
( 1 << VIRTIO_NET_F_MTU ) ) );
vp_set_status ( ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK );
return 0;
}
@ -239,6 +257,7 @@ static int virtnet_open_modern ( struct net_device *netdev ) {
}
vpm_set_features ( &virtnet->vdev, features & (
( 1ULL << VIRTIO_NET_F_MAC ) |
( 1ULL << VIRTIO_NET_F_MTU ) |
( 1ULL << VIRTIO_F_VERSION_1 ) |
( 1ULL << VIRTIO_F_ANY_LAYOUT ) ) );
vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FEATURES_OK );
@ -263,8 +282,7 @@ static int virtnet_open_modern ( struct net_device *netdev ) {
if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue ) ) {
DBGC ( virtnet, "VIRTIO-NET %p cannot register queues\n",
virtnet );
free ( virtnet->virtqueue );
virtnet->virtqueue = NULL;
virtnet_free_virtqueues ( netdev );
vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_FAILED );
return -ENOENT;
}
@ -304,7 +322,6 @@ static void virtnet_close ( struct net_device *netdev ) {
struct virtnet_nic *virtnet = netdev->priv;
struct io_buffer *iobuf;
struct io_buffer *next_iobuf;
int i;
if ( virtnet->virtio_version ) {
vpm_reset ( &virtnet->vdev );
@ -313,12 +330,7 @@ static void virtnet_close ( struct net_device *netdev ) {
}
/* Virtqueues can be freed now that NIC is reset */
for ( i = 0 ; i < QUEUE_NB ; i++ ) {
virtio_pci_unmap_capability ( &virtnet->virtqueue[i].notification );
}
free ( virtnet->virtqueue );
virtnet->virtqueue = NULL;
virtnet_free_virtqueues ( netdev );
/* Free rx iobufs */
list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) {
@ -375,7 +387,7 @@ static void virtnet_process_rx_packets ( struct net_device *netdev ) {
virtnet->rx_num_iobufs--;
/* Update iobuf length */
iob_unput ( iobuf, RX_BUF_SIZE );
iob_unput ( iobuf, iob_len ( iobuf ) );
iob_put ( iobuf, len - sizeof ( struct virtio_net_hdr ) );
DBGC2 ( virtnet, "VIRTIO-NET %p rx complete iobuf %p len %zd\n",
@ -447,6 +459,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
struct net_device *netdev;
struct virtnet_nic *virtnet;
u32 features;
u16 mtu;
int rc;
/* Allocate and hook up net device */
@ -466,7 +479,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
adjust_pci_device ( pci );
vp_reset ( ioaddr );
/* Load MAC address */
/* Load MAC address and MTU */
features = vp_get_features ( ioaddr );
if ( features & ( 1 << VIRTIO_NET_F_MAC ) ) {
vp_get ( ioaddr, offsetof ( struct virtio_net_config, mac ),
@ -474,6 +487,12 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
DBGC ( virtnet, "VIRTIO-NET %p mac=%s\n", virtnet,
eth_ntoa ( netdev->hw_addr ) );
}
if ( features & ( 1ULL << VIRTIO_NET_F_MTU ) ) {
vp_get ( ioaddr, offsetof ( struct virtio_net_config, mtu ),
&mtu, sizeof ( mtu ) );
DBGC ( virtnet, "VIRTIO-NET %p mtu=%d\n", virtnet, mtu );
netdev->max_pkt_len = ( mtu + ETH_HLEN );
}
/* Register network device */
if ( ( rc = register_netdev ( netdev ) ) != 0 )
@ -503,6 +522,7 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) {
struct net_device *netdev;
struct virtnet_nic *virtnet;
u64 features;
u16 mtu;
int rc, common, isr, notify, config, device;
common = virtio_pci_find_capability ( pci, VIRTIO_PCI_CAP_COMMON_CFG );
@ -569,7 +589,7 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) {
vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE );
vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_DRIVER );
/* Load MAC address */
/* Load MAC address and MTU */
if ( device ) {
features = vpm_get_features ( &virtnet->vdev );
if ( features & ( 1ULL << VIRTIO_NET_F_MAC ) ) {
@ -579,6 +599,14 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) {
DBGC ( virtnet, "VIRTIO-NET %p mac=%s\n", virtnet,
eth_ntoa ( netdev->hw_addr ) );
}
if ( features & ( 1ULL << VIRTIO_NET_F_MTU ) ) {
vpm_get ( &virtnet->vdev,
offsetof ( struct virtio_net_config, mtu ),
&mtu, sizeof ( mtu ) );
DBGC ( virtnet, "VIRTIO-NET %p mtu=%d\n", virtnet,
mtu );
netdev->max_pkt_len = ( mtu + ETH_HLEN );
}
}
/* We need a valid MAC address */

View File

@ -4,6 +4,7 @@
/* The feature bitmap for virtio net */
#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */
#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */
#define VIRTIO_NET_F_MTU 3 /* Initial MTU advice */
#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */
#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */
#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */
@ -25,6 +26,15 @@ struct virtio_net_config
{
/* The config defining mac address (if VIRTIO_NET_F_MAC) */
u8 mac[6];
/* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
u16 status;
/* Maximum number of each of transmit and receive queues;
* see VIRTIO_NET_F_MQ and VIRTIO_NET_CTRL_MQ.
* Legal values are between 1 and 0x8000
*/
u16 max_virtqueue_pairs;
/* Default maximum transmit unit advice */
u16 mtu;
} __attribute__((packed));
/* This is the first element of the scatter-gather list. If you don't

View File

@ -0,0 +1,304 @@
/*
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/x509.h>
#include <ipxe/certstore.h>
#include <ipxe/image.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <usr/imgmgmt.h>
#include <usr/certmgmt.h>
/** @file
*
* Certificate management commands
*
*/
/** "cert<xxx>" options */
struct cert_options {
/** Certificate subject name */
char *name;
/** Keep certificate file after parsing */
int keep;
};
/** "cert<xxx>" option list */
static union {
/* "certstore" takes both options */
struct option_descriptor certstore[2];
/* "certstat" takes only --subject */
struct option_descriptor certstat[1];
/* "certfree" takes only --subject */
struct option_descriptor certfree[1];
} opts = {
.certstore = {
OPTION_DESC ( "subject", 's', required_argument,
struct cert_options, name, parse_string ),
OPTION_DESC ( "keep", 'k', no_argument,
struct cert_options, keep, parse_flag ),
},
};
/** A "cert<xxx>" command descriptor */
struct cert_command_descriptor {
/** Command descriptor */
struct command_descriptor cmd;
/** Payload
*
* @v cert X.509 certificate
* @ret rc Return status code
*/
int ( * payload ) ( struct x509_certificate *cert );
};
/**
* Construct "cert<xxx>" command descriptor
*
* @v _struct Options structure type
* @v _options Option descriptor array
* @v _min_args Minimum number of non-option arguments
* @v _max_args Maximum number of non-option arguments
* @v _usage Command usage
* @v _payload Payload method
* @ret _command Command descriptor
*/
#define CERT_COMMAND_DESC( _struct, _options, _min_args, _max_args, \
_usage, _payload ) \
{ \
.cmd = COMMAND_DESC ( _struct, _options, _min_args, \
_max_args, _usage ), \
.payload = _payload, \
}
/**
* Execute "cert<xxx>" command
*
* @v argc Argument count
* @v argv Argument list
* @v certcmd Command descriptor
* @ret rc Return status code
*/
static int cert_exec ( int argc, char **argv,
struct cert_command_descriptor *certcmd ) {
struct command_descriptor *cmd = &certcmd->cmd;
struct cert_options opts;
struct image *image = NULL;
struct x509_certificate *cert;
struct x509_certificate *tmp;
unsigned int count = 0;
size_t offset = 0;
int next;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, cmd, &opts ) ) != 0 )
goto err_parse;
/* Acquire image, if applicable */
if ( ( optind < argc ) &&
( ( rc = imgacquire ( argv[optind], 0, &image ) ) != 0 ) )
goto err_acquire;
/* Get first entry in certificate store */
tmp = list_first_entry ( &certstore.links, struct x509_certificate,
store.list );
/* Iterate over certificates */
while ( 1 ) {
/* Get next certificate from image or store as applicable */
if ( image ) {
/* Get next certificate from image */
if ( offset >= image->len )
break;
next = image_x509 ( image, offset, &cert );
if ( next < 0 ) {
rc = next;
printf ( "Could not parse certificate: %s\n",
strerror ( rc ) );
goto err_x509;
}
offset = next;
} else {
/* Get next certificate from store */
cert = tmp;
if ( ! cert )
break;
tmp = list_next_entry ( tmp, &certstore.links,
store.list );
x509_get ( cert );
}
/* Skip non-matching names, if a name was specified */
if ( opts.name && ( x509_check_name ( cert, opts.name ) != 0 )){
x509_put ( cert );
continue;
}
/* Execute payload */
if ( ( rc = certcmd->payload ( cert ) ) != 0 ) {
x509_put ( cert );
goto err_payload;
}
/* Count number of certificates processed */
count++;
/* Drop reference to certificate */
x509_put ( cert );
}
/* Fail if a name was specified and no matching certificates
* were found.
*/
if ( opts.name && ( count == 0 ) ) {
printf ( "\"%s\" : no such certificate\n", opts.name );
rc = -ENOENT;
goto err_none;
}
err_none:
err_payload:
err_x509:
if ( image && ( ! opts.keep ) )
unregister_image ( image );
err_acquire:
err_parse:
return rc;
}
/**
* "certstat" payload
*
* @v cert X.509 certificate
* @ret rc Return status code
*/
static int certstat_payload ( struct x509_certificate *cert ) {
certstat ( cert );
return 0;
}
/** "certstat" command descriptor */
static struct cert_command_descriptor certstat_cmd =
CERT_COMMAND_DESC ( struct cert_options, opts.certstat, 0, 0, NULL,
certstat_payload );
/**
* The "certstat" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int certstat_exec ( int argc, char **argv ) {
return cert_exec ( argc, argv, &certstat_cmd );
}
/**
* "certstore" payload
*
* @v cert X.509 certificate
* @ret rc Return status code
*/
static int certstore_payload ( struct x509_certificate *cert ) {
/* Mark certificate as having been added explicitly */
cert->flags |= X509_FL_EXPLICIT;
return 0;
}
/** "certstore" command descriptor */
static struct cert_command_descriptor certstore_cmd =
CERT_COMMAND_DESC ( struct cert_options, opts.certstore, 0, 1,
"[<uri|image>]", certstore_payload );
/**
* The "certstore" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int certstore_exec ( int argc, char **argv ) {
return cert_exec ( argc, argv, &certstore_cmd );
}
/**
* "certfree" payload
*
* @v cert X.509 certificate
* @ret rc Return status code
*/
static int certfree_payload ( struct x509_certificate *cert ) {
/* Remove from certificate store */
certstore_del ( cert );
return 0;
}
/** "certfree" command descriptor */
static struct cert_command_descriptor certfree_cmd =
CERT_COMMAND_DESC ( struct cert_options, opts.certfree, 0, 0, NULL,
certfree_payload );
/**
* The "certfree" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int certfree_exec ( int argc, char **argv ) {
return cert_exec ( argc, argv, &certfree_cmd );
}
/** Certificate management commands */
struct command certmgmt_commands[] __command = {
{
.name = "certstat",
.exec = certstat_exec,
},
{
.name = "certstore",
.exec = certstore_exec,
},
{
.name = "certfree",
.exec = certfree_exec,
},
};

View File

@ -68,7 +68,7 @@ static int time_exec ( int argc, char **argv ) {
start = currticks();
rc = execv ( argv[1], argv + 1 );
elapsed = ( currticks() - start );
decisecs = ( 10 * elapsed / ticks_per_sec() );
decisecs = ( 10 * elapsed / TICKS_PER_SEC );
printf ( "%s: %d.%ds\n", argv[0],
( decisecs / 10 ), ( decisecs % 10 ) );

View File

@ -17,5 +17,6 @@ extern struct x509_chain certstore;
extern struct x509_certificate * certstore_find ( struct asn1_cursor *raw );
extern struct x509_certificate * certstore_find_key ( struct asn1_cursor *key );
extern void certstore_add ( struct x509_certificate *cert );
extern void certstore_del ( struct x509_certificate *cert );
#endif /* _IPXE_CERTSTORE_H */

View File

@ -83,6 +83,9 @@ struct dhcp_packet;
/** Root path */
#define DHCP_ROOT_PATH 17
/** Maximum transmission unit */
#define DHCP_MTU 26
/** Vendor encapsulated options */
#define DHCP_VENDOR_ENCAP 43

View File

@ -34,7 +34,7 @@ FILE_LICENCE ( BSD3 );
#if _MSC_EXTENSIONS
//
// use Microsoft* C complier dependent integer width types
// use Microsoft* C compiler dependent integer width types
//
typedef unsigned __int64 UINT64;
typedef __int64 INT64;

View File

@ -30,9 +30,16 @@ FILE_LICENCE ( BSD3 );
#pragma pack()
#endif
//
// RVCT does not support the __builtin_unreachable() macro
//
#ifdef __ARMCC_VERSION
#define UNREACHABLE()
#endif
#if _MSC_EXTENSIONS
//
// use Microsoft* C complier dependent integer width types
// use Microsoft* C compiler dependent integer width types
//
typedef unsigned __int64 UINT64;
typedef __int64 INT64;

View File

@ -86,6 +86,117 @@ VERIFY_SIZE_OF (CHAR16, 2);
#define GLOBAL_REMOVE_IF_UNREFERENCED
#endif
//
// Should be used in combination with NORETURN to avoid 'noreturn' returns
// warnings.
//
#ifndef UNREACHABLE
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)
///
/// Signal compilers and analyzers that this call is not reachable. It is
/// up to the compiler to remove any code past that point.
/// Not implemented by GCC 4.4 or earlier.
///
#define UNREACHABLE() __builtin_unreachable ()
#elif defined (__has_feature)
#if __has_builtin (__builtin_unreachable)
///
/// Signal compilers and analyzers that this call is not reachable. It is
/// up to the compiler to remove any code past that point.
///
#define UNREACHABLE() __builtin_unreachable ()
#endif
#endif
#ifndef UNREACHABLE
///
/// Signal compilers and analyzers that this call is not reachable. It is
/// up to the compiler to remove any code past that point.
///
#define UNREACHABLE()
#endif
#endif
//
// Signaling compilers and analyzers that a certain function cannot return may
// remove all following code and thus lead to better optimization and less
// false positives.
//
#ifndef NORETURN
#if defined (__GNUC__) || defined (__clang__)
///
/// Signal compilers and analyzers that the function cannot return.
/// It is up to the compiler to remove any code past a call to functions
/// flagged with this attribute.
///
#define NORETURN __attribute__((noreturn))
#elif defined(_MSC_EXTENSIONS) && !defined(MDE_CPU_EBC)
///
/// Signal compilers and analyzers that the function cannot return.
/// It is up to the compiler to remove any code past a call to functions
/// flagged with this attribute.
///
#define NORETURN __declspec(noreturn)
#else
///
/// Signal compilers and analyzers that the function cannot return.
/// It is up to the compiler to remove any code past a call to functions
/// flagged with this attribute.
///
#define NORETURN
#endif
#endif
//
// Should be used in combination with ANALYZER_NORETURN to avoid 'noreturn'
// returns warnings.
//
#ifndef ANALYZER_UNREACHABLE
#ifdef __clang_analyzer__
#if __has_builtin (__builtin_unreachable)
///
/// Signal the analyzer that this call is not reachable.
/// This excludes compilers.
///
#define ANALYZER_UNREACHABLE() __builtin_unreachable ()
#endif
#endif
#ifndef ANALYZER_UNREACHABLE
///
/// Signal the analyzer that this call is not reachable.
/// This excludes compilers.
///
#define ANALYZER_UNREACHABLE()
#endif
#endif
//
// Static Analyzers may issue errors about potential NULL-dereferences when
// dereferencing a pointer, that has been checked before, outside of a
// NULL-check. This may lead to false positives, such as when using ASSERT()
// for verification.
//
#ifndef ANALYZER_NORETURN
#ifdef __has_feature
#if __has_feature (attribute_analyzer_noreturn)
///
/// Signal analyzers that the function cannot return.
/// This excludes compilers.
///
#define ANALYZER_NORETURN __attribute__((analyzer_noreturn))
#endif
#endif
#ifndef ANALYZER_NORETURN
///
/// Signal the analyzer that the function cannot return.
/// This excludes compilers.
///
#define ANALYZER_NORETURN
#endif
#endif
//
// For symbol name in assembly code, an extra "_" is sometimes necessary
//
@ -193,7 +304,7 @@ struct _LIST_ENTRY {
//
// UEFI specification claims 1 and 0. We are concerned about the
// complier portability so we did it this way.
// compiler portability so we did it this way.
//
///
@ -480,7 +591,31 @@ struct _LIST_ENTRY {
#define VA_COPY(Dest, Start) __va_copy (Dest, Start)
#elif defined(__GNUC__) && !defined(NO_BUILTIN_VA_FUNCS)
#elif defined(__GNUC__)
#if defined(MDE_CPU_X64) && !defined(NO_MSABI_VA_FUNCS)
//
// X64 only. Use MS ABI version of GCC built-in macros for variable argument lists.
//
///
/// Both GCC and LLVM 3.8 for X64 support new variable argument intrinsics for Microsoft ABI
///
///
/// Variable used to traverse the list of arguments. This type can vary by
/// implementation and could be an array or structure.
///
typedef __builtin_ms_va_list VA_LIST;
#define VA_START(Marker, Parameter) __builtin_ms_va_start (Marker, Parameter)
#define VA_ARG(Marker, TYPE) ((sizeof (TYPE) < sizeof (UINTN)) ? (TYPE)(__builtin_va_arg (Marker, UINTN)) : (TYPE)(__builtin_va_arg (Marker, TYPE)))
#define VA_END(Marker) __builtin_ms_va_end (Marker)
#define VA_COPY(Dest, Start) __builtin_ms_va_copy (Dest, Start)
#else
//
// Use GCC built-in macros for variable argument lists.
//
@ -499,6 +634,8 @@ typedef __builtin_va_list VA_LIST;
#define VA_COPY(Dest, Start) __builtin_va_copy (Dest, Start)
#endif
#else
///
/// Variable used to traverse the list of arguments. This type can vary by
@ -1038,7 +1175,7 @@ typedef UINTN RETURN_STATUS;
#if defined(_MSC_EXTENSIONS) && !defined (__INTEL_COMPILER) && !defined (MDE_CPU_EBC)
#pragma intrinsic(_ReturnAddress)
/**
Get the return address of the calling funcation.
Get the return address of the calling function.
Based on intrinsic function _ReturnAddress that provides the address of
the instruction in the calling function that will be executed after
@ -1046,27 +1183,27 @@ typedef UINTN RETURN_STATUS;
@param L Return Level.
@return The return address of the calling funcation or 0 if L != 0.
@return The return address of the calling function or 0 if L != 0.
**/
#define RETURN_ADDRESS(L) ((L == 0) ? _ReturnAddress() : (VOID *) 0)
#elif defined(__GNUC__)
void * __builtin_return_address (unsigned int level);
/**
Get the return address of the calling funcation.
Get the return address of the calling function.
Based on built-in Function __builtin_return_address that returns
the return address of the current function, or of one of its callers.
@param L Return Level.
@return The return address of the calling funcation.
@return The return address of the calling function.
**/
#define RETURN_ADDRESS(L) __builtin_return_address (L)
#else
/**
Get the return address of the calling funcation.
Get the return address of the calling function.
@param L Return Level.

View File

@ -81,7 +81,7 @@ FILE_LICENCE ( BSD3 );
#pragma warning ( disable : 4057 )
//
// ASSERT(FALSE) or while (TRUE) are legal constructes so supress this warning
// ASSERT(FALSE) or while (TRUE) are legal constructs so suppress this warning
//
#pragma warning ( disable : 4127 )
@ -121,7 +121,7 @@ FILE_LICENCE ( BSD3 );
#if defined(_MSC_EXTENSIONS)
//
// use Microsoft C complier dependent integer width types
// use Microsoft C compiler dependent integer width types
//
///

View File

@ -5,11 +5,10 @@
PCI Local Bus Specification, 2.2
PCI-to-PCI Bridge Architecture Specification, Revision 1.2
PC Card Standard, 8.0
PCI Power Management Interface Specifiction, Revision 1.2
Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2014 - 2105, Hewlett-Packard Development Company, L.P.<BR>
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2014 - 2015, Hewlett-Packard Development Company, L.P.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -638,6 +637,7 @@ typedef union {
#define EFI_PCI_CAPABILITY_ID_SLOTID 0x04
#define EFI_PCI_CAPABILITY_ID_MSI 0x05
#define EFI_PCI_CAPABILITY_ID_HOTPLUG 0x06
#define EFI_PCI_CAPABILITY_ID_SHPC 0x0C
///
/// Capabilities List Header
@ -648,18 +648,6 @@ typedef struct {
UINT8 NextItemPtr;
} EFI_PCI_CAPABILITY_HDR;
///
/// Power Management Register Block Definition
/// Section 3.2, PCI Power Management Interface Specifiction, Revision 1.2
///
typedef struct {
EFI_PCI_CAPABILITY_HDR Hdr;
UINT16 PMC;
UINT16 PMCSR;
UINT8 BridgeExtention;
UINT8 Data;
} EFI_PCI_CAPABILITY_PMI;
///
/// PMC - Power Management Capabilities
/// Section 3.2.3, PCI Power Management Interface Specifiction, Revision 1.2
@ -668,7 +656,7 @@ typedef union {
struct {
UINT16 Version : 3;
UINT16 PmeClock : 1;
UINT16 : 1;
UINT16 Reserved : 1;
UINT16 DeviceSpecificInitialization : 1;
UINT16 AuxCurrent : 3;
UINT16 D1Support : 1;
@ -687,7 +675,9 @@ typedef union {
typedef union {
struct {
UINT16 PowerState : 2;
UINT16 : 6;
UINT16 ReservedForPciExpress : 1;
UINT16 NoSoftReset : 1;
UINT16 Reserved : 4;
UINT16 PmeEnable : 1;
UINT16 DataSelect : 4;
UINT16 DataScale : 2;
@ -696,6 +686,36 @@ typedef union {
UINT16 Data;
} EFI_PCI_PMCSR;
#define PCI_POWER_STATE_D0 0
#define PCI_POWER_STATE_D1 1
#define PCI_POWER_STATE_D2 2
#define PCI_POWER_STATE_D3_HOT 3
///
/// PMCSR_BSE - PMCSR PCI-to-PCI Bridge Support Extensions
/// Section 3.2.5, PCI Power Management Interface Specifiction, Revision 1.2
///
typedef union {
struct {
UINT8 Reserved : 6;
UINT8 B2B3 : 1;
UINT8 BusPowerClockControl : 1;
} Bits;
UINT8 Uint8;
} EFI_PCI_PMCSR_BSE;
///
/// Power Management Register Block Definition
/// Section 3.2, PCI Power Management Interface Specifiction, Revision 1.2
///
typedef struct {
EFI_PCI_CAPABILITY_HDR Hdr;
EFI_PCI_PMC PMC;
EFI_PCI_PMCSR PMCSR;
EFI_PCI_PMCSR_BSE BridgeExtention;
UINT8 Data;
} EFI_PCI_CAPABILITY_PMI;
///
/// A.G.P Capability
/// Section 6.1.4, Accelerated Graphics Port Interface Specification, Revision 1.0

View File

@ -2,7 +2,7 @@
Provides string functions, linked list functions, math functions, synchronization
functions, file path functions, and CPU architecture-specific functions.
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@ -189,6 +189,8 @@ typedef struct {
/**
Returns the length of a Null-terminated Unicode string.
This function is similar as strlen_s defined in C11.
If String is not aligned on a 16-bit boundary, then ASSERT().
@param String A pointer to a Null-terminated Unicode string.
@ -211,10 +213,14 @@ StrnLenS (
Copies the string pointed to by Source (including the terminating null char)
to the array pointed to by Destination.
This function is similar as strcpy_s defined in C11.
If Destination is not aligned on a 16-bit boundary, then ASSERT().
If Source is not aligned on a 16-bit boundary, then ASSERT().
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Unicode string.
@param DestMax The maximum number of Destination Unicode
char, including terminating null char.
@ -243,10 +249,14 @@ StrCpyS (
Source to the array pointed to by Destination. If no null char is copied from
Source, then Destination[Length] is always set to null.
This function is similar as strncpy_s defined in C11.
If Length > 0 and Destination is not aligned on a 16-bit boundary, then ASSERT().
If Length > 0 and Source is not aligned on a 16-bit boundary, then ASSERT().
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Unicode string.
@param DestMax The maximum number of Destination Unicode
char, including terminating null char.
@ -277,10 +287,14 @@ StrnCpyS (
Appends a copy of the string pointed to by Source (including the terminating
null char) to the end of the string pointed to by Destination.
This function is similar as strcat_s defined in C11.
If Destination is not aligned on a 16-bit boundary, then ASSERT().
If Source is not aligned on a 16-bit boundary, then ASSERT().
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Unicode string.
@param DestMax The maximum number of Destination Unicode
char, including terminating null char.
@ -313,10 +327,14 @@ StrCatS (
copied from Source, then Destination[StrLen(Destination) + Length] is always
set to null.
This function is similar as strncat_s defined in C11.
If Destination is not aligned on a 16-bit boundary, then ASSERT().
If Source is not aligned on a 16-bit boundary, then ASSERT().
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Unicode string.
@param DestMax The maximum number of Destination Unicode
char, including terminating null char.
@ -348,6 +366,8 @@ StrnCatS (
/**
Returns the length of a Null-terminated Ascii string.
This function is similar as strlen_s defined in C11.
@param String A pointer to a Null-terminated Ascii string.
@param MaxSize The maximum number of Destination Ascii
char, including terminating null char.
@ -368,8 +388,12 @@ AsciiStrnLenS (
Copies the string pointed to by Source (including the terminating null char)
to the array pointed to by Destination.
This function is similar as strcpy_s defined in C11.
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Ascii string.
@param DestMax The maximum number of Destination Ascii
char, including terminating null char.
@ -398,8 +422,12 @@ AsciiStrCpyS (
Source to the array pointed to by Destination. If no null char is copied from
Source, then Destination[Length] is always set to null.
This function is similar as strncpy_s defined in C11.
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Ascii string.
@param DestMax The maximum number of Destination Ascii
char, including terminating null char.
@ -430,8 +458,12 @@ AsciiStrnCpyS (
Appends a copy of the string pointed to by Source (including the terminating
null char) to the end of the string pointed to by Destination.
This function is similar as strcat_s defined in C11.
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Ascii string.
@param DestMax The maximum number of Destination Ascii
char, including terminating null char.
@ -464,8 +496,12 @@ AsciiStrCatS (
copied from Source, then Destination[StrLen(Destination) + Length] is always
set to null.
This function is similar as strncat_s defined in C11.
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Destination A pointer to a Null-terminated Ascii string.
@param DestMax The maximum number of Destination Ascii
char, including terminating null char.
@ -986,7 +1022,11 @@ StrHexToUint64 (
IN CONST CHAR16 *String
);
#ifndef DISABLE_NEW_DEPRECATED_INTERFACES
/**
[ATTENTION] This function is deprecated for security reason.
Convert a Null-terminated Unicode string to a Null-terminated
ASCII string and returns the ASCII string.
@ -1026,6 +1066,56 @@ UnicodeStrToAsciiStr (
OUT CHAR8 *Destination
);
#endif
/**
Convert a Null-terminated Unicode string to a Null-terminated
ASCII string.
This function is similar to AsciiStrCpyS.
This function converts the content of the Unicode string Source
to the ASCII string Destination by copying the lower 8 bits of
each Unicode character. The function terminates the ASCII string
Destination by appending a Null-terminator character at the end.
The caller is responsible to make sure Destination points to a buffer with size
equal or greater than ((StrLen (Source) + 1) * sizeof (CHAR8)) in bytes.
If any Unicode characters in Source contain non-zero value in
the upper 8 bits, then ASSERT().
If Source is not aligned on a 16-bit boundary, then ASSERT().
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Source The pointer to a Null-terminated Unicode string.
@param Destination The pointer to a Null-terminated ASCII string.
@param DestMax The maximum number of Destination Ascii
char, including terminating null char.
@retval RETURN_SUCCESS String is converted.
@retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than StrLen(Source).
@retval RETURN_INVALID_PARAMETER If Destination is NULL.
If Source is NULL.
If PcdMaximumAsciiStringLength is not zero,
and DestMax is greater than
PcdMaximumAsciiStringLength.
If PcdMaximumUnicodeStringLength is not zero,
and DestMax is greater than
PcdMaximumUnicodeStringLength.
If DestMax is 0.
@retval RETURN_ACCESS_DENIED If Source and Destination overlap.
**/
RETURN_STATUS
EFIAPI
UnicodeStrToAsciiStrS (
IN CONST CHAR16 *Source,
OUT CHAR8 *Destination,
IN UINTN DestMax
);
#ifndef DISABLE_NEW_DEPRECATED_INTERFACES
@ -1529,8 +1619,11 @@ AsciiStrHexToUint64 (
IN CONST CHAR8 *String
);
#ifndef DISABLE_NEW_DEPRECATED_INTERFACES
/**
[ATTENTION] This function is deprecated for security reason.
Convert one Null-terminated ASCII string to a Null-terminated
Unicode string and returns the Unicode string.
@ -1564,6 +1657,52 @@ AsciiStrToUnicodeStr (
OUT CHAR16 *Destination
);
#endif
/**
Convert one Null-terminated ASCII string to a Null-terminated
Unicode string.
This function is similar to StrCpyS.
This function converts the contents of the ASCII string Source to the Unicode
string Destination. The function terminates the Unicode string Destination by
appending a Null-terminator character at the end.
The caller is responsible to make sure Destination points to a buffer with size
equal or greater than ((AsciiStrLen (Source) + 1) * sizeof (CHAR16)) in bytes.
If Destination is not aligned on a 16-bit boundary, then ASSERT().
If an error would be returned, then the function will also ASSERT().
If an error is returned, then the Destination is unmodified.
@param Source The pointer to a Null-terminated ASCII string.
@param Destination The pointer to a Null-terminated Unicode string.
@param DestMax The maximum number of Destination Unicode
char, including terminating null char.
@retval RETURN_SUCCESS String is converted.
@retval RETURN_BUFFER_TOO_SMALL If DestMax is NOT greater than StrLen(Source).
@retval RETURN_INVALID_PARAMETER If Destination is NULL.
If Source is NULL.
If PcdMaximumUnicodeStringLength is not zero,
and DestMax is greater than
PcdMaximumUnicodeStringLength.
If PcdMaximumAsciiStringLength is not zero,
and DestMax is greater than
PcdMaximumAsciiStringLength.
If DestMax is 0.
@retval RETURN_ACCESS_DENIED If Source and Destination overlap.
**/
RETURN_STATUS
EFIAPI
AsciiStrToUnicodeStrS (
IN CONST CHAR8 *Source,
OUT CHAR16 *Destination,
IN UINTN DestMax
);
/**
Converts an 8-bit value to an 8-bit BCD value.
@ -1635,7 +1774,7 @@ PathRemoveLastItem(
@param[in] Path The pointer to the string containing the path.
@return Returns Path, otherwise returns NULL to indicate that an error has occured.
@return Returns Path, otherwise returns NULL to indicate that an error has occurred.
**/
CHAR16*
EFIAPI

View File

@ -1,7 +1,7 @@
/** @file
HOB related definitions in PI.
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
@ -11,7 +11,7 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
@par Revision Reference:
PI Version 1.4
PI Version 1.4a
**/
@ -295,7 +295,7 @@ typedef UINT32 EFI_RESOURCE_ATTRIBUTE_TYPE;
#define EFI_RESOURCE_ATTRIBUTE_PERSISTABLE 0x01000000
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED 0x00040000
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE 0x00800000
#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE 0x00080000
//
// Physical memory relative reliability attribute. This

View File

@ -1,5 +1,5 @@
#ifndef __EFI_APPLE_NET_BOOT_PROTOCOL_H__
#define __EFI_APPLE_NET_BOOT_PROTOCOL_H__
#ifndef _IPXE_EFI_APPLE_NET_BOOT_PROTOCOL_H
#define _IPXE_EFI_APPLE_NET_BOOT_PROTOCOL_H
/** @file
*
@ -43,4 +43,4 @@ struct _EFI_APPLE_NET_BOOT_PROTOCOL
GET_DHCP_RESPONSE GetBsdpResponse;
};
#endif /*__EFI_APPLE_NET_BOOT_PROTOCOL_H__ */
#endif /*_IPXE_EFI_APPLE_NET_BOOT_PROTOCOL_H */

View File

@ -0,0 +1,208 @@
/** @file
Block IO2 protocol as defined in the UEFI 2.3.1 specification.
The Block IO2 protocol defines an extension to the Block IO protocol which
enables the ability to read and write data at a block level in a non-blocking
manner.
Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __BLOCK_IO2_H__
#define __BLOCK_IO2_H__
FILE_LICENCE ( BSD3 );
#include <ipxe/efi/Protocol/BlockIo.h>
#define EFI_BLOCK_IO2_PROTOCOL_GUID \
{ \
0xa77b2472, 0xe282, 0x4e9f, {0xa2, 0x45, 0xc2, 0xc0, 0xe2, 0x7b, 0xbc, 0xc1} \
}
typedef struct _EFI_BLOCK_IO2_PROTOCOL EFI_BLOCK_IO2_PROTOCOL;
/**
The struct of Block IO2 Token.
**/
typedef struct {
///
/// If Event is NULL, then blocking I/O is performed.If Event is not NULL and
/// non-blocking I/O is supported, then non-blocking I/O is performed, and
/// Event will be signaled when the read request is completed.
///
EFI_EVENT Event;
///
/// Defines whether or not the signaled event encountered an error.
///
EFI_STATUS TransactionStatus;
} EFI_BLOCK_IO2_TOKEN;
/**
Reset the block device hardware.
@param[in] This Indicates a pointer to the calling context.
@param[in] ExtendedVerification Indicates that the driver may perform a more
exhausive verification operation of the device
during reset.
@retval EFI_SUCCESS The device was reset.
@retval EFI_DEVICE_ERROR The device is not functioning properly and could
not be reset.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_RESET_EX) (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
);
/**
Read BufferSize bytes from Lba into Buffer.
This function reads the requested number of blocks from the device. All the
blocks are read, or an error is returned.
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and
non-blocking I/O is being used, the Event associated with this request will
not be signaled.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId Id of the media, changes every time the media is
replaced.
@param[in] Lba The starting Logical Block Address to read from.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[out] Buffer A pointer to the destination buffer for the data. The
caller is responsible for either having implicit or
explicit ownership of the buffer.
@retval EFI_SUCCESS The read request was queued if Token->Event is
not NULL.The data was read correctly from the
device if the Token->Event is NULL.
@retval EFI_DEVICE_ERROR The device reported an error while performing
the read.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
intrinsic block size of the device.
@retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
or the buffer is not on proper alignment.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_READ_EX) (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA LBA,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
Write BufferSize bytes from Lba into Buffer.
This function writes the requested number of blocks to the device. All blocks
are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,
EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is
being used, the Event associated with this request will not be signaled.
@param[in] This Indicates a pointer to the calling context.
@param[in] MediaId The media ID that the write request is for.
@param[in] Lba The starting logical block address to be written. The
caller is responsible for writing to only legitimate
locations.
@param[in, out] Token A pointer to the token associated with the transaction.
@param[in] BufferSize Size of Buffer, must be a multiple of device block size.
@param[in] Buffer A pointer to the source buffer for the data.
@retval EFI_SUCCESS The write request was queued if Event is not NULL.
The data was written correctly to the device if
the Event is NULL.
@retval EFI_WRITE_PROTECTED The device can not be written to.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
@retval EFI_DEVICE_ERROR The device reported an error while performing the write.
@retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
@retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
or the buffer is not on proper alignment.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_WRITE_EX) (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN UINT32 MediaId,
IN EFI_LBA LBA,
IN OUT EFI_BLOCK_IO2_TOKEN *Token,
IN UINTN BufferSize,
IN VOID *Buffer
);
/**
Flush the Block Device.
If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED
is returned and non-blocking I/O is being used, the Event associated with
this request will not be signaled.
@param[in] This Indicates a pointer to the calling context.
@param[in,out] Token A pointer to the token associated with the transaction
@retval EFI_SUCCESS The flush request was queued if Event is not NULL.
All outstanding data was written correctly to the
device if the Event is NULL.
@retval EFI_DEVICE_ERROR The device reported an error while writting back
the data.
@retval EFI_WRITE_PROTECTED The device cannot be written to.
@retval EFI_NO_MEDIA There is no media in the device.
@retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
of resources.
**/
typedef
EFI_STATUS
(EFIAPI *EFI_BLOCK_FLUSH_EX) (
IN EFI_BLOCK_IO2_PROTOCOL *This,
IN OUT EFI_BLOCK_IO2_TOKEN *Token
);
///
/// The Block I/O2 protocol defines an extension to the Block I/O protocol which
/// enables the ability to read and write data at a block level in a non-blocking
// manner.
///
struct _EFI_BLOCK_IO2_PROTOCOL {
///
/// A pointer to the EFI_BLOCK_IO_MEDIA data for this device.
/// Type EFI_BLOCK_IO_MEDIA is defined in BlockIo.h.
///
EFI_BLOCK_IO_MEDIA *Media;
EFI_BLOCK_RESET_EX Reset;
EFI_BLOCK_READ_EX ReadBlocksEx;
EFI_BLOCK_WRITE_EX WriteBlocksEx;
EFI_BLOCK_FLUSH_EX FlushBlocksEx;
};
extern EFI_GUID gEfiBlockIo2ProtocolGuid;
#endif

View File

@ -5,7 +5,7 @@
from a software point of view. The path must persist from boot to boot, so
it can not contain things like PCI bus numbers that change from boot to boot.
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
@ -511,7 +511,7 @@ typedef struct {
UINT16 HBAPortNumber;
///
/// The Port multiplier port number that facilitates the connection
/// to the device. Bit 15 should be set if the device is directly
/// to the device. Must be set to 0xFFFF if the device is directly
/// connected to the HBA.
///
UINT16 PortMultiplierPortNumber;
@ -856,6 +856,15 @@ typedef struct {
UINT8 SlotNumber;
} SD_DEVICE_PATH;
///
/// EMMC (Embedded MMC) Device Path SubType.
///
#define MSG_EMMC_DP 0x1D
typedef struct {
EFI_DEVICE_PATH_PROTOCOL Header;
UINT8 SlotNumber;
} EMMC_DEVICE_PATH;
///
/// iSCSI Device Path SubType
///
@ -1241,6 +1250,7 @@ typedef union {
WIFI_DEVICE_PATH WiFi;
UFS_DEVICE_PATH Ufs;
SD_DEVICE_PATH Sd;
EMMC_DEVICE_PATH Emmc;
HARDDRIVE_DEVICE_PATH HardDrive;
CDROM_DEVICE_PATH CD;
@ -1297,6 +1307,7 @@ typedef union {
WIFI_DEVICE_PATH *WiFi;
UFS_DEVICE_PATH *Ufs;
SD_DEVICE_PATH *Sd;
EMMC_DEVICE_PATH *Emmc;
HARDDRIVE_DEVICE_PATH *HardDrive;
CDROM_DEVICE_PATH *CD;

View File

@ -1,7 +1,7 @@
/** @file
The file provides services to access to images in the images database.
Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@ -17,6 +17,8 @@
FILE_LICENCE ( BSD3 );
#include <ipxe/efi/Protocol/GraphicsOutput.h>
#define EFI_HII_IMAGE_PROTOCOL_GUID \
{ 0x31a6406a, 0x6bdf, 0x4e46, { 0xb2, 0xa2, 0xeb, 0xaa, 0x89, 0xc4, 0x9, 0x20 } }

View File

@ -1,5 +1,5 @@
/** @file
EFI Multicast Trivial File Tranfer Protocol Definition
EFI Multicast Trivial File Transfer Protocol Definition
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available under
@ -214,7 +214,7 @@ EFI_STATUS
);
/**
Timeout callback funtion.
Timeout callback function.
@param This The pointer to the EFI_MTFTP4_PROTOCOL instance.
@param Token The token that is provided in the

View File

@ -162,7 +162,7 @@ typedef EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SIMPLE_TEXT_OUTPUT_INTERFACE;
Reset the text output device hardware and optionaly run diagnostics
@param This The protocol instance pointer.
@param ExtendedVerification Driver may perform more exhaustive verfication
@param ExtendedVerification Driver may perform more exhaustive verification
operation of the device during reset.
@retval EFI_SUCCESS The text output device was reset.

View File

@ -3,7 +3,8 @@
IFR is primarily consumed by the EFI presentation engine, and produced by EFI
internal application and drivers as well as all add-in card option-ROM drivers
Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
This program and the accompanying materials are licensed and made available under
the terms and conditions of the BSD License that accompanies this distribution.
The full text of the license may be found at
@ -211,6 +212,7 @@ typedef struct _EFI_HII_FONT_PACKAGE_HDR {
#define EFI_HII_GIBT_GLYPHS 0x11
#define EFI_HII_GIBT_GLYPH_DEFAULT 0x12
#define EFI_HII_GIBT_GLYPHS_DEFAULT 0x13
#define EFI_HII_GIBT_GLYPH_VARIABILITY 0x14
#define EFI_HII_GIBT_DUPLICATE 0x20
#define EFI_HII_GIBT_SKIP2 0x21
#define EFI_HII_GIBT_SKIP1 0x22
@ -283,6 +285,13 @@ typedef struct _EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK {
UINT8 BitmapData[1];
} EFI_HII_GIBT_GLYPHS_DEFAULT_BLOCK;
typedef struct _EFI_HII_GIBT_VARIABILITY_BLOCK {
EFI_HII_GLYPH_BLOCK Header;
EFI_HII_GLYPH_INFO Cell;
UINT8 GlyphPackInBits;
UINT8 BitmapData [1];
} EFI_HII_GIBT_VARIABILITY_BLOCK;
typedef struct _EFI_HII_GIBT_SKIP1_BLOCK {
EFI_HII_GLYPH_BLOCK Header;
UINT8 SkipCount;
@ -491,6 +500,7 @@ typedef struct _EFI_HII_IMAGE_BLOCK {
#define EFI_HII_IIBT_IMAGE_24BIT 0x16
#define EFI_HII_IIBT_IMAGE_24BIT_TRANS 0x17
#define EFI_HII_IIBT_IMAGE_JPEG 0x18
#define EFI_HII_IIBT_IMAGE_PNG 0x19
#define EFI_HII_IIBT_DUPLICATE 0x20
#define EFI_HII_IIBT_SKIP2 0x21
#define EFI_HII_IIBT_SKIP1 0x22
@ -611,6 +621,12 @@ typedef struct _EFI_HII_IIBT_JPEG_BLOCK {
UINT8 Data[1];
} EFI_HII_IIBT_JPEG_BLOCK;
typedef struct _EFI_HII_IIBT_PNG_BLOCK {
EFI_HII_IMAGE_BLOCK Header;
UINT32 Size;
UINT8 Data[1];
} EFI_HII_IIBT_PNG_BLOCK;
typedef struct _EFI_HII_IIBT_SKIP1_BLOCK {
EFI_HII_IMAGE_BLOCK Header;
UINT8 SkipCount;
@ -2112,4 +2128,10 @@ typedef struct _EFI_HII_AIBT_SKIP2_BLOCK {
///
#define STRING_TOKEN(t) t
///
/// IMAGE_TOKEN is not defined in UEFI specification. But it is placed
/// here for the easy access by C files and VFR source files.
///
#define IMAGE_TOKEN(t) t
#endif

View File

@ -1081,7 +1081,7 @@ typedef struct s_pxe_cpb_start_31 {
///
/// protocol driver can provide anything for this Unique_ID, UNDI remembers
/// that as just a 64bit value assocaited to the interface specified by
/// that as just a 64bit value associated to the interface specified by
/// the ifnum and gives it back as a parameter to all the call-back routines
/// when calling for that interface!
///

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