mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e814d33900 | |||
| f4f9adf618 | |||
| fbbdc39260 | |||
| 53a5de3641 | |||
| 91c77e2592 | |||
| f43c2fd697 | |||
| 9062544f6a | |||
| 562c74e1ea | |||
| 0f4cc4b5a7 | |||
| a046da21a4 | |||
| 3ad27fbe78 | |||
| b6045a8cbb | |||
| 51612b6e69 | |||
| 236299baa3 | |||
| 1844aacc83 | |||
| 85eb961bf9 | |||
| f24a2794e1 | |||
| 2265a65191 | |||
| 05a76acc6d | |||
| 91e147213c | |||
| 0cc4c42f0a | |||
| 02ec659b73 | |||
| e09e1142a3 | |||
| db6310c3e5 | |||
| b33cc1efe3 | |||
| 4d180be517 | |||
| c64dfff0a9 | |||
| 8d08300ad9 | |||
| 2690f73096 | |||
| 4aa0375821 | |||
| 5622575c5e | |||
| 0688114ea6 | |||
| 9b6ad2d888 | |||
| 51c88a4a62 | |||
| bf4ccd4265 | |||
| 3c040ad387 | |||
| 3dd1989ac0 | |||
| 52300ccf98 | |||
| 92807f5759 | |||
| 065dce8d59 | |||
| f3f568e382 | |||
| 74c54461cb | |||
| 0d68d71519 | |||
| e5f0255173 | |||
| ef9953b712 | |||
| bfca3db41e | |||
| fc8bd4ba1a | |||
| 661093054b | |||
| 059c4dc688 | |||
| adb2ed907e | |||
| d7bc9e9d67 | |||
| 62f732207e | |||
| 191f8825cb | |||
| a6a8bb1a9a | |||
| 05fcf1a2f0 | |||
| 13c1abe10a | |||
| 866fa1ce76 | |||
| d093683d93 | |||
| 5c9c8d2b9b | |||
| de4f31cdca | |||
| 106f4c5391 | |||
| 1dfc05622d | |||
| 438513f6f6 | |||
| 6dad316e66 | |||
| e994237c0b | |||
| 323af9ee84 | |||
| b2501dd122 | |||
| 56f7d44fde | |||
| 3efdbef2f0 | |||
| e4afaa2246 | |||
| 614d99eba1 |
@ -3,14 +3,25 @@
|
||||
import argparse
|
||||
from base64 import b64encode
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from datetime import date
|
||||
from hashlib import sha256
|
||||
from itertools import count
|
||||
import subprocess
|
||||
|
||||
import boto3
|
||||
|
||||
BLOCKSIZE = 512 * 1024
|
||||
|
||||
|
||||
def detect_architecture(image):
|
||||
"""Detect CPU architecture"""
|
||||
mdir = subprocess.run(['mdir', '-b', '-i', image, '::/EFI/BOOT'],
|
||||
capture_output=True)
|
||||
if any(b'BOOTAA64.EFI' in x for x in mdir.stdout.splitlines()):
|
||||
return 'arm64'
|
||||
return 'x86_64'
|
||||
|
||||
|
||||
def create_snapshot(region, description, image):
|
||||
"""Create an EBS snapshot"""
|
||||
client = boto3.client('ebs', region_name=region)
|
||||
@ -65,36 +76,64 @@ def import_image(region, name, architecture, image, public):
|
||||
return image_id
|
||||
|
||||
|
||||
def launch_link(region, image_id):
|
||||
"""Construct a web console launch link"""
|
||||
return ("https://console.aws.amazon.com/ec2/v2/home?"
|
||||
"region=%s#LaunchInstanceWizard:ami=%s" % (region, image_id))
|
||||
|
||||
|
||||
# Parse command-line arguments
|
||||
parser = argparse.ArgumentParser(description="Import AWS EC2 image (AMI)")
|
||||
parser.add_argument('--architecture', '-a', default='x86_64',
|
||||
help="CPU architecture")
|
||||
parser.add_argument('--name', '-n', required=True,
|
||||
parser.add_argument('--name', '-n',
|
||||
help="Image name")
|
||||
parser.add_argument('--public', '-p', action='store_true',
|
||||
help="Make image public")
|
||||
parser.add_argument('--region', '-r', action='append',
|
||||
help="AWS region(s)")
|
||||
parser.add_argument('image', help="iPXE disk image")
|
||||
parser.add_argument('--wiki', '-w', metavar='FILE',
|
||||
help="Generate Dokuwiki table")
|
||||
parser.add_argument('image', nargs='+', help="iPXE disk image")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Detect CPU architectures
|
||||
architectures = {image: detect_architecture(image) for image in args.image}
|
||||
|
||||
# Use default name if none specified
|
||||
if not args.name:
|
||||
args.name = 'iPXE (%s)' % date.today().strftime('%Y-%m-%d')
|
||||
|
||||
# Use all regions if none specified
|
||||
if not args.region:
|
||||
args.region = sorted(x['RegionName'] for x in
|
||||
boto3.client('ec2').describe_regions()['Regions'])
|
||||
|
||||
# Use one thread per region to maximise parallelism
|
||||
with ThreadPoolExecutor(max_workers=len(args.region)) as executor:
|
||||
# Use one thread per import to maximise parallelism
|
||||
imports = [(region, image) for region in args.region for image in args.image]
|
||||
with ThreadPoolExecutor(max_workers=len(imports)) as executor:
|
||||
futures = {executor.submit(import_image,
|
||||
region=region,
|
||||
name=args.name,
|
||||
architecture=args.architecture,
|
||||
image=args.image,
|
||||
public=args.public): region
|
||||
for region in args.region}
|
||||
architecture=architectures[image],
|
||||
image=image,
|
||||
public=args.public): (region, image)
|
||||
for region, image in imports}
|
||||
results = {futures[future]: future.result()
|
||||
for future in as_completed(futures)}
|
||||
|
||||
# Construct Dokuwiki table
|
||||
wikitab = ["^ AWS region ^ CPU architecture ^ AMI ID ^\n"] + list(
|
||||
"| ''%s'' | ''%s'' | ''[[%s|%s]]'' |\n" % (
|
||||
region,
|
||||
architectures[image],
|
||||
launch_link(region, results[(region, image)]),
|
||||
results[(region, image)],
|
||||
) for region, image in imports)
|
||||
if args.wiki:
|
||||
with open(args.wiki, 'wt') as fh:
|
||||
fh.writelines(wikitab)
|
||||
|
||||
# Show created images
|
||||
for region in args.region:
|
||||
print("%s: %s" % (region, results[region]))
|
||||
for region, image in imports:
|
||||
print("%s %s %s %s" % (
|
||||
region, image, architectures[image], results[(region, image)]
|
||||
))
|
||||
|
||||
@ -190,7 +190,7 @@ vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
|
||||
@$(ECHO) ' bin/10222000.rom -- vlance/pcnet32'
|
||||
@$(ECHO) ' bin/15ad07b0.rom -- vmxnet3'
|
||||
@$(ECHO)
|
||||
@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
|
||||
@$(ECHO) 'For more information, see https://ipxe.org/howto/vmware'
|
||||
@$(ECHO)
|
||||
@$(ECHO) '==========================================================='
|
||||
|
||||
|
||||
@ -43,7 +43,8 @@ $(BIN)/%.drv.efi : $(BIN)/%.efidrv
|
||||
|
||||
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
|
||||
$(QM)$(ECHO) " [FINISH] $@"
|
||||
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) -c $< $@
|
||||
$(Q)$(EFIROM) -v $(firstword $(TGT_PCI_VENDOR) 0) \
|
||||
-d $(firstword $(TGT_PCI_DEVICE) 0) -c $< $@
|
||||
|
||||
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
|
||||
$(QM)$(ECHO) " [CAB] $@"
|
||||
|
||||
@ -918,7 +918,7 @@ $(BIN)/deps/%.d : % $(MAKEDEPS)
|
||||
|
||||
# Calculate list of dependency files
|
||||
#
|
||||
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
|
||||
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS) core/version.c)
|
||||
autodeps :
|
||||
@$(ECHO) $(AUTO_DEPS)
|
||||
VERYCLEANUP += $(BIN)/deps
|
||||
@ -1167,7 +1167,8 @@ $(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS)
|
||||
$(Q)$(RM) $(BLIB)
|
||||
$(QM)$(ECHO) " [AR] $@"
|
||||
$(Q)$(AR) rD $@ $(sort $(BLIB_OBJS))
|
||||
$(Q)$(OBJCOPY) --prefix-symbols=$(SYMBOL_PREFIX) $@
|
||||
$(Q)$(OBJCOPY) --enable-deterministic-archives \
|
||||
--prefix-symbols=$(SYMBOL_PREFIX) $@
|
||||
$(Q)$(RANLIB) -D $@
|
||||
blib : $(BLIB)
|
||||
|
||||
@ -1201,7 +1202,7 @@ endif
|
||||
# Build version
|
||||
#
|
||||
GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
|
||||
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
|
||||
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(version_DEPS) $(GIT_INDEX)
|
||||
$(QM)$(ECHO) " [VERSION] $@"
|
||||
$(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
|
||||
-DVERSION_MAJOR=$(VERSION_MAJOR) \
|
||||
|
||||
@ -136,6 +136,8 @@ SECTIONS {
|
||||
*(.note.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -100,5 +100,7 @@ SECTIONS {
|
||||
*(.rel.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,17 +75,18 @@ void bigint_multiply_raw ( const uint32_t *multiplicand0,
|
||||
*
|
||||
* a < 2^{n}, b < 2^{n} => ab < 2^{2n}
|
||||
*/
|
||||
__asm__ __volatile__ ( "mull %4\n\t"
|
||||
"addl %%eax, (%5,%2,4)\n\t"
|
||||
"adcl %%edx, 4(%5,%2,4)\n\t"
|
||||
__asm__ __volatile__ ( "mull %5\n\t"
|
||||
"addl %%eax, (%6,%2,4)\n\t"
|
||||
"adcl %%edx, 4(%6,%2,4)\n\t"
|
||||
"\n1:\n\t"
|
||||
"adcl $0, 8(%5,%2,4)\n\t"
|
||||
"adcl $0, 8(%6,%2,4)\n\t"
|
||||
"inc %2\n\t"
|
||||
/* Does not affect CF */
|
||||
"jc 1b\n\t"
|
||||
: "=&a" ( discard_a ),
|
||||
"=&d" ( discard_d ),
|
||||
"=&r" ( index )
|
||||
"=&r" ( index ),
|
||||
"+m" ( *result )
|
||||
: "0" ( multiplicand_element ),
|
||||
"g" ( multiplier_element ),
|
||||
"r" ( result_elements ),
|
||||
|
||||
@ -104,6 +104,13 @@ static union u_PXENV_ANY __bss16 ( undinet_params );
|
||||
SEGOFF16_t __bss16 ( undinet_entry_point );
|
||||
#define undinet_entry_point __use_data16 ( undinet_entry_point )
|
||||
|
||||
/* Read TSC in real mode only when profiling */
|
||||
#if PROFILING
|
||||
#define RDTSC_IF_PROFILING "rdtsc\n\t"
|
||||
#else
|
||||
#define RDTSC_IF_PROFILING ""
|
||||
#endif
|
||||
|
||||
/** IRQ profiler */
|
||||
static struct profiler undinet_irq_profiler __profiler =
|
||||
{ .name = "undinet.irq" };
|
||||
@ -288,14 +295,14 @@ static int undinet_call ( struct undi_nic *undinic, unsigned int function,
|
||||
*/
|
||||
profile_start ( &profiler->total );
|
||||
__asm__ __volatile__ ( REAL_CODE ( "pushl %%ebp\n\t" /* gcc bug */
|
||||
"rdtsc\n\t"
|
||||
RDTSC_IF_PROFILING
|
||||
"pushl %%eax\n\t"
|
||||
"pushw %%es\n\t"
|
||||
"pushw %%di\n\t"
|
||||
"pushw %%bx\n\t"
|
||||
"lcall *undinet_entry_point\n\t"
|
||||
"movw %%ax, %%bx\n\t"
|
||||
"rdtsc\n\t"
|
||||
RDTSC_IF_PROFILING
|
||||
"addw $6, %%sp\n\t"
|
||||
"popl %%edx\n\t"
|
||||
"popl %%ebp\n\t" /* gcc bug */ )
|
||||
|
||||
@ -326,32 +326,6 @@ static void bzimage_set_cmdline ( struct image *image,
|
||||
DBGC ( image, "bzImage %p command line \"%s\"\n", image, cmdline );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse standalone image command line for cpio parameters
|
||||
*
|
||||
* @v image bzImage file
|
||||
* @v cpio CPIO header
|
||||
* @v cmdline Command line
|
||||
*/
|
||||
static void bzimage_parse_cpio_cmdline ( struct image *image,
|
||||
struct cpio_header *cpio,
|
||||
const char *cmdline ) {
|
||||
char *arg;
|
||||
char *end;
|
||||
unsigned int mode;
|
||||
|
||||
/* Look for "mode=" */
|
||||
if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
|
||||
arg += 5;
|
||||
mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
|
||||
if ( *end && ( *end != ' ' ) ) {
|
||||
DBGC ( image, "bzImage %p strange \"mode=\""
|
||||
"terminator '%c'\n", image, *end );
|
||||
}
|
||||
cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Align initrd length
|
||||
*
|
||||
@ -374,11 +348,9 @@ static inline size_t bzimage_align ( size_t len ) {
|
||||
static size_t bzimage_load_initrd ( struct image *image,
|
||||
struct image *initrd,
|
||||
userptr_t address ) {
|
||||
char *filename = initrd->cmdline;
|
||||
char *cmdline;
|
||||
const char *filename = cpio_name ( initrd );
|
||||
struct cpio_header cpio;
|
||||
size_t offset;
|
||||
size_t name_len;
|
||||
size_t pad_len;
|
||||
|
||||
/* Do not include kernel image itself as an initrd */
|
||||
@ -386,25 +358,7 @@ static size_t bzimage_load_initrd ( struct image *image,
|
||||
return 0;
|
||||
|
||||
/* Create cpio header for non-prebuilt images */
|
||||
if ( filename && filename[0] ) {
|
||||
cmdline = strchr ( filename, ' ' );
|
||||
name_len = ( ( cmdline ? ( ( size_t ) ( cmdline - filename ) )
|
||||
: strlen ( filename ) ) + 1 /* NUL */ );
|
||||
memset ( &cpio, '0', sizeof ( cpio ) );
|
||||
memcpy ( cpio.c_magic, CPIO_MAGIC, sizeof ( cpio.c_magic ) );
|
||||
cpio_set_field ( cpio.c_mode, 0100644 );
|
||||
cpio_set_field ( cpio.c_nlink, 1 );
|
||||
cpio_set_field ( cpio.c_filesize, initrd->len );
|
||||
cpio_set_field ( cpio.c_namesize, name_len );
|
||||
if ( cmdline ) {
|
||||
bzimage_parse_cpio_cmdline ( image, &cpio,
|
||||
( cmdline + 1 /* ' ' */ ));
|
||||
}
|
||||
offset = ( ( sizeof ( cpio ) + name_len + 0x03 ) & ~0x03 );
|
||||
} else {
|
||||
offset = 0;
|
||||
name_len = 0;
|
||||
}
|
||||
offset = cpio_header ( initrd, &cpio );
|
||||
|
||||
/* Copy in initrd image body (and cpio header if applicable) */
|
||||
if ( address ) {
|
||||
@ -413,7 +367,7 @@ static size_t bzimage_load_initrd ( struct image *image,
|
||||
memset_user ( address, 0, 0, offset );
|
||||
copy_to_user ( address, 0, &cpio, sizeof ( cpio ) );
|
||||
copy_to_user ( address, sizeof ( cpio ), filename,
|
||||
( name_len - 1 /* NUL (or space) */ ) );
|
||||
cpio_name_len ( initrd ) );
|
||||
}
|
||||
DBGC ( image, "bzImage %p initrd %p [%#08lx,%#08lx,%#08lx)"
|
||||
"%s%s\n", image, initrd, user_to_phys ( address, 0 ),
|
||||
|
||||
@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/memblock.h>
|
||||
#include <ipxe/cpio.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
|
||||
@ -25,19 +25,22 @@ typedef uint32_t bigint_element_t;
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_init_raw ( uint32_t *value0, unsigned int size,
|
||||
const void *data, size_t len ) {
|
||||
long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
long pad_len = ( sizeof ( *value ) - len );
|
||||
void *discard_D;
|
||||
long discard_c;
|
||||
|
||||
/* Copy raw data in reverse order, padding with zeros */
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"movb -1(%2,%1), %%al\n\t"
|
||||
"movb -1(%3,%1), %%al\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t"
|
||||
"xorl %%eax, %%eax\n\t"
|
||||
"mov %3, %1\n\t"
|
||||
"mov %4, %1\n\t"
|
||||
"rep stosb\n\t"
|
||||
: "=&D" ( discard_D ), "=&c" ( discard_c )
|
||||
: "=&D" ( discard_D ), "=&c" ( discard_c ),
|
||||
"+m" ( *value )
|
||||
: "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
|
||||
"1" ( len )
|
||||
: "eax" );
|
||||
@ -53,6 +56,8 @@ bigint_init_raw ( uint32_t *value0, unsigned int size,
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
long index;
|
||||
void *discard_S;
|
||||
long discard_c;
|
||||
@ -60,11 +65,11 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
|
||||
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
|
||||
"\n1:\n\t"
|
||||
"lodsl\n\t"
|
||||
"adcl %%eax, (%3,%0,4)\n\t"
|
||||
"adcl %%eax, (%4,%0,4)\n\t"
|
||||
"inc %0\n\t" /* Does not affect CF */
|
||||
"loop 1b\n\t"
|
||||
: "=&r" ( index ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
"=&c" ( discard_c ), "+m" ( *value )
|
||||
: "r" ( value0 ), "1" ( addend0 ), "2" ( size )
|
||||
: "eax" );
|
||||
}
|
||||
@ -79,6 +84,8 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
|
||||
unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
long index;
|
||||
void *discard_S;
|
||||
long discard_c;
|
||||
@ -86,11 +93,11 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
|
||||
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
|
||||
"\n1:\n\t"
|
||||
"lodsl\n\t"
|
||||
"sbbl %%eax, (%3,%0,4)\n\t"
|
||||
"sbbl %%eax, (%4,%0,4)\n\t"
|
||||
"inc %0\n\t" /* Does not affect CF */
|
||||
"loop 1b\n\t"
|
||||
: "=&r" ( index ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
"=&c" ( discard_c ), "+m" ( *value )
|
||||
: "r" ( value0 ), "1" ( subtrahend0 ),
|
||||
"2" ( size )
|
||||
: "eax" );
|
||||
@ -104,15 +111,18 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
long index;
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
|
||||
"\n1:\n\t"
|
||||
"rcll $1, (%2,%0,4)\n\t"
|
||||
"rcll $1, (%3,%0,4)\n\t"
|
||||
"inc %0\n\t" /* Does not affect CF */
|
||||
"loop 1b\n\t"
|
||||
: "=&r" ( index ), "=&c" ( discard_c )
|
||||
: "=&r" ( index ), "=&c" ( discard_c ),
|
||||
"+m" ( *value )
|
||||
: "r" ( value0 ), "1" ( size ) );
|
||||
}
|
||||
|
||||
@ -124,13 +134,15 @@ bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
|
||||
bigint_t ( size ) __attribute__ (( may_alias )) *value =
|
||||
( ( void * ) value0 );
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "clc\n\t"
|
||||
"\n1:\n\t"
|
||||
"rcrl $1, -4(%1,%0,4)\n\t"
|
||||
"rcrl $1, -4(%2,%0,4)\n\t"
|
||||
"loop 1b\n\t"
|
||||
: "=&c" ( discard_c )
|
||||
: "=&c" ( discard_c ), "+m" ( *value )
|
||||
: "r" ( value0 ), "0" ( size ) );
|
||||
}
|
||||
|
||||
@ -239,6 +251,8 @@ bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
|
||||
uint32_t *dest0, unsigned int dest_size ) {
|
||||
bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
|
||||
( ( void * ) dest0 );
|
||||
long pad_size = ( dest_size - source_size );
|
||||
void *discard_D;
|
||||
void *discard_S;
|
||||
@ -246,10 +260,10 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
|
||||
|
||||
__asm__ __volatile__ ( "rep movsl\n\t"
|
||||
"xorl %%eax, %%eax\n\t"
|
||||
"mov %3, %2\n\t"
|
||||
"mov %4, %2\n\t"
|
||||
"rep stosl\n\t"
|
||||
: "=&D" ( discard_D ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
"=&c" ( discard_c ), "+m" ( *dest )
|
||||
: "g" ( pad_size ), "0" ( dest0 ),
|
||||
"1" ( source0 ), "2" ( source_size )
|
||||
: "eax" );
|
||||
@ -266,13 +280,15 @@ bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
|
||||
uint32_t *dest0, unsigned int dest_size ) {
|
||||
bigint_t ( dest_size ) __attribute__ (( may_alias )) *dest =
|
||||
( ( void * ) dest0 );
|
||||
void *discard_D;
|
||||
void *discard_S;
|
||||
long discard_c;
|
||||
|
||||
__asm__ __volatile__ ( "rep movsl\n\t"
|
||||
: "=&D" ( discard_D ), "=&S" ( discard_S ),
|
||||
"=&c" ( discard_c )
|
||||
"=&c" ( discard_c ), "+m" ( *dest )
|
||||
: "0" ( dest0 ), "1" ( source0 ),
|
||||
"2" ( dest_size )
|
||||
: "eax" );
|
||||
@ -289,15 +305,19 @@ bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
|
||||
void *out, size_t len ) {
|
||||
struct {
|
||||
uint8_t bytes[len];
|
||||
} __attribute__ (( may_alias )) *out_bytes = out;
|
||||
void *discard_D;
|
||||
long discard_c;
|
||||
|
||||
/* Copy raw data in reverse order */
|
||||
__asm__ __volatile__ ( "\n1:\n\t"
|
||||
"movb -1(%2,%1), %%al\n\t"
|
||||
"movb -1(%3,%1), %%al\n\t"
|
||||
"stosb\n\t"
|
||||
"loop 1b\n\t"
|
||||
: "=&D" ( discard_D ), "=&c" ( discard_c )
|
||||
: "=&D" ( discard_D ), "=&c" ( discard_c ),
|
||||
"+m" ( *out_bytes )
|
||||
: "r" ( value0 ), "0" ( out ), "1" ( len )
|
||||
: "eax" );
|
||||
}
|
||||
|
||||
@ -11,13 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/uaccess.h>
|
||||
|
||||
/** Minimum alignment for initrds
|
||||
*
|
||||
* Some versions of Linux complain about initrds that are not
|
||||
* page-aligned.
|
||||
*/
|
||||
#define INITRD_ALIGN 4096
|
||||
|
||||
/** Minimum free space required to reshuffle initrds
|
||||
*
|
||||
* Chosen to avoid absurdly long reshuffling times
|
||||
|
||||
@ -42,6 +42,9 @@ struct x86_features {
|
||||
/** Hypervisor is present */
|
||||
#define CPUID_FEATURES_INTEL_ECX_HYPERVISOR 0x80000000UL
|
||||
|
||||
/** TSC is present */
|
||||
#define CPUID_FEATURES_INTEL_EDX_TSC 0x00000010UL
|
||||
|
||||
/** FXSAVE and FXRSTOR are supported */
|
||||
#define CPUID_FEATURES_INTEL_EDX_FXSR 0x01000000UL
|
||||
|
||||
|
||||
@ -42,6 +42,69 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** _S5_ signature */
|
||||
#define S5_SIGNATURE ACPI_SIGNATURE ( '_', 'S', '5', '_' )
|
||||
|
||||
/**
|
||||
* Extract \_Sx value from DSDT/SSDT
|
||||
*
|
||||
* @v zsdt DSDT or SSDT
|
||||
* @v len Length of DSDT/SSDT
|
||||
* @v offset Offset of signature within DSDT/SSDT
|
||||
* @v data Data buffer
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* In theory, extracting the \_Sx value from the DSDT/SSDT requires a
|
||||
* full ACPI parser plus some heuristics to work around the various
|
||||
* broken encodings encountered in real ACPI implementations.
|
||||
*
|
||||
* In practice, we can get the same result by scanning through the
|
||||
* DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
|
||||
* four bytes, removing any bytes with bit 3 set, and treating
|
||||
* whatever is left as a little-endian value. This is one of the
|
||||
* uglier hacks I have ever implemented, but it's still prettier than
|
||||
* the ACPI specification itself.
|
||||
*/
|
||||
static int acpi_extract_sx ( userptr_t zsdt, size_t len, size_t offset,
|
||||
void *data ) {
|
||||
unsigned int *sx = data;
|
||||
uint8_t bytes[4];
|
||||
uint8_t *byte;
|
||||
|
||||
/* Skip signature and package header */
|
||||
offset += ( 4 /* signature */ + 3 /* package header */ );
|
||||
|
||||
/* Sanity check */
|
||||
if ( ( offset + sizeof ( bytes ) /* value */ ) > len ) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Read first four bytes of value */
|
||||
copy_from_user ( bytes, zsdt, offset, sizeof ( bytes ) );
|
||||
DBGC ( colour, "ACPI found \\_Sx containing %02x:%02x:%02x:%02x\n",
|
||||
bytes[0], bytes[1], bytes[2], bytes[3] );
|
||||
|
||||
/* Extract \Sx value. There are three potential encodings
|
||||
* that we might encounter:
|
||||
*
|
||||
* - SLP_TYPa, SLP_TYPb, rsvd, rsvd
|
||||
*
|
||||
* - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
|
||||
*
|
||||
* - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
|
||||
*
|
||||
* Since <byteprefix> and <dwordprefix> both have bit 3 set,
|
||||
* and valid SLP_TYPx must have bit 3 clear (since SLP_TYPx is
|
||||
* a 3-bit field), we can just skip any bytes with bit 3 set.
|
||||
*/
|
||||
byte = bytes;
|
||||
if ( *byte & 0x08 )
|
||||
byte++;
|
||||
*sx = *(byte++);
|
||||
if ( *byte & 0x08 )
|
||||
byte++;
|
||||
*sx |= ( *byte << 8 );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Power off the computer using ACPI
|
||||
*
|
||||
@ -56,7 +119,7 @@ int acpi_poweroff ( void ) {
|
||||
unsigned int pm1b_cnt;
|
||||
unsigned int slp_typa;
|
||||
unsigned int slp_typb;
|
||||
int s5;
|
||||
unsigned int s5;
|
||||
int rc;
|
||||
|
||||
/* Locate FADT */
|
||||
@ -74,9 +137,8 @@ int acpi_poweroff ( void ) {
|
||||
pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT );
|
||||
|
||||
/* Extract \_S5 from DSDT or any SSDT */
|
||||
s5 = acpi_sx ( S5_SIGNATURE );
|
||||
if ( s5 < 0 ) {
|
||||
rc = s5;
|
||||
if ( ( rc = acpi_extract ( S5_SIGNATURE, &s5,
|
||||
acpi_extract_sx ) ) != 0 ) {
|
||||
DBGC ( colour, "ACPI could not extract \\_S5: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
|
||||
@ -59,7 +59,8 @@ static void cachedhcp_init ( void ) {
|
||||
}
|
||||
|
||||
/* Record cached DHCPACK */
|
||||
if ( ( rc = cachedhcp_record ( phys_to_user ( cached_dhcpack_phys ),
|
||||
if ( ( rc = cachedhcp_record ( &cached_dhcpack,
|
||||
phys_to_user ( cached_dhcpack_phys ),
|
||||
sizeof ( BOOTPLAYER_t ) ) ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n",
|
||||
strerror ( rc ) );
|
||||
|
||||
@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <biosint.h>
|
||||
#include <pic8259.h>
|
||||
#include <rtc.h>
|
||||
#include <ipxe/cpuid.h>
|
||||
#include <ipxe/entropy.h>
|
||||
|
||||
/** Maximum time to wait for an RTC interrupt, in milliseconds */
|
||||
@ -174,8 +175,17 @@ static int rtc_entropy_check ( void ) {
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rtc_entropy_enable ( void ) {
|
||||
struct x86_features features;
|
||||
int rc;
|
||||
|
||||
/* Check that TSC is supported */
|
||||
x86_features ( &features );
|
||||
if ( ! ( features.intel.edx & CPUID_FEATURES_INTEL_EDX_TSC ) ) {
|
||||
DBGC ( &rtc_flag, "RTC has no TSC\n" );
|
||||
rc = -ENOTSUP;
|
||||
goto err_no_tsc;
|
||||
}
|
||||
|
||||
/* Hook ISR and enable RTC interrupts */
|
||||
rtc_hook_isr();
|
||||
enable_irq ( RTC_IRQ );
|
||||
@ -191,6 +201,7 @@ static int rtc_entropy_enable ( void ) {
|
||||
rtc_disable_int();
|
||||
disable_irq ( RTC_IRQ );
|
||||
rtc_unhook_isr();
|
||||
err_no_tsc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ static char __bss16_array ( syslinux_version, [32] );
|
||||
#define syslinux_version __use_data16 ( syslinux_version )
|
||||
|
||||
/** The "SYSLINUX" copyright string */
|
||||
static char __data16_array ( syslinux_copyright, [] ) = " http://ipxe.org";
|
||||
static char __data16_array ( syslinux_copyright, [] ) = " https://ipxe.org";
|
||||
#define syslinux_copyright __use_data16 ( syslinux_copyright )
|
||||
|
||||
static char __data16_array ( syslinux_configuration_file, [] ) = "";
|
||||
|
||||
@ -161,7 +161,7 @@ pnpheader:
|
||||
|
||||
/* Manufacturer string */
|
||||
mfgstr:
|
||||
.asciz "http://ipxe.org"
|
||||
.asciz "https://ipxe.org"
|
||||
.size mfgstr, . - mfgstr
|
||||
|
||||
/* Product string
|
||||
@ -607,7 +607,7 @@ get_pmm_decompress_to:
|
||||
* strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/branding.h.
|
||||
*
|
||||
* While nothing in the GPL prevents you from removing all references
|
||||
* to iPXE or http://ipxe.org, we prefer you not to do so.
|
||||
* to iPXE or https://ipxe.org, we prefer you not to do so.
|
||||
*
|
||||
* If you have an OEM-mandated branding requirement that cannot be
|
||||
* satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,
|
||||
|
||||
@ -44,7 +44,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*/
|
||||
|
||||
.text
|
||||
.arch i586
|
||||
.arch i486
|
||||
.section ".prefix.lib", "ax", @progbits
|
||||
|
||||
#ifdef CODE16
|
||||
|
||||
@ -229,6 +229,8 @@ SECTIONS {
|
||||
*(.einfo.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -24,6 +24,8 @@ SECTIONS {
|
||||
*(.einfo.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -100,5 +100,7 @@ SECTIONS {
|
||||
*(.rel.*)
|
||||
*(.discard)
|
||||
*(.discard.*)
|
||||
*(.sbat)
|
||||
*(.sbat.*)
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*/
|
||||
#define PRODUCT_NAME ""
|
||||
#define PRODUCT_SHORT_NAME "iPXE"
|
||||
#define PRODUCT_URI "http://ipxe.org"
|
||||
#define PRODUCT_URI "https://ipxe.org"
|
||||
|
||||
/*
|
||||
* Tag line
|
||||
@ -44,15 +44,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* (e.g. "Permission denied") and a 32-bit error number. This number
|
||||
* is incorporated into an error URI such as
|
||||
*
|
||||
* "No such file or directory (http://ipxe.org/2d0c613b)"
|
||||
* "No such file or directory (https://ipxe.org/2d0c613b)"
|
||||
*
|
||||
* or
|
||||
*
|
||||
* "Operation not supported (http://ipxe.org/3c092003)"
|
||||
* "Operation not supported (https://ipxe.org/3c092003)"
|
||||
*
|
||||
* Users may browse to the URI within the error message, which is
|
||||
* provided by a database running on the iPXE web site
|
||||
* (http://ipxe.org). This database provides details for all possible
|
||||
* (https://ipxe.org). This database provides details for all possible
|
||||
* errors generated by iPXE, including:
|
||||
*
|
||||
* - the detailed error message (e.g. "Not an OCSP signing
|
||||
@ -74,13 +74,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
* If you have a customer support team and would like your customers
|
||||
* to contact your support team for all problems, instead of using the
|
||||
* existing support infrastructure provided by http://ipxe.org, then
|
||||
* existing support infrastructure provided by https://ipxe.org, then
|
||||
* you may define a custom URI to be included within error messages.
|
||||
*
|
||||
* Note that the custom URI is a printf() format string which must
|
||||
* include a format specifier for the 32-bit error number.
|
||||
*/
|
||||
#define PRODUCT_ERROR_URI "http://ipxe.org/%08x"
|
||||
#define PRODUCT_ERROR_URI "https://ipxe.org/%08x"
|
||||
|
||||
/*
|
||||
* Command help messages
|
||||
@ -88,7 +88,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* iPXE command help messages include a URI constructed from the
|
||||
* command name, such as
|
||||
*
|
||||
* "See http://ipxe.org/cmd/vcreate for further information"
|
||||
* "See https://ipxe.org/cmd/vcreate for further information"
|
||||
*
|
||||
* The iPXE web site includes documentation for the commands provided
|
||||
* by the iPXE shell, including:
|
||||
@ -113,7 +113,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
* If you want to provide your own documentation for all of the
|
||||
* commands provided by the iPXE shell, rather than using the existing
|
||||
* support infrastructure provided by http://ipxe.org, then you may
|
||||
* support infrastructure provided by https://ipxe.org, then you may
|
||||
* define a custom URI to be included within command help messages.
|
||||
*
|
||||
* Note that the custom URI is a printf() format string which must
|
||||
@ -124,7 +124,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* iPXE project and prohibit the alteration or removal of any
|
||||
* references to "iPXE". ]
|
||||
*/
|
||||
#define PRODUCT_COMMAND_URI "http://ipxe.org/cmd/%s"
|
||||
#define PRODUCT_COMMAND_URI "https://ipxe.org/cmd/%s"
|
||||
|
||||
/*
|
||||
* Setting help messages
|
||||
@ -132,7 +132,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* iPXE setting help messages include a URI constructed from the
|
||||
* setting name, such as
|
||||
*
|
||||
* "http://ipxe.org/cfg/initiator-iqn"
|
||||
* "https://ipxe.org/cfg/initiator-iqn"
|
||||
*
|
||||
* The iPXE web site includes documentation for the settings used by
|
||||
* iPXE, including:
|
||||
@ -156,7 +156,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
* If you want to provide your own documentation for all of the
|
||||
* settings used by iPXE, rather than using the existing support
|
||||
* infrastructure provided by http://ipxe.org, then you may define a
|
||||
* infrastructure provided by https://ipxe.org, then you may define a
|
||||
* custom URI to be included within setting help messages.
|
||||
*
|
||||
* Note that the custom URI is a printf() format string which must
|
||||
@ -167,7 +167,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* iPXE project and prohibit the alteration or removal of any
|
||||
* references to "iPXE". ]
|
||||
*/
|
||||
#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s"
|
||||
#define PRODUCT_SETTING_URI "https://ipxe.org/cfg/%s"
|
||||
|
||||
/*
|
||||
* Product security name suffix
|
||||
*
|
||||
* Vendors creating signed iPXE binaries must set this to a non-empty
|
||||
* value (e.g. "2pint").
|
||||
*/
|
||||
#define PRODUCT_SBAT_NAME ""
|
||||
|
||||
/*
|
||||
* Product security generation
|
||||
*
|
||||
* Vendors creating signed iPXE binaries must set this to a non-zero
|
||||
* value, and must increment the value whenever a Secure Boot exploit
|
||||
* is fixed (unless the upstream IPXE_SBAT_GENERATION has already been
|
||||
* incremented as part of that fix).
|
||||
*/
|
||||
#define PRODUCT_SBAT_GENERATION 0
|
||||
|
||||
#include <config/local/branding.h>
|
||||
|
||||
|
||||
@ -3,6 +3,22 @@
|
||||
echo Amazon EC2 - iPXE boot via user-data
|
||||
echo CPU: ${cpuvendor} ${cpumodel}
|
||||
ifstat ||
|
||||
dhcp ||
|
||||
|
||||
set attempt:int8 1
|
||||
:dhcp_retry
|
||||
echo DHCP attempt ${attempt}
|
||||
dhcp --timeout 5000 && goto dhcp_ok ||
|
||||
ifstat ||
|
||||
inc attempt
|
||||
iseq ${attempt} 10 || goto dhcp_retry
|
||||
|
||||
:dhcp_fail
|
||||
echo DHCP failed - rebooting
|
||||
reboot ||
|
||||
exit
|
||||
|
||||
:dhcp_ok
|
||||
route ||
|
||||
chain -ar http://169.254.169.254/latest/user-data
|
||||
chain -ar http://169.254.169.254/latest/user-data ||
|
||||
ifstat ||
|
||||
exit
|
||||
|
||||
@ -5,4 +5,5 @@ echo CPU: ${cpuvendor} ${cpumodel}
|
||||
ifstat ||
|
||||
dhcp ||
|
||||
route ||
|
||||
chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot
|
||||
chain -ar http://metadata.google.internal/computeMetadata/v1/instance/attributes/ipxeboot ||
|
||||
ifstat ||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
/* 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).
|
||||
*/
|
||||
#if defined ( __i386__ ) || defined ( __x86_64__ )
|
||||
#define CPUID_SETTINGS
|
||||
#endif
|
||||
|
||||
@ -182,6 +182,12 @@ REQUIRE_OBJECT ( efi_image );
|
||||
#ifdef IMAGE_SDI
|
||||
REQUIRE_OBJECT ( sdi );
|
||||
#endif
|
||||
#ifdef IMAGE_ZLIB
|
||||
REQUIRE_OBJECT ( zlib );
|
||||
#endif
|
||||
#ifdef IMAGE_GZIP
|
||||
REQUIRE_OBJECT ( gzip );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in all requested commands
|
||||
|
||||
36
src/config/config_archive.c
Normal file
36
src/config/config_archive.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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/general.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Archive image configuration
|
||||
*
|
||||
*/
|
||||
|
||||
PROVIDE_REQUIRING_SYMBOL();
|
||||
|
||||
#ifdef IMAGE_ARCHIVE_CMD
|
||||
REQUIRE_OBJECT ( image_archive_cmd );
|
||||
#endif
|
||||
@ -117,6 +117,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define IMAGE_PNG /* PNG image support */
|
||||
#define IMAGE_DER /* DER image support */
|
||||
#define IMAGE_PEM /* PEM image support */
|
||||
//#define IMAGE_ZLIB /* ZLIB image support */
|
||||
//#define IMAGE_GZIP /* GZIP image support */
|
||||
|
||||
/*
|
||||
* Command-line commands to include
|
||||
@ -156,6 +158,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
//#define NTP_CMD /* NTP commands */
|
||||
//#define CERT_CMD /* Certificate management commands */
|
||||
//#define IMAGE_MEM_CMD /* Read memory command */
|
||||
#define IMAGE_ARCHIVE_CMD /* Archive image management commands */
|
||||
|
||||
/*
|
||||
* ROM-specific options
|
||||
|
||||
@ -169,33 +169,22 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract \_Sx value from DSDT/SSDT
|
||||
* Extract value from DSDT/SSDT
|
||||
*
|
||||
* @v zsdt DSDT or SSDT
|
||||
* @v signature Signature (e.g. "_S5_")
|
||||
* @ret sx \_Sx value, or negative error
|
||||
*
|
||||
* In theory, extracting the \_Sx value from the DSDT/SSDT requires a
|
||||
* full ACPI parser plus some heuristics to work around the various
|
||||
* broken encodings encountered in real ACPI implementations.
|
||||
*
|
||||
* In practice, we can get the same result by scanning through the
|
||||
* DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
|
||||
* four bytes, removing any bytes with bit 3 set, and treating
|
||||
* whatever is left as a little-endian value. This is one of the
|
||||
* uglier hacks I have ever implemented, but it's still prettier than
|
||||
* the ACPI specification itself.
|
||||
* @v data Data buffer
|
||||
* @v extract Extraction method
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
|
||||
static int acpi_zsdt ( userptr_t zsdt, uint32_t signature, void *data,
|
||||
int ( * extract ) ( userptr_t zsdt, size_t len,
|
||||
size_t offset, void *data ) ) {
|
||||
struct acpi_header acpi;
|
||||
union {
|
||||
uint32_t dword;
|
||||
uint8_t byte[4];
|
||||
} buf;
|
||||
uint32_t buf;
|
||||
size_t offset;
|
||||
size_t len;
|
||||
unsigned int sx;
|
||||
uint8_t *byte;
|
||||
int rc;
|
||||
|
||||
/* Read table header */
|
||||
copy_from_user ( &acpi, zsdt, 0, sizeof ( acpi ) );
|
||||
@ -203,75 +192,51 @@ static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
|
||||
|
||||
/* Locate signature */
|
||||
for ( offset = sizeof ( acpi ) ;
|
||||
( ( offset + sizeof ( buf ) /* signature */ + 3 /* pkg header */
|
||||
+ sizeof ( buf ) /* value */ ) < len ) ;
|
||||
( ( offset + sizeof ( buf ) /* signature */ ) < len ) ;
|
||||
offset++ ) {
|
||||
|
||||
/* Check signature */
|
||||
copy_from_user ( &buf, zsdt, offset, sizeof ( buf ) );
|
||||
if ( buf.dword != cpu_to_le32 ( signature ) )
|
||||
if ( buf != cpu_to_le32 ( signature ) )
|
||||
continue;
|
||||
DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n",
|
||||
user_to_phys ( zsdt, 0 ), acpi_name ( signature ),
|
||||
offset );
|
||||
offset += sizeof ( buf );
|
||||
|
||||
/* Read first four bytes of value */
|
||||
copy_from_user ( &buf, zsdt, ( offset + 3 /* pkg header */ ),
|
||||
sizeof ( buf ) );
|
||||
DBGC ( zsdt, "DSDT/SSDT %#08lx found %s containing "
|
||||
"%02x:%02x:%02x:%02x\n", user_to_phys ( zsdt, 0 ),
|
||||
acpi_name ( signature ), buf.byte[0], buf.byte[1],
|
||||
buf.byte[2], buf.byte[3] );
|
||||
|
||||
/* Extract \Sx value. There are three potential
|
||||
* encodings that we might encounter:
|
||||
*
|
||||
* - SLP_TYPa, SLP_TYPb, rsvd, rsvd
|
||||
*
|
||||
* - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
|
||||
*
|
||||
* - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
|
||||
*
|
||||
* Since <byteprefix> and <dwordprefix> both have bit
|
||||
* 3 set, and valid SLP_TYPx must have bit 3 clear
|
||||
* (since SLP_TYPx is a 3-bit field), we can just skip
|
||||
* any bytes with bit 3 set.
|
||||
*/
|
||||
byte = &buf.byte[0];
|
||||
if ( *byte & 0x08 )
|
||||
byte++;
|
||||
sx = *(byte++);
|
||||
if ( *byte & 0x08 )
|
||||
byte++;
|
||||
sx |= ( *byte << 8 );
|
||||
return sx;
|
||||
/* Attempt to extract data */
|
||||
if ( ( rc = extract ( zsdt, len, offset, data ) ) == 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract \_Sx value from DSDT/SSDT
|
||||
* Extract value from DSDT/SSDT
|
||||
*
|
||||
* @v signature Signature (e.g. "_S5_")
|
||||
* @ret sx \_Sx value, or negative error
|
||||
* @v data Data buffer
|
||||
* @v extract Extraction method
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int acpi_sx ( uint32_t signature ) {
|
||||
int acpi_extract ( uint32_t signature, void *data,
|
||||
int ( * extract ) ( userptr_t zsdt, size_t len,
|
||||
size_t offset, void *data ) ) {
|
||||
struct acpi_fadt fadtab;
|
||||
userptr_t fadt;
|
||||
userptr_t dsdt;
|
||||
userptr_t ssdt;
|
||||
unsigned int i;
|
||||
int sx;
|
||||
int rc;
|
||||
|
||||
/* Try DSDT first */
|
||||
fadt = acpi_find ( FADT_SIGNATURE, 0 );
|
||||
if ( fadt ) {
|
||||
copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
|
||||
dsdt = phys_to_user ( fadtab.dsdt );
|
||||
if ( ( sx = acpi_sx_zsdt ( dsdt, signature ) ) >= 0 )
|
||||
return sx;
|
||||
if ( ( rc = acpi_zsdt ( dsdt, signature, data,
|
||||
extract ) ) == 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try all SSDTs */
|
||||
@ -279,11 +244,12 @@ int acpi_sx ( uint32_t signature ) {
|
||||
ssdt = acpi_find ( SSDT_SIGNATURE, i );
|
||||
if ( ! ssdt )
|
||||
break;
|
||||
if ( ( sx = acpi_sx_zsdt ( ssdt, signature ) ) >= 0 )
|
||||
return sx;
|
||||
if ( ( rc = acpi_zsdt ( ssdt, signature, data,
|
||||
extract ) ) == 0 )
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBGC ( colour, "ACPI could not find \\_Sx \"%s\"\n",
|
||||
DBGC ( colour, "ACPI could not find \"%s\"\n",
|
||||
acpi_name ( signature ) );
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
154
src/core/acpimac.c
Normal file
154
src/core/acpimac.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/acpi.h>
|
||||
#include <ipxe/base16.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/acpimac.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ACPI MAC address
|
||||
*
|
||||
*/
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour FADT_SIGNATURE
|
||||
|
||||
/** AMAC signature */
|
||||
#define AMAC_SIGNATURE ACPI_SIGNATURE ( 'A', 'M', 'A', 'C' )
|
||||
|
||||
/** MACA signature */
|
||||
#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' )
|
||||
|
||||
/** Maximum number of bytes to skip after AMAC/MACA signature
|
||||
*
|
||||
* This is entirely empirical.
|
||||
*/
|
||||
#define AUXMAC_MAX_SKIP 8
|
||||
|
||||
/**
|
||||
* Extract MAC address from DSDT/SSDT
|
||||
*
|
||||
* @v zsdt DSDT or SSDT
|
||||
* @v len Length of DSDT/SSDT
|
||||
* @v offset Offset of signature within DSDT/SSDT
|
||||
* @v data Data buffer
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Some vendors provide a "system MAC address" within the DSDT/SSDT,
|
||||
* to be used to override the MAC address for a USB docking station.
|
||||
*
|
||||
* A full implementation would require an ACPI bytecode interpreter,
|
||||
* since at least one OEM allows the MAC address to be constructed by
|
||||
* executable ACPI bytecode (rather than a fixed data structure).
|
||||
*
|
||||
* We instead attempt to extract a plausible-looking "_AUXMAC_#.....#"
|
||||
* string that appears shortly after an "AMAC" or "MACA" signature.
|
||||
* This should work for most implementations encountered in practice.
|
||||
*/
|
||||
static int acpi_extract_mac ( userptr_t zsdt, size_t len, size_t offset,
|
||||
void *data ) {
|
||||
static const char prefix[9] = "_AUXMAC_#";
|
||||
uint8_t *hw_addr = data;
|
||||
size_t skip = 0;
|
||||
char auxmac[ sizeof ( prefix ) /* "_AUXMAC_#" */ +
|
||||
( ETH_ALEN * 2 ) /* MAC */ + 1 /* "#" */ + 1 /* NUL */ ];
|
||||
char *mac = &auxmac[ sizeof ( prefix ) ];
|
||||
int decoded_len;
|
||||
int rc;
|
||||
|
||||
/* Skip signature and at least one tag byte */
|
||||
offset += ( 4 /* signature */ + 1 /* tag byte */ );
|
||||
|
||||
/* Scan for "_AUXMAC_#.....#" close to signature */
|
||||
for ( skip = 0 ;
|
||||
( ( skip < AUXMAC_MAX_SKIP ) &&
|
||||
( offset + skip + sizeof ( auxmac ) ) < len ) ;
|
||||
skip++ ) {
|
||||
|
||||
/* Read value */
|
||||
copy_from_user ( auxmac, zsdt, ( offset + skip ),
|
||||
sizeof ( auxmac ) );
|
||||
|
||||
/* Check for expected format */
|
||||
if ( memcmp ( auxmac, prefix, sizeof ( prefix ) ) != 0 )
|
||||
continue;
|
||||
if ( auxmac[ sizeof ( auxmac ) - 2 ] != '#' )
|
||||
continue;
|
||||
if ( auxmac[ sizeof ( auxmac ) - 1 ] != '\0' )
|
||||
continue;
|
||||
DBGC ( colour, "ACPI found MAC string \"%s\"\n", auxmac );
|
||||
|
||||
/* Terminate MAC address string */
|
||||
mac = &auxmac[ sizeof ( prefix ) ];
|
||||
mac[ ETH_ALEN * 2 ] = '\0';
|
||||
|
||||
/* Decode MAC address */
|
||||
decoded_len = base16_decode ( mac, hw_addr, ETH_ALEN );
|
||||
if ( decoded_len < 0 ) {
|
||||
rc = decoded_len;
|
||||
DBGC ( colour, "ACPI could not decode MAC \"%s\": %s\n",
|
||||
mac, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check MAC address validity */
|
||||
if ( ! is_valid_ether_addr ( hw_addr ) ) {
|
||||
DBGC ( colour, "ACPI has invalid MAC %s\n",
|
||||
eth_ntoa ( hw_addr ) );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract MAC address from DSDT/SSDT
|
||||
*
|
||||
* @v hw_addr MAC address to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int acpi_mac ( uint8_t *hw_addr ) {
|
||||
int rc;
|
||||
|
||||
/* Look for an "AMAC" address */
|
||||
if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
|
||||
acpi_extract_mac ) ) == 0 )
|
||||
return 0;
|
||||
|
||||
/* Look for a "MACA" address */
|
||||
if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr,
|
||||
acpi_extract_mac ) ) == 0 )
|
||||
return 0;
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
138
src/core/archive.c
Normal file
138
src/core/archive.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 <string.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/image.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Archive images
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extract archive image
|
||||
*
|
||||
* @v image Image
|
||||
* @v name Extracted image name
|
||||
* @v extracted Extracted image to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int image_extract ( struct image *image, const char *name,
|
||||
struct image **extracted ) {
|
||||
char *dot;
|
||||
int rc;
|
||||
|
||||
/* Check that this image can be used to extract an archive image */
|
||||
if ( ! ( image->type && image->type->extract ) ) {
|
||||
rc = -ENOTSUP;
|
||||
goto err_unsupported;
|
||||
}
|
||||
|
||||
/* Allocate new image */
|
||||
*extracted = alloc_image ( image->uri );
|
||||
if ( ! *extracted ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Set image name */
|
||||
if ( ( rc = image_set_name ( *extracted,
|
||||
( name ? name : image->name ) ) ) != 0 ) {
|
||||
goto err_set_name;
|
||||
}
|
||||
|
||||
/* Strip any archive or compression suffix from implicit name */
|
||||
if ( ( ! name ) && ( (*extracted)->name ) &&
|
||||
( ( dot = strrchr ( (*extracted)->name, '.' ) ) != NULL ) ) {
|
||||
*dot = '\0';
|
||||
}
|
||||
|
||||
/* Try extracting archive image */
|
||||
if ( ( rc = image->type->extract ( image, *extracted ) ) != 0 ) {
|
||||
DBGC ( image, "IMAGE %s could not extract image: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
goto err_extract;
|
||||
}
|
||||
|
||||
/* Register image */
|
||||
if ( ( rc = register_image ( *extracted ) ) != 0 )
|
||||
goto err_register;
|
||||
|
||||
/* Propagate trust flag */
|
||||
if ( image->flags & IMAGE_TRUSTED )
|
||||
image_trust ( *extracted );
|
||||
|
||||
/* Drop local reference to image */
|
||||
image_put ( *extracted );
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_image ( *extracted );
|
||||
err_register:
|
||||
err_extract:
|
||||
err_set_name:
|
||||
image_put ( *extracted );
|
||||
err_alloc:
|
||||
err_unsupported:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract and execute image
|
||||
*
|
||||
* @v image Image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int image_extract_exec ( struct image *image ) {
|
||||
struct image *extracted;
|
||||
int rc;
|
||||
|
||||
/* Extract image */
|
||||
if ( ( rc = image_extract ( image, NULL, &extracted ) ) != 0 )
|
||||
goto err_extract;
|
||||
|
||||
/* Set image command line */
|
||||
if ( ( rc = image_set_cmdline ( extracted, image->cmdline ) ) != 0 )
|
||||
goto err_set_cmdline;
|
||||
|
||||
/* Set auto-unregister flag */
|
||||
extracted->flags |= IMAGE_AUTO_UNREGISTER;
|
||||
|
||||
/* Tail-recurse into extracted image */
|
||||
return image_exec ( extracted );
|
||||
|
||||
err_set_cmdline:
|
||||
unregister_image ( extracted );
|
||||
err_extract:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Drag in objects via image_extract() */
|
||||
REQUIRING_SYMBOL ( image_extract );
|
||||
|
||||
/* Drag in archive image formats */
|
||||
REQUIRE_OBJECT ( config_archive );
|
||||
@ -36,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
*/
|
||||
|
||||
static const char base64[64] =
|
||||
static const char base64[ 64 + 1 /* NUL */ ] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/**
|
||||
|
||||
@ -37,29 +37,121 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
*/
|
||||
|
||||
/** A cached DHCP packet */
|
||||
struct cached_dhcp_packet {
|
||||
/** Settings block name */
|
||||
const char *name;
|
||||
/** DHCP packet (if any) */
|
||||
struct dhcp_packet *dhcppkt;
|
||||
};
|
||||
|
||||
/** Cached DHCPACK */
|
||||
static struct dhcp_packet *cached_dhcpack;
|
||||
struct cached_dhcp_packet cached_dhcpack = {
|
||||
.name = DHCP_SETTINGS_NAME,
|
||||
};
|
||||
|
||||
/** Cached ProxyDHCPOFFER */
|
||||
struct cached_dhcp_packet cached_proxydhcp = {
|
||||
.name = PROXYDHCP_SETTINGS_NAME,
|
||||
};
|
||||
|
||||
/** Cached PXEBSACK */
|
||||
struct cached_dhcp_packet cached_pxebs = {
|
||||
.name = PXEBS_SETTINGS_NAME,
|
||||
};
|
||||
|
||||
/** List of cached DHCP packets */
|
||||
static struct cached_dhcp_packet *cached_packets[] = {
|
||||
&cached_dhcpack,
|
||||
&cached_proxydhcp,
|
||||
&cached_pxebs,
|
||||
};
|
||||
|
||||
/** Colour for debug messages */
|
||||
#define colour &cached_dhcpack
|
||||
|
||||
/**
|
||||
* Record cached DHCPACK
|
||||
* Free cached DHCP packet
|
||||
*
|
||||
* @v cache Cached DHCP packet
|
||||
*/
|
||||
static void cachedhcp_free ( struct cached_dhcp_packet *cache ) {
|
||||
|
||||
dhcppkt_put ( cache->dhcppkt );
|
||||
cache->dhcppkt = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply cached DHCP packet settings
|
||||
*
|
||||
* @v cache Cached DHCP packet
|
||||
* @v netdev Network device, or NULL
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
|
||||
struct net_device *netdev ) {
|
||||
struct settings *settings;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if cache is empty */
|
||||
if ( ! cache->dhcppkt )
|
||||
return 0;
|
||||
|
||||
/* Do nothing unless cached packet's MAC address matches this
|
||||
* network device, if specified.
|
||||
*/
|
||||
if ( netdev ) {
|
||||
if ( memcmp ( netdev->ll_addr, cache->dhcppkt->dhcphdr->chaddr,
|
||||
netdev->ll_protocol->ll_addr_len ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP %s does not match %s\n",
|
||||
cache->name, netdev->name );
|
||||
return 0;
|
||||
}
|
||||
DBGC ( colour, "CACHEDHCP %s is for %s\n",
|
||||
cache->name, netdev->name );
|
||||
}
|
||||
|
||||
/* Select appropriate parent settings block */
|
||||
settings = ( netdev ? netdev_settings ( netdev ) : NULL );
|
||||
|
||||
/* Register settings */
|
||||
if ( ( rc = register_settings ( &cache->dhcppkt->settings, settings,
|
||||
cache->name ) ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP %s could not register settings: %s\n",
|
||||
cache->name, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Free cached DHCP packet */
|
||||
cachedhcp_free ( cache );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record cached DHCP packet
|
||||
*
|
||||
* @v cache Cached DHCP packet
|
||||
* @v data DHCPACK packet buffer
|
||||
* @v max_len Maximum possible length
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int cachedhcp_record ( userptr_t data, size_t max_len ) {
|
||||
int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
|
||||
size_t max_len ) {
|
||||
struct dhcp_packet *dhcppkt;
|
||||
struct dhcp_packet *tmp;
|
||||
struct dhcphdr *dhcphdr;
|
||||
unsigned int i;
|
||||
size_t len;
|
||||
|
||||
/* Free any existing cached packet */
|
||||
cachedhcp_free ( cache );
|
||||
|
||||
/* Allocate and populate DHCP packet */
|
||||
dhcppkt = zalloc ( sizeof ( *dhcppkt ) + max_len );
|
||||
if ( ! dhcppkt ) {
|
||||
DBGC ( colour, "CACHEDHCP could not allocate copy\n" );
|
||||
DBGC ( colour, "CACHEDHCP %s could not allocate copy\n",
|
||||
cache->name );
|
||||
return -ENOMEM;
|
||||
}
|
||||
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
|
||||
@ -80,10 +172,26 @@ int cachedhcp_record ( userptr_t data, size_t max_len ) {
|
||||
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
|
||||
dhcppkt_init ( dhcppkt, dhcphdr, len );
|
||||
|
||||
/* Store as cached DHCPACK, and mark original copy as consumed */
|
||||
DBGC ( colour, "CACHEDHCP found cached DHCPACK at %#08lx+%#zx/%#zx\n",
|
||||
/* Discard duplicate packets, since some PXE stacks (including
|
||||
* iPXE itself) will report the DHCPACK packet as the PXEBSACK
|
||||
* if no separate PXEBSACK exists.
|
||||
*/
|
||||
for ( i = 0 ; i < ( sizeof ( cached_packets ) /
|
||||
sizeof ( cached_packets[0] ) ) ; i++ ) {
|
||||
tmp = cached_packets[i]->dhcppkt;
|
||||
if ( tmp && ( dhcppkt_len ( tmp ) == len ) &&
|
||||
( memcmp ( tmp->dhcphdr, dhcppkt->dhcphdr, len ) == 0 ) ) {
|
||||
DBGC ( colour, "CACHEDHCP %s duplicates %s\n",
|
||||
cache->name, cached_packets[i]->name );
|
||||
dhcppkt_put ( dhcppkt );
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store as cached packet */
|
||||
DBGC ( colour, "CACHEDHCP %s at %#08lx+%#zx/%#zx\n", cache->name,
|
||||
user_to_phys ( data, 0 ), len, max_len );
|
||||
cached_dhcpack = dhcppkt;
|
||||
cache->dhcppkt = dhcppkt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -94,14 +202,20 @@ int cachedhcp_record ( userptr_t data, size_t max_len ) {
|
||||
*/
|
||||
static void cachedhcp_startup ( void ) {
|
||||
|
||||
/* If cached DHCP packet was not claimed by any network device
|
||||
* during startup, then free it.
|
||||
*/
|
||||
if ( cached_dhcpack ) {
|
||||
DBGC ( colour, "CACHEDHCP freeing unclaimed cached DHCPACK\n" );
|
||||
dhcppkt_put ( cached_dhcpack );
|
||||
cached_dhcpack = NULL;
|
||||
/* Apply cached ProxyDHCPOFFER, if any */
|
||||
cachedhcp_apply ( &cached_proxydhcp, NULL );
|
||||
|
||||
/* Apply cached PXEBSACK, if any */
|
||||
cachedhcp_apply ( &cached_pxebs, NULL );
|
||||
|
||||
/* Free any remaining cached packets */
|
||||
if ( cached_dhcpack.dhcppkt ) {
|
||||
DBGC ( colour, "CACHEDHCP %s unclaimed\n",
|
||||
cached_dhcpack.name );
|
||||
}
|
||||
cachedhcp_free ( &cached_dhcpack );
|
||||
cachedhcp_free ( &cached_proxydhcp );
|
||||
cachedhcp_free ( &cached_pxebs );
|
||||
}
|
||||
|
||||
/** Cached DHCPACK startup function */
|
||||
@ -117,38 +231,9 @@ struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int cachedhcp_probe ( struct net_device *netdev ) {
|
||||
struct ll_protocol *ll_protocol = netdev->ll_protocol;
|
||||
int rc;
|
||||
|
||||
/* Do nothing unless we have a cached DHCPACK */
|
||||
if ( ! cached_dhcpack )
|
||||
return 0;
|
||||
|
||||
/* Do nothing unless cached DHCPACK's MAC address matches this
|
||||
* network device.
|
||||
*/
|
||||
if ( memcmp ( netdev->ll_addr, cached_dhcpack->dhcphdr->chaddr,
|
||||
ll_protocol->ll_addr_len ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP cached DHCPACK does not match %s\n",
|
||||
netdev->name );
|
||||
return 0;
|
||||
}
|
||||
DBGC ( colour, "CACHEDHCP cached DHCPACK is for %s\n", netdev->name );
|
||||
|
||||
/* Register as DHCP settings for this network device */
|
||||
if ( ( rc = register_settings ( &cached_dhcpack->settings,
|
||||
netdev_settings ( netdev ),
|
||||
DHCP_SETTINGS_NAME ) ) != 0 ) {
|
||||
DBGC ( colour, "CACHEDHCP could not register settings: %s\n",
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Claim cached DHCPACK */
|
||||
dhcppkt_put ( cached_dhcpack );
|
||||
cached_dhcpack = NULL;
|
||||
|
||||
return 0;
|
||||
/* Apply cached DHCPACK to network device, if applicable */
|
||||
return cachedhcp_apply ( &cached_dhcpack, netdev );
|
||||
}
|
||||
|
||||
/** Cached DHCP packet network device driver */
|
||||
|
||||
@ -20,11 +20,12 @@ unsigned int console_height = CONSOLE_DEFAULT_HEIGHT;
|
||||
* Write a single character to each console device
|
||||
*
|
||||
* @v character Character to be written
|
||||
* @ret character Character written
|
||||
*
|
||||
* The character is written out to all enabled console devices, using
|
||||
* each device's console_driver::putchar() method.
|
||||
*/
|
||||
void putchar ( int character ) {
|
||||
int putchar ( int character ) {
|
||||
struct console_driver *console;
|
||||
|
||||
/* Automatic LF -> CR,LF translation */
|
||||
@ -37,6 +38,8 @@ void putchar ( int character ) {
|
||||
console->putchar )
|
||||
console->putchar ( character );
|
||||
}
|
||||
|
||||
return character;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ipxe/cpio.h>
|
||||
|
||||
@ -45,3 +46,87 @@ void cpio_set_field ( char *field, unsigned long value ) {
|
||||
snprintf ( buf, sizeof ( buf ), "%08lx", value );
|
||||
memcpy ( field, buf, 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CPIO image filename
|
||||
*
|
||||
* @v image Image
|
||||
* @ret len CPIO filename length (0 for no filename)
|
||||
*/
|
||||
size_t cpio_name_len ( struct image *image ) {
|
||||
const char *name = cpio_name ( image );
|
||||
char *sep;
|
||||
size_t len;
|
||||
|
||||
/* Check for existence of CPIO filename */
|
||||
if ( ! name )
|
||||
return 0;
|
||||
|
||||
/* Locate separator (if any) */
|
||||
sep = strchr ( name, ' ' );
|
||||
len = ( sep ? ( ( size_t ) ( sep - name ) ) : strlen ( name ) );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse CPIO image parameters
|
||||
*
|
||||
* @v image Image
|
||||
* @v cpio CPIO header to fill in
|
||||
*/
|
||||
static void cpio_parse_cmdline ( struct image *image,
|
||||
struct cpio_header *cpio ) {
|
||||
const char *cmdline;
|
||||
char *arg;
|
||||
char *end;
|
||||
unsigned int mode;
|
||||
|
||||
/* Skip image filename */
|
||||
cmdline = ( cpio_name ( image ) + cpio_name_len ( image ) );
|
||||
|
||||
/* Look for "mode=" */
|
||||
if ( ( arg = strstr ( cmdline, "mode=" ) ) ) {
|
||||
arg += 5;
|
||||
mode = strtoul ( arg, &end, 8 /* Octal for file mode */ );
|
||||
if ( *end && ( *end != ' ' ) ) {
|
||||
DBGC ( image, "CPIO %p strange \"mode=\" "
|
||||
"terminator '%c'\n", image, *end );
|
||||
}
|
||||
cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct CPIO header for image, if applicable
|
||||
*
|
||||
* @v image Image
|
||||
* @v cpio CPIO header to fill in
|
||||
* @ret len Length of magic CPIO header (including filename)
|
||||
*/
|
||||
size_t cpio_header ( struct image *image, struct cpio_header *cpio ) {
|
||||
size_t name_len;
|
||||
size_t len;
|
||||
|
||||
/* Get filename length */
|
||||
name_len = cpio_name_len ( image );
|
||||
|
||||
/* Images with no filename are assumed to already be CPIO archives */
|
||||
if ( ! name_len )
|
||||
return 0;
|
||||
|
||||
/* Construct CPIO header */
|
||||
memset ( cpio, '0', sizeof ( *cpio ) );
|
||||
memcpy ( cpio->c_magic, CPIO_MAGIC, sizeof ( cpio->c_magic ) );
|
||||
cpio_set_field ( cpio->c_mode, 0100644 );
|
||||
cpio_set_field ( cpio->c_nlink, 1 );
|
||||
cpio_set_field ( cpio->c_filesize, image->len );
|
||||
cpio_set_field ( cpio->c_namesize, ( name_len + 1 /* NUL */ ) );
|
||||
cpio_parse_cmdline ( image, cpio );
|
||||
|
||||
/* Calculate total length */
|
||||
len = ( ( sizeof ( *cpio ) + name_len + 1 /* NUL */ + CPIO_ALIGN - 1 )
|
||||
& ~( CPIO_ALIGN - 1 ) );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -175,6 +175,26 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set image length
|
||||
*
|
||||
* @v image Image
|
||||
* @v len Length of image data
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int image_set_len ( struct image *image, size_t len ) {
|
||||
userptr_t new;
|
||||
|
||||
/* (Re)allocate image data */
|
||||
new = urealloc ( image->data, len );
|
||||
if ( ! new )
|
||||
return -ENOMEM;
|
||||
image->data = new;
|
||||
image->len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set image data
|
||||
*
|
||||
@ -184,17 +204,14 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int image_set_data ( struct image *image, userptr_t data, size_t len ) {
|
||||
userptr_t new;
|
||||
int rc;
|
||||
|
||||
/* (Re)allocate image data */
|
||||
new = urealloc ( image->data, len );
|
||||
if ( ! new )
|
||||
return -ENOMEM;
|
||||
image->data = new;
|
||||
/* Set image length */
|
||||
if ( ( rc = image_set_len ( image, len ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Copy in new image data */
|
||||
memcpy_user ( image->data, 0, data, 0, len );
|
||||
image->len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include <ipxe/xfer.h>
|
||||
#include <ipxe/uri.h>
|
||||
@ -47,7 +48,7 @@ struct uri_opener * xfer_uri_opener ( const char *scheme ) {
|
||||
struct uri_opener *opener;
|
||||
|
||||
for_each_table_entry ( opener, URI_OPENERS ) {
|
||||
if ( strcmp ( scheme, opener->scheme ) == 0 )
|
||||
if ( strcasecmp ( scheme, opener->scheme ) == 0 )
|
||||
return opener;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
@ -2199,7 +2199,7 @@ const struct setting_type setting_type_base64 __setting_type = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Format UUID setting value
|
||||
* Format UUID/GUID setting value
|
||||
*
|
||||
* @v type Setting type
|
||||
* @v raw Raw setting value
|
||||
@ -2208,17 +2208,24 @@ const struct setting_type setting_type_base64 __setting_type = {
|
||||
* @v len Length of buffer
|
||||
* @ret len Length of formatted value, or negative error
|
||||
*/
|
||||
static int format_uuid_setting ( const struct setting_type *type __unused,
|
||||
static int format_uuid_setting ( const struct setting_type *type,
|
||||
const void *raw, size_t raw_len, char *buf,
|
||||
size_t len ) {
|
||||
const union uuid *uuid = raw;
|
||||
union uuid uuid;
|
||||
|
||||
/* Range check */
|
||||
if ( raw_len != sizeof ( *uuid ) )
|
||||
if ( raw_len != sizeof ( uuid ) )
|
||||
return -ERANGE;
|
||||
|
||||
/* Copy value */
|
||||
memcpy ( &uuid, raw, sizeof ( uuid ) );
|
||||
|
||||
/* Mangle GUID byte ordering */
|
||||
if ( type == &setting_type_guid )
|
||||
uuid_mangle ( &uuid );
|
||||
|
||||
/* Format value */
|
||||
return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
|
||||
return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
|
||||
}
|
||||
|
||||
/** UUID setting type */
|
||||
@ -2227,6 +2234,12 @@ const struct setting_type setting_type_uuid __setting_type = {
|
||||
.format = format_uuid_setting,
|
||||
};
|
||||
|
||||
/** GUID setting type */
|
||||
const struct setting_type setting_type_guid __setting_type = {
|
||||
.name = "guid",
|
||||
.format = format_uuid_setting,
|
||||
};
|
||||
|
||||
/**
|
||||
* Format PCI bus:dev.fn setting value
|
||||
*
|
||||
|
||||
@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/** @file
|
||||
@ -205,11 +206,24 @@ int strncmp ( const char *first, const char *second, size_t max ) {
|
||||
* @ret diff Difference
|
||||
*/
|
||||
int strcasecmp ( const char *first, const char *second ) {
|
||||
|
||||
return strncasecmp ( first, second, ~( ( size_t ) 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare case-insensitive strings
|
||||
*
|
||||
* @v first First string
|
||||
* @v second Second string
|
||||
* @v max Maximum length to compare
|
||||
* @ret diff Difference
|
||||
*/
|
||||
int strncasecmp ( const char *first, const char *second, size_t max ) {
|
||||
const uint8_t *first_bytes = ( ( const uint8_t * ) first );
|
||||
const uint8_t *second_bytes = ( ( const uint8_t * ) second );
|
||||
int diff;
|
||||
|
||||
for ( ; ; first_bytes++, second_bytes++ ) {
|
||||
for ( ; max-- ; first_bytes++, second_bytes++ ) {
|
||||
diff = ( toupper ( *first_bytes ) -
|
||||
toupper ( *second_bytes ) );
|
||||
if ( diff )
|
||||
@ -217,6 +231,7 @@ int strcasecmp ( const char *first, const char *second ) {
|
||||
if ( ! *first_bytes )
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
144
src/core/uri.c
144
src/core/uri.c
@ -79,12 +79,10 @@ size_t uri_decode ( const char *encoded, void *buf, size_t len ) {
|
||||
/**
|
||||
* Decode URI field in-place
|
||||
*
|
||||
* @v uri URI
|
||||
* @v field URI field index
|
||||
* @v encoded Encoded field, or NULL
|
||||
*/
|
||||
static void uri_decode_inplace ( struct uri *uri, unsigned int field ) {
|
||||
const char *encoded = uri_field ( uri, field );
|
||||
char *decoded = ( ( char * ) encoded );
|
||||
static void uri_decode_inplace ( char *encoded ) {
|
||||
char *decoded = encoded;
|
||||
size_t len;
|
||||
|
||||
/* Do nothing if field is not present */
|
||||
@ -150,7 +148,7 @@ static int uri_character_escaped ( char c, unsigned int field ) {
|
||||
* parser but for any other URI parsers (e.g. HTTP query
|
||||
* string parsers, which care about '=' and '&').
|
||||
*/
|
||||
static const char *escaped[URI_FIELDS] = {
|
||||
static const char *escaped[URI_EPATH] = {
|
||||
/* Scheme or default: escape everything */
|
||||
[URI_SCHEME] = "/#:@?=&",
|
||||
/* Opaque part: escape characters which would affect
|
||||
@ -172,20 +170,21 @@ static int uri_character_escaped ( char c, unsigned int field ) {
|
||||
* appears within paths.
|
||||
*/
|
||||
[URI_PATH] = "#:@?",
|
||||
/* Query: escape everything except '/', which
|
||||
* sometimes appears within queries.
|
||||
*/
|
||||
[URI_QUERY] = "#:@?",
|
||||
/* Fragment: escape everything */
|
||||
[URI_FRAGMENT] = "/#:@?",
|
||||
};
|
||||
|
||||
return ( /* Always escape non-printing characters and whitespace */
|
||||
( ! isprint ( c ) ) || ( c == ' ' ) ||
|
||||
/* Always escape '%' */
|
||||
( c == '%' ) ||
|
||||
/* Escape field-specific characters */
|
||||
strchr ( escaped[field], c ) );
|
||||
/* Always escape non-printing characters and whitespace */
|
||||
if ( ( ! isprint ( c ) ) || ( c == ' ' ) )
|
||||
return 1;
|
||||
|
||||
/* Escape nothing else in already-escaped fields */
|
||||
if ( field >= URI_EPATH )
|
||||
return 0;
|
||||
|
||||
/* Escape '%' and any field-specific characters */
|
||||
if ( ( c == '%' ) || strchr ( escaped[field], c ) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,10 +261,12 @@ static void uri_dump ( const struct uri *uri ) {
|
||||
DBGC ( uri, " port \"%s\"", uri->port );
|
||||
if ( uri->path )
|
||||
DBGC ( uri, " path \"%s\"", uri->path );
|
||||
if ( uri->query )
|
||||
DBGC ( uri, " query \"%s\"", uri->query );
|
||||
if ( uri->fragment )
|
||||
DBGC ( uri, " fragment \"%s\"", uri->fragment );
|
||||
if ( uri->epath )
|
||||
DBGC ( uri, " epath \"%s\"", uri->epath );
|
||||
if ( uri->equery )
|
||||
DBGC ( uri, " equery \"%s\"", uri->equery );
|
||||
if ( uri->efragment )
|
||||
DBGC ( uri, " efragment \"%s\"", uri->efragment );
|
||||
if ( uri->params )
|
||||
DBGC ( uri, " params \"%s\"", uri->params->name );
|
||||
}
|
||||
@ -298,17 +299,19 @@ struct uri * parse_uri ( const char *uri_string ) {
|
||||
char *raw;
|
||||
char *tmp;
|
||||
char *path;
|
||||
char *epath;
|
||||
char *authority;
|
||||
size_t raw_len;
|
||||
unsigned int field;
|
||||
|
||||
/* Allocate space for URI struct and a copy of the string */
|
||||
/* Allocate space for URI struct and two copies of the string */
|
||||
raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
|
||||
uri = zalloc ( sizeof ( *uri ) + raw_len );
|
||||
uri = zalloc ( sizeof ( *uri ) + ( 2 * raw_len ) );
|
||||
if ( ! uri )
|
||||
return NULL;
|
||||
ref_init ( &uri->refcnt, uri_free );
|
||||
raw = ( ( ( void * ) uri ) + sizeof ( *uri ) );
|
||||
path = ( raw + raw_len );
|
||||
|
||||
/* Copy in the raw string */
|
||||
memcpy ( raw, uri_string, raw_len );
|
||||
@ -328,57 +331,62 @@ struct uri * parse_uri ( const char *uri_string ) {
|
||||
/* Chop off the fragment, if it exists */
|
||||
if ( ( tmp = strchr ( raw, '#' ) ) ) {
|
||||
*(tmp++) = '\0';
|
||||
uri->fragment = tmp;
|
||||
uri->efragment = tmp;
|
||||
}
|
||||
|
||||
/* Identify absolute/relative URI */
|
||||
if ( ( tmp = strchr ( raw, ':' ) ) ) {
|
||||
/* Identify absolute URIs */
|
||||
epath = raw;
|
||||
for ( tmp = raw ; ; tmp++ ) {
|
||||
/* Possible scheme character (for our URI schemes) */
|
||||
if ( isalpha ( *tmp ) || ( *tmp == '-' ) || ( *tmp == '_' ) )
|
||||
continue;
|
||||
/* Invalid scheme character or NUL: is a relative URI */
|
||||
if ( *tmp != ':' )
|
||||
break;
|
||||
/* Absolute URI: identify hierarchical/opaque */
|
||||
uri->scheme = raw;
|
||||
*(tmp++) = '\0';
|
||||
if ( *tmp == '/' ) {
|
||||
/* Absolute URI with hierarchical part */
|
||||
path = tmp;
|
||||
epath = tmp;
|
||||
} else {
|
||||
/* Absolute URI with opaque part */
|
||||
uri->opaque = tmp;
|
||||
path = NULL;
|
||||
epath = NULL;
|
||||
}
|
||||
} else {
|
||||
/* Relative URI */
|
||||
path = raw;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we don't have a path (i.e. we have an absolute URI with
|
||||
* an opaque portion, we're already finished processing
|
||||
*/
|
||||
if ( ! path )
|
||||
if ( ! epath )
|
||||
goto done;
|
||||
|
||||
/* Chop off the query, if it exists */
|
||||
if ( ( tmp = strchr ( path, '?' ) ) ) {
|
||||
if ( ( tmp = strchr ( epath, '?' ) ) ) {
|
||||
*(tmp++) = '\0';
|
||||
uri->query = tmp;
|
||||
uri->equery = tmp;
|
||||
}
|
||||
|
||||
/* If we have no path remaining, then we're already finished
|
||||
* processing.
|
||||
*/
|
||||
if ( ! path[0] )
|
||||
if ( ! epath[0] )
|
||||
goto done;
|
||||
|
||||
/* Identify net/absolute/relative path */
|
||||
if ( uri->scheme && ( strncmp ( path, "//", 2 ) == 0 ) ) {
|
||||
if ( uri->scheme && ( strncmp ( epath, "//", 2 ) == 0 ) ) {
|
||||
/* Net path. If this is terminated by the first '/'
|
||||
* of an absolute path, then we have no space for a
|
||||
* terminator after the authority field, so shuffle
|
||||
* the authority down by one byte, overwriting one of
|
||||
* the two slashes.
|
||||
*/
|
||||
authority = ( path + 2 );
|
||||
authority = ( epath + 2 );
|
||||
if ( ( tmp = strchr ( authority, '/' ) ) ) {
|
||||
/* Shuffle down */
|
||||
uri->path = tmp;
|
||||
uri->epath = tmp;
|
||||
memmove ( ( authority - 1 ), authority,
|
||||
( tmp - authority ) );
|
||||
authority--;
|
||||
@ -386,10 +394,16 @@ struct uri * parse_uri ( const char *uri_string ) {
|
||||
}
|
||||
} else {
|
||||
/* Absolute/relative path */
|
||||
uri->path = path;
|
||||
uri->epath = epath;
|
||||
authority = NULL;
|
||||
}
|
||||
|
||||
/* Create copy of path for decoding */
|
||||
if ( uri->epath ) {
|
||||
strcpy ( path, uri->epath );
|
||||
uri->path = path;
|
||||
}
|
||||
|
||||
/* If we don't have an authority (i.e. we have a non-net
|
||||
* path), we're already finished processing
|
||||
*/
|
||||
@ -421,8 +435,8 @@ struct uri * parse_uri ( const char *uri_string ) {
|
||||
|
||||
done:
|
||||
/* Decode fields in-place */
|
||||
for ( field = 0 ; field < URI_FIELDS ; field++ )
|
||||
uri_decode_inplace ( uri, field );
|
||||
for ( field = 0 ; field < URI_EPATH ; field++ )
|
||||
uri_decode_inplace ( ( char * ) uri_field ( uri, field ) );
|
||||
|
||||
DBGC ( uri, "URI parsed \"%s\" to", uri_string );
|
||||
uri_dump ( uri );
|
||||
@ -458,8 +472,8 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
|
||||
static const char prefixes[URI_FIELDS] = {
|
||||
[URI_PASSWORD] = ':',
|
||||
[URI_PORT] = ':',
|
||||
[URI_QUERY] = '?',
|
||||
[URI_FRAGMENT] = '#',
|
||||
[URI_EQUERY] = '?',
|
||||
[URI_EFRAGMENT] = '#',
|
||||
};
|
||||
char prefix;
|
||||
size_t used = 0;
|
||||
@ -480,6 +494,10 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
|
||||
if ( ! uri_field ( uri, field ) )
|
||||
continue;
|
||||
|
||||
/* Skip path field if encoded path is present */
|
||||
if ( ( field == URI_PATH ) && uri->epath )
|
||||
continue;
|
||||
|
||||
/* Prefix this field, if applicable */
|
||||
prefix = prefixes[field];
|
||||
if ( ( field == URI_HOST ) && ( uri->user != NULL ) )
|
||||
@ -676,6 +694,7 @@ char * resolve_path ( const char *base_path,
|
||||
struct uri * resolve_uri ( const struct uri *base_uri,
|
||||
struct uri *relative_uri ) {
|
||||
struct uri tmp_uri;
|
||||
char *tmp_epath = NULL;
|
||||
char *tmp_path = NULL;
|
||||
struct uri *new_uri;
|
||||
|
||||
@ -685,20 +704,27 @@ struct uri * resolve_uri ( const struct uri *base_uri,
|
||||
|
||||
/* Mangle URI */
|
||||
memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
|
||||
if ( relative_uri->path ) {
|
||||
tmp_path = resolve_path ( ( base_uri->path ?
|
||||
base_uri->path : "/" ),
|
||||
relative_uri->path );
|
||||
if ( relative_uri->epath ) {
|
||||
tmp_epath = resolve_path ( ( base_uri->epath ?
|
||||
base_uri->epath : "/" ),
|
||||
relative_uri->epath );
|
||||
if ( ! tmp_epath )
|
||||
goto err_epath;
|
||||
tmp_path = strdup ( tmp_epath );
|
||||
if ( ! tmp_path )
|
||||
goto err_path;
|
||||
uri_decode_inplace ( tmp_path );
|
||||
tmp_uri.epath = tmp_epath;
|
||||
tmp_uri.path = tmp_path;
|
||||
tmp_uri.query = relative_uri->query;
|
||||
tmp_uri.fragment = relative_uri->fragment;
|
||||
tmp_uri.equery = relative_uri->equery;
|
||||
tmp_uri.efragment = relative_uri->efragment;
|
||||
tmp_uri.params = relative_uri->params;
|
||||
} else if ( relative_uri->query ) {
|
||||
tmp_uri.query = relative_uri->query;
|
||||
tmp_uri.fragment = relative_uri->fragment;
|
||||
} else if ( relative_uri->equery ) {
|
||||
tmp_uri.equery = relative_uri->equery;
|
||||
tmp_uri.efragment = relative_uri->efragment;
|
||||
tmp_uri.params = relative_uri->params;
|
||||
} else if ( relative_uri->fragment ) {
|
||||
tmp_uri.fragment = relative_uri->fragment;
|
||||
} else if ( relative_uri->efragment ) {
|
||||
tmp_uri.efragment = relative_uri->efragment;
|
||||
tmp_uri.params = relative_uri->params;
|
||||
} else if ( relative_uri->params ) {
|
||||
tmp_uri.params = relative_uri->params;
|
||||
@ -707,7 +733,14 @@ struct uri * resolve_uri ( const struct uri *base_uri,
|
||||
/* Create demangled URI */
|
||||
new_uri = uri_dup ( &tmp_uri );
|
||||
free ( tmp_path );
|
||||
free ( tmp_epath );
|
||||
return new_uri;
|
||||
|
||||
free ( tmp_path );
|
||||
err_path:
|
||||
free ( tmp_epath );
|
||||
err_epath:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -746,6 +779,7 @@ static struct uri * tftp_uri ( struct sockaddr *sa_server,
|
||||
if ( asprintf ( &path, "/%s", filename ) < 0 )
|
||||
goto err_path;
|
||||
tmp.path = path;
|
||||
tmp.epath = path;
|
||||
|
||||
/* Demangle URI */
|
||||
uri = uri_dup ( &tmp );
|
||||
|
||||
@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <wchar.h>
|
||||
#include <ipxe/features.h>
|
||||
#include <ipxe/version.h>
|
||||
#include <ipxe/sbat.h>
|
||||
#include <config/general.h>
|
||||
#include <config/branding.h>
|
||||
|
||||
@ -92,3 +93,32 @@ const wchar_t build_wname[] = WSTRING ( BUILD_NAME );
|
||||
/** Copy of build name string within ".prefix" */
|
||||
const char build_name_prefix[] __attribute__ (( section ( ".prefix.name" ) ))
|
||||
= BUILD_NAME;
|
||||
|
||||
/** SBAT upstream iPXE line
|
||||
*
|
||||
* This line represents the security generation of the upstream
|
||||
* codebase from which this build is derived.
|
||||
*/
|
||||
#define SBAT_IPXE \
|
||||
SBAT_LINE ( "ipxe", IPXE_SBAT_GENERATION, \
|
||||
"iPXE", BUILD_NAME, VERSION, "https://ipxe.org" )
|
||||
|
||||
/** SBAT local build line
|
||||
*
|
||||
* This line states the security generation of the local build, which
|
||||
* may include non-default features or non-upstreamed modifications.
|
||||
*/
|
||||
#if PRODUCT_SBAT_GENERATION
|
||||
#define SBAT_PRODUCT \
|
||||
SBAT_LINE ( "ipxe." PRODUCT_SBAT_NAME, PRODUCT_SBAT_GENERATION, \
|
||||
PRODUCT_SHORT_NAME, BUILD_NAME, VERSION, \
|
||||
PRODUCT_URI )
|
||||
#else
|
||||
#define SBAT_PRODUCT ""
|
||||
#endif
|
||||
|
||||
/** SBAT data */
|
||||
#define SBAT_DATA SBAT_HEADER "" SBAT_IPXE "" SBAT_PRODUCT
|
||||
|
||||
/** SBAT data (without any NUL terminator) */
|
||||
const char sbat[ sizeof ( SBAT_DATA ) - 1 ] __sbat = SBAT_DATA;
|
||||
|
||||
@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/list.h>
|
||||
@ -1464,7 +1465,7 @@ static int x509_check_dnsname ( struct x509_certificate *cert,
|
||||
|
||||
/* Compare names */
|
||||
if ( ! ( ( strlen ( name ) == len ) &&
|
||||
( memcmp ( name, dnsname, len ) == 0 ) ) )
|
||||
( strncasecmp ( name, dnsname, len ) == 0 ) ) )
|
||||
return -ENOENT;
|
||||
|
||||
if ( name != fullname ) {
|
||||
|
||||
@ -17,37 +17,47 @@
|
||||
#include "ipxe/io.h"
|
||||
#include "ipxe/iomap.h"
|
||||
#include "ipxe/pci.h"
|
||||
#include "ipxe/dma.h"
|
||||
#include "ipxe/reboot.h"
|
||||
#include "ipxe/virtio-pci.h"
|
||||
#include "ipxe/virtio-ring.h"
|
||||
|
||||
static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num)
|
||||
static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num, size_t header_size)
|
||||
{
|
||||
size_t queue_size = PAGE_MASK + vring_size(num);
|
||||
size_t ring_size = PAGE_MASK + vring_size(num);
|
||||
size_t vdata_size = num * sizeof(void *);
|
||||
size_t queue_size = ring_size + vdata_size + header_size;
|
||||
|
||||
vq->queue = zalloc(queue_size + vdata_size);
|
||||
vq->queue = dma_alloc(vq->dma, &vq->map, queue_size, queue_size);
|
||||
if (!vq->queue) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset ( vq->queue, 0, queue_size );
|
||||
vq->queue_size = queue_size;
|
||||
|
||||
/* vdata immediately follows the ring */
|
||||
vq->vdata = (void **)(vq->queue + queue_size);
|
||||
vq->vdata = (void **)(vq->queue + ring_size);
|
||||
|
||||
/* empty header immediately follows vdata */
|
||||
vq->empty_header = (struct virtio_net_hdr_modern *)(vq->queue + ring_size + vdata_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vp_free_vq(struct vring_virtqueue *vq)
|
||||
{
|
||||
if (vq->queue) {
|
||||
free(vq->queue);
|
||||
if (vq->queue && vq->queue_size) {
|
||||
dma_free(&vq->map, vq->queue, vq->queue_size);
|
||||
vq->queue = NULL;
|
||||
vq->vdata = NULL;
|
||||
vq->queue_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int vp_find_vq(unsigned int ioaddr, int queue_index,
|
||||
struct vring_virtqueue *vq)
|
||||
struct vring_virtqueue *vq, struct dma_device *dma_dev,
|
||||
size_t header_size)
|
||||
{
|
||||
struct vring * vr = &vq->vring;
|
||||
u16 num;
|
||||
@ -73,9 +83,10 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
|
||||
}
|
||||
|
||||
vq->queue_index = queue_index;
|
||||
vq->dma = dma_dev;
|
||||
|
||||
/* initialize the queue */
|
||||
rc = vp_alloc_vq(vq, num);
|
||||
rc = vp_alloc_vq(vq, num, header_size);
|
||||
if (rc) {
|
||||
DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n");
|
||||
return rc;
|
||||
@ -87,8 +98,7 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
|
||||
* NOTE: vr->desc is initialized by vring_init()
|
||||
*/
|
||||
|
||||
outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
|
||||
ioaddr + VIRTIO_PCI_QUEUE_PFN);
|
||||
outl(dma(&vq->map, vr->desc) >> PAGE_SHIFT, ioaddr + VIRTIO_PCI_QUEUE_PFN);
|
||||
|
||||
return num;
|
||||
}
|
||||
@ -348,7 +358,8 @@ void vpm_notify(struct virtio_pci_modern_device *vdev,
|
||||
}
|
||||
|
||||
int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
|
||||
unsigned nvqs, struct vring_virtqueue *vqs)
|
||||
unsigned nvqs, struct vring_virtqueue *vqs,
|
||||
struct dma_device *dma_dev, size_t header_size)
|
||||
{
|
||||
unsigned i;
|
||||
struct vring_virtqueue *vq;
|
||||
@ -392,11 +403,12 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
|
||||
|
||||
vq = &vqs[i];
|
||||
vq->queue_index = i;
|
||||
vq->dma = dma_dev;
|
||||
|
||||
/* get offset of notification word for this vq */
|
||||
off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off));
|
||||
|
||||
err = vp_alloc_vq(vq, size);
|
||||
err = vp_alloc_vq(vq, size, header_size);
|
||||
if (err) {
|
||||
DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev);
|
||||
return err;
|
||||
@ -406,13 +418,16 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
|
||||
/* activate the queue */
|
||||
vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size));
|
||||
|
||||
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.desc),
|
||||
vpm_iowrite64(vdev, &vdev->common,
|
||||
dma(&vq->map, vq->vring.desc),
|
||||
COMMON_OFFSET(queue_desc_lo),
|
||||
COMMON_OFFSET(queue_desc_hi));
|
||||
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.avail),
|
||||
vpm_iowrite64(vdev, &vdev->common,
|
||||
dma(&vq->map, vq->vring.avail),
|
||||
COMMON_OFFSET(queue_avail_lo),
|
||||
COMMON_OFFSET(queue_avail_hi));
|
||||
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.used),
|
||||
vpm_iowrite64(vdev, &vdev->common,
|
||||
dma(&vq->map, vq->vring.used),
|
||||
COMMON_OFFSET(queue_used_lo),
|
||||
COMMON_OFFSET(queue_used_hi));
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
|
||||
for (i = head; out; i = vr->desc[i].next, out--) {
|
||||
|
||||
vr->desc[i].flags = VRING_DESC_F_NEXT;
|
||||
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
|
||||
vr->desc[i].addr = list->addr;
|
||||
vr->desc[i].len = list->length;
|
||||
prev = i;
|
||||
list++;
|
||||
@ -106,7 +106,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
|
||||
for ( ; in; i = vr->desc[i].next, in--) {
|
||||
|
||||
vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
|
||||
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
|
||||
vr->desc[i].addr = list->addr;
|
||||
vr->desc[i].len = list->length;
|
||||
prev = i;
|
||||
list++;
|
||||
|
||||
@ -39,6 +39,9 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
|
||||
{
|
||||
u32 status, timeout;
|
||||
|
||||
/* Avoid returning uninitialised data on error */
|
||||
*data = 0xffff;
|
||||
|
||||
/*
|
||||
* Initialize EEPROM access
|
||||
*/
|
||||
|
||||
@ -23,16 +23,74 @@ static void bnxt_adv_cq_index ( struct bnxt *bp, u16 cnt );
|
||||
static int bnxt_rx_complete ( struct net_device *dev, struct rx_pkt_cmpl *rx );
|
||||
void bnxt_link_evt ( struct bnxt *bp, struct hwrm_async_event_cmpl *evt );
|
||||
|
||||
static struct pci_device_id bnxt_nics[] = {
|
||||
PCI_ROM( 0x14e4, 0x16c0, "14e4-16C0", "14e4-16C0", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16c1, "14e4-16C1", "14e4-16C1", BNXT_FLAG_PCI_VF ),
|
||||
PCI_ROM( 0x14e4, 0x16c8, "14e4-16C8", "14e4-16C8", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16c9, "14e4-16C9", "14e4-16C9", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16ca, "14e4-16CA", "14e4-16CA", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16cc, "14e4-16CC", "14e4-16CC", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16cd, "14e4-16CD", "14e4-16CD", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16ce, "14e4-16CE", "14e4-16CE", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16cf, "14e4-16CF", "14e4-16CF", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d0, "14e4-16D0", "14e4-16D0", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d1, "14e4-16D1", "14e4-16D1", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d2, "14e4-16D2", "14e4-16D2", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d4, "14e4-16D4", "14e4-16D4", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d5, "14e4-16D5", "14e4-16D5", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d6, "14e4-16D6", "14e4-16D6", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d7, "14e4-16D7", "14e4-16D7", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d8, "14e4-16D8", "14e4-16D8", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16d9, "14e4-16D9", "14e4-16D9", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16da, "14e4-16DA", "14e4-16DA", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16db, "14e4-16DB", "14e4-16DB", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16dc, "14e4-16DC", "14e4-16DC", BNXT_FLAG_PCI_VF ),
|
||||
PCI_ROM( 0x14e4, 0x16de, "14e4-16DE", "14e4-16DE", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16df, "14e4-16DF", "14e4-16DF", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16e0, "14e4-16E0", "14e4-16E0", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16e2, "14e4-16E2", "14e4-16E2", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16e3, "14e4-16E3", "14e4-16E3", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16e4, "14e4-16E4", "14e4-16E4", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16e7, "14e4-16E7", "14e4-16E7", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16e8, "14e4-16E8", "14e4-16E8", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16e9, "14e4-16E9", "14e4-16E9", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16ea, "14e4-16EA", "14e4-16EA", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16eb, "14e4-16EB", "14e4-16EB", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16ec, "14e4-16EC", "14e4-16EC", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16ed, "14e4-16ED", "14e4-16ED", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16ee, "14e4-16EE", "14e4-16EE", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16ef, "14e4-16EF", "14e4-16EF", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16f0, "14e4-16F0", "14e4-16F0", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x16f1, "14e4-16F1", "14e4-16F1", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1604, "14e4-1604", "14e4-1604", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1605, "14e4-1605", "14e4-1605", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1606, "14e4-1606", "14e4-1606", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1609, "14e4-1609", "14e4-1609", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1614, "14e4-1614", "14e4-1614", 0 ),
|
||||
PCI_ROM( 0x14e4, 0xd802, "14e4-D802", "14e4-D802", 0 ),
|
||||
PCI_ROM( 0x14e4, 0xd804, "14e4-D804", "14e4-D804", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1750, "14e4-1750", "14e4-1750", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1802, "14e4-1802", "14e4-1802", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1805, "14e4-1805", "14e4-1805", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1751, "14e4-1751", "14e4-1751", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1801, "14e4-1801", "14e4-1801", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1804, "14e4-1804", "14e4-1804", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1752, "14e4-1752", "14e4-1752", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1800, "14e4-1800", "14e4-1800", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1803, "14e4-1803", "14e4-1803", 0 ),
|
||||
PCI_ROM( 0x14e4, 0x1806, "14e4-1806", "14e4-1806", BNXT_FLAG_PCI_VF ),
|
||||
PCI_ROM( 0x14e4, 0x1807, "14e4-1807", "14e4-1807", BNXT_FLAG_PCI_VF ),
|
||||
PCI_ROM( 0x14e4, 0x1808, "14e4-1808", "14e4-1808", BNXT_FLAG_PCI_VF ),
|
||||
PCI_ROM( 0x14e4, 0x1809, "14e4-1809", "14e4-1809", BNXT_FLAG_PCI_VF ),
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if Virtual Function
|
||||
*/
|
||||
u8 bnxt_is_pci_vf ( struct pci_device *pdev )
|
||||
{
|
||||
u16 i;
|
||||
|
||||
for ( i = 0; i < ARRAY_SIZE ( bnxt_vf_nics ); i++ ) {
|
||||
if ( pdev->device == bnxt_vf_nics[i] )
|
||||
return 1;
|
||||
if ( FLAG_TEST ( pdev->id->driver_data, BNXT_FLAG_PCI_VF ) ) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -51,6 +51,7 @@ union dma_addr64_t {
|
||||
#define BNXT_FLAG_MULTI_HOST 0x0008
|
||||
#define BNXT_FLAG_NPAR_MODE 0x0010
|
||||
#define BNXT_FLAG_ATOMICS_ENABLE 0x0020
|
||||
#define BNXT_FLAG_PCI_VF 0x0040
|
||||
/*******************************************************************************
|
||||
* Status codes.
|
||||
******************************************************************************/
|
||||
@ -867,140 +868,4 @@ struct bnxt {
|
||||
FUNC_VF_CFG_REQ_ENABLES_ASYNC_EVENT_CR | \
|
||||
FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR)
|
||||
|
||||
/* Device ID's */
|
||||
#define PCI_VID_BCOM 0x14e4
|
||||
#define CHIP_NUM_57500 0x1750
|
||||
|
||||
#define DID_57508 0x1750
|
||||
#define DID_57508_MF 0x1802
|
||||
#define DID_57508_MF_RDMA 0x1805
|
||||
#define DID_57504 0x1751
|
||||
#define DID_57504_MF 0x1801
|
||||
#define DID_57504_MF_RDMA 0x1804
|
||||
#define DID_57502 0x1752
|
||||
#define DID_57502_MF 0x1800
|
||||
#define DID_57502_MF_RDMA 0x1803
|
||||
#define DID_57508_VF 0x1806
|
||||
#define DID_57508_VF_RDMA 0x1807
|
||||
#define DID_57508_VF_HV 0x1806
|
||||
#define DID_57508_VF_RDMA_HV 0x1807
|
||||
/* Stratus Device IDs */
|
||||
#define DID_57320_1 0x16F0
|
||||
#define DID_57320_2 0x16F1
|
||||
#define DID_57454_MHB 0x1604
|
||||
#define DID_57454_MHB_RDMA 0x1605
|
||||
#define DID_57454_VF_RDMA 0x1606
|
||||
#define DID_57454_VF 0x1609
|
||||
#define DID_57454 0x1614
|
||||
#define DID_58802 0xD802
|
||||
#define DID_58804 0xD804
|
||||
|
||||
#define DID_57417_RDMA_MF 0x16C0
|
||||
#define DID_57417_VF_RDMA 0x16c1
|
||||
#define DID_57301 0x16C8
|
||||
#define DID_57302 0x16C9
|
||||
#define DID_57304 0x16CA
|
||||
#define DID_57417_MF 0x16CC
|
||||
#define DID_58700 0x16CD
|
||||
#define DID_57311 0x16CE
|
||||
#define DID_57312 0x16CF
|
||||
#define DID_57402 0x16D0
|
||||
#define DID_57404 0x16D1
|
||||
#define DID_57406 0x16D2
|
||||
#define DID_57402_MF 0x16D4
|
||||
#define DID_57407C 0x16D5
|
||||
#define DID_57412 0x16D6
|
||||
#define DID_57414 0x16D7
|
||||
#define DID_57416C 0x16D8
|
||||
#define DID_57417C 0x16D9
|
||||
#define DID_57402L 0x16DA
|
||||
#define DID_57404L 0x16DB
|
||||
#define DID_57417_VF 0x16dc
|
||||
#define DID_57412_MF 0x16DE
|
||||
#define DID_57314 0x16DF
|
||||
#define DID_57317C 0x16E0
|
||||
#define DID_57417F 0x16E2
|
||||
#define DID_57416F 0x16E3
|
||||
#define DID_57317F 0x16E4
|
||||
#define DID_57404_MF 0x16E7
|
||||
#define DID_57406_MF 0x16E8
|
||||
#define DID_57407F 0x16E9
|
||||
#define DID_57407_MF 0x16EA
|
||||
#define DID_57412_RDMA_MF 0x16EB
|
||||
#define DID_57414_MF 0x16EC
|
||||
#define DID_57414_RDMA_MF 0x16ED
|
||||
#define DID_57416_MF 0x16EE
|
||||
#define DID_57416_RDMA_MF 0x16EF
|
||||
|
||||
static struct pci_device_id bnxt_nics[] = {
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57417_RDMA_MF, "14e4-16C0", "14e4-16C0", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57417_VF_RDMA, "14e4-16C1", "14e4-16C1", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57301, "14e4-16C8", "14e4-16C8", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57302, "14e4-16C9", "14e4-16C9", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57304, "14e4-16CA", "14e4-16CA", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57417_MF, "14e4-16CC", "14e4-16CC", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_58700, "14e4-16CD", "14e4-16CD", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57311, "14e4-16CE", "14e4-16CE", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57312, "14e4-16CF", "14e4-16CF", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57402, "14e4-16D0", "14e4-16D0", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57404, "14e4-16D1", "14e4-16D1", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57406, "14e4-16D2", "14e4-16D2", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57402_MF, "14e4-16D4", "14e4-16D4", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57407C, "14e4-16D5", "14e4-16D5", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57412, "14e4-16D6", "14e4-16D6", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57414, "14e4-16D7", "14e4-16D7", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57416C, "14e4-16D8", "14e4-16D8", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57417C, "14e4-16D9", "14e4-16D9", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57402L, "14e4-16DA", "14e4-16DA", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57404L, "14e4-16DB", "14e4-16DB", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57417_VF, "14e4-16DC", "14e4-16DC", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57412_MF, "14e4-16DE", "14e4-16DE", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57314, "14e4-16DF", "14e4-16DF", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57317C, "14e4-16E0", "14e4-16E0", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57417F, "14e4-16E2", "14e4-16E2", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57416F, "14e4-16E3", "14e4-16E3", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57317F, "14e4-16E4", "14e4-16E4", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57404_MF, "14e4-16E7", "14e4-16E7", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57406_MF, "14e4-16E8", "14e4-16E8", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57407F, "14e4-16E9", "14e4-16E9", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57407_MF, "14e4-16EA", "14e4-16EA", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57412_RDMA_MF, "14e4-16EB", "14e4-16EB", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57414_MF, "14e4-16EC", "14e4-16EC", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57414_RDMA_MF, "14e4-16ED", "14e4-16ED", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57416_MF, "14e4-16EE", "14e4-16EE", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57416_RDMA_MF, "14e4-16EF", "14e4-16EF", 0),
|
||||
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57320_1, "14e4-16F0", "14e4-16F0", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57320_2, "14e4-16F1", "14e4-16F1", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57454_MHB, "14e4-1604", "14e4-1604", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57454_MHB_RDMA, "14e4-1605", "14e4-1605", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57454_VF_RDMA, "14e4-1606", "14e4-1606", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57454_VF, "14e4-1609", "14e4-1609", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57454, "14e4-1614", "14e4-1614", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_58802, "14e4-D802", "14e4-D802", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_58804, "14e4-D804", "14e4-D804", 0),
|
||||
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57508, "14e4-1750", "14e4-1750", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57508_MF, "14e4-1802", "14e4-1802", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57508_MF_RDMA, "14e4-1805", "14e4-1805", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57504, "14e4-1751", "14e4-1751", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57504_MF, "14e4-1801", "14e4-1801", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57504_MF_RDMA, "14e4-1804", "14e4-1804", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57502, "14e4-1752", "14e4-1752", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57502_MF, "14e4-1800", "14e4-1800", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57502_MF_RDMA, "14e4-1803", "14e4-1803", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57508_VF, "14e4-1806", "14e4-1806", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57508_VF_RDMA, "14e4-1807", "14e4-1807", 0),
|
||||
PCI_ROM(PCI_VID_BCOM, DID_57508_VF_HV, "14e4-1808", "14e4-1808", 0),
|
||||
PCI_ROM(PCI_VID_BCOM,
|
||||
DID_57508_VF_RDMA_HV, "14e4-1809", "14e4-1809", 0),
|
||||
};
|
||||
|
||||
static u16 bnxt_vf_nics[] = {
|
||||
DID_57508_VF,
|
||||
DID_57508_VF_RDMA,
|
||||
DID_57508_VF_HV,
|
||||
DID_57508_VF_RDMA_HV,
|
||||
DID_57417_VF,
|
||||
DID_57417_VF_RDMA,
|
||||
};
|
||||
|
||||
@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/base16.h>
|
||||
#include <ipxe/profile.h>
|
||||
#include <ipxe/acpimac.h>
|
||||
#include <ipxe/usb.h>
|
||||
#include "ecm.h"
|
||||
|
||||
@ -81,17 +82,26 @@ ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
|
||||
/**
|
||||
* Get hardware MAC address
|
||||
*
|
||||
* @v usb USB device
|
||||
* @v func USB function
|
||||
* @v desc Ethernet functional descriptor
|
||||
* @v hw_addr Hardware address to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int ecm_fetch_mac ( struct usb_device *usb,
|
||||
int ecm_fetch_mac ( struct usb_function *func,
|
||||
struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
|
||||
struct usb_device *usb = func->usb;
|
||||
char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Use system-specific MAC address, if present and not already used */
|
||||
if ( ( ( rc = acpi_mac ( hw_addr ) ) == 0 ) &&
|
||||
! find_netdev_by_ll_addr ( ðernet_protocol, hw_addr ) ) {
|
||||
DBGC ( usb, "USB %s using system-specific MAC %s\n",
|
||||
func->name, eth_ntoa ( hw_addr ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Fetch MAC address string */
|
||||
len = usb_get_string_descriptor ( usb, desc->mac, 0, buf,
|
||||
sizeof ( buf ) );
|
||||
@ -103,7 +113,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
|
||||
/* Sanity check */
|
||||
if ( len != ( ( int ) ( sizeof ( buf ) - 1 /* NUL */ ) ) ) {
|
||||
DBGC ( usb, "USB %s has invalid ECM MAC \"%s\"\n",
|
||||
usb->name, buf );
|
||||
func->name, buf );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -112,7 +122,7 @@ int ecm_fetch_mac ( struct usb_device *usb,
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( usb, "USB %s could not decode ECM MAC \"%s\": %s\n",
|
||||
usb->name, buf, strerror ( rc ) );
|
||||
func->name, buf, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -464,7 +474,7 @@ static int ecm_probe ( struct usb_function *func,
|
||||
}
|
||||
|
||||
/* Fetch MAC address */
|
||||
if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
|
||||
if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
|
||||
DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
|
||||
ecm, strerror ( rc ) );
|
||||
goto err_fetch_mac;
|
||||
|
||||
@ -86,7 +86,7 @@ struct ecm_device {
|
||||
extern struct ecm_ethernet_descriptor *
|
||||
ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
|
||||
struct usb_interface_descriptor *interface );
|
||||
extern int ecm_fetch_mac ( struct usb_device *usb,
|
||||
extern int ecm_fetch_mac ( struct usb_function *func,
|
||||
struct ecm_ethernet_descriptor *desc,
|
||||
uint8_t *hw_addr );
|
||||
|
||||
|
||||
@ -576,7 +576,7 @@ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb,
|
||||
cdb.IFnum = nii->nii->IfNum;
|
||||
|
||||
/* Raise task priority level */
|
||||
tpl = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
tpl = bs->RaiseTPL ( efi_internal_tpl );
|
||||
|
||||
/* Issue command */
|
||||
DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n",
|
||||
|
||||
@ -164,6 +164,10 @@ static int snpnet_transmit ( struct net_device *netdev,
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if shutdown is in progress */
|
||||
if ( efi_shutdown_in_progress )
|
||||
return -ECANCELED;
|
||||
|
||||
/* Defer the packet if there is already a transmission in progress */
|
||||
if ( snp->txbuf ) {
|
||||
netdev_tx_defer ( netdev, iobuf );
|
||||
@ -283,6 +287,10 @@ static void snpnet_poll_rx ( struct net_device *netdev ) {
|
||||
*/
|
||||
static void snpnet_poll ( struct net_device *netdev ) {
|
||||
|
||||
/* Do nothing if shutdown is in progress */
|
||||
if ( efi_shutdown_in_progress )
|
||||
return;
|
||||
|
||||
/* Process any TX completions */
|
||||
snpnet_poll_tx ( netdev );
|
||||
|
||||
@ -426,8 +434,9 @@ static void snpnet_close ( struct net_device *netdev ) {
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Shut down NIC */
|
||||
if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) {
|
||||
/* Shut down NIC (unless whole system shutdown is in progress) */
|
||||
if ( ( ! efi_shutdown_in_progress ) &&
|
||||
( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( snp, "SNP %s could not shut down: %s\n",
|
||||
netdev->name, strerror ( rc ) );
|
||||
@ -589,8 +598,9 @@ void snpnet_stop ( struct efi_device *efidev ) {
|
||||
/* Unregister network device */
|
||||
unregister_netdev ( netdev );
|
||||
|
||||
/* Stop SNP protocol */
|
||||
if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) {
|
||||
/* Stop SNP protocol (unless whole system shutdown is in progress) */
|
||||
if ( ( ! efi_shutdown_in_progress ) &&
|
||||
( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "SNP %s could not stop: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
|
||||
@ -1025,6 +1025,12 @@ static struct pci_device_id intel_nics[] = {
|
||||
PCI_ROM ( 0x8086, 0x043a, "dh8900cc-f", "DH8900CC Fiber", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x043c, "dh8900cc-b", "DH8900CC Backplane", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x0440, "dh8900cc-s", "DH8900CC SFP", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x0d4c, "i219lm-11", "I219-LM (11)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x0d4d, "i219v-11", "I219-V (11)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x0d4e, "i219lm-10", "I219-LM (10)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x0d4f, "i219v-10", "I219-V (10)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x0d53, "i219lm-12", "I219-LM (12)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x0d55, "i219v-12", "I219-V (12)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x1000, "82542-f", "82542 (Fiber)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1001, "82543gc-f", "82543GC (Fiber)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1004, "82543gc", "82543GC (Copper)", 0 ),
|
||||
@ -1161,6 +1167,12 @@ static struct pci_device_id intel_nics[] = {
|
||||
PCI_ROM ( 0x8086, 0x15e1, "i219lm-9", "I219-LM (9)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15e2, "i219v-9", "I219-V (9)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15e3, "i219lm-5", "I219-LM (5)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15f4, "i219lm-15", "I219-LM (15)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15f5, "i219v-15", "I219-V (15)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15f9, "i219lm-14", "I219-LM (14)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15fa, "i219v-14", "I219-V (14)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15fb, "i219lm-13", "I219-LM (13)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x15fc, "i219v-13", "I219-V (13)", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x1f41, "i354", "I354", INTEL_NO_ASDE ),
|
||||
PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ),
|
||||
|
||||
@ -481,6 +481,7 @@ static struct pci_device_id intelx_nics[] = {
|
||||
PCI_ROM ( 0x8086, 0x15ab, "x552", "X552", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15c8, "x553t", "X553/X557-AT", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15ce, "x553-sfp", "X553 (SFP+)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15e4, "x553a", "X553", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15e5, "x553", "X553", 0 ),
|
||||
};
|
||||
|
||||
|
||||
@ -598,7 +598,7 @@ static int ncm_probe ( struct usb_function *func,
|
||||
}
|
||||
|
||||
/* Fetch MAC address */
|
||||
if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
|
||||
if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev->hw_addr ) ) != 0 ) {
|
||||
DBGC ( ncm, "NCM %p could not fetch MAC address: %s\n",
|
||||
ncm, strerror ( rc ) );
|
||||
goto err_fetch_mac;
|
||||
|
||||
694
src/drivers/net/rdc.c
Normal file
694
src/drivers/net/rdc.c
Normal file
@ -0,0 +1,694 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/malloc.h>
|
||||
#include <ipxe/pci.h>
|
||||
#include "rdc.h"
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RDC R6040 network driver
|
||||
*
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Device reset
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Reset hardware
|
||||
*
|
||||
* @v rdc RDC device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_reset ( struct rdc_nic *rdc ) {
|
||||
unsigned int i;
|
||||
|
||||
/* Reset NIC */
|
||||
writew ( RDC_MCR1_RST, rdc->regs + RDC_MCR1 );
|
||||
|
||||
/* Wait for reset to complete */
|
||||
for ( i = 0 ; i < RDC_RESET_MAX_WAIT_MS ; i++ ) {
|
||||
|
||||
/* Check for reset completion */
|
||||
if ( readw ( rdc->regs + RDC_MCR1 ) & RDC_MCR1_RST ) {
|
||||
mdelay ( 1 );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Reset internal state machine */
|
||||
writew ( RDC_MACSM_RST, rdc->regs + RDC_MACSM );
|
||||
writew ( 0, rdc->regs + RDC_MACSM );
|
||||
mdelay ( RDC_MACSM_RESET_DELAY_MS );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBGC ( rdc, "RDC %p timed out waiting for reset\n", rdc );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* MII interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Read from MII register
|
||||
*
|
||||
* @v mdio MII interface
|
||||
* @v phy PHY address
|
||||
* @v reg Register address
|
||||
* @ret value Data read, or negative error
|
||||
*/
|
||||
static int rdc_mii_read ( struct mii_interface *mdio, unsigned int phy,
|
||||
unsigned int reg ) {
|
||||
struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
|
||||
uint16_t mmdio;
|
||||
unsigned int i;
|
||||
|
||||
/* Initiate read */
|
||||
mmdio = ( RDC_MMDIO_MIIRD | RDC_MMDIO_PHYAD ( phy ) |
|
||||
RDC_MMDIO_REGAD ( reg ) );
|
||||
writew ( mmdio, rdc->regs + RDC_MMDIO );
|
||||
|
||||
/* Wait for read to complete */
|
||||
for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
|
||||
|
||||
/* Check for read completion */
|
||||
if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIRD ) {
|
||||
udelay ( 1 );
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Return register value */
|
||||
return ( readw ( rdc->regs + RDC_MMRD ) );
|
||||
}
|
||||
|
||||
DBGC ( rdc, "RDC %p timed out waiting for MII read\n", rdc );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to MII register
|
||||
*
|
||||
* @v mdio MII interface
|
||||
* @v phy PHY address
|
||||
* @v reg Register address
|
||||
* @v data Data to write
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_mii_write ( struct mii_interface *mdio, unsigned int phy,
|
||||
unsigned int reg, unsigned int data ) {
|
||||
struct rdc_nic *rdc = container_of ( mdio, struct rdc_nic, mdio );
|
||||
uint16_t mmdio;
|
||||
unsigned int i;
|
||||
|
||||
/* Initiate write */
|
||||
mmdio = ( RDC_MMDIO_MIIWR | RDC_MMDIO_PHYAD ( phy ) |
|
||||
RDC_MMDIO_REGAD ( reg ) );
|
||||
writew ( data, rdc->regs + RDC_MMWD );
|
||||
writew ( mmdio, rdc->regs + RDC_MMDIO );
|
||||
|
||||
/* Wait for write to complete */
|
||||
for ( i = 0 ; i < RDC_MII_MAX_WAIT_US ; i++ ) {
|
||||
|
||||
/* Check for write completion */
|
||||
if ( readw ( rdc->regs + RDC_MMDIO ) & RDC_MMDIO_MIIWR ) {
|
||||
udelay ( 1 );
|
||||
continue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBGC ( rdc, "RDC %p timed out waiting for MII write\n", rdc );
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/** RDC MII operations */
|
||||
static struct mii_operations rdc_mii_operations = {
|
||||
.read = rdc_mii_read,
|
||||
.write = rdc_mii_write,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Link state
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialise PHY
|
||||
*
|
||||
* @v rdc RDC device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_init_phy ( struct rdc_nic *rdc ) {
|
||||
int rc;
|
||||
|
||||
/* Find PHY address */
|
||||
if ( ( rc = mii_find ( &rdc->mii ) ) != 0 ) {
|
||||
DBGC ( rdc, "RDC %p could not find PHY address: %s\n",
|
||||
rdc, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Reset PHY */
|
||||
if ( ( rc = mii_reset ( &rdc->mii ) ) != 0 ) {
|
||||
DBGC ( rdc, "RDC %p could not reset PHY: %s\n",
|
||||
rdc, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check link state
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_check_link ( struct net_device *netdev ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
int rc;
|
||||
|
||||
/* Check link state */
|
||||
if ( ( rc = mii_check_link ( &rdc->mii, netdev ) ) != 0 ) {
|
||||
DBGC ( rdc, "RDC %p could not check link: %s\n",
|
||||
rdc, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Network device interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create descriptor ring
|
||||
*
|
||||
* @v rdc RDC device
|
||||
* @v ring Descriptor ring
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_create_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
|
||||
size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
|
||||
struct rdc_descriptor *desc;
|
||||
struct rdc_descriptor *next;
|
||||
physaddr_t start;
|
||||
unsigned int i;
|
||||
|
||||
/* Allocate descriptor ring */
|
||||
ring->desc = dma_alloc ( rdc->dma, &ring->map, len, len );
|
||||
if ( ! ring->desc )
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialise descriptor ring */
|
||||
memset ( ring->desc, 0, len );
|
||||
for ( i = 0 ; i < ring->count ; i++ ) {
|
||||
desc = &ring->desc[i];
|
||||
next = &ring->desc[ ( i + 1 ) & ( ring->count - 1 ) ];
|
||||
desc->next = cpu_to_le32 ( dma ( &ring->map, next ) );
|
||||
}
|
||||
|
||||
/* Program ring address */
|
||||
start = dma ( &ring->map, ring->desc );
|
||||
writew ( ( start >> 0 ), ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
|
||||
writew ( ( start >> 16 ), ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
|
||||
|
||||
DBGC ( rdc, "RDC %p ring %#02x is at [%08lx,%08lx)\n",
|
||||
rdc, ring->reg, virt_to_phys ( ring->desc ),
|
||||
( virt_to_phys ( ring->desc ) + len ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy descriptor ring
|
||||
*
|
||||
* @v rdc RDC device
|
||||
* @v ring Descriptor ring
|
||||
*/
|
||||
static void rdc_destroy_ring ( struct rdc_nic *rdc, struct rdc_ring *ring ) {
|
||||
size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
|
||||
|
||||
/* Clear ring address */
|
||||
writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_LO ) );
|
||||
writew ( 0, ( rdc->regs + ring->reg + RDC_MxDSA_HI ) );
|
||||
|
||||
/* Free descriptors */
|
||||
dma_free ( &ring->map, ring->desc, len );
|
||||
ring->desc = NULL;
|
||||
|
||||
/* Reset ring */
|
||||
ring->prod = 0;
|
||||
ring->cons = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refill receive descriptor ring
|
||||
*
|
||||
* @v rdc RDC device
|
||||
*/
|
||||
static void rdc_refill_rx ( struct rdc_nic *rdc ) {
|
||||
struct rdc_descriptor *rx;
|
||||
struct io_buffer *iobuf;
|
||||
unsigned int rx_idx;
|
||||
|
||||
/* Refill ring */
|
||||
while ( ( rdc->rx.prod - rdc->rx.cons ) < RDC_NUM_RX_DESC ) {
|
||||
|
||||
/* Allocate I/O buffer */
|
||||
iobuf = alloc_rx_iob ( RDC_RX_MAX_LEN, rdc->dma );
|
||||
if ( ! iobuf ) {
|
||||
/* Wait for next refill */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get next receive descriptor */
|
||||
rx_idx = ( rdc->rx.prod++ % RDC_NUM_RX_DESC );
|
||||
rx = &rdc->rx.desc[rx_idx];
|
||||
|
||||
/* Populate receive descriptor */
|
||||
rx->len = cpu_to_le16 ( RDC_RX_MAX_LEN );
|
||||
rx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
|
||||
wmb();
|
||||
rx->flags = cpu_to_le16 ( RDC_FL_OWNED );
|
||||
|
||||
/* Record I/O buffer */
|
||||
assert ( rdc->rx_iobuf[rx_idx] == NULL );
|
||||
rdc->rx_iobuf[rx_idx] = iobuf;
|
||||
|
||||
DBGC2 ( rdc, "RDC %p RX %d is [%lx,%lx)\n",
|
||||
rdc, rx_idx, virt_to_phys ( iobuf->data ),
|
||||
( virt_to_phys ( iobuf->data ) + RDC_RX_MAX_LEN ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_open ( struct net_device *netdev ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
int rc;
|
||||
|
||||
/* Create transmit descriptor ring */
|
||||
if ( ( rc = rdc_create_ring ( rdc, &rdc->tx ) ) != 0 )
|
||||
goto err_create_tx;
|
||||
|
||||
/* Create receive descriptor ring */
|
||||
if ( ( rc = rdc_create_ring ( rdc, &rdc->rx ) ) != 0 )
|
||||
goto err_create_rx;
|
||||
|
||||
/* Program receive buffer length */
|
||||
writew ( RDC_RX_MAX_LEN, rdc->regs + RDC_MRBSR );
|
||||
|
||||
/* Enable transmit and receive */
|
||||
writew ( ( RDC_MCR0_FD | RDC_MCR0_TXEN | RDC_MCR0_PROMISC |
|
||||
RDC_MCR0_RXEN ),
|
||||
rdc->regs + RDC_MCR0 );
|
||||
|
||||
/* Enable PHY status polling */
|
||||
writew ( ( RDC_MPSCCR_EN | RDC_MPSCCR_PHYAD ( rdc->mii.address ) |
|
||||
RDC_MPSCCR_SLOW ),
|
||||
rdc->regs + RDC_MPSCCR );
|
||||
|
||||
/* Fill receive ring */
|
||||
rdc_refill_rx ( rdc );
|
||||
|
||||
/* Update link state */
|
||||
rdc_check_link ( netdev );
|
||||
|
||||
return 0;
|
||||
|
||||
rdc_destroy_ring ( rdc, &rdc->rx );
|
||||
err_create_rx:
|
||||
rdc_destroy_ring ( rdc, &rdc->tx );
|
||||
err_create_tx:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close network device
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void rdc_close ( struct net_device *netdev ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
unsigned int i;
|
||||
|
||||
/* Disable NIC */
|
||||
writew ( 0, rdc->regs + RDC_MCR0 );
|
||||
|
||||
/* Destroy receive descriptor ring */
|
||||
rdc_destroy_ring ( rdc, &rdc->rx );
|
||||
|
||||
/* Discard any unused receive buffers */
|
||||
for ( i = 0 ; i < RDC_NUM_RX_DESC ; i++ ) {
|
||||
if ( rdc->rx_iobuf[i] )
|
||||
free_rx_iob ( rdc->rx_iobuf[i] );
|
||||
rdc->rx_iobuf[i] = NULL;
|
||||
}
|
||||
|
||||
/* Destroy transmit descriptor ring */
|
||||
rdc_destroy_ring ( rdc, &rdc->tx );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transmit packet
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v iobuf I/O buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
struct rdc_descriptor *tx;
|
||||
unsigned int tx_idx;
|
||||
int rc;
|
||||
|
||||
/* Get next transmit descriptor */
|
||||
if ( ( rdc->tx.prod - rdc->tx.cons ) >= RDC_NUM_TX_DESC ) {
|
||||
DBGC ( rdc, "RDC %p out of transmit descriptors\n", rdc );
|
||||
return -ENOBUFS;
|
||||
}
|
||||
tx_idx = ( rdc->tx.prod % RDC_NUM_TX_DESC );
|
||||
tx = &rdc->tx.desc[tx_idx];
|
||||
|
||||
/* Pad to minimum length */
|
||||
iob_pad ( iobuf, ETH_ZLEN );
|
||||
|
||||
/* Map I/O buffer */
|
||||
if ( ( rc = iob_map_tx ( iobuf, rdc->dma ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Update producer index */
|
||||
rdc->tx.prod++;
|
||||
|
||||
/* Populate transmit descriptor */
|
||||
tx->len = cpu_to_le16 ( iob_len ( iobuf ) );
|
||||
tx->addr = cpu_to_le32 ( iob_dma ( iobuf ) );
|
||||
wmb();
|
||||
tx->flags = cpu_to_le16 ( RDC_FL_OWNED );
|
||||
wmb();
|
||||
|
||||
/* Notify card that there are packets ready to transmit */
|
||||
writew ( RDC_MTPR_TM2TX, rdc->regs + RDC_MTPR );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for completed packets
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void rdc_poll_tx ( struct net_device *netdev ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
struct rdc_descriptor *tx;
|
||||
unsigned int tx_idx;
|
||||
|
||||
/* Check for completed packets */
|
||||
while ( rdc->tx.cons != rdc->tx.prod ) {
|
||||
|
||||
/* Get next transmit descriptor */
|
||||
tx_idx = ( rdc->tx.cons % RDC_NUM_TX_DESC );
|
||||
tx = &rdc->tx.desc[tx_idx];
|
||||
|
||||
/* Stop if descriptor is still in use */
|
||||
if ( tx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
|
||||
return;
|
||||
DBGC2 ( rdc, "RDC %p TX %d complete\n", rdc, tx_idx );
|
||||
|
||||
/* Complete transmit descriptor */
|
||||
rdc->tx.cons++;
|
||||
netdev_tx_complete_next ( netdev );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for received packets
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void rdc_poll_rx ( struct net_device *netdev ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
struct rdc_descriptor *rx;
|
||||
struct io_buffer *iobuf;
|
||||
unsigned int rx_idx;
|
||||
size_t len;
|
||||
|
||||
/* Check for received packets */
|
||||
while ( rdc->rx.cons != rdc->rx.prod ) {
|
||||
|
||||
/* Get next receive descriptor */
|
||||
rx_idx = ( rdc->rx.cons % RDC_NUM_RX_DESC );
|
||||
rx = &rdc->rx.desc[rx_idx];
|
||||
|
||||
/* Stop if descriptor is still in use */
|
||||
if ( rx->flags & cpu_to_le16 ( RDC_FL_OWNED ) )
|
||||
return;
|
||||
|
||||
/* Populate I/O buffer */
|
||||
iobuf = rdc->rx_iobuf[rx_idx];
|
||||
rdc->rx_iobuf[rx_idx] = NULL;
|
||||
len = le16_to_cpu ( rx->len );
|
||||
iob_put ( iobuf, len );
|
||||
iob_unput ( iobuf, 4 /* strip CRC */ );
|
||||
|
||||
/* Hand off to network stack */
|
||||
if ( rx->flags & cpu_to_le16 ( RDC_FL_OK ) ) {
|
||||
DBGC2 ( rdc, "RDC %p RX %d complete (length %zd)\n",
|
||||
rdc, rx_idx, len );
|
||||
netdev_rx ( netdev, iobuf );
|
||||
} else {
|
||||
DBGC2 ( rdc, "RDC %p RX %d error (length %zd, "
|
||||
"flags %#04x)\n", rdc, rx_idx, len,
|
||||
le16_to_cpu ( rx->flags ) );
|
||||
netdev_rx_err ( netdev, iobuf, -EIO );
|
||||
}
|
||||
rdc->rx.cons++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for completed and received packets
|
||||
*
|
||||
* @v netdev Network device
|
||||
*/
|
||||
static void rdc_poll ( struct net_device *netdev ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
uint16_t misr;
|
||||
|
||||
/* Check for (and acknowledge) interrupts */
|
||||
misr = readw ( rdc->regs + RDC_MISR );
|
||||
|
||||
/* Poll for TX completions, if applicable */
|
||||
if ( misr & RDC_MIRQ_TX )
|
||||
rdc_poll_tx ( netdev );
|
||||
|
||||
/* Poll for RX completions, if applicable */
|
||||
if ( misr & RDC_MIRQ_RX )
|
||||
rdc_poll_rx ( netdev );
|
||||
|
||||
/* Check link state, if applicable */
|
||||
if ( misr & RDC_MIRQ_LINK )
|
||||
rdc_check_link ( netdev );
|
||||
|
||||
/* Check for unexpected interrupts */
|
||||
if ( misr & ~( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX_EARLY |
|
||||
RDC_MIRQ_RX_EMPTY | RDC_MIRQ_RX ) ) {
|
||||
DBGC ( rdc, "RDC %p unexpected MISR %#04x\n", rdc, misr );
|
||||
/* Report as a TX error */
|
||||
netdev_tx_err ( netdev, NULL, -ENOTSUP );
|
||||
}
|
||||
|
||||
/* Refill receive ring */
|
||||
rdc_refill_rx ( rdc );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable interrupts
|
||||
*
|
||||
* @v netdev Network device
|
||||
* @v enable Interrupts should be enabled
|
||||
*/
|
||||
static void rdc_irq ( struct net_device *netdev, int enable ) {
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
uint16_t mier;
|
||||
|
||||
/* Enable/disable interrupts */
|
||||
mier = ( enable ? ( RDC_MIRQ_LINK | RDC_MIRQ_TX | RDC_MIRQ_RX ) : 0 );
|
||||
writew ( mier, rdc->regs + RDC_MIER );
|
||||
}
|
||||
|
||||
/** RDC network device operations */
|
||||
static struct net_device_operations rdc_operations = {
|
||||
.open = rdc_open,
|
||||
.close = rdc_close,
|
||||
.transmit = rdc_transmit,
|
||||
.poll = rdc_poll,
|
||||
.irq = rdc_irq,
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* PCI interface
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Probe PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int rdc_probe ( struct pci_device *pci ) {
|
||||
struct net_device *netdev;
|
||||
struct rdc_nic *rdc;
|
||||
union rdc_mac mac;
|
||||
int rc;
|
||||
|
||||
/* Allocate and initialise net device */
|
||||
netdev = alloc_etherdev ( sizeof ( *rdc ) );
|
||||
if ( ! netdev ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
netdev_init ( netdev, &rdc_operations );
|
||||
rdc = netdev->priv;
|
||||
pci_set_drvdata ( pci, netdev );
|
||||
netdev->dev = &pci->dev;
|
||||
memset ( rdc, 0, sizeof ( *rdc ) );
|
||||
rdc->dma = &pci->dma;
|
||||
mdio_init ( &rdc->mdio, &rdc_mii_operations );
|
||||
mii_init ( &rdc->mii, &rdc->mdio, 0 );
|
||||
rdc_init_ring ( &rdc->tx, RDC_NUM_TX_DESC, RDC_MTDSA );
|
||||
rdc_init_ring ( &rdc->rx, RDC_NUM_RX_DESC, RDC_MRDSA );
|
||||
|
||||
/* Fix up PCI device */
|
||||
adjust_pci_device ( pci );
|
||||
|
||||
/* Map registers */
|
||||
rdc->regs = pci_ioremap ( pci, pci->membase, RDC_BAR_SIZE );
|
||||
if ( ! rdc->regs ) {
|
||||
rc = -ENODEV;
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
/* Fetch MAC address */
|
||||
mac.mid[0] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID0 ) );
|
||||
mac.mid[1] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID1 ) );
|
||||
mac.mid[2] = cpu_to_le16 ( readw ( rdc->regs + RDC_MID2 ) );
|
||||
memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
|
||||
|
||||
/* Reset the NIC */
|
||||
if ( ( rc = rdc_reset ( rdc ) ) != 0 )
|
||||
goto err_reset;
|
||||
|
||||
/* Initialise PHY */
|
||||
if ( ( rc = rdc_init_phy ( rdc ) ) != 0 )
|
||||
goto err_init_phy;
|
||||
|
||||
/* Register network device */
|
||||
if ( ( rc = register_netdev ( netdev ) ) != 0 )
|
||||
goto err_register_netdev;
|
||||
|
||||
/* Set initial link state */
|
||||
rdc_check_link ( netdev );
|
||||
|
||||
return 0;
|
||||
|
||||
unregister_netdev ( netdev );
|
||||
err_register_netdev:
|
||||
err_init_phy:
|
||||
rdc_reset ( rdc );
|
||||
err_reset:
|
||||
iounmap ( rdc->regs );
|
||||
err_ioremap:
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PCI device
|
||||
*
|
||||
* @v pci PCI device
|
||||
*/
|
||||
static void rdc_remove ( struct pci_device *pci ) {
|
||||
struct net_device *netdev = pci_get_drvdata ( pci );
|
||||
struct rdc_nic *rdc = netdev->priv;
|
||||
|
||||
/* Unregister network device */
|
||||
unregister_netdev ( netdev );
|
||||
|
||||
/* Reset card */
|
||||
rdc_reset ( rdc );
|
||||
|
||||
/* Free network device */
|
||||
iounmap ( rdc->regs );
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
}
|
||||
|
||||
/** RDC PCI device IDs */
|
||||
static struct pci_device_id rdc_nics[] = {
|
||||
PCI_ROM ( 0x17f3, 0x6040, "r6040", "RDC R6040", 0 ),
|
||||
};
|
||||
|
||||
/** RDC PCI driver */
|
||||
struct pci_driver rdc_driver __pci_driver = {
|
||||
.ids = rdc_nics,
|
||||
.id_count = ( sizeof ( rdc_nics ) / sizeof ( rdc_nics[0] ) ),
|
||||
.probe = rdc_probe,
|
||||
.remove = rdc_remove,
|
||||
};
|
||||
194
src/drivers/net/rdc.h
Normal file
194
src/drivers/net/rdc.h
Normal file
@ -0,0 +1,194 @@
|
||||
#ifndef _RDC_H
|
||||
#define _RDC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* RDC R6040 network driver
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/mii.h>
|
||||
|
||||
/** RDC BAR size */
|
||||
#define RDC_BAR_SIZE 256
|
||||
|
||||
/** An RDC descriptor */
|
||||
struct rdc_descriptor {
|
||||
/** Flags */
|
||||
uint16_t flags;
|
||||
/** Length */
|
||||
uint16_t len;
|
||||
/** Address */
|
||||
uint32_t addr;
|
||||
/** Next descriptor */
|
||||
uint32_t next;
|
||||
/** Reserved */
|
||||
uint32_t reserved;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Descriptor is owned by NIC */
|
||||
#define RDC_FL_OWNED 0x8000
|
||||
|
||||
/** Packet OK */
|
||||
#define RDC_FL_OK 0x4000
|
||||
|
||||
/** MAC control register 0 */
|
||||
#define RDC_MCR0 0x00
|
||||
#define RDC_MCR0_FD 0x8000 /**< Full duplex */
|
||||
#define RDC_MCR0_TXEN 0x1000 /**< Transmit enable */
|
||||
#define RDC_MCR0_PROMISC 0x0020 /**< Promiscuous mode */
|
||||
#define RDC_MCR0_RXEN 0x0002 /**< Receive enable */
|
||||
|
||||
/** MAC control register 1 */
|
||||
#define RDC_MCR1 0x04
|
||||
#define RDC_MCR1_RST 0x0001 /**< MAC reset */
|
||||
|
||||
/** Maximum time to wait for reset */
|
||||
#define RDC_RESET_MAX_WAIT_MS 10
|
||||
|
||||
/** MAC transmit poll command register */
|
||||
#define RDC_MTPR 0x14
|
||||
#define RDC_MTPR_TM2TX 0x0001 /**< Trigger MAC to transmit */
|
||||
|
||||
/** MAC receive buffer size register */
|
||||
#define RDC_MRBSR 0x18
|
||||
|
||||
/** MAC MDIO control register */
|
||||
#define RDC_MMDIO 0x20
|
||||
#define RDC_MMDIO_MIIWR 0x4000 /**< MDIO write */
|
||||
#define RDC_MMDIO_MIIRD 0x2000 /**< MDIO read */
|
||||
#define RDC_MMDIO_PHYAD(x) ( (x) << 8 ) /**< PHY address */
|
||||
#define RDC_MMDIO_REGAD(x) ( (x) << 0 ) /**< Register address */
|
||||
|
||||
/** Maximum time to wait for an MII read or write */
|
||||
#define RDC_MII_MAX_WAIT_US 2048
|
||||
|
||||
/** MAC MDIO read data register */
|
||||
#define RDC_MMRD 0x24
|
||||
|
||||
/** MAC MDIO write data register */
|
||||
#define RDC_MMWD 0x28
|
||||
|
||||
/** MAC transmit descriptor start address */
|
||||
#define RDC_MTDSA 0x2c
|
||||
|
||||
/** MAC receive descriptor start address */
|
||||
#define RDC_MRDSA 0x34
|
||||
|
||||
/** MAC descriptor start address low half */
|
||||
#define RDC_MxDSA_LO 0x0
|
||||
|
||||
/** MAC descriptor start address low half */
|
||||
#define RDC_MxDSA_HI 0x4
|
||||
|
||||
/** MAC interrupt status register */
|
||||
#define RDC_MISR 0x3c
|
||||
#define RDC_MIRQ_LINK 0x0200 /**< Link status changed */
|
||||
#define RDC_MIRQ_TX 0x0010 /**< Transmit complete */
|
||||
#define RDC_MIRQ_RX_EARLY 0x0008 /**< Receive early interrupt */
|
||||
#define RDC_MIRQ_RX_EMPTY 0x0002 /**< Receive descriptor unavailable */
|
||||
#define RDC_MIRQ_RX 0x0001 /**< Receive complete */
|
||||
|
||||
/** MAC interrupt enable register */
|
||||
#define RDC_MIER 0x40
|
||||
|
||||
/** MAC address word 0 */
|
||||
#define RDC_MID0 0x68
|
||||
|
||||
/** MAC address word 1 */
|
||||
#define RDC_MID1 0x6a
|
||||
|
||||
/** MAC address word 2 */
|
||||
#define RDC_MID2 0x6c
|
||||
|
||||
/** MAC PHY status change configuration register */
|
||||
#define RDC_MPSCCR 0x88
|
||||
#define RDC_MPSCCR_EN 0x8000 /**< PHY status change enable */
|
||||
#define RDC_MPSCCR_PHYAD(x) ( (x) << 8 ) /**< PHY address */
|
||||
#define RDC_MPSCCR_SLOW 0x0007 /**< Poll slowly */
|
||||
|
||||
/** MAC state machine register */
|
||||
#define RDC_MACSM 0xac
|
||||
#define RDC_MACSM_RST 0x0002 /**< Reset state machine */
|
||||
|
||||
/** Time to wait after resetting MAC state machine */
|
||||
#define RDC_MACSM_RESET_DELAY_MS 10
|
||||
|
||||
/** A MAC address */
|
||||
union rdc_mac {
|
||||
/** Raw bytes */
|
||||
uint8_t raw[ETH_ALEN];
|
||||
/** MIDx registers */
|
||||
uint16_t mid[ ETH_ALEN / 2 ];
|
||||
};
|
||||
|
||||
/** A descriptor ring */
|
||||
struct rdc_ring {
|
||||
/** Descriptors */
|
||||
struct rdc_descriptor *desc;
|
||||
/** Descriptor ring DMA mapping */
|
||||
struct dma_mapping map;
|
||||
/** Producer index */
|
||||
unsigned int prod;
|
||||
/** Consumer index */
|
||||
unsigned int cons;
|
||||
|
||||
/** Number of descriptors */
|
||||
unsigned int count;
|
||||
/** Start address register 0 */
|
||||
unsigned int reg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise descriptor ring
|
||||
*
|
||||
* @v ring Descriptor ring
|
||||
* @v count Number of descriptors
|
||||
* @v reg Start address register 0
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) void
|
||||
rdc_init_ring ( struct rdc_ring *ring, unsigned int count, unsigned int reg ) {
|
||||
|
||||
ring->count = count;
|
||||
ring->reg = reg;
|
||||
}
|
||||
|
||||
/** Number of transmit descriptors
|
||||
*
|
||||
* This is a policy decision.
|
||||
*/
|
||||
#define RDC_NUM_TX_DESC 16
|
||||
|
||||
/** Number of receive descriptors
|
||||
*
|
||||
* This is a policy decision.
|
||||
*/
|
||||
#define RDC_NUM_RX_DESC 8
|
||||
|
||||
/** Receive buffer length */
|
||||
#define RDC_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
|
||||
|
||||
/** An RDC network card */
|
||||
struct rdc_nic {
|
||||
/** Registers */
|
||||
void *regs;
|
||||
/** DMA device */
|
||||
struct dma_device *dma;
|
||||
/** MII interface */
|
||||
struct mii_interface mdio;
|
||||
/** MII device */
|
||||
struct mii_device mii;
|
||||
|
||||
/** Transmit descriptor ring */
|
||||
struct rdc_ring tx;
|
||||
/** Receive descriptor ring */
|
||||
struct rdc_ring rx;
|
||||
/** Receive I/O buffers */
|
||||
struct io_buffer *rx_iobuf[RDC_NUM_RX_DESC];
|
||||
};
|
||||
|
||||
#endif /* _RDC_H */
|
||||
@ -420,6 +420,16 @@ static int realtek_phy_reset ( struct realtek_nic *rtl ) {
|
||||
*/
|
||||
}
|
||||
|
||||
/* Some cards (e.g. RTL8211B) have a hardware errata that
|
||||
* requires the MII_MMD_DATA register to be cleared before the
|
||||
* link will come up.
|
||||
*/
|
||||
if ( ( rc = mii_write ( &rtl->mii, MII_MMD_DATA, 0 ) ) != 0 ) {
|
||||
/* Ignore failures, since the register may not be
|
||||
* present on all PHYs.
|
||||
*/
|
||||
}
|
||||
|
||||
/* Restart autonegotiation */
|
||||
if ( ( rc = mii_restart ( &rtl->mii ) ) != 0 ) {
|
||||
DBGC ( rtl, "REALTEK %p could not restart MII: %s\n",
|
||||
|
||||
@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <ipxe/iobuf.h>
|
||||
#include <ipxe/netdevice.h>
|
||||
#include <ipxe/pci.h>
|
||||
#include <ipxe/dma.h>
|
||||
#include <ipxe/if_ether.h>
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/virtio-pci.h>
|
||||
@ -99,8 +100,9 @@ struct virtnet_nic {
|
||||
/** Pending rx packet count */
|
||||
unsigned int rx_num_iobufs;
|
||||
|
||||
/** Virtio net dummy packet headers */
|
||||
struct virtio_net_hdr_modern empty_header[QUEUE_NB];
|
||||
/** DMA device */
|
||||
struct dma_device *dma;
|
||||
|
||||
};
|
||||
|
||||
/** Add an iobuf to a virtqueue
|
||||
@ -115,7 +117,7 @@ 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];
|
||||
struct virtio_net_hdr_modern *header = vq->empty_header;
|
||||
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 ?
|
||||
@ -132,11 +134,11 @@ static void virtnet_enqueue_iob ( struct net_device *netdev,
|
||||
* to header->flags for received packets. Work around
|
||||
* this by using separate RX and TX headers.
|
||||
*/
|
||||
.addr = ( char* ) header,
|
||||
.addr = dma ( &vq->map, header ),
|
||||
.length = header_len,
|
||||
},
|
||||
{
|
||||
.addr = ( char* ) iobuf->data,
|
||||
.addr = iob_dma ( iobuf ),
|
||||
.length = iob_len ( iobuf ),
|
||||
},
|
||||
};
|
||||
@ -161,7 +163,7 @@ static void virtnet_refill_rx_virtqueue ( struct net_device *netdev ) {
|
||||
struct io_buffer *iobuf;
|
||||
|
||||
/* Try to allocate a buffer, stop for now if out of memory */
|
||||
iobuf = alloc_iob ( len );
|
||||
iobuf = alloc_rx_iob ( len, virtnet->dma );
|
||||
if ( ! iobuf )
|
||||
break;
|
||||
|
||||
@ -215,7 +217,8 @@ static int virtnet_open_legacy ( struct net_device *netdev ) {
|
||||
|
||||
/* Initialize rx/tx virtqueues */
|
||||
for ( i = 0; i < QUEUE_NB; i++ ) {
|
||||
if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i] ) == -1 ) {
|
||||
if ( vp_find_vq ( ioaddr, i, &virtnet->virtqueue[i], virtnet->dma,
|
||||
sizeof ( struct virtio_net_hdr_modern ) ) == -1 ) {
|
||||
DBGC ( virtnet, "VIRTIO-NET %p cannot register queue %d\n",
|
||||
virtnet, i );
|
||||
virtnet_free_virtqueues ( netdev );
|
||||
@ -280,7 +283,8 @@ static int virtnet_open_modern ( struct net_device *netdev ) {
|
||||
}
|
||||
|
||||
/* Initialize rx/tx virtqueues */
|
||||
if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue ) ) {
|
||||
if ( vpm_find_vqs ( &virtnet->vdev, QUEUE_NB, virtnet->virtqueue,
|
||||
virtnet->dma, sizeof ( struct virtio_net_hdr_modern ) ) ) {
|
||||
DBGC ( virtnet, "VIRTIO-NET %p cannot register queues\n",
|
||||
virtnet );
|
||||
virtnet_free_virtqueues ( netdev );
|
||||
@ -335,7 +339,7 @@ static void virtnet_close ( struct net_device *netdev ) {
|
||||
|
||||
/* Free rx iobufs */
|
||||
list_for_each_entry_safe ( iobuf, next_iobuf, &virtnet->rx_iobufs, list ) {
|
||||
free_iob ( iobuf );
|
||||
free_rx_iob ( iobuf );
|
||||
}
|
||||
INIT_LIST_HEAD ( &virtnet->rx_iobufs );
|
||||
virtnet->rx_num_iobufs = 0;
|
||||
@ -478,6 +482,12 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
|
||||
|
||||
/* Enable PCI bus master and reset NIC */
|
||||
adjust_pci_device ( pci );
|
||||
|
||||
/* Configure DMA */
|
||||
virtnet->dma = &pci->dma;
|
||||
dma_set_mask_64bit ( virtnet->dma );
|
||||
netdev->dma = virtnet->dma;
|
||||
|
||||
vp_reset ( ioaddr );
|
||||
|
||||
/* Load MAC address and MTU */
|
||||
@ -506,7 +516,7 @@ static int virtnet_probe_legacy ( struct pci_device *pci ) {
|
||||
return 0;
|
||||
|
||||
unregister_netdev ( netdev );
|
||||
err_register_netdev:
|
||||
err_register_netdev:
|
||||
vp_reset ( ioaddr );
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
@ -586,6 +596,11 @@ static int virtnet_probe_modern ( struct pci_device *pci, int *found_dev ) {
|
||||
/* Enable the PCI device */
|
||||
adjust_pci_device ( pci );
|
||||
|
||||
/* Configure DMA */
|
||||
virtnet->dma = &pci->dma;
|
||||
dma_set_mask_64bit ( virtnet->dma );
|
||||
netdev->dma = virtnet->dma;
|
||||
|
||||
/* Reset the device and set initial status bits */
|
||||
vpm_reset ( &virtnet->vdev );
|
||||
vpm_add_status ( &virtnet->vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE );
|
||||
@ -633,7 +648,6 @@ err_mac_address:
|
||||
vpm_reset ( &virtnet->vdev );
|
||||
netdev_nullify ( netdev );
|
||||
netdev_put ( netdev );
|
||||
|
||||
virtio_pci_unmap_capability ( &virtnet->vdev.device );
|
||||
err_map_device:
|
||||
virtio_pci_unmap_capability ( &virtnet->vdev.isr );
|
||||
|
||||
@ -1165,6 +1165,31 @@ static int xhci_reset ( struct xhci_device *xhci ) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark xHCI device as permanently failed
|
||||
*
|
||||
* @v xhci xHCI device
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int xhci_fail ( struct xhci_device *xhci ) {
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
/* Mark command mechanism as permanently failed */
|
||||
xhci->failed = 1;
|
||||
|
||||
/* Reset device */
|
||||
if ( ( rc = xhci_reset ( xhci ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
/* Discard DCBAA entries since DCBAAP has been cleared */
|
||||
assert ( xhci->dcbaa.context != NULL );
|
||||
len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) );
|
||||
memset ( xhci->dcbaa.context, 0, len );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Transfer request blocks
|
||||
@ -1720,6 +1745,10 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
|
||||
unsigned int consumed;
|
||||
unsigned int type;
|
||||
|
||||
/* Do nothing if device has permanently failed */
|
||||
if ( xhci->failed )
|
||||
return;
|
||||
|
||||
/* Poll for events */
|
||||
profile_start ( &xhci_event_profiler );
|
||||
for ( consumed = 0 ; ; consumed++ ) {
|
||||
@ -1778,6 +1807,7 @@ static void xhci_event_poll ( struct xhci_device *xhci ) {
|
||||
*/
|
||||
static void xhci_abort ( struct xhci_device *xhci ) {
|
||||
physaddr_t crp;
|
||||
uint32_t crcr;
|
||||
|
||||
/* Abort the command */
|
||||
DBGC2 ( xhci, "XHCI %s aborting command\n", xhci->name );
|
||||
@ -1786,8 +1816,18 @@ static void xhci_abort ( struct xhci_device *xhci ) {
|
||||
/* Allow time for command to abort */
|
||||
mdelay ( XHCI_COMMAND_ABORT_DELAY_MS );
|
||||
|
||||
/* Sanity check */
|
||||
assert ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );
|
||||
/* Check for failure to abort */
|
||||
crcr = readl ( xhci->op + XHCI_OP_CRCR );
|
||||
if ( crcr & XHCI_CRCR_CRR ) {
|
||||
|
||||
/* Device has failed to abort a command and is almost
|
||||
* certainly beyond repair. Reset device, abandoning
|
||||
* all state, and mark device as failed to avoid
|
||||
* delays on any future command attempts.
|
||||
*/
|
||||
DBGC ( xhci, "XHCI %s failed to abort command\n", xhci->name );
|
||||
xhci_fail ( xhci );
|
||||
}
|
||||
|
||||
/* Consume (and ignore) any final command status */
|
||||
xhci_event_poll ( xhci );
|
||||
@ -1813,6 +1853,12 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) {
|
||||
unsigned int i;
|
||||
int rc;
|
||||
|
||||
/* Immediately fail all commands if command mechanism has failed */
|
||||
if ( xhci->failed ) {
|
||||
rc = -EPIPE;
|
||||
goto err_failed;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
if ( xhci->pending ) {
|
||||
DBGC ( xhci, "XHCI %s command ring busy\n", xhci->name );
|
||||
@ -1863,6 +1909,7 @@ static int xhci_command ( struct xhci_device *xhci, union xhci_trb *trb ) {
|
||||
err_enqueue:
|
||||
xhci->pending = NULL;
|
||||
err_pending:
|
||||
err_failed:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -3412,14 +3459,36 @@ static int xhci_probe ( struct pci_device *pci ) {
|
||||
static void xhci_remove ( struct pci_device *pci ) {
|
||||
struct xhci_device *xhci = pci_get_drvdata ( pci );
|
||||
struct usb_bus *bus = xhci->bus;
|
||||
uint16_t command;
|
||||
|
||||
/* Some systems are observed to disable bus mastering on
|
||||
* Thunderbolt controllers before we get a chance to shut
|
||||
* down. Detect this and avoid attempting any DMA operations,
|
||||
* which are guaranteed to fail and may end up spuriously
|
||||
* completing after the operating system kernel starts up.
|
||||
*/
|
||||
pci_read_config_word ( pci, PCI_COMMAND, &command );
|
||||
if ( ! ( command & PCI_COMMAND_MASTER ) ) {
|
||||
DBGC ( xhci, "XHCI %s DMA was disabled\n", xhci->name );
|
||||
xhci_fail ( xhci );
|
||||
}
|
||||
|
||||
/* Unregister and free USB bus */
|
||||
unregister_usb_bus ( bus );
|
||||
free_usb_bus ( bus );
|
||||
|
||||
/* Reset device and undo any PCH-specific fixes */
|
||||
xhci_reset ( xhci );
|
||||
if ( xhci->quirks & XHCI_PCH )
|
||||
xhci_pch_undo ( xhci, pci );
|
||||
|
||||
/* Release ownership back to BIOS */
|
||||
xhci_legacy_release ( xhci );
|
||||
|
||||
/* Unmap registers */
|
||||
iounmap ( xhci->regs );
|
||||
|
||||
/* Free device */
|
||||
free ( xhci );
|
||||
}
|
||||
|
||||
|
||||
@ -1115,6 +1115,8 @@ struct xhci_device {
|
||||
struct xhci_event_ring event;
|
||||
/** Current command (if any) */
|
||||
union xhci_trb *pending;
|
||||
/** Command mechanism has permanently failed */
|
||||
int failed;
|
||||
|
||||
/** Device slots, indexed by slot ID */
|
||||
struct xhci_slot **slot;
|
||||
|
||||
105
src/hci/commands/image_archive_cmd.c
Normal file
105
src/hci/commands/image_archive_cmd.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 <getopt.h>
|
||||
#include <ipxe/command.h>
|
||||
#include <ipxe/parseopt.h>
|
||||
#include <usr/imgmgmt.h>
|
||||
#include <usr/imgarchive.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Archive image commands
|
||||
*
|
||||
*/
|
||||
|
||||
/** "imgextract" options */
|
||||
struct imgextract_options {
|
||||
/** Image name */
|
||||
char *name;
|
||||
/** Keep original image */
|
||||
int keep;
|
||||
/** Download timeout */
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/** "imgextract" option list */
|
||||
static struct option_descriptor imgextract_opts[] = {
|
||||
OPTION_DESC ( "name", 'n', required_argument,
|
||||
struct imgextract_options, name, parse_string ),
|
||||
OPTION_DESC ( "keep", 'k', no_argument,
|
||||
struct imgextract_options, keep, parse_flag ),
|
||||
OPTION_DESC ( "timeout", 't', required_argument,
|
||||
struct imgextract_options, timeout, parse_timeout ),
|
||||
};
|
||||
|
||||
/** "imgextract" command descriptor */
|
||||
static struct command_descriptor imgextract_cmd =
|
||||
COMMAND_DESC ( struct imgextract_options, imgextract_opts, 1, 1, NULL );
|
||||
|
||||
/**
|
||||
* The "imgextract" command
|
||||
*
|
||||
* @v argc Argument count
|
||||
* @v argv Argument list
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int imgextract_exec ( int argc, char **argv ) {
|
||||
struct imgextract_options opts;
|
||||
struct image *image;
|
||||
int rc;
|
||||
|
||||
/* Parse options */
|
||||
if ( ( rc = parse_options ( argc, argv, &imgextract_cmd,
|
||||
&opts ) ) != 0 )
|
||||
goto err_parse;
|
||||
|
||||
/* Acquire image */
|
||||
if ( ( rc = imgacquire ( argv[optind], opts.timeout, &image ) ) != 0 )
|
||||
goto err_acquire;
|
||||
|
||||
/* Extract archive image */
|
||||
if ( ( rc = imgextract ( image, opts.name ) ) != 0 )
|
||||
goto err_extract;
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_extract:
|
||||
/* Discard original image unless --keep was specified */
|
||||
if ( ! opts.keep )
|
||||
unregister_image ( image );
|
||||
err_acquire:
|
||||
err_parse:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/** Archive image commands */
|
||||
struct command image_archive_commands[] __command = {
|
||||
{
|
||||
.name = "imgextract",
|
||||
.exec = imgextract_exec,
|
||||
},
|
||||
};
|
||||
@ -100,20 +100,40 @@ static int show_exec ( int argc, char **argv ) {
|
||||
}
|
||||
|
||||
/** "set", "clear", and "read" options */
|
||||
struct set_core_options {};
|
||||
struct set_core_options {
|
||||
/** Timeout */
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/** "set", "clear", and "read" option list */
|
||||
static struct option_descriptor set_core_opts[] = {};
|
||||
static union {
|
||||
/* "set" takes no options */
|
||||
struct option_descriptor set[0];
|
||||
/* "clear" takes no options */
|
||||
struct option_descriptor clear[0];
|
||||
/* "read" takes --timeout option */
|
||||
struct option_descriptor read[1];
|
||||
} set_core_opts = {
|
||||
.read = {
|
||||
OPTION_DESC ( "timeout", 't', required_argument,
|
||||
struct set_core_options, timeout, parse_timeout ),
|
||||
},
|
||||
};
|
||||
|
||||
/** "set" command descriptor */
|
||||
static struct command_descriptor set_cmd =
|
||||
COMMAND_DESC ( struct set_core_options, set_core_opts, 1, MAX_ARGUMENTS,
|
||||
"<setting> <value>" );
|
||||
COMMAND_DESC ( struct set_core_options, set_core_opts.set,
|
||||
1, MAX_ARGUMENTS, "<setting> <value>" );
|
||||
|
||||
/** "clear" and "read" command descriptor */
|
||||
static struct command_descriptor clear_read_cmd =
|
||||
COMMAND_DESC ( struct set_core_options, set_core_opts, 1, 1,
|
||||
"<setting>" );
|
||||
/** "clear" command descriptor */
|
||||
static struct command_descriptor clear_cmd =
|
||||
COMMAND_DESC ( struct set_core_options, set_core_opts.clear,
|
||||
1, 1, "<setting>" );
|
||||
|
||||
/** "read" command descriptor */
|
||||
static struct command_descriptor read_cmd =
|
||||
COMMAND_DESC ( struct set_core_options, set_core_opts.read,
|
||||
1, 1, "<setting>" );
|
||||
|
||||
/**
|
||||
* "set", "clear", and "read" command
|
||||
@ -127,6 +147,7 @@ static struct command_descriptor clear_read_cmd =
|
||||
static int set_core_exec ( int argc, char **argv,
|
||||
struct command_descriptor *cmd,
|
||||
int ( * get_value ) ( struct named_setting *setting,
|
||||
struct set_core_options *opts,
|
||||
char **args, char **value ) ) {
|
||||
struct set_core_options opts;
|
||||
struct named_setting setting;
|
||||
@ -143,7 +164,8 @@ static int set_core_exec ( int argc, char **argv,
|
||||
goto err_parse_setting;
|
||||
|
||||
/* Parse setting value */
|
||||
if ( ( rc = get_value ( &setting, &argv[ optind + 1 ], &value ) ) != 0 )
|
||||
if ( ( rc = get_value ( &setting, &opts, &argv[ optind + 1 ],
|
||||
&value ) ) != 0 )
|
||||
goto err_get_value;
|
||||
|
||||
/* Apply default type if necessary */
|
||||
@ -170,11 +192,13 @@ static int set_core_exec ( int argc, char **argv,
|
||||
* Get setting value for "set" command
|
||||
*
|
||||
* @v setting Named setting
|
||||
* @v opts Options list
|
||||
* @v args Remaining arguments
|
||||
* @ret value Setting value
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int set_value ( struct named_setting *setting __unused,
|
||||
struct set_core_options *opts __unused,
|
||||
char **args, char **value ) {
|
||||
|
||||
*value = concat_args ( args );
|
||||
@ -200,10 +224,12 @@ static int set_exec ( int argc, char **argv ) {
|
||||
*
|
||||
* @v setting Named setting
|
||||
* @v args Remaining arguments
|
||||
* @v opts Options list
|
||||
* @ret value Setting value
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int clear_value ( struct named_setting *setting __unused,
|
||||
struct set_core_options *opts __unused,
|
||||
char **args __unused, char **value ) {
|
||||
|
||||
*value = NULL;
|
||||
@ -218,7 +244,7 @@ static int clear_value ( struct named_setting *setting __unused,
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int clear_exec ( int argc, char **argv ) {
|
||||
return set_core_exec ( argc, argv, &clear_read_cmd, clear_value );
|
||||
return set_core_exec ( argc, argv, &clear_cmd, clear_value );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -226,11 +252,13 @@ static int clear_exec ( int argc, char **argv ) {
|
||||
*
|
||||
* @v setting Named setting
|
||||
* @v args Remaining arguments
|
||||
* @v opts Options list
|
||||
* @ret value Setting value
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int read_value ( struct named_setting *setting, char **args __unused,
|
||||
char **value ) {
|
||||
static int read_value ( struct named_setting *setting,
|
||||
struct set_core_options *opts,
|
||||
char **args __unused, char **value ) {
|
||||
char *existing;
|
||||
int rc;
|
||||
|
||||
@ -241,7 +269,8 @@ static int read_value ( struct named_setting *setting, char **args __unused,
|
||||
NULL, &setting->setting, &existing );
|
||||
|
||||
/* Read new value */
|
||||
if ( ( rc = readline_history ( NULL, existing, NULL, value ) ) != 0 )
|
||||
if ( ( rc = readline_history ( NULL, existing, NULL, opts->timeout,
|
||||
value ) ) != 0 )
|
||||
goto err_readline;
|
||||
|
||||
err_readline:
|
||||
@ -257,7 +286,7 @@ static int read_value ( struct named_setting *setting, char **args __unused,
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int read_exec ( int argc, char **argv ) {
|
||||
return set_core_exec ( argc, argv, &clear_read_cmd, read_value );
|
||||
return set_core_exec ( argc, argv, &read_cmd, read_value );
|
||||
}
|
||||
|
||||
/** "inc" options */
|
||||
|
||||
@ -38,7 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
*
|
||||
*/
|
||||
|
||||
#define READLINE_MAX 256
|
||||
#define READLINE_MAX 1024
|
||||
|
||||
/**
|
||||
* Synchronise console with edited string
|
||||
@ -248,6 +248,7 @@ void history_free ( struct readline_history *history ) {
|
||||
* @v prompt Prompt string
|
||||
* @v prefill Prefill string, or NULL for no prefill
|
||||
* @v history History buffer, or NULL for no history
|
||||
* @v timeout Timeout period, in ticks (0=indefinite)
|
||||
* @ret line Line read from console (excluding terminating newline)
|
||||
* @ret rc Return status code
|
||||
*
|
||||
@ -255,9 +256,10 @@ void history_free ( struct readline_history *history ) {
|
||||
* eventually call free() to release the storage.
|
||||
*/
|
||||
int readline_history ( const char *prompt, const char *prefill,
|
||||
struct readline_history *history, char **line ) {
|
||||
char buf[READLINE_MAX];
|
||||
struct readline_history *history, unsigned long timeout,
|
||||
char **line ) {
|
||||
struct edit_string string;
|
||||
char *buf;
|
||||
int key;
|
||||
int move_by;
|
||||
const char *new_string;
|
||||
@ -273,10 +275,14 @@ int readline_history ( const char *prompt, const char *prefill,
|
||||
/* Ensure cursor is visible */
|
||||
printf ( "\033[?25h" );
|
||||
|
||||
/* Initialise editable string */
|
||||
/* Allocate buffer and initialise editable string */
|
||||
buf = zalloc ( READLINE_MAX );
|
||||
if ( ! buf ) {
|
||||
rc = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
memset ( &string, 0, sizeof ( string ) );
|
||||
init_editstring ( &string, buf, sizeof ( buf ) );
|
||||
buf[0] = '\0';
|
||||
init_editstring ( &string, buf, READLINE_MAX );
|
||||
|
||||
/* Prefill string, if applicable */
|
||||
if ( prefill ) {
|
||||
@ -285,15 +291,29 @@ int readline_history ( const char *prompt, const char *prefill,
|
||||
}
|
||||
|
||||
while ( 1 ) {
|
||||
|
||||
/* Get keypress */
|
||||
key = getkey ( timeout );
|
||||
if ( key < 0 ) {
|
||||
rc = -ETIMEDOUT;
|
||||
goto done;
|
||||
}
|
||||
timeout = 0;
|
||||
|
||||
/* Handle keypress */
|
||||
key = edit_string ( &string, getkey ( 0 ) );
|
||||
key = edit_string ( &string, key );
|
||||
sync_console ( &string );
|
||||
move_by = 0;
|
||||
switch ( key ) {
|
||||
case CR:
|
||||
case LF:
|
||||
*line = strdup ( buf );
|
||||
rc = ( ( *line ) ? 0 : -ENOMEM );
|
||||
/* Shrink string (ignoring failures) */
|
||||
*line = realloc ( buf,
|
||||
( strlen ( buf ) + 1 /* NUL */ ) );
|
||||
if ( ! *line )
|
||||
*line = buf;
|
||||
buf = NULL;
|
||||
rc = 0;
|
||||
goto done;
|
||||
case CTRL_C:
|
||||
rc = -ECANCELED;
|
||||
@ -321,6 +341,7 @@ int readline_history ( const char *prompt, const char *prefill,
|
||||
|
||||
done:
|
||||
putchar ( '\n' );
|
||||
free ( buf );
|
||||
if ( history ) {
|
||||
if ( *line && (*line)[0] )
|
||||
history_append ( history, *line );
|
||||
@ -342,6 +363,6 @@ int readline_history ( const char *prompt, const char *prefill,
|
||||
char * readline ( const char *prompt ) {
|
||||
char *line;
|
||||
|
||||
readline_history ( prompt, NULL, NULL, &line );
|
||||
readline_history ( prompt, NULL, NULL, 0, &line );
|
||||
return line;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ int shell ( void ) {
|
||||
|
||||
/* Read and execute commands */
|
||||
do {
|
||||
readline_history ( shell_prompt, NULL, &history, &line );
|
||||
readline_history ( shell_prompt, NULL, &history, 0, &line );
|
||||
if ( line ) {
|
||||
rc = system ( line );
|
||||
free ( line );
|
||||
|
||||
167
src/image/gzip.c
Normal file
167
src/image/gzip.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/deflate.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/zlib.h>
|
||||
#include <ipxe/gzip.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* gzip compressed images
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extract gzip image
|
||||
*
|
||||
* @v image Image
|
||||
* @v extracted Extracted image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int gzip_extract ( struct image *image, struct image *extracted ) {
|
||||
struct gzip_header header;
|
||||
struct gzip_extra_header extra;
|
||||
struct gzip_crc_header crc;
|
||||
struct gzip_footer footer;
|
||||
struct deflate_chunk in;
|
||||
unsigned int strings;
|
||||
size_t offset;
|
||||
size_t len;
|
||||
off_t nul;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( image->len >= ( sizeof ( header ) + sizeof ( footer ) ) );
|
||||
|
||||
/* Extract footer */
|
||||
len = ( image->len - sizeof ( footer ) );
|
||||
copy_from_user ( &footer, image->data, len, sizeof ( footer ) );
|
||||
|
||||
/* Extract fixed header */
|
||||
copy_from_user ( &header, image->data, 0, sizeof ( header ) );
|
||||
offset = sizeof ( header );
|
||||
assert ( offset <= ( image->len - sizeof ( footer ) ) );
|
||||
|
||||
/* Skip extra header, if present */
|
||||
if ( header.flags & GZIP_FL_EXTRA ) {
|
||||
copy_from_user ( &extra, image->data, offset,
|
||||
sizeof ( extra ) );
|
||||
offset += sizeof ( extra );
|
||||
offset += le16_to_cpu ( extra.len );
|
||||
if ( offset > len ) {
|
||||
DBGC ( image, "GZIP %p overlength extra header\n",
|
||||
image );
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
assert ( offset <= ( image->len - sizeof ( footer ) ) );
|
||||
|
||||
/* Skip name and/or comment, if present */
|
||||
strings = 0;
|
||||
if ( header.flags & GZIP_FL_NAME )
|
||||
strings++;
|
||||
if ( header.flags & GZIP_FL_COMMENT )
|
||||
strings++;
|
||||
while ( strings-- ) {
|
||||
nul = memchr_user ( image->data, offset, 0, ( len - offset ) );
|
||||
if ( nul < 0 ) {
|
||||
DBGC ( image, "GZIP %p overlength name/comment\n",
|
||||
image );
|
||||
return -EINVAL;
|
||||
}
|
||||
offset = ( nul + 1 /* NUL */ );
|
||||
}
|
||||
assert ( offset <= ( image->len - sizeof ( footer ) ) );
|
||||
|
||||
/* Skip CRC, if present */
|
||||
if ( header.flags & GZIP_FL_HCRC ) {
|
||||
offset += sizeof ( crc );
|
||||
if ( offset > len ) {
|
||||
DBGC ( image, "GZIP %p overlength CRC header\n",
|
||||
image );
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise input chunk */
|
||||
deflate_chunk_init ( &in, userptr_add ( image->data, offset ), 0, len );
|
||||
|
||||
/* Presize extracted image */
|
||||
if ( ( rc = image_set_len ( extracted,
|
||||
le32_to_cpu ( footer.len ) ) ) != 0 ) {
|
||||
DBGC ( image, "GZIP %p could not presize: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Decompress image (expanding if necessary) */
|
||||
if ( ( rc = zlib_deflate ( DEFLATE_RAW, &in, extracted ) ) != 0 ) {
|
||||
DBGC ( image, "GZIP %p could not decompress: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe gzip image
|
||||
*
|
||||
* @v image gzip image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int gzip_probe ( struct image *image ) {
|
||||
struct gzip_header header;
|
||||
struct gzip_footer footer;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < ( sizeof ( header ) + sizeof ( footer ) ) ) {
|
||||
DBGC ( image, "GZIP %p image too short\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Check magic header */
|
||||
copy_from_user ( &header.magic, image->data, 0,
|
||||
sizeof ( header.magic ) );
|
||||
if ( header.magic != cpu_to_be16 ( GZIP_MAGIC ) ) {
|
||||
DBGC ( image, "GZIP %p invalid magic\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** gzip image type */
|
||||
struct image_type gzip_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "gzip",
|
||||
.probe = gzip_probe,
|
||||
.extract = gzip_extract,
|
||||
.exec = image_extract_exec,
|
||||
};
|
||||
163
src/image/zlib.c
Normal file
163
src/image/zlib.c
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/deflate.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/zlib.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* zlib compressed images
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extract compressed data to image
|
||||
*
|
||||
* @v format Compression format code
|
||||
* @v in Compressed input chunk
|
||||
* @v extracted Extracted image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in,
|
||||
struct image *extracted ) {
|
||||
struct deflate *deflate;
|
||||
struct deflate_chunk out;
|
||||
int rc;
|
||||
|
||||
/* Allocate and initialise decompressor */
|
||||
deflate = zalloc ( sizeof ( *deflate ) );
|
||||
if ( ! deflate ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
/* Decompress data, (re)allocating if necessary */
|
||||
while ( 1 ) {
|
||||
|
||||
/* (Re)initialise decompressor */
|
||||
deflate_init ( deflate, format );
|
||||
|
||||
/* (Re)initialise input chunk */
|
||||
in->offset = 0;
|
||||
|
||||
/* Initialise output chunk */
|
||||
deflate_chunk_init ( &out, extracted->data, 0, extracted->len );
|
||||
|
||||
/* Decompress data */
|
||||
if ( ( rc = deflate_inflate ( deflate, in, &out ) ) != 0 ) {
|
||||
DBGC ( extracted, "ZLIB %p could not decompress: %s\n",
|
||||
extracted, strerror ( rc ) );
|
||||
goto err_inflate;
|
||||
}
|
||||
|
||||
/* Check that decompression is valid */
|
||||
if ( ! deflate_finished ( deflate ) ) {
|
||||
DBGC ( extracted, "ZLIB %p decompression incomplete\n",
|
||||
extracted );
|
||||
rc = -EINVAL;
|
||||
goto err_unfinished;
|
||||
}
|
||||
|
||||
/* Finish if output image size was correct */
|
||||
if ( out.offset == extracted->len )
|
||||
break;
|
||||
|
||||
/* Otherwise, resize output image and retry */
|
||||
if ( ( rc = image_set_len ( extracted, out.offset ) ) != 0 ) {
|
||||
DBGC ( extracted, "ZLIB %p could not resize: %s\n",
|
||||
extracted, strerror ( rc ) );
|
||||
goto err_set_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_set_size:
|
||||
err_unfinished:
|
||||
err_inflate:
|
||||
free ( deflate );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract zlib image
|
||||
*
|
||||
* @v image Image
|
||||
* @v extracted Extracted image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int zlib_extract ( struct image *image, struct image *extracted ) {
|
||||
struct deflate_chunk in;
|
||||
int rc;
|
||||
|
||||
/* Initialise input chunk */
|
||||
deflate_chunk_init ( &in, image->data, 0, image->len );
|
||||
|
||||
/* Decompress image */
|
||||
if ( ( rc = zlib_deflate ( DEFLATE_ZLIB, &in, extracted ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe zlib image
|
||||
*
|
||||
* @v image zlib image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int zlib_probe ( struct image *image ) {
|
||||
union zlib_magic magic;
|
||||
|
||||
/* Sanity check */
|
||||
if ( image->len < sizeof ( magic ) ) {
|
||||
DBGC ( image, "ZLIB %p image too short\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
/* Check magic header */
|
||||
copy_from_user ( &magic, image->data, 0, sizeof ( magic ) );
|
||||
if ( ! zlib_magic_is_valid ( &magic ) ) {
|
||||
DBGC ( image, "ZLIB %p invalid magic data\n", image );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** zlib image type */
|
||||
struct image_type zlib_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "zlib",
|
||||
.probe = zlib_probe,
|
||||
.extract = zlib_extract,
|
||||
.exec = image_extract_exec,
|
||||
};
|
||||
@ -8,14 +8,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* Little-endian systems should define BYTE_ORDER as LITTLE_ENDIAN.
|
||||
* This constant is intended to be used only at compile time.
|
||||
*/
|
||||
#ifndef __LITTLE_ENDIAN
|
||||
#define __LITTLE_ENDIAN 0x44332211UL
|
||||
#endif
|
||||
|
||||
/** Constant representing big-endian byte order
|
||||
*
|
||||
* Big-endian systems should define BYTE_ORDER as BIG_ENDIAN.
|
||||
* This constant is intended to be used only at compile time.
|
||||
*/
|
||||
#ifndef __BIG_ENDIAN
|
||||
#define __BIG_ENDIAN 0x11223344UL
|
||||
#endif
|
||||
|
||||
#include "bits/endian.h"
|
||||
|
||||
|
||||
@ -387,7 +387,9 @@ acpi_describe ( struct interface *interface );
|
||||
typeof ( struct acpi_descriptor * ( object_type ) )
|
||||
|
||||
extern void acpi_fix_checksum ( struct acpi_header *acpi );
|
||||
extern int acpi_sx ( uint32_t signature );
|
||||
extern int acpi_extract ( uint32_t signature, void *data,
|
||||
int ( * extract ) ( userptr_t zsdt, size_t len,
|
||||
size_t offset, void *data ) );
|
||||
extern void acpi_add ( struct acpi_descriptor *desc );
|
||||
extern void acpi_del ( struct acpi_descriptor *desc );
|
||||
extern int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) );
|
||||
|
||||
14
src/include/ipxe/acpimac.h
Normal file
14
src/include/ipxe/acpimac.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _IPXE_ACPIMAC_H
|
||||
#define _IPXE_ACPIMAC_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ACPI MAC address
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
extern int acpi_mac ( uint8_t *hw_addr );
|
||||
|
||||
#endif /* _IPXE_ACPIMAC_H */
|
||||
@ -12,6 +12,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <stddef.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
|
||||
extern int cachedhcp_record ( userptr_t data, size_t max_len );
|
||||
struct cached_dhcp_packet;
|
||||
|
||||
extern struct cached_dhcp_packet cached_dhcpack;
|
||||
extern struct cached_dhcp_packet cached_proxydhcp;
|
||||
extern struct cached_dhcp_packet cached_pxebs;
|
||||
|
||||
extern int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
|
||||
size_t max_len );
|
||||
|
||||
#endif /* _IPXE_CACHEDHCP_H */
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/image.h>
|
||||
|
||||
/** A CPIO archive header
|
||||
*
|
||||
* All field are hexadecimal ASCII numbers padded with '0' on the
|
||||
@ -48,6 +50,25 @@ struct cpio_header {
|
||||
/** CPIO magic */
|
||||
#define CPIO_MAGIC "070701"
|
||||
|
||||
/** CPIO header length alignment */
|
||||
#define CPIO_ALIGN 4
|
||||
|
||||
/** Alignment for CPIO archives within an initrd */
|
||||
#define INITRD_ALIGN 4096
|
||||
|
||||
/**
|
||||
* Get CPIO image name
|
||||
*
|
||||
* @v image Image
|
||||
* @ret name Image name (not NUL terminated)
|
||||
*/
|
||||
static inline __attribute__ (( always_inline )) const char *
|
||||
cpio_name ( struct image *image ) {
|
||||
return image->cmdline;
|
||||
}
|
||||
|
||||
extern void cpio_set_field ( char *field, unsigned long value );
|
||||
extern size_t cpio_name_len ( struct image *image );
|
||||
extern size_t cpio_header ( struct image *image, struct cpio_header *cpio );
|
||||
|
||||
#endif /* _IPXE_CPIO_H */
|
||||
|
||||
@ -56,7 +56,7 @@ dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
|
||||
* @v dhcppkt DHCP packet
|
||||
* @ret len Used length
|
||||
*/
|
||||
static inline int dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
|
||||
static inline size_t dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
|
||||
return ( offsetof ( struct dhcphdr, options ) +
|
||||
dhcppkt->options.used_len );
|
||||
}
|
||||
|
||||
@ -223,6 +223,7 @@ extern EFI_HANDLE efi_image_handle;
|
||||
extern EFI_LOADED_IMAGE_PROTOCOL *efi_loaded_image;
|
||||
extern EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
|
||||
extern EFI_SYSTEM_TABLE *efi_systab;
|
||||
extern EFI_TPL efi_internal_tpl;
|
||||
extern EFI_TPL efi_external_tpl;
|
||||
extern int efi_shutdown_in_progress;
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/efi/efi.h>
|
||||
|
||||
extern EFI_SYSTEM_TABLE * efi_wrap_systab ( void );
|
||||
extern EFI_BOOT_SERVICES * efi_wrap_bs ( void );
|
||||
extern void efi_wrap ( EFI_HANDLE handle );
|
||||
|
||||
#endif /* _IPXE_EFI_WRAP_H */
|
||||
|
||||
@ -77,6 +77,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_fdt ( ERRFILE_CORE | 0x00250000 )
|
||||
#define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 )
|
||||
#define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 )
|
||||
#define ERRFILE_acpimac ( ERRFILE_CORE | 0x00280000 )
|
||||
|
||||
#define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 )
|
||||
#define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 )
|
||||
@ -213,6 +214,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_usbblk ( ERRFILE_DRIVER | 0x00ce0000 )
|
||||
#define ERRFILE_iphone ( ERRFILE_DRIVER | 0x00cf0000 )
|
||||
#define ERRFILE_slirp ( ERRFILE_DRIVER | 0x00d00000 )
|
||||
#define ERRFILE_rdc ( ERRFILE_DRIVER | 0x00d10000 )
|
||||
|
||||
#define ERRFILE_aoe ( ERRFILE_NET | 0x00000000 )
|
||||
#define ERRFILE_arp ( ERRFILE_NET | 0x00010000 )
|
||||
@ -301,6 +303,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 )
|
||||
#define ERRFILE_der ( ERRFILE_IMAGE | 0x00080000 )
|
||||
#define ERRFILE_pem ( ERRFILE_IMAGE | 0x00090000 )
|
||||
#define ERRFILE_archive ( ERRFILE_IMAGE | 0x000a0000 )
|
||||
#define ERRFILE_zlib ( ERRFILE_IMAGE | 0x000b0000 )
|
||||
#define ERRFILE_gzip ( ERRFILE_IMAGE | 0x000c0000 )
|
||||
|
||||
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
|
||||
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )
|
||||
|
||||
71
src/include/ipxe/gzip.h
Normal file
71
src/include/ipxe/gzip.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef _IPXE_GZIP_H
|
||||
#define _IPXE_GZIP_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* gzip compressed images
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/image.h>
|
||||
|
||||
/** gzip header */
|
||||
struct gzip_header {
|
||||
/** Magic ID */
|
||||
uint16_t magic;
|
||||
/** Compression method */
|
||||
uint8_t method;
|
||||
/** Flags */
|
||||
uint8_t flags;
|
||||
/** Modification time */
|
||||
uint32_t mtime;
|
||||
/** Extra flags */
|
||||
uint8_t extra;
|
||||
/** Operating system */
|
||||
uint8_t os;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** Magic ID */
|
||||
#define GZIP_MAGIC 0x1f8b
|
||||
|
||||
/** Compression method */
|
||||
#define GZIP_METHOD_DEFLATE 0x08
|
||||
|
||||
/** CRC header is present */
|
||||
#define GZIP_FL_HCRC 0x02
|
||||
|
||||
/** Extra header is present */
|
||||
#define GZIP_FL_EXTRA 0x04
|
||||
|
||||
/** File name is present */
|
||||
#define GZIP_FL_NAME 0x08
|
||||
|
||||
/** File comment is present */
|
||||
#define GZIP_FL_COMMENT 0x10
|
||||
|
||||
/** gzip extra header */
|
||||
struct gzip_extra_header {
|
||||
/** Extra header length (excluding this field) */
|
||||
uint16_t len;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** gzip CRC header */
|
||||
struct gzip_crc_header {
|
||||
/** CRC-16 */
|
||||
uint16_t crc;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** gzip footer */
|
||||
struct gzip_footer {
|
||||
/** CRC-32 */
|
||||
uint32_t crc;
|
||||
/** Uncompressed size (modulo 2^32) */
|
||||
uint32_t len;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
extern struct image_type gzip_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
#endif /* _IPXE_GZIP_H */
|
||||
@ -113,6 +113,14 @@ struct image_type {
|
||||
*/
|
||||
int ( * asn1 ) ( struct image *image, size_t offset,
|
||||
struct asn1_cursor **cursor );
|
||||
/**
|
||||
* Extract archive image
|
||||
*
|
||||
* @v image Image
|
||||
* @v extracted Extracted image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int ( * extract ) ( struct image *image, struct image *extracted );
|
||||
};
|
||||
|
||||
/**
|
||||
@ -175,6 +183,7 @@ extern struct image * alloc_image ( struct uri *uri );
|
||||
extern int image_set_uri ( struct image *image, struct uri *uri );
|
||||
extern int image_set_name ( struct image *image, const char *name );
|
||||
extern int image_set_cmdline ( struct image *image, const char *cmdline );
|
||||
extern int image_set_len ( struct image *image, size_t len );
|
||||
extern int image_set_data ( struct image *image, userptr_t data, size_t len );
|
||||
extern int register_image ( struct image *image );
|
||||
extern void unregister_image ( struct image *image );
|
||||
@ -189,6 +198,9 @@ extern struct image * image_memory ( const char *name, userptr_t data,
|
||||
extern int image_pixbuf ( struct image *image, struct pixel_buffer **pixbuf );
|
||||
extern int image_asn1 ( struct image *image, size_t offset,
|
||||
struct asn1_cursor **cursor );
|
||||
extern int image_extract ( struct image *image, const char *name,
|
||||
struct image **extracted );
|
||||
extern int image_extract_exec ( struct image *image );
|
||||
|
||||
/**
|
||||
* Increment reference count on an image
|
||||
|
||||
@ -84,7 +84,7 @@ struct rndis_initialise_completion {
|
||||
/** Packet alignment factor */
|
||||
uint32_t align;
|
||||
/** Reserved */
|
||||
uint32_t reserved;
|
||||
uint32_t reserved[2];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** RNDIS halt message */
|
||||
@ -237,7 +237,7 @@ struct rndis_packet_message {
|
||||
/** Per-packet information record */
|
||||
struct rndis_packet_field ppi;
|
||||
/** Reserved */
|
||||
uint32_t reserved;
|
||||
uint32_t reserved[2];
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/** RNDIS packet record */
|
||||
|
||||
68
src/include/ipxe/sbat.h
Normal file
68
src/include/ipxe/sbat.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef _IPXE_SBAT_H
|
||||
#define _IPXE_SBAT_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Secure Boot Advanced Targeting (SBAT)
|
||||
*
|
||||
* SBAT defines an encoding for security generation numbers stored as
|
||||
* a CSV file within a special ".sbat" section in the signed binary.
|
||||
* If a Secure Boot exploit is discovered then the generation number
|
||||
* will be incremented alongside the corresponding fix.
|
||||
*
|
||||
* Platforms may then record the minimum generation number required
|
||||
* for any given product. This allows for an efficient revocation
|
||||
* mechanism that consumes minimal flash storage space (in contrast to
|
||||
* the DBX mechanism, which allows for only a single-digit number of
|
||||
* revocation events to ever take place across all possible signed
|
||||
* binaries).
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/**
|
||||
* A single line within an SBAT CSV file
|
||||
*
|
||||
* @v name Machine-readable component name
|
||||
* @v generation Security generation number
|
||||
* @v vendor Human-readable vendor name
|
||||
* @v package Human-readable package name
|
||||
* @v version Human-readable package version
|
||||
* @v uri Contact URI
|
||||
* @ret line CSV line
|
||||
*/
|
||||
#define SBAT_LINE( name, generation, vendor, package, version, uri ) \
|
||||
name "," _S2 ( generation ) "," vendor "," package "," \
|
||||
version "," uri "\n"
|
||||
|
||||
/** SBAT format generation */
|
||||
#define SBAT_GENERATION 1
|
||||
|
||||
/** Upstream security generation
|
||||
*
|
||||
* This represents the security generation of the upstream codebase.
|
||||
* It will be incremented whenever a Secure Boot exploit is fixed in
|
||||
* the upstream codebase.
|
||||
*
|
||||
* If you do not have commit access to the upstream iPXE repository,
|
||||
* then you may not modify this value under any circumstances.
|
||||
*/
|
||||
#define IPXE_SBAT_GENERATION 1
|
||||
|
||||
/* Seriously, do not modify this value */
|
||||
#if IPXE_SBAT_GENERATION != 1
|
||||
#error "You may not modify IPXE_SBAT_GENERATION"
|
||||
#endif
|
||||
|
||||
/** SBAT header line */
|
||||
#define SBAT_HEADER \
|
||||
SBAT_LINE ( "sbat", SBAT_GENERATION, "SBAT Version", "sbat", \
|
||||
_S2 ( SBAT_GENERATION ), \
|
||||
"https://github.com/rhboot/shim/blob/main/SBAT.md" )
|
||||
|
||||
/** Mark variable as being in the ".sbat" section */
|
||||
#define __sbat __attribute__ (( section ( ".sbat" ), aligned ( 512 ) ))
|
||||
|
||||
extern const char sbat[] __sbat;
|
||||
|
||||
#endif /* _IPXE_SBAT_H */
|
||||
@ -426,6 +426,7 @@ extern const struct setting_type setting_type_hexhyp __setting_type;
|
||||
extern const struct setting_type setting_type_hexraw __setting_type;
|
||||
extern const struct setting_type setting_type_base64 __setting_type;
|
||||
extern const struct setting_type setting_type_uuid __setting_type;
|
||||
extern const struct setting_type setting_type_guid __setting_type;
|
||||
extern const struct setting_type setting_type_busdevfn __setting_type;
|
||||
extern const struct setting_type setting_type_dnssl __setting_type;
|
||||
|
||||
|
||||
@ -774,7 +774,7 @@ struct srp_aer_rsp {
|
||||
* The working draft specification for the SRP boot firmware table can
|
||||
* be found at
|
||||
*
|
||||
* http://ipxe.org/wiki/srp/sbft
|
||||
* https://ipxe.org/wiki/srp/sbft
|
||||
*
|
||||
*****************************************************************************
|
||||
*/
|
||||
|
||||
@ -46,6 +46,20 @@ struct parameters;
|
||||
* scheme = "ftp", user = "joe", password = "secret",
|
||||
* host = "insecure.org", port = "8081", path = "/hidden/path/to",
|
||||
* query = "what=is", fragment = "this"
|
||||
*
|
||||
* The URI syntax includes a percent-encoding mechanism that can be
|
||||
* used to represent characters that would otherwise not be possible,
|
||||
* such as a '/' character within the password field. These encodings
|
||||
* are decoded during the URI parsing stage, thereby allowing protocol
|
||||
* implementations to consume the raw field values directly without
|
||||
* further decoding.
|
||||
*
|
||||
* Some protocols (such as HTTP) communicate using URI-encoded values.
|
||||
* For these protocols, the original encoded substring must be
|
||||
* retained verbatim since the choice of whether or not to encode a
|
||||
* particular character may have significance to the receiving
|
||||
* application. We therefore retain the originally-encoded substrings
|
||||
* for the path, query, and fragment fields.
|
||||
*/
|
||||
struct uri {
|
||||
/** Reference count */
|
||||
@ -62,12 +76,14 @@ struct uri {
|
||||
const char *host;
|
||||
/** Port number */
|
||||
const char *port;
|
||||
/** Path */
|
||||
/** Path (after URI decoding) */
|
||||
const char *path;
|
||||
/** Query */
|
||||
const char *query;
|
||||
/** Fragment */
|
||||
const char *fragment;
|
||||
/** Path (with original URI encoding) */
|
||||
const char *epath;
|
||||
/** Query (with original URI encoding) */
|
||||
const char *equery;
|
||||
/** Fragment (with original URI encoding) */
|
||||
const char *efragment;
|
||||
/** Form parameters */
|
||||
struct parameters *params;
|
||||
} __attribute__ (( packed ));
|
||||
@ -100,8 +116,9 @@ enum uri_fields {
|
||||
URI_HOST = URI_FIELD ( host ),
|
||||
URI_PORT = URI_FIELD ( port ),
|
||||
URI_PATH = URI_FIELD ( path ),
|
||||
URI_QUERY = URI_FIELD ( query ),
|
||||
URI_FRAGMENT = URI_FIELD ( fragment ),
|
||||
URI_EPATH = URI_FIELD ( epath ),
|
||||
URI_EQUERY = URI_FIELD ( equery ),
|
||||
URI_EFRAGMENT = URI_FIELD ( efragment ),
|
||||
URI_FIELDS
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#ifndef _VIRTIO_PCI_H_
|
||||
# define _VIRTIO_PCI_H_
|
||||
|
||||
#include <ipxe/dma.h>
|
||||
|
||||
/* A 32-bit r/o bitmask of the features supported by the host */
|
||||
#define VIRTIO_PCI_HOST_FEATURES 0
|
||||
|
||||
@ -198,7 +200,8 @@ struct vring_virtqueue;
|
||||
|
||||
void vp_free_vq(struct vring_virtqueue *vq);
|
||||
int vp_find_vq(unsigned int ioaddr, int queue_index,
|
||||
struct vring_virtqueue *vq);
|
||||
struct vring_virtqueue *vq, struct dma_device *dma_dev,
|
||||
size_t header_size);
|
||||
|
||||
|
||||
/* Virtio 1.0 I/O routines abstract away the three possible HW access
|
||||
@ -298,7 +301,8 @@ void vpm_notify(struct virtio_pci_modern_device *vdev,
|
||||
struct vring_virtqueue *vq);
|
||||
|
||||
int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
|
||||
unsigned nvqs, struct vring_virtqueue *vqs);
|
||||
unsigned nvqs, struct vring_virtqueue *vqs,
|
||||
struct dma_device *dma_dev, size_t header_size);
|
||||
|
||||
int virtio_pci_find_capability(struct pci_device *pci, uint8_t cfg_type);
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
# define _VIRTIO_RING_H_
|
||||
|
||||
#include <ipxe/virtio-pci.h>
|
||||
#include <ipxe/dma.h>
|
||||
|
||||
/* Status byte for guest to report progress, and synchronize features. */
|
||||
/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
|
||||
@ -74,17 +75,21 @@ struct vring {
|
||||
|
||||
struct vring_virtqueue {
|
||||
unsigned char *queue;
|
||||
size_t queue_size;
|
||||
struct dma_mapping map;
|
||||
struct dma_device *dma;
|
||||
struct vring vring;
|
||||
u16 free_head;
|
||||
u16 last_used_idx;
|
||||
void **vdata;
|
||||
struct virtio_net_hdr_modern *empty_header;
|
||||
/* PCI */
|
||||
int queue_index;
|
||||
struct virtio_pci_region notification;
|
||||
};
|
||||
|
||||
struct vring_list {
|
||||
char *addr;
|
||||
physaddr_t addr;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
|
||||
43
src/include/ipxe/zlib.h
Normal file
43
src/include/ipxe/zlib.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef _IPXE_ZLIB_H
|
||||
#define _IPXE_ZLIB_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* zlib compressed images
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <byteswap.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/deflate.h>
|
||||
|
||||
/** zlib magic header */
|
||||
union zlib_magic {
|
||||
/** Compression method and flags */
|
||||
uint8_t cmf;
|
||||
/** Check value */
|
||||
uint16_t check;
|
||||
} __attribute__ (( packed ));
|
||||
|
||||
/**
|
||||
* Check that zlib magic header is valid
|
||||
*
|
||||
* @v magic Magic header
|
||||
* @ret is_valid Magic header is valid
|
||||
*/
|
||||
static inline int zlib_magic_is_valid ( union zlib_magic *magic ) {
|
||||
|
||||
/* Check magic value as per RFC 6713 */
|
||||
return ( ( ( magic->cmf & 0x8f ) == 0x08 ) &&
|
||||
( ( be16_to_cpu ( magic->check ) % 31 ) == 0 ) );
|
||||
}
|
||||
|
||||
extern int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in,
|
||||
struct image *extracted );
|
||||
|
||||
extern struct image_type zlib_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
#endif /* _IPXE_ZLIB_H */
|
||||
@ -23,6 +23,8 @@ FILE_LICENCE ( GPL2_ONLY );
|
||||
#define MII_EXPANSION 0x06 /* Expansion register */
|
||||
#define MII_CTRL1000 0x09 /* 1000BASE-T control */
|
||||
#define MII_STAT1000 0x0a /* 1000BASE-T status */
|
||||
#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
|
||||
#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
|
||||
#define MII_ESTATUS 0x0f /* Extended Status */
|
||||
#define MII_DCOUNTER 0x12 /* Disconnect counter */
|
||||
#define MII_FCSCOUNTER 0x13 /* False carrier counter */
|
||||
|
||||
@ -51,7 +51,8 @@ struct readline_history {
|
||||
|
||||
extern void history_free ( struct readline_history *history );
|
||||
extern int readline_history ( const char *prompt, const char *prefill,
|
||||
struct readline_history *history, char **line );
|
||||
struct readline_history *history,
|
||||
unsigned long timeout, char **line );
|
||||
extern char * __malloc readline ( const char *prompt );
|
||||
|
||||
#endif /* _READLINE_H */
|
||||
|
||||
@ -6,7 +6,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern void putchar ( int character );
|
||||
extern int putchar ( int character );
|
||||
|
||||
extern int getchar ( void );
|
||||
|
||||
|
||||
@ -189,5 +189,7 @@ bzero ( void *dest, size_t len ) {
|
||||
}
|
||||
|
||||
int __pure strcasecmp ( const char *first, const char *second ) __nonnull;
|
||||
int __pure strncasecmp ( const char *first, const char *second,
|
||||
size_t max ) __nonnull;
|
||||
|
||||
#endif /* _STRINGS_H */
|
||||
|
||||
16
src/include/usr/imgarchive.h
Normal file
16
src/include/usr/imgarchive.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _USR_IMGARCHIVE_H
|
||||
#define _USR_IMGARCHIVE_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Archive image management
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/image.h>
|
||||
|
||||
extern int imgextract ( struct image *image, const char *name );
|
||||
|
||||
#endif /* _USR_IMGARCHIVE_H */
|
||||
@ -75,17 +75,40 @@ int efi_cachedhcp_record ( EFI_HANDLE device ) {
|
||||
|
||||
/* Record DHCPACK, if present */
|
||||
if ( mode->DhcpAckReceived &&
|
||||
( ( rc = cachedhcp_record ( virt_to_user ( &mode->DhcpAck ),
|
||||
( ( rc = cachedhcp_record ( &cached_dhcpack,
|
||||
virt_to_user ( &mode->DhcpAck ),
|
||||
sizeof ( mode->DhcpAck ) ) ) != 0 ) ) {
|
||||
DBGC ( device, "EFI %s could not record DHCPACK: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_record;
|
||||
goto err_dhcpack;
|
||||
}
|
||||
|
||||
/* Record ProxyDHCPOFFER, if present */
|
||||
if ( mode->ProxyOfferReceived &&
|
||||
( ( rc = cachedhcp_record ( &cached_proxydhcp,
|
||||
virt_to_user ( &mode->ProxyOffer ),
|
||||
sizeof ( mode->ProxyOffer ) ) ) != 0)){
|
||||
DBGC ( device, "EFI %s could not record ProxyDHCPOFFER: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_proxydhcp;
|
||||
}
|
||||
|
||||
/* Record PxeBSACK, if present */
|
||||
if ( mode->PxeReplyReceived &&
|
||||
( ( rc = cachedhcp_record ( &cached_pxebs,
|
||||
virt_to_user ( &mode->PxeReply ),
|
||||
sizeof ( mode->PxeReply ) ) ) != 0)){
|
||||
DBGC ( device, "EFI %s could not record PXEBSACK: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_pxebs;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
rc = 0;
|
||||
|
||||
err_record:
|
||||
err_pxebs:
|
||||
err_proxydhcp:
|
||||
err_dhcpack:
|
||||
err_ipv6:
|
||||
bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid,
|
||||
efi_image_handle, NULL );
|
||||
|
||||
@ -104,8 +104,8 @@ static void efi_entropy_disable ( void ) {
|
||||
/* Close timer tick event */
|
||||
bs->CloseEvent ( tick );
|
||||
|
||||
/* Return to TPL_CALLBACK */
|
||||
bs->RaiseTPL ( TPL_CALLBACK );
|
||||
/* Return to internal TPL */
|
||||
bs->RaiseTPL ( efi_internal_tpl );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <errno.h>
|
||||
#include <wchar.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/cpio.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
|
||||
#include <ipxe/efi/Protocol/BlockIo.h>
|
||||
@ -50,17 +51,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
/** EFI media ID */
|
||||
#define EFI_MEDIA_ID_MAGIC 0x69505845
|
||||
|
||||
/** An image exposed as an EFI file */
|
||||
/** An EFI virtual file reader */
|
||||
struct efi_file_reader {
|
||||
/** EFI file */
|
||||
struct efi_file *file;
|
||||
/** Position within virtual file */
|
||||
size_t pos;
|
||||
/** Output data buffer */
|
||||
void *data;
|
||||
/** Length of output data buffer */
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/** An EFI file */
|
||||
struct efi_file {
|
||||
/** Reference count */
|
||||
struct refcnt refcnt;
|
||||
/** EFI file protocol */
|
||||
EFI_FILE_PROTOCOL file;
|
||||
/** Image */
|
||||
/** Image (if any) */
|
||||
struct image *image;
|
||||
/** Filename */
|
||||
const char *name;
|
||||
/** Current file position */
|
||||
size_t pos;
|
||||
/**
|
||||
* Read from file
|
||||
*
|
||||
* @v reader File reader
|
||||
* @ret len Length read
|
||||
*/
|
||||
size_t ( * read ) ( struct efi_file_reader *reader );
|
||||
};
|
||||
|
||||
static struct efi_file efi_file_root;
|
||||
static struct efi_file efi_file_initrd;
|
||||
|
||||
/**
|
||||
* Free EFI file
|
||||
*
|
||||
* @v refcnt Reference count
|
||||
*/
|
||||
static void efi_file_free ( struct refcnt *refcnt ) {
|
||||
struct efi_file *file =
|
||||
container_of ( refcnt, struct efi_file, refcnt );
|
||||
|
||||
image_put ( file->image );
|
||||
free ( file );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get EFI file name (for debugging)
|
||||
@ -70,28 +108,201 @@ static struct efi_file efi_file_root;
|
||||
*/
|
||||
static const char * efi_file_name ( struct efi_file *file ) {
|
||||
|
||||
return ( file->image ? file->image->name : "<root>" );
|
||||
return ( file == &efi_file_root ? "<root>" : file->name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find EFI file image
|
||||
*
|
||||
* @v wname Filename
|
||||
* @v name Filename
|
||||
* @ret image Image, or NULL
|
||||
*/
|
||||
static struct image * efi_file_find ( const CHAR16 *wname ) {
|
||||
char name[ wcslen ( wname ) + 1 /* NUL */ ];
|
||||
static struct image * efi_file_find ( const char *name ) {
|
||||
struct image *image;
|
||||
|
||||
/* Find image */
|
||||
snprintf ( name, sizeof ( name ), "%ls", wname );
|
||||
list_for_each_entry ( image, &images, list ) {
|
||||
if ( strcasecmp ( image->name, name ) == 0 )
|
||||
return image;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get length of EFI file
|
||||
*
|
||||
* @v file EFI file
|
||||
* @ret len Length of file
|
||||
*/
|
||||
static size_t efi_file_len ( struct efi_file *file ) {
|
||||
struct efi_file_reader reader;
|
||||
|
||||
/* If this is the root directory, then treat as length zero */
|
||||
if ( ! file->read )
|
||||
return 0;
|
||||
|
||||
/* Initialise reader */
|
||||
reader.file = file;
|
||||
reader.pos = 0;
|
||||
reader.data = NULL;
|
||||
reader.len = 0;
|
||||
|
||||
/* Perform dummy read to determine file length */
|
||||
file->read ( &reader );
|
||||
|
||||
return reader.pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read chunk of EFI file
|
||||
*
|
||||
* @v reader EFI file reader
|
||||
* @v data Input data, or UNULL to zero-fill
|
||||
* @v len Length of input data
|
||||
* @ret len Length of output data
|
||||
*/
|
||||
static size_t efi_file_read_chunk ( struct efi_file_reader *reader,
|
||||
userptr_t data, size_t len ) {
|
||||
struct efi_file *file = reader->file;
|
||||
size_t offset;
|
||||
|
||||
/* Calculate offset into input data */
|
||||
offset = ( file->pos - reader->pos );
|
||||
|
||||
/* Consume input data range */
|
||||
reader->pos += len;
|
||||
|
||||
/* Calculate output length */
|
||||
if ( offset < len ) {
|
||||
len -= offset;
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
if ( len > reader->len )
|
||||
len = reader->len;
|
||||
|
||||
/* Copy or zero output data */
|
||||
if ( data ) {
|
||||
copy_from_user ( reader->data, data, offset, len );
|
||||
} else {
|
||||
memset ( reader->data, 0, len );
|
||||
}
|
||||
|
||||
/* Consume output buffer */
|
||||
file->pos += len;
|
||||
reader->data += len;
|
||||
reader->len -= len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from image-backed file
|
||||
*
|
||||
* @v reader EFI file reader
|
||||
* @ret len Length read
|
||||
*/
|
||||
static size_t efi_file_read_image ( struct efi_file_reader *reader ) {
|
||||
struct efi_file *file = reader->file;
|
||||
struct image *image = file->image;
|
||||
|
||||
/* Read from file */
|
||||
return efi_file_read_chunk ( reader, image->data, image->len );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read from magic initrd file
|
||||
*
|
||||
* @v reader EFI file reader
|
||||
* @ret len Length read
|
||||
*/
|
||||
static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
|
||||
struct efi_file *file = reader->file;
|
||||
struct cpio_header cpio;
|
||||
struct image *image;
|
||||
const char *name;
|
||||
size_t pad_len;
|
||||
size_t cpio_len;
|
||||
size_t name_len;
|
||||
size_t len;
|
||||
|
||||
/* Read from file */
|
||||
len = 0;
|
||||
for_each_image ( image ) {
|
||||
|
||||
/* Ignore currently executing image */
|
||||
if ( image == current_image )
|
||||
continue;
|
||||
|
||||
/* Pad to alignment boundary */
|
||||
pad_len = ( ( -reader->pos ) & ( INITRD_ALIGN - 1 ) );
|
||||
if ( pad_len ) {
|
||||
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) pad\n",
|
||||
efi_file_name ( file ), reader->pos,
|
||||
( reader->pos + pad_len ) );
|
||||
}
|
||||
len += efi_file_read_chunk ( reader, UNULL, pad_len );
|
||||
|
||||
/* Read CPIO header, if applicable */
|
||||
cpio_len = cpio_header ( image, &cpio );
|
||||
if ( cpio_len ) {
|
||||
name = cpio_name ( image );
|
||||
name_len = cpio_name_len ( image );
|
||||
pad_len = ( cpio_len - sizeof ( cpio ) - name_len );
|
||||
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s header\n",
|
||||
efi_file_name ( file ), reader->pos,
|
||||
( reader->pos + cpio_len ), image->name );
|
||||
len += efi_file_read_chunk ( reader,
|
||||
virt_to_user ( &cpio ),
|
||||
sizeof ( cpio ) );
|
||||
len += efi_file_read_chunk ( reader,
|
||||
virt_to_user ( name ),
|
||||
name_len );
|
||||
len += efi_file_read_chunk ( reader, UNULL, pad_len );
|
||||
}
|
||||
|
||||
/* Read file data */
|
||||
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s\n",
|
||||
efi_file_name ( file ), reader->pos,
|
||||
( reader->pos + image->len ), image->name );
|
||||
len += efi_file_read_chunk ( reader, image->data, image->len );
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open fixed file
|
||||
*
|
||||
* @v file EFI file
|
||||
* @v new New EFI file
|
||||
* @ret efirc EFI status code
|
||||
*/
|
||||
static EFI_STATUS efi_file_open_fixed ( struct efi_file *file,
|
||||
EFI_FILE_PROTOCOL **new ) {
|
||||
|
||||
/* Increment reference count */
|
||||
ref_get ( &file->refcnt );
|
||||
|
||||
/* Return opened file */
|
||||
*new = &file->file;
|
||||
|
||||
DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate file with image
|
||||
*
|
||||
* @v file EFI file
|
||||
* @v image Image
|
||||
*/
|
||||
static void efi_file_image ( struct efi_file *file, struct image *image ) {
|
||||
|
||||
file->image = image;
|
||||
file->name = image->name;
|
||||
file->read = efi_file_read_image;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -106,50 +317,60 @@ static struct image * efi_file_find ( const CHAR16 *wname ) {
|
||||
*/
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
|
||||
CHAR16 *wname, UINT64 mode __unused,
|
||||
UINT64 attributes __unused ) {
|
||||
CHAR16 *wname, UINT64 mode, UINT64 attributes __unused ) {
|
||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
||||
char buf[ wcslen ( wname ) + 1 /* NUL */ ];
|
||||
struct efi_file *new_file;
|
||||
struct image *image;
|
||||
char *name;
|
||||
|
||||
/* Convert name to ASCII */
|
||||
snprintf ( buf, sizeof ( buf ), "%ls", wname );
|
||||
name = buf;
|
||||
|
||||
/* Initial '\' indicates opening from the root directory */
|
||||
while ( *wname == L'\\' ) {
|
||||
while ( *name == '\\' ) {
|
||||
file = &efi_file_root;
|
||||
wname++;
|
||||
name++;
|
||||
}
|
||||
|
||||
/* Allow root directory itself to be opened */
|
||||
if ( ( wname[0] == L'\0' ) || ( wname[0] == L'.' ) ) {
|
||||
*new = &efi_file_root.file;
|
||||
return 0;
|
||||
}
|
||||
if ( ( name[0] == '\0' ) || ( name[0] == '.' ) )
|
||||
return efi_file_open_fixed ( &efi_file_root, new );
|
||||
|
||||
/* Fail unless opening from the root */
|
||||
if ( file->image ) {
|
||||
if ( file != &efi_file_root ) {
|
||||
DBGC ( file, "EFIFILE %s is not a directory\n",
|
||||
efi_file_name ( file ) );
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Identify image */
|
||||
image = efi_file_find ( wname );
|
||||
if ( ! image ) {
|
||||
DBGC ( file, "EFIFILE \"%ls\" does not exist\n", wname );
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Fail unless opening read-only */
|
||||
if ( mode != EFI_FILE_MODE_READ ) {
|
||||
DBGC ( file, "EFIFILE %s cannot be opened in mode %#08llx\n",
|
||||
image->name, mode );
|
||||
name, mode );
|
||||
return EFI_WRITE_PROTECTED;
|
||||
}
|
||||
|
||||
/* Allow magic initrd to be opened */
|
||||
if ( strcasecmp ( name, efi_file_initrd.name ) == 0 )
|
||||
return efi_file_open_fixed ( &efi_file_initrd, new );
|
||||
|
||||
/* Identify image */
|
||||
image = efi_file_find ( name );
|
||||
if ( ! image ) {
|
||||
DBGC ( file, "EFIFILE %s does not exist\n", name );
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Allocate and initialise file */
|
||||
new_file = zalloc ( sizeof ( *new_file ) );
|
||||
if ( ! new_file )
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
ref_init ( &file->refcnt, efi_file_free );
|
||||
memcpy ( &new_file->file, &efi_file_root.file,
|
||||
sizeof ( new_file->file ) );
|
||||
new_file->image = image_get ( image );
|
||||
efi_file_image ( new_file, image_get ( image ) );
|
||||
*new = &new_file->file;
|
||||
DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
|
||||
|
||||
@ -165,14 +386,9 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
|
||||
static EFI_STATUS EFIAPI efi_file_close ( EFI_FILE_PROTOCOL *this ) {
|
||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
||||
|
||||
/* Do nothing if this is the root */
|
||||
if ( ! file->image )
|
||||
return 0;
|
||||
|
||||
/* Close file */
|
||||
DBGC ( file, "EFIFILE %s closed\n", efi_file_name ( file ) );
|
||||
image_put ( file->image );
|
||||
free ( file );
|
||||
ref_put ( &file->refcnt );
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -229,30 +445,29 @@ static EFI_STATUS efi_file_varlen ( UINT64 *base, size_t base_len,
|
||||
/**
|
||||
* Return file information structure
|
||||
*
|
||||
* @v image Image, or NULL for the root directory
|
||||
* @v file EFI file
|
||||
* @v len Length of data buffer
|
||||
* @v data Data buffer
|
||||
* @ret efirc EFI status code
|
||||
*/
|
||||
static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
|
||||
static EFI_STATUS efi_file_info ( struct efi_file *file, UINTN *len,
|
||||
VOID *data ) {
|
||||
EFI_FILE_INFO info;
|
||||
const char *name;
|
||||
size_t file_len;
|
||||
|
||||
/* Get file length */
|
||||
file_len = efi_file_len ( file );
|
||||
|
||||
/* Populate file information */
|
||||
memset ( &info, 0, sizeof ( info ) );
|
||||
if ( image ) {
|
||||
info.FileSize = image->len;
|
||||
info.PhysicalSize = image->len;
|
||||
info.Attribute = EFI_FILE_READ_ONLY;
|
||||
name = image->name;
|
||||
} else {
|
||||
info.Attribute = ( EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY );
|
||||
name = "";
|
||||
}
|
||||
info.FileSize = file_len;
|
||||
info.PhysicalSize = file_len;
|
||||
info.Attribute = EFI_FILE_READ_ONLY;
|
||||
if ( file == &efi_file_root )
|
||||
info.Attribute |= EFI_FILE_DIRECTORY;
|
||||
|
||||
return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO, name,
|
||||
len, data );
|
||||
return efi_file_varlen ( &info.Size, SIZE_OF_EFI_FILE_INFO,
|
||||
file->name, len, data );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -266,14 +481,16 @@ static EFI_STATUS efi_file_info ( struct image *image, UINTN *len,
|
||||
static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
|
||||
VOID *data ) {
|
||||
EFI_STATUS efirc;
|
||||
struct efi_file entry;
|
||||
struct image *image;
|
||||
unsigned int index;
|
||||
|
||||
/* Construct directory entry at current position */
|
||||
/* Construct directory entries for image-backed files */
|
||||
index = file->pos;
|
||||
for_each_image ( image ) {
|
||||
if ( index-- == 0 ) {
|
||||
efirc = efi_file_info ( image, len, data );
|
||||
efi_file_image ( &entry, image );
|
||||
efirc = efi_file_info ( &entry, len, data );
|
||||
if ( efirc == 0 )
|
||||
file->pos++;
|
||||
return efirc;
|
||||
@ -296,21 +513,25 @@ static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
|
||||
static EFI_STATUS EFIAPI efi_file_read ( EFI_FILE_PROTOCOL *this,
|
||||
UINTN *len, VOID *data ) {
|
||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
||||
size_t remaining;
|
||||
struct efi_file_reader reader;
|
||||
size_t pos = file->pos;
|
||||
|
||||
/* If this is the root directory, then construct a directory entry */
|
||||
if ( ! file->image )
|
||||
if ( ! file->read )
|
||||
return efi_file_read_dir ( file, len, data );
|
||||
|
||||
/* Initialise reader */
|
||||
reader.file = file;
|
||||
reader.pos = 0;
|
||||
reader.data = data;
|
||||
reader.len = *len;
|
||||
|
||||
/* Read from the file */
|
||||
remaining = ( file->image->len - file->pos );
|
||||
if ( *len > remaining )
|
||||
*len = remaining;
|
||||
DBGC ( file, "EFIFILE %s read [%#08zx,%#08zx)\n",
|
||||
efi_file_name ( file ), file->pos,
|
||||
( ( size_t ) ( file->pos + *len ) ) );
|
||||
copy_from_user ( data, file->image->data, file->pos, *len );
|
||||
file->pos += *len;
|
||||
efi_file_name ( file ), pos, file->pos );
|
||||
*len = file->read ( &reader );
|
||||
assert ( ( pos + *len ) == file->pos );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -342,24 +563,21 @@ static EFI_STATUS EFIAPI efi_file_write ( EFI_FILE_PROTOCOL *this,
|
||||
static EFI_STATUS EFIAPI efi_file_set_position ( EFI_FILE_PROTOCOL *this,
|
||||
UINT64 position ) {
|
||||
struct efi_file *file = container_of ( this, struct efi_file, file );
|
||||
size_t len;
|
||||
|
||||
/* If this is the root directory, reset to the start */
|
||||
if ( ! file->image ) {
|
||||
DBGC ( file, "EFIFILE root directory rewound\n" );
|
||||
file->pos = 0;
|
||||
return 0;
|
||||
}
|
||||
/* Get file length */
|
||||
len = efi_file_len ( file );
|
||||
|
||||
/* Check for the magic end-of-file value */
|
||||
if ( position == 0xffffffffffffffffULL )
|
||||
position = file->image->len;
|
||||
position = len;
|
||||
|
||||
/* Fail if we attempt to seek past the end of the file (since
|
||||
* we do not support writes).
|
||||
*/
|
||||
if ( position > file->image->len ) {
|
||||
if ( position > len ) {
|
||||
DBGC ( file, "EFIFILE %s cannot seek to %#08llx of %#08zx\n",
|
||||
efi_file_name ( file ), position, file->image->len );
|
||||
efi_file_name ( file ), position, len );
|
||||
return EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
@ -408,7 +626,7 @@ static EFI_STATUS EFIAPI efi_file_get_info ( EFI_FILE_PROTOCOL *this,
|
||||
/* Get file information */
|
||||
DBGC ( file, "EFIFILE %s get file information\n",
|
||||
efi_file_name ( file ) );
|
||||
return efi_file_info ( file->image, len, data );
|
||||
return efi_file_info ( file, len, data );
|
||||
|
||||
} else if ( memcmp ( type, &efi_file_system_info_id,
|
||||
sizeof ( *type ) ) == 0 ) {
|
||||
@ -468,6 +686,7 @@ static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
|
||||
|
||||
/** Root directory */
|
||||
static struct efi_file efi_file_root = {
|
||||
.refcnt = REF_INIT ( ref_no_free ),
|
||||
.file = {
|
||||
.Revision = EFI_FILE_PROTOCOL_REVISION,
|
||||
.Open = efi_file_open,
|
||||
@ -482,6 +701,28 @@ static struct efi_file efi_file_root = {
|
||||
.Flush = efi_file_flush,
|
||||
},
|
||||
.image = NULL,
|
||||
.name = "",
|
||||
};
|
||||
|
||||
/** Magic initrd file */
|
||||
static struct efi_file efi_file_initrd = {
|
||||
.refcnt = REF_INIT ( ref_no_free ),
|
||||
.file = {
|
||||
.Revision = EFI_FILE_PROTOCOL_REVISION,
|
||||
.Open = efi_file_open,
|
||||
.Close = efi_file_close,
|
||||
.Delete = efi_file_delete,
|
||||
.Read = efi_file_read,
|
||||
.Write = efi_file_write,
|
||||
.GetPosition = efi_file_get_position,
|
||||
.SetPosition = efi_file_set_position,
|
||||
.GetInfo = efi_file_get_info,
|
||||
.SetInfo = efi_file_set_info,
|
||||
.Flush = efi_file_flush,
|
||||
},
|
||||
.image = NULL,
|
||||
.name = "initrd.magic",
|
||||
.read = efi_file_read_initrd,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -496,8 +737,7 @@ efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
|
||||
EFI_FILE_PROTOCOL **file ) {
|
||||
|
||||
DBGC ( &efi_file_root, "EFIFILE open volume\n" );
|
||||
*file = &efi_file_root.file;
|
||||
return 0;
|
||||
return efi_file_open_fixed ( &efi_file_root, file );
|
||||
}
|
||||
|
||||
/** EFI simple file system protocol */
|
||||
|
||||
@ -47,6 +47,9 @@ EFI_DEVICE_PATH_PROTOCOL *efi_loaded_image_path;
|
||||
*/
|
||||
EFI_SYSTEM_TABLE * _C2 ( PLATFORM, _systab );
|
||||
|
||||
/** Internal task priority level */
|
||||
EFI_TPL efi_internal_tpl = TPL_CALLBACK;
|
||||
|
||||
/** External task priority level */
|
||||
EFI_TPL efi_external_tpl = TPL_APPLICATION;
|
||||
|
||||
@ -79,6 +82,17 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
|
||||
static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
|
||||
void *context __unused ) {
|
||||
|
||||
/* This callback is invoked at TPL_NOTIFY in order to ensure
|
||||
* that we have an opportunity to shut down cleanly before
|
||||
* other shutdown hooks perform destructive operations such as
|
||||
* disabling the IOMMU.
|
||||
*
|
||||
* Modify the internal task priority level so that no code
|
||||
* attempts to raise from TPL_NOTIFY to TPL_CALLBACK (which
|
||||
* would trigger a fatal exception).
|
||||
*/
|
||||
efi_internal_tpl = TPL_NOTIFY;
|
||||
|
||||
/* Mark shutdown as being in progress, to indicate that large
|
||||
* parts of the system (e.g. timers) are no longer functional.
|
||||
*/
|
||||
@ -273,7 +287,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||
* bother doing so when ExitBootServices() is called.
|
||||
*/
|
||||
if ( ( efirc = bs->CreateEvent ( EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
||||
TPL_CALLBACK, efi_shutdown_hook,
|
||||
TPL_NOTIFY, efi_shutdown_hook,
|
||||
NULL, &efi_shutdown_event ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( systab, "EFI could not create ExitBootServices event: "
|
||||
@ -316,9 +330,13 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
||||
static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_SYSTEM_TABLE *systab = efi_systab;
|
||||
struct efi_saved_tpl tpl;
|
||||
|
||||
DBGC ( systab, "EFI image unloading\n" );
|
||||
|
||||
/* Raise TPL */
|
||||
efi_raise_tpl ( &tpl );
|
||||
|
||||
/* Shut down */
|
||||
shutdown_exit();
|
||||
|
||||
@ -336,6 +354,9 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
|
||||
|
||||
DBGC ( systab, "EFI image unloaded\n" );
|
||||
|
||||
/* Restore TPL */
|
||||
efi_restore_tpl ( &tpl );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -366,7 +387,7 @@ __attribute__ (( noreturn )) void __stack_chk_fail ( void ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Raise task priority level to TPL_CALLBACK
|
||||
* Raise task priority level to internal level
|
||||
*
|
||||
* @v tpl Saved TPL
|
||||
*/
|
||||
@ -377,7 +398,7 @@ void efi_raise_tpl ( struct efi_saved_tpl *tpl ) {
|
||||
tpl->previous = efi_external_tpl;
|
||||
|
||||
/* Raise TPL and record previous TPL as new external TPL */
|
||||
tpl->current = bs->RaiseTPL ( TPL_CALLBACK );
|
||||
tpl->current = bs->RaiseTPL ( efi_internal_tpl );
|
||||
efi_external_tpl = tpl->current;
|
||||
}
|
||||
|
||||
|
||||
@ -337,6 +337,9 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
|
||||
offset = le64_to_cpu ( u.res->qword.offset );
|
||||
start = ( offset + le64_to_cpu ( u.res->qword.min ) );
|
||||
end = ( start + le64_to_cpu ( u.res->qword.len ) );
|
||||
DBGC2 ( pci, "EFIPCI " PCI_FMT " found range [%08llx,%08llx) "
|
||||
"-> [%08llx,%08llx)\n", PCI_ARGS ( pci ), start, end,
|
||||
( start - offset ), ( end - offset ) );
|
||||
if ( ( bus_addr < start ) || ( ( bus_addr + len ) > end ) )
|
||||
continue;
|
||||
|
||||
@ -523,7 +526,8 @@ static void * efipci_dma_alloc ( struct dma_device *dma,
|
||||
|
||||
/* Map buffer */
|
||||
if ( ( rc = efipci_dma_map ( dma, map, virt_to_phys ( addr ),
|
||||
len, DMA_BI ) ) != 0 )
|
||||
( pages * EFI_PAGE_SIZE ),
|
||||
DMA_BI ) ) != 0 )
|
||||
goto err_map;
|
||||
|
||||
/* Increment allocation count (for debugging) */
|
||||
|
||||
@ -137,7 +137,7 @@ static unsigned long efi_currticks ( void ) {
|
||||
efi_jiffies++;
|
||||
} else {
|
||||
bs->RestoreTPL ( efi_external_tpl );
|
||||
bs->RaiseTPL ( TPL_CALLBACK );
|
||||
bs->RaiseTPL ( efi_internal_tpl );
|
||||
}
|
||||
|
||||
return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );
|
||||
|
||||
@ -362,7 +362,7 @@ static int efi_veto_driver ( EFI_HANDLE driver ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Veto Dell Ip4ConfigDxe driver
|
||||
* Veto Ip4ConfigDxe driver on some platforms
|
||||
*
|
||||
* @v binding Driver binding protocol
|
||||
* @v loaded Loaded image protocol
|
||||
@ -372,19 +372,21 @@ static int efi_veto_driver ( EFI_HANDLE driver ) {
|
||||
* @ret vetoed Driver is to be vetoed
|
||||
*/
|
||||
static int
|
||||
efi_veto_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
|
||||
EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
|
||||
const char *manufacturer, const CHAR16 *name ) {
|
||||
efi_veto_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
|
||||
EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
|
||||
const char *manufacturer, const CHAR16 *name ) {
|
||||
static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
|
||||
static const char *dell = "Dell Inc.";
|
||||
static const char *itautec = "Itautec S.A.";
|
||||
|
||||
/* Check manufacturer and driver name */
|
||||
if ( ! manufacturer )
|
||||
return 0;
|
||||
if ( ! name )
|
||||
return 0;
|
||||
if ( strcmp ( manufacturer, dell ) != 0 )
|
||||
if ( ( strcmp ( manufacturer, dell ) != 0 ) &&
|
||||
( strcmp ( manufacturer, itautec ) != 0 ) )
|
||||
return 0;
|
||||
if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 )
|
||||
return 0;
|
||||
@ -436,8 +438,8 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
|
||||
/** Driver vetoes */
|
||||
static struct efi_veto efi_vetoes[] = {
|
||||
{
|
||||
.name = "Dell Ip4Config",
|
||||
.veto = efi_veto_dell_ip4config,
|
||||
.name = "Ip4Config",
|
||||
.veto = efi_veto_ip4config,
|
||||
},
|
||||
{
|
||||
.name = "HP Xhci",
|
||||
|
||||
@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <string.h>
|
||||
#include <ipxe/retry.h>
|
||||
#include <ipxe/timer.h>
|
||||
#include <ipxe/init.h>
|
||||
#include <ipxe/efi/efi.h>
|
||||
#include <ipxe/efi/efi_watchdog.h>
|
||||
|
||||
@ -80,3 +81,36 @@ static void efi_watchdog_expired ( struct retry_timer *timer,
|
||||
|
||||
/** Watchdog holdoff timer */
|
||||
struct retry_timer efi_watchdog = TIMER_INIT ( efi_watchdog_expired );
|
||||
|
||||
/**
|
||||
* Disable watching when shutting down to boot an operating system
|
||||
*
|
||||
* @v booting System is shutting down for OS boot
|
||||
*/
|
||||
static void efi_watchdog_shutdown ( int booting ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* If we are shutting down to boot an operating system, then
|
||||
* disable the boot services watchdog timer. The UEFI
|
||||
* specification mandates that the platform firmware does this
|
||||
* as part of the ExitBootServices() call, but some platforms
|
||||
* (e.g. Hyper-V) are observed to occasionally forget to do
|
||||
* so, resulting in a reboot approximately five minutes after
|
||||
* starting the operating system.
|
||||
*/
|
||||
if ( booting &&
|
||||
( ( efirc = bs->SetWatchdogTimer ( 0, 0, 0, NULL ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( &efi_watchdog, "EFI could not disable watchdog timer: "
|
||||
"%s\n", strerror ( rc ) );
|
||||
/* Nothing we can do */
|
||||
}
|
||||
}
|
||||
|
||||
/** Watchdog startup/shutdown function */
|
||||
struct startup_fn efi_watchdog_startup_fn __startup_fn ( STARTUP_EARLY ) = {
|
||||
.name = "efi_watchdog",
|
||||
.shutdown = efi_watchdog_shutdown,
|
||||
};
|
||||
|
||||
@ -195,6 +195,47 @@ static const char * efi_timer_delay ( EFI_TIMER_DELAY type ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump information about a loaded image
|
||||
*
|
||||
* @v handle Image handle
|
||||
*/
|
||||
static void efi_dump_image ( EFI_HANDLE handle ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
union {
|
||||
EFI_LOADED_IMAGE_PROTOCOL *image;
|
||||
void *intf;
|
||||
} loaded;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Open loaded image protocol */
|
||||
if ( ( efirc = bs->OpenProtocol ( handle,
|
||||
&efi_loaded_image_protocol_guid,
|
||||
&loaded.intf, efi_image_handle, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( colour, "WRAP %s could not get loaded image protocol: "
|
||||
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dump image information */
|
||||
DBGC ( colour, "WRAP %s at base %p has protocols:\n",
|
||||
efi_handle_name ( handle ), loaded.image->ImageBase );
|
||||
DBGC_EFI_PROTOCOLS ( colour, handle );
|
||||
DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle ));
|
||||
DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle ));
|
||||
DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) );
|
||||
|
||||
/* Close loaded image protocol */
|
||||
bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid,
|
||||
efi_image_handle, NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap RaiseTPL()
|
||||
*
|
||||
@ -655,9 +696,9 @@ efi_load_image_wrapper ( BOOLEAN boot_policy, EFI_HANDLE parent_image_handle,
|
||||
DBGC ( colour, "%s ", efi_handle_name ( *image_handle ) );
|
||||
DBGC ( colour, ") -> %p\n", retaddr );
|
||||
|
||||
/* Wrap the new image */
|
||||
/* Dump information about loaded image */
|
||||
if ( efirc == 0 )
|
||||
efi_wrap ( *image_handle );
|
||||
efi_dump_image ( *image_handle );
|
||||
|
||||
return efirc;
|
||||
}
|
||||
@ -735,11 +776,14 @@ efi_exit_boot_services_wrapper ( EFI_HANDLE image_handle, UINTN map_key ) {
|
||||
void *retaddr = __builtin_return_address ( 0 );
|
||||
EFI_STATUS efirc;
|
||||
|
||||
DBGC ( colour, "ExitBootServices ( %s, %#llx ) ",
|
||||
DBGC ( colour, "ExitBootServices ( %s, %#llx ) -> %p\n",
|
||||
efi_handle_name ( image_handle ),
|
||||
( ( unsigned long long ) map_key ) );
|
||||
( ( unsigned long long ) map_key ), retaddr );
|
||||
efirc = bs->ExitBootServices ( image_handle, map_key );
|
||||
DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
|
||||
if ( efirc != 0 ) {
|
||||
DBGC ( colour, "ExitBootServices ( ... ) = %s -> %p\n",
|
||||
efi_status ( efirc ), retaddr );
|
||||
}
|
||||
return efirc;
|
||||
}
|
||||
|
||||
@ -1129,12 +1173,11 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl,
|
||||
}
|
||||
|
||||
/**
|
||||
* Build table wrappers
|
||||
* Build boot services table wrapper
|
||||
*
|
||||
* @ret systab Wrapped system table
|
||||
* @ret bs Wrapped boot services table
|
||||
*/
|
||||
EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
|
||||
static EFI_SYSTEM_TABLE efi_systab_wrapper;
|
||||
EFI_BOOT_SERVICES * efi_wrap_bs ( void ) {
|
||||
static EFI_BOOT_SERVICES efi_bs_wrapper;
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
|
||||
@ -1194,12 +1237,7 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
|
||||
= efi_uninstall_multiple_protocol_interfaces_wrapper;
|
||||
efi_bs_wrapper.CreateEventEx = efi_create_event_ex_wrapper;
|
||||
|
||||
/* Build system table wrapper */
|
||||
memcpy ( &efi_systab_wrapper, efi_systab,
|
||||
sizeof ( efi_systab_wrapper ) );
|
||||
efi_systab_wrapper.BootServices = &efi_bs_wrapper;
|
||||
|
||||
return &efi_systab_wrapper;
|
||||
return &efi_bs_wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1208,42 +1246,20 @@ EFI_SYSTEM_TABLE * efi_wrap_systab ( void ) {
|
||||
* @v handle Image handle
|
||||
*/
|
||||
void efi_wrap ( EFI_HANDLE handle ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
union {
|
||||
EFI_LOADED_IMAGE_PROTOCOL *image;
|
||||
void *intf;
|
||||
} loaded;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
static EFI_SYSTEM_TABLE efi_systab_copy;
|
||||
|
||||
/* Do nothing unless debugging is enabled */
|
||||
if ( ! DBG_LOG )
|
||||
return;
|
||||
|
||||
/* Open loaded image protocol */
|
||||
if ( ( efirc = bs->OpenProtocol ( handle,
|
||||
&efi_loaded_image_protocol_guid,
|
||||
&loaded.intf, efi_image_handle, NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( colour, "WRAP %s could not get loaded image protocol: "
|
||||
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
|
||||
return;
|
||||
/* Construct modified system table */
|
||||
if ( efi_systab != &efi_systab_copy ) {
|
||||
memcpy ( &efi_systab_copy, efi_systab,
|
||||
sizeof ( efi_systab_copy ) );
|
||||
efi_systab->BootServices = efi_wrap_bs();
|
||||
efi_systab = &efi_systab_copy;
|
||||
}
|
||||
|
||||
/* Provide system table wrapper to image */
|
||||
loaded.image->SystemTable = efi_wrap_systab();
|
||||
DBGC ( colour, "WRAP %s at base %p has protocols:\n",
|
||||
efi_handle_name ( handle ), loaded.image->ImageBase );
|
||||
DBGC_EFI_PROTOCOLS ( colour, handle );
|
||||
DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle ));
|
||||
DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle ));
|
||||
DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) );
|
||||
DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) );
|
||||
|
||||
/* Close loaded image protocol */
|
||||
bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid,
|
||||
efi_image_handle, NULL );
|
||||
/* Dump image information */
|
||||
efi_dump_image ( handle );
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user