From 0d04635ef0e4fa0850716c03163e120c63125df7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 5 Apr 2023 13:41:53 +0100 Subject: [efi] Remove redundant zero padding in PE header Hybrid bzImage and UEFI binaries (such as wimboot) require the PE header to be kept as small as possible, since the bzImage header starts at a fixed offset 0x1f1. The PE header currently includes 128 bytes of zero padding between the DOS and NT header portions. This padding has been present since commit 81d92c6 ("[efi] Add EFI image format and basic runtime environment") first added support for EFI images in iPXE, and was included on the basis of matching the observed behaviour of the Microsoft toolchain. There appears to be no requirement for this padding to exist: EDK2 binaries built with gcc include only 64 bytes of zero padding, Linux kernel binaries include 66 bytes of non-zero padding, and wimboot binaries include no padding at all. Remove the unnecessary padding between the DOS and NT header portions to minimise the overall size of the PE header. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index cea9abf8..159f14e7 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -191,7 +191,6 @@ struct pe_relocs { struct pe_header { EFI_IMAGE_DOS_HEADER dos; - uint8_t padding[128]; EFI_IMAGE_NT_HEADERS nt; }; -- cgit v1.2.3-55-g7522 From 1e4c3789e95393a1b87a0b2147bed82a87576673 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 10 Apr 2023 16:44:36 +0100 Subject: [efi] Shrink size of data directory in PE header Hybrid bzImage and UEFI binaries (such as wimboot) require the PE header to be kept as small as possible, since the bzImage header starts at a fixed offset 0x1f1. The EFI_IMAGE_OPTIONAL_HEADER structures in PeImage.h define an optional header containing 16 data directory entries, of which the last eight are unused in binaries that we create. Shrink the data directory to contain only the first eight entries, to minimise the overall size of the PE header. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 159f14e7..a68154e4 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -168,6 +168,9 @@ */ #define EFI_IMAGE_ALIGN 0x1000 +/** Number of data directory entries */ +#define NUMBER_OF_DIRECTORY_ENTRIES 8 + struct elf_file { void *data; size_t len; @@ -204,7 +207,11 @@ static struct pe_header efi_pe_header = { .FileHeader = { .TimeDateStamp = 0x10d1a884, .SizeOfOptionalHeader = - sizeof ( efi_pe_header.nt.OptionalHeader ), + ( sizeof ( efi_pe_header.nt.OptionalHeader ) - + ( ( EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES - + NUMBER_OF_DIRECTORY_ENTRIES ) * + sizeof ( efi_pe_header.nt.OptionalHeader. + DataDirectory[0] ) ) ), .Characteristics = ( EFI_IMAGE_FILE_DLL | EFI_IMAGE_FILE_MACHINE | EFI_IMAGE_FILE_EXECUTABLE_IMAGE ), @@ -217,8 +224,7 @@ static struct pe_header efi_pe_header = { .FileAlignment = EFI_FILE_ALIGN, .SizeOfImage = EFI_IMAGE_ALIGN, .SizeOfHeaders = sizeof ( efi_pe_header ), - .NumberOfRvaAndSizes = - EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES, + .NumberOfRvaAndSizes = NUMBER_OF_DIRECTORY_ENTRIES, }, }, }; @@ -930,7 +936,10 @@ static void write_pe_file ( struct pe_header *pe_header, } /* Write file header */ - if ( fwrite ( pe_header, sizeof ( *pe_header ), 1, pe ) != 1 ) { + if ( fwrite ( pe_header, + ( offsetof ( typeof ( *pe_header ), nt.OptionalHeader ) + + pe_header->nt.FileHeader.SizeOfOptionalHeader ), + 1, pe ) != 1 ) { perror ( "Could not write PE header" ); exit ( 1 ); } -- cgit v1.2.3-55-g7522 From 9fb28080d97fac1061660befacfad8caaa2bc522 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 5 Apr 2023 13:29:29 +0100 Subject: [efi] Allow elf2efi to be used for hybrid binaries Hybrid 32-bit BIOS and 64-bit UEFI binaries (such as wimboot) may include R_X86_64_32 relocation records for the 32-bit BIOS portions. These should be ignored when generating PE relocation records, since they apply only to code that cannot be executed within the context of the 64-bit UEFI binary, and creating a 4-byte relocation record is invalid in a binary that may be relocated anywhere within the 64-bit address space (see commit 907cffb "[efi] Disallow R_X86_64_32 relocations"). Add a "--hybrid" option to elf2efi, which will cause R_X86_64_32 relocation records to be silently discarded. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index a68154e4..61ac0e27 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -231,7 +231,10 @@ static struct pe_header efi_pe_header = { /** Command-line options */ struct options { + /** PE32+ subsystem type */ unsigned int subsystem; + /** Create hybrid BIOS/UEFI binary */ + int hybrid; }; /** @@ -678,10 +681,12 @@ static struct pe_section * process_section ( struct elf_file *elf, * @v nsyms Number of symbol table entries * @v rel Relocation record * @v pe_reltab PE relocation table to fill in + * @v opts Options */ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, const Elf_Sym *syms, unsigned int nsyms, - const Elf_Rel *rel, struct pe_relocs **pe_reltab ) { + const Elf_Rel *rel, struct pe_relocs **pe_reltab, + struct options *opts ) { unsigned int type = ELF_R_TYPE ( rel->r_info ); unsigned int sym = ELF_R_SYM ( rel->r_info ); unsigned int mrel = ELF_MREL ( elf->ehdr->e_machine, type ); @@ -744,6 +749,15 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, * loaded. */ break; + case ELF_MREL ( EM_X86_64, R_X86_64_32 ) : + /* Ignore 32-bit relocations in a hybrid + * 32-bit BIOS and 64-bit UEFI binary, + * otherwise fall through to treat as an + * unknown type. + */ + if ( opts->hybrid ) + break; + /* fallthrough */ default: eprintf ( "Unrecognised relocation type %d\n", type ); exit ( 1 ); @@ -758,9 +772,11 @@ static void process_reloc ( struct elf_file *elf, const Elf_Shdr *shdr, * @v shdr ELF section header * @v stride Relocation record size * @v pe_reltab PE relocation table to fill in + * @v opts Options */ static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr, - size_t stride, struct pe_relocs **pe_reltab ) { + size_t stride, struct pe_relocs **pe_reltab, + struct options *opts ) { const Elf_Shdr *symtab; const Elf_Sym *syms; const Elf_Rel *rel; @@ -778,7 +794,7 @@ static void process_relocs ( struct elf_file *elf, const Elf_Shdr *shdr, rel = ( elf->data + shdr->sh_offset ); nrels = ( shdr->sh_size / stride ); for ( i = 0 ; i < nrels ; i++ ) { - process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab ); + process_reloc ( elf, shdr, syms, nsyms, rel, pe_reltab, opts ); rel = ( ( ( const void * ) rel ) + stride ); } } @@ -977,6 +993,7 @@ static void write_pe_file ( struct pe_header *pe_header, * * @v elf_name ELF file name * @v pe_name PE file name + * @v opts Options */ static void elf2pe ( const char *elf_name, const char *pe_name, struct options *opts ) { @@ -1020,13 +1037,13 @@ static void elf2pe ( const char *elf_name, const char *pe_name, /* Process .rel relocations */ process_relocs ( &elf, shdr, sizeof ( Elf_Rel ), - &pe_reltab ); + &pe_reltab, opts ); } else if ( shdr->sh_type == SHT_RELA ) { /* Process .rela relocations */ process_relocs ( &elf, shdr, sizeof ( Elf_Rela ), - &pe_reltab ); + &pe_reltab, opts ); } } @@ -1079,11 +1096,12 @@ static int parse_options ( const int argc, char **argv, int option_index = 0; static struct option long_options[] = { { "subsystem", required_argument, NULL, 's' }, + { "hybrid", no_argument, NULL, 'H' }, { "help", 0, NULL, 'h' }, { 0, 0, 0, 0 } }; - if ( ( c = getopt_long ( argc, argv, "s:h", + if ( ( c = getopt_long ( argc, argv, "s:Hh", long_options, &option_index ) ) == -1 ) { break; @@ -1098,6 +1116,9 @@ static int parse_options ( const int argc, char **argv, exit ( 2 ); } break; + case 'H': + opts->hybrid = 1; + break; case 'h': print_help ( argv[0] ); exit ( 0 ); -- cgit v1.2.3-55-g7522 From bd13697446e758d5fed6afcba8f3e9883b2e2de7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 10 Apr 2023 16:55:28 +0100 Subject: [efi] Allow for sections to be excluded from the generated PE file Hybrid bzImage and UEFI binaries (such as wimboot) include a bzImage header within a section starting at offset zero, with the PE header effectively occupying unused space within this section. This section should not appear as a named section in the resulting PE file. Allow for the existence of hidden sections that do not result in a section header being written to the PE file. Signed-off-by: Michael Brown --- src/util/elf2efi.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index 61ac0e27..5b3e785f 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -181,6 +181,7 @@ struct pe_section { struct pe_section *next; EFI_IMAGE_SECTION_HEADER hdr; void ( * fixup ) ( struct pe_section *section ); + int hidden; uint8_t contents[0]; }; @@ -641,10 +642,12 @@ static struct pe_section * process_section ( struct elf_file *elf, /* Update RVA limits */ start = new->hdr.VirtualAddress; end = ( start + new->hdr.Misc.VirtualSize ); - if ( ( ! *applicable_start ) || ( *applicable_start >= start ) ) - *applicable_start = start; - if ( *applicable_end < end ) - *applicable_end = end; + if ( ! new->hidden ) { + if ( ( ! *applicable_start ) || ( *applicable_start >= start ) ) + *applicable_start = start; + if ( *applicable_end < end ) + *applicable_end = end; + } if ( data_start < code_end ) data_start = code_end; if ( data_mid < data_start ) @@ -664,8 +667,11 @@ static struct pe_section * process_section ( struct elf_file *elf, ( data_end - data_mid ); /* Update remaining file header fields */ - pe_header->nt.FileHeader.NumberOfSections++; - pe_header->nt.OptionalHeader.SizeOfHeaders += sizeof ( new->hdr ); + if ( ! new->hidden ) { + pe_header->nt.FileHeader.NumberOfSections++; + pe_header->nt.OptionalHeader.SizeOfHeaders += + sizeof ( new->hdr ); + } pe_header->nt.OptionalHeader.SizeOfImage = efi_image_align ( data_end ); @@ -935,6 +941,7 @@ static void write_pe_file ( struct pe_header *pe_header, FILE *pe ) { struct pe_section *section; unsigned long fpos = 0; + unsigned int count = 0; /* Align length of headers */ fpos = pe_header->nt.OptionalHeader.SizeOfHeaders = @@ -962,12 +969,16 @@ static void write_pe_file ( struct pe_header *pe_header, /* Write section headers */ for ( section = pe_sections ; section ; section = section->next ) { + if ( section->hidden ) + continue; if ( fwrite ( §ion->hdr, sizeof ( section->hdr ), 1, pe ) != 1 ) { perror ( "Could not write section header" ); exit ( 1 ); } + count++; } + assert ( count == pe_header->nt.FileHeader.NumberOfSections ); /* Write sections */ for ( section = pe_sections ; section ; section = section->next ) { -- cgit v1.2.3-55-g7522 From 22cc65535a331f05863f3c4b48910b0d50ff5dd7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 4 May 2023 15:29:23 +0100 Subject: [efi] Allow downloaded images to take precedence over constructed files Try searching for a matching registered image before checking for fixed filenames (such as "initrd.magic" for the dynamically generated magic initrd file). This minimises surprise by ensuring that an explicitly downloaded image will always be used verbatim. Signed-off-by: Michael Brown --- src/interface/efi/efi_file.c | 55 ++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index b232591d..2ac6e2b2 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -320,6 +320,33 @@ static void efi_file_image ( struct efi_file *file, struct image *image ) { file->read = efi_file_read_image; } +/** + * Open image-backed file + * + * @v image Image + * @v new New EFI file + * @ret efirc EFI status code + */ +static EFI_STATUS efi_file_open_image ( struct image *image, + EFI_FILE_PROTOCOL **new ) { + struct efi_file *file; + + /* Allocate and initialise file */ + file = zalloc ( sizeof ( *file ) ); + if ( ! file ) + return EFI_OUT_OF_RESOURCES; + ref_init ( &file->refcnt, efi_file_free ); + memcpy ( &file->file, &efi_file_root.file, sizeof ( file->file ) ); + memcpy ( &file->load, &efi_file_root.load, sizeof ( file->load ) ); + efi_file_image ( file, image_get ( image ) ); + + /* Return opened file */ + *new = &file->file; + + DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) ); + return 0; +} + /** * Open file * @@ -335,7 +362,6 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, CHAR16 *wname, UINT64 mode, UINT64 attributes __unused ) { struct efi_file *file = container_of ( this, struct efi_file, file ); char buf[ wcslen ( wname ) + 1 /* NUL */ ]; - struct efi_file *new_file; struct image *image; char *name; @@ -367,31 +393,16 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, return EFI_WRITE_PROTECTED; } + /* Allow registered images to be opened */ + if ( ( image = efi_file_find ( name ) ) != NULL ) + return efi_file_open_image ( image, new ); + /* Allow magic initrd to be opened */ if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 ) return efi_file_open_fixed ( &efi_file_initrd.file, new ); - /* Identify image */ - image = efi_file_find ( name ); - if ( ! image ) { - DBGC ( file, "EFIFILE %s does not exist\n", name ); - return EFI_NOT_FOUND; - } - - /* Allocate and initialise file */ - new_file = zalloc ( sizeof ( *new_file ) ); - if ( ! new_file ) - return EFI_OUT_OF_RESOURCES; - ref_init ( &file->refcnt, efi_file_free ); - memcpy ( &new_file->file, &efi_file_root.file, - sizeof ( new_file->file ) ); - memcpy ( &new_file->load, &efi_file_root.load, - sizeof ( new_file->load ) ); - efi_file_image ( new_file, image_get ( image ) ); - *new = &new_file->file; - DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) ); - - return 0; + DBGC ( file, "EFIFILE %s does not exist\n", name ); + return EFI_NOT_FOUND; } /** -- cgit v1.2.3-55-g7522 From f93e6b712ff2beb7ea4e169a681b8144785f3e49 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 May 2023 12:46:54 +0100 Subject: [efi] Show original filenames in debug messages Show the original filename as used by the consumer when calling our EFI_SIMPLE_FILE_SYSTEM_PROTOCOL's Open() method. Signed-off-by: Michael Brown --- src/interface/efi/efi_file.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index 2ac6e2b2..fd0bcc6c 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -291,10 +291,12 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) { * Open fixed file * * @v file EFI file + * @v wname Filename * @v new New EFI file * @ret efirc EFI status code */ static EFI_STATUS efi_file_open_fixed ( struct efi_file *file, + const wchar_t *wname, EFI_FILE_PROTOCOL **new ) { /* Increment reference count */ @@ -303,7 +305,8 @@ static EFI_STATUS efi_file_open_fixed ( struct efi_file *file, /* Return opened file */ *new = &file->file; - DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) ); + DBGC ( file, "EFIFILE %s opened via %ls\n", + efi_file_name ( file ), wname ); return 0; } @@ -324,10 +327,12 @@ static void efi_file_image ( struct efi_file *file, struct image *image ) { * Open image-backed file * * @v image Image + * @v wname Filename * @v new New EFI file * @ret efirc EFI status code */ static EFI_STATUS efi_file_open_image ( struct image *image, + const wchar_t *wname, EFI_FILE_PROTOCOL **new ) { struct efi_file *file; @@ -343,7 +348,8 @@ static EFI_STATUS efi_file_open_image ( struct image *image, /* Return opened file */ *new = &file->file; - DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) ); + DBGC ( file, "EFIFILE %s opened via %ls\n", + efi_file_name ( file ), wname ); return 0; } @@ -377,7 +383,7 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, /* Allow root directory itself to be opened */ if ( ( name[0] == '\0' ) || ( name[0] == '.' ) ) - return efi_file_open_fixed ( &efi_file_root, new ); + return efi_file_open_fixed ( &efi_file_root, wname, new ); /* Fail unless opening from the root */ if ( file != &efi_file_root ) { @@ -395,13 +401,15 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, /* Allow registered images to be opened */ if ( ( image = efi_file_find ( name ) ) != NULL ) - return efi_file_open_image ( image, new ); + return efi_file_open_image ( image, wname, new ); /* Allow magic initrd to be opened */ - if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 ) - return efi_file_open_fixed ( &efi_file_initrd.file, new ); + if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 ) { + return efi_file_open_fixed ( &efi_file_initrd.file, wname, + new ); + } - DBGC ( file, "EFIFILE %s does not exist\n", name ); + DBGC ( file, "EFIFILE %ls does not exist\n", wname ); return EFI_NOT_FOUND; } @@ -832,7 +840,7 @@ efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused, EFI_FILE_PROTOCOL **file ) { DBGC ( &efi_file_root, "EFIFILE open volume\n" ); - return efi_file_open_fixed ( &efi_file_root, file ); + return efi_file_open_fixed ( &efi_file_root, L"", file ); } /** EFI simple file system protocol */ -- cgit v1.2.3-55-g7522 From f9beb20e99abbfcbea7cf222ba692aa3cbf10df7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 4 May 2023 14:21:42 +0100 Subject: [image] Allow for images to be hidden from lists of all images When invoking a kernel via the UEFI shim, the kernel (and potentially also a helper binary such as GRUB) must be accessible via the virtual filesystem exposed via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL but must not be present in the magic initrd constructed from all registered images. Allow for images to be flagged as hidden, which will cause them to be excluded from API-level lists of all images such as the virtual filesystem directory contents, the magic initrd, or the Multiboot module list. Hidden images remain visible to iPXE commands including "imgstat", which will show a "[HIDDEN]" flag for such images. Signed-off-by: Michael Brown --- src/arch/x86/image/bzimage.c | 4 ++++ src/arch/x86/image/multiboot.c | 4 ++++ src/include/ipxe/image.h | 12 +++--------- src/interface/efi/efi_file.c | 36 ++++++++++++++++++++++++++---------- src/usr/imgmgmt.c | 2 ++ 5 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c index b15bd556..2c776147 100644 --- a/src/arch/x86/image/bzimage.c +++ b/src/arch/x86/image/bzimage.c @@ -355,6 +355,10 @@ static size_t bzimage_load_initrd ( struct image *image, size_t offset; size_t pad_len; + /* Skip hidden images */ + if ( initrd->flags & IMAGE_HIDDEN ) + return 0; + /* Create cpio header for non-prebuilt images */ offset = cpio_header ( initrd, &cpio ); diff --git a/src/arch/x86/image/multiboot.c b/src/arch/x86/image/multiboot.c index c1c63bc9..cada021a 100644 --- a/src/arch/x86/image/multiboot.c +++ b/src/arch/x86/image/multiboot.c @@ -204,6 +204,10 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start, break; } + /* Skip hidden images */ + if ( module_image->flags & IMAGE_HIDDEN ) + continue; + /* Page-align the module */ start = ( ( start + 0xfff ) & ~0xfff ); diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 9e0c0f22..e00af82e 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -72,6 +72,9 @@ struct image { /** Image will be automatically unregistered after execution */ #define IMAGE_AUTO_UNREGISTER 0x0008 +/** Image will be hidden from enumeration */ +#define IMAGE_HIDDEN 0x0010 + /** An executable image type */ struct image_type { /** Name of this image type */ @@ -161,15 +164,6 @@ extern struct image *current_image; #define for_each_image_safe( image, tmp ) \ list_for_each_entry_safe ( (image), (tmp), &images, list ) -/** - * Test for existence of images - * - * @ret existence Some images exist - */ -static inline int have_images ( void ) { - return ( ! list_empty ( &images ) ); -} - /** * Retrieve first image * diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index fd0bcc6c..673f902d 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -250,6 +250,10 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) { len = 0; for_each_image ( image ) { + /* Skip hidden images */ + if ( image->flags & IMAGE_HIDDEN ) + continue; + /* Pad to alignment boundary */ pad_len = ( ( -reader->pos ) & ( INITRD_ALIGN - 1 ) ); if ( pad_len ) { @@ -524,13 +528,21 @@ static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len, /* Construct directory entries for image-backed files */ index = file->pos; for_each_image ( image ) { - if ( index-- == 0 ) { - efi_file_image ( &entry, image ); - efirc = efi_file_info ( &entry, len, data ); - if ( efirc == 0 ) - file->pos++; - return efirc; - } + + /* Skip hidden images */ + if ( image->flags & IMAGE_HIDDEN ) + continue; + + /* Skip preceding images */ + if ( index-- ) + continue; + + /* Construct directory entry */ + efi_file_image ( &entry, image ); + efirc = efi_file_info ( &entry, len, data ); + if ( efirc == 0 ) + file->pos++; + return efirc; } /* No more entries */ @@ -1093,6 +1105,7 @@ int efi_file_install ( EFI_HANDLE handle ) { EFI_DISK_IO_PROTOCOL *diskio; void *interface; } diskio; + struct image *image; EFI_STATUS efirc; int rc; @@ -1156,9 +1169,12 @@ int efi_file_install ( EFI_HANDLE handle ) { goto err_initrd_claim; /* Install Linux initrd fixed device path file if non-empty */ - if ( have_images() && - ( ( rc = efi_file_path_install ( &efi_file_initrd ) ) != 0 ) ) { - goto err_initrd_install; + for_each_image ( image ) { + if ( image->flags & IMAGE_HIDDEN ) + continue; + if ( ( rc = efi_file_path_install ( &efi_file_initrd ) ) != 0 ) + goto err_initrd_install; + break; } return 0; diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index b7fc8293..94f3d2ce 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -165,6 +165,8 @@ void imgstat ( struct image *image ) { printf ( " [SELECTED]" ); if ( image->flags & IMAGE_AUTO_UNREGISTER ) printf ( " [AUTOFREE]" ); + if ( image->flags & IMAGE_HIDDEN ) + printf ( " [HIDDEN]" ); if ( image->cmdline ) printf ( " \"%s\"", image->cmdline ); printf ( "\n" ); -- cgit v1.2.3-55-g7522 From 0bb0aea878bc9c2f775d967df83d3c081c1c34a2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 May 2023 14:46:42 +0100 Subject: [efi] Allow currently executing image to be opened via virtual filesystem When invoking a kernel via the UEFI shim, the kernel image must be accessible via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL but must not be present in the magic initrd constructed from all registered images. Re-register a currently executing EFI image and mark it as hidden, thereby allowing it to be accessed via the virtual filesystem exposed via EFI_SIMPLE_FILE_SYSTEM_PROTOCOL without appearing in the magic initrd contents. Signed-off-by: Michael Brown --- src/image/efi_image.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 467fb05a..0be48564 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -141,6 +141,7 @@ static int efi_image_exec ( struct image *image ) { EFI_HANDLE handle; EFI_MEMORY_TYPE type; wchar_t *cmdline; + unsigned int toggle; EFI_STATUS efirc; int rc; @@ -153,6 +154,12 @@ static int efi_image_exec ( struct image *image ) { goto err_no_snpdev; } + /* Re-register as a hidden image to allow for access via file I/O */ + toggle = ( ~image->flags & IMAGE_HIDDEN ); + image->flags |= IMAGE_HIDDEN; + if ( ( rc = register_image ( image ) ) != 0 ) + goto err_register_image; + /* Install file I/O protocols */ if ( ( rc = efi_file_install ( snpdev->handle ) ) != 0 ) { DBGC ( image, "EFIIMAGE %s could not install file protocol: " @@ -296,6 +303,9 @@ static int efi_image_exec ( struct image *image ) { err_pxe_install: efi_file_uninstall ( snpdev->handle ); err_file_install: + unregister_image ( image ); + err_register_image: + image->flags ^= toggle; err_no_snpdev: return rc; } -- cgit v1.2.3-55-g7522 From 03eea19c19b52851002654c2818b765d4aa42894 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 May 2023 12:51:09 +0100 Subject: [efi] Allow currently selected image to be opened as "grub*.efi" Versions 15.4 and earlier of the UEFI shim are incapable of correctly parsing the command line in order to extract the second stage loader filename, and will always attempt to load "grubx64.efi" or equivalent. Versions 15.3 and later of the UEFI shim are currently incapable of loading a Linux kernel directly anyway, since the kernel does not include SBAT metadata. These versions will require a genuine shim-signed GRUB binary to be used as a crutch to assist shim in loading a Linux kernel. This leaves versions 15.2 and earlier of the UEFI shim (as currently used in e.g. RHEL7) as being capable of directly loading a Linux kernel, but incorrectly attempting to load it using the filename "grubx64.efi" or equivalent. To support the bugs in these older versions of the UEFI shim, allow the currently selected image to be opened via any filename of the form "grub*.efi". Signed-off-by: Michael Brown --- src/interface/efi/efi_file.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index 673f902d..266de4a6 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -374,6 +374,7 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, char buf[ wcslen ( wname ) + 1 /* NUL */ ]; struct image *image; char *name; + char *sep; /* Convert name to ASCII */ snprintf ( buf, sizeof ( buf ), "%ls", wname ); @@ -413,6 +414,16 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, new ); } + /* Allow currently selected image to be opened as "grub*.efi", + * to work around buggy versions of the UEFI shim. + */ + if ( ( strncasecmp ( name, "grub", 4 ) == 0 ) && + ( ( sep = strrchr ( name, '.' ) ) != NULL ) && + ( strcasecmp ( sep, ".efi" ) == 0 ) && + ( ( image = image_find_selected() ) != NULL ) ) { + return efi_file_open_image ( image, wname, new ); + } + DBGC ( file, "EFIFILE %ls does not exist\n", wname ); return EFI_NOT_FOUND; } -- cgit v1.2.3-55-g7522 From d27cd8196de031c306e7c103df5711bb55e68fdd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 15 May 2023 13:58:07 +0100 Subject: [ci] Work around Ubuntu packaging metadata issues The libc6-dbg:i386 package has spontaneously started failing to install from the Azure package repositories used by the GitHub Actions runners, with the somewhat recalcitrant error message: libc6:i386: Depends: libgcc-s1:i386 but it is not going to be installed Work around this unexplained issue by explicitly requesting installation of the libgcc-s1:i386 package. Signed-off-by: Michael Brown --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 72a1234b..232375ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,8 @@ jobs: sudo apt update sudo apt install -y -o Acquire::Retries=50 \ mtools syslinux isolinux \ - libc6-dev-i386 libc6-dbg:i386 valgrind + libc6-dev-i386 valgrind \ + libgcc-s1:i386 libc6-dbg:i386 - name: Build (BIOS) run: | make -j 4 -C src -- cgit v1.2.3-55-g7522 From 79d85e29aa09c47f1d5a2be9eddd10e61fb22035 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 17 May 2023 14:36:25 +0100 Subject: [efi] Attempt to detect EFI images that fail Secure Boot verification An EFI image that is rejected by LoadImage() due to failing Secure Boot verification is still an EFI image. Unfortunately, the extremely broken UEFI Secure Boot model provides no way for us to unambiguously determine that a valid EFI executable image was rejected only because it failed signature verification. We must therefore use heuristics to guess whether not an image that was rejected by LoadImage() could still be loaded via a separate PE loader such as the UEFI shim. Signed-off-by: Michael Brown --- src/image/efi_image.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 0be48564..6a7bba01 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -356,9 +356,75 @@ static int efi_image_probe ( struct image *image ) { return rc; } -/** EFI image type */ -struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = { - .name = "EFI", - .probe = efi_image_probe, - .exec = efi_image_exec, +/** + * Probe EFI PE image + * + * @v image EFI file + * @ret rc Return status code + * + * The extremely broken UEFI Secure Boot model provides no way for us + * to unambiguously determine that a valid EFI executable image was + * rejected by LoadImage() because it failed signature verification. + * We must therefore use heuristics to guess whether not an image that + * was rejected by LoadImage() could still be loaded via a separate PE + * loader such as the UEFI shim. + */ +static int efi_pe_image_probe ( struct image *image ) { + const UINT16 magic = ( ( sizeof ( UINTN ) == sizeof ( uint32_t ) ) ? + EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC : + EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC ); + union { + EFI_IMAGE_DOS_HEADER dos; + EFI_IMAGE_OPTIONAL_HEADER_UNION pe; + } u; + + /* Check for existence of DOS header */ + if ( image->len < sizeof ( u.dos ) ) { + DBGC ( image, "EFIIMAGE %s too short for DOS header\n", + image->name ); + return -ENOEXEC; + } + copy_from_user ( &u.dos, image->data, 0, sizeof ( u.dos ) ); + if ( u.dos.e_magic != EFI_IMAGE_DOS_SIGNATURE ) { + DBGC ( image, "EFIIMAGE %s missing MZ signature\n", + image->name ); + return -ENOEXEC; + } + + /* Check for existence of PE header */ + if ( ( image->len < u.dos.e_lfanew ) || + ( ( image->len - u.dos.e_lfanew ) < sizeof ( u.pe ) ) ) { + DBGC ( image, "EFIIMAGE %s too short for PE header\n", + image->name ); + return -ENOEXEC; + } + copy_from_user ( &u.pe, image->data, u.dos.e_lfanew, sizeof ( u.pe ) ); + if ( u.pe.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE ) { + DBGC ( image, "EFIIMAGE %s missing PE signature\n", + image->name ); + return -ENOEXEC; + } + + /* Check PE header magic */ + if ( u.pe.Pe32.OptionalHeader.Magic != magic ) { + DBGC ( image, "EFIIMAGE %s incorrect magic %04x\n", + image->name, u.pe.Pe32.OptionalHeader.Magic ); + return -ENOEXEC; + } + + return 0; +} + +/** EFI image types */ +struct image_type efi_image_type[] __image_type ( PROBE_NORMAL ) = { + { + .name = "EFI", + .probe = efi_image_probe, + .exec = efi_image_exec, + }, + { + .name = "EFIPE", + .probe = efi_pe_image_probe, + .exec = efi_image_exec, + }, }; -- cgit v1.2.3-55-g7522 From c4a8d90387437425faec91bdee42a254944bab76 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 13 May 2023 20:27:58 +0100 Subject: [image] Generalise concept of selected image Most image flags are independent values: any combination of flags may be set for any image, and the flags for one image are independent of the flags for any other image. The "selected" flag does not follow this pattern: at most one image may be marked as selected at any time. When invoking a kernel via the UEFI shim, there will be multiple "special" images: the selected kernel itself, the shim image, and potentially a shim-signed GRUB binary to be used as a crutch to assist shim in loading the kernel (since current versions of the UEFI shim are not capable of directly loading a Linux kernel). Remove the "selected" image flag and replace it with a general concept of an image tag with the same semantics: a given tag may be assigned to at most one image, an image may be found by its tag only while the image is currently registered, and a tag will survive unregistration and reregistration of an image (if it has not already been assigned to a new image). For visual consistency, also replace the current image pointer with a current image tag. The image pointer stored within the image tag holds only a weak reference to the image, since the selection of an image should not prevent that image from being freed. (The strong reference to the currently executing image is held locally within the execution scope of image_exec(), and is logically separate from the current image pointer.) Signed-off-by: Michael Brown --- src/core/image.c | 69 +++++++++++++++++++++++--------------------- src/hci/commands/image_cmd.c | 2 +- src/image/script.c | 7 +++-- src/include/ipxe/image.h | 47 +++++++++++++++++++++++------- src/interface/efi/efi_file.c | 2 +- src/usr/imgmgmt.c | 8 +++-- 6 files changed, 85 insertions(+), 50 deletions(-) diff --git a/src/core/image.c b/src/core/image.c index b280eb4d..3e65b5ed 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -56,8 +56,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** List of registered images */ struct list_head images = LIST_HEAD_INIT ( images ); +/** Image selected for execution */ +struct image_tag selected_image __image_tag = { + .name = "SELECTED", +}; + /** Currently-executing image */ -struct image *current_image; +struct image_tag current_image __image_tag = { + .name = "CURRENT", +}; /** Current image trust requirement */ static int require_trusted_images = 0; @@ -72,8 +79,13 @@ static int require_trusted_images_permanent = 0; */ static void free_image ( struct refcnt *refcnt ) { struct image *image = container_of ( refcnt, struct image, refcnt ); + struct image_tag *tag; DBGC ( image, "IMAGE %s freed\n", image->name ); + for_each_table_entry ( tag, IMAGE_TAGS ) { + if ( tag->image == image ) + tag->image = NULL; + } free ( image->name ); free ( image->cmdline ); uri_put ( image->uri ); @@ -261,12 +273,6 @@ int register_image ( struct image *image ) { return rc; } - /* Avoid ending up with multiple "selected" images on - * re-registration - */ - if ( image_find_selected() ) - image->flags &= ~IMAGE_SELECTED; - /* Add to image list */ image_get ( image ); image->flags |= IMAGE_REGISTERED; @@ -320,6 +326,23 @@ struct image * find_image ( const char *name ) { return NULL; } +/** + * Find image by tag + * + * @v tag Image tag + * @ret image Executable image, or NULL + */ +struct image * find_image_tag ( struct image_tag *tag ) { + struct image *image; + + for_each_image ( image ) { + if ( tag->image == image ) + return image; + } + + return NULL; +} + /** * Execute image * @@ -346,13 +369,13 @@ int image_exec ( struct image *image ) { if ( image->uri ) churi ( image->uri ); - /* Preserve record of any currently-running image */ - saved_current_image = current_image; + /* Set as currently running image */ + saved_current_image = image_tag ( image, ¤t_image ); /* Take out a temporary reference to the image, so that it * does not get freed when temporarily unregistered. */ - current_image = image_get ( image ); + image_get ( image ); /* Check that this image can be executed */ if ( ! ( image->type && image->type->exec ) ) { @@ -419,7 +442,7 @@ int image_exec ( struct image *image ) { image_put ( image ); /* Restore previous currently-running image */ - current_image = saved_current_image; + image_tag ( saved_current_image, ¤t_image ); /* Reset current working directory */ churi ( old_cwuri ); @@ -442,7 +465,7 @@ int image_exec ( struct image *image ) { * registered until the currently-executing image returns. */ int image_replace ( struct image *replacement ) { - struct image *image = current_image; + struct image *image = current_image.image; int rc; /* Sanity check */ @@ -478,37 +501,17 @@ int image_replace ( struct image *replacement ) { * @ret rc Return status code */ int image_select ( struct image *image ) { - struct image *tmp; - - /* Unselect all other images */ - for_each_image ( tmp ) - tmp->flags &= ~IMAGE_SELECTED; /* Check that this image can be executed */ if ( ! ( image->type && image->type->exec ) ) return -ENOEXEC; /* Mark image as selected */ - image->flags |= IMAGE_SELECTED; + image_tag ( image, &selected_image ); return 0; } -/** - * Find selected image - * - * @ret image Executable image, or NULL - */ -struct image * image_find_selected ( void ) { - struct image *image; - - for_each_image ( image ) { - if ( image->flags & IMAGE_SELECTED ) - return image; - } - return NULL; -} - /** * Change image trust requirement * diff --git a/src/hci/commands/image_cmd.c b/src/hci/commands/image_cmd.c index 4a7c500a..bf97b4de 100644 --- a/src/hci/commands/image_cmd.c +++ b/src/hci/commands/image_cmd.c @@ -129,7 +129,7 @@ static int imgsingle_exec ( int argc, char **argv, &image ) ) != 0 ) goto err_acquire; } else { - image = image_find_selected(); + image = find_image_tag ( &selected_image ); if ( ! image ) { printf ( "No image selected\n" ); goto err_acquire; diff --git a/src/image/script.c b/src/image/script.c index b34df1e2..49b35640 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -311,6 +311,7 @@ static int terminate_on_label_found ( int rc ) { * @ret rc Return status code */ static int goto_exec ( int argc, char **argv ) { + struct image *image = current_image.image; struct goto_options opts; size_t saved_offset; int rc; @@ -320,7 +321,7 @@ static int goto_exec ( int argc, char **argv ) { return rc; /* Sanity check */ - if ( ! current_image ) { + if ( ! image ) { rc = -ENOTTY; printf ( "Not in a script: %s\n", strerror ( rc ) ); return rc; @@ -331,10 +332,10 @@ static int goto_exec ( int argc, char **argv ) { /* Find label */ saved_offset = script_offset; - if ( ( rc = process_script ( current_image, goto_find_label, + if ( ( rc = process_script ( image, goto_find_label, terminate_on_label_found ) ) != 0 ) { script_offset = saved_offset; - DBGC ( current_image, "[%04zx] No such label :%s\n", + DBGC ( image, "[%04zx] No such label :%s\n", script_offset, goto_label ); return rc; } diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index e00af82e..cd51188d 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -61,19 +61,16 @@ struct image { }; /** Image is registered */ -#define IMAGE_REGISTERED 0x00001 - -/** Image is selected for execution */ -#define IMAGE_SELECTED 0x0002 +#define IMAGE_REGISTERED 0x0001 /** Image is trusted */ -#define IMAGE_TRUSTED 0x0004 +#define IMAGE_TRUSTED 0x0002 /** Image will be automatically unregistered after execution */ -#define IMAGE_AUTO_UNREGISTER 0x0008 +#define IMAGE_AUTO_UNREGISTER 0x0004 /** Image will be hidden from enumeration */ -#define IMAGE_HIDDEN 0x0010 +#define IMAGE_HIDDEN 0x0008 /** An executable image type */ struct image_type { @@ -153,8 +150,23 @@ struct image_type { /** An executable image type */ #define __image_type( probe_order ) __table_entry ( IMAGE_TYPES, probe_order ) +/** An image tag */ +struct image_tag { + /** Name */ + const char *name; + /** Image (weak reference, nullified when image is freed) */ + struct image *image; +}; + +/** Image tag table */ +#define IMAGE_TAGS __table ( struct image_tag, "image_tags" ) + +/** An image tag */ +#define __image_tag __table_entry ( IMAGE_TAGS, 01 ) + extern struct list_head images; -extern struct image *current_image; +extern struct image_tag current_image; +extern struct image_tag selected_image; /** Iterate over all registered images */ #define for_each_image( image ) \ @@ -181,11 +193,11 @@ extern int image_set_len ( struct image *image, size_t len ); extern int image_set_data ( struct image *image, userptr_t data, size_t len ); extern int register_image ( struct image *image ); extern void unregister_image ( struct image *image ); -struct image * find_image ( const char *name ); +extern struct image * find_image ( const char *name ); +extern struct image * find_image_tag ( struct image_tag *tag ); extern int image_exec ( struct image *image ); extern int image_replace ( struct image *replacement ); extern int image_select ( struct image *image ); -extern struct image * image_find_selected ( void ); extern int image_set_trust ( int require_trusted, int permanent ); extern struct image * image_memory ( const char *name, userptr_t data, size_t len ); @@ -244,4 +256,19 @@ static inline void image_untrust ( struct image *image ) { image->flags &= ~IMAGE_TRUSTED; } +/** + * Tag image + * + * @v image Image + * @v tag Image tag + * @ret prev Previous tagged image (if any) + */ +static inline struct image * image_tag ( struct image *image, + struct image_tag *tag ) { + struct image *prev = tag->image; + + tag->image = image; + return prev; +} + #endif /* _IPXE_IMAGE_H */ diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index 266de4a6..2ae3a0cb 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -420,7 +420,7 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new, if ( ( strncasecmp ( name, "grub", 4 ) == 0 ) && ( ( sep = strrchr ( name, '.' ) ) != NULL ) && ( strcasecmp ( sep, ".efi" ) == 0 ) && - ( ( image = image_find_selected() ) != NULL ) ) { + ( ( image = find_image_tag ( &selected_image ) ) != NULL ) ) { return efi_file_open_image ( image, wname, new ); } diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index 94f3d2ce..92bf236f 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -156,13 +156,17 @@ int imgacquire ( const char *name_uri, unsigned long timeout, * @v image Executable/loadable image */ void imgstat ( struct image *image ) { + struct image_tag *tag; + printf ( "%s : %zd bytes", image->name, image->len ); if ( image->type ) printf ( " [%s]", image->type->name ); + for_each_table_entry ( tag, IMAGE_TAGS ) { + if ( tag->image == image ) + printf ( " [%s]", tag->name ); + } if ( image->flags & IMAGE_TRUSTED ) printf ( " [TRUSTED]" ); - if ( image->flags & IMAGE_SELECTED ) - printf ( " [SELECTED]" ); if ( image->flags & IMAGE_AUTO_UNREGISTER ) printf ( " [AUTOFREE]" ); if ( image->flags & IMAGE_HIDDEN ) -- cgit v1.2.3-55-g7522 From ce2200d5fb3d337c7fc7e8ff337c2ddf7645ba89 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 22 May 2023 13:35:34 +0100 Subject: [efi] Add efi_asprintf() and efi_vasprintf() Signed-off-by: Michael Brown --- src/image/efi_image.c | 16 ++++++-------- src/include/ipxe/efi/efi_strings.h | 2 ++ src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_strings.c | 44 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 6a7bba01..43713403 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -109,18 +109,14 @@ efi_image_path ( struct image *image, EFI_DEVICE_PATH_PROTOCOL *parent ) { */ static wchar_t * efi_image_cmdline ( struct image *image ) { wchar_t *cmdline; - size_t len; - len = ( strlen ( image->name ) + - ( image->cmdline ? - ( 1 /* " " */ + strlen ( image->cmdline ) ) : 0 ) ); - cmdline = zalloc ( ( len + 1 /* NUL */ ) * sizeof ( wchar_t ) ); - if ( ! cmdline ) + /* Allocate and construct command line */ + if ( efi_asprintf ( &cmdline, "%s%s%s", image->name, + ( image->cmdline ? " " : "" ), + ( image->cmdline ? image->cmdline : "" ) ) < 0 ) { return NULL; - efi_snprintf ( cmdline, ( len + 1 /* NUL */ ), "%s%s%s", - image->name, - ( image->cmdline ? " " : "" ), - ( image->cmdline ? image->cmdline : "" ) ); + } + return cmdline; } diff --git a/src/include/ipxe/efi/efi_strings.h b/src/include/ipxe/efi/efi_strings.h index a8ace45e..a7adff82 100644 --- a/src/include/ipxe/efi/efi_strings.h +++ b/src/include/ipxe/efi/efi_strings.h @@ -19,6 +19,8 @@ extern int efi_vssnprintf ( wchar_t *wbuf, ssize_t swsize, const char *fmt, va_list args ); extern int efi_ssnprintf ( wchar_t *wbuf, ssize_t swsize, const char *fmt, ... ); +extern int efi_vasprintf ( wchar_t **strp, const char *fmt, va_list args ); +extern int efi_asprintf ( wchar_t **strp, const char *fmt, ... ); /** * Write a formatted string to a wide-character buffer diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e6fd8524..235611a5 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -78,6 +78,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_dma ( ERRFILE_CORE | 0x00260000 ) #define ERRFILE_cachedhcp ( ERRFILE_CORE | 0x00270000 ) #define ERRFILE_acpimac ( ERRFILE_CORE | 0x00280000 ) +#define ERRFILE_efi_strings ( ERRFILE_CORE | 0x00290000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) diff --git a/src/interface/efi/efi_strings.c b/src/interface/efi/efi_strings.c index aa3afc64..765b23ca 100644 --- a/src/interface/efi/efi_strings.c +++ b/src/interface/efi/efi_strings.c @@ -25,6 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include +#include #include #include @@ -150,3 +152,45 @@ int efi_ssnprintf ( wchar_t *wbuf, ssize_t swsize, const char *fmt, ... ) { va_end ( args ); return len; } + +/** + * Write a formatted string to newly allocated memory + * + * @v wstrp Pointer to hold allocated string + * @v fmt Format string + * @v args Arguments corresponding to the format string + * @ret len Length of formatted string (in wide characters) + */ +int efi_vasprintf ( wchar_t **wstrp, const char *fmt, va_list args ) { + size_t len; + va_list args_tmp; + + /* Calculate length needed for string */ + va_copy ( args_tmp, args ); + len = ( efi_vsnprintf ( NULL, 0, fmt, args_tmp ) + 1 ); + va_end ( args_tmp ); + + /* Allocate and fill string */ + *wstrp = malloc ( len * sizeof ( **wstrp ) ); + if ( ! *wstrp ) + return -ENOMEM; + return efi_vsnprintf ( *wstrp, len, fmt, args ); +} + +/** + * Write a formatted string to newly allocated memory + * + * @v wstrp Pointer to hold allocated string + * @v fmt Format string + * @v ... Arguments corresponding to the format string + * @ret len Length of formatted string (in wide characters) + */ +int efi_asprintf ( wchar_t **wstrp, const char *fmt, ... ) { + va_list args; + int len; + + va_start ( args, fmt ); + len = efi_vasprintf ( wstrp, fmt, args ); + va_end ( args ); + return len; +} -- cgit v1.2.3-55-g7522 From 3c214f046507fb7b4e67845d61f38a13fa1bc2b5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 22 May 2023 14:07:26 +0100 Subject: [efi] Add definitions for the UEFI shim lock protocol The UEFI shim includes a "shim lock protocol" that can be used by a third party second stage loader such as GRUB to verify a kernel image. Add definitions for the relevant portions of this protocol interface. Signed-off-by: Michael Brown --- src/include/ipxe/efi/Protocol/ShimLock.h | 31 +++++++++++++++++++++++++++++++ src/include/ipxe/efi/efi.h | 1 + src/interface/efi/efi_debug.c | 2 ++ src/interface/efi/efi_guid.c | 5 +++++ 4 files changed, 39 insertions(+) create mode 100644 src/include/ipxe/efi/Protocol/ShimLock.h diff --git a/src/include/ipxe/efi/Protocol/ShimLock.h b/src/include/ipxe/efi/Protocol/ShimLock.h new file mode 100644 index 00000000..b3136517 --- /dev/null +++ b/src/include/ipxe/efi/Protocol/ShimLock.h @@ -0,0 +1,31 @@ +#ifndef _IPXE_EFI_SHIM_LOCK_PROTOCOL_H +#define _IPXE_EFI_SHIM_LOCK_PROTOCOL_H + +/** @file + * + * EFI "shim lock" protocol + * + */ + +FILE_LICENCE ( BSD3 ); + +#define EFI_SHIM_LOCK_PROTOCOL_GUID \ + { 0x605dab50, 0xe046, 0x4300, \ + { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } } + +#define SHIMAPI __asmcall + +typedef +EFI_STATUS SHIMAPI +(*EFI_SHIM_LOCK_VERIFY) ( + IN VOID *buffer, + IN UINT32 size + ); + +typedef struct _EFI_SHIM_LOCK_PROTOCOL { + EFI_SHIM_LOCK_VERIFY Verify; + VOID *Reserved1; + VOID *Reserved2; +} EFI_SHIM_LOCK_PROTOCOL; + +#endif /*_IPXE_EFI_SHIM_LOCK_PROTOCOL_H */ diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 1dd0d445..e0e2db60 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -197,6 +197,7 @@ extern EFI_GUID efi_pci_io_protocol_guid; extern EFI_GUID efi_pci_root_bridge_io_protocol_guid; extern EFI_GUID efi_pxe_base_code_protocol_guid; extern EFI_GUID efi_serial_io_protocol_guid; +extern EFI_GUID efi_shim_lock_protocol_guid; extern EFI_GUID efi_simple_file_system_protocol_guid; extern EFI_GUID efi_simple_network_protocol_guid; extern EFI_GUID efi_simple_pointer_protocol_guid; diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 967bb618..02cbf9fa 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -143,6 +143,8 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "PxeBaseCode" }, { &efi_serial_io_protocol_guid, "SerialIo" }, + { &efi_shim_lock_protocol_guid, + "ShimLock" }, { &efi_simple_file_system_protocol_guid, "SimpleFileSystem" }, { &efi_simple_network_protocol_guid, diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c index 663585dc..25c342ff 100644 --- a/src/interface/efi/efi_guid.c +++ b/src/interface/efi/efi_guid.c @@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -227,6 +228,10 @@ EFI_GUID efi_pxe_base_code_protocol_guid EFI_GUID efi_serial_io_protocol_guid = EFI_SERIAL_IO_PROTOCOL_GUID; +/** Shim lock protocol GUID */ +EFI_GUID efi_shim_lock_protocol_guid + = EFI_SHIM_LOCK_PROTOCOL_GUID; + /** Simple file system protocol GUID */ EFI_GUID efi_simple_file_system_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; -- cgit v1.2.3-55-g7522 From 28184b7c22ca2297bd5c0ad9d333bc8620d38915 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 22 May 2023 14:11:22 +0100 Subject: [efi] Add support for executing images via a shim Add support for using a shim as a helper to execute an EFI image. When a shim has been specified via shim(), the shim image will be passed to LoadImage() instead of the selected EFI image and the command line will be prepended with the name of the selected EFI image. The selected EFI image will be accessible to the shim via the virtual filesystem as a hidden file. Reduce the Secure Boot attack surface by removing, where possible, the spurious requirement for a third party second stage loader binary such as GRUB to be used solely in order to call the "shim lock protocol" entry point. Do not install the EFI PXE APIs when using a shim, since if shim finds EFI_PXE_BASE_CODE_PROTOCOL on the loaded image's device handle then it will attempt to download files afresh instead of using the files already downloaded by iPXE and exposed via the EFI_SIMPLE_FILE_SYSTEM protocol. (Experience shows that there is no point in trying to get a fix for this upstreamed into shim.) Signed-off-by: Michael Brown --- src/image/efi_image.c | 31 ++++- src/include/ipxe/efi/efi_image.h | 27 +++++ src/include/ipxe/efi/efi_shim.h | 23 ++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/image.h | 9 ++ src/include/usr/shimmgmt.h | 16 +++ src/interface/efi/efi_shim.c | 251 +++++++++++++++++++++++++++++++++++++++ src/usr/shimmgmt.c | 58 +++++++++ 8 files changed, 413 insertions(+), 3 deletions(-) create mode 100644 src/include/ipxe/efi/efi_image.h create mode 100644 src/include/ipxe/efi/efi_shim.h create mode 100644 src/include/usr/shimmgmt.h create mode 100644 src/interface/efi/efi_shim.c create mode 100644 src/usr/shimmgmt.c diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 43713403..104753a8 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -31,6 +31,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include +#include #include #include #include @@ -134,6 +136,8 @@ static int efi_image_exec ( struct image *image ) { EFI_LOADED_IMAGE_PROTOCOL *image; void *interface; } loaded; + struct image *shim; + struct image *exec; EFI_HANDLE handle; EFI_MEMORY_TYPE type; wchar_t *cmdline; @@ -150,6 +154,15 @@ static int efi_image_exec ( struct image *image ) { goto err_no_snpdev; } + /* Use shim instead of directly executing image if applicable */ + shim = ( efi_can_load ( image ) ? + NULL : find_image_tag ( &efi_shim ) ); + exec = ( shim ? shim : image ); + if ( shim ) { + DBGC ( image, "EFIIMAGE %s executing via %s\n", + image->name, shim->name ); + } + /* Re-register as a hidden image to allow for access via file I/O */ toggle = ( ~image->flags & IMAGE_HIDDEN ); image->flags |= IMAGE_HIDDEN; @@ -178,7 +191,7 @@ static int efi_image_exec ( struct image *image ) { } /* Create device path for image */ - path = efi_image_path ( image, snpdev->path ); + path = efi_image_path ( exec, snpdev->path ); if ( ! path ) { DBGC ( image, "EFIIMAGE %s could not create device path\n", image->name ); @@ -195,11 +208,20 @@ static int efi_image_exec ( struct image *image ) { goto err_cmdline; } + /* Install shim special handling if applicable */ + if ( shim && + ( ( rc = efi_shim_install ( shim, snpdev->handle, + &cmdline ) ) != 0 ) ){ + DBGC ( image, "EFIIMAGE %s could not install shim handling: " + "%s\n", image->name, strerror ( rc ) ); + goto err_shim_install; + } + /* Attempt loading image */ handle = NULL; if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path, - user_to_virt ( image->data, 0 ), - image->len, &handle ) ) != 0 ) { + user_to_virt ( exec->data, 0 ), + exec->len, &handle ) ) != 0 ) { /* Not an EFI image */ rc = -EEFI_LOAD ( efirc ); DBGC ( image, "EFIIMAGE %s could not load: %s\n", @@ -289,6 +311,9 @@ static int efi_image_exec ( struct image *image ) { if ( rc != 0 ) bs->UnloadImage ( handle ); err_load_image: + if ( shim ) + efi_shim_uninstall(); + err_shim_install: free ( cmdline ); err_cmdline: free ( path ); diff --git a/src/include/ipxe/efi/efi_image.h b/src/include/ipxe/efi/efi_image.h new file mode 100644 index 00000000..0fc0402b --- /dev/null +++ b/src/include/ipxe/efi/efi_image.h @@ -0,0 +1,27 @@ +#ifndef _IPXE_EFI_IMAGE_H +#define _IPXE_EFI_IMAGE_H + +/** @file + * + * EFI images + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +extern struct image_type efi_image_type[] __image_type ( PROBE_NORMAL ); + +/** + * Check if EFI image can be loaded directly + * + * @v image EFI image + * @ret can_load EFI image can be loaded directly + */ +static inline int efi_can_load ( struct image *image ) { + + return ( image->type == efi_image_type ); +} + +#endif /* _IPXE_EFI_IMAGE_H */ diff --git a/src/include/ipxe/efi/efi_shim.h b/src/include/ipxe/efi/efi_shim.h new file mode 100644 index 00000000..ad8d24dc --- /dev/null +++ b/src/include/ipxe/efi/efi_shim.h @@ -0,0 +1,23 @@ +#ifndef _IPXE_EFI_SHIM_H +#define _IPXE_EFI_SHIM_H + +/** @file + * + * UEFI shim special handling + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +extern int efi_shim_require_loader; +extern int efi_shim_allow_pxe; +extern struct image_tag efi_shim __image_tag; + +extern int efi_shim_install ( struct image *shim, EFI_HANDLE handle, + wchar_t **cmdline ); +extern void efi_shim_uninstall ( void ); + +#endif /* _IPXE_EFI_SHIM_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 235611a5..daa038c5 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -405,6 +405,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_dhe ( ERRFILE_OTHER | 0x005a0000 ) #define ERRFILE_efi_cmdline ( ERRFILE_OTHER | 0x005b0000 ) #define ERRFILE_efi_rng ( ERRFILE_OTHER | 0x005c0000 ) +#define ERRFILE_efi_shim ( ERRFILE_OTHER | 0x005d0000 ) /** @} */ diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index cd51188d..bfbf2368 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -256,6 +256,15 @@ static inline void image_untrust ( struct image *image ) { image->flags &= ~IMAGE_TRUSTED; } +/** + * Mark image as hidden + * + * @v image Image + */ +static inline void image_hide ( struct image *image ) { + image->flags |= IMAGE_HIDDEN; +} + /** * Tag image * diff --git a/src/include/usr/shimmgmt.h b/src/include/usr/shimmgmt.h new file mode 100644 index 00000000..5030607a --- /dev/null +++ b/src/include/usr/shimmgmt.h @@ -0,0 +1,16 @@ +#ifndef _USR_SHIMMGMT_H +#define _USR_SHIMMGMT_H + +/** @file + * + * EFI shim management + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +extern int shim ( struct image *image, int require_loader, int allow_pxe ); + +#endif /* _USR_SHIMMGMT_H */ diff --git a/src/interface/efi/efi_shim.c b/src/interface/efi/efi_shim.c new file mode 100644 index 00000000..9b1b69e8 --- /dev/null +++ b/src/interface/efi/efi_shim.c @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2022 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * UEFI shim special handling + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * Require use of a third party loader binary + * + * The UEFI shim is gradually becoming less capable of directly + * executing a Linux kernel image, due to an ever increasing list of + * assumptions that it will only ever be used in conjunction with a + * second stage loader binary such as GRUB. + * + * For example: shim will erroneously complain if the image that it + * loads and executes does not in turn call in to the "shim lock + * protocol" to verify a separate newly loaded binary before calling + * ExitBootServices(), even if no such separate binary is used or + * required. + * + * Experience shows that there is unfortunately no point in trying to + * get a fix for this upstreamed into shim. We therefore default to + * reducing the Secure Boot attack surface by removing, where + * possible, this spurious requirement for the use of an additional + * second stage loader. + * + * This option may be used to require the use of an additional second + * stage loader binary, in case this behaviour is ever desirable. + */ +int efi_shim_require_loader = 0; + +/** + * Allow use of PXE base code protocol + * + * We provide shim with access to all of the relevant downloaded files + * via our EFI_SIMPLE_FILE_SYSTEM_PROTOCOL interface. However, shim + * will instead try to redownload the files via TFTP since it prefers + * to use the EFI_PXE_BASE_CODE_PROTOCOL installed on the same handle. + * + * Experience shows that there is unfortunately no point in trying to + * get a fix for this upstreamed into shim. We therefore default to + * working around this undesirable behaviour by stopping the PXE base + * code protocol before invoking shim. + * + * This option may be used to allow shim to use the PXE base code + * protocol, in case this behaviour is ever desirable. + */ +int efi_shim_allow_pxe = 0; + +/** UEFI shim image */ +struct image_tag efi_shim __image_tag = { + .name = "SHIM", +}; + +/** Original GetMemoryMap() function */ +static EFI_GET_MEMORY_MAP efi_shim_orig_map; + +/** + * Unlock UEFI shim + * + * @v len Memory map size + * @v map Memory map + * @v key Memory map key + * @v desclen Descriptor size + * @v descver Descriptor version + * @ret efirc EFI status code + * + */ +static EFIAPI EFI_STATUS efi_shim_unlock ( UINTN *len, + EFI_MEMORY_DESCRIPTOR *map, + UINTN *key, UINTN *desclen, + UINT32 *descver ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + uint8_t empty[0]; + union { + EFI_SHIM_LOCK_PROTOCOL *lock; + void *interface; + } u; + EFI_STATUS efirc; + + /* Locate shim lock protocol */ + if ( ( efirc = bs->LocateProtocol ( &efi_shim_lock_protocol_guid, + NULL, &u.interface ) ) == 0 ) { + u.lock->Verify ( empty, sizeof ( empty ) ); + DBGC ( &efi_shim, "SHIM unlocked via %p\n", u.lock ); + } + + /* Hand off to original GetMemoryMap() */ + return efi_shim_orig_map ( len, map, key, desclen, descver ); +} + +/** + * Inhibit use of PXE base code + * + * @v handle EFI handle + * @ret rc Return status code + */ +static int efi_shim_inhibit_pxe ( EFI_HANDLE handle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + union { + EFI_PXE_BASE_CODE_PROTOCOL *pxe; + void *interface; + } u; + EFI_STATUS efirc; + int rc; + + /* Locate PXE base code */ + if ( ( efirc = bs->OpenProtocol ( handle, + &efi_pxe_base_code_protocol_guid, + &u.interface, efi_image_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){ + rc = -EEFI ( efirc ); + DBGC ( &efi_shim, "SHIM could not open PXE base code: %s\n", + strerror ( rc ) ); + goto err_no_base; + } + + /* Stop PXE base code */ + if ( ( efirc = u.pxe->Stop ( u.pxe ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efi_shim, "SHIM could not stop PXE base code: %s\n", + strerror ( rc ) ); + goto err_stop; + } + + /* Success */ + rc = 0; + DBGC ( &efi_shim, "SHIM stopped PXE base code\n" ); + + err_stop: + bs->CloseProtocol ( handle, &efi_pxe_base_code_protocol_guid, + efi_image_handle, NULL ); + err_no_base: + return rc; +} + +/** + * Update command line + * + * @v shim Shim image + * @v cmdline Command line to update + * @ret rc Return status code + */ +static int efi_shim_cmdline ( struct image *shim, wchar_t **cmdline ) { + wchar_t *shimcmdline; + int len; + int rc; + + /* Construct new command line */ + len = ( shim->cmdline ? + efi_asprintf ( &shimcmdline, "%s %s", shim->name, + shim->cmdline ) : + efi_asprintf ( &shimcmdline, "%s %ls", shim->name, + *cmdline ) ); + if ( len < 0 ) { + rc = len; + DBGC ( &efi_shim, "SHIM could not construct command line: " + "%s\n", strerror ( rc ) ); + return rc; + } + + /* Replace command line */ + free ( *cmdline ); + *cmdline = shimcmdline; + + return 0; +} + +/** + * Install UEFI shim special handling + * + * @v shim Shim image + * @v handle EFI device handle + * @v cmdline Command line to update + * @ret rc Return status code + */ +int efi_shim_install ( struct image *shim, EFI_HANDLE handle, + wchar_t **cmdline ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + int rc; + + /* Intercept GetMemoryMap() via boot services table */ + efi_shim_orig_map = bs->GetMemoryMap; + if ( ! efi_shim_require_loader ) + bs->GetMemoryMap = efi_shim_unlock; + + /* Stop PXE base code */ + if ( ( ! efi_shim_allow_pxe ) && + ( ( rc = efi_shim_inhibit_pxe ( handle ) ) != 0 ) ) { + goto err_inhibit_pxe; + } + + /* Update command line */ + if ( ( rc = efi_shim_cmdline ( shim, cmdline ) ) != 0 ) + goto err_cmdline; + + return 0; + + err_cmdline: + err_inhibit_pxe: + bs->GetMemoryMap = efi_shim_orig_map; + return rc; +} + +/** + * Uninstall UEFI shim special handling + * + */ +void efi_shim_uninstall ( void ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + + /* Restore original GetMemoryMap() */ + bs->GetMemoryMap = efi_shim_orig_map; +} diff --git a/src/usr/shimmgmt.c b/src/usr/shimmgmt.c new file mode 100644 index 00000000..ba9c3480 --- /dev/null +++ b/src/usr/shimmgmt.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** @file + * + * EFI shim management + * + */ + +/** + * Set shim image + * + * @v image Shim image, or NULL to clear shim + * @v require_loader Require use of a third party loader + * @v allow_pxe Allow use of PXE base code + * @ret rc Return status code + */ +int shim ( struct image *image, int require_loader, int allow_pxe ) { + + /* Record (or clear) shim image */ + image_tag ( image, &efi_shim ); + + /* Avoid including image in constructed initrd */ + if ( image ) + image_hide ( image ); + + /* Record configuration */ + efi_shim_require_loader = require_loader; + efi_shim_allow_pxe = allow_pxe; + + return 0; +} -- cgit v1.2.3-55-g7522 From 95b8338f0d4674b9f8bb51adf6886212d2b97e4b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 22 May 2023 14:13:36 +0100 Subject: [efi] Add "shim" command Allow a shim to be used to facilitate booting a kernel using a script such as: kernel /images/vmlinuz console=ttyS0,115200n8 initrd /images/initrd.img shim /images/shimx64.efi boot Signed-off-by: Michael Brown --- src/config/config.c | 3 ++ src/config/defaults/efi.h | 1 + src/config/general.h | 1 + src/hci/commands/shim_cmd.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 src/hci/commands/shim_cmd.c diff --git a/src/config/config.c b/src/config/config.c index a8186613..40f9c72c 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -290,6 +290,9 @@ REQUIRE_OBJECT ( cert_cmd ); #ifdef IMAGE_MEM_CMD REQUIRE_OBJECT ( image_mem_cmd ); #endif +#ifdef SHIM_CMD +REQUIRE_OBJECT ( shim_cmd ); +#endif /* * Drag in miscellaneous objects diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 8e53b9ab..998bdcc1 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -47,6 +47,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define USB_BLOCK /* USB block devices */ #define REBOOT_CMD /* Reboot command */ +#define SHIM_CMD /* EFI shim command */ #if defined ( __i386__ ) || defined ( __x86_64__ ) #define IOAPI_X86 diff --git a/src/config/general.h b/src/config/general.h index e75a2aff..2a371d0e 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -160,6 +160,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); //#define CERT_CMD /* Certificate management commands */ //#define IMAGE_MEM_CMD /* Read memory command */ #define IMAGE_ARCHIVE_CMD /* Archive image management commands */ +//#define SHIM_CMD /* EFI shim command */ /* * ROM-specific options diff --git a/src/hci/commands/shim_cmd.c b/src/hci/commands/shim_cmd.c new file mode 100644 index 00000000..00bd0acb --- /dev/null +++ b/src/hci/commands/shim_cmd.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2023 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include +#include +#include + +/** @file + * + * EFI shim command + * + */ + +/** "shim" options */ +struct shim_options { + /** Download timeout */ + unsigned long timeout; + /** Require third party loader */ + int require_loader; + /** Allow PXE base code protocol */ + int allow_pxe; +}; + +/** "shim" option list */ +static struct option_descriptor shim_opts[] = { + OPTION_DESC ( "timeout", 't', required_argument, + struct shim_options, timeout, parse_timeout ), + OPTION_DESC ( "require-loader", 'l', no_argument, + struct shim_options, require_loader, parse_flag ), + OPTION_DESC ( "allow-pxe", 'p', no_argument, + struct shim_options, allow_pxe, parse_flag ), +}; + +/** "shim" command descriptor */ +static struct command_descriptor shim_cmd = + COMMAND_DESC ( struct shim_options, shim_opts, 0, 1, NULL ); + +/** + * The "shim" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int shim_exec ( int argc, char **argv ) { + struct shim_options opts; + struct image *image = NULL; + struct image *kernel; + char *name_uri; + int download; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &shim_cmd, &opts ) ) != 0 ) + goto err_parse; + + /* Decide whether or not to download images */ + kernel = find_image_tag ( &selected_image ); + download = ( ! ( kernel && efi_can_load ( kernel ) ) ); + + /* Parse name/URI string */ + name_uri = argv[optind]; + + /* Acquire image, if applicable */ + if ( download && name_uri && + ( ( rc = imgacquire ( name_uri, opts.timeout, + &image ) ) != 0 ) ) { + goto err_image; + } + + /* (Un)register as shim */ + if ( ( rc = shim ( image, opts.require_loader, opts.allow_pxe ) ) != 0 ) + goto err_shim; + + err_shim: + err_image: + err_parse: + return rc; +} + +/** Shim commands */ +struct command shim_commands[] __command = { + { + .name = "shim", + .exec = shim_exec, + }, +}; -- cgit v1.2.3-55-g7522 From d2e1601cf4c8a0df21c08b9c8acf22e9cb631c5c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 23 May 2023 14:52:30 +0100 Subject: [efi] Separate GetMemoryMap() wrapper from shim unlocker Signed-off-by: Michael Brown --- src/interface/efi/efi_shim.c | 61 ++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/src/interface/efi/efi_shim.c b/src/interface/efi/efi_shim.c index 9b1b69e8..14d4806f 100644 --- a/src/interface/efi/efi_shim.c +++ b/src/interface/efi/efi_shim.c @@ -90,23 +90,13 @@ struct image_tag efi_shim __image_tag = { }; /** Original GetMemoryMap() function */ -static EFI_GET_MEMORY_MAP efi_shim_orig_map; +static EFI_GET_MEMORY_MAP efi_shim_orig_get_memory_map; /** * Unlock UEFI shim * - * @v len Memory map size - * @v map Memory map - * @v key Memory map key - * @v desclen Descriptor size - * @v descver Descriptor version - * @ret efirc EFI status code - * */ -static EFIAPI EFI_STATUS efi_shim_unlock ( UINTN *len, - EFI_MEMORY_DESCRIPTOR *map, - UINTN *key, UINTN *desclen, - UINT32 *descver ) { +static void efi_shim_unlock ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; uint8_t empty[0]; union { @@ -121,9 +111,30 @@ static EFIAPI EFI_STATUS efi_shim_unlock ( UINTN *len, u.lock->Verify ( empty, sizeof ( empty ) ); DBGC ( &efi_shim, "SHIM unlocked via %p\n", u.lock ); } +} + +/** + * Wrap GetMemoryMap() + * + * @v len Memory map size + * @v map Memory map + * @v key Memory map key + * @v desclen Descriptor size + * @v descver Descriptor version + * @ret efirc EFI status code + */ +static EFIAPI EFI_STATUS efi_shim_get_memory_map ( UINTN *len, + EFI_MEMORY_DESCRIPTOR *map, + UINTN *key, UINTN *desclen, + UINT32 *descver ) { + + /* Unlock shim */ + if ( ! efi_shim_require_loader ) + efi_shim_unlock(); /* Hand off to original GetMemoryMap() */ - return efi_shim_orig_map ( len, map, key, desclen, descver ); + return efi_shim_orig_get_memory_map ( len, map, key, desclen, + descver ); } /** @@ -216,27 +227,23 @@ int efi_shim_install ( struct image *shim, EFI_HANDLE handle, EFI_BOOT_SERVICES *bs = efi_systab->BootServices; int rc; - /* Intercept GetMemoryMap() via boot services table */ - efi_shim_orig_map = bs->GetMemoryMap; - if ( ! efi_shim_require_loader ) - bs->GetMemoryMap = efi_shim_unlock; - /* Stop PXE base code */ if ( ( ! efi_shim_allow_pxe ) && ( ( rc = efi_shim_inhibit_pxe ( handle ) ) != 0 ) ) { - goto err_inhibit_pxe; + return rc; } /* Update command line */ if ( ( rc = efi_shim_cmdline ( shim, cmdline ) ) != 0 ) - goto err_cmdline; + return rc; - return 0; + /* Record original boot services functions */ + efi_shim_orig_get_memory_map = bs->GetMemoryMap; - err_cmdline: - err_inhibit_pxe: - bs->GetMemoryMap = efi_shim_orig_map; - return rc; + /* Wrap relevant boot services functions */ + bs->GetMemoryMap = efi_shim_get_memory_map; + + return 0; } /** @@ -246,6 +253,6 @@ int efi_shim_install ( struct image *shim, EFI_HANDLE handle, void efi_shim_uninstall ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - /* Restore original GetMemoryMap() */ - bs->GetMemoryMap = efi_shim_orig_map; + /* Restore original boot services functions */ + bs->GetMemoryMap = efi_shim_orig_get_memory_map; } -- cgit v1.2.3-55-g7522 From 5b4318143648272b36736c1d1d5d1acbda9a5876 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 23 May 2023 14:55:08 +0100 Subject: [efi] Support versions of shim that perform SBAT verification The UEFI shim implements a fairly nicely designed revocation mechanism designed around the concept of security generations. Unfortunately nobody in the shim community has thus far added the relevant metadata to the Linux kernel, with the result that current versions of shim are incapable of booting current versions of the Linux kernel. Experience shows that there is unfortunately no point in trying to get a fix for this upstreamed into shim. We therefore default to working around this undesirable behaviour by patching data read from the "SbatLevel" variable used to hold SBAT configuration. Signed-off-by: Michael Brown --- src/hci/commands/shim_cmd.c | 7 +- src/include/ipxe/efi/efi_shim.h | 1 + src/include/usr/shimmgmt.h | 3 +- src/interface/efi/efi_shim.c | 150 +++++++++++++++++++++++++++++++++++++++- src/usr/shimmgmt.c | 5 +- 5 files changed, 160 insertions(+), 6 deletions(-) diff --git a/src/hci/commands/shim_cmd.c b/src/hci/commands/shim_cmd.c index 00bd0acb..9150af3f 100644 --- a/src/hci/commands/shim_cmd.c +++ b/src/hci/commands/shim_cmd.c @@ -44,6 +44,8 @@ struct shim_options { int require_loader; /** Allow PXE base code protocol */ int allow_pxe; + /** Allow SBAT variable access */ + int allow_sbat; }; /** "shim" option list */ @@ -54,6 +56,8 @@ static struct option_descriptor shim_opts[] = { struct shim_options, require_loader, parse_flag ), OPTION_DESC ( "allow-pxe", 'p', no_argument, struct shim_options, allow_pxe, parse_flag ), + OPTION_DESC ( "allow-sbat", 's', no_argument, + struct shim_options, allow_sbat, parse_flag ), }; /** "shim" command descriptor */ @@ -94,7 +98,8 @@ static int shim_exec ( int argc, char **argv ) { } /* (Un)register as shim */ - if ( ( rc = shim ( image, opts.require_loader, opts.allow_pxe ) ) != 0 ) + if ( ( rc = shim ( image, opts.require_loader, opts.allow_pxe, + opts.allow_sbat ) ) != 0 ) goto err_shim; err_shim: diff --git a/src/include/ipxe/efi/efi_shim.h b/src/include/ipxe/efi/efi_shim.h index ad8d24dc..21f24315 100644 --- a/src/include/ipxe/efi/efi_shim.h +++ b/src/include/ipxe/efi/efi_shim.h @@ -14,6 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); extern int efi_shim_require_loader; extern int efi_shim_allow_pxe; +extern int efi_shim_allow_sbat; extern struct image_tag efi_shim __image_tag; extern int efi_shim_install ( struct image *shim, EFI_HANDLE handle, diff --git a/src/include/usr/shimmgmt.h b/src/include/usr/shimmgmt.h index 5030607a..0c59f54a 100644 --- a/src/include/usr/shimmgmt.h +++ b/src/include/usr/shimmgmt.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -extern int shim ( struct image *image, int require_loader, int allow_pxe ); +extern int shim ( struct image *image, int require_loader, int allow_pxe, + int allow_sbat ); #endif /* _USR_SHIMMGMT_H */ diff --git a/src/interface/efi/efi_shim.c b/src/interface/efi/efi_shim.c index 14d4806f..a46d79d0 100644 --- a/src/interface/efi/efi_shim.c +++ b/src/interface/efi/efi_shim.c @@ -84,6 +84,26 @@ int efi_shim_require_loader = 0; */ int efi_shim_allow_pxe = 0; +/** + * Allow SBAT variable access + * + * The UEFI shim implements a fairly nicely designed revocation + * mechanism designed around the concept of security generations. + * Unfortunately nobody in the shim community has thus far added the + * relevant metadata to the Linux kernel, with the result that current + * versions of shim are incapable of booting current versions of the + * Linux kernel. + * + * Experience shows that there is unfortunately no point in trying to + * get a fix for this upstreamed into shim. We therefore default to + * working around this undesirable behaviour by patching data read + * from the "SbatLevel" variable used to hold SBAT configuration. + * + * This option may be used to allow shim unpatched access to the + * "SbatLevel" variable, in case this behaviour is ever desirable. + */ +int efi_shim_allow_sbat = 0; + /** UEFI shim image */ struct image_tag efi_shim __image_tag = { .name = "SHIM", @@ -92,6 +112,33 @@ struct image_tag efi_shim __image_tag = { /** Original GetMemoryMap() function */ static EFI_GET_MEMORY_MAP efi_shim_orig_get_memory_map; +/** Original ExitBootServices() function */ +static EFI_EXIT_BOOT_SERVICES efi_shim_orig_exit_boot_services; + +/** Original SetVariable() function */ +static EFI_SET_VARIABLE efi_shim_orig_set_variable; + +/** Original GetVariable() function */ +static EFI_GET_VARIABLE efi_shim_orig_get_variable; + +/** Verify read from SbatLevel variable */ +static int efi_shim_sbatlevel_verify; + +/** + * Check if variable is SbatLevel + * + * @v name Variable name + * @v guid Variable namespace GUID + * @ret is_sbatlevel Variable is SbatLevel + */ +static int efi_shim_is_sbatlevel ( const CHAR16 *name, const EFI_GUID *guid ) { + static CHAR16 sbatlevel[] = L"SbatLevel"; + EFI_GUID *shimlock = &efi_shim_lock_protocol_guid; + + return ( ( memcmp ( name, sbatlevel, sizeof ( sbatlevel ) ) == 0 ) && + ( memcmp ( guid, shimlock, sizeof ( *shimlock ) ) == 0 ) ); +} + /** * Unlock UEFI shim * @@ -137,6 +184,92 @@ static EFIAPI EFI_STATUS efi_shim_get_memory_map ( UINTN *len, descver ); } +/** + * Wrap ExitBootServices() + * + * @v handle Image handle + * @v key Memory map key + * @ret efirc EFI status code + */ +static EFIAPI EFI_STATUS efi_shim_exit_boot_services ( EFI_HANDLE handle, + UINTN key ) { + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; + + /* Restore original runtime services functions */ + rs->SetVariable = efi_shim_orig_set_variable; + rs->GetVariable = efi_shim_orig_get_variable; + + /* Hand off to original ExitBootServices() */ + return efi_shim_orig_exit_boot_services ( handle, key ); +} + +/** + * Wrap SetVariable() + * + * @v name Variable name + * @v guid Variable namespace GUID + * @v attrs Attributes + * @v len Buffer size + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_shim_set_variable ( CHAR16 *name, EFI_GUID *guid, UINT32 attrs, + UINTN len, VOID *data ) { + EFI_STATUS efirc; + + /* Call original SetVariable() */ + efirc = efi_shim_orig_set_variable ( name, guid, attrs, len, data ); + + /* Allow verification of SbatLevel variable content */ + if ( efi_shim_is_sbatlevel ( name, guid ) && ( efirc == 0 ) ) { + DBGC ( &efi_shim, "SHIM detected write to %ls:\n", name ); + DBGC_HDA ( &efi_shim, 0, data, len ); + efi_shim_sbatlevel_verify = 1; + } + + return efirc; +} + +/** + * Wrap GetVariable() + * + * @v name Variable name + * @v guid Variable namespace GUID + * @v attrs Attributes to fill in + * @v len Buffer size + * @v data Data buffer + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_shim_get_variable ( CHAR16 *name, EFI_GUID *guid, UINT32 *attrs, + UINTN *len, VOID *data ) { + char *value = data; + EFI_STATUS efirc; + + /* Call original GetVariable() */ + efirc = efi_shim_orig_get_variable ( name, guid, attrs, len, data ); + + /* Patch SbatLevel variable if applicable */ + if ( efi_shim_is_sbatlevel ( name, guid ) && data && ( efirc == 0 ) ) { + if ( efi_shim_allow_sbat ) { + DBGC ( &efi_shim, "SHIM allowing read from %ls:\n", + name ); + } else if ( efi_shim_sbatlevel_verify ) { + DBGC ( &efi_shim, "SHIM allowing one read from %ls:\n", + name ); + efi_shim_sbatlevel_verify = 0; + } else { + DBGC ( &efi_shim, "SHIM patching read from %ls:\n", + name ); + value[0] = '\0'; + } + DBGC_HDA ( &efi_shim, 0, data, *len ); + } + + return efirc; +} + /** * Inhibit use of PXE base code * @@ -225,6 +358,7 @@ static int efi_shim_cmdline ( struct image *shim, wchar_t **cmdline ) { int efi_shim_install ( struct image *shim, EFI_HANDLE handle, wchar_t **cmdline ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; int rc; /* Stop PXE base code */ @@ -237,11 +371,17 @@ int efi_shim_install ( struct image *shim, EFI_HANDLE handle, if ( ( rc = efi_shim_cmdline ( shim, cmdline ) ) != 0 ) return rc; - /* Record original boot services functions */ + /* Record original boot and runtime services functions */ efi_shim_orig_get_memory_map = bs->GetMemoryMap; + efi_shim_orig_exit_boot_services = bs->ExitBootServices; + efi_shim_orig_set_variable = rs->SetVariable; + efi_shim_orig_get_variable = rs->GetVariable; - /* Wrap relevant boot services functions */ + /* Wrap relevant boot and runtime services functions */ bs->GetMemoryMap = efi_shim_get_memory_map; + bs->ExitBootServices = efi_shim_exit_boot_services; + rs->SetVariable = efi_shim_set_variable; + rs->GetVariable = efi_shim_get_variable; return 0; } @@ -252,7 +392,11 @@ int efi_shim_install ( struct image *shim, EFI_HANDLE handle, */ void efi_shim_uninstall ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; - /* Restore original boot services functions */ + /* Restore original boot and runtime services functions */ bs->GetMemoryMap = efi_shim_orig_get_memory_map; + bs->ExitBootServices = efi_shim_orig_exit_boot_services; + rs->SetVariable = efi_shim_orig_set_variable; + rs->GetVariable = efi_shim_orig_get_variable; } diff --git a/src/usr/shimmgmt.c b/src/usr/shimmgmt.c index ba9c3480..6ac1ac35 100644 --- a/src/usr/shimmgmt.c +++ b/src/usr/shimmgmt.c @@ -39,9 +39,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v image Shim image, or NULL to clear shim * @v require_loader Require use of a third party loader * @v allow_pxe Allow use of PXE base code + * @v allow_sbat Allow SBAT variable access * @ret rc Return status code */ -int shim ( struct image *image, int require_loader, int allow_pxe ) { +int shim ( struct image *image, int require_loader, int allow_pxe, + int allow_sbat ) { /* Record (or clear) shim image */ image_tag ( image, &efi_shim ); @@ -53,6 +55,7 @@ int shim ( struct image *image, int require_loader, int allow_pxe ) { /* Record configuration */ efi_shim_require_loader = require_loader; efi_shim_allow_pxe = allow_pxe; + efi_shim_allow_sbat = allow_sbat; return 0; } -- cgit v1.2.3-55-g7522 From 6a7f560e60837fc2ce82a7aa976035656f7d231e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 24 May 2023 10:20:31 +0100 Subject: [efi] Implement "shim" as a dummy command on non-EFI platforms The "shim" command will skip downloading the shim binary (and is therefore a conditional no-op) if there is already a selected EFI image that can be executed directly via LoadImage()/StartImage(). This allows the same iPXE script to be used with Secure Boot either enabled or disabled. Generalise this further to provide a dummy "shim" command that is an unconditional no-op on non-EFI platforms. This then allows the same iPXE script to be used for BIOS, EFI with Secure Boot disabled, or EFI with Secure Boot enabled. The same effect could be achieved by using "iseq ${platform} efi" within the script, but this would complicate end-user documentation. To minimise the code size impact, the dummy "shim" command is a pure no-op that does not call parse_options() and so will ignore even standardised arguments such as "--help". Signed-off-by: Michael Brown --- src/config/defaults/efi.h | 1 - src/config/general.h | 2 +- src/hci/commands/shim_cmd.c | 14 ++++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 998bdcc1..8e53b9ab 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -47,7 +47,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define USB_BLOCK /* USB block devices */ #define REBOOT_CMD /* Reboot command */ -#define SHIM_CMD /* EFI shim command */ #if defined ( __i386__ ) || defined ( __x86_64__ ) #define IOAPI_X86 diff --git a/src/config/general.h b/src/config/general.h index 2a371d0e..6e8e86b2 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -160,7 +160,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); //#define CERT_CMD /* Certificate management commands */ //#define IMAGE_MEM_CMD /* Read memory command */ #define IMAGE_ARCHIVE_CMD /* Archive image management commands */ -//#define SHIM_CMD /* EFI shim command */ +#define SHIM_CMD /* EFI shim command (or dummy command) */ /* * ROM-specific options diff --git a/src/hci/commands/shim_cmd.c b/src/hci/commands/shim_cmd.c index 9150af3f..11956290 100644 --- a/src/hci/commands/shim_cmd.c +++ b/src/hci/commands/shim_cmd.c @@ -36,6 +36,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +/* Exist as a dummy command on non-EFI platforms */ +#ifdef PLATFORM_efi +#define shim_dummy 0 +#else +#define shim_dummy 1 +#endif + /** "shim" options */ struct shim_options { /** Download timeout */ @@ -79,6 +86,12 @@ static int shim_exec ( int argc, char **argv ) { int download; int rc; + /* Do absolutely nothing if this is a non-EFI platform */ + if ( shim_dummy ) { + rc = 0; + goto err_dummy; + } + /* Parse options */ if ( ( rc = parse_options ( argc, argv, &shim_cmd, &opts ) ) != 0 ) goto err_parse; @@ -105,6 +118,7 @@ static int shim_exec ( int argc, char **argv ) { err_shim: err_image: err_parse: + err_dummy: return rc; } -- cgit v1.2.3-55-g7522 From b0093571f8bc0207673bb6a6ad5081263e7863b6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 2 Jun 2023 13:49:27 +0100 Subject: [crypto] Add support for PKCS#8 private key format Signed-off-by: Michael Brown --- src/crypto/asn1.c | 26 +++++++++++++++++++++ src/crypto/rsa.c | 19 +++++++++++++++- src/include/ipxe/asn1.h | 2 ++ src/tests/rsa_test.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index 549ee4d8..dc9d1c54 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -589,6 +589,32 @@ int asn1_signature_algorithm ( const struct asn1_cursor *cursor, return 0; } +/** + * Check ASN.1 OID-identified algorithm + * + * @v cursor ASN.1 object cursor + * @v expected Expected algorithm + * @ret rc Return status code + */ +int asn1_check_algorithm ( const struct asn1_cursor *cursor, + struct asn1_algorithm *expected ) { + struct asn1_algorithm *actual; + int rc; + + /* Parse algorithm */ + if ( ( rc = asn1_algorithm ( cursor, &actual ) ) != 0 ) + return rc; + + /* Check algorithm matches */ + if ( actual != expected ) { + DBGC ( cursor, "ASN1 %p algorithm %s does not match %s\n", + cursor, actual->name, expected->name ); + return -ENOTTY_ALGORITHM; + } + + return 0; +} + /** * Parse ASN.1 GeneralizedTime * diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index a3895574..16c67d82 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -164,7 +164,7 @@ static int rsa_parse_mod_exp ( struct asn1_cursor *modulus, int is_private; int rc; - /* Enter subjectPublicKeyInfo/RSAPrivateKey */ + /* Enter subjectPublicKeyInfo/privateKeyInfo/RSAPrivateKey */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); @@ -177,6 +177,23 @@ static int rsa_parse_mod_exp ( struct asn1_cursor *modulus, /* Skip version */ asn1_skip_any ( &cursor ); + /* Enter privateKey, if present */ + if ( asn1_check_algorithm ( &cursor, + &rsa_encryption_algorithm ) == 0 ) { + + /* Skip privateKeyAlgorithm */ + asn1_skip_any ( &cursor ); + + /* Enter privateKey */ + asn1_enter ( &cursor, ASN1_OCTET_STRING ); + + /* Enter RSAPrivateKey */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Skip version */ + asn1_skip ( &cursor, ASN1_INTEGER ); + } + } else { /* Public key */ diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index fdf06f10..77429f3a 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -424,6 +424,8 @@ extern int asn1_digest_algorithm ( const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm ); extern int asn1_signature_algorithm ( const struct asn1_cursor *cursor, struct asn1_algorithm **algorithm ); +extern int asn1_check_algorithm ( const struct asn1_cursor *cursor, + struct asn1_algorithm *expected ); extern int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ); extern int asn1_grow ( struct asn1_builder *builder, size_t extra ); diff --git a/src/tests/rsa_test.c b/src/tests/rsa_test.c index c5b587ca..46894f60 100644 --- a/src/tests/rsa_test.c +++ b/src/tests/rsa_test.c @@ -206,7 +206,7 @@ struct rsa_signature_test { sizeof ( bad_signature ) ); \ } while ( 0 ) -/** "Hello world" encryption and decryption test */ +/** "Hello world" encryption and decryption test (traditional PKCS#1 key) */ RSA_ENCRYPT_DECRYPT_TEST ( hw_test, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xd2, 0xf1, 0x04, 0x67, 0xf6, 0x2c, 0x96, 0x07, 0xa6, 0xbd, @@ -260,6 +260,63 @@ RSA_ENCRYPT_DECRYPT_TEST ( hw_test, 0x88, 0x4f, 0xec, 0x43, 0x9c, 0xed, 0xb3, 0xf2, 0x19, 0x89, 0x38, 0x43, 0xf9, 0x41 ) ); +/** "Hello world" encryption and decryption test (PKCS#8 key) */ +RSA_ENCRYPT_DECRYPT_TEST ( hw_test_pkcs8, + PRIVATE ( 0x30, 0x82, 0x01, 0x55, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x04, 0x82, 0x01, 0x3f, 0x30, 0x82, 0x01, 0x3b, + 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xd2, 0xf1, 0x04, 0x67, + 0xf6, 0x2c, 0x96, 0x07, 0xa6, 0xbd, 0x85, 0xac, 0xc1, 0x17, + 0x5d, 0xe8, 0xf0, 0x93, 0x94, 0x0c, 0x45, 0x67, 0x26, 0x67, + 0xde, 0x7e, 0xfb, 0xa8, 0xda, 0xbd, 0x07, 0xdf, 0xcf, 0x45, + 0x04, 0x6d, 0xbd, 0x69, 0x8b, 0xfb, 0xc1, 0x72, 0xc0, 0xfc, + 0x03, 0x04, 0xf2, 0x82, 0xc4, 0x7b, 0x6a, 0x3e, 0xec, 0x53, + 0x7a, 0xe3, 0x4e, 0xa8, 0xc9, 0xf9, 0x1f, 0x2a, 0x13, 0x0d, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x40, 0x49, 0xb8, 0x61, + 0xc9, 0xd3, 0x87, 0x11, 0x87, 0xeb, 0x06, 0x21, 0x49, 0x96, + 0xd2, 0x0b, 0xc7, 0xf5, 0x0c, 0x1e, 0x99, 0x8b, 0x47, 0xd9, + 0x6c, 0x43, 0x9e, 0x2d, 0x65, 0x7d, 0xcc, 0xc2, 0x8b, 0x1a, + 0x6f, 0x2b, 0x55, 0xbe, 0xb3, 0x9f, 0xd1, 0xe2, 0x9a, 0xde, + 0x1d, 0xac, 0xec, 0x67, 0xec, 0xa5, 0xbf, 0x9c, 0x30, 0xd6, + 0xf9, 0x0a, 0x1a, 0x48, 0xf3, 0xc2, 0x93, 0x3a, 0x17, 0x27, + 0x21, 0x02, 0x21, 0x00, 0xfc, 0x8d, 0xfb, 0xee, 0x8a, 0xaa, + 0x45, 0x19, 0x4b, 0xf0, 0x68, 0xb0, 0x02, 0x38, 0x3e, 0x03, + 0x6b, 0x24, 0x77, 0x20, 0xbd, 0x5e, 0x6c, 0x76, 0xdb, 0xc9, + 0xe1, 0x43, 0xa3, 0x40, 0x62, 0x6f, 0x02, 0x21, 0x00, 0xd5, + 0xd1, 0xb4, 0x4d, 0x03, 0x40, 0x69, 0x3f, 0x9a, 0xa7, 0x44, + 0x15, 0x28, 0x1e, 0xa5, 0x5f, 0xcf, 0x97, 0x21, 0x12, 0xb3, + 0xe6, 0x1c, 0x9a, 0x8d, 0xb7, 0xb4, 0x80, 0x3a, 0x9c, 0xb0, + 0x43, 0x02, 0x20, 0x71, 0xf0, 0xa0, 0xab, 0x82, 0xf5, 0xc4, + 0x8c, 0xe0, 0x1c, 0xcb, 0x2e, 0x35, 0x22, 0x28, 0xa0, 0x24, + 0x33, 0x64, 0x67, 0x69, 0xe7, 0xf2, 0xa9, 0x41, 0x09, 0x78, + 0x4e, 0xaa, 0x95, 0x3e, 0x93, 0x02, 0x21, 0x00, 0x85, 0xcc, + 0x4d, 0xd9, 0x0b, 0x39, 0xd9, 0x22, 0x75, 0xf2, 0x49, 0x46, + 0x3b, 0xee, 0xc1, 0x69, 0x6d, 0x0b, 0x93, 0x24, 0x92, 0xf2, + 0x61, 0xdf, 0xcc, 0xe2, 0xb1, 0xce, 0xb3, 0xde, 0xac, 0xe5, + 0x02, 0x21, 0x00, 0x9c, 0x23, 0x6a, 0x95, 0xa6, 0xfe, 0x1e, + 0xd8, 0x0c, 0x3f, 0x6e, 0xe6, 0x0a, 0xeb, 0x97, 0xd6, 0x36, + 0x1c, 0x80, 0xc1, 0x02, 0x87, 0x0d, 0x4d, 0xfe, 0x28, 0x02, + 0x1e, 0xde, 0xe1, 0xcc, 0x72 ), + PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, + 0x30, 0x48, 0x02, 0x41, 0x00, 0xd2, 0xf1, 0x04, 0x67, 0xf6, + 0x2c, 0x96, 0x07, 0xa6, 0xbd, 0x85, 0xac, 0xc1, 0x17, 0x5d, + 0xe8, 0xf0, 0x93, 0x94, 0x0c, 0x45, 0x67, 0x26, 0x67, 0xde, + 0x7e, 0xfb, 0xa8, 0xda, 0xbd, 0x07, 0xdf, 0xcf, 0x45, 0x04, + 0x6d, 0xbd, 0x69, 0x8b, 0xfb, 0xc1, 0x72, 0xc0, 0xfc, 0x03, + 0x04, 0xf2, 0x82, 0xc4, 0x7b, 0x6a, 0x3e, 0xec, 0x53, 0x7a, + 0xe3, 0x4e, 0xa8, 0xc9, 0xf9, 0x1f, 0x2a, 0x13, 0x0d, 0x02, + 0x03, 0x01, 0x00, 0x01 ), + PLAINTEXT ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x0a ), + CIPHERTEXT ( 0x39, 0xff, 0x5c, 0x54, 0x65, 0x3e, 0x6a, 0xab, 0xc0, 0x62, + 0x91, 0xb2, 0xbf, 0x1d, 0x73, 0x5b, 0xd5, 0x4c, 0xbd, 0x16, + 0x0f, 0x24, 0xc9, 0xf5, 0xa7, 0xdd, 0x94, 0xd6, 0xf8, 0xae, + 0xd3, 0xa0, 0x9f, 0x4d, 0xff, 0x8d, 0x81, 0x34, 0x47, 0xff, + 0x2a, 0x87, 0x96, 0xd3, 0x17, 0x5d, 0x93, 0x4d, 0x7b, 0x27, + 0x88, 0x4f, 0xec, 0x43, 0x9c, 0xed, 0xb3, 0xf2, 0x19, 0x89, + 0x38, 0x43, 0xf9, 0x41 ) ); + /** Random message MD5 signature test */ RSA_SIGNATURE_TEST ( md5_test, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, @@ -486,6 +543,7 @@ RSA_SIGNATURE_TEST ( sha256_test, static void rsa_test_exec ( void ) { rsa_encrypt_decrypt_ok ( &hw_test ); + rsa_encrypt_decrypt_ok ( &hw_test_pkcs8 ); rsa_signature_ok ( &md5_test ); rsa_signature_ok ( &sha1_test ); rsa_signature_ok ( &sha256_test ); -- cgit v1.2.3-55-g7522 From 9cb0a4b8ecfa2aa24df36eb43d3f50dde32442d1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:18:38 +0100 Subject: [efi] Disable static assertions in EFI headers on non-EFI platforms The EDK2 headers may be included even in builds for non-EFI platforms. Commits such as 9de6c45 ("[arm] Use -fno-short-enums for all 32-bit ARM builds") have so far ensured that the compile-time checks within the EDK2 headers will pass even when building for a non-EFI platform. As a more general solution, temporarily disable static assertions while including UefiBaseType.h if building on a non-EFI platform. This avoids the need to modify the ABI on other platforms. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index e0e2db60..29117fa3 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -43,10 +43,19 @@ FILE_LICENCE ( GPL2_OR_LATER ); * checking somewhat useless. Work around this bizarre sabotage * attempt by redefining EFI_HANDLE as a pointer to an anonymous * structure. + * + * EFI headers perform some ABI validation checks via _Static_assert() + * that may fail when EFI headers are included on a non-EFI platform. + * Temporarily disable static assertions to allow these headers to be + * included. */ #define EFI_HANDLE STUPID_EFI_HANDLE +#ifndef PLATFORM_efi +#define _Static_assert(expr, msg) +#endif #include #undef EFI_HANDLE +#undef _Static_assert typedef struct {} *EFI_HANDLE; /* Include the top-level EFI header files */ -- cgit v1.2.3-55-g7522 From 3184ff74eb5fb65e12537b4047e941d406392561 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:24:42 +0100 Subject: [efi] Update to current EDK2 headers Signed-off-by: Michael Brown --- src/include/ipxe/efi/AArch64/ProcessorBind.h | 34 ++++++++ src/include/ipxe/efi/Base.h | 110 ++++++++++++++++++++++-- src/include/ipxe/efi/Ia32/ProcessorBind.h | 8 +- src/include/ipxe/efi/IndustryStandard/PeImage.h | 44 +++++++++- src/include/ipxe/efi/Library/BaseLib.h | 50 +++++++++++ src/include/ipxe/efi/Protocol/DebugSupport.h | 34 +++++++- src/include/ipxe/efi/Uefi/UefiSpec.h | 4 +- src/include/ipxe/efi/X64/ProcessorBind.h | 22 +---- 8 files changed, 266 insertions(+), 40 deletions(-) diff --git a/src/include/ipxe/efi/AArch64/ProcessorBind.h b/src/include/ipxe/efi/AArch64/ProcessorBind.h index d0cb86a4..3a7f7746 100644 --- a/src/include/ipxe/efi/AArch64/ProcessorBind.h +++ b/src/include/ipxe/efi/AArch64/ProcessorBind.h @@ -188,6 +188,40 @@ typedef INT64 INTN; #define GCC_ASM_IMPORT(func__) \ .extern _CONCATENATE (__USER_LABEL_PREFIX__, func__) + #if defined (__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1 +#define AARCH64_BTI_NOTE() \ + .ifndef .Lgnu_bti_notesize ;\ + .pushsection .note.gnu.property, "a" ;\ + .set NT_GNU_PROPERTY_TYPE_0, 0x5 ;\ + .set GNU_PROPERTY_AARCH64_FEATURE_1_AND, 0xc0000000 ;\ + .set GNU_PROPERTY_AARCH64_FEATURE_1_BTI, 0x1 ;\ + .align 3 ;\ + .long .Lnamesize ;\ + .long .Lgnu_bti_notesize ;\ + .long NT_GNU_PROPERTY_TYPE_0 ;\ +0: .asciz "GNU" ;\ + .set .Lnamesize, . - 0b ;\ + .align 3 ;\ +1: .long GNU_PROPERTY_AARCH64_FEATURE_1_AND ;\ + .long .Lvalsize ;\ +2: .long GNU_PROPERTY_AARCH64_FEATURE_1_BTI ;\ + .set .Lvalsize, . - 2b ;\ + .align 3 ;\ + .set .Lgnu_bti_notesize, . - 1b ;\ + .popsection ;\ + .endif + +#define AARCH64_BTI(__type) \ + AARCH64_BTI_NOTE() ;\ + bti __type + + #endif + +#endif + +#ifndef AARCH64_BTI +#define AARCH64_BTI_NOTE() +#define AARCH64_BTI(__type) #endif /** diff --git a/src/include/ipxe/efi/Base.h b/src/include/ipxe/efi/Base.h index b0093c63..e76013c1 100644 --- a/src/include/ipxe/efi/Base.h +++ b/src/include/ipxe/efi/Base.h @@ -760,6 +760,40 @@ typedef UINTN *BASE_LIST; #define OFFSET_OF(TYPE, Field) ((UINTN) &(((TYPE *)0)->Field)) #endif +/** + Returns the alignment requirement of a type. + + @param TYPE The name of the type to retrieve the alignment requirement of. + + @return Alignment requirement, in Bytes, of TYPE. +**/ +#if defined (__cplusplus) +// +// Standard C++ operator. +// +#define ALIGNOF(TYPE) alignof (TYPE) +#elif defined (__GNUC__) || defined (__clang__) || (defined (_MSC_VER) && _MSC_VER >= 1900) +// +// All supported versions of GCC and Clang, as well as MSVC 2015 and later, +// support the standard operator _Alignof. +// +#define ALIGNOF(TYPE) _Alignof (TYPE) +#elif defined (_MSC_EXTENSIONS) +// +// Earlier versions of MSVC, at least MSVC 2008 and later, support the vendor +// extension __alignof. +// +#define ALIGNOF(TYPE) __alignof (TYPE) +#else +// +// For compilers that do not support inbuilt alignof operators, use OFFSET_OF. +// CHAR8 is known to have both a size and an alignment requirement of 1 Byte. +// As such, A must be located exactly at the offset equal to its alignment +// requirement. +// +#define ALIGNOF(TYPE) OFFSET_OF (struct { CHAR8 C; TYPE A; }, A) +#endif + /** Portable definition for compile time assertions. Equivalent to C11 static_assert macro from assert.h. @@ -795,12 +829,27 @@ STATIC_ASSERT (sizeof (CHAR16) == 2, "sizeof (CHAR16) does not meet UEFI Specif STATIC_ASSERT (sizeof (L'A') == 2, "sizeof (L'A') does not meet UEFI Specification Data Type requirements"); STATIC_ASSERT (sizeof (L"A") == 4, "sizeof (L\"A\") does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (BOOLEAN) == sizeof (BOOLEAN), "Alignment of BOOLEAN does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (INT8) == sizeof (INT8), "Alignment of INT8 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (UINT8) == sizeof (UINT8), "Alignment of INT16 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (INT16) == sizeof (INT16), "Alignment of INT16 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (UINT16) == sizeof (UINT16), "Alignment of UINT16 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (INT32) == sizeof (INT32), "Alignment of INT32 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (UINT32) == sizeof (UINT32), "Alignment of UINT32 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (INT64) == sizeof (INT64), "Alignment of INT64 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (UINT64) == sizeof (UINT64), "Alignment of UINT64 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (CHAR8) == sizeof (CHAR8), "Alignment of CHAR8 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (CHAR16) == sizeof (CHAR16), "Alignment of CHAR16 does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (INTN) == sizeof (INTN), "Alignment of INTN does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (UINTN) == sizeof (UINTN), "Alignment of UINTN does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (VOID *) == sizeof (VOID *), "Alignment of VOID * does not meet UEFI Specification Data Type requirements"); + // // The following three enum types are used to verify that the compiler // configuration for enum types is compliant with Section 2.3.1 of the -// UEFI 2.3 Specification. These enum types and enum values are not -// intended to be used. A prefix of '__' is used avoid conflicts with -// other types. +// UEFI 2.3.1 Errata C Specification. These enum types and enum values +// are not intended to be used. A prefix of '__' is used avoid +// conflicts with other types. // typedef enum { __VerifyUint8EnumValue = 0xff @@ -811,12 +860,16 @@ typedef enum { } __VERIFY_UINT16_ENUM_SIZE; typedef enum { - __VerifyUint32EnumValue = 0xffffffff -} __VERIFY_UINT32_ENUM_SIZE; + __VerifyInt32EnumValue = 0x7fffffff +} __VERIFY_INT32_ENUM_SIZE; STATIC_ASSERT (sizeof (__VERIFY_UINT8_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements"); STATIC_ASSERT (sizeof (__VERIFY_UINT16_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements"); -STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (sizeof (__VERIFY_INT32_ENUM_SIZE) == 4, "Size of enum does not meet UEFI Specification Data Type requirements"); + +STATIC_ASSERT (ALIGNOF (__VERIFY_UINT8_ENUM_SIZE) == sizeof (__VERIFY_UINT8_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (__VERIFY_UINT16_ENUM_SIZE) == sizeof (__VERIFY_UINT16_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements"); +STATIC_ASSERT (ALIGNOF (__VERIFY_INT32_ENUM_SIZE) == sizeof (__VERIFY_INT32_ENUM_SIZE), "Alignment of enum does not meet UEFI Specification Data Type requirements"); /** Macro that returns a pointer to the data structure that contains a specified field of @@ -839,6 +892,49 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not m **/ #define BASE_CR(Record, TYPE, Field) ((TYPE *) ((CHAR8 *) (Record) - OFFSET_OF (TYPE, Field))) +/** + Checks whether a value is a power of two. + + @param Value The value to check. + + @retval TRUE Value is a power of two. + @retval FALSE Value is not a power of two. +**/ +#define IS_POW2(Value) ((Value) != 0U && ((Value) & ((Value) - 1U)) == 0U) + +/** + Checks whether a value is aligned by a specified alignment. + + @param Value The value to check. + @param Alignment The alignment boundary used to check against. + + @retval TRUE Value is aligned by Alignment. + @retval FALSE Value is not aligned by Alignment. +**/ +#define IS_ALIGNED(Value, Alignment) (((Value) & ((Alignment) - 1U)) == 0U) + +/** + Checks whether a pointer or address is aligned by a specified alignment. + + @param Address The pointer or address to check. + @param Alignment The alignment boundary used to check against. + + @retval TRUE Address is aligned by Alignment. + @retval FALSE Address is not aligned by Alignment. +**/ +#define ADDRESS_IS_ALIGNED(Address, Alignment) IS_ALIGNED ((UINTN) (Address), Alignment) + +/** + Determines the addend to add to a value to round it up to the next boundary of + a specified alignment. + + @param Value The value to round up. + @param Alignment The alignment boundary used to return the addend. + + @return Addend to round Value up to alignment boundary Alignment. +**/ +#define ALIGN_VALUE_ADDEND(Value, Alignment) (((Alignment) - (Value)) & ((Alignment) - 1U)) + /** Rounds a value up to the next boundary using a specified alignment. @@ -851,7 +947,7 @@ STATIC_ASSERT (sizeof (__VERIFY_UINT32_ENUM_SIZE) == 4, "Size of enum does not m @return A value up to the next boundary. **/ -#define ALIGN_VALUE(Value, Alignment) ((Value) + (((Alignment) - (Value)) & ((Alignment) - 1))) +#define ALIGN_VALUE(Value, Alignment) ((Value) + ALIGN_VALUE_ADDEND (Value, Alignment)) /** Adjust a pointer by adding the minimum offset required for it to be aligned on diff --git a/src/include/ipxe/efi/Ia32/ProcessorBind.h b/src/include/ipxe/efi/Ia32/ProcessorBind.h index 5e3fb92d..b922597f 100644 --- a/src/include/ipxe/efi/Ia32/ProcessorBind.h +++ b/src/include/ipxe/efi/Ia32/ProcessorBind.h @@ -90,19 +90,15 @@ FILE_LICENCE ( BSD2_PATENT ); #if defined (_MSC_VER) && _MSC_VER >= 1800 -// -// Disable these warnings for VS2013. -// - // // This warning is for potentially uninitialized local variable, and it may cause false -// positive issues in VS2013 and VS2015 build +// positive issues in VS2015 build // #pragma warning ( disable : 4701 ) // // This warning is for potentially uninitialized local pointer variable, and it may cause -// false positive issues in VS2013 and VS2015 build +// false positive issues in VS2015 build // #pragma warning ( disable : 4703 ) diff --git a/src/include/ipxe/efi/IndustryStandard/PeImage.h b/src/include/ipxe/efi/IndustryStandard/PeImage.h index 0e0f54f8..401e961c 100644 --- a/src/include/ipxe/efi/IndustryStandard/PeImage.h +++ b/src/include/ipxe/efi/IndustryStandard/PeImage.h @@ -103,6 +103,7 @@ typedef struct { #define EFI_IMAGE_FILE_EXECUTABLE_IMAGE BIT1 ///< 0x0002 File is executable (i.e. no unresolved externel references). #define EFI_IMAGE_FILE_LINE_NUMS_STRIPPED BIT2 ///< 0x0004 Line numbers stripped from file. #define EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED BIT3 ///< 0x0008 Local symbols stripped from file. +#define EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE BIT5 ///< 0x0020 Supports addresses > 2-GB #define EFI_IMAGE_FILE_BYTES_REVERSED_LO BIT7 ///< 0x0080 Bytes of machine word are reversed. #define EFI_IMAGE_FILE_32BIT_MACHINE BIT8 ///< 0x0100 32 bit word machine. #define EFI_IMAGE_FILE_DEBUG_STRIPPED BIT9 ///< 0x0200 Debugging info stripped from file in .DBG file. @@ -579,6 +580,13 @@ typedef struct { UINT32 AddressOfNameOrdinals; } EFI_IMAGE_EXPORT_DIRECTORY; +// +// Based export types. +// +#define EFI_IMAGE_EXPORT_ORDINAL_BASE 1 +#define EFI_IMAGE_EXPORT_ADDR_SIZE 4 +#define EFI_IMAGE_EXPORT_ORDINAL_SIZE 2 + /// /// Hint/Name Table. /// @@ -627,7 +635,8 @@ typedef struct { UINT32 FileOffset; ///< The file pointer to the debug data. } EFI_IMAGE_DEBUG_DIRECTORY_ENTRY; -#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information. +#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW 2 ///< The Visual C++ debug information. +#define EFI_IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS 20 /// /// Debug Data Structure defined in Microsoft C++. @@ -671,6 +680,39 @@ typedef struct { // } EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY; +// avoid conflict with windows header files +#ifndef RUNTIME_FUNCTION_INDIRECT + +// +// .pdata entries for X64 +// +typedef struct { + UINT32 FunctionStartAddress; + UINT32 FunctionEndAddress; + UINT32 UnwindInfoAddress; +} RUNTIME_FUNCTION; + +#endif + +typedef struct { + UINT8 Version : 3; + UINT8 Flags : 5; + UINT8 SizeOfProlog; + UINT8 CountOfUnwindCodes; + UINT8 FrameRegister : 4; + UINT8 FrameRegisterOffset : 4; +} UNWIND_INFO; + +/// +/// Extended DLL Characteristics +/// +#define EFI_IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT 0x0001 +#define EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT 0x0040 + +typedef struct { + UINT32 DllCharacteristicsEx; +} EFI_IMAGE_DEBUG_EX_DLLCHARACTERISTICS_ENTRY; + /// /// Resource format. /// diff --git a/src/include/ipxe/efi/Library/BaseLib.h b/src/include/ipxe/efi/Library/BaseLib.h index 416ca00d..e17f3da2 100644 --- a/src/include/ipxe/efi/Library/BaseLib.h +++ b/src/include/ipxe/efi/Library/BaseLib.h @@ -153,6 +153,56 @@ typedef struct { #define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT 8 +VOID +RiscVSetSupervisorScratch ( + IN UINT64 + ); + +UINT64 +RiscVGetSupervisorScratch ( + VOID + ); + +VOID +RiscVSetSupervisorStvec ( + IN UINT64 + ); + +UINT64 +RiscVGetSupervisorStvec ( + VOID + ); + +UINT64 +RiscVGetSupervisorTrapCause ( + VOID + ); + +VOID +RiscVSetSupervisorAddressTranslationRegister ( + IN UINT64 + ); + +UINT64 +RiscVReadTimer ( + VOID + ); + +VOID +RiscVEnableTimerInterrupt ( + VOID + ); + +VOID +RiscVDisableTimerInterrupt ( + VOID + ); + +VOID +RiscVClearPendingTimerInterrupt ( + VOID + ); + #endif // defined (MDE_CPU_RISCV64) #if defined (MDE_CPU_LOONGARCH64) diff --git a/src/include/ipxe/efi/Protocol/DebugSupport.h b/src/include/ipxe/efi/Protocol/DebugSupport.h index 1b28b0ed..453ea975 100644 --- a/src/include/ipxe/efi/Protocol/DebugSupport.h +++ b/src/include/ipxe/efi/Protocol/DebugSupport.h @@ -615,11 +615,34 @@ typedef struct { #define EXCEPT_RISCV_STORE_AMO_ACCESS_FAULT 7 #define EXCEPT_RISCV_ENV_CALL_FROM_UMODE 8 #define EXCEPT_RISCV_ENV_CALL_FROM_SMODE 9 -#define EXCEPT_RISCV_ENV_CALL_FROM_HMODE 10 +#define EXCEPT_RISCV_ENV_CALL_FROM_VS_MODE 10 #define EXCEPT_RISCV_ENV_CALL_FROM_MMODE 11 - -#define EXCEPT_RISCV_SOFTWARE_INT 0x0 -#define EXCEPT_RISCV_TIMER_INT 0x1 +#define EXCEPT_RISCV_INST_ACCESS_PAGE_FAULT 12 +#define EXCEPT_RISCV_LOAD_ACCESS_PAGE_FAULT 13 +#define EXCEPT_RISCV_14 14 +#define EXCEPT_RISCV_STORE_ACCESS_PAGE_FAULT 15 +#define EXCEPT_RISCV_16 16 +#define EXCEPT_RISCV_17 17 +#define EXCEPT_RISCV_18 18 +#define EXCEPT_RISCV_19 19 +#define EXCEPT_RISCV_INST_GUEST_PAGE_FAULT 20 +#define EXCEPT_RISCV_LOAD_GUEST_PAGE_FAULT 21 +#define EXCEPT_RISCV_VIRTUAL_INSTRUCTION 22 +#define EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT 23 +#define EXCEPT_RISCV_MAX_EXCEPTIONS (EXCEPT_RISCV_STORE_GUEST_PAGE_FAULT) + +/// +/// RISC-V processor exception types for interrupts. +/// +#define EXCEPT_RISCV_IS_IRQ(x) ((x & 0x8000000000000000UL) != 0) +#define EXCEPT_RISCV_IRQ_INDEX(x) (x & 0x7FFFFFFFFFFFFFFFUL) +#define EXCEPT_RISCV_IRQ_0 0x8000000000000000UL +#define EXCEPT_RISCV_IRQ_SOFT_FROM_SMODE 0x8000000000000001UL +#define EXCEPT_RISCV_IRQ_SOFT_FROM_VSMODE 0x8000000000000002UL +#define EXCEPT_RISCV_IRQ_SOFT_FROM_MMODE 0x8000000000000003UL +#define EXCEPT_RISCV_IRQ_4 0x8000000000000004UL +#define EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE 0x8000000000000005UL +#define EXCEPT_RISCV_MAX_IRQS (EXCEPT_RISCV_IRQ_INDEX(EXCEPT_RISCV_IRQ_TIMER_FROM_SMODE)) typedef struct { UINT64 X0; @@ -654,6 +677,9 @@ typedef struct { UINT64 X29; UINT64 X30; UINT64 X31; + UINT64 SEPC; + UINT32 SSTATUS; + UINT32 STVAL; } EFI_SYSTEM_CONTEXT_RISCV64; // diff --git a/src/include/ipxe/efi/Uefi/UefiSpec.h b/src/include/ipxe/efi/Uefi/UefiSpec.h index 3ef66daf..e5a32d88 100644 --- a/src/include/ipxe/efi/Uefi/UefiSpec.h +++ b/src/include/ipxe/efi/Uefi/UefiSpec.h @@ -467,8 +467,8 @@ EFI_STATUS (EFIAPI *EFI_CREATE_EVENT)( IN UINT32 Type, IN EFI_TPL NotifyTpl, - IN EFI_EVENT_NOTIFY NotifyFunction, - IN VOID *NotifyContext, + IN EFI_EVENT_NOTIFY NotifyFunction OPTIONAL, + IN VOID *NotifyContext OPTIONAL, OUT EFI_EVENT *Event ); diff --git a/src/include/ipxe/efi/X64/ProcessorBind.h b/src/include/ipxe/efi/X64/ProcessorBind.h index fa53404e..062a77ba 100644 --- a/src/include/ipxe/efi/X64/ProcessorBind.h +++ b/src/include/ipxe/efi/X64/ProcessorBind.h @@ -23,20 +23,6 @@ FILE_LICENCE ( BSD2_PATENT ); #pragma pack() #endif -#if defined (__GNUC__) && defined (__pic__) && !defined (USING_LTO) && !defined (__APPLE__) -// -// Mark all symbol declarations and references as hidden, meaning they will -// not be subject to symbol preemption. This allows the compiler to refer to -// symbols directly using relative references rather than via the GOT, which -// contains absolute symbol addresses that are subject to runtime relocation. -// -// The LTO linker will not emit GOT based relocations when all symbol -// references can be resolved locally, and so there is no need to set the -// pragma in that case (and doing so will cause other issues). -// - #pragma GCC visibility push (hidden) -#endif - #if defined (__INTEL_COMPILER) // // Disable ICC's remark #869: "Parameter" was never referenced warning. @@ -104,19 +90,15 @@ FILE_LICENCE ( BSD2_PATENT ); #if defined (_MSC_VER) && _MSC_VER >= 1800 -// -// Disable these warnings for VS2013. -// - // // This warning is for potentially uninitialized local variable, and it may cause false -// positive issues in VS2013 and VS2015 build +// positive issues in VS2015 build // #pragma warning ( disable : 4701 ) // // This warning is for potentially uninitialized local pointer variable, and it may cause -// false positive issues in VS2013 and VS2015 build +// false positive issues in VS2015 build // #pragma warning ( disable : 4703 ) -- cgit v1.2.3-55-g7522 From 92ab2de3a448fd0175c59f68582fee62114fde64 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:27:06 +0100 Subject: [efi] Add IPv6 versions of existing IPv4 headers and GUID definitions Signed-off-by: Michael Brown --- src/include/ipxe/efi/Protocol/Dhcp6.h | 782 ++++++++++++++++++++++++ src/include/ipxe/efi/Protocol/Ip6.h | 948 ++++++++++++++++++++++++++++++ src/include/ipxe/efi/Protocol/Ip6Config.h | 369 ++++++++++++ src/include/ipxe/efi/Protocol/Mtftp6.h | 820 ++++++++++++++++++++++++++ src/include/ipxe/efi/Protocol/Tcp6.h | 858 +++++++++++++++++++++++++++ src/include/ipxe/efi/Protocol/Udp6.h | 576 ++++++++++++++++++ src/include/ipxe/efi/efi.h | 11 + src/interface/efi/efi_debug.c | 22 + src/interface/efi/efi_guid.c | 50 ++ 9 files changed, 4436 insertions(+) create mode 100644 src/include/ipxe/efi/Protocol/Dhcp6.h create mode 100644 src/include/ipxe/efi/Protocol/Ip6.h create mode 100644 src/include/ipxe/efi/Protocol/Ip6Config.h create mode 100644 src/include/ipxe/efi/Protocol/Mtftp6.h create mode 100644 src/include/ipxe/efi/Protocol/Tcp6.h create mode 100644 src/include/ipxe/efi/Protocol/Udp6.h diff --git a/src/include/ipxe/efi/Protocol/Dhcp6.h b/src/include/ipxe/efi/Protocol/Dhcp6.h new file mode 100644 index 00000000..19f59086 --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Dhcp6.h @@ -0,0 +1,782 @@ +/** @file + UEFI Dynamic Host Configuration Protocol 6 Definition, which is used to get IPv6 + addresses and other configuration parameters from DHCPv6 servers. + + Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.2 + +**/ + +#ifndef __EFI_DHCP6_PROTOCOL_H__ +#define __EFI_DHCP6_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#define EFI_DHCP6_PROTOCOL_GUID \ + { \ + 0x87c8bad7, 0x595, 0x4053, {0x82, 0x97, 0xde, 0xde, 0x39, 0x5f, 0x5d, 0x5b } \ + } + +#define EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0x9fb9a8a1, 0x2f4a, 0x43a6, {0x88, 0x9c, 0xd0, 0xf7, 0xb6, 0xc4, 0x7a, 0xd5 } \ + } + +typedef struct _EFI_DHCP6_PROTOCOL EFI_DHCP6_PROTOCOL; + +typedef enum { + /// + /// The EFI DHCPv6 Protocol instance is configured, and start() needs + /// to be called + /// + Dhcp6Init = 0x0, + /// + /// A Solicit packet is sent out to discover DHCPv6 server, and the EFI + /// DHCPv6 Protocol instance is collecting Advertise packets. + /// + Dhcp6Selecting = 0x1, + /// + /// A Request is sent out to the DHCPv6 server, and the EFI DHCPv6 + /// Protocol instance is waiting for Reply packet. + /// + Dhcp6Requesting = 0x2, + /// + /// A Decline packet is sent out to indicate one or more addresses of the + /// configured IA are in use by another node, and the EFI DHCPv6. + /// Protocol instance is waiting for Reply packet. + /// + Dhcp6Declining = 0x3, + /// + /// A Confirm packet is sent out to confirm the IPv6 addresses of the + /// configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet. + /// + Dhcp6Confirming = 0x4, + /// + /// A Release packet is sent out to release one or more IPv6 addresses of + /// the configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet. + /// + Dhcp6Releasing = 0x5, + /// + /// The DHCPv6 S.A.R.R process is completed for the configured IA. + /// + Dhcp6Bound = 0x6, + /// + /// A Renew packet is sent out to extend lifetime for the IPv6 addresses of + /// the configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet. + /// + Dhcp6Renewing = 0x7, + /// + /// A Rebind packet is sent out to extend lifetime for the IPv6 addresses of + /// the configured IA, and the EFI DHCPv6 Protocol instance is waiting for Reply packet. + /// + Dhcp6Rebinding = 0x8 +} EFI_DHCP6_STATE; + +typedef enum { + /// + /// A Solicit packet is about to be sent. The packet is passed to Dhcp6Callback and + /// can be modified or replaced in Dhcp6Callback. + /// + Dhcp6SendSolicit = 0x0, + /// + /// An Advertise packet is received and will be passed to Dhcp6Callback. + /// + Dhcp6RcvdAdvertise = 0x1, + /// + /// It is time for Dhcp6Callback to determine whether select the default Advertise + /// packet by RFC 3315 policy, or overwrite it by specific user policy. + /// + Dhcp6SelectAdvertise = 0x2, + /// + /// A Request packet is about to be sent. The packet is passed to Dhcp6Callback and + /// can be modified or replaced in Dhcp6Callback. + /// + Dhcp6SendRequest = 0x3, + /// + /// A Reply packet is received and will be passed to Dhcp6Callback. + /// + Dhcp6RcvdReply = 0x4, + /// + /// A Reconfigure packet is received and will be passed to Dhcp6Callback. + /// + Dhcp6RcvdReconfigure = 0x5, + /// + /// A Decline packet is about to be sent. The packet is passed to Dhcp6Callback and + /// can be modified or replaced in Dhcp6Callback. + /// + Dhcp6SendDecline = 0x6, + /// + /// A Confirm packet is about to be sent. The packet is passed to Dhcp6Callback and + /// can be modified or replaced in Dhcp6Callback. + /// + Dhcp6SendConfirm = 0x7, + /// + /// A Release packet is about to be sent. The packet is passed to Dhcp6Callback and + /// can be modified or replaced in Dhcp6Callback. + /// + Dhcp6SendRelease = 0x8, + /// + /// A Renew packet is about to be sent. The packet is passed to Dhcp6Callback and + /// can be modified or replaced in Dhcp6Callback. + /// + Dhcp6EnterRenewing = 0x9, + /// + /// A Rebind packet is about to be sent. The packet is passed to Dhcp6Callback and + /// can be modified or replaced in Dhcp6Callback. + /// + Dhcp6EnterRebinding = 0xa +} EFI_DHCP6_EVENT; + +/// +/// An IA which carries assigned not temporary address. +/// +#define EFI_DHCP6_IA_TYPE_NA 3 +/// +/// An IA which carries assigned temporary address. +/// +#define EFI_DHCP6_IA_TYPE_TA 4 + +#pragma pack(1) +/// +/// EFI_DHCP6_PACKET_OPTION +/// defines the format of the DHCPv6 option, See RFC 3315 for more information. +/// This data structure is used to reference option data that is packed in the DHCPv6 packet. +/// +typedef struct { + /// + /// The DHCPv6 option code, stored in network order. + /// + UINT16 OpCode; + /// + /// Length of the DHCPv6 option data, stored in network order. + /// From the first byte to the last byte of the Data field. + /// + UINT16 OpLen; + /// + /// The data for the DHCPv6 option, stored in network order. + /// + UINT8 Data[1]; +} EFI_DHCP6_PACKET_OPTION; + +/// +/// EFI_DHCP6_HEADER +/// defines the format of the DHCPv6 header. See RFC 3315 for more information. +/// +typedef struct { + /// + /// The DHCPv6 transaction ID. + /// + UINT32 MessageType : 8; + /// + /// The DHCPv6 message type. + /// + UINT32 TransactionId : 24; +} EFI_DHCP6_HEADER; + +/// +/// EFI_DHCP6_PACKET +/// defines the format of the DHCPv6 packet. See RFC 3315 for more information. +/// +typedef struct { + /// + /// Size of the EFI_DHCP6_PACKET buffer. + /// + UINT32 Size; + /// + /// Length of the EFI_DHCP6_PACKET from the first byte of the Header field to the last + /// byte of the Option[] field. + /// + UINT32 Length; + struct { + /// + /// The DHCPv6 packet header. + /// + EFI_DHCP6_HEADER Header; + /// + /// Start of the DHCPv6 packed option data. + /// + UINT8 Option[1]; + } Dhcp6; +} EFI_DHCP6_PACKET; + +#pragma pack() + +typedef struct { + /// + /// Length of DUID in octects. + /// + UINT16 Length; + /// + /// Array of DUID octects. + /// + UINT8 Duid[1]; +} EFI_DHCP6_DUID; + +typedef struct { + /// + /// Initial retransmission timeout. + /// + UINT32 Irt; + /// + /// Maximum retransmission count for one packet. If Mrc is zero, there's no upper limit + /// for retransmission count. + /// + UINT32 Mrc; + /// + /// Maximum retransmission timeout for each retry. It's the upper bound of the number of + /// retransmission timeout. If Mrt is zero, there is no upper limit for retransmission + /// timeout. + /// + UINT32 Mrt; + /// + /// Maximum retransmission duration for one packet. It's the upper bound of the numbers + /// the client may retransmit a message. If Mrd is zero, there's no upper limit for + /// retransmission duration. + /// + UINT32 Mrd; +} EFI_DHCP6_RETRANSMISSION; + +typedef struct { + /// + /// The IPv6 address. + /// + EFI_IPv6_ADDRESS IpAddress; + /// + /// The preferred lifetime in unit of seconds for the IPv6 address. + /// + UINT32 PreferredLifetime; + /// + /// The valid lifetime in unit of seconds for the IPv6 address. + /// + UINT32 ValidLifetime; +} EFI_DHCP6_IA_ADDRESS; + +typedef struct { + UINT16 Type; ///< Type for an IA. + UINT32 IaId; ///< The identifier for an IA. +} EFI_DHCP6_IA_DESCRIPTOR; + +typedef struct { + /// + /// The descriptor for IA. + /// + EFI_DHCP6_IA_DESCRIPTOR Descriptor; + /// + /// The state of the configured IA. + /// + EFI_DHCP6_STATE State; + /// + /// Pointer to the cached latest Reply packet. May be NULL if no packet is cached. + /// + EFI_DHCP6_PACKET *ReplyPacket; + /// + /// Number of IPv6 addresses of the configured IA. + /// + UINT32 IaAddressCount; + /// + /// List of the IPv6 addresses of the configured IA. When the state of the configured IA is + /// in Dhcp6Bound, Dhcp6Renewing and Dhcp6Rebinding, the IPv6 addresses are usable. + /// + EFI_DHCP6_IA_ADDRESS IaAddress[1]; +} EFI_DHCP6_IA; + +typedef struct { + /// + /// Pointer to the DHCPv6 unique identifier. The caller is responsible for freeing this buffer. + /// + EFI_DHCP6_DUID *ClientId; + /// + /// Pointer to the configured IA of current instance. The caller can free this buffer after + /// using it. + /// + EFI_DHCP6_IA *Ia; +} EFI_DHCP6_MODE_DATA; + +/** + EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol instance to + intercept events that occurs in the DHCPv6 S.A.R.R process. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance that is used to configure this + callback function. + @param[in] Context Pointer to the context that is initialized by EFI_DHCP6_PROTOCOL.Configure(). + @param[in] CurrentState The current state of the configured IA. + @param[in] Dhcp6Event The event that occurs in the current state, which usually means a state transition. + @param[in] Packet Pointer to the DHCPv6 packet that is about to be sent or has been received. + The EFI DHCPv6 Protocol instance is responsible for freeing the buffer. + @param[out] NewPacket Pointer to the new DHCPv6 packet to overwrite the Packet. NewPacket can not + share the buffer with Packet. If *NewPacket is not NULL, the EFI DHCPv6 + Protocol instance is responsible for freeing the buffer. + + @retval EFI_SUCCESS Tell the EFI DHCPv6 Protocol instance to continue the DHCPv6 S.A.R.R process. + @retval EFI_ABORTED Tell the EFI DHCPv6 Protocol instance to abort the DHCPv6 S.A.R.R process, + and the state of the configured IA will be transferred to Dhcp6Init. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_CALLBACK)( + IN EFI_DHCP6_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP6_STATE CurrentState, + IN EFI_DHCP6_EVENT Dhcp6Event, + IN EFI_DHCP6_PACKET *Packet, + OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL + ); + +typedef struct { + /// + /// The callback function is to intercept various events that occur in the DHCPv6 S.A.R.R + /// process. Set to NULL to ignore all those events. + /// + EFI_DHCP6_CALLBACK Dhcp6Callback; + /// + /// Pointer to the context that will be passed to Dhcp6Callback. + /// + VOID *CallbackContext; + /// + /// Number of the DHCPv6 options in the OptionList. + /// + UINT32 OptionCount; + /// + /// List of the DHCPv6 options to be included in Solicit and Request packet. The buffer + /// can be freed after EFI_DHCP6_PROTOCOL.Configure() returns. Ignored if + /// OptionCount is zero. OptionList should not contain Client Identifier option + /// and any IA option, which will be appended by EFI DHCPv6 Protocol instance + /// automatically. + /// + EFI_DHCP6_PACKET_OPTION **OptionList; + /// + /// The descriptor for the IA of the EFI DHCPv6 Protocol instance. + /// + EFI_DHCP6_IA_DESCRIPTOR IaDescriptor; + /// + /// If not NULL, the event will be signaled when any IPv6 address information of the + /// configured IA is updated, including IPv6 address, preferred lifetime and valid + /// lifetime, or the DHCPv6 S.A.R.R process fails. Otherwise, Start(), + /// renewrebind(), decline(), release() and stop() will be blocking + /// operations, and they will wait for the exchange process completion or failure. + /// + EFI_EVENT IaInfoEvent; + /// + /// If TRUE, the EFI DHCPv6 Protocol instance is willing to accept Reconfigure packet. + /// Otherwise, it will ignore it. Reconfigure Accept option can not be specified through + /// OptionList parameter. + /// + BOOLEAN ReconfigureAccept; + /// + /// If TRUE, the EFI DHCPv6 Protocol instance will send Solicit packet with Rapid + /// Commit option. Otherwise, Rapid Commit option will not be included in Solicit + /// packet. Rapid Commit option can not be specified through OptionList parameter. + /// + BOOLEAN RapidCommit; + /// + /// Parameter to control Solicit packet retransmission behavior. The + /// buffer can be freed after EFI_DHCP6_PROTOCOL.Configure() returns. + /// + EFI_DHCP6_RETRANSMISSION *SolicitRetransmission; +} EFI_DHCP6_CONFIG_DATA; + +/** + EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol + instance to intercept events that occurs in the DHCPv6 Information Request exchange process. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance that is used to configure this + callback function. + @param[in] Context Pointer to the context that is initialized in the EFI_DHCP6_PROTOCOL.InfoRequest(). + @param[in] Packet Pointer to Reply packet that has been received. The EFI DHCPv6 Protocol instance is + responsible for freeing the buffer. + + @retval EFI_SUCCESS Tell the EFI DHCPv6 Protocol instance to finish Information Request exchange process. + @retval EFI_NOT_READY Tell the EFI DHCPv6 Protocol instance to continue Information Request exchange process. + @retval EFI_ABORTED Tell the EFI DHCPv6 Protocol instance to abort the Information Request exchange process. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_INFO_CALLBACK)( + IN EFI_DHCP6_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP6_PACKET *Packet + ); + +/** + Retrieve the current operating mode data and configuration data for the EFI DHCPv6 Protocol instance. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance. + @param[out] Dhcp6ModeData Pointer to the DHCPv6 mode data structure. The caller is responsible for freeing this + structure and each reference buffer. + @param[out] Dhcp6ConfigData Pointer to the DHCPv6 configuration data structure. The caller is responsible for + freeing this structure and each reference buffer. + + @retval EFI_SUCCESS The mode data was returned. + @retval EFI_ACCESS_DENIED The EFI DHCPv6 Protocol instance has not been configured when Dhcp6ConfigData is not NULL. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + - This is NULL. + - Both Dhcp6ConfigData and Dhcp6ModeData are NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_GET_MODE_DATA)( + IN EFI_DHCP6_PROTOCOL *This, + OUT EFI_DHCP6_MODE_DATA *Dhcp6ModeData OPTIONAL, + OUT EFI_DHCP6_CONFIG_DATA *Dhcp6ConfigData OPTIONAL + ); + +/** + Initialize or clean up the configuration data for the EFI DHCPv6 Protocol instance. + + The Configure() function is used to initialize or clean up the configuration data of the EFI + DHCPv6 Protocol instance. + - When Dhcp6CfgData is not NULL and Configure() is called successfully, the + configuration data will be initialized in the EFI DHCPv6 Protocol instance and the state of the + configured IA will be transferred into Dhcp6Init. + - When Dhcp6CfgData is NULL and Configure() is called successfully, the configuration + data will be cleaned up and no IA will be associated with the EFI DHCPv6 Protocol instance. + + To update the configuration data for an EFI DCHPv6 Protocol instance, the original data must be + cleaned up before setting the new configuration data. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance. + @param[in] Dhcp6CfgData Pointer to the DHCPv6 configuration data structure. + + @retval EFI_SUCCESS The mode data was returned. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE + - This is NULL. + - OptionCount > 0 and OptionList is NULL. + - OptionList is not NULL, and Client Id option, Reconfigure Accept option, + Rapid Commit option or any IA option is specified in the OptionList. + - IaDescriptor.Type is neither EFI_DHCP6_IA_TYPE_NA nor EFI_DHCP6_IA_TYPE_NA. + - IaDescriptor is not unique. + - Both IaInfoEvent and SolicitRetransimssion are NULL. + - SolicitRetransmission is not NULL, and both SolicitRetransimssion->Mrc and + SolicitRetransmission->Mrd are zero. + @retval EFI_ACCESS_DENIED The EFI DHCPv6 Protocol instance has been already configured + when Dhcp6CfgData is not NULL. + The EFI DHCPv6 Protocol instance has already started the + DHCPv6 S.A.R.R when Dhcp6CfgData is NULL. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_CONFIGURE)( + IN EFI_DHCP6_PROTOCOL *This, + IN EFI_DHCP6_CONFIG_DATA *Dhcp6CfgData OPTIONAL + ); + +/** + Start the DHCPv6 S.A.R.R process. + + The Start() function starts the DHCPv6 S.A.R.R process. This function can be called only when + the state of the configured IA is in the Dhcp6Init state. If the DHCPv6 S.A.R.R process completes + successfully, the state of the configured IA will be transferred through Dhcp6Selecting and + Dhcp6Requesting to Dhcp6Bound state. The update of the IPv6 addresses will be notified through + EFI_DHCP6_CONFIG_DATA.IaInfoEvent. At the time when each event occurs in this process, the + callback function set by EFI_DHCP6_PROTOCOL.Configure() will be called and the user can take + this opportunity to control the process. If EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, the + Start() function call is a blocking operation. It will return after the DHCPv6 S.A.R.R process + completes or aborted by users. If the process is aborted by system or network error, the state of + the configured IA will be transferred to Dhcp6Init. The Start() function can be called again to + restart the process. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance. + + @retval EFI_SUCCESS The DHCPv6 S.A.R.R process is completed and at least one IPv6 + address has been bound to the configured IA when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL. + The DHCPv6 S.A.R.R process is started when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL. + @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ALREADY_STARTED The DHCPv6 S.A.R.R process has already started. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_NO_RESPONSE The DHCPv6 S.A.R.R process failed because of no response. + @retval EFI_NO_MAPPING No IPv6 address has been bound to the configured IA after the + DHCPv6 S.A.R.R process. + @retval EFI_ABORTED The DHCPv6 S.A.R.R process aborted by user. + @retval EFI_NO_MEDIA There was a media error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_START)( + IN EFI_DHCP6_PROTOCOL *This + ); + +/** + Request configuration information without the assignment of any IA addresses of the client. + + The InfoRequest() function is used to request configuration information without the assignment + of any IPv6 address of the client. Client sends out Information Request packet to obtain + the required configuration information, and DHCPv6 server responds with Reply packet containing + the information for the client. The received Reply packet will be passed to the user by + ReplyCallback function. If user returns EFI_NOT_READY from ReplyCallback, the EFI DHCPv6 + Protocol instance will continue to receive other Reply packets unless timeout according to + the Retransmission parameter. Otherwise, the Information Request exchange process will be + finished successfully if user returns EFI_SUCCESS from ReplyCallback. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance. + @param[in] SendClientId If TRUE, the EFI DHCPv6 Protocol instance will build Client + Identifier option and include it into Information Request + packet. If FALSE, Client Identifier option will not be included. + Client Identifier option can not be specified through OptionList + parameter. + @param[in] OptionRequest Pointer to the Option Request option in the Information Request + packet. Option Request option can not be specified through + OptionList parameter. + @param[in] OptionCount Number of options in OptionList. + @param[in] OptionList List of other DHCPv6 options. These options will be appended + to the Option Request option. The caller is responsible for + freeing this buffer. Type is defined in EFI_DHCP6_PROTOCOL.GetModeData(). + @param[in] Retransmission Parameter to control Information Request packet retransmission + behavior. The buffer can be freed after EFI_DHCP6_PROTOCOL.InfoRequest() + returns. + @param[in] TimeoutEvent If not NULL, this event is signaled when the information request + exchange aborted because of no response. If NULL, the function + call is a blocking operation; and it will return after the + information-request exchange process finish or aborted by users. + @param[in] ReplyCallback The callback function is to intercept various events that occur + in the Information Request exchange process. It should not be + set to NULL. + @param[in] CallbackContext Pointer to the context that will be passed to ReplyCallback. + + @retval EFI_SUCCESS The DHCPv6 S.A.R.R process is completed and at least one IPv6 + @retval EFI_SUCCESS The DHCPv6 information request exchange process completed + when TimeoutEvent is NULL. Information Request packet has been + sent to DHCPv6 server when TimeoutEvent is not NULL. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + - This is NULL. + - OptionRequest is NULL or OptionRequest->OpCode is invalid. + - OptionCount > 0 and OptionList is NULL. + - OptionList is not NULL, and Client Identify option or + Option Request option is specified in the OptionList. + - Retransimssion is NULL. + - Both Retransimssion->Mrc and Retransmission->Mrd are zero. + - ReplyCallback is NULL. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_NO_RESPONSE The DHCPv6 information request exchange process failed + because of no response, or not all requested-options are + responded by DHCPv6 servers when Timeout happened. + @retval EFI_ABORTED The DHCPv6 information request exchange process aborted by user. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_INFO_REQUEST)( + IN EFI_DHCP6_PROTOCOL *This, + IN BOOLEAN SendClientId, + IN EFI_DHCP6_PACKET_OPTION *OptionRequest, + IN UINT32 OptionCount, + IN EFI_DHCP6_PACKET_OPTION *OptionList[] OPTIONAL, + IN EFI_DHCP6_RETRANSMISSION *Retransmission, + IN EFI_EVENT TimeoutEvent OPTIONAL, + IN EFI_DHCP6_INFO_CALLBACK ReplyCallback, + IN VOID *CallbackContext OPTIONAL + ); + +/** + Manually extend the valid and preferred lifetimes for the IPv6 addresses of the configured + IA and update other configuration parameters by sending Renew or Rebind packet. + + The RenewRebind() function is used to manually extend the valid and preferred lifetimes for the + IPv6 addresses of the configured IA and update other configuration parameters by sending Renew or + Rebind packet. + - When RebindRequest is FALSE and the state of the configured IA is Dhcp6Bound, it + will send Renew packet to the previously DHCPv6 server and transfer the state of the configured + IA to Dhcp6Renewing. If valid Reply packet received, the state transfers to Dhcp6Bound + and the valid and preferred timer restarts. If fails, the state transfers to Dhcp6Bound but the + timer continues. + - When RebindRequest is TRUE and the state of the configured IA is Dhcp6Bound, it will + send Rebind packet. If valid Reply packet received, the state transfers to Dhcp6Bound and the + valid and preferred timer restarts. If fails, the state transfers to Dhcp6Init and the IA can't + be used. + + @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. + @param[in] RebindRequest If TRUE, it will send Rebind packet and enter the Dhcp6Rebinding state. + Otherwise, it will send Renew packet and enter the Dhcp6Renewing state. + + @retval EFI_SUCCESS The DHCPv6 renew/rebind exchange process has completed and at + least one IPv6 address of the configured IA has been bound again + when EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL. + The EFI DHCPv6 Protocol instance has sent Renew or Rebind packet + when EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL. + @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured, or the state + of the configured IA is not in Dhcp6Bound. + @retval EFI_ALREADY_STARTED The state of the configured IA has already entered Dhcp6Renewing + when RebindRequest is FALSE. + The state of the configured IA has already entered Dhcp6Rebinding + when RebindRequest is TRUE. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or system error occurred. + @retval EFI_NO_RESPONSE The DHCPv6 renew/rebind exchange process failed because of no response. + @retval EFI_NO_MAPPING No IPv6 address has been bound to the configured IA after the DHCPv6 + renew/rebind exchange process. + @retval EFI_ABORTED The DHCPv6 renew/rebind exchange process aborted by user. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_RENEW_REBIND)( + IN EFI_DHCP6_PROTOCOL *This, + IN BOOLEAN RebindRequest + ); + +/** + Inform that one or more IPv6 addresses assigned by a server are already in use by + another node. + + The Decline() function is used to manually decline the assignment of IPv6 addresses, which + have been already used by another node. If all IPv6 addresses of the configured IA are declined + through this function, the state of the IA will switch through Dhcp6Declining to Dhcp6Init, + otherwise, the state of the IA will restore to Dhcp6Bound after the declining process. The + Decline() can only be called when the IA is in Dhcp6Bound state. If the + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, this function is a blocking operation. It + will return after the declining process finishes, or aborted by user. + + @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance. + @param[in] AddressCount Number of declining IPv6 addresses. + @param[in] Addresses Pointer to the buffer stored all the declining IPv6 addresses. + + @retval EFI_SUCCESS The DHCPv6 decline exchange process has completed when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL. + The EFI DHCPv6 Protocol instance has sent Decline packet when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE + - This is NULL. + - AddressCount is zero or Addresses is NULL. + @retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with the configured IA + for this instance. + @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured, or the + state of the configured IA is not in Dhcp6Bound. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_ABORTED The DHCPv6 decline exchange process aborted by user. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_DECLINE)( + IN EFI_DHCP6_PROTOCOL *This, + IN UINT32 AddressCount, + IN EFI_IPv6_ADDRESS *Addresses + ); + +/** + Release one or more IPv6 addresses associated with the configured IA for current instance. + + The Release() function is used to manually release the one or more IPv6 address. If AddressCount + is zero, it will release all IPv6 addresses of the configured IA. If all IPv6 addresses of the IA + are released through this function, the state of the IA will switch through Dhcp6Releasing to + Dhcp6Init, otherwise, the state of the IA will restore to Dhcp6Bound after the releasing process. + The Release() can only be called when the IA is in Dhcp6Bound state. If the + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL, the function is a blocking operation. It will return + after the releasing process finishes, or aborted by user. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance. + @param[in] AddressCount Number of releasing IPv6 addresses. + @param[in] Addresses Pointer to the buffer stored all the releasing IPv6 addresses. + Ignored if AddressCount is zero. + @retval EFI_SUCCESS The DHCPv6 release exchange process has completed when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL. + The EFI DHCPv6 Protocol instance has sent Release packet when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE + - This is NULL. + - AddressCount is not zero or Addresses is NULL. + @retval EFI_NOT_FOUND Any specified IPv6 address is not correlated with the configured + IA for this instance. + @retval EFI_ACCESS_DENIED The EFI DHCPv6 Child instance hasn't been configured, or the + state of the configured IA is not in Dhcp6Bound. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + @retval EFI_ABORTED The DHCPv6 release exchange process aborted by user. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_RELEASE)( + IN EFI_DHCP6_PROTOCOL *This, + IN UINT32 AddressCount, + IN EFI_IPv6_ADDRESS *Addresses + ); + +/** + Stop the DHCPv6 S.A.R.R process. + + The Stop() function is used to stop the DHCPv6 S.A.R.R process. If this function is called + successfully, all the IPv6 addresses of the configured IA will be released and the state of + the configured IA will be transferred to Dhcp6Init. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance. + + @retval EFI_SUCCESS The DHCPv6 S.A.R.R process has been stopped when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is NULL. + The EFI DHCPv6 Protocol instance has sent Release packet if + need release or has been stopped if needn't, when + EFI_DHCP6_CONFIG_DATA.IaInfoEvent is not NULL. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_STOP)( + IN EFI_DHCP6_PROTOCOL *This + ); + +/** + Parse the option data in the DHCPv6 packet. + + The Parse() function is used to retrieve the option list in the DHCPv6 packet. + + @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance. + + @param[in] Packet Pointer to packet to be parsed. + @param[in] OptionCount On input, the number of entries in the PacketOptionList. + On output, the number of DHCPv6 options in the Packet. + @param[in] PacketOptionList List of pointers to the DHCPv6 options in the Packet. + The OpCode and OpLen in EFI_DHCP6_PACKET_OPTION are + both stored in network byte order. + @retval EFI_SUCCESS The packet was successfully parsed. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE + - This is NULL. + - Packet is NULL. + - Packet is not a well-formed DHCPv6 packet. + - OptionCount is NULL. + - *OptionCount is not zero and PacketOptionList is NULL. + @retval EFI_BUFFER_TOO_SMALL *OptionCount is smaller than the number of options that were + found in the Packet. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DHCP6_PARSE)( + IN EFI_DHCP6_PROTOCOL *This, + IN EFI_DHCP6_PACKET *Packet, + IN OUT UINT32 *OptionCount, + OUT EFI_DHCP6_PACKET_OPTION *PacketOptionList[] OPTIONAL + ); + +/// +/// The EFI DHCPv6 Protocol is used to get IPv6 addresses and other configuration parameters +/// from DHCPv6 servers. +/// +struct _EFI_DHCP6_PROTOCOL { + EFI_DHCP6_GET_MODE_DATA GetModeData; + EFI_DHCP6_CONFIGURE Configure; + EFI_DHCP6_START Start; + EFI_DHCP6_INFO_REQUEST InfoRequest; + EFI_DHCP6_RENEW_REBIND RenewRebind; + EFI_DHCP6_DECLINE Decline; + EFI_DHCP6_RELEASE Release; + EFI_DHCP6_STOP Stop; + EFI_DHCP6_PARSE Parse; +}; + +extern EFI_GUID gEfiDhcp6ProtocolGuid; +extern EFI_GUID gEfiDhcp6ServiceBindingProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/Protocol/Ip6.h b/src/include/ipxe/efi/Protocol/Ip6.h new file mode 100644 index 00000000..c70df190 --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Ip6.h @@ -0,0 +1,948 @@ +/** @file + This file defines the EFI IPv6 (Internet Protocol version 6) + Protocol interface. It is split into the following three main + sections: + - EFI IPv6 Service Binding Protocol + - EFI IPv6 Variable (deprecated in UEFI 2.4B) + - EFI IPv6 Protocol + The EFI IPv6 Protocol provides basic network IPv6 packet I/O services, + which includes support for Neighbor Discovery Protocol (ND), Multicast + Listener Discovery Protocol (MLD), and a subset of the Internet Control + Message Protocol (ICMPv6). + + Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.2 + +**/ + +#ifndef __EFI_IP6_PROTOCOL_H__ +#define __EFI_IP6_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#include + +#define EFI_IP6_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xec835dd3, 0xfe0f, 0x617b, {0xa6, 0x21, 0xb3, 0x50, 0xc3, 0xe1, 0x33, 0x88 } \ + } + +#define EFI_IP6_PROTOCOL_GUID \ + { \ + 0x2c8759d5, 0x5c2d, 0x66ef, {0x92, 0x5f, 0xb6, 0x6c, 0x10, 0x19, 0x57, 0xe2 } \ + } + +typedef struct _EFI_IP6_PROTOCOL EFI_IP6_PROTOCOL; + +/// +/// EFI_IP6_ADDRESS_PAIR is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + /// + /// The EFI IPv6 Protocol instance handle that is using this address/prefix pair. + /// + EFI_HANDLE InstanceHandle; + /// + /// IPv6 address in network byte order. + /// + EFI_IPv6_ADDRESS Ip6Address; + /// + /// The length of the prefix associated with the Ip6Address. + /// + UINT8 PrefixLength; +} EFI_IP6_ADDRESS_PAIR; + +/// +/// EFI_IP6_VARIABLE_DATA is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + /// + /// The handle of the driver that creates this entry. + /// + EFI_HANDLE DriverHandle; + /// + /// The number of IPv6 address pairs that follow this data structure. + /// + UINT32 AddressCount; + /// + /// List of IPv6 address pairs that are currently in use. + /// + EFI_IP6_ADDRESS_PAIR AddressPairs[1]; +} EFI_IP6_VARIABLE_DATA; + +/// +/// ICMPv6 type definitions for error messages +/// +///@{ +#define ICMP_V6_DEST_UNREACHABLE 0x1 +#define ICMP_V6_PACKET_TOO_BIG 0x2 +#define ICMP_V6_TIME_EXCEEDED 0x3 +#define ICMP_V6_PARAMETER_PROBLEM 0x4 +///@} + +/// +/// ICMPv6 type definition for informational messages +/// +///@{ +#define ICMP_V6_ECHO_REQUEST 0x80 +#define ICMP_V6_ECHO_REPLY 0x81 +#define ICMP_V6_LISTENER_QUERY 0x82 +#define ICMP_V6_LISTENER_REPORT 0x83 +#define ICMP_V6_LISTENER_DONE 0x84 +#define ICMP_V6_ROUTER_SOLICIT 0x85 +#define ICMP_V6_ROUTER_ADVERTISE 0x86 +#define ICMP_V6_NEIGHBOR_SOLICIT 0x87 +#define ICMP_V6_NEIGHBOR_ADVERTISE 0x88 +#define ICMP_V6_REDIRECT 0x89 +#define ICMP_V6_LISTENER_REPORT_2 0x8F +///@} + +/// +/// ICMPv6 code definitions for ICMP_V6_DEST_UNREACHABLE +/// +///@{ +#define ICMP_V6_NO_ROUTE_TO_DEST 0x0 +#define ICMP_V6_COMM_PROHIBITED 0x1 +#define ICMP_V6_BEYOND_SCOPE 0x2 +#define ICMP_V6_ADDR_UNREACHABLE 0x3 +#define ICMP_V6_PORT_UNREACHABLE 0x4 +#define ICMP_V6_SOURCE_ADDR_FAILED 0x5 +#define ICMP_V6_ROUTE_REJECTED 0x6 +///@} + +/// +/// ICMPv6 code definitions for ICMP_V6_TIME_EXCEEDED +/// +///@{ +#define ICMP_V6_TIMEOUT_HOP_LIMIT 0x0 +#define ICMP_V6_TIMEOUT_REASSEMBLE 0x1 +///@} + +/// +/// ICMPv6 code definitions for ICMP_V6_PARAMETER_PROBLEM +/// +///@{ +#define ICMP_V6_ERRONEOUS_HEADER 0x0 +#define ICMP_V6_UNRECOGNIZE_NEXT_HDR 0x1 +#define ICMP_V6_UNRECOGNIZE_OPTION 0x2 +///@} + +/// +/// EFI_IP6_CONFIG_DATA +/// is used to report and change IPv6 session parameters. +/// +typedef struct { + /// + /// For the IPv6 packet to send and receive, this is the default value + /// of the 'Next Header' field in the last IPv6 extension header or in + /// the IPv6 header if there are no extension headers. Ignored when + /// AcceptPromiscuous is TRUE. + /// + UINT8 DefaultProtocol; + /// + /// Set to TRUE to receive all IPv6 packets that get through the + /// receive filters. + /// Set to FALSE to receive only the DefaultProtocol IPv6 + /// packets that get through the receive filters. Ignored when + /// AcceptPromiscuous is TRUE. + /// + BOOLEAN AcceptAnyProtocol; + /// + /// Set to TRUE to receive ICMP error report packets. Ignored when + /// AcceptPromiscuous or AcceptAnyProtocol is TRUE. + /// + BOOLEAN AcceptIcmpErrors; + /// + /// Set to TRUE to receive all IPv6 packets that are sent to any + /// hardware address or any protocol address. Set to FALSE to stop + /// receiving all promiscuous IPv6 packets. + /// + BOOLEAN AcceptPromiscuous; + /// + /// The destination address of the packets that will be transmitted. + /// Ignored if it is unspecified. + /// + EFI_IPv6_ADDRESS DestinationAddress; + /// + /// The station IPv6 address that will be assigned to this EFI IPv6 + /// Protocol instance. This field can be set and changed only when + /// the EFI IPv6 driver is transitioning from the stopped to the started + /// states. If the StationAddress is specified, the EFI IPv6 Protocol + /// driver will deliver only incoming IPv6 packets whose destination + /// matches this IPv6 address exactly. The StationAddress is required + /// to be one of currently configured IPv6 addresses. An address + /// containing all zeroes is also accepted as a special case. Under this + /// situation, the IPv6 driver is responsible for binding a source + /// address to this EFI IPv6 protocol instance according to the source + /// address selection algorithm. Only incoming packets destined to + /// the selected address will be delivered to the user. And the + /// selected station address can be retrieved through later + /// GetModeData() call. If no address is available for selecting, + /// EFI_NO_MAPPING will be returned, and the station address will + /// only be successfully bound to this EFI IPv6 protocol instance + /// after IP6ModeData.IsConfigured changed to TRUE. + /// + EFI_IPv6_ADDRESS StationAddress; + /// + /// TrafficClass field in transmitted IPv6 packets. Default value + /// is zero. + /// + UINT8 TrafficClass; + /// + /// HopLimit field in transmitted IPv6 packets. + /// + UINT8 HopLimit; + /// + /// FlowLabel field in transmitted IPv6 packets. Default value is + /// zero. + /// + UINT32 FlowLabel; + /// + /// The timer timeout value (number of microseconds) for the + /// receive timeout event to be associated with each assembled + /// packet. Zero means do not drop assembled packets. + /// + UINT32 ReceiveTimeout; + /// + /// The timer timeout value (number of microseconds) for the + /// transmit timeout event to be associated with each outgoing + /// packet. Zero means do not drop outgoing packets. + /// + UINT32 TransmitTimeout; +} EFI_IP6_CONFIG_DATA; + +/// +/// EFI_IP6_ADDRESS_INFO +/// +typedef struct { + EFI_IPv6_ADDRESS Address; ///< The IPv6 address. + UINT8 PrefixLength; ///< The length of the prefix associated with the Address. +} EFI_IP6_ADDRESS_INFO; + +/// +/// EFI_IP6_ROUTE_TABLE +/// is the entry structure that is used in routing tables +/// +typedef struct { + /// + /// The IPv6 address of the gateway to be used as the next hop for + /// packets to this prefix. If the IPv6 address is all zeros, then the + /// prefix is on-link. + /// + EFI_IPv6_ADDRESS Gateway; + /// + /// The destination prefix to be routed. + /// + EFI_IPv6_ADDRESS Destination; + /// + /// The length of the prefix associated with the Destination. + /// + UINT8 PrefixLength; +} EFI_IP6_ROUTE_TABLE; + +/// +/// EFI_IP6_NEIGHBOR_STATE +/// +typedef enum { + /// + /// Address resolution is being performed on this entry. Specially, + /// Neighbor Solicitation has been sent to the solicited-node + /// multicast address of the target, but corresponding Neighbor + /// Advertisement has not been received. + /// + EfiNeighborInComplete, + /// + /// Positive confirmation was received that the forward path to the + /// neighbor was functioning properly. + /// + EfiNeighborReachable, + /// + /// Reachable Time has elapsed since the last positive confirmation + /// was received. In this state, the forward path to the neighbor was + /// functioning properly. + /// + EfiNeighborStale, + /// + /// This state is an optimization that gives upper-layer protocols + /// additional time to provide reachability confirmation. + /// + EfiNeighborDelay, + /// + /// A reachability confirmation is actively sought by retransmitting + /// Neighbor Solicitations every RetransTimer milliseconds until a + /// reachability confirmation is received. + /// + EfiNeighborProbe +} EFI_IP6_NEIGHBOR_STATE; + +/// +/// EFI_IP6_NEIGHBOR_CACHE +/// is the entry structure that is used in neighbor cache. It records a set +/// of entries about individual neighbors to which traffic has been sent recently. +/// +typedef struct { + EFI_IPv6_ADDRESS Neighbor; ///< The on-link unicast/anycast IP address of the neighbor. + EFI_MAC_ADDRESS LinkAddress; ///< Link-layer address of the neighbor. + EFI_IP6_NEIGHBOR_STATE State; ///< State of this neighbor cache entry. +} EFI_IP6_NEIGHBOR_CACHE; + +/// +/// EFI_IP6_ICMP_TYPE +/// is used to describe those ICMP messages that are supported by this EFI +/// IPv6 Protocol driver. +/// +typedef struct { + UINT8 Type; ///< The type of ICMP message. + UINT8 Code; ///< The code of the ICMP message. +} EFI_IP6_ICMP_TYPE; + +/// +/// EFI_IP6_MODE_DATA +/// +typedef struct { + /// + /// Set to TRUE after this EFI IPv6 Protocol instance is started. + /// All other fields in this structure are undefined until this field is TRUE. + /// Set to FALSE when the EFI IPv6 Protocol instance is stopped. + /// + BOOLEAN IsStarted; + /// + /// The maximum packet size, in bytes, of the packet which the upper layer driver could feed. + /// + UINT32 MaxPacketSize; + /// + /// Current configuration settings. Undefined until IsStarted is TRUE. + /// + EFI_IP6_CONFIG_DATA ConfigData; + /// + /// Set to TRUE when the EFI IPv6 Protocol instance is configured. + /// The instance is configured when it has a station address and + /// corresponding prefix length. + /// Set to FALSE when the EFI IPv6 Protocol instance is not configured. + /// + BOOLEAN IsConfigured; + /// + /// Number of configured IPv6 addresses on this interface. + /// + UINT32 AddressCount; + /// + /// List of currently configured IPv6 addresses and corresponding + /// prefix lengths assigned to this interface. It is caller's + /// responsibility to free this buffer. + /// + EFI_IP6_ADDRESS_INFO *AddressList; + /// + /// Number of joined multicast groups. Undefined until + /// IsConfigured is TRUE. + /// + UINT32 GroupCount; + /// + /// List of joined multicast group addresses. It is caller's + /// responsibility to free this buffer. Undefined until + /// IsConfigured is TRUE. + /// + EFI_IPv6_ADDRESS *GroupTable; + /// + /// Number of entries in the routing table. Undefined until + /// IsConfigured is TRUE. + /// + UINT32 RouteCount; + /// + /// Routing table entries. It is caller's responsibility to free this buffer. + /// + EFI_IP6_ROUTE_TABLE *RouteTable; + /// + /// Number of entries in the neighbor cache. Undefined until + /// IsConfigured is TRUE. + /// + UINT32 NeighborCount; + /// + /// Neighbor cache entries. It is caller's responsibility to free this + /// buffer. Undefined until IsConfigured is TRUE. + /// + EFI_IP6_NEIGHBOR_CACHE *NeighborCache; + /// + /// Number of entries in the prefix table. Undefined until + /// IsConfigured is TRUE. + /// + UINT32 PrefixCount; + /// + /// On-link Prefix table entries. It is caller's responsibility to free this + /// buffer. Undefined until IsConfigured is TRUE. + /// + EFI_IP6_ADDRESS_INFO *PrefixTable; + /// + /// Number of entries in the supported ICMP types list. + /// + UINT32 IcmpTypeCount; + /// + /// Array of ICMP types and codes that are supported by this EFI + /// IPv6 Protocol driver. It is caller's responsibility to free this + /// buffer. + /// + EFI_IP6_ICMP_TYPE *IcmpTypeList; +} EFI_IP6_MODE_DATA; + +/// +/// EFI_IP6_HEADER +/// The fields in the IPv6 header structure are defined in the Internet +/// Protocol version6 specification. +/// +#pragma pack(1) +typedef struct _EFI_IP6_HEADER { + UINT8 TrafficClassH : 4; + UINT8 Version : 4; + UINT8 FlowLabelH : 4; + UINT8 TrafficClassL : 4; + UINT16 FlowLabelL; + UINT16 PayloadLength; + UINT8 NextHeader; + UINT8 HopLimit; + EFI_IPv6_ADDRESS SourceAddress; + EFI_IPv6_ADDRESS DestinationAddress; +} EFI_IP6_HEADER; +#pragma pack() + +/// +/// EFI_IP6_FRAGMENT_DATA +/// describes the location and length of the IPv6 packet +/// fragment to transmit or that has been received. +/// +typedef struct _EFI_IP6_FRAGMENT_DATA { + UINT32 FragmentLength; ///< Length of fragment data. This field may not be set to zero. + VOID *FragmentBuffer; ///< Pointer to fragment data. This field may not be set to NULL. +} EFI_IP6_FRAGMENT_DATA; + +/// +/// EFI_IP6_RECEIVE_DATA +/// +typedef struct _EFI_IP6_RECEIVE_DATA { + /// + /// Time when the EFI IPv6 Protocol driver accepted the packet. + /// Ignored if it is zero. + /// + EFI_TIME TimeStamp; + /// + /// After this event is signaled, the receive data structure is released + /// and must not be referenced. + /// + EFI_EVENT RecycleSignal; + /// + /// Length of the IPv6 packet headers, including both the IPv6 + /// header and any extension headers. + /// + UINT32 HeaderLength; + /// + /// Pointer to the IPv6 packet header. If the IPv6 packet was + /// fragmented, this argument is a pointer to the header in the first + /// fragment. + /// + EFI_IP6_HEADER *Header; + /// + /// Sum of the lengths of IPv6 packet buffers in FragmentTable. May + /// be zero. + /// + UINT32 DataLength; + /// + /// Number of IPv6 payload fragments. May be zero. + /// + UINT32 FragmentCount; + /// + /// Array of payload fragment lengths and buffer pointers. + /// + EFI_IP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP6_RECEIVE_DATA; + +/// +/// EFI_IP6_OVERRIDE_DATA +/// The information and flags in the override data structure will override +/// default parameters or settings for one Transmit() function call. +/// +typedef struct _EFI_IP6_OVERRIDE_DATA { + UINT8 Protocol; ///< Protocol type override. + UINT8 HopLimit; ///< Hop-Limit override. + UINT32 FlowLabel; ///< Flow-Label override. +} EFI_IP6_OVERRIDE_DATA; + +/// +/// EFI_IP6_TRANSMIT_DATA +/// +typedef struct _EFI_IP6_TRANSMIT_DATA { + /// + /// The destination IPv6 address. If it is unspecified, + /// ConfigData.DestinationAddress will be used instead. + /// + EFI_IPv6_ADDRESS DestinationAddress; + /// + /// If not NULL, the IPv6 transmission control override data. + /// + EFI_IP6_OVERRIDE_DATA *OverrideData; + /// + /// Total length in byte of the IPv6 extension headers specified in + /// ExtHdrs. + /// + UINT32 ExtHdrsLength; + /// + /// Pointer to the IPv6 extension headers. The IP layer will append + /// the required extension headers if they are not specified by + /// ExtHdrs. Ignored if ExtHdrsLength is zero. + /// + VOID *ExtHdrs; + /// + /// The protocol of first extension header in ExtHdrs. Ignored if + /// ExtHdrsLength is zero. + /// + UINT8 NextHeader; + /// + /// Total length in bytes of the FragmentTable data to transmit. + /// + UINT32 DataLength; + /// + /// Number of entries in the fragment data table. + /// + UINT32 FragmentCount; + /// + /// Start of the fragment data table. + /// + EFI_IP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_IP6_TRANSMIT_DATA; + +/// +/// EFI_IP6_COMPLETION_TOKEN +/// structures are used for both transmit and receive operations. +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by + /// the EFI IPv6 Protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. + /// + EFI_EVENT Event; + /// + /// Will be set to one of the following values: + /// - EFI_SUCCESS: The receive or transmit completed + /// successfully. + /// - EFI_ABORTED: The receive or transmit was aborted + /// - EFI_TIMEOUT: The transmit timeout expired. + /// - EFI_ICMP_ERROR: An ICMP error packet was received. + /// - EFI_DEVICE_ERROR: An unexpected system or network + /// error occurred. + /// - EFI_SECURITY_VIOLATION: The transmit or receive was + /// failed because of an IPsec policy check. + /// - EFI_NO_MEDIA: There was a media error. + /// + EFI_STATUS Status; + union { + /// + /// When the Token is used for receiving, RxData is a pointer to the EFI_IP6_RECEIVE_DATA. + /// + EFI_IP6_RECEIVE_DATA *RxData; + /// + /// When the Token is used for transmitting, TxData is a pointer to the EFI_IP6_TRANSMIT_DATA. + /// + EFI_IP6_TRANSMIT_DATA *TxData; + } Packet; +} EFI_IP6_COMPLETION_TOKEN; + +/** + Gets the current operational settings for this instance of the EFI IPv6 Protocol driver. + + The GetModeData() function returns the current operational mode data for this driver instance. + The data fields in EFI_IP6_MODE_DATA are read only. This function is used optionally to + retrieve the operational mode data of underlying networks or drivers.. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[out] Ip6ModeData Pointer to the EFI IPv6 Protocol mode data structure. + @param[out] MnpConfigData Pointer to the managed network configuration data structure. + @param[out] SnpModeData Pointer to the simple network mode data structure. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_GET_MODE_DATA)( + IN EFI_IP6_PROTOCOL *This, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + Assigns an IPv6 address and subnet mask to this EFI IPv6 Protocol driver instance. + + The Configure() function is used to set, change, or reset the operational parameters and filter + settings for this EFI IPv6 Protocol instance. Until these parameters have been set, no network traffic + can be sent or received by this instance. Once the parameters have been reset (by calling this + function with Ip6ConfigData set to NULL), no more traffic can be sent or received until these + parameters have been set again. Each EFI IPv6 Protocol instance can be started and stopped + independently of each other by enabling or disabling their receive filter settings with the + Configure() function. + + If Ip6ConfigData.StationAddress is a valid non-zero IPv6 unicast address, it is required + to be one of the currently configured IPv6 addresses list in the EFI IPv6 drivers, or else + EFI_INVALID_PARAMETER will be returned. If Ip6ConfigData.StationAddress is + unspecified, the IPv6 driver will bind a source address according to the source address selection + algorithm. Clients could frequently call GetModeData() to check get currently configured IPv6 + address list in the EFI IPv6 driver. If both Ip6ConfigData.StationAddress and + Ip6ConfigData.Destination are unspecified, when transmitting the packet afterwards, the + source address filled in each outgoing IPv6 packet is decided based on the destination of this packet. . + + If operational parameters are reset or changed, any pending transmit and receive requests will be + cancelled. Their completion token status will be set to EFI_ABORTED and their events will be + signaled. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[in] Ip6ConfigData Pointer to the EFI IPv6 Protocol configuration data structure. + + @retval EFI_SUCCESS The driver instance was successfully opened. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Ip6ConfigData.StationAddress is neither zero nor + a unicast IPv6 address. + - Ip6ConfigData.StationAddress is neither zero nor + one of the configured IP addresses in the EFI IPv6 driver. + - Ip6ConfigData.DefaultProtocol is illegal. + @retval EFI_OUT_OF_RESOURCES The EFI IPv6 Protocol driver instance data could not be allocated. + @retval EFI_NO_MAPPING The IPv6 driver was responsible for choosing a source address for + this instance, but no source address was available for use. + @retval EFI_ALREADY_STARTED The interface is already open and must be stopped before the IPv6 + address or prefix length can be changed. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI IPv6 + Protocol driver instance is not opened. + @retval EFI_UNSUPPORTED Default protocol specified through + Ip6ConfigData.DefaulProtocol isn't supported. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIGURE)( + IN EFI_IP6_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA *Ip6ConfigData OPTIONAL + ); + +/** + Joins and leaves multicast groups. + + The Groups() function is used to join and leave multicast group sessions. Joining a group will + enable reception of matching multicast packets. Leaving a group will disable reception of matching + multicast packets. Source-Specific Multicast isn't required to be supported. + + If JoinFlag is FALSE and GroupAddress is NULL, all joined groups will be left. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[in] JoinFlag Set to TRUE to join the multicast group session and FALSE to leave. + @param[in] GroupAddress Pointer to the IPv6 multicast address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following is TRUE: + - This is NULL. + - JoinFlag is TRUE and GroupAddress is NULL. + - GroupAddress is not NULL and *GroupAddress is + not a multicast IPv6 address. + - GroupAddress is not NULL and *GroupAddress is in the + range of SSM destination address. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_OUT_OF_RESOURCES System resources could not be allocated. + @retval EFI_UNSUPPORTED This EFI IPv6 Protocol implementation does not support multicast groups. + @retval EFI_ALREADY_STARTED The group address is already in the group table (when + JoinFlag is TRUE). + @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_GROUPS)( + IN EFI_IP6_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv6_ADDRESS *GroupAddress OPTIONAL + ); + +/** + Adds and deletes routing table entries. + + The Routes() function adds a route to or deletes a route from the routing table. + + Routes are determined by comparing the leftmost PrefixLength bits of Destination with + the destination IPv6 address arithmetically. The gateway address must be on the same subnet as the + configured station address. + + The default route is added with Destination and PrefixLegth both set to all zeros. The + default route matches all destination IPv6 addresses that do not match any other routes. + + All EFI IPv6 Protocol instances share a routing table. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[in] DeleteRoute Set to TRUE to delete this route from the routing table. Set to + FALSE to add this route to the routing table. Destination, + PrefixLength and Gateway are used as the key to each + route entry. + @param[in] Destination The address prefix of the subnet that needs to be routed. + @param[in] PrefixLength The prefix length of Destination. Ignored if Destination + is NULL. + @param[in] GatewayAddress The unicast gateway IPv6 address for this route. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The driver instance has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - When DeleteRoute is TRUE, both Destination and + GatewayAddress are NULL. + - When DeleteRoute is FALSE, either Destination or + GatewayAddress is NULL. + - *GatewayAddress is not a valid unicast IPv6 address. + - *GatewayAddress is one of the local configured IPv6 + addresses. + @retval EFI_OUT_OF_RESOURCES Could not add the entry to the routing table. + @retval EFI_NOT_FOUND This route is not in the routing table (when DeleteRoute is TRUE). + @retval EFI_ACCESS_DENIED The route is already defined in the routing table (when + DeleteRoute is FALSE). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_ROUTES)( + IN EFI_IP6_PROTOCOL *This, + IN BOOLEAN DeleteRoute, + IN EFI_IPv6_ADDRESS *Destination OPTIONAL, + IN UINT8 PrefixLength, + IN EFI_IPv6_ADDRESS *GatewayAddress OPTIONAL + ); + +/** + Add or delete Neighbor cache entries. + + The Neighbors() function is used to add, update, or delete an entry from neighbor cache. + IPv6 neighbor cache entries are typically inserted and updated by the network protocol driver as + network traffic is processed. Most neighbor cache entries will time out and be deleted if the network + traffic stops. Neighbor cache entries that were inserted by Neighbors() may be static (will not + timeout) or dynamic (will time out). + + The implementation should follow the neighbor cache timeout mechanism which is defined in + RFC4861. The default neighbor cache timeout value should be tuned for the expected network + environment + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[in] DeleteFlag Set to TRUE to delete the specified cache entry, set to FALSE to + add (or update, if it already exists and Override is TRUE) the + specified cache entry. TargetIp6Address is used as the key + to find the requested cache entry. + @param[in] TargetIp6Address Pointer to Target IPv6 address. + @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL. + @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor + cache, it will be deleted after Timeout. A value of zero means that + the entry is permanent. A non-zero value means that the entry is + dynamic. + @param[in] Override If TRUE, the cached link-layer address of the matching entry will + be overridden and updated; if FALSE, EFI_ACCESS_DENIED + will be returned if a corresponding cache entry already existed. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - TargetIpAddress is NULL. + - *TargetLinkAddress is invalid when not NULL. + - *TargetIpAddress is not a valid unicast IPv6 address. + - *TargetIpAddress is one of the local configured IPv6 + addresses. + @retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache. + @retval EFI_NOT_FOUND This entry is not in the neighbor cache (when DeleteFlag is + TRUE or when DeleteFlag is FALSE while + TargetLinkAddress is NULL.). + @retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache, + and that entry is tagged as un-overridden (when DeleteFlag + is FALSE). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_NEIGHBORS)( + IN EFI_IP6_PROTOCOL *This, + IN BOOLEAN DeleteFlag, + IN EFI_IPv6_ADDRESS *TargetIp6Address, + IN EFI_MAC_ADDRESS *TargetLinkAddress, + IN UINT32 Timeout, + IN BOOLEAN Override + ); + +/** + Places outgoing data packets into the transmit queue. + + The Transmit() function places a sending request in the transmit queue of this + EFI IPv6 Protocol instance. Whenever the packet in the token is sent out or some + errors occur, the event in the token will be signaled and the status is updated. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[in] Token Pointer to the transmit token. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NO_MAPPING The IPv6 driver was responsible for choosing a source address for + this transmission, but no source address was available for use. + @retval EFI_INVALID_PARAMETER One or more of the following is TRUE: + - This is NULL. + - Token is NULL. + - Token.Event is NULL. + - Token.Packet.TxData is NULL. + - Token.Packet.ExtHdrsLength is not zero and Token.Packet.ExtHdrs is NULL. + - Token.Packet.FragmentCount is zero. + - One or more of the Token.Packet.TxData.FragmentTable[].FragmentLength fields is zero. + - One or more of the Token.Packet.TxData.FragmentTable[].FragmentBuffer fields is NULL. + - Token.Packet.TxData.DataLength is zero or not equal to the sum of fragment lengths. + - Token.Packet.TxData.DestinationAddress is non-zero when DestinationAddress is configured as + non-zero when doing Configure() for this EFI IPv6 protocol instance. + - Token.Packet.TxData.DestinationAddress is unspecified when DestinationAddress is unspecified + when doing Configure() for this EFI IPv6 protocol instance. + @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event + was already in the transmit queue. + @retval EFI_NOT_READY The completion token could not be queued because the transmit + queue is full. + @retval EFI_NOT_FOUND Not route is found to destination address. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data. + @retval EFI_BUFFER_TOO_SMALL Token.Packet.TxData.TotalDataLength is too + short to transmit. + @retval EFI_BAD_BUFFER_SIZE If Token.Packet.TxData.DataLength is beyond the + maximum that which can be described through the Fragment Offset + field in Fragment header when performing fragmentation. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_TRANSMIT)( + IN EFI_IP6_PROTOCOL *This, + IN EFI_IP6_COMPLETION_TOKEN *Token + ); + +/** + Places a receiving request into the receiving queue. + + The Receive() function places a completion token into the receive packet queue. + This function is always asynchronous. + + The Token.Event field in the completion token must be filled in by the caller + and cannot be NULL. When the receive operation completes, the EFI IPv6 Protocol + driver updates the Token.Status and Token.Packet.RxData fields and the Token.Event + is signaled. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[in] Token Pointer to a token that is associated with the receive data descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI IPv6 Protocol instance has not been started. + @retval EFI_NO_MAPPING When IP6 driver responsible for binding source address to this instance, + while no source address is available for use. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Token is NULL. + - Token.Event is NULL. + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system + resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + The EFI IPv6 Protocol instance has been reset to startup defaults. + @retval EFI_ACCESS_DENIED The receive completion token with the same Token.Event was already + in the receive queue. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_RECEIVE)( + IN EFI_IP6_PROTOCOL *This, + IN EFI_IP6_COMPLETION_TOKEN *Token + ); + +/** + Abort an asynchronous transmit or receive request. + + The Cancel() function is used to abort a pending transmit or receive request. + If the token is in the transmit or receive request queues, after calling this + function, Token->Status will be set to EFI_ABORTED and then Token->Event will + be signaled. If the token is not in one of the queues, which usually means the + asynchronous operation has completed, this function will not signal the token + and EFI_NOT_FOUND is returned. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_IP6_PROTOCOL.Transmit() or + EFI_IP6_PROTOCOL.Receive(). If NULL, all pending + tokens are aborted. Type EFI_IP6_COMPLETION_TOKEN is + defined in EFI_IP6_PROTOCOL.Transmit(). + + @retval EFI_SUCCESS The asynchronous I/O request was aborted and + Token->Event was signaled. When Token is NULL, all + pending requests were aborted and their events were signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was + not found in the transmit or receive queue. It has either completed + or was not issued by Transmit() and Receive(). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CANCEL)( + IN EFI_IP6_PROTOCOL *This, + IN EFI_IP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function polls for incoming data packets and processes outgoing data + packets. Network drivers and applications can call the EFI_IP6_PROTOCOL.Poll() + function to increase the rate that data packets are moved between the communications + device and the transmit and receive queues. + + In some systems the periodic timer event may not poll the underlying communications + device fast enough to transmit and/or receive all data packets without missing + incoming packets or dropping outgoing packets. Drivers and applications that are + experiencing packet loss should try calling the EFI_IP6_PROTOCOL.Poll() function + more often. + + @param[in] This Pointer to the EFI_IP6_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI IPv6 Protocol instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_POLL)( + IN EFI_IP6_PROTOCOL *This + ); + +/// +/// The EFI IPv6 Protocol implements a simple packet-oriented interface that can be +/// used by drivers, daemons, and applications to transmit and receive network packets. +/// +struct _EFI_IP6_PROTOCOL { + EFI_IP6_GET_MODE_DATA GetModeData; + EFI_IP6_CONFIGURE Configure; + EFI_IP6_GROUPS Groups; + EFI_IP6_ROUTES Routes; + EFI_IP6_NEIGHBORS Neighbors; + EFI_IP6_TRANSMIT Transmit; + EFI_IP6_RECEIVE Receive; + EFI_IP6_CANCEL Cancel; + EFI_IP6_POLL Poll; +}; + +extern EFI_GUID gEfiIp6ServiceBindingProtocolGuid; +extern EFI_GUID gEfiIp6ProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/Protocol/Ip6Config.h b/src/include/ipxe/efi/Protocol/Ip6Config.h new file mode 100644 index 00000000..5665e93b --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Ip6Config.h @@ -0,0 +1,369 @@ +/** @file + This file provides a definition of the EFI IPv6 Configuration + Protocol. + +Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __EFI_IP6CONFIG_PROTOCOL_H__ +#define __EFI_IP6CONFIG_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#include + +#define EFI_IP6_CONFIG_PROTOCOL_GUID \ + { \ + 0x937fe521, 0x95ae, 0x4d1a, {0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \ + } + +typedef struct _EFI_IP6_CONFIG_PROTOCOL EFI_IP6_CONFIG_PROTOCOL; + +/// +/// EFI_IP6_CONFIG_DATA_TYPE +/// +typedef enum { + /// + /// The interface information of the communication + /// device this EFI IPv6 Configuration Protocol instance manages. + /// This type of data is read only.The corresponding Data is of type + /// EFI_IP6_CONFIG_INTERFACE_INFO. + /// + Ip6ConfigDataTypeInterfaceInfo, + /// + /// The alternative interface ID for the + /// communication device this EFI IPv6 Configuration Protocol + /// instance manages if the link local IPv6 address generated from + /// the interfaced ID based on the default source the EFI IPv6 + /// Protocol uses is a duplicate address. The length of the interface + /// ID is 64 bit. The corresponding Data is of type + /// EFI_IP6_CONFIG_INTERFACE_ID. + /// + Ip6ConfigDataTypeAltInterfaceId, + /// + /// The general configuration policy for the EFI IPv6 network + /// stack running on the communication device this EFI IPv6 + /// Configuration Protocol instance manages. The policy will affect + /// other configuration settings. The corresponding Data is of type + /// EFI_IP6_CONFIG_POLICY. + /// + Ip6ConfigDataTypePolicy, + /// + /// The number of consecutive + /// Neighbor Solicitation messages sent while performing Duplicate + /// Address Detection on a tentative address. A value of zero + /// indicates that Duplicate Address Detection will not be performed + /// on tentative addresses. The corresponding Data is of type + /// EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS. + /// + Ip6ConfigDataTypeDupAddrDetectTransmits, + /// + /// The station addresses set manually for the EFI + /// IPv6 network stack. It is only configurable when the policy is + /// Ip6ConfigPolicyManual. The corresponding Data is a + /// pointer to an array of EFI_IPv6_ADDRESS instances. When + /// DataSize is 0 and Data is NULL, the existing configuration + /// is cleared from the EFI IPv6 Configuration Protocol instance. + /// + Ip6ConfigDataTypeManualAddress, + /// + /// The gateway addresses set manually for the EFI IPv6 + /// network stack running on the communication device this EFI + /// IPv6 Configuration Protocol manages. It is not configurable when + /// the policy is Ip6ConfigPolicyAutomatic. The gateway + /// addresses must be unicast IPv6 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv6_ADDRESS instances. + /// When DataSize is 0 and Data is NULL, the existing configuration + /// is cleared from the EFI IPv6 Configuration Protocol instance. + /// + Ip6ConfigDataTypeGateway, + /// + /// The DNS server list for the EFI IPv6 network stack + /// running on the communication device this EFI IPv6 + /// Configuration Protocol manages. It is not configurable when the + /// policy is Ip6ConfigPolicyAutomatic.The DNS server + /// addresses must be unicast IPv6 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv6_ADDRESS instances. + /// When DataSize is 0 and Data is NULL, the existing configuration + /// is cleared from the EFI IPv6 Configuration Protocol instance. + /// + Ip6ConfigDataTypeDnsServer, + /// + /// The number of this enumeration memebers. + /// + Ip6ConfigDataTypeMaximum +} EFI_IP6_CONFIG_DATA_TYPE; + +/// +/// EFI_IP6_CONFIG_INTERFACE_INFO +/// describes the operational state of the interface this +/// EFI IPv6 Configuration Protocol instance manages. +/// +typedef struct { + /// + /// The name of the interface. It is a NULL-terminated string. + /// + CHAR16 Name[32]; + /// + /// The interface type of the network interface. + /// + UINT8 IfType; + /// + /// The size, in bytes, of the network interface's hardware address. + /// + UINT32 HwAddressSize; + /// + /// The hardware address for the network interface. + /// + EFI_MAC_ADDRESS HwAddress; + /// + /// Number of EFI_IP6_ADDRESS_INFO structures pointed to by AddressInfo. + /// + UINT32 AddressInfoCount; + /// + /// Pointer to an array of EFI_IP6_ADDRESS_INFO instances + /// which contain the local IPv6 addresses and the corresponding + /// prefix length information. Set to NULL if AddressInfoCount + /// is zero. + /// + EFI_IP6_ADDRESS_INFO *AddressInfo; + /// + /// Number of route table entries in the following RouteTable. + /// + UINT32 RouteCount; + /// + /// The route table of the IPv6 network stack runs on this interface. + /// Set to NULL if RouteCount is zero. + /// + EFI_IP6_ROUTE_TABLE *RouteTable; +} EFI_IP6_CONFIG_INTERFACE_INFO; + +/// +/// EFI_IP6_CONFIG_INTERFACE_ID +/// describes the 64-bit interface ID. +/// +typedef struct { + UINT8 Id[8]; +} EFI_IP6_CONFIG_INTERFACE_ID; + +/// +/// EFI_IP6_CONFIG_POLICY +/// defines the general configuration policy the EFI IPv6 +/// Configuration Protocol supports. +/// +typedef enum { + /// + /// Under this policy, the IpI6ConfigDataTypeManualAddress, + /// Ip6ConfigDataTypeGateway and Ip6ConfigDataTypeDnsServer + /// configuration data are required to be set manually. + /// The EFI IPv6 Protocol will get all required configuration + /// such as address, prefix and gateway settings from the EFI + /// IPv6 Configuration protocol. + /// + Ip6ConfigPolicyManual, + /// + /// Under this policy, the IpI6ConfigDataTypeManualAddress, + /// Ip6ConfigDataTypeGateway and Ip6ConfigDataTypeDnsServer + /// configuration data are not allowed to set via SetData(). + /// All of these configurations are retrieved from some auto + /// configuration mechanism. + /// The EFI IPv6 Protocol will use the IPv6 stateless address + /// autoconfiguration mechanism and/or the IPv6 stateful address + /// autoconfiguration mechanism described in the related RFCs to + /// get address and other configuration information + /// + Ip6ConfigPolicyAutomatic +} EFI_IP6_CONFIG_POLICY; + +/// +/// EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS +/// describes the number of consecutive Neighbor Solicitation messages sent +/// while performing Duplicate Address Detection on a tentative address. +/// The default value for a newly detected communication device is 1. +/// +typedef struct { + UINT32 DupAddrDetectTransmits; ///< The number of consecutive Neighbor Solicitation messages sent. +} EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS; + +/// +/// EFI_IP6_CONFIG_MANUAL_ADDRESS +/// is used to set the station address information for the EFI IPv6 network +/// stack manually when the policy is Ip6ConfigPolicyManual. +/// +typedef struct { + EFI_IPv6_ADDRESS Address; ///< The IPv6 unicast address. + BOOLEAN IsAnycast; ///< Set to TRUE if Address is anycast. + UINT8 PrefixLength; ///< The length, in bits, of the prefix associated with this Address. +} EFI_IP6_CONFIG_MANUAL_ADDRESS; + +/** + Set the configuration for the EFI IPv6 network stack running on the communication + device this EFI IPv6 Configuration Protocol instance manages. + + This function is used to set the configuration data of type DataType for the EFI + IPv6 network stack running on the communication device this EFI IPv6 Configuration + Protocol instance manages. + + The DataSize is used to calculate the count of structure instances in the Data for + some DataType that multiple structure instances are allowed. + + This function is always non-blocking. When setting some type of configuration data, + an asynchronous process is invoked to check the correctness of the data, such as + doing Duplicate Address Detection on the manually set local IPv6 addresses. + EFI_NOT_READY is returned immediately to indicate that such an asynchronous process + is invoked and the process is not finished yet. The caller willing to get the result + of the asynchronous process is required to call RegisterDataNotify() to register an + event on the specified configuration data. Once the event is signaled, the caller + can call GetData() to get back the configuration data in order to know the result. + For other types of configuration data that do not require an asynchronous configuration + process, the result of the operation is immediately returned. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to set. + @param[in] DataSize Size of the buffer pointed to by Data in bytes. + @param[in] Data The data buffer to set. The type of the data buffer is + associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data for the EFI IPv6 + network stack is set successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - One or more fields in Data and DataSize do not match the + requirement of the data type indicated by DataType. + @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified + configuration data can not be set under the current policy + @retval EFI_ACCESS_DENIED Another set operation on the specified configuration + data is already in process. + @retval EFI_NOT_READY An asynchronous process is invoked to set the specified + configuration data and the process is not finished yet. + @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type + indicated by DataType. + @retval EFI_UNSUPPORTED This DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_SET_DATA)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Get the configuration data for the EFI IPv6 network stack running on the communication + device this EFI IPv6 Configuration Protocol instance manages. + + This function returns the configuration data of type DataType for the EFI IPv6 network + stack running on the communication device this EFI IPv6 Configuration Protocol instance + manages. + + The caller is responsible for allocating the buffer used to return the specified + configuration data and the required size will be returned to the caller if the size of + the buffer is too small. + + EFI_NOT_READY is returned if the specified configuration data is not ready due to an + already in progress asynchronous configuration process. The caller can call RegisterDataNotify() + to register an event on the specified configuration data. Once the asynchronous configuration + process is finished, the event will be signaled and a subsequent GetData() call will return + the specified configuration data. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to get. + @param[in,out] DataSize On input, in bytes, the size of Data. On output, in bytes, the + size of buffer required to store the specified configuration data. + @param[in] Data The data buffer in which the configuration data is returned. The + type of the data buffer is associated with the DataType. + + @retval EFI_SUCCESS The specified configuration data is got successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + - This is NULL. + - DataSize is NULL. + - Data is NULL if *DataSize is not zero. + @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data + and the required size is returned in DataSize. + @retval EFI_NOT_READY The specified configuration data is not ready due to an already in + progress asynchronous configuration process. + @retval EFI_NOT_FOUND The specified configuration data is not found. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_GET_DATA)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN OUT UINTN *DataSize, + IN VOID *Data OPTIONAL + ); + +/** + Register an event that is to be signaled whenever a configuration process on the specified + configuration data is done. + + This function registers an event that is to be signaled whenever a configuration process + on the specified configuration data is done. An event can be registered for different DataType + simultaneously and the caller is responsible for determining which type of configuration data + causes the signaling of the event in such case. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to unregister the event for. + @param[in] Event The event to register. + + @retval EFI_SUCCESS The notification event for the specified configuration data is + registered. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not + supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_REGISTER_NOTIFY)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/** + Remove a previously registered event for the specified configuration data. + + This function removes a previously registered event for the specified configuration data. + + @param[in] This Pointer to the EFI_IP6_CONFIG_PROTOCOL instance. + @param[in] DataType The type of data to remove the previously registered event for. + @param[in] Event The event to unregister. + + @retval EFI_SUCCESS The event registered for the specified configuration data is removed. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_NOT_FOUND The Event has not been registered for the specified + DataType. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP6_CONFIG_UNREGISTER_NOTIFY)( + IN EFI_IP6_CONFIG_PROTOCOL *This, + IN EFI_IP6_CONFIG_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/// +/// The EFI_IP6_CONFIG_PROTOCOL provides the mechanism to set and get various +/// types of configurations for the EFI IPv6 network stack. +/// +struct _EFI_IP6_CONFIG_PROTOCOL { + EFI_IP6_CONFIG_SET_DATA SetData; + EFI_IP6_CONFIG_GET_DATA GetData; + EFI_IP6_CONFIG_REGISTER_NOTIFY RegisterDataNotify; + EFI_IP6_CONFIG_UNREGISTER_NOTIFY UnregisterDataNotify; +}; + +extern EFI_GUID gEfiIp6ConfigProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/Protocol/Mtftp6.h b/src/include/ipxe/efi/Protocol/Mtftp6.h new file mode 100644 index 00000000..b08af87e --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Mtftp6.h @@ -0,0 +1,820 @@ +/** @file + UEFI Multicast Trivial File Transfer Protocol v6 Definition, which is built upon + the EFI UDPv6 Protocol and provides basic services for client-side unicast and/or + multicast TFTP operations. + + Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.
+ (C) Copyright 2016 Hewlett Packard Enterprise Development LP
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.2 + +**/ + +#ifndef __EFI_MTFTP6_PROTOCOL_H__ +#define __EFI_MTFTP6_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#define EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xd9760ff3, 0x3cca, 0x4267, {0x80, 0xf9, 0x75, 0x27, 0xfa, 0xfa, 0x42, 0x23 } \ + } + +#define EFI_MTFTP6_PROTOCOL_GUID \ + { \ + 0xbf0a78ba, 0xec29, 0x49cf, {0xa1, 0xc9, 0x7a, 0xe5, 0x4e, 0xab, 0x6a, 0x51 } \ + } + +typedef struct _EFI_MTFTP6_PROTOCOL EFI_MTFTP6_PROTOCOL; +typedef struct _EFI_MTFTP6_TOKEN EFI_MTFTP6_TOKEN; + +/// +/// MTFTP Packet OpCodes +///@{ +#define EFI_MTFTP6_OPCODE_RRQ 1 ///< The MTFTPv6 packet is a read request. +#define EFI_MTFTP6_OPCODE_WRQ 2 ///< The MTFTPv6 packet is a write request. +#define EFI_MTFTP6_OPCODE_DATA 3 ///< The MTFTPv6 packet is a data packet. +#define EFI_MTFTP6_OPCODE_ACK 4 ///< The MTFTPv6 packet is an acknowledgement packet. +#define EFI_MTFTP6_OPCODE_ERROR 5 ///< The MTFTPv6 packet is an error packet. +#define EFI_MTFTP6_OPCODE_OACK 6 ///< The MTFTPv6 packet is an option acknowledgement packet. +#define EFI_MTFTP6_OPCODE_DIR 7 ///< The MTFTPv6 packet is a directory query packet. +#define EFI_MTFTP6_OPCODE_DATA8 8 ///< The MTFTPv6 packet is a data packet with a big block number. +#define EFI_MTFTP6_OPCODE_ACK8 9 ///< The MTFTPv6 packet is an acknowledgement packet with a big block number. +///@} + +/// +/// MTFTP ERROR Packet ErrorCodes +///@{ +/// +/// The error code is not defined. See the error message in the packet (if any) for details. +/// +#define EFI_MTFTP6_ERRORCODE_NOT_DEFINED 0 +/// +/// The file was not found. +/// +#define EFI_MTFTP6_ERRORCODE_FILE_NOT_FOUND 1 +/// +/// There was an access violation. +/// +#define EFI_MTFTP6_ERRORCODE_ACCESS_VIOLATION 2 +/// +/// The disk was full or its allocation was exceeded. +/// +#define EFI_MTFTP6_ERRORCODE_DISK_FULL 3 +/// +/// The MTFTPv6 operation was illegal. +/// +#define EFI_MTFTP6_ERRORCODE_ILLEGAL_OPERATION 4 +/// +/// The transfer ID is unknown. +/// +#define EFI_MTFTP6_ERRORCODE_UNKNOWN_TRANSFER_ID 5 +/// +/// The file already exists. +/// +#define EFI_MTFTP6_ERRORCODE_FILE_ALREADY_EXISTS 6 +/// +/// There is no such user. +/// +#define EFI_MTFTP6_ERRORCODE_NO_SUCH_USER 7 +/// +/// The request has been denied due to option negotiation. +/// +#define EFI_MTFTP6_ERRORCODE_REQUEST_DENIED 8 +///@} + +#pragma pack(1) + +/// +/// EFI_MTFTP6_REQ_HEADER +/// +typedef struct { + /// + /// For this packet type, OpCode = EFI_MTFTP6_OPCODE_RRQ for a read request + /// or OpCode = EFI_MTFTP6_OPCODE_WRQ for a write request. + /// + UINT16 OpCode; + /// + /// The file name to be downloaded or uploaded. + /// + UINT8 Filename[1]; +} EFI_MTFTP6_REQ_HEADER; + +/// +/// EFI_MTFTP6_OACK_HEADER +/// +typedef struct { + /// + /// For this packet type, OpCode = EFI_MTFTP6_OPCODE_OACK. + /// + UINT16 OpCode; + /// + /// The option strings in the option acknowledgement packet. + /// + UINT8 Data[1]; +} EFI_MTFTP6_OACK_HEADER; + +/// +/// EFI_MTFTP6_DATA_HEADER +/// +typedef struct { + /// + /// For this packet type, OpCode = EFI_MTFTP6_OPCODE_DATA. + /// + UINT16 OpCode; + /// + /// Block number of this data packet. + /// + UINT16 Block; + /// + /// The content of this data packet. + /// + UINT8 Data[1]; +} EFI_MTFTP6_DATA_HEADER; + +/// +/// EFI_MTFTP6_ACK_HEADER +/// +typedef struct { + /// + /// For this packet type, OpCode = EFI_MTFTP6_OPCODE_ACK. + /// + UINT16 OpCode; + /// + /// The block number of the data packet that is being acknowledged. + /// + UINT16 Block[1]; +} EFI_MTFTP6_ACK_HEADER; + +/// +/// EFI_MTFTP6_DATA8_HEADER +/// +typedef struct { + /// + /// For this packet type, OpCode = EFI_MTFTP6_OPCODE_DATA8. + /// + UINT16 OpCode; + /// + /// The block number of data packet. + /// + UINT64 Block; + /// + /// The content of this data packet. + /// + UINT8 Data[1]; +} EFI_MTFTP6_DATA8_HEADER; + +/// +/// EFI_MTFTP6_ACK8_HEADER +/// +typedef struct { + /// + /// For this packet type, OpCode = EFI_MTFTP6_OPCODE_ACK8. + /// + UINT16 OpCode; + /// + /// The block number of the data packet that is being acknowledged. + /// + UINT64 Block[1]; +} EFI_MTFTP6_ACK8_HEADER; + +/// +/// EFI_MTFTP6_ERROR_HEADER +/// +typedef struct { + /// + /// For this packet type, OpCode = EFI_MTFTP6_OPCODE_ERROR. + /// + UINT16 OpCode; + /// + /// The error number as defined by the MTFTPv6 packet error codes. + /// + UINT16 ErrorCode; + /// + /// Error message string. + /// + UINT8 ErrorMessage[1]; +} EFI_MTFTP6_ERROR_HEADER; + +/// +/// EFI_MTFTP6_PACKET +/// +typedef union { + UINT16 OpCode; ///< Type of packets as defined by the MTFTPv6 packet opcodes. + EFI_MTFTP6_REQ_HEADER Rrq; ///< Read request packet header. + EFI_MTFTP6_REQ_HEADER Wrq; ///< write request packet header. + EFI_MTFTP6_OACK_HEADER Oack; ///< Option acknowledge packet header. + EFI_MTFTP6_DATA_HEADER Data; ///< Data packet header. + EFI_MTFTP6_ACK_HEADER Ack; ///< Acknowledgement packet header. + EFI_MTFTP6_DATA8_HEADER Data8; ///< Data packet header with big block number. + EFI_MTFTP6_ACK8_HEADER Ack8; ///< Acknowledgement header with big block number. + EFI_MTFTP6_ERROR_HEADER Error; ///< Error packet header. +} EFI_MTFTP6_PACKET; + +#pragma pack() + +/// +/// EFI_MTFTP6_CONFIG_DATA +/// +typedef struct { + /// + /// The local IP address to use. Set to zero to let the underlying IPv6 + /// driver choose a source address. If not zero it must be one of the + /// configured IP addresses in the underlying IPv6 driver. + /// + EFI_IPv6_ADDRESS StationIp; + /// + /// Local port number. Set to zero to use the automatically assigned port number. + /// + UINT16 LocalPort; + /// + /// The IP address of the MTFTPv6 server. + /// + EFI_IPv6_ADDRESS ServerIp; + /// + /// The initial MTFTPv6 server port number. Request packets are + /// sent to this port. This number is almost always 69 and using zero + /// defaults to 69. + UINT16 InitialServerPort; + /// + /// The number of times to transmit MTFTPv6 request packets and wait for a response. + /// + UINT16 TryCount; + /// + /// The number of seconds to wait for a response after sending the MTFTPv6 request packet. + /// + UINT16 TimeoutValue; +} EFI_MTFTP6_CONFIG_DATA; + +/// +/// EFI_MTFTP6_MODE_DATA +/// +typedef struct { + /// + /// The configuration data of this instance. + /// + EFI_MTFTP6_CONFIG_DATA ConfigData; + /// + /// The number of option strings in the following SupportedOptions array. + /// + UINT8 SupportedOptionCount; + /// + /// An array of null-terminated ASCII option strings that are recognized and supported by + /// this EFI MTFTPv6 Protocol driver implementation. The buffer is + /// read only to the caller and the caller should NOT free the buffer. + /// + UINT8 **SupportedOptions; +} EFI_MTFTP6_MODE_DATA; + +/// +/// EFI_MTFTP_OVERRIDE_DATA +/// +typedef struct { + /// + /// IP address of the MTFTPv6 server. If set to all zero, the value that + /// was set by the EFI_MTFTP6_PROTOCOL.Configure() function will be used. + /// + EFI_IPv6_ADDRESS ServerIp; + /// + /// MTFTPv6 server port number. If set to zero, it will use the value + /// that was set by the EFI_MTFTP6_PROTOCOL.Configure() function. + /// + UINT16 ServerPort; + /// + /// Number of times to transmit MTFTPv6 request packets and wait + /// for a response. If set to zero, the value that was set by + /// theEFI_MTFTP6_PROTOCOL.Configure() function will be used. + /// + UINT16 TryCount; + /// + /// Number of seconds to wait for a response after sending the + /// MTFTPv6 request packet. If set to zero, the value that was set by + /// the EFI_MTFTP6_PROTOCOL.Configure() function will be used. + /// + UINT16 TimeoutValue; +} EFI_MTFTP6_OVERRIDE_DATA; + +/// +/// EFI_MTFTP6_OPTION +/// +typedef struct { + UINT8 *OptionStr; ///< Pointer to the null-terminated ASCII MTFTPv6 option string. + UINT8 *ValueStr; ///< Pointer to the null-terminated ASCII MTFTPv6 value string. +} EFI_MTFTP6_OPTION; + +/** + EFI_MTFTP6_TIMEOUT_CALLBACK is a callback function that the caller provides to capture the + timeout event in the EFI_MTFTP6_PROTOCOL.ReadFile(), EFI_MTFTP6_PROTOCOL.WriteFile() or + EFI_MTFTP6_PROTOCOL.ReadDirectory() functions. + + Whenever a timeout occurs, the EFI MTFTPv6 Protocol driver will call the EFI_MTFTP6_TIMEOUT_CALLBACK + function to notify the caller of the timeout event. Any status code other than EFI_SUCCESS + that is returned from this function will abort the current download process. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] Token The token that the caller provided in the EFI_MTFTP6_PROTOCOl.ReadFile(), + WriteFile() or ReadDirectory() function. + @param[in] PacketLen Indicates the length of the packet. + @param[in] Packet Pointer to an MTFTPv6 packet. + + @retval EFI_SUCCESS Operation success. + @retval Others Aborts session. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_CHECK_PACKET)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP6_PACKET *Packet + ); + +/** + EFI_MTFTP6_TIMEOUT_CALLBACK is a callback function that the caller provides to capture the + timeout event in the EFI_MTFTP6_PROTOCOL.ReadFile(), EFI_MTFTP6_PROTOCOL.WriteFile() or + EFI_MTFTP6_PROTOCOL.ReadDirectory() functions. + + Whenever a timeout occurs, the EFI MTFTPv6 Protocol driver will call the EFI_MTFTP6_TIMEOUT_CALLBACK + function to notify the caller of the timeout event. Any status code other than EFI_SUCCESS + that is returned from this function will abort the current download process. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] Token The token that is provided in the EFI_MTFTP6_PROTOCOL.ReadFile() or + EFI_MTFTP6_PROTOCOL.WriteFile() or EFI_MTFTP6_PROTOCOL.ReadDirectory() + functions by the caller. + + @retval EFI_SUCCESS Operation success. + @retval Others Aborts session. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_TIMEOUT_CALLBACK)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_TOKEN *Token + ); + +/** + EFI_MTFTP6_PACKET_NEEDED is a callback function that the caller provides to feed data to the + EFI_MTFTP6_PROTOCOL.WriteFile() function. + + EFI_MTFTP6_PACKET_NEEDED provides another mechanism for the caller to provide data to upload + other than a static buffer. The EFI MTFTP6 Protocol driver always calls EFI_MTFTP6_PACKET_NEEDED + to get packet data from the caller if no static buffer was given in the initial call to + EFI_MTFTP6_PROTOCOL.WriteFile() function. Setting *Length to zero signals the end of the session. + Returning a status code other than EFI_SUCCESS aborts the session. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] Token The token provided in the EFI_MTFTP6_PROTOCOL.WriteFile() by the caller. + @param[in, out] Length Indicates the length of the raw data wanted on input, and the + length the data available on output. + @param[out] Buffer Pointer to the buffer where the data is stored. + + @retval EFI_SUCCESS Operation success. + @retval Others Aborts session. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_PACKET_NEEDED)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_TOKEN *Token, + IN OUT UINT16 *Length, + OUT VOID **Buffer + ); + +struct _EFI_MTFTP6_TOKEN { + /// + /// The status that is returned to the caller at the end of the operation + /// to indicate whether this operation completed successfully. + /// Defined Status values are listed below. + /// + EFI_STATUS Status; + /// + /// The event that will be signaled when the operation completes. If + /// set to NULL, the corresponding function will wait until the read or + /// write operation finishes. The type of Event must be EVT_NOTIFY_SIGNAL. + /// + EFI_EVENT Event; + /// + /// If not NULL, the data that will be used to override the existing + /// configure data. + /// + EFI_MTFTP6_OVERRIDE_DATA *OverrideData; + /// + /// Pointer to the null-terminated ASCII file name string. + /// + UINT8 *Filename; + /// + /// Pointer to the null-terminated ASCII mode string. If NULL, octet is used. + /// + UINT8 *ModeStr; + /// + /// Number of option/value string pairs. + /// + UINT32 OptionCount; + /// + /// Pointer to an array of option/value string pairs. Ignored if + /// OptionCount is zero. Both a remote server and this driver + /// implementation should support these options. If one or more + /// options are unrecognized by this implementation, it is sent to the + /// remote server without being changed. + /// + EFI_MTFTP6_OPTION *OptionList; + /// + /// On input, the size, in bytes, of Buffer. On output, the number + /// of bytes transferred. + /// + UINT64 BufferSize; + /// + /// Pointer to the data buffer. Data that is downloaded from the + /// MTFTPv6 server is stored here. Data that is uploaded to the + /// MTFTPv6 server is read from here. Ignored if BufferSize is zero. + /// + VOID *Buffer; + /// + /// Pointer to the context that will be used by CheckPacket, + /// TimeoutCallback and PacketNeeded. + /// + VOID *Context; + /// + /// Pointer to the callback function to check the contents of the + /// received packet. + /// + EFI_MTFTP6_CHECK_PACKET CheckPacket; + /// + /// Pointer to the function to be called when a timeout occurs. + /// + EFI_MTFTP6_TIMEOUT_CALLBACK TimeoutCallback; + /// + /// Pointer to the function to provide the needed packet contents. + /// Only used in WriteFile() operation. + /// + EFI_MTFTP6_PACKET_NEEDED PacketNeeded; +}; + +/** + Read the current operational settings. + + The GetModeData() function reads the current operational settings of this EFI MTFTPv6 + Protocol driver instance. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[out] ModeData The buffer in which the EFI MTFTPv6 Protocol driver mode + data is returned. + + @retval EFI_SUCCESS The configuration data was successfully returned. + @retval EFI_OUT_OF_RESOURCES The required mode data could not be allocated. + @retval EFI_INVALID_PARAMETER This is NULL or ModeData is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_GET_MODE_DATA)( + IN EFI_MTFTP6_PROTOCOL *This, + OUT EFI_MTFTP6_MODE_DATA *ModeData + ); + +/** + Initializes, changes, or resets the default operational setting for this EFI MTFTPv6 + Protocol driver instance. + + The Configure() function is used to set and change the configuration data for this EFI + MTFTPv6 Protocol driver instance. The configuration data can be reset to startup defaults by calling + Configure() with MtftpConfigData set to NULL. Whenever the instance is reset, any + pending operation is aborted. By changing the EFI MTFTPv6 Protocol driver instance configuration + data, the client can connect to different MTFTPv6 servers. The configuration parameters in + MtftpConfigData are used as the default parameters in later MTFTPv6 operations and can be + overridden in later operations. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] MtftpConfigData Pointer to the configuration data structure. + + @retval EFI_SUCCESS The EFI MTFTPv6 Protocol instance was configured successfully. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + - This is NULL. + - MtftpConfigData.StationIp is neither zero nor one + of the configured IP addresses in the underlying IPv6 driver. + - MtftpCofigData.ServerIp is not a valid IPv6 unicast address. + @retval EFI_ACCESS_DENIED - The configuration could not be changed at this time because there + is some MTFTP background operation in progress. + - MtftpCofigData.LocalPort is already in use. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available for use. + @retval EFI_OUT_OF_RESOURCES The EFI MTFTPv6 Protocol driver instance data could not be + allocated. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI + MTFTPv6 Protocol driver instance is not configured. + + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_CONFIGURE)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_CONFIG_DATA *MtftpConfigData OPTIONAL + ); + +/** + Get information about a file from an MTFTPv6 server. + + The GetInfo() function assembles an MTFTPv6 request packet with options, sends it to the + MTFTPv6 server, and may return an MTFTPv6 OACK, MTFTPv6 ERROR, or ICMP ERROR packet. + Retries occur only if no response packets are received from the MTFTPv6 server before the + timeout expires. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] OverrideData Data that is used to override the existing parameters. If NULL, the + default parameters that were set in the EFI_MTFTP6_PROTOCOL.Configure() + function are used. + @param[in] Filename Pointer to null-terminated ASCII file name string. + @param[in] ModeStr Pointer to null-terminated ASCII mode string. If NULL, octet will be used + @param[in] OptionCount Number of option/value string pairs in OptionList. + @param[in] OptionList Pointer to array of option/value string pairs. Ignored if + OptionCount is zero. + @param[out] PacketLength The number of bytes in the returned packet. + @param[out] Packet The pointer to the received packet. This buffer must be freed by + the caller. + + @retval EFI_SUCCESS An MTFTPv6 OACK packet was received and is in the Packet. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Filename is NULL + - OptionCount is not zero and OptionList is NULL. + - One or more options in OptionList have wrong format. + - PacketLength is NULL. + - OverrideData.ServerIp is not valid unicast IPv6 addresses. + @retval EFI_UNSUPPORTED One or more options in the OptionList are unsupported by + this implementation. + @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available for use. + @retval EFI_ACCESS_DENIED The previous operation has not completed yet. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_TFTP_ERROR An MTFTPv6 ERROR packet was received and is in the Packet. + @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received and the Packet is set to NULL. + @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received and the Packet is set to NULL. + @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received and the Packet is set to NULL. + @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received and the Packet is set to NULL. + @retval EFI_ICMP_ERROR Some other ICMP ERROR packet was received and the Packet is set to NULL. + @retval EFI_PROTOCOL_ERROR An unexpected MTFTPv6 packet was received and is in the Packet. + @retval EFI_TIMEOUT No responses were received from the MTFTPv6 server. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + @retval EFI_NO_MEDIA There was a media error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_GET_INFO)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_OVERRIDE_DATA *OverrideData OPTIONAL, + IN UINT8 *Filename, + IN UINT8 *ModeStr OPTIONAL, + IN UINT8 OptionCount, + IN EFI_MTFTP6_OPTION *OptionList OPTIONAL, + OUT UINT32 *PacketLength, + OUT EFI_MTFTP6_PACKET **Packet OPTIONAL + ); + +/** + Parse the options in an MTFTPv6 OACK packet. + + The ParseOptions() function parses the option fields in an MTFTPv6 OACK packet and + returns the number of options that were found and optionally a list of pointers to + the options in the packet. + If one or more of the option fields are not valid, then EFI_PROTOCOL_ERROR is returned + and *OptionCount and *OptionList stop at the last valid option. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] PacketLen Length of the OACK packet to be parsed. + @param[in] Packet Pointer to the OACK packet to be parsed. + @param[out] OptionCount Pointer to the number of options in the following OptionList. + @param[out] OptionList Pointer to EFI_MTFTP6_OPTION storage. Each pointer in the + OptionList points to the corresponding MTFTP option buffer + in the Packet. Call the EFI Boot Service FreePool() to + release the OptionList if the options in this OptionList + are not needed any more. + + @retval EFI_SUCCESS The OACK packet was valid and the OptionCount and + OptionList parameters have been updated. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - PacketLen is 0. + - Packet is NULL or Packet is not a valid MTFTPv6 packet. + - OptionCount is NULL. + @retval EFI_NOT_FOUND No options were found in the OACK packet. + @retval EFI_OUT_OF_RESOURCES Storage for the OptionList array can not be allocated. + @retval EFI_PROTOCOL_ERROR One or more of the option fields is invalid. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_PARSE_OPTIONS)( + IN EFI_MTFTP6_PROTOCOL *This, + IN UINT32 PacketLen, + IN EFI_MTFTP6_PACKET *Packet, + OUT UINT32 *OptionCount, + OUT EFI_MTFTP6_OPTION **OptionList OPTIONAL + ); + +/** + Download a file from an MTFTPv6 server. + + The ReadFile() function is used to initialize and start an MTFTPv6 download process and + optionally wait for completion. When the download operation completes, whether successfully or + not, the Token.Status field is updated by the EFI MTFTPv6 Protocol driver and then + Token.Event is signaled if it is not NULL. + + Data can be downloaded from the MTFTPv6 server into either of the following locations: + - A fixed buffer that is pointed to by Token.Buffer + - A download service function that is pointed to by Token.CheckPacket + + If both Token.Buffer and Token.CheckPacket are used, then Token.CheckPacket + will be called first. If the call is successful, the packet will be stored in Token.Buffer. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] Token Pointer to the token structure to provide the parameters that are + used in this operation. + + @retval EFI_SUCCESS The data file has been transferred successfully. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_BUFFER_TOO_SMALL BufferSize is not zero but not large enough to hold the + downloaded data in downloading process. + @retval EFI_ABORTED Current operation is aborted by user. + @retval EFI_NETWORK_UNREACHABLE An ICMP network unreachable error packet was received. + @retval EFI_HOST_UNREACHABLE An ICMP host unreachable error packet was received. + @retval EFI_PROTOCOL_UNREACHABLE An ICMP protocol unreachable error packet was received. + @retval EFI_PORT_UNREACHABLE An ICMP port unreachable error packet was received. + @retval EFI_ICMP_ERROR An ICMP ERROR packet was received. + @retval EFI_TIMEOUT No responses were received from the MTFTPv6 server. + @retval EFI_TFTP_ERROR An MTFTPv6 ERROR packet was received. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + @retval EFI_NO_MEDIA There was a media error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_READ_FILE)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_TOKEN *Token + ); + +/** + Send a file to an MTFTPv6 server. May be unsupported in some implementations. + + The WriteFile() function is used to initialize an uploading operation with the given option list + and optionally wait for completion. If one or more of the options is not supported by the server, the + unsupported options are ignored and a standard TFTP process starts instead. When the upload + process completes, whether successfully or not, Token.Event is signaled, and the EFI MTFTPv6 + Protocol driver updates Token.Status. + + The caller can supply the data to be uploaded in the following two modes: + - Through the user-provided buffer + - Through a callback function + + With the user-provided buffer, the Token.BufferSize field indicates the length of the buffer, + and the driver will upload the data in the buffer. With an EFI_MTFTP6_PACKET_NEEDED + callback function, the driver will call this callback function to get more data from the user to upload. + See the definition of EFI_MTFTP6_PACKET_NEEDED for more information. These two modes + cannot be used at the same time. The callback function will be ignored if the user provides the + buffer. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] Token Pointer to the token structure to provide the parameters that are + used in this operation. + + @retval EFI_SUCCESS The upload session has started. + @retval EFI_UNSUPPORTED The operation is not supported by this implementation. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Token is NULL. + - Token.Filename is NULL. + - Token.OptionCount is not zero and Token.OptionList is NULL. + - One or more options in Token.OptionList have wrong format. + - Token.Buffer and Token.PacketNeeded are both NULL. + - Token.OverrideData.ServerIp is not valid unicast IPv6 addresses. + @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are not + supported by this implementation. + @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available for use. + @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv6 session. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The previous operation has not completed yet. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_WRITE_FILE)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_TOKEN *Token + ); + +/** + Download a data file directory from an MTFTPv6 server. May be unsupported in some implementations. + + The ReadDirectory() function is used to return a list of files on the MTFTPv6 server that are + logically (or operationally) related to Token.Filename. The directory request packet that is sent + to the server is built with the option list that was provided by caller, if present. + + The file information that the server returns is put into either of the following locations: + - A fixed buffer that is pointed to by Token.Buffer + - A download service function that is pointed to by Token.CheckPacket + + If both Token.Buffer and Token.CheckPacket are used, then Token.CheckPacket + will be called first. If the call is successful, the packet will be stored in Token.Buffer. + + The returned directory listing in the Token.Buffer or EFI_MTFTP6_PACKET consists of a list + of two or three variable-length ASCII strings, each terminated by a null character, for each file in the + directory. If the multicast option is involved, the first field of each directory entry is the static + multicast IP address and UDP port number that is associated with the file name. The format of the + field is ip:ip:ip:ip:port. If the multicast option is not involved, this field and its terminating + null character are not present. + + The next field of each directory entry is the file name and the last field is the file information string. + The information string contains the file size and the create/modify timestamp. The format of the + information string is filesize yyyy-mm-dd hh:mm:ss:ffff. The timestamp is + Coordinated Universal Time (UTC; also known as Greenwich Mean Time [GMT]). + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + @param[in] Token Pointer to the token structure to provide the parameters that are + used in this operation. + + @retval EFI_SUCCESS The MTFTPv6 related file "directory" has been downloaded. + @retval EFI_UNSUPPORTED The EFI MTFTPv6 Protocol driver does not support this function. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Token is NULL. + - Token.Filename is NULL. + - Token.OptionCount is not zero and Token.OptionList is NULL. + - One or more options in Token.OptionList have wrong format. + - Token.Buffer and Token.CheckPacket are both NULL. + - Token.OverrideData.ServerIp is not valid unicast IPv6 addresses. + @retval EFI_UNSUPPORTED One or more options in the Token.OptionList are not + supported by this implementation. + @retval EFI_NOT_STARTED The EFI MTFTPv6 Protocol driver has not been started. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available for use. + @retval EFI_ALREADY_STARTED This Token is already being used in another MTFTPv6 session. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The previous operation has not completed yet. + @retval EFI_DEVICE_ERROR An unexpected network error or system error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_READ_DIRECTORY)( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_TOKEN *Token + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function can be used by network drivers and applications to increase the rate that data + packets are moved between the communications device and the transmit and receive queues. + In some systems, the periodic timer event in the managed network driver may not poll the + underlying communications device fast enough to transmit and/or receive all data packets without + missing incoming packets or dropping outgoing packets. Drivers and applications that are + experiencing packet loss should try calling the Poll() function more often. + + @param[in] This Pointer to the EFI_MTFTP6_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI MTFTPv6 Protocol instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_MTFTP6_POLL)( + IN EFI_MTFTP6_PROTOCOL *This + ); + +/// +/// The EFI_MTFTP6_PROTOCOL is designed to be used by UEFI drivers and applications to transmit +/// and receive data files. The EFI MTFTPv6 Protocol driver uses the underlying EFI UDPv6 Protocol +/// driver and EFI IPv6 Protocol driver. +/// +struct _EFI_MTFTP6_PROTOCOL { + EFI_MTFTP6_GET_MODE_DATA GetModeData; + EFI_MTFTP6_CONFIGURE Configure; + EFI_MTFTP6_GET_INFO GetInfo; + EFI_MTFTP6_PARSE_OPTIONS ParseOptions; + EFI_MTFTP6_READ_FILE ReadFile; + EFI_MTFTP6_WRITE_FILE WriteFile; + EFI_MTFTP6_READ_DIRECTORY ReadDirectory; + EFI_MTFTP6_POLL Poll; +}; + +extern EFI_GUID gEfiMtftp6ServiceBindingProtocolGuid; +extern EFI_GUID gEfiMtftp6ProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/Protocol/Tcp6.h b/src/include/ipxe/efi/Protocol/Tcp6.h new file mode 100644 index 00000000..eed2f7cc --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Tcp6.h @@ -0,0 +1,858 @@ +/** @file + EFI TCPv6(Transmission Control Protocol version 6) Protocol Definition + The EFI TCPv6 Service Binding Protocol is used to locate EFI TCPv6 Protocol drivers to create + and destroy child of the driver to communicate with other host using TCP protocol. + The EFI TCPv6 Protocol provides services to send and receive data stream. + + Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.2 + +**/ + +#ifndef __EFI_TCP6_PROTOCOL_H__ +#define __EFI_TCP6_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#include +#include + +#define EFI_TCP6_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xec20eb79, 0x6c1a, 0x4664, {0x9a, 0x0d, 0xd2, 0xe4, 0xcc, 0x16, 0xd6, 0x64 } \ + } + +#define EFI_TCP6_PROTOCOL_GUID \ + { \ + 0x46e44855, 0xbd60, 0x4ab7, {0xab, 0x0d, 0xa6, 0x79, 0xb9, 0x44, 0x7d, 0x77 } \ + } + +typedef struct _EFI_TCP6_PROTOCOL EFI_TCP6_PROTOCOL; + +/// +/// EFI_TCP6_SERVICE_POINT is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + /// + /// The EFI TCPv6 Protocol instance handle that is using this + /// address/port pair. + /// + EFI_HANDLE InstanceHandle; + /// + /// The local IPv6 address to which this TCP instance is bound. Set + /// to 0::/128, if this TCP instance is configured to listen on all + /// available source addresses. + /// + EFI_IPv6_ADDRESS LocalAddress; + /// + /// The local port number in host byte order. + /// + UINT16 LocalPort; + /// + /// The remote IPv6 address. It may be 0::/128 if this TCP instance is + /// not connected to any remote host. + /// + EFI_IPv6_ADDRESS RemoteAddress; + /// + /// The remote port number in host byte order. It may be zero if this + /// TCP instance is not connected to any remote host. + /// + UINT16 RemotePort; +} EFI_TCP6_SERVICE_POINT; + +/// +/// EFI_TCP6_VARIABLE_DATA is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + EFI_HANDLE DriverHandle; ///< The handle of the driver that creates this entry. + UINT32 ServiceCount; ///< The number of address/port pairs following this data structure. + EFI_TCP6_SERVICE_POINT Services[1]; ///< List of address/port pairs that are currently in use. +} EFI_TCP6_VARIABLE_DATA; + +/// +/// EFI_TCP6_ACCESS_POINT +/// +typedef struct { + /// + /// The local IP address assigned to this TCP instance. The EFI + /// TCPv6 driver will only deliver incoming packets whose + /// destination addresses exactly match the IP address. Set to zero to + /// let the underlying IPv6 driver choose a source address. If not zero + /// it must be one of the configured IP addresses in the underlying + /// IPv6 driver. + /// + EFI_IPv6_ADDRESS StationAddress; + /// + /// The local port number to which this EFI TCPv6 Protocol instance + /// is bound. If the instance doesn't care the local port number, set + /// StationPort to zero to use an ephemeral port. + /// + UINT16 StationPort; + /// + /// The remote IP address to which this EFI TCPv6 Protocol instance + /// is connected. If ActiveFlag is FALSE (i.e. a passive TCPv6 + /// instance), the instance only accepts connections from the + /// RemoteAddress. If ActiveFlag is TRUE the instance will + /// connect to the RemoteAddress, i.e., outgoing segments will be + /// sent to this address and only segments from this address will be + /// delivered to the application. When ActiveFlag is FALSE, it + /// can be set to zero and means that incoming connection requests + /// from any address will be accepted. + /// + EFI_IPv6_ADDRESS RemoteAddress; + /// + /// The remote port to which this EFI TCPv6 Protocol instance + /// connects or from which connection request will be accepted by + /// this EFI TCPv6 Protocol instance. If ActiveFlag is FALSE it + /// can be zero and means that incoming connection request from + /// any port will be accepted. Its value can not be zero when + /// ActiveFlag is TRUE. + /// + UINT16 RemotePort; + /// + /// Set it to TRUE to initiate an active open. Set it to FALSE to + /// initiate a passive open to act as a server. + /// + BOOLEAN ActiveFlag; +} EFI_TCP6_ACCESS_POINT; + +/// +/// EFI_TCP6_OPTION +/// +typedef struct { + /// + /// The size of the TCP receive buffer. + /// + UINT32 ReceiveBufferSize; + /// + /// The size of the TCP send buffer. + /// + UINT32 SendBufferSize; + /// + /// The length of incoming connect request queue for a passive + /// instance. When set to zero, the value is implementation specific. + /// + UINT32 MaxSynBackLog; + /// + /// The maximum seconds a TCP instance will wait for before a TCP + /// connection established. When set to zero, the value is + /// implementation specific. + /// + UINT32 ConnectionTimeout; + /// + /// The number of times TCP will attempt to retransmit a packet on + /// an established connection. When set to zero, the value is + /// implementation specific. + /// + UINT32 DataRetries; + /// + /// How many seconds to wait in the FIN_WAIT_2 states for a final + /// FIN flag before the TCP instance is closed. This timeout is in + /// effective only if the application has called Close() to + /// disconnect the connection completely. It is also called + /// FIN_WAIT_2 timer in other implementations. When set to zero, + /// it should be disabled because the FIN_WAIT_2 timer itself is + /// against the standard. The default value is 60. + /// + UINT32 FinTimeout; + /// + /// How many seconds to wait in TIME_WAIT state before the TCP + /// instance is closed. The timer is disabled completely to provide a + /// method to close the TCP connection quickly if it is set to zero. It + /// is against the related RFC documents. + /// + UINT32 TimeWaitTimeout; + /// + /// The maximum number of TCP keep-alive probes to send before + /// giving up and resetting the connection if no response from the + /// other end. Set to zero to disable keep-alive probe. + /// + UINT32 KeepAliveProbes; + /// + /// The number of seconds a connection needs to be idle before TCP + /// sends out periodical keep-alive probes. When set to zero, the + /// value is implementation specific. It should be ignored if keep- + /// alive probe is disabled. + /// + UINT32 KeepAliveTime; + /// + /// The number of seconds between TCP keep-alive probes after the + /// periodical keep-alive probe if no response. When set to zero, the + /// value is implementation specific. It should be ignored if keep- + /// alive probe is disabled. + /// + UINT32 KeepAliveInterval; + /// + /// Set it to TRUE to enable the Nagle algorithm as defined in + /// RFC896. Set it to FALSE to disable it. + /// + BOOLEAN EnableNagle; + /// + /// Set it to TRUE to enable TCP timestamps option as defined in + /// RFC1323. Set to FALSE to disable it. + /// + BOOLEAN EnableTimeStamp; + /// + /// Set it to TRUE to enable TCP window scale option as defined in + /// RFC1323. Set it to FALSE to disable it. + /// + BOOLEAN EnableWindowScaling; + /// + /// Set it to TRUE to enable selective acknowledge mechanism + /// described in RFC 2018. Set it to FALSE to disable it. + /// Implementation that supports SACK can optionally support + /// DSAK as defined in RFC 2883. + /// + BOOLEAN EnableSelectiveAck; + /// + /// Set it to TRUE to enable path MTU discovery as defined in + /// RFC 1191. Set to FALSE to disable it. + /// + BOOLEAN EnablePathMtuDiscovery; +} EFI_TCP6_OPTION; + +/// +/// EFI_TCP6_CONFIG_DATA +/// +typedef struct { + /// + /// TrafficClass field in transmitted IPv6 packets. + /// + UINT8 TrafficClass; + /// + /// HopLimit field in transmitted IPv6 packets. + /// + UINT8 HopLimit; + /// + /// Used to specify TCP communication end settings for a TCP instance. + /// + EFI_TCP6_ACCESS_POINT AccessPoint; + /// + /// Used to configure the advance TCP option for a connection. If set + /// to NULL, implementation specific options for TCP connection will be used. + /// + EFI_TCP6_OPTION *ControlOption; +} EFI_TCP6_CONFIG_DATA; + +/// +/// EFI_TCP6_CONNECTION_STATE +/// +typedef enum { + Tcp6StateClosed = 0, + Tcp6StateListen = 1, + Tcp6StateSynSent = 2, + Tcp6StateSynReceived = 3, + Tcp6StateEstablished = 4, + Tcp6StateFinWait1 = 5, + Tcp6StateFinWait2 = 6, + Tcp6StateClosing = 7, + Tcp6StateTimeWait = 8, + Tcp6StateCloseWait = 9, + Tcp6StateLastAck = 10 +} EFI_TCP6_CONNECTION_STATE; + +/// +/// EFI_TCP6_COMPLETION_TOKEN +/// is used as a common header for various asynchronous tokens. +/// +typedef struct { + /// + /// The Event to signal after request is finished and Status field is + /// updated by the EFI TCPv6 Protocol driver. + /// + EFI_EVENT Event; + /// + /// The result of the completed operation. + /// + EFI_STATUS Status; +} EFI_TCP6_COMPLETION_TOKEN; + +/// +/// EFI_TCP6_CONNECTION_TOKEN +/// will be set if the active open succeeds or an unexpected +/// error happens. +/// +typedef struct { + /// + /// The Status in the CompletionToken will be set to one of + /// the following values if the active open succeeds or an unexpected + /// error happens: + /// EFI_SUCCESS: The active open succeeds and the instance's + /// state is Tcp6StateEstablished. + /// EFI_CONNECTION_RESET: The connect fails because the connection is reset + /// either by instance itself or the communication peer. + /// EFI_CONNECTION_REFUSED: The receiving or transmission operation fails because this + /// connection is refused. + /// EFI_ABORTED: The active open is aborted. + /// EFI_TIMEOUT: The connection establishment timer expires and + /// no more specific information is available. + /// EFI_NETWORK_UNREACHABLE: The active open fails because + /// an ICMP network unreachable error is received. + /// EFI_HOST_UNREACHABLE: The active open fails because an + /// ICMP host unreachable error is received. + /// EFI_PROTOCOL_UNREACHABLE: The active open fails + /// because an ICMP protocol unreachable error is received. + /// EFI_PORT_UNREACHABLE: The connection establishment + /// timer times out and an ICMP port unreachable error is received. + /// EFI_ICMP_ERROR: The connection establishment timer times + /// out and some other ICMP error is received. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// EFI_SECURITY_VIOLATION: The active open was failed because of IPSec policy check. + /// EFI_NO_MEDIA: There was a media error. + /// + EFI_TCP6_COMPLETION_TOKEN CompletionToken; +} EFI_TCP6_CONNECTION_TOKEN; + +/// +/// EFI_TCP6_LISTEN_TOKEN +/// returns when list operation finishes. +/// +typedef struct { + /// + /// The Status in CompletionToken will be set to the + /// following value if accept finishes: + /// EFI_SUCCESS: A remote peer has successfully established a + /// connection to this instance. A new TCP instance has also been + /// created for the connection. + /// EFI_CONNECTION_RESET: The accept fails because the connection is reset either + /// by instance itself or communication peer. + /// EFI_ABORTED: The accept request has been aborted. + /// EFI_SECURITY_VIOLATION: The accept operation was failed because of IPSec policy check. + /// + EFI_TCP6_COMPLETION_TOKEN CompletionToken; + EFI_HANDLE NewChildHandle; +} EFI_TCP6_LISTEN_TOKEN; + +/// +/// EFI_TCP6_FRAGMENT_DATA +/// allows multiple receive or transmit buffers to be specified. The +/// purpose of this structure is to provide scattered read and write. +/// +typedef struct { + UINT32 FragmentLength; ///< Length of data buffer in the fragment. + VOID *FragmentBuffer; ///< Pointer to the data buffer in the fragment. +} EFI_TCP6_FRAGMENT_DATA; + +/// +/// EFI_TCP6_RECEIVE_DATA +/// When TCPv6 driver wants to deliver received data to the application, +/// it will pick up the first queued receiving token, update its +/// Token->Packet.RxData then signal the Token->CompletionToken.Event. +/// +typedef struct { + /// + /// Whether the data is urgent. When this flag is set, the instance is in + /// urgent mode. + /// + BOOLEAN UrgentFlag; + /// + /// When calling Receive() function, it is the byte counts of all + /// Fragmentbuffer in FragmentTable allocated by user. + /// When the token is signaled by TCPv6 driver it is the length of + /// received data in the fragments. + /// + UINT32 DataLength; + /// + /// Number of fragments. + /// + UINT32 FragmentCount; + /// + /// An array of fragment descriptors. + /// + EFI_TCP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP6_RECEIVE_DATA; + +/// +/// EFI_TCP6_TRANSMIT_DATA +/// The EFI TCPv6 Protocol user must fill this data structure before sending a packet. +/// The packet may contain multiple buffers in non-continuous memory locations. +/// +typedef struct { + /// + /// Push If TRUE, data must be transmitted promptly, and the PUSH bit in + /// the last TCP segment created will be set. If FALSE, data + /// transmission may be delayed to combine with data from + /// subsequent Transmit()s for efficiency. + /// + BOOLEAN Push; + /// + /// The data in the fragment table are urgent and urgent point is in + /// effect if TRUE. Otherwise those data are NOT considered urgent. + /// + BOOLEAN Urgent; + /// + /// Length of the data in the fragments. + /// + UINT32 DataLength; + /// + /// Number of fragments. + /// + UINT32 FragmentCount; + /// + /// An array of fragment descriptors. + /// + EFI_TCP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_TCP6_TRANSMIT_DATA; + +/// +/// EFI_TCP6_IO_TOKEN +/// returns When transmission finishes or meets any unexpected error. +/// +typedef struct { + /// + /// When transmission finishes or meets any unexpected error it will + /// be set to one of the following values: + /// EFI_SUCCESS: The receiving or transmission operation + /// completes successfully. + /// EFI_CONNECTION_FIN: The receiving operation fails because the communication peer + /// has closed the connection and there is no more data in the + /// receive buffer of the instance. + /// EFI_CONNECTION_RESET: The receiving or transmission operation fails + /// because this connection is reset either by instance + /// itself or the communication peer. + /// EFI_ABORTED: The receiving or transmission is aborted. + /// EFI_TIMEOUT: The transmission timer expires and no more + /// specific information is available. + /// EFI_NETWORK_UNREACHABLE: The transmission fails + /// because an ICMP network unreachable error is received. + /// EFI_HOST_UNREACHABLE: The transmission fails because an + /// ICMP host unreachable error is received. + /// EFI_PROTOCOL_UNREACHABLE: The transmission fails + /// because an ICMP protocol unreachable error is received. + /// EFI_PORT_UNREACHABLE: The transmission fails and an + /// ICMP port unreachable error is received. + /// EFI_ICMP_ERROR: The transmission fails and some other + /// ICMP error is received. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurs. + /// EFI_SECURITY_VIOLATION: The receiving or transmission + /// operation was failed because of IPSec policy check + /// EFI_NO_MEDIA: There was a media error. + /// + EFI_TCP6_COMPLETION_TOKEN CompletionToken; + union { + /// + /// When this token is used for receiving, RxData is a pointer to + /// EFI_TCP6_RECEIVE_DATA. + /// + EFI_TCP6_RECEIVE_DATA *RxData; + /// + /// When this token is used for transmitting, TxData is a pointer to + /// EFI_TCP6_TRANSMIT_DATA. + /// + EFI_TCP6_TRANSMIT_DATA *TxData; + } Packet; +} EFI_TCP6_IO_TOKEN; + +/// +/// EFI_TCP6_CLOSE_TOKEN +/// returns when close operation finishes. +/// +typedef struct { + /// + /// When close finishes or meets any unexpected error it will be set + /// to one of the following values: + /// EFI_SUCCESS: The close operation completes successfully. + /// EFI_ABORTED: User called configure with NULL without close stopping. + /// EFI_SECURITY_VIOLATION: The close operation was failed because of IPSec policy check. + /// + EFI_TCP6_COMPLETION_TOKEN CompletionToken; + /// + /// Abort the TCP connection on close instead of the standard TCP + /// close process when it is set to TRUE. This option can be used to + /// satisfy a fast disconnect. + /// + BOOLEAN AbortOnClose; +} EFI_TCP6_CLOSE_TOKEN; + +/** + Get the current operational status. + + The GetModeData() function copies the current operational settings of this EFI TCPv6 + Protocol instance into user-supplied buffers. This function can also be used to retrieve + the operational setting of underlying drivers such as IPv6, MNP, or SNP. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[out] Tcp6State The buffer in which the current TCP state is returned. + @param[out] Tcp6ConfigData The buffer in which the current TCP configuration is returned. + @param[out] Ip6ModeData The buffer in which the current IPv6 configuration data used by + the TCP instance is returned. + @param[out] MnpConfigData The buffer in which the current MNP configuration data used + indirectly by the TCP instance is returned. + @param[out] SnpModeData The buffer in which the current SNP mode data used indirectly by + the TCP instance is returned. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_NOT_STARTED No configuration data is available because this instance hasn't + been started. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_GET_MODE_DATA)( + IN EFI_TCP6_PROTOCOL *This, + OUT EFI_TCP6_CONNECTION_STATE *Tcp6State OPTIONAL, + OUT EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + Initialize or brutally reset the operational parameters for this EFI TCPv6 instance. + + The Configure() function does the following: + - Initialize this TCP instance, i.e., initialize the communication end settings and + specify active open or passive open for an instance. + - Reset this TCP instance brutally, i.e., cancel all pending asynchronous tokens, flush + transmission and receiving buffer directly without informing the communication peer. + + No other TCPv6 Protocol operation except Poll() can be executed by this instance until + it is configured properly. For an active TCP instance, after a proper configuration it + may call Connect() to initiates the three-way handshake. For a passive TCP instance, + its state will transit to Tcp6StateListen after configuration, and Accept() may be + called to listen the incoming TCP connection requests. If Tcp6ConfigData is set to NULL, + the instance is reset. Resetting process will be done brutally, the state machine will + be set to Tcp6StateClosed directly, the receive queue and transmit queue will be flushed, + and no traffic is allowed through this instance. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[in] Tcp6ConfigData Pointer to the configure data to configure the instance. + If Tcp6ConfigData is set to NULL, the instance is reset. + + @retval EFI_SUCCESS The operational settings are set, changed, or reset + successfully. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available for + use. + @retval EFI_INVALID_PARAMETER One or more of the following conditions are TRUE: + - This is NULL. + - Tcp6ConfigData->AccessPoint.StationAddress is neither zero nor + one of the configured IP addresses in the underlying IPv6 driver. + - Tcp6ConfigData->AccessPoint.RemoteAddress isn't a valid unicast + IPv6 address. + - Tcp6ConfigData->AccessPoint.RemoteAddress is zero or + Tcp6ConfigData->AccessPoint.RemotePort is zero when + Tcp6ConfigData->AccessPoint.ActiveFlag is TRUE. + - A same access point has been configured in other TCP + instance properly. + @retval EFI_ACCESS_DENIED Configuring TCP instance when it is configured without + calling Configure() with NULL to reset it. + @retval EFI_UNSUPPORTED One or more of the control options are not supported in + the implementation. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when + executing Configure(). + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CONFIGURE)( + IN EFI_TCP6_PROTOCOL *This, + IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData OPTIONAL + ); + +/** + Initiate a nonblocking TCP connection request for an active TCP instance. + + The Connect() function will initiate an active open to the remote peer configured + in current TCP instance if it is configured active. If the connection succeeds or + fails due to any error, the ConnectionToken->CompletionToken.Event will be signaled + and ConnectionToken->CompletionToken.Status will be updated accordingly. This + function can only be called for the TCP instance in Tcp6StateClosed state. The + instance will transfer into Tcp6StateSynSent if the function returns EFI_SUCCESS. + If TCP three-way handshake succeeds, its state will become Tcp6StateEstablished, + otherwise, the state will return to Tcp6StateClosed. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[in] ConnectionToken Pointer to the connection token to return when the TCP three + way handshake finishes. + + @retval EFI_SUCCESS The connection request is successfully initiated and the state of + this TCP instance has been changed to Tcp6StateSynSent. + @retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured. + @retval EFI_ACCESS_DENIED One or more of the following conditions are TRUE: + - This instance is not configured as an active one. + - This instance is not in Tcp6StateClosed state. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - ConnectionToken is NULL. + - ConnectionToken->CompletionToken.Event is NULL. + @retval EFI_OUT_OF_RESOURCES The driver can't allocate enough resource to initiate the active open. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CONNECT)( + IN EFI_TCP6_PROTOCOL *This, + IN EFI_TCP6_CONNECTION_TOKEN *ConnectionToken + ); + +/** + Listen on the passive instance to accept an incoming connection request. This is a + nonblocking operation. + + The Accept() function initiates an asynchronous accept request to wait for an incoming + connection on the passive TCP instance. If a remote peer successfully establishes a + connection with this instance, a new TCP instance will be created and its handle will + be returned in ListenToken->NewChildHandle. The newly created instance is configured + by inheriting the passive instance's configuration and is ready for use upon return. + The new instance is in the Tcp6StateEstablished state. + + The ListenToken->CompletionToken.Event will be signaled when a new connection is + accepted, user aborts the listen or connection is reset. + + This function only can be called when current TCP instance is in Tcp6StateListen state. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[in] ListenToken Pointer to the listen token to return when operation finishes. + + + @retval EFI_SUCCESS The listen token has been queued successfully. + @retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured. + @retval EFI_ACCESS_DENIED One or more of the following are TRUE: + - This instance is not a passive instance. + - This instance is not in Tcp6StateListen state. + - The same listen token has already existed in the listen + token queue of this TCP instance. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - ListenToken is NULL. + - ListentToken->CompletionToken.Event is NULL. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough resource to finish the operation. + @retval EFI_DEVICE_ERROR Any unexpected and not belonged to above category error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_ACCEPT)( + IN EFI_TCP6_PROTOCOL *This, + IN EFI_TCP6_LISTEN_TOKEN *ListenToken + ); + +/** + Queues outgoing data into the transmit queue. + + The Transmit() function queues a sending request to this TCP instance along with the + user data. The status of the token is updated and the event in the token will be + signaled once the data is sent out or some error occurs. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[in] Token Pointer to the completion token to queue to the transmit queue. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a + source address for this instance, but no source address was + available for use. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - Token is NULL. + - Token->CompletionToken.Event is NULL. + - Token->Packet.TxData is NULL. + - Token->Packet.FragmentCount is zero. + - Token->Packet.DataLength is not equal to the sum of fragment lengths. + @retval EFI_ACCESS_DENIED One or more of the following conditions are TRUE: + - A transmit completion token with the same Token-> + CompletionToken.Event was already in the + transmission queue. + - The current instance is in Tcp6StateClosed state. + - The current instance is a passive one and it is in + Tcp6StateListen state. + - User has called Close() to disconnect this connection. + @retval EFI_NOT_READY The completion token could not be queued because the + transmit queue is full. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data because of resource + shortage. + @retval EFI_NETWORK_UNREACHABLE There is no route to the destination network or address. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_TRANSMIT)( + IN EFI_TCP6_PROTOCOL *This, + IN EFI_TCP6_IO_TOKEN *Token + ); + +/** + Places an asynchronous receive request into the receiving queue. + + The Receive() function places a completion token into the receive packet queue. This + function is always asynchronous. The caller must allocate the Token->CompletionToken.Event + and the FragmentBuffer used to receive data. The caller also must fill the DataLength which + represents the whole length of all FragmentBuffer. When the receive operation completes, the + EFI TCPv6 Protocol driver updates the Token->CompletionToken.Status and Token->Packet.RxData + fields and the Token->CompletionToken.Event is signaled. If got data the data and its length + will be copied into the FragmentTable, at the same time the full length of received data will + be recorded in the DataLength fields. Providing a proper notification function and context + for the event will enable the user to receive the notification and receiving status. That + notification function is guaranteed to not be re-entered. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[in] Token Pointer to a token that is associated with the receive data + descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available for use. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - Token is NULL. + - Token->CompletionToken.Event is NULL. + - Token->Packet.RxData is NULL. + - Token->Packet.RxData->DataLength is 0. + - The Token->Packet.RxData->DataLength is not the + sum of all FragmentBuffer length in FragmentTable. + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of + system resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + The EFI TCPv6 Protocol instance has been reset to startup defaults. + @retval EFI_ACCESS_DENIED One or more of the following conditions is TRUE: + - A receive completion token with the same Token->CompletionToken.Event + was already in the receive queue. + - The current instance is in Tcp6StateClosed state. + - The current instance is a passive one and it is in + Tcp6StateListen state. + - User has called Close() to disconnect this connection. + @retval EFI_CONNECTION_FIN The communication peer has closed the connection and there is no + any buffered data in the receive buffer of this instance + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_RECEIVE)( + IN EFI_TCP6_PROTOCOL *This, + IN EFI_TCP6_IO_TOKEN *Token + ); + +/** + Disconnecting a TCP connection gracefully or reset a TCP connection. This function is a + nonblocking operation. + + Initiate an asynchronous close token to TCP driver. After Close() is called, any buffered + transmission data will be sent by TCP driver and the current instance will have a graceful close + working flow described as RFC 793 if AbortOnClose is set to FALSE, otherwise, a rest packet + will be sent by TCP driver to fast disconnect this connection. When the close operation completes + successfully the TCP instance is in Tcp6StateClosed state, all pending asynchronous + operations are signaled and any buffers used for TCP network traffic are flushed. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[in] CloseToken Pointer to the close token to return when operation finishes. + + @retval EFI_SUCCESS The Close() is called successfully. + @retval EFI_NOT_STARTED This EFI TCPv6 Protocol instance has not been configured. + @retval EFI_ACCESS_DENIED One or more of the following are TRUE: + - CloseToken or CloseToken->CompletionToken.Event is already in use. + - Previous Close() call on this instance has not finished. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - CloseToken is NULL. + - CloseToken->CompletionToken.Event is NULL. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough resource to finish the operation. + @retval EFI_DEVICE_ERROR Any unexpected and not belonged to above category error. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CLOSE)( + IN EFI_TCP6_PROTOCOL *This, + IN EFI_TCP6_CLOSE_TOKEN *CloseToken + ); + +/** + Abort an asynchronous connection, listen, transmission or receive request. + + The Cancel() function aborts a pending connection, listen, transmit or + receive request. + + If Token is not NULL and the token is in the connection, listen, transmission + or receive queue when it is being cancelled, its Token->Status will be set + to EFI_ABORTED and then Token->Event will be signaled. + + If the token is not in one of the queues, which usually means that the + asynchronous operation has completed, EFI_NOT_FOUND is returned. + + If Token is NULL all asynchronous token issued by Connect(), Accept(), + Transmit() and Receive() will be aborted. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_TCP6_PROTOCOL.Connect(), + EFI_TCP6_PROTOCOL.Accept(), + EFI_TCP6_PROTOCOL.Transmit() or + EFI_TCP6_PROTOCOL.Receive(). If NULL, all pending + tokens issued by above four functions will be aborted. Type + EFI_TCP6_COMPLETION_TOKEN is defined in + EFI_TCP_PROTOCOL.Connect(). + + @retval EFI_SUCCESS The asynchronous I/O request is aborted and Token->Event + is signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance hasn't been configured. + @retval EFI_NOT_FOUND The asynchronous I/O request isn't found in the transmission or + receive queue. It has either completed or wasn't issued by + Transmit() and Receive(). + @retval EFI_UNSUPPORTED The implementation does not support this function. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_CANCEL)( + IN EFI_TCP6_PROTOCOL *This, + IN EFI_TCP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + Poll to receive incoming data and transmit outgoing segments. + + The Poll() function increases the rate that data is moved between the network + and application and can be called when the TCP instance is created successfully. + Its use is optional. + + @param[in] This Pointer to the EFI_TCP6_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_TIMEOUT Data was dropped out of the transmission or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_TCP6_POLL)( + IN EFI_TCP6_PROTOCOL *This + ); + +/// +/// EFI_TCP6_PROTOCOL +/// defines the EFI TCPv6 Protocol child to be used by any network drivers or +/// applications to send or receive data stream. It can either listen on a +/// specified port as a service or actively connect to remote peer as a client. +/// Each instance has its own independent settings. +/// +struct _EFI_TCP6_PROTOCOL { + EFI_TCP6_GET_MODE_DATA GetModeData; + EFI_TCP6_CONFIGURE Configure; + EFI_TCP6_CONNECT Connect; + EFI_TCP6_ACCEPT Accept; + EFI_TCP6_TRANSMIT Transmit; + EFI_TCP6_RECEIVE Receive; + EFI_TCP6_CLOSE Close; + EFI_TCP6_CANCEL Cancel; + EFI_TCP6_POLL Poll; +}; + +extern EFI_GUID gEfiTcp6ServiceBindingProtocolGuid; +extern EFI_GUID gEfiTcp6ProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/Protocol/Udp6.h b/src/include/ipxe/efi/Protocol/Udp6.h new file mode 100644 index 00000000..5a62a3e0 --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Udp6.h @@ -0,0 +1,576 @@ +/** @file + The EFI UDPv6 (User Datagram Protocol version 6) Protocol Definition, which is built upon + the EFI IPv6 Protocol and provides simple packet-oriented services to transmit and receive + UDP packets. + + Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.2 + +**/ + +#ifndef __EFI_UDP6_PROTOCOL_H__ +#define __EFI_UDP6_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#include + +#define EFI_UDP6_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0x66ed4721, 0x3c98, 0x4d3e, {0x81, 0xe3, 0xd0, 0x3d, 0xd3, 0x9a, 0x72, 0x54 } \ + } + +#define EFI_UDP6_PROTOCOL_GUID \ + { \ + 0x4f948815, 0xb4b9, 0x43cb, {0x8a, 0x33, 0x90, 0xe0, 0x60, 0xb3, 0x49, 0x55 } \ + } + +/// +/// EFI_UDP6_SERVICE_POINT is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + /// + /// The EFI UDPv6 Protocol instance handle that is using this address/port pair. + /// + EFI_HANDLE InstanceHandle; + /// + /// The IPv6 address to which this instance of the EFI UDPv6 Protocol is bound. + /// Set to 0::/128, if this instance is used to listen all packets from any + /// source address. + /// + EFI_IPv6_ADDRESS LocalAddress; + /// + /// The port number in host byte order on which the service is listening. + /// + UINT16 LocalPort; + /// + /// The IPv6 address of the remote host. May be 0::/128 if it is not connected + /// to any remote host or connected with more than one remote host. + /// + EFI_IPv6_ADDRESS RemoteAddress; + /// + /// The port number in host byte order on which the remote host is + /// listening. Maybe zero if it is not connected to any remote host. + /// + UINT16 RemotePort; +} EFI_UDP6_SERVICE_POINT; + +/// +/// EFI_UDP6_VARIABLE_DATA is deprecated in the UEFI 2.4B and should not be used any more. +/// The definition in here is only present to provide backwards compatability. +/// +typedef struct { + /// + /// The handle of the driver that creates this entry. + /// + EFI_HANDLE DriverHandle; + /// + /// The number of address/port pairs that follow this data structure. + /// + UINT32 ServiceCount; + /// + /// List of address/port pairs that are currently in use. + /// + EFI_UDP6_SERVICE_POINT Services[1]; +} EFI_UDP6_VARIABLE_DATA; + +typedef struct _EFI_UDP6_PROTOCOL EFI_UDP6_PROTOCOL; + +/// +/// EFI_UDP6_FRAGMENT_DATA allows multiple receive or transmit buffers to be specified. +/// The purpose of this structure is to avoid copying the same packet multiple times. +/// +typedef struct { + UINT32 FragmentLength; ///< Length of the fragment data buffer. + VOID *FragmentBuffer; ///< Pointer to the fragment data buffer. +} EFI_UDP6_FRAGMENT_DATA; + +/// +/// The EFI_UDP6_SESSION_DATA is used to retrieve the settings when receiving packets or +/// to override the existing settings (only DestinationAddress and DestinationPort can +/// be overridden) of this EFI UDPv6 Protocol instance when sending packets. +/// +typedef struct { + /// + /// Address from which this packet is sent. This field should not be used when + /// sending packets. + /// + EFI_IPv6_ADDRESS SourceAddress; + /// + /// Port from which this packet is sent. It is in host byte order. This field should + /// not be used when sending packets. + /// + UINT16 SourcePort; + /// + /// Address to which this packet is sent. When sending packet, it'll be ignored + /// if it is zero. + /// + EFI_IPv6_ADDRESS DestinationAddress; + /// + /// Port to which this packet is sent. When sending packet, it'll be + /// ignored if it is zero. + /// + UINT16 DestinationPort; +} EFI_UDP6_SESSION_DATA; + +typedef struct { + /// + /// Set to TRUE to accept UDP packets that are sent to any address. + /// + BOOLEAN AcceptPromiscuous; + /// + /// Set to TRUE to accept UDP packets that are sent to any port. + /// + BOOLEAN AcceptAnyPort; + /// + /// Set to TRUE to allow this EFI UDPv6 Protocol child instance to open a port number + /// that is already being used by another EFI UDPv6 Protocol child instance. + /// + BOOLEAN AllowDuplicatePort; + /// + /// TrafficClass field in transmitted IPv6 packets. + /// + UINT8 TrafficClass; + /// + /// HopLimit field in transmitted IPv6 packets. + /// + UINT8 HopLimit; + /// + /// The receive timeout value (number of microseconds) to be associated with each + /// incoming packet. Zero means do not drop incoming packets. + /// + UINT32 ReceiveTimeout; + /// + /// The transmit timeout value (number of microseconds) to be associated with each + /// outgoing packet. Zero means do not drop outgoing packets. + /// + UINT32 TransmitTimeout; + /// + /// The station IP address that will be assigned to this EFI UDPv6 Protocol instance. + /// The EFI UDPv6 and EFI IPv6 Protocol drivers will only deliver incoming packets + /// whose destination matches this IP address exactly. Address 0::/128 is also accepted + /// as a special case. Under this situation, underlying IPv6 driver is responsible for + /// binding a source address to this EFI IPv6 protocol instance according to source + /// address selection algorithm. Only incoming packet from the selected source address + /// is delivered. This field can be set and changed only when the EFI IPv6 driver is + /// transitioning from the stopped to the started states. If no address is available + /// for selecting, the EFI IPv6 Protocol driver will use EFI_IP6_CONFIG_PROTOCOL to + /// retrieve the IPv6 address. + EFI_IPv6_ADDRESS StationAddress; + /// + /// The port number to which this EFI UDPv6 Protocol instance is bound. If a client + /// of the EFI UDPv6 Protocol does not care about the port number, set StationPort + /// to zero. The EFI UDPv6 Protocol driver will assign a random port number to transmitted + /// UDP packets. Ignored it if AcceptAnyPort is TRUE. + /// + UINT16 StationPort; + /// + /// The IP address of remote host to which this EFI UDPv6 Protocol instance is connecting. + /// If RemoteAddress is not 0::/128, this EFI UDPv6 Protocol instance will be connected to + /// RemoteAddress; i.e., outgoing packets of this EFI UDPv6 Protocol instance will be sent + /// to this address by default and only incoming packets from this address will be delivered + /// to client. Ignored for incoming filtering if AcceptPromiscuous is TRUE. + EFI_IPv6_ADDRESS RemoteAddress; + /// + /// The port number of the remote host to which this EFI UDPv6 Protocol instance is connecting. + /// If it is not zero, outgoing packets of this EFI UDPv6 Protocol instance will be sent to + /// this port number by default and only incoming packets from this port will be delivered + /// to client. Ignored if RemoteAddress is 0::/128 and ignored for incoming filtering if + /// AcceptPromiscuous is TRUE. + UINT16 RemotePort; +} EFI_UDP6_CONFIG_DATA; + +/// +/// The EFI UDPv6 Protocol client must fill this data structure before sending a packet. +/// The packet may contain multiple buffers that may be not in a continuous memory location. +/// +typedef struct { + /// + /// If not NULL, the data that is used to override the transmitting settings.Only the two + /// filed UdpSessionData.DestinationAddress and UdpSessionData.DestionPort can be used as + /// the transmitting setting filed. + /// + EFI_UDP6_SESSION_DATA *UdpSessionData; + /// + /// Sum of the fragment data length. Must not exceed the maximum UDP packet size. + /// + UINT32 DataLength; + /// + /// Number of fragments. + /// + UINT32 FragmentCount; + /// + /// Array of fragment descriptors. + /// + EFI_UDP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP6_TRANSMIT_DATA; + +/// +/// EFI_UDP6_RECEIVE_DATA is filled by the EFI UDPv6 Protocol driver when this EFI UDPv6 +/// Protocol instance receives an incoming packet. If there is a waiting token for incoming +/// packets, the CompletionToken.Packet.RxData field is updated to this incoming packet and +/// the CompletionToken.Event is signaled. The EFI UDPv6 Protocol client must signal the +/// RecycleSignal after processing the packet. +/// FragmentTable could contain multiple buffers that are not in the continuous memory locations. +/// The EFI UDPv6 Protocol client might need to combine two or more buffers in FragmentTable to +/// form their own protocol header. +/// +typedef struct { + /// + /// Time when the EFI UDPv6 Protocol accepted the packet. + /// + EFI_TIME TimeStamp; + /// + /// Indicates the event to signal when the received data has been processed. + /// + EFI_EVENT RecycleSignal; + /// + /// The UDP session data including SourceAddress, SourcePort, DestinationAddress, + /// and DestinationPort. + /// + EFI_UDP6_SESSION_DATA UdpSession; + /// + /// The sum of the fragment data length. + /// + UINT32 DataLength; + /// + /// Number of fragments. Maybe zero. + /// + UINT32 FragmentCount; + /// + /// Array of fragment descriptors. Maybe zero. + /// + EFI_UDP6_FRAGMENT_DATA FragmentTable[1]; +} EFI_UDP6_RECEIVE_DATA; + +/// +/// The EFI_UDP6_COMPLETION_TOKEN structures are used for both transmit and receive operations. +/// When used for transmitting, the Event and TxData fields must be filled in by the EFI UDPv6 +/// Protocol client. After the transmit operation completes, the Status field is updated by the +/// EFI UDPv6 Protocol and the Event is signaled. +/// When used for receiving, only the Event field must be filled in by the EFI UDPv6 Protocol +/// client. After a packet is received, RxData and Status are filled in by the EFI UDPv6 Protocol +/// and the Event is signaled. +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by the EFI UDPv6 Protocol + /// driver. The type of Event must be EVT_NOTIFY_SIGNAL. + /// + EFI_EVENT Event; + /// + /// Will be set to one of the following values: + /// - EFI_SUCCESS: The receive or transmit operation completed successfully. + /// - EFI_ABORTED: The receive or transmit was aborted. + /// - EFI_TIMEOUT: The transmit timeout expired. + /// - EFI_NETWORK_UNREACHABLE: The destination network is unreachable. RxData is set to + /// NULL in this situation. + /// - EFI_HOST_UNREACHABLE: The destination host is unreachable. RxData is set to NULL in + /// this situation. + /// - EFI_PROTOCOL_UNREACHABLE: The UDP protocol is unsupported in the remote system. + /// RxData is set to NULL in this situation. + /// - EFI_PORT_UNREACHABLE: No service is listening on the remote port. RxData is set to + /// NULL in this situation. + /// - EFI_ICMP_ERROR: Some other Internet Control Message Protocol (ICMP) error report was + /// received. For example, packets are being sent too fast for the destination to receive them + /// and the destination sent an ICMP source quench report. RxData is set to NULL in this situation. + /// - EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// - EFI_SECURITY_VIOLATION: The transmit or receive was failed because of IPsec policy check. + /// - EFI_NO_MEDIA: There was a media error. + /// + EFI_STATUS Status; + union { + /// + /// When this token is used for receiving, RxData is a pointer to EFI_UDP6_RECEIVE_DATA. + /// + EFI_UDP6_RECEIVE_DATA *RxData; + /// + /// When this token is used for transmitting, TxData is a pointer to EFI_UDP6_TRANSMIT_DATA. + /// + EFI_UDP6_TRANSMIT_DATA *TxData; + } Packet; +} EFI_UDP6_COMPLETION_TOKEN; + +/** + Read the current operational settings. + + The GetModeData() function copies the current operational settings of this EFI UDPv6 Protocol + instance into user-supplied buffers. This function is used optionally to retrieve the operational + mode data of underlying networks or drivers. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[out] Udp6ConfigData The buffer in which the current UDP configuration data is returned. + @param[out] Ip6ModeData The buffer in which the current EFI IPv6 Protocol mode data is returned. + @param[out] MnpConfigData The buffer in which the current managed network configuration data is + returned. + @param[out] SnpModeData The buffer in which the simple network mode data is returned. + + @retval EFI_SUCCESS The mode data was read. + @retval EFI_NOT_STARTED When Udp6ConfigData is queried, no configuration data is available + because this instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_GET_MODE_DATA)( + IN EFI_UDP6_PROTOCOL *This, + OUT EFI_UDP6_CONFIG_DATA *Udp6ConfigData OPTIONAL, + OUT EFI_IP6_MODE_DATA *Ip6ModeData OPTIONAL, + OUT EFI_MANAGED_NETWORK_CONFIG_DATA *MnpConfigData OPTIONAL, + OUT EFI_SIMPLE_NETWORK_MODE *SnpModeData OPTIONAL + ); + +/** + Initializes, changes, or resets the operational parameters for this instance of the EFI UDPv6 + Protocol. + + The Configure() function is used to do the following: + - Initialize and start this instance of the EFI UDPv6 Protocol. + - Change the filtering rules and operational parameters. + - Reset this instance of the EFI UDPv6 Protocol. + + Until these parameters are initialized, no network traffic can be sent or received by this instance. + This instance can be also reset by calling Configure() with UdpConfigData set to NULL. + Once reset, the receiving queue and transmitting queue are flushed and no traffic is allowed through + this instance. + + With different parameters in UdpConfigData, Configure() can be used to bind this instance to specified + port. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] UdpConfigData Pointer to the buffer contained the configuration data. + + @retval EFI_SUCCESS The configuration settings were set, changed, or reset successfully. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available for use. + @retval EFI_INVALID_PARAMETER One or more following conditions are TRUE: + - This is NULL. + - UdpConfigData.StationAddress neither zero nor one of the configured IP + addresses in the underlying IPv6 driver. + - UdpConfigData.RemoteAddress is not a valid unicast IPv6 address if it + is not zero. + @retval EFI_ALREADY_STARTED The EFI UDPv6 Protocol instance is already started/configured and must be + stopped/reset before it can be reconfigured. Only TrafficClass, HopLimit, + ReceiveTimeout, and TransmitTimeout can be reconfigured without stopping + the current instance of the EFI UDPv6 Protocol. + @retval EFI_ACCESS_DENIED UdpConfigData.AllowDuplicatePort is FALSE and UdpConfigData.StationPort + is already used by other instance. + @retval EFI_OUT_OF_RESOURCES The EFI UDPv6 Protocol driver cannot allocate memory for this EFI UDPv6 + Protocol instance. + @retval EFI_DEVICE_ERROR An unexpected network or system error occurred and this instance was not + opened. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_CONFIGURE)( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_CONFIG_DATA *UdpConfigData OPTIONAL + ); + +/** + Joins and leaves multicast groups. + + The Groups() function is used to join or leave one or more multicast group. + If the JoinFlag is FALSE and the MulticastAddress is NULL, then all currently joined groups are left. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] JoinFlag Set to TRUE to join a multicast group. Set to FALSE to leave one + or all multicast groups. + @param[in] MulticastAddress Pointer to multicast group address to join or leave. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED The EFI UDPv6 Protocol instance has not been started. + @retval EFI_OUT_OF_RESOURCES Could not allocate resources to join the group. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + - This is NULL. + - JoinFlag is TRUE and MulticastAddress is NULL. + - JoinFlag is TRUE and *MulticastAddress is not a valid multicast address. + @retval EFI_ALREADY_STARTED The group address is already in the group table (when JoinFlag is TRUE). + @retval EFI_NOT_FOUND The group address is not in the group table (when JoinFlag is FALSE). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_GROUPS)( + IN EFI_UDP6_PROTOCOL *This, + IN BOOLEAN JoinFlag, + IN EFI_IPv6_ADDRESS *MulticastAddress OPTIONAL + ); + +/** + Queues outgoing data packets into the transmit queue. + + The Transmit() function places a sending request to this instance of the EFI UDPv6 Protocol, + alongside the transmit data that was filled by the user. Whenever the packet in the token is + sent out or some errors occur, the Token.Event will be signaled and Token.Status is updated. + Providing a proper notification function and context for the event will enable the user to + receive the notification and transmitting status. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to the completion token that will be placed into the + transmit queue. + + @retval EFI_SUCCESS The data has been queued for transmission. + @retval EFI_NOT_STARTED This EFI UDPv6 Protocol instance has not been started. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available + for use. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + - This is NULL. + - Token is NULL. + - Token.Event is NULL. + - Token.Packet.TxData is NULL. + - Token.Packet.TxData.FragmentCount is zero. + - Token.Packet.TxData.DataLength is not equal to the sum of fragment + lengths. + - One or more of the Token.Packet.TxData.FragmentTable[].FragmentLength + fields is zero. + - One or more of the Token.Packet.TxData.FragmentTable[].FragmentBuffer + fields is NULL. + - Token.Packet.TxData.UdpSessionData.DestinationAddress is not zero + and is not valid unicast Ipv6 address if UdpSessionData is not NULL. + - Token.Packet.TxData.UdpSessionData is NULL and this instance's + UdpConfigData.RemoteAddress is unspecified. + - Token.Packet.TxData.UdpSessionData.DestinationAddress is non-zero + when DestinationAddress is configured as non-zero when doing Configure() + for this EFI Udp6 protocol instance. + - Token.Packet.TxData.UdpSesionData.DestinationAddress is zero when + DestinationAddress is unspecified when doing Configure() for this + EFI Udp6 protocol instance. + @retval EFI_ACCESS_DENIED The transmit completion token with the same Token.Event was already + in the transmit queue. + @retval EFI_NOT_READY The completion token could not be queued because the transmit queue + is full. + @retval EFI_OUT_OF_RESOURCES Could not queue the transmit data. + @retval EFI_NOT_FOUND There is no route to the destination network or address. + @retval EFI_BAD_BUFFER_SIZE The data length is greater than the maximum UDP packet size. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_TRANSMIT)( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ); + +/** + Places an asynchronous receive request into the receiving queue. + + The Receive() function places a completion token into the receive packet queue. This function is + always asynchronous. + The caller must fill in the Token.Event field in the completion token, and this field cannot be + NULL. When the receive operation completes, the EFI UDPv6 Protocol driver updates the Token.Status + and Token.Packet.RxData fields and the Token.Event is signaled. + Providing a proper notification function and context for the event will enable the user to receive + the notification and receiving status. That notification function is guaranteed to not be re-entered. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to a token that is associated with the receive data descriptor. + + @retval EFI_SUCCESS The receive completion token was cached. + @retval EFI_NOT_STARTED This EFI UDPv6 Protocol instance has not been started. + @retval EFI_NO_MAPPING The underlying IPv6 driver was responsible for choosing a source + address for this instance, but no source address was available + for use. + @retval EFI_INVALID_PARAMETER One or more of the following is TRUE: + - This is NULL. + - Token is NULL. + - Token.Event is NULL. + @retval EFI_OUT_OF_RESOURCES The receive completion token could not be queued due to a lack of system + resources (usually memory). + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The EFI UDPv6 Protocol + instance has been reset to startup defaults. + @retval EFI_ACCESS_DENIED A receive completion token with the same Token.Event was already in + the receive queue. + @retval EFI_NOT_READY The receive request could not be queued because the receive queue is full. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_RECEIVE)( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token + ); + +/** + Aborts an asynchronous transmit or receive request. + + The Cancel() function is used to abort a pending transmit or receive request. If the token is in the + transmit or receive request queues, after calling this function, Token.Status will be set to + EFI_ABORTED and then Token.Event will be signaled. If the token is not in one of the queues, + which usually means that the asynchronous operation has completed, this function will not signal the + token and EFI_NOT_FOUND is returned. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by EFI_UDP6_PROTOCOL.Transmit() + or EFI_UDP6_PROTOCOL.Receive().If NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS The asynchronous I/O request was aborted and Token.Event was signaled. + When Token is NULL, all pending requests are aborted and their events + are signaled. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_NOT_FOUND When Token is not NULL, the asynchronous I/O request was not found in + the transmit or receive queue. It has either completed or was not issued + by Transmit() and Receive(). + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_CANCEL)( + IN EFI_UDP6_PROTOCOL *This, + IN EFI_UDP6_COMPLETION_TOKEN *Token OPTIONAL + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function can be used by network drivers and applications to increase the rate that data + packets are moved between the communications device and the transmit and receive queues. + In some systems, the periodic timer event in the managed network driver may not poll the underlying + communications device fast enough to transmit and/or receive all data packets without missing incoming + packets or dropping outgoing packets. Drivers and applications that are experiencing packet loss should + try calling the Poll() function more often. + + @param[in] This Pointer to the EFI_UDP6_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive queue. + Consider increasing the polling rate. + +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_UDP6_POLL)( + IN EFI_UDP6_PROTOCOL *This + ); + +/// +/// The EFI_UDP6_PROTOCOL defines an EFI UDPv6 Protocol session that can be used by any network drivers, +/// applications, or daemons to transmit or receive UDP packets. This protocol instance can either be +/// bound to a specified port as a service or connected to some remote peer as an active client. +/// Each instance has its own settings, such as group table, that are independent from each other. +/// +struct _EFI_UDP6_PROTOCOL { + EFI_UDP6_GET_MODE_DATA GetModeData; + EFI_UDP6_CONFIGURE Configure; + EFI_UDP6_GROUPS Groups; + EFI_UDP6_TRANSMIT Transmit; + EFI_UDP6_RECEIVE Receive; + EFI_UDP6_CANCEL Cancel; + EFI_UDP6_POLL Poll; +}; + +extern EFI_GUID gEfiUdp6ServiceBindingProtocolGuid; +extern EFI_GUID gEfiUdp6ProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 29117fa3..0d90fbb7 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -184,6 +184,8 @@ extern EFI_GUID efi_console_control_protocol_guid; extern EFI_GUID efi_device_path_protocol_guid; extern EFI_GUID efi_dhcp4_protocol_guid; extern EFI_GUID efi_dhcp4_service_binding_protocol_guid; +extern EFI_GUID efi_dhcp6_protocol_guid; +extern EFI_GUID efi_dhcp6_service_binding_protocol_guid; extern EFI_GUID efi_disk_io_protocol_guid; extern EFI_GUID efi_driver_binding_protocol_guid; extern EFI_GUID efi_graphics_output_protocol_guid; @@ -192,6 +194,9 @@ extern EFI_GUID efi_hii_font_protocol_guid; extern EFI_GUID efi_ip4_protocol_guid; extern EFI_GUID efi_ip4_config_protocol_guid; extern EFI_GUID efi_ip4_service_binding_protocol_guid; +extern EFI_GUID efi_ip6_protocol_guid; +extern EFI_GUID efi_ip6_config_protocol_guid; +extern EFI_GUID efi_ip6_service_binding_protocol_guid; extern EFI_GUID efi_load_file_protocol_guid; extern EFI_GUID efi_load_file2_protocol_guid; extern EFI_GUID efi_loaded_image_protocol_guid; @@ -200,6 +205,8 @@ extern EFI_GUID efi_managed_network_protocol_guid; extern EFI_GUID efi_managed_network_service_binding_protocol_guid; extern EFI_GUID efi_mtftp4_protocol_guid; extern EFI_GUID efi_mtftp4_service_binding_protocol_guid; +extern EFI_GUID efi_mtftp6_protocol_guid; +extern EFI_GUID efi_mtftp6_service_binding_protocol_guid; extern EFI_GUID efi_nii_protocol_guid; extern EFI_GUID efi_nii31_protocol_guid; extern EFI_GUID efi_pci_io_protocol_guid; @@ -216,9 +223,13 @@ extern EFI_GUID efi_simple_text_output_protocol_guid; extern EFI_GUID efi_tcg_protocol_guid; extern EFI_GUID efi_tcp4_protocol_guid; extern EFI_GUID efi_tcp4_service_binding_protocol_guid; +extern EFI_GUID efi_tcp6_protocol_guid; +extern EFI_GUID efi_tcp6_service_binding_protocol_guid; extern EFI_GUID efi_tree_protocol_guid; extern EFI_GUID efi_udp4_protocol_guid; extern EFI_GUID efi_udp4_service_binding_protocol_guid; +extern EFI_GUID efi_udp6_protocol_guid; +extern EFI_GUID efi_udp6_service_binding_protocol_guid; extern EFI_GUID efi_uga_draw_protocol_guid; extern EFI_GUID efi_unicode_collation_protocol_guid; extern EFI_GUID efi_usb_hc_protocol_guid; diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 02cbf9fa..8922fa2a 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -99,6 +99,10 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Dhcp4" }, { &efi_dhcp4_service_binding_protocol_guid, "Dhcp4Sb" }, + { &efi_dhcp6_protocol_guid, + "Dhcp6" }, + { &efi_dhcp6_service_binding_protocol_guid, + "Dhcp6Sb" }, { &efi_disk_io_protocol_guid, "DiskIo" }, { &efi_graphics_output_protocol_guid, @@ -113,6 +117,12 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Ip4Config" }, { &efi_ip4_service_binding_protocol_guid, "Ip4Sb" }, + { &efi_ip6_protocol_guid, + "Ip6" }, + { &efi_ip6_config_protocol_guid, + "Ip6Config" }, + { &efi_ip6_service_binding_protocol_guid, + "Ip6Sb" }, { &efi_iscsi4_dxe_guid, "IScsi4Dxe" }, { &efi_load_file_protocol_guid, @@ -131,6 +141,10 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Mtftp4" }, { &efi_mtftp4_service_binding_protocol_guid, "Mtftp4Sb" }, + { &efi_mtftp6_protocol_guid, + "Mtftp6" }, + { &efi_mtftp6_service_binding_protocol_guid, + "Mtftp6Sb" }, { &efi_nii_protocol_guid, "Nii" }, { &efi_nii31_protocol_guid, @@ -163,12 +177,20 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Tcp4" }, { &efi_tcp4_service_binding_protocol_guid, "Tcp4Sb" }, + { &efi_tcp6_protocol_guid, + "Tcp6" }, + { &efi_tcp6_service_binding_protocol_guid, + "Tcp6Sb" }, { &efi_tree_protocol_guid, "TrEE" }, { &efi_udp4_protocol_guid, "Udp4" }, { &efi_udp4_service_binding_protocol_guid, "Udp4Sb" }, + { &efi_udp6_protocol_guid, + "Udp6" }, + { &efi_udp6_service_binding_protocol_guid, + "Udp6Sb" }, { &efi_uga_draw_protocol_guid, "UgaDraw" }, { &efi_unicode_collation_protocol_guid, diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c index 25c342ff..b9f8e155 100644 --- a/src/interface/efi/efi_guid.c +++ b/src/interface/efi/efi_guid.c @@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -44,11 +45,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -63,7 +67,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include +#include #include #include #include @@ -140,6 +146,14 @@ EFI_GUID efi_dhcp4_protocol_guid EFI_GUID efi_dhcp4_service_binding_protocol_guid = EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID; +/** DHCPv6 protocol GUID */ +EFI_GUID efi_dhcp6_protocol_guid + = EFI_DHCP6_PROTOCOL_GUID; + +/** DHCPv6 service binding protocol GUID */ +EFI_GUID efi_dhcp6_service_binding_protocol_guid + = EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID; + /** Disk I/O protocol GUID */ EFI_GUID efi_disk_io_protocol_guid = EFI_DISK_IO_PROTOCOL_GUID; @@ -172,6 +186,18 @@ EFI_GUID efi_ip4_config_protocol_guid EFI_GUID efi_ip4_service_binding_protocol_guid = EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID; +/** IPv6 protocol GUID */ +EFI_GUID efi_ip6_protocol_guid + = EFI_IP6_PROTOCOL_GUID; + +/** IPv6 configuration protocol GUID */ +EFI_GUID efi_ip6_config_protocol_guid + = EFI_IP6_CONFIG_PROTOCOL_GUID; + +/** IPv6 service binding protocol GUID */ +EFI_GUID efi_ip6_service_binding_protocol_guid + = EFI_IP6_SERVICE_BINDING_PROTOCOL_GUID; + /** Load file protocol GUID */ EFI_GUID efi_load_file_protocol_guid = EFI_LOAD_FILE_PROTOCOL_GUID; @@ -204,6 +230,14 @@ EFI_GUID efi_mtftp4_protocol_guid EFI_GUID efi_mtftp4_service_binding_protocol_guid = EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID; +/** MTFTPv6 protocol GUID */ +EFI_GUID efi_mtftp6_protocol_guid + = EFI_MTFTP6_PROTOCOL_GUID; + +/** MTFTPv6 service binding protocol GUID */ +EFI_GUID efi_mtftp6_service_binding_protocol_guid + = EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID; + /** Network interface identifier protocol GUID (old version) */ EFI_GUID efi_nii_protocol_guid = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID; @@ -268,6 +302,14 @@ EFI_GUID efi_tcp4_protocol_guid EFI_GUID efi_tcp4_service_binding_protocol_guid = EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID; +/** TCPv6 protocol GUID */ +EFI_GUID efi_tcp6_protocol_guid + = EFI_TCP6_PROTOCOL_GUID; + +/** TCPv6 service binding protocol GUID */ +EFI_GUID efi_tcp6_service_binding_protocol_guid + = EFI_TCP6_SERVICE_BINDING_PROTOCOL_GUID; + /** TrEE protocol GUID */ EFI_GUID efi_tree_protocol_guid = EFI_TREE_PROTOCOL_GUID; @@ -280,6 +322,14 @@ EFI_GUID efi_udp4_protocol_guid EFI_GUID efi_udp4_service_binding_protocol_guid = EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID; +/** UDPv6 protocol GUID */ +EFI_GUID efi_udp6_protocol_guid + = EFI_UDP6_PROTOCOL_GUID; + +/** UDPv6 service binding protocol GUID */ +EFI_GUID efi_udp6_service_binding_protocol_guid + = EFI_UDP6_SERVICE_BINDING_PROTOCOL_GUID; + /** UGA draw protocol GUID */ EFI_GUID efi_uga_draw_protocol_guid = EFI_UGA_DRAW_PROTOCOL_GUID; -- cgit v1.2.3-55-g7522 From e7adf5701fac35ffca0dc477be0ce0d1d182638d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:56:36 +0100 Subject: [efi] Add Ip4Config2 header and GUID definition Signed-off-by: Michael Brown --- src/include/ipxe/efi/Protocol/Ip4Config2.h | 318 +++++++++++++++++++++++++++++ src/include/ipxe/efi/efi.h | 1 + src/interface/efi/efi_debug.c | 2 + src/interface/efi/efi_guid.c | 5 + 4 files changed, 326 insertions(+) create mode 100644 src/include/ipxe/efi/Protocol/Ip4Config2.h diff --git a/src/include/ipxe/efi/Protocol/Ip4Config2.h b/src/include/ipxe/efi/Protocol/Ip4Config2.h new file mode 100644 index 00000000..ca091dea --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Ip4Config2.h @@ -0,0 +1,318 @@ +/** @file + This file provides a definition of the EFI IPv4 Configuration II + Protocol. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +@par Revision Reference: +This Protocol is introduced in UEFI Specification 2.5 + +**/ + +#ifndef __EFI_IP4CONFIG2_PROTOCOL_H__ +#define __EFI_IP4CONFIG2_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#include + +#define EFI_IP4_CONFIG2_PROTOCOL_GUID \ + { \ + 0x5b446ed1, 0xe30b, 0x4faa, {0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \ + } + +typedef struct _EFI_IP4_CONFIG2_PROTOCOL EFI_IP4_CONFIG2_PROTOCOL; + +/// +/// EFI_IP4_CONFIG2_DATA_TYPE +/// +typedef enum { + /// + /// The interface information of the communication device this EFI + /// IPv4 Configuration II Protocol instance manages. This type of + /// data is read only. The corresponding Data is of type + /// EFI_IP4_CONFIG2_INTERFACE_INFO. + /// + Ip4Config2DataTypeInterfaceInfo, + /// + /// The general configuration policy for the EFI IPv4 network stack + /// running on the communication device this EFI IPv4 + /// Configuration II Protocol instance manages. The policy will + /// affect other configuration settings. The corresponding Data is of + /// type EFI_IP4_CONFIG2_POLICY. + /// + Ip4Config2DataTypePolicy, + /// + /// The station addresses set manually for the EFI IPv4 network + /// stack. It is only configurable when the policy is + /// Ip4Config2PolicyStatic. The corresponding Data is of + /// type EFI_IP4_CONFIG2_MANUAL_ADDRESS. When DataSize + /// is 0 and Data is NULL, the existing configuration is cleared + /// from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeManualAddress, + /// + /// The gateway addresses set manually for the EFI IPv4 network + /// stack running on the communication device this EFI IPv4 + /// Configuration II Protocol manages. It is not configurable when + /// the policy is Ip4Config2PolicyDhcp. The gateway + /// addresses must be unicast IPv4 addresses. The corresponding + /// Data is a pointer to an array of EFI_IPv4_ADDRESS instances. + /// When DataSize is 0 and Data is NULL, the existing configuration + /// is cleared from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeGateway, + /// + /// The DNS server list for the EFI IPv4 network stack running on + /// the communication device this EFI IPv4 Configuration II + /// Protocol manages. It is not configurable when the policy is + /// Ip4Config2PolicyDhcp. The DNS server addresses must be + /// unicast IPv4 addresses. The corresponding Data is a pointer to + /// an array of EFI_IPv4_ADDRESS instances. When DataSize + /// is 0 and Data is NULL, the existing configuration is cleared + /// from the EFI IPv4 Configuration II Protocol instance. + /// + Ip4Config2DataTypeDnsServer, + Ip4Config2DataTypeMaximum +} EFI_IP4_CONFIG2_DATA_TYPE; + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO related definitions +/// +#define EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE 32 + +/// +/// EFI_IP4_CONFIG2_INTERFACE_INFO +/// +typedef struct { + /// + /// The name of the interface. It is a NULL-terminated Unicode string. + /// + CHAR16 Name[EFI_IP4_CONFIG2_INTERFACE_INFO_NAME_SIZE]; + /// + /// The interface type of the network interface. See RFC 1700, + /// section "Number Hardware Type". + /// + UINT8 IfType; + /// + /// The size, in bytes, of the network interface's hardware address. + /// + UINT32 HwAddressSize; + /// + /// The hardware address for the network interface. + /// + EFI_MAC_ADDRESS HwAddress; + /// + /// The station IPv4 address of this EFI IPv4 network stack. + /// + EFI_IPv4_ADDRESS StationAddress; + /// + /// The subnet address mask that is associated with the station address. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// Size of the following RouteTable, in bytes. May be zero. + /// + UINT32 RouteTableSize; + /// + /// The route table of the IPv4 network stack runs on this interface. + /// Set to NULL if RouteTableSize is zero. Type EFI_IP4_ROUTE_TABLE is defined in + /// EFI_IP4_PROTOCOL.GetModeData(). + /// + EFI_IP4_ROUTE_TABLE *RouteTable OPTIONAL; +} EFI_IP4_CONFIG2_INTERFACE_INFO; + +/// +/// EFI_IP4_CONFIG2_POLICY +/// +typedef enum { + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration + /// data are required to be set manually. The EFI IPv4 Protocol will get all + /// required configuration such as IPv4 address, subnet mask and + /// gateway settings from the EFI IPv4 Configuration II protocol. + /// + Ip4Config2PolicyStatic, + /// + /// Under this policy, the Ip4Config2DataTypeManualAddress, + /// Ip4Config2DataTypeGateway and Ip4Config2DataTypeDnsServer configuration data are + /// not allowed to set via SetData(). All of these configurations are retrieved from DHCP + /// server or other auto-configuration mechanism. + /// + Ip4Config2PolicyDhcp, + Ip4Config2PolicyMax +} EFI_IP4_CONFIG2_POLICY; + +/// +/// EFI_IP4_CONFIG2_MANUAL_ADDRESS +/// +typedef struct { + /// + /// The IPv4 unicast address. + /// + EFI_IPv4_ADDRESS Address; + /// + /// The subnet mask. + /// + EFI_IPv4_ADDRESS SubnetMask; +} EFI_IP4_CONFIG2_MANUAL_ADDRESS; + +/** + Set the configuration for the EFI IPv4 network stack running on the communication device this EFI + IPv4 Configuration II Protocol instance manages. + + This function is used to set the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The successfully configured data is valid after system reset or power-off. + The DataSize is used to calculate the count of structure instances in the Data for some + DataType that multiple structure instances are allowed. + This function is always non-blocking. When setting some typeof configuration data, an + asynchronous process is invoked to check the correctness of the data, such as doing address conflict + detection on the manually set local IPv4 address. EFI_NOT_READY is returned immediately to + indicate that such an asynchronous process is invoked and the process is not finished yet. The caller + willing to get the result of the asynchronous process is required to call RegisterDataNotify() + to register an event on the specified configuration data. Once the event is signaled, the caller can call + GetData()to get back the configuration data in order to know the result. For other types of + configuration data that do not require an asynchronous configuration process, the result of the + operation is immediately returned. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to set. + @param[in] DataSize Size of the buffer pointed to by Data in bytes. + @param[in] Data The data buffer to set. The type ofthe data buffer is associated + with the DataType. + + @retval EFI_SUCCESS The specified configuration data for the EFI IPv4 network stack is set + successfully. + @retval EFI_INVALID_PARAMETER One or more of the following are TRUE: + This is NULL. + One or more fields in Data and DataSize do not match the + requirement of the data type indicated by DataType. + @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified configuration + data can not be set under the current policy. + @retval EFI_ACCESS_DENIED Another set operation on the specified configuration data is already in process. + @retval EFI_NOT_READY An asynchronous process is invoked to set the specified configuration data and + the process is not finished yet. + @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type indicated by DataType. + @retval EFI_UNSUPPORTED This DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_SET_DATA)( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Get the configuration data for the EFI IPv4 network stack running on the communication device this + EFI IPv4 Configuration II Protocol instance manages. + + This function returns the configuration data of type DataType for the EFI IPv4 network stack + running on the communication device this EFI IPv4 Configuration II Protocol instance manages. + The caller is responsible for allocating the buffer usedto return the specified configuration data and + the required size will be returned to the caller if the size of the buffer is too small. + EFI_NOT_READY is returned if the specified configuration data is not ready due to an already in + progress asynchronous configuration process. The caller can call RegisterDataNotify() to + register an event on the specified configuration data. Once the asynchronous configuration process is + finished, the event will be signaled and a subsequent GetData() call will return the specified + configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to get. + @param[out] DataSize On input, in bytes, the size of Data. On output, in bytes, the size + of buffer required to store the specified configuration data. + @param[in] Data The data buffer in which the configuration data is returned. The + type of the data buffer is associated with the DataType. Ignored + if DataSize is 0. + + @retval EFI_SUCCESS The specified configuration data is got successfully. + @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE: + This is NULL. + DataSize is NULL. + Data is NULL if *DataSizeis not zero. + @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data + and the required size is returned in DataSize. + @retval EFI_NOT_READY The specified configuration data is not ready due to an already in + progress asynchronous configuration process. + @retval EFI_NOT_FOUND The specified configuration data is not found. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_GET_DATA)( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN OUT UINTN *DataSize, + IN VOID *Data OPTIONAL + ); + +/** + Register an event that is to be signaled whenever a configuration process on the specified + configuration data is done. + + This function registers an event that is to be signaled whenever a configuration process on the + specified configuration data is done. An event can be registered for different DataType + simultaneously and the caller is responsible for determining which type of configuration data causes + the signaling of the event in such case. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to unregister the event for. + @param[in] Event The event to register. + + @retval EFI_SUCCESS The notification event for the specified configuration data is + registered. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not supported. + @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated. + @retval EFI_ACCESS_DENIED The Event is already registered for the DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_REGISTER_NOTIFY)( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/** + Remove a previously registered event for the specified configuration data. + + This function removes a previously registeredevent for the specified configuration data. + + @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance. + @param[in] DataType The type of data to remove the previously registered event for. + @param[in] Event The event to unregister. + + @retval EFI_SUCCESS The event registered for the specified configuration data is removed. + @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL. + @retval EFI_NOT_FOUND The Eventhas not been registered for the specified DataType. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_IP4_CONFIG2_UNREGISTER_NOTIFY)( + IN EFI_IP4_CONFIG2_PROTOCOL *This, + IN EFI_IP4_CONFIG2_DATA_TYPE DataType, + IN EFI_EVENT Event + ); + +/// +/// The EFI_IP4_CONFIG2_PROTOCOL is designed to be the central repository for the common +/// configurations and the administrator configurable settings for the EFI IPv4 network stack. +/// An EFI IPv4 Configuration II Protocol instance will be installed on each communication device that +/// the EFI IPv4 network stack runs on. +/// +struct _EFI_IP4_CONFIG2_PROTOCOL { + EFI_IP4_CONFIG2_SET_DATA SetData; + EFI_IP4_CONFIG2_GET_DATA GetData; + EFI_IP4_CONFIG2_REGISTER_NOTIFY RegisterDataNotify; + EFI_IP4_CONFIG2_UNREGISTER_NOTIFY UnregisterDataNotify; +}; + +extern EFI_GUID gEfiIp4Config2ProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 0d90fbb7..86a3c2f9 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -193,6 +193,7 @@ extern EFI_GUID efi_hii_config_access_protocol_guid; extern EFI_GUID efi_hii_font_protocol_guid; extern EFI_GUID efi_ip4_protocol_guid; extern EFI_GUID efi_ip4_config_protocol_guid; +extern EFI_GUID efi_ip4_config2_protocol_guid; extern EFI_GUID efi_ip4_service_binding_protocol_guid; extern EFI_GUID efi_ip6_protocol_guid; extern EFI_GUID efi_ip6_config_protocol_guid; diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 8922fa2a..dec6b6e6 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -115,6 +115,8 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Ip4" }, { &efi_ip4_config_protocol_guid, "Ip4Config" }, + { &efi_ip4_config2_protocol_guid, + "Ip4Config2" }, { &efi_ip4_service_binding_protocol_guid, "Ip4Sb" }, { &efi_ip6_protocol_guid, diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c index b9f8e155..4a76bdac 100644 --- a/src/interface/efi/efi_guid.c +++ b/src/interface/efi/efi_guid.c @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -182,6 +183,10 @@ EFI_GUID efi_ip4_protocol_guid EFI_GUID efi_ip4_config_protocol_guid = EFI_IP4_CONFIG_PROTOCOL_GUID; +/** IPv4 configuration 2 protocol GUID */ +EFI_GUID efi_ip4_config2_protocol_guid + = EFI_IP4_CONFIG2_PROTOCOL_GUID; + /** IPv4 service binding protocol GUID */ EFI_GUID efi_ip4_service_binding_protocol_guid = EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID; -- cgit v1.2.3-55-g7522 From bc75bbaf17b35bf7850255e7effe6f2ddf6f4fb2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:39:23 +0100 Subject: [efi] Add DNS headers and GUID definitions Signed-off-by: Michael Brown --- src/include/ipxe/efi/Protocol/Dns4.h | 538 +++++++++++++++++++++++++++++++++++ src/include/ipxe/efi/Protocol/Dns6.h | 535 ++++++++++++++++++++++++++++++++++ src/include/ipxe/efi/efi.h | 4 + src/interface/efi/efi_debug.c | 8 + src/interface/efi/efi_guid.c | 18 ++ 5 files changed, 1103 insertions(+) create mode 100644 src/include/ipxe/efi/Protocol/Dns4.h create mode 100644 src/include/ipxe/efi/Protocol/Dns6.h diff --git a/src/include/ipxe/efi/Protocol/Dns4.h b/src/include/ipxe/efi/Protocol/Dns4.h new file mode 100644 index 00000000..0ab07e51 --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Dns4.h @@ -0,0 +1,538 @@ +/** @file + This file defines the EFI Domain Name Service Binding Protocol interface. It is split + into the following two main sections: + DNSv4 Service Binding Protocol (DNSv4SB) + DNSv4 Protocol (DNSv4) + + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.5 + +**/ + +#ifndef __EFI_DNS4_PROTOCOL_H__ +#define __EFI_DNS4_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#define EFI_DNS4_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xb625b186, 0xe063, 0x44f7, {0x89, 0x5, 0x6a, 0x74, 0xdc, 0x6f, 0x52, 0xb4 } \ + } + +#define EFI_DNS4_PROTOCOL_GUID \ + { \ + 0xae3d28cc, 0xe05b, 0x4fa1, {0xa0, 0x11, 0x7e, 0xb5, 0x5a, 0x3f, 0x14, 0x1 } \ + } + +typedef struct _EFI_DNS4_PROTOCOL EFI_DNS4_PROTOCOL; + +/// +/// EFI_DNS4_CONFIG_DATA +/// +typedef struct { + /// + /// Count of the DNS servers. When used with GetModeData(), + /// this field is the count of originally configured servers when + /// Configure() was called for this instance. When used with + /// Configure() this is the count of caller-supplied servers. If the + /// DnsServerListCount is zero, the DNS server configuration + /// will be retrieved from DHCP server automatically. + /// + UINTN DnsServerListCount; + /// + /// Pointer to DNS server list containing DnsServerListCount entries or NULL + /// if DnsServerListCountis 0. For Configure(), this will be NULL when there are + /// no caller supplied server addresses, and, the DNS instance will retrieve + /// DNS server from DHCP Server. The provided DNS server list is + /// recommended to be filled up in the sequence of preference. When + /// used with GetModeData(), the buffer containing the list will + /// be allocated by the driver implementing this protocol and must be + /// freed by the caller. When used with Configure(), the buffer + /// containing the list will be allocated and released by the caller. + /// + EFI_IPv4_ADDRESS *DnsServerList; + /// + /// Set to TRUE to use the default IP address/subnet mask and default routing table. + /// + BOOLEAN UseDefaultSetting; + /// + /// If TRUE, enable DNS cache function for this DNS instance. If FALSE, all DNS + /// query will not lookup local DNS cache. + /// + BOOLEAN EnableDnsCache; + /// + /// Use the protocol number defined in "Links to UEFI-Related + /// Documents"(http://uefi.org/uefi) under the heading "IANA + /// Protocol Numbers". Only TCP or UDP are supported, and other + /// protocol values are invalid. An implementation can choose to + /// support only UDP, or both TCP and UDP. + /// + UINT8 Protocol; + /// + /// If UseDefaultSetting is FALSE indicates the station address to use. + /// + EFI_IPv4_ADDRESS StationIp; + /// + /// If UseDefaultSetting is FALSE indicates the subnet mask to use. + /// + EFI_IPv4_ADDRESS SubnetMask; + /// + /// Local port number. Set to zero to use the automatically assigned port number. + /// + UINT16 LocalPort; + /// + /// Retry number if no response received after RetryInterval. + /// + UINT32 RetryCount; + /// + /// Minimum interval of retry is 2 second. If the retry interval is less than 2 + /// seconds, then use the 2 seconds. + /// + UINT32 RetryInterval; +} EFI_DNS4_CONFIG_DATA; + +/// +/// EFI_DNS4_CACHE_ENTRY +/// +typedef struct { + /// + /// Host name. + /// + CHAR16 *HostName; + /// + /// IP address of this host. + /// + EFI_IPv4_ADDRESS *IpAddress; + /// + /// Time in second unit that this entry will remain in DNS cache. A value of zero + /// means that this entry is permanent. A nonzero value will override the existing + /// one if this entry to be added is dynamic entry. Implementations may set its + /// default timeout value for the dynamically created DNS cache entry after one DNS + /// resolve succeeds. + /// + UINT32 Timeout; +} EFI_DNS4_CACHE_ENTRY; + +/// +/// EFI_DNS4_MODE_DATA +/// +typedef struct { + /// + /// The configuration data of this instance. + /// + EFI_DNS4_CONFIG_DATA DnsConfigData; + /// + /// Number of configured DNS server. Each DNS instance has its own DNS server + /// configuration. + /// + UINT32 DnsServerCount; + /// + /// Pointer to common list of addresses of all configured DNS server + /// used by EFI_DNS4_PROTOCOL instances. List will include + /// DNS servers configured by this or any other EFI_DNS4_PROTOCOL instance. + /// The storage for this list is allocated by the driver publishing this + /// protocol, and must be freed by the caller. + /// + EFI_IPv4_ADDRESS *DnsServerList; + /// + /// Number of DNS Cache entries. The DNS Cache is shared among all DNS instances. + /// + UINT32 DnsCacheCount; + /// + /// Pointer to a buffer containing DnsCacheCount DNS Cache + /// entry structures. The storage for this list is allocated by the driver + /// publishing this protocol and must be freed by caller. + /// + EFI_DNS4_CACHE_ENTRY *DnsCacheList; +} EFI_DNS4_MODE_DATA; + +/// +/// DNS_HOST_TO_ADDR_DATA +/// +typedef struct { + /// + /// Number of the returned IP addresses. + /// + UINT32 IpCount; + /// + /// Pointer to the all the returned IP addresses. + /// + EFI_IPv4_ADDRESS *IpList; +} DNS_HOST_TO_ADDR_DATA; + +/// +/// DNS_ADDR_TO_HOST_DATA +/// +typedef struct { + /// + /// Pointer to the primary name for this host address. It's the caller's + /// responsibility to free the response memory. + /// + CHAR16 *HostName; +} DNS_ADDR_TO_HOST_DATA; + +/// +/// DNS_RESOURCE_RECORD +/// +typedef struct { + /// + /// The Owner name. + /// + CHAR8 *QName; + /// + /// The Type Code of this RR. + /// + UINT16 QType; + /// + /// The CLASS code of this RR. + /// + UINT16 QClass; + /// + /// 32 bit integer which specify the time interval that the resource record may be + /// cached before the source of the information should again be consulted. Zero means + /// this RR can not be cached. + /// + UINT32 TTL; + /// + /// 16 big integer which specify the length of RData. + /// + UINT16 DataLength; + /// + /// A string of octets that describe the resource, the format of this information + /// varies according to QType and QClass difference. + /// + CHAR8 *RData; +} DNS_RESOURCE_RECORD; + +/// +/// DNS_GENERAL_LOOKUP_DATA +/// +typedef struct { + /// + /// Number of returned matching RRs. + /// + UINTN RRCount; + /// + /// Pointer to the all the returned matching RRs. It's caller responsibility to free + /// the allocated memory to hold the returned RRs. + /// + DNS_RESOURCE_RECORD *RRList; +} DNS_GENERAL_LOOKUP_DATA; + +/// +/// EFI_DNS4_COMPLETION_TOKEN +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by the EFI DNS + /// protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. + /// + EFI_EVENT Event; + /// + /// Will be set to one of the following values: + /// EFI_SUCCESS: The host name to address translation completed successfully. + /// EFI_NOT_FOUND: No matching Resource Record (RR) is found. + /// EFI_TIMEOUT: No DNS server reachable, or RetryCount was exhausted without + /// response from all specified DNS servers. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// EFI_NO_MEDIA: There was a media error. + /// + EFI_STATUS Status; + /// + /// Retry number if no response received after RetryInterval. If zero, use the + /// parameter configured through Dns.Configure() interface. + /// + UINT32 RetryCount; + /// + /// Minimum interval of retry is 2 second. If the retry interval is less than 2 + /// seconds, then use the 2 seconds. If zero, use the parameter configured through + /// Dns.Configure() interface. + UINT32 RetryInterval; + /// + /// DNSv4 completion token data + /// + union { + /// + /// When the Token is used for host name to address translation, H2AData is a pointer + /// to the DNS_HOST_TO_ADDR_DATA. + /// + DNS_HOST_TO_ADDR_DATA *H2AData; + /// + /// When the Token is used for host address to host name translation, A2HData is a + /// pointer to the DNS_ADDR_TO_HOST_DATA. + /// + DNS_ADDR_TO_HOST_DATA *A2HData; + /// + /// When the Token is used for a general lookup function, GLookupDATA is a pointer to + /// the DNS_GENERAL_LOOKUP_DATA. + /// + DNS_GENERAL_LOOKUP_DATA *GLookupData; + } RspData; +} EFI_DNS4_COMPLETION_TOKEN; + +/** + Retrieve mode data of this DNS instance. + + This function is used to retrieve DNS mode data for this DNS instance. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[out] DnsModeData Point to the mode data. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data + is available because this instance has not been + configured. + @retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_GET_MODE_DATA)( + IN EFI_DNS4_PROTOCOL *This, + OUT EFI_DNS4_MODE_DATA *DnsModeData + ); + +/** + Configure this DNS instance. + + This function is used to configure DNS mode data for this DNS instance. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] DnsConfigData Point to the Configuration data. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED The designated protocol is not supported. + @retval EFI_INVALID_PARAMETER This is NULL. + The StationIp address provided in DnsConfigData is not a + valid unicast. + DnsServerList is NULL while DnsServerListCount + is not ZERO. + DnsServerListCount is ZERO while DnsServerList + is not NULL + @retval EFI_OUT_OF_RESOURCES The DNS instance data or required space could not be + allocated. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The + EFI DNSv4 Protocol instance is not configured. + @retval EFI_ALREADY_STARTED Second call to Configure() with DnsConfigData. To + reconfigure the instance the caller must call Configure() + with NULL first to return driver to unconfigured state. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_CONFIGURE)( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_DNS4_CONFIG_DATA *DnsConfigData + ); + +/** + Host name to host address translation. + + The HostNameToIp () function is used to translate the host name to host IP address. A + type A query is used to get the one or more IP addresses for this host. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] HostName Host name. + @param[in] Token Point to the completion token to translate host name + to host address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token.Event is NULL. + HostName is NULL. HostName string is unsupported format. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_HOST_NAME_TO_IP)( + IN EFI_DNS4_PROTOCOL *This, + IN CHAR16 *HostName, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/** + IPv4 address to host name translation also known as Reverse DNS lookup. + + The IpToHostName() function is used to translate the host address to host name. A type PTR + query is used to get the primary name of the host. Support of this function is optional. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] IpAddress Ip Address. + @param[in] Token Point to the completion token to translate host + address to host name. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED This function is not supported. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token.Event is NULL. + IpAddress is not valid IP address . + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_ALREADY_STARTED This Token is being used in another DNS session. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_IP_TO_HOST_NAME)( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_IPv4_ADDRESS IpAddress, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/** + Retrieve arbitrary information from the DNS server. + + This GeneralLookup() function retrieves arbitrary information from the DNS. The caller + supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. All + RR content (e.g., TTL) was returned. The caller need parse the returned RR to get + required information. The function is optional. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] QName Pointer to Query Name. + @param[in] QType Query Type. + @param[in] QClass Query Name. + @param[in] Token Point to the completion token to retrieve arbitrary + information. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED This function is not supported. Or the requested + QType is not supported + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token.Event is NULL. + QName is NULL. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_ALREADY_STARTED This Token is being used in another DNS session. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_GENERAL_LOOKUP)( + IN EFI_DNS4_PROTOCOL *This, + IN CHAR8 *QName, + IN UINT16 QType, + IN UINT16 QClass, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/** + This function is to update the DNS Cache. + + The UpdateDnsCache() function is used to add/delete/modify DNS cache entry. DNS cache + can be normally dynamically updated after the DNS resolve succeeds. This function + provided capability to manually add/delete/modify the DNS cache. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] DeleteFlag If FALSE, this function is to add one entry to the + DNS Cahce. If TRUE, this function will delete + matching DNS Cache entry. + @param[in] Override If TRUE, the maching DNS cache entry will be + overwritten with the supplied parameter. If FALSE, + EFI_ACCESS_DENIED will be returned if the entry to + be added is already existed. + @param[in] DnsCacheEntry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + DnsCacheEntry.HostName is NULL. + DnsCacheEntry.IpAddress is NULL. + DnsCacheEntry.Timeout is zero. + @retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is + not TRUE. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_UPDATE_DNS_CACHE)( + IN EFI_DNS4_PROTOCOL *This, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function can be used by network drivers and applications to increase the + rate that data packets are moved between the communications device and the transmit + and receive queues. + In some systems, the periodic timer event in the managed network driver may not poll + the underlying communications device fast enough to transmit and/or receive all data + packets without missing incoming packets or dropping outgoing packets. Drivers and + applications that are experiencing packet loss should try calling the Poll() + function more often. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive + queue. Consider increasing the polling rate. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_POLL)( + IN EFI_DNS4_PROTOCOL *This + ); + +/** + Abort an asynchronous DNS operation, including translation between IP and Host, and + general look up behavior. + + The Cancel() function is used to abort a pending resolution request. After calling + this function, Token.Status will be set to EFI_ABORTED and then Token.Event will be + signaled. If the token is not in one of the queues, which usually means that the + asynchronous operation has completed, this function will not signal the token and + EFI_NOT_FOUND is returned. + + @param[in] This Pointer to EFI_DNS4_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_DNS4_PROTOCOL.HostNameToIp (), + EFI_DNS4_PROTOCOL.IpToHostName() or + EFI_DNS4_PROTOCOL.GeneralLookup(). + If NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI DNS4 Protocol instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS + operation was not found in the transmit queue. It + was either completed or was not issued by + HostNameToIp(), IpToHostName() or GeneralLookup(). +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS4_CANCEL)( + IN EFI_DNS4_PROTOCOL *This, + IN EFI_DNS4_COMPLETION_TOKEN *Token + ); + +/// +/// The EFI_DNS4_Protocol provides the function to get the host name and address +/// mapping, also provides pass through interface to retrieve arbitrary information +/// from DNS. +/// +struct _EFI_DNS4_PROTOCOL { + EFI_DNS4_GET_MODE_DATA GetModeData; + EFI_DNS4_CONFIGURE Configure; + EFI_DNS4_HOST_NAME_TO_IP HostNameToIp; + EFI_DNS4_IP_TO_HOST_NAME IpToHostName; + EFI_DNS4_GENERAL_LOOKUP GeneralLookUp; + EFI_DNS4_UPDATE_DNS_CACHE UpdateDnsCache; + EFI_DNS4_POLL Poll; + EFI_DNS4_CANCEL Cancel; +}; + +extern EFI_GUID gEfiDns4ServiceBindingProtocolGuid; +extern EFI_GUID gEfiDns4ProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/Protocol/Dns6.h b/src/include/ipxe/efi/Protocol/Dns6.h new file mode 100644 index 00000000..3b88c88e --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Dns6.h @@ -0,0 +1,535 @@ +/** @file + This file defines the EFI DNSv6 (Domain Name Service version 6) Protocol. It is split + into the following two main sections: + DNSv6 Service Binding Protocol (DNSv6SB) + DNSv6 Protocol (DNSv6) + + Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.5 + +**/ + +#ifndef __EFI_DNS6_PROTOCOL_H__ +#define __EFI_DNS6_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#define EFI_DNS6_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0x7f1647c8, 0xb76e, 0x44b2, {0xa5, 0x65, 0xf7, 0xf, 0xf1, 0x9c, 0xd1, 0x9e } \ + } + +#define EFI_DNS6_PROTOCOL_GUID \ + { \ + 0xca37bc1f, 0xa327, 0x4ae9, {0x82, 0x8a, 0x8c, 0x40, 0xd8, 0x50, 0x6a, 0x17 } \ + } + +typedef struct _EFI_DNS6_PROTOCOL EFI_DNS6_PROTOCOL; + +/// +/// EFI_DNS6_CONFIG_DATA +/// +typedef struct { + /// + /// If TRUE, enable DNS cache function for this DNS instance. If FALSE, all DNS query + /// will not lookup local DNS cache. + /// + BOOLEAN EnableDnsCache; + /// + /// Use the protocol number defined in + /// http://www.iana.org/assignments/protocol-numbers. Beside TCP/UDP, Other protocol + /// is invalid value. An implementation can choose to support UDP, or both TCP and UDP. + /// + UINT8 Protocol; + /// + /// The local IP address to use. Set to zero to let the underlying IPv6 + /// driver choose a source address. If not zero it must be one of the + /// configured IP addresses in the underlying IPv6 driver. + /// + EFI_IPv6_ADDRESS StationIp; + /// + /// Local port number. Set to zero to use the automatically assigned port number. + /// + UINT16 LocalPort; + /// + /// Count of the DNS servers. When used with GetModeData(), + /// this field is the count of originally configured servers when + /// Configure() was called for this instance. When used with + /// Configure() this is the count of caller-supplied servers. If the + /// DnsServerListCount is zero, the DNS server configuration + /// will be retrieved from DHCP server automatically. + /// + UINT32 DnsServerCount; + /// + /// Pointer to DNS server list containing DnsServerListCount + /// entries or NULL if DnsServerListCount is 0. For Configure(), + /// this will be NULL when there are no caller supplied server addresses + /// and the DNS instance will retrieve DNS server from DHCP Server. + /// The provided DNS server list is recommended to be filled up in the sequence + /// of preference. When used with GetModeData(), the buffer containing the list + /// will be allocated by the driver implementing this protocol and must be + /// freed by the caller. When used with Configure(), the buffer + /// containing the list will be allocated and released by the caller. + /// + EFI_IPv6_ADDRESS *DnsServerList; + /// + /// Retry number if no response received after RetryInterval. + /// + UINT32 RetryCount; + /// + /// Minimum interval of retry is 2 second. If the retry interval is less than 2 + /// seconds, then use the 2 seconds. + UINT32 RetryInterval; +} EFI_DNS6_CONFIG_DATA; + +/// +/// EFI_DNS6_CACHE_ENTRY +/// +typedef struct { + /// + /// Host name. This should be interpreted as Unicode characters. + /// + CHAR16 *HostName; + /// + /// IP address of this host. + /// + EFI_IPv6_ADDRESS *IpAddress; + /// + /// Time in second unit that this entry will remain in DNS cache. A value of zero means + /// that this entry is permanent. A nonzero value will override the existing one if + /// this entry to be added is dynamic entry. Implementations may set its default + /// timeout value for the dynamically created DNS cache entry after one DNS resolve + /// succeeds. + UINT32 Timeout; +} EFI_DNS6_CACHE_ENTRY; + +/// +/// EFI_DNS6_MODE_DATA +/// +typedef struct { + /// + /// The configuration data of this instance. + /// + EFI_DNS6_CONFIG_DATA DnsConfigData; + /// + /// Number of configured DNS6 servers. + /// + UINT32 DnsServerCount; + /// + /// Pointer to common list of addresses of all configured DNS server used by EFI_DNS6_PROTOCOL + /// instances. List will include DNS servers configured by this or any other EFI_DNS6_PROTOCOL + /// instance. The storage for this list is allocated by the driver publishing this protocol, + /// and must be freed by the caller. + /// + EFI_IPv6_ADDRESS *DnsServerList; + /// + /// Number of DNS Cache entries. The DNS Cache is shared among all DNS instances. + /// + UINT32 DnsCacheCount; + /// + /// Pointer to a buffer containing DnsCacheCount DNS Cache + /// entry structures. The storage for thislist is allocated by the driver + /// publishing this protocol and must be freed by caller. + /// + EFI_DNS6_CACHE_ENTRY *DnsCacheList; +} EFI_DNS6_MODE_DATA; + +/// +/// DNS6_HOST_TO_ADDR_DATA +/// +typedef struct { + /// + /// Number of the returned IP address. + /// + UINT32 IpCount; + /// + /// Pointer to the all the returned IP address. + /// + EFI_IPv6_ADDRESS *IpList; +} DNS6_HOST_TO_ADDR_DATA; + +/// +/// DNS6_ADDR_TO_HOST_DATA +/// +typedef struct { + /// + /// Pointer to the primary name for this host address. It's the caller's + /// responsibility to free the response memory. + /// + CHAR16 *HostName; +} DNS6_ADDR_TO_HOST_DATA; + +/// +/// DNS6_RESOURCE_RECORD +/// +typedef struct { + /// + /// The Owner name. + /// + CHAR8 *QName; + /// + /// The Type Code of this RR. + /// + UINT16 QType; + /// + /// The CLASS code of this RR. + /// + UINT16 QClass; + /// + /// 32 bit integer which specify the time interval that the resource record may be + /// cached before the source of the information should again be consulted. Zero means + /// this RR cannot be cached. + /// + UINT32 TTL; + /// + /// 16 big integer which specify the length of RData. + /// + UINT16 DataLength; + /// + /// A string of octets that describe the resource, the format of this information + /// varies according to QType and QClass difference. + /// + CHAR8 *RData; +} DNS6_RESOURCE_RECORD; + +/// +/// DNS6_GENERAL_LOOKUP_DATA +/// +typedef struct { + /// + /// Number of returned matching RRs. + /// + UINTN RRCount; + /// + /// Pointer to the all the returned matching RRs. It's caller responsibility to free + /// the allocated memory to hold the returned RRs. + /// + DNS6_RESOURCE_RECORD *RRList; +} DNS6_GENERAL_LOOKUP_DATA; + +/// +/// EFI_DNS6_COMPLETION_TOKEN +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by the EFI DNSv6 + /// protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. + /// + EFI_EVENT Event; + /// + /// Will be set to one of the following values: + /// EFI_SUCCESS: The host name to address translation completed successfully. + /// EFI_NOT_FOUND: No matching Resource Record (RR) is found. + /// EFI_TIMEOUT: No DNS server reachable, or RetryCount was exhausted without + /// response from all specified DNS servers. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// EFI_NO_MEDIA: There was a media error. + /// + EFI_STATUS Status; + /// + /// The parameter configured through DNSv6.Configure() interface. Retry number if no + /// response received after RetryInterval. + /// + UINT32 RetryCount; + /// + /// The parameter configured through DNSv6.Configure() interface. Minimum interval of + /// retry is 2 seconds. If the retry interval is less than 2 seconds, then use the 2 + /// seconds. + /// + UINT32 RetryInterval; + /// + /// DNSv6 completion token data + /// + union { + /// + /// When the Token is used for host name to address translation, H2AData is a pointer + /// to the DNS6_HOST_TO_ADDR_DATA. + /// + DNS6_HOST_TO_ADDR_DATA *H2AData; + /// + /// When the Token is used for host address to host name translation, A2HData is a + /// pointer to the DNS6_ADDR_TO_HOST_DATA. + /// + DNS6_ADDR_TO_HOST_DATA *A2HData; + /// + /// When the Token is used for a general lookup function, GLookupDATA is a pointer to + /// the DNS6_GENERAL_LOOKUP_DATA. + /// + DNS6_GENERAL_LOOKUP_DATA *GLookupData; + } RspData; +} EFI_DNS6_COMPLETION_TOKEN; + +/** + Retrieve mode data of this DNS instance. + + This function is used to retrieve DNS mode data for this DNS instance. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[out] DnsModeData Pointer to the caller-allocated storage for the + EFI_DNS6_MODE_DATA data. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_NOT_STARTED When DnsConfigData is queried, no configuration data + is available because this instance has not been + configured. + @retval EFI_INVALID_PARAMETER This is NULL or DnsModeData is NULL. + @retval EFI_OUT_OF_RESOURCE Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_GET_MODE_DATA)( + IN EFI_DNS6_PROTOCOL *This, + OUT EFI_DNS6_MODE_DATA *DnsModeData + ); + +/** + Configure this DNS instance. + + The Configure() function is used to set and change the configuration data for this + EFI DNSv6 Protocol driver instance. Reset the DNS instance if DnsConfigData is NULL. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] DnsConfigData Pointer to the configuration data structure. All associated + storage to be allocated and released by caller. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER This is NULL. + The StationIp address provided in DnsConfigData is not zero and not a valid unicast. + DnsServerList is NULL while DnsServerList Count is not ZERO. + DnsServerList Count is ZERO while DnsServerList is not NULL. + @retval EFI_OUT_OF_RESOURCES The DNS instance data or required space could not be allocated. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. The + EFI DNSv6 Protocol instance is not configured. + @retval EFI_UNSUPPORTED The designated protocol is not supported. + @retval EFI_ALREADY_STARTED Second call to Configure() with DnsConfigData. To + reconfigure the instance the caller must call Configure() with + NULL first to return driver to unconfigured state. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_CONFIGURE)( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_DNS6_CONFIG_DATA *DnsConfigData + ); + +/** + Host name to host address translation. + + The HostNameToIp () function is used to translate the host name to host IP address. A + type AAAA query is used to get the one or more IPv6 addresses for this host. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] HostName Host name. + @param[in] Token Point to the completion token to translate host name + to host address. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token.Event is NULL. + HostName is NULL or buffer contained unsupported characters. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_ALREADY_STARTED This Token is being used in another DNS session. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_HOST_NAME_TO_IP)( + IN EFI_DNS6_PROTOCOL *This, + IN CHAR16 *HostName, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/** + Host address to host name translation. + + The IpToHostName () function is used to translate the host address to host name. A + type PTR query is used to get the primary name of the host. Implementation can choose + to support this function or not. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] IpAddress Ip Address. + @param[in] Token Point to the completion token to translate host + address to host name. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED This function is not supported. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token.Event is NULL. + IpAddress is not valid IP address. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_IP_TO_HOST_NAME)( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_IPv6_ADDRESS IpAddress, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/** + This function provides capability to retrieve arbitrary information from the DNS + server. + + This GeneralLookup() function retrieves arbitrary information from the DNS. The caller + supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. All + RR content (e.g., TTL) was returned. The caller need parse the returned RR to get + required information. The function is optional. Implementation can choose to support + it or not. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] QName Pointer to Query Name. + @param[in] QType Query Type. + @param[in] QClass Query Name. + @param[in] Token Point to the completion token to retrieve arbitrary + information. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_UNSUPPORTED This function is not supported. Or the requested + QType is not supported + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token.Event is NULL. + QName is NULL. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_STARTED This instance has not been started. + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_GENERAL_LOOKUP)( + IN EFI_DNS6_PROTOCOL *This, + IN CHAR8 *QName, + IN UINT16 QType, + IN UINT16 QClass, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/** + This function is to update the DNS Cache. + + The UpdateDnsCache() function is used to add/delete/modify DNS cache entry. DNS cache + can be normally dynamically updated after the DNS resolve succeeds. This function + provided capability to manually add/delete/modify the DNS cache. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] DeleteFlag If FALSE, this function is to add one entry to the + DNS Cahce. If TRUE, this function will delete + matching DNS Cache entry. + @param[in] Override If TRUE, the maching DNS cache entry will be + overwritten with the supplied parameter. If FALSE, + EFI_ACCESS_DENIED will be returned if the entry to + be added is already existed. + @param[in] DnsCacheEntry Pointer to DNS Cache entry. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + DnsCacheEntry.HostName is NULL. + DnsCacheEntry.IpAddress is NULL. + DnsCacheEntry.Timeout is zero. + @retval EFI_ACCESS_DENIED The DNS cache entry already exists and Override is + not TRUE. + @retval EFI_OUT_OF_RESOURCE Failed to allocate needed resources. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_UPDATE_DNS_CACHE)( + IN EFI_DNS6_PROTOCOL *This, + IN BOOLEAN DeleteFlag, + IN BOOLEAN Override, + IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry + ); + +/** + Polls for incoming data packets and processes outgoing data packets. + + The Poll() function can be used by network drivers and applications to increase the + rate that data packets are moved between the communications device and the transmit + and receive queues. + + In some systems, the periodic timer event in the managed network driver may not poll + the underlying communications device fast enough to transmit and/or receive all data + packets without missing incoming packets or dropping outgoing packets. Drivers and + applications that are experiencing packet loss should try calling the Poll() + function more often. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI DNS Protocol instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NO_MAPPING There is no source address is available for use. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit and/or receive + queue. Consider increasing the polling rate. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_POLL)( + IN EFI_DNS6_PROTOCOL *This + ); + +/** + Abort an asynchronous DNS operation, including translation between IP and Host, and + general look up behavior. + + The Cancel() function is used to abort a pending resolution request. After calling + this function, Token.Status will be set to EFI_ABORTED and then Token.Event will be + signaled. If the token is not in one of the queues, which usually means that the + asynchronous operation has completed, this function will not signal the token and + EFI_NOT_FOUND is returned. + + @param[in] This Pointer to EFI_DNS6_PROTOCOL instance. + @param[in] Token Pointer to a token that has been issued by + EFI_DNS6_PROTOCOL.HostNameToIp (), + EFI_DNS6_PROTOCOL.IpToHostName() or + EFI_DNS6_PROTOCOL.GeneralLookup(). + If NULL, all pending tokens are aborted. + + @retval EFI_SUCCESS Incoming or outgoing data was processed. + @retval EFI_NOT_STARTED This EFI DNS6 Protocol instance has not been started. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NO_MAPPING There's no source address is available for use. + @retval EFI_NOT_FOUND When Token is not NULL, and the asynchronous DNS + operation was not found in the transmit queue. It + was either completed or was not issued by + HostNameToIp(), IpToHostName() or GeneralLookup(). +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_DNS6_CANCEL)( + IN EFI_DNS6_PROTOCOL *This, + IN EFI_DNS6_COMPLETION_TOKEN *Token + ); + +/// +/// The EFI_DNS6_PROTOCOL provides the function to get the host name and address +/// mapping, also provide pass through interface to retrieve arbitrary information from +/// DNSv6. +/// +struct _EFI_DNS6_PROTOCOL { + EFI_DNS6_GET_MODE_DATA GetModeData; + EFI_DNS6_CONFIGURE Configure; + EFI_DNS6_HOST_NAME_TO_IP HostNameToIp; + EFI_DNS6_IP_TO_HOST_NAME IpToHostName; + EFI_DNS6_GENERAL_LOOKUP GeneralLookUp; + EFI_DNS6_UPDATE_DNS_CACHE UpdateDnsCache; + EFI_DNS6_POLL Poll; + EFI_DNS6_CANCEL Cancel; +}; + +extern EFI_GUID gEfiDns6ServiceBindingProtocolGuid; +extern EFI_GUID gEfiDns6ProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 86a3c2f9..fd3a5434 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -187,6 +187,10 @@ extern EFI_GUID efi_dhcp4_service_binding_protocol_guid; extern EFI_GUID efi_dhcp6_protocol_guid; extern EFI_GUID efi_dhcp6_service_binding_protocol_guid; extern EFI_GUID efi_disk_io_protocol_guid; +extern EFI_GUID efi_dns4_protocol_guid; +extern EFI_GUID efi_dns4_service_binding_protocol_guid; +extern EFI_GUID efi_dns6_protocol_guid; +extern EFI_GUID efi_dns6_service_binding_protocol_guid; extern EFI_GUID efi_driver_binding_protocol_guid; extern EFI_GUID efi_graphics_output_protocol_guid; extern EFI_GUID efi_hii_config_access_protocol_guid; diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index dec6b6e6..7205c699 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -105,6 +105,14 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Dhcp6Sb" }, { &efi_disk_io_protocol_guid, "DiskIo" }, + { &efi_dns4_protocol_guid, + "Dns4" }, + { &efi_dns4_service_binding_protocol_guid, + "Dns4Sb" }, + { &efi_dns6_protocol_guid, + "Dns6" }, + { &efi_dns6_service_binding_protocol_guid, + "Dns6Sb" }, { &efi_graphics_output_protocol_guid, "GraphicsOutput" }, { &efi_hii_config_access_protocol_guid, diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c index 4a76bdac..388a9c99 100644 --- a/src/interface/efi/efi_guid.c +++ b/src/interface/efi/efi_guid.c @@ -39,6 +39,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include +#include #include #include #include @@ -159,6 +161,22 @@ EFI_GUID efi_dhcp6_service_binding_protocol_guid EFI_GUID efi_disk_io_protocol_guid = EFI_DISK_IO_PROTOCOL_GUID; +/** DNSv4 protocol GUID */ +EFI_GUID efi_dns4_protocol_guid + = EFI_DNS4_PROTOCOL_GUID; + +/** DNSv4 service binding protocol GUID */ +EFI_GUID efi_dns4_service_binding_protocol_guid + = EFI_DNS4_SERVICE_BINDING_PROTOCOL_GUID; + +/** DNSv6 protocol GUID */ +EFI_GUID efi_dns6_protocol_guid + = EFI_DNS6_PROTOCOL_GUID; + +/** DNSv6 service binding protocol GUID */ +EFI_GUID efi_dns6_service_binding_protocol_guid + = EFI_DNS6_SERVICE_BINDING_PROTOCOL_GUID; + /** Driver binding protocol GUID */ EFI_GUID efi_driver_binding_protocol_guid = EFI_DRIVER_BINDING_PROTOCOL_GUID; -- cgit v1.2.3-55-g7522 From a64764d10fd78333c0696927a1009877388619d4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:44:56 +0100 Subject: [efi] Add HTTP header and GUID definitions Signed-off-by: Michael Brown --- src/include/ipxe/efi/Protocol/Http.h | 516 +++++++++++++++++++++++++++++++++++ src/include/ipxe/efi/efi.h | 2 + src/interface/efi/efi_debug.c | 4 + src/interface/efi/efi_guid.c | 9 + 4 files changed, 531 insertions(+) create mode 100644 src/include/ipxe/efi/Protocol/Http.h diff --git a/src/include/ipxe/efi/Protocol/Http.h b/src/include/ipxe/efi/Protocol/Http.h new file mode 100644 index 00000000..d30a5aa4 --- /dev/null +++ b/src/include/ipxe/efi/Protocol/Http.h @@ -0,0 +1,516 @@ +/** @file + This file defines the EFI HTTP Protocol interface. It is split into + the following two main sections: + HTTP Service Binding Protocol (HTTPSB) + HTTP Protocol (HTTP) + + Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
+ (C) Copyright 2015-2017 Hewlett Packard Enterprise Development LP
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + This Protocol is introduced in UEFI Specification 2.5 + +**/ + +#ifndef __EFI_HTTP_PROTOCOL_H__ +#define __EFI_HTTP_PROTOCOL_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#define EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID \ + { \ + 0xbdc8e6af, 0xd9bc, 0x4379, {0xa7, 0x2a, 0xe0, 0xc4, 0xe7, 0x5d, 0xae, 0x1c } \ + } + +#define EFI_HTTP_PROTOCOL_GUID \ + { \ + 0x7a59b29b, 0x910b, 0x4171, {0x82, 0x42, 0xa8, 0x5a, 0x0d, 0xf2, 0x5b, 0x5b } \ + } + +typedef struct _EFI_HTTP_PROTOCOL EFI_HTTP_PROTOCOL; + +/// +/// EFI_HTTP_VERSION +/// +typedef enum { + HttpVersion10, + HttpVersion11, + HttpVersionUnsupported +} EFI_HTTP_VERSION; + +/// +/// EFI_HTTP_METHOD +/// +typedef enum { + HttpMethodGet, + HttpMethodPost, + HttpMethodPatch, + HttpMethodOptions, + HttpMethodConnect, + HttpMethodHead, + HttpMethodPut, + HttpMethodDelete, + HttpMethodTrace, + HttpMethodMax +} EFI_HTTP_METHOD; + +/// +/// EFI_HTTP_STATUS_CODE +/// +typedef enum { + HTTP_STATUS_UNSUPPORTED_STATUS = 0, + HTTP_STATUS_100_CONTINUE, + HTTP_STATUS_101_SWITCHING_PROTOCOLS, + HTTP_STATUS_200_OK, + HTTP_STATUS_201_CREATED, + HTTP_STATUS_202_ACCEPTED, + HTTP_STATUS_203_NON_AUTHORITATIVE_INFORMATION, + HTTP_STATUS_204_NO_CONTENT, + HTTP_STATUS_205_RESET_CONTENT, + HTTP_STATUS_206_PARTIAL_CONTENT, + HTTP_STATUS_300_MULTIPLE_CHOICES, + HTTP_STATUS_301_MOVED_PERMANENTLY, + HTTP_STATUS_302_FOUND, + HTTP_STATUS_303_SEE_OTHER, + HTTP_STATUS_304_NOT_MODIFIED, + HTTP_STATUS_305_USE_PROXY, + HTTP_STATUS_307_TEMPORARY_REDIRECT, + HTTP_STATUS_400_BAD_REQUEST, + HTTP_STATUS_401_UNAUTHORIZED, + HTTP_STATUS_402_PAYMENT_REQUIRED, + HTTP_STATUS_403_FORBIDDEN, + HTTP_STATUS_404_NOT_FOUND, + HTTP_STATUS_405_METHOD_NOT_ALLOWED, + HTTP_STATUS_406_NOT_ACCEPTABLE, + HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED, + HTTP_STATUS_408_REQUEST_TIME_OUT, + HTTP_STATUS_409_CONFLICT, + HTTP_STATUS_410_GONE, + HTTP_STATUS_411_LENGTH_REQUIRED, + HTTP_STATUS_412_PRECONDITION_FAILED, + HTTP_STATUS_413_REQUEST_ENTITY_TOO_LARGE, + HTTP_STATUS_414_REQUEST_URI_TOO_LARGE, + HTTP_STATUS_415_UNSUPPORTED_MEDIA_TYPE, + HTTP_STATUS_416_REQUESTED_RANGE_NOT_SATISFIED, + HTTP_STATUS_417_EXPECTATION_FAILED, + HTTP_STATUS_500_INTERNAL_SERVER_ERROR, + HTTP_STATUS_501_NOT_IMPLEMENTED, + HTTP_STATUS_502_BAD_GATEWAY, + HTTP_STATUS_503_SERVICE_UNAVAILABLE, + HTTP_STATUS_504_GATEWAY_TIME_OUT, + HTTP_STATUS_505_HTTP_VERSION_NOT_SUPPORTED, + HTTP_STATUS_308_PERMANENT_REDIRECT +} EFI_HTTP_STATUS_CODE; + +/// +/// EFI_HTTPv4_ACCESS_POINT +/// +typedef struct { + /// + /// Set to TRUE to instruct the EFI HTTP instance to use the default address + /// information in every TCP connection made by this instance. In addition, when set + /// to TRUE, LocalAddress and LocalSubnet are ignored. + /// + BOOLEAN UseDefaultAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local IP address to be + /// used in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalAddress; + /// + /// If UseDefaultAddress is set to FALSE, this defines the local subnet to be used + /// in every TCP connection opened by this instance. + /// + EFI_IPv4_ADDRESS LocalSubnet; + /// + /// This defines the local port to be used in + /// every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv4_ACCESS_POINT; + +/// +/// EFI_HTTPv6_ACCESS_POINT +/// +typedef struct { + /// + /// Local IP address to be used in every TCP connection opened by this instance. + /// + EFI_IPv6_ADDRESS LocalAddress; + /// + /// Local port to be used in every TCP connection opened by this instance. + /// + UINT16 LocalPort; +} EFI_HTTPv6_ACCESS_POINT; + +/// +/// EFI_HTTP_CONFIG_DATA_ACCESS_POINT +/// + +typedef struct { + /// + /// HTTP version that this instance will support. + /// + EFI_HTTP_VERSION HttpVersion; + /// + /// Time out (in milliseconds) when blocking for requests. + /// + UINT32 TimeOutMillisec; + /// + /// Defines behavior of EFI DNS and TCP protocols consumed by this instance. If + /// FALSE, this instance will use EFI_DNS4_PROTOCOL and EFI_TCP4_PROTOCOL. If TRUE, + /// this instance will use EFI_DNS6_PROTOCOL and EFI_TCP6_PROTOCOL. + /// + BOOLEAN LocalAddressIsIPv6; + + union { + /// + /// When LocalAddressIsIPv6 is FALSE, this points to the local address, subnet, and + /// port used by the underlying TCP protocol. + /// + EFI_HTTPv4_ACCESS_POINT *IPv4Node; + /// + /// When LocalAddressIsIPv6 is TRUE, this points to the local IPv6 address and port + /// used by the underlying TCP protocol. + /// + EFI_HTTPv6_ACCESS_POINT *IPv6Node; + } AccessPoint; +} EFI_HTTP_CONFIG_DATA; + +/// +/// EFI_HTTP_REQUEST_DATA +/// +typedef struct { + /// + /// The HTTP method (e.g. GET, POST) for this HTTP Request. + /// + EFI_HTTP_METHOD Method; + /// + /// The URI of a remote host. From the information in this field, the HTTP instance + /// will be able to determine whether to use HTTP or HTTPS and will also be able to + /// determine the port number to use. If no port number is specified, port 80 (HTTP) + /// is assumed. See RFC 3986 for more details on URI syntax. + /// + CHAR16 *Url; +} EFI_HTTP_REQUEST_DATA; + +/// +/// EFI_HTTP_RESPONSE_DATA +/// +typedef struct { + /// + /// Response status code returned by the remote host. + /// + EFI_HTTP_STATUS_CODE StatusCode; +} EFI_HTTP_RESPONSE_DATA; + +/// +/// EFI_HTTP_HEADER +/// +typedef struct { + /// + /// Null terminated string which describes a field name. See RFC 2616 Section 14 for + /// detailed information about field names. + /// + CHAR8 *FieldName; + /// + /// Null terminated string which describes the corresponding field value. See RFC 2616 + /// Section 14 for detailed information about field values. + /// + CHAR8 *FieldValue; +} EFI_HTTP_HEADER; + +/// +/// EFI_HTTP_MESSAGE +/// +typedef struct { + /// + /// HTTP message data. + /// + union { + /// + /// When the token is used to send a HTTP request, Request is a pointer to storage that + /// contains such data as URL and HTTP method. + /// + EFI_HTTP_REQUEST_DATA *Request; + /// + /// When used to await a response, Response points to storage containing HTTP response + /// status code. + /// + EFI_HTTP_RESPONSE_DATA *Response; + } Data; + /// + /// Number of HTTP header structures in Headers list. On request, this count is + /// provided by the caller. On response, this count is provided by the HTTP driver. + /// + UINTN HeaderCount; + /// + /// Array containing list of HTTP headers. On request, this array is populated by the + /// caller. On response, this array is allocated and populated by the HTTP driver. It + /// is the responsibility of the caller to free this memory on both request and + /// response. + /// + EFI_HTTP_HEADER *Headers; + /// + /// Length in bytes of the HTTP body. This can be zero depending on the HttpMethod type. + /// + UINTN BodyLength; + /// + /// Body associated with the HTTP request or response. This can be NULL depending on + /// the HttpMethod type. + /// + VOID *Body; +} EFI_HTTP_MESSAGE; + +/// +/// EFI_HTTP_TOKEN +/// +typedef struct { + /// + /// This Event will be signaled after the Status field is updated by the EFI HTTP + /// Protocol driver. The type of Event must be EFI_NOTIFY_SIGNAL. The Task Priority + /// Level (TPL) of Event must be lower than or equal to TPL_CALLBACK. + /// + EFI_EVENT Event; + /// + /// Status will be set to one of the following value if the HTTP request is + /// successfully sent or if an unexpected error occurs: + /// EFI_SUCCESS: The HTTP request was successfully sent to the remote host. + /// EFI_HTTP_ERROR: The response message was successfully received but contains a + /// HTTP error. The response status code is returned in token. + /// EFI_ABORTED: The HTTP request was cancelled by the caller and removed from + /// the transmit queue. + /// EFI_TIMEOUT: The HTTP request timed out before reaching the remote host. + /// EFI_DEVICE_ERROR: An unexpected system or network error occurred. + /// + EFI_STATUS Status; + /// + /// Pointer to storage containing HTTP message data. + /// + EFI_HTTP_MESSAGE *Message; +} EFI_HTTP_TOKEN; + +/** + Returns the operational parameters for the current HTTP child instance. + + The GetModeData() function is used to read the current mode data (operational + parameters) for this HTTP protocol instance. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[out] HttpConfigData Point to buffer for operational parameters of this + HTTP instance. It is the responsibility of the caller + to allocate the memory for HttpConfigData and + HttpConfigData->AccessPoint.IPv6Node/IPv4Node. In fact, + it is recommended to allocate sufficient memory to record + IPv6Node since it is big enough for all possibilities. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER This is NULL. + HttpConfigData is NULL. + HttpConfigData->AccessPoint.IPv4Node or + HttpConfigData->AccessPoint.IPv6Node is NULL. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_GET_MODE_DATA)( + IN EFI_HTTP_PROTOCOL *This, + OUT EFI_HTTP_CONFIG_DATA *HttpConfigData + ); + +/** + Initialize or brutally reset the operational parameters for this EFI HTTP instance. + + The Configure() function does the following: + When HttpConfigData is not NULL Initialize this EFI HTTP instance by configuring + timeout, local address, port, etc. + When HttpConfigData is NULL, reset this EFI HTTP instance by closing all active + connections with remote hosts, canceling all asynchronous tokens, and flush request + and response buffers without informing the appropriate hosts. + + No other EFI HTTP function can be executed by this instance until the Configure() + function is executed and returns successfully. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] HttpConfigData Pointer to the configure data to configure the instance. + + @retval EFI_SUCCESS Operation succeeded. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + HttpConfigData->LocalAddressIsIPv6 is FALSE and + HttpConfigData->AccessPoint.IPv4Node is NULL. + HttpConfigData->LocalAddressIsIPv6 is TRUE and + HttpConfigData->AccessPoint.IPv6Node is NULL. + @retval EFI_ALREADY_STARTED Reinitialize this HTTP instance without calling + Configure() with NULL to reset it. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources when + executing Configure(). + @retval EFI_UNSUPPORTED One or more options in ConfigData are not supported + in the implementation. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_CONFIGURE)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_CONFIG_DATA *HttpConfigData OPTIONAL + ); + +/** + The Request() function queues an HTTP request to this HTTP instance, + similar to Transmit() function in the EFI TCP driver. When the HTTP request is sent + successfully, or if there is an error, Status in token will be updated and Event will + be signaled. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP request token. + + @retval EFI_SUCCESS Outgoing data was processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred. + @retval EFI_TIMEOUT Data was dropped out of the transmit or receive queue. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Request()has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_UNSUPPORTED The HTTP method is not supported in current implementation. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_REQUEST)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + Abort an asynchronous HTTP request or response token. + + The Cancel() function aborts a pending HTTP request or response transaction. If + Token is not NULL and the token is in transmit or receive queues when it is being + cancelled, its Token->Status will be set to EFI_ABORTED and then Token->Event will + be signaled. If the token is not in one of the queues, which usually means that the + asynchronous operation has completed, EFI_NOT_FOUND is returned. If Token is NULL, + all asynchronous tokens issued by Request() or Response() will be aborted. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Point to storage containing HTTP request or response + token. + + @retval EFI_SUCCESS Request and Response queues are successfully flushed. + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_STARTED This instance hasn't been configured. + @retval EFI_NOT_FOUND The asynchronous request or response token is not + found. + @retval EFI_UNSUPPORTED The implementation does not support this function. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_CANCEL)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Response() function queues an HTTP response to this HTTP instance, similar to + Receive() function in the EFI TCP driver. When the HTTP Response is received successfully, + or if there is an error, Status in token will be updated and Event will be signaled. + + The HTTP driver will queue a receive token to the underlying TCP instance. When data + is received in the underlying TCP instance, the data will be parsed and Token will + be populated with the response data. If the data received from the remote host + contains an incomplete or invalid HTTP header, the HTTP driver will continue waiting + (asynchronously) for more data to be sent from the remote host before signaling + Event in Token. + + It is the responsibility of the caller to allocate a buffer for Body and specify the + size in BodyLength. If the remote host provides a response that contains a content + body, up to BodyLength bytes will be copied from the receive buffer into Body and + BodyLength will be updated with the amount of bytes received and copied to Body. This + allows the client to download a large file in chunks instead of into one contiguous + block of memory. Similar to HTTP request, if Body is not NULL and BodyLength is + non-zero and all other fields are NULL or 0, the HTTP driver will queue a receive + token to underlying TCP instance. If data arrives in the receive buffer, up to + BodyLength bytes of data will be copied to Body. The HTTP driver will then update + BodyLength with the amount of bytes received and copied to Body. + + If the HTTP driver does not have an open underlying TCP connection with the host + specified in the response URL, Request() will return EFI_ACCESS_DENIED. This is + consistent with RFC 2616 recommendation that HTTP clients should attempt to maintain + an open TCP connection between client and host. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + @param[in] Token Pointer to storage containing HTTP response token. + + @retval EFI_SUCCESS Allocation succeeded. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been + initialized. + @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE: + This is NULL. + Token is NULL. + Token->Message->Headers is NULL. + Token->Message is NULL. + Token->Message->Body is not NULL, + Token->Message->BodyLength is non-zero, and + Token->Message->Data is NULL, but a previous call to + Response() has not been completed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough system resources. + @retval EFI_ACCESS_DENIED An open TCP connection is not present with the host + specified by response URL. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_RESPONSE)( + IN EFI_HTTP_PROTOCOL *This, + IN EFI_HTTP_TOKEN *Token + ); + +/** + The Poll() function can be used by network drivers and applications to increase the + rate that data packets are moved between the communication devices and the transmit + and receive queues. + + In some systems, the periodic timer event in the managed network driver may not poll + the underlying communications device fast enough to transmit and/or receive all data + packets without missing incoming packets or dropping outgoing packets. Drivers and + applications that are experiencing packet loss should try calling the Poll() function + more often. + + @param[in] This Pointer to EFI_HTTP_PROTOCOL instance. + + @retval EFI_SUCCESS Incoming or outgoing data was processed.. + @retval EFI_DEVICE_ERROR An unexpected system or network error occurred + @retval EFI_INVALID_PARAMETER This is NULL. + @retval EFI_NOT_READY No incoming or outgoing data is processed. + @retval EFI_NOT_STARTED This EFI HTTP Protocol instance has not been started. +**/ +typedef +EFI_STATUS +(EFIAPI *EFI_HTTP_POLL)( + IN EFI_HTTP_PROTOCOL *This + ); + +/// +/// The EFI HTTP protocol is designed to be used by EFI drivers and applications to +/// create and transmit HTTP Requests, as well as handle HTTP responses that are +/// returned by a remote host. This EFI protocol uses and relies on an underlying EFI +/// TCP protocol. +/// +struct _EFI_HTTP_PROTOCOL { + EFI_HTTP_GET_MODE_DATA GetModeData; + EFI_HTTP_CONFIGURE Configure; + EFI_HTTP_REQUEST Request; + EFI_HTTP_CANCEL Cancel; + EFI_HTTP_RESPONSE Response; + EFI_HTTP_POLL Poll; +}; + +extern EFI_GUID gEfiHttpServiceBindingProtocolGuid; +extern EFI_GUID gEfiHttpProtocolGuid; + +#endif diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index fd3a5434..0bf16e30 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -195,6 +195,8 @@ extern EFI_GUID efi_driver_binding_protocol_guid; extern EFI_GUID efi_graphics_output_protocol_guid; extern EFI_GUID efi_hii_config_access_protocol_guid; extern EFI_GUID efi_hii_font_protocol_guid; +extern EFI_GUID efi_http_protocol_guid; +extern EFI_GUID efi_http_service_binding_protocol_guid; extern EFI_GUID efi_ip4_protocol_guid; extern EFI_GUID efi_ip4_config_protocol_guid; extern EFI_GUID efi_ip4_config2_protocol_guid; diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 7205c699..f84f7561 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -119,6 +119,10 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "HiiConfigAccess" }, { &efi_hii_font_protocol_guid, "HiiFont" }, + { &efi_http_protocol_guid, + "Http" }, + { &efi_http_service_binding_protocol_guid, + "HttpSb" }, { &efi_ip4_protocol_guid, "Ip4" }, { &efi_ip4_config_protocol_guid, diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c index 388a9c99..f841448f 100644 --- a/src/interface/efi/efi_guid.c +++ b/src/interface/efi/efi_guid.c @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -193,6 +194,14 @@ EFI_GUID efi_hii_config_access_protocol_guid EFI_GUID efi_hii_font_protocol_guid = EFI_HII_FONT_PROTOCOL_GUID; +/** HTTP protocol GUID */ +EFI_GUID efi_http_protocol_guid + = EFI_HTTP_PROTOCOL_GUID; + +/** HTTP service binding protocol GUID */ +EFI_GUID efi_http_service_binding_protocol_guid + = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID; + /** IPv4 protocol GUID */ EFI_GUID efi_ip4_protocol_guid = EFI_IP4_PROTOCOL_GUID; -- cgit v1.2.3-55-g7522 From b9a60fb0b745a9df7ecf7704b5a4881e022b0a9f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:29:44 +0100 Subject: [efi] Add new IScsiDxe module GUID The old IPv4-only IScsiDxe driver in MdeModulePkg/Universal/Network was replaced by a dual-stack IScsiDxe driver in NetworkPkg. Add the module GUID for this driver. Signed-off-by: Michael Brown --- src/interface/efi/efi_debug.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index f84f7561..36f5a13e 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -47,7 +47,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *efidpt; EFI_REQUEST_PROTOCOL ( EFI_DEVICE_PATH_TO_TEXT_PROTOCOL, &efidpt ); -/** Iscsi4Dxe module GUID */ +/** IScsiDxe module GUID */ +static EFI_GUID efi_iscsi_dxe_guid = { + 0x86cddf93, 0x4872, 0x4597, + { 0x8a, 0xf9, 0xa3, 0x5a, 0xe4, 0xd3, 0x72, 0x5f } +}; + +/** Old IScsi4Dxe module GUID */ static EFI_GUID efi_iscsi4_dxe_guid = { 0x4579b72d, 0x7ec4, 0x4dd4, { 0x84, 0x86, 0x08, 0x3c, 0x86, 0xb1, 0x82, 0xa7 } @@ -137,6 +143,8 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Ip6Config" }, { &efi_ip6_service_binding_protocol_guid, "Ip6Sb" }, + { &efi_iscsi_dxe_guid, + "IScsiDxe" }, { &efi_iscsi4_dxe_guid, "IScsi4Dxe" }, { &efi_load_file_protocol_guid, -- cgit v1.2.3-55-g7522 From 367e022b5e28cbdcbda525c0ccc2347d029efea2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:46:49 +0100 Subject: [efi] Add HttpBootDxe module GUID Signed-off-by: Michael Brown --- src/interface/efi/efi_debug.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 36f5a13e..250bc013 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -47,6 +47,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *efidpt; EFI_REQUEST_PROTOCOL ( EFI_DEVICE_PATH_TO_TEXT_PROTOCOL, &efidpt ); +/** HttpBootDxe module GUID */ +static EFI_GUID efi_http_boot_dxe_guid = { + 0xecebcb00, 0xd9c8, 0x11e4, + { 0xaf, 0x3d, 0x8c, 0xdc, 0xd4, 0x26, 0xc9, 0x73 } +}; + /** IScsiDxe module GUID */ static EFI_GUID efi_iscsi_dxe_guid = { 0x86cddf93, 0x4872, 0x4597, @@ -125,6 +131,8 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "HiiConfigAccess" }, { &efi_hii_font_protocol_guid, "HiiFont" }, + { &efi_http_boot_dxe_guid, + "HttpBootDxe" }, { &efi_http_protocol_guid, "Http" }, { &efi_http_service_binding_protocol_guid, -- cgit v1.2.3-55-g7522 From 12776acce5e62af39797e8b692de12369e11f6a2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Jun 2023 12:48:55 +0100 Subject: [efi] Add UefiPxeBcDxe module GUID Signed-off-by: Michael Brown --- src/interface/efi/efi_debug.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 250bc013..1bec758f 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -65,6 +65,12 @@ static EFI_GUID efi_iscsi4_dxe_guid = { { 0x84, 0x86, 0x08, 0x3c, 0x86, 0xb1, 0x82, 0xa7 } }; +/** UefiPxeBcDxe module GUID */ +static EFI_GUID efi_uefi_pxe_bc_dxe_guid = { + 0xb95e9fda, 0x26de, 0x48d2, + { 0x88, 0x07, 0x1f, 0x91, 0x07, 0xac, 0x5e, 0x3a } +}; + /** VlanConfigDxe module GUID */ static EFI_GUID efi_vlan_config_dxe_guid = { 0xe4f61863, 0xfe2c, 0x4b56, @@ -221,6 +227,8 @@ static struct efi_well_known_guid efi_well_known_guids[] = { "Udp6" }, { &efi_udp6_service_binding_protocol_guid, "Udp6Sb" }, + { &efi_uefi_pxe_bc_dxe_guid, + "UefiPxeBcDxe" }, { &efi_uga_draw_protocol_guid, "UgaDraw" }, { &efi_unicode_collation_protocol_guid, -- cgit v1.2.3-55-g7522 From 8ab9bdca4f3aa5dbd6c277e5340b4071b952e061 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 8 Jun 2023 11:15:27 +0100 Subject: [efi] Include protocol interface address in debug output Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi.h | 13 +++++++++++++ src/interface/efi/efi_debug.c | 34 +++++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 0bf16e30..2137b824 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -269,6 +269,7 @@ efi_handle_name ( EFI_HANDLE handle ); extern void dbg_efi_opener ( EFI_HANDLE handle, EFI_GUID *protocol, EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener ); extern void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ); +extern void dbg_efi_protocol ( EFI_HANDLE handle, EFI_GUID *protocol ); extern void dbg_efi_protocols ( EFI_HANDLE handle ); #define DBG_EFI_OPENER_IF( level, handle, protocol, \ @@ -303,6 +304,12 @@ extern void dbg_efi_protocols ( EFI_HANDLE handle ); DBG_DC_IF ( level ); \ } while ( 0 ) +#define DBGC_EFI_PROTOCOL_IF( level, id, ... ) do { \ + DBG_AC_IF ( level, id ); \ + DBG_EFI_PROTOCOL_IF ( level, __VA_ARGS__ ); \ + DBG_DC_IF ( level ); \ + } while ( 0 ) + #define DBGC_EFI_PROTOCOLS_IF( level, id, ... ) do { \ DBG_AC_IF ( level, id ); \ DBG_EFI_PROTOCOLS_IF ( level, __VA_ARGS__ ); \ @@ -313,6 +320,8 @@ extern void dbg_efi_protocols ( EFI_HANDLE handle ); DBGC_EFI_OPENER_IF ( LOG, ##__VA_ARGS__ ) #define DBGC_EFI_OPENERS( ... ) \ DBGC_EFI_OPENERS_IF ( LOG, ##__VA_ARGS__ ) +#define DBGC_EFI_PROTOCOL( ... ) \ + DBGC_EFI_PROTOCOL_IF ( LOG, ##__VA_ARGS__ ) #define DBGC_EFI_PROTOCOLS( ... ) \ DBGC_EFI_PROTOCOLS_IF ( LOG, ##__VA_ARGS__ ) @@ -320,6 +329,8 @@ extern void dbg_efi_protocols ( EFI_HANDLE handle ); DBGC_EFI_OPENER_IF ( EXTRA, ##__VA_ARGS__ ) #define DBGC2_EFI_OPENERS( ... ) \ DBGC_EFI_OPENERS_IF ( EXTRA, ##__VA_ARGS__ ) +#define DBGC2_EFI_PROTOCOL( ... ) \ + DBGC_EFI_PROTOCOL_IF ( EXTRA, ##__VA_ARGS__ ) #define DBGC2_EFI_PROTOCOLS( ... ) \ DBGC_EFI_PROTOCOLS_IF ( EXTRA, ##__VA_ARGS__ ) @@ -327,6 +338,8 @@ extern void dbg_efi_protocols ( EFI_HANDLE handle ); DBGC_EFI_OPENER_IF ( PROFILE, ##__VA_ARGS__ ) #define DBGCP_EFI_OPENERS( ... ) \ DBGC_EFI_OPENERS_IF ( PROFILE, ##__VA_ARGS__ ) +#define DBGCP_EFI_PROTOCOL( ... ) \ + DBGC_EFI_PROTOCOL_IF ( PROFILE, ##__VA_ARGS__ ) #define DBGCP_EFI_PROTOCOLS( ... ) \ DBGC_EFI_PROTOCOLS_IF ( PROFILE, ##__VA_ARGS__ ) diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c index 1bec758f..1372776f 100644 --- a/src/interface/efi/efi_debug.c +++ b/src/interface/efi/efi_debug.c @@ -386,6 +386,34 @@ void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) { bs->FreePool ( openers ); } +/** + * Print protocol information on a given handle + * + * @v handle EFI handle + * @v protocol Protocol GUID + */ +void dbg_efi_protocol ( EFI_HANDLE handle, EFI_GUID *protocol ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + VOID *interface; + EFI_STATUS efirc; + int rc; + + /* Get protocol instance */ + if ( ( efirc = bs->HandleProtocol ( handle, protocol, + &interface ) ) != 0 ) { + rc = -EEFI ( efirc ); + printf ( "HANDLE %s could not identify %s: %s\n", + efi_handle_name ( handle ), + efi_guid_ntoa ( protocol ), strerror ( rc ) ); + return; + } + printf ( "HANDLE %s %s at %p\n", efi_handle_name ( handle ), + efi_guid_ntoa ( protocol ), interface ); + + /* Dump list of openers */ + dbg_efi_openers ( handle, protocol ); +} + /** * Print list of protocol handlers attached to a handle * @@ -394,7 +422,6 @@ void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) { void dbg_efi_protocols ( EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_GUID **protocols; - EFI_GUID *protocol; UINTN count; unsigned int i; EFI_STATUS efirc; @@ -417,10 +444,7 @@ void dbg_efi_protocols ( EFI_HANDLE handle ) { /* Dump list of protocols */ for ( i = 0 ; i < count ; i++ ) { - protocol = protocols[i]; - printf ( "HANDLE %s %s supported\n", efi_handle_name ( handle ), - efi_guid_ntoa ( protocol ) ); - dbg_efi_openers ( handle, protocol ); + dbg_efi_protocol ( handle, protocols[i] ); } /* Free list */ -- cgit v1.2.3-55-g7522 From 25a3d3acabeec97c4a4cb8ed8fb90853e8a195c3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 8 Jun 2023 11:29:07 +0100 Subject: [efi] Veto the VMware UefiPxeBcDxe driver The EDK2 UefiPxeBcDxe driver includes some remarkably convoluted and unsafe logic in its driver binding protocol Start() and Stop() methods in order to support a pair of nominally independent driver binding protocols (one for IPv4, one for IPv6) sharing a single dynamically allocated data structure. This PXEBC_PRIVATE_DATA structure is installed as a dummy protocol on the NIC handle in order to allow both IPv4 and IPv6 driver binding protocols to locate it as needed. The error handling code path in the UefiPxeBcDxe driver's Start() method may attempt to uninstall the dummy protocol but fail to do so. This failure is ignored and the containing memory is subsequently freed anyway. On the next invocation of the driver binding protocol, it will find and use this already freed block of memory. At some point another memory allocation will occur, the PXEBC_PRIVATE_DATA structure will be corrupted, and some undefined behaviour will occur. The UEFI firmware used in VMware ESX 8 includes some proprietary changes which attempt to install copies of the EFI_LOAD_FILE_PROTOCOL and EFI_PXE_BASE_CODE_PROTOCOL instances from the IPv4 child handle onto the NIC handle (along with a VMware-specific protocol with GUID 5190120d-453b-4d48-958d-f0bab3bc2161 and a NULL instance pointer). This will inevitably fail with iPXE, since the NIC handle already includes an EFI_LOAD_FILE_PROTOCOL instance. These VMware proprietary changes end up triggering the unsafe error handling code path described above. The typical symptom is that an attempt to exit from iPXE back to the UEFI firmware will crash the VM with a General Protection fault from within the UefiPxeBcDxe driver: this happens when the UefiPxeBcDxe driver's Stop() method attempts to call through a function pointer in the (freed) PXEBC_PRIVATE_DATA structure, but the function pointer has by then been overwritten by UCS-2 character data from an unrelated memory allocation. Work around this failure by adding the VMware UefiPxeBcDxe driver to the driver veto list. Signed-off-by: Michael Brown --- src/interface/efi/efi_veto.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c index b616539d..19e529af 100644 --- a/src/interface/efi/efi_veto.c +++ b/src/interface/efi/efi_veto.c @@ -435,6 +435,37 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused, return 0; } +/** + * Veto VMware UefiPxeBcDxe driver + * + * @v binding Driver binding protocol + * @v loaded Loaded image protocol + * @v wtf Component name protocol, if present + * @v manufacturer Manufacturer name, if present + * @v name Driver name, if present + * @ret vetoed Driver is to be vetoed + */ +static int +efi_veto_vmware_uefipxebc ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused, + EFI_LOADED_IMAGE_PROTOCOL *loaded __unused, + EFI_COMPONENT_NAME_PROTOCOL *wtf __unused, + const char *manufacturer, const CHAR16 *name ) { + static const CHAR16 uefipxebc[] = L"UEFI PXE Base Code Driver"; + static const char *vmware = "VMware, Inc."; + + /* Check manufacturer and driver name */ + if ( ! manufacturer ) + return 0; + if ( ! name ) + return 0; + if ( strcmp ( manufacturer, vmware ) != 0 ) + return 0; + if ( memcmp ( name, uefipxebc, sizeof ( uefipxebc ) ) != 0 ) + return 0; + + return 1; +} + /** Driver vetoes */ static struct efi_veto efi_vetoes[] = { { @@ -445,6 +476,10 @@ static struct efi_veto efi_vetoes[] = { .name = "HP Xhci", .veto = efi_veto_hp_xhci, }, + { + .name = "VMware UefiPxeBc", + .veto = efi_veto_vmware_uefipxebc, + }, }; /** -- cgit v1.2.3-55-g7522 From 4fa4052c7ebb59e4d4aa396f1563c89118623ec7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 9 Jun 2023 14:03:48 +0100 Subject: [efi] Provide read-only access to EFI variables via settings mechanism EFI variables do not map neatly to the iPXE settings mechanism, since the EFI variable identifier includes a namespace GUID that cannot cleanly be supplied as part of a setting name. Creating a new EFI variable requires the variable's attributes to be specified, which does not fit within iPXE's settings concept. However, EFI variable names are generally unique even without the namespace GUID, and EFI does provide a mechanism to iterate over all existent variables. We can therefore provide read-only access to EFI variables by comparing only the names and ignoring the namespace GUIDs. Provide an "efi" settings block that implements this mechanism using a syntax such as: echo Platform language is ${efi/PlatformLang:string} show efi/SecureBoot:int8 Settings are returned as raw binary values by default since an EFI variable may contain boolean flags, integer values, ASCII strings, UCS-2 strings, EFI device paths, X.509 certificates, or any other arbitrary blob of data. Signed-off-by: Michael Brown --- src/config/config.c | 3 + src/config/defaults/efi.h | 2 + src/config/settings.h | 2 + src/include/ipxe/errfile.h | 1 + src/interface/efi/efi_settings.c | 236 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 244 insertions(+) create mode 100644 src/interface/efi/efi_settings.c diff --git a/src/config/config.c b/src/config/config.c index 40f9c72c..abb7d16a 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -355,6 +355,9 @@ REQUIRE_OBJECT ( vram_settings ); #ifdef ACPI_SETTINGS REQUIRE_OBJECT ( acpi_settings ); #endif +#ifdef EFI_SETTINGS +REQUIRE_OBJECT ( efi_settings ); +#endif /* * Drag in selected keyboard map diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 8e53b9ab..cb9e2348 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -48,6 +48,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define REBOOT_CMD /* Reboot command */ +#define EFI_SETTINGS /* EFI variable settings */ + #if defined ( __i386__ ) || defined ( __x86_64__ ) #define IOAPI_X86 #define NAP_EFIX86 diff --git a/src/config/settings.h b/src/config/settings.h index d9c86a38..d7f787d3 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include + #define PCI_SETTINGS /* PCI device settings */ //#define CPUID_SETTINGS /* CPUID settings */ //#define MEMMAP_SETTINGS /* Memory map settings */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index daa038c5..320835a3 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -406,6 +406,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_efi_cmdline ( ERRFILE_OTHER | 0x005b0000 ) #define ERRFILE_efi_rng ( ERRFILE_OTHER | 0x005c0000 ) #define ERRFILE_efi_shim ( ERRFILE_OTHER | 0x005d0000 ) +#define ERRFILE_efi_settings ( ERRFILE_OTHER | 0x005e0000 ) /** @} */ diff --git a/src/interface/efi/efi_settings.c b/src/interface/efi/efi_settings.c new file mode 100644 index 00000000..cde0ff8d --- /dev/null +++ b/src/interface/efi/efi_settings.c @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2023 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @file + * + * EFI variable settings + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/** EFI variable settings scope */ +static const struct settings_scope efivars_scope; + +/** EFI variable settings */ +static struct settings efivars; + +/** + * Check applicability of EFI variable setting + * + * @v settings Settings block + * @v setting Setting + * @ret applies Setting applies within this settings block + */ +static int efivars_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &efivars_scope ); +} + +/** + * Find first matching EFI variable name + * + * @v wname Name + * @v guid GUID to fill in + * @ret rc Return status code + */ +static int efivars_find ( const CHAR16 *wname, EFI_GUID *guid ) { + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; + size_t wname_len = ( ( wcslen ( wname ) + 1 ) * sizeof ( wname[0] ) ); + CHAR16 *buf; + CHAR16 *tmp; + UINTN size; + EFI_STATUS efirc; + int rc; + + /* Allocate single wNUL for first call to GetNextVariableName() */ + size = sizeof ( buf[0] ); + buf = zalloc ( size ); + if ( ! buf ) + return -ENOMEM; + + /* Iterate over all veriables */ + while ( 1 ) { + + /* Get next variable name */ + efirc = rs->GetNextVariableName ( &size, buf, guid ); + if ( efirc == EFI_BUFFER_TOO_SMALL ) { + tmp = realloc ( buf, size ); + if ( ! tmp ) { + rc = -ENOMEM; + break; + } + buf = tmp; + efirc = rs->GetNextVariableName ( &size, buf, guid ); + } + if ( efirc == EFI_NOT_FOUND ) { + rc = -ENOENT; + break; + } + if ( efirc != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efivars, "EFIVARS %s:%ls could not fetch next " + "variable name: %s\n", + efi_guid_ntoa ( guid ), buf, strerror ( rc ) ); + break; + } + DBGC2 ( &efivars, "EFIVARS %s:%ls exists\n", + efi_guid_ntoa ( guid ), buf ); + + /* Check for matching variable name */ + if ( memcmp ( wname, buf, wname_len ) == 0 ) { + rc = 0; + break; + } + } + + /* Free temporary buffer */ + free ( buf ); + + return rc; +} + +/** + * Fetch value of EFI variable setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int efivars_fetch ( struct settings *settings __unused, + struct setting *setting, void *data, size_t len ) { + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; + size_t name_len = strlen ( setting->name ); + CHAR16 wname[ name_len + 1 /* wNUL */ ]; + EFI_GUID guid; + UINT32 attrs; + UINTN size; + void *buf; + EFI_STATUS efirc; + int rc; + + /* Convert name to UCS-2 */ + efi_snprintf ( wname, sizeof ( wname ), "%s", setting->name ); + + /* Find variable GUID */ + if ( ( rc = efivars_find ( wname, &guid ) ) != 0 ) + goto err_find; + + /* Get variable length */ + size = 0; + if ( ( efirc = rs->GetVariable ( wname, &guid, &attrs, &size, + NULL ) != EFI_BUFFER_TOO_SMALL ) ) { + rc = -EEFI ( efirc ); + DBGC ( &efivars, "EFIVARS %s:%ls could not get size: %s\n", + efi_guid_ntoa ( &guid ), wname, strerror ( rc ) ); + goto err_len; + } + + /* Allocate temporary buffer, since GetVariable() is not + * guaranteed to return partial data for an underlength + * buffer. + */ + buf = malloc ( size ); + if ( ! buf ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Get variable value */ + if ( ( efirc = rs->GetVariable ( wname, &guid, &attrs, &size, + buf ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efivars, "EFIVARS %s:%ls could not get %zd bytes: " + "%s\n", efi_guid_ntoa ( &guid ), wname, + ( ( size_t ) size ), strerror ( rc ) ); + goto err_get; + } + DBGC ( &efivars, "EFIVARS %s:%ls:\n", efi_guid_ntoa ( &guid ), wname ); + DBGC_HDA ( &efivars, 0, buf, size ); + + /* Return setting value */ + if ( len > size ) + len = size; + memcpy ( data, buf, len ); + if ( ! setting->type ) + setting->type = &setting_type_hex; + + /* Free temporary buffer */ + free ( buf ); + + return size; + + err_get: + free ( buf ); + err_alloc: + err_len: + err_find: + return rc; +} + +/** EFI variable settings operations */ +static struct settings_operations efivars_operations = { + .applies = efivars_applies, + .fetch = efivars_fetch, +}; + +/** EFI variable settings */ +static struct settings efivars = { + .refcnt = NULL, + .siblings = LIST_HEAD_INIT ( efivars.siblings ), + .children = LIST_HEAD_INIT ( efivars.children ), + .op = &efivars_operations, + .default_scope = &efivars_scope, +}; + +/** + * Initialise EFI variable settings + * + */ +static void efivars_init ( void ) { + int rc; + + /* Register settings block */ + if ( ( rc = register_settings ( &efivars, NULL, "efi" ) ) != 0 ) { + DBGC ( &efivars, "EFIVARS could not register: %s\n", + strerror ( rc ) ); + return; + } +} + +/** EFI variable settings initialiser */ +struct init_fn efivars_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = efivars_init, +}; -- cgit v1.2.3-55-g7522 From 2689a6e77668bc7bd0cf486fa7e4d733c5069bd9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Jun 2023 11:49:53 +0100 Subject: [efi] Always poll for TX completions Polling for TX completions is arguably redundant when there are no transmissions currently in progress. Commit c6c7e78 ("[efi] Poll for TX completions only when there is an outstanding TX buffer") switched to setting the PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS flag only when there is an in-progress transmission awaiting completion, in order to reduce reported TX errors and debug message noise from buggy NII implementations that report spurious TX completions whenever the transmit queue is empty. Some other NII implementations (observed with the Realtek driver in a Dell Latitude 3440) seem to have a bug in the transmit datapath handling which results in the transmit ring freezing after sending a few hundred packets under heavy load. The symptoms are that the TPPoll register's NPQ bit remains set and the 256-entry transmit ring contains a large number of uncompleted descriptors (with the OWN bit set), the first two of which have identical data buffer addresses. Though iPXE will submit at most one in-progress transmission via NII, the Dell/Realtek driver seems to make a page-aligned copy of each transmit data buffer and to report TX completions immediately without waiting for the packet to actually be transmitted. These synthetic TX completions continue even after the hardware transmit ring freezes. Setting PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll reduces the probability of this Dell/Realtek driver bug being triggered by a factor of around 500, which brings the failure rate down to the point that it can sensibly be managed by external logic such as the "--timeout" option for image downloads. Closing and reopening the interface (via "ifclose"/"ifopen") will clear the error condition and allow transmissions to resume. Revert to setting PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll, and silently ignore situations in which the hardware reports a completion when no transmission is in progress. This approximately matches the behaviour of the SnpDxe driver, which will also generally set PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS on every poll. Signed-off-by: Michael Brown --- src/drivers/net/efi/nii.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index be5bce4b..8dd17e4b 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -1032,8 +1032,9 @@ static void nii_poll_tx ( struct net_device *netdev, unsigned int stat ) { if ( stat & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN ) return; - /* Sanity check */ - assert ( nii->txbuf != NULL ); + /* Ignore spurious completions reported by some devices */ + if ( ! nii->txbuf ) + return; /* Complete transmission */ iobuf = nii->txbuf; @@ -1131,7 +1132,7 @@ static void nii_poll ( struct net_device *netdev ) { /* Get status */ op = NII_OP ( PXE_OPCODE_GET_STATUS, ( PXE_OPFLAGS_GET_INTERRUPT_STATUS | - ( nii->txbuf ? PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS : 0)| + PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS | ( nii->media ? PXE_OPFLAGS_GET_MEDIA_STATUS : 0 ) ) ); if ( ( stat = nii_issue_db ( nii, op, &db, sizeof ( db ) ) ) < 0 ) { rc = -EIO_STAT ( stat ); @@ -1141,8 +1142,7 @@ static void nii_poll ( struct net_device *netdev ) { } /* Process any TX completions */ - if ( nii->txbuf ) - nii_poll_tx ( netdev, stat ); + nii_poll_tx ( netdev, stat ); /* Process any RX completions */ nii_poll_rx ( netdev ); -- cgit v1.2.3-55-g7522 From 9a118322a025986b350343daf9d55882d3238327 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Jun 2023 23:20:37 +0100 Subject: [efi] Show manufacturer in veto debug output Simplify the process of adding new entries to the veto list by including the manufacturer name within the standard debug output. Signed-off-by: Michael Brown --- src/interface/efi/efi_veto.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c index 19e529af..e4791272 100644 --- a/src/interface/efi/efi_veto.c +++ b/src/interface/efi/efi_veto.c @@ -617,6 +617,7 @@ void efi_veto ( void ) { /* Get manufacturer name */ fetch_string_setting_copy ( NULL, &manufacturer_setting, &manufacturer ); + DBGC ( &efi_vetoes, "EFIVETO manufacturer is \"%s\"\n", manufacturer ); /* Unload any vetoed drivers */ for ( i = 0 ; i < num_drivers ; i++ ) { -- cgit v1.2.3-55-g7522 From c832580f197dac013edb72ce031570d66a9448f6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Jun 2023 16:05:42 +0100 Subject: [efi] Pass more detailed driver information to veto methods Pass the driver binding handle, the driver binding protocol instance, the image handle, and the loaded image protocol instance to all veto methods. Signed-off-by: Michael Brown --- src/interface/efi/efi_veto.c | 94 +++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 36 deletions(-) diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c index e4791272..79c15757 100644 --- a/src/interface/efi/efi_veto.c +++ b/src/interface/efi/efi_veto.c @@ -37,8 +37,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ -/** A driver veto */ -struct efi_veto { +/** A driver veto candidate */ +struct efi_veto_candidate { /** Veto name (for debugging) */ const char *name; /** @@ -57,14 +57,27 @@ struct efi_veto { const char *manufacturer, const CHAR16 *name ); }; +/** A driver veto */ +struct efi_veto { + /** Driver binding handle */ + EFI_HANDLE driver; + /** Driving binding protocol */ + EFI_DRIVER_BINDING_PROTOCOL *binding; + /** Image handle */ + EFI_HANDLE image; + /** Loaded image protocol */ + EFI_LOADED_IMAGE_PROTOCOL *loaded; +}; + /** * Unload an EFI driver * - * @v driver Driver binding handle + * @v veto Driver veto * @ret rc Return status code */ -static int efi_veto_unload ( EFI_HANDLE driver ) { +static int efi_veto_unload ( struct efi_veto *veto ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE driver = veto->driver; EFI_STATUS efirc; int rc; @@ -82,11 +95,12 @@ static int efi_veto_unload ( EFI_HANDLE driver ) { /** * Disconnect an EFI driver from all handles * - * @v driver Driver binding handle + * @v veto Driver veto * @ret rc Return status code */ -static int efi_veto_disconnect ( EFI_HANDLE driver ) { +static int efi_veto_disconnect ( struct efi_veto *veto ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE driver = veto->driver; EFI_HANDLE *handles; EFI_HANDLE handle; UINTN count; @@ -131,11 +145,12 @@ static int efi_veto_disconnect ( EFI_HANDLE driver ) { /** * Uninstall an EFI driver binding protocol * - * @v driver Driver binding handle + * @v veto Driver veto * @ret rc Return status code */ -static int efi_veto_uninstall ( EFI_HANDLE driver ) { +static int efi_veto_uninstall ( struct efi_veto *veto ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE driver = veto->driver; union { EFI_DRIVER_BINDING_PROTOCOL *binding; void *interface; @@ -178,14 +193,15 @@ static int efi_veto_uninstall ( EFI_HANDLE driver ) { /** * Close protocol on handle potentially opened by an EFI driver * - * @v driver Driver binding handle + * @v veto Driver veto * @v handle Potentially opened handle * @v protocol Opened protocol * @ret rc Return status code */ -static int efi_veto_close_protocol ( EFI_HANDLE driver, EFI_HANDLE handle, +static int efi_veto_close_protocol ( struct efi_veto *veto, EFI_HANDLE handle, EFI_GUID *protocol ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE driver = veto->driver; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener; EFI_HANDLE controller; @@ -235,12 +251,13 @@ static int efi_veto_close_protocol ( EFI_HANDLE driver, EFI_HANDLE handle, /** * Close handle potentially opened by an EFI driver * - * @v driver Driver binding handle + * @v veto Driver veto * @v handle Potentially opened handle * @ret rc Return status code */ -static int efi_veto_close_handle ( EFI_HANDLE driver, EFI_HANDLE handle ) { +static int efi_veto_close_handle ( struct efi_veto *veto, EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE driver = veto->driver; EFI_GUID **protocols; UINTN count; unsigned int i; @@ -260,7 +277,7 @@ static int efi_veto_close_handle ( EFI_HANDLE driver, EFI_HANDLE handle ) { /* Close each protocol */ for ( i = 0 ; i < count ; i++ ) { - if ( ( rc = efi_veto_close_protocol ( driver, handle, + if ( ( rc = efi_veto_close_protocol ( veto, handle, protocols[i] ) ) != 0 ) goto err_close; } @@ -277,11 +294,12 @@ static int efi_veto_close_handle ( EFI_HANDLE driver, EFI_HANDLE handle ) { /** * Close all remaining handles opened by an EFI driver * - * @v driver Driver binding handle + * @v veto Driver veto * @ret rc Return status code */ -static int efi_veto_close ( EFI_HANDLE driver ) { +static int efi_veto_close ( struct efi_veto *veto ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_HANDLE driver = veto->driver; EFI_HANDLE *handles; UINTN count; unsigned int i; @@ -299,8 +317,7 @@ static int efi_veto_close ( EFI_HANDLE driver ) { /* Close each handle */ for ( i = 0 ; i < count ; i++ ) { - if ( ( rc = efi_veto_close_handle ( driver, - handles[i] ) ) != 0 ) + if ( ( rc = efi_veto_close_handle ( veto, handles[i] ) ) != 0 ) goto err_close; } @@ -318,22 +335,23 @@ static int efi_veto_close ( EFI_HANDLE driver ) { /** * Terminate an EFI driver with extreme prejudice * - * @v driver Driver binding handle + * @v veto Driver veto * @ret rc Return status code */ -static int efi_veto_destroy ( EFI_HANDLE driver ) { +static int efi_veto_destroy ( struct efi_veto *veto ) { + EFI_HANDLE driver = veto->driver; int rc; /* Disconnect driver from all handles */ - if ( ( rc = efi_veto_disconnect ( driver ) ) != 0 ) + if ( ( rc = efi_veto_disconnect ( veto ) ) != 0 ) return rc; /* Uninstall driver binding protocol */ - if ( ( rc = efi_veto_uninstall ( driver ) ) != 0 ) + if ( ( rc = efi_veto_uninstall ( veto ) ) != 0 ) return rc; /* Close any remaining opened handles */ - if ( ( rc = efi_veto_close ( driver ) ) != 0 ) + if ( ( rc = efi_veto_close ( veto ) ) != 0 ) return rc; DBGC ( driver, "EFIVETO %s forcibly removed\n", @@ -344,18 +362,18 @@ static int efi_veto_destroy ( EFI_HANDLE driver ) { /** * Veto an EFI driver * - * @v driver Driver binding handle + * @v veto Driver veto * @ret rc Return status code */ -static int efi_veto_driver ( EFI_HANDLE driver ) { +static int efi_veto_driver ( struct efi_veto *veto ) { int rc; /* Try gracefully unloading the driver */ - if ( ( rc = efi_veto_unload ( driver ) ) == 0 ) + if ( ( rc = efi_veto_unload ( veto ) ) == 0 ) return 0; /* If that fails, use a hammer */ - if ( ( rc = efi_veto_destroy ( driver ) ) == 0 ) + if ( ( rc = efi_veto_destroy ( veto ) ) == 0 ) return 0; return rc; @@ -467,7 +485,7 @@ efi_veto_vmware_uefipxebc ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused, } /** Driver vetoes */ -static struct efi_veto efi_vetoes[] = { +static struct efi_veto_candidate efi_vetoes[] = { { .name = "Ip4Config", .veto = efi_veto_ip4config, @@ -487,11 +505,11 @@ static struct efi_veto efi_vetoes[] = { * * @v driver Driver binding handle * @v manufacturer Manufacturer name, if present - * @ret veto Driver veto, or NULL + * @ret veto Driver veto to fill in * @ret rc Return status code */ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer, - struct efi_veto **veto ) { + struct efi_veto *veto ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_DRIVER_BINDING_PROTOCOL *binding; @@ -515,7 +533,7 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer, efi_handle_name ( driver ) ); /* Mark as not vetoed */ - *veto = NULL; + memset ( veto, 0, sizeof ( *veto ) ); /* Open driver binding protocol */ if ( ( efirc = bs->OpenProtocol ( @@ -567,7 +585,13 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer, sizeof ( efi_vetoes[0] ) ) ; i++ ) { if ( efi_vetoes[i].veto ( binding.binding, loaded.loaded, wtf.wtf, manufacturer, name ) ) { - *veto = &efi_vetoes[i]; + DBGC ( driver, "EFIVETO %s is vetoed (%s)\n", + efi_handle_name ( driver ), + efi_vetoes[i].name ); + veto->driver = driver; + veto->binding = binding.binding; + veto->image = image; + veto->loaded = loaded.loaded; break; } } @@ -595,7 +619,7 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer, */ void efi_veto ( void ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - struct efi_veto *veto; + struct efi_veto veto; EFI_HANDLE *drivers; EFI_HANDLE driver; UINTN num_drivers; @@ -629,11 +653,9 @@ void efi_veto ( void ) { efi_handle_name ( driver ), strerror ( rc ) ); continue; } - if ( ! veto ) + if ( ! veto.driver ) continue; - DBGC ( driver, "EFIVETO %s is vetoed (%s)\n", - efi_handle_name ( driver ), veto->name ); - if ( ( rc = efi_veto_driver ( driver ) ) != 0 ) { + if ( ( rc = efi_veto_driver ( &veto ) ) != 0 ) { DBGC ( driver, "EFIVETO %s could not veto: %s\n", efi_handle_name ( driver ), strerror ( rc ) ); } -- cgit v1.2.3-55-g7522 From f0b1025503205515d5b105c37774596623481242 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Jun 2023 16:08:25 +0100 Subject: [efi] Unload vetoed drivers by image handle rather than driver handle In most cases, the driver handle will be the image handle itself. However, this is not required by the UEFI specification, and some images will install multiple driver binding handles. Use the image handle (extracted from the driver binding protocol instance) when attempting to unload the driver's image. Signed-off-by: Michael Brown --- src/interface/efi/efi_veto.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c index 79c15757..3e0806e0 100644 --- a/src/interface/efi/efi_veto.c +++ b/src/interface/efi/efi_veto.c @@ -78,14 +78,17 @@ struct efi_veto { static int efi_veto_unload ( struct efi_veto *veto ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE driver = veto->driver; + EFI_HANDLE image = veto->image; EFI_STATUS efirc; int rc; /* Unload the driver */ - if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) { + if ( ( efirc = bs->UnloadImage ( image ) ) != 0 ) { rc = -EEFI ( efirc ); - DBGC ( driver, "EFIVETO %s could not unload: %s\n", - efi_handle_name ( driver ), strerror ( rc ) ); + DBGC ( driver, "EFIVETO %s could not unload", + efi_handle_name ( driver ) ); + DBGC ( driver, " %s: %s\n", efi_handle_name ( image ), + strerror ( rc ) ); return rc; } -- cgit v1.2.3-55-g7522 From f8a0d1c0b8cfd7b04bdc9a006c52434661afd06a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Jun 2023 16:12:01 +0100 Subject: [efi] Check for protocols opened by vetoed driver and image handles The UEFI specification states that the AgentHandle may be either the driving binding protocol handle or the image handle. Check for both handles when searching for stale handles to be forcibly closed on behalf of a vetoed driver. Signed-off-by: Michael Brown --- src/interface/efi/efi_veto.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c index 3e0806e0..bc19a009 100644 --- a/src/interface/efi/efi_veto.c +++ b/src/interface/efi/efi_veto.c @@ -205,6 +205,7 @@ static int efi_veto_close_protocol ( struct efi_veto *veto, EFI_HANDLE handle, EFI_GUID *protocol ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE driver = veto->driver; + EFI_HANDLE image = veto->image; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers; EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener; EFI_HANDLE controller; @@ -227,8 +228,10 @@ static int efi_veto_close_protocol ( struct efi_veto *veto, EFI_HANDLE handle, /* Close anything opened by this driver */ for ( i = 0 ; i < count ; i++ ) { opener = &openers[i]; - if ( opener->AgentHandle != driver ) + if ( ( opener->AgentHandle != driver ) && + ( opener->AgentHandle != image ) ) { continue; + } controller = opener->ControllerHandle; DBGC_EFI_OPENER ( driver, handle, protocol, opener ); if ( ( efirc = bs->CloseProtocol ( handle, protocol, driver, -- cgit v1.2.3-55-g7522 From ae435cb4cc78183814f867686d278885db2988f8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 23 Jun 2023 16:27:47 +0100 Subject: [efi] Process veto objects in reverse order of enumeration While not guaranteed by the UEFI specification, the enumeration of handles, protocols, and openers will generally return results in order of creation. Processing these objects in reverse order (as is already done when calling DisconnectController() on the list of all handles) will generally therefore perform the forcible uninstallation operations in reverse order of object creation, which minimises the number of implicit operations performed (e.g. when disconnecting a controller that itself still has existent child controllers). Signed-off-by: Michael Brown --- src/interface/efi/efi_veto.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c index bc19a009..a3b60d65 100644 --- a/src/interface/efi/efi_veto.c +++ b/src/interface/efi/efi_veto.c @@ -227,7 +227,7 @@ static int efi_veto_close_protocol ( struct efi_veto *veto, EFI_HANDLE handle, /* Close anything opened by this driver */ for ( i = 0 ; i < count ; i++ ) { - opener = &openers[i]; + opener = &openers[ count - i - 1 ]; if ( ( opener->AgentHandle != driver ) && ( opener->AgentHandle != image ) ) { continue; @@ -265,6 +265,7 @@ static int efi_veto_close_handle ( struct efi_veto *veto, EFI_HANDLE handle ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE driver = veto->driver; EFI_GUID **protocols; + EFI_GUID *protocol; UINTN count; unsigned int i; EFI_STATUS efirc; @@ -283,8 +284,9 @@ static int efi_veto_close_handle ( struct efi_veto *veto, EFI_HANDLE handle ) { /* Close each protocol */ for ( i = 0 ; i < count ; i++ ) { + protocol = protocols[ count - i - 1]; if ( ( rc = efi_veto_close_protocol ( veto, handle, - protocols[i] ) ) != 0 ) + protocol ) ) != 0 ) goto err_close; } @@ -307,6 +309,7 @@ static int efi_veto_close ( struct efi_veto *veto ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_HANDLE driver = veto->driver; EFI_HANDLE *handles; + EFI_HANDLE handle; UINTN count; unsigned int i; EFI_STATUS efirc; @@ -323,7 +326,8 @@ static int efi_veto_close ( struct efi_veto *veto ) { /* Close each handle */ for ( i = 0 ; i < count ; i++ ) { - if ( ( rc = efi_veto_close_handle ( veto, handles[i] ) ) != 0 ) + handle = handles[ count - i - 1 ]; + if ( ( rc = efi_veto_close_handle ( veto, handle ) ) != 0 ) goto err_close; } @@ -628,7 +632,7 @@ void efi_veto ( void ) { struct efi_veto veto; EFI_HANDLE *drivers; EFI_HANDLE driver; - UINTN num_drivers; + UINTN count; unsigned int i; char *manufacturer; EFI_STATUS efirc; @@ -637,7 +641,7 @@ void efi_veto ( void ) { /* Locate all driver binding protocol handles */ if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol, &efi_driver_binding_protocol_guid, - NULL, &num_drivers, &drivers ) ) != 0 ) { + NULL, &count, &drivers ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( &efi_vetoes, "EFIVETO could not list all drivers: " "%s\n", strerror ( rc ) ); @@ -650,8 +654,8 @@ void efi_veto ( void ) { DBGC ( &efi_vetoes, "EFIVETO manufacturer is \"%s\"\n", manufacturer ); /* Unload any vetoed drivers */ - for ( i = 0 ; i < num_drivers ; i++ ) { - driver = drivers[i]; + for ( i = 0 ; i < count ; i++ ) { + driver = drivers[ count - i - 1 ]; if ( ( rc = efi_veto_find ( driver, manufacturer, &veto ) ) != 0 ) { DBGC ( driver, "EFIVETO %s could not determine " -- cgit v1.2.3-55-g7522 From cfe65aa82628f364718e8cb261e8f6b952cd9d26 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Jun 2023 15:38:08 +0100 Subject: [arm] Remove redundant inclusion of io.h The PCI I/O API (supporting accesses to PCI configuration space) is not related to the general I/O API (supporting accesses to memory-mapped I/O peripherals). Remove the spurious inclusion of ipxe/io.h from the PCI I/O header. Signed-off-by: Michael Brown --- src/arch/arm/include/bits/pci_io.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/arch/arm/include/bits/pci_io.h b/src/arch/arm/include/bits/pci_io.h index fba0eb97..91f507a4 100644 --- a/src/arch/arm/include/bits/pci_io.h +++ b/src/arch/arm/include/bits/pci_io.h @@ -9,6 +9,4 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include - #endif /* _BITS_PCI_IO_H */ -- cgit v1.2.3-55-g7522 From 18af669701b5396af4073b9de4bdb6cd3aff68c1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Jun 2023 15:26:49 +0100 Subject: [arm] Add missing arch/arm/core source directory Signed-off-by: Michael Brown --- src/arch/arm/Makefile | 1 + src/arch/arm/core/arm_io.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/arch/arm/Makefile b/src/arch/arm/Makefile index 3cee5f3a..b6509dda 100644 --- a/src/arch/arm/Makefile +++ b/src/arch/arm/Makefile @@ -9,4 +9,5 @@ INCDIRS += arch/arm/include # ARM-specific directories containing source files # +SRCDIRS += arch/arm/core SRCDIRS += arch/arm/interface/efi diff --git a/src/arch/arm/core/arm_io.c b/src/arch/arm/core/arm_io.c index 1ef571fc..f8022715 100644 --- a/src/arch/arm/core/arm_io.c +++ b/src/arch/arm/core/arm_io.c @@ -46,7 +46,7 @@ union arm32_io_qword { * * This is not atomic for ARM32. */ -static uint64_t arm32_readq ( volatile uint64_t *io_addr ) { +static __unused uint64_t arm32_readq ( volatile uint64_t *io_addr ) { volatile union arm32_io_qword *ptr = container_of ( io_addr, union arm32_io_qword, qword ); union arm32_io_qword tmp; @@ -64,7 +64,8 @@ static uint64_t arm32_readq ( volatile uint64_t *io_addr ) { * * This is not atomic for ARM32. */ -static void arm32_writeq ( uint64_t data, volatile uint64_t *io_addr ) { +static __unused void arm32_writeq ( uint64_t data, + volatile uint64_t *io_addr ) { volatile union arm32_io_qword *ptr = container_of ( io_addr, union arm32_io_qword, qword ); union arm32_io_qword tmp; -- cgit v1.2.3-55-g7522 From c57887bfc808c2be485ed97f2dc709f927550161 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Jun 2023 15:08:23 +0100 Subject: [ioapi] Centralise definitions for dummy PIO There is no common standard for I/O-space access for non-x86 CPU families, and non-MMIO peripherals are vanishingly rare. Generalise the existing ARM definitions for dummy PIO to allow for reuse by other CPU architectures. Signed-off-by: Michael Brown --- src/arch/arm/core/arm_io.c | 2 +- src/arch/arm/include/ipxe/arm_io.h | 54 +++----------------------------- src/include/ipxe/dummy_pio.h | 64 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 50 deletions(-) create mode 100644 src/include/ipxe/dummy_pio.h diff --git a/src/arch/arm/core/arm_io.c b/src/arch/arm/core/arm_io.c index f8022715..41b42389 100644 --- a/src/arch/arm/core/arm_io.c +++ b/src/arch/arm/core/arm_io.c @@ -83,7 +83,6 @@ PROVIDE_IOAPI_INLINE ( arm, readl ); PROVIDE_IOAPI_INLINE ( arm, writeb ); PROVIDE_IOAPI_INLINE ( arm, writew ); PROVIDE_IOAPI_INLINE ( arm, writel ); -PROVIDE_IOAPI_INLINE ( arm, iodelay ); PROVIDE_IOAPI_INLINE ( arm, mb ); #ifdef __aarch64__ PROVIDE_IOAPI_INLINE ( arm, readq ); @@ -92,3 +91,4 @@ PROVIDE_IOAPI_INLINE ( arm, writeq ); PROVIDE_IOAPI ( arm, readq, arm32_readq ); PROVIDE_IOAPI ( arm, writeq, arm32_writeq ); #endif +PROVIDE_DUMMY_PIO ( arm ); diff --git a/src/arch/arm/include/ipxe/arm_io.h b/src/arch/arm/include/ipxe/arm_io.h index 046cbdb0..7ed38993 100644 --- a/src/arch/arm/include/ipxe/arm_io.h +++ b/src/arch/arm/include/ipxe/arm_io.h @@ -15,6 +15,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define IOAPI_PREFIX_arm __arm_ #endif +#include + /* * Memory space mappings * @@ -77,55 +79,6 @@ ARM_WRITEX ( w, uint16_t, "h", "" ); ARM_WRITEX ( l, uint32_t, "", "" ); #endif -/* - * Dummy PIO reads and writes up to 32 bits - * - * There is no common standard for I/O-space access for ARM, and - * non-MMIO peripherals are vanishingly rare. Provide dummy - * implementations that will allow code to link and should cause - * drivers to simply fail to detect hardware at runtime. - * - */ - -#define ARM_INX( _suffix, _type ) \ -static inline __always_inline _type \ -IOAPI_INLINE ( arm, in ## _suffix ) ( volatile _type *io_addr __unused) { \ - return ~( (_type) 0 ); \ -} \ -static inline __always_inline void \ -IOAPI_INLINE ( arm, ins ## _suffix ) ( volatile _type *io_addr __unused, \ - _type *data, unsigned int count ) { \ - memset ( data, 0xff, count * sizeof ( *data ) ); \ -} -ARM_INX ( b, uint8_t ); -ARM_INX ( w, uint16_t ); -ARM_INX ( l, uint32_t ); - -#define ARM_OUTX( _suffix, _type ) \ -static inline __always_inline void \ -IOAPI_INLINE ( arm, out ## _suffix ) ( _type data __unused, \ - volatile _type *io_addr __unused ) { \ - /* Do nothing */ \ -} \ -static inline __always_inline void \ -IOAPI_INLINE ( arm, outs ## _suffix ) ( volatile _type *io_addr __unused, \ - const _type *data __unused, \ - unsigned int count __unused ) { \ - /* Do nothing */ \ -} -ARM_OUTX ( b, uint8_t ); -ARM_OUTX ( w, uint16_t ); -ARM_OUTX ( l, uint32_t ); - -/* - * Slow down I/O - * - */ -static inline __always_inline void -IOAPI_INLINE ( arm, iodelay ) ( void ) { - /* Nothing to do */ -} - /* * Memory barrier * @@ -140,4 +93,7 @@ IOAPI_INLINE ( arm, mb ) ( void ) { #endif } +/* Dummy PIO */ +DUMMY_PIO ( arm ); + #endif /* _IPXE_ARM_IO_H */ diff --git a/src/include/ipxe/dummy_pio.h b/src/include/ipxe/dummy_pio.h new file mode 100644 index 00000000..1cdabba1 --- /dev/null +++ b/src/include/ipxe/dummy_pio.h @@ -0,0 +1,64 @@ +#ifndef _IPXE_DUMMY_PIO_H +#define _IPXE_DUMMY_PIO_H + +/** @file + * + * Dummy PIO reads and writes up to 32 bits + * + * There is no common standard for I/O-space access for non-x86 CPU + * families, and non-MMIO peripherals are vanishingly rare. Provide + * dummy implementations that will allow code to link and should cause + * drivers to simply fail to detect hardware at runtime. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#define DUMMY_INX( _prefix, _suffix, _type ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( _prefix, in ## _suffix ) ( volatile _type *io_addr __unused) { \ + return ~( (_type) 0 ); \ +} \ +static inline __always_inline void \ +IOAPI_INLINE ( _prefix, ins ## _suffix ) ( volatile _type *io_addr __unused, \ + _type *data, unsigned int count ) {\ + memset ( data, 0xff, count * sizeof ( *data ) ); \ +} + +#define DUMMY_OUTX( _prefix, _suffix, _type ) \ +static inline __always_inline void \ +IOAPI_INLINE ( _prefix, out ## _suffix ) ( _type data __unused, \ + volatile _type *io_addr __unused ){\ + /* Do nothing */ \ +} \ +static inline __always_inline void \ +IOAPI_INLINE ( _prefix, outs ## _suffix ) ( volatile _type *io_addr __unused, \ + const _type *data __unused, \ + unsigned int count __unused ) { \ + /* Do nothing */ \ +} + +#define DUMMY_IODELAY( _prefix ) \ +static inline __always_inline void \ +IOAPI_INLINE ( _prefix, iodelay ) ( void ) { \ + /* Nothing to do */ \ +} + +#define DUMMY_PIO( _prefix ) \ + DUMMY_INX ( _prefix, b, uint8_t ); \ + DUMMY_INX ( _prefix, w, uint16_t ); \ + DUMMY_INX ( _prefix, l, uint32_t ); \ + DUMMY_OUTX ( _prefix, b, uint8_t ); \ + DUMMY_OUTX ( _prefix, w, uint16_t ); \ + DUMMY_OUTX ( _prefix, l, uint32_t ); \ + DUMMY_IODELAY ( _prefix ); + +#define PROVIDE_DUMMY_PIO( _prefix ) \ + PROVIDE_IOAPI_INLINE ( _prefix, inb ); \ + PROVIDE_IOAPI_INLINE ( _prefix, inw ); \ + PROVIDE_IOAPI_INLINE ( _prefix, inl ); \ + PROVIDE_IOAPI_INLINE ( _prefix, outb ); \ + PROVIDE_IOAPI_INLINE ( _prefix, outw ); \ + PROVIDE_IOAPI_INLINE ( _prefix, outl ); \ + PROVIDE_IOAPI_INLINE ( _prefix, iodelay ); + +#endif /* _IPXE_DUMMY_PIO_H */ -- cgit v1.2.3-55-g7522 From 0c67a3632dae9132b519f8b9d64453fff175322d Mon Sep 17 00:00:00 2001 From: Xiaotian Wu Date: Thu, 29 Jun 2023 15:30:08 +0100 Subject: [loong64] Add I/O API for LoongArch64 Signed-off-by: Xiaotian Wu Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/arch/loong64/core/loong64_io.c | 46 +++++++++++++++++ src/arch/loong64/include/bits/io.h | 2 + src/arch/loong64/include/ipxe/loong64_io.h | 82 ++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 src/arch/loong64/core/loong64_io.c create mode 100644 src/arch/loong64/include/ipxe/loong64_io.h diff --git a/src/arch/loong64/core/loong64_io.c b/src/arch/loong64/core/loong64_io.c new file mode 100644 index 00000000..6e2a78af --- /dev/null +++ b/src/arch/loong64/core/loong64_io.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023, Xiaotian Wu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +/** @file + * + * iPXE I/O API for LoongArch64 + * + */ + +PROVIDE_IOAPI_INLINE ( loong64, phys_to_bus ); +PROVIDE_IOAPI_INLINE ( loong64, bus_to_phys ); +PROVIDE_IOAPI_INLINE ( loong64, readb ); +PROVIDE_IOAPI_INLINE ( loong64, readw ); +PROVIDE_IOAPI_INLINE ( loong64, readl ); +PROVIDE_IOAPI_INLINE ( loong64, readq ); +PROVIDE_IOAPI_INLINE ( loong64, writeb ); +PROVIDE_IOAPI_INLINE ( loong64, writew ); +PROVIDE_IOAPI_INLINE ( loong64, writel ); +PROVIDE_IOAPI_INLINE ( loong64, writeq ); +PROVIDE_IOAPI_INLINE ( loong64, mb ); +PROVIDE_DUMMY_PIO ( loong64 ); diff --git a/src/arch/loong64/include/bits/io.h b/src/arch/loong64/include/bits/io.h index 20ca6a7b..e9bcf2ee 100644 --- a/src/arch/loong64/include/bits/io.h +++ b/src/arch/loong64/include/bits/io.h @@ -12,4 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Page shift */ #define PAGE_SHIFT 12 +#include + #endif /* _BITS_IO_H */ diff --git a/src/arch/loong64/include/ipxe/loong64_io.h b/src/arch/loong64/include/ipxe/loong64_io.h new file mode 100644 index 00000000..939fbf2b --- /dev/null +++ b/src/arch/loong64/include/ipxe/loong64_io.h @@ -0,0 +1,82 @@ +#ifndef _IPXE_LOONG64_IO_H +#define _IPXE_LOONG64_IO_H + +/** @file + * + * iPXE I/O API for LoongArch64 + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef IOAPI_LOONG64 +#define IOAPI_PREFIX_loong64 +#else +#define IOAPI_PREFIX_loong64 __loong64_ +#endif + +#include + +/* + * Memory space mappings + * + */ + +/* + * Physical<->Bus address mappings + * + */ + +static inline __always_inline unsigned long +IOAPI_INLINE ( loong64, phys_to_bus ) ( unsigned long phys_addr ) { + return phys_addr; +} + +static inline __always_inline unsigned long +IOAPI_INLINE ( loong64, bus_to_phys ) ( unsigned long bus_addr ) { + return bus_addr; +} + +/* + * MMIO reads and writes up to native word size + * + */ + +#define LOONG64_READX( _suffix, _type, _insn_suffix ) \ +static inline __always_inline _type \ +IOAPI_INLINE ( loong64, read ## _suffix ) ( volatile _type *io_addr ) { \ + _type data; \ + __asm__ __volatile__ ( "ld." _insn_suffix " %0, %1" \ + : "=r" ( data ) : "m" ( *io_addr ) ); \ + return data; \ +} +LOONG64_READX ( b, uint8_t, "bu"); +LOONG64_READX ( w, uint16_t, "hu"); +LOONG64_READX ( l, uint32_t, "wu"); +LOONG64_READX ( q, uint64_t, "d"); + +#define LOONG64_WRITEX( _suffix, _type, _insn_suffix ) \ +static inline __always_inline void \ +IOAPI_INLINE ( loong64, write ## _suffix ) ( _type data, \ + volatile _type *io_addr ) { \ + __asm__ __volatile__ ( "st." _insn_suffix " %0, %1" \ + : : "r" ( data ), "m" ( *io_addr ) ); \ +} +LOONG64_WRITEX ( b, uint8_t, "b"); +LOONG64_WRITEX ( w, uint16_t, "h"); +LOONG64_WRITEX ( l, uint32_t, "w" ); +LOONG64_WRITEX ( q, uint64_t, "d"); + +/* + * Memory barrier + * + */ +static inline __always_inline void +IOAPI_INLINE ( loong64, mb ) ( void ) { + __asm__ __volatile__ ( "dbar 0" ); +} + +/* Dummy PIO */ +DUMMY_PIO ( loong64 ); + +#endif /* _IPXE_LOONG64_IO_H */ -- cgit v1.2.3-55-g7522 From 6d98e0ca47b29c0041ce1aaea18b825105a354af Mon Sep 17 00:00:00 2001 From: Xiaotian Wu Date: Thu, 29 Jun 2023 15:49:27 +0100 Subject: [loong64] Add CPU sleeping API for EFI LoongArch64 Signed-off-by: Xiaotian Wu Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/arch/loong64/Makefile | 1 + src/arch/loong64/include/bits/nap.h | 4 +- src/arch/loong64/include/ipxe/efi/efiloong64_nap.h | 18 ++++++++ src/arch/loong64/interface/efi/efiloong64_nap.c | 53 ++++++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/arch/loong64/include/ipxe/efi/efiloong64_nap.h create mode 100644 src/arch/loong64/interface/efi/efiloong64_nap.c diff --git a/src/arch/loong64/Makefile b/src/arch/loong64/Makefile index f2dfc76e..fd0bf137 100644 --- a/src/arch/loong64/Makefile +++ b/src/arch/loong64/Makefile @@ -20,6 +20,7 @@ CFLAGS += -fshort-wchar # LoongArch64-specific directories containing source files SRCDIRS += arch/loong64/core +SRCDIRS += arch/loong64/interface/efi # Include platform-specific Makefile MAKEDEPS += arch/loong64/Makefile.$(PLATFORM) diff --git a/src/arch/loong64/include/bits/nap.h b/src/arch/loong64/include/bits/nap.h index 91e255d9..2deba355 100644 --- a/src/arch/loong64/include/bits/nap.h +++ b/src/arch/loong64/include/bits/nap.h @@ -9,4 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#endif /* _BITS_MAP_H */ +#include + +#endif /* _BITS_NAP_H */ diff --git a/src/arch/loong64/include/ipxe/efi/efiloong64_nap.h b/src/arch/loong64/include/ipxe/efi/efiloong64_nap.h new file mode 100644 index 00000000..5c0d3863 --- /dev/null +++ b/src/arch/loong64/include/ipxe/efi/efiloong64_nap.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_EFILOONG64_NAP_H +#define _IPXE_EFILOONG64_NAP_H + +/** @file + * + * EFI CPU sleeping + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef NAP_EFILOONG64 +#define NAP_PREFIX_efiloong64 +#else +#define NAP_PREFIX_efiloong64 __efiloong64_ +#endif + +#endif /* _IPXE_EFILOONG64_NAP_H */ diff --git a/src/arch/loong64/interface/efi/efiloong64_nap.c b/src/arch/loong64/interface/efi/efiloong64_nap.c new file mode 100644 index 00000000..5cd1c1b9 --- /dev/null +++ b/src/arch/loong64/interface/efi/efiloong64_nap.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023, Xiaotian Wu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +/** @file + * + * iPXE CPU sleeping API for EFI + * + */ + +/** + * Sleep until next interrupt + * + */ +static void efiloong64_cpu_nap ( void ) { + /* + * I can't find any EFI API that allows us to put the CPU to + * sleep. The CpuSleep() function is defined in CpuLib.h, but + * isn't part of any exposed protocol so we have no way to + * call it. + * + * The EFI shell doesn't seem to bother sleeping the CPU; it + * just sits there idly burning power. + * + */ + __asm__ __volatile__ ( "idle 0" ); +} + +PROVIDE_NAP ( efiloong64, cpu_nap, efiloong64_cpu_nap ); -- cgit v1.2.3-55-g7522 From 280942a92a4567796976e06d186d0a199ae0337e Mon Sep 17 00:00:00 2001 From: Xiaotian Wu Date: Thu, 29 Jun 2023 15:52:28 +0100 Subject: [loong64] Add support for building EFI binaries Signed-off-by: Xiaotian Wu Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/arch/loong64/Makefile.efi | 14 ++++++++++++++ src/config/defaults/efi.h | 5 +++++ 2 files changed, 19 insertions(+) create mode 100644 src/arch/loong64/Makefile.efi diff --git a/src/arch/loong64/Makefile.efi b/src/arch/loong64/Makefile.efi new file mode 100644 index 00000000..1c51bcd6 --- /dev/null +++ b/src/arch/loong64/Makefile.efi @@ -0,0 +1,14 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Specify EFI image builder +# +ELF2EFI = $(ELF2EFI64) + +# Specify EFI boot file +# +EFI_BOOT_FILE = bootloongarch64.efi + +# Include generic EFI Makefile +# +MAKEDEPS += Makefile.efi +include Makefile.efi diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index cb9e2348..e39d475b 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -67,4 +67,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define IMAGE_GZIP /* GZIP image support */ #endif +#if defined ( __loongarch__ ) +#define IOAPI_LOONG64 +#define NAP_EFILOONG64 +#endif + #endif /* CONFIG_DEFAULTS_EFI_H */ -- cgit v1.2.3-55-g7522 From 2524a60550b7b81d32447782e42485997b9af175 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 30 Jun 2023 10:31:52 +0100 Subject: [build] Avoid using multiple target patterns in pattern rules Multiple target patterns in pattern rules are treated as grouped targets regardless of the separator character. Newer verions of make will generate "warning: pattern recipe did not update peer target" to warn that the rule was expected to update all of the (implicitly) grouped targets. Fix by splitting all multiple target pattern rules into single target pattern rules. Signed-off-by: Michael Brown --- src/Makefile.efi | 6 +++++- src/arch/x86/Makefile.pcbios | 10 ++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Makefile.efi b/src/Makefile.efi index bd479b3d..6e8ad46b 100644 --- a/src/Makefile.efi +++ b/src/Makefile.efi @@ -50,6 +50,10 @@ $(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined $(QM)$(ECHO) " [CAB] $@" $(Q)$(LCAB) -n -q $(ALL_drv.efi) $@ -$(BIN)/%.iso $(BIN)/%.usb : $(BIN)/%.efi util/genfsimg +$(BIN)/%.iso : $(BIN)/%.efi util/genfsimg + $(QM)$(ECHO) " [GENFSIMG] $@" + $(Q)util/genfsimg -o $@ $< + +$(BIN)/%.usb : $(BIN)/%.efi util/genfsimg $(QM)$(ECHO) " [GENFSIMG] $@" $(Q)util/genfsimg -o $@ $< diff --git a/src/arch/x86/Makefile.pcbios b/src/arch/x86/Makefile.pcbios index ed8d554a..b9f8e6c2 100644 --- a/src/arch/x86/Makefile.pcbios +++ b/src/arch/x86/Makefile.pcbios @@ -54,9 +54,15 @@ LIST_NAME_mrom := ROMS LIST_NAME_pcirom := ROMS LIST_NAME_isarom := ROMS -# ISO or FAT filesystem images +# ISO images NON_AUTO_MEDIA += iso -$(BIN)/%.iso $(BIN)/%.sdsk: $(BIN)/%.lkrn util/genfsimg +$(BIN)/%.iso : $(BIN)/%.lkrn util/genfsimg + $(QM)$(ECHO) " [GENFSIMG] $@" + $(Q)util/genfsimg -o $@ $< + +# FAT filesystem images (via syslinux) +NON_AUTO_MEDIA += sdsk +$(BIN)/%.sdsk : $(BIN)/%.lkrn util/genfsimg $(QM)$(ECHO) " [GENFSIMG] $@" $(Q)util/genfsimg -o $@ $< -- cgit v1.2.3-55-g7522 From e17568ad0642490143d0c6b154c874b9b9e285bf Mon Sep 17 00:00:00 2001 From: Geert Stappers Date: Fri, 30 Jun 2023 10:59:59 +0100 Subject: [build] Inhibit linker warnings about an implied executable stack Signed-off-by: Geert Stappers Modified-by: Michael Brown Signed-off-by: Michael Brown --- src/arch/arm64/core/setjmp.S | 1 + src/arch/i386/core/gdbidt.S | 1 + src/arch/i386/core/setjmp.S | 1 + src/arch/i386/tests/gdbstub_test.S | 1 + src/arch/x86/core/patch_cf.S | 1 + src/arch/x86/core/stack.S | 1 + src/arch/x86/core/stack16.S | 1 + src/arch/x86/drivers/net/undiisr.S | 1 + src/arch/x86/interface/pcbios/e820mangler.S | 1 + src/arch/x86/interface/pxe/pxe_entry.S | 1 + src/arch/x86/interface/syslinux/com32_wrapper.S | 1 + src/arch/x86/prefix/bootpart.S | 1 + src/arch/x86/prefix/dskprefix.S | 1 + src/arch/x86/prefix/exeprefix.S | 1 + src/arch/x86/prefix/hdprefix.S | 1 + src/arch/x86/prefix/libprefix.S | 1 + src/arch/x86/prefix/lkrnprefix.S | 1 + src/arch/x86/prefix/mbr.S | 1 + src/arch/x86/prefix/mromprefix.S | 1 + src/arch/x86/prefix/nbiprefix.S | 1 + src/arch/x86/prefix/nullprefix.S | 1 + src/arch/x86/prefix/pxeprefix.S | 1 + src/arch/x86/prefix/rawprefix.S | 1 + src/arch/x86/prefix/romprefix.S | 1 + src/arch/x86/prefix/undiloader.S | 1 + src/arch/x86/prefix/unlzma.S | 1 + src/arch/x86/prefix/usbdisk.S | 1 + src/arch/x86/transitions/liba20.S | 1 + src/arch/x86/transitions/libkir.S | 1 + src/arch/x86/transitions/librm.S | 2 ++ src/arch/x86_64/core/gdbidt.S | 1 + src/arch/x86_64/core/setjmp.S | 1 + 32 files changed, 33 insertions(+) diff --git a/src/arch/arm64/core/setjmp.S b/src/arch/arm64/core/setjmp.S index fa47aa0a..c5c77c1f 100644 --- a/src/arch/arm64/core/setjmp.S +++ b/src/arch/arm64/core/setjmp.S @@ -1,5 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", %progbits .text /* Must match jmp_buf structure layout */ diff --git a/src/arch/i386/core/gdbidt.S b/src/arch/i386/core/gdbidt.S index 666ecce3..78945c62 100644 --- a/src/arch/i386/core/gdbidt.S +++ b/src/arch/i386/core/gdbidt.S @@ -9,6 +9,7 @@ * Interrupt handlers **************************************************************************** */ + .section ".note.GNU-stack", "", @progbits .section ".text", "ax", @progbits .code32 diff --git a/src/arch/i386/core/setjmp.S b/src/arch/i386/core/setjmp.S index 81d3b491..e0bbb7ef 100644 --- a/src/arch/i386/core/setjmp.S +++ b/src/arch/i386/core/setjmp.S @@ -1,5 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .text .arch i386 .code32 diff --git a/src/arch/i386/tests/gdbstub_test.S b/src/arch/i386/tests/gdbstub_test.S index 739b0527..e0c9e6c9 100644 --- a/src/arch/i386/tests/gdbstub_test.S +++ b/src/arch/i386/tests/gdbstub_test.S @@ -1,3 +1,4 @@ + .section ".note.GNU-stack", "", @progbits .arch i386 .section ".data", "aw", @progbits diff --git a/src/arch/x86/core/patch_cf.S b/src/arch/x86/core/patch_cf.S index 4365563f..63730c3f 100644 --- a/src/arch/x86/core/patch_cf.S +++ b/src/arch/x86/core/patch_cf.S @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .text .arch i386 .code16 diff --git a/src/arch/x86/core/stack.S b/src/arch/x86/core/stack.S index baa19ff8..49345347 100644 --- a/src/arch/x86/core/stack.S +++ b/src/arch/x86/core/stack.S @@ -1,5 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .arch i386 #ifdef __x86_64__ diff --git a/src/arch/x86/core/stack16.S b/src/arch/x86/core/stack16.S index ad67e4f2..d3949a55 100644 --- a/src/arch/x86/core/stack16.S +++ b/src/arch/x86/core/stack16.S @@ -1,5 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .arch i386 /**************************************************************************** diff --git a/src/arch/x86/drivers/net/undiisr.S b/src/arch/x86/drivers/net/undiisr.S index 2428d1f5..a1098b83 100644 --- a/src/arch/x86/drivers/net/undiisr.S +++ b/src/arch/x86/drivers/net/undiisr.S @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ) #define PIC1_ICR 0x20 #define PIC2_ICR 0xa0 + .section ".note.GNU-stack", "", @progbits .text .arch i386 .code16 diff --git a/src/arch/x86/interface/pcbios/e820mangler.S b/src/arch/x86/interface/pcbios/e820mangler.S index 296a6488..46e1cab4 100644 --- a/src/arch/x86/interface/pcbios/e820mangler.S +++ b/src/arch/x86/interface/pcbios/e820mangler.S @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .text .arch i386 .code16 diff --git a/src/arch/x86/interface/pxe/pxe_entry.S b/src/arch/x86/interface/pxe/pxe_entry.S index 3a5a100e..354dd1b3 100644 --- a/src/arch/x86/interface/pxe/pxe_entry.S +++ b/src/arch/x86/interface/pxe/pxe_entry.S @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include + .section ".note.GNU-stack", "", @progbits .arch i386 /**************************************************************************** diff --git a/src/arch/x86/interface/syslinux/com32_wrapper.S b/src/arch/x86/interface/syslinux/com32_wrapper.S index d59a3392..50191956 100644 --- a/src/arch/x86/interface/syslinux/com32_wrapper.S +++ b/src/arch/x86/interface/syslinux/com32_wrapper.S @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ) #include "librm.h" + .section ".note.GNU-stack", "", @progbits .text .code32 diff --git a/src/arch/x86/prefix/bootpart.S b/src/arch/x86/prefix/bootpart.S index 6d0c6034..575cb1c0 100644 --- a/src/arch/x86/prefix/bootpart.S +++ b/src/arch/x86/prefix/bootpart.S @@ -5,6 +5,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define STACK_SEG 0x0200 #define STACK_SIZE 0x2000 + .section ".note.GNU-stack", "", @progbits .text .arch i386 .section ".prefix", "awx", @progbits diff --git a/src/arch/x86/prefix/dskprefix.S b/src/arch/x86/prefix/dskprefix.S index 0503f113..bc194887 100644 --- a/src/arch/x86/prefix/dskprefix.S +++ b/src/arch/x86/prefix/dskprefix.S @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_ONLY ) .equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */ + .section ".note.GNU-stack", "", @progbits .org 0 .arch i386 .text diff --git a/src/arch/x86/prefix/exeprefix.S b/src/arch/x86/prefix/exeprefix.S index 0eab8c12..5b2605e8 100644 --- a/src/arch/x86/prefix/exeprefix.S +++ b/src/arch/x86/prefix/exeprefix.S @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define PSP_CMDLINE_LEN 0x80 #define PSP_CMDLINE_START 0x81 + .section ".note.GNU-stack", "", @progbits .text .arch i386 .org 0 diff --git a/src/arch/x86/prefix/hdprefix.S b/src/arch/x86/prefix/hdprefix.S index 28c8a532..fbf8d2e4 100644 --- a/src/arch/x86/prefix/hdprefix.S +++ b/src/arch/x86/prefix/hdprefix.S @@ -2,6 +2,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include + .section ".note.GNU-stack", "", @progbits .text .arch i386 .section ".prefix", "awx", @progbits diff --git a/src/arch/x86/prefix/libprefix.S b/src/arch/x86/prefix/libprefix.S index d7f26195..380e471d 100644 --- a/src/arch/x86/prefix/libprefix.S +++ b/src/arch/x86/prefix/libprefix.S @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include + .section ".note.GNU-stack", "", @progbits .arch i386 /* Image compression enabled */ diff --git a/src/arch/x86/prefix/lkrnprefix.S b/src/arch/x86/prefix/lkrnprefix.S index 922181f0..2c17f79d 100644 --- a/src/arch/x86/prefix/lkrnprefix.S +++ b/src/arch/x86/prefix/lkrnprefix.S @@ -4,6 +4,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define BZI_LOAD_HIGH_ADDR 0x100000 + .section ".note.GNU-stack", "", @progbits .text .arch i386 .code16 diff --git a/src/arch/x86/prefix/mbr.S b/src/arch/x86/prefix/mbr.S index 032c0e77..928bb338 100644 --- a/src/arch/x86/prefix/mbr.S +++ b/src/arch/x86/prefix/mbr.S @@ -1,5 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .text .arch i386 .section ".prefix", "awx", @progbits diff --git a/src/arch/x86/prefix/mromprefix.S b/src/arch/x86/prefix/mromprefix.S index d08284d7..5f3496b2 100644 --- a/src/arch/x86/prefix/mromprefix.S +++ b/src/arch/x86/prefix/mromprefix.S @@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define _pcirom_start _mrom_start #include "pciromprefix.S" + .section ".note.GNU-stack", "", @progbits .text .arch i386 .code16 diff --git a/src/arch/x86/prefix/nbiprefix.S b/src/arch/x86/prefix/nbiprefix.S index de38e4af..cae1009b 100644 --- a/src/arch/x86/prefix/nbiprefix.S +++ b/src/arch/x86/prefix/nbiprefix.S @@ -2,6 +2,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include + .section ".note.GNU-stack", "", @progbits .text .arch i386 .code16 diff --git a/src/arch/x86/prefix/nullprefix.S b/src/arch/x86/prefix/nullprefix.S index bd0ff339..1568188d 100644 --- a/src/arch/x86/prefix/nullprefix.S +++ b/src/arch/x86/prefix/nullprefix.S @@ -1,5 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .org 0 .text .arch i386 diff --git a/src/arch/x86/prefix/pxeprefix.S b/src/arch/x86/prefix/pxeprefix.S index 52ea1803..494fbc13 100644 --- a/src/arch/x86/prefix/pxeprefix.S +++ b/src/arch/x86/prefix/pxeprefix.S @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define PXE_HACK_EB54 0x0001 + .section ".note.GNU-stack", "", @progbits .text .arch i386 .org 0 diff --git a/src/arch/x86/prefix/rawprefix.S b/src/arch/x86/prefix/rawprefix.S index 4cf5f391..4a3d3504 100644 --- a/src/arch/x86/prefix/rawprefix.S +++ b/src/arch/x86/prefix/rawprefix.S @@ -8,6 +8,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .text .arch i386 .org 0 diff --git a/src/arch/x86/prefix/romprefix.S b/src/arch/x86/prefix/romprefix.S index 4e8793c2..79fed2a3 100644 --- a/src/arch/x86/prefix/romprefix.S +++ b/src/arch/x86/prefix/romprefix.S @@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define BUSTYPE "PCIR" #endif + .section ".note.GNU-stack", "", @progbits .text .code16 .arch i386 diff --git a/src/arch/x86/prefix/undiloader.S b/src/arch/x86/prefix/undiloader.S index 1d77110e..e544d504 100644 --- a/src/arch/x86/prefix/undiloader.S +++ b/src/arch/x86/prefix/undiloader.S @@ -2,6 +2,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include + .section ".note.GNU-stack", "", @progbits .text .code16 .arch i386 diff --git a/src/arch/x86/prefix/unlzma.S b/src/arch/x86/prefix/unlzma.S index 979f699e..f4bd81bd 100644 --- a/src/arch/x86/prefix/unlzma.S +++ b/src/arch/x86/prefix/unlzma.S @@ -43,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); **************************************************************************** */ + .section ".note.GNU-stack", "", @progbits .text .arch i486 .section ".prefix.lib", "ax", @progbits diff --git a/src/arch/x86/prefix/usbdisk.S b/src/arch/x86/prefix/usbdisk.S index 977de6dd..461a0837 100644 --- a/src/arch/x86/prefix/usbdisk.S +++ b/src/arch/x86/prefix/usbdisk.S @@ -2,6 +2,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #include + .section ".note.GNU-stack", "", @progbits .text .arch i386 .section ".prefix", "awx", @progbits diff --git a/src/arch/x86/transitions/liba20.S b/src/arch/x86/transitions/liba20.S index 57603353..6c1bac67 100644 --- a/src/arch/x86/transitions/liba20.S +++ b/src/arch/x86/transitions/liba20.S @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .arch i386 /**************************************************************************** diff --git a/src/arch/x86/transitions/libkir.S b/src/arch/x86/transitions/libkir.S index fa9459d5..af090b26 100644 --- a/src/arch/x86/transitions/libkir.S +++ b/src/arch/x86/transitions/libkir.S @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) /* Breakpoint for when debugging under bochs */ #define BOCHSBP xchgw %bx, %bx + .section ".note.GNU-stack", "", @progbits .text .arch i386 .section ".text16", "awx", @progbits diff --git a/src/arch/x86/transitions/librm.S b/src/arch/x86/transitions/librm.S index 5dacb9b0..39431324 100644 --- a/src/arch/x86/transitions/librm.S +++ b/src/arch/x86/transitions/librm.S @@ -83,6 +83,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) #define if64 if 0 #endif + .section ".note.GNU-stack", "", @progbits + /**************************************************************************** * Global descriptor table * diff --git a/src/arch/x86_64/core/gdbidt.S b/src/arch/x86_64/core/gdbidt.S index 89280bf8..477492b4 100644 --- a/src/arch/x86_64/core/gdbidt.S +++ b/src/arch/x86_64/core/gdbidt.S @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define SIGFPE 8 #define SIGSTKFLT 16 + .section ".note.GNU-stack", "", @progbits .section ".text.gdbmach_interrupt", "ax", @progbits .code64 diff --git a/src/arch/x86_64/core/setjmp.S b/src/arch/x86_64/core/setjmp.S index e43200d7..5137a72c 100644 --- a/src/arch/x86_64/core/setjmp.S +++ b/src/arch/x86_64/core/setjmp.S @@ -1,5 +1,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + .section ".note.GNU-stack", "", @progbits .text .code64 -- cgit v1.2.3-55-g7522 From 6f57d919357a43507935a5ea78a66702ac0f3d54 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 30 Jun 2023 12:03:41 +0100 Subject: [build] Use separate code segment if supported by linker Some versions of ld will complain that the automatically created (and unused by our build process) ELF program headers include a "LOAD segment with RWX permissions". Silence this warning by adding "-z separate-code" to the linker options, where supported. For BIOS builds, where the prefix will generally require writable access to its own (tiny) code segment, simply inhibit the warning completely via "--no-warn-rwx-segments". Signed-off-by: Michael Brown --- src/Makefile.housekeeping | 7 +++++++ src/arch/x86/Makefile.pcbios | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index b32003ea..4a90b3ca 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -502,6 +502,13 @@ LDFLAGS += --gc-sections # LDFLAGS += -static +# Use separate code segment if supported by linker +# +ZSC_TEST = $(LD) -z separate-code --version 2>&1 > /dev/null +ZSC_FLAGS := $(shell [ -z "`$(ZSC_TEST)`" ] && \ + $(ECHO) '-z separate-code -z max-page-size=4096') +LDFLAGS += $(ZSC_FLAGS) + # compiler.h is needed for our linking and debugging system # CFLAGS += -include include/compiler.h diff --git a/src/arch/x86/Makefile.pcbios b/src/arch/x86/Makefile.pcbios index b9f8e6c2..38dfa087 100644 --- a/src/arch/x86/Makefile.pcbios +++ b/src/arch/x86/Makefile.pcbios @@ -13,6 +13,13 @@ LDSCRIPT_PREFIX = arch/x86/scripts/prefixonly.lds # LDFLAGS += -N --no-check-sections +# Do not warn about RWX segments (required by most prefixes) +# +WRWX_TEST = $(LD) --warn-rwx-segments --version 2>&1 > /dev/null +WRWX_FLAGS := $(shell [ -z "`$(WRWX_TEST)`" ] && \ + $(ECHO) '--no-warn-rwx-segments') +LDFLAGS += $(WRWX_FLAGS) + # Media types. # MEDIA += rom -- cgit v1.2.3-55-g7522 From cc07ed7c7ede8dfc79643ccabb32285c74d6bff5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Jul 2023 14:17:48 +0100 Subject: [console] Avoid overlap between remapping flags and character values The keyboard remapping flags currently occupy bits 8 and upwards of the to-be-mapped character value. This overlaps the range used for special keys (KEY_MIN and upwards) and also overlaps the valid Unicode character range. No conflict is created by this overlap, since by design only ASCII character values (as generated by an ASCII-only keyboard driver) are subject to remapping, and so the to-be-remapped character values exist in a conceptually separate namespace from either special keys or non-ASCII Unicode characters. However, the overlap is potentially confusing for readers of the code. Minimise cognitive load by using bits 24 and upwards for the keyboard remapping flags. Signed-off-by: Michael Brown --- src/include/ipxe/keymap.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 8bfbe07a..49a8915e 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -52,10 +52,10 @@ struct keymap { #define KEYMAP_PSEUDO 0x80 /** Ctrl key flag */ -#define KEYMAP_CTRL 0x0100 +#define KEYMAP_CTRL 0x01000000 /** CapsLock key flag */ -#define KEYMAP_CAPSLOCK 0x0200 +#define KEYMAP_CAPSLOCK 0x02000000 /** Undo CapsLock key flag * @@ -64,13 +64,13 @@ struct keymap { * in order to correctly handle keyboard mappings that swap alphabetic * and non-alphabetic keys. */ -#define KEYMAP_CAPSLOCK_UNDO 0x0400 +#define KEYMAP_CAPSLOCK_UNDO 0x04000000 /** Undo and redo CapsLock key flags */ #define KEYMAP_CAPSLOCK_REDO ( KEYMAP_CAPSLOCK | KEYMAP_CAPSLOCK_UNDO ) /** AltGr key flag */ -#define KEYMAP_ALTGR 0x0800 +#define KEYMAP_ALTGR 0x08000000 extern unsigned int key_remap ( unsigned int character ); extern struct keymap * keymap_find ( const char *name ); -- cgit v1.2.3-55-g7522 From 3ef4f7e2ef4a22ea1e2eccc72957d7bf3fe2f945 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Jul 2023 14:31:07 +0100 Subject: [console] Avoid overlap between special keys and Unicode characters The special key range (from KEY_MIN upwards) currently overlaps with the valid range for Unicode characters, and therefore prohibits the use of Unicode key values outside the ASCII range. Create space for Unicode key values by moving the special keys to the range immediately above the maximum valid Unicode character. This allows the existing encoding of special keys as an efficiently packed representation of the equivalent ANSI escape sequence to be maintained almost as-is. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/bios_console.c | 59 +++++++++++++++++----------- src/drivers/usb/usbkbd.c | 4 +- src/include/ipxe/keys.h | 45 ++++++++++++++++++--- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 0220c856..7263eb71 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -290,29 +290,38 @@ static const char *bios_ansi_input = ""; struct bios_key { /** Scancode */ uint8_t scancode; - /** Key code */ - uint16_t key; + /** Relative key value */ + uint16_t rkey; } __attribute__ (( packed )); +/** + * Define a BIOS key mapping + * + * @v scancode Scancode + * @v key iPXE key code + * @v bioskey BIOS key mapping + */ +#define BIOS_KEY( scancode, key ) { scancode, KEY_REL ( key ) } + /** Mapping from BIOS scan codes to iPXE key codes */ static const struct bios_key bios_keys[] = { - { 0x53, KEY_DC }, - { 0x48, KEY_UP }, - { 0x50, KEY_DOWN }, - { 0x4b, KEY_LEFT }, - { 0x4d, KEY_RIGHT }, - { 0x47, KEY_HOME }, - { 0x4f, KEY_END }, - { 0x49, KEY_PPAGE }, - { 0x51, KEY_NPAGE }, - { 0x3f, KEY_F5 }, - { 0x40, KEY_F6 }, - { 0x41, KEY_F7 }, - { 0x42, KEY_F8 }, - { 0x43, KEY_F9 }, - { 0x44, KEY_F10 }, - { 0x85, KEY_F11 }, - { 0x86, KEY_F12 }, + BIOS_KEY ( 0x53, KEY_DC ), + BIOS_KEY ( 0x48, KEY_UP ), + BIOS_KEY ( 0x50, KEY_DOWN ), + BIOS_KEY ( 0x4b, KEY_LEFT ), + BIOS_KEY ( 0x4d, KEY_RIGHT ), + BIOS_KEY ( 0x47, KEY_HOME ), + BIOS_KEY ( 0x4f, KEY_END ), + BIOS_KEY ( 0x49, KEY_PPAGE ), + BIOS_KEY ( 0x51, KEY_NPAGE ), + BIOS_KEY ( 0x3f, KEY_F5 ), + BIOS_KEY ( 0x40, KEY_F6 ), + BIOS_KEY ( 0x41, KEY_F7 ), + BIOS_KEY ( 0x42, KEY_F8 ), + BIOS_KEY ( 0x43, KEY_F9 ), + BIOS_KEY ( 0x44, KEY_F10 ), + BIOS_KEY ( 0x85, KEY_F11 ), + BIOS_KEY ( 0x86, KEY_F12 ), }; /** @@ -323,7 +332,7 @@ static const struct bios_key bios_keys[] = { */ static const char * bios_ansi_seq ( unsigned int scancode ) { static char buf[ 5 /* "[" + two digits + terminator + NUL */ ]; - unsigned int key; + unsigned int rkey; unsigned int terminator; unsigned int n; unsigned int i; @@ -338,9 +347,9 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { continue; /* Construct escape sequence */ - key = bios_keys[i].key; - n = KEY_ANSI_N ( key ); - terminator = KEY_ANSI_TERMINATOR ( key ); + rkey = bios_keys[i].rkey; + n = KEY_ANSI_N ( rkey ); + terminator = KEY_ANSI_TERMINATOR ( rkey ); *(tmp++) = '['; if ( n ) tmp += sprintf ( tmp, "%d", n ); @@ -479,6 +488,7 @@ struct console_driver bios_console __console_driver = { static __asmcall __used void bios_inject ( struct i386_all_regs *ix86 ) { unsigned int discard_a; unsigned int scancode; + unsigned int rkey; unsigned int i; uint16_t keypress; int key; @@ -521,9 +531,10 @@ static __asmcall __used void bios_inject ( struct i386_all_regs *ix86 ) { /* Handle special keys */ if ( key >= KEY_MIN ) { + rkey = KEY_REL ( key ); for ( i = 0 ; i < ( sizeof ( bios_keys ) / sizeof ( bios_keys[0] ) ) ; i++ ) { - if ( bios_keys[i].key == key ) { + if ( bios_keys[i].rkey == rkey ) { scancode = bios_keys[i].scancode; keypress = ( scancode << 8 ); break; diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index b284e584..cf881ad1 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -95,7 +95,7 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, } } else if ( keycode <= USBKBD_KEY_UP ) { /* Special keys */ - static const uint16_t special[] = { + static const unsigned int special[] = { 0, 0, 0, 0, 0, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, KEY_IC, KEY_HOME, KEY_PPAGE, KEY_DC, KEY_END, KEY_NPAGE, KEY_RIGHT, @@ -110,7 +110,7 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, if ( leds & USBKBD_LED_NUM_LOCK ) { key = "1234567890." [ keycode - USBKBD_KEY_PAD_1 ]; } else { - static const uint16_t keypad[] = { + static const unsigned int keypad[] = { KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, 0, KEY_RIGHT, KEY_HOME, KEY_UP, KEY_PPAGE, KEY_IC, KEY_DC diff --git a/src/include/ipxe/keys.h b/src/include/ipxe/keys.h index d15267a1..23356913 100644 --- a/src/include/ipxe/keys.h +++ b/src/include/ipxe/keys.h @@ -49,19 +49,54 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ESC 0x1b /* - * Special keys outside the normal ASCII range - * + * Special keys outside the normal Unicode range * * The names are chosen to match those used by curses. The values are * chosen to facilitate easy conversion from a received ANSI escape * sequence to a KEY_XXX constant. */ -#define KEY_ANSI( n, terminator ) ( 0x100 * ( (n) + 1 ) + (terminator) ) -#define KEY_ANSI_N( key ) ( ( (key) / 0x100 ) - 1 ) +/** + * Minimum value for special keypresses + * + * This value is chosen to lie above the maximum Unicode code point + * value 0x10ffff. + */ +#define KEY_MIN 0x110000 + +/** + * Construct relative key value for special key + * + * @v key Key value + * @ret rkey Relative key value + */ +#define KEY_REL( key ) ( (key) - KEY_MIN ) + +/** + * Construct ANSI escape sequence key value + * + * @v n ANSI escape sequence numeric portion, or 0 for none + * @v terminator ANSI escape sequence terminating character + * @ret key Key value + */ +#define KEY_ANSI( n, terminator ) ( KEY_MIN + ( (n) << 8 ) + (terminator) ) + +/** + * Extract ANSI escape sequence numeric portion + * + * @v key Key value (or relative key value) + * @ret n ANSI escape sequence numeric portion, or 0 for none + */ +#define KEY_ANSI_N( key ) ( ( (key) >> 8 ) & 0xff ) + +/** + * Extract ANSI escape sequence terminating character + * + * @v key Key value (or relative key value) + * @ret terminator ANSI escape sequence terminating character + */ #define KEY_ANSI_TERMINATOR( key ) ( (key) & 0xff ) -#define KEY_MIN 0x101 #define KEY_UP KEY_ANSI ( 0, 'A' ) /**< Up arrow */ #define KEY_DOWN KEY_ANSI ( 0, 'B' ) /**< Down arrow */ #define KEY_RIGHT KEY_ANSI ( 0, 'C' ) /**< Right arrow */ -- cgit v1.2.3-55-g7522 From daa9e54ab8207ea9bae80db16d664d019d590fb2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Jul 2023 14:55:53 +0100 Subject: [build] Silence the "creating blib.a" message Signed-off-by: Michael Brown --- src/Makefile.housekeeping | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index 4a90b3ca..3b8ee258 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -1178,7 +1178,7 @@ BLIB = $(BIN)/blib.a $(BLIB) : $(BLIB_OBJS) $(BLIB_LIST) $(MAKEDEPS) $(Q)$(RM) $(BLIB) $(QM)$(ECHO) " [AR] $@" - $(Q)$(AR) rD $@ $(sort $(BLIB_OBJS)) + $(Q)$(AR) rcD $@ $(sort $(BLIB_OBJS)) $(Q)$(OBJCOPY) --enable-deterministic-archives \ --prefix-symbols=$(SYMBOL_PREFIX) $@ $(Q)$(RANLIB) -D $@ -- cgit v1.2.3-55-g7522 From 824441069010806b63cc5d110e5acd1f1d1ee858 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Jul 2023 15:12:49 +0100 Subject: [build] Inhibit more linker warnings about an implied executable stack Add .note.GNU-stack section declarations to the autogenerated PCI device ID list objects. Signed-off-by: Michael Brown --- src/Makefile.housekeeping | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index 3b8ee258..d13cb367 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -1009,6 +1009,7 @@ endif # Device ID tables (using IDs from ROM definition file) # define obj_pci_id_asm + .section ".note.GNU-stack", "", $(ASM_TCHAR)progbits .section ".pci_devlist.$(1)", "a", $(ASM_TCHAR)progbits .globl pci_devlist_$(1) pci_devlist_$(1): -- cgit v1.2.3-55-g7522 From b5b60ea33dc48a297515f95ac19cca20bb39edd1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 4 Jul 2023 16:50:03 +0100 Subject: [interface] Fix debug message values for temporary interfaces The interface debug message values constructed by INTF_DBG() et al rely on the interface being embedded within a containing object. This assumption is not valid for the temporary outbound-only interfaces constructed on the stack by intf_shutdown() and xfer_vredirect(). Formalise the notion of a temporary outbound-only interface as having a NULL interface descriptor, and overload the "original interface descriptor" field to contain a pointer to the original interface that the temporary interface is shadowing. Originally-fixed-by: Vincent Fazio Signed-off-by: Michael Brown --- src/core/interface.c | 1 + src/core/xfer.c | 3 +- src/include/ipxe/interface.h | 72 ++++++++++++++++++++++++++++++++++---------- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/core/interface.c b/src/core/interface.c index 34a4180a..ea060689 100644 --- a/src/core/interface.c +++ b/src/core/interface.c @@ -285,6 +285,7 @@ void intf_shutdown ( struct interface *intf, int rc ) { intf_nullify ( intf ); /* Transfer destination to temporary interface */ + intf_temp_init ( &tmp, intf ); tmp.dest = intf->dest; intf->dest = &null_intf; diff --git a/src/core/xfer.c b/src/core/xfer.c index 0faf3292..269359e1 100644 --- a/src/core/xfer.c +++ b/src/core/xfer.c @@ -60,7 +60,7 @@ static struct xfer_metadata dummy_metadata; * @ret rc Return status code */ int xfer_vredirect ( struct interface *intf, int type, va_list args ) { - struct interface tmp = INTF_INIT ( null_intf_desc ); + struct interface tmp; struct interface *dest; xfer_vredirect_TYPE ( void * ) *op = intf_get_dest_op_no_passthru ( intf, xfer_vredirect, &dest ); @@ -85,6 +85,7 @@ int xfer_vredirect ( struct interface *intf, int type, va_list args ) { * If redirection fails, then send intf_close() to the * parent interface. */ + intf_temp_init ( &tmp, intf ); intf_plug ( &tmp, dest ); rc = xfer_vreopen ( dest, type, args ); if ( rc == 0 ) { diff --git a/src/include/ipxe/interface.h b/src/include/ipxe/interface.h index 19f58a4b..d2fa8190 100644 --- a/src/include/ipxe/interface.h +++ b/src/include/ipxe/interface.h @@ -133,17 +133,30 @@ struct interface { struct interface *dest; /** Reference counter * - * If this interface is not part of a reference-counted - * object, this field may be NULL. + * If this interface is not part of a reference-counted object + * then this field is NULL. */ struct refcnt *refcnt; - /** Interface descriptor */ - struct interface_descriptor *desc; - /** Original interface descriptor + /** Interface descriptor * - * Used by intf_reinit(). + * If this is a temporary outbound-only interface created by + * intf_temp_init() then this field is NULL. */ - struct interface_descriptor *original; + struct interface_descriptor *desc; + /** Original interface properties */ + union { + /** Original interface descriptor + * + * Used by intf_reinit(). + */ + struct interface_descriptor *desc; + /** Original interface + * + * Used for temporary outbound-only interfaces created + * by intf_temp_init(). + */ + struct interface *intf; + } original; }; extern void intf_plug ( struct interface *intf, struct interface *dest ); @@ -193,7 +206,7 @@ static inline void intf_init ( struct interface *intf, intf->dest = &null_intf; intf->refcnt = refcnt; intf->desc = desc; - intf->original = desc; + intf->original.desc = desc; } /** @@ -201,13 +214,38 @@ static inline void intf_init ( struct interface *intf, * * @v descriptor Object interface descriptor */ -#define INTF_INIT( descriptor ) { \ - .dest = &null_intf, \ - .refcnt = NULL, \ - .desc = &(descriptor), \ - .original = &(descriptor), \ +#define INTF_INIT( descriptor ) { \ + .dest = &null_intf, \ + .refcnt = NULL, \ + .desc = &(descriptor), \ + .original = { \ + .desc = &(descriptor), \ + }, \ } +/** + * Initialise a temporary outbound-only object interface + * + * @v intf Temporary outbound-only object interface + * @v original Original object interface + */ +static inline void intf_temp_init ( struct interface *intf, + struct interface *original ) { + intf->dest = &null_intf; + intf->desc = NULL; + intf->original.intf = original; +} + +/** + * Get original interface + * + * @v intf Object interface (possibly a temporary interface) + * @ret intf Original object interface + */ +static inline struct interface * intf_origin ( struct interface *intf ) { + return ( intf->desc ? intf : intf->original.intf ); +} + /** * Get object interface destination and operation method (without pass-through) * @@ -240,7 +278,7 @@ static inline void intf_init ( struct interface *intf, * * Use as the first argument to DBGC() or equivalent macro. */ -#define INTF_COL( intf ) intf_object ( intf ) +#define INTF_COL( intf ) intf_object ( intf_origin ( intf ) ) /** printf() format string for INTF_DBG() */ #define INTF_FMT "%p+%zx" @@ -251,7 +289,9 @@ static inline void intf_init ( struct interface *intf, * @v intf Object interface * @ret args printf() argument list corresponding to INTF_FMT */ -#define INTF_DBG( intf ) intf_object ( intf ), (intf)->desc->offset +#define INTF_DBG( intf ) \ + intf_object ( intf_origin ( intf ) ), \ + intf_origin ( intf )->desc->offset /** printf() format string for INTF_INTF_DBG() */ #define INTF_INTF_FMT INTF_FMT "->" INTF_FMT @@ -273,7 +313,7 @@ static inline void intf_init ( struct interface *intf, static inline void intf_reinit ( struct interface *intf ) { /* Restore original interface descriptor */ - intf->desc = intf->original; + intf->desc = intf->original.desc; } #endif /* _IPXE_INTERFACE_H */ -- cgit v1.2.3-55-g7522 From 6701d91c5033a3804a3bb5d49a8f9f2212b901b4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 5 Jul 2023 14:30:54 +0100 Subject: [netdevice] Stop link block timer when device is closed A running link block timer holds a reference to the network device and will prevent it from being freed until the timer expires. It is impossible for free_netdev() to be called while the timer is still running: the call to stop_timer() therein is therefore a no-op. Stop the link block timer when the device is closed, to allow a link-blocked device to be freed immediately upon unregistration of the device. (Since link block state is updated in response to received packets, the state is effectively undefined for a closed device: there is therefore no reason to leave the timer running.) Signed-off-by: Michael Brown --- src/net/netdevice.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 07961bf2..91517821 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -656,7 +656,7 @@ static void free_netdev ( struct refcnt *refcnt ) { struct net_device *netdev = container_of ( refcnt, struct net_device, refcnt ); - stop_timer ( &netdev->link_block ); + assert ( ! timer_running ( &netdev->link_block ) ); netdev_tx_flush ( netdev ); netdev_rx_flush ( netdev ); clear_settings ( netdev_settings ( netdev ) ); @@ -879,6 +879,9 @@ void netdev_close ( struct net_device *netdev ) { /* Close the device */ netdev->op->close ( netdev ); + /* Stop link block timer */ + stop_timer ( &netdev->link_block ); + /* Flush TX and RX queues */ netdev_tx_flush ( netdev ); netdev_rx_flush ( netdev ); -- cgit v1.2.3-55-g7522 From 48ae5d53617f3eacff825a128c56bd74b4860bea Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 5 Jul 2023 14:46:41 +0100 Subject: [linux] Fix error control flow in tap_probe() Signed-off-by: Michael Brown --- src/drivers/linux/tap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/linux/tap.c b/src/drivers/linux/tap.c index ff1e08bd..9b52c20a 100644 --- a/src/drivers/linux/tap.c +++ b/src/drivers/linux/tap.c @@ -231,9 +231,9 @@ static int tap_probe(struct linux_device *device, struct linux_device_request *r return 0; -err_settings: unregister_netdev(netdev); err_register: +err_settings: netdev_nullify(netdev); netdev_put(netdev); return rc; -- cgit v1.2.3-55-g7522 From 59d065c9ac6e5476a21fb9b277f719fd4ae5b372 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 5 Jul 2023 15:17:58 +0100 Subject: [linux] Fix error control flow in af_packet_nic_probe() Signed-off-by: Michael Brown --- src/drivers/linux/af_packet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drivers/linux/af_packet.c b/src/drivers/linux/af_packet.c index 9fa6ef2a..980bd462 100644 --- a/src/drivers/linux/af_packet.c +++ b/src/drivers/linux/af_packet.c @@ -300,9 +300,9 @@ static int af_packet_nic_probe ( struct linux_device *device, return 0; -err_settings: unregister_netdev(netdev); err_register: +err_settings: netdev_nullify(netdev); netdev_put(netdev); return rc; -- cgit v1.2.3-55-g7522 From f3036fc213b6e6cce0bf5572167b93b9e9959a3a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 5 Jul 2023 15:24:32 +0100 Subject: [linux] Set a default MAC address for tap devices Avoid the need to always specify a local MAC address on the command line by setting a default hardware MAC address (using the same default address as for slirp devices). Signed-off-by: Michael Brown --- src/drivers/linux/tap.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/drivers/linux/tap.c b/src/drivers/linux/tap.c index 9b52c20a..c1364ddb 100644 --- a/src/drivers/linux/tap.c +++ b/src/drivers/linux/tap.c @@ -56,6 +56,10 @@ struct tap_nic { int fd; }; +/** Default MAC address */ +static const uint8_t tap_default_mac[ETH_ALEN] = + { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 }; + /** Open the TAP device */ static int tap_open(struct net_device * netdev) { @@ -202,6 +206,7 @@ static int tap_probe(struct linux_device *device, struct linux_device_request *r nic = netdev->priv; linux_set_drvdata(device, netdev); netdev->dev = &device->dev; + memcpy ( netdev->hw_addr, tap_default_mac, ETH_ALEN ); memset(nic, 0, sizeof(*nic)); /* Look for the mandatory if setting */ -- cgit v1.2.3-55-g7522 From c30b71ee9cc2dc2a1d2f225d99f2d70dd73de247 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 7 Jul 2023 15:05:39 +0100 Subject: [console] Restore compatibility with "--key" values in existing scripts Commit 3ef4f7e ("[console] Avoid overlap between special keys and Unicode characters") renumbered the special key encoding to avoid collisions with Unicode key values outside the ASCII range. This change broke backwards compatibility with existing scripts that specify key values using e.g. "prompt --key" or "menu --key". Restore compatibility with existing scripts by tweaking the special key encoding so that the relative key value (i.e. the delta from KEY_MIN) is numerically equal to the old pre-Unicode key value, and by modifying parse_key() to accept a relative key value. Reported-by: Sven Dreyer Signed-off-by: Michael Brown --- src/core/parseopt.c | 15 ++++++++++++++- src/include/ctype.h | 11 +++++++++++ src/include/ipxe/keys.h | 8 ++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/core/parseopt.c b/src/core/parseopt.c index 1dbfc7ae..cd3b3101 100644 --- a/src/core/parseopt.c +++ b/src/core/parseopt.c @@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -213,6 +215,7 @@ int parse_flag ( char *text __unused, int *flag ) { * @ret rc Return status code */ int parse_key ( char *text, unsigned int *key ) { + int rc; /* Interpret single characters as being a literal key character */ if ( text[0] && ! text[1] ) { @@ -221,7 +224,17 @@ int parse_key ( char *text, unsigned int *key ) { } /* Otherwise, interpret as an integer */ - return parse_integer ( text, key ); + if ( ( rc = parse_integer ( text, key ) ) < 0 ) + return rc; + + /* For backwards compatibility with existing scripts, treat + * integers between the ASCII range and special key range as + * being relative special key values. + */ + if ( ( ! isascii ( *key ) ) && ( *key < KEY_MIN ) ) + *key += KEY_MIN; + + return 0; } /** diff --git a/src/include/ctype.h b/src/include/ctype.h index 0d79ecd1..6fefd5d7 100644 --- a/src/include/ctype.h +++ b/src/include/ctype.h @@ -9,6 +9,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +/** + * Check if character is ASCII + * + * @v character Character + * @ret is_ascii Character is an ASCII character + */ +static inline int isascii ( int character ) { + + return ( character <= '\x7f' ); +} + /** * Check if character is a decimal digit * diff --git a/src/include/ipxe/keys.h b/src/include/ipxe/keys.h index 23356913..49e65fa4 100644 --- a/src/include/ipxe/keys.h +++ b/src/include/ipxe/keys.h @@ -54,6 +54,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * The names are chosen to match those used by curses. The values are * chosen to facilitate easy conversion from a received ANSI escape * sequence to a KEY_XXX constant. + * + * Note that the values are exposed to iPXE commands via parse_key() + * and therefore may not be changed without breaking existing scripts. */ /** @@ -79,7 +82,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v terminator ANSI escape sequence terminating character * @ret key Key value */ -#define KEY_ANSI( n, terminator ) ( KEY_MIN + ( (n) << 8 ) + (terminator) ) +#define KEY_ANSI( n, terminator ) \ + ( KEY_MIN + ( ( (n) + 1 ) << 8 ) + (terminator) ) /** * Extract ANSI escape sequence numeric portion @@ -87,7 +91,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v key Key value (or relative key value) * @ret n ANSI escape sequence numeric portion, or 0 for none */ -#define KEY_ANSI_N( key ) ( ( (key) >> 8 ) & 0xff ) +#define KEY_ANSI_N( key ) ( ( ( (key) >> 8 ) & 0xff ) - 1 ) /** * Extract ANSI escape sequence terminating character -- cgit v1.2.3-55-g7522 From d5c08f78bdf45668a955c1f3d3a96f35d8c0e91b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 19 Jul 2023 11:10:15 +0100 Subject: [ntp] Define NTP server setting Define the IPv4 NTP server setting to simplify the use of a DHCP-provided NTP server in scripts, using e.g. #!ipxe dhcp ntp ${ntp} Signed-off-by: Michael Brown --- src/include/ipxe/dhcp.h | 3 +++ src/net/udp/ntp.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index a1f9ee25..51349efd 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -86,6 +86,9 @@ struct dhcp_packet; /** Maximum transmission unit */ #define DHCP_MTU 26 +/** NTP servers */ +#define DHCP_NTP_SERVERS 42 + /** Vendor encapsulated options */ #define DHCP_VENDOR_ENCAP 43 diff --git a/src/net/udp/ntp.c b/src/net/udp/ntp.c index 11f8ccc0..55923357 100644 --- a/src/net/udp/ntp.c +++ b/src/net/udp/ntp.c @@ -36,6 +36,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include +#include #include /** @file @@ -273,3 +275,11 @@ int start_ntp ( struct interface *job, const char *hostname ) { err_alloc: return rc; } + +/** IPv4 NTP server setting */ +const struct setting ntp_setting __setting ( SETTING_IP4_EXTRA, ntp ) = { + .name = "ntp", + .description = "NTP server", + .tag = DHCP_NTP_SERVERS, + .type = &setting_type_ipv4, +}; -- cgit v1.2.3-55-g7522 From c1834f323f4f6b9b46cd5895b1457a117381363f Mon Sep 17 00:00:00 2001 From: Cornelius Hoffmann Date: Mon, 10 Jul 2023 22:24:26 +0200 Subject: [dhcp] Request NTP server option Signed-off-by: Michael Brown --- src/net/udp/dhcp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index bd2c4a19..8e2e97f1 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -91,9 +91,10 @@ static uint8_t dhcp_request_options_data[] = { DHCP_PARAMETER_REQUEST_LIST, DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS, DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME, - DHCP_ROOT_PATH, DHCP_MTU, DHCP_VENDOR_ENCAP, - DHCP_VENDOR_CLASS_ID, DHCP_TFTP_SERVER_NAME, - DHCP_BOOTFILE_NAME, DHCP_DOMAIN_SEARCH, + DHCP_ROOT_PATH, DHCP_MTU, DHCP_NTP_SERVERS, + DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID, + DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME, + DHCP_DOMAIN_SEARCH, 128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */ DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ), DHCP_END -- cgit v1.2.3-55-g7522 From 9e99a55b317f5da66f5110891b154084b337a031 Mon Sep 17 00:00:00 2001 From: Alexander Eichner Date: Fri, 18 Aug 2023 13:32:15 +0200 Subject: [virtio] Fix implementation of vpm_ioread32() The current implementation of vpm_ioread32() erroneously reads only 16 bits of data, which fails when used with the (stricter) virtio device emulation in VirtualBox. Fix by using the correct readl()/inl() I/O wrappers. Reworded-by: Michael Brown Signed-off-by: Michael Brown --- src/drivers/bus/virtio-pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/bus/virtio-pci.c b/src/drivers/bus/virtio-pci.c index 8b34c727..3fc93a90 100644 --- a/src/drivers/bus/virtio-pci.c +++ b/src/drivers/bus/virtio-pci.c @@ -230,10 +230,10 @@ u32 vpm_ioread32(struct virtio_pci_modern_device *vdev, uint32_t data; switch (region->flags & VIRTIO_PCI_REGION_TYPE_MASK) { case VIRTIO_PCI_REGION_MEMORY: - data = readw(region->base + offset); + data = readl(region->base + offset); break; case VIRTIO_PCI_REGION_PORT: - data = inw(region->base + offset); + data = inl(region->base + offset); break; case VIRTIO_PCI_REGION_PCI_CONFIG: prep_pci_cfg_cap(vdev, region, offset, 4); -- cgit v1.2.3-55-g7522 From 0aa2e4ec963597794dd8f8b36f77f4d0cf4e03c8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 5 Sep 2023 12:46:39 +0100 Subject: [librm] Use explicit operand size when pushing a label address We currently use "push $1f" within inline assembly to push the address of the real-mode code fragment, relying on the assembler to treat this as "pushl" for 32-bit code or "pushq" for 64-bit code. As of binutils commit 5cc0077 ("x86: further adjust extend-to-32bit- address conditions"), first included in binutils-2.41, this implicit operand size is no longer calculated as expected and 64-bit builds will fail with Error: operand size mismatch for `push' Fix by adding an explicit operand size to the "push" instruction. Originally-fixed-by: Justin Cano Signed-off-by: Michael Brown --- src/arch/x86/include/librm.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/arch/x86/include/librm.h b/src/arch/x86/include/librm.h index 5196d390..40f07543 100644 --- a/src/arch/x86/include/librm.h +++ b/src/arch/x86/include/librm.h @@ -250,8 +250,10 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size ); /* CODE_DEFAULT: restore default .code32/.code64 directive */ #ifdef __x86_64__ #define CODE_DEFAULT ".code64" +#define STACK_DEFAULT "q" #else #define CODE_DEFAULT ".code32" +#define STACK_DEFAULT "l" #endif /* LINE_SYMBOL: declare a symbol for the current source code line */ @@ -268,7 +270,7 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size ); /* REAL_CODE: declare a fragment of code that executes in real mode */ #define REAL_CODE( asm_code_str ) \ - "push $1f\n\t" \ + "push" STACK_DEFAULT " $1f\n\t" \ "call real_call\n\t" \ TEXT16_CODE ( "\n1:\n\t" \ asm_code_str \ @@ -277,7 +279,7 @@ extern void remove_user_from_rm_stack ( userptr_t data, size_t size ); /* PHYS_CODE: declare a fragment of code that executes in flat physical mode */ #define PHYS_CODE( asm_code_str ) \ - "push $1f\n\t" \ + "push" STACK_DEFAULT " $1f\n\t" \ "call phys_call\n\t" \ ".section \".text.phys\", \"ax\", @progbits\n\t"\ "\n" LINE_SYMBOL "\n\t" \ -- cgit v1.2.3-55-g7522 From eeb7cd56e54e2bc649626988872c170fba37c163 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Sep 2023 14:30:25 +0100 Subject: [netdevice] Remove netdev_priv() helper function Some network device drivers use the trivial netdev_priv() helper function while others use the netdev->priv pointer directly. Standardise on direct use of netdev->priv, in order to free up the function name netdev_priv() for reuse. Signed-off-by: Michael Brown --- src/drivers/net/3c90x.c | 20 +++++++++--------- src/drivers/net/atl1e.c | 18 ++++++++-------- src/drivers/net/b44.c | 16 +++++++-------- src/drivers/net/bnxt/bnxt.c | 18 ++++++++-------- src/drivers/net/eepro100.c | 2 +- src/drivers/net/efi/snpnet.c | 6 +++--- src/drivers/net/etherfabric.c | 14 ++++++------- src/drivers/net/forcedeth.c | 18 ++++++++-------- src/drivers/net/igbvf/igbvf_main.c | 18 ++++++++-------- src/drivers/net/jme.c | 2 +- src/drivers/net/pcnet32.c | 16 +++++++-------- src/drivers/net/phantom/phantom.c | 18 ++++++++-------- src/drivers/net/sfc/efx_common.c | 4 ++-- src/drivers/net/sfc/efx_hunt.c | 16 +++++++-------- src/drivers/net/sfc/sfc_hunt.c | 10 ++++----- src/drivers/net/sis190.c | 38 +++++++++++++++++----------------- src/drivers/net/skge.c | 42 +++++++++++++++++++------------------- src/drivers/net/sky2.c | 30 +++++++++++++-------------- src/drivers/net/tg3/tg3.c | 16 +++++++-------- src/drivers/net/tg3/tg3_hw.c | 2 +- src/drivers/net/vmxnet3.c | 26 +++++++++++------------ src/drivers/net/vxge/vxge_main.c | 14 ++++++------- src/include/ipxe/netdevice.h | 11 ---------- 23 files changed, 182 insertions(+), 193 deletions(-) diff --git a/src/drivers/net/3c90x.c b/src/drivers/net/3c90x.c index 63e07777..1b8190c4 100644 --- a/src/drivers/net/3c90x.c +++ b/src/drivers/net/3c90x.c @@ -272,7 +272,7 @@ static int a3c90x_setup_tx_ring(struct INF_3C90X *p) */ static void a3c90x_process_tx_packets(struct net_device *netdev) { - struct INF_3C90X *p = netdev_priv(netdev); + struct INF_3C90X *p = netdev->priv; unsigned int downlist_ptr; DBGP("a3c90x_process_tx_packets\n"); @@ -320,7 +320,7 @@ static void a3c90x_free_tx_ring(struct INF_3C90X *p) static int a3c90x_transmit(struct net_device *netdev, struct io_buffer *iob) { - struct INF_3C90X *inf_3c90x = netdev_priv(netdev); + struct INF_3C90X *inf_3c90x = netdev->priv; struct TXD *tx_cur_desc; struct TXD *tx_prev_desc; @@ -518,7 +518,7 @@ static void a3c90x_process_rx_packets(struct net_device *netdev) { int i; unsigned int rx_status; - struct INF_3C90X *p = netdev_priv(netdev); + struct INF_3C90X *p = netdev->priv; struct RXD *rx_cur_desc; DBGP("a3c90x_process_rx_packets\n"); @@ -567,7 +567,7 @@ static void a3c90x_process_rx_packets(struct net_device *netdev) */ static void a3c90x_poll(struct net_device *netdev) { - struct INF_3C90X *p = netdev_priv(netdev); + struct INF_3C90X *p = netdev->priv; uint16_t raw_status, int_status; DBGP("a3c90x_poll\n"); @@ -611,7 +611,7 @@ static void a3c90x_free_resources(struct INF_3C90X *p) static void a3c90x_remove(struct pci_device *pci) { struct net_device *netdev = pci_get_drvdata(pci); - struct INF_3C90X *inf_3c90x = netdev_priv(netdev); + struct INF_3C90X *inf_3c90x = netdev->priv; DBGP("a3c90x_remove\n"); @@ -628,7 +628,7 @@ static void a3c90x_remove(struct pci_device *pci) static void a3c90x_irq(struct net_device *netdev, int enable) { - struct INF_3C90X *p = netdev_priv(netdev); + struct INF_3C90X *p = netdev->priv; DBGP("a3c90x_irq\n"); @@ -657,7 +657,7 @@ static void a3c90x_hw_start(struct net_device *netdev) unsigned int cfg; unsigned int mopt; unsigned short linktype; - struct INF_3C90X *inf_3c90x = netdev_priv(netdev); + struct INF_3C90X *inf_3c90x = netdev->priv; DBGP("a3c90x_hw_start\n"); @@ -796,7 +796,7 @@ static void a3c90x_hw_start(struct net_device *netdev) static int a3c90x_open(struct net_device *netdev) { int rc; - struct INF_3C90X *inf_3c90x = netdev_priv(netdev); + struct INF_3C90X *inf_3c90x = netdev->priv; DBGP("a3c90x_open\n"); @@ -845,7 +845,7 @@ static int a3c90x_open(struct net_device *netdev) */ static void a3c90x_close(struct net_device *netdev) { - struct INF_3C90X *inf_3c90x = netdev_priv(netdev); + struct INF_3C90X *inf_3c90x = netdev->priv; DBGP("a3c90x_close\n"); @@ -895,7 +895,7 @@ static int a3c90x_probe(struct pci_device *pci) pci_set_drvdata(pci, netdev); netdev->dev = &pci->dev; - inf_3c90x = netdev_priv(netdev); + inf_3c90x = netdev->priv; memset(inf_3c90x, 0, sizeof(*inf_3c90x)); adjust_pci_device(pci); diff --git a/src/drivers/net/atl1e.c b/src/drivers/net/atl1e.c index 0f0df532..1acbb3ca 100644 --- a/src/drivers/net/atl1e.c +++ b/src/drivers/net/atl1e.c @@ -173,7 +173,7 @@ static int atl1e_check_link(struct atl1e_adapter *adapter) static int atl1e_mdio_read(struct net_device *netdev, int phy_id __unused, int reg_num) { - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; u16 result; atl1e_read_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, &result); @@ -183,7 +183,7 @@ static int atl1e_mdio_read(struct net_device *netdev, int phy_id __unused, static void atl1e_mdio_write(struct net_device *netdev, int phy_id __unused, int reg_num, int val) { - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; atl1e_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val); } @@ -841,7 +841,7 @@ fatal_err: */ static void atl1e_poll(struct net_device *netdev) { - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; struct atl1e_hw *hw = &adapter->hw; int max_ints = 64; u32 status; @@ -963,7 +963,7 @@ static void atl1e_tx_queue(struct atl1e_adapter *adapter, u16 count __unused, static int atl1e_xmit_frame(struct net_device *netdev, struct io_buffer *iob) { - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; u16 tpd_req = 1; struct atl1e_tpd_desc *tpd; @@ -1013,7 +1013,7 @@ int atl1e_up(struct atl1e_adapter *adapter) void atl1e_irq(struct net_device *netdev, int enable) { - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; if (enable) atl1e_irq_enable(adapter); @@ -1051,7 +1051,7 @@ void atl1e_down(struct atl1e_adapter *adapter) */ static int atl1e_open(struct net_device *netdev) { - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; int err; /* allocate rx/tx dma buffer & descriptors */ @@ -1086,7 +1086,7 @@ err_up: */ static void atl1e_close(struct net_device *netdev) { - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; atl1e_down(adapter); atl1e_free_ring_resources(adapter); @@ -1138,7 +1138,7 @@ static int atl1e_probe(struct pci_device *pdev) atl1e_init_netdev(netdev, pdev); - adapter = netdev_priv(netdev); + adapter = netdev->priv; adapter->bd_number = cards_found; adapter->netdev = netdev; adapter->pdev = pdev; @@ -1227,7 +1227,7 @@ err: static void atl1e_remove(struct pci_device *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct atl1e_adapter *adapter = netdev_priv(netdev); + struct atl1e_adapter *adapter = netdev->priv; unregister_netdev(netdev); atl1e_free_ring_resources(adapter); diff --git a/src/drivers/net/b44.c b/src/drivers/net/b44.c index eaf6d35c..1ca7e2e5 100644 --- a/src/drivers/net/b44.c +++ b/src/drivers/net/b44.c @@ -622,7 +622,7 @@ static void b44_load_mac_and_phy_addr(struct b44_private *bp) static void b44_set_rx_mode(struct net_device *netdev) { - struct b44_private *bp = netdev_priv(netdev); + struct b44_private *bp = netdev->priv; unsigned char zero[6] = { 0, 0, 0, 0, 0, 0 }; u32 val; int i; @@ -667,7 +667,7 @@ static int b44_probe(struct pci_device *pci) netdev->dev = &pci->dev; /* Set up private data */ - bp = netdev_priv(netdev); + bp = netdev->priv; memset(bp, 0, sizeof(*bp)); bp->netdev = netdev; bp->pci = pci; @@ -712,7 +712,7 @@ static int b44_probe(struct pci_device *pci) static void b44_remove(struct pci_device *pci) { struct net_device *netdev = pci_get_drvdata(pci); - struct b44_private *bp = netdev_priv(netdev); + struct b44_private *bp = netdev->priv; ssb_core_disable(bp); unregister_netdev(netdev); @@ -729,7 +729,7 @@ static void b44_remove(struct pci_device *pci) */ static void b44_irq(struct net_device *netdev, int enable) { - struct b44_private *bp = netdev_priv(netdev); + struct b44_private *bp = netdev->priv; /* Interrupt mask specifies which events generate interrupts */ bw32(bp, B44_IMASK, enable ? IMASK_DEF : IMASK_DISABLE); @@ -743,7 +743,7 @@ static void b44_irq(struct net_device *netdev, int enable) */ static int b44_open(struct net_device *netdev) { - struct b44_private *bp = netdev_priv(netdev); + struct b44_private *bp = netdev->priv; int rc; rc = b44_init_tx_ring(bp); @@ -769,7 +769,7 @@ static int b44_open(struct net_device *netdev) */ static void b44_close(struct net_device *netdev) { - struct b44_private *bp = netdev_priv(netdev); + struct b44_private *bp = netdev->priv; b44_chip_reset(bp, B44_FULL_RESET); b44_free_tx_ring(bp); @@ -785,7 +785,7 @@ static void b44_close(struct net_device *netdev) */ static int b44_transmit(struct net_device *netdev, struct io_buffer *iobuf) { - struct b44_private *bp = netdev_priv(netdev); + struct b44_private *bp = netdev->priv; u32 cur = bp->tx_cur; u32 ctrl; @@ -905,7 +905,7 @@ static void b44_process_rx_packets(struct b44_private *bp) */ static void b44_poll(struct net_device *netdev) { - struct b44_private *bp = netdev_priv(netdev); + struct b44_private *bp = netdev->priv; u32 istat; /* Interrupt status */ diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index e3876503..605aea32 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -307,7 +307,7 @@ void bnxt_set_txq ( struct bnxt *bp, int entry, dma_addr_t mapping, int len ) static void bnxt_tx_complete ( struct net_device *dev, u16 hw_idx ) { - struct bnxt *bp = netdev_priv ( dev ); + struct bnxt *bp = dev->priv; struct io_buffer *iob; iob = bp->tx.iob[hw_idx]; @@ -484,7 +484,7 @@ void bnxt_rx_process ( struct net_device *dev, struct bnxt *bp, static int bnxt_rx_complete ( struct net_device *dev, struct rx_pkt_cmpl *rx_cmp ) { - struct bnxt *bp = netdev_priv ( dev ); + struct bnxt *bp = dev->priv; struct rx_pkt_cmpl_hi *rx_cmp_hi; u8 cmpl_bit = bp->cq.completion_bit; @@ -1927,7 +1927,7 @@ int bnxt_hwrm_run ( hwrm_func_t cmds[], struct bnxt *bp ) static int bnxt_open ( struct net_device *dev ) { - struct bnxt *bp = netdev_priv ( dev ); + struct bnxt *bp = dev->priv; DBGP ( "%s\n", __func__ ); bnxt_mm_nic ( bp ); @@ -1952,7 +1952,7 @@ static void bnxt_tx_adjust_pkt ( struct bnxt *bp, struct io_buffer *iob ) static int bnxt_tx ( struct net_device *dev, struct io_buffer *iob ) { - struct bnxt *bp = netdev_priv ( dev ); + struct bnxt *bp = dev->priv; u16 len, entry; dma_addr_t mapping; @@ -2009,7 +2009,7 @@ void bnxt_link_evt ( struct bnxt *bp, struct hwrm_async_event_cmpl *evt ) static void bnxt_service_cq ( struct net_device *dev ) { - struct bnxt *bp = netdev_priv ( dev ); + struct bnxt *bp = dev->priv; struct cmpl_base *cmp; struct tx_cmpl *tx; u16 old_cid = bp->cq.cons_id; @@ -2057,7 +2057,7 @@ static void bnxt_service_cq ( struct net_device *dev ) static void bnxt_service_nq ( struct net_device *dev ) { - struct bnxt *bp = netdev_priv ( dev ); + struct bnxt *bp = dev->priv; struct nq_base *nqp; u16 old_cid = bp->nq.cons_id; int done = SERVICE_NEXT_NQ_BD; @@ -2102,7 +2102,7 @@ static void bnxt_poll ( struct net_device *dev ) static void bnxt_close ( struct net_device *dev ) { - struct bnxt *bp = netdev_priv ( dev ); + struct bnxt *bp = dev->priv; DBGP ( "%s\n", __func__ ); bnxt_down_nic (bp); @@ -2143,7 +2143,7 @@ static int bnxt_init_one ( struct pci_device *pci ) netdev_init ( netdev, &bnxt_netdev_ops ); /* Driver private area for this device */ - bp = netdev_priv ( netdev ); + bp = netdev->priv; /* Set PCI driver private data */ pci_set_drvdata ( pci, netdev ); @@ -2197,7 +2197,7 @@ disable_pdev: static void bnxt_remove_one ( struct pci_device *pci ) { struct net_device *netdev = pci_get_drvdata ( pci ); - struct bnxt *bp = netdev_priv ( netdev ); + struct bnxt *bp = netdev->priv; DBGP ( "%s\n", __func__ ); /* Unregister network device */ diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index 1a802b59..a0551a89 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -690,7 +690,7 @@ static void ifec_reset ( struct net_device *netdev ) */ static void ifec_free ( struct net_device *netdev ) { - struct ifec_private *priv = netdev_priv ( netdev ); + struct ifec_private *priv = netdev->priv; int i; DBGP ( "ifec_free\n" ); diff --git a/src/drivers/net/efi/snpnet.c b/src/drivers/net/efi/snpnet.c index 69ec6f5e..3b09d491 100644 --- a/src/drivers/net/efi/snpnet.c +++ b/src/drivers/net/efi/snpnet.c @@ -97,7 +97,7 @@ static const char * snpnet_mac_text ( EFI_MAC_ADDRESS *mac, size_t len ) { * @v netdev Network device */ static void snpnet_dump_mode ( struct net_device *netdev ) { - struct snp_nic *snp = netdev_priv ( netdev ); + struct snp_nic *snp = netdev->priv; EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode; size_t mac_len = mode->HwAddressSize; unsigned int i; @@ -136,7 +136,7 @@ static void snpnet_dump_mode ( struct net_device *netdev ) { * @v netdev Network device */ static void snpnet_check_link ( struct net_device *netdev ) { - struct snp_nic *snp = netdev_priv ( netdev ); + struct snp_nic *snp = netdev->priv; EFI_SIMPLE_NETWORK_MODE *mode = snp->snp->Mode; /* Do nothing unless media presence detection is supported */ @@ -160,7 +160,7 @@ static void snpnet_check_link ( struct net_device *netdev ) { */ static int snpnet_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct snp_nic *snp = netdev_priv ( netdev ); + struct snp_nic *snp = netdev->priv; EFI_STATUS efirc; int rc; diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index e43d4336..b40596be 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -3725,7 +3725,7 @@ efab_receive ( struct efab_nic *efab, unsigned int id, int len, int drop ) static int efab_transmit ( struct net_device *netdev, struct io_buffer *iob ) { - struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_nic *efab = netdev->priv; struct efab_tx_queue *tx_queue = &efab->tx_queue; int fill_level, space; falcon_tx_desc_t *txd; @@ -3844,7 +3844,7 @@ falcon_handle_event ( struct efab_nic *efab, falcon_event_t *evt ) static void efab_poll ( struct net_device *netdev ) { - struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_nic *efab = netdev->priv; struct efab_ev_queue *ev_queue = &efab->ev_queue; struct efab_rx_queue *rx_queue = &efab->rx_queue; falcon_event_t *evt; @@ -3883,7 +3883,7 @@ efab_poll ( struct net_device *netdev ) static void efab_irq ( struct net_device *netdev, int enable ) { - struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_nic *efab = netdev->priv; struct efab_ev_queue *ev_queue = &efab->ev_queue; switch ( enable ) { @@ -4032,7 +4032,7 @@ efab_init_mac ( struct efab_nic *efab ) static void efab_close ( struct net_device *netdev ) { - struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_nic *efab = netdev->priv; falcon_fini_resources ( efab ); efab_free_resources ( efab ); @@ -4043,7 +4043,7 @@ efab_close ( struct net_device *netdev ) static int efab_open ( struct net_device *netdev ) { - struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_nic *efab = netdev->priv; struct efab_rx_queue *rx_queue = &efab->rx_queue; int rc; @@ -4104,7 +4104,7 @@ static void efab_remove ( struct pci_device *pci ) { struct net_device *netdev = pci_get_drvdata ( pci ); - struct efab_nic *efab = netdev_priv ( netdev ); + struct efab_nic *efab = netdev->priv; if ( efab->membase ) { falcon_reset ( efab ); @@ -4143,7 +4143,7 @@ efab_probe ( struct pci_device *pci ) pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; - efab = netdev_priv ( netdev ); + efab = netdev->priv; memset ( efab, 0, sizeof ( *efab ) ); efab->netdev = netdev; diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c index 7fba08a0..ec3a5bdb 100644 --- a/src/drivers/net/forcedeth.c +++ b/src/drivers/net/forcedeth.c @@ -677,7 +677,7 @@ set_speed: static int forcedeth_open ( struct net_device *netdev ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; void *ioaddr = priv->mmio_addr; int i; int rc; @@ -794,7 +794,7 @@ err_init_rings: static int forcedeth_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; void *ioaddr = priv->mmio_addr; struct ring_desc *tx_curr_desc; u32 size = iob_len ( iobuf ); @@ -853,7 +853,7 @@ forcedeth_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) static void nv_process_tx_packets ( struct net_device *netdev ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; struct ring_desc *tx_curr_desc; u32 flaglen; @@ -899,7 +899,7 @@ nv_process_tx_packets ( struct net_device *netdev ) static void nv_process_rx_packets ( struct net_device *netdev ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; struct io_buffer *curr_iob; struct ring_desc *rx_curr_desc; u32 flags, len; @@ -960,7 +960,7 @@ nv_process_rx_packets ( struct net_device *netdev ) static void forcedeth_link_status ( struct net_device *netdev ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; void *ioaddr = priv->mmio_addr; /* Clear the MII link change status by reading the MIIStatus register */ @@ -981,7 +981,7 @@ forcedeth_link_status ( struct net_device *netdev ) static void forcedeth_poll ( struct net_device *netdev ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; void *ioaddr = priv->mmio_addr; u32 status; @@ -1018,7 +1018,7 @@ forcedeth_poll ( struct net_device *netdev ) static void forcedeth_close ( struct net_device *netdev ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; DBGP ( "forcedeth_close\n" ); @@ -1045,7 +1045,7 @@ forcedeth_close ( struct net_device *netdev ) static void forcedeth_irq ( struct net_device *netdev, int action ) { - struct forcedeth_private *priv = netdev_priv ( netdev ); + struct forcedeth_private *priv = netdev->priv; DBGP ( "forcedeth_irq\n" ); @@ -1814,7 +1814,7 @@ forcedeth_probe ( struct pci_device *pdev ) netdev->dev = &pdev->dev; /* Get a reference to our private data */ - priv = netdev_priv ( netdev ); + priv = netdev->priv; /* We'll need these set up for the rest of the routines */ priv->pci_dev = pdev; diff --git a/src/drivers/net/igbvf/igbvf_main.c b/src/drivers/net/igbvf/igbvf_main.c index a5ed0c45..862ad6a2 100644 --- a/src/drivers/net/igbvf/igbvf_main.c +++ b/src/drivers/net/igbvf/igbvf_main.c @@ -179,7 +179,7 @@ static void igbvf_irq_enable ( struct igbvf_adapter *adapter ) **/ static void igbvf_irq ( struct net_device *netdev, int enable ) { - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; DBG ( "igbvf_irq\n" ); @@ -197,7 +197,7 @@ static void igbvf_irq ( struct net_device *netdev, int enable ) **/ static void igbvf_process_tx_packets ( struct net_device *netdev ) { - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; uint32_t i; uint32_t tx_status; union e1000_adv_tx_desc *tx_curr_desc; @@ -243,7 +243,7 @@ static void igbvf_process_tx_packets ( struct net_device *netdev ) **/ static void igbvf_process_rx_packets ( struct net_device *netdev ) { - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; uint32_t i; uint32_t rx_status; @@ -306,7 +306,7 @@ static void igbvf_process_rx_packets ( struct net_device *netdev ) */ static void igbvf_poll ( struct net_device *netdev ) { - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; uint32_t rx_status; union e1000_adv_rx_desc *rx_curr_desc; @@ -612,7 +612,7 @@ int igbvf_setup_rx_resources ( struct igbvf_adapter *adapter ) **/ static int igbvf_open ( struct net_device *netdev ) { - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; int err; DBG ("igbvf_open\n"); @@ -667,7 +667,7 @@ err_setup_tx: **/ static void igbvf_close ( struct net_device *netdev ) { - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; uint32_t rxdctl; @@ -698,7 +698,7 @@ static void igbvf_close ( struct net_device *netdev ) */ static int igbvf_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; uint32_t tx_curr = adapter->tx_tail; union e1000_adv_tx_desc *tx_curr_desc; @@ -810,7 +810,7 @@ int igbvf_probe ( struct pci_device *pdev ) netdev->dev = &pdev->dev; /* Initialize driver private storage */ - adapter = netdev_priv ( netdev ); + adapter = netdev->priv; memset ( adapter, 0, ( sizeof ( *adapter ) ) ); adapter->pdev = pdev; @@ -924,7 +924,7 @@ err_alloc_etherdev: void igbvf_remove ( struct pci_device *pdev ) { struct net_device *netdev = pci_get_drvdata ( pdev ); - struct igbvf_adapter *adapter = netdev_priv ( netdev ); + struct igbvf_adapter *adapter = netdev->priv; DBG ( "igbvf_remove\n" ); diff --git a/src/drivers/net/jme.c b/src/drivers/net/jme.c index c7307728..298109c2 100644 --- a/src/drivers/net/jme.c +++ b/src/drivers/net/jme.c @@ -1153,7 +1153,7 @@ jme_reload_eeprom(struct jme_adapter *jme) static void jme_load_macaddr(struct net_device *netdev) { - struct jme_adapter *jme = netdev_priv(netdev); + struct jme_adapter *jme = netdev->priv; unsigned char macaddr[6]; u32 val; diff --git a/src/drivers/net/pcnet32.c b/src/drivers/net/pcnet32.c index c0dea86a..7da884e5 100644 --- a/src/drivers/net/pcnet32.c +++ b/src/drivers/net/pcnet32.c @@ -690,7 +690,7 @@ pcnet32_hw_start ( struct pcnet32_private *priv ) static int pcnet32_open ( struct net_device *netdev ) { - struct pcnet32_private *priv = netdev_priv ( netdev ); + struct pcnet32_private *priv = netdev->priv; unsigned long ioaddr = priv->pci_dev->ioaddr; int rc; u16 val; @@ -754,7 +754,7 @@ err_setup_tx: static int pcnet32_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct pcnet32_private *priv = netdev_priv ( netdev ); + struct pcnet32_private *priv = netdev->priv; unsigned long ioaddr = priv->pci_dev->ioaddr; uint32_t tx_len = iob_len ( iobuf ); struct pcnet32_tx_desc *tx_curr_desc; @@ -802,7 +802,7 @@ pcnet32_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) static void pcnet32_process_tx_packets ( struct net_device *netdev ) { - struct pcnet32_private *priv = netdev_priv ( netdev ); + struct pcnet32_private *priv = netdev->priv; struct pcnet32_tx_desc *tx_curr_desc; DBGP ( "pcnet32_process_tx_packets\n" ); @@ -848,7 +848,7 @@ pcnet32_process_tx_packets ( struct net_device *netdev ) static void pcnet32_process_rx_packets ( struct net_device *netdev ) { - struct pcnet32_private *priv = netdev_priv ( netdev ); + struct pcnet32_private *priv = netdev->priv; struct pcnet32_rx_desc *rx_curr_desc; u16 status; u32 len; @@ -913,7 +913,7 @@ pcnet32_process_rx_packets ( struct net_device *netdev ) static void pcnet32_poll ( struct net_device *netdev ) { - struct pcnet32_private *priv = netdev_priv ( netdev ); + struct pcnet32_private *priv = netdev->priv; unsigned long ioaddr = priv->pci_dev->ioaddr; u16 status; @@ -946,7 +946,7 @@ pcnet32_poll ( struct net_device *netdev ) static void pcnet32_close ( struct net_device *netdev ) { - struct pcnet32_private *priv = netdev_priv ( netdev ); + struct pcnet32_private *priv = netdev->priv; unsigned long ioaddr = priv->pci_dev->ioaddr; DBGP ( "pcnet32_close\n" ); @@ -1003,7 +1003,7 @@ static void pcnet32_irq_disable ( struct pcnet32_private *priv ) static void pcnet32_irq ( struct net_device *netdev, int action ) { - struct pcnet32_private *priv = netdev_priv ( netdev ); + struct pcnet32_private *priv = netdev->priv; DBGP ( "pcnet32_irq\n" ); @@ -1061,7 +1061,7 @@ pcnet32_probe ( struct pci_device *pdev ) netdev->dev = &pdev->dev; /* Get a reference to our private data */ - priv = netdev_priv ( netdev ); + priv = netdev->priv; /* We'll need these set up for the rest of the routines */ priv->pci_dev = pdev; diff --git a/src/drivers/net/phantom/phantom.c b/src/drivers/net/phantom/phantom.c index 84345905..e5fd1f31 100644 --- a/src/drivers/net/phantom/phantom.c +++ b/src/drivers/net/phantom/phantom.c @@ -1062,7 +1062,7 @@ static inline int phantom_del_macaddr ( struct phantom_nic *phantom, * @v netdev Network device */ static void phantom_poll_link_state ( struct net_device *netdev ) { - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; uint32_t xg_state_p3; unsigned int link; @@ -1109,7 +1109,7 @@ static void phantom_poll_link_state ( struct net_device *netdev ) { * @v netdev Net device */ static void phantom_refill_rx_ring ( struct net_device *netdev ) { - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; struct io_buffer *iobuf; struct phantom_rds rds; unsigned int handle; @@ -1160,7 +1160,7 @@ static void phantom_refill_rx_ring ( struct net_device *netdev ) { * @ret rc Return status code */ static int phantom_open ( struct net_device *netdev ) { - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; int rc; /* Allocate and zero descriptor rings */ @@ -1220,7 +1220,7 @@ static int phantom_open ( struct net_device *netdev ) { * @v netdev Net device */ static void phantom_close ( struct net_device *netdev ) { - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; struct io_buffer *iobuf; unsigned int i; @@ -1258,7 +1258,7 @@ static void phantom_close ( struct net_device *netdev ) { */ static int phantom_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; union phantom_cds cds; int index; @@ -1297,7 +1297,7 @@ static int phantom_transmit ( struct net_device *netdev, * @v netdev Network device */ static void phantom_poll ( struct net_device *netdev ) { - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; struct io_buffer *iobuf; unsigned int irq_vector; unsigned int irq_state; @@ -1434,7 +1434,7 @@ static void phantom_poll ( struct net_device *netdev ) { * @v enable Interrupts should be enabled */ static void phantom_irq ( struct net_device *netdev, int enable ) { - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; phantom_writel ( phantom, ( enable ? 1 : 0 ), phantom->sds_irq_mask_crb ); @@ -2070,7 +2070,7 @@ static int phantom_probe ( struct pci_device *pci ) { goto err_alloc_etherdev; } netdev_init ( netdev, &phantom_operations ); - phantom = netdev_priv ( netdev ); + phantom = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( phantom, 0, sizeof ( *phantom ) ); @@ -2161,7 +2161,7 @@ static int phantom_probe ( struct pci_device *pci ) { */ static void phantom_remove ( struct pci_device *pci ) { struct net_device *netdev = pci_get_drvdata ( pci ); - struct phantom_nic *phantom = netdev_priv ( netdev ); + struct phantom_nic *phantom = netdev->priv; unregister_settings ( &phantom->settings ); unregister_netdev ( netdev ); diff --git a/src/drivers/net/sfc/efx_common.c b/src/drivers/net/sfc/efx_common.c index ad572b1d..2b7a88a5 100644 --- a/src/drivers/net/sfc/efx_common.c +++ b/src/drivers/net/sfc/efx_common.c @@ -70,7 +70,7 @@ efx_readl(struct efx_nic *efx, efx_dword_t *value, unsigned int reg) ******************************************************************************/ void efx_probe(struct net_device *netdev, enum efx_revision revision) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; struct pci_device *pci = container_of(netdev->dev, struct pci_device, dev); unsigned int reg = PCI_BASE_ADDRESS_0; @@ -97,7 +97,7 @@ void efx_probe(struct net_device *netdev, enum efx_revision revision) void efx_remove(struct net_device *netdev) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; iounmap(efx->membase); efx->membase = NULL; diff --git a/src/drivers/net/sfc/efx_hunt.c b/src/drivers/net/sfc/efx_hunt.c index 0bce3e45..abe3e832 100644 --- a/src/drivers/net/sfc/efx_hunt.c +++ b/src/drivers/net/sfc/efx_hunt.c @@ -100,7 +100,7 @@ efx_hunt_notify_tx_desc(struct efx_nic *efx) int efx_hunt_transmit(struct net_device *netdev, struct io_buffer *iob) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; struct efx_tx_queue *txq = &efx->txq; int fill_level, space; efx_tx_desc_t *txd; @@ -155,7 +155,7 @@ efx_hunt_transmit_done(struct efx_nic *efx, int id) int efx_hunt_tx_init(struct net_device *netdev, dma_addr_t *dma_addr) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; struct efx_tx_queue *txq = &efx->txq; size_t bytes; @@ -270,7 +270,7 @@ efx_hunt_receive(struct efx_nic *efx, unsigned int id, int len, int drop) int efx_hunt_rx_init(struct net_device *netdev, dma_addr_t *dma_addr) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; struct efx_rx_queue *rxq = &efx->rxq; size_t bytes; @@ -294,7 +294,7 @@ int efx_hunt_rx_init(struct net_device *netdev, dma_addr_t *dma_addr) ******************************************************************************/ int efx_hunt_ev_init(struct net_device *netdev, dma_addr_t *dma_addr) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; struct efx_ev_queue *evq = &efx->evq; size_t bytes; @@ -404,7 +404,7 @@ efx_hunt_handle_event(struct efx_nic *efx, efx_event_t *evt) void efx_hunt_poll(struct net_device *netdev) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; struct efx_ev_queue *evq = &efx->evq; efx_event_t *evt; int budget = 10; @@ -443,7 +443,7 @@ void efx_hunt_poll(struct net_device *netdev) void efx_hunt_irq(struct net_device *netdev, int enable) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; efx->int_en = enable; @@ -465,7 +465,7 @@ void efx_hunt_irq(struct net_device *netdev, int enable) ******************************************************************************/ int efx_hunt_open(struct net_device *netdev) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; efx_dword_t cmd; /* Set interrupt moderation to 0*/ @@ -486,7 +486,7 @@ int efx_hunt_open(struct net_device *netdev) void efx_hunt_close(struct net_device *netdev) { - struct efx_nic *efx = netdev_priv(netdev); + struct efx_nic *efx = netdev->priv; struct efx_rx_queue *rxq = &efx->rxq; struct efx_tx_queue *txq = &efx->txq; int i; diff --git a/src/drivers/net/sfc/sfc_hunt.c b/src/drivers/net/sfc/sfc_hunt.c index a37670ae..43ac229a 100644 --- a/src/drivers/net/sfc/sfc_hunt.c +++ b/src/drivers/net/sfc/sfc_hunt.c @@ -1043,7 +1043,7 @@ static void hunt_ev_fini(struct hunt_nic *hunt) static void hunt_poll(struct net_device *netdev) { - struct hunt_nic *hunt = netdev_priv(netdev); + struct hunt_nic *hunt = netdev->priv; /* If called while already polling, return immediately */ if (hunt->efx.state & EFX_STATE_POLLING) @@ -1071,7 +1071,7 @@ hunt_poll(struct net_device *netdev) ******************************************************************************/ static int hunt_open(struct net_device *netdev) { - struct hunt_nic *hunt = netdev_priv(netdev); + struct hunt_nic *hunt = netdev->priv; int rc; /* Allocate VIs */ @@ -1133,7 +1133,7 @@ fail2: static void hunt_close(struct net_device *netdev) { - struct hunt_nic *hunt = netdev_priv(netdev); + struct hunt_nic *hunt = netdev->priv; /* Stop datapath */ efx_hunt_close(netdev); @@ -1187,7 +1187,7 @@ hunt_probe(struct pci_device *pci) netdev->dev = &pci->dev; netdev->state |= NETDEV_IRQ_UNSUPPORTED; - hunt = netdev_priv(netdev); + hunt = netdev->priv; memset(hunt, 0, sizeof(*hunt)); efx = &hunt->efx; @@ -1290,7 +1290,7 @@ fail1: static void hunt_remove(struct pci_device *pci) { struct net_device *netdev = pci_get_drvdata(pci); - struct hunt_nic *hunt = netdev_priv(netdev); + struct hunt_nic *hunt = netdev->priv; if (!(hunt->flags & (1 << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_NO_ACTIVE_PORT))) { diff --git a/src/drivers/net/sis190.c b/src/drivers/net/sis190.c index 0e4f0762..034cac9e 100644 --- a/src/drivers/net/sis190.c +++ b/src/drivers/net/sis190.c @@ -107,14 +107,14 @@ static int mdio_read(void *ioaddr, int phy_id, int reg) static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; mdio_write(tp->mmio_addr, phy_id, reg, val); } static int __mdio_read(struct net_device *dev, int phy_id, int reg) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; return mdio_read(tp->mmio_addr, phy_id, reg); } @@ -343,7 +343,7 @@ static void sis190_process_tx(struct sis190_private *tp) */ static void sis190_poll(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 status; @@ -374,7 +374,7 @@ static inline void sis190_init_ring_indexes(struct sis190_private *tp) static int sis190_init_ring(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; sis190_init_ring_indexes(tp); @@ -395,7 +395,7 @@ err: static void sis190_set_rx_mode(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 mc_filter[2]; /* Multicast hash filter */ u16 rx_mode; @@ -419,7 +419,7 @@ static void sis190_soft_reset(void *ioaddr) static void sis190_hw_start(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; sis190_soft_reset(ioaddr); @@ -548,7 +548,7 @@ static void sis190_phy_task(struct sis190_private *tp) static int sis190_open(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; int rc; /* Allocate TX ring */ @@ -587,7 +587,7 @@ error: static void sis190_down(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; do { @@ -597,7 +597,7 @@ static void sis190_down(struct net_device *dev) static void sis190_free(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; int i; free_phys(tp->TxDescRing, TX_RING_BYTES); @@ -630,7 +630,7 @@ static void sis190_close(struct net_device *dev) static int sis190_transmit(struct net_device *dev, struct io_buffer *iob) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u32 len, entry; struct TxDesc *desc; @@ -804,7 +804,7 @@ static void sis190_mii_probe_88e1111_fixup(struct sis190_private *tp) */ static int sis190_mii_probe(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; struct mii_if_info *mii_if = &tp->mii_if; void *ioaddr = tp->mmio_addr; int phy_id; @@ -858,7 +858,7 @@ out: static void sis190_mii_remove(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; sis190_free_phy(&tp->first_phy); } @@ -879,7 +879,7 @@ static int sis190_init_board(struct pci_device *pdev, struct net_device **netdev dev->dev = &pdev->dev; - tp = netdev_priv(dev); + tp = dev->priv; memset(tp, 0, sizeof(*tp)); tp->dev = dev; @@ -916,7 +916,7 @@ static void sis190_set_rgmii(struct sis190_private *tp, u8 reg) static int sis190_get_mac_addr_from_eeprom(struct pci_device *pdev __unused, struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u16 sig; int i; @@ -955,7 +955,7 @@ static int sis190_get_mac_addr_from_eeprom(struct pci_device *pdev __unused, static int sis190_get_mac_addr_from_apc(struct pci_device *pdev, struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; struct pci_device *isa_bridge = NULL; struct device *d; u8 reg, tmp8; @@ -1018,7 +1018,7 @@ static int sis190_get_mac_addr_from_apc(struct pci_device *pdev, */ static inline void sis190_init_rxfilter(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; u16 ctl; int i; @@ -1057,7 +1057,7 @@ static int sis190_get_mac_addr(struct pci_device *pdev, static void sis190_set_speed_auto(struct net_device *dev) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; int phy_id = tp->mii_if.phy_id; int val; @@ -1082,7 +1082,7 @@ static void sis190_set_speed_auto(struct net_device *dev) static void sis190_irq(struct net_device *dev, int enable) { - struct sis190_private *tp = netdev_priv(dev); + struct sis190_private *tp = dev->priv; void *ioaddr = tp->mmio_addr; SIS_W32(IntrStatus, 0xffffffff); @@ -1116,7 +1116,7 @@ static int sis190_probe(struct pci_device *pdev) pci_set_drvdata(pdev, dev); - tp = netdev_priv(dev); + tp = dev->priv; rc = sis190_get_mac_addr(pdev, dev); if (rc < 0) diff --git a/src/drivers/net/skge.c b/src/drivers/net/skge.c index 5aa5e2a6..cc7f0b91 100755 --- a/src/drivers/net/skge.c +++ b/src/drivers/net/skge.c @@ -213,7 +213,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) * * static int skge_get_eeprom_len(struct net_device *dev) * { - * struct skge_port *skge = netdev_priv(dev); + * struct skge_port *skge = dev->priv; * u32 reg2; * * pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, ®2); @@ -248,7 +248,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) * static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, * u8 *data) * { - * struct skge_port *skge = netdev_priv(dev); + * struct skge_port *skge = dev->priv; * struct pci_dev *pdev = skge->hw->pdev; * int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); * int length = eeprom->len; @@ -274,7 +274,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) * static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, * u8 *data) * { - * struct skge_port *skge = netdev_priv(dev); + * struct skge_port *skge = dev->priv; * struct pci_dev *pdev = skge->hw->pdev; * int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); * int length = eeprom->len; @@ -415,7 +415,7 @@ static void skge_link_down(struct skge_port *skge) static void xm_link_down(struct skge_hw *hw, int port) { struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); @@ -553,7 +553,7 @@ static const u16 fiber_pause_map[] = { static void bcom_check_link(struct skge_hw *hw, int port) { struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; u16 status; /* read twice because of latch */ @@ -751,7 +751,7 @@ static void xm_phy_init(struct skge_port *skge) static int xm_check_link(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_hw *hw = skge->hw; int port = skge->port; u16 status; @@ -852,7 +852,7 @@ static void xm_link_timer(struct skge_port *skge) static void genesis_mac_init(struct skge_hw *hw, int port) { struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; int i; u32 r; const u8 zero[6] = { 0 }; @@ -1209,7 +1209,7 @@ static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg) /* Marvell Phy Initialization */ static void yukon_init(struct skge_hw *hw, int port) { - struct skge_port *skge = netdev_priv(hw->dev[port]); + struct skge_port *skge = hw->dev[port]->priv; u16 ctrl, ct1000, adv; if (skge->autoneg == AUTONEG_ENABLE) { @@ -1325,7 +1325,7 @@ static int is_yukon_lite_a0(struct skge_hw *hw) static void yukon_mac_init(struct skge_hw *hw, int port) { - struct skge_port *skge = netdev_priv(hw->dev[port]); + struct skge_port *skge = hw->dev[port]->priv; int i; u32 reg; const u8 *addr = hw->dev[port]->ll_addr; @@ -1691,7 +1691,7 @@ static void skge_qset(struct skge_port *skge, u16 q, void skge_free(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; free(skge->rx_ring.start); skge->rx_ring.start = NULL; @@ -1706,7 +1706,7 @@ void skge_free(struct net_device *dev) static int skge_up(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_hw *hw = skge->hw; int port = skge->port; u32 chunk, ram_addr; @@ -1789,7 +1789,7 @@ static void skge_rx_stop(struct skge_hw *hw, int port) static void skge_down(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_hw *hw = skge->hw; int port = skge->port; @@ -1862,7 +1862,7 @@ static inline int skge_tx_avail(const struct skge_ring *ring) static int skge_xmit_frame(struct net_device *dev, struct io_buffer *iob) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_hw *hw = skge->hw; struct skge_element *e; struct skge_tx_desc *td; @@ -1908,7 +1908,7 @@ static int skge_xmit_frame(struct net_device *dev, struct io_buffer *iob) /* Free all buffers in transmit ring */ static void skge_tx_clean(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_element *e; for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) { @@ -1939,7 +1939,7 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status) /* Free all buffers in Tx ring which are no longer owned by device */ static void skge_tx_done(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_ring *ring = &skge->tx_ring; struct skge_element *e; @@ -1961,7 +1961,7 @@ static void skge_tx_done(struct net_device *dev) static void skge_rx_refill(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; struct io_buffer *iob; @@ -2003,7 +2003,7 @@ static void skge_rx_refill(struct net_device *dev) static void skge_rx_done(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_ring *ring = &skge->rx_ring; struct skge_rx_desc *rd; struct skge_element *e; @@ -2050,7 +2050,7 @@ static void skge_rx_done(struct net_device *dev) static void skge_poll(struct net_device *dev) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_hw *hw = skge->hw; u32 status; @@ -2085,7 +2085,7 @@ static void skge_phyirq(struct skge_hw *hw) for (port = 0; port < hw->ports; port++) { struct net_device *dev = hw->dev[port]; - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; if (hw->chip_id != CHIP_ID_GENESIS) yukon_phy_intr(skge); @@ -2302,7 +2302,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, dev->dev = &hw->pdev->dev; - skge = netdev_priv(dev); + skge = dev->priv; skge->netdev = dev; skge->hw = hw; @@ -2446,7 +2446,7 @@ static void skge_remove(struct pci_device *pdev) * This is a iPXE Network Driver API function. */ static void skge_net_irq ( struct net_device *dev, int enable ) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = dev->priv; struct skge_hw *hw = skge->hw; if (enable) diff --git a/src/drivers/net/sky2.c b/src/drivers/net/sky2.c index 9d612c99..26396585 100644 --- a/src/drivers/net/sky2.c +++ b/src/drivers/net/sky2.c @@ -296,7 +296,7 @@ static const u16 gm_fc_disable[] = { static void sky2_phy_init(struct sky2_hw *hw, unsigned port) { - struct sky2_port *sky2 = netdev_priv(hw->dev[port]); + struct sky2_port *sky2 = hw->dev[port]->priv; u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; if (sky2->autoneg == AUTONEG_ENABLE && @@ -1128,7 +1128,7 @@ static void sky2_free_rings(struct sky2_port *sky2) /* Bring up network interface. */ static int sky2_up(struct net_device *dev) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u32 imask, ramsize; @@ -1237,7 +1237,7 @@ static inline int tx_avail(const struct sky2_port *sky2) */ static int sky2_xmit_frame(struct net_device *dev, struct io_buffer *iob) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; struct sky2_hw *hw = sky2->hw; struct sky2_tx_le *le = NULL; struct tx_ring_info *re; @@ -1303,7 +1303,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) /* Cleanup all untransmitted buffers, assume transmitter not running */ static void sky2_tx_clean(struct net_device *dev) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; sky2_tx_complete(sky2, sky2->tx_prod); } @@ -1311,7 +1311,7 @@ static void sky2_tx_clean(struct net_device *dev) /* Network shutdown */ static void sky2_down(struct net_device *dev) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u16 ctrl; @@ -1511,7 +1511,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) { struct net_device *dev = hw->dev[port]; - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; u16 istatus, phystat; istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); @@ -1570,7 +1570,7 @@ static struct io_buffer *receive_new(struct sky2_port *sky2, static struct io_buffer *sky2_receive(struct net_device *dev, u16 length, u32 status) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next; struct io_buffer *iob = NULL; u16 count = (status & GMR_FS_LEN) >> 16; @@ -1634,7 +1634,7 @@ error: /* Transmit complete */ static inline void sky2_tx_done(struct net_device *dev, u16 last) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; sky2_tx_complete(sky2, last); } @@ -1700,10 +1700,10 @@ static void sky2_status_intr(struct sky2_hw *hw, u16 idx) sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); if (rx[0]) - sky2_rx_update(netdev_priv(hw->dev[0]), Q_R1); + sky2_rx_update(hw->dev[0]->priv, Q_R1); if (rx[1]) - sky2_rx_update(netdev_priv(hw->dev[1]), Q_R2); + sky2_rx_update(hw->dev[1]->priv, Q_R2); } static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status) @@ -1809,7 +1809,7 @@ static void sky2_le_error(struct sky2_hw *hw, unsigned port, u16 q, unsigned ring_size __unused) { struct net_device *dev = hw->dev[port]; - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; int idx; const u64 *le = (q == Q_R1 || q == Q_R2) ? (u64 *) sky2->rx_le : (u64 *) sky2->tx_le; @@ -1853,7 +1853,7 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 status) static void sky2_poll(struct net_device *dev) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; struct sky2_hw *hw = sky2->hw; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); u16 idx; @@ -2152,7 +2152,7 @@ static u32 sky2_supported_modes(const struct sky2_hw *hw) static void sky2_set_multicast(struct net_device *dev) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u16 reg; @@ -2189,7 +2189,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, dev->dev = &hw->pdev->dev; - sky2 = netdev_priv(dev); + sky2 = dev->priv; sky2->netdev = dev; sky2->hw = hw; @@ -2241,7 +2241,7 @@ static const char *sky2_name(u8 chipid, char *buf, int sz) static void sky2_net_irq(struct net_device *dev, int enable) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = dev->priv; struct sky2_hw *hw = sky2->hw; u32 imask = sky2_read32(hw, B0_IMSK); diff --git a/src/drivers/net/tg3/tg3.c b/src/drivers/net/tg3/tg3.c index cec599c1..559c2d63 100644 --- a/src/drivers/net/tg3/tg3.c +++ b/src/drivers/net/tg3/tg3.c @@ -233,7 +233,7 @@ int tg3_init_rings(struct tg3 *tp) static int tg3_open(struct net_device *dev) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; struct tg3_rx_prodring_set *tpr = &tp->prodring; int err = 0; @@ -299,7 +299,7 @@ static void __unused tw32_mailbox2(struct tg3 *tp, uint32_t reg, uint32_t val) static int tg3_transmit(struct net_device *dev, struct io_buffer *iob) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; u32 len, entry; dma_addr_t mapping; @@ -333,7 +333,7 @@ static int tg3_transmit(struct net_device *dev, struct io_buffer *iob) static void tg3_tx_complete(struct net_device *dev) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; u32 hw_idx = tp->hw_status->idx[0].tx_consumer; u32 sw_idx = tp->tx_cons; @@ -427,7 +427,7 @@ static void tg3_refill_prod_ring(struct tg3 *tp) static void tg3_rx_complete(struct net_device *dev) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; u32 sw_idx = tp->rx_rcb_ptr; u16 hw_idx; @@ -478,7 +478,7 @@ static void tg3_rx_complete(struct net_device *dev) static void tg3_poll(struct net_device *dev) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; /* ACK interrupts */ /* @@ -496,7 +496,7 @@ static void tg3_poll(struct net_device *dev) static void tg3_close(struct net_device *dev) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; DBGP("%s\n", __func__); @@ -511,7 +511,7 @@ static void tg3_close(struct net_device *dev) static void tg3_irq(struct net_device *dev, int enable) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; DBGP("%s: %d\n", __func__, enable); @@ -735,7 +735,7 @@ static int tg3_init_one(struct pci_device *pdev) dev->dev = &pdev->dev; - tp = netdev_priv(dev); + tp = dev->priv; tp->pdev = pdev; tp->dev = dev; tp->rx_mode = TG3_DEF_RX_MODE; diff --git a/src/drivers/net/tg3/tg3_hw.c b/src/drivers/net/tg3/tg3_hw.c index 798f8519..9a70413b 100644 --- a/src/drivers/net/tg3/tg3_hw.c +++ b/src/drivers/net/tg3/tg3_hw.c @@ -1717,7 +1717,7 @@ int tg3_get_device_address(struct tg3 *tp) static void __tg3_set_rx_mode(struct net_device *dev) { DBGP("%s\n", __func__); - struct tg3 *tp = netdev_priv(dev); + struct tg3 *tp = dev->priv; u32 rx_mode; rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC | diff --git a/src/drivers/net/vmxnet3.c b/src/drivers/net/vmxnet3.c index 63bcf0e0..3800d6b7 100644 --- a/src/drivers/net/vmxnet3.c +++ b/src/drivers/net/vmxnet3.c @@ -90,7 +90,7 @@ static inline uint32_t vmxnet3_command ( struct vmxnet3_nic *vmxnet, */ static int vmxnet3_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; struct vmxnet3_tx_desc *tx_desc; unsigned int fill; unsigned int desc_idx; @@ -139,7 +139,7 @@ static int vmxnet3_transmit ( struct net_device *netdev, * @v netdev Network device */ static void vmxnet3_poll_tx ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; struct vmxnet3_tx_comp *tx_comp; struct io_buffer *iobuf; unsigned int comp_idx; @@ -188,7 +188,7 @@ static void vmxnet3_poll_tx ( struct net_device *netdev ) { * @v netdev Network device */ static void vmxnet3_flush_tx ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; unsigned int i; for ( i = 0 ; i < VMXNET3_NUM_TX_DESC ; i++ ) { @@ -206,7 +206,7 @@ static void vmxnet3_flush_tx ( struct net_device *netdev ) { * @v netdev Network device */ static void vmxnet3_refill_rx ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; struct vmxnet3_rx_desc *rx_desc; struct io_buffer *iobuf; unsigned int orig_rx_prod = vmxnet->count.rx_prod; @@ -261,7 +261,7 @@ static void vmxnet3_refill_rx ( struct net_device *netdev ) { * @v netdev Network device */ static void vmxnet3_poll_rx ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; struct vmxnet3_rx_comp *rx_comp; struct io_buffer *iobuf; unsigned int comp_idx; @@ -315,7 +315,7 @@ static void vmxnet3_poll_rx ( struct net_device *netdev ) { * @v netdev Network device */ static void vmxnet3_flush_rx ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; struct io_buffer *iobuf; unsigned int i; @@ -333,7 +333,7 @@ static void vmxnet3_flush_rx ( struct net_device *netdev ) { * @v netdev Network device */ static void vmxnet3_check_link ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; uint32_t state; int link_up; unsigned int link_speed; @@ -360,7 +360,7 @@ static void vmxnet3_check_link ( struct net_device *netdev ) { * @v netdev Network device */ static void vmxnet3_poll_events ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; uint32_t events; /* Do nothing unless there are events to process */ @@ -424,7 +424,7 @@ static void vmxnet3_poll ( struct net_device *netdev ) { * @v enable Interrupts should be enabled */ static void vmxnet3_irq ( struct net_device *netdev, int enable ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; DBGC ( vmxnet, "VMXNET3 %p %s IRQ not implemented\n", vmxnet, ( enable ? "enable" : "disable" ) ); @@ -456,7 +456,7 @@ static void vmxnet3_set_ll_addr ( struct vmxnet3_nic *vmxnet, * @ret rc Return status code */ static int vmxnet3_open ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; struct vmxnet3_shared *shared; struct vmxnet3_queues *queues; uint64_t shared_bus; @@ -554,7 +554,7 @@ static int vmxnet3_open ( struct net_device *netdev ) { * @v netdev Network device */ static void vmxnet3_close ( struct net_device *netdev ) { - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; vmxnet3_command ( vmxnet, VMXNET3_CMD_QUIESCE_DEV ); vmxnet3_command ( vmxnet, VMXNET3_CMD_RESET_DEV ); @@ -633,7 +633,7 @@ static int vmxnet3_probe ( struct pci_device *pci ) { goto err_alloc_etherdev; } netdev_init ( netdev, &vmxnet3_operations ); - vmxnet = netdev_priv ( netdev ); + vmxnet = netdev->priv; pci_set_drvdata ( pci, netdev ); netdev->dev = &pci->dev; memset ( vmxnet, 0, sizeof ( *vmxnet ) ); @@ -699,7 +699,7 @@ static int vmxnet3_probe ( struct pci_device *pci ) { */ static void vmxnet3_remove ( struct pci_device *pci ) { struct net_device *netdev = pci_get_drvdata ( pci ); - struct vmxnet3_nic *vmxnet = netdev_priv ( netdev ); + struct vmxnet3_nic *vmxnet = netdev->priv; unregister_netdev ( netdev ); iounmap ( vmxnet->vd ); diff --git a/src/drivers/net/vxge/vxge_main.c b/src/drivers/net/vxge/vxge_main.c index 63192831..e323701f 100644 --- a/src/drivers/net/vxge/vxge_main.c +++ b/src/drivers/net/vxge/vxge_main.c @@ -186,7 +186,7 @@ vxge_xmit(struct net_device *dev, struct io_buffer *iobuf) vxge_trace(); - vdev = (struct vxgedev *)netdev_priv(dev); + vdev = (struct vxgedev *)dev->priv; if (!is_vxge_card_up(vdev)) { vxge_debug(VXGE_ERR, @@ -235,7 +235,7 @@ static void vxge_poll(struct net_device *ndev) vxge_debug(VXGE_POLL, "%s:%d \n", __func__, __LINE__); - vdev = (struct vxgedev *)netdev_priv(ndev); + vdev = (struct vxgedev *)ndev->priv; hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); if (!is_vxge_card_up(vdev)) @@ -263,7 +263,7 @@ static void vxge_irq(struct net_device *netdev __unused, int action) vxge_debug(VXGE_INFO, "%s:%d action(%d)\n", __func__, __LINE__, action); - vdev = (struct vxgedev *)netdev_priv(netdev); + vdev = (struct vxgedev *)netdev->priv; hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); switch (action) { @@ -297,7 +297,7 @@ vxge_open(struct net_device *dev) vxge_debug(VXGE_INFO, "%s: %s:%d\n", VXGE_DRIVER_NAME, __func__, __LINE__); - vdev = (struct vxgedev *)netdev_priv(dev); + vdev = (struct vxgedev *)dev->priv; hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); /* make sure you have link off by default every time Nic is @@ -369,7 +369,7 @@ static void vxge_close(struct net_device *dev) vxge_debug(VXGE_INFO, "%s: %s:%d\n", dev->name, __func__, __LINE__); - vdev = (struct vxgedev *)netdev_priv(dev); + vdev = (struct vxgedev *)dev->priv; hldev = (struct __vxge_hw_device *)pci_get_drvdata(vdev->pdev); if (!is_vxge_card_up(vdev)) @@ -420,7 +420,7 @@ int vxge_device_register(struct __vxge_hw_device *hldev, vxge_debug(VXGE_INFO, "%s:%d netdev registering\n", __func__, __LINE__); - vdev = netdev_priv(ndev); + vdev = ndev->priv; memset(vdev, 0, sizeof(struct vxgedev)); vdev->ndev = ndev; @@ -683,7 +683,7 @@ vxge_remove(struct pci_device *pdev) return; ndev = hldev->ndev; - vdev = netdev_priv(ndev); + vdev = ndev->priv; iounmap(vdev->bar0); diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index af932c25..a65dbfd2 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -568,17 +568,6 @@ netdev_put ( struct net_device *netdev ) { ref_put ( &netdev->refcnt ); } -/** - * Get driver private area for this network device - * - * @v netdev Network device - * @ret priv Driver private area for this network device - */ -static inline __attribute__ (( always_inline )) void * -netdev_priv ( struct net_device *netdev ) { - return netdev->priv; -} - /** * Get per-netdevice configuration settings block * -- cgit v1.2.3-55-g7522 From ae4e85bde97c9b216736a5087039f3309a628d24 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Sep 2023 16:29:59 +0100 Subject: [netdevice] Allocate private data for each network upper-layer driver Allow network upper-layer drivers (such as LLDP, which attaches to each network device in order to provide a corresponding LLDP settings block) to specify a size for private data, which will be allocated as part of the network device structure (as with the existing private data allocated for the underlying device driver). This will allow network upper-layer drivers to be simplified by omitting memory allocation and freeing code. If the upper-layer driver requires a reference counter (e.g. for interface initialisation), then it may use the network device's existing reference counter, since this is now the reference counter for the containing block of memory. Signed-off-by: Michael Brown --- src/arch/x86/interface/pxe/pxe_call.c | 3 +- src/arch/x86/interface/vmware/guestinfo.c | 8 +++- src/core/cachedhcp.c | 3 +- src/drivers/net/netfront.c | 4 +- src/include/ipxe/netdevice.h | 13 ++++-- src/interface/efi/efi_snp.c | 9 ++-- src/net/fcoe.c | 9 ++-- src/net/infiniband/xsigo.c | 4 +- src/net/ipv6.c | 4 +- src/net/lldp.c | 3 +- src/net/neighbour.c | 3 +- src/net/netdevice.c | 72 +++++++++++++++++++++++++------ src/net/vlan.c | 9 ++-- 13 files changed, 110 insertions(+), 34 deletions(-) diff --git a/src/arch/x86/interface/pxe/pxe_call.c b/src/arch/x86/interface/pxe/pxe_call.c index 67118299..0e8d5c5a 100644 --- a/src/arch/x86/interface/pxe/pxe_call.c +++ b/src/arch/x86/interface/pxe/pxe_call.c @@ -375,9 +375,10 @@ int pxe_start_nbp ( void ) { * Notify BIOS of existence of network device * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int pxe_notify ( struct net_device *netdev ) { +static int pxe_notify ( struct net_device *netdev, void *priv __unused ) { /* Do nothing if we already have a network device */ if ( pxe_netdev ) diff --git a/src/arch/x86/interface/vmware/guestinfo.c b/src/arch/x86/interface/vmware/guestinfo.c index a0530c8d..b52c2e87 100644 --- a/src/arch/x86/interface/vmware/guestinfo.c +++ b/src/arch/x86/interface/vmware/guestinfo.c @@ -207,9 +207,11 @@ struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = { * Create per-netdevice GuestInfo settings * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int guestinfo_net_probe ( struct net_device *netdev ) { +static int guestinfo_net_probe ( struct net_device *netdev, + void *priv __unused ) { struct settings *settings; int rc; @@ -247,8 +249,10 @@ static int guestinfo_net_probe ( struct net_device *netdev ) { * Remove per-netdevice GuestInfo settings * * @v netdev Network device + * @v priv Private data */ -static void guestinfo_net_remove ( struct net_device *netdev ) { +static void guestinfo_net_remove ( struct net_device *netdev, + void *priv __unused ) { struct settings *parent = netdev_settings ( netdev ); struct settings *settings; diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c index 60213f02..57226e16 100644 --- a/src/core/cachedhcp.c +++ b/src/core/cachedhcp.c @@ -295,9 +295,10 @@ struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = { * Apply cached DHCPACK to network device, if applicable * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int cachedhcp_probe ( struct net_device *netdev ) { +static int cachedhcp_probe ( struct net_device *netdev, void *priv __unused ) { /* Apply cached DHCPACK to network device, if applicable */ return cachedhcp_apply ( &cached_dhcpack, netdev ); diff --git a/src/drivers/net/netfront.c b/src/drivers/net/netfront.c index 90930a5a..12713c5b 100644 --- a/src/drivers/net/netfront.c +++ b/src/drivers/net/netfront.c @@ -1056,9 +1056,11 @@ struct xen_driver netfront_driver __xen_driver = { * Inhibit emulated PCI devices * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int netfront_net_probe ( struct net_device *netdev ) { +static int netfront_net_probe ( struct net_device *netdev, + void *priv __unused ) { struct netfront_nic *netfront; /* Inhibit emulated PCI devices matching an existing netfront device */ diff --git a/src/include/ipxe/netdevice.h b/src/include/ipxe/netdevice.h index a65dbfd2..caa83b44 100644 --- a/src/include/ipxe/netdevice.h +++ b/src/include/ipxe/netdevice.h @@ -473,22 +473,27 @@ struct net_device { struct net_driver { /** Name */ const char *name; + /** Size of private data */ + size_t priv_len; /** Probe device * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ - int ( * probe ) ( struct net_device *netdev ); + int ( * probe ) ( struct net_device *netdev, void *priv ); /** Notify of device or link state change * * @v netdev Network device + * @v priv Private data */ - void ( * notify ) ( struct net_device *netdev ); + void ( * notify ) ( struct net_device *netdev, void *priv ); /** Remove device * * @v netdev Network device + * @v priv Private data */ - void ( * remove ) ( struct net_device *netdev ); + void ( * remove ) ( struct net_device *netdev, void *priv ); }; /** Network driver table */ @@ -688,6 +693,8 @@ netdev_rx_frozen ( struct net_device *netdev ) { return ( netdev->state & NETDEV_RX_FROZEN ); } +extern void * netdev_priv ( struct net_device *netdev, + struct net_driver *driver ); extern void netdev_rx_freeze ( struct net_device *netdev ); extern void netdev_rx_unfreeze ( struct net_device *netdev ); extern void netdev_link_err ( struct net_device *netdev, int rc ); diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index c4f7d4ea..8443be99 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -1777,9 +1777,10 @@ static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) { * Create SNP device * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int efi_snp_probe ( struct net_device *netdev ) { +static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_device *efidev; struct efi_snp_device *snpdev; @@ -2017,8 +2018,9 @@ static int efi_snp_probe ( struct net_device *netdev ) { * Handle SNP device or link state change * * @v netdev Network device + * @v priv Private data */ -static void efi_snp_notify ( struct net_device *netdev ) { +static void efi_snp_notify ( struct net_device *netdev, void *priv __unused ) { struct efi_snp_device *snpdev; /* Locate SNP device */ @@ -2042,8 +2044,9 @@ static void efi_snp_notify ( struct net_device *netdev ) { * Destroy SNP device * * @v netdev Network device + * @v priv Private data */ -static void efi_snp_remove ( struct net_device *netdev ) { +static void efi_snp_remove ( struct net_device *netdev, void *priv __unused ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; struct efi_snp_device *snpdev; int leak = efi_shutdown_in_progress; diff --git a/src/net/fcoe.c b/src/net/fcoe.c index f910eeea..70804dd0 100644 --- a/src/net/fcoe.c +++ b/src/net/fcoe.c @@ -1110,9 +1110,10 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) { * Create FCoE port * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int fcoe_probe ( struct net_device *netdev ) { +static int fcoe_probe ( struct net_device *netdev, void *priv __unused ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; struct fcoe_port *fcoe; int rc; @@ -1162,8 +1163,9 @@ static int fcoe_probe ( struct net_device *netdev ) { * Handle FCoE port device or link state change * * @v netdev Network device + * @v priv Private data */ -static void fcoe_notify ( struct net_device *netdev ) { +static void fcoe_notify ( struct net_device *netdev, void *priv __unused ) { struct fcoe_port *fcoe; /* Sanity check */ @@ -1185,8 +1187,9 @@ static void fcoe_notify ( struct net_device *netdev ) { * Destroy FCoE port * * @v netdev Network device + * @v priv Private data */ -static void fcoe_remove ( struct net_device *netdev ) { +static void fcoe_remove ( struct net_device *netdev, void *priv __unused ) { struct fcoe_port *fcoe; /* Sanity check */ diff --git a/src/net/infiniband/xsigo.c b/src/net/infiniband/xsigo.c index 4f5c618d..5e805fa0 100644 --- a/src/net/infiniband/xsigo.c +++ b/src/net/infiniband/xsigo.c @@ -1829,8 +1829,10 @@ struct ib_driver xsigo_ib_driver __ib_driver = { * Handle device or link status change * * @v netdev Network device + * @v priv Private data */ -static void xsigo_net_notify ( struct net_device *netdev ) { +static void xsigo_net_notify ( struct net_device *netdev, + void *priv __unused ) { struct xsigo_device *xdev; struct ib_device *ibdev; struct xsigo_manager *xcm; diff --git a/src/net/ipv6.c b/src/net/ipv6.c index ef5e51da..a0173dfb 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -1224,9 +1224,11 @@ struct ipv6_settings { * Register IPv6 link-local address settings * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int ipv6_register_settings ( struct net_device *netdev ) { +static int ipv6_register_settings ( struct net_device *netdev, + void *priv __unused ) { struct settings *parent = netdev_settings ( netdev ); struct ipv6_settings *ipv6set; int rc; diff --git a/src/net/lldp.c b/src/net/lldp.c index 72e3ecdf..2ef32cb0 100644 --- a/src/net/lldp.c +++ b/src/net/lldp.c @@ -296,9 +296,10 @@ struct net_protocol lldp_protocol __net_protocol = { * Create LLDP settings block * * @v netdev Network device + * @v priv Private data * @ret rc Return status code */ -static int lldp_probe ( struct net_device *netdev ) { +static int lldp_probe ( struct net_device *netdev, void *priv __unused ) { struct lldp_settings *lldpset; int rc; diff --git a/src/net/neighbour.c b/src/net/neighbour.c index 7f66d999..13a8bc3b 100644 --- a/src/net/neighbour.c +++ b/src/net/neighbour.c @@ -383,8 +383,9 @@ int neighbour_define ( struct net_device *netdev, * Update neighbour cache on network device state change or removal * * @v netdev Network device + * @v priv Private data */ -static void neighbour_flush ( struct net_device *netdev ) { +static void neighbour_flush ( struct net_device *netdev, void *priv __unused ) { struct neighbour *neighbour; struct neighbour *tmp; diff --git a/src/net/netdevice.c b/src/net/netdevice.c index 91517821..a9ed1813 100644 --- a/src/net/netdevice.c +++ b/src/net/netdevice.c @@ -109,6 +109,51 @@ static int netdev_has_ll_addr ( struct net_device *netdev ) { return 0; } +/** + * Get offset of network device driver private data + * + * @v driver Upper-layer driver, or NULL for device driver + * @ret offset Offset of driver private data + */ +static size_t netdev_priv_offset ( struct net_driver *driver ) { + struct net_device *netdev; + unsigned int num_configs; + size_t offset; + + /* Allow space for network device */ + offset = sizeof ( *netdev ); + + /* Allow space for configurations */ + num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS ); + offset += ( num_configs * sizeof ( netdev->configs[0] ) ); + + /* Place variable-length device driver private data at end */ + if ( ! driver ) + driver = table_end ( NET_DRIVERS ); + + /* Allow space for preceding upper-layer drivers' private data */ + for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) { + offset += driver->priv_len; + } + + /* Sanity check */ + assert ( ( offset & ( sizeof ( void * ) - 1 ) ) == 0 ); + + return offset; +} + +/** + * Get network device driver private data + * + * @v netdev Network device + * @v driver Upper-layer driver, or NULL for device driver + * @ret priv Driver private data + */ +void * netdev_priv ( struct net_device *netdev, struct net_driver *driver ) { + + return ( ( ( void * ) netdev ) + netdev_priv_offset ( driver ) ); +} + /** * Notify drivers of network device or link state change * @@ -116,10 +161,12 @@ static int netdev_has_ll_addr ( struct net_device *netdev ) { */ static void netdev_notify ( struct net_device *netdev ) { struct net_driver *driver; + void *priv; for_each_table_entry ( driver, NET_DRIVERS ) { + priv = netdev_priv ( netdev, driver ); if ( driver->notify ) - driver->notify ( netdev ); + driver->notify ( netdev, priv ); } } @@ -675,14 +722,8 @@ struct net_device * alloc_netdev ( size_t priv_len ) { struct net_device *netdev; struct net_device_configurator *configurator; struct net_device_configuration *config; - unsigned int num_configs; - size_t confs_len; - size_t total_len; - num_configs = table_num_entries ( NET_DEVICE_CONFIGURATORS ); - confs_len = ( num_configs * sizeof ( netdev->configs[0] ) ); - total_len = ( sizeof ( *netdev ) + confs_len + priv_len ); - netdev = zalloc ( total_len ); + netdev = zalloc ( netdev_priv_offset ( NULL ) + priv_len ); if ( netdev ) { ref_init ( &netdev->refcnt, free_netdev ); netdev->link_rc = -EUNKNOWN_LINK_STATUS; @@ -701,8 +742,7 @@ struct net_device * alloc_netdev ( size_t priv_len ) { &netdev->refcnt ); config++; } - netdev->priv = ( ( ( void * ) netdev ) + sizeof ( *netdev ) + - confs_len ); + netdev->priv = netdev_priv ( netdev, NULL ); } return netdev; } @@ -722,6 +762,7 @@ int register_netdev ( struct net_device *netdev ) { struct net_device *duplicate; unsigned int i; uint32_t seed; + void *priv; int rc; /* Set initial link-layer address, if not already set */ @@ -784,7 +825,9 @@ int register_netdev ( struct net_device *netdev ) { /* Probe device */ for_each_table_entry ( driver, NET_DRIVERS ) { - if ( driver->probe && ( rc = driver->probe ( netdev ) ) != 0 ) { + priv = netdev_priv ( netdev, driver ); + if ( driver->probe && + ( rc = driver->probe ( netdev, priv ) ) != 0 ) { DBGC ( netdev, "NETDEV %s could not add %s device: " "%s\n", netdev->name, driver->name, strerror ( rc ) ); @@ -796,8 +839,9 @@ int register_netdev ( struct net_device *netdev ) { err_probe: for_each_table_entry_continue_reverse ( driver, NET_DRIVERS ) { + priv = netdev_priv ( netdev, driver ); if ( driver->remove ) - driver->remove ( netdev ); + driver->remove ( netdev, priv ); } clear_settings ( netdev_settings ( netdev ) ); unregister_settings ( netdev_settings ( netdev ) ); @@ -896,14 +940,16 @@ void netdev_close ( struct net_device *netdev ) { */ void unregister_netdev ( struct net_device *netdev ) { struct net_driver *driver; + void *priv; /* Ensure device is closed */ netdev_close ( netdev ); /* Remove device */ for_each_table_entry_reverse ( driver, NET_DRIVERS ) { + priv = netdev_priv ( netdev, driver ); if ( driver->remove ) - driver->remove ( netdev ); + driver->remove ( netdev, priv ); } /* Unregister per-netdev configuration settings */ diff --git a/src/net/vlan.c b/src/net/vlan.c index d73a9571..c61bb850 100644 --- a/src/net/vlan.c +++ b/src/net/vlan.c @@ -470,9 +470,10 @@ void vlan_auto ( const void *ll_addr, unsigned int tag ) { * Create automatic VLAN device * * @v trunk Trunk network device + * @v priv Private data * @ret rc Return status code */ -static int vlan_probe ( struct net_device *trunk ) { +static int vlan_probe ( struct net_device *trunk, void *priv __unused ) { int rc; /* Do nothing unless an automatic VLAN exists */ @@ -498,8 +499,9 @@ static int vlan_probe ( struct net_device *trunk ) { * Handle trunk network device link state change * * @v trunk Trunk network device + * @v priv Private data */ -static void vlan_notify ( struct net_device *trunk ) { +static void vlan_notify ( struct net_device *trunk, void *priv __unused ) { struct net_device *netdev; struct vlan_device *vlan; @@ -538,8 +540,9 @@ static int vlan_remove_first ( struct net_device *trunk ) { * Destroy all VLAN devices for a given trunk * * @v trunk Trunk network device + * @v priv Private data */ -static void vlan_remove ( struct net_device *trunk ) { +static void vlan_remove ( struct net_device *trunk, void *priv __unused ) { /* Remove all VLAN devices attached to this trunk, safe * against arbitrary net device removal. -- cgit v1.2.3-55-g7522 From cc1e27e525201f5ee7fcc098f47f04ec26814289 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Sep 2023 20:23:59 +0100 Subject: [lldp] Use driver-private data to hold LLDP settings block Simplify the LLDP code by using driver-private data to hold the LLDP settings block, instead of using a separate allocation. This avoids the need to maintain a list of LLDP settings blocks (since the LLDP settings block pointer can always be obtained using netdev_priv()) and obviates several failure paths. Any recorded LLDP data is now freed when the network device is unregistered, since there is no longer a dedicated reference counter for the LLDP settings block. To minimise surprise, we also now explicitly unregister the settings block. This is not strictly necessary (since the block will be automatically unregistered when the parent network device settings block is unregistered), but it maintains symmetry between lldp_probe() and lldp_remove(). The overall reduction in the size of the LLDP code is around 15%. Signed-off-by: Michael Brown --- src/net/lldp.c | 94 +++++++++++++++++++--------------------------------------- 1 file changed, 31 insertions(+), 63 deletions(-) diff --git a/src/net/lldp.c b/src/net/lldp.c index 2ef32cb0..a854d0ac 100644 --- a/src/net/lldp.c +++ b/src/net/lldp.c @@ -40,12 +40,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** An LLDP settings block */ struct lldp_settings { - /** Reference counter */ - struct refcnt refcnt; /** Settings interface */ struct settings settings; - /** List of LLDP settings blocks */ - struct list_head list; /** Name */ const char *name; /** LLDP data */ @@ -54,45 +50,12 @@ struct lldp_settings { size_t len; }; +/* Forward declaration */ +struct net_driver lldp_driver __net_driver; + /** LLDP settings scope */ static const struct settings_scope lldp_settings_scope; -/** List of LLDP settings blocks */ -static LIST_HEAD ( lldp_settings ); - -/** - * Free LLDP settings block - * - * @v refcnt Reference counter - */ -static void lldp_free ( struct refcnt *refcnt ) { - struct lldp_settings *lldpset = - container_of ( refcnt, struct lldp_settings, refcnt ); - - DBGC ( lldpset, "LLDP %s freed\n", lldpset->name ); - list_del ( &lldpset->list ); - free ( lldpset->data ); - free ( lldpset ); -} - -/** - * Find LLDP settings block - * - * @v netdev Network device - * @ret lldpset LLDP settings block - */ -static struct lldp_settings * lldp_find ( struct net_device *netdev ) { - struct lldp_settings *lldpset; - - /* Find matching LLDP settings block */ - list_for_each_entry ( lldpset, &lldp_settings, list ) { - if ( netdev_settings ( netdev ) == lldpset->settings.parent ) - return lldpset; - } - - return NULL; -} - /** * Check applicability of LLDP setting * @@ -246,13 +209,7 @@ static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev, int rc; /* Find matching LLDP settings block */ - lldpset = lldp_find ( netdev ); - if ( ! lldpset ) { - DBGC ( netdev, "LLDP %s has no \"%s\" settings block\n", - netdev->name, LLDP_SETTINGS_NAME ); - rc = -ENOENT; - goto err_find; - } + lldpset = netdev_priv ( netdev, &lldp_driver ); /* Create trimmed copy of received LLDP data */ len = iob_len ( iobuf ); @@ -280,7 +237,6 @@ static int lldp_rx ( struct io_buffer *iobuf, struct net_device *netdev, free ( data ); err_alloc: - err_find: free_iob ( iobuf ); return rc; } @@ -299,24 +255,18 @@ struct net_protocol lldp_protocol __net_protocol = { * @v priv Private data * @ret rc Return status code */ -static int lldp_probe ( struct net_device *netdev, void *priv __unused ) { - struct lldp_settings *lldpset; +static int lldp_probe ( struct net_device *netdev, void *priv ) { + struct lldp_settings *lldpset = priv; int rc; - /* Allocate LLDP settings block */ - lldpset = zalloc ( sizeof ( *lldpset ) ); - if ( ! lldpset ) { - rc = -ENOMEM; - goto err_alloc; - } - ref_init ( &lldpset->refcnt, lldp_free ); + /* Initialise LLDP settings block */ settings_init ( &lldpset->settings, &lldp_settings_operations, - &lldpset->refcnt, &lldp_settings_scope ); - list_add_tail ( &lldpset->list, &lldp_settings ); + &netdev->refcnt, &lldp_settings_scope ); lldpset->name = netdev->name; /* Register settings */ - if ( ( rc = register_settings ( &lldpset->settings, netdev_settings ( netdev ), + if ( ( rc = register_settings ( &lldpset->settings, + netdev_settings ( netdev ), LLDP_SETTINGS_NAME ) ) != 0 ) { DBGC ( lldpset, "LLDP %s could not register settings: %s\n", lldpset->name, strerror ( rc ) ); @@ -324,18 +274,36 @@ static int lldp_probe ( struct net_device *netdev, void *priv __unused ) { } DBGC ( lldpset, "LLDP %s registered\n", lldpset->name ); - ref_put ( &lldpset->refcnt ); return 0; unregister_settings ( &lldpset->settings ); err_register: - ref_put ( &lldpset->refcnt ); - err_alloc: + assert ( lldpset->data == NULL ); return rc; } +/** + * Remove LLDP settings block + * + * @v netdev Network device + * @v priv Private data + */ +static void lldp_remove ( struct net_device *netdev __unused, void *priv ) { + struct lldp_settings *lldpset = priv; + + /* Unregister settings */ + unregister_settings ( &lldpset->settings ); + DBGC ( lldpset, "LLDP %s unregistered\n", lldpset->name ); + + /* Free any LLDP data */ + free ( lldpset->data ); + lldpset->data = NULL; +} + /** LLDP driver */ struct net_driver lldp_driver __net_driver = { .name = "LLDP", + .priv_len = sizeof ( struct lldp_settings ), .probe = lldp_probe, + .remove = lldp_remove, }; -- cgit v1.2.3-55-g7522 From 8b1d34badf321668f830c78e6803d718446b57ef Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Sep 2023 22:21:08 +0100 Subject: [ipv6] Use driver-private data to hold link-local IPv6 settings block Simplify the IPv6 link-local settings code by using driver-private data to hold the settings block, instead of using a separate allocation. Signed-off-by: Michael Brown --- src/net/ipv6.c | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/src/net/ipv6.c b/src/net/ipv6.c index a0173dfb..8ee0804d 100644 --- a/src/net/ipv6.c +++ b/src/net/ipv6.c @@ -1212,14 +1212,6 @@ static struct settings_operations ipv6_settings_operations = { .fetch = ipv6_fetch, }; -/** IPv6 link-local address settings */ -struct ipv6_settings { - /** Reference counter */ - struct refcnt refcnt; - /** Settings interface */ - struct settings settings; -}; - /** * Register IPv6 link-local address settings * @@ -1227,37 +1219,26 @@ struct ipv6_settings { * @v priv Private data * @ret rc Return status code */ -static int ipv6_register_settings ( struct net_device *netdev, - void *priv __unused ) { +static int ipv6_register_settings ( struct net_device *netdev, void *priv ) { struct settings *parent = netdev_settings ( netdev ); - struct ipv6_settings *ipv6set; + struct settings *settings = priv; int rc; - /* Allocate and initialise structure */ - ipv6set = zalloc ( sizeof ( *ipv6set ) ); - if ( ! ipv6set ) { - rc = -ENOMEM; - goto err_alloc; - } - ref_init ( &ipv6set->refcnt, NULL ); - settings_init ( &ipv6set->settings, &ipv6_settings_operations, - &ipv6set->refcnt, &ipv6_settings_scope ); - ipv6set->settings.order = IPV6_ORDER_LINK_LOCAL; - - /* Register settings */ - if ( ( rc = register_settings ( &ipv6set->settings, parent, + /* Initialise and register settings */ + settings_init ( settings, &ipv6_settings_operations, + &netdev->refcnt, &ipv6_settings_scope ); + settings->order = IPV6_ORDER_LINK_LOCAL; + if ( ( rc = register_settings ( settings, parent, IPV6_SETTINGS_NAME ) ) != 0 ) - goto err_register; + return rc; - err_register: - ref_put ( &ipv6set->refcnt ); - err_alloc: - return rc; + return 0; } /** IPv6 network device driver */ struct net_driver ipv6_driver __net_driver = { .name = "IPv6", + .priv_len = sizeof ( struct settings ), .probe = ipv6_register_settings, }; -- cgit v1.2.3-55-g7522 From 8cbf248198f3bc66c52b2340b4decf293af8af47 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Sep 2023 22:43:24 +0100 Subject: [vmware] Use driver-private data to hold GuestInfo settings block Simplify the per-netdevice GuestInfo settings code by using driver-private data to hold the settings block, instead of using a separate allocation. The settings block (if existent) will be automatically unregistered when the parent network device settings block is unregistered, and no longer needs to be separately freed. The guestinfo_net_remove() function may therefore be omitted completely. Signed-off-by: Michael Brown --- src/arch/x86/interface/vmware/guestinfo.c | 48 +++++-------------------------- 1 file changed, 7 insertions(+), 41 deletions(-) diff --git a/src/arch/x86/interface/vmware/guestinfo.c b/src/arch/x86/interface/vmware/guestinfo.c index b52c2e87..4134515c 100644 --- a/src/arch/x86/interface/vmware/guestinfo.c +++ b/src/arch/x86/interface/vmware/guestinfo.c @@ -210,66 +210,32 @@ struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = { * @v priv Private data * @ret rc Return status code */ -static int guestinfo_net_probe ( struct net_device *netdev, - void *priv __unused ) { - struct settings *settings; +static int guestinfo_net_probe ( struct net_device *netdev, void *priv ) { + struct settings *settings = priv; int rc; /* Do nothing unless we have a GuestInfo channel available */ if ( guestinfo_channel < 0 ) return 0; - /* Allocate and initialise settings block */ - settings = zalloc ( sizeof ( *settings ) ); - if ( ! settings ) { - rc = -ENOMEM; - goto err_alloc; - } - settings_init ( settings, &guestinfo_settings_operations, NULL, NULL ); - - /* Register settings */ + /* Initialise and register settings */ + settings_init ( settings, &guestinfo_settings_operations, + &netdev->refcnt, NULL ); if ( ( rc = register_settings ( settings, netdev_settings ( netdev ), "vmware" ) ) != 0 ) { DBGC ( settings, "GuestInfo %p could not register for %s: %s\n", settings, netdev->name, strerror ( rc ) ); - goto err_register; + return rc; } DBGC ( settings, "GuestInfo %p registered for %s\n", settings, netdev->name ); return 0; - - err_register: - free ( settings ); - err_alloc: - return rc; -} - -/** - * Remove per-netdevice GuestInfo settings - * - * @v netdev Network device - * @v priv Private data - */ -static void guestinfo_net_remove ( struct net_device *netdev, - void *priv __unused ) { - struct settings *parent = netdev_settings ( netdev ); - struct settings *settings; - - list_for_each_entry ( settings, &parent->children, siblings ) { - if ( settings->op == &guestinfo_settings_operations ) { - DBGC ( settings, "GuestInfo %p unregistered for %s\n", - settings, netdev->name ); - unregister_settings ( settings ); - free ( settings ); - return; - } - } } /** GuestInfo per-netdevice driver */ struct net_driver guestinfo_net_driver __net_driver = { .name = "GuestInfo", + .priv_len = sizeof ( struct settings ), .probe = guestinfo_net_probe, - .remove = guestinfo_net_remove, }; -- cgit v1.2.3-55-g7522 From cac3a584dc8acea1522669f1ed16e0979fb92252 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Sep 2023 23:00:57 +0100 Subject: [fcoe] Use driver-private data to hold FCoE port structure Simplify the FCoE code by using driver-private data to hold the FCoE port for each network device, instead of using a separate allocation. Signed-off-by: Michael Brown --- src/net/fcoe.c | 85 +++++++++++++++------------------------------------------- 1 file changed, 21 insertions(+), 64 deletions(-) diff --git a/src/net/fcoe.c b/src/net/fcoe.c index 70804dd0..9f3ddf88 100644 --- a/src/net/fcoe.c +++ b/src/net/fcoe.c @@ -69,10 +69,6 @@ FEATURE ( FEATURE_PROTOCOL, "FCoE", DHCP_EB_FEATURE_FCOE, 1 ); /** An FCoE port */ struct fcoe_port { - /** Reference count */ - struct refcnt refcnt; - /** List of FCoE ports */ - struct list_head list; /** Transport interface */ struct interface transport; /** Network device */ @@ -115,6 +111,7 @@ enum fcoe_flags { FCOE_VLAN_TIMED_OUT = 0x0020, }; +struct net_driver fcoe_driver __net_driver; struct net_protocol fcoe_protocol __net_protocol; struct net_protocol fip_protocol __net_protocol; @@ -152,9 +149,6 @@ static uint8_t default_fcf_mac[ETH_ALEN] = /** Maximum number of missing discovery advertisements */ #define FCOE_MAX_FIP_MISSING_KEEPALIVES 4 -/** List of FCoE ports */ -static LIST_HEAD ( fcoe_ports ); - /****************************************************************************** * * FCoE protocol @@ -162,22 +156,6 @@ static LIST_HEAD ( fcoe_ports ); ****************************************************************************** */ -/** - * Identify FCoE port by network device - * - * @v netdev Network device - * @ret fcoe FCoE port, or NULL - */ -static struct fcoe_port * fcoe_demux ( struct net_device *netdev ) { - struct fcoe_port *fcoe; - - list_for_each_entry ( fcoe, &fcoe_ports, list ) { - if ( fcoe->netdev == netdev ) - return fcoe; - } - return NULL; -} - /** * Reset FCoE port * @@ -348,7 +326,8 @@ static int fcoe_rx ( struct io_buffer *iobuf, struct net_device *netdev, int rc; /* Identify FCoE port */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { + fcoe = netdev_priv ( netdev, &fcoe_driver ); + if ( ! fcoe->netdev ) { DBG ( "FCoE received frame for net device %s missing FCoE " "port\n", netdev->name ); rc = -ENOTCONN; @@ -448,9 +427,6 @@ static void fcoe_close ( struct fcoe_port *fcoe, int rc ) { stop_timer ( &fcoe->timer ); intf_shutdown ( &fcoe->transport, rc ); - netdev_put ( fcoe->netdev ); - list_del ( &fcoe->list ); - ref_put ( &fcoe->refcnt ); } /** @@ -947,7 +923,8 @@ static int fcoe_fip_rx ( struct io_buffer *iobuf, int rc; /* Identify FCoE port */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { + fcoe = netdev_priv ( netdev, &fcoe_driver ); + if ( ! fcoe->netdev ) { DBG ( "FCoE received FIP frame for net device %s missing FCoE " "port\n", netdev->name ); rc = -ENOTCONN; @@ -1113,29 +1090,21 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) { * @v priv Private data * @ret rc Return status code */ -static int fcoe_probe ( struct net_device *netdev, void *priv __unused ) { +static int fcoe_probe ( struct net_device *netdev, void *priv ) { struct ll_protocol *ll_protocol = netdev->ll_protocol; - struct fcoe_port *fcoe; - int rc; + struct fcoe_port *fcoe = priv; /* Sanity check */ if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) { /* Not an error; simply skip this net device */ DBG ( "FCoE skipping non-Ethernet device %s\n", netdev->name ); - rc = 0; - goto err_non_ethernet; + return 0; } - /* Allocate and initialise structure */ - fcoe = zalloc ( sizeof ( *fcoe ) ); - if ( ! fcoe ) { - rc = -ENOMEM; - goto err_zalloc; - } - ref_init ( &fcoe->refcnt, NULL ); - intf_init ( &fcoe->transport, &fcoe_transport_desc, &fcoe->refcnt ); - timer_init ( &fcoe->timer, fcoe_expired, &fcoe->refcnt ); - fcoe->netdev = netdev_get ( netdev ); + /* Initialise structure */ + intf_init ( &fcoe->transport, &fcoe_transport_desc, &netdev->refcnt ); + timer_init ( &fcoe->timer, fcoe_expired, &netdev->refcnt ); + fcoe->netdev = netdev; /* Construct node and port names */ fcoe->node_wwn.fcoe.authority = htons ( FCOE_AUTHORITY_IEEE ); @@ -1149,14 +1118,7 @@ static int fcoe_probe ( struct net_device *netdev, void *priv __unused ) { fc_ntoa ( &fcoe->node_wwn.fc ) ); DBGC ( fcoe, " port %s\n", fc_ntoa ( &fcoe->port_wwn.fc ) ); - /* Transfer reference to port list */ - list_add ( &fcoe->list, &fcoe_ports ); return 0; - - netdev_put ( fcoe->netdev ); - err_zalloc: - err_non_ethernet: - return rc; } /** @@ -1165,15 +1127,12 @@ static int fcoe_probe ( struct net_device *netdev, void *priv __unused ) { * @v netdev Network device * @v priv Private data */ -static void fcoe_notify ( struct net_device *netdev, void *priv __unused ) { - struct fcoe_port *fcoe; +static void fcoe_notify ( struct net_device *netdev, void *priv ) { + struct fcoe_port *fcoe = priv; - /* Sanity check */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { - DBG ( "FCoE notification for net device %s missing FCoE " - "port\n", netdev->name ); + /* Skip non-FCoE net devices */ + if ( ! fcoe->netdev ) return; - } /* Reset the FCoE link if necessary */ if ( ! ( netdev_is_open ( netdev ) && @@ -1189,15 +1148,12 @@ static void fcoe_notify ( struct net_device *netdev, void *priv __unused ) { * @v netdev Network device * @v priv Private data */ -static void fcoe_remove ( struct net_device *netdev, void *priv __unused ) { - struct fcoe_port *fcoe; +static void fcoe_remove ( struct net_device *netdev __unused, void *priv ) { + struct fcoe_port *fcoe = priv; - /* Sanity check */ - if ( ( fcoe = fcoe_demux ( netdev ) ) == NULL ) { - DBG ( "FCoE removal of net device %s missing FCoE port\n", - netdev->name ); + /* Skip non-FCoE net devices */ + if ( ! fcoe->netdev ) return; - } /* Close FCoE device */ fcoe_close ( fcoe, 0 ); @@ -1206,6 +1162,7 @@ static void fcoe_remove ( struct net_device *netdev, void *priv __unused ) { /** FCoE driver */ struct net_driver fcoe_driver __net_driver = { .name = "FCoE", + .priv_len = sizeof ( struct fcoe_port ), .probe = fcoe_probe, .notify = fcoe_notify, .remove = fcoe_remove, -- cgit v1.2.3-55-g7522 From 56cc61a168820c7cbbe23418388129ec11699a8c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 15 Sep 2023 16:10:07 +0100 Subject: [eap] Define a supplicant model for EAP and EAPoL Extend the EAP model to include a record of whether or not EAP authentication has completed (successfully or otherwise), and to provide a method for transmitting EAP responses. Signed-off-by: Michael Brown --- src/include/ipxe/eap.h | 21 +++++++- src/include/ipxe/eapol.h | 13 +++-- src/net/80211/wpa.c | 11 +++-- src/net/eap.c | 43 +++++++++++------ src/net/eapol.c | 123 +++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 184 insertions(+), 27 deletions(-) diff --git a/src/include/ipxe/eap.h b/src/include/ipxe/eap.h index 6fe70189..e5f60655 100644 --- a/src/include/ipxe/eap.h +++ b/src/include/ipxe/eap.h @@ -64,6 +64,25 @@ union eap_packet { */ #define EAP_BLOCK_TIMEOUT ( 45 * TICKS_PER_SEC ) -extern int eap_rx ( struct net_device *netdev, const void *data, size_t len ); +/** An EAP supplicant */ +struct eap_supplicant { + /** Network device */ + struct net_device *netdev; + /** Authentication outcome is final */ + int done; + /** + * Transmit EAP response + * + * @v supplicant EAP supplicant + * @v data Response data + * @v len Length of response data + * @ret rc Return status code + */ + int ( * tx ) ( struct eap_supplicant *supplicant, + const void *data, size_t len ); +}; + +extern int eap_rx ( struct eap_supplicant *supplicant, + const void *data, size_t len ); #endif /* _IPXE_EAP_H */ diff --git a/src/include/ipxe/eapol.h b/src/include/ipxe/eapol.h index 952d6c75..f6009a2f 100644 --- a/src/include/ipxe/eapol.h +++ b/src/include/ipxe/eapol.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include /** EAPoL header */ struct eapol_header { @@ -32,6 +33,12 @@ struct eapol_header { /** EAPoL key */ #define EAPOL_TYPE_KEY 5 +/** An EAPoL supplicant */ +struct eapol_supplicant { + /** EAP supplicant */ + struct eap_supplicant eap; +}; + /** An EAPoL handler */ struct eapol_handler { /** Type */ @@ -39,15 +46,15 @@ struct eapol_handler { /** * Process received packet * + * @v supplicant EAPoL supplicant * @v iobuf I/O buffer - * @v netdev Network device * @v ll_source Link-layer source address * @ret rc Return status code * * This method takes ownership of the I/O buffer. */ - int ( * rx ) ( struct io_buffer *iobuf, struct net_device *netdev, - const void *ll_source ); + int ( * rx ) ( struct eapol_supplicant *supplicant, + struct io_buffer *iobuf, const void *ll_source ); }; /** EAPoL handler table */ diff --git a/src/net/80211/wpa.c b/src/net/80211/wpa.c index 1484d0e8..17c11b8e 100644 --- a/src/net/80211/wpa.c +++ b/src/net/80211/wpa.c @@ -761,13 +761,14 @@ static int wpa_handle_1_of_2 ( struct wpa_common_ctx *ctx, /** * Handle receipt of EAPOL-Key frame for WPA * - * @v iob I/O buffer - * @v netdev Network device - * @v ll_source Source link-layer address + * @v supplicant EAPoL supplicant + * @v iob I/O buffer + * @v ll_source Source link-layer address */ -static int eapol_key_rx ( struct io_buffer *iob, struct net_device *netdev, - const void *ll_source ) +static int eapol_key_rx ( struct eapol_supplicant *supplicant, + struct io_buffer *iob, const void *ll_source ) { + struct net_device *netdev = supplicant->eap.netdev; struct net80211_device *dev = net80211_get ( netdev ); struct eapol_header *eapol; struct eapol_key_pkt *pkt; diff --git a/src/net/eap.c b/src/net/eap.c index 8d1d540f..beaeb61d 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -36,10 +36,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** * Handle EAP Request-Identity * - * @v netdev Network device + * @v supplicant EAP supplicant * @ret rc Return status code */ -static int eap_rx_request_identity ( struct net_device *netdev ) { +static int eap_rx_request_identity ( struct eap_supplicant *supplicant ) { + struct net_device *netdev = supplicant->netdev; /* Treat Request-Identity as blocking the link */ DBGC ( netdev, "EAP %s Request-Identity blocking link\n", @@ -52,13 +53,14 @@ static int eap_rx_request_identity ( struct net_device *netdev ) { /** * Handle EAP Request * - * @v netdev Network device + * @v supplicant EAP supplicant * @v req EAP request * @v len Length of EAP request * @ret rc Return status code */ -static int eap_rx_request ( struct net_device *netdev, +static int eap_rx_request ( struct eap_supplicant *supplicant, const struct eap_request *req, size_t len ) { + struct net_device *netdev = supplicant->netdev; /* Sanity check */ if ( len < sizeof ( *req ) ) { @@ -67,10 +69,13 @@ static int eap_rx_request ( struct net_device *netdev, return -EINVAL; } + /* Mark authentication as incomplete */ + supplicant->done = 0; + /* Handle according to type */ switch ( req->type ) { case EAP_TYPE_IDENTITY: - return eap_rx_request_identity ( netdev ); + return eap_rx_request_identity ( supplicant ); default: DBGC ( netdev, "EAP %s requested type %d unknown:\n", netdev->name, req->type ); @@ -82,10 +87,14 @@ static int eap_rx_request ( struct net_device *netdev, /** * Handle EAP Success * - * @v netdev Network device + * @v supplicant EAP supplicant * @ret rc Return status code */ -static int eap_rx_success ( struct net_device *netdev ) { +static int eap_rx_success ( struct eap_supplicant *supplicant ) { + struct net_device *netdev = supplicant->netdev; + + /* Mark authentication as complete */ + supplicant->done = 1; /* Mark link as unblocked */ DBGC ( netdev, "EAP %s Success\n", netdev->name ); @@ -97,10 +106,14 @@ static int eap_rx_success ( struct net_device *netdev ) { /** * Handle EAP Failure * - * @v netdev Network device + * @v supplicant EAP supplicant * @ret rc Return status code */ -static int eap_rx_failure ( struct net_device *netdev ) { +static int eap_rx_failure ( struct eap_supplicant *supplicant ) { + struct net_device *netdev = supplicant->netdev; + + /* Mark authentication as complete */ + supplicant->done = 1; /* Record error */ DBGC ( netdev, "EAP %s Failure\n", netdev->name ); @@ -110,12 +123,14 @@ static int eap_rx_failure ( struct net_device *netdev ) { /** * Handle EAP packet * - * @v netdev Network device + * @v supplicant EAP supplicant * @v data EAP packet * @v len Length of EAP packet * @ret rc Return status code */ -int eap_rx ( struct net_device *netdev, const void *data, size_t len ) { +int eap_rx ( struct eap_supplicant *supplicant, const void *data, + size_t len ) { + struct net_device *netdev = supplicant->netdev; const union eap_packet *eap = data; /* Sanity check */ @@ -128,11 +143,11 @@ int eap_rx ( struct net_device *netdev, const void *data, size_t len ) { /* Handle according to code */ switch ( eap->hdr.code ) { case EAP_CODE_REQUEST: - return eap_rx_request ( netdev, &eap->req, len ); + return eap_rx_request ( supplicant, &eap->req, len ); case EAP_CODE_SUCCESS: - return eap_rx_success ( netdev ); + return eap_rx_success ( supplicant ); case EAP_CODE_FAILURE: - return eap_rx_failure ( netdev ); + return eap_rx_failure ( supplicant ); default: DBGC ( netdev, "EAP %s unsupported code %d\n", netdev->name, eap->hdr.code ); diff --git a/src/net/eapol.c b/src/net/eapol.c index 3578f0e3..172037ce 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -28,7 +28,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include +#include #include #include @@ -38,6 +40,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +struct net_driver eapol_driver __net_driver; + +/** EAPoL destination MAC address */ +static const uint8_t eapol_mac[ETH_ALEN] = { + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 +}; + /** * Process EAPoL packet * @@ -51,12 +60,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source, unsigned int flags __unused ) { + struct eapol_supplicant *supplicant; struct eapol_header *eapol; struct eapol_handler *handler; size_t remaining; size_t len; int rc; + /* Find matching supplicant */ + supplicant = netdev_priv ( netdev, &eapol_driver ); + + /* Ignore non-EAPoL devices */ + if ( ! supplicant->eap.netdev ) { + DBGC ( netdev, "EAPOL %s is not an EAPoL device\n", + netdev->name ); + DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) ); + rc = -ENOTTY; + goto drop; + } + /* Sanity checks */ if ( iob_len ( iobuf ) < sizeof ( *eapol ) ) { DBGC ( netdev, "EAPOL %s underlength header:\n", @@ -83,7 +105,7 @@ static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev, /* Handle according to type */ for_each_table_entry ( handler, EAPOL_HANDLERS ) { if ( handler->type == eapol->type ) { - return handler->rx ( iob_disown ( iobuf ) , netdev, + return handler->rx ( supplicant, iob_disown ( iobuf ), ll_source ); } } @@ -107,12 +129,14 @@ struct net_protocol eapol_protocol __net_protocol = { /** * Process EAPoL-encapsulated EAP packet * - * @v netdev Network device + * @v supplicant EAPoL supplicant * @v ll_source Link-layer source address * @ret rc Return status code */ -static int eapol_eap_rx ( struct io_buffer *iobuf, struct net_device *netdev, +static int eapol_eap_rx ( struct eapol_supplicant *supplicant, + struct io_buffer *iobuf, const void *ll_source __unused ) { + struct net_device *netdev = supplicant->eap.netdev; struct eapol_header *eapol; int rc; @@ -123,7 +147,8 @@ static int eapol_eap_rx ( struct io_buffer *iobuf, struct net_device *netdev, eapol = iob_pull ( iobuf, sizeof ( *eapol ) ); /* Process EAP packet */ - if ( ( rc = eap_rx ( netdev, iobuf->data, iob_len ( iobuf ) ) ) != 0 ) { + if ( ( rc = eap_rx ( &supplicant->eap, iobuf->data, + iob_len ( iobuf ) ) ) != 0 ) { DBGC ( netdev, "EAPOL %s v%d EAP failed: %s\n", netdev->name, eapol->version, strerror ( rc ) ); goto drop; @@ -139,3 +164,93 @@ struct eapol_handler eapol_eap __eapol_handler = { .type = EAPOL_TYPE_EAP, .rx = eapol_eap_rx, }; + +/** + * Transmit EAPoL packet + * + * @v supplicant EAPoL supplicant + * @v type Packet type + * @v data Packet body + * @v len Length of packet body + * @ret rc Return status code + */ +static int eapol_tx ( struct eapol_supplicant *supplicant, unsigned int type, + const void *data, size_t len ) { + struct net_device *netdev = supplicant->eap.netdev; + struct io_buffer *iobuf; + struct eapol_header *eapol; + int rc; + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *eapol ) + len ); + if ( ! iobuf ) + return -ENOMEM; + iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); + + /* Construct EAPoL header */ + eapol = iob_put ( iobuf, sizeof ( *eapol ) ); + eapol->version = EAPOL_VERSION_2001; + eapol->type = type; + eapol->len = htons ( len ); + + /* Append packet body */ + memcpy ( iob_put ( iobuf, len ), data, len ); + + /* Transmit packet */ + if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &eapol_protocol, + &eapol_mac, netdev->ll_addr ) ) != 0 ) { + DBGC ( netdev, "EAPOL %s could not transmit type %d: %s\n", + netdev->name, type, strerror ( rc ) ); + DBGC_HDA ( netdev, 0, data, len ); + return rc; + } + + return 0; +} + +/** + * Transmit EAPoL-encapsulated EAP packet + * + * @v supplicant EAPoL supplicant + * @v ll_source Link-layer source address + * @ret rc Return status code + */ +static int eapol_eap_tx ( struct eap_supplicant *eap, const void *data, + size_t len ) { + struct eapol_supplicant *supplicant = + container_of ( eap, struct eapol_supplicant, eap ); + + /* Transmit encapsulated packet */ + return eapol_tx ( supplicant, EAPOL_TYPE_EAP, data, len ); +} + +/** + * Create EAPoL supplicant + * + * @v netdev Network device + * @v priv Private data + * @ret rc Return status code + */ +static int eapol_probe ( struct net_device *netdev, void *priv ) { + struct eapol_supplicant *supplicant = priv; + struct ll_protocol *ll_protocol = netdev->ll_protocol; + + /* Ignore non-EAPoL devices */ + if ( ll_protocol->ll_proto != htons ( ARPHRD_ETHER ) ) + return 0; + if ( vlan_tag ( netdev ) ) + return 0; + + /* Initialise structure */ + supplicant->eap.netdev = netdev; + supplicant->eap.tx = eapol_eap_tx; + + return 0; +} + +/** EAPoL driver */ +struct net_driver eapol_driver __net_driver = { + .name = "EAPoL", + .priv_len = sizeof ( struct eapol_supplicant ), + .probe = eapol_probe, +}; -- cgit v1.2.3-55-g7522 From 8b14652e506d99499cfbeaed0df07d6a83ec029e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 15 Sep 2023 16:14:59 +0100 Subject: [eapol] Send EAPoL-Start packets to trigger EAP authentication We have no way to force a link-layer restart in iPXE, and therefore no way to explicitly trigger a restart of EAP authentication. If an iPXE script has performed some action that requires such a restart (e.g. registering a device such that the port VLAN assignment will be changed), then the only means currently available to effect the restart is to reboot the whole system. If iPXE is taking over a physical link already used by a preceding bootloader, then even a reboot may not work. In the EAP model, the supplicant is a pure responder and never initiates transmissions. EAPoL extends this to include an EAPoL-Start packet type that may be sent by the supplicant to (re)trigger EAP. Add support for sending EAPoL-Start packets at two-second intervals on links that are open and have reached physical link-up, but for which EAP has not yet completed. This allows "ifclose ; ifopen" to be used to restart the EAP process. Signed-off-by: Michael Brown --- src/include/ipxe/eapol.h | 8 ++++++ src/net/eapol.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/include/ipxe/eapol.h b/src/include/ipxe/eapol.h index f6009a2f..d4ea3920 100644 --- a/src/include/ipxe/eapol.h +++ b/src/include/ipxe/eapol.h @@ -30,6 +30,9 @@ struct eapol_header { /** EAPoL-encapsulated EAP packets */ #define EAPOL_TYPE_EAP 0 +/** EAPoL start */ +#define EAPOL_TYPE_START 1 + /** EAPoL key */ #define EAPOL_TYPE_KEY 5 @@ -37,8 +40,13 @@ struct eapol_header { struct eapol_supplicant { /** EAP supplicant */ struct eap_supplicant eap; + /** EAPoL-Start retransmission timer */ + struct retry_timer timer; }; +/** Delay between EAPoL-Start packets */ +#define EAPOL_START_INTERVAL ( 2 * TICKS_PER_SEC ) + /** An EAPoL handler */ struct eapol_handler { /** Type */ diff --git a/src/net/eapol.c b/src/net/eapol.c index 172037ce..1b843e89 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -47,6 +48,37 @@ static const uint8_t eapol_mac[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }; +/** + * Update EAPoL supplicant state + * + * @v supplicant EAPoL supplicant + * @v timeout Timer ticks until next EAPoL-Start (if applicable) + */ +static void eapol_update ( struct eapol_supplicant *supplicant, + unsigned long timeout ) { + struct net_device *netdev = supplicant->eap.netdev; + + /* Check device and EAP state */ + if ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) { + if ( supplicant->eap.done ) { + + /* EAP has completed: stop sending EAPoL-Start */ + stop_timer ( &supplicant->timer ); + + } else if ( ! timer_running ( &supplicant->timer ) ) { + + /* EAP has not yet begun: start sending EAPoL-Start */ + start_timer_fixed ( &supplicant->timer, timeout ); + } + + } else { + + /* Not ready: clear completion and stop sending EAPoL-Start */ + supplicant->eap.done = 0; + stop_timer ( &supplicant->timer ); + } +} + /** * Process EAPoL packet * @@ -154,6 +186,9 @@ static int eapol_eap_rx ( struct eapol_supplicant *supplicant, goto drop; } + /* Update supplicant state */ + eapol_update ( supplicant, EAPOL_START_INTERVAL ); + drop: free_iob ( iobuf ); return rc; @@ -224,6 +259,25 @@ static int eapol_eap_tx ( struct eap_supplicant *eap, const void *data, return eapol_tx ( supplicant, EAPOL_TYPE_EAP, data, len ); } +/** + * (Re)transmit EAPoL-Start packet + * + * @v timer EAPoL-Start timer + * @v expired Failure indicator + */ +static void eapol_expired ( struct retry_timer *timer, int fail __unused ) { + struct eapol_supplicant *supplicant = + container_of ( timer, struct eapol_supplicant, timer ); + struct net_device *netdev = supplicant->eap.netdev; + + /* Schedule next transmission */ + start_timer_fixed ( timer, EAPOL_START_INTERVAL ); + + /* Transmit EAPoL-Start, ignoring errors */ + DBGC2 ( netdev, "EAPOL %s transmitting Start\n", netdev->name ); + eapol_tx ( supplicant, EAPOL_TYPE_START, NULL, 0 ); +} + /** * Create EAPoL supplicant * @@ -244,13 +298,32 @@ static int eapol_probe ( struct net_device *netdev, void *priv ) { /* Initialise structure */ supplicant->eap.netdev = netdev; supplicant->eap.tx = eapol_eap_tx; + timer_init ( &supplicant->timer, eapol_expired, &netdev->refcnt ); return 0; } +/** + * Handle EAPoL supplicant state change + * + * @v netdev Network device + * @v priv Private data + */ +static void eapol_notify ( struct net_device *netdev __unused, void *priv ) { + struct eapol_supplicant *supplicant = priv; + + /* Ignore non-EAPoL devices */ + if ( ! supplicant->eap.netdev ) + return; + + /* Update supplicant state */ + eapol_update ( supplicant, 0 ); +} + /** EAPoL driver */ struct net_driver eapol_driver __net_driver = { .name = "EAPoL", .priv_len = sizeof ( struct eapol_supplicant ), .probe = eapol_probe, + .notify = eapol_notify, }; -- cgit v1.2.3-55-g7522 From ff0f860483e344f1af633f94696ff7bc1854611f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 6 Oct 2023 12:43:02 +0100 Subject: [libc] Use wall clock time as seed for the (non-cryptographic) RNG We currently use the number of timer ticks since power-on as a seed for the non-cryptographic RNG implemented by random(). Since iPXE is often executed directly after power-on, and since the timer tick resolution is generally low, this can often result in identical seed values being used on each cold boot attempt. As of commit 41f786c ("[settings] Add "unixtime" builtin setting to expose the current time"), the current wall-clock time is always available within the default build of iPXE. Use this time instead, to introduce variability between cold boot attempts on the same host. (Note that variability between different hosts is obtained by using the MAC address as an additional seed value.) This has no effect on the separate DRBG used by cryptographic code. Suggested-by: Heiko Signed-off-by: Michael Brown --- src/core/random.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/random.c b/src/core/random.c index 975a03cf..e3251964 100644 --- a/src/core/random.c +++ b/src/core/random.c @@ -6,8 +6,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include -#include +#include static int32_t rnd_seed = 0; @@ -30,8 +31,9 @@ void srandom ( unsigned int seed ) { long int random ( void ) { int32_t q; - if ( ! rnd_seed ) /* Initialize linear congruential generator */ - srandom ( currticks() ); + /* Initialize linear congruential generator */ + if ( ! rnd_seed ) + srandom ( time ( NULL ) ); /* simplified version of the LCG given in Bruce Schneier's "Applied Cryptography" */ -- cgit v1.2.3-55-g7522