Compare commits

..

1 Commits

Author SHA1 Message Date
ea7646be89 [efi] Record cached ProxyDHCPOFFER and PXEBSACK, if present
Commit cd3de55 ("[efi] Record cached DHCPACK from loaded image's
device handle, if present") added the ability for a chainloaded UEFI
iPXE to reuse an IPv4 address and DHCP options previously obtained by
a built-in PXE stack, without needing to perform a second DHCP
request.

Extend this to also record the cached ProxyDHCPOFFER and PXEBSACK
obtained from the EFI_PXE_BASE_CODE_PROTOCOL instance installed on the
loaded image's device handle, if present.

This allows a chainloaded UEFI iPXE to reuse a boot filename or other
options that were provided via a ProxyDHCP or PXE boot server
mechanism, rather than by standard DHCP.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2021-07-23 11:32:04 +01:00
373 changed files with 18148 additions and 27562 deletions

View File

@ -16,7 +16,7 @@ BLOCKSIZE = 512 * 1024
def detect_architecture(image):
"""Detect CPU architecture"""
mdir = subprocess.run(['mdir', '-b', '-i', image, '::/EFI/BOOT'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
capture_output=True)
if any(b'BOOTAA64.EFI' in x for x in mdir.stdout.splitlines()):
return 'arm64'
return 'x86_64'

View File

@ -24,7 +24,6 @@ CP := cp
ECHO := echo
PRINTF := printf
PERL := perl
PYTHON := python
TRUE := true
CC := $(CROSS_COMPILE)gcc
CPP := $(CC) -E
@ -51,7 +50,7 @@ ELF2EFI64 := ./util/elf2efi64
EFIROM := ./util/efirom
EFIFATBIN := ./util/efifatbin
EINFO := ./util/einfo
GENKEYMAP := ./util/genkeymap.py
GENKEYMAP := ./util/genkeymap.pl
DOXYGEN := doxygen
LCAB := lcab
QEMUIMG := qemu-img
@ -191,7 +190,7 @@ vmware : bin/8086100f.mrom bin/808610d3.mrom bin/10222000.rom bin/15ad07b0.rom
@$(ECHO) ' bin/10222000.rom -- vlance/pcnet32'
@$(ECHO) ' bin/15ad07b0.rom -- vmxnet3'
@$(ECHO)
@$(ECHO) 'For more information, see https://ipxe.org/howto/vmware'
@$(ECHO) 'For more information, see http://ipxe.org/howto/vmware'
@$(ECHO)
@$(ECHO) '==========================================================='

View File

@ -43,8 +43,7 @@ $(BIN)/%.drv.efi : $(BIN)/%.efidrv
$(BIN)/%.efirom : $(BIN)/%.efidrv $(EFIROM)
$(QM)$(ECHO) " [FINISH] $@"
$(Q)$(EFIROM) -v $(firstword $(TGT_PCI_VENDOR) 0) \
-d $(firstword $(TGT_PCI_DEVICE) 0) -c $< $@
$(Q)$(EFIROM) -v $(TGT_PCI_VENDOR) -d $(TGT_PCI_DEVICE) -c $< $@
$(BIN)/efidrv.cab : $(BIN)/alldrv.efis # $(ALL_drv.efi) is not yet defined
$(QM)$(ECHO) " [CAB] $@"

View File

@ -369,6 +369,7 @@ endif
# Include architecture-specific include path
ifdef ARCH
INCDIRS += arch/$(ARCH)/include
INCDIRS += arch/$(ARCH)/include/$(PLATFORM)
endif
###############################################################################
@ -461,9 +462,7 @@ ifeq ($(CCTYPE),gcc)
CFLAGS += -ffreestanding
CFLAGS += -fcommon
CFLAGS += -Wall -W -Wformat-nonliteral
CFLAGS += -Wno-array-bounds -Wno-dangling-pointer
HOST_CFLAGS += -Wall -W -Wformat-nonliteral
HOST_CFLAGS += -Wno-array-bounds -Wno-dangling-pointer
endif
CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS)
ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS)
@ -511,10 +510,6 @@ CFLAGS += -include include/compiler.h
#
CFLAGS += -DASM_TCHAR='$(ASM_TCHAR)' -DASM_TCHAR_OPS='$(ASM_TCHAR_OPS)'
# Inhibit the default -Dlinux
#
CFLAGS += -Ulinux
# CFLAGS for specific object types
#
CFLAGS_c +=
@ -923,7 +918,7 @@ $(BIN)/deps/%.d : % $(MAKEDEPS)
# Calculate list of dependency files
#
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS) core/version.c)
AUTO_DEPS = $(patsubst %,$(BIN)/deps/%.d,$(AUTO_SRCS))
autodeps :
@$(ECHO) $(AUTO_DEPS)
VERYCLEANUP += $(BIN)/deps
@ -1207,7 +1202,7 @@ endif
# Build version
#
GIT_INDEX := $(if $(GITVERSION),$(if $(wildcard ../.git/index),../.git/index))
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(version_DEPS) $(GIT_INDEX)
$(BIN)/version.%.o : core/version.c $(MAKEDEPS) $(GIT_INDEX)
$(QM)$(ECHO) " [VERSION] $@"
$(Q)$(COMPILE_c) -DBUILD_NAME="\"$*\"" \
-DVERSION_MAJOR=$(VERSION_MAJOR) \
@ -1568,7 +1563,7 @@ endif # defined(BIN)
#
hci/keymap/keymap_%.c :
$(Q)$(PYTHON) $(GENKEYMAP) $* > $@
$(Q)$(PERL) $(GENKEYMAP) $* > $@
###############################################################################
#

View File

@ -8,10 +8,6 @@ SYMBOL_PREFIX = _ipxe__
#
CFLAGS += -UNVALGRIND
# The Linux linker script
#
LDSCRIPT = scripts/linux.lds
# Use a two-stage link
#
LDFLAGS += -r -d

View File

@ -1,6 +0,0 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Include generic Linux Makefile
#
MAKEDEPS += Makefile.linux
include Makefile.linux

View File

@ -5,7 +5,7 @@ SRCDIRS += arch/arm32/libgcc
# ARM32-specific flags
#
CFLAGS += -mthumb -mcpu=cortex-a15 -mabi=aapcs
CFLAGS += -mthumb -mcpu=cortex-a15 -mabi=aapcs -mfloat-abi=soft
CFLAGS += -mword-relocations
ASFLAGS += -mthumb -mcpu=cortex-a15
@ -13,11 +13,6 @@ ASFLAGS += -mthumb -mcpu=cortex-a15
#
CFLAGS += -fshort-wchar
# EFI requires that enums are always 32 bits, and nothing else
# currently cares
#
CFLAGS += -fno-short-enums
# Include common ARM Makefile
MAKEDEPS += arch/arm/Makefile
include arch/arm/Makefile

View File

@ -1,8 +1,8 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# EFI uses the soft float ABI
# UEFI requires that enums are always 32 bits
#
CFLAGS += -mfloat-abi=soft
CFLAGS += -fno-short-enums
# Specify EFI image builder
#

View File

@ -1,6 +1,5 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", %progbits
.text
.arm

View File

@ -1,10 +1,10 @@
/*
* Copyright (C) 2023 Michael Brown <mbrown@fensystems.co.uk>.
* Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
* 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
@ -21,33 +21,20 @@
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* CPU sleeping test
*
* Architecture-specific DHCP options
*/
/* Forcibly enable assertions */
#undef NDEBUG
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/nap.h>
#include <ipxe/test.h>
#include <ipxe/dhcp.h>
/**
* Perform CPU sleeping self-test
*
*/
static void nap_test_exec ( void ) {
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM32
/* Check that we can sleep without crashing or halting forever */
cpu_nap();
ok ( 1 );
}
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
/** CPU sleeping self-test */
struct self_test nap_test __self_test = {
.name = "nap",
.exec = nap_test_exec,
};
#endif

View File

@ -1,20 +0,0 @@
#ifndef _IPXE_EFI_DHCPARCH_H
#define _IPXE_EFI_DHCPARCH_H
/** @file
*
* DHCP client architecture definitions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
/** DHCP client architecture */
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM32
/** DHCP client network device interface */
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif /* _IPXE_EFI_DHCPARCH_H */

View File

@ -1,6 +1,5 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", %progbits
.text
.thumb

View File

@ -1,6 +1,5 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL )
.section ".note.GNU-stack", "", %progbits
.text
.arm

View File

@ -1,10 +0,0 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Starting virtual address
#
LDFLAGS += -Ttext=0x400000
# Include generic Linux Makefile
#
MAKEDEPS += arch/arm/Makefile.linux
include arch/arm/Makefile.linux

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM64
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif

View File

@ -1,20 +0,0 @@
#ifndef _IPXE_EFI_DHCPARCH_H
#define _IPXE_EFI_DHCPARCH_H
/** @file
*
* DHCP client architecture definitions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
/** DHCP client architecture */
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_ARM64
/** DHCP client network device interface */
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif /* _IPXE_EFI_DHCPARCH_H */

View File

@ -1,8 +1,8 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Starting virtual address
# Linker script
#
LDFLAGS += -Ttext=0x08048000
LDSCRIPT = arch/i386/scripts/linux.lds
# Compiler flags for building host API wrapper
#

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2010 VMware, Inc. All Rights Reserved.
*
* 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.
*/
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_IA32
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif

View File

@ -1,20 +0,0 @@
#ifndef _IPXE_EFI_DHCPARCH_H
#define _IPXE_EFI_DHCPARCH_H
/** @file
*
* DHCP client architecture definitions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
/** DHCP client architecture */
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_IA32
/** DHCP client network device interface */
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif /* _IPXE_EFI_DHCPARCH_H */

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2010 VMware, Inc. All Rights Reserved.
*
* 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.
*/
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_X86
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 2, 1 /* v2.1 */
#endif

View File

