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:
@@ -300,6 +300,7 @@ ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9
|
||||
#=======================================================================
|
||||
#boot: floppy
|
||||
#boot: disk
|
||||
boot: network, floppy
|
||||
|
||||
#=======================================================================
|
||||
# CLOCK:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ),
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 ) ) {
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ) {
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -85,7 +85,7 @@ __asmcall int main ( void ) {
|
||||
shell();
|
||||
}
|
||||
|
||||
shutdown ( SHUTDOWN_EXIT | shutdown_exit_flags );
|
||||
shutdown_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+122
-92
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
@@ -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
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 ) )
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 );
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 );
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user