2
0
mirror of https://github.com/xcat2/xNBA.git synced 2026-09-26 01:33:59 +00:00

Merge git://git.ipxe.org/ipxe

This commit is contained in:
Jarrod Johnson
2011-01-28 16:49:39 -05:00
57 changed files with 1380 additions and 811 deletions
+1
View File
@@ -300,6 +300,7 @@ ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
#=======================================================================
#boot: floppy
#boot: disk
boot: network, floppy
#=======================================================================
# CLOCK:
+3 -3
View File
@@ -114,13 +114,13 @@ struct root_device undi_root_device __root_device = {
/**
* Prepare for exit
*
* @v flags Shutdown flags
* @v booting System is shutting down for OS boot
*/
static void undionly_shutdown ( int flags ) {
static void undionly_shutdown ( int booting ) {
/* If we are shutting down to boot an OS, clear the "keep PXE
* stack" flag.
*/
if ( flags & SHUTDOWN_BOOT )
if ( booting )
preloaded_undi.flags &= ~UNDI_FL_KEEP_ALL;
}
+1 -1
View File
@@ -477,7 +477,7 @@ static int bzimage_exec ( struct image *image ) {
bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
/* Prepare for exiting */
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
DBGC ( image, "bzImage %p jumping to RM kernel at %04x:0000 "
"(stack %04x:%04zx)\n", image, ( bzimg.rm_kernel_seg + 0x20 ),
+1 -1
View File
@@ -48,7 +48,7 @@ static int elfboot_exec ( struct image *image ) {
/* An ELF image has no callback interface, so we need to shut
* down before invoking it.
*/
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
/* Jump to OS with flat physical addressing */
DBGC ( image, "ELF %p starting execution at %lx\n", image, entry );
+1 -1
View File
@@ -278,7 +278,7 @@ static int multiboot_exec ( struct image *image ) {
/* Multiboot images may not return and have no callback
* interface, so shut everything down prior to booting the OS.
*/
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
/* Build memory map after unhiding bootloader memory regions as part of
* shutting everything down.
+1 -1
View File
@@ -406,7 +406,7 @@ static int nbi_exec ( struct image *image ) {
/* Shut down now if NBI image will not return */
may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
if ( ! may_return )
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
/* Execute NBI image */
if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
+6 -2
View File
@@ -1209,8 +1209,10 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) {
int13->cylinders, int13->heads, int13->sectors_per_track );
/* Hook INT 13 vector if not already hooked */
if ( list_empty ( &int13s ) )
if ( list_empty ( &int13s ) ) {
int13_hook_vector();
devices_get();
}
/* Add to list of emulated drives */
list_add ( &int13->list, &int13s );
@@ -1277,8 +1279,10 @@ static void int13_unhook ( unsigned int drive ) {
DBGC ( int13, "INT13 drive %02x unregistered\n", int13->drive );
/* Unhook INT 13 vector if no more drives */
if ( list_empty ( &int13s ) )
if ( list_empty ( &int13s ) ) {
devices_put();
int13_unhook_vector();
}
/* Drop list's reference to drive */
ref_put ( &int13->refcnt );
+2
View File
@@ -448,6 +448,7 @@ void pxe_activate ( struct net_device *netdev ) {
if ( ! int_1a_hooked ) {
hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a,
&pxe_int_1a_vector );
devices_get();
int_1a_hooked = 1;
}
@@ -475,6 +476,7 @@ int pxe_deactivate ( void ) {
strerror ( rc ) );
return rc;
}
devices_put();
int_1a_hooked = 0;
}
+1 -1
View File
@@ -290,7 +290,7 @@ PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
pxe_deactivate();
/* Prepare for unload */
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
/* Check to see if we still have any hooked interrupts */
if ( hooked_bios_interrupts != 0 ) {
+3 -1
View File
@@ -615,7 +615,9 @@ PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
undi_get_iface_info->ServiceFlags =
( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
SUPPORTED_OPEN_CLOSE | SUPPORTED_IRQ );
SUPPORTED_OPEN_CLOSE );
if ( netdev_irq_supported ( pxe_netdev ) )
undi_get_iface_info->ServiceFlags |= SUPPORTED_IRQ;
memset ( undi_get_iface_info->Reserved, 0,
sizeof(undi_get_iface_info->Reserved) );
@@ -531,7 +531,7 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
break;
/* Perform final cleanup */
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
/* Perform sequence of copies */
shuffle ( ix86->segs.es, ix86->regs.di, ix86->regs.cx );
@@ -608,7 +608,7 @@ static __asmcall void int22 ( struct i386_all_regs *ix86 ) {
break;
/* Perform final cleanup */
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
/* Perform sequence of copies */
shuffle ( ix86->segs.es, ix86->regs.di, ix86->regs.cx );
+194 -43
View File
@@ -24,6 +24,9 @@ FILE_LICENCE ( GPL2_OR_LATER )
/* Image compression enabled */
#define COMPRESS 1
/* Protected mode flag */
#define CR0_PE 1
/*****************************************************************************
* Utility function: print character (with LF -> LF,CR translation)
*
@@ -229,16 +232,186 @@ print_kill_line:
* None
****************************************************************************
*/
#if ! COMPRESS
.section ".prefix.lib", "awx", @progbits
.code16
copy_bytes:
pushl %ecx
pushl %ecx
rep addr32 movsb
popl %ecx
popl %ecx
ret
.size copy_bytes, . - copy_bytes
#endif /* COMPRESS */
.size copy_bytes, . - copy_bytes
/****************************************************************************
* zero_bytes
*
* Zero bytes
*
* Parameters:
* %ds:esi : source address
* %es:edi : destination address
* %ecx : length
* Returns:
* %ds:esi : next source address
* %es:edi : next destination address
* Corrupts:
* None
****************************************************************************
*/
.section ".prefix.lib", "awx", @progbits
.code16
zero_bytes:
pushl %ecx
pushw %ax
xorw %ax, %ax
rep addr32 stosb
popw %ax
popl %ecx
ret
.size zero_bytes, . - zero_bytes
/****************************************************************************
* process_bytes
*
* Call memcpy()-like function
*
* Parameters:
* %esi : source physical address
* %edi : destination physical address
* %ecx : length
* %bx : memcpy()-like function to call, passing parameters:
* %ds:esi : source address
* %es:edi : destination address
* %ecx : length
* and returning:
* %ds:esi : next source address
* %es:edi : next destination address
* Returns:
* %esi : next source physical address
* %edi : next destination physical address
* Corrupts:
* None
****************************************************************************
*/
.section ".prefix.lib", "awx", @progbits
.code16
process_bytes:
#ifndef KEEP_IT_REAL
/* Preserve registers */
pushfw
pushl %eax
pushl %ebp
/* Construct GDT on stack (since .prefix may not be writable) */
.equ PM_DS, 0x18 /* Flat data segment */
pushl $0x008f9300
pushl $0x0000ffff
.equ PM_SS, 0x10 /* Stack segment based at %ss:0000 */
pushl $0x008f0930
pushw %ss
pushw $0xffff
.equ PM_CS, 0x08 /* Code segment based at %cs:0000 */
pushl $0x008f09b0
pushw %cs
pushw $0xffff
pushl $0 /* Base and length */
pushw %ss
pushw $0x1f
movzwl %sp, %ebp
shll $4, 0x02(%bp)
addl %ebp, 0x02(%bp)
shll $4, 0x0a(%bp)
shll $4, 0x12(%bp)
subw $8, %sp
sgdt -8(%bp)
/* Switch to protected mode */
pushw %gs
pushw %fs
pushw %es
pushw %ds
pushw %ss
pushw %cs
pushw $2f
cli
data32 lgdt (%bp)
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
ljmp $PM_CS, $1f
1: movw $PM_SS, %ax
movw %ax, %ss
movw $PM_DS, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
/* Call memcpy()-like function */
call *%bx
/* Return to (flat) real mode */
movl %cr0, %eax
andb $0!CR0_PE, %al
movl %eax, %cr0
lret
2: /* lret will ljmp to here */
popw %ss
popw %ds
popw %es
popw %fs
popw %gs
/* Restore GDT */
data32 lgdt -8(%bp)
addw $( 8 /* saved GDT */ + ( PM_DS + 8 ) /* GDT on stack */ ), %sp
/* Restore registers and return */
popl %ebp
popl %eax
popfw
ret
#else /* KEEP_IT_REAL */
/* Preserve registers */
pushl %eax
pushw %ds
pushw %es
/* Convert %esi and %edi to %ds:esi and %es:edi */
shrl $4, %esi
movw %si, %ds
xorw %si, %si
shll $4, %esi
shrl $4, %edi
movw %di, %es
xorw %di, %di
shll $4, %edi
/* Call memcpy()-like function */
call *%bx
/* Convert %ds:esi and %es:edi back to physical addresses */
xorl %eax, %eax
movw %ds, %cx
shll $4, %eax
addl %eax, %esi
xorl %eax, %eax
movw %es, %cx
shll $4, %eax
addl %eax, %edi
/* Restore registers and return */
popw %es
popw %ds
popl %eax
ret
#endif /* KEEP_IT_REAL */
.size process_bytes, . - process_bytes
/****************************************************************************
* install_block
@@ -261,35 +434,22 @@ copy_bytes:
.code16
install_block:
/* Preserve registers */
pushw %ds
pushw %es
pushl %ecx
/* Convert %esi and %edi to %ds:esi and %es:edi */
shrl $4, %esi
movw %si, %ds
xorw %si, %si
shll $4, %esi
shrl $4, %edi
movw %di, %es
xorw %di, %di
shll $4, %edi
pushw %bx
/* Decompress (or copy) source to destination */
#if COMPRESS
/* Decompress source to destination */
call decompress16
movw $decompress16, %bx
#else
/* Copy source to destination */
call copy_bytes
movw $copy_bytes, %bx
#endif
call process_bytes
/* Zero .bss portion */
negl %ecx
addl %edx, %ecx
pushw %ax
xorw %ax, %ax
rep addr32 stosb
popw %ax
movw $zero_bytes, %bx
call process_bytes
/* Round up %esi and %edi to start of next blocks */
addl $0xf, %esi
@@ -297,20 +457,9 @@ install_block:
addl $0xf, %edi
andl $~0xf, %edi
/* Convert %ds:esi and %es:edi back to physical addresses */
xorl %ecx, %ecx
movw %ds, %cx
shll $4, %ecx
addl %ecx, %esi
xorl %ecx, %ecx
movw %es, %cx
shll $4, %ecx
addl %ecx, %edi
/* Restore registers and return */
popw %bx
popl %ecx
popw %es
popw %ds
ret
.size install_block, . - install_block
@@ -500,7 +649,10 @@ install_prealloc:
popl %esi
#ifndef KEEP_IT_REAL
/* Access high memory */
/* Access high memory by enabling the A20 gate. (We will
* already have 4GB segment limits as a result of calling
* install_block.)
*/
pushw %cs
pushw $1f
pushw %ax
@@ -612,11 +764,10 @@ payload_death_message:
/* Copy code to new location */
pushl %edi
pushw %ax
xorw %ax, %ax
movw %ax, %es
es rep addr32 movsb
popw %ax
pushw %bx
movw $copy_bytes, %bx
call process_bytes
popw %bx
popl %edi
/* Initialise librm at new location */
+6 -1
View File
@@ -151,7 +151,12 @@ find_mem_bar:
/* Copy payload to buffer, or set buffer address to BAR address */
testl %esi, %esi
jz 1f
/* We have a buffer; copy payload to it */
/* We have a buffer; copy payload to it. Since .mrom is
* designed specifically for real hardware, we assume that
* flat real mode is working properly. (In the unlikely event
* that this code is run inside a hypervisor that doesn't
* properly support flat real mode, it will die horribly.)
*/
pushl %esi
pushw %es
movl %esi, %edi
@@ -21,124 +21,6 @@ FILE_LICENCE ( GPL2_OR_LATER )
.arch i386
#define CR0_PE 1
/****************************************************************************
* flatten_real_mode
*
* Set up 4GB segment limits
*
* Parameters:
* none
* Returns:
* none
* Corrupts:
* none
****************************************************************************
*/
/* GDT for protected-mode calls */
.section ".text16.early.data", "aw", @progbits
.align 16
flatten_gdt:
flatten_gdt_limit: .word flatten_gdt_length - 1
flatten_gdt_base: .long 0
.word 0 /* padding */
flatten_cs: /* 16-bit protected-mode flat code segment */
.equ FLAT_CS, flatten_cs - flatten_gdt
.word 0xffff, 0
.byte 0, 0x9b, 0x8f, 0
flatten_ss: /* 16-bit protected-mode flat stack segment */
.equ FLAT_SS, flatten_ss - flatten_gdt
.word 0xffff, 0
.byte 0, 0x93, 0x8f, 0
flatten_gdt_end:
.equ flatten_gdt_length, . - flatten_gdt
.size flatten_gdt, . - flatten_gdt
.section ".text16.early.data", "aw", @progbits
.align 16
flatten_saved_gdt:
.long 0, 0
.size flatten_saved_gdt, . - flatten_saved_gdt
.section ".text16.early", "awx", @progbits
.code16
flatten_real_mode:
/* Preserve registers and flags */
pushfl
pushl %eax
pushw %si
pushw %gs
pushw %fs
pushw %es
pushw %ds
pushw %ss
/* Set %ds for access to .text16.early.data variables */
pushw %cs
popw %ds
/* Preserve original GDT */
sgdt flatten_saved_gdt
/* Set up GDT bases */
xorl %eax, %eax
movw %cs, %ax
shll $4, %eax
addl $flatten_gdt, %eax
movl %eax, flatten_gdt_base
movw %cs, %ax
movw $flatten_cs, %si
call set_seg_base
movw %ss, %ax
movw $flatten_ss, %si
call set_seg_base
/* Switch temporarily to protected mode and set segment registers */
pushw %cs
pushw $2f
cli
data32 lgdt flatten_gdt
movl %cr0, %eax
orb $CR0_PE, %al
movl %eax, %cr0
ljmp $FLAT_CS, $1f
1: movw $FLAT_SS, %ax
movw %ax, %ss
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movl %cr0, %eax
andb $0!CR0_PE, %al
movl %eax, %cr0
lret
2: /* lret will ljmp to here */
/* Restore GDT, registers and flags */
data32 lgdt flatten_saved_gdt
popw %ss
popw %ds
popw %es
popw %fs
popw %gs
popw %si
popl %eax
popfl
ret
.size flatten_real_mode, . - flatten_real_mode
.section ".text16.early", "awx", @progbits
.code16
set_seg_base:
rolw $4, %ax
movw %ax, 2(%si)
andw $0xfff0, 2(%si)
movb %al, 4(%si)
andb $0x0f, 4(%si)
ret
.size set_seg_base, . - set_seg_base
/****************************************************************************
* test_a20_short, test_a20_long
*
@@ -403,7 +285,7 @@ enable_a20_method:
/****************************************************************************
* access_highmem (real mode far call)
*
* Open up access to high memory in flat real mode with A20 enabled
* Open up access to high memory with A20 enabled
*
* Parameters:
* none
@@ -419,7 +301,5 @@ enable_a20_method:
access_highmem:
/* Enable A20 line */
call enable_a20
/* Set up 4GB limits */
call flatten_real_mode
lret
.size access_highmem, . - access_highmem
+5 -2
View File
@@ -35,6 +35,9 @@ FILE_LICENCE ( GPL2_OR_LATER );
/** Registered root devices */
static LIST_HEAD ( devices );
/** Device removal inhibition counter */
int device_keep_count = 0;
/**
* Probe a root device
*
@@ -87,11 +90,11 @@ static void probe_devices ( void ) {
* Remove all devices
*
*/
static void remove_devices ( int flags ) {
static void remove_devices ( int booting __unused ) {
struct root_device *rootdev;
struct root_device *tmp;
if ( flags & SHUTDOWN_KEEP_DEVICES ) {
if ( device_keep_count != 0 ) {
DBG ( "Refusing to remove devices on shutdown\n" );
return;
}
+1 -75
View File
@@ -86,80 +86,6 @@ int execv ( const char *command, char * const argv[] ) {
return -ENOEXEC;
}
/**
* Expand variables within command line
*
* @v command Command line
* @ret expcmd Expanded command line
*
* The expanded command line is allocated with malloc() and the caller
* must eventually free() it.
*/
static char * expand_command ( const char *command ) {
char *expcmd;
char *start;
char *end;
char *head;
char *name;
char *tail;
int setting_len;
int new_len;
char *tmp;
/* Obtain temporary modifiable copy of command line */
expcmd = strdup ( command );
if ( ! expcmd )
return NULL;
/* Expand while expansions remain */
while ( 1 ) {
head = expcmd;
/* Locate setting to be expanded */
start = NULL;
end = NULL;
for ( tmp = expcmd ; *tmp ; tmp++ ) {
if ( ( tmp[0] == '$' ) && ( tmp[1] == '{' ) )
start = tmp;
if ( start && ( tmp[0] == '}' ) ) {
end = tmp;
break;
}
}
if ( ! end )
break;
*start = '\0';
name = ( start + 2 );
*end = '\0';
tail = ( end + 1 );
/* Determine setting length */
setting_len = fetchf_named_setting ( name, NULL, 0 );
if ( setting_len < 0 )
setting_len = 0; /* Treat error as empty setting */
/* Read setting into temporary buffer */
{
char setting_buf[ setting_len + 1 ];
setting_buf[0] = '\0';
fetchf_named_setting ( name, setting_buf,
sizeof ( setting_buf ) );
/* Construct expanded string and discard old string */
tmp = expcmd;
new_len = asprintf ( &expcmd, "%s%s%s",
head, setting_buf, tail );
free ( tmp );
if ( new_len < 0 )
return NULL;
}
}
return expcmd;
}
/**
* Split command line into tokens
*
@@ -294,7 +220,7 @@ int system ( const char *command ) {
int rc = 0;
/* Perform variable expansion */
expcmd = expand_command ( command );
expcmd = expand_settings ( command );
if ( ! expcmd )
return -ENOMEM;
+1 -1
View File
@@ -85,7 +85,7 @@ __asmcall int main ( void ) {
shell();
}
shutdown ( SHUTDOWN_EXIT | shutdown_exit_flags );
shutdown_exit();
return 0;
}
+122 -92
View File
@@ -43,12 +43,79 @@ static unsigned int nvo_checksum ( struct nvo_block *nvo ) {
uint8_t sum = 0;
unsigned int i;
for ( i = 0 ; i < nvo->total_len ; i++ ) {
for ( i = 0 ; i < nvo->len ; i++ ) {
sum += *(data++);
}
return sum;
}
/**
* Reallocate non-volatile stored options block
*
* @v nvo Non-volatile options block
* @v len New length
* @ret rc Return status code
*/
static int nvo_realloc ( struct nvo_block *nvo, size_t len ) {
void *new_data;
/* Reallocate data */
new_data = realloc ( nvo->data, len );
if ( ! new_data ) {
DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
nvo, len );
return -ENOMEM;
}
nvo->data = new_data;
nvo->len = len;
/* Update DHCP option block */
if ( len ) {
nvo->dhcpopts.data = ( nvo->data + 1 /* checksum */ );
nvo->dhcpopts.alloc_len = ( len - 1 /* checksum */ );
} else {
nvo->dhcpopts.data = NULL;
nvo->dhcpopts.used_len = 0;
nvo->dhcpopts.alloc_len = 0;
}
return 0;
}
/**
* Reallocate non-volatile stored options DHCP option block
*
* @v options DHCP option block
* @v len New length
* @ret rc Return status code
*/
static int nvo_realloc_dhcpopt ( struct dhcp_options *options, size_t len ) {
struct nvo_block *nvo =
container_of ( options, struct nvo_block, dhcpopts );
int rc;
/* Refuse to reallocate if we have no way to resize the block */
if ( ! nvo->resize )
return dhcpopt_no_realloc ( options, len );
/* Allow one byte for the checksum (if any data is present) */
if ( len )
len += 1;
/* Resize underlying non-volatile options block */
if ( ( rc = nvo->resize ( nvo, len ) ) != 0 ) {
DBGC ( nvo, "NVO %p could not resize to %zd bytes: %s\n",
nvo, len, strerror ( rc ) );
return rc;
}
/* Reallocate in-memory options block */
if ( ( rc = nvo_realloc ( nvo, len ) ) != 0 )
return rc;
return 0;
}
/**
* Load non-volatile stored options from non-volatile storage device
*
@@ -56,21 +123,37 @@ static unsigned int nvo_checksum ( struct nvo_block *nvo ) {
* @ret rc Return status code
*/
static int nvo_load ( struct nvo_block *nvo ) {
void *data = nvo->data;
struct nvo_fragment *frag;
uint8_t *options_data = nvo->dhcpopts.data;
int rc;
/* Read data a fragment at a time */
for ( frag = nvo->fragments ; frag->len ; frag++ ) {
if ( ( rc = nvs_read ( nvo->nvs, frag->address, data,
frag->len ) ) != 0 ) {
DBGC ( nvo, "NVO %p could not read %zd bytes at "
"%#04x\n", nvo, frag->len, frag->address );
return rc;
}
data += frag->len;
/* Skip reading zero-length NVO fields */
if ( nvo->len == 0 ) {
DBGC ( nvo, "NVO %p is empty; skipping load\n", nvo );
return 0;
}
/* Read data */
if ( ( rc = nvs_read ( nvo->nvs, nvo->address, nvo->data,
nvo->len ) ) != 0 ) {
DBGC ( nvo, "NVO %p could not read %zd bytes at %#04x: %s\n",
nvo, nvo->len, nvo->address, strerror ( rc ) );
return rc;
}
/* If checksum fails, or options data starts with a zero,
* assume the whole block is invalid. This should capture the
* case of random initial contents.
*/
if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
"assuming empty\n", nvo, nvo_checksum ( nvo ),
options_data[0] );
memset ( nvo->data, 0, nvo->len );
}
/* Rescan DHCP option block */
dhcpopt_update_used_len ( &nvo->dhcpopts );
DBGC ( nvo, "NVO %p loaded from non-volatile storage\n", nvo );
return 0;
}
@@ -82,60 +165,25 @@ static int nvo_load ( struct nvo_block *nvo ) {
* @ret rc Return status code
*/
static int nvo_save ( struct nvo_block *nvo ) {
void *data = nvo->data;
uint8_t *checksum = data;
struct nvo_fragment *frag;
uint8_t *checksum = nvo->data;
int rc;
/* Recalculate checksum */
*checksum -= nvo_checksum ( nvo );
/* Recalculate checksum, if applicable */
if ( nvo->len > 0 )
*checksum -= nvo_checksum ( nvo );
/* Write data a fragment at a time */
for ( frag = nvo->fragments ; frag->len ; frag++ ) {
if ( ( rc = nvs_write ( nvo->nvs, frag->address, data,
frag->len ) ) != 0 ) {
DBGC ( nvo, "NVO %p could not write %zd bytes at "
"%#04x\n", nvo, frag->len, frag->address );
return rc;
}
data += frag->len;
/* Write data */
if ( ( rc = nvs_write ( nvo->nvs, nvo->address, nvo->data,
nvo->len ) ) != 0 ) {
DBGC ( nvo, "NVO %p could not write %zd bytes at %#04x: %s\n",
nvo, nvo->len, nvo->address, strerror ( rc ) );
return rc;
}
DBGC ( nvo, "NVO %p saved to non-volatile storage\n", nvo );
return 0;
}
/**
* Parse stored options
*
* @v nvo Non-volatile options block
*
* Verifies that the options data is valid, and configures the DHCP
* options block. If the data is not valid, it is replaced with an
* empty options block.
*/
static void nvo_init_dhcpopts ( struct nvo_block *nvo ) {
uint8_t *options_data;
size_t options_len;
/* Steal one byte for the checksum */
options_data = ( nvo->data + 1 );
options_len = ( nvo->total_len - 1 );
/* If checksum fails, or options data starts with a zero,
* assume the whole block is invalid. This should capture the
* case of random initial contents.
*/
if ( ( nvo_checksum ( nvo ) != 0 ) || ( options_data[0] == 0 ) ) {
DBGC ( nvo, "NVO %p has checksum %02x and initial byte %02x; "
"assuming empty\n", nvo, nvo_checksum ( nvo ),
options_data[0] );
memset ( nvo->data, 0, nvo->total_len );
}
dhcpopt_init ( &nvo->dhcpopts, options_data, options_len );
}
/**
* Store value of NVO setting
*
@@ -197,13 +245,20 @@ static struct settings_operations nvo_settings_operations = {
*
* @v nvo Non-volatile options block
* @v nvs Underlying non-volatile storage device
* @v fragments List of option-containing fragments, or NULL
* @v address Address within NVS device
* @v len Length of non-volatile options data
* @v resize Resize method
* @v refcnt Containing object reference counter, or NULL
*/
void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
struct nvo_fragment *fragments, struct refcnt *refcnt ) {
size_t address, size_t len,
int ( * resize ) ( struct nvo_block *nvo, size_t len ),
struct refcnt *refcnt ) {
nvo->nvs = nvs;
nvo->fragments = fragments;
nvo->address = address;
nvo->len = len;
nvo->resize = resize;
dhcpopt_init ( &nvo->dhcpopts, NULL, 0, nvo_realloc_dhcpopt );
settings_init ( &nvo->settings, &nvo_settings_operations, refcnt, 0 );
}
@@ -215,40 +270,17 @@ void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
* @ret rc Return status code
*/
int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
struct nvo_fragment *fragment = nvo->fragments;
int rc;
/* Calculate total length of all fragments, if applicable */
if ( fragment ) {
for ( ; fragment->len ; fragment++ )
nvo->total_len += fragment->len;
} else {
nvo->total_len = nvo->nvs->size;
}
/* Allocate memory for options (and fragment list, if applicable) */
nvo->data = zalloc ( nvo->total_len +
( fragment ? 0 : ( 2 * sizeof ( *fragment ) ) ) );
if ( ! nvo->data ) {
DBGC ( nvo, "NVO %p could not allocate %zd bytes\n",
nvo, nvo->total_len );
rc = -ENOMEM;
goto err_malloc;
}
/* Create fragment list, if applicable */
if ( ! fragment ) {
fragment = ( nvo->data + nvo->total_len );
fragment->len = nvo->total_len;
nvo->fragments = fragment;
}
/* Allocate memory for options */
if ( ( rc = nvo_realloc ( nvo, nvo->len ) ) != 0 )
goto err_realloc;
/* Read data from NVS */
if ( ( rc = nvo_load ( nvo ) ) != 0 )
goto err_load;
/* Verify and register options */
nvo_init_dhcpopts ( nvo );
/* Register settings */
if ( ( rc = register_settings ( &nvo->settings, parent, "nvo" ) ) != 0 )
goto err_register;
@@ -257,9 +289,8 @@ int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
err_register:
err_load:
free ( nvo->data );
nvo->data = NULL;
err_malloc:
nvo_realloc ( nvo, 0 );
err_realloc:
return rc;
}
@@ -270,7 +301,6 @@ int register_nvo ( struct nvo_block *nvo, struct settings *parent ) {
*/
void unregister_nvo ( struct nvo_block *nvo ) {
unregister_settings ( &nvo->settings );
free ( nvo->data );
nvo->data = NULL;
nvo_realloc ( nvo, 0 );
DBGC ( nvo, "NVO %p unregistered\n", nvo );
}
+40 -15
View File
@@ -32,6 +32,22 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/**
* Find opener for URI scheme
*
* @v scheme URI scheme
* @ret opener Opener, or NULL
*/
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 )
return opener;
}
return NULL;
}
/**
* Open URI
*
@@ -45,29 +61,38 @@ FILE_LICENCE ( GPL2_OR_LATER );
int xfer_open_uri ( struct interface *intf, struct uri *uri ) {
struct uri_opener *opener;
struct uri *resolved_uri;
int rc = -ENOTSUP;
int rc;
/* Resolve URI */
resolved_uri = resolve_uri ( cwuri, uri );
if ( ! resolved_uri )
return -ENOMEM;
if ( ! resolved_uri ) {
rc = -ENOMEM;
goto err_resolve_uri;
}
/* Find opener which supports this URI scheme */
for_each_table_entry ( opener, URI_OPENERS ) {
if ( strcmp ( resolved_uri->scheme, opener->scheme ) == 0 ) {
DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT
" opening %s URI\n", INTF_DBG ( intf ),
resolved_uri->scheme );
rc = opener->open ( intf, resolved_uri );
goto done;
}
opener = xfer_uri_opener ( resolved_uri->scheme );
if ( ! opener ) {
DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open "
"unsupported URI scheme \"%s\"\n",
INTF_DBG ( intf ), resolved_uri->scheme );
rc = -ENOTSUP;
goto err_opener;
}
DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " attempted to open "
"unsupported URI scheme \"%s\"\n",
INTF_DBG ( intf ), resolved_uri->scheme );
done:
/* Call opener */
DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " opening %s URI\n",
INTF_DBG ( intf ), resolved_uri->scheme );
if ( ( rc = opener->open ( intf, resolved_uri ) ) != 0 ) {
DBGC ( INTF_COL ( intf ), "INTF " INTF_FMT " could not open: "
"%s\n", INTF_DBG ( intf ), strerror ( rc ) );
goto err_open;
}
err_open:
err_opener:
uri_put ( resolved_uri );
err_resolve_uri:
return rc;
}
+81
View File
@@ -1467,6 +1467,87 @@ struct setting_type setting_type_uuid __setting_type = {
.fetchf = fetchf_uuid,
};
/******************************************************************************
*
* Setting expansion
*
******************************************************************************
*/
/**
* Expand variables within string
*
* @v string String
* @ret expstr Expanded string
*
* The expanded string is allocated with malloc() and the caller must
* eventually free() it.
*/
char * expand_settings ( const char *string ) {
char *expstr;
char *start;
char *end;
char *head;
char *name;
char *tail;
int setting_len;
int new_len;
char *tmp;
/* Obtain temporary modifiable copy of string */
expstr = strdup ( string );
if ( ! expstr )
return NULL;
/* Expand while expansions remain */
while ( 1 ) {
head = expstr;
/* Locate setting to be expanded */
start = NULL;
end = NULL;
for ( tmp = expstr ; *tmp ; tmp++ ) {
if ( ( tmp[0] == '$' ) && ( tmp[1] == '{' ) )
start = tmp;
if ( start && ( tmp[0] == '}' ) ) {
end = tmp;
break;
}
}
if ( ! end )
break;
*start = '\0';
name = ( start + 2 );
*end = '\0';
tail = ( end + 1 );
/* Determine setting length */
setting_len = fetchf_named_setting ( name, NULL, 0 );
if ( setting_len < 0 )
setting_len = 0; /* Treat error as empty setting */
/* Read setting into temporary buffer */
{
char setting_buf[ setting_len + 1 ];
setting_buf[0] = '\0';
fetchf_named_setting ( name, setting_buf,
sizeof ( setting_buf ) );
/* Construct expanded string and discard old string */
tmp = expstr;
new_len = asprintf ( &expstr, "%s%s%s",
head, setting_buf, tail );
free ( tmp );
if ( new_len < 0 )
return NULL;
}
}
return expstr;
}
/******************************************************************************
*
* Settings
+169
View File
@@ -19,6 +19,7 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <byteswap.h>
@@ -73,6 +74,10 @@ static int pci_vpd_read_dword ( struct pci_vpd *vpd, int address,
unsigned int retries;
uint16_t flag;
/* Fail if no VPD present */
if ( ! cap )
return -ENOTTY;
/* Return cached value, if present */
if ( pci_vpd_cache_is_valid ( vpd ) &&
( vpd->cache.address == address ) ) {
@@ -127,6 +132,10 @@ static int pci_vpd_write_dword ( struct pci_vpd *vpd, int address,
unsigned int retries;
uint16_t flag;
/* Fail if no VPD present */
if ( ! cap )
return -ENOTTY;
/* Invalidate cache */
pci_vpd_invalidate_cache ( vpd );
@@ -384,3 +393,163 @@ int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ) );
return -ENOENT;
}
/**
* Resize VPD field
*
* @v vpd PCI VPD
* @v field VPD field descriptor
* @v len New length of field body
* @ret address Address of field body
* @ret rc Return status code
*/
int pci_vpd_resize ( struct pci_vpd *vpd, unsigned int field, size_t len,
unsigned int *address ) {
struct pci_vpd_field rw_field;
struct pci_vpd_field old_field;
struct pci_vpd_field new_field;
unsigned int rw_address;
unsigned int old_address;
unsigned int copy_address;
unsigned int dst_address;
unsigned int dump_address;
size_t rw_len;
size_t old_len;
size_t available_len;
size_t copy_len;
size_t dump_len;
void *copy;
int rc;
/* Sanity checks */
assert ( PCI_VPD_TAG ( field ) == PCI_VPD_TAG_RW );
assert ( PCI_VPD_KEYWORD ( field ) != 0 );
assert ( field != PCI_VPD_FIELD_RW );
/* Locate 'RW' field */
if ( ( rc = pci_vpd_find ( vpd, PCI_VPD_FIELD_RW, &rw_address,
&rw_len ) ) != 0 )
goto err_no_rw;
/* Locate old field, if any */
if ( ( rc = pci_vpd_find ( vpd, field, &old_address,
&old_len ) ) == 0 ) {
/* Field already exists */
if ( old_address > rw_address ) {
DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
" at [%04x,%04zx) is after field "
PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
PCI_ARGS ( vpd->pci ),
PCI_VPD_FIELD_ARGS ( field ),
old_address, ( old_address + old_len ),
PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ),
rw_address, ( rw_address + rw_len ) );
rc = -ENXIO;
goto err_after_rw;
}
dst_address = ( old_address - sizeof ( old_field ) );
copy_address = ( old_address + old_len );
copy_len = ( rw_address - sizeof ( rw_field ) - copy_address );
/* Calculate available length */
available_len = ( rw_len + old_len );
} else {
/* Field does not yet exist */
dst_address = ( rw_address - sizeof ( rw_field ) );
copy_address = dst_address;
copy_len = 0;
/* Calculate available length */
available_len = ( ( rw_len > sizeof ( new_field ) ) ?
( rw_len - sizeof ( new_field ) ) : 0 );
}
/* Dump region before changes */
dump_address = dst_address;
dump_len = ( rw_address + rw_len - dump_address );
DBGC ( vpd, PCI_FMT " VPD before resizing field " PCI_VPD_FIELD_FMT
" to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
PCI_VPD_FIELD_ARGS ( field ), len );
pci_vpd_dump ( vpd, dump_address, dump_len );
/* Check available length */
if ( available_len > PCI_VPD_MAX_LEN )
available_len = PCI_VPD_MAX_LEN;
if ( len > available_len ) {
DBGC ( vpd, PCI_FMT " VPD no space for field "
PCI_VPD_FIELD_FMT " (need %02zx, have %02zx)\n",
PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ),
len, available_len );
rc = -ENOSPC;
goto err_no_space;
}
/* Preserve intermediate fields, if any */
copy = malloc ( copy_len );
if ( ! copy ) {
rc = -ENOMEM;
goto err_copy_alloc;
}
if ( ( rc = pci_vpd_read ( vpd, copy_address, copy, copy_len ) ) != 0 )
goto err_copy_read;
/* Create new field, if applicable */
if ( len ) {
new_field.keyword = PCI_VPD_KEYWORD ( field );
new_field.len = len;
if ( ( rc = pci_vpd_write ( vpd, dst_address, &new_field,
sizeof ( new_field ) ) ) != 0 )
goto err_new_write;
dst_address += sizeof ( new_field );
*address = dst_address;
DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
"at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
PCI_VPD_FIELD_ARGS ( field ), dst_address,
( dst_address + new_field.len ) );
dst_address += len;
} else {
DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
" no longer exists\n", PCI_ARGS ( vpd->pci ),
PCI_VPD_FIELD_ARGS ( field ) );
}
/* Restore intermediate fields, if any */
if ( ( rc = pci_vpd_write ( vpd, dst_address, copy, copy_len ) ) != 0 )
goto err_copy_write;
dst_address += copy_len;
/* Create 'RW' field */
rw_field.keyword = PCI_VPD_KEYWORD ( PCI_VPD_FIELD_RW );
rw_field.len = ( rw_len +
( rw_address - sizeof ( rw_field ) ) - dst_address );
if ( ( rc = pci_vpd_write ( vpd, dst_address, &rw_field,
sizeof ( rw_field ) ) ) != 0 )
goto err_rw_write;
dst_address += sizeof ( rw_field );
DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
"at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ), dst_address,
( dst_address + rw_field.len ) );
/* Dump region after changes */
DBGC ( vpd, PCI_FMT " VPD after resizing field " PCI_VPD_FIELD_FMT
" to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
PCI_VPD_FIELD_ARGS ( field ), len );
pci_vpd_dump ( vpd, dump_address, dump_len );
rc = 0;
err_rw_write:
err_new_write:
err_copy_write:
err_copy_read:
free ( copy );
err_copy_alloc:
err_no_space:
err_after_rw:
err_no_rw:
return rc;
}
-12
View File
@@ -2319,17 +2319,6 @@ static void hermon_eth_poll ( struct net_device *netdev ) {
ib_poll_eq ( ibdev );
}
/**
* Enable/disable interrupts on Hermon Ethernet device
*
* @v netdev Network device
* @v enable Interrupts should be enabled
*/
static void hermon_eth_irq ( struct net_device *netdev __unused,
int enable __unused ) {
/* No implementation */
}
/**
* Open Hermon Ethernet device
*
@@ -2469,7 +2458,6 @@ static struct net_device_operations hermon_eth_operations = {
.close = hermon_eth_close,
.transmit = hermon_eth_transmit,
.poll = hermon_eth_poll,
.irq = hermon_eth_irq,
};
/**
+3 -3
View File
@@ -114,13 +114,13 @@ struct root_device snp_root_device __root_device = {
/**
* Prepare for exit
*
* @v flags Shutdown flags
* @v booting System is shutting down for OS boot
*/
static void snponly_shutdown ( int flags ) {
static void snponly_shutdown ( int booting ) {
/* If we are shutting down to boot an OS, make sure the SNP does not
* stay active.
*/
if ( flags & SHUTDOWN_BOOT )
if ( booting )
snponly_dev.removal_state = EfiSimpleNetworkStopped;
}
+4 -9
View File
@@ -1492,12 +1492,6 @@ fail1:
return rc;
}
/** Portion of EEPROM available for non-volatile options */
static struct nvo_fragment falcon_nvo_fragments[] = {
{ 0x100, 0xf0 },
{ 0, 0 }
};
/*******************************************************************************
*
*
@@ -3277,9 +3271,10 @@ falcon_probe_spi ( struct efab_nic *efab )
}
/* If the device has EEPROM attached, then advertise NVO space */
if ( has_eeprom )
nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, falcon_nvo_fragments,
&efab->netdev->refcnt );
if ( has_eeprom ) {
nvo_init ( &efab->nvo, &efab->spi_eeprom.nvs, 0x100, 0xf0,
NULL, &efab->netdev->refcnt );
}
return 0;
}
-12
View File
@@ -537,17 +537,6 @@ static void ipoib_poll ( struct net_device *netdev ) {
ib_poll_eq ( ibdev );
}
/**
* Enable/disable interrupts on IPoIB network device
*
* @v netdev Network device
* @v enable Interrupts should be enabled
*/
static void ipoib_irq ( struct net_device *netdev __unused,
int enable __unused ) {
/* No implementation */
}
/**
* Handle IPv4 broadcast multicast group join completion
*
@@ -730,7 +719,6 @@ static struct net_device_operations ipoib_operations = {
.close = ipoib_close,
.transmit = ipoib_transmit,
.poll = ipoib_poll,
.irq = ipoib_irq,
};
/**
+5 -12
View File
@@ -183,8 +183,8 @@ struct myri10ge_private
*/
struct nvs_device nvs;
struct nvo_fragment nvo_fragment[2];
struct nvo_block nvo;
unsigned int nvo_registered;
/* Cached PCI capability locations. */
@@ -727,28 +727,21 @@ static int myri10ge_nv_init ( struct myri10ge_private *priv )
priv->nvs.read = myri10ge_nvs_read;
priv->nvs.write = myri10ge_nvs_write;
/* Build the NonVolatile storage fragment list. We would like
to use the whole last EEPROM block for this, but we must
reduce the block size lest malloc fail in
src/core/nvo.o. */
priv->nvo_fragment[0].address = nvo_fragment_pos;
priv->nvo_fragment[0].len = 0x200;
/* Register the NonVolatile Options storage. */
nvo_init ( &priv->nvo,
&priv->nvs,
priv->nvo_fragment,
nvo_fragment_pos, 0x200,
NULL,
& myri10ge_netdev (priv) -> refcnt );
rc = register_nvo ( &priv->nvo,
netdev_settings ( myri10ge_netdev ( priv ) ) );
if ( rc ) {
DBG ("register_nvo failed");
priv->nvo_fragment[0].len = 0;
return rc;
}
priv->nvo_registered = 1;
DBG2 ( "NVO supported\n" );
return 0;
}
@@ -758,7 +751,7 @@ myri10ge_nv_fini ( struct myri10ge_private *priv )
{
/* Simply return if nonvolatile access is not supported. */
if ( 0 == priv->nvo_fragment[0].len )
if ( 0 == priv->nvo_registered )
return;
unregister_nvo ( &priv->nvo );
+7 -11
View File
@@ -130,15 +130,6 @@ static struct bit_basher_operations natsemi_basher_ops = {
.write = natsemi_spi_write_bit,
};
/* It looks that this portion of EEPROM can be used for
* non-volatile stored options. Data sheet does not talk about this region.
* Currently it is not working. But with some efforts it can.
*/
static struct nvo_fragment natsemi_nvo_fragments[] = {
{ 0x0c, 0x68 },
{ 0, 0 }
};
/*
* Set up for EEPROM access
*
@@ -157,8 +148,13 @@ static void natsemi_init_eeprom ( struct natsemi_private *np ) {
*/
init_at93c46 ( &np->eeprom, 16 );
np->eeprom.bus = &np->spibit.bus;
np->nvo.nvs = &np->eeprom.nvs;
np->nvo.fragments = natsemi_nvo_fragments;
/* It looks that this portion of EEPROM can be used for
* non-volatile stored options. Data sheet does not talk about
* this region. Currently it is not working. But with some
* efforts it can.
*/
nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL, NULL );
}
/**
+7 -13
View File
@@ -251,17 +251,6 @@ static struct bit_basher_operations rtl_basher_ops = {
.write = rtl_spi_write_bit,
};
/** Portion of EEPROM available for non-volatile stored options
*
* We use offset 0x40 (i.e. address 0x20), length 0x40. This block is
* marked as VPD in the rtl8139 datasheets, so we use it only if we
* detect that the card is not supporting VPD.
*/
static struct nvo_fragment rtl_nvo_fragments[] = {
{ 0x20, 0x40 },
{ 0, 0 }
};
/**
* Set up for EEPROM access
*
@@ -288,13 +277,18 @@ static void rtl_init_eeprom ( struct net_device *netdev ) {
}
rtl->eeprom.bus = &rtl->spibit.bus;
/* Initialise space for non-volatile options, if available */
/* Initialise space for non-volatile options, if available
*
* We use offset 0x40 (i.e. address 0x20), length 0x40. This
* block is marked as VPD in the rtl8139 datasheets, so we use
* it only if we detect that the card is not supporting VPD.
*/
vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable );
if ( vpd ) {
DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use "
"for options\n", rtl );
} else {
nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, rtl_nvo_fragments,
nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40, NULL,
&netdev->refcnt );
}
}
+48 -15
View File
@@ -17,6 +17,7 @@ FILE_LICENCE(GPL2_ONLY);
#include <stdlib.h>
#include <stdio.h>
#include <ipxe/malloc.h>
#include <ipxe/pci.h>
#include <ipxe/iobuf.h>
#include <ipxe/ethernet.h>
#include <byteswap.h>
@@ -186,28 +187,47 @@ __vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog)
return status;
}
/*
* __vxge_hw_device_get_legacy_reg
* This routine gets the legacy register section's memory mapped address
* and sets the swapper.
*/
static struct vxge_hw_legacy_reg __iomem *
__vxge_hw_device_get_legacy_reg(struct pci_device *pdev, void __iomem *bar0)
{
enum vxge_hw_status status;
struct vxge_hw_legacy_reg __iomem *legacy_reg;
/*
* If the length of Bar0 is 16MB, then assume that we are configured
* in MF8P_VP2 mode and then add 8MB to the legacy_reg offsets
*/
if (pci_bar_size(pdev, PCI_BASE_ADDRESS_0) == 0x1000000)
legacy_reg = (struct vxge_hw_legacy_reg __iomem *)
(bar0 + 0x800000);
else
legacy_reg = (struct vxge_hw_legacy_reg __iomem *)bar0;
status = __vxge_hw_legacy_swapper_set(legacy_reg);
if (status != VXGE_HW_OK)
return NULL;
return legacy_reg;
}
/*
* __vxge_hw_device_toc_get
* This routine sets the swapper and reads the toc pointer and returns the
* memory mapped address of the toc
*/
struct vxge_hw_toc_reg __iomem *
__vxge_hw_device_toc_get(void __iomem *bar0)
__vxge_hw_device_toc_get(void __iomem *bar0,
struct vxge_hw_legacy_reg __iomem *legacy_reg)
{
u64 val64;
struct vxge_hw_toc_reg __iomem *toc = NULL;
enum vxge_hw_status status;
struct vxge_hw_legacy_reg __iomem *legacy_reg =
(struct vxge_hw_legacy_reg __iomem *)bar0;
status = __vxge_hw_legacy_swapper_set(legacy_reg);
if (status != VXGE_HW_OK)
goto exit;
val64 = readq(&legacy_reg->toc_first_pointer);
toc = (struct vxge_hw_toc_reg __iomem *)(bar0+val64);
exit:
return toc;
}
@@ -224,9 +244,15 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
u32 i;
enum vxge_hw_status status = VXGE_HW_OK;
hldev->legacy_reg = (struct vxge_hw_legacy_reg __iomem *)hldev->bar0;
hldev->legacy_reg = __vxge_hw_device_get_legacy_reg(hldev->pdev,
hldev->bar0);
if (hldev->legacy_reg == NULL) {
status = VXGE_HW_FAIL;
goto exit;
}
hldev->toc_reg = __vxge_hw_device_toc_get(hldev->bar0);
hldev->toc_reg = __vxge_hw_device_toc_get(hldev->bar0,
hldev->legacy_reg);
if (hldev->toc_reg == NULL) {
status = VXGE_HW_FAIL;
goto exit;
@@ -234,7 +260,7 @@ __vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev)
val64 = readq(&hldev->toc_reg->toc_common_pointer);
hldev->common_reg =
(struct vxge_hw_common_reg __iomem *)(hldev->bar0 + val64);
(struct vxge_hw_common_reg __iomem *)(hldev->bar0 + val64);
val64 = readq(&hldev->toc_reg->toc_mrpcim_pointer);
hldev->mrpcim_reg =
@@ -355,7 +381,7 @@ void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev)
* each vpath
*/
enum vxge_hw_status
vxge_hw_device_hw_info_get(void __iomem *bar0,
vxge_hw_device_hw_info_get(struct pci_device *pdev, void __iomem *bar0,
struct vxge_hw_device_hw_info *hw_info)
{
u32 i;
@@ -365,13 +391,20 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
struct vxge_hw_common_reg __iomem *common_reg;
struct vxge_hw_vpath_reg __iomem *vpath_reg;
struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg;
struct vxge_hw_legacy_reg __iomem *legacy_reg;
enum vxge_hw_status status;
vxge_trace();
memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info));
toc = __vxge_hw_device_toc_get(bar0);
legacy_reg = __vxge_hw_device_get_legacy_reg(pdev, bar0);
if (legacy_reg == NULL) {
status = VXGE_HW_ERR_CRITICAL;
goto exit;
}
toc = __vxge_hw_device_toc_get(bar0, legacy_reg);
if (toc == NULL) {
status = VXGE_HW_ERR_CRITICAL;
goto exit;
+3 -7
View File
@@ -440,7 +440,7 @@ struct vxge_hw_device_hw_info {
#define VXGE_HW_VH_NORMAL_FUNCTION 7
u64 function_mode;
#define VXGE_HW_FUNCTION_MODE_MIN 0
#define VXGE_HW_FUNCTION_MODE_MAX 10
#define VXGE_HW_FUNCTION_MODE_MAX 11
#define VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION 0
#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION 1
@@ -453,6 +453,7 @@ struct vxge_hw_device_hw_info {
#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_2 8
#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_4 9
#define VXGE_HW_FUNCTION_MODE_MRIOV_4 10
#define VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION_DIRECT_IO 11
u32 func_id;
u64 vpath_mask;
@@ -607,6 +608,7 @@ void vxge_hw_ring_rxd_1b_set(struct vxge_hw_ring_rxd_1 *rxdp,
}
enum vxge_hw_status vxge_hw_device_hw_info_get(
struct pci_device *pdev,
void __iomem *bar0,
struct vxge_hw_device_hw_info *hw_info);
@@ -727,12 +729,6 @@ __vxge_hw_pio_mem_write64(u64 val64, void __iomem *addr,
return status;
}
struct vxge_hw_toc_reg __iomem *
__vxge_hw_device_toc_get(void __iomem *bar0);
enum vxge_hw_status
__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev);
void
__vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev);
+2 -1
View File
@@ -45,6 +45,7 @@ static char *vxge_func_mode_names[] = {
"Multi Function 2 - 2 func, 8 vpath per func",
"Multi Function 4 - 4 func, 4 vpath per func",
"WLPEX/SharedIO 4 - 17 func, 1 vpath per func (PCIe ARI)",
"Multi Function 8 - For ESX DirectIO - 8 func, 2 vpath per func",
};
static inline int is_vxge_card_up(struct vxgedev *vdev)
@@ -533,7 +534,7 @@ vxge_probe(struct pci_device *pdev, const struct pci_device_id *id __unused)
goto _exit0;
}
status = vxge_hw_device_hw_info_get(bar0, &hw_info);
status = vxge_hw_device_hw_info_get(pdev, bar0, &hw_info);
if (status != VXGE_HW_OK) {
vxge_debug(VXGE_ERR,
"%s: Reading of hardware info failed.\n",
+2 -2
View File
@@ -22,9 +22,9 @@ FILE_LICENCE(GPL2_ONLY);
* Note: Each field must be a nibble size
*/
#define VXGE_VERSION_MAJOR 3
#define VXGE_VERSION_MINOR 1
#define VXGE_VERSION_MINOR 5
#define VXGE_VERSION_FIX 0
#define VXGE_VERSION_BUILD 0
#define VXGE_VERSION_BUILD 1
#define VXGE_FW_VER(major, minor, build) \
(((major) << 16) + ((minor) << 8) + (build))
+32 -16
View File
@@ -30,6 +30,34 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/**
* Calculate length up to next block boundary
*
* @v nvs NVS device
* @v address Starting address
* @v max_len Maximum length
* @ret len Length to use, stopping at block boundaries
*/
static size_t nvs_frag_len ( struct nvs_device *nvs, unsigned int address,
size_t max_len ) {
size_t frag_len;
/* If there are no block boundaries, return the maximum length */
if ( ! nvs->block_size )
return max_len;
/* Calculate space remaining up to next block boundary */
frag_len = ( ( nvs->block_size -
( address & ( nvs->block_size - 1 ) ) )
<< nvs->word_len_log2 );
/* Limit to maximum length */
if ( max_len < frag_len )
return max_len;
return frag_len;
}
/**
* Read from non-volatile storage device
*
@@ -51,14 +79,8 @@ int nvs_read ( struct nvs_device *nvs, unsigned int address,
while ( len ) {
/* Calculate space remaining up to next block boundary */
frag_len = ( ( nvs->block_size -
( address & ( nvs->block_size - 1 ) ) )
<< nvs->word_len_log2 );
/* Limit to space remaining in buffer */
if ( frag_len > len )
frag_len = len;
/* Calculate length to read, stopping at block boundaries */
frag_len = nvs_frag_len ( nvs, address, len );
/* Read this portion of the buffer from the device */
if ( ( rc = nvs->read ( nvs, address, data, frag_len ) ) != 0 )
@@ -122,14 +144,8 @@ int nvs_write ( struct nvs_device *nvs, unsigned int address,
while ( len ) {
/* Calculate space remaining up to next block boundary */
frag_len = ( ( nvs->block_size -
( address & ( nvs->block_size - 1 ) ) )
<< nvs->word_len_log2 );
/* Limit to space remaining in buffer */
if ( frag_len > len )
frag_len = len;
/* Calculate length to write, stopping at block boundaries */
frag_len = nvs_frag_len ( nvs, address, len );
/* Write this portion of the buffer to the device */
if ( ( rc = nvs->write ( nvs, address, data, frag_len ) ) != 0)
+142 -33
View File
@@ -19,9 +19,11 @@
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdio.h>
#include <errno.h>
#include <ipxe/nvs.h>
#include <ipxe/pci.h>
#include <ipxe/pcivpd.h>
#include <ipxe/nvo.h>
#include <ipxe/nvsvpd.h>
/** @file
@@ -31,24 +33,50 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
/**
* Read from VPD
* Read from VPD field
*
* @v nvs NVS device
* @v address Starting address
* @v buf Data buffer
* @v field VPD field descriptor
* @v data Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int address,
static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int field,
void *data, size_t len ) {
struct nvs_vpd_device *nvsvpd =
container_of ( nvs, struct nvs_vpd_device, nvs );
struct pci_device *pci = nvsvpd->vpd.pci;
unsigned int address;
size_t max_len;
int rc;
if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, ( nvsvpd->address + address ),
data, len ) ) != 0 ) {
DBGC ( nvsvpd->vpd.pci, PCI_FMT " NVS could not read "
"[%04x,%04zx): %s\n", PCI_ARGS ( nvsvpd->vpd.pci ),
/* Allow reading non-existent field */
if ( len == 0 )
return 0;
/* Locate VPD field */
if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
&max_len ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
return rc;
}
/* Sanity check */
if ( len > max_len ) {
DBGC ( pci, PCI_FMT " NVS VPD cannot read %#02zx bytes "
"beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
address, ( address + max_len ) );
return -ENXIO;
}
/* Read from VPD field */
if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, address, data, len ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS VPD could not read field "
PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
address, ( address + len ), strerror ( rc ) );
return rc;
}
@@ -57,24 +85,47 @@ static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int address,
}
/**
* Write to VPD
* Write to VPD field
*
* @v nvs NVS device
* @v address Starting address
* @v buf Data buffer
* @v field VPD field descriptor
* @v data Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int address,
static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int field,
const void *data, size_t len ) {
struct nvs_vpd_device *nvsvpd =
container_of ( nvs, struct nvs_vpd_device, nvs );
struct pci_device *pci = nvsvpd->vpd.pci;
unsigned int address;
size_t max_len;
int rc;
if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, ( nvsvpd->address + address ),
data, len ) ) != 0 ) {
DBGC ( nvsvpd->vpd.pci, PCI_FMT " NVS could not write "
"[%04x,%04zx): %s\n", PCI_ARGS ( nvsvpd->vpd.pci ),
/* Locate VPD field */
if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
&max_len ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
return rc;
}
/* Sanity check */
if ( len > max_len ) {
DBGC ( pci, PCI_FMT " NVS VPD cannot write %#02zx bytes "
"beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
address, ( address + max_len ) );
return -ENXIO;
}
/* Write field */
if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, address, data,
len ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS VPD could not write field "
PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
address, ( address + len ), strerror ( rc ) );
return rc;
}
@@ -82,6 +133,36 @@ static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int address,
return 0;
}
/**
* Resize VPD field
*
* @v nvs NVS device
* @v field VPD field descriptor
* @v data Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*/
static int nvs_vpd_resize ( struct nvs_device *nvs, unsigned int field,
size_t len ) {
struct nvs_vpd_device *nvsvpd =
container_of ( nvs, struct nvs_vpd_device, nvs );
struct pci_device *pci = nvsvpd->vpd.pci;
unsigned int address;
int rc;
/* Resize field */
if ( ( rc = pci_vpd_resize ( &nvsvpd->vpd, field, len,
&address ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS VPD could not resize field "
PCI_VPD_FIELD_FMT " to %#02zx bytes: %s\n",
PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
len, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Initialise NVS VPD device
*
@@ -89,9 +170,7 @@ static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int address,
* @v pci PCI device
* @ret rc Return status code
*/
int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
unsigned int field ) {
size_t len;
int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci ) {
int rc;
/* Initialise VPD device */
@@ -101,24 +180,54 @@ int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
return rc;
}
/* Locate VPD field */
if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &nvsvpd->address,
&len ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS could not locate VPD field "
PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
return rc;
}
/* Initialise NVS device */
nvsvpd->nvs.block_size = 1;
nvsvpd->nvs.size = len;
nvsvpd->nvs.read = nvs_vpd_read;
nvsvpd->nvs.write = nvs_vpd_write;
DBGC ( pci, PCI_FMT " NVS using VPD field " PCI_VPD_FIELD_FMT " at "
"[%04x,%04x)\n", PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
nvsvpd->address, ( nvsvpd->address + nvsvpd->nvs.size ) );
return 0;
}
/**
* Resize non-volatile option storage within NVS VPD device
*
* @v nvo Non-volatile options block
* @v len New length
* @ret rc Return status code
*/
static int nvs_vpd_nvo_resize ( struct nvo_block *nvo, size_t len ) {
int rc;
/* Resize VPD field */
if ( ( rc = nvs_vpd_resize ( nvo->nvs, nvo->address, len ) ) != 0 )
return rc;
return 0;
}
/**
* Initialise non-volatile option storage within NVS VPD device
*
* @v nvsvpd NVS VPD device
* @v field VPD field descriptor
* @v nvo Non-volatile options block
* @v refcnt Containing object reference counter, or NULL
*/
void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd, unsigned int field,
struct nvo_block *nvo, struct refcnt *refcnt ) {
struct pci_device *pci = nvsvpd->vpd.pci;
unsigned int address;
size_t len;
int rc;
/* Locate VPD field, if present */
if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
&len ) ) != 0 ) {
DBGC ( pci, PCI_FMT " NVS VPD field " PCI_VPD_FIELD_FMT
" not present; assuming empty\n",
PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ) );
len = 0;
}
/* Initialise non-volatile options block */
nvo_init ( nvo, &nvsvpd->nvs, field, len, nvs_vpd_nvo_resize, refcnt );
}
+20 -8
View File
@@ -18,9 +18,11 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/uri.h>
#include <usr/autoboot.h>
FILE_LICENCE ( GPL2_OR_LATER );
@@ -52,23 +54,33 @@ static struct command_descriptor sanboot_cmd =
static int sanboot_exec ( int argc, char **argv ) {
struct sanboot_options opts;
const char *root_path;
struct uri *uri;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &sanboot_cmd, &opts ) ) != 0 )
return rc;
goto err_parse_options;
/* Parse root path */
root_path = argv[optind];
/* Boot from root path */
if ( ( rc = boot_root_path ( root_path ) ) != 0 ) {
printf ( "Could not boot from %s: %s\n",
root_path, strerror ( rc ) );
return rc;
uri = parse_uri ( root_path );
if ( ! uri ) {
rc = -ENOMEM;
goto err_parse_uri;
}
return 0;
/* Boot from root path */
if ( ( rc = uriboot ( NULL, uri ) ) != 0 ) {
printf ( "Could not boot from %s: %s\n",
root_path, strerror ( rc ) );
goto err_uriboot;
}
err_uriboot:
uri_put ( uri );
err_parse_uri:
err_parse_options:
return rc;
}
/** SAN commands */
+1 -1
View File
@@ -39,7 +39,7 @@ static EFI_EVENT efi_shutdown_event;
*/
static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
void *context __unused ) {
shutdown ( SHUTDOWN_BOOT );
shutdown_boot();
}
/**
+18
View File
@@ -112,6 +112,24 @@ struct root_driver {
/** Declare a root device */
#define __root_device __table_entry ( ROOT_DEVICES, 01 )
extern int device_keep_count;
/**
* Prevent devices from being removed on shutdown
*
*/
static inline void devices_get ( void ) {
device_keep_count++;
}
/**
* Allow devices to be removed on shutdown
*
*/
static inline void devices_put ( void ) {
device_keep_count--;
}
extern struct device * identify_device ( struct interface *intf );
#define identify_device_TYPE( object_type ) \
typeof ( struct device * ( object_type ) )
+16 -8
View File
@@ -15,20 +15,28 @@ FILE_LICENCE ( GPL2_OR_LATER );
struct dhcp_options {
/** Option block raw data */
void *data;
/** Option block length */
size_t len;
/** Option block maximum length */
size_t max_len;
/** Option block used length */
size_t used_len;
/** Option block allocated length */
size_t alloc_len;
/** Reallocate option block raw data
*
* @v options DHCP option block
* @v len New length
* @ret rc Return status code
*/
int ( * realloc ) ( struct dhcp_options *options, size_t len );
};
extern int dhcpopt_store ( struct dhcp_options *options, unsigned int tag,
const void *data, size_t len );
extern int dhcpopt_extensible_store ( struct dhcp_options *options,
unsigned int tag,
const void *data, size_t len );
extern int dhcpopt_fetch ( struct dhcp_options *options, unsigned int tag,
void *data, size_t len );
extern void dhcpopt_init ( struct dhcp_options *options,
void *data, size_t max_len );
void *data, size_t alloc_len,
int ( * realloc ) ( struct dhcp_options *options,
size_t len ) );
extern void dhcpopt_update_used_len ( struct dhcp_options *options );
extern int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len );
#endif /* _IPXE_DHCPOPTS_H */
+11 -4
View File
@@ -22,10 +22,6 @@ struct dhcp_packet {
struct refcnt refcnt;
/** The DHCP packet contents */
struct dhcphdr *dhcphdr;
/** Maximum length of the DHCP packet buffer */
size_t max_len;
/** Used length of the DHCP packet buffer */
size_t len;
/** DHCP options */
struct dhcp_options options;
/** Settings interface */
@@ -54,6 +50,17 @@ dhcppkt_put ( struct dhcp_packet *dhcppkt ) {
ref_put ( &dhcppkt->refcnt );
}
/**
* Get used length of DHCP packet
*
* @v dhcppkt DHCP packet
* @ret len Used length
*/
static inline int dhcppkt_len ( struct dhcp_packet *dhcppkt ) {
return ( offsetof ( struct dhcphdr, options ) +
dhcppkt->options.used_len );
}
extern int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
const void *data, size_t len );
extern int dhcppkt_fetch ( struct dhcp_packet *dhcppkt, unsigned int tag,
+2
View File
@@ -73,6 +73,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_spi ( ERRFILE_DRIVER | 0x00110000 )
#define ERRFILE_i2c_bit ( ERRFILE_DRIVER | 0x00120000 )
#define ERRFILE_spi_bit ( ERRFILE_DRIVER | 0x00130000 )
#define ERRFILE_nvsvpd ( ERRFILE_DRIVER | 0x00140000 )
#define ERRFILE_3c509 ( ERRFILE_DRIVER | 0x00200000 )
#define ERRFILE_bnx2 ( ERRFILE_DRIVER | 0x00210000 )
@@ -234,6 +235,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#define ERRFILE_ifmgmt_cmd ( ERRFILE_OTHER | 0x001d0000 )
#define ERRFILE_fcmgmt_cmd ( ERRFILE_OTHER | 0x001e0000 )
#define ERRFILE_gdbstub_cmd ( ERRFILE_OTHER | 0x001f0000 )
#define ERRFILE_sanboot_cmd ( ERRFILE_OTHER | 0x00200000 )
/** @} */
+18 -12
View File
@@ -32,16 +32,6 @@ struct init_fn {
/** @} */
/** Shutdown flags */
enum shutdown_flags {
/** Shutdown is in order to exit (return to iPXE's caller) */
SHUTDOWN_EXIT = 0x0001,
/** Shutdown is in order to boot an OS */
SHUTDOWN_BOOT = 0x0002,
/** Do not remove devices */
SHUTDOWN_KEEP_DEVICES = 0x0004,
};
/**
* A startup/shutdown function
*
@@ -50,7 +40,7 @@ enum shutdown_flags {
*/
struct startup_fn {
void ( * startup ) ( void );
void ( * shutdown ) ( int flags );
void ( * shutdown ) ( int booting );
};
/** Startup/shutdown function table */
@@ -76,6 +66,22 @@ struct startup_fn {
extern void initialise ( void );
extern void startup ( void );
extern void shutdown ( int flags );
extern void shutdown ( int booting );
/**
* Shut down system for OS boot
*
*/
static inline void shutdown_boot ( void ) {
shutdown ( 1 );
}
/**
* Shut down system for exit back to firmware
*
*/
static inline void shutdown_exit ( void ) {
shutdown ( 0 );
}
#endif /* _IPXE_INIT_H */
+14
View File
@@ -236,6 +236,9 @@ struct net_device_operations {
*
* @v netdev Network device
* @v enable Interrupts should be enabled
*
* This method may be NULL to indicate that interrupts are not
* supported.
*/
void ( * irq ) ( struct net_device *netdev, int enable );
};
@@ -515,6 +518,17 @@ netdev_is_open ( struct net_device *netdev ) {
return ( netdev->state & NETDEV_OPEN );
}
/**
* Check whether or not network device supports interrupts
*
* @v netdev Network device
* @ret irq_supported Network device supports interrupts
*/
static inline __attribute__ (( always_inline )) int
netdev_irq_supported ( struct net_device *netdev ) {
return ( netdev->op->irq != NULL );
}
/**
* Check whether or not network device interrupts are currently enabled
*
+15 -18
View File
@@ -16,16 +16,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
struct nvs_device;
struct refcnt;
/**
* A fragment of a non-volatile storage device used for stored options
*/
struct nvo_fragment {
/** Starting address of fragment within NVS device */
unsigned int address;
/** Length of fragment */
size_t len;
};
/**
* A block of non-volatile stored options
*/
@@ -34,21 +24,28 @@ struct nvo_block {
struct settings settings;
/** Underlying non-volatile storage device */
struct nvs_device *nvs;
/** List of option-containing fragments
*
* The list is terminated by a fragment with a length of zero.
*/
struct nvo_fragment *fragments;
/** Total length of option-containing fragments */
size_t total_len;
/** Address within NVS device */
unsigned int address;
/** Length of options data */
size_t len;
/** Option-containing data */
void *data;
/**
* Resize non-volatile stored option block
*
* @v nvo Non-volatile options block
* @v len New size
* @ret rc Return status code
*/
int ( * resize ) ( struct nvo_block *nvo, size_t len );
/** DHCP options block */
struct dhcp_options dhcpopts;
};
extern void nvo_init ( struct nvo_block *nvo, struct nvs_device *nvs,
struct nvo_fragment *fragments, struct refcnt *refcnt );
size_t address, size_t len,
int ( * resize ) ( struct nvo_block *nvo, size_t len ),
struct refcnt *refcnt );
extern int register_nvo ( struct nvo_block *nvo, struct settings *parent );
extern void unregister_nvo ( struct nvo_block *nvo );
+8 -8
View File
@@ -13,21 +13,21 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/nvs.h>
#include <ipxe/pcivpd.h>
struct nvo_block;
struct refcnt;
/** An NVS VPD device */
struct nvs_vpd_device {
/** NVS device */
struct nvs_device nvs;
/** PCI VPD device */
struct pci_vpd vpd;
/** Starting address
*
* This address is added to the NVS address to form the VPD
* address.
*/
unsigned int address;
};
extern int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci,
unsigned int field );
extern int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd,
struct pci_device *pci );
extern void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd,
unsigned int field, struct nvo_block *nvo,
struct refcnt *refcnt );
#endif /* IPXE_NVSVPD_H */
+1
View File
@@ -89,6 +89,7 @@ struct socket_opener {
/** Register a socket opener */
#define __socket_opener __table_entry ( SOCKET_OPENERS, 01 )
extern struct uri_opener * xfer_uri_opener ( const char *scheme );
extern int xfer_open_uri ( struct interface *intf, struct uri *uri );
extern int xfer_open_uri_string ( struct interface *intf,
const char *uri_string );
+16
View File
@@ -32,6 +32,9 @@ struct pci_vpd_field {
uint8_t len;
} __attribute__ (( packed ));
/** Maximum PCI VPD field length */
#define PCI_VPD_MAX_LEN 0xff
/** Construct PCI VPD field descriptor
*
* @v tag ISAPnP tag
@@ -133,6 +136,17 @@ struct pci_vpd {
struct pci_vpd_cache cache;
};
/**
* Check for presence of PCI VPD
*
* @v vpd PCI VPD
* @ret is_present VPD is present
*/
static inline __attribute__ (( always_inline )) int
pci_vpd_is_present ( struct pci_vpd *vpd ) {
return ( vpd->cap != 0 );
}
/**
* Check if PCI VPD read cache is valid
*
@@ -161,5 +175,7 @@ extern int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address,
const void *buf, size_t len );
extern int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
unsigned int *address, size_t *len );
extern int pci_vpd_resize ( struct pci_vpd *vpd, unsigned int field,
size_t len, unsigned int *address );
#endif /* _IPXE_PCIVPD_H */
+1
View File
@@ -221,6 +221,7 @@ extern int storef_setting ( struct settings *settings,
const char *value );
extern int storef_named_setting ( const char *name, const char *value );
extern int fetchf_named_setting ( const char *name, char *buf, size_t len );
extern char * expand_settings ( const char *string );
extern struct setting_type setting_type_string __setting_type;
extern struct setting_type setting_type_ipv4 __setting_type;
+5 -5
View File
@@ -11,14 +11,14 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/in.h>
struct net_device;
struct uri;
struct settings;
extern int shutdown_exit_flags;
extern int uriboot ( struct uri *filename, struct uri *root_path );
extern struct uri *
fetch_next_server_and_filename ( struct settings *settings );
extern int netboot ( struct net_device *netdev );
extern int autoboot ( void );
extern int boot_next_server_and_filename ( struct in_addr next_server,
const char *filename );
extern int boot_root_path ( const char *root_path );
extern int pxe_menu_boot ( struct net_device *netdev );
+2
View File
@@ -11,6 +11,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
struct image;
extern int imgdownload ( struct image *image, struct uri *uri,
int ( * image_register ) ( struct image *image ) );
extern int imgfetch ( struct image *image, const char *uri_string,
int ( * image_register ) ( struct image *image ) );
extern int imgload ( struct image *image );
+1 -1
View File
@@ -58,7 +58,7 @@ void store_cached_dhcpack ( userptr_t data, size_t len ) {
dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( * dhcppkt ) );
copy_from_user ( dhcphdr, data, 0, len );
dhcppkt_init ( dhcppkt, dhcphdr, len );
DBG_HD ( dhcppkt->options.data, dhcppkt->options.len );
DBG_HD ( dhcppkt->options.data, dhcppkt->options.used_len );
/* Register settings on the last opened network device.
* This will have the effect of registering cached settings
+71 -68
View File
@@ -117,7 +117,7 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
unsigned int original_tag __attribute__ (( unused )) = tag;
struct dhcp_option *option;
int offset = 0;
ssize_t remaining = options->len;
ssize_t remaining = options->used_len;
unsigned int option_len;
/* Sanity check */
@@ -169,6 +169,17 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
return -ENOENT;
}
/**
* Refuse to reallocate DHCP option block
*
* @v options DHCP option block
* @v len New length
* @ret rc Return status code
*/
int dhcpopt_no_realloc ( struct dhcp_options *options, size_t len ) {
return ( ( len <= options->alloc_len ) ? 0 : -ENOSPC );
}
/**
* Resize a DHCP option
*
@@ -177,46 +188,44 @@ static int find_dhcp_option_with_encap ( struct dhcp_options *options,
* @v encap_offset Offset of encapsulating offset (or -ve for none)
* @v old_len Old length (including header)
* @v new_len New length (including header)
* @v can_realloc Can reallocate options data if necessary
* @ret rc Return status code
*/
static int resize_dhcp_option ( struct dhcp_options *options,
int offset, int encap_offset,
size_t old_len, size_t new_len,
int can_realloc ) {
size_t old_len, size_t new_len ) {
struct dhcp_option *encapsulator;
struct dhcp_option *option;
ssize_t delta = ( new_len - old_len );
size_t new_options_len;
size_t old_alloc_len;
size_t new_used_len;
size_t new_encapsulator_len;
void *new_data;
void *source;
void *dest;
void *end;
int rc;
/* Check for sufficient space, and update length fields */
/* Check for sufficient space */
if ( new_len > DHCP_MAX_LEN ) {
DBGC ( options, "DHCPOPT %p overlength option\n", options );
return -ENOSPC;
}
new_options_len = ( options->len + delta );
if ( new_options_len > options->max_len ) {
/* Reallocate options block if allowed to do so. */
if ( can_realloc ) {
new_data = realloc ( options->data, new_options_len );
if ( ! new_data ) {
DBGC ( options, "DHCPOPT %p could not "
"reallocate to %zd bytes\n", options,
new_options_len );
return -ENOMEM;
}
options->data = new_data;
options->max_len = new_options_len;
} else {
DBGC ( options, "DHCPOPT %p out of space\n", options );
return -ENOMEM;
new_used_len = ( options->used_len + delta );
/* Expand options block, if necessary */
if ( new_used_len > options->alloc_len ) {
/* Reallocate options block */
old_alloc_len = options->alloc_len;
if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
DBGC ( options, "DHCPOPT %p could not reallocate to "
"%zd bytes\n", options, new_used_len );
return rc;
}
/* Clear newly allocated space */
memset ( ( options->data + old_alloc_len ), 0,
( options->alloc_len - old_alloc_len ) );
}
/* Update encapsulator, if applicable */
if ( encap_offset >= 0 ) {
encapsulator = dhcp_option ( options, encap_offset );
new_encapsulator_len = ( encapsulator->len + delta );
@@ -227,15 +236,26 @@ static int resize_dhcp_option ( struct dhcp_options *options,
}
encapsulator->len = new_encapsulator_len;
}
options->len = new_options_len;
/* Update used length */
options->used_len = new_used_len;
/* Move remainder of option data */
option = dhcp_option ( options, offset );
source = ( ( ( void * ) option ) + old_len );
dest = ( ( ( void * ) option ) + new_len );
end = ( options->data + options->max_len );
end = ( options->data + options->alloc_len );
memmove ( dest, source, ( end - dest ) );
/* Shrink options block, if applicable */
if ( new_used_len < options->alloc_len ) {
if ( ( rc = options->realloc ( options, new_used_len ) ) != 0 ){
DBGC ( options, "DHCPOPT %p could not reallocate to "
"%zd bytes\n", options, new_used_len );
return rc;
}
}
return 0;
}
@@ -246,7 +266,6 @@ static int resize_dhcp_option ( struct dhcp_options *options,
* @v tag DHCP option tag
* @v data New value for DHCP option
* @v len Length of value, in bytes
* @v can_realloc Can reallocate options data if necessary
* @ret offset Offset of DHCP option, or negative error
*
* Sets the value of a DHCP option within the options block. The
@@ -258,9 +277,8 @@ static int resize_dhcp_option ( struct dhcp_options *options,
* be left with its original value.
*/
static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
const void *data, size_t len,
int can_realloc ) {
static const uint8_t empty_encapsulator[] = { DHCP_END };
const void *data, size_t len ) {
static const uint8_t empty_encap[] = { DHCP_END };
int offset;
int encap_offset = -1;
int creation_offset;
@@ -277,7 +295,7 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
creation_offset = find_dhcp_option_with_encap ( options, DHCP_END,
NULL );
if ( creation_offset < 0 )
creation_offset = options->len;
creation_offset = options->used_len;
/* Find old instance of this option, if any */
offset = find_dhcp_option_with_encap ( options, tag, &encap_offset );
if ( offset >= 0 ) {
@@ -291,10 +309,12 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
/* Ensure that encapsulator exists, if required */
if ( encap_tag ) {
if ( encap_offset < 0 )
encap_offset = set_dhcp_option ( options, encap_tag,
empty_encapsulator, 1,
can_realloc );
if ( encap_offset < 0 ) {
encap_offset =
set_dhcp_option ( options, encap_tag,
empty_encap,
sizeof ( empty_encap ) );
}
if ( encap_offset < 0 )
return encap_offset;
creation_offset = ( encap_offset + DHCP_OPTION_HEADER_LEN );
@@ -306,8 +326,7 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
/* Resize option to fit new data */
if ( ( rc = resize_dhcp_option ( options, offset, encap_offset,
old_len, new_len,
can_realloc ) ) != 0 )
old_len, new_len ) ) != 0 )
return rc;
/* Copy new data into option, if applicable */
@@ -322,7 +341,7 @@ static int set_dhcp_option ( struct dhcp_options *options, unsigned int tag,
if ( encap_offset >= 0 ) {
option = dhcp_option ( options, encap_offset );
if ( option->len <= 1 )
set_dhcp_option ( options, encap_tag, NULL, 0, 0 );
set_dhcp_option ( options, encap_tag, NULL, 0 );
}
return offset;
@@ -341,26 +360,7 @@ int dhcpopt_store ( struct dhcp_options *options, unsigned int tag,
const void *data, size_t len ) {
int offset;
offset = set_dhcp_option ( options, tag, data, len, 0 );
if ( offset < 0 )
return offset;
return 0;
}
/**
* Store value of DHCP option setting, extending options block if necessary
*
* @v options DHCP option block
* @v tag Setting tag number
* @v data Setting data, or NULL to clear setting
* @v len Length of setting data
* @ret rc Return status code
*/
int dhcpopt_extensible_store ( struct dhcp_options *options, unsigned int tag,
const void *data, size_t len ) {
int offset;
offset = set_dhcp_option ( options, tag, data, len, 1 );
offset = set_dhcp_option ( options, tag, data, len );
if ( offset < 0 )
return offset;
return 0;
@@ -402,14 +402,14 @@ int dhcpopt_fetch ( struct dhcp_options *options, unsigned int tag,
* The "used length" field will be updated based on scanning through
* the block to find the end of the options.
*/
static void dhcpopt_update_len ( struct dhcp_options *options ) {
void dhcpopt_update_used_len ( struct dhcp_options *options ) {
struct dhcp_option *option;
int offset = 0;
ssize_t remaining = options->max_len;
ssize_t remaining = options->alloc_len;
unsigned int option_len;
/* Find last non-pad option */
options->len = 0;
options->used_len = 0;
while ( remaining ) {
option = dhcp_option ( options, offset );
option_len = dhcp_option_len ( option );
@@ -418,7 +418,7 @@ static void dhcpopt_update_len ( struct dhcp_options *options ) {
break;
offset += option_len;
if ( option->tag != DHCP_PAD )
options->len = offset;
options->used_len = offset;
}
}
@@ -427,21 +427,24 @@ static void dhcpopt_update_len ( struct dhcp_options *options ) {
*
* @v options Uninitialised DHCP option block
* @v data Memory for DHCP option data
* @v max_len Length of memory for DHCP option data
* @v alloc_len Length of memory for DHCP option data
* @v realloc DHCP option block reallocator
*
* The memory content must already be filled with valid DHCP options.
* A zeroed block counts as a block of valid DHCP options.
*/
void dhcpopt_init ( struct dhcp_options *options, void *data,
size_t max_len ) {
void dhcpopt_init ( struct dhcp_options *options, void *data, size_t alloc_len,
int ( * realloc ) ( struct dhcp_options *options,
size_t len ) ) {
/* Fill in fields */
options->data = data;
options->max_len = max_len;
options->alloc_len = alloc_len;
options->realloc = realloc;
/* Update length */
dhcpopt_update_len ( options );
dhcpopt_update_used_len ( options );
DBGC ( options, "DHCPOPT %p created (data %p len %#zx max_len %#zx)\n",
options, options->data, options->len, options->max_len );
DBGC ( options, "DHCPOPT %p created (data %p lengths %#zx,%#zx)\n",
options, options->data, options->used_len, options->alloc_len );
}
+3 -12
View File
@@ -147,7 +147,6 @@ int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
const void *data, size_t len ) {
struct dhcp_packet_field *field;
void *field_data;
int rc;
/* If this is a special field, fill it in */
if ( ( field = find_dhcp_packet_field ( tag ) ) != NULL ) {
@@ -163,13 +162,7 @@ int dhcppkt_store ( struct dhcp_packet *dhcppkt, unsigned int tag,
}
/* Otherwise, use the generic options block */
rc = dhcpopt_store ( &dhcppkt->options, tag, data, len );
/* Update our used-length field */
dhcppkt->len = ( offsetof ( struct dhcphdr, options ) +
dhcppkt->options.len );
return rc;
return dhcpopt_store ( &dhcppkt->options, tag, data, len );
}
/**
@@ -273,11 +266,9 @@ void dhcppkt_init ( struct dhcp_packet *dhcppkt, struct dhcphdr *data,
size_t len ) {
ref_init ( &dhcppkt->refcnt, NULL );
dhcppkt->dhcphdr = data;
dhcppkt->max_len = len;
dhcpopt_init ( &dhcppkt->options, &dhcppkt->dhcphdr->options,
( len - offsetof ( struct dhcphdr, options ) ) );
dhcppkt->len = ( offsetof ( struct dhcphdr, options ) +
dhcppkt->options.len );
( len - offsetof ( struct dhcphdr, options ) ),
dhcpopt_no_realloc );
settings_init ( &dhcppkt->settings,
&dhcppkt_settings_operations, &dhcppkt->refcnt, 0 );
}
+4
View File
@@ -542,6 +542,10 @@ void unregister_netdev ( struct net_device *netdev ) {
*/
void netdev_irq ( struct net_device *netdev, int enable ) {
/* Do nothing if device does not support interrupts */
if ( ! netdev_irq_supported ( netdev ) )
return;
/* Enable or disable device interrupts */
netdev->op->irq ( netdev, enable );
+1 -1
View File
@@ -1122,7 +1122,7 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
}
/* Transmit the packet */
iob_put ( iobuf, dhcppkt.len );
iob_put ( iobuf, dhcppkt_len ( &dhcppkt ) );
if ( ( rc = xfer_deliver ( &dhcp->xfer, iob_disown ( iobuf ),
&meta ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
+207 -134
View File
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/image.h>
#include <ipxe/sanboot.h>
#include <ipxe/uri.h>
#include <ipxe/open.h>
#include <ipxe/init.h>
#include <usr/ifmgmt.h>
#include <usr/route.h>
@@ -40,9 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
/** Shutdown flags for exit */
int shutdown_exit_flags = 0;
/**
* Perform PXE menu boot when PXE stack is not available
*/
@@ -60,30 +58,21 @@ static struct net_device * find_boot_netdev ( void ) {
}
/**
* Boot using next-server and filename
* Parse next-server and filename into a URI
*
* @v filename Boot filename
* @ret rc Return status code
* @v next_server Next-server address
* @v filename Filename
* @ret uri URI, or NULL on failure
*/
int boot_next_server_and_filename ( struct in_addr next_server,
const char *filename ) {
static struct uri * parse_next_server_and_filename ( struct in_addr next_server,
const char *filename ) {
struct uri *uri;
struct image *image;
char buf[ 23 /* tftp://xxx.xxx.xxx.xxx/ */ +
( 3 * strlen(filename) ) /* completely URI-encoded */
+ 1 /* NUL */ ];
int filename_is_absolute;
int rc;
struct uri *tmp;
/* Construct URI */
/* Parse filename */
uri = parse_uri ( filename );
if ( ! uri ) {
printf ( "Could not parse \"%s\"\n", filename );
rc = -ENOMEM;
goto err_parse_uri;
}
filename_is_absolute = uri_is_absolute ( uri );
uri_put ( uri );
if ( ! uri )
return NULL;
/* Construct a tftp:// URI for the filename, if applicable.
* We can't just rely on the current working URI, because the
@@ -91,41 +80,17 @@ int boot_next_server_and_filename ( struct in_addr next_server,
* filenames with and without initial slashes, which is
* significant for TFTP.
*/
if ( ! filename_is_absolute ) {
snprintf ( buf, sizeof ( buf ), "tftp://%s/",
inet_ntoa ( next_server ) );
uri_encode ( filename, buf + strlen ( buf ),
sizeof ( buf ) - strlen ( buf ), URI_PATH );
filename = buf;
if ( ! uri_is_absolute ( uri ) ) {
tmp = uri;
tmp->scheme = "tftp";
tmp->host = inet_ntoa ( next_server );
uri = uri_dup ( tmp );
uri_put ( tmp );
if ( ! uri )
return NULL;
}
/* Download and boot image */
image = alloc_image();
if ( ! image ) {
printf ( "Could not allocate image\n" );
rc = -ENOMEM;
goto err_alloc_image;
}
if ( ( rc = imgfetch ( image, filename,
register_and_autoload_image ) ) != 0 ) {
printf ( "Could not fetch image: %s\n", strerror ( rc ) );
goto err_imgfetch;
}
if ( ( rc = imgexec ( image ) ) != 0 ) {
printf ( "Could not execute image: %s\n", strerror ( rc ) );
goto err_imgexec;
}
/* Drop image reference */
image_put ( image );
return 0;
err_imgexec:
err_imgfetch:
image_put ( image );
err_alloc_image:
err_parse_uri:
return rc;
return uri;
}
/** The "keep-san" setting */
@@ -145,72 +110,99 @@ struct setting skip_san_boot_setting __setting = {
};
/**
* Boot using root path
* Boot from filename and root-path URIs
*
* @v filename Filename
* @v root_path Root path
* @ret rc Return status code
*/
int boot_root_path ( const char *root_path ) {
struct uri *uri;
int uriboot ( struct uri *filename, struct uri *root_path ) {
struct image *image;
int drive;
int rc;
/* Parse URI */
uri = parse_uri ( root_path );
if ( ! uri ) {
printf ( "Could not parse \"%s\"\n", root_path );
/* Allocate image */
image = alloc_image();
if ( ! image ) {
printf ( "Could not allocate image\n" );
rc = -ENOMEM;
goto err_parse_uri;
goto err_alloc_image;
}
/* Hook SAN device */
if ( ( drive = san_hook ( uri, 0 ) ) < 0 ) {
rc = drive;
printf ( "Could not open SAN device: %s\n",
strerror ( rc ) );
goto err_open;
}
printf ( "Registered as SAN device %#02x\n", drive );
/* Treat empty URIs as absent */
if ( filename && ( ! filename->path ) )
filename = NULL;
if ( root_path && ( ! uri_is_absolute ( root_path ) ) )
root_path = NULL;
/* Describe SAN device */
if ( ( rc = san_describe ( drive ) ) != 0 ) {
/* If we have both a filename and a root path, ignore an
* unsupported URI scheme in the root path, since it may
* represent an NFS root.
*/
if ( filename && root_path &&
( xfer_uri_opener ( root_path->scheme ) == NULL ) ) {
printf ( "Ignoring unsupported root path\n" );
root_path = NULL;
}
/* Hook SAN device, if applicable */
if ( root_path ) {
drive = san_hook ( root_path, 0 );
if ( drive < 0 ) {
rc = drive;
printf ( "Could not open SAN device: %s\n",
strerror ( rc ) );
goto err_san_hook;
}
printf ( "Registered as SAN device %#02x\n", drive );
} else {
drive = -ENODEV;
}
/* Describe SAN device, if applicable */
if ( ( drive >= 0 ) && ( ( rc = san_describe ( drive ) ) != 0 ) ) {
printf ( "Could not describe SAN device %#02x: %s\n",
drive, strerror ( rc ) );
goto err_describe;
goto err_san_describe;
}
/* Boot from SAN device */
if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) != 0 ) {
printf ( "Skipping boot from SAN device %#02x\n", drive );
/* Attempt filename or SAN boot as applicable */
if ( filename ) {
if ( ( rc = imgdownload ( image, filename,
register_and_autoexec_image ) ) !=0){
printf ( "Could not chain image: %s\n",
strerror ( rc ) );
}
} else if ( root_path ) {
if ( fetch_intz_setting ( NULL, &skip_san_boot_setting) == 0 ) {
printf ( "Booting from SAN device %#02x\n", drive );
rc = san_boot ( drive );
printf ( "Boot from SAN device %#02x failed: %s\n",
drive, strerror ( rc ) );
} else {
printf ( "Skipping boot from SAN device %#02x\n",
drive );
rc = 0;
}
} else {
printf ( "Booting from SAN device %#02x\n", drive );
rc = san_boot ( drive );
printf ( "Boot from SAN device %#02x failed: %s\n",
drive, strerror ( rc ) );
printf ( "No filename or root path specified\n" );
rc = -ENOENT;
}
/* Leave drive registered, if instructed to do so */
if ( fetch_intz_setting ( NULL, &keep_san_setting ) != 0 ) {
printf ( "Preserving connection to SAN device %#02x\n",
drive );
shutdown_exit_flags |= SHUTDOWN_KEEP_DEVICES;
goto err_keep_san;
err_san_describe:
/* Unhook SAN device, if applicable */
if ( drive >= 0 ) {
if ( fetch_intz_setting ( NULL, &keep_san_setting ) == 0 ) {
printf ( "Unregistering SAN device %#02x\n", drive );
san_unhook ( drive );
} else {
printf ( "Preserving connection to SAN device %#02x\n",
drive );
}
}
/* Unhook SAN deivce */
printf ( "Unregistering SAN device %#02x\n", drive );
san_unhook ( drive );
/* Drop URI reference */
uri_put ( uri );
return 0;
err_keep_san:
err_describe:
err_open:
uri_put ( uri );
err_parse_uri:
err_san_hook:
image_put ( image );
err_alloc_image:
return rc;
}
@@ -231,12 +223,75 @@ static void close_all_netdevs ( void ) {
}
/**
* Boot from a network device
* Fetch next-server and filename settings into a URI
*
* @v netdev Network device
* @ret rc Return status code
* @v settings Settings block
* @ret uri URI, or NULL on failure
*/
int netboot ( struct net_device *netdev ) {
struct uri * fetch_next_server_and_filename ( struct settings *settings ) {
struct in_addr next_server;
char buf[256];
char *filename;
struct uri *uri;
/* Fetch next-server setting */
fetch_ipv4_setting ( settings, &next_server_setting, &next_server );
if ( next_server.s_addr )
printf ( "Next server: %s\n", inet_ntoa ( next_server ) );
/* Fetch filename setting */
fetch_string_setting ( settings, &filename_setting,
buf, sizeof ( buf ) );
if ( buf[0] )
printf ( "Filename: %s\n", buf );
/* Expand filename setting */
filename = expand_settings ( buf );
if ( ! filename )
return NULL;
/* Parse next server and filename */
uri = parse_next_server_and_filename ( next_server, filename );
free ( filename );
return uri;
}
/**
* Fetch root-path setting into a URI
*
* @v settings Settings block
* @ret uri URI, or NULL on failure
*/
static struct uri * fetch_root_path ( struct settings *settings ) {
char buf[256];
char *root_path;
struct uri *uri;
/* Fetch root-path setting */
fetch_string_setting ( settings, &root_path_setting,
buf, sizeof ( buf ) );
if ( buf[0] )
printf ( "Root path: %s\n", buf );
/* Expand filename setting */
root_path = expand_settings ( buf );
if ( ! root_path )
return NULL;
/* Parse root path */
uri = parse_uri ( root_path );
free ( root_path );
return uri;
}
/**
* Check whether or not we have a usable PXE menu
*
* @ret have_menu A usable PXE menu is present
*/
static int have_pxe_menu ( void ) {
struct setting vendor_class_id_setting
= { .tag = DHCP_VENDOR_CLASS_ID };
struct setting pxe_discovery_control_setting
@@ -244,8 +299,28 @@ int netboot ( struct net_device *netdev ) {
struct setting pxe_boot_menu_setting
= { .tag = DHCP_PXE_BOOT_MENU };
char buf[256];
struct in_addr next_server;
unsigned int pxe_discovery_control;
fetch_string_setting ( NULL, &vendor_class_id_setting,
buf, sizeof ( buf ) );
pxe_discovery_control =
fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
return ( ( strcmp ( buf, "PXEClient" ) == 0 ) &&
setting_exists ( NULL, &pxe_boot_menu_setting ) &&
( ! ( ( pxe_discovery_control & PXEBS_SKIP ) &&
setting_exists ( NULL, &filename_setting ) ) ) );
}
/**
* Boot from a network device
*
* @v netdev Network device
* @ret rc Return status code
*/
int netboot ( struct net_device *netdev ) {
struct uri *filename;
struct uri *root_path;
int rc;
/* Close all other network devices */
@@ -253,44 +328,42 @@ int netboot ( struct net_device *netdev ) {
/* Open device and display device status */
if ( ( rc = ifopen ( netdev ) ) != 0 )
return rc;
goto err_ifopen;
ifstat ( netdev );
/* Configure device via DHCP */
if ( ( rc = dhcp ( netdev ) ) != 0 )
return rc;
goto err_dhcp;
route();
/* Try PXE menu boot, if applicable */
fetch_string_setting ( NULL, &vendor_class_id_setting,
buf, sizeof ( buf ) );
pxe_discovery_control =
fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
if ( ( strcmp ( buf, "PXEClient" ) == 0 ) &&
setting_exists ( NULL, &pxe_boot_menu_setting ) &&
( ! ( ( pxe_discovery_control & PXEBS_SKIP ) &&
setting_exists ( NULL, &filename_setting ) ) ) ) {
if ( have_pxe_menu() ) {
printf ( "Booting from PXE menu\n" );
return pxe_menu_boot ( netdev );
rc = pxe_menu_boot ( netdev );
goto err_pxe_menu_boot;
}
/* Try to download and boot whatever we are given as a filename */
fetch_ipv4_setting ( NULL, &next_server_setting, &next_server );
fetch_string_setting ( NULL, &filename_setting, buf, sizeof ( buf ) );
if ( buf[0] ) {
printf ( "Booting from filename \"%s\"\n", buf );
return boot_next_server_and_filename ( next_server, buf );
}
/* No filename; try the root path */
fetch_string_setting ( NULL, &root_path_setting, buf, sizeof ( buf ) );
if ( buf[0] ) {
printf ( "Booting from root path \"%s\"\n", buf );
return boot_root_path ( buf );
}
/* Fetch next server, filename and root path */
filename = fetch_next_server_and_filename ( NULL );
if ( ! filename )
goto err_filename;
root_path = fetch_root_path ( NULL );
if ( ! root_path )
goto err_root_path;
printf ( "No filename or root path specified\n" );
return -ENOENT;
/* Boot using next server, filename and root path */
if ( ( rc = uriboot ( filename, root_path ) ) != 0 )
goto err_uriboot;
err_uriboot:
uri_put ( root_path );
err_root_path:
uri_put ( filename );
err_filename:
err_pxe_menu_boot:
err_dhcp:
err_ifopen:
return rc;
}
/**
+37 -14
View File
@@ -36,24 +36,21 @@ FILE_LICENCE ( GPL2_OR_LATER );
*/
/**
* Fetch an image
* Download an image
*
* @v uri_string URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
* @v name Name for image, or NULL
* @v register_image Image registration routine
* @v image Image
* @v uri URI
* @v image_register Action to take upon a successful download
* @ret rc Return status code
*/
int imgfetch ( struct image *image, const char *uri_string,
int ( * image_register ) ( struct image *image ) ) {
char uri_string_redacted[ strlen ( uri_string ) + 3 /* "***" */
+ 1 /* NUL */ ];
struct uri *uri;
int imgdownload ( struct image *image, struct uri *uri,
int ( * image_register ) ( struct image *image ) ) {
size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 );
char uri_string_redacted[len];
const char *password;
int rc;
if ( ! ( uri = parse_uri ( uri_string ) ) )
return -ENOMEM;
/* Set image URI */
image_set_uri ( image, uri );
/* Redact password portion of URI, if necessary */
@@ -64,9 +61,35 @@ int imgfetch ( struct image *image, const char *uri_string,
uri, URI_ALL );
uri->password = password;
/* Create downloader */
if ( ( rc = create_downloader ( &monojob, image, image_register,
LOCATION_URI, uri ) ) == 0 )
rc = monojob_wait ( uri_string_redacted );
LOCATION_URI, uri ) ) != 0 )
return rc;
/* Wait for download to complete */
if ( ( rc = monojob_wait ( uri_string_redacted ) ) != 0 )
return rc;
return 0;
}
/**
* Fetch an image
*
* @v image Image
* @v uri_string URI as a string (e.g. "http://www.nowhere.com/vmlinuz")
* @v image_register Action to take upon a successful fetch
* @ret rc Return status code
*/
int imgfetch ( struct image *image, const char *uri_string,
int ( * image_register ) ( struct image *image ) ) {
struct uri *uri;
int rc;
if ( ! ( uri = parse_uri ( uri_string ) ) )
return -ENOMEM;
rc = imgdownload ( image, uri, image_register );
uri_put ( uri );
return rc;
+11 -8
View File
@@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/keys.h>
#include <ipxe/timer.h>
#include <ipxe/process.h>
#include <ipxe/uri.h>
#include <usr/dhcpmgmt.h>
#include <usr/autoboot.h>
@@ -346,8 +347,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
struct pxe_menu *menu;
unsigned int pxe_type;
struct settings *pxebs_settings;
struct in_addr next_server;
char filename[256];
struct uri *uri;
int rc;
/* Parse and allocate boot menu */
@@ -372,12 +372,15 @@ int pxe_menu_boot ( struct net_device *netdev ) {
if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 )
return rc;
/* Attempt boot */
/* Fetch next server and filename */
pxebs_settings = find_settings ( PXEBS_SETTINGS_NAME );
assert ( pxebs_settings );
fetch_ipv4_setting ( pxebs_settings, &next_server_setting,
&next_server );
fetch_string_setting ( pxebs_settings, &filename_setting,
filename, sizeof ( filename ) );
return boot_next_server_and_filename ( next_server, filename );
uri = fetch_next_server_and_filename ( pxebs_settings );
if ( ! uri )
return -ENOMEM;
/* Attempt boot */
rc = uriboot ( uri, NULL );
uri_put ( uri );
return rc;
}