@ -136,8 +136,6 @@ SECTIONS {
*(.note.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
/*

View File

@ -1,13 +1,18 @@
/* -*- sh -*- */
/*
* Linker script for Linux images
* Linker script for i386 Linux images
*
*/
OUTPUT_FORMAT ( "elf32-i386", "elf32-i386", "elf32-i386" )
OUTPUT_ARCH ( i386 )
SECTIONS {
_max_align = 32;
. = 0x08048000;
/*
* The text section
*
@ -81,18 +86,19 @@ SECTIONS {
_assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
/*
* Dispose of unwanted sections to make the link map easier to read
* Dispose of the comment and note sections to make the link map
* easier to read
*
*/
/DISCARD/ : {
*(.comment)
*(.comment.*)
*(.note)
*(.note.*)
*(.rel)
*(.rel.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
}

View File

@ -22,6 +22,9 @@ SRCDIRS += arch/x86/drivers/xen
SRCDIRS += arch/x86/drivers/hyperv
SRCDIRS += arch/x86/transitions
# breaks building some of the linux-related objects
CFLAGS += -Ulinux
# disable valgrind
CFLAGS += -DNVALGRIND

View File

@ -1,5 +1,9 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Include x86 Linux headers
#
INCDIRS += arch/x86/include/linux
# Include generic Linux Makefile
#
MAKEDEPS += Makefile.linux

View File

@ -45,7 +45,7 @@ void pcidirect_prepare ( struct pci_device *pci, int where ) {
PCIDIRECT_CONFIG_ADDRESS );
}
PROVIDE_PCIAPI_INLINE ( direct, pci_discover );
PROVIDE_PCIAPI_INLINE ( direct, pci_num_bus );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( direct, pci_read_config_dword );
@ -53,5 +53,3 @@ PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( direct, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( direct, pci_ioremap );
struct pci_api pcidirect_api = PCIAPI_RUNTIME ( direct );

View File

@ -252,17 +252,13 @@ static void bzimage_update_header ( struct image *image,
*/
static int bzimage_parse_cmdline ( struct image *image,
struct bzimage_context *bzimg,
char *cmdline ) {
char *sep;
const char *cmdline ) {
char *vga;
char *mem;
/* Look for "vga=" */
if ( ( vga = strstr ( cmdline, "vga=" ) ) ) {
vga += 4;
sep = strchr ( vga, ' ' );
if ( sep )
*sep = '\0';
if ( strcmp ( vga, "normal" ) == 0 ) {
bzimg->vid_mode = BZI_VID_MODE_NORMAL;
} else if ( strcmp ( vga, "ext" ) == 0 ) {
@ -271,13 +267,11 @@ static int bzimage_parse_cmdline ( struct image *image,
bzimg->vid_mode = BZI_VID_MODE_ASK;
} else {
bzimg->vid_mode = strtoul ( vga, &vga, 0 );
if ( *vga ) {
DBGC ( image, "bzImage %p strange \"vga=\" "
if ( *vga && ( *vga != ' ' ) ) {
DBGC ( image, "bzImage %p strange \"vga=\""
"terminator '%c'\n", image, *vga );
}
}
if ( sep )
*sep = ' ';
}
/* Look for "mem=" */
@ -528,7 +522,7 @@ static void bzimage_load_initrds ( struct image *image,
*/
static int bzimage_exec ( struct image *image ) {
struct bzimage_context bzimg;
char *cmdline = ( image->cmdline ? image->cmdline : "" );
const char *cmdline = ( image->cmdline ? image->cmdline : "" );
int rc;
/* Read and parse header from image */

View File

@ -6,11 +6,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define BDA_SEG 0x0040
#define BDA_EBDA 0x000e
#define BDA_EQUIPMENT_WORD 0x0010
#define BDA_KB0 0x0017
#define BDA_KB0_RSHIFT 0x01
#define BDA_KB0_LSHIFT 0x02
#define BDA_KB0_CTRL 0x04
#define BDA_KB0_CAPSLOCK 0x040
#define BDA_FBMS 0x0013
#define BDA_TICKS 0x006c
#define BDA_MIDNIGHT 0x0070
@ -18,7 +13,5 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define BDA_REBOOT_WARM 0x1234
#define BDA_NUM_DRIVES 0x0075
#define BDA_CHAR_HEIGHT 0x0085
#define BDA_KB2 0x0096
#define BDA_KB2_RALT 0x08
#endif /* BIOS_H */

View File

@ -11,6 +11,5 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h>
#include <ipxe/pcicloud.h>
#endif /* _BITS_PCI_IO_H */

View File

@ -1,20 +0,0 @@
#ifndef _IPXE_PCBIOS_DHCPARCH_H
#define _IPXE_PCBIOS_DHCPARCH_H
/** @file
*
* DHCP client architecture definitions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
/** DHCP client architecture */
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_X86
/** DHCP client network device interface */
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 2, 1 /* v2.1 */
#endif /* _IPXE_PCBIOS_DHCPARCH_H */

View File

@ -145,6 +145,4 @@ PCIAPI_INLINE ( pcbios, pci_ioremap ) ( struct pci_device *pci __unused,
return ioremap ( bus_addr, len );
}
extern struct pci_api pcibios_api;
#endif /* _IPXE_PCIBIOS_H */

View File

@ -1,18 +0,0 @@
#ifndef _IPXE_PCICLOUD_H
#define _IPXE_PCICLOUD_H
/** @file
*
* Cloud VM PCI configuration space access
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#ifdef PCIAPI_CLOUD
#define PCIAPI_PREFIX_cloud
#else
#define PCIAPI_PREFIX_cloud __cloud_
#endif
#endif /* _IPXE_PCICLOUD_H */

View File

@ -26,18 +26,14 @@ struct pci_device;
extern void pcidirect_prepare ( struct pci_device *pci, int where );
/**
* Find next PCI bus:dev.fn address range in system
* Determine number of PCI buses within system
*
* @v busdevfn Starting PCI bus:dev.fn address
* @v range PCI bus:dev.fn address range to fill in
* @ret num_bus Number of buses
*/
static inline __always_inline void
PCIAPI_INLINE ( direct, pci_discover ) ( uint32_t busdevfn __unused,
struct pci_range *range ) {
static inline __always_inline int
PCIAPI_INLINE ( direct, pci_num_bus ) ( void ) {
/* Scan first bus and rely on bridge detection to find higher buses */
range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
range->count = PCI_BUSDEVFN ( 0, 1, 0, 0 );
return 1;
}
/**
@ -155,6 +151,4 @@ PCIAPI_INLINE ( direct, pci_ioremap ) ( struct pci_device *pci __unused,
return ioremap ( bus_addr, len );
}
extern struct pci_api pcidirect_api;
#endif /* _PCIDIRECT_H */

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2010 Piotr Jaroszyński <p.jaroszynski@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (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.
*/
#ifndef _LINUX_DHCP_ARCH_H
#define _LINUX_DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL);
#include <ipxe/dhcp.h>
// Emulate one of the supported arch-platforms
#include <arch/i386/include/pcbios/ipxe/dhcp_arch.h>
//#include <arch/i386/include/efi/ipxe/dhcp_arch.h>
//#include <arch/x86_64/include/efi/ipxe/dhcp_arch.h>
#endif

View File

@ -107,7 +107,7 @@ static int acpi_timer_probe ( void ) {
unsigned int pm_tmr_blk;
/* Locate FADT */
fadt = acpi_table ( FADT_SIGNATURE, 0 );
fadt = acpi_find ( FADT_SIGNATURE, 0 );
if ( ! fadt ) {
DBGC ( &acpi_timer, "ACPI could not find FADT\n" );
return -ENOENT;

View File

@ -42,69 +42,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** _S5_ signature */
#define S5_SIGNATURE ACPI_SIGNATURE ( '_', 'S', '5', '_' )
/**
* Extract \_Sx value from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer
* @ret rc Return status code
*
* In theory, extracting the \_Sx value from the DSDT/SSDT requires a
* full ACPI parser plus some heuristics to work around the various
* broken encodings encountered in real ACPI implementations.
*
* In practice, we can get the same result by scanning through the
* DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
* four bytes, removing any bytes with bit 3 set, and treating
* whatever is left as a little-endian value. This is one of the
* uglier hacks I have ever implemented, but it's still prettier than
* the ACPI specification itself.
*/
static int acpi_extract_sx ( userptr_t zsdt, size_t len, size_t offset,
void *data ) {
unsigned int *sx = data;
uint8_t bytes[4];
uint8_t *byte;
/* Skip signature and package header */
offset += ( 4 /* signature */ + 3 /* package header */ );
/* Sanity check */
if ( ( offset + sizeof ( bytes ) /* value */ ) > len ) {
return -EINVAL;
}
/* Read first four bytes of value */
copy_from_user ( bytes, zsdt, offset, sizeof ( bytes ) );
DBGC ( colour, "ACPI found \\_Sx containing %02x:%02x:%02x:%02x\n",
bytes[0], bytes[1], bytes[2], bytes[3] );
/* Extract \Sx value. There are three potential encodings
* that we might encounter:
*
* - SLP_TYPa, SLP_TYPb, rsvd, rsvd
*
* - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
*
* - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
*
* Since <byteprefix> and <dwordprefix> both have bit 3 set,
* and valid SLP_TYPx must have bit 3 clear (since SLP_TYPx is
* a 3-bit field), we can just skip any bytes with bit 3 set.
*/
byte = bytes;
if ( *byte & 0x08 )
byte++;
*sx = *(byte++);
if ( *byte & 0x08 )
byte++;
*sx |= ( *byte << 8 );
return 0;
}
/**
* Power off the computer using ACPI
*
@ -119,11 +56,11 @@ int acpi_poweroff ( void ) {
unsigned int pm1b_cnt;
unsigned int slp_typa;
unsigned int slp_typb;
unsigned int s5;
int s5;
int rc;
/* Locate FADT */
fadt = acpi_table ( FADT_SIGNATURE, 0 );
fadt = acpi_find ( FADT_SIGNATURE, 0 );
if ( ! fadt ) {
DBGC ( colour, "ACPI could not find FADT\n" );
return -ENOENT;
@ -137,8 +74,9 @@ int acpi_poweroff ( void ) {
pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT );
/* Extract \_S5 from DSDT or any SSDT */
if ( ( rc = acpi_extract ( S5_SIGNATURE, &s5,
acpi_extract_sx ) ) != 0 ) {
s5 = acpi_sx ( S5_SIGNATURE );
if ( s5 < 0 ) {
rc = s5;
DBGC ( colour, "ACPI could not extract \\_S5: %s\n",
strerror ( rc ) );
return rc;

View File

@ -59,7 +59,7 @@ static void cachedhcp_init ( void ) {
}
/* Record cached DHCPACK */
if ( ( rc = cachedhcp_record ( &cached_dhcpack, 0,
if ( ( rc = cachedhcp_record ( &cached_dhcpack,
phys_to_user ( cached_dhcpack_phys ),
sizeof ( BOOTPLAYER_t ) ) ) != 0 ) {
DBGC ( colour, "CACHEDHCP could not record DHCPACK: %s\n",

View File

@ -60,21 +60,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ATTR_DEFAULT ATTR_FCOL_WHITE
/** Maximum keycode subject to remapping
*
* This allows us to avoid remapping the numeric keypad, which is
* necessary for keyboard layouts such as "fr" that swap the shifted
* and unshifted digit keys.
*/
#define SCANCODE_RSHIFT 0x36
/** Scancode for the "non-US \ and |" key
*
* This is the key that appears between Left Shift and Z on non-US
* keyboards.
*/
#define SCANCODE_NON_US 0x56
/* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
#undef CONSOLE_PCBIOS
@ -354,6 +339,22 @@ static const char * bios_ansi_seq ( unsigned int scancode ) {
return NULL;
}
/**
* Map a key
*
* @v character Character read from console
* @ret character Mapped character
*/
static int bios_keymap ( unsigned int character ) {
struct key_mapping *mapping;
for_each_table_entry ( mapping, KEYMAP ) {
if ( mapping->from == character )
return mapping->to;
}
return character;
}
/**
* Get character from BIOS console
*
@ -361,9 +362,6 @@ static const char * bios_ansi_seq ( unsigned int scancode ) {
*/
static int bios_getchar ( void ) {
uint16_t keypress;
uint8_t kb0;
uint8_t kb2;
unsigned int scancode;
unsigned int character;
const char *ansi_seq;
@ -385,42 +383,11 @@ static int bios_getchar ( void ) {
: "=a" ( keypress )
: "a" ( 0x1000 ), "m" ( bios_inject_lock ) );
bios_inject_lock--;
scancode = ( keypress >> 8 );
character = ( keypress & 0xff );
get_real ( kb0, BDA_SEG, BDA_KB0 );
get_real ( kb2, BDA_SEG, BDA_KB2 );
/* If it's a normal character, map (if applicable) and return it */
if ( character && ( character < 0x80 ) ) {
/* Handle special scancodes */
if ( scancode == SCANCODE_NON_US ) {
/* Treat as "\|" with high bit set */
character |= KEYMAP_PSEUDO;
} else if ( scancode >= SCANCODE_RSHIFT ) {
/* Non-remappable scancode (e.g. numeric keypad) */
return character;
}
/* Apply modifiers */
if ( kb0 & BDA_KB0_CTRL )
character |= KEYMAP_CTRL;
if ( kb0 & BDA_KB0_CAPSLOCK )
character |= KEYMAP_CAPSLOCK_REDO;
if ( kb2 & BDA_KB2_RALT )
character |= KEYMAP_ALTGR;
/* Treat LShift+RShift as AltGr since many BIOSes will
* not return ASCII characters when AltGr is pressed.
*/
if ( ( kb0 & ( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) ==
( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) {
character |= KEYMAP_ALTGR;
}
/* Map and return */
return key_remap ( character );
}
/* If it's a normal character, just map and return it */
if ( character && ( character < 0x80 ) )
return bios_keymap ( character );
/* Otherwise, check for a special key that we know about */
if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) {

View File

@ -34,15 +34,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
/**
* Find next PCI bus:dev.fn address range in system
* Determine number of PCI buses within system
*
* @v busdevfn Starting PCI bus:dev.fn address
* @v range PCI bus:dev.fn address range to fill in
* @ret num_bus Number of buses
*/
static void pcibios_discover ( uint32_t busdevfn __unused,
struct pci_range *range ) {
static int pcibios_num_bus ( void ) {
int discard_a, discard_D;
uint16_t num_bus;
uint8_t max_bus;
/* We issue this call using flat real mode, to work around a
* bug in some HP BIOSes.
@ -50,20 +48,16 @@ static void pcibios_discover ( uint32_t busdevfn __unused,
__asm__ __volatile__ ( REAL_CODE ( "call flatten_real_mode\n\t"
"stc\n\t"
"int $0x1a\n\t"
"movzbw %%cl, %%cx\n\t"
"incw %%cx\n\t"
"jnc 1f\n\t"
"xorw %%cx, %%cx\n\t"
"\n1:\n\t" )
: "=c" ( num_bus ), "=a" ( discard_a ),
: "=c" ( max_bus ), "=a" ( discard_a ),
"=D" ( discard_D )
: "a" ( PCIBIOS_INSTALLATION_CHECK >> 16 ),
"D" ( 0 )
: "ebx", "edx" );
/* Populate range */
range->start = PCI_BUSDEVFN ( 0, 0, 0, 0 );
range->count = PCI_BUSDEVFN ( 0, num_bus, 0, 0 );
return ( max_bus + 1 );
}
/**
@ -120,7 +114,7 @@ int pcibios_write ( struct pci_device *pci, uint32_t command, uint32_t value ){
return ( status >> 8 );
}
PROVIDE_PCIAPI ( pcbios, pci_discover, pcibios_discover );
PROVIDE_PCIAPI ( pcbios, pci_num_bus, pcibios_num_bus );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_read_config_dword );
@ -128,5 +122,3 @@ PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( pcbios, pci_ioremap );
struct pci_api pcibios_api = PCIAPI_RUNTIME ( pcbios );

View File

@ -1,191 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/init.h>
#include <ipxe/pci.h>
#include <ipxe/ecam.h>
#include <ipxe/pcibios.h>
#include <ipxe/pcidirect.h>
#include <ipxe/pcicloud.h>
/** @file
*
* Cloud VM PCI configuration space access
*
*/
/** Selected PCI configuration space access API */
static struct pci_api *pcicloud = &ecam_api;
/**
* Find next PCI bus:dev.fn address range in system
*
* @v busdevfn Starting PCI bus:dev.fn address
* @v range PCI bus:dev.fn address range to fill in
*/
static void pcicloud_discover ( uint32_t busdevfn, struct pci_range *range ) {
pcicloud->pci_discover ( busdevfn, range );
}
/**
* Read byte from PCI configuration space
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value read
* @ret rc Return status code
*/
static int pcicloud_read_config_byte ( struct pci_device *pci,
unsigned int where, uint8_t *value ) {
return pcicloud->pci_read_config_byte ( pci, where, value );
}
/**
* Read 16-bit word from PCI configuration space
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value read
* @ret rc Return status code
*/
static int pcicloud_read_config_word ( struct pci_device *pci,
unsigned int where, uint16_t *value ) {
return pcicloud->pci_read_config_word ( pci, where, value );
}
/**
* Read 32-bit dword from PCI configuration space
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value read
* @ret rc Return status code
*/
static int pcicloud_read_config_dword ( struct pci_device *pci,
unsigned int where, uint32_t *value ) {
return pcicloud->pci_read_config_dword ( pci, where, value );
}
/**
* Write byte to PCI configuration space
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value to be written
* @ret rc Return status code
*/
static int pcicloud_write_config_byte ( struct pci_device *pci,
unsigned int where, uint8_t value ) {
return pcicloud->pci_write_config_byte ( pci, where, value );
}
/**
* Write 16-bit word to PCI configuration space
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value to be written
* @ret rc Return status code
*/
static int pcicloud_write_config_word ( struct pci_device *pci,
unsigned int where, uint16_t value ) {
return pcicloud->pci_write_config_word ( pci, where, value );
}
/**
* Write 32-bit dword to PCI configuration space
*
* @v pci PCI device
* @v where Location within PCI configuration space
* @v value Value to be written
* @ret rc Return status code
*/
static int pcicloud_write_config_dword ( struct pci_device *pci,
unsigned int where, uint32_t value ) {
return pcicloud->pci_write_config_dword ( pci, where, value );
}
/**
* Map PCI bus address as an I/O address
*
* @v bus_addr PCI bus address
* @v len Length of region
* @ret io_addr I/O address, or NULL on error
*/
static void * pcicloud_ioremap ( struct pci_device *pci,
unsigned long bus_addr, size_t len ) {
return pcicloud->pci_ioremap ( pci, bus_addr, len );
}
PROVIDE_PCIAPI ( cloud, pci_discover, pcicloud_discover );
PROVIDE_PCIAPI ( cloud, pci_read_config_byte, pcicloud_read_config_byte );
PROVIDE_PCIAPI ( cloud, pci_read_config_word, pcicloud_read_config_word );
PROVIDE_PCIAPI ( cloud, pci_read_config_dword, pcicloud_read_config_dword );
PROVIDE_PCIAPI ( cloud, pci_write_config_byte, pcicloud_write_config_byte );
PROVIDE_PCIAPI ( cloud, pci_write_config_word, pcicloud_write_config_word );
PROVIDE_PCIAPI ( cloud, pci_write_config_dword, pcicloud_write_config_dword );
PROVIDE_PCIAPI ( cloud, pci_ioremap, pcicloud_ioremap );
/**
* Initialise cloud VM PCI configuration space access
*
*/
static void pcicloud_init ( void ) {
static struct pci_api *apis[] = {
&ecam_api, &pcibios_api, &pcidirect_api
};
struct pci_range range;
unsigned int i;
/* Select first API that successfully discovers an address range */
for ( i = 0 ; i < ( sizeof ( apis ) / sizeof ( apis[0] ) ) ; i++ ) {
pcicloud = apis[i];
pcicloud_discover ( 0, &range );
if ( range.count != 0 ) {
DBGC ( pcicloud, "PCICLOUD selected %s API\n",
pcicloud->name );
break;
}
}
/* The PCI direct API can never fail discovery since the range
* is hardcoded.
*/
assert ( range.count != 0 );
}
/** Cloud VM PCI configuration space access initialisation function */
struct init_fn pcicloud_init_fn __init_fn ( INIT_EARLY ) = {
.initialise = pcicloud_init,
};

View File

@ -78,15 +78,6 @@ struct console_driver bios_console __attribute__ (( weak ));
/** Font corresponding to selected character width and height */
#define VESAFB_FONT VBE_FONT_8x16
/** Number of ASCII glyphs within the font */
#define VESAFB_ASCII 128
/** Glyph to render for non-ASCII characters
*
* We choose to use one of the box-drawing glyphs.
*/
#define VESAFB_UNKNOWN 0xfe
/* Forward declaration */
struct console_driver vesafb_console __console_driver;
@ -139,24 +130,12 @@ static int vesafb_rc ( unsigned int status ) {
/**
* Get character glyph
*
* @v character Unicode character
* @v character Character
* @v glyph Character glyph to fill in
*/
static void vesafb_glyph ( unsigned int character, uint8_t *glyph ) {
unsigned int index;
size_t offset;
size_t offset = ( character * VESAFB_CHAR_HEIGHT );
/* Identify glyph */
if ( character < VESAFB_ASCII ) {
/* ASCII character: use corresponding glyph */
index = character;
} else {
/* Non-ASCII character: use "unknown" glyph */
index = VESAFB_UNKNOWN;
}
/* Copy glyph from BIOS font table */
offset = ( index * VESAFB_CHAR_HEIGHT );
copy_from_real ( glyph, vesafb.glyphs.segment,
( vesafb.glyphs.offset + offset ), VESAFB_CHAR_HEIGHT);
}

View File

@ -12,7 +12,6 @@
#include <ipxe/uaccess.h>
#include <ipxe/process.h>
#include <ipxe/netdevice.h>
#include <ipxe/malloc.h>
#include <realmode.h>
#include <pxe.h>
@ -483,28 +482,3 @@ struct pxe_api_call pxe_udp_api[] __pxe_api_call = {
PXE_API_CALL ( PXENV_UDP_READ, pxenv_udp_read,
struct s_PXENV_UDP_READ ),
};
/**
* Discard some cached PXE UDP data
*
* @ret discarded Number of cached items discarded
*/
static unsigned int pxe_udp_discard ( void ) {
struct io_buffer *iobuf;
unsigned int discarded = 0;
/* Try to discard the oldest received UDP packet */
iobuf = list_first_entry ( &pxe_udp.list, struct io_buffer, list );
if ( iobuf ) {
list_del ( &iobuf->list );
free_iob ( iobuf );
discarded++;
}
return discarded;
}
/** PXE UDP cache discarder */
struct cache_discarder pxe_udp_discarder __cache_discarder ( CACHE_NORMAL ) = {
.discard = pxe_udp_discard,
};

View File

@ -47,7 +47,7 @@ static char __bss16_array ( syslinux_version, [32] );
#define syslinux_version __use_data16 ( syslinux_version )
/** The "SYSLINUX" copyright string */
static char __data16_array ( syslinux_copyright, [] ) = " https://ipxe.org";
static char __data16_array ( syslinux_copyright, [] ) = " http://ipxe.org";
#define syslinux_copyright __use_data16 ( syslinux_copyright )
static char __data16_array ( syslinux_configuration_file, [] ) = "";

View File

@ -380,11 +380,6 @@ process_bytes:
pushl %eax
pushl %ebp
/* Construct ljmp code on stack (since .prefix may not be writable) */
.equ LJMP_LEN, 0x06
pushw %cs /* "nop ; ljmp %cs, $2f" */
pushw $2f
pushw $0xea90
/* Construct GDT on stack (since .prefix may not be writable) */
.equ GDT_LEN, 0x20
.equ PM_DS, 0x18 /* Flat data segment */
@ -415,9 +410,8 @@ process_bytes:
pushw %es
pushw %ds
pushw %ss
pushw %ss /* Far pointer to ljmp code on stack */
leaw (GDT_LEN + 1)(%bp), %ax
pushw %ax
pushw %cs
pushw $2f
cli
data32 lgdt (%bp)
movl %cr0, %eax
@ -444,7 +438,7 @@ process_bytes:
popfw
movl %eax, %cr0
lret
2: /* lret will ljmp to here (via constructed ljmp on stack) */
2: /* lret will ljmp to here */
popw %ss
popw %ds
popw %es
@ -467,7 +461,7 @@ process_bytes:
/* Restore GDT */
data32 lgdt -8(%bp)
leaw (GDT_LEN + LJMP_LEN)(%bp), %sp
leaw GDT_LEN(%bp), %sp
/* Restore registers and return */
popl %ebp

View File

@ -161,7 +161,7 @@ pnpheader:
/* Manufacturer string */
mfgstr:
.asciz "https://ipxe.org"
.asciz "http://ipxe.org"
.size mfgstr, . - mfgstr
/* Product string
@ -607,7 +607,7 @@ get_pmm_decompress_to:
* strings PRODUCT_NAME and PRODUCT_SHORT_NAME in config/branding.h.
*
* While nothing in the GPL prevents you from removing all references
* to iPXE or https://ipxe.org, we prefer you not to do so.
* to iPXE or http://ipxe.org, we prefer you not to do so.
*
* If you have an OEM-mandated branding requirement that cannot be
* satisfied simply by defining PRODUCT_NAME and PRODUCT_SHORT_NAME,

View File

@ -229,8 +229,6 @@ SECTIONS {
*(.einfo.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
/*

View File

@ -24,8 +24,6 @@ SECTIONS {
*(.einfo.*)
*(.discard)
*(.discard.*)
*(.sbat)
*(.sbat.*)
}
}

View File

@ -1,8 +1,8 @@
# -*- makefile -*- : Force emacs to use Makefile mode
# Starting virtual address
# Linker script
#
LDFLAGS += -Ttext=0x400000
LDSCRIPT = arch/x86_64/scripts/linux.lds
# Include generic Linux Makefile
#

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2010 VMware, Inc. All Rights Reserved.
*
* 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.
*/
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_X86_64
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif

View File

@ -1,20 +0,0 @@
#ifndef _IPXE_EFI_DHCPARCH_H
#define _IPXE_EFI_DHCPARCH_H
/** @file
*
* DHCP client architecture definitions
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
/** DHCP client architecture */
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_X86_64
/** DHCP client network device interface */
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */
#endif /* _IPXE_EFI_DHCPARCH_H */

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2010 VMware, Inc. All Rights Reserved.
*
* 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.
*/
#ifndef _DHCP_ARCH_H
#define _DHCP_ARCH_H
/** @file
*
* Architecture-specific DHCP options
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcp.h>
#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_X86
#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 2, 1 /* v2.1 */
#endif

View File

@ -0,0 +1,104 @@
/* -*- sh -*- */
/*
* Linker script for x86_64 Linux images
*
*/
OUTPUT_FORMAT ( "elf64-x86-64", "elf64-x86-64", "elf64-x86-64" )
OUTPUT_ARCH ( i386:x86-64 )
SECTIONS {
_max_align = 32;
. = 0x400000;
/*
* The text section
*
*/
. = ALIGN ( _max_align );
.text : {
_text = .;
*(.text)
*(.text.*)
_etext = .;
}
/*
* The rodata section
*
*/
. = ALIGN ( _max_align );
.rodata : {
_rodata = .;
*(.rodata)
*(.rodata.*)
_erodata = .;
}
/*
* The data section
*
* Adjust the address for the data segment. We want to adjust up to
* the same address within the page on the next page up.
*/
. = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1));
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
.data : {
_data = .;
*(.data)
*(.data.*)
KEEP(*(SORT(.tbl.*)))
KEEP(*(.provided))
KEEP(*(.provided.*))
_edata = .;
}
/*
* The bss section
*
*/
. = ALIGN ( _max_align );
.bss : {
_bss = .;
*(.bss)
*(.bss.*)
*(COMMON)
_ebss = .;
}
/*
* Weak symbols that need zero values if not otherwise defined
*
*/
.weak 0x0 : {
_weak = .;
*(.weak)
*(.weak.*)
_eweak = .;
}
_assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" );
/*
* Dispose of the comment and note sections to make the link map
* easier to read
*
*/
/DISCARD/ : {
*(.comment)
*(.comment.*)
*(.note)
*(.note.*)
*(.rel)
*(.rel.*)
*(.discard)
*(.discard.*)
}
}

View File

@ -26,7 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#define PRODUCT_NAME ""
#define PRODUCT_SHORT_NAME "iPXE"
#define PRODUCT_URI "https://ipxe.org"
#define PRODUCT_URI "http://ipxe.org"
/*
* Tag line
@ -44,15 +44,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* (e.g. "Permission denied") and a 32-bit error number. This number
* is incorporated into an error URI such as
*
* "No such file or directory (https://ipxe.org/2d0c613b)"
* "No such file or directory (http://ipxe.org/2d0c613b)"
*
* or
*
* "Operation not supported (https://ipxe.org/3c092003)"
* "Operation not supported (http://ipxe.org/3c092003)"
*
* Users may browse to the URI within the error message, which is
* provided by a database running on the iPXE web site
* (https://ipxe.org). This database provides details for all possible
* (http://ipxe.org). This database provides details for all possible
* errors generated by iPXE, including:
*
* - the detailed error message (e.g. "Not an OCSP signing
@ -74,13 +74,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* If you have a customer support team and would like your customers
* to contact your support team for all problems, instead of using the
* existing support infrastructure provided by https://ipxe.org, then
* existing support infrastructure provided by http://ipxe.org, then
* you may define a custom URI to be included within error messages.
*
* Note that the custom URI is a printf() format string which must
* include a format specifier for the 32-bit error number.
*/
#define PRODUCT_ERROR_URI "https://ipxe.org/%08x"
#define PRODUCT_ERROR_URI "http://ipxe.org/%08x"
/*
* Command help messages
@ -88,7 +88,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE command help messages include a URI constructed from the
* command name, such as
*
* "See https://ipxe.org/cmd/vcreate for further information"
* "See http://ipxe.org/cmd/vcreate for further information"
*
* The iPXE web site includes documentation for the commands provided
* by the iPXE shell, including:
@ -113,7 +113,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* If you want to provide your own documentation for all of the
* commands provided by the iPXE shell, rather than using the existing
* support infrastructure provided by https://ipxe.org, then you may
* support infrastructure provided by http://ipxe.org, then you may
* define a custom URI to be included within command help messages.
*
* Note that the custom URI is a printf() format string which must
@ -124,7 +124,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE project and prohibit the alteration or removal of any
* references to "iPXE". ]
*/
#define PRODUCT_COMMAND_URI "https://ipxe.org/cmd/%s"
#define PRODUCT_COMMAND_URI "http://ipxe.org/cmd/%s"
/*
* Setting help messages
@ -132,7 +132,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE setting help messages include a URI constructed from the
* setting name, such as
*
* "https://ipxe.org/cfg/initiator-iqn"
* "http://ipxe.org/cfg/initiator-iqn"
*
* The iPXE web site includes documentation for the settings used by
* iPXE, including:
@ -156,7 +156,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
* If you want to provide your own documentation for all of the
* settings used by iPXE, rather than using the existing support
* infrastructure provided by https://ipxe.org, then you may define a
* infrastructure provided by http://ipxe.org, then you may define a
* custom URI to be included within setting help messages.
*
* Note that the custom URI is a printf() format string which must
@ -167,25 +167,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* iPXE project and prohibit the alteration or removal of any
* references to "iPXE". ]
*/
#define PRODUCT_SETTING_URI "https://ipxe.org/cfg/%s"
/*
* Product security name suffix
*
* Vendors creating signed iPXE binaries must set this to a non-empty
* value (e.g. "2pint").
*/
#define PRODUCT_SBAT_NAME ""
/*
* Product security generation
*
* Vendors creating signed iPXE binaries must set this to a non-zero
* value, and must increment the value whenever a Secure Boot exploit
* is fixed (unless the upstream IPXE_SBAT_GENERATION has already been
* incremented as part of that fix).
*/
#define PRODUCT_SBAT_GENERATION 0
#define PRODUCT_SETTING_URI "http://ipxe.org/cfg/%s"
#include <config/local/branding.h>

View File

@ -3,5 +3,5 @@
*/
#ifdef PLATFORM_pcbios
#undef PCIAPI_PCBIOS
#define PCIAPI_CLOUD
#define PCIAPI_DIRECT
#endif

View File

@ -124,15 +124,3 @@ REQUIRE_OBJECT ( rsa_aes_cbc_sha1 );
defined ( CRYPTO_DIGEST_SHA256 )
REQUIRE_OBJECT ( rsa_aes_cbc_sha256 );
#endif
/* RSA, AES-GCM, and SHA-256 */
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \
defined ( CRYPTO_DIGEST_SHA256 )
REQUIRE_OBJECT ( rsa_aes_gcm_sha256 );
#endif
/* RSA, AES-GCM, and SHA-384 */
#if defined ( CRYPTO_PUBKEY_RSA ) && defined ( CRYPTO_CIPHER_AES_GCM ) && \
defined ( CRYPTO_DIGEST_SHA384 )
REQUIRE_OBJECT ( rsa_aes_gcm_sha384 );
#endif

View File

@ -18,9 +18,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** AES-CBC block cipher */
#define CRYPTO_CIPHER_AES_CBC
/** AES-GCM block cipher */
#define CRYPTO_CIPHER_AES_GCM
/** MD4 digest algorithm */
//#define CRYPTO_DIGEST_MD4

View File

@ -58,8 +58,4 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define NAP_EFIARM
#endif
#if defined ( __aarch64__ )
#define IMAGE_GZIP /* GZIP image support */
#endif
#endif /* CONFIG_DEFAULTS_EFI_H */

View File

@ -38,12 +38,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Colour for debug messages */
#define colour FADT_SIGNATURE
/** ACPI table finder
*
* May be overridden at link time to inject tables for testing.
*/
typeof ( acpi_find ) *acpi_finder __attribute__ (( weak )) = acpi_find;
/******************************************************************************
*
* Utility functions
@ -88,18 +82,6 @@ void acpi_fix_checksum ( struct acpi_header *acpi ) {
acpi->checksum -= acpi_checksum ( virt_to_user ( acpi ) );
}
/**
* Locate ACPI table
*
* @v signature Requested table signature
* @v index Requested index of table with this signature
* @ret table Table, or UNULL if not found
*/
userptr_t acpi_table ( uint32_t signature, unsigned int index ) {
return ( *acpi_finder ) ( signature, index );
}
/**
* Locate ACPI table via RSDT
*
@ -187,22 +169,33 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) {
}
/**
* Extract value from DSDT/SSDT
* Extract \_Sx value from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v signature Signature (e.g. "_S5_")
* @v data Data buffer
* @v extract Extraction method
* @ret rc Return status code
* @ret sx \_Sx value, or negative error
*
* In theory, extracting the \_Sx value from the DSDT/SSDT requires a
* full ACPI parser plus some heuristics to work around the various
* broken encodings encountered in real ACPI implementations.
*
* In practice, we can get the same result by scanning through the
* DSDT/SSDT for the signature (e.g. "_S5_"), extracting the first
* four bytes, removing any bytes with bit 3 set, and treating
* whatever is left as a little-endian value. This is one of the
* uglier hacks I have ever implemented, but it's still prettier than
* the ACPI specification itself.
*/
static int acpi_zsdt ( userptr_t zsdt, uint32_t signature, void *data,
int ( * extract ) ( userptr_t zsdt, size_t len,
size_t offset, void *data ) ) {
static int acpi_sx_zsdt ( userptr_t zsdt, uint32_t signature ) {
struct acpi_header acpi;
uint32_t buf;
union {
uint32_t dword;
uint8_t byte[4];
} buf;
size_t offset;
size_t len;
int rc;
unsigned int sx;
uint8_t *byte;
/* Read table header */
copy_from_user ( &acpi, zsdt, 0, sizeof ( acpi ) );
@ -210,64 +203,87 @@ static int acpi_zsdt ( userptr_t zsdt, uint32_t signature, void *data,
/* Locate signature */
for ( offset = sizeof ( acpi ) ;
( ( offset + sizeof ( buf ) /* signature */ ) < len ) ;
( ( offset + sizeof ( buf ) /* signature */ + 3 /* pkg header */
+ sizeof ( buf ) /* value */ ) < len ) ;
offset++ ) {
/* Check signature */
copy_from_user ( &buf, zsdt, offset, sizeof ( buf ) );
if ( buf != cpu_to_le32 ( signature ) )
if ( buf.dword != cpu_to_le32 ( signature ) )
continue;
DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n",
user_to_phys ( zsdt, 0 ), acpi_name ( signature ),
offset );
offset += sizeof ( buf );
/* Attempt to extract data */
if ( ( rc = extract ( zsdt, len, offset, data ) ) == 0 )
return 0;
/* Read first four bytes of value */
copy_from_user ( &buf, zsdt, ( offset + 3 /* pkg header */ ),
sizeof ( buf ) );
DBGC ( zsdt, "DSDT/SSDT %#08lx found %s containing "
"%02x:%02x:%02x:%02x\n", user_to_phys ( zsdt, 0 ),
acpi_name ( signature ), buf.byte[0], buf.byte[1],
buf.byte[2], buf.byte[3] );
/* Extract \Sx value. There are three potential
* encodings that we might encounter:
*
* - SLP_TYPa, SLP_TYPb, rsvd, rsvd
*
* - <byteprefix>, SLP_TYPa, <byteprefix>, SLP_TYPb, ...
*
* - <dwordprefix>, SLP_TYPa, SLP_TYPb, 0, 0
*
* Since <byteprefix> and <dwordprefix> both have bit
* 3 set, and valid SLP_TYPx must have bit 3 clear
* (since SLP_TYPx is a 3-bit field), we can just skip
* any bytes with bit 3 set.
*/
byte = &buf.byte[0];
if ( *byte & 0x08 )
byte++;
sx = *(byte++);
if ( *byte & 0x08 )
byte++;
sx |= ( *byte << 8 );
return sx;
}
return -ENOENT;
}
/**
* Extract value from DSDT/SSDT
* Extract \_Sx value from DSDT/SSDT
*
* @v signature Signature (e.g. "_S5_")
* @v data Data buffer
* @v extract Extraction method
* @ret rc Return status code
* @ret sx \_Sx value, or negative error
*/
int acpi_extract ( uint32_t signature, void *data,
int ( * extract ) ( userptr_t zsdt, size_t len,
size_t offset, void *data ) ) {
int acpi_sx ( uint32_t signature ) {
struct acpi_fadt fadtab;
userptr_t fadt;
userptr_t dsdt;
userptr_t ssdt;
unsigned int i;
int rc;
int sx;
/* Try DSDT first */
fadt = acpi_table ( FADT_SIGNATURE, 0 );
fadt = acpi_find ( FADT_SIGNATURE, 0 );
if ( fadt ) {
copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) );
dsdt = phys_to_user ( fadtab.dsdt );
if ( ( rc = acpi_zsdt ( dsdt, signature, data,
extract ) ) == 0 )
return 0;
if ( ( sx = acpi_sx_zsdt ( dsdt, signature ) ) >= 0 )
return sx;
}
/* Try all SSDTs */
for ( i = 0 ; ; i++ ) {
ssdt = acpi_table ( SSDT_SIGNATURE, i );
ssdt = acpi_find ( SSDT_SIGNATURE, i );
if ( ! ssdt )
break;
if ( ( rc = acpi_zsdt ( ssdt, signature, data,
extract ) ) == 0 )
return 0;
if ( ( sx = acpi_sx_zsdt ( ssdt, signature ) ) >= 0 )
return sx;
}
DBGC ( colour, "ACPI could not find \"%s\"\n",
DBGC ( colour, "ACPI could not find \\_Sx \"%s\"\n",
acpi_name ( signature ) );
return -ENOENT;
}

View File

@ -88,7 +88,7 @@ static int acpi_settings_fetch ( struct settings *settings,
acpi_name ( tag_signature ), tag_index, tag_offset, tag_len );
/* Locate ACPI table */
table = acpi_table ( tag_signature, tag_index );
table = acpi_find ( tag_signature, tag_index );
if ( ! table )
return -ENOENT;

View File

@ -1,288 +0,0 @@
/*
* Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <errno.h>
#include <ipxe/acpi.h>
#include <ipxe/base16.h>
#include <ipxe/ethernet.h>
#include <ipxe/if_ether.h>
#include <ipxe/settings.h>
#include <ipxe/acpimac.h>
/** @file
*
* ACPI MAC address
*
*/
/** Colour for debug messages */
#define colour FADT_SIGNATURE
/** AMAC signature */
#define AMAC_SIGNATURE ACPI_SIGNATURE ( 'A', 'M', 'A', 'C' )
/** MACA signature */
#define MACA_SIGNATURE ACPI_SIGNATURE ( 'M', 'A', 'C', 'A' )
/** RTMA signature */
#define RTMA_SIGNATURE ACPI_SIGNATURE ( 'R', 'T', 'M', 'A' )
/** Maximum number of bytes to skip after ACPI signature
*
* This is entirely empirical.
*/
#define ACPIMAC_MAX_SKIP 8
/** An ACPI MAC extraction mechanism */
struct acpimac_extractor {
/** Prefix string */
const char *prefix;
/** Encoded MAC length */
size_t len;
/** Decode MAC
*
* @v mac Encoded MAC
* @v hw_addr MAC address to fill in
* @ret rc Return status code
*/
int ( * decode ) ( const char *mac, uint8_t *hw_addr );
};
/**
* Decode Base16-encoded MAC address
*
* @v mac Encoded MAC
* @v hw_addr MAC address to fill in
* @ret rc Return status code
*/
static int acpimac_decode_base16 ( const char *mac, uint8_t *hw_addr ) {
int len;
int rc;
/* Attempt to base16-decode MAC address */
len = base16_decode ( mac, hw_addr, ETH_ALEN );
if ( len < 0 ) {
rc = len;
DBGC ( colour, "ACPI could not decode base16 MAC \"%s\": %s\n",
mac, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Decode raw MAC address
*
* @v mac Encoded MAC
* @v hw_addr MAC address to fill in
* @ret rc Return status code
*/
static int acpimac_decode_raw ( const char *mac, uint8_t *hw_addr ) {
memcpy ( hw_addr, mac, ETH_ALEN );
return 0;
}
/** "_AUXMAC_" extraction mechanism */
static struct acpimac_extractor acpimac_auxmac = {
.prefix = "_AUXMAC_#",
.len = ( ETH_ALEN * 2 ),
.decode = acpimac_decode_base16,
};
/** "_RTXMAC_" extraction mechanism */
static struct acpimac_extractor acpimac_rtxmac = {
.prefix = "_RTXMAC_#",
.len = ETH_ALEN,
.decode = acpimac_decode_raw,
};
/**
* Extract MAC address from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer
* @v extractor ACPI MAC address extractor
* @ret rc Return status code
*
* Some vendors provide a "system MAC address" within the DSDT/SSDT,
* to be used to override the MAC address for a USB docking station.
*
* A full implementation would require an ACPI bytecode interpreter,
* since at least one OEM allows the MAC address to be constructed by
* executable ACPI bytecode (rather than a fixed data structure).
*
* We instead attempt to extract a plausible-looking "_AUXMAC_#.....#"
* string that appears shortly after an "AMAC" or "MACA" signature.
* This should work for most implementations encountered in practice.
*/
static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset,
void *data, struct acpimac_extractor *extractor ){
size_t prefix_len = strlen ( extractor->prefix );
uint8_t *hw_addr = data;
size_t skip = 0;
char buf[ prefix_len + extractor->len + 1 /* "#" */ + 1 /* NUL */ ];
char *mac = &buf[prefix_len];
int rc;
/* Skip signature and at least one tag byte */
offset += ( 4 /* signature */ + 1 /* tag byte */ );
/* Scan for suitable string close to signature */
for ( skip = 0 ;
( ( skip < ACPIMAC_MAX_SKIP ) &&
( offset + skip + sizeof ( buf ) ) <= len ) ;
skip++ ) {
/* Read value */
copy_from_user ( buf, zsdt, ( offset + skip ),
sizeof ( buf ) );
/* Check for expected format */
if ( memcmp ( buf, extractor->prefix, prefix_len ) != 0 )
continue;
if ( buf[ sizeof ( buf ) - 2 ] != '#' )
continue;
if ( buf[ sizeof ( buf ) - 1 ] != '\0' )
continue;
DBGC ( colour, "ACPI found MAC:\n" );
DBGC_HDA ( colour, ( offset + skip ), buf, sizeof ( buf ) );
/* Terminate MAC address string */
mac[extractor->len] = '\0';
/* Decode MAC address */
if ( ( rc = extractor->decode ( mac, hw_addr ) ) != 0 )
return rc;
/* Check MAC address validity */
if ( ! is_valid_ether_addr ( hw_addr ) ) {
DBGC ( colour, "ACPI has invalid MAC %s\n",
eth_ntoa ( hw_addr ) );
return -EINVAL;
}
return 0;
}
return -ENOENT;
}
/**
* Extract "_AUXMAC_" MAC address from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer
* @ret rc Return status code
*/
static int acpimac_extract_auxmac ( userptr_t zsdt, size_t len, size_t offset,
void *data ) {
return acpimac_extract ( zsdt, len, offset, data, &acpimac_auxmac );
}
/**
* Extract "_RTXMAC_" MAC address from DSDT/SSDT
*
* @v zsdt DSDT or SSDT
* @v len Length of DSDT/SSDT
* @v offset Offset of signature within DSDT/SSDT
* @v data Data buffer
* @ret rc Return status code
*/
static int acpimac_extract_rtxmac ( userptr_t zsdt, size_t len, size_t offset,
void *data ) {
return acpimac_extract ( zsdt, len, offset, data, &acpimac_rtxmac );
}
/**
* Extract MAC address from DSDT/SSDT
*
* @v hw_addr MAC address to fill in
* @ret rc Return status code
*/
int acpi_mac ( uint8_t *hw_addr ) {
int rc;
/* Look for an "AMAC" address */
if ( ( rc = acpi_extract ( AMAC_SIGNATURE, hw_addr,
acpimac_extract_auxmac ) ) == 0 )
return 0;
/* Look for a "MACA" address */
if ( ( rc = acpi_extract ( MACA_SIGNATURE, hw_addr,
acpimac_extract_auxmac ) ) == 0 )
return 0;
/* Look for a "RTMA" address */
if ( ( rc = acpi_extract ( RTMA_SIGNATURE, hw_addr,
acpimac_extract_rtxmac ) ) == 0 )
return 0;
return -ENOENT;
}
/**
* Fetch system MAC address setting
*
* @v data Buffer to fill with setting data
* @v len Length of buffer
* @ret len Length of setting data, or negative error
*/
static int sysmac_fetch ( void *data, size_t len ) {
uint8_t mac[ETH_ALEN];
int rc;
/* Try fetching ACPI MAC address */
if ( ( rc = acpi_mac ( mac ) ) != 0 )
return rc;
/* Return MAC address */
if ( len > sizeof ( mac ) )
len = sizeof ( mac );
memcpy ( data, mac, len );
return ( sizeof ( mac ) );
}
/** System MAC address setting */
const struct setting sysmac_setting __setting ( SETTING_MISC, sysmac ) = {
.name = "sysmac",
.description = "System MAC",
.type = &setting_type_hex,
.scope = &builtin_scope,
};
/** System MAC address built-in setting */
struct builtin_setting sysmac_builtin_setting __builtin_setting = {
.setting = &sysmac_setting,
.fetch = sysmac_fetch,
};

View File

@ -29,7 +29,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/dhcppkt.h>
#include <ipxe/init.h>
#include <ipxe/netdevice.h>
#include <ipxe/vlan.h>
#include <ipxe/cachedhcp.h>
/** @file
@ -44,8 +43,6 @@ struct cached_dhcp_packet {
const char *name;
/** DHCP packet (if any) */
struct dhcp_packet *dhcppkt;
/** VLAN tag (if applicable) */
unsigned int vlan;
};
/** Cached DHCPACK */
@ -93,74 +90,30 @@ static void cachedhcp_free ( struct cached_dhcp_packet *cache ) {
*/
static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
struct net_device *netdev ) {
struct settings *settings = NULL;
struct ll_protocol *ll_protocol;
const uint8_t *chaddr;
uint8_t *hw_addr;
uint8_t *ll_addr;
size_t ll_addr_len;
struct settings *settings;
int rc;
/* Do nothing if cache is empty */
if ( ! cache->dhcppkt )
return 0;
chaddr = cache->dhcppkt->dhcphdr->chaddr;
/* Handle association with network device, if specified */
/* Do nothing unless cached packet's MAC address matches this
* network device, if specified.
*/
if ( netdev ) {
hw_addr = netdev->hw_addr;
ll_addr = netdev->ll_addr;
ll_protocol = netdev->ll_protocol;
ll_addr_len = ll_protocol->ll_addr_len;
/* If cached packet's MAC address matches the network
* device's permanent MAC address, then assume that
* the permanent MAC address ought to be the network
* device's current link-layer address.
*
* This situation can arise when the PXE ROM does not
* understand the system-specific mechanism for
* overriding the MAC address, and so uses the
* permanent MAC address instead. We choose to match
* this behaviour in order to minimise surprise.
*/
if ( memcmp ( hw_addr, chaddr, ll_addr_len ) == 0 ) {
if ( memcmp ( hw_addr, ll_addr, ll_addr_len ) != 0 ) {
DBGC ( colour, "CACHEDHCP %s resetting %s MAC "
"%s ", cache->name, netdev->name,
ll_protocol->ntoa ( ll_addr ) );
DBGC ( colour, "-> %s\n",
ll_protocol->ntoa ( hw_addr ) );
}
memcpy ( ll_addr, hw_addr, ll_addr_len );
}
/* Do nothing unless cached packet's MAC address
* matches this network device.
*/
if ( memcmp ( ll_addr, chaddr, ll_addr_len ) != 0 ) {
DBGC ( colour, "CACHEDHCP %s %s does not match %s\n",
cache->name, ll_protocol->ntoa ( chaddr ),
netdev->name );
if ( memcmp ( netdev->ll_addr, cache->dhcppkt->dhcphdr->chaddr,
netdev->ll_protocol->ll_addr_len ) != 0 ) {
DBGC ( colour, "CACHEDHCP %s does not match %s\n",
cache->name, netdev->name );
return 0;
}
/* Do nothing unless cached packet's VLAN tag matches
* this network device.
*/
if ( vlan_tag ( netdev ) != cache->vlan ) {
DBGC ( colour, "CACHEDHCP %s VLAN %d does not match "
"%s\n", cache->name, cache->vlan,
netdev->name );
return 0;
}
/* Use network device's settings block */
settings = netdev_settings ( netdev );
DBGC ( colour, "CACHEDHCP %s is for %s\n",
cache->name, netdev->name );
}
/* Select appropriate parent settings block */
settings = ( netdev ? netdev_settings ( netdev ) : NULL );
/* Register settings */
if ( ( rc = register_settings ( &cache->dhcppkt->settings, settings,
cache->name ) ) != 0 ) {
@ -179,13 +132,12 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache,
* Record cached DHCP packet
*
* @v cache Cached DHCP packet
* @v vlan VLAN tag, if any
* @v data DHCPACK packet buffer
* @v max_len Maximum possible length
* @ret rc Return status code
*/
int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan,
userptr_t data, size_t max_len ) {
int cachedhcp_record ( struct cached_dhcp_packet *cache, userptr_t data,
size_t max_len ) {
struct dhcp_packet *dhcppkt;
struct dhcp_packet *tmp;
struct dhcphdr *dhcphdr;
@ -240,55 +192,36 @@ int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan,
DBGC ( colour, "CACHEDHCP %s at %#08lx+%#zx/%#zx\n", cache->name,
user_to_phys ( data, 0 ), len, max_len );
cache->dhcppkt = dhcppkt;
cache->vlan = vlan;
return 0;
}
/**
* Cached DHCP packet startup function
* Cached DHCPACK startup function
*
*/
static void cachedhcp_startup ( void ) {
/* Apply cached ProxyDHCPOFFER, if any */
cachedhcp_apply ( &cached_proxydhcp, NULL );
cachedhcp_free ( &cached_proxydhcp );
/* Apply cached PXEBSACK, if any */
cachedhcp_apply ( &cached_pxebs, NULL );
cachedhcp_free ( &cached_pxebs );
/* Report unclaimed DHCPACK, if any. Do not free yet, since
* it may still be claimed by a dynamically created device
* such as a VLAN device.
*/
/* Free any remaining cached packets */
if ( cached_dhcpack.dhcppkt ) {
DBGC ( colour, "CACHEDHCP %s unclaimed\n",
cached_dhcpack.name );
}
}
/**
* Cached DHCP packet shutdown function
*
* @v booting System is shutting down for OS boot
*/
static void cachedhcp_shutdown ( int booting __unused ) {
/* Free cached DHCPACK, if any */
if ( cached_dhcpack.dhcppkt ) {
DBGC ( colour, "CACHEDHCP %s never claimed\n",
cached_dhcpack.name );
}
cachedhcp_free ( &cached_dhcpack );
cachedhcp_free ( &cached_proxydhcp );
cachedhcp_free ( &cached_pxebs );
}
/** Cached DHCPACK startup function */
struct startup_fn cachedhcp_startup_fn __startup_fn ( STARTUP_LATE ) = {
.name = "cachedhcp",
.startup = cachedhcp_startup,
.shutdown = cachedhcp_shutdown,
};
/**

View File

@ -1,131 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Dynamic keyboard mappings
*
*/
#include <stdlib.h>
#include <errno.h>
#include <ipxe/settings.h>
#include <ipxe/keymap.h>
/**
* Require a keyboard map
*
* @v name Keyboard map name
*/
#define REQUIRE_KEYMAP( name ) REQUIRE_OBJECT ( keymap_ ## name )
/** Keyboard map setting */
const struct setting keymap_setting __setting ( SETTING_MISC, keymap ) = {
.name = "keymap",
.description = "Keyboard map",
.type = &setting_type_string,
};
/**
* Apply keyboard map settings
*
* @ret rc Return status code
*/
static int keymap_apply ( void ) {
struct keymap *keymap;
char *name;
int rc;
/* Fetch keyboard map name */
fetch_string_setting_copy ( NULL, &keymap_setting, &name );
/* Identify keyboard map */
if ( name ) {
/* Identify named keyboard map */
keymap = keymap_find ( name );
if ( ! keymap ) {
DBGC ( &keymap_setting, "KEYMAP could not identify "
"\"%s\"\n", name );
rc = -ENOENT;
goto err_unknown;
}
} else {
/* Use default keyboard map */
keymap = NULL;
}
/* Set keyboard map */
keymap_set ( keymap );
/* Success */
rc = 0;
err_unknown:
free ( name );
return rc;
}
/** Keyboard map setting applicator */
struct settings_applicator keymap_applicator __settings_applicator = {
.apply = keymap_apply,
};
/* Provide virtual "dynamic" keyboard map for linker */
PROVIDE_SYMBOL ( obj_keymap_dynamic );
/* Drag in keyboard maps via keymap_setting */
REQUIRING_SYMBOL ( keymap_setting );
/* Require all known keyboard maps */
REQUIRE_KEYMAP ( al );
REQUIRE_KEYMAP ( by );
REQUIRE_KEYMAP ( cf );
REQUIRE_KEYMAP ( cz );
REQUIRE_KEYMAP ( de );
REQUIRE_KEYMAP ( dk );
REQUIRE_KEYMAP ( es );
REQUIRE_KEYMAP ( et );
REQUIRE_KEYMAP ( fi );
REQUIRE_KEYMAP ( fr );
REQUIRE_KEYMAP ( gr );
REQUIRE_KEYMAP ( hu );
REQUIRE_KEYMAP ( il );
REQUIRE_KEYMAP ( it );
REQUIRE_KEYMAP ( lt );
REQUIRE_KEYMAP ( mk );
REQUIRE_KEYMAP ( mt );
REQUIRE_KEYMAP ( nl );
REQUIRE_KEYMAP ( no );
REQUIRE_KEYMAP ( no_latin1 );
REQUIRE_KEYMAP ( pl );
REQUIRE_KEYMAP ( pt );
REQUIRE_KEYMAP ( ro );
REQUIRE_KEYMAP ( ru );
REQUIRE_KEYMAP ( se );
REQUIRE_KEYMAP ( sg );
REQUIRE_KEYMAP ( sr_latin );
REQUIRE_KEYMAP ( ua );
REQUIRE_KEYMAP ( uk );
REQUIRE_KEYMAP ( us );

View File

@ -446,11 +446,6 @@ void fbcon_putchar ( struct fbcon *fbcon, int character ) {
if ( character < 0 )
return;
/* Accumulate Unicode characters */
character = utf8_accumulate ( &fbcon->utf8, character );
if ( character == 0 )
return;
/* Handle control characters */
switch ( character ) {
case '\r':

View File

@ -338,12 +338,9 @@ int image_exec ( struct image *image ) {
/* Sanity check */
assert ( image->flags & IMAGE_REGISTERED );
/* Switch current working directory to be that of the image
* itself, if applicable
*/
/* Switch current working directory to be that of the image itself */
old_cwuri = uri_get ( cwuri );
if ( image->uri )
churi ( image->uri );
churi ( image->uri );
/* Preserve record of any currently-running image */
saved_current_image = current_image;

View File

@ -1,131 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ctype.h>
#include <ipxe/keys.h>
#include <ipxe/keymap.h>
/** @file
*
* Keyboard mappings
*
*/
/** ASCII character mask */
#define ASCII_MASK 0x7f
/** Control character mask */
#define CTRL_MASK 0x1f
/** Upper case character mask */
#define UPPER_MASK 0x5f
/** Case toggle bit */
#define CASE_TOGGLE ( ASCII_MASK & ~UPPER_MASK )
/** Default keyboard mapping */
static TABLE_START ( keymap_start, KEYMAP );
/** Current keyboard mapping */
static struct keymap *keymap_current = keymap_start;
/**
* Remap a key
*
* @v character Character read from console
* @ret mapped Mapped character
*/
unsigned int key_remap ( unsigned int character ) {
struct keymap *keymap = keymap_current;
unsigned int mapped = ( character & KEYMAP_MASK );
struct keymap_key *key;
/* Invert case before remapping if applicable */
if ( ( character & KEYMAP_CAPSLOCK_UNDO ) && isalpha ( mapped ) )
mapped ^= CASE_TOGGLE;
/* Select remapping table */
key = ( ( character & KEYMAP_ALTGR ) ? keymap->altgr : keymap->basic );
/* Remap via table */
for ( ; key->from ; key++ ) {
if ( mapped == key->from ) {
mapped = key->to;
break;
}
}
/* Handle Ctrl-<key> and CapsLock */
if ( isalpha ( mapped ) ) {
if ( character & KEYMAP_CTRL ) {
mapped &= CTRL_MASK;
} else if ( character & KEYMAP_CAPSLOCK ) {
mapped ^= CASE_TOGGLE;
}
}
/* Clear flags */
mapped &= ASCII_MASK;
DBGC2 ( &keymap_current, "KEYMAP mapped %04x => %02x\n",
character, mapped );
return mapped;
}
/**
* Find keyboard map by name
*
* @v name Keyboard map name
* @ret keymap Keyboard map, or NULL if not found
*/
struct keymap * keymap_find ( const char *name ) {
struct keymap *keymap;
/* Find matching keyboard map */
for_each_table_entry ( keymap, KEYMAP ) {
if ( strcmp ( keymap->name, name ) == 0 )
return keymap;
}
return NULL;
}
/**
* Set keyboard map
*
* @v keymap Keyboard map, or NULL to use default
*/
void keymap_set ( struct keymap *keymap ) {
/* Use default keymap if none specified */
if ( ! keymap )
keymap = keymap_start;
/* Set new keyboard map */
if ( keymap != keymap_current )
DBGC ( &keymap_current, "KEYMAP using \"%s\"\n", keymap->name );
keymap_current = keymap;
}

View File

@ -411,8 +411,9 @@ struct settings * find_settings ( const char *name ) {
/**
* Apply all settings
*
* @ret rc Return status code
*/
static void apply_settings ( void ) {
static int apply_settings ( void ) {
struct settings_applicator *applicator;
int rc;
@ -421,9 +422,11 @@ static void apply_settings ( void ) {
if ( ( rc = applicator->apply() ) != 0 ) {
DBG ( "Could not apply settings using applicator "
"%p: %s\n", applicator, strerror ( rc ) );
/* Continue to apply remaining settings */
return rc;
}
}
return 0;
}
/**
@ -641,7 +644,8 @@ int store_setting ( struct settings *settings, const struct setting *setting,
*/
for ( ; settings ; settings = settings->parent ) {
if ( settings == &settings_root ) {
apply_settings();
if ( ( rc = apply_settings() ) != 0 )
return rc;
break;
}
}
@ -2195,7 +2199,7 @@ const struct setting_type setting_type_base64 __setting_type = {
};
/**
* Format UUID/GUID setting value
* Format UUID setting value
*
* @v type Setting type
* @v raw Raw setting value
@ -2204,24 +2208,17 @@ const struct setting_type setting_type_base64 __setting_type = {
* @v len Length of buffer
* @ret len Length of formatted value, or negative error
*/
static int format_uuid_setting ( const struct setting_type *type,
static int format_uuid_setting ( const struct setting_type *type __unused,
const void *raw, size_t raw_len, char *buf,
size_t len ) {
union uuid uuid;
const union uuid *uuid = raw;
/* Range check */
if ( raw_len != sizeof ( uuid ) )
if ( raw_len != sizeof ( *uuid ) )
return -ERANGE;
/* Copy value */
memcpy ( &uuid, raw, sizeof ( uuid ) );
/* Mangle GUID byte ordering */
if ( type == &setting_type_guid )
uuid_mangle ( &uuid );
/* Format value */
return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) );
return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) );
}
/** UUID setting type */
@ -2230,12 +2227,6 @@ const struct setting_type setting_type_uuid __setting_type = {
.format = format_uuid_setting,
};
/** GUID setting type */
const struct setting_type setting_type_guid __setting_type = {
.name = "guid",
.format = format_uuid_setting,
};
/**
* Format PCI bus:dev.fn setting value
*

View File

@ -79,10 +79,12 @@ size_t uri_decode ( const char *encoded, void *buf, size_t len ) {
/**
* Decode URI field in-place
*
* @v encoded Encoded field, or NULL
* @v uri URI
* @v field URI field index
*/
static void uri_decode_inplace ( char *encoded ) {
char *decoded = encoded;
static void uri_decode_inplace ( struct uri *uri, unsigned int field ) {
const char *encoded = uri_field ( uri, field );
char *decoded = ( ( char * ) encoded );
size_t len;
/* Do nothing if field is not present */
@ -148,7 +150,7 @@ static int uri_character_escaped ( char c, unsigned int field ) {
* parser but for any other URI parsers (e.g. HTTP query
* string parsers, which care about '=' and '&').
*/
static const char *escaped[URI_EPATH] = {
static const char *escaped[URI_FIELDS] = {
/* Scheme or default: escape everything */
[URI_SCHEME] = "/#:@?=&",
/* Opaque part: escape characters which would affect
@ -170,21 +172,20 @@ static int uri_character_escaped ( char c, unsigned int field ) {
* appears within paths.
*/
[URI_PATH] = "#:@?",
/* Query: escape everything except '/', which
* sometimes appears within queries.
*/
[URI_QUERY] = "#:@?",
/* Fragment: escape everything */
[URI_FRAGMENT] = "/#:@?",
};
/* Always escape non-printing characters and whitespace */
if ( ( ! isprint ( c ) ) || ( c == ' ' ) )
return 1;
/* Escape nothing else in already-escaped fields */
if ( field >= URI_EPATH )
return 0;
/* Escape '%' and any field-specific characters */
if ( ( c == '%' ) || strchr ( escaped[field], c ) )
return 1;
return 0;
return ( /* Always escape non-printing characters and whitespace */
( ! isprint ( c ) ) || ( c == ' ' ) ||
/* Always escape '%' */
( c == '%' ) ||
/* Escape field-specific characters */
strchr ( escaped[field], c ) );
}
/**
@ -261,12 +262,10 @@ static void uri_dump ( const struct uri *uri ) {
DBGC ( uri, " port \"%s\"", uri->port );
if ( uri->path )
DBGC ( uri, " path \"%s\"", uri->path );
if ( uri->epath )
DBGC ( uri, " epath \"%s\"", uri->epath );
if ( uri->equery )
DBGC ( uri, " equery \"%s\"", uri->equery );
if ( uri->efragment )
DBGC ( uri, " efragment \"%s\"", uri->efragment );
if ( uri->query )
DBGC ( uri, " query \"%s\"", uri->query );
if ( uri->fragment )
DBGC ( uri, " fragment \"%s\"", uri->fragment );
if ( uri->params )
DBGC ( uri, " params \"%s\"", uri->params->name );
}
@ -299,19 +298,17 @@ struct uri * parse_uri ( const char *uri_string ) {
char *raw;
char *tmp;
char *path;
char *epath;
char *authority;
size_t raw_len;
unsigned int field;
/* Allocate space for URI struct and two copies of the string */
/* Allocate space for URI struct and a copy of the string */
raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
uri = zalloc ( sizeof ( *uri ) + ( 2 * raw_len ) );
uri = zalloc ( sizeof ( *uri ) + raw_len );
if ( ! uri )
return NULL;
ref_init ( &uri->refcnt, uri_free );
raw = ( ( ( void * ) uri ) + sizeof ( *uri ) );
path = ( raw + raw_len );
/* Copy in the raw string */
memcpy ( raw, uri_string, raw_len );
@ -331,62 +328,57 @@ struct uri * parse_uri ( const char *uri_string ) {
/* Chop off the fragment, if it exists */
if ( ( tmp = strchr ( raw, '#' ) ) ) {
*(tmp++) = '\0';
uri->efragment = tmp;
uri->fragment = tmp;
}
/* Identify absolute URIs */
epath = raw;
for ( tmp = raw ; ; tmp++ ) {
/* Possible scheme character (for our URI schemes) */
if ( isalpha ( *tmp ) || ( *tmp == '-' ) || ( *tmp == '_' ) )
continue;
/* Invalid scheme character or NUL: is a relative URI */
if ( *tmp != ':' )
break;
/* Identify absolute/relative URI */
if ( ( tmp = strchr ( raw, ':' ) ) ) {
/* Absolute URI: identify hierarchical/opaque */
uri->scheme = raw;
*(tmp++) = '\0';
if ( *tmp == '/' ) {
/* Absolute URI with hierarchical part */
epath = tmp;
path = tmp;
} else {
/* Absolute URI with opaque part */
uri->opaque = tmp;
epath = NULL;
path = NULL;
}
break;
} else {
/* Relative URI */
path = raw;
}
/* If we don't have a path (i.e. we have an absolute URI with
* an opaque portion, we're already finished processing
*/
if ( ! epath )
if ( ! path )
goto done;
/* Chop off the query, if it exists */
if ( ( tmp = strchr ( epath, '?' ) ) ) {
if ( ( tmp = strchr ( path, '?' ) ) ) {
*(tmp++) = '\0';
uri->equery = tmp;
uri->query = tmp;
}
/* If we have no path remaining, then we're already finished
* processing.
*/
if ( ! epath[0] )
if ( ! path[0] )
goto done;
/* Identify net/absolute/relative path */
if ( uri->scheme && ( strncmp ( epath, "//", 2 ) == 0 ) ) {
if ( uri->scheme && ( strncmp ( path, "//", 2 ) == 0 ) ) {
/* Net path. If this is terminated by the first '/'
* of an absolute path, then we have no space for a
* terminator after the authority field, so shuffle
* the authority down by one byte, overwriting one of
* the two slashes.
*/
authority = ( epath + 2 );
authority = ( path + 2 );
if ( ( tmp = strchr ( authority, '/' ) ) ) {
/* Shuffle down */
uri->epath = tmp;
uri->path = tmp;
memmove ( ( authority - 1 ), authority,
( tmp - authority ) );
authority--;
@ -394,14 +386,8 @@ struct uri * parse_uri ( const char *uri_string ) {
}
} else {
/* Absolute/relative path */
uri->epath = epath;
authority = NULL;
}
/* Create copy of path for decoding */
if ( uri->epath ) {
strcpy ( path, uri->epath );
uri->path = path;
authority = NULL;
}
/* If we don't have an authority (i.e. we have a non-net
@ -435,8 +421,8 @@ struct uri * parse_uri ( const char *uri_string ) {
done:
/* Decode fields in-place */
for ( field = 0 ; field < URI_EPATH ; field++ )
uri_decode_inplace ( ( char * ) uri_field ( uri, field ) );
for ( field = 0 ; field < URI_FIELDS ; field++ )
uri_decode_inplace ( uri, field );
DBGC ( uri, "URI parsed \"%s\" to", uri_string );
uri_dump ( uri );
@ -472,8 +458,8 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
static const char prefixes[URI_FIELDS] = {
[URI_PASSWORD] = ':',
[URI_PORT] = ':',
[URI_EQUERY] = '?',
[URI_EFRAGMENT] = '#',
[URI_QUERY] = '?',
[URI_FRAGMENT] = '#',
};
char prefix;
size_t used = 0;
@ -494,10 +480,6 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
if ( ! uri_field ( uri, field ) )
continue;
/* Skip path field if encoded path is present */
if ( ( field == URI_PATH ) && uri->epath )
continue;
/* Prefix this field, if applicable */
prefix = prefixes[field];
if ( ( field == URI_HOST ) && ( uri->user != NULL ) )
@ -694,7 +676,6 @@ char * resolve_path ( const char *base_path,
struct uri * resolve_uri ( const struct uri *base_uri,
struct uri *relative_uri ) {
struct uri tmp_uri;
char *tmp_epath = NULL;
char *tmp_path = NULL;
struct uri *new_uri;
@ -704,27 +685,20 @@ struct uri * resolve_uri ( const struct uri *base_uri,
/* Mangle URI */
memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
if ( relative_uri->epath ) {
tmp_epath = resolve_path ( ( base_uri->epath ?
base_uri->epath : "/" ),
relative_uri->epath );
if ( ! tmp_epath )
goto err_epath;
tmp_path = strdup ( tmp_epath );
if ( ! tmp_path )
goto err_path;
uri_decode_inplace ( tmp_path );
tmp_uri.epath = tmp_epath;
if ( relative_uri->path ) {
tmp_path = resolve_path ( ( base_uri->path ?
base_uri->path : "/" ),
relative_uri->path );
tmp_uri.path = tmp_path;
tmp_uri.equery = relative_uri->equery;
tmp_uri.efragment = relative_uri->efragment;
tmp_uri.query = relative_uri->query;
tmp_uri.fragment = relative_uri->fragment;
tmp_uri.params = relative_uri->params;
} else if ( relative_uri->equery ) {
tmp_uri.equery = relative_uri->equery;
tmp_uri.efragment = relative_uri->efragment;
} else if ( relative_uri->query ) {
tmp_uri.query = relative_uri->query;
tmp_uri.fragment = relative_uri->fragment;
tmp_uri.params = relative_uri->params;
} else if ( relative_uri->efragment ) {
tmp_uri.efragment = relative_uri->efragment;
} else if ( relative_uri->fragment ) {
tmp_uri.fragment = relative_uri->fragment;
tmp_uri.params = relative_uri->params;
} else if ( relative_uri->params ) {
tmp_uri.params = relative_uri->params;
@ -733,14 +707,7 @@ struct uri * resolve_uri ( const struct uri *base_uri,
/* Create demangled URI */
new_uri = uri_dup ( &tmp_uri );
free ( tmp_path );
free ( tmp_epath );
return new_uri;
free ( tmp_path );
err_path:
free ( tmp_epath );
err_epath:
return NULL;
}
/**
@ -779,7 +746,6 @@ static struct uri * tftp_uri ( struct sockaddr *sa_server,
if ( asprintf ( &path, "/%s", filename ) < 0 )
goto err_path;
tmp.path = path;
tmp.epath = path;
/* Demangle URI */
uri = uri_dup ( &tmp );

View File

@ -1,137 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <assert.h>
#include <ipxe/utf8.h>
/** @file
*
* UTF-8 Unicode encoding
*
*/
/**
* Accumulate Unicode character from UTF-8 byte sequence
*
* @v utf8 UTF-8 accumulator
* @v byte UTF-8 byte
* @ret character Unicode character, or 0 if incomplete
*/
unsigned int utf8_accumulate ( struct utf8_accumulator *utf8, uint8_t byte ) {
static unsigned int min[] = {
UTF8_MIN_TWO,
UTF8_MIN_THREE,
UTF8_MIN_FOUR,
};
unsigned int shift;
unsigned int len;
uint8_t tmp;
/* Handle continuation bytes */
if ( UTF8_IS_CONTINUATION ( byte ) ) {
/* Fail if this is an unexpected continuation byte */
if ( utf8->remaining == 0 ) {
DBGC ( utf8, "UTF8 %p unexpected %02x\n", utf8, byte );
return UTF8_INVALID;
}
/* Apply continuation byte */
utf8->character <<= UTF8_CONTINUATION_BITS;
utf8->character |= ( byte & UTF8_CONTINUATION_MASK );
/* Return 0 if more continuation bytes are expected */
if ( --utf8->remaining != 0 )
return 0;
/* Fail if sequence is illegal */
if ( utf8->character < utf8->min ) {
DBGC ( utf8, "UTF8 %p illegal %02x\n", utf8,
utf8->character );
return UTF8_INVALID;
}
/* Sanity check */
assert ( utf8->character != 0 );
/* Return completed character */
DBGC2 ( utf8, "UTF8 %p accumulated %02x\n",
utf8, utf8->character );
return utf8->character;
}
/* Reset state and report failure if this is an unexpected
* non-continuation byte. Do not return UTF8_INVALID since
* doing so could cause us to drop a valid ASCII character.
*/
if ( utf8->remaining != 0 ) {
shift = ( utf8->remaining * UTF8_CONTINUATION_BITS );
DBGC ( utf8, "UTF8 %p unexpected %02x (partial %02x/%02x)\n",
utf8, byte, ( utf8->character << shift ),
( ( 1 << shift ) - 1 ) );
utf8->remaining = 0;
}
/* Handle initial bytes */
if ( ! UTF8_IS_ASCII ( byte ) ) {
/* Sanity check */
assert ( utf8->remaining == 0 );
/* Count total number of bytes in sequence */
tmp = byte;
len = 0;
while ( tmp & UTF8_HIGH_BIT ) {
tmp <<= 1;
len++;
}
/* Check for illegal length */
if ( len > UTF8_MAX_LEN ) {
DBGC ( utf8, "UTF8 %p illegal %02x length %d\n",
utf8, byte, len );
return UTF8_INVALID;
}
/* Store initial bits of character */
utf8->character = ( tmp >> len );
/* Store number of bytes remaining */
len--;
utf8->remaining = len;
assert ( utf8->remaining > 0 );
/* Store minimum legal value */
utf8->min = min[ len - 1 ];
assert ( utf8->min > 0 );
/* Await continuation bytes */
return 0;
}
/* Handle ASCII bytes */
return byte;
}

View File

@ -32,7 +32,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <wchar.h>
#include <ipxe/features.h>
#include <ipxe/version.h>
#include <ipxe/sbat.h>
#include <config/general.h>
#include <config/branding.h>
@ -93,32 +92,3 @@ const wchar_t build_wname[] = WSTRING ( BUILD_NAME );
/** Copy of build name string within ".prefix" */
const char build_name_prefix[] __attribute__ (( section ( ".prefix.name" ) ))
= BUILD_NAME;
/** SBAT upstream iPXE line
*
* This line represents the security generation of the upstream
* codebase from which this build is derived.
*/
#define SBAT_IPXE \
SBAT_LINE ( "ipxe", IPXE_SBAT_GENERATION, \
"iPXE", BUILD_NAME, VERSION, "https://ipxe.org" )
/** SBAT local build line
*
* This line states the security generation of the local build, which
* may include non-default features or non-upstreamed modifications.
*/
#if PRODUCT_SBAT_GENERATION
#define SBAT_PRODUCT \
SBAT_LINE ( "ipxe." PRODUCT_SBAT_NAME, PRODUCT_SBAT_GENERATION, \
PRODUCT_SHORT_NAME, BUILD_NAME, VERSION, \
PRODUCT_URI )
#else
#define SBAT_PRODUCT ""
#endif
/** SBAT data */
#define SBAT_DATA SBAT_HEADER "" SBAT_IPXE "" SBAT_PRODUCT
/** SBAT data (without any NUL terminator) */
const char sbat[ sizeof ( SBAT_DATA ) - 1 ] __sbat = SBAT_DATA;

View File

@ -38,7 +38,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/crypto.h>
#include <ipxe/ecb.h>
#include <ipxe/cbc.h>
#include <ipxe/gcm.h>
#include <ipxe/aes.h>
/** AES strides
@ -779,18 +778,25 @@ static int aes_setkey ( void *ctx, const void *key, size_t keylen ) {
return 0;
}
/**
* Set initialisation vector
*
* @v ctx Context
* @v iv Initialisation vector
*/
static void aes_setiv ( void *ctx __unused, const void *iv __unused ) {
/* Nothing to do */
}
/** Basic AES algorithm */
struct cipher_algorithm aes_algorithm = {
.name = "aes",
.ctxsize = sizeof ( struct aes_context ),
.blocksize = AES_BLOCKSIZE,
.alignsize = 0,
.authsize = 0,
.setkey = aes_setkey,
.setiv = cipher_null_setiv,
.setiv = aes_setiv,
.encrypt = aes_encrypt,
.decrypt = aes_decrypt,
.auth = cipher_null_auth,
};
/* AES in Electronic Codebook mode */
@ -800,7 +806,3 @@ ECB_CIPHER ( aes_ecb, aes_ecb_algorithm,
/* AES in Cipher Block Chaining mode */
CBC_CIPHER ( aes_cbc, aes_cbc_algorithm,
aes_algorithm, struct aes_context, AES_BLOCKSIZE );
/* AES in Galois/Counter mode */
GCM_CIPHER ( aes_gcm, aes_gcm_algorithm,
aes_algorithm, struct aes_context, AES_BLOCKSIZE );

View File

@ -96,6 +96,12 @@ static void arc4_xor ( void *ctxv, const void *srcv, void *dstv,
ctx->j = j;
}
static void arc4_setiv ( void *ctx __unused, const void *iv __unused )
{
/* ARC4 does not use a fixed-length IV */
}
/**
* Perform ARC4 encryption or decryption, skipping initial keystream bytes
*
@ -119,11 +125,8 @@ struct cipher_algorithm arc4_algorithm = {
.name = "ARC4",
.ctxsize = ARC4_CTX_SIZE,
.blocksize = 1,
.alignsize = 1,
.authsize = 0,
.setkey = arc4_setkey,
.setiv = cipher_null_setiv,
.setiv = arc4_setiv,
.encrypt = arc4_xor,
.decrypt = arc4_xor,
.auth = cipher_null_auth,
};

View File

@ -32,16 +32,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/crypto.h>
void digest_null_init ( void *ctx __unused ) {
static void digest_null_init ( void *ctx __unused ) {
/* Do nothing */
}
void digest_null_update ( void *ctx __unused, const void *src __unused,
size_t len __unused ) {
static void digest_null_update ( void *ctx __unused, const void *src __unused,
size_t len __unused ) {
/* Do nothing */
}
void digest_null_final ( void *ctx __unused, void *out __unused ) {
static void digest_null_final ( void *ctx __unused, void *out __unused ) {
/* Do nothing */
}
@ -55,80 +55,76 @@ struct digest_algorithm digest_null = {
.final = digest_null_final,
};
int cipher_null_setkey ( void *ctx __unused, const void *key __unused,
size_t keylen __unused ) {
static int cipher_null_setkey ( void *ctx __unused, const void *key __unused,
size_t keylen __unused ) {
/* Do nothing */
return 0;
}
void cipher_null_setiv ( void *ctx __unused, const void *iv __unused,
size_t ivlen __unused ) {
static void cipher_null_setiv ( void *ctx __unused,
const void *iv __unused ) {
/* Do nothing */
}
void cipher_null_encrypt ( void *ctx __unused, const void *src, void *dst,
size_t len ) {
static void cipher_null_encrypt ( void *ctx __unused, const void *src,
void *dst, size_t len ) {
memcpy ( dst, src, len );
}
void cipher_null_decrypt ( void *ctx __unused, const void *src, void *dst,
size_t len ) {
static void cipher_null_decrypt ( void *ctx __unused, const void *src,
void *dst, size_t len ) {
memcpy ( dst, src, len );
}
void cipher_null_auth ( void *ctx __unused, void *auth __unused ) {
/* Do nothing */
}
struct cipher_algorithm cipher_null = {
.name = "null",
.ctxsize = 0,
.blocksize = 1,
.alignsize = 1,
.authsize = 0,
.setkey = cipher_null_setkey,
.setiv = cipher_null_setiv,
.encrypt = cipher_null_encrypt,
.decrypt = cipher_null_decrypt,
.auth = cipher_null_auth,
};
int pubkey_null_init ( void *ctx __unused, const void *key __unused,
size_t key_len __unused ) {
static int pubkey_null_init ( void *ctx __unused, const void *key __unused,
size_t key_len __unused ) {
return 0;
}
size_t pubkey_null_max_len ( void *ctx __unused ) {
static size_t pubkey_null_max_len ( void *ctx __unused ) {
return 0;
}
int pubkey_null_encrypt ( void *ctx __unused, const void *plaintext __unused,
size_t plaintext_len __unused,
void *ciphertext __unused ) {
static int pubkey_null_encrypt ( void *ctx __unused,
const void *plaintext __unused,
size_t plaintext_len __unused,
void *ciphertext __unused ) {
return 0;
}
int pubkey_null_decrypt ( void *ctx __unused, const void *ciphertext __unused,
size_t ciphertext_len __unused,
void *plaintext __unused ) {
static int pubkey_null_decrypt ( void *ctx __unused,
const void *ciphertext __unused,
size_t ciphertext_len __unused,
void *plaintext __unused ) {
return 0;
}
int pubkey_null_sign ( void *ctx __unused,
struct digest_algorithm *digest __unused,
const void *value __unused, void *signature __unused ) {
static int pubkey_null_sign ( void *ctx __unused,
struct digest_algorithm *digest __unused,
const void *value __unused,
void *signature __unused ) {
return 0;
}
int pubkey_null_verify ( void *ctx __unused,
struct digest_algorithm *digest __unused,
const void *value __unused,
const void *signature __unused ,
size_t signature_len __unused ) {
static int pubkey_null_verify ( void *ctx __unused,
struct digest_algorithm *digest __unused,
const void *value __unused,
const void *signature __unused ,
size_t signature_len __unused ) {
return 0;
}
void pubkey_null_final ( void *ctx __unused ) {
static void pubkey_null_final ( void *ctx __unused ) {
/* Do nothing */
}

View File

@ -1,133 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Ephemeral Diffie-Hellman key exchange
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <ipxe/bigint.h>
#include <ipxe/dhe.h>
/**
* Calculate Diffie-Hellman key
*
* @v modulus Prime modulus
* @v len Length of prime modulus
* @v generator Generator
* @v generator_len Length of generator
* @v partner Partner public key
* @v partner_len Length of partner public key
* @v private Private key
* @v private_len Length of private key
* @ret public Public key (length equal to prime modulus)
* @ret shared Shared secret (length equal to prime modulus)
* @ret rc Return status code
*/
int dhe_key ( const void *modulus, size_t len, const void *generator,
size_t generator_len, const void *partner, size_t partner_len,
const void *private, size_t private_len, void *public,
void *shared ) {
unsigned int size = bigint_required_size ( len );
unsigned int private_size = bigint_required_size ( private_len );
bigint_t ( size ) *mod;
bigint_t ( private_size ) *exp;
size_t tmp_len = bigint_mod_exp_tmp_len ( mod, exp );
struct {
bigint_t ( size ) modulus;
bigint_t ( size ) generator;
bigint_t ( size ) partner;
bigint_t ( private_size ) private;
bigint_t ( size ) result;
uint8_t tmp[tmp_len];
} __attribute__ (( packed )) *ctx;
int rc;
DBGC2 ( modulus, "DHE %p modulus:\n", modulus );
DBGC2_HDA ( modulus, 0, modulus, len );
DBGC2 ( modulus, "DHE %p generator:\n", modulus );
DBGC2_HDA ( modulus, 0, generator, generator_len );
DBGC2 ( modulus, "DHE %p partner public key:\n", modulus );
DBGC2_HDA ( modulus, 0, partner, partner_len );
DBGC2 ( modulus, "DHE %p private key:\n", modulus );
DBGC2_HDA ( modulus, 0, private, private_len );
/* Sanity checks */
if ( generator_len > len ) {
DBGC ( modulus, "DHE %p overlength generator\n", modulus );
rc = -EINVAL;
goto err_sanity;
}
if ( partner_len > len ) {
DBGC ( modulus, "DHE %p overlength partner public key\n",
modulus );
rc = -EINVAL;
goto err_sanity;
}
if ( private_len > len ) {
DBGC ( modulus, "DHE %p overlength private key\n", modulus );
rc = -EINVAL;
goto err_sanity;
}
/* Allocate context */
ctx = malloc ( sizeof ( *ctx ) );
if ( ! ctx ) {
rc = -ENOMEM;
goto err_alloc;
}
/* Initialise context */
bigint_init ( &ctx->modulus, modulus, len );
bigint_init ( &ctx->generator, generator, generator_len );
bigint_init ( &ctx->partner, partner, partner_len );
bigint_init ( &ctx->private, private, private_len );
/* Calculate public key */
bigint_mod_exp ( &ctx->generator, &ctx->modulus, &ctx->private,
&ctx->result, ctx->tmp );
bigint_done ( &ctx->result, public, len );
DBGC2 ( modulus, "DHE %p public key:\n", modulus );
DBGC2_HDA ( modulus, 0, public, len );
/* Calculate shared secret */
bigint_mod_exp ( &ctx->partner, &ctx->modulus, &ctx->private,
&ctx->result, ctx->tmp );
bigint_done ( &ctx->result, shared, len );
DBGC2 ( modulus, "DHE %p shared secret:\n", modulus );
DBGC2_HDA ( modulus, 0, shared, len );
/* Success */
rc = 0;
free ( ctx );
err_alloc:
err_sanity:
return rc;
}

View File

@ -1,535 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Galois/Counter Mode (GCM)
*
* The GCM algorithm is specified in
*
* https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
* https://csrc.nist.rip/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
*
*/
#include <stdint.h>
#include <string.h>
#include <byteswap.h>
#include <ipxe/crypto.h>
#include <ipxe/gcm.h>
/**
* Perform encryption
*
* This value is chosen to allow for ANDing with a fragment length.
*/
#define GCM_FL_ENCRYPT 0x00ff
/**
* Calculate hash over an initialisation vector value
*
* The hash calculation for a non 96-bit initialisation vector is
* identical to the calculation used for additional data, except that
* the non-additional data length counter is used.
*/
#define GCM_FL_IV 0x0100
/**
* GCM field polynomial
*
* GCM treats 128-bit blocks as polynomials in GF(2^128) with the
* field polynomial f(x) = 1 + x + x^2 + x^7 + x^128.
*
* In a somewhat bloody-minded interpretation of "big-endian", the
* constant term (with degree zero) is arbitrarily placed in the
* leftmost bit of the big-endian binary representation (i.e. the most
* significant bit of byte 0), thereby failing to correspond to the
* bit ordering in any CPU architecture in existence. This
* necessitates some wholly gratuitous byte reversals when
* constructing the multiplication tables, since all CPUs will treat
* bit 0 as being the least significant bit within a byte.
*
* The field polynomial maps to the 128-bit constant
* 0xe1000000000000000000000000000000 (with the x^128 term outside the
* 128-bit range), and can therefore be treated as a single-byte
* value.
*/
#define GCM_POLY 0xe1
/**
* Hash key for which multiplication tables are cached
*
* GCM operates much more efficiently with a cached multiplication
* table, which costs 4kB per hash key. Since this exceeds the
* available stack space, we place a single 4kB cache in .bss and
* recalculate the cached values as required. In the common case of a
* single HTTPS connection being used to download a (relatively) large
* file, the same key will be used repeatedly for almost all GCM
* operations, and so the overhead of recalculation is negligible.
*/
static const union gcm_block *gcm_cached_key;
/**
* Cached multiplication table (M0) for Shoup's method
*
* Each entry within this table represents the result of multiplying
* the cached hash key by an arbitrary 8-bit polynomial.
*/
static union gcm_block gcm_cached_mult[256];
/**
* Cached reduction table (R) for Shoup's method
*
* Each entry within this table represents the result of multiplying
* the fixed polynomial x^128 by an arbitrary 8-bit polynomial. Only
* the leftmost 16 bits are stored, since all other bits within the
* result will always be zero.
*/
static uint16_t gcm_cached_reduce[256];
/**
* Reverse bits in a byte
*
* @v byte Byte
* @ret etyb Bit-reversed byte
*/
static inline __attribute__ (( always_inline )) uint8_t
gcm_reverse ( const uint8_t byte ) {
uint8_t etyb = etyb;
uint8_t mask;
for ( mask = 1 ; mask ; mask <<= 1 ) {
etyb <<= 1;
if ( byte & mask )
etyb |= 1;
}
return etyb;
}
/**
* Update GCM counter
*
* @v ctr Counter
* @v delta Amount to add to counter
*/
static inline __attribute__ (( always_inline )) void
gcm_count ( union gcm_block *ctr, uint32_t delta ) {
uint32_t *value = &ctr->ctr.value;
/* Update counter modulo 2^32 */
*value = cpu_to_be32 ( be32_to_cpu ( *value ) + delta );
}
/**
* XOR partial data block
*
* @v src1 Source buffer 1
* @v src2 Source buffer 2
* @v dst Destination buffer
* @v len Length
*/
static inline void gcm_xor ( const void *src1, const void *src2, void *dst,
size_t len ) {
uint8_t *dst_bytes = dst;
const uint8_t *src1_bytes = src1;
const uint8_t *src2_bytes = src2;
/* XOR one byte at a time */
while ( len-- )
*(dst_bytes++) = ( *(src1_bytes++) ^ *(src2_bytes++) );
}
/**
* XOR whole data block in situ
*
* @v src Source block
* @v dst Destination block
*/
static inline void gcm_xor_block ( const union gcm_block *src,
union gcm_block *dst ) {
/* XOR whole dwords */
dst->dword[0] ^= src->dword[0];
dst->dword[1] ^= src->dword[1];
dst->dword[2] ^= src->dword[2];
dst->dword[3] ^= src->dword[3];
}
/**
* Multiply polynomial by (x)
*
* @v mult Multiplicand
* @v res Result
*/
static void gcm_multiply_x ( const union gcm_block *mult,
union gcm_block *res ) {
unsigned int i;
uint8_t byte;
uint8_t carry;
/* Multiply by (x) by shifting all bits rightward */
for ( i = 0, carry = 0 ; i < sizeof ( res->byte ) ; i++ ) {
byte = mult->byte[i];
res->byte[i] = ( ( carry << 7 ) | ( byte >> 1 ) );
carry = ( byte & 0x01 );
}
/* If result overflows, reduce modulo the field polynomial */
if ( carry )
res->byte[0] ^= GCM_POLY;
}
/**
* Construct cached tables
*
* @v key Hash key
* @v context Context
*/
static void gcm_cache ( const union gcm_block *key ) {
union gcm_block *mult;
uint16_t reduce;
unsigned int this;
unsigned int other;
unsigned int i;
/* Calculate M0[1..255] and R[1..255]
*
* The R[] values are independent of the key, but the overhead
* of recalculating them here is negligible and saves on
* overall code size since the calculations are related.
*/
for ( i = 1 ; i < 256 ; i++ ) {
/* Reverse bit order to compensate for poor life choices */
this = gcm_reverse ( i );
/* Construct entries */
mult = &gcm_cached_mult[this];
if ( this & 0x80 ) {
/* Odd number: entry[i] = entry[i - 1] + poly */
other = ( this & 0x7f ); /* bit-reversed (i - 1) */
gcm_xor ( key, &gcm_cached_mult[other], mult,
sizeof ( *mult ) );
reduce = gcm_cached_reduce[other];
reduce ^= be16_to_cpu ( GCM_POLY << 8 );
gcm_cached_reduce[this] = reduce;
} else {
/* Even number: entry[i] = entry[i/2] * (x) */
other = ( this << 1 ); /* bit-reversed (i / 2) */
gcm_multiply_x ( &gcm_cached_mult[other], mult );
reduce = be16_to_cpu ( gcm_cached_reduce[other] );
reduce >>= 1;
gcm_cached_reduce[this] = cpu_to_be16 ( reduce );
}
}
/* Record cached key */
gcm_cached_key = key;
}
/**
* Multiply polynomial by (x^8) in situ
*
* @v poly Multiplicand and result
*/
static void gcm_multiply_x_8 ( union gcm_block *poly ) {
uint8_t *byte;
uint8_t msb;
/* Reduction table must already have been calculated */
assert ( gcm_cached_key != NULL );
/* Record most significant byte */
byte = &poly->byte[ sizeof ( poly->byte ) - 1 ];
msb = *byte;
/* Multiply least significant bytes by shifting */
for ( ; byte > &poly->byte[0] ; byte-- )
*byte = *( byte - 1 );
*byte = 0;
/* Multiply most significant byte via reduction table */
poly->word[0] ^= gcm_cached_reduce[msb];
}
/**
* Multiply polynomial by hash key in situ
*
* @v key Hash key
* @v poly Multiplicand and result
*/
static void gcm_multiply_key ( const union gcm_block *key,
union gcm_block *poly ) {
union gcm_block res;
uint8_t *byte;
/* Construct tables, if necessary */
if ( gcm_cached_key != key )
gcm_cache ( key );
/* Multiply using Shoup's algorithm */
byte = &poly->byte[ sizeof ( poly->byte ) - 1 ];
memcpy ( &res, &gcm_cached_mult[ *byte ], sizeof ( res ) );
for ( byte-- ; byte >= &poly->byte[0] ; byte-- ) {
gcm_multiply_x_8 ( &res );
gcm_xor_block ( &gcm_cached_mult[ *byte ], &res );
}
/* Overwrite result */
memcpy ( poly, &res, sizeof ( *poly ) );
}
/**
* Encrypt/decrypt/authenticate data
*
* @v context Context
* @v src Input data
* @v dst Output data, or NULL to process additional data
* @v len Length of data
* @v flags Operation flags
*/
static void gcm_process ( struct gcm_context *context, const void *src,
void *dst, size_t len, unsigned int flags ) {
union gcm_block tmp;
uint64_t *total;
size_t frag_len;
unsigned int block;
/* Calculate block number (for debugging) */
block = ( ( ( context->len.len.add + 8 * sizeof ( tmp ) - 1 ) /
( 8 * sizeof ( tmp ) ) ) +
( ( context->len.len.data + 8 * sizeof ( tmp ) - 1 ) /
( 8 * sizeof ( tmp ) ) ) + 1 );
/* Update total length (in bits) */
total = ( ( dst || ( flags & GCM_FL_IV ) ) ?
&context->len.len.data : &context->len.len.add );
*total += ( len * 8 );
/* Process data */
for ( ; len ; src += frag_len, len -= frag_len, block++ ) {
/* Calculate fragment length */
frag_len = len;
if ( frag_len > sizeof ( tmp ) )
frag_len = sizeof ( tmp );
/* Update hash with input data */
gcm_xor ( src, &context->hash, &context->hash, frag_len );
/* Encrypt/decrypt block, if applicable */
if ( dst ) {
/* Increment counter */
gcm_count ( &context->ctr, 1 );
/* Encrypt counter */
DBGC2 ( context, "GCM %p Y[%d]:\n", context, block );
DBGC2_HDA ( context, 0, &context->ctr,
sizeof ( context->ctr ) );
cipher_encrypt ( context->raw_cipher, &context->raw_ctx,
&context->ctr, &tmp, sizeof ( tmp ) );
DBGC2 ( context, "GCM %p E(K,Y[%d]):\n",
context, block );
DBGC2_HDA ( context, 0, &tmp, sizeof ( tmp ) );
/* Encrypt/decrypt data */
gcm_xor ( src, &tmp, dst, frag_len );
dst += frag_len;
/* Update hash with encrypted data, if applicable */
gcm_xor ( &tmp, &context->hash, &context->hash,
( frag_len & flags ) );
}
/* Update hash */
gcm_multiply_key ( &context->key, &context->hash );
DBGC2 ( context, "GCM %p X[%d]:\n", context, block );
DBGC2_HDA ( context, 0, &context->hash,
sizeof ( context->hash ) );
}
}
/**
* Construct hash
*
* @v context Context
* @v hash Hash to fill in
*/
static void gcm_hash ( struct gcm_context *context, union gcm_block *hash ) {
/* Construct big-endian lengths block */
hash->len.add = cpu_to_be64 ( context->len.len.add );
hash->len.data = cpu_to_be64 ( context->len.len.data );
DBGC2 ( context, "GCM %p len(A)||len(C):\n", context );
DBGC2_HDA ( context, 0, hash, sizeof ( *hash ) );
/* Update hash */
gcm_xor_block ( &context->hash, hash );
gcm_multiply_key ( &context->key, hash );
DBGC2 ( context, "GCM %p GHASH(H,A,C):\n", context );
DBGC2_HDA ( context, 0, hash, sizeof ( *hash ) );
}
/**
* Construct tag
*
* @v context Context
* @v tag Tag
*/
void gcm_tag ( struct gcm_context *context, union gcm_block *tag ) {
union gcm_block tmp;
uint32_t offset;
/* Construct hash */
gcm_hash ( context, tag );
/* Construct encrypted initial counter value */
memcpy ( &tmp, &context->ctr, sizeof ( tmp ) );
offset = ( ( -context->len.len.data ) / ( 8 * sizeof ( tmp ) ) );
gcm_count ( &tmp, offset );
cipher_encrypt ( context->raw_cipher, &context->raw_ctx, &tmp,
&tmp, sizeof ( tmp ) );
DBGC2 ( context, "GCM %p E(K,Y[0]):\n", context );
DBGC2_HDA ( context, 0, &tmp, sizeof ( tmp ) );
/* Construct tag */
gcm_xor_block ( &tmp, tag );
DBGC2 ( context, "GCM %p T:\n", context );
DBGC2_HDA ( context, 0, tag, sizeof ( *tag ) );
}
/**
* Set key
*
* @v context Context
* @v key Key
* @v keylen Key length
* @v raw_cipher Underlying cipher
* @ret rc Return status code
*/
int gcm_setkey ( struct gcm_context *context, const void *key, size_t keylen,
struct cipher_algorithm *raw_cipher ) {
int rc;
/* Initialise GCM context */
memset ( context, 0, sizeof ( *context ) );
context->raw_cipher = raw_cipher;
/* Set underlying block cipher key */
if ( ( rc = cipher_setkey ( raw_cipher, context->raw_ctx, key,
keylen ) ) != 0 )
return rc;
/* Construct GCM hash key */
cipher_encrypt ( raw_cipher, context->raw_ctx, &context->ctr,
&context->key, sizeof ( context->key ) );
DBGC2 ( context, "GCM %p H:\n", context );
DBGC2_HDA ( context, 0, &context->key, sizeof ( context->key ) );
/* Reset counter */
context->ctr.ctr.value = cpu_to_be32 ( 1 );
/* Construct cached tables */
gcm_cache ( &context->key );
return 0;
}
/**
* Set initialisation vector
*
* @v ctx Context
* @v iv Initialisation vector
* @v ivlen Initialisation vector length
*/
void gcm_setiv ( struct gcm_context *context, const void *iv, size_t ivlen ) {
union gcm_block *check = ( ( void * ) context );
/* Sanity checks */
linker_assert ( &context->hash == check, gcm_bad_layout );
linker_assert ( &context->len == check + 1, gcm_bad_layout );
linker_assert ( &context->ctr == check + 2, gcm_bad_layout );
linker_assert ( &context->key == check + 3, gcm_bad_layout );
/* Reset non-key state */
memset ( context, 0, offsetof ( typeof ( *context ), key ) );
/* Reset counter */
context->ctr.ctr.value = cpu_to_be32 ( 1 );
/* Process initialisation vector */
if ( ivlen == sizeof ( context->ctr.ctr.iv ) ) {
/* Initialisation vector is exactly 96 bits, use it as-is */
memcpy ( context->ctr.ctr.iv, iv, ivlen );
} else {
/* Calculate hash over initialisation vector */
gcm_process ( context, iv, NULL, ivlen, GCM_FL_IV );
gcm_hash ( context, &context->ctr );
assert ( context->len.len.add == 0 );
/* Reset non-key, non-counter state */
memset ( context, 0, offsetof ( typeof ( *context ), ctr ) );
}
DBGC2 ( context, "GCM %p Y[0]:\n", context );
DBGC2_HDA ( context, 0, &context->ctr, sizeof ( context->ctr ) );
}
/**
* Encrypt data
*
* @v context Context
* @v src Data to encrypt
* @v dst Buffer for encrypted data, or NULL for additional data
* @v len Length of data
*/
void gcm_encrypt ( struct gcm_context *context, const void *src, void *dst,
size_t len ) {
/* Process data */
gcm_process ( context, src, dst, len, GCM_FL_ENCRYPT );
}
/**
* Decrypt data
*
* @v context Context
* @v src Data to decrypt
* @v dst Buffer for decrypted data, or NULL for additional data
* @v len Length of data
*/
void gcm_decrypt ( struct gcm_context *context, const void *src, void *dst,
size_t len ) {
/* Process data */
gcm_process ( context, src, dst, len, 0 );
}

View File

@ -47,61 +47,93 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/hmac.h>
/**
* Initialise HMAC
* Reduce HMAC key length
*
* @v digest Digest algorithm to use
* @v ctx HMAC context
* @v digest_ctx Digest context
* @v key Key
* @v key_len Length of key
*/
void hmac_init ( struct digest_algorithm *digest, void *ctx, const void *key,
size_t key_len ) {
hmac_context_t ( digest ) *hctx = ctx;
static void hmac_reduce_key ( struct digest_algorithm *digest,
void *key, size_t *key_len ) {
uint8_t digest_ctx[digest->ctxsize];
digest_init ( digest, digest_ctx );
digest_update ( digest, digest_ctx, key, *key_len );
digest_final ( digest, digest_ctx, key );
*key_len = digest->digestsize;
}
/**
* Initialise HMAC
*
* @v digest Digest algorithm to use
* @v digest_ctx Digest context
* @v key Key
* @v key_len Length of key
*
* The length of the key should be less than the block size of the
* digest algorithm being used. (If the key length is greater, it
* will be replaced with its own digest, and key_len will be updated
* accordingly).
*/
void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
void *key, size_t *key_len ) {
unsigned char k_ipad[digest->blocksize];
unsigned int i;
/* Construct input pad */
memset ( hctx->pad, 0, sizeof ( hctx->pad ) );
if ( key_len <= sizeof ( hctx->pad ) ) {
memcpy ( hctx->pad, key, key_len );
} else {
digest_init ( digest, hctx->ctx );
digest_update ( digest, hctx->ctx, key, key_len );
digest_final ( digest, hctx->ctx, hctx->pad );
}
for ( i = 0 ; i < sizeof ( hctx->pad ) ; i++ ) {
hctx->pad[i] ^= 0x36;
}
/* Reduce key if necessary */
if ( *key_len > sizeof ( k_ipad ) )
hmac_reduce_key ( digest, key, key_len );
/* Construct input pad */
memset ( k_ipad, 0, sizeof ( k_ipad ) );
memcpy ( k_ipad, key, *key_len );
for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) {
k_ipad[i] ^= 0x36;
}
/* Start inner hash */
digest_init ( digest, hctx->ctx );
digest_update ( digest, hctx->ctx, hctx->pad, sizeof ( hctx->pad ) );
digest_init ( digest, digest_ctx );
digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) );
}
/**
* Finalise HMAC
*
* @v digest Digest algorithm to use
* @v ctx HMAC context
* @v digest_ctx Digest context
* @v key Key
* @v key_len Length of key
* @v hmac HMAC digest to fill in
*
* The length of the key should be less than the block size of the
* digest algorithm being used. (If the key length is greater, it
* will be replaced with its own digest, and key_len will be updated
* accordingly).
*/
void hmac_final ( struct digest_algorithm *digest, void *ctx, void *hmac ) {
hmac_context_t ( digest ) *hctx = ctx;
void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
void *key, size_t *key_len, void *hmac ) {
unsigned char k_opad[digest->blocksize];
unsigned int i;
/* Construct output pad from input pad */
for ( i = 0 ; i < sizeof ( hctx->pad ) ; i++ ) {
hctx->pad[i] ^= 0x6a;
}
/* Reduce key if necessary */
if ( *key_len > sizeof ( k_opad ) )
hmac_reduce_key ( digest, key, key_len );
/* Construct output pad */
memset ( k_opad, 0, sizeof ( k_opad ) );
memcpy ( k_opad, key, *key_len );
for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
k_opad[i] ^= 0x5c;
}
/* Finish inner hash */
digest_final ( digest, hctx->ctx, hmac );
digest_final ( digest, digest_ctx, hmac );
/* Perform outer hash */
digest_init ( digest, hctx->ctx );
digest_update ( digest, hctx->ctx, hctx->pad, sizeof ( hctx->pad ) );
digest_update ( digest, hctx->ctx, hmac, digest->digestsize );
digest_final ( digest, hctx->ctx, hmac );
/* Erase output pad (from which the key may be derivable) */
memset ( hctx->pad, 0, sizeof ( hctx->pad ) );
digest_init ( digest, digest_ctx );
digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
digest_update ( digest, digest_ctx, hmac, digest->digestsize );
digest_final ( digest, digest_ctx, hmac );
}

View File

@ -79,7 +79,7 @@ static void hmac_drbg_update_key ( struct digest_algorithm *hash,
struct hmac_drbg_state *state,
const void *data, size_t len,
const uint8_t single ) {
uint8_t context[ hmac_ctxsize ( hash ) ];
uint8_t context[ hash->ctxsize ];
size_t out_len = hash->digestsize;
DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state );
@ -92,11 +92,13 @@ static void hmac_drbg_update_key ( struct digest_algorithm *hash,
assert ( ( single == 0x00 ) || ( single == 0x01 ) );
/* K = HMAC ( K, V || single || provided_data ) */
hmac_init ( hash, context, state->key, out_len );
hmac_init ( hash, context, state->key, &out_len );
assert ( out_len == hash->digestsize );
hmac_update ( hash, context, state->value, out_len );
hmac_update ( hash, context, &single, sizeof ( single ) );
hmac_update ( hash, context, data, len );
hmac_final ( hash, context, state->key );
hmac_final ( hash, context, state->key, &out_len, state->key );
assert ( out_len == hash->digestsize );
DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || "
"provided_data ) :\n", hash->name, state, single );
@ -120,7 +122,7 @@ static void hmac_drbg_update_key ( struct digest_algorithm *hash,
*/
static void hmac_drbg_update_value ( struct digest_algorithm *hash,
struct hmac_drbg_state *state ) {
uint8_t context[ hmac_ctxsize ( hash ) ];
uint8_t context[ hash->ctxsize ];
size_t out_len = hash->digestsize;
/* Sanity checks */
@ -128,9 +130,11 @@ static void hmac_drbg_update_value ( struct digest_algorithm *hash,
assert ( state != NULL );
/* V = HMAC ( K, V ) */
hmac_init ( hash, context, state->key, out_len );
hmac_init ( hash, context, state->key, &out_len );
assert ( out_len == hash->digestsize );
hmac_update ( hash, context, state->value, out_len );
hmac_final ( hash, context, state->value );
hmac_final ( hash, context, state->key, &out_len, state->value );
assert ( out_len == hash->digestsize );
DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n",
hash->name, state );

View File

@ -27,65 +27,22 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/rsa.h>
#include <ipxe/aes.h>
#include <ipxe/sha1.h>
#include <ipxe/sha256.h>
#include <ipxe/tls.h>
/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA cipher suite */
struct tls_cipher_suite
tls_dhe_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 05 ) = {
.code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA1_DIGEST_SIZE,
.exchange = &tls_dhe_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
.handshake = &sha256_algorithm,
};
/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA cipher suite */
struct tls_cipher_suite
tls_dhe_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 06 ) = {
.code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA1_DIGEST_SIZE,
.exchange = &tls_dhe_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
.handshake = &sha256_algorithm,
};
/** TLS_RSA_WITH_AES_128_CBC_SHA cipher suite */
struct tls_cipher_suite
tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite ( 15 ) = {
struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha __tls_cipher_suite (03) = {
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA1_DIGEST_SIZE,
.exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
.handshake = &sha256_algorithm,
};
/** TLS_RSA_WITH_AES_256_CBC_SHA cipher suite */
struct tls_cipher_suite
tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite ( 16 ) = {
struct tls_cipher_suite tls_rsa_with_aes_256_cbc_sha __tls_cipher_suite (04) = {
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA1_DIGEST_SIZE,
.exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha1_algorithm,
.handshake = &sha256_algorithm,
};

View File

@ -29,62 +29,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/sha256.h>
#include <ipxe/tls.h>
/** TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
struct tls_cipher_suite
tls_dhe_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 03 ) = {
.code = htons ( TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA256_DIGEST_SIZE,
.exchange = &tls_dhe_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
.handshake = &sha256_algorithm,
};
/** TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
struct tls_cipher_suite
tls_dhe_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 04 ) = {
.code = htons ( TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA256_DIGEST_SIZE,
.exchange = &tls_dhe_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
.handshake = &sha256_algorithm,
};
/** TLS_RSA_WITH_AES_128_CBC_SHA256 cipher suite */
struct tls_cipher_suite
tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite ( 13 ) = {
struct tls_cipher_suite tls_rsa_with_aes_128_cbc_sha256 __tls_cipher_suite(01)={
.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA256_DIGEST_SIZE,
.exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
.handshake = &sha256_algorithm,
};
/** TLS_RSA_WITH_AES_256_CBC_SHA256 cipher suite */
struct tls_cipher_suite
tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite ( 14 ) = {
struct tls_cipher_suite tls_rsa_with_aes_256_cbc_sha256 __tls_cipher_suite(02)={
.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 0,
.record_iv_len = AES_BLOCKSIZE,
.mac_len = SHA256_DIGEST_SIZE,
.exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_cbc_algorithm,
.digest = &sha256_algorithm,
.handshake = &sha256_algorithm,
};

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <byteswap.h>
#include <ipxe/rsa.h>
#include <ipxe/aes.h>
#include <ipxe/sha256.h>
#include <ipxe/tls.h>
/** TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
struct tls_cipher_suite
tls_dhe_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 01 ) = {
.code = htons ( TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 4,
.record_iv_len = 8,
.mac_len = 0,
.exchange = &tls_dhe_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_gcm_algorithm,
.digest = &sha256_algorithm,
.handshake = &sha256_algorithm,
};
/** TLS_RSA_WITH_AES_128_GCM_SHA256 cipher suite */
struct tls_cipher_suite
tls_rsa_with_aes_128_gcm_sha256 __tls_cipher_suite ( 11 ) = {
.code = htons ( TLS_RSA_WITH_AES_128_GCM_SHA256 ),
.key_len = ( 128 / 8 ),
.fixed_iv_len = 4,
.record_iv_len = 8,
.mac_len = 0,
.exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_gcm_algorithm,
.digest = &sha256_algorithm,
.handshake = &sha256_algorithm,
};

View File

@ -1,60 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <byteswap.h>
#include <ipxe/rsa.h>
#include <ipxe/aes.h>
#include <ipxe/sha512.h>
#include <ipxe/tls.h>
/** TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
struct tls_cipher_suite
tls_dhe_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 02 ) = {
.code = htons ( TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 4,
.record_iv_len = 8,
.mac_len = 0,
.exchange = &tls_dhe_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_gcm_algorithm,
.digest = &sha384_algorithm,
.handshake = &sha384_algorithm,
};
/** TLS_RSA_WITH_AES_256_GCM_SHA384 cipher suite */
struct tls_cipher_suite
tls_rsa_with_aes_256_gcm_sha384 __tls_cipher_suite ( 12 ) = {
.code = htons ( TLS_RSA_WITH_AES_256_GCM_SHA384 ),
.key_len = ( 256 / 8 ),
.fixed_iv_len = 4,
.record_iv_len = 8,
.mac_len = 0,
.exchange = &tls_pubkey_exchange_algorithm,
.pubkey = &rsa_algorithm,
.cipher = &aes_gcm_algorithm,
.digest = &sha384_algorithm,
.handshake = &sha384_algorithm,
};

View File

@ -117,9 +117,10 @@ void ntlm_key ( const char *domain, const char *username,
struct digest_algorithm *md5 = &md5_algorithm;
union {
uint8_t md4[MD4_CTX_SIZE];
uint8_t md5[ MD5_CTX_SIZE + MD5_BLOCK_SIZE ];
uint8_t md5[MD5_CTX_SIZE];
} ctx;
uint8_t digest[MD4_DIGEST_SIZE];
size_t digest_len;
uint8_t c;
uint16_t wc;
@ -140,7 +141,8 @@ void ntlm_key ( const char *domain, const char *username,
digest_final ( md4, ctx.md4, digest );
/* Construct HMAC-MD5 of (Unicode) upper-case username */
hmac_init ( md5, ctx.md5, digest, sizeof ( digest ) );
digest_len = sizeof ( digest );
hmac_init ( md5, ctx.md5, digest, &digest_len );
while ( ( c = *(username++) ) ) {
wc = cpu_to_le16 ( toupper ( c ) );
hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
@ -149,7 +151,7 @@ void ntlm_key ( const char *domain, const char *username,
wc = cpu_to_le16 ( c );
hmac_update ( md5, ctx.md5, &wc, sizeof ( wc ) );
}
hmac_final ( md5, ctx.md5, key->raw );
hmac_final ( md5, ctx.md5, digest, &digest_len, key->raw );
DBGC ( key, "NTLM key:\n" );
DBGC_HDA ( key, 0, key, sizeof ( *key ) );
}
@ -168,7 +170,8 @@ void ntlm_response ( struct ntlm_challenge_info *info, struct ntlm_key *key,
struct ntlm_nt_response *nt ) {
struct digest_algorithm *md5 = &md5_algorithm;
struct ntlm_nonce tmp_nonce;
uint8_t ctx[ MD5_CTX_SIZE + MD5_BLOCK_SIZE ];
uint8_t ctx[MD5_CTX_SIZE];
size_t key_len = sizeof ( *key );
unsigned int i;
/* Generate random nonce, if needed */
@ -180,10 +183,10 @@ void ntlm_response ( struct ntlm_challenge_info *info, struct ntlm_key *key,
/* Construct LAN Manager response */
memcpy ( &lm->nonce, nonce, sizeof ( lm->nonce ) );
hmac_init ( md5, ctx, key->raw, sizeof ( *key ) );
hmac_init ( md5, ctx, key->raw, &key_len );
hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
hmac_update ( md5, ctx, &lm->nonce, sizeof ( lm->nonce ) );
hmac_final ( md5, ctx, lm->digest );
hmac_final ( md5, ctx, key->raw, &key_len, lm->digest );
DBGC ( key, "NTLM LAN Manager response:\n" );
DBGC_HDA ( key, 0, lm, sizeof ( *lm ) );
@ -192,14 +195,14 @@ void ntlm_response ( struct ntlm_challenge_info *info, struct ntlm_key *key,
nt->version = NTLM_VERSION_NTLMV2;
nt->high = NTLM_VERSION_NTLMV2;
memcpy ( &nt->nonce, nonce, sizeof ( nt->nonce ) );
hmac_init ( md5, ctx, key->raw, sizeof ( *key ) );
hmac_init ( md5, ctx, key->raw, &key_len );
hmac_update ( md5, ctx, info->nonce, sizeof ( *info->nonce ) );
hmac_update ( md5, ctx, &nt->version,
( sizeof ( *nt ) -
offsetof ( typeof ( *nt ), version ) ) );
hmac_update ( md5, ctx, info->target, info->len );
hmac_update ( md5, ctx, &nt->zero, sizeof ( nt->zero ) );
hmac_final ( md5, ctx, nt->digest );
hmac_final ( md5, ctx, key->raw, &key_len, nt->digest );
DBGC ( key, "NTLM NT response prefix:\n" );
DBGC_HDA ( key, 0, nt, sizeof ( *nt ) );
}

View File

@ -49,7 +49,7 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
u8 *in_blknr; /* pointer to last byte of in, block number */
u8 out[SHA1_DIGEST_SIZE]; /* HMAC-SHA1 result */
u8 ctx[SHA1_CTX_SIZE + SHA1_BLOCK_SIZE]; /* HMAC-SHA1 context */
u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
const size_t label_len = strlen ( label );
/* The HMAC-SHA-1 is calculated using the given key on the
@ -65,9 +65,9 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label,
for ( blk = 0 ;; blk++ ) {
*in_blknr = blk;
hmac_init ( &sha1_algorithm, ctx, keym, key_len );
hmac_update ( &sha1_algorithm, ctx, in, sizeof ( in ) );
hmac_final ( &sha1_algorithm, ctx, out );
hmac_init ( &sha1_algorithm, sha1_ctx, keym, &key_len );
hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
if ( prf_len <= sizeof ( out ) ) {
memcpy ( prf, out, prf_len );
@ -100,7 +100,7 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
u8 pass[pass_len]; /* modifiable passphrase */
u8 in[salt_len + 4]; /* input buffer to first round */
u8 last[SHA1_DIGEST_SIZE]; /* output of round N, input of N+1 */
u8 ctx[SHA1_CTX_SIZE + SHA1_BLOCK_SIZE];
u8 sha1_ctx[SHA1_CTX_SIZE];
u8 *next_in = in; /* changed to `last' after first round */
int next_size = sizeof ( in );
int i;
@ -114,9 +114,9 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
memset ( block, 0, sizeof ( last ) );
for ( i = 0; i < iterations; i++ ) {
hmac_init ( &sha1_algorithm, ctx, pass, pass_len );
hmac_update ( &sha1_algorithm, ctx, next_in, next_size );
hmac_final ( &sha1_algorithm, ctx, last );
hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
for ( j = 0; j < sizeof ( last ); j++ ) {
block[j] ^= last[j];

View File

@ -1,267 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/uaccess.h>
#include <ipxe/ecam.h>
/** @file
*
* PCI Enhanced Configuration Access Mechanism (ECAM)
*
*/
/** Cached mapped ECAM allocation */
static struct ecam_mapping ecam;
/**
* Find lowest ECAM allocation not below a given PCI bus:dev.fn address
*
* @v busdevfn PCI bus:dev.fn address
* @v range PCI device address range to fill in
* @v alloc ECAM allocation to fill in, or NULL
* @ret rc Return status code
*/
static int ecam_find ( uint32_t busdevfn, struct pci_range *range,
struct ecam_allocation *alloc ) {
struct ecam_allocation tmp;
unsigned int best = 0;
unsigned int offset;
unsigned int count;
unsigned int index;
userptr_t mcfg;
uint32_t length;
uint32_t start;
/* Return empty range on error */
range->count = 0;
/* Locate MCFG table */
mcfg = acpi_table ( ECAM_SIGNATURE, 0 );
if ( ! mcfg ) {
DBGC ( &ecam, "ECAM found no MCFG table\n" );
return -ENOTSUP;
}
/* Get length of table */
copy_from_user ( &length, mcfg,
offsetof ( struct ecam_table, acpi.length ),
sizeof ( length ) );
/* Iterate over allocations */
for ( offset = offsetof ( struct ecam_table, alloc ) ;
( offset + sizeof ( tmp ) ) <= le32_to_cpu ( length ) ;
offset += sizeof ( tmp ) ) {
/* Read allocation */
copy_from_user ( &tmp, mcfg, offset, sizeof ( tmp ) );
DBGC2 ( &ecam, "ECAM %04x:[%02x-%02x] has base %08llx\n",
le16_to_cpu ( tmp.segment ), tmp.start, tmp.end,
( ( unsigned long long ) le64_to_cpu ( tmp.base ) ) );
start = PCI_BUSDEVFN ( le16_to_cpu ( tmp.segment ),
tmp.start, 0, 0 );
count = PCI_BUSDEVFN ( 0, ( tmp.end - tmp.start + 1 ), 0, 0 );
/* Check for a matching or new closest allocation */
index = ( busdevfn - start );
if ( ( index < count ) || ( index > best ) ) {
if ( alloc )
memcpy ( alloc, &tmp, sizeof ( *alloc ) );
range->start = start;
range->count = count;
best = index;
}
/* Stop if this range contains the target bus:dev.fn address */
if ( index < count )
return 0;
}
return ( best ? 0 : -ENOENT );
}
/**
* Find next PCI bus:dev.fn address range in system
*
* @v busdevfn Starting PCI bus:dev.fn address
* @v range PCI bus:dev.fn address range to fill in
*/
static void ecam_discover ( uint32_t busdevfn, struct pci_range *range ) {
/* Find new range, if any */
ecam_find ( busdevfn, range, NULL );
}
/**
* Access configuration space for PCI device
*
* @v pci PCI device
* @ret rc Return status code
*/
static int ecam_access ( struct pci_device *pci ) {
uint64_t base;
size_t len;
int rc;
/* Reuse mapping if possible */
if ( ( pci->busdevfn - ecam.range.start ) < ecam.range.count )
return 0;
/* Clear any existing mapping */
if ( ecam.regs ) {
iounmap ( ecam.regs );
ecam.regs = NULL;
}
/* Find allocation for this PCI device */
if ( ( rc = ecam_find ( pci->busdevfn, &ecam.range,
&ecam.alloc ) ) != 0 ) {
DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT ": %s\n",
PCI_ARGS ( pci ), strerror ( rc ) );
goto err_find;
}
if ( ecam.range.start > pci->busdevfn ) {
DBGC ( &ecam, "ECAM found no allocation for " PCI_FMT "\n",
PCI_ARGS ( pci ) );
goto err_find;
}
/* Map configuration space for this allocation */
base = le64_to_cpu ( ecam.alloc.base );
len = ( ecam.range.count * ECAM_SIZE );
ecam.regs = ioremap ( base, len );
if ( ! ecam.regs ) {
DBGC ( &ecam, "ECAM %04x:[%02x-%02x] could not map "
"[%08llx,%08llx)\n", le16_to_cpu ( ecam.alloc.segment ),
ecam.alloc.start, ecam.alloc.end, base, ( base + len ) );
rc = -ENODEV;
goto err_ioremap;
}
/* Populate cached mapping */
DBGC ( &ecam, "ECAM %04x:[%02x-%02x] mapped [%08llx,%08llx) -> %p\n",
le16_to_cpu ( ecam.alloc.segment ), ecam.alloc.start,
ecam.alloc.end, base, ( base + len ), ecam.regs );
return 0;
iounmap ( ecam.regs );
err_ioremap:
err_find:
ecam.range.count = 0;
return rc;
}
/**
* Read from PCI configuration space
*
* @v pci PCI device
* @v location Offset and length within PCI configuration space
* @v value Value read
* @ret rc Return status code
*/
int ecam_read ( struct pci_device *pci, unsigned int location, void *value ) {
unsigned int where = ECAM_WHERE ( location );
unsigned int len = ECAM_LEN ( location );
unsigned int index;
void *addr;
int rc;
/* Return all-ones on error */
memset ( value, 0xff, len );
/* Access configuration space */
if ( ( rc = ecam_access ( pci ) ) != 0 )
return rc;
/* Read from address */
index = ( pci->busdevfn - ecam.range.start );
addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
switch ( len ) {
case 4:
*( ( uint32_t *) value ) = readl ( addr );
break;
case 2:
*( ( uint16_t *) value ) = readw ( addr );
break;
case 1:
*( ( uint8_t *) value ) = readb ( addr );
break;
default:
assert ( 0 );
}
return 0;
}
/**
* Write to PCI configuration space
*
* @v pci PCI device
* @v location Offset and length within PCI configuration space
* @v value Value to write
* @ret rc Return status code
*/
int ecam_write ( struct pci_device *pci, unsigned int location,
unsigned long value ) {
unsigned int where = ECAM_WHERE ( location );
unsigned int len = ECAM_LEN ( location );
unsigned int index;
void *addr;
int rc;
/* Access configuration space */
if ( ( rc = ecam_access ( pci ) ) != 0 )
return rc;
/* Read from address */
index = ( pci->busdevfn - ecam.range.start );
addr = ( ecam.regs + ( index * ECAM_SIZE ) + where );
switch ( len ) {
case 4:
writel ( value, addr );
break;
case 2:
writew ( value, addr );
break;
case 1:
writeb ( value, addr );
break;
default:
assert ( 0 );
}
return 0;
}
PROVIDE_PCIAPI ( ecam, pci_discover, ecam_discover );
PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( ecam, pci_read_config_dword );
PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( ecam, pci_write_config_dword );
PROVIDE_PCIAPI_INLINE ( ecam, pci_ioremap );
struct pci_api ecam_api = PCIAPI_RUNTIME ( ecam );

View File

@ -121,11 +121,6 @@ static void pci_read_bases ( struct pci_device *pci ) {
unsigned long bar;
int reg;
/* Clear any existing base addresses */
pci->ioaddr = 0;
pci->membase = 0;
/* Get first memory and I/O BAR addresses */
for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4 ) {
bar = pci_bar ( pci, reg );
if ( bar & PCI_BASE_ADDRESS_SPACE_IO ) {
@ -229,55 +224,46 @@ int pci_read_config ( struct pci_device *pci ) {
*
* @v pci PCI device to fill in
* @v busdevfn Starting bus:dev.fn address
* @ret busdevfn Bus:dev.fn address of next PCI device
* @ret rc Return status code
* @ret busdevfn Bus:dev.fn address of next PCI device, or negative error
*/
int pci_find_next ( struct pci_device *pci, uint32_t *busdevfn ) {
static struct pci_range range;
int pci_find_next ( struct pci_device *pci, unsigned int busdevfn ) {
static unsigned int end;
unsigned int sub_end;
uint8_t hdrtype;
uint8_t sub;
uint32_t end;
unsigned int count;
int rc;
/* Determine number of PCI buses */
if ( ! end )
end = PCI_BUSDEVFN ( 0, pci_num_bus(), 0, 0 );
/* Find next PCI device, if any */
do {
/* Find next PCI bus:dev.fn address range, if necessary */
if ( ( *busdevfn - range.start ) >= range.count ) {
pci_discover ( *busdevfn, &range );
if ( *busdevfn < range.start )
*busdevfn = range.start;
if ( ( *busdevfn - range.start ) >= range.count )
break;
}
for ( ; busdevfn < end ; busdevfn++ ) {
/* Check for PCI device existence */
memset ( pci, 0, sizeof ( *pci ) );
pci_init ( pci, *busdevfn );
pci_init ( pci, busdevfn );
if ( ( rc = pci_read_config ( pci ) ) != 0 )
continue;
/* If device is a bridge, expand the PCI bus:dev.fn
* address range as needed.
/* If device is a bridge, expand the number of PCI
* buses as needed.
*/
pci_read_config_byte ( pci, PCI_HEADER_TYPE, &hdrtype );
hdrtype &= PCI_HEADER_TYPE_MASK;
if ( hdrtype == PCI_HEADER_TYPE_BRIDGE ) {
pci_read_config_byte ( pci, PCI_SUBORDINATE, &sub );
end = PCI_BUSDEVFN ( PCI_SEG ( *busdevfn ),
( sub + 1 ), 0, 0 );
count = ( end - range.start );
if ( count > range.count ) {
sub_end = PCI_BUSDEVFN ( 0, ( sub + 1 ), 0, 0 );
if ( end < sub_end ) {
DBGC ( pci, PCI_FMT " found subordinate bus "
"%#02x\n", PCI_ARGS ( pci ), sub );
range.count = count;
end = sub_end;
}
}
/* Return this device */
return 0;
} while ( ++(*busdevfn) );
return busdevfn;
}
return -ENODEV;
}
@ -357,10 +343,11 @@ void pci_remove ( struct pci_device *pci ) {
*/
static int pcibus_probe ( struct root_device *rootdev ) {
struct pci_device *pci = NULL;
uint32_t busdevfn = 0;
int busdevfn = 0;
int rc;
do {
for ( busdevfn = 0 ; 1 ; busdevfn++ ) {
/* Allocate struct pci_device */
if ( ! pci )
pci = malloc ( sizeof ( *pci ) );
@ -370,7 +357,8 @@ static int pcibus_probe ( struct root_device *rootdev ) {
}
/* Find next PCI device, if any */
if ( ( rc = pci_find_next ( pci, &busdevfn ) ) != 0 )
busdevfn = pci_find_next ( pci, busdevfn );
if ( busdevfn < 0 )
break;
/* Look for a driver */
@ -393,8 +381,7 @@ static int pcibus_probe ( struct root_device *rootdev ) {
/* Not registered; re-use struct pci_device */
list_del ( &pci->dev.siblings );
}
} while ( ++busdevfn );
}
free ( pci );
return 0;

View File

@ -61,15 +61,14 @@ pci_backup_excluded ( struct pci_device *pci, unsigned int offset,
*
* @v pci PCI device
* @v backup PCI configuration space backup
* @v limit Maximum offset in PCI configuration space
* @v exclude PCI configuration space backup exclusion list, or NULL
*/
void pci_backup ( struct pci_device *pci, struct pci_config_backup *backup,
unsigned int limit, const uint8_t *exclude ) {
const uint8_t *exclude ) {
unsigned int offset;
uint32_t *dword;
for ( offset = 0, dword = backup->dwords ; offset < limit ;
for ( offset = 0, dword = backup->dwords ; offset < 0x100 ;
offset += sizeof ( *dword ) , dword++ ) {
if ( ! pci_backup_excluded ( pci, offset, exclude ) )
pci_read_config_dword ( pci, offset, dword );
@ -81,15 +80,14 @@ void pci_backup ( struct pci_device *pci, struct pci_config_backup *backup,
*
* @v pci PCI device
* @v backup PCI configuration space backup
* @v limit Maximum offset in PCI configuration space
* @v exclude PCI configuration space backup exclusion list, or NULL
*/
void pci_restore ( struct pci_device *pci, struct pci_config_backup *backup,
unsigned int limit, const uint8_t *exclude ) {
const uint8_t *exclude ) {
unsigned int offset;
uint32_t *dword;
for ( offset = 0, dword = backup->dwords ; offset < limit ;
for ( offset = 0, dword = backup->dwords ; offset < 0x100 ;
offset += sizeof ( *dword ) , dword++ ) {
if ( ! pci_backup_excluded ( pci, offset, exclude ) )
pci_write_config_dword ( pci, offset, *dword );

View File

@ -1,132 +0,0 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include <byteswap.h>
#include <ipxe/pci.h>
#include <ipxe/pcibridge.h>
/** @file
*
* PCI-to-PCI bridge
*
*/
/** List of all PCI bridges */
static LIST_HEAD ( pcibridges );
/**
* Find bridge attached to a PCI device
*
* @v pci PCI device
* @ret bridge PCI bridge, or NULL
*/
struct pci_bridge * pcibridge_find ( struct pci_device *pci ) {
unsigned int bus = PCI_BUS ( pci->busdevfn );
struct pci_bridge *bridge;
/* Find matching bridge */
list_for_each_entry ( bridge, &pcibridges, list ) {
if ( bus == bridge->secondary )
return bridge;
}
return NULL;
}
/**
* Probe PCI device
*
* @v pci PCI device
* @ret rc Return status code
*/
static int pcibridge_probe ( struct pci_device *pci ) {
struct pci_bridge *bridge;
uint16_t base;
uint16_t limit;
int rc;
/* Allocate and initialise structure */
bridge = zalloc ( sizeof ( *bridge ) );
if ( ! bridge ) {
rc = -ENOMEM;
goto err_alloc;
}
bridge->pci = pci;
/* Read configuration */
pci_read_config_dword ( pci, PCI_PRIMARY, &bridge->buses );
cpu_to_le32s ( &buses );
pci_read_config_word ( pci, PCI_MEM_BASE, &base );
bridge->membase = ( ( base & ~PCI_MEM_MASK ) << 16 );
pci_read_config_word ( pci, PCI_MEM_LIMIT, &limit );
bridge->memlimit = ( ( ( ( limit | PCI_MEM_MASK ) + 1 ) << 16 ) - 1 );
DBGC ( bridge, "BRIDGE " PCI_FMT " bus %02x to [%02x,%02x) mem "
"[%08x,%08x)\n", PCI_ARGS ( pci ), bridge->primary,
bridge->secondary, bridge->subordinate, bridge->membase,
bridge->memlimit );
/* Add to list of PCI bridges */
list_add ( &bridge->list, &pcibridges );
pci_set_drvdata ( pci, bridge );
return 0;
free ( bridge );
err_alloc:
return rc;
}
/**
* Remove PCI device
*
* @v pci PCI device
*/
static void pcibridge_remove ( struct pci_device *pci ) {
struct pci_bridge *bridge = pci_get_drvdata ( pci );
/* Remove from list of bridges */
list_del ( &bridge->list );
/* Free device */
free ( bridge );
}
/** Bridge PCI device IDs */
static struct pci_device_id pcibridge_ids[] = {
PCI_ROM ( 0xffff, 0xffff, "bridge", "Bridge", 0 ),
};
/** Bridge PCI driver */
struct pci_driver pcibridge_driver __pci_driver = {
.ids = pcibridge_ids,
.id_count = ( sizeof ( pcibridge_ids ) / sizeof ( pcibridge_ids[0] ) ),
.class = PCI_CLASS_ID ( PCI_CLASS_BRIDGE, PCI_CLASS_BRIDGE_PCI,
PCI_ANY_ID ),
.probe = pcibridge_probe,
.remove = pcibridge_remove,
};

View File

@ -1,9 +1,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <ipxe/timer.h>
#include <ipxe/pci.h>
#include <ipxe/pcibackup.h>
static int pci_find_capability_common ( struct pci_device *pci,
uint8_t pos, int cap ) {
@ -114,28 +112,3 @@ unsigned long pci_bar_size ( struct pci_device *pci, unsigned int reg ) {
size = size & ~( size - 1 );
return size;
}
/**
* Perform PCI Express function-level reset (FLR)
*
* @v pci PCI device
* @v exp PCI Express Capability address
*/
void pci_reset ( struct pci_device *pci, unsigned int exp ) {
struct pci_config_backup backup;
uint16_t control;
/* Back up configuration space */
pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_STANDARD, NULL );
/* Perform a PCIe function-level reset */
pci_read_config_word ( pci, ( exp + PCI_EXP_DEVCTL ), &control );
control |= PCI_EXP_DEVCTL_FLR;
pci_write_config_word ( pci, ( exp + PCI_EXP_DEVCTL ), control );
/* Allow time for reset to complete */
mdelay ( PCI_EXP_FLR_DELAY_MS );
/* Restore configuration */
pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_STANDARD, NULL );
}

View File

@ -17,47 +17,37 @@
#include "ipxe/io.h"
#include "ipxe/iomap.h"
#include "ipxe/pci.h"
#include "ipxe/dma.h"
#include "ipxe/reboot.h"
#include "ipxe/virtio-pci.h"
#include "ipxe/virtio-ring.h"
static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num, size_t header_size)
static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num)
{
size_t ring_size = PAGE_MASK + vring_size(num);
size_t queue_size = PAGE_MASK + vring_size(num);
size_t vdata_size = num * sizeof(void *);
size_t queue_size = ring_size + vdata_size + header_size;
vq->queue = dma_alloc(vq->dma, &vq->map, queue_size, queue_size);
vq->queue = zalloc(queue_size + vdata_size);
if (!vq->queue) {
return -ENOMEM;
}
memset ( vq->queue, 0, queue_size );
vq->queue_size = queue_size;
/* vdata immediately follows the ring */
vq->vdata = (void **)(vq->queue + ring_size);
/* empty header immediately follows vdata */
vq->empty_header = (struct virtio_net_hdr_modern *)(vq->queue + ring_size + vdata_size);
vq->vdata = (void **)(vq->queue + queue_size);
return 0;
}
void vp_free_vq(struct vring_virtqueue *vq)
{
if (vq->queue && vq->queue_size) {
dma_free(&vq->map, vq->queue, vq->queue_size);
if (vq->queue) {
free(vq->queue);
vq->queue = NULL;
vq->vdata = NULL;
vq->queue_size = 0;
}
}
int vp_find_vq(unsigned int ioaddr, int queue_index,
struct vring_virtqueue *vq, struct dma_device *dma_dev,
size_t header_size)
struct vring_virtqueue *vq)
{
struct vring * vr = &vq->vring;
u16 num;
@ -83,10 +73,9 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
}
vq->queue_index = queue_index;
vq->dma = dma_dev;
/* initialize the queue */
rc = vp_alloc_vq(vq, num, header_size);
rc = vp_alloc_vq(vq, num);
if (rc) {
DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n");
return rc;
@ -98,7 +87,8 @@ int vp_find_vq(unsigned int ioaddr, int queue_index,
* NOTE: vr->desc is initialized by vring_init()
*/
outl(dma(&vq->map, vr->desc) >> PAGE_SHIFT, ioaddr + VIRTIO_PCI_QUEUE_PFN);
outl((unsigned long)virt_to_phys(vr->desc) >> PAGE_SHIFT,
ioaddr + VIRTIO_PCI_QUEUE_PFN);
return num;
}
@ -358,8 +348,7 @@ void vpm_notify(struct virtio_pci_modern_device *vdev,
}
int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
unsigned nvqs, struct vring_virtqueue *vqs,
struct dma_device *dma_dev, size_t header_size)
unsigned nvqs, struct vring_virtqueue *vqs)
{
unsigned i;
struct vring_virtqueue *vq;
@ -403,12 +392,11 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
vq = &vqs[i];
vq->queue_index = i;
vq->dma = dma_dev;
/* get offset of notification word for this vq */
off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off));
err = vp_alloc_vq(vq, size, header_size);
err = vp_alloc_vq(vq, size);
if (err) {
DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev);
return err;
@ -418,16 +406,13 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev,
/* activate the queue */
vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size));
vpm_iowrite64(vdev, &vdev->common,
dma(&vq->map, vq->vring.desc),
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.desc),
COMMON_OFFSET(queue_desc_lo),
COMMON_OFFSET(queue_desc_hi));
vpm_iowrite64(vdev, &vdev->common,
dma(&vq->map, vq->vring.avail),
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.avail),
COMMON_OFFSET(queue_avail_lo),
COMMON_OFFSET(queue_avail_hi));
vpm_iowrite64(vdev, &vdev->common,
dma(&vq->map, vq->vring.used),
vpm_iowrite64(vdev, &vdev->common, virt_to_phys(vq->vring.used),
COMMON_OFFSET(queue_used_lo),
COMMON_OFFSET(queue_used_hi));

View File

@ -98,7 +98,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
for (i = head; out; i = vr->desc[i].next, out--) {
vr->desc[i].flags = VRING_DESC_F_NEXT;
vr->desc[i].addr = list->addr;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].len = list->length;
prev = i;
list++;
@ -106,7 +106,7 @@ void vring_add_buf(struct vring_virtqueue *vq,
for ( ; in; i = vr->desc[i].next, in--) {
vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
vr->desc[i].addr = list->addr;
vr->desc[i].addr = (u64)virt_to_phys(list->addr);
vr->desc[i].len = list->length;
prev = i;
list++;

View File

@ -2561,7 +2561,7 @@ static void arbel_reset ( struct arbel *arbel ) {
unsigned int i;
/* Perform device reset and preserve PCI configuration */
pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_ALL, backup_exclude );
pci_backup ( pci, &backup, backup_exclude );
writel ( ARBEL_RESET_MAGIC,
( arbel->config + ARBEL_RESET_OFFSET ) );
for ( i = 0 ; i < ARBEL_RESET_WAIT_TIME_MS ; i++ ) {
@ -2570,7 +2570,7 @@ static void arbel_reset ( struct arbel *arbel ) {
if ( vendor != 0xffff )
break;
}
pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_ALL, backup_exclude );
pci_restore ( pci, &backup, backup_exclude );
}
/**

View File

@ -2647,7 +2647,6 @@ static struct pci_device_id golan_nics[] = {
PCI_ROM ( 0x15b3, 0x1021, "ConnectX-7", "ConnectX-7 HCA driver, DevID 4129", 0 ),
PCI_ROM ( 0x15b3, 0xa2d2, "BlueField", "BlueField integrated ConnectX-5 network controller HCA driver, DevID 41682", 0 ),
PCI_ROM ( 0x15b3, 0xa2d6, "BlueField-2", "BlueField-2 network controller HCA driver, DevID 41686", 0 ),
PCI_ROM ( 0x15b3, 0xa2dc, "BlueField-3", "BlueField-3 network controller HCA driver, DevID 41692", 0 ),
};
struct pci_driver golan_driver __pci_driver = {

View File

@ -2840,7 +2840,7 @@ static int hermon_reset ( struct hermon *hermon ) {
hermon->toggle = 0;
/* Perform device reset and preserve PCI configuration */
pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_ALL, backup_exclude );
pci_backup ( pci, &backup, backup_exclude );
writel ( HERMON_RESET_MAGIC,
( hermon->config + HERMON_RESET_OFFSET ) );
@ -2852,8 +2852,7 @@ static int hermon_reset ( struct hermon *hermon ) {
if ( vendor == pci->vendor ) {
/* Restore PCI configuration */
pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_ALL,
backup_exclude );
pci_restore ( pci, &backup, backup_exclude );
DBGC ( hermon, "Hermon %p reset after %dms\n",
hermon, i );

View File

@ -2256,7 +2256,7 @@ static void qib7322_reset ( struct qib7322 *qib7322, struct pci_device *pci ) {
struct pci_config_backup backup;
/* Back up PCI configuration space */
pci_backup ( pci, &backup, PCI_CONFIG_BACKUP_ALL, NULL );
pci_backup ( pci, &backup, NULL );
/* Assert reset */
memset ( &control, 0, sizeof ( control ) );
@ -2267,7 +2267,7 @@ static void qib7322_reset ( struct qib7322 *qib7322, struct pci_device *pci ) {
mdelay ( 1000 );
/* Restore PCI configuration space */
pci_restore ( pci, &backup, PCI_CONFIG_BACKUP_ALL, NULL );
pci_restore ( pci, &backup, NULL );
}
/**

View File

@ -30,7 +30,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/if_ether.h>
#include <ipxe/base16.h>
#include <ipxe/profile.h>
#include <ipxe/acpimac.h>
#include <ipxe/usb.h>
#include "ecm.h"
@ -82,17 +81,14 @@ ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
/**
* Get hardware MAC address
*
* @v func USB function
* @v usb USB device
* @v desc Ethernet functional descriptor
* @v netdev Network device
* @v hw_addr Hardware address to fill in
* @ret rc Return status code
*/
int ecm_fetch_mac ( struct usb_function *func,
struct ecm_ethernet_descriptor *desc,
struct net_device *netdev ) {
struct usb_device *usb = func->usb;
int ecm_fetch_mac ( struct usb_device *usb,
struct ecm_ethernet_descriptor *desc, uint8_t *hw_addr ) {
char buf[ base16_encoded_len ( ETH_ALEN ) + 1 /* NUL */ ];
uint8_t amac[ETH_ALEN];
int len;
int rc;
@ -107,28 +103,19 @@ int ecm_fetch_mac ( struct usb_function *func,
/* Sanity check */
if ( len != ( ( int ) ( sizeof ( buf ) - 1 /* NUL */ ) ) ) {
DBGC ( usb, "USB %s has invalid ECM MAC \"%s\"\n",
func->name, buf );
usb->name, buf );
return -EINVAL;
}
/* Decode MAC address */
len = base16_decode ( buf, netdev->hw_addr, ETH_ALEN );
len = base16_decode ( buf, hw_addr, ETH_ALEN );
if ( len < 0 ) {
rc = len;
DBGC ( usb, "USB %s could not decode ECM MAC \"%s\": %s\n",
func->name, buf, strerror ( rc ) );
usb->name, buf, strerror ( rc ) );
return rc;
}
/* Apply system-specific MAC address as current link-layer
* address, if present.
*/
if ( ( rc = acpi_mac ( amac ) ) == 0 ) {
memcpy ( netdev->ll_addr, amac, ETH_ALEN );
DBGC ( usb, "USB %s using system-specific MAC %s\n",
func->name, eth_ntoa ( netdev->ll_addr ) );
}
return 0;
}
@ -477,7 +464,7 @@ static int ecm_probe ( struct usb_function *func,
}
/* Fetch MAC address */
if ( ( rc = ecm_fetch_mac ( func, ethernet, netdev ) ) != 0 ) {
if ( ( rc = ecm_fetch_mac ( usb, ethernet, netdev->hw_addr ) ) != 0 ) {
DBGC ( ecm, "ECM %p could not fetch MAC address: %s\n",
ecm, strerror ( rc ) );
goto err_fetch_mac;

View File

@ -86,8 +86,8 @@ struct ecm_device {
extern struct ecm_ethernet_descriptor *
ecm_ethernet_descriptor ( struct usb_configuration_descriptor *config,
struct usb_interface_descriptor *interface );
extern int ecm_fetch_mac ( struct usb_function *func,
extern int ecm_fetch_mac ( struct usb_device *usb,
struct ecm_ethernet_descriptor *desc,
struct net_device *netdev );
uint8_t *hw_addr );
#endif /* _ECM_H */

View File

@ -222,7 +222,7 @@ static int nii_pci_open ( struct nii_nic *nii ) {
/* Locate PCI I/O protocol */
if ( ( rc = efi_locate_device ( device, &efi_pci_io_protocol_guid,
&pci_device, 0 ) ) != 0 ) {
&pci_device ) ) != 0 ) {
DBGC ( nii, "NII %s could not locate PCI I/O protocol: %s\n",
nii->dev.name, strerror ( rc ) );
goto err_locate;
@ -576,7 +576,7 @@ static int nii_issue_cpb_db ( struct nii_nic *nii, unsigned int op, void *cpb,
cdb.IFnum = nii->nii->IfNum;
/* Raise task priority level */
tpl = bs->RaiseTPL ( efi_internal_tpl );
tpl = bs->RaiseTPL ( TPL_CALLBACK );
/* Issue command */
DBGC2 ( nii, "NII %s issuing %02x:%04x ifnum %d%s%s\n",
@ -921,17 +921,18 @@ static int nii_set_station_address ( struct nii_nic *nii,
* Set receive filters
*
* @v nii NII NIC
* @v flags Flags
* @ret rc Return status code
*/
static int nii_set_rx_filters ( struct nii_nic *nii, unsigned int flags ) {
static int nii_set_rx_filters ( struct nii_nic *nii ) {
uint32_t implementation = nii->undi->Implementation;
unsigned int flags;
unsigned int op;
int stat;
int rc;
/* Construct receive filter set */
flags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
flags = ( PXE_OPFLAGS_RECEIVE_FILTER_ENABLE |
PXE_OPFLAGS_RECEIVE_FILTER_UNICAST );
if ( implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED )
flags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
if ( implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED )
@ -943,40 +944,14 @@ static int nii_set_rx_filters ( struct nii_nic *nii, unsigned int flags ) {
op = NII_OP ( PXE_OPCODE_RECEIVE_FILTERS, flags );
if ( ( stat = nii_issue ( nii, op ) ) < 0 ) {
rc = -EIO_STAT ( stat );
DBGC ( nii, "NII %s could not %s%sable receive filters "
"%#04x: %s\n", nii->dev.name,
( ( flags & PXE_OPFLAGS_RECEIVE_FILTER_ENABLE ) ?
"en" : "" ),
( ( flags & PXE_OPFLAGS_RECEIVE_FILTER_DISABLE ) ?
"dis" : "" ), flags, strerror ( rc ) );
DBGC ( nii, "NII %s could not set receive filters %#04x: %s\n",
nii->dev.name, flags, strerror ( rc ) );
return rc;
}
return 0;
}
/**
* Enable receive filters
*
* @v nii NII NIC
* @ret rc Return status code
*/
static int nii_enable_rx_filters ( struct nii_nic *nii ) {
return nii_set_rx_filters ( nii, PXE_OPFLAGS_RECEIVE_FILTER_ENABLE );
}
/**
* Disable receive filters
*
* @v nii NII NIC
* @ret rc Return status code
*/
static int nii_disable_rx_filters ( struct nii_nic *nii ) {
return nii_set_rx_filters ( nii, PXE_OPFLAGS_RECEIVE_FILTER_DISABLE );
}
/**
* Transmit packet
*
@ -1200,25 +1175,13 @@ static int nii_open ( struct net_device *netdev ) {
/* Treat as non-fatal */
}
/* Disable receive filters
*
* We have no reason to disable receive filters here (or
* anywhere), but some NII drivers have a bug which prevents
* packets from being received unless we attempt to disable
* the receive filters.
*
* Ignore any failures, since we genuinely don't care if the
* NII driver cannot disable the filters.
*/
nii_disable_rx_filters ( nii );
/* Enable receive filters */
if ( ( rc = nii_enable_rx_filters ( nii ) ) != 0 )
goto err_enable_rx_filters;
/* Set receive filters */
if ( ( rc = nii_set_rx_filters ( nii ) ) != 0 )
goto err_set_rx_filters;
return 0;
err_enable_rx_filters:
err_set_rx_filters:
nii_shutdown ( nii );
err_initialise:
return rc;

View File

@ -27,7 +27,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_snp.h>
#include <ipxe/efi/efi_utils.h>
#include "snpnet.h"
#include "nii.h"
@ -41,60 +40,34 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
* Check to see if driver supports a device
*
* @v device EFI device handle
* @v protocol Protocol GUID
* @ret rc Return status code
*/
static int snp_nii_supported ( EFI_HANDLE device, EFI_GUID *protocol ) {
static int snp_supported ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_HANDLE parent;
EFI_STATUS efirc;
int rc;
/* Check that this is not a device we are providing ourselves */
if ( find_snpdev ( device ) != NULL ) {
DBGCP ( device, "HANDLE %s is provided by this binary\n",
DBGCP ( device, "SNP %s is provided by this binary\n",
efi_handle_name ( device ) );
return -ENOTTY;
}
/* Test for presence of protocol */
if ( ( efirc = bs->OpenProtocol ( device, protocol,
/* Test for presence of simple network protocol */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_simple_network_protocol_guid,
NULL, efi_image_handle, device,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){
DBGCP ( device, "HANDLE %s is not a %s device\n",
efi_handle_name ( device ),
efi_guid_ntoa ( protocol ) );
DBGCP ( device, "SNP %s is not an SNP device\n",
efi_handle_name ( device ) );
return -EEFI ( efirc );
}
DBGC ( device, "SNP %s is an SNP device\n",
efi_handle_name ( device ) );
/* Check that there are no instances of this protocol further
* up this device path.
*/
if ( ( rc = efi_locate_device ( device, protocol,
&parent, 1 ) ) == 0 ) {
DBGC2 ( device, "HANDLE %s has %s-supporting parent ",
efi_handle_name ( device ),
efi_guid_ntoa ( protocol ) );
DBGC2 ( device, "%s\n", efi_handle_name ( parent ) );
return -ENOTTY;
}
DBGC ( device, "HANDLE %s is a %s device\n",
efi_handle_name ( device ), efi_guid_ntoa ( protocol ) );
return 0;
}
/**
* Check to see if driver supports a device
*
* @v device EFI device handle
* @ret rc Return status code
*/
static int snp_supported ( EFI_HANDLE device ) {
return snp_nii_supported ( device, &efi_simple_network_protocol_guid );
}
/**
* Check to see if driver supports a device
*
@ -102,8 +75,29 @@ static int snp_supported ( EFI_HANDLE device ) {
* @ret rc Return status code
*/
static int nii_supported ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_STATUS efirc;
return snp_nii_supported ( device, &efi_nii31_protocol_guid );
/* Check that this is not a device we are providing ourselves */
if ( find_snpdev ( device ) != NULL ) {
DBGCP ( device, "NII %s is provided by this binary\n",
efi_handle_name ( device ) );
return -ENOTTY;
}
/* Test for presence of NII protocol */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_nii31_protocol_guid,
NULL, efi_image_handle, device,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL))!=0){
DBGCP ( device, "NII %s is not an NII device\n",
efi_handle_name ( device ) );
return -EEFI ( efirc );
}
DBGC ( device, "NII %s is an NII device\n",
efi_handle_name ( device ) );
return 0;
}
/** EFI SNP driver */

View File

@ -164,10 +164,6 @@ static int snpnet_transmit ( struct net_device *netdev,
EFI_STATUS efirc;
int rc;
/* Do nothing if shutdown is in progress */
if ( efi_shutdown_in_progress )
return -ECANCELED;
/* Defer the packet if there is already a transmission in progress */
if ( snp->txbuf ) {
netdev_tx_defer ( netdev, iobuf );
@ -287,10 +283,6 @@ static void snpnet_poll_rx ( struct net_device *netdev ) {
*/
static void snpnet_poll ( struct net_device *netdev ) {
/* Do nothing if shutdown is in progress */
if ( efi_shutdown_in_progress )
return;
/* Process any TX completions */
snpnet_poll_tx ( netdev );
@ -434,9 +426,8 @@ static void snpnet_close ( struct net_device *netdev ) {
EFI_STATUS efirc;
int rc;
/* Shut down NIC (unless whole system shutdown is in progress) */
if ( ( ! efi_shutdown_in_progress ) &&
( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) ) {
/* Shut down NIC */
if ( ( efirc = snp->snp->Shutdown ( snp->snp ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( snp, "SNP %s could not shut down: %s\n",
netdev->name, strerror ( rc ) );
@ -598,9 +589,8 @@ void snpnet_stop ( struct efi_device *efidev ) {
/* Unregister network device */
unregister_netdev ( netdev );
/* Stop SNP protocol (unless whole system shutdown is in progress) */
if ( ( ! efi_shutdown_in_progress ) &&
( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) ) {
/* Stop SNP protocol */
if ( ( efirc = snp->snp->Stop ( snp->snp ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "SNP %s could not stop: %s\n",
efi_handle_name ( device ), strerror ( rc ) );

View File

@ -80,7 +80,7 @@ static int chained_locate ( struct chained_protocol *chained ) {
/* Locate handle supporting this protocol */
if ( ( rc = efi_locate_device ( device, chained->protocol,
&parent, 0 ) ) != 0 ) {
&parent ) ) != 0 ) {
DBGC ( device, "CHAINED %s does not support %s: %s\n",
efi_handle_name ( device ),
efi_guid_ntoa ( chained->protocol ), strerror ( rc ) );

View File

@ -24,7 +24,6 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
@ -35,8 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/iobuf.h>
#include <ipxe/malloc.h>
#include <ipxe/pci.h>
#include <ipxe/pcibridge.h>
#include <ipxe/version.h>
#include "ena.h"
/** @file
@ -350,90 +347,6 @@ static int ena_admin ( struct ena_nic *ena, union ena_aq_req *req,
return rc;
}
/**
* Set async event notification queue config
*
* @v ena ENA device
* @v enabled Bitmask of the groups to enable
* @ret rc Return status code
*/
static int ena_set_aenq_config ( struct ena_nic *ena, uint32_t enabled ) {
union ena_aq_req *req;
union ena_acq_rsp *rsp;
union ena_feature *feature;
int rc;
/* Construct request */
req = ena_admin_req ( ena );
req->header.opcode = ENA_SET_FEATURE;
req->set_feature.id = ENA_AENQ_CONFIG;
feature = &req->set_feature.feature;
feature->aenq.enabled = cpu_to_le32 ( enabled );
/* Issue request */
if ( ( rc = ena_admin ( ena, req, &rsp ) ) != 0 )
return rc;
return 0;
}
/**
* Create async event notification queue
*
* @v ena ENA device
* @ret rc Return status code
*/
static int ena_create_async ( struct ena_nic *ena ) {
size_t aenq_len = ( ENA_AENQ_COUNT * sizeof ( ena->aenq.evt[0] ) );
int rc;
/* Allocate async event notification queue */
ena->aenq.evt = malloc_phys ( aenq_len, aenq_len );
if ( ! ena->aenq.evt ) {
rc = -ENOMEM;
goto err_alloc_aenq;
}
memset ( ena->aenq.evt, 0, aenq_len );
/* Program queue address and capabilities */
ena_set_base ( ena, ENA_AENQ_BASE, ena->aenq.evt );
ena_set_caps ( ena, ENA_AENQ_CAPS, ENA_AENQ_COUNT,
sizeof ( ena->aenq.evt[0] ) );
DBGC ( ena, "ENA %p AENQ [%08lx,%08lx)\n",
ena, virt_to_phys ( ena->aenq.evt ),
( virt_to_phys ( ena->aenq.evt ) + aenq_len ) );
/* Disable all events */
if ( ( rc = ena_set_aenq_config ( ena, 0 ) ) != 0 )
goto err_set_aenq_config;
return 0;
err_set_aenq_config:
ena_clear_caps ( ena, ENA_AENQ_CAPS );
free_phys ( ena->aenq.evt, aenq_len );
err_alloc_aenq:
return rc;
}
/**
* Destroy async event notification queue
*
* @v ena ENA device
*/
static void ena_destroy_async ( struct ena_nic *ena ) {
size_t aenq_len = ( ENA_AENQ_COUNT * sizeof ( ena->aenq.evt[0] ) );
/* Clear queue capabilities */
ena_clear_caps ( ena, ENA_AENQ_CAPS );
wmb();
/* Free queue */
free_phys ( ena->aenq.evt, aenq_len );
DBGC ( ena, "ENA %p AENQ destroyed\n", ena );
}
/**
* Create submission queue
*
@ -446,7 +359,6 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq,
struct ena_cq *cq ) {
union ena_aq_req *req;
union ena_acq_rsp *rsp;
unsigned int i;
int rc;
/* Allocate submission queue entries */
@ -479,20 +391,11 @@ static int ena_create_sq ( struct ena_nic *ena, struct ena_sq *sq,
sq->prod = 0;
sq->phase = ENA_SQE_PHASE;
/* Calculate fill level */
sq->fill = sq->max;
if ( sq->fill > cq->actual )
sq->fill = cq->actual;
/* Initialise buffer ID ring */
for ( i = 0 ; i < sq->count ; i++ )
sq->ids[i] = i;
DBGC ( ena, "ENA %p %s SQ%d at [%08lx,%08lx) fill %d db +%04x CQ%d\n",
DBGC ( ena, "ENA %p %s SQ%d at [%08lx,%08lx) db +%04x CQ%d\n",
ena, ena_direction ( sq->direction ), sq->id,
virt_to_phys ( sq->sqe.raw ),
( virt_to_phys ( sq->sqe.raw ) + sq->len ),
sq->fill, sq->doorbell, cq->id );
sq->doorbell, cq->id );
return 0;
err_admin:
@ -556,7 +459,6 @@ static int ena_create_cq ( struct ena_nic *ena, struct ena_cq *cq ) {
req->header.opcode = ENA_CREATE_CQ;
req->create_cq.size = cq->size;
req->create_cq.count = cpu_to_le16 ( cq->requested );
req->create_cq.vector = cpu_to_le32 ( ENA_MSIX_NONE );
req->create_cq.address = cpu_to_le64 ( virt_to_bus ( cq->cqe.raw ) );
/* Issue request */
@ -694,32 +596,6 @@ static int ena_get_device_attributes ( struct net_device *netdev ) {
return 0;
}
/**
* Set host attributes
*
* @v ena ENA device
* @ret rc Return status code
*/
static int ena_set_host_attributes ( struct ena_nic *ena ) {
union ena_aq_req *req;
union ena_acq_rsp *rsp;
union ena_feature *feature;
int rc;
/* Construct request */
req = ena_admin_req ( ena );
req->header.opcode = ENA_SET_FEATURE;
req->set_feature.id = ENA_HOST_ATTRIBUTES;
feature = &req->set_feature.feature;
feature->host.info = cpu_to_le64 ( virt_to_bus ( ena->info ) );
/* Issue request */
if ( ( rc = ena_admin ( ena, req, &rsp ) ) != 0 )
return rc;
return 0;
}
/**
* Get statistics (for debugging)
*
@ -776,14 +652,13 @@ static void ena_refill_rx ( struct net_device *netdev ) {
struct ena_nic *ena = netdev->priv;
struct io_buffer *iobuf;
struct ena_rx_sqe *sqe;
unsigned int index;
physaddr_t address;
size_t len = netdev->max_pkt_len;
unsigned int refilled = 0;
unsigned int index;
unsigned int id;
/* Refill queue */
while ( ( ena->rx.sq.prod - ena->rx.cq.cons ) < ena->rx.sq.fill ) {
while ( ( ena->rx.sq.prod - ena->rx.cq.cons ) < ENA_RX_COUNT ) {
/* Allocate I/O buffer */
iobuf = alloc_iob ( len );
@ -792,15 +667,14 @@ static void ena_refill_rx ( struct net_device *netdev ) {
break;
}
/* Get next submission queue entry and buffer ID */
/* Get next submission queue entry */
index = ( ena->rx.sq.prod % ENA_RX_COUNT );
sqe = &ena->rx.sq.sqe.rx[index];
id = ena->rx_ids[index];
/* Construct submission queue entry */
address = virt_to_bus ( iobuf->data );
sqe->len = cpu_to_le16 ( len );
sqe->id = cpu_to_le16 ( id );
sqe->id = cpu_to_le16 ( ena->rx.sq.prod );
sqe->address = cpu_to_le64 ( address );
wmb();
sqe->flags = ( ENA_SQE_FIRST | ENA_SQE_LAST | ENA_SQE_CPL |
@ -812,10 +686,10 @@ static void ena_refill_rx ( struct net_device *netdev ) {
ena->rx.sq.phase ^= ENA_SQE_PHASE;
/* Record I/O buffer */
assert ( ena->rx_iobuf[id] == NULL );
ena->rx_iobuf[id] = iobuf;
assert ( ena->rx_iobuf[index] == NULL );
ena->rx_iobuf[index] = iobuf;
DBGC2 ( ena, "ENA %p RX %d at [%08llx,%08llx)\n", ena, id,
DBGC2 ( ena, "ENA %p RX %d at [%08llx,%08llx)\n", ena, sqe->id,
( ( unsigned long long ) address ),
( ( unsigned long long ) address + len ) );
refilled++;
@ -904,25 +778,23 @@ static void ena_close ( struct net_device *netdev ) {
static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
struct ena_nic *ena = netdev->priv;
struct ena_tx_sqe *sqe;
physaddr_t address;
unsigned int index;
unsigned int id;
physaddr_t address;
size_t len;
/* Get next submission queue entry */
if ( ( ena->tx.sq.prod - ena->tx.cq.cons ) >= ena->tx.sq.fill ) {
if ( ( ena->tx.sq.prod - ena->tx.cq.cons ) >= ENA_TX_COUNT ) {
DBGC ( ena, "ENA %p out of transmit descriptors\n", ena );
return -ENOBUFS;
}
index = ( ena->tx.sq.prod % ENA_TX_COUNT );
sqe = &ena->tx.sq.sqe.tx[index];
id = ena->tx_ids[index];
/* Construct submission queue entry */
address = virt_to_bus ( iobuf->data );
len = iob_len ( iobuf );
sqe->len = cpu_to_le16 ( len );
sqe->id = cpu_to_le16 ( id );
sqe->id = ena->tx.sq.prod;
sqe->address = cpu_to_le64 ( address );
wmb();
sqe->flags = ( ENA_SQE_FIRST | ENA_SQE_LAST | ENA_SQE_CPL |
@ -934,14 +806,10 @@ static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
if ( ( ena->tx.sq.prod % ENA_TX_COUNT ) == 0 )
ena->tx.sq.phase ^= ENA_SQE_PHASE;
/* Record I/O buffer */
assert ( ena->tx_iobuf[id] == NULL );
ena->tx_iobuf[id] = iobuf;
/* Ring doorbell */
writel ( ena->tx.sq.prod, ( ena->regs + ena->tx.sq.doorbell ) );
DBGC2 ( ena, "ENA %p TX %d at [%08llx,%08llx)\n", ena, id,
DBGC2 ( ena, "ENA %p TX %d at [%08llx,%08llx)\n", ena, sqe->id,
( ( unsigned long long ) address ),
( ( unsigned long long ) address + len ) );
return 0;
@ -955,9 +823,7 @@ static int ena_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
static void ena_poll_tx ( struct net_device *netdev ) {
struct ena_nic *ena = netdev->priv;
struct ena_tx_cqe *cqe;
struct io_buffer *iobuf;
unsigned int index;
unsigned int id;
/* Check for completed packets */
while ( ena->tx.cq.cons != ena->tx.sq.prod ) {
@ -969,24 +835,16 @@ static void ena_poll_tx ( struct net_device *netdev ) {
/* Stop if completion queue entry is empty */
if ( ( cqe->flags ^ ena->tx.cq.phase ) & ENA_CQE_PHASE )
return;
DBGC2 ( ena, "ENA %p TX %d complete\n", ena,
( le16_to_cpu ( cqe->id ) >> 2 /* Don't ask */ ) );
/* Increment consumer counter */
ena->tx.cq.cons++;
if ( ! ( ena->tx.cq.cons & ena->tx.cq.mask ) )
ena->tx.cq.phase ^= ENA_CQE_PHASE;
/* Identify and free buffer ID */
id = ENA_TX_CQE_ID ( le16_to_cpu ( cqe->id ) );
ena->tx_ids[index] = id;
/* Identify I/O buffer */
iobuf = ena->tx_iobuf[id];
assert ( iobuf != NULL );
ena->tx_iobuf[id] = NULL;
/* Complete transmit */
DBGC2 ( ena, "ENA %p TX %d complete\n", ena, id );
netdev_tx_complete ( netdev, iobuf );
netdev_tx_complete_next ( netdev );
}
}
@ -1000,14 +858,13 @@ static void ena_poll_rx ( struct net_device *netdev ) {
struct ena_rx_cqe *cqe;
struct io_buffer *iobuf;
unsigned int index;
unsigned int id;
size_t len;
/* Check for received packets */
while ( ena->rx.cq.cons != ena->rx.sq.prod ) {
/* Get next completion queue entry */
index = ( ena->rx.cq.cons & ena->rx.cq.mask );
index = ( ena->rx.cq.cons % ENA_RX_COUNT );
cqe = &ena->rx.cq.cqe.rx[index];
/* Stop if completion queue entry is empty */
@ -1019,20 +876,15 @@ static void ena_poll_rx ( struct net_device *netdev ) {
if ( ! ( ena->rx.cq.cons & ena->rx.cq.mask ) )
ena->rx.cq.phase ^= ENA_CQE_PHASE;
/* Identify and free buffer ID */
id = le16_to_cpu ( cqe->id );
ena->rx_ids[index] = id;
/* Populate I/O buffer */
iobuf = ena->rx_iobuf[id];
assert ( iobuf != NULL );
ena->rx_iobuf[id] = NULL;
iobuf = ena->rx_iobuf[index];
ena->rx_iobuf[index] = NULL;
len = le16_to_cpu ( cqe->len );
iob_put ( iobuf, len );
/* Hand off to network stack */
DBGC2 ( ena, "ENA %p RX %d complete (length %zd)\n",
ena, id, len );
ena, le16_to_cpu ( cqe->id ), len );
netdev_rx ( netdev, iobuf );
}
}
@ -1069,45 +921,6 @@ static struct net_device_operations ena_operations = {
******************************************************************************
*/
/**
* Assign memory BAR
*
* @v ena ENA device
* @v pci PCI device
* @ret rc Return status code
*
* Some BIOSes in AWS EC2 are observed to fail to assign a base
* address to the ENA device. The device is the only device behind
* its bridge, and the BIOS does assign a memory window to the bridge.
* We therefore place the device at the start of the memory window.
*/
static int ena_membase ( struct ena_nic *ena, struct pci_device *pci ) {
struct pci_bridge *bridge;
/* Locate PCI bridge */
bridge = pcibridge_find ( pci );
if ( ! bridge ) {
DBGC ( ena, "ENA %p found no PCI bridge\n", ena );
return -ENOTCONN;
}
/* Sanity check */
if ( PCI_SLOT ( pci->busdevfn ) || PCI_FUNC ( pci->busdevfn ) ) {
DBGC ( ena, "ENA %p at " PCI_FMT " may not be only device "
"on bus\n", ena, PCI_ARGS ( pci ) );
return -ENOTSUP;
}
/* Place device at start of memory window */
pci_write_config_dword ( pci, PCI_BASE_ADDRESS_0, bridge->membase );
pci->membase = bridge->membase;
DBGC ( ena, "ENA %p at " PCI_FMT " claiming bridge " PCI_FMT " mem "
"%08x\n", ena, PCI_ARGS ( pci ), PCI_ARGS ( bridge->pci ),
bridge->membase );
return 0;
}
/**
* Probe PCI device
*
@ -1117,7 +930,6 @@ static int ena_membase ( struct ena_nic *ena, struct pci_device *pci ) {
static int ena_probe ( struct pci_device *pci ) {
struct net_device *netdev;
struct ena_nic *ena;
struct ena_host_info *info;
int rc;
/* Allocate and initialise net device */
@ -1134,20 +946,16 @@ static int ena_probe ( struct pci_device *pci ) {
ena->acq.phase = ENA_ACQ_PHASE;
ena_cq_init ( &ena->tx.cq, ENA_TX_COUNT,
sizeof ( ena->tx.cq.cqe.tx[0] ) );
ena_sq_init ( &ena->tx.sq, ENA_SQ_TX, ENA_TX_COUNT, ENA_TX_COUNT,
sizeof ( ena->tx.sq.sqe.tx[0] ), ena->tx_ids );
ena_sq_init ( &ena->tx.sq, ENA_SQ_TX, ENA_TX_COUNT,
sizeof ( ena->tx.sq.sqe.tx[0] ) );
ena_cq_init ( &ena->rx.cq, ENA_RX_COUNT,
sizeof ( ena->rx.cq.cqe.rx[0] ) );
ena_sq_init ( &ena->rx.sq, ENA_SQ_RX, ENA_RX_COUNT, ENA_RX_FILL,
sizeof ( ena->rx.sq.sqe.rx[0] ), ena->rx_ids );
ena_sq_init ( &ena->rx.sq, ENA_SQ_RX, ENA_RX_COUNT,
sizeof ( ena->rx.sq.sqe.rx[0] ) );
/* Fix up PCI device */
adjust_pci_device ( pci );
/* Fix up PCI BAR if left unassigned by BIOS */
if ( ( ! pci->membase ) && ( ( rc = ena_membase ( ena, pci ) ) != 0 ) )
goto err_membase;
/* Map registers */
ena->regs = pci_ioremap ( pci, pci->membase, ENA_BAR_SIZE );
if ( ! ena->regs ) {
@ -1155,25 +963,6 @@ static int ena_probe ( struct pci_device *pci ) {
goto err_ioremap;
}
/* Allocate and initialise host info */
info = malloc_phys ( PAGE_SIZE, PAGE_SIZE );
if ( ! info ) {
rc = -ENOMEM;
goto err_info;
}
ena->info = info;
memset ( info, 0, PAGE_SIZE );
info->type = cpu_to_le32 ( ENA_HOST_INFO_TYPE_LINUX );
snprintf ( info->dist_str, sizeof ( info->dist_str ), "%s",
( product_name[0] ? product_name : product_short_name ) );
snprintf ( info->kernel_str, sizeof ( info->kernel_str ), "%s",
product_version );
info->version = cpu_to_le32 ( ENA_HOST_INFO_VERSION_WTF );
info->spec = cpu_to_le16 ( ENA_HOST_INFO_SPEC_2_0 );
info->busdevfn = cpu_to_le16 ( pci->busdevfn );
DBGC2 ( ena, "ENA %p host info:\n", ena );
DBGC2_HDA ( ena, virt_to_phys ( info ), info, sizeof ( *info ) );
/* Reset the NIC */
if ( ( rc = ena_reset ( ena ) ) != 0 )
goto err_reset;
@ -1182,14 +971,6 @@ static int ena_probe ( struct pci_device *pci ) {
if ( ( rc = ena_create_admin ( ena ) ) != 0 )
goto err_create_admin;
/* Create async event notification queue */
if ( ( rc = ena_create_async ( ena ) ) != 0 )
goto err_create_async;
/* Set host attributes */
if ( ( rc = ena_set_host_attributes ( ena ) ) != 0 )
goto err_set_host_attributes;
/* Fetch MAC address */
if ( ( rc = ena_get_device_attributes ( netdev ) ) != 0 )
goto err_get_device_attributes;
@ -1208,18 +989,12 @@ static int ena_probe ( struct pci_device *pci ) {
unregister_netdev ( netdev );
err_register_netdev:
err_get_device_attributes:
err_set_host_attributes:
ena_destroy_async ( ena );
err_create_async:
ena_destroy_admin ( ena );
err_create_admin:
ena_reset ( ena );
err_reset:
free_phys ( ena->info, PAGE_SIZE );
err_info:
iounmap ( ena->regs );
err_ioremap:
err_membase:
netdev_nullify ( netdev );
netdev_put ( netdev );
err_alloc:
@ -1238,18 +1013,12 @@ static void ena_remove ( struct pci_device *pci ) {
/* Unregister network device */
unregister_netdev ( netdev );
/* Destroy async event notification queue */
ena_destroy_async ( ena );
/* Destroy admin queues */
ena_destroy_admin ( ena );
/* Reset card */
ena_reset ( ena );
/* Free host info */
free_phys ( ena->info, PAGE_SIZE );
/* Free network device */
iounmap ( ena->regs );
netdev_nullify ( netdev );

View File

@ -24,17 +24,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Number of admin completion queue entries */
#define ENA_ACQ_COUNT 2
/** Number of async event notification queue entries */
#define ENA_AENQ_COUNT 2
/** Number of transmit queue entries */
#define ENA_TX_COUNT 16
/** Number of receive queue entries */
#define ENA_RX_COUNT 128
/** Receive queue maximum fill level */
#define ENA_RX_FILL 16
#define ENA_RX_COUNT 16
/** Base address low register offset */
#define ENA_BASE_LO 0x0
@ -63,12 +57,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Maximum time to wait for admin requests */
#define ENA_ADMIN_MAX_WAIT_MS 5000
/** Async event notification queue capabilities register */
#define ENA_AENQ_CAPS 0x34
/** Async event notification queue base address register */
#define ENA_AENQ_BASE 0x38
/** Device control register */
#define ENA_CTRL 0x54
#define ENA_CTRL_RESET 0x00000001UL /**< Reset */
@ -139,99 +127,10 @@ struct ena_device_attributes {
uint32_t mtu;
} __attribute__ (( packed ));
/** Async event notification queue config */
#define ENA_AENQ_CONFIG 26
/** Async event notification queue config */
struct ena_aenq_config {
/** Bitmask of supported AENQ groups (device -> host) */
uint32_t supported;
/** Bitmask of enabled AENQ groups (host -> device) */
uint32_t enabled;
} __attribute__ (( packed ));
/** Host attributes */
#define ENA_HOST_ATTRIBUTES 28
/** Host attributes */
struct ena_host_attributes {
/** Host info base address */
uint64_t info;
/** Debug area base address */
uint64_t debug;
/** Debug area size */
uint32_t debug_len;
} __attribute__ (( packed ));
/** Host information */
struct ena_host_info {
/** Operating system type */
uint32_t type;
/** Operating system distribution (string) */
char dist_str[128];
/** Operating system distribution (numeric) */
uint32_t dist;
/** Kernel version (string) */
char kernel_str[32];
/** Kernel version (numeric) */
uint32_t kernel;
/** Driver version */
uint32_t version;
/** Linux network device features */
uint64_t linux_features;
/** ENA specification version */
uint16_t spec;
/** PCI bus:dev.fn address */
uint16_t busdevfn;
/** Number of CPUs */
uint16_t cpus;
/** Reserved */
uint8_t reserved_a[2];
/** Supported features */
uint32_t features;
} __attribute__ (( packed ));
/** Linux operating system type
*
* There is a defined "iPXE" operating system type (with value 5).
* However, some very broken versions of the ENA firmware will refuse
* to allow a completion queue to be created if the "iPXE" type is
* used.
*/
#define ENA_HOST_INFO_TYPE_LINUX 1
/** Driver version
*
* The driver version field is nominally used to report a version
* number outside of the VM for consumption by humans (and potentially
* by automated monitoring tools that could e.g. check for outdated
* versions with known security flaws).
*
* However, at some point in the development of the ENA firmware, some
* unknown person at AWS thought it would be sensible to apply a
* machine interpretation to this field and adjust the behaviour of
* the firmware based on its value, thereby creating a maintenance and
* debugging nightmare for all existing and future drivers.
*
* Hint to engineers: if you ever find yourself writing code of the
* form "if (version == SOME_MAGIC_NUMBER)" then something has gone
* very, very wrong. This *always* indicates that something is
* broken, either in your own code or in the code with which you are
* forced to interact.
*/
#define ENA_HOST_INFO_VERSION_WTF 0x00000002UL
/** ENA specification version */
#define ENA_HOST_INFO_SPEC_2_0 0x0200
/** Feature */
union ena_feature {
/** Device attributes */
struct ena_device_attributes device;
/** Async event notification queue config */
struct ena_aenq_config aenq;
/** Host attributes */
struct ena_host_attributes host;
};
/** Submission queue direction */
@ -331,14 +230,6 @@ struct ena_create_cq_req {
uint64_t address;
} __attribute__ (( packed ));
/** Empty MSI-X vector
*
* Some versions of the ENA firmware will complain if the completion
* queue's MSI-X vector field is left empty, even though the queue
* configuration specifies that interrupts are not used.
*/
#define ENA_MSIX_NONE 0xffffffffUL
/** Create completion queue response */
struct ena_create_cq_rsp {
/** Header */
@ -401,27 +292,6 @@ struct ena_get_feature_rsp {
union ena_feature feature;
} __attribute__ (( packed ));
/** Set feature */
#define ENA_SET_FEATURE 9
/** Set feature request */
struct ena_set_feature_req {
/** Header */
struct ena_aq_header header;
/** Length */
uint32_t len;
/** Address */
uint64_t address;
/** Flags */
uint8_t flags;
/** Feature identifier */
uint8_t id;
/** Reserved */
uint8_t reserved[2];
/** Feature */
union ena_feature feature;
} __attribute__ (( packed ));
/** Get statistics */
#define ENA_GET_STATS 11
@ -482,8 +352,6 @@ union ena_aq_req {
struct ena_destroy_cq_req destroy_cq;
/** Get feature */
struct ena_get_feature_req get_feature;
/** Set feature */
struct ena_set_feature_req set_feature;
/** Get statistics */
struct ena_get_stats_req get_stats;
/** Padding */
@ -528,28 +396,6 @@ struct ena_acq {
unsigned int phase;
};
/** Async event notification queue event */
struct ena_aenq_event {
/** Type of event */
uint16_t group;
/** ID of event */
uint16_t syndrome;
/** Phase */
uint8_t flags;
/** Reserved */
uint8_t reserved[3];
/** Timestamp */
uint64_t timestamp;
/** Additional event data */
uint8_t data[48];
} __attribute__ (( packed ));
/** Async event notification queue */
struct ena_aenq {
/** Events */
struct ena_aenq_event *evt;
};
/** Transmit submission queue entry */
struct ena_tx_sqe {
/** Length */
@ -608,9 +454,6 @@ struct ena_tx_cqe {
uint16_t cons;
} __attribute__ (( packed ));
/** Transmit completion request identifier */
#define ENA_TX_CQE_ID(id) ( (id) >> 2 )
/** Receive completion queue entry */
struct ena_rx_cqe {
/** Reserved */
@ -639,8 +482,6 @@ struct ena_sq {
/** Raw data */
void *raw;
} sqe;
/** Buffer IDs */
uint8_t *ids;
/** Doorbell register offset */
unsigned int doorbell;
/** Total length of entries */
@ -655,10 +496,6 @@ struct ena_sq {
uint8_t direction;
/** Number of entries */
uint8_t count;
/** Maximum fill level */
uint8_t max;
/** Fill level (limited to completion queue size) */
uint8_t fill;
};
/**
@ -667,19 +504,15 @@ struct ena_sq {
* @v sq Submission queue
* @v direction Direction
* @v count Number of entries
* @v max Maximum fill level
* @v size Size of each entry
* @v ids Buffer IDs
*/
static inline __attribute__ (( always_inline )) void
ena_sq_init ( struct ena_sq *sq, unsigned int direction, unsigned int count,
unsigned int max, size_t size, uint8_t *ids ) {
size_t size ) {
sq->len = ( count * size );
sq->direction = direction;
sq->count = count;
sq->max = max;
sq->ids = ids;
}
/** Completion queue */
@ -740,25 +573,15 @@ struct ena_qp {
struct ena_nic {
/** Registers */
void *regs;
/** Host info */
struct ena_host_info *info;
/** Admin queue */
struct ena_aq aq;
/** Admin completion queue */
struct ena_acq acq;
/** Async event notification queue */
struct ena_aenq aenq;
/** Transmit queue */
struct ena_qp tx;
/** Receive queue */
struct ena_qp rx;
/** Transmit buffer IDs */
uint8_t tx_ids[ENA_TX_COUNT];
/** Transmit I/O buffers, indexed by buffer ID */
struct io_buffer *tx_iobuf[ENA_TX_COUNT];
/** Receive buffer IDs */
uint8_t rx_ids[ENA_RX_COUNT];
/** Receive I/O buffers, indexed by buffer ID */
/** Receive I/O buffers */
struct io_buffer *rx_iobuf[ENA_RX_COUNT];
};

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